mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
parent
cb886d8a36
commit
683778dfe2
14 changed files with 410 additions and 20 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -900,6 +900,7 @@ dependencies = [
|
|||
name = "oxc_semantic"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indextree",
|
||||
"oxc_ast",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ This project partially copies code from the following projects:
|
|||
| [microsoft/TypeScript](https://github.com/microsoft/TypeScript) | [Apache 2.0](https://github.com/microsoft/TypeScript/blob/main/LICENSE.txt) |
|
||||
| [rome/tools](https://github.com/rome/tools) | [MIT](https://github.com/rome/tools/blob/main/LICENSE) |
|
||||
| [mozilla-spidermonkey/jsparagus](https://github.com/mozilla-spidermonkey/jsparagus) | [MIT](https://github.com/mozilla-spidermonkey/jsparagus/blob/master/LICENSE-MIT) [Apache 2.0](https://github.com/mozilla-spidermonkey/jsparagus/blob/master/LICENSE-APACHE-2.0) |
|
||||
| [acorn](https://github.com/acornjs/acorn) | [MIT](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE) |
|
||||
|
||||
|
||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg?color=brightgreen
|
||||
|
|
|
|||
|
|
@ -146,3 +146,29 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
acorn
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2012-2022 by various contributors (see AUTHORS)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ impl Cli {
|
|||
|
||||
let program = allocator.alloc(ret.program);
|
||||
let trivias = Rc::new(ret.trivias);
|
||||
let semantic = SemanticBuilder::new().build(program, trivias);
|
||||
let semantic = SemanticBuilder::new(source_type).build(program, trivias);
|
||||
let result = Linter::new().run(&Rc::new(semantic), &source_text, fix);
|
||||
|
||||
if result.is_empty() {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ impl Tester {
|
|||
assert!(ret.errors.is_empty(), "{:?}", &ret.errors);
|
||||
let program = allocator.alloc(ret.program);
|
||||
let trivias = Rc::new(ret.trivias);
|
||||
let semantic = SemanticBuilder::new().build(program, trivias);
|
||||
let semantic = SemanticBuilder::new(source_type).build(program, trivias);
|
||||
let semantic = Rc::new(semantic);
|
||||
let rule = RULES
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -13,3 +13,4 @@ version.workspace = true
|
|||
oxc_ast = { path = "../oxc_ast" }
|
||||
|
||||
indextree = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -4,28 +4,33 @@
|
|||
|
||||
use std::rc::Rc;
|
||||
|
||||
use oxc_ast::{ast::Program, visit::Visit, AstKind, Trivias};
|
||||
use oxc_ast::{ast::Program, visit::Visit, AstKind, SourceType, Trivias};
|
||||
|
||||
use crate::{
|
||||
node::{AstNodeId, AstNodes, SemanticNode},
|
||||
node::{AstNodeId, AstNodes, NodeFlags, SemanticNode},
|
||||
scope::ScopeBuilder,
|
||||
Semantic,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SemanticBuilder<'a> {
|
||||
nodes: AstNodes<'a>,
|
||||
|
||||
// states
|
||||
current_node_id: AstNodeId,
|
||||
current_node_flags: NodeFlags,
|
||||
|
||||
// builders
|
||||
nodes: AstNodes<'a>,
|
||||
scope: ScopeBuilder,
|
||||
}
|
||||
|
||||
impl<'a> SemanticBuilder<'a> {
|
||||
#[must_use]
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
pub fn new(source_type: SourceType) -> Self {
|
||||
let scope = ScopeBuilder::new(source_type);
|
||||
let mut nodes = AstNodes::default();
|
||||
let semantic_node = SemanticNode::new(AstKind::Root);
|
||||
let semantic_node =
|
||||
SemanticNode::new(AstKind::Root, scope.current_scope_id, NodeFlags::empty());
|
||||
let current_node_id = nodes.new_node(semantic_node).into();
|
||||
Self { nodes, current_node_id }
|
||||
Self { current_node_id, nodes, scope, current_node_flags: NodeFlags::empty() }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -36,7 +41,8 @@ impl<'a> SemanticBuilder<'a> {
|
|||
}
|
||||
|
||||
fn create_ast_node(&mut self, kind: AstKind<'a>) {
|
||||
let ast_node = SemanticNode::new(kind);
|
||||
let ast_node =
|
||||
SemanticNode::new(kind, self.scope.current_scope_id, self.current_node_flags);
|
||||
let node_id = self.nodes.new_node(ast_node);
|
||||
self.current_node_id.append(node_id, &mut self.nodes);
|
||||
self.current_node_id = node_id.into();
|
||||
|
|
@ -46,14 +52,35 @@ impl<'a> SemanticBuilder<'a> {
|
|||
self.current_node_id =
|
||||
self.nodes[self.current_node_id.indextree_id()].parent().unwrap().into();
|
||||
}
|
||||
|
||||
fn try_enter_scope(&mut self, kind: AstKind<'a>) {
|
||||
if let Some(flags) = ScopeBuilder::scope_flags_from_ast_kind(kind) {
|
||||
self.scope.enter(flags);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_leave_scope(&mut self, kind: AstKind<'a>) {
|
||||
if ScopeBuilder::scope_flags_from_ast_kind(kind).is_some()
|
||||
|| matches!(kind, AstKind::Program(_))
|
||||
{
|
||||
self.scope.leave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||
// Setup all the context for the binder,
|
||||
// the order is important here.
|
||||
fn enter_node(&mut self, kind: AstKind<'a>) {
|
||||
// create new self.scope.current_scope_id
|
||||
self.try_enter_scope(kind);
|
||||
|
||||
// create new self.current_node_id
|
||||
self.create_ast_node(kind);
|
||||
}
|
||||
|
||||
fn leave_node(&mut self, _kind: AstKind<'a>) {
|
||||
fn leave_node(&mut self, kind: AstKind<'a>) {
|
||||
self.pop_ast_node();
|
||||
self.try_leave_scope(kind);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
mod builder;
|
||||
mod node;
|
||||
mod scope;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
pub use builder::SemanticBuilder;
|
||||
pub use node::{AstNode, AstNodes};
|
||||
use oxc_ast::Trivias;
|
||||
pub use scope::{Scope, ScopeTree};
|
||||
|
||||
pub struct Semantic<'a> {
|
||||
nodes: AstNodes<'a>,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#![allow(non_upper_case_globals)] // for bitflags
|
||||
|
||||
mod id;
|
||||
mod tree;
|
||||
|
||||
pub use id::AstNodeId;
|
||||
use bitflags::bitflags;
|
||||
use oxc_ast::AstKind;
|
||||
pub use tree::AstNodes;
|
||||
|
||||
pub use self::{id::AstNodeId, tree::AstNodes};
|
||||
use crate::scope::{Scope, ScopeId};
|
||||
|
||||
/// Indextree node containing a semantic node
|
||||
pub type AstNode<'a> = indextree::Node<SemanticNode<'a>>;
|
||||
|
|
@ -13,15 +17,42 @@ pub type AstNode<'a> = indextree::Node<SemanticNode<'a>>;
|
|||
pub struct SemanticNode<'a> {
|
||||
/// A pointer to the ast node, which resides in the `bumpalo` memory arena.
|
||||
kind: AstKind<'a>,
|
||||
|
||||
/// Associated Scope (initialized by binding)
|
||||
scope_id: ScopeId,
|
||||
|
||||
flags: NodeFlags,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct NodeFlags: u8 {
|
||||
const Class = 1 << 0; // If Node is inside a class
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SemanticNode<'a> {
|
||||
#[must_use]
|
||||
pub const fn new(kind: AstKind<'a>) -> Self {
|
||||
Self { kind }
|
||||
pub const fn new(kind: AstKind<'a>, scope_id: ScopeId, flags: NodeFlags) -> Self {
|
||||
Self { kind, scope_id, flags }
|
||||
}
|
||||
|
||||
pub const fn kind(&self) -> AstKind<'a> {
|
||||
self.kind
|
||||
}
|
||||
|
||||
pub const fn scope_id(&self) -> ScopeId {
|
||||
self.scope_id
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn strict_mode(&self, scope: &Scope) -> bool {
|
||||
// All parts of a ClassDeclaration or a ClassExpression are strict mode code.
|
||||
scope.strict_mode() || self.in_class()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn in_class(self) -> bool {
|
||||
self.flags.contains(NodeFlags::Class)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
71
crates/oxc_semantic/src/scope/builder.rs
Normal file
71
crates/oxc_semantic/src/scope/builder.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use oxc_ast::{AstKind, SourceType};
|
||||
|
||||
use super::{Scope, ScopeFlags, ScopeId, ScopeTree};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ScopeBuilder {
|
||||
pub scopes: ScopeTree,
|
||||
|
||||
pub current_scope_id: ScopeId,
|
||||
}
|
||||
|
||||
impl ScopeBuilder {
|
||||
#[must_use]
|
||||
pub fn new(source_type: SourceType) -> Self {
|
||||
// Module code is always strict mode code.
|
||||
let strict_mode = source_type.is_module();
|
||||
let scopes = ScopeTree::new(strict_mode);
|
||||
let current_scope_id = scopes.root_scope_id();
|
||||
Self { scopes, current_scope_id }
|
||||
}
|
||||
|
||||
pub fn enter(&mut self, flags: ScopeFlags) {
|
||||
// Inherit strict mode for functions
|
||||
// https://tc39.es/ecma262/#sec-strict-mode-code
|
||||
let mut strict_mode = self.scopes[self.scopes.root_scope_id()].strict_mode;
|
||||
let parent_scope = self.current_scope();
|
||||
if !strict_mode && parent_scope.is_function() && parent_scope.strict_mode {
|
||||
strict_mode = true;
|
||||
}
|
||||
|
||||
// inherit flags for non-function scopes
|
||||
let flags = if flags.contains(ScopeFlags::Function) {
|
||||
flags
|
||||
} else {
|
||||
flags | (parent_scope.flags & ScopeFlags::MODIFIERS)
|
||||
};
|
||||
|
||||
let scope = Scope::new(flags, strict_mode);
|
||||
let new_scope_id = self.scopes.new_node(scope);
|
||||
self.current_scope_id.append(new_scope_id, &mut self.scopes);
|
||||
self.current_scope_id = new_scope_id.into();
|
||||
}
|
||||
|
||||
pub fn leave(&mut self) {
|
||||
if let Some(parent_id) = self.scopes[self.current_scope_id.indextree_id()].parent() {
|
||||
self.current_scope_id = parent_id.into();
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn current_scope(&self) -> &Scope {
|
||||
&self.scopes[self.current_scope_id]
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn scope_flags_from_ast_kind(kind: AstKind) -> Option<ScopeFlags> {
|
||||
match kind {
|
||||
AstKind::Function(_) => Some(ScopeFlags::Function),
|
||||
AstKind::ArrowExpression(_) => Some(ScopeFlags::Function | ScopeFlags::Arrow),
|
||||
AstKind::StaticBlock(_) => Some(ScopeFlags::ClassStaticBlock),
|
||||
AstKind::TSModuleBlock(_) => Some(ScopeFlags::TsModuleBlock),
|
||||
AstKind::BlockStatement(_)
|
||||
| AstKind::CatchClause(_)
|
||||
| AstKind::ForStatement(_)
|
||||
| AstKind::ForInStatement(_)
|
||||
| AstKind::ForOfStatement(_)
|
||||
| AstKind::SwitchStatement(_) => Some(ScopeFlags::empty()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
32
crates/oxc_semantic/src/scope/id.rs
Normal file
32
crates/oxc_semantic/src/scope/id.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use indextree::NodeId;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ScopeId(NodeId);
|
||||
|
||||
impl ScopeId {
|
||||
#[must_use]
|
||||
pub const fn new(node_id: NodeId) -> Self {
|
||||
Self(node_id)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn indextree_id(&self) -> NodeId {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NodeId> for ScopeId {
|
||||
fn from(node_id: NodeId) -> Self {
|
||||
Self(node_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ScopeId {
|
||||
type Target = NodeId;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
86
crates/oxc_semantic/src/scope/mod.rs
Normal file
86
crates/oxc_semantic/src/scope/mod.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//! ECMAScript Scope Tree
|
||||
//! See [Scope Analysis](https://tc39.es/ecma262/#sec-syntax-directed-operations-scope-analysis)
|
||||
//! Code Adapted from [acorn](https://github.com/acornjs/acorn/blob/master/acorn/src/scope.js)
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
mod builder;
|
||||
mod id;
|
||||
mod tree;
|
||||
|
||||
use bitflags::bitflags;
|
||||
pub use builder::*;
|
||||
pub use tree::ScopeTree;
|
||||
|
||||
pub use self::id::ScopeId;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Scope {
|
||||
/// [Strict Mode Code](https://tc39.es/ecma262/#sec-strict-mode-code)
|
||||
/// [Use Strict Directive Prologue](https://tc39.es/ecma262/#sec-directive-prologues-and-the-use-strict-directive)
|
||||
pub(crate) strict_mode: bool,
|
||||
|
||||
pub flags: ScopeFlags,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct ScopeFlags: u16 {
|
||||
const Top = 1 << 0;
|
||||
const Function = 1 << 1;
|
||||
const Arrow = 1 << 2;
|
||||
const ClassStaticBlock = 1 << 4;
|
||||
const TsModuleBlock = 1 << 5; // `declare namespace`
|
||||
const Constructor = 1 << 6;
|
||||
const GetAccessor = 1 << 7;
|
||||
const SetAccessor = 1 << 8;
|
||||
const VAR = Self::Top.bits | Self::Function.bits | Self::ClassStaticBlock.bits | Self::TsModuleBlock.bits;
|
||||
const MODIFIERS = Self::Constructor.bits | Self::GetAccessor.bits | Self::SetAccessor.bits;
|
||||
}
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
#[must_use]
|
||||
pub const fn new(flags: ScopeFlags, strict_mode: bool) -> Self {
|
||||
Self { strict_mode, flags }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn strict_mode(&self) -> bool {
|
||||
self.strict_mode
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_top(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::Top)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_ts_module(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::TsModuleBlock)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_function(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::Function)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_static_block(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::ClassStaticBlock)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_constructor(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::Constructor)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_get_accessor(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::GetAccessor)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn is_set_accessor(&self) -> bool {
|
||||
self.flags.intersects(ScopeFlags::SetAccessor)
|
||||
}
|
||||
}
|
||||
111
crates/oxc_semantic/src/scope/tree.rs
Normal file
111
crates/oxc_semantic/src/scope/tree.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
|
||||
use indextree::{Ancestors, Arena, Node, NodeId};
|
||||
|
||||
use super::{Scope, ScopeFlags, ScopeId};
|
||||
use crate::node::AstNode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ScopeTree {
|
||||
scopes: Arena<Scope>,
|
||||
|
||||
root_scope_id: ScopeId,
|
||||
}
|
||||
|
||||
impl ScopeTree {
|
||||
#[must_use]
|
||||
pub fn new(root_strict_mode: bool) -> Self {
|
||||
let mut scopes = Arena::new();
|
||||
let root_scope = Scope::new(ScopeFlags::Top, root_strict_mode);
|
||||
let root_scope_id = scopes.new_node(root_scope).into();
|
||||
Self { scopes, root_scope_id }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn root_scope_id(&self) -> ScopeId {
|
||||
self.root_scope_id
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ancestors(&self, scope_id: ScopeId) -> Ancestors<'_, Scope> {
|
||||
scope_id.ancestors(&self.scopes)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn node_scope(&self, node: &AstNode) -> &Scope {
|
||||
self.scopes[node.get().scope_id().indextree_id()].get()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn node_scope_ancestors(&self, node: &AstNode) -> Ancestors<'_, Scope> {
|
||||
self.ancestors(node.get().scope_id())
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
/// When parent scope cannot be found, but this will not happen because
|
||||
/// scopes are never removed.
|
||||
#[must_use]
|
||||
pub fn parent_node_id(&self, scope_id: ScopeId) -> NodeId {
|
||||
self.scopes[*scope_id].parent().unwrap()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn parent_scope(&self, scope_id: ScopeId) -> &Scope {
|
||||
let parent_id = self.parent_node_id(scope_id);
|
||||
self.scopes[parent_id].get()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn parent_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope {
|
||||
let parent_id = self.parent_node_id(scope_id);
|
||||
self.scopes[parent_id].get_mut()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn strict_mode(&self, node: &AstNode) -> bool {
|
||||
let scope = self.node_scope(node);
|
||||
node.get().strict_mode(scope)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<NodeId> for ScopeTree {
|
||||
type Output = Node<Scope>;
|
||||
|
||||
fn index(&self, id: NodeId) -> &Self::Output {
|
||||
&self.scopes[id]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<NodeId> for ScopeTree {
|
||||
fn index_mut(&mut self, id: NodeId) -> &mut Node<Scope> {
|
||||
&mut self.scopes[id]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<ScopeId> for ScopeTree {
|
||||
type Output = Scope;
|
||||
|
||||
fn index(&self, id: ScopeId) -> &Self::Output {
|
||||
self.scopes[id.indextree_id()].get()
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<ScopeId> for ScopeTree {
|
||||
fn index_mut(&mut self, id: ScopeId) -> &mut Scope {
|
||||
self.scopes[id.indextree_id()].get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ScopeTree {
|
||||
type Target = Arena<Scope>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.scopes
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ScopeTree {
|
||||
fn deref_mut(&mut self) -> &mut Arena<Scope> {
|
||||
&mut self.scopes
|
||||
}
|
||||
}
|
||||
|
|
@ -91,12 +91,13 @@ fn bench_semantic(criterion: &mut Criterion, codes: &[Code]) {
|
|||
&code.source_text,
|
||||
|b, source_text| {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, SourceType::default()).parse();
|
||||
let source_type = SourceType::from_path(&code.file_name).unwrap();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
let trivias = Rc::new(ret.trivias);
|
||||
b.iter(|| {
|
||||
let _semantic =
|
||||
SemanticBuilder::new().build(black_box(program), trivias.clone());
|
||||
let _semantic = SemanticBuilder::new(source_type)
|
||||
.build(black_box(program), trivias.clone());
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue