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

Implement Symbol.prototype and other related Symbol and type coersion changes #1611

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ enum KEY_COERCION {
static boolean hasOwnProperty(Context cx, Object o, Object property) {
Scriptable obj = ScriptableObject.ensureScriptable(o);
boolean result;
if (property instanceof Symbol) {
if (ScriptRuntime.isSymbol(property)) {
result = ScriptableObject.ensureSymbolScriptable(o).has((Symbol) property, obj);
} else {
ScriptRuntime.StringIdOrIndex s = ScriptRuntime.toStringIdOrIndex(property);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ final void set(int id, Scriptable start, Object value) {
} else {
int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
Object name = valueArray[nameSlot];
if (name instanceof Symbol) {
if (ScriptRuntime.isSymbol(name)) {
if (start instanceof SymbolScriptable) {
((SymbolScriptable) start).put((Symbol) name, start, value);
}
Expand Down Expand Up @@ -241,7 +241,7 @@ final Object[] getNames(boolean getAll, boolean getSymbols, Object[] extraEntrie
names = new Object[maxId];
}
names[count++] = name;
} else if (getSymbols && (name instanceof Symbol)) {
} else if (getSymbols && ScriptRuntime.isSymbol(name)) {
if (names == null) {
names = new Object[maxId];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1949,7 +1949,7 @@ private static Boolean js_includes(
Object compareTo = args.length > 0 ? args[0] : Undefined.instance;

Scriptable o = ScriptRuntime.toObject(cx, scope, thisObj);
long len = ScriptRuntime.toLength(new Object[] {getProperty(thisObj, "length")}, 0);
long len = getLengthProperty(cx, o);
if (len == 0) return Boolean.FALSE;

long k;
Expand Down
61 changes: 49 additions & 12 deletions rhino/src/main/java/org/mozilla/javascript/NativeDate.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

/**
* This class implements the Date native object. See ECMA 15.9.
Expand Down Expand Up @@ -254,6 +255,10 @@ protected void initPrototypeId(int id) {
arity = 1;
s = "toJSON";
break;
case SymbolId_toPrimitive:
initPrototypeMethod(
DATE_TAG, id, SymbolKey.TO_PRIMITIVE, "[Symbol.toPrimitive]", 1);
return;
default:
throw new IllegalArgumentException(String.valueOf(id));
}
Expand Down Expand Up @@ -293,7 +298,8 @@ public Object execIdCall(
final String toISOString = "toISOString";

Scriptable o = ScriptRuntime.toObject(cx, scope, thisObj);
Object tv = ScriptRuntime.toPrimitive(o, ScriptRuntime.NumberClass);
Object tv =
ScriptRuntime.toPrimitive(o, Optional.of(ScriptRuntime.NumberClass));
if (tv instanceof Number) {
double d = ((Number) tv).doubleValue();
if (Double.isNaN(d) || Double.isInfinite(d)) {
Expand Down Expand Up @@ -322,6 +328,30 @@ public Object execIdCall(
}
return result;
}
case SymbolId_toPrimitive:
{
Scriptable o = ScriptRuntime.toObject(cx, scope, thisObj);
final Object arg0 = args.length > 0 ? args[0] : Undefined.instance;
final Optional<String> hint =
Optional.ofNullable(
arg0 instanceof CharSequence ? arg0.toString() : null);
final Class<?> tryFirst =
hint.map(
h -> {
if (h.equals("string") || h.equals("default")) {
return ScriptRuntime.StringClass;
} else if (h.equals("number")) {
return ScriptRuntime.NumberClass;
}
return null;
})
.orElseThrow(
() ->
ScriptRuntime.typeErrorById(
"msg.invalid.toprimitive.hint",
ScriptRuntime.toString(arg0)));
return ScriptableObject.getDefaultValue(o, tryFirst);
}
}

// The rest of Date.prototype methods require thisObj to be Date
Expand Down Expand Up @@ -1373,21 +1403,19 @@ private static Object jsConstructor(Context cx, Object[] args) {

// if called with just one arg -
if (args.length == 1) {
Object arg0 = args[0];
if (arg0 instanceof NativeDate) {
obj.date = ((NativeDate) arg0).date;
final Object value = args[0];
if (value instanceof NativeDate) {
obj.date = ((NativeDate) value).date;
return obj;
}
if (arg0 instanceof Scriptable) {
arg0 = ((Scriptable) arg0).getDefaultValue(null);
}
double date;
if (arg0 instanceof CharSequence) {
final Object v = ScriptRuntime.toPrimitive(value);
final double date;
if (v instanceof CharSequence) {
// it's a string; parse it.
date = date_parseString(cx, arg0.toString());
date = date_parseString(cx, v.toString());
} else {
// if it's not a string, use it as a millisecond date
date = ScriptRuntime.toNumber(arg0);
date = ScriptRuntime.toNumber(v);
}
obj.date = TimeClip(date);
return obj;
Expand Down Expand Up @@ -1899,6 +1927,14 @@ protected int findPrototypeId(String s) {
return id;
}

@Override
protected int findPrototypeId(Symbol key) {
if (SymbolKey.TO_PRIMITIVE.equals(key)) {
return SymbolId_toPrimitive;
}
return 0;
}

private static final int ConstructorId_now = -3,
ConstructorId_parse = -2,
ConstructorId_UTC = -1,
Expand Down Expand Up @@ -1949,7 +1985,8 @@ protected int findPrototypeId(String s) {
Id_setYear = 45,
Id_toISOString = 46,
Id_toJSON = 47,
MAX_PROTOTYPE_ID = Id_toJSON;
SymbolId_toPrimitive = 48,
MAX_PROTOTYPE_ID = SymbolId_toPrimitive;

private static final int Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6

Expand Down
4 changes: 2 additions & 2 deletions rhino/src/main/java/org/mozilla/javascript/NativeObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ public Object execIdCall(
Integer.toString(args.length));
}
Scriptable proto = (args[1] == null) ? null : ensureScriptable(args[1]);
if (proto instanceof Symbol) {
if (ScriptRuntime.isSymbol(proto)) {
throw ScriptRuntime.typeErrorById(
"msg.arg.not.object", ScriptRuntime.typeof(proto));
}
Expand Down Expand Up @@ -440,7 +440,7 @@ public Object execIdCall(
(key, value) -> {
if (key instanceof Integer) {
obj.put((Integer) key, obj, value);
} else if (key instanceof Symbol
} else if (ScriptRuntime.isSymbol(key)
&& obj instanceof SymbolScriptable) {
((SymbolScriptable) obj).put((Symbol) key, obj, value);
} else {
Expand Down
12 changes: 7 additions & 5 deletions rhino/src/main/java/org/mozilla/javascript/NativeSymbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,20 @@ public static void init(Context cx, Scriptable scope, boolean sealed) {

cx.putThreadLocal(CONSTRUCTOR_SLOT, Boolean.TRUE);
try {
createStandardSymbol(cx, scope, ctor, "iterator", SymbolKey.ITERATOR);
createStandardSymbol(cx, scope, ctor, "species", SymbolKey.SPECIES);
createStandardSymbol(cx, scope, ctor, "toStringTag", SymbolKey.TO_STRING_TAG);
createStandardSymbol(cx, scope, ctor, "asyncIterator", SymbolKey.ASYNC_ITERATOR);
createStandardSymbol(cx, scope, ctor, "hasInstance", SymbolKey.HAS_INSTANCE);
createStandardSymbol(
cx, scope, ctor, "isConcatSpreadable", SymbolKey.IS_CONCAT_SPREADABLE);
createStandardSymbol(cx, scope, ctor, "isRegExp", SymbolKey.IS_REGEXP);
createStandardSymbol(cx, scope, ctor, "toPrimitive", SymbolKey.TO_PRIMITIVE);
createStandardSymbol(cx, scope, ctor, "iterator", SymbolKey.ITERATOR);
createStandardSymbol(cx, scope, ctor, "match", SymbolKey.MATCH);
createStandardSymbol(cx, scope, ctor, "matchAll", SymbolKey.MATCH_ALL);
createStandardSymbol(cx, scope, ctor, "replace", SymbolKey.REPLACE);
createStandardSymbol(cx, scope, ctor, "search", SymbolKey.SEARCH);
createStandardSymbol(cx, scope, ctor, "species", SymbolKey.SPECIES);
createStandardSymbol(cx, scope, ctor, "split", SymbolKey.SPLIT);
createStandardSymbol(cx, scope, ctor, "toPrimitive", SymbolKey.TO_PRIMITIVE);
createStandardSymbol(cx, scope, ctor, "toStringTag", SymbolKey.TO_STRING_TAG);
createStandardSymbol(cx, scope, ctor, "unscopables", SymbolKey.UNSCOPABLES);

} finally {
Expand Down Expand Up @@ -164,7 +166,7 @@ protected void initPrototypeId(int id) {
break;
case SymbolId_toPrimitive:
initPrototypeMethod(
CLASS_NAME, id, SymbolKey.TO_PRIMITIVE, "Symbol.toPrimitive", 1);
CLASS_NAME, id, SymbolKey.TO_PRIMITIVE, "[Symbol.toPrimitive]", 1);
break;
default:
super.initPrototypeId(id);
Expand Down
Loading
Loading