Commit graph

695 commits

Author SHA1 Message Date
Jack Karamanian
edae926cb0 LibJS: Add Boolean constructor object 2020-04-07 08:41:25 +02:00
Jack Karamanian
57bd194e5a LibJS: Return false for NaN numbers in Value::to_boolean() 2020-04-07 08:41:25 +02:00
Andreas Kling
cb18b2c74d LibJS: Add String.prototype.toLowerCase() 2020-04-06 20:46:08 +02:00
Andreas Kling
4fe14aab3b LibJS: Inline JS::Value()
I had this out of line for debugging reasons. Put it back inline.
2020-04-06 20:30:36 +02:00
Andreas Kling
bdffc9e7fb LibJS: Support array holes, encoded as empty JS::Value
This patch adds a new kind of JS::Value, the empty value.
It's what you get when you do JSValue() (or most commonly, {} in C++.)

An empty Value signifies the absence of a value, and should never be
visible to JavaScript itself. As of right now, it's used for array
holes and as a return value when an exception has been thrown and we
just want to unwind.

This patch is a bit of a mess as I had to fix a whole bunch of code
that was relying on JSValue() being undefined, etc.
2020-04-06 20:27:44 +02:00
Andreas Kling
5495f06af5 LibJS: Give argument vectors an inline capacity of 8
This avoids one malloc/free pair for every function call if there are
8 arguments or fewer.
2020-04-06 19:22:12 +02:00
Andreas Kling
be019f28ca LibJS: Add a PropertyName class that represents a string or a number
Now that we have two separate storages for Object properties depending
on what kind of index they have, it's nice to have an abstraction that
still allows us to say "here's a property name".

We use PropertyName to always choose the optimal storage path directly
while interpreting the AST. :^)
2020-04-06 18:09:26 +02:00
Andreas Kling
90ba0145f6 LibJS: Add a number-indexed property storage to all Objects
Objects can have both named and indexed properties. Previously we kept
all property names as strings. This patch separates named and indexed
properties and splits them between Object::m_storage and m_elements.

