Пример #1
0
        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);
        }
Пример #2
0
        [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);
        }
Пример #3
0
		public static LNode ForwardProperty(LNode prop, IMessageSink sink)
		{
			LNode name, fwd, body;
			if (prop.ArgCount != 3)
				return null;
			LNode target = GetForwardingTarget(fwd = prop.Args[2], name = prop.Args[1]);
			if (target != null)
			{
				body = F.Braces(new RVList<LNode>(
					F.Call(S.get, F.Braces(F.Call(S.Return, target))),
					F.Call(S.set, F.Braces(F.Call(S.Assign, target, F.Id(S.value))))));

				return prop.WithArgChanged(2, body);
			}
			else if ((body = fwd).Calls(S.Braces))
			{
				var body2 = body.WithArgs(stmt => {
					if (stmt.Calls(S.get, 1) && (target = GetForwardingTarget(stmt.Args[0], name)) != null)
						return stmt.WithArgs(new RVList<LNode>(F.Braces(F.Call(S.Return, target))));
					if (stmt.Calls(S.set, 1) && (target = GetForwardingTarget(stmt.Args[0], name)) != null)
						return stmt.WithArgs(new RVList<LNode>(F.Braces(F.Call(S.Assign, target, F.Id(S.value)))));
					return stmt;
				});
				if (body2 != body)
					return prop.WithArgChanged(2, body2);
			}
			return null;
		}
Пример #4
0
        public static LNode ForwardProperty(LNode prop, IMacroContext context)
        {
            LNode name, fwd, body;

            if (prop.ArgCount != 4)
            {
                return(null);
            }
            LNode target = GetForwardingTarget(fwd = prop.Args[3], name = prop.Args[1]);

            if (target != null)
            {
                body = F.Braces(F.Call(S.get, F.Braces(F.Call(S.Return, target))));
                return(prop.WithArgChanged(3, body));
            }
            else if ((body = fwd).Calls(S.Braces))
            {
                var body2 = body.WithArgs(stmt => {
                    if (stmt.Calls(S.get, 1) && (target = GetForwardingTarget(stmt.Args[0], name)) != null)
                    {
                        return(stmt.WithArgs(new VList <LNode>(F.Braces(F.Call(S.Return, target)))));
                    }
                    if (stmt.Calls(S.set, 1) && (target = GetForwardingTarget(stmt.Args[0], name)) != null)
                    {
                        return(stmt.WithArgs(new VList <LNode>(F.Braces(F.Call(S.Assign, target, F.Id(S.value))))));
                    }
                    return(stmt);
                });
                if (body2 != body)
                {
                    return(prop.WithArgChanged(3, body2));
                }
            }
            return(null);
        }
Пример #5
0
        static LNode ProcessArgContractAttributes(LNode fn, int argsIndex, CodeContractRewriter rw, bool isLambda = false)
        {
            LNode fnArgs = fn.Args[argsIndex];

            if (fnArgs.CallsMin(isLambda ? S.Tuple : S.AltList, 1))
            {
                return(fn.WithArgChanged(argsIndex,
                                         fnArgs.WithArgs(arg => {
                    if (arg.HasAttrs)
                    {
                        return arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg)));
                    }
                    return arg;
                })));
            }
            else if (isLambda)
            {
                var arg = fnArgs;                       // just one argument
                if (arg.HasAttrs)
                {
                    fn = fn.WithArgChanged(argsIndex,
                                           arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg))));
                }
            }
            return(fn);
        }
Пример #6
0
        public static LNode of(LNode node, IMessageSink sink)
        {
            LNode kind;

            if (node.ArgCount == 2 && (kind = node.Args[0]).IsId)
            {
                if (kind.IsIdNamed(_array))
                {
                    return(node.WithArgChanged(0, kind.WithName(S.Array)));
                }
                if (kind.IsIdNamed(_opt))
                {
                    return(node.WithArgChanged(0, kind.WithName(S.QuestionMark)));
                }
                if (kind.IsIdNamed(_ptr))
                {
                    return(node.WithArgChanged(0, kind.WithName(S._Pointer)));
                }
            }
            else if (node.ArgCount == 3 && (kind = node.Args[0]).IsIdNamed(_array) && node.Args[1].IsLiteral)
            {
                return(node.WithArgs(kind.WithName(S.GetArrayKeyword((int)node.Args[1].Value)), node.Args[2]));
            }
            return(null);
        }
Пример #7
0
        [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);
        }
Пример #8
0
 protected virtual LNode MakeSuperExpr(LNode lhs, ref LNode primary, RVList <LNode> rhs)
 {
     if (primary == null)
     {
         return(lhs);                // an error should have been printed already
     }
     if (lhs == primary)
     {
         if (primary.BaseStyle == NodeStyle.Operator)
         {
             primary = F.Call(primary, rhs);
         }
         else
         {
             primary = lhs.WithArgs(lhs.Args.AddRange(rhs));
         }
         MarkSpecial(primary);
         return(primary);
     }
     else
     {
         Debug.Assert(lhs != null && lhs.IsCall && lhs.ArgCount > 0);
         Debug.Assert(lhs.BaseStyle != NodeStyle.Special);
         int   c  = lhs.ArgCount - 1;
         LNode ce = MakeSuperExpr(lhs.Args[c], ref primary, rhs);
         return(lhs.WithArgChanged(c, ce));
     }
 }
Пример #9
0
		public static LNode ForwardProperty(LNode prop, IMacroContext context)
		{
			LNode name, fwd, body;
			if (prop.ArgCount != 4)
				return null;
			LNode target = GetForwardingTarget(name = prop.Args[1], fwd = prop.Args[3]);
			if (target != null)
			{
				body = F.Braces(F.Call(S.get, F.Braces(F.Call(S.Return, target))).SetBaseStyle(NodeStyle.Special));
				return prop.WithArgChanged(3, body);
			}
			else if ((body = fwd).Calls(S.Braces))
			{
				var body2 = body.WithArgs(stmt => {
					if (stmt.Calls(S.get, 1) && (target = GetForwardingTarget(name, stmt.Args[0])) != null)
						return stmt.WithArgs(new VList<LNode>(F.Braces(F.Call(S.Return, target))));
					if (stmt.Calls(S.set, 1) && (target = GetForwardingTarget(name, stmt.Args[0])) != null)
						return stmt.WithArgs(new VList<LNode>(F.Braces(F.Call(S.Assign, target, F.Id(S.value)))));
					return stmt;
				});
				if (body2 != body)
					return prop.WithArgChanged(3, body2);
			}
			return null;
		}
Пример #10
0
		public static LNode ForwardMethod(LNode fn, IMessageSink sink)
		{
			LNode args, fwd, body;
			if (fn.ArgCount != 4 || !(fwd = fn.Args[3]).Calls(S.Forward, 1) || !(args = fn.Args[2]).Calls(S.List))
				return null;
			
			RVList<LNode> formalArgs = args.Args;
			RVList<LNode> argList =	RVList<LNode>.Empty;
			foreach (var formalArg in formalArgs)
			{
				if (!formalArg.Calls(S.Var, 2))
					return Reject(sink, formalArg, "'==>' expected a variable declaration here");
				LNode argName = formalArg.Args[1];
				if (argName.Calls(S.Assign, 2))
					argName = argName.Args[0];
				LNode @ref = formalArg.AttrNamed(S.Ref) ?? formalArg.AttrNamed(S.Out);
				if (@ref != null)
					argName = argName.PlusAttr(@ref);
				argList.Add(argName);
			}

			LNode target = GetForwardingTarget(fwd, fn.Args[1]);
			LNode call = F.Call(target, argList);
			
			bool isVoidFn = fn.Args[0].IsIdNamed(S.Void);
			body = F.Braces(isVoidFn ? call : F.Call(S.Return, call));
			return fn.WithArgChanged(3, body);
		}
