Permalink
Browse files

metadata for fns

  • Loading branch information...
1 parent 277f023 commit 430dd4fa711d0008137d7a82d4b4cd27b6e2d6d1 @richhickey committed Jan 19, 2010
View
@@ -36,7 +36,9 @@
(def
#^{:macro true}
- fn (fn* fn [&form &env & decl] (cons 'fn* decl)))
+ fn (fn* fn [&form &env & decl]
+ (.withMeta #^clojure.lang.IObj (cons 'fn* decl)
+ (.meta #^clojure.lang.IMeta &form))))
(def
#^{:arglists '([coll])
@@ -241,10 +243,10 @@
(if (instance? clojure.lang.Symbol iname) false true))
;; inserts the same fn name to the inline fn if it does not have one
(assoc m :inline (cons ifn (cons name (next inline))))
- m))]
- (list 'def (with-meta name (conj (if (meta name) (meta name) {}) m))
- (cons `fn (cons name fdecl))))))
- ;(cons `fn fdecl)))))
+ m))
+ m (conj (if (meta name) (meta name) {}) m)]
+ (list 'def (with-meta name m)
+ (list '.withMeta (cons `fn (cons name fdecl)) (list '.meta (list 'var name)))))))
(. (var defn) (setMacro))
@@ -14,18 +14,7 @@
import java.io.Serializable;
-public abstract class AFn extends Obj implements IFn, Serializable{
-
-public AFn(IPersistentMap meta){
- super(meta);
-}
-
-public AFn(){
-}
-
-public Obj withMeta(IPersistentMap meta){
- throw new UnsupportedOperationException();
-}
+public abstract class AFn implements IFn, Serializable{
public Object call() throws Exception{
return invoke();
@@ -14,19 +14,11 @@
import java.util.Comparator;
-public abstract class AFunction extends AFn implements Comparator, Fn{
+public abstract class AFunction extends AFn implements IObj, Comparator, Fn{
//note - this is not even volatile by design
public MethodImplCache __methodImplCache;
-public AFunction(IPersistentMap meta){
- super(meta);
-}
-
-public AFunction(){
- super();
-}
-
public int compare(Object o1, Object o2){
try
{
@@ -15,15 +15,6 @@
public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable{
int _hash = -1;
-
-protected APersistentMap(IPersistentMap meta){
- super(meta);
-}
-
-
-protected APersistentMap(){
-}
-
public String toString(){
return RT.printString(this);
}
@@ -20,8 +20,7 @@
int _hash = -1;
final IPersistentMap impl;
-protected APersistentSet(IPersistentMap meta, IPersistentMap impl){
- super(meta);
+protected APersistentSet(IPersistentMap impl){
this.impl = impl;
}
@@ -13,20 +13,12 @@
package clojure.lang;
import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable,
List,
RandomAccess, Comparable, Streamable{
int _hash = -1;
-public APersistentVector(IPersistentMap meta){
- super(meta);
-}
-
-protected APersistentVector(){
-}
-
public String toString(){
return RT.printString(this);
}
@@ -516,14 +508,17 @@ public int count(){
}
}
-static class SubVector extends APersistentVector{
+static class SubVector extends APersistentVector implements IObj{
final IPersistentVector v;
final int start;
final int end;
+ final IPersistentMap _meta;
+
public SubVector(IPersistentMap meta, IPersistentVector v, int start, int end){
- super(meta);
+ this._meta = meta;
+
if(v instanceof APersistentVector.SubVector)
{
APersistentVector.SubVector sv = (APersistentVector.SubVector) v;
@@ -575,5 +570,9 @@ public SubVector withMeta(IPersistentMap meta){
return this;
return new SubVector(meta, v, start, end);
}
+
+ public IPersistentMap meta(){
+ return _meta;
+ }
}
}
@@ -181,6 +181,9 @@
//vector<object>
static final public Var CONSTANTS = Var.create();
+//IdentityHashMap
+static final public Var CONSTANT_IDS = Var.create();
+
//vector<keyword>
static final public Var KEYWORD_CALLSITES = Var.create();
@@ -359,19 +362,19 @@ public Object eval() throws Exception{
public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
objx.emitVar(gen, var);
- if(initProvided)
- {
- gen.dup();
- init.emit(C.EXPRESSION, objx, gen);
- gen.invokeVirtual(VAR_TYPE, bindRootMethod);
- }
if(meta != null)
{
gen.dup();
meta.emit(C.EXPRESSION, objx, gen);
gen.checkCast(IPERSISTENTMAP_TYPE);
gen.invokeVirtual(VAR_TYPE, setMetaMethod);
}
+ if(initProvided)
+ {
+ gen.dup();
+ init.emit(C.EXPRESSION, objx, gen);
+ gen.invokeVirtual(VAR_TYPE, bindRootMethod);
+ }
if(context == C.STATEMENT)
gen.pop();
@@ -3070,6 +3073,14 @@ public FnExpr(Object tag){
super(tag);
}
+ public boolean hasJavaClass() throws Exception{
+ return true;
+ }
+
+ public Class getJavaClass() throws Exception{
+ return AFunction.class;
+ }
+
protected void emitMethods(ClassVisitor cv){
//override of invoke/doInvoke for each method
for(ISeq s = RT.seq(methods); s != null; s = s.next())
@@ -3093,6 +3104,7 @@ protected void emitMethods(ClassVisitor cv){
}
static Expr parse(C context, ISeq form, String name) throws Exception{
+ ISeq origForm = form;
FnExpr fn = new FnExpr(tagOf(form));
ObjMethod enclosingMethod = (ObjMethod) METHOD.deref();
if(((IMeta) form.first()).meta() != null)
@@ -3117,6 +3129,7 @@ static Expr parse(C context, ISeq form, String name) throws Exception{
{
Var.pushThreadBindings(
RT.map(CONSTANTS, PersistentVector.EMPTY,
+ CONSTANT_IDS, new IdentityHashMap(),
KEYWORDS, PersistentHashMap.EMPTY,
VARS, PersistentHashMap.EMPTY,
KEYWORD_CALLSITES, PersistentVector.EMPTY,
@@ -3188,7 +3201,11 @@ else if(methodArray[f.reqParms.count()] == null)
fn.compile(fn.isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction",null,fn.onceOnly);
fn.getCompiledClass();
- return fn;
+ if(origForm instanceof IObj && ((IObj) origForm).meta() != null)
+ return new MetaExpr(fn, (MapExpr) MapExpr
+ .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) origForm).meta()));
+ else
+ return fn;
}
public final ObjMethod variadicMethod(){
@@ -3315,9 +3332,7 @@ static String trimGenID(String name){
Type[] ctorTypes(){
- if(closes.count() == 0)
- return ARG_TYPES[0];
- PersistentVector tv = PersistentVector.EMPTY;
+ IPersistentVector tv = isDeftype()?PersistentVector.EMPTY:RT.vector(IPERSISTENTMAP_TYPE);
for(ISeq s = RT.keys(closes); s != null; s = s.next())
{
LocalBinding lb = (LocalBinding) s.first();
@@ -3451,6 +3466,10 @@ void compile(String superName, String[] interfaceNames, boolean oneTimeUse) thro
clinitgen.returnValue();
clinitgen.endMethod();
+ if(!isDeftype())
+ {
+ cv.visitField(ACC_FINAL, "__meta", IPERSISTENTMAP_TYPE.getDescriptor(), null, null);
+ }
//instance fields for closed-overs
for(ISeq s = RT.keys(closes); s != null; s = s.next())
{
@@ -3510,7 +3529,14 @@ void compile(String superName, String[] interfaceNames, boolean oneTimeUse) thro
// }
// else
// ctorgen.invokeConstructor(aFnType, voidctor);
- int a = 1;
+ if(!isDeftype())
+ {
+ ctorgen.loadThis();
+ ctorgen.visitVarInsn(IPERSISTENTMAP_TYPE.getOpcode(Opcodes.ILOAD), 1);
+ ctorgen.putField(objtype, "__meta", IPERSISTENTMAP_TYPE);
+ }
+
+ int a = isDeftype()?1:2;
for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a)
{
LocalBinding lb = (LocalBinding) s.first();
@@ -3563,6 +3589,76 @@ void compile(String superName, String[] interfaceNames, boolean oneTimeUse) thro
ctorgen.endMethod();
}
+ if(!isDeftype())
+ {
+ //ctor that takes closed-overs but not meta
+ Type[] ctorTypes = ctorTypes();
+ Type[] noMetaCtorTypes = new Type[ctorTypes.length-1];
+ for(int i=1;i<ctorTypes.length;i++)
+ noMetaCtorTypes[i-1] = ctorTypes[i];
+ Method alt = new Method("<init>", Type.VOID_TYPE, noMetaCtorTypes);
+ ctorgen = new GeneratorAdapter(ACC_PUBLIC,
+ alt,
+ null,
+ null,
+ cv);
+ ctorgen.visitCode();
+ ctorgen.loadThis();
+ ctorgen.visitInsn(Opcodes.ACONST_NULL); //null meta
+ ctorgen.loadArgs();
+ ctorgen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes));
+
+ ctorgen.returnValue();
+ ctorgen.endMethod();
+
+ //meta()
+ Method meth = Method.getMethod("clojure.lang.IPersistentMap meta()");
+
+ GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC,
+ meth,
+ null,
+ null,
+ cv);
+ gen.visitCode();
+ gen.loadThis();
+ gen.getField(objtype,"__meta",IPERSISTENTMAP_TYPE);
+
+ gen.returnValue();
+ gen.endMethod();
+
+ //withMeta()
+ meth = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)");
+
+ gen = new GeneratorAdapter(ACC_PUBLIC,
+ meth,
+ null,
+ null,
+ cv);
+ gen.visitCode();
+ gen.newInstance(objtype);
+ gen.dup();
+ gen.loadArg(0);
+
+ for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a)
+ {
+ LocalBinding lb = (LocalBinding) s.first();
+ gen.loadThis();
+ Class primc = lb.getPrimitiveType();
+ if(primc != null)
+ {
+ gen.getField(objtype, lb.name, Type.getType(primc));
+ }
+ else
+ {
+ gen.getField(objtype, lb.name, OBJECT_TYPE);
+ }
+ }
+
+ gen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes));
+ gen.returnValue();
+ gen.endMethod();
+ }
+
emitMethods(cv);
if(keywordCallsites.count() > 0)
@@ -3888,6 +3984,7 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
{
gen.newInstance(objtype);
gen.dup();
+ gen.visitInsn(Opcodes.ACONST_NULL);
for(ISeq s = RT.seq(closesExprs); s != null; s = s.next())
{
LocalBindingExpr lbe = (LocalBindingExpr) s.first();
@@ -5280,7 +5377,12 @@ private static int registerConstant(Object o){
if(!CONSTANTS.isBound())
return -1;
PersistentVector v = (PersistentVector) CONSTANTS.deref();
+ IdentityHashMap<Object,Integer> ids = (IdentityHashMap<Object,Integer>) CONSTANT_IDS.deref();
+ Integer i = ids.get(o);
+ if(i != null)
+ return i;
CONSTANTS.set(RT.conj(v, o));
+ ids.put(o, v.count());
return v.count();
}
@@ -5757,6 +5859,7 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
LINE_BEFORE, pushbackReader.getLineNumber(),
LINE_AFTER, pushbackReader.getLineNumber(),
CONSTANTS, PersistentVector.EMPTY,
+ CONSTANT_IDS, new IdentityHashMap(),
KEYWORDS, PersistentHashMap.EMPTY,
VARS, PersistentHashMap.EMPTY
,LOADER, RT.makeClassLoader()
@@ -5970,6 +6073,7 @@ static ObjExpr build(IPersistentVector interfaceSyms, IPersistentVector fieldSym
{
Var.pushThreadBindings(
RT.map(CONSTANTS, PersistentVector.EMPTY,
+ CONSTANT_IDS, new IdentityHashMap(),
KEYWORDS, PersistentHashMap.EMPTY,
VARS, PersistentHashMap.EMPTY,
KEYWORD_CALLSITES, PersistentVector.EMPTY,
Oops, something went wrong.

0 comments on commit 430dd4f

Please sign in to comment.