Commit graph

470 commits

Author SHA1 Message Date
Linus Groh
1bff65c591 LibJS: Add ErrorType::ConstructorWithoutNew
...and use it in Proxy::call(), rather than having a specific error
type just for that.
2020-12-02 12:52:31 +01:00
Andreas Kling
3565d3c60c LibJS: Add six typed arrays (signed and unsigned 8/16/32-bit)
This patch adds six of the standard type arrays and tries to share as
much code as possible:

- Uint8Array
- Uint16Array
- Uint32Array
- Int8Array
- Int16Array
- Int32Array
2020-12-01 21:05:25 +01:00
Andreas Kling
2d9d883274 LibJS: Add a basic implementation of String.prototype.substr() 2020-11-29 20:29:49 +01:00
Andreas Kling
2e4832c3da LibJS: Constructor function's "prototype" property should be writable
This matches other engines.
2020-11-29 19:49:27 +01:00
Linus Groh
3ac7fb9f6c LibJS: Disallow 'with' statement in strict mode 2020-11-28 20:33:41 +01:00
Andreas Kling
1fad95fec5 LibJS: Add a basic unit test for the "with" statement 2020-11-28 17:16:48 +01:00
Linus Groh
8a9a7f1677 LibJS: Make RegExp.prototype.source spec-compliant
Basically:
- And edge case for this object being RegExp.prototype.source
- Return "(?:)" for empty pattern
- Escape some things properly
2020-11-28 01:20:11 +01:00
Linus Groh
b6e5442d55 LibJS: Make RegExp.prototype.toString() spec-compliant
It should use the 'source' and 'flags' properties of the object, and
therefore work with non-RegExp objects as well.
2020-11-28 01:20:11 +01:00
Linus Groh
ee66eaa1b0 LibJS: Make RegExp.prototype.flags spec-compliant
This should be using the individual flag boolean properties rather than
the [[OriginalFlags]] internal slot.
Use an enumerator macro here for brevity, this will be useful for other
things as well. :^)
2020-11-28 01:20:11 +01:00
Linus Groh
5cb45e4feb LibJS: Make RegExp() constructor spec-compliant
- Default values should depend on arguments being undefined, not being
  missing
- "(?:)" for empty pattern happens in RegExp.prototype.source, not the
  constructor
2020-11-28 01:20:11 +01:00
AnotherTest
210a3db44d LibJS: Implement `RegExpPrototype::exec()'
This implements *only* the builtin exec() function.
2020-11-27 21:32:41 +01:00
AnotherTest
8ba273a2f3 LibJS: Hook up Regex<ECMA262> to RegExpObject and implement `test()'
This makes RegExpObject compile and store a Regex<ECMA262>, adds
all flag-related properties, and implements `RegExpPrototype.test()`
(complete with 'lastIndex' support) :^)
It should be noted that this only implements `test()' using the builtin
`exec()'.
2020-11-27 21:32:41 +01:00
Linus Groh
f6f0d3cbae LibJS: Support receiver in ProxyObject::get/put()
If a receiver is given, e.g. via Reflect.get/set(), forward it to the
target object's get()/put() or use it as last argument of the trap
function. The default value is the Proxy object itself.
2020-11-24 21:35:03 +01:00
Linus Groh
48369194d2 LibJS: Forward receiver value to native property getters/setters
There's no reason why only (user-defined) accessors would have set the
receiver as this value for their getters/setters, this is an oversight.
2020-11-22 19:00:19 +01:00
Linus Groh
5a307836c1 LibJS: Handle symbol PropertyName in primitive assignment error
We can't just to_string() the PropertyName, it might be a symbol.
Instead to_value() it and then use to_string_without_side_effects() as
usual.

Fixes #4062.
2020-11-12 11:40:29 +01:00
Linus Groh
e77202fe0f LibJS/Tests: Use canParseSource() for toEval()
We can now enable the "new.target is syntax error outside of function"
test :^)
2020-11-12 10:14:57 +01:00
Linus Groh
8694d804c7 LibJS: Run prettier on test-common.js 2020-11-12 10:14:57 +01:00
Linus Groh
1b0c862f3a LibJS: Throw TypeError when calling class constructor without 'new' 2020-11-12 10:14:00 +01:00
Linus Groh
a02b9983f9 LibJS: Throw RuntimeError when reaching the end of the stack
This prevents stack overflows when calling infinite/deep recursive
functions, e.g.:

    const f = () => f(); f();
    JSON.stringify({}, () => ({ foo: "bar" }));
    new Proxy({}, { get: (_, __, p) => p.foo }).foo;

