diff --git a/Cargo.toml b/Cargo.toml index feb4029..5f466cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -regex = "1.10.4" -once_cell = "1.19.0" -clap = { version = "4.0", features = ["derive"] } rand = "0.8.5" serde_json = "1.0" serde = "1.0.203" @@ -16,3 +13,7 @@ serde_derive = "1.0.203" lsp-types = "0.97.0" zip = "2.1.3" dirs = "5.0.1" +pest = "2" +pest_derive = "2.1" +clap = "3" +hex = "0.4" diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..d41d038 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,4 @@ +# Wyst stdlib + +## > [!NOTE] +> any changes made here should be documented before pushed to master diff --git a/lib/stdio.rs b/lib/stdio.rs new file mode 100644 index 0000000..1e2f3de --- /dev/null +++ b/lib/stdio.rs @@ -0,0 +1,7 @@ +#[macro_export] + +macro_rules! _0x7072696e7466 { + ($($arg:tt)*) => { + print!($($arg)*); + }; +} diff --git a/src/compile.rs b/src/compile.rs deleted file mode 100644 index 032a5f1..0000000 --- a/src/compile.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::fs; -use std::io::{Error, ErrorKind}; -use std::path::Path; -use std::process::Command; - -pub fn write_to_rust_file(transpiled_code: &str, file_name: &str) -> Result<(), Error> { - // Determine the file extension based on the provided file_name - let mut output_file = String::from(file_name); - if let Some(extension) = Path::new(file_name).extension() { - if let Some(ext_str) = extension.to_str() { - // Replace the existing extension with ".rs" if it's not already ".rs" - if ext_str != "rs" { - output_file.push_str(".rs"); - } - } - } else { - // If no extension is provided, append ".rs" to the file_name - output_file.push_str(".rs"); - } - - // Write the transpiled_code to the determined output file - fs::write(&output_file, transpiled_code)?; - - Ok(()) -} - -pub fn compile_to_executable(output_exe: &str) -> Result<(), Error> { - let output = Command::new("rustc") - .arg("main.rs".to_string()) - .arg("-o") - .arg(output_exe) - .output()?; - - // Check if compilation was successful - if output.status.success() { - println!("Compilation successful!"); - } else { - if let Some(code) = output.status.code() { - eprintln!("Compilation failed with error code: {}", code); - } - if !output.stdout.is_empty() { - eprintln!( - "Compiler output:\n{}", - String::from_utf8_lossy(&output.stdout) - ); - } - if !output.stderr.is_empty() { - eprintln!( - "Compiler errors:\n{}", - String::from_utf8_lossy(&output.stderr) - ); - } - return Err(Error::new(ErrorKind::Other, "Compilation failed")); - } - - Ok(()) -} diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 0000000..b4270d9 --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,90 @@ +use std::str; +use std::{fs, path::Path, process::Command}; + +use crate::{ + transpiler::{State, Transpiler}, + utils::{Problem, ProblemCap, ProblemType}, +}; + +pub fn transpile_file(input_file: String, output_file: String, is_main: bool) -> u8 { + let mut ecode: u8 = 0; + let mut trsp = Transpiler { + ..Default::default() + }; + if let Ok(file_contents) = fs::read_to_string(input_file) { + let mut module_code = String::new(); + let mut output_code = String::new(); + match trsp.transpile_code(file_contents, 0) { + Ok(rcode) => output_code += rcode.as_str(), + Err(e) => { + ecode = 1; + println!("{e}") + } + } + if is_main { + for module in trsp.clone().mod_manager.modules { + module_code += "mod "; + module_code += module.rs_mod.as_str(); + module_code += ";\n"; + } + } + output_code = format!( + "{module_code}\n{output_code}\nfn main() {}{}{}", + "{_0x", + hex::encode("main"), + "();}" + ); + if let Ok(_) = fs::write(Path::new("build").join(output_file), output_code) { + trsp.problems.append(&mut trsp.mod_manager.write()); + } + } else { + trsp.problems.push(ProblemCap::Error(Problem { + problem_msg: "File not found".to_string(), + problem_type: ProblemType::FileNotFound, + state: State { + line: 0, + column: 0, + file: None, + }, + })) + } + for p in trsp.problems { + match p { + ProblemCap::Error(problem) => { + ecode = 1; + if problem.state.file == None { + println!( + "\x1b[31;1m{:?}\x1b[0;1m: {}", + problem.problem_type, problem.problem_msg, + ) + } else { + println!( + "\x1b[31;1mError\x1b[0;1m: {}\x1b[0m\n{}:{}: {:?}", + problem.problem_msg, + problem.state.line, + problem.state.column, + problem.problem_type, + ) + } + } + } + } + ecode +} + +pub fn compile_rust(exe_file: String) { + let output = Command::new("rustc") + .arg(Path::new("build").join("main.rs")) + .arg("-o") + .arg(exe_file.clone()) + .output() + .expect("Error compiling rust: "); + if &output.stderr.len() == &0 { + println!("Compiled successfully: \x1b[34;4m{}", exe_file.clone()); + } else { + println!( + "{}", + str::from_utf8(&output.stderr).expect("Error encoding stderr") + ); + } +} diff --git a/src/dllmgr.rs b/src/dllmgr.rs deleted file mode 100644 index c81f064..0000000 --- a/src/dllmgr.rs +++ /dev/null @@ -1,76 +0,0 @@ -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 deleted file mode 100644 index 6559a5b..0000000 --- a/src/file_writer.rs +++ /dev/null @@ -1,197 +0,0 @@ -use std::{collections::HashMap, fs, path::Path}; - -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 { - pub file_ws: String, - pub file_rs: String, - pub mod_rs: String, - pub _code: String, - pub code_rs: String, -} - -#[derive(Clone, Debug)] -pub struct FileWriter { - pub files: Vec, - pub mod_num: u32, - pub _projpath: String, -} - -impl FileWriter { - pub fn new(_projpath: String) -> FileWriter { - FileWriter { - files: Vec::new(), - mod_num: 0, - _projpath, - } - } - pub fn write(&mut self) { - for module in &self.files { - fs::write(&module.file_rs, &module.code_rs).expect("WriteErr: can't write to file"); - } - } - /*Checks if a path has already been imported*/ - pub fn check(&mut self, filepath: String) -> Option<&Module> { - for module in &self.files { - if filepath == module.file_ws { - return Some(module); - } - } - return None; - } - pub fn expand(&mut self, writer: FileWriter) { - for module in writer.files { - self.files.push(module); - } - } - 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 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), - }), - } - } -} diff --git a/src/lexer.rs b/src/lexer.rs deleted file mode 100644 index 8f98af3..0000000 --- a/src/lexer.rs +++ /dev/null @@ -1,439 +0,0 @@ -use once_cell::sync::Lazy; -use regex::Regex; -use serde::{Deserialize, Serialize}; -use std::fmt; -#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)] -pub struct LexerState { - pub line: usize, - pub column: usize, -} - -// Define token types -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum TokenType { - Keyword, - Keyword1, - Keyword2, - Newline, - Whitespace, - Number, - Identifier, - Ptr, - Operator, - SecondOperator, - Semicolon, - Round, - Curly, - Square, - Angle, - Include, - String, - Comment, - StaticExecution, - // EOF, -} - -#[derive(Clone)] -pub struct Token { - pub token_type: TokenType, - pub value: String, - pub line: usize, - pub column: usize, -} - -impl fmt::Debug for Token { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(TokenType: {:?}, TokenValue: {}, Line: {}, Column {})", - self.token_type, - self.value.replace("\n", "\\n"), - self.line, - self.column - ) - } -} - -impl fmt::Display for Token { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(\x1b[33mTokenType:\x1b[0m \x1b[35m{:?}\x1b[0m, \x1b[33mTokenValue:\x1b[0m \x1b[32m\"{}\"\x1b[0m, \x1b[33mLine:\x1b[0m \x1b[36m{}\x1b[0m, \x1b[33mColumn:\x1b[0m \x1b[36m{}\x1b[0m)", self.token_type, self.value.replace("\n", "\\n"), self.line, self.column) - } -} - -pub struct Node { - token_type: TokenType, - token_regex: Lazy, -} - -const SYNTAX: [Node; 17] = [ - Node { - token_type: TokenType::Semicolon, - token_regex: Lazy::new(|| Regex::new(r"^\;").unwrap()), - }, - Node { - token_type: TokenType::SecondOperator, - token_regex: Lazy::new(|| Regex::new(r"^,").unwrap()), - }, - Node { - token_type: TokenType::String, - token_regex: Lazy::new(|| Regex::new("^\"").unwrap()), - }, - Node { - token_type: TokenType::Whitespace, - token_regex: Lazy::new(|| Regex::new(r"^\s+").unwrap()), - }, - Node { - token_type: TokenType::Keyword, - token_regex: Lazy::new(|| { - Regex::new(r"^(pub|mut|try|catch|return|fn|let|use|cb|struct|impl|in|as)\b").unwrap() - }), - }, - Node { - token_type: TokenType::Keyword1, - token_regex: Lazy::new(|| { - Regex::new(r"^(impl|namespace|if|for|while|else *if)\b").unwrap() - }), - }, - Node { - token_type: TokenType::Keyword2, - token_regex: Lazy::new(|| Regex::new(r"^(else)\b").unwrap()), - }, - Node { - token_type: TokenType::Identifier, - token_regex: Lazy::new(|| Regex::new(r"^[.:_a-zA-Z][a-zA-Z0-9_.:]*").unwrap()), - }, - Node { - token_type: TokenType::Number, - token_regex: Lazy::new(|| Regex::new(r"^\d+").unwrap()), - }, - Node { - token_type: TokenType::Ptr, - token_regex: Lazy::new(|| Regex::new(r"^->").unwrap()), - }, - Node { - token_type: TokenType::Operator, - token_regex: Lazy::new(|| Regex::new(r"^[\&\&|\-|\+|\*|\=|\!|\&|\:]").unwrap()), - }, - Node { - token_type: TokenType::Round, - token_regex: Lazy::new(|| Regex::new(r"^[\(|\)]").unwrap()), - }, - Node { - token_type: TokenType::Curly, - token_regex: Lazy::new(|| Regex::new(r"^[\{|\}]").unwrap()), - }, - Node { - token_type: TokenType::Square, - token_regex: Lazy::new(|| Regex::new(r"^[\[|\]]").unwrap()), - }, - Node { - token_type: TokenType::Include, - token_regex: Lazy::new(|| Regex::new(r"^#include *<(.*?)>").unwrap()), - }, - Node { - 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 { - value.chars().next().unwrap().to_string() -} - -pub fn lex( - mut code: &str, - use_whitespace: bool, - state: LexerState, -) -> Result, (LexerState, Vec)> { - let mut state = state; - let mut tokens: Vec = Vec::new(); - let mut brstr: String = String::new(); - let mut br_state: LexerState = LexerState { line: 0, column: 0 }; - let mut brtp: Vec = Vec::new(); - while !code.is_empty() { - let mut is_match = false; - let fch = get_first_char(code); - let brln = brtp.len(); - match fch.as_str() { - "/" => { - brstr += "/"; - code = code.strip_prefix(fch.as_str()).expect(""); - if brln == 0 { - if code.len() > 0 { - let sch = get_first_char(code); - if sch == "/" { - code = code.strip_prefix(sch.as_str()).expect(""); - brstr += &sch; - brtp.push(4); - if brln > 0 { - brstr += fch.as_str(); - } else { - br_state.line = state.line; - br_state.column = state.column; - } - } else if sch == "*" { - code = code.strip_prefix(sch.as_str()).expect(""); - brstr += &sch; - brtp.push(5); - if brln > 0 { - brstr += fch.as_str(); - } else { - br_state.line = state.line; - br_state.column = state.column; - } - } else if brln == 0 { - tokens.push(Token { - token_type: TokenType::Operator, - value: "/".to_string(), - column: state.column, - line: state.line, - }); - } - } else if brln == 0 { - tokens.push(Token { - token_type: TokenType::Operator, - value: "*".to_string(), - column: state.column, - line: state.line, - }); - } - } - } - "\"" => { - brstr += "\""; - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 && brtp[brln - 1] == 0 { - brtp.pop(); - tokens.push(Token { - token_type: TokenType::String, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } else if brln == 0 { - brtp.push(0); - br_state.line = state.line; - br_state.column = state.column; - } - } - "'" => { - brstr += "'"; - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 && brtp[brln - 1] == 1 { - brtp.pop(); - tokens.push(Token { - token_type: TokenType::String, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } else if brln == 0 { - brtp.push(1); - br_state.line = state.line; - br_state.column = state.column; - } - } - "(" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 { - brstr += fch.as_str(); - } else { - br_state.line = state.line; - br_state.column = state.column; - } - brtp.push(2); - } - ")" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 && brtp[brln - 1] == 2 { - brtp.pop(); - if brln == 1 { - tokens.push(Token { - token_type: TokenType::Round, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } else { - brstr += fch.as_str(); - } - } else { - brstr += fch.as_str(); - } - } - "{" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 { - brstr += fch.as_str(); - } else { - br_state.line = state.line; - br_state.column = state.column; - } - brtp.push(3); - } - "}" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 && brtp[brln - 1] == 3 { - brtp.pop(); - if brln == 1 { - tokens.push(Token { - token_type: TokenType::Curly, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } else { - brstr += fch.as_str(); - } - } else { - brstr += fch.as_str(); - } - } - "[" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 { - brstr += fch.as_str(); - } else { - br_state.line = state.line; - br_state.column = state.column; - } - brtp.push(3); - } - "]" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 && brtp[brln - 1] == 3 { - brtp.pop(); - if brln == 1 { - tokens.push(Token { - token_type: TokenType::Square, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } else { - brstr += fch.as_str(); - } - } else { - brstr += fch.as_str(); - } - } - "<" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 { - brstr += fch.as_str(); - } else { - br_state.line = state.line; - br_state.column = state.column; - } - brtp.push(6); - } - ">" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 && brtp[brln - 1] == 6 { - brtp.pop(); - if brln == 1 { - tokens.push(Token { - token_type: TokenType::Angle, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } else { - brstr += fch.as_str(); - } - } else { - brstr += fch.as_str(); - } - } - "\\" => { - brstr += "\\"; - code = code.strip_prefix(fch.as_str()).expect(""); - if code.len() > 0 { - let sch = get_first_char(code); - code = code.strip_prefix(sch.as_str()).expect(""); - brstr += &sch; - } - } - "\n" => { - code = code.strip_prefix(fch.as_str()).expect(""); - if brln > 0 { - brstr += "\n"; - } - if brln == 1 && brtp[0] == 4 { - brtp.pop(); - tokens.push(Token { - token_type: TokenType::Comment, - value: brstr.clone(), - column: br_state.column, - line: br_state.line, - }); - brstr = String::new(); - } - state.line += 1; - state.column = 0; - } - _ => { - if brln > 0 { - code = code.strip_prefix(fch.as_str()).expect(""); - brstr += fch.as_str(); - } else { - for s in &SYNTAX { - if let Some(caps) = s.token_regex.captures(code) { - is_match = true; - code = code.strip_prefix(&caps[0]).unwrap_or(code); - if (!use_whitespace && s.token_type != TokenType::Whitespace) - || use_whitespace - { - let cap = caps[0].to_string(); - match cap.as_str() { - "int" => { - tokens.push(Token { - token_type: s.token_type, - value: "i32".to_string(), - line: state.line, - column: state.column, - }); - } - "float" => { - tokens.push(Token { - token_type: s.token_type, - value: "f32".to_string(), - line: state.line, - column: state.column, - }); - } - _ => { - tokens.push(Token { - token_type: s.token_type, - value: cap, - line: state.line, - column: state.column, - }); - } - } - } - state.column += caps[0].len(); - } else { - continue; - }; - break; - } - if !is_match { - return Err((state, tokens)); - } - } - } - } - } - Ok(tokens) -} diff --git a/src/lsp.rs b/src/lsp.rs deleted file mode 100644 index af8dead..0000000 --- a/src/lsp.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::{ - lspcom::{get_completion, get_items, request_methods, LspServer, TextDocumentChangeParams}, - variable::Variables, -}; -use lsp_types::*; -use once_cell::sync::Lazy; -use regex::Regex; -use serde_json::{self, json, Value}; -use std::{ - collections::HashMap, - fs, - io::{stdin, stdout, Read, Write}, - path::Path, -}; - -#[derive(Debug)] -pub struct Server { - documents: HashMap, -} - -impl LspServer for Server { - fn initialize(&mut self) -> InitializeResult { - InitializeResult { - capabilities: ServerCapabilities { - completion_provider: Some(CompletionOptions { - trigger_characters: Some(vec![".".to_string()]), - ..Default::default() - }), - ..Default::default() - }, - ..Default::default() - } - } - fn completion(&mut self, params: CompletionParams) -> CompletionResponse { - let text = self - .documents - .get(params.text_document_position.text_document.uri.as_str()) - .expect("err_textdoc"); - let items: Variables = get_completion( - text.clone(), - params.text_document_position.position.line as usize + 1, - params.text_document_position.position.character as usize, - ); - CompletionResponse::Array(get_items(items, "".to_string())) - } - fn did_change(&mut self, params: TextDocumentChangeParams) { - self.documents.insert(params.uri, params.text); - } -} - -pub fn run_lsp_server() { - if Path::new("/home/leo/work/wyst/log.txt").exists() { - fs::remove_file("/home/leo/work/wyst/log.txt").unwrap(); - } - let clpattern = Lazy::new(|| Regex::new(r"^Content-Length: (\d+)").unwrap()); - let mut reader = stdin(); - let mut server = Server { - documents: HashMap::new(), - }; - loop { - let mut input = String::new(); - if reader.read_line(&mut input).is_err() { - continue; - } - let stdout = stdout(); - let mut handle = stdout.lock(); - - if let Some(caps) = clpattern.captures(&input) { - let content_len = caps[1].parse::().unwrap() + 2; - let mut buf = vec![0u8; content_len]; - if reader.read_exact(&mut buf).is_err() { - continue; - } - let json_string = String::from_utf8(buf).expect("Our bytes should be valid utf8"); - let client_json: Value = serde_json::from_str(&json_string).expect("err_json"); - let response = match client_json["method"].as_str().unwrap() { - request_methods::INITIALIZE => { - serde_json::to_string(&json!({ - "jsonrpc": "2.0", - "id": client_json["id"].as_u64().unwrap(), - "result": server.initialize() - })) - .unwrap() - } - request_methods::COMPLETION => serde_json::to_string(&json!({ - "jsonrpc": "2.0", - "id": client_json["id"].as_u64().unwrap(), - "result": server.completion(serde_json::from_value(serde_json::to_value(client_json["params"].as_object()).expect("err_pars2")).unwrap()) - })) - .unwrap(), - request_methods::DID_CHANGE =>{ - server.did_change(serde_json::from_value(serde_json::to_value(client_json["params"].as_object()).expect("err_pars2")).expect("err_pars3")); - "None".to_string()}, - request_methods::INITIALIZED => "None".to_string(), - request_methods::SHUTDOWN => { - return; - } - _ => { - continue; - } - }; - if response != "None" { - let header = format!( - "Content-Length: {}\r\n\r\n{}", - response.trim().len(), - response.trim() - ); - handle - .write_all(header.as_bytes()) - .expect("err_write_stdin"); - handle.flush().expect("err_flush_stdin"); - } - } else { - } - } -} diff --git a/src/lspcom.rs b/src/lspcom.rs deleted file mode 100644 index 1ac6a7c..0000000 --- a/src/lspcom.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::{ - transpiler::Transpiler, - variable::{VariableType, Variables}, -}; -use lsp_types::{ - CompletionItem, CompletionItemKind, CompletionParams, CompletionResponse, InitializeResult, -}; -use rand::{thread_rng, Rng}; -use serde::{Deserialize, Serialize}; - -pub fn place_at(input: String, in2: String, line_goal: usize, column_goal: usize) -> String { - let mut line: usize = 1; - let mut column: usize = 0; - let mut out = String::new(); - for c in input.chars() { - out += c.to_string().as_str(); - column += 1; - if c == '\n' { - line += 1; - column = 0; - } else if line == line_goal && column == column_goal { - out += in2.as_str(); - column += 1 - } - } - out -} - -pub fn get_completion(input: String, line: usize, column: usize) -> Variables { - let rand_id: u32 = thread_rng().gen(); - let rand_id: String = rand_id.to_string(); - let mut transpiler = Transpiler { - peek: rand_id.clone(), - ..Default::default() - }; - let mut vars = Variables::new(); - transpiler.transpile(place_at(input, rand_id, line, column), 0, &mut vars); - transpiler.matched_vars -} - -pub mod request_methods { - pub const INITIALIZE: &str = "initialize"; - pub const COMPLETION: &str = "textDocument/completion"; - pub const INITIALIZED: &str = "initialized"; - pub const SHUTDOWN: &str = "shutdown"; - pub const DID_CHANGE: &str = "textDocument/didChange"; -} - -pub trait LspServer { - fn did_change(&mut self, _params: TextDocumentChangeParams) {} - fn completion(&mut self, _params: CompletionParams) -> CompletionResponse { - CompletionResponse::Array(vec![]) - } - fn initialize(&mut self) -> InitializeResult { - InitializeResult::default() - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct TextDocumentChangeParams { - pub uri: String, - pub text: String, -} - -pub fn get_items(mut items: Variables, lname: String) -> Vec { - let mut completion_items: Vec = Vec::new(); - for (name, var) in items.iter_mut() { - let mut item = CompletionItem::new_simple(lname.clone() + &name, var.desc.clone()); - if var.vtype != VariableType::Func { - completion_items.extend( - get_items(var.params.clone(), name.to_owned() + "::") - .iter() - .cloned(), - ) - } else { - // item.documentation = Some(Documentation::MarkupContent(MarkupContent { - // kind: MarkupKind::Markdown, - // value: "Markup".to_string(), - // })); - } - match var.vtype { - VariableType::Func => { - item.kind = Some(CompletionItemKind::FUNCTION); - } - VariableType::Var => { - item.kind = Some(CompletionItemKind::VARIABLE); - } - VariableType::Keyword => { - item.kind = Some(CompletionItemKind::KEYWORD); - } - VariableType::Struct => { - item.kind = Some(CompletionItemKind::STRUCT); - } - VariableType::Namespace => { - item.kind = Some(CompletionItemKind::MODULE); - } - } - completion_items.push(item); - } - completion_items -} - -#[derive(Clone, Debug)] -pub enum ProblemType { - VariableNotFound, - FileNotFound, - HeaderSyntaxError, -} - -#[derive(Clone, Debug)] -pub struct Problem { - //pub code: u32, - pub problem_type: ProblemType, - pub problem_msg: String, -} diff --git a/src/main.rs b/src/main.rs index 494d6d3..cfaccb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,120 +1,55 @@ -mod compile; -mod dllmgr; -mod file_writer; -mod lexer; -mod lsp; -mod lspcom; -mod parser; +use std::{fs, process}; +mod compiler; mod transpiler; -mod variable; -use clap::Parser; -use std::{fs, path::Path}; -use transpiler::Transpiler; -use variable::{Variable, VariableType, Variables}; +mod utils; -use crate::lsp::run_lsp_server; - -// Arguments for Wyst (short and long version) -#[derive(Parser)] -struct Args { - //#[clap(short, long)] - //rust: Option, - #[clap(short, long)] - compile: Option, - - #[clap(short, long)] - dll: Option, - - #[clap(long)] - stdio: bool, -} +use clap::{App, Arg}; +use compiler::{compile_rust, transpile_file}; fn main() { - let args = Args::parse(); - match args.stdio { - true => { - run_lsp_server(); - } - false => { - match args.compile { - Some(ref exe_name) => { - let file_content = fs::read_to_string("main.wt").expect("Error reading file"); - if Path::new("build").exists() { - fs::remove_dir_all("build").expect("err rm build"); - } - fs::create_dir("build").expect("error making build"); - let mut trsp = Transpiler::default(); - let mut vars = Variables::new(); - let mut transpiled_code = trsp.transpile(file_content, 0, &mut vars); - transpiled_code += "\nfn 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_type, problem.problem_msg) - } - if trsp.problems.len() > 0 { - return; - } - trsp.writer.write(); + let matches = App::new("Wyst") + .version("0.51") + .author("Leo dev") + .about("The wyst compiler") + .arg( + Arg::with_name("file") + .required(true) + .help("Sets the input file to use"), + ) + .arg( + Arg::with_name("output") + .short('o') + .long("output") + .takes_value(true) + .help("Specifies the output binary file name"), + ) + .arg( + Arg::with_name("build") + .short('b') + .long("build") + .help("Puts the rust files in the build directory"), + ) + .arg( + Arg::with_name("stdio") + .short('s') + .long("stdio") + .help("LSP Mode"), + ) + .get_matches(); - compile::write_to_rust_file(&transpiled_code, "build/main.rs") - .expect("Error writing to temporary Rust file"); - std::env::set_current_dir("build").expect("setDir err: "); - compile::compile_to_executable(exe_name) - .expect("Error compiling to executable"); - std::env::set_current_dir("..").expect("setDir0 err: "); - fs::rename(Path::new("build").join(exe_name).as_path(), exe_name) - .expect("RenameErrBuld: "); - fs::remove_dir_all("build").expect("err rm build"); - } - None => {} - } - match args.dll { - Some(ref dll_path) => { - let file_content = fs::read_to_string("lib.wt").expect("Error reading file"); - if Path::new("build").exists() { - fs::remove_dir_all("build").expect("err rm build"); - } - fs::create_dir("build").expect("error making build"); - let mut trsp = Transpiler::default(); - let mut vars = Variables::new(); - let transpiled_code = trsp.transpile(file_content, 0, &mut vars); - for problem in trsp.problems { - println!("{}", problem.problem_msg) - } - trsp.writer.write(); - 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(); - } - dll_main += format!( - "\"{}\" => {}return {}({dparams});{}", - name, "{", var.rname, "}" - ) - .as_str(); - } - 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") - .expect("Error writing to main dll"); - std::env::set_current_dir("build").expect("setDir err: "); - compile::compile_to_executable("run").expect("Error compiling to executable"); - dllmgr::write_dll(vars, "run".to_string(), dll_path.to_string()); - // fs::remove_dir_all("build").expect("err rm build"); - } - None => {} - } + if matches.is_present("stdio") { + println!("stdio mode!"); + } else { + let file = matches.value_of("file").unwrap().to_string(); + let output = matches.value_of("output").unwrap_or("out").to_string(); + if let Ok(_) = fs::create_dir("build") {} + let ecode = transpile_file(file, "main.rs".to_string(), true); + if ecode == 0 { + compile_rust(output); } + if !matches.is_present("build") { + fs::remove_dir_all("build").expect("Error removing build"); + } + process::exit(ecode as i32); } } diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 2ab67dc..0000000 --- a/src/parser.rs +++ /dev/null @@ -1,365 +0,0 @@ -use crate::{ - lexer::{LexerState, Token, TokenType}, - variable::Variables, -}; -use once_cell::sync::Lazy; -use regex::Regex; -use std::fmt; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum AstType { - Ref, - FunctionDeceleration, - StructDeceleration, - StructCall, - StructVar, - VoidFunctionDeceleration, - Namespace, - VariableDeceleration, - PointerDeceleration, - MutVariableDeceleration, - State3, - State2, - Include, - IncludeLocal, - CodeBlock, - Json, - Impl, - StaticExecution, - Other, -} - -pub fn is_decl(ast: &Ast) -> bool { - ast.ast_type == AstType::FunctionDeceleration - || ast.ast_type == AstType::VoidFunctionDeceleration - || ast.ast_type == AstType::Namespace - || ast.ast_type == AstType::VariableDeceleration - || ast.ast_type == AstType::PointerDeceleration - || ast.ast_type == AstType::MutVariableDeceleration - || ast.ast_type == AstType::StructDeceleration -} - -pub struct Ast { - pub tokens: Vec, - pub ast_type: AstType, -} - -impl fmt::Display for Ast { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "\x1b[36m{:?}:\x1b[0m [\n", self.ast_type)?; - for (i, token) in self.tokens.iter().enumerate() { - if i < self.tokens.len() - 1 { - write!(f, " {},\n", token)?; - } else { - write!(f, " {}\n", token)?; - } - } - write!(f, "]") - } -} - -impl fmt::Debug for Ast { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}: [\n", self.ast_type)?; - for (i, token) in self.tokens.iter().enumerate() { - if i < self.tokens.len() - 1 { - write!(f, " {:?},\n", token)?; - } else { - write!(f, " {:?}\n", token)?; - } - } - write!(f, "]") - } -} - -pub struct Parser { - pub tokens: Vec, - pub index: u32, - pub include_regex: Lazy, - pub include_regex_local: Lazy, - pub variables: Variables, - pub json: bool, -} - -impl Parser { - pub fn new(tokens: Vec, variables: Variables) -> Parser { - Parser { - tokens: tokens, - index: 0, - include_regex: Lazy::new(|| Regex::new(r"^(#include *)<(.*?)>").unwrap()), - include_regex_local: Lazy::new(|| Regex::new(r#"^(#include *)"(.*?)""#).unwrap()), - variables: variables, - json: false, - } - } - pub fn parse(&mut self) -> Vec { - let mut full_ast: Vec = Vec::new(); - while self.tokens.len() > self.index as usize { - let mut ast_res: Ast = Ast { - tokens: vec![], - ast_type: AstType::Other, - }; - let index = self.index as usize; - if index == self.tokens.len() { - panic!("Reached the end of tokens") - } - let token = &self.tokens[index]; - if self.json - && self.tokens.len() - (self.index as usize) > 2 - && self.tokens[index + 1].value == ":" - { - ast_res.ast_type = AstType::Json; - ast_res.tokens.push(self.tokens[index].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - self.index += 2; - } else if self.tokens.len() - index > 1 - && self.tokens[index].value == "&" - && self.tokens[index + 1].token_type == TokenType::Identifier - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.ast_type = AstType::Ref; - self.index += 1; - } else if self.tokens.len() - index > 2 - && self.tokens[index].value == "struct" - && self.tokens[index + 1].token_type == TokenType::Identifier - && self.tokens[index + 2].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.ast_type = AstType::StructDeceleration; - self.index += 2; - let mut desc = String::new(); - if index > 0 && self.tokens[index - 1].token_type == TokenType::Comment { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_struct( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } else if self.tokens.len() - index > 2 - && self.tokens[index].value == "namespace" - && self.tokens[index + 1].token_type == TokenType::Identifier - && self.tokens[index + 2].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.ast_type = AstType::Namespace; - self.index += 2; - let mut desc = String::new(); - if index > 0 && self.tokens[index - 1].token_type == TokenType::Comment { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_namespace( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } else if self.tokens.len() - index > 2 - && self.tokens[index].value == "impl" - && self.tokens[index + 1].token_type == TokenType::Identifier - && self.tokens[index + 2].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.ast_type = AstType::Impl; - self.index += 2; - } else if self.tokens.len() - index > 2 - && self.tokens[index].token_type == TokenType::Keyword1 - && self.tokens[index + 1].token_type == TokenType::Round - && self.tokens[index + 2].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index].clone()); - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.ast_type = AstType::State3; - self.index += 2; - } else if self.tokens.len() - index > 1 - && self.tokens[index].token_type == TokenType::Keyword2 - && self.tokens[index + 1].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index].clone()); - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.ast_type = AstType::State2; - self.index += 1; - } else { - match token.token_type { - TokenType::Identifier => { - ast_res.tokens.push(self.tokens[index].clone()); - if self.tokens.len() - index > 3 - && self.tokens[index + 1].token_type == TokenType::Identifier - && self.tokens[index + 2].token_type == TokenType::Round - && self.tokens[index + 3].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.tokens.push(self.tokens[index + 3].clone()); - if token.value == "void" { - ast_res.ast_type = AstType::VoidFunctionDeceleration; - } else { - ast_res.ast_type = AstType::FunctionDeceleration; - } - self.index += 3; - let mut desc = String::new(); - if index > 0 && self.tokens[index - 1].token_type == TokenType::Comment - { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_func( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } else if self.tokens.len() - index > 1 - && self.tokens[index + 1].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.ast_type = AstType::StructCall; - self.index += 1; - } else if self.tokens.len() - index > 2 - && self.tokens[index + 1].token_type == TokenType::Identifier - && self.tokens[index + 2].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.ast_type = AstType::StructVar; - self.index += 2; - let mut desc = String::new(); - if index > 0 && self.tokens[index - 1].token_type == TokenType::Comment - { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_var( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } else if self.tokens.len() - index > 1 { - if self.tokens[index + 1].token_type == TokenType::Identifier { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.ast_type = AstType::VariableDeceleration; - self.index += 1; - let mut desc = String::new(); - if index > 0 - && self.tokens[index - 1].token_type == TokenType::Comment - { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_var( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } else if self.tokens.len() - index > 2 - && self.tokens[index + 2].token_type == TokenType::Identifier - && self.tokens[index + 1].token_type == TokenType::Angle - { - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.tokens[0].value += "<"; - ast_res.tokens[0].value += self.tokens[index + 1].value.as_str(); - ast_res.tokens[0].value += ">"; - ast_res.ast_type = AstType::VariableDeceleration; - self.index += 2; - let mut desc = String::new(); - if index > 0 - && self.tokens[index - 1].token_type == TokenType::Comment - { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_var( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } else if self.tokens.len() - index > 2 - && self.tokens[index + 1].value == "*" - && self.tokens[index + 2].token_type == TokenType::Identifier - { - ast_res.tokens.push(self.tokens[index + 2].clone()); - ast_res.ast_type = AstType::PointerDeceleration; - self.index += 2; - let mut desc = String::new(); - if index > 0 - && self.tokens[index - 1].token_type == TokenType::Comment - { - desc = self.tokens[index - 1].value.clone() - } - self.variables.new_var( - self.tokens[index + 1].clone().value, - LexerState { - line: self.tokens[index + 1].clone().line, - column: self.tokens[index + 1].clone().column, - }, - desc, - ); - } - } - } - TokenType::Include => { - if let Some(caps) = self.include_regex.captures(&token.value) { - ast_res.tokens.push(Token { - token_type: TokenType::String, - value: caps[2].to_owned().to_string(), - line: 0, - column: 0, - }); - ast_res.ast_type = AstType::Include; - } else if let Some(caps) = self.include_regex_local.captures(&token.value) { - ast_res.tokens.push(Token { - token_type: TokenType::String, - value: caps[2].to_owned().to_string(), - line: 0, - column: 0, - }); - ast_res.ast_type = AstType::IncludeLocal; - } else { - ast_res.tokens.push(token.clone()); - ast_res.ast_type = AstType::Include; - } - } - TokenType::Keyword => { - if token.value == "cb" - && self.tokens[index + 1].token_type == TokenType::Curly - { - ast_res.tokens.push(self.tokens[index + 1].clone()); - ast_res.ast_type = AstType::CodeBlock; - self.index += 1; - } else { - 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()); - } - } - } - self.index += 1; - full_ast.push(ast_res); - } - full_ast - } -} diff --git a/src/transpiler.rs b/src/transpiler.rs index 190ae76..ef83d54 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -1,880 +1,186 @@ -use crate::{ - file_writer::FileWriter, - lexer::{lex, LexerState, TokenType}, - lspcom::{Problem, ProblemType}, - parser::{is_decl, Ast, AstType, Parser}, - variable::{VariableType, Variables}, -}; +use crate::utils::{ModManager, ProblemCap}; +use pest::iterators::{Pair, Pairs}; +use serde::{Deserialize, Serialize}; -use std::{fs, path::Path}; +// The Parser +use pest::{error::Error, Parser}; +use pest_derive::Parser; +#[derive(Parser)] +#[grammar = "wyst.pest"] +pub struct WystParser; + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct State { + pub line: u32, + pub column: u32, + pub file: Option, +} #[derive(Debug, Clone)] +#[allow(dead_code)] pub struct Transpiler { - pub state: LexerState, - pub auto_mut: bool, - pub auto_macro: bool, - pub auto_pub: bool, - pub macros: Vec, - pub modnum: u32, - pub peek: String, - pub matched_vars: Variables, - pub problems: Vec, - pub writer: FileWriter, + pub problems: Vec, + pub state: State, + pub inject: Inject, + pub mod_manager: ModManager, +} +#[derive(Debug, Clone)] +#[allow(dead_code)] +pub struct Inject { + pub state: State, + pub inject: bool, +} + +impl Default for Inject { + fn default() -> Self { + Inject { + inject: false, + state: State { + line: 0, + column: 0, + file: None, + }, + } + } } impl Default for Transpiler { - fn default() -> Transpiler { - let transpiler = Transpiler { - writer: FileWriter::new(".".to_string()), - state: LexerState { line: 1, column: 0 }, - auto_mut: true, - auto_macro: true, - auto_pub: false, - macros: vec![String::from("println")], - modnum: 0, - peek: String::new(), - matched_vars: Variables::new(), + fn default() -> Self { + Transpiler { + inject: Inject::default(), problems: Vec::new(), - }; - transpiler + mod_manager: ModManager::new(), + state: State { + line: 1, + column: 0, + file: None, + }, + } } } +pub fn to_indexable(pairs: Pairs) -> Vec> { + let mut arr: Vec> = Vec::new(); + for pair in pairs { + arr.push(pair) + } + arr +} + impl Transpiler { - pub fn transpile(&mut self, input: String, indent: u32, variables: &mut Variables) -> String { - let mut result = String::new(); - if indent == 0 { - // result += "type int = i32;\n"; - } else { - result += " ".repeat((indent as usize) * 2).as_str(); + pub fn transpile_pairs(&mut self, pairs: Pairs) -> String { + let mut res = String::new(); + for pair in pairs { + res += self.transpile(pair).as_str(); } - let lexer_out = lex(input.as_str(), false, self.state); + res + } + pub fn transpile(&mut self, pair: Pair) -> String { + let mut res = String::new(); + let tokens = to_indexable(pair.clone().into_inner()); + match pair.as_rule() { + Rule::func_def => { + res += format!( + "pub fn {}({}) -> {} {}\n", + self.transpile(tokens[1].clone()), + self.transpile_pairs(tokens[2].clone().into_inner()) + .as_str(), + self.transpile(tokens[0].clone()), + self.transpile(tokens[3].clone()) + ) + .as_str(); + } + Rule::var_def => { + res += format!("let mut {}: {}", tokens[1].as_str(), tokens[0].as_str()).as_str(); + } + Rule::curly => { + res += "{"; + res += &self.transpile_pairs(pair.clone().into_inner()); + res += "}"; + } + Rule::code_expr => { + res += &self.transpile_pairs(pair.clone().into_inner()); + } - match lexer_out { - Ok(tokens) => { - let mut full_ast = Parser::new(tokens.clone(), variables.clone()); - let mut last_ast = Ast { - ast_type: AstType::Other, - tokens: vec![], - }; - let f_ast = full_ast.parse(); - //variables.expand(full_ast.variables.clone()); - *variables = full_ast.variables.clone(); - //let mut variables = full_ast.variables.clone(); - for ast in f_ast { - let mut ast = ast; - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.clone().iter_mut() { - if (ctoken.line > var.state.line && var.vtype == VariableType::Var) - || var.vtype != VariableType::Var - { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } else { - for i in (if is_decl(&ast) { 1 } else { 0 })..ast.tokens.len() { - if ast.tokens[i].token_type == TokenType::Identifier { - if ast.tokens[i].value.contains(&self.peek) && self.peek != "" {} - let x = variables.get_var(ast.tokens[i].value.clone(), self); - ast.tokens[i].value = x; - } - } - } - if last_ast.tokens.len() > 0 { - let mut fl = 0; - for t in &last_ast.tokens { - fl += t.value.len() - } - if ast.tokens[ast.tokens.len() - 1].column - > last_ast.tokens[last_ast.tokens.len() - 1].column + fl - { - result += " " - .repeat( - ast.tokens[ast.tokens.len() - 1].column - - (last_ast.tokens[last_ast.tokens.len() - 1].column + fl), - ) - .as_str(); - } - } - last_ast = Ast { - ast_type: ast.ast_type.clone(), - tokens: ast.tokens.clone(), - }; + Rule::include_global => { + res += "#[allow(unused_imports)]\nuse "; + res += self + .mod_manager + .add(tokens[0].as_str().to_string(), true) + .as_str(); + res += "::*;\n"; + } + Rule::include => { + res += "#[allow(unused_imports)]\nuse "; + res += self + .mod_manager + .add(tokens[0].as_str().to_string(), false) + .as_str(); + res += "::*;\n"; + } - if ast.ast_type == AstType::FunctionDeceleration { - if self.auto_pub { - result += "pub "; - } - let mut vars: Variables = variables.clone(); - let round = self.transpile_round(ast.tokens[2].value.clone(), &mut vars); - result += format!( - "fn {}({}) -> {} {}", - ast.tokens[1].value, - round, - ast.tokens[0].value, - self.transpile( - ast.tokens[3].value.clone(), - indent + 1, - &mut (vars.clone()) - ) - ) - .as_str(); - } else if ast.ast_type == AstType::VoidFunctionDeceleration { - if self.auto_pub { - result += "pub "; - } - let mut vars: Variables = variables.clone(); - let round = self.transpile_round(ast.tokens[2].value.clone(), &mut vars); - result += format!( - "fn {}({}) {}", - ast.tokens[1].value, - round, - self.transpile( - ast.tokens[3].value.clone(), - indent + 1, - &mut (vars.clone()) - ) - ) - .as_str(); - } else if ast.ast_type == AstType::StructDeceleration { - if self.auto_pub { - result += "pub "; - } - let mut vars: Variables = variables.clone(); - let round = self.transpile_round(ast.tokens[1].value.clone(), &mut vars); - result += format!( - "struct {} {} {}", - ast.tokens[0].value, - "{\n", - round.trim_end() - ) - .replace( - "\n", - ("\n".to_string() + " ".repeat(((indent + 1) as usize) * 2).as_str()) - .as_str(), - ) - .as_str(); - result += "\n}\n"; - let vvars = variables.clone(); - if let Some(v) = variables.get_mut(ast.tokens[0].value.clone()) { - for (name, var) in vars.iter_mut() { - if !(vvars.vars.contains_key(name)) { - v.params.new_var( - name.to_string(), - LexerState { line: 0, column: 0 }, - var.desc.clone(), - ); - } - } - } - } else if ast.ast_type == AstType::VariableDeceleration { - if self.clone().auto_mut { - result += - format!("let mut {}: {}", ast.tokens[1].value, ast.tokens[0].value) - .as_str(); - } else { - result += - format!("let {}: {}", ast.tokens[1].value, ast.tokens[0].value) - .as_str(); - } - } else if ast.ast_type == AstType::MutVariableDeceleration { - result += - format!("let mut {}: {}", ast.tokens[1].value, ast.tokens[0].value) - .as_str(); - } else if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Round - { - result += format!( - "({})", - self.transpile_round( - ast.tokens[0].value.clone(), - &mut variables.clone() - ) - ) - .as_str(); - } else if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Comment - { - result += ast.tokens[0].value.clone().as_str(); - result += " ".repeat((indent as usize) * 2).as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Square - { - result += format!( - "[{}]", - self.transpile_square( - ast.tokens[0].value.clone(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column - }, - variables.clone() - ) - ) - .as_str(); - } else if ast.ast_type == AstType::CodeBlock { - result += "{"; - result += ast.tokens[0].value.as_str(); - result += "}"; - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Curly - { - result += self - .transpile_json( - ast.tokens[0].value.as_str().to_string(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column, - }, - variables.clone(), - ) - .as_str(); - // } - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Ptr { - result += "."; - } else if ast.ast_type == AstType::StructCall { - result += ast.tokens[0].value.as_str(); - result += " {"; - result += ast.tokens[1].value.as_str(); - result += "}"; - } else if ast.ast_type == AstType::StructVar { - result += format!( - "let mut {}: {} = {} {}{}{}", - ast.tokens[1].value.as_str(), - ast.tokens[0].value.as_str(), - ast.tokens[0].value.as_str(), - "{", - ast.tokens[2].value.as_str(), - "}" - ) - .as_str(); - } else if ast.ast_type == AstType::Include { - 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 { - 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!( - "{} {} {}", - ast.tokens[0].value.clone(), - self.transpile_round( - ast.tokens[1].value.clone(), - &mut variables.clone() - ), - self.transpile( - ast.tokens[2].value.clone(), - indent + 1, - &mut variables.clone() - ), - ) - .as_str(); - } else if ast.ast_type == AstType::State2 { - result += format!( - "{} {}", - ast.tokens[0].value.clone(), - self.transpile( - ast.tokens[1].value.clone(), - indent + 1, - &mut variables.clone() - ), - ) - .as_str(); - } else if ast.ast_type == AstType::Namespace { - result += format!( - "mod {} {}{}{}", - &ast.tokens[0].value.clone(), - "{", - self.transpile(ast.tokens[1].value.clone(), 0, &mut variables.clone()), - "}" - ) - .as_str(); - } else if ast.ast_type == AstType::Impl { - result += format!( - "impl {} {}{}{}", - &ast.tokens[0].value.clone(), - "{", - self.transpile(ast.tokens[1].value.clone(), 0, &mut variables.clone()), - "}" - ) - .as_str(); - } else if ast.ast_type == AstType::PointerDeceleration { - if self.auto_mut { - result += format!( - "let mut {}: &mut {}", - ast.tokens[1].value, ast.tokens[0].value - ) - .as_str(); - } else { - result += format!( - "let {}: &mut {}", - ast.tokens[1].value, ast.tokens[0].value - ) - .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(); - } - // flp - else { - if ast.tokens[0].token_type == TokenType::Newline { - result += (ast.tokens[0].value.as_str().to_owned() - + (" ".repeat((indent as usize) * 2).as_str())) - .as_str(); - } else if ast.tokens[0].token_type == TokenType::Semicolon { - result += ";\n"; - result += " ".repeat((indent as usize) * 2).as_str(); - } else { - result += ast.tokens[0].value.as_str(); - if self.auto_macro - && self - .macros - .contains(&ast.tokens[0].value.as_str().to_string()) - { - result += "!"; - } - } - } - } - result = result.trim_end().to_string(); - if indent > 0 { - result += "\n"; - result += " ".repeat((indent as usize - 1) * 2).as_str(); - return "{\n".to_owned() + result.as_str() + "}"; + Rule::identifier | Rule::def_identifier => { + let ident = pair.as_str().trim(); + let ident_rs = format!("_0x{}", hex::encode(ident.as_bytes())); + if self.mod_manager.macros.contains(&ident_rs) { + res += ident_rs.as_str(); + res += "!"; } else { - return result; - } - } - Err((state, _tokens)) => { - panic!("Invalid syntax at code.ws:{}:{}", state.line, state.column); - } - } - } - pub fn transpile_mod(&mut self, ast: Ast, s: &str) -> String { - let modfile = ast.tokens[0].value.as_str(); - let modname = format!( - "mod_{}", - // clean_incl(modfile.split(".").collect::>()[0]), - self.clone().modnum - ); - let file_content = fs::read_to_string(s.to_string() + modfile).expect("Error reading file"); - let transpiled_code = self.transpile(file_content, 0, &mut Variables::new()); - fs::write( - ("build/".to_string() + modname.as_str()) + ".rs", - transpiled_code, - ) - .expect("Error writing file"); - modname - } - pub fn transpile_round(&mut self, input: String, variables: &mut Variables) -> String { - let mut result = String::new(); - let lexer_out = lex(input.as_str(), false, self.state); - match lexer_out { - Ok(tokens) => { - let mut full_ast = Parser::new(tokens.clone(), variables.clone()); - let mut last_ast = Ast { - ast_type: AstType::Other, - tokens: vec![], - }; - let fast = full_ast.parse(); - *variables = full_ast.variables.clone(); - for ast in fast { - let mut ast = ast; - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.clone().iter_mut() { - if (ctoken.line > var.state.line && var.vtype == VariableType::Var) - || var.vtype != VariableType::Var - { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } else { - for i in (if is_decl(&ast) { 1 } else { 0 })..ast.tokens.len() { - if ast.tokens[i].token_type == TokenType::Identifier { - if ast.tokens[i].value.contains(&self.peek) && self.peek != "" {} - let x = variables.get_var(ast.tokens[i].value.clone(), self); - ast.tokens[i].value = x; - } - } - } - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.clone().iter_mut() { - if ctoken.line > var.state.line || var.vtype != VariableType::Var { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } - if last_ast.tokens.len() > 0 { - let mut fl = 0; - for t in &last_ast.tokens { - fl += t.value.len() - } - if ast.tokens[ast.tokens.len() - 1].column - > last_ast.tokens[last_ast.tokens.len() - 1].column + fl - { - result += " " - .repeat( - ast.tokens[ast.tokens.len() - 1].column - - (last_ast.tokens[last_ast.tokens.len() - 1].column + fl), - ) - .as_str(); - } - } - last_ast = Ast { - ast_type: ast.ast_type.clone(), - tokens: ast.tokens.clone(), + res += match ident { + "void" => "()", + _ => ident_rs.as_str(), }; - if ast.ast_type == AstType::VariableDeceleration { - result += - format!("{}: {}", ast.tokens[1].value, ast.tokens[0].value).as_str(); - } else if ast.ast_type == AstType::MutVariableDeceleration { - result += format!("mut {}: {}", ast.tokens[1].value, ast.tokens[0].value) - .as_str(); - } else if ast.ast_type == AstType::PointerDeceleration { - result += format!("{}: &mut {}", ast.tokens[1].value, ast.tokens[0].value) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Round - { - result += format!( - "({})", - self.transpile_round( - ast.tokens[0].value.clone(), - &mut variables.clone() - ) - ) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Square - { - result += format!( - "[{}]", - self.transpile_square( - ast.tokens[0].value.clone(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column - }, - variables.clone() - ) - ) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Ptr { - result += "."; - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Curly - { - result += self - .transpile_json( - ast.tokens[0].value.as_str().to_string(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column, - }, - variables.clone(), - ) - .as_str(); - } else if ast.ast_type == AstType::StructCall { - result += ast.tokens[0].value.as_str(); - result += " {"; - result += ast.tokens[1].value.as_str(); - result += "}"; - } else if ast.ast_type == AstType::Ref { - result += "&mut "; - result += ast.tokens[0].value.as_str(); - } - // flp - else { - result += ast.tokens[0].value.as_str(); - } } - - result = result.trim_end().to_string(); - result } - Err((state, _tokens)) => { - panic!("Invalid syntax at code.ws:{}:{}", state.line, state.column); + + Rule::call => { + res += " "; + res += self.transpile(tokens[0].clone()).as_str(); + res += self.transpile(tokens[1].clone()).as_str(); + } + + Rule::round => { + res += "("; + res += self.transpile_pairs(pair.into_inner()).as_str(); + res += ")"; + } + + Rule::expr => { + res += self.transpile_pairs(pair.into_inner()).as_str(); + } + + Rule::expr_ => { + res += self.transpile_pairs(pair.into_inner()).as_str(); + } + + _ => { + res += " "; + res += pair.as_str(); + res += " "; } } + res } - - pub fn transpile_square( - &mut self, - input: String, - state: LexerState, - variables: Variables, - ) -> String { - let mut result = String::new(); - let lexer_out = lex(input.as_str(), false, state); - match lexer_out { - Ok(tokens) => { - let mut full_ast = Parser::new(tokens.clone(), variables.clone()); - let mut last_ast = Ast { - ast_type: AstType::Other, - tokens: vec![], - }; - let fast = full_ast.parse(); - let mut variables = full_ast.variables.clone(); - for ast in fast { - let mut ast = ast; - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.clone().iter_mut() { - if (ctoken.line > var.state.line && var.vtype == VariableType::Var) - || var.vtype != VariableType::Var - { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } else { - for i in (if is_decl(&ast) { 1 } else { 0 })..ast.tokens.len() { - if ast.tokens[i].token_type == TokenType::Identifier { - if ast.tokens[i].value.contains(&self.peek) && self.peek != "" {} - let x = variables.get_var(ast.tokens[i].value.clone(), self); - ast.tokens[i].value = x; - } - } - } - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.iter_mut() { - if ctoken.line > var.state.line || var.vtype != VariableType::Var { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } - if last_ast.tokens.len() > 0 { - let mut fl = 0; - for t in &last_ast.tokens { - fl += t.value.len() - } - if ast.tokens[ast.tokens.len() - 1].column - > last_ast.tokens[last_ast.tokens.len() - 1].column + fl - { - result += " " - .repeat( - ast.tokens[ast.tokens.len() - 1].column - - (last_ast.tokens[last_ast.tokens.len() - 1].column + fl), - ) - .as_str(); - } - } - last_ast = Ast { - ast_type: ast.ast_type.clone(), - tokens: ast.tokens.clone(), - }; - - if ast.ast_type == AstType::VariableDeceleration { - result += - format!("{}: {}", ast.tokens[1].value, ast.tokens[0].value).as_str(); - } else if ast.ast_type == AstType::MutVariableDeceleration { - result += format!("mut {}: {}", ast.tokens[1].value, ast.tokens[0].value) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Round - { - result += format!( - "({})", - self.transpile_round( - ast.tokens[0].value.clone(), - &mut variables.clone() - ) - ) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Square - { - result += format!( - "[{}]", - self.transpile_square( - ast.tokens[0].value.clone(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column - }, - variables.clone() - ) - ) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Ptr { - result += "."; - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Curly - { - result += self - .transpile_json( - ast.tokens[0].value.as_str().to_string(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column, - }, - variables.clone(), - ) - .as_str(); - } else if ast.ast_type == AstType::StructCall { - result += ast.tokens[0].value.as_str(); - result += " {"; - result += ast.tokens[1].value.as_str(); - result += "}"; - } else if ast.ast_type == AstType::Ref { - result += "&mut "; - result += ast.tokens[0].value.as_str(); - } - // flp - else { - result += ast.tokens[0].value.as_str(); - } + pub fn transpile_code(&mut self, code: String, indent: usize) -> Result> { + let mut res = String::new(); + match WystParser::parse(Rule::top_expr, &code) { + Ok(parsed) => { + for pair in parsed { + res += self.transpile_pairs(pair.into_inner()).as_str(); } - - result = result.trim_end().to_string(); - result } - Err((state, _tokens)) => { - panic!("Invalid syntax at code.ws:{}:{}", state.line, state.column); + Err(e) => { + return Err(e); } } - } - - pub fn transpile_json( - &mut self, - input: String, - state: LexerState, - variables: Variables, - ) -> String { - let mut result = String::new(); - let lexer_out = lex(input.as_str(), false, state); - match lexer_out { - Ok(tokens) => { - let mut full_ast = Parser::new(tokens.clone(), variables.clone()); - full_ast.json = true; - result += "HashMap::from(["; - let mut last_ast = Ast { - ast_type: AstType::Other, - tokens: vec![], - }; - let fast = full_ast.parse(); - let mut variables = full_ast.variables.clone(); - for ast in fast { - let mut ast = ast; - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.clone().iter_mut() { - if (ctoken.line > var.state.line && var.vtype == VariableType::Var) - || var.vtype != VariableType::Var - { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } else { - for i in (if is_decl(&ast) { 1 } else { 0 })..ast.tokens.len() { - if ast.tokens[i].token_type == TokenType::Identifier { - if ast.tokens[i].value.contains(&self.peek) && self.peek != "" {} - let x = variables.get_var(ast.tokens[i].value.clone(), self); - ast.tokens[i].value = x; - } - } - } - if ast.ast_type == AstType::Other - && ast.tokens[0].token_type == TokenType::Identifier - && ast.tokens[0].value.contains(&self.peek) - && self.peek != "" - { - let ctoken = &ast.tokens[0]; - // let pname = ctoken.value.split(&self.peek).next().unwrap(); - for (name, var) in variables.iter_mut() { - if ctoken.line > var.state.line || var.vtype != VariableType::Var { - self.matched_vars.add( - var.vtype.clone(), - name.to_string(), - var.state, - var.desc.clone(), - ); - } - } - self.peek = String::new(); - continue; - } - if last_ast.tokens.len() > 0 { - let mut fl = 0; - for t in &last_ast.tokens { - fl += t.value.len() - } - if ast.tokens[ast.tokens.len() - 1].column - > last_ast.tokens[last_ast.tokens.len() - 1].column + fl - { - result += " " - .repeat( - ast.tokens[ast.tokens.len() - 1].column - - (last_ast.tokens[last_ast.tokens.len() - 1].column + fl), - ) - .as_str(); - } - } - last_ast = Ast { - ast_type: ast.ast_type.clone(), - tokens: ast.tokens.clone(), - }; - - if ast.ast_type == AstType::Json { - result += "("; - result += ast.tokens[0].value.as_str(); - result += ","; - result += ast.tokens[1].value.as_str(); - result += ")"; - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Round - { - result += format!( - "({})", - self.transpile_round( - ast.tokens[0].value.clone(), - &mut variables.clone() - ) - ) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Square - { - result += format!( - "[{}]", - self.transpile_square( - ast.tokens[0].value.clone(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column - }, - variables.clone() - ) - ) - .as_str(); - } else if ast.tokens.len() == 1 && ast.tokens[0].token_type == TokenType::Curly - { - result += self - .transpile_json( - ast.tokens[0].value.as_str().to_string(), - LexerState { - line: ast.tokens[0].line, - column: ast.tokens[0].column, - }, - variables.clone(), - ) - .as_str(); - } else if ast.ast_type == AstType::Ref { - result += "&mut "; - result += ast.tokens[0].value.as_str(); - } else { - result += ast.tokens[0].value.as_str(); - } - } - result += "])"; - result = result.trim_end().to_string(); - result - } - Err((state, _tokens)) => { - panic!("Invalid syntax at code.ws:{}:{}", state.line, state.column); - } + if indent > 0 { + res += " ".repeat(indent * 2).as_str(); } + + if indent > 0 { + res += "\n"; + res += " ".repeat((indent - 1) * 2).as_str(); + } + Ok(res) } } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..740fb1b --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,126 @@ +use std::fs; +use std::path::Path; +use crate::transpiler::{Rule, State, Transpiler, WystParser}; +use serde::{Deserialize, Serialize}; +use dirs::home_dir; +use pest::Parser; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ProblemType { + VariableNotFound, + FileNotFound, + HeaderSyntaxError, + SyntaxError, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ProblemCap { + Error(Problem), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Problem { + pub problem_type: ProblemType, + pub problem_msg: String, + pub state: State, +} + +#[derive(Debug, Clone)] +pub struct Module { + pub rs_mod: String, + pub file_path: String, + pub code: String +} + +#[derive(Debug, Clone)] +pub struct ModManager { + pub modules: Vec, + pub macros: Vec +} + +impl ModManager { + pub fn new() -> ModManager { + ModManager {modules: Vec::new(), macros: Vec::new()} + } + pub fn check(&mut self, path: String) -> Option { + for module in self.modules.clone() { + if module.file_path == path { + return Some(module); + } + } + None + } + pub fn add(&mut self, file_path: String, global: bool) -> String { + let mut problems: Vec = Vec::new(); + let mod_name = format!("mod_{}", self.modules.len()); + let home_dirpb = home_dir().unwrap(); + let home_dir = home_dirpb.to_str().unwrap(); + let mut file_path = file_path; + if global { + let mut tmp = Path::new(home_dir).join("wyst").join("lib").join(file_path.clone()).to_str().unwrap().to_string(); + if !Path::new(&tmp).exists() { + tmp = Path::new("lib").join(file_path).to_str().unwrap().to_string(); + } + file_path = tmp; + } + if let Some(modl) = self.check(file_path.clone()) { + return modl.rs_mod; + } + if let Ok(code) = fs::read_to_string(file_path.clone()) { + self.modules.push(Module { rs_mod: mod_name.clone(), file_path: file_path.clone(), code: code.clone() }); + match file_path.rsplit_once('.').unwrap_or(("", "")).1 { + "rs" => { + match WystParser::parse(Rule::rust_code, &code) { + Ok(parsed) => { + for pair in parsed { + for p in pair.into_inner() { + if p.as_rule() == Rule::rust_macro_lint { + self.macros.push(p.into_inner().as_str().to_string()); + } + } + } + } + Err(_) => {} + } + } + _ => {} + } + } else { + problems.push(ProblemCap::Error(Problem { + problem_msg: format!("File not found '{}'", file_path), + problem_type: ProblemType::FileNotFound, + state: State { + line: 0, + column: 0, + file: None, + }, + })) + } + mod_name + } + pub fn write(&mut self) -> Vec { + let mut problems: Vec = Vec::new(); + for module in self.modules.clone() { + let file_path = module.file_path; + match file_path.rsplit_once('.').unwrap_or(("", "")).1 { + "wst" => { + let mut trsp = Transpiler { + mod_manager: self.clone(), + ..Default::default() + }; + let rust_code = trsp.transpile_code(module.code, 0).expect(""); + fs::write(Path::new("build").join((module.rs_mod+".rs").as_str()), rust_code).expect("Error writing rust file: "); + problems.append(&mut trsp.problems); + self.modules = trsp.mod_manager.modules; + } + + "rs" => { + fs::write(Path::new("build").join((module.rs_mod+".rs").as_str()), &module.code).unwrap() + } + + _ => {} + } + } + problems + } +} \ No newline at end of file diff --git a/src/variable.rs b/src/variable.rs deleted file mode 100644 index 127d4e4..0000000 --- a/src/variable.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::collections::HashMap; - -use rand::Rng; -use serde::{Deserialize, Serialize}; - -use crate::{ - lexer::LexerState, - lspcom::{Problem, ProblemType}, - transpiler::Transpiler, -}; - -#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub enum VariableType { - Var, - Func, - Keyword, - Struct, - Namespace, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Variable { - pub vtype: VariableType, - pub desc: String, - pub state: LexerState, - pub params: Variables, - pub rname: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Variables { - pub vars: HashMap, -} - -impl Variables { - pub fn new() -> Variables { - Variables { - vars: HashMap::from([( - "void".to_string(), - Variable { - vtype: VariableType::Keyword, - desc: "".to_string(), - state: LexerState { line: 0, column: 0 }, - params: Variables { - vars: HashMap::new(), - }, - rname: "".to_string(), - }, - )]), - } - } - pub fn new_var(&mut self, name: String, state: LexerState, desc: String) { - self.vars.insert( - name, - Variable { - vtype: VariableType::Var, - desc, - state, - params: Variables { - vars: HashMap::new(), - }, - rname: generate_varname(), - }, - ); - } - - pub fn new_namespace(&mut self, name: String, state: LexerState, desc: String) { - self.vars.insert( - name, - Variable { - vtype: VariableType::Namespace, - desc, - state, - params: Variables { - vars: HashMap::new(), - }, - rname: generate_varname(), - }, - ); - } - - pub fn new_struct(&mut self, name: String, state: LexerState, desc: String) { - self.vars.insert( - name, - Variable { - vtype: VariableType::Struct, - desc, - state, - params: Variables { - vars: HashMap::new(), - }, - rname: generate_varname(), - }, - ); - } - - // pub fn new_keyword(&mut self, name: String, state: LexerState, desc: String) { - // self.vars.insert( - // name, - // Variable { - // vtype: VariableType::Keyword, - // desc, - // state, - // params: Variables { - // vars: HashMap::new(), - // }, - // rname: generate_varname(), - // }, - // ); - // } - - pub fn new_func(&mut self, name: String, state: LexerState, desc: String) { - self.vars.insert( - name, - Variable { - vtype: VariableType::Func, - desc, - state, - params: Variables { - vars: HashMap::new(), - }, - rname: generate_varname(), - }, - ); - } - pub fn add(&mut self, vtype: VariableType, name: String, state: LexerState, desc: String) { - self.vars.insert( - name, - Variable { - vtype, - desc, - state, - params: Variables { - vars: HashMap::new(), - }, - rname: generate_varname(), - }, - ); - } - pub fn get_var(&mut self, name: String, root: &mut Transpiler) -> String { - if let Some(x) = self.get_mut(name.clone()) { - return x.rname.clone(); - } else { - root.problems.push(Problem { - problem_type: ProblemType::VariableNotFound, - problem_msg: format!("Variable '{}' doesn't exist", &name), - }); - return name; - } - } - pub fn iter_mut( - &mut self, - ) -> std::collections::hash_map::IterMut<'_, std::string::String, Variable> { - self.vars.iter_mut() - } - pub fn get_mut(&mut self, name: String) -> Option<&mut Variable> { - self.vars.get_mut(&name) - } - pub fn expand(&mut self, vars: Variables) { - for (x, y) in vars.vars { - self.vars.insert(x, y); - } - } -} - -pub fn generate_varname() -> String { - let mut rng = rand::thread_rng(); - let charset: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789"; - let mut result = String::with_capacity(19); - result.push('_'); - result.push('0'); - result.push('x'); - for _ in 0..14 { - let random_char = charset[rng.gen_range(0..charset.len())] as char; - result.push(random_char); - } - result -} diff --git a/src/wyst.pest b/src/wyst.pest new file mode 100644 index 0000000..761a618 --- /dev/null +++ b/src/wyst.pest @@ -0,0 +1,75 @@ +WHITESPACE = _{ " " | "\t" | "\n" } + +// [chars] +comma = {","} +semicolon = {";"} + +// [literals] +filepath = { ("/"|('a'..'z' | 'a'..'z' | '0'..'9' | "_" | "-" | "."))+ } +include = { "#" ~ "include" ~ "\"" ~ filepath ~ "\"" } +include_global = { "#" ~ "include" ~ "<" ~ filepath ~ ">" } +round = { "(" ~ ((expr ~ comma)* ~ expr?) ~ ")" } +curly = { "{" ~ (code_expr)* ~ "}" } +escape = { "\\" ~ ANY } +raw_string = { (!("\\" | "\"") ~ ANY)+ } +string = { "\"" ~ (raw_string | escape )* ~ "\"" } +char = { "'" ~ (escape | ANY) ~ "'" } +bool = @{"true" | "false"} + +// [numbers] +hex = @{ "0" ~ ("x"|"X") ~ ('0'..'9' | 'a'..'f' | 'A'..'F')*} +float = @{ ('0'..'9')* ~ "." ~ ('0'..'9')+ } +int = @{ '0'..'9'+ } + +// [identifiers] +identifier = @{ !(hex|float|int) ~ ("." | "::" | "_" | 'a'..'z' | 'A'..'Z') ~ ( "." | "::" | "_" | 'a'..'z' | 'A'..'Z' | int )*} +def_identifier = {identifier ~ ("<" ~ ((def_identifier ~ comma)* ~ def_identifier?) ~ ">")?} + +// [definitions] +round_def = { "(" ~ ((var_def ~ comma)* ~ var_def?) ~ ")" } +var_def = { def_identifier ~ identifier } +var_def_set = { var_def ~ "=" ~ expr } +var_set = { def_identifier ~ "=" ~ expr } +func_def = { def_identifier ~ identifier ~ round_def ~ curly } + +rust_macro_lint = { "macro_rules" ~ "!" ~ identifier } +rust_code = { (rust_macro_lint | ANY)* } + +plus = {"+"} + +call = {identifier ~ round} + +expr_ = { + call | + round | + curly | + char | + hex | + float | + int | + bool | + identifier | + string +} + +expr = { + (expr_ ~ plus ~ expr_) | + expr_ +} + +code_expr = { + ( + var_def_set| + var_def | + var_set | + expr + ) ~ semicolon +} + +top_expr = { + ( + include | + include_global | + func_def + )* ~ !ANY +}