Compare commits

..

2 Commits

Author SHA1 Message Date
2184f7e654 Parse function parameters 2024-01-21 15:06:53 -05:00
a605d182b4 Codegen function call parameters 2024-01-11 19:36:11 -05:00
6 changed files with 110 additions and 10 deletions

View File

@ -3,6 +3,7 @@
## TODO
- Parse __more__ binary operators
- Parse `Type name = value` bindings
- Parse more complex bindings
- Watch mode
- Improve error messages
@ -20,8 +21,8 @@
## v0.0.10
- [x] Parse function call parameters
- [ ] Codegen function call parameters
- [ ] Parse function declaration arguments
- [x] Codegen function call parameters
- [x] Parse function declaration arguments (Type id)
- [ ] Begin work on semantic analysis
- [ ] Symbol table
- [ ] Typecheck bindings

View File

@ -4,6 +4,8 @@ use super::Transpilable;
impl Transpilable for FunctionCall {
fn transpile(&self) -> String {
format!("{}()", self.function.transpile())
let parameters = &self.arguments.arguments.iter().map(|expr| expr.transpile()).collect::<Vec<_>>().join(", ");
format!("{}({})", self.function.transpile(), parameters)
}
}

View File

@ -3,6 +3,7 @@ use super::Expression;
#[derive(Debug)]
pub struct FunctionCall {
pub function: Box<Expression>,
pub arguments: Box<ArgumentsList>,
}
#[derive(Debug)]

View File

@ -29,6 +29,11 @@ pub struct Block {
#[derive(Debug)]
pub struct ParamsList {}
pub struct Parameter {
pub identifier: Box<String>,
pub datatype: Box<String>,
}
#[derive(Debug)]
pub enum Expression {
Number(Box<String>),

View File

@ -1,7 +1,10 @@
use crate::{
lexic::token::Token,
syntax::{
ast::{functions::FunctionCall, Expression},
ast::{
functions::{ArgumentsList, FunctionCall},
Expression,
},
functions::arguments_list,
ParseResult,
},
@ -20,7 +23,7 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
};
// Parse arguments list
let (_args_list, next_pos) = match arguments_list::try_parse(tokens, next_pos) {
let (arguments, next_pos) = match arguments_list::try_parse(tokens, next_pos) {
ParseResult::Ok(args, next) => (args, next),
ParseResult::Err(err) => return ParseResult::Err(err),
_ => {
@ -30,13 +33,11 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
let fun_call = FunctionCall {
function: Box::new(primary_expr),
arguments: Box::new(arguments),
};
ParseResult::Ok(Expression::FunctionCall(fun_call), next_pos)
}
#[cfg(test)]
mod test {
}
mod test {}

View File

@ -4,7 +4,10 @@ use crate::{
syntax::utils::parse_token_type,
};
use super::{ast::ParamsList, ParseResult};
use super::{
ast::{Parameter, ParamsList},
utils, ParseResult,
};
pub fn parse_params_list<'a>(
tokens: &'a Vec<Token>,
@ -21,6 +24,36 @@ pub fn parse_params_list<'a>(
};
current_pos = next_pos;
// Parse parameters definitions, separated by commas
let mut parameters = Vec::<Parameter>::new();
loop {
let (next_parameter, next_pos) = match parse_param_definition(tokens, current_pos) {
ParseResult::Ok(parameter, next_pos) => (parameter, next_pos),
ParseResult::Err(error) => {
return ParseResult::Err(error);
}
_ => break,
};
current_pos = next_pos;
parameters.push(next_parameter);
// 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) {
@ -45,3 +78,60 @@ pub fn parse_params_list<'a>(
ParseResult::Ok(ParamsList {}, current_pos)
}
fn parse_param_definition<'a>(
tokens: &'a Vec<Token>,
pos: usize,
) -> ParseResult<Parameter, &Token> {
// Parse a single parameter definition of the form:
// - Type identifier
// There will be more constructs in the future, like:
// - Type identifier = default_value
// - FunctionType identifier
// - Pattern identifier (e.g. Some[String] value)?
let mut current_pos = pos;
let (datatype, next_pos) =
match utils::parse_token_type(tokens, current_pos, TokenType::Datatype) {
ParseResult::Ok(token, next) => (token, next),
ParseResult::Err(err) => {
return ParseResult::Err(err);
}
// If there is no datatype this construction doesn't apply.
// Return a mismatch and let the caller handle it
ParseResult::Mismatch(t) => return ParseResult::Mismatch(t),
ParseResult::Unmatched => return ParseResult::Unmatched,
};
current_pos = next_pos;
let (identifier, next_pos) =
match utils::parse_token_type(tokens, current_pos, TokenType::Identifier) {
ParseResult::Ok(token, next) => (token, next),
ParseResult::Err(err) => {
return ParseResult::Err(err);
}
// However, if we fail to parse an identifier, it's an error
ParseResult::Mismatch(_) => {
return ParseResult::Err(SyntaxError {
reason: String::from("Expected an identifier for the parameter."),
error_start: tokens[pos].position,
error_end: tokens[pos].get_end_position(),
});
}
ParseResult::Unmatched => {
return ParseResult::Err(SyntaxError {
reason: String::from("Expected an identifier for the parameter."),
error_start: tokens[pos].position,
error_end: tokens[pos].get_end_position(),
})
}
};
ParseResult::Ok(
Parameter {
identifier: Box::new(identifier.value.clone()),
datatype: Box::new(datatype.value.clone()),
},
next_pos,
)
}