Commit graph

646 commits

Author SHA1 Message Date
Andreas Kling
340a115dfe LibJS: Make native function/property callbacks take VM, not Interpreter
More work on decoupling the general runtime from Interpreter. The goal
is becoming clearer. Interpreter should be one possible way to execute
code inside a VM. In the future we might have other ways :^)
2020-09-27 20:26:58 +02:00
Andreas Kling
1ff9d33131 LibJS: Make Function::call() not require an Interpreter&
This makes a difference inside ScriptFunction::call(), which will now
instantiate a temporary Interpreter if one is not attached to the VM.
2020-09-27 20:26:58 +02:00
Andreas Kling
be31805e8b LibJS: Move scope stack from VM back to Interpreter
Okay, my vision here is improving. Interpreter should be a thing that
executes an AST. The scope stack is irrelevant to the VM proper,
so we can move that to the Interpreter. Same with execute_statement().
2020-09-27 20:26:58 +02:00
Andreas Kling
6861c619c6 LibJS: Move most of Interpreter into VM
This patch moves the exception state, call stack and scope stack from
Interpreter to VM. I'm doing this to help myself discover what the
split between Interpreter and VM should be, by shuffling things around
and seeing what falls where.

With these changes, we no longer have a persistent lexical environment
for the current global object on the Interpreter's call stack. Instead,
we push/pop that environment on Interpreter::run() enter/exit.
Since it should only be used to find the global "this", and not for
variable storage (that goes directly into the global object instead!),
I had to insert some short-circuiting when walking the environment
parent chain during variable lookup.

Note that this is a "stepping stone" commit, not a final design.
2020-09-27 20:26:58 +02:00
Ben Wiederhake
08f9bc26a6 Meta+LibHTTP through LibWeb: Make clang-format-10 clean 2020-09-25 21:18:17 +02:00
Andreas Kling
69bbf0285b LibJS: Let the VM cache an empty ("") PrimitiveString
Empty string is extremely common and we can avoid a lot of heap churn
by simply caching one in the VM. Primitive strings are immutable anyway
so there is no observable behavior change outside of fewer collections.
2020-09-22 20:10:20 +02:00
Andreas Kling
d1b58ee9ad LibJS: Move well-known symbols to the VM
No need to instantiate unique symbols for each Interpreter; they can
be VM-global. This reduces the memory cost and startup time anyway.
2020-09-22 20:10:20 +02:00
Andreas Kling
676cb87a8f LibJS: Use VM::exception() instead of Interpreter::exception() a bunch
There's a lot more of these things to fix. We'll also want to move from
passing Interpreter& around to VM& instead wherever that is enough.
2020-09-22 20:10:20 +02:00
Andreas Kling
d74bb87d46 LibJS: Add a way to get from a Cell to the VM 2020-09-22 20:10:20 +02:00
Andreas Kling
4a8bfcdd1c LibJS: Move the current exception from Interpreter to VM
This will allow us to throw exceptions even when there is no active
interpreter in the VM.
2020-09-22 20:10:20 +02:00
Andreas Kling
5b6ccbb918 LibJS: VM::interpreter() should just assert when no active interpreter
I accidentally committed some code here to force a crash, but this
should just assert.
2020-09-21 14:42:26 +02:00
Andreas Kling
df3ff76815 LibJS: Rename InterpreterScope => InterpreterExecutionScope
To make it a little clearer what this is for. (This is an RAII helper
class for adding and removing an Interpreter to a VM's list of the
currently active (executing code) Interpreters.)
2020-09-21 14:35:12 +02:00
Andreas Kling
fbe2907510 LibJS: GC should gather roots from all active interpreters
If we are in a nested execution context, we shouldn't only mark things
used by the active interpreter.
2020-09-21 14:34:40 +02:00
Andreas Kling
1c43442be4 LibJS+Clients: Add JS::VM object, separate Heap from Interpreter
Taking a big step towards a world of multiple global object, this patch
adds a new JS::VM object that houses the JS::Heap.

This means that the Heap moves out of Interpreter, and the same Heap
can now be used by multiple Interpreters, and can also outlive them.

The VM keeps a stack of Interpreter pointers. We push/pop on this
stack when entering/exiting execution with a given Interpreter.
This allows us to make this change without disturbing too much of
the existing code.

There is still a 1-to-1 relationship between Interpreter and the
global object. This will change in the future.

Ultimately, the goal here is to make Interpreter a transient object
that only needs to exist while you execute some code. Getting there
will take a lot more work though. :^)

Note that in LibWeb, the global JS::VM is called main_thread_vm(),
to distinguish it from future worker VM's.
2020-09-20 19:24:44 +02:00
Andreas Kling
976e55e942 LibJS: Remove some unnecessary indirection in Object constructors 2020-09-20 19:18:05 +02:00
Andreas Kling
893df28e80 LibJS: Don't allocate property table during GC marking phase
Shape was allocating property tables inside visit_children(), which
could cause garbage collection to happen. It's not very good to start
a new garbage collection while you are in the middle of one already.
2020-09-20 19:11:49 +02:00
Andreas Kling
4036ff9d91 LibJS: Remove unused argument in NativeFunction constructor 2020-09-20 19:11:11 +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
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
Andreas Kling
d830c107ce LibJS: Deal with a FIXME in Shape::ensure_property_table()
Prevent GC while messing with the shape transition chain.
2020-09-09 21:34:02 +02:00
Andreas Kling
d467a0ffef LibJS: ArrayIterator needs to mark the array it's iterating 2020-09-08 16:20:34 +02:00
Andreas Kling
3143fea1eb LibJS: GlobalObject needs to mark the iterator prototypes
Otherwise they all disappear in the first garbage collection.
2020-09-08 15:37:39 +02:00
Andreas Kling
b32c0c8181 LibJS: Convert two suspicious Vector<Value> to MarkedValueList 2020-09-08 14:16:59 +02:00
Andreas Kling
d85eed585c LibJS: get_iterator_values() should pass Value to callback (not Value&)
Value& implies that the callback is expected/able to modify the value,
which is not the case.
2020-09-08 14:15:13 +02:00
AnotherTest
699e1fdc07 LibJS: Eliminate some (unnecessary) Vector copies 2020-09-08 13:43:03 +02:00
AnotherTest
8d9c5a8e70 LibJS: Make MarkedValueList inherit from Vector<Value>
This makes the nicer vector API available to MVL without extra wrapper
functions.
2020-09-08 13:43:03 +02:00
AnotherTest
9a00699983 LibJS: Format IndexedProperties.cpp 2020-09-08 13:43:03 +02:00
Linus Groh
b27d90db1f LibJS: Actually change size in generic storage's set_array_like_size()
Looks like an oversight to me - we were not actually setting a new value
for m_array_size, which would cause arrays created with generic storage
to report a .length of 0.
2020-09-01 21:35:59 +02:00
Linus Groh
ae9d64e544 LibJS: Let set_array_like_size() switch to generic storage if necessary
This is already considered in put()/insert()/append_all() but not
set_array_like_size(), which crashed the interpreter with an assertion
when creating an array with more than SPARSE_ARRAY_THRESHOLD (200)
initial elements as the simple storage was being resized beyond its
limit.

