diff --git a/Cargo.toml b/Cargo.toml index 7d7edfa..1196dee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,17 @@ members = [ "ast", "project", "ty", - "ir", "e2e", "tyvm", - "linter", + "linter", "codelocation", - "types", - "cachectx", - "typetable", - "scopetable" -] + "types", + "typetable", + "scopetable", + "fir", + "oir", + "scir", + "datatable", + ] resolver = "2" diff --git a/bootstrap/token/lib.ty b/bootstrap/token/lib.ty index c4060da..1903996 100644 --- a/bootstrap/token/lib.ty +++ b/bootstrap/token/lib.ty @@ -2,7 +2,7 @@ pub type TokenError = error | InvalidToken | UnexpectedEnd -pub type Token = enum(u8) { +pub type Token = enum | Error | Defer | ErrDefer diff --git a/cachectx/Cargo.toml b/cachectx/Cargo.toml deleted file mode 100644 index a5be0a0..0000000 --- a/cachectx/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "cachectx" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -lexer = { path = "../lexer" } -parser = { path = "../parser" } -ast = { path = "../ast" } -symtable = { path = "../symtable" } -typetable = { path = "../typetable" } -scopetable = { path = "../scopetable" } -types = { path = "../types" } -linter = { path = "../linter" } -ir = { path = "../ir" } diff --git a/cachectx/src/lib.rs b/cachectx/src/lib.rs deleted file mode 100644 index f3f15bb..0000000 --- a/cachectx/src/lib.rs +++ /dev/null @@ -1,57 +0,0 @@ -use lexer::*; -use linter::*; -use parser::*; -use scopetable::*; -use std::{fs::File, io::Read, path::PathBuf, rc::Rc}; -use symtable::*; -use types::*; -use typetable::*; - -struct InternalContext { - source: PathBuf, - parsed: Option, - ttbls: Option>, - scopes: Option>, - tree: Option>>>, -} - -pub struct CacheContext { - files: Vec, -} - -impl CacheContext { - pub fn new() -> Self { - CacheContext { files: vec![] } - } - pub fn add_file(&mut self, source: PathBuf) -> () { - self.files.push(InternalContext { - source, - parsed: None, - ttbls: None, - scopes: None, - tree: None, - }); - } - pub fn analysis(&mut self) -> () { - self.files.iter_mut().enumerate().for_each(|(_i, ic)| { - let mut file = File::open(&ic.source).unwrap(); - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); - let lexer = TLexer::new(&contents); - let mut parser = Parser::new(lexer); - match parser.all() { - Ok(mut val) => { - let mut ttbls = vec![]; - let mut scopes = vec![]; - let mut linter = LintSource::new(&contents, &mut scopes, &mut ttbls); - - let analysis = linter.lint_check(&mut val); - - ic.tree = Some(analysis); - ic.ttbls = Some(ttbls); - } - Err(perr) => ic.parsed = Some(Err(perr)), - } - }) - } -} diff --git a/datatable/Cargo.toml b/datatable/Cargo.toml new file mode 100644 index 0000000..3cd3c1c --- /dev/null +++ b/datatable/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "datatable" +version = "0.1.0" +edition = "2021" + +[dependencies] +cranelift-module = "0" diff --git a/datatable/src/lib.rs b/datatable/src/lib.rs new file mode 100644 index 0000000..52ef1bc --- /dev/null +++ b/datatable/src/lib.rs @@ -0,0 +1,14 @@ +use cranelift_module::DataId; +use std::collections::BTreeMap; + +pub struct DataTable { + pub table: BTreeMap, +} + +impl DataTable { + pub fn new() -> Self { + DataTable { + table: BTreeMap::new(), + } + } +} diff --git a/e2e/Cargo.toml b/e2e/Cargo.toml index bf50b43..1899505 100644 --- a/e2e/Cargo.toml +++ b/e2e/Cargo.toml @@ -12,7 +12,6 @@ typetable = { path = "../typetable" } lexer = { path = "../lexer" } token = { path = "../token" } parser = { path = "../parser" } -ir = { path = "../ir" } object = { path = "../object" } objmaker = { path = "../objmaker" } linter = { path = "../linter" } diff --git a/e2e/src/main.rs b/e2e/src/main.rs index 32b7cb7..775a857 100644 --- a/e2e/src/main.rs +++ b/e2e/src/main.rs @@ -4,7 +4,6 @@ use linter::LintSource; use parser::Parser; use std::fs::File; use std::io::Read; -use typetable::TypeTable; use std::path::Path; use std::process::Command; @@ -12,10 +11,10 @@ use std::process::Command; fn main() { println!("[run] simple exe"); objmaker::from_buffer( - "pub const main = fn() usize { - const m = 7 + "const m = 7 + pub const main = fn() usize { const x = 5 - return x + m + return x + m }", Path::new("main.ty"), ); diff --git a/ebnf.txt b/ebnf.txt index 9e841bf..b818c8b 100644 --- a/ebnf.txt +++ b/ebnf.txt @@ -1,9 +1,9 @@ // use this to test, and this must pass at all times // https://bnfplayground.pauliankline.com/ ::= ()* - ::= "pub "? ("const " | "let " | "type " | "impl ") (":" )? " = " ( | | | | | | | | ) + ::= "pub "? ("const " | "let " | "type " | "impl ") (":" )? " = " ( | | | | | | | | ) ::= "import " - ::= "trait " "{ " ( ::= "trait " "{ " ()* " }" ::= | ("&" | "*")? ("[" "]" | ("." )* | ) ::= "fn" "(" ")" ("void" | ) ::= ( ("," )*)? @@ -15,14 +15,15 @@ ::= "for " "(" ")" ( | ) ::= "while " "(" ")" ( | ) ::= "match " "(" ")" "{ " + "}" - ::= "=> " ( | ) + ::= "=> " ( | | ) ::= "tag " ("| " (":" )?)+ ::= "enum" "(" ")" ("| " ("=" )?)+ ::= ()* ::= "pub "? (":" )? + ::= ("{ " ("," )* " }") | ::= ( ("," )*)? ::= ("self " (": " )?) | (":" )? - ::= ( "const " | "let ") (":" )? "= " + ::= ( "const " | "let ") (":" )? "= " ::= ("= " )? ::= "{ " ( | | | | )* ( | )? "}" ::= "return " ? diff --git a/ir/Cargo.toml b/fir/Cargo.toml similarity index 72% rename from ir/Cargo.toml rename to fir/Cargo.toml index 1bd0b3b..a096697 100644 --- a/ir/Cargo.toml +++ b/fir/Cargo.toml @@ -1,14 +1,15 @@ [package] -name = "ir" +name = "fir" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] ast = { path="../ast" } +oir = { path="../oir" } symtable = { path="../symtable" } +datatable = { path="../datatable" } typetable = { path="../typetable" } +scopetable = { path="../scopetable" } token = { path="../token" } perror = { path="../perror" } lexer = { path="../lexer" } @@ -16,3 +17,4 @@ linter = { path="../linter" } types = { path="../types" } cranelift-frontend = "0" cranelift-codegen = "0" +cranelift-module = "0" diff --git a/ir/src/lib.rs b/fir/src/lib.rs similarity index 55% rename from ir/src/lib.rs rename to fir/src/lib.rs index 0509eda..36c7606 100644 --- a/ir/src/lib.rs +++ b/fir/src/lib.rs @@ -1,50 +1,95 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::entities::FuncRef; use cranelift_codegen::ir::function::DisplayFunction; +use cranelift_codegen::ir::immediates::Offset32; use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::AbiParam; +use cranelift_codegen::ir::MemFlags; use cranelift_codegen::ir::{Function, InstBuilder, Signature, UserFuncName, Value}; use cranelift_codegen::isa::CallConv; use cranelift_codegen::settings; use cranelift_codegen::verifier::verify_function; use cranelift_frontend::*; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; +use cranelift_module::Module; +use datatable::DataTable; +use oir::Oir; use perror::*; -use std::rc::Rc; -use symtable::*; +use scopetable::ScopeTable; +use symtable::SymTable; use types::*; -use typetable::*; +use typetable::TypeTable; -pub struct IRSource<'tt> { - package: u32, - fname: u32, +// Function Intermediate Representation +pub struct Fir { variables: u32, - scope: SymTable, - t_scope: &'tt TypeTable, + sym: SymTable, } -impl<'tt> IRSource<'tt> { - pub fn new(package: u32, scope: SymTable, t_scope: &'tt TypeTable) -> Self { - IRSource { - package, - fname: 0, - variables: 0, - scope, - t_scope, - } +impl Fir { + pub fn refresh(&mut self) -> () { + self.variables = 0; + self.sym = SymTable::new() + } + pub fn new(variables: u32, sym: SymTable) -> Self { + Fir { variables, sym } + } + pub fn run( + &mut self, + func_def: &FunctionInitialize, + ctx: &mut FunctionBuilderContext, + namespace: u32, + index: u32, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, + ) -> Function { + let mut sig = Signature::new(CallConv::SystemV); + let name = UserFuncName::user(namespace, index); + // todo:: types need to be worked out, params and returns defined + func_def + .args + .iter() + .for_each(|_x| sig.params.push(AbiParam::new(I64))); + sig.returns.push(AbiParam::new(I64)); + let mut func = Function::with_name_signature(name, sig); + let mut builder = FunctionBuilder::new(&mut func, ctx); + let root_block = builder.create_block(); + builder.append_block_params_for_function_params(root_block); + builder.switch_to_block(root_block); + let _result = self.recurse( + &func_def.block, + &mut builder, + dtbl, + scopes, + type_tables, + oir, + ); + builder.seal_block(root_block); + builder.finalize(); + func } pub fn handle_const_init( &mut self, op: &Initialization, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { let result = self.add_var(); builder.declare_var(result, I64); - let temp = self.recurse(&op.right, builder).unwrap(); + let temp = self + .recurse(&op.right, builder, dtbl, scopes, type_tables, oir) + .unwrap(); // todo:: optimization: not all paths need declare var if value is only ever read. or something similar, this statement is in the same ballpark, but might not be totally correct let x = builder.use_var(temp); - self.scope.table.insert(op.left.clone(), temp.as_u32()); + self.sym + .table + .insert(op.left.into_symbol_init().ident.clone(), temp.as_u32()); builder.def_var(temp, x); Ok(temp) } @@ -52,12 +97,18 @@ impl<'tt> IRSource<'tt> { &mut self, op: &Invoke, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { let args: Vec = op .args .iter() .map(|x| { - let result = self.recurse(&x, builder).unwrap(); + let result = self + .recurse(&x, builder, dtbl, scopes, type_tables, oir) + .unwrap(); return builder.use_var(result).clone(); }) .collect::>(); @@ -72,12 +123,18 @@ impl<'tt> IRSource<'tt> { &mut self, op: &Block, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { let temp: Vec = op .exprs .iter() .map(|x| { - return self.recurse(&x, builder).unwrap(); + return self + .recurse(&x, builder, dtbl, scopes, type_tables, oir) + .unwrap(); }) .collect(); Ok(*temp.last().unwrap()) @@ -90,16 +147,40 @@ impl<'tt> IRSource<'tt> { &mut self, op: &UnaryOp, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { - let temp = self.recurse(&op.val, builder).unwrap(); + let temp = self + .recurse(&op.val, builder, dtbl, scopes, type_tables, oir) + .unwrap(); let arg = builder.use_var(temp); builder.ins().return_(&[arg]); Ok(temp) } - pub fn handle_sym(&self, op: &SymbolAccess) -> ResultFir { - Ok(Variable::from_u32( - *self.scope.table.get(&op.ident).unwrap(), - )) + pub fn handle_sym_access( + &mut self, + op: &SymbolAccess, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, + builder: &mut FunctionBuilder, + ) -> ResultFir { + let sym = self.sym.table.get(&op.ident); + if let Some(s) = sym { + return Ok(Variable::from_u32(*s)); + } + let id = dtbl.table.get(&op.ident).unwrap(); + let gv = oir.obj_mod.declare_data_in_func(*id, builder.func); + let val = builder.ins().global_value(I64, gv); + let result = self.add_var(); + builder.declare_var(result, I64); + let mem = MemFlags::new(); + let loaded = builder.ins().load(I64, mem, val, Offset32::new(0)); + builder.def_var(result, loaded); + Ok(result) } pub fn handle_u64(&mut self, num: u64, builder: &mut FunctionBuilder) -> ResultFir { let result = self.add_var(); @@ -121,11 +202,19 @@ impl<'tt> IRSource<'tt> { &mut self, num: &BinaryOp, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { let result = self.add_var(); builder.declare_var(result, I64); - let left = self.recurse(&num.left, builder).unwrap(); - let right = self.recurse(&num.right, builder).unwrap(); + let left = self + .recurse(&num.left, builder, dtbl, scopes, type_tables, oir) + .unwrap(); + let right = self + .recurse(&num.right, builder, dtbl, scopes, type_tables, oir) + .unwrap(); let arg1 = builder.use_var(left); let arg2 = builder.use_var(right); let temp = builder.ins().isub(arg1, arg2); @@ -136,11 +225,19 @@ impl<'tt> IRSource<'tt> { &mut self, num: &BinaryOp, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { let result = self.add_var(); builder.declare_var(result, I64); - let left = self.recurse(&num.left, builder).unwrap(); - let right = self.recurse(&num.right, builder).unwrap(); + let left = self + .recurse(&num.left, builder, dtbl, scopes, type_tables, oir) + .unwrap(); + let right = self + .recurse(&num.right, builder, dtbl, scopes, type_tables, oir) + .unwrap(); let arg1 = builder.use_var(left); let arg2 = builder.use_var(right); let temp = builder.ins().iadd(arg1, arg2); @@ -151,43 +248,31 @@ impl<'tt> IRSource<'tt> { &mut self, expr: &TypeTree, builder: &mut FunctionBuilder, + dtbl: &DataTable, + scopes: &Vec, + type_tables: &Vec, + oir: &mut Oir, ) -> ResultFir { match expr { - TypeTree::Block(op) => self.handle_block(&op, builder), - TypeTree::Invoke(op) => self.handle_invoke(&op, builder), - TypeTree::Plus(op) => self.handle_plus(&op, builder), - TypeTree::Minus(op) => self.handle_minus(&op, builder), - TypeTree::Return(op) => self.handle_ret(&op, builder), + TypeTree::Block(op) => self.handle_block(&op, builder, dtbl, scopes, type_tables, oir), + TypeTree::Invoke(op) => { + self.handle_invoke(&op, builder, dtbl, scopes, type_tables, oir) + } + TypeTree::Plus(op) => self.handle_plus(&op, builder, dtbl, scopes, type_tables, oir), + TypeTree::Minus(op) => self.handle_minus(&op, builder, dtbl, scopes, type_tables, oir), + TypeTree::Return(op) => self.handle_ret(&op, builder, dtbl, scopes, type_tables, oir), TypeTree::ReturnVoid(_) => self.handle_ret_void(builder), - TypeTree::ConstInit(op) => self.handle_const_init(&op, builder), - TypeTree::SymbolAccess(op) => self.handle_sym(&op), + TypeTree::ConstInit(op) => { + self.handle_const_init(&op, builder, dtbl, scopes, type_tables, oir) + } + TypeTree::SymbolAccess(op) => { + self.handle_sym_access(&op, dtbl, scopes, type_tables, oir, builder) + } TypeTree::U64(op) => self.handle_u64(*op, builder), TypeTree::I64(op) => self.handle_i64(*op, builder), _ => panic!("developer error unexpected expression {:?}", expr), } } - pub fn begin(&mut self, func_def: Rc>) -> Function { - let mut ctx = FunctionBuilderContext::new(); - let mut sig = Signature::new(CallConv::SystemV); - let name = UserFuncName::user(self.package, self.fname); - let func_init = func_def.into_func_init(); - // todo:: types need to be worked out, params and returns defined - func_init - .args - .iter() - .for_each(|_x| sig.params.push(AbiParam::new(I64))); - sig.returns.push(AbiParam::new(I64)); - let mut func = Function::with_name_signature(name, sig); - self.fname += 1; - let mut builder = FunctionBuilder::new(&mut func, &mut ctx); - let root_block = builder.create_block(); - builder.append_block_params_for_function_params(root_block); - builder.switch_to_block(root_block); - let _result = self.recurse(&func_init.block, &mut builder); - builder.seal_block(root_block); - builder.finalize(); - func - } pub fn get_ir(self, func: &Function) -> Result { let flags = settings::Flags::new(settings::builder()); let res = verify_function(func, &flags); @@ -202,81 +287,3 @@ impl<'tt> IRSource<'tt> { temp } } - -#[cfg(test)] -mod tests { - use super::*; - use ast::*; - use lexer::*; - use linter::*; - use token::*; - #[test] - fn it_should_build_ret_5() { - let func_def = FuncDecl::new( - None, - Lexeme { - token: Token::Const, - span: 0..3, - slice: "const".to_string(), - }, - expr!( - Symbol, - Lexeme { - token: Token::Symbol, - span: 4..5, - slice: "x".to_string() - } - ), - None, - expr!( - Sig, - Some(expr!( - ValueType, - Lexeme { - token: Token::USize, - span: 6..7, - slice: "usize".to_string(), - } - )), - None, - None, - None - ), - expr!( - Block, - vec![expr!( - RetOp, - Lexeme { - token: Token::Return, - span: 8..10, - slice: "return".to_string() - }, - expr!( - Number, - Lexeme { - token: Token::Number, - span: 6..7, - slice: "5".to_string() - } - ) - )] - ), - None, - ); - let mut tt = vec![]; - let mut scp = vec![]; - let mut linter = LintSource::new("test", &mut scp, &mut tt); - let linter_result = linter.check_func_decl(&func_def).unwrap(); - let mut fir = IRSource::new(0, SymTable::new(), &linter.ttbls.get(0).unwrap()); - let result = fir.begin(linter_result.0); - /* - * function u0:0() -> i64 system_v - * { - * block0: - * v0 = iconst.i64 5 - * return v0 ; v0 = 5 - * } - */ - assert_eq!(format!("{}", fir.get_ir(&result).unwrap()), "function u0:0() -> i64 system_v {\nblock0:\n v0 = iconst.i64 5\n return v0 ; v0 = 5\n}\n"); - } -} diff --git a/linker/src/lib.rs b/linker/src/lib.rs index 79e2593..f8ce04b 100644 --- a/linker/src/lib.rs +++ b/linker/src/lib.rs @@ -10,10 +10,11 @@ pub fn link(obj_file: Vec<&PathBuf>, output: &PathBuf) -> () { .arg(format!("{}{}{}", "/out:", output.to_str().unwrap(), ".exe")) .args(obj_file) .arg("/entry:main") + .arg("/NOLOGO") .status() .unwrap(); } else { - Command::new("cc") + Command::new("gcc") .args(obj_file) .args(&[Path::new("-o"), output]) .status() diff --git a/linter/src/lib.rs b/linter/src/lib.rs index 6968aa8..d280d7f 100644 --- a/linter/src/lib.rs +++ b/linter/src/lib.rs @@ -13,15 +13,23 @@ type ResultTreeType = Result<(Rc>, Ty), usize>; pub struct LintSource<'buf, 'ttb, 'sco> { buffer: &'buf str, - idx: usize, - curr_scope: usize, - curr_self: Option, + idx: u32, + curr_scope: u32, pub scopes: &'sco mut Vec, pub ttbls: &'ttb mut Vec, pub issues: Vec, } impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { + pub fn reinit(&mut self, new_buffer: &'buf str) -> () { + self.buffer = new_buffer; + self.idx = 0; + self.curr_scope = 0; + self.scopes.clear(); + self.scopes.push(ScopeTable::new(0, 0)); + self.ttbls.clear(); + self.issues.clear(); + } pub fn new( buffer: &'buf str, scopes: &'sco mut Vec, @@ -33,7 +41,6 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { buffer, idx: 0, curr_scope: 0, - curr_self: None, scopes, ttbls, issues: vec![], @@ -45,7 +52,9 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { Expr::InnerDecl(decl) => self.check_inner_decl(&decl), Expr::Import(import) => self.check_import(&import), Expr::TagDecl(decl) => self.check_tag_decl(&decl), + Expr::EnumDecl(decl) => self.check_enum_decl(&decl), Expr::Sig(sig) => self.check_sig(&sig), + Expr::ValueType(vt) => self.check_value_type(&vt), Expr::PropAssignments(props) => self.check_props_init(&props), Expr::PropAssignment(prop) => self.check_prop_init(&prop), Expr::StructDecl(decl) => self.check_struct_decl(&decl), @@ -84,8 +93,8 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { ), }, Expr::Number(num) => match num.val.token { - Token::Decimal => self.check_f64(num), - Token::Number => self.check_i64(num), + Token::Decimal => self.check_dec(num), + Token::Number => self.check_num(num), _ => panic!("type-lang linter issue, number not implemented"), }, Expr::TopDecl(top) => self.check_top_decl(&top), @@ -95,6 +104,7 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { Expr::FuncDecl(fun) => self.check_func_decl(&fun), Expr::RetOp(ret) => self.check_ret_op(&ret), Expr::ArgDef(arg) => self.check_arg_def(&arg), + Expr::ArrayType(arr) => self.check_array_type(&arr), _ => panic!("type-lang linter issue, expr not implemented {:?}", to_cmp), } } @@ -102,6 +112,7 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { pub fn check_func_decl(&mut self, td: &FuncDecl) -> ResultTreeType { let mut largs = vec![]; let mut largs_curried = vec![]; + self.inc_scope_tracker(); if let Some(args) = td.args.as_ref() { args.iter().for_each(|x| { let res = self.lint_recurse(x); @@ -124,9 +135,10 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { block: result.0, block_curried: result.1, }; + self.dec_scope_tracker(); let curried = init.block_curried.clone(); let full = tree!(FuncInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); Ok((full, curried)) @@ -144,7 +156,8 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { } }); - let curried = blk.curried.clone(); + // todo:: get the last one if ret, curry, if not void + let curried = blk.exprs.last().unwrap().get_curried().clone(); ok_tree!(Block, blk, curried) } @@ -202,38 +215,42 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { } pub fn check_declarator(&mut self, decl: &Declarator) -> ResultTreeType { + let slice = decl.ident.into_symbol().val.slice.clone(); let dec = DeclaratorInfo { - name: decl.ident.into_symbol().val.slice.clone(), + name: slice.clone(), curried: Ty::Undefined, }; let curried = dec.curried.clone(); - return ok_tree!(DeclaratorInfo, dec, curried); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); + let full = tree!(DeclaratorInfo, dec); + + tbl.table.insert(slice, Rc::clone(&full)); + return Ok((full, curried)); } pub fn check_symbol_decl(&mut self, symbol: &Symbol) -> ResultTreeType { - let sym = SymbolAccess { - ident: symbol.val.slice.clone(), + let slice = symbol.val.slice.clone(); + let sym = SymbolInit { + ident: slice.clone(), curried: Ty::Unknown, }; let curried = sym.curried.clone(); let full = tree!(SymbolInit, sym); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); - tbl.table.insert(symbol.val.slice.clone(), Rc::clone(&full)); + tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, curried)); } pub fn check_symbol_ref(&mut self, symbol: &Symbol) -> ResultTreeType { - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let ss = self.scopes.get(self.curr_scope as usize).unwrap(); + let tt = ss + .get_tt_same_up(&symbol.val.slice, self.ttbls, self.scopes) + .unwrap(); let sym = SymbolAccess { ident: symbol.val.slice.clone(), - curried: tbl - .table - .get(&symbol.val.slice) - .unwrap() - .get_curried() - .clone(), + curried: tt.get_curried(), }; let curried = sym.curried.clone(); return ok_tree!(SymbolAccess, sym, curried); @@ -272,34 +289,77 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { let curried = err_info.curried.clone(); let full = tree!(ErrorInfo, err_info); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, curried)); } + pub fn check_value_type(&mut self, _vt: &ValueType) -> ResultTreeType { + let mut curried = Ty::Unknown; + match _vt.val.token { + Token::U64 => curried = Ty::U64, + Token::USize => curried = Ty::USize, + Token::ISize => curried = Ty::ISize, + Token::F64 => curried = Ty::F64, + Token::U8 => curried = Ty::U8, + Token::Char => curried = Ty::Char, + _ => panic!("type lang issue, unmatched value type"), + }; + let copied = curried.clone(); + let full = tree!(ValueType, copied); + return Ok((full, curried)); + } + pub fn check_sig(&mut self, _sig: &Sig) -> ResultTreeType { - let sig_info = SigInfo { - left: Some(Ty::Error), - err: Some(Ty::Error), - undefined: Some(Ty::Error), - right: Ty::Error, + let mut sig_info = SigTypes { + left: Ty::Unknown, + err: Some(Ty::Unknown), + undefined: Some(Ty::Unknown), + right: Some(Ty::Unknown), }; + let mut c_right: Option = None; + let mut c_left: Ty = Ty::Unknown; + let mut c_err: Option = None; + let mut c_undefined: Option = None; + let mut curried = Ty::Unknown; + + if let Some(right) = &_sig.right_most_type { + c_right = match self.lint_recurse(&right) { + Err(_) => Some(Ty::Unknown), + Ok(v) => Some(v.1), + } + } + if let Some(left) = &_sig.left_most_type { + c_left = match self.lint_recurse(&left) { + Err(_) => Ty::Unknown, + Ok(v) => v.1, + } + } + if let Some(_) = &_sig.err { + c_err = Some(Ty::Error); + } + if let Some(_) = &_sig.undef { + c_undefined = Some(Ty::Undefined); + } + if c_right.is_some() || c_err.is_some() || c_undefined.is_some() { + sig_info.left = c_left; + sig_info.err = c_err; + sig_info.undefined = c_undefined; + sig_info.right = c_right; + let full = tree!(SigTypes, sig_info); - let curried = sig_info.right.clone(); - let full = tree!(SigInfo, sig_info); + return Ok((full, curried)); + } + let full = tree!(SingleType, c_left); return Ok((full, curried)); } pub fn check_self_value(&mut self) -> ResultTreeType { - let curr_self = self - .curr_self - .as_ref() - .expect("expected self to be defined"); let self_ref = NoOp { - curried: curr_self.clone(), + curried: Ty::Unknown, }; let curried = self_ref.curried.clone(); ok_tree!(SelfAccess, self_ref, curried) @@ -333,29 +393,30 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { // assert left type == right type or elidable // need to ensure constness is checked on the property - let end = reassignment.left.get_curried().ensure_mut().or_else(|x| { + reassignment.left.get_curried().ensure_mut().or_else(|x| { Err(self.set_error( format!("found {}", x), - "did you mean to make it mutable?".to_string(), + format!("{} is immutable, did you mean to declare with let?", x), reas.left.into_symbol().val, )) - }); - if let Err(err) = end { - return Err(err); - } + })?; let curried = reassignment.curried.clone(); return ok_tree!(As, reassignment, curried); } pub fn check_struct_decl(&mut self, obj: &StructDecl) -> ResultTreeType { if let Some(x) = &obj.declarators { + self.inc_scope_tracker(); + let prop_scope = self.curr_scope; let result: Vec = x.into_iter().map(|e| self.lint_recurse(&e)).collect(); + self.dec_scope_tracker(); let slice = obj.identifier.into_symbol().val.slice; let mut obj_info = StructInfo { props: vec![], types: vec![], curried: Ty::Custom(slice.clone()), + scope: prop_scope, }; result.into_iter().for_each(|res| { if let Ok(exp) = res { @@ -372,7 +433,7 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { let curried = obj_info.curried.clone(); let full = tree!(StructInfo, obj_info); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, curried)); @@ -386,23 +447,28 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { pub fn check_prop_init(&mut self, prop: &PropAssignment) -> ResultTreeType { let result = self.lint_recurse(&prop.val)?; - let slice = prop.ident.into_symbol().val.slice.clone(); + let decl = self.lint_recurse(&prop.ident)?; + let slice = decl.0.into_symbol_init().ident.clone(); + let init = Initialization { - left: slice.clone(), + left: decl.0, right: result.0, curried: result.1, }; let curried = init.curried.clone(); let full = tree!(PropInit, init); - - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); - + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, curried)); } pub fn check_props_init(&mut self, props: &PropAssignments) -> ResultTreeType { let prev = self.lint_recurse(&props.prev)?; + let current_scope = self.curr_scope; + let scope = self.get_tt_by_symbol(&prev.0.into_symbol_access().ident); + let temp_scope = scope.into_child_scope(); + self.curr_scope = temp_scope; + if let Some(p) = &props.props { let result: Vec = p.into_iter().map(|e| self.lint_recurse(&e)).collect(); @@ -419,15 +485,18 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { .vals_curried .push(x.0.into_prop_init().curried.clone()); } else { - struct_init.idents.push("unknown".to_string()); + struct_init + .idents + .push(Rc::new(Box::new(TypeTree::UnknownValue))); struct_init.vals_curried.push(Ty::Unknown); } }); + self.curr_scope = current_scope; let curried = struct_init.curried.clone(); let full = tree!(StructInit, struct_init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table .insert(prev.0.into_symbol_access().ident.clone(), Rc::clone(&full)); @@ -440,12 +509,46 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { )) } + pub fn check_enum_decl(&mut self, _enum: &EnumDecl) -> ResultTreeType { + self.inc_scope_tracker(); + let result: Vec = _enum + .variants + .iter() + .map(|e| self.lint_recurse(&e)) + .collect(); + self.dec_scope_tracker(); + let slice = _enum.identifier.into_symbol().val.slice; + let copy = slice.clone(); + let mut e_info = EnumInfo { + name: slice, + props: vec![], + curried: Ty::Enum(Box::new(Ty::U8)), + }; + result.into_iter().for_each(|res| { + if let Ok(exp) = res { + e_info.props.push(exp.0); + return; + } + e_info.props.push(simple_tree!(UnknownValue)); + }); + + let curried = e_info.curried.clone(); + let full = tree!(EnumInfo, e_info); + + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); + + tbl.table.insert(copy, Rc::clone(&full)); + return Ok((full, curried)); + } + pub fn check_tag_decl(&mut self, tag: &TagDecl) -> ResultTreeType { + self.inc_scope_tracker(); let result: Vec = tag .declarators .iter() .map(|e| self.lint_recurse(&e)) .collect(); + self.dec_scope_tracker(); let slice = tag.identifier.into_symbol().val.slice; let copy = slice.clone(); let mut tag_info = TagInfo { @@ -467,7 +570,7 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { let curried = tag_info.curried.clone(); let full = tree!(TagInfo, tag_info); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(copy, Rc::clone(&full)); return Ok((full, curried)); @@ -502,7 +605,7 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { let curried = init.block_curried.clone(); let full = tree!(FuncInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); Ok((full, curried)) @@ -510,23 +613,23 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { pub fn check_import(&mut self, import: &Import) -> ResultTreeType { let result = self.lint_recurse(&import.expr)?; - let slice = import.expr.into_chars_value().val.slice; - + let decl = self.lint_recurse(&import.identifier)?; + let slice = decl.0.into_symbol_init().ident.clone(); let init = Initialization { - left: slice.clone(), + left: decl.0, right: result.0, curried: result.1, }; let curried = init.curried.clone(); if import.mutability.token == Token::Const { let full: Rc> = tree!(ConstInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, Ty::Const(Box::new(curried)))); } let full: Rc> = tree!(MutInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, Ty::Mut(Box::new(curried)))); @@ -534,10 +637,11 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { pub fn check_inner_decl(&mut self, inner: &InnerDecl) -> ResultTreeType { let result = self.lint_recurse(&inner.expr)?; - let slice = inner.identifier.into_symbol().val.slice; + let decl = self.lint_recurse(&inner.identifier)?; + let slice = decl.0.into_symbol_init().ident.clone(); let mut init = Initialization { - left: slice.clone(), + left: decl.0, right: result.0, curried: result.1, }; @@ -545,14 +649,14 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { if inner.mutability.token == Token::Const { init.curried = Ty::Const(Box::new(init.curried)); let full: Rc> = tree!(ConstInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, Ty::Const(Box::new(curried)))); } init.curried = Ty::Mut(Box::new(init.curried)); let full: Rc> = tree!(MutInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, Ty::Mut(Box::new(curried)))); @@ -560,23 +664,25 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { pub fn check_top_decl(&mut self, td: &TopDecl) -> ResultTreeType { let result = self.lint_recurse(&td.expr)?; - let slice = td.identifier.into_symbol().val.slice; + let decl = self.lint_recurse(&td.identifier)?; + let slice = decl.0.into_symbol_init().ident.clone(); - let init = Initialization { - left: slice.clone(), + let init = TopInitialization { + left: decl.0, right: result.0, curried: result.1, + vis: td.visibility.is_some(), }; let curried = init.curried.clone(); if td.mutability.token == Token::Const { - let full: Rc> = tree!(ConstInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let full: Rc> = tree!(TopConstInit, init); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, Ty::Const(Box::new(curried)))); } - let full: Rc> = tree!(MutInit, init); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let full: Rc> = tree!(TopMutInit, init); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); return Ok((full, Ty::Mut(Box::new(curried)))); @@ -656,17 +762,31 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { return ok_tree!(Return, unop, curried); } + pub fn check_array_type(&mut self, arr: &ArrayType) -> ResultTreeType { + let result = self.lint_recurse(&arr.arr_of)?; + let curried = result.1.clone(); + let arrtype = ArrType { + arr_of: result.0, + curried: result.1, + }; + let full: Rc> = tree!(ArrayType, arrtype); + + return Ok((full, curried)); + } + pub fn check_arg_def(&mut self, arg: &ArgDef) -> ResultTreeType { match arg.ident.as_ref() { Expr::SymbolDecl(x) => { let slice = x.val.slice.clone(); let typ = self.lint_recurse(&arg.typ)?; - let a = NoOp { curried: typ.1 }; + let a = SymbolInit { + ident: slice.clone(), + curried: typ.1, + }; let curried = a.curried.clone(); - self.curr_self = Some(a.curried.clone()); let full: Rc> = tree!(ArgInit, a); - let tbl = self.ttbls.get_mut(self.curr_scope).unwrap(); + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); tbl.table.insert(slice, Rc::clone(&full)); @@ -677,9 +797,11 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { let a = NoOp { curried: typ.1 }; let curried = a.curried.clone(); - self.curr_self = Some(a.curried.clone()); + + let tbl = self.ttbls.get_mut(self.curr_scope as usize).unwrap(); let full: Rc> = tree!(SelfAccess, a); + tbl.table.insert("self".to_string(), Rc::clone(&full)); return Ok((full, curried)); } @@ -844,17 +966,17 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { return ok_tree!(ReadBorrow, unop, curried); } - pub fn check_f64(&mut self, num: &Number) -> ResultTreeType { + pub fn check_dec(&mut self, num: &Number) -> ResultTreeType { let val = num.val.slice.parse::().unwrap(); let typ = Ty::F64; return ok_tree!(F64, val, typ); } // todo:: convert this back to u64, need to check to see if it fits in i64 and return type - pub fn check_i64(&mut self, num: &Number) -> ResultTreeType { - let val = num.val.slice.parse::().unwrap(); - let typ = Ty::I64; - return ok_tree!(I64, val, typ); + pub fn check_num(&mut self, num: &Number) -> ResultTreeType { + let val = num.val.slice.parse::().unwrap(); + let typ = Ty::U64; + return ok_tree!(U64, val, typ); } pub fn lint_check(&mut self, start: &Expr) -> Vec>> { @@ -872,6 +994,25 @@ impl<'buf, 'ttb, 'sco> LintSource<'buf, 'ttb, 'sco> { _ => panic!("type-lang linter issue expected all at lint_check"), } } + fn inc_scope_tracker(&mut self) -> () { + self.ttbls.push(TypeTable::new()); + let new_curr = self.ttbls.len() - 1; + self.scopes + .push(ScopeTable::new(self.curr_scope, new_curr as u32)); + self.curr_scope = new_curr as u32; + } + fn dec_scope_tracker(&mut self) -> () { + self.curr_scope = self + .scopes + .get(self.curr_scope as usize) + .unwrap() + .parent_scope; + } + + fn get_tt_by_symbol(&mut self, sym: &str) -> &Rc> { + let scope = self.scopes.get(self.curr_scope as usize).unwrap(); + return scope.get_tt_same_up(sym, self.ttbls, self.scopes).unwrap(); + } fn set_error(&mut self, title: String, suggestion: String, lexeme: Lexeme) -> usize { let mut le = LinterError::new(title); @@ -925,9 +1066,9 @@ impl DoConvert for &Expr { Token::Utf32 => Ty::Char, Token::Utf64 => Ty::Char, Token::Bool => Ty::Char, - Token::Any => Ty::Custom("any".to_string()), - Token::Sized => Ty::Custom("sized".to_string()), - Token::Scalar => Ty::Custom("scalar".to_string()), + Token::Any => Ty::Any, + Token::Sized => Ty::Sized, + Token::Scalar => Ty::Scalar, Token::Void => Ty::Void, Token::TSelf => Ty::TSelf, _ => panic!("type-lang linter issue, not a value type"), @@ -939,6 +1080,7 @@ impl DoConvert for &Expr { #[cfg(test)] mod tests { + use super::*; use parser::*; #[test] @@ -961,4 +1103,19 @@ mod tests { } ); } + #[test] + fn it_should_handle_basic_types() { + const TEST_STR: &'static str = "const val: usize = 2 + const main = fn() void { return 7 + val } + "; + let lexer = TLexer::new(TEST_STR); + let mut parser = Parser::new(lexer); + let result = parser.all(); + let mut tts = vec![]; + let mut scps = vec![]; + let mut linter = LintSource::new(TEST_STR, &mut scps, &mut tts); + let _ = linter.lint_check(&result.unwrap()); + + assert!(linter.issues.len() == 0); + } } diff --git a/objmaker/Cargo.toml b/objmaker/Cargo.toml index 06237bc..2437392 100644 --- a/objmaker/Cargo.toml +++ b/objmaker/Cargo.toml @@ -14,5 +14,5 @@ lexer = { path = "../lexer" } linter = { path = "../linter" } token = { path = "../token" } parser = { path = "../parser" } -ir = { path = "../ir" } object = { path = "../object" } +scir = { path = "../scir" } diff --git a/objmaker/src/lib.rs b/objmaker/src/lib.rs index 371ff31..80cc63e 100644 --- a/objmaker/src/lib.rs +++ b/objmaker/src/lib.rs @@ -1,18 +1,13 @@ -use ir::IRSource; use lexer::TLexer; use linter::LintSource; -use object::build_std_fn; -use object::flush_obj; -use object::new_obj_handler; use parser::Parser; +use scir::Scir; use std::fs::create_dir; use std::fs::write; use std::fs::File; use std::io::Read; use std::path::Path; use std::path::PathBuf; -use symtable::SymTable; -use typetable::TypeTable; pub fn from_buffer(contents: &str, path: &Path) -> () { let lex = TLexer::new(&contents); @@ -22,15 +17,12 @@ pub fn from_buffer(contents: &str, path: &Path) -> () { let mut scopes = vec![]; let mut linter = LintSource::new(path.to_str().unwrap(), &mut scopes, &mut type_tables); let lint_res = linter.lint_check(&ast_parsed); - let mut ir = IRSource::new(0, SymTable::new(), linter.ttbls.get(0).unwrap()); if linter.issues.len() > 0 { for x in linter.issues { println!("{}", x); } panic!("linter issues exist"); } - let rc_thing = lint_res.first().unwrap().to_owned(); - let result = ir.begin(rc_thing); if !Path::new(".ty").is_dir() { create_dir(".ty").unwrap(); } @@ -40,38 +32,14 @@ pub fn from_buffer(contents: &str, path: &Path) -> () { output.push(".ty"); output.push(filename); output.set_extension("o"); - let mut om = new_obj_handler(filename); - build_std_fn(&mut om, result, filename); - write(output, flush_obj(om)).unwrap(); + let mut scir = Scir::new(filename, scopes, type_tables); + scir.loopf(lint_res); + write(output, scir.flush_self()).unwrap(); } pub fn from_file(input_path: &PathBuf) -> () { let mut file = File::open(input_path.clone()).unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); - let lex = TLexer::new(&contents); - let mut parse = Parser::new(lex); - let ast_parsed = parse.all().unwrap(); - let mut type_tables = vec![]; - let mut scopes = vec![]; - let mut linter = LintSource::new(input_path.to_str().unwrap(), &mut scopes, &mut type_tables); - let lint_res = linter.lint_check(&ast_parsed); - let mut ir = IRSource::new(0, SymTable::new(), linter.ttbls.get(0).unwrap()); - if linter.issues.len() > 0 { - panic!("linter issues exist"); - } - let rc_thing = lint_res.first().unwrap().to_owned(); - let result = ir.begin(rc_thing); - if !Path::new(".ty").is_dir() { - create_dir(".ty").unwrap(); - } - let wo_extension = input_path.with_extension(""); - let filename = wo_extension.file_name().unwrap().to_str().unwrap(); - let mut output = PathBuf::new(); - output.push(".ty"); - output.push(filename); - output.set_extension("o"); - let mut om = new_obj_handler(filename); - build_std_fn(&mut om, result, filename); - write(output, flush_obj(om)).unwrap(); + from_buffer(&contents, input_path); } diff --git a/oir/Cargo.toml b/oir/Cargo.toml new file mode 100644 index 0000000..0faa34d --- /dev/null +++ b/oir/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "oir" +version = "0.1.0" +edition = "2021" + +[dependencies] +cranelift-codegen = "0" +cranelift-native = "0" +cranelift-object = "0" +cranelift-module = "0" +types = { path="../types" } +datatable = { path="../datatable" } + diff --git a/oir/src/lib.rs b/oir/src/lib.rs new file mode 100644 index 0000000..93a64d8 --- /dev/null +++ b/oir/src/lib.rs @@ -0,0 +1,63 @@ +use cranelift_codegen::ir::Function; +use cranelift_codegen::settings::*; +use cranelift_codegen::Context; +use cranelift_module::{DataDescription, Linkage, Module}; +use cranelift_object::{ObjectBuilder, ObjectModule}; +use datatable::DataTable; +use types::TopInitialization; +use types::TypeTree; + +// Object intermediate representation +pub struct Oir { + pub obj_mod: ObjectModule, + pub data: DataDescription, +} + +impl Oir { + pub fn new(obj_name: &str) -> Oir { + let mut settings = builder(); + let _ = settings.set("is_pic", "true"); + let flags = Flags::new(settings); + let isa_builder = cranelift_native::builder().unwrap(); + let isa = isa_builder.finish(flags).unwrap(); + + let obj_builder = + ObjectBuilder::new(isa, obj_name, cranelift_module::default_libcall_names()).unwrap(); + Oir { + obj_mod: ObjectModule::new(obj_builder), + data: DataDescription::new(), + } + } + pub fn recurse(&mut self, expr: &TypeTree) -> () { + match expr { + TypeTree::I64(x) => self.data.define(Box::from(x.clone().to_ne_bytes())), + TypeTree::U64(x) => self.data.define(Box::from(x.clone().to_ne_bytes())), + _ => panic!("unexpected type tree in oir"), + } + } + + pub fn const_init(&mut self, init: &TopInitialization, dt: &mut DataTable) -> () { + let slice = &init.left.into_symbol_init().ident; + self.recurse(init.right.as_ref()); + let id = self + .obj_mod + .declare_data(slice, Linkage::Export, false, false) + .unwrap(); + self.obj_mod.define_data(id, &self.data).unwrap(); + dt.table.insert(slice.to_string(), id); + } + pub fn add_fn(&mut self, name: &str, func: Function) -> () { + let func_id = self + .obj_mod + .declare_function(name, Linkage::Export, &func.signature) + .unwrap(); + + let mut ctx = Context::for_function(func); + self.obj_mod.define_function(func_id, &mut ctx).unwrap(); + } + pub fn flush_self(self) -> Vec { + let object_product = self.obj_mod.finish(); + let bytes = object_product.emit().unwrap(); + return bytes; + } +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 1a449a6..29290b5 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -324,19 +324,20 @@ impl<'s> Parser<'s> { } Ok(None) } + pub fn sig_union(&mut self) -> ResultOptExpr { - let start = self.signature_no_colon(); + let left = self.signature_no_colon(); let err = self.lexer.collect_if(Token::Exclam); let undef = self.lexer.collect_if(Token::Question); - let fin = self.signature_no_colon(); - if start.is_err() { - return start; + let right = self.signature_no_colon(); + if left.is_err() { + return left; } - if fin.is_err() { - return fin; + if right.is_err() { + return right; } - match start? { - None => match fin? { + match left? { + None => match right? { None => { if err.is_none() { return Err(self.make_error( @@ -351,7 +352,7 @@ impl<'s> Parser<'s> { } }, Some(x) => { - return result_expr!(Sig, Some(x), err, undef, fin.unwrap()) + return result_expr!(Sig, Some(x), err, undef, right.unwrap()) .xconvert_to_result_opt(); } }; @@ -380,6 +381,9 @@ impl<'s> Parser<'s> { } return Ok(Some(fn_typ)); } + if muta.is_some() { + return Err(self.make_error("mutability token found but no type".to_string())); + } Ok(None) } pub fn opt_signature(&mut self) -> ResultOptExpr { @@ -589,19 +593,21 @@ impl<'s> Parser<'s> { let mut arms: Vec> = vec![]; let first_arm = self.arm()?.xexpect_expr( &self, - "expected match arm ' => ( | )'".to_string(), + "expected match arm ' => ( | | )'".to_string(), )?; arms.push(first_arm); let second_arm = self.arm()?.xexpect_expr( &self, - "expected at least 2 match arms ' => ( | )'".to_string(), + "expected at least 2 match arms ' => ( | | )'".to_string(), )?; arms.push(second_arm); loop { match self.arm() { Ok(Some(x)) => arms.push(x), Ok(None) => break, - Err(e) => return Err(e), + Err(e) => { + return Err(e); + } } } let _ = self @@ -625,14 +631,19 @@ impl<'s> Parser<'s> { .lexer .collect_if(Token::Arrow) .xexpect_token(self, "expected '=>'".to_string())?; - if let Some(blk) = self.ident() { + if let Some(anon) = self.anon_fn()? { + return result_expr!(Arm, or, anon).xconvert_to_result_opt(); + } + if self.lexer.peek().is_some_and(|l| l.token == Token::OBrace) { + let blk = self.block()?; return result_expr!(Arm, or, blk).xconvert_to_result_opt(); } - let anon = self.anon_fn()?.xconvert_to_result( - self, - "expected identifier or anonymous function'".to_string(), - )?; - result_expr!(Arm, or, anon).xconvert_to_result_opt() + let right = self.or().map_err(|err| { + return self.make_error( + "expected a block expression, anonymous function capture, or a single line expression" + .to_string()); + })?; + return result_expr!(Arm, or, right).xconvert_to_result_opt(); } pub fn or(&mut self) -> ResultExpr { @@ -773,7 +784,8 @@ impl<'s> Parser<'s> { if let None = self.lexer.collect_if(Token::CBrace) { let ident = self .ident() - .xexpect_expr(&self, "expected identifier".to_string())?; + .xexpect_expr(&self, "expected identifier".to_string()) + .xconvert_to_decl()?; let mut props: Vec> = vec![]; let _ = self .lexer @@ -784,7 +796,8 @@ impl<'s> Parser<'s> { while let Some(_comma) = self.lexer.collect_if(Token::Comma) { let id = self .ident() - .xexpect_expr(&self, "expected identifier".to_string())?; + .xexpect_expr(&self, "expected identifier".to_string()) + .xconvert_to_decl()?; let _ = self .lexer .collect_if(Token::Colon) diff --git a/scir/Cargo.toml b/scir/Cargo.toml new file mode 100644 index 0000000..536b512 --- /dev/null +++ b/scir/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "scir" +version = "0.1.0" +edition = "2021" + +[dependencies] +types = { path="../types" } +oir = { path="../oir" } +fir = { path="../fir" } +scopetable = { path="../scopetable" } +typetable = { path="../typetable" } +symtable = { path="../symtable" } +datatable = { path="../datatable" } +cranelift-frontend = "0" +cranelift-codegen = "0" diff --git a/scir/src/lib.rs b/scir/src/lib.rs new file mode 100644 index 0000000..e6c1933 --- /dev/null +++ b/scir/src/lib.rs @@ -0,0 +1,75 @@ +use cranelift_codegen::ir::Function; +use cranelift_frontend::FunctionBuilderContext; +use datatable::DataTable; +use fir::Fir; +use oir::Oir; +use scopetable::ScopeTable; +use std::rc::Rc; +use symtable::SymTable; +use types::{FunctionInitialize, TypeTree}; +use typetable::TypeTable; + +pub struct Scir { + pub oir: Oir, + pub fir: Fir, + pub dtable: DataTable, + pub scopes: Vec, + pub type_tables: Vec, + pub namespace: u32, + pub index: u32, + pub fbc: FunctionBuilderContext, +} + +// Source Compiled Intermediate Representation +// Context of a Source file, these are the scopes, name, and type tables containing the type tree +// output from the linter. +// name = the name of the source file. +// scopes = the scopes output from linter. +// type_tables = the type table output from the linter +impl Scir { + pub fn new(name: &str, scopes: Vec, type_tables: Vec) -> Scir { + Scir { + oir: Oir::new(name), + fir: Fir::new(0, SymTable::new()), + dtable: DataTable::new(), + scopes, + type_tables, + namespace: 0, + index: 0, + fbc: FunctionBuilderContext::new(), + } + } + // top_res is the output top decls of the linter + pub fn loopf(&mut self, top_res: Vec>>) -> () { + for item in &top_res { + match item.as_ref().as_ref() { + TypeTree::TopConstInit(ci) => { + self.oir.const_init(&ci, &mut self.dtable); + } + TypeTree::FuncInit(fi) => { + let _fn = self.make_fir(fi); + self.oir.add_fn(&fi.name, _fn); + } + _ => panic!("developer error, unhandled loopfval, {:?}", item.clone()), + } + } + } + fn make_fir(&mut self, fi: &FunctionInitialize) -> Function { + self.fir.refresh(); + let _fn = self.fir.run( + fi, + &mut self.fbc, + self.namespace, + self.index, + &self.dtable, + &self.scopes, + &self.type_tables, + &mut self.oir, + ); + self.index += 1; + return _fn; + } + pub fn flush_self(self) -> Vec { + return self.oir.flush_self(); + } +} diff --git a/scopetable/Cargo.toml b/scopetable/Cargo.toml index c24c2e5..e3460cf 100644 --- a/scopetable/Cargo.toml +++ b/scopetable/Cargo.toml @@ -5,4 +5,5 @@ edition = "2021" [dependencies] typetable = { path = "../typetable" } +symtable = { path = "../symtable" } types = { path = "../types" } diff --git a/scopetable/src/lib.rs b/scopetable/src/lib.rs index 39592cd..1c183db 100644 --- a/scopetable/src/lib.rs +++ b/scopetable/src/lib.rs @@ -2,34 +2,68 @@ use std::rc::Rc; use types::*; use typetable::TypeTable; +#[derive(Debug)] pub struct ScopeTable { - pub parent_scope: usize, - pub self_scope: usize, + pub parent_scope: u32, + pub self_scope: u32, } impl ScopeTable { - pub fn new(parent_scope_id: usize, self_scope: usize) -> Self { + pub fn new(parent_scope_id: u32, self_scope: u32) -> Self { ScopeTable { parent_scope: parent_scope_id, self_scope, } } + pub fn get_scope_same_up<'sco, 'ttb: 'sco>( + &'sco self, + symbol: &str, + ttbls: &'ttb Vec, + scopes: &'sco Vec, + ) -> Option { + let tbl = ttbls.get(self.self_scope as usize).unwrap(); + let sibling = tbl.table.get(symbol); + if sibling.is_some() { + return Some(self.self_scope); + } + if self.parent_scope != self.self_scope { + let ptbl = ttbls.get(self.parent_scope as usize).unwrap(); + let parent = ptbl.table.get(symbol); + if parent.is_some() { + return Some(self.parent_scope); + } + if self.parent_scope != 0 && self.self_scope != 0 { + return scopes + .get(self.parent_scope as usize) + .unwrap() + .get_scope_same_up(symbol, ttbls, scopes); + } + } + return None; + } pub fn get_tt_same_up<'sco, 'ttb: 'sco>( &'sco self, - symbol: String, + symbol: &str, ttbls: &'ttb Vec, - ) -> Option<&Rc>> { - let tbl = ttbls.get(self.self_scope).unwrap(); - let sibling = tbl.table.get(&symbol); + scopes: &'sco Vec, + ) -> Option<&'sco Rc>> { + let tbl = ttbls.get(self.self_scope as usize).unwrap(); + let sibling = tbl.table.get(symbol); if sibling.is_some() { return sibling; } if self.parent_scope != self.self_scope { - let ptbl = ttbls.get(self.parent_scope).unwrap(); - let parent = ptbl.table.get(&symbol); + let ptbl = ttbls.get(self.parent_scope as usize).unwrap(); + let parent = ptbl.table.get(symbol); if parent.is_some() { return parent; } + if self.parent_scope != 0 && self.self_scope != 0 { + return scopes + .get(self.parent_scope as usize) + .unwrap() + .get_tt_same_up(symbol, ttbls, scopes); + } } None } diff --git a/test/main.ty b/test/main.ty index f8664ee..c933ecd 100644 --- a/test/main.ty +++ b/test/main.ty @@ -1,3 +1,7 @@ +const m = 5 +const x = 7 + pub const main = fn() usize { - return 0 - 0 + const z = x - m + return 2 - z } diff --git a/test/test.ty b/test/test.ty index 66a6104..f092b40 100644 --- a/test/test.ty +++ b/test/test.ty @@ -6,8 +6,8 @@ const a = -5 // or mutatable with let let b = 2 -// enumerable types are declared as follows, similar to unions in other languages, they are called tags because they are both a union and enumerable and can contain values -const Day = tag +// enumerable types are declared as follows, +const Day = enum | monday | tuesday | wednesday @@ -20,12 +20,12 @@ const next_weekday = fn(d: Day) Day { // tags can be matched on // return must be specified return match (d) { - monday => tuesday - tuesday => wednesday - wednesday => thursday - thursday => friday + Day.monday => Day.tuesday + Day.tuesday => Day.wednesday + Day.wednesday => Day.thursday + Day.thursday => Day.friday // rest operator specifies any remaining match arms - _ => monday + _ => Day.monday } } @@ -37,8 +37,8 @@ type InvalidWeekday = error const assert_weekday = fn(d: Day) InvalidWeekday!Day { return match (d) { - saturday => InvalidWeekday - sunday => InvalidWeekday + Day.saturday => InvalidWeekday + Day.sunday => InvalidWeekday _ => d } } @@ -118,6 +118,7 @@ const q = import "std.io" // direction: u8 // } +// 3000 or so let r = Car { wheels: 0, make: "toyoba", @@ -140,5 +141,5 @@ const mul2: fn(usize) usize = fn(a) usize { return a * 2 } -// destructuring is supported -const { a, b, c } = import "std.thing" +// destructuring is supported, but not yet +// const { a, b, c } = import "std.thing" diff --git a/todos.txt b/todos.txt index 7916e87..663435f 100644 --- a/todos.txt +++ b/todos.txt @@ -1,7 +1,6 @@ - data layout -- scopes -- Bar '|' ebnf doesn't match parser, update parser for every '|' syntax -- "all function declarations must have types in arguments." this can be changed to support deducing types at some point -- impl -- trait -- modify match syntax to take place of else branches +- compiler +- scopes are just 1 single global +- work on linter, several issues there, write more tests + get more lint rules in place +- destructure could be `const x,y,z = thing()` but you lose the "structure" portion { x,y,z } diff --git a/types/src/lib.rs b/types/src/lib.rs index ef8810e..4f074ca 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -8,10 +8,21 @@ pub struct FileContainer { } #[derive(Debug)] -pub struct SigInfo { - pub left: Option, +pub struct SigTypes { + pub left: Ty, pub err: Option, pub undefined: Option, + pub right: Option, +} + +#[derive(Debug)] +pub struct ArrType { + pub arr_of: Rc>, + pub curried: Ty, +} + +#[derive(Debug)] +pub struct SingleType { pub right: Ty, } @@ -30,11 +41,19 @@ pub struct TagInfo { pub curried: Ty, } +#[derive(Debug)] +pub struct EnumInfo { + pub name: String, + pub props: Vec>>, + pub curried: Ty, +} + #[derive(Debug)] pub struct StructInfo { pub props: Vec, pub types: Vec, pub curried: Ty, + pub scope: u32, } #[derive(Debug)] @@ -100,11 +119,19 @@ pub struct Invoke { #[derive(Debug)] pub struct Initialization { - pub left: String, + pub left: Rc>, pub right: Rc>, pub curried: Ty, } +#[derive(Debug)] +pub struct TopInitialization { + pub left: Rc>, + pub right: Rc>, + pub curried: Ty, + pub vis: bool, +} + #[derive(Debug)] pub struct Reassignment { pub left: Rc>, @@ -119,6 +146,12 @@ pub struct PropAccess { pub curried: Ty, } +#[derive(Debug)] +pub struct SymbolInit { + pub ident: String, + pub curried: Ty, +} + #[derive(Debug)] pub struct SymbolAccess { pub ident: String, @@ -134,7 +167,7 @@ pub struct ArrayAccess { #[derive(Debug)] pub struct StructInitialize { - pub idents: Vec, + pub idents: Vec>>, pub vals: Vec>>, pub vals_curried: Vec, pub curried: Ty, @@ -168,8 +201,8 @@ pub enum TypeTree { StructInfo(StructInfo), DeclaratorInfo(DeclaratorInfo), TagInfo(TagInfo), + EnumInfo(EnumInfo), ErrorInfo(ErrorInfo), - SigInfo(SigInfo), // flow For(ForOp), If(IfOp), @@ -205,16 +238,18 @@ pub enum TypeTree { RestAccess(NoOp), SelfAccess(NoOp), // data types - ArgInit(NoOp), + ArgInit(SymbolInit), SelfInit(NoOp), - SymbolInit(SymbolAccess), + SymbolInit(SymbolInit), StructInit(StructInitialize), PropInit(Initialization), ArrayInit(ArrayInitialize), FuncInit(FunctionInitialize), AnonFuncInit(FunctionInitialize), ConstInit(Initialization), + TopConstInit(TopInitialization), MutInit(Initialization), + TopMutInit(TopInitialization), StringInit(ArrayInitialize), // reassignments As(Reassignment), @@ -238,6 +273,11 @@ pub enum TypeTree { U64(u64), U32(u32), F64(f64), + // typereferencing + SigTypes(SigTypes), + ValueType(Ty), + ArrayType(ArrType), + SingleType(Ty), } impl TypeTree { @@ -246,7 +286,8 @@ impl TypeTree { TypeTree::DeclaratorInfo(x) => x.curried.clone(), TypeTree::StructInfo(x) => x.curried.clone(), TypeTree::TagInfo(x) => x.curried.clone(), - TypeTree::SigInfo(x) => x.right.clone(), + TypeTree::EnumInfo(x) => x.curried.clone(), + TypeTree::SigTypes(x) => x.left.clone(), TypeTree::ErrorInfo(x) => x.curried.clone(), TypeTree::For(x) => x.body_curried.clone(), TypeTree::If(x) => x.body_curried.clone(), @@ -285,6 +326,8 @@ impl TypeTree { TypeTree::AnonFuncInit(x) => x.block_curried.clone(), TypeTree::ConstInit(x) => x.curried.clone(), TypeTree::MutInit(x) => x.curried.clone(), + TypeTree::TopConstInit(x) => x.curried.clone(), + TypeTree::TopMutInit(x) => x.curried.clone(), TypeTree::StringInit(x) => x.curried.clone(), TypeTree::As(x) => x.curried.clone(), TypeTree::PlusAs(x) => x.curried.clone(), @@ -309,6 +352,9 @@ impl TypeTree { TypeTree::ArgInit(x) => x.curried.clone(), TypeTree::SelfInit(x) => x.curried.clone(), TypeTree::SymbolInit(x) => x.curried.clone(), + TypeTree::ValueType(x) => x.clone(), + TypeTree::SingleType(x) => x.clone(), + TypeTree::ArrayType(x) => x.curried.clone(), } } pub fn into_declarator(&self) -> &DeclaratorInfo { @@ -320,15 +366,28 @@ impl TypeTree { pub fn into_func_init(&self) -> &FunctionInitialize { match self { TypeTree::FuncInit(x) => x, + TypeTree::AnonFuncInit(x) => x, _ => panic!("issue function not found"), } } + pub fn into_symbol_init(&self) -> &SymbolInit { + match self { + TypeTree::SymbolInit(x) => x, + _ => panic!("issue symbol not found"), + } + } pub fn into_symbol_access(&self) -> &SymbolAccess { match self { TypeTree::SymbolAccess(x) => x, _ => panic!("issue symbol not found"), } } + pub fn into_child_scope(&self) -> u32 { + match self { + TypeTree::StructInfo(x) => x.scope, + _ => panic!("issue property not found"), + } + } pub fn into_prop_init(&self) -> &Initialization { match self { TypeTree::PropInit(x) => x, @@ -346,7 +405,8 @@ impl TypeTree { TypeTree::StructInfo(_) => "struct declaration", TypeTree::DeclaratorInfo(_) => "property declaration", TypeTree::TagInfo(_) => "tag declaration", - TypeTree::SigInfo(_) => "type signature", + TypeTree::EnumInfo(_) => "enum declaration", + TypeTree::SigTypes(_) => "type signature", TypeTree::ErrorInfo(_) => "error declaration", TypeTree::For(_) => "for loop", TypeTree::If(_) => "if statement", @@ -385,6 +445,8 @@ impl TypeTree { TypeTree::AnonFuncInit(_) => "anonymous function initialization", TypeTree::ConstInit(_) => "constant initialization", TypeTree::MutInit(_) => "mutable initialization", + TypeTree::TopConstInit(_) => "constant initialization", + TypeTree::TopMutInit(_) => "mutable initialization", TypeTree::StringInit(_) => "string initialization", TypeTree::As(_) => "reassignment", TypeTree::PlusAs(_) => "addition reassignment", @@ -409,16 +471,25 @@ impl TypeTree { TypeTree::ArgInit(_) => "function argument", TypeTree::SelfInit(_) => "self as function argument", TypeTree::SymbolInit(_) => "symbol definition or initialization", + TypeTree::ValueType(_) => "a value type", + TypeTree::SingleType(_) => "a type", + TypeTree::ArrayType(_) => "an array type", } } } #[derive(Clone, Debug, PartialEq, Eq)] pub enum Ty { + Any, + Sized, + Scalar, I64, I32, + ISize, U64, + USize, U32, + U8, F64, Unknown, Rest, @@ -436,8 +507,10 @@ pub enum Ty { Struct(Vec), Error, Tag(Vec), + Enum(Box), Function(Vec, Box), Custom(String), + CustomError(String), Trait(String), TSelf, Array(Box), @@ -446,9 +519,14 @@ pub enum Ty { impl fmt::Display for Ty { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + Ty::Any => write!(f, "any"), + Ty::Scalar => write!(f, "scalar"), + Ty::Sized => write!(f, "sized"), Ty::I64 => write!(f, "i64"), + Ty::ISize => write!(f, "isize"), Ty::I32 => write!(f, "i32"), Ty::U64 => write!(f, "u64"), + Ty::USize => write!(f, "usize"), Ty::U32 => write!(f, "u32"), Ty::F64 => write!(f, "f64"), Ty::Unknown => write!(f, "unknown"), @@ -481,6 +559,7 @@ impl fmt::Display for Ty { Ok(()) } Ty::Error => write!(f, "error"), + Ty::CustomError(x) => write!(f, "error {}", x), Ty::Tag(x) => { write!(f, "tag ").unwrap(); for a in x { @@ -500,6 +579,8 @@ impl fmt::Display for Ty { Ty::Array(x) => write!(f, "[{}]", x), Ty::Trait(x) => write!(f, "trait {}", x), Ty::TSelf => write!(f, "self"), + Ty::U8 => write!(f, "u8"), + Ty::Enum(x) => write!(f, "enum({})", x), } } } @@ -516,6 +597,8 @@ impl Ty { Ty::MutBorrow(_) => Ok(()), Ty::Void => Err(Ty::Void), Ty::Error => Ok(()), + Ty::Unknown => Ok(()), + Ty::Undefined => Ok(()), _ => panic!("type lang issue. type not able to be associated to const"), } } diff --git a/typetable/src/lib.rs b/typetable/src/lib.rs index ba02998..7a0f074 100644 --- a/typetable/src/lib.rs +++ b/typetable/src/lib.rs @@ -2,6 +2,8 @@ use std::collections::BTreeMap; use std::rc::Rc; use types::*; +// the purpose of this table is to serve as a lookup for the types of identifiers +#[derive(Debug)] pub struct TypeTable { pub table: BTreeMap>>, }