From 236a9c296bd6703dad1902e5727d628a57e49c6f Mon Sep 17 00:00:00 2001 From: Araozu Date: Mon, 23 Jan 2023 09:31:49 -0500 Subject: [PATCH] Simple codegen --- CHANGELOG.md | 17 +++++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/codegen/binding.rs | 36 ++++++++++++++++++++++++++++++++++++ src/codegen/expression.rs | 28 ++++++++++++++++++++++++++++ src/codegen/mod.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/codegen/module_ast.rs | 35 +++++++++++++++++++++++++++++++++++ src/main.rs | 3 ++- src/repl/mod.rs | 3 +++ src/semantic/mod.rs | 2 +- src/token.rs | 3 --- 11 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 src/codegen/binding.rs create mode 100644 src/codegen/expression.rs create mode 100644 src/codegen/mod.rs create mode 100644 src/codegen/module_ast.rs diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..df9e208 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +## TODO + +- [ ] Automatic semicolon insertion +- [ ] Improve error messages +- [ ] Parse other language constructions +- [ ] Type checking +- [ ] Check for conflicting identifiers +- [ ] Namespace identifiers in the symbol table +- [ ] Stdlib +- [ ] Document code + +## v0.0.1 + +- Compilation of a `val` binding with a number. +- Scan all tokens except new lines, indentation. diff --git a/Cargo.lock b/Cargo.lock index d192477..66583c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "misti" -version = "0.1.0" +version = "0.0.1" dependencies = [ "chrono", ] diff --git a/Cargo.toml b/Cargo.toml index 754eae0..35d2d65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "misti" -version = "0.1.0" +version = "0.0.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/codegen/binding.rs b/src/codegen/binding.rs new file mode 100644 index 0000000..c5b1354 --- /dev/null +++ b/src/codegen/binding.rs @@ -0,0 +1,36 @@ +use crate::ast_types::Binding; +use super::Transpilable; + +impl Transpilable for Binding<'_> { + fn transpile(&self) -> String { + match self { + Binding::Val(val_binding) => { + let expression_str = val_binding.expression.transpile(); + + format!("const {} = {};", val_binding.identifier, expression_str) + } + } + } +} + + + +#[cfg(test)] +mod tests { + use super::*; + use crate::ast_types::{Expression, ValBinding}; + + #[test] + fn binding_should_transpile() { + let id = String::from("identifier"); + let value = String::from("322"); + let binding = Binding::Val(ValBinding { + identifier: &id, + expression: Expression::Number(&value), + }); + + let result = binding.transpile(); + + assert_eq!("const identifier = 322;", result); + } +} diff --git a/src/codegen/expression.rs b/src/codegen/expression.rs new file mode 100644 index 0000000..8de91df --- /dev/null +++ b/src/codegen/expression.rs @@ -0,0 +1,28 @@ +use crate::ast_types::Expression; +use super::Transpilable; + +impl Transpilable for Expression<'_> { + fn transpile(&self) -> String { + match self { + Expression::Number(value) => { + String::from(*value) + } + } + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use crate::ast_types::Expression; + + #[test] + fn number_should_transpile() { + let str = String::from("42"); + let exp = Expression::Number(&str); + let result = exp.transpile(); + + assert_eq!("42", result); + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs new file mode 100644 index 0000000..8108701 --- /dev/null +++ b/src/codegen/mod.rs @@ -0,0 +1,39 @@ +use super::ast_types::ModuleAST; + +mod expression; +mod binding; +mod module_ast; + +trait Transpilable { + fn transpile(&self) -> String; +} + +/// Generates JavaScript from the AST +pub fn codegen<'a>(ast: &'a ModuleAST) -> String { + ast.transpile() +} + + + + + +#[cfg(test)] +mod tests { + use crate::{lexic, syntax, semantic, symbol_table::SymbolTable}; + + use super::*; + + #[test] + fn should_codegen_1() { + let input = String::from("val id = 322"); + let tokens = lexic::get_tokens(&input).unwrap(); + let mut ast = syntax::construct_ast(&tokens).unwrap(); + let mut table = SymbolTable::new(); + semantic::check_ast(&mut ast, &mut table); + + let out_str = codegen(&ast); + + assert_eq!("const id = 322;", out_str); + } +} + diff --git a/src/codegen/module_ast.rs b/src/codegen/module_ast.rs new file mode 100644 index 0000000..24c34f9 --- /dev/null +++ b/src/codegen/module_ast.rs @@ -0,0 +1,35 @@ +use crate::ast_types::ModuleAST; +use super::Transpilable; + +impl Transpilable for ModuleAST<'_> { + fn transpile(&self) -> String { + let bindings_str: Vec:: = self.bindings.iter().map(|binding| binding.transpile()).collect(); + + bindings_str.join("\n") + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use crate::ast_types::{Expression, ValBinding, Binding}; + + #[test] + fn module_ast_should_transpile() { + let id = String::from("identifier"); + let value = String::from("322"); + let binding = Binding::Val(ValBinding { + identifier: &id, + expression: Expression::Number(&value), + }); + + let module = ModuleAST { + bindings: vec![binding], + }; + + let result = module.transpile(); + + assert_eq!("const identifier = 322;", result); + } +} diff --git a/src/main.rs b/src/main.rs index 757044c..e44afc5 100755 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,14 @@ mod token; mod semantic; mod ast_types; mod symbol_table; +mod codegen; const VERSION: &str = "0.0.1"; fn get_copyright() -> String { let year = Utc::now().year(); - format!("Misti {}\nCopyright (c) {} Fernando Enrique Araoz Morales", VERSION, year) + format!("Misti {}\nCopyright (c) {} Fernando Enrique Araoz Morales\n", VERSION, year) } /// # Misti diff --git a/src/repl/mod.rs b/src/repl/mod.rs index a943d96..87cf7a5 100755 --- a/src/repl/mod.rs +++ b/src/repl/mod.rs @@ -5,6 +5,7 @@ use crate::symbol_table::SymbolTable; use super::lexic; use super::syntax; use super::semantic; +use super::codegen; fn compile(input: &String) { let _tokens = lexic::get_tokens(input); @@ -14,6 +15,8 @@ fn compile(input: &String) { let mut ast = syntax::construct_ast(&tokens).unwrap(); let mut table = SymbolTable::new(); semantic::check_ast(&mut ast, &mut table); + let js_code = codegen::codegen(&ast); + println!("{}", js_code) }, Err(error) => { eprintln!("Error scanning.\n{} at pos {}", error.reason, error.position) diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index 2437f0f..072457f 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,7 +1,7 @@ use super::symbol_table::{SymbolTable, _NUMBER}; use super::ast_types::{ModuleAST, Binding}; -/// Checks the ast. In the future should return a list of errors. +/// Checks the AST. In the future should return a list of errors. pub fn check_ast<'a>(ast: &'a mut ModuleAST, symbol_table: &'a mut SymbolTable) { for binding in &ast.bindings { match binding { diff --git a/src/token.rs b/src/token.rs index d5f2e0b..c0a7468 100755 --- a/src/token.rs +++ b/src/token.rs @@ -1,6 +1,5 @@ #[derive(PartialEq, Debug, Clone)] pub enum TokenType { - NewLine, Identifier, Comment, Number, @@ -12,8 +11,6 @@ pub enum TokenType { RightBracket, LeftBrace, RightBrace, - Indent, - Dedent, VAR, VAL, EOF,