conlang: Add statements

TODO: Parse `let` statements
This commit is contained in:
John 2023-10-26 14:33:56 -05:00
parent d1b5c48aac
commit b1f90ca4e9
4 changed files with 400 additions and 270 deletions

View File

@ -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 ;

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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 {