This allows us to do much faster array-style access using numeric
indices. It also makes the Array class much less special, since all
Objects now have number-indexed storage. :^)
2020-04-06 18:09:26 +02:00
Emanuele Torre
ba67fc68b8
LibJS: Rename variable "max" to "min" in MathObject::min() (#1665) 2020-04-06 14:08:56 +02:00
Andreas Kling
67f7763ab9 LibJS: Object needs to protect values in its storage
Otherwise the garbage collector will eat them way too soon! This made
it impossible to use "js -g" without crashing.
2020-04-06 13:35:20 +02:00
Andreas Kling
e323246517 Meta: Add missing copyright headers 2020-04-06 11:09:01 +02:00
Linus Groh
f5dacfbb5b LibJS: Add Math.{cos,sin,tan}() 2020-04-06 10:58:16 +02:00
Linus Groh
04a36b247b LibJS: Simplify MathObject functions 2020-04-06 10:58:16 +02:00
Andreas Kling
003741db1c LibJS: Add Math.min() 2020-04-06 08:26:26 +02:00
Linus Groh
9e7dcaa106 LibJS: Return -Infinity in Math.max() with no argument 2020-04-05 19:30:47 +02:00
Andreas Kling
8bfee015bc LibJS: Make Object::to_string() call the "toString" property if present 2020-04-05 18:19:56 +02:00
Andreas Kling
a7b21ec0f4 LibJS: Add Array.prototype.toString() 2020-04-05 18:07:41 +02:00
Linus Groh
2f775a925b LibJS: Fix Math.SQRT1_2
The value of Math.SQRT1_2 was zero as we were dividing two integers.
2020-04-05 16:01:46 +02:00
Linus Groh
0403845d3e LibJS: Implement exponentiation (** operator) 2020-04-05 15:32:06 +02:00
Andreas Kling
1d468ed6d3 AK: Stop allowing implicit downcast with RefPtr and NonnullRefPtr
We were allowing this dangerous kind of thing:

RefPtr<Base> base;
RefPtr<Derived> derived = base;

This patch changes the {Nonnull,}RefPtr constructors so this is no
longer possible.

To downcast one of these pointers, there is now static_ptr_cast<T>:

RefPtr<Derived> derived = static_ptr_cast<Derived>(base);

Fixing this exposed a ton of cowboy-downcasts in various places,
which we're now forced to fix. :^)
2020-04-05 11:19:00 +02:00
Brian Gianforcaro
240a5b5fd7 LibJS: Add support for Math.ceil() and Math.trunc()
Introduce support for the both of these Math methods.
Math.trunc is implemented in terms of Math.ceil or Math.floor
based on the input value. Added tests as well.
2020-04-05 10:56:23 +02:00
Brian Gianforcaro
b8cef3a2d3 LibJS: Add support for floating point modulous
This change implements floating point mod based on the algorithm
used in LibM's fmod() implementation. To avoid taking a dependency
on LibM from LibJS I reimplemented the formula in LibJS.

I've incuded some of the example MDM test cases as well.
This surfaced and issue handling NaN which I've fixed as well.
2020-04-05 10:38:13 +02:00
Brian Gianforcaro
41bfff1abe LibJS: Correctness fixes for bitwise_or, address FIXME's in test. 2020-04-05 10:37:02 +02:00
Brian Gianforcaro
4e54d0ff21 LibJS: Add support for arbitrary arguments to Math.max
Address the FIXME in MathObject::max to handle an arbitrary
number of arguments. Also adding a test case to verify the
behavior of Math.max() while I'm here.
2020-04-05 09:28:58 +02:00
Andreas Kling
d84de532f1 LibJS: Add Math.max() 2020-04-05 00:57:00 +02:00
Andreas Kling
16bd99aa52 LibJS: Add Math.round() 2020-04-05 00:29:01 +02:00
Andreas Kling
afff228308 LibJS: Add Math.floor() 2020-04-05 00:26:56 +02:00
Andreas Kling
97cd1173fa LibJS: Add String.prototype.indexOf() 2020-04-04 23:44:29 +02:00
Andreas Kling
9e05672f87 LibJS: Math.sqrt.length should be 1 2020-04-04 23:28:38 +02:00
Andreas Kling
3a026a1ede LibJS: Add NumberObject and make to_object() on number values create it 2020-04-04 23:13:13 +02:00
Andreas Kling
d4dfe7e525 LibJS: Add Math.sqrt() 2020-04-04 22:44:48 +02:00
Andreas Kling
d155491122 LibJS: Add basic Array constructor
We only support Array() with 0 or 1 parameters so far.
2020-04-04 22:28:21 +02:00
Andreas Kling
644ff1bbfd LibJS: Add basic support for modulo (%) in binary expressions 2020-04-04 21:17:34 +02:00
Linus Groh
2944039d6b LibJS: Add Function() and Function.prototype 2020-04-04 15:58:49 +02:00
Linus Groh
4d931b524d LibJS: Add length property to ScriptFunction 2020-04-04 15:58:49 +02:00
Linus Groh
cd3e2690eb LibJS: Set length property in Object::put_native_function() 2020-04-04 15:58:49 +02:00
Andreas Kling
faac43597a LibJS: Add js_string(Interpreter&, String) 2020-04-04 12:58:05 +02:00
Linus Groh
94afcb54de LibJS: Implement Error.prototype.toString() 2020-04-03 09:07:05 +02:00
Linus Groh
2636cac6e4 LibJS: Remove UndefinedLiteral, add undefined to global object
There is no such thing as a "undefined literal" in JS - undefined is
just a property on the global object with a value of undefined.
This is pretty similar to NaN.

var undefined = "foo"; is a perfectly fine AssignmentExpression :^)
2020-04-03 00:10:52 +02:00
Linus Groh
543c6e00db LibJS: Implement Infinity 2020-04-02 21:52:15 +02:00
Andreas Kling
99aab4470a LibJS: Object::put() shouldn't create own properties on prototype chain
Unless there is a setter present on the prototype chain, put() should
only set own properties on the object itself.

