ast: Merge Ty into Pat, merge Mod and Fn into Bind

This commit is contained in:
2025-10-20 04:24:21 -04:00
parent 22094f4862
commit b80a3a55c3
4 changed files with 188 additions and 338 deletions

View File

@@ -40,12 +40,14 @@ pub enum Literal {
/// A character literal: 'a', '\u{1f988}' /// A character literal: 'a', '\u{1f988}'
Char(char), Char(char),
/// An integer literal: 0, 123, 0x10 /// An integer literal: 0, 123, 0x10
Int(u128), Int(u128, u32),
/// A string literal: /// A string literal:
Str(String), Str(String),
} }
/// Binding patterns for each kind of matchable [Ty] /// Binding patterns for each kind of matchable value.
///
/// This covers both patterns in Match expressions, and type annotations.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Pat { pub enum Pat {
/// Matches anything without binding /// Matches anything without binding
@@ -57,13 +59,11 @@ pub enum Pat {
/// Matches against a named const value /// Matches against a named const value
Path(FqPath), Path(FqPath),
/// Matches a Struct Expression `Ident { Pat }` /// Matches a Struct Expression `Ident { Pat }`
Struct(FqPath, Box<Pat>), NamedStruct(FqPath, Box<Pat>),
/// Matches a Tuple Struct Expression `Ident ( Pat )` /// Matches a Tuple Struct Expression `Ident ( Pat )`
TupStruct(FqPath, Box<Pat>), NamedTuple(FqPath, Box<Pat>),
/// Matches a literal value by equality comparison /// Matches a literal value by equality comparison
Lit(Literal), Lit(Literal),
/// Matches a typed pattern
Typed(Box<Pat>, Ty),
/// Matches a compound pattern /// Matches a compound pattern
Op(PatOp, Vec<Pat>), Op(PatOp, Vec<Pat>),
} }
@@ -83,34 +83,22 @@ pub enum PatOp {
Tuple, Tuple,
/// Matches the elements of a slice or array /// Matches the elements of a slice or array
Slice, Slice,
/// Matches a type annotation or struct member
Typed,
/// Matches a function signature
Fn,
/// Matches one of a list of alternatives /// Matches one of a list of alternatives
Alt, Alt,
} }
/// In-universe types
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Ty {
/// `_`
Infer,
/// `(Identifier :: )* Identifier`
Named(FqPath),
/// `&Ty`
Ref(Box<Ty>),
/// `(..Tys)`
Tuple(Vec<Ty>),
/// `[Ty]`
Slice(Box<Ty>),
/// `[Ty; _]`
Array(Box<Ty>, Box<Expr>),
/// `[..Args, Rety]`
Fn(Vec<Ty>),
}
/// A pattern binding /// A pattern binding
/// ```ignore /// ```ignore
/// let Pat (= Expr (else Expr)?)? /// let Pat (= Expr (else Expr)?)?
/// const Pat (= Expr (else Expr)?)? /// const Pat (= Expr (else Expr)?)?
/// static Pat (= Expr (else Expr)?)? /// static Pat (= Expr (else Expr)?)?
/// fn Pat Expr
/// mod Pat Expr
/// impl Pat Expr
/// Pat => Expr // in match /// Pat => Expr // in match
/// `````` /// ``````
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@@ -124,17 +112,16 @@ pub enum BindKind {
Const, Const,
/// A `static Pat = Expr` binding /// A `static Pat = Expr` binding
Static, Static,
/// A `fn Pat Expr` binding
Fn,
/// A `mod Pat Expr` binding
Mod,
/// An `impl Pat Expr` binding
Impl,
/// A `Pat => Expr` binding /// A `Pat => Expr` binding
Match, Match,
} }
/// A function definition
/// ```ignore
/// fn Ident? (Pat) Expr
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Fn<A: Annotation = Span>(pub Option<String>, pub Pat, pub Ty, pub Anno<Expr<A>, A>);
/// A make (constructor) expression /// A make (constructor) expression
/// ```ignore /// ```ignore
/// Expr { (Ident (: Expr)?),* } /// Expr { (Ident (: Expr)?),* }
@@ -149,12 +136,9 @@ pub struct Make<A: Annotation = Span>(pub Anno<Expr<A>, A>, pub Vec<MakeArm<A>>)
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct MakeArm<A: Annotation = Span>(pub String, pub Option<Anno<Expr<A>, A>>); pub struct MakeArm<A: Annotation = Span>(pub String, pub Option<Anno<Expr<A>, A>>);
/// An inline namespace /// A record-type definition
/// ```ignore
/// mod Ty Expr
/// ```
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Mod<A: Annotation = Span>(pub Ty, pub Anno<Expr<A>, A>); pub struct Typedef(pub TypedefKind, pub Pat);
/// The type of type being defined /// The type of type being defined
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@@ -164,10 +148,6 @@ pub enum TypedefKind {
Enum, Enum,
} }
/// A record-type definition
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Typedef(pub TypedefKind, pub Pat);
/// Expressions: The beating heart of Dough /// Expressions: The beating heart of Dough
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr<A: Annotation = Span> { pub enum Expr<A: Annotation = Span> {
@@ -177,16 +157,13 @@ 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 | const | static) Pat<NoTopAlt> (= expr (else expr)?)? /// `(let | const | static) Pat<NoTopAlt> (= expr (else expr)?)?` |
/// `(fn | mod | impl) Pat<Fn> Expr`
Bind(Box<Bind<A>>), Bind(Box<Bind<A>>),
/// (struct | enum | type) Pat<NoTopAlt> /// (struct | enum | type) Pat<NoTopAlt>
Struct(Box<Typedef>), Struct(Box<Typedef>),
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr`
Fn(Box<Fn<A>>),
/// Expr { (Ident (: Expr)?),* } /// Expr { (Ident (: Expr)?),* }
Make(Box<Make<A>>), Make(Box<Make<A>>),
/// mod Ty Expr
Mod(Box<Mod<A>>),
/// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr /// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr
Op(Op, Vec<Anno<Self, A>>), Op(Op, Vec<Anno<Self, A>>),
} }
@@ -311,7 +288,10 @@ impl Display for Literal {
match self { match self {
Self::Bool(v) => v.fmt(f), Self::Bool(v) => v.fmt(f),
Self::Char(c) => write!(f, "'{}'", c.escape_debug()), Self::Char(c) => write!(f, "'{}'", c.escape_debug()),
Self::Int(i) => i.fmt(f), Self::Int(i, 2) => write!(f, "0b{i:b}"),
Self::Int(i, 8) => write!(f, "0o{i:o}"),
Self::Int(i, 16) => write!(f, "0x{i:x}"),
Self::Int(i, _) => i.fmt(f),
Self::Str(s) => write!(f, "\"{}\"", s.escape_debug()), Self::Str(s) => write!(f, "\"{}\"", s.escape_debug()),
} }
} }
@@ -330,28 +310,21 @@ impl<T: Display + Annotation, A: Annotation> Display for Anno<T, A> {
} }
} }
impl<A: Annotation> Display for Fn<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self(Some(name), pat, rety, expr) => write!(f, "fn {name} {pat} -> {rety} {expr}"),
Self(None, pat, rety, expr) => write!(f, "|{pat}| -> {rety} {expr}"),
}
}
}
impl<A: Annotation> Display for Bind<A> { impl<A: Annotation> Display for Bind<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(op, pat, exprs) = self; let Self(op, pat, exprs) = self;
if let BindKind::Match = op { match op {
return f.delimit(fmt!("{pat} => "), "").list(exprs, ",!? "); BindKind::Match => f.delimit(fmt!("{pat} => "), "").list(exprs, ",!? "),
BindKind::Fn | BindKind::Mod | BindKind::Impl => {
f.delimit(fmt!("{op}{pat} "), "").list(exprs, ",!? ")
} }
_ => match exprs.as_slice() {
match exprs.as_slice() {
[] => write!(f, "{op}{pat}"), [] => write!(f, "{op}{pat}"),
[value] => write!(f, "{op}{pat} = {value}"), [value] => write!(f, "{op}{pat} = {value}"),
[value, fail] => write!(f, "{op} {pat} = {value} else {fail}"), [value, fail] => write!(f, "{op} {pat} = {value} else {fail}"),
other => f.delimit(fmt!("{op}?! {pat} ("), ")").list(other, ", "), other => f.delimit(fmt!("{op}{pat} ("), ")").list(other, ", "),
},
} }
} }
} }
@@ -362,6 +335,9 @@ impl Display for BindKind {
Self::Let => "let ", Self::Let => "let ",
Self::Const => "const ", Self::Const => "const ",
Self::Static => "static ", Self::Static => "static ",
Self::Fn => "fn ",
Self::Mod => "mod ",
Self::Impl => "impl ",
Self::Match => "| ", Self::Match => "| ",
}) })
} }
@@ -374,13 +350,6 @@ impl<A: Annotation> Display for Make<A> {
} }
} }
impl<A: Annotation> Display for Mod<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(ty, expr) = self;
write!(f, "mod {ty} {expr}")
}
}
impl Display for Typedef { impl Display for Typedef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(kind, pat) = self; let Self(kind, pat) = self;
@@ -390,7 +359,7 @@ impl Display for Typedef {
TypedefKind::Enum => "enum ", TypedefKind::Enum => "enum ",
})?; })?;
match pat { match pat {
Pat::Struct(name, bind) => match bind.as_ref() { Pat::NamedStruct(name, bind) => match bind.as_ref() {
Pat::Op(PatOp::Tuple, parts) => f Pat::Op(PatOp::Tuple, parts) => f
.delimit_indented(fmt!("{name} {{"), "}") .delimit_indented(fmt!("{name} {{"), "}")
.list_wrap("\n", parts, ",\n", ",\n"), .list_wrap("\n", parts, ",\n", ",\n"),
@@ -410,8 +379,6 @@ impl<A: Annotation> Display for Expr<A> {
Self::Bind(v) => v.fmt(f), Self::Bind(v) => v.fmt(f),
Self::Struct(v) => v.fmt(f), Self::Struct(v) => v.fmt(f),
Self::Make(v) => v.fmt(f), Self::Make(v) => v.fmt(f),
Self::Mod(v) => v.fmt(f),
Self::Fn(v) => v.fmt(f),
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, Anno(Expr::Op(Op::Tuple, e), _)] if e.is_empty() => { [cond, pass, Anno(Expr::Op(Op::Tuple, e), _)] if e.is_empty() => {
@@ -539,16 +506,16 @@ impl Display for Pat {
Self::MetId(name) => write!(f, "`{name}"), Self::MetId(name) => write!(f, "`{name}"),
Self::Name(name) => name.fmt(f), Self::Name(name) => name.fmt(f),
Self::Path(path) => path.fmt(f), Self::Path(path) => path.fmt(f),
Self::Struct(name, bind) => match bind.as_ref() { Self::NamedStruct(name, bind) => match bind.as_ref() {
Pat::Op(PatOp::Tuple, parts) => { Pat::Op(PatOp::Tuple, parts) => {
f.delimit(fmt!("{name} {{ "), " }").list(parts, ", ") f.delimit(fmt!("{name} {{ "), " }").list(parts, ", ")
} }
other => write!(f, "{name} {{ {other} }}"), other => write!(f, "{name} {{ {other} }}"),
}, },
Self::TupStruct(name, bind) => write!(f, "{name} {bind}"), Self::NamedTuple(name, bind) => write!(f, "{name} {bind}"),
Self::Typed(pat, ty) => write!(f, "{pat}: {ty}"),
Self::Op(PatOp::Tuple, pats) => f.delimit("(", ")").list(pats, ", "), Self::Op(PatOp::Tuple, pats) => f.delimit("(", ")").list(pats, ", "),
Self::Op(PatOp::Slice, pats) => f.delimit("[", "]").list(pats, ", "), Self::Op(PatOp::Slice, pats) => f.delimit("[", "]").list(pats, ", "),
Self::Op(op @ (PatOp::Typed | PatOp::Fn), pats) => f.list(pats, op),
Self::Op(op @ PatOp::Alt, pats) => f.delimit("<", ">").list(pats, op), Self::Op(op @ PatOp::Alt, pats) => f.delimit("<", ">").list(pats, op),
Self::Op(op, pats) => match pats.as_slice() { Self::Op(op, pats) => match pats.as_slice() {
[] => op.fmt(f), [] => op.fmt(f),
@@ -562,36 +529,19 @@ impl Display for Pat {
impl Display for PatOp { impl Display for PatOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self { f.write_str(match self {
Self::Ref => "&",
Self::Rest => "..", Self::Rest => "..",
Self::RangeEx => "..", Self::RangeEx => "..",
Self::RangeIn => "..=", Self::RangeIn => "..=",
Self::Ref => "&",
Self::Tuple => ", ", Self::Tuple => ", ",
Self::Slice => ", ", Self::Slice => ", ",
Self::Typed => ": ",
Self::Fn => " -> ",
Self::Alt => " | ", Self::Alt => " | ",
}) })
} }
} }
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::Ref(ty) => write!(f, "&{ty}"),
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 ()"),
[args @ .., rety] => f
.delimit(fmt!("fn ("), fmt!(") -> {rety}"))
.list(args, ", "),
},
}
}
}
impl<A: Annotation> TryFrom<Expr<A>> for Pat { impl<A: Annotation> TryFrom<Expr<A>> for Pat {
type Error = Expr<A>; type Error = Expr<A>;

View File

@@ -78,24 +78,6 @@ impl<M: Match<A> + Annotation, A: Annotation> Match<A> for Anno<M, A> {
} }
} }
impl<A: Annotation> Match<A> for Fn<A> {
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
let (
Self(pat_id, pat_arg, _pat_rety, pat_body),
Self(expr_id, expr_arg, _expr_rety, expr_body),
) = (pat, expr);
pat_id == expr_id
&& Match::recurse(sub, pat_arg, expr_arg)
&& Match::recurse(sub, pat_body, expr_body)
}
fn apply(&mut self, sub: &Subst<A>) {
let Self(_, pat, _rety, body) = self;
pat.apply(sub);
body.apply(sub);
}
}
impl<A: Annotation> Match<A> for Bind<A> { impl<A: Annotation> Match<A> for Bind<A> {
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool { fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
let (Self(pat_kind, pat_pat, pat_expr), Self(expr_kind, expr_pat, expr_expr)) = (pat, expr); let (Self(pat_kind, pat_pat, pat_expr), Self(expr_kind, expr_pat, expr_expr)) = (pat, expr);
@@ -124,20 +106,6 @@ impl<A: Annotation> Match<A> for crate::ast::Make<A> {
} }
} }
impl<A: Annotation> Match<A> for Mod<A> {
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
let (Self(_pat_ty, pat_expr), Self(_expr_ty, expr_expr)) = (pat, expr);
// TODO: unify types for ast matching
// Match::recurse(sub, pat_ty, expr_ty) &&
Match::recurse(sub, pat_expr, expr_expr)
}
fn apply(&mut self, sub: &Subst<A>) {
let Mod(_ty, expr) = self;
expr.apply(sub);
}
}
impl<A: Annotation> Match<A> for Typedef { impl<A: Annotation> Match<A> for Typedef {
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool { fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
let (Self(pat_kind, pat_pat), Self(expr_kind, expr_pat)) = (pat, expr); let (Self(pat_kind, pat_pat), Self(expr_kind, expr_pat)) = (pat, expr);
@@ -165,10 +133,6 @@ impl<A: Annotation> Match<A> for Expr<A> {
(Expr::Struct(_), _) => false, (Expr::Struct(_), _) => false,
(Expr::Make(pat), Expr::Make(expr)) => Match::recurse(sub, pat, expr), (Expr::Make(pat), Expr::Make(expr)) => Match::recurse(sub, pat, expr),
(Expr::Make(..), _) => false, (Expr::Make(..), _) => false,
(Expr::Mod(pat), Expr::Mod(expr)) => Match::recurse(sub, pat, expr),
(Expr::Mod(..), _) => false,
(Expr::Fn(pat), Expr::Fn(expr)) => Match::recurse(sub, pat, expr),
(Expr::Fn(..), _) => false,
(Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => { (Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => {
Match::recurse(sub, pat_op, expr_op) && Match::recurse(sub, pat_exprs, expr_exprs) Match::recurse(sub, pat_op, expr_op) && Match::recurse(sub, pat_exprs, expr_exprs)
} }
@@ -187,8 +151,6 @@ impl<A: Annotation> Match<A> for Expr<A> {
Expr::Bind(expr) => expr.apply(sub), Expr::Bind(expr) => expr.apply(sub),
Expr::Struct(expr) => expr.apply(sub), Expr::Struct(expr) => expr.apply(sub),
Expr::Make(expr) => expr.apply(sub), Expr::Make(expr) => expr.apply(sub),
Expr::Mod(expr) => expr.apply(sub),
Expr::Fn(expr) => expr.apply(sub),
Expr::Op(op, exprs) => { Expr::Op(op, exprs) => {
op.apply(sub); op.apply(sub);
exprs.apply(sub); exprs.apply(sub);
@@ -220,14 +182,12 @@ impl<A: Annotation> Match<A> for Pat {
(Pat::Name(_), _) => false, (Pat::Name(_), _) => false,
(Pat::Path(_), Pat::Path(_)) => true, (Pat::Path(_), Pat::Path(_)) => true,
(Pat::Path(_), _) => false, (Pat::Path(_), _) => false,
(Pat::Struct(_, pat), Pat::Struct(_, expr)) => Match::recurse(sub, pat, expr), (Pat::NamedStruct(_, pat), Pat::NamedStruct(_, expr)) => Match::recurse(sub, pat, expr),
(Pat::Struct(..), _) => false, (Pat::NamedStruct(..), _) => false,
(Pat::TupStruct(_, pat), Pat::TupStruct(_, expr)) => Match::recurse(sub, pat, expr), (Pat::NamedTuple(_, pat), Pat::NamedTuple(_, expr)) => Match::recurse(sub, pat, expr),
(Pat::TupStruct(..), _) => false, (Pat::NamedTuple(..), _) => false,
(Pat::Lit(pat), Pat::Lit(expr)) => pat == expr, (Pat::Lit(pat), Pat::Lit(expr)) => pat == expr,
(Pat::Lit(_), _) => false, (Pat::Lit(_), _) => false,
(Pat::Typed(pat, _), Pat::Typed(expr, _)) => Match::recurse(sub, pat, expr),
(Pat::Typed(..), _) => false,
(Pat::Op(_, pat), Pat::Op(_, expr)) => Match::recurse(sub, pat, expr), (Pat::Op(_, pat), Pat::Op(_, expr)) => Match::recurse(sub, pat, expr),
(Pat::Op(..), _) => false, (Pat::Op(..), _) => false,
} }
@@ -241,27 +201,13 @@ impl<A: Annotation> Match<A> for Pat {
*self = expr.clone() *self = expr.clone()
} }
} }
Pat::Struct(_, expr) => expr.apply(sub), Pat::NamedStruct(_, expr) => expr.apply(sub),
Pat::TupStruct(_, expr) => expr.apply(sub), Pat::NamedTuple(_, expr) => expr.apply(sub),
Pat::Typed(pat, ty) => {
pat.apply(sub);
ty.apply(sub);
}
Pat::Op(_, pats) => pats.apply(sub), Pat::Op(_, pats) => pats.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 {
pat == expr pat == expr

View File

@@ -1,6 +1,6 @@
//! Tests the lexer //! Tests the lexer
use doughlang::{ use doughlang::{
ast::{Anno, Pat, Ty}, ast::{Anno, Pat},
parser::PPrec, parser::PPrec,
}; };
#[allow(unused_imports)] #[allow(unused_imports)]
@@ -45,10 +45,6 @@ fn main() -> Result<(), Box<dyn Error>> {
pats()?; pats()?;
Ok(Response::Deny) Ok(Response::Deny)
} }
"ty" => {
tys()?;
Ok(Response::Deny)
}
"macro" => { "macro" => {
if let Err(e) = subst() { if let Err(e) = subst() {
println!("\x1b[31m{e}\x1b[0m"); println!("\x1b[31m{e}\x1b[0m");
@@ -141,29 +137,6 @@ fn pats() -> Result<(), Box<dyn Error>> {
Ok(()) Ok(())
} }
fn tys() -> Result<(), Box<dyn Error>> {
clear();
read_and("\x1b[94m", ".>", " >", |line| {
let mut parser = Parser::new(Lexer::new(line));
if line.trim().is_empty() {
return Ok(Response::Break);
}
loop {
match parser.parse::<Ty>(()) {
Err(ParseError::FromLexer(LexError { res: EOF, .. })) => {
break Ok(Response::Accept);
}
Err(e) => {
println!("\x1b[31m{e}\x1b[0m");
break Ok(Response::Deny);
}
Ok(v) => println!("{v}\n{v:#?}"),
}
}
})?;
Ok(())
}
fn subst() -> Result<(), Box<dyn Error>> { fn subst() -> Result<(), Box<dyn Error>> {
let mut rl = repline::Repline::new("\x1b[35mexp", " >", "?>"); let mut rl = repline::Repline::new("\x1b[35mexp", " >", "?>");
let exp = rl.read()?; let exp = rl.read()?;

View File

@@ -271,18 +271,13 @@ impl<'t> Parse<'t> for Literal {
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 => Literal::Char({ TKind::Character | TKind::Integer | TKind::String => {
let Token { lexeme, .. } = p.take().expect("should have Token"); match p.take().expect("should have Token").lexeme {
lexeme.char().expect("char token should have char") Lexeme::String(str) => Literal::Str(str),
}), Lexeme::Integer(int, base) => Literal::Int(int, base),
TKind::Integer => Literal::Int({ Lexeme::Char(chr) => Literal::Char(chr),
let Token { lexeme, .. } = p.take().expect("should have Token"); }
lexeme.int().expect("integer token should have int") }
}),
TKind::String => Literal::Str({
let Token { lexeme, .. } = p.take().expect("should have Token");
lexeme.string().expect("string token should have string")
}),
other => Err(ParseError::NotLiteral(other, tok.span))?, other => Err(ParseError::NotLiteral(other, tok.span))?,
}) })
} }
@@ -295,6 +290,7 @@ pub enum PPrec {
Tuple, Tuple,
Typed, Typed,
Range, Range,
Fn,
Max, Max,
} }
@@ -305,14 +301,14 @@ impl PPrec {
Self::Alt => Self::Tuple, Self::Alt => Self::Tuple,
Self::Tuple => Self::Typed, Self::Tuple => Self::Typed,
Self::Typed => Self::Range, Self::Typed => Self::Range,
Self::Range => Self::Max, Self::Range => Self::Fn,
Self::Fn => Self::Max,
Self::Max => Self::Max, Self::Max => Self::Max,
} }
} }
} }
enum PatPs { enum PatPs {
Typed,
Op(PatOp), Op(PatOp),
} }
@@ -320,8 +316,9 @@ fn pat_from_infix(token: &Token) -> Option<(PatPs, PPrec)> {
Some(match token.kind { Some(match token.kind {
TKind::DotDot => (PatPs::Op(PatOp::RangeEx), PPrec::Range), TKind::DotDot => (PatPs::Op(PatOp::RangeEx), PPrec::Range),
TKind::DotDotEq => (PatPs::Op(PatOp::RangeIn), PPrec::Range), TKind::DotDotEq => (PatPs::Op(PatOp::RangeIn), PPrec::Range),
TKind::Colon => (PatPs::Typed, PPrec::Typed), TKind::Colon => (PatPs::Op(PatOp::Typed), PPrec::Typed),
TKind::Comma => (PatPs::Op(PatOp::Tuple), PPrec::Tuple), TKind::Comma => (PatPs::Op(PatOp::Tuple), PPrec::Tuple),
TKind::Arrow => (PatPs::Op(PatOp::Fn), PPrec::Fn),
TKind::Bar => (PatPs::Op(PatOp::Alt), PPrec::Alt), TKind::Bar => (PatPs::Op(PatOp::Alt), PPrec::Alt),
_ => None?, _ => None?,
}) })
@@ -335,6 +332,7 @@ impl<'t> Parse<'t> for Pat {
// Prefix // Prefix
let mut head = match tok.kind { let mut head = match tok.kind {
TKind::Fn => return p.consume().parse(PPrec::Fn),
TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => { TKind::True | TKind::False | TKind::Character | TKind::Integer | TKind::String => {
Pat::Lit(p.parse(())?) Pat::Lit(p.parse(())?)
} }
@@ -350,8 +348,8 @@ impl<'t> Parse<'t> for Pat {
let mut path: FqPath = p.parse(())?; let mut path: FqPath = p.parse(())?;
// TODO: make these postfix. // TODO: make these postfix.
match p.peek().map(|t| t.kind) { match p.peek().map(|t| t.kind) {
Ok(TKind::LParen) => Pat::TupStruct(path, p.parse(PPrec::Typed)?), Ok(TKind::LParen) => Pat::NamedTuple(path, p.parse(PPrec::Typed)?),
Ok(TKind::LCurly) => Pat::Struct( Ok(TKind::LCurly) if level <= PPrec::Tuple => Pat::NamedStruct(
path, path,
p.consume() p.consume()
.opt(PPrec::Alt, TKind::RCurly)? .opt(PPrec::Alt, TKind::RCurly)?
@@ -406,7 +404,12 @@ impl<'t> Parse<'t> for Pat {
{ {
let kind = tok.kind; let kind = tok.kind;
head = match op { head = match op {
PatPs::Typed => Pat::Typed(head.into(), p.consume().parse(())?), PatPs::Op(PatOp::Typed) => {
Pat::Op(PatOp::Typed, vec![head, p.consume().parse(PPrec::Max)?])
}
PatPs::Op(PatOp::Fn) => {
Pat::Op(PatOp::Fn, vec![head, p.consume().parse(PPrec::Fn.next())?])
}
PatPs::Op(op @ (PatOp::RangeEx | PatOp::RangeIn)) => Pat::Op( PatPs::Op(op @ (PatOp::RangeEx | PatOp::RangeIn)) => Pat::Op(
op, op,
match p.consume().peek().map(|t| t.kind) { match p.consume().peek().map(|t| t.kind) {
@@ -423,59 +426,59 @@ impl<'t> Parse<'t> for Pat {
} }
} }
impl<'t> Parse<'t> for Ty { // impl<'t> Parse<'t> for Ty {
type Prec = (); // type Prec = ();
fn parse(p: &mut Parser<'t>, level: Self::Prec) -> PResult<Self> // fn parse(p: &mut Parser<'t>, level: Self::Prec) -> PResult<Self>
where Self: Sized { // where Self: Sized {
let &Token { kind, span, .. } = p.peek()?; // let &Token { kind, span, .. } = p.peek()?;
// TODO: this is a kinda jank way of error reporting // // TODO: this is a kinda jank way of error reporting
let head = match kind { // let head = match kind {
TKind::Identifier => match p.peek()?.lexeme.str() { // TKind::Identifier => match p.peek()?.lexeme.str() {
Some("_") => p.consume().then(Ty::Infer), // Some("_") => p.consume().then(Ty::Infer),
_ => Ty::Named(p.parse(())?), // _ => Ty::Named(p.parse(())?),
}, // },
TKind::Amp => Ty::Ref(p.consume().parse(())?), // TKind::Amp => Ty::Ref(p.consume().parse(())?),
TKind::AmpAmp => Ty::Ref(Box::new(Ty::Ref(p.consume().parse(())?))), // TKind::AmpAmp => Ty::Ref(Box::new(Ty::Ref(p.consume().parse(())?))),
TKind::LBrack => { // TKind::LBrack => {
let ty = p.consume().parse(level)?; // let ty = p.consume().parse(level)?;
match p.next()? { // match p.next()? {
Token { kind: TKind::Semi, .. } => { // Token { kind: TKind::Semi, .. } => {
let ty = Ty::Array(ty, p.parse(Prec::Binary.next())?); // let ty = Ty::Array(ty, p.parse(Prec::Binary.next())?);
p.expect(TKind::RBrack)?; // p.expect(TKind::RBrack)?;
ty // ty
} // }
Token { kind: TKind::RBrack, .. } => Ty::Slice(ty), // Token { kind: TKind::RBrack, .. } => Ty::Slice(ty),
tok => Err(ParseError::NotType(tok.kind, tok.span))?, // tok => Err(ParseError::NotType(tok.kind, tok.span))?,
} // }
} // }
TKind::Fn => { // TKind::Fn => {
p.consume(); // p.consume();
match p.parse(())? { // match p.parse(())? {
Ty::Fn(args) => Ty::Fn(args), // Ty::Fn(args) => Ty::Fn(args),
other @ Ty::Tuple(_) => Ty::Fn(vec![other, Ty::Tuple(vec![])]), // other @ Ty::Tuple(_) => Ty::Fn(vec![other, Ty::Tuple(vec![])]),
other => Ty::Fn(vec![other, Ty::Tuple(vec![])]), // other => Ty::Fn(vec![other, Ty::Tuple(vec![])]),
} // }
} // }
TKind::LParen => { // TKind::LParen => {
Ty::Tuple(p.consume().list(vec![], (), TKind::Comma, TKind::RParen)?) // Ty::Tuple(p.consume().list(vec![], (), TKind::Comma, TKind::RParen)?)
} // }
_ => Err(ParseError::NotType(kind, span))?, // _ => Err(ParseError::NotType(kind, span))?,
}; // };
Ok(match p.next_if(TKind::Arrow).allow_eof()? { // Ok(match p.next_if(TKind::Arrow).allow_eof()? {
Some(Ok(_)) => Ty::Fn(vec![ // Some(Ok(_)) => Ty::Fn(vec![
match head { // match head {
args @ Ty::Tuple(_) => args, // args @ Ty::Tuple(_) => args,
arg => Ty::Tuple(vec![arg]), // arg => Ty::Tuple(vec![arg]),
}, // },
p.parse(())?, // p.parse(())?,
]), // ]),
_ => head, // _ => head,
}) // })
} // }
} // }
/// Organizes the precedence hierarchy for syntactic elements /// Organizes the precedence hierarchy for syntactic elements
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -669,56 +672,38 @@ impl<'t> Parse<'t> for Typedef {
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> { fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
let tok = p.next()?; let tok = p.next()?;
match tok.kind { match tok.kind {
TKind::Enum => Ok(Self(TypedefKind::Enum, p.parse(PPrec::Alt)?)), TKind::Enum => Ok(Self(TypedefKind::Enum, p.parse(PPrec::Tuple)?)),
TKind::Struct => Ok(Self(TypedefKind::Struct, p.parse(PPrec::Tuple)?)), TKind::Struct => Ok(Self(TypedefKind::Struct, p.parse(PPrec::Tuple)?)),
_ => Err(ParseError::NotType(tok.kind, tok.span)), _ => Err(ParseError::NotType(tok.kind, tok.span)),
} }
} }
} }
impl<'t> Parse<'t> for Fn {
type Prec = ();
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
match p.consume().next_if(TKind::Identifier)? {
Ok(Token { lexeme, .. }) => Ok(Self(
lexeme.string(),
p.parse(PPrec::Tuple)?,
p.opt_if((), TKind::Arrow)?.unwrap_or(Ty::Tuple(vec![])),
p.parse(Prec::Body.next())?,
)),
_ => Ok(Self(
None,
Pat::Op(
PatOp::Tuple,
p.expect(TKind::LParen)?.list(
vec![],
PPrec::Tuple,
TKind::Comma,
TKind::RParen,
)?,
),
p.opt_if((), TKind::Arrow)?.unwrap_or(Ty::Tuple(vec![])),
p.parse(Prec::Body.next())?,
)),
}
}
}
impl<'t> Parse<'t> for Bind { impl<'t> Parse<'t> for Bind {
type Prec = BindKind; type Prec = BindKind;
fn parse(p: &mut Parser<'t>, level: Self::Prec) -> PResult<Self> { fn parse(p: &mut Parser<'t>, level: Self::Prec) -> PResult<Self> {
if let BindKind::Match = level { match level {
BindKind::Match => {
// |? Pat => Expr // |? Pat => Expr
p.next_if(TKind::Bar)?.ok(); // and discard p.next_if(TKind::Bar)?.ok(); // and discard
return Ok(Self( Ok(Self(
level, level,
p.parse(PPrec::Min)?, p.parse(PPrec::Alt)?,
vec![p.expect(TKind::FatArrow)?.parse(Prec::Body.next())?], vec![p.expect(TKind::FatArrow)?.parse(Prec::Body.next())?],
)); ))
} }
BindKind::Mod => Ok(Self(
level,
p.consume().parse(PPrec::Max)?,
vec![p.parse(Prec::Body.next())?],
)),
BindKind::Fn => Ok(Self(
level,
p.consume().parse(PPrec::Fn)?,
vec![p.parse(Prec::Body.next())?],
)),
_ => {
// let Pat // let Pat
let pat = p.consume().parse(PPrec::Tuple)?; let pat = p.consume().parse(PPrec::Tuple)?;
if p.next_if(TKind::Eq).allow_eof()?.is_none_or(|v| v.is_err()) { if p.next_if(TKind::Eq).allow_eof()?.is_none_or(|v| v.is_err()) {
@@ -738,6 +723,8 @@ impl<'t> Parse<'t> for Bind {
Ok(Self(level, pat, vec![body, p.parse(Prec::Body.next())?])) Ok(Self(level, pat, vec![body, p.parse(Prec::Body.next())?]))
} }
} }
}
}
impl<'t> Parse<'t> for MakeArm { impl<'t> Parse<'t> for MakeArm {
type Prec = (); type Prec = ();
@@ -753,16 +740,6 @@ impl<'t> Parse<'t> for MakeArm {
} }
} }
impl<'t> Parse<'t> for Mod {
type Prec = ();
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
let ty = p.consume().parse(())?;
let body = p.parse(Prec::Body.value())?;
Ok(Mod(ty, body))
}
}
fn parse_for<'t>(p: &mut Parser<'t>, _level: ()) -> PResult<Expr> { fn parse_for<'t>(p: &mut Parser<'t>, _level: ()) -> PResult<Expr> {
// for Pat // for Pat
let pat = p.consume().parse(PPrec::Tuple)?; let pat = p.consume().parse(PPrec::Tuple)?;
@@ -830,7 +807,7 @@ fn parse_for<'t>(p: &mut Parser<'t>, _level: ()) -> PResult<Expr> {
.anno(fspan), .anno(fspan),
Expr::Bind(Box::new(Bind( Expr::Bind(Box::new(Bind(
BindKind::Match, BindKind::Match,
Pat::TupStruct( Pat::NamedTuple(
"Some".into(), "Some".into(),
Box::new(Pat::Op(PatOp::Tuple, vec![pat])), Box::new(Pat::Op(PatOp::Tuple, vec![pat])),
), ),
@@ -876,12 +853,31 @@ impl<'t> Parse<'t> for Expr {
Ps::Id => Expr::Id(p.parse(())?), Ps::Id => Expr::Id(p.parse(())?),
Ps::Mid => Expr::MetId(p.consume().next()?.lexeme.to_string()), Ps::Mid => Expr::MetId(p.consume().next()?.lexeme.to_string()),
Ps::Lit => Expr::Lit(p.parse(())?), Ps::Lit => Expr::Lit(p.parse(())?),
Ps::Typedef => Expr::Struct(p.parse(())?),
Ps::Let => Expr::Bind(p.parse(BindKind::Let)?), Ps::Let => Expr::Bind(p.parse(BindKind::Let)?),
Ps::Const => Expr::Bind(p.parse(BindKind::Const)?), Ps::Const => Expr::Bind(p.parse(BindKind::Const)?),
Ps::Static => Expr::Bind(p.parse(BindKind::Static)?), Ps::Static => Expr::Bind(p.parse(BindKind::Static)?),
Ps::Mod => Expr::Bind(p.parse(BindKind::Mod)?),
Ps::Fn => Expr::Bind(p.parse(BindKind::Fn)?),
Ps::Lambda | Ps::Lambda0 => {
p.consume();
let args = if op == Ps::Lambda {
p.opt(PPrec::Tuple, TKind::Bar)?
.unwrap_or(Pat::Op(PatOp::Tuple, vec![]))
} else {
Pat::Op(PatOp::Tuple, vec![])
};
let rety = p.opt_if(PPrec::Max, TKind::Arrow)?.unwrap_or(Pat::Ignore);
Expr::Bind(Box::new(Bind(
BindKind::Fn,
Pat::Op(PatOp::Fn, vec![args, rety]),
vec![p.parse(Prec::Body.next())?],
)))
}
Ps::For => parse_for(p, ())?, Ps::For => parse_for(p, ())?,
Ps::Typedef => Expr::Struct(p.parse(())?),
Ps::Mod => Expr::Mod(p.parse(())?),
Ps::Op(Op::Match) => parse_match(p)?, Ps::Op(Op::Match) => parse_match(p)?,
Ps::Op(Op::Meta) => Expr::Op( Ps::Op(Op::Meta) => Expr::Op(
Op::Meta, Op::Meta,
@@ -917,21 +913,6 @@ impl<'t> Parse<'t> for Expr {
]; ];
Expr::Op(op, exprs) Expr::Op(op, exprs)
} }
Ps::Fn => Expr::Fn(p.parse(())?),
Ps::Lambda => Expr::Fn(Box::new(Fn(
None,
p.consume()
.opt(PPrec::Tuple, TKind::Bar)?
.unwrap_or(Pat::Op(PatOp::Tuple, vec![])),
p.opt_if((), TKind::Arrow)?.unwrap_or(Ty::Infer),
p.parse(Prec::Body.next())?,
))),
Ps::Lambda0 => Expr::Fn(Box::new(Fn(
None,
Pat::Op(PatOp::Tuple, vec![]),
p.consume().opt_if((), TKind::Arrow)?.unwrap_or(Ty::Infer),
p.parse(Prec::Body.next())?,
))),
Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| { Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| {
Expr::Op( Expr::Op(
Op::Refer, Op::Refer,