Exemple #1
0
 private static bool _isPartialList(AstExpr expr, out AstListLiteral lit)
 {
     lit = expr as AstListLiteral;
     return lit != null && lit.CheckForPlaceholders();
 }
Exemple #2
0
        private static bool _parseArguments(MacroContext context, out AstExpr call,
            out AstExpr justEffect, out AstExpr[] args,
            out AstExpr macroSpec)
        {
            /* call(macroRef,...) = call([],macroRef,[false],...);
             * call([],macroRef,[je],...) = call([],macroRef,[je,context.Call],...);
             * call([],macroRef,[je,c],...) = { macroId := macroRef.Id; 
             *                                  macroInterpretation := interpretation(macroRef); 
             *                                  call := c; 
             *                                  justEffect := je 
             *                                }
             * call([proto(...1)],...2) = call([],from_proto(proto),[false,PCall.Get],[...1],...2);
             * call([proto(...1) = x],...2) = call([],from_proto(proto),[false,PCall.Set],[...1],...2,[x]);
             * call([proto(...1),je],...2) = call([],from_proto(proto),[je,PCall.Get],[...1],...2);
             * call([proto(...1) = x,je],...2) = call([],from_proto(proto),[je,PCall.Set],[...1],...2,[x]);
             * call([proto(...1),je,c],...2) = call([],from_proto(proto),[je,c],[...1],...2);
             */

            var inv = context.Invocation;
            justEffect = new AstConstant(inv.File, inv.Line,
                inv.Column, false);
            call = PCall.Get.ToExpr(context.Invocation.Position);

            var invokeSpec = inv.Arguments[0];
            var listSpec = invokeSpec as AstListLiteral;
            if (listSpec == null)
            {
                // - Macro reference specified as expression that evaluates to an actual macro reference

                args = inv.Arguments.Skip(1).ToArray();
                macroSpec = invokeSpec;
                return _parseReference(context, inv.Arguments[0]);
            }
            else if (listSpec.Elements.Count == 0)
            {
                // - Macro reference specified as expression that evaluates to an actual macro reference
                // - followed by a list of options

                AstListLiteral optionsRaw;
                if (inv.Arguments.Count < 3 ||
                    (optionsRaw = inv.Arguments[2] as AstListLiteral) == null)
                {
                    _errorUsageFullRef(context);
                    args = null;
                    macroSpec = null;
                    return false;
                }

                macroSpec = inv.Arguments[1];

                //first option: justEffect
                if (optionsRaw.Elements.Count >= 1)
                    justEffect = optionsRaw.Elements[0];

                //second option: call type
                if (optionsRaw.Elements.Count >= 2)
                    call = optionsRaw.Elements[1];

                //args: except first 3
                args = inv.Arguments.Skip(3).ToArray();

                return _parseReference(context, inv.Arguments[1]);
            }
            else
            {
                // - Macro reference specified as a prototype
                // - includes list of options

                var specProto = listSpec.Elements[0];
                PCall protoCall;
                IList<AstExpr> protoArguments;
                if (
                    !_parsePrototype(context, specProto, out protoCall,
                        out protoArguments, out macroSpec))
                {
                    args = null;
                    return false;
                }

                //first option: justEffect
                if (listSpec.Elements.Count >= 2)
                    justEffect = listSpec.Elements[1];

                //second option: call type
                call = listSpec.Elements.Count >= 3
                    ? listSpec.Elements[2]
                    : protoCall.ToExpr(specProto.Position);

                //args: lift and pass prototype arguments, special care for set

                var setArgs = protoCall == PCall.Set
                    ? protoArguments.Last()
                    : null;
                var getArgs = protoCall == PCall.Set
                    ? protoArguments.Take(protoArguments.Count - 1)
                    : protoArguments;

                // ReSharper disable PossibleMultipleEnumeration 
                // enumerating getArgs multiple times is safe and efficient
                if (getArgs.Any(a => !_ensureExplicitPlaceholder(context, a)))

                {
                    args = new AstExpr[] {};
                    return false;
                }

                IEnumerable<AstExpr> getArgsLit;
                if (getArgs.Any())
                {
                    var getArgsLitNode = new AstListLiteral(specProto.File, specProto.Line,
                        specProto.Column);
                    getArgsLitNode.Elements.AddRange(getArgs);
                    getArgsLit = getArgsLitNode.Singleton();
                }
                // ReSharper restore PossibleMultipleEnumeration
                else
                {
                    getArgsLit = Enumerable.Empty<AstExpr>();
                }

                IEnumerable<AstExpr> setArgsLit;
                if (setArgs != null)
                {
                    if (!_ensureExplicitPlaceholder(context, setArgs))
                    {
                        args = new AstExpr[] {};
                        return false;
                    }
                    var lit = new AstListLiteral(setArgs.File, setArgs.Line, setArgs.Column);
                    lit.Elements.Add(setArgs);
                    setArgsLit = lit.Singleton();
                }
                else
                {
                    setArgsLit = Enumerable.Empty<AstExpr>();
                }

                args = getArgsLit
                    .Append(inv.Arguments.Skip(1))
                    .Append(setArgsLit).ToArray();

                return true;
            }
        }