mirror of
https://github.com/Ratstail91/Mementos.git
synced 2025-11-29 10:34:27 +11:00
Committed everything
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
using Ink.Parsed;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ink
|
||||
{
|
||||
public partial class InkParser
|
||||
{
|
||||
protected Choice Choice()
|
||||
{
|
||||
bool onceOnlyChoice = true;
|
||||
var bullets = Interleave <string>(OptionalExclude(Whitespace), String("*") );
|
||||
if (bullets == null) {
|
||||
|
||||
bullets = Interleave <string>(OptionalExclude(Whitespace), String("+") );
|
||||
if (bullets == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
onceOnlyChoice = false;
|
||||
}
|
||||
|
||||
// Optional name for the choice
|
||||
Identifier optionalName = Parse(BracketedName);
|
||||
|
||||
Whitespace ();
|
||||
|
||||
// Optional condition for whether the choice should be shown to the player
|
||||
Expression conditionExpr = Parse(ChoiceCondition);
|
||||
|
||||
Whitespace ();
|
||||
|
||||
// Ordinarily we avoid parser state variables like these, since
|
||||
// nesting would require us to store them in a stack. But since you should
|
||||
// never be able to nest choices within choice content, it's fine here.
|
||||
Debug.Assert(_parsingChoice == false, "Already parsing a choice - shouldn't have nested choices");
|
||||
_parsingChoice = true;
|
||||
|
||||
ContentList startContent = null;
|
||||
var startTextAndLogic = Parse (MixedTextAndLogic);
|
||||
if (startTextAndLogic != null)
|
||||
startContent = new ContentList (startTextAndLogic);
|
||||
|
||||
|
||||
ContentList optionOnlyContent = null;
|
||||
ContentList innerContent = null;
|
||||
|
||||
// Check for a the weave style format:
|
||||
// * "Hello[."]," he said.
|
||||
bool hasWeaveStyleInlineBrackets = ParseString("[") != null;
|
||||
if (hasWeaveStyleInlineBrackets) {
|
||||
|
||||
var optionOnlyTextAndLogic = Parse (MixedTextAndLogic);
|
||||
if (optionOnlyTextAndLogic != null)
|
||||
optionOnlyContent = new ContentList (optionOnlyTextAndLogic);
|
||||
|
||||
|
||||
Expect (String("]"), "closing ']' for weave-style option");
|
||||
|
||||
var innerTextAndLogic = Parse (MixedTextAndLogic);
|
||||
if( innerTextAndLogic != null )
|
||||
innerContent = new ContentList (innerTextAndLogic);
|
||||
}
|
||||
|
||||
Whitespace ();
|
||||
|
||||
// Finally, now we know we're at the end of the main choice body, parse
|
||||
// any diverts separately.
|
||||
var diverts = Parse(MultiDivert);
|
||||
|
||||
_parsingChoice = false;
|
||||
|
||||
Whitespace ();
|
||||
|
||||
// Completely empty choice without even an empty divert?
|
||||
bool emptyContent = !startContent && !innerContent && !optionOnlyContent;
|
||||
if (emptyContent && diverts == null)
|
||||
Warning ("Choice is completely empty. Interpretting as a default fallback choice. Add a divert arrow to remove this warning: * ->");
|
||||
|
||||
// * [] some text
|
||||
else if (!startContent && hasWeaveStyleInlineBrackets && !optionOnlyContent)
|
||||
Warning ("Blank choice - if you intended a default fallback choice, use the `* ->` syntax");
|
||||
|
||||
if (!innerContent) innerContent = new ContentList ();
|
||||
|
||||
var tags = Parse (Tags);
|
||||
if (tags != null) {
|
||||
innerContent.AddContent(tags);
|
||||
}
|
||||
|
||||
// Normal diverts on the end of a choice - simply add to the normal content
|
||||
if (diverts != null) {
|
||||
foreach (var divObj in diverts) {
|
||||
// may be TunnelOnwards
|
||||
var div = divObj as Divert;
|
||||
|
||||
// Empty divert serves no purpose other than to say
|
||||
// "this choice is intentionally left blank"
|
||||
// (as an invisible default choice)
|
||||
if (div && div.isEmpty) continue;
|
||||
|
||||
innerContent.AddContent (divObj);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate main content with a newline since this is the end of the line
|
||||
// Note that this will be redundant if the diverts above definitely take
|
||||
// the flow away permanently.
|
||||
innerContent.AddContent (new Text ("\n"));
|
||||
|
||||
var choice = new Choice (startContent, optionOnlyContent, innerContent);
|
||||
choice.identifier = optionalName;
|
||||
choice.indentationDepth = bullets.Count;
|
||||
choice.hasWeaveStyleInlineBrackets = hasWeaveStyleInlineBrackets;
|
||||
choice.condition = conditionExpr;
|
||||
choice.onceOnly = onceOnlyChoice;
|
||||
choice.isInvisibleDefault = emptyContent;
|
||||
|
||||
return choice;
|
||||
|
||||
}
|
||||
|
||||
protected Expression ChoiceCondition()
|
||||
{
|
||||
var conditions = Interleave<Expression> (ChoiceSingleCondition, ChoiceConditionsSpace);
|
||||
if (conditions == null)
|
||||
return null;
|
||||
else if (conditions.Count == 1)
|
||||
return conditions [0];
|
||||
else {
|
||||
return new MultipleConditionExpression (conditions);
|
||||
}
|
||||
}
|
||||
|
||||
protected object ChoiceConditionsSpace()
|
||||
{
|
||||
// Both optional
|
||||
// Newline includes initial end of line whitespace
|
||||
Newline ();
|
||||
Whitespace ();
|
||||
return ParseSuccess;
|
||||
}
|
||||
|
||||
protected Expression ChoiceSingleCondition()
|
||||
{
|
||||
if (ParseString ("{") == null)
|
||||
return null;
|
||||
|
||||
var condExpr = Expect(Expression, "choice condition inside { }") as Expression;
|
||||
DisallowIncrement (condExpr);
|
||||
|
||||
Expect (String ("}"), "closing '}' for choice condition");
|
||||
|
||||
return condExpr;
|
||||
}
|
||||
|
||||
protected Gather Gather()
|
||||
{
|
||||
object gatherDashCountObj = Parse(GatherDashes);
|
||||
if (gatherDashCountObj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int gatherDashCount = (int)gatherDashCountObj;
|
||||
|
||||
// Optional name for the gather
|
||||
Identifier optionalName = Parse(BracketedName);
|
||||
|
||||
var gather = new Gather (optionalName, gatherDashCount);
|
||||
|
||||
// Optional newline before gather's content begins
|
||||
Newline ();
|
||||
|
||||
return gather;
|
||||
}
|
||||
|
||||
protected object GatherDashes()
|
||||
{
|
||||
Whitespace ();
|
||||
|
||||
int gatherDashCount = 0;
|
||||
|
||||
while (ParseDashNotArrow () != null) {
|
||||
gatherDashCount++;
|
||||
Whitespace ();
|
||||
}
|
||||
|
||||
if (gatherDashCount == 0)
|
||||
return null;
|
||||
|
||||
return gatherDashCount;
|
||||
}
|
||||
|
||||
protected object ParseDashNotArrow()
|
||||
{
|
||||
var ruleId = BeginRule ();
|
||||
|
||||
if (ParseString ("->") == null && ParseSingleCharacter () == '-') {
|
||||
return SucceedRule (ruleId);
|
||||
} else {
|
||||
return FailRule (ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
protected Identifier BracketedName()
|
||||
{
|
||||
if (ParseString ("(") == null)
|
||||
return null;
|
||||
|
||||
Whitespace ();
|
||||
|
||||
Identifier name = Parse(IdentifierWithMetadata);
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
Whitespace ();
|
||||
|
||||
Expect (String (")"), "closing ')' for bracketed name");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool _parsingChoice;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user