public AltType(VList<LNode> classAttrs, LNode typeName, VList<LNode> baseTypes, AltType parentType) { _classAttrs = classAttrs; TypeName = typeName; BaseTypes = baseTypes; ParentType = parentType; //matchCode (TypeName) { // case $stem<$(..a)>, $stem: // _typeNameStem = stem; // _genericArgs = a; // default: // _genericArgs = new WList<LNode>(); //} { // Above matchCode expanded: LNode stem; VList<LNode> a = default(VList<LNode>); if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new VList<LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) { _typeNameStem = stem; _genericArgs = a.ToWList(); } else { _genericArgs = new WList<LNode>(); } } if (ParentType != null) { BaseTypes.Insert(0, ParentType.TypeNameWithoutAttrs); // Search for all 'where' clauses on the ParentType and make sure OUR generic args have them too. bool changed = false; for (int i = 0; i < _genericArgs.Count; i++) { var arg = _genericArgs[i]; var parentArg = ParentType._genericArgs.FirstOrDefault(a => a.IsIdNamed(arg.Name)); if (parentArg != null) { var wheres = new HashSet<LNode>(WhereTypes(arg)); int oldCount = wheres.Count; var parentWheres = WhereTypes(parentArg); foreach (var where in parentWheres) wheres.Add(where); if (wheres.Count > oldCount) { arg = arg.WithAttrs(arg.Attrs.SmartWhere(a => !a.Calls(S.Where)) .Add(LNode.Call(S.Where, LNode.List(wheres)))); _genericArgs[i] = arg; changed = true; } } } if (changed) TypeName = LNode.Call(CodeSymbols.Of, LNode.List().Add(_typeNameStem).AddRange(_genericArgs)).SetStyle(NodeStyle.Operator); } TypeNameWithoutAttrs = TypeName.Select(n => n.WithoutAttrs()); }
public AltType(RVList<LNode> typeAttrs, LNode typeName, RVList<LNode> baseTypes, AltType parentType) { _typeAttrs = typeAttrs; TypeName = typeName; BaseTypes = baseTypes; ParentType = parentType; if (ParentType != null) BaseTypes.Add(ParentType.TypeName); { LNode stem; RVList<LNode> a = default(RVList<LNode>); if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new RVList<LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) { _typeNameStem = stem; _genericArgs = a; } } }
protected override LNode DoneAttaching(LNode node, LNode parent, int indexInParent) { // Constructors are funky in EC# because EC# generalizes constructors so // you can write, for example, `this() { F(); base(); G(); }`. // Plain C# constructors like `this() : base() { G(); }`, `base(x)` // are actually stored like `this() { base(); G(); }`, where the colon // is the beginning of the Range of the constructor body and the opening // brace is the range of the Target of the method body. This makes it // difficult to get the trivia attached the way we want. For example, this // constructor: // // Foo(int x) // : base(x) // { // Bar(); // } // // Gets trivia attached like this: // // #cons(@``, Foo, #(int x), [#trivia_newline] ([#trivia_newline] @`'{}`)( // [#trivia_appendStatement] base(x), Bar())); // // This code changes the trivia to something more reasonable: // // #cons(@``, Foo, #(int x), [#trivia_newline] { base(x), Bar() }); // LNode baseCall; if (node.CallsMin(S.Braces, 1) && parent != null && parent.Calls(S.Constructor) && (baseCall = node.Args[0]).Range.StartIndex < node.Target.Range.StartIndex) { if (RemoveLeadingNewline(ref node) != null) { node = node.WithArgChanged(0, baseCall.WithoutAttrNamed(S.TriviaAppendStatement)); } LNode target = node.Target, newline_trivia; if ((newline_trivia = RemoveLeadingNewline(ref target)) != null) { node = node.WithTarget(target).PlusAttrBefore(newline_trivia); } } return(node); }
Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr) { var target = expr.Target; var args = expr.Args; var combinedSequence = LNode.List(); target = BubbleUpBlocks(target); if (target.CallsMin(__runSequence, 1)) { combinedSequence = target.Args.WithoutLast(1); expr = expr.WithTarget(target.Args.Last); } args = args.SmartSelect(arg => BubbleUpBlocks(arg)); int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__runSequence, 1)); if (lastRunSeq >= 0) { if (lastRunSeq > 0 && (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark))) { Context.Write(Severity.Error, expr, "#useVarDeclExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code may be incorrect."); } var argsW = args.ToList(); for (int i = lastRunSeq - 1; i >= 0; i--) { if (!argsW[i].CallsMin(__runSequence, 1) && !argsW[i].IsLiteral) { LNode tmpVarName, tmpVarDecl = TempVarDecl(argsW[i], out tmpVarName); argsW[i] = LNode.Call((Symbol)"#runSequence", LNode.List(tmpVarDecl, tmpVarName)); } } for (int i = 0; i <= lastRunSeq; i++) { LNode arg = argsW[i]; if (arg.CallsMin(__runSequence, 1)) { combinedSequence.AddRange(arg.Args.WithoutLast(1)); argsW[i] = arg.Args.Last; } } expr = expr.WithArgs(LNode.List(argsW)); } return(Pair.Create(combinedSequence, expr)); }
public static bool IsLinqExpression(LNode n, Pedantics p = Pedantics.Lax) { var parts = n.Args; if (n.CallsMin(S.Linq, 2) && parts[0].Calls(S.From)) { if (IsValidIntoClause(parts.Last, p)) { parts = parts.WithoutLast(1); } if (DetectSelectOrGroupBy(parts.Last) == null) { return(false); } parts = parts.WithoutLast(1); return(AreValidLinqClauses(parts, 1, p)); } return(false); }
public AltType(RVList <LNode> typeAttrs, LNode typeName, RVList <LNode> baseTypes, AltType parentType) { _typeAttrs = typeAttrs; TypeName = typeName; BaseTypes = baseTypes; ParentType = parentType; if (ParentType != null) { BaseTypes.Add(ParentType.TypeName); } { LNode stem; RVList <LNode> a = default(RVList <LNode>); if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new RVList <LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) { _typeNameStem = stem; _genericArgs = a; } } }
public AltType(VList<LNode> classAttrs, LNode typeName, VList<LNode> baseTypes, AltType parentType) { _classAttrs = classAttrs; TypeName = typeName; BaseTypes = baseTypes; ParentType = parentType; { LNode stem; VList<LNode> a = default(VList<LNode>); if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new VList<LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) { _typeNameStem = stem; _genericArgs = a.ToWList(); } else { _genericArgs = new WList<LNode>(); } } if (ParentType != null) { BaseTypes.Insert(0, ParentType.TypeNameWithoutAttrs); bool changed = false; for (int i = 0; i < _genericArgs.Count; i++) { var arg = _genericArgs[i]; var parentArg = ParentType._genericArgs.FirstOrDefault(a => a.IsIdNamed(arg.Name)); if (parentArg != null) { var wheres = new HashSet<LNode>(WhereTypes(arg)); int oldCount = wheres.Count; var parentWheres = WhereTypes(parentArg); foreach (var where in parentWheres) wheres.Add(where); if (wheres.Count > oldCount) { arg = arg.WithAttrs(arg.Attrs.Where(a => !a.Calls(S.Where)).Add(LNode.Call(S.Where, LNode.List(wheres)))); _genericArgs[i] = arg; changed = true; } } } if (changed) TypeName = LNode.Call(CodeSymbols.Of, LNode.List().Add(_typeNameStem).AddRange(_genericArgs)); } TypeNameWithoutAttrs = TypeName.Select(n => n.WithoutAttrs()); }
LNode ConvertVarDeclToRunSequence(VList <LNode> attrs, LNode varType, LNode varName, LNode initValue) { initValue = BubbleUpBlocks(initValue); varType = varType ?? F.Missing; LNode @ref; attrs = attrs.WithoutNodeNamed(S.Ref, out @ref); { LNode resultValue; VList <LNode> stmts; if (initValue.CallsMin((Symbol)"#runSequence", 1) && (resultValue = initValue.Args[initValue.Args.Count - 1]) != null) { stmts = initValue.Args.WithoutLast(1); var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, resultValue)))); return(initValue.WithArgs(stmts.Add(newVarDecl).Add(varName))); } else { var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, initValue)))); return(LNode.Call((Symbol)"#runSequence", LNode.List(newVarDecl, varName))); } } }
internal static bool IsEventDefinition(LNode node, out LNode type, out LNode name, out LNode body, Pedantics p) { // Syntax should either be // #event(EventHandler, Click, {...}), or // #event(EventHandler, #(Click, DoubleClick)), // but we can also parse // #event(EventHandler, #(Click, DoubleClick), {...}) type = name = body = null; int argCount = node.ArgCount; if (!CallsMinWPAIH(node, S.Event, 2, p) || argCount > 3) { return(false); } type = node.Args[0]; name = node.Args[1]; if (!IsComplexIdentifier(type, ICI.Default, p)) { return(false); } if (!IsComplexIdentifier(name, ICI.Default, p) && !(name.CallsMin(S.AltList, 1) && name.Args.All(a => IsComplexIdentifier(a, ICI.Default, p)))) { return(false); } if (argCount == 3) { body = node.Args[2]; return(CallsWPAIH(body, S.Braces, p) || CallsWPAIH(body, S.Forward, p)); } else { return(argCount == 2); } }
// A definition identifier has the form Name or Name!(Id,$Id,...) // where Id is a simple identifier and Name is either a simple identifier // or (if dots are allowed) a complex identifier with allowOf=false. public static bool IsDefinitionId(LNode id, bool allowDots) { var args = id.Args; if (id.CallsMin(S.Of, 1)) { if (!(allowDots ? IsComplexId(args[0], false) : args[0].IsId)) { return(false); } for (int i = 1; i < args.Count; i++) { if (!(args[i].IsId || args[i].Calls(S.Substitute, 1) && args[i].Args[0].IsId)) { return(false); } } return(true); } else { return(allowDots ? IsComplexId(id, false) : id.IsId); } }
static LNode ProcessArgContractAttributes(LNode fn, int argsIndex, CodeContractRewriter rw, bool isLambda = false) { LNode fnArgs = fn.Args[argsIndex]; if (fnArgs.CallsMin(isLambda ? S.Tuple : S.AltList, 1)) { return(fn.WithArgChanged(argsIndex, fnArgs.WithArgs(arg => { if (arg.HasAttrs) { return arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg))); } return arg; }))); } else if (isLambda) { var arg = fnArgs; if (arg.HasAttrs) { fn = fn.WithArgChanged(argsIndex, arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg)))); } } return(fn); }
/// <summary>Retrieves the "key" name component for the nameof(...) macro.</summary> /// <remarks> /// The key name component of <c>global::Foo!int.Bar!T(x)</c> (which is /// is structured <c>((((global::Foo)!int).Bar)!T)(x)</c>) is <c>Bar</c>. /// </remarks> public static LNode KeyNameComponentOf(LNode name) { // So if #of, get first arg (which cannot itself be #of), then if @`.`, get second arg. // If it's a call, note that we have to check for #of and @`.` BEFORE stripping off the args. if (name.CallsMin(S.Of, 1)) name = name.Args[0]; if (name.CallsMin(S.Dot, 1)) name = name.Args.Last; if (name.IsCall) return KeyNameComponentOf(name.Target); return name; }
void WhereClausesOpt(ref LNode name) { TokenType la0; #line 1163 "EcsParserGrammar.les" var list = new BMultiMap<Symbol,LNode>(); #line default // Line 1164: (WhereClause)* for (;;) { la0 = LA0; if (la0 == TT.ContextualKeyword) list.Add(WhereClause()); else break; } #line 1165 "EcsParserGrammar.les" if ((list.Count != 0)) { if ((!name.CallsMin(S.Of, 2))) { Error("'{0}' is not generic and cannot use 'where' clauses.", name.ToString()); } else { var tparams = name.Args.ToRWList(); for (int i = 1; i < tparams.Count; i++) { var wheres = list[TParamSymbol(tparams[i])]; tparams[i] = tparams[i].PlusAttrs(wheres); wheres.Clear(); } name = name.WithArgs(tparams.ToRVList()); if ((list.Count > 0)) { Error(list[0].Value, "There is no type parameter named '{0}'", list[0].Key); } } } #line default }
LNode EliminateSequenceExpressionsInExecStmt(LNode stmt) { { LNode block, collection, cond, init, initValue, loopVar, name, tmp_11, tmp_12, type; VList <LNode> attrs, incs, inits; if (stmt.Calls(CodeSymbols.Braces)) { return(stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, false))); } else if (stmt.CallsMin(CodeSymbols.If, 1) || stmt.Calls(CodeSymbols.UsingStmt, 2) || stmt.Calls(CodeSymbols.Lock, 2) || stmt.Calls(CodeSymbols.Switch, 2) && stmt.Args[1].Calls(CodeSymbols.Braces)) { return(ProcessBlockCallStmt(stmt, 1)); } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fixed, 2) && (init = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) { init = EliminateSequenceExpressionsInExecStmt(init); block = EliminateSequenceExpressionsInChildStmt(block); if (init.CallsMin(__numrunSequence, 1)) { return(LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(init.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.Fixed, LNode.List(init.Args.Last, block)))).SetStyle(NodeStyle.Statement)); } else { return(stmt.WithArgChanged(1, block)); } } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.While, 2) && (cond = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) { cond = BubbleUpBlocks(cond); block = EliminateSequenceExpressionsInChildStmt(block); if (cond.CallsMin(__numrunSequence, 1)) { return(LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList), LNode.Missing, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(cond.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.If, LNode.List(cond.Args.Last, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)))); } else { return(stmt.WithArgChanged(1, block)); } } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.DoWhile, 2) && (block = stmt.Args[0]) != null && (cond = stmt.Args[1]) != null) { block = EliminateSequenceExpressionsInChildStmt(block); cond = BubbleUpBlocks(cond); if (cond.CallsMin(__numrunSequence, 1)) { var continue_N = F.Id(NextTempName(Context, "continue_")); var bodyStmts = block.AsList(S.Braces); bodyStmts.AddRange(cond.Args.WithoutLast(1)); bodyStmts.Add(LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, cond.Args.Last)).SetStyle(NodeStyle.Operator)); return(LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id(CodeSymbols.Bool), LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, LNode.Literal(true))))))), continue_N, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(bodyStmts)).SetStyle(NodeStyle.Statement)))); } else { return(stmt.WithArgChanged(0, block)); } } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.For, 4) && stmt.Args[0].Calls(CodeSymbols.AltList) && (cond = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (block = stmt.Args[3]) != null) { inits = stmt.Args[0].Args; incs = stmt.Args[2].Args; return(ESEInForLoop(stmt, attrs, inits, cond, incs, block)); } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.ForEach, 3) && (tmp_11 = stmt.Args[0]) != null && tmp_11.Calls(CodeSymbols.Var, 2) && (type = tmp_11.Args[0]) != null && (loopVar = tmp_11.Args[1]) != null && (collection = stmt.Args[1]) != null && (block = stmt.Args[2]) != null) { block = EliminateSequenceExpressionsInChildStmt(block); collection = BubbleUpBlocks(collection); if (collection.CallsMin(__numrunSequence, 1)) { return(LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(collection.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.ForEach, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(type, loopVar)), collection.Args.Last, block)))).SetStyle(NodeStyle.Statement)); } else { return(stmt.WithArgChanged(stmt.Args.Count - 1, block)); } } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Var, 2) && (type = stmt.Args[0]) != null && (tmp_12 = stmt.Args[1]) != null && tmp_12.Calls(CodeSymbols.Assign, 2) && (name = tmp_12.Args[0]) != null && (initValue = tmp_12.Args[1]) != null) { var initValue_apos = BubbleUpBlocks(initValue); if (initValue_apos != initValue) { { LNode last; VList <LNode> stmts; if (initValue_apos.CallsMin((Symbol)"#runSequence", 1) && (last = initValue_apos.Args[initValue_apos.Args.Count - 1]) != null) { stmts = initValue_apos.Args.WithoutLast(1); return(LNode.Call((Symbol)"#runSequence", LNode.List().AddRange(stmts).Add(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, last))))))); } else { return(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, initValue_apos))))); } } } } else if (stmt.CallsMin(S.Try, 2)) { return(ESEInTryStmt(stmt)); } else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces)) { return(ProcessBlockCallStmt(stmt, stmt.ArgCount - 1)); } else { // Ordinary expression statement return(BubbleUpBlocks(stmt, stmtContext: true)); } } return(stmt); }
public SPResult AutoPrintMethodDefinition(Ambiguity flags) { // S.Fn, S.Delegate: #fn(#int32, Square, #(int x), { return x * x; }); if (EcsValidators.MethodDefinitionKind(_n, true, Pedantics) == null) { return(SPResult.Fail); } LNode retType = _n.Args[0], name = _n.Args[1]; LNode args = _n.Args[2]; LNode body = _n.Args[3, null]; bool isConstructor = _n.Name == S.Constructor; bool isDestructor = !isConstructor && name.Calls(S._Destruct, 1); LNode firstStmt = null; if (isConstructor && body != null && body.CallsMin(S.Braces, 1)) { // Detect ": this(...)" or ": base(...)" firstStmt = body.Args[0]; if (!CallsWPAIH(firstStmt, S.This) && !CallsWPAIH(firstStmt, S.Base)) { firstStmt = null; } } if (!AllowConstructorAmbiguity) { if (isDestructor && _spaceName == S.Fn) { // When destructor syntax is ambiguous, use prefix notation. return(SPResult.Fail); } else if (isConstructor && firstStmt == null) { // When constructor syntax is ambiguous, use prefix notation. if (name.IsIdNamed(S.This)) { if (_spaceName == S.Fn) { return(SPResult.Fail); } } else if (!name.IsIdNamed(_spaceName)) { return(SPResult.Fail); } } } // A cast operator with the structure: #fn(Foo, operator`#cast`, #(...)) // can be printed in a special format: operator Foo(...); bool isCastOperator = (name.Name == S.Cast && name.AttrNamed(S.TriviaUseOperatorKeyword) != null); var ifClause = PrintTypeAndName(isConstructor || isDestructor, isCastOperator, isConstructor && !name.IsIdNamed(S.This) ? AttrStyle.IsConstructor : AttrStyle.IsDefinition); PrintArgList(args.Args, ParenFor.MethodDecl, Ambiguity.AllowUnassignedVarDecl, OmitMissingArguments); PrintWhereClauses(name); // If this is a constructor where the first statement is this(...) or // base(...), we must change the notation to ": this(...) {...}" as // required in plain C# if (firstStmt != null) { using (Indented) { if (!Newline(NewlineOpt.BeforeConstructorColon)) { Space(SpaceOpt.BeforeConstructorColon); } WriteThenSpace(':', SpaceOpt.AfterColon); PrintExpr(firstStmt, StartExpr, Ambiguity.NoBracedBlock); } } return(AutoPrintBodyOfMethodOrProperty(body, ifClause, firstStmt != null)); }
private static void ApplyRuleOptions(ref LNode node, Rule rule, IMacroContext context) { node = node.WithAttrs(node.Attrs.WhereSelect(attr => { if (attr.ArgCount > 1) { return(attr); } LNode key = attr.Target ?? attr; object value = null; if (attr.ArgCount == 1) { value = attr.Args[0].Value; } switch (key.Name.Name) { case "fullLLk": case "FullLLk": SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.FullLLk = v); break; case "#private": case "private": SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsPrivate = v); return(attr); // keep attribute case "#public": case "#internal": case "#protected": case "public": case "internal": case "protected": // this is before macros run, and non-special names are used in LES rule.IsPrivate = false; return(attr); // keep attribute case "token": case "Token": SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsToken = v); break; case "start": case "Start": SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsStartingRule = v); break; case "#extern": case "extern": case "Extern": SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsExternal = v); break; case "#inline": case "inline": case "Inline": case "#fragment": case "fragment": SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsInline = v); break; case "k": case "K": case "LL": SetOption <int>(context, key, value, k => rule.K = k); break; case "recognizer": case "Recognizer": LNode sig = attr.Args[0, null]; if (sig != null) { // Invoke macros here so that LES code like "public fn Foo()::bool" // is transformed into a method signature. sig = context.PreProcess(sig.UnwrapBraces()); } if (sig != null && sig.CallsMin(S.Fn, 3)) { sig = sig.WithoutAttrNamed(S.TriviaAppendStatement); // prevent weird-looking output rule.MakeRecognizerVersion(sig).TryWrapperNeeded(); } else { context.Sink.Error(sig, "'recognizer' expects one parameter, a method signature."); } break; default: return(attr); } return(NoValue.Value); }).ToArray()); }
/// <summary>Given a complex name such as <c>global::Foo<int>.Bar<T></c>, /// this method identifies the base name component, which in this example /// is Bar. This is used, for example, to identify the expected name for /// a constructor based on the class name, e.g. <c>Foo<T></c> => Foo.</summary> /// <remarks>It is not verified that name is a complex identifier. There /// is no error detection but in some cases an empty name may be returned, /// e.g. for input like <c>Foo."Hello"</c>.</remarks> public static Symbol KeyNameComponentOf(LNode name) { // global::Foo<int>.Bar<T> is structured (((global::Foo)<int>).Bar)<T> // So if #of, get first arg (which cannot itself be #of), then if #dot, // get second arg. if (name.CallsMin(S.Of, 1)) name = name.Args[0]; if (name.CallsMin(S.Dot, 1)) name = name.Args.Last; return name.Name; }
public LNode EliminateSequenceExpressions(LNode stmt, bool isDeclContext) { LNode retType, name, argList, bases, body, initValue; if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null) { // Space definition: class, struct, etc. return body == null ? stmt : stmt.WithArgChanged(2, EliminateSequenceExpressions(body, true)); } else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null) { // Method definition return body == null ? stmt : stmt.WithArgChanged(3, EliminateSequenceExpressionsInLambdaExpr(body, retType)); } else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue)) { // Property definition stmt = stmt.WithArgChanged(3, body.WithArgs(part => { if (part.ArgCount == 1 && part[0].Calls(S.Braces)) part = part.WithArgChanged(0, EliminateSequenceExpressions(part[0], false)); return part; })); if (initValue != null) { var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue); if (initMethod != null) { stmt = stmt.WithArgChanged(4, initValue); return LNode.Call((Symbol) "#runSequence", LNode.List(stmt, initMethod)); } } return stmt; } else if (stmt.Calls(CodeSymbols.Braces)) { return stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, isDeclContext)); } else if (!isDeclContext) { return EliminateSequenceExpressionsInExecStmt(stmt); } else if (stmt.CallsMin(S.Var, 2)) { // Eliminate blocks from field member var results = new List<LNode> { stmt }; var vars = stmt.Args; var varType = vars[0]; for (int i = 1; i < vars.Count; i++) { var @var = vars[i]; if (@var.Calls(CodeSymbols.Assign, 2) && (name = @var.Args[0]) != null && (initValue = @var.Args[1]) != null) { var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue); if (initMethod != null) { results.Add(initMethod); vars[i] = vars[i].WithArgChanged(1, initValue); } } } if (results.Count > 1) { results[0] = stmt.WithArgs(vars); return LNode.List(results).AsLNode(__numrunSequence); } return stmt; } else return stmt; }
object AutoNodeToPred(LNode expr, Context ctx) { if (expr.CallsMin(S.Braces, 0)) return RemoveBraces(expr); return NodeToPred(expr, ctx); }
// Creates a temporary for an LValue (left side of `=`, or `ref` parameter) // e.g. f(x).Foo becomes f(x_N).Foo, and `var x_N = x` is added to `stmtSequence`, // where N is a unique integer for the temporary variable. LNode MaybeCreateTemporaryForLValue(LNode expr, ref VList<LNode> stmtSequence) { { LNode _, lhs; if (expr.Calls(CodeSymbols.Dot, 2) && (lhs = expr.Args[0]) != null || expr.CallsMin(CodeSymbols.Of, 1) && (lhs = expr.Args[0]) != null) return expr.WithArgChanged(0, MaybeCreateTemporaryForLValue(lhs, ref stmtSequence)); else if ((_ = expr) != null && !_.IsCall) return expr; else { var args = expr.Args.ToWList(); int i = 0; if (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1)) { // Consider foo[i]. We cannot always store `foo` in a temporary, as // this may change the code's behavior in case `foo` is a struct. i = 1; } for (; i < args.Count; i++) { if (!args[i].IsLiteral && !args[i].Attrs.Contains(_trivia_isTmpVar)) { LNode tmpVarName; stmtSequence.Add(TempVarDecl(Context, args[i], out tmpVarName)); args[i] = tmpVarName.PlusAttr(_trivia_isTmpVar); } } return expr.WithArgs(args.ToVList()); } } }
// Decides whether to add a "break" at the end of a switch case. internal protected static bool EndMayBeReachable(LNode stmt) { // The goal of this code is to avoid the dreaded compiler warning // "Unreachable code detected". We're conservative, to avoid a compiler // error about a missing "break". This is just a heuristic since we // don't have access to proper reachability analysis. if (stmt.CallsMin(S.Braces, 1)) { return(EndMayBeReachable(stmt.Args.Last)); } if (!stmt.HasSpecialName) { return(true); } if (stmt.Calls(S.Goto, 1)) { return(false); } else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break)) { return(false); } else if (stmt.Calls(S.Return)) { return(false); } else if (stmt.Calls(S.GotoCase, 1)) { return(false); } LNode body; if (stmt.Calls(S.If, 2)) { return(true); } else if (stmt.Calls(S.If, 3)) { return(EndMayBeReachable(stmt.Args[1]) || EndMayBeReachable(stmt.Args[2])); } else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2)) { // for a switch statement, assume it exits normally if a break // statement is the last statement of any of the cases, or if // there is no "default" case. bool beforeCase = true; bool hasDefaultCase = false; for (int i = body.ArgCount - 1; i > 0; i--) { var substmt = body.Args[i]; if (beforeCase && substmt.Calls(S.Break)) { return(true); } if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default)) { hasDefaultCase = beforeCase = true; } else { beforeCase = substmt.Calls(S.Case); } } return(hasDefaultCase == false); } else if (stmt.Calls(S.For) || stmt.Calls(S.While) || stmt.Calls(S.DoWhile)) { return(true); } else if (stmt.CallsMin(S.Try, 1)) { return(EndMayBeReachable(stmt.Args[0])); } else if (stmt.ArgCount >= 1) { Debug.Assert(stmt.HasSpecialName); return(EndMayBeReachable(stmt.Args.Last)); } return(true); }
/// <summary>Given a complex name such as <c>global::Foo<int>.Bar<T></c>, /// this method identifies the base name component, which in this example /// is Bar. This is used, for example, to identify the expected name for /// a constructor based on the class name, e.g. <c>Foo<T></c> => Foo.</summary> /// <remarks>It is not verified that name is a complex identifier. There /// is no error detection but in some cases an empty name may be returned, /// e.g. for input like <c>Foo."Hello"</c>.</remarks> public static Symbol KeyNameComponentOf(LNode name) { if (name == null) return null; // global::Foo<int>.Bar<T> is structured (global::(Foo<int>)).(Bar<T>) // so if `'.` or `'::` get second arg, then if #of, get first arg. if (name.CallsMin(S.Dot, 1) || name.Calls(S.ColonColon, 2)) name = name.Args.Last; if (name.CallsMin(S.Of, 1)) name = name.Args[0]; if (name.IsCall) return KeyNameComponentOf(name.Target); return name.Name; }
internal static bool IsEventDefinition(LNode node, out LNode type, out LNode name, out LNode body, Pedantics p) { // Syntax should either be // #event(EventHandler, Click, {...}), or // #event(EventHandler, #(Click, DoubleClick)), // but we can also parse // #event(EventHandler, #(Click, DoubleClick), {...}) type = name = body = null; int argCount = node.ArgCount; if (!CallsMinWPAIH(node, S.Event, 2, p) || argCount > 3) return false; type = node.Args[0]; name = node.Args[1]; if (!IsComplexIdentifier(type, ICI.Default, p)) return false; if (!IsComplexIdentifier(name, ICI.Default, p) && !(name.CallsMin(S.AltList, 1) && name.Args.All(a => IsComplexIdentifier(a, ICI.Default, p)))) return false; if (argCount == 3) { body = node.Args[2]; return CallsWPAIH(body, S.Braces, p) || CallsWPAIH(body, S.Forward, p); } else return argCount == 2; }
internal static bool CallsMinWPAIH(LNode self, Symbol name, int argCount, Pedantics p) { return self.CallsMin(name, argCount) && HasSimpleHeadWPA(self, p); }
// quote @{ Hope.For(777, $cash) } => F.Call(F.Dot(F.Id("Hope"), F.Id("For")), F.Literal(777), cash) // declare_symbols @@Foo @@Bar {...} (braces optional, invoke replace_code) // replace_code (IntSet.Parse($s) \with ParseSet($s), IntSet \with HashSet!int) {...} // replace_code_after ($X($Y, -1) \with $X($Y, EOF)) {...} // with Foo.Bar {...} => replace_code (.($x) \with Foo.Bar.$x) {...} // include_here "../Util/Util.les" // specialize $T \in (int, float, double) { def Square!$T(T x) { x*x; }; class Foo!($T,U) {}; } // run_macros (specialize $T \in (int, float)) (replace Xyz \with Zyx) { ... } // Bob.Hair?.Brush() // cons Point(public field X::int, public field Y::int) { } // def SetX(public X::int) { } // prop X::int (public field _x) { get; set; }; // def DoSomething(required X::string) { }; // public override def ToString()::string ==> _obj; // forward_to _obj { def ToString()::string; def GetHashCode()::int; }; // foo ??= Foo(); // x - 0.5; // x in (1, 2, 3); // $"The value is {Value,-10:C}." => string.Format("The value is {0,-10:C}", Value) // save_and_restore _foo { Foo(_foo = true); } => var tmp17 = _foo; try { Foo(_foo = true); } finally { _foo = tmp17; } /// <summary>Given a statement, this method attempts to decide if the /// immediately following statement (if any) is reachable.</summary> /// <returns>true if reachable/unsure, false if definitely unreachable.</returns> /// <remarks> /// The goal of this code is to avoid the dreaded compiler warning /// "Unreachable code detected". This is just a heuristic since we /// don't have access to proper reachability analysis. In fact, it's /// no doubt buggy. /// </remarks> public static bool NextStatementMayBeReachable(LNode stmt) { if (stmt.CallsMin(S.Braces, 1)) return NextStatementMayBeReachable(stmt.Args.Last); if (!stmt.HasSpecialName) return true; if (stmt.Calls(S.Goto, 1)) return false; else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break)) return false; else if (stmt.Calls(S.Return)) return false; else if (stmt.Calls(S.GotoCase, 1)) return false; bool isFor; LNode body; if (stmt.Calls(S.If, 2)) return true; else if (stmt.Calls(S.If, 3)) { var r1 = NextStatementMayBeReachable(stmt.Args[1]); var r2 = NextStatementMayBeReachable(stmt.Args[2]); return r1 || r2; } else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2)) { // for a switch statement, assume it exits normally if a break // statement is the last statement of any of the cases, or if // there is no "default" case. bool beforeCase = true; bool hasDefaultCase = false; foreach (var substmt in body.Args.ToFVList()) { if (beforeCase && substmt.Calls(S.Break)) return true; if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default)) hasDefaultCase = beforeCase = true; else beforeCase = substmt.Calls(S.Case); } return hasDefaultCase == false; } else if ((isFor = stmt.Calls(S.For, 4)) || stmt.Calls(S.While, 2) || stmt.Calls(S.DoWhile, 2)) { // Infinite loop? var cond = stmt.Args[isFor ? 1 : 0]; if (cond.IsIdNamed(S.Missing) || true.Equals(cond.Value)) return true; // ok, I don't know what to do return true; } else if (stmt.CallsMin(S.Try, 1)) { return NextStatementMayBeReachable(stmt.Args[0]); } else if (stmt.ArgCount >= 1) { Debug.Assert(stmt.HasSpecialName); return NextStatementMayBeReachable(stmt.Args.Last); } return true; }
// Bubbles up a call. The returned pair consists of // 1. A sequence of statements to run before the call // 2. The call with all (outer) #runSequences removed Pair<VList<LNode>, LNode> BubbleUp_GeneralCall2(LNode expr) { var target = expr.Target; var args = expr.Args; var combinedSequence = LNode.List(); // Bubbe up target target = BubbleUpBlocks(target); if (target.CallsMin(__numrunSequence, 1)) { combinedSequence = target.Args.WithoutLast(1); expr = expr.WithTarget(target.Args.Last); } // Bubble up each argument var isAssignment = EcsValidators.IsAssignmentOperator(expr.Name); if (isAssignment) { LNode lhs = BubbleUpBlocks(expr.Args[0]); LNode rhs = BubbleUpBlocks(expr.Args[1]); args = LNode.List(lhs, rhs); } else { // most common case args = args.SmartSelect(arg => BubbleUpBlocks(arg)); } int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__numrunSequence, 1)); if (lastRunSeq >= 0) { // last index of #runSequence that is not marked pure int lastRunSeqImpure = args.First(lastRunSeq + 1).LastIndexWhere(a => a.CallsMin(__numrunSequence, 1) && a.AttrNamed(_trivia_pure.Name) == null); if (lastRunSeq > 0 && (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark))) { Context.Sink.Error(target, "#useSequenceExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code will be incorrect."); } var argsW = args.ToList(); for (int i = 0; i <= lastRunSeq; i++) { LNode arg = argsW[i]; if (!arg.IsLiteral) { if (arg.CallsMin(__numrunSequence, 1)) { combinedSequence.AddRange(arg.Args.WithoutLast(1)); argsW[i] = arg = arg.Args.Last; } if (i < lastRunSeqImpure) { if (i == 0 && (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1))) { // Consider foo[#runSequence(f(), i)]. In case this appears in // an lvalue context and `foo` is a struct, we cannot store `foo` in // a temporary, as this may silently change the code's behavior. // Better to take the risk of evaluating `foo` after `f()`. } else { if (isAssignment || arg.Attrs.Any(a => a.IsIdNamed(S.Ref) || a.IsIdNamed(S.Out))) argsW[i] = MaybeCreateTemporaryForLValue(arg, ref combinedSequence); else { // Create a temporary variable to hold this argument LNode tmpVarName, tmpVarDecl = TempVarDecl(Context, arg, out tmpVarName); combinedSequence.Add(tmpVarDecl); argsW[i] = tmpVarName.PlusAttr(_trivia_isTmpVar); } } } } } expr = expr.WithArgs(LNode.List(argsW)); } return Pair.Create(combinedSequence, expr); }
// quote @{ Hope.For(777, $cash) } => F.Call(F.Dot(F.Id("Hope"), F.Id("For")), F.Literal(777), cash) // declare_symbols @@Foo @@Bar {...} (braces optional, invoke replace_code) // replace_code (IntSet.Parse($s) \with ParseSet($s), IntSet \with HashSet!int) {...} // replace_code_after ($X($Y, -1) \with $X($Y, EOF)) {...} // with Foo.Bar {...} => replace_code (.($x) \with Foo.Bar.$x) {...} // include_here "../Util/Util.les" // specialize $T \in (int, float, double) { def Square!$T(T x) { x*x; }; class Foo!($T,U) {}; } // run_macros (specialize $T \in (int, float)) (replace Xyz \with Zyx) { ... } // Bob.Hair?.Brush() // cons Point(public field X::int, public field Y::int) { } // def SetX(public X::int) { } // prop X::int (public field _x) { get; set; }; // def DoSomething(required X::string) { }; // public override def ToString()::string ==> _obj; // forward_to _obj { def ToString()::string; def GetHashCode()::int; }; // foo ??= Foo(); // x - 0.5; // x in (1, 2, 3); // $"The value is {Value,-10:C}." => string.Format("The value is {0,-10:C}", Value) // save_and_restore _foo { Foo(_foo = true); } => var tmp17 = _foo; try { Foo(_foo = true); } finally { _foo = tmp17; } /// <summary>Given a statement, this method attempts to decide if the /// immediately following statement (if any) is reachable.</summary> /// <returns>true if reachable/unsure, false if definitely unreachable.</returns> /// <remarks> /// The goal of this code is to avoid the dreaded compiler warning /// "Unreachable code detected". This is just a heuristic since we /// don't have access to proper reachability analysis. In fact, it's /// no doubt buggy. /// </remarks> public static bool NextStatementMayBeReachable(LNode stmt) { if (stmt.CallsMin(S.Braces, 1)) { return(NextStatementMayBeReachable(stmt.Args.Last)); } if (!stmt.HasSpecialName) { return(true); } if (stmt.Calls(S.Goto, 1)) { return(false); } else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break)) { return(false); } else if (stmt.Calls(S.Return)) { return(false); } else if (stmt.Calls(S.GotoCase, 1)) { return(false); } bool isFor; LNode body; if (stmt.Calls(S.If, 2)) { return(true); } else if (stmt.Calls(S.If, 3)) { var r1 = NextStatementMayBeReachable(stmt.Args[1]); var r2 = NextStatementMayBeReachable(stmt.Args[2]); return(r1 || r2); } else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2)) { // for a switch statement, assume it exits normally if a break // statement is the last statement of any of the cases, or if // there is no "default" case. bool beforeCase = true; bool hasDefaultCase = false; foreach (var substmt in body.Args.ToFVList()) { if (beforeCase && substmt.Calls(S.Break)) { return(true); } if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default)) { hasDefaultCase = beforeCase = true; } else { beforeCase = substmt.Calls(S.Case); } } return(hasDefaultCase == false); } else if ((isFor = stmt.Calls(S.For, 4)) || stmt.Calls(S.While, 2) || stmt.Calls(S.DoWhile, 2)) { // Infinite loop? var cond = stmt.Args[isFor ? 1 : 0]; if (cond.IsIdNamed(S.Missing) || true.Equals(cond.Value)) { return(true); // ok, I don't know what to do } return(true); } else if (stmt.CallsMin(S.Try, 1)) { return(NextStatementMayBeReachable(stmt.Args[0])); } else if (stmt.ArgCount >= 1) { Debug.Assert(stmt.HasSpecialName); return(NextStatementMayBeReachable(stmt.Args.Last)); } return(true); }
internal static bool CallsMinWPAIH(LNode self, Symbol name, int argCount, Pedantics p) { return(self.CallsMin(name, argCount) && HasSimpleHeadWPA(self, p)); }
// Decides whether to add a "break" at the end of a switch case. internal protected static bool EndMayBeReachable(LNode stmt) { // The goal of this code is to avoid the dreaded compiler warning // "Unreachable code detected". We're conservative, to avoid a compiler // error about a missing "break". This is just a heuristic since we // don't have access to proper reachability analysis. if (stmt.CallsMin(S.Braces, 1)) return EndMayBeReachable(stmt.Args.Last); if (!stmt.HasSpecialName) return true; if (stmt.Calls(S.Goto, 1)) return false; else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break)) return false; else if (stmt.Calls(S.Return)) return false; else if (stmt.Calls(S.GotoCase, 1)) return false; LNode body; if (stmt.Calls(S.If, 2)) return true; else if (stmt.Calls(S.If, 3)) { return EndMayBeReachable(stmt.Args[1]) || EndMayBeReachable(stmt.Args[2]); } else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2)) { // for a switch statement, assume it exits normally if a break // statement is the last statement of any of the cases, or if // there is no "default" case. bool beforeCase = true; bool hasDefaultCase = false; for (int i = body.ArgCount - 1; i > 0; i--) { var substmt = body.Args[i]; if (beforeCase && substmt.Calls(S.Break)) return true; if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default)) hasDefaultCase = beforeCase = true; else beforeCase = substmt.Calls(S.Case); } return hasDefaultCase == false; } else if (stmt.Calls(S.For) || stmt.Calls(S.While) || stmt.Calls(S.DoWhile)) { return true; } else if (stmt.CallsMin(S.Try, 1)) { return EndMayBeReachable(stmt.Args[0]); } else if (stmt.ArgCount >= 1) { Debug.Assert(stmt.HasSpecialName); return EndMayBeReachable(stmt.Args.Last); } return true; }
// Bubbles up a call. The returned pair consists of // 1. A sequence of statements to run before the call // 2. The call with all (outer) #runSequences removed Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr) { var target = expr.Target; var args = expr.Args; var combinedSequence = LNode.List(); // Bubbe up target target = BubbleUpBlocks(target); if (target.CallsMin(__numrunSequence, 1)) { combinedSequence = target.Args.WithoutLast(1); expr = expr.WithTarget(target.Args.Last); } // Bubble up each argument var isAssignment = EcsValidators.IsAssignmentOperator(expr.Name); if (isAssignment) { LNode lhs = BubbleUpBlocks(expr.Args[0]); LNode rhs = BubbleUpBlocks(expr.Args[1]); args = LNode.List(lhs, rhs); } else // most common case { args = args.SmartSelect(arg => BubbleUpBlocks(arg)); } int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__numrunSequence, 1)); if (lastRunSeq >= 0) { // last index of #runSequence that is not marked pure int lastRunSeqImpure = args.First(lastRunSeq + 1).LastIndexWhere(a => a.CallsMin(__numrunSequence, 1) && a.AttrNamed(_trivia_pure.Name) == null); if (lastRunSeq > 0 && (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark))) { Context.Sink.Error(target, "#useSequenceExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code will be incorrect."); } var argsW = args.ToList(); for (int i = 0; i <= lastRunSeq; i++) { LNode arg = argsW[i]; if (!arg.IsLiteral) { if (arg.CallsMin(__numrunSequence, 1)) { combinedSequence.AddRange(arg.Args.WithoutLast(1)); argsW[i] = arg = arg.Args.Last; } if (i < lastRunSeqImpure) { if (i == 0 && (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1))) { // Consider foo[#runSequence(f(), i)]. In case this appears in // an lvalue context and `foo` is a struct, we cannot store `foo` in // a temporary, as this may silently change the code's behavior. // Better to take the risk of evaluating `foo` after `f()`. } else { if (isAssignment || arg.Attrs.Any(a => a.IsIdNamed(S.Ref) || a.IsIdNamed(S.Out))) { argsW[i] = MaybeCreateTemporaryForLValue(arg, ref combinedSequence); } else { // Create a temporary variable to hold this argument LNode tmpVarName, tmpVarDecl = TempVarDecl(Context, arg, out tmpVarName); combinedSequence.Add(tmpVarDecl); argsW[i] = tmpVarName.PlusAttr(_trivia_isTmpVar); } } } } } expr = expr.WithArgs(LNode.List(argsW)); } return(Pair.Create(combinedSequence, expr)); }
public LNode EliminateSequenceExpressions(LNode stmt, bool isDeclContext) { LNode retType, name, argList, bases, body, initValue; if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null) { // Space definition: class, struct, etc. return(body == null ? stmt : stmt.WithArgChanged(2, EliminateSequenceExpressions(body, true))); } else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null) { // Method definition return(body == null ? stmt : stmt.WithArgChanged(3, EliminateSequenceExpressionsInLambdaExpr(body, retType))); } else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue)) { // Property definition stmt = stmt.WithArgChanged(3, body.WithArgs(part => { if (part.ArgCount == 1 && part[0].Calls(S.Braces)) { part = part.WithArgChanged(0, EliminateSequenceExpressions(part[0], false)); } return(part); })); if (initValue != null) { var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue); if (initMethod != null) { stmt = stmt.WithArgChanged(4, initValue); return(LNode.Call((Symbol)"#runSequence", LNode.List(stmt, initMethod))); } } return(stmt); } else if (stmt.Calls(CodeSymbols.Braces)) { return(stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, isDeclContext))); } else if (!isDeclContext) { return(EliminateSequenceExpressionsInExecStmt(stmt)); } else if (stmt.CallsMin(S.Var, 2)) { // Eliminate blocks from field member var results = new List <LNode> { stmt }; var vars = stmt.Args; var varType = vars[0]; for (int i = 1; i < vars.Count; i++) { var @var = vars[i]; if (@var.Calls(CodeSymbols.Assign, 2) && (name = @var.Args[0]) != null && (initValue = @var.Args[1]) != null) { var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue); if (initMethod != null) { results.Add(initMethod); vars[i] = vars[i].WithArgChanged(1, initValue); } } } if (results.Count > 1) { results[0] = stmt.WithArgs(vars); return(LNode.List(results).AsLNode(__numrunSequence)); } return(stmt); } else { return(stmt); } }
public SPResult AutoPrintSpaceDefinition(Ambiguity flags) { // Spaces: S.Struct, S.Class, S.Trait, S.Enum, S.Alias, S.Interface, S.Namespace var kind = EcsValidators.SpaceDefinitionKind(_n, Pedantics); if (kind == null) { return(SPResult.Fail); } var ifClause = GetIfClause(); int ai; var old_n = _n; if (kind == S.Alias && (ai = _n.Attrs.IndexWhere(a => a.IsIdNamed(S.FilePrivate))) > -1) { // Cause "[#filePrivate] #alias x = y;" to print as "using x = y;" _n = _n.WithAttrs(_n.Attrs.RemoveAt(ai)).WithTarget(S.UsingStmt); kind = S.UsingStmt; } G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.IsDefinition, flags, ifClause)); LNode name = _n.Args[0], bases = _n.Args[1], body = _n.Args[2, null]; WriteOperatorName(kind); _n = old_n; _out.Space(); PrintExpr(name, ContinueExpr, Ambiguity.InDefinitionName); if (bases.CallsMin(S.AltList, 1)) { Space(SpaceOpt.BeforeBaseListColon); WriteThenSpace(':', SpaceOpt.AfterColon); for (int i = 0, c = bases.ArgCount; i < c; i++) { if (i != 0) { WriteThenSpace(',', SpaceOpt.AfterComma); } PrintType(bases.Args[i], ContinueExpr); } } bool alias = name.Calls(S.Assign, 2); var name2 = name; if (name2.Calls(S.Of) || (alias && (name2 = name.Args[0]).Calls(S.Of))) { PrintWhereClauses(name2); } AutoPrintIfClause(ifClause); if (body == null) { return(SPResult.NeedSemicolon); } if (kind == S.Enum) { PrintEnumBody(body); } else { PrintBracedBlock(body, NewlineOpt.BeforeSpaceDefBrace, false, KeyNameComponentOf(name)); } return(SPResult.NeedSuffixTrivia); }
/// Eliminates run sequence(s) in a field initializer expression. /// If any are found, a method is returned to encapsulate the /// initialization code, e.g. /// expr on entry: Foo()::foo.x + foo.y /// return value: static retType fieldName_initializer() { /// var foo = Foo(); /// return foo.x + foo.y; /// } /// expr on exit: fieldName_initializer() LNode EliminateRunSeqFromInitializer(LNode retType, LNode fieldName, ref LNode expr) { expr = BubbleUpBlocks(expr); if (expr.CallsMin(__numrunSequence, 1)) { var statements = expr.Args.WithoutLast(1); var finalResult = expr.Args.Last; LNode methodName = F.Id(KeyNameComponentOf(fieldName).Name + "_initializer"); expr = LNode.Call(methodName); return LNode.Call(LNode.List(LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(retType, methodName, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(statements).Add(LNode.Call(CodeSymbols.Return, LNode.List(finalResult)))).SetStyle(NodeStyle.Statement))); } else return null; // most common case }
// A definition identifier has the form Name or Name!(Id,$Id,...) // where Id is a simple identifier and Name is either a simple identifier // or (if dots are allowed) a complex identifier with allowOf=false. public static bool IsDefinitionId(LNode id, bool allowDots) { var args = id.Args; if (id.CallsMin(S.Of, 1)) { if (!(allowDots ? IsComplexId(args[0], false) : args[0].IsId)) return false; for (int i = 1; i < args.Count; i++) if (!(args[i].IsId || args[i].Calls(S.Substitute, 1) && args[i].Args[0].IsId)) return false; return true; } else return allowDots ? IsComplexId(id, false) : id.IsId; }
LNode EliminateSequenceExpressionsInExecStmt(LNode stmt) { { LNode block, collection, cond, init, initValue, loopVar, name, tmp_11, tmp_12, type; VList<LNode> attrs, incs, inits; if (stmt.Calls(CodeSymbols.Braces)) return stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, false)); else if (stmt.CallsMin(CodeSymbols.If, 1) || stmt.Calls(CodeSymbols.UsingStmt, 2) || stmt.Calls(CodeSymbols.Lock, 2) || stmt.Calls(CodeSymbols.Switch, 2) && stmt.Args[1].Calls(CodeSymbols.Braces)) return ProcessBlockCallStmt(stmt, 1); else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fixed, 2) && (init = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) { init = EliminateSequenceExpressionsInExecStmt(init); block = EliminateSequenceExpressionsInChildStmt(block); if (init.CallsMin(__numrunSequence, 1)) { return LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(init.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.Fixed, LNode.List(init.Args.Last, block)))).SetStyle(NodeStyle.Statement); } else return stmt.WithArgChanged(1, block); } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.While, 2) && (cond = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) { cond = BubbleUpBlocks(cond); block = EliminateSequenceExpressionsInChildStmt(block); if (cond.CallsMin(__numrunSequence, 1)) { return LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList), LNode.Missing, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(cond.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.If, LNode.List(cond.Args.Last, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement))); } else return stmt.WithArgChanged(1, block); } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.DoWhile, 2) && (block = stmt.Args[0]) != null && (cond = stmt.Args[1]) != null) { block = EliminateSequenceExpressionsInChildStmt(block); cond = BubbleUpBlocks(cond); if (cond.CallsMin(__numrunSequence, 1)) { var continue_N = F.Id(NextTempName(Context, "continue_")); var bodyStmts = block.AsList(S.Braces); bodyStmts.AddRange(cond.Args.WithoutLast(1)); bodyStmts.Add(LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, cond.Args.Last)).SetStyle(NodeStyle.Operator)); return LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id(CodeSymbols.Bool), LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, LNode.Literal(true))))))), continue_N, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(bodyStmts)).SetStyle(NodeStyle.Statement))); } else return stmt.WithArgChanged(0, block); } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.For, 4) && stmt.Args[0].Calls(CodeSymbols.AltList) && (cond = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (block = stmt.Args[3]) != null) { inits = stmt.Args[0].Args; incs = stmt.Args[2].Args; return ESEInForLoop(stmt, attrs, inits, cond, incs, block); } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.ForEach, 3) && (tmp_11 = stmt.Args[0]) != null && tmp_11.Calls(CodeSymbols.Var, 2) && (type = tmp_11.Args[0]) != null && (loopVar = tmp_11.Args[1]) != null && (collection = stmt.Args[1]) != null && (block = stmt.Args[2]) != null) { block = EliminateSequenceExpressionsInChildStmt(block); collection = BubbleUpBlocks(collection); if (collection.CallsMin(__numrunSequence, 1)) { return LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(collection.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.ForEach, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(type, loopVar)), collection.Args.Last, block)))).SetStyle(NodeStyle.Statement); } else { return stmt.WithArgChanged(stmt.Args.Count - 1, block); } } else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Var, 2) && (type = stmt.Args[0]) != null && (tmp_12 = stmt.Args[1]) != null && tmp_12.Calls(CodeSymbols.Assign, 2) && (name = tmp_12.Args[0]) != null && (initValue = tmp_12.Args[1]) != null) { var initValue_apos = BubbleUpBlocks(initValue); if (initValue_apos != initValue) { { LNode last; VList<LNode> stmts; if (initValue_apos.CallsMin((Symbol) "#runSequence", 1) && (last = initValue_apos.Args[initValue_apos.Args.Count - 1]) != null) { stmts = initValue_apos.Args.WithoutLast(1); return LNode.Call((Symbol) "#runSequence", LNode.List().AddRange(stmts).Add(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, last)))))); } else return LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, initValue_apos)))); } } } else if (stmt.CallsMin(S.Try, 2)) { return ESEInTryStmt(stmt); } else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces)) { return ProcessBlockCallStmt(stmt, stmt.ArgCount - 1); } else { // Ordinary expression statement return BubbleUpBlocks(stmt, stmtContext: true); } } return stmt; }
LNode CoreName(LNode complexId) { if (complexId.IsId) return complexId; if (complexId.CallsMin(S.Of, 1)) return CoreName(complexId.Args[0]); if (complexId.CallsMin(S.Dot, 1)) return complexId.Args.Last; if (complexId.CallsMin(S.Substitute, 1)) return complexId; Debug.Fail("Not a complex identifier"); return complexId.Target; }
public LNode EliminateBlockExprs(LNode stmt, bool isDeclContext) { LNode retType, name, argList, bases, body, initValue; if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null) { return(body == null ? stmt : stmt.WithArgChanged(2, EliminateBlockExprs(body, true))); } else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null) { return(body == null ? stmt : stmt.WithArgChanged(3, EliminateBlockExprs(body, false))); } else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue)) { stmt = stmt.WithArgChanged(3, EliminateBlockExprs(body, false)); if (initValue != null) { var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue); if (initMethod != null) { stmt = stmt.WithArgChanged(4, initValue); return(LNode.Call(CodeSymbols.Splice, LNode.List(stmt, initMethod))); } } return(stmt); } else if (!isDeclContext) { return(EliminateBlockExprsInExecStmt(stmt)); } else if (stmt.CallsMin(S.Var, 2)) { var results = new List <LNode> { stmt }; var vars = stmt.Args; var varType = vars[0]; for (int i = 1; i < vars.Count; i++) { { var tmp_1 = vars[i]; if (tmp_1.Calls(CodeSymbols.Assign, 2) && (name = tmp_1.Args[0]) != null && (initValue = tmp_1.Args[1]) != null) { var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue); if (initMethod != null) { results.Add(initMethod); vars[i] = vars[i].WithArgChanged(1, initValue); } } } } if (results.Count > 1) { results[0] = stmt.WithArgs(vars); return(LNode.List(results).AsLNode(S.Splice)); } return(stmt); } else { return(stmt); } }
public AltType(VList <LNode> classAttrs, LNode typeName, VList <LNode> baseTypes, AltType parentType) { _classAttrs = classAttrs; TypeName = typeName; BaseTypes = baseTypes; ParentType = parentType; //matchCode (TypeName) { // case $stem<$(..a)>, $stem: // _typeNameStem = stem; // _genericArgs = a; // default: // _genericArgs = new WList<LNode>(); //} { // Above matchCode expanded: LNode stem; VList <LNode> a = default(VList <LNode>); if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new VList <LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) { _typeNameStem = stem; _genericArgs = a.ToWList(); } else { _genericArgs = new WList <LNode>(); } } if (ParentType != null) { BaseTypes.Insert(0, ParentType.TypeNameWithoutAttrs); // Search for all 'where' clauses on the ParentType and make sure OUR generic args have them too. bool changed = false; for (int i = 0; i < _genericArgs.Count; i++) { var arg = _genericArgs[i]; var parentArg = ParentType._genericArgs.FirstOrDefault(a => a.IsIdNamed(arg.Name)); if (parentArg != null) { var wheres = new HashSet <LNode>(WhereTypes(arg)); int oldCount = wheres.Count; var parentWheres = WhereTypes(parentArg); foreach (var where in parentWheres) { wheres.Add(where); } if (wheres.Count > oldCount) { arg = arg.WithAttrs(arg.Attrs.SmartWhere(a => !a.Calls(S.Where)) .Add(LNode.Call(S.Where, LNode.List(wheres)))); _genericArgs[i] = arg; changed = true; } } } if (changed) { TypeName = LNode.Call(CodeSymbols.Of, LNode.List().Add(_typeNameStem).AddRange(_genericArgs)).SetStyle(NodeStyle.Operator); } } TypeNameWithoutAttrs = TypeName.Select(n => n.WithoutAttrs()); }
private static void ApplyRuleOptions(ref LNode node, Rule rule, IMessageSink sink) { node = node.WithAttrs(node.Attrs.Select(attr => { switch (attr.Name.Name) { case "fullLLk": case "FullLLk": ReadOption <bool>(sink, attr, v => rule.FullLLk = v, true); break; case "#private": case "private": case "priv": case "Private": ReadOption <bool>(sink, attr, v => rule.IsPrivate = v, true); break; case "token": case "Token": ReadOption <bool>(sink, attr, v => rule.IsToken = v, true); break; case "start": case "Start": ReadOption <bool>(sink, attr, v => rule.IsStartingRule = v, true); break; case "#extern": case "extern": case "Extern": ReadOption <bool>(sink, attr, v => rule.IsExternal = v, true); break; case "#inline": case "inline": case "Inline": ReadOption <bool>(sink, attr, v => rule.IsInline = v, true); break; case "k": case "K": case "LL": ReadOption <int>(sink, attr, k => rule.K = k, null); break; case "recognizer": case "Recognizer": LNode sig = null; if (attr.ArgCount == 1) { sig = attr.Args[0]; if (sig.Calls(S.Braces, 1)) { sig = sig.Args[0]; } // TODO: we need a way to invoke all applicable macros at a particular location // e.g. "public fn Foo()::bool;" is not supported by def() alone. sig = LeMP.Prelude.Les.Macros.fn(sig, sink) ?? sig; } if (sig != null && sig.CallsMin(S.Fn, 3)) { rule.MakeRecognizerVersion(sig).TryWrapperNeeded(); } else { sink.Write(Severity.Error, sig, "'recognizer' expects one parameter, a method signature."); } break; default: return(attr); } return(null); }).WhereNotNull().ToArray()); }
public virtual LNode VisitInput(LNode stmt, IMessageSink sink) { LNode aliasSet; if ((stmt.Calls(_alias, 1) || stmt.CallsMin(S.Alias, 1)) && (aliasSet = stmt.Args[0]).Calls(S.Assign, 2)) { IEnumerable<KeyValuePair<LNode, LNode>> q; LNode alias = aliasSet.Args[0], replacement = aliasSet.Args[1], old; if (_definedAliases.TryGetValue(alias, out old)) { if (stmt.AttrNamed(S.Partial) == null || !old.Equals(replacement)) sink.Write(Severity.Warning, alias, "Redefinition of alias '{0}'", alias); } else if ((q = _definedAliases.Where(pair => replacement.Equals(pair.Value))).Any()) sink.Write(Severity.Warning, replacement, "Aliases '{0}' and '{1}' have the same replacement value", q.First().Key, alias); _definedAliases[alias] = replacement; return LNode.Call(S.Splice, RVList<LNode>.Empty); // erase alias from output } return null; }
LNode ConvertVarDeclToRunSequence(VList<LNode> attrs, LNode varType, LNode varName, LNode initValue) { initValue = BubbleUpBlocks(initValue); varType = varType ?? F.Missing; LNode @ref; attrs = attrs.WithoutNodeNamed(S.Ref, out @ref); var varName_apos = varName.PlusAttr(_trivia_isTmpVar); if (@ref != null) varName_apos = varName_apos.PlusAttr(@ref); { LNode resultValue; VList<LNode> stmts; if (initValue.CallsMin((Symbol) "#runSequence", 1) && (resultValue = initValue.Args[initValue.Args.Count - 1]) != null) { stmts = initValue.Args.WithoutLast(1); var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, resultValue)))); return initValue.WithArgs(stmts.Add(newVarDecl).Add(varName_apos)); } else { var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, initValue)))); return LNode.Call((Symbol) "#runSequence", LNode.List(newVarDecl, varName_apos)); } } }
protected override LNode DoneAttaching(LNode node, LNode parent, int indexInParent) { // Constructors are funky in EC# because EC# generalizes constructors so // you can write, for example, `this() { F(); base(); G(); }`. // Plain C# constructors like `this() : base() { G(); }`, `base(x)` // are actually stored like `this() { base(); G(); }`, where the colon // is the beginning of the Range of the constructor body and the opening // brace is the range of the Target of the method body. This makes it // difficult to get the trivia attached the way we want. For example, this // constructor: // // Foo(int x) // : base(x) // { // Bar(); // } // // Gets trivia attached like this: // // #cons(@``, Foo, #(int x), [#trivia_newline] ([#trivia_newline] @`'{}`)( // [#trivia_appendStatement] base(x), Bar())); // // This code changes the trivia to something more reasonable: // // #cons(@``, Foo, #(int x), [#trivia_newline] { base(x), Bar() }); // LNode baseCall; if (node.CallsMin(S.Braces, 1) && parent != null && parent.Calls(S.Constructor) && (baseCall = node.Args[0]).Range.StartIndex < node.Target.Range.StartIndex) { if (RemoveLeadingNewline(ref node) != null) node = node.WithArgChanged(0, baseCall.WithoutAttrNamed(S.TriviaAppendStatement)); LNode target = node.Target, newline_trivia; if ((newline_trivia = RemoveLeadingNewline(ref target)) != null) { node = node.WithTarget(target).PlusAttrBefore(newline_trivia); } } return node; }
Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr) { var target = expr.Target; var args = expr.Args; var combinedSequence = LNode.List(); target = BubbleUpBlocks(target); if (target.CallsMin(__numrunSequence, 1)) { combinedSequence = target.Args.WithoutLast(1); expr = expr.WithTarget(target.Args.Last); } var isAssignment = EcsValidators.IsAssignmentOperator(expr.Name); if (isAssignment) { LNode lhs = BubbleUpBlocks(expr.Args[0]); LNode rhs = BubbleUpBlocks(expr.Args[1]); args = LNode.List(lhs, rhs); } else { args = args.SmartSelect(arg => BubbleUpBlocks(arg)); } int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__numrunSequence, 1)); if (lastRunSeq >= 0) { int lastRunSeqImpure = args.First(lastRunSeq + 1).LastIndexWhere(a => a.CallsMin(__numrunSequence, 1) && a.AttrNamed(_trivia_pure.Name) == null); if (lastRunSeq > 0 && (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark))) { Context.Write(Severity.Error, target, "#useSequenceExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code will be incorrect."); } var argsW = args.ToList(); for (int i = 0; i <= lastRunSeq; i++) { LNode arg = argsW[i]; if (!arg.IsLiteral) { if (arg.CallsMin(__numrunSequence, 1)) { combinedSequence.AddRange(arg.Args.WithoutLast(1)); argsW[i] = arg = arg.Args.Last; } if (i < lastRunSeqImpure) { if (i == 0 && (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1))) { } else { if (isAssignment || arg.Attrs.Any(a => a.IsIdNamed(S.Ref) || a.IsIdNamed(S.Out))) { argsW[i] = MaybeCreateTemporaryForLValue(arg, ref combinedSequence); } else { LNode tmpVarName, tmpVarDecl = TempVarDecl(Context, arg, out tmpVarName); combinedSequence.Add(tmpVarDecl); argsW[i] = tmpVarName.PlusAttr(_trivia_isTmpVar); } } } } } expr = expr.WithArgs(LNode.List(argsW)); } return(Pair.Create(combinedSequence, expr)); }