feat: store token on expression::int
This commit is contained in:
parent
f7168f1d09
commit
d88d2e7f2d
@ -17,7 +17,7 @@ impl<'a> PHPTransformable<'a> for Expression<'_> {
|
|||||||
PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))
|
PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))
|
||||||
}
|
}
|
||||||
Expression::Int(value) => {
|
Expression::Int(value) => {
|
||||||
let expr = PhpPrimaryExpression::IntegerLiteral(value);
|
let expr = PhpPrimaryExpression::IntegerLiteral(&value.value);
|
||||||
PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))
|
PhpExpression::Assignment(PhpAssignmentExpression::Primary(expr))
|
||||||
}
|
}
|
||||||
Expression::Float(value) => {
|
Expression::Float(value) => {
|
||||||
@ -32,6 +32,7 @@ impl<'a> PHPTransformable<'a> for Expression<'_> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
|
lexic::token::Token,
|
||||||
php_ast::{
|
php_ast::{
|
||||||
transformers::PHPTransformable, PhpAssignmentExpression, PhpExpression,
|
transformers::PHPTransformable, PhpAssignmentExpression, PhpExpression,
|
||||||
PhpPrimaryExpression,
|
PhpPrimaryExpression,
|
||||||
@ -57,8 +58,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transform_int() {
|
fn should_transform_int() {
|
||||||
let value = String::from("322");
|
let binding = Token::new_int(String::from("322"), 0);
|
||||||
let input = Expression::Int(&value);
|
let input = Expression::Int(&binding);
|
||||||
let output = input.into_php_ast();
|
let output = input.into_php_ast();
|
||||||
|
|
||||||
match output {
|
match output {
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> PHPTransformable<'a> for ModuleAST<'_> {
|
|||||||
Expression::Int(value) => {
|
Expression::Int(value) => {
|
||||||
php_statements.push(PhpStatement::PhpExpressionStatement(
|
php_statements.push(PhpStatement::PhpExpressionStatement(
|
||||||
PhpExpression::Assignment(PhpAssignmentExpression::Primary(
|
PhpExpression::Assignment(PhpAssignmentExpression::Primary(
|
||||||
PhpPrimaryExpression::IntegerLiteral(value),
|
PhpPrimaryExpression::IntegerLiteral(&value.value),
|
||||||
)),
|
)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
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,
|
syntax::ast::Expression,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,13 +40,14 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
let argument_datatype = argument.get_type(scope)?;
|
let argument_datatype = argument.get_type(scope)?;
|
||||||
if !argument_datatype.is_value(parameter) {
|
if !argument_datatype.is_value(parameter) {
|
||||||
// The argument and the parameter have diferent types
|
// The argument and the parameter have diferent types
|
||||||
|
let (error_start, error_end) = argument.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
return Err(MistiError::Semantic(SemanticError {
|
||||||
// TODO: fix
|
// TODO: fix
|
||||||
error_start: 0,
|
error_start,
|
||||||
error_end: 1,
|
error_end,
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"Expected datatype {}, got {:?}",
|
"Expected a {}, got {:?}",
|
||||||
parameter, argument
|
parameter, argument_datatype
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -74,16 +79,22 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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]
|
#[test]
|
||||||
fn should_error() {
|
fn should_error_on_undefined_symbol() {
|
||||||
// source code: `print()`
|
// source code: `print()`
|
||||||
let expr_token = Token::new_identifier("print".into(), 0);
|
let expr_token = Token::new_identifier("print".into(), 0);
|
||||||
let expr_function = Expression::Identifier(&expr_token);
|
let expr_function = Expression::Identifier(&expr_token);
|
||||||
let arguments = ArgumentsList {
|
let arguments = ArgumentsList { arguments: vec![] };
|
||||||
arguments: vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
let expr = Expression::FunctionCall(FunctionCall {
|
let expr = Expression::FunctionCall(FunctionCall {
|
||||||
function: Box::new(expr_function),
|
function: Box::new(expr_function),
|
||||||
@ -99,8 +110,39 @@ mod tests {
|
|||||||
assert_eq!(err.reason, "Cannot find `print` in this scope.");
|
assert_eq!(err.reason, "Cannot find `print` in this scope.");
|
||||||
assert_eq!(err.error_start, 0);
|
assert_eq!(err.error_start, 0);
|
||||||
assert_eq!(err.error_end, 5);
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
pub mod binding;
|
pub mod binding;
|
||||||
|
pub mod expression;
|
||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod top_level_declaration;
|
pub mod top_level_declaration;
|
||||||
pub mod expression;
|
|
||||||
|
|
||||||
|
@ -35,9 +35,6 @@ impl Typed for Expression<'_> {
|
|||||||
// for this to work with any arbitrary expression.
|
// for this to work with any arbitrary expression.
|
||||||
// for now it justs expects an identifier
|
// 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?
|
// TODO: Should this check that the type signature is correct?
|
||||||
// or is this done elsewhere?
|
// or is this done elsewhere?
|
||||||
|
|
||||||
@ -48,7 +45,7 @@ impl Typed for Expression<'_> {
|
|||||||
// Return the return type of the function,
|
// Return the return type of the function,
|
||||||
// not the function itself
|
// not the function itself
|
||||||
Ok(Type::Value(return_type))
|
Ok(Type::Value(return_type))
|
||||||
},
|
}
|
||||||
Some(_) => Err(MistiError::Semantic(SemanticError {
|
Some(_) => Err(MistiError::Semantic(SemanticError {
|
||||||
error_start: id.position,
|
error_start: id.position,
|
||||||
error_end: id.get_end_position(),
|
error_end: id.get_end_position(),
|
||||||
@ -127,10 +124,21 @@ impl Typed for Expression<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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]
|
#[test]
|
||||||
fn should_get_global_print_type() {
|
fn should_get_global_print_type() {
|
||||||
@ -145,7 +153,7 @@ mod tests {
|
|||||||
assert_eq!(params.len(), 1);
|
assert_eq!(params.len(), 1);
|
||||||
assert_eq!(params[0], "String");
|
assert_eq!(params[0], "String");
|
||||||
assert_eq!(return_type, "Void");
|
assert_eq!(return_type, "Void");
|
||||||
},
|
}
|
||||||
Ok(t) => panic!("Expected a Function, got {:?}", t),
|
Ok(t) => panic!("Expected a Function, got {:?}", t),
|
||||||
Err(e) => panic!("Expected Ok, got Err: {:?}", e),
|
Err(e) => panic!("Expected Ok, got Err: {:?}", e),
|
||||||
}
|
}
|
||||||
@ -164,8 +172,8 @@ mod tests {
|
|||||||
assert_eq!(err.error_start, 0);
|
assert_eq!(err.error_start, 0);
|
||||||
assert_eq!(err.error_end, 5);
|
assert_eq!(err.error_end, 5);
|
||||||
assert_eq!(err.reason, "Cannot find `print` in this scope.");
|
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 id_token = Token::new_identifier("print".into(), 0);
|
||||||
let fn_expr = Expression::Identifier(&id_token);
|
let fn_expr = Expression::Identifier(&id_token);
|
||||||
|
|
||||||
let args = ArgumentsList{arguments: vec![]};
|
let args = ArgumentsList { arguments: vec![] };
|
||||||
|
|
||||||
let fn_call = Expression::FunctionCall(FunctionCall {
|
let fn_call = Expression::FunctionCall(FunctionCall {
|
||||||
function: Box::new(fn_expr),
|
function: Box::new(fn_expr),
|
||||||
@ -199,8 +207,8 @@ mod tests {
|
|||||||
|
|
||||||
let id_token = Token::new_identifier("print".into(), 0);
|
let id_token = Token::new_identifier("print".into(), 0);
|
||||||
let fn_expr = Expression::Identifier(&id_token);
|
let fn_expr = Expression::Identifier(&id_token);
|
||||||
|
|
||||||
let args = ArgumentsList{arguments: vec![]};
|
let args = ArgumentsList { arguments: vec![] };
|
||||||
|
|
||||||
let fn_call = Expression::FunctionCall(FunctionCall {
|
let fn_call = Expression::FunctionCall(FunctionCall {
|
||||||
function: Box::new(fn_expr),
|
function: Box::new(fn_expr),
|
||||||
@ -224,8 +232,8 @@ mod tests {
|
|||||||
|
|
||||||
let id_token = Token::new_identifier("print".into(), 0);
|
let id_token = Token::new_identifier("print".into(), 0);
|
||||||
let fn_expr = Expression::Identifier(&id_token);
|
let fn_expr = Expression::Identifier(&id_token);
|
||||||
|
|
||||||
let args = ArgumentsList{arguments: vec![]};
|
let args = ArgumentsList { arguments: vec![] };
|
||||||
|
|
||||||
let fn_call = Expression::FunctionCall(FunctionCall {
|
let fn_call = Expression::FunctionCall(FunctionCall {
|
||||||
function: Box::new(fn_expr),
|
function: Box::new(fn_expr),
|
||||||
|
@ -60,7 +60,7 @@ pub struct Parameter<'a> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Expression<'a> {
|
pub enum Expression<'a> {
|
||||||
Int(&'a String),
|
Int(&'a Token),
|
||||||
Float(&'a String),
|
Float(&'a String),
|
||||||
String(&'a String),
|
String(&'a String),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
@ -69,3 +69,20 @@ pub enum Expression<'a> {
|
|||||||
UnaryOperator(&'a String, Box<Expression<'a>>),
|
UnaryOperator(&'a String, Box<Expression<'a>>),
|
||||||
BinaryOperator(Box<Expression<'a>>, Box<Expression<'a>>, &'a String),
|
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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
match tokens.get_significant(pos) {
|
match tokens.get_significant(pos) {
|
||||||
Some((token, token_pos)) => match token.token_type {
|
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::Float => Ok((Expression::Float(&token.value), token_pos + 1)),
|
||||||
TokenType::String => Ok((Expression::String(&token.value), token_pos + 1)),
|
TokenType::String => Ok((Expression::String(&token.value), token_pos + 1)),
|
||||||
TokenType::Identifier if token.value == "true" || token.value == "false" => {
|
TokenType::Identifier if token.value == "true" || token.value == "false" => {
|
||||||
@ -53,7 +53,7 @@ mod tests {
|
|||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
Ok((Expression::Int(value), _)) => {
|
Ok((Expression::Int(value), _)) => {
|
||||||
assert_eq!("40", format!("{}", value))
|
assert_eq!("40", format!("{}", value.value))
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ mod tests {
|
|||||||
match (operator, *expression) {
|
match (operator, *expression) {
|
||||||
(op, Expression::Int(value)) => {
|
(op, Expression::Int(value)) => {
|
||||||
assert_eq!(*op, "-");
|
assert_eq!(*op, "-");
|
||||||
assert_eq!(*value, "10");
|
assert_eq!(value.value, "10");
|
||||||
}
|
}
|
||||||
_ => panic!("unexpected values"),
|
_ => panic!("unexpected values"),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user