The VM caches a StackInfo object to not slow down function calls
considerably. VM::push_call_frame() will throw an exception if
necessary (plain Error with "RuntimeError" as its .name).
2020-11-08 16:51:54 +01:00
Linus Groh
745ffca580 LibJS: Use element index as key for array spread in object
This fixes spreading of arrays with holes in object literals where the
inserted keys are not consecutive numbers.

Fixes #3967.
2020-11-07 10:08:28 +01:00
Linus Groh
06a3625545 LibJS: Set prototype of GlobalObject to ObjectPrototype
As the global object is constructed and initialized in a different way
than most other objects we were not setting its prototype! This made
things like "globalThis.toString()" fail unexpectedly.
2020-11-07 10:08:05 +01:00
Linus Groh
82b42cefbd LibJS: Handle circular references in Array.prototype.toLocaleString()
Also use ArmedScopeGuard for removing seen objects to account for early
returns.

Fixes #3963.
2020-11-06 15:50:18 +01:00
Linus Groh
dec6c0a207 LibJS: Use array-like size for IndexedProperties::is_empty()
Some things, like (the non-generic version of) Array.prototype.pop(),
check is_empty() to determine whether an action, like removing elements,
can be performed. We need to know the array-like size for that, not the
size of the underlying storage, which can be different - and is not
something IndexedProperties should expose so I removed its size().

Fixes #3948.
2020-11-05 20:01:30 +01:00
Linus Groh
0bb66890c8 LibJS: Fix Object::delete_property() with numeric string property
- We have to check if the property name is a string before calling
  as_string() on it
- We can't as_number() the same property name but have to use the parsed
  index number

Fixes #3950.
2020-11-05 19:15:00 +01:00
Linus Groh
2cf8649d0e LibJS: Fix ProxyObject get/set with symbol property name
We can't assume that property names can be converted to strings anymore,
as we have symbols. Use name.to_value() instead.

This makes something like this possible:

    new Proxy(Object, { get(t, p) { return t[p] }  })[Symbol.hasInstance]
2020-11-04 23:06:44 +01:00
Linus Groh
2645dfafcf LibJS: Implement Object(value) constructor
Not sure why we didn't have this yet, it's super simple :^)
2020-11-04 23:06:44 +01:00
Linus Groh
0603402c80 LibJS: Handle circular references in Array.prototype.join()
This fixes Array.prototype.{join,toString}() crashing with arrays
containing themselves, i.e. circular references.

The spec is suspiciously silent about this, and indeed engine262, a
"100% spec compliant" ECMA-262 implementation, can't handle these cases.
I had a look at some major engines instead and they all seem to keep
track or check for circular references and return an empty string for
already seen objects.

- SpiderMonkey: "AutoCycleDetector detector(cx, obj)"
- V8: "CycleProtectedArrayJoin<JSArray>(...)"
- JavaScriptCore: "StringRecursionChecker checker(globalObject, thisObject)"
- ChakraCore: "scriptContext->CheckObject(thisArg)"

To keep things simple & consistent this uses the same pattern as
JSONObject, MarkupGenerator and js: simply putting each seen object in a
HashTable<Object*>.

Fixes #3929.
2020-11-04 19:35:43 +01:00
Linus Groh
e5845ba3a0 LibJS: Use "," separator in Array.prototype.join() if first arg is undefined
This is how the spec describes it, not "if the first arg is missing".
Also swap length & separator steps to match spec.
2020-11-04 19:35:43 +01:00
Linus Groh
fb89c324c5 LibJS: Implement spec-compliant OrdinaryToPrimitive
This renames Object::to_primitive() to Object::ordinary_to_primitive()
for two reasons:

- No confusion with Value::to_primitive()
- To match the spec's name

Also change existing uses of Object::to_primitive() to
Value::to_primitive() when the spec uses the latter (which will still
call Object::ordinary_to_primitive()). Object::to_string() has been
removed as it's not needed anymore (and nothing the spec uses).

