public override Pred CodeToTerminalPred(LNode expr, ref string errorMsg) { bool isInt = false; PGIntSet set; if (expr.IsIdNamed(_underscore)) { set = PGIntSet.AllExceptEOF; } else if (expr.IsIdNamed(_EOF)) { set = PGIntSet.EOF; } else if (expr.Calls(S.DotDot, 2)) { int? from = ConstValue(expr.Args[0], ref isInt); int? to = ConstValue(expr.Args[1], ref isInt); if (from == null || to == null) { errorMsg = "Expected int32 or character literal on each side of «..»"; return null; } set = PGIntSet.WithRanges(from.Value, to.Value); } else if (expr.Value is string) { return Pred.Seq((string)expr.Value); } else { int? num = ConstValue(expr, ref isInt); if (num == null) { errorMsg = "Unrecognized expression. Expected int32 or character literal instead of: " + expr.ToString(); // warning return null; } set = PGIntSet.With(num.Value); } set.IsCharSet = !isInt; return new TerminalPred(expr, set, true); }
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));`"); } }
public virtual LNode GenerateSwitch(IPGTerminalSet[] branchSets, MSet<int> casesToInclude, LNode[] branchCode, LNode defaultBranch, LNode laVar) { Debug.Assert(branchSets.Length == branchCode.Length); WList<LNode> stmts = new WList<LNode>(); for (int i = 0; i < branchSets.Length; i++) { if (casesToInclude.Contains(i)) { int index = -1; foreach (LNode value in GetCases(branchSets[i])) { var label = F.Call(S.Case, value); if (++index > 0 && (index % 4) != 0) // write 4 cases per line label = label.PlusAttr(F.Id(S.TriviaAppendStatement)); stmts.Add(label); if (stmts.Count > 65535) // sanity check throw new InvalidOperationException("switch is too large to generate"); } AddSwitchHandler(branchCode[i], stmts); } } if (!defaultBranch.IsIdNamed(S.Missing)) { stmts.Add(F.Call(S.Label, F.Id(S.Default))); AddSwitchHandler(defaultBranch, stmts); } return F.Call(S.Switch, (LNode)laVar, F.Braces(stmts.ToVList())); }
void ProcessEnsuresAttribute(LNodeList 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.StatementBlock))).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.StatementBlock))).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.StatementBlock))).SetStyle(NodeStyle.Special)); } } }
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 SPResult AutoPrintMethodDefinition() { // S.Fn, S.Delegate: #fn(#int32, Square, #(int x), { return x * x; }); if (EcsValidators.MethodDefinitionKind(_n, true, Pedantics) == null) { return(SPResult.Fail); } LNode retType = _n.Args[0], name = _n.Args[1]; LNode args = _n.Args[2]; LNode body = _n.Args[3, null]; bool isConstructor = _name == S.Constructor; bool isDestructor = !isConstructor && name.Calls(S._Destruct, 1); LNode firstStmt = null; if (isConstructor && body != null && body.CallsMin(S.Braces, 1)) { // Detect ": this(...)" or ": base(...)" firstStmt = body.Args[0]; if (!CallsWPAIH(firstStmt, S.This) && !CallsWPAIH(firstStmt, S.Base)) { firstStmt = null; } } if (!_o.AllowConstructorAmbiguity) { if (isDestructor && _spaceName == S.Fn) { // When destructor syntax is ambiguous, use prefix notation. return(SPResult.Fail); } else if (isConstructor && firstStmt == null) { // When constructor syntax is ambiguous, use prefix notation. if (name.IsIdNamed(S.This)) { if (_spaceName == S.Fn) { return(SPResult.Fail); } } else if (!name.IsIdNamed(_spaceName)) { return(SPResult.Fail); } } } // A cast operator with the structure: #fn(Foo, operator`#cast`, #(...)) // can be printed in a special format: operator Foo(...); bool isCastOperator = (name.Name == S.Cast && name.AttrNamed(S.TriviaUseOperatorKeyword) != null); PrintTypeAndName(isConstructor || isDestructor, isCastOperator, isConstructor && !name.IsIdNamed(S.This) ? AttrStyle.IsConstructor : AttrStyle.IsDefinition); PrintTrivia(args, trailingTrivia: false); PrintArgList(args.Args, ParenFor.MethodDecl, true, _o.OmitMissingArguments); PrintTrivia(args, trailingTrivia: true); PrintWhereClauses(name); // If this is a constructor where the first statement is this(...) or // base(...), we must change the notation to ": this(...) {...}" as // required in plain C# if (firstStmt != null) { using (Indented) { if (!IsDefaultNewlineSuppressed(firstStmt)) { Newline(NewlineOpt.BeforeConstructorColon); } Space(SpaceOpt.BeforeConstructorColon); WriteThenSpace(':', SpaceOpt.AfterColon); PrintExpr(firstStmt, StartExpr, Ambiguity.NoBracedBlock); } } return(AutoPrintBodyOfMethodOrProperty(body, firstStmt != null)); }
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))); }
LNode EliminateSequenceExpressionsInLambdaExpr(LNode expr, LNode retType) { var stmt = EliminateSequenceExpressions(expr, false); if (stmt.Calls(__numrunSequence)) { stmt = stmt.WithTarget(S.Braces); if (!retType.IsIdNamed(S.Void)) { if (retType.IsIdNamed(S.Missing) && stmt.Args.Last.IsCall) Context.Sink.Warning(expr, "This lambda must be converted to a braced block, but in LeMP it's not possible to tell whether the return keyword is needed. The output assumes `return` is required."); stmt = stmt.WithArgChanged(stmt.Args.Count - 1, LNode.Call(CodeSymbols.Return, LNode.List(stmt.Args.Last))); } } return stmt; }
private BlockFlow DecodeBlockFlow( LNode node, FlowGraphBuilder graph, Dictionary <Symbol, BasicBlockBuilder> blocks, Dictionary <Symbol, ValueTag> valueTags) { if (node.Calls(CodeSymbols.Goto)) { Branch target; if (FeedbackHelpers.AssertArgCount(node, 1, Log) && AssertDecodeBranch(node.Args[0], graph, blocks, valueTags, out target)) { return(new JumpFlow(target)); } else { return(UnreachableFlow.Instance); } } else if (node.Calls(CodeSymbols.Switch)) { // Decode the value being switched on as well as the default branch. Instruction switchVal; Branch defaultTarget; if (FeedbackHelpers.AssertArgCount(node, 3, Log) && AssertDecodeInstruction(node.Args[0], valueTags, out switchVal) && AssertDecodeBranch(node.Args[1], graph, blocks, valueTags, out defaultTarget)) { // Decode the switch cases. var switchCases = ImmutableList.CreateBuilder <SwitchCase>(); foreach (var caseNode in node.Args[2].Args) { if (!FeedbackHelpers.AssertArgCount(caseNode, 2, Log) || !FeedbackHelpers.AssertIsCall(caseNode.Args[0], Log)) { continue; } var constants = ImmutableHashSet.CreateRange <Constant>( caseNode.Args[0].Args .Select(DecodeConstant) .Where(x => x != null)); Branch caseTarget; if (AssertDecodeBranch(caseNode.Args[1], graph, blocks, valueTags, out caseTarget)) { switchCases.Add(new SwitchCase(constants, caseTarget)); } } return(new SwitchFlow(switchVal, switchCases.ToImmutable(), defaultTarget)); } else { return(UnreachableFlow.Instance); } } else if (node.Calls(CodeSymbols.Return)) { Instruction retValue; if (FeedbackHelpers.AssertArgCount(node, 1, Log) && AssertDecodeInstruction(node.Args[0], valueTags, out retValue)) { return(new ReturnFlow(retValue)); } else { return(UnreachableFlow.Instance); } } else if (node.Calls(CodeSymbols.Try)) { Instruction tryValue; Branch successBranch; Branch exceptionBranch; if (FeedbackHelpers.AssertArgCount(node, 3, Log) && AssertDecodeInstruction(node.Args[0], valueTags, out tryValue) && AssertDecodeBranch(node.Args[1], graph, blocks, valueTags, out successBranch) && AssertDecodeBranch(node.Args[2], graph, blocks, valueTags, out exceptionBranch)) { return(new TryFlow(tryValue, successBranch, exceptionBranch)); } else { return(UnreachableFlow.Instance); } } else if (node.IsIdNamed(EncoderState.unreachableFlowSymbol)) { return(UnreachableFlow.Instance); } else { FeedbackHelpers.LogSyntaxError( Log, node, Quotation.QuoteEvenInBold( "unknown type of flow; expected one of ", CodeSymbols.Goto.Name, ", ", CodeSymbols.Switch.Name, ", ", CodeSymbols.Try.Name, ", ", CodeSymbols.Return.Name, " or ", EncoderState.unreachableFlowSymbol.Name, ".")); return(UnreachableFlow.Instance); } }
static LNode asAltList(LNode node) { return node.Calls(S.AltList) ? node : node.IsIdNamed(GSymbol.Empty) ? LNode.Call(S.AltList, node) : LNode.Call(S.AltList, LNode.List(node), node); }
Pred BranchToPred(LNode expr, out BranchMode mode, Context ctx) { if (expr.Calls(_Default, 1) || expr.Calls(_Default2, 1)) { expr = expr.Args[0]; mode = BranchMode.Default; } else if (expr.Calls(_Error, 1) || expr.IsIdNamed(_DefaultError)) { mode = (expr.AttrNamed(S.Continue) != null || expr.AttrNamed(GSymbol.Get("continue")) != null) ? BranchMode.ErrorContinue : BranchMode.ErrorExit; if (expr.Calls(_Error, 1)) expr = expr.Args[0]; else return DefaultErrorBranch.Value; } else mode = BranchMode.None; return NodeToPred(expr, ctx); }
/// <summary>Returns true iff the given node has a valid syntax tree for /// a property definition, and gets the component parts of the definition.</summary> /// <remarks>The body may be anything. If it calls CodeSymbols.Braces, it's a normal body.</remarks> public static bool IsPropertyDefinition(LNode n, out LNode retType, out LNode name, out LNode args, out LNode body, out LNode initialValue, Pedantics p = Pedantics.Lax) { var argCount = n.ArgCount; if (!CallsMinWPAIH(n, S.Property, 4, p) || n.ArgCount > 5) { retType = name = args = body = initialValue = null; return false; } retType = n.Args[0]; name = n.Args[1]; args = n.Args[2]; body = n.Args[3]; initialValue = n.Args[4, null]; return IsComplexIdentifier(retType, ICI.Default, p) && IsComplexIdentifier(name, ICI.Default | ICI.NameDefinition, p) && (args.IsIdNamed(S.Missing) || args.Calls(S.AltList)); }
/// <summary>If the given node has a valid syntax tree for a method definition, /// a constructor, or (when orDelegate is true) a delegate definition, gets /// the definition kind (#fn, #cons, or #delegate).</summary> /// <param name="retType">Return type of the method (if it's a constructor, this will be the empty identifier).</param> /// <param name="name">Name of the method.</param> /// <param name="args">args.Args is the argument list of the method.</param> /// <param name="body">The method body, or null if there is no method body. /// The method body calls <see cref="CodeSymbols.Braces"/> if the method is a /// non-lambda-style method.</param> /// <returns>The definition kind (#fn, #cons, or #delegate), or null if it's no kind of method.</returns> /// <remarks> /// Method declarations (no body) also count. /// <para/> /// A destructor counts as a #fn with a method name that calls the ~ operator. /// </remarks> public static Symbol MethodDefinitionKind(LNode n, out LNode retType, out LNode name, out LNode args, out LNode body, bool allowDelegate, Pedantics p = Pedantics.Lax) { retType = name = args = body = null; var kind = n.Name; if ((kind != S.Fn && kind != S.Delegate && kind != S.Constructor) || !HasSimpleHeadWPA(n, p)) return null; if (!n.ArgCount.IsInRange(3, kind == S.Delegate ? 3 : 4)) return null; retType = n.Args[0]; name = n.Args[1]; args = n.Args[2]; body = n.Args[3, null]; if (kind == S.Constructor && !retType.IsIdNamed(S.Missing)) return null; // Note: the parser doesn't require that the argument list have a // particular format, so the printer doesn't either. if (!CallsWPAIH(args, S.AltList, p)) return null; if (kind == S.Constructor && ((body != null && !CallsWPAIH(body, S.Braces, p) && !CallsWPAIH(body, S.Forward, 1, p)) || !retType.IsIdNamed(S.Missing))) return null; if (IsComplexIdentifier(name, ICI.Default | ICI.NameDefinition, p)) { return IsComplexIdentifier(retType, ICI.Default | ICI.AllowAttrs, p) ? kind : null; } else { // Check for a destructor return retType.IsIdNamed(S.Missing) && CallsWPAIH(name, S._Destruct, 1, p) && IsSimpleIdentifier(name.Args[0], p) ? kind : null; } }
public bool AutoPrintNewOperator(Precedence precedence, Precedence context, Ambiguity flags) { // Prints the new Xyz(...) {...} operator Debug.Assert(_n.Name == S.New); int argCount = _n.ArgCount; if (argCount == 0) { return(false); } bool needParens; Debug.Assert(CanAppearIn(precedence, context, out needParens) && !needParens); LNode cons = _n.Args[0]; LNode type = cons.Target; var consArgs = cons.Args; // There are two basic uses of new: for objects, and for arrays. // In all cases, #new has 1 arg plus optional initializer arguments, // and there's always a list of "constructor args" even if it is empty // (exception: new {...}). // 1. Init an object: 1a. new Foo<Bar>() { ... } <=> #new(Foo<bar>(...), ...) // 1b. new { ... } <=> #new(@``, ...) // 2. Init an array: 2a. new int[] { ... }, <=> #new(int[](), ...) <=> #new(#of(@`[]`, int)(), ...) // 2b. new[,] { ... }. <=> #new(@`[,]`(), ...) // 2c. new int[10,10] { ... }, <=> #new(#of(@`[,]`, int)(10,10), ...) // 2d. new int[10][] { ... }, <=> #new(#of(@`[]`, #of(@`[]`, int))(10), ...) if (HasPAttrs(cons)) { return(false); } if (type == null ? !cons.IsIdNamed(S.Missing) : HasPAttrs(type) || !IsComplexIdentifier(type)) { return(false); } // Okay, we can now be sure that it's printable, but is it an array decl? if (type == null) { // 1b, new {...} _out.Write("new ", true); PrintBracedBlockInNewExpr(); } else if (type != null && type.IsId && S.CountArrayDimensions(type.Name) > 0) // 2b { _out.Write("new", true); _out.Write(type.Name.Name, true); Space(SpaceOpt.Default); PrintBracedBlockInNewExpr(); } else { _out.Write("new ", true); int dims = CountDimensionsIfArrayType(type); if (dims > 0 && cons.Args.Count == dims) { PrintTypeWithArraySizes(cons); } else { // Otherwise we can print the type name without caring if it's an array or not. PrintType(type, EP.Primary.LeftContext(context)); if (cons.ArgCount != 0 || (argCount == 1 && dims == 0)) { PrintArgList(cons, ParenFor.MethodCall, cons.ArgCount, 0, OmitMissingArguments); } } if (_n.Args.Count > 1) { PrintBracedBlockInNewExpr(); } } return(true); }
public virtual LNode GenerateSwitch(IPGTerminalSet[] branchSets, MSet<int> casesToInclude, LNode[] branchCode, LNode defaultBranch, LNode laVar) { Debug.Assert(branchSets.Length == branchCode.Length); RWList<LNode> stmts = new RWList<LNode>(); for (int i = 0; i < branchSets.Length; i++) { if (casesToInclude.Contains(i)) { foreach (LNode value in GetCases(branchSets[i])) { stmts.Add(F.Call(S.Case, value)); if (stmts.Count > 65535) // sanity check throw new InvalidOperationException("switch is too large to generate"); } AddSwitchHandler(branchCode[i], stmts); } } if (!defaultBranch.IsIdNamed(S.Missing)) { stmts.Add(F.Call(S.Label, F.Id(S.Default))); AddSwitchHandler(defaultBranch, stmts); } return F.Call(S.Switch, (LNode)laVar, F.Braces(stmts.ToRVList())); }
public void BasicTests() { var parsed = Les2LanguageService.Value.Parse((UString) @" // Leading comment x = random.NextInt(); // Comment nodes extend a node's range, which could certainly, in principle, // affect LNodeRangeMapper's ability to do its job properly. But given // a range covering the text `x = random.NextInt()`, it should still decide // that the node for `x = random.NextInt()` is a better match than, say, `x` // or `random.NextInt()` or the `if` block below. if x > ExtraordinarilyLongIdentifier { return x - ExtraordinarilyLongIdentifier; } else { Log.Write(Severity.Error, ""Unexpectedly low x""); // Trailing comment return -(1); } // Trailing comment" , "Input.les").ToList(); // Replace first "return" statement with a synthetic call to #return LNode originalFirstReturn = parsed[1][1][0]; parsed[1] = parsed[1].WithArgChanged(1, parsed[1][1].WithArgChanged(0, LNode.Call(S.Return, LNode.List(originalFirstReturn[0])))); LNode assignment = parsed[0], @if = parsed[1], logWrite = @if[3][0], firstReturn = @if[1][0], random = assignment[1].Target[0]; // Verify we've correctly extracted parts of the input tree IsTrue(@if[1].Calls(S.Braces) && @if[3].Calls(S.Braces)); IsTrue(firstReturn.Calls(S.Return) && random.IsIdNamed("random")); AreEqual("Input.les", @if.Target.Range.Source.FileName); AreSame(EmptySourceFile.Synthetic, firstReturn.Range.Source); // Create a simulated output file mapping in which all indexes are multiplied by 2 IndexRange TweakedRange(IIndexRange r) => new IndexRange(r.StartIndex * 2, r.Length * 2); var mapper = new LNodeRangeMapper(); foreach (var node in parsed.SelectMany(stmt => stmt.DescendantsAndSelf()).Where(n => n.Range.StartIndex >= 0)) { mapper.SaveRange(node, TweakedRange(node.Range)); } // In real life, synthetic nodes do get their range saved, but here we must do it manually mapper.SaveRange(firstReturn, TweakedRange(originalFirstReturn.Range)); IndexRange CallFindRelatedNode_AndExpectFirstFoundNodeToBe(LNode node, IndexRange searchQuery, int maxSearchResults) { var list = mapper.FindRelatedNodes(searchQuery, 10); AreEqual(node, list[0].Item1); return(list[0].B); } // Let the tests begin. foreach (var node in new[] { assignment, @if, logWrite, random }) { // Given perfect input, FindRelatedNodes should always list the correct node first var range = CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range), 10); AreEqual(TweakedRange(node.Range), range); // FindMostUsefulRelatedNode will find the same result var pair2 = mapper.FindMostUsefulRelatedNode(TweakedRange(node.Range), node.Range.Source); AreEqual(node, pair2.Item1); AreEqual(TweakedRange(node.Range), pair2.Item2); } // However, the firstReturn is synthetic. It can still be found with FindRelatedNodes(), // but `FindMostUsefulRelatedNode` won't return it because its source file is wrong. // Instead, the best match should be the first argument to #return. CallFindRelatedNode_AndExpectFirstFoundNodeToBe(firstReturn, TweakedRange(originalFirstReturn.Range), 10); var bestPair = mapper.FindMostUsefulRelatedNode(TweakedRange(originalFirstReturn.Range), originalFirstReturn.Range.Source); AreEqual(firstReturn[0], bestPair.Item1); AreEqual(TweakedRange(firstReturn[0].Range), bestPair.Item2); // Compute and test the target range for `x = random.NextInt()` with comments excluded var assignmentRange = new IndexRange(assignment[0].Range.StartIndex, assignment[1].Range.EndIndex); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(assignment, TweakedRange(assignmentRange), 10); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(assignment, TweakedRange(assignmentRange), 1); // Given a slightly skewed range, it should still find the nearest node. foreach (var node in new[] { assignment, @if, logWrite, random }) { CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex += 2; r.EndIndex += 2; }), 10); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex -= 2; r.EndIndex -= 2; }), 10); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex += 2; r.EndIndex -= 2; }), 10); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex -= 2; r.EndIndex += 2; }), 10); // We don't need to ask for 10 search results either, not in code this simple CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex += 2; r.EndIndex += 2; }), 1); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex -= 2; r.EndIndex -= 2; }), 1); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex += 2; r.EndIndex -= 2; }), 1); CallFindRelatedNode_AndExpectFirstFoundNodeToBe(node, TweakedRange(node.Range).With(r => { r.StartIndex -= 2; r.EndIndex += 2; }), 1); } }
protected virtual LNode DefaultOf(LNode type, bool wantList) { if (wantList) { return ReplaceT(ListInitializer, type); } else { if (type.IsIdNamed(S.Int32)) return F.Literal(0); return F.Call(S.Default, type); } }
public static LNode QuickProp(LNode node, IMacroContext context) { { LNode getExpr = null, setExpr = null, sig, tmp_10 = null, tmp_11 = null; if (node.Calls((Symbol)"'get", 2) && (sig = node.Args[0]) != null && (tmp_10 = node.Args[1]) != null && tmp_10.Calls((Symbol)"'set", 2) && (getExpr = tmp_10.Args[0]) != null && (setExpr = tmp_10.Args[1]) != null || node.Calls((Symbol)"'set", 2) && (sig = node.Args[0]) != null && (tmp_11 = node.Args[1]) != null && tmp_11.Calls((Symbol)"'get", 2) && (setExpr = tmp_11.Args[0]) != null && (getExpr = tmp_11.Args[1]) != null || node.Calls((Symbol)"'get", 2) && (sig = node.Args[0]) != null && (getExpr = node.Args[1]) != null || node.Calls((Symbol)"'set", 2) && (sig = node.Args[0]) != null && (setExpr = node.Args[1]) != null) { // Deconstruct the signature { LNode name, type; if (sig.Calls(CodeSymbols.Colon, 2) && (name = sig.Args[0]) != null && (type = sig.Args[1]) != null) { // Build C# property body (the stuff in braces) LNode get = ToCSharpGetOrSet(getExpr, sy_get); LNode set = ToCSharpGetOrSet(setExpr, sy_set); LNode body; if (setExpr == null) { body = LNode.Call(CodeSymbols.Braces, LNode.List(get)).SetStyle(NodeStyle.StatementBlock); } else if (getExpr == null) { body = LNode.Call(CodeSymbols.Braces, LNode.List(set)).SetStyle(NodeStyle.StatementBlock); } else { body = LNode.Call(CodeSymbols.Braces, LNode.List(get, set)).SetStyle(NodeStyle.StatementBlock); } // Detect indexer (e.g. this[index: int]) LNode args = LNode.Missing; { LNode name_apos; LNodeList args_apos; if (name.CallsMin(CodeSymbols.IndexBracks, 1) && (name_apos = name.Args[0]) != null) { args_apos = new LNodeList(name.Args.Slice(1)); name = name_apos; args = LNode.Call(CodeSymbols.AltList, LNode.List(args_apos)); } } // Detect property initializer (C# 6) LNode output; { LNode initializer, type_apos; if (type.Calls(CodeSymbols.Assign, 2) && (type_apos = type.Args[0]) != null && (initializer = type.Args[1]) != null) { output = LNode.Call(CodeSymbols.Property, LNode.List(type_apos, name, args, body, initializer)); } else { output = LNode.Call(CodeSymbols.Property, LNode.List(type, name, args, body)); } } return(output.WithAttrs(node.Attrs)); } } } } return(null); // Assume it's not a property decl LNode ToCSharpGetOrSet(LNode getExpr, Symbol get_) { if (getExpr == null) { return(null); } LNode get = LNode.Id(get_); if (getExpr.Calls(S.Braces)) { return(LNode.Call(get, LNode.List(getExpr)).SetBaseStyle(NodeStyle.Special)); } else if (getExpr.IsIdNamed("_")) { return(get); } else { return(LNode.Call(CodeSymbols.Lambda, LNode.List(get, getExpr)).SetStyle(NodeStyle.Operator)); } } }