mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-14 17:35:03 +01:00
bump alloc
This commit is contained in:
parent
9019dc0295
commit
e26e849b56
9 changed files with 302 additions and 225 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -8,6 +8,12 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
|
|
@ -25,6 +31,7 @@ dependencies = [
|
||||||
name = "dilaria"
|
name = "dilaria"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
"insta",
|
"insta",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bumpalo = { version = "3.8.0", features = ["collections", "boxed"] }
|
||||||
rustc-hash = { version = "1.1.0", optional = true }
|
rustc-hash = { version = "1.1.0", optional = true }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
10
clippy.toml
10
clippy.toml
|
|
@ -1,2 +1,8 @@
|
||||||
# we want to use our custom type from `values.rs`, so that consumers can choose between which HashMap they want
|
disallowed-types = [
|
||||||
disallowed-types = ["std::collections::HashMap", "std::collections::HashSet"]
|
# we want to use our custom HashMap/HashSet from `values.rs`, so that consumers can choose between which HashMap they want
|
||||||
|
"std::collections::HashMap",
|
||||||
|
"std::collections::HashSet",
|
||||||
|
# we want to use bumpalo::collections::Vec, this can be removed later I guess
|
||||||
|
"std::collections::Vec",
|
||||||
|
"std::boxed::Box",
|
||||||
|
]
|
||||||
|
|
|
||||||
142
src/ast.rs
142
src/ast.rs
|
|
@ -3,74 +3,76 @@
|
||||||
|
|
||||||
use crate::errors::Span;
|
use crate::errors::Span;
|
||||||
use crate::value::Symbol;
|
use crate::value::Symbol;
|
||||||
|
use bumpalo::boxed::Box;
|
||||||
|
use bumpalo::collections::Vec;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Ident {
|
pub struct Ident {
|
||||||
pub sym: Symbol,
|
pub sym: Symbol,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Program(pub Vec<Stmt>);
|
pub struct Program<'ast>(pub Vec<'ast, Stmt<'ast>>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Block {
|
pub struct Block<'ast> {
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<'ast, Stmt<'ast>>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Stmt {
|
pub enum Stmt<'ast> {
|
||||||
Declaration(Declaration),
|
Declaration(Declaration<'ast>),
|
||||||
Assignment(Assignment),
|
Assignment(Assignment<'ast>),
|
||||||
FnDecl(FnDecl),
|
FnDecl(FnDecl<'ast>),
|
||||||
If(IfStmt),
|
If(IfStmt<'ast>),
|
||||||
Loop(Block, Span),
|
Loop(Block<'ast>, Span),
|
||||||
While(WhileStmt),
|
While(WhileStmt<'ast>),
|
||||||
Break(Span),
|
Break(Span),
|
||||||
Return(Option<Expr>, Span),
|
Return(Option<Expr<'ast>>, Span),
|
||||||
Block(Block),
|
Block(Block<'ast>),
|
||||||
Expr(Expr),
|
Expr(Expr<'ast>),
|
||||||
Print(Expr, Span),
|
Print(Expr<'ast>, Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Declaration {
|
pub struct Declaration<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub init: Expr,
|
pub init: Expr<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Assignment {
|
pub struct Assignment<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub lhs: Expr,
|
pub lhs: Expr<'ast>,
|
||||||
pub rhs: Expr,
|
pub rhs: Expr<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct FnDecl {
|
pub struct FnDecl<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub params: Vec<Ident>,
|
pub params: Vec<'ast, Ident>,
|
||||||
pub body: Block,
|
pub body: Block<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct IfStmt {
|
pub struct IfStmt<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub cond: Expr,
|
pub cond: Expr<'ast>,
|
||||||
pub body: Block,
|
pub body: Block<'ast>,
|
||||||
pub else_part: Option<Box<ElsePart>>,
|
pub else_part: Option<Box<'ast, ElsePart<'ast>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ElsePart {
|
pub enum ElsePart<'ast> {
|
||||||
Else(Block, Span),
|
Else(Block<'ast>, Span),
|
||||||
ElseIf(IfStmt, Span),
|
ElseIf(IfStmt<'ast>, Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElsePart {
|
impl ElsePart<'_> {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
ElsePart::Else(_, span) => *span,
|
ElsePart::Else(_, span) => *span,
|
||||||
|
|
@ -79,23 +81,23 @@ impl ElsePart {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct WhileStmt {
|
pub struct WhileStmt<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub cond: Expr,
|
pub cond: Expr<'ast>,
|
||||||
pub body: Block,
|
pub body: Block<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr<'ast> {
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
Literal(Literal),
|
Literal(Literal<'ast>),
|
||||||
UnaryOp(Box<UnaryOp>),
|
UnaryOp(Box<'ast, UnaryOp<'ast>>),
|
||||||
BinaryOp(Box<BinaryOp>),
|
BinaryOp(Box<'ast, BinaryOp<'ast>>),
|
||||||
Call(Box<Call>),
|
Call(Box<'ast, Call<'ast>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr<'_> {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Expr::Literal(lit) => lit.span(),
|
Expr::Literal(lit) => lit.span(),
|
||||||
|
|
@ -107,17 +109,17 @@ impl Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Literal {
|
pub enum Literal<'ast> {
|
||||||
String(String, Span),
|
String(String, Span),
|
||||||
Number(f64, Span),
|
Number(f64, Span),
|
||||||
Array(Vec<Expr>, Span),
|
Array(Vec<'ast, Expr<'ast>>, Span),
|
||||||
Object(Span),
|
Object(Span),
|
||||||
Boolean(bool, Span),
|
Boolean(bool, Span),
|
||||||
Null(Span),
|
Null(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Literal {
|
impl Literal<'_> {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Literal::String(_, span) => *span,
|
Literal::String(_, span) => *span,
|
||||||
|
|
@ -130,28 +132,28 @@ impl Literal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct UnaryOp {
|
pub struct UnaryOp<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub expr: Expr,
|
pub expr: Expr<'ast>,
|
||||||
pub kind: UnaryOpKind,
|
pub kind: UnaryOpKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum UnaryOpKind {
|
pub enum UnaryOpKind {
|
||||||
Not,
|
Not,
|
||||||
Neg,
|
Neg,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct BinaryOp {
|
pub struct BinaryOp<'ast> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub lhs: Expr,
|
pub lhs: Expr<'ast>,
|
||||||
pub rhs: Expr,
|
pub rhs: Expr<'ast>,
|
||||||
pub kind: BinaryOpKind,
|
pub kind: BinaryOpKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum BinaryOpKind {
|
pub enum BinaryOpKind {
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
|
|
@ -168,15 +170,15 @@ pub enum BinaryOpKind {
|
||||||
Mod,
|
Mod,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Call {
|
pub struct Call<'ast> {
|
||||||
pub callee: Expr,
|
pub callee: Expr<'ast>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub kind: CallKind,
|
pub kind: CallKind<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum CallKind {
|
pub enum CallKind<'ast> {
|
||||||
Field(Ident),
|
Field(Ident),
|
||||||
Fn(Vec<Expr>),
|
Fn(Vec<'ast, Expr<'ast>>),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,26 @@
|
||||||
use crate::errors::Span;
|
use crate::errors::Span;
|
||||||
use crate::value::{HashMap, Symbol};
|
use crate::value::{HashMap, Symbol};
|
||||||
|
use bumpalo::boxed::Box;
|
||||||
|
use bumpalo::collections::Vec;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct FnBlock {
|
pub struct FnBlock<'bc> {
|
||||||
pub code: Vec<Instr>,
|
pub code: Vec<'bc, Instr<'bc>>,
|
||||||
pub stack_sizes: Vec<usize>,
|
pub stack_sizes: Vec<'bc, usize>,
|
||||||
pub spans: Vec<Span>,
|
pub spans: Vec<'bc, Span>,
|
||||||
pub arity: u8,
|
pub arity: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: this should be copy in the end tbh
|
// todo: this should be copy in the end tbh
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Instr {
|
pub enum Instr<'bc> {
|
||||||
/// Store the current value on the stack to the stack location with the local offset `usize`
|
/// Store the current value on the stack to the stack location with the local offset `usize`
|
||||||
Store(usize),
|
Store(usize),
|
||||||
/// Load the variable value from the local offset `usize` onto the stack
|
/// Load the variable value from the local offset `usize` onto the stack
|
||||||
Load(usize),
|
Load(usize),
|
||||||
/// Push a value onto the stack
|
/// Push a value onto the stack
|
||||||
PushVal(Box<Value>),
|
PushVal(Box<'bc, Value>),
|
||||||
/// Negate the top value on the stack. Only works with numbers and booleans
|
/// Negate the top value on the stack. Only works with numbers and booleans
|
||||||
Neg,
|
Neg,
|
||||||
BinAdd,
|
BinAdd,
|
||||||
|
|
@ -45,6 +47,6 @@ pub enum Value {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Num(f64),
|
Num(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
Array(Vec<Value>),
|
Array,
|
||||||
Object(HashMap<Symbol, Value>),
|
Object(HashMap<Symbol, Value>),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ use crate::ast::{
|
||||||
use crate::bytecode::{FnBlock, Instr, Value};
|
use crate::bytecode::{FnBlock, Instr, Value};
|
||||||
use crate::errors::{CompilerError, Span};
|
use crate::errors::{CompilerError, Span};
|
||||||
use crate::value::{HashMap, Symbol};
|
use crate::value::{HashMap, Symbol};
|
||||||
|
use bumpalo::boxed::Box;
|
||||||
|
use bumpalo::collections::Vec;
|
||||||
|
use bumpalo::Bump;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
@ -39,25 +42,39 @@ impl Env {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
struct Compiler {
|
struct Compiler<'bc> {
|
||||||
blocks: Vec<FnBlock>,
|
blocks: Vec<'bc, FnBlock<'bc>>,
|
||||||
current_block: usize,
|
current_block: usize,
|
||||||
|
bump: &'bc Bump,
|
||||||
/// the current local variables that are in scope, only needed for compiling
|
/// the current local variables that are in scope, only needed for compiling
|
||||||
env: Rc<RefCell<Env>>,
|
env: Rc<RefCell<Env>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(ast: &Program) -> Result<Vec<FnBlock>, CompileError> {
|
pub fn compile<'bc>(
|
||||||
let mut compiler = Compiler::default();
|
ast: &Program,
|
||||||
|
bytecode_bump: &'bc Bump,
|
||||||
|
) -> Result<Vec<'bc, FnBlock<'bc>>, CompileError> {
|
||||||
|
let mut compiler = Compiler {
|
||||||
|
blocks: Vec::new_in(bytecode_bump),
|
||||||
|
current_block: 0,
|
||||||
|
bump: bytecode_bump,
|
||||||
|
env: Rc::new(RefCell::new(Default::default())),
|
||||||
|
};
|
||||||
|
|
||||||
compiler.compile(ast)?;
|
compiler.compile(ast)?;
|
||||||
|
|
||||||
Ok(compiler.blocks)
|
Ok(compiler.blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compiler {
|
impl<'bc> Compiler<'bc> {
|
||||||
fn compile(&mut self, ast: &Program) -> CResult<()> {
|
fn compile(&mut self, ast: &Program) -> CResult<()> {
|
||||||
let global_block = FnBlock::default();
|
let global_block = FnBlock {
|
||||||
|
code: Vec::new_in(self.bump),
|
||||||
|
stack_sizes: Vec::new_in(self.bump),
|
||||||
|
spans: Vec::new_in(self.bump),
|
||||||
|
arity: 0,
|
||||||
|
};
|
||||||
self.blocks.push(global_block);
|
self.blocks.push(global_block);
|
||||||
self.current_block = self.blocks.len() - 1;
|
self.current_block = self.blocks.len() - 1;
|
||||||
self.compile_stmts(&ast.0)?;
|
self.compile_stmts(&ast.0)?;
|
||||||
|
|
@ -180,7 +197,7 @@ impl Compiler {
|
||||||
Literal::Number(num, _) => Value::Num(*num),
|
Literal::Number(num, _) => Value::Num(*num),
|
||||||
Literal::Array(vec, _) => {
|
Literal::Array(vec, _) => {
|
||||||
if vec.is_empty() {
|
if vec.is_empty() {
|
||||||
Value::Array(Vec::new())
|
Value::Array
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +208,7 @@ impl Compiler {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.push_instr(
|
self.push_instr(
|
||||||
Instr::PushVal(Box::new(value)),
|
Instr::PushVal(Box::new_in(value, self.bump)),
|
||||||
StackChange::Grow,
|
StackChange::Grow,
|
||||||
lit.span(),
|
lit.span(),
|
||||||
);
|
);
|
||||||
|
|
@ -244,7 +261,7 @@ impl Compiler {
|
||||||
*block.stack_sizes.last().expect("empty stack") - 1
|
*block.stack_sizes.last().expect("empty stack") - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_instr(&mut self, instr: Instr, stack_change: StackChange, span: Span) {
|
fn push_instr(&mut self, instr: Instr<'bc>, stack_change: StackChange, span: Span) {
|
||||||
let block = &mut self.blocks[self.current_block];
|
let block = &mut self.blocks[self.current_block];
|
||||||
let stack_top = block.stack_sizes.last().copied().unwrap_or(0);
|
let stack_top = block.stack_sizes.last().copied().unwrap_or(0);
|
||||||
let new_stack_top = stack_top as isize + stack_change as isize;
|
let new_stack_top = stack_top as isize + stack_change as isize;
|
||||||
|
|
@ -299,6 +316,5 @@ impl CompilerError for CompileError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {}
|
mod test {}
|
||||||
|
|
|
||||||
|
|
@ -355,7 +355,7 @@ fn is_valid_ident_start(char: char) -> bool {
|
||||||
char.is_alphabetic() || char == '_'
|
char.is_alphabetic() || char == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LexError {
|
pub struct LexError {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub kind: LexErrorKind,
|
pub kind: LexErrorKind,
|
||||||
|
|
@ -399,7 +399,7 @@ impl CompilerError for LexError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LexErrorKind {
|
pub enum LexErrorKind {
|
||||||
InvalidCharacter(char),
|
InvalidCharacter(char),
|
||||||
InvalidFloat(std::num::ParseFloatError),
|
InvalidFloat(std::num::ParseFloatError),
|
||||||
|
|
|
||||||
47
src/lib.rs
47
src/lib.rs
|
|
@ -8,40 +8,33 @@ mod lex;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
|
use crate::ast::Program;
|
||||||
|
use bumpalo::Bump;
|
||||||
pub use lex::*;
|
pub use lex::*;
|
||||||
pub use parse::*;
|
pub use parse::*;
|
||||||
|
|
||||||
pub fn run_program(program: &str) {
|
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());
|
|
||||||
|
|
||||||
if errors.is_empty() {
|
let ast_alloc = Bump::new();
|
||||||
let tokens = success.into_iter().collect::<Result<Vec<_>, _>>().unwrap();
|
|
||||||
|
|
||||||
println!(
|
let ast = parse::parse(lexer, &ast_alloc);
|
||||||
"Tokens:\n{:?}\n",
|
|
||||||
tokens.iter().map(|token| &token.kind).collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
|
|
||||||
let ast = parse::parse(tokens);
|
match ast {
|
||||||
|
Ok(ast) => process_ast(program, ast),
|
||||||
match ast {
|
Err(err) => errors::display_error(program, err),
|
||||||
Ok(ast) => {
|
}
|
||||||
println!("AST:\n{:?}\n", ast);
|
}
|
||||||
|
|
||||||
let bytecode = compile::compile(&ast);
|
fn process_ast(program: &str, ast: Program) {
|
||||||
|
println!("AST:\n{:?}\n", ast);
|
||||||
match bytecode {
|
|
||||||
Ok(code) => println!("Bytecode:\n{:#?}\n", code),
|
let bytecode_alloc = Bump::new();
|
||||||
Err(err) => errors::display_error(program, err),
|
|
||||||
}
|
let bytecode = compile::compile(&ast, &bytecode_alloc);
|
||||||
}
|
|
||||||
Err(err) => errors::display_error(program, err),
|
match bytecode {
|
||||||
}
|
Ok(code) => println!("Bytecode:\n{:#?}\n", code),
|
||||||
} else {
|
Err(err) => errors::display_error(program, err),
|
||||||
errors
|
|
||||||
.into_iter()
|
|
||||||
.map(Result::unwrap_err)
|
|
||||||
.for_each(|err| errors::display_error(program, err));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
258
src/parse.rs
258
src/parse.rs
|
|
@ -4,25 +4,38 @@ mod test;
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::errors::{CompilerError, Span};
|
use crate::errors::{CompilerError, Span};
|
||||||
use crate::lex::{Token, TokenType};
|
use crate::lex::{Token, TokenType};
|
||||||
|
use crate::LexError;
|
||||||
|
use bumpalo::boxed::Box;
|
||||||
|
use bumpalo::collections::Vec;
|
||||||
|
use bumpalo::Bump;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
pub fn parse(tokens: Vec<Token>) -> Result<Program, ParseErr> {
|
|
||||||
let mut parser = Parser {
|
|
||||||
tokens: tokens.into_iter().peekable(),
|
|
||||||
depth: 0,
|
|
||||||
inside_fn_depth: 0,
|
|
||||||
inside_loop_depth: 0,
|
|
||||||
};
|
|
||||||
let program = parser.program()?;
|
|
||||||
Ok(program)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Parser<'code> {
|
struct Parser<'code, 'ast, I>
|
||||||
tokens: Peekable<std::vec::IntoIter<Token<'code>>>,
|
where
|
||||||
|
I: Iterator<Item = Result<Token<'code>, LexError>>,
|
||||||
|
I: 'code,
|
||||||
|
{
|
||||||
|
tokens: Peekable<I>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
inside_fn_depth: usize,
|
inside_fn_depth: usize,
|
||||||
inside_loop_depth: usize,
|
inside_loop_depth: usize,
|
||||||
|
bump: &'ast Bump,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse<'ast, 'code>(
|
||||||
|
tokens: impl Iterator<Item = Result<Token<'code>, LexError>> + 'code,
|
||||||
|
ast_bump: &'ast Bump,
|
||||||
|
) -> Result<Program<'ast>, ParseErr<'code>> {
|
||||||
|
let mut parser = Parser {
|
||||||
|
tokens: tokens.peekable(),
|
||||||
|
depth: 0,
|
||||||
|
inside_fn_depth: 0,
|
||||||
|
inside_loop_depth: 0,
|
||||||
|
bump: ast_bump,
|
||||||
|
};
|
||||||
|
let program = parser.program()?;
|
||||||
|
Ok(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParseResult<'code, T> = Result<T, ParseErr<'code>>;
|
type ParseResult<'code, T> = Result<T, ParseErr<'code>>;
|
||||||
|
|
@ -31,12 +44,15 @@ macro_rules! parse_bin_op {
|
||||||
($self: ident, $lhs: ident, $kind: expr, $function: ident) => {{
|
($self: ident, $lhs: ident, $kind: expr, $function: ident) => {{
|
||||||
let _ = $self.next();
|
let _ = $self.next();
|
||||||
let rhs = $self.$function()?;
|
let rhs = $self.$function()?;
|
||||||
Ok(Expr::BinaryOp(Box::new(BinaryOp {
|
Ok(Expr::BinaryOp(Box::new_in(
|
||||||
span: $lhs.span().extend(rhs.span()),
|
BinaryOp {
|
||||||
lhs: $lhs,
|
span: $lhs.span().extend(rhs.span()),
|
||||||
rhs,
|
lhs: $lhs,
|
||||||
kind: $kind,
|
rhs,
|
||||||
})))
|
kind: $kind,
|
||||||
|
},
|
||||||
|
$self.bump,
|
||||||
|
)))
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,26 +72,30 @@ macro_rules! enter_parse {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'code> Parser<'code> {
|
impl<'code, 'ast, I> Parser<'code, 'ast, I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Result<Token<'code>, LexError>>,
|
||||||
|
I: 'code,
|
||||||
|
{
|
||||||
const MAX_DEPTH: usize = 100;
|
const MAX_DEPTH: usize = 100;
|
||||||
|
|
||||||
fn program(&mut self) -> ParseResult<'code, Program> {
|
fn program(&mut self) -> ParseResult<'code, Program<'ast>> {
|
||||||
Ok(Program(self.statement_list()?))
|
Ok(Program(self.statement_list()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn too_nested_error(&mut self) -> ParseResult<'code, ()> {
|
fn too_nested_error(&mut self) -> ParseResult<'code, ()> {
|
||||||
let next_token = self.next();
|
let next_token = self.next()?;
|
||||||
match next_token {
|
match next_token {
|
||||||
Some(token) => Err(ParseErr::MaxDepth(token.span)),
|
Some(token) => Err(ParseErr::MaxDepth(token.span)),
|
||||||
None => Err(ParseErr::Eof("reached EOF while being nested to deeply")),
|
None => Err(ParseErr::Eof("reached EOF while being nested to deeply")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement_list(&mut self) -> ParseResult<'code, Vec<Stmt>> {
|
fn statement_list(&mut self) -> ParseResult<'code, Vec<'ast, Stmt<'ast>>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new_in(self.bump);
|
||||||
let return_stmts = loop {
|
let return_stmts = loop {
|
||||||
if let Some(TokenType::BraceC) | None = self.peek_kind() {
|
if let Some(TokenType::BraceC) | None = self.peek_kind()? {
|
||||||
break Ok(stmts);
|
break Ok(stmts);
|
||||||
}
|
}
|
||||||
let stmt = self.statement()?;
|
let stmt = self.statement()?;
|
||||||
|
|
@ -85,7 +105,7 @@ impl<'code> Parser<'code> {
|
||||||
return_stmts
|
return_stmts
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&mut self) -> ParseResult<'code, Block> {
|
fn block(&mut self) -> ParseResult<'code, Block<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let start_span = self.expect(TokenType::BraceO)?.span;
|
let start_span = self.expect(TokenType::BraceO)?.span;
|
||||||
|
|
@ -100,10 +120,10 @@ impl<'code> Parser<'code> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement(&mut self) -> ParseResult<'code, Stmt> {
|
fn statement(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let stmt = match *self.peek_kind().ok_or(ParseErr::Eof("statement"))? {
|
let stmt = match *self.peek_kind()?.ok_or(ParseErr::Eof("statement"))? {
|
||||||
TokenType::Let => self.declaration(),
|
TokenType::Let => self.declaration(),
|
||||||
TokenType::Fn => self.fn_decl(),
|
TokenType::Fn => self.fn_decl(),
|
||||||
TokenType::If => Ok(Stmt::If(self.if_stmt()?)),
|
TokenType::If => Ok(Stmt::If(self.if_stmt()?)),
|
||||||
|
|
@ -122,7 +142,7 @@ impl<'code> Parser<'code> {
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declaration(&mut self) -> ParseResult<'code, Stmt> {
|
fn declaration(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::Let)?.span;
|
let keyword_span = self.expect(TokenType::Let)?.span;
|
||||||
|
|
@ -140,7 +160,7 @@ impl<'code> Parser<'code> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_decl(&mut self) -> ParseResult<'code, Stmt> {
|
fn fn_decl(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::Fn)?.span;
|
let keyword_span = self.expect(TokenType::Fn)?.span;
|
||||||
|
|
@ -161,7 +181,7 @@ impl<'code> Parser<'code> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_args(&mut self) -> ParseResult<'code, Vec<Ident>> {
|
fn fn_args(&mut self) -> ParseResult<'code, Vec<'ast, Ident>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
self.expect(TokenType::ParenO)?;
|
self.expect(TokenType::ParenO)?;
|
||||||
|
|
@ -173,14 +193,14 @@ impl<'code> Parser<'code> {
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn if_stmt(&mut self) -> ParseResult<'code, IfStmt> {
|
fn if_stmt(&mut self) -> ParseResult<'code, IfStmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::If)?.span;
|
let keyword_span = self.expect(TokenType::If)?.span;
|
||||||
let cond = self.expression()?;
|
let cond = self.expression()?;
|
||||||
let body = self.block()?;
|
let body = self.block()?;
|
||||||
|
|
||||||
let else_part = if let Some(TokenType::Else) = self.peek_kind() {
|
let else_part = if let Some(TokenType::Else) = self.peek_kind()? {
|
||||||
Some(self.else_part()?)
|
Some(self.else_part()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -194,16 +214,16 @@ impl<'code> Parser<'code> {
|
||||||
.option_extend(else_part.as_ref().map(|part| part.span())),
|
.option_extend(else_part.as_ref().map(|part| part.span())),
|
||||||
cond,
|
cond,
|
||||||
body,
|
body,
|
||||||
else_part: else_part.map(Box::new),
|
else_part: else_part.map(|part| Box::new_in(part, self.bump)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn else_part(&mut self) -> ParseResult<'code, ElsePart> {
|
fn else_part(&mut self) -> ParseResult<'code, ElsePart<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::Else)?.span;
|
let keyword_span = self.expect(TokenType::Else)?.span;
|
||||||
|
|
||||||
let else_part = if let Some(TokenType::If) = self.peek_kind() {
|
let else_part = if let Some(TokenType::If) = self.peek_kind()? {
|
||||||
let else_if_stmt = self.if_stmt()?;
|
let else_if_stmt = self.if_stmt()?;
|
||||||
let else_span = keyword_span.extend(else_if_stmt.span);
|
let else_span = keyword_span.extend(else_if_stmt.span);
|
||||||
Ok(ElsePart::ElseIf(else_if_stmt, else_span))
|
Ok(ElsePart::ElseIf(else_if_stmt, else_span))
|
||||||
|
|
@ -218,7 +238,7 @@ impl<'code> Parser<'code> {
|
||||||
else_part
|
else_part
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loop_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
fn loop_stmt(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::Loop)?.span;
|
let keyword_span = self.expect(TokenType::Loop)?.span;
|
||||||
|
|
@ -234,7 +254,7 @@ impl<'code> Parser<'code> {
|
||||||
Ok(Stmt::Loop(block, keyword_span.extend(loop_span)))
|
Ok(Stmt::Loop(block, keyword_span.extend(loop_span)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn while_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
fn while_stmt(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::While)?.span;
|
let keyword_span = self.expect(TokenType::While)?.span;
|
||||||
|
|
@ -253,7 +273,7 @@ impl<'code> Parser<'code> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn break_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
fn break_stmt(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::Break)?.span;
|
let keyword_span = self.expect(TokenType::Break)?.span;
|
||||||
|
|
@ -268,12 +288,12 @@ impl<'code> Parser<'code> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
fn return_stmt(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let keyword_span = self.expect(TokenType::Return)?.span;
|
let keyword_span = self.expect(TokenType::Return)?.span;
|
||||||
|
|
||||||
let expr = if let Some(TokenType::Semi) = self.peek_kind() {
|
let expr = if let Some(TokenType::Semi) = self.peek_kind()? {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.expression()?)
|
Some(self.expression()?)
|
||||||
|
|
@ -292,7 +312,7 @@ impl<'code> Parser<'code> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
fn print_stmt(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let print_span = self.expect(TokenType::Print)?.span;
|
let print_span = self.expect(TokenType::Print)?.span;
|
||||||
|
|
@ -306,12 +326,12 @@ impl<'code> Parser<'code> {
|
||||||
Ok(Stmt::Print(expr, print_span.extend(semi_span)))
|
Ok(Stmt::Print(expr, print_span.extend(semi_span)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assignment(&mut self) -> ParseResult<'code, Stmt> {
|
fn assignment(&mut self) -> ParseResult<'code, Stmt<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
|
|
||||||
let stmt = if let Some(TokenType::Equal) = self.peek_kind() {
|
let stmt = if let Some(TokenType::Equal) = self.peek_kind()? {
|
||||||
let _ = self.expect(TokenType::Equal)?;
|
let _ = self.expect(TokenType::Equal)?;
|
||||||
let init = self.expression()?;
|
let init = self.expression()?;
|
||||||
let semi_span = self.expect(TokenType::Semi)?.span;
|
let semi_span = self.expect(TokenType::Semi)?.span;
|
||||||
|
|
@ -329,18 +349,18 @@ impl<'code> Parser<'code> {
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> ParseResult<'code, Expr> {
|
fn expression(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
let return_expr = self.logical_or();
|
let return_expr = self.logical_or();
|
||||||
exit_parse!(self);
|
exit_parse!(self);
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logical_or(&mut self) -> ParseResult<'code, Expr> {
|
fn logical_or(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let lhs = self.logical_and()?;
|
let lhs = self.logical_and()?;
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::Or) => parse_bin_op!(self, lhs, BinaryOpKind::Or, logical_or),
|
Some(TokenType::Or) => parse_bin_op!(self, lhs, BinaryOpKind::Or, logical_or),
|
||||||
_ => Ok(lhs),
|
_ => Ok(lhs),
|
||||||
};
|
};
|
||||||
|
|
@ -349,11 +369,11 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logical_and(&mut self) -> ParseResult<'code, Expr> {
|
fn logical_and(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let lhs = self.equality()?;
|
let lhs = self.equality()?;
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::And) => parse_bin_op!(self, lhs, BinaryOpKind::And, logical_and),
|
Some(TokenType::And) => parse_bin_op!(self, lhs, BinaryOpKind::And, logical_and),
|
||||||
_ => Ok(lhs),
|
_ => Ok(lhs),
|
||||||
};
|
};
|
||||||
|
|
@ -362,11 +382,11 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equality(&mut self) -> ParseResult<'code, Expr> {
|
fn equality(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let lhs = self.comparison()?;
|
let lhs = self.comparison()?;
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::BangEqual) => {
|
Some(TokenType::BangEqual) => {
|
||||||
parse_bin_op!(self, lhs, BinaryOpKind::NotEqual, comparison)
|
parse_bin_op!(self, lhs, BinaryOpKind::NotEqual, comparison)
|
||||||
}
|
}
|
||||||
|
|
@ -379,11 +399,11 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comparison(&mut self) -> ParseResult<'code, Expr> {
|
fn comparison(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let lhs = self.term()?;
|
let lhs = self.term()?;
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::Greater) => parse_bin_op!(self, lhs, BinaryOpKind::Greater, term),
|
Some(TokenType::Greater) => parse_bin_op!(self, lhs, BinaryOpKind::Greater, term),
|
||||||
Some(TokenType::GreaterEqual) => {
|
Some(TokenType::GreaterEqual) => {
|
||||||
parse_bin_op!(self, lhs, BinaryOpKind::GreaterEqual, term)
|
parse_bin_op!(self, lhs, BinaryOpKind::GreaterEqual, term)
|
||||||
|
|
@ -398,11 +418,11 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term(&mut self) -> ParseResult<'code, Expr> {
|
fn term(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let lhs = self.factor()?;
|
let lhs = self.factor()?;
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::Plus) => parse_bin_op!(self, lhs, BinaryOpKind::Add, term),
|
Some(TokenType::Plus) => parse_bin_op!(self, lhs, BinaryOpKind::Add, term),
|
||||||
Some(TokenType::Minus) => parse_bin_op!(self, lhs, BinaryOpKind::Sub, term),
|
Some(TokenType::Minus) => parse_bin_op!(self, lhs, BinaryOpKind::Sub, term),
|
||||||
_ => Ok(lhs),
|
_ => Ok(lhs),
|
||||||
|
|
@ -411,11 +431,11 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn factor(&mut self) -> ParseResult<'code, Expr> {
|
fn factor(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let lhs = self.unary()?;
|
let lhs = self.unary()?;
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::Asterisk) => parse_bin_op!(self, lhs, BinaryOpKind::Mul, factor),
|
Some(TokenType::Asterisk) => parse_bin_op!(self, lhs, BinaryOpKind::Mul, factor),
|
||||||
Some(TokenType::Slash) => parse_bin_op!(self, lhs, BinaryOpKind::Div, factor),
|
Some(TokenType::Slash) => parse_bin_op!(self, lhs, BinaryOpKind::Div, factor),
|
||||||
Some(TokenType::Percent) => parse_bin_op!(self, lhs, BinaryOpKind::Mod, factor),
|
Some(TokenType::Percent) => parse_bin_op!(self, lhs, BinaryOpKind::Mod, factor),
|
||||||
|
|
@ -425,27 +445,33 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(&mut self) -> ParseResult<'code, Expr> {
|
fn unary(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let return_expr = match self.peek_kind() {
|
let return_expr = match self.peek_kind()? {
|
||||||
Some(TokenType::Not) => {
|
Some(TokenType::Not) => {
|
||||||
let unary_op_span = self.next().unwrap().span;
|
let unary_op_span = self.next()?.unwrap().span;
|
||||||
let expr = self.call()?;
|
let expr = self.call()?;
|
||||||
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
Ok(Expr::UnaryOp(Box::new_in(
|
||||||
span: unary_op_span.extend(expr.span()),
|
UnaryOp {
|
||||||
expr,
|
span: unary_op_span.extend(expr.span()),
|
||||||
kind: UnaryOpKind::Not,
|
expr,
|
||||||
})))
|
kind: UnaryOpKind::Not,
|
||||||
|
},
|
||||||
|
self.bump,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
Some(TokenType::Minus) => {
|
Some(TokenType::Minus) => {
|
||||||
let unary_op_span = self.next().unwrap().span;
|
let unary_op_span = self.next()?.unwrap().span;
|
||||||
let expr = self.call()?;
|
let expr = self.call()?;
|
||||||
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
Ok(Expr::UnaryOp(Box::new_in(
|
||||||
span: unary_op_span.extend(expr.span()),
|
UnaryOp {
|
||||||
expr,
|
span: unary_op_span.extend(expr.span()),
|
||||||
kind: UnaryOpKind::Neg,
|
expr,
|
||||||
})))
|
kind: UnaryOpKind::Neg,
|
||||||
|
},
|
||||||
|
self.bump,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
_ => self.call(),
|
_ => self.call(),
|
||||||
};
|
};
|
||||||
|
|
@ -453,33 +479,39 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self) -> ParseResult<'code, Expr> {
|
fn call(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let mut expr = self.primary()?;
|
let mut expr = self.primary()?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
expr = match self.peek_kind() {
|
expr = match self.peek_kind()? {
|
||||||
Some(TokenType::ParenO) => {
|
Some(TokenType::ParenO) => {
|
||||||
let open_span = self.expect(TokenType::ParenO)?.span;
|
let open_span = self.expect(TokenType::ParenO)?.span;
|
||||||
let args = self.parse_list(TokenType::ParenC, Self::expression)?;
|
let args = self.parse_list(TokenType::ParenC, Self::expression)?;
|
||||||
let close_span = self.expect(TokenType::ParenC)?.span;
|
let close_span = self.expect(TokenType::ParenC)?.span;
|
||||||
|
|
||||||
Expr::Call(Box::new(Call {
|
Expr::Call(Box::new_in(
|
||||||
callee: expr,
|
Call {
|
||||||
span: open_span.extend(close_span),
|
callee: expr,
|
||||||
kind: CallKind::Fn(args),
|
span: open_span.extend(close_span),
|
||||||
}))
|
kind: CallKind::Fn(args),
|
||||||
|
},
|
||||||
|
self.bump,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Some(TokenType::Dot) => {
|
Some(TokenType::Dot) => {
|
||||||
let dot_span = self.expect(TokenType::Dot)?.span;
|
let dot_span = self.expect(TokenType::Dot)?.span;
|
||||||
let field = self.ident()?;
|
let field = self.ident()?;
|
||||||
|
|
||||||
Expr::Call(Box::new(Call {
|
Expr::Call(Box::new_in(
|
||||||
callee: expr,
|
Call {
|
||||||
span: dot_span.extend(field.span),
|
callee: expr,
|
||||||
kind: CallKind::Field(field),
|
span: dot_span.extend(field.span),
|
||||||
}))
|
kind: CallKind::Field(field),
|
||||||
|
},
|
||||||
|
self.bump,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
|
|
@ -490,10 +522,10 @@ impl<'code> Parser<'code> {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primary(&mut self) -> ParseResult<'code, Expr> {
|
fn primary(&mut self) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let next = self.next().ok_or(ParseErr::Eof("primary"))?;
|
let next = self.next()?.ok_or(ParseErr::Eof("primary"))?;
|
||||||
let return_expr = match next.kind {
|
let return_expr = match next.kind {
|
||||||
TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))),
|
TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))),
|
||||||
TokenType::Number(literal) => Ok(Expr::Literal(Literal::Number(literal, next.span))),
|
TokenType::Number(literal) => Ok(Expr::Literal(Literal::Number(literal, next.span))),
|
||||||
|
|
@ -523,7 +555,7 @@ impl<'code> Parser<'code> {
|
||||||
fn ident(&mut self) -> ParseResult<'code, Ident> {
|
fn ident(&mut self) -> ParseResult<'code, Ident> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let Token { kind, span } = self.next().ok_or(ParseErr::Eof("identifier"))?;
|
let Token { kind, span } = self.next()?.ok_or(ParseErr::Eof("identifier"))?;
|
||||||
let return_expr = match kind {
|
let return_expr = match kind {
|
||||||
TokenType::Ident(name) => {
|
TokenType::Ident(name) => {
|
||||||
let name_owned = name.to_owned();
|
let name_owned = name.to_owned();
|
||||||
|
|
@ -543,7 +575,7 @@ impl<'code> Parser<'code> {
|
||||||
return_expr
|
return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn object_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
|
fn object_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let close_span = self.expect(TokenType::BraceC)?.span;
|
let close_span = self.expect(TokenType::BraceC)?.span;
|
||||||
|
|
@ -552,7 +584,7 @@ impl<'code> Parser<'code> {
|
||||||
Ok(Expr::Literal(Literal::Object(open_span.extend(close_span))))
|
Ok(Expr::Literal(Literal::Object(open_span.extend(close_span))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
|
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr<'ast>> {
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let elements = self.parse_list(TokenType::BracketC, Self::expression)?;
|
let elements = self.parse_list(TokenType::BracketC, Self::expression)?;
|
||||||
|
|
@ -570,15 +602,15 @@ impl<'code> Parser<'code> {
|
||||||
&mut self,
|
&mut self,
|
||||||
close: TokenType<'code>,
|
close: TokenType<'code>,
|
||||||
mut parser: F,
|
mut parser: F,
|
||||||
) -> ParseResult<'code, Vec<T>>
|
) -> ParseResult<'code, Vec<'ast, T>>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Self) -> ParseResult<'code, T>,
|
F: FnMut(&mut Self) -> ParseResult<'code, T>,
|
||||||
{
|
{
|
||||||
enter_parse!(self);
|
enter_parse!(self);
|
||||||
|
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new_in(self.bump);
|
||||||
|
|
||||||
if self.peek_kind() == Some(&close) {
|
if self.peek_kind()? == Some(&close) {
|
||||||
return Ok(elements);
|
return Ok(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -586,14 +618,14 @@ impl<'code> Parser<'code> {
|
||||||
elements.push(expr);
|
elements.push(expr);
|
||||||
|
|
||||||
while self
|
while self
|
||||||
.peek_kind()
|
.peek_kind()?
|
||||||
.ok_or_else(|| ParseErr::EofExpecting(close.clone()))?
|
.ok_or_else(|| ParseErr::EofExpecting(close.clone()))?
|
||||||
!= &close
|
!= &close
|
||||||
{
|
{
|
||||||
self.expect(TokenType::Comma)?;
|
self.expect(TokenType::Comma)?;
|
||||||
|
|
||||||
// trailing comma support
|
// trailing comma support
|
||||||
if self.peek_kind() == Some(&close) {
|
if self.peek_kind()? == Some(&close) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -607,23 +639,28 @@ impl<'code> Parser<'code> {
|
||||||
|
|
||||||
// token helpers
|
// token helpers
|
||||||
|
|
||||||
#[must_use]
|
fn next(&mut self) -> ParseResult<'code, Option<Token<'code>>> {
|
||||||
fn next(&mut self) -> Option<Token<'code>> {
|
match self.tokens.next() {
|
||||||
self.tokens.next()
|
Some(Ok(t)) => Ok(Some(t)),
|
||||||
|
Some(Err(t)) => Err(t.into()),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
fn peek(&mut self) -> ParseResult<'code, Option<&Token<'code>>> {
|
||||||
fn peek(&mut self) -> Option<&Token<'code>> {
|
match self.tokens.peek() {
|
||||||
self.tokens.peek()
|
Some(Ok(t)) => Ok(Some(t)),
|
||||||
|
Some(Err(t)) => Err(t.clone().into()),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
fn peek_kind(&mut self) -> ParseResult<'code, Option<&TokenType<'code>>> {
|
||||||
fn peek_kind(&mut self) -> Option<&TokenType<'code>> {
|
self.peek().map(|option| option.map(|token| &token.kind))
|
||||||
self.peek().map(|token| &token.kind)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, Token> {
|
fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, Token> {
|
||||||
if let Some(token) = self.next() {
|
if let Some(token) = self.next()? {
|
||||||
if token.kind == kind {
|
if token.kind == kind {
|
||||||
Ok(token)
|
Ok(token)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -650,6 +687,14 @@ pub enum ParseErr<'code> {
|
||||||
InvalidTokenPrimary(Token<'code>),
|
InvalidTokenPrimary(Token<'code>),
|
||||||
EofExpecting(TokenType<'code>),
|
EofExpecting(TokenType<'code>),
|
||||||
Eof(&'static str),
|
Eof(&'static str),
|
||||||
|
LexError(LexError),
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: unify error handling
|
||||||
|
impl From<LexError> for ParseErr<'_> {
|
||||||
|
fn from(err: LexError) -> Self {
|
||||||
|
Self::LexError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerError for ParseErr<'_> {
|
impl CompilerError for ParseErr<'_> {
|
||||||
|
|
@ -665,6 +710,7 @@ impl CompilerError for ParseErr<'_> {
|
||||||
ParseErr::BreakOutsideLoop(span) => *span,
|
ParseErr::BreakOutsideLoop(span) => *span,
|
||||||
ParseErr::ReturnOutsideFunction(span) => *span,
|
ParseErr::ReturnOutsideFunction(span) => *span,
|
||||||
ParseErr::MaxDepth(span) => *span,
|
ParseErr::MaxDepth(span) => *span,
|
||||||
|
ParseErr::LexError(err) => err.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -685,10 +731,14 @@ impl CompilerError for ParseErr<'_> {
|
||||||
ParseErr::BreakOutsideLoop(_) => "break used outside of loop".to_string(),
|
ParseErr::BreakOutsideLoop(_) => "break used outside of loop".to_string(),
|
||||||
ParseErr::ReturnOutsideFunction(_) => "return used outside of function".to_string(),
|
ParseErr::ReturnOutsideFunction(_) => "return used outside of function".to_string(),
|
||||||
ParseErr::MaxDepth(_) => "reached maximal nesting depth".to_string(),
|
ParseErr::MaxDepth(_) => "reached maximal nesting depth".to_string(),
|
||||||
|
ParseErr::LexError(err) => err.message(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn note(&self) -> Option<String> {
|
fn note(&self) -> Option<String> {
|
||||||
None
|
match self {
|
||||||
|
ParseErr::LexError(err) => err.note(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue