private LNode ApplyMacrosFound(LNode input, int maxExpansions) { // Implicit paramater: _foundMacros. _results and _messageHolder are // temporaries that are re-used between invocations of this method to // avoid stressing the garbage collector. var s = new ApplyMacroState { foundMacros = _foundMacros, results = _results, messageHolder = _messageHolder }; // if any of the macros use a priority flag, group by priority. if (_foundMacros.Count > 1) { var p = s.foundMacros[0].Mode & MacroMode.PriorityMask; for (int x = 1, c = s.foundMacros.Count; x < c; x++) { if ((s.foundMacros[x].Mode & MacroMode.PriorityMask) != p) { // need to make an independent list because _foundMacros may be cleared and re-used for descendant nodes s.foundMacros = new List <MacroInfo>(s.foundMacros); s.foundMacros.Sort(); for (int i = 0, j; i < c; i = j) { p = s.foundMacros[i].Mode & MacroMode.PriorityMask; for (j = i + 1; j < c; j++) { if ((s.foundMacros[j].Mode & MacroMode.PriorityMask) != p) { break; } } LNode result = ApplyMacrosFound2(input, maxExpansions, s.foundMacros.Slice(i, j - i), ref s); if (result != null) { return(result); } } return(null); } } } return(ApplyMacrosFound2(input, maxExpansions, s.foundMacros.Slice(0), ref s)); }
private LNode ApplyMacrosFound2(LNode input, int maxExpansions, ListSlice <MacroInfo> foundMacros, ref ApplyMacroState s) { s.results.Clear(); s.messageHolder.List.Clear(); int accepted = 0, acceptedIndex = -1; for (int i = 0; i < foundMacros.Count; i++) { var macro = foundMacros[i]; var macroInput = input; if ((macro.Mode & MacroMode.ProcessChildrenBefore) != 0) { if (maxExpansions == 1) { continue; // avoid expanding both this macro and its children } if (s.preprocessed == null) { // _foundMacros, _results, and _messageHolder are re-used // by callee for unrelated contexts, so make copies of the s.* // variables which point to them. s.foundMacros = new List <MacroInfo>(s.foundMacros); s.results = new List <Result>(s.results); s.messageHolder = s.messageHolder.Clone(); foundMacros = new List <MacroInfo>(foundMacros).Slice(0); s.preprocessed = ApplyMacrosToChildren(input, maxExpansions) ?? input; } macroInput = s.preprocessed; } LNode output = null; int mhi = s.messageHolder.List.Count; try { output = macro.Macro(macroInput, s.messageHolder); if (output != null) { accepted++; acceptedIndex = i; } } catch (ThreadAbortException e) { _sink.Write(Severity.Error, input, "Macro-processing thread aborted in {0}", QualifiedName(macro.Macro.Method)); _sink.Write(Severity.Detail, input, e.StackTrace); s.results.Add(new Result(macro, output, s.messageHolder.List.Slice(mhi, s.messageHolder.List.Count - mhi))); PrintMessages(s.results, input, accepted, Severity.Error); throw; } catch (Exception e) { s.messageHolder.Write(Severity.Error, input, "{0}: {1}", e.GetType().Name, e.Message); s.messageHolder.Write(Severity.Detail, input, e.StackTrace); } s.results.Add(new Result(macro, output, s.messageHolder.List.Slice(mhi, s.messageHolder.List.Count - mhi))); } PrintMessages(s.results, input, accepted, s.messageHolder.List.MaxOrDefault(msg => (int)msg.Severity).Severity); if (accepted >= 1) { var result = s.results[acceptedIndex]; Debug.Assert(result.Node != null); if ((result.Macro.Mode & MacroMode.ProcessChildrenBefore) != 0) { maxExpansions--; } if ((result.Macro.Mode & MacroMode.Normal) != 0) { if (result.Node == input) { return(ApplyMacrosToChildren(result.Node, maxExpansions - 1) ?? result.Node); } else { return(ApplyMacros(result.Node, maxExpansions - 1) ?? result.Node); } } else if ((result.Macro.Mode & MacroMode.ProcessChildrenAfter) != 0) { return(ApplyMacrosToChildren(result.Node, maxExpansions - 1) ?? result.Node); } else { return(result.Node); } } else { // "{}" needs special treatment if (input.Calls(S.Braces)) { try { return(s.preprocessed ?? ApplyMacrosToChildren(input, maxExpansions)); } finally { PopScope(); } } return(s.preprocessed ?? ApplyMacrosToChildren(input, maxExpansions)); } }