Parse function call parameters

master
Araozu 2024-01-11 19:29:19 -05:00
parent eb3b755a3c
commit a6bff95d24
13 changed files with 214 additions and 32 deletions

View File

@ -19,6 +19,9 @@
## v0.0.10 ## v0.0.10
- [x] Parse function call parameters
- [ ] Codegen function call parameters
- [ ] Parse function declaration arguments
- [ ] Begin work on semantic analysis - [ ] Begin work on semantic analysis
- [ ] Symbol table - [ ] Symbol table
- [ ] Typecheck bindings - [ ] Typecheck bindings

View File

@ -18,10 +18,6 @@ impl Transpilable for Expression {
Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }), Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }),
Expression::Identifier(value) => format!("{}", *value), Expression::Identifier(value) => format!("{}", *value),
Expression::FunctionCall(f) => f.transpile(), Expression::FunctionCall(f) => f.transpile(),
<<<<<<< HEAD
Expression::BinaryOperator(_, _, _) => {
todo!("BinaryOperator codegen is not implemented yet")
=======
Expression::BinaryOperator(left_expr, right_expr, operator) => { Expression::BinaryOperator(left_expr, right_expr, operator) => {
format!( format!(
"{}{}{}", "{}{}{}",
@ -29,7 +25,6 @@ impl Transpilable for Expression {
operator, operator,
right_expr.transpile() right_expr.transpile()
) )
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
} }
Expression::UnaryOperator(operator, expression) => { Expression::UnaryOperator(operator, expression) => {
format!("{}{}", operator, expression.transpile()) format!("{}{}", operator, expression.transpile())

View File

@ -4,10 +4,6 @@ use super::Transpilable;
impl Transpilable for FunctionCall { impl Transpilable for FunctionCall {
fn transpile(&self) -> String { fn transpile(&self) -> String {
<<<<<<< HEAD format!("{}()", self.function.transpile())
format!("{}();", self.function.transpile())
=======
format!("{}()", self.identifier)
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
} }
} }

View File

@ -5,7 +5,6 @@ mod block;
mod expression; mod expression;
mod function_call; mod function_call;
mod function_declaration; mod function_declaration;
mod function_call;
mod module_ast; mod module_ast;
mod statement; mod statement;
mod top_level_construct; mod top_level_construct;

View File

@ -37,10 +37,6 @@ mod tests {
let result = module.transpile(); let result = module.transpile();
<<<<<<< HEAD
assert_eq!("<?php\n\n$identifier = 322;\n", result);
=======
assert_eq!("<?php\n\n$identifier = 322\n", result); assert_eq!("<?php\n\n$identifier = 322\n", result);
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
} }
} }

View File

@ -4,18 +4,11 @@ use super::Transpilable;
impl Transpilable for Statement { impl Transpilable for Statement {
fn transpile(&self) -> String { fn transpile(&self) -> String {
<<<<<<< HEAD
match self {
Statement::Binding(binding) => binding.transpile(),
Statement::FunctionCall(function_call) => function_call.transpile(),
}
=======
let stmt = match self { let stmt = match self {
Statement::FunctionCall(f) => f.transpile(), Statement::FunctionCall(f) => f.transpile(),
Statement::Binding(b) => b.transpile(), Statement::Binding(b) => b.transpile(),
}; };
format!("{stmt};") format!("{stmt};")
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
} }
} }

View File

@ -116,6 +116,16 @@ fn next_token(
.or_else(|| scanner::operator(next_char, chars, current_pos)) .or_else(|| scanner::operator(next_char, chars, current_pos))
.or_else(|| scanner::grouping_sign(next_char, chars, current_pos)) .or_else(|| scanner::grouping_sign(next_char, chars, current_pos))
.or_else(|| scanner::new_line(next_char, chars, current_pos)) .or_else(|| scanner::new_line(next_char, chars, current_pos))
.or_else(|| {
if next_char == ',' {
Some(LexResult::Some(
Token::new(",".into(), current_pos, TokenType::Comma),
current_pos + 1,
))
} else {
None
}
})
.unwrap_or_else(|| { .unwrap_or_else(|| {
let error = LexError { let error = LexError {
position: current_pos, position: current_pos,

View File

@ -13,6 +13,7 @@ pub enum TokenType {
RightBrace, RightBrace,
NewLine, NewLine,
Comment, Comment,
Comma,
INDENT, INDENT,
DEDENT, DEDENT,
LET, LET,

View File

@ -7,8 +7,6 @@ pub struct FunctionCall {
#[derive(Debug)] #[derive(Debug)]
pub struct ArgumentsList { pub struct ArgumentsList {
pub arguments: Vec<Box<Argument>>, pub arguments: Vec<Expression>,
} }
#[derive(Debug)]
pub enum Argument {}

View File

@ -13,3 +13,9 @@ mod unary;
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
return equality::try_parse(tokens, pos); return equality::try_parse(tokens, pos);
} }
#[cfg(test)]
mod tests {
}

View File

@ -98,4 +98,17 @@ mod tests {
_ => panic!(), _ => panic!(),
} }
} }
#[test]
fn should_parse_grouped_expression() {
let tokens = get_tokens(&String::from("(identifier)")).unwrap();
let expression = try_parse(&tokens, 0);
match expression {
ParseResult::Ok(Expression::Identifier(value), _) => {
assert_eq!("identifier", format!("{}", value))
}
_ => panic!(),
}
}
} }

View File

@ -25,3 +25,60 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
_ => function_call_expr::try_parse(tokens, pos), _ => function_call_expr::try_parse(tokens, pos),
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::lexic::get_tokens;
#[test]
fn should_parse_single_expression() {
let tokens = get_tokens(&String::from("identifier")).unwrap();
let expression = try_parse(&tokens, 0);
match expression {
ParseResult::Ok(Expression::Identifier(value), _) => {
assert_eq!("identifier", format!("{}", value))
}
_ => panic!(),
}
}
#[test]
fn should_parse_unary_expression() {
let tokens = get_tokens(&String::from("-10")).unwrap();
let expression = try_parse(&tokens, 0);
match expression {
ParseResult::Ok(Expression::UnaryOperator(operator, expression), _) => {
match (operator, *expression) {
(op, Expression::Number(value)) => {
assert_eq!(*op, "-");
assert_eq!(*value, "10");
}
_ => panic!("unexpected values"),
}
}
_ => panic!(),
}
}
#[test]
fn should_parse_grouped_unary_expression() {
let tokens = get_tokens(&String::from("-(25 + 30)")).unwrap();
let expression = try_parse(&tokens, 0);
match expression {
ParseResult::Ok(Expression::UnaryOperator(operator, expression), _) => {
assert_eq!(*operator, "-");
match *expression {
Expression::BinaryOperator(_, _, _) => {
// :D
}
_ => panic!("unexpected values"),
}
}
_ => panic!(),
}
}
}

View File

@ -1,7 +1,11 @@
use crate::{ use crate::{
error_handling::SyntaxError, error_handling::SyntaxError,
lexic::token::{Token, TokenType}, lexic::token::{Token, TokenType},
syntax::{ast::functions::ArgumentsList, utils::parse_token_type, ParseResult}, syntax::{
ast::{functions::ArgumentsList, Expression},
utils::parse_token_type,
ParseResult,
},
}; };
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<ArgumentsList, &Token> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<ArgumentsList, &Token> {
@ -16,6 +20,38 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Argument
}; };
current_pos = next_pos; current_pos = next_pos;
let mut arguments = Vec::<Expression>::new();
loop {
let (next_expression, next_pos) =
match super::super::expression::try_parse(tokens, current_pos) {
ParseResult::Ok(expression, next_pos) => (expression, next_pos),
ParseResult::Err(error) => {
// TODO: Write a more detailed error
return ParseResult::Err(error);
}
_ => break,
};
current_pos = next_pos;
arguments.push(next_expression);
// Parse comma. This also parses a trailing comma
match parse_token_type(tokens, current_pos, TokenType::Comma) {
ParseResult::Ok(_, next) => {
current_pos = next;
}
// This should never happen
ParseResult::Err(err) => return ParseResult::Err(err),
ParseResult::Mismatch(_) => {
// Something other than a comma was found. It must be a closing paren )
// Still, break the loop, assume there are no more arguments
// TODO: This could be a good place to write a detailed error?
break;
}
ParseResult::Unmatched => break,
};
}
// Parse closing paren // Parse closing paren
let (_closing_paren, next_pos) = let (_closing_paren, next_pos) =
match parse_token_type(tokens, current_pos, TokenType::RightParen) { match parse_token_type(tokens, current_pos, TokenType::RightParen) {
@ -38,16 +74,13 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Argument
}; };
current_pos = next_pos; current_pos = next_pos;
ParseResult::Ok( ParseResult::Ok(ArgumentsList { arguments }, current_pos)
ArgumentsList {
arguments: Vec::new(),
},
current_pos,
)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::net;
use super::*; use super::*;
use crate::lexic::get_tokens; use crate::lexic::get_tokens;
@ -89,4 +122,86 @@ mod tests {
assert_eq!(next, 3); assert_eq!(next, 3);
assert_eq!(list.arguments.len(), 0); assert_eq!(list.arguments.len(), 0);
} }
#[test]
fn should_parse_one_argument() {
let tokens = get_tokens(&String::from("(0)")).unwrap();
let fun_decl = try_parse(&tokens, 0);
let ParseResult::Ok(arguments_list, next) = fun_decl else {
panic!("Expected a result, got: {:?}", fun_decl);
};
assert_eq!(next, 3);
assert_eq!(arguments_list.arguments.len(), 1);
let first_argument = arguments_list.arguments.get(0).unwrap();
let Expression::Number(_) = first_argument else {
panic!("Expected a number")
};
}
#[test]
fn should_parse_one_argument_with_trailing_comma() {
let tokens = get_tokens(&String::from("(0, )")).unwrap();
let fun_decl = try_parse(&tokens, 0);
let ParseResult::Ok(arguments_list, next) = fun_decl else {
panic!("Expected a result, got: {:?}", fun_decl);
};
assert_eq!(next, 4);
assert_eq!(arguments_list.arguments.len(), 1);
let first_argument = arguments_list.arguments.get(0).unwrap();
let Expression::Number(_) = first_argument else {
panic!("Expected a number")
};
}
#[test]
fn should_parse_multiple_arguments() {
let tokens = get_tokens(&String::from("(\"Hello new world\", 322, )")).unwrap();
let fun_decl = try_parse(&tokens, 0);
let ParseResult::Ok(arguments_list, _next) = fun_decl else {
panic!("Expected a result, got: {:?}", fun_decl);
};
assert_eq!(arguments_list.arguments.len(), 2);
let first_argument = arguments_list.arguments.get(0).unwrap();
let Expression::String(_) = first_argument else {
panic!("Expected a string")
};
let second_argument = arguments_list.arguments.get(1).unwrap();
let Expression::Number(_) = second_argument else {
panic!("Expected a number")
};
}
#[test]
fn should_parse_nested_function_calls() {
let tokens = get_tokens(&String::from("(foo(), bar())")).unwrap();
let fun_decl = try_parse(&tokens, 0);
let ParseResult::Ok(arguments_list, _next) = fun_decl else {
panic!("Expected a result, got: {:?}", fun_decl);
};
assert_eq!(arguments_list.arguments.len(), 2);
let first_argument = arguments_list.arguments.get(0).unwrap();
let Expression::FunctionCall(_f1) = first_argument else {
panic!("Expected a function call")
};
let second_argument = arguments_list.arguments.get(1).unwrap();
let Expression::FunctionCall(_) = second_argument else {
panic!("Expected a number")
};
}
} }