Exemplo n.º 1
0
        internal static FnMethod Parse(FnExpr fn, ISeq form, object retTag)
        {
            // ([args] body ... )

            IPersistentVector parms = (IPersistentVector)RT.first(form);
            ISeq body = RT.next(form);

            try
            {
                FnMethod method = new FnMethod(fn, (ObjMethod)Compiler.MethodVar.deref());
                method.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref();

                Var.pushThreadBindings(RT.mapUniqueKeys(
                                           Compiler.MethodVar, method,
                                           Compiler.LocalEnvVar, Compiler.LocalEnvVar.deref(),
                                           Compiler.LoopLocalsVar, null,
                                           Compiler.NextLocalNumVar, 0));

                method._prim = PrimInterface(parms);
                //if (method._prim != null)
                //    method._prim = method._prim.Replace('.', '/');


                if (retTag is String)
                {
                    retTag = Symbol.intern(null, (string)retTag);
                }
                if (!(retTag is Symbol))
                {
                    retTag = null;
                }
                if (retTag != null)
                {
                    string retStr = ((Symbol)retTag).Name;
                    if (!(retStr.Equals("long") || retStr.Equals("double")))
                    {
                        retTag = null;
                    }
                }
                method._retType = Compiler.TagType(Compiler.TagOf(parms) ?? retTag);

                if (method._retType.IsPrimitive)
                {
                    if (!(method._retType == typeof(double) || method._retType == typeof(long)))
                    {
                        throw new ParseException("Only long and double primitives are supported");
                    }
                }
                else
                {
                    method._retType = typeof(object);
                }

                // register 'this' as local 0
                Compiler.RegisterLocalThis(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null);

                ParamParseState   paramState = ParamParseState.Required;
                IPersistentVector argLocals  = PersistentVector.EMPTY;
                List <Type>       argTypes   = new List <Type>();

                int parmsCount = parms.count();

                for (int i = 0; i < parmsCount; i++)
                {
                    if (!(parms.nth(i) is Symbol))
                    {
                        throw new ParseException("fn params must be Symbols");
                    }
                    Symbol p = (Symbol)parms.nth(i);
                    if (p.Namespace != null)
                    {
                        throw new ParseException("Can't use qualified name as parameter: " + p);
                    }
                    if (p.Equals(Compiler.AmpersandSym))
                    {
                        if (paramState == ParamParseState.Required)
                        {
                            paramState = ParamParseState.Rest;
                        }
                        else
                        {
                            throw new ParseException("Invalid parameter list");
                        }
                    }
                    else
                    {
                        Type pt = Compiler.PrimType(Compiler.TagType(Compiler.TagOf(p)));

                        if (pt.IsPrimitive && !(pt == typeof(double) || pt == typeof(long)))
                        {
                            throw new ParseException("Only long and double primitives are supported: " + p);
                        }

                        if (paramState == ParamParseState.Rest && Compiler.TagOf(p) != null)
                        {
                            throw new ParseException("& arg cannot have type hint");
                        }
                        if (paramState == ParamParseState.Rest && method.Prim != null)
                        {
                            throw new ParseException("fns taking primitives cannot be variadic");
                        }
                        if (paramState == ParamParseState.Rest)
                        {
                            pt = typeof(ISeq);
                        }
                        argTypes.Add(pt);
                        LocalBinding b = pt.IsPrimitive
                            ? Compiler.RegisterLocal(p, null, new MethodParamExpr(pt), pt, true)
                            : Compiler.RegisterLocal(p,
                                                     paramState == ParamParseState.Rest ? Compiler.ISeqSym : Compiler.TagOf(p),
                                                     null, pt, true);

                        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 ParseException("Unexpected parameter");
                        }
                    }
                }

                if (method.RequiredArity > Compiler.MaxPositionalArity)
                {
                    throw new ParseException(string.Format("Can't specify more than {0} parameters", Compiler.MaxPositionalArity));
                }
                Compiler.LoopLocalsVar.set(argLocals);
                method.ArgLocals = argLocals;
                method._argTypes = argTypes.ToArray();
                method.Body      = (new BodyExpr.Parser()).Parse(new ParserContext(RHC.Return), body);
                return(method);
            }
            finally
            {
                Var.popThreadBindings();
            }
        }
Exemplo n.º 2
0
        internal static FnMethod Parse(FnExpr fn, ISeq form)
        {
            // ([args] body ... )

            IPersistentVector parms = (IPersistentVector)RT.first(form);
            ISeq body = RT.next(form);

            try
            {
                FnMethod method = new FnMethod(fn, (FnMethod)Compiler.METHODS.deref());
                // TODO: method.line = (Integer) LINE.deref();


                Var.pushThreadBindings(RT.map(
                                           Compiler.METHODS, method,
                                           Compiler.LOCAL_ENV, Compiler.LOCAL_ENV.deref(),
                                           Compiler.LOOP_LOCALS, null,
                                           Compiler.NEXT_LOCAL_NUM, 0));

                // register 'this' as local 0
                method._thisBinding = Compiler.RegisterLocal(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null);

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

                for (int i = 0; i < parmsCount; i++)
                {
                    if (!(parms.nth(i) is Symbol))
                    {
                        throw new ArgumentException("fn params must be Symbols");
                    }
                    Symbol p = (Symbol)parms.nth(i);
                    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 = Compiler.RegisterLocal(p,
                                                                paramState == ParamParseState.Rest ? Compiler.ISEQ : Compiler.TagOf(p),
                                                                null); // asdf-tag

                        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 > Compiler.MAX_POSITIONAL_ARITY)
                {
                    throw new Exception(string.Format("Can't specify more than {0} parameters", Compiler.MAX_POSITIONAL_ARITY));
                }
                Compiler.LOOP_LOCALS.set(argLocals);
                method._argLocals = argLocals;
                method._body      = (new BodyExpr.Parser()).Parse(body);
                return(method);
            }
            finally
            {
                Var.popThreadBindings();
            }
        }