Fixes #3382.
2020-09-01 21:35:59 +02:00
Ben Wiederhake
d8e22fedc3 Libraries: Unbreak building with extra debug macros 2020-08-30 09:43:49 +02:00
Ben Wiederhake
9f7ec33180 Meta: Force semi-colon after MAKE_AK_NONXXXABLE()
Before, we had about these occurrence counts:
COPY: 13 without, 33 with
MOVE: 12 without, 28 with

Clearly, 'with' was the preferred way. However, this introduced double-semicolons
all over the place, and caused some warnings to trigger.

This patch *forces* the usage of a semi-colon when calling the macro,
by removing the semi-colon within the macro. (And thus also gets rid
of the double-semicolon.)
2020-08-27 10:12:04 +02:00
AnotherTest
394e4c04cd LibJS: Add a helper for calling JS::Function's with arguments
The fact that a `MarkedValueList` had to be created was just annoying,
so here's an alternative.
This patchset also removes some (now) unneeded MarkedValueList.h includes.
2020-08-26 08:45:01 +02:00
Linus Groh
9ea6ef4ed1 LibJS: Make Interpreter::throw_exception() a void function
The motivation for this change is twofold:

- Returning a JS::Value is misleading as one would expect it to carry
  some meaningful information, like maybe the error object that's being
  created, but in fact it is always empty. Supposedly to serve as a
  shortcut for the common case of "throw and return empty value", but
  that's just leading us to my second point.
- Inconsistent usage / coding style: as of this commit there are 114
  uses of throw_exception() discarding its return value and 55 uses
  directly returning the call result (in LibJS, not counting LibWeb);
  with the first style often having a more explicit empty value (or
  nullptr in some cases) return anyway.
  One more line to always make the return value obvious is should be
  worth it.

So now it's basically always these steps, which is already being used in
the majority of cases (as outlined above):

- Throw an exception. This mutates interpreter state by updating
  m_exception and unwinding, but doesn't return anything.
- Let the caller explicitly return an empty value, nullptr or anything
  else itself.
2020-08-25 18:30:31 +02:00
Nico Weber
697faba147 LibJS: Make Date.getUTCSeconds() call through to LibC
The tzset documentation says that TZ allows a per-second local timezone,
so don't be needlessly clever here.

No observable behavior difference at this point, but if we ever
implement tzset, this will have a small effect.
2020-08-24 18:21:16 +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
d5eaefe87b LibJS: Move datetime access out of DatePrototype
How Date keeps time internally should be an implementation detail
of Date, so move it behind accessors.

No behavior change.
2020-08-23 22:00:05 +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
c8cf465174 LibJS: Implement Date.valueOf()
It does exactly the same thing as Date.getTime().
2020-08-21 16:03:34 +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
a3908732ad LibJS: Add toLocaleString(), toLocaleDateString(), toLocaleTimeString() to Date
These just return a "readable" implementation of the date for now.
2020-08-17 21:23:11 +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
Andreas Kling
6444f49d22 LibJS: Make StringOrSymbol not leak strings
Ideally this thing would not allocate strings at all, but I'll leave
that as a separate exercise.
2020-08-16 20:31:05 +02:00
Andreas Kling
bbe2d4a2d9 LibJS+LibWeb: Clear exceptions after call'ing JavaScript functions
Decorated Interpreter::call() with [[nodiscard]] to provoke thinking
about the returned value at each call site. This is definitely not
perfect and we should really start thinking about slimming down the
public-facing LibJS interpreter API.

Fixes #3136.
2020-08-14 17:31:07 +02:00
Nico Weber
ce95628b7f Unicode: Try s/codepoint/code_point/g again
This time, without trailing 's'. Ran:

    git grep -l 'codepoint' | xargs sed -ie 's/codepoint/code_point/g
2020-08-05 22:33:42 +02:00
Nico Weber
19ac1f6368 Revert "Unicode: s/codepoint/code_point/g"
This reverts commit ea9ac3155d.
It replaced "codepoint" with "code_points", not "code_point".
2020-08-05 22:33:42 +02:00
Melissa Goad
192b2383ac LibJS: The Math.ceil() of a number between -1 and 0 should be -0,
according to the spec.
2020-08-04 11:31:11 +02:00
Andreas Kling
ea9ac3155d Unicode: s/codepoint/code_point/g
Unicode calls them "code points" so let's follow their style.
2020-08-03 19:06:41 +02:00
Andreas Kling
3ee6ed965f LibJS: Use allocate_without_global_object for primitive cell types
More steps towards multiple global object support. Primitive cells
like strings, bigints, etc, don't actually have any connection to
the global object. Use the explicit API to clarify this.
2020-07-25 13:12:17 +02:00
Andreas Kling
aaf6014ae1 LibJS: Simplify Cell::initialize()
Remove the Interpreter& argument and pass only GlobalObject&. We can
find everything we need via the global object anyway.
2020-07-23 17:31:08 +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
b9ce56aee6 LibWeb: Make btoa() and atob() correctly handle values between 128 and 255
btoa() takes a byte string, so it must decode the UTF-8 argument into
a Vector<u8> before calling encode_base64.

Likewise, in atob() decode_base64 returns a byte string, so that needs
to be converted to UTF-8.

With this, `btoa(String.fromCharCode(255))` is '/w==' as it should
be, and `atob(btoa(String.fromCharCode(255))) == String.fromCharCode(255)`
remains true.
2020-07-22 19:22:00 +02:00
Nico Weber
248b79d687 LibJS: Add FIXMEs to a few functions that need UTF-16 handling 2020-07-22 17:26:34 +02:00
Nico Weber
979e02c0a8 LibJS: Implement String.prototype.charCodeAt
It's broken for strings with characters outside 7-bit ASCII, but
it's broken in the same way as several existing functions (e.g.
charAt()), so that's probably ok for now.
2020-07-22 15:48:01 +02:00
Matthew Olsson
02305d01ea LibJS: Add Number.prototype.toString 2020-07-15 18:24:55 +02:00
Matthew Olsson
b0296735a5 LibJS: Implement Symbol.hasInstance 2020-07-14 20:15:19 +02:00
Matthew Olsson
dd49ec17a2 LibJS: Implement spec-complient instance_of operation 2020-07-14 20:15:19 +02:00
Matthew Olsson
a51b2393f2 LibJS: Integrate iterator protocol into language features
Finally use Symbol.iterator protocol in language features :) currently
only used in for-of loops and spread expressions, but will have more
uses later (Maps, Sets, Array.from, etc).
2020-07-14 17:58:42 +02:00
Matthew Olsson
c831fb17bf LibJS: Add StringIterator 2020-07-13 15:07:29 +02:00
Matthew Olsson
43d955014d LibJS: Implement Symbol.toStringTag 2020-07-11 23:13:29 +02:00
Matthew Olsson
5ecd504f4e LibJS: Implement spec-compliant Object.prototype.toString 2020-07-11 23:13:29 +02:00
Matthew Olsson
531fdb2e82 LibJS: Prefer "define_property" over "put" 2020-07-11 18:54:13 +02:00
Matthew Olsson
c485c86015 LibJS: Use macros to enumerate well-known symbols
Not only is this a much nicer api (can't pass a typo'd string into the
get_well_known_symbol function), it is also a bit more performant since
there are no hashmap lookups.
2020-07-11 18:54:13 +02:00
Matthew Olsson
2ea85355fe LibJS: Start implementing iterable framework, add ArrayIterator
With the addition of symbol keys, work can now be done on starting to
implement the well-known symbol functionality. The most important of
these well-known symbols is by far Symbol.iterator.

