Beispiel #1
0
        // for the shortcut options (-> line of text <<if expression>> indent
        // statements dedent)+
        public override int VisitShortcut_option_statement(YarnSpinnerParser.Shortcut_option_statementContext context)
        {
            string endOfGroupLabel = this.compiler.RegisterLabel("group_end");

            var labels = new List <string>();

            int optionCount = 0;

            // For each option, create an internal destination label that, if
            // the user selects the option, control flow jumps to. Then,
            // evaluate its associated line_statement, and use that as the
            // option text. Finally, add this option to the list of upcoming
            // options.
            foreach (var shortcut in context.shortcut_option())
            {
                // Generate the name of internal label that we'll jump to if
                // this option is selected. We'll emit the label itself later.
                string optionDestinationLabel = this.compiler.RegisterLabel($"shortcutoption_{this.compiler.CurrentNode.Name ?? "node"}_{optionCount + 1}");
                labels.Add(optionDestinationLabel);

                // This line statement may have a condition on it. If it does,
                // emit code that evaluates the condition, and add a flag on the
                // 'Add Option' instruction that indicates that a condition
                // exists.
                bool hasLineCondition = false;
                if (shortcut.line_statement().line_condition() != null)
                {
                    // Evaluate the condition, and leave it on the stack
                    this.Visit(shortcut.line_statement().line_condition().expression());

                    hasLineCondition = true;
                }

                // We can now prepare and add the option.

                // Start by figuring out the text that we want to add. This will
                // involve evaluating any inline expressions.
                var expressionCount = this.GenerateCodeForExpressionsInFormattedText(shortcut.line_statement().line_formatted_text().children);

                // Get the line ID from the hashtags if it has one
                var    lineIDTag = Compiler.GetLineIDTag(shortcut.line_statement().hashtag());
                string lineID    = lineIDTag.text.Text;

                if (lineIDTag == null)
                {
                    throw new InvalidOperationException("Internal error: no line ID provided");
                }

                // And add this option to the list.
                this.compiler.Emit(
                    OpCode.AddOption,
                    shortcut.line_statement().Start,
                    new Operand(lineID),
                    new Operand(optionDestinationLabel),
                    new Operand(expressionCount),
                    new Operand(hasLineCondition));

                optionCount++;
            }

            // All of the options that we intend to show are now ready to go.
            this.compiler.Emit(OpCode.ShowOptions, context.Stop);

            // The top of the stack now contains the name of the label we want
            // to jump to. Jump to it now.
            this.compiler.Emit(OpCode.Jump, context.Stop);

            // We'll now emit the labels and code associated with each option.
            optionCount = 0;
            foreach (var shortcut in context.shortcut_option())
            {
                // Emit the label for this option's code
                this.compiler.CurrentNode.Labels.Add(labels[optionCount], this.compiler.CurrentNode.Instructions.Count);

                // Run through all the children statements of the shortcut
                // option.
                foreach (var child in shortcut.statement())
                {
                    this.Visit(child);
                }

                // Jump to the end of this shortcut option group.
                this.compiler.Emit(OpCode.JumpTo, shortcut.Stop, new Operand(endOfGroupLabel));

                optionCount++;
            }

            // We made it to the end! Mark the end of the group, so we can jump
            // to it.
            this.compiler.CurrentNode.Labels.Add(endOfGroupLabel, this.compiler.CurrentNode.Instructions.Count);
            this.compiler.Emit(OpCode.Pop, context.Stop);

            return(0);
        }
