feat: store paren positions on argument list
This commit is contained in:
parent
96d3e11951
commit
d999b8ecfd
@ -5,7 +5,7 @@ use crate::{
|
||||
symbol_table::SymbolTable,
|
||||
types::{Type, Typed},
|
||||
},
|
||||
syntax::ast::Expression,
|
||||
syntax::ast::{Expression, Positionable},
|
||||
};
|
||||
|
||||
impl SemanticCheck for Expression<'_> {
|
||||
@ -20,12 +20,13 @@ impl SemanticCheck for Expression<'_> {
|
||||
Type::Function(parameters, _return_type) => {
|
||||
// Check parameters length
|
||||
if parameters.len() != arguments.len() {
|
||||
let (error_start, error_end) = f.arguments.get_position();
|
||||
|
||||
return Err(MistiError::Semantic(SemanticError {
|
||||
// TODO: fix
|
||||
error_start: 0,
|
||||
error_end: 1,
|
||||
error_start,
|
||||
error_end,
|
||||
reason: format!(
|
||||
"Expected {} arguments, found {}",
|
||||
"Expected {} arguments, got {}",
|
||||
parameters.len(),
|
||||
arguments.len(),
|
||||
),
|
||||
@ -54,10 +55,10 @@ impl SemanticCheck for Expression<'_> {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let (error_start, error_end) = fun.get_position();
|
||||
return Err(MistiError::Semantic(SemanticError {
|
||||
// TODO: fix
|
||||
error_start: 0,
|
||||
error_end: 1,
|
||||
error_start,
|
||||
error_end,
|
||||
reason: format!(
|
||||
"Expected a function type, got {:?}",
|
||||
function_datatype
|
||||
@ -94,7 +95,11 @@ mod tests {
|
||||
// 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![],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 7,
|
||||
};
|
||||
|
||||
let expr = Expression::FunctionCall(FunctionCall {
|
||||
function: Box::new(expr_function),
|
||||
@ -128,6 +133,8 @@ mod tests {
|
||||
let arg_1 = Expression::Int(&arg_t);
|
||||
let arguments = ArgumentsList {
|
||||
arguments: vec![arg_1],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 10,
|
||||
};
|
||||
|
||||
let expr = Expression::FunctionCall(FunctionCall {
|
||||
@ -145,4 +152,72 @@ mod tests {
|
||||
Err(e) => panic!("Expected semantic error, got {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_error_on_invalid_function_argument_count() {
|
||||
// source code: `print()`
|
||||
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 arguments = ArgumentsList {
|
||||
arguments: vec![],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 7,
|
||||
};
|
||||
|
||||
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 1 arguments, got 0");
|
||||
assert_eq!(e.error_start, 5);
|
||||
assert_eq!(e.error_end, 7);
|
||||
}
|
||||
Err(e) => panic!("Expected semantic error, got {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_error_on_invalid_function_argument_2() {
|
||||
// source code: `print(322, 644)`
|
||||
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 arg_t_2 = Token::new_int(String::from("644"), 11);
|
||||
let arg_2 = Expression::Int(&arg_t_2);
|
||||
|
||||
let arguments = ArgumentsList {
|
||||
arguments: vec![arg_1, arg_2],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 15,
|
||||
};
|
||||
|
||||
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 1 arguments, got 2");
|
||||
assert_eq!(e.error_start, 5);
|
||||
assert_eq!(e.error_end, 15);
|
||||
}
|
||||
Err(e) => panic!("Expected semantic error, got {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,11 @@ 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![],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 7,
|
||||
};
|
||||
|
||||
let fn_call = Expression::FunctionCall(FunctionCall {
|
||||
function: Box::new(fn_expr),
|
||||
@ -208,7 +212,11 @@ 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![],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 7,
|
||||
};
|
||||
|
||||
let fn_call = Expression::FunctionCall(FunctionCall {
|
||||
function: Box::new(fn_expr),
|
||||
@ -233,7 +241,11 @@ 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![],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 7,
|
||||
};
|
||||
|
||||
let fn_call = Expression::FunctionCall(FunctionCall {
|
||||
function: Box::new(fn_expr),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::Expression;
|
||||
use super::{Expression, Positionable};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionCall<'a> {
|
||||
@ -9,4 +9,13 @@ pub struct FunctionCall<'a> {
|
||||
#[derive(Debug)]
|
||||
pub struct ArgumentsList<'a> {
|
||||
pub arguments: Vec<Expression<'a>>,
|
||||
pub paren_open_pos: usize,
|
||||
/// This is after the paren is closed
|
||||
pub paren_close_pos: usize,
|
||||
}
|
||||
|
||||
impl Positionable for ArgumentsList<'_> {
|
||||
fn get_position(&self) -> (usize, usize) {
|
||||
(self.paren_open_pos, self.paren_close_pos)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,12 @@ use var_binding::VariableBinding;
|
||||
pub mod functions;
|
||||
pub mod var_binding;
|
||||
|
||||
/// Trait that allows nodes to inform
|
||||
/// on where they start and end on the source code
|
||||
pub trait Positionable {
|
||||
fn get_position(&self) -> (usize, usize);
|
||||
}
|
||||
|
||||
/// The AST for a whole THP file
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleAST<'a> {
|
||||
@ -70,19 +76,19 @@ pub enum Expression<'a> {
|
||||
BinaryOperator(Box<Expression<'a>>, Box<Expression<'a>>, &'a String),
|
||||
}
|
||||
|
||||
impl Expression<'_> {
|
||||
impl Positionable for Expression<'_> {
|
||||
/// Returns the absolute start and end position
|
||||
/// of this expression
|
||||
pub fn get_position(&self) -> (usize, usize) {
|
||||
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(id) => (id.position, id.get_end_position()),
|
||||
Expression::String(id) => (id.position, id.get_end_position()),
|
||||
Expression::Boolean(id) => (id.position, id.get_end_position()),
|
||||
Expression::FunctionCall(_) => todo!(),
|
||||
Expression::UnaryOperator(_, _) => todo!(),
|
||||
Expression::BinaryOperator(_, _, _) => todo!(),
|
||||
Expression::FunctionCall(_) => (0, 1),
|
||||
Expression::UnaryOperator(_, _) => (0, 1),
|
||||
Expression::BinaryOperator(_, _, _) => (0, 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Argume
|
||||
}
|
||||
|
||||
// Parse closing paren
|
||||
let (_closing_paren, next_pos) =
|
||||
let (closing_paren, next_pos) =
|
||||
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
||||
Ok((t, next)) => (t, next),
|
||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||
@ -74,7 +74,14 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Argume
|
||||
};
|
||||
current_pos = next_pos;
|
||||
|
||||
Ok((ArgumentsList { arguments }, current_pos))
|
||||
Ok((
|
||||
ArgumentsList {
|
||||
arguments,
|
||||
paren_open_pos: opening_paren.position,
|
||||
paren_close_pos: closing_paren.get_end_position(),
|
||||
},
|
||||
current_pos,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Loading…
Reference in New Issue
Block a user