Browse Source

Refactor Interner

refactor/interner
Haled Odat 1 year ago
parent
commit
753f22641e
  1. 4
      Cargo.lock
  2. 1
      boa_ast/Cargo.toml
  3. 11
      boa_ast/src/expression/identifier.rs
  4. 13
      boa_ast/src/expression/literal/template.rs
  5. 8
      boa_ast/src/function/class.rs
  6. 87
      boa_ast/src/keyword/mod.rs
  7. 127
      boa_ast/src/keyword/tests.rs
  8. 2
      boa_engine/src/bytecompiler/class.rs
  9. 4
      boa_engine/src/bytecompiler/declaration/declaration_pattern.rs
  10. 9
      boa_engine/src/bytecompiler/declarations.rs
  11. 15
      boa_engine/src/bytecompiler/expression/mod.rs
  12. 5
      boa_engine/src/bytecompiler/mod.rs
  13. 5
      boa_engine/src/bytecompiler/module.rs
  14. 10
      boa_engine/src/context/mod.rs
  15. 51
      boa_engine/src/environments/runtime/mod.rs
  16. 16
      boa_engine/src/module/mod.rs
  17. 6
      boa_engine/src/module/source.rs
  18. 4
      boa_engine/src/module/synthetic.rs
  19. 10
      boa_engine/src/optimizer/pass/constant_folding.rs
  20. 5
      boa_engine/src/vm/opcode/call/mod.rs
  21. 2
      boa_interner/Cargo.toml
  22. 80
      boa_interner/src/fixed_string.rs
  23. 80
      boa_interner/src/interned_str.rs
  24. 290
      boa_interner/src/lib.rs
  25. 194
      boa_interner/src/raw.rs
  26. 55
      boa_interner/src/tests.rs
  27. 20
      boa_macros/src/lib.rs
  28. 1
      boa_parser/Cargo.toml
  29. 77
      boa_parser/src/lexer/tests.rs
  30. 57
      boa_parser/src/parser/cursor/buffered_lexer/tests.rs
  31. 12
      boa_parser/src/parser/expression/identifiers.rs
  32. 2
      boa_parser/src/parser/expression/left_hand_side/mod.rs
  33. 14
      boa_parser/src/parser/expression/left_hand_side/optional/tests.rs
  34. 9
      boa_parser/src/parser/expression/left_hand_side/tests.rs
  35. 3
      boa_parser/src/parser/expression/primary/array_initializer/tests.rs
  36. 7
      boa_parser/src/parser/expression/primary/async_function_expression/tests.rs
  37. 8
      boa_parser/src/parser/expression/primary/async_generator_expression/tests.rs
  38. 11
      boa_parser/src/parser/expression/primary/function_expression/tests.rs
  39. 5
      boa_parser/src/parser/expression/primary/generator_expression/tests.rs
  40. 16
      boa_parser/src/parser/expression/primary/object_initializer/mod.rs
  41. 128
      boa_parser/src/parser/expression/primary/object_initializer/tests.rs
  42. 3
      boa_parser/src/parser/expression/primary/tests.rs
  43. 213
      boa_parser/src/parser/expression/tests.rs
  44. 173
      boa_parser/src/parser/function/tests.rs
  45. 13
      boa_parser/src/parser/statement/block/tests.rs
  46. 9
      boa_parser/src/parser/statement/break_stm/tests.rs
  47. 9
      boa_parser/src/parser/statement/continue_stm/tests.rs
  48. 2
      boa_parser/src/parser/statement/declaration/export.rs
  49. 7
      boa_parser/src/parser/statement/declaration/hoistable/async_function_decl/tests.rs
  50. 3
      boa_parser/src/parser/statement/declaration/hoistable/async_generator_decl/tests.rs
  51. 10
      boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs
  52. 31
      boa_parser/src/parser/statement/declaration/hoistable/class_decl/tests.rs
  53. 13
      boa_parser/src/parser/statement/declaration/hoistable/function_decl/tests.rs
  54. 3
      boa_parser/src/parser/statement/declaration/hoistable/generator_decl/tests.rs
  55. 2
      boa_parser/src/parser/statement/declaration/import.rs
  56. 39
      boa_parser/src/parser/statement/declaration/tests.rs
  57. 61
      boa_parser/src/parser/statement/iteration/tests.rs
  58. 8
      boa_parser/src/parser/statement/mod.rs
  59. 13
      boa_parser/src/parser/statement/switch/tests.rs
  60. 3
      boa_parser/src/parser/statement/throw/tests.rs
  61. 39
      boa_parser/src/parser/statement/try_stm/tests.rs
  62. 72
      boa_parser/src/parser/tests/mod.rs
  63. 103
      boa_types/src/string/common.rs
  64. 6
      boa_types/src/string/mod.rs

4
Cargo.lock generated

