From 15e0ff362ca2add8bd6176681f1e736f33c2e696 Mon Sep 17 00:00:00 2001 From: Leo Dev Date: Sun, 23 Jun 2024 17:53:46 +0200 Subject: [PATCH] Added rust imports with header --- .gitignore | 5 +- Cargo.toml | 1 + src/dllmgr.rs | 76 ++++++++++++++++++++ src/file_writer.rs | 172 ++++++++++++++++++++++++++++++++++++++------- src/lexer.rs | 11 ++- src/lspcom.rs | 4 +- src/main.rs | 20 ++++-- src/parser.rs | 7 ++ src/transpiler.rs | 65 ++++++++++------- src/variable.rs | 9 ++- 10 files changed, 306 insertions(+), 64 deletions(-) create mode 100644 src/dllmgr.rs diff --git a/.gitignore b/.gitignore index a89630a..0053249 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ # will have compiled files and executables debug/ target/ +test/ +.vscode/ +.idea/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html @@ -24,4 +27,4 @@ Cargo.lock *.wt /log.txt -/lsp.log \ No newline at end of file +/lsp.log diff --git a/Cargo.toml b/Cargo.toml index 658ca1a..feb4029 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ serde = "1.0.203" serde_derive = "1.0.203" lsp-types = "0.97.0" zip = "2.1.3" +dirs = "5.0.1" diff --git a/src/dllmgr.rs b/src/dllmgr.rs new file mode 100644 index 0000000..c81f064 --- /dev/null +++ b/src/dllmgr.rs @@ -0,0 +1,76 @@ +use regex::Regex; +use std::fs; +use std::io::Write; +use std::{ + fs::File, + io::{BufReader, Read}, +}; +use zip::{write::SimpleFileOptions, ZipArchive, ZipWriter}; + +use crate::variable::Variables; + +pub fn read_dll(dll_path: String) -> Variables { + let mut vars = Variables::new(); + let dll_file = File::open(dll_path).expect("err_dll_read"); + let dll_reader = BufReader::new(dll_file); + let mut dll_zip = ZipArchive::new(dll_reader).expect("err_archive"); + for i in 0..dll_zip.len() { + let mut buf = Vec::new(); + let mut file = dll_zip.by_index(i).expect("err_dll_idx"); + let filename = file.name(); + if filename == "map.json" && file.is_file() { + file.read_to_end(&mut buf).expect("err_read_zip_file"); + println!( + "Filename: {}\nFileContents: {}", + file.name(), + String::from_utf8_lossy(&buf) + ); + } + } + vars +} + +pub fn write_dll(vars: Variables, exe_path: String, dll_path: String) { + let dll_file = File::create(&dll_path).expect("Err_DllCREATE"); + let mut dll = ZipWriter::new(dll_file); + dll.start_file("run", SimpleFileOptions::default()) + .expect("ERR_STARTFILE_RUN"); + let buf_vec = fs::read(exe_path).expect("ERR_READ_EXE"); + let buf_u8: &[u8] = buf_vec.as_slice(); + dll.write_all(buf_u8).expect("ERR_DLL_EXEWRITE"); + dll.start_file("map.json", SimpleFileOptions::default()) + .expect("ERR_STARTFILE_MAP"); + let json_data = serde_json::to_string(&vars.vars).expect("ERR_MAP_JSON"); + dll.write_all(json_data.as_bytes()) + .expect("ERR_DLL_JSONWRITE"); + println!("{:?}", serde_json::to_string(&vars.vars)); +} + +pub struct HeaderConfig { + pub file_path: String, + pub map_path: String, +} + +impl HeaderConfig { + // Function to parse the input string + pub fn new(input: String) -> Option { + let re = Regex::new(r#"FILE_PATH\s*=\s*"([^"]*)""#).expect("ERR_REGEX_HDR"); + let re1 = Regex::new(r#"MAP_PATH\s*=\s*"([^"]*)""#).expect("ERR_REGEX_HDR1"); + let mut fp: String = String::new(); + let mut mp: String = String::new(); + if let Some(caps) = re.captures(input.as_str()) { + fp = caps.get(1)?.as_str().to_string(); + } else { + return None; + } + if let Some(caps) = re1.captures(input.as_str()) { + mp = caps.get(1)?.as_str().to_string(); + } else { + return None; + } + return Some(HeaderConfig { + file_path: fp, + map_path: mp, + }); + } +} diff --git a/src/file_writer.rs b/src/file_writer.rs index ca45dba..6559a5b 100644 --- a/src/file_writer.rs +++ b/src/file_writer.rs @@ -1,6 +1,34 @@ -use std::fs; +use std::{collections::HashMap, fs, path::Path}; -use crate::{dllmgr::read_dll, transpiler::Transpiler, variable::Variables}; +use dirs::home_dir; + +use crate::{ + dllmgr::{read_dll, HeaderConfig}, + lspcom::{Problem, ProblemType}, + transpiler::Transpiler, + variable::{Variable, Variables}, +}; + +fn join_directories(dir1: &str, dir2: &str) -> String { + let mut main_seperator = '/'; + if cfg!(windows) { + main_seperator = '\\'; + } + let mut result = dir1.to_string(); + + if !result.ends_with(main_seperator) { + result.push(main_seperator); + } + + let dir2_trimmed = if dir2.starts_with(main_seperator) { + &dir2[1..] + } else { + dir2 + }; + + result.push_str(dir2_trimmed); + result +} #[derive(Clone, Debug)] pub struct Module { @@ -45,31 +73,125 @@ impl FileWriter { self.files.push(module); } } - pub fn add(&mut self, filepath: String, variables: &mut Variables) -> String { - if filepath.ends_with(".dll") { - read_dll(filepath.clone()); - return "xyz".to_string(); + pub fn add( + &mut self, + filepath: String, + variables: &mut Variables, + global: bool, + ) -> Result { + let mut filepath = filepath; + if global { + let homedir_ = home_dir().expect("Err_HOMEDIR_NOTFOUND"); + let homedir = homedir_.to_str().expect("ERR_HOMEDIR_STR"); + let gdir = join_directories(&homedir, &join_directories("wyst", "lib")); + let lpath = join_directories("lib", &filepath); + let gpath = join_directories(&gdir, &filepath); + if Path::new(&lpath).exists() { + filepath = lpath; + } else if Path::new(&gpath).exists() { + filepath = gpath; + } else { + return Err(Problem { + problem_type: ProblemType::FileNotFound, + problem_msg: format!("failed to import {}: Not found", filepath), + }); + } + } + if !Path::new(&filepath).exists() { + return Err(Problem { + problem_type: ProblemType::FileNotFound, + problem_msg: format!("failed to import {}: Not found", filepath), + }); } if let Some(module) = self.check(filepath.clone()) { - return module.mod_rs.clone(); + return Ok(module.mod_rs.clone()); + } + match filepath.rsplit_once('.').expect("Err_SPLIT").1 { + "wt" => { + let mut trsp = Transpiler { + writer: self.clone(), + ..Default::default() + }; + let mut vars = Variables::new(); + let code = fs::read_to_string(filepath.clone()).expect("failed to read"); + let code_rs = trsp.transpile(code.clone(), 0, &mut vars); + let module = Module { + file_ws: filepath, + mod_rs: format!("mod_{}", self.mod_num), + file_rs: format!("build/mod_{}.rs", self.mod_num), + _code: code, + code_rs, + }; + self.files.push(module.clone()); + self.expand(trsp.writer); + variables.expand(vars); + self.mod_num += 1; + Ok(module.mod_rs) + } + "h" => { + let hdr_code = fs::read_to_string(filepath.clone()).expect("failed to read"); + let mut parent = String::new(); + match Path::new(&filepath).parent() { + Some(p) => parent = format!("{}", p.display()), + None => {} + }; + match HeaderConfig::new(hdr_code) { + Some(hdrcnf) => { + let file_path = Path::new(&parent).join(hdrcnf.file_path.clone()); + let map_path = Path::new(&parent).join(hdrcnf.map_path.clone()); + match fs::read_to_string(file_path) { + Ok(code) => match fs::read_to_string(map_path) { + Ok(map_string) => { + let map: HashMap = + serde_json::from_str(&map_string) + .expect(format!("err_hdr.map: {}", filepath).as_str()); + let vars = Variables { vars: map }; + let module = Module { + file_ws: filepath, + mod_rs: format!("mod_{}", self.mod_num), + file_rs: format!("build/mod_{}.rs", self.mod_num), + _code: code.clone(), + code_rs: code, + }; + self.files.push(module.clone()); + variables.expand(vars); + Ok(module.mod_rs) + } + Err(_) => Err(Problem { + problem_type: ProblemType::FileNotFound, + problem_msg: format!( + "failed to import {}: Not found", + hdrcnf.map_path + ), + }), + }, + Err(_) => Err(Problem { + problem_type: ProblemType::FileNotFound, + problem_msg: format!( + "failed to import {}: Not found", + hdrcnf.file_path + ), + }), + } + } + None => Err(Problem { + problem_type: ProblemType::HeaderSyntaxError, + problem_msg: format!("failed to deserialize"), + }), + } + } + "dll" => { + read_dll(filepath.clone()); + return Ok("xyz".to_string()); + } + "rs" => Err(Problem { + problem_type: ProblemType::FileNotFound, + problem_msg: format!("failed to import {}: Not found", filepath), + }), + _ => Err(Problem { + problem_type: ProblemType::FileNotFound, + problem_msg: format!("failed to import {}: Not found", filepath), + }), } - let mut trsp = Transpiler { - writer: self.clone(), - ..Default::default() - }; - let mut vars = Variables::new(); - let code = fs::read_to_string(filepath.clone()).expect("failed to read"); - let code_rs = trsp.transpile(code.clone(), 0, &mut vars); - let module = Module { - file_ws: filepath, - mod_rs: format!("mod_{}", self.mod_num), - file_rs: format!("build/mod_{}.rs", self.mod_num), - _code: code, - code_rs, - }; - self.files.push(module.clone()); - self.expand(trsp.writer); - variables.expand(vars); - return module.mod_rs; } } diff --git a/src/lexer.rs b/src/lexer.rs index 680197d..8f98af3 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,8 +1,8 @@ use once_cell::sync::Lazy; use regex::Regex; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use std::fmt; -#[derive(Debug, PartialEq, Clone, Copy, Serialize)] +#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)] pub struct LexerState { pub line: usize, pub column: usize, @@ -29,6 +29,7 @@ pub enum TokenType { Include, String, Comment, + StaticExecution, // EOF, } @@ -64,7 +65,7 @@ pub struct Node { token_regex: Lazy, } -const SYNTAX: [Node; 16] = [ +const SYNTAX: [Node; 17] = [ Node { token_type: TokenType::Semicolon, token_regex: Lazy::new(|| Regex::new(r"^\;").unwrap()), @@ -133,6 +134,10 @@ const SYNTAX: [Node; 16] = [ token_type: TokenType::Include, token_regex: Lazy::new(|| Regex::new(r#"^#include *"(.*?)""#).unwrap()), }, + Node { + token_type: TokenType::StaticExecution, + token_regex: Lazy::new(|| Regex::new(r"^#").unwrap()), + }, ]; fn get_first_char(value: &str) -> String { diff --git a/src/lspcom.rs b/src/lspcom.rs index 09f710d..1ac6a7c 100644 --- a/src/lspcom.rs +++ b/src/lspcom.rs @@ -103,11 +103,13 @@ pub fn get_items(mut items: Variables, lname: String) -> Vec { #[derive(Clone, Debug)] pub enum ProblemType { VariableNotFound, + FileNotFound, + HeaderSyntaxError, } #[derive(Clone, Debug)] pub struct Problem { - pub code: u32, + //pub code: u32, pub problem_type: ProblemType, pub problem_msg: String, } diff --git a/src/main.rs b/src/main.rs index 69d1e01..494d6d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ mod variable; use clap::Parser; use std::{fs, path::Path}; use transpiler::Transpiler; -use variable::{Variable, Variables}; +use variable::{Variable, VariableType, Variables}; use crate::lsp::run_lsp_server; @@ -50,8 +50,11 @@ fn main() { transpiled_code += "std::process::exit("; transpiled_code += vars.get_var("main".to_string(), &mut trsp).as_str(); transpiled_code += "())}"; - for problem in trsp.problems { - println!("{}", problem.problem_msg) + for problem in &trsp.problems { + println!("{:?}: {}", problem.problem_type, problem.problem_msg) + } + if trsp.problems.len() > 0 { + return; } trsp.writer.write(); @@ -81,9 +84,15 @@ fn main() { println!("{}", problem.problem_msg) } trsp.writer.write(); - let mut dll_main = String::from("fn call_fn(params: Vec){"); + let mut dll_main = String::from( + "mod wslib;use wslib::*;\nfn call_fn(fn_name: &str, params: Vec)->i32{match fn_name {", + ); for (name, var) in vars.vars.clone() { + if var.vtype != VariableType::Func { + continue; + } let mut dparams = String::new(); + println!("{:?}", var.params.vars); for i in 0..var.params.vars.len() { dparams += format!("params.get({}).expect(\"Err_prms\"),", i).as_str(); } @@ -93,7 +102,8 @@ fn main() { ) .as_str(); } - dll_main += "}"; + dll_main += "}}\nfn main(){}"; + //dll_main = "fn main(){}".to_string(); compile::write_to_rust_file(&transpiled_code, "build/wslib.rs") .expect("Error writing to temporary Rust file"); compile::write_to_rust_file(&dll_main, "build/main.rs") diff --git a/src/parser.rs b/src/parser.rs index 05e86f3..2ab67dc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -25,6 +25,7 @@ pub enum AstType { CodeBlock, Json, Impl, + StaticExecution, Other, } @@ -345,6 +346,12 @@ impl Parser { ast_res.tokens.push(token.clone()); } } + TokenType::StaticExecution => { + if self.tokens[index + 1].token_type == TokenType::Square { + ast_res.tokens.push(self.tokens[index + 1].clone()); + ast_res.ast_type = AstType::StaticExecution; + } + } _ => { ast_res.tokens.push(token.clone()); } diff --git a/src/transpiler.rs b/src/transpiler.rs index dc024a6..190ae76 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -1,7 +1,7 @@ use crate::{ file_writer::FileWriter, lexer::{lex, LexerState, TokenType}, - lspcom::Problem, + lspcom::{Problem, ProblemType}, parser::{is_decl, Ast, AstType, Parser}, variable::{VariableType, Variables}, }; @@ -260,30 +260,39 @@ impl Transpiler { ) .as_str(); } else if ast.ast_type == AstType::Include { - let modname = self.writer.add( - Path::new("lib") - .join(&ast.tokens[0].value.clone()) - .to_str() - .expect("ErrConvStr0") - .to_string(), - variables, - ); - result += "mod "; - result += modname.as_str(); - result += ";\n"; - result += "use "; - result += modname.as_str(); - result += "::*;\n"; - self.modnum += 1; + match self + .writer + .add(ast.tokens[0].value.clone(), variables, true) + { + Ok(modname) => { + result += "mod "; + result += modname.as_str(); + result += ";\n"; + result += "use "; + result += modname.as_str(); + result += "::*;\n"; + } + Err(ptype) => { + self.problems.push(ptype); + } + } } else if ast.ast_type == AstType::IncludeLocal { - let modname = self.writer.add(ast.tokens[0].value.clone(), variables); - result += "mod "; - result += modname.as_str(); - result += ";\n"; - result += "use "; - result += modname.as_str(); - result += "::*;\n"; - self.modnum += 1; + match self + .writer + .add(ast.tokens[0].value.clone(), variables, false) + { + Ok(modname) => { + result += "mod "; + result += modname.as_str(); + result += ";\n"; + result += "use "; + result += modname.as_str(); + result += "::*;\n"; + } + Err(ptype) => { + self.problems.push(ptype); + } + } } else if ast.ast_type == AstType::State3 { result += format!( "{} {} {}", @@ -342,6 +351,14 @@ impl Transpiler { ) .as_str(); } + } else if ast.ast_type == AstType::StaticExecution { + result += r#"use serde::Deserialize; +use serde_json::Value; +#[derive(Deserialize, Debug)] +struct Request(i32, String, Vec<(bool, Value)>); +#[derive(Deserialize, Debug)] +struct Response(i32, Vec<(bool, Value)>); +"#; } else if ast.ast_type == AstType::Ref { result += "&mut "; result += ast.tokens[0].value.as_str(); diff --git a/src/variable.rs b/src/variable.rs index c722684..127d4e4 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use rand::Rng; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::{ lexer::LexerState, @@ -9,7 +9,7 @@ use crate::{ transpiler::Transpiler, }; -#[derive(Clone, PartialEq, Debug, Serialize)] +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub enum VariableType { Var, Func, @@ -18,7 +18,7 @@ pub enum VariableType { Namespace, } -#[derive(Clone, Debug, Serialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Variable { pub vtype: VariableType, pub desc: String, @@ -27,7 +27,7 @@ pub struct Variable { pub rname: String, } -#[derive(Clone, Debug, Serialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Variables { pub vars: HashMap, } @@ -142,7 +142,6 @@ impl Variables { return x.rname.clone(); } else { root.problems.push(Problem { - code: 1, problem_type: ProblemType::VariableNotFound, problem_msg: format!("Variable '{}' doesn't exist", &name), });