parser: Refactor coagulated binops as postfix operators
This allows them to intermingle more nicely with `Try`
This commit is contained in:
parent
baf94a9dab
commit
b6949147c4
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
|
//! 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.
|
/// A value with an annotation.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[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 {}
|
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 {}
|
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)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
/// A boolean literal: true | false
|
/// A boolean literal: true | false
|
||||||
@ -25,13 +26,22 @@ pub enum Literal {
|
|||||||
/// Binding patterns for each kind of matchable [Ty]
|
/// Binding patterns for each kind of matchable [Ty]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Pat {
|
pub enum Pat {
|
||||||
|
/// Matches anything without binding
|
||||||
Ignore,
|
Ignore,
|
||||||
|
/// Matches nothing; used for macro substitution.
|
||||||
MetId(String),
|
MetId(String),
|
||||||
|
/// Matches anything, and binds it to a name
|
||||||
Name(String),
|
Name(String),
|
||||||
|
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`).
|
||||||
Rest(Option<Box<Pat>>),
|
Rest(Option<Box<Pat>>),
|
||||||
|
/// Matches a literal value by equality comparison
|
||||||
Lit(Literal),
|
Lit(Literal),
|
||||||
|
/// Matches the elements of a tuple
|
||||||
Tuple(Vec<Pat>),
|
Tuple(Vec<Pat>),
|
||||||
|
/// Matches the elements
|
||||||
Slice(Vec<Pat>),
|
Slice(Vec<Pat>),
|
||||||
|
/// Matches one of the provided alternates
|
||||||
|
Alt(Vec<Pat>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The arms of a make expression
|
/// 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 {
|
pub enum Ty {
|
||||||
/// `_`
|
/// `_`
|
||||||
Infer,
|
Infer,
|
||||||
|
/// `(Identifier :: )* Identifier`
|
||||||
|
Named(String),
|
||||||
/// `(..Tys)`
|
/// `(..Tys)`
|
||||||
Tuple(Vec<Ty>),
|
Tuple(Vec<Ty>),
|
||||||
/// `[Ty]`
|
/// `[Ty]`
|
||||||
@ -72,12 +84,12 @@ pub enum Expr<A: Annotation = Span> {
|
|||||||
MetId(String),
|
MetId(String),
|
||||||
/// A literal bool, string, char, or int
|
/// A literal bool, string, char, or int
|
||||||
Lit(Literal),
|
Lit(Literal),
|
||||||
/// let pattern = expr
|
/// let Pat<NoTopAlt> = expr
|
||||||
Let(Pat, Option<Box<Anno<Self, A>>>),
|
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>>),
|
Const(Pat, Box<Anno<Self, A>>),
|
||||||
/// `| Pat,* | Expr` | `|| Expr` | `fn (Pat,*) Expr`
|
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn (Pat,*) Expr`
|
||||||
Fn(Vec<Pat>, Box<Anno<Self, A>>),
|
Fn(Pat, Box<Anno<Self, A>>),
|
||||||
/// Expr { (Ident (: Expr)?),* }
|
/// Expr { (Ident (: Expr)?),* }
|
||||||
Make(Box<Anno<Self, A>>, Vec<MakeArm<A>>),
|
Make(Box<Anno<Self, A>>, Vec<MakeArm<A>>),
|
||||||
/// match Expr { MatchArm,* }
|
/// match Expr { MatchArm,* }
|
||||||
@ -101,50 +113,22 @@ impl<A: Annotation> Expr<A> {
|
|||||||
| Self::Op(Op::Deref, _)
|
| 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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum Op {
|
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
|
// -- true operators
|
||||||
Do, // Expr ; Expr
|
Do, // Expr ; Expr
|
||||||
|
Macro, // macro Expr => Expr
|
||||||
Block, // { Expr }
|
Block, // { Expr }
|
||||||
Array, // [ Expr,* ]
|
Array, // [ Expr,* ]
|
||||||
Group, // ( Expr ,?)
|
Group, // ( Expr ,?)
|
||||||
Tuple, // ( Expr,* )
|
Tuple, // Expr (, Expr)*
|
||||||
|
|
||||||
Try, // Expr '?'
|
Try, // Expr '?'
|
||||||
Index, // Expr [ Expr,* ]
|
Index, // Expr [ Expr,* ]
|
||||||
Call, // Expr ( Expr,* )
|
Call, // Expr ( Expr,* )
|
||||||
|
|
||||||
Lambda, // |Pat?| Expr
|
|
||||||
|
|
||||||
Loop, // loop Expr
|
Loop, // loop Expr
|
||||||
If, // if Expr Expr (else Expr)?
|
If, // if Expr Expr (else Expr)?
|
||||||
While, // while 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::Let(pat, None) => write!(f, "let {pat}"),
|
||||||
Self::Const(pat, expr) => write!(f, "const {pat} = {expr}"),
|
Self::Const(pat, expr) => write!(f, "const {pat} = {expr}"),
|
||||||
Self::Make(expr, make_arms) => {
|
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
|
Self::Match(expr, match_arms) => f
|
||||||
.delimit_indented(fmt!("match {expr} {{\n"), "\n}")
|
.delimit_indented(fmt!("match {expr} {{\n"), "}")
|
||||||
.list_end(match_arms, ",\n", ","),
|
.list_wrap("\n", match_arms, ",\n", ",\n"),
|
||||||
Self::Fn(pats, expr) => f.delimit("fn (", fmt!(") {expr}")).list(pats, ", "),
|
Self::Fn(pat, expr) => write!(f, "fn {pat} {expr}"),
|
||||||
|
|
||||||
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
||||||
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
||||||
other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
|
other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
|
||||||
},
|
},
|
||||||
Self::Op(Op::Array, exprs) => f.delimit("[", "]").list(exprs, ", "),
|
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::Tuple, exprs) => f.delimit("(", ")").list(exprs, ", "),
|
||||||
|
Self::Op(Op::Group, exprs) => f.list(exprs, ", "),
|
||||||
|
|
||||||
Self::Op(op @ Op::Call, exprs) => match exprs.as_slice() {
|
Self::Op(op @ Op::Call, exprs) => match exprs.as_slice() {
|
||||||
[callee, args @ ..] => f.delimit(fmt!("{callee}("), ")").list(args, ", "),
|
[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::Do, exprs) => f.list(exprs, ";\n"),
|
||||||
Self::Op(op @ Op::Macro, exprs) => f.delimit(op, "").list(exprs, " => "),
|
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() {
|
Self::Op(op, exprs) => match exprs.as_slice() {
|
||||||
[_] => f.delimit(op, "").list(exprs, ", "),
|
[one] => write!(f, "{op}({one})"),
|
||||||
many => f.delimit("(", ")").list(many, op),
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Op::Do => "; ".fmt(f),
|
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::Macro => "macro ".fmt(f),
|
||||||
Op::Match => "match ".fmt(f),
|
|
||||||
Op::End => "()".fmt(f),
|
|
||||||
Op::Block => "{}".fmt(f),
|
Op::Block => "{}".fmt(f),
|
||||||
Op::Array => "[]".fmt(f),
|
Op::Array => "[]".fmt(f),
|
||||||
Op::Group => "()".fmt(f),
|
Op::Group => "()".fmt(f),
|
||||||
@ -275,8 +254,6 @@ impl Display for Op {
|
|||||||
Op::Try => "?".fmt(f),
|
Op::Try => "?".fmt(f),
|
||||||
Op::Index => "".fmt(f),
|
Op::Index => "".fmt(f),
|
||||||
Op::Call => "".fmt(f),
|
Op::Call => "".fmt(f),
|
||||||
Op::Make => "".fmt(f),
|
|
||||||
Op::Lambda => "".fmt(f),
|
|
||||||
Op::Loop => "loop ".fmt(f),
|
Op::Loop => "loop ".fmt(f),
|
||||||
Op::If => "if ".fmt(f),
|
Op::If => "if ".fmt(f),
|
||||||
Op::While => "while ".fmt(f),
|
Op::While => "while ".fmt(f),
|
||||||
@ -342,6 +319,7 @@ impl Display for Pat {
|
|||||||
Self::Rest(None) => write!(f, ".."),
|
Self::Rest(None) => write!(f, ".."),
|
||||||
Self::Tuple(pats) => f.delimit("(", ")").list(pats, ", "),
|
Self::Tuple(pats) => f.delimit("(", ")").list(pats, ", "),
|
||||||
Self::Slice(pats) => f.delimit("[", "]").list(pats, ", "),
|
Self::Slice(pats) => f.delimit("[", "]").list(pats, ", "),
|
||||||
|
Self::Alt(pats) => f.delimit("<", ">").list(pats, " | "),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,6 +191,8 @@ impl<A: Annotation> Match<A> for Pat {
|
|||||||
(Pat::Tuple(_), _) => false,
|
(Pat::Tuple(_), _) => false,
|
||||||
(Pat::Slice(pat), Pat::Slice(expr)) => Match::recurse(sub, pat, expr),
|
(Pat::Slice(pat), Pat::Slice(expr)) => Match::recurse(sub, pat, expr),
|
||||||
(Pat::Slice(_), _) => false,
|
(Pat::Slice(_), _) => false,
|
||||||
|
(Pat::Alt(pat), Pat::Alt(expr)) => Match::recurse(sub, pat, expr),
|
||||||
|
(Pat::Alt(_), _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +207,7 @@ impl<A: Annotation> Match<A> for Pat {
|
|||||||
Pat::Rest(pat) => pat.apply(sub),
|
Pat::Rest(pat) => pat.apply(sub),
|
||||||
Pat::Tuple(pats) => pats.apply(sub),
|
Pat::Tuple(pats) => pats.apply(sub),
|
||||||
Pat::Slice(pats) => pats.apply(sub),
|
Pat::Slice(pats) => pats.apply(sub),
|
||||||
|
Pat::Alt(pats) => pats.apply(sub),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
src/fmt.rs
26
src/fmt.rs
@ -31,7 +31,7 @@ pub trait FmtAdapter: Write {
|
|||||||
/// Formats bracketed lists of the kind (Item (Comma Item)*)?
|
/// Formats bracketed lists of the kind (Item (Comma Item)*)?
|
||||||
#[inline]
|
#[inline]
|
||||||
fn list<Item: Display, Sep: Display>(&mut self, items: &[Item], sep: Sep) -> std::fmt::Result {
|
fn list<Item: Display, Sep: Display>(&mut self, items: &[Item], sep: Sep) -> std::fmt::Result {
|
||||||
self.list_end(items, sep, "")
|
self.list_wrap("", items, sep, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_end<Item: Display, Sep: Display, End: Display>(
|
fn list_end<Item: Display, Sep: Display, End: Display>(
|
||||||
@ -40,15 +40,31 @@ pub trait FmtAdapter: Write {
|
|||||||
sep: Sep,
|
sep: Sep,
|
||||||
end: End,
|
end: End,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
let mut pats = items;
|
self.list_wrap("", items, sep, end)
|
||||||
while let [pat, rest @ ..] = pats {
|
}
|
||||||
|
|
||||||
|
/// Wraps a list in `open` and `close`.
|
||||||
|
/// This differs from [`FmtAdapter::delimit`] because it prints nothing
|
||||||
|
/// if the list is empty.
|
||||||
|
fn list_wrap<Item: Display, Sep: Display, O: Display, E: Display>(
|
||||||
|
&mut self,
|
||||||
|
open: O,
|
||||||
|
mut items: &[Item],
|
||||||
|
sep: Sep,
|
||||||
|
close: E,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
if items.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
write!(self, "{open}")?;
|
||||||
|
while let [pat, rest @ ..] = items {
|
||||||
write!(self, "{pat}")?;
|
write!(self, "{pat}")?;
|
||||||
if !rest.is_empty() {
|
if !rest.is_empty() {
|
||||||
write!(self, "{sep}")?;
|
write!(self, "{sep}")?;
|
||||||
}
|
}
|
||||||
pats = rest
|
items = rest
|
||||||
}
|
}
|
||||||
write!(self, "{end}")
|
write!(self, "{close}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,9 +46,7 @@ impl<'t> Lexer<'t> {
|
|||||||
fn advance_tail(&mut self) {
|
fn advance_tail(&mut self) {
|
||||||
match self.iter.peek() {
|
match self.iter.peek() {
|
||||||
Some(&(idx, _)) => self.tail = idx as u32,
|
Some(&(idx, _)) => self.tail = idx as u32,
|
||||||
None => {
|
None => self.tail = self.text.len() as _,
|
||||||
self.tail = self.text.len() as _;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/main.rs
16
src/main.rs
@ -3,7 +3,7 @@
|
|||||||
use doughlang::{
|
use doughlang::{
|
||||||
ast::{
|
ast::{
|
||||||
Expr,
|
Expr,
|
||||||
matcher::{Match, Subst},
|
macro_matcher::{Match, Subst},
|
||||||
},
|
},
|
||||||
lexer::{LexError, Lexer},
|
lexer::{LexError, Lexer},
|
||||||
parser::{ParseError, Parser},
|
parser::{ParseError, Parser},
|
||||||
@ -32,6 +32,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(Response::Deny)
|
Ok(Response::Deny)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
lex(line);
|
||||||
parse(line);
|
parse(line);
|
||||||
Ok(Response::Accept)
|
Ok(Response::Accept)
|
||||||
}
|
}
|
||||||
@ -82,14 +83,19 @@ fn subst() -> Result<(), Box<dyn Error>> {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if p.next_if(TKind::Colon).is_err() {
|
if p.next_if(TKind::Arrow).is_err() {
|
||||||
let Some(Subst { exp, pat }) = exp.construct(&pat) else {
|
let Some(Subst { exp, pat }) = exp.construct(&pat) else {
|
||||||
|
println!("Match failed: {exp} <- {pat}");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
for (name, pat) in pat.iter() {
|
let mut pats: Vec<_> = pat.into_iter().collect();
|
||||||
|
pats.sort_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
for (name, pat) in pats {
|
||||||
println!("{name}: {pat}")
|
println!("{name}: {pat}")
|
||||||
}
|
}
|
||||||
for (name, expr) in exp.iter() {
|
let mut exprs: Vec<_> = exp.into_iter().collect();
|
||||||
|
exprs.sort_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
for (name, expr) in exprs.iter() {
|
||||||
println!("{name}: {expr}")
|
println!("{name}: {expr}")
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -108,7 +114,7 @@ fn parse(document: &str) {
|
|||||||
let mut parser = Parser::new(Lexer::new(document));
|
let mut parser = Parser::new(Lexer::new(document));
|
||||||
loop {
|
loop {
|
||||||
match parser.parse::<Expr>(0) {
|
match parser.parse::<Expr>(0) {
|
||||||
// Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => break,
|
Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => break,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("\x1b[31m{e}\x1b[0m");
|
println!("\x1b[31m{e}\x1b[0m");
|
||||||
break;
|
break;
|
||||||
|
415
src/parser.rs
415
src/parser.rs
@ -13,6 +13,7 @@ pub mod numeric;
|
|||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
FromLexer(LexError),
|
FromLexer(LexError),
|
||||||
Expected(TKind, Span),
|
Expected(TKind, Span),
|
||||||
|
NotLiteral(TKind, Span),
|
||||||
NotPattern(TKind, Span),
|
NotPattern(TKind, Span),
|
||||||
NotPrefix(TKind, Span),
|
NotPrefix(TKind, Span),
|
||||||
NotInfix(TKind, Span),
|
NotInfix(TKind, Span),
|
||||||
@ -24,6 +25,7 @@ impl Display for ParseError {
|
|||||||
match self {
|
match self {
|
||||||
Self::FromLexer(e) => e.fmt(f),
|
Self::FromLexer(e) => e.fmt(f),
|
||||||
Self::Expected(tk, loc) => write!(f, "{loc}: Expected {tk:?}."),
|
Self::Expected(tk, loc) => write!(f, "{loc}: Expected {tk:?}."),
|
||||||
|
Self::NotLiteral(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a literal."),
|
||||||
Self::NotPattern(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a pattern."),
|
Self::NotPattern(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a pattern."),
|
||||||
Self::NotPrefix(tk, loc) => write!(f, "{loc}: {tk:?} is not a prefix operator."),
|
Self::NotPrefix(tk, loc) => write!(f, "{loc}: {tk:?} is not a prefix operator."),
|
||||||
Self::NotInfix(tk, loc) => write!(f, "{loc}: {tk:?} is not a infix operator."),
|
Self::NotInfix(tk, loc) => write!(f, "{loc}: {tk:?} is not a infix operator."),
|
||||||
@ -57,7 +59,7 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a value that implements the [Parse] trait.
|
/// Parses a value that implements the [Parse] trait.
|
||||||
pub fn parse<T: Parse<'t>>(&mut self, level: usize) -> PResult<T> {
|
pub fn parse<T: Parse<'t>>(&mut self, level: T::Prec) -> PResult<T> {
|
||||||
Parse::parse(self, level)
|
Parse::parse(self, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,17 +109,18 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a list of P separated by `sep` tokens, ending in an `end` token.
|
/// Parses a list of P separated by `sep` tokens, ending in an `end` token.
|
||||||
/// ```nobnf
|
/// ```ignore
|
||||||
/// List<T> = (T `sep`)* T? `end` ;
|
/// List<T> = (T `sep`)* T? `end` ;
|
||||||
/// ```
|
/// ```
|
||||||
pub fn list<P: Parse<'t>>(
|
pub fn list<P: Parse<'t>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut elems: Vec<P>,
|
mut elems: Vec<P>,
|
||||||
|
level: P::Prec,
|
||||||
sep: TKind,
|
sep: TKind,
|
||||||
end: TKind,
|
end: TKind,
|
||||||
) -> PResult<Vec<P>> {
|
) -> PResult<Vec<P>> {
|
||||||
while self.peek_if(end).is_none() {
|
while self.peek_if(end).is_none() {
|
||||||
elems.push(self.parse(0)?);
|
elems.push(self.parse(level)?);
|
||||||
if self.next_if(sep).is_err() {
|
if self.next_if(sep).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -126,8 +129,26 @@ impl<'t> Parser<'t> {
|
|||||||
Ok(elems)
|
Ok(elems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a list of one or more P at level `level`, separated by `sep` tokens
|
||||||
|
/// ```ignore
|
||||||
|
/// UnterminatedList<P> = P (`sep` P)*
|
||||||
|
/// ```
|
||||||
|
pub fn list_bare<P: Parse<'t>>(
|
||||||
|
&mut self,
|
||||||
|
mut elems: Vec<P>,
|
||||||
|
level: P::Prec,
|
||||||
|
sep: TKind,
|
||||||
|
) -> PResult<Vec<P>> {
|
||||||
|
loop {
|
||||||
|
elems.push(self.parse(level)?);
|
||||||
|
if self.next_if(sep).is_err() {
|
||||||
|
break Ok(elems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses into an [`Option<P>`] if the next token is `next`
|
/// Parses into an [`Option<P>`] if the next token is `next`
|
||||||
pub fn opt_if<P: Parse<'t>>(&mut self, level: usize, next: TKind) -> PResult<Option<P>> {
|
pub fn opt_if<P: Parse<'t>>(&mut self, level: P::Prec, next: TKind) -> PResult<Option<P>> {
|
||||||
Ok(match self.next_if(next) {
|
Ok(match self.next_if(next) {
|
||||||
Ok(_) => Some(self.parse(level)?),
|
Ok(_) => Some(self.parse(level)?),
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
@ -135,7 +156,7 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an expression into a vec unless the next token is `end`
|
/// Parses an expression into a vec unless the next token is `end`
|
||||||
pub fn opt<P: Parse<'t>>(&mut self, level: usize, end: TKind) -> PResult<Option<P>> {
|
pub fn opt<P: Parse<'t>>(&mut self, level: P::Prec, end: TKind) -> PResult<Option<P>> {
|
||||||
let out = match self.peek_if(end) {
|
let out = match self.peek_if(end) {
|
||||||
None => Some(self.parse(level)?),
|
None => Some(self.parse(level)?),
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
@ -152,19 +173,25 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Parse<'t> {
|
pub trait Parse<'t> {
|
||||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self>
|
type Prec: Copy;
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self>
|
||||||
where Self: Sized;
|
where Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Literal {
|
impl<'t> Parse<'t> for Literal {
|
||||||
|
type Prec = usize;
|
||||||
fn parse(p: &mut Parser<'t>, _level: usize) -> PResult<Self> {
|
fn parse(p: &mut Parser<'t>, _level: usize) -> PResult<Self> {
|
||||||
let tok = p.peek()?;
|
let tok = p.peek()?;
|
||||||
Ok(match tok.kind {
|
Ok(match tok.kind {
|
||||||
TKind::True => p.consume().then(Literal::Bool(true)),
|
TKind::True => p.consume().then(Literal::Bool(true)),
|
||||||
TKind::False => p.consume().then(Literal::Bool(false)),
|
TKind::False => p.consume().then(Literal::Bool(false)),
|
||||||
TKind::Character => {
|
TKind::Character => Literal::Char(
|
||||||
Literal::Char(p.take_lexeme().expect("should have Token").remove(0))
|
p.take_lexeme()
|
||||||
}
|
.expect("should have Token")
|
||||||
|
.chars()
|
||||||
|
.next()
|
||||||
|
.expect("should have one char in char literal"),
|
||||||
|
),
|
||||||
TKind::Integer => {
|
TKind::Integer => {
|
||||||
let Token { lexeme, kind: _, span } = p.take().expect("should have Token");
|
let Token { lexeme, kind: _, span } = p.take().expect("should have Token");
|
||||||
// TODO: more complex int parsing
|
// TODO: more complex int parsing
|
||||||
@ -179,78 +206,128 @@ impl<'t> Parse<'t> for Literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum PPrec {
|
||||||
|
Min,
|
||||||
|
Tuple,
|
||||||
|
Alt,
|
||||||
|
NoTopAlt,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Pat {
|
impl<'t> Parse<'t> for Pat {
|
||||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
type Prec = PPrec;
|
||||||
|
fn parse(p: &mut Parser<'t>, level: PPrec) -> PResult<Self> {
|
||||||
|
while p.next_if(TKind::Comment).is_ok() {}
|
||||||
let tok = p.peek()?;
|
let tok = p.peek()?;
|
||||||
match tok.kind {
|
|
||||||
TKind::Comment => p.consume().parse(level),
|
// Prefix
|
||||||
|
let mut head = match tok.kind {
|
||||||
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
|
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
|
||||||
Ok(Pat::Lit(p.parse(0)?))
|
Pat::Lit(p.parse(0)?)
|
||||||
}
|
}
|
||||||
TKind::Identifier => match tok.lexeme.as_str() {
|
TKind::Identifier => match tok.lexeme.as_str() {
|
||||||
"_" => Ok(p.consume().then(Pat::Ignore)),
|
"_" => p.consume().then(Pat::Ignore),
|
||||||
_ => Ok(Pat::Name(p.take_lexeme().expect("should have Token"))),
|
_ => Pat::Name(p.take_lexeme().expect("should have Token")),
|
||||||
},
|
},
|
||||||
TKind::Grave => Ok(Pat::MetId(p.consume().next_if(TKind::Identifier)?.lexeme)),
|
TKind::Grave => Pat::MetId(p.consume().next_if(TKind::Identifier)?.lexeme),
|
||||||
TKind::DotDot => Ok(Pat::Rest(match p.consume().peek_if(TKind::Identifier) {
|
TKind::DotDot => Pat::Rest(match p.consume().peek_if(TKind::Identifier) {
|
||||||
Some(_) => Some(p.parse(level)?),
|
Some(_) => Some(p.parse(level)?),
|
||||||
None => None,
|
None => None,
|
||||||
})),
|
}),
|
||||||
TKind::LParen => Ok(Pat::Tuple(p.consume().list(
|
TKind::LParen => {
|
||||||
vec![],
|
Pat::Tuple(
|
||||||
TKind::Comma,
|
p.consume()
|
||||||
TKind::RParen,
|
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::RParen)?,
|
||||||
)?)),
|
)
|
||||||
TKind::LBrack => Ok(Pat::Slice(p.consume().list(
|
}
|
||||||
vec![],
|
TKind::LBrack => {
|
||||||
TKind::Comma,
|
Pat::Slice(
|
||||||
TKind::RBrack,
|
p.consume()
|
||||||
)?)),
|
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::RBrack)?,
|
||||||
_ => Err(ParseError::NotPattern(tok.kind, tok.span)),
|
)
|
||||||
|
}
|
||||||
|
_ => Err(ParseError::NotPattern(tok.kind, tok.span))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Infix
|
||||||
|
while let Ok(tok) = p.peek() {
|
||||||
|
let kind = tok.kind;
|
||||||
|
|
||||||
|
head = match kind {
|
||||||
|
TKind::Bar if level < PPrec::Alt => {
|
||||||
|
Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt, kind)?)
|
||||||
|
}
|
||||||
|
TKind::Comma if level < PPrec::Tuple => {
|
||||||
|
Pat::Tuple(p.consume().list_bare(vec![head], PPrec::Tuple, kind)?)
|
||||||
|
}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for MatchArm {
|
impl<'t> Parse<'t> for MatchArm {
|
||||||
|
type Prec = usize;
|
||||||
fn parse(p: &mut Parser<'t>, _level: usize) -> PResult<Self> {
|
fn parse(p: &mut Parser<'t>, _level: usize) -> PResult<Self> {
|
||||||
p.next_if(TKind::Bar).ok();
|
p.next_if(TKind::Bar).ok();
|
||||||
Ok(MatchArm(
|
Ok(MatchArm(
|
||||||
p.list(vec![], TKind::Bar, TKind::FatArrow)?,
|
p.list(vec![], PPrec::Min, TKind::Bar, TKind::FatArrow)?,
|
||||||
p.parse(0)?,
|
p.parse(0)?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for MakeArm {
|
impl<'t> Parse<'t> for MakeArm {
|
||||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
type Prec = ();
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: ()) -> PResult<Self> {
|
||||||
Ok(MakeArm(p.next_if(TKind::Identifier)?.lexeme, {
|
Ok(MakeArm(p.next_if(TKind::Identifier)?.lexeme, {
|
||||||
p.next_if(TKind::Colon)
|
p.next_if(TKind::Colon)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|_| p.parse(level))
|
.map(|_| p.parse(Prec::Min.value()))
|
||||||
.transpose()?
|
.transpose()?
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Organizes the precedence hierarchy for syntactic elements
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum Prec {
|
enum Prec {
|
||||||
Min,
|
Min,
|
||||||
|
/// The Semicolon Operator gets its own precedence level
|
||||||
Do,
|
Do,
|
||||||
|
/// An assignment
|
||||||
Assign,
|
Assign,
|
||||||
|
/// Constructor for a tuple
|
||||||
Tuple,
|
Tuple,
|
||||||
|
/// Constructor for a struct
|
||||||
Make,
|
Make,
|
||||||
|
/// The body of a function, conditional, etc.
|
||||||
Body,
|
Body,
|
||||||
|
/// The short-circuiting logical operators [Prec::LogOr], [Prec::LogAnd]
|
||||||
Logical,
|
Logical,
|
||||||
|
/// The short-circuiting "boolean or" operator
|
||||||
LogOr,
|
LogOr,
|
||||||
|
/// The short-circuiting "boolean and" operator
|
||||||
LogAnd,
|
LogAnd,
|
||||||
|
/// Value comparison operators
|
||||||
Compare,
|
Compare,
|
||||||
|
/// Constructor for a Range
|
||||||
Range,
|
Range,
|
||||||
|
/// Binary/bitwise operators
|
||||||
Binary,
|
Binary,
|
||||||
|
/// Bit-shifting operators
|
||||||
Shift,
|
Shift,
|
||||||
|
/// Addition and Subtraction operators
|
||||||
Factor,
|
Factor,
|
||||||
|
/// Multiplication, Division, and Remainder operators
|
||||||
Term,
|
Term,
|
||||||
Project,
|
/// Negation, (De)reference, Try
|
||||||
Unary,
|
Unary,
|
||||||
|
/// Place-projection operators
|
||||||
|
Project,
|
||||||
|
/// Array/Call subscripting and reference
|
||||||
Extend,
|
Extend,
|
||||||
Max,
|
Max,
|
||||||
}
|
}
|
||||||
@ -274,96 +351,117 @@ impl Prec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_prefix(token: &Token) -> PResult<(Op, Prec)> {
|
/// PseudoOperator: fake operators used to give certain tokens special behavior.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Ps {
|
||||||
|
Id, // Identifier
|
||||||
|
Mid, // MetaIdentifier
|
||||||
|
Lit, // Literal
|
||||||
|
Let, // let Pat = Expr
|
||||||
|
Const, // const Pat = Expr
|
||||||
|
Fn, // fn ( Pat,* ) Expr
|
||||||
|
Lambda0, // || Expr
|
||||||
|
Lambda, // | Pat,* | Expr
|
||||||
|
DoubleRef, // && Expr
|
||||||
|
Make, // Expr{ Expr,* }
|
||||||
|
Match, // match Expr { MatchArm,* }
|
||||||
|
End, // Produces an empty value.
|
||||||
|
Op(Op), // A normal [ast::Op]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||||
Ok(match token.kind {
|
Ok(match token.kind {
|
||||||
TKind::Do => (Op::Do, Prec::Do),
|
TKind::Do => (Ps::Op(Op::Do), Prec::Do),
|
||||||
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
|
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
|
||||||
(Op::Lit, Prec::Max)
|
(Ps::Lit, Prec::Max)
|
||||||
}
|
}
|
||||||
TKind::Identifier => (Op::Id, Prec::Max),
|
|
||||||
TKind::Grave => (Op::Mid, Prec::Max),
|
|
||||||
TKind::Fn => (Op::Fn, Prec::Body),
|
|
||||||
|
|
||||||
TKind::Match => (Op::Match, Prec::Body),
|
TKind::Identifier => (Ps::Id, Prec::Max),
|
||||||
TKind::Macro => (Op::Macro, Prec::Assign),
|
TKind::Grave => (Ps::Mid, Prec::Max),
|
||||||
TKind::Let => (Op::Let, Prec::Body),
|
TKind::Fn => (Ps::Fn, Prec::Body),
|
||||||
TKind::Const => (Op::Const, Prec::Body),
|
|
||||||
TKind::Loop => (Op::Loop, Prec::Body),
|
|
||||||
TKind::If => (Op::If, Prec::Body),
|
|
||||||
TKind::While => (Op::While, Prec::Body),
|
|
||||||
TKind::Break => (Op::Break, Prec::Body),
|
|
||||||
TKind::Return => (Op::Return, Prec::Body),
|
|
||||||
|
|
||||||
TKind::LBrack => (Op::Array, Prec::Min),
|
TKind::Match => (Ps::Match, Prec::Body),
|
||||||
TKind::RBrack => (Op::End, Prec::Min),
|
TKind::Macro => (Ps::Op(Op::Macro), Prec::Assign),
|
||||||
TKind::LCurly => (Op::Block, Prec::Min),
|
TKind::Let => (Ps::Let, Prec::Body),
|
||||||
TKind::RCurly => (Op::End, Prec::Min),
|
TKind::Const => (Ps::Const, Prec::Body),
|
||||||
TKind::LParen => (Op::Group, Prec::Min),
|
TKind::Loop => (Ps::Op(Op::Loop), Prec::Body),
|
||||||
TKind::RParen => (Op::End, Prec::Min),
|
TKind::If => (Ps::Op(Op::If), Prec::Body),
|
||||||
TKind::Amp => (Op::Refer, Prec::Max),
|
TKind::While => (Ps::Op(Op::While), Prec::Body),
|
||||||
// TKind::AmpAmp => todo!("addraddr"),
|
TKind::Break => (Ps::Op(Op::Break), Prec::Body),
|
||||||
TKind::Bang => (Op::Not, Prec::Unary),
|
TKind::Return => (Ps::Op(Op::Return), Prec::Body),
|
||||||
TKind::BangBang => (Op::Identity, Prec::Unary),
|
|
||||||
TKind::Bar => (Op::Lambda, Prec::Min),
|
TKind::LCurly => (Ps::Op(Op::Block), Prec::Min),
|
||||||
TKind::BarBar => (Op::Lambda, Prec::Max),
|
TKind::RCurly => (Ps::End, Prec::Do),
|
||||||
TKind::DotDot => (Op::RangeEx, Prec::Range),
|
TKind::LBrack => (Ps::Op(Op::Array), Prec::Min),
|
||||||
TKind::DotDotEq => (Op::RangeIn, Prec::Range),
|
TKind::RBrack => (Ps::End, Prec::Tuple),
|
||||||
TKind::Minus => (Op::Neg, Prec::Unary),
|
TKind::LParen => (Ps::Op(Op::Group), Prec::Min),
|
||||||
TKind::Plus => (Op::Identity, Prec::Unary),
|
TKind::RParen => (Ps::End, Prec::Tuple),
|
||||||
TKind::Star => (Op::Deref, Prec::Unary),
|
TKind::Amp => (Ps::Op(Op::Refer), Prec::Extend),
|
||||||
|
TKind::AmpAmp => (Ps::DoubleRef, Prec::Extend),
|
||||||
|
TKind::Bang => (Ps::Op(Op::Not), Prec::Unary),
|
||||||
|
TKind::BangBang => (Ps::Op(Op::Identity), Prec::Unary),
|
||||||
|
TKind::Bar => (Ps::Lambda, Prec::Body),
|
||||||
|
TKind::BarBar => (Ps::Lambda0, Prec::Body),
|
||||||
|
TKind::DotDot => (Ps::Op(Op::RangeEx), Prec::Range),
|
||||||
|
TKind::DotDotEq => (Ps::Op(Op::RangeIn), Prec::Range),
|
||||||
|
TKind::Minus => (Ps::Op(Op::Neg), Prec::Unary),
|
||||||
|
TKind::Plus => (Ps::Op(Op::Identity), Prec::Unary),
|
||||||
|
TKind::Star => (Ps::Op(Op::Deref), Prec::Unary),
|
||||||
|
|
||||||
kind => Err(ParseError::NotPrefix(kind, token.span))?,
|
kind => Err(ParseError::NotPrefix(kind, token.span))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_infix(token: &Token) -> PResult<(Op, Prec)> {
|
fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||||
Ok(match token.kind {
|
Ok(match token.kind {
|
||||||
TKind::Semi => (Op::Do, Prec::Do), // the inspiration
|
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
||||||
TKind::RParen => (Op::End, Prec::Do),
|
TKind::Eq => (Ps::Op(Op::Set), Prec::Assign),
|
||||||
TKind::Comma => (Op::Tuple, Prec::Tuple),
|
TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical),
|
||||||
TKind::Eq => (Op::Set, Prec::Assign),
|
TKind::Lt => (Ps::Op(Op::Lt), Prec::Compare),
|
||||||
TKind::XorXor => (Op::LogXor, Prec::Logical),
|
TKind::LtEq => (Ps::Op(Op::Leq), Prec::Compare),
|
||||||
TKind::AmpAmp => (Op::LogAnd, Prec::LogAnd),
|
TKind::EqEq => (Ps::Op(Op::Eq), Prec::Compare),
|
||||||
TKind::BarBar => (Op::LogOr, Prec::LogOr),
|
TKind::BangEq => (Ps::Op(Op::Neq), Prec::Compare),
|
||||||
TKind::Lt => (Op::Lt, Prec::Compare),
|
TKind::GtEq => (Ps::Op(Op::Geq), Prec::Compare),
|
||||||
TKind::LtEq => (Op::Leq, Prec::Compare),
|
TKind::Gt => (Ps::Op(Op::Gt), Prec::Compare),
|
||||||
TKind::EqEq => (Op::Eq, Prec::Compare),
|
TKind::DotDot => (Ps::Op(Op::RangeEx), Prec::Range),
|
||||||
TKind::BangEq => (Op::Neq, Prec::Compare),
|
TKind::DotDotEq => (Ps::Op(Op::RangeIn), Prec::Range),
|
||||||
TKind::GtEq => (Op::Geq, Prec::Compare),
|
TKind::Amp => (Ps::Op(Op::And), Prec::Binary),
|
||||||
TKind::Gt => (Op::Gt, Prec::Compare),
|
TKind::Xor => (Ps::Op(Op::Xor), Prec::Binary),
|
||||||
TKind::DotDot => (Op::RangeEx, Prec::Range),
|
TKind::Bar => (Ps::Op(Op::Or), Prec::Binary),
|
||||||
TKind::DotDotEq => (Op::RangeIn, Prec::Range),
|
TKind::LtLt => (Ps::Op(Op::Shl), Prec::Shift),
|
||||||
TKind::Amp => (Op::And, Prec::Binary),
|
TKind::GtGt => (Ps::Op(Op::Shr), Prec::Shift),
|
||||||
TKind::Xor => (Op::Xor, Prec::Binary),
|
TKind::Plus => (Ps::Op(Op::Add), Prec::Factor),
|
||||||
TKind::Bar => (Op::Or, Prec::Binary),
|
TKind::Minus => (Ps::Op(Op::Sub), Prec::Factor),
|
||||||
TKind::LtLt => (Op::Shl, Prec::Shift),
|
TKind::Star => (Ps::Op(Op::Mul), Prec::Term),
|
||||||
TKind::GtGt => (Op::Shr, Prec::Shift),
|
TKind::Slash => (Ps::Op(Op::Div), Prec::Term),
|
||||||
TKind::Plus => (Op::Add, Prec::Factor),
|
TKind::Rem => (Ps::Op(Op::Rem), Prec::Term),
|
||||||
TKind::Minus => (Op::Sub, Prec::Factor),
|
TKind::ColonColon => (Ps::Op(Op::Path), Prec::Max),
|
||||||
TKind::Star => (Op::Mul, Prec::Term),
|
TKind::Question => (Ps::End, Prec::Extend),
|
||||||
TKind::Slash => (Op::Div, Prec::Term),
|
|
||||||
TKind::Rem => (Op::Rem, Prec::Term),
|
|
||||||
TKind::Dot => (Op::Dot, Prec::Project),
|
|
||||||
TKind::ColonColon => (Op::Path, Prec::Max),
|
|
||||||
kind => Err(ParseError::NotInfix(kind, token.span))?,
|
kind => Err(ParseError::NotInfix(kind, token.span))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_postfix(token: &Token) -> PResult<(Op, Prec)> {
|
fn from_postfix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||||
Ok(match token.kind {
|
Ok(match token.kind {
|
||||||
TKind::Question => (Op::Try, Prec::Unary),
|
TKind::Semi => (Ps::Op(Op::Do), Prec::Do), // the inspiration
|
||||||
TKind::LParen => (Op::Call, Prec::Extend),
|
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
||||||
TKind::LBrack => (Op::Index, Prec::Extend),
|
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
||||||
TKind::LCurly => (Op::Make, Prec::Make),
|
TKind::ColonColon => (Ps::Op(Op::Path), Prec::Max),
|
||||||
|
TKind::AmpAmp => (Ps::Op(Op::LogAnd), Prec::LogAnd),
|
||||||
|
TKind::BarBar => (Ps::Op(Op::LogOr), Prec::LogOr),
|
||||||
|
TKind::Question => (Ps::Op(Op::Try), Prec::Unary),
|
||||||
|
TKind::LParen => (Ps::Op(Op::Call), Prec::Extend),
|
||||||
|
TKind::LBrack => (Ps::Op(Op::Index), Prec::Extend),
|
||||||
|
TKind::LCurly => (Ps::Make, Prec::Make),
|
||||||
kind => Err(ParseError::NotPostfix(kind, token.span))?,
|
kind => Err(ParseError::NotPostfix(kind, token.span))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn should_coagulate(prev: Op, op: Op) -> bool {
|
fn should_coagulate(prev: Op, op: Op) -> bool {
|
||||||
prev == op && (match prev {
|
prev == op && match prev {
|
||||||
Op::Do => true,
|
Op::LogAnd => true,
|
||||||
Op::Tuple => true,
|
Op::LogOr => true,
|
||||||
Op::Dot => false,
|
Op::Dot => false,
|
||||||
Op::Path => true,
|
Op::Path => true,
|
||||||
Op::Lt => false,
|
Op::Lt => false,
|
||||||
@ -373,10 +471,12 @@ fn should_coagulate(prev: Op, op: Op) -> bool {
|
|||||||
Op::Geq => false,
|
Op::Geq => false,
|
||||||
Op::Gt => false,
|
Op::Gt => false,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Expr {
|
impl<'t> Parse<'t> for Expr {
|
||||||
|
type Prec = usize;
|
||||||
|
|
||||||
/// Parses an [Expr]ession.
|
/// Parses an [Expr]ession.
|
||||||
///
|
///
|
||||||
/// The `level` parameter indicates the operator binding level of the expression.
|
/// The `level` parameter indicates the operator binding level of the expression.
|
||||||
@ -391,38 +491,44 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
let mut head = match op {
|
let mut head = match op {
|
||||||
// Empty is returned when a block finisher is an expr prefix.
|
// Empty is returned when a block finisher is an expr prefix.
|
||||||
// It's the only expr that doesn't consume.
|
// It's the only expr that doesn't consume.
|
||||||
Op::End if level == Prec::Do.next() => Expr::Op(Op::Tuple, vec![]),
|
Ps::End if level == prec.next() => Expr::Op(Op::Tuple, vec![]),
|
||||||
Op::End => Err(ParseError::NotPrefix(tok.kind, span))?,
|
Ps::End => Err(ParseError::NotPrefix(tok.kind, span))?,
|
||||||
|
|
||||||
Op::Id => Expr::Id(p.take_lexeme().expect("should have ident")),
|
Ps::Id => Expr::Id(p.take_lexeme().expect("should have ident")),
|
||||||
Op::Mid => Expr::MetId(p.consume().next_if(TKind::Identifier)?.lexeme),
|
Ps::Mid => Expr::MetId(p.consume().next_if(TKind::Identifier)?.lexeme),
|
||||||
Op::Lit => Expr::Lit(p.parse(MIN)?),
|
Ps::Lit => Expr::Lit(p.parse(MIN)?),
|
||||||
Op::Let => Expr::Let(p.consume().parse(MIN)?, p.opt_if(prec.next(), TKind::Eq)?),
|
Ps::Let => Expr::Let(
|
||||||
Op::Const => Expr::Const(p.consume().parse(prec.next())?, {
|
p.consume().parse(PPrec::NoTopAlt)?,
|
||||||
|
p.opt_if(prec.next(), TKind::Eq)?,
|
||||||
|
),
|
||||||
|
Ps::Const => Expr::Const(p.consume().parse(PPrec::NoTopAlt)?, {
|
||||||
p.next_if(TKind::Eq)?;
|
p.next_if(TKind::Eq)?;
|
||||||
p.parse(prec.next())?
|
p.parse(prec.next())?
|
||||||
}),
|
}),
|
||||||
Op::Macro => Expr::Op(
|
Ps::Op(Op::Macro) => Expr::Op(
|
||||||
op,
|
Op::Macro,
|
||||||
vec![p.consume().parse(prec.next())?, {
|
vec![p.consume().parse(prec.next())?, {
|
||||||
p.next_if(TKind::FatArrow)?;
|
p.next_if(TKind::FatArrow)?;
|
||||||
p.parse(prec.next())?
|
p.parse(prec.next())?
|
||||||
}],
|
}],
|
||||||
),
|
),
|
||||||
Op::Match => Expr::Match(p.consume().parse(Prec::Logical.value())?, {
|
Ps::Match => Expr::Match(p.consume().parse(Prec::Logical.value())?, {
|
||||||
p.next_if(TKind::LCurly)?;
|
p.next_if(TKind::LCurly)?;
|
||||||
p.list(vec![], TKind::Comma, TKind::RCurly)?
|
p.list(vec![], 0, TKind::Comma, TKind::RCurly)?
|
||||||
}),
|
}),
|
||||||
Op::Block => Expr::Op(
|
Ps::Op(Op::Block) => Expr::Op(
|
||||||
op,
|
Op::Block,
|
||||||
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
||||||
),
|
),
|
||||||
Op::Array => Expr::Op(op, p.consume().list(vec![], TKind::Comma, TKind::RBrack)?),
|
Ps::Op(Op::Array) => Expr::Op(
|
||||||
Op::Group => match p.consume().opt(MIN, TKind::RParen)? {
|
Op::Array,
|
||||||
|
p.consume().list(vec![], 0, TKind::Comma, TKind::RBrack)?,
|
||||||
|
),
|
||||||
|
Ps::Op(Op::Group) => match p.consume().opt(MIN, TKind::RParen)? {
|
||||||
Some(value) => Expr::Op(Op::Group, vec![value]),
|
Some(value) => Expr::Op(Op::Group, vec![value]),
|
||||||
None => Expr::Op(Op::Tuple, vec![]),
|
None => Expr::Op(Op::Tuple, vec![]),
|
||||||
},
|
},
|
||||||
Op::If | Op::While => {
|
Ps::Op(op @ (Op::If | Op::While)) => {
|
||||||
p.consume();
|
p.consume();
|
||||||
let exprs = vec![
|
let exprs = vec![
|
||||||
// conditional restricted to Logical operators or above
|
// conditional restricted to Logical operators or above
|
||||||
@ -430,50 +536,68 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
p.parse(prec.next())?,
|
p.parse(prec.next())?,
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
Ok(Token { kind: TKind::Else, .. }) => p.consume().parse(prec.next())?,
|
Ok(Token { kind: TKind::Else, .. }) => p.consume().parse(prec.next())?,
|
||||||
_ => Expr::Op(Op::End, vec![]).anno(span.merge(p.span())),
|
_ => Expr::Op(Op::Tuple, vec![]).anno(span.merge(p.span())),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
Expr::Op(op, exprs)
|
Expr::Op(op, exprs)
|
||||||
}
|
}
|
||||||
Op::Fn => {
|
Ps::Fn => {
|
||||||
|
// TODO: move this to 'item' parsing
|
||||||
p.consume().next_if(TKind::LParen)?;
|
p.consume().next_if(TKind::LParen)?;
|
||||||
Expr::Fn(
|
Expr::Fn(
|
||||||
p.list(vec![], TKind::Comma, TKind::RParen)?,
|
Pat::Tuple(p.consume().list(
|
||||||
|
vec![],
|
||||||
|
PPrec::Tuple,
|
||||||
|
TKind::Comma,
|
||||||
|
TKind::RParen,
|
||||||
|
)?),
|
||||||
p.parse(prec.next())?,
|
p.parse(prec.next())?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// dirty hack: There are two closure operators, signaled by returned prec.
|
Ps::Lambda => Expr::Fn(
|
||||||
Op::Lambda if prec == Prec::Min => Expr::Fn(
|
Pat::Tuple(
|
||||||
p.consume().list(vec![], TKind::Comma, TKind::Bar)?,
|
p.consume()
|
||||||
|
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::Bar)?,
|
||||||
|
),
|
||||||
p.parse(Prec::Body.next())?,
|
p.parse(Prec::Body.next())?,
|
||||||
),
|
),
|
||||||
Op::Lambda => Expr::Fn(vec![], p.consume().parse(Prec::Body.next())?),
|
Ps::Lambda0 => Expr::Fn(Pat::Tuple(vec![]), p.consume().parse(Prec::Body.next())?),
|
||||||
|
Ps::DoubleRef => Expr::Op(
|
||||||
|
Op::Refer,
|
||||||
|
vec![Expr::Op(Op::Refer, vec![p.consume().parse(prec.next())?]).anno(span)],
|
||||||
|
),
|
||||||
|
|
||||||
_ => Expr::Op(op, vec![p.consume().parse(prec.next())?]),
|
Ps::Op(op) => Expr::Op(op, vec![p.consume().parse(prec.next())?]),
|
||||||
|
_ => unimplemented!("prefix {op:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Postfix
|
// Postfix
|
||||||
while let Ok(tok) = p.peek()
|
while let Ok(tok) = p.peek()
|
||||||
&& let Ok((op, prec)) = from_postfix(tok)
|
&& let Ok((op, prec)) = from_postfix(tok)
|
||||||
&& level <= prec.prev()
|
&& level <= prec.prev()
|
||||||
&& op != Op::End
|
&& op != Ps::End
|
||||||
{
|
{
|
||||||
|
let kind = tok.kind;
|
||||||
let span = span.merge(p.span());
|
let span = span.merge(p.span());
|
||||||
p.consume();
|
p.consume();
|
||||||
head = match op {
|
head = match op {
|
||||||
Op::Make => Expr::Make(
|
Ps::Make => Expr::Make(
|
||||||
head.anno(span).into(),
|
head.anno(span).into(),
|
||||||
p.consume().list(vec![], TKind::Comma, TKind::RCurly)?,
|
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
||||||
),
|
),
|
||||||
Op::Index => Expr::Op(
|
Ps::Op(Op::Index) => Expr::Op(
|
||||||
op,
|
Op::Index,
|
||||||
p.list(vec![head.anno(span)], TKind::Comma, TKind::RBrack)?,
|
p.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?,
|
||||||
),
|
),
|
||||||
Op::Call => Expr::Op(
|
Ps::Op(Op::Call) => Expr::Op(
|
||||||
op,
|
Op::Call,
|
||||||
p.list(vec![head.anno(span)], TKind::Comma, TKind::RParen)?,
|
p.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RParen)?,
|
||||||
),
|
),
|
||||||
_ => Expr::Op(op, vec![head.anno(span)]),
|
Ps::Op(op @ (Op::Do | Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => {
|
||||||
|
Expr::Op(op, p.list_bare(vec![head.anno(span)], prec.next(), kind)?)
|
||||||
|
}
|
||||||
|
Ps::Op(op) => Expr::Op(op, vec![head.anno(span)]),
|
||||||
|
_ => unimplemented!("postfix {op:?}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,18 +605,19 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
while let Ok(tok) = p.peek()
|
while let Ok(tok) = p.peek()
|
||||||
&& let Ok((op, prec)) = from_infix(tok)
|
&& let Ok((op, prec)) = from_infix(tok)
|
||||||
&& level <= prec.prev()
|
&& level <= prec.prev()
|
||||||
&& op != Op::End
|
&& op != Ps::End
|
||||||
{
|
{
|
||||||
let span = span.merge(p.span());
|
let span = span.merge(p.span());
|
||||||
p.consume();
|
p.consume();
|
||||||
|
|
||||||
head = match head {
|
head = match (op, head) {
|
||||||
// controls expression chaining vs coagulating
|
// controls expression chaining vs coagulating
|
||||||
Expr::Op(prev, mut args) if should_coagulate(prev, op) => {
|
(Ps::Op(op), Expr::Op(prev, mut args)) if should_coagulate(prev, op) => {
|
||||||
args.push(p.parse(prec.next())?);
|
args.push(p.parse(prec.next())?);
|
||||||
Expr::Op(op, args)
|
Expr::Op(op, args)
|
||||||
}
|
}
|
||||||
head => Expr::Op(op, vec![head.anno(span), p.parse(prec.next())?]),
|
(Ps::Op(op), head) => Expr::Op(op, vec![head.anno(span), p.parse(prec.next())?]),
|
||||||
|
_ => unimplemented!("infix {op:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,15 +626,19 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, P: Parse<'t> + Annotation> Parse<'t> for Anno<P> {
|
impl<'t, P: Parse<'t> + Annotation> Parse<'t> for Anno<P> {
|
||||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self>
|
type Prec = P::Prec;
|
||||||
|
fn parse(p: &mut Parser<'t>, level: P::Prec) -> PResult<Self>
|
||||||
where Self: Sized {
|
where Self: Sized {
|
||||||
let start = p.span();
|
let start = p.span();
|
||||||
Ok(Anno(p.parse(level)?, start.merge(p.span())))
|
let anno = Anno(p.parse(level)?, start.merge(p.span()));
|
||||||
|
println!("{}:\t{anno}", anno.1);
|
||||||
|
Ok(anno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, P: Parse<'t>> Parse<'t> for Box<P> {
|
impl<'t, P: Parse<'t>> Parse<'t> for Box<P> {
|
||||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self>
|
type Prec = P::Prec;
|
||||||
|
fn parse(p: &mut Parser<'t>, level: P::Prec) -> PResult<Self>
|
||||||
where Self: Sized {
|
where Self: Sized {
|
||||||
Ok(Box::new(p.parse(level)?))
|
Ok(Box::new(p.parse(level)?))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user