fix(ast): visit Programs hashbang field first (#4368)

Visit `hashbang` before `directives` for `Program`.
This commit is contained in:
overlookmotel 2024-07-19 16:27:51 +00:00
parent 6ffce865d1
commit aece1df561
8 changed files with 88 additions and 88 deletions

View file

@ -39,8 +39,8 @@ pub struct Program<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub source_type: SourceType,
pub directives: Vec<'a, Directive<'a>>,
pub hashbang: Option<Hashbang<'a>>,
pub directives: Vec<'a, Directive<'a>>,
pub body: Vec<'a, Statement<'a>>,
pub scope_id: Cell<Option<ScopeId>>,
}

View file

@ -136,11 +136,11 @@ impl<'a> AstBuilder<'a> {
self,
span: Span,
source_type: SourceType,
directives: Vec<'a, Directive<'a>>,
hashbang: Option<Hashbang<'a>>,
directives: Vec<'a, Directive<'a>>,
body: Vec<'a, Statement<'a>>,
) -> Program<'a> {
Program { span, source_type, directives, hashbang, body, scope_id: Default::default() }
Program { span, source_type, hashbang, directives, body, scope_id: Default::default() }
}
#[inline]
@ -148,11 +148,11 @@ impl<'a> AstBuilder<'a> {
self,
span: Span,
source_type: SourceType,
directives: Vec<'a, Directive<'a>>,
hashbang: Option<Hashbang<'a>>,
directives: Vec<'a, Directive<'a>>,
body: Vec<'a, Statement<'a>>,
) -> Box<'a, Program<'a>> {
self.program(span, source_type, directives, hashbang, body).into_in(self.allocator)
self.program(span, source_type, hashbang, directives, body).into_in(self.allocator)
}
#[inline]

View file