@ -357,7 +357,6 @@ dependencies = [
"arbitrary",
"bitflags 2.4.1",
"boa_interner",
"boa_macros",
"indexmap 2.1.0",
"num-bigint",
"rustc-hash",
@ -496,9 +495,9 @@ dependencies = [
"arbitrary",
"boa_gc",
"boa_macros",
"boa_types",
"hashbrown 0.14.2",
"indexmap 2.1.0",
"once_cell",
"phf",
"rustc-hash",
"serde",
@ -531,7 +530,6 @@ dependencies = [
"bitflags 2.4.1",
"boa_ast",
"boa_interner",
"boa_macros",
"boa_profiler",
"fast-float",
"icu_properties",

1
boa_ast/Cargo.toml

@ -17,7 +17,6 @@ temporal = []
[dependencies]
boa_interner.workspace = true
boa_macros.workspace = true
rustc-hash = { workspace = true, features = ["std"] }
bitflags.workspace = true
num-bigint.workspace = true

11
boa_ast/src/expression/identifier.rs

@ -1,9 +1,6 @@
//! Local identifier Expression.
use crate::{
visitor::{VisitWith, Visitor, VisitorMut},
ToStringEscaped,
};
use crate::visitor::{VisitWith, Visitor, VisitorMut};
use boa_interner::{Interner, Sym, ToInternedString};
use core::ops::ControlFlow;
@ -83,11 +80,7 @@ impl Identifier {
impl ToInternedString for Identifier {
#[inline]
fn to_interned_string(&self, interner: &Interner) -> String {
interner.resolve_expect(self.ident).join(
String::from,
ToStringEscaped::to_string_escaped,
true,
)
interner.resolve_expect(self.ident).to_std_string_escaped()
}
}

13
boa_ast/src/expression/literal/template.rs

@ -1,15 +1,12 @@
//! Template literal Expression.
use core::ops::ControlFlow;
use std::borrow::Cow;
use boa_interner::{Interner, Sym, ToInternedString};
use core::ops::ControlFlow;
use crate::{
expression::Expression,
try_break,
visitor::{VisitWith, Visitor, VisitorMut},
ToStringEscaped,
};
/// Template literals are string literals allowing embedded expressions.
@ -72,11 +69,9 @@ impl ToInternedString for TemplateLiteral {
for elt in &*self.elements {
match elt {
TemplateElement::String(s) => buf.push_str(&interner.resolve_expect(*s).join(
Cow::Borrowed,
|utf16| Cow::Owned(utf16.to_string_escaped()),
true,
)),
TemplateElement::String(s) => {
buf.push_str(&interner.resolve_expect(*s).to_std_string_escaped());
}
TemplateElement::Expr(n) => {
buf.push_str(&format!("${{{}}}", n.to_interned_string(interner)));
}

8
boa_ast/src/function/class.rs

@ -6,7 +6,7 @@ use crate::{
property::{MethodDefinition, PropertyName},
try_break,
visitor::{VisitWith, Visitor, VisitorMut},
Declaration, ToStringEscaped,
Declaration,
};
use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString};
use core::ops::ControlFlow;
@ -90,11 +90,7 @@ impl Class {
impl ToIndentedString for Class {
fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String {
let class_name = self.name.map_or(Cow::Borrowed(""), |s| {
interner.resolve_expect(s.sym()).join(
Cow::Borrowed,
|utf16| Cow::Owned(utf16.to_string_escaped()),
true,
)
Cow::Owned(interner.resolve_expect(s.sym()).to_std_string_escaped())
});
if self.elements.is_empty() && self.constructor().is_none() {
return format!(

87
boa_ast/src/keyword/mod.rs

@ -11,7 +11,6 @@
use crate::expression::operator::binary::{BinaryOp, RelationalOp};
use boa_interner::Sym;
use boa_macros::utf16;
use std::{convert::TryFrom, error, fmt, str::FromStr};
#[cfg(test)]
@ -491,49 +490,49 @@ impl Keyword {
/// Gets the keyword as a tuple of strings.
#[must_use]
pub const fn as_str(self) -> (&'static str, &'static [u16]) {
pub const fn as_str(self) -> &'static str {
match self {
Self::Await => ("await", utf16!("await")),
Self::Async => ("async", utf16!("async")),
Self::Break => ("break", utf16!("break")),
Self::Case => ("case", utf16!("case")),
Self::Catch => ("catch", utf16!("catch")),
Self::Class => ("class", utf16!("class")),
Self::Continue => ("continue", utf16!("continue")),
Self::Const => ("const", utf16!("const")),
Self::Debugger => ("debugger", utf16!("debugger")),
Self::Default => ("default", utf16!("default")),
Self::Delete => ("delete", utf16!("delete")),
Self::Do => ("do", utf16!("do")),
Self::Else => ("else", utf16!("else")),
Self::Enum => ("enum", utf16!("enum")),
Self::Extends => ("extends", utf16!("extends")),
Self::Export => ("export", utf16!("export")),
Self::False => ("false", utf16!("false")),
Self::Finally => ("finally", utf16!("finally")),
Self::For => ("for", utf16!("for")),
Self::Function => ("function", utf16!("function")),
Self::If => ("if", utf16!("if")),
Self::In => ("in", utf16!("in")),
Self::InstanceOf => ("instanceof", utf16!("instanceof")),
Self::Import => ("import", utf16!("import")),
Self::Let => ("let", utf16!("let")),
Self::New => ("new", utf16!("new")),
Self::Null => ("null", utf16!("null")),
Self::Of => ("of", utf16!("of")),
Self::Return => ("return", utf16!("return")),
Self::Super => ("super", utf16!("super")),
Self::Switch => ("switch", utf16!("switch")),
Self::This => ("this", utf16!("this")),
Self::Throw => ("throw", utf16!("throw")),
Self::True => ("true", utf16!("true")),
Self::Try => ("try", utf16!("try")),
Self::TypeOf => ("typeof", utf16!("typeof")),
Self::Var => ("var", utf16!("var")),
Self::Void => ("void", utf16!("void")),
Self::While => ("while", utf16!("while")),
Self::With => ("with", utf16!("with")),
Self::Yield => ("yield", utf16!("yield")),
Self::Await => "await",
Self::Async => "async",
Self::Break => "break",
Self::Case => "case",
Self::Catch => "catch",
Self::Class => "class",
Self::Continue => "continue",
Self::Const => "const",
Self::Debugger => "debugger",
Self::Default => "default",
Self::Delete => "delete",
Self::Do => "do",
Self::Else => "else",
Self::Enum => "enum",
Self::Extends => "extends",
Self::Export => "export",
Self::False => "false",
Self::Finally => "finally",
Self::For => "for",
Self::Function => "function",
Self::If => "if",
Self::In => "in",
Self::InstanceOf => "instanceof",
Self::Import => "import",
Self::Let => "let",
Self::New => "new",
Self::Null => "null",
Self::Of => "of",
Self::Return => "return",
Self::Super => "super",
Self::Switch => "switch",
Self::This => "this",
Self::Throw => "throw",
Self::True => "true",
Self::Try => "try",
Self::TypeOf => "typeof",
Self::Var => "var",
Self::Void => "void",
Self::While => "while",
Self::With => "with",
Self::Yield => "yield",
}
}
@ -661,6 +660,6 @@ impl FromStr for Keyword {
impl fmt::Display for Keyword {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str().0, f)
fmt::Display::fmt(self.as_str(), f)
}
}

127
boa_ast/src/keyword/tests.rs

@ -71,171 +71,130 @@ fn as_binary_op() {
fn as_str() {
for k in all_keywords() {
match k.as_str() {
("await", utf16) => {
"await" => {
assert_eq!(k, Keyword::Await);
assert_eq!(utf16, utf16!("await"));
}
("async", utf16) => {
"async" => {
assert_eq!(k, Keyword::Async);
assert_eq!(utf16, utf16!("async"));
}
("break", utf16) => {
"break" => {
assert_eq!(k, Keyword::Break);
assert_eq!(utf16, utf16!("break"));
}
("case", utf16) => {
"case" => {
assert_eq!(k, Keyword::Case);
assert_eq!(utf16, utf16!("case"));
}
("catch", utf16) => {
"catch" => {
assert_eq!(k, Keyword::Catch);
assert_eq!(utf16, utf16!("catch"));
}
("class", utf16) => {
"class" => {
assert_eq!(k, Keyword::Class);
assert_eq!(utf16, utf16!("class"));
}
("continue", utf16) => {
"continue" => {
assert_eq!(k, Keyword::Continue);
assert_eq!(utf16, utf16!("continue"));
}
("const", utf16) => {
"const" => {
assert_eq!(k, Keyword::Const);
assert_eq!(utf16, utf16!("const"));
}
("debugger", utf16) => {
"debugger" => {
assert_eq!(k, Keyword::Debugger);
assert_eq!(utf16, utf16!("debugger"));
}
("default", utf16) => {
"default" => {
assert_eq!(k, Keyword::Default);
assert_eq!(utf16, utf16!("default"));
}
("delete", utf16) => {
"delete" => {
assert_eq!(k, Keyword::Delete);
assert_eq!(utf16, utf16!("delete"));
}
("do", utf16) => {
"do" => {
assert_eq!(k, Keyword::Do);
assert_eq!(utf16, utf16!("do"));
}
("else", utf16) => {
"else" => {
assert_eq!(k, Keyword::Else);
assert_eq!(utf16, utf16!("else"));
}
("enum", utf16) => {
"enum" => {
assert_eq!(k, Keyword::Enum);
assert_eq!(utf16, utf16!("enum"));
}
("extends", utf16) => {
"extends" => {
assert_eq!(k, Keyword::Extends);
assert_eq!(utf16, utf16!("extends"));
}
("export", utf16) => {
"export" => {
assert_eq!(k, Keyword::Export);
assert_eq!(utf16, utf16!("export"));
}
("false", utf16) => {
"false" => {
assert_eq!(k, Keyword::False);
assert_eq!(utf16, utf16!("false"));
}
("finally", utf16) => {
"finally" => {
assert_eq!(k, Keyword::Finally);
assert_eq!(utf16, utf16!("finally"));
}
("for", utf16) => {
"for" => {
assert_eq!(k, Keyword::For);
assert_eq!(utf16, utf16!("for"));
}
("function", utf16) => {
"function" => {
assert_eq!(k, Keyword::Function);
assert_eq!(utf16, utf16!("function"));
}
("if", utf16) => {
"if" => {
assert_eq!(k, Keyword::If);
assert_eq!(utf16, utf16!("if"));
}
("in", utf16) => {
"in" => {
assert_eq!(k, Keyword::In);
assert_eq!(utf16, utf16!("in"));
}
("instanceof", utf16) => {
"instanceof" => {
assert_eq!(k, Keyword::InstanceOf);
assert_eq!(utf16, utf16!("instanceof"));
}
("import", utf16) => {
"import" => {
assert_eq!(k, Keyword::Import);
assert_eq!(utf16, utf16!("import"));
}
("let", utf16) => {
"let" => {
assert_eq!(k, Keyword::Let);
assert_eq!(utf16, utf16!("let"));
}
("new", utf16) => {
"new" => {
assert_eq!(k, Keyword::New);
assert_eq!(utf16, utf16!("new"));
}
("null", utf16) => {
"null" => {
assert_eq!(k, Keyword::Null);
assert_eq!(utf16, utf16!("null"));
}
("of", utf16) => {
"of" => {
assert_eq!(k, Keyword::Of);
assert_eq!(utf16, utf16!("of"));
}
("return", utf16) => {
"return" => {
assert_eq!(k, Keyword::Return);
assert_eq!(utf16, utf16!("return"));
}
("super", utf16) => {
"super" => {
assert_eq!(k, Keyword::Super);
assert_eq!(utf16, utf16!("super"));
}
("switch", utf16) => {
"switch" => {
assert_eq!(k, Keyword::Switch);
assert_eq!(utf16, utf16!("switch"));
}
("this", utf16) => {
"this" => {
assert_eq!(k, Keyword::This);
assert_eq!(utf16, utf16!("this"));
}
("throw", utf16) => {
"throw" => {
assert_eq!(k, Keyword::Throw);
assert_eq!(utf16, utf16!("throw"));
}
("true", utf16) => {
"true" => {
assert_eq!(k, Keyword::True);
assert_eq!(utf16, utf16!("true"));
}
("try", utf16) => {
"try" => {
assert_eq!(k, Keyword::Try);
assert_eq!(utf16, utf16!("try"));
}
("typeof", utf16) => {
"typeof" => {
assert_eq!(k, Keyword::TypeOf);
assert_eq!(utf16, utf16!("typeof"));
}
("var", utf16) => {
"var" => {
assert_eq!(k, Keyword::Var);
assert_eq!(utf16, utf16!("var"));
}
("void", utf16) => {
"void" => {
assert_eq!(k, Keyword::Void);
assert_eq!(utf16, utf16!("void"));
}
("while", utf16) => {
"while" => {
assert_eq!(k, Keyword::While);
assert_eq!(utf16, utf16!("while"));
}
("with", utf16) => {
"with" => {
assert_eq!(k, Keyword::With);
assert_eq!(utf16, utf16!("with"));
}
("yield", utf16) => {
"yield" => {
assert_eq!(k, Keyword::Yield);
assert_eq!(utf16, utf16!("yield"));
}
(_, _) => unreachable!("unknown keyword {k:?} found"),
_ => unreachable!("unknown keyword {k:?} found"),
}
}
}
@ -341,7 +300,7 @@ fn try_into_binary_op() {
#[test]
fn from_str() {
for k in all_keywords() {
let str = k.as_str().0;
let str = k.as_str();
assert_eq!(str.parse::<Keyword>().unwrap(), k);
}

2
boa_engine/src/bytecompiler/class.rs

@ -269,7 +269,7 @@ impl ByteCompiler<'_, '_> {
match name {
PropertyName::Literal(name) => {
self.emit_push_literal(Literal::String(
self.interner().resolve_expect(*name).into_common(false),
self.interner().resolve_expect(*name).into(),
));
}
PropertyName::Computed(name) => {

4
boa_engine/src/bytecompiler/declaration/declaration_pattern.rs

@ -77,7 +77,7 @@ impl ByteCompiler<'_, '_> {
for key in excluded_keys {
self.emit_push_literal(Literal::String(
self.interner().resolve_expect(key.sym()).into_common(false),
self.interner().resolve_expect(key.sym()).into(),
));
}
@ -98,7 +98,7 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::PushEmptyObject);
for key in excluded_keys {
self.emit_push_literal(Literal::String(
self.interner().resolve_expect(key.sym()).into_common(false),
self.interner().resolve_expect(key.sym()).into(),
));
}
self.emit(

9
boa_engine/src/bytecompiler/declarations.rs

@ -286,7 +286,7 @@ impl ByteCompiler<'_, '_> {
let function = create_function_object_fast(code, self.context);
// c. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false).
let name = js_string!(self.interner().resolve_expect(name.sym()).utf16());
let name = js_string!(self.interner().resolve_expect(name.sym()));
self.context
.create_global_function_binding(name, function, false)?;
}
@ -454,12 +454,7 @@ impl ByteCompiler<'_, '_> {
let private_identifiers = self.context.vm.environments.private_name_descriptions();
let private_identifiers = private_identifiers
.into_iter()
.map(|ident| {
self.context
.interner()
.get(ident.as_str().as_str_ref())
.expect("string should be in interner")
})
.map(|ident| self.context.interner_mut().get_or_intern(ident.as_str()))
.collect();
// 7. If AllPrivateIdentifiersValid of body with argument privateIdentifiers is false, throw a SyntaxError exception.

15
boa_engine/src/bytecompiler/expression/mod.rs

@ -22,9 +22,9 @@ use boa_ast::{
impl ByteCompiler<'_, '_> {
fn compile_literal(&mut self, lit: &AstLiteral, use_expr: bool) {
match lit {
AstLiteral::String(v) => self.emit_push_literal(Literal::String(
self.interner().resolve_expect(*v).into_common(false),
)),
AstLiteral::String(v) => {
self.emit_push_literal(Literal::String(self.interner().resolve_expect(*v).into()));
}
AstLiteral::Int(v) => self.emit_push_integer(*v),
AstLiteral::Num(v) => self.emit_push_rational(*v),
AstLiteral::BigInt(v) => {
@ -58,9 +58,8 @@ impl ByteCompiler<'_, '_> {
fn compile_template_literal(&mut self, template_literal: &TemplateLiteral, use_expr: bool) {
for element in template_literal.elements() {
match element {
TemplateElement::String(s) => self.emit_push_literal(Literal::String(
self.interner().resolve_expect(*s).into_common(false),
)),
TemplateElement::String(s) => self
.emit_push_literal(Literal::String(self.interner().resolve_expect(*s).into())),
TemplateElement::Expr(expr) => {
self.compile_expr(expr, true);
}
@ -269,13 +268,13 @@ impl ByteCompiler<'_, '_> {
for (cooked, raw) in template.cookeds().iter().zip(template.raws()) {
if let Some(cooked) = cooked {
self.emit_push_literal(Literal::String(
self.interner().resolve_expect(*cooked).into_common(false),
self.interner().resolve_expect(*cooked).into(),
));
} else {
self.emit_opcode(Opcode::PushUndefined);
}
self.emit_push_literal(Literal::String(
self.interner().resolve_expect(*raw).into_common(false),
self.interner().resolve_expect(*raw).into(),
));
}

5
boa_engine/src/bytecompiler/mod.rs

@ -371,9 +371,9 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
return *index;
}
let string = self.interner().resolve_expect(name.sym()).utf16();
let string = js_string!(self.interner().resolve_expect(name.sym()));
let index = self.constants.len() as u32;
self.constants.push(Constant::String(js_string!(string)));
self.constants.push(Constant::String(string));
self.names_map.insert(name, index);
index
}
@ -1453,7 +1453,6 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
.context
.interner()
.resolve_expect(self.function_name)
.utf16()
.into();
CodeBlock {

5
boa_engine/src/bytecompiler/module.rs

@ -57,10 +57,7 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(expr, true);
if expr.is_anonymous_function_definition() {
let default = self
.interner()
.resolve_expect(Sym::DEFAULT)
.into_common(false);
let default = self.interner().resolve_expect(Sym::DEFAULT).into();
self.emit_push_literal(Literal::String(default));
self.emit_opcode(Opcode::Swap);
self.emit(Opcode::SetFunctionName, &[Operand::U8(0)]);

10
boa_engine/src/context/mod.rs

@ -617,7 +617,7 @@ impl Context<'_> {
let global_object = self.realm().global_object().clone();
// 3. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
let name = self.interner().resolve_expect(name.sym()).utf16().into();
let name = JsString::from(self.interner().resolve_expect(name.sym())).into();
let existing_prop = global_object.__get_own_property__(&name, self)?;
// 4. If existingProp is undefined, return ? IsExtensible(globalObject).
@ -654,7 +654,7 @@ impl Context<'_> {
let global_object = self.realm().global_object().clone();
// 3. Let hasProperty be ? HasOwnProperty(globalObject, N).
let name = PropertyKey::from(self.interner().resolve_expect(name.sym()).utf16());
let name = JsString::from(self.interner().resolve_expect(name.sym()));
let has_property = global_object.has_own_property(name, self)?;
// 4. If hasProperty is true, return true.
@ -682,7 +682,7 @@ impl Context<'_> {
let global_object = self.realm().global_object().clone();
// 3. Let hasProperty be ? HasOwnProperty(globalObject, N).
let name = PropertyKey::from(self.interner().resolve_expect(name.sym()).utf16());
let name = JsString::from(self.interner().resolve_expect(name.sym()));
let has_property = global_object.has_own_property(name.clone(), self)?;
// 4. Let extensible be ? IsExtensible(globalObject).
@ -773,8 +773,8 @@ impl Context<'_> {
let global_object = self.realm().global_object().clone();
// 3. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
let name = PropertyKey::from(self.interner().resolve_expect(name.sym()).utf16());
let existing_prop = global_object.__get_own_property__(&name, self)?;
let name = JsString::from(self.interner().resolve_expect(name.sym()));
let existing_prop = global_object.__get_own_property__(&name.into(), self)?;
// 4. If existingProp is undefined, return false.
let Some(existing_prop) = existing_prop else {

51
boa_engine/src/environments/runtime/mod.rs

@ -401,12 +401,12 @@ impl EnvironmentStack {
}
/// Return all private name descriptions in all private environments.
pub(crate) fn private_name_descriptions(&self) -> Vec<&JsString> {
pub(crate) fn private_name_descriptions(&self) -> Vec<JsString> {
let mut names = Vec::new();
for environment in self.private_stack.iter().rev() {
for name in environment.descriptions() {
if !names.contains(&name) {
names.push(name);
if !names.contains(name) {
names.push(name.clone());
}
}
}
@ -523,10 +523,7 @@ impl Context<'_> {
}
Environment::Object(o) => {
let o = o.clone();
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
if o.has_property(key.clone(), self)? {
if let Some(unscopables) = o.get(JsSymbol::unscopables(), self)?.as_object()
{
@ -552,19 +549,13 @@ impl Context<'_> {
/// Panics if the environment or binding index are out of range.
pub(crate) fn is_initialized_binding(&mut self, locator: &BindingLocator) -> JsResult<bool> {
if locator.global {
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
self.global_object().has_property(key, self)
} else {
match self.environment_expect(locator.environment_index) {
Environment::Declarative(env) => Ok(env.get(locator.binding_index).is_some()),
Environment::Object(obj) => {
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
obj.clone().has_property(key, self)
}
}
@ -579,10 +570,7 @@ impl Context<'_> {
pub(crate) fn get_binding(&mut self, locator: BindingLocator) -> JsResult<Option<JsValue>> {
if locator.global {
let global = self.global_object();
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
if global.has_property(key.clone(), self)? {
global.get(key, self).map(Some)
} else {
@ -593,10 +581,7 @@ impl Context<'_> {
Environment::Declarative(env) => Ok(env.get(locator.binding_index)),
Environment::Object(obj) => {
let obj = obj.clone();
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
obj.get(key, self).map(Some)
}
}
@ -616,10 +601,7 @@ impl Context<'_> {
strict: bool,
) -> JsResult<()> {
if locator.global {
let key = self
.interner()
.resolve_expect(locator.name().sym())
.into_common::<JsString>(false);
let key: JsString = self.interner().resolve_expect(locator.name().sym()).into();
self.global_object().set(key, value, strict, self)?;
} else {
@ -629,10 +611,7 @@ impl Context<'_> {
}
Environment::Object(obj) => {
let obj = obj.clone();
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
obj.set(key, value, strict, self)?;
}
@ -651,20 +630,14 @@ impl Context<'_> {
/// Panics if the environment or binding index are out of range.
pub(crate) fn delete_binding(&mut self, locator: BindingLocator) -> JsResult<bool> {
if locator.is_global() {
let key: JsString = self
.interner()
.resolve_expect(locator.name().sym())
.into_common::<JsString>(false);
let key: JsString = self.interner().resolve_expect(locator.name().sym()).into();
self.global_object().__delete__(&key.into(), self)
} else {
match self.environment_expect(locator.environment_index) {
Environment::Declarative(_) => Ok(false),
Environment::Object(obj) => {
let obj = obj.clone();
let key: JsString = self
.interner()
.resolve_expect(locator.name.sym())
.into_common(false);
let key: JsString = self.interner().resolve_expect(locator.name.sym()).into();
obj.__delete__(&key.into(), self)
}

16
boa_engine/src/module/mod.rs

@ -181,11 +181,7 @@ impl Module {
) -> Self {
let names: FxHashSet<Sym> = export_names
.iter()
.map(|string| {
context
.interner_mut()
.get_or_intern(string.as_str().as_str_ref())
})
.map(|string| context.interner_mut().get_or_intern(string.as_str()))
.collect();
let realm = realm.unwrap_or_else(|| context.realm().clone());
let inner = Gc::new_cyclic(|weak| {
@ -594,15 +590,7 @@ impl ModuleNamespace {
// 6. Let sortedExports be a List whose elements are the elements of exports ordered as if an Array of the same values had been sorted using %Array.prototype.sort% using undefined as comparefn.
let mut exports = names
.into_iter()
.map(|sym| {
(
context
.interner()
.resolve_expect(sym)
.into_common::<JsString>(false),
sym,
)
})
.map(|sym| (context.interner().resolve_expect(sym).into(), sym))
.collect::<IndexMap<_, _, _>>();
exports.sort_keys();

6
boa_engine/src/module/source.rs

@ -436,10 +436,8 @@ impl SourceTextModule {
// 1. Perform HostLoadImportedModule(module, required, state.[[HostDefined]], state).
// 2. NOTE: HostLoadImportedModule will call FinishLoadingImportedModule, which re-enters
// the graph loading process through ContinueModuleLoading.
let name_specifier: JsString = context
.interner()
.resolve_expect(required)
.into_common(false);
let name_specifier: JsString =
context.interner().resolve_expect(required).into();
let src = self.clone();
let state = state.clone();
context.module_loader().load_imported_module(

4
boa_engine/src/module/synthetic.rs

@ -359,9 +359,7 @@ impl SyntheticModule {
export_value: JsValue,
context: &mut Context<'_>,
) -> JsResult<()> {
let identifier = context
.interner_mut()
.get_or_intern(export_name.as_str().as_str_ref());
let identifier = context.interner_mut().get_or_intern(export_name.as_str());
let identifier = Identifier::new(identifier);
let environment = self

10
boa_engine/src/optimizer/pass/constant_folding.rs

@ -15,9 +15,7 @@ use boa_ast::{
fn literal_to_js_value(literal: &Literal, context: &mut Context<'_>) -> JsValue {
match literal {
Literal::String(v) => JsValue::new(JsString::from(
context.interner().resolve_expect(*v).utf16(),
)),
Literal::String(v) => JsValue::new(JsString::from(context.interner().resolve_expect(*v))),
Literal::Num(v) => JsValue::new(*v),
Literal::Int(v) => JsValue::new(*v),
Literal::BigInt(v) => JsValue::new(JsBigInt::new(v.clone())),
@ -32,11 +30,7 @@ fn js_value_to_literal(value: JsValue, context: &mut Context<'_>) -> Literal {
JsValue::Null => Literal::Null,
JsValue::Undefined => Literal::Undefined,
JsValue::Boolean(v) => Literal::Bool(v),
JsValue::String(v) => Literal::String(
context
.interner_mut()
.get_or_intern(v.as_str().as_str_ref()),
),
JsValue::String(v) => Literal::String(context.interner_mut().get_or_intern(v.as_str())),
JsValue::Rational(v) => Literal::Num(v),
JsValue::Integer(v) => Literal::Int(v),
JsValue::BigInt(v) => Literal::BigInt(Box::new(v.as_inner().clone())),

5
boa_engine/src/vm/opcode/call/mod.rs

@ -299,9 +299,8 @@ impl Operation for ImportCall {
panic!("referrer cannot be a synthetic module");
};
let sym = context
.interner_mut()
.get_or_intern(specifier.as_str().as_str_ref());
let sym =
context.interner_mut().get_or_intern(specifier.as_str());
let mut loaded_modules = src.loaded_modules().borrow_mut();

2
boa_interner/Cargo.toml

@ -17,10 +17,10 @@ arbitrary = ["dep:arbitrary"]
[dependencies]
boa_macros.workspace = true
boa_gc.workspace = true
boa_types.workspace = true
phf = { workspace = true, default-features = false, features = ["macros"] }
rustc-hash = { workspace = true, default-features = false }
static_assertions.workspace = true
once_cell = { workspace = true, features = ["std"]}
indexmap.workspace = true
serde = { workspace = true, features = ["derive"], optional = true }
arbitrary = { workspace = true, features = ["derive"], optional = true }

80
boa_interner/src/fixed_string.rs

@ -1,80 +0,0 @@
use alloc::vec::Vec;
use crate::interned_str::InternedStr;
#[derive(Debug)]
pub(super) struct FixedString<Char> {
inner: Vec<Char>,
}
impl<Char> Default for FixedString<Char> {
fn default() -> Self {
Self {
inner: Vec::default(),
}
}
}
impl<Char> FixedString<Char> {
/// Creates a new, pinned [`FixedString`].
pub(super) fn new(capacity: usize) -> Self {
Self {
inner: Vec::with_capacity(capacity),
}
}
/// Gets the maximum capacity of the [`FixedString`].
pub(super) fn capacity(&self) -> usize {
self.inner.capacity()
}
/// Returns `true` if the [`FixedString`] has length zero,
/// and `false` otherwise.
pub(super) fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
impl<Char> FixedString<Char>
where
Char: Clone,
{
/// Tries to push `string` to the [`FixedString`], and returns
/// an [`InternedStr`] pointer to the stored `string`, or
/// `None` if the capacity is not enough to store `string`.
///
/// # Safety
///
/// The caller is responsible for ensuring `self` outlives the returned
/// [`InternedStr`].
pub(super) unsafe fn push(&mut self, string: &[Char]) -> Option<InternedStr<Char>> {
let capacity = self.inner.capacity();
(capacity >= self.inner.len() + string.len()).then(|| {
// SAFETY:
// The caller is responsible for extending the lifetime
// of `self` to outlive the return value.
unsafe { self.push_unchecked(string) }
})
}
/// Pushes `string` to the [`FixedString`], and returns
/// an [`InternedStr`] pointer to the stored `string`, without
/// checking if the total `capacity` is enough to store `string`,
/// and without checking if the string is correctly aligned.
///
/// # Safety
///
/// The caller is responsible for ensuring that `self` outlives the returned
/// [`InternedStr`] and that it has enough capacity to store `string` without
/// reallocating.
pub(super) unsafe fn push_unchecked(&mut self, string: &[Char]) -> InternedStr<Char> {
let old_len = self.inner.len();
self.inner.extend_from_slice(string);
// SAFETY: The caller is responsible for extending the lifetime
// of `self` to outlive the return value, and for ensuring
// the alignment of `string` is correct.
let ptr = &self.inner[old_len..self.inner.len()];
unsafe { InternedStr::new(ptr.into()) }
}
}

80
boa_interner/src/interned_str.rs

@ -1,80 +0,0 @@
use core::{hash::Hash, ptr::NonNull};
/// Wrapper for an interned str pointer, required to
/// quickly check using a hash if a string is inside an [`Interner`][`super::Interner`].
///
/// # Safety
///
/// This struct could cause Undefined Behaviour on:
/// - Use without ensuring the referenced memory is still allocated.
/// - Construction of an [`InternedStr`] from an invalid [`NonNull<Char>`] pointer.
/// - Construction of an [`InternedStr`] from a [`NonNull<Char>`] pointer
/// without checking if the pointed memory of the [`NonNull<Char>`] outlives
/// the [`InternedStr`].
///
/// In general, this should not be used outside of an [`Interner`][`super::Interner`].
#[derive(Debug)]
pub(super) struct InternedStr<Char> {
ptr: NonNull<[Char]>,
}
impl<Char> InternedStr<Char> {
/// Create a new interned string from the given `*const u8` pointer,
/// length and encoding kind
///
/// # Safety
///
/// Not maintaining the invariants specified on the struct definition
/// could cause Undefined Behaviour.
pub(super) const unsafe fn new(ptr: NonNull<[Char]>) -> Self {
Self { ptr }
}
/// Returns a shared reference to the underlying string.
///
/// # Safety
///
/// Not maintaining the invariants specified on the struct definition
/// could cause Undefined Behaviour.
pub(super) unsafe fn as_ref(&self) -> &[Char] {
// SAFETY:
// The caller must ensure `ptr` is still valid throughout the
// lifetime of `self`.
unsafe { self.ptr.as_ref() }
}
}
impl<Char> Clone for InternedStr<Char> {
fn clone(&self) -> Self {
*self
}
}
impl<Char> Copy for InternedStr<Char> {}
impl<Char> Eq for InternedStr<Char> where Char: Eq {}
impl<Char> PartialEq for InternedStr<Char>
where
Char: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
// SAFETY: The caller must verify the invariants
// specified in the struct definition.
unsafe { self.as_ref() == other.as_ref() }
}
}
impl<Char> Hash for InternedStr<Char>
where
Char: Hash,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
// SAFETY:
// The caller must ensure `ptr` is still valid throughout the
// lifetime of `self`.
unsafe {
self.as_ref().hash(state);
}
}
}

290
boa_interner/src/lib.rs

@ -77,19 +77,27 @@
extern crate alloc;
mod fixed_string;
mod interned_str;
mod raw;
mod sym;
#[cfg(test)]
mod tests;
use alloc::{borrow::Cow, format, string::String};
use raw::RawInterner;
use alloc::{format, string::String};
use boa_types::string::{
common::{StaticJsStrings, RAW_STATICS},
JsString, JsStringSlice,
};
use alloc::vec::Vec;
use core::hash::BuildHasherDefault;
use hashbrown::{hash_map::Entry, HashMap};
use rustc_hash::FxHasher;
pub use sym::*;
pub use boa_types::js_string;
type Map<T, U> = HashMap<T, U, BuildHasherDefault<FxHasher>>;
/// An enumeration of all slice types [`Interner`] can internally store.
///
/// This struct allows us to intern either `UTF-8` or `UTF-16` str references, which are the two
@ -121,107 +129,47 @@ impl<'a, const N: usize> From<&'a [u16; N]> for JStrRef<'a> {
}
}
/// A double reference to an interned string inside [`Interner`].
///
/// [`JSInternedStrRef::utf8`] returns an [`Option`], since not every `UTF-16` string is fully
/// representable as a `UTF-8` string (because of unpaired surrogates). However, every `UTF-8`
/// string is representable as a `UTF-16` string, so `JSInternedStrRef::utf8` returns a
/// [<code>&\[u16\]</code>][core::slice].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct JSInternedStrRef<'a, 'b> {
utf8: Option<&'a str>,
utf16: &'b [u16],
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct JSInternedStrRef {
inner: JsString,
}
impl<'a, 'b> JSInternedStrRef<'a, 'b> {
/// Returns the inner reference to the interned string in `UTF-8` encoding.
/// if the string is not representable in `UTF-8`, returns [`None`]
#[inline]
#[must_use]
pub const fn utf8(&self) -> Option<&'a str> {
self.utf8
}
/// Returns the inner reference to the interned string in `UTF-16` encoding.
#[inline]
#[must_use]
pub const fn utf16(&self) -> &'b [u16] {
self.utf16
}
/// Joins the result of both possible strings into a common type.
///
/// If `self` is representable by a `UTF-8` string and the `prioritize_utf8` argument is set,
/// it will prioritize calling `f`, and will only call `g` if `self` is only representable by a
/// `UTF-16` string. Otherwise, it will directly call `g`.
pub fn join<F, G, T>(self, f: F, g: G, prioritize_utf8: bool) -> T
where
F: FnOnce(&'a str) -> T,
G: FnOnce(&'b [u16]) -> T,
{
if prioritize_utf8 {
if let Some(str) = self.utf8 {
return f(str);
}
impl core::ops::Deref for JSInternedStrRef {
type Target = JsString;
fn deref(&self) -> &Self::Target {
&self.inner
}
g(self.utf16)
}
/// Same as [`join`][`JSInternedStrRef::join`], but where you can pass an additional context.
///
/// Useful when you have a `&mut Context` context that cannot be borrowed by both closures at
/// the same time.
pub fn join_with_context<C, F, G, T>(self, f: F, g: G, ctx: C, prioritize_utf8: bool) -> T
where
F: FnOnce(&'a str, C) -> T,
G: FnOnce(&'b [u16], C) -> T,
{
if prioritize_utf8 {
if let Some(str) = self.utf8 {
return f(str, ctx);
}
impl From<JsString> for JSInternedStrRef {
fn from(value: JsString) -> Self {
Self { inner: value }
}
g(self.utf16, ctx)
}
/// Converts both string types into a common type `C`.
///
/// If `self` is representable by a `UTF-8` string and the `prioritize_utf8` argument is set, it
/// will prioritize converting its `UTF-8` representation first, and will only convert its
/// `UTF-16` representation if it is only representable by a `UTF-16` string. Otherwise, it will
/// directly convert its `UTF-16` representation.
pub fn into_common<C>(self, prioritize_utf8: bool) -> C
where
C: From<&'a str> + From<&'b [u16]>,
{
self.join(Into::into, Into::into, prioritize_utf8)
impl From<JSInternedStrRef> for JsString {
fn from(value: JSInternedStrRef) -> Self {
value.inner
}
}
impl core::fmt::Display for JSInternedStrRef<'_, '_> {
impl core::fmt::Display for JSInternedStrRef {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.join_with_context(
core::fmt::Display::fmt,
|js, f| {
char::decode_utf16(js.iter().copied())
char::decode_utf16(self.inner.iter())
.map(|r| match r {
Ok(c) => String::from(c),
Err(e) => format!("\\u{:04X}", e.unpaired_surrogate()),
})
.collect::<String>()
.fmt(f)
},
f,
true,
)
}
}
/// The string interner for Boa.
#[derive(Debug, Default)]
pub struct Interner {
utf8_interner: RawInterner<u8>,
utf16_interner: RawInterner<u16>,
symbol_cache: Map<JsString, usize>,
full: Vec<JsString>,
}
impl Interner {
@ -235,10 +183,10 @@ impl Interner {
/// Creates a new [`Interner`] with the specified capacity.
#[inline]
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
pub fn with_capacity(_capacity: usize) -> Self {
Self {
utf8_interner: RawInterner::with_capacity(capacity),
utf16_interner: RawInterner::with_capacity(capacity),
symbol_cache: Map::default(),
full: Vec::new(),
}
}
@ -246,37 +194,14 @@ impl Interner {
#[inline]
#[must_use]
pub fn len(&self) -> usize {
// `utf16_interner.len()` == `utf8_interner.len()`,
// so we can use any of them.
COMMON_STRINGS_UTF8.len() + self.utf16_interner.len()
self.full.len()
}
/// Returns `true` if the [`Interner`] contains no interned strings.
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
COMMON_STRINGS_UTF8.is_empty() && self.utf16_interner.is_empty()
}
/// Returns the symbol for the given string if any.
///
/// Can be used to query if a string has already been interned without interning.
pub fn get<'a, T>(&self, string: T) -> Option<Sym>
where
T: Into<JStrRef<'a>>,
{
let string = string.into();
Self::get_common(string).or_else(|| {
let index = match string {
JStrRef::Utf8(s) => self.utf8_interner.get(s.as_bytes()),
JStrRef::Utf16(s) => self.utf16_interner.get(s),
};
// SAFETY:
// `get_or_intern/get_or_intern_static` already have checks to avoid returning indices
// that could cause overflows, meaning the indices returned by
// `idx + 1 + COMMON_STRINGS_UTF8.len()` cannot cause overflows.
unsafe { index.map(|i| Sym::new_unchecked(i + 1 + COMMON_STRINGS_UTF8.len())) }
})
self.full.is_empty()
}
/// Interns the given string.
@ -288,116 +213,39 @@ impl Interner {
/// If the interner already interns the maximum number of strings possible by the chosen symbol type.
pub fn get_or_intern<'a, T>(&mut self, string: T) -> Sym
where
T: Into<JStrRef<'a>>,
T: Into<JsStringSlice<'a>>,
{
let string = string.into();
self.get(string).unwrap_or_else(|| {
let (utf8, utf16) = match string {
JStrRef::Utf8(s) => (
Some(Cow::Borrowed(s)),
Cow::Owned(s.encode_utf16().collect()),
),
JStrRef::Utf16(s) => (String::from_utf16(s).ok().map(Cow::Owned), Cow::Borrowed(s)),
};
// We need a way to check for the strings that can be interned by `utf16_interner` but
// not by `utf8_interner` (since there are some UTF-16 strings with surrogates that are
// not representable in UTF-8), so we use the sentinel value `""` as a marker indicating
// that the `Sym` corresponding to that string is only available in `utf16_interner`.
//
// We don't need to worry about matches with `""` inside `get`, because
// `COMMON_STRINGS_UTF8` filters all the empty strings before interning.
let index = if let Some(utf8) = utf8 {
self.utf8_interner.intern(utf8.as_bytes())
} else {
self.utf8_interner.intern_static(b"")
};
let utf16_index = self.utf16_interner.intern(&utf16);
// Just to check everything is okay
assert_eq!(index, utf16_index);
index
.checked_add(1 + COMMON_STRINGS_UTF8.len())
.and_then(Sym::new)
.expect("Cannot intern new string: integer overflow")
})
let string = JsString::from(string.into());
if let Some(index) = string.as_static() {
return Sym::new(index + 1).expect("should not be zero");
}
let next_index = self.full.len();
match self.symbol_cache.entry(string.clone()) {
Entry::Occupied(entry) => {
return Sym::new(*entry.get() + 1 + RAW_STATICS.len()).expect("should not be zero");
}
Entry::Vacant(entry) => {
entry.insert(next_index);
}
}
/// Interns the given `'static` string.
///
/// Returns a symbol for resolution into the original string.
///
/// # Note
///
/// This is more efficient than [`Interner::get_or_intern`], since it avoids allocating space
/// for one `string` inside the [`Interner`], with the disadvantage that you need to provide
/// both the `UTF-8` and the `UTF-16` representation of the string.
///
/// # Panics
///
/// If the interner already interns the maximum number of strings possible by the chosen symbol type.
pub fn get_or_intern_static(&mut self, utf8: &'static str, utf16: &'static [u16]) -> Sym {
// Uses the utf8 because it's quicker to check inside `COMMON_STRINGS_UTF8`
// (which is a perfect hash set) than to check inside `COMMON_STRINGS_UTF16`
// (which is a lazy static hash set).
self.get(utf8).unwrap_or_else(|| {
let index = self.utf8_interner.intern(utf8.as_bytes());
let utf16_index = self.utf16_interner.intern(utf16);
// Just to check everything is okay
debug_assert_eq!(index, utf16_index);
index
.checked_add(1 + COMMON_STRINGS_UTF8.len())
.and_then(Sym::new)
.expect("Cannot intern new string: integer overflow")
})
self.full.push(string);
Sym::new(next_index + 1 + RAW_STATICS.len()).expect("should not be zero")
}
/// Returns the string for the given symbol if any.
///
/// # Panics
///
/// Panics if the size of both statics is not equal or the interners do
/// not have the same size
#[must_use]
pub fn resolve(&self, symbol: Sym) -> Option<JSInternedStrRef<'_, '_>> {
let index = symbol.get() - 1;
if let Some(utf8) = COMMON_STRINGS_UTF8.index(index).copied() {
let utf16 = COMMON_STRINGS_UTF16
.get_index(index)
.copied()
.expect("The sizes of both statics must be equal");
return Some(JSInternedStrRef {
utf8: Some(utf8),
utf16,
});
}
let index = index - COMMON_STRINGS_UTF8.len();
if let Some(utf16) = self.utf16_interner.index(index) {
let index = index - (self.utf16_interner.len() - self.utf8_interner.len());
// SAFETY:
// We only manipulate valid UTF-8 `str`s and convert them to `[u8]` for convenience,
// so converting back to a `str` is safe.
let utf8 = unsafe {
core::str::from_utf8_unchecked(
self.utf8_interner
.index(index)
.expect("both interners must have the same size"),
)
};
return Some(JSInternedStrRef {
utf8: if utf8.is_empty() { None } else { Some(utf8) },
utf16,
});
pub fn resolve(&self, sym: Sym) -> Option<JSInternedStrRef> {
let index = sym.get() - 1;
if index < RAW_STATICS.len() {
return StaticJsStrings::get_string(StaticJsStrings::get(index)?).map(Into::into);
}
None
let index = index - RAW_STATICS.len();
self.full.get(index).cloned().map(Into::into)
}
/// Returns the string for the given symbol.
@ -407,27 +255,9 @@ impl Interner {
/// If the interner cannot resolve the given symbol.
#[inline]
#[must_use]
pub fn resolve_expect(&self, symbol: Sym) -> JSInternedStrRef<'_, '_> {
pub fn resolve_expect(&self, symbol: Sym) -> JSInternedStrRef {
self.resolve(symbol).expect("string disappeared")
}
/// Gets the symbol of the common string if one of them
fn get_common(string: JStrRef<'_>) -> Option<Sym> {
match string {
JStrRef::Utf8(s) => COMMON_STRINGS_UTF8.get_index(s).map(|idx| {
// SAFETY: `idx >= 0`, since it's an `usize`, and `idx + 1 > 0`.
// In this case, we don't need to worry about overflows because we have a static
// assertion in place checking that `COMMON_STRINGS.len() < usize::MAX`.
unsafe { Sym::new_unchecked(idx + 1) }
}),
JStrRef::Utf16(s) => COMMON_STRINGS_UTF16.get_index_of(&s).map(|idx| {
// SAFETY: `idx >= 0`, since it's an `usize`, and `idx + 1 > 0`.
// In this case, we don't need to worry about overflows because we have a static
// assertion in place checking that `COMMON_STRINGS.len() < usize::MAX`.
unsafe { Sym::new_unchecked(idx + 1) }
}),
}
}
}
/// Implements the display formatting with indentation.

194
boa_interner/src/raw.rs

@ -1,194 +0,0 @@
use crate::{fixed_string::FixedString, interned_str::InternedStr};
use alloc::vec::Vec;
use core::hash::{BuildHasherDefault, Hash};
use hashbrown::HashMap;
use rustc_hash::FxHasher;
type Map<T, U> = HashMap<T, U, BuildHasherDefault<FxHasher>>;
/// Raw string interner, generic by a char type.
#[derive(Debug)]
pub(super) struct RawInterner<Char> {
// COMMENT FOR DEVS:
// This interner works on the assumption that
// `head` won't ever be reallocated, since this could invalidate
// some of our stored pointers inside `spans`.
// This means that any operation on `head` and `full` should be carefully
// reviewed to not cause Undefined Behaviour.
// `intern` has a more thorough explanation on this.
//
// Also, if you want to implement `shrink_to_fit` (and friends),
// please check out https://github.com/Robbepop/string-interner/pull/47 first.
// This doesn't implement that method, since implementing it increases
// our memory footprint.
symbol_cache: Map<InternedStr<Char>, usize>,
spans: Vec<InternedStr<Char>>,
head: FixedString<Char>,
full: Vec<FixedString<Char>>,
}
impl<Char> Default for RawInterner<Char> {
fn default() -> Self {
Self {
symbol_cache: Map::default(),
spans: Vec::default(),
head: FixedString::default(),
full: Vec::default(),
}
}
}
impl<Char> RawInterner<Char> {
/// Creates a new `RawInterner` with the specified capacity.
pub(super) fn with_capacity(capacity: usize) -> Self {
Self {
symbol_cache: Map::default(),
spans: Vec::with_capacity(capacity),
head: FixedString::new(capacity),
full: Vec::new(),
}
}
/// Returns the number of strings interned by the interner.
pub(super) fn len(&self) -> usize {
self.spans.len()
}
/// Returns `true` if the interner contains no interned strings.
pub(super) fn is_empty(&self) -> bool {
self.spans.is_empty()
}
}
impl<Char> RawInterner<Char>
where
Char: Hash + Eq,
{
/// Returns the index position for the given string if any.
///
/// Can be used to query if a string has already been interned without interning.
pub(super) fn get(&self, string: &[Char]) -> Option<usize> {
// SAFETY:
// `string` is a valid slice that doesn't outlive the
// created `InternedStr`, so this is safe.
unsafe {
self.symbol_cache
.get(&InternedStr::new(string.into()))
.copied()
}
}
/// Interns the given `'static` string.
///
/// Returns the index of `string` within the interner.
///
/// # Note
///
/// This is more efficient than [`RawInterner::intern`], since it
/// avoids storing `string` inside the interner.
///
/// # Panics
///
/// If the interner already interns the maximum number of strings possible
/// by the chosen symbol type.
pub(super) fn intern_static(&mut self, string: &'static [Char]) -> usize {
// SAFETY:
// A static string reference is always valid, meaning it cannot outlive
// the lifetime of the created `InternedStr`. This makes this
// operation safe.
let string = unsafe { InternedStr::new(string.into()) };
// SAFETY:
// A `InternedStr` created from a static reference
// cannot be invalidated by allocations and deallocations,
// so this is safe.
unsafe { self.next_index(string) }
}
/// Returns the string for the given index if any.
pub(super) fn index(&self, index: usize) -> Option<&[Char]> {
self.spans.get(index).map(|ptr|
// SAFETY: We always ensure the stored `InternedStr`s always
// reference memory inside `head` and `full`
unsafe {ptr.as_ref()})
}
/// Inserts a new string pointer into `spans` and returns its index.
///
/// # Safety
///
/// The caller must ensure `string` points to a valid
/// memory inside `head` (or only valid in the case of statics)
/// and that it won't be invalidated by allocations and deallocations.
unsafe fn next_index(&mut self, string: InternedStr<Char>) -> usize {
let next = self.len();
self.spans.push(string);
self.symbol_cache.insert(string, next);
next
}
}
impl<Char> RawInterner<Char>
where
Char: Hash + Eq + Clone,
{
/// Interns the given string.
///
/// Returns the index of `string` within the interner.
///
/// # Panics
///
/// If the interner already interns the maximum number of strings possible by the chosen symbol type.
pub(super) fn intern(&mut self, string: &[Char]) -> usize {
// SAFETY:
//
// Firstly, this interner works on the assumption that the allocated
// memory by `head` won't ever be moved from its position on the heap,
// which is an important point to understand why manipulating it like
// this is safe.
//
// `String` (which is simply a `Vec<u8>` with additional invariants)
// is essentially a pointer to heap memory that can be moved without
// any problems, since copying a pointer cannot invalidate the memory
// that it points to.
//
// However, `String` CAN be invalidated when pushing, extending or
// shrinking it, since all those operations reallocate on the heap.
//
// To prevent that, we HAVE to ensure the capacity will succeed without
// having to reallocate, and the only way to do that without invalidating
// any other alive `InternedStr` is to create a brand new `head` with
// enough capacity and push the old `head` to `full` to keep it alive
// throughout the lifetime of the whole interner.
//
// `FixedString` encapsulates this by only allowing checked `push`es
// to the internal string, but we still have to ensure the memory
// of `head` is not deallocated until the whole interner deallocates,
// which we can do by moving it inside the interner itself, specifically
// on the `full` vector, where every other old `head` also lives.
let interned_str = unsafe {
self.head.push(string).unwrap_or_else(|| {
let new_cap =
(usize::max(self.head.capacity(), string.len()) + 1).next_power_of_two();
let new_head = FixedString::new(new_cap);
let old_head = core::mem::replace(&mut self.head, new_head);
// If the user creates an `Interner`
// with `Interner::with_capacity(BIG_NUMBER)` and
// the first interned string's length is bigger than `BIG_NUMBER`,
// `self.full.push(old_head)` would push a big, empty string of
// allocated size `BIG_NUMBER` into `full`.
// This prevents that case.
if !old_head.is_empty() {
self.full.push(old_head);
}
self.head.push_unchecked(string)
})
};
// SAFETY: We are obtaining a pointer to the internal memory of
// `head`, which is alive through the whole life of the interner, so
// this is safe.
unsafe { self.next_index(interned_str) }
}
}

55
boa_interner/src/tests.rs

@ -1,4 +1,4 @@
use crate::{Interner, Sym, COMMON_STRINGS_UTF16, COMMON_STRINGS_UTF8};
use crate::{Interner, Sym, COMMON_STRINGS_UTF8};
use boa_macros::utf16;
#[track_caller]
@ -34,13 +34,13 @@ fn check_resolve() {
for (s8, s16) in utf_8_strings.zip(utf_16_strings) {
let sym = interner.get_or_intern(s8);
let resolved = interner.resolve(sym).unwrap();
assert_eq!(Some(s8), resolved.utf8());
assert_eq!(s8, &*resolved);
let new_sym = interner.get_or_intern(s8);
assert_eq!(sym, new_sym);
let sym = interner.get_or_intern(s16);
let resolved = interner.resolve(sym).unwrap();
assert_eq!(s16, resolved.utf16());
assert_eq!(s16, &*resolved);
let new_sym = interner.get_or_intern(s16);
assert_eq!(sym, new_sym);
}
@ -50,26 +50,16 @@ fn check_resolve() {
fn check_static_resolve() {
let mut interner = Interner::default();
for (utf8, utf16) in COMMON_STRINGS_UTF8
for string in COMMON_STRINGS_UTF8
.into_iter()
.copied()
.zip(COMMON_STRINGS_UTF16.iter().copied())
.chain(
[
("my test str", utf16!("my test str")),
("hello world", utf16!("hello world")),
(";", utf16!(";")),
]
.into_iter(),
)
.chain(["my test str", "hello world", ";"].into_iter())
{
let sym = interner.get_or_intern_static(utf8, utf16);
let sym = interner.get_or_intern(string);
let resolved = interner.resolve(sym).unwrap();
assert_eq!(Some(utf8), resolved.utf8());
assert_eq!(utf16, resolved.utf16());
let new_sym = interner.get_or_intern(utf8);
assert_eq!(string, &*resolved);
let new_sym = interner.get_or_intern(string);
assert_eq!(sym, new_sym);
}
}
@ -88,29 +78,18 @@ fn check_unpaired_surrogates() {
let sym = interner.get_or_intern("abc");
let sym2 = interner.get_or_intern("def");
let sym3 = interner.get_or_intern(unp);
let sym4 = interner.get_or_intern(utf16!("ghi"));
let sym5 = interner.get_or_intern(unp2);
let sym3 = interner.get_or_intern(&unp[..]);
let sym4 = interner.get_or_intern("ghi");
let sym5 = interner.get_or_intern(&unp2[..]);
let sym6 = interner.get_or_intern("jkl");
assert_eq!(interner.resolve_expect(sym).utf8(), Some("abc"));
assert_eq!(interner.resolve_expect(sym).utf16(), utf16!("abc"));
assert_eq!(interner.resolve_expect(sym2).utf8(), Some("def"));
assert_eq!(interner.resolve_expect(sym2).utf16(), utf16!("def"));
assert!(interner.resolve_expect(sym3).utf8().is_none());
assert_eq!(interner.resolve_expect(sym3).utf16(), unp);
assert_eq!(interner.resolve_expect(sym4).utf8(), Some("ghi"));
assert_eq!(interner.resolve_expect(sym4).utf16(), utf16!("ghi"));
assert!(interner.resolve_expect(sym5).utf8().is_none());
assert_eq!(interner.resolve_expect(sym5).utf16(), unp2);
assert_eq!(interner.resolve_expect(sym6).utf8(), Some("jkl"));
assert_eq!(interner.resolve_expect(sym6).utf16(), utf16!("jkl"));
assert_eq!(&*interner.resolve_expect(sym), "abc");
assert_eq!(&*interner.resolve_expect(sym2), "def");
assert_eq!(&*interner.resolve_expect(sym3), &unp[..]);
assert_eq!(&*interner.resolve_expect(sym4), "ghi");
assert_eq!(&*interner.resolve_expect(sym5), &unp2[..]);
assert_eq!(&*interner.resolve_expect(sym6), "jkl");
}
#[test]

20
boa_macros/src/lib.rs

@ -178,26 +178,6 @@ pub fn static_syms(input: TokenStream) -> TokenStream {
::static_assertions::const_assert!(COMMON_STRINGS.len() < usize::MAX);
COMMON_STRINGS
};
/// Ordered set of commonly used static `UTF-16` strings.
///
/// # Note
///
/// `COMMON_STRINGS_UTF8`, `COMMON_STRINGS_UTF16` and the constants
/// defined in [`Sym`] must always be in sync.
// FIXME: use phf when const expressions are allowed.
// <https://github.com/rust-phf/rust-phf/issues/188>
pub(super) static COMMON_STRINGS_UTF16: ::once_cell::sync::Lazy<Set<&'static [u16]>> =
::once_cell::sync::Lazy::new(|| {
let mut set = Set::with_capacity_and_hasher(
COMMON_STRINGS_UTF8.len(),
::core::hash::BuildHasherDefault::default()
);
#(
set.insert(::boa_macros::utf16!(#literals));
)*
set
});
};
quote! {

1
boa_parser/Cargo.toml

@ -12,7 +12,6 @@ rust-version.workspace = true
[dependencies]
boa_interner.workspace = true
boa_macros.workspace = true
boa_ast.workspace = true
boa_profiler.workspace = true
rustc-hash = { workspace = true, features = ["std"] }

77
boa_parser/src/lexer/tests.rs

@ -7,7 +7,6 @@ use crate::lexer::{
};
use boa_ast::Keyword;
use boa_interner::Sym;
use boa_macros::utf16;
use std::str;
fn span(start: (u32, u32), end: (u32, u32)) -> Span {
@ -66,7 +65,7 @@ fn check_multi_line_comment() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("x", utf16!("x"));
let sym = interner.get_or_intern("x");
let expected = [
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator,
@ -83,29 +82,18 @@ fn check_identifier() {
let interner = &mut Interner::default();
let expected = [
TokenKind::identifier(interner.get_or_intern_static("x", utf16!("x"))),
TokenKind::identifier(interner.get_or_intern_static("x1", utf16!("x1"))),
TokenKind::identifier(interner.get_or_intern_static("_x", utf16!("_x"))),
TokenKind::identifier(interner.get_or_intern_static("$x", utf16!("$x"))),
TokenKind::identifier(interner.get_or_intern_static("__", utf16!("__"))),
TokenKind::identifier(interner.get_or_intern_static("$$", utf16!("$$"))),
TokenKind::identifier(interner.get_or_intern_static("Ѐ", utf16!("Ѐ"))),
TokenKind::identifier(interner.get_or_intern_static("ЀЀ", utf16!("ЀЀ"))),
TokenKind::identifier(
interner.get_or_intern_static("x\u{200C}\u{200D}", utf16!("x\u{200C}\u{200D}")),
),
TokenKind::IdentifierName((
interner.get_or_intern_static("x", utf16!("x")),
ContainsEscapeSequence(true),
)),
TokenKind::IdentifierName((
interner.get_or_intern_static("xx", utf16!("xx")),
ContainsEscapeSequence(true),
)),
TokenKind::IdentifierName((
interner.get_or_intern_static("xxx", utf16!("xxx")),
ContainsEscapeSequence(true),
)),
TokenKind::identifier(interner.get_or_intern("x")),
TokenKind::identifier(interner.get_or_intern("x1")),
TokenKind::identifier(interner.get_or_intern("_x")),
TokenKind::identifier(interner.get_or_intern("$x")),
TokenKind::identifier(interner.get_or_intern("__")),
TokenKind::identifier(interner.get_or_intern("$$")),
TokenKind::identifier(interner.get_or_intern("Ѐ")),
TokenKind::identifier(interner.get_or_intern("ЀЀ")),
TokenKind::identifier(interner.get_or_intern("x\u{200C}\u{200D}")),
TokenKind::IdentifierName((interner.get_or_intern("x"), ContainsEscapeSequence(true))),
TokenKind::IdentifierName((interner.get_or_intern("xx"), ContainsEscapeSequence(true))),
TokenKind::IdentifierName((interner.get_or_intern("xxx"), ContainsEscapeSequence(true))),
];
expect_tokens(&mut lexer, &expected, interner);
@ -129,7 +117,7 @@ fn check_invalid_identifier_part() {
let invalid_identifier_parts = [" ", "\n", ".", "*", "😀", "\u{007F}"];
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("x", utf16!("x"));
let sym = interner.get_or_intern("x");
for part in &invalid_identifier_parts {
let s = String::from("x") + part;
let mut lexer = Lexer::new(s.as_bytes());
@ -147,8 +135,8 @@ fn check_string() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let a_sym = interner.get_or_intern_static("aaa", utf16!("aaa"));
let b_sym = interner.get_or_intern_static("bbb", utf16!("bbb"));
let a_sym = interner.get_or_intern("aaa");
let b_sym = interner.get_or_intern("bbb");
let expected = [
TokenKind::string_literal(a_sym, EscapeSequence::empty()),
TokenKind::string_literal(b_sym, EscapeSequence::empty()),
@ -163,8 +151,7 @@ fn check_template_literal_simple() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let sym =
interner.get_or_intern_static("I'm a template literal", utf16!("I'm a template literal"));
let sym = interner.get_or_intern("I'm a template literal");
assert_eq!(
lexer.next(interner).unwrap().unwrap().kind(),
@ -308,8 +295,8 @@ fn check_variable_definition_tokens() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let a_sym = interner.get_or_intern_static("a", utf16!("a"));
let hello_sym = interner.get_or_intern_static("hello", utf16!("hello"));
let a_sym = interner.get_or_intern("a");
let hello_sym = interner.get_or_intern("hello");
let expected = [
TokenKind::Keyword((Keyword::Let, false)),
TokenKind::identifier(a_sym),
@ -601,7 +588,7 @@ fn hexadecimal_edge_case() {
let mut lexer = Lexer::new(&b"0xffff.ff 0xffffff"[..]);
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("ff", utf16!("ff"));
let sym = interner.get_or_intern("ff");
let expected = [
TokenKind::numeric_literal(0xffff),
TokenKind::Punctuator(Punctuator::Dot),
@ -641,7 +628,7 @@ fn regex_literal() {
let interner = &mut Interner::default();
let expected = [TokenKind::regular_expression_literal(
interner.get_or_intern_static("(?:)", utf16!("(?:)")),
interner.get_or_intern("(?:)"),
Sym::EMPTY_STRING,
)];
@ -655,12 +642,9 @@ fn regex_equals_following_assignment() {
let expected = [
TokenKind::Keyword((Keyword::Const, false)),
TokenKind::identifier(interner.get_or_intern_static("myRegex", utf16!("myRegex"))),
TokenKind::identifier(interner.get_or_intern("myRegex")),
TokenKind::Punctuator(Punctuator::Assign),
TokenKind::regular_expression_literal(
interner.get_or_intern_static("=", utf16!("=")),
Sym::EMPTY_STRING,
),
TokenKind::regular_expression_literal(interner.get_or_intern("="), Sym::EMPTY_STRING),
TokenKind::Punctuator(Punctuator::Semicolon),
];
@ -673,8 +657,8 @@ fn regex_literal_flags() {
let interner = &mut Interner::default();
let expected = [TokenKind::regular_expression_literal(
interner.get_or_intern_static("\\/[^\\/]*\\/*", utf16!("\\/[^\\/]*\\/*")),
interner.get_or_intern_static("gim", utf16!("gim")),
interner.get_or_intern("\\/[^\\/]*\\/*"),
interner.get_or_intern("gim"),
)];
expect_tokens(&mut lexer, &expected, interner);
@ -950,7 +934,7 @@ fn string_unicode() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("中文", utf16!("中文"));
let sym = interner.get_or_intern("中文");
let expected = [
TokenKind::StringLiteral((sym, EscapeSequence::empty())),
TokenKind::Punctuator(Punctuator::Semicolon),
@ -964,8 +948,7 @@ fn string_unicode_escape_with_braces() {
let mut lexer = Lexer::new(&br"'{\u{20ac}\u{a0}\u{a0}}'"[..]);
let interner = &mut Interner::default();
let sym =
interner.get_or_intern_static("{\u{20ac}\u{a0}\u{a0}}", utf16!("{\u{20ac}\u{a0}\u{a0}}"));
let sym = interner.get_or_intern("{\u{20ac}\u{a0}\u{a0}}");
let expected = [TokenKind::StringLiteral((sym, EscapeSequence::OTHER))];
expect_tokens(&mut lexer, &expected, interner);
@ -1000,7 +983,7 @@ fn string_unicode_escape_with_braces_2() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("\u{20ac}\u{a0}\u{a0}", utf16!("\u{20ac}\u{a0}\u{a0}"));
let sym = interner.get_or_intern("\u{20ac}\u{a0}\u{a0}");
let expected = [TokenKind::StringLiteral((sym, EscapeSequence::OTHER))];
expect_tokens(&mut lexer, &expected, interner);
@ -1013,7 +996,7 @@ fn string_with_single_escape() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("Б", utf16!("Б"));
let sym = interner.get_or_intern("Б");
let expected = [TokenKind::StringLiteral((sym, EscapeSequence::OTHER))];
expect_tokens(&mut lexer, &expected, interner);
@ -1115,7 +1098,7 @@ fn string_line_continuation() {
let mut lexer = Lexer::new(s.as_bytes());
let interner = &mut Interner::default();
let sym = interner.get_or_intern_static("hello world", utf16!("hello world"));
let sym = interner.get_or_intern("hello world");
let expected_tokens = [TokenKind::StringLiteral((sym, EscapeSequence::OTHER))];
expect_tokens(&mut lexer, &expected_tokens, interner);

57
boa_parser/src/parser/cursor/buffered_lexer/tests.rs

@ -3,7 +3,6 @@ use crate::{
parser::cursor::BufferedLexer,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn peek_skip_accending() {
@ -15,42 +14,42 @@ fn peek_skip_accending() {
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("a", utf16!("a")))
TokenKind::identifier(interner.get_or_intern("a"))
);
assert_eq!(
*cur.peek(1, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("b", utf16!("b")))
TokenKind::identifier(interner.get_or_intern("b"))
);
assert_eq!(
*cur.peek(2, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("c", utf16!("c")))
TokenKind::identifier(interner.get_or_intern("c"))
);
assert_eq!(
*cur.peek(2, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("c", utf16!("c")))
TokenKind::identifier(interner.get_or_intern("c"))
);
assert_eq!(
*cur.peek(1, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("b", utf16!("b")))
TokenKind::identifier(interner.get_or_intern("b"))
);
assert_eq!(
*cur.peek(0, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("a", utf16!("a")))
TokenKind::identifier(interner.get_or_intern("a"))
);
}
@ -64,77 +63,77 @@ fn peek_skip_next() {
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("a", utf16!("a")))
TokenKind::identifier(interner.get_or_intern("a"))
);
assert_eq!(
*cur.peek(1, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("b", utf16!("b")))
TokenKind::identifier(interner.get_or_intern("b"))
);
assert_eq!(
*cur.peek(2, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("c", utf16!("c")))
TokenKind::identifier(interner.get_or_intern("c"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("a", utf16!("a")))
TokenKind::identifier(interner.get_or_intern("a"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("b", utf16!("b")))
TokenKind::identifier(interner.get_or_intern("b"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("c", utf16!("c")))
TokenKind::identifier(interner.get_or_intern("c"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("d", utf16!("d")))
TokenKind::identifier(interner.get_or_intern("d"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("e", utf16!("e")))
TokenKind::identifier(interner.get_or_intern("e"))
);
assert_eq!(
*cur.peek(0, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("f", utf16!("f")))
TokenKind::identifier(interner.get_or_intern("f"))
);
assert_eq!(
*cur.peek(1, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("g", utf16!("g")))
TokenKind::identifier(interner.get_or_intern("g"))
);
assert_eq!(
*cur.peek(2, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("h", utf16!("h")))
TokenKind::identifier(interner.get_or_intern("h"))
);
}
@ -148,49 +147,49 @@ fn peek_skip_next_alternating() {
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("a", utf16!("a")))
TokenKind::identifier(interner.get_or_intern("a"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("a", utf16!("a")))
TokenKind::identifier(interner.get_or_intern("a"))
);
assert_eq!(
*cur.peek(1, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("c", utf16!("c")))
TokenKind::identifier(interner.get_or_intern("c"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("b", utf16!("b")))
TokenKind::identifier(interner.get_or_intern("b"))
);
assert_eq!(
*cur.peek(1, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("d", utf16!("d")))
TokenKind::identifier(interner.get_or_intern("d"))
);
assert_eq!(
*cur.next(false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("c", utf16!("c")))
TokenKind::identifier(interner.get_or_intern("c"))
);
assert_eq!(
*cur.peek(2, false, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("f", utf16!("f")))
TokenKind::identifier(interner.get_or_intern("f"))
);
}
@ -244,14 +243,14 @@ fn skip_peeked_terminators() {
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("A", utf16!("A")))
TokenKind::identifier(interner.get_or_intern("A"))
);
assert_eq!(
*cur.peek(0, true, interner)
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("A", utf16!("A")))
TokenKind::identifier(interner.get_or_intern("A"))
);
assert_eq!(
@ -266,7 +265,7 @@ fn skip_peeked_terminators() {
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("B", utf16!("B"))) /* This value is after the line terminator */
TokenKind::identifier(interner.get_or_intern("B")) /* This value is after the line terminator */
);
assert_eq!(
@ -274,7 +273,7 @@ fn skip_peeked_terminators() {
.unwrap()
.expect("Some value expected")
.kind(),
TokenKind::identifier(interner.get_or_intern_static("B", utf16!("B")))
TokenKind::identifier(interner.get_or_intern("B"))
);
// End of stream
assert!(cur.peek(2, true, interner).unwrap().is_none());

12
boa_parser/src/parser/expression/identifiers.rs

@ -110,10 +110,8 @@ where
let ident = Identifier.parse(cursor, interner)?;
match ident.sym() {
Sym::ARGUMENTS | Sym::EVAL if cursor.strict() => {
let name = interner
.resolve_expect(ident.sym())
.utf8()
.expect("keyword must be utf-8");
let name = interner.resolve_expect(ident.sym());
name.as_str().as_ascii().expect("keyword must be utf-8");
Err(Error::general(
format!("binding identifier `{name}` not allowed in strict mode"),
span.start(),
@ -179,7 +177,8 @@ where
return Err(Error::unexpected(
interner
.resolve_expect(ident)
.utf8()
.as_str()
.as_ascii()
.expect("keyword must always be utf-8"),
tok.span(),
"strict reserved word cannot be an identifier",
@ -198,7 +197,8 @@ where
return Err(Error::unexpected(
interner
.resolve_expect(ident)
.utf8()
.as_str()
.as_ascii()
.expect("keyword must always be utf-8"),
tok.span(),
"reserved word cannot be an identifier",

2
boa_parser/src/parser/expression/left_hand_side/mod.rs

@ -99,7 +99,7 @@ where
return Err(Error::general(
format!(
"keyword `{}` cannot contain escaped characters",
kw.as_str().0
kw.as_str()
),
next.span().start(),
));

14
boa_parser/src/parser/expression/left_hand_side/optional/tests.rs

@ -8,7 +8,6 @@ use boa_ast::{
Expression, Statement,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn simple() {
@ -21,9 +20,7 @@ fn simple() {
Literal::Int(5).into(),
vec![OptionalOperation::new(
OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(
interner.get_or_intern_static("name", utf16!("name")),
),
field: PropertyAccessField::Const(interner.get_or_intern("name")),
},
true,
)]
@ -44,13 +41,11 @@ fn complex_chain() {
r#"a?.b(true)?.["c"]"#,
vec![Statement::Expression(
Optional::new(
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
vec![
OptionalOperation::new(
OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(
interner.get_or_intern_static("b", utf16!("b")),
),
field: PropertyAccessField::Const(interner.get_or_intern("b")),
},
true,
),
@ -63,8 +58,7 @@ fn complex_chain() {
OptionalOperation::new(
OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Expr(Box::new(
Literal::String(interner.get_or_intern_static("c", utf16!("c")))
.into(),
Literal::String(interner.get_or_intern("c")).into(),
)),
},
true,

9
boa_parser/src/parser/expression/left_hand_side/tests.rs

@ -4,7 +4,6 @@ use boa_ast::{
Expression, Statement,
};
use boa_interner::Interner;
use boa_macros::utf16;
macro_rules! check_call_property_identifier {
($property:literal) => {{
@ -14,11 +13,11 @@ macro_rules! check_call_property_identifier {
vec![Statement::Expression(Expression::PropertyAccess(
SimplePropertyAccess::new(
Call::new(
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Box::default(),
)
.into(),
interner.get_or_intern_static($property, utf16!($property)),
interner.get_or_intern($property),
)
.into(),
))
@ -44,8 +43,8 @@ macro_rules! check_member_property_identifier {
format!("a.{}", $property).as_str(),
vec![Statement::Expression(Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
interner.get_or_intern_static($property, utf16!($property)),
Identifier::new(interner.get_or_intern("a")).into(),
interner.get_or_intern($property),
)
.into(),
))

3
boa_parser/src/parser/expression/primary/array_initializer/tests.rs

@ -6,7 +6,6 @@ use boa_ast::{
Expression, Statement,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
/// Checks an empty array.
#[test]
@ -108,7 +107,7 @@ fn check_combined() {
vec![
Statement::Expression(Expression::from(ArrayLiteral::from(vec![
Some(Literal::from(1).into()),
Some(Literal::from(interner.get_or_intern_static("a", utf16!("a"))).into()),
Some(Literal::from(interner.get_or_intern("a")).into()),
Some(Literal::from(2).into()),
])))
.into(),

7
boa_parser/src/parser/expression/primary/async_function_expression/tests.rs

@ -7,13 +7,12 @@ use boa_ast::{
Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Checks async expression parsing.
#[test]
fn check_async_expression() {
let interner = &mut Interner::default();
let add = interner.get_or_intern_static("add", utf16!("add"));
let add = interner.get_or_intern("add");
check_script_parser(
"const add = async function() {
return 1;
@ -48,8 +47,8 @@ fn check_async_expression() {
#[test]
fn check_nested_async_expression() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let b = interner.get_or_intern_static("b", utf16!("b"));
let a = interner.get_or_intern("a");
let b = interner.get_or_intern("b");
check_script_parser(
"const a = async function() {
const b = async function() {

8
boa_parser/src/parser/expression/primary/async_generator_expression/tests.rs

@ -7,14 +7,12 @@ use boa_ast::{
Declaration, Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
///checks async generator expression parsing
#[test]
fn check_async_generator_expr() {
let interner = &mut Interner::default();
let add = interner.get_or_intern_static("add", utf16!("add"));
let add = interner.get_or_intern("add");
check_script_parser(
"const add = async function*(){
return 1;
@ -49,8 +47,8 @@ fn check_async_generator_expr() {
#[test]
fn check_nested_async_generator_expr() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let b = interner.get_or_intern_static("b", utf16!("b"));
let a = interner.get_or_intern("a");
let b = interner.get_or_intern("b");
check_script_parser(
"const a = async function*() {
const b = async function*() {

11
boa_parser/src/parser/expression/primary/function_expression/tests.rs

@ -7,13 +7,12 @@ use boa_ast::{
Declaration, Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Checks async expression parsing.
#[test]
fn check_function_expression() {
let interner = &mut Interner::default();
let add = interner.get_or_intern_static("add", utf16!("add"));
let add = interner.get_or_intern("add");
check_script_parser(
"const add = function() {
return 1;
@ -47,8 +46,8 @@ fn check_function_expression() {
#[test]
fn check_nested_function_expression() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let b = interner.get_or_intern_static("b", utf16!("b"));
let a = interner.get_or_intern("a");
let b = interner.get_or_intern("b");
check_script_parser(
"const a = function() {
const b = function() {
@ -107,10 +106,10 @@ fn check_function_non_reserved_keyword() {
($keyword:literal, $interner:expr) => {
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
$interner.get_or_intern_static("add", utf16!("add")).into(),
$interner.get_or_intern("add").into(),
Some(
Function::new_with_binding_identifier(
Some($interner.get_or_intern_static($keyword, utf16!($keyword)).into()),
Some($interner.get_or_intern($keyword).into()),
FormalParameterList::default(),
FunctionBody::new(
vec![StatementListItem::Statement(

5
boa_parser/src/parser/expression/primary/generator_expression/tests.rs

@ -6,12 +6,11 @@ use boa_ast::{
Declaration, Expression, Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn check_generator_function_expression() {
let interner = &mut Interner::default();
let gen = interner.get_or_intern_static("gen", utf16!("gen"));
let gen = interner.get_or_intern("gen");
check_script_parser(
"const gen = function*() {
yield 1;
@ -46,7 +45,7 @@ fn check_generator_function_expression() {
#[test]
fn check_generator_function_delegate_yield_expression() {
let interner = &mut Interner::default();
let gen = interner.get_or_intern_static("gen", utf16!("gen"));
let gen = interner.get_or_intern("gen");
check_script_parser(
"const gen = function*() {
yield* 1;

16
boa_parser/src/parser/expression/primary/object_initializer/mod.rs

@ -37,8 +37,7 @@ use boa_ast::{
property::{self, MethodDefinition},
Expression, Keyword, Punctuator,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
use boa_interner::{js_string, Interner, Sym};
use boa_profiler::Profiler;
use std::io::Read;
@ -358,9 +357,9 @@ where
)?;
let name = property_name.literal().map(|name| {
let s = interner.resolve_expect(name).utf16();
let s = interner.resolve_expect(name);
interner
.get_or_intern([utf16!("get "), s].concat().as_slice())
.get_or_intern(js_string!("get ", &*s).as_str())
.into()
});
@ -451,9 +450,9 @@ where
)?;
let name = property_name.literal().map(|name| {
let s = interner.resolve_expect(name).utf16();
let s = interner.resolve_expect(name);
interner
.get_or_intern([utf16!("set "), s].concat().as_slice())
.get_or_intern(js_string!("set ", &*s).as_str())
.into()
});
@ -599,10 +598,7 @@ where
Numeric::Integer(num) => Expression::Literal(Literal::from(*num)).into(),
Numeric::BigInt(num) => Expression::Literal(Literal::from(num.clone())).into(),
},
TokenKind::Keyword((word, _)) => {
let (utf8, utf16) = word.as_str();
interner.get_or_intern_static(utf8, utf16).into()
}
TokenKind::Keyword((word, _)) => interner.get_or_intern(word.as_str()).into(),
TokenKind::NullLiteral(_) => (Sym::NULL).into(),
TokenKind::BooleanLiteral((bool, _)) => match bool {
true => Sym::TRUE.into(),

128
boa_parser/src/parser/expression/primary/object_initializer/tests.rs

@ -13,7 +13,6 @@ use boa_ast::{
Declaration,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
/// Checks object literal parsing.
#[test]
@ -22,11 +21,11 @@ fn check_object_literal() {
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Literal::from(true).into(),
),
PropertyDefinition::Property(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
Literal::from(false).into(),
),
];
@ -39,7 +38,7 @@ fn check_object_literal() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -57,13 +56,13 @@ fn check_object_short_function() {
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Literal::from(true).into(),
),
PropertyDefinition::MethodDefinition(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
MethodDefinition::Ordinary(Function::new(
Some(interner.get_or_intern_static("b", utf16!("b")).into()),
Some(interner.get_or_intern("b").into()),
FormalParameterList::default(),
FunctionBody::default(),
)),
@ -78,7 +77,7 @@ fn check_object_short_function() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -95,10 +94,7 @@ fn check_object_short_function_arguments() {
let interner = &mut Interner::default();
let parameters = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(
interner.get_or_intern_static("test", utf16!("test")).into(),
None,
),
Variable::from_identifier(interner.get_or_intern("test").into(), None),
false,
));
@ -107,13 +103,13 @@ fn check_object_short_function_arguments() {
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Literal::from(true).into(),
),
PropertyDefinition::MethodDefinition(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
MethodDefinition::Ordinary(Function::new(
Some(interner.get_or_intern_static("b", utf16!("b")).into()),
Some(interner.get_or_intern("b").into()),
parameters,
FunctionBody::default(),
)),
@ -128,7 +124,7 @@ fn check_object_short_function_arguments() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -145,17 +141,13 @@ fn check_object_getter() {
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Literal::from(true).into(),
),
PropertyDefinition::MethodDefinition(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
MethodDefinition::Get(Function::new(
Some(
interner
.get_or_intern_static("get b", utf16!("get b"))
.into(),
),
Some(interner.get_or_intern("get b").into()),
FormalParameterList::default(),
FunctionBody::default(),
)),
@ -170,7 +162,7 @@ fn check_object_getter() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -186,10 +178,7 @@ fn check_object_setter() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(
interner.get_or_intern_static("test", utf16!("test")).into(),
None,
),
Variable::from_identifier(interner.get_or_intern("test").into(), None),
false,
));
@ -198,17 +187,13 @@ fn check_object_setter() {
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Literal::from(true).into(),
),
PropertyDefinition::MethodDefinition(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
MethodDefinition::Set(Function::new(
Some(
interner
.get_or_intern_static("set b", utf16!("set b"))
.into(),
),
Some(interner.get_or_intern("set b").into()),
params,
FunctionBody::default(),
)),
@ -223,7 +208,7 @@ fn check_object_setter() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -241,7 +226,7 @@ fn check_object_short_function_get() {
let object_properties = vec![PropertyDefinition::MethodDefinition(
Sym::GET.into(),
MethodDefinition::Ordinary(Function::new(
Some(interner.get_or_intern_static("get", utf16!("get")).into()),
Some(interner.get_or_intern("get").into()),
FormalParameterList::default(),
FunctionBody::default(),
)),
@ -254,7 +239,7 @@ fn check_object_short_function_get() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -272,7 +257,7 @@ fn check_object_short_function_set() {
let object_properties = vec![PropertyDefinition::MethodDefinition(
Sym::SET.into(),
MethodDefinition::Ordinary(Function::new(
Some(interner.get_or_intern_static("set", utf16!("set")).into()),
Some(interner.get_or_intern("set").into()),
FormalParameterList::default(),
FunctionBody::default(),
)),
@ -285,7 +270,7 @@ fn check_object_short_function_set() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -301,7 +286,7 @@ fn check_object_shorthand_property_names() {
let interner = &mut Interner::default();
let object_properties = vec![PropertyDefinition::IdentifierReference(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
)];
check_script_parser(
@ -311,7 +296,7 @@ fn check_object_shorthand_property_names() {
vec![
Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(true).into()),
)]
.try_into()
@ -320,7 +305,7 @@ fn check_object_shorthand_property_names() {
.into(),
Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -337,12 +322,8 @@ fn check_object_shorthand_multiple_properties() {
let interner = &mut Interner::default();
let object_properties = vec![
PropertyDefinition::IdentifierReference(
interner.get_or_intern_static("a", utf16!("a")).into(),
),
PropertyDefinition::IdentifierReference(
interner.get_or_intern_static("b", utf16!("b")).into(),
),
PropertyDefinition::IdentifierReference(interner.get_or_intern("a").into()),
PropertyDefinition::IdentifierReference(interner.get_or_intern("b").into()),
];
check_script_parser(
@ -353,7 +334,7 @@ fn check_object_shorthand_multiple_properties() {
vec![
Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(true).into()),
)]
.try_into()
@ -362,7 +343,7 @@ fn check_object_shorthand_multiple_properties() {
.into(),
Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
Some(Literal::from(false).into()),
)]
.try_into()
@ -371,7 +352,7 @@ fn check_object_shorthand_multiple_properties() {
.into(),
Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -388,13 +369,8 @@ fn check_object_spread() {
let interner = &mut Interner::default();
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
Literal::from(1).into(),
),
PropertyDefinition::SpreadObject(
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
),
PropertyDefinition::Property(interner.get_or_intern("a").into(), Literal::from(1).into()),
PropertyDefinition::SpreadObject(Identifier::new(interner.get_or_intern("b")).into()),
];
check_script_parser(
@ -402,7 +378,7 @@ fn check_object_spread() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -418,9 +394,9 @@ fn check_async_method() {
let interner = &mut Interner::default();
let object_properties = vec![PropertyDefinition::MethodDefinition(
interner.get_or_intern_static("dive", utf16!("dive")).into(),
interner.get_or_intern("dive").into(),
MethodDefinition::Async(AsyncFunction::new(
Some(interner.get_or_intern_static("dive", utf16!("dive")).into()),
Some(interner.get_or_intern("dive").into()),
FormalParameterList::default(),
FunctionBody::default(),
false,
@ -434,7 +410,7 @@ fn check_async_method() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -450,15 +426,9 @@ fn check_async_generator_method() {
let interner = &mut Interner::default();
let object_properties = vec![PropertyDefinition::MethodDefinition(
interner
.get_or_intern_static("vroom", utf16!("vroom"))
.into(),
interner.get_or_intern("vroom").into(),
MethodDefinition::AsyncGenerator(AsyncGenerator::new(
Some(
interner
.get_or_intern_static("vroom", utf16!("vroom"))
.into(),
),
Some(interner.get_or_intern("vroom").into()),
FormalParameterList::default(),
FunctionBody::default(),
false,
@ -472,7 +442,7 @@ fn check_async_generator_method() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -510,13 +480,9 @@ fn check_async_ordinary_method() {
let interner = &mut Interner::default();
let object_properties = vec![PropertyDefinition::MethodDefinition(
PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))),
PropertyName::Literal(interner.get_or_intern("async")),
MethodDefinition::Ordinary(Function::new(
Some(
interner
.get_or_intern_static("async", utf16!("async"))
.into(),
),
Some(interner.get_or_intern("async").into()),
FormalParameterList::default(),
FunctionBody::default(),
)),
@ -529,7 +495,7 @@ fn check_async_ordinary_method() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -545,7 +511,7 @@ fn check_async_property() {
let interner = &mut Interner::default();
let object_properties = vec![PropertyDefinition::Property(
PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))),
PropertyName::Literal(interner.get_or_intern("async")),
Literal::from(true).into(),
)];
@ -556,7 +522,7 @@ fn check_async_property() {
",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()

3
boa_parser/src/parser/expression/primary/tests.rs

@ -1,7 +1,6 @@
use crate::parser::tests::check_script_parser;
use boa_ast::{expression::literal::Literal, Expression, Statement};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
#[test]
fn check_string() {
@ -17,7 +16,7 @@ fn check_string() {
check_script_parser(
"\"hello\"",
vec![Statement::Expression(Expression::from(Literal::from(
interner.get_or_intern_static("hello", utf16!("hello")),
interner.get_or_intern("hello"),
)))
.into()],
interner,

213
boa_parser/src/parser/expression/tests.rs

@ -13,7 +13,6 @@ use boa_ast::{
Declaration, Expression, Statement,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
/// Checks numeric operations
#[test]
@ -23,8 +22,8 @@ fn check_numeric_operations() {
"a + b",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Add.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -35,7 +34,7 @@ fn check_numeric_operations() {
"a+1",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Add.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(1).into(),
)))
.into()],
@ -47,8 +46,8 @@ fn check_numeric_operations() {
"a - b",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Sub.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -59,7 +58,7 @@ fn check_numeric_operations() {
"a-1",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Sub.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(1).into(),
)))
.into()],
@ -71,8 +70,8 @@ fn check_numeric_operations() {
"a / b",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Div.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -83,7 +82,7 @@ fn check_numeric_operations() {
"a/2",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Div.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(2).into(),
)))
.into()],
@ -95,16 +94,8 @@ fn check_numeric_operations() {
"let myRegex = /=/;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner
.get_or_intern_static("myRegex", utf16!("myRegex"))
.into(),
Some(
RegExpLiteral::new(
interner.get_or_intern_static("=", utf16!("=")),
Sym::EMPTY_STRING,
)
.into(),
),
interner.get_or_intern("myRegex").into(),
Some(RegExpLiteral::new(interner.get_or_intern("="), Sym::EMPTY_STRING).into()),
)]
.try_into()
.unwrap(),
@ -117,13 +108,8 @@ fn check_numeric_operations() {
check_script_parser(
"fn(/=/);",
vec![Statement::Expression(Expression::from(Call::new(
Identifier::new(interner.get_or_intern_static("fn", utf16!("fn"))).into(),
vec![RegExpLiteral::new(
interner.get_or_intern_static("=", utf16!("=")),
Sym::EMPTY_STRING,
)
.into()]
.into(),
Identifier::new(interner.get_or_intern("fn")).into(),
vec![RegExpLiteral::new(interner.get_or_intern("="), Sym::EMPTY_STRING).into()].into(),
)))
.into()],
interner,
@ -133,11 +119,11 @@ fn check_numeric_operations() {
check_script_parser(
"fn(a / b);",
vec![Statement::Expression(Expression::from(Call::new(
Identifier::new(interner.get_or_intern_static("fn", utf16!("fn"))).into(),
Identifier::new(interner.get_or_intern("fn")).into(),
vec![Expression::from(Binary::new(
ArithmeticOp::Div.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
))]
.into(),
)))
@ -151,12 +137,11 @@ fn check_numeric_operations() {
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Div.into(),
Call::new(
Identifier::new(interner.get_or_intern_static("fn", utf16!("fn"))).into(),
vec![Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into()]
.into(),
Identifier::new(interner.get_or_intern("fn")).into(),
vec![Identifier::new(interner.get_or_intern("a")).into()].into(),
)
.into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -167,8 +152,8 @@ fn check_numeric_operations() {
"a * b",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Mul.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -179,7 +164,7 @@ fn check_numeric_operations() {
"a*2",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Mul.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(2).into(),
)))
.into()],
@ -191,8 +176,8 @@ fn check_numeric_operations() {
"a ** b",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Exp.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -203,7 +188,7 @@ fn check_numeric_operations() {
"a**2",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Exp.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(2).into(),
)))
.into()],
@ -215,8 +200,8 @@ fn check_numeric_operations() {
"a % b",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Mod.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -227,7 +212,7 @@ fn check_numeric_operations() {
"a%2",
vec![Statement::Expression(Expression::from(Binary::new(
ArithmeticOp::Mod.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(2).into(),
)))
.into()],
@ -245,14 +230,14 @@ fn check_complex_numeric_operations() {
ArithmeticOp::Add.into(),
Binary::new(
ArithmeticOp::Add.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Binary::new(
ArithmeticOp::Mul.into(),
Identifier::new(interner.get_or_intern_static("d", utf16!("d"))).into(),
Identifier::new(interner.get_or_intern("d")).into(),
Parenthesized::new(
Binary::new(
ArithmeticOp::Sub.into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("b")).into(),
Literal::from(3).into(),
)
.into(),
@ -277,8 +262,8 @@ fn check_bitwise_operations() {
"a & b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::And.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -289,8 +274,8 @@ fn check_bitwise_operations() {
"a&b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::And.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -301,8 +286,8 @@ fn check_bitwise_operations() {
"a | b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Or.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -313,8 +298,8 @@ fn check_bitwise_operations() {
"a|b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Or.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -325,8 +310,8 @@ fn check_bitwise_operations() {
"a ^ b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Xor.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -337,8 +322,8 @@ fn check_bitwise_operations() {
"a^b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Xor.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -349,8 +334,8 @@ fn check_bitwise_operations() {
"a << b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Shl.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -361,8 +346,8 @@ fn check_bitwise_operations() {
"a<<b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Shl.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -373,8 +358,8 @@ fn check_bitwise_operations() {
"a >> b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Shr.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -385,8 +370,8 @@ fn check_bitwise_operations() {
"a>>b",
vec![Statement::Expression(Expression::from(Binary::new(
BitwiseOp::Shr.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -401,8 +386,8 @@ fn check_assign_operations() {
"a += b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Add,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -413,8 +398,8 @@ fn check_assign_operations() {
"a -= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Sub,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -425,8 +410,8 @@ fn check_assign_operations() {
"a *= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Mul,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -437,8 +422,8 @@ fn check_assign_operations() {
"a **= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Exp,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -449,8 +434,8 @@ fn check_assign_operations() {
"a /= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Div,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -461,8 +446,8 @@ fn check_assign_operations() {
"a %= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Mod,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -473,8 +458,8 @@ fn check_assign_operations() {
"a &= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::And,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -485,8 +470,8 @@ fn check_assign_operations() {
"a |= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Or,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -497,8 +482,8 @@ fn check_assign_operations() {
"a ^= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Xor,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -509,8 +494,8 @@ fn check_assign_operations() {
"a <<= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Shl,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -521,8 +506,8 @@ fn check_assign_operations() {
"a >>= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Shr,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -533,8 +518,8 @@ fn check_assign_operations() {
"a >>>= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Ushr,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -545,7 +530,7 @@ fn check_assign_operations() {
"a %= 10 / 2",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Mod,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Binary::new(
ArithmeticOp::Div.into(),
Literal::from(10).into(),
@ -562,8 +547,8 @@ fn check_assign_operations() {
"a ??= b",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Coalesce,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -577,8 +562,8 @@ fn check_relational_operations() {
"a < b",
vec![Statement::Expression(Expression::from(Binary::new(
RelationalOp::LessThan.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -589,8 +574,8 @@ fn check_relational_operations() {
"a > b",
vec![Statement::Expression(Expression::from(Binary::new(
RelationalOp::GreaterThan.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -601,8 +586,8 @@ fn check_relational_operations() {
"a <= b",
vec![Statement::Expression(Expression::from(Binary::new(
RelationalOp::LessThanOrEqual.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -613,8 +598,8 @@ fn check_relational_operations() {
"a >= b",
vec![Statement::Expression(Expression::from(Binary::new(
RelationalOp::GreaterThanOrEqual.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)))
.into()],
interner,
@ -625,8 +610,8 @@ fn check_relational_operations() {
"p in o",
vec![Statement::Expression(Expression::from(Binary::new(
RelationalOp::In.into(),
Identifier::new(interner.get_or_intern_static("p", utf16!("p"))).into(),
Identifier::new(interner.get_or_intern_static("o", utf16!("o"))).into(),
Identifier::new(interner.get_or_intern("p")).into(),
Identifier::new(interner.get_or_intern("o")).into(),
)))
.into()],
interner,
@ -642,19 +627,19 @@ fn check_logical_expressions() {
LogicalOp::Or.into(),
Binary::new(
LogicalOp::And.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)
.into(),
Binary::new(
LogicalOp::Or.into(),
Binary::new(
LogicalOp::And.into(),
Identifier::new(interner.get_or_intern_static("c", utf16!("c"))).into(),
Identifier::new(interner.get_or_intern_static("d", utf16!("d"))).into(),
Identifier::new(interner.get_or_intern("c")).into(),
Identifier::new(interner.get_or_intern("d")).into(),
)
.into(),
Identifier::new(interner.get_or_intern_static("e", utf16!("e"))).into(),
Identifier::new(interner.get_or_intern("e")).into(),
)
.into(),
)))
@ -669,11 +654,11 @@ fn check_logical_expressions() {
LogicalOp::Coalesce.into(),
Binary::new(
LogicalOp::Coalesce.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)
.into(),
Identifier::new(interner.get_or_intern_static("c", utf16!("c"))).into(),
Identifier::new(interner.get_or_intern("c")).into(),
)))
.into()],
interner,
@ -691,11 +676,7 @@ macro_rules! check_non_reserved_identifier {
check_script_parser(
format!("({})", $keyword).as_str(),
vec![Statement::Expression(
Parenthesized::new(
Identifier::new(interner.get_or_intern_static($keyword, utf16!($keyword)))
.into(),
)
.into(),
Parenthesized::new(Identifier::new(interner.get_or_intern($keyword)).into()).into(),
)
.into()],
interner,

173
boa_parser/src/parser/function/tests.rs

@ -13,14 +13,13 @@ use boa_ast::{
Declaration, Expression, Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Checks basic function declaration parsing.
#[test]
fn check_basic() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -29,13 +28,11 @@ fn check_basic() {
check_script_parser(
"function foo(a) { return a; }",
vec![Declaration::Function(Function::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::from(interner.get_or_intern_static("a", utf16!("a"))).into(),
)),
Return::new(Some(Identifier::from(interner.get_or_intern("a")).into())),
))]
.into(),
),
@ -51,11 +48,11 @@ fn check_duplicates_strict_off() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
]);
@ -67,13 +64,11 @@ fn check_duplicates_strict_off() {
check_script_parser(
"function foo(a, a) { return a; }",
vec![Declaration::Function(Function::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::from(interner.get_or_intern_static("a", utf16!("a"))).into(),
)),
Return::new(Some(Identifier::from(interner.get_or_intern("a")).into())),
))]
.into(),
),
@ -94,7 +89,7 @@ fn check_duplicates_strict_on() {
fn check_basic_semicolon_insertion() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -103,13 +98,11 @@ fn check_basic_semicolon_insertion() {
check_script_parser(
"function foo(a) { return a }",
vec![Declaration::Function(Function::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::from(interner.get_or_intern_static("a", utf16!("a"))).into(),
)),
Return::new(Some(Identifier::from(interner.get_or_intern("a")).into())),
))]
.into(),
),
@ -124,7 +117,7 @@ fn check_basic_semicolon_insertion() {
fn check_empty_return() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -132,7 +125,7 @@ fn check_empty_return() {
check_script_parser(
"function foo(a) { return; }",
vec![Declaration::Function(Function::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
@ -151,7 +144,7 @@ fn check_empty_return() {
fn check_empty_return_semicolon_insertion() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -159,7 +152,7 @@ fn check_empty_return_semicolon_insertion() {
check_script_parser(
"function foo(a) { return }",
vec![Declaration::Function(Function::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
@ -179,11 +172,11 @@ fn check_rest_operator() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
true,
),
]);
@ -195,7 +188,7 @@ fn check_rest_operator() {
check_script_parser(
"function foo(a, ...b) {}",
vec![Declaration::Function(Function::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::default(),
))
@ -209,7 +202,7 @@ fn check_rest_operator() {
fn check_arrow_only_rest() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
true,
));
assert_eq!(
@ -235,15 +228,15 @@ fn check_arrow_rest() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("c", utf16!("c")).into(), None),
Variable::from_identifier(interner.get_or_intern("c").into(), None),
true,
),
]);
@ -270,11 +263,11 @@ fn check_arrow() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
]);
@ -290,8 +283,8 @@ fn check_arrow() {
Return::new(Some(
Binary::new(
ArithmeticOp::Add.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)
.into(),
)),
@ -310,11 +303,11 @@ fn check_arrow_semicolon_insertion() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
]);
@ -328,8 +321,8 @@ fn check_arrow_semicolon_insertion() {
Return::new(Some(
Binary::new(
ArithmeticOp::Add.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)
.into(),
)),
@ -348,11 +341,11 @@ fn check_arrow_epty_return() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
]);
@ -379,11 +372,11 @@ fn check_arrow_empty_return_semicolon_insertion() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
]);
@ -408,7 +401,7 @@ fn check_arrow_empty_return_semicolon_insertion() {
fn check_arrow_assignment() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -417,18 +410,15 @@ fn check_arrow_assignment() {
"let foo = (a) => { return a };",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("foo", utf16!("foo"))),
Identifier::new(interner.get_or_intern("foo")),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -449,7 +439,7 @@ fn check_arrow_assignment() {
fn check_arrow_assignment_nobrackets() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -458,18 +448,15 @@ fn check_arrow_assignment_nobrackets() {
"let foo = (a) => a;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("foo", utf16!("foo")).into(),
interner.get_or_intern("foo").into(),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -490,7 +477,7 @@ fn check_arrow_assignment_nobrackets() {
fn check_arrow_assignment_noparenthesis() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -499,18 +486,15 @@ fn check_arrow_assignment_noparenthesis() {
"let foo = a => { return a };",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("foo", utf16!("foo")).into(),
interner.get_or_intern("foo").into(),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -531,7 +515,7 @@ fn check_arrow_assignment_noparenthesis() {
fn check_arrow_assignment_noparenthesis_nobrackets() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
));
assert_eq!(params.flags(), FormalParameterListFlags::default());
@ -540,18 +524,15 @@ fn check_arrow_assignment_noparenthesis_nobrackets() {
"let foo = a => a;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("foo", utf16!("foo"))),
Identifier::new(interner.get_or_intern("foo")),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -573,11 +554,11 @@ fn check_arrow_assignment_2arg() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
]);
@ -587,18 +568,15 @@ fn check_arrow_assignment_2arg() {
"let foo = (a, b) => { return a };",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("foo", utf16!("foo"))),
Identifier::new(interner.get_or_intern("foo")),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -620,11 +598,11 @@ fn check_arrow_assignment_2arg_nobrackets() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
]);
@ -634,18 +612,15 @@ fn check_arrow_assignment_2arg_nobrackets() {
"let foo = (a, b) => a;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("foo", utf16!("foo"))),
Identifier::new(interner.get_or_intern("foo")),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -667,15 +642,15 @@ fn check_arrow_assignment_3arg() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("c", utf16!("c")).into(), None),
Variable::from_identifier(interner.get_or_intern("c").into(), None),
false,
),
]);
@ -685,18 +660,15 @@ fn check_arrow_assignment_3arg() {
"let foo = (a, b, c) => { return a };",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("foo", utf16!("foo"))),
Identifier::new(interner.get_or_intern("foo")),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),
@ -718,15 +690,15 @@ fn check_arrow_assignment_3arg_nobrackets() {
let interner = &mut Interner::default();
let params = FormalParameterList::from(vec![
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("a", utf16!("a")).into(), None),
Variable::from_identifier(interner.get_or_intern("a").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("b", utf16!("b")).into(), None),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
false,
),
FormalParameter::new(
Variable::from_identifier(interner.get_or_intern_static("c", utf16!("c")).into(), None),
Variable::from_identifier(interner.get_or_intern("c").into(), None),
false,
),
]);
@ -736,18 +708,15 @@ fn check_arrow_assignment_3arg_nobrackets() {
"let foo = (a, b, c) => a;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("foo", utf16!("foo"))),
Identifier::new(interner.get_or_intern("foo")),
Some(
ArrowFunction::new(
Some(interner.get_or_intern_static("foo", utf16!("foo")).into()),
Some(interner.get_or_intern("foo").into()),
params,
FunctionBody::new(
vec![StatementListItem::Statement(Statement::Return(
Return::new(Some(
Identifier::new(
interner.get_or_intern_static("a", utf16!("a")),
)
.into(),
Identifier::new(interner.get_or_intern("a")).into(),
)),
))]
.into(),

13
boa_parser/src/parser/statement/block/tests.rs

@ -17,7 +17,6 @@ use boa_ast::{
Declaration, Expression, Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Helper function to check a block.
#[track_caller]
@ -40,7 +39,7 @@ fn empty() {
#[test]
fn non_empty() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_block(
r"{
var a = 10;
@ -66,8 +65,8 @@ fn non_empty() {
);
let interner = &mut Interner::default();
let hello = interner.get_or_intern_static("hello", utf16!("hello"));
let a = interner.get_or_intern_static("a", utf16!("a"));
let hello = interner.get_or_intern("hello");
let a = interner.get_or_intern("a");
check_block(
r"{
function hello() {
@ -111,8 +110,8 @@ fn non_empty() {
#[test]
fn hoisting() {
let interner = &mut Interner::default();
let hello = interner.get_or_intern_static("hello", utf16!("hello"));
let a = interner.get_or_intern_static("a", utf16!("a"));
let hello = interner.get_or_intern("hello");
let a = interner.get_or_intern("a");
check_block(
r"{
var a = hello();
@ -151,7 +150,7 @@ fn hoisting() {
);
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_block(
r"{
a = 10;

9
boa_parser/src/parser/statement/break_stm/tests.rs

@ -5,7 +5,6 @@ use boa_ast::{
Statement, StatementListItem,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
#[test]
fn inline() {
@ -61,11 +60,11 @@ fn new_line_semicolon_insertion() {
LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new(
Literal::from(true).into(),
Block::from(vec![StatementListItem::Statement(Statement::Break(
Break::new(Some(interner.get_or_intern_static("test", utf16!("test")))),
Break::new(Some(interner.get_or_intern("test"))),
))])
.into(),
))),
interner.get_or_intern_static("test", utf16!("test")),
interner.get_or_intern("test"),
))
.into()],
interner,
@ -99,11 +98,11 @@ fn new_line_block() {
LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new(
Literal::from(true).into(),
Block::from(vec![StatementListItem::Statement(Statement::Break(
Break::new(Some(interner.get_or_intern_static("test", utf16!("test")))),
Break::new(Some(interner.get_or_intern("test"))),
))])
.into(),
))),
interner.get_or_intern_static("test", utf16!("test")),
interner.get_or_intern("test"),
))
.into()],
interner,

9
boa_parser/src/parser/statement/continue_stm/tests.rs

@ -5,7 +5,6 @@ use boa_ast::{
Statement, StatementListItem,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
#[test]
fn inline() {
@ -61,11 +60,11 @@ fn new_line_semicolon_insertion() {
LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new(
Literal::from(true).into(),
Block::from(vec![StatementListItem::Statement(Statement::Continue(
Continue::new(Some(interner.get_or_intern_static("test", utf16!("test")))),
Continue::new(Some(interner.get_or_intern("test"))),
))])
.into(),
))),
interner.get_or_intern_static("test", utf16!("test")),
interner.get_or_intern("test"),
))
.into()],
interner,
@ -99,11 +98,11 @@ fn new_line_block() {
LabelledItem::Statement(Statement::WhileLoop(WhileLoop::new(
Literal::from(true).into(),
Block::from(vec![StatementListItem::Statement(Statement::Continue(
Continue::new(Some(interner.get_or_intern_static("test", utf16!("test")))),
Continue::new(Some(interner.get_or_intern("test"))),
))])
.into(),
))),
interner.get_or_intern_static("test", utf16!("test")),
interner.get_or_intern("test"),
))
.into()],
interner,

2
boa_parser/src/parser/statement/declaration/export.rs

@ -307,7 +307,7 @@ where
match tok.kind() {
TokenKind::StringLiteral((ident, _)) => {
if interner.resolve_expect(*ident).utf8().is_none() {
if !interner.resolve_expect(*ident).as_str().is_ascii() {
return Err(Error::general(
"import specifiers don't allow unpaired surrogates",
tok.span().end(),

7
boa_parser/src/parser/statement/declaration/hoistable/async_function_decl/tests.rs

@ -4,7 +4,6 @@ use boa_ast::{
Declaration,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
/// Async function declaration parsing.
#[test]
@ -13,11 +12,7 @@ fn async_function_declaration() {
check_script_parser(
"async function hello() {}",
vec![Declaration::AsyncFunction(AsyncFunction::new(
Some(
interner
.get_or_intern_static("hello", utf16!("hello"))
.into(),
),
Some(interner.get_or_intern("hello").into()),
FormalParameterList::default(),
FunctionBody::default(),
false,

3
boa_parser/src/parser/statement/declaration/hoistable/async_generator_decl/tests.rs

@ -4,7 +4,6 @@ use boa_ast::{
Declaration,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn async_generator_function_declaration() {
@ -12,7 +11,7 @@ fn async_generator_function_declaration() {
check_script_parser(
"async function* gen() {}",
vec![Declaration::AsyncGenerator(AsyncGenerator::new(
Some(interner.get_or_intern_static("gen", utf16!("gen")).into()),
Some(interner.get_or_intern("gen").into()),
FormalParameterList::default(),
FunctionBody::default(),
false,

10
boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs

@ -28,8 +28,7 @@ use boa_ast::{
property::{ClassElementName, MethodDefinition},
Expression, Keyword, Punctuator,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
use boa_interner::{js_string, Interner, Sym};
use rustc_hash::{FxHashMap, FxHashSet};
use std::io::Read;
@ -1162,11 +1161,8 @@ where
}
TokenKind::PrivateIdentifier(name) => {
let name = *name;
let name_private = interner.get_or_intern(
[utf16!("#"), interner.resolve_expect(name).utf16()]
.concat()
.as_slice(),
);
let name_private = interner
.get_or_intern(js_string!("#", &*interner.resolve_expect(name)).as_str());
cursor.advance(interner);
let token = cursor.peek(0, interner).or_abrupt()?;
match token.kind() {

31
boa_parser/src/parser/statement/declaration/hoistable/class_decl/tests.rs

@ -11,14 +11,13 @@ use boa_ast::{
Declaration, Expression, Statement, StatementList, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn check_async_ordinary_method() {
let interner = &mut Interner::default();
let elements = vec![ClassElement::MethodDefinition(
PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))),
PropertyName::Literal(interner.get_or_intern("async")),
MethodDefinition::Ordinary(Function::new(
None,
FormalParameterList::default(),
@ -32,7 +31,7 @@ fn check_async_ordinary_method() {
}
",
[Declaration::Class(Class::new(
Some(interner.get_or_intern_static("A", utf16!("A")).into()),
Some(interner.get_or_intern("A").into()),
None,
None,
elements.into(),
@ -48,7 +47,7 @@ fn check_async_field_initialization() {
let interner = &mut Interner::default();
let elements = vec![ClassElement::FieldDefinition(
PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))),
PropertyName::Literal(interner.get_or_intern("async")),
Some(Literal::from(1).into()),
)];
@ -59,7 +58,7 @@ fn check_async_field_initialization() {
}
",
[Declaration::Class(Class::new(
Some(interner.get_or_intern_static("A", utf16!("A")).into()),
Some(interner.get_or_intern("A").into()),
None,
None,
elements.into(),
@ -75,7 +74,7 @@ fn check_async_field() {
let interner = &mut Interner::default();
let elements = vec![ClassElement::FieldDefinition(
PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))),
PropertyName::Literal(interner.get_or_intern("async")),
None,
)];
@ -85,7 +84,7 @@ fn check_async_field() {
}
",
[Declaration::Class(Class::new(
Some(interner.get_or_intern_static("A", utf16!("A")).into()),
Some(interner.get_or_intern("A").into()),
None,
None,
elements.into(),
@ -101,24 +100,20 @@ fn check_new_target_with_property_access() {
let interner = &mut Interner::default();
let new_target = Expression::PropertyAccess(
SimplePropertyAccess::new(
Expression::NewTarget,
interner.get_or_intern_static("name", utf16!("name")),
)
.into(),
SimplePropertyAccess::new(Expression::NewTarget, interner.get_or_intern("name")).into(),
);
let console = Expression::Call(Call::new(
PropertyAccess::Simple(SimplePropertyAccess::new(
Identifier::from(interner.get_or_intern_static("console", utf16!("console"))).into(),
interner.get_or_intern_static("log", utf16!("log")),
Identifier::from(interner.get_or_intern("console")).into(),
interner.get_or_intern("log"),
))
.into(),
[new_target].into(),
));
let constructor = Function::new(
Some(interner.get_or_intern_static("A", utf16!("A")).into()),
Some(interner.get_or_intern("A").into()),
FormalParameterList::default(),
FunctionBody::new(StatementList::new(
[Statement::Expression(console).into()],
@ -127,7 +122,7 @@ fn check_new_target_with_property_access() {
);
let class = Class::new(
Some(interner.get("A").unwrap().into()),
Some(interner.get_or_intern("A").into()),
None,
Some(constructor),
Box::default(),
@ -136,7 +131,7 @@ fn check_new_target_with_property_access() {
let instantiation = Expression::New(
Call::new(
Identifier::from(interner.get("A").unwrap()).into(),
Identifier::from(interner.get_or_intern("A")).into(),
Box::default(),
)
.into(),
@ -145,7 +140,7 @@ fn check_new_target_with_property_access() {
let const_decl = LexicalDeclaration::Const(
VariableList::new(
[Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(instantiation),
)]
.into(),

13
boa_parser/src/parser/statement/declaration/hoistable/function_decl/tests.rs

@ -4,7 +4,6 @@ use boa_ast::{
Declaration,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Function declaration parsing.
#[test]
@ -13,11 +12,7 @@ fn function_declaration() {
check_script_parser(
"function hello() {}",
vec![Declaration::Function(Function::new(
Some(
interner
.get_or_intern_static("hello", utf16!("hello"))
.into(),
),
Some(interner.get_or_intern("hello").into()),
FormalParameterList::default(),
FunctionBody::default(),
))
@ -32,11 +27,7 @@ fn function_declaration_keywords() {
macro_rules! genast {
($keyword:literal, $interner:expr) => {
vec![Declaration::Function(Function::new(
Some(
$interner
.get_or_intern_static($keyword, utf16!($keyword))
.into(),
),
Some($interner.get_or_intern($keyword).into()),
FormalParameterList::default(),
FunctionBody::default(),
))

3
boa_parser/src/parser/statement/declaration/hoistable/generator_decl/tests.rs

@ -4,7 +4,6 @@ use boa_ast::{
Declaration,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn generator_function_declaration() {
@ -12,7 +11,7 @@ fn generator_function_declaration() {
check_script_parser(
"function* gen() {}",
vec![Declaration::Generator(Generator::new(
Some(interner.get_or_intern_static("gen", utf16!("gen")).into()),
Some(interner.get_or_intern("gen").into()),
FormalParameterList::default(),
FunctionBody::default(),
false,

2
boa_parser/src/parser/statement/declaration/import.rs

@ -298,7 +298,7 @@ where
match tok.kind() {
TokenKind::StringLiteral((name, _)) => {
let name = *name;
if interner.resolve_expect(name).utf8().is_none() {
if !interner.resolve_expect(name).as_str().is_ascii() {
return Err(Error::general(
"import specifiers don't allow unpaired surrogates",
tok.span().end(),

39
boa_parser/src/parser/statement/declaration/tests.rs

@ -5,7 +5,6 @@ use boa_ast::{
Declaration, Statement,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
/// Checks `var` declaration parsing.
#[test]
@ -15,7 +14,7 @@ fn var_declaration() {
"var a = 5;",
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
)]
.try_into()
@ -68,7 +67,7 @@ fn var_declaration_no_spaces() {
"var a=5;",
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
)]
.try_into()
@ -87,7 +86,7 @@ fn empty_var_declaration() {
"var a;",
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
None,
)]
.try_into()
@ -107,15 +106,12 @@ fn multiple_var_declaration() {
vec![Statement::Var(VarDeclaration(
vec![
Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
Variable::from_identifier(
interner.get_or_intern_static("b", utf16!("b")).into(),
None,
),
Variable::from_identifier(
interner.get_or_intern_static("c", utf16!("c")).into(),
interner.get_or_intern("c").into(),
Some(Literal::from(6).into()),
),
]
@ -135,7 +131,7 @@ fn let_declaration() {
"let a = 5;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
)]
.try_into()
@ -188,7 +184,7 @@ fn let_declaration_no_spaces() {
"let a=5;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
)]
.try_into()
@ -207,7 +203,7 @@ fn empty_let_declaration() {
"let a;",
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
None,
)]
.try_into()
@ -227,15 +223,12 @@ fn multiple_let_declaration() {
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![
Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
),
Variable::from_identifier(interner.get_or_intern("b").into(), None),
Variable::from_identifier(
interner.get_or_intern_static("b", utf16!("b")).into(),
None,
),
Variable::from_identifier(
interner.get_or_intern_static("c", utf16!("c")).into(),
interner.get_or_intern("c").into(),
Some(Literal::from(6).into()),
),
]
@ -255,7 +248,7 @@ fn const_declaration() {
"const a = 5;",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
)]
.try_into()
@ -308,7 +301,7 @@ fn const_declaration_no_spaces() {
"const a=5;",
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
)]
.try_into()
@ -334,11 +327,11 @@ fn multiple_const_declaration() {
vec![Declaration::Lexical(LexicalDeclaration::Const(
vec![
Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::from(5).into()),
),
Variable::from_identifier(
interner.get_or_intern_static("c", utf16!("c")).into(),
interner.get_or_intern("c").into(),
Some(Literal::from(6).into()),
),
]

61
boa_parser/src/parser/statement/iteration/tests.rs

@ -16,7 +16,6 @@ use boa_ast::{
Expression, Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Checks do-while statement parsing.
#[test]
@ -31,7 +30,7 @@ fn check_do_while() {
vec![StatementListItem::Statement(Statement::Expression(
Expression::from(Assign::new(
AssignOp::Add,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(1).into(),
)),
))]
@ -54,7 +53,7 @@ fn check_do_while_semicolon_insertion() {
vec![
Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("i", utf16!("i")).into(),
interner.get_or_intern("i").into(),
Some(Literal::from(0).into()),
)]
.try_into()
@ -67,19 +66,12 @@ fn check_do_while_semicolon_insertion() {
Expression::from(Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static("console", utf16!("console")),
)
.into(),
interner.get_or_intern_static("log", utf16!("log")),
Identifier::new(interner.get_or_intern("console")).into(),
interner.get_or_intern("log"),
)
.into(),
),
vec![Literal::from(
interner.get_or_intern_static("hello", utf16!("hello")),
)
.into()]
.into(),
vec![Literal::from(interner.get_or_intern("hello")).into()].into(),
)),
))]
.into(),
@ -88,9 +80,7 @@ fn check_do_while_semicolon_insertion() {
RelationalOp::LessThan.into(),
Update::new(
UpdateOp::IncrementPost,
UpdateTarget::Identifier(Identifier::new(
interner.get_or_intern_static("i", utf16!("i")),
)),
UpdateTarget::Identifier(Identifier::new(interner.get_or_intern("i"))),
)
.into(),
Literal::from(10).into(),
@ -101,16 +91,12 @@ fn check_do_while_semicolon_insertion() {
Statement::Expression(Expression::from(Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static("console", utf16!("console")),
)
.into(),
interner.get_or_intern_static("log", utf16!("log")),
Identifier::new(interner.get_or_intern("console")).into(),
interner.get_or_intern("log"),
)
.into(),
),
vec![Literal::from(interner.get_or_intern_static("end", utf16!("end"))).into()]
.into(),
vec![Literal::from(interner.get_or_intern("end")).into()].into(),
)))
.into(),
],
@ -129,7 +115,7 @@ fn check_do_while_semicolon_insertion_no_space() {
vec![
Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("i", utf16!("i")).into(),
interner.get_or_intern("i").into(),
Some(Literal::from(0).into()),
)]
.try_into()
@ -142,19 +128,12 @@ fn check_do_while_semicolon_insertion_no_space() {
Expression::from(Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static("console", utf16!("console")),
)
.into(),
interner.get_or_intern_static("log", utf16!("log")),
Identifier::new(interner.get_or_intern("console")).into(),
interner.get_or_intern("log"),
)
.into(),
),
vec![Literal::from(
interner.get_or_intern_static("hello", utf16!("hello")),
)
.into()]
.into(),
vec![Literal::from(interner.get_or_intern("hello")).into()].into(),
)),
))]
.into(),
@ -163,9 +142,7 @@ fn check_do_while_semicolon_insertion_no_space() {
RelationalOp::LessThan.into(),
Update::new(
UpdateOp::IncrementPost,
UpdateTarget::Identifier(Identifier::new(
interner.get_or_intern_static("i", utf16!("i")),
)),
UpdateTarget::Identifier(Identifier::new(interner.get_or_intern("i"))),
)
.into(),
Literal::from(10).into(),
@ -176,16 +153,12 @@ fn check_do_while_semicolon_insertion_no_space() {
Statement::Expression(Expression::from(Call::new(
Expression::PropertyAccess(
SimplePropertyAccess::new(
Identifier::new(
interner.get_or_intern_static("console", utf16!("console")),
)
.into(),
interner.get_or_intern_static("log", utf16!("log")),
Identifier::new(interner.get_or_intern("console")).into(),
interner.get_or_intern("log"),
)
.into(),
),
vec![Literal::from(interner.get_or_intern_static("end", utf16!("end"))).into()]
.into(),
vec![Literal::from(interner.get_or_intern("end")).into()].into(),
)))
.into(),
],

8
boa_parser/src/parser/statement/mod.rs

@ -56,7 +56,6 @@ use boa_ast::{
Keyword, Punctuator,
};
use boa_interner::Interner;
use boa_macros::utf16;
use boa_profiler::Profiler;
use std::io::Read;
@ -317,11 +316,8 @@ where
ast::StatementListItem::Statement(ast::Statement::Expression(
ast::Expression::Literal(ast::expression::literal::Literal::String(string)),
)) if !strict => {
if interner.resolve_expect(*string).join(
|s| s == "use strict",
|g| g == utf16!("use strict"),
true,
) && directives_stack.last().expect("token should exist").1
if &*interner.resolve_expect(*string) == "use strict"
&& directives_stack.last().expect("token should exist").1
== EscapeSequence::empty()
{
cursor.set_strict(true);

13
boa_parser/src/parser/statement/switch/tests.rs

@ -6,7 +6,6 @@ use boa_ast::{
Declaration, Expression, Statement,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Checks parsing malformed switch with no closeblock.
#[test]
@ -148,9 +147,9 @@ fn check_separated_switch() {
"#;
let interner = &mut Interner::default();
let log = interner.get_or_intern_static("log", utf16!("log"));
let console = interner.get_or_intern_static("console", utf16!("console"));
let a = interner.get_or_intern_static("a", utf16!("a"));
let log = interner.get_or_intern("log");
let console = interner.get_or_intern("console");
let a = interner.get_or_intern("a");
check_script_parser(
s,
@ -203,11 +202,7 @@ fn check_separated_switch() {
SimplePropertyAccess::new(Identifier::new(console).into(), log)
.into(),
),
vec![Literal::from(
interner.get_or_intern_static("Default", utf16!("Default")),
)
.into()]
.into(),
vec![Literal::from(interner.get_or_intern("Default")).into()].into(),
)))
.into()]
.into(),

3
boa_parser/src/parser/statement/throw/tests.rs

@ -1,7 +1,6 @@
use crate::parser::tests::check_script_parser;
use boa_ast::{expression::literal::Literal, statement::Throw, Statement};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn check_throw_parsing() {
@ -9,7 +8,7 @@ fn check_throw_parsing() {
check_script_parser(
"throw 'error';",
vec![Statement::Throw(Throw::new(
Literal::from(interner.get_or_intern_static("error", utf16!("error"))).into(),
Literal::from(interner.get_or_intern("error")).into(),
))
.into()],
interner,

39
boa_parser/src/parser/statement/try_stm/tests.rs

@ -8,7 +8,6 @@ use boa_ast::{
Statement, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
#[test]
fn check_inline_with_empty_try_catch() {
@ -18,7 +17,7 @@ fn check_inline_with_empty_try_catch() {
vec![Statement::Try(Try::new(
Block::default(),
ErrorHandler::Catch(Catch::new(
Some(Identifier::from(interner.get_or_intern_static("e", utf16!("e"))).into()),
Some(Identifier::from(interner.get_or_intern("e")).into()),
Block::default(),
)),
))
@ -35,7 +34,7 @@ fn check_inline_with_var_decl_inside_try() {
vec![Statement::Try(Try::new(
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(Literal::from(1).into()),
)]
.try_into()
@ -44,7 +43,7 @@ fn check_inline_with_var_decl_inside_try() {
.into()]
.into(),
ErrorHandler::Catch(Catch::new(
Some(Identifier::from(interner.get_or_intern_static("e", utf16!("e"))).into()),
Some(Identifier::from(interner.get_or_intern("e")).into()),
Block::default(),
)),
))
@ -61,7 +60,7 @@ fn check_inline_with_var_decl_inside_catch() {
vec![Statement::Try(Try::new(
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(Literal::from(1).into()),
)]
.try_into()
@ -70,10 +69,10 @@ fn check_inline_with_var_decl_inside_catch() {
.into()]
.into(),
ErrorHandler::Catch(Catch::new(
Some(Identifier::from(interner.get_or_intern_static("e", utf16!("e"))).into()),
Some(Identifier::from(interner.get_or_intern("e")).into()),
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(Literal::from(1).into()),
)]
.try_into()
@ -97,7 +96,7 @@ fn check_inline_with_empty_try_catch_finally() {
Block::default(),
ErrorHandler::Full(
Catch::new(
Some(Identifier::from(interner.get_or_intern_static("e", utf16!("e"))).into()),
Some(Identifier::from(interner.get_or_intern("e")).into()),
Block::default(),
),
Finally::from(Block::default()),
@ -131,7 +130,7 @@ fn check_inline_with_empty_try_var_decl_in_finally() {
ErrorHandler::Finally(Finally::from(Block::from(vec![
StatementListItem::Statement(Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(Literal::from(1).into()),
)]
.try_into()
@ -155,7 +154,7 @@ fn check_inline_empty_try_paramless_catch() {
None,
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(Literal::from(1).into()),
)]
.try_into()
@ -173,7 +172,7 @@ fn check_inline_empty_try_paramless_catch() {
#[test]
fn check_inline_with_binding_pattern_object() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_script_parser(
"try {} catch ({ a, b: c }) {}",
vec![Statement::Try(Try::new(
@ -187,10 +186,8 @@ fn check_inline_with_binding_pattern_object() {
default_init: None,
},
ObjectPatternElement::SingleName {
ident: interner.get_or_intern_static("c", utf16!("c")).into(),
name: PropertyName::Literal(
interner.get_or_intern_static("b", utf16!("b")),
),
ident: interner.get_or_intern("c").into(),
name: PropertyName::Literal(interner.get_or_intern("b")),
default_init: None,
},
])
@ -215,11 +212,11 @@ fn check_inline_with_binding_pattern_array() {
Some(
Pattern::from(vec![
ArrayPatternElement::SingleName {
ident: interner.get_or_intern_static("a", utf16!("a")).into(),
ident: interner.get_or_intern("a").into(),
default_init: None,
},
ArrayPatternElement::SingleName {
ident: interner.get_or_intern_static("b", utf16!("b")).into(),
ident: interner.get_or_intern("b").into(),
default_init: None,
},
])
@ -241,13 +238,11 @@ fn check_catch_with_var_redeclaration() {
vec![Statement::Try(Try::new(
Block::from(vec![]),
ErrorHandler::Catch(Catch::new(
Some(Identifier::new(interner.get_or_intern_static("e", utf16!("e"))).into()),
Some(Identifier::new(interner.get_or_intern("e")).into()),
vec![Statement::Var(VarDeclaration(
vec![Variable::from_identifier(
interner.get_or_intern_static("e", utf16!("e")).into(),
Some(
Literal::from(interner.get_or_intern_static("oh", utf16!("oh"))).into(),
),
interner.get_or_intern("e").into(),
Some(Literal::from(interner.get_or_intern("oh")).into()),
)]
.try_into()
.unwrap(),

72
boa_parser/src/parser/tests/mod.rs

@ -27,7 +27,6 @@ use boa_ast::{
Expression, Script, Statement, StatementList, StatementListItem,
};
use boa_interner::Interner;
use boa_macros::utf16;
/// Checks that the given JavaScript string gives the expected expression.
#[track_caller]
@ -61,12 +60,11 @@ fn check_construct_call_precedence() {
Expression::PropertyAccess(
SimplePropertyAccess::new(
New::from(Call::new(
Identifier::new(interner.get_or_intern_static("Date", utf16!("Date")))
.into(),
Identifier::new(interner.get_or_intern("Date")).into(),
Box::default(),
))
.into(),
interner.get_or_intern_static("getTime", utf16!("getTime")),
interner.get_or_intern("getTime"),
)
.into(),
),
@ -84,10 +82,10 @@ fn assign_operator_precedence() {
"a = a + 1",
vec![Statement::Expression(Expression::from(Assign::new(
AssignOp::Assign,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Binary::new(
ArithmeticOp::Add.into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(1).into(),
)
.into(),
@ -100,8 +98,8 @@ fn assign_operator_precedence() {
#[test]
fn hoisting() {
let interner = &mut Interner::default();
let hello = interner.get_or_intern_static("hello", utf16!("hello"));
let a = interner.get_or_intern_static("a", utf16!("a"));
let hello = interner.get_or_intern("hello");
let a = interner.get_or_intern("a");
check_script_parser(
r"
var a = hello();
@ -137,7 +135,7 @@ fn hoisting() {
);
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_script_parser(
r"
a = 10;
@ -179,13 +177,13 @@ fn ambigous_regex_divide_expression() {
Binary::new(
ArithmeticOp::Div.into(),
Literal::Int(1).into(),
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
)
.into(),
Binary::new(
ArithmeticOp::Div.into(),
Literal::Int(1).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)
.into(),
)))
@ -199,7 +197,7 @@ fn two_divisions_in_expression() {
let s = "a !== 0 || 1 / a === 1 / b;";
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_script_parser(
s,
vec![Statement::Expression(Expression::from(Binary::new(
@ -221,7 +219,7 @@ fn two_divisions_in_expression() {
Binary::new(
ArithmeticOp::Div.into(),
Literal::Int(1).into(),
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
Identifier::new(interner.get_or_intern("b")).into(),
)
.into(),
)
@ -245,7 +243,7 @@ fn comment_semi_colon_insertion() {
vec![
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::Int(10).into()),
)]
.try_into()
@ -254,7 +252,7 @@ fn comment_semi_colon_insertion() {
.into(),
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
Some(Literal::Int(20).into()),
)]
.try_into()
@ -281,7 +279,7 @@ fn multiline_comment_semi_colon_insertion() {
vec![
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::Int(10).into()),
)]
.try_into()
@ -290,7 +288,7 @@ fn multiline_comment_semi_colon_insertion() {
.into(),
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
Some(Literal::Int(20).into()),
)]
.try_into()
@ -314,7 +312,7 @@ fn multiline_comment_no_lineterminator() {
vec![
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::Int(10).into()),
)]
.try_into()
@ -323,7 +321,7 @@ fn multiline_comment_no_lineterminator() {
.into(),
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("b", utf16!("b")).into(),
interner.get_or_intern("b").into(),
Some(Literal::Int(20).into()),
)]
.try_into()
@ -350,7 +348,7 @@ fn assignment_line_terminator() {
vec![
Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("a", utf16!("a")).into(),
interner.get_or_intern("a").into(),
Some(Literal::Int(3).into()),
)]
.try_into()
@ -359,7 +357,7 @@ fn assignment_line_terminator() {
.into(),
Statement::Expression(Expression::from(Assign::new(
AssignOp::Assign,
Identifier::new(interner.get_or_intern_static("a", utf16!("a"))).into(),
Identifier::new(interner.get_or_intern("a")).into(),
Literal::from(5).into(),
)))
.into(),
@ -381,7 +379,7 @@ fn assignment_multiline_terminator() {
"#;
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_script_parser(
s,
vec![
@ -413,10 +411,7 @@ fn bracketed_expr() {
check_script_parser(
s,
vec![Statement::Expression(
Parenthesized::new(
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
)
.into(),
Parenthesized::new(Identifier::new(interner.get_or_intern("b")).into()).into(),
)
.into()],
interner,
@ -428,7 +423,7 @@ fn increment_in_comma_op() {
let s = r#"(b++, b)"#;
let interner = &mut Interner::default();
let b = interner.get_or_intern_static("b", utf16!("b"));
let b = interner.get_or_intern("b");
check_script_parser(
s,
vec![Statement::Expression(
@ -463,20 +458,15 @@ fn spread_in_object() {
let interner = &mut Interner::default();
let object_properties = vec![
PropertyDefinition::Property(
interner.get_or_intern_static("a", utf16!("a")).into(),
Literal::from(1).into(),
),
PropertyDefinition::SpreadObject(
Identifier::new(interner.get_or_intern_static("b", utf16!("b"))).into(),
),
PropertyDefinition::Property(interner.get_or_intern("a").into(), Literal::from(1).into()),
PropertyDefinition::SpreadObject(Identifier::new(interner.get_or_intern("b")).into()),
];
check_script_parser(
s,
vec![Declaration::Lexical(LexicalDeclaration::Let(
vec![Variable::from_identifier(
interner.get_or_intern_static("x", utf16!("x")).into(),
interner.get_or_intern("x").into(),
Some(ObjectLiteral::from(object_properties).into()),
)]
.try_into()
@ -496,7 +486,7 @@ fn spread_in_arrow_function() {
"#;
let interner = &mut Interner::default();
let b = interner.get_or_intern_static("b", utf16!("b"));
let b = interner.get_or_intern("b");
let params = FormalParameterList::from(FormalParameter::new(
Variable::from_identifier(b.into(), None),
true,
@ -520,7 +510,7 @@ fn spread_in_arrow_function() {
#[test]
fn empty_statement() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let a = interner.get_or_intern("a");
check_script_parser(
r"
;;var a = 10;
@ -547,11 +537,9 @@ fn empty_statement() {
#[test]
fn empty_statement_ends_directive_prologues() {
let interner = &mut Interner::default();
let a = interner.get_or_intern_static("a", utf16!("a"));
let use_strict = interner.get_or_intern_static("use strict", utf16!("use strict"));
let public = interner
.get_or_intern_static("public", utf16!("public"))
.into();
let a = interner.get_or_intern("a");
let use_strict = interner.get_or_intern("use strict");
let public = interner.get_or_intern("public").into();
check_script_parser(
r#"
"a";

103
boa_types/src/string/common.rs

@ -60,7 +60,8 @@ impl StaticJsStrings {
/// Gets the `JsString` corresponding to `string`, or `None` if the string
/// doesn't exist inside the static array.
pub(crate) fn get_string(string: &str) -> Option<JsString> {
#[must_use]
pub fn get_string(string: &str) -> Option<JsString> {
if string.len() > MAX_STATIC_LENGTH {
return None;
}
@ -74,7 +75,8 @@ impl StaticJsStrings {
/// Gets the `&[u16]` slice corresponding to the provided index, or `None` if the index
/// provided exceeds the size of the static array.
pub(crate) fn get(index: usize) -> Option<&'static str> {
#[must_use]
pub fn get(index: usize) -> Option<&'static str> {
RAW_STATICS.index(index).copied()
}
@ -206,8 +208,82 @@ const MAX_STATIC_LENGTH: usize = {
};
/// Array of raw static strings that aren't reference counted.
const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
pub const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
// Reserved identifiers
// See: <https://tc39.es/ecma262/#prod-ReservedWord>
// Note, they must all be together.
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"enum",
"export",
"extends",
"false",
"finally",
"for",
"function",
"if",
"import",
"in",
"instanceof",
"new",
"null",
"return",
"super",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
// End reserved identifier
// strict reserved identifiers.
// See: <https://tc39.es/ecma262/#prod-Identifier>
// Note, they must all be together.
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield",
// End strict reserved identifiers
"",
"prototype",
"constructor",
"arguments",
"eval",
"RegExp",
"get",
"set",
"<main>",
"raw",
"anonymous",
"async",
"of",
"target",
"as",
"from",
"__proto__",
"name",
"await",
"*default*",
"meta",
// Well known symbols
"Symbol.asyncIterator",
"[Symbol.asyncIterator]",
@ -259,7 +335,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"URIError",
"escape",
"unescape",
"eval",
"Function",
"Generator",
"GeneratorFunction",
@ -282,7 +357,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"Promise",
"Proxy",
"Reflect",
"RegExp",
"Set",
"String",
"Symbol",
@ -321,28 +395,18 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
",",
":",
// Generic use
"name",
"length",
"arguments",
"prototype",
"constructor",
"return",
"throw",
"global",
"globalThis",
// typeof
"null",
"undefined",
"number",
"string",
"symbol",
"bigint",
"object",
"function",
// Property descriptor
"value",
"get",
"set",
"writable",
"enumerable",
"configurable",
@ -381,7 +445,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"__defineSetter__",
"__lookupGetter__",
"__lookupSetter__",
"__proto__",
"get __proto__",
"set __proto__",
// Function object
@ -393,9 +456,7 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"callee",
// Array object
"at",
"from",
"isArray",
"of",
"copyWithin",
"every",
"fill",
@ -427,7 +488,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"toReversed",
"toSorted",
"toSpliced",
"with",
// String object
"charAt",
"charCodeAt",
@ -442,7 +502,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"normalize",
"padEnd",
"padStart",
"raw",
"repeat",
"replace",
"replaceAll",
@ -519,7 +578,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"get flags",
"get source",
// Symbol object
"for",
"keyFor",
"description",
"asyncIterator",
@ -533,7 +591,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"get description",
// Map object
"clear",
"delete",
"has",
"size",
// Set object
@ -601,8 +658,6 @@ const RAW_STATICS: phf::OrderedSet<&'static str> = phf::phf_ordered_set!(
"any",
"race",
"then",
"catch",
"finally",
"withResolvers",
// Iterator object
"Array Iterator",

6
boa_types/src/string/mod.rs

@ -867,6 +867,12 @@ impl JsString {
pub fn is_static(&self) -> bool {
self.ptr.is_tagged()
}
pub fn as_static(&self) -> Option<usize> {
if let UnwrappedTagged::Tag(index) = self.ptr.unwrap() {
return Some(index);
}
None
}
pub fn get<'a, I>(&'a self, index: I) -> Option<I::Value>
where

Loading…
Cancel
Save