// Given a bunch of raw text, load all nodes that were inside it. public static Status CompileString(string text, string fileName, out Program program, out IDictionary <string, StringInfo> stringTable) { string inputString = PreprocessIndentationInSource(text); ICharStream input = CharStreams.fromstring(inputString); YarnSpinnerLexer lexer = new YarnSpinnerLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); YarnSpinnerParser parser = new YarnSpinnerParser(tokens); // turning off the normal error listener and using ours parser.RemoveErrorListeners(); parser.AddErrorListener(ErrorListener.Instance); IParseTree tree = parser.dialogue(); Compiler compiler = new Compiler(fileName); compiler.Compile(tree); program = compiler.program; stringTable = compiler.StringTable; if (compiler.containsImplicitStringTags) { return(Status.SucceededUntaggedStrings); } else { return(Status.Succeeded); } }
// Given a bunch of raw text, load all nodes that were inside it. // You can call this multiple times to append to the collection of nodes, // but note that new nodes will replace older ones with the same name. // Returns the number of nodes that were loaded. public Program Load(string text, Library library, string fileName, Program includeProgram, bool showTokens, bool showParseTree, string onlyConsiderNode, NodeFormat format) { if (format == NodeFormat.Unknown) { format = GetFormatFromFileName(fileName); } // currently experimental node can only be used on yarn.txt yarn files and single nodes if (format != NodeFormat.Text && format != NodeFormat.SingleNodeText) { throw new InvalidDataException($"Invalid node format {format}"); } // this isn't the greatest... if (format == NodeFormat.SingleNodeText) { // it is just the body // need to add a dummy header and body delimiters StringBuilder builder = new StringBuilder(); builder.Append("title:Start\n"); builder.Append("---\n"); builder.Append(text); builder.Append("\n===\n"); text = builder.ToString(); } string inputString = preprocessor(text); ICharStream input = CharStreams.fromstring(inputString); YarnSpinnerLexer lexer = new YarnSpinnerLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); YarnSpinnerParser parser = new YarnSpinnerParser(tokens); // turning off the normal error listener and using ours parser.RemoveErrorListeners(); parser.AddErrorListener(ErrorListener.Instance); IParseTree tree = parser.dialogue(); Compiler compiler = new Compiler(library); compiler.Compile(tree); // merging in the other program if requested if (includeProgram != null) { compiler.program.Include(includeProgram); } return(compiler.program); }
/// <summary> /// Generates a program and a derived string table from the /// contents of a string. /// </summary> /// <param name="text">The source code of the program.</param> /// <param name="fileName">The file name to assign to the compiled /// results.</param> /// <param name="program">On return, contains the compiled /// program.</param> /// <param name="stringTable">On return, contains the string table /// generated from the source code.</param> /// <returns>The status of the compilation.</returns> /// <exception cref="ParseException">Thrown when a parse error /// occurs during compilation.</exception> public static Status CompileString(string text, string fileName, out Program program, out IDictionary <string, StringInfo> stringTable) { ICharStream input = CharStreams.fromstring(text); YarnSpinnerLexer lexer = new YarnSpinnerLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); YarnSpinnerParser parser = new YarnSpinnerParser(tokens); // turning off the normal error listener and using ours parser.RemoveErrorListeners(); parser.AddErrorListener(ParserErrorListener.Instance); lexer.RemoveErrorListeners(); lexer.AddErrorListener(LexerErrorListener.Instance); IParseTree tree; try { tree = parser.dialogue(); } catch (ParseException e) { var tokenStringList = new List <string>(); tokens.Reset(); foreach (var token in tokens.GetTokens()) { tokenStringList.Add($"{token.Line}:{token.Column} {YarnSpinnerLexer.DefaultVocabulary.GetDisplayName(token.Type)} \"{token.Text}\""); } throw new ParseException($"{e.Message}\n\nTokens:\n{string.Join("\n", tokenStringList)}"); } Compiler compiler = new Compiler(fileName); compiler.Compile(tree); program = compiler.Program; stringTable = compiler.StringTable; if (compiler.containsImplicitStringTags) { return(Status.SucceededUntaggedStrings); } else { return(Status.Succeeded); } }
private static IParseTree ParseSyntaxTree(CompilationJob.File file) { ICharStream input = CharStreams.fromstring(file.Source); YarnSpinnerLexer lexer = new YarnSpinnerLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); YarnSpinnerParser parser = new YarnSpinnerParser(tokens); // turning off the normal error listener and using ours parser.RemoveErrorListeners(); parser.AddErrorListener(ParserErrorListener.Instance); lexer.RemoveErrorListeners(); lexer.AddErrorListener(LexerErrorListener.Instance); IParseTree tree; try { tree = parser.dialogue(); } catch (ParseException e) { #if DEBUG var tokenStringList = new List <string>(); tokens.Reset(); foreach (var token in tokens.GetTokens()) { tokenStringList.Add($"{token.Line}:{token.Column} {YarnSpinnerLexer.DefaultVocabulary.GetDisplayName(token.Type)} \"{token.Text}\""); } throw new ParseException(e.Context, $"{e.Message}\n\nTokens:\n{string.Join("\n", tokenStringList)}", file.FileName); #else throw new ParseException(e.Context, e.Message, file.FileName); #endif // DEBUG } return(tree); }
// Given a bunch of raw text, load all nodes that were inside it. // You can call this multiple times to append to the collection of nodes, // but note that new nodes will replace older ones with the same name. // Returns the number of nodes that were loaded. public Program Load(string text, Library library, string fileName, Program includeProgram, bool showTokens, bool showParseTree, string onlyConsiderNode, NodeFormat format, bool experimentalMode = false) { if (format == NodeFormat.Unknown) { format = GetFormatFromFileName(fileName); } // currently experimental node can only be used on yarn.txt yarn files and single nodes if (experimentalMode && (format == NodeFormat.Text || format == NodeFormat.SingleNodeText)) { // this isn't the greatest... if (format == NodeFormat.SingleNodeText) { // it is just the body // need to add a dummy header and body delimiters StringBuilder builder = new StringBuilder(); builder.Append("title:Start\n"); builder.Append("---\n"); builder.Append(text); builder.Append("\n===\n"); text = builder.ToString(); } string inputString = preprocessor(text); ICharStream input = CharStreams.fromstring(inputString); YarnSpinnerLexer lexer = new YarnSpinnerLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); YarnSpinnerParser parser = new YarnSpinnerParser(tokens); // turning off the normal error listener and using ours parser.RemoveErrorListeners(); parser.AddErrorListener(ErrorListener.Instance); IParseTree tree = parser.dialogue(); AntlrCompiler antlrcompiler = new AntlrCompiler(library); antlrcompiler.Compile(tree); // merging in the other program if requested if (includeProgram != null) { antlrcompiler.program.Include(includeProgram); } return(antlrcompiler.program); } else { // The final parsed nodes that were in the file we were given Dictionary <string, Yarn.Parser.Node> nodes = new Dictionary <string, Parser.Node>(); // Load the raw data and get the array of node title-text pairs var nodeInfos = GetNodesFromText(text, format); int nodesLoaded = 0; foreach (NodeInfo nodeInfo in nodeInfos) { if (onlyConsiderNode != null && nodeInfo.title != onlyConsiderNode) { continue; } // Attempt to parse every node; log if we encounter any errors #if CATCH_EXCEPTIONS try { #endif if (nodeInfo.title == null) { throw new InvalidOperationException("Tried to load a node with no title."); } if (nodes.ContainsKey(nodeInfo.title)) { throw new InvalidOperationException("Attempted to load a node called " + nodeInfo.title + ", but a node with that name has already been loaded!"); } var lexer = new Lexer(); var tokens = lexer.Tokenise(nodeInfo.title, nodeInfo.body); if (showTokens) { PrintTokenList(tokens); } var node = new Parser(tokens, library).Parse(); // If this node is tagged "rawText", then preserve its source if (string.IsNullOrEmpty(nodeInfo.tags) == false && nodeInfo.tags.Contains("rawText")) { node.source = nodeInfo.body; } node.name = nodeInfo.title; node.nodeTags = nodeInfo.tagsList; if (showParseTree) { PrintParseTree(node); } nodes[nodeInfo.title] = node; nodesLoaded++; #if CATCH_EXCEPTIONS } catch (Yarn.TokeniserException t) { // Add file information var message = string.Format("In file {0}: Error reading node {1}: {2}", fileName, nodeInfo.title, t.Message); throw new Yarn.TokeniserException(message); } catch (Yarn.ParseException p) { var message = string.Format("In file {0}: Error parsing node {1}: {2}", fileName, nodeInfo.title, p.Message); throw new Yarn.ParseException(message); } catch (InvalidOperationException e) { var message = string.Format("In file {0}: Error reading node {1}: {2}", fileName, nodeInfo.title, e.Message); throw new InvalidOperationException(message); } #endif } var compiler = new Yarn.Compiler(fileName); foreach (var node in nodes) { compiler.CompileNode(node.Value); } if (includeProgram != null) { compiler.program.Include(includeProgram); } return(compiler.program); } }