Fixes #1588.
2020-04-02 21:36:14 +02:00
Linus Groh
a62230770b LibJS: Implement unary plus / minus 2020-04-02 19:55:45 +02:00
Andreas Kling
5e6e1fd482 LibJS: Start implementing object shapes
This patch adds JS::Shape, which implements a transition tree for our
Object class. Object property keys, prototypes and attributes are now
stored in a Shape, and each Object has a Shape.

When adding a property to an Object, we make a transition from the old
Shape to a new Shape. If we've made the same exact transition in the
past (with another Object), we reuse the same transition and both
objects may now share a Shape.

This will become the foundation of inline caching and other engine
optimizations in the future. :^)
2020-04-02 19:32:21 +02:00
Andreas Kling
fbb16073d1 LibJS: Make JS::Cell non-copyable and non-movable
Also make the JS::Cell default constructor protected to provove a
compilation error if you tried to allocate a plain cell.
2020-04-02 15:24:50 +02:00
Andreas Kling
cd1d369cdd LibJS: Add argument(i) and argument_count() to Interpreter
Add some convenience accessors for retrieving arguments from the
current call frame.
2020-04-01 22:38:59 +02:00
Andreas Kling
1549c5c48b LibJS: Make Value::as_object() return Object&
Let's move towards using references over pointers in LibJS as well.
I had originally steered away from it because that's how I've seen
things done in other engines. But this is not the other engines. :^)
2020-04-01 22:18:47 +02:00
Linus Groh
a0da97cb5a LibJS: Add NaN to global object 2020-04-01 22:09:37 +02:00
Linus Groh
ee6472fef2 LibJS: Implement Error function/constructor 2020-04-01 20:47:37 +02:00
Linus Groh
849e2c77e4 LibJS: Implement constructor/non-constructor function calls
This adds Function::construct() for constructor function calls via `new`
keyword. NativeFunction doesn't have constructor behaviour by default,
ScriptFunction simply calls call() in construct()
2020-04-01 20:18:36 +02:00
Andreas Kling
d062d7baa7 LibWeb+LibJS: Move DOM Window object to dedicated classes
LibWeb now creates a WindowObject which inherits from GlobalObject.
Allocation of the global object is moved out of the Interpreter ctor
to allow for specialized construction.

The existing Window interfaces are moved to WindowObject with their
implementation code in the new Window class.
2020-04-01 18:57:00 +02:00
Linus Groh
632231cc0c js: Implement print function for Date objects 2020-03-31 21:19:21 +02:00
Andreas Kling
a8dc6501de LibJS: Use "%d" to stringify numeric values that are whole integers
This unbreaks a bunch of the JS tests since they were now printing all
the numbers as "1.000000" instead of "1".
2020-03-31 19:06:10 +02:00
Linus Groh
3fcea71538 LibJS: Implement Date.prototype.to{Date,Time}String() 2020-03-30 21:43:35 +02:00
Linus Groh
dc9b1226ac LibJS: Implement Date.prototype.toString() 2020-03-30 20:36:18 +02:00
Linus Groh
d4e3688f4f LibJS: Start implementing Date :^)
This adds:

- A global Date object (with `length` property and `now` function)
- The Date constructor (no arguments yet)
- The Date prototype (with `get*` functions)
2020-03-30 14:11:54 +02:00
Linus Groh
0a94661c14 LibJS: Implement String.prototype.startsWith() 2020-03-29 19:37:16 +02:00
Linus Groh
03c3530d86 LibJS: Add constant properties to MathObject 2020-03-29 17:35:08 +02:00
Linus Groh
bad0556a59 LibJS: Handle empty strings and arrays in Value::to_number()
- An empty string is converted to 0
 - An empty array is converted to 0
 - An array with one item is converted to that item's numeric value
 - An array with more than one item is converted to NaN
