diff --git a/examples/parsing/output.hank b/examples/parsing/output.hank index d7e4be4..211dabf 100644 --- a/examples/parsing/output.hank +++ b/examples/parsing/output.hank @@ -4,9 +4,10 @@ Multiline comments /*will not split*/ an output expression. This should parse as one line of output. Comments at the end of lines won't parse as part of the Output. // I'm my own expression! You can {insert} the values of expressions. -{you} can start an output line with an insert expression. +{you} can start an output line with an insert expression. {and_end_one} {shuffle: Things get weird|when you start to use sequence expressions.} -{once: And they don't get any easier|{when you nest them|{insert}}}! +// If you don't believe me, just look at ParserTest.hx!! +{once: And they don't get any {easier}|{when you nest them|{insert}}}! You can { if (flag) "insert" else "interpolate" diff --git a/hank/Alt.hx b/hank/Alt.hx index 91f47d0..619ca62 100644 --- a/hank/Alt.hx +++ b/hank/Alt.hx @@ -1,5 +1,8 @@ package hank; +import haxe.ds.Option; +using Extensions.OptionExtender; + enum AltBehavior { Sequence; OnceOnly; @@ -7,9 +10,42 @@ enum AltBehavior { Shuffle; } -typedef Alt = { +@:allow(hank.AltInstance) +class Alt { var behavior: AltBehavior; var outputs: Array; + + static var behaviorMap = [ + '>' => Sequence, + '!' => OnceOnly, + '&' => Cycle, + '~' => Shuffle, + 'seq:' => Sequence, + 'once:' => OnceOnly, + 'cycle:' => Cycle, + 'shuffle:' => Shuffle + ]; + + public function new(behavior: AltBehavior, outputs: Array) { + this.behavior = behavior; + this.outputs = outputs; + } + + public static function parse(buffer: HankBuffer): Option { + var rawExpr = buffer.findNestedExpression('{', '}').unwrap().checkValue(); + var expr = rawExpr.substr(1, rawExpr.length-2); + + for (prefix in behaviorMap.keys()) { + if (StringTools.startsWith(expr, prefix)) { + var _outputs = StringTools.trim(expr.substr(prefix.length)); + + buffer.take(rawExpr.length); + return Some(new Alt(behaviorMap[prefix], [])); + } + } + + return None; + } } class AltInstance { @@ -18,10 +54,7 @@ class AltInstance { var random: Random; public function new(behavior: AltBehavior, outputs: Array, random: Random) { - this.alt = { - behavior: behavior, - outputs: outputs - }; + this.alt = new Alt(behavior, outputs); this.random = random; } diff --git a/hank/HankBuffer.hx b/hank/HankBuffer.hx index b976cf6..b327e27 100644 --- a/hank/HankBuffer.hx +++ b/hank/HankBuffer.hx @@ -38,7 +38,7 @@ class BufferSlice { this.buffer = buffer; } - public function checkValue() { + public function checkValue(): String { if (!buffer.position().equals(anchorPosition)) { throw 'Tried to access an expired BufferSlice.'; } @@ -91,7 +91,7 @@ class HankBuffer { return s; } - public function indexOf(s: String) { + public function indexOf(s: String): Int { return cleanBuffer.indexOf(s); } @@ -104,7 +104,7 @@ class HankBuffer { } /** Peek at contents buffer waiting further ahead in the buffer **/ - public function peekAhead(start: Int, length: Int) { + public function peekAhead(start: Int, length: Int): String { return cleanBuffer.substr(start, length); } diff --git a/hank/Output.hx b/hank/Output.hx index de4a114..edc344a 100644 --- a/hank/Output.hx +++ b/hank/Output.hx @@ -27,18 +27,10 @@ class Output { while (!buffer.isEmpty()) { var endSegment = buffer.length(); - var findHaxeExpression = buffer.findNestedExpression('{', '}'); - var findAltExpression = buffer.findNestedExpression('{{', '}}', 0, false); // Single brace expressions trip up the double brace search, so don't throw exceptions - switch (findHaxeExpression) { + var findBraceExpression = buffer.findNestedExpression('{', '}'); + switch (findBraceExpression) { case Some(slice): - if (slice.start < endSegment) - endSegment = slice.start; - default: - } - switch (findAltExpression) { - case Some(slice): - if (slice.start < endSegment) - endSegment = slice.start; + endSegment = slice.start; default: } if (endSegment == buffer.length() || endSegment != 0) { @@ -47,7 +39,9 @@ class Output { if (peekLine.length < endSegment) { var text = buffer.takeLine().unwrap(); trace(text); - parts.push(Text(text)); + if (text.length > 0) { + parts.push(Text(text)); + } break; } else { var text = buffer.take(endSegment); @@ -55,11 +49,7 @@ class Output { parts.push(Text(text)); } } else { - if (buffer.indexOf('{{') == 0) { - parts.push(parseAltExpression(buffer)); - } else { - parts.push(parseHaxeExpression(buffer)); - } + parts.push(parseBraceExpression(buffer)); } } @@ -78,7 +68,16 @@ class Output { return new Output(parts); } - public static function parseHaxeExpression(buffer: HankBuffer) { + public static function parseBraceExpression(buffer: HankBuffer): OutputType { + switch (Alt.parse(buffer)) { + case Some(altExpression): + return AltExpression(altExpression); + default: + return parseHaxeExpression(buffer); + } + } + + public static function parseHaxeExpression(buffer: HankBuffer): OutputType { var rawExpression = buffer.findNestedExpression('{', '}').unwrap().checkValue(); // Strip out the enclosing braces var hExpression = rawExpression.substr(1, rawExpression.length - 2); @@ -88,8 +87,4 @@ class Output { buffer.take(rawExpression.length); return HExpression(hExpression); } - - public static function parseAltExpression(buffer: HankBuffer) { - return AltExpression({behavior: Cycle, outputs:[]}); - } } \ No newline at end of file diff --git a/tests/ParserTest.hx b/tests/ParserTest.hx index 2099092..278c410 100644 --- a/tests/ParserTest.hx +++ b/tests/ParserTest.hx @@ -4,6 +4,8 @@ import hank.Parser; import hank.Parser.HankAST; import hank.Output; import hank.Output.OutputType; +import hank.Alt; +import hank.Alt.AltBehavior; class ParserTest extends utest.Test { var ast: HankAST; @@ -25,6 +27,21 @@ class ParserTest extends utest.Test { assertNextExpr(EOutput(new Output([Text("A line won't be interrupted or anything.")]))); assertNextExpr(EOutput(new Output([Text("Multiline comments an output expression. This should parse as one line of output.")]))); assertNextExpr(EOutput(new Output([Text("Comments at the end of lines won't parse as part of the Output.")]))); + assertNextExpr(EOutput(new Output([Text("You can "), HExpression("insert"), Text(" the values of expressions.")]))); + assertNextExpr(EOutput(new Output([HExpression("you"), Text(" can start an output line with an insert expression. "), HExpression("and_end_one")]))); + + assertNextExpr( + EOutput(new Output([ + AltExpression( + new Alt( + Shuffle, + [ + new Output([Text("Things get weird"), Text("when you start to use sequence expressions.")]) + ] + ) + ) + ])) + ); }