LNode EliminateRunSeqFromInitializer(LNode retType, LNode fieldName, ref LNode expr) { expr = BubbleUpBlocks(expr); if (expr.CallsMin(__runSequence, 1)) { var statements = expr.Args.WithoutLast(1); var finalResult = expr.Args.Last; LNode methodName = F.Id(KeyNameComponentOf(fieldName).Name + "_initializer"); expr = LNode.Call(methodName); return(LNode.Call(LNode.List(LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(retType, methodName, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(statements).Add(LNode.Call(CodeSymbols.Return, LNode.List(finalResult)))).SetStyle(NodeStyle.Statement)))); } else { return(null); } }
void ProcessAttribute(LNode attr, Symbol mode, LNode exceptionType, LNode variableName, bool isPropSetter) { var conditions = attr.Args; object haveCCRewriter = Context.ScopedProperties.TryGetValue(_haveContractRewriter, null); _haveCCRewriter = haveCCRewriter is bool?(bool)haveCCRewriter : false; // #notnull is equivalent to either requires(_ != null) or ensures(_ != null) if (mode == sy_notnull) { if (attr.Args.Count != 0) { Context.Sink.Warning(attr, "'#notnull' does not expect arguments."); } if (variableName != null // argument ) { mode = sy_requires; } else { // return value mode = sy_ensures; } conditions.Add(LNode.Call(CodeSymbols.Neq, LNode.List(LNode.Id((Symbol)"_"), LNode.Literal(null))).SetStyle(NodeStyle.Operator)); } else if (!attr.IsCall) { Context.Sink.Warning(attr, "'{0}' expects a list of conditions.", attr.Name); } if (mode == sy_requires || mode == sy_assert) { ProcessRequiresAttribute(conditions, mode, variableName); } else // mode == @@ensures || mode == @@ensuresFinally || mode == @@ensuresOnThrow { if (variableName != null && !isPropSetter) { Context.Sink.Error(attr, "The '{0}' attribute does not apply to method arguments.", mode); } else { ProcessEnsuresAttribute(conditions, mode, exceptionType, variableName); } } }
public void GenerateOutput(ref VList <LNode> 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)), 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 VList <LNode>(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.Statement))); var outBody = new VList <LNode>(); 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.Statement)))); 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(LNode.List(LNode.Id(CodeSymbols.TriviaWordAttribute)), 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)), 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.Statement))))).SetStyle(NodeStyle.Statement)))); } foreach (var child in _children) { child.GenerateOutput(ref list); } }
public static LNode printKnownMacros(LNode node, IMacroContext context) { // namespace LeMP { // /* documentation */ // macroName; // ... // } return(F.Call(S.Splice, context.AllKnownMacros.SelectMany(p => p.Value) .GroupBy(mi => mi.Namespace).OrderBy(g => g.Key).Select(group => F.Attr(F.Trivia(S.TriviaSLComment, " printKnownMacros output "), F.Call(S.Namespace, NamespaceSymbolToLNode(group.Key ?? GSymbol.Empty), LNode.Missing, F.Braces(group.OrderBy(mi => mi.Macro.Method.Name).Select(mi => { StringBuilder descr = new StringBuilder(); descr.Append("\n### ").Append(mi.Names.FirstOrDefault("<no name>")).Append(" ###\n"); if (!string.IsNullOrEmpty(mi.Syntax)) { descr.Append("\n\t").Append(mi.Syntax).Append("\n"); } if (!string.IsNullOrEmpty(mi.Description)) { descr.Append("\n").Append(mi.Description).Append("\n"); } descr.Replace("\n", "\n\t\t"); descr.Append("\t"); LNode line = mi.Names.Length == 1 ? (LNode)LNode.Id(mi.Names[0]) : LNode.Call(S.Tuple, LNode.List(mi.Names.Select(name => (LNode)LNode.Id(name)))); string methodName = mi.Macro.Method.Name, @class = mi.Macro.Method.DeclaringType.Name; string postComment = " " + @class + "." + methodName; if (mi.Mode != MacroMode.Normal) { postComment += string.Format(" (Mode = {0})", mi.Mode); } return F.Attr( F.Trivia(S.TriviaMLComment, descr.ToString()), F.TriviaNewline, line).PlusTrailingTrivia(F.Trivia(S.TriviaSLComment, postComment)); }))))))); }
public static LNode concatId(LNode node, IMacroContext context) { StringBuilder sb = ConcatCore(node, out var attrs, context.Sink, allowLastToBeCall: true); if (sb == null) { return(null); } Symbol combined = GSymbol.Get(sb.ToString()); LNode result; if (node.Args.Last.IsCall) { result = node.Args.Last.WithTarget(combined); } else { result = LNode.Id(combined, node); } return(result.WithAttrs(attrs)); }
public static LNode printKnownMacros(LNode node, IMacroContext context) { // namespace LeMP { // /* documentation */ // #fn; // ... // } return(F.Call(S.Splice, context.AllKnownMacros.SelectMany(p => p.Value) .GroupBy(mi => mi.NamespaceSym).OrderBy(g => g.Key).Select(group => F.Attr(F.Trivia(S.TriviaSLCommentBefore, "#printKnownMacros"), F.Call(S.Namespace, NamespaceSymbolToLNode(group.Key ?? GSymbol.Empty), LNode.Missing, F.Braces(group.Select(mi => { StringBuilder descr = new StringBuilder(string.Format("\n\t\t### {0} ###\n", ParsingService.Current.Print(LNode.Id(mi.Name), null, ParsingService.Exprs))); if (!string.IsNullOrWhiteSpace(mi.Info.Syntax)) { descr.Append("\n\t\t\t").Append(mi.Info.Syntax.Replace("\n", "\n\t\t")).Append("\n"); } if (!string.IsNullOrWhiteSpace(mi.Info.Description)) { descr.Append("\n\t\t").Append(mi.Info.Description.Replace("\n", "\n\t\t")).Append("\n"); } descr.Append("\t"); LNode line = LNode.Id(mi.Name ?? (Symbol)"<null>"); string methodName = mi.Macro.Method.Name, @class = mi.Macro.Method.DeclaringType.Name; string postComment = " " + @class + "." + methodName; if (mi.Mode != MacroMode.Normal) { postComment += string.Format(" (Mode = {0})", mi.Mode); } return F.Attr( F.Trivia(S.TriviaMLCommentBefore, descr.ToString()), F.Trivia(S.TriviaSpaceBefore, "\n"), F.Trivia(S.TriviaSLCommentAfter, postComment), line); }))))))); }
/// <summary>Converts a <see cref="Token"/> to a <see cref="LNode"/>.</summary> /// <param name="file">This becomes the <see cref="LNode.Source"/> property.</param> /// <remarks>If you really need to store tokens as LNodes, use this. Only /// the <see cref="Kind"/>, not the TypeInt, is preserved. Identifiers /// (where Kind==TokenKind.Id and Value is Symbol) are translated as Id /// nodes; everything else is translated as a call, using the TokenKind as /// the <see cref="LNode.Name"/> and the value, if any, as parameters. For /// example, if it has been treeified with <see cref="TokensToTree"/>, the /// token list for <c>"Nodes".Substring(1, 3)</c> as parsed by LES might /// translate to the LNode sequence <c>String("Nodes"), Dot(@@.), /// Substring, LParam(Number(1), Separator(@@,), Number(3)), RParen()</c>. /// The <see cref="LNode.Range"/> will match the range of the token. /// </remarks> public LNode ToLNode(ISourceFile file) { var kind = Kind; Symbol kSym = GSymbol.Empty; Symbol id; if (kind != TokenKind.Id) { int k = (int)kind >> TokenKindShift; kSym = _kindAttrTable.TryGet(k, null); } var r = new SourceRange(file, StartIndex, Length); var c = Children; if (c != null) { if (c.Count != 0) { r = new SourceRange(file, StartIndex, System.Math.Max(EndIndex, c.Last.EndIndex) - StartIndex); } return(LNode.Call(kSym, c.ToLNodes(), r, Style)); } else if (IsOpenerOrCloser(kind) || Value == WhitespaceTag.Value) { return(LNode.Call(kSym, VList <LNode> .Empty, r, Style)); } else if (kind == TokenKind.Id && (id = this.Value as Symbol) != null) { return(LNode.Id(id, r, Style)); } else { return(LNode.Trivia(kSym, this.Value, r, Style)); } }
void ProcessEnsuresAttribute(VList <LNode> conditions, Symbol mode, LNode exceptionType, LNode variableName) { // Create a "Contract.Whatever()" check for each provided condition. bool haveCCRewriter = _haveCCRewriter && mode != sy_ensuresAssert && mode != sy_ensuresFinally; var checks = LNode.List(); foreach (var condition_ in conditions) { LNode condition = condition_; // make it writable so we can replace `_` LNode conditionStr; LNode contractResult = null; string underscoreError = null; if (mode == sy_ensuresOnThrow) { contractResult = Id__exception__; if (haveCCRewriter) { underscoreError = "`ensuresOnThrow` does not support `_` in MS Code Contracts mode."; } } else // @@ensures or @@ensuresAssert or @@ensuresFinally { contractResult = haveCCRewriter ? LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"Result"), ReturnType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator)) : Id_return_value; if (mode == sy_ensuresFinally) { underscoreError = "The macro for `{0}` does not support `_` because the return value is not available in `finally`"; } else if (haveCCRewriter && ReturnType.IsIdNamed(S.Missing)) { underscoreError = "The macro for `{0}` does not support `_` in this context when MS Code Contracts are enabled, because the return type is unknown."; } bool changed = ReplaceContractUnderscore(ref condition, contractResult); } if (ReplaceContractUnderscore(ref condition, contractResult) && underscoreError != null) { Context.Sink.Error(condition, underscoreError, mode); } if (haveCCRewriter) { if (mode == sy_ensuresOnThrow) { checks.Add(exceptionType != null ? LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"EnsuresOnThrow"), exceptionType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), LNode.List(condition)) : LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"EnsuresOnThrow"))).SetStyle(NodeStyle.Operator), LNode.List(condition))); } else { checks.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"Ensures"))).SetStyle(NodeStyle.Operator), LNode.List(condition))); } } else { conditionStr = ConditionToStringLit(condition, mode == sy_ensuresOnThrow ? "Postcondition failed after throwing an exception: {1}" : "Postcondition failed: {1}"); if (mode == sy_ensuresOnThrow) { var excType = GetExceptionTypeForEnsuresOnThrow(); checks.Add(LNode.Call(CodeSymbols.If, LNode.List(LNode.Call(CodeSymbols.Not, LNode.List(condition)).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.Throw, LNode.List(LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(excType, LNode.List(conditionStr, Id__exception__))))))))); } else { LNode assertMethod; if (mode == sy_ensuresAssert) { assertMethod = GetAssertMethod(Context); } else if (mode == sy_ensuresFinally) { assertMethod = GetAssertMethodForEnsuresFinally(); } else { assertMethod = GetAssertMethodForEnsures(); } checks.Add(LNode.Call(assertMethod, LNode.List(condition, conditionStr))); } } } // Request that the checks be added to the beginning of the method if (checks.Count > 0) { if (_haveCCRewriter) { PrependStmts.AddRange(checks); } else if (mode == sy_ensuresOnThrow) { LNode excSpec = exceptionType == null ? Id__exception__ : LNode.Call(CodeSymbols.Var, LNode.List(exceptionType, Id__exception__)); PrependStmts.Add(LNode.Call((Symbol)"on_throw", LNode.List(excSpec, LNode.Call(CodeSymbols.Braces, LNode.List(checks)).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special)); } else if (mode == sy_ensuresFinally) { PrependStmts.Add(LNode.Call((Symbol)"on_finally", LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(checks)).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special)); } else // mode == @@ensures || mode == @@ensuresAssert { PrependStmts.Add(LNode.Call((Symbol)"on_return", LNode.List(Id_return_value, LNode.Call(CodeSymbols.Braces, LNode.List(checks)).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special)); } } }
LNode GetExceptionTypeForEnsuresOnThrow() { return((Context.ScopedProperties.TryGetValue(sy__numexceptionTypeForEnsuresOnThrow, null) as LNode) ?? LNode.Id((Symbol)"InvalidOperationException")); }
void ProcessRequiresAttribute(VList <LNode> conditions, Symbol mode, LNode variableName) { foreach (var condition_ in conditions) { LNode condition = condition_; LNode conditionStr; if (ReplaceContractUnderscore(ref condition, variableName)) { if (variableName == null) { Context.Write(Severity.Error, condition, "`{0}`: underscore has no meaning in this location.", mode); } } if (mode == sy_assert) { PrependStmts.Add(LNode.Call((Symbol)"assert", LNode.List(condition))); } else if (_haveCCRewriter) { PrependStmts.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"Requires"))), LNode.List(condition))); } else { conditionStr = ConditionToStringLit(condition, "Precondition failed: {1}"); PrependStmts.Add(LNode.Call(GetAssertMethodForRequires(), LNode.List(condition, conditionStr))); } } }
void ProcessRequiresAttribute(VList <LNode> 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))); } } }
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 static LNode ContractsOnProperty(LNode prop, 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 oldProp = prop; if (prop.ArgCount == 4) { LNode braces = prop[3]; var oldBraces = braces; var rw = new CodeContractRewriter(prop.Args[0], prop.Args[1], context); // If this has an argument list (this[...]), process its contract attributes prop = ProcessArgContractAttributes(prop, 2, rw); // Remove contract attributes from the property and store in a list VList <LNode> cAttrs = LNode.List(); prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter)); prop = GrabContractAttrs(prop, ref cAttrs); // Find the getter and setter LNode getter = null, setter = null; int getterIndex = -1, setterIndex = -1; VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List(); bool isLambdaProperty = !braces.Calls(S.Braces); if (isLambdaProperty) { if (cAttrs.Count == 0) { return(null); // lambda property has no contract attributes } // Transform into a normal property getterAttrs = cAttrs; getter = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special); braces = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement); getterIndex = 0; } else { for (int i = 0; i < braces.Args.Count; i++) { var part = braces.Args[i]; if (part.Calls(S.get)) { getter = part; getterIndex = i; } if (part.Calls(S.set)) { setter = part; setterIndex = i; } } // Now create separate lists of contract attributes for the getter and the setter if (cAttrs.Count != 0) { getterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0); setterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0); } } // Process the discovered attributes to produce prepended statements var sharedPrependStmts = rw.PrependStmts; if (getter != null) { getter = GrabContractAttrs(getter, ref getterAttrs); rw.Process(getterAttrs, null); rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter); } if (setter != null) { rw.PrependStmts = sharedPrependStmts; setter = GrabContractAttrs(setter, ref setterAttrs); rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true); rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter); } // Update the property if (braces == oldBraces) { return(null); // this is the common case } else { return(prop.WithArgChanged(3, braces)); } } return(null); }
[LexicalMacro("x in lo..hi; x in lo...hi; x in ..hi; x in lo..._; x in range", "Converts an 'in' expression to a normal C# expression using the following rules " + "(keeping in mind that the EC# parser treats `..<` as an alias for `..`):\n" + "1. `x in _..hi` and `x in ..hi` become `x.IsInRangeExcl(hi)`\n" + "2. `x in _...hi` and `x in ...hi` become `x.IsInRangeIncl(hi)`\n" + "3. `x in lo.._` and `x in lo..._` become simply `x >= lo`\n" + "4. `x in lo..hi` becomes `x.IsInRangeExcludeHi(lo, hi)`\n" + "5. `x in lo...hi` becomes `x.IsInRange(lo, hi)`\n" + "6. `x in range` becomes `range.Contains(x)`\n" + "The first applicable rule is used.", "#in")] public static LNode In(LNode node, IMacroContext context) { { LNode range, x; if (node.Calls(CodeSymbols.In, 2) && (x = node.Args[0]) != null && (range = node.Args[1]) != null) { LNode parens; range = range.WithoutAttrNamed(S.TriviaInParens, out parens); if (parens == null) { { LNode hi, lo; if (range.Calls(CodeSymbols.DotDot, 2) && (lo = range.Args[0]) != null && (hi = range.Args[1]) != null) { if (lo.IsIdNamed(__)) { return(LNode.Call(CodeSymbols.LT, LNode.List(x, hi)).SetStyle(NodeStyle.Operator)); } else if (hi.IsIdNamed(__)) { return(LNode.Call(CodeSymbols.GE, LNode.List(x, lo)).SetStyle(NodeStyle.Operator)); } else { return(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(x, LNode.Id((Symbol)"IsInRangeExcludeHi"))), LNode.List(lo, hi))); } } else if (range.Calls(CodeSymbols.DotDot, 1) && (hi = range.Args[0]) != null) { return(LNode.Call(CodeSymbols.LT, LNode.List(x, hi)).SetStyle(NodeStyle.Operator)); } else if (range.Calls(CodeSymbols.DotDotDot, 2) && (lo = range.Args[0]) != null && (hi = range.Args[1]) != null) { if (lo.IsIdNamed(__)) { return(LNode.Call(CodeSymbols.LE, LNode.List(x, hi)).SetStyle(NodeStyle.Operator)); } else if (hi.IsIdNamed(__)) { return(LNode.Call(CodeSymbols.GE, LNode.List(x, lo)).SetStyle(NodeStyle.Operator)); } else { return(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(x, LNode.Id((Symbol)"IsInRange"))), LNode.List(lo, hi))); } } else if (range.Calls(CodeSymbols.DotDotDot, 1) && (hi = range.Args[0]) != null) { return(LNode.Call(CodeSymbols.LE, LNode.List(x, hi)).SetStyle(NodeStyle.Operator)); } } } return(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(range, LNode.Id((Symbol)"Contains"))), LNode.List(x))); } } return(null); }
internal static LNode TempVarDecl(IMacroContext ctx, LNode value, out LNode tmpVarName, string prefix) { tmpVarName = LNode.Id(NextTempName(ctx, prefix), value); return(F.Var(F.Missing, tmpVarName, value)); }
public 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 VList <LNode>(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.Statement))); } return(method); }
public LNode GetItemDecl(int itemNum) { LNode ItemN = F.Id("Item" + itemNum); // ItemN properties are used by the code generated for pattern matching return(LNode.Call(LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"System"), LNode.Id((Symbol)"ComponentModel"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"EditorBrowsable"))).SetStyle(NodeStyle.Operator), LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"System"), LNode.Id((Symbol)"ComponentModel"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"EditorBrowsableState"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Never"))).SetStyle(NodeStyle.Operator))), LNode.Id(CodeSymbols.Public)), CodeSymbols.Property, LNode.List(Type, ItemN, LNode.Missing, LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(NameId)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special))).SetStyle(NodeStyle.Statement)))); }
private void MakeArgListTests(VList <LNode> patternArgs, ref LNode candidate) { 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"))), F.Literal(i))), 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"))), LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Count"))), F.Literal(left))).SetStyle(NodeStyle.Operator))), out varArgSym2, out varArgCond2); if (varArgSym2 != null) { Context.Sink.Write(Severity.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)) { 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); } 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"))), LNode.Id((Symbol)"WithoutLast"))), 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(LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode"))), LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Slice"))), LNode.List(varArgStartLit)))))))).SetStyle(NodeStyle.Operator); } else { grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode"))), LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Slice"))), 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"))), LNode.Id((Symbol)"Count"))), fixedArgsLit)).SetStyle(NodeStyle.Operator))))))))).SetStyle(NodeStyle.Operator); } } 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"))), LNode.Literal(true))).SetStyle(NodeStyle.Operator)); Tests.Add(varArgCond); } else { ThenClause.Add(grabVarArgs); } } }
[LexicalMacro("matchCode (var) { case ...: ... }; // In LES, use a => b instead of case a: b", "Attempts to match and deconstruct a Loyc tree against a series of cases with patterns, e.g. " + "`case $a + $b:` expects a tree that calls `+` with two parameters, placed in new variables called a and b. " + "`break` is not required or recognized at the end of each case's handler (code block). " + "Use `$(...x)` to gather zero or more parameters into a list `x`. " + "Use `case pattern1, pattern2:` in EC# to handle multiple cases with the same handler.")] public static LNode matchCode(LNode node, IMacroContext context) { var args_body = context.GetArgsAndBody(true); VList <LNode> args = args_body.Item1, body = args_body.Item2; if (args.Count != 1 || body.Count < 1) { return(null); } var cases = GetCases(body, context.Sink); if (cases.IsEmpty) { return(null); } var output = new WList <LNode>(); var @var = MaybeAddTempVarDecl(args[0], output); var ifClauses = new List <Pair <LNode, LNode> >(); var cmc = new CodeMatchContext { Context = context }; foreach (var @case in cases) { cmc.ThenClause.Clear(); LNode testExpr = null; if (@case.Key.Count > 0) { if (cmc.IsMultiCase = @case.Key.Count > 1) { cmc.UsageCounters.Clear(); testExpr = @case.Key.Aggregate((LNode)null, (test, pattern) => { test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, @var), S.Or); return(test); }); foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count)) { if (cmc.NodeVars.ContainsKey(pair.Key)) { cmc.NodeVars[pair.Key] = true; } if (cmc.ListVars.ContainsKey(pair.Key)) { cmc.ListVars[pair.Key] = true; } } } else { testExpr = cmc.MakeTopTestExpr(@case.Key[0], @var); } } var handler = @case.Value; if (cmc.ThenClause.Count > 0) { handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces); } ifClauses.Add(Pair.Create(testExpr, handler)); } LNode ifStmt = null; for (int i = ifClauses.Count - 1; i >= 0; i--) { if (ifClauses[i].Item1 == null) { if (ifStmt == null) { ifStmt = ifClauses[i].Item2; } else { context.Sink.Write(Severity.Error, node, "The default case must appear last, and there can be only one."); } } else { if (ifStmt == null) { ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2); } else { ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt); } } } if (cmc.NodeVars.Count > 0) { output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat(cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key))))); } if (cmc.ListVars.Count > 0) { LNode type = LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode"))); output.Add(F.Call(S.Var, ListExt.Single(type).Concat(cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key))))); } if (output.Count == 0) { return(ifStmt); } else { output.Add(ifStmt); return(F.Braces(output.ToVList())); } }
void GenCodeForPattern(LNode input, LNode pattern) { bool refExistingVar; LNode varBinding, cmpExpr, isType, inRange; VList <LNode> subPatterns, conditions; GetPatternComponents(pattern, out varBinding, out refExistingVar, out cmpExpr, out isType, out inRange, out subPatterns, out conditions); if (isType != null) { if ((cmpExpr ?? inRange ?? varBinding) != null) { if (!LooksLikeSimpleValue(input)) { PutStmt(TempVarDecl(input, out input)); } } PutCond(LNode.Call(CodeSymbols.Is, LNode.List(input, isType)).SetStyle(NodeStyle.Operator)); if (varBinding == null && ((cmpExpr ?? inRange) != null || subPatterns.Count > 0)) { varBinding = LNode.Id(NextTempName(), isType); } } if (varBinding != null) { if (isType != null) { if (refExistingVar) { PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator)); } else { PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(isType, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator)))))); } } else { if (refExistingVar) { PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)).SetStyle(NodeStyle.Operator)); } else { PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Missing, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input))))); } } input = varBinding; } if (cmpExpr != null) { if (cmpExpr.Value == null) { PutCond(LNode.Call(CodeSymbols.Eq, LNode.List(input, LNode.Literal(null))).SetStyle(NodeStyle.Operator)); } else { PutCond(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(cmpExpr, LNode.Id((Symbol)"Equals"))), LNode.List(input))); } } for (int itemIndex = 0; itemIndex < subPatterns.Count; itemIndex++) { var subPattern = subPatterns[itemIndex]; LNode propName; if (subPattern.Calls(S.NamedArg, 2) || subPattern.Calls(S.Colon, 2)) { propName = subPattern[0]; subPattern = subPattern[1]; } else { propName = LNode.Id("Item" + (itemIndex + 1), subPattern); } GenCodeForPattern(LNode.Call(CodeSymbols.Dot, LNode.List(input, propName)), subPattern); } if (inRange != null) { PutCond(LNode.Call(CodeSymbols.In, LNode.List(input, inRange)).SetStyle(NodeStyle.Operator)); } foreach (var cond in conditions) { PutCond(cond); } }
public static LNode ContractsOnProperty(LNode prop, IMacroContext context) { LNode oldProp = prop; if (prop.ArgCount == 4) { LNode braces = prop[3]; var oldBraces = braces; var rw = new CodeContractRewriter(prop.Args[0], prop.Args[1], context); prop = ProcessArgContractAttributes(prop, 2, rw); VList <LNode> cAttrs = LNode.List(); prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter)); prop = GrabContractAttrs(prop, ref cAttrs); LNode getter = null, setter = null; int getterIndex = -1, setterIndex = -1; VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List(); bool isLambdaProperty = !braces.Calls(S.Braces); if (isLambdaProperty) { if (cAttrs.Count == 0) { return(null); } getterAttrs = cAttrs; getter = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special); braces = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement); getterIndex = 0; } else { for (int i = 0; i < braces.Args.Count; i++) { var part = braces.Args[i]; if (part.Calls(S.get)) { getter = part; getterIndex = i; } if (part.Calls(S.set)) { setter = part; setterIndex = i; } } if (cAttrs.Count != 0) { getterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0); setterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0); } } var sharedPrependStmts = rw.PrependStmts; if (getter != null) { getter = GrabContractAttrs(getter, ref getterAttrs); rw.Process(getterAttrs, null); rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter); } if (setter != null) { rw.PrependStmts = sharedPrependStmts; setter = GrabContractAttrs(setter, ref setterAttrs); rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true); rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter); } if (braces == oldBraces) { return(null); } else { return(prop.WithArgChanged(3, braces)); } } return(null); }
/// <summary>Returns the same node with a parentheses attribute added.</summary> public static LNode InParens(this LNode node) { return(node.PlusAttrBefore(LNode.Id(CodeSymbols.TriviaInParens))); }
public LNode GetItemDecl(int itemNum) { LNode ItemN = F.Id("Item" + itemNum); return(LNode.Call(LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"System"), LNode.Id((Symbol)"ComponentModel"))), LNode.Id((Symbol)"EditorBrowsable"))), LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"System"), LNode.Id((Symbol)"ComponentModel"))), LNode.Id((Symbol)"EditorBrowsableState"))), LNode.Id((Symbol)"Never"))))), LNode.Id(CodeSymbols.Public)), CodeSymbols.Property, LNode.List(Type, ItemN, LNode.Missing, LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(NameId)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special))).SetStyle(NodeStyle.Statement)))); }
/// <summary>Returns the same node with a parentheses attribute added.</summary> /// <remarks>The node's range is changed to the provided <see cref="SourceRange"/>.</remarks> public static LNode InParens(this LNode node, SourceRange range) { return(node.WithRange(range).PlusAttrBefore(LNode.Id(CodeSymbols.TriviaInParens))); }
public LNode GetFieldDecl() { return(LNode.Call(LNode.List(LNode.Id(CodeSymbols.Public)), CodeSymbols.Property, LNode.List(Type, NameId, LNode.Missing, LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Id(CodeSymbols.get), LNode.Id(LNode.List(LNode.Id(CodeSymbols.Private)), CodeSymbols.set))).SetStyle(NodeStyle.Statement)))); }
private void MakeTestExpr(LNode pattern, LNode candidate, out Symbol varArgSym, out LNode varArgCond) { varArgSym = null; varArgCond = null; // is this a $substitutionVar? LNode condition; bool isParams, refExistingVar; var nodeVar = DecodeSubstitutionExpr(pattern, out condition, out isParams, out refExistingVar); // Unless the candidate is a simple variable name, avoid repeating // it by creating a temporary variable to hold its value int predictedTests = pattern.Attrs.Count + (nodeVar != null ? 0 : pattern.Args.Count) + (!pattern.HasSimpleHeadWithoutPAttrs() ? 1 : 0); if (predictedTests > 1) { candidate = MaybePutCandidateInTempVar(candidate.IsCall, candidate); } MatchAttributes(pattern, candidate); // Look for @[$(...var)] // case $_ if (nodeVar != null) { if (nodeVar != __ || condition != null) { if (!refExistingVar) { AddVar(nodeVar, isParams, errAt: pattern); } if (!isParams) { var assignment = LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(nodeVar), candidate)).SetStyle(NodeStyle.Operator); Tests.Add(LNode.Call(CodeSymbols.NotEq, LNode.List(assignment.PlusAttrs(LNode.List(LNode.InParensTrivia)), LNode.Literal(null))).SetStyle(NodeStyle.Operator)); Tests.Add(condition); } } if (isParams) { varArgSym = nodeVar; varArgCond = condition; return; } } else if (pattern.IsId) { Tests.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"IsIdNamed"))).SetStyle(NodeStyle.Operator), LNode.List(LNode.Call(CodeSymbols.Cast, LNode.List(F.Literal(pattern.Name.Name), LNode.Id((Symbol)"Symbol"))).SetStyle(NodeStyle.Operator)))); } else if (pattern.IsLiteral) { if (pattern.Value == null) { Tests.Add(LNode.Call(CodeSymbols.Eq, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Value"))).SetStyle(NodeStyle.Operator), LNode.Literal(null))).SetStyle(NodeStyle.Operator)); } else { Tests.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(pattern, LNode.Id((Symbol)"Equals"))).SetStyle(NodeStyle.Operator), LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Value"))).SetStyle(NodeStyle.Operator)))); } } else // call(...) { int?varArgAt; int fixedArgC = GetFixedArgCount(pattern.Args, out varArgAt); // Test if the call target matches var pTarget = pattern.Target; if (pTarget.IsId && !pTarget.HasPAttrs()) { var quoteTarget = QuoteSymbol(pTarget.Name); LNode targetTest; if (varArgAt.HasValue && fixedArgC == 0) { targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Calls"))).SetStyle(NodeStyle.Operator), LNode.List(quoteTarget)); } else if (varArgAt.HasValue) { targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"CallsMin"))).SetStyle(NodeStyle.Operator), LNode.List(quoteTarget, F.Literal(fixedArgC))); } else { targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Calls"))).SetStyle(NodeStyle.Operator), LNode.List(quoteTarget, F.Literal(fixedArgC))); } Tests.Add(targetTest); } else { if (fixedArgC == 0) { Tests.Add(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"IsCall"))).SetStyle(NodeStyle.Operator)); if (!varArgAt.HasValue) { Tests.Add(LNode.Call(CodeSymbols.Eq, 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), LNode.Literal(0))).SetStyle(NodeStyle.Operator)); } } else { var op = varArgAt.HasValue ? S.GE : S.Eq; Tests.Add(LNode.Call(op, 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(fixedArgC)))); } int i = Tests.Count; MakeTestExpr(pTarget, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Target"))).SetStyle(NodeStyle.Operator)); } MakeArgListTests(pattern.Args, ref candidate); } }
void GenCodeForPattern(LNode input, LNode pattern, string defaultPropName = null) { // Get the parts of the pattern, e.g. `$x is T(sp)` => varBinding=x, isType=T, sp is returned bool refExistingVar; LNode varBinding, cmpExpr, isType, inRange, propName; VList <LNode> subPatterns, conditions; GetPatternComponents(pattern, out propName, out varBinding, out refExistingVar, out cmpExpr, out isType, out inRange, out subPatterns, out conditions); if (defaultPropName == null) // Outermost pattern { if (propName != null) { _context.Sink.Error(propName, "match: property name not allowed on outermost pattern"); } } else { if ((propName = propName ?? LNode.Id(defaultPropName, pattern)) != null) { input = LNode.Call(CodeSymbols.Dot, LNode.List(input, propName)).SetStyle(NodeStyle.Operator); } } // For a pattern like `is Type varBinding(subPatterns) in A...B && conds`, // our goal is to generate code like this: // // var tmp_1 = $input; // temp var created unless $input looks simple // if (tmp_1 is Type) { // Type varBinding = (Type)tmp_1; // if (varBinding >= A && varBinding <= B && /* code for matching subPatterns */) // if (conds) // $handler; // } if (isType != null) { if ((cmpExpr ?? inRange ?? varBinding) != null) { // input will be used multiple times, so consider making a tmp var. if (!LooksLikeSimpleValue(input)) { PutStmt(TempVarDecl(_context, input, out input)); } } PutCond(LNode.Call(CodeSymbols.Is, LNode.List(input, isType)).SetStyle(NodeStyle.Operator)); if (varBinding == null && ((cmpExpr ?? inRange) != null || subPatterns.Count > 0)) { // we'll need another temp variable to hold the same value, casted. varBinding = LNode.Id(NextTempName(_context), isType); } } if (varBinding != null) { if (isType != null) { if (refExistingVar) { PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator)); } else { PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(isType, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator)))))); } } else { if (refExistingVar) { PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)).SetStyle(NodeStyle.Operator)); } else { PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Missing, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input))))); } } input = varBinding; } if (cmpExpr != null) // do equality test { if (cmpExpr.Value == null) { PutCond(LNode.Call(CodeSymbols.Eq, LNode.List(input, LNode.Literal(null))).SetStyle(NodeStyle.Operator)); } else { PutCond(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(cmpExpr, LNode.Id((Symbol)"Equals"))).SetStyle(NodeStyle.Operator), LNode.List(input))); } } // Generate code for subpatterns for (int itemIndex = 0; itemIndex < subPatterns.Count; itemIndex++) { var subPattern = subPatterns[itemIndex]; GenCodeForPattern(input, subPattern, "Item" + (itemIndex + 1)); } if (inRange != null) { PutCond(LNode.Call(CodeSymbols.In, LNode.List(input, inRange)).SetStyle(NodeStyle.Operator)); } foreach (var cond in conditions) { PutCond(cond); } }
public static LNode matchCode(LNode node, IMacroContext context) { if (node.AttrNamed(S.Static) != null) { return(null); // this case is handled by static_matchCode macro } var args_body = context.GetArgsAndBody(false); LNodeList args = args_body.Item1, body = args_body.Item2; if (args.Count != 1 || body.Count < 1) { return(null); } var cases = GetCases(body, context.Sink); if (cases.IsEmpty) { return(null); } var output = new WList <LNode>(); var var = MaybeAddTempVarDecl(context, args[0], output); var ifClauses = new List <Pair <LNode, LNode> >(); var cmc = new CodeMatchContext { Context = context }; foreach (var @case in cases) { cmc.ThenClause.Clear(); // e.g. case [$(..._)] Foo($x + 1, $y) => // LNode x, y, tmp9; // if (var.Calls((Symbol) "Foo", 2) && (tmp9 = var.Args[0]).Calls(CodeSymbols.Plus, 2) // && (x = tmp9.Args[0]) != null // this will never be null, but we want to put it the assignment in the 'if' statement // && 1.Equals(tmp9.Args[1].Value) && (y = var.Args[1]) != null) { ... } LNode testExpr = null; if (@case.Key.Count > 0) { if (cmc.IsMultiCase = @case.Key.Count > 1) { cmc.UsageCounters.Clear(); testExpr = @case.Key.Aggregate((LNode)null, (test, pattern) => { test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, var), S.Or); return(test); }); foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count)) { if (cmc.NodeVars.ContainsKey(pair.Key)) { cmc.NodeVars[pair.Key] = true; } if (cmc.ListVars.ContainsKey(pair.Key)) { cmc.ListVars[pair.Key] = true; } } } else { testExpr = cmc.MakeTopTestExpr(@case.Key[0], var); } } var handler = F.Braces(@case.Value); if (cmc.ThenClause.Count > 0) { handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces); } ifClauses.Add(Pair.Create(testExpr, handler)); } LNode ifStmt = null; for (int i = ifClauses.Count - 1; i >= 0; i--) { if (ifClauses[i].Item1 == null) { if (ifStmt == null) { ifStmt = ifClauses[i].Item2; } else { context.Sink.Error(node, "The default case must appear last, and there can be only one."); } } else { if (ifStmt == null) { ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2); } else { ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt); } } } if (cmc.NodeVars.Count > 0) { output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat( cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key))))); } if (cmc.ListVars.Count > 0) { LNode type = LNode.Id((Symbol)"LNodeList"); output.Add(F.Call(S.Var, ListExt.Single(type).Concat( cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key))))); } if (output.Count == 0) { return(ifStmt.IncludingTriviaFrom(node)); } else { output.Add(ifStmt); return(F.Braces(output.ToVList()).IncludingTriviaFrom(node)); } }
public static LNode ArrayLiteral(LNode node, IMacroContext context) { var value = node.Value; if (value is Array array) { Type elementType = value.GetType().GetElementType(); string elementTypeName = elementType.NameWithGenericArgs(); LNode elementTypeN = LNode.Call(S.CsRawText, LNode.List(LNode.Literal(elementTypeName))); Func <object, LNode, LNode> newLiteral = (el, pnode) => LNode.Literal(el, pnode); // Reduce output text size by preventing the printer from using casts // e.g. print `23` instead of `(byte) 23` or `(short) 23`. Also, unbox // ints to save memory (ideally we'd do this for all Value Types) if (elementType == typeof(byte)) { newLiteral = (el, pnode) => LNode.Literal((int)(byte)el, pnode); } if (elementType == typeof(sbyte)) { newLiteral = (el, pnode) => LNode.Literal((int)(sbyte)el, pnode); } if (elementType == typeof(short)) { newLiteral = (el, pnode) => LNode.Literal((int)(short)el, pnode); } if (elementType == typeof(ushort)) { newLiteral = (el, pnode) => LNode.Literal((int)(ushort)el, pnode); } if (elementType == typeof(int)) { newLiteral = (el, pnode) => LNode.Literal((int)(int)el, pnode); } if (array.Rank == 1) { var initializers = new List <LNode>(); int count = 0; foreach (object element in array) { LNode elemNode = newLiteral(element, node); if ((count++ & 7) == 0 && array.Length > 8) { elemNode = elemNode.PlusAttr(LNode.Id(S.TriviaNewline)); } initializers.Add(elemNode); } return(LNode.Call(CodeSymbols.New, LNode.List().Add(LNode.Call(LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id(CodeSymbols.Array), elementTypeN)))).AddRange(initializers))); } else { return(null); // TODO //Stmt("int[,] Foo = new[,] { {\n 0 }, {\n 1,\n 2, }, };", F.Call(S.Var, F.Of(S.TwoDimensionalArray, S.Int32), // F.Call(S.Assign, Foo, F.Call(S.New, F.Call(S.TwoDimensionalArray), F.Braces(zero), F.Braces(one, two))))); } } return(null); }
private void MatchAttributes(LNode pattern, LNode candidate) { LNode condition; bool isParams, refExistingVar; Symbol listVar; var pAttrs = pattern.PAttrs(); if (pAttrs.Count == 1 && (listVar = DecodeSubstitutionExpr(pAttrs[0], out condition, out isParams, out refExistingVar)) != null && isParams) { if (listVar != __ || condition != null) { if (!refExistingVar) { AddVar(listVar, true, errAt: pattern); } Tests.Add(LNode.Call(CodeSymbols.OrBits, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(LNode.List(LNode.InParensTrivia), CodeSymbols.Assign, LNode.List(F.Id(listVar), LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Attrs"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"IsEmpty"))).SetStyle(NodeStyle.Operator), LNode.Literal(true))).SetStyle(NodeStyle.Operator)); if (condition != null) { Tests.Add(condition); } } } else if (pAttrs.Count != 0) { Context.Sink.Error(pAttrs[0], "Currently, Attribute matching is very limited; you can only use `[$(...varName)]`"); } }