2020-03-29 16:45:11 +02:00
Andreas Kling
2d3634d5f5 LibJS: Implement Math.abs() 2020-03-29 15:03:58 +02:00
Andreas Kling
f95a119627 LibJS: Implement Object.getOwnPropertyNames() 2020-03-29 01:26:57 +01:00
Andreas Kling
30440134cb LibJS+LibWeb: Move native properties to separate getters/setters
This was a bit cumbersome now, but it gets us closer to a format suited
for code generation.
2020-03-29 00:37:33 +01:00
Andreas Kling
56936b97d0 LibJS+LibWeb: Move native JS functions into dedicated member functions
Instead of implementing every native function as a lambda function,
use static member functions instead.

This makes it easier to navigate the code + backtraces look nicer. :^)
2020-03-28 23:10:37 +01:00
Andreas Kling
7c4e53f31e LibJS: Rework how native functions are called to improve |this| value
Native functions now only get the Interpreter& as an argument. They can
then extract |this| along with any indexed arguments it wants from it.

This forces functions that want |this| to actually deal with calling
interpreter.this_value().to_object(), and dealing with the possibility
of a non-object |this|.

This is still not great but let's keep massaging it forward.
2020-03-28 22:51:09 +01:00
Linus Groh
c209ea1985 LibJS: Implement Array.prototype.{shift,pop} 2020-03-28 22:18:11 +01:00
Andreas Kling
82ca7ae1f8 LibJS: Oops, "instanceof" was backwards!
Fix the "instanceof" operator to check if the constructor's prototype
property occurs anywhere in the prototype chain of the instance object.

This patch also adds Object.setPrototypeOf() to make it possible to
create a test for this bug.

Thanks to DexesTTP for pointing this out! :^)
2020-03-28 19:48:12 +01:00
Andreas Kling
14047ca432 LibJS: Add a global "Object" constructor
This patch adds an "Object" constructor to the global object. The only
function it implements so far is Object.getPrototypeOf().
2020-03-28 17:23:54 +01:00
Andreas Kling
a3d92b1210 LibJS: Implement the "instanceof" operator
This operator walks the prototype chain of the RHS value and looks for
a "prototype" property with the same value as the prototype of the LHS.

This is pretty cool. :^)
2020-03-28 16:56:54 +01:00
Andreas Kling
37fe16a99c LibJS: Add Function.prototype and make "new" Objects delegate to it 2020-03-28 16:40:36 +01:00
Andreas Kling
6a5cd32205 LibJS: The global isNaN() should coerce to number before testing NaN
For stricter NaN checking, we'll have to implement Number.isNaN().
2020-03-27 12:59:41 +01:00
Andreas Kling
c60dc84a33 LibJS: Allow function calls with missing arguments
We were interpreting "undefined" as a variable lookup failure in some
cases and throwing a ReferenceError exception instead of treating it
as the valid value "undefined".

This patch wraps the result of variable lookup in Optional<>, which
allows us to only throw ReferenceError when lookup actually fails.
2020-03-27 12:56:05 +01:00
Andreas Kling
04ced9e24a LibJS: Add global isNaN() function 2020-03-27 12:45:36 +01:00
Andreas Kling
9a78b4af2c LibJS: Basic NaN support
This patch adds js_nan() for constructing a NaN value. You can check
if a Value is NaN with Value::is_nan().
2020-03-27 12:40:22 +01:00
Andreas Kling
68dec2801d LibJS: Add Object::own_properties() convenience accessor 2020-03-26 12:19:01 +01:00
Andreas Kling
d7073b9f3e LibJS: Add Value::is_array() 2020-03-26 12:02:18 +01:00
Andreas Kling
a94a150df0 LibJS: Remove unnecessary space character at the end of console.log() 2020-03-25 14:08:47 +01:00
Andreas Kling
faddf3a1db LibJS: Implement "throw"
You can now throw an expression to the nearest catcher! :^)

To support throwing arbitrary values, I added an Exception class that
sits as a wrapper around whatever is thrown. In the future it will be
a logical place to store a call stack.
2020-03-24 22:21:58 +01:00
Andreas Kling
db024a9cb1 LibJS: Remove debug spam in Error.prototype.name 2020-03-24 22:21:58 +01:00
Andreas Kling
7dc78b5e38 LibJS: Use correct |this| value when getting/setting native properties 2020-03-24 16:14:10 +01:00
Andreas Kling
343e224aa8 LibJS: Implement basic exception throwing
You can now throw exceptions by calling Interpreter::throw_exception().
Anyone who calls ASTNode::execute() needs to check afterwards if the
Interpreter now has an exception(), and if so, stop what they're doing
and simply return.

