public static LNode ContractsOnMethod(LNode fn, IMacroContext context) { LNode oldFn = fn; if (fn.ArgCount >= 4) { var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context); fn = ProcessArgContractAttributes(fn, 2, rw); if (fn.Args[0].HasAttrs) { fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null))); } if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[3]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(3, body); return(fn); } } return(null); }
LNode AutoRemoveParens(LNode node) { int i = node.Attrs.IndexWithName(S.TriviaInParens); if ((i > -1)) return node.WithAttrs(node.Attrs.RemoveAt(i)); return node; }
[LexicalMacro("notnull T method(notnull T arg) {...}; T method([requires(expr)] T arg) {...}; " + "[requires(expr)] T method(...) {...}; [ensures(expr)] T method(...) {...}; " + "[ensuresOnThrow(expr)] T method(...) {...}; [ensuresOnThrow<Exception>(expr)] T method(...) {...}", "Generates Contract checks in a method.\n\n" + "- [requires(expr)] and [assert(expr)] specify an expression that must be true at the beginning of the method; assert conditions are checked in debug builds only, while \"requires\" conditions are checked in all builds. The condition can include an underscore `_` that refers to the argument that the attribute is attached to, if any.\n" + "- [ensures(expr)] and [ensuresAssert(expr)] specify an expression that must be true if-and-when the method returns normally. assert conditions are checked in debug builds only. The condition can include an underscore `_` that refers to the return value of the method.\n" + "- [ensuresFinally(expr)] specifies an expression that must be true when the method exits, whether by exception or by a normal return. This is implemented by wrapping the method in a try-finally block.\n" + "- [ensuresOnThrow(expr)] and [ensuresOnThrow<ExceptionType>(expr)] specify a condition that must be true if the method throws an exception. When #haveContractRewriter is false, underscore `_` refers to the thrown exception object; this is not available in the MS Code Contracts Rewriter.\n" + "- notnull is equivalent to [requires(_ != null)] if applied to an argument, and [ensures(_ != null)] if applied to the method as a whole.\n" + "\nAll contract attributes (except notnull) can specify multiple expressions separated by commas, to produce multiple checks, each with its own error message.", "#fn", "#cons", Mode = MacroMode.Passive | MacroMode.PriorityInternalFallback)] public static LNode ContractsOnMethod(LNode fn, IMacroContext context) { LNode fnArgs, oldFn = fn; if (fn.ArgCount >= 4) { var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context); fn = ProcessArgContractAttributes(fn, 2, rw); if (fn.Args[0].HasAttrs) { fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null))); } if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[3]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(3, body); return(fn); } } return(null); }
[LexicalMacro("([notnull] (x => ...)); ([notnull] x) => ...; ([requires(expr)] x) => ...; " + "([ensures(expr)] (x => ...)); ([ensuresOnThrow(expr)] (x => ...)); ", "Generates Contract checks in a lambda function. See the documentation of " + "ContractsOnMethod for more information about the contract attributes.", "=>", Mode = MacroMode.Passive | MacroMode.PriorityInternalFallback)] public static LNode ContractsOnLambda(LNode fn, IMacroContext context) { LNode oldFn = fn; if (fn.ArgCount == 2) { var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context); fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true); if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[1]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(1, body); return(fn); } } return(null); }
public static LNode ContractsOnLambda(LNode fn, IMacroContext context) { LNode oldFn = fn; if (fn.ArgCount == 2) { var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context); fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true); if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); } else { var body = fn.Args[1]; if (!body.Calls(S.Braces)) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(1, body); return(fn); } } return(null); }
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); }
public static LNode BackingField(LNode prop, IMessageSink sink) { LNode type, name, body; if (prop.ArgCount != 3 || !(body = prop.Args[2]).Calls(S.Braces)) return null; LNode fieldAttr = null, fieldVarAttr = null; LNode fieldName; bool autoType = false; int i; for (i = 0; i < prop.Attrs.Count; i++) { LNode attr = prop.Attrs[i]; if (attr.IsIdNamed(_field) || attr.Calls(S.Var, 2) && ((autoType = attr.Args[0].IsIdNamed(_field)) || (fieldVarAttr = attr.AttrNamed(_field)) != null && fieldVarAttr.IsId)) { fieldAttr = attr; break; } } if (fieldAttr == null) return null; LNode field = fieldAttr; type = prop.Args[0]; if (field.IsId) { name = prop.Args[1]; fieldName = F.Id(ChooseFieldName(Ecs.EcsNodePrinter.KeyNameComponentOf(name))); field = F.Call(S.Var, type, fieldName).WithAttrs(fieldAttr.Attrs); } else { fieldName = field.Args[1]; if (fieldName.Calls(S.Assign, 2)) fieldName = fieldName.Args[0]; } if (autoType) field = field.WithArgChanged(0, type); if (fieldVarAttr != null) field = field.WithoutAttrNamed(_field); LNode newBody = body.WithArgs(body.Args.SmartSelect(stmt => { var attrs = stmt.Attrs; if (stmt.IsIdNamed(S.get)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Return, fieldName))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } if (stmt.IsIdNamed(S.set)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Assign, fieldName, F.Id(S.value)))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } return stmt; })); if (newBody == body) sink.Write(Severity.Warning, fieldAttr, "The body of the property does not contain a 'get;' or 'set;' statement without a body, so no code was generated to get or set the backing field."); prop = prop.WithAttrs(prop.Attrs.RemoveAt(i)).WithArgChanged(2, newBody); return F.Call(S.Splice, new RVList<LNode>(field, prop)); }
private Pred TranslateAndPred(LNode andExpr, bool not) { var expr = andExpr.Args[0]; // Distinguish between semantic and syntactic predicates LNode subexpr = null; Pred subpred = null; if (expr.Calls(S.Braces)) { subexpr = expr.ArgCount == 1 ? expr[0] : expr; } else { subpred = NodeToPred(expr, Context.And); } LNode subexpr0 = subexpr; // Extract [Local] or [Hoist] attribute bool local = false; if (subexpr != null) { local = true; if ((subexpr = subexpr.WithoutAttrNamed(_Hoist)) != subexpr0) { local = false; } // also recognize [Local], which was not the default until v1.9.1 subexpr = subexpr.WithoutAttrNamed(_Local); } // Extract error message for Check(), if provided. string errorString = null; if (subexpr != null) { subexpr = subexpr.WithAttrs(n => { if (n.Value is string) { errorString = (string)n.Value; return(NoValue.Value); // drop attribute from output } else if (n.IsIdNamed("NoCheck")) { errorString = ""; return(NoValue.Value); } return(n); }); } return(new AndPred(expr, (object)subexpr ?? subpred, not, local) { CheckErrorMessage = errorString }); }
public static LNode AutoRemoveParens(LNode node) { int i = node.Attrs.IndexWithName(S.TriviaInParens); if (i > -1) { return(node.WithAttrs(node.Attrs.RemoveAt(i))); } return(node); }
protected LNode Attr(params LNode[] attrsAndNode) { LNode node = attrsAndNode[attrsAndNode.Length - 1]; var attrs = node.Attrs; for (int i = 0; i < attrsAndNode.Length - 1; i++) { attrs.Insert(i, attrsAndNode[i]); } return(node.WithAttrs(attrs)); }
public static LNode WithoutAttrNamed(this LNode self, Symbol name, out LNode removedAttr) { var a = self.Attrs.WithoutNodeNamed(name, out removedAttr); if (removedAttr != null) { return(self.WithAttrs(a)); } else { return(self); } }
public static LNode WithoutAttrNamed(this LNode self, Symbol name, out LNode removedAttr) { var a = self.Attrs; for (int i = 0, c = a.Count; i < c; i++) { if (a[i].Name == name) { removedAttr = a[i]; return(self.WithAttrs(a.RemoveAt(i))); } } removedAttr = null; return(self); }
private LNode StripTrivia(LNode node) { var strippedNode = node.WithAttrs( attr => attr.IsTrivia ? Maybe <LNode> .NoValue : new Maybe <LNode>(attr)); if (strippedNode.IsCall) { return(strippedNode .WithTarget(StripTrivia(strippedNode.Target)) .WithArgs(arg => new Maybe <LNode>(StripTrivia(arg)))); } else { return(strippedNode); } }
public static LNode ContractsOnMethod(LNode fn, IMacroContext context) { // Performance note: one should keep in mind that this macro usually // has no effect. It looks for contracts and usually finds none, so // we should try to search quickly. Luckily, LNode methods like // n.WithArgChanged(i,N) do not allocate a new node if the new value // equals the old value (if n[i] == N). LNode oldFn = fn; if (fn.ArgCount >= 4) { var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context); // If this thing has an argument list, scan it fn = ProcessArgContractAttributes(fn, 2, rw); // Scan attributes on return type, then attributes on the whole method if (fn.Args[0].HasAttrs) { fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null))); } if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); // this is the common case } else { var body = fn.Args[3]; if (!body.Calls(S.Braces) // Add braces in case of void LambdaMethod() => expr; ) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(3, body); return(fn); } } return(null); }
static LNode GrabContractAttrs(LNode node, ref VList <LNode> cAttrs, ContractAppliesTo kinds = ContractAppliesTo.Both) { if (node.HasAttrs) { VList <LNode> cAttrs2 = cAttrs; var r = node.WithAttrs(attr => { if ((PropertyContractInterpretation(attr) & kinds) != 0) { cAttrs2.Add(attr); return(NoValue.Value); } return(attr); }); cAttrs = cAttrs2; return(r); } return(node); }
static LNode GrabContractAttrs(LNode node, ref VList <LNode> cAttrs, ContractAppliesTo kinds = ContractAppliesTo.Both) { if (node.HasAttrs) { VList <LNode> 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); }
LNode ApplyMacrosToChildrenOf(LNode node, int maxExpansions) { if (maxExpansions <= 0) { return(null); } bool changed = false; VList <LNode> old; var newAttrs = ApplyMacrosToList(old = node.Attrs, maxExpansions, true); _s.IsAttribute = false; if (newAttrs != old) { node = node.WithAttrs(newAttrs); changed = true; } LNode target = node.Target; if (target != null && target.Kind != LNodeKind.Literal) { DList <Pair <LNode, int> > _ = null; LNode newTarget = ApplyMacros(target, maxExpansions, true, true, ref _); if (newTarget != null) { if (newTarget.Calls(S.Splice, 1)) { newTarget = newTarget.Args[0]; } node = node.WithTarget(newTarget); changed = true; } } var newArgs = ApplyMacrosToList(old = node.Args, maxExpansions, false); if (newArgs != old) { node = node.WithArgs(newArgs); changed = true; } return(changed ? node : null); }
public static LNode ContractsOnLambda(LNode fn, IMacroContext context) { // Performance note: one should keep in mind that this macro usually // has no effect. It looks for contracts and usually finds none. LNode oldFn = fn; if (fn.ArgCount == 2) { var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context); // If this thing has an argument list, scan it fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true); // Scan attributes on the lambda as a whole if (fn.HasAttrs) { fn = fn.WithAttrs(rw.Process(fn.Attrs, null)); } if (rw.PrependStmts.IsEmpty) { return(null); // this is the common case } else { var body = fn.Args[1]; if (!body.Calls(S.Braces) // Add braces in case of void LambdaMethod() => expr; ) { body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement); } body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts)); fn = fn.WithArgChanged(1, body); return(fn); } } return(null); }
LNode ApplyMacrosToChildren(LNode node, int maxExpansions) { if (maxExpansions <= 0) { return(null); } bool changed = false; RVList <LNode> old; var newAttrs = ApplyMacrosToList(old = node.Attrs, maxExpansions); if (newAttrs != old) { node = node.WithAttrs(newAttrs); changed = true; } if (!node.HasSimpleHead()) { LNode target = node.Target, newTarget = ApplyMacros(target, maxExpansions); if (newTarget != null) { if (newTarget.Calls(S.Splice, 1)) { newTarget = newTarget.Args[0]; } node = node.WithTarget(newTarget); changed = true; } } var newArgs = ApplyMacrosToList(old = node.Args, maxExpansions); if (newArgs != old) { node = node.WithArgs(newArgs); changed = true; } return(changed ? node : null); }
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()); }
protected LNode Attr(LNode attr, LNode node) { return(node.WithAttrs(node.Attrs.Insert(0, attr))); }
public static LNode BackingField(LNode prop, IMessageSink sink) { LNode type, name, body; if (prop.ArgCount != 3 || !(body = prop.Args[2]).Calls(S.Braces)) { return(null); } LNode fieldAttr = null, fieldVarAttr = null; LNode fieldName; bool autoType = false; int i; for (i = 0; i < prop.Attrs.Count; i++) { LNode attr = prop.Attrs[i]; if (attr.IsIdNamed(_field) || attr.Calls(S.Var, 2) && ((autoType = attr.Args[0].IsIdNamed(_field)) || (fieldVarAttr = attr.AttrNamed(_field)) != null && fieldVarAttr.IsId)) { fieldAttr = attr; break; } } if (fieldAttr == null) { return(null); } LNode field = fieldAttr; type = prop.Args[0]; if (field.IsId) { name = prop.Args[1]; fieldName = F.Id(ChooseFieldName(Ecs.EcsNodePrinter.KeyNameComponentOf(name))); field = F.Call(S.Var, type, fieldName).WithAttrs(fieldAttr.Attrs); } else { fieldName = field.Args[1]; if (fieldName.Calls(S.Assign, 2)) { fieldName = fieldName.Args[0]; } } if (autoType) { field = field.WithArgChanged(0, type); } if (fieldVarAttr != null) { field = field.WithoutAttrNamed(_field); } LNode newBody = body.WithArgs(body.Args.SmartSelect(stmt => { var attrs = stmt.Attrs; if (stmt.IsIdNamed(S.get)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Return, fieldName))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } if (stmt.IsIdNamed(S.set)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Assign, fieldName, F.Id(S.value)))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } return(stmt); })); if (newBody == body) { sink.Write(Severity.Warning, fieldAttr, "The body of the property does not contain a 'get;' or 'set;' statement without a body, so no code was generated to get or set the backing field."); } prop = prop.WithAttrs(prop.Attrs.RemoveAt(i)).WithArgChanged(2, newBody); return(F.Call(S.Splice, new RVList <LNode>(field, prop))); }
public static LNode BackingField(LNode prop, IMessageSink sink) { LNode propType, propName, propArgs, body; if (prop.ArgCount != 4 || !(body = prop.Args[3]).Calls(S.Braces)) return null; // Look for an attribute of the form [field], [field name] or [field Type name] LNode fieldAttr = null, fieldName; bool autoType = false; int i; for (i = 0; i < prop.Attrs.Count; i++) { LNode attr = prop.Attrs[i]; if (attr.IsIdNamed(_field)) { fieldAttr = attr; break; } else if (attr.Calls(S.Var, 2)) { LNode fieldVarAttr = null; attr = attr.WithoutAttrNamed(__field, out fieldVarAttr); if (fieldVarAttr != null && fieldVarAttr.IsId || (autoType = attr.Args[0].IsIdNamed(_field))) { fieldAttr = attr; break; } } } if (fieldAttr == null) return null; // Extract the type and name of the backing field, if specified LNode field = fieldAttr; propType = prop.Args[0]; propName = prop.Args[1]; propArgs = prop.Args[2]; if (field.IsId) { fieldName = F.Id(ChooseFieldName(Loyc.Ecs.EcsNodePrinter.KeyNameComponentOf(propName))); field = F.Call(S.Var, propType, fieldName).WithAttrs(fieldAttr.Attrs); } else { fieldName = field.Args[1]; if (fieldName.Calls(S.Assign, 2)) fieldName = fieldName.Args[0]; } if (autoType) field = field.WithArgChanged(0, propType); // Construct the new backing field, fill in the property getter and/or setter if (body.ArgCount == 0) body = body.WithArgs(LNode.Id(S.get)); LNode newBody = body.WithArgs(body.Args.SmartSelect(stmt => { var fieldAccessExpr = fieldName; if (propArgs.ArgCount > 0) { // Special case: the property has arguments, // e.g. [field List<T> L] T this[int x] { get; set; } // ==> List<T> L; T this[int x] { get { return L[x]; } set { L[x] = value; } } var argList = GetArgNamesFromFormalArgList(propArgs, formalArg => sink.Error(formalArg, "'field' macro expected a variable declaration here")); fieldAccessExpr = F.Call(S.IndexBracks, argList.Insert(0, fieldName)); } var attrs = stmt.Attrs; if (stmt.IsIdNamed(S.get)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Return, fieldAccessExpr))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } if (stmt.IsIdNamed(S.set)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Assign, fieldAccessExpr, F.Id(S.value)))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } return stmt; })); if (newBody == body) sink.Warning(fieldAttr, "The body of the property does not contain a 'get;' or 'set;' statement without a body, so no code was generated to get or set the backing field."); prop = prop.WithAttrs(prop.Attrs.RemoveAt(i)).WithArgChanged(3, newBody); prop.Style &= ~NodeStyle.OneLiner; // avoid collapsing output to one line return F.Call(S.Splice, new VList<LNode>(field, prop)); }
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; LNode body = null; VList <LNode> propOrFieldDecls = VList <LNode> .Empty; VList <LNode> setStmts = VList <LNode> .Empty; for (int i = 0; i < args.Count; i++) { var arg = args[i]; Symbol a = S.Property; Symbol fieldName = null; Symbol paramName = null; LNode plainArg = null; LNode propOrFieldDecl = null; if (arg.CallsMin(S.Property, 4)) { // #property(Type, Name<T>, {...}) var name = arg.Args[1]; fieldName = EcsNodePrinter.KeyNameComponentOf(name); paramName = ChooseArgName(fieldName); if (arg.ArgCount == 5) // initializer is Args[4] { plainArg = F.Var(arg.Args[0], F.Call(S.Assign, F.Id(paramName), arg.Args[4])); propOrFieldDecl = arg.WithArgs(arg.Args.First(4)); } else { plainArg = F.Var(arg.Args[0], paramName); propOrFieldDecl = arg; } } else { LNode type, defaultValue; if (IsVar(arg, out type, out paramName, out defaultValue)) { int a_i = 0; foreach (var attr in arg.Attrs) { if (attr.IsId) { a = attr.Name; if (a == _set || a == S.Public || a == S.Internal || a == S.Protected || a == S.Private || a == S.ProtectedIn || a == S.Static || a == S.Partial) { fieldName = paramName; paramName = ChooseArgName(fieldName); if (a == _set) { plainArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.RemoveAt(a_i)); } else { // in case of something like "[A] public params T arg = value", // assume that "= value" represents a default value, not a field // initializer, that [A] belongs on the field, except `params` // which stays on the argument. plainArg = F.Var(type, paramName, defaultValue); propOrFieldDecl = arg; if (arg.Args[1].Calls(S.Assign, 2)) { propOrFieldDecl = arg.WithArgChanged(1, arg.Args[1].Args[0]); } int i_params = arg.Attrs.IndexWithName(S.Params); if (i_params > -1) { plainArg = plainArg.PlusAttr(arg.Attrs[i_params]); propOrFieldDecl = propOrFieldDecl.WithAttrs(propOrFieldDecl.Attrs.RemoveAt(i_params)); } } break; } } a_i++; } } } if (plainArg != null) { if (body == null) { if (fn.ArgCount < 4 || !fn.Args[3].Calls(S.Braces)) { return(Reject(sink, arg, Localize.Localized("'{0}': to set or create a field or property, the method must have a body in braces {{}}.", a))); } body = fn.Args[3]; } args[i] = plainArg; LNode assignment; if (fieldName == paramName) { assignment = F.Call(S.Assign, F.Dot(F.@this, F.Id(fieldName)), F.Id(paramName)); } else { assignment = F.Call(S.Assign, F.Id(fieldName), F.Id(paramName)); } setStmts.Add(assignment); if (propOrFieldDecl != null) { propOrFieldDecls.Add(propOrFieldDecl); } } } if (body != null) // if this macro has been used... { var parts = fn.Args; parts[2] = parts[2].WithArgs(args); parts[3] = body.WithArgs(body.Args.InsertRange(0, setStmts)); fn = fn.WithArgs(parts); if (propOrFieldDecls.IsEmpty) { return(fn); } else { propOrFieldDecls.Add(fn); return(F.Call(S.Splice, propOrFieldDecls)); } } return(null); }
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()); }
private void InjectTriviaInChildren(LNode parent, out SourceRange triviaRange, out Maybe <Trivia> trivia, int indexInParent, ref LNode node) { // Current trivia's range is within node's range: Apply it to // the node's children, if any. First gather list of children // and sort by source-code order, if necessary: int min = node.Min; InternalList <Pair <LNode, int> > children = InternalList <Pair <LNode, int> > .Empty; children.Resize(node.Max - min + 1); bool inOrder = true; int start, prevStart = int.MinValue; for (int i = 0; i < children.Count; i++, prevStart = start) { children[i] = Pair.Create(node[i + min], i + min); start = children[i].A.Range.StartIndex; if (prevStart > start) { inOrder = false; } } if (!inOrder) { children.Sort((a, b) => a.Item1.Range.StartIndex.CompareTo(b.Item1.Range.StartIndex)); } // Call ourself recursively to apply trivia to children. Usually, // newChildren is the same length as children, but it may have extra // trivia attributes added. InternalList <Pair <LNode, int> > newChildren = new InternalList <Pair <LNode, int> >(children.Count); var output = RunCore(children.GetEnumerator(), node); bool changed = false; while (output.MoveNext()) { var @new = output.Current; newChildren.Add(@new); if (@new.Item1 != children[@new.Item2 - min].Item1) { changed = true; } } // At the end, gather up any remaining trivia in the node's range that wasn't // associated with a child. // // A newline is treated specially here, because sometimes (e.g. in LES3 token // lists) a newline can be reified into its own node but also exist in the trivia // list. In this case, node will be something like `'\n` when triviaRange equals // node.Range. So let's say the node stream is something like Ann, `'\n`, Bob. If // we attach the newline to the `'\n` node as usual (using the // TriviaLocation.Ambiguous attachment mode, since the newline is neither leading // nor trailing), the output node list will be something rather complicated: // Ann, @`%appendStatement` @(`%trailing`(`%newline`)) `'\n`, @`%appendStatement` Bob // If we ignore the newline temporarily so that it gets treated as leading trivia // of Bob instead, we get simpler output: // Ann, @`%appendStatement` `'\n`, Bob InternalList <Trivia> triviaList = InternalList <Trivia> .Empty; trivia = CurrentTrivia(out triviaRange); while (trivia.HasValue && triviaRange.EndIndex <= node.Range.EndIndex && !(IsNewline(trivia.Value) && triviaRange == node.Range)) { triviaList.Add(trivia.Value); trivia = AdvanceTrivia(out triviaRange); changed = true; } if (changed) { // If this is a call, attach any remaining trivia to the last child. if (node.IsCall && !triviaList.IsEmpty) { int i = newChildren.Count - 1; var last = newChildren.InternalArray[i]; newChildren.InternalArray[i].A = AttachTriviaTo(last.A, triviaList, TriviaLocation.TrailingExtra, node, last.B) ?? last.A; } // Put the children back in their "conceptual" order if (!inOrder) { newChildren.StableSort((a, b) => a.Item2.CompareTo(b.Item2)); } // Update node's attributes, if any int numAttrs = newChildren.TakeWhile(p => p.B < -1).Count(); if (numAttrs > 0) { var attrs = LNode.List(newChildren.Slice(0, numAttrs).SelectArray(p => p.A)); node = node.WithAttrs(attrs); } if (node.IsCall) { Debug.Assert(newChildren[numAttrs].B == -1); var newArgs = newChildren.Slice(numAttrs + 1).SelectArray(p => p.A); node = node.With(newChildren[numAttrs].A, LNode.List(newArgs)); } else if (!triviaList.IsEmpty) { // If current node is not a call, attach any remaining trivia to it. node = AttachTriviaTo(node, triviaList, TriviaLocation.Ambiguous, parent, indexInParent); } } }
private static void DSOCM_DistributeAttributes(VList<LNode> 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`. VList<LNode> argAttrs = VList<LNode>.Empty, fieldAttrs = VList<LNode>.Empty; foreach (var attr in attrs) { var name = attr.Name; if (attr.IsId && (FieldCreationAttributes.Contains(name) || name == S.Readonly)) fieldAttrs.Add(attr); 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); }
public static LNode WithoutAttr(this LNode self, LNode node) { return(self.WithAttrs(self.Attrs.Without(node))); }
private static bool DetectSetOrCreateMember(LNode arg, out Symbol relevantAttribute, out Symbol fieldName, out Symbol paramName, out LNode plainArg, out LNode propOrFieldDecl) { relevantAttribute = null; fieldName = null; paramName = null; plainArg = null; propOrFieldDecl = null; LNode _, type, name, defaultValue, propArgs; if (EcsValidators.IsPropertyDefinition(arg, out type, out name, out propArgs, out _, out defaultValue) && propArgs.ArgCount == 0) { // #property(Type, Name<T>, {...}) relevantAttribute = S.Property; fieldName = EcsNodePrinter.KeyNameComponentOf(name); paramName = ChooseArgName(fieldName); if (defaultValue != null) // initializer is Args[4] { plainArg = F.Var(type, paramName, defaultValue); propOrFieldDecl = arg.WithArgs(arg.Args.First(4)); } else { plainArg = F.Var(type, paramName); propOrFieldDecl = arg; } return(true); } else if (IsVar(arg, out type, out paramName, out defaultValue)) { int a_i = 0; foreach (var attr in arg.Attrs) { if (attr.IsId) { var a = attr.Name; if (a == _set || a == S.Public || a == S.Internal || a == S.Protected || a == S.Private || a == S.ProtectedIn || a == S.Static || a == S.Partial) { relevantAttribute = a; fieldName = paramName; paramName = ChooseArgName(fieldName); if (a == _set) { plainArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.Without(attr)); } else { // in case of something like "[A] public params T arg = value", // assume that "= value" represents a default value, not a field // initializer, that [A] belongs on the field, except `params` // which stays on the argument. plainArg = F.Var(type, paramName, defaultValue); propOrFieldDecl = arg; if (arg.Args[1].Calls(S.Assign, 2)) { propOrFieldDecl = arg.WithArgChanged(1, arg.Args[1].Args[0]); } int i_params = arg.Attrs.IndexWithName(S.Params); if (i_params > -1) { plainArg = plainArg.PlusAttr(arg.Attrs[i_params]); propOrFieldDecl = propOrFieldDecl.WithAttrs(propOrFieldDecl.Attrs.RemoveAt(i_params)); } } break; } } a_i++; } return(plainArg != null); } return(false); }
private void InjectTriviaInChildren(LNode parent, out SourceRange triviaRange, out Maybe <Trivia> trivia, int indexInParent, ref LNode node) { // Current trivia's range is within node's range: Apply it to // the node's children, if any. First gather list of children // and sort by source-code order, if necessary: int min = node.Min; InternalList <Pair <LNode, int> > children = InternalList <Pair <LNode, int> > .Empty; children.Resize(node.Max - min + 1); bool inOrder = true; int start, prevStart = int.MinValue; for (int i = 0; i < children.Count; i++, prevStart = start) { children[i] = Pair.Create(node[i + min], i + min); start = children[i].A.Range.StartIndex; if (prevStart > start) { inOrder = false; } } if (!inOrder) { children.Sort((a, b) => a.Item1.Range.StartIndex.CompareTo(b.Item1.Range.StartIndex)); } // Call ourself recursively to apply trivia to children. Usually, // newChildren is the same length as children, but it may have extra // trivia attributes added. InternalList <Pair <LNode, int> > newChildren = new InternalList <Pair <LNode, int> >(children.Count); var output = RunCore(children.GetEnumerator(), node); bool changed = false; while (output.MoveNext()) { var @new = output.Current; newChildren.Add(@new); if (@new.Item1 != children[@new.Item2 - min].Item1) { changed = true; } } // At the end, gather up any remaining trivia InternalList <Trivia> triviaList = InternalList <Trivia> .Empty; trivia = CurrentTrivia(out triviaRange); while (trivia.HasValue && triviaRange.EndIndex <= node.Range.EndIndex) { triviaList.Add(trivia.Value); trivia = AdvanceTrivia(out triviaRange); changed = true; } if (changed) { // If this is a call, attach any remaining trivia to the last child. if (node.IsCall && !triviaList.IsEmpty) { int i = newChildren.Count - 1; var last = newChildren.InternalArray[i]; newChildren.InternalArray[i].A = AttachTriviaTo(last.A, triviaList, TriviaLocation.TrailingExtra, node, last.B) ?? last.A; } // Put the children back in their "conceptual" order if (!inOrder) { newChildren.StableSort((a, b) => a.Item2.CompareTo(b.Item2)); } // Update node's attributes, if any int numAttrs = newChildren.TakeWhile(p => p.B < -1).Count(); if (numAttrs > 0) { var attrs = LNode.List(newChildren.Slice(0, numAttrs).SelectArray(p => p.A)); node = node.WithAttrs(attrs); } if (node.IsCall) { Debug.Assert(newChildren[numAttrs].B == -1); var newArgs = newChildren.Slice(numAttrs + 1).SelectArray(p => p.A); node = node.With(newChildren[numAttrs].A, LNode.List(newArgs)); } else if (!triviaList.IsEmpty) { // If current node is not a call, attach any remaining trivia to it. node = AttachTriviaTo(node, triviaList, TriviaLocation.Ambiguous, parent, indexInParent); } } }
/// <summary>Adds additional trailing trivia to a node.</summary> public static LNode PlusTrailingTrivia(this LNode node, LNode trivia) { return(node.WithAttrs(PlusTrailingTrivia(node.Attrs, trivia))); }
/// <summary>Removes a node's trailing trivia and adds a new list of trailing trivia.</summary> public static LNode WithTrailingTrivia(this LNode node, LNodeList trivia) { return(node.WithAttrs(WithTrailingTrivia(node.Attrs, trivia))); }
protected LNode Attr(LNode attr, LNode node) { return node.WithAttrs(node.Attrs.Insert(0, attr)); }
public static LNode BackingField(LNode prop, IMessageSink sink) { LNode propType, propName, propArgs, body; if (prop.ArgCount != 4 || !(body = prop.Args[3]).Calls(S.Braces)) { return(null); } // Look for an attribute of the form [field], [field name] or [field Type name] LNode fieldAttr = null, fieldName; bool autoType = false; int i; for (i = 0; i < prop.Attrs.Count; i++) { LNode attr = prop.Attrs[i]; if (attr.IsIdNamed(_field)) { fieldAttr = attr; break; } else if (attr.Calls(S.Var, 2)) { LNode fieldVarAttr = null; attr = attr.WithoutAttrNamed(__field, out fieldVarAttr); if (fieldVarAttr != null && fieldVarAttr.IsId || (autoType = attr.Args[0].IsIdNamed(_field))) { fieldAttr = attr; break; } } } if (fieldAttr == null) { return(null); } // Extract the type and name of the backing field, if specified LNode field = fieldAttr; propType = prop.Args[0]; propName = prop.Args[1]; propArgs = prop.Args[2]; if (field.IsId) { fieldName = F.Id(ChooseFieldName(Loyc.Ecs.EcsNodePrinter.KeyNameComponentOf(propName))); field = F.Call(S.Var, propType, fieldName).WithAttrs(fieldAttr.Attrs); } else { fieldName = field.Args[1]; if (fieldName.Calls(S.Assign, 2)) { fieldName = fieldName.Args[0]; } } if (autoType) { field = field.WithArgChanged(0, propType); } // Construct the new backing field, fill in the property getter and/or setter if (body.ArgCount == 0) { body = body.WithArgs(LNode.Id(S.get)); } LNode newBody = body.WithArgs(body.Args.SmartSelect(stmt => { var fieldAccessExpr = fieldName; if (propArgs.ArgCount > 0) { // Special case: the property has arguments, // e.g. [field List<T> L] T this[int x] { get; set; } // ==> List<T> L; T this[int x] { get { return L[x]; } set { L[x] = value; } } var argList = GetArgNamesFromFormalArgList(propArgs, formalArg => sink.Write(Severity.Error, formalArg, "'field' macro expected a variable declaration here")); fieldAccessExpr = F.Call(S.IndexBracks, argList.Insert(0, fieldName)); } var attrs = stmt.Attrs; if (stmt.IsIdNamed(S.get)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Return, fieldAccessExpr))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } if (stmt.IsIdNamed(S.set)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Assign, fieldAccessExpr, F.Id(S.value)))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } return(stmt); })); if (newBody == body) { sink.Write(Severity.Warning, fieldAttr, "The body of the property does not contain a 'get;' or 'set;' statement without a body, so no code was generated to get or set the backing field."); } prop = prop.WithAttrs(prop.Attrs.RemoveAt(i)).WithArgChanged(3, newBody); return(F.Call(S.Splice, new VList <LNode>(field, prop))); }
public static bool MatchesPattern(LNode candidate, LNode pattern, ref MMap <Symbol, LNode> captures, out RVList <LNode> attrs) { // [$capture] (...) if (!AttributesMatch(candidate, pattern, ref captures, out attrs)) { return(false); } // $capture LNode sub; if (pattern.Calls(S.Substitute, 1) && (sub = pattern.Args.Last).IsId) { if (candidate.AttrCount > attrs.Count) { candidate = candidate.WithAttrs(attrs); } AddCapture(captures, sub.Name, candidate); attrs = RVList <LNode> .Empty; return(true); } var kind = candidate.Kind; if (kind != pattern.Kind) { return(false); } if (candidate.Name != pattern.Name) { return(false); } if (kind == NodeKind.Literal) { return(object.Equals(candidate.Value, pattern.Value)); } else if (kind == NodeKind.Call) { if (!MatchesPatternNested(candidate.Target, pattern.Target, ref captures, ref attrs)) { return(false); } var cArgs = candidate.Args; var pArgs = pattern.Args; if (pArgs.Count != cArgs.Count && !pArgs.Any(IsParamsCapture)) { return(false); } // Scan from the end of the list to the beginning (RVLists is good at this), // matching args one-by-one. Use MatchThenParams() in case of $(params capture). while (!pArgs.IsEmpty) { LNode pArg = pArgs.Pop(); if (IsParamsCapture(pArg)) { return(MatchThenParams(cArgs, pArgs, pArg, ref captures, ref attrs)); } if (cArgs.IsEmpty) { return(false); } if (!MatchesPatternNested(cArgs.Pop(), pArg, ref captures, ref attrs)) { return(false); } } return(true); } else // kind == Id { return(true); } }