refactor label handling into AsyncEmbeddedScript

This commit is contained in:
2021-12-21 20:43:10 -07:00
parent 322fc20743
commit 5d7620e409
3 changed files with 48 additions and 43 deletions

View File

@@ -6,7 +6,9 @@ import haxe.macro.Context;
import haxe.macro.PositionTools; import haxe.macro.PositionTools;
import sys.io.File; import sys.io.File;
import haxe.io.Path; import haxe.io.Path;
using kiss.Helpers;
#end #end
import kiss.Kiss; import kiss.Kiss;
import kiss.Prelude; import kiss.Prelude;
import kiss.cloner.Cloner; import kiss.cloner.Cloner;
@@ -20,10 +22,10 @@ typedef AsyncCommand = (AsyncEmbeddedScript, Continuation) -> Void;
**/ **/
class AsyncEmbeddedScript { class AsyncEmbeddedScript {
private var instructions:Array<AsyncCommand> = null; private var instructions:Array<AsyncCommand> = null;
public var instructionPointersByLine:Map<Int,Int> = [];
private var breakPoints:Map<Int, () -> Bool> = []; private var breakPoints:Map<Int, () -> Bool> = [];
private var onBreak:AsyncCommand = null; private var onBreak:AsyncCommand = null;
public var lastInstructionPointer = 0; private var lastInstructionPointer = -1;
private var labels:Map<String,Int> = [];
public function setBreakHandler(handler:AsyncCommand) { public function setBreakHandler(handler:AsyncCommand) {
onBreak = handler; onBreak = handler;
@@ -50,7 +52,7 @@ class AsyncEmbeddedScript {
return instructions.length; return instructions.length;
} }
public function runInstruction(instructionPointer:Int, withBreakPoints = true) { private function runInstruction(instructionPointer:Int, withBreakPoints = true) {
lastInstructionPointer = instructionPointer; lastInstructionPointer = instructionPointer;
if (instructions == null) if (instructions == null)
resetInstructions(); resetInstructions();
@@ -78,6 +80,26 @@ class AsyncEmbeddedScript {
runInstruction(0, withBreakPoints); runInstruction(0, withBreakPoints);
} }
private function skipToInstruction(ip:Int) {
for (cIdx in lastInstructionPointer+1... ip) {
// TODO add an optional cc argument to runInstruction
// TODO use that chain together the unskippable instructions prior to running the requested ip
}
// TODO remember whether breakpoints were requested
runInstruction(ip);
}
public function skipToNextLabel() {
var labelPointers = [for (ip in labels) ip];
labelPointers.sort(Reflect.compare);
for (ip in labelPointers) {
if (ip > lastInstructionPointer) {
skipToInstruction(ip);
break;
}
}
}
#if macro #if macro
public static function build(dslHaxelib:String, dslFile:String, scriptFile:String):Array<Field> { public static function build(dslHaxelib:String, dslFile:String, scriptFile:String):Array<Field> {
// trace('AsyncEmbeddedScript.build $dslHaxelib $dslFile $scriptFile'); // trace('AsyncEmbeddedScript.build $dslHaxelib $dslFile $scriptFile');
@@ -89,7 +111,15 @@ class AsyncEmbeddedScript {
var classFields = []; // Kiss.build() will already include Context.getBuildFields() var classFields = []; // Kiss.build() will already include Context.getBuildFields()
var commandList:Array<Expr> = []; var commandList:Array<Expr> = [];
var mappedIndexList:Array<Expr> = []; var labelsList:Array<Expr> = [];
k.macros["label"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(1, 1, '(label <label>)');
var label = Prelude.symbolNameValue(args[0]);
labelsList.push(macro labels[$v{label}] = $v{commandList.length});
wholeExp.expBuilder().callSymbol("cc", []);
};
if (dslHaxelib.length > 0) { if (dslHaxelib.length > 0) {
dslFile = Path.join([Prelude.libPath(dslHaxelib), dslFile]); dslFile = Path.join([Prelude.libPath(dslHaxelib), dslFile]);
@@ -109,10 +139,7 @@ class AsyncEmbeddedScript {
#if debug #if debug
expr = macro { trace($v{exprString}); $expr; }; expr = macro { trace($v{exprString}); $expr; };
#end #end
if (expr != null) { if (expr != null) {
mappedIndexList.push(macro instructionPointersByLine[$v{nextExp.pos.line}] = $v{commandList.length});
commandList.push(macro function(self, cc) { commandList.push(macro function(self, cc) {
$expr; $expr;
}); });
@@ -139,7 +166,7 @@ class AsyncEmbeddedScript {
args: [], args: [],
expr: macro { expr: macro {
this.instructions = [$a{commandList}]; this.instructions = [$a{commandList}];
$b{mappedIndexList}; $b{labelsList};
} }
}) })
}); });

View File

@@ -33,9 +33,4 @@
(method :Void update [:Float elapsed] (method :Void update [:Float elapsed]
(#when debug (#when debug
(when FlxG.keys.justPressed.N (when FlxG.keys.justPressed.N
(doFor [idx label] (enumerate labels) (skipToNextLabel))))
(when (> label lastInstructionPointer)
(doFor =>labelName labelIdx labelsByName
(when (= labelIdx label) (trace "SKIPPING TO $labelName")))
(runInstruction (dictGet instructionPointersByLine label))
(break))))))

View File

@@ -4,36 +4,19 @@
(collectBlocks preload (#when (StringTools.contains kissFile className) (cc))) (collectBlocks preload (#when (StringTools.contains kissFile className) (cc)))
(collectBlocks cleanup (#when (StringTools.contains kissFile className) (cc))) (collectBlocks cleanup (#when (StringTools.contains kissFile className) (cc)))
(prop :Map<String,Int> labelsByName (new Map))
(prop :Array<Int> labels [])
(defMacroVar _labelNames [])
(defMacroVar _labelLines [])
(defReaderMacro "LABEL " [stream]
(_labelNames.push (stream.expect "label name" ->(stream.takeLine)))
(_labelLines.push (- .line (stream.position) 1))
`(cc))
(defMacro end [] (defMacro end []
(let [labelSetters `{
(for [label idx] (zipThrow _labelNames _labelLines) (method doPreload [:Void->Void cc]
`{ (set isLoading true)
(dictSet labelsByName ,label ,idx) (collectedBlocks preload)
(labels.push ,idx) (set isLoading false)
})] (cc))
`{ (method doCleanup []
(method doPreload [:Void->Void cc] (director.cleanup)
(set isLoading true) (set lastInstructionPointer -2)
(collectedBlocks preload) (collectedBlocks cleanup))
(set isLoading false) (doCleanup)
,@labelSetters })
(cc))
(method doCleanup []
(director.cleanup)
(set lastInstructionPointer -2)
(collectedBlocks cleanup))
(doCleanup)
}))
(defReaderMacro &bof "" [stream] `(#when (StringTools.contains kissFile className) (doPreload cc))) (defReaderMacro &bof "" [stream] `(#when (StringTools.contains kissFile className) (doPreload cc)))
(defReaderMacro &eof "" [stream] `(#when (StringTools.contains kissFile className) (end))) (defReaderMacro &eof "" [stream] `(#when (StringTools.contains kissFile className) (end)))