feat: store token on expression::int

master
Araozu 2024-08-12 19:36:31 -05:00
parent f7168f1d09
commit d88d2e7f2d
8 changed files with 104 additions and 37 deletions

View File

@ -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 {

View File

@ -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),
)),
));
}

View File

@ -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),
}
}
}

View File

@ -1,5 +1,4 @@
pub mod binding;
pub mod expression;
pub mod function_declaration;
pub mod top_level_declaration;
pub mod expression;

View File

@ -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),

View File

@ -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<Expression<'a>>),
BinaryOperator(Box<Expression<'a>>, Box<Expression<'a>>, &'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!(),
}
}
}

View File

@ -13,7 +13,7 @@ use crate::{
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
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!(),
}

View File

@ -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"),
}