LNode ConvertVarDeclToRunSequence(VList <LNode> attrs, LNode varType, LNode varName, LNode initValue) { initValue = BubbleUpBlocks(initValue); varType = varType ?? F.Missing; LNode @ref; attrs = attrs.WithoutNodeNamed(S.Ref, out @ref); var varName_apos = varName.PlusAttr(_trivia_isTmpVar); if (@ref != null) { varName_apos = varName_apos.PlusAttr(@ref); } { LNode resultValue; VList <LNode> stmts; if (initValue.CallsMin((Symbol)"#runSequence", 1) && (resultValue = initValue.Args[initValue.Args.Count - 1]) != null) { stmts = initValue.Args.WithoutLast(1); var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, resultValue)))); return(initValue.WithArgs(stmts.Add(newVarDecl).Add(varName_apos))); } else { var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, initValue)))); return(LNode.Call((Symbol)"#runSequence", LNode.List(newVarDecl, varName_apos))); } } }
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); }
static LNode MergeIdentifiers(LNode left, LNode right) { if (left == null) { return(right); } if (right.IsIdNamed(S.Missing)) { return(left); } { LNode right1, right2; if (right.Calls(CodeSymbols.Dot, 1) && (right2 = right.Args[0]) != null) { return(LNode.Call(CodeSymbols.Dot, LNode.List(left, right2))); } else if (right.Calls(CodeSymbols.Dot, 2) && (right1 = right.Args[0]) != null && (right2 = right.Args[1]) != null) { return(LNode.Call(CodeSymbols.Dot, LNode.List(MergeIdentifiers(left, right1), right2))); } else { throw new LogException(Severity.Note, right, "Multi-using statement seems malformed. Correct example: `using System(.Text, .Linq));`"); } } }
[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); }
[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); }
/// <summary>Adds additional trailing trivia to an attribute list.</summary> public static VList <LNode> PlusTrailingTrivia(this VList <LNode> attrs, LNode trivia) { VList <LNode> oldTrivia; attrs = WithoutTrailingTrivia(attrs, out oldTrivia); return(attrs.Add(LNode.Call(S.TriviaTrailing, oldTrivia.Add(trivia)))); }
static LNode ToLNodeCore(ILNode node) { var attrs = VList <LNode> .Empty; for (int i = node.Min; i < -1; i++) { attrs.Add(ToLNodeCore(node[i])); } switch (node.Kind) { case LNodeKind.Id: return(LNode.Id(attrs, node.Name, node.Range, node.Style)); case LNodeKind.Literal: return(LNode.Literal(attrs, node.Value, node.Range, node.Style)); default: var args = VList <LNode> .Empty; for (int i = 0, max = node.Max; i <= max; i++) { args.Add(ToLNodeCore(node[i])); } var target = ToLNodeCore(node.Target); return(LNode.Call(attrs, target, args, node.Range, node.Style)); } }
public static LNode RangeIncl(LNode node, IMacroContext context) { LNode lo = null; { LNode hi; if (node.Args.Count == 2 && (lo = node.Args[0]) != null && (hi = node.Args[1]) != null || node.Args.Count == 1 && (hi = node.Args[0]) != null) { if (lo == null || lo.IsIdNamed(__)) { if (hi.IsIdNamed(__)) { return(Range_Everything); } else { return(LNode.Call(Range_UntilInclusive, LNode.List(hi))); } } else if (hi.IsIdNamed(__)) { return(LNode.Call(Range_StartingAt, LNode.List(lo))); } else { return(LNode.Call(Range_Inclusive, LNode.List(lo, hi))); } } } 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); }
public static LNode @case(LNode node, IMacroContext context) { LNode expr, braces = null; if (node.ArgCount == 2 && (braces = node.Args.Last).Calls(S.Braces) || node.ArgCount == 1 && (node[0].Calls(S.Colon, 2) || node[0].Calls("'or", 2))) { expr = node[0]; var results = LNode.List(); while (expr.Calls("'or", 2)) { results.Add(LNode.Call(S.Case, LNode.List(expr[0]), expr[0])); expr = expr[1]; } if (braces != null) { results.Add(LNode.Call(S.Case, LNode.List(expr), expr)); return(F.Call(S.Splice, results.Add(braces))); } else if (expr.Calls(S.Colon, 2)) { results.Add(LNode.Call(S.Case, LNode.List(expr[0]), expr[0])); return(F.Call(S.Splice, results.Add(expr[1]))); } else { return(Les2.Reject(context, node, "Unrecognized syntax in case statement")); } } 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)]`"); } }
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))); } } }
[LexicalMacro("lo..hi; ..hi; lo.._", "Given `lo..hi, produces `Range.Excl(lo, hi)", "..")] public static LNode RangeExcl(LNode node, IMacroContext context) { LNode lo = null; { LNode hi; if (node.Args.Count == 2 && (lo = node.Args[0]) != null && (hi = node.Args[1]) != null || node.Args.Count == 1 && (hi = node.Args[0]) != null) { if (lo == null || lo.IsIdNamed(__)) { if (hi.IsIdNamed(__)) { return(Range_Everything); } else { return(LNode.Call(Range_UntilExclusive, LNode.List(hi))); } } else if (hi.IsIdNamed(__)) { return(LNode.Call(Range_StartingAt, LNode.List(lo))); } else { return(LNode.Call(Range_ExcludeHi, LNode.List(lo, hi))); } } } return(null); }
LNode GetOutputAsLNode() { WList <LNode> finalOutput = _handler.ToWList(); for (int end = _output.Count - 1; end >= 0; end--) { var tmp_10 = _output[end]; Mode mode = tmp_10.Item1; LNode code = tmp_10.Item2; if (mode == Mode.Condition) { // Merge adjacent conditions into the same if-statement int start = end; for (; start > 0 && _output[start - 1].A == mode; start--) { } LNode cond = _output[start].B; for (int i = start + 1; i <= end; i++) { cond = LNode.Call(CodeSymbols.And, LNode.List(cond, _output[i].B)).SetStyle(NodeStyle.Operator); } end = start; finalOutput = new WList <LNode> { LNode.Call(CodeSymbols.If, LNode.List(cond, finalOutput.ToVList().AsLNode(S.Braces))) }; } else { finalOutput.Insert(0, code); } } return(finalOutput.ToVList().AsLNode(S.Braces)); }
public static LNode ExpectAncestorStack(LNode node, IMacroContext context) { // Verify AncestorsAndPreviousSiblings Assert.AreEqual(node.ArgCount, context.AncestorsAndPreviousSiblings.Count); int index = 0; foreach (var expect in node.Args) { Assert.IsTrue(expect.Calls(S.Tuple)); var pair = context.AncestorsAndPreviousSiblings[index]; ExpectList(pair.Item1, expect.Args.WithoutLast(1)); if (!expect.Args.Last.IsIdNamed("#skip")) { Assert.AreEqual(expect.Args.Last, pair.Item2.Target); } index++; } // Verify PreviousSiblings var expectedPreviousSiblings = node.Args.Last.Args.WithoutLast(1); int i = 0; foreach (var expected in expectedPreviousSiblings) { if (!expected.IsIdNamed("#skip")) { Assert.AreEqual(expected, context.PreviousSiblings[i]); } i++; } return(LNode.Call(S.Splice)); // delete this node }
public static LNode saveAndRestore(LNode node, IMacroContext context) { var tmp_10 = context.GetArgsAndBody(true); var args = tmp_10.Item1; var body = tmp_10.Item2; if (args.Count == 1) { LNode newValue = null; { var tmp_11 = args[0]; LNode property; if (tmp_11.Calls(CodeSymbols.Assign, 2) && (property = tmp_11.Args[0]) != null && (newValue = tmp_11.Args[1]) != null || (property = tmp_11) != null) { string mainProp = KeyNameComponentOf(property).Name; string varPrefix = "old" + mainProp + "_"; LNode varName, varDecl = TempVarDecl(context, property, out varName, varPrefix); LNode tryFinally = LNode.Call(CodeSymbols.Try, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(body)).SetStyle(NodeStyle.StatementBlock), LNode.Call(CodeSymbols.Finally, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Assign, LNode.List(property, varName)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.StatementBlock))))); if (newValue != null) { return(LNode.Call(CodeSymbols.Splice, LNode.List(varDecl, LNode.Call(CodeSymbols.Assign, LNode.List(property, newValue)).SetStyle(NodeStyle.Operator), tryFinally)).IncludingTriviaFrom(node)); } else { return(LNode.Call(CodeSymbols.Splice, LNode.List(varDecl, tryFinally)).IncludingTriviaFrom(node)); } } } } return(null); }
/// <summary>Adds additional trailing trivia to an attribute list.</summary> public static LNodeList PlusTrailingTrivia(this LNodeList attrs, LNode trivia) { LNodeList oldTrivia; attrs = WithoutTrailingTrivia(attrs, out oldTrivia); return(attrs.Add(LNode.Call(S.TriviaTrailing, oldTrivia.Add(trivia)))); }
public static LNode match(LNode node, IMacroContext context) { { LNode input; VList <LNode> contents; if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces)) { contents = node.Args[1].Args; var outputs = new WList <LNode>(); input = MaybeAddTempVarDecl(context, input, outputs); int next_i = 0; for (int case_i = 0; case_i < contents.Count; case_i = next_i) { var @case = contents[case_i]; if (!IsCaseLabel(@case)) { return(Reject(context, contents[0], "In 'match': expected 'case' statement")); } for (next_i = case_i + 1; next_i < contents.Count; next_i++) { var stmt = contents[next_i]; if (IsCaseLabel(stmt)) { break; } if (stmt.Calls(S.Break, 0)) { next_i++; break; } } var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1))); if (@case.Calls(S.Case) && @case.Args.Count > 0) { var codeGen = new CodeGeneratorForMatchCase(context, input, handler); foreach (var pattern in @case.Args) { outputs.Add(codeGen.GenCodeForPattern(pattern)); } } else // default: // Note: the extra {braces} around the handler are rarely // needed. They are added just in case the handler declares a // variable and a different handler declares another variable // by the same name, which is illegal unless we add braces. { outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement)); if (next_i < contents.Count) { context.Sink.Error(contents[next_i], "The default branch must be the final branch in a 'match' statement."); } } } return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false)))); } } return(null); }
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))); } } }
public static LNode IfUnless(LNode node, bool isUnless, IMessageSink sink) { var args = node.Args; LNode cond = args.TryGet(0, null), then = args.TryGet(1, null), elseKW = args.TryGet(2, null), @else = args.TryGet(3, null); if (cond == null) { return(null); } if (then == null) { return(Reject(sink, cond, "'{0}' statement ended early", isUnless ? "unless" : "if")); } if (isUnless) { cond = F.Call(S.Not, cond); } if (elseKW == null) { return(node.With(S.If, cond, then)); } if (!elseKW.IsIdNamed(_else)) { return(Reject(sink, elseKW, "'{0}': expected else clause or end-of-statement marker", isUnless ? "unless" : "if")); } if (@else.IsId && args.Count > 4) { @else = LNode.Call(@else.Name, new VList <LNode>(args.Slice(4)), node); } return(node.With(S.If, cond, then, @else)); }
public virtual LNode VisitInput(LNode stmt, IMessageSink sink) { LNode aliasSet; if ((stmt.Calls(_alias, 1) || stmt.CallsMin(S.Alias, 1)) && (aliasSet = stmt.Args[0]).Calls(S.Assign, 2)) { IEnumerable <KeyValuePair <LNode, LNode> > q; LNode alias = aliasSet.Args[0], replacement = aliasSet.Args[1], old; if (_definedAliases.TryGetValue(alias, out old)) { if (stmt.AttrNamed(S.Partial) == null || !old.Equals(replacement)) { sink.Warning(alias, "Redefinition of alias '{0}'", alias); } } else if ((q = _definedAliases.Where(pair => replacement.Equals(pair.Value))).Any()) { sink.Warning(replacement, "Aliases '{0}' and '{1}' have the same replacement value", q.First().Key, alias); } _definedAliases[alias] = replacement; return(LNode.Call(S.Splice, VList <LNode> .Empty)); // erase alias from output } return(null); }
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)))); }
/// <summary>Converts <see cref="ILNode"/> to <see cref="LNode"/> recursively.</summary> public static LNode ToLNode(this ILNode node) { if (node is LNode n) { return(n); } var attrs = LNodeList.Empty; for (int i = node.Min; i < -1; i++) { attrs.Add(ToLNode(node[i])); } switch (node.Kind) { case LNodeKind.Id: return(LNode.Id(attrs, node.Name, new SourceRange(node.Range), node.Style)); case LNodeKind.Literal: return(LNode.Literal(attrs, node.Value, new SourceRange(node.Range), node.Style)); default: var args = LNodeList.Empty; for (int i = 0, max = node.Max; i <= max; i++) { args.Add(ToLNode(node[i])); } var target = ToLNode(node.Target); return(LNode.Call(attrs, target, args, new SourceRange(node.Range), node.Style)); } }
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); }
public static LNode ECSharpRule(LNode node, IMacroContext context) { // This will be called for all methods and properties, so we have to // examine it for the earmarks of a rule definition. bool isProp; if (!(isProp = node.Calls(S.Property, 4)) && !node.Calls(S.Fn, 4)) { return(null); } LNode returnType = node.Args[0]; bool isToken; bool retValIsRule = (isToken = returnType.IsIdNamed(_token)) || returnType.IsIdNamed(_rule); var attrs = node.Attrs; LNode lastAttr = null; if (!retValIsRule) { if (attrs.IsEmpty) { return(null); } lastAttr = attrs.Last; if (!(isToken = lastAttr.IsIdNamed(_hash_token)) && !lastAttr.IsIdNamed(_hash_rule)) { return(null); } attrs.RemoveAt(attrs.Count - 1); } else { returnType = F.Void; } //node = context.PreProcessChildren(); LNode name = node.Args[1]; LNode args = node.Args[2]; if (args.IsIdNamed(S.Missing)) // @`` { args = F.List(); // output will be a #fn, which does not allow @`` as its arg list } LNode newBody = ParseRuleBody(node.Args.Last, context); if (newBody != null) { return(LNode.Call(isToken ? _hash_token : _hash_rule, new VList <LNode> { returnType, name, args, newBody }, node.Range, node.Style).WithAttrs(attrs)); } else { return(null); } }
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); }
[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); }
/// <summary>Removes all existing trailing trivia from an attribute list and adds a new list of trailing trivia.</summary> /// <remarks>This method has a side-effect of recreating the %trailing /// node, if there is one, at the end of the attribute list. If <c>trivia</c> /// is empty then all calls to %trailing are removed.</remarks> public static LNodeList WithTrailingTrivia(this LNodeList attrs, LNodeList trivia) { var attrs2 = WithoutTrailingTrivia(attrs); if (trivia.IsEmpty) { return(attrs2); } return(attrs2.Add(LNode.Call(S.TriviaTrailing, trivia))); }
public static LNode ECSharpRule(LNode node, IMacroContext context) { // This will be called for all methods and properties, so we have to // examine it for the earmarks of a rule definition. bool isProp; if (!(isProp = node.Calls(S.Property, 4)) && !node.Calls(S.Fn, 4)) { return(null); } LNode returnType = node.Args[0]; bool isToken; bool retValIsRule = (isToken = returnType.IsIdNamed(_token)) || returnType.IsIdNamed(_rule); var attrs = node.Attrs; if (!retValIsRule) { int?i_rule = attrs.FinalIndexWhere(n => n.IsIdNamed(_hash_token) || n.IsIdNamed(_hash_rule)); if (i_rule == null) { return(null); } isToken |= attrs[i_rule.Value].IsIdNamed(_hash_token); attrs.RemoveAt(i_rule.Value); } else { returnType = F.Void; } //node = context.PreProcessChildren(); LNode name = node.Args[1]; LNode args = node.Args[2]; if (args.IsIdNamed(S.Missing)) // @`` { args = F.AltList(); // output will be a #fn, which does not allow @`` as its arg list } LNode newBody = ParseRuleBody(node.Args.Last, context); if (newBody != null) { // #rule($returnType, $name, $args, $newBody) return(LNode.Call(isToken ? _hash_token : _hash_rule, LNode.List(returnType, name, args, newBody), node.Range, node.Style).WithAttrs(attrs)); } else { return(null); } }
[LexicalMacro("match (var) { case ...: ... }; // In LES, use a => b instead of case a: b", "Attempts to match and deconstruct an object against a \"pattern\", such as a tuple or an algebraic data type. Example:\n" + "match (obj) { \n" + " case is Shape(ShapeType.Circle, $size, Location: $p is Point<int>($x, $y)): \n" + " Circle(size, x, y); \n" + "}\n\n" + "This is translated to the following C# code: \n" + "do { \n" + " Point<int> p; \n" + " Shape tmp1; \n" + " if (obj is Shape) { \n" + " var tmp1 = (Shape)obj; \n" + " if (tmp1.Item1 == ShapeType.Circle) { \n" + " var size = tmp1.Item2; \n" + " var tmp2 = tmp1.Location; \n" + " if (tmp2 is Point<int>) { \n" + " var p = (Point<int>)tmp2; \n" + " var x = p.Item1; \n" + " var y = p.Item2; \n" + " Circle(size, x, y); \n" + " break; \n" + " } \n" + " }\n" + " }\n" + "} while(false); \n" + "`break` is not expected at the end of each handler (`case` code block), but it can " + "be used to exit early from a `case`. You can associate multiple patterns with the same " + "handler using `case pattern1, pattern2:` in EC#, but please note that (due to a " + "limitation of plain C#) this causes code duplication since the handler will be repeated " + "for each pattern.")] public static LNode match(LNode node, IMacroContext context) { { LNode input; VList <LNode> contents; if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces)) { contents = node.Args[1].Args; var outputs = new WList <LNode>(); input = MaybeAddTempVarDecl(input, outputs); int next_i = 0; for (int case_i = 0; case_i < contents.Count; case_i = next_i) { var @case = contents[case_i]; if (!IsCaseLabel(@case)) { return(Reject(context, contents[0], "In 'match': expected 'case' statement")); } for (next_i = case_i + 1; next_i < contents.Count; next_i++) { var stmt = contents[next_i]; if (IsCaseLabel(stmt)) { break; } if (stmt.Calls(S.Break, 0)) { next_i++; break; } } var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1))); if (@case.Calls(S.Case) && @case.Args.Count > 0) { var codeGen = new CodeGeneratorForMatchCase(context, input, handler); foreach (var pattern in @case.Args) { outputs.Add(codeGen.GenCodeForPattern(pattern)); } } else { outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement)); if (next_i < contents.Count) { context.Write(Severity.Error, contents[next_i], "The default branch must be the final branch in a 'match' statement."); } } } return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false)))); } } return(null); }
public void Visit(LNode node) { node.Call(this); }