finish parser + change token types to enum

This commit is contained in:
YannAhlgrim
2026-06-03 16:35:43 +02:00
parent 0b4223e509
commit c53bc78b46
5 changed files with 742 additions and 143 deletions
+277 -20
View File
@@ -1,32 +1,65 @@
use crate::token; use crate::token::Token;
pub trait NodeTrait { pub trait NodeTrait {
fn token_literal(&self) -> String; fn token_literal(&self) -> String;
fn string(&self) -> String;
} }
pub trait StatementTrait: NodeTrait { pub trait StatementTrait: NodeTrait {
fn statement_node(&self); fn statement_node(&self);
} }
trait ExpressionTrait: NodeTrait { pub enum Expression {
fn expression_node(&self); Identifier(Identifier),
} IntegerLiteral(IntegerLiteral),
pub struct Expression { PrefixExpression(PrefixExpression),
// InfixExpression(InfixExpression),
Boolean(Boolean),
BlockStatement(BlockStatement),
IfExpression(IfExpression),
FunctionLiteral(FunctionLiteral),
CallExpression(CallExpression),
} }
impl NodeTrait for Expression { impl NodeTrait for Expression {
fn token_literal(&self) -> String { fn token_literal(&self) -> String {
todo!() match self {
Expression::Identifier(i) => i.token_literal(),
Expression::IntegerLiteral(i) => i.token_literal(),
Expression::PrefixExpression(i) => i.token_literal(),
Expression::InfixExpression(i) => i.token_literal(),
Expression::Boolean(i) => i.token_literal(),
Expression::BlockStatement(i) => i.token_literal(),
Expression::IfExpression(i) => i.token_literal(),
Expression::FunctionLiteral(i) => i.token_literal(),
Expression::CallExpression(i) => i.token_literal(),
}
}
fn string(&self) -> String {
match self {
Expression::Identifier(i) => i.string(),
Expression::IntegerLiteral(i) => i.string(),
Expression::PrefixExpression(i) => i.string(),
Expression::InfixExpression(i) => i.string(),
Expression::Boolean(i) => i.string(),
Expression::BlockStatement(i) => i.string(),
Expression::IfExpression(i) => i.string(),
Expression::FunctionLiteral(i) => i.string(),
Expression::CallExpression(i) => i.string(),
}
} }
} }
pub struct Statement { pub struct Statement;
//
}
impl NodeTrait for Statement { impl NodeTrait for Statement {
fn token_literal(&self) -> String { fn token_literal(&self) -> String {
todo!() todo!()
} }
fn string(&self) -> String {
todo!()
}
} }
impl StatementTrait for Statement { impl StatementTrait for Statement {
@@ -45,28 +78,89 @@ impl NodeTrait for Program {
String::new() String::new()
} }
} }
fn string(&self) -> String {
let mut out = String::new();
for stmt in &self.statements {
out.push_str(&stmt.string());
}
out
}
} }
pub struct LetStatement { pub struct LetStatement {
pub token: token::Token, pub token: Token,
pub name: Identifier, pub name: Identifier,
pub value: Expression, pub value: Expression,
} }
pub struct ReturnStatement {
pub token: Token,
pub return_value: Expression,
}
pub struct ExpressionStatement {
pub token: Token,
pub expression: Expression,
}
impl NodeTrait for LetStatement { impl NodeTrait for LetStatement {
fn token_literal(&self) -> String { fn token_literal(&self) -> String {
String::from(&self.token.literal) String::from(&self.token.literal)
} }
}
impl StatementTrait for LetStatement { fn string(&self) -> String {
fn statement_node(&self) { let mut out = String::new();
todo!() out.push_str(&self.token_literal());
out.push_str(" ");
out.push_str(&self.name.string());
out.push_str(" = ");
out.push_str(&self.value.string());
out.push_str(";");
out
} }
} }
impl StatementTrait for LetStatement {
fn statement_node(&self) {}
}
impl NodeTrait for ReturnStatement {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
out.push_str(&self.token_literal());
out.push_str(" ");
out.push_str(&self.return_value.string());
out.push_str(";");
out
}
}
impl StatementTrait for ReturnStatement {
fn statement_node(&self) {}
}
impl NodeTrait for ExpressionStatement {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
self.expression.string()
}
}
impl StatementTrait for ExpressionStatement {
fn statement_node(&self) {}
}
#[derive(Debug, Default)]
pub struct Identifier { pub struct Identifier {
pub token: token::Token, pub token: Token,
pub value: String, pub value: String,
} }
@@ -74,10 +168,173 @@ impl NodeTrait for Identifier {
fn token_literal(&self) -> String { fn token_literal(&self) -> String {
String::from(&self.token.literal) String::from(&self.token.literal)
} }
}
impl ExpressionTrait for Identifier { fn string(&self) -> String {
fn expression_node(&self) { self.value.clone()
todo!() }
}
#[derive(Debug)]
pub struct IntegerLiteral {
pub token: Token,
pub value: i64,
}
impl NodeTrait for IntegerLiteral {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
self.token.literal.clone()
}
}
pub struct PrefixExpression {
pub token: Token,
pub operator: String,
pub right: Box<Expression>,
}
impl NodeTrait for PrefixExpression {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
out.push_str(&self.operator);
out.push_str(&self.right.string());
out
}
}
pub struct InfixExpression {
pub token: Token,
pub left: Box<Expression>,
pub operator: String,
pub right: Box<Expression>,
}
impl NodeTrait for InfixExpression {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
out.push_str("(");
out.push_str(&self.left.string());
out.push_str(" ");
out.push_str(&self.operator);
out.push_str(" ");
out.push_str(&self.right.string());
out.push_str(")");
out
}
}
pub struct Boolean {
pub token: Token,
pub value: bool,
}
impl NodeTrait for Boolean {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
self.token.literal.clone()
}
}
pub struct IfExpression {
pub token: Token,
pub condition: Box<Expression>,
pub consequence: BlockStatement,
pub alternative: Option<BlockStatement>,
}
impl NodeTrait for IfExpression {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
out.push_str("if");
out.push_str(&self.condition.string());
out.push_str(" ");
out.push_str(&self.consequence.string());
if let Some(alt) = &self.alternative {
out.push_str("else ");
out.push_str(&alt.string());
}
out
}
}
pub struct BlockStatement {
pub token: Token,
pub statements: Vec<Box<dyn StatementTrait>>,
}
impl NodeTrait for BlockStatement {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
for stmt in &self.statements {
out.push_str(&stmt.string());
}
out
}
}
pub struct FunctionLiteral {
pub token: Token,
pub parameters: Vec<Identifier>,
pub body: BlockStatement,
}
impl NodeTrait for FunctionLiteral {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
out.push_str(&self.token_literal());
out.push_str("(");
let params: Vec<String> = self.parameters.iter().map(|p| p.string()).collect();
out.push_str(&params.join(", "));
out.push_str(") ");
out.push_str(&self.body.string());
out
}
}
pub struct CallExpression {
pub token: Token,
pub function: Box<Expression>,
pub arguments: Vec<Expression>,
}
impl NodeTrait for CallExpression {
fn token_literal(&self) -> String {
String::from(&self.token.literal)
}
fn string(&self) -> String {
let mut out = String::new();
out.push_str(&self.function.string());
out.push_str("(");
let args: Vec<String> = self.arguments.iter().map(|a| a.string()).collect();
out.push_str(&args.join(", "));
out.push_str(")");
out
} }
} }
+26 -46
View File
@@ -1,25 +1,5 @@
use crate::token::lookup_ident; use crate::token::lookup_ident;
use crate::token::{Token, TokenType};
use super::token::ASSIGN;
use super::token::ASTERISK;
use super::token::BANG;
use super::token::COMMA;
use super::token::EOF;
use super::token::EQ;
use super::token::GT;
use super::token::ILLEGAL;
use super::token::INT;
use super::token::LBRACE;
use super::token::LPAREN;
use super::token::LT;
use super::token::MINUS;
use super::token::NQ;
use super::token::PLUS;
use super::token::RBRACE;
use super::token::RPAREN;
use super::token::SEMICOLON;
use super::token::SLASH;
use super::token::Token;
pub struct Lexer { pub struct Lexer {
input: String, input: String,
@@ -67,44 +47,46 @@ impl LexerTraits for Lexer {
} }
fn next_token(&mut self) -> Token { fn next_token(&mut self) -> Token {
#[allow(unused_assignments)] let mut tok = Token {
let mut tok = Token::default(); type_: TokenType::Illegal,
literal: String::new(),
};
self.skip_whitespace(); self.skip_whitespace();
let lit = self.ch.unwrap(); let lit = self.ch.unwrap();
let c = char::from(lit); let c = char::from(lit);
match c { match c {
'\0' => tok = new_token(EOF, lit), '\0' => tok = new_token(TokenType::Eof, lit),
'=' => { '=' => {
if char::from(self.peek_char()) == '=' { if char::from(self.peek_char()) == '=' {
self.read_char(); self.read_char();
let lit = String::from("=="); let lit = String::from("==");
tok = new_token_from_str(EQ, lit); tok = new_token_from_str(TokenType::Eq, lit);
} else { } else {
tok = new_token(ASSIGN, lit); tok = new_token(TokenType::Assign, lit);
} }
} }
';' => tok = new_token(SEMICOLON, lit), ';' => tok = new_token(TokenType::Semicolon, lit),
'(' => tok = new_token(LPAREN, lit), '(' => tok = new_token(TokenType::Lparen, lit),
')' => tok = new_token(RPAREN, lit), ')' => tok = new_token(TokenType::Rparen, lit),
',' => tok = new_token(COMMA, lit), ',' => tok = new_token(TokenType::Comma, lit),
'+' => tok = new_token(PLUS, lit), '+' => tok = new_token(TokenType::Plus, lit),
'-' => tok = new_token(MINUS, lit), '-' => tok = new_token(TokenType::Minus, lit),
'!' => { '!' => {
if char::from(self.peek_char()) == '=' { if char::from(self.peek_char()) == '=' {
self.read_char(); self.read_char();
let lit = String::from("!="); let lit = String::from("!=");
tok = new_token_from_str(NQ, lit); tok = new_token_from_str(TokenType::Neq, lit);
} else { } else {
tok = new_token(BANG, lit); tok = new_token(TokenType::Bang, lit);
} }
} }
'/' => tok = new_token(SLASH, lit), '/' => tok = new_token(TokenType::Slash, lit),
'*' => tok = new_token(ASTERISK, lit), '*' => tok = new_token(TokenType::Asterisk, lit),
'<' => tok = new_token(LT, lit), '<' => tok = new_token(TokenType::Lt, lit),
'>' => tok = new_token(GT, lit), '>' => tok = new_token(TokenType::Gt, lit),
'{' => tok = new_token(LBRACE, lit), '{' => tok = new_token(TokenType::Lbrace, lit),
'}' => tok = new_token(RBRACE, lit), '}' => tok = new_token(TokenType::Rbrace, lit),
_ => { _ => {
if c.is_alphabetic() { if c.is_alphabetic() {
let lit = self.read_identifier(); let lit = self.read_identifier();
@@ -112,9 +94,9 @@ impl LexerTraits for Lexer {
return new_token_from_str(tok_type, lit); return new_token_from_str(tok_type, lit);
} else if c.is_ascii_digit() { } else if c.is_ascii_digit() {
let lit = self.read_number(); let lit = self.read_number();
return new_token_from_str(INT, lit); return new_token_from_str(TokenType::Int, lit);
} else { } else {
tok = new_token(ILLEGAL, lit); tok = new_token(TokenType::Illegal, lit);
} }
} }
} }
@@ -166,17 +148,15 @@ impl LexerTraits for Lexer {
} }
} }
fn new_token(token_type: &str, ch: u8) -> Token { fn new_token(token_type: TokenType, ch: u8) -> Token {
let lit = String::from(char::from(ch)); let lit = String::from(char::from(ch));
let token_type = String::from(token_type);
Token { Token {
type_: token_type, type_: token_type,
literal: lit, literal: lit,
} }
} }
fn new_token_from_str(token_type: &str, lit: String) -> Token { fn new_token_from_str(token_type: TokenType, lit: String) -> Token {
let token_type = String::from(token_type);
Token { Token {
type_: token_type, type_: token_type,
literal: lit, literal: lit,
+358 -35
View File
@@ -1,52 +1,118 @@
use crate::{ use crate::{
ast::{self}, ast::{self},
lexer::{self, LexerTraits}, lexer::{self, LexerTraits},
token::{self, EOF}, token::{self, TokenType},
}; };
use std::collections::HashMap;
type PrefixParseFn = fn(&mut Parser) -> Option<ast::Expression>;
type InfixParseFn = fn(&mut Parser, ast::Expression) -> Option<ast::Expression>;
pub struct Parser { pub struct Parser {
lexer: lexer::Lexer, lexer: lexer::Lexer,
cur_token: token::Token, cur_token: token::Token,
peek_token: token::Token, peek_token: token::Token,
errors: Vec<String>, errors: Vec<String>,
} prefix_parse_fns: HashMap<TokenType, PrefixParseFn>,
infix_parse_fns: HashMap<TokenType, InfixParseFn>,
pub trait ParserTrait {
fn next_token(&mut self);
fn parse_program(&mut self) -> ast::Program;
fn parse_statement(&mut self) -> Option<Box<dyn ast::StatementTrait>>;
fn parse_let_statement(&mut self) -> Option<Box<dyn ast::StatementTrait>>;
fn cur_token_is(&self, t: String) -> bool;
fn peek_token_is(&self, t: String) -> bool;
fn expect_peek(&mut self, t: String) -> bool;
fn errors(&self) -> &Vec<String>;
fn peek_error(&mut self, t: String);
} }
pub fn new_parser(l: lexer::Lexer) -> Parser { pub fn new_parser(l: lexer::Lexer) -> Parser {
let mut p: Parser = Parser { let mut p = Parser {
lexer: l, lexer: l,
cur_token: token::Token { cur_token: token::Token {
literal: String::new(), literal: String::new(),
type_: String::new(), type_: TokenType::Illegal,
}, },
peek_token: token::Token { peek_token: token::Token {
literal: String::new(), literal: String::new(),
type_: String::new(), type_: TokenType::Illegal,
}, },
errors: Vec::new(), errors: Vec::new(),
prefix_parse_fns: HashMap::new(),
infix_parse_fns: HashMap::new(),
}; };
p.register_prefix(TokenType::Ident, Parser::parse_identifier);
p.register_prefix(TokenType::Int, Parser::parse_integer_literal);
p.register_prefix(TokenType::Bang, Parser::parse_prefix_expression);
p.register_prefix(TokenType::Minus, Parser::parse_prefix_expression);
p.register_infix(TokenType::Plus, Parser::parse_infix_expression);
p.register_infix(TokenType::Minus, Parser::parse_infix_expression);
p.register_infix(TokenType::Slash, Parser::parse_infix_expression);
p.register_infix(TokenType::Asterisk, Parser::parse_infix_expression);
p.register_infix(TokenType::Eq, Parser::parse_infix_expression);
p.register_infix(TokenType::Neq, Parser::parse_infix_expression);
p.register_infix(TokenType::Lt, Parser::parse_infix_expression);
p.register_infix(TokenType::Gt, Parser::parse_infix_expression);
p.register_prefix(TokenType::True, Parser::parse_boolean);
p.register_prefix(TokenType::False, Parser::parse_boolean);
p.register_prefix(TokenType::Lparen, Parser::parse_grouped_expression);
p.register_prefix(TokenType::If, Parser::parse_if_expression);
p.register_prefix(TokenType::Function, Parser::parse_function_literal);
p.register_infix(TokenType::Lparen, Parser::parse_call_expression);
p.next_token(); p.next_token();
p.next_token(); p.next_token();
p p
} }
impl ParserTrait for Parser { impl Parser {
fn register_prefix(&mut self, t: TokenType, f: PrefixParseFn) {
self.prefix_parse_fns.insert(t, f);
}
fn register_infix(&mut self, t: TokenType, f: InfixParseFn) {
self.infix_parse_fns.insert(t, f);
}
fn parse_identifier(&mut self) -> Option<ast::Expression> {
Some(ast::Expression::Identifier(ast::Identifier {
token: self.cur_token.clone(),
value: self.cur_token.literal.clone(),
}))
}
fn parse_integer_literal(&mut self) -> Option<ast::Expression> {
let value: i64 = self.cur_token.literal.parse().ok()?;
Some(ast::Expression::IntegerLiteral(ast::IntegerLiteral {
token: self.cur_token.clone(),
value,
}))
}
fn no_prefix_parse_fn_error(&mut self) {
let msg = format!(
"no prefix parse function for {} found",
self.cur_token.type_
);
self.errors.push(msg);
}
fn peek_precedence(&self) -> Precedence {
match self.peek_token.type_ {
TokenType::Eq | TokenType::Neq => Precedence::Equals,
TokenType::Lt | TokenType::Gt => Precedence::Lessgreater,
TokenType::Plus | TokenType::Minus => Precedence::Sum,
TokenType::Slash | TokenType::Asterisk => Precedence::Product,
TokenType::Lparen => Precedence::Call,
_ => Precedence::Lowest,
}
}
fn cur_precedence(&self) -> Precedence {
match self.cur_token.type_ {
TokenType::Eq | TokenType::Neq => Precedence::Equals,
TokenType::Lt | TokenType::Gt => Precedence::Lessgreater,
TokenType::Plus | TokenType::Minus => Precedence::Sum,
TokenType::Slash | TokenType::Asterisk => Precedence::Product,
TokenType::Lparen => Precedence::Call,
_ => Precedence::Lowest,
}
}
fn next_token(&mut self) { fn next_token(&mut self) {
self.cur_token = token::Token { self.cur_token = token::Token {
literal: String::from(&self.peek_token.literal), literal: String::from(&self.peek_token.literal),
type_: String::from(&self.peek_token.type_), type_: self.peek_token.type_,
}; };
self.peek_token = self.lexer.next_token(); self.peek_token = self.lexer.next_token();
} }
@@ -55,7 +121,7 @@ impl ParserTrait for Parser {
let mut program = ast::Program { let mut program = ast::Program {
statements: Vec::new(), statements: Vec::new(),
}; };
while &self.cur_token.type_ != EOF { while self.cur_token.type_ != TokenType::Eof {
if let Some(stmt) = self.parse_statement() { if let Some(stmt) = self.parse_statement() {
program.statements.push(stmt); program.statements.push(stmt);
} }
@@ -65,21 +131,22 @@ impl ParserTrait for Parser {
} }
fn parse_statement(&mut self) -> Option<Box<dyn ast::StatementTrait>> { fn parse_statement(&mut self) -> Option<Box<dyn ast::StatementTrait>> {
match self.cur_token.type_.as_str() { match self.cur_token.type_ {
token::LET => self.parse_let_statement(), TokenType::Let => self.parse_let_statement(),
_ => None, TokenType::Return => self.parse_return_statement(),
_ => self.parse_expression_statement(),
} }
} }
fn cur_token_is(&self, t: String) -> bool { fn cur_token_is(&self, t: TokenType) -> bool {
self.cur_token.type_ == t self.cur_token.type_ == t
} }
fn peek_token_is(&self, t: String) -> bool { fn peek_token_is(&self, t: TokenType) -> bool {
self.peek_token.type_ == t self.peek_token.type_ == t
} }
fn expect_peek(&mut self, t: String) -> bool { fn expect_peek(&mut self, t: TokenType) -> bool {
if self.peek_token_is(t) { if self.peek_token_is(t) {
self.next_token(); self.next_token();
true true
@@ -92,46 +159,291 @@ impl ParserTrait for Parser {
let mut stmt = ast::LetStatement { let mut stmt = ast::LetStatement {
token: token::Token { token: token::Token {
literal: String::from(&self.cur_token.literal), literal: String::from(&self.cur_token.literal),
type_: String::from(&self.cur_token.type_), type_: self.cur_token.type_.clone(),
}, },
name: ast::Identifier { name: ast::Identifier {
token: token::Token { token: token::Token {
literal: String::new(), literal: String::new(),
type_: String::new(), type_: TokenType::Illegal,
}, },
value: String::new(), value: String::new(),
}, },
value: ast::Expression {}, value: ast::Expression::Identifier(ast::Identifier {
token: token::Token {
literal: String::new(),
type_: TokenType::Illegal,
},
value: String::new(),
}),
}; };
if !self.expect_peek(token::IDENT.to_string()) { if !self.expect_peek(TokenType::Ident) {
return None; return None;
} }
stmt.name = ast::Identifier { stmt.name = ast::Identifier {
token: token::Token { token: token::Token {
literal: String::from(&self.cur_token.literal), literal: String::from(&self.cur_token.literal),
type_: String::from(&self.cur_token.type_), type_: self.cur_token.type_.clone(),
}, },
value: String::from(&self.cur_token.literal), value: String::from(&self.cur_token.literal),
}; };
if !self.expect_peek(token::ASSIGN.to_string()) { if !self.expect_peek(TokenType::Assign) {
return None; return None;
} }
while !self.cur_token_is(token::SEMICOLON.to_string()) { self.next_token();
stmt.value = self.parse_expression(Precedence::Lowest)?;
if self.peek_token_is(TokenType::Semicolon) {
self.next_token(); self.next_token();
} }
Some(Box::from(stmt)) Some(Box::new(stmt))
}
fn parse_return_statement(&mut self) -> Option<Box<dyn ast::StatementTrait>> {
let mut stmt = ast::ReturnStatement {
token: token::Token {
literal: String::from(&self.cur_token.literal),
type_: self.cur_token.type_.clone(),
},
return_value: ast::Expression::Identifier(ast::Identifier {
token: token::Token {
literal: String::new(),
type_: TokenType::Illegal,
},
value: String::new(),
}),
};
self.next_token();
stmt.return_value = self.parse_expression(Precedence::Lowest)?;
if self.peek_token_is(TokenType::Semicolon) {
self.next_token();
}
Some(Box::new(stmt))
}
fn parse_expression_statement(&mut self) -> Option<Box<dyn ast::StatementTrait>> {
let stmt = ast::ExpressionStatement {
token: token::Token {
literal: String::from(&self.cur_token.literal),
type_: self.cur_token.type_,
},
expression: self.parse_expression(Precedence::Lowest).unwrap(),
};
if self.peek_token_is(TokenType::Semicolon) {
self.next_token();
}
Some(Box::new(stmt))
}
fn parse_expression(&mut self, precedence: Precedence) -> Option<ast::Expression> {
let prefix = self.prefix_parse_fns.get(&self.cur_token.type_).copied();
let mut left = match prefix {
Some(f) => f(self)?,
None => {
self.no_prefix_parse_fn_error();
return None;
}
};
while !self.peek_token_is(TokenType::Semicolon) && precedence < self.peek_precedence() {
let infix = self.infix_parse_fns.get(&self.peek_token.type_).copied();
match infix {
Some(f) => {
self.next_token();
left = f(self, left)?;
}
None => return Some(left),
}
}
Some(left)
}
fn parse_prefix_expression(&mut self) -> Option<ast::Expression> {
let token = self.cur_token.clone();
let operator = self.cur_token.literal.clone();
self.next_token();
let right = self.parse_expression(Precedence::Prefix)?;
Some(ast::Expression::PrefixExpression(ast::PrefixExpression {
token,
operator,
right: Box::new(right),
}))
}
fn parse_infix_expression(&mut self, left: ast::Expression) -> Option<ast::Expression> {
let token = self.cur_token.clone();
let operator = self.cur_token.literal.clone();
let precedence = self.cur_precedence();
self.next_token();
let right = self.parse_expression(precedence)?;
Some(ast::Expression::InfixExpression(ast::InfixExpression {
token,
left: Box::new(left),
operator,
right: Box::new(right),
}))
}
fn parse_boolean(&mut self) -> Option<ast::Expression> {
Some(ast::Expression::Boolean(ast::Boolean {
token: self.cur_token.clone(),
value: self.cur_token_is(TokenType::True),
}))
}
fn parse_grouped_expression(&mut self) -> Option<ast::Expression> {
self.next_token();
let exp = self.parse_expression(Precedence::Lowest)?;
if !self.expect_peek(TokenType::Rparen) {
return None;
}
Some(exp)
}
fn parse_if_expression(&mut self) -> Option<ast::Expression> {
let mut expression = ast::IfExpression {
token: self.cur_token.clone(),
condition: Box::new(ast::Expression::Identifier(ast::Identifier {
token: token::Token {
literal: String::new(),
type_: TokenType::Illegal,
},
value: String::new(),
})),
consequence: ast::BlockStatement {
token: token::Token {
literal: String::new(),
type_: TokenType::Illegal,
},
statements: Vec::new(),
},
alternative: None,
};
if !self.expect_peek(TokenType::Lparen) {
return None;
}
self.next_token();
expression.condition = Box::new(self.parse_expression(Precedence::Lowest)?);
if !self.expect_peek(TokenType::Rparen) {
return None;
}
if !self.expect_peek(TokenType::Lbrace) {
return None;
}
expression.consequence = self.parse_block_statement()?;
if self.peek_token_is(TokenType::Else) {
self.next_token();
if !self.expect_peek(TokenType::Lbrace) {
return None;
}
expression.alternative = Some(self.parse_block_statement()?);
}
return Some(ast::Expression::IfExpression(expression));
}
fn parse_block_statement(&mut self) -> Option<ast::BlockStatement> {
let mut block = ast::BlockStatement {
token: self.cur_token.clone(),
statements: Vec::new(),
};
self.next_token();
while !self.cur_token_is(TokenType::Rbrace) && !self.cur_token_is(TokenType::Eof) {
if let Some(stmt) = self.parse_statement() {
block.statements.push(stmt);
}
self.next_token();
}
Some(block)
}
fn parse_function_literal(&mut self) -> Option<ast::Expression> {
let token = self.cur_token.clone();
if !self.expect_peek(TokenType::Lparen) {
return None;
}
let parameters = self.parse_function_parameters()?;
if !self.expect_peek(TokenType::Lbrace) {
return None;
}
let body = self.parse_block_statement()?;
Some(ast::Expression::FunctionLiteral(ast::FunctionLiteral {
token,
parameters,
body,
}))
}
fn parse_function_parameters(&mut self) -> Option<Vec<ast::Identifier>> {
let mut identifiers = Vec::new();
if self.peek_token_is(TokenType::Rparen) {
self.next_token();
return Some(identifiers);
}
self.next_token();
identifiers.push(ast::Identifier {
token: self.cur_token.clone(),
value: self.cur_token.literal.clone(),
});
while self.peek_token_is(TokenType::Comma) {
self.next_token();
self.next_token();
identifiers.push(ast::Identifier {
token: self.cur_token.clone(),
value: self.cur_token.literal.clone(),
});
}
if !self.expect_peek(TokenType::Rparen) {
return None;
}
Some(identifiers)
}
fn parse_call_expression(&mut self, function: ast::Expression) -> Option<ast::Expression> {
let token = self.cur_token.clone();
let arguments = self.parse_call_arguments()?;
Some(ast::Expression::CallExpression(ast::CallExpression {
token,
function: Box::new(function),
arguments,
}))
}
fn parse_call_arguments(&mut self) -> Option<Vec<ast::Expression>> {
let mut args = Vec::new();
if self.peek_token_is(TokenType::Rparen) {
self.next_token();
return Some(args);
}
self.next_token();
args.push(self.parse_expression(Precedence::Lowest)?);
while self.peek_token_is(TokenType::Comma) {
self.next_token();
self.next_token();
args.push(self.parse_expression(Precedence::Lowest)?);
}
if !self.expect_peek(TokenType::Rparen) {
return None;
}
Some(args)
} }
fn errors(&self) -> &Vec<String> { fn errors(&self) -> &Vec<String> {
&self.errors &self.errors
} }
fn peek_error(&mut self, t: String) { fn peek_error(&mut self, t: TokenType) {
let msg = format!( let msg = format!(
"expected next token to be {}, got {} instead", "expected next token to be {}, got {} instead",
t, self.peek_token.type_ t, self.peek_token.type_
@@ -139,3 +451,14 @@ impl ParserTrait for Parser {
self.errors.push(msg); self.errors.push(msg);
} }
} }
#[derive(Debug, PartialEq, PartialOrd)]
pub enum Precedence {
Lowest,
Equals,
Lessgreater,
Sum,
Product,
Prefix,
Call,
}
+2 -3
View File
@@ -1,3 +1,4 @@
use crate::ast::NodeTrait;
use crate::lexer::new; use crate::lexer::new;
use crate::parser::Parser; use crate::parser::Parser;
use crate::parser::ParserTrait; use crate::parser::ParserTrait;
@@ -20,8 +21,6 @@ pub fn start_repl() {
let lexer = new(input.to_string()); let lexer = new(input.to_string());
let mut parser: Parser = new_parser(lexer); let mut parser: Parser = new_parser(lexer);
let program = parser.parse_program(); let program = parser.parse_program();
for stmt in program.statements { println!("{}", program.string());
println!("{:?}", stmt.token_literal());
}
} }
} }
+79 -39
View File
@@ -1,46 +1,86 @@
#[derive(Default)] use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TokenType {
#[default]
Illegal,
Eof,
Ident,
Int,
Assign,
Plus,
Minus,
Bang,
Asterisk,
Slash,
Lt,
Gt,
Comma,
Semicolon,
Lparen,
Rparen,
Lbrace,
Rbrace,
Function,
Let,
True,
False,
If,
Else,
Return,
Eq,
Neq,
}
impl fmt::Display for TokenType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TokenType::Illegal => write!(f, "ILLEGAL"),
TokenType::Eof => write!(f, "EOF"),
TokenType::Ident => write!(f, "IDENT"),
TokenType::Int => write!(f, "INT"),
TokenType::Assign => write!(f, "="),
TokenType::Plus => write!(f, "+"),
TokenType::Minus => write!(f, "-"),
TokenType::Bang => write!(f, "!"),
TokenType::Asterisk => write!(f, "*"),
TokenType::Slash => write!(f, "/"),
TokenType::Lt => write!(f, "<"),
TokenType::Gt => write!(f, ">"),
TokenType::Comma => write!(f, ","),
TokenType::Semicolon => write!(f, ";"),
TokenType::Lparen => write!(f, "("),
TokenType::Rparen => write!(f, ")"),
TokenType::Lbrace => write!(f, "{{"),
TokenType::Rbrace => write!(f, "}}"),
TokenType::Function => write!(f, "FUNCTION"),
TokenType::Let => write!(f, "LET"),
TokenType::True => write!(f, "TRUE"),
TokenType::False => write!(f, "FALSE"),
TokenType::If => write!(f, "IF"),
TokenType::Else => write!(f, "ELSE"),
TokenType::Return => write!(f, "RETURN"),
TokenType::Eq => write!(f, "=="),
TokenType::Neq => write!(f, "!="),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Token { pub struct Token {
pub type_: String, pub type_: TokenType,
pub literal: String, pub literal: String,
} }
pub const ILLEGAL: &str = "ILLEGAL"; pub fn lookup_ident(ident: &str) -> TokenType {
pub const EOF: &str = "EOF";
pub const IDENT: &str = "IDENT";
pub const INT: &str = "INT";
pub const ASSIGN: &str = "=";
pub const PLUS: &str = "+";
pub const MINUS: &str = "-";
pub const BANG: &str = "!";
pub const ASTERISK: &str = "*";
pub const SLASH: &str = "/";
pub const LT: &str = "<";
pub const GT: &str = ">";
pub const COMMA: &str = ",";
pub const SEMICOLON: &str = ";";
pub const LPAREN: &str = "(";
pub const RPAREN: &str = ")";
pub const LBRACE: &str = "{";
pub const RBRACE: &str = "}";
pub const FUNCTION: &str = "FUNCTION";
pub const LET: &str = "LET";
pub const TRUE: &str = "TRUE";
pub const FALSE: &str = "FALSE";
pub const IF: &str = "IF";
pub const ELSE: &str = "ELSE";
pub const RETURN: &str = "RETURN";
pub const EQ: &str = "EQ";
pub const NQ: &str = "NQ";
pub fn lookup_ident(ident: &str) -> &'static str {
match ident { match ident {
"fn" => FUNCTION, "fn" => TokenType::Function,
"let" => LET, "let" => TokenType::Let,
"true" => TRUE, "true" => TokenType::True,
"false" => FALSE, "false" => TokenType::False,
"if" => IF, "if" => TokenType::If,
"else" => ELSE, "else" => TokenType::Else,
"return" => RETURN, "return" => TokenType::Return,
_ => IDENT, _ => TokenType::Ident,
} }
} }