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}'
Char(char),
/// An integer literal: 0, 123, 0x10
Int(u128),
Int(u128, u32),
/// A string literal:
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)]
pub enum Pat {
/// Matches anything without binding
@@ -57,13 +59,11 @@ pub enum Pat {
/// Matches against a named const value
Path(FqPath),
/// Matches a Struct Expression `Ident { Pat }`
Struct(FqPath, Box<Pat>),
NamedStruct(FqPath, Box<Pat>),
/// Matches a Tuple Struct Expression `Ident ( Pat )`
TupStruct(FqPath, Box<Pat>),
NamedTuple(FqPath, Box<Pat>),
/// Matches a literal value by equality comparison
Lit(Literal),
/// Matches a typed pattern
Typed(Box<Pat>, Ty),
/// Matches a compound pattern
Op(PatOp, Vec<Pat>),
}
@@ -83,34 +83,22 @@ pub enum PatOp {
Tuple,
/// Matches the elements of a slice or array
Slice,
/// Matches a type annotation or struct member
Typed,
/// Matches a function signature
Fn,
/// Matches one of a list of alternatives
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
/// ```ignore
/// let Pat (= Expr (else Expr)?)?
/// const Pat (= Expr (else Expr)?)?
/// static Pat (= Expr (else Expr)?)?
/// fn Pat Expr
/// mod Pat Expr
/// impl Pat Expr
/// Pat => Expr // in match
/// ``````
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -124,17 +112,16 @@ pub enum BindKind {
Const,
/// A `static Pat = Expr` binding
Static,
/// A `fn Pat Expr` binding
Fn,
/// A `mod Pat Expr` binding
Mod,
/// An `impl Pat Expr` binding
Impl,
/// A `Pat => Expr` binding
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
/// ```ignore
/// 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)]
pub struct MakeArm<A: Annotation = Span>(pub String, pub Option<Anno<Expr<A>, A>>);
/// An inline namespace
/// ```ignore
/// mod Ty Expr
/// ```
/// A record-type definition
#[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
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -164,10 +148,6 @@ pub enum TypedefKind {
Enum,
}
/// A record-type definition
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Typedef(pub TypedefKind, pub Pat);
/// Expressions: The beating heart of Dough
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr<A: Annotation = Span> {
@@ -177,16 +157,13 @@ pub enum Expr<A: Annotation = Span> {
MetId(String),
/// A literal bool, string, char, or int
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>>),
/// (struct | enum | type) Pat<NoTopAlt>
Struct(Box<Typedef>),
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr`
Fn(Box<Fn<A>>),
/// Expr { (Ident (: Expr)?),* }
Make(Box<Make<A>>),
/// mod Ty Expr
Mod(Box<Mod<A>>),
/// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr
Op(Op, Vec<Anno<Self, A>>),
}
@@ -311,7 +288,10 @@ impl Display for Literal {
match self {
Self::Bool(v) => v.fmt(f),
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()),
}
}
@@ -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> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(op, pat, exprs) = self;
if let BindKind::Match = op {
return f.delimit(fmt!("{pat} => "), "").list(exprs, ",!? ");
}
match exprs.as_slice() {
[] => write!(f, "{op} {pat}"),
[value] => write!(f, "{op} {pat} = {value}"),
[value, fail] => write!(f, "{op} {pat} = {value} else {fail}"),
other => f.delimit(fmt!("{op}?! {pat} ("), ")").list(other, ", "),
match op {
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() {
[] => write!(f, "{op}{pat}"),
[value] => write!(f, "{op}{pat} = {value}"),
[value, fail] => write!(f, "{op} {pat} = {value} else {fail}"),
other => f.delimit(fmt!("{op}{pat} ("), ")").list(other, ", "),
},
}
}
}
@@ -359,9 +332,12 @@ impl<A: Annotation> Display for Bind<A> {
impl Display for BindKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Let => "let",
Self::Const => "const",
Self::Static => "static",
Self::Let => "let ",
Self::Const => "const ",
Self::Static => "static ",
Self::Fn => "fn ",
Self::Mod => "mod ",
Self::Impl => "impl ",
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 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(kind, pat) = self;
@@ -390,7 +359,7 @@ impl Display for Typedef {
TypedefKind::Enum => "enum ",
})?;
match pat {
Pat::Struct(name, bind) => match bind.as_ref() {
Pat::NamedStruct(name, bind) => match bind.as_ref() {
Pat::Op(PatOp::Tuple, parts) => f
.delimit_indented(fmt!("{name} {{"), "}")
.list_wrap("\n", parts, ",\n", ",\n"),
@@ -410,8 +379,6 @@ impl<A: Annotation> Display for Expr<A> {
Self::Bind(v) => v.fmt(f),
Self::Struct(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() {
[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::Name(name) => name.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) => {
f.delimit(fmt!("{name} {{ "), " }").list(parts, ", ")
}
other => write!(f, "{name} {{ {other} }}"),
},
Self::TupStruct(name, bind) => write!(f, "{name} {bind}"),
Self::Typed(pat, ty) => write!(f, "{pat}: {ty}"),
Self::NamedTuple(name, bind) => write!(f, "{name} {bind}"),
Self::Op(PatOp::Tuple, 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, pats) => match pats.as_slice() {
[] => op.fmt(f),
@@ -562,36 +529,19 @@ impl Display for Pat {
impl Display for PatOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Ref => "&",
Self::Rest => "..",
Self::RangeEx => "..",
Self::RangeIn => "..=",
Self::Ref => "&",
Self::Tuple => ", ",
Self::Slice => ", ",
Self::Typed => ": ",
Self::Fn => " -> ",
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 {
type Error = Expr<A>;