diff options
Diffstat (limited to 'clojurescript/rt.js')
-rw-r--r-- | clojurescript/rt.js | 2053 |
1 files changed, 2053 insertions, 0 deletions
diff --git a/clojurescript/rt.js b/clojurescript/rt.js new file mode 100644 index 00000000..5eac7c36 --- /dev/null +++ b/clojurescript/rt.js @@ -0,0 +1,2053 @@ +// Copyright (c) Chris Houser, Sep 2008. All rights reserved. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/licenses/cpl.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. +// You must not remove this notice, or any other, from this software. + +// Runtime support for code generated by tojs.clj + +clojure = { + JS: { + global: this, + merge: function( t, s ) { + for( var i in s ) { + t[ i ] = s[ i ]; + } + return t; + }, + Class: { + classname: "clojure.JS.Class", + hashCode: function() { return clojure.lang.Util.hash( this.classname ); }, + isAssignableFrom: function(base) { return base.classset[this.classname];}, + getSuperclass: function() { return this.extend || null; }, + getInterfaces: function() { return this.implement || null; } + } + }, + lang: { + Namespace: function( n, m ) { + this.name = n; // FIXME: this pollutes the namespace + clojure.JS.merge( this, m || {} ); + } + } +}; + +clojure.JS.Class.constructor = clojure.JS.Class; +clojure.JS.Class.classset = { Class: true }; + +if( ! clojure.JS.global["java"] ) { + java = { lang: { String: {}, Character: {}, Class: {}, Number: {}, + Boolean: {} }, + math: { BigDecimal: {} }, + util: { Collection: {}, Map: {}, Set: {}, regex: { Pattern: {} } } }; +} + +clojure = { + JS: { + merge: clojure.JS.merge, + global: clojure.JS.global, + Class: clojure.JS.Class, + objectType: typeof {}, + functionType: typeof function(){}, + stringType: typeof "", + numberType: typeof 0, + variadic: function( arity, f ) { + f.arity = arity; + f.isVariadic = true; + return f; + }, + resolveVar: function( sym, ctxns ) { + return ctxns[ sym ] || clojure[ sym ] || clojure.JS.global[ sym ]; + }, + def: function( ns, name, init ) { + var v = new clojure.lang.Var( ns, name ); + ns["_var_" + name] = v; + v.push( init ); + return v; + }, + variadic_sentinel: {}, + rest_args: function( varflag, args, i ) { + if( varflag === clojure.JS.variadic_sentinel ) + return args[ args.length - 1 ]; + return new clojure.lang.ArraySeq( null, args, i ); + }, + invoke: function( obj, methodname, args ) { + return obj[ methodname ].apply( obj, args ); + }, + getOrRun: function( obj, prop ) { + var val = obj[ prop ]; + if( typeof val === clojure.JS.functionType + || (typeof val === clojure.JS.objectType && "apply" in val) ) + { + return val.apply( obj, [] ); + } + return val; + }, + lit_list: function( a ) { + if( a.length > 0 ) + return new clojure.lang.ArraySeq( null, a, 0 ); + return clojure.lang.PersistentList.EMPTY; + }, + lit_vector: function( a ) { + return clojure.lang.LazilyPersistentVector.createOwning( a ); + }, + implement: function( cls, name, extend, implement ) { + clojure.JS.merge( cls, clojure.JS.Class ); + cls.classname = name; + cls.extend = extend; + cls.implement = implement; + cls.classset = {}; + cls.classset[ name ] = true; + if( implement ) { + for( var i = 0; i < implement.length; ++i ) { + if( ! implement[ i ] ) + throw "Can't implement null: " + name; + clojure.JS.merge( cls.classset, implement[ i ].classset ); + } + } + }, + definterface: function( pkg, name, implement ) { + var cls = pkg[ name ] = {}; + clojure.JS.implement( cls, name, null, implement ); + return cls; + }, + defclass: function( pkg, name, opts ) { + var cls = pkg[ name ] = opts.init || function() {}; + clojure.JS.implement( cls, name, opts.extend, opts.implement ); + if( 'extend' in opts ) { + cls.prototype = new opts.extend; + cls.prototype.constructor = cls; + clojure.JS.merge( cls.classset, opts.extend.classset ); + } + if( opts.statics ) { clojure.JS.merge( cls, opts.statics ); } + if( opts.methods ) { clojure.JS.merge( cls.prototype, opts.methods ); } + return cls; + }, + instanceq: function( c, o ){ + if( o === null ) + return false; + if( typeof o === clojure.JS.functionType && ! ("constructor" in o) ) + return false; // a Java class? + if( o.constructor === c ) + return true; + if( ! o.constructor.classset ) + return false; // builtin class that doesn't match? + return o.constructor.classset[ c.classname ]; + }, + relayPrintMethod: function( jsclass, javaclass, ctor ) { + var m = clojure.core.print_method; + m.addMethod( jsclass, function(o,w) { + return (clojure.core.get( m.methodTable, javaclass ) + .apply(null, [ctor ? ctor(o) : o, w])); + }); + }, + bitcount: function(n){ + var rtn = 0; + for( ; n; n >>= 1) { + rtn += n & 1; + } + return rtn; + }, + ObjSeq: { + create: function( obj ) { + var i, pairs = []; + for( i in obj ) { + pairs.push( [i, obj[i]] ); + } + return clojure.lang.ArraySeq.create( pairs ); + } + } + }, + lang: { + Namespace: clojure.lang.Namespace, + Numbers: { + isZero: function(x) { return x === 0; }, + isPos: function(x) { return x > 0; }, + isNeg: function(x) { return x < 0; }, + minus: function(x,y) { return y === undefined ? -x : x - y; }, + inc: function(x) { return x + 1; }, + dec: function(x) { return x - 1; }, + add: function(x,y) { return x + y; }, + multiply: function(x,y) { return x * y; }, + divide: function(x,y) { return x / y; }, + quotient: function(x,y) { return parseInt(x / y); }, + remainder: function(x,y) { return x % y; }, + equiv: function(x,y) { return x == y; }, + lt: function(x,y) { return x < y; }, + lte: function(x,y) { return x <= y; }, + gt: function(x,y) { return x > y; }, + gte: function(x,y) { return x >= y; }, + compare: function(x,y) { return (x<y) ? -1 :( (y<x) ? 1 : 0 ); }, + unchecked_inc: function(x) { return x + 1; } + }, + Util: { + hash: function(o){ + switch( o ) { + case null: return 0; + case Array: return 0x7A837A71; + case Boolean: return 0x7A837A72; + case Function: return 0x7A837A73; + case Number: return 0x7A837A74; + case Object: return 0x7A837A75; + case RegExp: return 0x7A837A76; + case String: return 0x7A837A77; + case java.lang.Boolean: + case java.lang.Character: + case java.lang.Class: + case java.lang.Double: + case java.lang.Integer: + case java.lang.Number: + case java.lang.String: + case java.math.BigDecimal: + case java.util.Collection: + case java.util.Map: + case java.util.Set: + case java.util.regex.Pattern: + return 0x7A830001; + } + var i = 0, ret = o.length; + switch( typeof o ) { + case clojure.JS.stringType: + // lousy hand-made string hash + for( ; i < o.length; ++i ) { + ret ^= o.charCodeAt(i) << ((i % 4) * 8); + } + return ret; + case clojure.JS.numberType: + return o & 0xffffffff; + } + switch( o.constructor ) { + case Array: + for( ; i < o.length; ++i ) { + ret = clojure.lang.Util.hashCombine( + ret, clojure.lang.Util.hash( o[i] ) ); + } + return ret; + } + if( o.hashCode ) + return o.hashCode(); + return 0x11111111; + }, + hashCombine: function(seed, hash){ + return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + }, + equal: function(x,y) { return x == y; }, + isInteger: function(x) { return typeof x == clojure.JS.numberType; } + }, + RT: { + EMPTY_ARRAY: [], + conj: function( coll, x ) { + if( coll === null ) + return new clojure.lang.PersistentList( null, x ); + return coll.cons( x ); + }, + seqToArray: function(s) { + var i = 0, ret = new Array( clojure.count( s ) ); + for( ; s !== null; ++i, s = s.rest() ) + ret[ i ] = s.first(); + return ret; + }, + intCast: function(i) { + return parseInt(i); + }, + makeStringBuilder: function(s) { + return new clojure.JS.StringBuilder( s===undefined ? "" : s ); + }, + className: function(c) { + if( "classname" in c ) + return c.classname; + if( "name" in c ) + return c.name; + var s = "" + c, + m = /^\[JavaClass (.*)]$/.exec(s); + if( m ) + return m[1]; + return s; + }, + simpleClassName: function(c) { + // FIXME: should generate simple name + return clojure.lang.RT.className(c); + } + } + } +}; + +clojure.core = new clojure.lang.Namespace("clojure.core",{ + in_ns: function(s) { + var i, nsparts = s.getName().split('.'), + base = clojure.JS.global; + for( i = 0; i < nsparts.length; ++i ) { + if( ! base[nsparts[i]] ) { + base[nsparts[i]] = new clojure.lang.Namespace(nsparts[i]); + } + base = base[nsparts[i]]; + } + }, + refer: function(s) {}, + load: function(s) {}, + seq: function(coll){ + if( coll === null ) return null; + else if( coll.seq ) return coll.seq(); + //else if( coll.constructor === String ) + // return clojure.lang.StringSeq.create(coll); + else if( typeof coll.length == clojure.JS.numberType ) + return clojure.lang.ArraySeq.create(coll); + else if( typeof coll === clojure.JS.objectType ) + return clojure.JS.ObjSeq.create(coll); + throw ("Don't know how to create ISeq from: " + + (typeof coll) + " " + coll.constructor.name); + }, + apply: function( f ) { + var i, newargs = [], s, eagercount, + oldargs = arguments, arglen = oldargs.length; + if( f.isVariadic ) { + // lazy + eagercount = Math.min( f.arity, arglen - 2 ); + for( i = 0; i < eagercount; ++i ) { + newargs.push( oldargs[ i + 1 ] ); + } + if( eagercount == f.arity ) { + if( arglen - eagercount < 3 ) { + newargs.push( clojure.core.seq( oldargs[ arglen - 1 ] ) ); + } + else { + newargs.push( clojure.core.concat( + new clojure.lang.ArraySeq( + null, oldargs, eagercount + 1, arglen - 1 ), + oldargs[ arglen - 1 ] ) ); + } + } + else { + s = clojure.core.seq( oldargs[ arglen - 1 ] ); + for( ; s && newargs.length < f.arity; s = s.rest() ) { + newargs.push( s.first() ); + } + if( s ) + newargs.push( s ); + } + return f.apply( clojure.JS.variadic_sentinel, newargs ); + } + else { + // non-lazy + for( i = 1; i < arglen - 1; ++i ) { + newargs.push( oldargs[ i ] ); + } + for( s = oldargs[ arglen - 1]; s; s = s.rest()) { + newargs.push( s.first() ); + } + return f.apply( null, newargs ); + } + }, + first: function(x) { + if( x === null ) return null; + if( x.first ) return x.first(); + var seq = clojure.core.seq( x ); + if( seq === null ) return null; + return seq.first(); + }, + rest: function(x) { + if( x === null ) return null; + if( x.rest ) return x.rest(); + var seq = clojure.core.seq( x ); + if( seq === null ) return null; + return seq.rest(); + }, + second: function(x) { return clojure.first(clojure.rest(x)); }, + cons: function( x, coll ) { + var y = clojure.core.seq( coll ); + if( y === null ) + return new clojure.lang.PersistentList( null, x ); + return y.cons( x ); + }, + instance_QMARK_: function( c, o ) { + return clojure.JS.instanceq( c, o ); + }, + class_QMARK_: function(o) { return clojure.JS.instanceq(clojure.JS.Class,o);}, + number_QMARK_: function(o) { return clojure.JS.instanceq( Number, o ); }, + string_QMARK_: function(o) { return clojure.JS.instanceq( String, o ); }, + integer_QMARK_: function(o) { return parseInt( o ) === o; }, + find: function(coll, key) { + if( coll == null ) + return null; + else if( coll.containsKey ) { + if( coll.containsKey( key ) ) + return new clojure.lang.MapEntry( key, coll.get( key ) ); + return null; + } + return coll.entryAt( key ); + }, + get: function(coll, key, notFound ) { + var usenull = notFound === undefined; + if( coll === null ) + return usenull ? null : notFound; + if( coll.valAt ) + return coll.valAt( key, notFound ); + if( coll.containsKey ) + return (usenull || coll.containsKey( key )) ? coll.get( key ) : notFound; + if( coll.contains ) + return (usenull || coll.contains( key )) ? coll.get( key ) : notFound; + return (usenull || key in coll) ? coll[ key ] : notFound; + }, + nth: function(coll, n, notFound) { + var usenull = (notFound === undefined), seq, i; + if( coll === null ) + return usenull ? null : notFound; + if( coll.nth ) + return usenull || n < coll.count() ? coll.nth(n) : notFound; + if( coll.get ) + return usenull || n < coll.size() ? coll.get(n) : notFound; + if( coll.seq ) { + for( seq = coll.seq(), i = 0; i <= n && seq; seq = seq.rest() ) { + if( i == n ) + return seq.first(); + } + if( usenull ) + throw "IndexOutOfBoundsException"; + return notFound; + } + return usenull || n < coll.length ? coll[n] : notFound; + }, + contains_QMARK_: function(coll, key) { + if( coll === null ) + return false; + if( coll.containsKey ) + return coll.containsKey( key ) ? true : false; + if( coll.contains ) + return coll.contains( key ) ? true : false; + return key in coll; + }, + hash_map: function() { + return clojure.lang.PersistentHashMap.create( arguments ); + }, + hash_set: function() { + return clojure.lang.PersistentHashSet.create( arguments ); + }, + to_array: function(coll){ + if( coll === null ) + return clojure.lang.RT.EMPTY_ARRAY; + if( coll.toArray ) + return coll.toArray(); + if( typeof coll === clojure.JS.stringType ) { + var i = 0, rtn = new Array( coll.length ); + for( ; i < coll.length; ++i ) { + rtn[i] = coll[i]; + } + return rtn; + } + if( coll.constructor === Array ) { + return coll.slice(0); + } + throw "Unable to convert: " + coll.constructor.classname + " to Array"; + }, + keyword: function(a,b) { + if( b === undefined ) + return clojure.lang.Keyword.intern( null, a ); + return clojure.lang.Keyword.intern( a, b ); + }, + symbol: function(a,b) { + if( b === undefined ) + return clojure.lang.Symbol.intern( null, a ); + return clojure.lang.Symbol.intern( a, b ); + }, + assoc: function( coll, key, val ) { + if( coll === null ) + return new clojure.lang.PersistentArrayMap([key, val]); + return coll.assoc( key, val ); + }, + count: function(x) { + if( x === null ) return 0; + if( x.count ) return x.count(); + if( x.length != undefined ) return x.length; + throw ("count not supported on: " + (typeof x) + " " + x.constructor); + }, + class_: function(o) { + if( o === null || o === undefined ) + return null; + if( typeof o === clojure.JS.functionType && ! ("constructor" in o) ) + return java.lang.Class; + return o.constructor || typeof o; + }, + import_: function() { + // do nothing + }, + identical_QMARK_: function( a, b ) { + return a === b; + }, + keys: function(coll) { + return clojure.lang.APersistentMap.KeySeq.create(clojure.core.seq(coll)); + }, + vals: function(coll) { + return clojure.lang.APersistentMap.ValSeq.create(clojure.core.seq(coll)); + } +}); + +clojure.JS.definterface( clojure.JS, "Collection" ); + +clojure.JS.defclass( clojure.JS, "StringBuilder", { + init: function( x ) { this.a = [ x ]; }, + methods: { + append: function( x ) { this.a.push( x ); return this; }, + toString: function() { return this.a.join(''); } + } +}); + +clojure.JS.defclass( clojure.JS, "String", { + init: function(s) { + this.s = s; + this.length = s.length; + }, + methods: { + charAt: function(x) { return this.s.charAt(x); }, + toString: function() { return this.s; } + } +}); + +clojure.JS.definterface( clojure.lang, "IObj" ); + +clojure.JS.defclass( clojure.lang, "Obj", { + implement: [ clojure.lang.IObj ], + init: function(_meta) { this._meta = _meta; }, + methods: { + meta: function() { return this._meta; } + } +}); + +clojure.JS.definterface( clojure.lang, "IReduce" ); + +clojure.JS.definterface( clojure.lang, "IPersistentCollection" ); + +clojure.JS.definterface( clojure.lang, "ISeq", + [clojure.lang.IPersistentCollection] ); + +clojure.JS.definterface( clojure.lang, "IndexedSeq", + [clojure.lang.ISeq] ); + +clojure.JS.defclass( clojure.lang, "ASeq", { + implement: [clojure.lang.ISeq], + methods: { + equals: function( obj ) { + var s = this.seq(), ms = obj.seq(); + for( ; s !== null; s = s.rest(), ms = ms.rest() ) { + if( ms === null || !clojure.lang.Util.equal( s.first(), ms.first() )) + return false; + } + if( ms !== null ) + return false; + return true; + }, + hashCode: function() { throw "not yet implemented"; }, + count: function() { + var i = 1, s = this.rest(); + for( ; s; s = s.rest() ) + i += 1; + return i; + }, + seq: function(){ return this; }, + cons: function(o){ return new clojure.lang.Cons( null, o, this ); }, + toArray: function(){ return clojure.lang.RT.seqToArray( this.seq() ); }, + containsAll: function(c){ throw "not yet implemented"; }, + size: function(){ return this.count(); }, + isEmpty: function(){ return this.count() == 0; }, + contains: function(c){ throw "not yet implemented"; } + } +}); + +clojure.JS.defclass( clojure.lang, "Cons", { + extend: clojure.lang.ASeq, + init: function( _meta, _first, _rest ) { + this._meta = _meta; + this._first = _first; + this._rest = _rest; + }, + methods: { + first: function(){ return this._first; }, + rest: function(){ return this._rest; }, + count: function(){ return 1 + clojure.count( this._rest ); }, + seq: function(){ return this; }, + withMeta: function(_meta){ + return new clojure.lang.Cons( _meta, this._first, this._rest ); + } + } +}); + +clojure.JS.defclass( clojure.lang, "ArraySeq", { + extend: clojure.lang.ASeq, + implement: [clojure.lang.IndexedSeq, clojure.lang.IReduce], + init: function( _meta, a, i, len ) { + this._meta = _meta; + this.a = a; + this.i = i; + this.len = (len === undefined) ? a.length : len; + }, + statics: { + create: function( a ) { + if( a && a.length ) + return new clojure.lang.ArraySeq( null, a, 0 ); + return null; + } + }, + methods: { + first: function() { return this.a[this.i]; }, + rest: function() { + if( this.i + 1 < this.len ) + return new clojure.lang.ArraySeq( + this._meta, this.a, this.i + 1, this.len); + return null; + }, + count: function() { return this.len - this.i; }, + index: function() { return this.i; }, + withMeta: function( _meta ) { + return new clojure.lang.ArraySeq( _meta, this.array, this.i, this.len ); + }, + reduce: function( fn, start ) { + var ret = (start===undefined) ? this.a[this.i] : fn(start,this.a[this.i]), + x = this.i + 1; + for( ; x < this.len; ++x ) { + ret = fn( ret, this.a[x] ); + } + return ret; + }, + seq: function() { return this; } + } +}); + + +clojure.JS.defclass( clojure.lang, "LazyCons", { + extend: clojure.lang.ASeq, + init: function(f,_first,_rest) { + this.f = f; + this._first = _first === undefined ? clojure.lang.LazyCons.sentinel :_first; + this._rest = _rest === undefined ? clojure.lang.LazyCons.sentinel :_rest; + }, + statics: { + sentinel: {} + }, + methods: { + first: function() { + if( this._first === clojure.lang.LazyCons.sentinel ) + this._first = this.f(); + return this._first; + }, + rest: function() { + if( this._rest === clojure.lang.LazyCons.sentinel ) { + if( this._first === clojure.lang.LazyCons.sentinel ) { + this.first(); + } + this._rest = clojure.core.seq( this.f(null) ); + this.f = null; + } + return this._rest; + }, + withMeta: function(_meta) { + if( _meta == this.meta() ) + return this; + //force before copying + this.rest(); + return new clojure.lang.LazyCons( _meta, this._first, this._rest ); + }, + seq: function() { return this; } + } +}); + + +clojure.JS.defclass( clojure.lang, "Var", { + init: function( ns, name ) { + this.ns = ns; + this.name = name; + this.stack = []; + }, + statics: { + stack: [], + pushThreadBindings: function( m ) { + var vars=[], bs = m.seq(), e; + for( ; bs; bs = bs.rest()) { + e = bs.first(); + vars.push( e.key() ); + e.key().push( e.val() ); + } + clojure.lang.Var.stack.push( vars ); + }, + popThreadBindings: function() { + var i = 0, vars = clojure.lang.Var.stack.pop(); + for( ; i < vars.length; ++i ) { + vars[i].pop(); + } + } + }, + methods: { + push: function( val ) { + this.stack.push( val ); + this.ns[ this.name ] = val; + }, + pop: function() { + this.stack.pop(); + this.ns[ this.name ] = this.stack[ this.stack.length - 1 ]; + }, + set: function( val ) { + this.stack.pop(); + this.push( val ); + }, + get: function() { + return this.ns[ this.name ]; + }, + hasRoot: function() { return this.stack.length > 0; }, + toString: function() { + if( this.ns !== null ) + return "#=(var " + this.ns.name + "/" + this.name + ")"; + return "#<Var: " + (this.name !== null ? this.name : "--unnamed--") + ">"; + }, + hashCode: function() { + return clojure.lang.Util.hash( this.ns + "/" + this.name ); + } + } +}); + +clojure.JS.definterface( clojure.lang, "IFn" ); + +clojure.JS.defclass( clojure.lang, "AFn", { + extend: clojure.lang.Obj, + implement: [clojure.lang.IFn], + methods: { + apply: function( obj, args ){ + return this.invoke.apply( this, args ); + } + } +}); + +clojure.JS.definterface( clojure.lang, "IPersistentStack", + [clojure.lang.IPersistentCollection] ); + +clojure.JS.definterface( clojure.lang, "Sequential" ); + +clojure.JS.definterface( clojure.lang, "Reversible" ); + +clojure.JS.definterface( clojure.lang, "Named" ); + +clojure.JS.defclass( clojure.lang, "Keyword", { + extend: clojure.lang.AFn, + implement: [clojure.lang.Named], + init: function( ns, name ) { + this._ns = ns; + this._name = name; + }, + statics: { + table: {}, + intern: function( ns, name ) { + var key = (ns || "") + "/" + name, + obj = clojure.lang.Keyword.table[ key ]; + if( obj ) + return obj; + return clojure.lang.Keyword.table[ key ] = + new clojure.lang.Keyword( ns, name ); + } + }, + methods: { + toString: function() { + return ":" + (this.ns ? this.ns+"/" : "") + this._name; + }, + compareTo: function(o) { + if( this == o ) + return 0; + if( this._ns === null && o._ns !== null ) + return -1; + if( this._ns !== null ) { + if( o._ns === null ) + return 1; + var nsc = clojure.JS.compare(this._ns, o._ns); + if( nsc !== 0 ) + return nsc; + } + return clojure.JS.compare(this._name, o._name); + }, + getNamespace: function() { return this._ns; }, + getName: function() { return this._name; }, + hashCode: function() { + return clojure.lang.Util.hash( this._ns + "/" + this._name ); + }, + invoke: function(coll, notFound) { return clojure.core.get( coll,this,notFound);} + } +}); + +clojure.JS.defclass( clojure.lang, "Ratio", {} ); + +clojure.JS.defclass( clojure.lang, "Symbol", { + extend: clojure.lang.AFn, + implement: [clojure.lang.Named], + init: function( ns, name ) { + this._ns = ns; + this._name = name; + }, + statics: { + table: {}, + intern: function( ns, name ) { + var key = (ns || "") + "/" + name, + obj = clojure.lang.Symbol.table[ key ]; + if( obj ) + return obj; + return clojure.lang.Symbol.table[ key ] = + new clojure.lang.Symbol( ns, name ); + } + }, + methods: { + toString: function() { + return (this.ns ? this.ns+"/" : "") + this._name; + }, + compareTo: function(o) { + if( this == o ) + return 0; + if( this._ns === null && o._ns !== null ) + return -1; + if( this._ns !== null ) { + if( o._ns === null ) + return 1; + var nsc = clojure.JS.compare(this._ns, o._ns); + if( nsc !== 0 ) + return nsc; + } + return clojure.JS.compare(this._name, o._name); + }, + getNamespace: function() { return this._ns; }, + getName: function() { return this._name; }, + hashCode: function() { + return clojure.lang.Util.hash( this._ns + "/" + this._name ); + }, + invoke: function(coll, notFound) { + return clojure.core.get( coll,this,notFound); + } + } +}); + + +clojure.JS.definterface( clojure.lang, "IPersistentList", + [clojure.lang.Sequential, clojure.lang.IPersistentStack] ); + +clojure.JS.defclass( clojure.lang, "EmptyList", { + extend: clojure.lang.Obj, + implement: [clojure.lang.IPersistentList, clojure.JS.Collection], + init: function( _meta ) { this._meta = _meta; }, + methods: { + cons: function(o) { + return new clojure.lang.PersistentList( this.meta(), o ); + }, + empty: function() { return this; }, + withMeta: function(m) { + if( m != this.meta() ) + return new clojure.lang.EmptyList( m ); + return this; + }, + peek: function() { return null; }, + pop: function() { throw "Can't pop empty list"; }, + count: function() { return 0; }, + seq: function() { return null; }, + size: function() { return 0; }, + isEmpty: function() { return true; }, + contains: function() { return false; }, + toArray: function() { return clojure.lang.RT.EMPTY_ARRAY; }, + containsAll: function( coll ) { return coll.isEmpty(); } + } +}); + +clojure.JS.definterface( clojure.lang, "IMapEntry" ); + +clojure.JS.definterface( clojure.lang, "Associative", + [ clojure.lang.IPersistentCollection ] ); + +clojure.JS.definterface( clojure.lang, "IPersistentVector", + [ clojure.lang.Associative, clojure.lang.Sequential, + clojure.lang.IPersistentStack, clojure.lang.Reversible ]); + +clojure.JS.defclass( clojure.lang, "AMapEntry", { + implement: [ clojure.lang.IMapEntry, clojure.lang.IPersistentVector ], + methods: { + empty: function(){ return null; }, + equals: function(o){ + return clojure.lang.APersistentVector.doEquals(this,o); + }, + hashCode: function(){ throw "not implemented yet"; }, + toString: function(){ + return this.key() + " " + this.val(); + var sw = new clojure.JS.StringWriter(); + clojure.lang.RT.print( this, sw ); + return sw.toString(); + }, + length: function(){ return 2; }, + nth: function(i){ + switch(i){ + case 0: return this.key(); + case 1: return this.val(); + default: throw "Index out of bounds"; + } + }, + asVector: function(){ + return clojure.lang.LazilyPersistentVector.createOwning( + this.key(), this.val() ); + }, + assocN: function(i,v){ return this.asVector().assocN(i,v); }, + count: function(){ return 2; }, + seq: function(){ return this.asVector().seq(); }, + cons: function(o){ return this.asVector().cons(o); }, + containsKey: function(k){ return this.asVector().containsKey(k); }, + entryAt: function(k){ return this.asVector().entryAt(k); }, + assoc: function(k,v){ return this.asVector().assoc(k,v); }, + valAt: function(k,notFound){ return this.asVector().valAt(k,notFound); }, + peek: function(){ return this.val(); }, + pop: function(){ + return clojure.lang.LazilyPersistentVector.createOwning( this.key() ); + }, + rseq: function(){ return this.asVector().rseq(); } + } +}); + +clojure.JS.defclass( clojure.lang, "MapEntry", { + extend: clojure.lang.AMapEntry, + init: function(k,v){ + this._key = k; + this._val = v; + }, + methods: { + key: function(){ return this._key; }, + val: function(){ return this._val; }, + getKey: function(){ return this._key; }, + getValue: function(){ return this._val; } + } +}); + +clojure.JS.defclass( clojure.lang, "PersistentList", { + extend: clojure.lang.ASeq, + implement: [clojure.lang.IPersistentList, clojure.lang.IReduce], + init: function( _meta, _first, _rest, _count ) { + this._meta = _meta || null; + this._first = _first; + this._rest = _rest || null; + this._count = _count || 1; + }, + statics: { + creator: clojure.JS.variadic(0,function(){ + var args = clojure.JS.rest_args(this,arguments,0), + ret, i; + if( clojure.JS.instanceq( clojure.lang.ArraySeq, args ) ) { + ret = clojure.lang.PersistentList.EMPTY; + for( i = args.a.length - 1; i >= 0; --i ) { + ret = ret.cons( args.a[ i ] ); + } + return ret; + } + throw "Not yet implemented: clojure.lang.PersistentList.creator with non-ArraySeq"; + }), + EMPTY: new clojure.lang.EmptyList(null) + }, + methods: { + first: function(){ return this._first; }, + rest: function(){ + if( this._count == 1 ) + return null; + return this._rest; + }, + peek: function(){ return this.first; }, + pop: function(){ + if( this._rest === null ) + return this.empty(); + return this._rest; + }, + count: function(){ return this._count; }, + cons: function(o){ + return new clojure.lang.PersistentList( + this._meta, o, this, this._count + 1 ); + }, + empty: function(){ + return clojure.lang.PersistentList.EMPTY.withMeta( this._meta ); + }, + withMeta: function( _meta ){ + if( _meta != this._meta ) + return new clojure.lang.PersistentList( + this._meta, this._first, this._rest, this._count ); + return this; + }, + reduce: function( f, start ){ + var ret = (start === undefined) ? this.first() : f( start, this.first() ), + s = this.rest(); + for( ; s !== null; s = s.rest() ) + ret = f( ret, s.first() ); + return ret; + } + } +}); + +clojure.JS.defclass( clojure.lang, "APersistentVector", { + extend: clojure.lang.AFn, + implement: [clojure.lang.IPersistentVector], + init: function( _meta ) { this._meta = _meta; }, + methods: { + meta: function() { return this._meta; }, + peek: function() { + if( this.count() > 0 ) + return this.nth( this.count() - 1 ); + return null; + }, + seq: function() { + if( this.count() > 0 ) + return new clojure.lang.APersistentVector.Seq( null, this, 0 ); + return null; + }, + rseq: function() { + if( this.count() > 0 ) + return new clojure.lang.APersistentVector.RSeq( null, this, this.count() - 1); + return null; + }, + equals: function() { throw "not implemented yet"; }, + hashCode: function() { throw "not implemented yet"; }, + get: function(i) { return this.nth(i); }, + indexOf: function( o ){ + var i = 0, len = this.count(); + for( ; i < len; ++i ) + if( clojure.lang.Util.equal( this.nth( i ), o ) ) + return i; + return -1; + }, + lastIndexOf: function( o ){ + for( var i = this.count() - 1; i >= 0; --i ) + if( clojure.lang.Util.equal( this.nth( i ), o ) ) + return i; + return -1; + }, + subList: function( fromi, toi ) { + return clojure.lang.RT.subvec( this, fromi, toi ); + }, + invoke: function( i ) { + if( clojure.lang.Util.isInteger(i) ) + return this.nth( parseInt( i ) ); + throw "Key must be integer"; + }, + peek: function() { + if( this.count() > 0 ) + return this.nth( this.count() - 1 ); + return null + }, + constainsKey: function(k){ + if( ! clojure.lang.Util.isInteger( k ) ) + return false; + var i = parseInt(k); + return i >= 0 && i < this.count(); + }, + entryAt: function(k){ + if( clojure.lang.Util.isInteger( k ) ) { + var i = parseInt(k); + if( i >= 0 && i < this.count() ) + return new clojure.lang.MapEntry( k, this.nth(i) ); + } + return null; + }, + assoc: function(k,v){ + if( clojure.lang.Util.isInteger( k ) ) { + var i = parseInt(k); + return this.assocN(i,v); + } + throw "Key must be integer"; + }, + valAt: function(k, notFound){ + if( clojure.lang.Util.isInteger( k ) ) { + var i = parseInt(k); + if( i >= 0 && i < this.count() ) + return this.nth(i); + } + if( notFound === undefined ) + return null; + return notFound; + }, + toArray: function(){ return clojure.lang.RT.seqToArray( this.seq() ); }, + containsAll: function(){ throw "not implemented yet"; }, + size: function(){ return this.count(); }, + isEmpty: function(){ return this.count() === 0; }, + contains: function(o){ + for( var s = this.seq(); s !== null; s = s.rest() ) { + if( clojure.lang.Util.equal( s.first(), o ) ) + return true; + } + return false; + }, + length: function(){ return this.count(); }, + compareTo: function(v){ + var i, c, len = this.count(); + if( len < v.count() ) + return -1; + else if( len > v.count() ) + return 1; + for( i = 0; i < len; ++i ) { + c = this.nth(i).compareTo( v.nth(i) ); + if( c != 0 ) + return c; + } + return 0; + } + } +}); + +clojure.JS.defclass( clojure.lang.APersistentVector, "Seq", { + extend: clojure.lang.ASeq, + implement: [clojure.lang.IndexedSeq, clojure.lang.IReduce], + init: function( _meta, v, i){ + this._meta = _meta; + this.v = v; + this.i = i; + }, + methods: { + seq: function(){ return this; }, + first: function(){ return this.v.nth(this.i); }, + rest: function(){ + if( this.i + 1 < this.v.count() ) + return new clojure.lang.APersistentVector.Seq( + this._meta, this.v, this |