diff --git a/commons/src/err/mod.rs b/commons/src/err/mod.rs index 0cef6bd..0052d5d 100644 --- a/commons/src/err/mod.rs +++ b/commons/src/err/mod.rs @@ -39,8 +39,8 @@ impl fmt::Display for PositionedError { }; let before = &line[0..self.start.col - 1]; - let target = &line[self.start.col - 1..self.end.col].cyan().underline(); - let after = &line[self.end.col..]; + let target = &line[self.start.col - 1..self.end.col - 1].cyan().underline(); + let after = &line[self.end.col - 1..]; writeln!(f, "{}{}{}", before, target, after)?; writeln!(f, "")?; diff --git a/examples/math.qf b/examples/math.qf new file mode 100644 index 0000000..caf381a --- /dev/null +++ b/examples/math.qf @@ -0,0 +1,5 @@ +func test() { + var i32 e = !56 + + eee +} \ No newline at end of file diff --git a/lexer/src/lexer.rs b/lexer/src/lexer.rs index 5b49cd6..2bc997c 100644 --- a/lexer/src/lexer.rs +++ b/lexer/src/lexer.rs @@ -6,7 +6,7 @@ use std::{fs, hash::{DefaultHasher, Hash, Hasher}, io::Error}; use commons::Position; -use crate::{LexerParseResult, LexerParsingError, token::LexerToken, token::LexerTokenType}; +use crate::{LexerParseResult, LexerParsingError, token::{LexerToken, LexerTokenType}, toks::math::MathOperator}; const FUNC_KEYWORD_HASH: u64 = 17439195341824537259; const RET_KEYWORD_HASH: u64 = 9222097151127739705; @@ -72,6 +72,14 @@ pub fn lexer_parse_file(file_path: &String) -> LexerParseResult> continue; } + if c == '+' || c == '-' || c == '*' || c == '/' { + let col = i - last_line_break + 1; + + tokens.push(parse_math_operator(&contents, &mut i, Position::new(file_path.to_string(), line, col))?); + + continue; + } + i += c.len_utf8(); @@ -93,7 +101,7 @@ pub fn lexer_parse_file(file_path: &String) -> LexerParseResult> '&' => tokens.push(LexerToken::make_single_sized(pos, LexerTokenType::AMPERSAND)), '<' => tokens.push(LexerToken::make_single_sized(pos, LexerTokenType::ANGEL_BRACKET_OPEN)), '>' => tokens.push(LexerToken::make_single_sized(pos, LexerTokenType::ANGEL_BRACKET_CLOSE)), - _ => continue + _ => continue } } @@ -103,6 +111,40 @@ pub fn lexer_parse_file(file_path: &String) -> LexerParseResult> Ok(tokens) } +fn parse_math_operator(contents: &String, ind: &mut usize, start_pos: Position) -> LexerParseResult { + let operatorChar = contents.chars().nth(*ind).unwrap(); + + let operator = match operatorChar { + '+' => MathOperator::ADD, + '-' => MathOperator::SUBSTRACT, + '*' => MathOperator::MULTIPLY, + '/' => MathOperator::DIVIDE, + _ => return Err(LexerParsingError::new(String::from("Invalid operator sign!"), 0)) + }; + + *ind += 1; + + let assigns = match contents.chars().nth(*ind) { + Some(v) => v == '=', + None => false + }; + + if assigns { + *ind += 1; + } + + let mut incrementCount = 1; + + if assigns { + incrementCount += 1; + } + + let end = start_pos.increment_by(incrementCount); + + return Ok(LexerToken::new(start_pos, end, LexerTokenType::MATH_OPERATOR(operator, assigns))); + +} + fn parse_number_token(str: &String, ind: &mut usize, start_pos: Position) -> LexerParseResult { let start = *ind + 1; let mut end: usize = start; diff --git a/lexer/src/lib.rs b/lexer/src/lib.rs index b5629cc..ffd87a9 100644 --- a/lexer/src/lib.rs +++ b/lexer/src/lib.rs @@ -7,6 +7,7 @@ use core::fmt; pub mod token; pub mod lexer; +pub mod toks; type LexerParseResult = std::result::Result; diff --git a/lexer/src/token.rs b/lexer/src/token.rs index 148eb69..1d7e27d 100644 --- a/lexer/src/token.rs +++ b/lexer/src/token.rs @@ -6,7 +6,7 @@ use std::any::Any; use commons::{Position, err::{PositionedError, PositionedResult}}; -use crate::{LexerParseResult, LexerParsingError}; +use crate::{LexerParseResult, LexerParsingError, toks::math::MathOperator}; /// The token type for the lexer #[derive(PartialEq, Debug)] @@ -19,6 +19,11 @@ pub enum LexerTokenType { LAYOUT, LAY, + /// 0: the operator + /// 1: does the operator affect the original variable! + MATH_OPERATOR(MathOperator, bool), + + /// Represent the ret keyword RETURN, @@ -91,6 +96,13 @@ impl LexerToken { }; } + pub fn expects_math_operator(&self) -> PositionedResult<(MathOperator, bool)> { + match &self.tok_type { + LexerTokenType::MATH_OPERATOR(a, b) => return Ok((a.clone(), *b)), + _ => return Err(self.make_err("Expected math operator here!")) + }; + } + pub fn expects_string_lit(&self) -> PositionedResult { match &self.tok_type { LexerTokenType::STRING_LIT(v) => return Ok(v.to_string()), diff --git a/lexer/src/toks/math.rs b/lexer/src/toks/math.rs new file mode 100644 index 0000000..0621019 --- /dev/null +++ b/lexer/src/toks/math.rs @@ -0,0 +1,10 @@ +///! Maths token related utils + +/// The different operators +#[derive(Debug, PartialEq, Clone)] +pub enum MathOperator { + ADD, + SUBSTRACT, + MULTIPLY, + DIVIDE +} \ No newline at end of file diff --git a/lexer/src/toks/mod.rs b/lexer/src/toks/mod.rs new file mode 100644 index 0000000..354c7c9 --- /dev/null +++ b/lexer/src/toks/mod.rs @@ -0,0 +1 @@ +pub mod math; \ No newline at end of file diff --git a/parser/src/ast/math.rs b/parser/src/ast/math.rs new file mode 100644 index 0000000..82aa244 --- /dev/null +++ b/parser/src/ast/math.rs @@ -0,0 +1,18 @@ +use commons::err::PositionedResult; +use lexer::token::LexerToken; + +use crate::ast::{parse_ast_value, tree::ASTTreeNode}; + +pub fn parse_math_operation(tokens: &Vec, ind: &mut usize, original: Box, restricts_to_assigns: bool) -> PositionedResult> { + let oper = tokens[*ind].expects_math_operator()?; + + if !oper.1 && restricts_to_assigns { + return Err(tokens[*ind].make_err("Using math operation without assigments is forbidden here!")); + } + + *ind += 1; + + let rightMember = parse_ast_value(tokens, ind)?; + + return Ok(Box::new(ASTTreeNode::MathResult { lval: original, rval: rightMember, operator: oper.0, assigns: oper.1 })) +} \ No newline at end of file diff --git a/parser/src/ast/mod.rs b/parser/src/ast/mod.rs index b6041d1..20bfadd 100644 --- a/parser/src/ast/mod.rs +++ b/parser/src/ast/mod.rs @@ -12,7 +12,7 @@ use commons::err::PositionedResult; use lexer::token::{LexerToken, LexerTokenType}; use utils::hash::WithHash; -use crate::{ParserError, ParserResult, ast::{cond::operators::parse_condition_operator, control::{forloop::parse_for_loop, ifelse::parse_if_statement, whileblock::parse_while_block}, func::{call::parse_function_call, decl::parse_function_declaraction}, literals::{parse_integer_literal, parse_string_literal}, tree::ASTTreeNode, var::decl::parse_variable_declaration}}; +use crate::{ParserError, ParserResult, ast::{cond::operators::parse_condition_operator, control::{forloop::parse_for_loop, ifelse::parse_if_statement, whileblock::parse_while_block}, func::{call::parse_function_call, decl::parse_function_declaraction}, literals::{parse_integer_literal, parse_string_literal}, math::parse_math_operation, tree::ASTTreeNode, var::decl::parse_variable_declaration}}; pub mod tree; pub mod func; @@ -20,8 +20,9 @@ pub mod var; pub mod literals; pub mod cond; pub mod control; +pub mod math; -pub fn parse_ast_value_post_l(tokens: &Vec, ind: &mut usize, original: PositionedResult>) -> PositionedResult> { +pub fn parse_ast_value_post_l(tokens: &Vec, ind: &mut usize, original: PositionedResult>, invoked_on_body: bool) -> PositionedResult> { match &tokens[*ind].tok_type { LexerTokenType::DOT => { let o = &original?; @@ -43,6 +44,13 @@ pub fn parse_ast_value_post_l(tokens: &Vec, ind: &mut usize, origina return Err(tokens[*ind].make_err("Invalid token type to use dot access!")); }, + LexerTokenType::MATH_OPERATOR(_, _) => { + let o = &original?; + let k = Box::new(ASTTreeNode::clone(o.as_ref())); + + return Ok(parse_math_operation(tokens, ind, k, invoked_on_body)?); + }, + LexerTokenType::ANGEL_BRACKET_CLOSE | LexerTokenType::EQUAL_SIGN | LexerTokenType::ANGEL_BRACKET_OPEN => { let operator = parse_condition_operator(tokens, ind)?; @@ -75,28 +83,28 @@ pub fn parse_ast_value(tokens: &Vec, ind: &mut usize) -> PositionedR LexerTokenType::INT_LIT(_) => { let int = parse_integer_literal(tokens, ind); - return parse_ast_value_post_l(tokens, ind, int); + return parse_ast_value_post_l(tokens, ind, int, false); }, LexerTokenType::STRING_LIT(_) => { let str = parse_string_literal(tokens, ind); - return parse_ast_value_post_l(tokens, ind, str); + return parse_ast_value_post_l(tokens, ind, str, false); }, LexerTokenType::KEYWORD(str, _) => { if tokens[*ind + 1].tok_type == LexerTokenType::PAREN_OPEN { let call = parse_function_call(tokens, ind); - return parse_ast_value_post_l(tokens, ind, call); + return parse_ast_value_post_l(tokens, ind, call, false); } let n = Ok(Box::new(ASTTreeNode::VariableReference(WithHash::new(String::clone(str))))); *ind += 1; - return parse_ast_value_post_l(tokens, ind, n); + return parse_ast_value_post_l(tokens, ind, n, false); } - _ => return Err(tokens[*ind].make_err("Cannot be parsed as value!")) + _ => return Err(tokens[*ind].make_err("Invalid token to parse as a value!")) } } @@ -122,11 +130,23 @@ pub fn parse_ast_node(tokens: &Vec, ind: &mut usize) -> PositionedRe LexerTokenType::FOR => { return parse_for_loop(tokens, ind); - } + }, + + LexerTokenType::KEYWORD(str, _) => { + if tokens[*ind + 1].tok_type == LexerTokenType::PAREN_OPEN { + let call = parse_function_call(tokens, ind); + return parse_ast_value_post_l(tokens, ind, call, true); + } + + let n = Ok(Box::new(ASTTreeNode::VariableReference(WithHash::new(String::clone(str))))); + + *ind += 1; + + return parse_ast_value_post_l(tokens, ind, n, true); + }, _ => { - return Err(tokens[*ind].make_err("Invalid token type! Shouldn't be there!")); + return Err(tokens[*ind].make_err("Expected valid token type in this context!")); } - } } \ No newline at end of file diff --git a/parser/src/ast/tree.rs b/parser/src/ast/tree.rs index b23c121..a05aef8 100644 --- a/parser/src/ast/tree.rs +++ b/parser/src/ast/tree.rs @@ -2,9 +2,10 @@ //! AST tree related definitions. //! +use lexer::toks::math::MathOperator; use utils::hash::{TypeHash, WithHash}; -use crate::ast::cond::operators::ConditionOperator; +use crate::ast::{cond::operators::ConditionOperator}; #[derive(Debug, PartialEq, Clone)] pub struct FunctionDeclarationArgument { @@ -26,6 +27,8 @@ pub enum ASTTreeNode { OperatorBasedConditionMember { lval: Box, rval: Box, operator: ConditionOperator }, BooleanBasedConditionMember { val: Box, negate: bool }, + MathResult { lval: Box, rval: Box, operator: MathOperator, assigns: bool }, + VariableReference(WithHash), VarDeclaration { varName: WithHash, varType: TypeHash, value: Option> },