do: Elaborate on pattern syntax, add binary as
operator
This commit is contained in:
parent
b6949147c4
commit
7b05da1334
37
src/ast.rs
37
src/ast.rs
@ -42,6 +42,8 @@ pub enum Pat {
|
|||||||
Slice(Vec<Pat>),
|
Slice(Vec<Pat>),
|
||||||
/// Matches one of the provided alternates
|
/// Matches one of the provided alternates
|
||||||
Alt(Vec<Pat>),
|
Alt(Vec<Pat>),
|
||||||
|
/// Matches a typed pattern
|
||||||
|
Typed(Box<Pat>, Ty),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The arms of a make expression
|
/// The arms of a make expression
|
||||||
@ -70,7 +72,7 @@ pub enum Ty {
|
|||||||
/// `[Ty]`
|
/// `[Ty]`
|
||||||
Slice(Box<Ty>),
|
Slice(Box<Ty>),
|
||||||
/// `[Ty; _]`
|
/// `[Ty; _]`
|
||||||
Array(Box<Ty>, usize),
|
Array(Box<Ty>, Box<Expr>),
|
||||||
/// `[Rety, ..Args]`
|
/// `[Rety, ..Args]`
|
||||||
Fn(Vec<Ty>),
|
Fn(Vec<Ty>),
|
||||||
}
|
}
|
||||||
@ -113,12 +115,21 @@ impl<A: Annotation> Expr<A> {
|
|||||||
| Self::Op(Op::Deref, _)
|
| Self::Op(Op::Deref, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn as_slice(&self) -> Option<(Op, &[Anno<Expr<A>, A>])> {
|
||||||
|
match self {
|
||||||
|
Expr::Op(op, args) => Some((*op, args.as_slice())),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
// -- true operators
|
// -- true operators
|
||||||
Do, // Expr ; Expr
|
Do, // Expr ; Expr
|
||||||
|
As, // Expr as Expr
|
||||||
Macro, // macro Expr => Expr
|
Macro, // macro Expr => Expr
|
||||||
Block, // { Expr }
|
Block, // { Expr }
|
||||||
Array, // [ Expr,* ]
|
Array, // [ Expr,* ]
|
||||||
@ -201,13 +212,13 @@ impl<A: Annotation> Display for Expr<A> {
|
|||||||
Self::MetId(id) => write!(f, "`{id}"),
|
Self::MetId(id) => write!(f, "`{id}"),
|
||||||
Self::Lit(literal) => literal.fmt(f),
|
Self::Lit(literal) => literal.fmt(f),
|
||||||
Self::Let(pat, Some(expr)) => write!(f, "let {pat} = {expr}"),
|
Self::Let(pat, Some(expr)) => write!(f, "let {pat} = {expr}"),
|
||||||
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!("({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"), "}")
|
.delimit_indented(fmt!("match {expr} {{"), "}")
|
||||||
.list_wrap("\n", match_arms, ",\n", ",\n"),
|
.list_wrap("\n", match_arms, ",\n", ",\n"),
|
||||||
Self::Fn(pat, expr) => write!(f, "fn {pat} {expr}"),
|
Self::Fn(pat, expr) => write!(f, "fn {pat} {expr}"),
|
||||||
|
|
||||||
@ -246,6 +257,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::As => " as ".fmt(f),
|
||||||
Op::Macro => "macro ".fmt(f),
|
Op::Macro => "macro ".fmt(f),
|
||||||
Op::Block => "{}".fmt(f),
|
Op::Block => "{}".fmt(f),
|
||||||
Op::Array => "[]".fmt(f),
|
Op::Array => "[]".fmt(f),
|
||||||
@ -320,6 +332,25 @@ impl Display for Pat {
|
|||||||
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, " | "),
|
Self::Alt(pats) => f.delimit("<", ">").list(pats, " | "),
|
||||||
|
Self::Typed(pat, ty) => write!(f, "{pat}: {ty}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Ty {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Infer => "_".fmt(f),
|
||||||
|
Self::Named(name) => name.fmt(f),
|
||||||
|
Self::Tuple(items) => f.delimit('(', ')').list(items, ", "),
|
||||||
|
Self::Slice(ty) => write!(f, "[{ty}]"),
|
||||||
|
Self::Array(ty, n) => write!(f, "[{ty}; {n}]"),
|
||||||
|
Self::Fn(items) => match items.as_slice() {
|
||||||
|
[] => write!(f, "fn ()"),
|
||||||
|
[rety, args @ ..] => f
|
||||||
|
.delimit(fmt!("fn ("), fmt!(") -> {rety}"))
|
||||||
|
.list(args, ", "),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,8 @@ impl<A: Annotation> Match<A> for Pat {
|
|||||||
(Pat::Slice(_), _) => false,
|
(Pat::Slice(_), _) => false,
|
||||||
(Pat::Alt(pat), Pat::Alt(expr)) => Match::recurse(sub, pat, expr),
|
(Pat::Alt(pat), Pat::Alt(expr)) => Match::recurse(sub, pat, expr),
|
||||||
(Pat::Alt(_), _) => false,
|
(Pat::Alt(_), _) => false,
|
||||||
|
(Pat::Typed(pat, _), Pat::Typed(expr, _)) => Match::recurse(sub, pat, expr),
|
||||||
|
(Pat::Typed(..), _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +210,23 @@ impl<A: Annotation> Match<A> for Pat {
|
|||||||
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),
|
Pat::Alt(pats) => pats.apply(sub),
|
||||||
|
Pat::Typed(pat, ty) => {
|
||||||
|
pat.apply(sub);
|
||||||
|
ty.apply(sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Match<A> for Ty {
|
||||||
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
|
todo!("Apply subst {sub:?} for {self}.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
todo!("Construct subst {sub:?} from {pat} and {expr}.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Annotation> Match<A> for Op {
|
impl<A: Annotation> Match<A> for Op {
|
||||||
fn recurse(_: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
fn recurse(_: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
@ -220,6 +220,7 @@ impl<'t> Lexer<'t> {
|
|||||||
let token = self.produce(TKind::Identifier);
|
let token = self.produce(TKind::Identifier);
|
||||||
Ok(Token {
|
Ok(Token {
|
||||||
kind: match token.lexeme.as_str() {
|
kind: match token.lexeme.as_str() {
|
||||||
|
"as" => TKind::As,
|
||||||
"break" => TKind::Break,
|
"break" => TKind::Break,
|
||||||
"const" => TKind::Const,
|
"const" => TKind::Const,
|
||||||
"do" => TKind::Do,
|
"do" => TKind::Do,
|
||||||
|
@ -32,7 +32,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(Response::Deny)
|
Ok(Response::Deny)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
lex(line);
|
|
||||||
parse(line);
|
parse(line);
|
||||||
Ok(Response::Accept)
|
Ok(Response::Accept)
|
||||||
}
|
}
|
||||||
|
168
src/parser.rs
168
src/parser.rs
@ -15,6 +15,7 @@ pub enum ParseError {
|
|||||||
Expected(TKind, Span),
|
Expected(TKind, Span),
|
||||||
NotLiteral(TKind, Span),
|
NotLiteral(TKind, Span),
|
||||||
NotPattern(TKind, Span),
|
NotPattern(TKind, Span),
|
||||||
|
NotType(TKind, Span),
|
||||||
NotPrefix(TKind, Span),
|
NotPrefix(TKind, Span),
|
||||||
NotInfix(TKind, Span),
|
NotInfix(TKind, Span),
|
||||||
NotPostfix(TKind, Span),
|
NotPostfix(TKind, Span),
|
||||||
@ -27,6 +28,7 @@ impl Display for ParseError {
|
|||||||
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::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::NotType(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a type."),
|
||||||
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."),
|
||||||
Self::NotPostfix(tk, loc) => write!(f, "{loc}: {tk:?} is not a postfix operator."),
|
Self::NotPostfix(tk, loc) => write!(f, "{loc}: {tk:?} is not a postfix operator."),
|
||||||
@ -155,7 +157,7 @@ impl<'t> Parser<'t> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an expression into a vec unless the next token is `end`
|
/// Parses a P unless the next token is `end`
|
||||||
pub fn opt<P: Parse<'t>>(&mut self, level: P::Prec, 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)?),
|
||||||
@ -179,8 +181,8 @@ pub trait Parse<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Literal {
|
impl<'t> Parse<'t> for Literal {
|
||||||
type Prec = usize;
|
type Prec = ();
|
||||||
fn parse(p: &mut Parser<'t>, _level: usize) -> PResult<Self> {
|
fn parse(p: &mut Parser<'t>, _level: ()) -> 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)),
|
||||||
@ -209,9 +211,10 @@ impl<'t> Parse<'t> for Literal {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum PPrec {
|
pub enum PPrec {
|
||||||
Min,
|
Min,
|
||||||
|
Typed,
|
||||||
Tuple,
|
Tuple,
|
||||||
Alt,
|
Alt,
|
||||||
NoTopAlt,
|
Max,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Pat {
|
impl<'t> Parse<'t> for Pat {
|
||||||
@ -223,7 +226,7 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
// Prefix
|
// Prefix
|
||||||
let mut head = match tok.kind {
|
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 => {
|
||||||
Pat::Lit(p.parse(0)?)
|
Pat::Lit(p.parse(())?)
|
||||||
}
|
}
|
||||||
TKind::Identifier => match tok.lexeme.as_str() {
|
TKind::Identifier => match tok.lexeme.as_str() {
|
||||||
"_" => p.consume().then(Pat::Ignore),
|
"_" => p.consume().then(Pat::Ignore),
|
||||||
@ -254,12 +257,15 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
let kind = tok.kind;
|
let kind = tok.kind;
|
||||||
|
|
||||||
head = match kind {
|
head = match kind {
|
||||||
TKind::Bar if level < PPrec::Alt => {
|
TKind::Colon if level > PPrec::Typed => {
|
||||||
Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt, kind)?)
|
Pat::Typed(head.into(), p.consume().parse(())?)
|
||||||
}
|
}
|
||||||
TKind::Comma if level < PPrec::Tuple => {
|
TKind::Comma if level > PPrec::Tuple => {
|
||||||
Pat::Tuple(p.consume().list_bare(vec![head], PPrec::Tuple, kind)?)
|
Pat::Tuple(p.consume().list_bare(vec![head], PPrec::Tuple, kind)?)
|
||||||
}
|
}
|
||||||
|
TKind::Bar if level > PPrec::Alt => {
|
||||||
|
Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt, kind)?)
|
||||||
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,13 +274,44 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'t> Parse<'t> for Ty {
|
||||||
|
type Prec = ();
|
||||||
|
|
||||||
|
fn parse(p: &mut Parser<'t>, level: Self::Prec) -> PResult<Self>
|
||||||
|
where Self: Sized {
|
||||||
|
let tok = p.peek()?;
|
||||||
|
|
||||||
|
let head = match tok.kind {
|
||||||
|
TKind::Identifier => match tok.lexeme.as_str() {
|
||||||
|
"_" => p.consume().then(Ty::Infer),
|
||||||
|
_ => Ty::Named(p.take_lexeme().expect("should have Token")),
|
||||||
|
},
|
||||||
|
TKind::LBrack => {
|
||||||
|
let ty = p.consume().parse(level)?;
|
||||||
|
match p.next()? {
|
||||||
|
Token { kind: TKind::Semi, .. } => {
|
||||||
|
let ty = Ty::Array(ty, p.parse(Prec::Binary.next())?);
|
||||||
|
p.next_if(TKind::RBrack)?;
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
Token { kind: TKind::RBrack, .. } => Ty::Slice(ty),
|
||||||
|
tok => Err(ParseError::NotType(tok.kind, tok.span))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ParseError::NotType(tok.kind, tok.span))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(head)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for MatchArm {
|
impl<'t> Parse<'t> for MatchArm {
|
||||||
type Prec = usize;
|
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![], PPrec::Min, TKind::Bar, TKind::FatArrow)?,
|
p.list(vec![], PPrec::Max, TKind::Bar, TKind::FatArrow)?,
|
||||||
p.parse(0)?,
|
p.parse(level)?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,11 +338,11 @@ enum Prec {
|
|||||||
Assign,
|
Assign,
|
||||||
/// Constructor for a tuple
|
/// Constructor for a tuple
|
||||||
Tuple,
|
Tuple,
|
||||||
/// Constructor for a struct
|
|
||||||
Make,
|
|
||||||
/// The body of a function, conditional, etc.
|
/// The body of a function, conditional, etc.
|
||||||
Body,
|
Body,
|
||||||
/// The short-circuiting logical operators [Prec::LogOr], [Prec::LogAnd]
|
/// Constructor for a struct
|
||||||
|
Make,
|
||||||
|
/// The conditional of an `if` or `while` (which is really an `if`)
|
||||||
Logical,
|
Logical,
|
||||||
/// The short-circuiting "boolean or" operator
|
/// The short-circuiting "boolean or" operator
|
||||||
LogOr,
|
LogOr,
|
||||||
@ -372,17 +409,18 @@ pub enum Ps {
|
|||||||
fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||||
Ok(match token.kind {
|
Ok(match token.kind {
|
||||||
TKind::Do => (Ps::Op(Op::Do), Prec::Do),
|
TKind::Do => (Ps::Op(Op::Do), Prec::Do),
|
||||||
|
|
||||||
|
TKind::Identifier => (Ps::Id, Prec::Max),
|
||||||
|
TKind::Grave => (Ps::Mid, Prec::Max),
|
||||||
|
TKind::ColonColon => (Ps::Op(Op::Path), Prec::Max),
|
||||||
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
|
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
|
||||||
(Ps::Lit, Prec::Max)
|
(Ps::Lit, Prec::Max)
|
||||||
}
|
}
|
||||||
|
|
||||||
TKind::Identifier => (Ps::Id, Prec::Max),
|
|
||||||
TKind::Grave => (Ps::Mid, Prec::Max),
|
|
||||||
TKind::Fn => (Ps::Fn, Prec::Body),
|
TKind::Fn => (Ps::Fn, Prec::Body),
|
||||||
|
|
||||||
TKind::Match => (Ps::Match, Prec::Body),
|
TKind::Match => (Ps::Match, Prec::Body),
|
||||||
TKind::Macro => (Ps::Op(Op::Macro), Prec::Assign),
|
TKind::Macro => (Ps::Op(Op::Macro), Prec::Assign),
|
||||||
TKind::Let => (Ps::Let, Prec::Body),
|
TKind::Let => (Ps::Let, Prec::Tuple),
|
||||||
TKind::Const => (Ps::Const, Prec::Body),
|
TKind::Const => (Ps::Const, Prec::Body),
|
||||||
TKind::Loop => (Ps::Op(Op::Loop), Prec::Body),
|
TKind::Loop => (Ps::Op(Op::Loop), Prec::Body),
|
||||||
TKind::If => (Ps::Op(Op::If), Prec::Body),
|
TKind::If => (Ps::Op(Op::If), Prec::Body),
|
||||||
@ -414,6 +452,17 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
|||||||
|
|
||||||
fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||||
Ok(match token.kind {
|
Ok(match token.kind {
|
||||||
|
TKind::Semi => (Ps::Op(Op::Do), Prec::Do), // the inspiration
|
||||||
|
TKind::As => (Ps::Op(Op::As), Prec::Body),
|
||||||
|
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
||||||
|
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
||||||
|
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),
|
||||||
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
||||||
TKind::Eq => (Ps::Op(Op::Set), Prec::Assign),
|
TKind::Eq => (Ps::Op(Op::Set), Prec::Assign),
|
||||||
TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical),
|
TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical),
|
||||||
@ -435,45 +484,19 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
|||||||
TKind::Star => (Ps::Op(Op::Mul), Prec::Term),
|
TKind::Star => (Ps::Op(Op::Mul), Prec::Term),
|
||||||
TKind::Slash => (Ps::Op(Op::Div), Prec::Term),
|
TKind::Slash => (Ps::Op(Op::Div), Prec::Term),
|
||||||
TKind::Rem => (Ps::Op(Op::Rem), Prec::Term),
|
TKind::Rem => (Ps::Op(Op::Rem), Prec::Term),
|
||||||
TKind::ColonColon => (Ps::Op(Op::Path), Prec::Max),
|
|
||||||
TKind::Question => (Ps::End, Prec::Extend),
|
|
||||||
kind => Err(ParseError::NotInfix(kind, token.span))?,
|
kind => Err(ParseError::NotInfix(kind, token.span))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::match_single_binding, unused)]
|
||||||
fn from_postfix(token: &Token) -> PResult<(Ps, Prec)> {
|
fn from_postfix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||||
Ok(match token.kind {
|
Ok(match token.kind {
|
||||||
TKind::Semi => (Ps::Op(Op::Do), Prec::Do), // the inspiration
|
|
||||||
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
|
||||||
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
|
||||||
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),
|
TKind::LCurly => (Ps::Make, Prec::Make),
|
||||||
kind => Err(ParseError::NotPostfix(kind, token.span))?,
|
kind => Err(ParseError::NotPostfix(kind, token.span))?,
|
||||||
|
// _ => (Ps::End, Prec::Max),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn should_coagulate(prev: Op, op: Op) -> bool {
|
|
||||||
prev == op && match prev {
|
|
||||||
Op::LogAnd => true,
|
|
||||||
Op::LogOr => true,
|
|
||||||
Op::Dot => false,
|
|
||||||
Op::Path => true,
|
|
||||||
Op::Lt => false,
|
|
||||||
Op::Leq => false,
|
|
||||||
Op::Eq => false,
|
|
||||||
Op::Neq => false,
|
|
||||||
Op::Geq => false,
|
|
||||||
Op::Gt => false,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Expr {
|
impl<'t> Parse<'t> for Expr {
|
||||||
type Prec = usize;
|
type Prec = usize;
|
||||||
|
|
||||||
@ -496,12 +519,12 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
|
|
||||||
Ps::Id => Expr::Id(p.take_lexeme().expect("should have ident")),
|
Ps::Id => Expr::Id(p.take_lexeme().expect("should have ident")),
|
||||||
Ps::Mid => Expr::MetId(p.consume().next_if(TKind::Identifier)?.lexeme),
|
Ps::Mid => Expr::MetId(p.consume().next_if(TKind::Identifier)?.lexeme),
|
||||||
Ps::Lit => Expr::Lit(p.parse(MIN)?),
|
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||||
Ps::Let => Expr::Let(
|
Ps::Let => Expr::Let(
|
||||||
p.consume().parse(PPrec::NoTopAlt)?,
|
p.consume().parse(PPrec::Alt)?,
|
||||||
p.opt_if(prec.next(), TKind::Eq)?,
|
p.opt_if(prec.value(), TKind::Eq)?,
|
||||||
),
|
),
|
||||||
Ps::Const => Expr::Const(p.consume().parse(PPrec::NoTopAlt)?, {
|
Ps::Const => Expr::Const(p.consume().parse(PPrec::Tuple)?, {
|
||||||
p.next_if(TKind::Eq)?;
|
p.next_if(TKind::Eq)?;
|
||||||
p.parse(prec.next())?
|
p.parse(prec.next())?
|
||||||
}),
|
}),
|
||||||
@ -514,7 +537,7 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
),
|
),
|
||||||
Ps::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![], 0, TKind::Comma, TKind::RCurly)?
|
p.list(vec![], prec.next(), TKind::Comma, TKind::RCurly)?
|
||||||
}),
|
}),
|
||||||
Ps::Op(Op::Block) => Expr::Op(
|
Ps::Op(Op::Block) => Expr::Op(
|
||||||
Op::Block,
|
Op::Block,
|
||||||
@ -576,10 +599,30 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
&& let Ok((op, prec)) = from_postfix(tok)
|
&& let Ok((op, prec)) = from_postfix(tok)
|
||||||
&& level <= prec.prev()
|
&& level <= prec.prev()
|
||||||
&& op != Ps::End
|
&& op != Ps::End
|
||||||
|
{
|
||||||
|
// let kind = tok.kind;
|
||||||
|
let span = span.merge(p.span());
|
||||||
|
// p.consume();
|
||||||
|
head = match (op, &head) {
|
||||||
|
(Ps::Make, Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_)) => Expr::Make(
|
||||||
|
head.anno(span).into(),
|
||||||
|
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
||||||
|
),
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infix
|
||||||
|
while let Ok(tok) = p.peek()
|
||||||
|
&& let Ok((op, prec)) = from_infix(tok)
|
||||||
|
&& level <= prec.prev()
|
||||||
|
&& op != Ps::End
|
||||||
{
|
{
|
||||||
let kind = tok.kind;
|
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 {
|
||||||
Ps::Make => Expr::Make(
|
Ps::Make => Expr::Make(
|
||||||
head.anno(span).into(),
|
head.anno(span).into(),
|
||||||
@ -596,27 +639,8 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
Ps::Op(op @ (Op::Do | Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => {
|
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)?)
|
Expr::Op(op, p.list_bare(vec![head.anno(span)], prec.next(), kind)?)
|
||||||
}
|
}
|
||||||
Ps::Op(op) => Expr::Op(op, vec![head.anno(span)]),
|
Ps::Op(op @ Op::Try) => Expr::Op(op, vec![head.anno(span)]),
|
||||||
_ => unimplemented!("postfix {op:?}"),
|
Ps::Op(op) => Expr::Op(op, vec![head.anno(span), p.parse(prec.next())?]),
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infix
|
|
||||||
while let Ok(tok) = p.peek()
|
|
||||||
&& let Ok((op, prec)) = from_infix(tok)
|
|
||||||
&& level <= prec.prev()
|
|
||||||
&& op != Ps::End
|
|
||||||
{
|
|
||||||
let span = span.merge(p.span());
|
|
||||||
p.consume();
|
|
||||||
|
|
||||||
head = match (op, head) {
|
|
||||||
// controls expression chaining vs coagulating
|
|
||||||
(Ps::Op(op), Expr::Op(prev, mut args)) if should_coagulate(prev, op) => {
|
|
||||||
args.push(p.parse(prec.next())?);
|
|
||||||
Expr::Op(op, args)
|
|
||||||
}
|
|
||||||
(Ps::Op(op), head) => Expr::Op(op, vec![head.anno(span), p.parse(prec.next())?]),
|
|
||||||
_ => unimplemented!("infix {op:?}"),
|
_ => unimplemented!("infix {op:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ pub struct Token {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum TKind {
|
pub enum TKind {
|
||||||
Comment,
|
Comment,
|
||||||
|
As,
|
||||||
Break,
|
Break,
|
||||||
Const,
|
Const,
|
||||||
Do,
|
Do,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user