diff --git a/src/main.rs b/src/main.rs index fb4473f..ddb7201 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,7 +64,9 @@ main() = int { if let Ok(mut tokens) = tokenize(source, &mut diagnostics) { if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) { - vmrt::compile(&fs, &ds); + if let Ok(prog) = vmrt::compile(&fs, &ds) { + vmrt::execute(&prog); + } } } diff --git a/src/parser/data.rs b/src/parser/data.rs index 556eace..2f123bb 100644 --- a/src/parser/data.rs +++ b/src/parser/data.rs @@ -146,6 +146,21 @@ impl<'a> Declr<'a> { } } + pub fn main() -> Self { + let mut main = Declr { + name: Some("main"), + args: None, + results: true, + result_typ: Some(Prim::Int), + info: None, + uuid: 0 + }; + + main.gen_uuid(); + + main + } + pub fn get_arg_ord(&self, name: &str) -> usize { if let Some(args) = self.args.as_ref() { for (x, arg) in args.iter().enumerate() { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index ad4c550..fcdef03 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -493,7 +493,7 @@ fn collapse_operation( ) -> Result<(), ()> { match operation { - Token::Operator(op, _, dbginf) => op.operate(operands, &dbginf, diagnostics)?, + Token::Operator(op, ref mut typehint, dbginf) => *typehint = Some(op.operate(operands, &dbginf, diagnostics)?), Token::Assign(name, ref mut typ, dbginf) => { check_var_typ(typ, operands, &dbginf, diagnostics)?; scope.decl_var((*name).to_owned(), typ.clone()); diff --git a/src/token/mod.rs b/src/token/mod.rs index 29f0ac1..6bccd46 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -115,13 +115,23 @@ impl Operator { } } + fn operation_type(operands: &[Prim]) -> Option { + let mut typ = None; + for op in operands.iter() { + op.merge_types(&mut typ); + } + + typ + } + fn present_types( + &self, operands: &[Prim], types: &[Prim], r#yield: Prim, info: &DebugInfo, diagnostics: &mut crate::parser::data::Diagnostics, - ) -> Result, ()> { + ) -> Result<(Option, Option), ()> { if operands.len() < types.len() { diagnostics.set_err(info, crate::msg::ERR74, format!( @@ -134,27 +144,30 @@ impl Operator { } for (x, typ) in types.iter().enumerate() { - if typ != &operands[x] { - return Ok(None); + if !typ.is_equal(operands[x]) { + return Ok((None, None)); } } - Ok(Some(r#yield)) + + // this combination fits + Ok((Some(r#yield), Self::operation_type(types) )) } fn check_types( + &self, operands: &[Prim], types: &[(&[Prim], Prim)], dbginf: &DebugInfo, diagnostics: &mut crate::parser::data::Diagnostics, - ) -> Result,()> { + ) -> Result<(Option, Option),()> { for combination in types.iter() { - if let Some(result) = - Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)? + if let (result, hint) = + self.present_types(operands, combination.0, combination.1, dbginf, diagnostics)? { - return Ok(Some(result)); + return Ok((result, hint)); } } - Ok(None) + Ok((None, None)) } pub fn operate( @@ -162,36 +175,36 @@ impl Operator { operands: &mut Vec, info: &DebugInfo, diagnostics: &mut crate::parser::data::Diagnostics, - ) -> Result<(),()> { + ) -> Result { // TODO: insert type hint match self { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { - let types_valid = - Self::check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?; + let (types_valid, hint) = + self.check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?; if let Some(result) = types_valid { operands.pop(); operands.pop(); operands.push(result); - return Ok(()); + return Ok(hint.unwrap()); } else { diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers"); return Err(()); } } Operator::And | Operator::Or | Operator::Xor => { - let types_valid = Self::check_types( + let types_valid = self.check_types( operands, &[(&[Prim::Bool, Prim::Bool], Prim::Bool)], info, diagnostics, )?; - if let Some(result) = types_valid { + if let (Some(result), Some(hint)) = types_valid { operands.pop(); operands.pop(); operands.push(result); - return Ok(()) + return Ok(hint) } else { diagnostics.set_err(info, crate::msg::ERR73, "expected two booleans"); return Err(()); @@ -203,7 +216,7 @@ impl Operator { | Operator::Gt | Operator::GtEq | Operator::LtEq => { - let types_valid = Self::check_types( + let types_valid = self.check_types( operands, &[ (&[Prim::Int, Prim::Int], Prim::Bool), @@ -225,11 +238,11 @@ impl Operator { diagnostics, )?; - if let Some(result) = types_valid { + if let (Some(result), Some(hint)) = types_valid { operands.pop(); operands.pop(); operands.push(result); - return Ok(()); + return Ok(hint); } else { diagnostics.set_err(info, crate::msg::ERR73, "expected either two booleans or two numbers"); return Err(()); @@ -315,6 +328,16 @@ impl Prim { }; } + pub fn merge_types(&self, current: &mut Option) { + if let Some(prim) = current { + if !prim.is_equal(*self) { + *current = None; + } + } else { + *current = Some(*self); + } + } + pub fn is_equal(&self, value: Prim) -> bool { return match self { Prim::Bool => *self == value, @@ -486,7 +509,7 @@ impl<'a> std::fmt::Display for Token<'a> { Token::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)), Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)), Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)), - Token::Operator(o, _, _) => f.write_fmt(format_args!("{:?}", o)), + Token::Operator(o, hint, _) => f.write_fmt(format_args!("{:?} {:?}", o, hint.unwrap())), Token::Number(n, hint, _) => f.write_fmt(format_args!("Load {:?} {}", hint, n)), Token::LineBreak(_) => f.write_str("__Line-break"), Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)), diff --git a/src/vmrt/mod.rs b/src/vmrt/mod.rs index ff77ae5..b62062b 100644 --- a/src/vmrt/mod.rs +++ b/src/vmrt/mod.rs @@ -1,13 +1,13 @@ use std::collections::{VecDeque, HashMap}; -use crate::{parser::data::*, token::{Token, NumHint}}; +use crate::{parser::data::*, token::{Token, NumHint, Prim}}; -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] enum Data { Int(i64), Rat(f64), Bool(bool), - Off(usize), + Off(u64), } #[derive(Debug)] @@ -64,7 +64,7 @@ enum Instr { /// delete the last value from stack Pop, - /// push the value stored at offset onto the stack + /// push the value stored at offset from the local stack onto the local stack Load(usize), /// store the value stored at the stack[0](offset) stack[1](value) onto the stack Store, @@ -91,10 +91,15 @@ enum Instr { /// +----------------------------------+ /// | Parameter (n) | /// +----------------------------------+ +struct Proc { + code: Vec, + args: usize, + addr: u64, +} #[derive(Default)] pub struct Program { - code: HashMap> + code: HashMap } #[derive(Default)] @@ -103,7 +108,7 @@ struct Compiletime<'a> { stacksize: usize, } -fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, code: &mut Vec) { +fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, code: &mut Vec) -> Result<(), ()>{ for token in term.iter() { let instr = match token { Token::Number(value, hint, _) => { @@ -130,13 +135,71 @@ fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, code.push(Instr::Load(*ct.vartable.get(name).unwrap())); ct.stacksize += 1; } - Token::Operator(op, _, _) => { + Token::Operator(op, hint, _) => { + code.push(match op { crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)), crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)), crate::token::Operator::Xor => Instr::Operation(Operation::Bool(BoolOp::Xor)), + + crate::token::Operator::Add => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)), + _ => panic!() + }, + crate::token::Operator::Sub => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)), + _ => panic!() + }, + crate::token::Operator::Mul => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)), + _ => panic!() + }, + crate::token::Operator::Div => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)), + _ => panic!() + }, - _ => panic!() + crate::token::Operator::Eq => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)), + Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)), + _ => panic!() + }, + crate::token::Operator::NotEq => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)), + Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)), + _ => panic!() + }, + crate::token::Operator::Lt => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)), + _ => panic!() + }, + crate::token::Operator::Gt => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)), + _ => panic!() + }, + crate::token::Operator::GtEq => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)), + _ => panic!() + }, + crate::token::Operator::LtEq => match hint.unwrap() { + Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)), + Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)), + _ => panic!() + }, + + crate::token::Operator::Assign => { + crate::message(crate::token::MessageType::Critical, format!("Invalid operator: {:?}", op)); + return Err(()); + } }); // TODO: operatiors @@ -161,22 +224,26 @@ fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, _ => () }; } + Ok(()) } -fn parse_block<'a>(block: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) { +fn parse_block<'a>(block: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) -> Result<(), ()> { for expr in block.iter() { - compile_expr(expr, x, declr, ct, prog); + compile_expr(expr, x, declr, ct, prog)?; } + Ok(()) } -fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) { +fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) -> Result<(), ()> { match expr { - Expr::Block(block) => parse_block(block, x, declr, ct, prog), - Expr::Term(term) => parse_term(term, x, declr, ct, prog), + Expr::Block(block) => parse_block(block, x, declr, ct, prog)?, + Expr::Term(term) => parse_term(term, x, declr, ct, prog)?, } + + Ok(()) } -pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>) { +pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>) -> Result { let mut prog = Program::default(); for (x, func) in funcs.iter().enumerate() { @@ -186,10 +253,24 @@ pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>) { // at beginn the is the return address and the parameter on the stack ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len() + 1; - compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code); + compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?; println!("{:#?}", code); prog.code.insert(declrs[x].uuid(), code); } + Ok(prog) +} + +pub fn execute(prog: &Program) -> Result { + // declaration of entry function + let main_fn_declr = crate::parser::data::Declr::main(); + + if let Some(main_fn) = prog.code.get(&main_fn_declr.uuid()) { + + Ok(0) + } else { + crate::message(crate::token::MessageType::Critical, "Program has no main() = int function"); + return Err(()); + } } diff --git a/test.erpn b/test.erpn index 0434502..cc24e30 100644 --- a/test.erpn +++ b/test.erpn @@ -3,18 +3,18 @@ pi: foo: Load Int 5 Load Int 6 - Add + Add Int Store Int x Load Arg x Load Int 6 - Lt + Lt Int Unless Load Bool true Yield Please Load Arg x Load Int 6 - Lt + Lt Int Unless Load Bool true Yield