Simple codegen

master
Araozu 2023-01-23 09:31:49 -05:00
parent 418be5dc17
commit 236a9c296b
11 changed files with 163 additions and 7 deletions

17
CHANGELOG.md Normal file
View File

@ -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.

2
Cargo.lock generated
View File

@ -169,7 +169,7 @@ dependencies = [
[[package]]
name = "misti"
version = "0.1.0"
version = "0.0.1"
dependencies = [
"chrono",
]

View File

@ -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

36
src/codegen/binding.rs Normal file
View File

@ -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);
}
}

28
src/codegen/expression.rs Normal file
View File

@ -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);
}
}

39
src/codegen/mod.rs Normal file
View File

@ -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);
}
}

35
src/codegen/module_ast.rs Normal file
View File

@ -0,0 +1,35 @@
use crate::ast_types::ModuleAST;
use super::Transpilable;
impl Transpilable for ModuleAST<'_> {
fn transpile(&self) -> String {
let bindings_str: Vec::<String> = 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);
}
}

View File

@ -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

View File

@ -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)

View File

@ -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 {

View File

@ -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,