mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
parent
fd3fa6ca84
commit
e7c2313817
14 changed files with 145 additions and 30 deletions
|
|
@ -1,9 +1,13 @@
|
||||||
use std::fmt;
|
use std::{cell::Cell, fmt, hash::Hash};
|
||||||
|
|
||||||
use oxc_allocator::{Box, Vec};
|
use oxc_allocator::{Box, Vec};
|
||||||
use oxc_span::{Atom, SourceType, Span};
|
use oxc_span::{Atom, SourceType, Span};
|
||||||
use oxc_syntax::operator::{
|
use oxc_syntax::{
|
||||||
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
|
operator::{
|
||||||
|
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
|
||||||
|
},
|
||||||
|
reference::ReferenceId,
|
||||||
|
symbol::SymbolId,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
@ -254,21 +258,51 @@ pub struct IdentifierName {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifier Reference
|
/// Identifier Reference
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||||
pub struct IdentifierReference {
|
pub struct IdentifierReference {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: Atom,
|
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
|
/// Binding Identifier
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
#[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))]
|
||||||
pub struct BindingIdentifier {
|
pub struct BindingIdentifier {
|
||||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub name: Atom,
|
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
|
/// Label Identifier
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ impl<'a> AstLower<'a> {
|
||||||
self.hir.with_statement(stmt.span, object, body)
|
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> {
|
fn lower_expression(&mut self, expr: &ast::Expression<'a>) -> hir::Expression<'a> {
|
||||||
ensure_sufficient_stack(|| {
|
ensure_sufficient_stack(|| {
|
||||||
match expr {
|
match expr {
|
||||||
|
|
@ -444,7 +445,7 @@ impl<'a> AstLower<'a> {
|
||||||
ast::Expression::JSXElement(elem) => {
|
ast::Expression::JSXElement(elem) => {
|
||||||
// TODO: implement JSX
|
// TODO: implement JSX
|
||||||
let ident = self.lower_identifier_reference(
|
let ident = self.lower_identifier_reference(
|
||||||
&ast::IdentifierReference { span: elem.span, name: "undefined".into() },
|
&ast::IdentifierReference::new("undefined".into(), elem.span),
|
||||||
ReferenceFlag::Read,
|
ReferenceFlag::Read,
|
||||||
);
|
);
|
||||||
self.hir.identifier_reference_expression(ident)
|
self.hir.identifier_reference_expression(ident)
|
||||||
|
|
@ -452,7 +453,7 @@ impl<'a> AstLower<'a> {
|
||||||
ast::Expression::JSXFragment(elem) => {
|
ast::Expression::JSXFragment(elem) => {
|
||||||
// TODO: implement JSX
|
// TODO: implement JSX
|
||||||
let ident = self.lower_identifier_reference(
|
let ident = self.lower_identifier_reference(
|
||||||
&ast::IdentifierReference { span: elem.span, name: "undefined".into() },
|
&ast::IdentifierReference::new("undefined".into(), elem.span),
|
||||||
ReferenceFlag::Read,
|
ReferenceFlag::Read,
|
||||||
);
|
);
|
||||||
self.hir.identifier_reference_expression(ident)
|
self.hir.identifier_reference_expression(ident)
|
||||||
|
|
@ -850,7 +851,7 @@ impl<'a> AstLower<'a> {
|
||||||
expr => {
|
expr => {
|
||||||
// return undefined because this is invalid syntax
|
// return undefined because this is invalid syntax
|
||||||
let ident = self.lower_identifier_reference(
|
let ident = self.lower_identifier_reference(
|
||||||
&ast::IdentifierReference { span: expr.span(), name: "undefined".into() },
|
&ast::IdentifierReference::new("undefined".into(), expr.span()),
|
||||||
ReferenceFlag::Write,
|
ReferenceFlag::Write,
|
||||||
);
|
);
|
||||||
self.hir.assignment_target_identifier(ident)
|
self.hir.assignment_target_identifier(ident)
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,7 @@ impl<'a> Parser<'a> {
|
||||||
// ^ BindingIdentifier
|
// ^ BindingIdentifier
|
||||||
if let PropertyKey::Identifier(ident) = &key {
|
if let PropertyKey::Identifier(ident) = &key {
|
||||||
shorthand = true;
|
shorthand = true;
|
||||||
let binding_identifier =
|
let binding_identifier = BindingIdentifier::new(ident.name.clone(), ident.span);
|
||||||
BindingIdentifier { span: ident.span, name: ident.name.clone() };
|
|
||||||
let identifier = self.ast.binding_identifier(binding_identifier);
|
let identifier = self.ast.binding_identifier(binding_identifier);
|
||||||
let left = self.ast.binding_pattern(identifier, None, false);
|
let left = self.ast.binding_pattern(identifier, None, false);
|
||||||
self.parse_initializer(span, left)?
|
self.parse_initializer(span, left)?
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
use oxc_allocator::Box;
|
use oxc_allocator::Box;
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
use oxc_diagnostics::Result;
|
use oxc_diagnostics::Result;
|
||||||
|
|
@ -55,7 +57,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
||||||
self.check_identifier(span, &name);
|
self.check_identifier(span, &name);
|
||||||
Ok(IdentifierReference { span, name })
|
Ok(IdentifierReference { span, name, reference_id: Cell::default() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `BindingIdentifier` : Identifier
|
/// `BindingIdentifier` : Identifier
|
||||||
|
|
@ -65,7 +67,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
||||||
self.check_identifier(span, &name);
|
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> {
|
pub(crate) fn parse_label_identifier(&mut self) -> Result<LabelIdentifier> {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
use oxc_allocator::Box;
|
use oxc_allocator::Box;
|
||||||
use oxc_ast::{ast::*, AstBuilder};
|
use oxc_ast::{ast::*, AstBuilder};
|
||||||
use oxc_diagnostics::Result;
|
use oxc_diagnostics::Result;
|
||||||
|
|
@ -332,7 +334,7 @@ impl<'a> Parser<'a> {
|
||||||
let id = self.cur_kind().is_binding_identifier().then(|| {
|
let id = self.cur_kind().is_binding_identifier().then(|| {
|
||||||
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
let (span, name) = self.parse_identifier_kind(Kind::Ident);
|
||||||
self.check_identifier(span, &name);
|
self.check_identifier(span, &name);
|
||||||
BindingIdentifier { span, name }
|
BindingIdentifier { span, name, symbol_id: Cell::default() }
|
||||||
});
|
});
|
||||||
self.ctx = ctx;
|
self.ctx = ctx;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,8 @@ impl<'a> CoverGrammar<'a, ObjectProperty<'a>> for AssignmentTargetProperty<'a> {
|
||||||
if property.shorthand {
|
if property.shorthand {
|
||||||
let binding = match property.key {
|
let binding = match property.key {
|
||||||
PropertyKey::Identifier(ident) => {
|
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()),
|
_ => return Err(p.unexpected()),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -431,7 +431,7 @@ impl<'a> Parser<'a> {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
let (ident_span, name) = self.parse_identifier_kind(Kind::This);
|
let (ident_span, name) = self.parse_identifier_kind(Kind::This);
|
||||||
let type_annotation = self.parse_ts_type_annotation()?;
|
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);
|
let binding = self.ast.binding_pattern(kind, type_annotation, /* optional */ false);
|
||||||
Ok(self.ast.formal_parameter(
|
Ok(self.ast.formal_parameter(
|
||||||
self.end_span(span),
|
self.end_span(span),
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ impl<'a> Binder for VariableDeclarator<'a> {
|
||||||
};
|
};
|
||||||
self.id.bound_names(&mut |ident| {
|
self.id.bound_names(&mut |ident| {
|
||||||
let symbol_id = 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));
|
||||||
if self.kind == VariableDeclarationKind::Var
|
if self.kind == VariableDeclarationKind::Var
|
||||||
&& !builder.scope.get_flags(current_scope_id).is_var()
|
&& !builder.scope.get_flags(current_scope_id).is_var()
|
||||||
{
|
{
|
||||||
|
|
@ -59,12 +60,13 @@ impl<'a> Binder for Class<'a> {
|
||||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||||
let Some(ident) = &self.id else { return };
|
let Some(ident) = &self.id else { return };
|
||||||
if !self.modifiers.contains(ModifierKind::Declare) {
|
if !self.modifiers.contains(ModifierKind::Declare) {
|
||||||
builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
ident.span,
|
ident.span,
|
||||||
&ident.name,
|
&ident.name,
|
||||||
SymbolFlags::Class,
|
SymbolFlags::Class,
|
||||||
SymbolFlags::ClassExcludes,
|
SymbolFlags::ClassExcludes,
|
||||||
);
|
);
|
||||||
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.span,
|
||||||
&ident.name,
|
&ident.name,
|
||||||
parent_scope_id,
|
parent_scope_id,
|
||||||
includes,
|
includes,
|
||||||
excludes,
|
excludes,
|
||||||
);
|
);
|
||||||
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,7 +155,8 @@ impl<'a> Binder for FormalParameters<'a> {
|
||||||
let is_signature = self.kind == FormalParameterKind::Signature;
|
let is_signature = self.kind == FormalParameterKind::Signature;
|
||||||
self.bound_names(&mut |ident| {
|
self.bound_names(&mut |ident| {
|
||||||
if !is_signature {
|
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));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -167,15 +171,22 @@ impl<'a> Binder for CatchClause<'a> {
|
||||||
// unless CatchParameter is CatchParameter : BindingIdentifier
|
// unless CatchParameter is CatchParameter : BindingIdentifier
|
||||||
if let BindingPatternKind::BindingIdentifier(ident) = ¶m.kind {
|
if let BindingPatternKind::BindingIdentifier(ident) = ¶m.kind {
|
||||||
let includes = SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable;
|
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 {
|
} else {
|
||||||
param.bound_names(&mut |ident| {
|
param.bound_names(&mut |ident| {
|
||||||
builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
ident.span,
|
ident.span,
|
||||||
&ident.name,
|
&ident.name,
|
||||||
SymbolFlags::BlockScopedVariable | SymbolFlags::CatchVariable,
|
SymbolFlags::BlockScopedVariable | SymbolFlags::CatchVariable,
|
||||||
SymbolFlags::BlockScopedVariableExcludes,
|
SymbolFlags::BlockScopedVariableExcludes,
|
||||||
);
|
);
|
||||||
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -185,35 +196,38 @@ impl<'a> Binder for CatchClause<'a> {
|
||||||
impl<'a> Binder for ModuleDeclaration<'a> {
|
impl<'a> Binder for ModuleDeclaration<'a> {
|
||||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||||
self.bound_names(&mut |ident| {
|
self.bound_names(&mut |ident| {
|
||||||
builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
ident.span,
|
ident.span,
|
||||||
&ident.name,
|
&ident.name,
|
||||||
SymbolFlags::ImportBinding,
|
SymbolFlags::ImportBinding,
|
||||||
SymbolFlags::ImportBindingExcludes,
|
SymbolFlags::ImportBindingExcludes,
|
||||||
);
|
);
|
||||||
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Binder for TSTypeAliasDeclaration<'a> {
|
impl<'a> Binder for TSTypeAliasDeclaration<'a> {
|
||||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||||
builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
self.id.span,
|
self.id.span,
|
||||||
&self.id.name,
|
&self.id.name,
|
||||||
SymbolFlags::TypeAlias,
|
SymbolFlags::TypeAlias,
|
||||||
SymbolFlags::TypeAliasExcludes,
|
SymbolFlags::TypeAliasExcludes,
|
||||||
);
|
);
|
||||||
|
self.id.symbol_id.set(Some(symbol_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Binder for TSInterfaceDeclaration<'a> {
|
impl<'a> Binder for TSInterfaceDeclaration<'a> {
|
||||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||||
builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
self.id.span,
|
self.id.span,
|
||||||
&self.id.name,
|
&self.id.name,
|
||||||
SymbolFlags::Interface,
|
SymbolFlags::Interface,
|
||||||
SymbolFlags::InterfaceExcludes,
|
SymbolFlags::InterfaceExcludes,
|
||||||
);
|
);
|
||||||
|
self.id.symbol_id.set(Some(symbol_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,7 +240,8 @@ impl<'a> Binder for TSEnumDeclaration<'a> {
|
||||||
} else {
|
} else {
|
||||||
SymbolFlags::RegularEnumExcludes
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,11 +286,12 @@ impl<'a> Binder for TSModuleDeclaration<'a> {
|
||||||
|
|
||||||
impl<'a> Binder for TSTypeParameter<'a> {
|
impl<'a> Binder for TSTypeParameter<'a> {
|
||||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||||
builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
self.name.span,
|
self.name.span,
|
||||||
&self.name.name,
|
&self.name.name,
|
||||||
SymbolFlags::TypeParameter,
|
SymbolFlags::TypeParameter,
|
||||||
SymbolFlags::TypeParameterExcludes,
|
SymbolFlags::TypeParameterExcludes,
|
||||||
);
|
);
|
||||||
|
self.name.symbol_id.set(Some(symbol_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,8 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
fn reference_identifier(&mut self, ident: &IdentifierReference) {
|
fn reference_identifier(&mut self, ident: &IdentifierReference) {
|
||||||
let flag = self.resolve_reference_usages();
|
let flag = self.resolve_reference_usages();
|
||||||
let reference = Reference::new(ident.span, ident.name.clone(), self.current_node_id, flag);
|
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.
|
/// Resolve reference flags for the current ast node.
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use oxc_index::define_index_type;
|
|
||||||
use oxc_span::{Atom, Span};
|
use oxc_span::{Atom, Span};
|
||||||
|
|
||||||
use crate::{symbol::SymbolId, AstNodeId};
|
use crate::{symbol::SymbolId, AstNodeId};
|
||||||
|
|
||||||
define_index_type! {
|
pub use oxc_syntax::reference::ReferenceId;
|
||||||
pub struct ReferenceId = u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Reference {
|
pub struct Reference {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pub mod identifier;
|
||||||
pub mod module_record;
|
pub mod module_record;
|
||||||
pub mod operator;
|
pub mod operator;
|
||||||
pub mod precedence;
|
pub mod precedence;
|
||||||
|
pub mod reference;
|
||||||
pub mod scope;
|
pub mod scope;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
|
|
||||||
|
|
|
||||||
5
crates/oxc_syntax/src/reference.rs
Normal file
5
crates/oxc_syntax/src/reference.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
use oxc_index::define_index_type;
|
||||||
|
|
||||||
|
define_index_type! {
|
||||||
|
pub struct ReferenceId = u32;
|
||||||
|
}
|
||||||
|
|
@ -285,6 +285,9 @@ pub trait Case: Sized + Sync + Send + UnwindSafe {
|
||||||
.with_module_record_builder(true)
|
.with_module_record_builder(true)
|
||||||
.with_check_syntax_error(true)
|
.with_check_syntax_error(true)
|
||||||
.build(program);
|
.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 errors = parser_ret.errors.into_iter().chain(semantic_ret.errors).collect::<Vec<_>>();
|
||||||
|
|
||||||
let result = if errors.is_empty() {
|
let result = if errors.is_empty() {
|
||||||
|
|
@ -356,4 +359,8 @@ pub trait Case: Sized + Sync + Send + UnwindSafe {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_semantic(&self, _semantic: &oxc_semantic::Semantic<'_>) -> Option<TestResult> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,4 +190,53 @@ impl Case for Test262Case {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_semantic(&self, semantic: &oxc_semantic::Semantic<'_>) -> Option<TestResult> {
|
||||||
|
if are_all_identifiers_resolved(semantic) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(TestResult::ParseError("Unset symbol / reference".to_string(), true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn are_all_identifiers_resolved(semantic: &oxc_semantic::Semantic<'_>) -> bool {
|
||||||
|
use oxc_ast::{ast, AstKind};
|
||||||
|
use oxc_semantic::AstNode;
|
||||||
|
|
||||||
|
let ast_nodes = semantic.nodes();
|
||||||
|
let has_non_resolved = ast_nodes.iter().any(|node| {
|
||||||
|
match node.kind() {
|
||||||
|
AstKind::BindingIdentifier(id) => {
|
||||||
|
let mut parents = ast_nodes.iter_parents(node.id()).map(AstNode::kind);
|
||||||
|
parents.next(); // Exclude BindingIdentifier itself
|
||||||
|
match parents.next() {
|
||||||
|
Some(AstKind::Function(func))
|
||||||
|
if func.r#type == ast::FunctionType::FunctionExpression =>
|
||||||
|
{
|
||||||
|
// FIXME: Currently, the name of `FunctionExpression` won't be assigned a `SymbolId`
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let mut parents = ast_nodes.iter_parents(node.id()).map(AstNode::kind);
|
||||||
|
parents.next(); // Exclude BindingIdentifier itself
|
||||||
|
match (parents.next(), parents.next()) {
|
||||||
|
// FIXME: case like `if (xx) ; else function test() {}`
|
||||||
|
(Some(AstKind::Function(func)), Some(AstKind::IfStatement(_)))
|
||||||
|
if func.r#type == ast::FunctionType::FunctionDeclaration =>
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
id.symbol_id.get().is_none()
|
||||||
|
}
|
||||||
|
AstKind::IdentifierReference(ref_id) => ref_id.reference_id.get().is_none(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
!has_non_resolved
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue