예제 #1
0
        private static MethodDef GenerateFnMethod(FnDef fn, ISeq form)
        {
            // form == ([args] body ... )
            IPersistentVector parms = (IPersistentVector)RT.first(form);
            ISeq body = RT.next(form);

            MethodDef method = new MethodDef(fn, (MethodDef)METHODS.deref());

            try
            {
                LabelTarget loopLabel = Expression.Label();

                Var.pushThreadBindings(PersistentHashMap.create(
                    METHODS, method,
                    LOOP_LABEL, loopLabel,
                    LOCAL_ENV, LOCAL_ENV.deref(),
                    LOOP_LOCALS, null));

                // register 'this' as local 0
                LocalBinding thisB = RegisterLocal(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null);  //asdf-tag
                thisB.ParamExpression = fn.ThisParam;

                IPersistentVector argLocals = PersistentVector.EMPTY;
                int parmsCount = parms.count();
                ParamParseState paramState = ParamParseState.Required;

                for (int i = 0; i < parmsCount; i++)
                {
                    if (!(parms.nth(i) is Symbol))
                        throw new ArgumentException("fn params must be Symbols");
                    Symbol p = parms.nth(i) as Symbol;
                    if (p.Namespace != null)
                        throw new Exception("Can't use qualified name as parameter: " + p);
                    if (p.Equals(Compiler._AMP_))
                    {
                        if (paramState == ParamParseState.Required)
                            paramState = ParamParseState.Rest;
                        else
                            throw new Exception("Invalid parameter list");
                    }
                    else
                    {
                        LocalBinding b = RegisterLocal(p, paramState == ParamParseState.Rest ? ISEQ : TagOf(p), null); // asdf-tag
                        //LocalBinding b = RegisterLocal(p, TagOf(p), null);

                        argLocals = argLocals.cons(b);
                        switch (paramState)
                        {
                            case ParamParseState.Required:
                                method.ReqParms = method.ReqParms.cons(b);
                                break;
                            case ParamParseState.Rest:
                                method.RestParm = b;
                                paramState = ParamParseState.Done;
                                break;
                            default:
                                throw new Exception("Unexpected parameter");
                        }
                    }
                }

                if (method.NumParams > MAX_POSITIONAL_ARITY)
                    throw new Exception(string.Format("Can't specify more than {0} parameters",MAX_POSITIONAL_ARITY));
                LOOP_LOCALS.set(argLocals);
                method.ArgLocals = argLocals;

                List<ParameterExpression> parmExprs = new List<ParameterExpression>(argLocals.count());
                List<ParameterExpression> typedParmExprs = new List<ParameterExpression>();
                List<Expression> typedParmInitExprs = new List<Expression>();

                for (int i = 0; i < argLocals.count(); i++)
                {
                    LocalBinding b = (LocalBinding)argLocals.nth(i);

                    ParameterExpression pexpr = Expression.Parameter(typeof(object), b.Name);  //asdf-tag
                    b.ParamExpression = pexpr;
                    parmExprs.Add(pexpr);

                    if (b.Tag != null)
                    {
                        // we have a type hint
                        // The ParameterExpression above will be the parameter to the function.
                        // We need to generate another local parameter that is typed.
                        // This will be the parameter tied to the LocalBinding so that the typing information is seen in the body.
                        Type t = TagToType(b.Tag);
                        ParameterExpression p2 = Expression.Parameter(t, b.Name);
                        b.ParamExpression = p2;
                        typedParmExprs.Add(p2);
                        typedParmInitExprs.Add(Expression.Assign(p2, Expression.Convert(pexpr, t)));
                    }
                }

                // TODO:  Eventually, type this param to ISeq.
                // This will require some reworking with signatures in various places around here.
                //if (fn.IsVariadic)
                //    parmExprs.Add(Expression.Parameter(typeof(object), "____REST"));

                // If we have any typed parameters, we need to add an extra block to do the initialization.

                List<Expression> bodyExprs = new List<Expression>();
                bodyExprs.AddRange(typedParmInitExprs);
                bodyExprs.Add(Expression.Label(loopLabel));
                bodyExprs.Add(MaybeBox(GenerateBodyExpr(body)));

                Expression block;
                if ( typedParmExprs.Count > 0 )
                    block = Expression.Block(typedParmExprs,bodyExprs);
                else
                    block = Expression.Block(bodyExprs);

                method.Lambda = Expression.Lambda(
                    FuncTypeHelpers.GetFFuncType(parmExprs.Count),
                    block,
                    fn.Name,
                    parmExprs);

                //method.Lambda = Expression.Lambda(
                //    FuncTypeHelpers.GetFFuncType(parmExprs.Count),
                //    Expression.Block(Expression.Label(loopLabel), MaybeBox(GenerateBodyExpr(body))),
                //    fn.Name,
                //    parmExprs);

                return method;
            }
            finally
            {
                Var.popThreadBindings();
            }
        }
