コード例 #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
ファイル: EcsParserGrammar.cs プロジェクト: Shaykh/Loyc
		LNode AutoRemoveParens(LNode node)
		{
			int i = node.Attrs.IndexWithName(S.TriviaInParens);
			if ((i > -1))
				 return node.WithAttrs(node.Attrs.RemoveAt(i));
			return node;
		}
コード例 #3
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);
        }
コード例 #4
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);
        }
コード例 #5
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);
        }
コード例 #6
0
        private static void DSOCM_DistributeAttributes(LNodeList attrs, ref LNode newArg, ref LNode propOrFieldDecl)
        {
            // Some word attributes like `public` and `static` move to the field
            // or property, as well as named parameters representing an attribute
            // target `field:` or `property:`; all others belong on the argument.
            // Example: given `[A] [field: B] public params T _arg = value`, we want
            // a field `[B] public T arg` and a parameter `[A] params T arg = value`.
            LNodeList argAttrs = LNodeList.Empty, fieldAttrs = LNodeList.Empty;

            foreach (var attr in attrs)
            {
                var name = attr.Name;
                if (attr.IsId && (FieldCreationAttributes.Contains(name) || name == S.Readonly))
                {
                    fieldAttrs.Add(attr);
                }
                else if (name == S.TriviaSLComment || name == S.TriviaNewline)
                {
                    fieldAttrs.Add(attr);                     // Put doc comments and leading newline on the field/prop
                }
                else if (attr.Calls(S.NamedArg, 2) && (attr.Args[0].IsIdNamed("field") || attr.Args[0].IsIdNamed("property")))
                {
                    fieldAttrs.Add(attr.Args[1]);
                }
                else
                {
                    argAttrs.Add(attr);
                }
            }
            propOrFieldDecl = propOrFieldDecl.WithAttrs(fieldAttrs);
            newArg          = newArg.WithAttrs(argAttrs);
        }
コード例 #7
0
ファイル: BackingFieldMacro.cs プロジェクト: BingjieGao/Loyc
		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));
		}
コード例 #8
0
ファイル: StageTwoParser.cs プロジェクト: sizzles/ecsharp
        private Pred TranslateAndPred(LNode andExpr, bool not)
        {
            var expr = andExpr.Args[0];

            // Distinguish between semantic and syntactic predicates
            LNode subexpr = null;
            Pred  subpred = null;

            if (expr.Calls(S.Braces))
            {
                subexpr = expr.ArgCount == 1 ? expr[0] : expr;
            }
            else
            {
                subpred = NodeToPred(expr, Context.And);
            }
            LNode subexpr0 = subexpr;

            // Extract [Local] or [Hoist] attribute
            bool local = false;

            if (subexpr != null)
            {
                local = true;
                if ((subexpr = subexpr.WithoutAttrNamed(_Hoist)) != subexpr0)
                {
                    local = false;
                }
                // also recognize [Local], which was not the default until v1.9.1
                subexpr = subexpr.WithoutAttrNamed(_Local);
            }

            // Extract error message for Check(), if provided.
            string errorString = null;

            if (subexpr != null)
            {
                subexpr = subexpr.WithAttrs(n => {
                    if (n.Value is string)
                    {
                        errorString = (string)n.Value;
                        return(NoValue.Value);                        // drop attribute from output
                    }
                    else if (n.IsIdNamed("NoCheck"))
                    {
                        errorString = "";
                        return(NoValue.Value);
                    }
                    return(n);
                });
            }

            return(new AndPred(expr, (object)subexpr ?? subpred, not, local)
            {
                CheckErrorMessage = errorString
            });
        }
コード例 #9
0
ファイル: Prelude.Les.cs プロジェクト: jonathanvdc/Loyc
        public static LNode AutoRemoveParens(LNode node)
        {
            int i = node.Attrs.IndexWithName(S.TriviaInParens);

            if (i > -1)
            {
                return(node.WithAttrs(node.Attrs.RemoveAt(i)));
            }
            return(node);
        }