Пример #11
0
 // Creates a temporary for an LValue (left side of `=`, or `ref` parameter)
 // e.g. f(x).Foo becomes f(x_N).Foo, and `var x_N = x` is added to `stmtSequence`,
 // where N is a unique integer for the temporary variable.
 LNode MaybeCreateTemporaryForLValue(LNode expr, ref VList <LNode> stmtSequence)
 {
     {
         LNode _, lhs;
         if (expr.Calls(CodeSymbols.Dot, 2) && (lhs = expr.Args[0]) != null || expr.CallsMin(CodeSymbols.Of, 1) && (lhs = expr.Args[0]) != null)
         {
             return(expr.WithArgChanged(0, MaybeCreateTemporaryForLValue(lhs, ref stmtSequence)));
         }
         else if ((_ = expr) != null && !_.IsCall)
         {
             return(expr);
         }
         else
         {
             var args = expr.Args.ToWList();
             int i    = 0;
             if (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1))
             {
                 // Consider foo[i]. We cannot always store `foo` in a temporary, as
                 // this may change the code's behavior in case `foo` is a struct.
                 i = 1;
             }
             for (; i < args.Count; i++)
             {
                 if (!args[i].IsLiteral && !args[i].Attrs.Contains(_trivia_isTmpVar))
                 {
                     LNode tmpVarName;
                     stmtSequence.Add(TempVarDecl(Context, args[i], out tmpVarName));
                     args[i] = tmpVarName.PlusAttr(_trivia_isTmpVar);
                 }
             }
             return(expr.WithArgs(args.ToVList()));
         }
     }
 }
Пример #12
0
        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);
        }
Пример #13
0
        public static LNode IfUnless(LNode node, IMacroContext context)
        {
            // #if(cond1, {...}, #elsif(cond2, {...}), #else({...}));
            // #unless(cond1, {...}, #else({...}));
            var  args     = node.Args;
            bool isUnless = node.Calls(__unless) && args.Count >= 2;

            if (isUnless)
            {
                node = node.WithArgChanged(0, F.Call(S.Not, args[0]));
            }

            if (args.Count >= 3)
            {
                LNode clause   = args[2];
                bool  isElseIf = clause.Calls(__elsif) || clause.Calls(__elseif);
                if (clause.Calls(S.Else, 2) && clause[0].Calls("if", 1))
                {
                    // Although it's possible to accept "else if (foo)", "else if foo {...}"
                    // would be parsed quite wrongly as "else (if foo {...})"! So issue a
                    // warning to discourage the bad habit of writing "else if".
                    context.Warning(clause[0].Target, "'else if' should be one word (elsif or elseif)");
                    isElseIf = true;
                    clause   = clause.WithArgChanged(0, clause[0][0]);
                }
                if (isElseIf)
                {
                    var first3 = args.WithoutLast(args.Count - 3);
                    // node: #if(cond1, {...}, #elsif(cond2, {...}), #elsif(cond3, {...}), #else({...}))
                    //                        ^^^^^^^clause^^^^^^^
                    //          ^^^^^^^^^^^^first3^^^^^^^^^^^^^^^^
                    // returns: #if(cond1, {...}, #if(cond2, {...}, #elsif(cond3, {...}), #else({...})))
                    LNode @else = clause.WithTarget(S.If);
                    if (args.Count > 3)
                    {
                        @else = @else.WithArgs(@else.Args.AddRange(args.Slice(3)));
                    }
                    return(node.WithArgs(first3.WithoutLast(1).Add(@else)));
                }
                if (clause.Calls(S.Else, 1) && args.Count == 3)
                {
                    return(node.WithArgChanged(2, clause[0]));
                }
            }

            return(isUnless ? node : null);
        }
Пример #14
0
 public static LNode priorityTestHi(LNode node, IMessageSink sink)
 {
     if (node.ArgCount >= 1 && !node[0].IsIdNamed("hi"))
     {
         return(node.WithArgChanged(0, LNode.Id("hi")));
     }
     return(null);
 }
Пример #15
0
        public static LNode ContractsOnMethod(LNode fn, IMacroContext context)
        {
            // Performance note: one should keep in mind that this macro usually
            // has no effect. It looks for contracts and usually finds none, so
            // we should try to search quickly. Luckily, LNode methods like
            // n.WithArgChanged(i,N) do not allocate a new node if the new value
            // equals the old value (if n[i] == N).
            LNode oldFn = fn;

            if (fn.ArgCount >= 4)
            {
                var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context);

                // If this thing has an argument list, scan it
                fn = ProcessArgContractAttributes(fn, 2, rw);

                // Scan attributes on return type, then attributes on the whole method
                if (fn.Args[0].HasAttrs)
                {
                    fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null)));
                }
                if (fn.HasAttrs)
                {
                    fn = fn.WithAttrs(rw.Process(fn.Attrs, null));
                }

                if (rw.PrependStmts.IsEmpty)
                {
                    return(null);                       // this is the common case
                }
                else
                {
                    var body = fn.Args[3];
                    if (!body.Calls(S.Braces)                           // Add braces in case of void LambdaMethod() => expr;
                        )
                    {
                        body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement);
                    }
                    body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts));
                    fn   = fn.WithArgChanged(3, body);
                    return(fn);
                }
            }
            return(null);
        }
Пример #16
0
		public static LNode TupleType(LNode node, IMacroContext context)
		{
			var stem = node.Args[0, F.Missing];
			if (stem.IsId && (stem.Name == S.AltList || stem.Name == S.Tuple)) {
				var tupleMakers = MaybeInitTupleMakers(context.ScopedProperties);
				
				var bareType = tupleMakers.TryGet(node.Args.Count - 1, new Pair<LNode, LNode>()).A;
				if (bareType == null)
					bareType = ((Pair<LNode, LNode>)context.ScopedProperties[DefaultTupleMaker]).A;
				if (bareType != null)
					return node.WithArgChanged(0, bareType);
			}
			return null;
		}
Пример #17
0
            LNode ESEInForLoop(LNode stmt, VList <LNode> attrs, VList <LNode> init, LNode cond, VList <LNode> inc, LNode block)
            {
                // TODO: handle multi-int and multi-inc
                var preInit   = VList <LNode> .Empty;
                var init_apos = init.SmartSelect(init1 => {
                    init1 = EliminateSequenceExpressionsInExecStmt(init1);
                    if (init1.CallsMin(__numrunSequence, 1))
                    {
                        preInit.AddRange(init1.Args.WithoutLast(1));
                        return(init1.Args.Last);
                    }
                    return(init1);
                });
                var cond_apos = BubbleUpBlocks(cond);
                var inc_apos  = inc.SmartSelectMany(inc1 => {
                    inc1 = BubbleUpBlocks(inc1);
                    return(inc1.AsList(__numrunSequence));
                });

                block = EliminateSequenceExpressionsInChildStmt(block);
                if (init_apos != init || cond_apos != cond || inc_apos != inc)
                {
                    init = init_apos;
                    if (inc_apos != inc)
                    {
                        var blockStmts = block.AsList(S.Braces).AddRange(inc_apos);
                        block = blockStmts.AsLNode(S.Braces);
                        inc   = LNode.List();
                    }
                    if (cond_apos.CallsMin(__numrunSequence, 1))
                    {
                        var preCond = cond_apos.Args.WithoutLast(1);
                        cond = cond_apos.Args.Last;
                        stmt = LNode.Call(CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), LNode.Missing, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preCond).Add(LNode.Call(CodeSymbols.If, LNode.List(cond, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)));
                    }
                    else
                    {
                        stmt = LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), cond, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), block));
                    }
                    if (preInit.Count != 0)
                    {
                        stmt = LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preInit).Add(stmt)).SetStyle(NodeStyle.Statement);
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt.WithArgChanged(3, block));
                }
            }