This makes it possible to overwrite an object's toString and valueOf and
have them provide results for anything that uses to_primitive() - e.g.:

    const o = { toString: undefined, valueOf: () => 42 };
    Number(o) // 42, previously NaN
    ["foo", o].toString(); // "foo,42", previously "foo,[object Object]"
    ++o // 43, previously NaN

etc.
2020-11-04 19:33:49 +01:00
Linus Groh
e163db248d LibJS: Implement RegExp.prototype.toString() as standalone function
This should not just inherit Object.prototype.toString() (and override
Object::to_string()) but be its own function, i.e.
'RegExp.prototype.toString !== Object.prototype.toString'.
2020-11-04 19:33:49 +01:00
Linus Groh
41837f548d LibJS: Don't create "valid" PropertyName from null string
When value.to_string() throws an exception it returns a null string in
which case we must not construct a valid PropertyName.

Also ASSERT in PropertyName(String) and PropertyName(FlyString) to
prevent this from happening in the future.

Fixes #3941.
2020-11-04 15:31:39 +01:00
Linus Groh
565a26808d LibJS: Fix crashing exception in Value::ordinary_has_instance()
Two issues:

- throw_exception() with ErrorType::InstanceOfOperatorBadPrototype would
  receive rhs_prototype.to_string_without_side_effects(), which would
  ASSERT_NOT_REACHED() as to_string_without_side_effects() must not be
  called on an empty value. It should (and now does) receive the RHS
  value instead as the message is "'prototype' property of {} is not an
  object".
- Value::instance_of() was missing an exception check after calling
  has_instance_method, to_boolean() on an empty value result would crash
  as well.

Fixes #3930.
2020-11-03 19:14:13 +01:00
Linus Groh
39a1c9d827 LibJS: Implement 'new.target'
This adds a new MetaProperty AST node which will be used for
'new.target' and 'import.meta' meta properties. The parser now
distinguishes between "in function context" and "in arrow function
context" (which is required for this).
When encountering TokenType::New we will attempt to parse it as meta
property and resort to regular new expression parsing if that fails,
much like the parsing of labelled statements.
2020-11-02 22:40:59 +01:00
Linus Groh
9e80c67608 LibJS: Fix "use strict" directive false positives
By having the "is this a use strict directive?" logic in
parse_string_literal() we would apply it to *any* string literal, which
is incorrect and would lead to false positives - e.g.:

    "use strict" + 1
    `"use strict"`
    "\123"; ({"use strict": ...})

Relevant part from the spec which is now implemented properly:

[...] and where each ExpressionStatement in the sequence consists
entirely of a StringLiteral token [...]

I also got rid of UseStrictDirectiveState which is not needed anymore.

Fixes #3903.
2020-11-02 13:13:54 +01:00
Linus Groh
a598a2c19d LibJS: Function declarations in if statement clauses
https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses

B.3.4 FunctionDeclarations in IfStatement Statement Clauses

The following augments the IfStatement production in 13.6:

    IfStatement[Yield, Await, Return] :
        if ( Expression[+In, ?Yield, ?Await] ) FunctionDeclaration[?Yield, ?Await, ~Default] else Statement[?Yield, ?Await, ?Return]
        if ( Expression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return] else FunctionDeclaration[?Yield, ?Await, ~Default]
        if ( Expression[+In, ?Yield, ?Await] ) FunctionDeclaration[?Yield, ?Await, ~Default] else FunctionDeclaration[?Yield, ?Await, ~Default]
        if ( Expression[+In, ?Yield, ?Await] ) FunctionDeclaration[?Yield, ?Await, ~Default]

This production only applies when parsing non-strict code. Code matching
this production is processed as if each matching occurrence of
FunctionDeclaration[?Yield, ?Await, ~Default] was the sole
StatementListItem of a BlockStatement occupying that position in the
source code. The semantics of such a synthetic BlockStatement includes
the web legacy compatibility semantics specified in B.3.3.
2020-10-31 15:25:12 +01:00
Linus Groh
563d3c8055 LibJS: Require initializer for 'const' variable declaration 2020-10-30 23:43:38 +01:00
Linus Groh
69845ae460 LibJS: "-->" preceded by token on same line isn't start of HTML-like comment
B.1.3 HTML-like Comments

