From d88d2e7f2d3e9dc76805ad4992302028cb8043e6 Mon Sep 17 00:00:00 2001 From: Araozu Date: Mon, 12 Aug 2024 19:36:31 -0500 Subject: [PATCH] feat: store token on expression::int --- src/php_ast/transformers/expression.rs | 7 +-- src/php_ast/transformers/module_ast.rs | 2 +- src/semantic/checks/expression.rs | 66 +++++++++++++++++++----- src/semantic/checks/mod.rs | 3 +- src/semantic/types/expression.rs | 38 ++++++++------ src/syntax/ast/mod.rs | 19 ++++++- src/syntax/parsers/expression/primary.rs | 4 +- src/syntax/parsers/expression/unary.rs | 2 +- 8 files changed, 104 insertions(+), 37 deletions(-) diff --git a/src/php_ast/transformers/expression.rs b/src/php_ast/transformers/expression.rs index 8673fea..ee3fc56 100644 --- a/src/php_ast/transformers/expression.rs +++ b/src/php_ast/transformers/expression.rs @@ -17,7 +17,7 @@ impl<'a> PHPTransformable<'a> for Expression<'_> { PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)) } Expression::Int(value) => { - let expr = PhpPrimaryExpression::IntegerLiteral(value); + let expr = PhpPrimaryExpression::IntegerLiteral(&value.value); PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr)) } Expression::Float(value) => { @@ -32,6 +32,7 @@ impl<'a> PHPTransformable<'a> for Expression<'_> { #[cfg(test)] mod tests { use crate::{ + lexic::token::Token, php_ast::{ transformers::PHPTransformable, PhpAssignmentExpression, PhpExpression, PhpPrimaryExpression, @@ -57,8 +58,8 @@ mod tests { #[test] fn should_transform_int() { - let value = String::from("322"); - let input = Expression::Int(&value); + let binding = Token::new_int(String::from("322"), 0); + let input = Expression::Int(&binding); let output = input.into_php_ast(); match output { diff --git a/src/php_ast/transformers/module_ast.rs b/src/php_ast/transformers/module_ast.rs index 9de64b8..003a811 100644 --- a/src/php_ast/transformers/module_ast.rs +++ b/src/php_ast/transformers/module_ast.rs @@ -54,7 +54,7 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> { Expression::Int(value) => { php_statements.push(PhpStatement::PhpExpressionStatement( PhpExpression::Assignment(PhpAssignmentExpression::Primary( - PhpPrimaryExpression::IntegerLiteral(value), + PhpPrimaryExpression::IntegerLiteral(&value.value), )), )); } diff --git a/src/semantic/checks/expression.rs b/src/semantic/checks/expression.rs index 04a89b0..7fb4e5e 100644 --- a/src/semantic/checks/expression.rs +++ b/src/semantic/checks/expression.rs @@ -1,6 +1,10 @@ use crate::{ error_handling::{semantic_error::SemanticError, MistiError}, - semantic::{impls::SemanticCheck, symbol_table::SymbolTable, types::{Type, Typed}}, + semantic::{ + impls::SemanticCheck, + symbol_table::SymbolTable, + types::{Type, Typed}, + }, syntax::ast::Expression, }; @@ -36,13 +40,14 @@ impl SemanticCheck for Expression<'_> { let argument_datatype = argument.get_type(scope)?; if !argument_datatype.is_value(parameter) { // The argument and the parameter have diferent types + let (error_start, error_end) = argument.get_position(); return Err(MistiError::Semantic(SemanticError { // TODO: fix - error_start: 0, - error_end: 1, + error_start, + error_end, reason: format!( - "Expected datatype {}, got {:?}", - parameter, argument + "Expected a {}, got {:?}", + parameter, argument_datatype ), })); } @@ -74,16 +79,22 @@ impl SemanticCheck for Expression<'_> { #[cfg(test)] mod tests { - use crate::{error_handling::MistiError, lexic::token::Token, semantic::{impls::SemanticCheck, symbol_table::SymbolTable}, syntax::ast::{functions::{ArgumentsList, FunctionCall}, Expression}}; + use crate::{ + error_handling::MistiError, + lexic::token::Token, + semantic::{impls::SemanticCheck, std::populate, symbol_table::SymbolTable}, + syntax::ast::{ + functions::{ArgumentsList, FunctionCall}, + Expression, + }, + }; #[test] - fn should_error() { + fn should_error_on_undefined_symbol() { // source code: `print()` let expr_token = Token::new_identifier("print".into(), 0); let expr_function = Expression::Identifier(&expr_token); - let arguments = ArgumentsList { - arguments: vec![] - }; + let arguments = ArgumentsList { arguments: vec![] }; let expr = Expression::FunctionCall(FunctionCall { function: Box::new(expr_function), @@ -99,8 +110,39 @@ mod tests { assert_eq!(err.reason, "Cannot find `print` in this scope."); assert_eq!(err.error_start, 0); assert_eq!(err.error_end, 5); - }, - Err(e) => panic!("Expected a Semantic error, got {:?}", e) + } + Err(e) => panic!("Expected a Semantic error, got {:?}", e), + } + } + + #[test] + fn should_error_on_invalid_function_argument() { + // source code: `print(322)` + let mut scope = SymbolTable::new(); + populate(&mut scope); + + let expr_token = Token::new_identifier("print".into(), 0); + let expr_function = Expression::Identifier(&expr_token); + + let arg_t = Token::new_int(String::from("322"), 6); + let arg_1 = Expression::Int(&arg_t); + let arguments = ArgumentsList { + arguments: vec![arg_1], + }; + + let expr = Expression::FunctionCall(FunctionCall { + function: Box::new(expr_function), + arguments: Box::new(arguments), + }); + + match expr.check_semantics(&scope) { + Ok(_) => panic!("Expected semantic error, got ok"), + Err(MistiError::Semantic(e)) => { + assert_eq!(e.reason, "Expected a String, got Value(\"Int\")"); + assert_eq!(e.error_start, 6); + assert_eq!(e.error_end, 9); + } + Err(e) => panic!("Expected semantic error, got {:?}", e), } } } diff --git a/src/semantic/checks/mod.rs b/src/semantic/checks/mod.rs index 4bf25fd..58ef15b 100644 --- a/src/semantic/checks/mod.rs +++ b/src/semantic/checks/mod.rs @@ -1,5 +1,4 @@ pub mod binding; +pub mod expression; pub mod function_declaration; pub mod top_level_declaration; -pub mod expression; - diff --git a/src/semantic/types/expression.rs b/src/semantic/types/expression.rs index 9b2b0a0..69a029e 100644 --- a/src/semantic/types/expression.rs +++ b/src/semantic/types/expression.rs @@ -35,9 +35,6 @@ impl Typed for Expression<'_> { // for this to work with any arbitrary expression. // for now it justs expects an identifier - // The type of a function call is the return type - // of the function - // TODO: Should this check that the type signature is correct? // or is this done elsewhere? @@ -48,7 +45,7 @@ impl Typed for Expression<'_> { // Return the return type of the function, // not the function itself Ok(Type::Value(return_type)) - }, + } Some(_) => Err(MistiError::Semantic(SemanticError { error_start: id.position, error_end: id.get_end_position(), @@ -127,10 +124,21 @@ impl Typed for Expression<'_> { } } - #[cfg(test)] mod tests { - use crate::{error_handling::MistiError, lexic::token::Token, semantic::{std::populate, symbol_table::SymbolTable, types::{Type, Typed}}, syntax::ast::{functions::{ArgumentsList, FunctionCall}, Expression}}; + use crate::{ + error_handling::MistiError, + lexic::token::Token, + semantic::{ + std::populate, + symbol_table::SymbolTable, + types::{Type, Typed}, + }, + syntax::ast::{ + functions::{ArgumentsList, FunctionCall}, + Expression, + }, + }; #[test] fn should_get_global_print_type() { @@ -145,7 +153,7 @@ mod tests { assert_eq!(params.len(), 1); assert_eq!(params[0], "String"); assert_eq!(return_type, "Void"); - }, + } Ok(t) => panic!("Expected a Function, got {:?}", t), Err(e) => panic!("Expected Ok, got Err: {:?}", e), } @@ -164,8 +172,8 @@ mod tests { assert_eq!(err.error_start, 0); assert_eq!(err.error_end, 5); assert_eq!(err.reason, "Cannot find `print` in this scope."); - }, - Err(e) => panic!("Expected a semantic error, got {:?}", e) + } + Err(e) => panic!("Expected a semantic error, got {:?}", e), } } @@ -176,8 +184,8 @@ mod tests { let id_token = Token::new_identifier("print".into(), 0); let fn_expr = Expression::Identifier(&id_token); - - let args = ArgumentsList{arguments: vec![]}; + + let args = ArgumentsList { arguments: vec![] }; let fn_call = Expression::FunctionCall(FunctionCall { function: Box::new(fn_expr), @@ -199,8 +207,8 @@ mod tests { let id_token = Token::new_identifier("print".into(), 0); let fn_expr = Expression::Identifier(&id_token); - - let args = ArgumentsList{arguments: vec![]}; + + let args = ArgumentsList { arguments: vec![] }; let fn_call = Expression::FunctionCall(FunctionCall { function: Box::new(fn_expr), @@ -224,8 +232,8 @@ mod tests { let id_token = Token::new_identifier("print".into(), 0); let fn_expr = Expression::Identifier(&id_token); - - let args = ArgumentsList{arguments: vec![]}; + + let args = ArgumentsList { arguments: vec![] }; let fn_call = Expression::FunctionCall(FunctionCall { function: Box::new(fn_expr), diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index 706e53e..4f06b33 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -60,7 +60,7 @@ pub struct Parameter<'a> { #[derive(Debug)] pub enum Expression<'a> { - Int(&'a String), + Int(&'a Token), Float(&'a String), String(&'a String), Boolean(bool), @@ -69,3 +69,20 @@ pub enum Expression<'a> { UnaryOperator(&'a String, Box>), BinaryOperator(Box>, Box>, &'a String), } + +impl Expression<'_> { + /// Returns the absolute start and end position + /// of this expression + pub fn get_position(&self) -> (usize, usize) { + match self { + Expression::Identifier(id) => (id.position, id.get_end_position()), + Expression::Int(id) => (id.position, id.get_end_position()), + Expression::Float(_) => todo!(), + Expression::String(_) => todo!(), + Expression::Boolean(_) => todo!(), + Expression::FunctionCall(_) => todo!(), + Expression::UnaryOperator(_, _) => todo!(), + Expression::BinaryOperator(_, _, _) => todo!(), + } + } +} diff --git a/src/syntax/parsers/expression/primary.rs b/src/syntax/parsers/expression/primary.rs index fb6c3d8..807f6cd 100644 --- a/src/syntax/parsers/expression/primary.rs +++ b/src/syntax/parsers/expression/primary.rs @@ -13,7 +13,7 @@ use crate::{ pub fn try_parse(tokens: &Vec, pos: usize) -> ParsingResult { match tokens.get_significant(pos) { Some((token, token_pos)) => match token.token_type { - TokenType::Int => Ok((Expression::Int(&token.value), token_pos + 1)), + TokenType::Int => Ok((Expression::Int(&token), token_pos + 1)), TokenType::Float => Ok((Expression::Float(&token.value), token_pos + 1)), TokenType::String => Ok((Expression::String(&token.value), token_pos + 1)), TokenType::Identifier if token.value == "true" || token.value == "false" => { @@ -53,7 +53,7 @@ mod tests { match expression { Ok((Expression::Int(value), _)) => { - assert_eq!("40", format!("{}", value)) + assert_eq!("40", format!("{}", value.value)) } _ => panic!(), } diff --git a/src/syntax/parsers/expression/unary.rs b/src/syntax/parsers/expression/unary.rs index f496f2e..827d681 100644 --- a/src/syntax/parsers/expression/unary.rs +++ b/src/syntax/parsers/expression/unary.rs @@ -54,7 +54,7 @@ mod tests { match (operator, *expression) { (op, Expression::Int(value)) => { assert_eq!(*op, "-"); - assert_eq!(*value, "10"); + assert_eq!(value.value, "10"); } _ => panic!("unexpected values"), }