Пример #18
0
        static LNode ConvertToNormalDot(LNode prefix, LNode suffix)
        {
            // Essentially, we must increase the precedence of ?. to convert it to a normal dot.
            // This often requires multiple stages, as in:
            //     (a.b) ?. (c().d<x>)    ==> (a.b ?. c().d)<x>      ==> (a.b ?. c)().d<x>      ==> a.b.c().d<x>
            //     (a.b) ?. @'of(c().d, x) ==> @'of((a.b) ?. c().d, x) ==> @'of((a.b ?. c)().d, x) ==> @'of(a.b.c().d, x)
            // The cases to be handled are...
            //     x ?. y         <=>  x ?. y             ==>  x.y               (1)
            //     x ?. "foo"     <=>  x ?. "foo"         ==>  x."Foo"           (1)
            //     x ?. ++y       <=>  x ?. @`++`(y)      ==>  x.(++y)           (1)
            //     x ?. y<a, b>   <=>  x ?. @'of(y, a, b)  ==>  #of(x.y, a, b)    (2)
            //     x ?. y[a, b]   <=>  x ?. @`[]`(y, a, b)==>  @`[]`(x.y, a, b)  (2)
            //     x ?. y.z       <=>  x ?. @.(y, z)      ==>  #.(x?.y, z)       (2)
            //     x ?. y::z      <=>  x ?. @`::`(y, z)   ==>  #::(x?.y, z)      (2)
            //     x ?. y:::z     <=>  x ?. @`:::`(y, z)  ==>  #:::(x?.y, z)     (2)
            //     x ?. y->z      <=>  x ?. @`->`(y, z)   ==>  #->(x?.y, z)      (2)
            //     x ?. y(->z)    <=>  x ?. @'cast(y, z)  ==>  @'cast(x?.y, z)    (2)
            //     x ?. y++       <=>  x ?. @`suf++`(y)   ==>  @`suf++`(x?.y)    (2)
            //     x ?. y ?. z    <=>  x ?. @`?.`(y, z)   ==>  @`?.`(x.y, z)
            //     x ?. y(a, b)   <=>  x ?. y(a, b)       ==>  x.y(a, b)         (3: default case)
            // The following groups are handled essentially the same way:
            // 1. Ids, Literals and prefix operators (+ - ++ -- ! ~ new)
            // 2. @'of, @`[]`, @`.`, @`::`, @`:::`, @`=:`, @`->`, @'cast, @`suf++`, @`suf--`
            // 3. All other calls
            var c    = suffix.ArgCount;
            var name = suffix.Name;

            if (suffix.IsCall)
            {
                if (c == 1 && PrefixOps.Contains(name))                 // (1)
                {
                    return(F.Dot(prefix, suffix));
                }
                else if (c >= 1 && OtherOps.Contains(name))                   // (2)
                {
                    var inner = ConvertToNormalDot(prefix, suffix.Args[0]);
                    return(suffix.WithArgChanged(0, inner));
                }
                else                     // (3)
                {
                    var inner = ConvertToNormalDot(prefix, suffix.Target);
                    return(suffix.WithTarget(inner));
                }
            }
            else               // (1)
            {
                return(F.Dot(prefix, suffix));
            }
        }
Пример #19
0
 public static LNode Constructor(LNode cons, IMacroContext context)
 {
     if (cons.ArgCount >= 3 && cons.Args[1].IsIdNamed(S.This))
     {
         var    anc = context.Ancestors;
         LNode  space = anc.TryGet(anc.Count - 3, LNode.Missing), typeName;
         Symbol type = EcsValidators.SpaceStatementKind(space);
         if (type != null && anc[anc.Count - 2] == space.Args[2])
         {
             typeName = space.Args[0];
             return(cons.WithArgChanged(1, F.Id(KeyNameComponentOf(typeName))));
         }
     }
     return(null);
 }
Пример #20
0
		public static LNode ForwardMethod(LNode fn, IMacroContext context)
		{
			LNode args, fwd, body;
			if (fn.ArgCount != 4 || !(fwd = fn.Args[3]).Calls(S.Forward, 1) || !(args = fn.Args[2]).Calls(S.AltList))
				return null;

			VList<LNode> argList = GetArgNamesFromFormalArgList(args, formalArg =>
				context.Write(Severity.Error, formalArg, "'==>': Expected a variable declaration here"));

			LNode target = GetForwardingTarget(fn.Args[1], fwd);
			LNode call = F.Call(target, argList);
			
			bool isVoidFn = fn.Args[0].IsIdNamed(S.Void);
			body = F.Braces(isVoidFn ? call : F.Call(S.Return, call));
			return fn.WithArgChanged(3, body);
		}
Пример #21
0
 static LNode GetForwardingTarget(LNode fwd, LNode methodName)
 {
     if (fwd.Calls(S.Forward, 1))
     {
         LNode target = fwd.Args[0];
         if (target.Calls(S.Dot, 2) && (target.Args[1].IsIdNamed(_hash) || target.Args[1].IsIdNamed(__)))
         {
             return(target.WithArgChanged(1, target.Args[1].WithName(
                                              EcsNodePrinter.KeyNameComponentOf(methodName))));
         }
         return(target);
     }
     else
     {
         return(null);
     }
 }
Пример #22
0
        protected override LNode DoneAttaching(LNode node, LNode parent, int indexInParent)
        {
            // Constructors are funky in EC# because EC# generalizes constructors so
            // you can write, for example, `this() { F(); base(); G(); }`.
            // Plain C# constructors like `this() : base() { G(); }`, `base(x)`
            // are actually stored like   `this() { base(); G(); }`, where the colon
            // is the beginning of the Range of the constructor body and the opening
            // brace is the range of the Target of the method body. This makes it
            // difficult to get the trivia attached the way we want. For example, this
            // constructor:
            //
            //     Foo(int x)
            //        : base(x)
            //     {
            //        Bar();
            //     }
            //
            // Gets trivia attached like this:
            //
            //     #cons(``, Foo, #(int x), @`%newline` (@`%newline` `'{}`)(
            //         [`%appendStatement`] base(x), Bar()));
            //
            // This code changes the trivia to something more reasonable:
            //
            //     #cons(``, Foo, #(int x), @`%newline` { base(x), Bar() });
            //
            LNode baseCall;

            if (node.CallsMin(S.Braces, 1) && parent != null && parent.Calls(S.Constructor) &&
                (baseCall = node.Args[0]).Range.StartIndex < node.Target.Range.StartIndex)
            {
                if (RemoveLeadingNewline(ref node) != null)
                {
                    node = node.WithArgChanged(0, baseCall.WithoutAttrNamed(S.TriviaAppendStatement));
                }
                LNode target = node.Target, newline_trivia;
                if ((newline_trivia = RemoveLeadingNewline(ref target)) != null)
                {
                    node = node.WithTarget(target).PlusAttrBefore(newline_trivia);
                }
            }
            return(node);
        }
Пример #23
0
        public static LNode TupleType(LNode node, IMessageSink sink)
        {
            var stem = node.Args[0, F._Missing];

            if (stem.IsId && (stem.Name == S.List || stem.Name == S.Tuple))
            {
                MaybeInitTupleMakers();
                var bareType = TupleMakers.TryGet(node.Args.Count - 1, new Pair <LNode, LNode>()).A;
                if (bareType == null)
                {
                    bareType = DefaultTupleMaker.A;
                }
                if (bareType != null)
                {
                    return(node.WithArgChanged(0, bareType));
                }
            }
            return(null);
        }