The syntax and semantics of 11.4 is extended as follows except that this
extension is not allowed when parsing source code using the goal symbol
Module:

Syntax (only relevant part included)

    SingleLineHTMLCloseComment ::
        LineTerminatorSequence HTMLCloseComment

    HTMLCloseComment ::
        WhiteSpaceSequence[opt] SingleLineDelimitedCommentSequence[opt] --> SingleLineCommentChars[opt]

Fixes #3810.
2020-10-29 22:28:15 +01:00
Linus Groh
a10d09faba LibJS: Tweak generated source in 'new Function()' to match ES 2015 spec
ES 5(.1) described parsing of the function body string as:

https://www.ecma-international.org/ecma-262/5.1/#sec-15.3.2.1

7. If P is not parsable as a FormalParameterList[opt] then throw a SyntaxError exception.
8. If body is not parsable as FunctionBody then throw a SyntaxError exception.

We implemented it as building the source string of a complete function
and feeding that to the parser, with the same outcome. ES 2015+ does
exactly that, but with newlines at certain positions:

https://tc39.es/ecma262/#sec-createdynamicfunction

16. Let bodyString be the string-concatenation of 0x000A (LINE FEED), ? ToString(bodyArg), and 0x000A (LINE FEED).
17. Let prefix be the prefix associated with kind in Table 49.
18. Let sourceString be the string-concatenation of prefix, " anonymous(", P, 0x000A (LINE FEED), ") {", bodyString, and "}".

This patch updates the generated source string to match these
requirements. This will make certain edge cases work, e.g.
'new Function("-->")', where the user supplied input must be placed on
its own line to be valid syntax.
2020-10-29 22:27:55 +01:00
Linus Groh
3dbf4c62b0 LibJS: Use GenericLexer for Token::string_value()
This is, and I can't stress this enough, a lot better than all the
manual bounds checking and indexing that was going on before.

Also fixes a small bug where "\u{}" wouldn't get rejected as invalid
unicode escape sequence.
2020-10-29 11:52:31 +01:00
Linus Groh
b5bd05b717 LibJS: Don't parse numeric literal containing 8 or 9 as octal
If the value has a leading zero (allowed in non-strict mode) but
contains the digits 8 or 9 it can't be an octal number.
2020-10-28 21:11:32 +01:00
Linus Groh
b4e51249e9 LibJS: Always insert semicolon after do-while statement if missing
https://tc39.es/ecma262/#sec-additions-and-changes-that-introduce-incompatibilities-with-prior-editions

11.9.1: In ECMAScript 2015, Automatic Semicolon Insertion adds a
semicolon at the end of a do-while statement if the semicolon is
missing. This change aligns the specification with the actual behaviour
of most existing implementations.
2020-10-28 21:11:32 +01:00
Linus Groh
d278f61f4c LibJS: Restrict toEval() failures to SyntaxError
We only use expect(...).toEval() / not.toEval() for checking syntax
errors, where we obviously can't put the code in a regular function. For
runtime errors we do exactly that, so toEval() should not fail - this
allows us to use undefined identifiers in syntax tests.
2020-10-28 21:11:32 +01:00
Linus Groh
19edcbd79c LibJS: Emit TokenType::Invalid for unterminated multi-line comments 2020-10-26 21:38:34 +01:00
Linus Groh
66e315959d LibJS: Allow all line terminators to be used for line continuations 2020-10-25 19:45:47 +01:00
Marcin Gasperowicz
e5ddcadd3c LibJS: Parse line continuations in string literals properly
Newlines after line continuation were inserted into the string 
literals. This patch makes the parser ignore the newlines after \ and
also makes it so that "use strict" containing a line continuation is 
not a valid "use strict".
2020-10-25 15:16:47 +01:00
Linus Groh
dca9e4ec10 LibJS: Implement rules for duplicate function parameters
- A regular function can have duplicate parameters except in strict mode
  or if its parameter list is not "simple" (has a default or rest
  parameter)
- An arrow function can never have duplicate parameters

