mirror of
https://github.com/Ratstail91/Mementos.git
synced 2025-11-29 02:24:28 +11:00
159 lines
5.6 KiB
C#
159 lines
5.6 KiB
C#
|
|
using System.Collections.Generic;
|
|
|
|
namespace Ink.Parsed
|
|
{
|
|
public class ConditionalSingleBranch : Parsed.Object
|
|
{
|
|
// bool condition, e.g.:
|
|
// { 5 == 4:
|
|
// - the true branch
|
|
// - the false branch
|
|
// }
|
|
public bool isTrueBranch { get; set; }
|
|
|
|
// When each branch has its own expression like a switch statement,
|
|
// this is non-null. e.g.
|
|
// { x:
|
|
// - 4: the value of x is four (ownExpression is the value 4)
|
|
// - 3: the value of x is three
|
|
// }
|
|
public Expression ownExpression {
|
|
get {
|
|
return _ownExpression;
|
|
}
|
|
set {
|
|
_ownExpression = value;
|
|
if (_ownExpression) {
|
|
AddContent (_ownExpression);
|
|
}
|
|
}
|
|
}
|
|
|
|
// In the above example, match equality of x with 4 for the first branch.
|
|
// This is as opposed to simply evaluating boolean equality for each branch,
|
|
// example when shouldMatchEqualtity is FALSE:
|
|
// {
|
|
// 3 > 2: This will happen
|
|
// 2 > 3: This won't happen
|
|
// }
|
|
public bool matchingEquality { get; set; }
|
|
|
|
public bool isElse { get; set; }
|
|
|
|
public bool isInline { get; set; }
|
|
|
|
public Runtime.Divert returnDivert { get; protected set; }
|
|
|
|
public ConditionalSingleBranch (List<Parsed.Object> content)
|
|
{
|
|
// Branches are allowed to be empty
|
|
if (content != null) {
|
|
_innerWeave = new Weave (content);
|
|
AddContent (_innerWeave);
|
|
}
|
|
}
|
|
|
|
// Runtime content can be summarised as follows:
|
|
// - Evaluate an expression if necessary to branch on
|
|
// - Branch to a named container if true
|
|
// - Divert back to main flow
|
|
// (owner Conditional is in control of this target point)
|
|
public override Runtime.Object GenerateRuntimeObject ()
|
|
{
|
|
// Check for common mistake, of putting "else:" instead of "- else:"
|
|
if (_innerWeave) {
|
|
foreach (var c in _innerWeave.content) {
|
|
var text = c as Parsed.Text;
|
|
if (text) {
|
|
// Don't need to trim at the start since the parser handles that already
|
|
if (text.text.StartsWith ("else:")) {
|
|
Warning ("Saw the text 'else:' which is being treated as content. Did you mean '- else:'?", text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var container = new Runtime.Container ();
|
|
|
|
// Are we testing against a condition that's used for more than just this
|
|
// branch? If so, the first thing we need to do is replicate the value that's
|
|
// on the evaluation stack so that we don't fully consume it, in case other
|
|
// branches need to use it.
|
|
bool duplicatesStackValue = matchingEquality && !isElse;
|
|
if ( duplicatesStackValue )
|
|
container.AddContent (Runtime.ControlCommand.Duplicate ());
|
|
|
|
_conditionalDivert = new Runtime.Divert ();
|
|
|
|
// else clause is unconditional catch-all, otherwise the divert is conditional
|
|
_conditionalDivert.isConditional = !isElse;
|
|
|
|
// Need extra evaluation?
|
|
if( !isTrueBranch && !isElse ) {
|
|
|
|
bool needsEval = ownExpression != null;
|
|
if( needsEval )
|
|
container.AddContent (Runtime.ControlCommand.EvalStart ());
|
|
|
|
if (ownExpression)
|
|
ownExpression.GenerateIntoContainer (container);
|
|
|
|
// Uses existing duplicated value
|
|
if (matchingEquality)
|
|
container.AddContent (Runtime.NativeFunctionCall.CallWithName ("=="));
|
|
|
|
if( needsEval )
|
|
container.AddContent (Runtime.ControlCommand.EvalEnd ());
|
|
}
|
|
|
|
// Will pop from stack if conditional
|
|
container.AddContent (_conditionalDivert);
|
|
|
|
_contentContainer = GenerateRuntimeForContent ();
|
|
_contentContainer.name = "b";
|
|
|
|
// Multi-line conditionals get a newline at the start of each branch
|
|
// (as opposed to the start of the multi-line conditional since the condition
|
|
// may evaluate to false.)
|
|
if (!isInline) {
|
|
_contentContainer.InsertContent (new Runtime.StringValue ("\n"), 0);
|
|
}
|
|
|
|
if( duplicatesStackValue || (isElse && matchingEquality) )
|
|
_contentContainer.InsertContent (Runtime.ControlCommand.PopEvaluatedValue (), 0);
|
|
|
|
container.AddToNamedContentOnly (_contentContainer);
|
|
|
|
returnDivert = new Runtime.Divert ();
|
|
_contentContainer.AddContent (returnDivert);
|
|
|
|
return container;
|
|
}
|
|
|
|
Runtime.Container GenerateRuntimeForContent()
|
|
{
|
|
// Empty branch - create empty container
|
|
if (_innerWeave == null) {
|
|
return new Runtime.Container ();
|
|
}
|
|
|
|
return _innerWeave.rootContainer;
|
|
}
|
|
|
|
public override void ResolveReferences (Story context)
|
|
{
|
|
_conditionalDivert.targetPath = _contentContainer.path;
|
|
|
|
base.ResolveReferences (context);
|
|
}
|
|
|
|
Runtime.Container _contentContainer;
|
|
Runtime.Divert _conditionalDivert;
|
|
Expression _ownExpression;
|
|
|
|
Weave _innerWeave;
|
|
}
|
|
}
|
|
|