cl-ast: Add Fold and Visit traits, to more easily map or collect nodes in the AST
typeck.rs: Since this is apparently my testbed now, add a new mode. TODO: replace the main `conlang` binary with this, since it's so much better.
This commit is contained in:
parent
de024b6cb7
commit
01ffdb67a6
8
cl-ast/src/ast_visitor.rs
Normal file
8
cl-ast/src/ast_visitor.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//! Contains an [immutable visitor](Visit) and an [owned folder](Fold) trait,
|
||||
//! with default implementations across the entire AST
|
||||
|
||||
pub mod fold;
|
||||
pub mod visit;
|
||||
|
||||
pub use fold::Fold;
|
||||
pub use visit::Visit;
|
493
cl-ast/src/ast_visitor/fold.rs
Normal file
493
cl-ast/src/ast_visitor/fold.rs
Normal file
@ -0,0 +1,493 @@
|
||||
//! A folder (implementer of the [Fold] trait) maps ASTs to ASTs
|
||||
|
||||
use crate::ast::*;
|
||||
use cl_structures::span::Span;
|
||||
|
||||
/// Deconstructs the entire AST, and reconstructs it from scratch.
|
||||
///
|
||||
/// Each method acts as a customization point.
|
||||
///
|
||||
/// There are a set of default implementations for enums
|
||||
/// under the name [`or_fold_`*](or_fold_expr_kind),
|
||||
/// provided for ease of use.
|
||||
///
|
||||
/// For all other nodes, traversal is *explicit*.
|
||||
pub trait Fold {
|
||||
fn fold_span(&mut self, extents: Span) -> Span {
|
||||
extents
|
||||
}
|
||||
fn fold_mutability(&mut self, mutability: Mutability) -> Mutability {
|
||||
mutability
|
||||
}
|
||||
fn fold_visibility(&mut self, visibility: Visibility) -> Visibility {
|
||||
visibility
|
||||
}
|
||||
fn fold_identifier(&mut self, ident: Identifier) -> Identifier {
|
||||
ident
|
||||
}
|
||||
fn fold_literal(&mut self, lit: Literal) -> Literal {
|
||||
or_fold_literal(self, lit)
|
||||
}
|
||||
fn fold_bool(&mut self, b: bool) -> bool {
|
||||
b
|
||||
}
|
||||
fn fold_char(&mut self, c: char) -> char {
|
||||
c
|
||||
}
|
||||
fn fold_int(&mut self, i: u128) -> u128 {
|
||||
i
|
||||
}
|
||||
fn fold_string(&mut self, s: String) -> String {
|
||||
s
|
||||
}
|
||||
fn fold_file(&mut self, f: File) -> File {
|
||||
let File { items } = f;
|
||||
File { items: items.into_iter().map(|i| self.fold_item(i)).collect() }
|
||||
}
|
||||
fn fold_attrs(&mut self, a: Attrs) -> Attrs {
|
||||
let Attrs { meta } = a;
|
||||
Attrs { meta: meta.into_iter().map(|m| self.fold_meta(m)).collect() }
|
||||
}
|
||||
fn fold_meta(&mut self, m: Meta) -> Meta {
|
||||
let Meta { name, kind } = m;
|
||||
Meta { name: self.fold_identifier(name), kind: self.fold_meta_kind(kind) }
|
||||
}
|
||||
fn fold_meta_kind(&mut self, kind: MetaKind) -> MetaKind {
|
||||
or_fold_meta_kind(self, kind)
|
||||
}
|
||||
fn fold_item(&mut self, i: Item) -> Item {
|
||||
let Item { extents, attrs, vis, kind } = i;
|
||||
Item {
|
||||
extents: self.fold_span(extents),
|
||||
attrs: self.fold_attrs(attrs),
|
||||
vis: self.fold_visibility(vis),
|
||||
kind: self.fold_item_kind(kind),
|
||||
}
|
||||
}
|
||||
fn fold_item_kind(&mut self, kind: ItemKind) -> ItemKind {
|
||||
or_fold_item_kind(self, kind)
|
||||
}
|
||||
fn fold_alias(&mut self, a: Alias) -> Alias {
|
||||
let Alias { to, from } = a;
|
||||
Alias { to: self.fold_identifier(to), from: from.map(|from| Box::new(self.fold_ty(*from))) }
|
||||
}
|
||||
fn fold_const(&mut self, c: Const) -> Const {
|
||||
let Const { name, ty, init } = c;
|
||||
Const {
|
||||
name: self.fold_identifier(name),
|
||||
ty: Box::new(self.fold_ty(*ty)),
|
||||
init: Box::new(self.fold_expr(*init)),
|
||||
}
|
||||
}
|
||||
fn fold_static(&mut self, s: Static) -> Static {
|
||||
let Static { mutable, name, ty, init } = s;
|
||||
Static {
|
||||
mutable: self.fold_mutability(mutable),
|
||||
name: self.fold_identifier(name),
|
||||
ty: Box::new(self.fold_ty(*ty)),
|
||||
init: Box::new(self.fold_expr(*init)),
|
||||
}
|
||||
}
|
||||
fn fold_module(&mut self, m: Module) -> Module {
|
||||
let Module { name, kind } = m;
|
||||
Module { name: self.fold_identifier(name), kind: self.fold_module_kind(kind) }
|
||||
}
|
||||
fn fold_module_kind(&mut self, m: ModuleKind) -> ModuleKind {
|
||||
match m {
|
||||
ModuleKind::Inline(f) => ModuleKind::Inline(self.fold_file(f)),
|
||||
ModuleKind::Outline => ModuleKind::Outline,
|
||||
}
|
||||
}
|
||||
fn fold_function(&mut self, f: Function) -> Function {
|
||||
let Function { name, sign, bind, body } = f;
|
||||
Function {
|
||||
name: self.fold_identifier(name),
|
||||
sign: self.fold_ty_fn(sign),
|
||||
bind: bind.into_iter().map(|p| self.fold_param(p)).collect(),
|
||||
body: body.map(|b| self.fold_block(b)),
|
||||
}
|
||||
}
|
||||
fn fold_param(&mut self, p: Param) -> Param {
|
||||
let Param { mutability, name } = p;
|
||||
Param { mutability: self.fold_mutability(mutability), name: self.fold_identifier(name) }
|
||||
}
|
||||
fn fold_struct(&mut self, s: Struct) -> Struct {
|
||||
let Struct { name, kind } = s;
|
||||
Struct { name: self.fold_identifier(name), kind: self.fold_struct_kind(kind) }
|
||||
}
|
||||
fn fold_struct_kind(&mut self, kind: StructKind) -> StructKind {
|
||||
match kind {
|
||||
StructKind::Empty => StructKind::Empty,
|
||||
StructKind::Tuple(tys) => {
|
||||
StructKind::Tuple(tys.into_iter().map(|t| self.fold_ty(t)).collect())
|
||||
}
|
||||
StructKind::Struct(mem) => StructKind::Struct(
|
||||
mem.into_iter()
|
||||
.map(|m| self.fold_struct_member(m))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
fn fold_struct_member(&mut self, m: StructMember) -> StructMember {
|
||||
let StructMember { vis, name, ty } = m;
|
||||
StructMember {
|
||||
vis: self.fold_visibility(vis),
|
||||
name: self.fold_identifier(name),
|
||||
ty: self.fold_ty(ty),
|
||||
}
|
||||
}
|
||||
fn fold_enum(&mut self, e: Enum) -> Enum {
|
||||
let Enum { name, kind } = e;
|
||||
Enum { name: self.fold_identifier(name), kind: self.fold_enum_kind(kind) }
|
||||
}
|
||||
fn fold_enum_kind(&mut self, kind: EnumKind) -> EnumKind {
|
||||
or_fold_enum_kind(self, kind)
|
||||
}
|
||||
fn fold_variant(&mut self, v: Variant) -> Variant {
|
||||
let Variant { name, kind } = v;
|
||||
|
||||
Variant { name: self.fold_identifier(name), kind: self.fold_variant_kind(kind) }
|
||||
}
|
||||
fn fold_variant_kind(&mut self, kind: VariantKind) -> VariantKind {
|
||||
or_fold_variant_kind(self, kind)
|
||||
}
|
||||
fn fold_impl(&mut self, i: Impl) -> Impl {
|
||||
let Impl { target, body } = i;
|
||||
Impl { target: self.fold_impl_kind(target), body: self.fold_file(body) }
|
||||
}
|
||||
fn fold_impl_kind(&mut self, kind: ImplKind) -> ImplKind {
|
||||
or_fold_impl_kind(self, kind)
|
||||
}
|
||||
fn fold_ty(&mut self, t: Ty) -> Ty {
|
||||
let Ty { extents, kind } = t;
|
||||
Ty { extents: self.fold_span(extents), kind: self.fold_ty_kind(kind) }
|
||||
}
|
||||
fn fold_ty_kind(&mut self, kind: TyKind) -> TyKind {
|
||||
or_fold_ty_kind(self, kind)
|
||||
}
|
||||
fn fold_ty_tuple(&mut self, t: TyTuple) -> TyTuple {
|
||||
let TyTuple { types } = t;
|
||||
TyTuple {
|
||||
types: types
|
||||
.into_iter()
|
||||
.map(|kind| self.fold_ty_kind(kind))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
fn fold_ty_ref(&mut self, t: TyRef) -> TyRef {
|
||||
let TyRef { mutable, count, to } = t;
|
||||
TyRef { mutable: self.fold_mutability(mutable), count, to: self.fold_path(to) }
|
||||
}
|
||||
fn fold_ty_fn(&mut self, t: TyFn) -> TyFn {
|
||||
let TyFn { args, rety } = t;
|
||||
TyFn {
|
||||
args: Box::new(self.fold_ty_kind(*args)),
|
||||
rety: rety.map(|t| Box::new(self.fold_ty(*t))),
|
||||
}
|
||||
}
|
||||
fn fold_path(&mut self, p: Path) -> Path {
|
||||
let Path { absolute, parts } = p;
|
||||
Path { absolute, parts: parts.into_iter().map(|p| self.fold_path_part(p)).collect() }
|
||||
}
|
||||
fn fold_path_part(&mut self, p: PathPart) -> PathPart {
|
||||
match p {
|
||||
PathPart::SuperKw => PathPart::SuperKw,
|
||||
PathPart::SelfKw => PathPart::SelfKw,
|
||||
PathPart::Ident(i) => PathPart::Ident(self.fold_identifier(i)),
|
||||
}
|
||||
}
|
||||
fn fold_stmt(&mut self, s: Stmt) -> Stmt {
|
||||
let Stmt { extents, kind, semi } = s;
|
||||
Stmt {
|
||||
extents: self.fold_span(extents),
|
||||
kind: self.fold_stmt_kind(kind),
|
||||
semi: self.fold_semi(semi),
|
||||
}
|
||||
}
|
||||
fn fold_stmt_kind(&mut self, kind: StmtKind) -> StmtKind {
|
||||
or_fold_stmt_kind(self, kind)
|
||||
}
|
||||
fn fold_semi(&mut self, s: Semi) -> Semi {
|
||||
s
|
||||
}
|
||||
fn fold_let(&mut self, l: Let) -> Let {
|
||||
let Let { mutable, name, ty, init } = l;
|
||||
Let {
|
||||
mutable: self.fold_mutability(mutable),
|
||||
name: self.fold_identifier(name),
|
||||
ty: ty.map(|t| Box::new(self.fold_ty(*t))),
|
||||
init: init.map(|e| Box::new(self.fold_expr(*e))),
|
||||
}
|
||||
}
|
||||
fn fold_expr(&mut self, e: Expr) -> Expr {
|
||||
let Expr { extents, kind } = e;
|
||||
Expr { extents: self.fold_span(extents), kind: self.fold_expr_kind(kind) }
|
||||
}
|
||||
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
||||
or_fold_expr_kind(self, kind)
|
||||
}
|
||||
fn fold_assign(&mut self, a: Assign) -> Assign {
|
||||
let Assign { kind, parts } = a;
|
||||
let (head, tail) = *parts;
|
||||
Assign {
|
||||
kind: self.fold_assign_kind(kind),
|
||||
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||
}
|
||||
}
|
||||
fn fold_assign_kind(&mut self, kind: AssignKind) -> AssignKind {
|
||||
kind
|
||||
}
|
||||
fn fold_binary(&mut self, b: Binary) -> Binary {
|
||||
let Binary { kind, parts } = b;
|
||||
let (head, tail) = *parts;
|
||||
Binary {
|
||||
kind: self.fold_binary_kind(kind),
|
||||
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||
}
|
||||
}
|
||||
fn fold_binary_kind(&mut self, kind: BinaryKind) -> BinaryKind {
|
||||
kind
|
||||
}
|
||||
fn fold_unary(&mut self, u: Unary) -> Unary {
|
||||
let Unary { kind, tail } = u;
|
||||
Unary { kind: self.fold_unary_kind(kind), tail: Box::new(self.fold_expr_kind(*tail)) }
|
||||
}
|
||||
fn fold_unary_kind(&mut self, kind: UnaryKind) -> UnaryKind {
|
||||
kind
|
||||
}
|
||||
fn fold_index(&mut self, i: Index) -> Index {
|
||||
let Index { head, indices } = i;
|
||||
Index {
|
||||
head: Box::new(self.fold_expr_kind(*head)),
|
||||
indices: indices.into_iter().map(|e| self.fold_expr(e)).collect(),
|
||||
}
|
||||
}
|
||||
fn fold_array(&mut self, a: Array) -> Array {
|
||||
let Array { values } = a;
|
||||
Array { values: values.into_iter().map(|e| self.fold_expr(e)).collect() }
|
||||
}
|
||||
fn fold_array_rep(&mut self, a: ArrayRep) -> ArrayRep {
|
||||
let ArrayRep { value, repeat } = a;
|
||||
ArrayRep {
|
||||
value: Box::new(self.fold_expr_kind(*value)),
|
||||
repeat: Box::new(self.fold_expr_kind(*repeat)),
|
||||
}
|
||||
}
|
||||
fn fold_addrof(&mut self, a: AddrOf) -> AddrOf {
|
||||
let AddrOf { count, mutable, expr } = a;
|
||||
AddrOf {
|
||||
count,
|
||||
mutable: self.fold_mutability(mutable),
|
||||
expr: Box::new(self.fold_expr_kind(*expr)),
|
||||
}
|
||||
}
|
||||
fn fold_block(&mut self, b: Block) -> Block {
|
||||
let Block { stmts } = b;
|
||||
Block { stmts: stmts.into_iter().map(|s| self.fold_stmt(s)).collect() }
|
||||
}
|
||||
fn fold_group(&mut self, g: Group) -> Group {
|
||||
let Group { expr } = g;
|
||||
Group { expr: Box::new(self.fold_expr_kind(*expr)) }
|
||||
}
|
||||
fn fold_tuple(&mut self, t: Tuple) -> Tuple {
|
||||
let Tuple { exprs } = t;
|
||||
Tuple { exprs: exprs.into_iter().map(|e| self.fold_expr(e)).collect() }
|
||||
}
|
||||
fn fold_loop(&mut self, l: Loop) -> Loop {
|
||||
let Loop { body } = l;
|
||||
Loop { body: Box::new(self.fold_expr(*body)) }
|
||||
}
|
||||
fn fold_while(&mut self, w: While) -> While {
|
||||
let While { cond, pass, fail } = w;
|
||||
While {
|
||||
cond: Box::new(self.fold_expr(*cond)),
|
||||
pass: Box::new(self.fold_block(*pass)),
|
||||
fail: self.fold_else(fail),
|
||||
}
|
||||
}
|
||||
fn fold_if(&mut self, i: If) -> If {
|
||||
let If { cond, pass, fail } = i;
|
||||
If {
|
||||
cond: Box::new(self.fold_expr(*cond)),
|
||||
pass: Box::new(self.fold_block(*pass)),
|
||||
fail: self.fold_else(fail),
|
||||
}
|
||||
}
|
||||
fn fold_for(&mut self, f: For) -> For {
|
||||
let For { bind, cond, pass, fail } = f;
|
||||
For {
|
||||
bind: self.fold_identifier(bind),
|
||||
cond: Box::new(self.fold_expr(*cond)),
|
||||
pass: Box::new(self.fold_block(*pass)),
|
||||
fail: self.fold_else(fail),
|
||||
}
|
||||
}
|
||||
fn fold_else(&mut self, e: Else) -> Else {
|
||||
let Else { body } = e;
|
||||
Else { body: body.map(|e| Box::new(self.fold_expr(*e))) }
|
||||
}
|
||||
fn fold_break(&mut self, b: Break) -> Break {
|
||||
let Break { body } = b;
|
||||
Break { body: body.map(|e| Box::new(self.fold_expr(*e))) }
|
||||
}
|
||||
fn fold_return(&mut self, r: Return) -> Return {
|
||||
let Return { body } = r;
|
||||
Return { body: body.map(|e| Box::new(self.fold_expr(*e))) }
|
||||
}
|
||||
fn fold_continue(&mut self, c: Continue) -> Continue {
|
||||
let Continue = c;
|
||||
Continue
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [Literal] in the default way
|
||||
pub fn or_fold_literal<F: Fold + ?Sized>(folder: &mut F, lit: Literal) -> Literal {
|
||||
match lit {
|
||||
Literal::Bool(b) => Literal::Bool(folder.fold_bool(b)),
|
||||
Literal::Char(c) => Literal::Char(folder.fold_char(c)),
|
||||
Literal::Int(i) => Literal::Int(folder.fold_int(i)),
|
||||
Literal::String(s) => Literal::String(folder.fold_string(s)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [MetaKind] in the default way
|
||||
pub fn or_fold_meta_kind<F: Fold + ?Sized>(folder: &mut F, kind: MetaKind) -> MetaKind {
|
||||
match kind {
|
||||
MetaKind::Plain => MetaKind::Plain,
|
||||
MetaKind::Equals(l) => MetaKind::Equals(folder.fold_literal(l)),
|
||||
MetaKind::Func(lits) => {
|
||||
MetaKind::Func(lits.into_iter().map(|l| folder.fold_literal(l)).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds an [ItemKind] in the default way
|
||||
pub fn or_fold_item_kind<F: Fold + ?Sized>(folder: &mut F, kind: ItemKind) -> ItemKind {
|
||||
match kind {
|
||||
ItemKind::Module(m) => ItemKind::Module(folder.fold_module(m)),
|
||||
ItemKind::Alias(a) => ItemKind::Alias(folder.fold_alias(a)),
|
||||
ItemKind::Enum(e) => ItemKind::Enum(folder.fold_enum(e)),
|
||||
ItemKind::Struct(s) => ItemKind::Struct(folder.fold_struct(s)),
|
||||
ItemKind::Const(c) => ItemKind::Const(folder.fold_const(c)),
|
||||
ItemKind::Static(s) => ItemKind::Static(folder.fold_static(s)),
|
||||
ItemKind::Function(f) => ItemKind::Function(folder.fold_function(f)),
|
||||
ItemKind::Impl(i) => ItemKind::Impl(folder.fold_impl(i)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [ModuleKind] in the default way
|
||||
pub fn or_fold_module_kind<F: Fold + ?Sized>(folder: &mut F, kind: ModuleKind) -> ModuleKind {
|
||||
match kind {
|
||||
ModuleKind::Inline(f) => ModuleKind::Inline(folder.fold_file(f)),
|
||||
ModuleKind::Outline => ModuleKind::Outline,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [StructKind] in the default way
|
||||
pub fn or_fold_struct_kind<F: Fold + ?Sized>(folder: &mut F, kind: StructKind) -> StructKind {
|
||||
match kind {
|
||||
StructKind::Empty => StructKind::Empty,
|
||||
StructKind::Tuple(tys) => {
|
||||
StructKind::Tuple(tys.into_iter().map(|t| folder.fold_ty(t)).collect())
|
||||
}
|
||||
StructKind::Struct(mem) => StructKind::Struct(
|
||||
mem.into_iter()
|
||||
.map(|m| folder.fold_struct_member(m))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds an [EnumKind] in the default way
|
||||
pub fn or_fold_enum_kind<F: Fold + ?Sized>(folder: &mut F, kind: EnumKind) -> EnumKind {
|
||||
match kind {
|
||||
EnumKind::NoVariants => EnumKind::NoVariants,
|
||||
EnumKind::Variants(v) => {
|
||||
EnumKind::Variants(v.into_iter().map(|v| folder.fold_variant(v)).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [VariantKind] in the default way
|
||||
pub fn or_fold_variant_kind<F: Fold + ?Sized>(folder: &mut F, kind: VariantKind) -> VariantKind {
|
||||
match kind {
|
||||
VariantKind::Plain => VariantKind::Plain,
|
||||
VariantKind::CLike(n) => VariantKind::CLike(n),
|
||||
VariantKind::Tuple(t) => VariantKind::Tuple(folder.fold_ty(t)),
|
||||
VariantKind::Struct(mem) => VariantKind::Struct(
|
||||
mem.into_iter()
|
||||
.map(|m| folder.fold_struct_member(m))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds an [ImplKind] in the default way
|
||||
pub fn or_fold_impl_kind<F: Fold + ?Sized>(folder: &mut F, kind: ImplKind) -> ImplKind {
|
||||
match kind {
|
||||
ImplKind::Type(t) => ImplKind::Type(folder.fold_ty(t)),
|
||||
ImplKind::Trait { impl_trait, for_type } => ImplKind::Trait {
|
||||
impl_trait: folder.fold_path(impl_trait),
|
||||
for_type: Box::new(folder.fold_ty(*for_type)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [TyKind] in the default way
|
||||
pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind {
|
||||
match kind {
|
||||
TyKind::Never => TyKind::Never,
|
||||
TyKind::Empty => TyKind::Empty,
|
||||
TyKind::SelfTy => TyKind::SelfTy,
|
||||
TyKind::Path(p) => TyKind::Path(folder.fold_path(p)),
|
||||
TyKind::Tuple(t) => TyKind::Tuple(folder.fold_ty_tuple(t)),
|
||||
TyKind::Ref(t) => TyKind::Ref(folder.fold_ty_ref(t)),
|
||||
TyKind::Fn(t) => TyKind::Fn(folder.fold_ty_fn(t)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Folds a [StmtKind] in the default way
|
||||
pub fn or_fold_stmt_kind<F: Fold + ?Sized>(folder: &mut F, kind: StmtKind) -> StmtKind {
|
||||
match kind {
|
||||
StmtKind::Empty => StmtKind::Empty,
|
||||
StmtKind::Local(l) => StmtKind::Local(folder.fold_let(l)),
|
||||
StmtKind::Item(i) => StmtKind::Item(Box::new(folder.fold_item(*i))),
|
||||
StmtKind::Expr(e) => StmtKind::Expr(Box::new(folder.fold_expr(*e))),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
/// Folds an [ExprKind] in the default way
|
||||
pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> ExprKind {
|
||||
match kind {
|
||||
ExprKind::Empty => ExprKind::Empty,
|
||||
ExprKind::Assign(a) => ExprKind::Assign(folder.fold_assign(a)),
|
||||
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),
|
||||
ExprKind::Unary(u) => ExprKind::Unary(folder.fold_unary(u)),
|
||||
ExprKind::Index(i) => ExprKind::Index(folder.fold_index(i)),
|
||||
ExprKind::Path(p) => ExprKind::Path(folder.fold_path(p)),
|
||||
ExprKind::Literal(l) => ExprKind::Literal(folder.fold_literal(l)),
|
||||
ExprKind::Array(a) => ExprKind::Array(folder.fold_array(a)),
|
||||
ExprKind::ArrayRep(a) => ExprKind::ArrayRep(folder.fold_array_rep(a)),
|
||||
ExprKind::AddrOf(a) => ExprKind::AddrOf(folder.fold_addrof(a)),
|
||||
ExprKind::Block(b) => ExprKind::Block(folder.fold_block(b)),
|
||||
ExprKind::Group(g) => ExprKind::Group(folder.fold_group(g)),
|
||||
ExprKind::Tuple(t) => ExprKind::Tuple(folder.fold_tuple(t)),
|
||||
ExprKind::Loop(l) => ExprKind::Loop(folder.fold_loop(l)),
|
||||
ExprKind::While(w) => ExprKind::While(folder.fold_while(w)),
|
||||
ExprKind::If(i) => ExprKind::If(folder.fold_if(i)),
|
||||
ExprKind::For(f) => ExprKind::For(folder.fold_for(f)),
|
||||
ExprKind::Break(b) => ExprKind::Break(folder.fold_break(b)),
|
||||
ExprKind::Return(r) => ExprKind::Return(folder.fold_return(r)),
|
||||
ExprKind::Continue(c) => ExprKind::Continue(folder.fold_continue(c)),
|
||||
}
|
||||
}
|
411
cl-ast/src/ast_visitor/visit.rs
Normal file
411
cl-ast/src/ast_visitor/visit.rs
Normal file
@ -0,0 +1,411 @@
|
||||
//! A [visitor](Visit) (implementer of the [Visit] trait) walks the immutable AST, mutating itself.
|
||||
|
||||
use crate::ast::*;
|
||||
use cl_structures::span::Span;
|
||||
|
||||
/// Immutably walks the entire AST
|
||||
///
|
||||
/// Each method acts as a customization point.
|
||||
///
|
||||
/// There are a set of default implementations for enums
|
||||
/// under the name [`or_visit_`*](or_visit_expr_kind),
|
||||
/// provided for ease of use.
|
||||
///
|
||||
/// For all other nodes, traversal is *explicit*.
|
||||
pub trait Visit<'a>: Sized {
|
||||
fn visit_span(&mut self, _extents: &'a Span) {}
|
||||
fn visit_mutability(&mut self, _mutable: &'a Mutability) {}
|
||||
fn visit_visibility(&mut self, _vis: &'a Visibility) {}
|
||||
fn visit_identifier(&mut self, _name: &'a Identifier) {}
|
||||
fn visit_literal(&mut self, l: &'a Literal) {
|
||||
or_visit_literal(self, l)
|
||||
}
|
||||
fn visit_bool(&mut self, _b: &'a bool) {}
|
||||
fn visit_char(&mut self, _c: &'a char) {}
|
||||
fn visit_int(&mut self, _i: &'a u128) {}
|
||||
fn visit_string(&mut self, _s: &'a str) {}
|
||||
fn visit_file(&mut self, f: &'a File) {
|
||||
let File { items } = f;
|
||||
items.iter().for_each(|i| self.visit_item(i));
|
||||
}
|
||||
fn visit_attrs(&mut self, a: &'a Attrs) {
|
||||
let Attrs { meta } = a;
|
||||
meta.iter().for_each(|m| self.visit_meta(m));
|
||||
}
|
||||
fn visit_meta(&mut self, m: &'a Meta) {
|
||||
let Meta { name, kind } = m;
|
||||
self.visit_identifier(name);
|
||||
self.visit_meta_kind(kind);
|
||||
}
|
||||
fn visit_meta_kind(&mut self, kind: &'a MetaKind) {
|
||||
or_visit_meta_kind(self, kind)
|
||||
}
|
||||
fn visit_item(&mut self, i: &'a Item) {
|
||||
let Item { extents, attrs, vis, kind } = i;
|
||||
self.visit_span(extents);
|
||||
self.visit_attrs(attrs);
|
||||
self.visit_visibility(vis);
|
||||
self.visit_item_kind(kind);
|
||||
}
|
||||
fn visit_item_kind(&mut self, kind: &'a ItemKind) {
|
||||
or_visit_item_kind(self, kind)
|
||||
}
|
||||
fn visit_alias(&mut self, a: &'a Alias) {
|
||||
let Alias { to, from } = a;
|
||||
self.visit_identifier(to);
|
||||
if let Some(t) = from {
|
||||
self.visit_ty(t)
|
||||
}
|
||||
}
|
||||
fn visit_const(&mut self, c: &'a Const) {
|
||||
let Const { name, ty, init } = c;
|
||||
self.visit_identifier(name);
|
||||
self.visit_ty(ty);
|
||||
self.visit_expr(init);
|
||||
}
|
||||
fn visit_static(&mut self, s: &'a Static) {
|
||||
let Static { mutable, name, ty, init } = s;
|
||||
self.visit_mutability(mutable);
|
||||
self.visit_identifier(name);
|
||||
self.visit_ty(ty);
|
||||
self.visit_expr(init);
|
||||
}
|
||||
fn visit_module(&mut self, m: &'a Module) {
|
||||
let Module { name, kind } = m;
|
||||
self.visit_identifier(name);
|
||||
self.visit_module_kind(kind);
|
||||
}
|
||||
fn visit_module_kind(&mut self, kind: &'a ModuleKind) {
|
||||
or_visit_module_kind(self, kind)
|
||||
}
|
||||
fn visit_function(&mut self, f: &'a Function) {
|
||||
let Function { name, sign, bind, body } = f;
|
||||
self.visit_identifier(name);
|
||||
self.visit_ty_fn(sign);
|
||||
bind.iter().for_each(|p| self.visit_param(p));
|
||||
if let Some(b) = body {
|
||||
self.visit_block(b)
|
||||
}
|
||||
}
|
||||
fn visit_param(&mut self, p: &'a Param) {
|
||||
let Param { mutability, name } = p;
|
||||
self.visit_mutability(mutability);
|
||||
self.visit_identifier(name);
|
||||
}
|
||||
fn visit_struct(&mut self, s: &'a Struct) {
|
||||
let Struct { name, kind } = s;
|
||||
self.visit_identifier(name);
|
||||
self.visit_struct_kind(kind);
|
||||
}
|
||||
fn visit_struct_kind(&mut self, kind: &'a StructKind) {
|
||||
or_visit_struct_kind(self, kind)
|
||||
}
|
||||
fn visit_struct_member(&mut self, m: &'a StructMember) {
|
||||
let StructMember { vis, name, ty } = m;
|
||||
self.visit_visibility(vis);
|
||||
self.visit_identifier(name);
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
fn visit_enum(&mut self, e: &'a Enum) {
|
||||
let Enum { name, kind } = e;
|
||||
self.visit_identifier(name);
|
||||
self.visit_enum_kind(kind);
|
||||
}
|
||||
fn visit_enum_kind(&mut self, kind: &'a EnumKind) {
|
||||
or_visit_enum_kind(self, kind)
|
||||
}
|
||||
fn visit_variant(&mut self, v: &'a Variant) {
|
||||
let Variant { name, kind } = v;
|
||||
self.visit_identifier(name);
|
||||
self.visit_variant_kind(kind);
|
||||
}
|
||||
fn visit_variant_kind(&mut self, kind: &'a VariantKind) {
|
||||
or_visit_variant_kind(self, kind)
|
||||
}
|
||||
fn visit_impl(&mut self, i: &'a Impl) {
|
||||
let Impl { target, body } = i;
|
||||
self.visit_impl_kind(target);
|
||||
self.visit_file(body)
|
||||
}
|
||||
fn visit_impl_kind(&mut self, target: &'a ImplKind) {
|
||||
or_visit_impl_kind(self, target)
|
||||
}
|
||||
fn visit_ty(&mut self, t: &'a Ty) {
|
||||
let Ty { extents, kind } = t;
|
||||
self.visit_span(extents);
|
||||
self.visit_ty_kind(kind);
|
||||
}
|
||||
fn visit_ty_kind(&mut self, kind: &'a TyKind) {
|
||||
or_visit_ty_kind(self, kind)
|
||||
}
|
||||
fn visit_ty_tuple(&mut self, t: &'a TyTuple) {
|
||||
let TyTuple { types } = t;
|
||||
types.iter().for_each(|kind| self.visit_ty_kind(kind))
|
||||
}
|
||||
fn visit_ty_ref(&mut self, t: &'a TyRef) {
|
||||
let TyRef { mutable, count: _, to } = t;
|
||||
self.visit_mutability(mutable);
|
||||
self.visit_path(to);
|
||||
}
|
||||
fn visit_ty_fn(&mut self, t: &'a TyFn) {
|
||||
let TyFn { args, rety } = t;
|
||||
self.visit_ty_kind(args);
|
||||
if let Some(rety) = rety {
|
||||
self.visit_ty(rety);
|
||||
}
|
||||
}
|
||||
fn visit_path(&mut self, p: &'a Path) {
|
||||
let Path { absolute: _, parts } = p;
|
||||
parts.iter().for_each(|p| self.visit_path_part(p))
|
||||
}
|
||||
fn visit_path_part(&mut self, p: &'a PathPart) {
|
||||
match p {
|
||||
PathPart::SuperKw => {}
|
||||
PathPart::SelfKw => {}
|
||||
PathPart::Ident(i) => self.visit_identifier(i),
|
||||
}
|
||||
}
|
||||
fn visit_stmt(&mut self, s: &'a Stmt) {
|
||||
let Stmt { extents, kind, semi } = s;
|
||||
self.visit_span(extents);
|
||||
self.visit_stmt_kind(kind);
|
||||
self.visit_semi(semi);
|
||||
}
|
||||
fn visit_stmt_kind(&mut self, kind: &'a StmtKind) {
|
||||
or_visit_stmt_kind(self, kind)
|
||||
}
|
||||
fn visit_semi(&mut self, _s: &'a Semi) {}
|
||||
fn visit_let(&mut self, l: &'a Let) {
|
||||
let Let { mutable, name, ty, init } = l;
|
||||
self.visit_mutability(mutable);
|
||||
self.visit_identifier(name);
|
||||
if let Some(ty) = ty {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
if let Some(init) = init {
|
||||
self.visit_expr(init)
|
||||
}
|
||||
}
|
||||
fn visit_expr(&mut self, e: &'a Expr) {
|
||||
let Expr { extents, kind } = e;
|
||||
self.visit_span(extents);
|
||||
self.visit_expr_kind(kind)
|
||||
}
|
||||
fn visit_expr_kind(&mut self, e: &'a ExprKind) {
|
||||
or_visit_expr_kind(self, e)
|
||||
}
|
||||
fn visit_assign(&mut self, a: &'a Assign) {
|
||||
let Assign { kind, parts } = a;
|
||||
let (head, tail) = parts.as_ref();
|
||||
self.visit_assign_kind(kind);
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr_kind(tail);
|
||||
}
|
||||
fn visit_assign_kind(&mut self, _kind: &'a AssignKind) {}
|
||||
fn visit_binary(&mut self, b: &'a Binary) {
|
||||
let Binary { kind, parts } = b;
|
||||
let (head, tail) = parts.as_ref();
|
||||
self.visit_binary_kind(kind);
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr_kind(tail);
|
||||
}
|
||||
fn visit_binary_kind(&mut self, _kind: &'a BinaryKind) {}
|
||||
fn visit_unary(&mut self, u: &'a Unary) {
|
||||
let Unary { kind, tail } = u;
|
||||
self.visit_unary_kind(kind);
|
||||
self.visit_expr_kind(tail);
|
||||
}
|
||||
fn visit_unary_kind(&mut self, _kind: &'a UnaryKind) {}
|
||||
fn visit_index(&mut self, i: &'a Index) {
|
||||
let Index { head, indices } = i;
|
||||
self.visit_expr_kind(head);
|
||||
indices.iter().for_each(|e| self.visit_expr(e));
|
||||
}
|
||||
fn visit_array(&mut self, a: &'a Array) {
|
||||
let Array { values } = a;
|
||||
values.iter().for_each(|e| self.visit_expr(e))
|
||||
}
|
||||
fn visit_array_rep(&mut self, a: &'a ArrayRep) {
|
||||
let ArrayRep { value, repeat } = a;
|
||||
self.visit_expr_kind(value);
|
||||
self.visit_expr_kind(repeat);
|
||||
}
|
||||
fn visit_addrof(&mut self, a: &'a AddrOf) {
|
||||
let AddrOf { count: _, mutable, expr } = a;
|
||||
self.visit_mutability(mutable);
|
||||
self.visit_expr_kind(expr);
|
||||
}
|
||||
fn visit_block(&mut self, b: &'a Block) {
|
||||
let Block { stmts } = b;
|
||||
stmts.iter().for_each(|s| self.visit_stmt(s));
|
||||
}
|
||||
fn visit_group(&mut self, g: &'a Group) {
|
||||
let Group { expr } = g;
|
||||
self.visit_expr_kind(expr)
|
||||
}
|
||||
fn visit_tuple(&mut self, t: &'a Tuple) {
|
||||
let Tuple { exprs } = t;
|
||||
exprs.iter().for_each(|e| self.visit_expr(e))
|
||||
}
|
||||
fn visit_loop(&mut self, l: &'a Loop) {
|
||||
let Loop { body } = l;
|
||||
self.visit_expr(body)
|
||||
}
|
||||
fn visit_while(&mut self, w: &'a While) {
|
||||
let While { cond, pass, fail } = w;
|
||||
self.visit_expr(cond);
|
||||
self.visit_block(pass);
|
||||
self.visit_else(fail);
|
||||
}
|
||||
fn visit_if(&mut self, i: &'a If) {
|
||||
let If { cond, pass, fail } = i;
|
||||
self.visit_expr(cond);
|
||||
self.visit_block(pass);
|
||||
self.visit_else(fail);
|
||||
}
|
||||
fn visit_for(&mut self, f: &'a For) {
|
||||
let For { bind, cond, pass, fail } = f;
|
||||
self.visit_identifier(bind);
|
||||
self.visit_expr(cond);
|
||||
self.visit_block(pass);
|
||||
self.visit_else(fail);
|
||||
}
|
||||
fn visit_else(&mut self, e: &'a Else) {
|
||||
let Else { body } = e;
|
||||
if let Some(body) = body {
|
||||
self.visit_expr(body)
|
||||
}
|
||||
}
|
||||
fn visit_break(&mut self, b: &'a Break) {
|
||||
let Break { body } = b;
|
||||
if let Some(body) = body {
|
||||
self.visit_expr(body)
|
||||
}
|
||||
}
|
||||
fn visit_return(&mut self, r: &'a Return) {
|
||||
let Return { body } = r;
|
||||
if let Some(body) = body {
|
||||
self.visit_expr(body)
|
||||
}
|
||||
}
|
||||
fn visit_continue(&mut self, c: &'a Continue) {
|
||||
let Continue = c;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_literal<'a, V: Visit<'a>>(visitor: &mut V, l: &'a Literal) {
|
||||
match l {
|
||||
Literal::Bool(b) => visitor.visit_bool(b),
|
||||
Literal::Char(c) => visitor.visit_char(c),
|
||||
Literal::Int(i) => visitor.visit_int(i),
|
||||
Literal::String(s) => visitor.visit_string(s),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_meta_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a MetaKind) {
|
||||
match kind {
|
||||
MetaKind::Plain => {}
|
||||
MetaKind::Equals(l) => visitor.visit_literal(l),
|
||||
MetaKind::Func(lits) => lits.iter().for_each(|l| visitor.visit_literal(l)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_item_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a ItemKind) {
|
||||
match kind {
|
||||
ItemKind::Module(m) => visitor.visit_module(m),
|
||||
ItemKind::Alias(a) => visitor.visit_alias(a),
|
||||
ItemKind::Enum(e) => visitor.visit_enum(e),
|
||||
ItemKind::Struct(s) => visitor.visit_struct(s),
|
||||
ItemKind::Const(c) => visitor.visit_const(c),
|
||||
ItemKind::Static(s) => visitor.visit_static(s),
|
||||
ItemKind::Function(f) => visitor.visit_function(f),
|
||||
ItemKind::Impl(i) => visitor.visit_impl(i),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_module_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a ModuleKind) {
|
||||
match kind {
|
||||
ModuleKind::Inline(f) => visitor.visit_file(f),
|
||||
ModuleKind::Outline => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_struct_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a StructKind) {
|
||||
match kind {
|
||||
StructKind::Empty => {}
|
||||
StructKind::Tuple(ty) => ty.iter().for_each(|t| visitor.visit_ty(t)),
|
||||
StructKind::Struct(m) => m.iter().for_each(|m| visitor.visit_struct_member(m)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_enum_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a EnumKind) {
|
||||
match kind {
|
||||
EnumKind::NoVariants => {}
|
||||
EnumKind::Variants(variants) => variants.iter().for_each(|v| visitor.visit_variant(v)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_variant_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a VariantKind) {
|
||||
match kind {
|
||||
VariantKind::Plain => {}
|
||||
VariantKind::CLike(_) => {}
|
||||
VariantKind::Tuple(t) => visitor.visit_ty(t),
|
||||
VariantKind::Struct(m) => m.iter().for_each(|m| visitor.visit_struct_member(m)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_impl_kind<'a, V: Visit<'a>>(visitor: &mut V, target: &'a ImplKind) {
|
||||
match target {
|
||||
ImplKind::Type(t) => visitor.visit_ty(t),
|
||||
ImplKind::Trait { impl_trait, for_type } => {
|
||||
visitor.visit_path(impl_trait);
|
||||
visitor.visit_ty(for_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_ty_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a TyKind) {
|
||||
match kind {
|
||||
TyKind::Never => {}
|
||||
TyKind::Empty => {}
|
||||
TyKind::SelfTy => {}
|
||||
TyKind::Path(p) => visitor.visit_path(p),
|
||||
TyKind::Tuple(t) => visitor.visit_ty_tuple(t),
|
||||
TyKind::Ref(t) => visitor.visit_ty_ref(t),
|
||||
TyKind::Fn(t) => visitor.visit_ty_fn(t),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_stmt_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a StmtKind) {
|
||||
match kind {
|
||||
StmtKind::Empty => {}
|
||||
StmtKind::Local(l) => visitor.visit_let(l),
|
||||
StmtKind::Item(i) => visitor.visit_item(i),
|
||||
StmtKind::Expr(e) => visitor.visit_expr(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
|
||||
match e {
|
||||
ExprKind::Empty => {}
|
||||
ExprKind::Assign(a) => visitor.visit_assign(a),
|
||||
ExprKind::Binary(b) => visitor.visit_binary(b),
|
||||
ExprKind::Unary(u) => visitor.visit_unary(u),
|
||||
ExprKind::Index(i) => visitor.visit_index(i),
|
||||
ExprKind::Path(p) => visitor.visit_path(p),
|
||||
ExprKind::Literal(l) => visitor.visit_literal(l),
|
||||
ExprKind::Array(a) => visitor.visit_array(a),
|
||||
ExprKind::ArrayRep(a) => visitor.visit_array_rep(a),
|
||||
ExprKind::AddrOf(a) => visitor.visit_addrof(a),
|
||||
ExprKind::Block(b) => visitor.visit_block(b),
|
||||
ExprKind::Group(g) => visitor.visit_group(g),
|
||||
ExprKind::Tuple(t) => visitor.visit_tuple(t),
|
||||
ExprKind::Loop(l) => visitor.visit_loop(l),
|
||||
ExprKind::While(w) => visitor.visit_while(w),
|
||||
ExprKind::If(i) => visitor.visit_if(i),
|
||||
ExprKind::For(f) => visitor.visit_for(f),
|
||||
ExprKind::Break(b) => visitor.visit_break(b),
|
||||
ExprKind::Return(r) => visitor.visit_return(r),
|
||||
ExprKind::Continue(c) => visitor.visit_continue(c),
|
||||
}
|
||||
}
|
5
cl-ast/src/desugar.rs
Normal file
5
cl-ast/src/desugar.rs
Normal file
@ -0,0 +1,5 @@
|
||||
//! Desugaring passes for Conlang
|
||||
|
||||
pub mod while_else;
|
||||
|
||||
pub mod squash_groups;
|
14
cl-ast/src/desugar/squash_groups.rs
Normal file
14
cl-ast/src/desugar/squash_groups.rs
Normal file
@ -0,0 +1,14 @@
|
||||
//! Squashes group expressions
|
||||
use crate::{ast::*, ast_visitor::fold::*};
|
||||
|
||||
/// Squashes group expressions
|
||||
pub struct SquashGroups;
|
||||
|
||||
impl Fold for SquashGroups {
|
||||
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
||||
match kind {
|
||||
ExprKind::Group(Group { expr }) => self.fold_expr_kind(*expr),
|
||||
_ => or_fold_expr_kind(self, kind),
|
||||
}
|
||||
}
|
||||
}
|
34
cl-ast/src/desugar/while_else.rs
Normal file
34
cl-ast/src/desugar/while_else.rs
Normal file
@ -0,0 +1,34 @@
|
||||
//! Desugars `while {...} else` expressions
|
||||
//! into `loop if {...} else break` expressions
|
||||
|
||||
use crate::{ast::*, ast_visitor::fold::Fold};
|
||||
use cl_structures::span::Span;
|
||||
|
||||
/// Desugars while-else expressions
|
||||
/// into loop-if-else-break expressions
|
||||
pub struct WhileElseDesugar;
|
||||
|
||||
impl Fold for WhileElseDesugar {
|
||||
fn fold_expr(&mut self, e: Expr) -> Expr {
|
||||
let Expr { extents, kind } = e;
|
||||
let kind = desugar_while(extents, kind);
|
||||
Expr { extents: self.fold_span(extents), kind: self.fold_expr_kind(kind) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Desugars while(-else) expressions into loop-if-else-break expressions
|
||||
fn desugar_while(extents: Span, kind: ExprKind) -> ExprKind {
|
||||
match kind {
|
||||
// work backwards: fail -> break -> if -> loop
|
||||
ExprKind::While(While { cond, pass, fail: Else { body } }) => {
|
||||
// Preserve the else-expression's extents, if present, or use the parent's extents
|
||||
let fail_span = body.as_ref().map(|body| body.extents).unwrap_or(extents);
|
||||
let break_expr = Expr { extents: fail_span, kind: ExprKind::Break(Break { body }) };
|
||||
|
||||
let loop_body = If { cond, pass, fail: Else { body: Some(Box::new(break_expr)) } };
|
||||
let loop_body = Expr { extents, kind: ExprKind::If(loop_body) };
|
||||
ExprKind::Loop(Loop { body: Box::new(loop_body) })
|
||||
}
|
||||
_ => kind,
|
||||
}
|
||||
}
|
@ -16,4 +16,6 @@ pub use ast::*;
|
||||
|
||||
pub mod ast;
|
||||
pub mod ast_impl;
|
||||
pub mod ast_visitor;
|
||||
pub mod desugar;
|
||||
pub mod format;
|
||||
|
@ -1,3 +1,7 @@
|
||||
use cl_ast::{
|
||||
ast_visitor::fold::Fold,
|
||||
desugar::{squash_groups::SquashGroups, while_else::WhileElseDesugar},
|
||||
};
|
||||
use cl_lexer::Lexer;
|
||||
use cl_parser::Parser;
|
||||
use cl_repl::repline::{error::Error as RlError, Repline};
|
||||
@ -33,6 +37,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
Err(e)?
|
||||
}
|
||||
};
|
||||
|
||||
unsafe { TREES.push(code) }.collect_in_root(&mut prj)?;
|
||||
|
||||
main_menu(&mut prj)
|
||||
@ -81,6 +86,7 @@ fn main_menu(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
||||
"l" | "list" => list_types(prj),
|
||||
"q" | "query" => query_type_expression(prj),
|
||||
"r" | "resolve" => resolve_all(prj),
|
||||
"d" | "desugar" => live_desugar(),
|
||||
"h" | "help" => {
|
||||
println!(
|
||||
"Valid commands are:
|
||||
@ -88,6 +94,7 @@ fn main_menu(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
||||
list (l): List all known types
|
||||
query (q): Query the type system
|
||||
resolve (r): Perform type resolution
|
||||
desugar (d): WIP: Test the experimental desugaring passes
|
||||
help (h): Print this list
|
||||
exit (e): Exit the program"
|
||||
);
|
||||
@ -105,7 +112,7 @@ fn enter_code(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
||||
return Ok(Response::Break);
|
||||
}
|
||||
let code = Parser::new(Lexer::new(line)).file()?;
|
||||
|
||||
let code = WhileElseDesugar.fold_file(code);
|
||||
// Safety: this is totally unsafe
|
||||
unsafe { TREES.push(code) }.collect_in_root(prj)?;
|
||||
|
||||
@ -113,6 +120,21 @@ fn enter_code(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
||||
})
|
||||
}
|
||||
|
||||
fn live_desugar() -> Result<(), Box<dyn Error>> {
|
||||
read_and(C_RESV, "se>", |line| {
|
||||
let code = Parser::new(Lexer::new(line)).stmt()?;
|
||||
println!("Raw, as parsed:\n{C_LISTING}{code}\x1b[0m");
|
||||
|
||||
let code = SquashGroups.fold_stmt(code);
|
||||
println!("SquashGroups\n{C_LISTING}{code}\x1b[0m");
|
||||
|
||||
let code = WhileElseDesugar.fold_stmt(code);
|
||||
println!("WhileElseDesugar\n{C_LISTING}{code}\x1b[0m");
|
||||
|
||||
Ok(Response::Accept)
|
||||
})
|
||||
}
|
||||
|
||||
fn query_type_expression(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
||||
read_and(C_RESV, "ty>", |line| {
|
||||
if line.trim().is_empty() {
|
||||
|
@ -112,10 +112,16 @@ pub mod program {
|
||||
self.parse_file().or_else(|_| self.parse_stmt())
|
||||
}
|
||||
pub fn parse_stmt(&self) -> PResult<Program<'t, Parsed>> {
|
||||
Ok(Program { data: Parsed::Stmt(Parser::new(self.lex()).stmt()?), text: self.text })
|
||||
let stmt = Parser::new(self.lex()).stmt()?;
|
||||
// let stmt = WhileElseDesugar.fold_stmt(stmt);
|
||||
|
||||
Ok(Program { data: Parsed::Stmt(stmt), text: self.text })
|
||||
}
|
||||
pub fn parse_file(&self) -> PResult<Program<'t, Parsed>> {
|
||||
Ok(Program { data: Parsed::File(Parser::new(self.lex()).file()?), text: self.text })
|
||||
let file = Parser::new(self.lex()).file()?;
|
||||
// let file = WhileElseDesugar.fold_file(file);
|
||||
|
||||
Ok(Program { data: Parsed::File(file), text: self.text })
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user