Parse function call parameters
This commit is contained in:
parent
eb3b755a3c
commit
a6bff95d24
@ -19,6 +19,9 @@
|
||||
|
||||
## v0.0.10
|
||||
|
||||
- [x] Parse function call parameters
|
||||
- [ ] Codegen function call parameters
|
||||
- [ ] Parse function declaration arguments
|
||||
- [ ] Begin work on semantic analysis
|
||||
- [ ] Symbol table
|
||||
- [ ] Typecheck bindings
|
||||
|
@ -18,10 +18,6 @@ impl Transpilable for Expression {
|
||||
Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }),
|
||||
Expression::Identifier(value) => format!("{}", *value),
|
||||
Expression::FunctionCall(f) => f.transpile(),
|
||||
<<<<<<< HEAD
|
||||
Expression::BinaryOperator(_, _, _) => {
|
||||
todo!("BinaryOperator codegen is not implemented yet")
|
||||
=======
|
||||
Expression::BinaryOperator(left_expr, right_expr, operator) => {
|
||||
format!(
|
||||
"{}{}{}",
|
||||
@ -29,7 +25,6 @@ impl Transpilable for Expression {
|
||||
operator,
|
||||
right_expr.transpile()
|
||||
)
|
||||
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
|
||||
}
|
||||
Expression::UnaryOperator(operator, expression) => {
|
||||
format!("{}{}", operator, expression.transpile())
|
||||
|
@ -4,10 +4,6 @@ use super::Transpilable;
|
||||
|
||||
impl Transpilable for FunctionCall {
|
||||
fn transpile(&self) -> String {
|
||||
<<<<<<< HEAD
|
||||
format!("{}();", self.function.transpile())
|
||||
=======
|
||||
format!("{}()", self.identifier)
|
||||
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
|
||||
format!("{}()", self.function.transpile())
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ mod block;
|
||||
mod expression;
|
||||
mod function_call;
|
||||
mod function_declaration;
|
||||
mod function_call;
|
||||
mod module_ast;
|
||||
mod statement;
|
||||
mod top_level_construct;
|
||||
|
@ -37,10 +37,6 @@ mod tests {
|
||||
|
||||
let result = module.transpile();
|
||||
|
||||
<<<<<<< HEAD
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -4,18 +4,11 @@ use super::Transpilable;
|
||||
|
||||
impl Transpilable for Statement {
|
||||
fn transpile(&self) -> String {
|
||||
<<<<<<< HEAD
|
||||
match self {
|
||||
Statement::Binding(binding) => binding.transpile(),
|
||||
Statement::FunctionCall(function_call) => function_call.transpile(),
|
||||
}
|
||||
=======
|
||||
let stmt = match self {
|
||||
Statement::FunctionCall(f) => f.transpile(),
|
||||
Statement::Binding(b) => b.transpile(),
|
||||
};
|
||||
|
||||
format!("{stmt};")
|
||||
>>>>>>> f71f9ab ((lazily) codegen parsed expressions. v0.0.9)
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +116,16 @@ fn next_token(
|
||||
.or_else(|| scanner::operator(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(|| {
|
||||
if next_char == ',' {
|
||||
Some(LexResult::Some(
|
||||
Token::new(",".into(), current_pos, TokenType::Comma),
|
||||
current_pos + 1,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let error = LexError {
|
||||
position: current_pos,
|
||||
|
@ -13,6 +13,7 @@ pub enum TokenType {
|
||||
RightBrace,
|
||||
NewLine,
|
||||
Comment,
|
||||
Comma,
|
||||
INDENT,
|
||||
DEDENT,
|
||||
LET,
|
||||
|
@ -7,8 +7,6 @@ pub struct FunctionCall {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArgumentsList {
|
||||
pub arguments: Vec<Box<Argument>>,
|
||||
pub arguments: Vec<Expression>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Argument {}
|
||||
|
@ -13,3 +13,9 @@ mod unary;
|
||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
||||
return equality::try_parse(tokens, pos);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
}
|
||||
|
@ -98,4 +98,17 @@ mod tests {
|
||||
_ => 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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,3 +25,60 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
|
||||
_ => 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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
use crate::{
|
||||
error_handling::SyntaxError,
|
||||
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> {
|
||||
@ -16,6 +20,38 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Argument
|
||||
};
|
||||
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
|
||||
let (_closing_paren, next_pos) =
|
||||
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;
|
||||
|
||||
ParseResult::Ok(
|
||||
ArgumentsList {
|
||||
arguments: Vec::new(),
|
||||
},
|
||||
current_pos,
|
||||
)
|
||||
ParseResult::Ok(ArgumentsList { arguments }, current_pos)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::net;
|
||||
|
||||
use super::*;
|
||||
use crate::lexic::get_tokens;
|
||||
|
||||
@ -89,4 +122,86 @@ mod tests {
|
||||
assert_eq!(next, 3);
|
||||
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")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user