added statement parsing
This commit is contained in:
parent
a21b119e58
commit
9932c83d6f
4 changed files with 226 additions and 17 deletions
|
|
@ -30,8 +30,9 @@ pub fn infix_bp(op: &BinaryOp) -> (u8, u8) {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Expr {
|
||||
Number(i64),
|
||||
Bool(bool),
|
||||
Ident(String),
|
||||
EOL,
|
||||
StringLit(String),
|
||||
|
||||
Binary {
|
||||
op: BinaryOp,
|
||||
|
|
@ -42,6 +43,8 @@ pub enum Expr {
|
|||
Unary {
|
||||
op: UnaryOp,
|
||||
right: Box<Expr>
|
||||
}
|
||||
},
|
||||
|
||||
EOL
|
||||
}
|
||||
|
||||
|
|
|
|||
31
src/main.rs
31
src/main.rs
|
|
@ -2,13 +2,14 @@ use std::{fs::File, io::Read};
|
|||
|
||||
mod token;
|
||||
mod expr;
|
||||
mod stmt;
|
||||
mod lexer;
|
||||
mod error;
|
||||
use lexer::Lexer;
|
||||
mod parser;
|
||||
use parser::Parser;
|
||||
mod eval;
|
||||
use eval::Evaluator;
|
||||
// mod eval;
|
||||
// use eval::Evaluator;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let args = std::env::args().collect::<Vec<String>>();
|
||||
|
|
@ -30,17 +31,23 @@ fn main() -> std::io::Result<()> {
|
|||
println!("\n");
|
||||
|
||||
let mut parser = Parser::new(tokens);
|
||||
loop {
|
||||
let parsed = parser.parse().unwrap_or(expr::Expr::EOL);
|
||||
match parsed {
|
||||
expr::Expr::EOL => break,
|
||||
_ => {
|
||||
println!("AST: {:?}", parsed);
|
||||
let eval = Evaluator::new(parsed);
|
||||
println!("Eval: {:?}", eval.eval());
|
||||
}
|
||||
}
|
||||
let parsed = parser.parse();
|
||||
match parsed {
|
||||
Ok(parsed) => println!("AST: {:?}", parsed),
|
||||
Err(e) => eprintln!("{e}")
|
||||
}
|
||||
|
||||
// loop {
|
||||
// let parsed = parser.parse().unwrap_or(Vec::new());
|
||||
// match parsed {
|
||||
// expr::Expr::EOL => break,
|
||||
// _ => {
|
||||
// println!("AST: {:?}", parsed);
|
||||
// // let eval = Evaluator::new(parsed);
|
||||
// // println!("Eval: {:?}", eval.eval());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
173
src/parser.rs
173
src/parser.rs
|
|
@ -1,5 +1,6 @@
|
|||
use crate::token::Token;
|
||||
use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp};
|
||||
use crate::stmt::{CondOp, Condition, Stmt};
|
||||
use crate::error::ParseError;
|
||||
|
||||
type ParseResult<T> = Result<T, ParseError>;
|
||||
|
|
@ -40,9 +41,19 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_ident(&mut self) -> ParseResult<String> {
|
||||
match self.next() {
|
||||
Some(Token::Ident(ident)) => Ok(ident),
|
||||
other => Err(ParseError::new(format!(
|
||||
"expected identifier, got {other:?}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_atom(&mut self) -> ParseResult<Expr> {
|
||||
match self.next() {
|
||||
Some(Token::Number(n)) => Ok(Expr::Number(n)),
|
||||
Some(Token::StringLit(s)) => Ok(Expr::StringLit(s)),
|
||||
Some(Token::Ident(id)) => Ok(Expr::Ident(id)),
|
||||
Some(Token::LParen) => {
|
||||
let expr = self.parse_expr(0)?;
|
||||
|
|
@ -102,8 +113,164 @@ impl Parser {
|
|||
Ok(lhs)
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> ParseResult<Expr> {
|
||||
if self.peek().is_none() {return Ok(Expr::EOL)}
|
||||
self.parse_expr(0)
|
||||
fn parse_block(&mut self) -> ParseResult<Vec<Stmt>> {
|
||||
self.expect(&Token::LBrace)?;
|
||||
let mut stmts = Vec::new();
|
||||
while !matches!(self.peek(), Some(Token::RBrace) | None) {
|
||||
stmts.push(self.parse_stmt()?);
|
||||
}
|
||||
self.expect(&Token::RBrace)?;
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
fn parse_condition(&mut self) -> ParseResult<Condition> {
|
||||
let op = match self.next() {
|
||||
Some(Token::Eq) => CondOp::Eq,
|
||||
Some(Token::Neq) => CondOp::Neq,
|
||||
Some(Token::Lt) => CondOp::Lt,
|
||||
Some(Token::Gt) => CondOp::Gt,
|
||||
Some(Token::Lte) => CondOp::Lte,
|
||||
Some(Token::Gte) => CondOp::Gte,
|
||||
tok => return Err(ParseError::new(format!(
|
||||
"expected condition operator, got {tok:?}"
|
||||
)))
|
||||
};
|
||||
|
||||
let left = self.parse_expr(0)?;
|
||||
self.expect(&Token::Comma)?;
|
||||
let right = self.parse_expr(0)?;
|
||||
|
||||
Ok(Condition { op, left, right })
|
||||
}
|
||||
|
||||
fn parse_mov(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::Mov)?;
|
||||
let src = self.parse_expr(0)?;
|
||||
self.expect(&Token::Comma)?;
|
||||
let dst = self.expect_ident()?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
Ok(Stmt::Mov { src, dst })
|
||||
}
|
||||
|
||||
fn parse_ifelse(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::If)?;
|
||||
let condition = self.parse_condition()?;
|
||||
let then = if matches!(self.peek(), Some(Token::LBrace)) {
|
||||
self.parse_block()?
|
||||
} else {
|
||||
self.expect(&Token::Comma)?;
|
||||
vec![self.parse_stmt()?]
|
||||
};
|
||||
|
||||
let else_ = if matches!(self.peek(), Some(Token::Else)) {
|
||||
self.advance();
|
||||
Some(if matches!(self.peek(), Some(Token::LBrace)) {
|
||||
self.parse_block()?
|
||||
} else {
|
||||
vec![self.parse_stmt()?]
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Stmt::IfElse { condition, then, else_ })
|
||||
}
|
||||
|
||||
fn parse_loop(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::Loop)?;
|
||||
let body = self.parse_block()?;
|
||||
Ok(Stmt::Loop { body })
|
||||
}
|
||||
|
||||
fn parse_while(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::While)?;
|
||||
let condition = self.parse_condition()?;
|
||||
let body = self.parse_block()?;
|
||||
Ok(Stmt::While { condition, body })
|
||||
}
|
||||
|
||||
fn parse_for(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::For)?;
|
||||
let var = self.expect_ident()?;
|
||||
|
||||
match self.peek() {
|
||||
Some(Token::In) => {
|
||||
self.advance();
|
||||
let list = self.parse_expr(0)?;
|
||||
let body = self.parse_block()?;
|
||||
Ok(Stmt::ForIn { var, list, body })
|
||||
},
|
||||
Some(Token::Comma) => {
|
||||
self.advance();
|
||||
let start = self.parse_expr(0)?;
|
||||
self.expect(&Token::DotDot)?;
|
||||
let end = self.parse_expr(0)?;
|
||||
let step = if matches!(self.peek(), Some(Token::Comma)) {
|
||||
self.advance();
|
||||
Some(self.parse_expr(0)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let body = self.parse_block()?;
|
||||
Ok(Stmt::ForRange { var, start, end, step, body })
|
||||
},
|
||||
tok => Err(ParseError::new(format!(
|
||||
"expected 'in' or ',' after for variable, got {tok:?}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_call(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::Call)?;
|
||||
let name = self.expect_ident()?;
|
||||
let mut args = Vec::new();
|
||||
while matches!(self.peek(), Some(Token::Comma)) {
|
||||
self.advance();
|
||||
args.push(self.parse_expr(0)?);
|
||||
}
|
||||
self.expect(&Token::Semicolon)?;
|
||||
Ok(Stmt::Call { name, args })
|
||||
}
|
||||
|
||||
fn parse_func_def(&mut self) -> ParseResult<Stmt> {
|
||||
self.expect(&Token::Fun)?;
|
||||
let name = self.expect_ident()?;
|
||||
let mut params = Vec::new();
|
||||
while matches!(self.peek(), Some(Token::Comma)) {
|
||||
self.advance();
|
||||
params.push(self.expect_ident()?);
|
||||
}
|
||||
let body = self.parse_block()?;
|
||||
Ok(Stmt::FuncDef { name, params, body })
|
||||
}
|
||||
|
||||
fn parse_stmt(&mut self) -> ParseResult<Stmt> {
|
||||
match self.peek() {
|
||||
Some(Token::Mov) => self.parse_mov(),
|
||||
Some(Token::If) => self.parse_ifelse(),
|
||||
Some(Token::Loop) => self.parse_loop(),
|
||||
Some(Token::While) => self.parse_while(),
|
||||
Some(Token::For) => self.parse_for(),
|
||||
Some(Token::Call) => self.parse_call(),
|
||||
Some(Token::Fun) => self.parse_func_def(),
|
||||
Some(Token::Break) => { self.advance(); self.expect(&Token::Semicolon)?; Ok(Stmt::Break) },
|
||||
Some(Token::Continue) => { self.advance(); self.expect(&Token::Semicolon)?; Ok(Stmt::Continue) },
|
||||
tok => Err(ParseError::new(format!(
|
||||
"expected start of statement, got {tok:?}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> ParseResult<Vec<Stmt>> {
|
||||
let mut stmts = Vec::new();
|
||||
|
||||
while self.peek().is_some() {
|
||||
match self.parse_stmt() {
|
||||
Ok(stmt) => stmts.push(stmt),
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(stmts)
|
||||
}
|
||||
}
|
||||
32
src/stmt.rs
Normal file
32
src/stmt.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use crate::expr::Expr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CondOp {
|
||||
Eq,
|
||||
Neq,
|
||||
Lt,
|
||||
Gt,
|
||||
Lte,
|
||||
Gte
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Condition {
|
||||
pub op: CondOp,
|
||||
pub left: Expr,
|
||||
pub right: Expr
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Stmt {
|
||||
Mov { src: Expr, dst: String },
|
||||
IfElse { condition: Condition, then: Vec<Stmt>, else_: Option<Vec<Stmt>> },
|
||||
Loop { body: Vec<Stmt> },
|
||||
While { condition: Condition, body: Vec<Stmt> },
|
||||
ForRange { var: String, start: Expr, end: Expr, step: Option<Expr>, body: Vec<Stmt> },
|
||||
ForIn { var: String, list: Expr, body: Vec<Stmt> },
|
||||
Call { name: String, args: Vec<Expr> },
|
||||
FuncDef { name: String, params: Vec<String>, body: Vec<Stmt> },
|
||||
Break,
|
||||
Continue
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue