Browse Source

Parser Idempotency Fuzzer (#2400)

This Pull Request offers a fuzzer which is capable of detecting faults in the parser and interner. It does so by ensuring that the parsed AST remains the same between a parsed source and the result of parsing the `to_interned_string` result of the first parsed source.

It changes the following:

- Adds a fuzzer for the parser and interner.

Any issues I raise in association with this fuzzer will link back to this fuzzer.

You may run the fuzzer using the following commands:
```bash
$ cd boa_engine
$ cargo +nightly fuzz run -s none parser-idempotency
```

Co-authored-by: Addison Crump <addison.crump@cispa.de>
pull/2414/head
Addison Crump 2 years ago
parent
commit
e64a20e2a6
  1. 23
      Cargo.lock
  2. 3
      boa_ast/Cargo.toml
  3. 1
      boa_ast/src/declaration/mod.rs
  4. 5
      boa_ast/src/declaration/variable.rs
  5. 5
      boa_ast/src/expression/access.rs
  6. 1
      boa_ast/src/expression/await.rs
  7. 2
      boa_ast/src/expression/call.rs
  8. 1
      boa_ast/src/expression/identifier.rs
  9. 1
      boa_ast/src/expression/literal/array.rs
  10. 1
      boa_ast/src/expression/literal/mod.rs
  11. 1
      boa_ast/src/expression/literal/object.rs
  12. 2
      boa_ast/src/expression/literal/template.rs
  13. 1
      boa_ast/src/expression/mod.rs
  14. 1
      boa_ast/src/expression/new.rs
  15. 2
      boa_ast/src/expression/operator/assign/mod.rs
  16. 1
      boa_ast/src/expression/operator/assign/op.rs
  17. 1
      boa_ast/src/expression/operator/binary/mod.rs
  18. 5
      boa_ast/src/expression/operator/binary/op.rs
  19. 1
      boa_ast/src/expression/operator/conditional.rs
  20. 1
      boa_ast/src/expression/operator/unary/mod.rs
  21. 1
      boa_ast/src/expression/operator/unary/op.rs
  22. 3
      boa_ast/src/expression/optional.rs
  23. 1
      boa_ast/src/expression/spread.rs
  24. 1
      boa_ast/src/expression/tagged_template.rs
  25. 1
      boa_ast/src/expression/yield.rs
  26. 1
      boa_ast/src/function/arrow_function.rs
  27. 1
      boa_ast/src/function/async_arrow_function.rs
  28. 1
      boa_ast/src/function/async_function.rs
  29. 1
      boa_ast/src/function/async_generator.rs
  30. 2
      boa_ast/src/function/class.rs
  31. 1
      boa_ast/src/function/generator.rs
  32. 1
      boa_ast/src/function/mod.rs
  33. 9
      boa_ast/src/function/parameters.rs
  34. 5
      boa_ast/src/pattern.rs
  35. 3
      boa_ast/src/property.rs
  36. 1
      boa_ast/src/statement/block.rs
  37. 1
      boa_ast/src/statement/if.rs
  38. 1
      boa_ast/src/statement/iteration/break.rs
  39. 1
      boa_ast/src/statement/iteration/continue.rs
  40. 1
      boa_ast/src/statement/iteration/do_while_loop.rs
  41. 1
      boa_ast/src/statement/iteration/for_in_loop.rs
  42. 3
      boa_ast/src/statement/iteration/for_loop.rs
  43. 1
      boa_ast/src/statement/iteration/for_of_loop.rs
  44. 1
      boa_ast/src/statement/iteration/mod.rs
  45. 1
      boa_ast/src/statement/iteration/while_loop.rs
  46. 2
      boa_ast/src/statement/labelled.rs
  47. 1
      boa_ast/src/statement/mod.rs
  48. 1
      boa_ast/src/statement/return.rs
  49. 2
      boa_ast/src/statement/switch.rs
  50. 1
      boa_ast/src/statement/throw.rs
  51. 4
      boa_ast/src/statement/try.rs
  52. 11
      boa_ast/src/statement_list.rs
  53. 2
      boa_engine/Cargo.toml
  54. 5
      boa_interner/Cargo.toml
  55. 3
      boa_interner/src/sym.rs
  56. 4
      fuzz/.gitignore
  57. 831
      fuzz/Cargo.lock
  58. 29
      fuzz/Cargo.toml
  59. 37
      fuzz/README.md
  60. 74
      fuzz/fuzz_targets/common.rs
  61. 74
      fuzz/fuzz_targets/parser-idempotency.rs

23
Cargo.lock generated

@ -32,6 +32,15 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "arbitrary"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -59,6 +68,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
name = "boa_ast" name = "boa_ast"
version = "0.16.0" version = "0.16.0"
dependencies = [ dependencies = [
"arbitrary",
"bitflags", "bitflags",
"boa_interner", "boa_interner",
"boa_macros", "boa_macros",
@ -153,6 +163,7 @@ dependencies = [
name = "boa_interner" name = "boa_interner"
version = "0.16.0" version = "0.16.0"
dependencies = [ dependencies = [
"arbitrary",
"boa_macros", "boa_macros",
"indexmap", "indexmap",
"once_cell", "once_cell",
@ -539,6 +550,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "derive_arbitrary"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4903dff04948f22033ca30232ab8eca2c3fc4c913a8b6a34ee5199699814817f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "dirs-next" name = "dirs-next"
version = "2.0.0" version = "2.0.0"
@ -1077,6 +1099,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [ dependencies = [
"arbitrary",
"autocfg", "autocfg",
"num-integer", "num-integer",
"num-traits", "num-traits",

3
boa_ast/Cargo.toml

@ -13,6 +13,8 @@ rust-version.workspace = true
[features] [features]
serde = ["boa_interner/serde", "dep:serde"] serde = ["boa_interner/serde", "dep:serde"]
fuzz = ["arbitrary", "boa_interner/fuzz", "num-bigint/arbitrary"]
[dependencies] [dependencies]
boa_interner.workspace = true boa_interner.workspace = true
boa_macros.workspace = true boa_macros.workspace = true
@ -20,3 +22,4 @@ rustc-hash = "1.1.0"
serde = { version = "1.0.147", features = ["derive"], optional = true } serde = { version = "1.0.147", features = ["derive"], optional = true }
bitflags = "1.3.2" bitflags = "1.3.2"
num-bigint = "0.4.3" num-bigint = "0.4.3"
arbitrary = { version = "1", optional = true, features = ["derive"] }

1
boa_ast/src/declaration/mod.rs

@ -27,6 +27,7 @@ pub use variable::*;
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Declaration { pub enum Declaration {
/// See [`Function`] /// See [`Function`]

5
boa_ast/src/declaration/variable.rs

@ -45,6 +45,7 @@ use super::Declaration;
/// [varstmt]: https://tc39.es/ecma262/#prod-VariableStatement /// [varstmt]: https://tc39.es/ecma262/#prod-VariableStatement
/// [hoisting]: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting /// [hoisting]: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct VarDeclaration(pub VariableList); pub struct VarDeclaration(pub VariableList);
@ -81,6 +82,7 @@ impl VisitWith for VarDeclaration {
/// ///
/// [lexical declaration]: https://tc39.es/ecma262/#sec-let-and-const-declarations /// [lexical declaration]: https://tc39.es/ecma262/#sec-let-and-const-declarations
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum LexicalDeclaration { pub enum LexicalDeclaration {
/// A <code>[const]</code> variable creates a constant whose scope can be either global or local /// A <code>[const]</code> variable creates a constant whose scope can be either global or local
@ -160,6 +162,7 @@ impl VisitWith for LexicalDeclaration {
/// List of variables in a variable declaration. /// List of variables in a variable declaration.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct VariableList { pub struct VariableList {
list: Box<[Variable]>, list: Box<[Variable]>,
@ -250,6 +253,7 @@ impl TryFrom<Vec<Variable>> for VariableList {
/// [spec2]: https://tc39.es/ecma262/#prod-VariableDeclaration /// [spec2]: https://tc39.es/ecma262/#prod-VariableDeclaration
/// [spec3]: https://tc39.es/ecma262/#sec-declarations-and-the-variable-statement /// [spec3]: https://tc39.es/ecma262/#sec-declarations-and-the-variable-statement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Variable { pub struct Variable {
binding: Binding, binding: Binding,
@ -332,6 +336,7 @@ impl VisitWith for Variable {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-declarations-and-the-variable-statement /// [spec]: https://tc39.es/ecma262/#sec-declarations-and-the-variable-statement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Binding { pub enum Binding {
/// A single identifier binding. /// A single identifier binding.

5
boa_ast/src/expression/access.rs

@ -24,6 +24,7 @@ use core::ops::ControlFlow;
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum PropertyAccessField { pub enum PropertyAccessField {
/// A constant property field, such as `x.prop`. /// A constant property field, such as `x.prop`.
@ -72,6 +73,7 @@ impl VisitWith for PropertyAccessField {
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum PropertyAccess { pub enum PropertyAccess {
/// A simple property access (`x.prop`). /// A simple property access (`x.prop`).
@ -126,6 +128,7 @@ impl VisitWith for PropertyAccess {
/// A simple property access, where the target object is an [`Expression`]. /// A simple property access, where the target object is an [`Expression`].
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SimplePropertyAccess { pub struct SimplePropertyAccess {
target: Box<Expression>, target: Box<Expression>,
@ -209,6 +212,7 @@ impl VisitWith for SimplePropertyAccess {
/// [spec]: https://tc39.es/ecma262/#prod-MemberExpression /// [spec]: https://tc39.es/ecma262/#prod-MemberExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct PrivatePropertyAccess { pub struct PrivatePropertyAccess {
target: Box<Expression>, target: Box<Expression>,
@ -285,6 +289,7 @@ impl VisitWith for PrivatePropertyAccess {
/// [spec]: https://tc39.es/ecma262/#prod-SuperProperty /// [spec]: https://tc39.es/ecma262/#prod-SuperProperty
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SuperPropertyAccess { pub struct SuperPropertyAccess {
field: PropertyAccessField, field: PropertyAccessField,

1
boa_ast/src/expression/await.rs

@ -16,6 +16,7 @@ use boa_interner::{Interner, ToIndentedString, ToInternedString};
/// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression /// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Await { pub struct Await {
target: Box<Expression>, target: Box<Expression>,

2
boa_ast/src/expression/call.rs

@ -21,6 +21,7 @@ use super::Expression;
/// [spec]: https://tc39.es/ecma262/#prod-CallExpression /// [spec]: https://tc39.es/ecma262/#prod-CallExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_functions /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Calling_functions
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Call { pub struct Call {
function: Box<Expression>, function: Box<Expression>,
@ -104,6 +105,7 @@ impl VisitWith for Call {
/// [spec]: https://tc39.es/ecma262/#prod-SuperCall /// [spec]: https://tc39.es/ecma262/#prod-SuperCall
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SuperCall { pub struct SuperCall {
args: Box<[Expression]>, args: Box<[Expression]>,

1
boa_ast/src/expression/identifier.rs

@ -43,6 +43,7 @@ pub const RESERVED_IDENTIFIERS_STRICT: [Sym; 9] = [
derive(serde::Serialize, serde::Deserialize), derive(serde::Serialize, serde::Deserialize),
serde(transparent) serde(transparent)
)] )]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)] #[repr(transparent)]
pub struct Identifier { pub struct Identifier {

1
boa_ast/src/expression/literal/array.rs

@ -25,6 +25,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ArrayLiteral /// [spec]: https://tc39.es/ecma262/#prod-ArrayLiteral
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ArrayLiteral { pub struct ArrayLiteral {
arr: Box<[Option<Expression>]>, arr: Box<[Option<Expression>]>,

1
boa_ast/src/expression/literal/mod.rs

@ -33,6 +33,7 @@ use super::Expression;
/// [spec]: https://tc39.es/ecma262/#sec-primary-expression-literals /// [spec]: https://tc39.es/ecma262/#sec-primary-expression-literals
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Literal { pub enum Literal {
/// A string literal is zero or more characters enclosed in double (`"`) or single (`'`) quotation marks. /// A string literal is zero or more characters enclosed in double (`"`) or single (`'`) quotation marks.

1
boa_ast/src/expression/literal/object.rs

@ -33,6 +33,7 @@ use core::ops::ControlFlow;
/// [primitive]: https://developer.mozilla.org/en-US/docs/Glossary/primitive /// [primitive]: https://developer.mozilla.org/en-US/docs/Glossary/primitive
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))] #[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ObjectLiteral { pub struct ObjectLiteral {
properties: Box<[PropertyDefinition]>, properties: Box<[PropertyDefinition]>,

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

@ -21,6 +21,7 @@ use crate::{
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
/// [spec]: https://tc39.es/ecma262/#sec-template-literals /// [spec]: https://tc39.es/ecma262/#sec-template-literals
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct TemplateLiteral { pub struct TemplateLiteral {
elements: Box<[TemplateElement]>, elements: Box<[TemplateElement]>,
@ -40,6 +41,7 @@ impl From<TemplateLiteral> for Expression {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-template-literals /// [spec]: https://tc39.es/ecma262/#sec-template-literals
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum TemplateElement { pub enum TemplateElement {
/// A simple string. /// A simple string.

1
boa_ast/src/expression/mod.rs

@ -51,6 +51,7 @@ pub mod operator;
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Expression { pub enum Expression {
/// The JavaScript `this` keyword refers to the object it belongs to. /// The JavaScript `this` keyword refers to the object it belongs to.

1
boa_ast/src/expression/new.rs

@ -21,6 +21,7 @@ use super::Expression;
/// [spec]: https://tc39.es/ecma262/#prod-NewExpression /// [spec]: https://tc39.es/ecma262/#prod-NewExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct New { pub struct New {
call: Call, call: Call,

2
boa_ast/src/expression/operator/assign/mod.rs

@ -28,6 +28,7 @@ use crate::{
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Assign { pub struct Assign {
op: AssignOp, op: AssignOp,
@ -110,6 +111,7 @@ impl VisitWith for Assign {
/// ///
/// [spec]: hhttps://tc39.es/ecma262/#prod-LeftHandSideExpression /// [spec]: hhttps://tc39.es/ecma262/#prod-LeftHandSideExpression
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum AssignTarget { pub enum AssignTarget {
/// A simple identifier, such as `a`. /// A simple identifier, such as `a`.

1
boa_ast/src/expression/operator/assign/op.rs

@ -12,6 +12,7 @@
/// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator /// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AssignOp { pub enum AssignOp {
/// The assignment operator assigns the value of the right operand to the left operand. /// The assignment operator assigns the value of the right operand to the left operand.

1
boa_ast/src/expression/operator/binary/mod.rs

@ -31,6 +31,7 @@ use crate::{
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Binary { pub struct Binary {
op: BinaryOp, op: BinaryOp,

5
boa_ast/src/expression/operator/binary/op.rs

@ -4,6 +4,7 @@ use std::fmt::{Display, Formatter, Result};
/// This represents a binary operation between two values. /// This represents a binary operation between two values.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinaryOp { pub enum BinaryOp {
/// Numeric operation. /// Numeric operation.
@ -86,6 +87,7 @@ impl Display for BinaryOp {
/// ///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Arithmetic /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Arithmetic
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ArithmeticOp { pub enum ArithmeticOp {
/// The addition operator produces the sum of numeric operands or string concatenation. /// The addition operator produces the sum of numeric operands or string concatenation.
@ -196,6 +198,7 @@ impl Display for ArithmeticOp {
/// ///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BitwiseOp { pub enum BitwiseOp {
/// Performs the AND operation on each pair of bits. a AND b yields 1 only if both a and b are 1. /// Performs the AND operation on each pair of bits. a AND b yields 1 only if both a and b are 1.
@ -319,6 +322,7 @@ impl Display for BitwiseOp {
/// [spec]: tc39.es/ecma262/#sec-testing-and-comparison-operations /// [spec]: tc39.es/ecma262/#sec-testing-and-comparison-operations
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Comparison /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Comparison
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RelationalOp { pub enum RelationalOp {
/// The equality operator converts the operands if they are not of the same type, then applies /// The equality operator converts the operands if they are not of the same type, then applies
@ -512,6 +516,7 @@ impl Display for RelationalOp {
/// [spec]: https://tc39.es/ecma262/#sec-binary-logical-operators /// [spec]: https://tc39.es/ecma262/#sec-binary-logical-operators
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Logical /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Logical
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LogicalOp { pub enum LogicalOp {
/// The logical AND operator returns the value of the first operand if it can be coerced into `false`; /// The logical AND operator returns the value of the first operand if it can be coerced into `false`;

1
boa_ast/src/expression/operator/conditional.rs

@ -21,6 +21,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression /// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Conditional { pub struct Conditional {
condition: Box<Expression>, condition: Box<Expression>,

1
boa_ast/src/expression/operator/unary/mod.rs

@ -30,6 +30,7 @@ use crate::visitor::{VisitWith, Visitor, VisitorMut};
/// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression /// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary_operators /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary_operators
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Unary { pub struct Unary {
op: UnaryOp, op: UnaryOp,

1
boa_ast/src/expression/operator/unary/op.rs

@ -11,6 +11,7 @@
/// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression /// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UnaryOp { pub enum UnaryOp {
/// The increment operator increments (adds one to) its operand and returns a value. /// The increment operator increments (adds one to) its operand and returns a value.

3
boa_ast/src/expression/optional.rs

@ -9,6 +9,7 @@ use super::{access::PropertyAccessField, Expression};
/// List of valid operations in an [`Optional`] chain. /// List of valid operations in an [`Optional`] chain.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum OptionalOperationKind { pub enum OptionalOperationKind {
/// A property access (`a?.prop`). /// A property access (`a?.prop`).
@ -73,6 +74,7 @@ impl VisitWith for OptionalOperationKind {
/// In contrast, a non-shorted operation (`.prop`) will try to access the property, even if the target /// In contrast, a non-shorted operation (`.prop`) will try to access the property, even if the target
/// is `undefined` or `null`. /// is `undefined` or `null`.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct OptionalOperation { pub struct OptionalOperation {
kind: OptionalOperationKind, kind: OptionalOperationKind,
@ -175,6 +177,7 @@ impl VisitWith for OptionalOperation {
/// [spec]: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#prod-OptionalExpression /// [spec]: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#prod-OptionalExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Optional { pub struct Optional {
target: Box<Expression>, target: Box<Expression>,

1
boa_ast/src/expression/spread.rs

@ -23,6 +23,7 @@ use super::Expression;
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))] #[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Spread { pub struct Spread {
target: Box<Expression>, target: Box<Expression>,

1
boa_ast/src/expression/tagged_template.rs

@ -14,6 +14,7 @@ use super::Expression;
/// [moz]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates /// [moz]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates
/// [spec]: https://tc39.es/ecma262/#sec-tagged-templates /// [spec]: https://tc39.es/ecma262/#sec-tagged-templates
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct TaggedTemplate { pub struct TaggedTemplate {
tag: Box<Expression>, tag: Box<Expression>,

1
boa_ast/src/expression/yield.rs

@ -14,6 +14,7 @@ use super::Expression;
/// [spec]: https://tc39.es/ecma262/#prod-YieldExpression /// [spec]: https://tc39.es/ecma262/#prod-YieldExpression
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Yield { pub struct Yield {
target: Option<Box<Expression>>, target: Option<Box<Expression>>,

1
boa_ast/src/function/arrow_function.rs

@ -19,6 +19,7 @@ use super::FormalParameterList;
/// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction /// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ArrowFunction { pub struct ArrowFunction {
name: Option<Identifier>, name: Option<Identifier>,

1
boa_ast/src/function/async_arrow_function.rs

@ -19,6 +19,7 @@ use boa_interner::{Interner, ToIndentedString};
/// [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction /// [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct AsyncArrowFunction { pub struct AsyncArrowFunction {
name: Option<Identifier>, name: Option<Identifier>,

1
boa_ast/src/function/async_function.rs

@ -20,6 +20,7 @@ use super::FormalParameterList;
/// [spec]: https://tc39.es/ecma262/#sec-async-function-definitions /// [spec]: https://tc39.es/ecma262/#sec-async-function-definitions
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct AsyncFunction { pub struct AsyncFunction {
name: Option<Identifier>, name: Option<Identifier>,

1
boa_ast/src/function/async_generator.rs

@ -19,6 +19,7 @@ use super::FormalParameterList;
/// [spec]: https://tc39.es/ecma262/#sec-async-generator-function-definitions /// [spec]: https://tc39.es/ecma262/#sec-async-generator-function-definitions
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function* /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct AsyncGenerator { pub struct AsyncGenerator {
name: Option<Identifier>, name: Option<Identifier>,

2
boa_ast/src/function/class.rs

@ -22,6 +22,7 @@ use super::Function;
/// [spec]: https://tc39.es/ecma262/#sec-class-definitions /// [spec]: https://tc39.es/ecma262/#sec-class-definitions
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Class { pub struct Class {
name: Option<Identifier>, name: Option<Identifier>,
@ -406,6 +407,7 @@ impl VisitWith for Class {
/// ///
/// [spec]: https://tc39.es/ecma262/#prod-ClassElement /// [spec]: https://tc39.es/ecma262/#prod-ClassElement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ClassElement { pub enum ClassElement {
/// A method definition, including `get` and `set` accessors. /// A method definition, including `get` and `set` accessors.

1
boa_ast/src/function/generator.rs

@ -21,6 +21,7 @@ use super::FormalParameterList;
/// [spec]: https://tc39.es/ecma262/#sec-generator-function-definitions /// [spec]: https://tc39.es/ecma262/#sec-generator-function-definitions
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Generator { pub struct Generator {
name: Option<Identifier>, name: Option<Identifier>,

1
boa_ast/src/function/mod.rs

@ -57,6 +57,7 @@ use super::Declaration;
/// [spec]: https://tc39.es/ecma262/#sec-function-definitions /// [spec]: https://tc39.es/ecma262/#sec-function-definitions
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Function { pub struct Function {
name: Option<Identifier>, name: Option<Identifier>,

9
boa_ast/src/function/parameters.rs

@ -166,6 +166,14 @@ impl VisitWith for FormalParameterList {
} }
} }
#[cfg(feature = "fuzz")]
impl<'a> arbitrary::Arbitrary<'a> for FormalParameterList {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let params: Vec<FormalParameter> = u.arbitrary()?;
Ok(Self::from(params))
}
}
bitflags! { bitflags! {
/// Flags for a [`FormalParameterList`]. /// Flags for a [`FormalParameterList`].
#[allow(clippy::unsafe_derive_deserialize)] #[allow(clippy::unsafe_derive_deserialize)]
@ -206,6 +214,7 @@ impl Default for FormalParameterListFlags {
/// [spec]: https://tc39.es/ecma262/#prod-FormalParameter /// [spec]: https://tc39.es/ecma262/#prod-FormalParameter
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Missing_formal_parameter /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Missing_formal_parameter
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct FormalParameter { pub struct FormalParameter {
variable: Variable, variable: Variable,

5
boa_ast/src/pattern.rs

@ -36,6 +36,7 @@ use core::ops::ControlFlow;
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Pattern { pub enum Pattern {
/// An object pattern (`let {a, b, c} = object`). /// An object pattern (`let {a, b, c} = object`).
@ -108,6 +109,7 @@ impl VisitWith for Pattern {
/// [spec1]: https://tc39.es/ecma262/#prod-ObjectBindingPattern /// [spec1]: https://tc39.es/ecma262/#prod-ObjectBindingPattern
/// [spec2]: https://tc39.es/ecma262/#prod-ObjectAssignmentPattern /// [spec2]: https://tc39.es/ecma262/#prod-ObjectAssignmentPattern
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ObjectPattern(Box<[ObjectPatternElement]>); pub struct ObjectPattern(Box<[ObjectPatternElement]>);
@ -196,6 +198,7 @@ impl VisitWith for ObjectPattern {
/// [spec1]: https://tc39.es/ecma262/#prod-ArrayBindingPattern /// [spec1]: https://tc39.es/ecma262/#prod-ArrayBindingPattern
/// [spec2]: https://tc39.es/ecma262/#prod-ArrayAssignmentPattern /// [spec2]: https://tc39.es/ecma262/#prod-ArrayAssignmentPattern
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ArrayPattern(Box<[ArrayPatternElement]>); pub struct ArrayPattern(Box<[ArrayPatternElement]>);
@ -270,6 +273,7 @@ impl VisitWith for ArrayPattern {
/// [spec1]: https://tc39.es/ecma262/#prod-BindingProperty /// [spec1]: https://tc39.es/ecma262/#prod-BindingProperty
/// [spec2]: https://tc39.es/ecma262/#prod-AssignmentProperty /// [spec2]: https://tc39.es/ecma262/#prod-AssignmentProperty
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ObjectPatternElement { pub enum ObjectPatternElement {
/// SingleName represents one of the following properties: /// SingleName represents one of the following properties:
@ -569,6 +573,7 @@ impl VisitWith for ObjectPatternElement {
/// [spec1]: https://tc39.es/ecma262/#prod-BindingElement /// [spec1]: https://tc39.es/ecma262/#prod-BindingElement
/// [spec2]: https://tc39.es/ecma262/#prod-AssignmentElement /// [spec2]: https://tc39.es/ecma262/#prod-AssignmentElement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ArrayPatternElement { pub enum ArrayPatternElement {
/// Elision represents the elision of an item in the array binding pattern. /// Elision represents the elision of an item in the array binding pattern.

3
boa_ast/src/property.rs

@ -25,6 +25,7 @@ use super::{
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/property/JavaScript /// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/property/JavaScript
// TODO: Support all features: https://tc39.es/ecma262/#prod-PropertyDefinition // TODO: Support all features: https://tc39.es/ecma262/#prod-PropertyDefinition
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum PropertyDefinition { pub enum PropertyDefinition {
/// Puts a variable into an object. /// Puts a variable into an object.
@ -137,6 +138,7 @@ impl VisitWith for PropertyDefinition {
/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum MethodDefinition { pub enum MethodDefinition {
/// The `get` syntax binds an object property to a function that will be called when that property is looked up. /// The `get` syntax binds an object property to a function that will be called when that property is looked up.
@ -248,6 +250,7 @@ impl VisitWith for MethodDefinition {
/// ///
/// [spec]: https://tc39.es/ecma262/#prod-PropertyName /// [spec]: https://tc39.es/ecma262/#prod-PropertyName
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum PropertyName { pub enum PropertyName {
/// A `Literal` property name can be either an identifier, a string or a numeric literal. /// A `Literal` property name can be either an identifier, a string or a numeric literal.

1
boa_ast/src/statement/block.rs

@ -23,6 +23,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-BlockStatement /// [spec]: https://tc39.es/ecma262/#prod-BlockStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq, Default)] #[derive(Clone, Debug, PartialEq, Default)]
pub struct Block { pub struct Block {
#[cfg_attr(feature = "serde", serde(flatten))] #[cfg_attr(feature = "serde", serde(flatten))]

1
boa_ast/src/statement/if.rs

@ -26,6 +26,7 @@ use core::ops::ControlFlow;
/// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/falsy /// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/falsy
/// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions /// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct If { pub struct If {
condition: Expression, condition: Expression,

1
boa_ast/src/statement/iteration/break.rs

@ -19,6 +19,7 @@ use crate::Statement;
/// [spec]: https://tc39.es/ecma262/#prod-BreakStatement /// [spec]: https://tc39.es/ecma262/#prod-BreakStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Break { pub struct Break {
label: Option<Sym>, label: Option<Sym>,

1
boa_ast/src/statement/iteration/continue.rs

@ -17,6 +17,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement /// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Continue { pub struct Continue {
label: Option<Sym>, label: Option<Sym>,

1
boa_ast/src/statement/iteration/do_while_loop.rs

@ -20,6 +20,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#sec-do-while-statement /// [spec]: https://tc39.es/ecma262/#sec-do-while-statement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct DoWhileLoop { pub struct DoWhileLoop {
body: Box<Statement>, body: Box<Statement>,

1
boa_ast/src/statement/iteration/for_in_loop.rs

@ -15,6 +15,7 @@ use core::ops::ControlFlow;
/// [forin]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in /// [forin]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement /// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ForInLoop { pub struct ForInLoop {
initializer: IterableLoopInitializer, initializer: IterableLoopInitializer,

3
boa_ast/src/statement/iteration/for_loop.rs

@ -19,6 +19,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ForDeclaration /// [spec]: https://tc39.es/ecma262/#prod-ForDeclaration
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ForLoop { pub struct ForLoop {
#[cfg_attr(feature = "serde", serde(flatten))] #[cfg_attr(feature = "serde", serde(flatten))]
@ -135,6 +136,7 @@ impl VisitWith for ForLoop {
/// Inner structure to avoid multiple indirections in the heap. /// Inner structure to avoid multiple indirections in the heap.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct InnerForLoop { struct InnerForLoop {
init: Option<ForLoopInitializer>, init: Option<ForLoopInitializer>,
@ -194,6 +196,7 @@ impl InnerForLoop {
/// ///
/// [spec]: https://tc39.es/ecma262/#prod-ForStatement /// [spec]: https://tc39.es/ecma262/#prod-ForStatement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ForLoopInitializer { pub enum ForLoopInitializer {
/// An expression initializer. /// An expression initializer.

1
boa_ast/src/statement/iteration/for_of_loop.rs

@ -20,6 +20,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement /// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
/// [forawait]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of /// [forawait]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ForOfLoop { pub struct ForOfLoop {
init: IterableLoopInitializer, init: IterableLoopInitializer,

1
boa_ast/src/statement/iteration/mod.rs

@ -35,6 +35,7 @@ use boa_interner::{Interner, ToInternedString};
/// ///
/// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement /// [spec]: https://tc39.es/ecma262/#prod-ForInOfStatement
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum IterableLoopInitializer { pub enum IterableLoopInitializer {
/// An already declared variable. /// An already declared variable.

1
boa_ast/src/statement/iteration/while_loop.rs

@ -19,6 +19,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement /// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct WhileLoop { pub struct WhileLoop {
condition: Expression, condition: Expression,

2
boa_ast/src/statement/labelled.rs

@ -17,6 +17,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-LabelledItem /// [spec]: https://tc39.es/ecma262/#prod-LabelledItem
/// [label-fn]: https://tc39.es/ecma262/#sec-labelled-function-declarations /// [label-fn]: https://tc39.es/ecma262/#sec-labelled-function-declarations
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum LabelledItem { pub enum LabelledItem {
/// A labelled [`Function`]. /// A labelled [`Function`].
@ -81,6 +82,7 @@ impl VisitWith for LabelledItem {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-labelled-statements /// [spec]: https://tc39.es/ecma262/#sec-labelled-statements
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Labelled { pub struct Labelled {
item: Box<LabelledItem>, item: Box<LabelledItem>,

1
boa_ast/src/statement/mod.rs

@ -38,6 +38,7 @@ use super::{declaration::VarDeclaration, expression::Expression};
/// ///
/// See the [module level documentation][self] for more information. /// See the [module level documentation][self] for more information.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Statement { pub enum Statement {
/// See [`Block`]. /// See [`Block`].

1
boa_ast/src/statement/return.rs

@ -24,6 +24,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement /// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Return { pub struct Return {
target: Option<Expression>, target: Option<Expression>,

2
boa_ast/src/statement/switch.rs

@ -19,6 +19,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-CaseClause /// [spec]: https://tc39.es/ecma262/#prod-CaseClause
/// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy /// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Case { pub struct Case {
condition: Expression, condition: Expression,
@ -83,6 +84,7 @@ impl VisitWith for Case {
/// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement /// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Switch { pub struct Switch {
val: Expression, val: Expression,

1
boa_ast/src/statement/throw.rs

@ -21,6 +21,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-ThrowStatement /// [spec]: https://tc39.es/ecma262/#prod-ThrowStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Throw { pub struct Throw {
target: Expression, target: Expression,

4
boa_ast/src/statement/try.rs

@ -23,6 +23,7 @@ use core::ops::ControlFlow;
/// [spec]: https://tc39.es/ecma262/#prod-TryStatement /// [spec]: https://tc39.es/ecma262/#prod-TryStatement
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Try { pub struct Try {
block: Block, block: Block,
@ -31,6 +32,7 @@ pub struct Try {
/// The type of error handler in a [`Try`] statement. /// The type of error handler in a [`Try`] statement.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ErrorHandler { pub enum ErrorHandler {
/// A [`Catch`] error handler. /// A [`Catch`] error handler.
@ -137,6 +139,7 @@ impl VisitWith for Try {
/// Catch block. /// Catch block.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Catch { pub struct Catch {
parameter: Option<Binding>, parameter: Option<Binding>,
@ -205,6 +208,7 @@ impl VisitWith for Catch {
/// Finally block. /// Finally block.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Finally { pub struct Finally {
block: Block, block: Block,

11
boa_ast/src/statement_list.rs

@ -18,6 +18,7 @@ use std::cmp::Ordering;
/// ///
/// [spec]: https://tc39.es/ecma262/#prod-StatementListItem /// [spec]: https://tc39.es/ecma262/#prod-StatementListItem
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum StatementListItem { pub enum StatementListItem {
/// See [`Statement`]. /// See [`Statement`].
@ -198,3 +199,13 @@ impl VisitWith for StatementList {
ControlFlow::Continue(()) ControlFlow::Continue(())
} }
} }
#[cfg(feature = "fuzz")]
impl<'a> arbitrary::Arbitrary<'a> for StatementList {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(Self {
statements: u.arbitrary()?,
strict: false, // disable strictness; this is *not* in source data
})
}
}

2
boa_engine/Cargo.toml

@ -24,6 +24,8 @@ intl = [
"dep:sys-locale" "dep:sys-locale"
] ]
fuzz = ["boa_ast/fuzz", "boa_interner/fuzz"]
# Enable Boa's WHATWG console object implementation. # Enable Boa's WHATWG console object implementation.
console = [] console = []

5
boa_interner/Cargo.toml

@ -10,6 +10,9 @@ license.workspace = true
repository.workspace = true repository.workspace = true
rust-version.workspace = true rust-version.workspace = true
[features]
fuzz = ["arbitrary"]
[dependencies] [dependencies]
boa_macros.workspace = true boa_macros.workspace = true
serde = { version = "1.0.147", features = ["derive"], optional = true } serde = { version = "1.0.147", features = ["derive"], optional = true }
@ -18,4 +21,4 @@ rustc-hash = "1.1.0"
static_assertions = "1.1.0" static_assertions = "1.1.0"
once_cell = "1.16.0" once_cell = "1.16.0"
indexmap = "1.9.1" indexmap = "1.9.1"
arbitrary = { version = "1", optional = true, features = ["derive"] }

3
boa_interner/src/sym.rs

@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))] #[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
#[allow(clippy::unsafe_derive_deserialize)] #[allow(clippy::unsafe_derive_deserialize)]
pub struct Sym { pub struct Sym {
value: NonZeroUsize, value: NonZeroUsize,
@ -127,7 +128,7 @@ impl Sym {
/// Returns the internal value of the [`Sym`] /// Returns the internal value of the [`Sym`]
#[inline] #[inline]
pub(super) const fn get(self) -> usize { pub const fn get(self) -> usize {
self.value.get() self.value.get()
} }
} }

4
fuzz/.gitignore vendored

@ -0,0 +1,4 @@
target
corpus
artifacts
coverage

831
fuzz/Cargo.lock generated

@ -0,0 +1,831 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "arbitrary"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "boa_ast"
version = "0.16.0"
dependencies = [
"arbitrary",
"bitflags",
"boa_interner",
"boa_macros",
"num-bigint",
"rustc-hash",
]
[[package]]
name = "boa_engine"
version = "0.16.0"
dependencies = [
"bitflags",
"boa_ast",
"boa_gc",
"boa_interner",
"boa_macros",
"boa_parser",
"boa_profiler",
"boa_unicode",
"chrono",
"dyn-clone",
"fast-float",
"gc",
"indexmap",
"num-bigint",
"num-integer",
"num-traits",
"once_cell",
"rand",
"regress",
"rustc-hash",
"ryu-js",
"serde",
"serde_json",
"sptr",
"static_assertions",
"tap",
"thiserror",
"unicode-normalization",
]
[[package]]
name = "boa_fuzz"
version = "0.0.0"
dependencies = [
"boa_ast",
"boa_engine",
"boa_interner",
"boa_parser",
"libfuzzer-sys",
]
[[package]]
name = "boa_gc"
version = "0.16.0"
dependencies = [
"gc",
]
[[package]]
name = "boa_interner"
version = "0.16.0"
dependencies = [
"arbitrary",
"boa_macros",
"indexmap",
"once_cell",
"phf",
"rustc-hash",
"static_assertions",
]
[[package]]
name = "boa_macros"
version = "0.16.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "boa_parser"
version = "0.16.0"
dependencies = [
"bitflags",
"boa_ast",
"boa_interner",
"boa_macros",
"boa_profiler",
"boa_unicode",
"fast-float",
"num-bigint",
"num-traits",
"rustc-hash",
]
[[package]]
name = "boa_profiler"
version = "0.16.0"
[[package]]
name = "boa_unicode"
version = "0.16.0"
dependencies = [
"unicode-general-category",
]
[[package]]
name = "bumpalo"
version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "cc"
version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574"
dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
"time",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cxx"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"proc-macro2",
"quote",
"scratch",
"syn",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a"
[[package]]
name = "cxxbridge-macro"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_arbitrary"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4903dff04948f22033ca30232ab8eca2c3fc4c913a8b6a34ee5199699814817f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "dyn-clone"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2"
[[package]]
name = "fast-float"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c"
[[package]]
name = "gc"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3edaac0f5832202ebc99520cb77c932248010c4645d20be1dc62d6579f5b3752"
dependencies = [
"gc_derive",
]
[[package]]
name = "gc_derive"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60df8444f094ff7885631d80e78eb7d88c3c2361a98daaabb06256e4500db941"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "getrandom"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "iana-time-zone"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
dependencies = [
"cxx",
"cxx-build",
]
[[package]]
name = "indexmap"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "jobserver"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "libfuzzer-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8fff891139ee62800da71b7fd5b508d570b9ad95e614a53c6f453ca08366038"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]]
name = "link-cplusplus"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
dependencies = [
"cc",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"arbitrary",
"autocfg",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "phf"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
dependencies = [
"phf_macros",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_macros"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
dependencies = [
"siphasher",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regress"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a92ff21fe8026ce3f2627faaf43606f0b67b014dbc9ccf027181a804f75d92e"
dependencies = [
"memchr",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "ryu-js"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f"
[[package]]
name = "scratch"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
[[package]]
name = "serde"
version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "siphasher"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "sptr"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "unicode-general-category"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

29
fuzz/Cargo.toml

@ -0,0 +1,29 @@
[package]
name = "boa_fuzz"
version = "0.0.0"
publish = false
edition = "2021"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
boa_ast = { path = "../boa_ast", features = ["fuzz"] }
boa_engine = { path = "../boa_engine", features = ["fuzz"] }
boa_interner = { path = "../boa_interner", features = ["fuzz"] }
boa_parser = { path = "../boa_parser" }
# Prevent this from interfering with workspaces
[workspace]
members = ["."]
[profile.release]
debug = 1
[[bin]]
name = "parser-idempotency"
path = "fuzz_targets/parser-idempotency.rs"
test = false
doc = false

37
fuzz/README.md

@ -0,0 +1,37 @@
# boa_engine-fuzz
This directory contains fuzzers which can be used to automatically identify faults present in Boa. All the fuzzers in
this directory are [grammar-aware](https://www.fuzzingbook.org/html/Grammars.html) (based on
[Arbitrary](https://docs.rs/arbitrary/latest/arbitrary/)) and coverage-guided. See [common.rs](fuzz/fuzz_targets/common.rs)
for implementation specifics.
You can run any fuzzer you wish with the following command (replacing `your-fuzzer` with a fuzzer availble in
fuzz_targets, e.g. `parser-idempotency`):
```bash
cargo fuzz run -s none your-fuzzer
```
Note that you may wish to use a different sanitizer option (`-s`) according to what kind of issue you're looking for.
Refer to the [cargo-fuzz book](https://rust-fuzz.github.io/book/cargo-fuzz.html) for details on how to select a
sanitizer and other flags.
## Parser Fuzzer
The parser fuzzer, located in [parser-idempotency.rs](fuzz/fuzz_targets/parser-idempotency.rs), identifies
correctness issues in both the parser and the AST-to-source conversion process (e.g., via `to_interned_string`) by
searching for inputs which are not idempotent over parsing and conversion back to source. It does this by doing the
following:
1. Generate an arbitrary AST
2. Convert that AST to source code with `to_interned_string`; we'll call this the "original source"
3. Parse the original source into an AST; we'll call this the "first AST"
- Arbitrary ASTs aren't guaranteed to be parseable; to avoid errors caused by this, we discard errors here.
4. Convert the first AST to source code with `to_interned_string`; we'll call this the "first source"
5. Parse the first source into an AST; we'll call this the "second AST"
- Since the original source was parseable, the first source must be parseable; emit any errors parsing produces.
6. Compare the first AST and the second AST. If they are not equal, emit an error.
- An error here indicates that either the parser or the AST-to-source conversion lost information or added incorrect
information, as the inputs parsed between the two should be the same.
In this way, this fuzzer can identify correctness issues present in the parser.

74
fuzz/fuzz_targets/common.rs

@ -0,0 +1,74 @@
use boa_ast::{
visitor::{VisitWith, VisitorMut},
Expression, StatementList,
};
use boa_interner::{Interner, Sym};
use libfuzzer_sys::arbitrary;
use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};
use std::fmt::{Debug, Formatter};
use std::ops::ControlFlow;
/// Context for performing fuzzing. This structure contains both the generated AST as well as the
/// context used to resolve the symbols therein.
pub struct FuzzData {
pub interner: Interner,
pub ast: StatementList,
}
impl<'a> Arbitrary<'a> for FuzzData {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let mut interner = Interner::with_capacity(8);
let mut syms_available = Vec::with_capacity(8);
for c in 'a'..='h' {
syms_available.push(interner.get_or_intern(&*String::from(c)));
}
let mut ast = StatementList::arbitrary(u)?;
struct FuzzReplacer<'a, 's, 'u> {
syms: &'s [Sym],
u: &'u mut Unstructured<'a>,
}
impl<'a, 's, 'u, 'ast> VisitorMut<'ast> for FuzzReplacer<'a, 's, 'u> {
type BreakTy = arbitrary::Error;
// TODO arbitrary strings literals?
fn visit_expression_mut(
&mut self,
node: &'ast mut Expression,
) -> ControlFlow<Self::BreakTy> {
if matches!(node, Expression::FormalParameterList(_)) {
match self.u.arbitrary() {
Ok(id) => *node = Expression::Identifier(id),
Err(e) => return ControlFlow::Break(e),
}
}
node.visit_with_mut(self)
}
fn visit_sym_mut(&mut self, node: &'ast mut Sym) -> ControlFlow<Self::BreakTy> {
*node = self.syms[node.get() % self.syms.len()];
ControlFlow::Continue(())
}
}
let mut replacer = FuzzReplacer {
syms: &syms_available,
u,
};
if let ControlFlow::Break(e) = replacer.visit_statement_list_mut(&mut ast) {
Err(e)
} else {
Ok(Self { interner, ast })
}
}
}
impl Debug for FuzzData {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FuzzData")
.field("ast", &self.ast)
.finish_non_exhaustive()
}
}

74
fuzz/fuzz_targets/parser-idempotency.rs

@ -0,0 +1,74 @@
#![no_main]
mod common;
use crate::common::FuzzData;
use boa_interner::ToInternedString;
use boa_parser::Parser;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::Corpus;
use std::error::Error;
use std::io::Cursor;
/// Fuzzer test harness. This function accepts the arbitrary AST and performs the fuzzing operation.
///
/// See [README.md](../README.md) for details on the design of this fuzzer.
fn do_fuzz(mut data: FuzzData) -> Result<(), Box<dyn Error>> {
let original = data.ast.to_interned_string(&data.interner);
let mut parser = Parser::new(Cursor::new(&original));
let before = data.interner.len();
// For a variety of reasons, we may not actually produce valid code here (e.g., nameless function).
// Fail fast and only make the next checks if we were valid.
if let Ok(first) = parser.parse_all(&mut data.interner) {
let after_first = data.interner.len();
let first_interned = first.to_interned_string(&data.interner);
assert_eq!(
before,
after_first,
"The number of interned symbols changed; a new string was read.\nBefore:\n{}\nAfter:\n{}\nBefore (AST):\n{:#?}\nAfter (AST):\n{:#?}",
original,
first_interned,
data.ast,
first
);
let mut parser = Parser::new(Cursor::new(&first_interned));
// Now, we most assuredly should produce valid code. It has already gone through a first pass.
let second = parser
.parse_all(&mut data.interner)
.expect("Could not parse the first-pass interned copy.");
let second_interned = second.to_interned_string(&data.interner);
let after_second = data.interner.len();
assert_eq!(
after_first,
after_second,
"The number of interned symbols changed; a new string was read.\nBefore:\n{}\nAfter:\n{}\nBefore (AST):\n{:#?}\nAfter (AST):\n{:#?}",
first_interned,
second_interned,
first,
second
);
assert_eq!(
first,
second,
"Expected the same AST after two intern passes, but found dissimilar.\nOriginal:\n{}\nFirst:\n{}\nSecond:\n{}",
original,
first_interned,
second_interned,
);
}
Ok(())
}
// Fuzz harness wrapper to expose it to libfuzzer (and thus cargo-fuzz)
// See: https://rust-fuzz.github.io/book/cargo-fuzz.html
fuzz_target!(|data: FuzzData| -> Corpus {
if do_fuzz(data).is_ok() {
Corpus::Keep
} else {
Corpus::Reject
}
});
Loading…
Cancel
Save