schala/schala-lang/language/src/ast/visitor.rs

199 lines
6.3 KiB
Rust
Raw Normal View History

2019-09-25 18:41:07 -07:00
use crate::ast::*;
2021-10-24 00:08:26 -07:00
#[derive(Debug)]
pub enum Recursion {
Continue,
2021-10-28 02:00:37 -07:00
Stop,
2021-10-24 00:08:26 -07:00
}
2021-10-24 00:08:26 -07:00
pub trait ASTVisitor: Sized {
2021-10-28 02:00:37 -07:00
fn expression(&mut self, _expression: &Expression) -> Recursion {
Recursion::Continue
}
fn declaration(&mut self, _declaration: &Declaration, _id: &ItemId) -> Recursion {
Recursion::Continue
}
2021-10-28 02:00:37 -07:00
fn import(&mut self, _import: &ImportSpecifier) -> Recursion {
Recursion::Continue
}
fn module(&mut self, _module: &ModuleSpecifier) -> Recursion {
Recursion::Continue
}
2021-10-28 02:00:37 -07:00
fn pattern(&mut self, _pat: &Pattern) -> Recursion {
Recursion::Continue
}
}
pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) {
walk_block(v, &ast.statements);
}
pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
use StatementKind::*;
2021-10-26 14:05:27 -07:00
for statement in block.statements.iter() {
match statement.kind {
StatementKind::Expression(ref expr) => {
walk_expression(v, expr);
}
Declaration(ref decl) => {
walk_declaration(v, decl, &statement.id);
}
2021-10-24 00:08:26 -07:00
Import(ref import_spec) => {
v.import(import_spec);
2021-10-28 02:00:37 -07:00
}
Module(ref module_spec) =>
2021-10-24 00:08:26 -07:00
if let Recursion::Continue = v.module(module_spec) {
walk_block(v, &module_spec.contents);
2021-10-28 02:00:37 -07:00
},
}
}
}
2021-10-26 11:37:43 -07:00
pub fn walk_declaration<V: ASTVisitor>(v: &mut V, decl: &Declaration, id: &ItemId) {
use Declaration::*;
if let Recursion::Continue = v.declaration(decl, id) {
2021-10-24 00:08:26 -07:00
match decl {
FuncDecl(_sig, block) => {
walk_block(v, block);
}
2021-10-28 02:00:37 -07:00
Binding { name: _, constant: _, type_anno: _, expr } => {
2021-10-24 00:08:26 -07:00
walk_expression(v, expr);
}
_ => (),
};
}
}
2021-10-26 11:37:43 -07:00
pub fn walk_expression<V: ASTVisitor>(v: &mut V, expr: &Expression) {
use ExpressionKind::*;
2021-10-24 00:08:26 -07:00
if let Recursion::Continue = v.expression(expr) {
match &expr.kind {
NatLiteral(_) | FloatLiteral(_) | StringLiteral(_) | BoolLiteral(_) | Value(_) => (),
BinExp(_, lhs, rhs) => {
2021-10-26 13:37:03 -07:00
walk_expression(v, lhs);
walk_expression(v, rhs);
}
2021-10-24 00:08:26 -07:00
PrefixExp(_, arg) => {
2021-10-26 13:37:03 -07:00
walk_expression(v, arg);
}
2021-10-28 02:00:37 -07:00
TupleLiteral(exprs) =>
2021-10-24 00:08:26 -07:00
for expr in exprs {
2021-10-26 13:37:03 -07:00
walk_expression(v, expr);
2021-10-28 02:00:37 -07:00
},
NamedStruct { name: _, fields } =>
2021-10-24 00:08:26 -07:00
for (_, expr) in fields.iter() {
walk_expression(v, expr);
2021-10-28 02:00:37 -07:00
},
2021-10-24 00:08:26 -07:00
Call { f, arguments } => {
2021-10-26 13:37:03 -07:00
walk_expression(v, f);
2021-10-24 00:08:26 -07:00
for arg in arguments.iter() {
match arg {
InvocationArgument::Positional(expr) => walk_expression(v, expr),
InvocationArgument::Keyword { expr, .. } => walk_expression(v, expr), //TODO maybe I can combine this pattern
_ => (),
}
}
}
2021-10-24 00:08:26 -07:00
Index { indexee, indexers } => {
2021-10-26 13:37:03 -07:00
walk_expression(v, indexee);
2021-10-24 00:08:26 -07:00
for indexer in indexers.iter() {
walk_expression(v, indexer);
}
}
2021-10-28 02:00:37 -07:00
IfExpression { discriminator, body } => {
2021-10-24 00:08:26 -07:00
if let Some(d) = discriminator.as_ref() {
2021-10-26 13:37:03 -07:00
walk_expression(v, d);
2021-10-24 00:08:26 -07:00
}
2021-10-26 13:37:03 -07:00
walk_if_expr_body(v, body.as_ref());
}
2021-10-24 00:08:26 -07:00
WhileExpression { condition, body } => {
if let Some(d) = condition.as_ref() {
walk_expression(v, d);
}
2021-10-26 13:37:03 -07:00
walk_block(v, body);
2021-10-24 00:08:26 -07:00
}
ForExpression { enumerators, body } => {
for enumerator in enumerators {
walk_expression(v, &enumerator.generator);
}
match body.as_ref() {
ForBody::MonadicReturn(expr) => walk_expression(v, expr),
ForBody::StatementBlock(block) => walk_block(v, block),
};
}
2021-10-28 02:00:37 -07:00
Lambda { params: _, type_anno: _, body } => {
2021-10-26 13:37:03 -07:00
walk_block(v, body);
2021-10-24 00:08:26 -07:00
}
2021-10-28 02:00:37 -07:00
ListLiteral(exprs) =>
2021-10-24 00:08:26 -07:00
for expr in exprs {
2021-10-26 13:37:03 -07:00
walk_expression(v, expr);
2021-10-28 02:00:37 -07:00
},
2021-10-24 00:08:26 -07:00
};
}
}
2021-10-26 11:37:43 -07:00
pub fn walk_if_expr_body<V: ASTVisitor>(v: &mut V, body: &IfExpressionBody) {
use IfExpressionBody::*;
match body {
2021-10-28 02:00:37 -07:00
SimpleConditional { then_case, else_case } => {
walk_block(v, then_case);
if let Some(block) = else_case.as_ref() {
walk_block(v, block)
}
}
2021-10-28 02:00:37 -07:00
SimplePatternMatch { pattern, then_case, else_case } => {
walk_pattern(v, pattern);
2021-10-26 13:37:03 -07:00
walk_block(v, then_case);
if let Some(block) = else_case.as_ref() {
walk_block(v, block)
}
}
2021-10-28 02:00:37 -07:00
CondList(arms) =>
for arm in arms {
match arm.condition {
Condition::Pattern(ref pat) => {
walk_pattern(v, pat);
}
Condition::TruncatedOp(ref _binop, ref expr) => {
walk_expression(v, expr);
}
Condition::Expression(ref expr) => {
walk_expression(v, expr);
}
2021-10-26 01:03:06 -07:00
Condition::Else => (),
}
2021-10-26 01:03:06 -07:00
if let Some(ref guard) = arm.guard {
2021-10-26 13:37:03 -07:00
walk_expression(v, guard);
2021-10-26 01:03:06 -07:00
}
walk_block(v, &arm.body);
2021-10-28 02:00:37 -07:00
},
}
}
2021-10-26 11:37:43 -07:00
pub fn walk_pattern<V: ASTVisitor>(v: &mut V, pat: &Pattern) {
use Pattern::*;
2021-10-24 00:08:26 -07:00
if let Recursion::Continue = v.pattern(pat) {
match pat {
2021-10-28 02:00:37 -07:00
TuplePattern(patterns) =>
2021-10-24 00:08:26 -07:00
for pat in patterns {
walk_pattern(v, pat);
2021-10-28 02:00:37 -07:00
},
TupleStruct(_, patterns) =>
2021-10-24 00:08:26 -07:00
for pat in patterns {
walk_pattern(v, pat);
2021-10-28 02:00:37 -07:00
},
Record(_, name_and_patterns) =>
2021-10-24 00:08:26 -07:00
for (_, pat) in name_and_patterns {
walk_pattern(v, pat);
2021-10-28 02:00:37 -07:00
},
2021-10-24 00:08:26 -07:00
_ => (),
};
}
2019-09-25 18:41:07 -07:00
}