Compared to other engines I opted for more useful syntax error messages
than a generic "duplicate parameter name not allowed in this context":

    "use strict"; function test(foo, foo) {}
                                     ^
    Uncaught exception: [SyntaxError]: Duplicate parameter 'foo' not allowed in strict mode (line: 1, column: 34)

    function test(foo, foo = 1) {}
                       ^
    Uncaught exception: [SyntaxError]: Duplicate parameter 'foo' not allowed in function with default parameter (line: 1, column: 20)

    function test(foo, ...foo) {}
                          ^
    Uncaught exception: [SyntaxError]: Duplicate parameter 'foo' not allowed in function with rest parameter (line: 1, column: 23)

    (foo, foo) => {}
          ^
    Uncaught exception: [SyntaxError]: Duplicate parameter 'foo' not allowed in arrow function (line: 1, column: 7)
2020-10-25 12:56:02 +01:00
Linus Groh
2adcabb6b3 LibJS: Disallow escape sequence/line continuation in use strict directive
https://tc39.es/ecma262/#sec-directive-prologues-and-the-use-strict-directive

A Use Strict Directive is an ExpressionStatement in a Directive Prologue
whose StringLiteral is either of the exact code point sequences
"use strict" or 'use strict'. A Use Strict Directive may not contain an
EscapeSequence or LineContinuation.
2020-10-24 16:34:01 +02:00
Linus Groh
4fb96afafc LibJS: Support LegacyOctalEscapeSequence in string literals
https://tc39.es/ecma262/#sec-additional-syntax-string-literals

The syntax and semantics of 11.8.4 is extended as follows except that
this extension is not allowed for strict mode code:

Syntax

    EscapeSequence::
        CharacterEscapeSequence
        LegacyOctalEscapeSequence
        NonOctalDecimalEscapeSequence
        HexEscapeSequence
        UnicodeEscapeSequence

    LegacyOctalEscapeSequence::
        OctalDigit [lookahead ∉ OctalDigit]
        ZeroToThree OctalDigit [lookahead ∉ OctalDigit]
        FourToSeven OctalDigit
        ZeroToThree OctalDigit OctalDigit

    ZeroToThree :: one of
        0 1 2 3

    FourToSeven :: one of
        4 5 6 7

    NonOctalDecimalEscapeSequence :: one of
        8 9

This definition of EscapeSequence is not used in strict mode or when
parsing TemplateCharacter.

Note

It is possible for string literals to precede a Use Strict Directive
that places the enclosing code in strict mode, and implementations must
take care to not use this extended definition of EscapeSequence with
such literals. For example, attempting to parse the following source
text must fail:

function invalid() { "\7"; "use strict"; }
2020-10-24 16:34:01 +02:00
Linus Groh
d6f8c52245 LibJS: Allow try statement with only finally clause
This was a regression introduced by 9ffe45b - a TryStatement without
'catch' clause *is* allowed, if it has a 'finally' clause. It is now
checked properly that at least one of both is present.
2020-10-24 16:34:01 +02:00
Linus Groh
80bb62b9cc LibJS: Distinguish between statement and declaration
This separates matching/parsing of statements and declarations and
fixes a few edge cases where the parser would incorrectly accept a
declaration where only a statement is allowed - for example:

    if (foo) const a = 1;
    for (var bar;;) function b() {}
    while (baz) class c {}
2020-10-23 19:13:06 +02:00
Linus Groh
f8ae6fa713 LibJS: Disallow NumericLiteral immediately followed by Identifier
From the spec: https://tc39.es/ecma262/#sec-literals-numeric-literals

The SourceCharacter immediately following a NumericLiteral must not be
an IdentifierStart or DecimalDigit.

For example: 3in is an error and not the two input elements 3 and in.
2020-10-23 19:13:06 +02:00
Linus Groh
82ac936a9d LibJS: Check for exception after executing (do)while test expression
Otherwise we crash the interpreter when an exception is thrown during
evaluation of the while or do/while test expression - which is easily
caused by a ReferenceError - e.g.:

    while (someUndefinedVariable) {
        // ...
    }