Пример #24
0
        public static LNode ForwardMethod(LNode fn, IMacroContext context)
        {
            LNode args, fwd, body;

            if (fn.ArgCount != 4 || !(fwd = fn.Args[3]).Calls(S.Forward, 1) || !(args = fn.Args[2]).Calls(S.AltList))
            {
                return(null);
            }

            VList <LNode> argList = GetArgNamesFromFormalArgList(args, formalArg =>
                                                                 context.Write(Severity.Error, formalArg, "'==>': Expected a variable declaration here"));

            LNode target = GetForwardingTarget(fwd, fn.Args[1]);
            LNode call   = F.Call(target, argList);

            bool isVoidFn = fn.Args[0].IsIdNamed(S.Void);

            body = F.Braces(isVoidFn ? call : F.Call(S.Return, call));
            return(fn.WithArgChanged(3, body));
        }
Пример #25
0
        public static LNode TupleType(LNode node, IMacroContext context)
        {
            var stem = node.Args[0, F.Missing];

            if (stem.IsId && (stem.Name == S.AltList || stem.Name == S.Tuple))
            {
                var tupleMakers = MaybeInitTupleMakers(context.ScopedProperties);

                var bareType = tupleMakers.TryGet(node.Args.Count - 1, new Pair <LNode, LNode>()).A;
                if (bareType == null)
                {
                    bareType = ((Pair <LNode, LNode>)context.ScopedProperties[DefaultTupleMaker]).A;
                }
                if (bareType != null)
                {
                    return(node.WithArgChanged(0, bareType));
                }
            }
            return(null);
        }
Пример #26
0
 public void PrependStmtsToGetterOrSetter(ref LNode braces, int getterIndex, LNode getter)
 {
     if (!PrependStmts.IsEmpty)
     {
         if (getter.ArgCount == 0)
         {
             Context.Write(Severity.Error, getter, "`{0}`: contracts cannot be applied to autoproperties. " + "A body is required, but you can use [field] on the property to add a body to `get` and `set` automatically.", getter);
             return;
         }
         else if (getter.ArgCount == 1)
         {
             var body = getter.Args[0];
             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, PrependStmts));
             getter = getter.WithArgs(body);
             braces = braces.WithArgChanged(getterIndex, getter);
         }
     }
 }
Пример #27
0
        public static LNode ForwardMethod(LNode fn, IMessageSink sink)
        {
            LNode args, fwd, body;

            if (fn.ArgCount != 4 || !(fwd = fn.Args[3]).Calls(S.Forward, 1) || !(args = fn.Args[2]).Calls(S.List))
            {
                return(null);
            }

            RVList <LNode> formalArgs = args.Args;
            RVList <LNode> argList    = RVList <LNode> .Empty;

            foreach (var formalArg in formalArgs)
            {
                if (!formalArg.Calls(S.Var, 2))
                {
                    return(Reject(sink, formalArg, "'==>' expected a variable declaration here"));
                }
                LNode argName = formalArg.Args[1];
                if (argName.Calls(S.Assign, 2))
                {
                    argName = argName.Args[0];
                }
                LNode @ref = formalArg.AttrNamed(S.Ref) ?? formalArg.AttrNamed(S.Out);
                if (@ref != null)
                {
                    argName = argName.PlusAttr(@ref);
                }
                argList.Add(argName);
            }

            LNode target = GetForwardingTarget(fwd, fn.Args[1]);
            LNode call   = F.Call(target, argList);

            bool isVoidFn = fn.Args[0].IsIdNamed(S.Void);

            body = F.Braces(isVoidFn ? call : F.Call(S.Return, call));
            return(fn.WithArgChanged(3, body));
        }
Пример #28
0
		static LNode ConvertToNormalDot(LNode prefix, LNode suffix)
		{
			// Essentially, we must increase the precedence of ?. to convert it to a normal dot.
			// This often requires multiple stages, as in:
			//     (a.b) ?. (c().d<x>)    ==> (a.b ?. c().d)<x>      ==> (a.b ?. c)().d<x>      ==> a.b.c().d<x>
			//     (a.b) ?. #of(c().d, x) ==> #of((a.b) ?. c().d, x) ==> #of((a.b ?. c)().d, x) ==> #of(a.b.c().d, x)
			// The cases to be handled are...
			//     x ?. y         <=>  x ?. y             ==>  x.y               (1)
			//     x ?. "foo"     <=>  x ?. "foo"         ==>  x."Foo"           (1)
			//     x ?. ++y       <=>  x ?. @`++`(y)      ==>  x.(++y)           (1)
			//     x ?. y<a, b>   <=>  x ?. #of(y, a, b)  ==>  #of(x.y, a, b)    (2)
			//     x ?. y[a, b]   <=>  x ?. @`[]`(y, a, b)==>  @`[]`(x.y, a, b)  (2)
			//     x ?. y.z       <=>  x ?. @.(y, z)      ==>  #.(x?.y, z)       (2)
			//     x ?. y::z      <=>  x ?. @`::`(y, z)   ==>  #::(x?.y, z)      (2)
			//     x ?. y:::z     <=>  x ?. @`:::`(y, z)  ==>  #:::(x?.y, z)     (2)
			//     x ?. y->z      <=>  x ?. @`->`(y, z)   ==>  #->(x?.y, z)      (2)
			//     x ?. y(->z)    <=>  x ?. #cast(y, z)   ==>  #cast(x?.y, z)    (2)
			//     x ?. y++       <=>  x ?. @`suf++`(y)   ==>  @`suf++`(x?.y)    (2)
			//     x ?. y ?. z    <=>  x ?. @`?.`(y, z)   ==>  @`?.`(x.y, z)       
			//     x ?. y(a, b)   <=>  x ?. y(a, b)       ==>  x.y(a, b)         (3: default case)
			// The following groups are handled essentially the same way:
			// 1. Ids, Literals and prefix operators (+ - ++ -- ! ~ new)
			// 2. #of, @`[]`, @`.`, @`::`, @`:::`, @`=:`, @`->`, #cast, @`suf++`, @`suf--`
			// 3. All other calls
			var c = suffix.ArgCount;
			var name = suffix.Name;
			if (suffix.IsCall) {
				if (c == 1 && PrefixOps.Contains(name)) // (1)
					return F.Dot(prefix, suffix);
				else if (c >= 1 && OtherOps.Contains(name)) { // (2)
					var inner = ConvertToNormalDot(prefix, suffix.Args[0]);
					return suffix.WithArgChanged(0, inner);
				} else { // (3)
					var inner = ConvertToNormalDot(prefix, suffix.Target);
					return suffix.WithTarget(inner);
				}
			} else // (1)
				return F.Dot(prefix, suffix);
		}
Пример #29
0
        public static LNode ContractsOnLambda(LNode fn, IMacroContext context)
        {
            // Performance note: one should keep in mind that this macro usually
            // has no effect. It looks for contracts and usually finds none.
            LNode oldFn = fn;

            if (fn.ArgCount == 2)
            {
                var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context);

                // If this thing has an argument list, scan it
                fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true);

                // Scan attributes on the lambda as a whole
                if (fn.HasAttrs)
                {
                    fn = fn.WithAttrs(rw.Process(fn.Attrs, null));
                }

                if (rw.PrependStmts.IsEmpty)
                {
                    return(null);                       // this is the common case
                }
                else
                {
                    var body = fn.Args[1];
                    if (!body.Calls(S.Braces)                           // Add braces in case of void LambdaMethod() => expr;
                        )
                    {
                        body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement);
                    }
                    body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts));
                    fn   = fn.WithArgChanged(1, body);
                    return(fn);
                }
            }
            return(null);
        }
