Simple codegen
This commit is contained in:
parent
418be5dc17
commit
236a9c296b
17
CHANGELOG.md
Normal file
17
CHANGELOG.md
Normal 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
2
Cargo.lock
generated
@ -169,7 +169,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "misti"
|
||||
version = "0.1.0"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
]
|
||||
|
@ -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
36
src/codegen/binding.rs
Normal 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
28
src/codegen/expression.rs
Normal 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
39
src/codegen/mod.rs
Normal 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
35
src/codegen/module_ast.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user