def syntaxQuote(self, form): from py.clojure.lang.compiler import builtins as compilerbuiltins if form in compilerbuiltins: ret = RT.list(_QUOTE_, form) elif isinstance(form, Symbol): sym = form if sym.ns is None and sym.name.endswith("#"): gmap = GENSYM_ENV.deref() if gmap == None: raise ReaderException("Gensym literal not in syntax-quote, before", self.rdr) gs = gmap[sym] if gs is None: gs = symbol(None, sym.name[:-1] + "__" + str(RT.nextID()) + "__auto__") GENSYM_ENV.set(gmap.assoc(sym, gs)) sym = gs elif sym.ns is None and sym.name.endswith("."): ret = sym elif sym.ns is None and sym.name.startswith("."): ret = sym elif sym.ns is not None: ret = sym else: comp = currentCompiler.get(lambda: None) if comp is None: raise IllegalStateException("No Compiler found in syntax quote!") ns = comp.getNS() if ns is None: raise IllegalStateException("No ns in reader") sym = symbol(ns.__name__, sym.name) ret = RT.list(_QUOTE_, sym) else: if isUnquote(form): return form.next().first() elif isUnquoteSplicing(form): raise IllegalStateException("splice not in list") elif isinstance(form, IPersistentCollection): if isinstance(form, IPersistentMap): keyvals = flattenMap(form) ret = RT.list(_APPLY_, _HASHMAP_, RT.list(RT.cons(_CONCAT_, self.sqExpandList(keyvals.seq())))) elif isinstance(form, (IPersistentVector, IPersistentSet)): ret = RT.list(_APPLY_, _VECTOR_, RT.list(_SEQ_, RT.cons(_CONCAT_, self.sqExpandList(form.seq())))) elif isinstance(form, (ISeq, IPersistentList)): seq = form.seq() if seq is None: ret = RT.cons(_LIST_, None) else: ret = RT.list(_SEQ_, RT.cons(_CONCAT_, self.sqExpandList(seq))) else: raise IllegalStateException("Unknown collection type") elif isinstance(form, (int, float, str, Keyword)): ret = form else: ret = RT.list(_QUOTE_, form) if hasattr(form, "meta") and form.meta() is not None: newMeta = form.meta().without(LINE_KEY) if len(newMeta) > 0: return RT.list(_WITH_META_, ret, self.syntaxQuote(form.meta())) return ret
def find(sym): from py.clojure.lang.namespace import find as findNamespace if sym.ns is None: raise InvalidArgumentException("Symbol must be namespace-qualified") ns = findNamespace(symbol(sym.ns)) if ns is None: raise InvalidArgumentException("No such namespace " + str(sym.ns)) return ns.findInternedVar(symbol(sym.name))
def find(self, *args): if len(args) == 1: if isinstance(args[0], Symbol): return interned.val()[args[0]]() if isinstance(args[0], str): return Keyword.find(symbol(args[0])) if len(args) == 2: return Keyword.find(symbol(*args)) raise ArityException()
def compileFn(comp, name, form, orgform): locals, args, lastisargs, argsname = unpackArgs(form.first()) for x in locals: comp.pushAlias(x, FnArgument(x)) if orgform.meta() is not None: line = orgform.meta()[LINE_KEY] else: line = 0 code = [(SetLineno,line if line is not None else 0)] if lastisargs: code.extend(cleanRest(argsname.name)) recurlabel = Label("recurLabel") recur = {"label": recurlabel, "args": args} code.append((recurlabel, None)) comp.pushRecur(recur) code.extend(compileImplcitDo(comp, form.next())) comp.popRecur() code.append((RETURN_VALUE,None)) comp.popAliases(locals) clist = map(lambda x: x.sym.name, comp.closureList()) c = Code(code, clist, args, lastisargs, False, True, str(symbol(comp.getNS().__name__, name.name)), comp.filename, 0, None) if not clist: c = new.function(c.to_code(), comp.ns.__dict__, name.name) return [(LOAD_CONST, c)]
def compileMultiFn(comp, name, form): s = form argdefs = [] while s is not None: argdefs.append(MultiFn(comp, s.first())) s = s.next() argdefs = sorted(argdefs, lambda x, y: len(x.args) < len(y.args)) if len(filter(lambda x: x.lastisargs, argdefs)) > 1: raise CompilerException("Only one function overload may have variable number of arguments", form) code = [] if len(argdefs) == 1 and not argdefs[0].lastisargs: hasvararg = False argslist = argdefs[0].args code.extend(argdefs[0].bodycode) else: hasvararg = True argslist = ["__argsv__"] for x in argdefs: code.extend(x.argcode) code.extend(x.bodycode) code.append((LOAD_CONST, Exception)) code.append((CALL_FUNCTION, 0)) code.append((RAISE_VARARGS, 1)) clist = map(lambda x: x.sym.name, comp.closureList()) c = Code(code, clist, argslist, hasvararg, False, True, str(symbol(comp.getNS().__name__, name.name)), comp.filename, 0, None) if not clist: c = new.function(c.to_code(), comp.ns.__dict__, name.name) return [(LOAD_CONST, c)]
def compileDef(comp, form): if len(form) not in [2, 3]: raise CompilerException("Only 2 or 3 arguments allowed to def", form) sym = form.next().first() value = None if len(form) == 3: value = form.next().next().first() if sym.ns is None: ns = comp.getNS() else: ns = sym.ns comp.pushName(sym.name) code = [] code.extend(comp.compile(value)) code.append((DUP_TOP, 0)) code.append((STORE_GLOBAL, sym.name)) if sym.meta() is not None: code.extend(comp.compileAccessList(symbol("clojure.lang.rt.setMeta"))) code.append((ROT_TWO, 0)) code.append((LOAD_CONST, sym.meta())) code.append((CALL_FUNCTION, 2)) comp.popName() return code
def compileVector(comp, form): code = [] code.extend(comp.compile(symbol("clojure.lang.rt.vector"))) for x in form: code.extend(comp.compile(x)) code.append((CALL_FUNCTION, len(form))) return code
def executeCode(self, code): import sys if code == []: return None newcode = code[:] newcode.append((RETURN_VALUE, None)) c = Code(newcode, [], [], False, False, False, str(symbol(self.getNS().__name__, "<string>")), self.filename, 0, None) retval = eval(c.to_code(), self.getNS().__dict__) return retval
def keyword(*args): if len(args) == 1: if isinstance(args[0], Symbol): sym = args[0] if sym.meta() is not None: sym = sym.withMeta(None) k = Keyword(sym) interned.mutate(lambda old: old if sym in old else old.assoc(sym,k)) return interned.get()[sym] elif isinstance(args[0], str): return keyword(symbol(args[0])) else: raise InvalidArgumentException() elif len(args) == 2: return keyword(symbol(*args)) else: raise ArityException()
def compileMap(comp, form): s = form.seq() c = 0 code = [] code.extend(comp.compile(symbol("clojure.lang.rt.map"))) while s is not None: kvp = s.first() code.extend(comp.compile(kvp.getKey())) code.extend(comp.compile(kvp.getValue())) c += 2 s = s.next() code.append([CALL_FUNCTION, c]) return code
def executeModule(self, code): code.append((RETURN_VALUE, None)) c = Code(code, [], [], False, False, False, str(symbol(self.getNS().__name__, "<string>")), self.filename, 0, None) import marshal import pickle import py_compile import time import dis dis.dis(c) codeobject = c.to_code() with open('output.pyc', 'wb') as fc: fc.write(py_compile.MAGIC) py_compile.wr_long(fc, long(time.time())) marshal.dump(c, fc)
def compileLoopStar(comp, form): if len(form) < 3: raise CompilerException("loop* takes at least two args") form = form.next() if not isinstance(form.first(), PersistentVector): raise CompilerException("loop* takes a vector as it's first argument") s = form.first() args = [] code = [] idx = 0 while idx < len(s): if len(s) - idx < 2: raise CompilerException("loop* takes a even number of bindings") local = s[idx] if not isinstance(local, Symbol) or local.ns is not None: raise CompilerException("bindings must be non-namespaced symbols") idx += 1 body = s[idx] if local in comp.aliases: newlocal = symbol(str(local)+"_"+str(RT.nextID())) code.extend(comp.compile(body)) comp.pushAlias(local, RenamedLocal(newlocal)) args.append(local) else: comp.pushAlias(local, RenamedLocal(local)) args.append(local) code.extend(comp.compile(body)) code.extend(comp.getAlias(local).compileSet(comp)) idx += 1 form = form.next() recurlabel = Label("recurLabel") recur = {"label": recurlabel, "args": map(lambda x: x.name, args)} code.append((recurlabel, None)) comp.pushRecur(recur) code.extend(compileImplcitDo(comp, form)) comp.popRecur() comp.popAliases(args) return code
def matchSymbol(s): from py.clojure.lang.symbol import Symbol from py.clojure.lang.cljkeyword import Keyword m = symbolPat.match(s) if m is not None: ns = m.group(1) name = m.group(2) if ns is not None and ns.endswith(":/") or name.endswith(":")\ or s.find("::") != -1: return None if s.startswith("::"): return "FIX" ns = ns if ns is None else ns[:-1] iskeyword = s.find(':') == 0 sym = symbol(ns, name[(1 if iskeyword else 0):]) if iskeyword: return keyword(s) else: return sym return None
def compileRecur(comp, form): s = form.next() idx = 0 code = [] locals = [] while s is not None: code.extend(comp.compile(s.first())) if idx >= len(comp.recurPoint.first()["args"]): raise CompilerException("to many arguments to recur", form) local = comp.recurPoint.first()["args"][idx] local = comp.getAlias(symbol(local)) if local is None: pass locals.append(local) idx += 1 s = s.next() locals.reverse() for x in locals: code.extend(x.compileSet(comp)) code.append((JUMP_ABSOLUTE, comp.recurPoint.first()["label"])) return code
def main(): requireClj(os.path.dirname(__file__) + "/clj/clojure/core.clj") RT.init() comp = Compiler() currentCompiler.set(comp) comp.setNS(symbol("user")) if not sys.argv[1:]: while True: try: line = raw_input(comp.getNS().__name__ + "=> ") except EOFError: break if not line: continue while unbalanced(line): try: line += raw_input('.' * len(comp.getNS().__name__) + '.. ') except EOFError: break # Propogate break from above loop. if unbalanced(line): break r = StringReader(line) s = read(r, True, None, True) try: res = comp.compile(s) print comp.executeCode(res) except Exception: traceback.print_exc() else: for x in sys.argv[1:]: requireClj(x)
def compileLetStar(comp, form): if len(form) < 3: raise CompilerException("let* takes at least two args") form = form.next() if not isinstance(form.first(), PersistentVector): raise CompilerException("let* takes a vector as it's first argument") s = form.first() args = [] code = [] idx = 0 while idx < len(s): if len(s) - idx < 2: raise CompilerException("let* takes a even number of bindings") local = s[idx] if not isinstance(local, Symbol) or local.ns is not None: raise CompilerException("bindings must be non-namespaced symbols") idx += 1 body = s[idx] if comp.getAlias(local) is not None: code.extend(comp.compile(body)) newlocal = symbol(str(local)+"_"+str(RT.nextID())) comp.pushAlias(local, RenamedLocal(newlocal)) args.append(local) else: code.extend(comp.compile(body)) comp.pushAlias(local, RenamedLocal(local)) args.append(local) code.extend(comp.getAlias(local).compileSet(comp)) idx += 1 form = form.next() code.extend(compileImplcitDo(comp, form)) comp.popAliases(args) return code
from py.clojure.lang.ipersistentmap import IPersistentMap from py.clojure.lang.ipersistentlist import IPersistentList from py.clojure.lang.var import Var from py.clojure.util.byteplay import * import py.clojure.util.byteplay as byteplay from py.clojure.lang.cljkeyword import Keyword, keyword import new import py.clojure.lang.rt as RT from py.clojure.lang.lispreader import _AMP_ from py.clojure.lang.namespace import findItem from py.clojure.lang.lispreader import LINE_KEY, garg import re import new import sys _MACRO_ = keyword(symbol(":macro")) version = (sys.version_info[0] * 10) + sys.version_info[1] def emitJump(label): if version == 26: return [(JUMP_IF_FALSE, label), (POP_TOP, None)] else: return [(POP_JUMP_IF_FALSE, label)] def emitLanding(label): if version == 26: return [(label, None), (POP_TOP, None)] else: return [(label, None)]
def __init__(self, sym, rest = None): AAlias.__init__(self, rest) self.sym = sym self.newsym = symbol(sym.name + str(RT.nextID()))
def compileFNStar(comp, form): haslocalcaptures = False aliases = [] if len(comp.aliases) > 0: # we got a closure to deal with for x in comp.aliases: comp.pushAlias(x, Closure(x)) aliases.append(x) haslocalcaptures = True orgform = form if len(form) < 2: raise CompilerException("2 or more arguments to fn* required", form) form = form.next() name = form.first() pushed = False if not isinstance(name, Symbol): name = comp.getNamesString() else: comp.pushName(name.name) pushed = True form = form.next() name = symbol(name) gensym = symbol("_"+name.name + str(RT.nextID())) if haslocalcaptures: comp.pushAlias(name, LocalMacro(name, gensym)) if isinstance(form.first(), IPersistentVector): code = compileFn(comp, name, form, orgform) else: code = compileMultiFn(comp, name, form) if pushed: comp.popName() clist = comp.closureList() fcode = [] if haslocalcaptures: comp.popAlias(name) if haslocalcaptures: comp.popAliases(aliases) if clist: for x in clist: fcode.extend(comp.getAlias(x.sym).compile(comp)) # Load our local version fcode.append((STORE_DEREF, x.sym.name)) # Store it in a Closure Cell fcode.append((LOAD_CLOSURE, x.sym.name)) # Push the cell on the stack fcode.append((BUILD_TUPLE, len(clist))) fcode.extend(code) fcode.append((MAKE_CLOSURE, 0)) code = fcode if haslocalcaptures: code.append((DUP_TOP, None)) code.append((STORE_GLOBAL, gensym.name)) return code
from py.clojure.lang.iref import IRef from py.clojure.lang.ifn import IFn from py.clojure.lang.settable import Settable from py.clojure.lang.aref import ARef from py.clojure.lang.cljexceptions import (ArityException, InvalidArgumentException, IllegalStateException) from py.clojure.lang.persistenthashmap import EMPTY from py.clojure.lang.threadutil import ThreadLocal, currentThread from py.clojure.lang.symbol import symbol from py.clojure.lang.cljkeyword import keyword import persistentarraymap privateKey = keyword(symbol("private")) macrokey = keyword(symbol(":macro")) dvals = ThreadLocal() privateMeta = persistentarraymap.create([privateKey, True]) UKNOWN = symbol("UNKNOWN") def pushThreadBindings(bindings): f = dvals.get(lambda: Frame()) bmap = f.bindings bs = bindings.seq() while bs is not None: e = bs.first() v = e.getKey() if not v.dynamic: raise IllegalStateException("Can't dynamically bind non-dynamic " "var: " + str(v.ns) + "/" + str(v.sym))
def intern(ns, name): if isinstance(ns, Namespace): return ns.intern(name) ns = Namespace.findOrCreate(symbol(ns)) return intern(ns, name)
def internPrivate(nsName, sym): ns = Namespace.findOrCreate(symbol(nsName)) ret = intern(ns, symbol(sym)) ret.setMeta(Var.privateMeta) return ret
from py.clojure.lang.cljexceptions import ReaderException, IllegalStateException import py.clojure.lang.rt as RT from py.clojure.lang.cljkeyword import LINE_KEY from py.clojure.lang.symbol import Symbol, symbol from py.clojure.lang.persistentvector import EMPTY as EMPTY_VECTOR from py.clojure.lang.globals import currentCompiler from py.clojure.lang.cljkeyword import Keyword, keyword import re def read1(rdr): rdr.next() if rdr is None: return "" return rdr.first() _AMP_ = symbol("&") _FN_ = symbol("fn") _VAR_ = symbol("var") _APPLY_ = symbol("apply") _HASHMAP_ = symbol("clojure.core", "hashmap") _CONCAT_ = symbol("clojure.core", "concat") _LIST_ = symbol("clojure.core", "list") _SEQ_ = symbol("clojure.core", "seq") _VECTOR_ = symbol("clojure.core", "vector") _QUOTE_ = symbol("quote") _SYNTAX_QUOTE_ = symbol("`") _UNQUOTE_ = symbol("~") _UNQUOTE_SPLICING_ = symbol("~@") ARG_ENV = var(None).setDynamic() GENSYM_ENV = var(None).setDynamic()
def setUp(self): RT.init() self.comp = Compiler() currentCompiler.set(self.comp) self.comp.setNS(symbol("clojure.core"))
def garg(n): from symbol import Symbol return symbol(None, "rest" if n == -1 else ("p" + str(n)) + "__" + str(RT.nextID()) + "#")