This patch adds IteratorPrototype, as well as ArrayIterator and
ArrayIteratorPrototype. In the future, sometime after StringIterator has
also been added, this will allow us to use Symbol.iterator directly in
for..of loops, enabling the use of custom iterator objects. Also makes
adding iterator support to native objects much easier (as will have to
be done for Map and Set, when they get added).
2020-07-11 18:54:13 +02:00
Matthew Olsson
51bfc6c6b3 LibJS: Renamed Object::GetOwnPropertyReturnMode to Object::PropertyKind
This enum will be used by iterators, so it makes sense to use a more
general name.
2020-07-11 18:54:13 +02:00
Linus Groh
7241b9ca0c LibJS: Remove a few superfluous exception checks
We don't need to check for exceptions when defining properties on an
array we literally created ourselves a few lines earlier.
2020-07-11 18:38:51 +02:00
Matthew Olsson
7a1d485b19 LibJS: Integrate Symbols into objects as valid keys
This allows objects properties to be created for symbol keys in addition
to just plain strings/numbers
2020-07-09 23:33:00 +02:00
Matthew Olsson
d9db6bec42 LibJS: Move global symbol map from SymbolObject to Interpreter
This allows different instances of the Interpreter to have their own
global symbols. Also makes Symbol non-copyable and non-moveable.
2020-07-09 23:29:28 +02:00
Matthew Olsson
93ebd320ef LibJS: Object.preventExtensions should allow property modfication
Existing properties on a non-extensible object should be changable and
deletable.
2020-07-07 10:47:10 +02:00
Matthew Olsson
26acc8ba88 LibJS/test-js: Clean up test-js code
This commit also exposes JSONObject's implementation of stringify to the
public, so that it can be used by test-js without having to go through
the interpreter's environment.
2020-07-06 23:40:35 +02:00
Matthew Olsson
4c6fd49169 LibJS: Fix String.raw.length 2020-07-06 23:40:35 +02:00
Matthew Olsson
5e971c91e3 LibJS: Hide some debug output behind flags
This hides some Object.cpp output, as well as removing the "debugger"
debug output.
2020-07-06 23:40:35 +02:00
Matthew Olsson
21064a1883 LibJS: Use correct MarkedValueList append method 2020-07-03 19:30:13 +02:00
Matthew Olsson
bda39ef7ab LibJS: Explicitly pass a "Function& new_target" to Function::construct
This allows the proxy handler to pass the proper new.target to construct
handlers.
2020-07-01 11:16:37 +02:00
Matthew Olsson
98323e19e5 LibJS: Implement Proxy [[Call]] and [[Construct]] traps
In order to do this, Proxy now extends Function rather than Object, and
whether or not it returns true for is_function() depends on it's
m_target.
2020-07-01 11:16:37 +02:00
Jack Karamanian
7533fd8b02 LibJS: Initial class implementation; allow super expressions in object
literal methods; add EnvrionmentRecord fields and methods to
LexicalEnvironment

Adding EnvrionmentRecord's fields and methods lets us throw an exception
when |this| is not initialized, which occurs when the super constructor
in a derived class has not yet been called, or when |this| has already
been initialized (the super constructor was already called).
2020-06-29 17:54:54 +02:00
Jack Karamanian
a535d58cac LibJS: Add Object::define_accessor()
This is a helper function based on the getter/setter definition logic from
ObjectExpression::execute() to look up an Accessor property if it already
exists, define a new Accessor property if it doesn't exist, and set the getter or
setter function on the Accessor.
2020-06-29 17:54:54 +02:00
Jack Karamanian
949bffdc93 LibJS: Define the "constructor" property on ScriptFunction's prototype
and set it to the current function
2020-06-29 17:54:54 +02:00
Andreas Kling
200481efb2 LibJS: to_string_without_side_effects() should handle NativeProperty 2020-06-26 00:53:25 +02:00
Linus Groh
afcfea2001 LibJS: Handle "receiver" argument in Reflect.{get,set}() 2020-06-25 15:51:47 +02:00
Andreas Kling
675e7c0e6f LibJS: Explicitly invoke Cell constructor in Object(Object& prototype) 2020-06-23 18:28:28 +02:00
Andreas Kling
0166a1fa74 LibJS: Make NativeProperty a plain Cell instead of an Object
This removes the need for NativeProperty objects to have a prototype,
which just made things confusing.
2020-06-23 17:56:57 +02:00
Andreas Kling
ba641e97d9 LibJS: Clarify Object (base class) construction somewhat
Divide the Object constructor into three variants:

- The regular one (takes an Object& prototype)
- One for use by GlobalObject
- One for use by objects without a prototype (e.g ObjectPrototype)
2020-06-23 17:21:53 +02:00
Andreas Kling
fc4ed8d444 LibWeb: Make wrapper factory functions take JS::GlobalObject&
Instead of taking the JS::Heap&. This allows us to get rid of some
calls to JS::Interpreter::global_object(). We're getting closer and
closer to multiple global objects. :^)
2020-06-23 16:57:39 +02:00
Andreas Kling
9ce25bbf1d LibWeb: Generate CanvasRenderingContext2D bindings from IDL :^)
We're still missing optional argument support, so this implementation
doesn't support fill(), only fill(fill_rule).

Still it's really nice to get rid of so much hand-written wrapper code.
2020-06-22 19:07:25 +02:00
stelar7
9e18005c64 LibJS: expose some more math functions 2020-06-22 10:33:50 +02:00
Andreas Kling
af51dc105a LibJS+LibWeb: Add JS::Object::inherits(class_name)
To allow implementing the DOM class hierarchy in JS bindings, this
patch adds an inherits() function that can be used to ask an Object
if it inherits from a specific C++ class (by name).

The necessary overrides are baked into each Object subclass by the
new JS_OBJECT macro, which works similarly to C_OBJECT in LibCore.

Thanks to @Dexesttp for suggesting this approach. :^)
2020-06-21 15:15:52 +02:00
Andreas Kling
94fdf4fa5a LibWeb+LibJS: Add a naive way to check if a wrapper "is" a certain type
Instead of only checking the class_name(), we now generate an is_foo()
virtual in the wrapper generator. (It's currently something we override
on Bindings::Wrapper, which is not really scalable.)