Пример #30
0
        [LexicalMacro("notnull T Prop {...}; T this[[requires(expr)] T arg] {...}; " + "T Prop { [requires(expr)] set; }; [ensures(expr)] T Prop {...}; " + "[ensuresOnThrow(expr)] T Prop {...}; [ensuresOnThrow<Exception>(expr)] T Prop {...}", "Generates contract checks in a property. You can apply contract attributes to " + "the property itself, to the getter, to the setter, or all three. When the [requires] " + "or [assert] attributes are applied to the property itself, they are treated as if " + "they were applied to the getter; but when the [ensures], [ensuresAssert], notnull, " + "and [ensuresOnThrow] attributes are applied to the property itself, they are treated " + "as if they were applied to both the getter and the setter separately.", "#property", Mode = MacroMode.Passive | MacroMode.PriorityInternalFallback)] public static LNode ContractsOnProperty(LNode prop, IMacroContext context)
        {
            LNode propArgs, oldProp = prop;

            if (prop.ArgCount == 4)
            {
                LNode braces    = prop[3];
                var   oldBraces = braces;
                var   rw        = new CodeContractRewriter(prop.Args[0], prop.Args[1], context);
                prop = ProcessArgContractAttributes(prop, 2, rw);
                VList <LNode> cAttrs = LNode.List();
                prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter));
                prop = GrabContractAttrs(prop, ref cAttrs);
                LNode         getter = null, setter = null;
                int           getterIndex = -1, setterIndex = -1;
                VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List();
                bool          isLambdaProperty = !braces.Calls(S.Braces);
                if (isLambdaProperty)
                {
                    if (cAttrs.Count == 0)
                    {
                        return(null);
                    }
                    getterAttrs = cAttrs;
                    getter      = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special);
                    braces      = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement);
                    getterIndex = 0;
                }
                else
                {
                    for (int i = 0; i < braces.Args.Count; i++)
                    {
                        var part = braces.Args[i];
                        if (part.Calls(S.get))
                        {
                            getter      = part;
                            getterIndex = i;
                        }
                        if (part.Calls(S.set))
                        {
                            setter      = part;
                            setterIndex = i;
                        }
                    }
                    if (cAttrs.Count != 0)
                    {
                        getterAttrs = cAttrs.Where(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0);
                        setterAttrs = cAttrs.Where(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0);
                    }
                }
                var sharedPrependStmts = rw.PrependStmts;
                if (getter != null)
                {
                    getter = GrabContractAttrs(getter, ref getterAttrs);
                    rw.Process(getterAttrs, null);
                    rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter);
                }
                if (setter != null)
                {
                    rw.PrependStmts = sharedPrependStmts;
                    setter          = GrabContractAttrs(setter, ref setterAttrs);
                    rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true);
                    rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter);
                }
                if (braces == oldBraces)
                {
                    return(null);
                }
                else
                {
                    return(prop.WithArgChanged(3, braces));
                }
            }
            return(null);
        }
Пример #31
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)));
        }
Пример #32
0
			public LNode EliminateSequenceExpressions(LNode stmt, bool isDeclContext)
			{
				LNode retType, name, argList, bases, body, initValue;
				if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null) {
					// Space definition: class, struct, etc.
					return body == null ? stmt : stmt.WithArgChanged(2, EliminateSequenceExpressions(body, true));
				} else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null) {
					// Method definition
					return body == null ? stmt : stmt.WithArgChanged(3, EliminateSequenceExpressionsInLambdaExpr(body, retType));
				} else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue)) {
					// Property definition
					stmt = stmt.WithArgChanged(3, 
					body.WithArgs(part => {
						if (part.ArgCount == 1 && part[0].Calls(S.Braces))
							part = part.WithArgChanged(0, EliminateSequenceExpressions(part[0], false));
						return part;
					}));
					if (initValue != null) {
						var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
						if (initMethod != null) {
							stmt = stmt.WithArgChanged(4, initValue);
							return LNode.Call((Symbol) "#runSequence", LNode.List(stmt, initMethod));
						}
					}
					return stmt;
				} else if (stmt.Calls(CodeSymbols.Braces)) {
					return stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, isDeclContext));
				} else if (!isDeclContext) {
					return EliminateSequenceExpressionsInExecStmt(stmt);
				} else if (stmt.CallsMin(S.Var, 2)) {
					// Eliminate blocks from field member
					var results = new List<LNode> { 
						stmt
					};
					var vars = stmt.Args;
					var varType = vars[0];
					for (int i = 1; i < vars.Count; i++) {
						var @var = vars[i];
						if (@var.Calls(CodeSymbols.Assign, 2) && (name = @var.Args[0]) != null && (initValue = @var.Args[1]) != null) {
							var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
							if (initMethod != null) {
								results.Add(initMethod);
								vars[i] = vars[i].WithArgChanged(1, initValue);
							}
						}
					}
					if (results.Count > 1) {
						results[0] = stmt.WithArgs(vars);
						return LNode.List(results).AsLNode(__numrunSequence);
					}
					return stmt;
				} else
					return stmt;
			}
Пример #33
0
        public static LNode ContractsOnProperty(LNode prop, IMacroContext context)
        {
            // Performance note: one should keep in mind that this macro usually
            // has no effect. It looks for contracts and usually finds none.
            LNode oldProp = prop;

            if (prop.ArgCount == 4)
            {
                LNode braces    = prop[3];
                var   oldBraces = braces;
                var   rw        = new CodeContractRewriter(prop.Args[0], prop.Args[1], context);

                // If this has an argument list (this[...]), process its contract attributes
                prop = ProcessArgContractAttributes(prop, 2, rw);

                // Remove contract attributes from the property and store in a list
                VList <LNode> cAttrs = LNode.List();
                prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter));
                prop = GrabContractAttrs(prop, ref cAttrs);

                // Find the getter and setter
                LNode         getter = null, setter = null;
                int           getterIndex = -1, setterIndex = -1;
                VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List();
                bool          isLambdaProperty = !braces.Calls(S.Braces);
                if (isLambdaProperty)
                {
                    if (cAttrs.Count == 0)
                    {
                        return(null);                           // lambda property has no contract attributes
                    }
                    // Transform into a normal property
                    getterAttrs = cAttrs;
                    getter      = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special);
                    braces      = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement);
                    getterIndex = 0;
                }
                else
                {
                    for (int i = 0; i < braces.Args.Count; i++)
                    {
                        var part = braces.Args[i];
                        if (part.Calls(S.get))
                        {
                            getter = part; getterIndex = i;
                        }
                        if (part.Calls(S.set))
                        {
                            setter = part; setterIndex = i;
                        }
                    }

                    // Now create separate lists of contract attributes for the getter and the setter
                    if (cAttrs.Count != 0)
                    {
                        getterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0);
                        setterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0);
                    }
                }

                // Process the discovered attributes to produce prepended statements
                var sharedPrependStmts = rw.PrependStmts;
                if (getter != null)
                {
                    getter = GrabContractAttrs(getter, ref getterAttrs);
                    rw.Process(getterAttrs, null);
                    rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter);
                }
                if (setter != null)
                {
                    rw.PrependStmts = sharedPrependStmts;
                    setter          = GrabContractAttrs(setter, ref setterAttrs);
                    rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true);
                    rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter);
                }

                // Update the property
                if (braces == oldBraces)
                {
                    return(null);                       // this is the common case
                }
                else
                {
                    return(prop.WithArgChanged(3, braces));
                }
            }
            return(null);
        }
