Skip to content

Commit

Permalink
refactor(visitor): move visitors to their own crate.
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Mar 11, 2024
1 parent f44bfa1 commit ba3ef8e
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 71 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fuse_common = { version = "0.0.0", path = "crates/fuse-common" }
fuse_common_proc = { version = "0.0.0", path = "crates/fuse-common-proc" }
fuse_parser = { version = "0.0.0", path = "crates/fuse-parser" }
fuse_semantic = { version = "0.0.0", path = "crates/fuse-semantic" }
fuse_visitor = { version = "0.0.0", path = "crates/fuse-visitor" }
fusec = { version = "0.0.0", path = "crates/fusec" }

thiserror = { version = "1.0" }
Expand Down
4 changes: 2 additions & 2 deletions crates/fuse-ast/src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fuse_common::{ReferenceId, Span};
use fuse_common::{ReferenceType, Span};
use fuse_common_proc::serializable;
use std::{cell::Cell, rc::Rc};

Expand Down Expand Up @@ -185,7 +185,7 @@ pub enum InterpolationFormat {
pub struct Identifier {
pub span: Span,
pub name: Atom,
pub reference: Cell<Option<ReferenceId>>,
pub reference: Cell<Option<ReferenceType>>,
}

#[serializable]
Expand Down
5 changes: 2 additions & 3 deletions crates/fuse-ast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
mod ast;
mod ast_factory;
mod precedence;
mod visit;

pub mod ast;

pub use ast::*;
pub use ast_factory::*;
pub use precedence::*;
pub use visit::*;
4 changes: 2 additions & 2 deletions crates/fuse-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
mod debug;
mod span;
mod span_view;
mod debug;

pub use span::*;
pub use span_view::*;

pub type ReferenceId = usize;
pub type ReferenceType = usize;
1 change: 1 addition & 0 deletions crates/fuse-semantic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ edition.workspace = true
[dependencies]
fuse_ast = { workspace = true }
fuse_common = { workspace = true }
fuse_visitor = { workspace = true }
41 changes: 23 additions & 18 deletions crates/fuse-semantic/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
use std::collections::HashMap;

use fuse_ast::{
walk_binding_pattern, walk_function, walk_variable_declaration, Atom, BindingPattern,
BindingPatternKind, Chunk, Identifier, VariableDeclaration, Visitor,
};
use fuse_common::ReferenceId;
use fuse_ast::{Atom, BindingPattern, BindingPatternKind, Chunk, Identifier, VariableDeclaration};
use fuse_common::ReferenceType;
use fuse_visitor::{walk_binding_pattern, walk_function, walk_variable_declaration, Visitor};

#[derive(Debug, PartialEq, Clone, Copy)]
struct ScopeId(ReferenceId);
struct ScopeId(ReferenceType);

impl ScopeId {
#[inline(always)]
const fn as_index(self) -> ReferenceId {
const fn as_index(self) -> ReferenceType {
self.0
}

Expand All @@ -21,24 +19,24 @@ impl ScopeId {
}
}

impl PartialEq<ReferenceId> for ScopeId {
fn eq(&self, other: &ReferenceId) -> bool {
impl PartialEq<ReferenceType> for ScopeId {
fn eq(&self, other: &ReferenceType) -> bool {
self.0 == *other
}
}

struct IdentifierMap(HashMap<Atom, ReferenceId>);
struct IdentifierMap(HashMap<Atom, ReferenceType>);

impl IdentifierMap {
fn new() -> Self {
Self(HashMap::new())
}

fn insert(&mut self, atom: Atom, ref_id: ReferenceId) -> Option<ReferenceId> {
fn insert(&mut self, atom: Atom, ref_id: ReferenceType) -> Option<ReferenceType> {
self.0.insert(atom, ref_id)
}

fn get(&self, atom: &Atom) -> Option<ReferenceId> {
fn get(&self, atom: &Atom) -> Option<ReferenceType> {
self.0.get(atom).map(|r| r.clone())
}
}
Expand Down Expand Up @@ -80,7 +78,7 @@ impl ScopeTree {

/// Get an identifier reference from current scope or its parents.
/// This function is implemented using loops instead of recursion.
fn identifier_reference(&mut self, atom: &Atom) -> Option<ReferenceId> {
fn identifier_reference(&mut self, atom: &Atom) -> Option<ReferenceType> {
let mut scope_id = self.current;
let mut reference;
loop {
Expand All @@ -95,9 +93,13 @@ impl ScopeTree {
reference
}

/// Set a `ReferenceId` for the given identifier's `Atom` in the current scope.
/// Would return the last `ReferenceId` if we are shadowing it.
fn set_identifier_reference(&mut self, atom: Atom, ref_id: ReferenceId) -> Option<ReferenceId> {
/// Set a `ReferenceType` for the given identifier's `Atom` in the current scope.
/// Would return the last `ReferenceType` if we are shadowing it.
fn set_identifier_reference(
&mut self,
atom: Atom,
ref_id: ReferenceType,
) -> Option<ReferenceType> {
self.identifier_maps[self.current.as_index()].insert(atom, ref_id)
}

Expand All @@ -122,7 +124,7 @@ pub struct Semantic<'ast> {
source: &'ast str,
chunk: &'ast Chunk,
scope: ScopeTree,
last_reference: ReferenceId,
last_reference: ReferenceType,
}

impl<'ast> Semantic<'ast> {
Expand Down Expand Up @@ -165,7 +167,10 @@ impl<'ast> Visitor<'ast> for Semantic<'ast> {
}

fn visit_identifier(&mut self, ident: &Identifier) {
self.reference_identifier(ident);
let refer = unsafe { ident.reference.as_ptr().as_ref() };
if refer.is_none() {
self.reference_identifier(ident);
}
}

fn visit_variable_declaration(&mut self, decl: &'ast VariableDeclaration) {
Expand Down
10 changes: 10 additions & 0 deletions crates/fuse-visitor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "fuse_visitor"
version = "0.0.0"
authors.workspace = true
license.workspace = true
repository.workspace = true
edition.workspace = true

[dependencies]
fuse_ast = { workspace = true }
33 changes: 33 additions & 0 deletions crates/fuse-visitor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
mod visitor;
mod visitor_mut;

pub use visitor::*;
pub use visitor_mut::*;

/// Placeholder macro for visiting, It is used instead of calling visitor methods directly.
/// Would be useful if we need some operation to happen for every visit.
#[macro_export]
macro_rules! visit {
($expr:expr) => {
$expr
};
}

#[macro_export]
macro_rules! visit_list {
($visitor:ident.$method:ident($list:expr $(, $($extra_args:expr), *)?)) => {
for elem in $list {
visit!($visitor.$method(elem $(, $($extra_args),*)?))
}
};
}

#[macro_export]
macro_rules! visit_scope {
($visitor:ident => $block:block) => {
$visitor.enter_scope();
$block
$visitor.leave_scope();
};
}

69 changes: 23 additions & 46 deletions crates/fuse-ast/src/visit.rs → crates/fuse-visitor/src/visitor.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,8 @@
// based on https://rust-unofficial.github.io/patterns/patterns/behavioural/visitor.html
// and https://github.com/rust-lang/rust/blob/5bc7b9ac8ace5312e1d2cdc2722715cf58d4f926/compiler/rustc_ast_ir/src/visit.rs

use crate::ast::*;

/// Placeholder macro for visiting, It is used instead of calling visitor methods directly.
/// Would be useful if we need some operation to happen for every visit.
macro_rules! visit {
($expr:expr) => {
$expr
};
}

macro_rules! visit_list {
($visitor:ident.$method:ident($list:expr $(, $($extra_args:expr), *)?)) => {
for elem in $list {
visit!($visitor.$method(elem $(, $($extra_args),*)?))
}
};
}

macro_rules! visit_scope {
($visitor:ident => $block:block) => {
$visitor.enter_scope();
$block
$visitor.leave_scope();
};
}
use fuse_ast::ast::*;
use crate::{visit, visit_scope, visit_list};

pub trait Visitor<'ast>: Sized {
fn enter_scope(&mut self) {}
Expand All @@ -41,37 +18,37 @@ pub trait Visitor<'ast>: Sized {
}

fn visit_statement(&mut self, statement: &'ast Statement) {
walk_statement(self, &statement)
walk_statement(self, statement)
}

fn visit_variable_declaration(&mut self, decl: &'ast VariableDeclaration) {
walk_variable_declaration(self, &decl)
walk_variable_declaration(self, decl)
}

fn visit_function_declaration(&mut self, decl: &'ast Function) {
walk_function(self, &decl)
walk_function(self, decl)
}

fn visit_enum_declaration(&mut self, decl: &'ast EnumDeclaration) {
walk_enum_declaration(self, &decl)
walk_enum_declaration(self, decl)
}

fn visit_enum_variant(&mut self, var: &'ast EnumVariant) {
walk_enum_variant(self, &var)
walk_enum_variant(self, var)
}

fn visit_struct_declaration(&mut self, decl: &'ast StructDeclaration) {
walk_struct_declaration(self, &decl)
walk_struct_declaration(self, decl)
}

fn visit_struct_field(&mut self, field: &'ast StructField) {
walk_struct_field(self, &field)
walk_struct_field(self, field)
}

fn visit_visibility_modifier(&mut self, _: &'ast VisibilityModifier) {}

fn visit_expression(&mut self, expression: &'ast Expression) {
walk_expression(self, &expression)
walk_expression(self, expression)
}

fn visit_number_literal(&mut self, _: &'ast NumberLiteral) {}
Expand All @@ -83,31 +60,31 @@ pub trait Visitor<'ast>: Sized {
fn visit_identifier(&mut self, _: &'ast Identifier) {}

fn visit_function(&mut self, func: &'ast Function) {
walk_function(self, &func)
walk_function(self, func)
}

fn visit_function_signature(&mut self, sign: &'ast FunctionSignature) {
walk_function_signature(self, &sign)
walk_function_signature(self, sign)
}

fn visit_function_parameters(&mut self, params: &'ast FunctionParameters) {
walk_function_parameters(self, &params)
walk_function_parameters(self, params)
}

fn visit_function_parameter(&mut self, param: &'ast FunctionParameter) {
walk_function_parameter(self, &param)
walk_function_parameter(self, param)
}

fn visit_function_body(&mut self, body: &'ast FunctionBody) {
walk_function_body(self, &body)
walk_function_body(self, body)
}

fn visit_if(&mut self, r#if: &'ast If) {
walk_if(self, &r#if)
walk_if(self, r#if)
}

fn visit_else(&mut self, r#else: &'ast Else) {
walk_else(self, &r#else)
walk_else(self, r#else)
}

fn visit_unary_operator(&mut self, op: &'ast UnaryOperator) {
Expand Down Expand Up @@ -151,27 +128,27 @@ pub trait Visitor<'ast>: Sized {
}

fn visit_binding_pattern(&mut self, pattern: &'ast BindingPattern) {
walk_binding_pattern(self, &pattern)
walk_binding_pattern(self, pattern)
}

fn visit_binding_identifier(&mut self, pattern: &'ast BindingIdentifier) {
walk_binding_identifier(self, &pattern)
walk_binding_identifier(self, pattern)
}

fn visit_binding_rest(&mut self, arg: &'ast BindingRest) {
walk_binding_rest(self, &arg)
walk_binding_rest(self, arg)
}

fn visit_key_value_argument(&mut self, arg: &'ast KeyValueArgument) {
walk_key_value_argument(self, &arg)
walk_key_value_argument(self, arg)
}

fn visit_spread_argument(&mut self, arg: &'ast SpreadArgument) {
walk_spread_argument(self, &arg)
walk_spread_argument(self, arg)
}

fn visit_type_annotation(&mut self, annotation: &'ast TypeAnnotation) {
walk_type_annotation(self, &annotation)
walk_type_annotation(self, annotation)
}
}

Expand Down

0 comments on commit ba3ef8e

Please sign in to comment.