move FunctionMap logic away from core
This commit is contained in:
parent
eff076f6fe
commit
208444381e
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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);
|
||||||
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)";
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user