diff --git a/src/kiss/AsyncEmbeddedScript.hx b/src/kiss/AsyncEmbeddedScript.hx deleted file mode 100644 index 7ee5eeb..0000000 --- a/src/kiss/AsyncEmbeddedScript.hx +++ /dev/null @@ -1,408 +0,0 @@ -package kiss; - -#if macro -import haxe.macro.Expr; -import haxe.macro.Context; -import haxe.macro.PositionTools; -import sys.io.File; -import haxe.io.Path; -using haxe.io.Path; -import kiss.Helpers; -using kiss.Helpers; -using tink.MacroApi; - -#end - -import kiss.Kiss; -using kiss.Kiss; -import kiss.ReaderExp; -import kiss.Prelude; -import kiss.cloner.Cloner; -using StringTools; -import hscript.Parser; -import hscript.Interp; - -typedef Continuation = () -> Void; -typedef AsyncCommand = (AsyncEmbeddedScript, Continuation) -> Void; - -class ObjectInterp extends Interp { - var obj:T; - var fields:Map = []; - public function new(obj:T) { - this.obj = obj; - - for (field in Type.getInstanceFields(Type.getClass(obj))) { - fields[field] = true; - } - - super(); - } - - override function resolve(id:String):Dynamic { - var fieldVal = Reflect.field(obj, id); - if (fieldVal != null) - return fieldVal; - else - return super.resolve(id); - } - - // TODO every method of setting variables should try to set them on the object, - // but there are a lot of them and I might have missed some. - - override function setVar(name:String, v:Dynamic) { - if (Reflect.field(obj, name) != null) { - Reflect.setField(obj, name, v); - } else { - super.setVar(name, v); - } - } - - public override function expr( e : hscript.Expr ) : Dynamic { - var curExpr = e; - #if hscriptPos - var e = e.e; - #end - switch( e ) { - // Handle fuzzyMaps correctly: - case EArray(e, index): - var arr:Dynamic = expr(e); - var index:Dynamic = expr(index); - if (isMap(arr)) { - if (kiss.FuzzyMapTools.isFuzzy(arr)) - return getMapValue(arr, kiss.FuzzyMapTools.bestMatch(arr, index)); - return getMapValue(arr, index); - } - else { - return arr[index]; - } - case ECall(e,params): - switch( hscript.Tools.expr(e) ) { - case EIdent(name) if (fields.exists(name)): - var args = new Array(); - for( p in params ) - args.push(expr(p)); - return call(obj,expr(e),args); - default: - } - default: - } - return super.expr(curExpr); - } -} - -/** - Utility class for making statically typed, debuggable, ASYNC-BASED embedded Kiss-based DSLs. - Examples are in the hollywoo project. -**/ -class AsyncEmbeddedScript { - private var instructions:Array = null; - private var breakPoints:Map Bool> = []; - private var onBreak:AsyncCommand = null; - private var lastInstructionPointer = -1; - private var labels:Map = []; - private var noSkipInstructions:Map = []; - - private var parser = new Parser(); - private var interp:ObjectInterp; - public var interpVariables(get, null):Map; - private function get_interpVariables() { - return interp.variables; - } - - private var hscriptInstructions:Map = []; - private function hscriptInstructionFile() return ""; - - public function setBreakHandler(handler:AsyncCommand) { - onBreak = handler; - } - - public function addBreakPoint(instruction:Int, ?condition:() -> Bool) { - if (condition == null) { - condition = () -> true; - } - breakPoints[instruction] = condition; - } - - public function removeBreakPoint(instruction:Int) { - breakPoints.remove(instruction); - } - - public function new() { - interp = new ObjectInterp(this); - kiss.KissInterp.prepare(interp); - if (hscriptInstructionFile().length > 0) { - #if (sys || hxnodejs) - var cacheJson:haxe.DynamicAccess = haxe.Json.parse(sys.io.File.getContent(hscriptInstructionFile())); - for (key => value in cacheJson) { - hscriptInstructions[Std.parseInt(key)] = value; - } - #end - } - } - - private function resetInstructions() {} - - public function instructionCount() { - if (instructions == null) - resetInstructions(); - return instructions.length; - } - - #if test - public var ranHscriptInstruction = false; - #end - private function runHscriptInstruction(instructionPointer:Int, cc:Continuation) { - #if test - ranHscriptInstruction = true; - #end - interp.variables['cc'] = cc; - if (printCurrentInstruction) - Prelude.print(hscriptInstructions[instructionPointer]); - interp.execute(parser.parseString(hscriptInstructions[instructionPointer])); - } - - private function runInstruction(instructionPointer:Int, withBreakPoints = true) { - lastInstructionPointer = instructionPointer; - if (instructions == null) - resetInstructions(); - if (withBreakPoints && breakPoints.exists(instructionPointer) && breakPoints[instructionPointer]()) { - if (onBreak != null) { - onBreak(this, () -> runInstruction(instructionPointer, false)); - } - } - var continuation = if (instructionPointer < instructions.length - 1) { - () -> { - // runInstruction may be called externally to skip through the script. - // When this happens, make sure other scheduled continuations are canceled - // by verifying that lastInstructionPointer hasn't changed - if (lastInstructionPointer == instructionPointer) { - runInstruction(instructionPointer + 1); - } - }; - } else { - () -> {}; - } - if (hscriptInstructions.exists(instructionPointer)) { - runHscriptInstruction(instructionPointer, continuation); - } else { - instructions[instructionPointer](this, continuation); - } - } - - public function run(withBreakPoints = true) { - runInstruction(0, withBreakPoints); - } - - private function skipToInstruction(ip:Int) { - var lastCC = ()->runInstruction(ip); - // chain together the unskippable instructions prior to running the requested ip - var noSkipList = []; - for (cIdx in lastInstructionPointer+1... ip) { - if (noSkipInstructions.exists(cIdx)) { - noSkipList.push(cIdx); - } - } - if (noSkipList.length > 0) { - var cc = null; - cc = ()->{ - if (noSkipList.length == 0) { - lastCC(); - } else { - var inst = noSkipList.shift(); - lastInstructionPointer = inst; - instructions[inst](this, cc); - } - }; - cc(); - } else { - lastCC(); - } - - // TODO remember whether breakpoints were requested - } - - public function skipToNextLabel() { - var labelPointers = [for (ip in labels) ip]; - labelPointers.sort(Reflect.compare); - for (ip in labelPointers) { - if (ip > lastInstructionPointer) { - skipToInstruction(ip); - break; - } - } - } - - public function skipToLabel(name:String) { - var ip = labels[name]; - if (lastInstructionPointer > ip) { - throw "Rewinding AsyncEmbeddedScript is not implemented"; - } - skipToInstruction(ip); - } - - public function labelRunners():MapVoid> { - return [for (label => ip in labels) label => () -> skipToInstruction(ip)]; - } - - public var printCurrentInstruction = true; - - #if macro - public static function build(dslHaxelib:String, dslFile:String, scriptFile:String):Array { - // trace('AsyncEmbeddedScript.build $dslHaxelib $dslFile $scriptFile'); - var k = Kiss.defaultKissState(); - - k.file = scriptFile; - var classPath = Context.getPosInfos(Context.currentPos()).file; - var loadingDirectory = Path.directory(classPath); - var classFields = []; // Kiss.build() will already include Context.getBuildFields() - - var hscriptInstructions:Map = []; - var cache:Map = []; - #if kissCache - var cacheFile = scriptFile.withoutExtension().withoutDirectory() + ".cache.json"; - if (sys.FileSystem.exists(cacheFile)) { - var cacheJson:haxe.DynamicAccess = haxe.Json.parse(sys.io.File.getContent(cacheFile)); - for (key => value in cacheJson) - cache[key] = value; - } - #end - - var hscriptInstructionFile = scriptFile.withoutExtension().withoutDirectory() + ".hscript.json"; - - var commandList:Array = []; - var labelsList:Array = []; - var noSkipList:Array = []; - - var labelNum = 0; - k.macros["label"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { - k.stateChanged = true; - wholeExp.checkNumArgs(1, 1, '(label