From e80a69fb41c4f3a64f1a0d7a5f7b07a2f113d900 Mon Sep 17 00:00:00 2001 From: Servostar Date: Tue, 29 Nov 2022 18:34:54 +0100 Subject: [PATCH] added vmrt module --- src/main.rs | 14 +++- src/parser/data.rs | 37 ++++++++- src/parser/mod.rs | 38 +++++---- src/token/mod.rs | 9 ++- src/vmrt/mod.rs | 195 +++++++++++++++++++++++++++++++++++++++++++++ test.erpn | 12 ++- 6 files changed, 276 insertions(+), 29 deletions(-) create mode 100644 src/vmrt/mod.rs diff --git a/src/main.rs b/src/main.rs index 9481d4a..fb4473f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod parser; // designed for a virtual stack machiene mod inter; mod conf; +mod vmrt; use colored::Colorize; use parser::*; @@ -47,10 +48,13 @@ foo(x:int, y:rat) = bool { main() = int { a = 4 - b = 5.5 + b = pi c = true - r = foo(3, ffalsee) - 0 + r = foo(3, 4.0) + h = foo(3,5.0) + b:int = 4 + + 9 } "; @@ -59,7 +63,9 @@ main() = int { let settings = conf::parse_args(&mut diagnostics); if let Ok(mut tokens) = tokenize(source, &mut diagnostics) { - parse(&mut tokens, &mut diagnostics, &settings); + if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) { + vmrt::compile(&fs, &ds); + } } println!("{}", diagnostics); diff --git a/src/parser/data.rs b/src/parser/data.rs index 86700bb..556eace 100644 --- a/src/parser/data.rs +++ b/src/parser/data.rs @@ -2,6 +2,8 @@ use crate::token::{DebugInfo, DebugNotice, Token, MessageType}; use crate::Prim; use core::panic; use std::collections::VecDeque; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum LogLvl { @@ -127,7 +129,9 @@ pub struct Declr<'a> { pub result_typ: Option, /// debug info - pub info: Option + pub info: Option, + + uuid: u64 } impl<'a> Declr<'a> { @@ -138,8 +142,39 @@ impl<'a> Declr<'a> { results: false, result_typ: None, info: None, + uuid: 0, } } + + pub fn get_arg_ord(&self, name: &str) -> usize { + if let Some(args) = self.args.as_ref() { + for (x, arg) in args.iter().enumerate() { + if arg.0 == name { + return x; + } + } + } + return 0; + } + + pub fn gen_uuid(&mut self) { + let mut hasher = DefaultHasher::default(); + + self.name.unwrap().hash(&mut hasher); + + if let Some(args) = self.args.as_ref() { + for arg in args.iter() { + arg.0.hash(&mut hasher); + arg.1.hash(&mut hasher); + } + } + + self.uuid = hasher.finish() + } + + pub fn uuid(&self) -> u64 { + self.uuid + } } impl<'a> std::fmt::Display for Declr<'a> { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 30ee24f..ad4c550 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -44,6 +44,8 @@ fn discover_functions<'a>( return Err(()); } + declr.gen_uuid(); + // store new function and its declaration funcs.push(func); declrs.push(declr); @@ -134,7 +136,7 @@ fn discover_functions<'a>( if func.raw.is_none() { match &top { - Token::Operator(op, _) => match op { + Token::Operator(op, _, _) => match op { Operator::Assign => { // check if we already have an assign if declr.results { @@ -458,7 +460,7 @@ fn process_keyword( if let Some(operand) = operands.pop() { if let Some(typ) = scope.func_return_typ { - if typ != operand { + if !typ.is_equal(operand) { diagnostics.set_err( info, crate::msg::ERR59, @@ -491,7 +493,7 @@ fn collapse_operation( ) -> Result<(), ()> { match operation { - Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics)?, + Token::Operator(op, _, dbginf) => 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()); @@ -660,11 +662,11 @@ fn parse_term<'a>( } }, - Token::Operator(op, _) => { + Token::Operator(op, _, _) => { let prec0 = op.prec(); while let Some(mut top) = op_stack.last_mut() { match &top { - Token::Operator(op1, _) => { + Token::Operator(op1, _, _) => { let prec1 = op1.prec(); if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { @@ -711,8 +713,10 @@ fn parse_term<'a>( scope.expr_yield = value_stack.len() == 1; if scope.expr_yield { - let yielded = value_stack.pop().unwrap(); - if !yielded.is_equal(scope.func_return_typ.unwrap()) { + let yielded = value_stack.pop().unwrap(); + + if !yielded.is_equal(scope.func_return_typ.unwrap()) { + diagnostics.set_err( &output[0], crate::msg::ERR59, @@ -722,7 +726,7 @@ fn parse_term<'a>( yielded ), ); - panic!(); + return Err(()); } } @@ -793,16 +797,16 @@ fn parse_exprs<'a>( /// reorder and organize a listing of instructions to a RPN based format: /// any program is made out of functions. /// A function has a name followed by an optional parameter list, followed by an optional equal sign and block. -pub fn parse<'a>(tokens: &mut VecDeque>, diagnostics: &mut data::Diagnostics, settings: &Settings) { +pub fn parse<'a>(tokens: &mut VecDeque>, diagnostics: &mut data::Diagnostics, settings: &Settings) -> Result<(Vec>, Vec>), ()> { - if let Ok((mut funcs, declrs)) = discover_functions(tokens, diagnostics) { - if let Ok(()) = discover_exprs(&mut funcs, &declrs, diagnostics) { - if let Ok(()) = parse_exprs(&mut funcs, &declrs, diagnostics) { + let (mut funcs, declrs) = discover_functions(tokens, diagnostics)?; - if settings.gen_erpn() { - crate::inter::convert_to_erpn(&mut funcs, &declrs); - } - } - } + discover_exprs(&mut funcs, &declrs, diagnostics)?; + parse_exprs(&mut funcs, &declrs, diagnostics)?; + + if settings.gen_erpn() { + crate::inter::convert_to_erpn(&mut funcs, &declrs); } + + return Ok((funcs, declrs)); } diff --git a/src/token/mod.rs b/src/token/mod.rs index e30bece..29f0ac1 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -163,6 +163,7 @@ impl Operator { info: &DebugInfo, diagnostics: &mut crate::parser::data::Diagnostics, ) -> Result<(),()> { + // TODO: insert type hint match self { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { let types_valid = @@ -459,7 +460,7 @@ pub enum Token<'a> { Word(&'a str, DebugInfo), /// Single symbol delemiter like ```(```,```}``` Delemiter(char, DebugInfo), - Operator(Operator, DebugInfo), + Operator(Operator, Option, DebugInfo), Number(&'a str, NumHint, DebugInfo), LineBreak(DebugInfo), Func(&'a str, DebugInfo), @@ -485,7 +486,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, _, _) => f.write_fmt(format_args!("{:?}", o)), 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)), @@ -506,7 +507,7 @@ impl<'a> Into for Token<'a> { Token::Type(_, d) => d, Token::Word(_, d) => d, Token::Delemiter(_, d) => d, - Token::Operator(_, d) => d, + Token::Operator(_, _, d) => d, Token::Number(_, _, d) => d, Token::LineBreak(d) => d, Token::Func(_, d) => d, @@ -577,7 +578,7 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result Token::Word(mat.as_str(), debug_info), 10 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info), - 11 => Token::Operator(Operator::parse(mat.as_str()), debug_info), + 11 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info), 12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), 13 => { line_count += 1; diff --git a/src/vmrt/mod.rs b/src/vmrt/mod.rs new file mode 100644 index 0000000..ff77ae5 --- /dev/null +++ b/src/vmrt/mod.rs @@ -0,0 +1,195 @@ +use std::collections::{VecDeque, HashMap}; + +use crate::{parser::data::*, token::{Token, NumHint}}; + +#[derive(Debug)] +enum Data { + Int(i64), + Rat(f64), + Bool(bool), + Off(usize), +} + +#[derive(Debug)] +enum IntOp { + CmpEq, + CmpNEq, + CmpLt, + CmpGt, + CmpLtEq, + CmpGtEq, + + Add, + Sub, + Mul, + Div +} + +#[derive(Debug)] +enum RatOp { + CmpEq, + CmpNEq, + CmpLt, + CmpGt, + CmpLtEq, + CmpGtEq, + + Add, + Sub, + Mul, + Div +} + +#[derive(Debug)] +enum BoolOp { + CmpEq, + CmpNEq, + + And, + Or, + Xor +} + +#[derive(Debug)] +enum Operation { + Int(IntOp), + Rat(RatOp), + Bool(BoolOp) +} + +#[derive(Debug)] +enum Instr { + /// load some data onto the stack + Push(Data), + /// delete the last value from stack + Pop, + + /// push the value stored at offset onto the stack + Load(usize), + /// store the value stored at the stack[0](offset) stack[1](value) onto the stack + Store, + + Call(u64), + + Return, + + Operation(Operation), + + Exit +} + + +/// function stack layout +/// +----------------------------------+ +/// | Return address | +/// +----------------------------------+ +/// | Parameter (0) | +/// +----------------------------------+ +/// | Parameter (1) | +/// +----------------------------------+ +/// | Parameter (2) | +/// +----------------------------------+ +/// | Parameter (n) | +/// +----------------------------------+ + +#[derive(Default)] +pub struct Program { + code: HashMap> +} + +#[derive(Default)] +struct Compiletime<'a> { + vartable: HashMap<&'a str, usize>, + stacksize: usize, +} + +fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, code: &mut Vec) { + for token in term.iter() { + let instr = match token { + Token::Number(value, hint, _) => { + code.push(Instr::Push(match hint { + NumHint::Int => Data::Int(value.parse::().unwrap()), + NumHint::Rat => Data::Rat(value.parse::().unwrap()), + })); + ct.stacksize += 1; + }, + Token::Bool(value, _) => { + code.push(Instr::Push(Data::Bool(*value))); + ct.stacksize += 1; + }, + Token::Arg(name, _) => { + let off = declr[x].get_arg_ord(name); + + code.push(Instr::Load(off + 1)); + ct.stacksize += 1; + }, + Token::Assign(name, _, _) => { + ct.vartable.insert(name.clone(), ct.stacksize - 1); + }, + Token::Var(name, _) => { + code.push(Instr::Load(*ct.vartable.get(name).unwrap())); + ct.stacksize += 1; + } + Token::Operator(op, _, _) => { + 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)), + + _ => panic!() + }); + + // TODO: operatiors + // we pop 2 values as arguments and push 1 as result (-2 + 1 = 1) + ct.stacksize -= 1; + }, + Token::Func(name, _) => { + for decl in declr.iter() { + if decl.name.as_ref().unwrap() == name { + code.push(Instr::Call(decl.uuid())) + } + } + } + Token::Keyword(keyword, _) => { + match keyword { + crate::token::Keyword::Yield | crate::token::Keyword::Return => code.push(Instr::Return), + _ => () + } + } + + + _ => () + }; + } +} + +fn parse_block<'a>(block: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) { + for expr in block.iter() { + compile_expr(expr, x, declr, ct, prog); + } +} + +fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) { + match expr { + Expr::Block(block) => parse_block(block, x, declr, ct, prog), + Expr::Term(term) => parse_term(term, x, declr, ct, prog), + } +} + +pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>) { + let mut prog = Program::default(); + + for (x, func) in funcs.iter().enumerate() { + let mut code = vec![]; + let mut ct = Compiletime::default(); + + // 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); + + println!("{:#?}", code); + + prog.code.insert(declrs[x].uuid(), code); + } +} diff --git a/test.erpn b/test.erpn index 470ae8f..0434502 100644 --- a/test.erpn +++ b/test.erpn @@ -23,12 +23,18 @@ foo: main: Load Int 4 Store Int a - Load Rat 5.5 + Call pi Store Rat b Load Bool true Store Bool c Load Int 3 - Load Rat 3.4 + Load Rat 4.0 Call foo Store Bool r - Load Int 0 + Load Int 3 + Load Rat 5.0 + Call foo + Store Bool h + Load Int 4 + Store Int b + Load Int 9