refactor: improve meber listing system
This commit is contained in:
parent
b6f04aa177
commit
515011b3ef
@ -1,8 +1,8 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
package me.topchetoeu.jscript.runtime;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
@ -402,19 +402,11 @@ public final class Frame {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@Override public Map<String, Member> getOwnMembers(Environment env) {
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashMap<String, Member>();
|
var res = new LinkedHashSet<String>();
|
||||||
|
res.addAll(super.getOwnMembers(env, onlyEnumerable));
|
||||||
|
|
||||||
for (var i = 0; i < stackPtr; i++) {
|
for (var i = 0; i < stackPtr; i++) res.add(i + "");
|
||||||
var _i = i;
|
|
||||||
res.put(i + "", new FieldMember(false, true, true) {
|
|
||||||
@Override public Value get(Environment env, Value self) { return stack[_i]; }
|
|
||||||
@Override public boolean set(Environment env, Value val, Value self) {
|
|
||||||
stack[_i] = val;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import me.topchetoeu.jscript.common.Instruction;
|
|||||||
import me.topchetoeu.jscript.common.Operation;
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.Member.PropertyMember;
|
import me.topchetoeu.jscript.runtime.values.Member.PropertyMember;
|
||||||
import me.topchetoeu.jscript.runtime.values.Value;
|
import me.topchetoeu.jscript.runtime.values.Value;
|
||||||
import me.topchetoeu.jscript.runtime.values.functions.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.functions.CodeFunction;
|
||||||
@ -83,14 +82,14 @@ public class InstructionRunner {
|
|||||||
private static Value execKeys(Environment env, Instruction instr, Frame frame) {
|
private static Value execKeys(Environment env, Instruction instr, Frame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
var members = new ArrayList<>(val.getMembers(env, false, true).keySet());
|
var members = new ArrayList<>(val.getMembers(env, false, true));
|
||||||
Collections.reverse(members);
|
Collections.reverse(members);
|
||||||
|
|
||||||
frame.push(null);
|
frame.push(null);
|
||||||
|
|
||||||
for (var el : members) {
|
for (var el : members) {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineOwnMember(env, "value", FieldMember.of(new StringValue(el)));
|
obj.defineOwnMember(env, "value", new StringValue(el));
|
||||||
frame.push(obj);
|
frame.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +70,11 @@ public class JSONConverter {
|
|||||||
|
|
||||||
var res = new JSONMap();
|
var res = new JSONMap();
|
||||||
|
|
||||||
for (var el : val.getMembers(env, true, true).entrySet()) {
|
for (var key : val.getOwnMembers(env, true)) {
|
||||||
var jsonEl = fromJs(env, el.getValue().get(env, val), prev);
|
var el = fromJs(env, val.getMember(env, key), prev);
|
||||||
if (jsonEl == null) continue;
|
if (el == null) continue;
|
||||||
res.put(el.getKey(), jsonEl);
|
|
||||||
|
res.put(key, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev.remove(val);
|
prev.remove(val);
|
||||||
|
@ -7,8 +7,9 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.common.environment.Key;
|
import me.topchetoeu.jscript.common.environment.Key;
|
||||||
@ -119,8 +120,8 @@ public abstract class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract Member getOwnMember(Environment env, KeyCache key);
|
public abstract Member getOwnMember(Environment env, KeyCache key);
|
||||||
public abstract Map<String, Member> getOwnMembers(Environment env);
|
public abstract Set<String> getOwnMembers(Environment env, boolean onlyEnumerable);
|
||||||
public abstract Map<SymbolValue, Member> getOwnSymbolMembers(Environment env);
|
public abstract Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable);
|
||||||
public abstract boolean defineOwnMember(Environment env, KeyCache key, Member member);
|
public abstract boolean defineOwnMember(Environment env, KeyCache key, Member member);
|
||||||
public abstract boolean deleteOwnMember(Environment env, KeyCache key);
|
public abstract boolean deleteOwnMember(Environment env, KeyCache key);
|
||||||
|
|
||||||
@ -317,8 +318,8 @@ public abstract class Value {
|
|||||||
return deleteMember(env, new KeyCache(key));
|
return deleteMember(env, new KeyCache(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Map<String, Member> getMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
public final Set<String> getMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashMap<String, Member>();
|
var res = new LinkedHashSet<String>();
|
||||||
var protos = new ArrayList<Value>();
|
var protos = new ArrayList<Value>();
|
||||||
|
|
||||||
for (var proto = this; proto != null; proto = proto.getPrototype(env)) {
|
for (var proto = this; proto != null; proto = proto.getPrototype(env)) {
|
||||||
@ -329,19 +330,13 @@ public abstract class Value {
|
|||||||
Collections.reverse(protos);
|
Collections.reverse(protos);
|
||||||
|
|
||||||
for (var proto : protos) {
|
for (var proto : protos) {
|
||||||
if (onlyEnumerable) {
|
res.addAll(proto.getOwnMembers(env, onlyEnumerable));
|
||||||
for (var el : proto.getOwnMembers(env).entrySet()) {
|
|
||||||
if (!el.getValue().enumerable()) continue;
|
|
||||||
res.put(el.getKey(), el.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else res.putAll(proto.getOwnMembers(env));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public final Map<SymbolValue, Member> getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
public final Set<SymbolValue> getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashMap<SymbolValue, Member>();
|
var res = new LinkedHashSet<SymbolValue>();
|
||||||
var protos = new ArrayList<Value>();
|
var protos = new ArrayList<Value>();
|
||||||
|
|
||||||
for (var proto = this; proto != null; proto = proto.getPrototype(env)) {
|
for (var proto = this; proto != null; proto = proto.getPrototype(env)) {
|
||||||
@ -352,13 +347,7 @@ public abstract class Value {
|
|||||||
Collections.reverse(protos);
|
Collections.reverse(protos);
|
||||||
|
|
||||||
for (var proto : protos) {
|
for (var proto : protos) {
|
||||||
if (onlyEnumerable) {
|
res.addAll(proto.getOwnSymbolMembers(env, onlyEnumerable));
|
||||||
for (var el : proto.getOwnSymbolMembers(env).entrySet()) {
|
|
||||||
if (!el.getValue().enumerable()) continue;
|
|
||||||
res.put(el.getKey(), el.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else res.putAll(proto.getOwnSymbolMembers(env));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -444,7 +433,7 @@ public abstract class Value {
|
|||||||
if (
|
if (
|
||||||
func.prototype instanceof ObjectValue objProto &&
|
func.prototype instanceof ObjectValue objProto &&
|
||||||
objProto.getMember(env, "constructor") == func &&
|
objProto.getMember(env, "constructor") == func &&
|
||||||
objProto.getOwnMembers(env).size() + objProto.getOwnSymbolMembers(env).size() == 1
|
objProto.getOwnMembers(env, true).size() + objProto.getOwnSymbolMembers(env, true).size() == 1
|
||||||
) { keys.remove("constructor"); }
|
) { keys.remove("constructor"); }
|
||||||
}
|
}
|
||||||
else if (this instanceof ArrayValue) {
|
else if (this instanceof ArrayValue) {
|
||||||
@ -469,29 +458,29 @@ public abstract class Value {
|
|||||||
|
|
||||||
passed.add(this);
|
passed.add(this);
|
||||||
|
|
||||||
if (keys.size() + obj.getOwnSymbolMembers(env).size() == 0) {
|
if (keys.size() + obj.getOwnSymbolMembers(env, true).size() == 0) {
|
||||||
if (!printed) res.append("{}\n");
|
if (!printed) res.append("{}\n");
|
||||||
}
|
}
|
||||||
else if (!printed) {
|
else if (!printed) {
|
||||||
if (tab > 3) return "{...}";
|
if (tab > 3) return "{...}";
|
||||||
res.append("{\n");
|
res.append("{\n");
|
||||||
|
|
||||||
for (var entry : obj.getOwnSymbolMembers(env).entrySet()) {
|
for (var entry : obj.getOwnSymbolMembers(env, true)) {
|
||||||
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
||||||
res.append("[" + entry.getKey().value + "]" + ": ");
|
res.append("[" + entry.value + "]" + ": ");
|
||||||
|
|
||||||
var member = entry.getValue();
|
var member = obj.getOwnMember(env, entry);
|
||||||
if (member instanceof FieldMember) res.append(((FieldMember)member).get(env, obj).toReadable(env, passed, tab + 1));
|
if (member instanceof FieldMember field) res.append(field.get(env, obj).toReadable(env, passed, tab + 1));
|
||||||
else res.append("[property]");
|
else res.append("[property]");
|
||||||
|
|
||||||
res.append(",\n");
|
res.append(",\n");
|
||||||
}
|
}
|
||||||
for (var entry : obj.getOwnMembers(env).entrySet()) {
|
for (var entry : obj.getOwnMembers(env, true)) {
|
||||||
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
||||||
res.append(entry.getKey() + ": ");
|
res.append(entry + ": ");
|
||||||
|
|
||||||
var member = entry.getValue();
|
var member = obj.getOwnMember(env, entry);
|
||||||
if (member instanceof FieldMember) res.append(((FieldMember)member).get(env, obj).toReadable(env, passed, tab + 1));
|
if (member instanceof FieldMember field) res.append(field.get(env, obj).toReadable(env, passed, tab + 1));
|
||||||
else res.append("[property]");
|
else res.append("[property]");
|
||||||
|
|
||||||
res.append(",\n");
|
res.append(",\n");
|
||||||
|
@ -4,8 +4,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.KeyCache;
|
import me.topchetoeu.jscript.runtime.values.KeyCache;
|
||||||
@ -183,17 +183,16 @@ public class ArrayValue extends ObjectValue implements Iterable<Value> {
|
|||||||
else return true;
|
else return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Map<String, Member> getOwnMembers(Environment env) {
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
||||||
var res = new LinkedHashMap<String, Member>();
|
var res = new LinkedHashSet<String>();
|
||||||
|
|
||||||
|
res.addAll(super.getOwnMembers(env, onlyEnumerable));
|
||||||
|
|
||||||
for (var i = 0; i < size; i++) {
|
for (var i = 0; i < size; i++) {
|
||||||
var member = getOwnMember(env, i);
|
if (has(i)) res.add(i + "");
|
||||||
if (member != null) res.put(i + "", member);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.put("length", lengthField);
|
if (!onlyEnumerable) res.add("length");
|
||||||
|
|
||||||
res.putAll(super.getOwnMembers(env));
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values.objects;
|
package me.topchetoeu.jscript.runtime.values.objects;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.common.environment.Key;
|
import me.topchetoeu.jscript.common.environment.Key;
|
||||||
@ -100,11 +100,29 @@ public class ObjectValue extends Value {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Map<String, Member> getOwnMembers(Environment env) {
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
||||||
return members;
|
if (onlyEnumerable) {
|
||||||
|
var res = new LinkedHashSet<String>();
|
||||||
|
|
||||||
|
for (var el : members.entrySet()) {
|
||||||
|
if (el.getValue().enumerable()) res.add(el.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else return members.keySet();
|
||||||
}
|
}
|
||||||
@Override public Map<SymbolValue, Member> getOwnSymbolMembers(Environment env) {
|
@Override public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) {
|
||||||
return Collections.unmodifiableMap(symbolMembers);
|
if (onlyEnumerable) {
|
||||||
|
var res = new LinkedHashSet<SymbolValue>();
|
||||||
|
|
||||||
|
for (var el : symbolMembers.entrySet()) {
|
||||||
|
if (el.getValue().enumerable()) res.add(el.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else return symbolMembers.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public ObjectValue getPrototype(Environment env) {
|
@Override public ObjectValue getPrototype(Environment env) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values.primitives;
|
package me.topchetoeu.jscript.runtime.values.primitives;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.KeyCache;
|
import me.topchetoeu.jscript.runtime.values.KeyCache;
|
||||||
@ -17,6 +17,6 @@ public abstract class PrimitiveValue extends Value {
|
|||||||
@Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; }
|
@Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; }
|
||||||
|
|
||||||
@Override public Member getOwnMember(Environment env, KeyCache key) { return null; }
|
@Override public Member getOwnMember(Environment env, KeyCache key) { return null; }
|
||||||
@Override public Map<String, Member> getOwnMembers(Environment env) { return Map.of(); }
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) { return Set.of(); }
|
||||||
@Override public Map<SymbolValue, Member> getOwnSymbolMembers(Environment env) { return Map.of(); }
|
@Override public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return Set.of(); }
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values.primitives;
|
package me.topchetoeu.jscript.runtime.values.primitives;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.common.parsing.Parsing;
|
import me.topchetoeu.jscript.common.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.common.parsing.Source;
|
import me.topchetoeu.jscript.common.parsing.Source;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.KeyCache;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member;
|
import me.topchetoeu.jscript.runtime.values.Member;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
||||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||||
|
|
||||||
public final class StringValue extends PrimitiveValue {
|
public final class StringValue extends PrimitiveValue {
|
||||||
@ -32,9 +35,29 @@ public final class StringValue extends PrimitiveValue {
|
|||||||
|
|
||||||
@Override public ObjectValue getPrototype(Environment env) { return env.get(STRING_PROTO); }
|
@Override public ObjectValue getPrototype(Environment env) { return env.get(STRING_PROTO); }
|
||||||
|
|
||||||
@Override public Map<String, Member> getOwnMembers(Environment env) {
|
@Override public Member getOwnMember(Environment env, KeyCache key) {
|
||||||
// TODO Auto-generated method stub
|
var num = key.toNumber(env);
|
||||||
return super.getOwnMembers(env);
|
var i = key.toInt(env);
|
||||||
|
|
||||||
|
if (i == num && i >= 0 && i < value.length()) {
|
||||||
|
return FieldMember.of(new StringValue(value.charAt(i) + ""), false, true, false);
|
||||||
|
}
|
||||||
|
else if (key.toString(env).equals("length")) {
|
||||||
|
return FieldMember.of(new NumberValue(value.length()), false, false, false);
|
||||||
|
}
|
||||||
|
else return super.getOwnMember(env, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
||||||
|
var res = new LinkedHashSet<String>();
|
||||||
|
|
||||||
|
res.addAll(super.getOwnMembers(env, onlyEnumerable));
|
||||||
|
|
||||||
|
for (var i = 0; i < value.length(); i++) res.add(i + "");
|
||||||
|
|
||||||
|
if (!onlyEnumerable) res.add("length");
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringValue(String value) {
|
public StringValue(String value) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values.primitives;
|
package me.topchetoeu.jscript.runtime.values.primitives;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
@ -24,17 +24,13 @@ public final class VoidValue extends PrimitiveValue {
|
|||||||
@Override public Member getOwnMember(Environment env, KeyCache key) {
|
@Override public Member getOwnMember(Environment env, KeyCache key) {
|
||||||
throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toString(env)));
|
throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toString(env)));
|
||||||
}
|
}
|
||||||
@Override public Map<String, Member> getOwnMembers(Environment env) {
|
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
||||||
throw EngineException.ofError(String.format("Cannot read properties of %s (listing all members)", name));
|
throw EngineException.ofError(String.format("Cannot read properties of %s (listing all members)", name));
|
||||||
}
|
}
|
||||||
@Override public Map<SymbolValue, Member> getOwnSymbolMembers(Environment env) {
|
@Override public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) {
|
||||||
throw EngineException.ofError(String.format("Cannot read properties of %s (listing all symbol members)", name));
|
throw EngineException.ofError(String.format("Cannot read properties of %s (listing all symbol members)", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override public Value call(Environment env, Value self, Value... args) {
|
|
||||||
// throw EngineException.ofType(String.format("Tried to call a value of %s", name));
|
|
||||||
// }
|
|
||||||
|
|
||||||
public VoidValue(String name, StringValue type) {
|
public VoidValue(String name, StringValue type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.typeString = type;
|
this.typeString = type;
|
||||||
|
Loading…
Reference in New Issue
Block a user