add parser

This commit is contained in:
nora 2021-10-30 18:29:56 +02:00
parent 03fe10d7c0
commit a0e17c6042
4 changed files with 163 additions and 38 deletions

View file

@ -1,84 +1,102 @@
#![allow(dead_code)]
/// imagine interning or something here
pub type Symbol = String;
#[derive(Debug, Clone, PartialEq)]
pub struct Program(pub Block);
#[derive(Debug, Clone, PartialEq)]
pub struct Block(pub Vec<Stmt>); pub struct Block(pub Vec<Stmt>);
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt { pub enum Stmt {
VariableDecl(VariableDecl), Declaration(Declaration),
Assignment(Assignment), Assignment(Assignment),
FnDecl(FnDecl), FnDecl(FnDecl),
If(IfStmt),
Loop(Block),
While(WhileStmt),
Break, Break,
Return(Option<Expr>), Return(Option<Expr>),
Conditional(Conditional),
Loop(Block),
WhileLoop(WhileLoop),
ForLoop(Box<ForLoop>),
Expr(Expr), Expr(Expr),
} }
pub struct VariableDecl { #[derive(Debug, Clone, PartialEq)]
name: String, pub struct Declaration {
init: Option<Expr>, name: Symbol,
init: Expr,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct Assignment { pub struct Assignment {
pub lhs: Expr, pub lhs: Symbol,
pub rhs: Expr, pub rhs: Expr,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct FnDecl { pub struct FnDecl {
pub name: String, pub name: Symbol,
pub params: Vec<String>, pub params: Vec<Symbol>,
pub body: Block, pub body: Block,
} }
pub struct Conditional { #[derive(Debug, Clone, PartialEq)]
pub struct IfStmt {
pub condition: Expr, pub condition: Expr,
pub body: Block, pub body: Block,
pub else_block: Option<Block>, pub else_part: Box<ElsePart>,
} }
pub struct WhileLoop { #[derive(Debug, Clone, PartialEq)]
pub enum ElsePart {
Else(Block),
ElseIf(IfStmt),
}
#[derive(Debug, Clone, PartialEq)]
pub struct WhileStmt {
pub cond: Expr, pub cond: Expr,
pub body: Block, pub body: Block,
} }
pub struct ForLoop { #[derive(Debug, Clone, PartialEq)]
pub init: Stmt,
pub cond: Expr,
pub post: Stmt,
pub body: Block,
}
pub enum Expr { pub enum Expr {
Literal(Literal), Literal(Literal),
UnaryOp, UnaryOp,
BinaryOp, BinaryOp,
Call,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum Literal { pub enum Literal {
String(String), String(String),
Number(f64), Number(f64),
Array(Vec<Expr>), Array(Vec<Expr>),
Object, // todo Object,
Boolean(bool), Boolean(bool),
Null, Null,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct UnaryOp { pub struct UnaryOp {
pub expr: Expr, pub expr: Expr,
pub kind: UnaryOpKind, pub kind: UnaryOpKind,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum UnaryOpKind { pub enum UnaryOpKind {
Not, Not,
Neg, Neg,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct BinaryOp { pub struct BinaryOp {
pub lhs: Expr, pub lhs: Expr,
pub rhs: Expr, pub rhs: Expr,
pub kind: BinaryOpKind, pub kind: BinaryOpKind,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum BinaryOpKind { pub enum BinaryOpKind {
And, And,
Or, Or,
@ -95,6 +113,7 @@ pub enum BinaryOpKind {
Mod, Mod,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum Call { pub enum Call {
Function(Expr, Vec<Expr>), Function(Expr, Vec<Expr>),
Field(Expr, Vec<Expr>), Field(Expr, Vec<Expr>),

View file

@ -48,6 +48,8 @@ pub enum TokenType<'code> {
// ident // ident
Ident(&'code str), Ident(&'code str),
// punctuation // punctuation
/// ;
Semi,
/// + /// +
Plus, Plus,
/// - /// -

View file

@ -8,19 +8,23 @@ pub fn run_program(program: &str) {
let lexer = lex::Lexer::lex(program); let lexer = lex::Lexer::lex(program);
let (success, errors) = lexer.partition::<Vec<_>, _>(|result| result.is_ok()); let (success, errors) = lexer.partition::<Vec<_>, _>(|result| result.is_ok());
if errors.is_empty() { // terrible, but works
println!( let tokens = success.into_iter().collect::<Result<_, _>>();
"{:#?}", let _ast = parse::parse(tokens.unwrap());
success
.into_iter() // if errors.is_empty() {
.map(Result::unwrap) // println!(
.map(|token| token.kind) // "{:#?}",
.collect::<Vec<_>>() // success
); // .into_iter()
} else { // .map(Result::unwrap)
errors // .map(|token| token.kind)
.into_iter() // .collect::<Vec<_>>()
.map(Result::unwrap_err) // );
.for_each(|err| crate::errors::display_error(program, err)); // } else {
} // errors
// .into_iter()
// .map(Result::unwrap_err)
// .for_each(|err| crate::errors::display_error(program, err));
// }
} }

View file

@ -0,0 +1,100 @@
#![allow(dead_code)]
use crate::ast::*;
use crate::lex::{Token, TokenType};
use std::iter::Peekable;
pub fn parse(tokens: Vec<Token>) -> Result<Program, ParseErr> {
let mut parser = Parser {
tokens: tokens.into_iter().peekable(),
};
let program = parser.program()?;
Ok(program)
}
#[derive(Debug)]
struct Parser<'code> {
tokens: Peekable<std::vec::IntoIter<Token<'code>>>,
}
type ParseResult<'code, T> = Result<T, ParseErr<'code>>;
impl<'code> Parser<'code> {
fn program(&mut self) -> ParseResult<'code, Program> {
Ok(Program(self.block()?))
}
fn block(&mut self) -> ParseResult<'code, Block> {
let mut stmts = Vec::new();
loop {
if let Some(Token {
kind: TokenType::BraceC,
..
}) = self.peek()
{
let _ = self.next();
return Ok(Block(stmts));
}
let stmt = self.statement()?;
stmts.push(stmt);
}
}
fn statement(&mut self) -> ParseResult<'code, Stmt> {
let expr = self.expression()?;
self.expect(TokenType::Semi);
Ok(Stmt::Expr(expr))
}
fn declaration(&mut self) -> ParseResult<'code, Declaration> {
todo!()
}
fn assignment(&mut self) -> ParseResult<'code, Assignment> {
todo!()
}
fn fn_decl(&mut self) -> ParseResult<'code, FnDecl> {
todo!()
}
fn if_stmt(&mut self) -> ParseResult<'code, IfStmt> {
todo!()
}
fn loop_stmt(&mut self) -> ParseResult<'code, Block> {
todo!()
}
fn expression(&mut self) -> ParseResult<'code, Expr> {
todo!()
}
// helpers
fn next(&mut self) -> Option<Token<'code>> {
self.tokens.next()
}
fn peek(&mut self) -> Option<&Token<'code>> {
self.tokens.peek()
}
fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, ()> {
if let Some(token) = self.next() {
if token.kind == kind {
Ok(())
} else {
Err(ParseErr::MismatchedKind { expected: kind })
}
} else {
Err(ParseErr::UnexpectedEOF { expected: kind })
}
}
}
#[derive(Debug)]
pub enum ParseErr<'code> {
MismatchedKind { expected: TokenType<'code> },
UnexpectedEOF { expected: TokenType<'code> },
}