Fixed hexpression example
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
Have you tried inserting {test} in your Hank stories?
|
||||
~ var good = true;
|
||||
Rumor has it, it can be {if (good) {
|
||||
'rewarding'
|
||||
'rewarding';
|
||||
} else {
|
||||
'obnoxious'
|
||||
'obnoxious';
|
||||
}} to write a story with {test}.
|
||||
Null values will simply not appear.{if (!good) 'Invisible.'}
|
||||
@@ -1,2 +1,3 @@
|
||||
Have you tried inserting dynamic content in your Hank stories?
|
||||
Rumor has it, it can be rewarding to write a story with dynamic content.
|
||||
Null values will simply not appear.
|
||||
@@ -13,38 +13,73 @@ class HInterface {
|
||||
|
||||
var parser: Parser = new Parser();
|
||||
var interp: Interp = new Interp();
|
||||
var viewCounts: ViewCounts;
|
||||
|
||||
public function new(?variables: Map<String, Dynamic>) {
|
||||
if (variables != null) {
|
||||
interp.variables = variables;
|
||||
public function new(viewCounts: ViewCounts) {
|
||||
this.viewCounts = viewCounts;
|
||||
|
||||
this.interp.variables['_isTruthy'] = isTruthy;
|
||||
}
|
||||
|
||||
static function isTruthy(v: Dynamic) {
|
||||
switch (Type.typeof(v)) {
|
||||
case TBool:
|
||||
return v;
|
||||
case TInt | TFloat:
|
||||
return v > 0;
|
||||
default:
|
||||
throw '$v cannot be coerced to a boolean';
|
||||
}
|
||||
}
|
||||
|
||||
public function getVariable(v: String) {
|
||||
return interp.variables[v];
|
||||
public function addVariable(identifier: String, value: Dynamic) {
|
||||
this.interp.variables[identifier] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
Run a pre-processed block of Haxe embedded in a Hank story.
|
||||
**/
|
||||
public function runEmbeddedHaxe(haxe: String) {
|
||||
var expr = parser.parseString(haxe);
|
||||
public function runEmbeddedHaxe(h: String) {
|
||||
trace(h);
|
||||
var expr = parser.parseString(h);
|
||||
expr = transmute(expr);
|
||||
interp.execute(expr);
|
||||
}
|
||||
|
||||
public function evaluateExpr(h: String): String {
|
||||
var expr = parser.parseString(h);
|
||||
trace(expr);
|
||||
expr = transmute(expr);
|
||||
var val = interp.expr(expr);
|
||||
if (val == null) {
|
||||
return '';
|
||||
} else {
|
||||
return Std.string(val);
|
||||
}
|
||||
}
|
||||
|
||||
public function resolve(identifier: String, scope: String): Dynamic {
|
||||
if (interp.variables.exists(identifier)) {
|
||||
return interp.variables[identifier];
|
||||
} else {
|
||||
return viewCounts.resolve(identifier, scope);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Convert numerical value expressions to booleans for binary operations
|
||||
**/
|
||||
function boolify(expr: Expr): Expr {
|
||||
// TODO this won't work in cases where the expression is already a bool
|
||||
return EBinop('>', expr, EConst(CInt(0)));
|
||||
return ECall(EIdent('_isTruthy'), [expr]);
|
||||
}
|
||||
|
||||
/**
|
||||
Adapt an expression for the embedded context
|
||||
**/
|
||||
function transmute(expr: Expr) {
|
||||
if (expr == null) {
|
||||
return null;
|
||||
}
|
||||
return switch (expr) {
|
||||
case EIdent(name):
|
||||
// TODO if the name is a root-level view count, return EArray(view_counts, ...)
|
||||
|
||||
@@ -151,6 +151,7 @@ class Output {
|
||||
fullOutput += t;
|
||||
case AltExpression(a):
|
||||
case HExpression(h):
|
||||
fullOutput += hInterface.evaluateExpr(h);
|
||||
case InlineDivert(t):
|
||||
case ToggleOutput(o, b):
|
||||
if (b != displayToggles) {
|
||||
|
||||
@@ -30,14 +30,11 @@ class Story {
|
||||
|
||||
parser = new Parser();
|
||||
ast = parser.parseFile(script);
|
||||
// viewCounts = new ViewCounts(ast);
|
||||
|
||||
var variables = [
|
||||
'story' => this/*,
|
||||
'viewCounts' => viewCounts
|
||||
*/
|
||||
];
|
||||
hInterface = new HInterface(variables);
|
||||
var viewCounts = new ViewCounts(ast);
|
||||
|
||||
hInterface = new HInterface(viewCounts);
|
||||
hInterface.addVariable('story', this);
|
||||
|
||||
exprIndex = ast.findFile(script);
|
||||
}
|
||||
@@ -51,6 +48,11 @@ class Story {
|
||||
case EOutput(output):
|
||||
exprIndex += 1;
|
||||
return HasText(output.format(hInterface, false));
|
||||
case EHaxeLine(h):
|
||||
exprIndex += 1;
|
||||
|
||||
hInterface.runEmbeddedHaxe(h);
|
||||
return nextFrame();
|
||||
default:
|
||||
return Finished;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class StoryTestCase extends utest.Test {
|
||||
// Allow white-box story testing through variable checks prefixed with #
|
||||
if (StringTools.startsWith(line, "#")) {
|
||||
var parts = StringTools.trim(line.substr(1)).split(':');
|
||||
HankAssert.equals(StringTools.trim(parts[1]), Std.string(story.hInterface.getVariable(parts[0])));
|
||||
HankAssert.equals(StringTools.trim(parts[1]), Std.string(story.hInterface.resolve(parts[0], '')));
|
||||
}
|
||||
if (StringTools.startsWith(line, "*")) {
|
||||
// Collect the expected set of choices from the transcript.
|
||||
|
||||
11
hank/ViewCounts.hx
Normal file
11
hank/ViewCounts.hx
Normal file
@@ -0,0 +1,11 @@
|
||||
package hank;
|
||||
|
||||
class ViewCounts {
|
||||
public function new(ast: HankAST) {
|
||||
|
||||
}
|
||||
|
||||
public function resolve(identifier: String, scope: String): Int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,14 @@ import utest.Test;
|
||||
import utest.Assert;
|
||||
|
||||
import hank.HInterface;
|
||||
import hank.ViewCounts;
|
||||
|
||||
class HInterfaceTest extends utest.Test {
|
||||
|
||||
var hInterface: HInterface;
|
||||
|
||||
public function setup() {
|
||||
hInterface = new HInterface();
|
||||
hInterface = new HInterface(new ViewCounts([]));
|
||||
}
|
||||
|
||||
function assertVar(name: String, value: Dynamic) {
|
||||
@@ -20,6 +21,8 @@ class HInterfaceTest extends utest.Test {
|
||||
public function testVarDeclaration() {
|
||||
hInterface.runEmbeddedHaxe('var test = "str"');
|
||||
assertVar('test', 'str');
|
||||
hInterface.runEmbeddedHaxe('var test2 = 2');
|
||||
assertVar('test2', 2);
|
||||
}
|
||||
|
||||
public function testBoolification() {
|
||||
|
||||
Reference in New Issue
Block a user