コード例 #10
0
        protected LNode Attr(params LNode[] attrsAndNode)
        {
            LNode node  = attrsAndNode[attrsAndNode.Length - 1];
            var   attrs = node.Attrs;

            for (int i = 0; i < attrsAndNode.Length - 1; i++)
            {
                attrs.Insert(i, attrsAndNode[i]);
            }
            return(node.WithAttrs(attrs));
        }
コード例 #11
0
ファイル: LNodeExt.cs プロジェクト: modulexcite/ecsharp
        public static LNode WithoutAttrNamed(this LNode self, Symbol name, out LNode removedAttr)
        {
            var a = self.Attrs.WithoutNodeNamed(name, out removedAttr);

            if (removedAttr != null)
            {
                return(self.WithAttrs(a));
            }
            else
            {
                return(self);
            }
        }
コード例 #12
0
ファイル: LNodeExt.cs プロジェクト: lydonchandra/Loyc
        public static LNode WithoutAttrNamed(this LNode self, Symbol name, out LNode removedAttr)
        {
            var a = self.Attrs;

            for (int i = 0, c = a.Count; i < c; i++)
            {
                if (a[i].Name == name)
                {
                    removedAttr = a[i];
                    return(self.WithAttrs(a.RemoveAt(i)));
                }
            }
            removedAttr = null;
            return(self);
        }
コード例 #13
0
        private LNode StripTrivia(LNode node)
        {
            var strippedNode = node.WithAttrs(
                attr => attr.IsTrivia ? Maybe <LNode> .NoValue : new Maybe <LNode>(attr));

            if (strippedNode.IsCall)
            {
                return(strippedNode
                       .WithTarget(StripTrivia(strippedNode.Target))
                       .WithArgs(arg => new Maybe <LNode>(StripTrivia(arg))));
            }
            else
            {
                return(strippedNode);
            }
        }
コード例 #14
0
ファイル: ContractsMacro.out.cs プロジェクト: sizzles/ecsharp
        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);
        }
コード例 #15
0
 static LNode GrabContractAttrs(LNode node, ref VList <LNode> cAttrs, ContractAppliesTo kinds = ContractAppliesTo.Both)
 {
     if (node.HasAttrs)
     {
         VList <LNode> cAttrs2 = cAttrs;
         var           r       = node.WithAttrs(attr => {
             if ((PropertyContractInterpretation(attr) & kinds) != 0)
             {
                 cAttrs2.Add(attr);
                 return(NoValue.Value);
             }
             return(attr);
         });
         cAttrs = cAttrs2;
         return(r);
     }
     return(node);
 }
コード例 #16
0
ファイル: ContractsMacro.out.cs プロジェクト: sizzles/ecsharp
 static LNode GrabContractAttrs(LNode node, ref VList <LNode> cAttrs, ContractAppliesTo kinds = ContractAppliesTo.Both)
 {
     if (node.HasAttrs)
     {
         VList <LNode> cAttrs2 = cAttrs;                 // because lambdas cannot access cAttrs directly
         var           r       = node.WithAttrs(attr => {
             if ((PropertyContractInterpretation(attr) & kinds) != 0)
             {
                 cAttrs2.Add(attr);
                 return(NoValue.Value);                          // remove
             }
             return(attr);
         });
         cAttrs = cAttrs2;
         return(r);
     }
     return(node);
 }
コード例 #17
0
        LNode ApplyMacrosToChildrenOf(LNode node, int maxExpansions)
        {
            if (maxExpansions <= 0)
            {
                return(null);
            }

            bool          changed = false;
            VList <LNode> old;
            var           newAttrs = ApplyMacrosToList(old = node.Attrs, maxExpansions, true);

            _s.IsAttribute = false;
            if (newAttrs != old)
            {
                node    = node.WithAttrs(newAttrs);
                changed = true;
            }
            LNode target = node.Target;

            if (target != null && target.Kind != LNodeKind.Literal)
            {
                DList <Pair <LNode, int> > _ = null;
                LNode newTarget = ApplyMacros(target, maxExpansions, true, true, ref _);
                if (newTarget != null)
                {
                    if (newTarget.Calls(S.Splice, 1))
                    {
                        newTarget = newTarget.Args[0];
                    }
                    node    = node.WithTarget(newTarget);
                    changed = true;
                }
            }
            var newArgs = ApplyMacrosToList(old = node.Args, maxExpansions, false);

            if (newArgs != old)
            {
                node    = node.WithArgs(newArgs);
                changed = true;
            }
            return(changed ? node : null);
        }
