doughlang: let else, fn rety
ast: - `let Pat (= Expr (else Expr)?)?`, - `fn (args) -> Ty`, coagulating `do`, `if/while` formatting fixes parser: - int cleanup, - fn rety parsing, - experimental `for` desugar, - experimental semicolon elision (TODO: it sucks), - let-else parsing - `do` coagulation impl (still not 100% there) TODO: - Fix `do` coagulation - codify `do` elision rules - `for` needs lib support - this is fine because we have no codegen yet - Ty matching in macro_matcher - Or rip out macro_matcher? Who knows what the future holds.
This commit is contained in:
63
src/ast.rs
63
src/ast.rs
@@ -3,13 +3,25 @@
|
||||
pub mod macro_matcher;
|
||||
|
||||
/// A value with an annotation.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Anno<T: Annotation, A: Annotation = Span>(pub T, pub A);
|
||||
|
||||
impl<T: Annotation, A: Annotation> std::fmt::Debug for Anno<T, A> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
<A as std::fmt::Debug>::fmt(&self.1, f)?;
|
||||
f.write_str(": ")?;
|
||||
<T as std::fmt::Debug>::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// An annotation: extra data added on to important AST nodes.
|
||||
pub trait Annotation: Clone + std::fmt::Display + std::fmt::Debug + PartialEq + Eq {}
|
||||
impl<T: Clone + std::fmt::Debug + std::fmt::Display + PartialEq + Eq> Annotation for T {}
|
||||
|
||||
//
|
||||
// TODO: Identifier interning
|
||||
//
|
||||
|
||||
/// A literal value (boolean, character, integer, string)
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Literal {
|
||||
@@ -18,7 +30,7 @@ pub enum Literal {
|
||||
/// A character literal: 'a', '\u{1f988}'
|
||||
Char(char),
|
||||
/// An integer literal: 0, 123, 0x10
|
||||
Int(i128),
|
||||
Int(u128),
|
||||
/// A string literal:
|
||||
Str(String),
|
||||
}
|
||||
@@ -66,13 +78,18 @@ pub enum Ty {
|
||||
/// `[..Args, Rety]`
|
||||
Fn(Vec<Ty>),
|
||||
}
|
||||
impl Default for Ty {
|
||||
fn default() -> Self {
|
||||
Self::Tuple(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// A `let` binding
|
||||
/// ```ignore
|
||||
/// let Pat (= Expr)?
|
||||
/// ``````
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Let<A: Annotation = Span>(pub Pat, pub Option<Anno<Expr<A>, A>>);
|
||||
pub struct Let<A: Annotation = Span>(pub Pat, pub Vec<Anno<Expr<A>, A>>);
|
||||
|
||||
/// A `const` binding (which defines its name before executing)
|
||||
/// ```ignore
|
||||
@@ -86,7 +103,7 @@ pub struct Const<A: Annotation = Span>(pub Pat, pub Anno<Expr<A>, A>);
|
||||
/// fn Ident? (Pat) Expr
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Fn<A: Annotation = Span>(pub Option<String>, pub Pat, pub Anno<Expr<A>, A>);
|
||||
pub struct Fn<A: Annotation = Span>(pub Option<String>, pub Pat, pub Ty, pub Anno<Expr<A>, A>);
|
||||
|
||||
/// A match expression
|
||||
/// ```ignore
|
||||
@@ -107,7 +124,7 @@ pub struct MatchArm<A: Annotation = Span>(pub Pat, pub Anno<Expr<A>, A>);
|
||||
/// Expr { (Ident (: Expr)?),* }
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Make<A: Annotation = Span>(pub Box<Anno<Expr<A>, A>>, pub Vec<MakeArm<A>>);
|
||||
pub struct Make<A: Annotation = Span>(pub Anno<Expr<A>, A>, pub Vec<MakeArm<A>>);
|
||||
|
||||
/// A single "arm" of a make expression
|
||||
/// ```ignore
|
||||
@@ -154,11 +171,29 @@ pub enum Expr<A: Annotation = Span> {
|
||||
Op(Op, Vec<Anno<Self, A>>),
|
||||
}
|
||||
|
||||
impl<A: Annotation> Default for Expr<A> {
|
||||
fn default() -> Self {
|
||||
Self::Op(Op::Tuple, vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation> Expr<A> {
|
||||
pub fn anno(self, annotation: A) -> Anno<Expr<A>, A> {
|
||||
Anno(self, annotation)
|
||||
}
|
||||
|
||||
pub fn and_do(self, annotation: A, other: Anno<Expr<A>, A>) -> Self {
|
||||
let Self::Op(Op::Do, mut exprs) = self else {
|
||||
return Self::Op(Op::Do, vec![self.anno(annotation), other]);
|
||||
};
|
||||
let Anno(Self::Op(Op::Do, mut other), _) = other else {
|
||||
exprs.push(other);
|
||||
return Self::Op(Op::Do, exprs);
|
||||
};
|
||||
exprs.append(&mut other);
|
||||
Self::Op(Op::Do, exprs)
|
||||
}
|
||||
|
||||
pub fn is_place(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
@@ -271,17 +306,20 @@ impl<A: Annotation> Display for Const<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, expr) => write!(f, "fn {name} {pat} {expr}"),
|
||||
Self(None, pat, expr) => write!(f, "|{pat}| {expr}"),
|
||||
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 Let<A> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self(pat, Some(expr)) => write!(f, "let {pat} = {expr}"),
|
||||
Self(pat, None) => write!(f, "let ({pat})"),
|
||||
let Self(pat, exprs) = self;
|
||||
match exprs.as_slice() {
|
||||
[] => write!(f, "let {pat}"),
|
||||
[value] => write!(f, "let {pat} = {value}"),
|
||||
[value, fail] => write!(f, "let {pat} = {value} else {fail}"),
|
||||
other => f.delimit(fmt!("let! {pat} ("), ")").list(other, ", "),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +352,7 @@ impl Display for Struct {
|
||||
match pat {
|
||||
Pat::Struct(name, bind) => match bind.as_ref() {
|
||||
Pat::Tuple(parts) => f
|
||||
.delimit_indented(fmt!("{name} {{"), "}")
|
||||
.delimit_indented(fmt!("struct {name} {{"), "}")
|
||||
.list_wrap("\n", parts, ",\n", ",\n"),
|
||||
other => write!(f, "{name} {{ {other} }}"),
|
||||
},
|
||||
@@ -338,6 +376,9 @@ impl<A: Annotation> Display for Expr<A> {
|
||||
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() => {
|
||||
write!(f, "{op}{cond} {pass}")
|
||||
}
|
||||
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
||||
other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user