ast: struct
This commit is contained in:
parent
bcabbcd39d
commit
222b2d7b98
21
src/ast.rs
21
src/ast.rs
@ -32,6 +32,10 @@ pub enum Pat {
|
|||||||
MetId(String),
|
MetId(String),
|
||||||
/// Matches anything, and binds it to a name
|
/// Matches anything, and binds it to a name
|
||||||
Name(String),
|
Name(String),
|
||||||
|
/// Matches a Struct Expression `Ident { Pat }`
|
||||||
|
Struct(String, Box<Pat>),
|
||||||
|
/// Matches a Tuple Struct Expression `Ident ( Pat )`
|
||||||
|
TupStruct(String, Box<Pat>),
|
||||||
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`).
|
/// 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
|
/// Matches a literal value by equality comparison
|
||||||
@ -119,6 +123,11 @@ 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>);
|
||||||
|
|
||||||
|
/// A record-type definition
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Struct(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> {
|
||||||
@ -132,6 +141,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(Box<Struct>),
|
||||||
/// `| 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)?),* }
|
||||||
@ -298,6 +309,13 @@ impl<A: Annotation> Display for Mod<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Struct {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self(pat) = self;
|
||||||
|
write!(f, "struct {pat}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Annotation> Display for Expr<A> {
|
impl<A: Annotation> Display for Expr<A> {
|
||||||
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 {
|
||||||
@ -306,6 +324,7 @@ impl<A: Annotation> Display for Expr<A> {
|
|||||||
Self::Lit(literal) => literal.fmt(f),
|
Self::Lit(literal) => literal.fmt(f),
|
||||||
Self::Let(v) => v.fmt(f),
|
Self::Let(v) => v.fmt(f),
|
||||||
Self::Const(v) => v.fmt(f),
|
Self::Const(v) => v.fmt(f),
|
||||||
|
Self::Struct(v) => v.fmt(f),
|
||||||
Self::Make(v) => v.fmt(f),
|
Self::Make(v) => v.fmt(f),
|
||||||
Self::Match(v) => v.fmt(f),
|
Self::Match(v) => v.fmt(f),
|
||||||
Self::Mod(v) => v.fmt(f),
|
Self::Mod(v) => v.fmt(f),
|
||||||
@ -419,6 +438,8 @@ impl Display for Pat {
|
|||||||
Self::Lit(literal) => literal.fmt(f),
|
Self::Lit(literal) => literal.fmt(f),
|
||||||
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::Struct(name, bind) => write!(f, "{name} {{{bind}}}"),
|
||||||
|
Self::TupStruct(name, bind) => write!(f, "{name} {bind}"),
|
||||||
Self::Rest(Some(rest)) => write!(f, "..{rest}"),
|
Self::Rest(Some(rest)) => write!(f, "..{rest}"),
|
||||||
Self::Rest(None) => write!(f, ".."),
|
Self::Rest(None) => write!(f, ".."),
|
||||||
Self::Tuple(pats) => f.delimit("(", ")").list(pats, ", "),
|
Self::Tuple(pats) => f.delimit("(", ")").list(pats, ", "),
|
||||||
|
@ -159,6 +159,18 @@ impl<A: Annotation> Match<A> for Mod<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Match<A> for Struct {
|
||||||
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
|
let (Self(pat_pat), Self(expr_pat)) = (pat, expr);
|
||||||
|
Match::recurse(sub, pat_pat, expr_pat)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, sub: &Subst<A>) {
|
||||||
|
let Self(pat) = self;
|
||||||
|
pat.apply(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Annotation> Match<A> for Expr<A> {
|
impl<A: Annotation> Match<A> for Expr<A> {
|
||||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||||
match (pat, expr) {
|
match (pat, expr) {
|
||||||
@ -172,6 +184,8 @@ impl<A: Annotation> Match<A> for Expr<A> {
|
|||||||
(Expr::Let(..), _) => false,
|
(Expr::Let(..), _) => false,
|
||||||
(Expr::Const(pat), Expr::Const(expr)) => Match::recurse(sub, pat, expr),
|
(Expr::Const(pat), Expr::Const(expr)) => Match::recurse(sub, pat, expr),
|
||||||
(Expr::Const(..), _) => false,
|
(Expr::Const(..), _) => false,
|
||||||
|
(Expr::Struct(pat), Expr::Struct(expr)) => Match::recurse(sub, pat, expr),
|
||||||
|
(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::Match(pat), Expr::Match(expr)) => Match::recurse(sub, pat, expr),
|
(Expr::Match(pat), Expr::Match(expr)) => Match::recurse(sub, pat, expr),
|
||||||
@ -197,6 +211,7 @@ impl<A: Annotation> Match<A> for Expr<A> {
|
|||||||
Expr::Id(_) | Expr::Lit(_) => {}
|
Expr::Id(_) | Expr::Lit(_) => {}
|
||||||
Expr::Let(expr) => expr.apply(sub),
|
Expr::Let(expr) => expr.apply(sub),
|
||||||
Expr::Const(expr) => expr.apply(sub),
|
Expr::Const(expr) => expr.apply(sub),
|
||||||
|
Expr::Struct(expr) => expr.apply(sub),
|
||||||
Expr::Make(expr) => expr.apply(sub),
|
Expr::Make(expr) => expr.apply(sub),
|
||||||
Expr::Match(expr) => expr.apply(sub),
|
Expr::Match(expr) => expr.apply(sub),
|
||||||
Expr::Mod(expr) => expr.apply(sub),
|
Expr::Mod(expr) => expr.apply(sub),
|
||||||
@ -242,6 +257,10 @@ impl<A: Annotation> Match<A> for Pat {
|
|||||||
(Pat::Ignore, _) => false,
|
(Pat::Ignore, _) => false,
|
||||||
(Pat::Name(pat), Pat::Name(expr)) => pat == expr,
|
(Pat::Name(pat), Pat::Name(expr)) => pat == expr,
|
||||||
(Pat::Name(_), _) => false,
|
(Pat::Name(_), _) => false,
|
||||||
|
(Pat::Struct(_, pat), Pat::Struct(_, expr)) => Match::recurse(sub, pat, expr),
|
||||||
|
(Pat::Struct(..), _) => false,
|
||||||
|
(Pat::TupStruct(_, pat), Pat::TupStruct(_, expr)) => Match::recurse(sub, pat, expr),
|
||||||
|
(Pat::TupStruct(..), _) => false,
|
||||||
(Pat::Rest(pat), Pat::Rest(expr)) => Match::recurse(sub, pat, expr),
|
(Pat::Rest(pat), Pat::Rest(expr)) => Match::recurse(sub, pat, expr),
|
||||||
(Pat::Rest(_), _) => false,
|
(Pat::Rest(_), _) => false,
|
||||||
(Pat::Lit(pat), Pat::Lit(expr)) => pat == expr,
|
(Pat::Lit(pat), Pat::Lit(expr)) => pat == expr,
|
||||||
@ -265,6 +284,8 @@ impl<A: Annotation> Match<A> for Pat {
|
|||||||
*self = expr.clone()
|
*self = expr.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Pat::Struct(_, expr) => expr.apply(sub),
|
||||||
|
Pat::TupStruct(_, expr) => expr.apply(sub),
|
||||||
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),
|
||||||
|
@ -235,6 +235,7 @@ impl<'t> Lexer<'t> {
|
|||||||
"mod" => TKind::Module,
|
"mod" => TKind::Module,
|
||||||
"pub" => TKind::Public,
|
"pub" => TKind::Public,
|
||||||
"return" => TKind::Return,
|
"return" => TKind::Return,
|
||||||
|
"struct" => TKind::Struct,
|
||||||
"then" => TKind::Do,
|
"then" => TKind::Do,
|
||||||
"true" => TKind::True,
|
"true" => TKind::True,
|
||||||
"while" => TKind::While,
|
"while" => TKind::While,
|
||||||
|
@ -100,7 +100,7 @@ fn exprs() -> Result<(), Box<dyn Error>> {
|
|||||||
println!("\x1b[31m{e}\x1b[0m");
|
println!("\x1b[31m{e}\x1b[0m");
|
||||||
break Ok(Response::Deny);
|
break Ok(Response::Deny);
|
||||||
}
|
}
|
||||||
Ok(v) => println!("{v}\n{v:#?}"),
|
Ok(v) => println!("{v}\n{v:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
@ -248,7 +248,19 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
}
|
}
|
||||||
TKind::Identifier => match tok.lexeme.as_str() {
|
TKind::Identifier => match tok.lexeme.as_str() {
|
||||||
"_" => p.consume().then(Pat::Ignore),
|
"_" => p.consume().then(Pat::Ignore),
|
||||||
_ => Pat::Name(p.take_lexeme().expect("should have Token")),
|
_ => {
|
||||||
|
let name = p.take_lexeme().expect("should have Token");
|
||||||
|
match p.peek().map(|t| t.kind)? {
|
||||||
|
TKind::LParen => Pat::TupStruct(name, p.parse(PPrec::Tuple)?),
|
||||||
|
TKind::LCurly => Pat::Struct(
|
||||||
|
name,
|
||||||
|
p.consume()
|
||||||
|
.opt(PPrec::Tuple, TKind::RCurly)?
|
||||||
|
.unwrap_or_else(|| Box::new(Pat::Tuple(vec![]))),
|
||||||
|
),
|
||||||
|
_ => Pat::Name(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
TKind::Grave => Pat::MetId(p.consume().next()?.lexeme),
|
TKind::Grave => Pat::MetId(p.consume().next()?.lexeme),
|
||||||
TKind::DotDot => Pat::Rest(match p.consume().peek_if(TKind::Identifier) {
|
TKind::DotDot => Pat::Rest(match p.consume().peek_if(TKind::Identifier) {
|
||||||
@ -258,13 +270,13 @@ impl<'t> Parse<'t> for Pat {
|
|||||||
TKind::LParen => {
|
TKind::LParen => {
|
||||||
Pat::Tuple(
|
Pat::Tuple(
|
||||||
p.consume()
|
p.consume()
|
||||||
.list(vec![], PPrec::Max, TKind::Comma, TKind::RParen)?,
|
.list(vec![], PPrec::Typed, TKind::Comma, TKind::RParen)?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TKind::LBrack => {
|
TKind::LBrack => {
|
||||||
Pat::Slice(
|
Pat::Slice(
|
||||||
p.consume()
|
p.consume()
|
||||||
.list(vec![], PPrec::Max, TKind::Comma, TKind::RBrack)?,
|
.list(vec![], PPrec::Typed, TKind::Comma, TKind::RBrack)?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => Err(ParseError::NotPattern(tok.kind, tok.span))?,
|
_ => Err(ParseError::NotPattern(tok.kind, tok.span))?,
|
||||||
@ -415,6 +427,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 )
|
||||||
Fn, // fn ( Pat,* ) Expr
|
Fn, // fn ( Pat,* ) Expr
|
||||||
Lambda0, // || Expr
|
Lambda0, // || Expr
|
||||||
Lambda, // | Pat,* | Expr
|
Lambda, // | Pat,* | Expr
|
||||||
@ -444,6 +457,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::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),
|
||||||
@ -521,15 +535,27 @@ impl<'t> Parse<'t> for Const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'t> Parse<'t> for Struct {
|
||||||
|
type Prec = ();
|
||||||
|
|
||||||
|
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||||
|
let value = p.consume().parse(PPrec::Tuple)?;
|
||||||
|
Ok(Self(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'t> Parse<'t> for Fn {
|
impl<'t> Parse<'t> for Fn {
|
||||||
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> {
|
||||||
Ok(Self(
|
match p.consume().next_if(TKind::Identifier) {
|
||||||
p.consume()
|
Ok(Token { lexeme, .. }) => Ok(Self(
|
||||||
.next_if(TKind::Identifier)
|
Some(lexeme),
|
||||||
.map(|id| id.lexeme)
|
p.parse(PPrec::Typed)?,
|
||||||
.ok(),
|
p.parse(Prec::Body.next())?,
|
||||||
|
)),
|
||||||
|
_ => Ok(Self(
|
||||||
|
None,
|
||||||
Pat::Tuple(p.consume_if(TKind::LParen)?.list(
|
Pat::Tuple(p.consume_if(TKind::LParen)?.list(
|
||||||
vec![],
|
vec![],
|
||||||
PPrec::Tuple,
|
PPrec::Tuple,
|
||||||
@ -537,7 +563,8 @@ impl<'t> Parse<'t> for Fn {
|
|||||||
TKind::RParen,
|
TKind::RParen,
|
||||||
)?),
|
)?),
|
||||||
p.parse(Prec::Body.next())?,
|
p.parse(Prec::Body.next())?,
|
||||||
))
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,6 +644,7 @@ impl<'t> Parse<'t> for Expr {
|
|||||||
Ps::Lit => Expr::Lit(p.parse(())?),
|
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||||
Ps::Let => Expr::Let(p.parse(())?),
|
Ps::Let => Expr::Let(p.parse(())?),
|
||||||
Ps::Const => Expr::Const(p.parse(())?),
|
Ps::Const => Expr::Const(p.parse(())?),
|
||||||
|
Ps::Struct => 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(
|
||||||
|
@ -27,6 +27,7 @@ pub enum TKind {
|
|||||||
Module,
|
Module,
|
||||||
Public,
|
Public,
|
||||||
Return,
|
Return,
|
||||||
|
Struct,
|
||||||
True,
|
True,
|
||||||
While,
|
While,
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user