Пример #34
0
			LNode ESEInForLoop(LNode stmt, VList<LNode> attrs, VList<LNode> init, LNode cond, VList<LNode> inc, LNode block)
			{
				// TODO: handle multi-int and multi-inc
				var preInit = VList<LNode>.Empty;
				var init_apos = init.SmartSelect(init1 => {
					init1 = EliminateSequenceExpressionsInExecStmt(init1);
					if (init1.CallsMin(__numrunSequence, 1)) {
						preInit.AddRange(init1.Args.WithoutLast(1));
						return init1.Args.Last;
					}
					return init1;
				});
				var cond_apos = BubbleUpBlocks(cond);
				var inc_apos = inc.SmartSelectMany(inc1 => {
					inc1 = BubbleUpBlocks(inc1);
					return inc1.AsList(__numrunSequence);
				});
			
				block = EliminateSequenceExpressionsInChildStmt(block);
				if (init_apos != init || cond_apos != cond || inc_apos != inc) {
					init = init_apos;
					if (inc_apos != inc) {
						var blockStmts = block.AsList(S.Braces).AddRange(inc_apos);
						block = blockStmts.AsLNode(S.Braces);
						inc = LNode.List();
					}
					if (cond_apos.CallsMin(__numrunSequence, 1)) {
						var preCond = cond_apos.Args.WithoutLast(1);
						cond = cond_apos.Args.Last;
						stmt = LNode.Call(CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), LNode.Missing, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preCond).Add(LNode.Call(CodeSymbols.If, LNode.List(cond, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)));
					} else {
						stmt = LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), cond, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), block));
					}
					if (preInit.Count != 0) {
						stmt = LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preInit).Add(stmt)).SetStyle(NodeStyle.Statement);
					}
					return stmt;
				} else {
					return stmt.WithArgChanged(3, block);
				}
			}
Пример #35
0
            public LNode EliminateBlockExprs(LNode stmt, bool isDeclContext)
            {
                LNode retType, name, argList, bases, body, initValue;

                if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null)
                {
                    return(body == null ? stmt : stmt.WithArgChanged(2, EliminateBlockExprs(body, true)));
                }
                else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null)
                {
                    return(body == null ? stmt : stmt.WithArgChanged(3, EliminateBlockExprs(body, false)));
                }
                else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue))
                {
                    stmt = stmt.WithArgChanged(3, EliminateBlockExprs(body, false));
                    if (initValue != null)
                    {
                        var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
                        if (initMethod != null)
                        {
                            stmt = stmt.WithArgChanged(4, initValue);
                            return(LNode.Call(CodeSymbols.Splice, LNode.List(stmt, initMethod)));
                        }
                    }
                    return(stmt);
                }
                else if (!isDeclContext)
                {
                    return(EliminateBlockExprsInExecStmt(stmt));
                }
                else if (stmt.CallsMin(S.Var, 2))
                {
                    var results = new List <LNode> {
                        stmt
                    };
                    var vars    = stmt.Args;
                    var varType = vars[0];
                    for (int i = 1; i < vars.Count; i++)
                    {
                        {
                            var tmp_1 = vars[i];
                            if (tmp_1.Calls(CodeSymbols.Assign, 2) && (name = tmp_1.Args[0]) != null && (initValue = tmp_1.Args[1]) != null)
                            {
                                var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
                                if (initMethod != null)
                                {
                                    results.Add(initMethod);
                                    vars[i] = vars[i].WithArgChanged(1, initValue);
                                }
                            }
                        }
                    }
                    if (results.Count > 1)
                    {
                        results[0] = stmt.WithArgs(vars);
                        return(LNode.List(results).AsLNode(S.Splice));
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt);
                }
            }
Пример #36
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)));
        }
Пример #37
0
			LNode EliminateSequenceExpressionsInExecStmt(LNode stmt)
			{
				{
					LNode block, collection, cond, init, initValue, loopVar, name, tmp_11, tmp_12, type;
					VList<LNode> attrs, incs, inits;
					if (stmt.Calls(CodeSymbols.Braces))
						return stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, false));
					else if (stmt.CallsMin(CodeSymbols.If, 1) || stmt.Calls(CodeSymbols.UsingStmt, 2) || stmt.Calls(CodeSymbols.Lock, 2) || stmt.Calls(CodeSymbols.Switch, 2) && stmt.Args[1].Calls(CodeSymbols.Braces))
						return ProcessBlockCallStmt(stmt, 1);
					else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fixed, 2) && (init = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) {
						init = EliminateSequenceExpressionsInExecStmt(init);
						block = EliminateSequenceExpressionsInChildStmt(block);
						if (init.CallsMin(__numrunSequence, 1)) {
							return LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(init.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.Fixed, LNode.List(init.Args.Last, block)))).SetStyle(NodeStyle.Statement);
						} else
							return stmt.WithArgChanged(1, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.While, 2) && (cond = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) {
						cond = BubbleUpBlocks(cond);
						block = EliminateSequenceExpressionsInChildStmt(block);
						if (cond.CallsMin(__numrunSequence, 1)) {
							return LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList), LNode.Missing, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(cond.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.If, LNode.List(cond.Args.Last, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)));
						} else
							return stmt.WithArgChanged(1, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.DoWhile, 2) && (block = stmt.Args[0]) != null && (cond = stmt.Args[1]) != null) {
						block = EliminateSequenceExpressionsInChildStmt(block);
						cond = BubbleUpBlocks(cond);
						if (cond.CallsMin(__numrunSequence, 1)) {
							var continue_N = F.Id(NextTempName(Context, "continue_"));
							var bodyStmts = block.AsList(S.Braces);
							bodyStmts.AddRange(cond.Args.WithoutLast(1));
							bodyStmts.Add(LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, cond.Args.Last)).SetStyle(NodeStyle.Operator));
							return LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id(CodeSymbols.Bool), LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, LNode.Literal(true))))))), continue_N, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(bodyStmts)).SetStyle(NodeStyle.Statement)));
						} else
							return stmt.WithArgChanged(0, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.For, 4) && stmt.Args[0].Calls(CodeSymbols.AltList) && (cond = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (block = stmt.Args[3]) != null) {
						inits = stmt.Args[0].Args;
						incs = stmt.Args[2].Args;
						return ESEInForLoop(stmt, attrs, inits, cond, incs, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.ForEach, 3) && (tmp_11 = stmt.Args[0]) != null && tmp_11.Calls(CodeSymbols.Var, 2) && (type = tmp_11.Args[0]) != null && (loopVar = tmp_11.Args[1]) != null && (collection = stmt.Args[1]) != null && (block = stmt.Args[2]) != null) {
						block = EliminateSequenceExpressionsInChildStmt(block);
						collection = BubbleUpBlocks(collection);
						if (collection.CallsMin(__numrunSequence, 1)) {
							return LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(collection.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.ForEach, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(type, loopVar)), collection.Args.Last, block)))).SetStyle(NodeStyle.Statement);
						} else {
							return stmt.WithArgChanged(stmt.Args.Count - 1, block);
						}
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Var, 2) && (type = stmt.Args[0]) != null && (tmp_12 = stmt.Args[1]) != null && tmp_12.Calls(CodeSymbols.Assign, 2) && (name = tmp_12.Args[0]) != null && (initValue = tmp_12.Args[1]) != null) {
						var initValue_apos = BubbleUpBlocks(initValue);
						if (initValue_apos != initValue) {
							{
								LNode last;
								VList<LNode> stmts;
								if (initValue_apos.CallsMin((Symbol) "#runSequence", 1) && (last = initValue_apos.Args[initValue_apos.Args.Count - 1]) != null) {
									stmts = initValue_apos.Args.WithoutLast(1);
									return LNode.Call((Symbol) "#runSequence", LNode.List().AddRange(stmts).Add(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, last))))));
								} else
									return LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, initValue_apos))));
							}
						}
					} else if (stmt.CallsMin(S.Try, 2)) {
						return ESEInTryStmt(stmt);
					} else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces)) {
						return ProcessBlockCallStmt(stmt, stmt.ArgCount - 1);
					} else {
						// Ordinary expression statement
						return BubbleUpBlocks(stmt, stmtContext: true);
					}
				}
				return stmt;
			}
