protected override void Stmt(string text, LNode expected, Action <EcsPrinterOptions> configure = null, Mode mode = Mode.Both) { bool exprMode = (mode & Mode.Expression) != 0; if ((mode & (Mode.ParserTest | Mode.ExpectAndDropParserError)) == 0) { return; } var sink = (mode & Mode.ExpectAndDropParserError) != 0 ? new MessageHolder() : (IMessageSink)ConsoleMessageSink.Value; using (Token.SetToStringStrategy(TokenExt.ToString)) // debugging aid { // This is the easy way: // LNode result = EcsLanguageService.Value.ParseSingle(text, sink, exprMode ? ParsingMode.Expressions : ParsingMode.Statements, preserveComments: true); // But to make debugging easier, I'll do it the long way: ILexer <Token> lexer = EcsLanguageService.Value.Tokenize(new UString(text), "", sink); var preprocessed = new EcsPreprocessor(lexer, true); var treeified = new TokensToTree(preprocessed, false); var parser = new EcsParser(treeified.Buffered(), lexer.SourceFile, sink); VList <LNode> results = exprMode ? LNode.List(parser.ExprStart(false)) : LNode.List(parser.ParseStmtsGreedy()); // Inject comments var injector = new EcsTriviaInjector(preprocessed.TriviaList, preprocessed.SourceFile, (int)TokenType.Newline, "/*", "*/", "//"); results = LNode.List(injector.Run(results.GetEnumerator()).ToList()); LNode result = results.AsLNode(S.Splice); AreEqual(TokenType.EOF, parser.LT0.Type(), string.Format("Parser stopped before EOF at [{0}] in {1}", parser.LT0.StartIndex, text)); if ((mode & Mode.IgnoreTrivia) != 0) { result = result.ReplaceRecursive(n => n.IsTrivia ? Maybe <LNode> .NoValue : n, LNode.ReplaceOpt.ProcessAttrs).Value; } if (sink is MessageHolder) { ((MessageHolder)sink).WriteListTo(TraceMessageSink.Value); GreaterOrEqual(((MessageHolder)sink).List.Count(m => m.Severity >= Severity.Error), 1, "Expected an error but got none for " + text); if (expected == null) { return; } } AreEqual(expected, result); } }
// This is called either at the root node, or by a macro that wants to // preprocess its children (see IMacroContext.PreProcess()). LNode PreProcess(ref VList <LNode> list, LNode single, bool asRoot, bool resetOpenNamespaces, bool areAttributesOrIsTarget) { if (single == null && list.Count == 0) { return(null); // no-op requested } var oldS = _s; var oldAncestors = _ancestorStack; var oldMP = MacroProcessor._current; MacroProcessor._current = _parent; bool newScope = false; int maxExpansions = asRoot ? MaxExpansions : _s.MaxExpansions - 1; try { bool reentrant = _reentrancyCounter++ != 0; if (!reentrant) { asRoot = true; } Debug.Assert(reentrant || _scopes.Count == 0); Debug.Assert(reentrant || _ancestorStack == null); if (asRoot) { _ancestorStack = new DList <LNode>(); } _s = new CurNodeState(); if (asRoot || resetOpenNamespaces) { var namespaces = !reentrant || resetOpenNamespaces?_parent._preOpenedNamespaces.Clone() : _curScope.OpenNamespaces.Clone(); var properties = asRoot ? _rootScopedProperties.Clone() : _curScope.ScopedProperties; newScope = true; _curScope = new Scope(namespaces, properties, this, true); _scopes.Add(_curScope); } if (single != null) { bool _; return(ApplyMacros(single, maxExpansions, areAttributesOrIsTarget, out _) ?? single); } else { int oldStackCount = _ancestorStack.Count; LNode splice = null; if (asRoot) { splice = list.AsLNode(S.Splice); _ancestorStack.PushLast(splice); } list = ApplyMacrosToList(list, maxExpansions, areAttributesOrIsTarget); if (asRoot) { _ancestorStack.PopLast(); } Debug.Assert(_ancestorStack.Count == oldStackCount); return(splice); } } finally { _reentrancyCounter--; MacroProcessor._current = oldMP; _ancestorStack = oldAncestors; _s = oldS; if (newScope) { PopScope(); } } }