Longer term we'll need to think up something smarter for verifying that
one wrapper "is" another type of wrapper.
2020-06-21 00:58:55 +02:00
Andreas Kling
3ba17d8df7 LibJS: Make Interpreter::construct() take a GlobalObject& 2020-06-20 17:53:33 +02:00
Andreas Kling
2fe4285693 LibJS: Object::initialize() overrides must always call base class 2020-06-20 17:50:48 +02:00
Andreas Kling
e1f9da142e LibJS: NativeProperty get/put should take a GlobalObject& 2020-06-20 17:50:48 +02:00
Andreas Kling
06e29fac57 LibJS: Split more native object constructors into construct/initialize 2020-06-20 17:50:48 +02:00
Andreas Kling
9610d18ebb LibJS: Remove some Interpreter::global_object() calls in JSONObject 2020-06-20 17:50:48 +02:00
Andreas Kling
32c121a8f7 LibJS: Pass GlobalObject& to Reference get/put 2020-06-20 17:50:48 +02:00
Andreas Kling
8d56e6103e LibJS: Make Value::to_object() take a GlobalObject& 2020-06-20 17:50:48 +02:00
Andreas Kling
cd14ebb11f LibJS: More Interpreter::global_object() removal
Also let's settle on calling the operation of fetching the "this" value
from the Interpreter and converting it to a specific Object pointer
typed_this() since consistency is nice.
2020-06-20 17:50:48 +02:00
Andreas Kling
a9e4babdaf LibJS: Pass GlobalObject& when constructing an Accessor 2020-06-20 17:50:48 +02:00
Andreas Kling
64513f3c23 LibJS: Move native objects towards two-pass construction
To make sure that everything is set up correctly in objects before we
start adding properties to them, we split cell allocation into 3 steps:

1. Allocate a cell of appropriate size from the Heap
2. Call the C++ constructor on the cell
3. Call initialize() on the constructed object

The job of initialize() is to define all the initial properties.
Doing it in a second pass guarantees that the Object has a valid Shape
and can find its own GlobalObject.
2020-06-20 15:46:30 +02:00
Andreas Kling
e4add19915 LibJS: Pass GlobalObject& to native functions and property accessors
More work towards supporting multiple global objects. Native C++ code
now get a GlobalObject& and don't have to ask the Interpreter for it.

I've added macros for declaring and defining native callbacks since
this was pretty tedious and this makes it easier next time we want to
change any of these signatures.
2020-06-20 15:45:07 +02:00
Andreas Kling
4aa98052ca LibJS: Remove some more use of Interpreter::global_object()
Let's do some more work towards supporting multiple global objects.
2020-06-20 15:45:07 +02:00
Matthew Olsson
b155e64b67 LibJS: Add JSON.parse 2020-06-13 12:43:22 +02:00
Matthew Olsson
39576b2238 LibJS: Add JSON.stringify 2020-06-13 12:43:22 +02:00
Andreas Kling
fdfda6dec2 AK: Make string-to-number conversion helpers return Optional
Get rid of the weird old signature:

- int StringType::to_int(bool& ok) const

And replace it with sensible new signature:

- Optional<int> StringType::to_int() const
2020-06-12 21:28:55 +02:00
Matthew Olsson
78155a6668 LibJS: Consolidate error messages into ErrorTypes.h
Now, exceptions can be thrown with
interpreter.throw_exception<T>(ErrorType:TYPE, "format", "args",
"here").
2020-06-11 07:46:20 +02:00
Andreas Kling
5042e560ef LibJS: Make more Interpreter functions take a GlobalObject& 2020-06-08 21:25:16 +02:00
Andreas Kling
053863f35e LibJS: Interpreter::this_value() => this_value(GlobalObject&)
Once the Interpreter has no global object attached to it, we have to
provide it everywhere.
2020-06-08 21:12:20 +02:00
Andreas Kling
25f2a29d84 LibJS: Pass GlobalObject& to AST node execute() functions
More work towards supporting multiple global objects.
2020-06-08 21:12:20 +02:00
Andreas Kling
affc479e83 LibJS+LibWeb: Remove a bunch of calls to Interpreter::global_object()
Objects should get the GlobalObject from themselves instead. However,
it's not yet available during construction so this only switches code
that happens after construction.

To support multiple global objects, Interpreter needs to stop holding
on to "the" global object and let each object graph own their global.
2020-06-08 12:25:45 +02:00
Andreas Kling
ff8bb962b6 LibJS: Always keep a reference to the global object in Shape
We need to move towards supporting multiple global objects, which will
be a large refactoring. To keep it manageable, let's do it in steps,
starting with giving Object a way to find the GlobalObject it lives
inside by asking its Shape for it.
2020-06-08 12:15:58 +02:00
Andreas Kling
10aebabf0b LibJS: BigInts and Symbols values are cells and the GC needs this info
Make Value::is_cell() return true for BigInts and Symbols. This makes
all the tests pass when running run-tests.sh -g (GC after every alloc.)
2020-06-08 12:08:51 +02:00
Matthew Olsson
4e33fbdb67 LibJS: Add interpreter exception checks 2020-06-08 09:57:29 +02:00
Linus Groh
0ff9d7e189 LibJS: Add BigInt 2020-06-07 19:29:40 +02:00
Linus Groh
5b88aa8e96 LibJS: Move Value::as_accessor() to Value.h 2020-06-07 19:29:40 +02:00
Linus Groh
5a983c238b LibJS: Use switch/case for Value::to_{string{_w/o_side_effects},boolean}
This makes them a bit more compact and improves consistency as
to_boolean() and to_number() already use this style as well.

Also re-order the types to match the table in the spec document.
2020-06-07 19:29:40 +02:00
Linus Groh
9f399f7341 LibJS: Remove reduntant set_prototype() calls
If we're inheriting from Object() we already call its constructor which
sets the prototype - no need to do it again.
2020-06-07 19:29:40 +02:00
Matthew Olsson
61ac1d3ffa LibJS: Lex and parse regex literals, add RegExp objects
This adds regex parsing/lexing, as well as a relatively empty
RegExpObject. The purpose of this patch is to allow the engine to not
get hung up on parsing regexes. This will aid in finding new syntax
errors (say, from google or twitter) without having to replace all of
their regexes first!
2020-06-07 19:06:55 +02:00
Matthew Olsson
39ad42defd LibJS: Add Proxy objects
Includes all traps except the following: [[Call]], [[Construct]],
[[OwnPropertyKeys]].

An important implication of this commit is that any call to any virtual
Object method has the potential to throw an exception. These methods
were not checked in this commit -- a future commit will have to protect
these various method calls throughout the codebase.
2020-06-06 22:13:01 +02:00
Matthew Olsson
58a72e9b81 LibJS: Value.in uses has_property instead of get().is_empty() 2020-06-06 22:13:01 +02:00
Matthew Olsson
24430b3860 LibJS: Object.setPrototypeOf throws error on too few arguments 2020-06-06 22:13:01 +02:00
Matthew Olsson
79958f4520 LibJS: Add PropertyDescriptor object
This new struct is now returned from get_own_property_descriptor. To
preserve the old functionality of returning an object, there is now a
get_own_property_descriptor_object method, for use in
{Object,Reflect}.getOwnPropertyDescriptor().

