diff --git a/editor/vscode/mclang-0.0.2.vsix b/editor/vscode/mclang-0.0.2.vsix deleted file mode 100644 index a81eedd..0000000 Binary files a/editor/vscode/mclang-0.0.2.vsix and /dev/null differ diff --git a/editor/vscode/mclang-0.0.3.vsix b/editor/vscode/mclang-0.0.3.vsix new file mode 100644 index 0000000..fc2c7ce Binary files /dev/null and b/editor/vscode/mclang-0.0.3.vsix differ diff --git a/editor/vscode/package.json b/editor/vscode/package.json index 90aeeec..25be400 100644 --- a/editor/vscode/package.json +++ b/editor/vscode/package.json @@ -2,7 +2,7 @@ "name": "mclang", "displayName": "mclang", "description": "Code highlighting for mclang", - "version": "0.0.2", + "version": "0.0.3", "repository": { "type": "git", "url": "git@github.com:mc-lang/mclang2.git" diff --git a/editor/vscode/syntaxes/mclang.tmLanguage.json b/editor/vscode/syntaxes/mclang.tmLanguage.json index 7fa7b7b..a70f660 100644 --- a/editor/vscode/syntaxes/mclang.tmLanguage.json +++ b/editor/vscode/syntaxes/mclang.tmLanguage.json @@ -112,7 +112,7 @@ ] }, "comments": { - "disabled__patterns": [ + "patterns": [ { "name": "constant.other.character-class.regexp", "match": "(?://\\s*)(TODO(O*)|FIXME).*" diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index a87969e..572caf7 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -1,5 +1,5 @@ use std::{fs, path::PathBuf, io::{Write, BufWriter}, collections::HashMap}; -use crate::{constants::{Operator, OpType, KeywordType}, Args}; +use crate::{constants::{Operator, OpType, KeywordType}, Args, warn, lerror}; use color_eyre::Result; use crate::compile::commands::linux_x86_64_compile_and_link; use crate::constants::InstructionType; @@ -25,6 +25,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ of_o.set_extension("o"); of_a.set_extension("nasm"); + let mut should_push_ret = false; let file = fs::File::create(&of_a)?; let mut writer = BufWriter::new(&file); @@ -71,11 +72,14 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " add rsp, 40")?; writeln!(writer, " ret")?; - writeln!(writer, "global _start")?; - writeln!(writer, "_start:")?; - writeln!(writer, " lea rbp, [rel ret_stack]")?; - writeln!(writer, " call main")?; - writeln!(writer, " jmp end")?; + if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode { + writeln!(writer, "global _start")?; + writeln!(writer, "_start:")?; + writeln!(writer, " lea rbp, [rel ret_stack]")?; + writeln!(writer, " call main")?; + writeln!(writer, " jmp end")?; + + } let mut ti = 0; @@ -92,10 +96,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " ;; -- {:?}", token.typ)?; } } else { - - if ti != 0 && tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) || + if ti > 0 { + if tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) || tokens[ti-1].typ == OpType::Keyword(KeywordType::End){ - writeln!(writer, "addr_{ti}:")?; + writeln!(writer, "addr_{ti}:")?; + } } if ti + 1 < tokens.len() && tokens[ti+1].typ == OpType::Keyword(KeywordType::End) { @@ -415,6 +420,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; }, InstructionType::Return => { + + if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret { + writeln!(writer, " pop rdx")?; + should_push_ret = false; + } + writeln!(writer, " sub rbp, 8")?; writeln!(writer, " mov rbx, qword [rbp]")?; writeln!(writer, " push rbx")?; @@ -429,7 +440,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ InstructionType::TypePtr | InstructionType::TypeInt | InstructionType::TypeVoid | - InstructionType::TypeStr | InstructionType::TypeAny | InstructionType::Returns | InstructionType::With => { @@ -496,10 +506,16 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " pop rbx")?; writeln!(writer, " mov qword [rbp], rbx")?; writeln!(writer, " add rbp, 8")?; - functions.push(Function { loc: token.loc.clone(), name: token.text.clone() }); + functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false}); ti += 1; }, KeywordType::FunctionDone => { + + if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret { + writeln!(writer, " pop rdx")?; + should_push_ret = false; + } + writeln!(writer, " sub rbp, 8")?; writeln!(writer, " mov rbx, qword [rbp]")?; writeln!(writer, " push rbx")?; @@ -509,16 +525,71 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ KeywordType::FunctionThen => ti += 1, KeywordType::Function | KeywordType::Include | + KeywordType::Inline | + KeywordType::Export | KeywordType::Constant => unreachable!(), + KeywordType::FunctionDefExported => { + + if !crate::config::ENABLE_EXPORTED_FUNCTIONS { + lerror!(&token.loc, "Experimental feature 'exported functions' is not enabled"); + return Err(eyre!("")); + } + + writeln!(writer, "global {}", token.text)?; + writeln!(writer, "{}:", token.text)?; + + writeln!(writer, " pop rbx")?; + writeln!(writer, " mov qword [rbp], rbx")?; + writeln!(writer, " add rbp, 8")?; + warn!("External functions are highly experimental and should be treated as such"); + if token.types.0 == 0 { + writeln!(writer, " ; no arguments")?; + } else { + if token.types.0 >= 1 { + writeln!(writer, " push rdi")?; + } + if token.types.0 >= 2 { + writeln!(writer, " push rsi")?; + } + if token.types.0 >= 3 { + writeln!(writer, " push rdx")?; + } + if token.types.0 >= 4 { + writeln!(writer, " push rcx")?; + } + if token.types.0 >= 5 { + writeln!(writer, " push r8")?; + } + if token.types.0 >= 6 { + writeln!(writer, " push r9")?; + } + if token.types.0 >= 7 { + lerror!(&token.loc, "More than 6 arguments in an external function is not supported"); + return Err(eyre!("")); + } + } + + if token.types.1 == 1 { + should_push_ret = true; + } else if token.types.1 > 1 { + lerror!(&token.loc, "More than 1 return arguments in an external function is not supported"); + return Err(eyre!("")); + } + + functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false}); + ti += 1; + }, } } } } writeln!(writer, "addr_{ti}:")?; - writeln!(writer, "end:")?; - writeln!(writer, " mov rax, 60")?; - writeln!(writer, " mov rdi, 0")?; - writeln!(writer, " syscall")?; + if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode { + writeln!(writer, "end:")?; + writeln!(writer, " mov rax, 60")?; + writeln!(writer, " mov rdi, 0")?; + writeln!(writer, " syscall")?; + } writeln!(writer, "segment .data")?; for (i, s) in strings.iter().enumerate() { let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::>(); diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 8391aa0..542e6ed 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -23,5 +23,6 @@ pub struct Memory { #[derive(Debug, Clone)] pub struct Function { pub loc: Loc, - pub name: String + pub name: String, + pub exter: bool, } \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 55ff8b4..214c4be 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,7 @@ /** * Prints out extra information */ -pub const DEV_MODE: bool = true; +pub const DEV_MODE: bool = false; pub const DEFAULT_OUT_FILE: &str = "a.out"; pub const DEFAULT_INCLUDES: [&str;1] = [ @@ -17,4 +17,10 @@ pub const DEFAULT_INCLUDES: [&str;1] = [ * if you have buffer overflow consider increasing these */ pub const MEM_SZ: usize = 640 * 1000; // 4kb -pub const STRING_SZ: usize = 640 * 1000; // 4kb \ No newline at end of file +pub const STRING_SZ: usize = 640 * 1000; // 4kb + + +/** + * Experimental options + */ +pub const ENABLE_EXPORTED_FUNCTIONS: bool = false; \ No newline at end of file diff --git a/src/constants.rs b/src/constants.rs index ea7d9e2..9027aa6 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -58,7 +58,7 @@ pub enum InstructionType { TypePtr, TypeInt, TypeVoid, - TypeStr, + // TypeStr, TypeAny, Returns, With, @@ -84,8 +84,11 @@ pub enum KeywordType { ConstantDef, Function, FunctionDef, + FunctionDefExported, FunctionThen, - FunctionDone + FunctionDone, + Inline, + Export } #[derive(Debug, Clone, PartialEq)] @@ -102,7 +105,8 @@ pub struct Operator{ pub text: String, //? only used for OpType::PushStr pub addr: Option, //? only used for OpType::PushStr pub jmp: usize, - pub loc: Loc + pub loc: Loc, + pub types: (usize, usize) } impl Operator { @@ -115,13 +119,19 @@ impl Operator { text, loc: (file, row, col), tok_typ, + types: (0, 0) } } - pub fn set_addr(mut self, addr: usize) -> Self { + pub fn set_addr(&mut self, addr: usize) -> Self { self.addr = Some(addr); - self + (*self).clone() } + // pub fn set_types(&mut self, args: usize, rets: usize) -> Self { + // self.types = (args, rets); + // (*self).clone() + // } + } impl OpType { @@ -178,7 +188,6 @@ impl OpType { InstructionType::TypePtr => "ptr", InstructionType::TypeInt => "int", InstructionType::TypeVoid => "void", - InstructionType::TypeStr => "str", InstructionType::Returns => "returns", InstructionType::With => "with", InstructionType::TypeAny => "any", @@ -198,7 +207,10 @@ impl OpType { KeywordType::FunctionThen => "then", KeywordType::FunctionDone => "done", KeywordType::ConstantDef => "constant Definition (internal)", - KeywordType::FunctionDef => "function definition (internal)" + KeywordType::FunctionDef => "function definition (internal)", + KeywordType::FunctionDefExported => "extern function definition (internal)", + KeywordType::Inline => "inline", + KeywordType::Export => "export", } } @@ -255,7 +267,6 @@ pub enum Types { Ptr, Int, Void, - Str, Any // U8, // U16, diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 7ed383f..62c686e 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -328,7 +328,6 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ InstructionType::TypePtr | InstructionType::TypeInt | InstructionType::TypeVoid | - InstructionType::TypeStr | InstructionType::TypeAny | InstructionType::Returns | InstructionType::With => ip += 1, @@ -362,6 +361,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ KeywordType::While | //* exept this one, this one should just skip over KeywordType::Memory | KeywordType::FunctionDef | + KeywordType::FunctionDefExported | KeywordType::ConstantDef => { //? Disabled since we now pre run the whole program // constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false }); @@ -378,6 +378,8 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ KeywordType::FunctionThen => ip += 1, KeywordType::Constant | KeywordType::Function | + KeywordType::Inline | + KeywordType::Export | KeywordType::Include => unreachable!(), } } @@ -407,6 +409,9 @@ pub fn pre_run(ops: &[Operator]) -> Defineds { OpType::Keyword(KeywordType::Memory) => { defineds.memories.insert(op.addr.unwrap(), Memory { size: op.value, loc: op.loc.clone(), id: op.addr.unwrap() }); }, + OpType::Keyword(KeywordType::FunctionDefExported) => { + + } OpType::Keyword(KeywordType::FunctionDef) => { defineds.functions.insert(op.text.clone(), Function { loc: op.loc.clone(), name: op.text.clone(), id: ip }); }, diff --git a/src/main.rs b/src/main.rs index 5aa2839..9de7469 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,6 +57,9 @@ pub struct Args { #[arg(long, short='O', default_value_t=String::from("0"))] optimisation: String, + // disables the main function + #[arg(long="lib")] + lib_mode: bool //#[arg(long, short='F')] //features: Vec, diff --git a/src/parser.rs b/src/parser.rs index cd9d395..61ffe43 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -44,9 +44,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { program[ip].jmp = program[block_ip].jmp; program[block_ip].jmp = ip + 1; } - OpType::Keyword(KeywordType::FunctionThen) => { - program[ip].typ = OpType::Instruction(InstructionType::Return); - } + OpType::Keyword(KeywordType::Memory | KeywordType::Constant) => (), a => { @@ -208,6 +206,8 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "fn" => OpType::Keyword(KeywordType::Function), "then" => OpType::Keyword(KeywordType::FunctionThen), "done" => OpType::Keyword(KeywordType::FunctionDone), + "inline" => OpType::Keyword(KeywordType::Inline), + "export" => OpType::Keyword(KeywordType::Export), "return" => OpType::Instruction(InstructionType::Return), "returns" => OpType::Instruction(InstructionType::Returns), "bool" => OpType::Instruction(InstructionType::TypeBool), @@ -215,7 +215,6 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "ptr" => OpType::Instruction(InstructionType::TypePtr), "void" => OpType::Instruction(InstructionType::TypeVoid), "any" => OpType::Instruction(InstructionType::TypeAny), - "str" => OpType::Instruction(InstructionType::TypeStr), "with" => OpType::Instruction(InstructionType::With), _ => OpType::Instruction(InstructionType::None) } diff --git a/src/preprocessor.rs b/src/preprocessor.rs index 719bc89..360e47b 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -17,7 +17,9 @@ use crate::parser::lookup_word; #[derive(Debug, Clone)] pub struct Function { pub loc: Loc, - pub name: String + pub name: String, + pub inline: bool, + pub tokens: Option> } #[derive(Debug, Clone)] @@ -62,20 +64,21 @@ impl<'a> Preprocessor<'a> { pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{ // println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::>>()); + let mut f_inline = false; + let mut f_extern = false; + let mut program: Vec = Vec::new(); let mut rtokens = self.program.clone(); rtokens.reverse(); while !rtokens.is_empty() { - let mut token = rtokens.pop().unwrap(); + let mut op = rtokens.pop().unwrap(); // println!("{token:?}"); - let op_type = token.typ.clone(); - match token.clone() { - - - _ if op_type == OpType::Keyword(KeywordType::Include) => { + let op_type = op.typ.clone(); + match op_type { + OpType::Keyword(KeywordType::Include) => { if rtokens.is_empty() { - lerror!(&token.loc, "Include path not found, expected {} but found nothing", TokenType::String.human()); + lerror!(&op.loc, "Include path not found, expected {} but found nothing", TokenType::String.human()); return Err(eyre!("")); } @@ -127,9 +130,10 @@ impl<'a> Preprocessor<'a> { } - _ if op_type == OpType::Keyword(KeywordType::Memory) => { + + OpType::Keyword(KeywordType::Memory) => { if rtokens.is_empty() { - lerror!(&token.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human()); + lerror!(&op.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human()); return Err(eyre!("")); } @@ -159,19 +163,20 @@ impl<'a> Preprocessor<'a> { if res.len() != 1 { - lerror!(&token.loc, "Expected 1 number, got {:?}", res); + lerror!(&op.loc, "Expected 1 number, got {:?}", res); return Err(eyre!("")); } - token.value = res[0]; - token.addr = Some(self.memories.len()); - program.push(token.clone()); + op.value = res[0]; + op.addr = Some(self.memories.len()); + program.push(op.clone()); - self.memories.insert(name.text, Memory { loc: token.loc, id: self.memories.len() }); + self.memories.insert(name.text, Memory { loc: op.loc, id: self.memories.len() }); } - _ if op_type == OpType::Keyword(KeywordType::Function) => { + + OpType::Keyword(KeywordType::Function) => { if rtokens.is_empty() { - lerror!(&token.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human()); + lerror!(&op.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human()); return Err(eyre!("")); } @@ -206,20 +211,130 @@ impl<'a> Preprocessor<'a> { self.is_word_available(&name, KeywordType::Function)?; - self.functions.insert(name.text.clone(), Function{ - loc: name.loc.clone(), - name: name.text.clone(), - }); + if f_inline { + f_inline = false; + let mut prog: Vec = Vec::new(); + let mut depth = -1; + while !rtokens.is_empty() { + let op = rtokens.pop().unwrap(); - let mut fn_def = token.clone(); - fn_def.typ = OpType::Keyword(KeywordType::FunctionDef); - fn_def.text = name.text; - // println!("{:?}", token); - program.push(fn_def); + match op.typ.clone() { + OpType::Instruction(i) => { + match i { + InstructionType::TypeAny | + InstructionType::TypeBool | + InstructionType::TypeInt | + InstructionType::TypePtr | + InstructionType::With | + InstructionType::Returns | + InstructionType::TypeVoid => { + if depth >= 0 { + prog.push(op); + } + }, + _ => prog.push(op) + } + } + OpType::Keyword(k) => { + match k { + KeywordType::Inline | + KeywordType::Include => { + todo!("make error") + }, + KeywordType::FunctionThen => { + if depth >= 0 { + prog.push(op); + } + depth += 1; + }, + KeywordType::FunctionDone => { + if depth == 0 { + break; + } + + depth -= 1; + }, + _ => prog.push(op) + } + } + } + } + let mut pre = self.clone(); + pre.program = prog; + pre.preprocess()?; + prog = pre.get_ops(); + + self.functions.insert(name.text.clone(), Function{ + loc: name.loc.clone(), + name: name.text.clone(), + inline: true, + tokens: Some(prog) + }); + + } else if f_extern { + f_extern = false; + self.functions.insert(name.text.clone(), Function{ + loc: name.loc.clone(), + name: name.text.clone(), + inline: false, + tokens: None + }); + let mut a: Vec = Vec::new(); + let mut fn_def = op.clone(); + a.push(rtokens.pop().unwrap()); + let mut ret = false; + while !rtokens.is_empty() { + let op = rtokens.pop().unwrap(); + // println!("{:?}",op); + a.push(op.clone()); + if op.typ == OpType::Instruction(InstructionType::Returns) { + ret = true; + } + + if op.typ == OpType::Keyword(KeywordType::FunctionThen) { + break; + } + + if op.typ == OpType::Instruction(InstructionType::TypeBool) || + op.typ == OpType::Instruction(InstructionType::TypeInt) || + op.typ == OpType::Instruction(InstructionType::TypePtr) { + + if ret { + fn_def.types.1 += 1; + } else { + fn_def.types.0 += 1; + } + } + } + + fn_def.typ = OpType::Keyword(KeywordType::FunctionDefExported); + fn_def.text = name.text; + // fn_def.set_types(args, rets); + // println!("{:?}", fn_def.types); + program.push(fn_def); + program.append(&mut a); + + + } else { + + self.functions.insert(name.text.clone(), Function{ + loc: name.loc.clone(), + name: name.text.clone(), + inline: false, + tokens: None + }); + + let mut fn_def = op.clone(); + fn_def.typ = OpType::Keyword(KeywordType::FunctionDef); + fn_def.text = name.text; + // println!("{:?}", token); + program.push(fn_def); + } } - _ if op_type == OpType::Keyword(KeywordType::Constant) => { + + OpType::Keyword(KeywordType::Constant) => { if rtokens.is_empty() { - lerror!(&token.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human()); + lerror!(&op.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human()); return Err(eyre!("")); } // println!("{token:?}"); @@ -263,7 +378,7 @@ impl<'a> Preprocessor<'a> { // println!("{:?}", self.constants); - let mut const_def = token.clone(); + let mut const_def = op.clone(); const_def.typ = OpType::Keyword(KeywordType::ConstantDef); const_def.text = name.text; @@ -271,14 +386,14 @@ impl<'a> Preprocessor<'a> { if item.tok_typ == TokenType::Int { const_def.value = item.value; } else { - lerror!(&token.loc, "For now only {:?} is allowed in constants", TokenType::Int); + lerror!(&op.loc, "For now only {:?} is allowed in constants", TokenType::Int); return Err(eyre!("")); } let posibly_end = rtokens.pop(); // println!("end: {posibly_end:?}"); if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) { - lerror!(&token.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing"); + lerror!(&op.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing"); return Err(eyre!("")); } // token.value = @@ -286,9 +401,32 @@ impl<'a> Preprocessor<'a> { program.push(const_def); } + OpType::Keyword(KeywordType::Inline) => { + if f_extern { + lerror!(&op.loc, "Function is already marked as extern, function cannot be inline and extern at the same time"); + return Err(eyre!("")); + } else if f_inline { + lerror!(&op.loc, "Function is already marked as inline, remove this inline Keyword"); + return Err(eyre!("")); + } else { + f_inline = true; + } + } + + OpType::Keyword(KeywordType::Export) => { + if f_inline { + lerror!(&op.loc, "Function is already marked as inline, function cannot be inline and extern at the same time"); + return Err(eyre!("")); + } else if f_extern { + lerror!(&op.loc, "Function is already marked as extern, remove this extern Keyword"); + return Err(eyre!("")); + } else { + f_extern = true; + } + } + _ => { - - program.push(token); + program.push(op); } } } @@ -303,6 +441,7 @@ impl<'a> Preprocessor<'a> { f.typ != OpType::Instruction(InstructionType::FnCall) && f.typ != OpType::Instruction(InstructionType::MemUse) && f.typ != OpType::Keyword(KeywordType::FunctionDef) && + f.typ != OpType::Keyword(KeywordType::FunctionDefExported) && f.typ != OpType::Keyword(KeywordType::ConstantDef) && f.typ != OpType::Instruction(InstructionType::ConstUse) { lookup_word(&f.text, &f.loc) @@ -334,15 +473,18 @@ impl<'a> Preprocessor<'a> { if op.tok_typ == TokenType::Word { match op_type { OpType::Instruction(InstructionType::None) => { - let m = self.functions.get(&op.text); + let m = self.functions.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__")); let mem = self.memories.get(&op.text); - let cons = self.constants.get(&op.text); + let cons = self.constants.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__")); if let Some(m) = m { - // println!("------ FOUND FUNCTION {} -----------", m.name); - let mut t = op.clone(); - t.typ = OpType::Instruction(InstructionType::FnCall); - t.text = m.name.clone(); - program.push(t.clone()); + if m.inline { + program.append(&mut m.tokens.clone().unwrap()); + } else { + let mut t = op.clone(); + t.typ = OpType::Instruction(InstructionType::FnCall); + t.text = m.name.clone(); + program.push(t.clone()); + } // println!("##### {:?}", t); } else if let Some(mem) = mem { diff --git a/src/typechecker.rs b/src/typechecker.rs index a32c653..1d256b0 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -62,9 +62,10 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> stack_pop(&mut stack, &op, &[Types::Bool])?; }, + KeywordType::FunctionDefExported | KeywordType::FunctionDef => { let name = op.text.clone(); - + // println!("{:?}", name); if let Some(p) = rtokens.pop() { if p.typ != OpType::Instruction(InstructionType::With){ lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ); @@ -105,8 +106,6 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> continue; } Types::Void - } else if op.typ == OpType::Instruction(InstructionType::TypeStr) { - Types::Str } else if op.typ == OpType::Instruction(InstructionType::TypeAny) { Types::Any } else { @@ -176,7 +175,12 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> }, KeywordType::FunctionThen | KeywordType::FunctionDone | - KeywordType::Function => unreachable!(), + KeywordType::Inline | + KeywordType::Export | + KeywordType::Function => { + println!("{:?}", op); + unreachable!() + }, } }, OpType::Instruction(instruction) => { @@ -330,7 +334,10 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> InstructionType::FnCall => { stack_snapshots.push(stack.clone()); - let f = functions.get(&op.text).unwrap().clone(); + let f = if let Some(f) = functions.get(&op.text) {f} else { + lerror!(&op.loc, "Could not find function {}", op.text); + return Err(eyre!("")); + }; // in_function = (op.text.clone(), f.clone(), op.loc.clone()); @@ -360,7 +367,6 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> InstructionType::TypeInt | InstructionType::TypeVoid | InstructionType::TypeAny | - InstructionType::TypeStr | InstructionType::Returns | InstructionType::With => (), InstructionType::ConstUse => { diff --git a/test.mcl b/test.mcl index c2cfa73..4e424cf 100644 --- a/test.mcl +++ b/test.mcl @@ -1,5 +1,12 @@ -include "std.mcl" +// include "std.mcl" +fn mcl_print with int ptr returns void then + 1 1 syscall3 drop +done + +fn mcl_dump with int returns void then + _dbg_print +done fn main with void returns void then - "hi\n" puts -done \ No newline at end of file + "hi\n" mcl_print +done