Expression GenImmediateCode(RHC rhc, ObjExpr objx, GenContext context) { ParameterExpression p1 = Expression.Parameter(CompiledType, "__x__"); _thisParam = p1; List <Expression> exprs = new List <Expression>(); if (CompiledType == typeof(RestFnImpl)) { exprs.Add(Expression.Assign(p1, Expression.New(Compiler.Ctor_RestFnImpl_1, Expression.Constant(_variadicMethod.RequiredArity)))); } else { exprs.Add(Expression.Assign(p1, Expression.New(p1.Type))); } for (ISeq s = RT.seq(Methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); LambdaExpression lambda = method.GenerateImmediateLambda(rhc, this, context); string fieldName = IsVariadic && method.IsVariadic ? "_fnDo" + method.RequiredArity : "_fn" + method.NumParams; exprs.Add(Expression.Assign(Expression.Field(p1, fieldName), lambda)); } exprs.Add(p1); Expression expr = Expression.Block(new ParameterExpression[] { p1 }, exprs); return(expr); }
private static int GetMethodKey(FnMethod method) { int arity = method.IsVariadic ? method.RequiredArity + 1 // to avoid the non-variadics, the last of which may have NumParams == this method RequireArity : method.NumParams; return(arity); }
private void GenerateMethods(GenContext context) { for (ISeq s = RT.seq(_methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); method.GenerateCode(context); } }
static bool HasPrimDecls(ISeq forms) { for (ISeq s = forms; s != null; s = RT.next(s)) { if (FnMethod.HasPrimInterface((ISeq)RT.first(s))) { return(true); } } return(false); }
// This naming convention drawn from the Java code. internal void ComputeNames(ISeq form, string name) { FnMethod enclosingMethod = (FnMethod)Compiler.METHODS.deref(); string baseName = enclosingMethod != null ? (enclosingMethod.Fn._name + "$") : (Compiler.Munge(Compiler.CurrentNamespace.Name.Name) + "$"); if (RT.second(form) is Symbol) { name = ((Symbol)RT.second(form)).Name; } _simpleName = (name == null ? "fn" : Compiler.Munge(name).Replace(".", "_DOT_")) + "__" + RT.nextID(); _name = baseName + _simpleName; _internalName = _name.Replace('.', '/'); _fnType = RT.classForName(_internalName); // fn.fntype = Type.getObjectType(fn.internalName) -- JAVA }
void LightCompileMethods() { Dictionary <int, DynamicMethod> dict = new Dictionary <int, DynamicMethod>(); // Create a dynamic method that takes an array of closed-over values // and returns an instance of AFnImpl. for (ISeq s = RT.seq(_methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); method.LightEmit(this, CompiledType); int key = GetMethodKey(method); //dict[key] = new WeakReference(method.DynMethod); dict[key] = method.DynMethod; } DynMethodMap[DynMethodMapKey] = dict; _dynMethodMap = dict; }
protected override void GenerateMethods(GenContext context) { for (ISeq s = RT.seq(Methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); method.GenerateCode(this, context); } if (IsVariadic) { GenerateGetRequiredArityMethod(TypeBuilder, _variadicMethod.RequiredArity); } List <int> supportedArities = new List <int>(); for (ISeq s = RT.seq(Methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); supportedArities.Add(method.NumParams); } GenerateHasArityMethod(TypeBuilder, supportedArities, IsVariadic, IsVariadic ? _variadicMethod.RequiredArity : 0); }
protected override void EmitMethods(TypeBuilder tb) { for (ISeq s = RT.seq(_methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); method.Emit(this, tb); } if (IsVariadic) { EmitGetRequiredArityMethod(_typeBuilder, _variadicMethod.RequiredArity); } List <int> supportedArities = new List <int>(); for (ISeq s = RT.seq(_methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); supportedArities.Add(method.NumParams); } EmitHasArityMethod(_typeBuilder, supportedArities, IsVariadic, IsVariadic ? _variadicMethod.RequiredArity : 0); }
private Expression GenerateImmediateLambda(GenContext context, Type baseClass) { // ParameterExpression p1 = ThisParam ?? Expression.Parameter(baseClass, "____x"); ParameterExpression p1 = Expression.Parameter(baseClass, "____x"); _thisParam = p1; List <Expression> exprs = new List <Expression>(); if (baseClass == typeof(RestFnImpl)) { exprs.Add(Expression.Assign(p1, Expression.New(Compiler.Ctor_RestFnImpl_1, Expression.Constant(_variadicMethod.RequiredArity)))); } else { exprs.Add(Expression.Assign(p1, Expression.New(p1.Type))); } GenContext newContext = CreateContext(context, null, baseClass); for (ISeq s = RT.seq(_methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); LambdaExpression lambda = method.GenerateImmediateLambda(newContext); string fieldName = IsVariadic && method.IsVariadic ? "_fnDo" + method.RequiredArity : "_fn" + method.NumParams; exprs.Add(Expression.Assign(Expression.Field(p1, fieldName), lambda)); } exprs.Add(p1); Expression expr = Expression.Block(new ParameterExpression[] { p1 }, exprs); return(expr); }
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(); } }
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 void AddMethod(FnMethod method) { _methods = RT.conj(_methods, method); }
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(); } } }
public static Expr Parse(ParserContext pcon, ISeq form) { bool tailPosition = Compiler.InTailCall(pcon.Rhc); pcon = pcon.EvalOrExpr(); Expr fexpr = Compiler.Analyze(pcon, form.first()); VarExpr varFexpr = fexpr as VarExpr; if (varFexpr != null && varFexpr.Var.Equals(Compiler.InstanceVar) && RT.count(form) == 3) { Expr sexpr = Compiler.Analyze(pcon.SetRhc(RHC.Expression), RT.second(form)); if (sexpr is ConstantExpr csexpr) { Type tval = csexpr.Val as Type; if (tval != null) { return(new InstanceOfExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), tval, Compiler.Analyze(pcon, RT.third(form)))); } } } if (RT.booleanCast(Compiler.GetCompilerOption(Compiler.DirectLinkingKeyword)) && varFexpr != null && pcon.Rhc != RHC.Eval) { Var v = varFexpr.Var; if (!v.isDynamic() && !RT.booleanCast(RT.get(v.meta(), Compiler.RedefKeyword, false)) && !RT.booleanCast(RT.get(v.meta(), RT.DeclaredKey, false))) { Symbol formTag = Compiler.TagOf(form); //object arglists = RT.get(RT.meta(v), Compiler.ArglistsKeyword); int arity = RT.count(form.next()); object sigtag = SigTag(arity, v); object vtag = RT.get(RT.meta(v), RT.TagKey); if (StaticInvokeExpr.Parse(v, RT.next(form), formTag ?? sigtag ?? vtag) is StaticInvokeExpr ret && !((Compiler.IsCompiling || Compiler.IsCompilingDefType) && GenContext.IsInternalAssembly(ret.Method.DeclaringType.Assembly))) { //Console.WriteLine("invoke direct: {0}", v); return(ret); } //Console.WriteLine("NOT direct: {0}", v); } } if (varFexpr != null && pcon.Rhc != RHC.Eval) { Var v = varFexpr.Var; object arglists = RT.get(RT.meta(v), Compiler.ArglistsKeyword); int arity = RT.count(form.next()); for (ISeq s = RT.seq(arglists); s != null; s = s.next()) { IPersistentVector sargs = (IPersistentVector)s.first(); if (sargs.count() == arity) { string primc = FnMethod.PrimInterface(sargs); if (primc != null) { return(Compiler.Analyze(pcon, ((IObj)RT.listStar(Symbol.intern(".invokePrim"), ((Symbol)form.first()).withMeta(RT.map(RT.TagKey, Symbol.intern(primc))), form.next())).withMeta((IPersistentMap)RT.conj(RT.meta(v), RT.meta(form))))); } break; } } } if (fexpr is KeywordExpr kwFexpr && RT.count(form) == 2 && Compiler.KeywordCallsitesVar.isBound) { Expr target = Compiler.Analyze(pcon, RT.second(form)); return(new KeywordInvokeExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), Compiler.TagOf(form), kwFexpr, target)); } IPersistentVector args = PersistentVector.EMPTY; for (ISeq s = RT.seq(form.next()); s != null; s = s.next()) { args = args.cons(Compiler.Analyze(pcon, s.first())); } //if (args.count() > Compiler.MAX_POSITIONAL_ARITY) // throw new ArgumentException(String.Format("No more than {0} args supported", Compiler.MAX_POSITIONAL_ARITY)); return(new InvokeExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), //Compiler.GetSourceSpanMap(form), Compiler.TagOf(form), fexpr, args, tailPosition)); }
private static int GetMethodKey(FnMethod method) { int arity = method.IsVariadic ? method.RequiredArity + 1 // to avoid the non-variadics, the last of which may have NumParams == this method RequireArity : method.NumParams; return arity; }
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(); } }
static void CloseOver(LocalBinding b, FnMethod method) { if (b != null && method != null) { if (RT.get(method.Locals, b) == null) { method.Fn.Closes = (IPersistentMap)RT.assoc(method.Fn.Closes, b, b); CloseOver(b, method.Parent); } else if (IN_CATCH_FINALLY.deref() != null) { method.LocalsUsedInCatchFinally = (PersistentHashSet)method.LocalsUsedInCatchFinally.cons(b.Index); } } }
public FnMethod(FnExpr fn, FnMethod parent) { _parent = parent; _fn = 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.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(); } }
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; }
void LightEmit(RHC rhc, ObjExpr objx, CljILGen ilg) { //emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any //objx arg is enclosing objx, not this // Create the function instance LocalBuilder fnLocal = ilg.DeclareLocal(CompiledType); if (CompiledType == typeof(RestFnImpl)) { ilg.EmitInt(_variadicMethod.RequiredArity); ilg.EmitNew(Compiler.Ctor_RestFnImpl_1); } else { ilg.EmitNew(Compiler.Ctor_AFnImpl); } ilg.Emit(OpCodes.Stloc, fnLocal); //ilg.EmitString(String.Format("Creating fn {0}", Name)); //ilg.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(string) })); // Set up the methods for (ISeq s = RT.seq(_methods); s != null; s = s.next()) { FnMethod method = (FnMethod)s.first(); int key = GetMethodKey(method); string fieldName = IsVariadic && method.IsVariadic ? "_fnDo" + (key - 1) // because key is arity+1 for variadic : "_fn" + key; FieldInfo fi = CompiledType.GetField(fieldName); ilg.Emit(OpCodes.Ldloc, fnLocal); EmitGetDynMethod(key, ilg); ilg.EmitType(fi.FieldType); ilg.Emit(OpCodes.Ldloc, fnLocal); ilg.Emit(OpCodes.Callvirt, Method_DynamicMethod_CreateDelegate); ilg.Emit(OpCodes.Castclass, fi.FieldType); ilg.EmitFieldSet(fi); } // setup the constants and locals ilg.Emit(OpCodes.Ldloc, fnLocal); if (Constants.count() > 0) { EmitGetCompiledConstants(ilg); } else { ilg.EmitInt(0); ilg.EmitArray(typeof(Object[])); } if (Closes.count() > 0) { int maxIndex = Closes.Max(c => ((LocalBinding)c.key()).Index); ilg.EmitInt(maxIndex + 1); ilg.Emit(OpCodes.Newarr, typeof(object)); for (ISeq s = RT.keys(Closes); s != null; s = s.next()) { LocalBinding lb = (LocalBinding)s.first(); ilg.Emit(OpCodes.Dup); ilg.EmitInt(lb.Index); objx.EmitLocal(ilg, lb); ilg.EmitStoreElement(typeof(object)); } } else { ilg.EmitInt(0); ilg.EmitArray(typeof(Object[])); } // Create the closure ilg.EmitNew(Compiler.Ctor_Closure_2); // Assign the clojure ilg.EmitCall(Compiler.Method_IFnClosure_SetClosure); // Leave the instance on the stack. ilg.Emit(OpCodes.Ldloc, fnLocal); }
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(); } }
public static Expr Parse(ParserContext pcon, ISeq form) { pcon = pcon.EvalOrExpr(); Expr fexpr = Compiler.Analyze(pcon, form.first()); VarExpr varFexpr = fexpr as VarExpr; if (varFexpr != null && varFexpr.Var.Equals(Compiler.InstanceVar)) { if (RT.second(form) is Symbol) { Type t = HostExpr.MaybeType(RT.second(form), false); if (t != null) { return(new InstanceOfExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), t, Compiler.Analyze(pcon, RT.third(form)))); } } } if (varFexpr != null && pcon.Rhc != RHC.Eval) { Var v = varFexpr.Var; object arglists = RT.get(RT.meta(v), Compiler.ArglistsKeyword); int arity = RT.count(form.next()); for (ISeq s = RT.seq(arglists); s != null; s = s.next()) { IPersistentVector sargs = (IPersistentVector)s.first(); if (sargs.count() == arity) { string primc = FnMethod.PrimInterface(sargs); if (primc != null) { return(Compiler.Analyze(pcon, RT.listStar(Symbol.intern(".invokePrim"), ((Symbol)form.first()).withMeta(RT.map(RT.TagKey, Symbol.intern(primc))), form.next()))); } break; } } } KeywordExpr kwFexpr = fexpr as KeywordExpr; if (kwFexpr != null && RT.count(form) == 2 && Compiler.KeywordCallsitesVar.isBound) { Expr target = Compiler.Analyze(pcon, RT.second(form)); return(new KeywordInvokeExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), Compiler.TagOf(form), kwFexpr, target)); } IPersistentVector args = PersistentVector.EMPTY; for (ISeq s = RT.seq(form.next()); s != null; s = s.next()) { args = args.cons(Compiler.Analyze(pcon, s.first())); } //if (args.count() > Compiler.MAX_POSITIONAL_ARITY) // throw new ArgumentException(String.Format("No more than {0} args supported", Compiler.MAX_POSITIONAL_ARITY)); return(new InvokeExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), //Compiler.GetSourceSpanMap(form), Compiler.TagOf(form), fexpr, args)); }
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 void AddMethod(FnMethod method) { _methods = RT.conj(_methods,method); }
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(); } }