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(); } }
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; }
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); }
internal MethodDef(FnDef fn, MethodDef parent) { _fn = fn; _parent = parent; }
// 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(); } }
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; }