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 matchSymbol(s): """Return a symbol or keyword. Return None if the string s does not define a legal symbol or keyword.""" m = symbolPat.match(s) if m is not None: ns = m.group(1) name = m.group(2) if name.endswith(".") and not name.startswith("."): name = name[:-1] if ns is not None and (ns.endswith(":/") or name.endswith(":")\ or s.find("::") != -1): return None ns = ns if ns is None else ns[:-1] if s.startswith("::"): return Keyword(currentNSName(), s[2:]) iskeyword = s.startswith(':') if iskeyword: return Keyword(s[1:]) else: return Symbol(ns, name) return None
def compileLetStar(comp, form): if len(form) < 2: raise CompilerException("let* takes at least two args", form) form = form.next() if not isinstance(form.first(), IPersistentVector): raise CompilerException("let* takes a vector as it's first argument", form) bindings = RT.seq(form.first()) args = [] code = [] if bindings and len(bindings) % 2: raise CompilerException("let* takes a even number of bindings", form) while bindings: local, bindings = bindings.first(), bindings.next() body, bindings = bindings.first(), bindings.next() if not isinstance(local, Symbol) or local.ns is not None: raise CompilerException("bindings must be non-namespaced symbols", form) code.extend(comp.compile(body)) alias = RenamedLocal( Symbol("{0}_{1}".format(local, RT.nextID())) if comp. getAlias(local) else local) comp.pushAlias(local, alias) args.append(local) code.extend(alias.compileSet(comp)) form = form.next() code.extend(compileImplcitDo(comp, form)) comp.popAliases(args) return code
def findNS(name, fromns=None): """Finds a namespace, possibly as an defined as an alias in another one. """ symbol_name = Symbol(name) if symbol_name in getattr(fromns, "__aliases__", {}): return fromns.__aliases__[symbol_name] return sys.modules.get(str(name))
def compileDot(comp, form): if len(form) != 3: raise CompilerException(". form must have two arguments", form) clss = form.next().first() member = form.next().next().first() if isinstance(member, Symbol): attr = member.name args = [] elif isinstance(member, ISeq): if not isinstance(member.first(), Symbol): raise CompilerException("Member name must be symbol", form) attr = member.first().name args = [] if len(member) > 1: f = member.next() while f is not None: args.append(comp.compile(f.first())) f = f.next() alias = comp.getAlias(clss) if alias: code = alias.compile(comp) code.append((LOAD_ATTR, attr)) else: code = comp.compile(Symbol(clss, attr)) for x in args: code.extend(x) code.append((CALL_FUNCTION, len(args))) return code
def __init__(self, comp, form): form = RT.seq(form) if len(form) < 1: raise CompilerException("FN defs must have at least one arg", form) argv = form.first() if not isinstance(argv, PersistentVector): raise CompilerException("FN arg list must be a vector", form) body = form.next() self.locals, self.args, self.lastisargs, self.argsname = unpackArgs( argv) endLabel = Label("endLabel") argcode = [(LOAD_CONST, len), (LOAD_FAST, '__argsv__'), (CALL_FUNCTION, 1), (LOAD_CONST, len(self.args) - (1 if self.lastisargs else 0)), (COMPARE_OP, ">=" if self.lastisargs else "==")] argcode.extend(emitJump(endLabel)) for x in range(len(self.args)): if self.lastisargs and x == len(self.args) - 1: offset = len(self.args) - 1 argcode.extend([(LOAD_FAST, '__argsv__'), (LOAD_CONST, offset), (SLICE_1, None), (STORE_FAST, self.argsname.name)]) argcode.extend(cleanRest(self.argsname.name)) else: argcode.extend([(LOAD_FAST, '__argsv__'), (LOAD_CONST, x), (BINARY_SUBSCR, None), (STORE_FAST, self.args[x])]) for x in self.locals: comp.pushAlias(x, FnArgument(x)) recurlabel = Label("recurLabel") recur = { "label": recurlabel, "args": map(lambda x: comp.getAlias(Symbol(x)).compileSet(comp), self.args) } bodycode = [(recurlabel, None)] comp.pushRecur(recur) bodycode.extend(compileImplcitDo(comp, body)) bodycode.append((RETURN_VALUE, None)) bodycode.extend(emitLanding(endLabel)) comp.popRecur() comp.popAliases(self.locals) self.argcode = argcode self.bodycode = bodycode
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) 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 read_number(self, reader): chars = [] while self.is_number(reader.current()) or \ reader.current() == '.' or \ reader.current() == '-': chars.append(reader.current()) reader.next() str = "".join(chars) if str == "-": return Symbol.from_string(str) if '.' in str: return FloatObj(float(str)) return IntObj(int(str))
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 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": map(lambda x: comp.getAlias(Symbol(x)).compileSet(comp), 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: RT.name(x.sym), comp.closureList()) code = expandMetas(code, comp) c = Code(code, clist, args, lastisargs, False, True, str(Symbol(comp.getNS().__name__, name.name)), comp.filename, 0, None) if not clist: c = types.FunctionType(c.to_code(), comp.ns.__dict__, name.name) return [(LOAD_CONST, c)], c
def getAccessCode(self, sym): if sym.ns is None or sym.ns == self.getNS().__name__: if self.getNS() is None: raise CompilerException("no namespace has been defined", None) if not hasattr(self.getNS(), RT.name(sym)): raise CompilerException( "could not resolve '{0}', '{1}' not found in {2} reference {3}" .format(sym, RT.name(sym), self.getNS().__name__, self.getNamesString(False)), None) var = getattr(self.getNS(), RT.name(sym)) return [GlobalPtr(self.getNS(), RT.name(sym))] if Symbol(sym.ns) in getattr(self.getNS(), "__aliases__", {}): sym = Symbol(self.getNS().__aliases__[Symbol(sym.ns)].__name__, RT.name(sym)) splt = [] if sym.ns is not None: module = findNS(sym.ns) if not hasattr(module, RT.name(sym)): raise CompilerException( "{0} does not define {1}".format(module, RT.name(sym)), None) return [GlobalPtr(module, RT.name(sym))] code = LOAD_ATTR if sym.ns else LOAD_GLOBAL #if not sym.ns and RT.name(sym).find(".") != -1 and RT.name(sym) != "..": raise CompilerException( "unqualified dotted forms not supported: {0}".format(sym), sym) if len(RT.name(sym).replace(".", "")): splt.extend((code, attr) for attr in RT.name(sym).split(".")) else: splt.append((code, RT.name(sym))) return splt
def __new__(cls, *args): """Keyword constructor. Argument(s) will be passed to Symbol() first. If the keyword was already interned, it will be returned. """ sym = Symbol(*args).withMeta(None) if sym in Keyword.interned.get(): return Keyword.interned.get()[sym] obj = super(Keyword, cls).__new__(cls) Keyword.interned.mutate( lambda old: old if sym in old else old.assoc(sym, obj)) obj.sym = sym obj.hash = hash(sym) + 0x9e3779b9 return obj
def intern(ns, sym): """Interns a non-ns-qualified Symbol in a namespace. """ sym = Symbol(sym) if sym.ns is not None: raise InvalidArgumentException( "Can't intern namespace-qualified symbol") if not isinstance(ns, ModuleType): raise InvalidArgumentException v = getattr(ns, str(sym), None) if v is not None: if not isinstance(v, Var): raise Exception("Can't redefine {0} as {1}: is not Var".format( v, sym)) if ns.__name__ == v.ns.__name__: return v v = Var(ns, sym) setattr(ns, sym.name, v) return v
def read_term(self, reader): if not reader.has_more(): return None while reader.current() in _whitespace: reader.next() if not reader.has_more(): return None cur = reader.current() if cur == '"': return self.read_string(reader, '"') if self.is_number(cur) or cur == '-': return self.read_number(reader) if cur == '(': return self.read_list('(', reader, ')') if cur == ')': return StrObj(cur) chrs = [] while (not reader.current() in _whitespace) \ and (reader.current() != ')') \ and (reader.current() != '(') \ and reader.has_more(): chrs.append(reader.current()) reader.next() sym = "".join(chrs) #if sym.strip(_whitespace) == "": # return None return Symbol.intern(StrObj(sym))
def executeCode(self, code, ns=None): ns = ns or self.getNS() if code == []: return None newcode = expandMetas(code, self) newcode.append((RETURN_VALUE, None)) c = Code(newcode, [], [], False, False, False, str(Symbol(ns.__name__, "<string>")), self.filename, 0, None) try: c = c.to_code() except: for x in newcode: print x raise # work on .cljs #from clojure.util.freeze import write, read #with open("foo.cljs", "wb") as fl: # f = write(c, fl) with threadBindings({self._NS_: ns}): retval = eval(c, ns.__dict__) return retval
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: RT.name(x.sym), comp.closureList()) code = expandMetas(code, comp) c = Code(code, clist, argslist, hasvararg, False, True, str(Symbol(comp.getNS().__name__, name.name)), comp.filename, 0, None) if not clist: c = types.FunctionType(c.to_code(), comp.ns.__dict__, name.name) return [(LOAD_CONST, c)], c
def find(*args): if len(args) == 1 and isinstance(args[0], Symbol): return Keyword.interned.val()[args[0]]() if len(args) == 2: return find(Symbol(*args))
from clojure.lang.var import Var from clojure.lang.symbol import Symbol from clojure.lang.primitives import Obj, IntObj from clojure.lang.afn import AFn class Add(AFn): def __init__(self): pass def evaluate(self): return self def invoke2(self, arg0, arg1): return IntObj(arg0.int_value() + arg1.int_value()) add = Var(Symbol.from_string("+"), Add()) class Sub(AFn): def __init__(self): pass def evaluate(self): return self def invoke2(self, arg0, arg1): return IntObj(arg0.int_value() - arg1.int_value()) sub = Var(Symbol.from_string("-"), Sub()) class Equals(AFn): def __init__(self): pass def evaluate(self): return self
def run_repl(opts, comp=None): """Initializes and runs the REPL. Assumes that RT.init has been called. Repeatedly reads well-formed forms from stdin (with an interactive prompt if a tty) and evaluates them (and prints the result if a tty). Exits on EOF. """ if not opts.quiet and os.isatty(0): print VERSION_MSG if comp is None: curr = currentCompiler.get(lambda: None) if curr == None: comp = Compiler() currentCompiler.set(comp) else: comp = curr comp.setNS(Symbol("user")) core = sys.modules["clojure.core"] for i in dir(core): if not i.startswith("_"): setattr(comp.getNS(), i, getattr(core, i)) line = opts.cmd last3 = [None, None, None] def firstLinePrompt(): return comp.getNS().__name__ + "=> " if os.isatty(0) else "" def continuationLinePrompt(): return "." * len(comp.getNS().__name__) + ".. " if os.isatty(0) else "" while True: # Evaluating before prompting caters for initially given forms. r = StringReader(line) while True: try: s = read(r, False, None, True) if s is None: break res = comp.compile(s) out = comp.executeCode(res) except Exception: traceback.print_exc() else: if os.isatty(0): RT.printTo(out) last3.pop() last3.insert(0, out) for i, value in enumerate(last3, 1): v = findItem(Namespace("clojure.core"), Symbol("*{0}".format(i))) if isinstance(value, Var): v.bindRoot(value.deref()) v.setMeta(value.meta()) else: v.bindRoot(value) try: line = raw_input(firstLinePrompt()) while unbalanced(line): line += "\n" + raw_input(continuationLinePrompt()) except BracketsException as exc: print exc continue except EOFError: print break
def main(): """Main entry point to clojure-py. """ def gobble(option, opt_str, value, parser): """Interprets all the remaining arguments as a single argument. """ setattr(parser.values, option.dest, " ".join(parser.rargs)) del parser.rargs[:] parser = OptionParser( usage="%prog [options] ... [-c cmd | file | -] [arg] ...", version=VERSION_MSG) parser.add_option( "-c", action="callback", dest="cmd", default="", callback=gobble, help="program passed in as a string (terminates option list)") parser.add_option("-i", action="store_true", dest="interactive", help="inspect interactively after running script") parser.add_option( "-q", action="store_true", dest="quiet", help="don't print version message on interactive startup") # fooling OptionParser parser.add_option("--\b\bfile", action="store_true", help=" program read from script file") parser.add_option( "--\b\b-", action="store_true", help=" program read from stdin (default; interactive mode if a tty)" ) parser.add_option( "--\b\barg ...", action="store_true", help=" arguments passed to program in *command-line-args*") args = sys.argv[1:] try: i = args.index("-") except ValueError: i = len(args) dash_and_post = args[i:] opts, command_line_args = parser.parse_args(args[:i]) source = command_line_args.pop(0) if command_line_args else None command_line_args.extend(dash_and_post) opts.command_line_args = command_line_args RT.init() comp = Compiler() command_line_args_sym = findItem(Namespace("clojure.core"), Symbol("*command-line-args*")) with threadBindings({ currentCompiler: comp, command_line_args_sym: command_line_args }): if source: requireClj(source) if opts.interactive or not source and not opts.cmd: import clojure.repl clojure.repl.enable_readline() clojure.repl.run_repl(opts, comp)
import os.path import sys import unittest sys.path = [os.path.dirname(__file__) + "../"] + sys.path from clojure.lang.cljkeyword import Keyword from clojure.lang.namespace import Namespace, findItem from clojure.lang.var import Var, threadBindings from clojure.lang.symbol import Symbol from clojure.main import requireClj _NS_ = findItem(Namespace("clojure.core"), Symbol("*ns*")) def mapTest(ns, var): class Test(unittest.TestCase): def testVar(self): with threadBindings({_NS_: var.ns}): var() name = ns + str(var) tst = Test tst.__name__ = name globals()[name] = tst for x in os.listdir(os.path.dirname(__file__)): if x.endswith(".clj") and x.find("test") >= 0: print "Reading tests from", x requireClj(os.path.join(os.path.dirname(__file__), x)) folder, file = os.path.split(x)
def is_builtin(self): return BoolObj(True) def evaluate(self): return self def invoke2(self, arg0, arg1): val = arg1.evaluate() return Var(arg0, val) class Recur(Obj): def __init__(self): pass def is_builtin(self): return BoolObj(True) def evaluate(self): return self def apply(self, args): nlist = [] while args is not None: nlist.append(args.first().evaluate()) args = args.rest() _RecurInfo.set_recur(List.from_list(nlist)) return None recur = Var(Symbol.from_string("recur"), Recur()) d = Var(Symbol.from_string("def"), Def()) fn = Var(Symbol.from_string("fn"), Fn()) ifsym = Var(Symbol.from_string("if"), If())
from clojure.lang.ipersistentlist import IPersistentList from clojure.lang.ipersistentvector import IPersistentVector from clojure.lang.ipersistentmap import IPersistentMap from clojure.lang.ipersistentset import IPersistentSet from clojure.lang.ipersistentcollection import IPersistentCollection from clojure.lang.iseq import ISeq from clojure.lang.persistenthashmap import EMPTY as EMPTY_MAP from clojure.lang.persistentvector import EMPTY as EMPTY_VECTOR import clojure.lang.persistenthashset from clojure.lang.persistenthashset import createWithCheck import clojure.lang.rt as RT from clojure.lang.symbol import Symbol from clojure.lang.var import Var, threadBindings import clojure.lang.namespace as namespace _AMP_ = Symbol("&") _FN_ = Symbol("fn") _VAR_ = Symbol("var") _APPLY_ = Symbol("apply") _DEREF_ = Symbol("deref") _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()
from clojure.lang.cljexceptions import (ArityException, IllegalStateException) from clojure.lang.cljkeyword import Keyword from clojure.lang.ifn import IFn from clojure.lang.iprintable import IPrintable from clojure.lang.persistenthashmap import EMPTY from clojure.lang.persistentarraymap import create from clojure.lang.settable import Settable from clojure.lang.symbol import Symbol from clojure.lang.threadutil import ThreadLocal, currentThread privateKey = Keyword("private") macrokey = Keyword("macro") STATIC_KEY = Keyword("static") dvals = ThreadLocal() privateMeta = create([privateKey, True]) UNKNOWN = Symbol("UNKNOWN") class Var(ARef, Settable, IFn, IPrintable): def __init__(self, *args): """Var initializer Valid calls: - Var(namespace, symbol, root) - Var(namespace, symbol) -- unbound Var - Var(root) -- anonymous Var - Var() -- anonymous, unbound Var """ self.ns = args[0] if len(args) >= 2 else None self.sym = args[1] if len(args) >= 2 else None root = args[-1] if len(args) % 2 else UNKNOWN
def inner(func): builtins[Symbol(sym)] = func return func
def __init__(self, sym, rest=None): AAlias.__init__(self, rest) self.sym = sym self.newsym = Symbol(RT.name(sym) + str(RT.nextID()))
from clojure.lang.ipersistentlist import IPersistentList from clojure.lang.iseq import ISeq from clojure.lang.lispreader import _AMP_, LINE_KEY, garg from clojure.lang.namespace import Namespace, findNS, findItem, intern from clojure.lang.persistentlist import PersistentList, EmptyList from clojure.lang.persistentvector import PersistentVector import clojure.lang.rt as RT from clojure.lang.symbol import Symbol from clojure.lang.var import Var, threadBindings from clojure.util.byteplay import * import clojure.util.byteplay as byteplay import marshal import types _MACRO_ = Keyword("macro") _NS_ = Symbol("*ns*") version = (sys.version_info[0] * 10) + sys.version_info[1] PTR_MODE_GLOBAL = "PTR_MODE_GLOBAL" PTR_MODE_DEREF = "PTR_MODE_DEREF" AUDIT_CONSTS = False class MetaBytecode(object): pass class GlobalPtr(MetaBytecode): def __init__(self, ns, name): self.ns = ns
def syntaxQuote(self, form): # compiler uses this module, so import it lazily from 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, "{0}__{1}__auto__".format(sym.name[:-1], RT.nextID())) 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.deref() 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") item = namespace.findItem(ns, sym) if item is None: sym = Symbol(ns.__name__, sym.name) else: sym = Symbol(item.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 = self.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 getattr(form, "meta", lambda: None)() is not None: newMeta = form.meta().without(LINE_KEY) if len(newMeta) > 0: return RT.list(_WITH_META_, ret, self.syntaxQuote(form.meta()))#FIXME: _WITH_META_ undefined return ret
def compileFNStar(comp, form): haslocalcaptures = False aliases = [] if len(comp.aliases) > 0: # we might have closures 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() + "_auto_" else: comp.pushName(name.name) pushed = True form = form.next() name = Symbol(name) # This is fun stuff here. The idea is that we want closures to be able # to call themselves. But we can't get a pointer to a closure until after # it's created, which is when we actually run this code. So, we're going to # create a tmp local that is None at first, then pass that in as a possible # closure cell. Then after we create the closure with MAKE_CLOSURE we'll # populate this var with the correct value selfalias = Closure(name) comp.pushAlias(name, selfalias) # form = ([x] x) if isinstance(form.first(), IPersistentVector): code, ptr = compileFn(comp, name, form, orgform) # form = (([x] x)) elif len(form) == 1: code, ptr = compileFn(comp, name, RT.list(*form.first()), orgform) # form = (([x] x) ([x y] x)) else: code, ptr = compileMultiFn(comp, name, form) if pushed: comp.popName() clist = comp.closureList() fcode = [] if haslocalcaptures: comp.popAliases(aliases) if clist: for x in clist: if x is not selfalias: #we'll populate selfalias later fcode.extend(comp.getAlias( x.sym).compile(comp)) # Load our local version fcode.append((STORE_DEREF, RT.name(x.sym))) # Store it in a Closure Cell fcode.append( (LOAD_CLOSURE, RT.name(x.sym))) # Push the cell on the stack fcode.append((BUILD_TUPLE, len(clist))) fcode.extend(code) fcode.append((MAKE_CLOSURE, 0)) code = fcode if selfalias in clist: prefix = [] prefix.append((LOAD_CONST, None)) prefix.extend(selfalias.compileSet(comp)) prefix.extend(code) code = prefix code.append((DUP_TOP, None)) code.extend(selfalias.compileSet(comp)) comp.popAlias(Symbol(name)) #closure return code
def garg(n): return Symbol("rest" if n == -1 else "p{0}__{1}#".format(n, RT.nextID()))
def init_vars(): from clojure.lang.var import Var conslist = Var(Symbol.from_string("cons_list*"), Cons_List())
def compileTry(comp, form): """ Compiles the try macro. """ assert form.first() == Symbol("try") form = form.next() if not form: # I don't like this, but (try) == nil return [(LOAD_CONST, None)] # Keep a list of compiled might-throw statements in # implicit-do try body body = comp.compile(form.first()) form = form.next() if not form: # If there are no further body statements, or # catch/finally/else etc statements, just # compile the body return body catch = [] els = None fin = None for subform in form: try: name = subform.first() except AttributeError: name = None if name in (Symbol("catch"), Symbol("except")): name = subform.first() if len(subform) != 4: raise CompilerException( "try {0} blocks must be 4 items long".format(name), form) # Exception is second, val is third exception = subform.next().first() if not isinstance(exception, Symbol): raise CompilerException( "exception passed to {0} block must be a symbol".format( name), form) for ex, _, _ in catch: if ex == exception: raise CompilerException( "try cannot catch duplicate exceptions", form) var = subform.next().next().first() if not isinstance(var, Symbol): raise CompilerException( "variable name for {0} block must be a symbol".format( name), form) val = subform.next().next().next().first() catch.append((exception, var, val)) elif name == Symbol("else"): if len(subform) != 2: raise CompilerException("try else blocks must be 2 items", form) elif els: raise CompilerException("try cannot have multiple els blocks", form) els = subform.next().first() elif name == Symbol("finally"): if len(subform) != 2: raise CompilerException("try finally blocks must be 2 items", form) elif fin: raise CompilerException( "try cannot have multiple finally blocks", form) fin = subform.next().first() else: # Append to implicit do body.append((POP_TOP, None)) body.extend(comp.compile(subform)) if fin and not catch and not els: return compileTryFinally(body, comp.compile(fin)) elif catch and not fin and not els: return compileTryCatch(comp, body, catch) elif not fin and not catch and els: raise CompilerException( "try does not accept else statements on their own", form) if fin and catch and not els: return compileTryCatchFinally(comp, body, catch, comp.compile(fin)) if not fin and not catch and not els: # No other statements, return compiled body return body
def compileTry(comp, form): """ Compiles the try macro. """ assert form.first() == Symbol("try") form = form.next() if not form: # I don't like this, but (try) == nil return [(LOAD_CONST, None)] # Extract the thing that may raise exceptions body = form.first() form = form.next() if not form: # If there are no catch/finally/else etc statements, just # compile the budy return comp.compile(body) catch = [] els = None fin = None for subform in form: # FIXME, could also be a Cons, LazySeq, etc. #if not isinstance(subform, IPersistentList): # raise CompilerException("try arguments must be lists", form) if not len(subform): raise CompilerException("try arguments must not be empty", form) name = subform.first() if name in (Symbol("catch"), Symbol("except")): if len(subform) != 4: raise CompilerException( "try {0} blocks must be 4 items long".format(name), form) # Exception is second, val is third exception = subform.next().first() if not isinstance(exception, Symbol): raise CompilerException( "exception passed to {0} block must be a symbol".format( name), form) for ex, _, _ in catch: if ex == exception: raise CompilerException( "try cannot catch duplicate exceptions", form) var = subform.next().next().first() if not isinstance(var, Symbol): raise CompilerException( "variable name for {0} block must be a symbol".format( name), form) val = subform.next().next().next().first() catch.append((exception, var, val)) elif name == Symbol("else"): if len(subform) != 2: raise CompilerException("try else blocks must be 2 items", form) elif els: raise CompilerException("try cannot have multiple els blocks", form) els = subform.next().first() elif name == Symbol("finally"): if len(subform) != 2: raise CompilerException("try finally blocks must be 2 items", form) elif fin: raise CompilerException( "try cannot have multiple finally blocks", form) fin = subform.next().first() else: raise CompilerException( "try does not accept any symbols apart from " "catch/except/else/finally, got {0}".format(form), form) if fin and not catch and not els: return compileTryFinally(comp.compile(body), comp.compile(fin)) elif catch and not fin and not els: return compileTryCatch(comp, comp.compile(body), catch) elif not fin and not catch and els: raise CompilerException( "try does not accept else statements on their own", form) if fin and catch and not els: return compileTryCatchFinally(comp, comp.compile(body), catch, comp.compile(fin))