This change will be useful for the implementation of Proxies, which do a
lot of descriptor checks. We want to avoid as many object gets and puts
as possible.
2020-06-06 22:13:01 +02:00
Matthew Olsson
5ad5322f6a LibJS: Distinguish between omitted descriptor attributes and false ones
When calling Object.defineProperty, there is now a difference between
omitting a descriptor attribute and specifying that it is false. For
example, "{}" and "{ configurable: false }" will have different
attribute values.
2020-06-06 22:13:01 +02:00
Linus Groh
ead76377b0 LibM: Add INFINITY macro 2020-06-04 15:45:11 +02:00
Linus Groh
8a94813007 LibM: Add NAN macro 2020-06-04 15:45:11 +02:00
Jack Karamanian
b0932b0aec LibJS: Allow null or undefined as a bound |this| value in strict mode 2020-06-03 08:19:03 +02:00
Linus Groh
4f6912c605 LibJS: Store basic traceback in Exception
Nothing fancy like line numbers, but Exception now stores a list of
function names up to the current call frame.
2020-06-02 15:22:34 +02:00
Linus Groh
b32761f2e0 LibJS: Consider non-extensible objects in Reflect.setPrototypeOf() 2020-06-02 13:51:02 +02:00
Linus Groh
c1248a7fd8 LibJS: Implement Reflect.{isExtensible,preventExtensions}() 2020-06-02 13:51:02 +02:00
Linus Groh
b958e4f573 LibJS: Disallow changing the prototype of non-extensible objects
Object::set_prototype() now returns a boolean indicating success.
Setting the prototype to an identical object is always considered
successful, even if the object is non-extensible.
2020-06-02 13:51:02 +02:00
Linus Groh
8cf1ded478 LibJS: Don't assume Object.setPrototypeOf() prototype value is an object
We're crashing otherwise. Also it was not possible to set the prototype
to null.
2020-06-02 13:51:02 +02:00
Linus Groh
1a64bdd80c LibJS: Return specified object from Object.setPrototypeOf()
We were leaking an empty value.
2020-06-02 13:51:02 +02:00
Matthew Olsson
d5ae73a63b LibJS: Add Object.{isExtensible,preventExtensions}() 2020-06-02 08:50:26 +02:00
Sergey Bugaev
53a94b8bbd LibJS: Fix casting a value to ScriptFunction without checking it's one 2020-06-01 17:37:44 +02:00
Linus Groh
e33820b557 LibJS: Add String.fromCharCode() 2020-05-31 02:19:52 +02:00
Jack Karamanian
3ffb0a4e87 LibJS: Throw a TypeError when an arrow function is used as a constructor 2020-05-30 10:33:24 +02:00
Jack Karamanian
1110b1b444 LibJS: Don't define the "prototype" property for arrow functions 2020-05-30 10:33:24 +02:00
Jack Karamanian
45ccd9f8d9 LibJS: Set the bound |this| value to the |this| value of the current
scope for arrow functions
2020-05-30 10:33:24 +02:00
Jack Karamanian
c12125fa81 LibJS: Track whether ScriptFunctions and FunctionExpressions are arrow
functions
2020-05-30 10:33:24 +02:00
Jack Karamanian
5243e9974d LibJS: Remove unnecessary explicit from the 3 argument Function
constructor
2020-05-30 10:33:24 +02:00
Matthew Olsson
4e331a1fcf LibJS: Object.getOwnPropertyDescriptor works properly with accessors 2020-05-30 10:32:52 +02:00
Linus Groh
688ca7b196 LibJS: Make Object::invoke() non-const
As suggested in #2431's code review.
2020-05-29 15:55:40 +02:00
Linus Groh
1dd44210b7 LibJS: Add Array.prototype.toLocaleString() 2020-05-29 08:00:02 +02:00
Linus Groh
70d2add22f LibJS: Add Object.prototype.toLocaleString() 2020-05-29 08:00:02 +02:00
Linus Groh
9755f8d297 LibJS: Add Object::invoke() 2020-05-29 08:00:02 +02:00
Emanuele Torre
937d0be762 Meta: Add a script check the presence of "#pragma once" in header files
.. and make travis run it.

I renamed check-license-headers.sh to check-style.sh and expanded it so
that it now also checks for the presence of "#pragma once" in .h files.

It also checks the presence of a (single) blank line above and below the
"#pragma once" line.

I also added "#pragma once" to all the files that need it: even the ones
we are not check.
I also added/removed blank lines in order to make the script not fail.