@ -50,6 +50,11 @@ pub trait Visit<'a>: Sized {
walk_program(self, it);
}
#[inline]
fn visit_hashbang(&mut self, it: &Hashbang<'a>) {
walk_hashbang(self, it);
}
#[inline]
fn visit_directives(&mut self, it: &Vec<'a, Directive<'a>>) {
walk_directives(self, it);
@ -65,11 +70,6 @@ pub trait Visit<'a>: Sized {
walk_string_literal(self, it);
}
#[inline]
fn visit_hashbang(&mut self, it: &Hashbang<'a>) {
walk_hashbang(self, it);
}
#[inline]
fn visit_statements(&mut self, it: &Vec<'a, Statement<'a>>) {
walk_statements(self, it);
@ -1366,15 +1366,22 @@ pub mod walk {
},
&it.scope_id,
);
visitor.visit_directives(&it.directives);
if let Some(hashbang) = &it.hashbang {
visitor.visit_hashbang(hashbang);
}
visitor.visit_directives(&it.directives);
visitor.visit_statements(&it.body);
visitor.leave_scope();
visitor.leave_node(kind);
}
#[inline]
pub fn walk_hashbang<'a, V: Visit<'a>>(visitor: &mut V, it: &Hashbang<'a>) {
let kind = AstKind::Hashbang(visitor.alloc(it));
visitor.enter_node(kind);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_directives<'a, V: Visit<'a>>(visitor: &mut V, it: &Vec<'a, Directive<'a>>) {
for el in it.iter() {
@ -1397,13 +1404,6 @@ pub mod walk {
visitor.leave_node(kind);
}
#[inline]
pub fn walk_hashbang<'a, V: Visit<'a>>(visitor: &mut V, it: &Hashbang<'a>) {
let kind = AstKind::Hashbang(visitor.alloc(it));
visitor.enter_node(kind);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_statements<'a, V: Visit<'a>>(visitor: &mut V, it: &Vec<'a, Statement<'a>>) {
for el in it.iter() {

View file

@ -42,6 +42,11 @@ pub trait VisitMut<'a>: Sized {
walk_program(self, it);
}
#[inline]
fn visit_hashbang(&mut self, it: &mut Hashbang<'a>) {
walk_hashbang(self, it);
}
#[inline]
fn visit_directives(&mut self, it: &mut Vec<'a, Directive<'a>>) {
walk_directives(self, it);
@ -57,11 +62,6 @@ pub trait VisitMut<'a>: Sized {
walk_string_literal(self, it);
}
#[inline]
fn visit_hashbang(&mut self, it: &mut Hashbang<'a>) {
walk_hashbang(self, it);
}
#[inline]
fn visit_statements(&mut self, it: &mut Vec<'a, Statement<'a>>) {
walk_statements(self, it);
@ -1361,15 +1361,22 @@ pub mod walk_mut {
},
&it.scope_id,
);
visitor.visit_directives(&mut it.directives);
if let Some(hashbang) = &mut it.hashbang {
visitor.visit_hashbang(hashbang);
}
visitor.visit_directives(&mut it.directives);
visitor.visit_statements(&mut it.body);
visitor.leave_scope();
visitor.leave_node(kind);
}
#[inline]
pub fn walk_hashbang<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Hashbang<'a>) {
let kind = AstType::Hashbang;
visitor.enter_node(kind);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_directives<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Vec<'a, Directive<'a>>) {
for el in it.iter_mut() {
@ -1392,13 +1399,6 @@ pub mod walk_mut {
visitor.leave_node(kind);
}
#[inline]
pub fn walk_hashbang<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Hashbang<'a>) {
let kind = AstType::Hashbang;
visitor.enter_node(kind);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_statements<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Vec<'a, Statement<'a>>) {
for el in it.iter_mut() {

View file

@ -58,7 +58,7 @@ impl<'a> IsolatedDeclarations<'a> {
let source_type = SourceType::default().with_module(true).with_typescript_definition(true);
let directives = self.ast.vec();
let stmts = self.transform_program(program);
let program = self.ast.program(SPAN, source_type, directives, None, stmts);
let program = self.ast.program(SPAN, source_type, None, directives, stmts);
IsolatedDeclarationsReturn { program, errors: self.take_errors() }
}

View file

@ -328,9 +328,9 @@ impl<'a> ParserImpl<'a> {
let program = self.ast.program(
Span::default(),
self.source_type,
self.ast.vec(),
None,
self.ast.vec(),
self.ast.vec(),
);
(program, true)
}
@ -361,7 +361,7 @@ impl<'a> ParserImpl<'a> {
self.parse_directives_and_statements(/* is_top_level */ true)?;
let span = Span::new(0, self.source_text.len() as u32);
Ok(self.ast.program(span, self.source_type, directives, hashbang, statements))
Ok(self.ast.program(span, self.source_type, hashbang, directives, statements))
}
fn default_context(source_type: SourceType, options: ParserOptions) -> Context {

View file

@ -30,8 +30,8 @@ use oxc_syntax::{
#[allow(dead_code)]
pub(crate) enum AncestorType {
None = 0,
ProgramDirectives = 1,
ProgramHashbang = 2,
ProgramHashbang = 1,
ProgramDirectives = 2,
ProgramBody = 3,
ArrayExpressionElements = 4,
ObjectExpressionProperties = 5,
@ -343,8 +343,8 @@ pub(crate) enum AncestorType {
#[derive(Debug)]
pub enum Ancestor<'a> {
None = AncestorType::None as u16,
ProgramDirectives(ProgramWithoutDirectives<'a>) = AncestorType::ProgramDirectives as u16,
ProgramHashbang(ProgramWithoutHashbang<'a>) = AncestorType::ProgramHashbang as u16,
ProgramDirectives(ProgramWithoutDirectives<'a>) = AncestorType::ProgramDirectives as u16,
ProgramBody(ProgramWithoutBody<'a>) = AncestorType::ProgramBody as u16,
ArrayExpressionElements(ArrayExpressionWithoutElements<'a>) =
AncestorType::ArrayExpressionElements as u16,
@ -872,7 +872,7 @@ pub enum Ancestor<'a> {
impl<'a> Ancestor<'a> {
#[inline]
pub fn is_program(&self) -> bool {
matches!(self, Self::ProgramDirectives(_) | Self::ProgramHashbang(_) | Self::ProgramBody(_))
matches!(self, Self::ProgramHashbang(_) | Self::ProgramDirectives(_) | Self::ProgramBody(_))
}
#[inline]
@ -2178,48 +2178,11 @@ impl<'a> Ancestor<'a> {
pub(crate) const OFFSET_PROGRAM_SPAN: usize = offset_of!(Program, span);
pub(crate) const OFFSET_PROGRAM_SOURCE_TYPE: usize = offset_of!(Program, source_type);
pub(crate) const OFFSET_PROGRAM_DIRECTIVES: usize = offset_of!(Program, directives);
pub(crate) const OFFSET_PROGRAM_HASHBANG: usize = offset_of!(Program, hashbang);
pub(crate) const OFFSET_PROGRAM_DIRECTIVES: usize = offset_of!(Program, directives);
pub(crate) const OFFSET_PROGRAM_BODY: usize = offset_of!(Program, body);
pub(crate) const OFFSET_PROGRAM_SCOPE_ID: usize = offset_of!(Program, scope_id);
#[repr(transparent)]
#[derive(Debug)]
pub struct ProgramWithoutDirectives<'a>(pub(crate) *const Program<'a>);
impl<'a> ProgramWithoutDirectives<'a> {
#[inline]
pub fn span(&self) -> &Span {
unsafe { &*((self.0 as *const u8).add(OFFSET_PROGRAM_SPAN) as *const Span) }
}
#[inline]
pub fn source_type(&self) -> &SourceType {
unsafe { &*((self.0 as *const u8).add(OFFSET_PROGRAM_SOURCE_TYPE) as *const SourceType) }
}
#[inline]
pub fn hashbang(&self) -> &Option<Hashbang<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_HASHBANG) as *const Option<Hashbang<'a>>)
}
}
#[inline]
pub fn body(&self) -> &Vec<'a, Statement<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_BODY) as *const Vec<'a, Statement<'a>>)
}
}
#[inline]
pub fn scope_id(&self) -> &Cell<Option<ScopeId>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_SCOPE_ID) as *const Cell<Option<ScopeId>>)
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct ProgramWithoutHashbang<'a>(pub(crate) *const Program<'a>);
@ -2258,6 +2221,43 @@ impl<'a> ProgramWithoutHashbang<'a> {
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct ProgramWithoutDirectives<'a>(pub(crate) *const Program<'a>);
impl<'a> ProgramWithoutDirectives<'a> {
#[inline]
pub fn span(&self) -> &Span {
unsafe { &*((self.0 as *const u8).add(OFFSET_PROGRAM_SPAN) as *const Span) }
}
#[inline]
pub fn source_type(&self) -> &SourceType {
unsafe { &*((self.0 as *const u8).add(OFFSET_PROGRAM_SOURCE_TYPE) as *const SourceType) }
}
#[inline]
pub fn hashbang(&self) -> &Option<Hashbang<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_HASHBANG) as *const Option<Hashbang<'a>>)
}
}
#[inline]
pub fn body(&self) -> &Vec<'a, Statement<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_BODY) as *const Vec<'a, Statement<'a>>)
}
}
#[inline]
pub fn scope_id(&self) -> &Cell<Option<ScopeId>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_SCOPE_ID) as *const Cell<Option<ScopeId>>)
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct ProgramWithoutBody<'a>(pub(crate) *const Program<'a>);
@ -2274,17 +2274,17 @@ impl<'a> ProgramWithoutBody<'a> {
}
#[inline]
pub fn directives(&self) -> &Vec<'a, Directive<'a>> {
pub fn hashbang(&self) -> &Option<Hashbang<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_DIRECTIVES)
as *const Vec<'a, Directive<'a>>)
&*((self.0 as *const u8).add(OFFSET_PROGRAM_HASHBANG) as *const Option<Hashbang<'a>>)
}
}
#[inline]
pub fn hashbang(&self) -> &Option<Hashbang<'a>> {
pub fn directives(&self) -> &Vec<'a, Directive<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_PROGRAM_HASHBANG) as *const Option<Hashbang<'a>>)
&*((self.0 as *const u8).add(OFFSET_PROGRAM_DIRECTIVES)
as *const Vec<'a, Directive<'a>>)
}
}

