Skip to content

Commit

Permalink
feat(ast): add SymbolId and ReferenceId (#755)
Browse files Browse the repository at this point in the history
Closes #510
  • Loading branch information
hyf0 authored Aug 19, 2023
1 parent fd3fa6c commit e7c2313
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 30 deletions.
44 changes: 39 additions & 5 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::fmt;
use std::{cell::Cell, fmt, hash::Hash};

use oxc_allocator::{Box, Vec};
use oxc_span::{Atom, SourceType, Span};
use oxc_syntax::operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
use oxc_syntax::{
operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
},
reference::ReferenceId,
symbol::SymbolId,
};
#[cfg(feature = "serde")]
use serde::Serialize;
Expand Down Expand Up @@ -254,21 +258,51 @@ pub struct IdentifierName {
}

/// Identifier Reference
#[derive(Debug, Clone, Hash)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct IdentifierReference {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
pub name: Atom,
#[cfg_attr(feature = "serde", serde(skip))]
pub reference_id: Cell<Option<ReferenceId>>,
}

impl Hash for IdentifierReference {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.span.hash(state);
self.name.hash(state);
}
}

impl IdentifierReference {
pub fn new(name: Atom, span: Span) -> Self {
Self { name, span, reference_id: Cell::default() }
}
}

/// Binding Identifier
#[derive(Debug, Clone, Hash)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
pub struct BindingIdentifier {
#[cfg_attr(feature = "serde", serde(flatten))]
pub span: Span,
pub name: Atom,
#[cfg_attr(feature = "serde", serde(skip))]
pub symbol_id: Cell<Option<SymbolId>>,
}

impl Hash for BindingIdentifier {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.span.hash(state);
self.name.hash(state);
}
}

impl BindingIdentifier {
pub fn new(name: Atom, span: Span) -> Self {
Self { name, span, symbol_id: Cell::default() }
}
}

/// Label Identifier
Expand Down
7 changes: 4 additions & 3 deletions crates/oxc_ast_lower/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ impl<'a> AstLower<'a> {
self.hir.with_statement(stmt.span, object, body)
}

