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:
parent
4ec91ff806
commit
feb5cc5dd0
@ -3,7 +3,7 @@
|
|||||||
use conlang::{lexer::Lexer, parser::Parser, pretty_printer::PrettyPrintable, token::Token};
|
use conlang::{lexer::Lexer, parser::Parser, pretty_printer::PrettyPrintable, token::Token};
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{stdin, IsTerminal, Read},
|
io::{stdin, stdout, IsTerminal, Read, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,9 +30,18 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn take_stdin() -> Result<(), Box<dyn Error>> {
|
fn take_stdin() -> Result<(), Box<dyn Error>> {
|
||||||
|
const PROMPT: &str = "> ";
|
||||||
if stdin().is_terminal() {
|
if stdin().is_terminal() {
|
||||||
|
print!("{PROMPT}");
|
||||||
|
stdout().flush()?;
|
||||||
for line in stdin().lines() {
|
for line in stdin().lines() {
|
||||||
parse(&line?, None)
|
let line = line?;
|
||||||
|
if !line.is_empty() {
|
||||||
|
parse(&line, None);
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
print!("{PROMPT}");
|
||||||
|
stdout().flush()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parse(&std::io::read_to_string(stdin())?, None)
|
parse(&std::io::read_to_string(stdin())?, None)
|
||||||
@ -44,8 +53,8 @@ fn parse(file: &str, path: Option<&Path>) {
|
|||||||
use conlang::parser::error::Error;
|
use conlang::parser::error::Error;
|
||||||
match Parser::from(Lexer::new(file)).parse() {
|
match Parser::from(Lexer::new(file)).parse() {
|
||||||
Ok(ast) => ast.print(),
|
Ok(ast) => ast.print(),
|
||||||
Err(e) if e.start().is_some() => println!("{:?}:{}", path.unwrap_or(Path::new("-")), e),
|
Err(e) if e.start().is_some() => print!("{:?}:{}", path.unwrap_or(Path::new("-")), e),
|
||||||
Err(e) => println!("{e}"),
|
Err(e) => print!("{e}"),
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
@ -26,82 +26,120 @@ pub mod preamble {
|
|||||||
|
|
||||||
mod visitor {
|
mod visitor {
|
||||||
use super::{
|
use super::{
|
||||||
expression::{control::*, math::*, Block, *},
|
expression::{
|
||||||
|
control::*,
|
||||||
|
math::{operator::*, *},
|
||||||
|
Block, *,
|
||||||
|
},
|
||||||
literal::*,
|
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> {
|
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;
|
fn walk(&self, visitor: &mut T) -> R;
|
||||||
}
|
}
|
||||||
pub mod walker {
|
pub mod walker {
|
||||||
use super::*;
|
use super::*;
|
||||||
macro_rules! impl_walk {
|
macro leaf($($T:ty),*$(,)?) {$(
|
||||||
($($T:ty => $f:ident),*$(,)?) => {
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for $T {
|
||||||
$(impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for $T {
|
#[doc = concat!("A(n) [`", stringify!($T), "`] is a leaf node.")]
|
||||||
fn walk(&self, visitor: &mut T) -> R {
|
/// Calling this will do nothing.
|
||||||
visitor.$f(self)
|
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 {
|
||||||
impl_walk! {
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
// ast
|
visitor.visit_expr(&self.cond)?;
|
||||||
Start => visit,
|
visitor.visit_block(&self.body)?;
|
||||||
// grouped expr
|
match &self.else_ {
|
||||||
Block => visit_block,
|
Some(expr) => visitor.visit_else(expr),
|
||||||
Group => visit_group,
|
None => Ok(()),
|
||||||
// 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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Expr {
|
}
|
||||||
fn walk(&self, visitor: &mut T) -> R {
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for If {
|
||||||
visitor.visit_ignore(&self.ignore)
|
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<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 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 {
|
match self {
|
||||||
Primary::Identifier(i) => visitor.visit_identifier(i),
|
Primary::Identifier(i) => visitor.visit_identifier(i),
|
||||||
Primary::Literal(l) => visitor.visit_literal(l),
|
Primary::Literal(l) => visitor.visit_literal(l),
|
||||||
@ -111,8 +149,8 @@ mod visitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Visitor<R> + ?Sized, R> Walk<T, R> for Literal {
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Literal {
|
||||||
fn walk(&self, visitor: &mut T) -> R {
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
match self {
|
match self {
|
||||||
Literal::String(s) => visitor.visit_string_literal(s),
|
Literal::String(s) => visitor.visit_string_literal(s),
|
||||||
Literal::Char(c) => visitor.visit_char_literal(c),
|
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 {
|
impl<T: Visitor<Result<(), E>> + ?Sized, E> Walk<T, Result<(), E>> for Flow {
|
||||||
fn walk(&self, visitor: &mut T) -> R {
|
fn walk(&self, visitor: &mut T) -> Result<(), E> {
|
||||||
match self {
|
match self {
|
||||||
Flow::While(w) => visitor.visit_while(w),
|
Flow::While(w) => visitor.visit_while(w),
|
||||||
Flow::If(i) => visitor.visit_if(i),
|
Flow::If(i) => visitor.visit_if(i),
|
||||||
@ -144,15 +182,12 @@ mod visitor {
|
|||||||
|
|
||||||
/// Visit an [Expression](Expr)
|
/// Visit an [Expression](Expr)
|
||||||
fn visit_expr(&mut self, expr: &Expr) -> R {
|
fn visit_expr(&mut self, expr: &Expr) -> R {
|
||||||
expr.walk(self)
|
self.visit_operation(&expr.ignore)
|
||||||
}
|
}
|
||||||
// Block expression
|
// Block expression
|
||||||
/// Visit a [Block] expression
|
/// Visit a [Block] expression
|
||||||
fn visit_block(&mut self, expr: &Block) -> R {
|
fn visit_block(&mut self, expr: &Block) -> R {
|
||||||
match &expr.expr {
|
self.visit_expr(&expr.expr)
|
||||||
Some(expr) => self.visit_expr(expr),
|
|
||||||
None => self.visit_empty(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Visit a [Group] expression
|
/// Visit a [Group] expression
|
||||||
fn visit_group(&mut self, group: &Group) -> R {
|
fn visit_group(&mut self, group: &Group) -> R {
|
||||||
@ -163,73 +198,39 @@ mod visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Math expression
|
// Math expression
|
||||||
fn visit_binary<F, Op>(&mut self, expr: &Binary<F, (Op, F)>) -> R
|
/// Visit an [Operation]
|
||||||
where F: Walk<Self, R>, Op: Walk<Self, R>;
|
fn visit_operation(&mut self, expr: &Operation) -> R;
|
||||||
/// Visit an [Ignore] expression
|
/// Visit a [Binary](Operation::Binary) [operator](operator::Binary)
|
||||||
fn visit_ignore(&mut self, expr: &Ignore) -> R {
|
// Math operators
|
||||||
self.visit_binary(expr)
|
fn visit_binary_op(&mut self, op: &operator::Binary) -> R;
|
||||||
}
|
/// Visit a [Unary](Operation::Unary) [operator](operator::Unary)
|
||||||
/// Visit an [Assign] expression
|
fn visit_unary_op(&mut self, op: &operator::Unary) -> 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 {
|
|
||||||
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 a [Primary] expression
|
/// Visit a [Primary] expression
|
||||||
///
|
///
|
||||||
/// [Primary] := [Identifier] | [Literal] | [Block] | [Flow]
|
/// [Primary] := [Identifier] | [Literal] | [Block] | [Flow]
|
||||||
fn visit_primary(&mut self, expr: &Primary) -> R {
|
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.
|
/// Visit a [Flow] expression.
|
||||||
///
|
///
|
||||||
/// [Flow] := [While] | [If] | [For]
|
/// [Flow] := [While] | [If] | [For]
|
||||||
fn visit_branch_expr(&mut self, expr: &Flow) -> R {
|
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
|
/// Visit an [If] expression
|
||||||
fn visit_if(&mut self, expr: &If) -> R;
|
fn visit_if(&mut self, expr: &If) -> R;
|
||||||
@ -253,7 +254,13 @@ mod visitor {
|
|||||||
///
|
///
|
||||||
/// [Literal] := [String] | [char] | [bool] | [Float] | [u128]
|
/// [Literal] := [String] | [char] | [bool] | [Float] | [u128]
|
||||||
fn visit_literal(&mut self, literal: &Literal) -> R {
|
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
|
/// Visit a [string](str) literal
|
||||||
fn visit_string_literal(&mut self, string: &str) -> R;
|
fn visit_string_literal(&mut self, string: &str) -> R;
|
||||||
@ -265,7 +272,8 @@ mod visitor {
|
|||||||
fn visit_float_literal(&mut self, float: &Float) -> R;
|
fn visit_float_literal(&mut self, float: &Float) -> R;
|
||||||
/// Visit an [integer](u128) literal
|
/// Visit an [integer](u128) literal
|
||||||
fn visit_int_literal(&mut self, int: &u128) -> R;
|
fn visit_int_literal(&mut self, int: &u128) -> R;
|
||||||
/// Visit an Empty literal
|
|
||||||
|
/// Visit an Empty
|
||||||
fn visit_empty(&mut self) -> R;
|
fn visit_empty(&mut self) -> R;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,19 +398,19 @@ pub mod expression {
|
|||||||
//! | # | Node | Function
|
//! | # | Node | Function
|
||||||
//! |----|------------------:|:----------------------------------------------
|
//! |----|------------------:|:----------------------------------------------
|
||||||
//! | 0 | [`Expr`] | Contains an expression
|
//! | 0 | [`Expr`] | Contains an expression
|
||||||
//! | 1 | [`math::Ignore`] | Ignores the preceding sub-expression's result
|
//! | 1 | [`Ignore`](math) | Ignores the preceding sub-expression's result
|
||||||
//! | 2 | [`math::Assign`] | Assignment
|
//! | 2 | [`Assign`](math) | Assignment
|
||||||
//! | 3 | [`math::Compare`] | Value Comparison
|
//! | 3 | [`Compare`](math) | Value Comparison
|
||||||
//! | 4 | [`math::Logic`] | Boolean And, Or, Xor
|
//! | 4 | [`Logic`](math) | Boolean And, Or, Xor
|
||||||
//! | 5 | [`math::Bitwise`] | Bitwise And, Or, Xor
|
//! | 5 | [`Bitwise`](math) | Bitwise And, Or, Xor
|
||||||
//! | 6 | [`math::Shift`] | Shift Left/Right
|
//! | 6 | [`Shift`](math) | Shift Left/Right
|
||||||
//! | 7 | [`math::Term`] | Add, Subtract
|
//! | 7 | [`Term`](math) | Add, Subtract
|
||||||
//! | 8 | [`math::Factor`] | Multiply, Divide, Remainder
|
//! | 8 | [`Factor`](math) | Multiply, Divide, Remainder
|
||||||
//! | 9 | [`math::Unary`] | Unary Dereference, Reference, Negate, Not
|
//! | 9 | [`Unary`](math) | Unary Dereference, Reference, Negate, Not
|
||||||
//! | 10 | [`control::Flow`] | Branch expressions (`if`, `while`, `for`, `return`, `break`, `continue`), `else`
|
//! | 10 | [`control::Flow`] | Branch expressions (`if`, `while`, `for`, `return`, `break`, `continue`), `else`
|
||||||
//! | 10 | [`Group`] | Group expressions `(` [Expr]? `)` /* Can evaluate to Empty! */
|
//! | 10 | [`Group`] | Group expressions `(` [Expr]? `)` /* Can evaluate to Empty! */
|
||||||
//! | 10 | [`Block`] | Block expressions `{` [Expr] `}`
|
//! | 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
|
//! ## Syntax
|
||||||
//! ```ignore
|
//! ```ignore
|
||||||
@ -417,10 +425,10 @@ pub mod expression {
|
|||||||
/// Contains an expression
|
/// Contains an expression
|
||||||
///
|
///
|
||||||
/// # Syntax
|
/// # Syntax
|
||||||
/// [`Expr`] := [`math::Ignore`]
|
/// [`Expr`] := [`math::Operation`]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Expr {
|
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
|
/// A [Primary] Expression is the expression with the highest precedence (i.e. the deepest
|
||||||
@ -430,6 +438,7 @@ pub mod expression {
|
|||||||
/// [`IDENTIFIER`](Identifier)
|
/// [`IDENTIFIER`](Identifier)
|
||||||
/// | [`Literal`](literal::Literal)
|
/// | [`Literal`](literal::Literal)
|
||||||
/// | [`Block`]
|
/// | [`Block`]
|
||||||
|
/// | [`Group`]
|
||||||
/// | [`Branch`](control::Flow)
|
/// | [`Branch`](control::Flow)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Primary {
|
pub enum Primary {
|
||||||
@ -445,7 +454,7 @@ pub mod expression {
|
|||||||
/// [`Block`] := `'{'` [`Expr`] `'}'`
|
/// [`Block`] := `'{'` [`Expr`] `'}'`
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub expr: Option<Box<Expr>>,
|
pub expr: Box<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains a Parenthesized Expression
|
/// Contains a Parenthesized Expression
|
||||||
@ -466,23 +475,24 @@ pub mod expression {
|
|||||||
//! | # | Name | Operators | Associativity
|
//! | # | Name | Operators | Associativity
|
||||||
//! |---|----------:|:--------------------------------------|---------------
|
//! |---|----------:|:--------------------------------------|---------------
|
||||||
// | | TODO: Try | `?` |
|
// | | TODO: Try | `?` |
|
||||||
//! | 1 | [Unary] | `*` `&` `-` `!` | Right
|
//! | 1 | Unary | `*` `&` `-` `!` | Right
|
||||||
//! | 2 | [Factor] | `*` `/` `%` | Left to Right
|
//! | 2 | Factor | `*` `/` `%` | Left to Right
|
||||||
//! | 3 | [Term] | `+` `-` | Left to Right
|
//! | 3 | Term | `+` `-` | Left to Right
|
||||||
//! | 4 | [Shift] | `<<` `>>` | Left to Right
|
//! | 4 | Shift | `<<` `>>` | Left to Right
|
||||||
//! | 5 | [Bitwise] | `&` <code>|</code> | Left to Right
|
//! | 5 | Bitwise | `&` <code>|</code> | Left to Right
|
||||||
//! | 6 | [Logic] | `&&` <code>||</code> `^^` | Left to Right
|
//! | 6 | Logic | `&&` <code>||</code> `^^` | Left to Right
|
||||||
//! | 7 | [Compare] | `<` `<=` `==` `!=` `>=` `>` | Left to Right
|
//! | 7 | Compare | `<` `<=` `==` `!=` `>=` `>` | Left to Right
|
||||||
#![doc = concat!( //| |
|
#![doc = concat!( //| |
|
||||||
r" | 8 | [Assign] |", r"`*=`, `/=`, `%=`, `+=`, `-=`, ",//|
|
r" | 8 | Assign |", r"`*=`, `/=`, `%=`, `+=`, `-=`, ",//|
|
||||||
/* | | |*/ r"`&=`, <code>|=</code>, ", //|
|
/* | | |*/ r"`&=`, <code>|=</code>, ", //|
|
||||||
/* | | |*/ r"`^=`, `<<=`, `>>=`", r"| Right to Left")]
|
/* | | |*/ r"`^=`, `<<=`, `>>=`", r"| Right to Left")]
|
||||||
//! | 9 | [Ignore] | `;` |
|
//! | 9 | Ignore | `;` |
|
||||||
//!
|
//!
|
||||||
//! <!-- Note: | == | /-->
|
//! <!-- Note: '|' == '|' /-->
|
||||||
//!
|
//!
|
||||||
//! ## Syntax
|
//! ## Syntax
|
||||||
//! ```ignore
|
//! ```ignore
|
||||||
|
//! /* All precedence levels other than Unary fold into Binary */
|
||||||
//! Ignore := Assign (CompareOp Assign )*
|
//! Ignore := Assign (CompareOp Assign )*
|
||||||
//! Assign := Compare (IgnoreOp Compare)*
|
//! Assign := Compare (IgnoreOp Compare)*
|
||||||
//! Compare := Logic (AssignOp Logic )*
|
//! Compare := Logic (AssignOp Logic )*
|
||||||
@ -495,80 +505,31 @@ pub mod expression {
|
|||||||
//! ```
|
//! ```
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// The template for [Binary] operations.
|
/// An Operation is a tree of [operands](Primary) and [operators](operator).
|
||||||
/// # Syntax
|
|
||||||
/// [`Binary`] := `First` (`Other`)*
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Binary<First, Other> {
|
pub enum Operation {
|
||||||
pub first: Box<First>,
|
/// [`Binary`](Operation::Binary) :=
|
||||||
pub other: Vec<Other>,
|
/// [`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> {
|
impl Operation {
|
||||||
pub fn new(first: First, other: Vec<Other>) -> Self {
|
pub fn binary(first: Self, other: Vec<(operator::Binary, Self)>) -> Self {
|
||||||
Self { first: Box::new(first), other }
|
Self::Binary { 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`])*
|
|
||||||
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 {
|
pub mod operator {
|
||||||
//! | # | [Operators](Operator) | Associativity
|
//! | # | [Operators](self) | Associativity
|
||||||
//! |---|---------------------------------------|--------------
|
//! |---|---------------------------------------|--------------
|
||||||
//! | 0 | ([Unary]) `*`, `&`, `-`, `!` | Left to Right
|
//! | 0 |[`*`, `&`, `-`, `!`](Unary) | Left to Right
|
||||||
//! | 1 | `*`, `/`, `%` | Left to Right
|
//! | 1 | `*`, `/`, `%` | Left to Right
|
||||||
//! | 2 | `+`, `-` | Left to Right
|
//! | 2 | `+`, `-` | Left to Right
|
||||||
//! | 3 | `<<`, `>>` | Left to Right
|
//! | 3 | `<<`, `>>` | Left to Right
|
||||||
@ -580,87 +541,108 @@ pub mod expression {
|
|||||||
/* | |*/ r"`&=`, <code>|=</code>, ", //|
|
/* | |*/ r"`&=`, <code>|=</code>, ", //|
|
||||||
/* | |*/ r"`^=`, `<<=`, `>>=`, `=`", r"| Left to Right")]
|
/* | |*/ r"`^=`, `<<=`, `>>=`, `=`", r"| Left to Right")]
|
||||||
//! | 8 | `;` |
|
//! | 8 | `;` |
|
||||||
use crate::token::Type;
|
|
||||||
/// Defines an operator enum and a conversion
|
/// Operators which take a single argument
|
||||||
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 {
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
RefRef := Type::AmpAmp,
|
pub enum Unary {
|
||||||
Deref := Type::Star,
|
/// `&&`: Take a reference, twice
|
||||||
Ref := Type::Amp,
|
RefRef,
|
||||||
Neg := Type::Minus,
|
/// `&`: Take a reference
|
||||||
Not := Type::Bang,
|
Ref,
|
||||||
At := Type::At,
|
/// `*`: Dereference
|
||||||
Hash := Type::Hash,
|
Deref,
|
||||||
Tilde := Type::Tilde,
|
/// `-`: Arithmetic negation
|
||||||
}
|
Neg,
|
||||||
/// (`*`, `/`, `%`)
|
/// `!`: Binary/Boolean negation
|
||||||
Factor {
|
Not,
|
||||||
Mul := Type::Star,
|
/// `@`: Undefined
|
||||||
Div := Type::Slash,
|
At,
|
||||||
Rem := Type::Rem,
|
/// `#`: Undefined
|
||||||
}
|
Hash,
|
||||||
/// (`+`, `-`)
|
/// `~`: Undefined
|
||||||
Term {
|
Tilde,
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,18 +17,21 @@ pub mod error {
|
|||||||
pub enum Reason {
|
pub enum Reason {
|
||||||
Expected(Type),
|
Expected(Type),
|
||||||
NotIdentifier,
|
NotIdentifier,
|
||||||
|
NotOperator,
|
||||||
NotLiteral,
|
NotLiteral,
|
||||||
NotString,
|
NotString,
|
||||||
NotChar,
|
NotChar,
|
||||||
NotBool,
|
NotBool,
|
||||||
NotFloat,
|
NotFloat,
|
||||||
|
NotInt,
|
||||||
FloatExponentOverflow,
|
FloatExponentOverflow,
|
||||||
FloatMantissaOverflow,
|
FloatMantissaOverflow,
|
||||||
NotInt,
|
|
||||||
IntOverflow,
|
IntOverflow,
|
||||||
NotControlFlow,
|
|
||||||
NotBranch,
|
NotBranch,
|
||||||
|
IncompleteBranch,
|
||||||
|
AllElseFailed,
|
||||||
EndOfFile,
|
EndOfFile,
|
||||||
|
PanicStackUnderflow,
|
||||||
#[default]
|
#[default]
|
||||||
Unspecified,
|
Unspecified,
|
||||||
}
|
}
|
||||||
@ -38,28 +41,30 @@ pub mod error {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Expected(t) => write!(f, "Expected {t}"),
|
Self::Expected(t) => write!(f, "Expected {t}"),
|
||||||
Self::NotIdentifier => Display::fmt("Not an identifier", f),
|
Self::NotIdentifier => "Not an identifier".fmt(f),
|
||||||
Self::NotLiteral => Display::fmt("Not a literal", f),
|
Self::NotOperator => "Not an operator".fmt(f),
|
||||||
Self::NotString => Display::fmt("Not a string", f),
|
Self::NotLiteral => "Not a literal".fmt(f),
|
||||||
Self::NotChar => Display::fmt("Not a char", f),
|
Self::NotString => "Not a string".fmt(f),
|
||||||
Self::NotBool => Display::fmt("Not a bool", f),
|
Self::NotChar => "Not a char".fmt(f),
|
||||||
Self::NotFloat => Display::fmt("Not a float", f),
|
Self::NotBool => "Not a bool".fmt(f),
|
||||||
Self::FloatExponentOverflow => Display::fmt("Float exponent too large", f),
|
Self::NotFloat => "Not a float".fmt(f),
|
||||||
Self::FloatMantissaOverflow => Display::fmt("Float mantissa too large", f),
|
Self::FloatExponentOverflow => "Float exponent too large".fmt(f),
|
||||||
Self::NotInt => Display::fmt("Not an integer", f),
|
Self::FloatMantissaOverflow => "Float mantissa too large".fmt(f),
|
||||||
Self::IntOverflow => Display::fmt("Integer too large", f),
|
Self::NotInt => "Not an integer".fmt(f),
|
||||||
Self::NotControlFlow => Display::fmt("Control flow expression was incomplete", f),
|
Self::IntOverflow => "Integer too large".fmt(f),
|
||||||
Self::NotBranch => Display::fmt("Branch expression was incomplete", f),
|
Self::IncompleteBranch => "Branch expression was incomplete".fmt(f),
|
||||||
Self::EndOfFile => Display::fmt("Got end of file", f),
|
Self::NotBranch => "Expected branch expression".fmt(f),
|
||||||
Self::Unspecified => Display::fmt(
|
Self::AllElseFailed => "Did not match any rule".fmt(f),
|
||||||
"Unspecified error. You are permitted to slap the code author.",
|
Self::EndOfFile => "Got end of file".fmt(f),
|
||||||
f,
|
Self::PanicStackUnderflow => "Could not recover from panic".fmt(f),
|
||||||
),
|
Self::Unspecified => {
|
||||||
|
"Unspecified error. You are permitted to slap the code author.".fmt(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Parser] [Result]
|
/// [Parser](super::Parser) [Result]
|
||||||
pub type PResult<T> = Result<T, Error>;
|
pub type PResult<T> = Result<T, Error>;
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
@ -99,6 +104,7 @@ pub mod error {
|
|||||||
error_impl! {
|
error_impl! {
|
||||||
expected(e: Type): Expected,
|
expected(e: Type): Expected,
|
||||||
not_identifier: NotIdentifier,
|
not_identifier: NotIdentifier,
|
||||||
|
not_operator: NotOperator,
|
||||||
not_literal: NotLiteral,
|
not_literal: NotLiteral,
|
||||||
not_string: NotString,
|
not_string: NotString,
|
||||||
not_char: NotChar,
|
not_char: NotChar,
|
||||||
@ -108,9 +114,10 @@ pub mod error {
|
|||||||
float_mantissa_overflow: FloatMantissaOverflow,
|
float_mantissa_overflow: FloatMantissaOverflow,
|
||||||
not_int: NotInt,
|
not_int: NotInt,
|
||||||
int_overflow: IntOverflow,
|
int_overflow: IntOverflow,
|
||||||
not_control_flow: NotControlFlow,
|
|
||||||
not_branch: NotBranch,
|
not_branch: NotBranch,
|
||||||
|
all_else_failed: AllElseFailed,
|
||||||
end_of_file: EndOfFile,
|
end_of_file: EndOfFile,
|
||||||
|
panic_underflow: PanicStackUnderflow,
|
||||||
unspecified: Unspecified,
|
unspecified: Unspecified,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +168,9 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
/// Peek at the current token
|
/// Peek at the current token
|
||||||
pub fn peek(&self) -> PResult<&Token> {
|
pub fn peek(&self) -> PResult<&Token> {
|
||||||
self.tokens.get(self.curr).ok_or(Error::end_of_file())
|
self.tokens
|
||||||
|
.get(self.curr)
|
||||||
|
.ok_or(Error::end_of_file().maybe_token(self.tokens.last().copied()))
|
||||||
}
|
}
|
||||||
/// Records the current position on the panic stack
|
/// Records the current position on the panic stack
|
||||||
pub fn mark(&mut self) -> &mut Self {
|
pub fn mark(&mut self) -> &mut Self {
|
||||||
@ -174,12 +183,18 @@ impl<'t> Parser<'t> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// Unwinds the panic stack one step
|
/// Unwinds the panic stack one step
|
||||||
pub fn unwind(&mut self) -> Option<usize> {
|
pub fn unwind(&mut self) -> PResult<&mut Self> {
|
||||||
let out = self.panic_stack.pop();
|
let v = self.panic_stack.pop().ok_or(Error::panic_underflow())?;
|
||||||
if let Some(v) = out {
|
|
||||||
self.curr = v;
|
self.curr = v;
|
||||||
|
Ok(self)
|
||||||
}
|
}
|
||||||
out
|
pub fn advance_until(&mut self, t: Type) -> PResult<&mut Self> {
|
||||||
|
while self.matches(t).is_err() {
|
||||||
|
self.check_eof()
|
||||||
|
.map_err(|e| e.reason(Expected(t)))?
|
||||||
|
.consume();
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Helpers
|
/// Helpers
|
||||||
@ -192,7 +207,7 @@ impl<'t> Parser<'t> {
|
|||||||
if self.curr < self.tokens.len() {
|
if self.curr < self.tokens.len() {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::end_of_file())
|
Err(Error::end_of_file().maybe_token(self.tokens.last().copied()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn todo_error(&mut self, l: u32, c: u32, s: &str) -> Error {
|
fn todo_error(&mut self, l: u32, c: u32, s: &str) -> Error {
|
||||||
@ -211,9 +226,17 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
fn delimited<F, R>(&mut self, lhs: Type, mid: F, rhs: Type) -> PResult<R>
|
fn delimited<F, R>(&mut self, lhs: Type, mid: F, rhs: Type) -> PResult<R>
|
||||||
where F: Fn(&mut Self) -> PResult<R> {
|
where F: Fn(&mut Self) -> PResult<R> {
|
||||||
self.consume_type(lhs)?;
|
self.consume_type(lhs)?.mark();
|
||||||
let out = mid(self)?;
|
let out = match mid(self) {
|
||||||
self.consume_type(rhs)?;
|
Ok(out) => out,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{e}");
|
||||||
|
// Jump back in time and try to re-parse from the next brace
|
||||||
|
self.unwind()?.advance_until(lhs)?.mark();
|
||||||
|
return self.delimited(lhs, mid, rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.consume_type(rhs)?.unmark();
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,41 +251,44 @@ macro ptodo($self:expr $(, $t:expr)*) {
|
|||||||
|
|
||||||
/// # Terminals and Pseudo-Terminals
|
/// # Terminals and Pseudo-Terminals
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
pub fn identifier(&mut self) -> PResult<Identifier> {
|
fn identifier(&mut self) -> PResult<Identifier> {
|
||||||
let token = *self
|
let token = *self
|
||||||
.matches(Type::Identifier)
|
.matches(Type::Identifier)
|
||||||
.map_err(|e| Error::not_identifier().maybe_token(e.start()))?;
|
.map_err(|e| Error::not_identifier().maybe_token(e.start()))?;
|
||||||
Ok(Identifier(self.consume().text[&token].into()))
|
Ok(Identifier(self.consume().text[&token].into()))
|
||||||
}
|
}
|
||||||
pub fn literal(&mut self) -> PResult<literal::Literal> {
|
fn literal(&mut self) -> PResult<literal::Literal> {
|
||||||
use literal::Literal::*;
|
use literal::Literal::*;
|
||||||
use Keyword::{False, True};
|
use Keyword::{False, True};
|
||||||
let tok = self.peek()?;
|
let tok = self.peek()?;
|
||||||
match tok.ty() {
|
match tok.ty() {
|
||||||
Type::Float => self.float().map(Float),
|
Type::Float => self.float().map(Float),
|
||||||
Type::Integer => self.int::<10>().map(Int),
|
Type::Integer => self.int().map(Int),
|
||||||
Type::String => self.string().map(String),
|
Type::String => self.string().map(String),
|
||||||
Type::Character => self.char().map(Char),
|
Type::Character => self.char().map(Char),
|
||||||
Type::Keyword(True | False) => self.bool().map(Bool),
|
Type::Keyword(True | False) => self.bool().map(Bool),
|
||||||
_ => Err(Error::not_literal().token(*tok)),
|
_ => Err(Error::not_literal().token(*tok)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn float(&mut self) -> PResult<literal::Float> {
|
fn float(&mut self) -> PResult<literal::Float> {
|
||||||
ptodo!(self)
|
ptodo!(self)
|
||||||
}
|
}
|
||||||
pub fn int<const BASE: u32>(&mut self) -> PResult<u128> {
|
fn int(&mut self) -> PResult<u128> {
|
||||||
let token = *self.matches(Type::Integer)?;
|
let token = *self.matches(Type::Integer)?;
|
||||||
u128::from_str_radix(&self.consume().text[&token], BASE)
|
self.consume().text[&token]
|
||||||
.map_err(|_| Error::not_int().token(token))
|
.chars()
|
||||||
|
.parse_int::<u128>()
|
||||||
|
.next()
|
||||||
|
.ok_or(Error::not_int().token(token))
|
||||||
}
|
}
|
||||||
pub fn string(&mut self) -> PResult<String> {
|
fn string(&mut self) -> PResult<String> {
|
||||||
let range = self
|
let range = self
|
||||||
.matches(Type::String)
|
.matches(Type::String)
|
||||||
.map_err(|e| e.reason(NotString))?
|
.map_err(|e| e.reason(NotString))?
|
||||||
.range();
|
.range();
|
||||||
Ok(self.consume().text[range].chars().unescape().collect())
|
Ok(self.consume().text[range].chars().unescape().collect())
|
||||||
}
|
}
|
||||||
pub fn char(&mut self) -> PResult<char> {
|
fn char(&mut self) -> PResult<char> {
|
||||||
let token = *self.matches(Type::Character)?;
|
let token = *self.matches(Type::Character)?;
|
||||||
self.consume().text[&token]
|
self.consume().text[&token]
|
||||||
.chars()
|
.chars()
|
||||||
@ -270,7 +296,7 @@ impl<'t> Parser<'t> {
|
|||||||
.next()
|
.next()
|
||||||
.ok_or(Error::not_char().token(token))
|
.ok_or(Error::not_char().token(token))
|
||||||
}
|
}
|
||||||
pub fn bool(&mut self) -> PResult<bool> {
|
fn bool(&mut self) -> PResult<bool> {
|
||||||
use Keyword::{False, True};
|
use Keyword::{False, True};
|
||||||
let token = self.peek()?;
|
let token = self.peek()?;
|
||||||
let out = match token.ty() {
|
let out = match token.ty() {
|
||||||
@ -284,22 +310,15 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
/// Expressions
|
/// Expressions
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
pub fn expr(&mut self) -> PResult<expression::Expr> {
|
fn expr(&mut self) -> PResult<expression::Expr> {
|
||||||
use expression::Expr;
|
use expression::Expr;
|
||||||
Ok(Expr { ignore: self.ignore()? })
|
Ok(Expr { ignore: self.ignore()? })
|
||||||
}
|
}
|
||||||
pub fn if_not_expr(&mut self, matches: Type) -> PResult<Option<expression::Expr>> {
|
fn block(&mut self) -> PResult<expression::Block> {
|
||||||
if self.peek()?.ty() == matches {
|
self.delimited(Type::LCurly, |p| p.expr(), Type::RCurly)
|
||||||
Ok(None)
|
.map(|e| expression::Block { expr: Box::new(e) })
|
||||||
} else {
|
|
||||||
Some(self.expr()).transpose()
|
|
||||||
}
|
}
|
||||||
}
|
fn group(&mut self) -> PResult<expression::Group> {
|
||||||
pub fn block(&mut self) -> PResult<expression::Block> {
|
|
||||||
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> {
|
|
||||||
use expression::Group;
|
use expression::Group;
|
||||||
let t = self.consume_type(Type::LParen)?.peek()?;
|
let t = self.consume_type(Type::LParen)?.peek()?;
|
||||||
match t.ty() {
|
match t.ty() {
|
||||||
@ -314,14 +333,21 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn primary(&mut self) -> PResult<expression::Primary> {
|
fn primary(&mut self) -> PResult<expression::Primary> {
|
||||||
use expression::Primary;
|
use expression::Primary;
|
||||||
self.identifier()
|
let token = *self.peek()?;
|
||||||
.map(Primary::Identifier)
|
match token.ty() {
|
||||||
.or_else(|_| self.literal().map(Primary::Literal))
|
Type::Identifier => self.identifier().map(Primary::Identifier),
|
||||||
.or_else(|_| self.block().map(Primary::Block))
|
Type::String
|
||||||
.or_else(|_| self.group().map(Primary::Group))
|
| Type::Character
|
||||||
.or_else(|_| self.flow().map(Primary::Branch))
|
| Type::Integer
|
||||||
|
| Type::Float
|
||||||
|
| Type::Keyword(Keyword::True | Keyword::False) => self.literal().map(Primary::Literal),
|
||||||
|
Type::LCurly => self.block().map(Primary::Block),
|
||||||
|
Type::LParen => self.group().map(Primary::Group),
|
||||||
|
Type::Keyword(_) => self.flow().map(Primary::Branch),
|
||||||
|
_ => Err(Error::all_else_failed().token(token))?,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,65 +363,130 @@ impl<'t> Parser<'t> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// becomes
|
/// becomes
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// pub fn function_name(&mut self) -> PResult<ret::Value> { ... }
|
/// fn function_name(&mut self) -> PResult<ret::Value> { ... }
|
||||||
/// ```
|
/// ```
|
||||||
macro binary ($($f:ident: $Ret:ty = $a:ident, $b:ident);*$(;)?) {$(
|
macro binary ($($f:ident = $a:ident, $b:ident);*$(;)?) {$(
|
||||||
pub fn $f (&mut self) -> PResult<$Ret> {
|
fn $f (&mut self) -> PResult<math::Operation> {
|
||||||
let (first, mut others) = (self.$a()?, vec![]);
|
let (first, mut others) = (self.$a()?, vec![]);
|
||||||
while let Some(op) = self.$b() {
|
while let Ok(op) = self.$b() {
|
||||||
others.push((op, self.$a()?));
|
others.push((op, self.$a()?));
|
||||||
}
|
}
|
||||||
Ok(<$Ret>::new(first, others))
|
Ok(if others.is_empty() { first } else {
|
||||||
|
math::Operation::binary(first, others)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)*}
|
)*}
|
||||||
/// # [Arithmetic and Logical Subexpressions](math)
|
/// # [Arithmetic and Logical Subexpressions](math)
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
binary! {
|
binary! {
|
||||||
//name returns operands operators
|
//name operands operators
|
||||||
ignore: math::Ignore = assign, ignore_op;
|
ignore = assign, ignore_op;
|
||||||
assign: math::Assign = compare, assign_op;
|
assign = compare, assign_op;
|
||||||
compare: math::Compare = logic, compare_op;
|
compare = logic, compare_op;
|
||||||
logic: math::Logic = bitwise, logic_op;
|
logic = bitwise, logic_op;
|
||||||
bitwise: math::Bitwise = shift, bitwise_op;
|
bitwise = shift, bitwise_op;
|
||||||
shift: math::Shift = term, shift_op;
|
shift = term, shift_op;
|
||||||
term: math::Term = factor, term_op;
|
term = factor, term_op;
|
||||||
factor: math::Factor = unary, factor_op;
|
factor = unary, factor_op;
|
||||||
}
|
}
|
||||||
pub fn unary(&mut self) -> PResult<math::Unary> {
|
|
||||||
let mut ops = vec![];
|
fn unary(&mut self) -> PResult<math::Operation> {
|
||||||
while let Some(op) = self.unary_op() {
|
let mut operators = vec![];
|
||||||
ops.push(op)
|
while let Ok(op) = self.unary_op() {
|
||||||
|
operators.push(op)
|
||||||
}
|
}
|
||||||
Ok(math::Unary(ops, self.primary()?))
|
Ok(math::Operation::Unary { operators, operand: self.primary()? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
macro operator_impl($($(#[$m:meta])*$f:ident: $Ret:ty),*$(,)*) {$(
|
macro operator_impl ($($(#[$m:meta])* $f:ident : {$($type:pat => $op:ident),*$(,)?})*) {
|
||||||
$(#[$m])* pub fn $f(&mut self) -> Option<$Ret> {
|
$($(#[$m])* fn $f(&mut self) -> PResult<operator::Binary> {
|
||||||
let out: Option<$Ret> = self.peek().ok()?.ty().into();
|
use operator::Binary;
|
||||||
if out.is_some() { self.consume(); }
|
let token = *self.peek()?;
|
||||||
|
let out = Ok(match token.ty() {
|
||||||
|
$($type => Binary::$op,)*
|
||||||
|
_ => Err(Error::not_operator().token(token))?,
|
||||||
|
});
|
||||||
|
self.consume();
|
||||||
out
|
out
|
||||||
|
})*
|
||||||
}
|
}
|
||||||
)*}
|
|
||||||
/// # [Operators](operator)
|
/// # [Operators](operator)
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
operator_impl! {
|
operator_impl! {
|
||||||
ignore_op: operator::Ignore,
|
factor_op: {
|
||||||
compare_op: operator::Compare,
|
Type::Star => Mul,
|
||||||
assign_op: operator::Assign,
|
Type::Slash => Div,
|
||||||
logic_op: operator::Logic,
|
Type::Rem => Rem,
|
||||||
bitwise_op: operator::Bitwise,
|
}
|
||||||
shift_op: operator::Shift,
|
term_op: {
|
||||||
term_op: operator::Term,
|
Type::Plus => Add,
|
||||||
factor_op: operator::Factor,
|
Type::Minus => Sub,
|
||||||
unary_op: operator::Unary,
|
}
|
||||||
|
shift_op: {
|
||||||
|
Type::LtLt => Lsh,
|
||||||
|
Type::GtGt => Rsh,
|
||||||
|
}
|
||||||
|
bitwise_op: {
|
||||||
|
Type::Amp => BitAnd,
|
||||||
|
Type::Bar => BitOr,
|
||||||
|
Type::Xor => BitXor,
|
||||||
|
}
|
||||||
|
logic_op: {
|
||||||
|
Type::AmpAmp => LogAnd,
|
||||||
|
Type::BarBar => LogOr,
|
||||||
|
Type::XorXor => LogXor,
|
||||||
|
}
|
||||||
|
compare_op: {
|
||||||
|
Type::Lt => Less,
|
||||||
|
Type::LtEq => LessEq,
|
||||||
|
Type::EqEq => Equal,
|
||||||
|
Type::BangEq => NotEq,
|
||||||
|
Type::GtEq => GreaterEq,
|
||||||
|
Type::Gt => Greater,
|
||||||
|
}
|
||||||
|
assign_op: {
|
||||||
|
Type::Eq => Assign,
|
||||||
|
Type::PlusEq => AddAssign,
|
||||||
|
Type::MinusEq => SubAssign,
|
||||||
|
Type::StarEq => MulAssign,
|
||||||
|
Type::SlashEq => DivAssign,
|
||||||
|
Type::RemEq => RemAssign,
|
||||||
|
Type::AmpEq => BitAndAssign,
|
||||||
|
Type::BarEq => BitOrAssign,
|
||||||
|
Type::XorEq => BitXorAssign,
|
||||||
|
Type::LtLtEq => ShlAssign,
|
||||||
|
Type::GtGtEq => ShrAssign,
|
||||||
|
}
|
||||||
|
ignore_op: {
|
||||||
|
Type::Semi => Ignore,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/// Parse a [unary operator](operator::Unary)
|
||||||
|
fn unary_op(&mut self) -> PResult<operator::Unary> {
|
||||||
|
use operator::Unary;
|
||||||
|
let token = *self.peek()?;
|
||||||
|
let out = Ok(match token.ty() {
|
||||||
|
Type::AmpAmp => Unary::RefRef,
|
||||||
|
Type::Amp => Unary::Ref,
|
||||||
|
Type::Star => Unary::Deref,
|
||||||
|
Type::Minus => Unary::Neg,
|
||||||
|
Type::Bang => Unary::Not,
|
||||||
|
Type::At => Unary::At,
|
||||||
|
Type::Hash => Unary::Hash,
|
||||||
|
Type::Tilde => Unary::Tilde,
|
||||||
|
_ => Err(Error::not_operator().token(token))?,
|
||||||
|
});
|
||||||
|
self.consume();
|
||||||
|
out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// # [Control Flow](control)
|
/// # [Control Flow](control)
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
pub fn flow(&mut self) -> PResult<control::Flow> {
|
fn flow(&mut self) -> PResult<control::Flow> {
|
||||||
use control::Flow;
|
use control::Flow;
|
||||||
use Keyword::{Break, Continue, For, If, Return, While};
|
use Keyword::{Break, Continue, For, If, Return, While};
|
||||||
let token = self.peek()?;
|
let token = *self.peek()?;
|
||||||
match token.ty() {
|
match token.ty() {
|
||||||
Type::Keyword(While) => self.parse_while().map(Flow::While),
|
Type::Keyword(While) => self.parse_while().map(Flow::While),
|
||||||
Type::Keyword(For) => self.parse_for().map(Flow::For),
|
Type::Keyword(For) => self.parse_for().map(Flow::For),
|
||||||
@ -403,10 +494,11 @@ impl<'t> Parser<'t> {
|
|||||||
Type::Keyword(Break) => self.parse_break().map(Flow::Break),
|
Type::Keyword(Break) => self.parse_break().map(Flow::Break),
|
||||||
Type::Keyword(Return) => self.parse_return().map(Flow::Return),
|
Type::Keyword(Return) => self.parse_return().map(Flow::Return),
|
||||||
Type::Keyword(Continue) => self.parse_continue().map(Flow::Continue),
|
Type::Keyword(Continue) => self.parse_continue().map(Flow::Continue),
|
||||||
_ => Err(Error::not_branch().token(*token)),
|
_ => Err(Error::all_else_failed().token(token)),
|
||||||
}
|
}
|
||||||
|
.map_err(|e| e.reason(IncompleteBranch).token(token))
|
||||||
}
|
}
|
||||||
pub fn parse_if(&mut self) -> PResult<control::If> {
|
fn parse_if(&mut self) -> PResult<control::If> {
|
||||||
self.keyword(Keyword::If)?;
|
self.keyword(Keyword::If)?;
|
||||||
Ok(control::If {
|
Ok(control::If {
|
||||||
cond: self.expr()?.into(),
|
cond: self.expr()?.into(),
|
||||||
@ -414,7 +506,7 @@ impl<'t> Parser<'t> {
|
|||||||
else_: self.parse_else()?,
|
else_: self.parse_else()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn parse_while(&mut self) -> PResult<control::While> {
|
fn parse_while(&mut self) -> PResult<control::While> {
|
||||||
self.keyword(Keyword::While)?;
|
self.keyword(Keyword::While)?;
|
||||||
Ok(control::While {
|
Ok(control::While {
|
||||||
cond: self.expr()?.into(),
|
cond: self.expr()?.into(),
|
||||||
@ -422,7 +514,7 @@ impl<'t> Parser<'t> {
|
|||||||
else_: self.parse_else()?,
|
else_: self.parse_else()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn parse_for(&mut self) -> PResult<control::For> {
|
fn parse_for(&mut self) -> PResult<control::For> {
|
||||||
self.keyword(Keyword::For)?;
|
self.keyword(Keyword::For)?;
|
||||||
Ok(control::For {
|
Ok(control::For {
|
||||||
var: self.identifier()?,
|
var: self.identifier()?,
|
||||||
@ -431,20 +523,21 @@ impl<'t> Parser<'t> {
|
|||||||
else_: self.parse_else()?,
|
else_: self.parse_else()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn parse_else(&mut self) -> PResult<Option<control::Else>> {
|
fn parse_else(&mut self) -> PResult<Option<control::Else>> {
|
||||||
// it's fine for `else` to be missing entirely
|
// it's fine for `else` to be missing entirely
|
||||||
self.keyword(Keyword::Else)
|
self.keyword(Keyword::Else)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|p| Ok(control::Else { block: p.block()? }))
|
.map(|p| Ok(control::Else { block: p.block()? }))
|
||||||
.transpose()
|
.transpose()
|
||||||
}
|
}
|
||||||
pub fn parse_break(&mut self) -> PResult<control::Break> {
|
fn parse_break(&mut self) -> PResult<control::Break> {
|
||||||
Ok(control::Break { expr: self.keyword(Keyword::Break)?.expr()?.into() })
|
Ok(control::Break { expr: self.keyword(Keyword::Break)?.expr()?.into() })
|
||||||
}
|
}
|
||||||
pub fn parse_return(&mut self) -> PResult<control::Return> {
|
fn parse_return(&mut self) -> PResult<control::Return> {
|
||||||
Ok(control::Return { expr: self.keyword(Keyword::Return)?.expr()?.into() })
|
Ok(control::Return { expr: self.keyword(Keyword::Return)?.expr()?.into() })
|
||||||
}
|
}
|
||||||
pub fn parse_continue(&mut self) -> PResult<control::Continue> {
|
fn parse_continue(&mut self) -> PResult<control::Continue> {
|
||||||
ptodo!(self)
|
self.keyword(Keyword::Continue)?;
|
||||||
|
Ok(control::Continue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,135 +63,111 @@ 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_binary<F, Op>(&mut self, expr: &math::Binary<F, (Op, F)>) -> IOResult<()>
|
fn visit_operation(&mut self, expr: &math::Operation) -> IOResult<()> {
|
||||||
where
|
use math::Operation;
|
||||||
F: Walk<Self, IOResult<()>>,
|
match expr {
|
||||||
Op: Walk<Self, IOResult<()>>,
|
Operation::Binary { first, other } => {
|
||||||
{
|
self.put('(')?.visit_operation(first)?;
|
||||||
expr.first().walk(self)?;
|
for (op, other) in other {
|
||||||
for (op, target) in expr.other() {
|
self.visit_binary_op(op)?;
|
||||||
op.walk(self)?;
|
self.visit_operation(other)?;
|
||||||
target.walk(self)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
self.put(')').map(drop)
|
||||||
}
|
}
|
||||||
|
Operation::Unary { operators, operand } => {
|
||||||
fn visit_unary(&mut self, expr: &math::Unary) -> IOResult<()> {
|
for op in operators {
|
||||||
for op in &expr.0 {
|
self.visit_unary_op(op)?;
|
||||||
op.walk(self)?;
|
|
||||||
}
|
}
|
||||||
expr.1.walk(self)
|
self.visit_primary(operand)
|
||||||
}
|
}
|
||||||
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<()> {
|
}
|
||||||
|
fn visit_binary_op(&mut self, op: &operator::Binary) -> IOResult<()> {
|
||||||
|
use operator::Binary;
|
||||||
visit_operator!(self.match op {
|
visit_operator!(self.match op {
|
||||||
operator::Compare::Less => "<",
|
Binary::Mul => "*",
|
||||||
operator::Compare::LessEq => "<=",
|
Binary::Div => "/",
|
||||||
operator::Compare::Equal => "==",
|
Binary::Rem => "%",
|
||||||
operator::Compare::NotEq => "!=",
|
Binary::Add => "+",
|
||||||
operator::Compare::GreaterEq => ">=",
|
Binary::Sub => "-",
|
||||||
operator::Compare::Greater => ">",
|
Binary::Lsh => "<<",
|
||||||
})
|
Binary::Rsh => ">>",
|
||||||
}
|
Binary::BitAnd => "&",
|
||||||
fn visit_assign_op(&mut self, op: &operator::Assign) -> IOResult<()> {
|
Binary::BitOr => "|",
|
||||||
visit_operator!( self.match op {
|
Binary::BitXor => "^",
|
||||||
operator::Assign::Assign => "=",
|
Binary::LogAnd => "&&",
|
||||||
operator::Assign::AddAssign => "+=",
|
Binary::LogOr => "||",
|
||||||
operator::Assign::SubAssign => "-=",
|
Binary::LogXor => "^^",
|
||||||
operator::Assign::MulAssign => "*=",
|
Binary::Less => "<",
|
||||||
operator::Assign::DivAssign => "/=",
|
Binary::LessEq => "<=",
|
||||||
operator::Assign::BitAndAssign => "&=",
|
Binary::Equal => "==",
|
||||||
operator::Assign::BitOrAssign => "|=",
|
Binary::NotEq => "!=",
|
||||||
operator::Assign::BitXorAssign => "^=",
|
Binary::GreaterEq => ">=",
|
||||||
operator::Assign::ShlAssign => "<<=",
|
Binary::Greater => ">",
|
||||||
operator::Assign::ShrAssign => ">>=",
|
Binary::Assign => "=",
|
||||||
})
|
Binary::AddAssign => "+=",
|
||||||
}
|
Binary::SubAssign => "-=",
|
||||||
fn visit_logic_op(&mut self, op: &operator::Logic) -> IOResult<()> {
|
Binary::MulAssign => "*=",
|
||||||
visit_operator!(self.match op {
|
Binary::DivAssign => "/=",
|
||||||
operator::Logic::LogAnd => "&&",
|
Binary::RemAssign => "%=",
|
||||||
operator::Logic::LogOr => "||",
|
Binary::BitAndAssign => "&=",
|
||||||
operator::Logic::LogXor => "^^",
|
Binary::BitOrAssign => "|=",
|
||||||
})
|
Binary::BitXorAssign => "^=",
|
||||||
}
|
Binary::ShlAssign => "<<=",
|
||||||
fn visit_bitwise_op(&mut self, op: &operator::Bitwise) -> IOResult<()> {
|
Binary::ShrAssign => ">>=",
|
||||||
visit_operator!(self.match op {
|
Binary::Ignore => ";",
|
||||||
operator::Bitwise::BitAnd => "&",
|
|
||||||
operator::Bitwise::BitOr => "|",
|
|
||||||
operator::Bitwise::BitXor => "^",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn visit_shift_op(&mut self, op: &operator::Shift) -> IOResult<()> {
|
|
||||||
visit_operator!(self.match op {
|
|
||||||
operator::Shift::Lsh => "<<",
|
|
||||||
operator::Shift::Rsh => ">>",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn visit_term_op(&mut self, op: &operator::Term) -> IOResult<()> {
|
|
||||||
visit_operator!(self.match op {
|
|
||||||
operator::Term::Add => "+",
|
|
||||||
operator::Term::Sub => "-",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn visit_factor_op(&mut self, op: &operator::Factor) -> IOResult<()> {
|
|
||||||
visit_operator!(self.match op {
|
|
||||||
operator::Factor::Mul => "*",
|
|
||||||
operator::Factor::Div => "/",
|
|
||||||
operator::Factor::Rem => "%",
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn visit_unary_op(&mut self, op: &operator::Unary) -> IOResult<()> {
|
fn visit_unary_op(&mut self, op: &operator::Unary) -> IOResult<()> {
|
||||||
|
use operator::Unary;
|
||||||
self.put(match op {
|
self.put(match op {
|
||||||
operator::Unary::RefRef => "&&",
|
Unary::RefRef => "&&",
|
||||||
operator::Unary::Deref => "*",
|
Unary::Deref => "*",
|
||||||
operator::Unary::Ref => "&",
|
Unary::Ref => "&",
|
||||||
operator::Unary::Neg => "-",
|
Unary::Neg => "-",
|
||||||
operator::Unary::Not => "!",
|
Unary::Not => "!",
|
||||||
operator::Unary::At => "@",
|
Unary::At => "@",
|
||||||
operator::Unary::Hash => "#",
|
Unary::Hash => "#",
|
||||||
operator::Unary::Tilde => "~",
|
Unary::Tilde => "~",
|
||||||
})
|
})
|
||||||
.map(drop)
|
.map(drop)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_if(&mut self, expr: &control::If) -> IOResult<()> {
|
fn visit_if(&mut self, expr: &control::If) -> IOResult<()> {
|
||||||
expr.cond.walk(self.put("if")?.space()?)?;
|
self.put("while")?.space()?.visit_expr(&expr.cond)?;
|
||||||
expr.body.walk(self.space()?)?;
|
self.space()?.visit_block(&expr.body)?;
|
||||||
if let Some(e) = &expr.else_ {
|
match &expr.else_ {
|
||||||
e.walk(self)?
|
Some(e) => self.visit_else(e),
|
||||||
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
fn visit_while(&mut self, expr: &control::While) -> IOResult<()> {
|
fn visit_while(&mut self, expr: &control::While) -> IOResult<()> {
|
||||||
expr.cond.walk(self.put("while")?.space()?)?;
|
self.put("while")?.space()?.visit_expr(&expr.cond)?;
|
||||||
expr.body.walk(self.space()?)?;
|
self.space()?.visit_block(&expr.body)?;
|
||||||
if let Some(e) = &expr.else_ {
|
match &expr.else_ {
|
||||||
e.walk(self)?
|
Some(e) => self.visit_else(e),
|
||||||
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
fn visit_for(&mut self, expr: &control::For) -> IOResult<()> {
|
fn visit_for(&mut self, expr: &control::For) -> IOResult<()> {
|
||||||
expr.var.walk(self.put("for")?.space()?)?;
|
self.put("for")?.space()?.visit_identifier(&expr.var)?;
|
||||||
expr.iter.walk(self.space()?.put("in")?.space()?)?;
|
self.space()?.put("in")?.space()?.visit_expr(&expr.iter)?;
|
||||||
expr.body.walk(self.space()?)?;
|
self.space()?.visit_block(&expr.body)?;
|
||||||
if let Some(e) = &expr.else_ {
|
match &expr.else_ {
|
||||||
e.walk(self)?
|
Some(e) => self.visit_else(e),
|
||||||
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
fn visit_else(&mut self, expr: &control::Else) -> IOResult<()> {
|
fn visit_else(&mut self, expr: &control::Else) -> IOResult<()> {
|
||||||
expr.block.walk(self.space()?.put("else")?.space()?)
|
self.space()?.put("else")?.space()?.visit_block(&expr.block)
|
||||||
}
|
}
|
||||||
fn visit_continue(&mut self, _expr: &control::Continue) -> IOResult<()> {
|
fn visit_continue(&mut self, _: &control::Continue) -> IOResult<()> {
|
||||||
self.put("continue").map(drop)
|
self.put("continue").map(drop)
|
||||||
}
|
}
|
||||||
fn visit_break(&mut self, expr: &control::Break) -> IOResult<()> {
|
fn visit_break(&mut self, brk: &control::Break) -> IOResult<()> {
|
||||||
expr.expr.walk(self.put("break")?.space()?)
|
self.put("break")?.space()?.visit_expr(&brk.expr)
|
||||||
}
|
}
|
||||||
fn visit_return(&mut self, expr: &control::Return) -> IOResult<()> {
|
fn visit_return(&mut self, ret: &control::Return) -> IOResult<()> {
|
||||||
expr.expr.walk(self.put("return")?.space()?)
|
self.put("return")?.space()?.visit_expr(&ret.expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_identifier(&mut self, ident: &Identifier) -> IOResult<()> {
|
fn visit_identifier(&mut self, ident: &Identifier) -> IOResult<()> {
|
||||||
@ -220,15 +196,9 @@ impl<W: Write> Visitor<IOResult<()>> for Printer<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block(&mut self, expr: &expression::Block) -> IOResult<()> {
|
fn visit_block(&mut self, expr: &expression::Block) -> IOResult<()> {
|
||||||
self.put('{')?;
|
self.put('{')?.indent().newline()?;
|
||||||
match &expr.expr {
|
expr.walk(self)?;
|
||||||
Some(expr) => {
|
self.dedent().newline()?.put('}').map(drop)
|
||||||
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<()> {
|
fn visit_group(&mut self, expr: &expression::Group) -> IOResult<()> {
|
||||||
|
Loading…
Reference in New Issue
Block a user