parser: Refactor coagulated binops as postfix operators
This allows them to intermingle more nicely with `Try`
This commit is contained in:
82
src/ast.rs
82
src/ast.rs
@@ -1,6 +1,6 @@
|
||||
//! The Abstract Syntax Tree defines an interface between the parser and type checker
|
||||
|
||||
pub mod matcher;
|
||||
pub mod macro_matcher;
|
||||
|
||||
/// A value with an annotation.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -10,6 +10,7 @@ pub struct Anno<T: Annotation, A: Annotation = Span>(pub T, pub A);
|
||||
pub trait Annotation: Clone + std::fmt::Display + std::fmt::Debug + PartialEq + Eq {}
|
||||
impl<T: Clone + std::fmt::Debug + std::fmt::Display + PartialEq + Eq> Annotation for T {}
|
||||
|
||||
/// A literal value (boolean, character, integer, string)
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Literal {
|
||||
/// A boolean literal: true | false
|
||||
@@ -25,13 +26,22 @@ pub enum Literal {
|
||||
/// Binding patterns for each kind of matchable [Ty]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Pat {
|
||||
/// Matches anything without binding
|
||||
Ignore,
|
||||
/// Matches nothing; used for macro substitution.
|
||||
MetId(String),
|
||||
/// Matches anything, and binds it to a name
|
||||
Name(String),
|
||||
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`).
|
||||
Rest(Option<Box<Pat>>),
|
||||
/// Matches a literal value by equality comparison
|
||||
Lit(Literal),
|
||||
/// Matches the elements of a tuple
|
||||
Tuple(Vec<Pat>),
|
||||
/// Matches the elements
|
||||
Slice(Vec<Pat>),
|
||||
/// Matches one of the provided alternates
|
||||
Alt(Vec<Pat>),
|
||||
}
|
||||
|
||||
/// The arms of a make expression
|
||||
@@ -53,6 +63,8 @@ pub struct MatchArm<A: Annotation = Span>(pub Vec<Pat>, pub Anno<Expr<A>, A>);
|
||||
pub enum Ty {
|
||||
/// `_`
|
||||
Infer,
|
||||
/// `(Identifier :: )* Identifier`
|
||||
Named(String),
|
||||
/// `(..Tys)`
|
||||
Tuple(Vec<Ty>),
|
||||
/// `[Ty]`
|
||||
@@ -72,12 +84,12 @@ pub enum Expr<A: Annotation = Span> {
|
||||
MetId(String),
|
||||
/// A literal bool, string, char, or int
|
||||
Lit(Literal),
|
||||
/// let pattern = expr
|
||||
/// let Pat<NoTopAlt> = expr
|
||||
Let(Pat, Option<Box<Anno<Self, A>>>),
|
||||
/// `const Pat (= Expr)?` (Basically let rec)
|
||||
/// `const Pat<NoTopAlt> (= Expr)?` (Basically let rec)
|
||||
Const(Pat, Box<Anno<Self, A>>),
|
||||
/// `| Pat,* | Expr` | `|| Expr` | `fn (Pat,*) Expr`
|
||||
Fn(Vec<Pat>, Box<Anno<Self, A>>),
|
||||
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn (Pat,*) Expr`
|
||||
Fn(Pat, Box<Anno<Self, A>>),
|
||||
/// Expr { (Ident (: Expr)?),* }
|
||||
Make(Box<Anno<Self, A>>, Vec<MakeArm<A>>),
|
||||
/// match Expr { MatchArm,* }
|
||||
@@ -101,50 +113,22 @@ impl<A: Annotation> Expr<A> {
|
||||
| Self::Op(Op::Deref, _)
|
||||
)
|
||||
}
|
||||
|
||||
// pub fn is_assignee(&self) -> bool {
|
||||
// match self {
|
||||
// Self::Id(_) => todo!(),
|
||||
// Self::MetId(_) => todo!(),
|
||||
// Self::Lit(literal) => todo!(),
|
||||
// Self::Let(pat, anno) => todo!(),
|
||||
// Self::Const(pat, anno) => todo!(),
|
||||
// Self::Fn(pats, anno) => todo!(),
|
||||
// Self::Make(anno, make_arms) => todo!(),
|
||||
// Self::Match(anno, match_arms) => todo!(),
|
||||
// Self::Op(Op::Add, annos) => todo!(),
|
||||
// Self::Op(Op::And, _) => false,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Op {
|
||||
// -- fake operators used to assign precedences to special forms
|
||||
Id, // Identifier
|
||||
Mid, // MetaIdentifier
|
||||
Lit, // Literal
|
||||
Let, // let Pat = Expr
|
||||
Const, // const Pat = Expr
|
||||
Fn, // fn ( Pat,* ) Expr
|
||||
Make, // Expr{ Expr,* }
|
||||
Macro, // macro Expr => Expr
|
||||
Match, // match Expr { MatchArm,* }
|
||||
End, // Produces an empty value.
|
||||
|
||||
// -- true operators
|
||||
Do, // Expr ; Expr
|
||||
Macro, // macro Expr => Expr
|
||||
Block, // { Expr }
|
||||
Array, // [ Expr,* ]
|
||||
Group, // ( Expr ,?)
|
||||
Tuple, // ( Expr,* )
|
||||
Tuple, // Expr (, Expr)*
|
||||
|
||||
Try, // Expr '?'
|
||||
Index, // Expr [ Expr,* ]
|
||||
Call, // Expr ( Expr,* )
|
||||
|
||||
Lambda, // |Pat?| Expr
|
||||
|
||||
Loop, // loop Expr
|
||||
If, // if Expr Expr (else Expr)?
|
||||
While, // while Expr Expr (else Expr)?
|
||||
@@ -220,20 +204,23 @@ impl<A: Annotation> Display for Expr<A> {
|
||||
Self::Let(pat, None) => write!(f, "let {pat}"),
|
||||
Self::Const(pat, expr) => write!(f, "const {pat} = {expr}"),
|
||||
Self::Make(expr, make_arms) => {
|
||||
f.delimit(fmt!("make {expr} {{"), "}").list(make_arms, ", ")
|
||||
f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ")
|
||||
}
|
||||
Self::Match(expr, match_arms) => f
|
||||
.delimit_indented(fmt!("match {expr} {{\n"), "\n}")
|
||||
.list_end(match_arms, ",\n", ","),
|
||||
Self::Fn(pats, expr) => f.delimit("fn (", fmt!(") {expr}")).list(pats, ", "),
|
||||
.delimit_indented(fmt!("match {expr} {{\n"), "}")
|
||||
.list_wrap("\n", match_arms, ",\n", ",\n"),
|
||||
Self::Fn(pat, expr) => write!(f, "fn {pat} {expr}"),
|
||||
|
||||
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
||||
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
||||
other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
|
||||
},
|
||||
Self::Op(Op::Array, exprs) => f.delimit("[", "]").list(exprs, ", "),
|
||||
Self::Op(Op::Block, exprs) => f.delimit_indented("{\n", "\n}").list(exprs, ", "),
|
||||
Self::Op(Op::Block, exprs) => f
|
||||
.delimit_indented("{", "}")
|
||||
.list_wrap("\n", exprs, "\n", "\n"),
|
||||
Self::Op(Op::Tuple, exprs) => f.delimit("(", ")").list(exprs, ", "),
|
||||
Self::Op(Op::Group, exprs) => f.list(exprs, ", "),
|
||||
|
||||
Self::Op(op @ Op::Call, exprs) => match exprs.as_slice() {
|
||||
[callee, args @ ..] => f.delimit(fmt!("{callee}("), ")").list(args, ", "),
|
||||
@@ -246,9 +233,9 @@ impl<A: Annotation> Display for Expr<A> {
|
||||
|
||||
Self::Op(Op::Do, exprs) => f.list(exprs, ";\n"),
|
||||
Self::Op(op @ Op::Macro, exprs) => f.delimit(op, "").list(exprs, " => "),
|
||||
Self::Op(op @ Op::Try, exprs) => f.delimit("", op).list(exprs, ", "),
|
||||
Self::Op(op @ Op::Try, exprs) => f.delimit("(", fmt!("){op}")).list(exprs, ", "),
|
||||
Self::Op(op, exprs) => match exprs.as_slice() {
|
||||
[_] => f.delimit(op, "").list(exprs, ", "),
|
||||
[one] => write!(f, "{op}({one})"),
|
||||
many => f.delimit("(", ")").list(many, op),
|
||||
},
|
||||
}
|
||||
@@ -259,15 +246,7 @@ impl Display for Op {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Op::Do => "; ".fmt(f),
|
||||
Op::Id => "_".fmt(f),
|
||||
Op::Mid => "`".fmt(f),
|
||||
Op::Lit => "##".fmt(f),
|
||||
Op::Let => "let ".fmt(f),
|
||||
Op::Const => "const ".fmt(f),
|
||||
Op::Fn => "fn ".fmt(f),
|
||||
Op::Macro => "macro ".fmt(f),
|
||||
Op::Match => "match ".fmt(f),
|
||||
Op::End => "()".fmt(f),
|
||||
Op::Block => "{}".fmt(f),
|
||||
Op::Array => "[]".fmt(f),
|
||||
Op::Group => "()".fmt(f),
|
||||
@@ -275,8 +254,6 @@ impl Display for Op {
|
||||
Op::Try => "?".fmt(f),
|
||||
Op::Index => "".fmt(f),
|
||||
Op::Call => "".fmt(f),
|
||||
Op::Make => "".fmt(f),
|
||||
Op::Lambda => "".fmt(f),
|
||||
Op::Loop => "loop ".fmt(f),
|
||||
Op::If => "if ".fmt(f),
|
||||
Op::While => "while ".fmt(f),
|
||||
@@ -342,6 +319,7 @@ impl Display for Pat {
|
||||
Self::Rest(None) => write!(f, ".."),
|
||||
Self::Tuple(pats) => f.delimit("(", ")").list(pats, ", "),
|
||||
Self::Slice(pats) => f.delimit("[", "]").list(pats, ", "),
|
||||
Self::Alt(pats) => f.delimit("<", ">").list(pats, " | "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user