#[allow(clippy::too_many_lines)]
fn lower_expression(&mut self, expr: &ast::Expression<'a>) -> hir::Expression<'a> {
ensure_sufficient_stack(|| {
match expr {
Expand Down Expand Up @@ -444,15 +445,15 @@ impl<'a> AstLower<'a> {
ast::Expression::JSXElement(elem) => {
// TODO: implement JSX
let ident = self.lower_identifier_reference(
&ast::IdentifierReference { span: elem.span, name: "undefined".into() },
&ast::IdentifierReference::new("undefined".into(), elem.span),
ReferenceFlag::Read,
);
self.hir.identifier_reference_expression(ident)
}
ast::Expression::JSXFragment(elem) => {
// TODO: implement JSX
let ident = self.lower_identifier_reference(
&ast::IdentifierReference { span: elem.span, name: "undefined".into() },
&ast::IdentifierReference::new("undefined".into(), elem.span),
ReferenceFlag::Read,
);
self.hir.identifier_reference_expression(ident)
Expand Down Expand Up @@ -850,7 +851,7 @@ impl<'a> AstLower<'a> {
expr => {
// return undefined because this is invalid syntax
let ident = self.lower_identifier_reference(
&ast::IdentifierReference { span: expr.span(), name: "undefined".into() },
&ast::IdentifierReference::new("undefined".into(), expr.span()),
ReferenceFlag::Write,
);
self.hir.assignment_target_identifier(ident)
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_parser/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ impl<'a> Parser<'a> {
// ^ BindingIdentifier
if let PropertyKey::Identifier(ident) = &key {
shorthand = true;
let binding_identifier =
BindingIdentifier { span: ident.span, name: ident.name.clone() };
let binding_identifier = BindingIdentifier::new(ident.name.clone(), ident.span);
let identifier = self.ast.binding_identifier(binding_identifier);
let left = self.ast.binding_pattern(identifier, None, false);
self.parse_initializer(span, left)?
Expand Down
6 changes: 4 additions & 2 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::Cell;

use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_diagnostics::Result;
Expand Down Expand Up @@ -55,7 +57,7 @@ impl<'a> Parser<'a> {
}
let (span, name) = self.parse_identifier_kind(Kind::Ident);
self.check_identifier(span, &name);
Ok(IdentifierReference { span, name })
Ok(IdentifierReference { span, name, reference_id: Cell::default() })
}

/// `BindingIdentifier` : Identifier
Expand All @@ -65,7 +67,7 @@ impl<'a> Parser<'a> {
}
let (span, name) = self.parse_identifier_kind(Kind::Ident);
self.check_identifier(span, &name);
Ok(BindingIdentifier { span, name })
Ok(BindingIdentifier { span, name, symbol_id: Cell::default() })
}

pub(crate) fn parse_label_identifier(&mut self) -> Result<LabelIdentifier> {
Expand Down
4 changes: 3 additions & 1 deletion crates/oxc_parser/src/js/function.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::Cell;

use oxc_allocator::Box;
use oxc_ast::{ast::*, AstBuilder};
use oxc_diagnostics::Result;
Expand Down Expand Up @@ -332,7 +334,7 @@ impl<'a> Parser<'a> {
let id = self.cur_kind().is_binding_identifier().then(|| {
let (span, name) = self.parse_identifier_kind(Kind::Ident);
self.check_identifier(span, &name);
BindingIdentifier { span, name }
BindingIdentifier { span, name, symbol_id: Cell::default() }
});
self.ctx = ctx;

Expand Down
3 changes: 2 additions & 1 deletion crates/oxc_parser/src/js/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ impl<'a> CoverGrammar<'a, ObjectProperty<'a>> for AssignmentTargetProperty<'a> {
if property.shorthand {
let binding = match property.key {
PropertyKey::Identifier(ident) => {
IdentifierReference { span: ident.span, name: ident.unbox().name }
let ident = ident.unbox();
IdentifierReference::new(ident.name, ident.span)
}
_ => return Err(p.unexpected()),
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_parser/src/ts/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ impl<'a> Parser<'a> {
let span = self.start_span();
let (ident_span, name) = self.parse_identifier_kind(Kind::This);
let type_annotation = self.parse_ts_type_annotation()?;
let kind = self.ast.binding_identifier(BindingIdentifier { span: ident_span, name });
let kind = self.ast.binding_identifier(BindingIdentifier::new(name, ident_span));
let binding = self.ast.binding_pattern(kind, type_annotation, /* optional */ false);
Ok(self.ast.formal_parameter(
self.end_span(span),
Expand Down
36 changes: 26 additions & 10 deletions crates/oxc_semantic/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ impl<'a> Binder for VariableDeclarator<'a> {
};
self.id.bound_names(&mut |ident| {
let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes);
ident.symbol_id.set(Some(symbol_id));
if self.kind == VariableDeclarationKind::Var
&& !builder.scope.get_flags(current_scope_id).is_var()
{
Expand Down Expand Up @@ -59,12 +60,13 @@ impl<'a> Binder for Class<'a> {
fn bind(&self, builder: &mut SemanticBuilder) {
let Some(ident) = &self.id else { return };
if !self.modifiers.contains(ModifierKind::Declare) {
builder.declare_symbol(
let symbol_id = builder.declare_symbol(
ident.span,
&ident.name,
SymbolFlags::Class,
SymbolFlags::ClassExcludes,
);
ident.symbol_id.set(Some(symbol_id));
}
}
}
Expand Down Expand Up @@ -108,13 +110,14 @@ impl<'a> Binder for Function<'a> {
)
};

builder.declare_symbol_on_scope(
let symbol_id = builder.declare_symbol_on_scope(
ident.span,
&ident.name,
parent_scope_id,
includes,
excludes,
);
ident.symbol_id.set(Some(symbol_id));
}
}

Expand Down Expand Up @@ -152,7 +155,8 @@ impl<'a> Binder for FormalParameters<'a> {
let is_signature = self.kind == FormalParameterKind::Signature;
self.bound_names(&mut |ident| {
if !is_signature {
builder.declare_symbol(ident.span, &ident.name, includes, excludes);
let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes);
ident.symbol_id.set(Some(symbol_id));
}
});
}
Expand All @@ -167,15 +171,22 @@ impl<'a> Binder for CatchClause<'a> {
// unless CatchParameter is CatchParameter : BindingIdentifier
if let BindingPatternKind::BindingIdentifier(ident) = &param.kind {
let includes = SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable;
builder.declare_shadow_symbol(&ident.name, ident.span, current_scope_id, includes);
let symbol_id = builder.declare_shadow_symbol(
&ident.name,
ident.span,
current_scope_id,
includes,
);
ident.symbol_id.set(Some(symbol_id));
} else {
param.bound_names(&mut |ident| {
builder.declare_symbol(
let symbol_id = builder.declare_symbol(
ident.span,
&ident.name,
SymbolFlags::BlockScopedVariable | SymbolFlags::CatchVariable,
SymbolFlags::BlockScopedVariableExcludes,
);
ident.symbol_id.set(Some(symbol_id));
});
}
}
Expand All @@ -185,35 +196,38 @@ impl<'a> Binder for CatchClause<'a> {
impl<'a> Binder for ModuleDeclaration<'a> {
fn bind(&self, builder: &mut SemanticBuilder) {
self.bound_names(&mut |ident| {
builder.declare_symbol(
let symbol_id = builder.declare_symbol(
ident.span,
&ident.name,
SymbolFlags::ImportBinding,
SymbolFlags::ImportBindingExcludes,
);
ident.symbol_id.set(Some(symbol_id));
});
}
}

impl<'a> Binder for TSTypeAliasDeclaration<'a> {
fn bind(&self, builder: &mut SemanticBuilder) {
builder.declare_symbol(
let symbol_id = builder.declare_symbol(
self.id.span,
&self.id.name,
SymbolFlags::TypeAlias,
SymbolFlags::TypeAliasExcludes,
);
self.id.symbol_id.set(Some(symbol_id));
}
}

impl<'a> Binder for TSInterfaceDeclaration<'a> {
fn bind(&self, builder: &mut SemanticBuilder) {
builder.declare_symbol(
let symbol_id = builder.declare_symbol(
self.id.span,
&self.id.name,
SymbolFlags::Interface,
SymbolFlags::InterfaceExcludes,
);
self.id.symbol_id.set(Some(symbol_id));
}
}

Expand All @@ -226,7 +240,8 @@ impl<'a> Binder for TSEnumDeclaration<'a> {
} else {
SymbolFlags::RegularEnumExcludes
};
builder.declare_symbol(self.id.span, &self.id.name, includes, excludes);
let symbol_id = builder.declare_symbol(self.id.span, &self.id.name, includes, excludes);
self.id.symbol_id.set(Some(symbol_id));
}
}

Expand Down Expand Up @@ -271,11 +286,12 @@ impl<'a> Binder for TSModuleDeclaration<'a> {

impl<'a> Binder for TSTypeParameter<'a> {
fn bind(&self, builder: &mut SemanticBuilder) {
builder.declare_symbol(
let symbol_id = builder.declare_symbol(
self.name.span,
&self.name.name,
SymbolFlags::TypeParameter,
SymbolFlags::TypeParameterExcludes,
);
self.name.symbol_id.set(Some(symbol_id));
}
}
3 changes: 2 additions & 1 deletion crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,8 @@ impl<'a> SemanticBuilder<'a> {
fn reference_identifier(&mut self, ident: &IdentifierReference) {
let flag = self.resolve_reference_usages();
let reference = Reference::new(ident.span, ident.name.clone(), self.current_node_id, flag);
self.declare_reference(reference);
let reference_id = self.declare_reference(reference);
ident.reference_id.set(Some(reference_id));
}

/// Resolve reference flags for the current ast node.
Expand Down
5 changes: 1 addition & 4 deletions crates/oxc_semantic/src/reference.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use bitflags::bitflags;
use oxc_index::define_index_type;
use oxc_span::{Atom, Span};

use crate::{symbol::SymbolId, AstNodeId};

define_index_type! {
pub struct ReferenceId = u32;
}
pub use oxc_syntax::reference::ReferenceId;

#[derive(Debug, Clone)]
pub struct Reference {
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_syntax/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod identifier;
pub mod module_record;
pub mod operator;
pub mod precedence;
pub mod reference;
pub mod scope;
pub mod symbol;

Expand Down
5 changes: 5 additions & 0 deletions crates/oxc_syntax/src/reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use oxc_index::define_index_type;

define_index_type! {
pub struct ReferenceId = u32;
}
7 changes: 7 additions & 0 deletions tasks/coverage/src/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ pub trait Case: Sized + Sync + Send + UnwindSafe {
.with_module_record_builder(true)
.with_check_syntax_error(true)
.build(program);
if let Some(res) = self.check_semantic(&semantic_ret.semantic) {
return res;
}
let errors = parser_ret.errors.into_iter().chain(semantic_ret.errors).collect::<Vec<_>>();

let result = if errors.is_empty() {
Expand Down Expand Up @@ -356,4 +359,8 @@ pub trait Case: Sized + Sync + Send + UnwindSafe {
}
Ok(())
}

fn check_semantic(&self, _semantic: &oxc_semantic::Semantic<'_>) -> Option<TestResult> {
None
}
}
Loading

0 comments on commit e7c2313

Please sign in to comment.