Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oxc_ast/src/ast/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub struct BigIntLiteral<'a> {
#[generate_derive(CloneIn, ContentEq, GetSpan, GetSpanMut, ESTree)]
#[estree(
rename = "Literal",
add_fields(value = crate::serialize::EmptyObject),
add_fields(value = crate::serialize::RegExpLiteralValue(self)),
add_ts = "value: {} | null",
)]
pub struct RegExpLiteral<'a> {
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_ast/src/generated/derive_estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ impl Serialize for RegExpLiteral<'_> {
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("regex", &crate::serialize::RegExpLiteralRegex(self))?;
map.serialize_entry("raw", &self.raw)?;
map.serialize_entry("value", &crate::serialize::EmptyObject)?;
map.serialize_entry("value", &crate::serialize::RegExpLiteralValue(self))?;
map.end()
}
}
Expand Down
37 changes: 24 additions & 13 deletions crates/oxc_ast/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,35 +110,46 @@ pub fn bigint_literal_bigint<'a>(lit: &'a BigIntLiteral<'a>) -> Cow<'a, str> {
lit.raw.strip_suffix('n').unwrap().cow_replace('_', "")
}

/// Serializer for `RegExpLiteral`'s `value` field.
///
/// `null` for invalid RegExp, otherwise empty object.
pub struct RegExpLiteralValue<'a>(pub &'a RegExpLiteral<'a>);

impl Serialize for RegExpLiteralValue<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if matches!(&self.0.regex.pattern, RegExpPattern::Invalid(_)) {
// `null`
().serialize(serializer)
} else {
// `{}`
let map = serializer.serialize_map(None)?;
map.end()
}
}
}

/// Serializer for `RegExpLiteral`'s `regex` field.
pub struct RegExpLiteralRegex<'a>(pub &'a RegExpLiteral<'a>);

impl Serialize for RegExpLiteralRegex<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("pattern", &self.0.regex.pattern)?;

// If `raw` field is present, flags must be in same order as in source to match Acorn.
// Count number of set bits in `flags` to get number of flags
// (cheaper than searching through `raw` for last `/`).
// If `raw` field is present, flags must be in same order as in source,
// and `pattern` exactly as in source, to match Acorn.
let flags = self.0.regex.flags;
if let Some(raw) = &self.0.raw {
// Count number of set bits in `flags` to get number of flags
// (cheaper than searching through `raw` for last `/`)
let flags_count = flags.bits().count_ones() as usize;
let flags_index = raw.len() - flags_count;
map.serialize_entry("pattern", &raw[1..flags_index - 1])?;
map.serialize_entry("flags", &raw[flags_index..])?;
} else {
map.serialize_entry("pattern", &self.0.regex.pattern)?;
map.serialize_entry("flags", &flags)?;
}
map.end()
}
}

/// A placeholder for `RegExpLiteral`'s `value` field.
pub struct EmptyObject;

impl Serialize for EmptyObject {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let map = serializer.serialize_map(None)?;
map.end()
}
}
Expand Down
8 changes: 6 additions & 2 deletions tasks/coverage/src/tools/estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::io::Write;
use std::path::{Path, PathBuf};

use oxc::{
allocator::Allocator, ast::utf8_to_utf16::Utf8ToUtf16, parser::Parser, span::SourceType,
allocator::Allocator,
ast::utf8_to_utf16::Utf8ToUtf16,
parser::{ParseOptions, Parser},
span::SourceType,
};

use crate::{
Expand Down Expand Up @@ -57,7 +60,8 @@ impl Case for EstreeTest262Case {
let is_module = self.base.is_module();
let source_type = SourceType::default().with_module(is_module);
let allocator = Allocator::new();
let ret = Parser::new(&allocator, source_text, source_type).parse();
let options = ParseOptions { parse_regular_expression: true, ..ParseOptions::default() };
let ret = Parser::new(&allocator, source_text, source_type).with_options(options).parse();
// Ignore empty AST or parse errors.
let mut program = ret.program;
if program.is_empty() || ret.panicked || !ret.errors.is_empty() {
Expand Down