Lex & parse function call
This commit is contained in:
parent
88c5be6439
commit
85339db25e
@ -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)]
|
||||
|
||||
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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 {
|
||||
@ -98,13 +95,17 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
}
|
||||
|
||||
body_false = self.parse();
|
||||
|
||||
|
||||
if !matches!(self.next(), Token::RBraces) {
|
||||
panic!("Error lexing if: Expected '}}'")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -210,7 +216,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
let operand = self.parse_primary();
|
||||
Expression::UnOp(UnOpType::BNot, operand.into())
|
||||
}
|
||||
|
||||
|
||||
// Unary logical not
|
||||
Token::LNot => {
|
||||
let operand = self.parse_primary();
|
||||
@ -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);
|
||||
|
||||
@ -23,6 +23,10 @@ pub enum Token {
|
||||
/// Else keyword (else)
|
||||
Else,
|
||||
|
||||
Fun,
|
||||
|
||||
Comma,
|
||||
|
||||
/// Left Parenthesis ('(')
|
||||
LParen,
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user