private static LNode ValidateOnStmt(LNode node, IMacroContext context, out LNodeList restOfStmts, out LNode firstArg) { var a = node.Args; LNode on_handler; restOfStmts = LNode.List(); firstArg = null; if (a.Count == 2) { firstArg = a[0]; } else if (a.Count != 1) { return(null); } if (!(on_handler = a.Last).Calls(S.Braces)) { return(null); } if (context.RemainingNodes.Count == 0) { context.Sink.Warning(node, "{0} should not be the final statement of a block.", node.Name); } restOfStmts = new LNodeList(context.RemainingNodes); context.DropRemainingNodes = true; return(on_handler); }
internal static MacroMode GetMacroMode(ref LNodeList attrs, LNode pattern) { MacroMode modes = 0; attrs = attrs.SmartWhere(attr => { if (attr.IsId && Enum.TryParse(attr.Name.Name, out MacroMode mode)) { modes |= mode; return(false); } return(true); }); if (pattern.IsLiteral) { modes |= MacroMode.MatchEveryLiteral; } else if (pattern.IsId) { modes |= MacroMode.MatchIdentifierOnly; } else if (DecodeSubstitutionExpr(pattern, out _, out _, out _) != null) { modes |= MacroMode.MatchEveryCall | MacroMode.MatchEveryIdentifier | MacroMode.MatchEveryLiteral; } else if (!pattern.Target.IsId) { modes |= MacroMode.MatchEveryCall; // custom matching code needed } return(modes); }
public LNodeList EliminateSequenceExpressions(LNodeList stmts, bool isDeclContext) { return(stmts.SmartSelectMany(stmt => { /* * // Optimization: scan find out whether this construct has any block * // expressions. If not, skip it. * hasBlockExprs = false; * stmt.ReplaceRecursive(new Func<LNode, Maybe<LNode>>(n => { * if (!hasBlockExprs) * hasBlockExprs = n.IsCall && ( * (n.Calls(S.ColonColon, 2) && n.Args[1].IsId) || * (n.Calls(S.Var, 2) && n.AttrNamed(S.Out) != null) || * (n.Calls(S.In, 2) && n.Args[1].Calls(S.Braces))); * return hasBlockExprs ? n : null; * })); * if (!hasBlockExprs) * return stmt; */ LNode result = EliminateSequenceExpressions(stmt, isDeclContext); if (result != stmt) { if (result.Calls(sy__numrunSequence)) { return result.Args; } } _arrayOf1[0] = result; return _arrayOf1; })); }
private static void DSOCM_DistributeAttributes(LNodeList attrs, ref LNode newArg, ref LNode propOrFieldDecl) { // Some word attributes like `public` and `static` move to the field // or property, as well as named parameters representing an attribute // target `field:` or `property:`; all others belong on the argument. // Example: given `[A] [field: B] public params T _arg = value`, we want // a field `[B] public T arg` and a parameter `[A] params T arg = value`. LNodeList argAttrs = LNodeList.Empty, fieldAttrs = LNodeList.Empty; foreach (var attr in attrs) { var name = attr.Name; if (attr.IsId && (FieldCreationAttributes.Contains(name) || name == S.Readonly)) { fieldAttrs.Add(attr); } else if (name == S.TriviaSLComment || name == S.TriviaNewline) { fieldAttrs.Add(attr); // Put doc comments and leading newline on the field/prop } else if (attr.Calls(S.NamedArg, 2) && (attr.Args[0].IsIdNamed("field") || attr.Args[0].IsIdNamed("property"))) { fieldAttrs.Add(attr.Args[1]); } else { argAttrs.Add(attr); } } propOrFieldDecl = propOrFieldDecl.WithAttrs(fieldAttrs); newArg = newArg.WithAttrs(argAttrs); }
/// <summary>Searches a list of expressions/statements for one or more /// patterns, and performs replacements.</summary> /// <param name="stmts">A list of expressions/statements in which to search.</param> /// <param name="patterns">Each pair consists of (A) something to search /// for and (B) a replacement expression. Part A can use the substitution /// operator with an identifier inside (e.g. $Foo) to "capture" any /// subexpression, and part B can use the same substitution (e.g. $Foo) /// to insert the captured subexpression(s) into the output.</param> /// <param name="replacementCount">Number of replacements that occurred.</param> /// <returns>The result of applying the replacements.</returns> /// <remarks><see cref="LNodeExt.MatchesPattern"/> is used for matching.</remarks> public static LNodeList Replace(LNodeList stmts, Pair <LNode, LNode>[] patterns, out int replacementCount) { // This list is used to support simple token replacement in TokenTrees _tokenTreeRepls = InternalList <Triplet <Symbol, LNode, int> > .Empty; foreach (var pair in patterns) // Look for Id => Id or Id => Literal { if (pair.A.IsId && (pair.B.IsId || pair.B.IsLiteral)) { _tokenTreeRepls.Add(new Triplet <Symbol, LNode, int>(pair.A.Name, pair.B, 0)); } } // Scan the syntax tree for things to replace... int count = 0; var temp = new MMap <Symbol, LNode>(); var output = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(n => { LNode r = TryReplaceHere(n, patterns, temp); if (r != null) { count++; } return(r); })); replacementCount = count; return(output); }
internal void AddParts(LNodeList parts) { foreach (var part in parts) { Parts.Add(new AdtParam(part, this)); } }
internal static LNodeList GetArgNamesFromFormalArgList(LNode args, Action <LNode> onError) { LNodeList formalArgs = args.Args; LNodeList argList = LNodeList.Empty; foreach (var formalArg in formalArgs) { if (!formalArg.Calls(S.Var, 2)) { onError(formalArg); } else { LNode argName = formalArg.Args[1]; if (argName.Calls(S.Assign, 2)) { argName = argName.Args[0]; } LNode @ref = formalArg.AttrNamed(S.Ref) ?? formalArg.AttrNamed(S.Out); if (@ref != null) { argName = argName.PlusAttr(@ref); } argList.Add(argName); } } return(argList); }
private static void WarnAboutMissingDollarSigns(LNodeList argList, IMacroContext context, LNode pattern, LNode replacement) { // Warn if a name appears in both pattern and replacement but uses $ in only one of the two. Dictionary <Symbol, LNode> pVars = ScanForVariables(pattern), rVars = ScanForVariables(replacement); // Also warn if it looks like all `$`s were forgotten. bool allIds = argList.Count > 0 && argList.All(n => !n.IsCall); foreach (var pair in pVars) { LNode rVar = rVars.TryGetValue(pair.Key, null); if (pair.Value.IsId) // id without `$` in pattern list { if (rVar != null && (allIds || !rVar.IsId)) { context.Sink.Warning(pair.Value, "`{0}` is written without `$`, so it may not match as intended.", pair.Value.Name); } } else // $id in pattern list { if (rVar != null && rVar.IsId) { context.Sink.Warning(rVar, "`{0}` appears in the output without `$` so replacement will not occur.", pair.Key); } } } }
/// <summary>Given the contents of case statement like `matchCode` or /// `switch`, this method gets a list of the cases.</summary> /// <returns>The first item in each pair is a list of the cases associated /// with a single handler (for `default:`, the list is empty). The second /// item is the handler code.</returns> static internal VList <Pair <LNodeList, LNodeList> > GetCases(LNodeList body, IMessageSink sink) { var pairs = VList <Pair <LNodeList, LNodeList> > .Empty; for (int i = 0; i < body.Count; i++) { bool isDefault; if (body[i].Calls(S.Lambda, 2)) { var alts = body[i][0].WithoutOuterParens().AsList(S.Tuple).SmartSelect(UnwrapBraces); pairs.Add(Pair.Create(alts, body[i][1].AsList(S.Braces))); } else if ((isDefault = IsDefaultLabel(body[i])) || body[i].CallsMin(S.Case, 1)) { var alts = isDefault ? LNodeList.Empty : body[i].Args.SmartSelect(UnwrapBraces); int bodyStart = ++i; for (; i < body.Count && !IsDefaultLabel(body[i]) && !body[i].CallsMin(S.Case, 1); i++) { } var handler = new LNodeList(body.Slice(bodyStart, i - bodyStart)); pairs.Add(Pair.Create(alts, handler)); i--; // counteract i++ when loop repeats (redo) } else { Reject(sink, body[i], "expected 'case _:' or '_ => _'"); break; } } return(pairs); }
void ProcessRequiresAttribute(LNodeList conditions, Symbol mode, LNode variableName) { // Create a "Contract.Requires()" check for each provided condition. foreach (var condition_ in conditions) { LNode condition = condition_; // make it writable so we can replace `_` LNode conditionStr; if (ReplaceContractUnderscore(ref condition, variableName)) { if (variableName == null) { Context.Sink.Error(condition, "`{0}`: underscore has no meaning in this location.", mode); } } if (mode == sy_assert) { PrependStmts.Add(LNode.Call((Symbol)"assert", LNode.List(condition))); // relies on assert() macro } else if (_haveCCRewriter) { PrependStmts.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"Requires"))).SetStyle(NodeStyle.Operator), LNode.List(condition))); } else { conditionStr = ConditionToStringLit(condition, "Precondition failed: {1}"); PrependStmts.Add(LNode.Call(GetAssertMethodForRequires(), LNode.List(condition, conditionStr))); } } }
protected void Test(string input, IParsingService inLang, string expected, IParsingService outLang, int maxExpand = 0xFFFF, IMessageSink sink = null) { MacroProcessor lemp = NewLemp(maxExpand, inLang).With(l => l.Sink = sink); var inputCode = new LNodeList(inLang.Parse(input, MessageSink.Default)); Test(inputCode, lemp, expected, outLang); }
public LNodeList StmtList() { LNodeList result = default(LNodeList); var endMarker = LT0.Type() == TT.Literal && LT0.TypeMarker == null ? TT.EOF : TT.Semicolon; result = ExprList(ref endMarker); return(result); }
protected void AppendInitializersInside(Token group, ref LNodeList list) { if (Down(group.Children)) { InitializerList(ref list); Up(); } }
protected override void WriteOutput(InputOutput io) { LNodeList results = io.Output; Output.AppendFormat("// Generated from {1} by LeMP {2}.{0}", io.OutOptions.NewlineString, io.FileName, typeof(Compiler).Assembly.GetName().Version.ToString()); io.OutPrinter.Print(results, Output, Sink, ParsingMode.File, io.OutOptions); }
public override LNode WithAttrs(LNodeList attrs) { if (attrs.Count == 0) { return(this); } return(new StdLiteralNodeWithAttrs <TValue>(attrs, _value, this)); }
protected LNodeList AppendExprsInside(Token group, LNodeList list, bool allowTrailingComma = false, bool allowUnassignedVarDecl = false) { if (Down(group.Children)) { ExprList(ref list, allowTrailingComma, allowUnassignedVarDecl); return(Up(list)); } return(list); }
public static LNodeList MaybeRemoveNoOpFromRunSeq(LNodeList runSeq) { // Delete final no-op in case of e.g. Foo()::id; => #runSequence(var id = Foo(); id) if (runSeq.Count > 1 && runSeq.Last.IsId) { return(runSeq.WithoutLast(1)); } return(runSeq); }
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, null); LNodeList results = exprMode ? LNode.List(parser.ExprStart(false)) : LNode.List(parser.ParseStmtsGreedy()); // Inject comments var injector = new EcsTriviaInjector(preprocessed.TriviaList, preprocessed.SourceFile, (int)TokenType.Newline, "/*", "*/", "//", (mode & Mode.Expression) == 0); 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; } } if (!expected.Equals(result, LNode.CompareMode.TypeMarkers)) { if ((mode & Mode.CompareAsLes) != 0) { using (LNode.SetPrinter(Syntax.Les.Les3LanguageService.Value)) AreEqual(expected.ToString(), result.ToString()); } else { AreEqual(expected, result); } Fail("{0} has a different type marker than {1}", expected, result); } } }
private static LNode RegisterSimpleMacro(LNodeList attrs, LNode pattern, LNode body, IMacroContext context) { if (DecodeSubstitutionExpr(pattern, out _, out _, out _) != null) { return(Reject(context, pattern, "Defining a macro that could match everything is not allowed.")); } MacroMode modes = GetMacroMode(ref attrs, pattern); LNode macroName = pattern.Target ?? pattern; LNode replacement = body.AsList(S.Braces).AsLNode(S.Splice); if (pattern.IsCall) { WarnAboutMissingDollarSigns(pattern.Args, context, pattern, replacement); } // Note: we could fill out the macro's Syntax and Description with the // pattern and replacement converted to strings, but it's generally a // waste of CPU time as those strings are usually not requested. // Compromise: provide syntax pattern only var syntax = pattern.ToString(); var lma = new LexicalMacroAttribute(syntax, "User-defined macro at {0}".Localized(pattern.Range.Start), macroName.Name.Name) { Mode = modes }; if ((modes & (MacroMode.MatchEveryLiteral | MacroMode.MatchEveryCall | MacroMode.MatchEveryIdentifier)) != 0) { lma = new LexicalMacroAttribute(syntax, lma.Description) { Mode = modes } } ; var macroInfo = new MacroInfo(null, lma, UserDefinedMacro); macroInfo.Mode |= MacroMode.UseLogicalNameInErrorMessages; context.RegisterMacro(macroInfo); return(F.Splice()); // delete the `define` node from the output LNode UserDefinedMacro(LNode candidate, IMacroContext context2) { MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>(); if (candidate.MatchesPattern(pattern, ref captures, out LNodeList unmatchedAttrs)) { LNode replacement2 = WithUniqueIdentifiers(replacement, context.IncrementTempCounter, out _); return(ReplaceCaptures(replacement2, captures).PlusAttrsBefore(unmatchedAttrs)); } return(null); } }
// Given Foo(x, y, a = 1, c = 2), extracts { a = 1, c = 2 } to a separate list private static LNodeList SeparateAttributeSetters(ref LNode attribute) { LNodeList setters = LNode.List(); while (attribute.Args.LastOrDefault()?.Calls(S.Assign) == true) { setters.Insert(0, attribute.Args.Last); attribute = attribute.WithArgs(attribute.Args.WithoutLast(1)); } return(setters); }
private static bool AreValidLinqClauses(LNodeList parts, int i, Pedantics p) { for (; i < parts.Count; i++) { if (LinqClauseKind(parts[i], p) == null) { return(false); } } return(true); }
private LNodeList StmtListInside(Token t) { var list = new LNodeList(); if (Down(t.Children)) { StmtList(ref list); return(Up(list)); } return(list); }
private void PrintArgList(LNodeList args, ParenFor kind, bool allowUnassignedVarDecl, bool omitMissingArguments, char separator = ',') { var keepFlags = _flags & (Ambiguity.InPattern | Ambiguity.IsPattern); using (WithFlags(keepFlags | (allowUnassignedVarDecl ? Ambiguity.AllowUnassignedVarDecl : 0))) { WriteOpenParen(kind); _out.Indent(PrinterIndentHint.Brackets); PrintArgs(args, _flags, omitMissingArguments, separator); _out.Dedent(PrinterIndentHint.Brackets); WriteCloseParen(kind); } }
internal CodeGeneratorForMatchCase(IMacroContext context, LNode input, LNodeList handler) { _context = context; _input = input; _handler = handler; var @break = LNode.Call(CodeSymbols.Break); if (_handler.IsEmpty || !_handler.Last.Equals(@break)) { _handler.Add(@break); } }
// Looks for contract attributes in a list and creates statements that // should be inserted at the beginning of the method that those attributes // are a part of. `variableName` is the name of the associated method // argument, or null if the attributes are attached to the return value or // the entire method. Returns the attribute list with contract attributes // removed. internal LNodeList Process(LNodeList attributes, LNode variableName, bool isPropSetter = false) { return(attributes.SmartWhere(attr => { LNode exceptionType = null; var mode = GetContractAttrMode(attr, out exceptionType); if (mode != null) { ProcessAttribute(attr, mode, exceptionType, variableName, isPropSetter); return false; // Remove contract attribute from method signature } return true; // No change })); }
public static LNode AddCsLineDirectives(LNode node, IMacroContext context) { if (node.ArgCount != 0) { return(null); } int sourceLine = -1; var list0 = new LNodeList(context.RemainingNodes); var list1 = context.PreProcess(list0); var list2 = AddLineDirectives(list1, true, ref sourceLine); context.DropRemainingNodes = true; return(F.Call(S.Splice, list2)); }
// Generates a class declaration for the current alt and its subtypes internal void GenerateOutput(ref LNodeList list) { bool isAbstract = _classAttrs.Any(a => a.IsIdNamed(S.Abstract)); var baseParts = new List <AdtParam>(); for (var type = ParentType; type != null; type = type.ParentType) { baseParts.InsertRange(0, type.Parts); } var allParts = baseParts.Concat(Parts); var initialization = Parts.Select(p => LNode.Call(CodeSymbols.Assign, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id(CodeSymbols.This), p.NameId)).SetStyle(NodeStyle.Operator), p.NameId)).SetStyle(NodeStyle.Operator)).ToList(); if (baseParts.Count > 0) { initialization.Insert(0, F.Call(S.Base, baseParts.Select(p => p.NameId))); } var args = new LNodeList(allParts.Select(p => p.OriginalDecl)); if (!_constructorAttrs.Any(a => a.IsIdNamed(S.Public))) { _constructorAttrs.Add(F.Id(S.Public)); } LNode constructor = LNode.Call(LNode.List(_constructorAttrs), CodeSymbols.Constructor, LNode.List(LNode.Missing, _typeNameStem, LNode.Call(CodeSymbols.AltList, LNode.List(args)), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(initialization).AddRange(_extraConstrLogic)).SetStyle(NodeStyle.StatementBlock))); var outBody = new LNodeList(); outBody.Add(constructor); outBody.AddRange(Parts.Select(p => p.GetFieldDecl())); outBody.AddRange(baseParts.Select(p => GetWithFn(p, isAbstract, S.Override, allParts))); outBody.AddRange(Parts.Select(p => GetWithFn(p, isAbstract, _children.Count > 0 ? S.Virtual : null, allParts))); outBody.AddRange(Parts.WithIndexes() .Where(kvp => kvp.Value.NameId.Name.Name != "Item" + (baseParts.Count + kvp.Key + 1)) .Select(kvp => kvp.Value.GetItemDecl(baseParts.Count + kvp.Key + 1))); outBody.AddRange(_classBody); list.Add(LNode.Call(LNode.List(_classAttrs), CodeSymbols.Class, LNode.List(TypeName, LNode.Call(CodeSymbols.AltList, LNode.List(BaseTypes)), LNode.Call(CodeSymbols.Braces, LNode.List(outBody)).SetStyle(NodeStyle.StatementBlock)))); if (_genericArgs.Count > 0 && Parts.Count > 0) { var argNames = allParts.Select(p => p.NameId); list.Add(LNode.Call(LNode.List().AddRange(_classAttrs).Add(LNode.Id(CodeSymbols.Static)).Add(LNode.Id(CodeSymbols.Partial)), CodeSymbols.Class, LNode.List(_typeNameStem, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(LNode.List(LNode.Id(CodeSymbols.Public), LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(TypeNameWithoutAttrs, LNode.Call(CodeSymbols.Of, LNode.List().Add(LNode.Id((Symbol)"New")).AddRange(_genericArgs)).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.AltList, LNode.List(args)), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(TypeNameWithoutAttrs, LNode.List(argNames)))))))).SetStyle(NodeStyle.StatementBlock))))).SetStyle(NodeStyle.StatementBlock)))); } foreach (var child in _children) { child.GenerateOutput(ref list); } }
private static LNode CompileTimeMacro(string macroName, LNode node, IMacroContext context, bool alsoRuntime, bool wantPreprocess = true) { if (node.ArgCount != 1 || !node[0].Calls(S.Braces)) { context.Error(node.Target, "{0} should have a single argument: a braced block.", macroName); return(null); } LNodeList code = node[0].Args; if (wantPreprocess) { if (context.Ancestors.Take(context.Ancestors.Count - 1).Any( n => n.Name.IsOneOf(S.Class, S.Struct, S.Enum, S.Namespace) || n.Name.IsOneOf(S.Constructor, S.Fn, S.Property, S.Var))) { context.Error(node.Target, "{0} is designed for use only at the top level of the file. It will be executed as though it is at the top level: any outer scopes will be ignored.", macroName); } code = context.PreProcess(code); } WriteHeaderCommentInSessionLog(node, context.Sink); // Remove namespace blocks (not supported by Roslyn scripting) LNode namespaceBlock = null; var codeSansNamespaces = code.RecursiveReplace(RemoveNamespaces); LNodeList?RemoveNamespaces(LNode n) { if (EcsValidators.SpaceDefinitionKind(n, out _, out _, out LNode body) == S.Namespace) { namespaceBlock = n; return(body.Args.RecursiveReplace(RemoveNamespaces)); } return(null); } if (namespaceBlock != null && wantPreprocess) { context.Warning(namespaceBlock, "The C# scripting engine does not support namespaces. They will be ignored when running at compile time."); } RunCSharpCodeWithRoslyn(node, codeSansNamespaces, context); _roslynSessionLog?.Flush(); return(alsoRuntime ? F.Splice(code) : F.Splice()); }
private void PrintArgs(LNodeList args, Ambiguity flags, bool omitMissingArguments, char separator = ',') { for (int i = 0; i < args.Count; i++) { var arg = args[i]; bool missing = omitMissingArguments && IsSimpleSymbolWPA(arg, S.Missing) && args.Count > 1; if (i != 0) { WriteThenSpace(separator, missing ? SpaceOpt.MissingAfterComma : SpaceOpt.AfterComma); } if (!missing) { PrintExpr(arg, StartExpr, flags); } } }
/// <summary>Creates the default method definition wrapped around the body /// of the rule, which was generated by the caller. Returns <see cref="Basis"/> /// with the specified new method body. If Basis is null, a simple default /// method signature is used, e.g. <c>public void R() {...}</c> where R is /// the rule name.</summary> /// <param name="methodBody">The parsing code that was generated for this rule.</param> /// <returns>A method.</returns> public virtual LNode CreateRuleMethod(Rule rule, LNodeList methodBody) { LNode method = rule.GetMethodSignature(); var parts = method.Args.ToWList(); if (parts[0].IsIdNamed(S.Missing)) { parts[0] = F.Id(rule.Name); } Debug.Assert(parts.Count == 3); if (rule.IsRecognizer) { methodBody.Add(F.Call(S.Return, F.True)); } parts.Add(F.OnNewLine(F.Braces(methodBody))); return(method.WithArgs(parts.ToLNodeList())); }