refactor(transformer): move Semantic into Transformer (#1130)

This commit is contained in:
Boshen 2023-11-02 13:10:15 +08:00 committed by GitHub
parent fa4e0cae81
commit 69150d812c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 36 additions and 52 deletions

View file

@ -72,6 +72,10 @@ impl<'a> Semantic<'a> {
&self.scopes &self.scopes
} }
pub fn scopes_mut(&mut self) -> &mut ScopeTree {
&mut self.scopes
}
pub fn trivias(&self) -> &TriviasMap { pub fn trivias(&self) -> &TriviasMap {
&self.trivias &self.trivias
} }

View file

@ -1,4 +1,4 @@
use std::{cell::RefCell, env, path::Path, rc::Rc}; use std::{env, path::Path};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_codegen::{Codegen, CodegenOptions}; use oxc_codegen::{Codegen, CodegenOptions};
@ -36,9 +36,6 @@ fn main() {
println!("{printed}\n"); println!("{printed}\n");
let semantic = SemanticBuilder::new(&source_text, source_type).build(&ret.program).semantic; let semantic = SemanticBuilder::new(&source_text, source_type).build(&ret.program).semantic;
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let program = allocator.alloc(ret.program); let program = allocator.alloc(ret.program);
let transform_options = TransformOptions { let transform_options = TransformOptions {
@ -49,7 +46,7 @@ fn main() {
}), }),
..TransformOptions::default() ..TransformOptions::default()
}; };
Transformer::new(&allocator, source_type, &symbols, &scopes, transform_options).build(program); Transformer::new(&allocator, source_type, semantic, transform_options).build(program);
let printed = Codegen::<false>::new(source_text.len(), codegen_options).build(program); let printed = Codegen::<false>::new(source_text.len(), codegen_options).build(program);
println!("Transformed:\n"); println!("Transformed:\n");
println!("{printed}"); println!("{printed}");

View file

@ -1,30 +1,37 @@
use std::{ use std::{
cell::{Ref, RefCell}, cell::{Ref, RefCell, RefMut},
rc::Rc, rc::Rc,
}; };
use oxc_ast::AstBuilder; use oxc_ast::AstBuilder;
use oxc_semantic::{ScopeId, ScopeTree, SymbolId, SymbolTable}; use oxc_semantic::{ScopeId, ScopeTree, Semantic, SymbolId, SymbolTable};
use oxc_span::Atom; use oxc_span::Atom;
#[derive(Clone)] #[derive(Clone)]
pub struct TransformerCtx<'a> { pub struct TransformerCtx<'a> {
pub ast: Rc<AstBuilder<'a>>, pub ast: Rc<AstBuilder<'a>>,
pub symbols: Rc<RefCell<SymbolTable>>, semantic: Rc<RefCell<Semantic<'a>>>,
pub scopes: Rc<RefCell<ScopeTree>>,
} }
impl<'a> TransformerCtx<'a> { impl<'a> TransformerCtx<'a> {
pub fn symbols(&self) -> Ref<SymbolTable> { pub fn new(ast: Rc<AstBuilder<'a>>, semantic: Rc<RefCell<Semantic<'a>>>) -> Self {
self.symbols.borrow() Self { ast, semantic }
} }
pub fn scopes(&self) -> Ref<ScopeTree> { pub fn symbols(&self) -> Ref<'_, SymbolTable> {
self.scopes.borrow() Ref::map(self.semantic.borrow(), |semantic| semantic.symbols())
}
pub fn scopes(&self) -> Ref<'_, ScopeTree> {
Ref::map(self.semantic.borrow(), |semantic| semantic.scopes())
}
pub fn scopes_mut(&self) -> RefMut<'_, ScopeTree> {
RefMut::map(self.semantic.borrow_mut(), |semantic| semantic.scopes_mut())
} }
pub fn add_binding(&self, name: Atom) { pub fn add_binding(&self, name: Atom) {
// TODO: use the correct scope and symbol id // TODO: use the correct scope and symbol id
self.scopes.borrow_mut().add_binding(ScopeId::new(0), name, SymbolId::new(0)); self.scopes_mut().add_binding(ScopeId::new(0), name, SymbolId::new(0));
} }
} }

