refactor: improve meber listing system

This commit is contained in:
TopchetoEU 2024-09-06 10:01:34 +03:00
parent b6f04aa177
commit 515011b3ef
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
9 changed files with 98 additions and 81 deletions

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.runtime;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Stack;
import me.topchetoeu.jscript.common.Instruction;
@ -402,19 +402,11 @@ public final class Frame {
}
};
}
@Override public Map<String, Member> getOwnMembers(Environment env) {
var res = new LinkedHashMap<String, Member>();
@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 < stackPtr; 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;
}
});
}
for (var i = 0; i < stackPtr; i++) res.add(i + "");
return res;
}

View File

@ -7,7 +7,6 @@ import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.environment.Environment;
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.Value;
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) {
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);
frame.push(null);
for (var el : members) {
var obj = new ObjectValue();
obj.defineOwnMember(env, "value", FieldMember.of(new StringValue(el)));
obj.defineOwnMember(env, "value", new StringValue(el));
frame.push(obj);
}

View File

@ -70,10 +70,11 @@ public class JSONConverter {
var res = new JSONMap();
for (var el : val.getMembers(env, true, true).entrySet()) {
var jsonEl = fromJs(env, el.getValue().get(env, val), prev);
if (jsonEl == null) continue;
res.put(el.getKey(), jsonEl);
for (var key : val.getOwnMembers(env, true)) {
var el = fromJs(env, val.getMember(env, key), prev);
if (el == null) continue;
res.put(key, el);
}
prev.remove(val);

View File

@ -7,8 +7,9 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
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.Key;
@ -119,8 +120,8 @@ public abstract class Value {
}
public abstract Member getOwnMember(Environment env, KeyCache key);
public abstract Map<String, Member> getOwnMembers(Environment env);
public abstract Map<SymbolValue, Member> getOwnSymbolMembers(Environment env);
public abstract Set<String> getOwnMembers(Environment env, boolean onlyEnumerable);
public abstract Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable);
public abstract boolean defineOwnMember(Environment env, KeyCache key, Member member);
public abstract boolean deleteOwnMember(Environment env, KeyCache key);
@ -317,8 +318,8 @@ public abstract class Value {
return deleteMember(env, new KeyCache(key));
}
public final Map<String, Member> getMembers(Environment env, boolean own, boolean onlyEnumerable) {
var res = new LinkedHashMap<String, Member>();
public final Set<String> getMembers(Environment env, boolean own, boolean onlyEnumerable) {
var res = new LinkedHashSet<String>();
var protos = new ArrayList<Value>();
for (var proto = this; proto != null; proto = proto.getPrototype(env)) {
@ -329,19 +330,13 @@ public abstract class Value {
Collections.reverse(protos);
for (var proto : protos) {
if (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));
res.addAll(proto.getOwnMembers(env, onlyEnumerable));
}
return res;
}
public final Map<SymbolValue, Member> getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) {
var res = new LinkedHashMap<SymbolValue, Member>();
public final Set<SymbolValue> getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) {
var res = new LinkedHashSet<SymbolValue>();
var protos = new ArrayList<Value>();
for (var proto = this; proto != null; proto = proto.getPrototype(env)) {
@ -352,13 +347,7 @@ public abstract class Value {
Collections.reverse(protos);
for (var proto : protos) {
if (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));
res.addAll(proto.getOwnSymbolMembers(env, onlyEnumerable));
}
return res;
@ -444,7 +433,7 @@ public abstract class Value {
if (
func.prototype instanceof ObjectValue objProto &&
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"); }
}
else if (this instanceof ArrayValue) {
@ -469,29 +458,29 @@ public abstract class Value {
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");
}
else if (!printed) {
if (tab > 3) return "{...}";
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(" ");
res.append("[" + entry.getKey().value + "]" + ": ");
res.append("[" + entry.value + "]" + ": ");
var member = entry.getValue();
if (member instanceof FieldMember) res.append(((FieldMember)member).get(env, obj).toReadable(env, passed, tab + 1));
var member = obj.getOwnMember(env, entry);
if (member instanceof FieldMember field) res.append(field.get(env, obj).toReadable(env, passed, tab + 1));
else res.append("[property]");
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(" ");
res.append(entry.getKey() + ": ");
res.append(entry + ": ");
var member = entry.getValue();
if (member instanceof FieldMember) res.append(((FieldMember)member).get(env, obj).toReadable(env, passed, tab + 1));
var member = obj.getOwnMember(env, entry);
if (member instanceof FieldMember field) res.append(field.get(env, obj).toReadable(env, passed, tab + 1));
else res.append("[property]");
res.append(",\n");

View File

@ -4,8 +4,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
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.runtime.values.KeyCache;
@ -183,17 +183,16 @@ public class ArrayValue extends ObjectValue implements Iterable<Value> {
else return true;
}
@Override public Map<String, Member> getOwnMembers(Environment env) {
var res = new LinkedHashMap<String, Member>();
@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 < size; i++) {
var member = getOwnMember(env, i);
if (member != null) res.put(i + "", member);
if (has(i)) res.add(i + "");
}
res.put("length", lengthField);
res.putAll(super.getOwnMembers(env));
if (!onlyEnumerable) res.add("length");
return res;
}

View File

@ -1,8 +1,8 @@
package me.topchetoeu.jscript.runtime.values.objects;
import java.util.Collections;
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.Key;
@ -100,11 +100,29 @@ public class ObjectValue extends Value {
return true;
}
@Override public Map<String, Member> getOwnMembers(Environment env) {
return members;
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
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) {
return Collections.unmodifiableMap(symbolMembers);
@Override public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) {
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) {

View File

@ -1,6 +1,6 @@
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.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 Member getOwnMember(Environment env, KeyCache key) { return null; }
@Override public Map<String, Member> getOwnMembers(Environment env) { return Map.of(); }
@Override public Map<SymbolValue, Member> getOwnSymbolMembers(Environment env) { return Map.of(); }
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) { return Set.of(); }
@Override public Set<SymbolValue> getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return Set.of(); }
}

View File

@ -1,11 +1,14 @@
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.parsing.Parsing;
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.FieldMember;
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
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 Map<String, Member> getOwnMembers(Environment env) {
// TODO Auto-generated method stub
return super.getOwnMembers(env);
@Override public Member getOwnMember(Environment env, KeyCache key) {
var num = key.toNumber(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) {

View File

@ -1,6 +1,6 @@
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.runtime.exceptions.EngineException;
@ -24,17 +24,13 @@ public final class VoidValue extends PrimitiveValue {
@Override public Member getOwnMember(Environment env, KeyCache key) {
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));
}
@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));
}
// @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) {
this.name = name;
this.typeString = type;