diff --git a/hank/HInterface.hx b/hank/HInterface.hx index 597efde..36d4d6b 100644 --- a/hank/HInterface.hx +++ b/hank/HInterface.hx @@ -13,6 +13,8 @@ using hank.Extensions; import hank.StoryTree; import hank.Story; +// TODO when hscriptPos is defined, much of this doesn't work + class HankInterp extends Interp { var hInterface:HInterface; var story:Story; @@ -30,10 +32,18 @@ class HankInterp extends Interp { } public override function expr(e:Expr):Dynamic { + var orig = e; + #if hscriptPos + curExpr = e; + var e = e.e; + #end switch (e) { // pointers are actually just string keys to the Interp's variables. case EUnop("&", true, e): + #if hscriptPos + var e = e.e; + #end switch (e) { case EIdent(id): return id; @@ -41,6 +51,9 @@ class HankInterp extends Interp { throw 'Addressing complex expressions is not implemented'; } case EUnop("*", true, e): + #if hscriptPos + var e = e.e; + #end switch (e) { case EIdent(id): return variables[variables[id]]; @@ -49,6 +62,9 @@ class HankInterp extends Interp { } // TODO Divert target variables are just StoryNode values case EUnop("->", true, e): + #if hscriptPos + var e = e.e; + #end // trace(e); var targetWithDots = ''; var trailingDot = false; @@ -65,21 +81,35 @@ class HankInterp extends Interp { targetWithDots = lastTarget + '.' + targetWithDots; trailingDot = true; + #if hscriptPos + e = eNested.e; + #else e = eNested; + #end default: throw 'Divert target variable cannot be specified in form $e'; } } default: - return super.expr(e); + return super.expr(orig); } } override function assign(e1:Expr, e2:Expr):Dynamic { var v = expr(e2); - switch (e1) { + #if hscriptPos + var e1change = e1.e; + #else + var e1change = e1; + #end + switch (e1change) { case EUnop("*", true, e): - switch (e) { + #if hscriptPos + var eChange = e.e; + #else + var eChange = e; + #end + switch (eChange) { case EIdent(id): variables[variables[id]] = v; default: @@ -238,107 +268,151 @@ class HInterface { }; } + function exp(e, eOrig):Expr { + #if hscriptPos + return {e: e, pmin: eOrig.pmin, pmax: eOrig.pmax, origin: eOrig.origin, line: eOrig.line}; + #else + return e; + #end + } + /** Convert numerical value expressions to booleans for binary operations **/ function boolify(expr:Expr):Expr { + var orig = expr; var newExpr = transmute(expr); // trace(newExpr); - return ECall(EIdent('_isTruthy'), [newExpr]); + return exp(ECall( + exp(EIdent('_isTruthy'), orig), + [ + newExpr + ]), orig); } function valify(expr:Expr):Expr { - return ECall(EIdent('_valueOf'), [transmute(expr)]); + var orig = expr; + return exp(ECall( + exp(EIdent('_valueOf'), orig), + [ + transmute(expr) + ]), orig); } /** Adapt an expression for the embedded context **/ - function transmute(expr:Expr) { + function transmute(expr:Expr):Expr { if (expr == null) { return null; } + #if hscriptPos + var orig = expr; + var expr = expr.e; + #else + var orig = null; + #end return switch (expr) { case EIdent(name): // Identifiers need to be resolved - ECall(EIdent('_resolve'), [EConst(CString(name))]); + exp(ECall( + exp(EIdent('_resolve'), orig), + [ + exp(EConst(CString(name)), orig) + ]), orig); case EVar(name, _, nested): // Declare all variables in embedded global context interp.variables[name] = null; - EBinop('=', EIdent(name), transmute(nested)); + exp(EBinop( + '=', + exp(EIdent(name), orig), + transmute(nested)), orig); case EParent(nested): - EParent(transmute(nested)); + exp(EParent(transmute(nested)), orig); case EBlock(nestedExpressions): - EBlock([for (nested in nestedExpressions) transmute(nested)]); + exp(EBlock([for (nested in nestedExpressions) transmute(nested)]), orig); case EField(nested, f): - ECall(EIdent('_resolveField'), [transmute(nested), EConst(CString(f))]); + exp(ECall( + exp(EIdent('_resolveField'), orig), + [ + transmute(nested), + exp(EConst(CString(f)), orig) + ]), orig); case EBinop(op, e1, e2): - if (BOOLEAN_OPS.indexOf(op) != -1) { - EBinop(op, boolify(e1), boolify(e2)); - } else if (op == '=') { - EBinop(op, e1, e2); - } else { - EBinop(op, valify(e1), valify(e2)); - } + exp( + if (BOOLEAN_OPS.indexOf(op) != -1) { + EBinop(op, boolify(e1), boolify(e2)); + } else if (op == '=') { + EBinop(op, e1, e2); + } else { + EBinop(op, valify(e1), valify(e2)); + }, orig); case EUnop(op, prefix, e): - if (BOOLEAN_OPS.indexOf(op) != -1) { - EUnop(op, prefix, boolify(e)); - } else { - expr; - } + exp( + if (BOOLEAN_OPS.indexOf(op) != -1) { + EUnop(op, prefix, boolify(e)); + } else { + expr; + }, orig); case ECall(e, params): + #if hscriptPos + var eOrig = e; + var e = e.e; + #else + var eOrig = e; + #end // Here we get funky to make sure method calls are preserved as such (bound to their object) by matching ECall(EField(e, f), []) switch (e) { case EField(innerE, f): var obj = interp.expr(innerE); if (obj != null) { - return expr; + return orig; } default: } // trace(ECall(transmute(e), [for (ex in params) transmute(ex)])); - ECall(transmute(e), [for (ex in params) transmute(ex)]); + exp(ECall(transmute(eOrig), [for (ex in params) transmute(ex)]), orig); case EIf(cond, e1, e2): // To provide for the {if(cond) 'something'} idiom, give every if statement an else clause returning an empty string. if (e2 == null) { - e2 = EConst(CString('')); + e2 = exp(EConst(CString('')), orig); } - EIf(boolify(cond), transmute(e1), transmute(e2)); + exp(EIf(boolify(cond), transmute(e1), transmute(e2)), orig); case EWhile(cond, e): - EWhile(boolify(cond), transmute(e)); + exp(EWhile(boolify(cond), transmute(e)), orig); case EFor(v, it, e): - EFor(v, transmute(it), transmute(e)); + exp(EFor(v, transmute(it), transmute(e)), orig); case EFunction(args, e, name, ret): - EFunction(args, transmute(e), name, ret); + exp(EFunction(args, transmute(e), name, ret), orig); case EReturn(e): - EReturn(transmute(e)); + exp(EReturn(transmute(e)), orig); case EArray(e, index): - EArray(transmute(e), transmute(index)); + exp(EArray(transmute(e), transmute(index)), orig); case EArrayDecl(e): - EArrayDecl([for (ex in e) transmute(ex)]); + exp(EArrayDecl([for (ex in e) transmute(ex)]), orig); case ENew(cl, params): - ENew(cl, [for (ex in params) transmute(ex)]); + exp(ENew(cl, [for (ex in params) transmute(ex)]), orig); case EThrow(e): - EThrow(transmute(e)); + exp(EThrow(transmute(e)), orig); case ETry(e, v, t, ecatch): - ETry(transmute(e), v, t, transmute(ecatch)); + exp(ETry(transmute(e), v, t, transmute(ecatch)), orig); case EObject(fl): - EObject([for (pair in fl) {name: pair.name, e: transmute(pair.e)}]); + exp(EObject([for (pair in fl) {name: pair.name, e: transmute(pair.e)}]), orig); case ETernary(cond, e1, e2): - ETernary(boolify(cond), transmute(e1), transmute(e2)); + exp(ETernary(boolify(cond), transmute(e1), transmute(e2)), orig); case ESwitch(e, cases, defaultExpr): - ESwitch(transmute(e), [ + exp(ESwitch(transmute(e), [ for (arm in cases) {values: [for (value in arm.values) transmute(value)], expr: transmute(arm.expr)} - ], transmute(defaultExpr)); + ], transmute(defaultExpr)), orig); case EDoWhile(cond, e): - EDoWhile(boolify(cond), transmute(e)); + exp(EDoWhile(boolify(cond), transmute(e)), orig); case EMeta(name, args, e): - EMeta(name, [for (arg in args) transmute(arg)], transmute(e)); + exp(EMeta(name, [for (arg in args) transmute(arg)], transmute(e)), orig); case ECheckType(e, t): - ECheckType(transmute(e), t); + exp(ECheckType(transmute(e), t), orig); default: - expr; + orig; } } }