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

164 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Ink.Parsed;
namespace Ink
{
public partial class InkParser
{
protected enum StatementLevel
{
InnerBlock,
Stitch,
Knot,
Top
}
protected List<Parsed.Object> StatementsAtLevel(StatementLevel level)
{
// Check for error: Should not be allowed gather dashes within an inner block
if (level == StatementLevel.InnerBlock) {
object badGatherDashCount = Parse(GatherDashes);
if (badGatherDashCount != null) {
Error ("You can't use a gather (the dashes) within the { curly braces } context. For multi-line sequences and conditions, you should only use one dash.");
}
}
return Interleave<Parsed.Object>(
Optional (MultilineWhitespace),
() => StatementAtLevel (level),
untilTerminator: () => StatementsBreakForLevel(level));
}
protected object StatementAtLevel(StatementLevel level)
{
ParseRule[] rulesAtLevel = _statementRulesAtLevel[(int)level];
var statement = OneOf (rulesAtLevel);
// For some statements, allow them to parse, but create errors, since
// writers may think they can use the statement, so it's useful to have
// the error message.
if (level == StatementLevel.Top) {
if( statement is Return )
Error ("should not have return statement outside of a knot");
}
return statement;
}
protected object StatementsBreakForLevel(StatementLevel level)
{
Whitespace ();
ParseRule[] breakRules = _statementBreakRulesAtLevel[(int)level];
var breakRuleResult = OneOf (breakRules);
if (breakRuleResult == null)
return null;
return breakRuleResult;
}
void GenerateStatementLevelRules()
{
var levels = Enum.GetValues (typeof(StatementLevel)).Cast<StatementLevel> ().ToList();
_statementRulesAtLevel = new ParseRule[levels.Count][];
_statementBreakRulesAtLevel = new ParseRule[levels.Count][];
foreach (var level in levels) {
List<ParseRule> rulesAtLevel = new List<ParseRule> ();
List<ParseRule> breakingRules = new List<ParseRule> ();
// Diverts can go anywhere
rulesAtLevel.Add(Line(MultiDivert));
// Knots can only be parsed at Top/Global scope
if (level >= StatementLevel.Top)
rulesAtLevel.Add (KnotDefinition);
rulesAtLevel.Add(Line(Choice));
rulesAtLevel.Add(Line(AuthorWarning));
// Gather lines would be confused with multi-line block separators, like
// within a multi-line if statement
if (level > StatementLevel.InnerBlock) {
rulesAtLevel.Add (Gather);
}
// Stitches (and gathers) can (currently) only go in Knots and top level
if (level >= StatementLevel.Knot) {
rulesAtLevel.Add (StitchDefinition);
}
// Global variable declarations can go anywhere
rulesAtLevel.Add(Line(ListDeclaration));
rulesAtLevel.Add(Line(VariableDeclaration));
rulesAtLevel.Add(Line(ConstDeclaration));
rulesAtLevel.Add(Line(ExternalDeclaration));
// Global include can go anywhere
rulesAtLevel.Add(Line(IncludeStatement));
// Normal logic / text can go anywhere
rulesAtLevel.Add(LogicLine);
rulesAtLevel.Add(LineOfMixedTextAndLogic);
// --------
// Breaking rules
// Break current knot with a new knot
if (level <= StatementLevel.Knot) {
breakingRules.Add (KnotDeclaration);
}
// Break current stitch with a new stitch
if (level <= StatementLevel.Stitch) {
breakingRules.Add (StitchDeclaration);
}
// Breaking an inner block (like a multi-line condition statement)
if (level <= StatementLevel.InnerBlock) {
breakingRules.Add (ParseDashNotArrow);
breakingRules.Add (String ("}"));
}
_statementRulesAtLevel [(int)level] = rulesAtLevel.ToArray ();
_statementBreakRulesAtLevel [(int)level] = breakingRules.ToArray ();
}
}
protected object SkipToNextLine()
{
ParseUntilCharactersFromString ("\n\r");
ParseNewline ();
return ParseSuccess;
}
// Modifier to turn a rule into one that expects a newline on the end.
// e.g. anywhere you can use "MixedTextAndLogic" as a rule, you can use
// "Line(MixedTextAndLogic)" to specify that it expects a newline afterwards.
protected ParseRule Line(ParseRule inlineRule)
{
return () => {
object result = ParseObject(inlineRule);
if (result == null) {
return null;
}
Expect(EndOfLine, "end of line", recoveryRule: SkipToNextLine);
return result;
};
}
ParseRule[][] _statementRulesAtLevel;
ParseRule[][] _statementBreakRulesAtLevel;
}
}