I also ran clang-format on the files I modified.
2020-05-29 07:59:45 +02:00
Linus Groh
8ff4587f65 LibJS: Throw in strict mode when assigning property to primitive value 2020-05-29 07:45:22 +02:00
Marcin Gasperowicz
eadce65e04
LibJS: Implement standard semantics for relational operators (#2417)
Previously, the relational operators where casting any value to double
and comparing the results according to C++ semantics.

This patch makes the relational operators in JS behave according to the
standard specification.

Since we don't have BigInt yet, the implementation doesn't take it into
account. 

Moved PreferredType from Object to Value. Value::to_primitive now
passes preferred_type to Object::to_primitive.
2020-05-28 17:19:59 +02:00
Matthew Olsson
5ae9419a06 LibJS: Object index properties have descriptors; Handle sparse indices
This patch adds an IndexedProperties object for storing indexed
properties within an Object. This accomplishes two goals: indexed
properties now have an associated descriptor, and objects now gracefully
handle sparse properties.

The IndexedProperties class is a wrapper around two other classes, one
for simple indexed properties storage, and one for general indexed
property storage. Simple indexed property storage is the common-case,
and is simply a vector of properties which all have attributes of
default_attributes (writable, enumerable, and configurable).

General indexed property storage is for a collection of indexed
properties where EITHER one or more properties have attributes other
than default_attributes OR there is a property with a large index (in
particular, large is '200' or higher).

Indexed properties are now treated relatively the same as storage within
the various Object methods. Additionally, there is a custom iterator
class for IndexedProperties which makes iteration easy. The iterator
skips empty values by default, but can be configured otherwise.
Likewise, it evaluates getters by default, but can be set not to.
2020-05-28 17:17:13 +02:00
Linus Groh
99e775cee3 LibJS: Reformat ArrayPrototype.cpp 2020-05-27 19:51:52 +02:00
Matthew Olsson
dd08c992e8 LibJS: Simplify and normalize publicly-exposed Object functions
Previously, the Object class had many different types of functions for
each action. For example: get_by_index, get(PropertyName),
get(FlyString). This is a bit verbose, so these methods have been
shortened to simply use the PropertyName structure. The methods then
internally call _by_index if necessary. Note that the _by_index
have been made private to enforce this change.

Secondly, a clear distinction has been made between "putting" and
"defining" an object property. "Putting" should mean modifying a
(potentially) already existing property. This is akin to doing "a.b =
'foo'".

This implies two things about put operations:
    - They will search the prototype chain for setters and call them, if
      necessary.
    - If no property exists with a particular key, the put operation
      should create a new property with the default attributes
      (configurable, writable, and enumerable).

In contrast, "defining" a property should completely overwrite any
existing value without calling setters (if that property is
configurable, of course).

Thus, all of the many JS objects have had any "put" calls changed to
"define_property" calls. Additionally, "put_native_function" and
"put_native_property" have had their "put" replaced with "define".

Finally, "put_own_property" has been made private, as all necessary
functionality should be exposed with the put and define_property
methods.
2020-05-27 13:17:35 +02:00
Angel
199a6b40b3 LibJS: Add Array.prototype.fill 2020-05-26 20:34:44 +02:00
Luke
f9f7cb4583 LibJS: Add Array.prototype.splice
Adds splice to Array.prototype according to the specification:
https://tc39.es/ecma262/#sec-array.prototype.splice
2020-05-26 12:47:11 +02:00
Linus Groh
92fd140cb2 LibJS: Make Array.prototype.includes() generic 2020-05-24 23:51:14 +02:00
Linus Groh
e78bc2f6fd LibJS: Make Array.prototype.lastIndexOf() generic 2020-05-24 23:51:14 +02:00
Linus Groh
9b9b6a4cff LibJS: Make Array.prototype.indexOf() generic 2020-05-24 23:51:14 +02:00
Sergey Bugaev
31359e3ad2 LibJS: Use the new math constants
Instead of evaluating their values at runtime.
2020-05-24 23:30:12 +02:00
Marcin Gasperowicz
99991761fd LibJS: add Array.prototype.reduceRight()
This patch adds `Array.prototype.reduceRight()` method to LibJS Runtime. The implementation is (to my best knowledge) conformant to https://tc39.es/ecma262/#sec-array.prototype.reduceright.

Short test in `LibJS/Tests/Array.prototype-generic-functions.js` demonstrates that the function can be applied to other objects besides `Array`.
2020-05-24 20:58:14 +02:00
Linus Groh
9c8d390682 LibJS: Refactor Accessor
This changes Accessor's m_{getter,setter} from Value to Function* which
seems like a better API to me - a getter/setter must either be a
function or missing, and the creation of an accessor with other values
must be prevented by the parser and Object.defineProperty() anyway.

Also add Accessor::set_{getter,setter}() so we can reuse an already
created accessor when evaluating an ObjectExpression with getter/setter
shorthand syntax.
2020-05-24 18:49:58 +02:00
Marcin Gasperowicz
27c71d2627
LibJS: Add Array.prototype.reduce() (#2334)
This patch adds `Array.prototype.reduce()` method to LibJS Runtime.
The implementation is (to my best knowledge) comformant to ECMA262.

The test `Array.prototype-generic-functions.js` demonstrates that the
function can be applied to other objects besides `Array`.
2020-05-23 16:41:25 +02:00
Linus Groh
00fe7f82c0 LibJS: Treat NaN in Value::to_i32() as zero
Let's treat it as zero like the ECMAScript spec does in toInteger().

That way we can use to_i32() and don't have to care about weird input
input values where a number is expected, i.e.

"foo".charAt() === "f"
"foo".charAt("bar") === "f"
"foo".charAt(0) === "f"
2020-05-23 16:39:17 +02:00
Linus Groh
daf74838dd LibJS: Add missing exception check to ArrayPrototype's for_each_item()
Object::get_by_index() cannot throw for positive indices *right now*,
but once we implement descriptors for array index properties, it can.
2020-05-23 00:38:00 +02:00
Linus Groh
843e000f18 LibJS: Fix Array.prototype.lastIndexOf() implementation 2020-05-23 00:02:13 +02:00
Linus Groh
6a4280e6e5 LibJS: Treat missing arg in Array.prototype.{indexOf,lastIndexOf}() as undefined 2020-05-23 00:02:13 +02:00
Linus Groh
040c75a3cc LibJS: Make Array.prototype.{join,toString}() generic 2020-05-22 17:43:44 +02:00
Linus Groh
e9ee06b19e LibJS: Make Array.prototype.pop() generic 2020-05-22 17:43:44 +02:00
Linus Groh
4334a1b208 LibJS: Make Array.prototype.push() generic 2020-05-22 17:43:44 +02:00
Linus Groh
9f7a6e116a LibJS: Let Array.prototype.join() ignore additional arguments
I.e.

array.join("x", "y", "z") === array.join("x")

rather than

array.join("x", "y", "z") === array.join()
2020-05-22 17:43:44 +02:00
Matthew Olsson
45dfa094e9 LibJS: Add getter/setter support
This patch adds a GetterSetterPair object. Values can now store pointers
to objects of this type. These objects are created when using
Object.defineProperty and providing an accessor descriptor.
2020-05-21 22:56:18 +02:00
Linus Groh
a4d04cc748 LibJS: Refactor Array.prototype callback functions and make them generic 2020-05-21 22:50:14 +02:00
Linus Groh
5db9becc4a LibJS: Treat missing arg in Array.prototype.includes() as undefined 2020-05-21 22:50:14 +02:00
Luke
57d15acd4c LibJS: Add Array.prototype.every 2020-05-21 19:44:59 +02:00
Linus Groh
b3090678a9 LibJS: Add Math.clz32() 2020-05-18 17:57:28 +02:00
Linus Groh
452dbbc463 LibJS: Add Math.expm1() 2020-05-18 17:57:28 +02:00
Linus Groh
e375766f98 LibJS: Add Math.exp() 2020-05-18 17:57:28 +02:00
Linus Groh
b27834cf16 LibJS: Add Math.sign() 2020-05-18 17:57:28 +02:00
Linus Groh
f06c12173c LibJS: Return early from parseFloat() if argument is a number
This saves us both a bit of time and accuracy, as Serenity's strtod()
still is a little bit off sometimes - and stringifying the result and
parsing it again just increases that offset.
2020-05-18 14:33:53 +02:00
Linus Groh
eb72ba2466 LibJS: Remove is_nan() check in as_size_t() and fix to_size_t()
We need to call as_double() on the freshly converted number, not the
value itself.
2020-05-18 11:39:11 +02:00
Linus Groh
36996bd720 LibJS: Rename to_{i32,size_t}() to as_{i32,size_t}() for clarity
As these parameter-less overloads don't change the value's type and
just assume Type::Number, naming them as_i32() and as_size_t() is more
appropriate.
2020-05-18 10:21:51 +02:00
Linus Groh
56502b0e84 LibJS: Check for exception after converting object to string primitive 2020-05-18 09:39:55 +02:00
Linus Groh
4569e88bea LibJS: Throw TypeError when coercing symbol to number 2020-05-18 09:39:55 +02:00
Linus Groh
476094922b LibJS: Pass Interpreter& to Value::to_number() et al.
This patch is unfortunately rather large and might make some things feel
bloated, but it is necessary to fix a few flaws in LibJS, primarily
blindly coercing values to numbers without exception checks - i.e.

interpreter.argument(0).to_i32();  // can fail!!!

Some examples where the interpreter would actually crash:

var o = { toString: () => { throw Error() } };
+o;
o - 1;
"foo".charAt(o);
"bar".repeat(o);

To fix this, we now have the following...

to_double(Interpreter&)
to_i32()
to_i32(Interpreter&)
to_size_t()
to_size_t(Interpreter&)

...and a whole lot of exception checking.

There's intentionally no to_double(), use as_double() directly instead.

This way we still can use these convenient utility functions but don't
need to check for exceptions if we are sure the value already is a
number.

Fixes #2267.
2020-05-18 09:39:55 +02:00
Linus Groh
1a1394f7a2 LibJS: Change Value::to_object(Heap& -> Interpreter&)
Passing a Heap& to it only to then call interpreter() on that is weird.
Let's just give it the Interpreter& directly, like some of the other
to_something() functions.
2020-05-18 09:39:55 +02:00
Linus Groh
b8b7f84547 LibJS: Remove no-op SymbolPrototype::description_setter()
We can just give put_native_property() a nullptr for the setter.
2020-05-18 09:36:14 +02:00
mattco98
4ced126704 LibJS: Add symbol objects
This commit adds the following classes: SymbolObject, SymbolConstructor,
SymbolPrototype, and Symbol. This commit does not introduce any
new functionality to the Object class, so they cannot be used as
property keys in objects.
2020-05-17 18:05:15 +02:00
Linus Groh
71ec72bddf LibJS: Simplify various StringPrototype functions 2020-05-17 16:23:48 +02:00
Linus Groh
73eef31f49 LibJS: Add Number.parseFloat() 2020-05-17 16:21:38 +02:00
Linus Groh
6f6b089aa0 LibJS: Add parseFloat() 2020-05-17 16:21:33 +02:00
Linus Groh
b299c75d45 LibJS: Make Object.prototype.constructor non-enumerable 2020-05-16 21:22:34 +02:00
Andreas Kling
c6ddbd1f3e LibJS: Add side-effect-free version of Value::to_string()
There are now two API's on Value:

- Value::to_string(Interpreter&) -- may throw.
- Value::to_string_without_side_effects() -- will never throw.

These are some pretty big sweeping changes, so it's possible that I did
some part the wrong way. We'll work it out as we go. :^)

Fixes #2123.
2020-05-15 13:50:42 +02:00
Linus Groh
33defef267 LibJS: Let parser keep track of errors
Rather than printing them to stderr directly the parser now keeps a
Vector<Error>, which allows the "owner" of the parser to consume them
individually after parsing.

The Error struct has a message, line number, column number and a
to_string() helper function to format this information into a meaningful
error message.

The Function() constructor will now include an error message when
throwing a SyntaxError.
2020-05-15 09:53:52 +02:00
Linus Groh
de42ddfd93 LibJS: Trim whitespace from string before coercing to number 2020-05-13 09:36:20 +02:00
Linus Groh
f39c7c2978 LibJS: Use String::trim_whitespace() for String.prototype.trim*() 2020-05-13 09:36:20 +02:00
Linus Groh
0c14ee035c LibJS: Make string to number coercion work for doubles 2020-05-13 09:36:20 +02:00
Linus Groh
7b8765c311 LibJS: Make the Function() constructor throw a SyntaxError, not return 2020-05-13 09:34:25 +02:00
Linus Groh
063228c02e LibJS: Handle empty values in operator<<()
Otherwise something like dbg() << Value(); chokes on
ASSERT_NOT_REACHED() in Value::to_string()
2020-05-13 01:14:22 +02:00
Linus Groh
e333b60064 LibJS: Add Array.of() 2020-05-08 20:06:49 +02:00
Linus Groh
ca22476d9d LibJS: Add Array.isArray() 2020-05-08 20:06:49 +02:00
Linus Groh
01fd6ce045 LibJS: Support multiple arguments in Array constructor 2020-05-08 20:06:49 +02:00
Linus Groh
8137f40b73 LibJS: Add Value::is_integer() 2020-05-08 20:06:49 +02:00
Matthew Olsson
532d4bc0ab LibJS: Spec-compliant equality comparisons
The ECMAScript spec defines multiple equality operations which are used
all over the spec; this patch introduces them. Of course, the two
primary equality operations are AbtractEquals ('==') and StrictEquals
('==='), which have been renamed to 'abstract_eq' and 'strict_eq' in
this patch.

In support of the two operations mentioned above, the following have
also been added: SameValue, SameValueZero, and SameValueNonNumeric.
These are important to have, because they are used elsewhere in the spec
aside from the two primary equality comparisons.
2020-05-08 09:49:20 +02:00
Matthew Olsson
ab652fa1ee LibJS: Add String.raw 2020-05-07 23:05:55 +02:00
Matthew Olsson
838390171c LibJS: Function.length respects default and rest parameters
"[Function.length is] the number of formal parameters. This number
excludes the rest parameter and only includes parameters before
the first one with a default value." - MDN
2020-05-06 17:40:56 +02:00
Andreas Kling
025cdfdce8 LibJS: Simplify a Value type check in Object::to_string() 2020-05-06 16:40:08 +02:00
Linus Groh
eea62dd365 LibJS: Add Value::{is, as}_function() 2020-05-06 14:49:53 +02:00
Andreas Kling
fc5d0a1bd2 LibJS: Switch objects to unique shape after 100 property additions
At that point, it seems unlikely that the shape is gonna be shared with
other objects, and we avoid getting stuck holding a big bag of shapes.
2020-05-05 18:49:45 +02:00
Emanuele Torre
8bd9f7e50e LibJS: run clang-format on all the files 2020-05-05 09:15:16 +02:00
Emanuele Torre
30519c22f6 LibJS: Re-implement console functions as wrappers around Console methods
Console methods are now Value(void) functions.

JavaScript functions in the JavaScript ConsoleObject are now implemented
as simple wrappers around Console methods.

This will make it possible for LibJS users to easily override the
default behaviour of JS console functions (even their return value!)
once we add a way to override Console behaviour.
2020-05-05 09:15:16 +02:00
Emanuele Torre
73bead5ae9 LibJS: Move join_args() in Interpreter
It can be useful outside of Runtime/ConsoleObject.cpp.
join_args() => Interpreter::join_arguments()
2020-05-05 09:15:16 +02:00
Linus Groh
454c1e6bbe LibJS: Implement rest parameters 2020-05-04 23:30:52 +02:00
Linus Groh
25cf0da2fb LibJS: Set name of anonymous functions during assignment 2020-05-03 11:41:56 +02:00
Matthew Olsson
5e66f1900b LibJS: Add function default arguments
Adds the ability for function arguments to have default values. This
works for standard functions as well as arrow functions. Default values
are not printed in a <function>.toString() call, as nodes cannot print
their source string representation.
2020-05-03 00:44:57 +02:00
Andreas Kling
c00ff4ba62 LibJS: Fix build (GlobalObject::add_constructor not visible in LibWeb) 2020-05-02 20:43:44 +02:00
Linus Groh
99be27b4a1 LibJS: Add "name" property to functions 2020-05-02 20:41:31 +02:00
Linus Groh
d007e8d00f LibJS: Set correct "length" of Object constructor 2020-05-02 20:41:31 +02:00
Linus Groh
85582953c6 LibJS: Minor formatting changes in Function.cpp 2020-05-02 20:41:31 +02:00
Linus Groh
ae05dc8abc LibJS: Name functions created by "Function" "anonymous"
...as it is supposed to be.
2020-05-02 20:41:31 +02:00
Emanuele Torre
be1a5bf3f7 LibJS: Add ConsoleMessage concept
A ConsoleMessage is a struct cointaining:
 * AK::String text;         represents the text of the message sent
                             to the console.
 * ConsoleMessageKind kind; represents the kind of JS `console` function
                             from which the message was sent.

Now, Javascript `console` functions only send a ConsoleMessage to the
Interpreter's Console instead of printing text directly to stdout.
The Console then stores the recived ConsoleMessage in
Console::m_messages; the Console does not print to stdout by default.

You can set Console::on_new_message to a void(ConsoleMessage&); this
function will get call everytime a new message is added to the Console's
messages and can be used, for example, to print ConsoleMessages to
stdout or to color the output based on the kind of ConsoleMessage.

In this patch, I also:
  * Re-implement all the previously implemented functions in the
     JavaScript ConsoleObject, as wrappers around Console functions
     that add new message to the Console.
  * Implement console.clear() like so:
    - m_messages get cleared;
    - a new_message with kind set ConsoleMessageKind::Clear gets added
       to m_messages, its text is an empty AK::String;
  * Give credit to linusg in Console.cpp since I used his
     console.trace() algorithm in Console::trace().

I think that having this abstration will help us in the implementation
of a browser console or a JS debugger. We could also add more MetaData
to ConsoleMessage, e.g. Object IDs of the arguments passed to console
functions in order to make hyperlinks, Timestamps, ecc.; which could be
interesting to see.

This will also help in implementing a `/bin/js` option to make, for
example, return a ConsoleMessageWrapper to console functions instead of
undefined. This will be useful to make tests for functions like
console.count() and console.countClear(). :^)
2020-05-02 11:41:35 +02:00
Emanuele Torre
e9c7d4524a LibJS: Implement ConsoleObject::count() as a Console::count() wrapper
Also implement ConsoleObject::count_clear() as a wrapper for
Console::count_clear()
2020-05-02 11:41:35 +02:00
Emanuele Torre
2e92c2e5e1 LibJS: Start implementing a Console class for the interpreter
The goal is to start factoring out core ConsoleObject functionality and
to make ConsoleObject only a JS wrapper around Console.
2020-05-02 11:41:35 +02:00
Linus Groh
79b829637e LibJS: Implement most of the Reflect object 2020-05-01 16:54:01 +02:00
Linus Groh
1ba2e6768d LibJS: Implement indexed access for StringObject 2020-05-01 16:54:01 +02:00
Linus Groh
a81bce8c2a LibJS: Make Array.length non-configurable
This was incorrect, it's only writable.
2020-05-01 16:54:01 +02:00
Linus Groh
65dbe17dd7 LibJS: Add Value::to_size_t() 2020-05-01 16:54:01 +02:00
Linus Groh
62671bea68 LibJS: Add Object::has_property()
Like Object::has_own_property() but going down the prototype chain.
2020-05-01 16:54:01 +02:00
Linus Groh
4cdd802927 LibJS: Return a bool from Object::put* to indicate success 2020-05-01 16:54:01 +02:00
Kesse Jones
6dbb5df81f LibJS: Add String.prototype.lastIndexOf 2020-05-01 16:50:37 +02:00
Emanuele Torre
46b79eaad9 LibJS: Implement console.countReset()
I chose to also make it print "<counter_name>: 0\n" when a counter gets
reset, similarly to how firefox behaves.
2020-05-01 13:02:01 +02:00
Emanuele Torre
8c60ba1e42 LibJS: Implement console.count() 2020-05-01 13:02:01 +02:00
mattco98
683a0696f3 LibJS: Add Object.{keys,values,entries}() 2020-04-30 09:53:16 +02:00
Linus Groh
8159f45f6e LibJS: Make String.prototype.slice() generic 2020-04-29 19:14:36 +02:00
Linus Groh
cfdb7b8806 LibJS: Make (most) String.prototype functions generic
I.e. they don't require the |this| value to be a string object and
"can be transferred to other kinds of objects for use as a method" as
the spec describes it.
2020-04-29 18:53:21 +02:00
Linus Groh
4bdb6daac5 LibJS: Handle non-string primitive values in Object::to_string() 2020-04-29 18:53:21 +02:00
Linus Groh
2c6e7dbd07 LibJS: Throw error in Object::to_string() if string conversion fails 2020-04-29 18:53:21 +02:00
mattco98
95abcc3722 LibJS: Implement correct object property ordering
This commit introduces a way to get an object's own properties in the
correct order. The "correct order" for JS object properties is first all
array-like index properties (numeric keys) sorted by insertion order,
followed by all string properties sorted by insertion order.

Objects also now print correctly in the repl! Before this commit:

courage ~/js-tests $ js
> ({ foo: 1, bar: 2, baz: 3 })
{ bar: 2, foo: 1, baz: 3 }

After:

courage ~/js-tests $ js
> ({ foo: 1, bar: 2, baz: 3 })
{ foo: 1, bar: 2, baz: 3 }
2020-04-29 18:47:03 +02:00
Kesse Jones
58f6f50de4 LibJS: Add String.prototype.slice 2020-04-29 18:35:18 +02:00
Andreas Kling
aaf35112a4 LibJS: Pass JS::Function around by reference more 2020-04-29 13:43:57 +02:00
Andreas Kling
a38658dc88 LibJS: Don't use Optional<Value> for bound |this| values
Just use a plain Value since it already has an empty state.
2020-04-29 12:41:58 +02:00
Andreas Kling
698652a548 LibJS: Make Value::as_string() return a PrimitiveString reference 2020-04-29 12:35:39 +02:00
Andreas Kling
75f246dde8 LibJS: Make StringObject::primitive_string() return a reference 2020-04-29 12:33:28 +02:00
Linus Groh
d4ec38097f LibJS: Return undefined in Array.prototype.{pop,shift} for empty values 2020-04-29 09:38:25 +02:00
mattco98
18cfb9218a LibJS: Set Array length attributes to "Configurable | Writable" 2020-04-29 09:02:29 +02:00
Linus Groh
da0ab16f01 LibJS: Don't handle arrays separately in Value::to_number()
Now that Array.prototype.join() is producing the correct results we
can remove the separate code path for arrays in Value::to_number()
and treat them like all other objects - using to_primitive() with
number as the preferred type and then calling to_number() on the
result.

This is how the spec descibes it.

This also means we don't crash anymore when trying to coerce
[<empty>] to a number - it now does the following:

[<empty>] - to string - "" - to number - 0
[<empty>, <empty>] - to string - "," - to number - NaN
2020-04-29 01:30:59 +02:00
Linus Groh
6d6cd64689 LibJS: Skip undefined and null in join_array_with_separator()
This it being used in Array.prototype.{join,toString}() - and now
adhering to the spec: [undefined, null].join() === ","
2020-04-29 01:30:59 +02:00
Linus Groh
3152559422 LibJS: Call Array.prototype.findIndex() callback for empty elements
If the array value at the current index is empty, the callback will
be called with undefined as value.
2020-04-28 20:15:38 +02:00
Linus Groh
823cc7bc1c LibJS: Call Array.prototype.find() callback for empty elements
If the array value at the current index is empty, the callback will
be called with undefined as value.
2020-04-28 20:15:38 +02:00
Linus Groh
ad8abce8a5 LibJS: Let Array.prototype.map() resize new array before loop
Currently we would create an empty array of size 0 and appening results
of the callback function while skipping empty values.

This is incorrect, we should be initializing a full array of the correct
size beforehand and then inserting the results while still skipping
empty values.

Wrong: new Array(5).map(() => {}) // []
Right: new Array(5).map(() => {}) // [<empty> * 5]
2020-04-28 20:15:38 +02:00