Lex & parse function call

This commit is contained in:
Daniel M 2022-02-03 01:03:05 +01:00
parent 88c5be6439
commit 85339db25e
5 changed files with 61 additions and 16 deletions

View File

@ -82,6 +82,8 @@ pub enum Expression {
I64(i64),
/// String literal
String(Rc<String>),
FunCall(String, Vec<Expression>),
/// Variable
Var(String),
/// Binary operation. Consists of type, left hand side and right hand side
@ -116,6 +118,7 @@ pub enum Statement {
Loop(Loop),
If(If),
Print(Expression),
FunDecl(Vec<(String, Expression)>),
}
#[derive(Debug, PartialEq, Eq, Clone, Default)]

View File

@ -68,6 +68,7 @@ impl Interpreter {
self.run(body_true);
}
}
Statement::FunDecl(_) => todo!(),
}
}
@ -80,6 +81,7 @@ impl Interpreter {
Expression::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, lhs, rhs),
Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand),
Expression::Var(name) => self.resolve_var(name),
Expression::FunCall(_, _) => todo!(),
}
}

View File

@ -106,6 +106,7 @@ impl<'a> Lexer<'a> {
'{' => tokens.push(Token::LBraces),
'}' => tokens.push(Token::RBraces),
'!' => tokens.push(Token::LNot),
',' => tokens.push(Token::Comma),
// Lex numbers
ch @ '0'..='9' => {
@ -189,6 +190,7 @@ impl<'a> Lexer<'a> {
"print" => Token::Print,
"if" => Token::If,
"else" => Token::Else,
"fun" => Token::Fun,
// If it doesn't match a keyword, it is a normal identifier
_ => Token::Ident(ident),

View File

@ -1,7 +1,7 @@
use std::iter::Peekable;
use crate::token::Token;
use crate::ast::*;
use crate::token::Token;
struct Parser<T: Iterator<Item = Token>> {
tokens: Peekable<T>,
@ -28,14 +28,11 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
// By default try to lex a statement
_ => {
prog.push(self.parse_stmt())
}
_ => prog.push(self.parse_stmt()),
}
}
Ast { prog }
}
fn parse_stmt(&mut self) -> Statement {
@ -104,7 +101,11 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
}
If { condition, body_true, body_false }
If {
condition,
body_true,
body_false,
}
}
fn parse_loop(&mut self) -> Loop {
@ -130,17 +131,20 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
body = self.parse();
},
}
_ => panic!("Error lexing loop: Expected ';' or '{{'")
_ => panic!("Error lexing loop: Expected ';' or '{{'"),
}
if !matches!(self.next(), Token::RBraces) {
panic!("Error lexing loop: Expected '}}'")
}
Loop { condition, advancement, body }
Loop {
condition,
advancement,
body,
}
}
fn parse_expr(&mut self) -> Expression {
@ -185,6 +189,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
// Literal String
Token::String(text) => Expression::String(text.into()),
Token::Ident(name) if matches!(self.peek(), Token::LParen) => self.parse_funcall(name),
Token::Ident(name) => Expression::Var(name),
// Parentheses grouping
@ -221,6 +227,24 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
}
fn parse_funcall(&mut self, name: String) -> Expression {
let mut args = Vec::new();
// Consume (
self.next();
while self.peek() != &Token::RParen {
args.push(self.parse_expr());
if self.peek() == &Token::Comma {
self.next();
}
}
self.next();
Expression::FunCall(name, args)
}
/// Get the next Token without removing it
fn peek(&mut self) -> &Token {
self.tokens.peek().unwrap_or(&Token::EoF)
@ -265,8 +289,11 @@ impl BinOpType {
#[cfg(test)]
mod tests {
use super::{parse, Expression, BinOpType};
use crate::{token::Token, parser::{Statement, Ast}};
use super::{parse, BinOpType, Expression};
use crate::{
parser::{Ast, Statement},
token::Token,
};
#[test]
fn test_parser() {
@ -288,13 +315,20 @@ mod tests {
Expression::BinOp(
BinOpType::Add,
Expression::I64(1).into(),
Expression::BinOp(BinOpType::Mul, Expression::I64(2).into(), Expression::I64(3).into()).into(),
Expression::BinOp(
BinOpType::Mul,
Expression::I64(2).into(),
Expression::I64(3).into(),
)
.into(),
)
.into(),
Expression::I64(4).into(),
));
let expected = Ast { prog: vec![expected] };
let expected = Ast {
prog: vec![expected],
};
let actual = parse(tokens);
assert_eq!(expected, actual);

View File

@ -23,6 +23,10 @@ pub enum Token {
/// Else keyword (else)
Else,
Fun,
Comma,
/// Left Parenthesis ('(')
LParen,