AST: Refactor binary operations, fix Walk trait
- Unified math operations into a single self-referential enum - Walk now visits the children of a node, rather than the node itself - The old behavior was super confusing, and led to numerous stack overflows.
This commit is contained in:
@@ -26,82 +26,120 @@ pub mod preamble {
|
||||
|
||||
mod visitor {
|
||||
use super::{
|
||||
expression::{control::*, math::*, Block, *},
|
||||
expression::{
|
||||
control::*,
|
||||
math::{operator::*, *},
|
||||
Block, *,
|
||||
},
|
||||
literal::*,
|
||||
*,
|
||||
};
|
||||
/// [Walk] is the lexical inverse of [Visitor]
|
||||
/// [Walk] traverses the AST, calling [`Visitor::visit_*()`](Visitor) on all the nodes
|
||||
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;
|
||||
}
|
||||
pub mod walker {
|
||||
use super::*;
|
||||
macro_rules! impl_walk {
|
||||
($($T:ty => $f:ident),*$(,)?) => {
|
||||
$(impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for $T {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
visitor.$f(self)
|
||||
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(())
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
impl_walk! {
|
||||
// ast
|
||||
Start => visit,
|
||||
// grouped expr
|
||||
Block => visit_block,
|
||||
Group => visit_group,
|
||||
// Identifier
|
||||
Identifier => visit_identifier,
|
||||
// ast::literal
|
||||
str => visit_string_literal,
|
||||
char => visit_char_literal,
|
||||
bool => visit_bool_literal,
|
||||
u128 => visit_int_literal,
|
||||
Float => visit_float_literal,
|
||||
// ast::math
|
||||
Ignore => visit_ignore,
|
||||
Assign => visit_assign,
|
||||
Compare => visit_compare,
|
||||
Logic => visit_logic,
|
||||
Bitwise => visit_bitwise,
|
||||
Shift => visit_shift,
|
||||
Term => visit_term,
|
||||
Factor => visit_factor,
|
||||
Unary => visit_unary,
|
||||
// ast::math::operator
|
||||
operator::Ignore => visit_ignore_op,
|
||||
operator::Compare => visit_compare_op,
|
||||
operator::Assign => visit_assign_op,
|
||||
operator::Logic => visit_logic_op,
|
||||
operator::Bitwise => visit_bitwise_op,
|
||||
operator::Shift => visit_shift_op,
|
||||
operator::Term => visit_term_op,
|
||||
operator::Factor => visit_factor_op,
|
||||
operator::Unary => visit_unary_op,
|
||||
// ast::control::Branch
|
||||
While => visit_while,
|
||||
If => visit_if,
|
||||
For => visit_for,
|
||||
Else => visit_else,
|
||||
// ast::control::Flow
|
||||
Continue => visit_continue,
|
||||
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()
|
||||
Operation::Unary { operators, operand } => {
|
||||
for op in operators {
|
||||
visitor.visit_unary_op(op)?;
|
||||
}
|
||||
visitor.visit_primary(operand)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Expr {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
visitor.visit_ignore(&self.ignore)
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Primary {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
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),
|
||||
@@ -111,8 +149,8 @@ mod visitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Literal {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
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),
|
||||
@@ -122,8 +160,8 @@ mod visitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Flow {
|
||||
fn walk(&self, visitor: &mut T) -> R {
|
||||
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),
|
||||
@@ -144,15 +182,12 @@ mod visitor {
|
||||
|
||||
/// Visit an [Expression](Expr)
|
||||
fn visit_expr(&mut self, expr: &Expr) -> R {
|
||||
expr.walk(self)
|
||||
self.visit_operation(&expr.ignore)
|
||||
}
|
||||
// Block expression
|
||||
/// Visit a [Block] expression
|
||||
fn visit_block(&mut self, expr: &Block) -> R {
|
||||
match &expr.expr {
|
||||
Some(expr) => self.visit_expr(expr),
|
||||
None => self.visit_empty(),
|
||||
}
|
||||
self.visit_expr(&expr.expr)
|
||||
}
|
||||
/// Visit a [Group] expression
|
||||
fn visit_group(&mut self, group: &Group) -> R {
|
||||
@@ -163,73 +198,39 @@ mod visitor {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit an [Assign] expression
|
||||
fn visit_assign(&mut self, expr: &Assign) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Compare] expression
|
||||
fn visit_compare(&mut self, expr: &Compare) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Logic] expression
|
||||
fn visit_logic(&mut self, expr: &Logic) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Bitwise] expression
|
||||
fn visit_bitwise(&mut self, expr: &Bitwise) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Shift] expression
|
||||
fn visit_shift(&mut self, expr: &Shift) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Term] expression
|
||||
fn visit_term(&mut self, expr: &Term) -> R {
|
||||
self.visit_binary(expr)
|
||||
}
|
||||
/// Visit a [Factor] expression
|
||||
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 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 {
|
||||
expr.walk(self)
|
||||
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),
|
||||
}
|
||||
}
|
||||
// Math operators
|
||||
/// Visit an [Ignore] [operator](operator::Ignore)
|
||||
fn visit_ignore_op(&mut self, op: &operator::Ignore) -> R;
|
||||
/// Visit a [Compare] [operator](operator::Compare)
|
||||
fn visit_compare_op(&mut self, op: &operator::Compare) -> R;
|
||||
/// Visit an [Assign] [operator](operator::Assign)
|
||||
fn visit_assign_op(&mut self, op: &operator::Assign) -> R;
|
||||
/// Visit a [Logic] [operator](operator::Logic)
|
||||
fn visit_logic_op(&mut self, op: &operator::Logic) -> R;
|
||||
/// Visit a [Bitwise] [operator](operator::Bitwise)
|
||||
fn visit_bitwise_op(&mut self, op: &operator::Bitwise) -> R;
|
||||
/// Visit a [Shift] [operator](operator::Shift)
|
||||
fn visit_shift_op(&mut self, op: &operator::Shift) -> R;
|
||||
/// Visit a [Term] [operator](operator::Term)
|
||||
fn visit_term_op(&mut self, op: &operator::Term) -> R;
|
||||
/// Visit a [Factor] [operator](operator::Factor)
|
||||
fn visit_factor_op(&mut self, op: &operator::Factor) -> R;
|
||||
/// Visit a [Unary] [operator](operator::Unary)
|
||||
fn visit_unary_op(&mut self, op: &operator::Unary) -> R;
|
||||
|
||||
/// Visit a [Flow] expression.
|
||||
///
|
||||
/// [Flow] := [While] | [If] | [For]
|
||||
fn visit_branch_expr(&mut self, expr: &Flow) -> R {
|
||||
expr.walk(self)
|
||||
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;
|
||||
@@ -253,7 +254,13 @@ mod visitor {
|
||||
///
|
||||
/// [Literal] := [String] | [char] | [bool] | [Float] | [u128]
|
||||
fn visit_literal(&mut self, literal: &Literal) -> R {
|
||||
literal.walk(self)
|
||||
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;
|
||||
@@ -265,7 +272,8 @@ mod visitor {
|
||||
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 literal
|
||||
|
||||
/// Visit an Empty
|
||||
fn visit_empty(&mut self) -> R;
|
||||
}
|
||||
}
|
||||
@@ -390,19 +398,19 @@ pub mod expression {
|
||||
//! | # | Node | Function
|
||||
//! |----|------------------:|:----------------------------------------------
|
||||
//! | 0 | [`Expr`] | Contains an expression
|
||||
//! | 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
|
||||
//! | 1 | [`Ignore`](math) | Ignores the preceding sub-expression's result
|
||||
//! | 2 | [`Assign`](math) | Assignment
|
||||
//! | 3 | [`Compare`](math) | Value Comparison
|
||||
//! | 4 | [`Logic`](math) | Boolean And, Or, Xor
|
||||
//! | 5 | [`Bitwise`](math) | Bitwise And, Or, Xor
|
||||
//! | 6 | [`Shift`](math) | Shift Left/Right
|
||||
//! | 7 | [`Term`](math) | Add, Subtract
|
||||
//! | 8 | [`Factor`](math) | Multiply, Divide, Remainder
|
||||
//! | 9 | [`Unary`](math) | 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)
|
||||
//! | 10 | [`Primary`] | Contains an [Identifier], [Literal](literal::Literal), [Block], [Group], or [Flow](control::Flow)
|
||||
//!
|
||||
//! ## Syntax
|
||||
//! ```ignore
|
||||
@@ -417,10 +425,10 @@ pub mod expression {
|
||||
/// Contains an expression
|
||||
///
|
||||
/// # Syntax
|
||||
/// [`Expr`] := [`math::Ignore`]
|
||||
/// [`Expr`] := [`math::Operation`]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Expr {
|
||||
pub ignore: math::Ignore,
|
||||
pub ignore: math::Operation,
|
||||
}
|
||||
|
||||
/// A [Primary] Expression is the expression with the highest precedence (i.e. the deepest
|
||||
@@ -430,6 +438,7 @@ pub mod expression {
|
||||
/// [`IDENTIFIER`](Identifier)
|
||||
/// | [`Literal`](literal::Literal)
|
||||
/// | [`Block`]
|
||||
/// | [`Group`]
|
||||
/// | [`Branch`](control::Flow)
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Primary {
|
||||
@@ -445,7 +454,7 @@ pub mod expression {
|
||||
/// [`Block`] := `'{'` [`Expr`] `'}'`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Block {
|
||||
pub expr: Option<Box<Expr>>,
|
||||
pub expr: Box<Expr>,
|
||||
}
|
||||
|
||||
/// Contains a Parenthesized Expression
|
||||
@@ -466,23 +475,24 @@ pub mod expression {
|
||||
//! | # | Name | Operators | Associativity
|
||||
//! |---|----------:|:--------------------------------------|---------------
|
||||
// | | TODO: Try | `?` |
|
||||
//! | 1 | [Unary] | `*` `&` `-` `!` | Right
|
||||
//! | 2 | [Factor] | `*` `/` `%` | Left to Right
|
||||
//! | 3 | [Term] | `+` `-` | Left to Right
|
||||
//! | 4 | [Shift] | `<<` `>>` | Left to Right
|
||||
//! | 5 | [Bitwise] | `&` <code>|</code> | Left to Right
|
||||
//! | 6 | [Logic] | `&&` <code>||</code> `^^` | Left to Right
|
||||
//! | 7 | [Compare] | `<` `<=` `==` `!=` `>=` `>` | Left to Right
|
||||
//! | 1 | Unary | `*` `&` `-` `!` | Right
|
||||
//! | 2 | Factor | `*` `/` `%` | Left to Right
|
||||
//! | 3 | Term | `+` `-` | Left to Right
|
||||
//! | 4 | Shift | `<<` `>>` | Left to Right
|
||||
//! | 5 | Bitwise | `&` <code>|</code> | Left to Right
|
||||
//! | 6 | Logic | `&&` <code>||</code> `^^` | Left to Right
|
||||
//! | 7 | Compare | `<` `<=` `==` `!=` `>=` `>` | Left to Right
|
||||
#![doc = concat!( //| |
|
||||
r" | 8 | [Assign] |", r"`*=`, `/=`, `%=`, `+=`, `-=`, ",//|
|
||||
r" | 8 | Assign |", r"`*=`, `/=`, `%=`, `+=`, `-=`, ",//|
|
||||
/* | | |*/ r"`&=`, <code>|=</code>, ", //|
|
||||
/* | | |*/ r"`^=`, `<<=`, `>>=`", r"| Right to Left")]
|
||||
//! | 9 | [Ignore] | `;` |
|
||||
//! | 9 | Ignore | `;` |
|
||||
//!
|
||||
//! <!-- Note: | == | /-->
|
||||
//! <!-- Note: '|' == '|' /-->
|
||||
//!
|
||||
//! ## Syntax
|
||||
//! ```ignore
|
||||
//! /* All precedence levels other than Unary fold into Binary */
|
||||
//! Ignore := Assign (CompareOp Assign )*
|
||||
//! Assign := Compare (IgnoreOp Compare)*
|
||||
//! Compare := Logic (AssignOp Logic )*
|
||||
@@ -495,80 +505,31 @@ pub mod expression {
|
||||
//! ```
|
||||
use super::*;
|
||||
|
||||
/// The template for [Binary] operations.
|
||||
/// # Syntax
|
||||
/// [`Binary`] := `First` (`Other`)*
|
||||
/// An Operation is a tree of [operands](Primary) and [operators](operator).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Binary<First, Other> {
|
||||
pub first: Box<First>,
|
||||
pub other: Vec<Other>,
|
||||
pub enum Operation {
|
||||
/// [`Binary`](Operation::Binary) :=
|
||||
/// [`Operation`] ([`operator::Binary`] [`Operation`])*
|
||||
Binary {
|
||||
first: Box<Self>,
|
||||
other: Vec<(operator::Binary, Self)>,
|
||||
},
|
||||
/// [`Unary`](Operation::Unary) := ([`operator::Unary`])* [`Primary`]
|
||||
Unary {
|
||||
operators: Vec<operator::Unary>,
|
||||
operand: Primary,
|
||||
},
|
||||
}
|
||||
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
|
||||
impl Operation {
|
||||
pub fn binary(first: Self, other: Vec<(operator::Binary, Self)>) -> Self {
|
||||
Self::Binary { first: Box::new(first), other }
|
||||
}
|
||||
}
|
||||
|
||||
/// Ignores the result of the leading sub-expression.
|
||||
/// Great if you only want the side-effects.
|
||||
/// # Syntax
|
||||
/// [`Ignore`] := [`Assign`] ([`operator::Ignore`] [`Assign`])*
|
||||
pub type Ignore = Binary<Assign, (operator::Ignore, Assign)>;
|
||||
|
||||
/// Assigns the result of the trailing sub-expression to the leading sub-expression.
|
||||
/// Resolves to the Empty type.
|
||||
/// # Syntax
|
||||
/// [`Assign`] := [`Compare`] ([`operator::Assign`] [`Compare`])?
|
||||
pub type Assign = Binary<Compare, (operator::Assign, Compare)>;
|
||||
|
||||
/// Compares the values of the trailing and leading sub-expressions,
|
||||
/// and resolves to a boolean.
|
||||
/// # Syntax
|
||||
/// [`Compare`] := [`Logic`] ([`operator::Compare`] [`Logic`])*
|
||||
pub type Compare = Binary<Logic, (operator::Compare, Logic)>;
|
||||
|
||||
/// Performs a boolean logic operation on the leading and trailing sub-expressions.
|
||||
/// # Syntax
|
||||
/// [`Logic`] := [`Bitwise`] ([`operator::Logic`] [`Bitwise`])*
|
||||
pub type Logic = Binary<Bitwise, (operator::Logic, Bitwise)>;
|
||||
|
||||
/// Performs a bitwise opration on the leading and trailing sub-expressions.
|
||||
/// # Syntax
|
||||
/// [`Bitwise`] := [`Shift`] ([`operator::Bitwise`] [`Shift`])*
|
||||
pub type Bitwise = Binary<Shift, (operator::Bitwise, Shift)>;
|
||||
|
||||
/// Shifts the leading sub-expression by the trailing sub-expression
|
||||
/// # Syntax
|
||||
/// [`Shift`] := [`Term`] ([`operator::Shift`] [`Term`])*
|
||||
pub type Shift = Binary<Term, (operator::Shift, Term)>;
|
||||
|
||||
/// Adds or subtracts the trailing sub-expression from the leading sub-expression
|
||||
/// # Syntax
|
||||
/// [`Term`] := [`Factor`] ([`operator::Term`] [`Factor`])*
|
||||
pub type Term = Binary<Factor, (operator::Term, Factor)>;
|
||||
|
||||
/// Multiplies, Divides, or finds the remainder of the trailing sub-expression
|
||||
/// from the leading sub-expression
|
||||
/// # Syntax
|
||||
/// [`Factor`] := [`Unary`] ([`operator::Factor`] [`Unary`])*
|
||||
pub type Factor = Binary<Unary, (operator::Factor, Unary)>;
|
||||
|
||||
/// Performs a unary operation on the trailing sub-expression.
|
||||
/// # Syntax
|
||||
/// [`Unary`] := ([`operator::Unary`])* [`Primary`]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Unary(pub Vec<operator::Unary>, pub Primary);
|
||||
|
||||
pub mod operator {
|
||||
//! | # | [Operators](Operator) | Associativity
|
||||
//! | # | [Operators](self) | Associativity
|
||||
//! |---|---------------------------------------|--------------
|
||||
//! | 0 | ([Unary]) `*`, `&`, `-`, `!` | Left to Right
|
||||
//! | 0 |[`*`, `&`, `-`, `!`](Unary) | Left to Right
|
||||
//! | 1 | `*`, `/`, `%` | Left to Right
|
||||
//! | 2 | `+`, `-` | Left to Right
|
||||
//! | 3 | `<<`, `>>` | Left to Right
|
||||
@@ -580,87 +541,108 @@ pub mod expression {
|
||||
/* | |*/ r"`&=`, <code>|=</code>, ", //|
|
||||
/* | |*/ r"`^=`, `<<=`, `>>=`, `=`", r"| Left to Right")]
|
||||
//! | 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")]
|
||||
$(#[$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 }
|
||||
}
|
||||
})*
|
||||
|
||||
/// Operators which take a single argument
|
||||
///
|
||||
/// (`*`, `&`, `-`, `!`, `@`, `#`, `~`)
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Unary {
|
||||
/// `&&`: Take a reference, twice
|
||||
RefRef,
|
||||
/// `&`: Take a reference
|
||||
Ref,
|
||||
/// `*`: Dereference
|
||||
Deref,
|
||||
/// `-`: Arithmetic negation
|
||||
Neg,
|
||||
/// `!`: Binary/Boolean negation
|
||||
Not,
|
||||
/// `@`: Undefined
|
||||
At,
|
||||
/// `#`: Undefined
|
||||
Hash,
|
||||
/// `~`: Undefined
|
||||
Tilde,
|
||||
}
|
||||
operator! {
|
||||
/// (`*`, `&`, `-`, `!`, `@`, `#`, `~`)
|
||||
Unary {
|
||||
RefRef := Type::AmpAmp,
|
||||
Deref := Type::Star,
|
||||
Ref := Type::Amp,
|
||||
Neg := Type::Minus,
|
||||
Not := Type::Bang,
|
||||
At := Type::At,
|
||||
Hash := Type::Hash,
|
||||
Tilde := Type::Tilde,
|
||||
}
|
||||
/// (`*`, `/`, `%`)
|
||||
Factor {
|
||||
Mul := Type::Star,
|
||||
Div := Type::Slash,
|
||||
Rem := Type::Rem,
|
||||
}
|
||||
/// (`+`, `-`)
|
||||
Term {
|
||||
Add := Type::Plus,
|
||||
Sub := Type::Minus,
|
||||
}
|
||||
/// (`<<`, `>>`)
|
||||
Shift {
|
||||
Lsh := Type::LtLt,
|
||||
Rsh := Type::GtGt,
|
||||
}
|
||||
/// (`&`, `|`, `^`)
|
||||
Bitwise {
|
||||
BitAnd := Type::Amp,
|
||||
BitOr := Type::Bar,
|
||||
BitXor := Type::Xor,
|
||||
}
|
||||
/// (`&&`, `||`, `^^`)
|
||||
Logic {
|
||||
LogAnd := Type::AmpAmp,
|
||||
LogOr := Type::BarBar,
|
||||
LogXor := Type::XorXor,
|
||||
}
|
||||
/// (`<`, `<=`, `==`, `!=`, `>=`, `>`)
|
||||
Compare {
|
||||
Less := Type::Lt,
|
||||
LessEq := Type::LtEq,
|
||||
Equal := Type::EqEq,
|
||||
NotEq := Type::BangEq,
|
||||
GreaterEq := Type::GtEq,
|
||||
Greater := Type::Gt,
|
||||
}
|
||||
/// (`=`, `+=`, `-=`, `*=`, `/=`,
|
||||
/// `&=`, `|=`, `^=`, `<<=`, `>>=`)
|
||||
Assign {
|
||||
Assign := Type::Eq,
|
||||
AddAssign := Type::PlusEq,
|
||||
SubAssign := Type::MinusEq,
|
||||
MulAssign := Type::StarEq,
|
||||
DivAssign := Type::SlashEq,
|
||||
BitAndAssign := Type::AmpEq,
|
||||
BitOrAssign := Type::BarEq,
|
||||
BitXorAssign := Type::XorEq,
|
||||
ShlAssign := Type::LtLtEq,
|
||||
ShrAssign := Type::GtGtEq,
|
||||
}
|
||||
/// (`;`)
|
||||
Ignore {
|
||||
Ignore := Type::Semi,
|
||||
}
|
||||
/// Operators which take two arguments
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Binary {
|
||||
// Term operators
|
||||
/// `*`: Multiplication
|
||||
Mul,
|
||||
/// `/`: Division
|
||||
Div,
|
||||
/// `%`: Remainder
|
||||
Rem,
|
||||
|
||||
// Factor operators
|
||||
/// `+`: Addition
|
||||
Add,
|
||||
/// `-`: Subtraction
|
||||
Sub,
|
||||
|
||||
// Shift operators
|
||||
/// `<<`: Left Shift
|
||||
Lsh,
|
||||
/// `>>`: Right Shift
|
||||
Rsh,
|
||||
|
||||
// Bitwise operators
|
||||
/// `&`: Bitwise AND
|
||||
BitAnd,
|
||||
/// `|`: Bitwise OR
|
||||
BitOr,
|
||||
/// `^`: Bitwise XOR
|
||||
BitXor,
|
||||
|
||||
// Logic operators
|
||||
/// `&&`: Short-circuiting logical AND
|
||||
LogAnd,
|
||||
/// `||`: Short-circuiting logical OR
|
||||
LogOr,
|
||||
/// `^^`: **Non-short-circuiting** logical XOR
|
||||
LogXor,
|
||||
|
||||
// Comparison operators
|
||||
/// `<`: Less-than Comparison
|
||||
Less,
|
||||
/// `<=`: Less-than or Equal Comparison
|
||||
LessEq,
|
||||
/// `==`: Equal Comparison
|
||||
Equal,
|
||||
/// `!=`: Not Equal Comparison
|
||||
NotEq,
|
||||
/// `>=`: Greater-than or Equal Comparison
|
||||
GreaterEq,
|
||||
/// `>`: Greater-than Comparison
|
||||
Greater,
|
||||
|
||||
// Assignment operators
|
||||
/// `=`: Assignment
|
||||
Assign,
|
||||
/// `+=`: Additive In-place Assignment
|
||||
AddAssign,
|
||||
/// `-=`: Subtractive In-place Assignment
|
||||
SubAssign,
|
||||
/// `*=`: Multiplicative In-place Assignment
|
||||
MulAssign,
|
||||
/// `/=`: Divisive In-place Assignment
|
||||
DivAssign,
|
||||
/// `%=`: Remainder In-place Assignment
|
||||
RemAssign,
|
||||
/// `&=`: Bitwise-AND In-place Assignment
|
||||
BitAndAssign,
|
||||
/// `|=`: Bitwise-OR In-place Assignment
|
||||
BitOrAssign,
|
||||
/// `^=`: Bitwise-XOR In-place Assignment
|
||||
BitXorAssign,
|
||||
/// `<<=`: Left Shift In-place Assignment
|
||||
ShlAssign,
|
||||
/// `>>=`: Right Shift In-place Assignment
|
||||
ShrAssign,
|
||||
// Ignorance operators
|
||||
/// `;`: Ignore
|
||||
Ignore,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user