make HInterface compatible with hscriptPos
Some checks failed
/ test (push) Failing after 47s

This commit is contained in:
2025-11-03 15:16:24 -06:00
parent 915f0ea58c
commit be61716535

View File

@@ -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):
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):
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;
}
}
}