From f4759f01c81eb001355bb0d6d8b423f962f3977e Mon Sep 17 00:00:00 2001 From: Leo Dev Date: Thu, 11 Jul 2024 14:15:31 +0200 Subject: [PATCH] new compiler --- src/main.rs | 34 ++++++++++---- src/parser.rs | 117 +++++++++++++++++++++++++++++++++++++--------- src/transpiler.rs | 11 +++-- src/utils.rs | 48 +++++++++++++------ 4 files changed, 163 insertions(+), 47 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3b30eda..0fe5c31 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,15 +22,33 @@ fn main() { .short('o') .long("output") .takes_value(true) - .help("Specifies the output executable file name"), + .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(); - 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, "main.rs".to_string(), true); - compile_rust(output); - fs::remove_dir_all("build").expect("Error removing build"); - process::exit(ecode as i32); + 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, "main.rs".to_string(), true); + 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 index 5bc2238..4c57304 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,10 +1,33 @@ use std::usize; +use once_cell::sync::Lazy; +use regex::Regex; + use crate::{ transpiler::{State, Transpiler}, utils::{Problem, ProblemCap, ProblemType, Variables}, }; +pub struct Node { + pub regex_pattern: Lazy, + pub token: u32, +} + +const NODES: [Node; 3] = [ + Node { + token: 1, + regex_pattern: Lazy::new(|| Regex::new(r"^(0(x|X)\d+|\d+)").unwrap()), + }, + Node { + token: 2, + regex_pattern: Lazy::new(|| Regex::new(r"^[.:_a-zA-Z][a-zA-Z0-9_.:]*").unwrap()), + }, + Node { + token: 5, + regex_pattern: Lazy::new(|| Regex::new(r"^(\;|\!|\=)").unwrap()), + }, +]; + #[derive(Clone, Debug)] #[allow(dead_code)] pub enum Token { @@ -15,6 +38,8 @@ pub enum Token { Identifier(String, State), Curly(String, State), Round(String, State), + Operator(String, State), + String(String, State), // Square(String), } @@ -27,6 +52,8 @@ pub fn extract_values(token: Token) -> (u8, String, State) { Token::DKeyword(x, state) => (4, x, state), Token::SKeyword(x, state) => (5, x, state), Token::Keyword(x, state) => (6, x, state), + Token::Operator(x, state) => (7, x, state), + Token::String(x, state) => (8, x, state), } } @@ -72,10 +99,30 @@ pub fn get_token(v: String, t: u32, state: State) -> Token { }, 3 => Token::Round(v, state), 4 => Token::Curly(v, state), + 5 => Token::Operator(v, state), + 6 => Token::String(v, state), _ => Token::Number(String::from(""), state), } } +pub fn tokenzie_regex(code: String, state: &mut State) -> (u32, String) { + let mut token = (0, String::new()); + if !code.is_empty() { + for node in &NODES { + if let Some(caps) = node.regex_pattern.captures(&code) { + token.0 = node.token; + token.1 = caps[0].to_string(); + state.column += token.1.len() as u32; + if token.1.contains("\n") { + state.column = 0; + state.line += token.1.chars().filter(|c| *c == '\n').count() as u32; + } + } + } + } + token +} + pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec { let mut code = code; code += " "; @@ -91,7 +138,8 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec Vec { - if stoken.0 == 1 { + if stoken.0 == 2 { stoken.1 += 1; token_value += c.to_string().as_str(); } } '}' => { - if stoken.0 == 1 { + if stoken.0 == 2 { stoken.1 -= 1; if stoken.1 == 0 { stoken.0 = 0; @@ -149,20 +197,35 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec { + token_value += c.to_string().as_str(); + if stoken.0 == 3 { + stoken.1 -= 1; + if stoken.1 == 0 { + stoken.0 = 0; + tokens.push(get_token( + token_value.clone(), + token_type, + token_state.clone(), + )); + token_type = 0; + token_value = String::new(); + } + } + } + '\\' => { + token_value += c.to_string().as_str(); + token_value += code + .chars() + .next() + .expect("Error expected a char for \\") + .to_string() + .as_str(); + } _ => token_value += c.to_string().as_str(), } } else { match c { - '0'..='9' => { - if token_type == 2 { - t = 2; - } else { - t = 1; - } - } - 'a'..='z' | 'A'..='Z' => { - t = 2; - } '\t' | ' ' => { ignore = true; } @@ -174,23 +237,35 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec { stoken.0 = 1; stoken.1 = 1; - tval = ' '; + tval = " "; t = 3; } '{' => { stoken.0 = 2; stoken.1 = 1; - tval = ' '; + tval = " "; t = 4; } - x => { - root.problems.push(ProblemCap::Error(Problem { - problem_msg: format!("Invalid character '{}'", x,), - problem_type: ProblemType::SyntaxError, - state: state.clone(), - })); + '"' => { + stoken.0 = 3; + stoken.1 = 1; + t = 6; ignore = true; } + x => { + ignore = true; + let vals = tokenzie_regex(format!("{}{}", c, code.clone()), state); + if vals.0 != 0 { + tokens.push(get_token(vals.1.clone(), vals.0, state.clone())); + code.drain(0..vals.1.len() - 1); + } else { + root.problems.push(ProblemCap::Error(Problem { + problem_msg: format!("Invalid syntax '{}'", x,), + problem_type: ProblemType::SyntaxError, + state: state.clone(), + })); + } + } } if token_type != t && token_type != 0 { tokens.push(get_token( diff --git a/src/transpiler.rs b/src/transpiler.rs index c970ae8..953c79c 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -106,10 +106,15 @@ impl Transpiler { res += "}"; } Ast::Single(x) => { + println!("{:?}", x); let vals = extract_values(x); - if vals.0 == 1 { - println!("{:?}", vals); - res += vars.get_var(vals.1, self, vals.2).as_str(); + match vals.0 { + 2 => res += vars.get_var(vals.1, self, vals.2).as_str(), + 3 => res += format!("({})", vals.1).as_str(), + 8 => res += vals.1.as_str(), + _ => { + res += vals.1.as_str(); + } } } } diff --git a/src/utils.rs b/src/utils.rs index 626dfbe..ad41986 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -51,22 +51,40 @@ pub struct Variables { impl Variables { pub fn new() -> Variables { Variables { - vars: HashMap::from([( - "void".to_string(), - Variable { - vtype: VariableType::Keyword, - desc: "".to_string(), - state: State { - line: 0, - column: 0, - file: None, + vars: HashMap::from([ + ( + "void".to_string(), + Variable { + vtype: VariableType::Keyword, + desc: "".to_string(), + state: State { + line: 0, + column: 0, + file: None, + }, + params: Variables { + vars: HashMap::new(), + }, + rname: "".to_string(), }, - params: Variables { - vars: HashMap::new(), + ), + ( + "println".to_string(), + Variable { + vtype: VariableType::Keyword, + desc: "".to_string(), + state: State { + line: 0, + column: 0, + file: None, + }, + params: Variables { + vars: HashMap::new(), + }, + rname: "println".to_string(), }, - rname: "".to_string(), - }, - )]), + ), + ]), } } pub fn new_var(&mut self, name: String, state: State, desc: String) -> String { @@ -173,7 +191,7 @@ impl Variables { } else { root.problems.push(ProblemCap::Error(Problem { problem_type: ProblemType::VariableNotFound, - problem_msg: format!("Variable '{}' doesn't exist", &name), + problem_msg: format!("'{}' doesn't exist", &name), state: state, })); return name;