Skip to content

Commit

Permalink
refactor: start of abstacting away ast nodes into an enum.
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Mar 16, 2024
1 parent faad477 commit 7dd03cb
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 130 deletions.
2 changes: 0 additions & 2 deletions crates/fuse-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ pub enum BinaryOperatorKind {
Modulo(Span),
ShiftLeft(Span),
ShiftRight(Span),
Member(Span),
}

impl GetSpan for BinaryOperatorKind {
Expand All @@ -380,7 +379,6 @@ impl GetSpan for BinaryOperatorKind {
Self::Modulo(span) => span,
Self::ShiftLeft(span) => span,
Self::ShiftRight(span) => span,
Self::Member(span) => span,
};
*span
}
Expand Down
47 changes: 47 additions & 0 deletions crates/fuse-ast/src/ast_node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::ast::*;

#[derive(Debug, Clone, Copy)]
pub enum AstNode<'a> {
// Primary nodes
Chunk(&'a Chunk),
Block(&'a Block),

// Statement related
EmptyStatement(&'a EmptyStatement),
ImplStatement(&'a ImplStatement),
EnumDeclaration(&'a EnumDeclaration),
StructDeclaration(&'a StructDeclaration),
FunctionDeclaration(&'a Function),
VariableDeclaration(&'a VariableDeclaration),

// expression related
FunctionExpression(&'a Function),
ArrayExpression(&'a ArrayExpression),
ParenthesizedExpression(&'a ParenthesizedExpression),
ConstructionExpression(&'a ConstructionExpression),
StructConstructionExpression(&'a StructConstructionExpression),
If(&'a If),
Else(&'a Else),

// function inner nodes
FunctionSignature(&'a FunctionSignature),
FunctionParameters(&'a FunctionParameters),
FunctionParameter(&'a FunctionParameter),
FunctionBody(&'a FunctionBody),

EnumVariant(&'a EnumVariant),

StructField(&'a StructField),

VisibilityModifier(&'a VisibilityModifier),

// literals
NumberLiteral(&'a NumberLiteral),
StringLiteral(&'a StringLiteral),
BooleanLiteral(&'a BooleanLiteral),

Identifier(&'a Identifier),

UnaryOperator(&'a UnaryOperator),
BinaryOperator(&'a BinaryOperator),
}
2 changes: 2 additions & 0 deletions crates/fuse-ast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod ast_factory;
mod ast_node;
mod get_span;
mod precedence;

pub mod ast;

pub use ast::*;
pub use ast_factory::*;
pub use ast_node::*;
pub use get_span::*;
pub use precedence::*;
1 change: 0 additions & 1 deletion crates/fuse-parser/src/parsers/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ impl<'a> Parser<'a> {
Percent => Modulo
LShift => ShiftLeft
RShift => ShiftRight
Dot => Member
}
}

Expand Down
132 changes: 68 additions & 64 deletions crates/fuse-semantic/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::collections::HashMap;

use fuse_ast::{
Atom, BinaryOperator, BinaryOperatorKind, BindingPatternKind, CallExpression, Chunk,
Expression, Function, Identifier, VariableDeclaration,
Atom, BindingPatternKind, Chunk, Function, Identifier, MemberExpression, MemberExpressionLHS,
MemberExpressionRHS, VariableDeclaration,
};
use fuse_common::ReferenceType;
use fuse_visitor::{
walk_binary_operator_mut, walk_call_expression_mut, walk_function_mut,
walk_variable_declaration_mut, ScopeVisitor, VisitorMut,
walk_function_mut, walk_member_expression_mut, walk_variable_declaration_mut, ScopeVisitor,
VisitorMut,
};

#[derive(Debug, PartialEq, Clone, Copy)]
Expand All @@ -31,9 +31,9 @@ impl PartialEq<ReferenceType> for ScopeId {
}
}

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

impl IdentifierMap {
impl IdentDeclMap {
fn new() -> Self {
Self(HashMap::new())
}
Expand All @@ -54,30 +54,31 @@ enum ReferenceKind {

struct ScopeTree {
current: ScopeId,
identifier_maps: Vec<IdentifierMap>,
ident_decl_maps: Vec<IdentDeclMap>,
/// Maps between `ReferenceId` and `ReferenceKind`
reference_kinds: Vec<ReferenceKind>,
parent_ids: Vec<ScopeId>,
}

/// Tree operations for `ScopeTree`
impl ScopeTree {
fn root_scope() -> Self {
Self {
current: ScopeId(0),
parent_ids: vec![ScopeId(0)],
identifier_maps: vec![IdentifierMap::new()],
ident_decl_maps: vec![IdentDeclMap::new()],
reference_kinds: Vec::new(),
}
}

fn push_stack(&mut self) -> ScopeId {
self.identifier_maps.push(IdentifierMap::new());
self.ident_decl_maps.push(IdentDeclMap::new());
self.parent_ids.push(self.current);

// length of all arrays should be same.
debug_assert!(self.identifier_maps.len() == self.parent_ids.len());
debug_assert!(self.ident_decl_maps.len() == self.parent_ids.len());

self.current = ScopeId(self.identifier_maps.len() - 1);
self.current = ScopeId(self.ident_decl_maps.len() - 1);
self.current
}

Expand All @@ -90,13 +91,32 @@ impl ScopeTree {
self.current = self.parent();
}

fn parent(&self) -> ScopeId {
assert_ne!(
self.current, 0,
"Attempt to access the root scope's parent."
);
self.parent_ids[self.current.as_index()]
}

fn parent_of(&self, children_id: ScopeId) -> ScopeId {
assert_ne!(
self.current, 0,
"Attempt to access the root scope's parent."
);
self.parent_ids[children_id.as_index()]
}
}

/// Identifier operations for `ScopeTree`
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<ReferenceType> {
fn scope_identifier_reference(&mut self, atom: &Atom) -> Option<ReferenceType> {
let mut scope_id = self.current;
let mut reference;
loop {
reference = self.identifier_maps[scope_id.as_index()].get(atom);
reference = self.ident_decl_maps[scope_id.as_index()].get(atom);

if reference.is_some() || scope_id.is_root() {
break;
Expand All @@ -109,29 +129,20 @@ impl ScopeTree {

/// 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(
fn set_scope_identifier_reference(
&mut self,
atom: Atom,
ref_id: ReferenceType,
ref_kind: ReferenceKind,
) -> Option<ReferenceType> {
self.identifier_maps[self.current.as_index()].insert(atom, ref_id)
}

fn parent(&self) -> ScopeId {
assert_ne!(
self.current, 0,
"Attempt to access the root scope's parent."
);
self.parent_ids[self.current.as_index()]
self.ident_decl_maps[self.current.as_index()].insert(atom, ref_id)
}

fn parent_of(&self, children_id: ScopeId) -> ScopeId {
assert_ne!(
self.current, 0,
"Attempt to access the root scope's parent."
);
self.parent_ids[children_id.as_index()]
fn member_identifier_reference(
&mut self,
atom: Atom,
ref_id: ReferenceType,
) -> Option<ReferenceType> {
self.ident_decl_maps[self.current.as_index()].insert(atom, ref_id)
}
}

Expand Down Expand Up @@ -159,23 +170,29 @@ impl<'ast> Semantic<'ast> {

fn declare_identifier(&mut self, ident: &Identifier) {
self.last_reference += 1;
self.scope.set_identifier_reference(
ident.name.clone(),
self.last_reference,
ReferenceKind::Scope,
);
self.scope
.set_scope_identifier_reference(ident.name.clone(), self.last_reference);
ident.reference.set(Some(self.last_reference))
}

fn reference_scope_identifier(&mut self, ident: &Identifier) {
let reference = self.scope.identifier_reference(&ident.name);
let reference = self.scope.scope_identifier_reference(&ident.name);
ident.reference.set(reference)
}

fn reference_member_identifier(&mut self, ident: &Identifier, sup: Option<&Identifier>) {
let reference = self.scope.identifier_reference(&ident.name);
fn resolve_member_identifier(&mut self, ident: &Identifier, sup: Option<&Identifier>) {
let Some(sup) = sup else {
return self.declare_member_identifier(ident, None);
};
let reference = self.scope.scope_identifier_reference(&ident.name);
ident.reference.set(reference);
// todo!()
}

fn declare_member_identifier(&mut self, ident: &Identifier, sup: Option<&Identifier>) {
let reference = self.scope.scope_identifier_reference(&ident.name);
ident.reference.set(reference);
todo!()
// todo!()
}
}

Expand Down Expand Up @@ -205,33 +222,20 @@ impl<'ast> VisitorMut<'ast> for Semantic<'ast> {
walk_function_mut(self, decl)
}

fn visit_binary_operator_mut(&mut self, op: &'ast mut BinaryOperator) {
match &op.kind {
BinaryOperatorKind::Member(_) => {
println!("{:?}", op);
let rhs = match &op.rhs {
Expression::Identifier(rhs) => rhs,
Expression::BinaryOperator(op) => match &**op {
BinaryOperator {
kind: BinaryOperatorKind::Member(..),
lhs: Expression::Identifier(lhs),
..
} => lhs,
BinaryOperator {
kind: BinaryOperatorKind::Member(..),
lhs: Expression::ParenthesizedExpression(expr),
..
} => todo!(),
_ => {
todo!()
}
},
_ => panic!("Right hand side of a member(.) operator should be an identifier"),
};
fn visit_member_expression_mut(&mut self, member: &'ast mut MemberExpression) {
let lhs = member.lhs.as_ref();
let rhs = member.rhs.as_ref();
let sup = match lhs {
MemberExpressionLHS::Identifier(ident) => {
self.reference_scope_identifier(ident);
Some(ident)
}
_ => {}
_ => None,
};
if let MemberExpressionRHS::Identifier(ident) = rhs {
self.resolve_member_identifier(ident, sup)
}
walk_binary_operator_mut(self, op)
walk_member_expression_mut(self, member)
}
}

Expand Down
6 changes: 4 additions & 2 deletions crates/fuse-visitor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod node_visitor;
mod scope_visitor;
mod visitor;
mod visitor_mut;

pub use node_visitor::*;
pub use scope_visitor::*;
pub use visitor::*;
pub use visitor_mut::*;
Expand All @@ -26,9 +28,9 @@ macro_rules! visit_list {

#[macro_export]
macro_rules! visit_scope {
($visitor:ident => $block:block) => {
($visitor:ident => $block:expr) => {
$visitor.enter_scope();
$block
$block;
$visitor.leave_scope();
};
}
6 changes: 6 additions & 0 deletions crates/fuse-visitor/src/node_visitor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use fuse_ast::AstNode;

pub trait NodeVisitor {
fn enter_node(&mut self, node: AstNode) {}
fn leave_node(&mut self, node: AstNode) {}
}
Loading

0 comments on commit 7dd03cb

Please sign in to comment.