diff --git a/src/IR/func.rs b/src/IR/func.rs index a7c11412..4181230e 100644 --- a/src/IR/func.rs +++ b/src/IR/func.rs @@ -16,6 +16,8 @@ pub struct FunctionType { pub args: Vec<(/*num*/usize, TypeMetadata)>, /// The return type pub ret: TypeMetadata, + /// After the given arguments any argument type can be supplied (like the printf function - is in c ...) + pub any_args: bool, } impl FunctionType { @@ -35,9 +37,16 @@ impl FunctionType { ret }, ret: ret, + any_args: false, } } + /// Activates dynamic arguments + /// Makes that you can supply any argument after the fixed given arguments + pub fn activate_dynamic_arguments(&mut self) { + self.any_args = true; + } + /// Returns the argument as a var /// If the num doesn't exists, it panics pub fn arg(&self, num: usize) -> Var { diff --git a/src/IR/ir.rs b/src/IR/ir.rs index d25e64d4..21ef428f 100644 --- a/src/IR/ir.rs +++ b/src/IR/ir.rs @@ -631,10 +631,18 @@ impl Ir for Call, Var> { } let mut index = 0; + let args = &self.inner1.ty.args; for arg in &self.inner2 { - if matches!(self.inner1.ty.args.get(index), Some((_, argty)) if *argty != (*arg).ty.into()) { - Err(VerifyError::IDontWantToAddAnErrorMessageHereButItsAnError)? + if index < args.len() { + if matches!(args.get(index), Some((_, argty)) if *argty != (*arg).ty.into()) { + Err(VerifyError::InvalidArgumentTypeFound)? + } + } else { + if !self.inner1.ty.any_args { + Err(VerifyError::ToManyArgumentsWereSupplyed)? + } } + index += 1; } diff --git a/src/IR/mod.rs b/src/IR/mod.rs index f19e63da..a0d5a19e 100644 --- a/src/IR/mod.rs +++ b/src/IR/mod.rs @@ -27,8 +27,10 @@ pub enum VerifyError { RetTyNotFnTy(TypeMetadata, TypeMetadata), /// The type of op0 operand doesn't match the type of the op1 operand Op0Op1TyNoMatch(TypeMetadata, TypeMetadata), - /// I am to lazy to add an error message here - IDontWantToAddAnErrorMessageHereButItsAnError, + /// The given argument type doesn't overllap with the actual argument type + InvalidArgumentTypeFound, + /// To many arguments were supplyed + ToManyArgumentsWereSupplyed, } impl Display for VerifyError { @@ -47,8 +49,15 @@ impl Display for VerifyError { ) }, - VerifyError::IDontWantToAddAnErrorMessageHereButItsAnError => { - "i am to lazy to add an useful error message here. go ahed and create an github issue".to_string() + VerifyError::InvalidArgumentTypeFound => { + format!( + "an unexpected argument type was found" + ) + }, + VerifyError::ToManyArgumentsWereSupplyed => { + format!( + "too many arguments were supplyed" + ) } }) } diff --git a/src/IR/module.rs b/src/IR/module.rs index e1b5130b..deef2b10 100644 --- a/src/IR/module.rs +++ b/src/IR/module.rs @@ -188,7 +188,14 @@ impl Module { lines.push_str("section .rodata\n\n"); for (_, consta) in &self.consts { - lines.push_str(&format!("{}: {:?}\n", consta.name, consta.data)); + lines.push_str(&format!("{}: {:?} # {}\n", consta.name, consta.data, consta.data.iter() + .filter_map(|&byte| { + if byte >= 32 && byte <= 126 { + Some(byte as char) + } else { + None + } + }).collect::())); } lines.push_str("section .text\n\n"); @@ -206,12 +213,16 @@ impl Module { for block in &func.blocks { if block.name.to_lowercase() != "entry" { - lines += &format!(" {}:\n", block.name) + lines += &format!("\t.{}:\n", block.name) } let asm_lines = registry.buildAsmForTarget(triple, block, func)?; for line in asm_lines { + if line.starts_with("#") { // debug + lines.pop(); // \n + } + lines += &format!("\t{}\n", line); } } diff --git a/src/Target/x64/asm/instr.rs b/src/Target/x64/asm/instr.rs index dba1f8dd..08a091eb 100644 --- a/src/Target/x64/asm/instr.rs +++ b/src/Target/x64/asm/instr.rs @@ -81,9 +81,7 @@ impl Instr { if let Some(Operand::Reg(op0)) = &self.op1 { let op0 = op0.as_any().downcast_ref::().expect("expected x64 registers and not the ones from other archs"); - - println!("mov r, r"); - + if op0.extended() { rex.b = true; } @@ -327,6 +325,7 @@ impl Instr { (vec![], None) } } + Mnemonic::Debug => (vec![], None), }) } @@ -406,7 +405,7 @@ impl Instr { } } } - Mnemonic::Link => {}, + Mnemonic::Link | Mnemonic::Debug => {}, Mnemonic::Endbr64 => { if self.op1.is_some() || self.op2.is_some() { Err(InstrEncodingError::InvalidVariant(self.clone(), "endbr64 can't have operands".to_string()))? @@ -437,6 +436,7 @@ impl Instr { Operand::Reg(reg) => profile.markup(®.to_string(), ColorClass::Var), Operand::Mem(mem) => profile.markup(&format!("{}", mem), ColorClass::Var), Operand::LinkDestination(_, _) => "".to_string(), + Operand::Debug(s) => s.to_string(), })); if let Some(op2) = &self.op2 { string.push_str(&format!(", {}", match op2 { @@ -444,6 +444,7 @@ impl Instr { Operand::Reg(reg) => profile.markup(&format!(", {}", reg.to_string()), ColorClass::Var), Operand::Mem(mem) => profile.markup(&format!("{}", mem), ColorClass::Var), Operand::LinkDestination(_, _) => "".to_string(), + Operand::Debug(s) => s.to_string(), })); } } @@ -556,6 +557,8 @@ pub enum Mnemonic { /// here's a link placed Link, + /// for debugging pourpusis + Debug, } impl FromStr for Mnemonic { @@ -602,6 +605,7 @@ impl Display for Mnemonic { Mnemonic::Jmp => "jmp", Mnemonic::Endbr64 => "endbr64", Mnemonic::Link => "", + Mnemonic::Debug => "#", }) } } @@ -617,6 +621,8 @@ pub enum Operand { Mem(MemOp), /// The link destination LinkDestination(String, i64), + //// For debugging pourpusis + Debug(String), } impl PartialEq for Operand { @@ -626,6 +632,7 @@ impl PartialEq for Operand { (Self::Reg(l0), Self::Reg(r0)) => l0 == r0, (Self::Mem(l0), Self::Mem(r0)) => l0 == r0, (Self::LinkDestination(l0, l1), Self::LinkDestination(r0, r1)) => l0 == r0 && l1 == r1, + (Self::Debug(l0), Self::Debug(r0)) => l0 == r0, _ => false, } } @@ -638,6 +645,7 @@ impl Display for Operand { Operand::Reg(reg) => reg.to_string(), Operand::Mem(mem) => format!("{}", mem), Operand::LinkDestination(_, _) => "".to_string(), + Operand::Debug(s) => s.to_string(), }) } } diff --git a/src/Target/x64/ir.rs b/src/Target/x64/ir.rs index 65f27aad..bd367a85 100644 --- a/src/Target/x64/ir.rs +++ b/src/Target/x64/ir.rs @@ -692,6 +692,7 @@ pub(crate) fn buildAsmX86<'a>(block: &'a Block, func: &Function, call: &CallConv for node in &block.nodes { let compiled = node.compile(registry); out.extend(compiled); + out.push_back(Instr::with1(Mnemonic::Debug, Operand::Debug(format!("{}", node.dump())))); } registry.block = None; diff --git a/tools/simplelang/ast.rs b/tools/simplelang/ast.rs index e4c92fba..34423c1b 100644 --- a/tools/simplelang/ast.rs +++ b/tools/simplelang/ast.rs @@ -36,6 +36,7 @@ pub struct FnStmt { pub extrn: bool, pub import: bool, + pub dynamic_args: bool, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/tools/simplelang/codegen.rs b/tools/simplelang/codegen.rs index ec5c6e11..6c2e1830 100644 --- a/tools/simplelang/codegen.rs +++ b/tools/simplelang/codegen.rs @@ -65,6 +65,10 @@ impl CodeGenerator { let mut builder = IRBuilder(); + if func.dynamic_args { + func_ty.activate_dynamic_arguments(); + } + let mut fun = Func(func.name.to_string(), func_ty); if func.extrn { @@ -161,6 +165,8 @@ impl CodeGenerator { fn gen_string(&mut self, builder: &mut IRBuilder, string: &String) -> Var { let constant = self.module.addConst(&format!(".const{}", self.const_index)); + self.const_index += 1; + let mut string = string.clone(); string.push('\0'); diff --git a/tools/simplelang/example.sl b/tools/simplelang/example.sl index e2a534ad..214083da 100644 --- a/tools/simplelang/example.sl +++ b/tools/simplelang/example.sl @@ -13,15 +13,14 @@ HOW TO RUN: */ -import with (fmt: string) printf // printf from libc +import with (fmt: string, ...) printf // printf from libc extern with () main: { - var x: string = "Hello World!"; + printf("Hello World!\n"); - x += 6; - x -= 4; + var x: u32 = 5; - printf(x); + printf("%d = %d", x, 5); return 0; } \ No newline at end of file diff --git a/tools/simplelang/lexer.rs b/tools/simplelang/lexer.rs index a9781aa2..25a5e9cc 100644 --- a/tools/simplelang/lexer.rs +++ b/tools/simplelang/lexer.rs @@ -100,6 +100,9 @@ pub enum Token { #[token(":")] DoubleDot, + #[token("...")] + TripleDot, + #[token("return")] Return, diff --git a/tools/simplelang/main.rs b/tools/simplelang/main.rs index 25163fbd..f0440528 100644 --- a/tools/simplelang/main.rs +++ b/tools/simplelang/main.rs @@ -78,7 +78,7 @@ pub fn main() -> Result<(), Box> { }; let _tmp; - err!(_tmp, "{:?}", error); + err!(_tmp, "{}", error); exit(-1); } } diff --git a/tools/simplelang/parser.rs b/tools/simplelang/parser.rs index 2f62e23c..0c7eb6fd 100644 --- a/tools/simplelang/parser.rs +++ b/tools/simplelang/parser.rs @@ -71,14 +71,24 @@ impl Parser { let mut args = vec![]; + let mut dynamic_args = false; + loop { match self.tokens.front()? { Token::Ident(_) => args.push(Expr::Var(self.parse_var()?)), + Token::TripleDot => { + dynamic_args = true; + self.tokens.pop_front(); + }, Token::RParam => break, _ => { return None; }, } if let Some(Token::Comma) = self.tokens.front() { + if dynamic_args { + err!(self.error, "after a any arg indicator (...) no arguments are allowed to be there"); + return None; + } self.tokens.pop_front(); } } @@ -101,6 +111,7 @@ impl Parser { args: args, extrn: false, import: import, + dynamic_args: dynamic_args, })) } @@ -137,6 +148,7 @@ impl Parser { body: body, args: args, extrn: extrn, + dynamic_args: dynamic_args, import: false, // we handled imported functions earlier })) diff --git a/tools/simplelang/semnatic.rs b/tools/simplelang/semnatic.rs index 224e73ac..27055339 100644 --- a/tools/simplelang/semnatic.rs +++ b/tools/simplelang/semnatic.rs @@ -9,7 +9,7 @@ use crate::{ast::*, err, warn}; pub struct Semnatic { stmts: VecDeque, - funcs: HashMap, /*body*/Vec)>, + funcs: HashMap, /*body*/Vec, /*dynamic amount of args*/bool)>, in_binary: bool, @@ -50,13 +50,23 @@ impl Semnatic { fn analyze_func(&mut self, func: &FnStmt) { if self.funcs.contains_key(&func.name) { - err!(self.error, "func {:?} defined twice", func.name); + err!(self.error, "func {} defined twice", func.name); return; } let mut vars = HashMap::new(); let mut args = vec![]; + if func.import && func.body.len() > 0 { + err!(self.error, "imported functions aren't allowed to have a body but {} has", func.name); + return; + } + + if func.dynamic_args && !func.import { + err!(self.error, "only imported functions are allowed to have a variable amount of arguments. But func {} has", func.name); + return; + } + for arg in &func.args { match arg { Expr::Var(var) => { @@ -76,7 +86,7 @@ impl Semnatic { return; } - self.funcs.insert(func.name.to_string(), (args, vec![])); + self.funcs.insert(func.name.to_string(), (args, vec![], func.dynamic_args)); return; } @@ -172,13 +182,18 @@ impl Semnatic { return; } - let (args, _) = self.funcs.get(&call.name).unwrap(); + let (args, _, dynamic) = self.funcs.get(&call.name).unwrap(); let args = args.len(); let given = call.args.len(); - if args != given { - err!(self.error, "expected {} arguments found {}", args, given); + if args != given && !dynamic { + err!(self.error, "expected {} argument(s) found {}", args, given); + return; + } + + if args > given { + err!(self.error, "too few arguments were supplyed (expected {} found {})", args, given); return; }