Enhanced EmbeddedScript error messages
This commit is contained in:
@@ -18,14 +18,18 @@ typedef Command = () -> Void;
|
||||
projects/aoc/year2020/BootCode.hx
|
||||
**/
|
||||
class EmbeddedScript {
|
||||
var instructionPointer = 0;
|
||||
public var instructionPointer(default, null) = 0;
|
||||
|
||||
var running = false;
|
||||
|
||||
private var instructions:Array<Command> = null;
|
||||
private var breakPoints:Map<Int, () -> Bool> = [];
|
||||
private var onBreak:() -> Void = null;
|
||||
// Break handlers accept a Dynamic argument because when fork() happens
|
||||
// (1) the calling context can no longer assume the instance it constructed is the instance hitting the breakpoint.
|
||||
// (2) I don't know how to put a generic parameter <T extends EmbeddedScript> on a BreakHandler function type.
|
||||
private var onBreak:(Dynamic) -> Void = null;
|
||||
|
||||
public function setBreakHandler(handler:() -> Void) {
|
||||
public function setBreakHandler(handler:(Dynamic) -> Void) {
|
||||
onBreak = handler;
|
||||
}
|
||||
|
||||
@@ -87,6 +91,25 @@ class EmbeddedScript {
|
||||
})
|
||||
});
|
||||
|
||||
classFields.push({
|
||||
pos: PositionTools.make({
|
||||
min: 0,
|
||||
max: File.getContent(scriptFile).length,
|
||||
file: scriptFile
|
||||
}),
|
||||
name: "instructionCount",
|
||||
access: [APublic],
|
||||
kind: FFun({
|
||||
ret: null,
|
||||
args: [],
|
||||
expr: macro {
|
||||
if (instructions == null)
|
||||
resetInstructions();
|
||||
return instructions.length;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
classFields.push({
|
||||
pos: PositionTools.make({
|
||||
min: 0,
|
||||
@@ -106,9 +129,9 @@ class EmbeddedScript {
|
||||
if (breakPoints.exists(instructionPointer) && breakPoints[instructionPointer]()) {
|
||||
running = false;
|
||||
if (onBreak != null) {
|
||||
onBreak();
|
||||
onBreak(this);
|
||||
}
|
||||
} else if (instructionPointer >= instructions.length) {
|
||||
} else if (instructionPointer < 0 || instructionPointer >= instructions.length) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
@@ -187,32 +187,59 @@ class Helpers {
|
||||
}
|
||||
}
|
||||
|
||||
// This stack will contain multiple references to the same interp--to count how many layers deep it is.
|
||||
// This stack is like top in Inception. When empty, it proves that we're not running at compiletime yet.
|
||||
// When we ARE running at compiletime already, the pre-existing interp will be used
|
||||
static var interps:kiss.List<Interp> = [];
|
||||
|
||||
public static function runAtCompileTime(exp:ReaderExp, k:KissState, ?args:Map<String, Dynamic>):Dynamic {
|
||||
var code = k.convert(exp).toString(); // tink_macro to the rescue
|
||||
#if test
|
||||
Prelude.print("Compile-time hscript: " + code);
|
||||
#end
|
||||
var parser = new Parser();
|
||||
var interp = new Interp();
|
||||
interp.variables.set("read", Reader.assertRead.bind(_, k.readTable));
|
||||
interp.variables.set("readExpArray", Reader.readExpArray.bind(_, _, k.readTable));
|
||||
interp.variables.set("ReaderExp", ReaderExpDef);
|
||||
interp.variables.set("nextToken", Reader.nextToken.bind(_, "a token"));
|
||||
interp.variables.set("kiss", {
|
||||
Reader: {
|
||||
ReaderExpDef: ReaderExpDef
|
||||
}
|
||||
});
|
||||
interp.variables.set("k", k);
|
||||
interp.variables.set("args", args); // trippy
|
||||
interp.variables.set("Helpers", Helpers);
|
||||
interp.variables.set("Prelude", Prelude);
|
||||
if (interps.length == 0) {
|
||||
var interp = new Interp();
|
||||
interp.variables.set("read", Reader.assertRead.bind(_, k.readTable));
|
||||
interp.variables.set("readExpArray", Reader.readExpArray.bind(_, _, k.readTable));
|
||||
interp.variables.set("ReaderExp", ReaderExpDef);
|
||||
interp.variables.set("nextToken", Reader.nextToken.bind(_, "a token"));
|
||||
interp.variables.set("kiss", {
|
||||
Reader: {
|
||||
ReaderExpDef: ReaderExpDef
|
||||
},
|
||||
Operand: {
|
||||
fromDynamic: Operand.fromDynamic
|
||||
}
|
||||
});
|
||||
interp.variables.set("k", k.forCaseParsing());
|
||||
interp.variables.set("Helpers", Helpers);
|
||||
interp.variables.set("Prelude", Prelude);
|
||||
interp.variables.set("Std", Std);
|
||||
|
||||
interps.push(interp);
|
||||
} else {
|
||||
interps.push(interps[-1]);
|
||||
}
|
||||
var parsed = parser.parseString(code);
|
||||
|
||||
// TODO if an internal evaluation ever needs to end before its outer evaluation is done,
|
||||
// this will cause problems because the old args will be overwritten and lost
|
||||
interps[-1].variables.set("args", args); // trippy
|
||||
if (args != null) {
|
||||
for (arg => value in args) {
|
||||
interp.variables.set(arg, value);
|
||||
interps[-1].variables.set(arg, value);
|
||||
}
|
||||
}
|
||||
var value = interp.execute(parser.parseString(code));
|
||||
var value = if (interps.length == 1) {
|
||||
interps[-1].execute(parsed);
|
||||
} else {
|
||||
interps[-1].expr(parsed);
|
||||
};
|
||||
interps.pop();
|
||||
if (value == null) {
|
||||
throw CompileError.fromExp(exp, "compile-time evaluation returned null");
|
||||
}
|
||||
#if test
|
||||
Prelude.print("Compile-time value: " + Std.string(value));
|
||||
#end
|
||||
@@ -254,8 +281,10 @@ class Helpers {
|
||||
throw CompileError.fromExp(innerExp, "unquote evaluated to null");
|
||||
} else if (Std.isOfType(unquoteValue, ReaderExpDef)) {
|
||||
unquoteValue;
|
||||
} else {
|
||||
} else if (Reflect.getProperty(unquoteValue, "def") != null) {
|
||||
unquoteValue.def;
|
||||
} else {
|
||||
throw CompileError.fromExp(exp, "unquote didn't evaluate to a ReaderExp or ReaderExpDef");
|
||||
};
|
||||
default:
|
||||
throw CompileError.fromExp(exp, 'unquote evaluation not implemented');
|
||||
|
@@ -167,11 +167,10 @@ class Kiss {
|
||||
EField(convert(innerExp), field).withMacroPosOf(exp);
|
||||
case KeyValueExp(keyExp, valueExp):
|
||||
EBinop(OpArrow, convert(keyExp), convert(valueExp)).withMacroPosOf(exp);
|
||||
case Quasiquote(exp):
|
||||
// TODO pass args here (including the recursive args value)
|
||||
case Quasiquote(innerExp):
|
||||
// This statement actually turns into an HScript expression before running
|
||||
macro {
|
||||
Helpers.evalUnquotes($v{exp}, k, args).def;
|
||||
Helpers.evalUnquotes($v{innerExp}, k, args).def;
|
||||
};
|
||||
default:
|
||||
throw CompileError.fromExp(exp, 'conversion not implemented');
|
||||
|
@@ -14,7 +14,8 @@ typedef Position = {
|
||||
};
|
||||
|
||||
class Stream {
|
||||
var content:String;
|
||||
public var content(default, null):String;
|
||||
|
||||
var file:String;
|
||||
var line:Int;
|
||||
var column:Int;
|
||||
|
@@ -8,6 +8,9 @@ import kiss.Prelude;
|
||||
class DSLTestCase extends Test {
|
||||
function testScript() {
|
||||
new DSLScript().run();
|
||||
}
|
||||
|
||||
function testFork() {
|
||||
new DSLScript().fork([() -> Assert.equals(5, 5), () -> Assert.equals(7, 7)]);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user