View file

@ -163,7 +163,7 @@ impl<'a> ExponentiationOperator<'a> {
if ident if ident
.reference_id .reference_id
.get() .get()
.is_some_and(|reference_id| self.ctx.symbols.borrow().has_binding(reference_id)) .is_some_and(|reference_id| self.ctx.symbols().has_binding(reference_id))
{ {
// this variable is declared in scope so we can be 100% sure // this variable is declared in scope so we can be 100% sure
// that evaluating it multiple times won't trigger a getter // that evaluating it multiple times won't trigger a getter
@ -185,7 +185,7 @@ impl<'a> ExponentiationOperator<'a> {
// Super cannot be directly assigned so lets return it also // Super cannot be directly assigned so lets return it also
if matches!(expr, Expression::Super(_)) if matches!(expr, Expression::Super(_))
|| matches!(&expr, Expression::Identifier(ident) if || matches!(&expr, Expression::Identifier(ident) if
ident.reference_id.get().is_some_and(|reference_id| self.ctx.symbols.borrow().has_binding(reference_id))) ident.reference_id.get().is_some_and(|reference_id| self.ctx.symbols().has_binding(reference_id)))
{ {
return Some(expr); return Some(expr);
} }

View file

@ -26,7 +26,7 @@ use std::{cell::RefCell, rc::Rc};
use oxc_allocator::{Allocator, Vec}; use oxc_allocator::{Allocator, Vec};
use oxc_ast::{ast::*, AstBuilder, VisitMut}; use oxc_ast::{ast::*, AstBuilder, VisitMut};
use oxc_semantic::{ScopeTree, SymbolTable}; use oxc_semantic::Semantic;
use oxc_span::SourceType; use oxc_span::SourceType;
use crate::{ use crate::{
@ -66,16 +66,14 @@ impl<'a> Transformer<'a> {
pub fn new( pub fn new(
allocator: &'a Allocator, allocator: &'a Allocator,
source_type: SourceType, source_type: SourceType,
symbols: &Rc<RefCell<SymbolTable>>, semantic: Semantic<'a>,
scopes: &Rc<RefCell<ScopeTree>>,
options: TransformOptions, options: TransformOptions,
) -> Self { ) -> Self {
let ast = Rc::new(AstBuilder::new(allocator)); let ast = Rc::new(AstBuilder::new(allocator));
let ctx = TransformerCtx { let ctx = TransformerCtx::new(
ast: Rc::clone(&ast), Rc::clone(&ast),
symbols: Rc::clone(symbols), Rc::new(RefCell::new(semantic)),
scopes: Rc::clone(scopes), );
};
Self { Self {
// TODO: pass verbatim_module_syntax from user config // TODO: pass verbatim_module_syntax from user config
typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast), ctx.clone(), false)), typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast), ctx.clone(), false)),

View file

@ -1,5 +1,3 @@
use std::{cell::RefCell, rc::Rc};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_codegen::{Codegen, CodegenOptions}; use oxc_codegen::{Codegen, CodegenOptions};
use oxc_parser::Parser; use oxc_parser::Parser;
@ -32,15 +30,9 @@ impl Tester {
fn transform(&self, source_text: &str) -> String { fn transform(&self, source_text: &str) -> String {
let program = Parser::new(&self.allocator, source_text, self.source_type).parse().program; let program = Parser::new(&self.allocator, source_text, self.source_type).parse().program;
let semantic = SemanticBuilder::new(source_text, self.source_type).build(&program).semantic; let semantic = SemanticBuilder::new(source_text, self.source_type).build(&program).semantic;
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let program = self.allocator.alloc(program); let program = self.allocator.alloc(program);
Transformer::new(&self.allocator, self.source_type, &symbols, &scopes, self.options) Transformer::new(&self.allocator, self.source_type, semantic, self.options).build(program);
.build(program);
Codegen::<false>::new(source_text.len(), CodegenOptions).build(program) Codegen::<false>::new(source_text.len(), CodegenOptions).build(program)
} }

View file

@ -213,12 +213,9 @@ impl Oxc {
// FIXME: this should not be duplicated with the linter semantic, // FIXME: this should not be duplicated with the linter semantic,
// we need to fix the API so symbols and scopes can be shared. // we need to fix the API so symbols and scopes can be shared.
let semantic = SemanticBuilder::new(source_text, source_type).build(program).semantic; let semantic = SemanticBuilder::new(source_text, source_type).build(program).semantic;
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let options = let options =
TransformOptions { target: TransformTarget::ES2015, ..TransformOptions::default() }; TransformOptions { target: TransformTarget::ES2015, ..TransformOptions::default() };
Transformer::new(&allocator, source_type, &symbols, &scopes, options).build(program); Transformer::new(&allocator, source_type, semantic, options).build(program);
} }
let program = allocator.alloc(program); let program = allocator.alloc(program);

View file

@ -6,7 +6,7 @@ static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;
#[global_allocator] #[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
use std::{cell::RefCell, fs, hint::black_box, rc::Rc}; use std::{fs, hint::black_box};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion}; use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion};
@ -35,12 +35,9 @@ fn bench_transformer(criterion: &mut Criterion) {
let program = Parser::new(&allocator, source_text, source_type).parse().program; let program = Parser::new(&allocator, source_text, source_type).parse().program;
let semantic = let semantic =
SemanticBuilder::new(source_text, source_type).build(&program).semantic; SemanticBuilder::new(source_text, source_type).build(&program).semantic;
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let program = allocator.alloc(program); let program = allocator.alloc(program);
let transform_options = TransformOptions::default(); let transform_options = TransformOptions::default();
Transformer::new(&allocator, source_type, &symbols, &scopes, transform_options) Transformer::new(&allocator, source_type, semantic, transform_options)
.build(black_box(program)); .build(black_box(program));
allocator allocator
}); });

