Skip to content
This repository was archived by the owner on Dec 31, 2024. It is now read-only.

Commit 5e6e6fe

Browse files
committed
feat: some API improvements
1 parent 89eea7d commit 5e6e6fe

File tree

12 files changed

+90
-121
lines changed

12 files changed

+90
-121
lines changed

src/me/topchetoeu/jscript/engine/Context.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import me.topchetoeu.jscript.mapping.SourceMap;
2323

2424
public class Context implements Extensions {
25+
public static final Context NULL = new Context(null);
26+
2527
public final Context parent;
2628
public final Environment environment;
2729
public final CodeFrame frame;

src/me/topchetoeu/jscript/engine/Environment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static FunctionValue compileFunc(Extensions ext) {
7171
return ext.init(COMPILE_FUNC, new NativeFunction("compile", args -> {
7272
var source = args.getString(0);
7373
var filename = args.getString(1);
74-
var env = Values.wrapper(args.convert(2, ObjectValue.class).getMember(args.ctx, Symbol.get("env")), Environment.class);
74+
var env = Values.wrapper(Values.getMember(args.ctx, args.get(2), Symbol.get("env")), Environment.class);
7575
var isDebug = DebugContext.enabled(args.ctx);
7676
var res = new ObjectValue();
7777

src/me/topchetoeu/jscript/engine/ExtensionStack.java

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/me/topchetoeu/jscript/engine/debug/SimpleDebugger.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ public Frame(CodeFrame frame, int id) {
124124
this.global = frame.function.environment.global.obj;
125125
this.local = frame.getLocalScope(true);
126126
this.capture = frame.getCaptureScope(true);
127-
this.local.setPrototype(frame.ctx, capture);
128-
this.capture.setPrototype(frame.ctx, global);
127+
Values.makePrototypeChain(frame.ctx, global, capture, local);
129128
this.valstack = frame.getValStackScope();
130129

131130
this.serialized = new JSONMap()
@@ -841,7 +840,7 @@ else if (idToBreakpoint.containsKey(id)) {
841840
}
842841
else {
843842
propDesc.set("name", Values.toString(ctx, key));
844-
propDesc.set("value", serializeObj(ctx, obj.getMember(ctx, key)));
843+
propDesc.set("value", serializeObj(ctx, Values.getMember(ctx, obj, key)));
845844
propDesc.set("writable", obj.memberWritable(key));
846845
propDesc.set("enumerable", obj.memberEnumerable(key));
847846
propDesc.set("configurable", obj.memberConfigurable(key));
@@ -850,7 +849,7 @@ else if (idToBreakpoint.containsKey(id)) {
850849
}
851850
}
852851

853-
var proto = obj.getPrototype(ctx);
852+
var proto = Values.getPrototype(ctx, obj);
854853

855854
var protoDesc = new JSONMap();
856855
protoDesc.set("name", "__proto__");

src/me/topchetoeu/jscript/engine/frame/InstructionResult.java

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/me/topchetoeu/jscript/engine/scope/GlobalScope.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,35 @@
77
import me.topchetoeu.jscript.engine.values.FunctionValue;
88
import me.topchetoeu.jscript.engine.values.NativeFunction;
99
import me.topchetoeu.jscript.engine.values.ObjectValue;
10+
import me.topchetoeu.jscript.engine.values.Values;
1011
import me.topchetoeu.jscript.exceptions.EngineException;
1112

1213
public class GlobalScope implements ScopeRecord {
1314
public final ObjectValue obj;
1415

1516
public boolean has(Context ctx, String name) {
16-
return obj.hasMember(ctx, name, false);
17+
return Values.hasMember(null, obj, name, false);
1718
}
1819
public Object getKey(String name) {
1920
return name;
2021
}
2122

2223
public GlobalScope globalChild() {
2324
var obj = new ObjectValue();
24-
obj.setPrototype(null, this.obj);
25+
Values.setPrototype(null, obj, this.obj);
2526
return new GlobalScope(obj);
2627
}
2728
public LocalScopeRecord child() {
2829
return new LocalScopeRecord();
2930
}
3031

3132
public Object define(String name) {
32-
if (obj.hasMember(null, name, true)) return name;
33-
obj.defineProperty(null, name, null);
33+
if (Values.hasMember(Context.NULL, obj, name, false)) return name;
34+
obj.defineProperty(Context.NULL, name, null);
3435
return name;
3536
}
3637
public void define(String name, Variable val) {
37-
obj.defineProperty(null, name,
38+
obj.defineProperty(Context.NULL, name,
3839
new NativeFunction("get " + name, args -> val.get(args.ctx)),
3940
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
4041
true, true
@@ -51,12 +52,12 @@ public void define(boolean readonly, FunctionValue val) {
5152
}
5253

5354
public Object get(Context ctx, String name) {
54-
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
55-
else return obj.getMember(ctx, name);
55+
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
56+
else return Values.getMember(ctx, obj, name);
5657
}
5758
public void set(Context ctx, String name, Object val) {
58-
if (!obj.hasMember(ctx, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
59-
if (!obj.setMember(ctx, name, val, false)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
59+
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
60+
if (!Values.setMember(ctx, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
6061
}
6162

6263
public Set<String> keys() {

src/me/topchetoeu/jscript/engine/values/ObjectValue.java

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ public Property(FunctionValue getter, FunctionValue setter) {
5454
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
5555
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
5656

57+
private Property getProperty(Context ctx, Object key) {
58+
if (properties.containsKey(key)) return properties.get(key);
59+
var proto = getPrototype(ctx);
60+
if (proto != null) return proto.getProperty(ctx, key);
61+
else return null;
62+
}
63+
5764
public final boolean memberWritable(Object key) {
5865
if (state == State.FROZEN) return false;
5966
return !values.containsKey(key) || !nonWritableSet.contains(key);
@@ -159,33 +166,6 @@ public ObjectValue getPrototype(Context ctx) {
159166

160167
return (ObjectValue)prototype;
161168
}
162-
public final boolean setPrototype(Context ctx, Object val) {
163-
val = Values.normalize(ctx, val);
164-
165-
if (!extensible()) return false;
166-
if (val == null || val == Values.NULL) {
167-
prototype = null;
168-
return true;
169-
}
170-
else if (val instanceof ObjectValue) {
171-
var obj = Values.object(val);
172-
173-
if (ctx != null) {
174-
if (obj == ctx.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
175-
else if (obj == ctx.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
176-
else if (obj == ctx.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
177-
else if (obj == ctx.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
178-
else if (obj == ctx.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
179-
else if (obj == ctx.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
180-
else if (obj == ctx.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
181-
else prototype = obj;
182-
}
183-
else prototype = obj;
184-
185-
return true;
186-
}
187-
return false;
188-
}
189169
public final boolean setPrototype(PlaceholderProto val) {
190170
if (!extensible()) return false;
191171
switch (val) {
@@ -201,18 +181,21 @@ public final boolean setPrototype(PlaceholderProto val) {
201181
return true;
202182
}
203183

204-
protected Property getProperty(Context ctx, Object key) {
205-
if (properties.containsKey(key)) return properties.get(key);
206-
var proto = getPrototype(ctx);
207-
if (proto != null) return proto.getProperty(ctx, key);
208-
else return null;
209-
}
184+
/**
185+
* A method, used to get the value of a field. If a property is bound to
186+
* this key, but not a field, this method should return null.
187+
*/
210188
protected Object getField(Context ctx, Object key) {
211189
if (values.containsKey(key)) return values.get(key);
212190
var proto = getPrototype(ctx);
213191
if (proto != null) return proto.getField(ctx, key);
214192
else return null;
215193
}
194+
/**
195+
* Changes the value of a field, that is bound to the given key. If no field is
196+
* bound to this key, a new field should be created with the given value
197+
* @return Whether or not the operation was successful
198+
*/
216199
protected boolean setField(Context ctx, Object key, Object val) {
217200
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
218201
((FunctionValue)val).name = Values.toString(ctx, key);
@@ -221,9 +204,16 @@ protected boolean setField(Context ctx, Object key, Object val) {
221204
values.put(key, val);
222205
return true;
223206
}
207+
/**
208+
* Deletes the field bound to the given key.
209+
*/
224210
protected void deleteField(Context ctx, Object key) {
225211
values.remove(key);
226212
}
213+
/**
214+
* Returns whether or not there is a field bound to the given key.
215+
* This must ignore properties
216+
*/
227217
protected boolean hasField(Context ctx, Object key) {
228218
return values.containsKey(key);
229219
}
@@ -244,10 +234,6 @@ public final Object getMember(Context ctx, Object key, Object thisArg) {
244234
}
245235
else return getField(ctx, key);
246236
}
247-
public final Object getMember(Context ctx, Object key) {
248-
return getMember(ctx, key, this);
249-
}
250-
251237
public final boolean setMember(Context ctx, Object key, Object val, Object thisArg, boolean onlyProps) {
252238
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val);
253239

@@ -267,10 +253,6 @@ else if (key == null) {
267253
else if (nonWritableSet.contains(key)) return false;
268254
else return setField(ctx, key, val);
269255
}
270-
public final boolean setMember(Context ctx, Object key, Object val, boolean onlyProps) {
271-
return setMember(ctx, Values.normalize(ctx, key), Values.normalize(ctx, val), this, onlyProps);
272-
}
273-
274256
public final boolean hasMember(Context ctx, Object key, boolean own) {
275257
key = Values.normalize(ctx, key);
276258

@@ -291,6 +273,33 @@ public final boolean deleteMember(Context ctx, Object key) {
291273
deleteField(ctx, key);
292274
return true;
293275
}
276+
public final boolean setPrototype(Context ctx, Object val) {
277+
val = Values.normalize(ctx, val);
278+
279+
if (!extensible()) return false;
280+
if (val == null || val == Values.NULL) {
281+
prototype = null;
282+
return true;
283+
}
284+
else if (val instanceof ObjectValue) {
285+
var obj = Values.object(val);
286+
287+
if (ctx != null) {
288+
if (obj == ctx.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
289+
else if (obj == ctx.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
290+
else if (obj == ctx.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
291+
else if (obj == ctx.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
292+
else if (obj == ctx.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
293+
else if (obj == ctx.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
294+
else if (obj == ctx.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
295+
else prototype = obj;
296+
}
297+
else prototype = obj;
298+
299+
return true;
300+
}
301+
return false;
302+
}
294303

295304
public final ObjectValue getMemberDescriptor(Context ctx, Object key) {
296305
key = Values.normalize(ctx, key);

src/me/topchetoeu/jscript/engine/values/Values.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ public static Object getMember(Context ctx, Object obj, Object key) {
281281
obj = normalize(ctx, obj); key = normalize(ctx, key);
282282
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
283283
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
284-
if (obj instanceof ObjectValue) return object(obj).getMember(ctx, key);
284+
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMember(ctx, key, obj);
285285

286286
if (obj instanceof String && key instanceof Number) {
287287
var i = number(key);
@@ -307,7 +307,7 @@ public static boolean setMember(Context ctx, Object obj, Object key, Object val)
307307
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
308308
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
309309
if (key != null && "__proto__".equals(key)) return setPrototype(ctx, obj, val);
310-
if (obj instanceof ObjectValue) return object(obj).setMember(ctx, key, val, false);
310+
if (obj instanceof ObjectValue) return ((ObjectValue)obj).setMember(ctx, key, val, obj, false);
311311

312312
var proto = getPrototype(ctx, obj);
313313
return proto.setMember(ctx, key, val, obj, true);
@@ -340,7 +340,7 @@ public static boolean deleteMember(Context ctx, Object obj, Object key) {
340340
public static ObjectValue getPrototype(Context ctx, Object obj) {
341341
if (obj == null || obj == NULL) return null;
342342
obj = normalize(ctx, obj);
343-
if (obj instanceof ObjectValue) return object(obj).getPrototype(ctx);
343+
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ctx);
344344
if (ctx == null) return null;
345345

346346
if (obj instanceof String) return ctx.get(Environment.STRING_PROTO);
@@ -352,7 +352,12 @@ public static ObjectValue getPrototype(Context ctx, Object obj) {
352352
}
353353
public static boolean setPrototype(Context ctx, Object obj, Object proto) {
354354
obj = normalize(ctx, obj);
355-
return obj instanceof ObjectValue && object(obj).setPrototype(ctx, proto);
355+
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ctx, proto);
356+
}
357+
public static void makePrototypeChain(Context ctx, Object... chain) {
358+
for(var i = 1; i < chain.length; i++) {
359+
setPrototype(ctx, chain[i], chain[i - 1]);
360+
}
356361
}
357362
public static List<Object> getMembers(Context ctx, Object obj, boolean own, boolean includeNonEnumerable) {
358363
List<Object> res = new ArrayList<>();
@@ -367,7 +372,7 @@ public static List<Object> getMembers(Context ctx, Object obj, boolean own, bool
367372

368373
while (proto != null) {
369374
res.addAll(proto.keys(includeNonEnumerable));
370-
proto = proto.getPrototype(ctx);
375+
proto = getPrototype(ctx, proto);
371376
}
372377
}
373378

@@ -400,10 +405,10 @@ public static Object callNew(Context ctx, Object func, Object ...args) {
400405
var res = new ObjectValue();
401406
try {
402407
var proto = Values.getMember(ctx, func, "prototype");
403-
res.setPrototype(ctx, proto);
404-
408+
setPrototype(ctx, res, proto);
409+
405410
var ret = call(ctx, func, res, args);
406-
411+
407412
if (ret != null && func instanceof FunctionValue && ((FunctionValue)func).special) return ret;
408413
return res;
409414
}
@@ -569,11 +574,11 @@ public static Iterable<Object> fromJSIterator(Context ctx, Object obj) {
569574
private void loadNext() {
570575
if (next == null) value = null;
571576
else if (consumed) {
572-
var curr = object(next.call(ctx, iterator));
577+
var curr = next.call(ctx, iterator);
573578
if (curr == null) { next = null; value = null; }
574-
if (toBoolean(curr.getMember(ctx, "done"))) { next = null; value = null; }
579+
if (toBoolean(Values.getMember(ctx, curr, "done"))) { next = null; value = null; }
575580
else {
576-
this.value = curr.getMember(ctx, "value");
581+
this.value = Values.getMember(ctx, curr, "value");
577582
consumed = false;
578583
}
579584
}

src/me/topchetoeu/jscript/interop/NativeWrapperProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ private void initType(Class<?> clazz, FunctionValue constr, ObjectValue proto) {
298298
var parentProto = getProto(parent);
299299
var parentConstr = getConstr(parent);
300300

301-
if (parentProto != null) proto.setPrototype(null, parentProto);
302-
if (parentConstr != null) constr.setPrototype(null, parentConstr);
301+
if (parentProto != null) Values.setPrototype(Context.NULL, proto, parentProto);
302+
if (parentConstr != null) Values.setPrototype(Context.NULL, constr, parentConstr);
303303
}
304304

305305
public ObjectValue getProto(Class<?> clazz) {

0 commit comments

Comments
 (0)