Compare commits

..

3 Commits

Author SHA1 Message Date
1e982cd2ef
some minor restructuring 2025-01-24 00:22:15 +02:00
4389d115b6
use only babel 2025-01-24 00:22:03 +02:00
208444381e
move FunctionMap logic away from core 2025-01-24 00:21:51 +02:00
20 changed files with 383 additions and 298 deletions

View File

@ -1,199 +1,62 @@
package me.topchetoeu.j2s.common; package me.topchetoeu.j2s.common;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import me.topchetoeu.j2s.common.Instruction.BreakpointType; import me.topchetoeu.j2s.common.Instruction.BreakpointType;
public class FunctionMap { public interface FunctionMap {
public static class FunctionMapBuilder { public static final FunctionMap EMPTY = new FunctionMap() {
private Location first, last; @Override public Location first() {
private final TreeMap<Integer, Location> sourceMap = new TreeMap<>(); return null;
private final HashMap<Location, BreakpointType> breakpoints = new HashMap<>(); }
@Override public Location last() {
public Location toLocation(int pc) { return null;
return sourceMap.headMap(pc, true).firstEntry().getValue();
} }
public FunctionMapBuilder setDebug(Location loc, BreakpointType type) { @Override public Location toLocation(int i, boolean approximate) {
if (loc == null || type == null || type == BreakpointType.NONE) return this; return null;
breakpoints.put(loc, type);
return this;
}
public FunctionMapBuilder setLocation(int i, Location loc) {
if (loc == null || i < 0) return this;
if (first == null || first.compareTo(loc) > 0) first = loc;
if (last == null || last.compareTo(loc) < 0) last = loc;
sourceMap.put(i, loc);
return this;
}
public FunctionMapBuilder setLocationAndDebug(int i, Location loc, BreakpointType type) {
setDebug(loc, type);
setLocation(i, loc);
return this;
} }
public Location first() { @Override public BreakpointType getBreakpoint(int i) {
return first; return BreakpointType.NONE;
} }
public Location last() { @Override public Iterable<Location> breakpoints(Location start, Location end) {
return last; return Arrays.asList();
} }
public FunctionMapBuilder map(Function<Location, Location> mapper) { @Override public Location correctBreakpoint(Location i) {
var newSourceMaps = new HashMap<Integer, Location>(); return null;
var newBreakpoints = new HashMap<Location, BreakpointType>(); }
@Override public Iterable<Location> correctBreakpoint(Pattern filename, int line, int column) {
for (var key : sourceMap.keySet()) { return Arrays.asList();
var mapped = mapper.apply(sourceMap.get(key));
if (mapped == null) continue;
newSourceMaps.put(key, mapped);
}
for (var key : breakpoints.keySet()) {
var mapped = mapper.apply(key);
if (mapped == null) continue;
newBreakpoints.put(mapped, breakpoints.get(key));
}
sourceMap.clear();
sourceMap.putAll(newSourceMaps);
breakpoints.clear();
breakpoints.putAll(newBreakpoints);
return this;
} }
public FunctionMap build(String[] localNames, String[] capturableNames, String[] captureNames) { @Override public String[] localNames() {
return new FunctionMap(sourceMap, breakpoints, first, last, localNames, capturableNames, captureNames); return null;
} }
public FunctionMap build() { @Override public String[] capturableNames() {
return new FunctionMap(sourceMap, breakpoints, first, last, new String[0], new String[0], new String[0]); return null;
} }
@Override public String[] captureNames() {
private FunctionMapBuilder() { } return null;
}
public static final FunctionMap EMPTY = new FunctionMap();
private final HashMap<Integer, BreakpointType> bps = new HashMap<>();
private final HashMap<Filename, TreeSet<Location>> bpLocs = new HashMap<>();
private final TreeMap<Integer, Location> pcToLoc = new TreeMap<>();
public final String[] localNames, capturableNames, captureNames;
public final Location first, last;
public Location toLocation(int pc, boolean approximate) {
if (pcToLoc.size() == 0 || pc < 0 || pc > pcToLoc.lastKey()) return null;
var res = pcToLoc.get(pc);
if (!approximate || res != null) return res;
var entry = pcToLoc.headMap(pc, true).lastEntry();
if (entry == null) return null;
else return entry.getValue();
}
public Location toLocation(int pc) {
return toLocation(pc, false);
}
public BreakpointType getBreakpoint(int pc) {
return bps.getOrDefault(pc, BreakpointType.NONE);
}
public Location correctBreakpoint(Location loc) {
var set = bpLocs.get(loc.filename());
if (set == null) return null;
else return set.ceiling(loc);
}
public List<Location> correctBreakpoint(Pattern filename, int line, int column) {
var candidates = new HashMap<Filename, TreeSet<Location>>();
for (var name : bpLocs.keySet()) {
if (filename.matcher(name.toString()).matches()) {
candidates.put(name, bpLocs.get(name));
}
} }
};
var res = new ArrayList<Location>(candidates.size()); Location first();
for (var candidate : candidates.entrySet()) { Location last();
var val = correctBreakpoint(Location.of(candidate.getKey(), line, column));
if (val == null) continue;
res.add(val);
}
return res; Location toLocation(int i, boolean approximate);
} default Location toLocation(int i) {
public List<Location> breakpoints(Location start, Location end) { return toLocation(i, false);
if (!Objects.equals(start.filename(), end.filename())) return Arrays.asList();
NavigableSet<Location> set = bpLocs.get(start.filename());
if (set == null) return Arrays.asList();
if (start != null) set = set.tailSet(start, true);
if (end != null) set = set.headSet(end, true);
return set.stream().collect(Collectors.toList());
} }
public Location start() { BreakpointType getBreakpoint(int i);
if (pcToLoc.size() == 0) return null; Location correctBreakpoint(Location i);
return pcToLoc.firstEntry().getValue(); Iterable<Location> correctBreakpoint(Pattern filename, int line, int column);
} Iterable<Location> breakpoints(Location start, Location end);
public Location end() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.lastEntry().getValue();
}
public FunctionMap clone() { String[] localNames();
var res = new FunctionMap(new HashMap<>(), new HashMap<>(), first, last, localNames, capturableNames, captureNames); String[] capturableNames();
res.pcToLoc.putAll(this.pcToLoc); String[] captureNames();
res.bps.putAll(bps); }
res.bpLocs.putAll(bpLocs);
res.pcToLoc.putAll(pcToLoc);
return res;
}
public FunctionMap(Map<Integer, Location> map, Map<Location, BreakpointType> breakpoints, Location first, Location last, String[] localNames, String[] capturableNames, String[] captureNames) {
var locToPc = new HashMap<Location, Integer>();
for (var el : map.entrySet()) {
pcToLoc.put(el.getKey(), el.getValue());
locToPc.putIfAbsent(el.getValue(), el.getKey());
}
for (var el : breakpoints.entrySet()) {
if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue;
bps.put(locToPc.get(el.getKey()), el.getValue());
if (!bpLocs.containsKey(el.getKey().filename())) bpLocs.put(el.getKey().filename(), new TreeSet<>());
bpLocs.get(el.getKey().filename()).add(el.getKey());
}
this.localNames = localNames;
this.captureNames = captureNames;
this.capturableNames = capturableNames;
this.first = first;
this.last = last;
}
private FunctionMap() {
localNames = new String[0];
captureNames = new String[0];
capturableNames = new String[0];
first = null;
last = null;
}
public static FunctionMapBuilder builder() {
return new FunctionMapBuilder();
}
}

