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); }
// 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); } }
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); }
internal LNode GetWithFn(AdtParam part, bool isAbstract, Symbol virtualOverride, IEnumerable <AdtParam> allParts) { int totalParts = allParts.Count(); var withField = F.Id("With" + part.NameId.Name); var args = LNode.List(); foreach (AdtParam otherPart in allParts) { if (part == otherPart) { args.Add(F.Id("newValue")); } else { args.Add(otherPart.NameId); } } var attrs = new LNodeList(F.Id(S.Public)); if (isAbstract) { attrs.Add(F.Id(S.Abstract)); } if (virtualOverride != null && (!isAbstract || virtualOverride == S.Override)) { attrs.Add(F.Id(virtualOverride)); } LNode method; LNode type = part.Type; LNode retType = part.ContainingType.TypeNameWithoutAttrs; if (isAbstract) { method = LNode.Call(LNode.List(attrs), CodeSymbols.Fn, LNode.List(retType, withField, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(LNode.List(part.OriginalDecl.Attrs), CodeSymbols.Var, LNode.List(type, LNode.Id((Symbol)"newValue"))))))); } else { method = LNode.Call(LNode.List(attrs), CodeSymbols.Fn, LNode.List(retType, withField, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(LNode.List(part.OriginalDecl.Attrs), CodeSymbols.Var, LNode.List(type, LNode.Id((Symbol)"newValue"))))), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(TypeNameWithoutAttrs, LNode.List(args)))))))).SetStyle(NodeStyle.StatementBlock))); } return(method); }
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); } }
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))); } } }
/// <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())); }
static LNode GrabContractAttrs(LNode node, ref LNodeList cAttrs, ContractAppliesTo kinds = ContractAppliesTo.Both) { if (node.HasAttrs) { LNodeList cAttrs2 = cAttrs; // because lambdas cannot access cAttrs directly var r = node.WithAttrs(attr => { if ((PropertyContractInterpretation(attr) & kinds) != 0) { cAttrs2.Add(attr); return(NoValue.Value); // remove } return(attr); }); cAttrs = cAttrs2; return(r); } return(node); }
internal void ScanClassBody(LNodeList body) { foreach (var stmt in body) { int?i; { LNode altName; LNodeList attrs, childBody = default(LNodeList), parts, rest; if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fn, 3) && stmt.Args[0].IsIdNamed((Symbol)"alt") && (altName = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (parts = stmt.Args[2].Args).IsEmpty | true || (attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fn, 4) && stmt.Args[0].IsIdNamed((Symbol)"alt") && (altName = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (parts = stmt.Args[2].Args).IsEmpty | true && stmt.Args[3].Calls(CodeSymbols.Braces) && (childBody = stmt.Args[3].Args).IsEmpty | true) { LNode genericAltName = altName; if (altName.CallsMin(CodeSymbols.Of, 1)) { } else { if (_genericArgs.Count > 0) { genericAltName = LNode.Call(CodeSymbols.Of, LNode.List().Add(altName).AddRange(_genericArgs.ToVList())).SetStyle(NodeStyle.Operator); } } var child = new AltType(attrs, genericAltName, LNode.List(), this); child.AddParts(parts); child.ScanClassBody(childBody); _children.Add(child); } else if ((attrs = stmt.Attrs).IsEmpty | true && (i = attrs.FirstIndexWhere(a => a.IsIdNamed(__alt))) != null && stmt.CallsMin(CodeSymbols.Constructor, 3) && stmt.Args[1].IsIdNamed((Symbol)"#this") && stmt.Args[2].Calls(CodeSymbols.AltList) && (rest = new LNodeList(stmt.Args.Slice(3))).IsEmpty | true && rest.Count <= 1) { parts = stmt.Args[2].Args; attrs.RemoveAt(i.Value); _constructorAttrs.AddRange(attrs); if (rest.Count > 0 && rest[0].Calls(S.Braces)) { _extraConstrLogic.AddRange(rest[0].Args); } AddParts(parts); } else { _classBody.Add(stmt); } } } }
protected LNode SingleExprInside(Token group, string stmtType, bool allowUnassignedVarDecl, ref LNodeList list) { int oldCount = list.Count; list = AppendExprsInside(group, list, false, allowUnassignedVarDecl); if (list.Count != oldCount + 1) { if (list.Count <= oldCount) { LNode result = F.Id(S.Missing, group.StartIndex + 1, group.StartIndex + 1); list.Add(result); Error(result, "Missing expression inside '{0}'", stmtType); return(result); } else { Error(list[1], "There should be only one expression inside '{0}'", stmtType); list.Resize(oldCount + 1); } } return(list[0]); }
public LNodeList RulesAndStuff() { LNodeList result = default(LNodeList); // Line 176: ( Rule | HostCall | HostBlock ) switch ((TT)LA0) { case TT.At: case TT.AttrKeyword: case TT.LBrack: result.Add(Rule()); break; case TT.Id: { switch ((TT)LA(1)) { case TT.Id: case TT.LBrack: result.Add(Rule()); break; case TT.LParen: { switch ((TT)LA(3)) { case TT.At: case TT.Colon: case TT.Id: case TT.Returns: case TT.StartColon: result.Add(Rule()); break; case TT.Semicolon: result.Add(HostCall()); break; default: { // line 179 Error(0, "Expected a rule definition here (or a block of code in the host language)"); } break; } } break; case TT.At: case TT.Colon: case TT.Returns: case TT.StartColon: result.Add(Rule()); break; case TT.LBrace: result.Add(HostBlock()); break; default: { // line 179 Error(0, "Expected a rule definition here (or a block of code in the host language)"); } break; } } break; case TT.LParen: result.Add(HostCall()); break; case TT.LBrace: result.Add(HostBlock()); break; default: { // line 179 Error(0, "Expected a rule definition here (or a block of code in the host language)"); } break; } // Line 176: ( Rule | HostCall | HostBlock )* for (;;) { switch ((TT)LA0) { case TT.At: case TT.AttrKeyword: case TT.LBrack: result.Add(Rule()); break; case TT.Id: { switch ((TT)LA(1)) { case TT.Id: case TT.LBrack: result.Add(Rule()); break; case TT.LParen: { switch ((TT)LA(3)) { case TT.At: case TT.Colon: case TT.Id: case TT.Returns: case TT.StartColon: result.Add(Rule()); break; case TT.Semicolon: result.Add(HostCall()); break; default: { // line 179 Error(0, "Expected a rule definition here (or a block of code in the host language)"); } break; } } break; case TT.At: case TT.Colon: case TT.Returns: case TT.StartColon: result.Add(Rule()); break; case TT.LBrace: result.Add(HostBlock()); break; default: { // line 179 Error(0, "Expected a rule definition here (or a block of code in the host language)"); } break; } } break; case TT.LParen: result.Add(HostCall()); break; case TT.LBrace: result.Add(HostBlock()); break; case EOF: goto stop; default: { // line 179 Error(0, "Expected a rule definition here (or a block of code in the host language)"); } break; } } stop :; Skip(); return(result); }
// A sequence of expressions separated by commas OR semicolons. // The `ref endMarker` parameter tells the caller if semicolons were used. public virtual LNodeList ExprList(ref TokenType endMarker, LNodeList list = default(LNodeList)) { TT la0; LNode e = default(LNode); Token end = default(Token); // Line 1: ( / TopExpr) switch ((TT)LA0) { case EOF: case TT.Comma: case TT.RBrace: case TT.RBrack: case TT.RParen: case TT.Semicolon: { } break; default: e = TopExpr(); break; } // Line 61: ((TT.Comma|TT.Semicolon) ({..} / TopExpr))* for (;;) { la0 = (TT)LA0; if (la0 == TT.Comma || la0 == TT.Semicolon) { end = MatchAny(); e = e ?? MissingExpr(end); // line 63 list.Add(e.WithRange(e.Range.StartIndex, end.EndIndex)); // line 64 CheckEndMarker(ref endMarker, ref end); // Line 65: ({..} / TopExpr) switch ((TT)LA0) { case EOF: case TT.Comma: case TT.RBrace: case TT.RBrack: case TT.RParen: case TT.Semicolon: // line 65 e = null; break; default: e = TopExpr(); break; } } else { break; } } // line 67 if ((e != null || end.Type() == TT.Comma)) { list.Add(e ?? MissingExpr(end)); } // line 68 return(list); }
// Types of (normal) expressions: // - particles: ids, literals, (parenthesized), {braced} // - ++prefix_operators // - infix + operators // - suffix_operators++ // - Special primary expressions: // method_calls(with arguments), indexers[with indexes], generic!arguments LNode Expr(Precedence context) { TT la0; LNode e = default(LNode); Token lit_excl = default(Token); Token t = default(Token); // line 128 Precedence prec; e = PrefixExpr(context); // Line 132: greedy( &{context.CanParse(prec = InfixPrecedenceOf(LT($LI)))} (TT.Assignment|TT.BQOperator|TT.Dot|TT.NormalOp) Expr | &{context.CanParse(P.Primary)} FinishPrimaryExpr | &{context.CanParse(P.Of)} TT.Not (TT.LParen ExprList TT.RParen / Expr) | &{context.CanParse(SuffixPrecedenceOf(LT($LI)))} TT.PreOrSufOp )* for (;;) { switch ((TT)LA0) { case TT.Assignment: case TT.BQOperator: case TT.Dot: case TT.NormalOp: { if (context.CanParse(prec = InfixPrecedenceOf(LT(0)))) { // line 133 if ((!prec.CanMixWith(context))) { Error(0, "Operator '{0}' is not allowed in this context. Add parentheses to clarify the code's meaning.", LT0.Value); } t = MatchAny(); var rhs = Expr(prec); // line 138 e = F.Call(t, e, rhs, e.Range.StartIndex, rhs.Range.EndIndex, NodeStyle.Operator); } else { goto stop; } } break; case TT.LBrack: case TT.LParen: { if (context.CanParse(P.Primary)) { e = FinishPrimaryExpr(e); } else { goto stop; } } break; case TT.Not: { if (context.CanParse(P.Of)) { lit_excl = MatchAny(); // line 145 var args = new LNodeList { e }; int endIndex; // Line 146: (TT.LParen ExprList TT.RParen / Expr) la0 = (TT)LA0; if (la0 == TT.LParen) { Skip(); args = ExprList(args); var c = Match((int)TT.RParen); // line 146 endIndex = c.EndIndex; } else { var T = Expr(P.Of); // line 147 args.Add(T); endIndex = T.Range.EndIndex; } // line 149 e = F.Call(S.Of, args, e.Range.StartIndex, endIndex, lit_excl.StartIndex, lit_excl.EndIndex, NodeStyle.Operator); } else { goto stop; } } break; case TT.PreOrSufOp: { if (context.CanParse(SuffixPrecedenceOf(LT(0)))) { t = MatchAny(); // line 153 e = F.Call(ToSuffixOpName((Symbol)t.Value), e, e.Range.StartIndex, t.EndIndex, t.StartIndex, t.EndIndex, NodeStyle.Operator); } else { goto stop; } } break; default: goto stop; } } stop :; // line 155 return(e); }
private void MakeArgListTests(LNodeList patternArgs, ref LNode candidate) { // Note: at this point we can assume that the quantity of // arguments has already been checked and is not too small. Symbol varArgSym = null; LNode varArgCond = null; int i; for (i = 0; i < patternArgs.Count; i++) { MakeTestExpr(patternArgs[i], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), F.Literal(i))).SetStyle(NodeStyle.Operator), out varArgSym, out varArgCond); if (varArgSym != null) { break; } } int i2 = i + 1; for (int left = patternArgs.Count - i2; i2 < patternArgs.Count; i2++) { Symbol varArgSym2 = null; LNode varArgCond2 = null; MakeTestExpr(patternArgs[i2], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), F.Literal(left))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), out varArgSym2, out varArgCond2); if (varArgSym2 != null) { Context.Sink.Error(patternArgs[i2], "More than a single $(...varargs) variable is not supported in a single argument list."); break; } left--; } if (varArgSym != null && (varArgSym != __ || varArgCond != null)) { // Extract variable arg list LNode varArgSymId = F.Id(varArgSym); LNode grabVarArgs; if (i == 0 && patternArgs.Count == 1) { grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator); } else if (i == 0 && patternArgs.Count > 1) { var fixedArgsLit = F.Literal(patternArgs.Count - 1); grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"WithoutLast"))).SetStyle(NodeStyle.Operator), LNode.List(fixedArgsLit)))).SetStyle(NodeStyle.Operator); } else { var varArgStartLit = F.Literal(i); var fixedArgsLit = F.Literal(patternArgs.Count - 1); if (i + 1 == patternArgs.Count) { grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call((Symbol)"LNodeList", LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Slice"))).SetStyle(NodeStyle.Operator), LNode.List(varArgStartLit)))))))).SetStyle(NodeStyle.Operator); } else { grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call((Symbol)"LNodeList", LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Slice"))).SetStyle(NodeStyle.Operator), LNode.List(varArgStartLit, LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), fixedArgsLit)).SetStyle(NodeStyle.Operator))))))))).SetStyle(NodeStyle.Operator); } } // Add an extra condition on the $(...list) if requested by user if (varArgCond != null || IsMultiCase) { Tests.Add(LNode.Call(CodeSymbols.OrBits, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(grabVarArgs.PlusAttrs(LNode.List(LNode.InParensTrivia)), LNode.Id((Symbol)"IsEmpty"))).SetStyle(NodeStyle.Operator), LNode.Literal(true))).SetStyle(NodeStyle.Operator)); Tests.Add(varArgCond); } else { ThenClause.Add(grabVarArgs); } } }
public LNode Quote(LNode node) { // TODO: When quoting, ignore injected trivia (trivia with the TriviaInjected flag) if (node.Equals(LNode.InParensTrivia)) { return(LNode_InParensTrivia); } if (node.Equals(LNode.Missing)) { return(LNode_Missing); } LNodeList creationArgs = new LNodeList(); // Translate attributes (if any) var attrList = MaybeQuoteList(node.Attrs, isAttributes: true); if (attrList != null) { creationArgs.Add(attrList); } LNode result; switch (node.Kind) { case LNodeKind.Literal: // => F.Literal(value) creationArgs.Add(node.WithoutAttrs()); result = F.Call(LNode_Literal, creationArgs); break; case LNodeKind.Id: // => F.Id(string), F.Id(CodeSymbols.Name) creationArgs.Add(QuoteSymbol(node.Name)); result = F.Call(LNode_Id, creationArgs); break; default: // NodeKind.Call => F.Dot(...), F.Of(...), F.Call(...), F.Braces(...) bool preserveStyle = true; if (_doSubstitutions && node.Calls(S.Substitute, 1)) { preserveStyle = false; result = node.Args[0]; if (attrList != null) { if (result.IsCall) { result = result.InParens(); } result = F.Call(F.Dot(result, Id_PlusAttrs), attrList); } } else if (!_ignoreTrivia && node.ArgCount == 1 && node.TriviaValue != NoValue.Value && node.Target.IsId) { // LNode.Trivia(Symbol, object) result = F.Call(LNode_Trivia, QuoteSymbol(node.Name), F.Literal(node.TriviaValue)); } /*else if (node.Calls(S.Braces)) // F.Braces(...) * result = F.Call(LNode_Braces, node.Args.SmartSelect(arg => QuoteOne(arg, substitutions))); * else if (node.Calls(S.Dot) && node.ArgCount.IsInRange(1, 2)) * result = F.Call(LNode_Dot, node.Args.SmartSelect(arg => QuoteOne(arg, substitutions))); * else if (node.Calls(S.Of)) * result = F.Call(LNode_Of, node.Args.SmartSelect(arg => QuoteOne(arg, substitutions)));*/ else { // General case: F.Call(<Target>, <Args>) if (node.Target.IsId) { creationArgs.Add(QuoteSymbol(node.Name)); } else { creationArgs.Add(Quote(node.Target)); } var argList = MaybeQuoteList(node.Args); if (argList != null) { creationArgs.Add(argList); } result = F.Call(LNode_Call, creationArgs); } // Note: don't preserve prefix notation because if $op is +, // we want $op(x, y) to generate code for x + y (there is no // way to express this with infix notation.) if (preserveStyle && node.BaseStyle != NodeStyle.Default && node.BaseStyle != NodeStyle.PrefixNotation) { result = F.Call(F.Dot(result, F.Id("SetStyle")), F.Dot(F.Id("NodeStyle"), F.Id(node.BaseStyle.ToString()))); } break; } return(result); }
void GetPatternComponents(LNode pattern, out LNode propName, out LNode varBinding, out bool refExistingVar, out LNode cmpExpr, out LNode isType, out LNode inRange, out LNodeList subPatterns, out LNodeList conditions) { // Format: PropName: is DerivedClass name(...) in Range // Here's a typical pattern (case expr): // is Shape(ShapeType.Circle, ref size, Location: p is Point<int>(x, y)) // When there is an arg list, we decode its Target and return the args. // // The caller is in charge of stripping out "Property:" prefix, if any, // so the most complex pattern that this method considers is something // like `expr is Type x(subPatterns) in Range && conds` where `expr` is // a varName or $varName to deconstruct, or some expression to test for // equality. Assuming it's an equality test, the output will be // // varBinding = null // refExistingVar = false // cmpExpr = quote(expr); // isType = quote(Type); // inRange = quote(Range); // conds will have "conds" pushed to the front. // subPatterns = LNodeList.Empty; refExistingVar = pattern.AttrNamed(S.Ref) != null; propName = varBinding = cmpExpr = isType = inRange = null; // Deconstruct `PropName: pattern` (fun fact: we can't use `matchCode` // to detect a named parameter here, because if we write // `case { $propName: $subPattern; }:` it is parsed as a goto-label, // not as a named parameter.) if (pattern.Calls(S.NamedArg, 2) || pattern.Calls(S.Colon, 2)) { propName = pattern[0]; pattern = pattern[1]; } // Deconstruct `pattern && condition` (iteratively) conditions = LNodeList.Empty; while (pattern.Calls(S.And, 2)) { conditions.Add(pattern.Args.Last); pattern = pattern.Args[0]; } // deconstruct `pattern in Range` { LNode lhs; if (pattern.Calls(CodeSymbols.In, 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol)"in", 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.In, 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null) { pattern = lhs; } } // Deconstruct `PropName is Type` with optional list of subpatterns. // In LES let's accept ``PropName `is` (Type `with` (subpatterns))`` instead. LNode subpatterns = null; { LNode lhs, type; if (pattern.Calls(CodeSymbols.Is, 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.Is, 3) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null && (subpatterns = pattern.Args[2]) != null || pattern.Calls((Symbol)"is", 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.Is, 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null) { if (subpatterns == null) { // Check for syntax for LES with `with` if (type.Calls((Symbol)"with", 2) && (isType = type.Args[0]) != null && (subpatterns = type.Args[1]) != null || type.Calls(CodeSymbols.With, 2) && (isType = type.Args[0]) != null && (subpatterns = type.Args[1]) != null) { } } if (type.Calls(CodeSymbols.Var, 2) && (isType = type.Args[0]) != null && (varBinding = type.Args[1]) != null) { } else { isType = type; } if (lhs.Calls(S.Substitute, 1)) { if (varBinding != null) { _context.Sink.Error(varBinding, "match: cannot bind two variable names to one value"); } varBinding = lhs[0]; } else if (propName != null) { _context.Sink.Error(varBinding, "match: property name already set to {0}", propName.Name); if (varBinding == null) { varBinding = lhs; // assume it was intended as a variable binding } } if (type.IsIdNamed("") // is var x ) { isType = null; } } else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1)) { inRange = pattern; } else if (pattern.Calls(CodeSymbols.AltList) || pattern.Calls(CodeSymbols.Tuple)) { subpatterns = pattern; } else { if (pattern.Calls(S.Substitute, 1)) { varBinding = pattern[0]; } else { cmpExpr = pattern; } } } if (subpatterns != null) { if (subpatterns.Calls(S.Tuple) || subpatterns.Calls(S.AltList)) { subPatterns = subpatterns.Args; } else { _context.Sink.Error(subpatterns, "match: expected list of subpatterns (at '{0}')", subpatterns); } } if (cmpExpr != null) { if (cmpExpr.IsIdNamed(__)) { cmpExpr = null; } else if (refExistingVar && varBinding == null) // Treat `ref expr` as var binding { varBinding = cmpExpr; cmpExpr = null; } } if (varBinding != null) { if (varBinding.AttrNamed(S.Ref) != null) { varBinding = varBinding.WithoutAttrNamed(S.Ref); refExistingVar = true; } else if (varBinding.IsIdNamed(__)) { varBinding = null; } else if (!varBinding.IsId) { _context.Sink.Error(varBinding, "match: expected variable name (at '{0}')", varBinding); varBinding = null; } } }
public static LNode SetOrCreateMember(LNode fn, IMessageSink sink) { // Expecting #fn(Type, Name, #(args), {body}) if (fn.ArgCount < 3 || !fn.Args[2].Calls(S.AltList)) { return(null); } var args = fn.Args[2].Args; LNodeList propOrFieldDecls = LNodeList.Empty; Dictionary <Symbol, LNode> assignments = null; for (int i = 0; i < args.Count; i++) { var arg = args[i]; Symbol relevantAttribute, fieldName, paramName; LNode plainArg, propOrFieldDecl; if (DetectSetOrCreateMember(arg, out relevantAttribute, out fieldName, out paramName, out plainArg, out propOrFieldDecl)) { if (fn.ArgCount < 4) { return(Reject(sink, arg, Localize.Localized("'{0}': to set or create a field or property, the method must have a body in braces {{}}.", relevantAttribute))); } args[i] = plainArg; assignments = assignments ?? new Dictionary <Symbol, LNode>(); assignments[fieldName] = F.Id(paramName); if (propOrFieldDecl != null) { propOrFieldDecls.Add(propOrFieldDecl); } } } if (assignments != null) // if this macro has been used... { var parts = fn.Args; parts[2] = parts[2].WithArgs(args); var body = parts[3]; // Ensure the method has a normal braced body if (!body.Calls(S.Braces)) { if (parts[0].IsIdNamed(S.Void)) { body = F.Braces(body); } else { body = F.Braces(F.Call(S.Return, body)); } } // In case one constructor calls another, we have to ensure that the // assignments are inserted _after_ that call, and if the constructor // call refers to properties or fields that will be set, we must remap // those references onto parameters, e.g. // this(public int X) { base(X); } => this(int x) { base(x); X = x; } var bodyStmts = body.Args; int indexAtWhichToDoAssignments = 0; if (fn.Calls(S.Constructor)) { LNode baseCall = bodyStmts[0, LNode.Missing]; if (baseCall.Calls(S.Base) || baseCall.Calls(S.This)) { bodyStmts[0] = baseCall.ReplaceRecursive(n => { LNode param; if (n.IsId && assignments.TryGetValue(n.Name, out param)) { return(param); } return(null); }); indexAtWhichToDoAssignments = 1; } } // Insert assignment statements parts[3] = body.WithArgs(bodyStmts.InsertRange(indexAtWhichToDoAssignments, assignments.Select(p => { if (p.Key == p.Value.Name) { return(F.Call(S.Assign, F.Dot(F.@this, F.Id(p.Key)), p.Value)); } else { return(F.Call(S.Assign, F.Id(p.Key), p.Value)); } }).ToList())); // Return output code fn = fn.WithArgs(parts); if (propOrFieldDecls.IsEmpty) { return(fn); } else { propOrFieldDecls.Add(fn); return(F.Call(S.Splice, propOrFieldDecls)); } } return(null); }
public static LNodeList UseSymbolsCore(LNodeList symbolAttrs, LNodeList options, LNodeList body, IMacroContext context, bool inType) { // Decode options (TODO: invent a simpler approach) string prefix = "sy_"; var inherited = new HashSet <Symbol>(); foreach (var pair in MacroContext.GetOptions(options)) { if (pair.Key.Name.Name == "prefix" && pair.Value.IsId) { prefix = pair.Value.Name.Name; } else if (pair.Key.Name.Name == "inherit" && pair.Value.Value is Symbol) { inherited.Add((Symbol)pair.Value.Value); } else if (pair.Key.Name.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol)) { foreach (var arg in pair.Value.Args) { inherited.Add((Symbol)arg.Value); } } else { context.Sink.Warning(pair.Key, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})"); } } // Replace all symbols while collecting a list of them var symbols = new Dictionary <Symbol, LNode>(); LNodeList output = body.SmartSelect(stmt => stmt.ReplaceRecursive(n => { if (!inType && n.ArgCount == 3) { // Since we're outside any type, we must avoid creating symbol // fields. When we cross into a type then we can start making // Symbols by calling ourself recursively with inType=true var kind = EcsValidators.SpaceDefinitionKind(n); if (kind == S.Class || kind == S.Struct || kind == S.Interface || kind == S.Alias || kind == S.Trait) { var body2 = n.Args[2]; return(n.WithArgChanged(2, body2.WithArgs(UseSymbolsCore(symbolAttrs, options, body2.Args, context, true)))); } } var sym = n.Value as Symbol; if (n.IsLiteral && sym != null) { return(symbols[sym] = LNode.Id(prefix + sym.Name)); } return(null); }) ); // Return updated code with variable declaration at the top for all non-inherit symbols used. var _Symbol = F.Id("Symbol"); var vars = (from sym in symbols where !inherited.Contains(sym.Key) select F.Call(S.Assign, sym.Value, F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList(); if (vars.Count > 0) { output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars)) .WithAttrs(symbolAttrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly)))); } return(output); }