Files
Mementos/Unity/Alternate Genre Jam/Assets/Ink/InkLibs/InkCompiler/InkParser/InkParser_Divert.cs
2021-06-30 21:39:19 +10:00

207 lines
6.5 KiB
C#

using System.Collections.Generic;
using Ink.Parsed;
namespace Ink
{
public partial class InkParser
{
protected List<Parsed.Object> MultiDivert()
{
Whitespace ();
List<Parsed.Object> diverts = null;
// Try single thread first
var threadDivert = Parse(StartThread);
if (threadDivert) {
diverts = new List<Object> ();
diverts.Add (threadDivert);
return diverts;
}
// Normal diverts and tunnels
var arrowsAndDiverts = Interleave<object> (
ParseDivertArrowOrTunnelOnwards,
DivertIdentifierWithArguments);
if (arrowsAndDiverts == null)
return null;
diverts = new List<Parsed.Object> ();
// Possible patterns:
// -> -- explicit gather
// ->-> -- tunnel onwards
// -> div -- normal divert
// ->-> div -- tunnel onwards, followed by override divert
// -> div -> -- normal tunnel
// -> div ->-> -- tunnel then tunnel continue
// -> div -> div -- tunnel then divert
// -> div -> div -> -- tunnel then tunnel
// -> div -> div ->->
// -> div -> div ->-> div (etc)
// Look at the arrows and diverts
for (int i = 0; i < arrowsAndDiverts.Count; ++i) {
bool isArrow = (i % 2) == 0;
// Arrow string
if (isArrow) {
// Tunnel onwards
if ((string)arrowsAndDiverts [i] == "->->") {
bool tunnelOnwardsPlacementValid = (i == 0 || i == arrowsAndDiverts.Count - 1 || i == arrowsAndDiverts.Count - 2);
if (!tunnelOnwardsPlacementValid)
Error ("Tunnel onwards '->->' must only come at the begining or the start of a divert");
var tunnelOnwards = new TunnelOnwards ();
if (i < arrowsAndDiverts.Count - 1) {
var tunnelOnwardDivert = arrowsAndDiverts [i+1] as Parsed.Divert;
tunnelOnwards.divertAfter = tunnelOnwardDivert;
}
diverts.Add (tunnelOnwards);
// Not allowed to do anything after a tunnel onwards.
// If we had anything left it would be caused in the above Error for
// the positioning of a ->->
break;
}
}
// Divert
else {
var divert = arrowsAndDiverts [i] as Divert;
// More to come? (further arrows) Must be tunnelling.
if (i < arrowsAndDiverts.Count - 1) {
divert.isTunnel = true;
}
diverts.Add (divert);
}
}
// Single -> (used for default choices)
if (diverts.Count == 0 && arrowsAndDiverts.Count == 1) {
var gatherDivert = new Divert ((Parsed.Object)null);
gatherDivert.isEmpty = true;
diverts.Add (gatherDivert);
if (!_parsingChoice)
Error ("Empty diverts (->) are only valid on choices");
}
return diverts;
}
protected Divert StartThread()
{
Whitespace ();
if (ParseThreadArrow() == null)
return null;
Whitespace ();
var divert = Expect(DivertIdentifierWithArguments, "target for new thread", () => new Divert(null)) as Divert;
divert.isThread = true;
return divert;
}
protected Divert DivertIdentifierWithArguments()
{
Whitespace ();
List<Identifier> targetComponents = Parse (DotSeparatedDivertPathComponents);
if (targetComponents == null)
return null;
Whitespace ();
var optionalArguments = Parse(ExpressionFunctionCallArguments);
Whitespace ();
var targetPath = new Path (targetComponents);
return new Divert (targetPath, optionalArguments);
}
protected Divert SingleDivert()
{
var diverts = Parse (MultiDivert);
if (diverts == null)
return null;
// Ideally we'd report errors if we get the
// wrong kind of divert, but unfortunately we
// have to hack around the fact that sequences use
// a very similar syntax.
// i.e. if you have a multi-divert at the start
// of a sequence, it initially tries to parse it
// as a divert target (part of an expression of
// a conditional) and gives errors. So instead
// we just have to blindly reject it as a single
// divert, and give a slightly less nice error
// when you DO use a multi divert as a divert taret.
if (diverts.Count != 1) {
return null;
}
var singleDivert = diverts [0];
if (singleDivert is TunnelOnwards) {
return null;
}
var divert = diverts [0] as Divert;
if (divert.isTunnel) {
return null;
}
return divert;
}
List<Identifier> DotSeparatedDivertPathComponents()
{
return Interleave<Identifier> (Spaced (IdentifierWithMetadata), Exclude (String (".")));
}
protected string ParseDivertArrowOrTunnelOnwards()
{
int numArrows = 0;
while (ParseString ("->") != null)
numArrows++;
if (numArrows == 0)
return null;
else if (numArrows == 1)
return "->";
else if (numArrows == 2)
return "->->";
else {
Error ("Unexpected number of arrows in divert. Should only have '->' or '->->'");
return "->->";
}
}
protected string ParseDivertArrow()
{
return ParseString ("->");
}
protected string ParseThreadArrow()
{
return ParseString ("<-");
}
}
}