From 37671f4550e27cfded0cb632943351f7a621dc8c Mon Sep 17 00:00:00 2001 From: Servostar Date: Thu, 27 Oct 2022 21:34:31 +0200 Subject: [PATCH] added yield --- README.md | 7 +++---- src/main.rs | 14 +++++-------- src/parser/data.rs | 5 +++++ src/parser/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++++---- src/token/mod.rs | 18 ++++++++--------- 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 03dbee6..d6f9e92 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,9 @@ It contains features such as: 1. a COMEFROM keyword (inverse goto) 2. a `don't` code block which never executes -3. `rand(x)` returns x, always. -4. no if. only `unless`, an inverted version of if. Meaning a block gets executed if the expression is false -5. three spaces start a single line comment -6. many ways of making comments: `// comment`, `:REM: comment`, `# comment`, `-- comment --` cuz we can +3. no if. only `unless`, an inverted version of if. Meaning a block gets executed if the expression is false +4. three spaces start a single line comment +5. many ways of making comments: `// comment`, `:REM: comment`, `# comment`, `-- comment --` cuz we can ### Keywords diff --git a/src/main.rs b/src/main.rs index 202c661..9d78edb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,18 +24,14 @@ pi = rat 3.1415926535 foo(x :int, y: rat) = bool { yield maybe } - comment -main { - -- comment -- + +main { + unless 3 > 4 { - a = 4 - 5; // also comment + a = 4 - 5; b:rat = 0.3 + 7 - t = foo(a, b) :REM: comment 3 - } - - don't { - + t = foo(a, b) } } "; diff --git a/src/parser/data.rs b/src/parser/data.rs index 14d4433..aff66bf 100644 --- a/src/parser/data.rs +++ b/src/parser/data.rs @@ -84,6 +84,11 @@ pub struct Scope<'a> { pub args: Option<&'a Vec<(&'a str, Prim)>>, /// stack of scoped block variables pub vars: Vec)>>, + pub func_return_typ: Option, + /// if we safely yielded sth + pub yields: bool, + /// if the current location in the scope is fixed in execution (no loop, no unless) + pub cond_scope: bool } impl<'a> Scope<'a> { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 997c6dd..02678b1 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -316,7 +316,7 @@ fn check_var_typ(typ: &mut Option, operands: &mut Vec, dbginf: &crat } } -fn process_keyword(keyword: Keyword, _: &Vec, _: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { +fn process_keyword(keyword: Keyword, _: &Vec, scope: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { match keyword { Keyword::If | Keyword::While => { if operands.len() != 1 { @@ -334,6 +334,36 @@ fn process_keyword(keyword: Keyword, _: &Vec, _: &mut Scope, operands: &m } } }, + Keyword::Return => { + if scope.func_return_typ.is_some() { + dbginf.print(MessageType::Error, "cannot return function, did u mean to use `yield`?", source); + panic!(); + } + } + Keyword::Yield => { + if operands.len() != 1 { + dbginf.print(MessageType::Error, format!("Expected single value but got {} values", operands.len()).as_str(), source); + panic!(); + } + + if let Some(operand) = operands.pop() { + if let Some(typ) = scope.func_return_typ { + if typ != operand { + dbginf.print(MessageType::Error, format!("Expected {:?} but got {:?}", typ, operand).as_str(), source); + panic!(); + } + if scope.cond_scope { + scope.yields = true; + } + } else { + dbginf.print(MessageType::Error, format!("Function does not return anything").as_str(), source); + panic!(); + } + } else { + dbginf.print(MessageType::Error, format!("Yield must return something").as_str(), source); + panic!(); + } + } _ => () } } @@ -518,15 +548,26 @@ fn parse_block<'a>(block: &mut Block<'a>, declrs: &Vec>, scope: &mut S fn parse_exprs<'a>(funcs: &mut Vec>, declrs: &Vec>, source: &'a str) { let mut scope = Scope { args: None, - vars: vec![] + vars: vec![], + func_return_typ: None, + cond_scope: false, + yields: false, }; for (x, func) in funcs.iter_mut().enumerate() { match func.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.cond_scope = false; + scope.yields = false; - parse_block(block, declrs, &mut scope, source) + parse_block(block, declrs, &mut scope, source); + + if scope.func_return_typ.is_some() && !scope.yields { + crate::message(MessageType::Error, format!("Function {} missing return value at some point", declrs[x])); + panic!(); + } }, _ => panic!("Fatal-Compilier-Error: function must have a block") } @@ -545,6 +586,6 @@ pub fn parse<'a>(tokens: &mut VecDeque>, source: &'a str) -> Ve for (x, f) in funcs.iter().enumerate() { println!("{:#?}{:#?}", declrs[x], f); } - + funcs } \ No newline at end of file diff --git a/src/token/mod.rs b/src/token/mod.rs index 54c27f2..6cfb8b8 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -36,8 +36,8 @@ impl Operator { "^" => Operator::Xor, "==" => Operator::Eq, - "<" => Operator::Lt, - ">" => Operator::Gt, + "<" => Operator::Lt, + ">" => Operator::Gt, "<=" => Operator::LtEq, ">=" => Operator::GtEq, "!=" => Operator::NotEq, @@ -108,9 +108,9 @@ impl Operator { match self { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div=> { let types_valid = Self::check_types(operands, &[ - // +-------------------------------------------------------------------------------+---------------------------------+ - // | Parameter list of types | result type | - // +-------------------------------------------------------------------------------+---------------------------------+ + // +------------------------------------------------------------------------------------+---------------------------------+ + // | Parameter list of types | result type | + // +------------------------------------------------------------------------------------+---------------------------------+ (vec![Prim::Int, Prim::Int ], Prim::Int), (vec![Prim::Rat, Prim::Rat ], Prim::Rat), (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Int), @@ -150,9 +150,9 @@ impl Operator { }, Operator::Eq | Operator::NotEq | Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => { let types_valid = Self::check_types(operands, &[ - // +-------------------------------------------------------------------------------+---------------------------------+ - // | Parameter list of types | result type | - // +-------------------------------------------------------------------------------+---------------------------------+ + // +------------------------------------------------------------------------------------+---------------------------------+ + // | Parameter list of types | result type | + // +------------------------------------------------------------------------------------+---------------------------------+ (vec![Prim::Int, Prim::Int ], Prim::Bool ), (vec![Prim::Rat, Prim::Rat ], Prim::Bool ), (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Bool ), @@ -373,7 +373,7 @@ impl<'a> Token<'a> { } } -const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*--|//.*|:REM:.*| .*)|(unless|while|loop|break|cont|ret|yield)|(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 = r"(#.*)|(unless|while|loop|break|cont|ret|yield)|(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)|(;)"; lazy_static::lazy_static! { static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();