doughlang: "fix" semi elision, add "fully qualified" paths, add proper pattern prec parsing.
This actually gets some old code parsing!
This commit is contained in:
125
src/ast.rs
125
src/ast.rs
@@ -18,9 +18,19 @@ impl<T: Annotation, A: Annotation> std::fmt::Debug for Anno<T, A> {
|
||||
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 qualified identifier
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct FqPath {
|
||||
// TODO: Identifier interning
|
||||
pub parts: Vec<String>,
|
||||
// TODO:
|
||||
}
|
||||
|
||||
impl From<&str> for FqPath {
|
||||
fn from(value: &str) -> Self {
|
||||
Self { parts: vec![value.to_owned()] }
|
||||
}
|
||||
}
|
||||
|
||||
/// A literal value (boolean, character, integer, string)
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -40,26 +50,37 @@ pub enum Literal {
|
||||
pub enum Pat {
|
||||
/// Matches anything without binding
|
||||
Ignore,
|
||||
/// Matches nothing; used for macro substitution.
|
||||
/// Matches nothing; used for macro substitution
|
||||
MetId(String),
|
||||
/// Matches anything, and binds it to a name
|
||||
Name(String),
|
||||
/// Matches against a named const value
|
||||
Path(FqPath),
|
||||
/// Matches a Struct Expression `Ident { Pat }`
|
||||
Struct(String, Box<Pat>),
|
||||
Struct(FqPath, Box<Pat>),
|
||||
/// Matches a Tuple Struct Expression `Ident ( Pat )`
|
||||
TupStruct(String, Box<Pat>),
|
||||
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`).
|
||||
Rest(Option<Box<Pat>>),
|
||||
TupStruct(FqPath, Box<Pat>),
|
||||
/// Matches a literal value by equality comparison
|
||||
Lit(Literal),
|
||||
/// Matches the elements of a tuple
|
||||
Tuple(Vec<Pat>),
|
||||
/// Matches the elements
|
||||
Slice(Vec<Pat>),
|
||||
/// Matches one of the provided alternates
|
||||
Alt(Vec<Pat>),
|
||||
/// Matches a typed pattern
|
||||
Typed(Box<Pat>, Ty),
|
||||
/// Matches a compound pattern
|
||||
Op(PatOp, Vec<Pat>),
|
||||
}
|
||||
|
||||
/// Operators on lists of patterns
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PatOp {
|
||||
/// Matches a partial decomposition (`..rest`) or upper-bounded range (`..100`)
|
||||
Rest,
|
||||
/// Matches an exclusive bounded range (`0..100`)
|
||||
RangeEx,
|
||||
/// Matches the elements of a tuple
|
||||
Tuple,
|
||||
/// Matches the elements of a slice or array
|
||||
Slice,
|
||||
/// Matches one of a list of alternatives
|
||||
Alt,
|
||||
}
|
||||
|
||||
/// In-universe types
|
||||
@@ -68,7 +89,7 @@ pub enum Ty {
|
||||
/// `_`
|
||||
Infer,
|
||||
/// `(Identifier :: )* Identifier`
|
||||
Named(String),
|
||||
Named(FqPath),
|
||||
/// `(..Tys)`
|
||||
Tuple(Vec<Ty>),
|
||||
/// `[Ty]`
|
||||
@@ -78,11 +99,6 @@ pub enum Ty {
|
||||
/// `[..Args, Rety]`
|
||||
Fn(Vec<Ty>),
|
||||
}
|
||||
impl Default for Ty {
|
||||
fn default() -> Self {
|
||||
Self::Tuple(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// A `let` binding
|
||||
/// ```ignore
|
||||
@@ -148,7 +164,7 @@ pub struct Struct(pub Pat);
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Expr<A: Annotation = Span> {
|
||||
/// An identifier
|
||||
Id(String),
|
||||
Id(FqPath),
|
||||
/// A meta-identifier
|
||||
MetId(String),
|
||||
/// A literal bool, string, char, or int
|
||||
@@ -197,11 +213,7 @@ impl<A: Annotation> Expr<A> {
|
||||
pub fn is_place(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Id(_)
|
||||
| Self::Op(Op::Index, _)
|
||||
| Self::Op(Op::Dot, _)
|
||||
| Self::Op(Op::Path, _)
|
||||
| Self::Op(Op::Deref, _)
|
||||
Self::Id(_) | Self::Op(Op::Index, _) | Self::Op(Op::Dot, _) | Self::Op(Op::Deref, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -237,8 +249,7 @@ pub enum Op {
|
||||
Break, // break Expr
|
||||
Return, // return Expr
|
||||
|
||||
Dot, // Expr . Expr
|
||||
Path, // Expr :: Expr
|
||||
Dot, // Expr . Expr
|
||||
|
||||
RangeEx, // Expr? ..Expr
|
||||
RangeIn, // Expr? ..=Expr
|
||||
@@ -290,6 +301,13 @@ impl Display for Literal {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FqPath {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { parts } = self;
|
||||
f.list(parts, "::")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display + Annotation, A: Annotation> Display for Anno<T, A> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
@@ -351,7 +369,7 @@ impl Display for Struct {
|
||||
let Self(pat) = self;
|
||||
match pat {
|
||||
Pat::Struct(name, bind) => match bind.as_ref() {
|
||||
Pat::Tuple(parts) => f
|
||||
Pat::Op(PatOp::Tuple, parts) => f
|
||||
.delimit_indented(fmt!("struct {name} {{"), "}")
|
||||
.list_wrap("\n", parts, ",\n", ",\n"),
|
||||
other => write!(f, "{name} {{ {other} }}"),
|
||||
@@ -431,7 +449,6 @@ impl Display for Op {
|
||||
Op::Break => "break ".fmt(f),
|
||||
Op::Return => "return ".fmt(f),
|
||||
Op::Dot => ".".fmt(f),
|
||||
Op::Path => "::".fmt(f),
|
||||
Op::RangeEx => "..".fmt(f),
|
||||
Op::RangeIn => "..=".fmt(f),
|
||||
Op::Neg => "-".fmt(f),
|
||||
@@ -486,17 +503,23 @@ impl Display for Pat {
|
||||
Self::Lit(literal) => literal.fmt(f),
|
||||
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() {
|
||||
Pat::Tuple(parts) => f.delimit(fmt!("{name} {{"), "}").list(parts, ", "),
|
||||
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::Rest(Some(rest)) => write!(f, "..{rest}"),
|
||||
Self::Rest(None) => write!(f, ".."),
|
||||
Self::Tuple(pats) => f.delimit("(", ")").list(pats, ", "),
|
||||
Self::Slice(pats) => f.delimit("[", "]").list(pats, ", "),
|
||||
Self::Alt(pats) => f.delimit("<", ">").list(pats, " | "),
|
||||
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::Slice, pats) => f.delimit("[", "]").list(pats, ", "),
|
||||
Self::Op(PatOp::Alt, pats) => f.delimit("<", ">").list(pats, " | "),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,21 +547,35 @@ impl<A: Annotation> TryFrom<Expr<A>> for Pat {
|
||||
|
||||
fn try_from(value: Expr<A>) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
Expr::Id(name) if name == "_" => Self::Ignore,
|
||||
Expr::Id(name) => Self::Name(name),
|
||||
Expr::Id(FqPath { mut parts }) if parts.len() == 1 => {
|
||||
match parts.pop().expect("parts should have len 1") {
|
||||
ig if ig == "_" => Self::Ignore,
|
||||
name => Self::Name(name),
|
||||
}
|
||||
}
|
||||
Expr::Id(path) => Self::Path(path),
|
||||
Expr::MetId(name) => Self::MetId(name),
|
||||
Expr::Lit(literal) => Self::Lit(literal),
|
||||
Expr::Op(Op::RangeEx, exprs) if exprs.is_empty() => Self::Rest(None),
|
||||
Expr::Op(Op::RangeEx, mut exprs) if exprs.len() == 1 => {
|
||||
Self::Rest(Some(Box::new(Self::try_from(exprs.remove(0))?)))
|
||||
}
|
||||
Expr::Op(Op::Tuple, exprs) => Self::Tuple(
|
||||
Expr::Op(Op::RangeEx, exprs) => Self::Op(
|
||||
if exprs.len() > 1 {
|
||||
PatOp::RangeEx
|
||||
} else {
|
||||
PatOp::Rest
|
||||
},
|
||||
exprs
|
||||
.into_iter()
|
||||
.map(Self::try_from)
|
||||
.collect::<Result<Vec<_>, Expr<A>>>()?,
|
||||
),
|
||||
Expr::Op(Op::Tuple, exprs) => Self::Op(
|
||||
PatOp::Tuple,
|
||||
exprs
|
||||
.into_iter()
|
||||
.map(Self::try_from)
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
Expr::Op(Op::Array, exprs) => Self::Slice(
|
||||
Expr::Op(Op::Array, exprs) => Self::Op(
|
||||
PatOp::Slice,
|
||||
exprs
|
||||
.into_iter()
|
||||
.map(Self::try_from)
|
||||
|
||||
Reference in New Issue
Block a user