Lex & parse function call
This commit is contained in:
parent
88c5be6439
commit
85339db25e
@ -82,6 +82,8 @@ pub enum Expression {
|
|||||||
I64(i64),
|
I64(i64),
|
||||||
/// String literal
|
/// String literal
|
||||||
String(Rc<String>),
|
String(Rc<String>),
|
||||||
|
|
||||||
|
FunCall(String, Vec<Expression>),
|
||||||
/// Variable
|
/// Variable
|
||||||
Var(String),
|
Var(String),
|
||||||
/// Binary operation. Consists of type, left hand side and right hand side
|
/// Binary operation. Consists of type, left hand side and right hand side
|
||||||
@ -116,6 +118,7 @@ pub enum Statement {
|
|||||||
Loop(Loop),
|
Loop(Loop),
|
||||||
If(If),
|
If(If),
|
||||||
Print(Expression),
|
Print(Expression),
|
||||||
|
FunDecl(Vec<(String, Expression)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||||
|
|||||||
@ -68,6 +68,7 @@ impl Interpreter {
|
|||||||
self.run(body_true);
|
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::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, lhs, rhs),
|
||||||
Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand),
|
Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand),
|
||||||
Expression::Var(name) => self.resolve_var(name),
|
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::LBraces),
|
||||||
'}' => tokens.push(Token::RBraces),
|
'}' => tokens.push(Token::RBraces),
|
||||||
'!' => tokens.push(Token::LNot),
|
'!' => tokens.push(Token::LNot),
|
||||||
|
',' => tokens.push(Token::Comma),
|
||||||
|
|
||||||
// Lex numbers
|
// Lex numbers
|
||||||
ch @ '0'..='9' => {
|
ch @ '0'..='9' => {
|
||||||
@ -189,6 +190,7 @@ impl<'a> Lexer<'a> {
|
|||||||
"print" => Token::Print,
|
"print" => Token::Print,
|
||||||
"if" => Token::If,
|
"if" => Token::If,
|
||||||
"else" => Token::Else,
|
"else" => Token::Else,
|
||||||
|
"fun" => Token::Fun,
|
||||||
|
|
||||||
// If it doesn't match a keyword, it is a normal identifier
|
// If it doesn't match a keyword, it is a normal identifier
|
||||||
_ => Token::Ident(ident),
|
_ => Token::Ident(ident),
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
use crate::token::Token;
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
|
use crate::token::Token;
|
||||||
|
|
||||||
struct Parser<T: Iterator<Item = Token>> {
|
struct Parser<T: Iterator<Item = Token>> {
|
||||||
tokens: Peekable<T>,
|
tokens: Peekable<T>,
|
||||||
@ -28,14 +28,11 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// By default try to lex a statement
|
// By default try to lex a statement
|
||||||
_ => {
|
_ => prog.push(self.parse_stmt()),
|
||||||
prog.push(self.parse_stmt())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast { prog }
|
Ast { prog }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(&mut self) -> Statement {
|
fn parse_stmt(&mut self) -> Statement {
|
||||||
@ -98,13 +95,17 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body_false = self.parse();
|
body_false = self.parse();
|
||||||
|
|
||||||
if !matches!(self.next(), Token::RBraces) {
|
if !matches!(self.next(), Token::RBraces) {
|
||||||
panic!("Error lexing if: Expected '}}'")
|
panic!("Error lexing if: Expected '}}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
If { condition, body_true, body_false }
|
If {
|
||||||
|
condition,
|
||||||
|
body_true,
|
||||||
|
body_false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_loop(&mut self) -> Loop {
|
fn parse_loop(&mut self) -> Loop {
|
||||||
@ -130,17 +131,20 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = self.parse();
|
body = self.parse();
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => panic!("Error lexing loop: Expected ';' or '{{'")
|
_ => panic!("Error lexing loop: Expected ';' or '{{'"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(self.next(), Token::RBraces) {
|
if !matches!(self.next(), Token::RBraces) {
|
||||||
panic!("Error lexing loop: Expected '}}'")
|
panic!("Error lexing loop: Expected '}}'")
|
||||||
}
|
}
|
||||||
|
|
||||||
Loop { condition, advancement, body }
|
Loop {
|
||||||
|
condition,
|
||||||
|
advancement,
|
||||||
|
body,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&mut self) -> Expression {
|
fn parse_expr(&mut self) -> Expression {
|
||||||
@ -185,6 +189,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
// Literal String
|
// Literal String
|
||||||
Token::String(text) => Expression::String(text.into()),
|
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),
|
Token::Ident(name) => Expression::Var(name),
|
||||||
|
|
||||||
// Parentheses grouping
|
// Parentheses grouping
|
||||||
@ -210,7 +216,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
let operand = self.parse_primary();
|
let operand = self.parse_primary();
|
||||||
Expression::UnOp(UnOpType::BNot, operand.into())
|
Expression::UnOp(UnOpType::BNot, operand.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unary logical not
|
// Unary logical not
|
||||||
Token::LNot => {
|
Token::LNot => {
|
||||||
let operand = self.parse_primary();
|
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
|
/// Get the next Token without removing it
|
||||||
fn peek(&mut self) -> &Token {
|
fn peek(&mut self) -> &Token {
|
||||||
self.tokens.peek().unwrap_or(&Token::EoF)
|
self.tokens.peek().unwrap_or(&Token::EoF)
|
||||||
@ -265,8 +289,11 @@ impl BinOpType {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{parse, Expression, BinOpType};
|
use super::{parse, BinOpType, Expression};
|
||||||
use crate::{token::Token, parser::{Statement, Ast}};
|
use crate::{
|
||||||
|
parser::{Ast, Statement},
|
||||||
|
token::Token,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
@ -288,13 +315,20 @@ mod tests {
|
|||||||
Expression::BinOp(
|
Expression::BinOp(
|
||||||
BinOpType::Add,
|
BinOpType::Add,
|
||||||
Expression::I64(1).into(),
|
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(),
|
.into(),
|
||||||
Expression::I64(4).into(),
|
Expression::I64(4).into(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = Ast { prog: vec![expected] };
|
let expected = Ast {
|
||||||
|
prog: vec![expected],
|
||||||
|
};
|
||||||
|
|
||||||
let actual = parse(tokens);
|
let actual = parse(tokens);
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|||||||
@ -23,6 +23,10 @@ pub enum Token {
|
|||||||
/// Else keyword (else)
|
/// Else keyword (else)
|
||||||
Else,
|
Else,
|
||||||
|
|
||||||
|
Fun,
|
||||||
|
|
||||||
|
Comma,
|
||||||
|
|
||||||
/// Left Parenthesis ('(')
|
/// Left Parenthesis ('(')
|
||||||
LParen,
|
LParen,
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user