View File

@ -51,11 +51,11 @@ public class Instruction {
STORE_MEMBER_INT(0x4A), STORE_MEMBER_INT(0x4A),
STORE_MEMBER_STR(0x4B), STORE_MEMBER_STR(0x4B),
OPERATION(0x50), GLOB_GET(0x50),
GLOB_SET(0x51),
GLOB_DEF(0x52),
GLOB_GET(0x60), OPERATION(0x56);
GLOB_SET(0x61),
GLOB_DEF(0x62);
private static final HashMap<Integer, Type> types = new HashMap<>(); private static final HashMap<Integer, Type> types = new HashMap<>();
public final int numeric; public final int numeric;

View File

@ -1,18 +0,0 @@
package me.topchetoeu.j2s.common;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class TestFunctionMap {
@Test public void createEmpty() {
FunctionMap.builder().build(null, null, null);
FunctionMap.builder().build();
}
@Test public void startOfEmpty() {
var empty = FunctionMap.EMPTY;
assertEquals(null, empty.start());
assertEquals(null, empty.end());
}
}

View File

@ -0,0 +1,219 @@
package me.topchetoeu.j2s.compilation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import me.topchetoeu.j2s.common.Filename;
import me.topchetoeu.j2s.common.FunctionMap;
import me.topchetoeu.j2s.common.Location;
import me.topchetoeu.j2s.common.Instruction.BreakpointType;
public final class CompilationFunctionMap implements FunctionMap {
public static class FunctionMapBuilder {
private Location first, last;
private final TreeMap<Integer, Location> sourceMap = new TreeMap<>();
private final HashMap<Location, BreakpointType> breakpoints = new HashMap<>();
public Location toLocation(int pc) {
return sourceMap.headMap(pc, true).firstEntry().getValue();
}
public FunctionMapBuilder setDebug(Location loc, BreakpointType type) {
if (loc == null || type == null || type == BreakpointType.NONE) return this;
breakpoints.put(loc, type);
return this;
}
public FunctionMapBuilder setLocation(int i, Location loc) {
if (loc == null || i < 0) return this;
if (first == null || first.compareTo(loc) > 0) first = loc;
if (last == null || last.compareTo(loc) < 0) last = loc;
sourceMap.put(i, loc);
return this;
}
public FunctionMapBuilder setLocationAndDebug(int i, Location loc, BreakpointType type) {
setDebug(loc, type);
setLocation(i, loc);
return this;
}
public Location first() {
return first;
}
public Location last() {
return last;
}
public FunctionMapBuilder map(Function<Location, Location> mapper) {
var newSourceMaps = new HashMap<Integer, Location>();
var newBreakpoints = new HashMap<Location, BreakpointType>();
for (var key : sourceMap.keySet()) {
var mapped = mapper.apply(sourceMap.get(key));
if (mapped == null) continue;
newSourceMaps.put(key, mapped);
}
for (var key : breakpoints.keySet()) {
var mapped = mapper.apply(key);
if (mapped == null) continue;
newBreakpoints.put(mapped, breakpoints.get(key));
}
sourceMap.clear();
sourceMap.putAll(newSourceMaps);
breakpoints.clear();
breakpoints.putAll(newBreakpoints);
return this;
}
public CompilationFunctionMap build(String[] localNames, String[] capturableNames, String[] captureNames) {
return new CompilationFunctionMap(sourceMap, breakpoints, first, last, localNames, capturableNames, captureNames);
}
public CompilationFunctionMap build() {
return new CompilationFunctionMap(sourceMap, breakpoints, first, last, new String[0], new String[0], new String[0]);
}
private FunctionMapBuilder() { }
}
public static final CompilationFunctionMap EMPTY = new CompilationFunctionMap();
private final HashMap<Integer, BreakpointType> bps = new HashMap<>();
private final HashMap<Filename, TreeSet<Location>> bpLocs = new HashMap<>();
private final TreeMap<Integer, Location> pcToLoc = new TreeMap<>();
public final String[] localNames, capturableNames, captureNames;
public final Location first, last;
@Override public Location toLocation(int pc, boolean approximate) {
if (pcToLoc.size() == 0 || pc < 0 || pc > pcToLoc.lastKey()) return null;
var res = pcToLoc.get(pc);
if (!approximate || res != null) return res;
var entry = pcToLoc.headMap(pc, true).lastEntry();
if (entry == null) return null;
else return entry.getValue();
}
@Override public Location toLocation(int pc) {
return toLocation(pc, false);
}
@Override public BreakpointType getBreakpoint(int pc) {
return bps.getOrDefault(pc, BreakpointType.NONE);
}
@Override public Location correctBreakpoint(Location loc) {
var set = bpLocs.get(loc.filename());
if (set == null) return null;
else return set.ceiling(loc);
}
@Override public List<Location> correctBreakpoint(Pattern filename, int line, int column) {
var candidates = new HashMap<Filename, TreeSet<Location>>();
for (var name : bpLocs.keySet()) {
if (filename.matcher(name.toString()).matches()) {
candidates.put(name, bpLocs.get(name));
}
}
var res = new ArrayList<Location>(candidates.size());
for (var candidate : candidates.entrySet()) {
var val = correctBreakpoint(Location.of(candidate.getKey(), line, column));
if (val == null) continue;
res.add(val);
}
return res;
}
@Override public List<Location> breakpoints(Location start, Location end) {
if (!Objects.equals(start.filename(), end.filename())) return Arrays.asList();
NavigableSet<Location> set = bpLocs.get(start.filename());
if (set == null) return Arrays.asList();
if (start != null) set = set.tailSet(start, true);
if (end != null) set = set.headSet(end, true);
return set.stream().collect(Collectors.toList());
}
public Location start() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.firstEntry().getValue();
}
public Location end() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.lastEntry().getValue();
}
@Override public Location first() {
return first;
}
@Override public Location last() {
return last;
}
@Override public String[] capturableNames() {
return capturableNames;
}
@Override public String[] captureNames() {
return captureNames;
}
@Override public String[] localNames() {
return localNames;
}
public CompilationFunctionMap clone() {
var res = new CompilationFunctionMap(new HashMap<>(), new HashMap<>(), first, last, localNames, capturableNames, captureNames);
res.pcToLoc.putAll(this.pcToLoc);
res.bps.putAll(bps);
res.bpLocs.putAll(bpLocs);
res.pcToLoc.putAll(pcToLoc);
return res;
}
public CompilationFunctionMap(Map<Integer, Location> map, Map<Location, BreakpointType> breakpoints, Location first, Location last, String[] localNames, String[] capturableNames, String[] captureNames) {
var locToPc = new HashMap<Location, Integer>();
for (var el : map.entrySet()) {
pcToLoc.put(el.getKey(), el.getValue());
locToPc.putIfAbsent(el.getValue(), el.getKey());
}
for (var el : breakpoints.entrySet()) {
if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue;
bps.put(locToPc.get(el.getKey()), el.getValue());
if (!bpLocs.containsKey(el.getKey().filename())) bpLocs.put(el.getKey().filename(), new TreeSet<>());
bpLocs.get(el.getKey().filename()).add(el.getKey());
}
this.localNames = localNames;
this.captureNames = captureNames;
this.capturableNames = capturableNames;
this.first = first;
this.last = last;
}
private CompilationFunctionMap() {
localNames = new String[0];
captureNames = new String[0];
capturableNames = new String[0];
first = null;
last = null;
}
public static FunctionMapBuilder builder() {
return new FunctionMapBuilder();
}
}