예제 #2
0
        private static Expression GenerateFnLambda(FnDef fn, SortedDictionary<int, MethodDef> methods, MethodDef variadicMethod)
        {
            // TODO: Supername metadata on form can change the implementation superclass.
            Type fnType = fn.ImplType;

            if (fn.SuperName != null)
                Console.WriteLine("Crap");

            ParameterExpression p1 = fn.ThisParam ?? Expression.Parameter(fnType, "____x");
            List<Expression> exprs = new List<Expression>();

            if ( p1.Type == typeof(AFnImpl) )
                exprs.Add(Expression.Assign(p1, Expression.New(Ctor_AFnImpl_0)));
            else if (p1.Type == typeof(RestFnImpl))
                exprs.Add(Expression.Assign(p1, Expression.New(Ctor_RestFnImpl_1, Expression.Constant(variadicMethod.RequiredArity))));
            else
                exprs.Add(Expression.Assign(p1,Expression.New(p1.Type)));

            foreach (KeyValuePair<int, MethodDef> pair in methods)
            {
                int arity = pair.Key;
                LambdaExpression lambda = pair.Value.Lambda;
                exprs.Add(Expression.Assign(Expression.Field(p1, "_fn" + arity), lambda));
            }

            if (fn.IsVariadic)
                exprs.Add(Expression.Assign(Expression.Field(p1, "_fnDo" + variadicMethod.RequiredArity), variadicMethod.Lambda));

               exprs.Add(p1);

               Expression expr = Expression.Block(new ParameterExpression[] { p1 }, exprs);
               return expr;
        }
예제 #3
0
        private static Expression GenerateFnExpr(ISeq form)
        {
            FnDef fn = new FnDef(TagOf(form));

            if (((IMeta)form.first()).meta() != null)
            {
                fn.OnceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE));
                fn.SuperName = (string)RT.get(RT.meta(form.first()), KW_SUPER_NAME);
            }

            fn.ComputeNames(form);

            Symbol name = null;
            if ( RT.second(form) is Symbol )
            {
                name = (Symbol)RT.second(form);
                form = RT.cons(Compiler.FN, RT.next(RT.next(form)));
            }

            // Normalize body
            // If it is (fn [arg...] body ...), turn it into
            //  (fn ([arg...] body...))
            // so that we can treat uniformly as (fn ([arg...] body...) ([arg...] body...) ... )
            if (RT.second(form) is IPersistentVector)
                form = RT.list(Compiler.FN, RT.next(form));

            // needs to be called after normalization
            fn.IsVariadic = ComputeIsVariadicQuickly(RT.next(form));

            // Create the 'this' parameter needed for recursion
            // we no longer need the name (second element) if it is given
            if (name != null )
            {
                // ThisName will be non-null;
                fn.ThisParam = Expression.Parameter(fn.ImplType, fn.ThisName);
            }

            MethodDef variadicMethod = null;
            SortedDictionary<int, MethodDef> methods = new SortedDictionary<int, MethodDef>();

            for (ISeq s = RT.next(form); s != null; s = s.next())
            {
                MethodDef method = GenerateFnMethod(fn, (ISeq) s.first());
                if (method.IsVariadic)
                {
                    if (variadicMethod == null)
                        variadicMethod = method;
                    else
                        throw new Exception("Can't have more than 1 variadic overload");
                }
                else if (! methods.ContainsKey(method.RequiredArity))
                    methods[method.RequiredArity] = method;
                else
                    throw new Exception("Can't have 2 overloads with the same arity.");
            }

            if ( variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams )
                throw new Exception("Can't have fixed arity methods with more params than the variadic method.");

            if (fn.IsVariadic != (variadicMethod != null))
                throw new Exception("Internal error:  ComputeIsVariadicQuickly failed!!!");

            return GenerateFnLambda(fn, methods, variadicMethod);
        }
예제 #4
0
 internal MethodDef(FnDef fn, MethodDef parent)
 {
     _fn = fn;
     _parent = parent;
 }