コード例 #18
0
ファイル: ContractsMacro.out.cs プロジェクト: sizzles/ecsharp
        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);
        }
コード例 #19
0
            LNode ApplyMacrosToChildren(LNode node, int maxExpansions)
            {
                if (maxExpansions <= 0)
                {
                    return(null);
                }

                bool           changed = false;
                RVList <LNode> old;
                var            newAttrs = ApplyMacrosToList(old = node.Attrs, maxExpansions);

                if (newAttrs != old)
                {
                    node    = node.WithAttrs(newAttrs);
                    changed = true;
                }
                if (!node.HasSimpleHead())
                {
                    LNode target = node.Target, newTarget = ApplyMacros(target, maxExpansions);
                    if (newTarget != null)
                    {
                        if (newTarget.Calls(S.Splice, 1))
                        {
                            newTarget = newTarget.Args[0];
                        }
                        node    = node.WithTarget(newTarget);
                        changed = true;
                    }
                }
                var newArgs = ApplyMacrosToList(old = node.Args, maxExpansions);

                if (newArgs != old)
                {
                    node    = node.WithArgs(newArgs);
                    changed = true;
                }
                return(changed ? node : null);
            }
コード例 #20
0
ファイル: Macros.cs プロジェクト: dadhi/ecsharp
        private static void ApplyRuleOptions(ref LNode node, Rule rule, IMacroContext context)
        {
            node = node.WithAttrs(node.Attrs.WhereSelect(attr => {
                if (attr.ArgCount > 1)
                {
                    return(attr);
                }
                LNode key    = attr.Target ?? attr;
                object value = null;
                if (attr.ArgCount == 1)
                {
                    value = attr.Args[0].Value;
                }
                switch (key.Name.Name)
                {
                case "fullLLk":
                case "FullLLk":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.FullLLk = v);
                    break;

                case "#private":
                case "private":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsPrivate = v);
                    return(attr);                            // keep attribute

                case "#public":
                case "#internal":
                case "#protected":
                case "public":
                case "internal":
                case "protected":                            // this is before macros run, and non-special names are used in LES
                    rule.IsPrivate = false;
                    return(attr);                            // keep attribute

                case "token":
                case "Token":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsToken = v);
                    break;

                case "start":
                case "Start":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsStartingRule = v);
                    break;

                case "#extern":
                case "extern":
                case "Extern":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsExternal = v);
                    break;

                case "#inline":
                case "inline":
                case "Inline":
                case "#fragment":
                case "fragment":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsInline = v);
                    break;

                case "k":
                case "K":
                case "LL":
                    SetOption <int>(context, key, value, k => rule.K = k);
                    break;

                case "recognizer":
                case "Recognizer":
                    LNode sig = attr.Args[0, null];
                    if (sig != null)
                    {
                        // Invoke macros here so that LES code like "public fn Foo()::bool"
                        // is transformed into a method signature.
                        sig = context.PreProcess(sig.UnwrapBraces());
                    }
                    if (sig != null && sig.CallsMin(S.Fn, 3))
                    {
                        sig = sig.WithoutAttrNamed(S.TriviaAppendStatement);                                 // prevent weird-looking output
                        rule.MakeRecognizerVersion(sig).TryWrapperNeeded();
                    }
                    else
                    {
                        context.Sink.Error(sig, "'recognizer' expects one parameter, a method signature.");
                    }
                    break;

                default:
                    return(attr);
                }
                return(NoValue.Value);
            }).ToArray());
        }
コード例 #21
0
 protected LNode Attr(LNode attr, LNode node)
 {
     return(node.WithAttrs(node.Attrs.Insert(0, attr)));
 }
コード例 #22
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)));
        }
コード例 #23
0
ファイル: BackingFieldMacro.cs プロジェクト: qwertie/ecsharp
		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.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.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);
			prop.Style &= ~NodeStyle.OneLiner; // avoid collapsing output to one line
			return F.Call(S.Splice, new VList<LNode>(field, prop));
		}