Пример #38
0
			// Creates a temporary for an LValue (left side of `=`, or `ref` parameter)
			// e.g. f(x).Foo becomes f(x_N).Foo, and `var x_N = x` is added to `stmtSequence`,
			// where N is a unique integer for the temporary variable.
			LNode MaybeCreateTemporaryForLValue(LNode expr, ref VList<LNode> stmtSequence)
			{
				{
					LNode _, lhs;
					if (expr.Calls(CodeSymbols.Dot, 2) && (lhs = expr.Args[0]) != null || expr.CallsMin(CodeSymbols.Of, 1) && (lhs = expr.Args[0]) != null)
						return expr.WithArgChanged(0, MaybeCreateTemporaryForLValue(lhs, ref stmtSequence));
					else if ((_ = expr) != null && !_.IsCall)
						return expr;
					else {
						var args = expr.Args.ToWList();
						int i = 0;
						if (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1)) {
							// Consider foo[i]. We cannot always store `foo` in a temporary, as
							// this may change the code's behavior in case `foo` is a struct.
							i = 1;
						}
						for (; i < args.Count; i++) {
							if (!args[i].IsLiteral && !args[i].Attrs.Contains(_trivia_isTmpVar)) {
								LNode tmpVarName;
								stmtSequence.Add(TempVarDecl(Context, args[i], out tmpVarName));
								args[i] = tmpVarName.PlusAttr(_trivia_isTmpVar);
							}
						}
						return expr.WithArgs(args.ToVList());
					}
				}
			}
Пример #39
0
        public static LNode ContractsOnProperty(LNode prop, IMacroContext context)
        {
            LNode oldProp = prop;

            if (prop.ArgCount == 4)
            {
                LNode braces    = prop[3];
                var   oldBraces = braces;
                var   rw        = new CodeContractRewriter(prop.Args[0], prop.Args[1], context);
                prop = ProcessArgContractAttributes(prop, 2, rw);
                VList <LNode> cAttrs = LNode.List();
                prop = prop.WithArgChanged(0, GrabContractAttrs(prop.Args[0], ref cAttrs, ContractAppliesTo.Getter));
                prop = GrabContractAttrs(prop, ref cAttrs);
                LNode         getter = null, setter = null;
                int           getterIndex = -1, setterIndex = -1;
                VList <LNode> getterAttrs = LNode.List(), setterAttrs = LNode.List();
                bool          isLambdaProperty = !braces.Calls(S.Braces);
                if (isLambdaProperty)
                {
                    if (cAttrs.Count == 0)
                    {
                        return(null);
                    }
                    getterAttrs = cAttrs;
                    getter      = LNode.Call(CodeSymbols.get, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(braces)))).SetStyle(NodeStyle.Statement))).SetStyle(NodeStyle.Special);
                    braces      = LNode.Call(CodeSymbols.Braces, LNode.List(getter)).SetStyle(NodeStyle.Statement);
                    getterIndex = 0;
                }
                else
                {
                    for (int i = 0; i < braces.Args.Count; i++)
                    {
                        var part = braces.Args[i];
                        if (part.Calls(S.get))
                        {
                            getter      = part;
                            getterIndex = i;
                        }
                        if (part.Calls(S.set))
                        {
                            setter      = part;
                            setterIndex = i;
                        }
                    }
                    if (cAttrs.Count != 0)
                    {
                        getterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Getter) != 0);
                        setterAttrs = cAttrs.SmartWhere(a => (PropertyContractInterpretation(a) & ContractAppliesTo.Setter) != 0);
                    }
                }
                var sharedPrependStmts = rw.PrependStmts;
                if (getter != null)
                {
                    getter = GrabContractAttrs(getter, ref getterAttrs);
                    rw.Process(getterAttrs, null);
                    rw.PrependStmtsToGetterOrSetter(ref braces, getterIndex, getter);
                }
                if (setter != null)
                {
                    rw.PrependStmts = sharedPrependStmts;
                    setter          = GrabContractAttrs(setter, ref setterAttrs);
                    rw.Process(setterAttrs, LNode.Id(CodeSymbols.value), true);
                    rw.PrependStmtsToGetterOrSetter(ref braces, setterIndex, setter);
                }
                if (braces == oldBraces)
                {
                    return(null);
                }
                else
                {
                    return(prop.WithArgChanged(3, braces));
                }
            }
            return(null);
        }
Пример #40
0
        private static bool DetectSetOrCreateMember(LNode arg, out Symbol relevantAttribute, out Symbol fieldName, out Symbol paramName, out LNode newArg, out LNode propOrFieldDecl)
        {
            relevantAttribute = null;
            fieldName         = null;
            paramName         = null;
            newArg            = null;
            propOrFieldDecl   = null;
            LNode _, type, name, defaultValue, propArgs;

            if (EcsValidators.IsPropertyDefinition(arg, out type, out name, out propArgs, out _, out defaultValue) && propArgs.ArgCount == 0)
            {
                // #property(Type, Name<T>, {...})
                relevantAttribute = S.Property;
                fieldName         = EcsNodePrinter.KeyNameComponentOf(name);
                paramName         = ChooseArgName(fieldName);
                if (defaultValue != null)                   // initializer is Args[4]
                {
                    newArg          = LNode.Call(S.Var, LNode.List(type, F.Assign(paramName, defaultValue)), arg);
                    propOrFieldDecl = arg.WithArgs(arg.Args.Initial(4));
                }
                else
                {
                    newArg          = LNode.Call(S.Var, LNode.List(type, F.Id(paramName)), arg);
                    propOrFieldDecl = arg;
                }
                DSOCM_DistributeAttributes(arg.Attrs, ref newArg, ref propOrFieldDecl);
                return(true);
            }
            else if (IsVar(arg, out type, out paramName, out defaultValue))
            {
                int a_i = 0;
                foreach (var attr in arg.Attrs)
                {
                    if (attr.IsId)
                    {
                        var a = attr.Name;
                        if (a == _set || FieldCreationAttributes.Contains(a))
                        {
                            relevantAttribute = a;
                            fieldName         = paramName;
                            paramName         = ChooseArgName(fieldName);
                            if (a == _set)
                            {
                                newArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.Without(attr));
                            }
                            else
                            {
                                // in case of something like "[A] public params T arg = value",
                                // assume that "= value" represents a default value, not a field
                                // initializer. Most attributes stay on the argument.
                                newArg = arg.WithArgChanged(1,
                                                            defaultValue != null ? F.Assign(paramName, defaultValue) : F.Id(paramName));
                                propOrFieldDecl = LNode.Call(S.Var, LNode.List(type, F.Id(fieldName)), arg);
                                DSOCM_DistributeAttributes(arg.Attrs, ref newArg, ref propOrFieldDecl);
                            }
                            break;
                        }
                    }
                    a_i++;
                }
                return(newArg != null);
            }
            return(false);
        }
