mirror of
https://github.com/Ratstail91/Mementos.git
synced 2025-11-29 02:24:28 +11:00
164 lines
5.4 KiB
C#
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;
|
|
}
|
|
}
|
|
|