Beispiel #2
0
        // for the shortcut options
        // (-> line of text <<if expression>> indent statements dedent)+
        public override int VisitShortcut_option_statement(YarnSpinnerParser.Shortcut_option_statementContext context)
        {
            string endOfGroupLabel = compiler.RegisterLabel("group_end");

            var labels = new List <string>();

            int optionCount = 0;

            // For each option, create an internal destination label that,
            // if the user selects the option, control flow jumps to. Then,
            // evaluate its associated line_statement, and use that as the
            // option text. Finally, add this option to the list of
            // upcoming options.
            foreach (var shortcut in context.shortcut_option())
            {
                // Generate the name of internal label that we'll jump to
                // if this option is selected. We'll emit the label itself
                // later.
                string optionDestinationLabel = compiler.RegisterLabel("option_" + (optionCount + 1));
                labels.Add(optionDestinationLabel);

                // This line statement may have a condition on it. If it
                // does, emit code that evaluates the condition, and skips
                // over the code that prepares and adds the option.
                string endOfClauseLabel = null;
                if (shortcut.line_statement().line_condition() != null)
                {
                    // Register the label we'll jump to if the condition
                    // fails. We'll add it later.
                    endOfClauseLabel = compiler.RegisterLabel("conditional_" + optionCount);

                    // Evaluate the condition, and jump to the end of
                    // clause if it evaluates to false.

                    Visit(shortcut.line_statement().line_condition().expression());

                    compiler.Emit(OpCode.JumpIfFalse, new Operand(endOfClauseLabel));
                }

                // We can now prepare and add the option.

                // Start by figuring out the text that we want to add. This
                // will involve evaluating any inline expressions.
                GenerateFormattedText(shortcut.line_statement().line_formatted_text().children, out var composedString, out var expressionCount);

                // Get the line ID from the hashtags if it has one
                string lineID = compiler.GetLineID(shortcut.line_statement().hashtag());

                // Get the hashtags for the line
                var hashtags = GetHashtagTexts(shortcut.line_statement().hashtag());

                // Register this string
                string labelStringID = compiler.RegisterString(composedString, compiler.CurrentNode.Name, lineID, shortcut.Start.Line, hashtags);

                // And add this option to the list.
                compiler.Emit(OpCode.AddOption, new Operand(labelStringID), new Operand(optionDestinationLabel), new Operand(expressionCount));

                // If we had a line condition, now's the time to generate
                // the label that we'd jump to if its condition is false.
                if (shortcut.line_statement().line_condition() != null)
                {
                    compiler.CurrentNode.Labels.Add(endOfClauseLabel, compiler.CurrentNode.Instructions.Count);

                    // JumpIfFalse doesn't change the stack, so we need to
                    // tidy up
                    compiler.Emit(OpCode.Pop);
                }

                optionCount++;
            }

            // All of the options that we intend to show are now ready to
            // go.
            compiler.Emit(OpCode.ShowOptions);

            // The top of the stack now contains the name of the label we
            // want to jump to. Jump to it now.
            compiler.Emit(OpCode.Jump);

            // We'll now emit the labels and code associated with each
            // option.
            optionCount = 0;
            foreach (var shortcut in context.shortcut_option())
            {
                // Emit the label for this option's code
                compiler.CurrentNode.Labels.Add(labels[optionCount], compiler.CurrentNode.Instructions.Count);

                // Run through all the children statements of the shortcut
                // option.
                foreach (var child in shortcut.statement())
                {
                    Visit(child);
                }

                // Jump to the end of this shortcut option group.
                compiler.Emit(OpCode.JumpTo, new Operand(endOfGroupLabel));

                optionCount++;
            }

            // We made it to the end! Mark the end of the group, so we can jump to it.
            compiler.CurrentNode.Labels.Add(endOfGroupLabel, compiler.CurrentNode.Instructions.Count);
            compiler.Emit(OpCode.Pop);

            return(0);
        }
 /// <summary>
 /// Visit a parse tree produced by <see cref="YarnSpinnerParser.shortcut_option_statement"/>.
 /// <para>
 /// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
 /// on <paramref name="context"/>.
 /// </para>
 /// </summary>
 /// <param name="context">The parse tree.</param>
 /// <return>The visitor result.</return>
 public virtual Result VisitShortcut_option_statement([NotNull] YarnSpinnerParser.Shortcut_option_statementContext context)
 {
     return(VisitChildren(context));
 }
 /// <summary>
 /// Exit a parse tree produced by <see cref="YarnSpinnerParser.shortcut_option_statement"/>.
 /// <para>The default implementation does nothing.</para>
 /// </summary>
 /// <param name="context">The parse tree.</param>
 public virtual void ExitShortcut_option_statement([NotNull] YarnSpinnerParser.Shortcut_option_statementContext context)
 {
 }