LNode Process(ref RVList <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; 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 ? new MMap <object, object>() : _curScope.ScopedProperties; newScope = true; _curScope = new Scope(namespaces, properties, this, true); _scopes.Add(_curScope); } int maxExpansions = asRoot ? MaxExpansions : _s.MaxExpansions - 1; if (single != null) { return(ApplyMacros(single, maxExpansions, areAttributesOrIsTarget)); } else { int oldStackCount = _ancestorStack.Count; LNode splice = null; if (asRoot) { splice = list.AsLNode(S.Splice); _ancestorStack.PushLast(splice); } list = ApplyMacrosToList(list, maxExpansions, areAttributesOrIsTarget); _ancestorStack.PopLast(); Debug.Assert(_ancestorStack.Count == oldStackCount); return(splice); } } finally { _reentrancyCounter--; MacroProcessor._current = oldMP; _ancestorStack = oldAncestors; _s = oldS; if (newScope) { PopScope(); } } }
public static LNode on_return(LNode node, IMacroContext context) { LNode firstArg, rest, on_handler = ValidateOnStmt(node, context, out rest, out firstArg); if (on_handler == null) { return(null); } // Get/construct the declaration of the var to return, and get its name LNode varDecl = firstArg, varName = firstArg; bool varAssigned = false; if (firstArg == null) { varName = F.Id(__result__); varDecl = F.Var(F._Missing, varName); } else { if (varDecl.Calls(S.Var, 2)) { if (varAssigned = (varName = varDecl.Args[1]).Calls(S.Assign, 2)) { varName = varName.Args[0]; } } else if (varName.IsId) { varDecl = node.With(S.Var, F._Missing, varName); } else { return(Reject(context, firstArg, "The first parameter to on_return must be a simple identifier (the name of a variable to return) or a variable declaration (for a variable to be returned).")); } } var retExpr = F.Call(S.Substitute, F.Id(__retexpr__)); Pair <LNode, LNode>[] patterns = new Pair <LNode, LNode>[2] { // return; => { <on_handler> return; } new Pair <LNode, LNode>(F.Call(S.Return), varAssigned ? on_handler.WithArgs(new RVList <LNode>(varDecl) .AddRange(on_handler.Args) .Add(F.Call(S.Return, varName))) : on_handler.PlusArg(F.Call(S.Return))), // return exp; => { <varDecl = $exp> <on_handler> return <varName>; } new Pair <LNode, LNode>(F.Call(S.Return, retExpr), on_handler.WithArgs(new RVList <LNode>( varDecl.WithArgChanged(1, F.Call(S.Assign, varName, retExpr))) .AddRange(on_handler.Args) .Add(F.Call(S.Return, varName)))) }; int replacementCount = 0; RVList <LNode> output = StandardMacros.Replace(rest.Args, patterns, out replacementCount); if (replacementCount == 0) { context.Write(Severity.Warning, node, "'on_return': no 'return' statements were found below this line, so this macro had no effect."); } return(output.AsLNode(S.Splice)); }