예제 #5
0
        // There is a tremendous overlap between this and GenerateFnExpr+GenerateFnMethod.  TODO: DRY it.
        private static LambdaExpression GenerateTypedDelegateExpression(Type delegateType, Symbol name, IPersistentVector parms, ISeq body)
        {
            // Create the form that is more or less correct

            ISeq form = (name == null)
                ? RT.cons(Compiler.FN, RT.cons(parms, body))
                : RT.cons(Compiler.FN, RT.cons(name, RT.cons(parms, body)));

            FnDef fnDef = new FnDef(null); // compute tag from delegateType?
            fnDef.ComputeNames(form);

            MethodDef methodDef = new MethodDef(fnDef, (MethodDef)METHODS.deref());

            try
            {
                LabelTarget loopLabel = Expression.Label();

                Var.pushThreadBindings(PersistentHashMap.create(
                    METHODS, methodDef,
                    LOOP_LABEL, loopLabel,
                    LOCAL_ENV, LOCAL_ENV.deref(),
                    LOOP_LOCALS, null));

                // register 'this' as local 0
                LocalBinding thisB = RegisterLocal(Symbol.intern(fnDef.ThisName ?? "fn__" + RT.nextID()), null, null);
                thisB.ParamExpression = fnDef.ThisParam;

                IPersistentVector argLocals = PersistentVector.EMPTY;
                int parmsCount = parms.count();
                ParamParseState paramState = ParamParseState.Required;

                for (int i = 0; i < parmsCount; i++)
                {
                    if (!(parms.nth(i) is Symbol))
                        throw new ArgumentException("fn params must be Symbols");
                    Symbol p = parms.nth(i) as Symbol;
                    if (p.Namespace != null)
                        throw new Exception("Can't use qualified name as parameter: " + p);
                    if (p.Equals(Compiler._AMP_))
                    {
                        if (paramState == ParamParseState.Required)
                            paramState = ParamParseState.Rest;
                        else
                            throw new Exception("Invalid parameter list");
                    }
                    else
                    {
                        // TODO: Need more type inferencing to make this work.
                        //LocalBinding b = RegisterLocal(p, paramState == ParamParseState.Rest ? ISEQ : TagOf(p), null);
                        LocalBinding b = RegisterLocal(p, TagOf(p), null);

                        argLocals = argLocals.cons(b);
                        switch (paramState)
                        {
                            case ParamParseState.Required:
                                methodDef.ReqParms = methodDef.ReqParms.cons(b);
                                break;
                            case ParamParseState.Rest:
                                methodDef.RestParm = b;
                                paramState = ParamParseState.Done;
                                break;
                            default:
                                throw new Exception("Unexpected parameter");
                        }
                    }
                }

                MethodInfo invokeMI = delegateType.GetMethod("Invoke");
                Type returnType = invokeMI.ReturnType;
                ParameterInfo[] delParams = invokeMI.GetParameters();

                bool isVariadic = (invokeMI.CallingConvention & CallingConventions.VarArgs) != 0;
                if (isVariadic != methodDef.IsVariadic)
                    throw new ArgumentException("Arglist and delegate type must agree on being variadic.");

                if (delParams.Length != argLocals.count() )
                    throw new ArgumentException("Wrong number of parameters to generate typed delegate");

                if (methodDef.NumParams > MAX_POSITIONAL_ARITY)
                    throw new Exception(string.Format("Can't specify more than {0} parameters",MAX_POSITIONAL_ARITY));

                LOOP_LOCALS.set(argLocals);
                methodDef.ArgLocals = argLocals;

                List<ParameterExpression> parmExprs = new List<ParameterExpression>(argLocals.count());
                for (int i = 0; i < argLocals.count(); i++)
                {
                    LocalBinding b = (LocalBinding)argLocals.nth(i);
                    ParameterExpression pexpr = Expression.Parameter(delParams[i].ParameterType, b.Name);  //asdf-tag
                    b.ParamExpression = pexpr;
                    parmExprs.Add(pexpr);
                }

                methodDef.Lambda = Expression.Lambda(
                    delegateType,
                    Expression.Block(
                      Expression.Label(loopLabel),
                      Expression.Convert(GenerateBodyExpr(body),returnType)),
                      fnDef.Name,
                      parmExprs);

                return methodDef.Lambda;

            }
            finally
            {
                Var.popThreadBindings();
            }
        }
예제 #6
0
        private static Expression GenerateFnLambda(FnDef fn, SortedDictionary<int, MethodDef> methods, MethodDef variadicMethod)
        {
            Type fnType = fn.IsVariadic ? typeof(RestFnImpl) : typeof(AFnImpl);

            ParameterExpression p1 = fn.ThisParam ?? Expression.Parameter(fnType, "____x");
            List<Expression> exprs = new List<Expression>();

            if (fn.IsVariadic)
                exprs.Add(Expression.Assign(p1, Expression.New(Ctor_RestFnImpl_1, Expression.Constant(variadicMethod.RequiredArity))));
            else
                exprs.Add(Expression.Assign(p1, Expression.New(Ctor_AFnImpl_0)));

            foreach (KeyValuePair<int, MethodDef> pair in methods)
            {
                int arity = pair.Key;
                LambdaExpression lambda = pair.Value.Lambda;
                exprs.Add(Expression.Assign(Expression.Field(p1, "_fn" + arity), lambda));
            }

            if (fn.IsVariadic)
                exprs.Add(Expression.Assign(Expression.Field(p1, "_fnDo" + variadicMethod.RequiredArity), variadicMethod.Lambda));

               exprs.Add(p1);

               Expression expr = Expression.Block(new ParameterExpression[] { p1 }, exprs);
               return expr;
        }