This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user