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

Updated: Implement Symbol.prototype.description #1651

Merged
merged 5 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 62 additions & 11 deletions rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ public class LambdaConstructor extends LambdaFunction {
public static final int CONSTRUCTOR_DEFAULT = CONSTRUCTOR_FUNCTION | CONSTRUCTOR_NEW;

// Lambdas should not be serialized.
private final transient Constructable targetConstructor;
protected final transient Constructable targetConstructor;
private final int flags;

/**
* Create a new function that may be used as a constructor. The new object will have the
* Function prototype and no parent. The caller is responsible for binding this object to the
* appropriate scope.
* appropriate scope. The new constructor function can be invoked using "new" or by calling it
* directly, and in either case will result in a new object being returned and wired to the
* correct prototype and scope.
*
* @param scope scope of the calling context
* @param name name of the function
Expand All @@ -56,8 +58,18 @@ public LambdaConstructor(Scriptable scope, String name, int length, Constructabl
}

/**
* Create a new function and control whether it may be invoked using new, as a function, or
* both.
* Create a new function that may be used as a constructor. The new object will have the
* Function prototype and no parent. The caller is responsible for binding this object to the
* appropriate scope. The "flags" argument controls whether the function may be invoked using
* "new," via a direct call, or both. If allowed by the flags, then the constructor will have
* the same effect either way. If not allowed by the flags, then a TypeError will be thrown.
*
* @param scope scope of the calling context
* @param name name of the function
* @param length the arity of the function
* @param flags which may be a combination of CONSTRUCTOR_NEW and CONSTRUCTOR_FUNCTION
* @param target an object that implements the function in Java. Since Constructable is a
* single-function interface this will typically be implemented as a lambda.
*/
public LambdaConstructor(
Scriptable scope, String name, int length, int flags, Constructable target) {
Expand All @@ -67,8 +79,19 @@ public LambdaConstructor(
}

/**
* Create a new constructor that may be called using new or as a function, and exhibits
* different behavior for each.
* Create a new function that may be used as a constructor. The new object will have the
* Function prototype and no parent. The caller is responsible for binding this object to the
* appropriate scope. The new constructor function will have different behavior depending on
* whether it is invoked via "new" or via a direct call. In the case of "new", a new object with
* a prototype and scope chain be returned, but in the case of a direct call, the user must
* implement whatever they need. This is typically used in the case of functions like the native
* Date constructor, which has totally different behavior depending on how it's invoked.
*
* @param scope scope of the calling context
* @param name name of the function
* @param length the arity of the function
* @param target an object that implements the function in Java. Since Constructable is a
* single-function interface this will typically be implemented as a lambda.
*/
public LambdaConstructor(
Scriptable scope,
Expand All @@ -87,7 +110,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar
throw ScriptRuntime.typeErrorById("msg.constructor.no.function", getFunctionName());
}
if (target == null) {
return targetConstructor.construct(cx, scope, args);
return fireConstructor(cx, scope, args);
}
return target.call(cx, scope, thisObj, args);
}
Expand All @@ -97,6 +120,10 @@ public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
if ((flags & CONSTRUCTOR_NEW) == 0) {
throw ScriptRuntime.typeErrorById("msg.no.new", getFunctionName());
}
return fireConstructor(cx, scope, args);
}

private Scriptable fireConstructor(Context cx, Scriptable scope, Object[] args) {
Scriptable obj = targetConstructor.construct(cx, scope, args);
obj.setPrototype(getClassPrototype());
obj.setParentScope(scope);
Expand Down Expand Up @@ -130,6 +157,23 @@ public void definePrototypeMethod(
proto.defineProperty(name, f, attributes);
}

/**
* Define a function property on the prototype of the constructor using a LambdaFunction under
* the covers.
*/
public void definePrototypeMethod(
Scriptable scope,
SymbolKey name,
int length,
Callable target,
int attributes,
int propertyAttributes) {
LambdaFunction f = new LambdaFunction(scope, "[" + name.getName() + "]", length, target);
f.setStandardPropertyAttributes(propertyAttributes);
ScriptableObject proto = getPrototypeScriptable();
proto.defineProperty(name, f, attributes);
}

/** Define a property that may be of any type on the prototype of this constructor. */
public void definePrototypeProperty(String name, Object value, int attributes) {
ScriptableObject proto = getPrototypeScriptable();
Expand All @@ -141,15 +185,22 @@ public void definePrototypeProperty(Symbol key, Object value, int attributes) {
proto.defineProperty(key, value, attributes);
}

/**
* Define a property on the prototype using a function. The function will be wired to a
* JavaScript function, so the resulting property will look just like one that was defined using
* "Object.defineOwnProperty" with a property descriptor.
*/
public void definePrototypeProperty(
Context cx,
String name,
java.util.function.Function<Scriptable, Object> getter,
int attributes) {
Context cx, String name, Function<Scriptable, Object> getter, int attributes) {
ScriptableObject proto = getPrototypeScriptable();
proto.defineProperty(cx, name, getter, null, attributes);
}

/**
* Define a property on the prototype using functions for getter and setter. The function will
* be wired to a JavaScript function, so the resulting property will look just like one that was
* defined using "Object.defineOwnProperty" with a property descriptor.
*/
public void definePrototypeProperty(
Context cx,
String name,
Expand Down
Loading
Loading