conlang: Grammatical cleanup; merge control flow expressions
This commit is contained in:
parent
331141356a
commit
7f7393d2c6
91
grammar.ebnf
91
grammar.ebnf
@ -1,55 +1,48 @@
|
||||
# Conlang Expression Grammar
|
||||
Start = Expr
|
||||
(* Conlang Expression Grammar *)
|
||||
Start = Expr ;
|
||||
|
||||
# literal
|
||||
Literal = String | Char | Float | Int | Bool
|
||||
String = STRING
|
||||
Float = FLOAT
|
||||
Char = CHARACTER
|
||||
Bool = "true" | "false"
|
||||
Int = INTEGER
|
||||
(* literal *)
|
||||
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
||||
Bool = "true" | "false" ;
|
||||
Identifier = IDENTIFIER ;
|
||||
(* # Expressions *)
|
||||
(* expression *)
|
||||
Expr = Ignore
|
||||
Block = '{' Expr? '}' ;
|
||||
Group = '(' Expr? ')' ;
|
||||
Primary = Item | Identifier | Literal
|
||||
| Block | Group | Branch ;
|
||||
|
||||
Identifier = IDENTIFIER
|
||||
(* expression::math *)
|
||||
Ignore = Assign (IgnoreOp Assign )* ;
|
||||
Assign = Compare (AssignOp Compare)* ;
|
||||
Compare = Logic (CompareOp Logic )* ;
|
||||
Logic = Bitwise (LogicOp Bitwise)* ;
|
||||
Bitwise = Shift (BitwiseOp Shift )* ;
|
||||
Shift = Term (ShiftOp Term )* ;
|
||||
Term = Factor (TermOp Factor )* ;
|
||||
Factor = Unary (FactorOp Unary )* ;
|
||||
Unary = (UnaryOp)* Primary ;
|
||||
|
||||
# Expressions
|
||||
Expr = Flow | Ignore
|
||||
Block = '{' Expr '}'
|
||||
Group = '(' Expr ')'
|
||||
Final = Identifier | Literal |
|
||||
Block | Group | Branch
|
||||
|
||||
# expression::math
|
||||
Ignore = Assign (IgnoreOp Assign )*
|
||||
Assign = Compare (AssignOp Compare)*
|
||||
Compare = Logic (CompareOp Logic )*
|
||||
Logic = Bitwise (LogicOp Bitwise)*
|
||||
Bitwise = Shift (BitwiseOp Shift )*
|
||||
Shift = Term (ShiftOp Term )*
|
||||
Term = Factor (TermOp Factor )*
|
||||
Factor = Unary (FactorOp Unary )*
|
||||
Unary = (UnaryOp)* Final
|
||||
|
||||
# expression::math::operator
|
||||
IgnoreOp = ';'
|
||||
CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>'
|
||||
(* expression::math::operator *)
|
||||
IgnoreOp = ';' ;
|
||||
CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>' ;
|
||||
AssignOp = '=' | "+=" | "-=" | "*=" | "/=" |
|
||||
"&=" | "|=" | "^=" |"<<=" |">>="
|
||||
LogicOp = "&&" | "||" | "^^"
|
||||
"&=" | "|=" | "^=" |"<<=" |">>=" ;
|
||||
LogicOp = "&&" | "||" | "^^" ;
|
||||
|
||||
BitwiseOp = '&' | '|' | '^'
|
||||
ShiftOp = "<<" | ">>"
|
||||
TermOp = '+' | '-'
|
||||
FactorOp = '*' | '/' | '%'
|
||||
UnaryOp = '*' | '&' | '-' | '!'
|
||||
BitwiseOp = '&' | '|' | '^' ;
|
||||
ShiftOp = "<<" | ">>";
|
||||
TermOp = '+' | '-' ;
|
||||
FactorOp = '*' | '/' | '%' ;
|
||||
UnaryOp = '*' | '&' | '-' | '!' ;
|
||||
|
||||
# expression::control
|
||||
Branch = While | If | For
|
||||
If = "if" Expr Block (Else)?
|
||||
While = "while" Expr Block (Else)?
|
||||
For = "for" Identifier "in" Expr Block (Else)?
|
||||
Else = "else" Block
|
||||
|
||||
Flow = Break | Return | Continue
|
||||
Break = "break" Expr
|
||||
Return = "return" Expr
|
||||
Continue = "continue"
|
||||
(* expression::control *)
|
||||
Branch = While | If | For | Break | Return | Continue ;
|
||||
If = "if" Expr Block (Else)? ;
|
||||
While = "while" Expr Block (Else)? ;
|
||||
For = "for" Identifier "in" Expr Block (Else)? ;
|
||||
Else = "else" Block ;
|
||||
Break = "break" Expr ;
|
||||
Return = "return" Expr ;
|
||||
Continue = "continue" ;
|
||||
|
@ -31,10 +31,6 @@ mod visitor {
|
||||
*,
|
||||
};
|
||||
/// [Walk] is the lexical inverse of [Visitor]
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust,ignore
|
||||
/// ```
|
||||
pub trait Walk<T: Visitor<R> + ?Sized, R> {
|
||||
///
|
||||
fn walk(&self, visitor: &mut T) -> R;
|
||||
@ -43,7 +39,7 @@ mod visitor {
|
||||
use super::*;
|
||||
macro_rules! impl_walk {
|
||||
($($T:ty => $f:ident),*$(,)?) => {
|
||||
$(impl<T: Visitor<R>, R> Walk<T, R> for $T {
|
||||
$(impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for $T {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
visitor.$f(self)
|
||||
}
|
||||
@ -59,7 +55,7 @@ mod visitor {
|
||||
// Identifier
|
||||
Identifier => visit_identifier,
|
||||
// ast::literal
|
||||
&str => visit_string_literal,
|
||||
str => visit_string_literal,
|
||||
char => visit_char_literal,
|
||||
bool => visit_bool_literal,
|
||||
u128 => visit_int_literal,
|
||||
@ -94,22 +90,26 @@ mod visitor {
|
||||
Return => visit_return,
|
||||
Break => visit_break,
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for () {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
visitor.visit_empty()
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Expr {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
match self {
|
||||
Expr::Flow(f) => visitor.visit_control_flow(f),
|
||||
Expr::Ignore(i) => visitor.visit_ignore(i),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Final {
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Primary {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
match self {
|
||||
Final::Identifier(i) => visitor.visit_identifier(i),
|
||||
Final::Literal(l) => visitor.visit_literal(l),
|
||||
Final::Block(b) => visitor.visit_block(b),
|
||||
Final::Group(g) => visitor.visit_group(g),
|
||||
Final::Branch(b) => visitor.visit_branch_expr(b),
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,18 +124,12 @@ mod visitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Branch {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
match self {
|
||||
Branch::While(w) => visitor.visit_while(w),
|
||||
Branch::If(i) => visitor.visit_if(i),
|
||||
Branch::For(f) => visitor.visit_for(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Flow {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
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),
|
||||
@ -157,36 +151,60 @@ mod visitor {
|
||||
// Block expression
|
||||
/// Visit a [Block] expression
|
||||
fn visit_block(&mut self, expr: &Block) -> R {
|
||||
self.visit_expr(&expr.expr)
|
||||
match &expr.expr {
|
||||
Some(expr) => self.visit_expr(expr),
|
||||
None => self.visit_empty(),
|
||||
}
|
||||
}
|
||||
/// Visit a [Group] expression
|
||||
fn visit_group(&mut self, expr: &Group) -> R {
|
||||
self.visit_expr(&expr.expr)
|
||||
match &expr.expr {
|
||||
Some(expr) => self.visit_expr(expr),
|
||||
None => self.visit_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
// Math expression
|
||||
fn visit_binary<F, Op>(&mut self, expr: &Binary<F, (Op, F)>) -> R
|
||||
where F: Walk<Self, R>, Op: Walk<Self, R>;
|
||||
/// Visit an [Ignore] expression
|
||||
fn visit_ignore(&mut self, expr: &Ignore) -> R;
|
||||
fn visit_ignore(&mut self, expr: &Ignore) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit an [Assign] expression
|
||||
fn visit_assign(&mut self, expr: &Assign) -> R;
|
||||
fn visit_assign(&mut self, expr: &Assign) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Compare] expression
|
||||
fn visit_compare(&mut self, expr: &Compare) -> R;
|
||||
fn visit_compare(&mut self, expr: &Compare) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Logic] expression
|
||||
fn visit_logic(&mut self, expr: &Logic) -> R;
|
||||
fn visit_logic(&mut self, expr: &Logic) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Bitwise] expression
|
||||
fn visit_bitwise(&mut self, expr: &Bitwise) -> R;
|
||||
fn visit_bitwise(&mut self, expr: &Bitwise) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Shift] expression
|
||||
fn visit_shift(&mut self, expr: &Shift) -> R;
|
||||
fn visit_shift(&mut self, expr: &Shift) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Term] expression
|
||||
fn visit_term(&mut self, expr: &Term) -> R;
|
||||
fn visit_term(&mut self, expr: &Term) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Factor] expression
|
||||
fn visit_factor(&mut self, expr: &Factor) -> R;
|
||||
fn visit_factor(&mut self, expr: &Factor) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Unary] expression
|
||||
fn visit_unary(&mut self, expr: &Unary) -> R;
|
||||
/// Visit a [Final] expression
|
||||
/// Visit a [Primary] expression
|
||||
///
|
||||
/// [Final] := [Identifier] | [Literal] | [Block] | [Branch]
|
||||
fn visit_final(&mut self, expr: &Final) -> R {
|
||||
/// [Primary] := [Identifier] | [Literal] | [Block] | [Flow]
|
||||
fn visit_primary(&mut self, expr: &Primary) -> R {
|
||||
expr.walk(self)
|
||||
}
|
||||
// Math operators
|
||||
@ -209,10 +227,10 @@ mod visitor {
|
||||
/// Visit a [Unary] [operator](operator::Unary)
|
||||
fn visit_unary_op(&mut self, op: &operator::Unary) -> R;
|
||||
|
||||
/// Visit a [Branch] expression.
|
||||
/// Visit a [Flow] expression.
|
||||
///
|
||||
/// [Branch] := [While] | [If] | [For]
|
||||
fn visit_branch_expr(&mut self, expr: &Branch) -> R {
|
||||
/// [Flow] := [While] | [If] | [For]
|
||||
fn visit_branch_expr(&mut self, expr: &Flow) -> R {
|
||||
expr.walk(self)
|
||||
}
|
||||
/// Visit an [If] expression
|
||||
@ -223,12 +241,6 @@ mod visitor {
|
||||
fn visit_for(&mut self, expr: &For) -> R;
|
||||
/// Visit an [Else] expression
|
||||
fn visit_else(&mut self, expr: &Else) -> R;
|
||||
/// Visit a [Control Flow](control::Flow) expression
|
||||
///
|
||||
/// [`Flow`] := [`Continue`] | [`Return`] | [`Break`]
|
||||
fn visit_control_flow(&mut self, expr: &control::Flow) -> R {
|
||||
expr.walk(self)
|
||||
}
|
||||
/// Visit a [Continue] expression
|
||||
fn visit_continue(&mut self, expr: &Continue) -> R;
|
||||
/// Visit a [Break] expression
|
||||
@ -236,12 +248,12 @@ mod visitor {
|
||||
/// Visit a [Return] expression
|
||||
fn visit_return(&mut self, expr: &Return) -> R;
|
||||
|
||||
// final symbols
|
||||
// primary symbols
|
||||
/// Visit an [Identifier]
|
||||
fn visit_identifier(&mut self, ident: &Identifier) -> R;
|
||||
/// Visit a [Literal]
|
||||
///
|
||||
/// [Literal] := [String] | [char] | [bool] | [Float] | [Int]
|
||||
/// [Literal] := [String] | [char] | [bool] | [Float] | [u128]
|
||||
fn visit_literal(&mut self, literal: &Literal) -> R {
|
||||
literal.walk(self)
|
||||
}
|
||||
@ -253,8 +265,10 @@ mod visitor {
|
||||
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](Int) literal
|
||||
/// Visit an [integer](u128) literal
|
||||
fn visit_int_literal(&mut self, int: &u128) -> R;
|
||||
/// Visit an Empty literal
|
||||
fn visit_empty(&mut self) -> R;
|
||||
}
|
||||
}
|
||||
/// Marks the root of a tree
|
||||
@ -283,8 +297,7 @@ pub mod todo {
|
||||
//! - [ ] Store token spans in AST
|
||||
pub mod path {
|
||||
//! Path support
|
||||
//! - [ ] Add namespace syntax (i.e. `::crate::foo::bar` | `foo::bar::Baz` |
|
||||
//! `foo::bar::*`)
|
||||
//! - [ ] Add namespace syntax (i.e. `::crate::foo::bar` | `foo::bar::Baz` | `foo::bar::*`)
|
||||
//!
|
||||
//! Path resolution will be vital to the implementation of structs, enums, impl blocks,
|
||||
//! traits, modules, etc.
|
||||
@ -330,7 +343,7 @@ pub mod literal {
|
||||
|
||||
/// Represents a literal value
|
||||
/// # Syntax
|
||||
/// [`Literal`] := [`String`] | [`char`] | [`bool`] | [`Float`] | [`Int`]
|
||||
/// [`Literal`] := [`String`] | [`char`] | [`bool`] | [`Float`] | [`u128`]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Literal {
|
||||
/// Represents a literal string value
|
||||
@ -353,7 +366,7 @@ pub mod literal {
|
||||
Float(Float),
|
||||
/// Represents a literal integer value
|
||||
/// # Syntax
|
||||
/// [`Int`] := [`INTEGER`](crate::token::Type::Integer)
|
||||
/// [`u128`] := [`INTEGER`](crate::token::Type::Integer)
|
||||
Int(u128),
|
||||
}
|
||||
|
||||
@ -379,27 +392,26 @@ pub mod expression {
|
||||
//! | # | Node | Function
|
||||
//! |----|------------------:|:----------------------------------------------
|
||||
//! | 0 | [`Expr`] | Contains an expression
|
||||
//! | 1 | [`control::Flow`]| Unconditional branches (`return`, `break`, `continue`)
|
||||
//! | 2 | [`math::Ignore`]| Ignores the preceding sub-expression's result
|
||||
//! | 3 | [`math::Assign`]| Assignment
|
||||
//! | 4 | [`math::Compare`]| Value Comparison
|
||||
//! | 5 | [`math::Logic`]| Boolean And, Or, Xor
|
||||
//! | 6 | [`math::Bitwise`]| Bitwise And, Or, Xor
|
||||
//! | 7 | [`math::Shift`]| Shift Left/Right
|
||||
//! | 8 | [`math::Term`]| Add, Subtract
|
||||
//! | 9 | [`math::Factor`]| Multiply, Divide, Remainder
|
||||
//! | 10 | [`math::Unary`]| Unary Dereference, Reference, Negate, Not
|
||||
//! | 11 |[`control::Branch`]| Conditional branches (`if`, `while`, `for`), `else`
|
||||
//! | 12 | [`Group`]| Group expressions `(` [Expr] `)`
|
||||
//! | 12 | [`Block`]| Block expressions `{` [Expr] `}`
|
||||
//! | 12 | [`Final`]| Contains an [Identifier], [Literal](literal::Literal), [Block], or [Branch](control::Branch)
|
||||
//! | 1 | [`math::Ignore`] | Ignores the preceding sub-expression's result
|
||||
//! | 2 | [`math::Assign`] | Assignment
|
||||
//! | 3 | [`math::Compare`] | Value Comparison
|
||||
//! | 4 | [`math::Logic`] | Boolean And, Or, Xor
|
||||
//! | 5 | [`math::Bitwise`] | Bitwise And, Or, Xor
|
||||
//! | 6 | [`math::Shift`] | Shift Left/Right
|
||||
//! | 7 | [`math::Term`] | Add, Subtract
|
||||
//! | 8 | [`math::Factor`] | Multiply, Divide, Remainder
|
||||
//! | 9 | [`math::Unary`] | Unary Dereference, Reference, Negate, Not
|
||||
//! | 10 | [`control::Flow`] | Branch expressions (`if`, `while`, `for`, `return`, `break`, `continue`), `else`
|
||||
//! | 10 | [`Group`] | Group expressions `(` [Expr]? `)` /* Can evaluate to Empty! */
|
||||
//! | 10 | [`Block`] | Block expressions `{` [Expr] `}`
|
||||
//! | 10 | [`Primary`] | Contains an [Identifier], [Literal](literal::Literal), [Block], or [Flow](control::Flow)
|
||||
//!
|
||||
//! ## Syntax
|
||||
//! ```ignore
|
||||
//! Expr := control::Flow | math::Ignore
|
||||
//! Block := '{' Expr '}'
|
||||
//! Group := '(' Expr ')'
|
||||
//! Final := Identifier | Literal | Block | control::Branch
|
||||
//! Group := '(' Expr? ')'
|
||||
//! Primary := Identifier | Literal | Block | control::Branch
|
||||
//! ```
|
||||
//! See [control] and [math] for their respective production rules.
|
||||
use super::*;
|
||||
@ -407,28 +419,27 @@ pub mod expression {
|
||||
/// Contains an expression
|
||||
///
|
||||
/// # Syntax
|
||||
/// [`Expr`] := [`control::Flow`] | [`math::Ignore`]
|
||||
/// [`Expr`] := [`math::Ignore`]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Expr {
|
||||
Flow(control::Flow),
|
||||
Ignore(math::Ignore),
|
||||
}
|
||||
|
||||
/// A [Final] Expression is the expression with the highest precedence (i.e. the deepest
|
||||
/// A [Primary] Expression is the expression with the highest precedence (i.e. the deepest
|
||||
/// derivation)
|
||||
/// # Syntax
|
||||
/// [`Final`] :=
|
||||
/// [`Primary`] :=
|
||||
/// [`IDENTIFIER`](Identifier)
|
||||
/// | [`Literal`](literal::Literal)
|
||||
/// | [`Block`]
|
||||
/// | [`Branch`](control::Branch)
|
||||
/// | [`Branch`](control::Flow)
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Final {
|
||||
pub enum Primary {
|
||||
Identifier(Identifier),
|
||||
Literal(literal::Literal),
|
||||
Block(Block),
|
||||
Group(Group),
|
||||
Branch(control::Branch),
|
||||
Branch(control::Flow),
|
||||
}
|
||||
|
||||
/// Contains a Block Expression
|
||||
@ -436,15 +447,15 @@ pub mod expression {
|
||||
/// [`Block`] := `'{'` [`Expr`] `'}'`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Block {
|
||||
pub expr: Box<Expr>,
|
||||
pub expr: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
/// Contains a Parenthesized Expression
|
||||
/// # Syntax
|
||||
/// [`Group`] := `'('` [`Expr`] `')'`
|
||||
/// [`Group`] := `'('` [`Expr`]? `')'`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Group {
|
||||
pub expr: Box<Expr>,
|
||||
pub expr: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
pub mod math {
|
||||
@ -481,70 +492,82 @@ pub mod expression {
|
||||
//! Shift := Term (ShiftOp Term )*
|
||||
//! Term := Factor (TermOp Factor )*
|
||||
//! Factor := Unary (FactorOp Unary )*
|
||||
//! Unary := (UnaryOp)* Final
|
||||
//! Unary := (UnaryOp)* Primary
|
||||
//! ```
|
||||
use super::*;
|
||||
|
||||
/// Ignores the result of the left sub-expression.
|
||||
/// The template for [Binary] operations.
|
||||
/// # Syntax
|
||||
/// [`Binary`] := `First` (`Other`)*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Binary<First, Other> {
|
||||
pub first: Box<First>,
|
||||
pub other: Vec<Other>,
|
||||
}
|
||||
impl<First, Other> Binary<First, Other> {
|
||||
pub fn new(first: First, other: Vec<Other>) -> Self {
|
||||
Self { first: Box::new(first), other }
|
||||
}
|
||||
pub fn first(&self) -> &First {
|
||||
&self.first
|
||||
}
|
||||
pub fn other(&self) -> &[Other] {
|
||||
&self.other
|
||||
}
|
||||
}
|
||||
|
||||
/// Ignores the result of the leading sub-expression.
|
||||
/// Great if you only want the side-effects.
|
||||
/// # Syntax
|
||||
/// [`Ignore`] := [`Assign`] ([`operator::Ignore`] [`Assign`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Ignore(pub Assign, pub Vec<(operator::Ignore, Assign)>);
|
||||
pub type Ignore = Binary<Assign, (operator::Ignore, Assign)>;
|
||||
|
||||
/// Assigns the result of the right sub-expression to the left sub-expression.
|
||||
/// Assigns the result of the trailing sub-expression to the leading sub-expression.
|
||||
/// Resolves to the Empty type.
|
||||
/// # Syntax
|
||||
/// [`Assign`] := [`Compare`] ([`operator::Assign`] [`Compare`])?
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Assign(pub Compare, pub Vec<(operator::Assign, Compare)>);
|
||||
pub type Assign = Binary<Compare, (operator::Assign, Compare)>;
|
||||
|
||||
/// Compares the values of the right and left sub-expressions,
|
||||
/// Compares the values of the trailing and leading sub-expressions,
|
||||
/// and resolves to a boolean.
|
||||
/// # Syntax
|
||||
/// [`Compare`] := [`Logic`] ([`operator::Compare`] [`Logic`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Compare(pub Logic, pub Vec<(operator::Compare, Logic)>);
|
||||
pub type Compare = Binary<Logic, (operator::Compare, Logic)>;
|
||||
|
||||
/// Performs a boolean logic operation on the left and right sub-expressions.
|
||||
/// Performs a boolean logic operation on the leading and trailing sub-expressions.
|
||||
/// # Syntax
|
||||
/// [`Logic`] := [`Bitwise`] ([`operator::Logic`] [`Bitwise`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Logic(pub Bitwise, pub Vec<(operator::Logic, Bitwise)>);
|
||||
pub type Logic = Binary<Bitwise, (operator::Logic, Bitwise)>;
|
||||
|
||||
/// Performs a bitwise opration on the left and right sub-expressions.
|
||||
/// Performs a bitwise opration on the leading and trailing sub-expressions.
|
||||
/// # Syntax
|
||||
/// [`Bitwise`] := [`Shift`] ([`operator::Bitwise`] [`Shift`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Bitwise(pub Shift, pub Vec<(operator::Bitwise, Shift)>);
|
||||
pub type Bitwise = Binary<Shift, (operator::Bitwise, Shift)>;
|
||||
|
||||
/// Shifts the left sub-expression by the right sub-expression
|
||||
/// Shifts the leading sub-expression by the trailing sub-expression
|
||||
/// # Syntax
|
||||
/// [`Shift`] := [`Term`] ([`operator::Shift`] [`Term`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Shift(pub Term, pub Vec<(operator::Shift, Term)>);
|
||||
pub type Shift = Binary<Term, (operator::Shift, Term)>;
|
||||
|
||||
/// Adds or subtracts the right sub-expression from the left sub-expression
|
||||
/// Adds or subtracts the trailing sub-expression from the leading sub-expression
|
||||
/// # Syntax
|
||||
/// [`Term`] := [`Factor`] ([`operator::Term`] [`Factor`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Term(pub Factor, pub Vec<(operator::Term, Factor)>);
|
||||
pub type Term = Binary<Factor, (operator::Term, Factor)>;
|
||||
|
||||
/// Multiplies, Divides, or finds the remainder of the right sub-expression
|
||||
/// from the left sub-expression
|
||||
/// Multiplies, Divides, or finds the remainder of the trailing sub-expression
|
||||
/// from the leading sub-expression
|
||||
/// # Syntax
|
||||
/// [`Factor`] := [`Unary`] ([`operator::Factor`] [`Unary`])*
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Factor(pub Unary, pub Vec<(operator::Factor, Unary)>);
|
||||
pub type Factor = Binary<Unary, (operator::Factor, Unary)>;
|
||||
|
||||
/// Performs a unary operation on the right sub-expression.
|
||||
/// Performs a unary operation on the trailing sub-expression.
|
||||
/// # Syntax
|
||||
/// [`Unary`] := ([`operator::Unary`])* [`Final`]
|
||||
/// [`Unary`] := ([`operator::Unary`])* [`Primary`]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Unary(pub Vec<operator::Unary>, pub Final);
|
||||
pub struct Unary(pub Vec<operator::Unary>, pub Primary);
|
||||
|
||||
pub mod operator {
|
||||
//! | # | Operators | Associativity
|
||||
//! | # | [Operators](Operator) | Associativity
|
||||
//! |---|---------------------------------------|--------------
|
||||
//! | 0 | ([Unary]) `*`, `&`, `-`, `!` | Left to Right
|
||||
//! | 1 | `*`, `/`, `%` | Left to Right
|
||||
@ -560,22 +583,22 @@ pub mod expression {
|
||||
//! | 8 | `;` |
|
||||
use crate::token::Type;
|
||||
/// Defines an operator enum and a conversion
|
||||
macro operator ($($(#[$doc:meta])* $T:ident {
|
||||
$( $v:ident := $tty:pat ),*$(,)?
|
||||
})*) {$(
|
||||
#[doc = concat!("[`",stringify!($T),"`](super::",stringify!($T),") operators")]
|
||||
macro operator ($(
|
||||
$(#[$doc:meta])* $T:ident { $( $v:ident := $tty:pat ),*$(,)? }
|
||||
)*) {
|
||||
$(#[doc = concat!("[`",stringify!($T),"`](super::",stringify!($T),") operators")]
|
||||
$(#[$doc])* #[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum $T { $($v,)* }
|
||||
impl From<Type> for Option<$T> {
|
||||
fn from(value: Type) -> Option<$T> {
|
||||
match value { $($tty => Some(<$T>::$v),)* _ => None }
|
||||
}
|
||||
})*
|
||||
}
|
||||
)*}
|
||||
|
||||
operator! {
|
||||
/// (`*`, `&`, `-`, `!`)
|
||||
/// (`*`, `&`, `-`, `!`, `@`, `#`, `~`)
|
||||
Unary {
|
||||
RefRef := Type::AmpAmp,
|
||||
Deref := Type::Star,
|
||||
Ref := Type::Amp,
|
||||
Neg := Type::Minus,
|
||||
@ -685,28 +708,23 @@ pub mod expression {
|
||||
//! [4]: Else
|
||||
//! [5]: Break
|
||||
//! [6]: Return
|
||||
//! [7]: Flow::Continue
|
||||
//! [7]: Continue
|
||||
use super::*;
|
||||
|
||||
/// Contains a [ConditionalBranch Expression](control).
|
||||
/// Contains a [Control Flow Expression](control).
|
||||
///
|
||||
/// [While], [If], [For]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Branch {
|
||||
While(While),
|
||||
If(If),
|
||||
For(For),
|
||||
}
|
||||
|
||||
/// Contains an [Unconditional Branch Expression](control).
|
||||
/// See the module-level documentation for more information.
|
||||
///
|
||||
/// [Continue](Flow::Continue), [Return], [Break]
|
||||
/// [While], [If], [For], [Continue], [Return], or [Break]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Flow {
|
||||
/// Represents a [`continue` expression](Flow::Continue)
|
||||
///
|
||||
/// # Syntax
|
||||
/// [`Flow::Continue`] := `"continue"`
|
||||
/// Represents a [`while` expression](While)
|
||||
While(While),
|
||||
/// Represents a [`if` expression](If)
|
||||
If(If),
|
||||
/// Represents a [`for` expression](For)
|
||||
For(For),
|
||||
/// Represents a [`continue` expression](Continue)
|
||||
Continue(Continue),
|
||||
/// Represents a [`return` expression](Return)
|
||||
Return(Return),
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Conlang is an expression-based programming language with similarities to Rust
|
||||
#![warn(clippy::all)]
|
||||
#![feature(decl_macro)]
|
||||
|
||||
pub mod token;
|
||||
|
||||
pub mod ast;
|
||||
|
@ -1,10 +1,12 @@
|
||||
//! Parses [tokens](super::token) into an [AST](super::ast)
|
||||
use std::vec;
|
||||
|
||||
use super::{
|
||||
ast::preamble::*,
|
||||
lexer::Lexer,
|
||||
token::{Keyword, Token, Type},
|
||||
};
|
||||
use error::{Error, *};
|
||||
use error::{Error, Reason::*, *};
|
||||
|
||||
mod error {
|
||||
use super::{Token, Type};
|
||||
@ -15,6 +17,7 @@ mod error {
|
||||
NotIdentifier,
|
||||
NotLiteral,
|
||||
NotString,
|
||||
NotChar,
|
||||
NotBool,
|
||||
NotFloat,
|
||||
FloatExponentOverflow,
|
||||
@ -46,6 +49,9 @@ mod error {
|
||||
pub fn token(self, start: Token) -> Self {
|
||||
Self { start: Some(start), ..self }
|
||||
}
|
||||
pub fn maybe_token(self, start: Option<Token>) -> Self {
|
||||
Self { start, ..self }
|
||||
}
|
||||
pub fn start(&self) -> Option<Token> {
|
||||
self.start
|
||||
}
|
||||
@ -57,6 +63,7 @@ mod error {
|
||||
not_identifier: NotIdentifier,
|
||||
not_literal: NotLiteral,
|
||||
not_string: NotString,
|
||||
not_char: NotChar,
|
||||
not_bool: NotBool,
|
||||
not_float: NotFloat,
|
||||
float_exponent_overflow: FloatExponentOverflow,
|
||||
@ -113,14 +120,6 @@ impl<'t> Parser<'t> {
|
||||
pub fn peek(&self) -> Option<&Token> {
|
||||
self.tokens.get(self.curr)
|
||||
}
|
||||
/// Look ahead `n` tokens
|
||||
pub fn ahead(&self, n: usize) -> Option<&Token> {
|
||||
self.tokens.get(self.curr.wrapping_add(n))
|
||||
}
|
||||
/// Look behind `n` tokens
|
||||
pub fn behind(&self, n: usize) -> Option<&Token> {
|
||||
self.tokens.get(self.curr.wrapping_sub(n))
|
||||
}
|
||||
/// Records the current position on the panic stack
|
||||
pub fn mark(&mut self) -> &mut Self {
|
||||
self.panic_stack.push(self.curr);
|
||||
@ -175,9 +174,9 @@ impl<'t> Parser<'t> {
|
||||
fn delimited<F, R>(&mut self, lhs: Type, mid: F, rhs: Type) -> PResult<R>
|
||||
where F: Fn(&mut Self) -> PResult<R> {
|
||||
self.consume_type(lhs)?;
|
||||
let out = mid(self);
|
||||
let out = mid(self)?;
|
||||
self.consume_type(rhs)?;
|
||||
out
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
macro ptodo_err($self:expr $(, $t:expr)*) {
|
||||
@ -195,7 +194,10 @@ fn check_eof(t: Option<&Token>) -> PResult<&Token> {
|
||||
/// # Terminals and Pseudo-Terminals
|
||||
impl<'t> Parser<'t> {
|
||||
pub fn identifier(&mut self) -> PResult<Identifier> {
|
||||
let range = self.matches(Type::Identifier)?.range();
|
||||
let range = self
|
||||
.matches(Type::Identifier)
|
||||
.map_err(|e| Error::not_identifier().maybe_token(e.start()))?
|
||||
.range();
|
||||
Ok(Identifier(self.consume().text[range].into()))
|
||||
}
|
||||
pub fn literal(&mut self) -> PResult<literal::Literal> {
|
||||
@ -204,7 +206,7 @@ impl<'t> Parser<'t> {
|
||||
let tok = check_eof(self.peek())?;
|
||||
match tok.ty() {
|
||||
Type::Float => self.float().map(Float),
|
||||
Type::Integer => self.int().map(Int),
|
||||
Type::Integer => self.int::<10>().map(Int),
|
||||
Type::String => self.string().map(String),
|
||||
Type::Character => self.char().map(Char),
|
||||
Type::Keyword(True | False) => self.bool().map(Bool),
|
||||
@ -227,7 +229,11 @@ impl<'t> Parser<'t> {
|
||||
Ok(self.consume().text[range].into())
|
||||
}
|
||||
pub fn char(&mut self) -> PResult<char> {
|
||||
ptodo!(self)
|
||||
let token = *self.matches(Type::Character)?;
|
||||
self.consume().text[&token]
|
||||
.chars()
|
||||
.next()
|
||||
.ok_or(Error::not_char().token(token))
|
||||
}
|
||||
pub fn bool(&mut self) -> PResult<bool> {
|
||||
use Keyword::{False, True};
|
||||
@ -245,26 +251,41 @@ impl<'t> Parser<'t> {
|
||||
impl<'t> Parser<'t> {
|
||||
pub fn expr(&mut self) -> PResult<expression::Expr> {
|
||||
use expression::Expr;
|
||||
self.flow()
|
||||
.map(Expr::Flow)
|
||||
.or_else(|_| self.ignore().map(Expr::Ignore))
|
||||
self.ignore().map(Expr::Ignore)
|
||||
}
|
||||
pub fn if_not_expr(&mut self, matches: Type) -> PResult<Option<expression::Expr>> {
|
||||
if check_eof(self.peek())?.ty() == matches {
|
||||
Ok(None)
|
||||
} else {
|
||||
Some(self.expr()).transpose()
|
||||
}
|
||||
}
|
||||
pub fn block(&mut self) -> PResult<expression::Block> {
|
||||
self.delimited(Type::LCurly, Parser::expr, Type::RCurly)
|
||||
.map(|e| expression::Block { expr: Box::new(e) })
|
||||
self.delimited(Type::LCurly, |p| p.if_not_expr(Type::RCurly), Type::RCurly)
|
||||
.map(|e| expression::Block { expr: e.map(Box::new) })
|
||||
}
|
||||
pub fn group(&mut self) -> PResult<expression::Group> {
|
||||
self.delimited(Type::LParen, Parser::expr, Type::RParen)
|
||||
.map(|e| expression::Group { expr: Box::new(e) })
|
||||
let t = check_eof(self.consume_type(Type::LParen)?.peek())?;
|
||||
match t.ty() {
|
||||
Type::RParen => {
|
||||
self.consume();
|
||||
Ok(expression::Group { expr: None })
|
||||
}
|
||||
pub fn r#final(&mut self) -> PResult<expression::Final> {
|
||||
use expression::Final;
|
||||
_ => {
|
||||
let out = self.expr().map(|expr| expression::Group {expr: Some(expr.into())});
|
||||
self.consume_type(Type::RParen)?;
|
||||
out
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn primary(&mut self) -> PResult<expression::Primary> {
|
||||
use expression::Primary;
|
||||
self.identifier()
|
||||
.map(Final::Identifier)
|
||||
.or_else(|_| self.literal().map(Final::Literal))
|
||||
.or_else(|_| self.block().map(Final::Block))
|
||||
.or_else(|_| self.group().map(Final::Group))
|
||||
.or_else(|_| self.branch().map(Final::Branch))
|
||||
.map(Primary::Identifier)
|
||||
.or_else(|_| self.literal().map(Primary::Literal))
|
||||
.or_else(|_| self.block().map(Primary::Block))
|
||||
.or_else(|_| self.group().map(Primary::Group))
|
||||
.or_else(|_| self.flow().map(Primary::Branch))
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,7 +295,7 @@ impl<'t> Parser<'t> {
|
||||
/// ```
|
||||
/// # Examples
|
||||
/// ```rust,ignore
|
||||
/// math_impl!{
|
||||
/// binary!{
|
||||
/// function_name: ret::Value = parse_operands, parse_operators;
|
||||
/// }
|
||||
/// ```
|
||||
@ -282,18 +303,18 @@ impl<'t> Parser<'t> {
|
||||
/// ```rust,ignore
|
||||
/// pub fn function_name(&mut self) -> PResult<ret::Value> { ... }
|
||||
/// ```
|
||||
macro math_impl ($($f: ident: $Ret:path = $a:ident, $b:ident);*$(;)?) {$(
|
||||
macro binary ($($f:ident: $Ret:ty = $a:ident, $b:ident);*$(;)?) {$(
|
||||
pub fn $f (&mut self) -> PResult<$Ret> {
|
||||
let (first, mut others) = (self.$a()?, vec![]);
|
||||
while let Some(op) = self.$b() {
|
||||
others.push((op, self.$a()?));
|
||||
}
|
||||
Ok($Ret(first, others))
|
||||
Ok(<$Ret>::new(first, others))
|
||||
}
|
||||
)*}
|
||||
/// # [Arithmetic and Logical Subexpressions](math)
|
||||
impl<'t> Parser<'t> {
|
||||
math_impl! {
|
||||
binary! {
|
||||
//name returns operands operators
|
||||
ignore: math::Ignore = assign, ignore_op;
|
||||
assign: math::Assign = compare, assign_op;
|
||||
@ -309,7 +330,7 @@ impl<'t> Parser<'t> {
|
||||
while let Some(op) = self.unary_op() {
|
||||
ops.push(op)
|
||||
}
|
||||
Ok(math::Unary(ops, self.r#final()?))
|
||||
Ok(math::Unary(ops, self.primary()?))
|
||||
}
|
||||
}
|
||||
macro operator_impl($($(#[$m:meta])*$f:ident: $Ret:ty),*$(,)*) {$(
|
||||
@ -335,19 +356,22 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
/// # [Control Flow](control)
|
||||
impl<'t> Parser<'t> {
|
||||
pub fn branch(&mut self) -> PResult<control::Branch> {
|
||||
use control::Branch;
|
||||
use Keyword::{For, If, While};
|
||||
pub fn flow(&mut self) -> PResult<control::Flow> {
|
||||
use control::Flow;
|
||||
use Keyword::{Break, Continue, For, If, Return, While};
|
||||
let token = check_eof(self.peek())?;
|
||||
match token.ty() {
|
||||
Type::Keyword(While) => self.parse_while().map(Branch::While),
|
||||
Type::Keyword(For) => self.parse_for().map(Branch::For),
|
||||
Type::Keyword(If) => self.parse_if().map(Branch::If),
|
||||
Type::Keyword(While) => self.parse_while().map(Flow::While),
|
||||
Type::Keyword(For) => self.parse_for().map(Flow::For),
|
||||
Type::Keyword(If) => self.parse_if().map(Flow::If),
|
||||
Type::Keyword(Break) => self.parse_break().map(Flow::Break),
|
||||
Type::Keyword(Return) => self.parse_return().map(Flow::Return),
|
||||
Type::Keyword(Continue) => self.parse_continue().map(Flow::Continue),
|
||||
_ => Err(Error::not_branch().token(*token)),
|
||||
}
|
||||
}
|
||||
pub fn parse_if(&mut self) -> PResult<control::If> {
|
||||
self.consume_type(Type::Keyword(Keyword::If))?;
|
||||
self.keyword(Keyword::If)?;
|
||||
Ok(control::If {
|
||||
cond: self.expr()?.into(),
|
||||
body: self.block()?,
|
||||
@ -355,7 +379,7 @@ impl<'t> Parser<'t> {
|
||||
})
|
||||
}
|
||||
pub fn parse_while(&mut self) -> PResult<control::While> {
|
||||
self.consume_type(Type::Keyword(Keyword::While))?;
|
||||
self.keyword(Keyword::While)?;
|
||||
Ok(control::While {
|
||||
cond: self.expr()?.into(),
|
||||
body: self.block()?,
|
||||
@ -373,21 +397,10 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
pub fn parse_else(&mut self) -> PResult<Option<control::Else>> {
|
||||
// it's fine for `else` to be missing entirely
|
||||
match self.keyword(Keyword::Else) {
|
||||
Ok(_) => Ok(Some(control::Else { block: self.block()? })),
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
pub fn flow(&mut self) -> PResult<control::Flow> {
|
||||
use control::Flow;
|
||||
use Keyword::{Break, Continue, Return};
|
||||
let token = check_eof(self.peek())?;
|
||||
match token.ty() {
|
||||
Type::Keyword(Break) => self.parse_break().map(Flow::Break),
|
||||
Type::Keyword(Return) => self.parse_return().map(Flow::Return),
|
||||
Type::Keyword(Continue) => self.parse_continue().map(Flow::Continue),
|
||||
_ => Err(Error::not_control_flow().token(*token)),
|
||||
}
|
||||
self.keyword(Keyword::Else)
|
||||
.ok()
|
||||
.map(|p| Ok(control::Else { block: p.block()? }))
|
||||
.transpose()
|
||||
}
|
||||
pub fn parse_break(&mut self) -> PResult<control::Break> {
|
||||
Ok(control::Break { expr: self.keyword(Keyword::Break)?.expr()?.into() })
|
||||
|
@ -46,6 +46,9 @@ impl<W: Write> Printer<W> {
|
||||
write!(self.writer, "{d}")?;
|
||||
Ok(self)
|
||||
}
|
||||
fn space(&mut self) -> IOResult<&mut Self> {
|
||||
write!(self.writer, " ").map(|_| self)
|
||||
}
|
||||
/// Increase the indentation level by 1
|
||||
fn indent(&mut self) -> &mut Self {
|
||||
self.level += 1;
|
||||
@ -56,58 +59,34 @@ impl<W: Write> Printer<W> {
|
||||
self
|
||||
}
|
||||
}
|
||||
macro visit_math($self:expr, $expr:expr) {{
|
||||
$expr.0.walk($self)?;
|
||||
for (op, target) in &$expr.1 {
|
||||
op.walk($self)?;
|
||||
target.walk($self)?;
|
||||
macro visit_operator($self:ident.$op:expr) {
|
||||
$self.space()?.put($op)?.space().map(drop)
|
||||
}
|
||||
Ok(())
|
||||
}}
|
||||
impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||
fn visit_ignore(&mut self, expr: &math::Ignore) -> IOResult<()> {
|
||||
expr.0.walk(self)?;
|
||||
for (op, target) in &expr.1 {
|
||||
fn visit_binary<F, Op>(&mut self, expr: &math::Binary<F, (Op, F)>) -> IOResult<()>
|
||||
where
|
||||
F: Walk<Self, IOResult<()>>,
|
||||
Op: Walk<Self, IOResult<()>>,
|
||||
{
|
||||
expr.first().walk(self)?;
|
||||
for (op, target) in expr.other() {
|
||||
op.walk(self)?;
|
||||
target.walk(self.newline()?)?;
|
||||
target.walk(self)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_assign(&mut self, expr: &math::Assign) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
fn visit_compare(&mut self, expr: &math::Compare) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
fn visit_logic(&mut self, expr: &math::Logic) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
fn visit_bitwise(&mut self, expr: &math::Bitwise) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
fn visit_shift(&mut self, expr: &math::Shift) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
fn visit_term(&mut self, expr: &math::Term) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
fn visit_factor(&mut self, expr: &math::Factor) -> IOResult<()> {
|
||||
visit_math!(self, expr)
|
||||
}
|
||||
|
||||
fn visit_unary(&mut self, expr: &math::Unary) -> IOResult<()> {
|
||||
for op in &expr.0 {
|
||||
op.walk(self)?;
|
||||
}
|
||||
expr.1.walk(self)
|
||||
}
|
||||
fn visit_ignore_op(&mut self, op: &operator::Ignore) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
operator::Ignore::Ignore => "\x08;",
|
||||
})
|
||||
.map(drop)
|
||||
fn visit_ignore_op(&mut self, _op: &operator::Ignore) -> IOResult<()> {
|
||||
self.put(";")?.newline().map(drop)
|
||||
}
|
||||
fn visit_compare_op(&mut self, op: &operator::Compare) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!(self.match op {
|
||||
operator::Compare::Less => "<",
|
||||
operator::Compare::LessEq => "<=",
|
||||
operator::Compare::Equal => "==",
|
||||
@ -115,10 +94,9 @@ impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||
operator::Compare::GreaterEq => ">=",
|
||||
operator::Compare::Greater => ">",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_assign_op(&mut self, op: &operator::Assign) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!( self.match op {
|
||||
operator::Assign::Assign => "=",
|
||||
operator::Assign::AddAssign => "+=",
|
||||
operator::Assign::SubAssign => "-=",
|
||||
@ -130,48 +108,43 @@ impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||
operator::Assign::ShlAssign => "<<=",
|
||||
operator::Assign::ShrAssign => ">>=",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_logic_op(&mut self, op: &operator::Logic) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!(self.match op {
|
||||
operator::Logic::LogAnd => "&&",
|
||||
operator::Logic::LogOr => "||",
|
||||
operator::Logic::LogXor => "^^",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_bitwise_op(&mut self, op: &operator::Bitwise) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!(self.match op {
|
||||
operator::Bitwise::BitAnd => "&",
|
||||
operator::Bitwise::BitOr => "|",
|
||||
operator::Bitwise::BitXor => "^",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_shift_op(&mut self, op: &operator::Shift) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!(self.match op {
|
||||
operator::Shift::Lsh => "<<",
|
||||
operator::Shift::Rsh => ">>",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_term_op(&mut self, op: &operator::Term) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!(self.match op {
|
||||
operator::Term::Add => "+",
|
||||
operator::Term::Sub => "-",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_factor_op(&mut self, op: &operator::Factor) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
visit_operator!(self.match op {
|
||||
operator::Factor::Mul => "*",
|
||||
operator::Factor::Div => "/",
|
||||
operator::Factor::Rem => "%",
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
fn visit_unary_op(&mut self, op: &operator::Unary) -> IOResult<()> {
|
||||
self.put(match op {
|
||||
operator::Unary::RefRef => "&&",
|
||||
operator::Unary::Deref => "*",
|
||||
operator::Unary::Ref => "&",
|
||||
operator::Unary::Neg => "-",
|
||||
@ -184,42 +157,41 @@ impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||
}
|
||||
|
||||
fn visit_if(&mut self, expr: &control::If) -> IOResult<()> {
|
||||
expr.cond.walk(self.put("if")?)?;
|
||||
expr.body.walk(self)?;
|
||||
expr.cond.walk(self.put("if")?.space()?)?;
|
||||
expr.body.walk(self.space()?)?;
|
||||
if let Some(e) = &expr.else_ {
|
||||
e.walk(self)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_while(&mut self, expr: &control::While) -> IOResult<()> {
|
||||
expr.cond.walk(self.put("while")?)?;
|
||||
expr.body.walk(self)?;
|
||||
expr.cond.walk(self.put("while")?.space()?)?;
|
||||
expr.body.walk(self.space()?)?;
|
||||
if let Some(e) = &expr.else_ {
|
||||
e.walk(self)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_for(&mut self, expr: &control::For) -> IOResult<()> {
|
||||
expr.var.walk(self.put("for")?)?;
|
||||
expr.iter.walk(self.put("in")?)?;
|
||||
expr.body.walk(self)?;
|
||||
self.visit_block(&expr.body)?;
|
||||
expr.var.walk(self.put("for")?.space()?)?;
|
||||
expr.iter.walk(self.space()?.put("in")?.space()?)?;
|
||||
expr.body.walk(self.space()?)?;
|
||||
if let Some(e) = &expr.else_ {
|
||||
e.walk(self)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn visit_else(&mut self, expr: &control::Else) -> IOResult<()> {
|
||||
expr.block.walk(self.put("else")?)
|
||||
expr.block.walk(self.space()?.put("else")?.space()?)
|
||||
}
|
||||
fn visit_continue(&mut self, _expr: &control::Continue) -> IOResult<()> {
|
||||
self.put("continue").map(drop)
|
||||
}
|
||||
fn visit_break(&mut self, expr: &control::Break) -> IOResult<()> {
|
||||
expr.expr.walk(self.put("break")?)
|
||||
expr.expr.walk(self.put("break")?.space()?)
|
||||
}
|
||||
fn visit_return(&mut self, expr: &control::Return) -> IOResult<()> {
|
||||
expr.expr.walk(self.put("return")?)
|
||||
expr.expr.walk(self.put("return")?.space()?)
|
||||
}
|
||||
|
||||
fn visit_identifier(&mut self, ident: &Identifier) -> IOResult<()> {
|
||||
@ -229,7 +201,7 @@ impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||
self.put("\"")?.put(string)?.put("\"").map(drop)
|
||||
}
|
||||
fn visit_char_literal(&mut self, char: &char) -> IOResult<()> {
|
||||
self.put(char).map(drop)
|
||||
self.put("'")?.put(char)?.put("'").map(drop)
|
||||
}
|
||||
fn visit_bool_literal(&mut self, bool: &bool) -> IOResult<()> {
|
||||
self.put(bool).map(drop)
|
||||
@ -243,15 +215,28 @@ impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
||||
fn visit_int_literal(&mut self, int: &u128) -> IOResult<()> {
|
||||
self.put(int).map(drop)
|
||||
}
|
||||
fn visit_empty(&mut self) -> IOResult<()> {
|
||||
self.put("").map(drop)
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, expr: &expression::Block) -> IOResult<()> {
|
||||
self.put('{')?.indent().newline()?.visit_expr(&expr.expr)?;
|
||||
self.dedent().newline()?.put('}').map(drop)
|
||||
self.put('{')?;
|
||||
match &expr.expr {
|
||||
Some(expr) => {
|
||||
expr.walk(self.indent().newline()?)?;
|
||||
self.dedent().newline()?;
|
||||
}
|
||||
None => ().walk(self.space()?)?,
|
||||
}
|
||||
self.put('}').map(drop)
|
||||
}
|
||||
|
||||
fn visit_group(&mut self, expr: &expression::Group) -> IOResult<()> {
|
||||
self.put('(')?;
|
||||
self.visit_expr(&expr.expr)?;
|
||||
self.put(')').map(drop)
|
||||
self.put('(')?.space()?;
|
||||
match &expr.expr {
|
||||
Some(expr) => expr.walk(self),
|
||||
None => ().walk(self),
|
||||
}?;
|
||||
self.space()?.put(')').map(drop)
|
||||
}
|
||||
}
|
||||
|
@ -132,3 +132,10 @@ impl Token {
|
||||
self.head..self.tail
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Index<&Token> for str {
|
||||
type Output = str;
|
||||
fn index(&self, index: &Token) -> &Self::Output {
|
||||
&self[index.range()]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user