// For top-level compilation only // TODO: Can we get rid of this when the DLR-based compile goes away? public FnMethod(FnExpr fn, ObjMethod parent, BodyExpr body) : base(fn, parent) { Body = body; ArgLocals = PersistentVector.EMPTY; //_thisBinding = Compiler.RegisterLocal(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null, false); }
public GenContext CreateWithNewType(FnExpr fnExpr) { GenContext newContext = Clone(); newContext._fnExpr = fnExpr; return(newContext); }
// For top-level compilation only // TODO: Can we get rid of this when the DLR-based compile goes away? public FnMethod(FnExpr fn, ObjMethod parent, BodyExpr body) : base(fn,parent) { _body = body; _argLocals = PersistentVector.EMPTY; //_thisBinding = Compiler.RegisterLocal(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null, false); }
MethodBuilder GenerateStaticMethod(GenContext context) { string methodName = GetStaticMethodName(); FnExpr fn = context.FnExpr; TypeBuilder tb = fn.TypeBuilder; List <ParameterExpression> parms = new List <ParameterExpression>(_argLocals.count() + 1); ParameterExpression thisParm = Expression.Parameter(fn.BaseType, "this"); _thisBinding.ParamExpression = thisParm; fn.ThisParam = thisParm; parms.Add(thisParm); try { LabelTarget loopLabel = Expression.Label("top"); Var.pushThreadBindings(RT.map(Compiler.LOOP_LABEL, loopLabel, Compiler.METHODS, this)); for (int i = 0; i < _argLocals.count(); i++) { LocalBinding lb = (LocalBinding)_argLocals.nth(i); ParameterExpression parm = Expression.Parameter(typeof(object), lb.Name); lb.ParamExpression = parm; parms.Add(parm); } Expression body = Expression.Block( Expression.Label(loopLabel), Compiler.MaybeBox(_body.GenDlr(context))); LambdaExpression lambda = Expression.Lambda(body, parms); // TODO: Figure out why the Java code nulls all the local variables here. // TODO: Cache all the CreateObjectTypeArray values MethodBuilder mb = tb.DefineMethod(methodName, MethodAttributes.Static, typeof(object), Compiler.CreateObjectTypeArray(NumParams)); lambda.CompileToMethod(mb); //lambda.CompileToMethod(mb, true); return(mb); } finally { Var.popThreadBindings(); } }
public static Expr Parse(ParserContext pcon, ISeq form, string name) { ISeq origForm = form; FnExpr fn = new FnExpr(Compiler.TagOf(form)); fn._src = form; if (((IMeta)form.first()).meta() != null) { fn._onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE)); } fn.ComputeNames(form, name); List<string> prims = new List<string>(); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { Symbol nm = (Symbol)RT.second(form); fn._thisName = nm.Name; fn._isStatic = false; // RT.booleanCast(RT.get(nm.meta(), Compiler.STATIC_KEY)); form = RT.cons(Compiler.FnSym, RT.next(RT.next(form))); } // Normalize body //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...) //turn former into latter if (RT.second(form) is IPersistentVector) form = RT.list(Compiler.FnSym, RT.next(form)); fn.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref(); GenContext newContext = null; // Uncomment -if- to enable light compilation (and see below) //bool hasPrimDecls = HasPrimDecls((ISeq)RT.next(form)); //if (Compiler.IsCompiling || hasPrimDecls || fn.IsStatic) //{ GenContext context = Compiler.CompilerContextVar.deref() as GenContext ?? Compiler.EvalContext; newContext = context.WithNewDynInitHelper(fn.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); Var.pushThreadBindings(RT.map(Compiler.CompilerContextVar, newContext)); //} try { try { Var.pushThreadBindings(RT.mapUniqueKeys( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null)); SortedDictionary<int, FnMethod> methods = new SortedDictionary<int, FnMethod>(); FnMethod variadicMethod = null; for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s), fn._isStatic); if (f.IsVariadic) { if (variadicMethod == null) variadicMethod = f; else throw new ParseException("Can't have more than 1 variadic overload"); } else if (!methods.ContainsKey(f.RequiredArity)) methods[f.RequiredArity] = f; else throw new ParseException("Can't have 2 overloads with the same arity."); if (f.Prim != null) prims.Add(f.Prim); } if (variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams) throw new ParseException("Can't have fixed arity methods with more params than the variadic method."); if (fn._isStatic && fn.Closes.count() > 0) throw new ParseException("static fns can't be closures"); IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) allMethods = RT.conj(allMethods, method); if (variadicMethod != null) allMethods = RT.conj(allMethods, variadicMethod); fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); fn.Vars = (IPersistentMap)Compiler.VarsVar.deref(); fn.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); fn.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); fn.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); fn.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } IPersistentMap fmeta = RT.meta(origForm); if (fmeta != null) fmeta = fmeta.without(RT.LineKey).without(RT.ColumnKey).without(RT.SourceSpanKey).without(RT.FileKey); fn._hasMeta = RT.count(fmeta) > 0; // Uncomment if/else to enable light compilation (and see above) //if (Compiler.IsCompiling || prims.Count > 0|| fn.IsStatic) //{ IPersistentVector primTypes = PersistentVector.EMPTY; foreach (string typename in prims) primTypes = primTypes.cons(Type.GetType(typename)); fn.Compile( fn.IsVariadic ? typeof(RestFn) : typeof(AFunction), null, primTypes, fn._onceOnly, newContext); //} //else //{ // fn.FnMode = FnMode.Light; // fn.LightCompile(fn.GetPrecompiledType(), Compiler.EvalContext); //} if (fn.SupportsMeta) return new MetaExpr(fn, MapExpr.Parse(pcon.EvalOrExpr(), fmeta)); else return fn; } finally { if (newContext != null) Var.popThreadBindings(); } }
public FnMethod(FnExpr fn, FnMethod parent) { _parent = parent; _fn = fn; }
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(); } }
internal Expression GenLetFnInits(GenContext context, ParameterExpression parm, FnExpr fn, IPersistentSet leFnLocals) { // TODO: Implement this!!!!!!!!!!!!!!!! // fn is the enclosing IFn, not this. throw new NotImplementedException(); }
public GenContext CreateWithNewType(FnExpr fnExpr) { GenContext newContext = Clone(); newContext._fnExpr = fnExpr; return newContext; }
internal static object Compile(TextReader rdr, string sourceDirectory, string sourceName, string relativePath) { if (COMPILE_PATH.deref() == null) throw new Exception("*compile-path* not set"); object eofVal = new object(); object form; //string sourcePath = sourceDirectory == null ? sourceName : sourceDirectory + "\\" + sourceName; string sourcePath = relativePath; LineNumberingTextReader lntr = (rdr is LineNumberingTextReader) ? (LineNumberingTextReader)rdr : new LineNumberingTextReader(rdr); GenContext context = new GenContext(sourceName, ".dll", sourceDirectory, true); GenContext evalContext = new GenContext("EvalForCompile", false); Var.pushThreadBindings(RT.map( SOURCE_PATH, sourcePath, SOURCE, sourceName, METHOD, null, LOCAL_ENV, null, LOOP_LOCALS, null, NEXT_LOCAL_NUM, 0, RT.CURRENT_NS, RT.CURRENT_NS.deref(), //LINE_BEFORE, lntr.LineNumber, //LINE_AFTER, lntr.LineNumber, DOCUMENT_INFO, Expression.SymbolDocument(sourceName), // I hope this is enough CONSTANTS, PersistentVector.EMPTY, CONSTANT_IDS, new IdentityHashMap(), KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why VAR_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why PROTOCOL_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why COMPILER_CONTEXT, context )); try { FnExpr objx = new FnExpr(null); objx.InternalName = sourcePath.Replace(Path.PathSeparator, '/').Substring(0, sourcePath.LastIndexOf('.')) + "__init"; TypeBuilder exprTB = context.AssemblyGen.DefinePublicType("__REPL__", typeof(object), true); //List<string> names = new List<string>(); List<Expr> exprs = new List<Expr>(); int i = 0; while ((form = LispReader.read(lntr, false, eofVal, false)) != eofVal) { //Java version: LINE_AFTER.set(lntr.LineNumber); Compile1(context, evalContext, exprTB, form, exprs, ref i); //Java version: LINE_BEFORE.set(lntr.LineNumber); } Type exprType = exprTB.CreateType(); // Need to put the loader init in its own type because we can't generate calls on the MethodBuilders // until after their types have been closed. TypeBuilder initTB = context.AssemblyGen.DefinePublicType("__Init__", typeof(object), true); Expression pushNSExpr = Expression.Call(null, Method_Compiler_PushNS); Expression popExpr = Expression.Call(null, Method_Var_popThreadBindings); BodyExpr bodyExpr = new BodyExpr(PersistentVector.create1(exprs)); FnMethod method = new FnMethod(objx, null, bodyExpr); objx.AddMethod(method); objx.Keywords = (IPersistentMap)KEYWORDS.deref(); objx.Vars = (IPersistentMap)VARS.deref(); objx.Constants = (PersistentVector)CONSTANTS.deref(); objx.KeywordCallsites = (IPersistentVector)KEYWORD_CALLSITES.deref(); objx.ProtocolCallsites = (IPersistentVector)PROTOCOL_CALLSITES.deref(); objx.VarCallsites = (IPersistentVector)VAR_CALLSITES.deref(); objx.Compile(typeof(AFunction), PersistentVector.EMPTY, false, context); Expression fnNew = objx.GenCode(RHC.Expression,objx,context); Expression fnInvoke = Expression.Call(fnNew, fnNew.Type.GetMethod("invoke", System.Type.EmptyTypes)); Expression tryCatch = Expression.TryCatchFinally(fnInvoke, popExpr); Expression body = Expression.Block(pushNSExpr, tryCatch); // create initializer call MethodBuilder mbInit = initTB.DefineMethod("Initialize", MethodAttributes.Public | MethodAttributes.Static); LambdaExpression initFn = Expression.Lambda(body); //initFn.CompileToMethod(mbInit, DebugInfoGenerator.CreatePdbGenerator()); initFn.CompileToMethod(mbInit, context.IsDebuggable); initTB.CreateType(); context.SaveAssembly(); } catch (LispReader.ReaderException e) { throw new CompilerException(sourceName, e.Line, e.InnerException); } finally { Var.popThreadBindings(); } return null; }
internal Expression GenLetFnInits(GenContext context, ParameterExpression parm, FnExpr fn, IPersistentSet leFnLocals) { // fn is the enclosing IFn, not this. throw new NotImplementedException(); }
public static Expr Parse(object frm, string name) { ISeq form = (ISeq)frm; FnExpr fn = new FnExpr(Compiler.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, name); try { Var.pushThreadBindings(RT.map( Compiler.CONSTANTS, PersistentVector.EMPTY, Compiler.KEYWORDS, PersistentHashMap.EMPTY, Compiler.VARS, PersistentHashMap.EMPTY)); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { fn._thisName = ((Symbol)RT.second(form)).Name; 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)); } FnMethod variadicMethod = null; SortedDictionary <int, FnMethod> methods = new SortedDictionary <int, FnMethod>(); for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s)); if (f.IsVariadic) { if (variadicMethod == null) { variadicMethod = f; } else { throw new Exception("Can't have more than 1 variadic overload"); } } else if (!methods.ContainsKey(f.RequiredArity)) { methods[f.RequiredArity] = f; } 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."); } IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) { allMethods = RT.conj(allMethods, method); } if (variadicMethod != null) { allMethods = RT.conj(allMethods, variadicMethod); } fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn._keywords = (IPersistentMap)Compiler.KEYWORDS.deref(); fn._vars = (IPersistentMap)Compiler.VARS.deref(); fn._constants = (PersistentVector)Compiler.CONSTANTS.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } // JAVA: fn.compile(); return(fn); }
internal LambdaExpression GenerateImmediateLambda(GenContext context) { List <ParameterExpression> parmExprs = new List <ParameterExpression>(_argLocals.count()); List <ParameterExpression> typedParmExprs = new List <ParameterExpression>(); List <Expression> typedParmInitExprs = new List <Expression>(); //FnExpr fn = context.FnExpr; //ParameterExpression thisParm = Expression.Parameter(fn.BaseType, "this"); //_thisBinding.ParamExpression = thisParm; //fn.ThisParam = thisParm; FnExpr fn = context.FnExpr; _thisBinding.ParamExpression = fn.ThisParam; try { LabelTarget loopLabel = Expression.Label("top"); Var.pushThreadBindings(RT.map(Compiler.LOOP_LABEL, loopLabel, Compiler.METHODS, this)); 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 = Compiler.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(Compiler.MaybeBox(_body.GenDlr(context))); Expression block; if (typedParmExprs.Count > 0) { block = Expression.Block(typedParmExprs, bodyExprs); } else { block = Expression.Block(bodyExprs); } return(Expression.Lambda( FuncTypeHelpers.GetFFuncType(parmExprs.Count), block, _fn.ThisName, parmExprs)); } finally { Var.popThreadBindings(); } }
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(); } }
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()); method._line = (int) Compiler.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); 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,true); return method; } finally { Var.popThreadBindings(); } }
public static Expr Parse(ParserContext pcon, ISeq form, string name) { ISeq origForm = form; FnExpr fn = new FnExpr(Compiler.TagOf(form)); fn.Src = form; Keyword retKey = Keyword.intern(null, "rettag"); // TODO: make static object retTag = RT.get(RT.meta(form), retKey); ObjMethod enclosingMethod = (ObjMethod)Compiler.MethodVar.deref(); fn._hasEnclosingMethod = enclosingMethod != null; if (((IMeta)form.first()).meta() != null) { fn.OnceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE)); } fn.ComputeNames(form, name); List<string> prims = new List<string>(); //arglist might be preceded by symbol naming this fn Symbol nm = RT.second(form) as Symbol; if (nm != null) { fn.ThisName = nm.Name; form = RT.cons(Compiler.FnSym, RT.next(RT.next(form))); } // Normalize body //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...) //turn former into latter if (RT.second(form) is IPersistentVector) form = RT.list(Compiler.FnSym, RT.next(form)); fn.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref(); GenContext newContext = null; GenContext context = Compiler.CompilerContextVar.deref() as GenContext ?? Compiler.EvalContext; newContext = context.WithNewDynInitHelper(fn.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); Var.pushThreadBindings(RT.map(Compiler.CompilerContextVar, newContext)); try { try { Var.pushThreadBindings(RT.mapUniqueKeys( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null)); SortedDictionary<int, FnMethod> methods = new SortedDictionary<int, FnMethod>(); FnMethod variadicMethod = null; bool usesThis = false; for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s), retTag); if ( f.UsesThis) { //Console.WriteLine("{0} uses this",fn.Name); usesThis = true; } if (f.IsVariadic) { if (variadicMethod == null) variadicMethod = f; else throw new ParseException("Can't have more than 1 variadic overload"); } else if (!methods.ContainsKey(f.RequiredArity)) methods[f.RequiredArity] = f; else throw new ParseException("Can't have 2 overloads with the same arity."); if (f.Prim != null) prims.Add(f.Prim); } if (variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams) throw new ParseException("Can't have fixed arity methods with more params than the variadic method."); fn.CanBeDirect = !fn._hasEnclosingMethod && fn.Closes.count() == 0 && !usesThis; IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) allMethods = RT.conj(allMethods, method); if (variadicMethod != null) allMethods = RT.conj(allMethods, variadicMethod); if ( fn.CanBeDirect ) { for (ISeq s = RT.seq(allMethods); s != null; s = s.next()) { FnMethod fm = s.first() as FnMethod; if ( fm.Locals != null) { for (ISeq sl = RT.seq(RT.keys(fm.Locals)); sl != null; sl = sl.next()) { LocalBinding lb = sl.first() as LocalBinding; if ( lb.IsArg) lb.Index -= 1; } } } } fn.Methods = allMethods; fn._variadicMethod = variadicMethod; fn.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); fn.Vars = (IPersistentMap)Compiler.VarsVar.deref(); fn.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); fn.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); fn.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); fn.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); fn.ConstantsID = RT.nextID(); } finally { Var.popThreadBindings(); } IPersistentMap fmeta = RT.meta(origForm); if (fmeta != null) fmeta = fmeta.without(RT.LineKey).without(RT.ColumnKey).without(RT.SourceSpanKey).without(RT.FileKey).without(retKey); fn._hasMeta = RT.count(fmeta) > 0; IPersistentVector primTypes = PersistentVector.EMPTY; foreach (string typename in prims) primTypes = primTypes.cons(Type.GetType(typename)); fn.Compile( fn.IsVariadic ? typeof(RestFn) : typeof(AFunction), null, primTypes, fn.OnceOnly, newContext); if (fn.SupportsMeta) return new MetaExpr(fn, MapExpr.Parse(pcon.EvalOrExpr(), fmeta)); else return fn; } finally { if (newContext != null) Var.popThreadBindings(); } }
public static Expr Parse(object frm, string name, bool isRecurContext) { ISeq form = (ISeq)frm; FnExpr fn = new FnExpr(Compiler.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, name); try { Var.pushThreadBindings(RT.map( Compiler.CONSTANTS, PersistentVector.EMPTY, Compiler.KEYWORDS, PersistentHashMap.EMPTY, Compiler.VARS, PersistentHashMap.EMPTY)); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { fn._thisName = ((Symbol)RT.second(form)).Name; 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)); fn._line = (int)Compiler.LINE.deref(); FnMethod variadicMethod = null; SortedDictionary<int, FnMethod> methods = new SortedDictionary<int, FnMethod>(); for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s)); if (f.IsVariadic) { if (variadicMethod == null) variadicMethod = f; else throw new Exception("Can't have more than 1 variadic overload"); } else if (!methods.ContainsKey(f.RequiredArity)) methods[f.RequiredArity] = f; 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."); IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) allMethods = RT.conj(allMethods, method); if (variadicMethod != null) allMethods = RT.conj(allMethods, variadicMethod); fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn._keywords = (IPersistentMap)Compiler.KEYWORDS.deref(); fn._vars = (IPersistentMap)Compiler.VARS.deref(); fn._constants = (PersistentVector)Compiler.CONSTANTS.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } // JAVA: fn.compile(); return fn; }
internal static object Compile(TextReader rdr, string sourceDirectory, string sourceName, string relativePath) { if (CompilePathVar.deref() == null) throw new InvalidOperationException("*compile-path* not set"); object eofVal = new object(); object form; //string sourcePath = sourceDirectory == null ? sourceName : sourceDirectory + "\\" + sourceName; string sourcePath = relativePath; LineNumberingTextReader lntr = rdr as LineNumberingTextReader ?? new LineNumberingTextReader(rdr); GenContext context = GenContext.CreateWithExternalAssembly(relativePath, ".dll", true); GenContext evalContext = GenContext.CreateWithInternalAssembly("EvalForCompile", false); Var.pushThreadBindings(RT.map( SourcePathVar, sourcePath, SourceVar, sourceName, MethodVar, null, LocalEnvVar, null, LoopLocalsVar, null, NextLocalNumVar, 0, RT.CurrentNSVar, RT.CurrentNSVar.deref(), //LINE_BEFORE, lntr.LineNumber, //LINE_AFTER, lntr.LineNumber, DocumentInfoVar, Expression.SymbolDocument(sourceName), // I hope this is enough ConstantsVar, PersistentVector.EMPTY, ConstantIdsVar, new IdentityHashMap(), KeywordsVar, PersistentHashMap.EMPTY, VarsVar, PersistentHashMap.EMPTY, RT.UncheckedMathVar, RT.UncheckedMathVar.deref(), RT.WarnOnReflectionVar, RT.WarnOnReflectionVar.deref(), RT.DataReadersVar, RT.DataReadersVar.deref(), //KEYWORD_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why //VAR_CALLSITES, EmptyVarCallSites(), // jvm doesn't do this, don't know why //PROTOCOL_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why CompilerContextVar, context )); try { FnExpr objx = new FnExpr(null); objx.InternalName = sourcePath.Replace(Path.PathSeparator, '/').Substring(0, sourcePath.LastIndexOf('.')) + "__init"; TypeBuilder exprTB = context.AssemblyGen.DefinePublicType("__REPL__", typeof(object), true); //List<string> names = new List<string>(); List<Expr> exprs = new List<Expr>(); int i = 0; while ((form = LispReader.read(lntr, false, eofVal, false)) != eofVal) { //Java version: LINE_AFTER.set(lntr.LineNumber); Compile1(context, evalContext, exprTB, form, exprs, ref i); //Java version: LINE_BEFORE.set(lntr.LineNumber); } exprTB.CreateType(); // Need to put the loader init in its own type because we can't generate calls on the MethodBuilders // until after their types have been closed. TypeBuilder initTB = context.AssemblyGen.DefinePublicType("__Init__", typeof(object), true); Expression pushNSExpr = Expression.Call(null, Method_Compiler_PushNS); Expression popExpr = Expression.Call(null, Method_Var_popThreadBindings); BodyExpr bodyExpr = new BodyExpr(PersistentVector.create1(exprs)); FnMethod method = new FnMethod(objx, null, bodyExpr); objx.AddMethod(method); objx.Keywords = (IPersistentMap)KeywordsVar.deref(); objx.Vars = (IPersistentMap)VarsVar.deref(); objx.Constants = (PersistentVector)ConstantsVar.deref(); //objx.KeywordCallsites = (IPersistentVector)KEYWORD_CALLSITES.deref(); //objx.ProtocolCallsites = (IPersistentVector)PROTOCOL_CALLSITES.deref(); //objx.VarCallsites = (IPersistentSet)VAR_CALLSITES.deref(); objx.KeywordCallsites = PersistentVector.EMPTY; objx.ProtocolCallsites = PersistentVector.EMPTY; objx.VarCallsites = (IPersistentSet)EmptyVarCallSites(); objx.Compile(typeof(AFunction), null, PersistentVector.EMPTY, false, context); Expression fnNew = objx.GenCode(RHC.Expression,objx,context); Expression fnInvoke = Expression.Call(fnNew, fnNew.Type.GetMethod("invoke", System.Type.EmptyTypes)); Expression tryCatch = Expression.TryCatchFinally(fnInvoke, popExpr); Expression body = Expression.Block(pushNSExpr, tryCatch); // create initializer call MethodBuilder mbInit = initTB.DefineMethod("Initialize", MethodAttributes.Public | MethodAttributes.Static); LambdaExpression initFn = Expression.Lambda(body); //initFn.CompileToMethod(mbInit, DebugInfoGenerator.CreatePdbGenerator()); initFn.CompileToMethod(mbInit, context.IsDebuggable); initTB.CreateType(); context.SaveAssembly(); } catch (LispReader.ReaderException e) { throw new CompilerException(sourcePath, e.Line, e.InnerException); } finally { Var.popThreadBindings(); } return null; }
public static Expr Parse(ParserContext pcon, ISeq form, string name) { ISeq origForm = form; FnExpr fn = new FnExpr(Compiler.TagOf(form)); fn._src = form; if (((IMeta)form.first()).meta() != null) { fn._onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE)); } fn.ComputeNames(form, name); List <string> prims = new List <string>(); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { Symbol nm = (Symbol)RT.second(form); fn._thisName = nm.Name; fn._isStatic = false; // RT.booleanCast(RT.get(nm.meta(), Compiler.STATIC_KEY)); form = RT.cons(Compiler.FnSym, RT.next(RT.next(form))); } // Normalize body //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...) //turn former into latter if (RT.second(form) is IPersistentVector) { form = RT.list(Compiler.FnSym, RT.next(form)); } fn.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref(); GenContext newContext = null; GenContext context = Compiler.CompilerContextVar.deref() as GenContext ?? Compiler.EvalContext; newContext = context.WithNewDynInitHelper(fn.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); Var.pushThreadBindings(RT.map(Compiler.CompilerContextVar, newContext)); try { try { Var.pushThreadBindings(RT.mapUniqueKeys( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null)); SortedDictionary <int, FnMethod> methods = new SortedDictionary <int, FnMethod>(); FnMethod variadicMethod = null; for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s), fn._isStatic); if (f.IsVariadic) { if (variadicMethod == null) { variadicMethod = f; } else { throw new ParseException("Can't have more than 1 variadic overload"); } } else if (!methods.ContainsKey(f.RequiredArity)) { methods[f.RequiredArity] = f; } else { throw new ParseException("Can't have 2 overloads with the same arity."); } if (f.Prim != null) { prims.Add(f.Prim); } } if (variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams) { throw new ParseException("Can't have fixed arity methods with more params than the variadic method."); } if (fn._isStatic && fn.Closes.count() > 0) { throw new ParseException("static fns can't be closures"); } IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) { allMethods = RT.conj(allMethods, method); } if (variadicMethod != null) { allMethods = RT.conj(allMethods, variadicMethod); } fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); fn.Vars = (IPersistentMap)Compiler.VarsVar.deref(); fn.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); fn.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); fn.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); fn.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } IPersistentMap fmeta = RT.meta(origForm); if (fmeta != null) { fmeta = fmeta.without(RT.LineKey).without(RT.ColumnKey).without(RT.SourceSpanKey).without(RT.FileKey); } fn._hasMeta = RT.count(fmeta) > 0; IPersistentVector primTypes = PersistentVector.EMPTY; foreach (string typename in prims) { primTypes = primTypes.cons(Type.GetType(typename)); } fn.Compile( fn.IsVariadic ? typeof(RestFn) : typeof(AFunction), null, primTypes, fn._onceOnly, newContext); if (fn.SupportsMeta) { return(new MetaExpr(fn, MapExpr.Parse(pcon.EvalOrExpr(), fmeta))); } else { return(fn); } } finally { if (newContext != null) { Var.popThreadBindings(); } } }
internal static FnMethod Parse(FnExpr fn, ISeq form, bool isStatic) { // ([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('.', '/'); method._retType = Compiler.TagType(Compiler.TagOf(parms)); if (method._retType.IsPrimitive && !(method._retType == typeof(double) || method._retType == typeof(long))) throw new ParseException("Only long and double primitives are supported"); // register 'this' as local 0 if ( !isStatic ) //method._thisBinding = Compiler.RegisterLocalThis(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null); 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 (isStatic) // throw new Exception("Variadic fns cannot be static"); 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), true) : Compiler.RegisterLocal(p, paramState == ParamParseState.Rest ? Compiler.ISeqSym : Compiler.TagOf(p), null,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; //if (isStatic) if ( method.Prim != null ) method._argTypes = argTypes.ToArray(); method._body = (new BodyExpr.Parser()).Parse(new ParserContext(RHC.Return),body); return method; } finally { Var.popThreadBindings(); } }
public FnMethod(FnExpr fn, ObjMethod parent) : base(fn, parent) { }
public FnMethod(FnExpr fn, ObjMethod parent) : base(fn,parent) { }
public static Expr Parse(ParserContext pcon, ISeq form, string name) { ISeq origForm = form; FnExpr fn = new FnExpr(Compiler.TagOf(form)); fn._src = form; if (((IMeta)form.first()).meta() != null) { fn._onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE)); } fn.ComputeNames(form, name); // Java: fn.objtype = Type.getObjectType(fn.internalName) -- makes no sense for us, this is ASM only. List<string> prims = new List<string>(); try { Var.pushThreadBindings(RT.map( Compiler.CONSTANTS, PersistentVector.EMPTY, Compiler.CONSTANT_IDS, new IdentityHashMap(), Compiler.KEYWORDS, PersistentHashMap.EMPTY, Compiler.VARS, PersistentHashMap.EMPTY, Compiler.KEYWORD_CALLSITES,PersistentVector.EMPTY, Compiler.PROTOCOL_CALLSITES,PersistentVector.EMPTY, Compiler.VAR_CALLSITES,Compiler.EmptyVarCallSites(), Compiler.NO_RECUR,null)); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { Symbol nm = (Symbol)RT.second(form); fn._thisName = nm.Name; fn.IsStatic = false; // RT.booleanCast(RT.get(nm.meta(), Compiler.STATIC_KEY)); form = RT.cons(Compiler.FN, RT.next(RT.next(form))); } // Normalize body //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...) //turn former into latter if (RT.second(form) is IPersistentVector) form = RT.list(Compiler.FN, RT.next(form)); SortedDictionary<int, FnMethod> methods = new SortedDictionary<int, FnMethod>(); FnMethod variadicMethod = null; for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s),fn.IsStatic); if (f.IsVariadic) { if (variadicMethod == null) variadicMethod = f; else throw new Exception("Can't have more than 1 variadic overload"); } else if (!methods.ContainsKey(f.RequiredArity)) methods[f.RequiredArity] = f; else throw new Exception("Can't have 2 overloads with the same arity."); if (f.Prim != null) prims.Add(f.Prim); } 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.IsStatic && fn.Closes.count() > 0 ) throw new ArgumentException("static fns can't be closures"); IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) allMethods = RT.conj(allMethods, method); if (variadicMethod != null) allMethods = RT.conj(allMethods, variadicMethod); fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn.Keywords = (IPersistentMap)Compiler.KEYWORDS.deref(); fn.Vars = (IPersistentMap)Compiler.VARS.deref(); fn.Constants = (PersistentVector)Compiler.CONSTANTS.deref(); fn.KeywordCallsites = (IPersistentVector)Compiler.KEYWORD_CALLSITES.deref(); fn.ProtocolCallsites = (IPersistentVector)Compiler.PROTOCOL_CALLSITES.deref(); fn.VarCallsites = (IPersistentSet)Compiler.VAR_CALLSITES.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } IPersistentMap fmeta = RT.meta(origForm); if (fmeta != null) fmeta = fmeta.without(RT.LINE_KEY).without(RT.FILE_KEY); fn._hasMeta = RT.count(fmeta) > 0; if (Compiler.IsCompiling || prims.Count > 0) { GenContext context = Compiler.COMPILER_CONTEXT.get() as GenContext ?? Compiler.EvalContext; GenContext genC = context.WithNewDynInitHelper(fn.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); IPersistentVector primTypes = PersistentVector.EMPTY; foreach (string typename in prims) primTypes = primTypes.cons(Type.GetType(typename)); fn.Compile( fn.IsVariadic ? typeof(RestFn) : typeof(AFunction), null, primTypes, fn.OnceOnly, genC); } else { fn.CompiledType = fn.GetPrecompiledType(); fn.FnMode = FnMode.Light; } if (fn.SupportsMeta) return new MetaExpr(fn, MapExpr.Parse(pcon.EvEx(),fmeta)); else return fn; }
internal static FnMethod Parse(FnExpr fn, ISeq form, bool isStatic) { // ([args] body ... ) IPersistentVector parms = (IPersistentVector)RT.first(form); ISeq body = RT.next(form); try { FnMethod method = new FnMethod(fn, (ObjMethod)Compiler.METHOD.deref()); Var.pushThreadBindings(RT.map( Compiler.METHOD, method, Compiler.LOCAL_ENV, Compiler.LOCAL_ENV.deref(), Compiler.LOOP_LOCALS, null, Compiler.NEXT_LOCAL_NUM, 0)); method._prim = PrimInterface(parms); //if (method._prim != null) // method._prim = method._prim.Replace('.', '/'); method._retType = Compiler.TagType(Compiler.TagOf(parms)); if (method._retType.IsPrimitive && !(method._retType == typeof(double) || method._retType == typeof(long))) throw new ArgumentException("Only long and double primitives are supported"); // register 'this' as local 0 if ( !isStatic ) method._thisBinding = Compiler.RegisterLocal(Symbol.intern(fn.ThisName ?? "fn__" + RT.nextID()), null, null,false); 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 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 (isStatic) // throw new Exception("Variadic fns cannot be static"); if (paramState == ParamParseState.Required) paramState = ParamParseState.Rest; else throw new Exception("Invalid parameter list"); } else { Type pt = Compiler.PrimType(Compiler.TagType(Compiler.TagOf(p))); //if (pt.IsPrimitive && !isStatic) //{ // pt = typeof(object); // p = (Symbol)((IObj)p).withMeta((IPersistentMap)RT.assoc(RT.meta(p), RT.TAG_KEY, null)); // //throw new Exception("Non-static fn can't have primitive parameter: " + p); //} if (pt.IsPrimitive && !(pt == typeof(double) || pt == typeof(long))) throw new ArgumentException("Only long and double primitives are supported: " + p); if (paramState == ParamParseState.Rest && Compiler.TagOf(p) != null) throw new Exception("& arg cannot have type hint"); if (paramState == ParamParseState.Rest && method.Prim != null) throw new Exception("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), true) : Compiler.RegisterLocal(p, paramState == ParamParseState.Rest ? Compiler.ISEQ : Compiler.TagOf(p), null,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 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; //if (isStatic) if ( method.Prim != null ) method._argTypes = argTypes.ToArray(); method._body = (new BodyExpr.Parser()).Parse(new ParserContext(RHC.Return),body); return method; } finally { Var.popThreadBindings(); } }