コード例 #24
0
        public static LNode SetOrCreateMember(LNode fn, IMessageSink sink)
        {
            // Expecting #fn(Type, Name, #(args), {body})
            if (fn.ArgCount < 3 || !fn.Args[2].Calls(S.AltList))
            {
                return(null);
            }
            var   args = fn.Args[2].Args;
            LNode body = null;

            VList <LNode> propOrFieldDecls = VList <LNode> .Empty;
            VList <LNode> setStmts         = VList <LNode> .Empty;

            for (int i = 0; i < args.Count; i++)
            {
                var    arg             = args[i];
                Symbol a               = S.Property;
                Symbol fieldName       = null;
                Symbol paramName       = null;
                LNode  plainArg        = null;
                LNode  propOrFieldDecl = null;
                if (arg.CallsMin(S.Property, 4))
                {
                    // #property(Type, Name<T>, {...})
                    var name = arg.Args[1];
                    fieldName = EcsNodePrinter.KeyNameComponentOf(name);
                    paramName = ChooseArgName(fieldName);
                    if (arg.ArgCount == 5)                       // initializer is Args[4]
                    {
                        plainArg        = F.Var(arg.Args[0], F.Call(S.Assign, F.Id(paramName), arg.Args[4]));
                        propOrFieldDecl = arg.WithArgs(arg.Args.First(4));
                    }
                    else
                    {
                        plainArg        = F.Var(arg.Args[0], paramName);
                        propOrFieldDecl = arg;
                    }
                }
                else
                {
                    LNode type, defaultValue;
                    if (IsVar(arg, out type, out paramName, out defaultValue))
                    {
                        int a_i = 0;
                        foreach (var attr in arg.Attrs)
                        {
                            if (attr.IsId)
                            {
                                a = attr.Name;
                                if (a == _set ||
                                    a == S.Public || a == S.Internal || a == S.Protected || a == S.Private ||
                                    a == S.ProtectedIn || a == S.Static || a == S.Partial)
                                {
                                    fieldName = paramName;
                                    paramName = ChooseArgName(fieldName);
                                    if (a == _set)
                                    {
                                        plainArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.RemoveAt(a_i));
                                    }
                                    else
                                    {
                                        // in case of something like "[A] public params T arg = value",
                                        // assume that "= value" represents a default value, not a field
                                        // initializer, that [A] belongs on the field, except `params`
                                        // which stays on the argument.
                                        plainArg        = F.Var(type, paramName, defaultValue);
                                        propOrFieldDecl = arg;
                                        if (arg.Args[1].Calls(S.Assign, 2))
                                        {
                                            propOrFieldDecl = arg.WithArgChanged(1,
                                                                                 arg.Args[1].Args[0]);
                                        }
                                        int i_params = arg.Attrs.IndexWithName(S.Params);
                                        if (i_params > -1)
                                        {
                                            plainArg        = plainArg.PlusAttr(arg.Attrs[i_params]);
                                            propOrFieldDecl = propOrFieldDecl.WithAttrs(propOrFieldDecl.Attrs.RemoveAt(i_params));
                                        }
                                    }
                                    break;
                                }
                            }
                            a_i++;
                        }
                    }
                }
                if (plainArg != null)
                {
                    if (body == null)
                    {
                        if (fn.ArgCount < 4 || !fn.Args[3].Calls(S.Braces))
                        {
                            return(Reject(sink, arg, Localize.Localized("'{0}': to set or create a field or property, the method must have a body in braces {{}}.", a)));
                        }
                        body = fn.Args[3];
                    }

                    args[i] = plainArg;
                    LNode assignment;
                    if (fieldName == paramName)
                    {
                        assignment = F.Call(S.Assign, F.Dot(F.@this, F.Id(fieldName)), F.Id(paramName));
                    }
                    else
                    {
                        assignment = F.Call(S.Assign, F.Id(fieldName), F.Id(paramName));
                    }
                    setStmts.Add(assignment);
                    if (propOrFieldDecl != null)
                    {
                        propOrFieldDecls.Add(propOrFieldDecl);
                    }
                }
            }
            if (body != null)             // if this macro has been used...
            {
                var parts = fn.Args;
                parts[2] = parts[2].WithArgs(args);
                parts[3] = body.WithArgs(body.Args.InsertRange(0, setStmts));
                fn       = fn.WithArgs(parts);
                if (propOrFieldDecls.IsEmpty)
                {
                    return(fn);
                }
                else
                {
                    propOrFieldDecls.Add(fn);
                    return(F.Call(S.Splice, propOrFieldDecls));
                }
            }
            return(null);
        }