View file

@ -1,8 +1,6 @@
use std::{ use std::{
cell::RefCell,
fs, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::Rc,
}; };
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
@ -144,12 +142,9 @@ pub trait TestCase {
let semantic = let semantic =
SemanticBuilder::new(&source_text, source_type).build(&transformed_program).semantic; SemanticBuilder::new(&source_text, source_type).build(&transformed_program).semantic;
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let transformed_program = allocator.alloc(transformed_program); let transformed_program = allocator.alloc(transformed_program);
Transformer::new(&allocator, source_type, &symbols, &scopes, self.transform_options()) Transformer::new(&allocator, source_type, semantic, self.transform_options())
.build(transformed_program); .build(transformed_program);
Codegen::<false>::new(source_text.len(), CodegenOptions).build(transformed_program) Codegen::<false>::new(source_text.len(), CodegenOptions).build(transformed_program)
} }
@ -197,11 +192,8 @@ impl TestCase for ConformanceTestCase {
// Transform input.js // Transform input.js
let program = Parser::new(&allocator, &input, source_type).parse().program; let program = Parser::new(&allocator, &input, source_type).parse().program;
let semantic = SemanticBuilder::new(&input, source_type).build(&program).semantic; let semantic = SemanticBuilder::new(&input, source_type).build(&program).semantic;
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let program = allocator.alloc(program); let program = allocator.alloc(program);
Transformer::new(&allocator, source_type, &symbols, &scopes, self.transform_options()) Transformer::new(&allocator, source_type, semantic, self.transform_options())
.build(program); .build(program);
let transformed_code = Codegen::<false>::new(input.len(), CodegenOptions).build(program); let transformed_code = Codegen::<false>::new(input.len(), CodegenOptions).build(program);