// 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($"shortcutoption_{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 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 = GenerateCodeForExpressionsInFormattedText(shortcut.line_statement().line_formatted_text().children); // Get the line ID from the hashtags if it has one string lineID = Compiler.GetLineID(shortcut.line_statement().hashtag()); if (lineID == null) { throw new ParseException("No line ID provided"); } // And add this option to the list. compiler.Emit( OpCode.AddOption, 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. 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); }
public CodeGenerationVisitor(Compiler compiler) { this.compiler = compiler; this.loadOperators(); }