コード例 #25
0
        private static void ApplyRuleOptions(ref LNode node, Rule rule, IMessageSink sink)
        {
            node = node.WithAttrs(node.Attrs.Select(attr => {
                switch (attr.Name.Name)
                {
                case "fullLLk":
                case "FullLLk":
                    ReadOption <bool>(sink, attr, v => rule.FullLLk = v, true);
                    break;

                case "#private":
                case "private":
                case "priv":
                case "Private":
                    ReadOption <bool>(sink, attr, v => rule.IsPrivate = v, true);
                    break;

                case "token":
                case "Token":
                    ReadOption <bool>(sink, attr, v => rule.IsToken = v, true);
                    break;

                case "start":
                case "Start":
                    ReadOption <bool>(sink, attr, v => rule.IsStartingRule = v, true);
                    break;

                case "#extern":
                case "extern":
                case "Extern":
                    ReadOption <bool>(sink, attr, v => rule.IsExternal = v, true);
                    break;

                case "#inline":
                case "inline":
                case "Inline":
                    ReadOption <bool>(sink, attr, v => rule.IsInline = v, true);
                    break;

                case "k":
                case "K":
                case "LL":
                    ReadOption <int>(sink, attr, k => rule.K = k, null);
                    break;

                case "recognizer":
                case "Recognizer":
                    LNode sig = null;
                    if (attr.ArgCount == 1)
                    {
                        sig = attr.Args[0];
                        if (sig.Calls(S.Braces, 1))
                        {
                            sig = sig.Args[0];
                        }
                        // TODO: we need a way to invoke all applicable macros at a particular location
                        //       e.g. "public fn Foo()::bool;" is not supported by def() alone.
                        sig = LeMP.Prelude.Les.Macros.fn(sig, sink) ?? sig;
                    }
                    if (sig != null && sig.CallsMin(S.Fn, 3))
                    {
                        rule.MakeRecognizerVersion(sig).TryWrapperNeeded();
                    }
                    else
                    {
                        sink.Write(Severity.Error, sig, "'recognizer' expects one parameter, a method signature.");
                    }
                    break;

                default:
                    return(attr);
                }
                return(null);
            }).WhereNotNull().ToArray());
        }
