conlang: Add statements
TODO: Parse `let` statements
This commit is contained in:
parent
d1b5c48aac
commit
b1f90ca4e9
11
grammar.ebnf
11
grammar.ebnf
@ -1,15 +1,22 @@
|
|||||||
(* Conlang Expression Grammar *)
|
(* Conlang Expression Grammar *)
|
||||||
Start = Expr ;
|
Start = Program ;
|
||||||
|
Program = Stmt* EOI ;
|
||||||
|
|
||||||
(* literal *)
|
(* literal *)
|
||||||
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
||||||
Bool = "true" | "false" ;
|
Bool = "true" | "false" ;
|
||||||
Identifier = IDENTIFIER ;
|
Identifier = IDENTIFIER ;
|
||||||
|
|
||||||
|
(* # Statements *)
|
||||||
|
(* statement *)
|
||||||
|
Stmt = Fn | Let | Expr ';' ;
|
||||||
|
Let = "let" "mut"? Identifier (':' Type)? ('=' Expr)? ';' ;
|
||||||
|
Fn = "fn" Identifier Block ; (* TODO: params, return value*)
|
||||||
|
|
||||||
(* # Expressions *)
|
(* # Expressions *)
|
||||||
(* expression *)
|
(* expression *)
|
||||||
Expr = Ignore ;
|
Expr = Ignore ;
|
||||||
Block = '{' Stmt* Expr? '}' ;
|
Block = '{' Expr '}' ;
|
||||||
Group = '(' Expr? ')' ;
|
Group = '(' Expr? ')' ;
|
||||||
Primary = Item | Identifier | Literal
|
Primary = Item | Identifier | Literal
|
||||||
| Block | Group | Branch ;
|
| Block | Group | Branch ;
|
||||||
|
@ -4,12 +4,11 @@
|
|||||||
//! Also contains a [Visitor](visitor::Visitor) trait for visiting nodes
|
//! Also contains a [Visitor](visitor::Visitor) trait for visiting nodes
|
||||||
//!
|
//!
|
||||||
//! ## Syntax
|
//! ## Syntax
|
||||||
//! ```ignore
|
//! [`Start`]` := `[`Program`] \
|
||||||
//! Start := expression::Expr
|
//! [`Program`] := [`statement::Stmt`]* EOI \
|
||||||
//! Identifier := IDENTIFIER
|
//! [`Identifier`] := [`IDENTIFIER`](crate::token::token_type::Type::Identifier)
|
||||||
//! Literal := STRING | CHAR | FLOAT | INT | TRUE | FALSE
|
//!
|
||||||
//! ```
|
//! See [statement], [literal], and [expression] for more information.
|
||||||
//! See [literal] and [expression] for more details.
|
|
||||||
|
|
||||||
pub mod preamble {
|
pub mod preamble {
|
||||||
//! Common imports for working with the [ast](super)
|
//! Common imports for working with the [ast](super)
|
||||||
@ -18,272 +17,24 @@ pub mod preamble {
|
|||||||
self, control,
|
self, control,
|
||||||
math::{self, operator},
|
math::{self, operator},
|
||||||
},
|
},
|
||||||
literal,
|
literal, statement::Stmt,
|
||||||
visitor::{Visitor, Walk},
|
visitor::{Visitor, Walk},
|
||||||
Identifier, Start,
|
Identifier, Program, Start,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod visitor {
|
|
||||||
//! A [`Visitor`] visits every kind of node in the [Abstract Syntax Tree](super). Nodes, conversely are [`Walkers`](Walk) for Visitors which return a [`Result<(), E>`](Result)
|
|
||||||
use super::{
|
|
||||||
expression::{
|
|
||||||
control::*,
|
|
||||||
math::{operator::*, *},
|
|
||||||
Block, *,
|
|
||||||
},
|
|
||||||
literal::*,
|
|
||||||
*,
|
|
||||||
};
|
|
||||||
/// A [Walker](Walk) is a node in the AST, and calls [`Visitor::visit_*()`](Visitor) on all its children
|
|
||||||
pub trait Walk<T: Visitor<R> + ?Sized, R> {
|
|
||||||
/// Traverses the children of this node in order, calling the appropriate [Visitor] function
|
|
||||||
fn walk(&self, visitor: &mut T) -> R;
|
|
||||||
}
|
|
||||||
mod walker {
|
|
||||||
use super::*;
|
|
||||||
macro leaf($($T:ty),*$(,)?) {$(
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for $T {
|
|
||||||
#[doc = concat!("A(n) [`", stringify!($T), "`] is a leaf node.")]
|
|
||||||
/// Calling this will do nothing.
|
|
||||||
fn walk(&self, _visitor: &mut T) -> Result<(), E> { Ok(()) }
|
|
||||||
}
|
|
||||||
)*}
|
|
||||||
leaf!(Binary, bool, char, Continue, Float, Identifier, str, u128, Unary);
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for While {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_expr(&self.cond)?;
|
|
||||||
visitor.visit_block(&self.body)?;
|
|
||||||
match &self.else_ {
|
|
||||||
Some(expr) => visitor.visit_else(expr),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for If {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_expr(&self.cond)?;
|
|
||||||
visitor.visit_block(&self.body)?;
|
|
||||||
match &self.else_ {
|
|
||||||
Some(expr) => visitor.visit_else(expr),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for For {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_identifier(&self.var)?;
|
|
||||||
visitor.visit_expr(&self.iter)?;
|
|
||||||
visitor.visit_block(&self.body)?;
|
|
||||||
match &self.else_ {
|
|
||||||
Some(expr) => visitor.visit_else(expr),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Else {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_block(&self.block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Return {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_expr(&self.expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Break {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_expr(&self.expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Start {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_expr(&self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Expr {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_operation(&self.ignore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Group {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
match self {
|
|
||||||
Group::Expr(expr) => visitor.visit_expr(expr),
|
|
||||||
Group::Empty => visitor.visit_empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Block {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
visitor.visit_expr(&self.expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Operation {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
match self {
|
|
||||||
Operation::Binary { first, other } => {
|
|
||||||
visitor.visit_operation(first)?;
|
|
||||||
for (op, other) in other {
|
|
||||||
visitor.visit_binary_op(op)?;
|
|
||||||
visitor.visit_operation(other)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Operation::Unary { operators, operand } => {
|
|
||||||
for op in operators {
|
|
||||||
visitor.visit_unary_op(op)?;
|
|
||||||
}
|
|
||||||
visitor.visit_primary(operand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Primary {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
match self {
|
|
||||||
Primary::Identifier(i) => visitor.visit_identifier(i),
|
|
||||||
Primary::Literal(l) => visitor.visit_literal(l),
|
|
||||||
Primary::Block(b) => visitor.visit_block(b),
|
|
||||||
Primary::Group(g) => visitor.visit_group(g),
|
|
||||||
Primary::Branch(b) => visitor.visit_branch_expr(b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Literal {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
match self {
|
|
||||||
Literal::String(s) => visitor.visit_string_literal(s),
|
|
||||||
Literal::Char(c) => visitor.visit_char_literal(c),
|
|
||||||
Literal::Bool(b) => visitor.visit_bool_literal(b),
|
|
||||||
Literal::Float(f) => visitor.visit_float_literal(f),
|
|
||||||
Literal::Int(i) => visitor.visit_int_literal(i),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Flow {
|
|
||||||
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
|
||||||
match self {
|
|
||||||
Flow::While(w) => visitor.visit_while(w),
|
|
||||||
Flow::If(i) => visitor.visit_if(i),
|
|
||||||
Flow::For(f) => visitor.visit_for(f),
|
|
||||||
Flow::Continue(c) => visitor.visit_continue(c),
|
|
||||||
Flow::Return(r) => visitor.visit_return(r),
|
|
||||||
Flow::Break(b) => visitor.visit_break(b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Visitor traverses every kind of node in the [Abstract Syntax Tree](super)
|
|
||||||
pub trait Visitor<R> {
|
|
||||||
/// Visit the start of an AST
|
|
||||||
fn visit(&mut self, start: &Start) -> R {
|
|
||||||
self.visit_expr(&start.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Visit an [Expression](Expr)
|
|
||||||
fn visit_expr(&mut self, expr: &Expr) -> R {
|
|
||||||
self.visit_operation(&expr.ignore)
|
|
||||||
}
|
|
||||||
// Block expression
|
|
||||||
/// Visit a [Block] expression
|
|
||||||
fn visit_block(&mut self, expr: &Block) -> R {
|
|
||||||
self.visit_expr(&expr.expr)
|
|
||||||
}
|
|
||||||
/// Visit a [Group] expression
|
|
||||||
fn visit_group(&mut self, group: &Group) -> R {
|
|
||||||
match group {
|
|
||||||
Group::Expr(expr) => self.visit_expr(expr),
|
|
||||||
Group::Empty => self.visit_empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Math expression
|
|
||||||
/// Visit an [Operation]
|
|
||||||
fn visit_operation(&mut self, expr: &Operation) -> R;
|
|
||||||
/// Visit a [Binary](Operation::Binary) [operator](operator::Binary)
|
|
||||||
// Math operators
|
|
||||||
fn visit_binary_op(&mut self, op: &operator::Binary) -> R;
|
|
||||||
/// Visit a [Unary](Operation::Unary) [operator](operator::Unary)
|
|
||||||
fn visit_unary_op(&mut self, op: &operator::Unary) -> R;
|
|
||||||
|
|
||||||
/// Visit a [Primary] expression
|
|
||||||
///
|
|
||||||
/// [Primary] := [Identifier] | [Literal] | [Block] | [Flow]
|
|
||||||
fn visit_primary(&mut self, expr: &Primary) -> R {
|
|
||||||
match expr {
|
|
||||||
Primary::Identifier(v) => self.visit_identifier(v),
|
|
||||||
Primary::Literal(v) => self.visit_literal(v),
|
|
||||||
Primary::Block(v) => self.visit_block(v),
|
|
||||||
Primary::Group(v) => self.visit_group(v),
|
|
||||||
Primary::Branch(v) => self.visit_branch_expr(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Visit a [Flow] expression.
|
|
||||||
///
|
|
||||||
/// [Flow] := [While] | [If] | [For]
|
|
||||||
fn visit_branch_expr(&mut self, expr: &Flow) -> R {
|
|
||||||
match expr {
|
|
||||||
Flow::While(e) => self.visit_while(e),
|
|
||||||
Flow::If(e) => self.visit_if(e),
|
|
||||||
Flow::For(e) => self.visit_for(e),
|
|
||||||
Flow::Continue(e) => self.visit_continue(e),
|
|
||||||
Flow::Return(e) => self.visit_return(e),
|
|
||||||
Flow::Break(e) => self.visit_break(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Visit an [If] expression
|
|
||||||
fn visit_if(&mut self, expr: &If) -> R;
|
|
||||||
/// Visit a [While] loop expression
|
|
||||||
fn visit_while(&mut self, expr: &While) -> R;
|
|
||||||
/// Visit a [For] loop expression
|
|
||||||
fn visit_for(&mut self, expr: &For) -> R;
|
|
||||||
/// Visit an [Else] expression
|
|
||||||
fn visit_else(&mut self, expr: &Else) -> R;
|
|
||||||
/// Visit a [Continue] expression
|
|
||||||
fn visit_continue(&mut self, expr: &Continue) -> R;
|
|
||||||
/// Visit a [Break] expression
|
|
||||||
fn visit_break(&mut self, expr: &Break) -> R;
|
|
||||||
/// Visit a [Return] expression
|
|
||||||
fn visit_return(&mut self, expr: &Return) -> R;
|
|
||||||
|
|
||||||
// primary symbols
|
|
||||||
/// Visit an [Identifier]
|
|
||||||
fn visit_identifier(&mut self, ident: &Identifier) -> R;
|
|
||||||
/// Visit a [Literal]
|
|
||||||
///
|
|
||||||
/// [Literal] := [String] | [char] | [bool] | [Float] | [u128]
|
|
||||||
fn visit_literal(&mut self, literal: &Literal) -> R {
|
|
||||||
match literal {
|
|
||||||
Literal::String(l) => self.visit_string_literal(l),
|
|
||||||
Literal::Char(l) => self.visit_char_literal(l),
|
|
||||||
Literal::Bool(l) => self.visit_bool_literal(l),
|
|
||||||
Literal::Float(l) => self.visit_float_literal(l),
|
|
||||||
Literal::Int(l) => self.visit_int_literal(l),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Visit a [string](str) literal
|
|
||||||
fn visit_string_literal(&mut self, string: &str) -> R;
|
|
||||||
/// Visit a [character](char) literal
|
|
||||||
fn visit_char_literal(&mut self, char: &char) -> R;
|
|
||||||
/// Visit a [boolean](bool) literal
|
|
||||||
fn visit_bool_literal(&mut self, bool: &bool) -> R;
|
|
||||||
/// Visit a [floating point](Float) literal
|
|
||||||
fn visit_float_literal(&mut self, float: &Float) -> R;
|
|
||||||
/// Visit an [integer](u128) literal
|
|
||||||
fn visit_int_literal(&mut self, int: &u128) -> R;
|
|
||||||
|
|
||||||
/// Visit an Empty
|
|
||||||
fn visit_empty(&mut self) -> R;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Marks the root of a tree
|
/// Marks the root of a tree
|
||||||
/// # Syntax
|
/// # Syntax
|
||||||
/// [`Start`] := [`expression::Expr`]
|
/// [`Start`] := [`Program`]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Start(pub expression::Expr);
|
pub struct Start(pub Program);
|
||||||
|
|
||||||
|
/// Contains an entire Conlang program
|
||||||
|
/// # Syntax
|
||||||
|
/// [`Program`] := [`statement::Stmt`]*
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Program(pub Vec<statement::Stmt>);
|
||||||
|
|
||||||
/// An Identifier stores the name of an item
|
/// An Identifier stores the name of an item
|
||||||
/// # Syntax
|
/// # Syntax
|
||||||
@ -389,6 +140,37 @@ pub mod literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod statement {
|
||||||
|
//! # Statements
|
||||||
|
//! A statement is an expression which evaluates to Empty
|
||||||
|
//!
|
||||||
|
//! # Syntax
|
||||||
|
//! [`Stmt`] := [`Let`](Stmt::Let) | [`Expr`](Stmt::Expr)
|
||||||
|
//! [`Let`](Stmt::Let) := `"let"` [`Identifier`] (`:` `Type`)? (`=` [`Expr`])? `;`
|
||||||
|
//! [`Expr`](Stmt::Expr) := [`Expr`] `;`
|
||||||
|
use super::{expression::Expr, Identifier};
|
||||||
|
|
||||||
|
/// Contains a statement
|
||||||
|
/// # Syntax
|
||||||
|
/// [`Stmt`] := [`Let`](Stmt::Let) | [`Expr`](Stmt::Expr)
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Stmt {
|
||||||
|
/// Contains a variable declaration
|
||||||
|
/// # Syntax
|
||||||
|
/// [`Let`](Stmt::Let) := `"let"` [`Identifier`] (`:` `Type`)? (`=` [`Expr`])? `;`
|
||||||
|
Let {
|
||||||
|
name: Identifier,
|
||||||
|
mutable: bool,
|
||||||
|
ty: Option<Identifier>,
|
||||||
|
init: Option<Expr>,
|
||||||
|
},
|
||||||
|
/// Contains an expression statement
|
||||||
|
/// # Syntax
|
||||||
|
/// [`Expr`](Stmt::Expr) := [`Expr`] `;`
|
||||||
|
Expr(Expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod expression {
|
pub mod expression {
|
||||||
//! # Expressions
|
//! # Expressions
|
||||||
//!
|
//!
|
||||||
@ -831,3 +613,294 @@ pub mod expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod visitor {
|
||||||
|
//! A [`Visitor`] visits every kind of node in the [Abstract Syntax Tree](super). Nodes,
|
||||||
|
//! conversely are [`Walkers`](Walk) for Visitors which return a [`Result<(), E>`](Result)
|
||||||
|
use super::{
|
||||||
|
expression::{
|
||||||
|
control::*,
|
||||||
|
math::{operator::*, *},
|
||||||
|
Block, *,
|
||||||
|
},
|
||||||
|
literal::*,
|
||||||
|
statement::Stmt,
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
/// A [Walker](Walk) is a node in the AST, and calls [`Visitor::visit_*()`](Visitor) on all its
|
||||||
|
/// children
|
||||||
|
pub trait Walk<T: Visitor<R> + ?Sized, R> {
|
||||||
|
/// Traverses the children of this node in order, calling the appropriate [Visitor] function
|
||||||
|
fn walk(&self, visitor: &mut T) -> R;
|
||||||
|
}
|
||||||
|
mod walker {
|
||||||
|
use crate::ast::statement::Stmt;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
macro leaf($($T:ty),*$(,)?) {$(
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for $T {
|
||||||
|
#[doc = concat!("A(n) [`", stringify!($T), "`] is a leaf node.")]
|
||||||
|
/// Calling this will do nothing.
|
||||||
|
fn walk(&self, _visitor: &mut T) -> Result<(), E> { Ok(()) }
|
||||||
|
}
|
||||||
|
)*}
|
||||||
|
leaf!(Binary, bool, char, Continue, Float, Identifier, str, u128, Unary);
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for While {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_expr(&self.cond)?;
|
||||||
|
visitor.visit_block(&self.body)?;
|
||||||
|
match &self.else_ {
|
||||||
|
Some(expr) => visitor.visit_else(expr),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for If {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_expr(&self.cond)?;
|
||||||
|
visitor.visit_block(&self.body)?;
|
||||||
|
match &self.else_ {
|
||||||
|
Some(expr) => visitor.visit_else(expr),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for For {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_identifier(&self.var)?;
|
||||||
|
visitor.visit_expr(&self.iter)?;
|
||||||
|
visitor.visit_block(&self.body)?;
|
||||||
|
match &self.else_ {
|
||||||
|
Some(expr) => visitor.visit_else(expr),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Else {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_block(&self.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Return {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_expr(&self.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Break {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_expr(&self.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Start {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_program(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Expr {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_operation(&self.ignore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Group {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
match self {
|
||||||
|
Group::Expr(expr) => visitor.visit_expr(expr),
|
||||||
|
Group::Empty => visitor.visit_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Block {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
visitor.visit_expr(&self.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Operation {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
match self {
|
||||||
|
Operation::Binary { first, other } => {
|
||||||
|
visitor.visit_operation(first)?;
|
||||||
|
for (op, other) in other {
|
||||||
|
visitor.visit_binary_op(op)?;
|
||||||
|
visitor.visit_operation(other)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Operation::Unary { operators, operand } => {
|
||||||
|
for op in operators {
|
||||||
|
visitor.visit_unary_op(op)?;
|
||||||
|
}
|
||||||
|
visitor.visit_primary(operand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Primary {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
match self {
|
||||||
|
Primary::Identifier(i) => visitor.visit_identifier(i),
|
||||||
|
Primary::Literal(l) => visitor.visit_literal(l),
|
||||||
|
Primary::Block(b) => visitor.visit_block(b),
|
||||||
|
Primary::Group(g) => visitor.visit_group(g),
|
||||||
|
Primary::Branch(b) => visitor.visit_branch_expr(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Literal {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
match self {
|
||||||
|
Literal::String(s) => visitor.visit_string_literal(s),
|
||||||
|
Literal::Char(c) => visitor.visit_char_literal(c),
|
||||||
|
Literal::Bool(b) => visitor.visit_bool_literal(b),
|
||||||
|
Literal::Float(f) => visitor.visit_float_literal(f),
|
||||||
|
Literal::Int(i) => visitor.visit_int_literal(i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Flow {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
match self {
|
||||||
|
Flow::While(w) => visitor.visit_while(w),
|
||||||
|
Flow::If(i) => visitor.visit_if(i),
|
||||||
|
Flow::For(f) => visitor.visit_for(f),
|
||||||
|
Flow::Continue(c) => visitor.visit_continue(c),
|
||||||
|
Flow::Return(r) => visitor.visit_return(r),
|
||||||
|
Flow::Break(b) => visitor.visit_break(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Stmt {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
match self {
|
||||||
|
Stmt::Let { name, mutable: _, ty, init } => {
|
||||||
|
visitor.visit_identifier(name)?;
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
visitor.visit_identifier(ty)?;
|
||||||
|
}
|
||||||
|
if let Some(init) = init {
|
||||||
|
visitor.visit_expr(init)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Stmt::Expr(e) => visitor.visit_expr(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Program {
|
||||||
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
|
for stmt in &self.0 {
|
||||||
|
visitor.visit_statement(stmt)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Visitor traverses every kind of node in the [Abstract Syntax Tree](super)
|
||||||
|
pub trait Visitor<R> {
|
||||||
|
/// Visit the start of an AST
|
||||||
|
fn visit(&mut self, start: &Start) -> R {
|
||||||
|
self.visit_program(&start.0)
|
||||||
|
}
|
||||||
|
/// Visit a [Program]
|
||||||
|
fn visit_program(&mut self, prog: &Program) -> R;
|
||||||
|
|
||||||
|
/// Visit a [Statement](Stmt)
|
||||||
|
fn visit_statement(&mut self, stmt: &Stmt) -> R;
|
||||||
|
|
||||||
|
/// Visit an [Expression](Expr)
|
||||||
|
fn visit_expr(&mut self, expr: &Expr) -> R {
|
||||||
|
self.visit_operation(&expr.ignore)
|
||||||
|
}
|
||||||
|
// Block expression
|
||||||
|
/// Visit a [Block] expression
|
||||||
|
fn visit_block(&mut self, expr: &Block) -> R {
|
||||||
|
self.visit_expr(&expr.expr)
|
||||||
|
}
|
||||||
|
/// Visit a [Group] expression
|
||||||
|
fn visit_group(&mut self, group: &Group) -> R {
|
||||||
|
match group {
|
||||||
|
Group::Expr(expr) => self.visit_expr(expr),
|
||||||
|
Group::Empty => self.visit_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Math expression
|
||||||
|
/// Visit an [Operation]
|
||||||
|
fn visit_operation(&mut self, expr: &Operation) -> R;
|
||||||
|
/// Visit a [Binary](Operation::Binary) [operator](operator::Binary)
|
||||||
|
// Math operators
|
||||||
|
fn visit_binary_op(&mut self, op: &operator::Binary) -> R;
|
||||||
|
/// Visit a [Unary](Operation::Unary) [operator](operator::Unary)
|
||||||
|
fn visit_unary_op(&mut self, op: &operator::Unary) -> R;
|
||||||
|
|
||||||
|
/// Visit a [Primary] expression
|
||||||
|
///
|
||||||
|
/// [Primary] := [Identifier] | [Literal] | [Block] | [Flow]
|
||||||
|
fn visit_primary(&mut self, expr: &Primary) -> R {
|
||||||
|
match expr {
|
||||||
|
Primary::Identifier(v) => self.visit_identifier(v),
|
||||||
|
Primary::Literal(v) => self.visit_literal(v),
|
||||||
|
Primary::Block(v) => self.visit_block(v),
|
||||||
|
Primary::Group(v) => self.visit_group(v),
|
||||||
|
Primary::Branch(v) => self.visit_branch_expr(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visit a [Flow] expression.
|
||||||
|
///
|
||||||
|
/// [Flow] := [While] | [If] | [For]
|
||||||
|
fn visit_branch_expr(&mut self, expr: &Flow) -> R {
|
||||||
|
match expr {
|
||||||
|
Flow::While(e) => self.visit_while(e),
|
||||||
|
Flow::If(e) => self.visit_if(e),
|
||||||
|
Flow::For(e) => self.visit_for(e),
|
||||||
|
Flow::Continue(e) => self.visit_continue(e),
|
||||||
|
Flow::Return(e) => self.visit_return(e),
|
||||||
|
Flow::Break(e) => self.visit_break(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Visit an [If] expression
|
||||||
|
fn visit_if(&mut self, expr: &If) -> R;
|
||||||
|
/// Visit a [While] loop expression
|
||||||
|
fn visit_while(&mut self, expr: &While) -> R;
|
||||||
|
/// Visit a [For] loop expression
|
||||||
|
fn visit_for(&mut self, expr: &For) -> R;
|
||||||
|
/// Visit an [Else] expression
|
||||||
|
fn visit_else(&mut self, expr: &Else) -> R;
|
||||||
|
/// Visit a [Continue] expression
|
||||||
|
fn visit_continue(&mut self, expr: &Continue) -> R;
|
||||||
|
/// Visit a [Break] expression
|
||||||
|
fn visit_break(&mut self, expr: &Break) -> R;
|
||||||
|
/// Visit a [Return] expression
|
||||||
|
fn visit_return(&mut self, expr: &Return) -> R;
|
||||||
|
|
||||||
|
// primary symbols
|
||||||
|
/// Visit an [Identifier]
|
||||||
|
fn visit_identifier(&mut self, ident: &Identifier) -> R;
|
||||||
|
/// Visit a [Literal]
|
||||||
|
///
|
||||||
|
/// [Literal] := [String] | [char] | [bool] | [Float] | [u128]
|
||||||
|
fn visit_literal(&mut self, literal: &Literal) -> R {
|
||||||
|
match literal {
|
||||||
|
Literal::String(l) => self.visit_string_literal(l),
|
||||||
|
Literal::Char(l) => self.visit_char_literal(l),
|
||||||
|
Literal::Bool(l) => self.visit_bool_literal(l),
|
||||||
|
Literal::Float(l) => self.visit_float_literal(l),
|
||||||
|
Literal::Int(l) => self.visit_int_literal(l),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Visit a [string](str) literal
|
||||||
|
fn visit_string_literal(&mut self, string: &str) -> R;
|
||||||
|
/// Visit a [character](char) literal
|
||||||
|
fn visit_char_literal(&mut self, char: &char) -> R;
|
||||||
|
/// Visit a [boolean](bool) literal
|
||||||
|
fn visit_bool_literal(&mut self, bool: &bool) -> R;
|
||||||
|
/// Visit a [floating point](Float) literal
|
||||||
|
fn visit_float_literal(&mut self, float: &Float) -> R;
|
||||||
|
/// Visit an [integer](u128) literal
|
||||||
|
fn visit_int_literal(&mut self, int: &u128) -> R;
|
||||||
|
|
||||||
|
/// Visit an Empty
|
||||||
|
fn visit_empty(&mut self) -> R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -147,12 +147,15 @@ impl Parser {
|
|||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
Self { tokens, panic_stack: vec![], curr: 0 }
|
Self { tokens, panic_stack: vec![], curr: 0 }
|
||||||
}
|
}
|
||||||
/// Parse the [start of an AST](Start)
|
/// Parses the [start of an AST](Start)
|
||||||
pub fn parse(&mut self) -> PResult<Start> {
|
pub fn parse(&mut self) -> PResult<Start> {
|
||||||
self.consume_comments();
|
self.consume_comments();
|
||||||
Ok(Start(self.expr()?))
|
Ok(Start(self.program()?))
|
||||||
|
}
|
||||||
|
/// Parses only one expression
|
||||||
|
pub fn parse_expr(&mut self) -> PResult<expression::Expr> {
|
||||||
|
self.expr()
|
||||||
}
|
}
|
||||||
/// Consumes any consecutive comments
|
|
||||||
fn consume_comments(&mut self) -> &mut Self {
|
fn consume_comments(&mut self) -> &mut Self {
|
||||||
while let Ok(Type::Comment) = self.peek().map(|t| t.ty()) {
|
while let Ok(Type::Comment) = self.peek().map(|t| t.ty()) {
|
||||||
self.curr += 1;
|
self.curr += 1;
|
||||||
@ -311,6 +314,29 @@ impl Parser {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Statements
|
||||||
|
impl Parser {
|
||||||
|
/// Parses a series of [statements](Stmt)
|
||||||
|
fn program(&mut self) -> PResult<Program> {
|
||||||
|
let mut out = vec![];
|
||||||
|
while self.check_eof().is_ok() {
|
||||||
|
out.push(self.stmt()?);
|
||||||
|
}
|
||||||
|
Ok(Program(out))
|
||||||
|
}
|
||||||
|
/// Parses a single [statement](Stmt)
|
||||||
|
fn stmt(&mut self) -> PResult<Stmt> {
|
||||||
|
let token = self.peek()?;
|
||||||
|
match token.ty() {
|
||||||
|
Type::Keyword(Keyword::Let) => todo!("Let statements"),
|
||||||
|
_ => {
|
||||||
|
let out = Stmt::Expr(self.expr()?);
|
||||||
|
self.consume_type(Type::Semi)?;
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Expressions
|
/// Expressions
|
||||||
impl Parser {
|
impl Parser {
|
||||||
fn expr(&mut self) -> PResult<expression::Expr> {
|
fn expr(&mut self) -> PResult<expression::Expr> {
|
||||||
@ -404,7 +430,6 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
macro operator_impl ($($(#[$m:meta])* $f:ident : {$($type:pat => $op:ident),*$(,)?})*) {
|
macro operator_impl ($($(#[$m:meta])* $f:ident : {$($type:pat => $op:ident),*$(,)?})*) {
|
||||||
$($(#[$m])* fn $f(&mut self) -> PResult<operator::Binary> {
|
$($(#[$m])* fn $f(&mut self) -> PResult<operator::Binary> {
|
||||||
|
|
||||||
use operator::Binary;
|
use operator::Binary;
|
||||||
let token = self.peek()?;
|
let token = self.peek()?;
|
||||||
let out = Ok(match token.ty() {
|
let out = Ok(match token.ty() {
|
||||||
|
@ -68,6 +68,31 @@ macro visit_operator($self:ident.$op:expr) {
|
|||||||
$self.space()?.put($op)?.space().map(drop)
|
$self.space()?.put($op)?.space().map(drop)
|
||||||
}
|
}
|
||||||
impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||||
|
fn visit_program(&mut self, prog: &Program) -> IOResult<()> {
|
||||||
|
// delegate to the walker
|
||||||
|
prog.walk(self)
|
||||||
|
}
|
||||||
|
fn visit_statement(&mut self, stmt: &Stmt) -> IOResult<()> {
|
||||||
|
match stmt {
|
||||||
|
Stmt::Let { name, mutable, ty, init } => {
|
||||||
|
self.put("let")?.space()?;
|
||||||
|
if *mutable {
|
||||||
|
self.put("mut")?.space()?;
|
||||||
|
}
|
||||||
|
self.visit_identifier(name)?;
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
self.put(':')?.space()?.visit_identifier(ty)?;
|
||||||
|
}
|
||||||
|
if let Some(init) = init {
|
||||||
|
self.space()?.put('=')?.space()?.visit_expr(init)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Stmt::Expr(e) => {
|
||||||
|
self.visit_expr(e)?;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.put(';')?.newline().map(drop)
|
||||||
|
}
|
||||||
fn visit_operation(&mut self, expr: &math::Operation) -> IOResult<()> {
|
fn visit_operation(&mut self, expr: &math::Operation) -> IOResult<()> {
|
||||||
use math::Operation;
|
use math::Operation;
|
||||||
match expr {
|
match expr {
|
||||||
|
Loading…
Reference in New Issue
Block a user