Пример #41
0
		private static bool DetectSetOrCreateMember(LNode arg, out Symbol relevantAttribute, out Symbol fieldName, out Symbol paramName, out LNode newArg, out LNode propOrFieldDecl)
		{
			relevantAttribute = null;
			fieldName = null;
			paramName = null;
			newArg = null;
			propOrFieldDecl = null;
			LNode _, type, name, defaultValue, propArgs;
			if (EcsValidators.IsPropertyDefinition(arg, out type, out name, out propArgs, out _, out defaultValue) && propArgs.ArgCount == 0) {
				// #property(Type, Name<T>, {...})
				relevantAttribute = S.Property;
				fieldName = EcsNodePrinter.KeyNameComponentOf(name);
				paramName = ChooseArgName(fieldName);
				if (defaultValue != null) { // initializer is Args[4]
					newArg = LNode.Call(S.Var, LNode.List(type, F.Assign(paramName, defaultValue)), arg);
					propOrFieldDecl = arg.WithArgs(arg.Args.First(4));
				} else {
					newArg = LNode.Call(S.Var, LNode.List(type, F.Id(paramName)), arg);
					propOrFieldDecl = arg;
				}
				DSOCM_DistributeAttributes(arg.Attrs, ref newArg, ref propOrFieldDecl);
				return true;
			} else if (IsVar(arg, out type, out paramName, out defaultValue)) {
				int a_i = 0;
				foreach (var attr in arg.Attrs) {
					if (attr.IsId) {
						var a = attr.Name;
						if (a == _set || FieldCreationAttributes.Contains(a))
						{
							relevantAttribute = a;
							fieldName = paramName;
							paramName = ChooseArgName(fieldName);
							if (a == _set) {
								newArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.Without(attr));
							} else {
								// in case of something like "[A] public params T arg = value", 
								// assume that "= value" represents a default value, not a field 
								// initializer. Most attributes stay on the argument.
								newArg = arg.WithArgChanged(1, 
									defaultValue != null ? F.Assign(paramName, defaultValue) : F.Id(paramName));
								propOrFieldDecl = LNode.Call(S.Var, LNode.List(type, F.Id(fieldName)), arg);
								DSOCM_DistributeAttributes(arg.Attrs, ref newArg, ref propOrFieldDecl);
							}
							break;
						}
					}
					a_i++;
				}
				return newArg != null;
			}
			return false;
		}
Пример #42
0
		protected override LNode DoneAttaching(LNode node, LNode parent, int indexInParent)
		{
			// Constructors are funky in EC# because EC# generalizes constructors so
			// you can write, for example, `this() { F(); base(); G(); }`. 
			// Plain C# constructors like `this() : base() { G(); }`, `base(x)`
			// are actually stored like   `this() { base(); G(); }`, where the colon
			// is the beginning of the Range of the constructor body and the opening 
			// brace is the range of the Target of the method body. This makes it 
			// difficult to get the trivia attached the way we want. For example, this 
			// constructor:
			//
			//     Foo(int x) 
			//        : base(x)
			//     {
			//        Bar();
			//     }
			//
			// Gets trivia attached like this:
			//
			//     #cons(@``, Foo, #(int x), [#trivia_newline] ([#trivia_newline] @`'{}`)(
			//         [#trivia_appendStatement] base(x), Bar()));
			//
			// This code changes the trivia to something more reasonable:
			//
			//     #cons(@``, Foo, #(int x), [#trivia_newline] { base(x), Bar() });
			//
			LNode baseCall;
			if (node.CallsMin(S.Braces, 1) && parent != null && parent.Calls(S.Constructor) 
				&& (baseCall = node.Args[0]).Range.StartIndex < node.Target.Range.StartIndex)
			{
				if (RemoveLeadingNewline(ref node) != null)
					node = node.WithArgChanged(0, baseCall.WithoutAttrNamed(S.TriviaAppendStatement));
				LNode target = node.Target, newline_trivia;
				if ((newline_trivia = RemoveLeadingNewline(ref target)) != null) {
					node = node.WithTarget(target).PlusAttrBefore(newline_trivia);
				}
			}
			return node;
		}
Пример #43
0
		public static LNode of(LNode node, IMessageSink sink)
		{
			LNode kind;
			if (node.ArgCount == 2 && (kind = node.Args[0]).IsId) {
				if (kind.IsIdNamed(_array)) return node.WithArgChanged(0, kind.WithName(S.Array));
				if (kind.IsIdNamed(_opt))   return node.WithArgChanged(0, kind.WithName(S.QuestionMark));
				if (kind.IsIdNamed(_ptr))   return node.WithArgChanged(0, kind.WithName(S._Pointer));
			} else if (node.ArgCount == 3 && (kind = node.Args[0]).IsIdNamed(_array) && node.Args[1].IsLiteral) {
				return node.WithArgs(kind.WithName(S.GetArrayKeyword((int)node.Args[1].Value)), node.Args[2]);
			}
			return null;
		}
Пример #44
0
		public static LNode priorityTestHi(LNode node, IMessageSink sink)
		{
			if (node.ArgCount >= 1 && !node[0].IsIdNamed("hi"))
				return node.WithArgChanged(0, LNode.Id("hi"));
			return null;
		}
Пример #45
0
			// This method's main goal is to move #runSequence from child nodes to outer nodes:
			//   Foo(a, #runSequence(b(), c())) => #runSequence(var a_10 = a; b(); Foo(a_10, c()));
			// It also converts variable declarations, e.g. 
			//   Foo()::foo => #runSequence(var foo = Foo(), foo)
			LNode BubbleUpBlocks(LNode expr, bool stmtContext = false)
			{
				if (!expr.IsCall)
					return expr;
			
				LNode result = null;
				if (!stmtContext) {
					{
						LNode tmp_14, value, varName, varType;
						VList<LNode> attrs;
						if (expr.Calls(CodeSymbols.Braces)) {
							Context.Sink.Warning(expr, "A braced block is not supported directly within an expression. Did you mean to use `#runSequence {...}`?");
							result = expr;
						
						} else if ((attrs = expr.Attrs).IsEmpty | true && attrs.NodeNamed(S.Out) != null && expr.Calls(CodeSymbols.Var, 2) && (varType = expr.Args[0]) != null && (varName = expr.Args[1]) != null && varName.IsId) {
							if (varType.IsIdNamed(S.Missing))
								Context.Sink.Error(expr, "#useSequenceExpressions: the data type of this variable declaration cannot be inferred and must be stated explicitly.");
							result = LNode.Call(LNode.List(_trivia_pure), (Symbol) "#runSequence", LNode.List(expr.WithoutAttrNamed(S.Out), varName.PlusAttrs(LNode.List(LNode.Id(CodeSymbols.Out)))));
						
						} else if ((attrs = expr.Attrs).IsEmpty | true && expr.Calls(CodeSymbols.Var, 2) && (varType = expr.Args[0]) != null && (tmp_14 = expr.Args[1]) != null && tmp_14.Calls(CodeSymbols.Assign, 2) && (varName = tmp_14.Args[0]) != null && (value = tmp_14.Args[1]) != null)
							if (stmtContext)
								result = expr;	// no-op
							else
								result = ConvertVarDeclToRunSequence(attrs, varType, varName, value);
					}
				}
				if (result == null) {
					{
						LNode args, code, value, varName;
						VList<LNode> attrs;
						if ((attrs = expr.Attrs).IsEmpty | true && expr.Calls(CodeSymbols.ColonColon, 2) && (value = expr.Args[0]) != null && IsQuickBindLhs(value) && (varName = expr.Args[1]) != null && varName.IsId)
							result = ConvertVarDeclToRunSequence(attrs, F.Missing, varName, value);
						
						else if ((attrs = expr.Attrs).IsEmpty | true && expr.Calls(CodeSymbols.Lambda, 2) && (args = expr.Args[0]) != null && (code = expr.Args[1]) != null)
							result = expr.WithArgChanged(1, EliminateSequenceExpressionsInLambdaExpr(code, F.Missing));
						
						else if (expr.Calls(__numrunSequence))
							result = expr;
						else
							result = BubbleUp_GeneralCall(expr);
					}
				}
			
				// #runSequences can be nested by the user or produced by BubbleUp_GeneralCall,
				// so process the code inside #runSequence too
				if (result.Calls(__numrunSequence))
					return result.WithArgs(EliminateSequenceExpressions(result.Args, false));
				else
					return result;
			}