コード例 #26
0
        private void InjectTriviaInChildren(LNode parent, out SourceRange triviaRange, out Maybe <Trivia> trivia, int indexInParent, ref LNode node)
        {
            // Current trivia's range is within node's range: Apply it to
            // the node's children, if any. First gather list of children
            // and sort by source-code order, if necessary:
            int min = node.Min;
            InternalList <Pair <LNode, int> > children = InternalList <Pair <LNode, int> > .Empty;

            children.Resize(node.Max - min + 1);
            bool inOrder = true;
            int  start, prevStart = int.MinValue;

            for (int i = 0; i < children.Count; i++, prevStart = start)
            {
                children[i] = Pair.Create(node[i + min], i + min);
                start       = children[i].A.Range.StartIndex;
                if (prevStart > start)
                {
                    inOrder = false;
                }
            }
            if (!inOrder)
            {
                children.Sort((a, b) => a.Item1.Range.StartIndex.CompareTo(b.Item1.Range.StartIndex));
            }

            // Call ourself recursively to apply trivia to children. Usually,
            // newChildren is the same length as children, but it may have extra
            // trivia attributes added.
            InternalList <Pair <LNode, int> > newChildren = new InternalList <Pair <LNode, int> >(children.Count);
            var  output  = RunCore(children.GetEnumerator(), node);
            bool changed = false;

            while (output.MoveNext())
            {
                var @new = output.Current;
                newChildren.Add(@new);
                if (@new.Item1 != children[@new.Item2 - min].Item1)
                {
                    changed = true;
                }
            }

            // At the end, gather up any remaining trivia in the node's range that wasn't
            // associated with a child.
            //
            // A newline is treated specially here, because sometimes (e.g. in LES3 token
            // lists) a newline can be reified into its own node but also exist in the trivia
            // list. In this case, node will be something like `'\n` when triviaRange equals
            // node.Range. So let's say the node stream is something like Ann, `'\n`, Bob. If
            // we attach the newline to the `'\n` node as usual (using the
            // TriviaLocation.Ambiguous attachment mode, since the newline is neither leading
            // nor trailing), the output node list will be something rather complicated:
            //   Ann, @`%appendStatement` @(`%trailing`(`%newline`)) `'\n`, @`%appendStatement` Bob
            // If we ignore the newline temporarily so that it gets treated as leading trivia
            // of Bob instead, we get simpler output:
            //   Ann, @`%appendStatement` `'\n`, Bob
            InternalList <Trivia> triviaList = InternalList <Trivia> .Empty;

            trivia = CurrentTrivia(out triviaRange);
            while (trivia.HasValue && triviaRange.EndIndex <= node.Range.EndIndex &&
                   !(IsNewline(trivia.Value) && triviaRange == node.Range))
            {
                triviaList.Add(trivia.Value);
                trivia  = AdvanceTrivia(out triviaRange);
                changed = true;
            }

            if (changed)
            {
                // If this is a call, attach any remaining trivia to the last child.
                if (node.IsCall && !triviaList.IsEmpty)
                {
                    int i    = newChildren.Count - 1;
                    var last = newChildren.InternalArray[i];
                    newChildren.InternalArray[i].A = AttachTriviaTo(last.A, triviaList, TriviaLocation.TrailingExtra, node, last.B) ?? last.A;
                }

                // Put the children back in their "conceptual" order
                if (!inOrder)
                {
                    newChildren.StableSort((a, b) => a.Item2.CompareTo(b.Item2));
                }

                // Update node's attributes, if any
                int numAttrs = newChildren.TakeWhile(p => p.B < -1).Count();
                if (numAttrs > 0)
                {
                    var attrs = LNode.List(newChildren.Slice(0, numAttrs).SelectArray(p => p.A));
                    node = node.WithAttrs(attrs);
                }

                if (node.IsCall)
                {
                    Debug.Assert(newChildren[numAttrs].B == -1);
                    var newArgs = newChildren.Slice(numAttrs + 1).SelectArray(p => p.A);
                    node = node.With(newChildren[numAttrs].A, LNode.List(newArgs));
                }
                else if (!triviaList.IsEmpty)
                {
                    // If current node is not a call, attach any remaining trivia to it.
                    node = AttachTriviaTo(node, triviaList, TriviaLocation.Ambiguous, parent, indexInParent);
                }
            }
        }
コード例 #27
0
		private static void DSOCM_DistributeAttributes(VList<LNode> attrs, ref LNode newArg, ref LNode propOrFieldDecl)
		{
			// Some word attributes like `public` and `static` move to the field
			// or property, as well as named parameters representing an attribute 
			// target `field:` or `property:`; all others belong on the argument. 
			// Example: given `[A] [field: B] public params T _arg = value`, we want 
			// a field `[B] public T arg` and a parameter `[A] params T arg = value`.
			VList<LNode> argAttrs = VList<LNode>.Empty, fieldAttrs = VList<LNode>.Empty;
			foreach (var attr in attrs) {
				var name = attr.Name;
				if (attr.IsId && (FieldCreationAttributes.Contains(name) || name == S.Readonly))
					fieldAttrs.Add(attr);
				else if (attr.Calls(S.NamedArg, 2) && (attr.Args[0].IsIdNamed("field") || attr.Args[0].IsIdNamed("property")))
					fieldAttrs.Add(attr.Args[1]);
				else
					argAttrs.Add(attr);
			}
			propOrFieldDecl = propOrFieldDecl.WithAttrs(fieldAttrs);
			newArg = newArg.WithAttrs(argAttrs);
		}
コード例 #28
0
ファイル: LNodeExt.cs プロジェクト: modulexcite/ecsharp
 public static LNode WithoutAttr(this LNode self, LNode node)
 {
     return(self.WithAttrs(self.Attrs.Without(node)));
 }
