Пример #1
0
        // a regular ol' line of text
        public override int VisitLine_statement(YarnSpinnerParser.Line_statementContext context)
        {
            // TODO: add support for line conditions:
            //
            // Mae: here's a line <<if true>>
            //
            // is identical to
            //
            // <<if true>> Mae: here's a line <<endif>>

            // Evaluate the inline expressions and push the results onto the
            // stack.
            var expressionCount = this.GenerateCodeForExpressionsInFormattedText(context.line_formatted_text().children);

            // Get the lineID for this string from the hashtags
            var lineIDTag = Compiler.GetLineIDTag(context.hashtag());

            if (lineIDTag == null)
            {
                throw new InvalidOperationException("Internal error: line should have an implicit or explicit line ID tag, but none was found");
            }

            var lineID = lineIDTag.text.Text;

            this.compiler.Emit(OpCode.RunLine, context.Start, new Operand(lineID), new Operand(expressionCount));

            return(0);
        }
        public override int VisitLine_statement([NotNull] YarnSpinnerParser.Line_statementContext context)
        {
            int lineNumber = context.Start.Line;

            YarnSpinnerParser.HashtagContext[] hashtags = context.hashtag();
            var lineIDTag = Compiler.GetLineIDTag(hashtags);
            var lineID    = lineIDTag?.text.Text ?? null;

            var hashtagText = GetHashtagTexts(hashtags);

            GenerateFormattedText(context.line_formatted_text().children, out var composedString, out var expressionCount);

            // Does this string table already have a string with this ID?
            if (lineID != null && stringTableManager.ContainsKey(lineID))
            {
                // If so, this is an error.
                ParserRuleContext diagnosticContext;

                diagnosticContext = lineIDTag ?? (ParserRuleContext)context;

                this.diagnostics.Add(new Diagnostic(fileName, diagnosticContext, $"Duplicate line ID {lineID}"));

                return(0);
            }

            string stringID = stringTableManager.RegisterString(
                composedString.ToString(),
                fileName,
                currentNodeName,
                lineID,
                lineNumber,
                hashtagText);

            if (lineID == null)
            {
                var hashtag = new YarnSpinnerParser.HashtagContext(context, 0);
                hashtag.text = new CommonToken(YarnSpinnerLexer.HASHTAG_TEXT, stringID);
                context.AddChild(hashtag);
            }

            return(0);
        }
Пример #3
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);
        }