#[derive(Debug, Clone)]
pub struct Program {
pub items: Vec<Item>,
}
#[derive(Debug, Clone)]
pub enum Item {
Fn(FnDef),
Type(TypeDef),
Let {
pattern: Pattern,
expr: Expr,
exported: bool,
line: u32,
},
Expr(Expr),
Import(ImportDef),
Extern {
name: String,
params: Vec<String>,
line: u32,
},
ExternLet {
name: String,
line: u32,
},
}
#[derive(Debug, Clone)]
pub struct FnDef {
pub name: String,
pub params: Vec<Pattern>,
pub body: Expr,
pub exported: bool,
pub attrs: Vec<String>,
pub line: u32,
}
#[derive(Debug, Clone)]
pub struct ImportDef {
pub path: String,
pub kind: ImportKind,
pub line: u32,
}
#[derive(Debug, Clone)]
pub enum ImportKind {
Named(Vec<(String, Option<String>)>),
Qualified(Option<String>),
}
#[derive(Debug, Clone)]
pub struct TypeDef {
pub name: String,
pub variants: Vec<VariantDef>,
pub line: u32,
}
#[derive(Debug, Clone)]
pub struct VariantDef {
pub tag: String,
pub fields: Option<Vec<String>>,
}
#[derive(Debug, Clone)]
pub enum Stmt {
Let {
mutable: bool,
pattern: Pattern,
expr: Expr,
line: u32,
},
Assign {
name: String,
expr: Expr,
line: u32,
},
While {
cond: Expr,
body: Expr,
line: u32,
},
For {
pattern: Pattern,
iter: Expr,
body: Expr,
line: u32,
},
Return {
expr: Option<Expr>,
line: u32,
},
Break {
line: u32,
},
Continue {
line: u32,
},
Expr(Expr),
}
#[derive(Debug, Clone)]
pub struct Expr {
pub kind: ExprKind,
pub line: u32,
}
#[derive(Debug, Clone)]
pub enum ExprKind {
Unit,
Bool(bool),
Int(i64),
Float(f64),
Str(String),
Interp(Vec<InterpPart>),
Ident(String),
Variant {
tag: String,
payload: VariantCtor,
},
List(Vec<Expr>),
Tuple(Vec<Expr>),
Record {
spread: Option<Box<Expr>>,
fields: Vec<(String, Expr)>,
},
Lambda {
params: Vec<Pattern>,
body: Box<Expr>,
},
Call {
callee: Box<Expr>,
args: Vec<Expr>,
},
MethodCall {
recv: Box<Expr>,
name: String,
args: Vec<Expr>,
},
Field {
recv: Box<Expr>,
name: String,
},
Index {
recv: Box<Expr>,
index: Box<Expr>,
},
Unary {
op: UnOp,
operand: Box<Expr>,
},
Binary {
op: BinOp,
lhs: Box<Expr>,
rhs: Box<Expr>,
},
And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>),
Range {
lo: Box<Expr>,
hi: Box<Expr>,
inclusive: bool,
},
If {
cond: Box<Expr>,
then: Box<Expr>,
els: Option<Box<Expr>>,
},
Match {
subject: Box<Expr>,
arms: Vec<Arm>,
},
Block(Vec<Stmt>, Option<Box<Expr>>),
Try(Box<Expr>),
Deref(Box<Expr>),
}
#[derive(Debug, Clone)]
pub enum InterpPart {
Lit(String),
Expr(Expr),
}
#[derive(Debug, Clone)]
pub enum VariantCtor {
Unit,
Positional(Vec<Expr>),
Named(Vec<(String, Expr)>),
}
#[derive(Debug, Clone)]
pub struct Arm {
pub pattern: Pattern,
pub guard: Option<Expr>,
pub body: Expr,
pub line: u32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UnOp {
Neg,
Not,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Mod,
Pow,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
#[derive(Debug, Clone)]
pub enum Pattern {
Wildcard,
Bind(String),
LitInt(i64),
LitFloat(f64),
LitStr(String),
LitBool(bool),
LitUnit,
VariantPos {
tag: String,
items: Vec<Pattern>,
},
VariantNamed {
tag: String,
fields: Vec<(String, Pattern)>,
rest: bool,
},
Record {
fields: Vec<(String, Pattern)>,
rest: bool,
},
Tuple(Vec<Pattern>),
List {
items: Vec<Pattern>,
rest: Option<Option<String>>,
},
Range {
lo: i64,
hi: i64,
inclusive: bool,
},
Or(Vec<Pattern>),
As(Box<Pattern>, String),
}
impl Pattern {
pub fn bound_names(&self, out: &mut Vec<String>) {
match self {
Pattern::Wildcard
| Pattern::LitInt(_)
| Pattern::LitFloat(_)
| Pattern::LitStr(_)
| Pattern::LitBool(_)
| Pattern::LitUnit
| Pattern::Range { .. } => {}
Pattern::Bind(n) => {
if !out.contains(n) {
out.push(n.clone());
}
}
Pattern::VariantPos { items, .. } | Pattern::Tuple(items) => {
for p in items {
p.bound_names(out);
}
}
Pattern::VariantNamed { fields, .. } | Pattern::Record { fields, .. } => {
for (_, p) in fields {
p.bound_names(out);
}
}
Pattern::List { items, rest } => {
for p in items {
p.bound_names(out);
}
if let Some(Some(n)) = rest {
if !out.contains(n) {
out.push(n.clone());
}
}
}
Pattern::Or(alts) => {
if let Some(first) = alts.first() {
first.bound_names(out);
}
}
Pattern::As(inner, name) => {
inner.bound_names(out);
if !out.contains(name) {
out.push(name.clone());
}
}
}
}
}