doughlang: enums, ref patterns, ref types
This commit is contained in:
62
src/ast.rs
62
src/ast.rs
@@ -71,10 +71,14 @@ pub enum Pat {
|
|||||||
/// Operators on lists of patterns
|
/// Operators on lists of patterns
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum PatOp {
|
pub enum PatOp {
|
||||||
|
/// Matches the dereference of a pointer (`&pat`)
|
||||||
|
Ref,
|
||||||
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`)
|
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`)
|
||||||
Rest,
|
Rest,
|
||||||
/// Matches an exclusive bounded range (`0..100`)
|
/// Matches an exclusive bounded range (`0..100`)
|
||||||
RangeEx,
|
RangeEx,
|
||||||
|
/// Matches an inclusive bounded range (`0..=100`)
|
||||||
|
RangeIn,
|
||||||
/// Matches the elements of a tuple
|
/// Matches the elements of a tuple
|
||||||
Tuple,
|
Tuple,
|
||||||
/// Matches the elements of a slice or array
|
/// Matches the elements of a slice or array
|
||||||
@@ -90,6 +94,8 @@ pub enum Ty {
|
|||||||
Infer,
|
Infer,
|
||||||
/// `(Identifier :: )* Identifier`
|
/// `(Identifier :: )* Identifier`
|
||||||
Named(FqPath),
|
Named(FqPath),
|
||||||
|
/// `&Ty`
|
||||||
|
Ref(Box<Ty>),
|
||||||
/// `(..Tys)`
|
/// `(..Tys)`
|
||||||
Tuple(Vec<Ty>),
|
Tuple(Vec<Ty>),
|
||||||
/// `[Ty]`
|
/// `[Ty]`
|
||||||
@@ -156,9 +162,17 @@ pub struct MakeArm<A: Annotation = Span>(pub String, pub Option<Anno<Expr<A>, A>
|
|||||||
#[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 Mod<A: Annotation = Span>(pub Ty, pub Anno<Expr<A>, A>);
|
||||||
|
|
||||||
|
/// The type of type being defined
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum TypedefKind {
|
||||||
|
Alias,
|
||||||
|
Struct,
|
||||||
|
Enum,
|
||||||
|
}
|
||||||
|
|
||||||
/// A record-type definition
|
/// A record-type definition
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Struct(pub Pat);
|
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)]
|
||||||
@@ -173,8 +187,8 @@ pub enum Expr<A: Annotation = Span> {
|
|||||||
Let(Box<Let<A>>),
|
Let(Box<Let<A>>),
|
||||||
/// `const Pat<NoTopAlt> (= Expr)?` (Basically let rec)
|
/// `const Pat<NoTopAlt> (= Expr)?` (Basically let rec)
|
||||||
Const(Box<Const<A>>),
|
Const(Box<Const<A>>),
|
||||||
/// struct Pat<NoTopAlt>
|
/// (struct | enum | type) Pat<NoTopAlt>
|
||||||
Struct(Box<Struct>),
|
Struct(Box<Typedef>),
|
||||||
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr`
|
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr`
|
||||||
Fn(Box<Fn<A>>),
|
Fn(Box<Fn<A>>),
|
||||||
/// Expr { (Ident (: Expr)?),* }
|
/// Expr { (Ident (: Expr)?),* }
|
||||||
@@ -364,17 +378,22 @@ impl<A: Annotation> Display for Mod<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Struct {
|
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(pat) = self;
|
let Self(kind, pat) = self;
|
||||||
|
let kind = match kind {
|
||||||
|
TypedefKind::Alias => "type",
|
||||||
|
TypedefKind::Struct => "struct",
|
||||||
|
TypedefKind::Enum => "enum",
|
||||||
|
};
|
||||||
match pat {
|
match pat {
|
||||||
Pat::Struct(name, bind) => match bind.as_ref() {
|
Pat::Struct(name, bind) => match bind.as_ref() {
|
||||||
Pat::Op(PatOp::Tuple, parts) => f
|
Pat::Op(PatOp::Tuple, parts) => f
|
||||||
.delimit_indented(fmt!("struct {name} {{"), "}")
|
.delimit_indented(fmt!("{kind} {name} {{"), "}")
|
||||||
.list_wrap("\n", parts, ",\n", ",\n"),
|
.list_wrap("\n", parts, ",\n", ",\n"),
|
||||||
other => write!(f, "{name} {{ {other} }}"),
|
other => write!(f, "{name} {{ {other} }}"),
|
||||||
},
|
},
|
||||||
_ => write!(f, "struct {pat}"),
|
_ => write!(f, "{kind} {pat}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,25 +529,38 @@ impl Display for Pat {
|
|||||||
},
|
},
|
||||||
Self::TupStruct(name, bind) => write!(f, "{name} {bind}"),
|
Self::TupStruct(name, bind) => write!(f, "{name} {bind}"),
|
||||||
Self::Typed(pat, ty) => write!(f, "{pat}: {ty}"),
|
Self::Typed(pat, ty) => write!(f, "{pat}: {ty}"),
|
||||||
Self::Op(PatOp::Rest, pats) => match pats.as_slice() {
|
|
||||||
[] => write!(f, ".."),
|
|
||||||
[rest] => write!(f, "..{rest}"),
|
|
||||||
[from, to] => write!(f, "{from}..{to}"),
|
|
||||||
_ => f.list(pats, "<..>"),
|
|
||||||
},
|
|
||||||
Self::Op(PatOp::RangeEx, pats) => f.delimit("(", ")").list(pats, ".."),
|
|
||||||
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(PatOp::Alt, pats) => f.delimit("<", ">").list(pats, " | "),
|
Self::Op(op @ PatOp::Alt, pats) => f.delimit("<", ">").list(pats, op),
|
||||||
|
Self::Op(op, pats) => match pats.as_slice() {
|
||||||
|
[] => op.fmt(f),
|
||||||
|
[rest] => write!(f, "{op}{rest}"),
|
||||||
|
_ => f.delimit("(", ")").list(pats, op),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for PatOp {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Rest => "..",
|
||||||
|
Self::RangeEx => "..",
|
||||||
|
Self::RangeIn => "..=",
|
||||||
|
Self::Ref => "&",
|
||||||
|
Self::Tuple => ", ",
|
||||||
|
Self::Slice => ", ",
|
||||||
|
Self::Alt => " | ",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Ty {
|
impl Display for Ty {
|
||||||
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 {
|
||||||
Self::Infer => "_".fmt(f),
|
Self::Infer => "_".fmt(f),
|
||||||
Self::Named(name) => name.fmt(f),
|
Self::Named(name) => name.fmt(f),
|
||||||
|
Self::Ref(ty) => write!(f, "&{ty}"),
|
||||||
Self::Tuple(items) => f.delimit('(', ')').list(items, ", "),
|
Self::Tuple(items) => f.delimit('(', ')').list(items, ", "),
|
||||||
Self::Slice(ty) => write!(f, "[{ty}]"),
|
Self::Slice(ty) => write!(f, "[{ty}]"),
|
||||||
Self::Array(ty, n) => write!(f, "[{ty}; {n}]"),
|
Self::Array(ty, n) => write!(f, "[{ty}; {n}]"),
|
||||||
|
|||||||
@@ -162,14 +162,14 @@ impl<A: Annotation> Match<A> for Mod<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Annotation> Match<A> for Struct {
|
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_pat), Self(expr_pat)) = (pat, expr);
|
let (Self(pat_kind, pat_pat), Self(expr_kind, expr_pat)) = (pat, expr);
|
||||||
Match::recurse(sub, pat_pat, expr_pat)
|
pat_kind == expr_kind && Match::recurse(sub, pat_pat, expr_pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(&mut self, sub: &Subst<A>) {
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
let Self(pat) = self;
|
let Self(_, pat) = self;
|
||||||
pat.apply(sub);
|
pat.apply(sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ impl<'t> Lexer<'t> {
|
|||||||
"const" => TKind::Const,
|
"const" => TKind::Const,
|
||||||
"do" => TKind::Do,
|
"do" => TKind::Do,
|
||||||
"else" => TKind::Else,
|
"else" => TKind::Else,
|
||||||
|
"enum" => TKind::Enum,
|
||||||
"false" => TKind::False,
|
"false" => TKind::False,
|
||||||
"fn" => TKind::Fn,
|
"fn" => TKind::Fn,
|
||||||
"for" => TKind::For,
|
"for" => TKind::For,
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ enum PatPs {
|
|||||||
fn pat_from_infix(token: &Token) -> Option<(PatPs, PPrec)> {
|
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::Colon => (PatPs::Typed, PPrec::Typed),
|
TKind::Colon => (PatPs::Typed, PPrec::Typed),
|
||||||
TKind::Comma => (PatPs::Op(PatOp::Tuple), PPrec::Tuple),
|
TKind::Comma => (PatPs::Op(PatOp::Tuple), PPrec::Tuple),
|
||||||
TKind::Bar => (PatPs::Op(PatOp::Alt), PPrec::Alt),
|
TKind::Bar => (PatPs::Op(PatOp::Alt), PPrec::Alt),
|
||||||
@@ -297,6 +298,11 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
Pat::Lit(p.parse(())?)
|
Pat::Lit(p.parse(())?)
|
||||||
}
|
}
|
||||||
TKind::Bar => p.consume().parse(level)?,
|
TKind::Bar => p.consume().parse(level)?,
|
||||||
|
TKind::Amp => Pat::Op(PatOp::Ref, vec![p.consume().parse(PPrec::Max)?]),
|
||||||
|
TKind::AmpAmp => Pat::Op(
|
||||||
|
PatOp::Ref,
|
||||||
|
vec![Pat::Op(PatOp::Ref, vec![p.consume().parse(PPrec::Max)?])],
|
||||||
|
),
|
||||||
TKind::Identifier => match tok.lexeme.str() {
|
TKind::Identifier => match tok.lexeme.str() {
|
||||||
Some("_") => p.consume().then(Pat::Ignore),
|
Some("_") => p.consume().then(Pat::Ignore),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -335,6 +341,13 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
_ => vec![],
|
_ => vec![],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
TKind::DotDotEq => Pat::Op(
|
||||||
|
PatOp::RangeIn,
|
||||||
|
match p.consume().peek()?.kind {
|
||||||
|
TKind::Grave | TKind::Integer | TKind::Character => vec![p.parse(level)?],
|
||||||
|
_ => vec![],
|
||||||
|
},
|
||||||
|
),
|
||||||
TKind::LParen => Pat::Op(
|
TKind::LParen => Pat::Op(
|
||||||
PatOp::Tuple,
|
PatOp::Tuple,
|
||||||
p.consume()
|
p.consume()
|
||||||
@@ -384,6 +397,8 @@ impl<'t> Parse<'t> for Ty {
|
|||||||
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::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()? {
|
||||||
@@ -494,7 +509,7 @@ pub enum Ps {
|
|||||||
Lit, // Literal
|
Lit, // Literal
|
||||||
Let, // let Pat = Expr
|
Let, // let Pat = Expr
|
||||||
Const, // const Pat = Expr
|
Const, // const Pat = Expr
|
||||||
Struct, // struct { Pat } | struct ( Pat )
|
Typedef, // struct { Pat } | struct ( Pat )
|
||||||
For, // for Pat in Expr Expr else Expr
|
For, // for Pat in Expr Expr else Expr
|
||||||
Fn, // fn ( Pat,* ) Expr
|
Fn, // fn ( Pat,* ) Expr
|
||||||
Lambda0, // || Expr
|
Lambda0, // || Expr
|
||||||
@@ -528,7 +543,7 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
|||||||
TKind::Module => (Ps::Mod, Prec::Body),
|
TKind::Module => (Ps::Mod, Prec::Body),
|
||||||
TKind::Let => (Ps::Let, Prec::Tuple),
|
TKind::Let => (Ps::Let, Prec::Tuple),
|
||||||
TKind::Const => (Ps::Const, Prec::Body),
|
TKind::Const => (Ps::Const, Prec::Body),
|
||||||
TKind::Struct => (Ps::Struct, Prec::Body),
|
TKind::Struct | TKind::Enum => (Ps::Typedef, 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),
|
||||||
TKind::While => (Ps::Op(Op::While), Prec::Body),
|
TKind::While => (Ps::Op(Op::While), Prec::Body),
|
||||||
@@ -560,7 +575,7 @@ 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::Semi => (Ps::Op(Op::Do), Prec::Do), // the inspiration
|
||||||
TKind::As => (Ps::Op(Op::As), Prec::Body),
|
TKind::As => (Ps::Op(Op::As), Prec::Max),
|
||||||
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
||||||
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
||||||
TKind::AmpAmp => (Ps::Op(Op::LogAnd), Prec::LogAnd),
|
TKind::AmpAmp => (Ps::Op(Op::LogAnd), Prec::LogAnd),
|
||||||
@@ -606,12 +621,16 @@ impl<'t> Parse<'t> for Const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Struct {
|
impl<'t> Parse<'t> for Typedef {
|
||||||
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> {
|
||||||
let value = p.consume().parse(PPrec::Min)?;
|
let tok = p.next()?;
|
||||||
Ok(Self(value))
|
match tok.kind {
|
||||||
|
TKind::Enum => Ok(Self(TypedefKind::Enum, p.parse(PPrec::Alt)?)),
|
||||||
|
TKind::Struct => Ok(Self(TypedefKind::Struct, p.parse(PPrec::Tuple)?)),
|
||||||
|
_ => Err(ParseError::NotType(tok.kind, tok.span)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,7 +856,7 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
Ps::Let => Expr::Let(p.parse(())?),
|
Ps::Let => Expr::Let(p.parse(())?),
|
||||||
Ps::For => parse_for(p, ())?,
|
Ps::For => parse_for(p, ())?,
|
||||||
Ps::Const => Expr::Const(p.parse(())?),
|
Ps::Const => Expr::Const(p.parse(())?),
|
||||||
Ps::Struct => Expr::Struct(p.parse(())?),
|
Ps::Typedef => Expr::Struct(p.parse(())?),
|
||||||
Ps::Match => Expr::Match(p.parse(())?),
|
Ps::Match => Expr::Match(p.parse(())?),
|
||||||
Ps::Mod => Expr::Mod(p.parse(())?),
|
Ps::Mod => Expr::Mod(p.parse(())?),
|
||||||
Ps::Op(Op::Block) => Expr::Op(
|
Ps::Op(Op::Block) => Expr::Op(
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ pub enum TKind {
|
|||||||
Const,
|
Const,
|
||||||
Do,
|
Do,
|
||||||
Else,
|
Else,
|
||||||
|
Enum,
|
||||||
False,
|
False,
|
||||||
Fn,
|
Fn,
|
||||||
For,
|
For,
|
||||||
|
|||||||
Reference in New Issue
Block a user