2020-10-23 19:06:57 +02:00
Linus Groh
15642874f3 LibJS: Support all line terminators (LF, CR, LS, PS)
https://tc39.es/ecma262/#sec-line-terminators
2020-10-22 10:06:30 +02:00
Linus Groh
1e86379327 LibJS: Rest parameter in setter functions is a syntax error 2020-10-20 20:27:58 +02:00
Linus Groh
46cc1f718e LibJS: Unprefixed octal numbers are a syntax error in strict mode 2020-10-19 20:08:22 +02:00
Linus Groh
e898c98873 LibJS: Don't parse arrow function with newline between ) and =>
If there's a newline between the closing paren and arrow it's not a
valid arrow function, ASI should kick in instead (it'll then fail with
"Unexpected token Arrow")
2020-10-19 11:31:55 +02:00
Linus Groh
965d952ff3 LibJS: Share parameter parsing between regular and arrow functions
This simplifies try_parse_arrow_function_expression() and fixes a few
cases that should not produce an arrow function AST but did:

    (a,,) => {}
    (a b) => {}
    (a ...b) => {}
    (...b a) => {}

The new parsing logic checks whether parens are expected and uses
parse_function_parameters() if so, rolling back if a new syntax error
occurs during that. Otherwise it's just an identifier in which case we
parse the single parameter ourselves.
2020-10-19 11:31:55 +02:00
Linus Groh
2dbea60fe2 LibJS: Multiple 'default' clauses in switch statement are a syntax error 2020-10-19 11:30:14 +02:00
Linus Groh
f8886ef5ba LibJS: Handle continue in switch statement unwinding 2020-10-18 19:08:52 +02:00
Linus Groh
8f54edb7a0 LibJS: Handle return value in switch statement unwinding
Fixes #3790.
2020-10-18 19:08:52 +02:00
Stephan Unverwerth
2c888b3c6e LibJS: Fix parsing of invalid numeric literals
i.e. "1e" "0x" "0b" "0o" used to be parsed as valid literals.
They now produce invalid tokens. Fixes #3716
2020-10-18 15:38:57 +02:00
Linus Groh
a5bf6cfff9 LibJS: Don't change offset when reconfiguring property in unique shape
When changing the attributes of an existing property of an object with
unique shape we must not change the PropertyMetadata offset.
Doing so without resizing the underlying storage vector caused an OOB
write crash.

Fixes #3735.
2020-10-10 23:25:00 +02:00
Matthew Olsson
e8da5f99b1 LibJS: break or continue with nonexistent label is a syntax error 2020-10-08 23:27:16 +02:00
Matthew Olsson
6e05685ad4 LibJS: Fix return statements not working properly in loops
Previously, when a loop detected an unwind of type ScopeType::Function
(which means a return statement was executed inside of the loop), it
would just return undefined. This set the VM's last_value to undefined,
when it should have been the returned value. This patch makes all loop
statements return the appropriate value in the above case.
2020-10-08 23:23:55 +02:00
Matthew Olsson
d980073122 LibJS: Handle unwinding in while and do-while statements
For some reason, this was never added. So something like "while (true)
{ return }" would loop infinitely.
2020-10-08 23:23:55 +02:00
Matthew Olsson
e49ea1b520 LibJS: Disallow 'continue' & 'break' outside of their respective scopes
'continue' is no longer allowed outside of a loop, and an unlabeled
'break' is not longer allowed outside of a loop or switch statement.
Labeled 'break' statements are still allowed everywhere, even if the
label does not exist.
2020-10-08 10:20:49 +02:00
Linus Groh
bc78e4b7da LibJS: Fix PropertyName::from_value() for negative and non-int numbers
It was converting *any* number to an i32 index, which obviously is not
correct for negative ints, doubles, infinity and nan.

