Fixed method calls in embedded haxe

This commit is contained in:
2019-03-27 15:31:56 -06:00
parent c486fb321a
commit 2fffeab412
4 changed files with 104 additions and 23 deletions

View File

@@ -67,7 +67,7 @@ class HInterface {
return node.resolve(name);
}
else {
var val = container.field(name);
var val:Dynamic = container.field(name);
if (val != null) {
return Some(val);
} else {
@@ -141,6 +141,8 @@ class HInterface {
return ECall(EIdent('_valueOf'), [transmute(expr)]);
}
/**
Adapt an expression for the embedded context
**/
@@ -175,6 +177,16 @@ class HInterface {
expr;
}
case ECall(e, params):
// 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;
}
default:
}
trace(ECall(transmute(e), [for (ex in params) transmute(ex)]));
ECall(transmute(e), [for (ex in params) transmute(ex)]);
case EIf(cond, e1, e2):
// To provide for the {if(cond) 'something'} idiom, give every if statement an else clause returning an empty string.

View File

@@ -28,6 +28,30 @@ class Parser {
}
public function parseString(h: String): HankAST {
var stringBuffer = HankBuffer.Dummy(h);
var parsedAST = [];
do {
var position = stringBuffer.position();
stringBuffer.skipWhitespace();
var expr = parseExpr(stringBuffer, position);
switch(expr) {
case EIncludeFile(file):
throw 'cannot include files from within an embedded Hank block';
case ENoOp:
// Drop no-ops from the AST
default:
parsedAST.push({
position: position,
expr: expr
});
}
} while (!stringBuffer.isEmpty());
return parsedAST;
}
public function parseFile(f: String, includedFile = false) : HankAST {
var directory = '';
var lastSlashIdx = f.lastIndexOf('/');

View File

@@ -1,5 +1,8 @@
package hank;
import haxe.ds.Option;
using hank.Extensions;
using HankAST.ASTExtension;
import hank.HankAST.ExprType;
import hank.StoryTree;
@@ -30,28 +33,57 @@ class Story {
var parser: Parser;
var embedded: Option<Story> = None;
var parent: Option<Story> = None;
public function new(script: String, ?randomSeed: Int) {
random = new Random(randomSeed);
function new(r: Random, p: Parser, ast: HankAST, st: StoryNode, sc: Array<StoryNode>, vc: Map<StoryNode, Int>, hi: HInterface) {
this.random = r;
this.parser = p;
this.ast = ast;
this.storyTree = st;
this.nodeScopes = sc;
this.viewCounts = vc;
this.hInterface = hi;
}
parser = new Parser();
ast = parser.parseFile(script);
function embeddedStory(h: String): Story {
var ast = parser.parseString(h);
storyTree = StoryNode.FromAST(ast);
nodeScopes = [storyTree];
viewCounts = storyTree.createViewCounts();
var story = new Story(random, parser, ast, storyTree, nodeScopes, viewCounts, hInterface);
story.exprIndex = 0;
story.parent = Some(this);
return story;
}
hInterface = new HInterface(storyTree, viewCounts);
hInterface.addVariable('story', this);
public static function FromFile(script: String, ?randomSeed: Int): Story {
var random = new Random(randomSeed);
exprIndex = ast.findFile(script);
var parser = new Parser();
var ast = parser.parseFile(script);
var storyTree = StoryNode.FromAST(ast);
var nodeScopes = [storyTree];
var viewCounts = storyTree.createViewCounts();
var hInterface = new HInterface(storyTree, viewCounts);
var story = new Story(random, parser, ast, storyTree, nodeScopes, viewCounts, hInterface);
hInterface.addVariable('story', story);
story.exprIndex = ast.findFile(script);
return story;
}
public function nextFrame(): StoryFrame {
if (exprIndex >= ast.length) {
return Finished;
switch (embedded) {
case Some(s):
return s.nextFrame();
case None:
if (exprIndex >= ast.length) {
return Finished;
}
return processExpr(ast[exprIndex].expr);
}
return processExpr(ast[exprIndex].expr);
}
private function processExpr(expr: ExprType) {
@@ -100,17 +132,14 @@ class Story {
var scope = whichScope[i];
switch (scope.resolve(targetParts[0])) {
case Some(node):
trace('found outer part ${targetParts[0]}');
newScopes = whichScope.slice(i);
newScopes.insert(0, node);
trace(newScopes);
// Then resolve the rest of the parts inward from there
for (part in targetParts.slice(1)) {
trace('trying to find $part');
var scope = newScopes[0];
switch (scope.resolve(part)) {
case Some(innerNode):
trace('found $part');
newScopes.insert(0, innerNode);
case None:
break;
@@ -121,11 +150,17 @@ class Story {
case None:
}
}
trace('done seraching');
return newScopes;
}
public function divertTo(target: String) {
trace('diverting to $target');
switch (parent) {
case Some(p):
p.embedded = None; //
return p.divertTo(target); // A divert from inside embedded hank, ends the embedding
default:
}
var newScopes = resolveNodeInScope(target);
var targetIdx = newScopes[0].astIndex;
@@ -177,12 +212,18 @@ class Story {
}
public function choose(choiceIndex: Int): String {
// TODO if the choice has a label, increment its view count
return '';
switch (embedded) {
case Some(s):
return s.choose(choiceIndex);
case None:
// TODO if the choice has a label, increment its view count
return '';
}
}
/** Parse and run embedded Hank script on the fly. **/
public function runEmbeddedHank(hank: String) {
// TODO
public function runEmbeddedHank(h: String) {
trace(h);
embedded = Some(embeddedStory(h));
}
}

View File

@@ -13,7 +13,7 @@ class StoryTestCase extends utest.Test {
transcriptLines.remove(transcriptLines[0]);
}
var story: Story = new Story(storyFile, randomSeed);
var story: Story = Story.FromFile(storyFile, randomSeed);
var i = 0;
while (i < transcriptLines.length) {
@@ -57,6 +57,10 @@ class StoryTestCase extends utest.Test {
HankAssert.equals(HasText(line), frame);
}
if (frame == Finished) {
break;
}
i += 1;
}