go.ketch.com/lib/goja@v0.0.1/tc39_test.go (about)

     1  package goja
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"gopkg.in/yaml.v3"
     7  	"io"
     8  	"os"
     9  	"path"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  	"testing"
    14  	"time"
    15  )
    16  
    17  const (
    18  	tc39BASE = "testdata/test262"
    19  )
    20  
    21  var (
    22  	invalidFormatError = errors.New("Invalid file format")
    23  
    24  	ignorableTestError = newSymbol(stringEmpty)
    25  )
    26  
    27  var (
    28  	skipPrefixes prefixList
    29  
    30  	skipList = map[string]bool{
    31  
    32  		// out-of-date (https://github.com/tc39/test262/issues/3407)
    33  		"test/language/expressions/prefix-increment/S11.4.4_A6_T3.js":        true,
    34  		"test/language/expressions/prefix-increment/S11.4.4_A6_T2.js":        true,
    35  		"test/language/expressions/prefix-increment/S11.4.4_A6_T1.js":        true,
    36  		"test/language/expressions/prefix-decrement/S11.4.5_A6_T3.js":        true,
    37  		"test/language/expressions/prefix-decrement/S11.4.5_A6_T2.js":        true,
    38  		"test/language/expressions/prefix-decrement/S11.4.5_A6_T1.js":        true,
    39  		"test/language/expressions/postfix-increment/S11.3.1_A6_T3.js":       true,
    40  		"test/language/expressions/postfix-increment/S11.3.1_A6_T2.js":       true,
    41  		"test/language/expressions/postfix-increment/S11.3.1_A6_T1.js":       true,
    42  		"test/language/expressions/postfix-decrement/S11.3.2_A6_T3.js":       true,
    43  		"test/language/expressions/postfix-decrement/S11.3.2_A6_T2.js":       true,
    44  		"test/language/expressions/postfix-decrement/S11.3.2_A6_T1.js":       true,
    45  		"test/language/expressions/compound-assignment/S11.13.2_A7.1_T4.js":  true,
    46  		"test/language/expressions/compound-assignment/S11.13.2_A7.1_T2.js":  true,
    47  		"test/language/expressions/compound-assignment/S11.13.2_A7.1_T1.js":  true,
    48  		"test/language/expressions/compound-assignment/S11.13.2_A7.11_T4.js": true,
    49  		"test/language/expressions/compound-assignment/S11.13.2_A7.11_T2.js": true,
    50  		"test/language/expressions/compound-assignment/S11.13.2_A7.11_T1.js": true,
    51  		"test/language/expressions/compound-assignment/S11.13.2_A7.10_T4.js": true,
    52  		"test/language/expressions/compound-assignment/S11.13.2_A7.10_T2.js": true,
    53  		"test/language/expressions/compound-assignment/S11.13.2_A7.10_T1.js": true,
    54  		"test/language/expressions/compound-assignment/S11.13.2_A7.9_T4.js":  true,
    55  		"test/language/expressions/compound-assignment/S11.13.2_A7.9_T2.js":  true,
    56  		"test/language/expressions/compound-assignment/S11.13.2_A7.9_T1.js":  true,
    57  		"test/language/expressions/compound-assignment/S11.13.2_A7.8_T4.js":  true,
    58  		"test/language/expressions/compound-assignment/S11.13.2_A7.8_T2.js":  true,
    59  		"test/language/expressions/compound-assignment/S11.13.2_A7.8_T1.js":  true,
    60  		"test/language/expressions/compound-assignment/S11.13.2_A7.7_T4.js":  true,
    61  		"test/language/expressions/compound-assignment/S11.13.2_A7.7_T2.js":  true,
    62  		"test/language/expressions/compound-assignment/S11.13.2_A7.7_T1.js":  true,
    63  		"test/language/expressions/compound-assignment/S11.13.2_A7.6_T4.js":  true,
    64  		"test/language/expressions/compound-assignment/S11.13.2_A7.6_T2.js":  true,
    65  		"test/language/expressions/compound-assignment/S11.13.2_A7.6_T1.js":  true,
    66  		"test/language/expressions/compound-assignment/S11.13.2_A7.5_T4.js":  true,
    67  		"test/language/expressions/compound-assignment/S11.13.2_A7.5_T2.js":  true,
    68  		"test/language/expressions/compound-assignment/S11.13.2_A7.5_T1.js":  true,
    69  		"test/language/expressions/compound-assignment/S11.13.2_A7.4_T4.js":  true,
    70  		"test/language/expressions/compound-assignment/S11.13.2_A7.4_T2.js":  true,
    71  		"test/language/expressions/compound-assignment/S11.13.2_A7.4_T1.js":  true,
    72  		"test/language/expressions/compound-assignment/S11.13.2_A7.3_T4.js":  true,
    73  		"test/language/expressions/compound-assignment/S11.13.2_A7.3_T2.js":  true,
    74  		"test/language/expressions/compound-assignment/S11.13.2_A7.3_T1.js":  true,
    75  		"test/language/expressions/compound-assignment/S11.13.2_A7.2_T4.js":  true,
    76  		"test/language/expressions/compound-assignment/S11.13.2_A7.2_T2.js":  true,
    77  		"test/language/expressions/compound-assignment/S11.13.2_A7.2_T1.js":  true,
    78  		"test/language/expressions/assignment/S11.13.1_A7_T3.js":             true,
    79  
    80  		// timezone
    81  		"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-8.js":  true,
    82  		"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-9.js":  true,
    83  		"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-10.js": true,
    84  
    85  		// floating point date calculations
    86  		"test/built-ins/Date/UTC/fp-evaluation-order.js": true,
    87  
    88  		// quantifier integer limit in regexp
    89  		"test/built-ins/RegExp/quantifier-integer-limit.js": true,
    90  
    91  		// GetFunctionRealm
    92  		"test/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js": true,
    93  
    94  		// Uses deprecated __lookupGetter__/__lookupSetter__
    95  		"test/language/expressions/class/elements/private-getter-is-not-a-own-property.js": true,
    96  		"test/language/expressions/class/elements/private-setter-is-not-a-own-property.js": true,
    97  		"test/language/statements/class/elements/private-setter-is-not-a-own-property.js":  true,
    98  		"test/language/statements/class/elements/private-getter-is-not-a-own-property.js":  true,
    99  
   100  		// restricted unicode regexp syntax
   101  		"test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js":         true,
   102  		"test/built-ins/RegExp/unicode_restricted_octal_escape.js":                   true,
   103  		"test/built-ins/RegExp/unicode_restricted_incomple_quantifier.js":            true,
   104  		"test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js":          true,
   105  		"test/built-ins/RegExp/unicode_restricted_identity_escape_x.js":              true,
   106  		"test/built-ins/RegExp/unicode_restricted_identity_escape_u.js":              true,
   107  		"test/built-ins/RegExp/unicode_restricted_identity_escape_c.js":              true,
   108  		"test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js":          true,
   109  		"test/built-ins/RegExp/unicode_restricted_identity_escape.js":                true,
   110  		"test/built-ins/RegExp/unicode_restricted_brackets.js":                       true,
   111  		"test/built-ins/RegExp/unicode_restricted_character_class_escape.js":         true,
   112  		"test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js": true,
   113  
   114  		// Because goja parser works in UTF-8 it is not possible to pass strings containing invalid UTF-16 code points.
   115  		// This is mitigated by escaping them as \uXXXX, however because of this the RegExp source becomes
   116  		// `\uXXXX` instead of `<the actual UTF-16 code point of XXXX>`.
   117  		// The resulting RegExp will work exactly the same, but it causes these two tests to fail.
   118  		"test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js":  true,
   119  		"test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js": true,
   120  		"test/language/literals/regexp/S7.8.5_A1.4_T2.js":            true,
   121  		"test/language/literals/regexp/S7.8.5_A1.1_T2.js":            true,
   122  		"test/language/literals/regexp/S7.8.5_A2.1_T2.js":            true,
   123  		"test/language/literals/regexp/S7.8.5_A2.4_T2.js":            true,
   124  
   125  		// generators
   126  		"test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js":                                                        true,
   127  		"test/language/statements/switch/scope-lex-generator.js":                                                                      true,
   128  		"test/language/expressions/in/rhs-yield-present.js":                                                                           true,
   129  		"test/language/expressions/object/cpn-obj-lit-computed-property-name-from-yield-expression.js":                                true,
   130  		"test/language/expressions/object/cpn-obj-lit-computed-property-name-from-generator-function-declaration.js":                  true,
   131  		"test/built-ins/TypedArrayConstructors/ctors/object-arg/as-generator-iterable-returns.js":                                     true,
   132  		"test/built-ins/Object/seal/seal-generatorfunction.js":                                                                        true,
   133  		"test/language/statements/class/syntax/class-declaration-computed-method-generator-definition.js":                             true,
   134  		"test/language/statements/class/cpn-class-decl-fields-methods-computed-property-name-from-yield-expression.js":                true,
   135  		"test/language/statements/class/cpn-class-decl-fields-methods-computed-property-name-from-generator-function-declaration.js":  true,
   136  		"test/language/statements/class/cpn-class-decl-fields-computed-property-name-from-yield-expression.js":                        true,
   137  		"test/language/statements/class/cpn-class-decl-fields-computed-property-name-from-generator-function-declaration.js":          true,
   138  		"test/language/statements/class/cpn-class-decl-computed-property-name-from-yield-expression.js":                               true,
   139  		"test/language/statements/class/cpn-class-decl-computed-property-name-from-generator-function-declaration.js":                 true,
   140  		"test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-yield-expression.js":                     true,
   141  		"test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-generator-function-declaration.js":       true,
   142  		"test/language/expressions/class/cpn-class-expr-fields-computed-property-name-from-yield-expression.js":                       true,
   143  		"test/language/expressions/class/cpn-class-expr-fields-computed-property-name-from-generator-function-declaration.js":         true,
   144  		"test/language/expressions/class/cpn-class-expr-computed-property-name-from-yield-expression.js":                              true,
   145  		"test/language/expressions/class/cpn-class-expr-computed-property-name-from-generator-function-declaration.js":                true,
   146  		"test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-yield-expression.js":                    true,
   147  		"test/language/expressions/class/cpn-class-expr-fields-methods-computed-property-name-from-yield-expression.js":               true,
   148  		"test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-generator-function-declaration.js":      true,
   149  		"test/language/expressions/class/cpn-class-expr-fields-methods-computed-property-name-from-generator-function-declaration.js": true,
   150  		"test/language/statements/class/static-init-arguments-methods.js":                                                             true,
   151  		"test/language/statements/class/static-init-arguments-functions.js":                                                           true,
   152  		"test/language/expressions/object/method-definition/static-init-await-reference-generator.js":                                 true,
   153  		"test/language/expressions/generators/static-init-await-binding.js":                                                           true,
   154  		"test/language/expressions/generators/static-init-await-reference.js":                                                         true,
   155  		"test/language/expressions/optional-chaining/member-expression.js":                                                            true,
   156  		"test/language/expressions/class/elements/private-generator-method-name.js":                                                   true,
   157  		"test/language/statements/class/elements/private-generator-method-name.js":                                                    true,
   158  		"test/language/expressions/in/private-field-rhs-yield-present.js":                                                             true,
   159  		"test/language/expressions/class/elements/private-static-generator-method-name.js":                                            true,
   160  		"test/language/expressions/class/elements/private-static-async-generator-method-name.js":                                      true,
   161  		"test/language/computed-property-names/class/static/generator-prototype.js":                                                   true,
   162  		"test/language/computed-property-names/class/method/constructor-can-be-generator.js":                                          true,
   163  		"test/language/computed-property-names/class/static/generator-constructor.js":                                                 true,
   164  		"test/language/computed-property-names/class/method/generator.js":                                                             true,
   165  		"test/language/computed-property-names/object/method/generator.js":                                                            true,
   166  		"test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js":                     true,
   167  		"test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js":                      true,
   168  
   169  		// async
   170  		"test/language/eval-code/direct/async-func-decl-a-preceding-parameter-is-named-arguments-declare-arguments-and-assign.js":      true,
   171  		"test/language/statements/switch/scope-lex-async-generator.js":                                                                 true,
   172  		"test/language/statements/switch/scope-lex-async-function.js":                                                                  true,
   173  		"test/language/statements/for-of/head-lhs-async-invalid.js":                                                                    true,
   174  		"test/language/expressions/object/cpn-obj-lit-computed-property-name-from-async-arrow-function-expression.js":                  true,
   175  		"test/language/expressions/object/cpn-obj-lit-computed-property-name-from-await-expression.js":                                 true,
   176  		"test/language/statements/async-function/evaluation-body.js":                                                                   true,
   177  		"test/language/expressions/object/method-definition/object-method-returns-promise.js":                                          true,
   178  		"test/language/expressions/object/method-definition/async-super-call-param.js":                                                 true,
   179  		"test/language/expressions/object/method-definition/async-super-call-body.js":                                                  true,
   180  		"test/built-ins/Object/seal/seal-asyncgeneratorfunction.js":                                                                    true,
   181  		"test/built-ins/Object/seal/seal-asyncfunction.js":                                                                             true,
   182  		"test/built-ins/Object/seal/seal-asyncarrowfunction.js":                                                                        true,
   183  		"test/language/statements/for/head-init-async-of.js":                                                                           true,
   184  		"test/language/reserved-words/await-module.js":                                                                                 true,
   185  		"test/language/expressions/optional-chaining/optional-chain-async-square-brackets.js":                                          true,
   186  		"test/language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js":                           true,
   187  		"test/language/expressions/optional-chaining/member-expression-async-this.js":                                                  true,
   188  		"test/language/expressions/optional-chaining/member-expression-async-literal.js":                                               true,
   189  		"test/language/expressions/optional-chaining/member-expression-async-identifier.js":                                            true,
   190  		"test/language/expressions/optional-chaining/iteration-statement-for-await-of.js":                                              true,
   191  		"test/language/statements/class/cpn-class-decl-fields-methods-computed-property-name-from-async-arrow-function-expression.js":  true,
   192  		"test/language/statements/class/cpn-class-decl-fields-computed-property-name-from-async-arrow-function-expression.js":          true,
   193  		"test/language/statements/class/cpn-class-decl-computed-property-name-from-async-arrow-function-expression.js":                 true,
   194  		"test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-async-arrow-function-expression.js":       true,
   195  		"test/language/expressions/class/cpn-class-expr-fields-computed-property-name-from-async-arrow-function-expression.js":         true,
   196  		"test/language/expressions/class/cpn-class-expr-computed-property-name-from-async-arrow-function-expression.js":                true,
   197  		"test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-async-arrow-function-expression.js":      true,
   198  		"test/language/expressions/class/cpn-class-expr-fields-methods-computed-property-name-from-async-arrow-function-expression.js": true,
   199  		"test/language/statements/let/static-init-await-binding-invalid.js":                                                            true,
   200  		"test/language/statements/labeled/static-init-invalid-await.js":                                                                true,
   201  		"test/language/statements/variable/dstr/obj-ptrn-elem-id-static-init-await-invalid.js":                                         true,
   202  		"test/language/statements/variable/static-init-await-binding-invalid.js":                                                       true,
   203  		"test/language/statements/variable/dstr/ary-ptrn-elem-id-static-init-await-invalid.js":                                         true,
   204  		"test/language/statements/try/static-init-await-binding-invalid.js":                                                            true,
   205  		"test/language/statements/function/static-init-await-binding-invalid.js":                                                       true,
   206  		"test/language/statements/const/static-init-await-binding-invalid.js":                                                          true,
   207  		"test/language/statements/class/static-init-await-binding-invalid.js":                                                          true,
   208  		"test/language/identifier-resolution/static-init-invalid-await.js":                                                             true,
   209  		"test/language/expressions/class/static-init-await-binding.js":                                                                 true,
   210  		"test/language/expressions/class/heritage-async-arrow-function.js":                                                             true,
   211  		"test/language/expressions/arrow-function/static-init-await-reference.js":                                                      true,
   212  		"test/language/expressions/arrow-function/static-init-await-binding.js":                                                        true,
   213  		"test/language/expressions/object/method-definition/static-init-await-binding-generator.js":                                    true,
   214  		"test/language/expressions/object/identifier-shorthand-static-init-await-invalid.js":                                           true,
   215  		"test/language/expressions/class/heritage-arrow-function.js":                                                                   true,
   216  		"test/language/expressions/class/elements/private-async-generator-method-name.js":                                              true,
   217  		"test/language/expressions/class/elements/private-async-method-name.js":                                                        true,
   218  		"test/language/statements/class/elements/private-async-generator-method-name.js":                                               true,
   219  		"test/language/statements/class/elements/private-async-method-name.js":                                                         true,
   220  		"test/language/expressions/in/private-field-rhs-await-present.js":                                                              true,
   221  		"test/language/expressions/class/elements/private-static-async-method-name.js":                                                 true,
   222  		"test/language/comments/hashbang/function-constructor.js":                                                                      true,
   223  
   224  		// legacy number literals
   225  		"test/language/literals/numeric/non-octal-decimal-integer.js": true,
   226  		"test/language/literals/string/S7.8.4_A4.3_T2.js":             true,
   227  		"test/language/literals/string/S7.8.4_A4.3_T1.js":             true,
   228  
   229  		// integer separators
   230  		"test/language/expressions/object/cpn-obj-lit-computed-property-name-from-integer-separators.js":                  true,
   231  		"test/language/expressions/class/cpn-class-expr-accessors-computed-property-name-from-integer-separators.js":      true,
   232  		"test/language/statements/class/cpn-class-decl-fields-computed-property-name-from-integer-separators.js":          true,
   233  		"test/language/statements/class/cpn-class-decl-computed-property-name-from-integer-separators.js":                 true,
   234  		"test/language/statements/class/cpn-class-decl-accessors-computed-property-name-from-integer-separators.js":       true,
   235  		"test/language/statements/class/cpn-class-decl-fields-methods-computed-property-name-from-integer-separators.js":  true,
   236  		"test/language/expressions/class/cpn-class-expr-fields-computed-property-name-from-integer-separators.js":         true,
   237  		"test/language/expressions/class/cpn-class-expr-computed-property-name-from-integer-separators.js":                true,
   238  		"test/language/expressions/class/cpn-class-expr-fields-methods-computed-property-name-from-integer-separators.js": true,
   239  
   240  		// BigInt
   241  		"test/built-ins/Object/seal/seal-biguint64array.js": true,
   242  		"test/built-ins/Object/seal/seal-bigint64array.js":  true,
   243  
   244  		// Regexp
   245  		"test/language/literals/regexp/invalid-range-negative-lookbehind.js":    true,
   246  		"test/language/literals/regexp/invalid-range-lookbehind.js":             true,
   247  		"test/language/literals/regexp/invalid-optional-negative-lookbehind.js": true,
   248  		"test/language/literals/regexp/invalid-optional-lookbehind.js":          true,
   249  
   250  		// FIXME bugs
   251  
   252  		// 'in' in a branch
   253  		"test/language/expressions/conditional/in-branch-1.js": true,
   254  
   255  		// Left-hand side as a CoverParenthesizedExpression
   256  		"test/language/expressions/assignment/fn-name-lhs-cover.js": true,
   257  	}
   258  
   259  	featuresBlackList = []string{
   260  		"async-iteration",
   261  		"Symbol.asyncIterator",
   262  		"async-functions",
   263  		"BigInt",
   264  		"generators",
   265  		"String.prototype.replaceAll",
   266  		"resizable-arraybuffer",
   267  		"array-find-from-last",
   268  		"regexp-named-groups",
   269  		"regexp-dotall",
   270  		"regexp-unicode-property-escapes",
   271  		"regexp-match-indices",
   272  		"legacy-regexp",
   273  		"tail-call-optimization",
   274  		"Temporal",
   275  		"import-assertions",
   276  		"dynamic-import",
   277  		"logical-assignment-operators",
   278  		"import.meta",
   279  		"Atomics",
   280  		"Atomics.waitAsync",
   281  		"FinalizationRegistry",
   282  		"WeakRef",
   283  		"numeric-separator-literal",
   284  		"Object.fromEntries",
   285  		"Object.hasOwn",
   286  		"__getter__",
   287  		"__setter__",
   288  		"ShadowRealm",
   289  		"SharedArrayBuffer",
   290  		"error-cause",
   291  		"decorators",
   292  		"regexp-v-flag",
   293  	}
   294  )
   295  
   296  func init() {
   297  
   298  	skip := func(prefixes ...string) {
   299  		for _, prefix := range prefixes {
   300  			skipPrefixes.Add(prefix)
   301  		}
   302  	}
   303  
   304  	skip(
   305  		// Go 1.16 only supports unicode 13
   306  		"test/language/identifiers/start-unicode-14.",
   307  		"test/language/identifiers/part-unicode-14.",
   308  
   309  		// async
   310  		"test/language/eval-code/direct/async-",
   311  		"test/language/expressions/async-",
   312  		"test/language/expressions/await/",
   313  		"test/language/statements/async-function/",
   314  		"test/built-ins/Async",
   315  		"test/language/statements/class/elements/private-static-async-",
   316  		"test/language/statements/class/elements/wrapped-in-sc-rs-static-async-",
   317  		"test/language/expressions/class/elements/wrapped-in-sc-rs-static-async-",
   318  		"test/language/statements/class/elements/after-same-line-static-method-rs-static-async-",
   319  		"test/language/expressions/class/elements/after-same-line-static-method-rs-static-async-",
   320  		"test/language/statements/class/elements/after-same-line-method-rs-static-async-",
   321  		"test/language/expressions/class/elements/after-same-line-method-rs-static-async-",
   322  		"test/language/statements/class/elements/new-sc-line-method-rs-static-async-",
   323  		"test/language/expressions/class/elements/new-sc-line-method-rs-static-async-",
   324  		"test/language/statements/class/elements/new-no-sc-line-method-rs-static-async-",
   325  		"test/language/expressions/class/elements/new-no-sc-line-method-rs-static-async-",
   326  		"test/language/statements/class/elements/same-line-method-rs-static-async-",
   327  		"test/language/expressions/class/elements/same-line-method-rs-static-async-",
   328  		"test/language/statements/class/elements/regular-definitions-rs-static-async-",
   329  		"test/language/expressions/class/elements/regular-definitions-rs-static-async-",
   330  		"test/language/statements/class/elements/multiple-stacked-definitions-rs-static-async-",
   331  		"test/language/expressions/class/elements/multiple-stacked-definitions-rs-static-async-",
   332  		"test/language/statements/class/elements/multiple-definitions-rs-static-async-",
   333  		"test/language/expressions/class/elements/multiple-definitions-rs-static-async-",
   334  
   335  		// generators
   336  		"test/language/eval-code/direct/gen-",
   337  		"test/built-ins/GeneratorFunction/",
   338  		"test/built-ins/Function/prototype/toString/generator-",
   339  		"test/language/statements/class/elements/private-static-generator-",
   340  		"test/language/statements/class/subclass/builtin-objects/GeneratorFunction/",
   341  		"test/language/statements/class/elements/wrapped-in-sc-rs-static-generator-",
   342  		"test/language/expressions/class/elements/wrapped-in-sc-rs-static-generator-",
   343  		"test/language/statements/class/elements/after-same-line-method-rs-static-generator-",
   344  		"test/language/expressions/class/elements/after-same-line-method-rs-static-generator-",
   345  		"test/language/statements/class/elements/after-same-line-static-method-rs-static-generator-",
   346  		"test/language/expressions/class/elements/after-same-line-static-method-rs-static-generator-",
   347  		"test/language/statements/class/elements/new-sc-line-method-rs-static-generator-",
   348  		"test/language/expressions/class/elements/new-sc-line-method-rs-static-generator-",
   349  		"test/language/statements/class/elements/new-no-sc-line-method-rs-static-generator-",
   350  		"test/language/expressions/class/elements/new-no-sc-line-method-rs-static-generator-",
   351  		"test/language/statements/class/elements/same-line-method-rs-static-generator-",
   352  		"test/language/expressions/class/elements/same-line-method-rs-static-generator-",
   353  		"test/language/statements/class/elements/regular-definitions-rs-static-generator-",
   354  		"test/language/expressions/class/elements/regular-definitions-rs-static-generator-",
   355  		"test/language/statements/class/elements/multiple-stacked-definitions-rs-static-generator-",
   356  		"test/language/expressions/class/elements/multiple-stacked-definitions-rs-static-generator-",
   357  		"test/language/statements/class/elements/multiple-definitions-rs-static-generator-",
   358  		"test/language/expressions/class/elements/multiple-definitions-rs-static-generator-",
   359  
   360  		// BigInt
   361  		"test/built-ins/TypedArrayConstructors/BigUint64Array/",
   362  		"test/built-ins/TypedArrayConstructors/BigInt64Array/",
   363  
   364  		// restricted unicode regexp syntax
   365  		"test/language/literals/regexp/u-",
   366  
   367  		// legacy octal escape in strings in strict mode
   368  		"test/language/literals/string/legacy-octal-",
   369  		"test/language/literals/string/legacy-non-octal-",
   370  
   371  		// modules
   372  		"test/language/export/",
   373  		"test/language/import/",
   374  		"test/language/module-code/",
   375  	)
   376  
   377  }
   378  
   379  type tc39Test struct {
   380  	name string
   381  	f    func(t *testing.T)
   382  }
   383  
   384  type tc39BenchmarkItem struct {
   385  	name     string
   386  	duration time.Duration
   387  }
   388  
   389  type tc39BenchmarkData []tc39BenchmarkItem
   390  
   391  type tc39TestCtx struct {
   392  	base         string
   393  	t            *testing.T
   394  	prgCache     map[string]*Program
   395  	prgCacheLock sync.Mutex
   396  	enableBench  bool
   397  	benchmark    tc39BenchmarkData
   398  	benchLock    sync.Mutex
   399  	sabStub      *Program
   400  	//lint:ignore U1000 Only used with race
   401  	testQueue []tc39Test
   402  }
   403  
   404  type TC39MetaNegative struct {
   405  	Phase, Type string
   406  }
   407  
   408  type tc39Meta struct {
   409  	Negative TC39MetaNegative
   410  	Includes []string
   411  	Flags    []string
   412  	Features []string
   413  	Es5id    string
   414  	Es6id    string
   415  	Esid     string
   416  }
   417  
   418  type prefixList struct {
   419  	prefixes map[int]map[string]struct{}
   420  }
   421  
   422  func (pl *prefixList) Add(prefix string) {
   423  	l := pl.prefixes[len(prefix)]
   424  	if l == nil {
   425  		l = make(map[string]struct{})
   426  		if pl.prefixes == nil {
   427  			pl.prefixes = make(map[int]map[string]struct{})
   428  		}
   429  		pl.prefixes[len(prefix)] = l
   430  	}
   431  	l[prefix] = struct{}{}
   432  }
   433  
   434  func (pl *prefixList) Match(s string) bool {
   435  	for l, prefixes := range pl.prefixes {
   436  		if len(s) >= l {
   437  			if _, exists := prefixes[s[:l]]; exists {
   438  				return true
   439  			}
   440  		}
   441  	}
   442  	return false
   443  }
   444  
   445  func (m *tc39Meta) hasFlag(flag string) bool {
   446  	for _, f := range m.Flags {
   447  		if f == flag {
   448  			return true
   449  		}
   450  	}
   451  	return false
   452  }
   453  
   454  func parseTC39File(name string) (*tc39Meta, string, error) {
   455  	f, err := os.Open(name)
   456  	if err != nil {
   457  		return nil, "", err
   458  	}
   459  	defer f.Close()
   460  
   461  	b, err := io.ReadAll(f)
   462  	if err != nil {
   463  		return nil, "", err
   464  	}
   465  
   466  	str := string(b)
   467  	metaStart := strings.Index(str, "/*---")
   468  	if metaStart == -1 {
   469  		return nil, "", invalidFormatError
   470  	} else {
   471  		metaStart += 5
   472  	}
   473  	metaEnd := strings.Index(str, "---*/")
   474  	if metaEnd == -1 || metaEnd <= metaStart {
   475  		return nil, "", invalidFormatError
   476  	}
   477  
   478  	var meta tc39Meta
   479  	err = yaml.Unmarshal([]byte(str[metaStart:metaEnd]), &meta)
   480  	if err != nil {
   481  		return nil, "", err
   482  	}
   483  
   484  	if meta.Negative.Type != "" && meta.Negative.Phase == "" {
   485  		return nil, "", errors.New("negative type is set, but phase isn't")
   486  	}
   487  
   488  	return &meta, str, nil
   489  }
   490  
   491  func (*tc39TestCtx) detachArrayBuffer(call FunctionCall) Value {
   492  	if obj, ok := call.Argument(0).(*Object); ok {
   493  		if buf, ok := obj.self.(*arrayBufferObject); ok {
   494  			buf.detach()
   495  			return _undefined
   496  		}
   497  	}
   498  	panic(typeError("detachArrayBuffer() is called with incompatible argument"))
   499  }
   500  
   501  func (*tc39TestCtx) throwIgnorableTestError(FunctionCall) Value {
   502  	panic(ignorableTestError)
   503  }
   504  
   505  func (ctx *tc39TestCtx) runTC39Test(name, src string, meta *tc39Meta, t testing.TB) {
   506  	defer func() {
   507  		if x := recover(); x != nil {
   508  			panic(fmt.Sprintf("panic while running %s: %v", name, x))
   509  		}
   510  	}()
   511  	vm := New()
   512  	_262 := vm.NewObject()
   513  	_262.Set("detachArrayBuffer", ctx.detachArrayBuffer)
   514  	_262.Set("createRealm", ctx.throwIgnorableTestError)
   515  	_262.Set("evalScript", func(call FunctionCall) Value {
   516  		script := call.Argument(0).String()
   517  		result, err := vm.RunString(script)
   518  		if err != nil {
   519  			panic(err)
   520  		}
   521  		return result
   522  	})
   523  	vm.Set("$262", _262)
   524  	vm.Set("IgnorableTestError", ignorableTestError)
   525  	vm.RunProgram(ctx.sabStub)
   526  	var out []string
   527  	async := meta.hasFlag("async")
   528  	if async {
   529  		err := ctx.runFile(ctx.base, path.Join("harness", "doneprintHandle.js"), vm)
   530  		if err != nil {
   531  			t.Fatal(err)
   532  		}
   533  		vm.Set("print", func(msg string) {
   534  			out = append(out, msg)
   535  		})
   536  	} else {
   537  		vm.Set("print", t.Log)
   538  	}
   539  
   540  	err, early := ctx.runTC39Script(name, src, meta.Includes, vm)
   541  
   542  	if err != nil {
   543  		if meta.Negative.Type == "" {
   544  			if err, ok := err.(*Exception); ok {
   545  				if err.Value() == ignorableTestError {
   546  					t.Skip("Test threw IgnorableTestError")
   547  				}
   548  			}
   549  			t.Fatalf("%s: %v", name, err)
   550  		} else {
   551  			if (meta.Negative.Phase == "early" || meta.Negative.Phase == "parse") && !early || meta.Negative.Phase == "runtime" && early {
   552  				t.Fatalf("%s: error %v happened at the wrong phase (expected %s)", name, err, meta.Negative.Phase)
   553  			}
   554  			var errType string
   555  
   556  			switch err := err.(type) {
   557  			case *Exception:
   558  				if o, ok := err.Value().(*Object); ok {
   559  					if c := o.Get("constructor"); c != nil {
   560  						if c, ok := c.(*Object); ok {
   561  							errType = c.Get("name").String()
   562  						} else {
   563  							t.Fatalf("%s: error constructor is not an object (%v)", name, o)
   564  						}
   565  					} else {
   566  						t.Fatalf("%s: error does not have a constructor (%v)", name, o)
   567  					}
   568  				} else {
   569  					t.Fatalf("%s: error is not an object (%v)", name, err.Value())
   570  				}
   571  			case *CompilerSyntaxError:
   572  				errType = "SyntaxError"
   573  			case *CompilerReferenceError:
   574  				errType = "ReferenceError"
   575  			default:
   576  				t.Fatalf("%s: error is not a JS error: %v", name, err)
   577  			}
   578  
   579  			if errType != meta.Negative.Type {
   580  				vm.vm.prg.dumpCode(t.Logf)
   581  				t.Fatalf("%s: unexpected error type (%s), expected (%s)", name, errType, meta.Negative.Type)
   582  			}
   583  		}
   584  	} else {
   585  		if meta.Negative.Type != "" {
   586  			vm.vm.prg.dumpCode(t.Logf)
   587  			t.Fatalf("%s: Expected error: %v", name, err)
   588  		}
   589  	}
   590  
   591  	if vm.vm.sp != 0 {
   592  		t.Fatalf("sp: %d", vm.vm.sp)
   593  	}
   594  
   595  	if l := len(vm.vm.iterStack); l > 0 {
   596  		t.Fatalf("iter stack is not empty: %d", l)
   597  	}
   598  	if async {
   599  		complete := false
   600  		for _, line := range out {
   601  			if strings.HasPrefix(line, "Test262:AsyncTestFailure:") {
   602  				t.Fatal(line)
   603  			} else if line == "Test262:AsyncTestComplete" {
   604  				complete = true
   605  			}
   606  		}
   607  		if !complete {
   608  			for _, line := range out {
   609  				t.Log(line)
   610  			}
   611  			t.Fatal("Test262:AsyncTestComplete was not printed")
   612  		}
   613  	}
   614  }
   615  
   616  func (ctx *tc39TestCtx) runTC39File(name string, t testing.TB) {
   617  	if skipList[name] {
   618  		t.Skip("Excluded")
   619  	}
   620  	if skipPrefixes.Match(name) {
   621  		t.Skip("Excluded")
   622  	}
   623  	p := path.Join(ctx.base, name)
   624  	meta, src, err := parseTC39File(p)
   625  	if err != nil {
   626  		//t.Fatalf("Could not parse %s: %v", name, err)
   627  		t.Errorf("Could not parse %s: %v", name, err)
   628  		return
   629  	}
   630  	if meta.hasFlag("module") {
   631  		t.Skip("module")
   632  	}
   633  	if meta.Es5id == "" {
   634  		for _, feature := range meta.Features {
   635  			for _, bl := range featuresBlackList {
   636  				if feature == bl {
   637  					t.Skip("Blacklisted feature")
   638  				}
   639  			}
   640  		}
   641  	}
   642  
   643  	var startTime time.Time
   644  	if ctx.enableBench {
   645  		startTime = time.Now()
   646  	}
   647  
   648  	hasRaw := meta.hasFlag("raw")
   649  
   650  	if hasRaw || !meta.hasFlag("onlyStrict") {
   651  		//log.Printf("Running normal test: %s", name)
   652  		t.Logf("Running normal test: %s", name)
   653  		ctx.runTC39Test(name, src, meta, t)
   654  	}
   655  
   656  	if !hasRaw && !meta.hasFlag("noStrict") {
   657  		//log.Printf("Running strict test: %s", name)
   658  		t.Logf("Running strict test: %s", name)
   659  		ctx.runTC39Test(name, "'use strict';\n"+src, meta, t)
   660  	}
   661  
   662  	if ctx.enableBench {
   663  		ctx.benchLock.Lock()
   664  		ctx.benchmark = append(ctx.benchmark, tc39BenchmarkItem{
   665  			name:     name,
   666  			duration: time.Since(startTime),
   667  		})
   668  		ctx.benchLock.Unlock()
   669  	}
   670  
   671  }
   672  
   673  func (ctx *tc39TestCtx) init() {
   674  	ctx.prgCache = make(map[string]*Program)
   675  	ctx.sabStub = MustCompile("sabStub.js", `
   676  		Object.defineProperty(this, "SharedArrayBuffer", {
   677  			get: function() {
   678  				throw IgnorableTestError;
   679  			}
   680  		});`,
   681  		false)
   682  }
   683  
   684  func (ctx *tc39TestCtx) compile(base, name string) (*Program, error) {
   685  	ctx.prgCacheLock.Lock()
   686  	defer ctx.prgCacheLock.Unlock()
   687  
   688  	prg := ctx.prgCache[name]
   689  	if prg == nil {
   690  		fname := path.Join(base, name)
   691  		f, err := os.Open(fname)
   692  		if err != nil {
   693  			return nil, err
   694  		}
   695  		defer f.Close()
   696  
   697  		b, err := io.ReadAll(f)
   698  		if err != nil {
   699  			return nil, err
   700  		}
   701  
   702  		str := string(b)
   703  		prg, err = Compile(name, str, false)
   704  		if err != nil {
   705  			return nil, err
   706  		}
   707  		ctx.prgCache[name] = prg
   708  	}
   709  
   710  	return prg, nil
   711  }
   712  
   713  func (ctx *tc39TestCtx) runFile(base, name string, vm *Runtime) error {
   714  	prg, err := ctx.compile(base, name)
   715  	if err != nil {
   716  		return err
   717  	}
   718  	_, err = vm.RunProgram(prg)
   719  	return err
   720  }
   721  
   722  func (ctx *tc39TestCtx) runTC39Script(name, src string, includes []string, vm *Runtime) (err error, early bool) {
   723  	early = true
   724  	err = ctx.runFile(ctx.base, path.Join("harness", "assert.js"), vm)
   725  	if err != nil {
   726  		return
   727  	}
   728  
   729  	err = ctx.runFile(ctx.base, path.Join("harness", "sta.js"), vm)
   730  	if err != nil {
   731  		return
   732  	}
   733  
   734  	for _, include := range includes {
   735  		err = ctx.runFile(ctx.base, path.Join("harness", include), vm)
   736  		if err != nil {
   737  			return
   738  		}
   739  	}
   740  
   741  	var p *Program
   742  	p, err = Compile(name, src, false)
   743  
   744  	if err != nil {
   745  		return
   746  	}
   747  
   748  	early = false
   749  	_, err = vm.RunProgram(p)
   750  
   751  	return
   752  }
   753  
   754  func (ctx *tc39TestCtx) runTC39Tests(name string) {
   755  	files, err := os.ReadDir(path.Join(ctx.base, name))
   756  	if err != nil {
   757  		ctx.t.Fatal(err)
   758  	}
   759  
   760  	for _, file := range files {
   761  		if file.Name()[0] == '.' {
   762  			continue
   763  		}
   764  		if file.IsDir() {
   765  			ctx.runTC39Tests(path.Join(name, file.Name()))
   766  		} else {
   767  			fileName := file.Name()
   768  			if strings.HasSuffix(fileName, ".js") && !strings.HasSuffix(fileName, "_FIXTURE.js") {
   769  				name := path.Join(name, fileName)
   770  				ctx.runTest(name, func(t *testing.T) {
   771  					ctx.runTC39File(name, t)
   772  				})
   773  			}
   774  		}
   775  	}
   776  
   777  }
   778  
   779  func TestTC39(t *testing.T) {
   780  	if testing.Short() {
   781  		t.Skip()
   782  	}
   783  
   784  	if _, err := os.Stat(tc39BASE); err != nil {
   785  		t.Skipf("If you want to run tc39 tests, download them from https://github.com/tc39/test262 and put into %s. See .tc39_test262_checkout.sh for the latest working commit id. (%v)", tc39BASE, err)
   786  	}
   787  
   788  	ctx := &tc39TestCtx{
   789  		base: tc39BASE,
   790  	}
   791  	ctx.init()
   792  	//ctx.enableBench = true
   793  
   794  	t.Run("tc39", func(t *testing.T) {
   795  		ctx.t = t
   796  		//ctx.runTC39File("test/language/types/number/8.5.1.js", t)
   797  		ctx.runTC39Tests("test/language")
   798  		ctx.runTC39Tests("test/built-ins")
   799  		ctx.runTC39Tests("test/annexB/built-ins/String/prototype/substr")
   800  		ctx.runTC39Tests("test/annexB/built-ins/String/prototype/trimLeft")
   801  		ctx.runTC39Tests("test/annexB/built-ins/String/prototype/trimRight")
   802  		ctx.runTC39Tests("test/annexB/built-ins/escape")
   803  		ctx.runTC39Tests("test/annexB/built-ins/unescape")
   804  		ctx.runTC39Tests("test/annexB/built-ins/RegExp")
   805  
   806  		ctx.flush()
   807  	})
   808  
   809  	if ctx.enableBench {
   810  		sort.Slice(ctx.benchmark, func(i, j int) bool {
   811  			return ctx.benchmark[i].duration > ctx.benchmark[j].duration
   812  		})
   813  		bench := ctx.benchmark
   814  		if len(bench) > 50 {
   815  			bench = bench[:50]
   816  		}
   817  		for _, item := range bench {
   818  			fmt.Printf("%s\t%d\n", item.name, item.duration/time.Millisecond)
   819  		}
   820  	}
   821  }