Esempio n. 1
0
		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);
		}
Esempio n. 2
0
		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));`");
			}
		}
Esempio n. 3
0
		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()));
		}
Esempio n. 4
0
            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));
                    }
                }
            }
Esempio n. 5
0
        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)));
        }
Esempio n. 6
0
        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));
        }
Esempio n. 7
0
        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;
			}
Esempio n. 9
0
        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);
            }
        }
Esempio n. 10
0
		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);
		}
Esempio n. 11
0
		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);
		}
Esempio n. 12
0
		/// <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));
		}
Esempio n. 13
0
		/// <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;
			}
		}
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
		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()));
		}
Esempio n. 16
0
        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);
            }
        }
Esempio n. 17
0
		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);
			}
		}
Esempio n. 18
0
        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));
                }
            }
        }