View File

@ -7,12 +7,11 @@ import java.util.function.Function;
import me.topchetoeu.j2s.common.Environment; import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.common.FunctionBody; import me.topchetoeu.j2s.common.FunctionBody;
import me.topchetoeu.j2s.common.FunctionMap;
import me.topchetoeu.j2s.common.Instruction; import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.Key; import me.topchetoeu.j2s.common.Key;
import me.topchetoeu.j2s.common.Location; import me.topchetoeu.j2s.common.Location;
import me.topchetoeu.j2s.common.FunctionMap.FunctionMapBuilder;
import me.topchetoeu.j2s.common.Instruction.BreakpointType; import me.topchetoeu.j2s.common.Instruction.BreakpointType;
import me.topchetoeu.j2s.compilation.CompilationFunctionMap.FunctionMapBuilder;
import me.topchetoeu.j2s.compilation.control.TryNode; import me.topchetoeu.j2s.compilation.control.TryNode;
import me.topchetoeu.j2s.compilation.scope.FunctionScope; import me.topchetoeu.j2s.compilation.scope.FunctionScope;
import me.topchetoeu.j2s.compilation.scope.Variable; import me.topchetoeu.j2s.compilation.scope.Variable;
@ -104,10 +103,10 @@ public final class CompileResult {
return instructions.toArray(new Instruction[0]); return instructions.toArray(new Instruction[0]);
} }
public FunctionMap map(Function<Location, Location> mapper) { public CompilationFunctionMap map(Function<Location, Location> mapper) {
return map.map(mapper).build(scope.localNames(), scope.capturableNames(), scope.captureNames()); return map.map(mapper).build(scope.localNames(), scope.capturableNames(), scope.captureNames());
} }
public FunctionMap map() { public CompilationFunctionMap map() {
return map.build(scope.localNames(), scope.capturableNames(), scope.captureNames()); return map.build(scope.localNames(), scope.capturableNames(), scope.captureNames());
} }
public FunctionBody body() { public FunctionBody body() {
@ -155,7 +154,7 @@ public final class CompileResult {
this.scope = scope; this.scope = scope;
this.instructions = new ArrayList<>(); this.instructions = new ArrayList<>();
this.children = new LinkedList<>(); this.children = new LinkedList<>();
this.map = FunctionMap.builder(); this.map = CompilationFunctionMap.builder();
this.env = env; this.env = env;
this.length = length; this.length = length;
} }

View File

@ -72,7 +72,7 @@ export interface BufferPrimordials {
export interface FunctionPrimordials { export interface FunctionPrimordials {
invokeType(args: IArguments, self: any): "new" | "call"; invokeType(args: IArguments, self: any): "new" | "call";
invokeTypeInfer(): "new" | "call"; invokeTypeInfer(): "new" | "call";
target(): Function | null | undefined; target(level?: number): Function | null | undefined;
setConstructable(func: Function, flag: boolean): void; setConstructable(func: Function, flag: boolean): void;
setCallable(func: Function, flag: boolean): void; setCallable(func: Function, flag: boolean): void;
invoke(func: Function, self: any, args: any[]): any; invoke(func: Function, self: any, args: any[]): any;

View File

@ -58,6 +58,10 @@ export const Function = (() => {
public static compile(src: string, filename?: string) { public static compile(src: string, filename?: string) {
return compile(String(src), filename); return compile(String(src), filename);
} }
public static newTarget() {
return func.target(1);
}
} }
func.setCallable(Function, true); func.setCallable(Function, true);

View File

@ -1,4 +1,3 @@
import coffeescript from "./coffeescript.ts";
import babel from "./babel.ts"; import babel from "./babel.ts";
register(v => coffeescript(babel(v))); register(babel);

View File

@ -47,6 +47,7 @@ export default function babel(next: Compiler): Compiler {
availablePlugins["transform-exponentiation-operator"], availablePlugins["transform-exponentiation-operator"],
// ES2015 // ES2015
availablePlugins["transform-arrow-functions"],
availablePlugins["transform-block-scoping"], availablePlugins["transform-block-scoping"],
availablePlugins["transform-classes"], availablePlugins["transform-classes"],
availablePlugins["transform-computed-properties"], availablePlugins["transform-computed-properties"],

View File

@ -30,6 +30,7 @@ import me.topchetoeu.j2s.repl.buffers.Int32ArrayValue;
import me.topchetoeu.j2s.repl.buffers.Int8ArrayValue; import me.topchetoeu.j2s.repl.buffers.Int8ArrayValue;
import me.topchetoeu.j2s.repl.buffers.TypedArrayValue; import me.topchetoeu.j2s.repl.buffers.TypedArrayValue;
import me.topchetoeu.j2s.repl.buffers.Uint8ArrayValue; import me.topchetoeu.j2s.repl.buffers.Uint8ArrayValue;
import me.topchetoeu.j2s.repl.debug.SimpleDebugHandler;
import me.topchetoeu.j2s.repl.debug.DebugServer; import me.topchetoeu.j2s.repl.debug.DebugServer;
import me.topchetoeu.j2s.repl.debug.Debugger; import me.topchetoeu.j2s.repl.debug.Debugger;
import me.topchetoeu.j2s.repl.debug.SimpleDebugger; import me.topchetoeu.j2s.repl.debug.SimpleDebugger;
@ -39,7 +40,7 @@ import me.topchetoeu.j2s.runtime.Compiler;
import me.topchetoeu.j2s.runtime.Engine; import me.topchetoeu.j2s.runtime.Engine;
import me.topchetoeu.j2s.runtime.EventLoop; import me.topchetoeu.j2s.runtime.EventLoop;
import me.topchetoeu.j2s.runtime.Frame; import me.topchetoeu.j2s.runtime.Frame;
import me.topchetoeu.j2s.runtime.debug.DebugContext; import me.topchetoeu.j2s.runtime.debug.DebugHandler;
import me.topchetoeu.j2s.runtime.exceptions.EngineException; import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.Value; import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction; import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
@ -61,9 +62,9 @@ public class SimpleRepl {
var res = JavaScript.compile(env, filename, raw, true); var res = JavaScript.compile(env, filename, raw, true);
var body = res.body(); var body = res.body();
DebugContext.get(env).onSource(filename, raw); DebugHandler.get(env).onSourceLoad(filename, raw);
for (var el : res.all()) { for (var el : res.all()) {
DebugContext.get(env).onFunctionLoad(el.body(), el.map(mapper)); DebugHandler.get(env).onFunctionLoad(el.body(), el.map(mapper));
} }
return new CodeFunction(env, filename.toString(), body, new Value[0][]); return new CodeFunction(env, filename.toString(), body, new Value[0][]);
@ -98,8 +99,8 @@ public class SimpleRepl {
server = new DebugServer(); server = new DebugServer();
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true); debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
server.targets.put("default", (socket, req) -> new SimpleDebugger(socket) server.targets.put("default", (socket, req) -> new SimpleDebugger(socket)
.attach(DebugContext.get(environment)) .attach((SimpleDebugHandler)DebugHandler.get(environment))
.attach(DebugContext.get(tsEnvironment)) .attach((SimpleDebugHandler)DebugHandler.get(tsEnvironment))
); );
try { try {
@ -846,7 +847,7 @@ public class SimpleRepl {
private static Environment initEnv() { private static Environment initEnv() {
var env = new Environment(); var env = new Environment();
env.add(EventLoop.KEY, engine); env.add(EventLoop.KEY, engine);
env.add(DebugContext.KEY, new DebugContext()); env.add(DebugHandler.KEY, new SimpleDebugHandler());
env.add(Compiler.KEY, DEFAULT_COMPILER); env.add(Compiler.KEY, DEFAULT_COMPILER);
// env.add(CompileResult.DEBUG_LOG); // env.add(CompileResult.DEBUG_LOG);
@ -905,7 +906,7 @@ public class SimpleRepl {
tsGlob.defineOwnField(tsEnvironment, "registerSource", new NativeFunction(args -> { tsGlob.defineOwnField(tsEnvironment, "registerSource", new NativeFunction(args -> {
var filename = Filename.parse(args.get(0).toString(args.env)); var filename = Filename.parse(args.get(0).toString(args.env));
var src = args.get(1).toString(args.env); var src = args.get(1).toString(args.env);
DebugContext.get(environment).onSource(filename, src); DebugHandler.get(environment).onSourceLoad(filename, src);
return Value.UNDEFINED; return Value.UNDEFINED;
})); }));

View File

@ -1,24 +1,19 @@
package me.topchetoeu.j2s.runtime.debug; package me.topchetoeu.j2s.repl.debug;
import java.util.HashMap; import java.util.HashMap;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import me.topchetoeu.j2s.common.Environment; import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.common.Filename; import me.topchetoeu.j2s.common.Filename;
import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.FunctionBody; import me.topchetoeu.j2s.common.FunctionBody;
import me.topchetoeu.j2s.common.FunctionMap; import me.topchetoeu.j2s.common.FunctionMap;
import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.Key;
import me.topchetoeu.j2s.runtime.Frame; import me.topchetoeu.j2s.runtime.Frame;
import me.topchetoeu.j2s.runtime.debug.DebugHandler;
import me.topchetoeu.j2s.runtime.exceptions.EngineException; import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.Value; import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
public class DebugContext {
public static final Key<DebugContext> KEY = new Key<>();
public static final Key<Void> IGNORE = new Key<>();
public class SimpleDebugHandler implements DebugHandler {
private HashMap<Filename, String> sources; private HashMap<Filename, String> sources;
private WeakHashMap<FunctionBody, FunctionMap> maps; private WeakHashMap<FunctionBody, FunctionMap> maps;
private DebugHandler debugger; private DebugHandler debugger;
@ -49,24 +44,10 @@ public class DebugContext {
return debugger; return debugger;
} }
public FunctionMap getMap(FunctionBody func) { public FunctionMap getMap(Environment env, FunctionBody func) {
if (maps == null) return null; if (maps == null) return null;
return maps.get(func); return maps.get(func);
} }
public FunctionMap getMap(FunctionValue func) {
if (maps == null || !(func instanceof CodeFunction)) return null;
return getMap(((CodeFunction)func).body);
}
public FunctionMap getMapOrEmpty(FunctionBody func) {
if (maps == null) return FunctionMap.EMPTY;
var res = maps.get(func);
if (res == null) return FunctionMap.EMPTY;
else return res;
}
public FunctionMap getMapOrEmpty(FunctionValue func) {
if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY;
return getMapOrEmpty(((CodeFunction)func).body);
}
public void onFramePop(Environment env, Frame frame) { public void onFramePop(Environment env, Frame frame) {
if (debugger != null) debugger.onFramePop(env, frame); if (debugger != null) debugger.onFramePop(env, frame);
@ -75,39 +56,27 @@ public class DebugContext {
if (debugger != null) debugger.onFramePush(env, frame); if (debugger != null) debugger.onFramePush(env, frame);
} }
public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Value returnVal, EngineException error, boolean caught) { @Override public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Value returnVal, EngineException error, boolean caught) {
if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught); if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught);
else return false; else return false;
} }
public boolean onInstruction(Environment env, Frame frame, Instruction instruction) { @Override public void onSourceLoad(Filename filename, String source) {
if (debugger != null) return debugger.onInstruction(env, frame, instruction, null, null, false);
else return false;
}
public void onSource(Filename filename, String source) {
if (debugger != null) debugger.onSourceLoad(filename, source); if (debugger != null) debugger.onSourceLoad(filename, source);
if (sources != null) sources.put(filename, source); if (sources != null) sources.put(filename, source);
} }
public void onFunctionLoad(FunctionBody func, FunctionMap map) { @Override public void onFunctionLoad(FunctionBody func, FunctionMap map) {
if (maps != null) maps.put(func, map); if (maps != null) maps.put(func, map);
if (debugger != null) debugger.onFunctionLoad(func, map); if (debugger != null) debugger.onFunctionLoad(func, map);
} }
private DebugContext(boolean enabled) { private SimpleDebugHandler(boolean enabled) {
if (enabled) { if (enabled) {
sources = new HashMap<>(); sources = new HashMap<>();
maps = new WeakHashMap<>(); maps = new WeakHashMap<>();
} }
} }
public DebugContext() { public SimpleDebugHandler() {
this(true); this(true);
} }
public static boolean enabled(Environment exts) {
return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE);
}
public static DebugContext get(Environment exts) {
if (enabled(exts)) return exts.get(KEY);
else return new DebugContext(false);
}
} }

View File

@ -30,7 +30,7 @@ import me.topchetoeu.j2s.runtime.Compiler;
import me.topchetoeu.j2s.runtime.Engine; import me.topchetoeu.j2s.runtime.Engine;
import me.topchetoeu.j2s.runtime.EventLoop; import me.topchetoeu.j2s.runtime.EventLoop;
import me.topchetoeu.j2s.runtime.Frame; import me.topchetoeu.j2s.runtime.Frame;
import me.topchetoeu.j2s.runtime.debug.DebugContext; import me.topchetoeu.j2s.runtime.debug.DebugHandler;
import me.topchetoeu.j2s.runtime.exceptions.EngineException; import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.Value; import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.Member.FieldMember; import me.topchetoeu.j2s.runtime.values.Member.FieldMember;
@ -201,11 +201,11 @@ public class SimpleDebugger implements Debugger {
this.frame = frame; this.frame = frame;
this.id = id; this.id = id;
var map = DebugContext.get(frame.env).getMapOrEmpty(frame.function); var map = DebugHandler.get(frame.env).getMapOrEmpty(frame.env, frame.function);
this.globals = Value.global(frame.env); this.globals = Value.global(frame.env);
this.locals = ScopeObject.locals(frame, map.localNames); this.locals = ScopeObject.locals(frame, map.localNames());
this.capturables = ScopeObject.capturables(frame, map.capturableNames); this.capturables = ScopeObject.capturables(frame, map.capturableNames());
this.captures = ScopeObject.captures(frame, map.captureNames); this.captures = ScopeObject.captures(frame, map.captureNames());
if (this.globals instanceof ObjectValue) { if (this.globals instanceof ObjectValue) {
this.variables = ScopeObject.combine((ObjectValue)this.globals, locals, capturables, captures); this.variables = ScopeObject.combine((ObjectValue)this.globals, locals, capturables, captures);
} }
@ -249,7 +249,7 @@ public class SimpleDebugger implements Debugger {
private ObjectValue emptyObject = new ObjectValue(); private ObjectValue emptyObject = new ObjectValue();
private WeakHashMap<DebugContext, DebugContext> contexts = new WeakHashMap<>(); private WeakHashMap<SimpleDebugHandler, SimpleDebugHandler> contexts = new WeakHashMap<>();
private WeakHashMap<FunctionBody, FunctionMap> mappings = new WeakHashMap<>(); private WeakHashMap<FunctionBody, FunctionMap> mappings = new WeakHashMap<>();
private HashMap<Location, HashSet<Breakpoint>> bpLocs = new HashMap<>(); private HashMap<Location, HashSet<Breakpoint>> bpLocs = new HashMap<>();
@ -617,22 +617,12 @@ public class SimpleDebugger implements Debugger {
} }
} }
// private Environment sanitizeEnvironment(Environment env) {
// var res = env.child();
// res.remove(EventLoop.KEY);
// res.remove(DebugContext.KEY);
// res.add(DebugContext.IGNORE);
// return res;
// }
private RunResult run(DebugFrame codeFrame, String code) { private RunResult run(DebugFrame codeFrame, String code) {
if (codeFrame == null) return new RunResult(null, null, EngineException.ofError("Invalid code frame!")); if (codeFrame == null) return new RunResult(null, null, EngineException.ofError("Invalid code frame!"));
var engine = new Engine(); var engine = new Engine();
var env = codeFrame.frame.env.child(); var env = codeFrame.frame.env.child();
env.remove(DebugContext.KEY); env.remove(DebugHandler.KEY);
env.remove(EventLoop.KEY); env.remove(EventLoop.KEY);
env.remove(Value.GLOBAL); env.remove(Value.GLOBAL);
env.add(Compiler.KEY, SimpleRepl.DEFAULT_COMPILER); env.add(Compiler.KEY, SimpleRepl.DEFAULT_COMPILER);
@ -1076,7 +1066,7 @@ public class SimpleDebugger implements Debugger {
} }
private boolean instructionLock; private boolean instructionLock;
@Override public boolean onInstruction(Environment env, Frame cf, Instruction instruction, Value returnVal, EngineException error, boolean caught) { @Override public boolean onInstruction(Environment env, Frame cf, Instruction instruction, Value returnVal, EngineException error, boolean caught) {
if (!enabled) return false; if (!enabled) return false;
if (instructionLock) return false; if (instructionLock) return false;
@ -1090,7 +1080,7 @@ public class SimpleDebugger implements Debugger {
frame = getFrame(cf); frame = getFrame(cf);
var map = DebugContext.get(env).getMap(frame.frame.function); var map = DebugHandler.get(env).getMap(env, frame.frame.function);
frame.updateLoc(map.toLocation(frame.frame.codePtr)); frame.updateLoc(map.toLocation(frame.frame.codePtr));
loc = frame.location; loc = frame.location;
@ -1197,7 +1187,11 @@ public class SimpleDebugger implements Debugger {
} }
} }
public SimpleDebugger attach(DebugContext ctx) { @Override public FunctionMap getMap(Environment env, FunctionBody func) {
return mappings.get(func);
}
public SimpleDebugger attach(SimpleDebugHandler ctx) {
ctx.attachDebugger(this); ctx.attachDebugger(this);
contexts.put(ctx, ctx); contexts.put(ctx, ctx);
return this; return this;

View File

@ -7,7 +7,7 @@ import java.util.concurrent.CancellationException;
import me.topchetoeu.j2s.common.Environment; import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.common.Instruction; import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.Key; import me.topchetoeu.j2s.common.Key;
import me.topchetoeu.j2s.runtime.debug.DebugContext; import me.topchetoeu.j2s.runtime.debug.DebugHandler;
import me.topchetoeu.j2s.runtime.exceptions.EngineException; import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.Value; import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction; import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
@ -17,6 +17,9 @@ import me.topchetoeu.j2s.runtime.values.primitives.numbers.IntValue;
public final class Frame { public final class Frame {
public static final Key<Stack<Frame>> KEY = new Key<>(); public static final Key<Stack<Frame>> KEY = new Key<>();
public static final Key<Integer> MAX_STACK_COUNT = new Key<>();
public static final Key<Boolean> HIDE_STACK = new Key<>();
public static final EngineException STACK_OVERFLOW; public static final EngineException STACK_OVERFLOW;
static { static {
STACK_OVERFLOW = EngineException.ofRange("Stack overflow!"); STACK_OVERFLOW = EngineException.ofRange("Stack overflow!");
@ -120,7 +123,7 @@ public final class Frame {
public final Stack<TryCtx> tryStack = new Stack<>(); public final Stack<TryCtx> tryStack = new Stack<>();
public final CodeFunction function; public final CodeFunction function;
public final Environment env; public final Environment env;
private final DebugContext dbg; private final DebugHandler dbg;
public Value getVar(int i) { public Value getVar(int i) {
if (i < 0) return captures[~i][0]; if (i < 0) return captures[~i][0];
@ -206,7 +209,7 @@ public final class Frame {
returnValue = InstructionRunner.exec(env, instr, this); returnValue = InstructionRunner.exec(env, instr, this);
} }
catch (EngineException e) { catch (EngineException e) {
error = e.add(env, function.name, dbg.getMapOrEmpty(function).toLocation(codePtr, true)); error = e.add(env, function.name, dbg.getMapOrEmpty(env, function).toLocation(codePtr));
} }
} }
} }
@ -214,7 +217,7 @@ public final class Frame {
catch (EngineException e) { error = e; } catch (EngineException e) { error = e; }
catch (RuntimeException e) { catch (RuntimeException e) {
if (!(e instanceof CancellationException)) { if (!(e instanceof CancellationException)) {
System.out.println(dbg.getMapOrEmpty(function).toLocation(codePtr, true)); System.out.println(dbg.getMapOrEmpty(env, function).toLocation(codePtr));
} }
throw e; throw e;
} }
@ -352,10 +355,10 @@ public final class Frame {
public void onPush() { public void onPush() {
get(env).push(this); get(env).push(this);
DebugContext.get(env).onFramePush(env, this); DebugHandler.get(env).onFramePush(env, this);
} }
public void onPop() { public void onPop() {
DebugContext.get(env).onFramePop(env, this); DebugHandler.get(env).onFramePop(env, this);
get(env).pop(); get(env).pop();
} }
@ -376,7 +379,7 @@ public final class Frame {
public Frame(Environment env, boolean isNew, Value target, Value self, Value[] args, CodeFunction func) { public Frame(Environment env, boolean isNew, Value target, Value self, Value[] args, CodeFunction func) {
this.env = env; this.env = env;
this.dbg = DebugContext.get(env); this.dbg = DebugHandler.get(env);
this.function = func; this.function = func;
this.isNew = isNew; this.isNew = isNew;
this.target = target; this.target = target;

View File

@ -14,6 +14,7 @@ import me.topchetoeu.j2s.runtime.values.primitives.numbers.NumberValue;
public class InstructionRunner { public class InstructionRunner {
private static Value execReturn(Environment env, Instruction instr, Frame frame) { private static Value execReturn(Environment env, Instruction instr, Frame frame) {
frame.codePtr++;
return frame.pop(); return frame.pop();
} }
private static Value execThrow(Environment env, Instruction instr, Frame frame) { private static Value execThrow(Environment env, Instruction instr, Frame frame) {

View File

@ -2,14 +2,31 @@ package me.topchetoeu.j2s.runtime.debug;
import me.topchetoeu.j2s.common.Environment; import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.common.Filename; import me.topchetoeu.j2s.common.Filename;
import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.Key;
import me.topchetoeu.j2s.common.FunctionBody; import me.topchetoeu.j2s.common.FunctionBody;
import me.topchetoeu.j2s.common.FunctionMap; import me.topchetoeu.j2s.common.FunctionMap;
import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.runtime.Frame; import me.topchetoeu.j2s.runtime.Frame;
import me.topchetoeu.j2s.runtime.exceptions.EngineException; import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.Value; import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.functions.CodeFunction;
import me.topchetoeu.j2s.runtime.values.functions.FunctionValue;
public interface DebugHandler { public interface DebugHandler {
public static final Key<DebugHandler> KEY = new Key<>();
public static final Key<Void> IGNORE = new Key<>();
public static DebugHandler EMPTY = new DebugHandler() {
@Override public void onSourceLoad(Filename filename, String source) { }
@Override public void onFunctionLoad(FunctionBody body, FunctionMap map) { }
@Override public boolean onInstruction(
Environment env, Frame frame, Instruction instruction, Value returnVal, EngineException error, boolean caught
) { return false; }
@Override public void onFramePush(Environment env, Frame frame) { }
@Override public void onFramePop(Environment env, Frame frame) { }
@Override public FunctionMap getMap(Environment env, FunctionBody body) { return null; }
};
/** /**
* Called when a script has been loaded * Called when a script has been loaded
* @param filename The name of the source * @param filename The name of the source
@ -17,17 +34,17 @@ public interface DebugHandler {
* @param breakpoints A set of all the breakpointable locations in this source * @param breakpoints A set of all the breakpointable locations in this source
* @param map The source map associated with this file. null if this source map isn't mapped * @param map The source map associated with this file. null if this source map isn't mapped
*/ */
void onSourceLoad(Filename filename, String source); public void onSourceLoad(Filename filename, String source);
/** /**
* Called when a function body has been loaded * Called when a function body has been loaded
* @param body The body loaded * @param body The body loaded
* @param map The map of the function * @param map The map of the function
*/ */
void onFunctionLoad(FunctionBody body, FunctionMap map); public void onFunctionLoad(FunctionBody body, FunctionMap map);
/** /**
* Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned. * Called immediately before an instruction is executed, as well as after an instruction, if it has threw or returned.
* This function might pause in order to await debugging commands. * This function might pause in order to await debugging commands.
* @param env The context of execution * @param env The context of execution
* @param frame The frame in which execution is occuring * @param frame The frame in which execution is occuring
@ -37,7 +54,19 @@ public interface DebugHandler {
* @param caught Whether or not the error has been caught * @param caught Whether or not the error has been caught
* @return Whether or not the frame should restart (currently does nothing) * @return Whether or not the frame should restart (currently does nothing)
*/ */
boolean onInstruction(Environment env, Frame frame, Instruction instruction, Value returnVal, EngineException error, boolean caught); public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Value returnVal, EngineException error, boolean caught);
/**
* Called immediately before an instruction is executed, as well as after an instruction, if it has threw or returned.
* This function might pause in order to await debugging commands.
* @param env The context of execution
* @param frame The frame in which execution is occuring
* @param instruction The instruction which was or will be executed
* @return Whether or not the frame should restart (currently does nothing)
*/
public default boolean onInstruction(Environment env, Frame frame, Instruction instruction) {
return onInstruction(env, frame, instruction, null, null, false);
}
/** /**
* Called immediatly before a frame has been pushed on the frame stack. * Called immediatly before a frame has been pushed on the frame stack.
@ -45,12 +74,36 @@ public interface DebugHandler {
* @param env The context of execution * @param env The context of execution
* @param frame The code frame which was pushed * @param frame The code frame which was pushed
*/ */
void onFramePush(Environment env, Frame frame); public void onFramePush(Environment env, Frame frame);
/** /**
* Called immediatly after a frame has been popped out of the frame stack. * Called immediatly after a frame has been popped out of the frame stack.
* This function might pause in order to await debugging commands. * This function might pause in order to await debugging commands.
* @param env The context of execution * @param env The context of execution
* @param frame The code frame which was popped out * @param frame The code frame which was popped out
*/ */
void onFramePop(Environment env, Frame frame); public void onFramePop(Environment env, Frame frame);
public FunctionMap getMap(Environment env, FunctionBody func);
public default FunctionMap getMap(Environment env, FunctionValue func) {
if (func instanceof CodeFunction codeFunc) return getMap(env, codeFunc.body);
else return null;
}
public default FunctionMap getMapOrEmpty(Environment env, FunctionBody func) {
var res = getMap(env, func);
if (res == null) return FunctionMap.EMPTY;
else return res;
}
public default FunctionMap getMapOrEmpty(Environment env, FunctionValue func) {
if (func instanceof CodeFunction codeFunc) return getMapOrEmpty(env, codeFunc.body);
else return null;
}
public static DebugHandler get(Environment exts) {
if (enabled(exts)) return exts.get(KEY);
else return EMPTY;
}
public static boolean enabled(Environment exts) {
return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE);
}
} }

View File

@ -5,6 +5,7 @@ import java.util.List;
import me.topchetoeu.j2s.common.Environment; import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.common.Location; import me.topchetoeu.j2s.common.Location;
import me.topchetoeu.j2s.runtime.Frame;
import me.topchetoeu.j2s.runtime.values.Value; import me.topchetoeu.j2s.runtime.values.Value;
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue; import me.topchetoeu.j2s.runtime.values.objects.ObjectValue;
import me.topchetoeu.j2s.runtime.values.objects.ObjectValue.PrototypeProvider; import me.topchetoeu.j2s.runtime.values.objects.ObjectValue.PrototypeProvider;
@ -18,7 +19,7 @@ public class EngineException extends RuntimeException {
public final Environment ext; public final Environment ext;
public boolean visible() { public boolean visible() {
return ext == null || !ext.get(Value.HIDE_STACK, false); return ext == null || !ext.get(Frame.HIDE_STACK, false);
} }
public String toString() { public String toString() {
if (name == null && location == null) return "(skipped)"; if (name == null && location == null) return "(skipped)";

View File

@ -48,9 +48,6 @@ public abstract class Value {
} }
} }
public static final Key<Integer> MAX_STACK_COUNT = new Key<>();
public static final Key<Boolean> HIDE_STACK = new Key<>();
public static final Key<ObjectValue> BOOL_PROTO = new Key<>(); public static final Key<ObjectValue> BOOL_PROTO = new Key<>();
public static final Key<ObjectValue> NUMBER_PROTO = new Key<>(); public static final Key<ObjectValue> NUMBER_PROTO = new Key<>();
public static final Key<ObjectValue> STRING_PROTO = new Key<>(); public static final Key<ObjectValue> STRING_PROTO = new Key<>();

View File

@ -25,12 +25,12 @@ public final class CodeFunction extends FunctionValue {
} }
} }
@Override protected Value onApply(Environment ext, Value self, Value... args) { @Override protected Value onApply(Environment env, Value self, Value... args) {
var frame = new Frame(env, false, null, self, args, this); var frame = new Frame(env, false, null, self, args, this);
var res = onCall(frame); var res = onCall(frame);
return res; return res;
} }
@Override protected Value onConstruct(Environment ext, Value target, Value... args) { @Override protected Value onConstruct(Environment env, Value target, Value... args) {
var self = new ObjectValue(); var self = new ObjectValue();
var proto = target.getMember(env, "prototype"); var proto = target.getMember(env, "prototype");

View File

@ -6,7 +6,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import me.topchetoeu.j2s.common.Environment; import me.topchetoeu.j2s.common.Environment;
import me.topchetoeu.j2s.runtime.debug.DebugContext; import me.topchetoeu.j2s.runtime.debug.DebugHandler;
import me.topchetoeu.j2s.runtime.exceptions.EngineException; import me.topchetoeu.j2s.runtime.exceptions.EngineException;
import me.topchetoeu.j2s.runtime.values.KeyCache; import me.topchetoeu.j2s.runtime.values.KeyCache;
import me.topchetoeu.j2s.runtime.values.Member; import me.topchetoeu.j2s.runtime.values.Member;
@ -91,9 +91,9 @@ public abstract class FunctionValue extends ObjectValue {
@Override public StringValue type() { return StringValue.of("function"); } @Override public StringValue type() { return StringValue.of("function"); }
@Override public List<String> toReadableLines(Environment env, HashSet<ObjectValue> passed) { @Override public List<String> toReadableLines(Environment env, HashSet<ObjectValue> passed) {
var dbg = DebugContext.get(env); var dbg = DebugHandler.get(env);
var res = new StringBuilder(this.toString()); var res = new StringBuilder(this.toString());
var loc = dbg.getMapOrEmpty(this).start(); var loc = dbg.getMapOrEmpty(env, this).first();
if (loc != null) res.append(" @ " + loc); if (loc != null) res.append(" @ " + loc);

View File

@ -44,6 +44,7 @@ public class ObjectValue extends Value {
private HashMap<SymbolValue, FieldMember> symbolFields = new HashMap<>(); private HashMap<SymbolValue, FieldMember> symbolFields = new HashMap<>();
private HashMap<String, PropertyMember> properties = new HashMap<>(); private HashMap<String, PropertyMember> properties = new HashMap<>();
private HashMap<SymbolValue, PropertyMember> symbolProperties = new HashMap<>(); private HashMap<SymbolValue, PropertyMember> symbolProperties = new HashMap<>();
private State state = State.NORMAL;
private LinkedHashMap<String, Boolean> keys = new LinkedHashMap<>(); private LinkedHashMap<String, Boolean> keys = new LinkedHashMap<>();
private LinkedHashMap<SymbolValue, Boolean> symbols = new LinkedHashMap<>(); private LinkedHashMap<SymbolValue, Boolean> symbols = new LinkedHashMap<>();
@ -72,8 +73,6 @@ public class ObjectValue extends Value {
@Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); } @Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); }
@Override public StringValue type() { return StringValue.of("object"); } @Override public StringValue type() { return StringValue.of("object"); }
private State state = State.NORMAL;
@Override public State getState() { return state; } @Override public State getState() { return state; }
public final void preventExtensions() { public final void preventExtensions() {