diff --git a/README.md b/README.md index 89fe6c2..d2fc3bc 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,8 @@

Wyst is a programing language that has similar syntax to C and transpiles to Rust

+# Re Write +We are re-writing the parser and transpiler due to the messy code that is very hard to expand + # Alpha We are on pure alpha. if you would like to contribute please open a new issue. diff --git a/src/lexer.rs b/src/lexer.rs index 8f98af3..76df225 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -85,7 +85,8 @@ const SYNTAX: [Node; 17] = [ 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() + Regex::new(r"^(pub|mut|try|catch|return|fn|let|use|cb|enum|struct|impl|in|as)\b") + .unwrap() }), }, Node { diff --git a/src/main.rs b/src/main.rs index 494d6d3..a7b7897 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,120 +1,255 @@ -mod compile; -mod dllmgr; -mod file_writer; -mod lexer; -mod lsp; -mod lspcom; -mod parser; -mod transpiler; -mod variable; -use clap::Parser; -use std::{fs, path::Path}; -use transpiler::Transpiler; -use variable::{Variable, VariableType, Variables}; - -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, +#[derive(Debug, PartialEq, Clone)] +enum Token { + Plus, + Minus, + Star, + Slash, + Equals, + Semicolon, + LParen, + RParen, + Identifier(String), + Number(i64), + EOF, } -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(); +fn tokenize(input: &str) -> Vec { + let mut tokens = Vec::new(); + let chars: Vec = input.chars().collect(); + let mut i = 0; - 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 => {} + while i < chars.len() { + match chars[i] { + ' ' | '\t' | '\n' | '\r' => i += 1, + '+' => { + tokens.push(Token::Plus); + i += 1; } - 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"); + '-' => { + tokens.push(Token::Minus); + i += 1; + } + '*' => { + tokens.push(Token::Star); + i += 1; + } + '/' => { + tokens.push(Token::Slash); + i += 1; + } + '=' => { + tokens.push(Token::Equals); + i += 1; + } + ';' => { + tokens.push(Token::Semicolon); + i += 1; + } + '(' => { + tokens.push(Token::LParen); + i += 1; + } + ')' => { + tokens.push(Token::RParen); + i += 1; + } + '0'..='9' => { + let mut num = 0; + while i < chars.len() && chars[i].is_digit(10) { + num = num * 10 + chars[i].to_digit(10).unwrap() as i64; + i += 1; } - None => {} + tokens.push(Token::Number(num)); + } + 'a'..='z' | 'A'..='Z' => { + let mut id = String::new(); + while i < chars.len() && (chars[i].is_alphanumeric() || chars[i] == '_') { + id.push(chars[i]); + i += 1; + } + match id.as_str() { + _ => tokens.push(Token::Identifier(id)), + } + } + _ => panic!("Unexpected character: {}", chars[i]), + } + } + + tokens.push(Token::EOF); + tokens +} + +#[derive(Debug)] +enum ASTNode { + Number(i64), + Identifier(String), + BinaryOp(Box, Token, Box), + Assignment(String, Box), + Print(Box), + Let(String, Box), + Sequence(Vec), +} + +struct Parser { + tokens: Vec, + current_token: Token, + pos: usize, +} + +impl Parser { + fn new(tokens: Vec) -> Self { + Self { + tokens: tokens.clone(), + current_token: tokens[0].clone(), + pos: 0, + } + } + + fn eat(&mut self, token: Token) { + if self.current_token == token { + self.pos += 1; + self.current_token = self.tokens[self.pos].clone(); + } else { + panic!("Unexpected token: {:?}", self.current_token); + } + } + + fn factor(&mut self) -> ASTNode { + match self.current_token.clone() { + Token::Number(value) => { + self.eat(Token::Number(value)); + ASTNode::Number(value) + } + Token::Identifier(name) => { + self.eat(Token::Identifier(name.clone())); + ASTNode::Identifier(name) + } + Token::LParen => { + self.eat(Token::LParen); + let expr = self.expression(); + self.eat(Token::RParen); + expr + } + _ => panic!("Unexpected token: {:?}", self.current_token), + } + } + + fn term(&mut self) -> ASTNode { + let mut node = self.factor(); + + while self.current_token == Token::Star || self.current_token == Token::Slash { + let token = self.current_token.clone(); + self.eat(token.clone()); + node = ASTNode::BinaryOp(Box::new(node), token, Box::new(self.factor())); + } + + node + } + + fn expression(&mut self) -> ASTNode { + let mut node = self.term(); + + while self.current_token == Token::Plus || self.current_token == Token::Minus { + let token = self.current_token.clone(); + self.eat(token.clone()); + node = ASTNode::BinaryOp(Box::new(node), token, Box::new(self.term())); + } + + node + } + + fn statement(&mut self) -> ASTNode { + match self.current_token.clone() { + Token::Identifier(name) => { + self.eat(Token::Identifier(name.clone())); + self.eat(Token::Equals); + let expr = self.expression(); + self.eat(Token::Semicolon); + ASTNode::Assignment(name, Box::new(expr)) + } + _ => panic!("Unexpected token: {:?}", self.current_token), + } + } + + fn parse(&mut self) -> ASTNode { + let mut statements = Vec::new(); + + while self.current_token != Token::EOF { + statements.push(self.statement()); + } + + ASTNode::Sequence(statements) + } +} + +use std::collections::HashMap; + +struct Interpreter { + symbol_table: HashMap, +} + +impl Interpreter { + fn new() -> Self { + Self { + symbol_table: HashMap::new(), + } + } + + fn evaluate(&mut self, node: &ASTNode) -> i64 { + match node { + ASTNode::Number(value) => *value, + ASTNode::Identifier(name) => *self.symbol_table.get(name).expect("Undefined variable"), + ASTNode::BinaryOp(left, token, right) => { + let left_val = self.evaluate(left); + let right_val = self.evaluate(right); + match token { + Token::Plus => left_val + right_val, + Token::Minus => left_val - right_val, + Token::Star => left_val * right_val, + Token::Slash => left_val / right_val, + _ => panic!("Unexpected binary operator"), + } + } + ASTNode::Assignment(name, expr) => { + let value = self.evaluate(expr); + self.symbol_table.insert(name.clone(), value); + value + } + ASTNode::Let(name, expr) => { + let value = self.evaluate(expr); + self.symbol_table.insert(name.clone(), value); + value + } + ASTNode::Print(expr) => { + let value = self.evaluate(expr); + println!("{}", value); + value + } + ASTNode::Sequence(statements) => { + for statement in statements { + self.evaluate(statement); + } + 0 } } } } + +fn main() { + let input = " + let x = 5; + let y = x + 3; + print y; + x = y * 2; + print x; + "; + let tokens = tokenize(input); + println!("Tokens: {:?}", tokens); + + let mut parser = Parser::new(tokens); + let ast = parser.parse(); + println!("AST: {:?}", ast); + + let mut interpreter = Interpreter::new(); + interpreter.evaluate(&ast); +} diff --git a/src/parser.rs b/src/parser.rs index 2ab67dc..6583f59 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -26,6 +26,7 @@ pub enum AstType { Json, Impl, StaticExecution, + EnumDeceleration, Other, } @@ -119,6 +120,27 @@ impl Parser { 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 == "enum" + && 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::EnumDeceleration; + 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_enum( + 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 == "struct" && self.tokens[index + 1].token_type == TokenType::Identifier diff --git a/src/transpiler.rs b/src/transpiler.rs index 190ae76..f794f88 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -149,6 +149,37 @@ impl Transpiler { ) ) .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!( + "enum {} {} {}", + 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::StructDeceleration { if self.auto_pub { result += "pub "; diff --git a/src/variable.rs b/src/variable.rs index 127d4e4..e48a660 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -16,6 +16,7 @@ pub enum VariableType { Keyword, Struct, Namespace, + Enum, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -93,6 +94,20 @@ impl Variables { }, ); } + pub fn new_enum(&mut self, name: String, state: LexerState, desc: String) { + self.vars.insert( + name, + Variable { + vtype: VariableType::Enum, + 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(