When catching an exception, we'll first execute the CatchClause node
if present. After that, we'll execute the finalizer block if present.

This is unlikely to be completely correct, but it's a start! :^)
2020-03-24 16:14:10 +01:00
Andreas Kling
538537dfd0 LibJS: Use rand() for Math.random() on other systems
I bet we could be smarter here and use arc4random() on systems where
it is present. I'm not sure how to detect it though.
2020-03-23 13:14:04 +01:00
Andreas Kling
cccbe43056 LibJS: Use FlyString for identifiers
This makes variable and property lookups a lot faster since comparing
two FlyStrings is O(1).
2020-03-22 13:03:43 +01:00
Andreas Kling
8b18674229 LibJS: Add Math.random() :^) 2020-03-21 17:52:12 +01:00
Andreas Kling
08b17d70af LibJS+LibWeb: Fix some inconsistencies in NativeFunction callbacks
These should always pass the arguments in a const Vector<JS::Value>&.
2020-03-21 14:43:44 +01:00
Andreas Kling
324b92fd06 LibJS: Virtualize access to an Object's own properties
Object now has virtual get_own_property() and put_own_property() member
functions that can be overridden to provide custom behavior.

We use these virtuals to move Array-specific access behavior to Array.
2020-03-21 14:37:34 +01:00
Andreas Kling
bceabd7c4b LibJS: Add ArrayPrototype and implement Array.prototype.push()
This function is ultimately supposed to be generic and allow any |this|
that has a length property, but for now it only works on our own Array
object type.
2020-03-20 21:56:40 +01:00
Andreas Kling
8f7d4f67a4 LibJS: Support reading/writing elements in an Array via Object get/put
I'm not completely thrilled about Object::get() and Object::put() doing
special-case stuff for arrays, and we should probably come up with a
better abstraction for it.

But at least it works for now, which is really nice. :^)
2020-03-20 21:56:40 +01:00
Andreas Kling
86642add2f LibJS: Allow default-constructing a JS::Value (undefined) 2020-03-20 21:56:40 +01:00
Andreas Kling
a82f64d3d6 LibJS: Parse ArrayExpression and start implementing Array objects
Note that property lookup is not functional yet.
2020-03-20 21:56:40 +01:00
Andreas Kling
218f082226 LibJS: Print a newline in each console.log() 2020-03-20 14:41:23 +01:00
Andreas Kling
1a10470c1d LibJS: Implement basic object property assignment
This is pretty naive, we just walk up the prototype chain and call any
NativeProperty setter that we find. If we don't find one, we put/set
the value as an own property of the object itself.
2020-03-19 17:44:06 +01:00
Andreas Kling
97674da502 LibJS: Tolerate NativeFunction::call() with non-object 'this' for now
I'm not exactly sure why we end up in this situation, we'll have to
look into it.
2020-03-18 17:13:22 +01:00
Andreas Kling
ddd69e3660 LibJS: Make the AST reference-counted
This allows function objects to outlive the original parsed program
without their ScopeNode disappearing.
2020-03-18 11:23:53 +01:00
Andreas Kling
0a71533aff LibJS: Pass argument value vectors as const Vector<Value>&
Now that Interpreter keeps all arguments in the CallFrame stack, we can
just pass a const-reference to the CallFrame's argument vector to each
function handler (instead of copying it.)
2020-03-17 16:24:53 +01:00
Andreas Kling
086f68e878 LibJS: Replace the global print() function with console.log() :^) 2020-03-16 14:58:20 +01:00
Andreas Kling
19452230cd LibJS: Add "Heap" and "Runtime" subdirectories
Let's try to keep LibJS tidy as it expands. :^)
2020-03-16 14:37:19 +01:00