Fixes #3712.
2020-10-08 10:02:47 +02:00
Linus Groh
aa71dae03c LibJS: Implement logical assignment operators (&&=, ||=, ??=)
TC39 proposal, stage 4 as of 2020-07.
https://tc39.es/proposal-logical-assignment/
2020-10-05 17:57:26 +02:00
Linus Groh
2d4cd5b49b LibJS: Evaluate AssignmentExpression LHS before RHS according to the spec
Fixes #3689.
2020-10-05 14:34:37 +02:00
Linus Groh
f4d0babd5d LibJS: Make assignment to CallExpression a syntax error in strict mode 2020-10-05 09:25:04 +02:00
Linus Groh
283ee678f7 LibJS: Validate all assignment expressions, not just "="
The check for invalid lhs and assignment to eval/arguments in strict
mode should happen for all kinds of assignment expressions, not just
AssignmentOp::Assignment.
2020-10-05 09:25:04 +02:00
Matthew Olsson
6eb6752c4c LibJS: Strict mode is now handled by Functions and Programs, not Blocks
Since blocks can't be strict by themselves, it makes no sense for them
to store whether or not they are strict. Strict-ness is now stored in
the Program and FunctionNode ASTNodes. Fixes issue #3641
2020-10-04 10:46:12 +02:00
Nico Weber
ef1b21004f Everywhere: Fix typos
Mostly in comments, but sprintf() now prints "August" instead of
"Auguest" so that's something.
2020-10-02 16:03:17 +02:00
Linus Groh
c0e4353bde LibJS: Handle getter exception in JSONObject::serialize_json_property()
In the case of an exception in a property getter function we would not
return early, and a subsequent attempt to call the replacer function
would crash the interpreter due to call_internal() asserting.

Fixes #3548.
2020-09-19 14:17:22 +02:00
AnotherTest
21f513fe0f LibJS: Do not revisit already visited values in update_function_name()
Fixes #3471, adds a test.
2020-09-19 00:33:56 +02:00
Linus Groh
a9f5b0339d LibJS: Simplify toEval() implementation 2020-09-18 20:49:35 +02:00
Linus Groh
568d53c9b1 LibJS: Check validity of computed_property_name() result before using it
This fixes two cases obj[expr] and obj[expr]() (MemberExpression and
CallExpression respectively) when expr throws an exception and results
in an empty value, causing a crash by passing the invalid PropertyName
created by computed_property_name() to Object::get() without checking it
first.

Fixes #3459.
2020-09-12 11:29:39 +02:00
Linus Groh
75dac35d0e LibJS: Stop unwinding and reset exception for TryStatement finalizer
This fixes two issues with running a TryStatement finalizer:

- Temporarily store and clear the exception, if any, so we can run the
  finalizer block statement without it getting in our way, which could
  have unexpected side effects otherwise (and will likely return early
  somewhere).
- Stop unwinding so more than one child node of the finalizer
  BlockStatement is executed if an exception has been thrown previously
  (which would have called unwind(ScopeType::Try)). Re-throwing as
  described above ensures we still unwind after the finalizer, if
  necessary.

Also add some tests specifically for try/catch/finally blocks, we
didn't have any!
2020-09-12 09:31:16 +02:00
Linus Groh
ec43f73b74 LibJS: Extract most of Interpreter's run() into execute_statement()
Interpreter::run() was so far being used both as the "public API entry
point" for running a JS::Program as well as internally to execute
JS::Statement|s of all kinds - this is now more distinctly separated.
A program as returned by the parser is still going through run(), which
is responsible for creating the initial global call frame, but all other
statements are executed via execute_statement() directly.

Fixes #3437, a regression introduced by adding ASSERT(!exception()) to
run() without considering the effects that would have on internal usage.
2020-09-12 09:31:16 +02:00
Linus Groh
55c4866370 LibJS: Add tests for issue #3382 2020-09-01 21:35:59 +02:00
AnotherTest
8e89233bba LibJS: Demonstrate weird behaviour with 'break' 2020-08-28 20:19:56 +02:00
Nico Weber
2c1b84b3e1 LibJS: Add some more tests, mostly around leap years 2020-08-26 08:52:07 +02:00
Nico Weber
e4dac38127 JS Tests: Disable the one failing test when running test-js in Serenity 2020-08-25 21:23:10 +02:00
AnotherTest
54036d660a Meta: Move prettier config files to the root of the repository 2020-08-24 18:21:33 +02:00
Nico Weber
2191ec591f LibJS: Make Date's tuple constructor correctly handle out-of-range arguments
Milliseconds need extra handling, but everything else just works
now that mktime() handles this case.
2020-08-24 18:20:07 +02:00
Nico Weber
84f729c2b4 LibJS+LibC: Add tests for Date tuple ctor overflow and make mktime()/timegm() handle month overflow 2020-08-24 09:30:11 +02:00
Nico Weber
ad00462daa LibJS: Implement Date.getUTC*
Test files created with:
    $ for f in Libraries/LibJS/Tests/builtins/Date/Date.prototype.get*js; do
          cp $f $(echo $f | sed -e 's/get/getUTC/') ;
      done
    $ rm Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCTime.js
    $ git add Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTC*.js
    $ ls Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTC*.js | \
          xargs sed -i -e 's/get/getUTC/g'
