Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing native returns for constructor functions #10

Closed
1 task
jasonwilliams opened this issue Mar 21, 2019 · 9 comments
Closed
1 task

Implementing native returns for constructor functions #10

jasonwilliams opened this issue Mar 21, 2019 · 9 comments
Milestone

Comments

@jasonwilliams
Copy link
Member

jasonwilliams commented Mar 21, 2019

Calling new String() currently works however calling String() without new will fail.
You will be returned the global object which has everything in it and causes a stack overflow. This would be the equivalent of traversing every object and property of window in the browser.

The reason this happens is because String() is currently written to take the this value, and attach a primitiveValue field to the slice which is set to the native string. Because we're calling String() without new, there is no this passed in, and so this becomes the global object rather than a new object we pass

The pattern here is this
new Number() returns an instance of Number
Number() returns a primitive number

new String() returns an instance of String
String() returns a primitive string

Notes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

Sub issues:

@vitkarpov
Copy link

vitkarpov commented Mar 21, 2019

Hey @jasonwilliams, it's nice that you have so clean descriptions of issues 👍 Do you consider to take a PR on this?

@jasonwilliams
Copy link
Member Author

@vitkarpov sure!

@jasonwilliams
Copy link
Member Author

@vitkarpov ECMA spec defines 2 methods for calling and constructing an object, maybe this helps:
https://tc39.github.io/ecma262/#table-6

@jasonwilliams
Copy link
Member Author

@vitkarpov how you getting on?

@vitkarpov
Copy link

vitkarpov commented Apr 5, 2019

@jasonwilliams now so good, actually I have a pretty basic understanding of Rust, so not being able to articulate in a particular language makes this kind of hard 😞

I'd be happy to follow your PRs and ask questions if you don't mind, I'm sure it's going to be better with time.

I'm sorry I didn't tell about it in advance if you're counting on me.

@jasonwilliams
Copy link
Member Author

@vitkarpov no problem, im still learning myself, mainly start on something then ask questions as needed

@someguynamedmatt
Copy link
Contributor

@jasonwilliams For clarity: in the description are we suggesting that Number() works as intended, whereas String() doesn't? Or are they both not functioning to the spec?

@jasonwilliams
Copy link
Member Author

jasonwilliams commented Aug 12, 2019

I've been thinking about this for some time, so sorry for the long write up.

@someguynamedmatt Number() doesn't work or exist at the moment, there is no Number object on the global scope at the that's where this ticket comes in: jasonwilliams#34
The number and String pattern in the description was just hypothetical and what we should be aiming for.

Our global function objects (String, Boolean, Array) need refactoring. If you look at the specification these are all function objects, which can create exotic objects or native data types, these function objects have [[Call]] and [[Construct]] internal methods. (this is easier to implement now now Objects have been refactored).

Let's take String as an example. String is exposed to the global scope as a function (make_string) with the methods on its prototype. This is ok for constucting objects but leaves us no room for calling String() normally.

Right now when we construct a new string, we actually just call it like a normal function. This means that in exec.rs Construct and Call are currently doing the same thing (except Construct passes this as its first argument)

Once function objects have been created exprDef::Construct will need to be more clever to return the [[Construct]] func, and ExprDef::Call will need to be more clever to return the [[Cal]] func

https://github.com/jasonwilliams/boa/blob/master/src/lib/js/string.rs#L556-L558 can go, ive not been a big fan of passing global in just to do that. Instead there should be a ::new() method which can be pulled into exec.rs

Refactoring
Functions (String(), Boolean(), Array()) should all be function objects to match https://tc39.es/ecma262/#function-object this can re-use https://github.com/jasonwilliams/boa/blob/master/src/lib/js/object.rs#L22-L31

Function Objects
https://tc39.es/ecma262/#function-object
A function object is just a regular object with the [[Call]] and [[Construct]] internal methods set

@jasonwilliams jasonwilliams added this to the v0.4.0 milestone Sep 8, 2019
@jasonwilliams
Copy link
Member Author

jasonwilliams commented Sep 8, 2019

A huge amount of the above work is now done. Constructor functions are now function objects which have a [[Construct]] and a [[Call]] method.
The Construct gets used here: https://github.com/jasonwilliams/boa/blob/master/src/lib/exec.rs#L281

Call currently doesn't use the [[Call]] internal slot.
https://github.com/jasonwilliams/boa/blob/master/src/lib/exec.rs#L111

@someguynamedmatt

This ticket may need to be broken out to others:
String: jasonwilliams#100

jasonwilliams added a commit that referenced this issue Sep 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants