From a506f51f71a53da988c76cbdc9d3225a16106810 Mon Sep 17 00:00:00 2001 From: Teridax Date: Mon, 2 Jan 2023 12:06:24 +0100 Subject: [PATCH] finished yard --- prog.vsasm | 53 ++++++++-- src/conf/mod.rs | 25 +++-- src/inter/mod.rs | 20 ++-- src/main.rs | 57 +++++------ src/parser/data.rs | 70 +++++++++---- src/parser/mod.rs | 237 +++++++++++++++++++++++++-------------------- src/parser/msg.rs | 1 - src/token/mod.rs | 120 ++++++++++++++++------- src/vmrt/mod.rs | 183 +++++++++++++++++++++++++++------- src/vmrt/output.rs | 9 +- test.erpn | 57 +++++++++-- 11 files changed, 578 insertions(+), 254 deletions(-) diff --git a/prog.vsasm b/prog.vsasm index f420973..feec742 100644 --- a/prog.vsasm +++ b/prog.vsasm @@ -1,16 +1,57 @@ +section[text] 0xc8c7a99bb88e156b: push int 0x0 store 0x0 load 0x0 - push int 0x4 + push int 0x9 + cmp gt int + jump-unless 0x19 + load 0x0 + push int 0x5 + cmp not-eq int + jump-unless 0xf + load 0x0 + push int 0x1 add int store 0x0 - load 0x0 - push int 0x10 - cmp lt eq int - jump-unless 0xb - jump 0xc jump 0x2 + push string "" load 0x0 + cat + call 0xa451e518c3d4dbea + call 0x396ceaf58c7ab783 + load 0x0 + push int 0x1 + add int + store 0x0 + jump 0x2 + jump 0x1b + jump 0x2 + push int 0x0 ret + +extern builtin 0x396ceaf58c7ab783 + +extern builtin 0x608aa48c89877fc5 + +0x967b65e0e8f1394: + load 0x0 + push int 0x1 + cmp not-eq int + jump-unless 0x6 + push int 0x1 + ret + load 0x0 + push int 0x1 + sub int + call 0x967b65e0e8f1394 + load 0x0 + mul int + ret + +extern builtin 0xdcd0c37eed9c3ddf + +extern builtin 0x6d3c1164316ec324 + +extern builtin 0xa451e518c3d4dbea diff --git a/src/conf/mod.rs b/src/conf/mod.rs index eb02ea8..cf3adee 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -1,9 +1,12 @@ -use crate::parser::data::Diagnostics; +use crate::{parser::data::LogLvl, srcio::CodeSrc}; #[derive(Default)] pub struct Settings { gen_erpn: bool, gen_vsasm: bool, + loglvl: LogLvl, + + srcs: Vec } impl Settings { @@ -14,17 +17,25 @@ impl Settings { pub fn gen_vsasm(&self) -> bool { self.gen_vsasm } + + pub fn get_source(&self) -> &Vec { + &self.srcs + } + + pub fn loglvl(&self) -> LogLvl { + self.loglvl + } } -pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings { +pub fn parse_args() -> Result { let args = std::env::args().collect::>(); let mut settings = Settings::default(); - for arg in args.iter() { + for arg in args.iter().skip(1) { match arg.as_str() { - "--no-info" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Warn), - "--no-warn" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Err), + "--no-info" => settings.loglvl = crate::parser::data::LogLvl::Warn, + "--no-warn" => settings.loglvl = crate::parser::data::LogLvl::Err, "--erpn" => settings.gen_erpn = true, "--vsasm" => settings.gen_vsasm = true, "-h" => println!(concat!( @@ -35,9 +46,9 @@ pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings { "--vsasm: write a .vsasm (virtual simplified assembly language) summary to disk\n", "-h: print this dialog" )), - _ => () + _ => settings.srcs.push(CodeSrc::new(arg)?) } } - settings + Ok(settings) } diff --git a/src/inter/mod.rs b/src/inter/mod.rs index 822b83d..1070484 100644 --- a/src/inter/mod.rs +++ b/src/inter/mod.rs @@ -23,18 +23,26 @@ fn write_block(file: &mut std::fs::File, indent: &mut String, block: &std::colle indent.pop(); } -pub fn convert_to_erpn<'a>(funcs: &mut Vec>, declrs: &Vec>) { +pub fn convert_to_erpn<'a>(parser: &crate::Parser) { let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("test.erpn").unwrap(); let mut indent = String::new(); - for (x, func) in funcs.iter().enumerate() { - // write function name - write!(&mut file, "{}:\n", declrs[x].name.unwrap()).unwrap(); + for (x, func) in parser.funcs.iter().enumerate() { + if func.is_builtin { + write!(&mut file, "extern function {}\n\n", parser.declrs[x].name.unwrap()).unwrap(); + continue; + } - // write down function body - write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap()); + // write function name + write!(&mut file, "{}:\n", parser.declrs[x].name.unwrap()).unwrap(); + + if !func.is_builtin { + // write down function body + write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap()); + } + writeln!(&mut file).unwrap(); } } diff --git a/src/main.rs b/src/main.rs index 910005c..1f73678 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,14 @@ mod parser; mod inter; mod conf; mod vmrt; +mod srcio; +mod builtin; +mod direct; +use builtin::BuiltinFun; use colored::Colorize; -use parser::*; +use conf::Settings; +use parser::{*, data::{Declr, Func}}; use token::*; use crate::parser::data::Diagnostics; @@ -21,39 +26,37 @@ where println!("{}: {}\n", typ.to_colored(), msg.into().bold().bright_white()); } -fn main() { - let source = r" --- structs are tables +fn compile(settings: &Settings) -> Option<(Vec, Vec, Vec)> { -main() = int { - - x:rat = 0.0; + for src in settings.get_source().iter() { + let code = src.code(); - loop { - x = x + 4 + let mut diagnostics = Diagnostics::new(&settings, code); + + if let Ok(mut tokens) = tokenize(code, &mut diagnostics) { + let specs = crate::direct::resolve_directives(&mut tokens); - unless x < 16 { - break - } - } - - yield x; -} -"; + let mut parser = Parser::new(&specs); - let mut diagnostics = Diagnostics::new(source); - - let settings = conf::parse_args(&mut diagnostics); - - if let Ok(mut tokens) = tokenize(source, &mut diagnostics) { - if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) { - if let Ok(prog) = vmrt::compile(&fs, &ds, &settings) { - if let Ok(exit_code) = vmrt::execute(&prog) { - crate::message(MessageType::Info, format!("Program exited with {}", exit_code)); + if let Ok((funcs, declrs, builtin)) = parser.parse(&mut tokens, &mut diagnostics, &settings) { + if let Ok(prog) = vmrt::compile(&funcs, &declrs, builtin, &settings) { + if let Ok(exit_code) = vmrt::execute(&prog) { + crate::message(MessageType::Info, format!("Program exited with {}", exit_code)); + } } } } + + println!("{}", diagnostics); + continue; } - println!("{}", diagnostics); + None +} + +fn main() { + + if let Ok(settings) = conf::parse_args() { + compile(&settings); + } } diff --git a/src/parser/data.rs b/src/parser/data.rs index 2f123bb..44a7918 100644 --- a/src/parser/data.rs +++ b/src/parser/data.rs @@ -1,3 +1,6 @@ +use rand::RngCore; + +use crate::conf::Settings; use crate::token::{DebugInfo, DebugNotice, Token, MessageType}; use crate::Prim; use core::panic; @@ -15,6 +18,12 @@ pub enum LogLvl { Err, } +impl Default for LogLvl { + fn default() -> Self { + Self::Info + } +} + pub struct Diagnostics<'a> { /// terminating factor on error err: Option>, @@ -28,26 +37,23 @@ pub struct Diagnostics<'a> { } impl<'a> Diagnostics<'a> { - pub fn new(source: &'a str) -> Self { + pub fn new(settings: &Settings, source: &'a str) -> Diagnostics<'a> { Self { err: None, hints: vec![], source, - loglvl: LogLvl::Info + loglvl: settings.loglvl() } } - pub fn set_loglvl(&mut self, lvl: LogLvl) { - self.loglvl = lvl; - } - pub fn set_err(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T) where T: Into, S: Into + Clone, { if self.err.is_some() { - panic!("Error already set"); + crate::message(MessageType::Warning, "Multiple Errors occured during compilation"); + return; } let info: DebugInfo = source.clone().into(); @@ -100,12 +106,14 @@ impl<'a> std::fmt::Display for Diagnostics<'a> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Func<'a> { /// raw tokens pub raw: Option>>, /// parsed content pub expr: Option>, + + pub is_builtin:bool, } impl<'a> Func<'a> { @@ -113,6 +121,7 @@ impl<'a> Func<'a> { Self { raw: None, expr: None, + is_builtin: false } } } @@ -131,10 +140,29 @@ pub struct Declr<'a> { /// debug info pub info: Option, + pub is_builtin: bool, + uuid: u64 } impl<'a> Declr<'a> { + + pub fn generate_builtin(name: &'static str, args: Vec<(&'static str, Prim)>, ret: Option) -> Declr { + Declr { + name: Some(name), + args: if args.is_empty() { + None + } else { + Some(args) + }, + results: ret.is_some(), + result_typ: ret, + info: None, + is_builtin: true, + uuid: rand::thread_rng().next_u64() + } + } + pub fn new() -> Self { Self { name: None, @@ -142,6 +170,7 @@ impl<'a> Declr<'a> { results: false, result_typ: None, info: None, + is_builtin: false, uuid: 0, } } @@ -153,6 +182,7 @@ impl<'a> Declr<'a> { results: true, result_typ: Some(Prim::Int), info: None, + is_builtin: false, uuid: 0 }; @@ -233,11 +263,10 @@ pub enum Expr<'a> { Term(VecDeque>), } -pub struct Scope<'a> { - pub args: Option<&'a Vec<(&'a str, Prim)>>, +pub struct Scope { + pub declr: usize, /// stack of scoped block variables pub vars: Vec)>>, - pub func_return_typ: Option, /// if we safely yielded sth pub yields: bool, /// if the last expr yielded a result @@ -245,7 +274,7 @@ pub struct Scope<'a> { pub cond_count: usize, } -impl<'a> Scope<'a> { +impl Scope { pub fn alloc_scope(&mut self) { self.vars.push(Vec::new()) } @@ -258,8 +287,8 @@ impl<'a> Scope<'a> { self.vars.last_mut().unwrap().push((name, typ)) } - pub fn is_arg(&self, name: &'a str) -> bool { - if let Some(args) = self.args { + pub fn is_arg(&self, name: &str, declrs: &Vec) -> bool { + if let Some(args) = &declrs[self.declr].args { for arg in args.iter() { if arg.0 == name { return true; @@ -269,8 +298,8 @@ impl<'a> Scope<'a> { false } - pub fn get_arg_type(&self, name: &'a str) -> Prim { - if let Some(args) = self.args { + pub fn get_arg_type(&self, name: &str, declrs: &Vec) -> Prim { + if let Some(args) = &declrs[self.declr].args { for arg in args.iter() { if arg.0 == name { return arg.1; @@ -280,7 +309,7 @@ impl<'a> Scope<'a> { panic!("No argument of name: {name}"); } - pub fn get_var_type(&self, name: &'a str) -> Prim { + pub fn get_var_type(&self, name: &str) -> Prim { // create an owned version of the string let owned = &name.to_owned(); @@ -294,7 +323,7 @@ impl<'a> Scope<'a> { panic!("No variable of name: {name}"); } - pub fn is_var(&self, name: &'a str) -> Option { + pub fn is_var(&self, name: &str) -> Option { // create an owned version of the string let owned = &name.to_owned(); @@ -309,11 +338,10 @@ impl<'a> Scope<'a> { None } - pub fn new<'b>() -> Scope<'b> { + pub fn new() -> Scope { Scope { - args: None, + declr: 0, vars: vec![], - func_return_typ: None, expr_yield: false, yields: false, cond_count: 0, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 489b96c..bd10c22 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,4 +1,4 @@ -use crate::{token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}, conf::Settings}; +use crate::{token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}, conf::Settings, builtin::{BuiltinFun, get_builtin_funs}, direct::LangSpecs}; use core::panic; use std::{collections::VecDeque, vec}; @@ -7,15 +7,34 @@ pub mod msg; use data::*; +pub struct Parser<'a> { + pub declrs: Vec>, + pub funcs: Vec>, + pub scope: Scope, + + pub builtin: Vec, +} + +impl<'a> Parser<'a> { + + pub fn new(specs: &LangSpecs) -> Parser<'a> { + let builtin = get_builtin_funs(specs.features()); + + Self { + declrs: builtin.iter().map(|bf| bf.declr()).collect(), + funcs: builtin.iter().map(|bf| bf.func()).collect(), + scope: Scope::new(), + builtin + } + } + + /// simple brace-counting parser to detect functions -fn discover_functions<'a>( +fn discover_functions( + &mut self, tokens: &mut VecDeque>, diagnostics: &mut data::Diagnostics, -) -> Result<(Vec>, Vec>), ()> { - - let mut funcs = Vec::new(); - let mut declrs = Vec::new(); - +) -> Result<(), ()> { // function to currently identifiy let mut func = Func::new(); let mut declr = Declr::new(); @@ -29,17 +48,17 @@ fn discover_functions<'a>( macro_rules! finish_func { ($token:expr) => { // check if the function is already declared - if declrs.contains(&declr) { + if self.declrs.contains(&declr) { diagnostics.set_err( $token, crate::msg::ERR10, format!("Multiple definitions: {declr}"), ); return Err(()); - } + } // check if the function returns sth but no return value is given - if declr.results && declr.result_typ.is_none() { + if declr.results &&declr.result_typ.is_none() { diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}")); return Err(()); } @@ -47,8 +66,8 @@ fn discover_functions<'a>( declr.gen_uuid(); // store new function and its declaration - funcs.push(func); - declrs.push(declr); + self.funcs.push(func); + self.declrs.push(declr); // create new empty function declr = Declr::new(); @@ -106,7 +125,7 @@ fn discover_functions<'a>( Token::Type(typ, _) => { // check if we already have a result type if declr.result_typ.is_none() { - // then check if we even need to return sth. + // then check if we even need to return Err(()) sth. if declr.results { declr.result_typ = Some(*typ); continue; @@ -181,7 +200,7 @@ fn discover_functions<'a>( } Token::Assign(name, _, info) => { - // check if we already marked a return type + // check if we already marked a return Err(()) type // we dont want a double assignment if declr.results { diagnostics.set_err(&top, crate::msg::ERR17, ""); @@ -258,7 +277,7 @@ fn discover_functions<'a>( } _ => { diagnostics.set_err(&top, crate::msg::ERR23, ""); - return Err(()); + return Err(()) ; } } continue; @@ -269,7 +288,7 @@ fn discover_functions<'a>( Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace _ => { diagnostics.set_err(&top, crate::msg::ERR22, ""); - return Err(()); + return Err(()) ; } } } @@ -282,19 +301,22 @@ fn discover_functions<'a>( } } - Ok((funcs, declrs)) + Ok(()) } /// parse the functions raw content to expr for easy compilation using a brace-counter. /// - ```{...}``` surround a block /// - line breaks seperate expressions -fn discover_exprs<'a>( - functions: &mut Vec>, - _: &Vec>, +fn discover_exprs( + &mut self, diagnostics: &mut data::Diagnostics, -) -> Result<(),()> { + ) -> Result<(), ()> { + + for func in self.funcs.iter_mut() { + if func.is_builtin { + continue; + } - for func in functions.iter_mut() { let mut blocks = vec![Block::new()]; let mut expr = VecDeque::new(); @@ -320,7 +342,7 @@ fn discover_exprs<'a>( block.push_back(Expr::Term(expr)); } else { diagnostics.set_err(&top, crate::msg::ERR41, ""); - return Err(()); + return Err(()) ; } expr = VecDeque::new(); blocks.push(Block::new()); @@ -334,16 +356,16 @@ fn discover_exprs<'a>( dst.push_back(Expr::Block(block)); } else { diagnostics.set_err(&top, crate::msg::ERR41, ""); - return Err(()); + return Err(()) ; } } else { diagnostics.set_err(&top, crate::msg::ERR40, ""); - return Err(()); + return Err(()) ; } if blocks.is_empty() { diagnostics.set_err(&top, crate::msg::ERR41, ""); - return Err(()); + return Err(()) ; } continue; @@ -361,7 +383,7 @@ fn discover_exprs<'a>( block.push_back(Expr::Term(expr)); } else { diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, ""); - return Err(()); + return Err(()) ; } } @@ -369,7 +391,8 @@ fn discover_exprs<'a>( func.expr = Some(Expr::Block(block)); } } - Ok(()) + + return Ok(()) } fn check_var_typ( @@ -410,15 +433,16 @@ fn check_var_typ( } } else { diagnostics.set_err(info, crate::msg::ERR52, ""); - return Err(()); + return Err(()) ; } + Ok(()) } fn process_keyword( + &mut self, info: &DebugInfo, keyword: Keyword, - scope: &mut Scope, operands: &mut Vec, diagnostics: &mut data::Diagnostics, ) -> Result<(), ()> { @@ -430,7 +454,7 @@ fn process_keyword( crate::msg::ERR53, format!("got {:?} values", operands.len()), ); - return Err(()); + return Err(()) ; } if let Some(operand) = operands.pop() { @@ -438,13 +462,13 @@ fn process_keyword( Prim::Bool => (), _ => { diagnostics.set_err(info, crate::msg::ERR53, format!("got {:?}", operand)); - return Err(()); + return Err(()) ; } } } } Keyword::Return => { - if scope.func_return_typ.is_some() { + if self.declrs[self.scope.declr].result_typ.is_some() { diagnostics.set_err(info, crate::msg::ERR54, "perhaps use `yield`"); return Err(()); } @@ -460,7 +484,7 @@ fn process_keyword( } if let Some(operand) = operands.pop() { - if let Some(typ) = scope.func_return_typ { + if let Some(typ) = self.declrs[self.scope.declr].result_typ { if !typ.is_equal(operand) { diagnostics.set_err( info, @@ -469,7 +493,7 @@ fn process_keyword( ); return Err(()); } - scope.yields = scope.cond_count == 1; + self.scope.yields = self.scope.cond_count == 1; } else { diagnostics.set_err(info, crate::msg::ERR57, ""); return Err(()); @@ -486,9 +510,8 @@ fn process_keyword( } fn collapse_operation( + &mut self, operation: &mut Token, - declrs: &Vec, - scope: &mut Scope, operands: &mut Vec, diagnostics: &mut data::Diagnostics, ) -> Result<(), ()> { @@ -496,14 +519,14 @@ fn collapse_operation( match operation { 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()); + Self::check_var_typ(typ, operands, &dbginf, diagnostics)?; + self.scope.decl_var((*name).to_owned(), typ.clone()); } Token::Func(name, dbginf) => { - call_func(name, declrs, operands, &dbginf, diagnostics)?; + self.call_func(name, operands, &dbginf, diagnostics)?; }, Token::Keyword(keyword, dbginf) => { - process_keyword(dbginf, *keyword, scope, operands, diagnostics)?; + self.process_keyword(dbginf, *keyword, operands, diagnostics)?; } _ => (), } @@ -512,15 +535,15 @@ fn collapse_operation( } fn call_func( + &mut self, name: &str, - declrs: &Vec, operands: &mut Vec, info: &DebugInfo, diagnostics: &mut data::Diagnostics, ) -> Result<(), ()> { // find the function in our function declarations by its name - for declr in declrs { + for declr in self.declrs.iter() { // check if declaration name matches the function name if let Some(declr_name) = declr.name { if declr_name != name { @@ -543,9 +566,8 @@ fn call_func( // check parameter types for (x, arg) in args.iter().enumerate() { - // parameter are in reverse order on the stack - // so they are placed at the bottom - let operand = operands.first().unwrap(); + // fetch next operand which is ontop of the stack + let operand = operands.last().unwrap(); // check types if !operand.is_equal(arg.1) { diagnostics.set_err(info, crate::msg::ERR61, format!("expected {:?} got {:?} as {}th argument", arg, operand, x)); @@ -563,14 +585,14 @@ fn call_func( } break; } + Ok(()) } /// parse a single term using a modified shunting yard -fn parse_term<'a>( +fn parse_term( + &mut self, term: &mut VecDeque>, - declrs: &Vec>, - scope: &mut Scope, diagnostics: &mut data::Diagnostics, ) -> Result<(),()> { @@ -583,25 +605,25 @@ fn parse_term<'a>( // resolve word to either a function, parameter or variable Token::Word(text, dbginf) => { // test for function - if is_func(declrs, text) { + if self.is_func(&self.declrs, text) || self.is_func(&self.declrs, text){ op_stack.push(Token::Func(text, *dbginf)); continue; // test for function parameter - } else if scope.is_arg(text) { - value_stack.push(scope.get_arg_type(text)); + } else if self.scope.is_arg(text, &self.declrs) { + value_stack.push(self.scope.get_arg_type(text, &self.declrs)); output.push_back(Token::Arg(text, *dbginf)); continue; // test for variable in scope - } else if scope.is_var(text).is_some() { - value_stack.push(scope.get_var_type(text)); + } else if self.scope.is_var(text).is_some() { + value_stack.push(self.scope.get_var_type(text)); output.push_back(Token::Var(text, *dbginf)); continue; } // word was not reolved to anything diagnostics.set_err(&token, crate::msg::ERR62, ""); - return Err(()); + return Err(()); } Token::Bool(_, _) => { output.push_back(token); @@ -610,6 +632,10 @@ fn parse_term<'a>( Token::Number(_, hint, _) => { output.push_back(token.clone()); value_stack.push(Prim::Num(*hint)) + }, + Token::String(_, _) => { + output.push_back(token.clone()); + value_stack.push(Prim::Str) } Token::Assign(_, _, _) => { op_stack.push(token); @@ -617,7 +643,7 @@ fn parse_term<'a>( Token::Label(_, _) => output.push_back(token), Token::Keyword(key, _) => { match key { - Keyword::Unless => (), + Keyword::While => output.push_back(Token::LoopStart), _ => () } op_stack.push(token) @@ -634,10 +660,8 @@ fn parse_term<'a>( match &next { Token::Func(_, _) => { let mut token = op_stack.pop().unwrap(); - collapse_operation( + self.collapse_operation( &mut token, - declrs, - scope, &mut value_stack, diagnostics, )?; @@ -650,10 +674,8 @@ fn parse_term<'a>( } } _ => { - collapse_operation( + self.collapse_operation( &mut token, - declrs, - scope, &mut value_stack, diagnostics, )?; @@ -662,11 +684,11 @@ fn parse_term<'a>( } } diagnostics.set_err(&token, crate::msg::ERR64, ""); - return Err(()); + return Err(()); } _ => { diagnostics.set_err(&token, crate::msg::ERR65, ""); - return Err(()); + return Err(()); } }, @@ -678,10 +700,8 @@ fn parse_term<'a>( let prec1 = op1.prec(); if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { - collapse_operation( + self.collapse_operation( &mut top, - declrs, - scope, &mut value_stack, diagnostics, )?; @@ -709,7 +729,7 @@ fn parse_term<'a>( } } _ => { - collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics)?; + self.collapse_operation(&mut token, &mut value_stack, diagnostics)?; output.push_back(token) } } @@ -720,18 +740,18 @@ fn parse_term<'a>( return Err(()); } - scope.expr_yield = value_stack.len() == 1; - if scope.expr_yield { + self.scope.expr_yield = value_stack.len() == 1; + if self.scope.expr_yield { let yielded = value_stack.pop().unwrap(); - if !yielded.is_equal(scope.func_return_typ.unwrap()) { + if !yielded.is_equal(self.declrs[self.scope.declr].result_typ.unwrap()) { diagnostics.set_err( &output[0], crate::msg::ERR59, format!( "expected {:?} got {:?}", - scope.func_return_typ.unwrap(), + self.declrs[self.scope.declr].result_typ.unwrap(), yielded ), ); @@ -744,7 +764,7 @@ fn parse_term<'a>( Ok(()) } -fn is_func(declrs: &[Declr], text: &str) -> bool { +fn is_func(&self, declrs: &[Declr], text: &str) -> bool { for declr in declrs { if declr.name.is_some() && declr.name.unwrap() == text { return true; @@ -753,51 +773,55 @@ fn is_func(declrs: &[Declr], text: &str) -> bool { return false; } -fn parse_block<'a>( +fn parse_block( + &mut self, block: &mut Block<'a>, - declrs: &Vec>, - scope: &mut Scope, diagnostics: &mut data::Diagnostics, ) -> Result<(), ()> { - scope.cond_count += 1; - scope.alloc_scope(); + self.scope.cond_count += 1; + self.scope.alloc_scope(); for expr in block.iter_mut() { match expr { - Expr::Block(block) => parse_block(block, declrs, scope, diagnostics)?, - Expr::Term(term) => parse_term(term, declrs, scope, diagnostics)?, + Expr::Block(block) => self.parse_block(block, diagnostics)?, + Expr::Term(term) => self.parse_term(term, diagnostics)?, } } - scope.pop_scope(); - scope.cond_count -= 1; + self.scope.pop_scope(); + self.scope.cond_count -= 1; Ok(()) } -fn parse_exprs<'a>( - funcs: &mut Vec>, - declrs: &Vec>, +fn parse_exprs( + &mut self, diagnostics: &mut data::Diagnostics, ) -> Result<(),()> { - let mut scope = Scope::new(); - for (x, func) in funcs.iter_mut().enumerate() { - match func.expr.as_mut().expect("Function has no body") { + for x in 0..self.funcs.len() { + if self.declrs[x].is_builtin { + continue; + } + + let mut block = match self.funcs[x].expr.as_mut().expect("Function has no body") { Expr::Block(block) => { - scope.args = declrs[x].args.as_ref(); - scope.func_return_typ = declrs[x].result_typ; - scope.yields = false; - scope.cond_count = 0; - - parse_block(block, declrs, &mut scope, diagnostics)?; - - if scope.func_return_typ.is_some() && !scope.yields && !scope.expr_yield { - diagnostics.set_err(declrs[x].info.as_ref().unwrap(), crate::msg::ERR56, format!("for function: {}", declrs[x])); - return Err(()); - } + block.clone() } _ => { - crate::message(crate::token::MessageType::Critical, "Fatal-Compilier-Error: function must have a block"); + crate::message(crate::token::MessageType::Critical, "Fatal-Compiler-Error: function must have a block"); panic!(); }, + }; + + self.scope.declr = x; + self.scope.yields = false; + self.scope.cond_count = 0; + + self.parse_block(&mut block, diagnostics)?; + + self.funcs[x].expr = Some(Expr::Block(block)); + + if self.declrs[self.scope.declr].result_typ.is_some() && !self.scope.yields && !self.scope.expr_yield { + diagnostics.set_err(self.declrs[x].info.as_ref().unwrap(), crate::msg::ERR56, format!("for function: {}", self.declrs[x])); + return Err(()); } } Ok(()) @@ -806,16 +830,17 @@ 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) -> Result<(Vec>, Vec>), ()> { +pub fn parse(&'a mut self, tokens: &mut VecDeque>, diagnostics: &mut data::Diagnostics, settings: &Settings) -> Result<(&mut Vec, &mut Vec, &mut Vec), ()> { - let (mut funcs, declrs) = discover_functions(tokens, diagnostics)?; + self.discover_functions(tokens, diagnostics)?; - discover_exprs(&mut funcs, &declrs, diagnostics)?; - parse_exprs(&mut funcs, &declrs, diagnostics)?; + self.discover_exprs(diagnostics)?; + self.parse_exprs(diagnostics)?; if settings.gen_erpn() { - crate::inter::convert_to_erpn(&mut funcs, &declrs); + crate::inter::convert_to_erpn(self); } - return Ok((funcs, declrs)); + return Ok((&mut self.funcs, &mut self.declrs, &mut self.builtin)); } +} \ No newline at end of file diff --git a/src/parser/msg.rs b/src/parser/msg.rs index a8b5e2b..8261bf7 100644 --- a/src/parser/msg.rs +++ b/src/parser/msg.rs @@ -1,7 +1,6 @@ use crate::token::DebugMsg; use crate::token::MessageType::Error; use crate::token::MessageType::Info; -//use crate::token::MessageType::Warning; pub const ERR10: &DebugMsg = &DebugMsg { typ: Error, diff --git a/src/token/mod.rs b/src/token/mod.rs index 22575a8..6f9db60 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -1,5 +1,5 @@ use colored::{ColoredString, Colorize}; -use std::{collections::VecDeque, fmt::format}; +use std::{collections::VecDeque}; use crate::parser::data::Diagnostics; @@ -25,6 +25,9 @@ pub enum Operator { Div, Assign, + + // concatonate primitve data types to string + Cat } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -78,11 +81,11 @@ impl Operator { "-" => Operator::Sub, "*" => Operator::Mul, "/" => Operator::Div, - "=" => { - Operator::Assign }, + "=" => Operator::Assign, + ".." => Operator::Cat, _ => { - crate::message(MessageType::Critical, "Unknown operator"); + crate::message(MessageType::Critical, format!("Unknown operator: {}", str)); panic!(); } }; @@ -107,6 +110,8 @@ impl Operator { Operator::Div => 4, Operator::Assign => 0, + + Operator::Cat => 0 }; } @@ -145,8 +150,8 @@ impl Operator { } for (x, typ) in types.iter().enumerate() { - if !typ.is_equal(operands[x]) { - return Ok((None, None)); + if *typ != operands[x] { + return Err(()); } } @@ -162,10 +167,11 @@ impl Operator { diagnostics: &mut crate::parser::data::Diagnostics, ) -> Result<(Option, Option),()> { for combination in types.iter() { - let (result, hint) = - self.present_types(operands, combination.0, combination.1, dbginf, diagnostics)?; + if let Ok((result, hint)) = + self.present_types(operands, combination.0, combination.1, dbginf, diagnostics) { + return Ok((result, hint)); + } - return Ok((result, hint)); } Ok((None, None)) } @@ -178,15 +184,22 @@ impl Operator { ) -> Result { // TODO: insert type hint match self { + Operator::Cat => { + operands.pop(); + operands.pop(); + operands.push(Prim::Str); + return Ok(Prim::Str); + }, Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { - let (types_valid, hint) = + + let (types_valid, _) = self.check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?; if let Some(result) = types_valid { operands.pop(); operands.pop(); operands.push(result); - return Ok(hint.unwrap()); + return Ok(types_valid.unwrap()); } else { diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers"); return Err(()); @@ -276,11 +289,12 @@ lazy_static::lazy_static! { static ref GOTO_REGEX: regex::Regex = regex::Regex::new(GOTO_REGEX_SRC).unwrap(); } + impl<'a> Keyword<'a> { pub fn parse(text: &'a str) -> Keyword<'a> { return match text { - "unless" => Keyword::Unless, - "while" => Keyword::While, + "despite" => Keyword::Unless, + "until" => Keyword::While, "loop" => Keyword::Loop, "break" => Keyword::Break, "cont" => Keyword::Continue, @@ -326,6 +340,7 @@ pub enum Prim { Rat, Bool, Num(NumHint), + Str, } impl Prim { @@ -334,6 +349,7 @@ impl Prim { "int" => Ok(Prim::Int), "rat" => Ok(Prim::Rat), "bool" => Ok(Prim::Bool), + "str" => Ok(Prim::Str), _ => { diagnostics.set_err(info, crate::msg::ERR70, format!("token is not a type: {}", text)); return Err(()) @@ -353,12 +369,14 @@ impl Prim { pub fn is_equal(&self, value: Prim) -> bool { return match self { + Prim::Str => *self == value, Prim::Bool => *self == value, Prim::Rat => { return match value { Prim::Num(NumHint::Int) => true, Prim::Num(NumHint::Rat) => true, - _ => *self == value, + Prim::Rat => true, + _ => false, } } Prim::Int => { @@ -389,7 +407,8 @@ impl std::fmt::Display for Prim { Prim::Int => f.write_str("Int")?, Prim::Rat => f.write_str("Rat")?, Prim::Bool => f.write_str("Bool")?, - Prim::Num(_) => f.write_fmt(format_args!("{:?}", self))? + Prim::Num(_) => f.write_fmt(format_args!("{:?}", self))?, + Prim::Str => f.write_str("Str")?, } Ok(()) } @@ -419,7 +438,7 @@ impl<'a> std::fmt::Display for DebugNotice<'a> { self.msg.typ.to_colored(), self.msg.code, self.msg.msg.bold().bright_white(), - self.info.line, + self.info.line + 1, self.ext ))?; // write additional information @@ -435,7 +454,7 @@ impl<'a> std::fmt::Display for DebugNotice<'a> { )) .unwrap(); - (0..self.info.start + 6) + (0..self.info.start + 7) .into_iter() .for_each(|_| f.write_str(" ").unwrap()); (self.info.start..self.info.end) @@ -514,7 +533,10 @@ pub enum Token<'a> { Type(Prim, DebugInfo), /// Semicolon Terminator(DebugInfo), - Label(&'a str, DebugInfo) + Label(&'a str, DebugInfo), + CompilerDirective(&'a str, DebugInfo), + String(&'a str, DebugInfo), + LoopStart, } impl<'a> std::fmt::Display for Token<'a> { @@ -535,6 +557,9 @@ impl<'a> std::fmt::Display for Token<'a> { Token::Bool(b, _) => f.write_fmt(format_args!("Load Bool {}", b)), Token::Keyword(k, _) => f.write_fmt(format_args!("{:?}", k)), Token::Terminator(_) => f.write_str("__Terminator"), + Token::CompilerDirective(_, _) => f.write_str("compiler-directive"), + Token::String(mat, _) => f.write_fmt(format_args!("Load String \"{}\"", mat)), + Token::LoopStart => f.write_str("Loopstart"), } } } @@ -557,11 +582,31 @@ impl<'a> Into for Token<'a> { Token::Keyword(_, d) => d, Token::Terminator(d) => d, Token::Label(_, d) => d, + Token::CompilerDirective(_, d) => d, + Token::String(_, d) => d, + Token::LoopStart => panic!("loop start has no debug info"), } } } -const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*)|'([a-zA-Z0-9]+)|(goto\s+[a-zA-Z0-9]+|unless|while|loop|break|cont|ret|yield|please)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=[^=]|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n)|(;)"; +const TOKEN_REGEX_SRC: &'static str = concat!( + r"(#.*|--.*|//.*)", // comments + r"|(@.*)", // interpreter directives + "|\"([^\"]*)\"", // string literal + r"|'([a-zA-Z0-9_]+)", // labels: 'example + r"|(goto\s+[a-zA-Z0-9_]+", // goto example + r"|despite|until|loop|break|cont|ret|yield|please)", // keywords + r"|\W(int|rat|bool|str)\W", // raw data types + r"|(true|false|ye|no|maybe)", // boolean values + r"|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9_]+))?\s*=[^=]", // assignment var:int= + r"|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9_]+))", // declaration var:int + r"|([A-Za-z_]+)", // symbol + r"|(\d*\.?\d+)", // number + r"|(!=|==|<=|<=|\.\.|[&|+\-*/<>=])", // operator + r"|([(){}])", // delemeiter + r"|(\n)", // line break + r"|(;)" // expression terminator +); lazy_static::lazy_static! { static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap(); @@ -574,6 +619,8 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result(source: &'a str, diagnostics: &mut Diagnostics) -> Result(source: &'a str, diagnostics: &mut Diagnostics) -> Result Token::Label(mat.as_str(), debug_info), - 3 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info), - 4 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info), - 5 => Token::Bool(parse_bool(mat.as_str()), debug_info), - 6 => { + 2 => Token::CompilerDirective(mat.as_str(), debug_info), + 3 => Token::String(mat.as_str(), debug_info), + 4 => Token::Label(mat.as_str(), debug_info), + 5 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info), + 6 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info), + 7 => Token::Bool(parse_bool(mat.as_str()), debug_info), + 8 => { let var_type = if let Some(mat) = enumerator.next().unwrap().1 { Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?) } else { @@ -611,21 +665,21 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result { + 10 => { let var_type = Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?; Token::Decl(mat.as_str(), var_type, debug_info) } - 10 => Token::Word(mat.as_str(), debug_info), - 11 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info), - 12 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info), - 13 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), - 14 => { + 12 => Token::Word(mat.as_str(), debug_info), + 13 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info), + 14 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info), + 15 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), + 16 => { line_count += 1; - line_start = mat.start(); + new_line = true; Token::LineBreak(debug_info) } - 15 => Token::Terminator(debug_info), + 17 => Token::Terminator(debug_info), _ => { diagnostics.set_err(&debug_info, crate::msg::ERR71, format!("token: {}", mat.as_str())); @@ -643,7 +697,7 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result bool { return match text { "true" | "ye" => true, - "false" | "no" => false, + "false" | "no" => false, "maybe" => rand::random(), _ => { crate::message(MessageType::Critical, format!("token is not a boolean value: {}", text)); diff --git a/src/vmrt/mod.rs b/src/vmrt/mod.rs index 07591d7..30a5a0c 100644 --- a/src/vmrt/mod.rs +++ b/src/vmrt/mod.rs @@ -1,17 +1,18 @@ mod output; -use std::collections::{HashMap, VecDeque}; +use std::{collections::{HashMap, VecDeque}, vec}; use crate::{ parser::data::*, - token::{NumHint, Prim, Token}, + token::{NumHint, Prim, Token}, builtin::{BuiltinFun}, }; -#[derive(Debug, Clone, Copy)] -enum Data { +#[derive(Debug, Clone)] +pub enum Data { Int(i64), Rat(f64), Bool(bool), + Str(String), } impl std::fmt::Display for Data { @@ -19,33 +20,50 @@ impl std::fmt::Display for Data { match self { Data::Int(v) => f.write_fmt(format_args!("int {:#x}", v))?, Data::Rat(v) => f.write_fmt(format_args!("float {}", v))?, - Data::Bool(v) => f.write_fmt(format_args!("bool {}", v))? + Data::Bool(v) => f.write_fmt(format_args!("bool {}", v))?, + Data::Str(v) => f.write_fmt(format_args!("string \"{}\"", &v))? } Ok(()) } } impl Data { - fn to_int(&self) -> Result { + pub fn to_int(&self) -> Result { return match self { Data::Int(v) => Ok(*v), _ => Err(()), }; } - fn to_float(&self) -> Result { + pub fn to_float(&self) -> Result { return match self { Data::Rat(v) => Ok(*v), _ => Err(()), }; } - fn to_bool(&self) -> Result { + pub fn to_bool(&self) -> Result { return match self { Data::Bool(v) => Ok(*v), _ => Err(()), }; } + + pub fn to_str(&self) -> Result { + return match self { + Data::Str(v) => Ok(v.clone()), + _ => Err(()), + }; + } + + fn as_str(&self) -> String { + return match self { + Data::Str(v) => v.clone(), + Data::Bool(b) => format!("{}", b), + Data::Rat(b) => format!("{}", b), + Data::Int(b) => format!("{}", b), + }; + } } #[derive(Debug)] @@ -93,9 +111,11 @@ enum Operation { Int(IntOp), Rat(RatOp), Bool(BoolOp), + Cat, } #[derive(Debug)] +#[allow(unused)] enum Instr { /// load some data onto the stack Push(Data), @@ -115,6 +135,7 @@ enum Instr { Jump(usize), JumpUnless(usize), + JumpRandom(usize), Exit, } @@ -130,8 +151,10 @@ impl std::fmt::Display for Instr { Instr::Call(uuid) => f.write_fmt(format_args!("\tcall {:#x}", uuid))?, Instr::Jump(offset) => f.write_fmt(format_args!("\tjump {:#x}", offset))?, Instr::JumpUnless(offset) => f.write_fmt(format_args!("\tjump-unless {:#x}", offset))?, + Instr::JumpRandom(offset) => f.write_fmt(format_args!("\tjump-random {:#x}", offset))?, Instr::Operation(op) => { match op { + Operation::Cat => f.write_str("\tcat")?, Operation::Int(op) => match op { IntOp::Add => f.write_str("\tadd int")?, IntOp::Sub => f.write_str("\tsub int")?, @@ -165,7 +188,7 @@ impl std::fmt::Display for Instr { BoolOp::CmpNEq => f.write_str("\tcmp not-eq bool")?, BoolOp::CmpEq => f.write_str("\tcmp eq bool")?, - } + }, } }, Instr::Store(offset) => f.write_fmt(format_args!("\tstore {:#x}", offset))?, @@ -184,25 +207,31 @@ impl std::fmt::Display for Instr { /// +----------------------------------+ /// | Parameter (n) | /// +----------------------------------+ -struct Proc { +#[allow(unused)] +struct Proc<'a> { // executable code code: Vec, // number of expected arguments args: usize, // hashed declaration is used as "address" addr: u64, + + builtin: Option<&'a BuiltinFun> } #[derive(Default)] -pub struct Program { - procs: HashMap, +pub struct Program<'a> { + procs: HashMap>, } enum LabelType { Unless(usize), Loop(usize), Break(usize), - Pad + Pad, + JumpRandom(usize), + While(usize), + LoopStart(usize), } #[derive(Default)] @@ -234,7 +263,11 @@ fn parse_term<'a>( Token::Bool(value, _) => { code.push(Instr::Push(Data::Bool(*value))); ct.stacksize += 1; - } + }, + Token::String(value, _) => { + code.push(Instr::Push(Data::Str(String::from(*value)))); + ct.stacksize += 1; + }, Token::Arg(name, _) => { let off = declr[x].get_arg_ord(name); code.push(Instr::Load(off)); @@ -253,10 +286,14 @@ fn parse_term<'a>( ct.stacksize += 1; }, Token::Label(name, _) => { - ct.marker.insert(name, ct.stacksize + 1); + ct.marker.insert(name, code.len()); + }, + Token::LoopStart => { + ct.lopctl.push(LabelType::LoopStart(code.len())); }, Token::Operator(op, hint, _) => { code.push(match op { + crate::token::Operator::Cat => Instr::Operation(Operation::Cat), 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)), @@ -333,6 +370,7 @@ fn parse_term<'a>( if decl.results { ct.stacksize += 1; + ct.stacksize -= decl.args.as_ref().unwrap_or(&Vec::new()).len(); } } } @@ -349,14 +387,34 @@ fn parse_term<'a>( code.push(Instr::JumpUnless(0)); }, crate::token::Keyword::Goto(label) => { - let index = ct.marker.get(label).unwrap(); + let index = ct.marker.get(*label).unwrap(); code.push(Instr::Jump(*index)); }, crate::token::Keyword::Break => { ct.lopctl.push(LabelType::Break(code.len())); code.push(Instr::Jump(0)); - } - _ => (), + }, + crate::token::Keyword::Please => { + ct.labels.push(LabelType::JumpRandom(code.len())); + code.push(Instr::JumpRandom(0)); + }, + crate::token::Keyword::While => { + ct.labels.push(LabelType::While(code.len())); + code.push(Instr::JumpUnless(0)); + }, + crate::token::Keyword::Continue => { + // make cont work in loop + for label in ct.lopctl.iter().rev() { + match label { + LabelType::LoopStart(line) => { + code.push(Instr::Jump(*line)); + break; + }, + _ => (), + } + } + + }, }, _ => (), }; @@ -385,14 +443,29 @@ fn parse_block<'a>( LabelType::Unless(line) => { prog[line] = Instr::JumpUnless(prog.len()); }, + LabelType::JumpRandom(line) => { + prog[line] = Instr::JumpRandom(prog.len()); + }, + LabelType::While(whilepos) => { + if let Some(label) = ct.lopctl.pop() { + match label { + LabelType::LoopStart(loopstart) => { + prog.push(Instr::Jump(loopstart)); + prog[whilepos] = Instr::JumpUnless(prog.len()); + }, + _ => () + } + } + }, LabelType::Loop(line) => { prog.push(Instr::Jump(line)); + // multiple breaks? if let Some(label) = ct.lopctl.pop() { match label { LabelType::Break(line) => { prog[line] = Instr::Jump(prog.len()); - }, + }, _ => () } } @@ -419,7 +492,7 @@ fn compile_expr<'a>( Ok(()) } -fn create_proc(declr: &Declr, code: Vec) -> Proc { +fn create_proc(declr: &Declr, code: Vec) -> Proc<'static> { Proc { code, args: if let Some(args) = &declr.args { @@ -428,23 +501,36 @@ fn create_proc(declr: &Declr, code: Vec) -> Proc { 0 }, addr: declr.uuid(), + builtin: None, } } -pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>, settings: &crate::conf::Settings) -> Result { +pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>, builtin: &'a Vec, settings: &crate::conf::Settings) -> Result, ()> { let mut prog = Program::default(); for (x, func) in funcs.iter().enumerate() { - let mut code = vec![]; - let mut ct = Compiletime::default(); + if func.is_builtin { - //at the beginning there are all parameters on the stack - ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len(); + for builtin in builtin.iter() { + if builtin.declr().name == declrs[x].name { + prog.procs.insert(declrs[x].uuid(), create_builtin_proc(builtin)); + break; + } + } - compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?; + } else { + let mut code = vec![]; + let mut ct = Compiletime::default(); + + //at the beginning there are all parameters on the stack + ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len(); + + compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?; + + prog.procs + .insert(declrs[x].uuid(), create_proc(&declrs[x], code)); + } - prog.procs - .insert(declrs[x].uuid(), create_proc(&declrs[x], code)); } if settings.gen_vsasm() { @@ -454,6 +540,10 @@ pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>, settings: &cr Ok(prog) } +fn create_builtin_proc(func: &BuiltinFun) -> Proc { + Proc { code: Vec::new(), args: func.declr().args.unwrap_or(vec![]).len(), addr: 0, builtin: Some(func) } +} + struct Runtimestack { stack: Vec, } @@ -472,7 +562,7 @@ impl Runtimestack { } pub fn peek(&mut self, index: usize) -> Data { - self.stack[index] + self.stack[index].clone() } pub fn top(&self) -> &Data { @@ -484,12 +574,16 @@ impl Runtimestack { } } -fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result, ()> { +fn call_fn(prog: &Program, proc: &Proc, superstack: &mut Vec) -> Result, ()> { let mut stack = Runtimestack::new(); // build local procedure stack - for i in 0..proc.args { - stack.push(superstack[superstack.len() - i - 1].clone()); + for _ in 0..proc.args { + stack.push(superstack.pop().unwrap()); + } + + if let Some(builtin) = proc.builtin { + return builtin.get_function()(&stack.stack[..]); } let mut x = 0; @@ -501,7 +595,9 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result { return Ok(stack.pop()); } - Instr::Push(data) => stack.push(*data), + Instr::Push(data) => { + stack.push(data.clone()); + }, Instr::Load(offset) => { let v = stack.peek(*offset); stack.push(v); @@ -511,16 +607,26 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result { - if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &stack.stack)? { + if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &mut stack.stack)? { stack.push(value); } }, Instr::Jump(addr) => { - x = *addr - 1; + x = *addr; + continue; + }, + Instr::JumpRandom(addr) => { + if rand::random() { + x = *addr; + continue; + } }, Instr::JumpUnless(addr) => { match stack.pop() { - Some(Data::Bool(true)) => x = *addr - 1, + Some(Data::Bool(true)) => { + x = *addr; + continue; + }, Some(Data::Bool(false)) => (), _ => { crate::message(crate::token::MessageType::Critical, "no condition for unless on stack"); @@ -541,6 +647,9 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result { + stack.push(Data::Str(format!("{}{}", op1.as_str(), op0.as_str()))); + }, Operation::Int(op) => match op { IntOp::Add => stack.push(Data::Int(op1.to_int()? + op0.to_int()?)), IntOp::Sub => stack.push(Data::Int(op1.to_int()? - op0.to_int()?)), @@ -628,7 +737,7 @@ pub fn execute(prog: &Program) -> Result { if let Some(main_fn) = prog.procs.get(&main_fn_declr.uuid()) { - if let Some(exit_code) = call_fn(prog, main_fn, &[])? { + if let Some(exit_code) = call_fn(prog, main_fn, &mut Vec::new())? { return Ok(exit_code.to_int()?); } diff --git a/src/vmrt/output.rs b/src/vmrt/output.rs index 4f49ccf..a4dafd9 100644 --- a/src/vmrt/output.rs +++ b/src/vmrt/output.rs @@ -1,7 +1,13 @@ use std::io::Write; fn print_to_file(file: &mut std::fs::File, prog: &crate::vmrt::Program) -> std::io::Result<()> { + writeln!(file, "section[text]")?; for proc in prog.procs.iter() { + if proc.1.builtin.is_some() { + writeln!(file, "\nextern builtin {:#x}", proc.0)?; + continue; + } + writeln!(file, "\n{:#x}:", proc.0)?; for instr in proc.1.code.iter() { @@ -15,6 +21,7 @@ pub fn dump_program(prog: &crate::vmrt::Program) { let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("prog.vsasm").unwrap(); if print_to_file(&mut file, prog).is_err() { - + crate::message(crate::token::MessageType::Critical, "Failed dumping program"); + panic!(); } } diff --git a/test.erpn b/test.erpn index 3b4c359..1e05c63 100644 --- a/test.erpn +++ b/test.erpn @@ -1,16 +1,55 @@ +extern function say_hello + +extern function print + +extern function println + +extern function print + +extern function println + +fac: + Load Arg x + Load Int 1 + NotEq Int + Unless + Load Int 1 + Yield + Load Arg x + Load Int 1 + Sub Int + Call fac + Load Arg x + Mul Int + Yield + main: Load Int 0 Store Int x Loop + Loopstart Load Var x - Load Int 4 - Add Int - Store Int x - Load Var x - Load Int 16 - Lt Int - Unless - Break - Load Var x + Load Int 9 + Gt Int + While + Load Var x + Load Int 5 + NotEq Int + Unless + Load Var x + Load Int 1 + Add Int + Store Int x + Continue + Load String "" + Load Var x + Cat Str + Call println + Load Var x + Load Int 1 + Add Int + Store Int x + Break + Load Int 0 Yield