View file

@ -37,19 +37,19 @@ pub(crate) unsafe fn walk_program<'a, Tr: Traverse<'a>>(
ctx.set_current_scope_id(scope_id);
}
traverser.enter_program(&mut *node, ctx);
ctx.push_stack(Ancestor::ProgramDirectives(ancestor::ProgramWithoutDirectives(node)));
ctx.push_stack(Ancestor::ProgramHashbang(ancestor::ProgramWithoutHashbang(node)));
if let Some(field) =
&mut *((node as *mut u8).add(ancestor::OFFSET_PROGRAM_HASHBANG) as *mut Option<Hashbang>)
{
walk_hashbang(traverser, field as *mut _, ctx);
}
ctx.retag_stack(AncestorType::ProgramDirectives);
for item in (*((node as *mut u8).add(ancestor::OFFSET_PROGRAM_DIRECTIVES)
as *mut Vec<Directive>))
.iter_mut()
{
walk_directive(traverser, item as *mut _, ctx);
}
if let Some(field) =
&mut *((node as *mut u8).add(ancestor::OFFSET_PROGRAM_HASHBANG) as *mut Option<Hashbang>)
{
ctx.retag_stack(AncestorType::ProgramHashbang);
walk_hashbang(traverser, field as *mut _, ctx);
}
ctx.retag_stack(AncestorType::ProgramBody);
walk_statements(
traverser,