2020-08-23 22:00:05 +02:00
Nico Weber
5f595e7e1b LibC: Make localtime() and gmtime() handle years before 1970
Year computation has to be based on seconds, not days, in case
t is < 0 but t / __seconds_per_day is 0.

Year computation also has to consider negative timestamps.

With this, days is always positive and <= the number of days in the
year, so base the tm_wday computation directly on the timestamp,
and do it first, before t is modified in the year computation.
In C, % can return a negative number if the left operand is negative,
compensate for that.

Tested via test-js. (Except for tm_wday, since we don't implement
Date.prototype.getUTCDate() yet.)
2020-08-23 10:42:37 +02:00
Nico Weber
cec467fe35 LibJS: Enable Date.parse.js tests that pass after c399caf27f 2020-08-23 10:42:37 +02:00
Nico Weber
c399caf27f LibC: Make mktime() and timegm() handle years before 1970
And also years that don't fit in 32-bit.

Lovingly tested via LibJS's Date.UTC(), which happens to call
timegm().
2020-08-22 10:53:33 +02:00
Nico Weber
96891669c3 test-js: Sometimes include more details for failures
LibJS doesn't store stacks for exception objects, so this
only amends test-common.js's __expect() with an optional
`details` function that can produce a more detailed error
message, and it lets test-js.cpp read and print that
error message.  I added the optional details parameter to
a few matchers, most notably toBe() where it now prints
expected and actual value.

It'd be nice to have line numbers of failures, but that
seems hard to do with the current design, and this is already
much better than the current state.
2020-08-22 10:52:40 +02:00
Nico Weber
ebd510ef5e LibJS: Allow conversion from Symbol to String via explicit String() call
https://tc39.es/ecma262/#sec-string-constructor-string-value has an
explicit special case for Symbols allowing this:

    If NewTarget is undefined and Type(value) is Symbol,
    return SymbolDescriptiveString(value).
2020-08-22 10:52:40 +02:00
Nico Weber
116c0c0ab3 LibJS: Implement Date's string constructor
... by calling Date.parse().

With this, dates on http://45.33.8.238/ and
http://45.33.8.238/linux/summary.html are correctly converted to local
time :^)
2020-08-21 21:12:54 +02:00
Nico Weber
6e5aa5d5df LibJS: Implement Date.parse()
The spec says Date.parse() should accept at least a simplified form
of ISO 8601, so that's all this implements.
2020-08-21 21:12:54 +02:00
Nico Weber
a6b68451dc LibJS: Implement Date.prototype.toISOString() 2020-08-21 12:11:48 +02:00
Nico Weber
1eac1b360b LibJS: Implement Date.UTC() 2020-08-21 12:11:48 +02:00
Nico Weber
d4d9222eea LibJS: Basic implementation of most of Date's constructor arguments
The constructor with a string argument isn't implemented yet, but
this implements the other variants.

The timestamp constructor doens't handle negative timestamps correctly.

Out-of-bound and invalid arguments aren't handled correctly.
2020-08-20 20:53:43 +02:00
Nico Weber
8ebef785eb LibJS: Implement basic functionality of Array.from()
The optional 2nd and 3rd arguments are not yet implemented.

This assumes that `this` is the Array constructor and doesn't yet
implement the more general behavior in the ES6 spec that allows
transferring this method to other constructors.
2020-08-17 21:23:11 +02:00
Nico Weber
79a5ba58a5 LibJS: Add tests for bitwise & and ^
And fix some edge case conversion bugs found by the tests.
2020-07-23 13:06:49 +02:00
Nico Weber
9e32ad6c99 LibJS: Fix \x escapes of bytes with high bit set
With this, typing `"\xff"` into Browser's console no longer
makes the app crash.

While here, also make the \u handler call append_codepoint()
instead of calling an overload where it's not immediately clear
which overload is getting called. This has no behavior change.
2020-07-22 19:21:35 +02:00