// A complex identifier has the form Id, ComplexId.Id, or ComplexId!(ComplexId, ...) // where Id is a simple identifier and ComplexId is a complex identifier. Also, the // form X!Y!Z, i.e. #of(#of(...), ...) is not allowed. $Substitution is allowed. public static bool IsComplexId(LNode id, bool allowOf = true) { if (id.IsCall) { if (id.Name == S.Of) { if (allowOf) { return((id.HasSimpleHead() || IsComplexId(id.Target, false)) && id.Args.All(a => IsComplexId(a))); } return(false); } else if (id.Calls(S.Dot, 2)) { return(id.Args.Last.IsId && IsComplexId(id.Args[0])); } else if (id.Calls(S.Substitute, 1)) { return(true); } else { return(false); } } else { return(id.IsId); } }
static Symbol GetContractAttrMode(LNode attr, out LNode exceptionType) { var mode = attr.Name; exceptionType = null; if (!attr.HasSimpleHead()) { var target = attr.Target; if (target.Calls(S.Of, 2) && target.Args[0].IsIdNamed(sy_ensuresOnThrow)) { exceptionType = target.Args[1]; mode = sy_ensuresOnThrow; } } if (mode == __notnull) { mode = sy_notnull; } if (mode == sy_ensuresOnThrow || mode == sy_requires || mode == sy_notnull || mode == sy_assert || mode == sy_ensures || mode == sy_ensuresAssert || mode == sy_ensuresFinally) { return(mode); } return(null); }
/// <summary>Recursively applies macros in scope to <c>input</c>.</summary> /// <param name="maxExpansions">Maximum number of opportunities given /// to macros to transform a given subtree. The output of any macro is /// transformed again (as if by calling this method) with /// <c>maxExpansions = maxExpansions - 1</c> to encourage the /// expansion process to terminate eventually.</param> /// <returns>Returns a transformed tree or null if the macros did not /// change the syntax tree at any level, paired with a flag that is /// true if the remainder of the nodes in the current list of nodes /// should be dropped.</returns> LNode ApplyMacros(LNode input, int maxExpansions, bool isTargetNode) { if (maxExpansions <= 0) { return(null); } _s.StartNextNode(input, maxExpansions, isTargetNode); // Find macros... LNode target; if (input.HasSimpleHead()) { GetApplicableMacros(_curScope.OpenNamespaces, input.Name, _s.FoundMacros); } else if ((target = input.Target).Calls(S.Dot, 2) && target.Args[1].IsId) { Symbol name = target.Args[1].Name, @namespace = NamespaceToSymbol(target.Args[0]); GetApplicableMacros(@namespace, name, _s.FoundMacros); } _ancestorStack.PushLast(input); try { if (_s.FoundMacros.Count != 0) { return(ApplyMacrosFound(_s)); } else { return(ApplyMacrosToChildrenOf(input, maxExpansions)); } } finally { _ancestorStack.PopLast(1); } }
/// <summary>Applies macros in scope to <c>input</c>.</summary> /// <param name="maxExpansions">Maximum number of opportunities given /// to macros to transform a given subtree. The output of any macro is /// transformed again (as if by calling this method) with /// <c>maxExpansions = maxExpansions - 1</c> to encourage the /// expansion process to terminate eventually.</param> /// <returns>Returns a transformed tree or null if the macros did not /// change the syntax tree at any level.</returns> LNode ApplyMacros(LNode input, int maxExpansions) { if (maxExpansions <= 0) { return(null); } // Find macros... _foundMacros.Clear(); LNode target; if (input.HasSimpleHead()) { GetApplicableMacros(_curScope.OpenNamespaces, input.Name, _foundMacros); } else if ((target = input.Target).Calls(S.Dot, 2) && target.Args[1].IsId) { Symbol name = target.Args[1].Name, @namespace = NamespaceToSymbol(target.Args[0]); GetApplicableMacros(@namespace, name, _foundMacros); } if (_foundMacros.Count != 0) { return(ApplyMacrosFound(input, maxExpansions)); } else { return(ApplyMacrosToChildren(input, maxExpansions)); } }
private bool HasSimpleTargetWithoutPAttrs(LNode node) { if (node.HasSimpleHead()) { return(true); } var t = node.Target; return(!t.IsCall && !HasPAttrs(t)); }
public static LNode concat_id(LNode node, IMessageSink sink) { var args = node.Args; if (args.Count == 0) { return(null); } if (args.Slice(0, args.Count - 1).Any(n => n.IsCall)) { return(Reject(sink, node, "All arguments to ##() or concat() must be identifiers or literals (except the last one)")); } RVList <LNode> attrs = node.Attrs; LNode arg = null; StringBuilder sb = new StringBuilder(); for (int i = 0; i < args.Count; i++) { arg = args[i]; attrs.AddRange(arg.Attrs); if (arg.IsLiteral) { sb.Append(arg.Value ?? "null"); } else if (arg.IsId) { sb.Append(arg.Name); } else // call { if (i + 1 != args.Count || !arg.HasSimpleHead()) { return(Reject(sink, arg, "Expected simple identifier or literal")); } sb.Append(arg.Name); } } Symbol combined = GSymbol.Get(sb.ToString()); LNode result; if (arg.IsCall) { result = arg.WithTarget(combined); } else { result = LNode.Id(combined, node); } return(result.WithAttrs(attrs)); }
private void GetApplicableMacros(LNode curNode, List <MacroInfo> foundMacros) { LNode target; if (curNode.HasSimpleHead()) { GetApplicableMacros(_curScope.OpenNamespaces, curNode.Name, foundMacros); } else if ((target = curNode.Target).Calls(S.Dot, 2) && target.Args[1].IsId) { Symbol name = target.Args[1].Name, @namespace = NamespaceToSymbol(target.Args[0]); GetApplicableMacros(@namespace, name, foundMacros); } }
private static StringBuilder ConcatCore(LNode node, out LNodeList attrs, IMessageSink sink, bool allowLastToBeCall = false) { attrs = node.Attrs; var args = node.Args; if (args.Count == 0) { return(null); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < args.Count; i++) { LNode arg = args[i]; attrs.AddRange(arg.Attrs); if (arg.IsLiteral) { if (!arg.TextValue.IsNull) { arg.TextValue.AppendTo(sb); } else { sb.Append(arg.Value ?? "null"); } } else if (arg.IsId) { sb.Append(arg.Name); } else // call { if (i + 1 != args.Count || !arg.HasSimpleHead()) { Reject(sink, arg, "Expected simple identifier or literal"); return(null); } sb.Append(arg.Name); } } return(sb); }
LNode ApplyMacrosToChildren(LNode node, int maxExpansions) { if (maxExpansions <= 0) { return(null); } bool changed = false; RVList <LNode> old; var newAttrs = ApplyMacrosToList(old = node.Attrs, maxExpansions); if (newAttrs != old) { node = node.WithAttrs(newAttrs); changed = true; } if (!node.HasSimpleHead()) { LNode target = node.Target, newTarget = ApplyMacros(target, maxExpansions); if (newTarget != null) { if (newTarget.Calls(S.Splice, 1)) { newTarget = newTarget.Args[0]; } node = node.WithTarget(newTarget); changed = true; } } var newArgs = ApplyMacrosToList(old = node.Args, maxExpansions); if (newArgs != old) { node = node.WithArgs(newArgs); changed = true; } return(changed ? node : null); }
// A complex identifier has the form Id, ComplexId.Id, or ComplexId!(ComplexId, ...) // where Id is a simple identifier and ComplexId is a complex identifier. Also, the // form X!Y!Z, i.e. #of(#of(...), ...) is not allowed. $Substitution is allowed. public static bool IsComplexId(LNode id, bool allowOf = true) { if (id.IsCall) { if (id.Name == S.Of) { if (allowOf) return (id.HasSimpleHead() || IsComplexId(id.Target, false)) && id.Args.All(a => IsComplexId(a)); return false; } else if (id.Calls(S.Dot, 2)) { return id.Args.Last.IsId && IsComplexId(id.Args[0]); } else if (id.Calls(S.Substitute, 1)) { return true; } else return false; } else return id.IsId; }
public static bool IsTargetDefinitionId(LNode id, bool allowDots) { return id.HasSimpleHead() || IsDefinitionId(id.Target, allowDots); }
internal static bool HasSimpleHeadWPA(LNode self, Pedantics p) { return((p & Pedantics.IgnoreAttributesInOddPlaces) != 0 ? self.HasSimpleHead() : self.HasSimpleHeadWithoutPAttrs()); }
public static bool IsTargetDefinitionId(LNode id, bool allowDots) { return(id.HasSimpleHead() || IsDefinitionId(id.Target, allowDots)); }
internal static bool HasSimpleHeadWPA(LNode self, Pedantics p) { return (p & Pedantics.IgnoreWeirdAttributes) != 0 ? self.HasSimpleHead() : self.HasSimpleHeadWithoutPAttrs(); }
/// <summary>Recursively applies macros in scope to <c>input</c>.</summary> /// <param name="maxExpansions">Maximum number of opportunities given /// to macros to transform a given subtree. The output of any macro is /// transformed again (as if by calling this method) with /// <c>maxExpansions = maxExpansions - 1</c> to encourage the /// expansion process to terminate eventually.</param> /// <param name="nodeQueue">The act of processing child nodes (by calling /// ApplyMacrosToChildrenOf) invalidates most members of _s including /// _s.NodeQueue. But when ApplyMacrosToList calls this method it needs /// the node queue, so this method saves _s.NodeQueue in nodeQueue before /// doing something that will destroy _s.NodeQueue. It also sets /// _s.NodeQueue = nodeQueue when it starts.</param> /// <returns>Returns a transformed tree (or null if the macros did not /// change the syntax tree at any level).</returns> /// <remarks>EnqueueSplice is used if a #splice(...) is encountered.</remarks> LNode ApplyMacros(LNode input, int maxExpansions, bool isTargetNode, bool isSingleNode, ref DList <Pair <LNode, int> > nodeQueue) { _s.NodeQueue = nodeQueue; int maxExpansionsBefore = maxExpansions; LNode resultNode = null; for (LNode curNode = input; maxExpansions > 0; curNode = resultNode) { // If #splice, expand it if (!isSingleNode && curNode.Calls(S.Splice)) { if (curNode.ArgCount == 0) { return(curNode); // #splice() } curNode = resultNode = _s.EnqueueSplice(curNode.Args, maxExpansions, maxExpansionsBefore); Debug.Assert(curNode != null); } _s.StartNextNode(curNode, maxExpansions, isTargetNode); GetApplicableMacros(curNode, _s.FoundMacros); if (_s.FoundMacros.Count == 0 && curNode.ArgCount == 0 && curNode.HasSimpleHead() && !curNode.HasAttrs) { nodeQueue = _s.NodeQueue; return(resultNode); // most common case: a boring leaf node } bool braces = curNode.Calls(S.Braces); if (braces) { _scopes.Add(null); } MacroResult result; _ancestorStack.PushLast(curNode); try { if (_s.FoundMacros.Count == 0) { nodeQueue = _s.NodeQueue; return(ApplyMacrosToChildrenOf(curNode, maxExpansions) ?? resultNode); } // USER MACROS RUN HERE! var result_ = ApplyMacrosFound(_s); if (result_ == null) { // Macro(s) had no effect (not in this iteration, anyway), // so move on to processing children. nodeQueue = _s.NodeQueue; return(_s.Preprocessed ?? ApplyMacrosToChildrenOf(curNode, maxExpansions) ?? resultNode); } result = result_.Value; } finally { _ancestorStack.PopLast(1); if (braces) { PopScope(); } } // Deal with result produced by the macro NodesReplaced++; Debug.Assert(result.NewNode != null); _s.DropRemainingNodesIfRequested(); resultNode = result.NewNode; nodeQueue = _s.NodeQueue; if ((result.Macro.Mode & MacroMode.ProcessChildrenAfter) != 0) { return(ApplyMacrosToChildrenOf(resultNode, maxExpansions - 1) ?? resultNode); } else if ((result.Macro.Mode & (MacroMode.NoReprocessing | MacroMode.ProcessChildrenBefore)) != 0) { return(resultNode); // we're done! } else if (resultNode == curNode) { // node is unchanged, so reprocessing would produce the // same result. Don't do that, just process children. return(ApplyMacrosToChildrenOf(resultNode, maxExpansions - 1) ?? resultNode); } else { // Avoid deepening the call stack like we used to do... // result2 = ApplyMacros(result.NewNode, s.MaxExpansions - 1, s.IsTarget); // if (result2 != null) result.DropRemainingNodesRequested |= _s.DropRemainingNodesRequested; // instead, iterate, changing our own parameters. maxExpansions--; Debug.Assert(isTargetNode == _s.IsTarget); } } nodeQueue = _s.NodeQueue; return(resultNode); }