コード例 #29
0
        private static bool DetectSetOrCreateMember(LNode arg, out Symbol relevantAttribute, out Symbol fieldName, out Symbol paramName, out LNode plainArg, out LNode propOrFieldDecl)
        {
            relevantAttribute = null;
            fieldName         = null;
            paramName         = null;
            plainArg          = 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]
                {
                    plainArg        = F.Var(type, paramName, defaultValue);
                    propOrFieldDecl = arg.WithArgs(arg.Args.First(4));
                }
                else
                {
                    plainArg        = F.Var(type, paramName);
                    propOrFieldDecl = arg;
                }
                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 ||
                            a == S.Public || a == S.Internal || a == S.Protected || a == S.Private ||
                            a == S.ProtectedIn || a == S.Static || a == S.Partial)
                        {
                            relevantAttribute = a;
                            fieldName         = paramName;
                            paramName         = ChooseArgName(fieldName);
                            if (a == _set)
                            {
                                plainArg = 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, that [A] belongs on the field, except `params`
                                // which stays on the argument.
                                plainArg        = F.Var(type, paramName, defaultValue);
                                propOrFieldDecl = arg;
                                if (arg.Args[1].Calls(S.Assign, 2))
                                {
                                    propOrFieldDecl = arg.WithArgChanged(1,
                                                                         arg.Args[1].Args[0]);
                                }
                                int i_params = arg.Attrs.IndexWithName(S.Params);
                                if (i_params > -1)
                                {
                                    plainArg        = plainArg.PlusAttr(arg.Attrs[i_params]);
                                    propOrFieldDecl = propOrFieldDecl.WithAttrs(propOrFieldDecl.Attrs.RemoveAt(i_params));
                                }
                            }
                            break;
                        }
                    }
                    a_i++;
                }
                return(plainArg != null);
            }
            return(false);
        }
コード例 #30
0
        private void InjectTriviaInChildren(LNode parent, out SourceRange triviaRange, out Maybe <Trivia> trivia, int indexInParent, ref LNode node)
        {
            // Current trivia's range is within node's range: Apply it to
            // the node's children, if any. First gather list of children
            // and sort by source-code order, if necessary:
            int min = node.Min;
            InternalList <Pair <LNode, int> > children = InternalList <Pair <LNode, int> > .Empty;

            children.Resize(node.Max - min + 1);
            bool inOrder = true;
            int  start, prevStart = int.MinValue;

            for (int i = 0; i < children.Count; i++, prevStart = start)
            {
                children[i] = Pair.Create(node[i + min], i + min);
                start       = children[i].A.Range.StartIndex;
                if (prevStart > start)
                {
                    inOrder = false;
                }
            }
            if (!inOrder)
            {
                children.Sort((a, b) => a.Item1.Range.StartIndex.CompareTo(b.Item1.Range.StartIndex));
            }

            // Call ourself recursively to apply trivia to children. Usually,
            // newChildren is the same length as children, but it may have extra
            // trivia attributes added.
            InternalList <Pair <LNode, int> > newChildren = new InternalList <Pair <LNode, int> >(children.Count);
            var  output  = RunCore(children.GetEnumerator(), node);
            bool changed = false;

            while (output.MoveNext())
            {
                var @new = output.Current;
                newChildren.Add(@new);
                if (@new.Item1 != children[@new.Item2 - min].Item1)
                {
                    changed = true;
                }
            }

            // At the end, gather up any remaining trivia
            InternalList <Trivia> triviaList = InternalList <Trivia> .Empty;

            trivia = CurrentTrivia(out triviaRange);
            while (trivia.HasValue && triviaRange.EndIndex <= node.Range.EndIndex)
            {
                triviaList.Add(trivia.Value);
                trivia  = AdvanceTrivia(out triviaRange);
                changed = true;
            }

            if (changed)
            {
                // If this is a call, attach any remaining trivia to the last child.
                if (node.IsCall && !triviaList.IsEmpty)
                {
                    int i    = newChildren.Count - 1;
                    var last = newChildren.InternalArray[i];
                    newChildren.InternalArray[i].A = AttachTriviaTo(last.A, triviaList, TriviaLocation.TrailingExtra, node, last.B) ?? last.A;
                }

                // Put the children back in their "conceptual" order
                if (!inOrder)
                {
                    newChildren.StableSort((a, b) => a.Item2.CompareTo(b.Item2));
                }

                // Update node's attributes, if any
                int numAttrs = newChildren.TakeWhile(p => p.B < -1).Count();
                if (numAttrs > 0)
                {
                    var attrs = LNode.List(newChildren.Slice(0, numAttrs).SelectArray(p => p.A));
                    node = node.WithAttrs(attrs);
                }

                if (node.IsCall)
                {
                    Debug.Assert(newChildren[numAttrs].B == -1);
                    var newArgs = newChildren.Slice(numAttrs + 1).SelectArray(p => p.A);
                    node = node.With(newChildren[numAttrs].A, LNode.List(newArgs));
                }
                else if (!triviaList.IsEmpty)
                {
                    // If current node is not a call, attach any remaining trivia to it.
                    node = AttachTriviaTo(node, triviaList, TriviaLocation.Ambiguous, parent, indexInParent);
                }
            }
        }
コード例 #31
0
 /// <summary>Adds additional trailing trivia to a node.</summary>
 public static LNode PlusTrailingTrivia(this LNode node, LNode trivia)
 {
     return(node.WithAttrs(PlusTrailingTrivia(node.Attrs, trivia)));
 }
コード例 #32
0
 /// <summary>Removes a node's trailing trivia and adds a new list of trailing trivia.</summary>
 public static LNode WithTrailingTrivia(this LNode node, LNodeList trivia)
 {
     return(node.WithAttrs(WithTrailingTrivia(node.Attrs, trivia)));
 }
コード例 #33
0
		protected LNode Attr(LNode attr, LNode node)
		{
			return node.WithAttrs(node.Attrs.Insert(0, attr));
		}
コード例 #34
0
ファイル: BackingFieldMacro.cs プロジェクト: murven/Loyc
        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)));
        }
コード例 #35
0
        public static bool MatchesPattern(LNode candidate, LNode pattern, ref MMap <Symbol, LNode> captures, out RVList <LNode> attrs)
        {
            // [$capture] (...)
            if (!AttributesMatch(candidate, pattern, ref captures, out attrs))
            {
                return(false);
            }

            // $capture
            LNode sub;

            if (pattern.Calls(S.Substitute, 1) && (sub = pattern.Args.Last).IsId)
            {
                if (candidate.AttrCount > attrs.Count)
                {
                    candidate = candidate.WithAttrs(attrs);
                }
                AddCapture(captures, sub.Name, candidate);
                attrs = RVList <LNode> .Empty;
                return(true);
            }

            var kind = candidate.Kind;

            if (kind != pattern.Kind)
            {
                return(false);
            }

            if (candidate.Name != pattern.Name)
            {
                return(false);
            }
            if (kind == NodeKind.Literal)
            {
                return(object.Equals(candidate.Value, pattern.Value));
            }
            else if (kind == NodeKind.Call)
            {
                if (!MatchesPatternNested(candidate.Target, pattern.Target, ref captures, ref attrs))
                {
                    return(false);
                }
                var cArgs = candidate.Args;
                var pArgs = pattern.Args;

                if (pArgs.Count != cArgs.Count && !pArgs.Any(IsParamsCapture))
                {
                    return(false);
                }

                // Scan from the end of the list to the beginning (RVLists is good at this),
                // matching args one-by-one. Use MatchThenParams() in case of $(params capture).
                while (!pArgs.IsEmpty)
                {
                    LNode pArg = pArgs.Pop();
                    if (IsParamsCapture(pArg))
                    {
                        return(MatchThenParams(cArgs, pArgs, pArg, ref captures, ref attrs));
                    }
                    if (cArgs.IsEmpty)
                    {
                        return(false);
                    }
                    if (!MatchesPatternNested(cArgs.Pop(), pArg, ref captures, ref attrs))
                    {
                        return(false);
                    }
                }
                return(true);
            }
            else               // kind == Id
            {
                return(true);
            }
        }