def compileBytecode(comp, form): codename = form.first().name if not hasattr(byteplay, codename): raise CompilerException("bytecode {0} unknown".format(codename), form) bc = getattr(byteplay, codename) hasarg = bc in byteplay.hasarg form = form.next() arg = None if hasarg: arg = form.first() if not isinstance(arg, (int, str, unicode)) and bc is not LOAD_CONST: raise CompilerException( "first argument to {0} must be int, unicode, or str".format( codename), form) arg = evalForm(arg, comp.getNS()) form = form.next() se = byteplay.getse(bc, arg) if form != None and se[0] != 0 and (se[0] != len(form) or se[1] > 1): raise CompilerException( "literal bytecode {0} not supported".format(codename), form) s = form code = [] while s is not None: code.extend(comp.compile(s.first())) s = s.next() code.append((bc, arg)) if se[1] == 0: code.append((LOAD_CONST, None)) return code
def getAccessCode(self, sym): if (sym.ns is not None and sym.ns == self.getNS().__name__) \ or sym.ns is None: 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 '" + str(sym) + "', '" \ + RT.name(sym) + "' not found in " + self.getNS().__name__ + " reference " + str(self.getNamesString(False)), None) var = getattr(self.getNS(), RT.name(sym)) return [GlobalPtr(self.getNS(), RT.name(sym))] if hasattr(self.getNS(), "__aliases__") and \ symbol(sym.ns) in self.getNS().__aliases__: sym = symbol(self.getNS().__aliases__[symbol(sym.ns)].__name__, RT.name(sym)) splt = [] if sym.ns is not None: module = findNamespace(sym.ns) if not hasattr(module, RT.name(sym)): raise CompilerException( str(module) + " does not define " + 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: " + str(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 compileLetMacro(comp, form): if len(form) < 3: raise CompilerException("alias-properties takes at least two args", form) form = form.next() s = RT.seq(form.first()) syms = [] while s is not None: sym = s.first() syms.append(sym) s = s.next() if s is None: raise CompilerException( "let-macro takes a even number of bindings") macro = s.first() comp.pushAlias(sym, LocalMacro(sym, macro)) s = s.next() body = form.next() code = compileImplcitDo(comp, body) comp.popAliases(syms) return code
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 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 __init__(self, comp, form): form = RT.seq(form) if len(form) < 2: raise CompilerException("FN defs must have at least two vars", 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 compileIf(comp, form): if len(form) != 3 and len(form) != 4: raise CompilerException("if takes 2 or 3 args", form) cmp = comp.compile(form.next().first()) body = comp.compile(form.next().next().first()) if len(form) == 3: body2 = [(LOAD_CONST, None)] else: body2 = comp.compile(form.next().next().next().first()) elseLabel = Label("IfElse") endlabel = Label("IfEnd") condition_name = garg(0).name code = cmp code.append((STORE_FAST, condition_name)) code.append((LOAD_FAST, condition_name)) code.append((LOAD_CONST, None)) code.append((COMPARE_OP, 'is not')) code.extend(emitJump(elseLabel)) code.append((LOAD_FAST, condition_name)) code.append((LOAD_CONST, False)) code.append((COMPARE_OP, '!=')) code.extend(emitJump(elseLabel)) code.extend(body) code.append((JUMP_ABSOLUTE, endlabel)) code.extend(emitLanding(elseLabel)) code.extend(body2) code.append((endlabel, None)) return code
def compileIfStar(comp, form): """ Compiles the form (if* pred val else?). """ if len(form) != 3 and len(form) != 4: raise CompilerException("if takes 2 or 3 args", form) cmp = comp.compile(form.next().first()) body = comp.compile(form.next().next().first()) if len(form) == 3: body2 = [(LOAD_CONST, None)] else: body2 = comp.compile(form.next().next().next().first()) elseLabel = Label("IfElse") endlabel = Label("IfEnd") condition_name = garg(0).name code = cmp code.append((STORE_FAST, condition_name)) code.append((LOAD_FAST, condition_name)) code.append((LOAD_CONST, None)) code.append((COMPARE_OP, 'is not')) code.extend(emitJump(elseLabel)) code.append((LOAD_FAST, condition_name)) code.append((LOAD_CONST, False)) code.append((COMPARE_OP, 'is not')) # Use is not instead of != as bool is a subclass of int, and # therefore False == 0 code.extend(emitJump(elseLabel)) code.extend(body) code.append((JUMP_ABSOLUTE, endlabel)) code.extend(emitLanding(elseLabel)) code.extend(body2) code.append((endlabel, None)) return code
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 = [] v = internVar(comp.getNS(), sym) v.setDynamic(True) v.setMeta(sym.meta()) code.append((LOAD_CONST, v)) code.append((LOAD_ATTR, "bindRoot")) code.extend(comp.compile(value)) code.append((CALL_FUNCTION, 1)) code.append((LOAD_CONST, v.setDynamic)) code.append((LOAD_CONST, False)) code.append((CALL_FUNCTION, 1)) code.append((POP_TOP, None)) comp.popName() return code
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(RT.name(sym)) code = [] v = intern(comp.getNS(), sym) v.setDynamic(True) if len(form) == 3: code.append((LOAD_CONST, v)) code.append((LOAD_ATTR, "bindRoot")) compiledValue = comp.compile(value) if isinstance(value, ISeq) \ and value.first().getName() == 'fn' \ and sym.meta() is not None: try: compiledValue[0][1].__doc__ = sym.meta()[Keyword('doc')] except AttributeError: pass code.extend(compiledValue) code.append((CALL_FUNCTION, 1)) else: code.append((LOAD_CONST, v)) v.setMeta(sym.meta()) comp.popName() return code
def compilePropertyAccess(self, form): attrname = form.first().name[2:] if len(form) != 2: raise CompilerException( "Property access must have at only one argument", form) c = self.compile(form.next().first()) c.append((LOAD_ATTR, attrname)) return c
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: comp.getAlias(x).compileSet(comp), args) } code.append((recurlabel, None)) comp.pushRecur(recur) code.extend(compileImplcitDo(comp, form)) comp.popRecur() comp.popAliases(args) return code
def compileIs(comp, form): if len(form) != 3: raise CompilerException("is? requires 2 arguments", form) fst = form.next().first() itm = form.next().next().first() code = comp.compile(fst) code.extend(comp.compile(itm)) code.append((COMPARE_OP, "is")) return code
def unpackArgs(form): locals = {} args = [] lastisargs = False argsname = None for x in form: if x == _AMP_: lastisargs = True continue if lastisargs and argsname is not None: raise CompilerException( "variable length argument must be the last in the function") if lastisargs: argsname = x if not isinstance(x, Symbol) or x.ns is not None: raise CompilerException( "fn* arguments must be non namespaced symbols " + " got " + str(form) + " instead", form) locals[x] = RT.list(x) args.append(x.name) return locals, args, lastisargs, argsname
def getAccessCode(self, sym): if (sym.ns is not None and sym.ns == self.getNS().__name__) \ or sym.ns is None: if not hasattr(self.getNS(), sym.name): raise CompilerException("could not resolve " + str(sym) + " " \ + sym.name + " not found in " + self.getNS().__name__, sym) var = getattr(self.getNS(), sym.name) if isinstance(var, Var): if (var.isDynamic()): return [(LOAD_CONST, var.deref), (CALL_FUNCTION, 0)] else: return [(LOAD_CONST, var.deref())] return [(LOAD_GLOBAL, sym.name)] splt = [] if sym.ns is not None: module = findNamespace(sym.ns) if not hasattr(module, sym.name): raise CompilerException( str(module) + " does not define " + sym.name, None) attr = getattr(module, sym.name) if isinstance(attr, Var): splt.append((LOAD_CONST, attr.deref)) splt.append((CALL_FUNCTION, 0)) else: splt.append((LOAD_CONST, module)) splt.append((LOAD_ATTR, sym.name)) return splt code = LOAD_ATTR if sym.ns else LOAD_GLOBAL if not sym.ns and sym.name.find(".") != -1 and sym.name != "..": raise CompilerException( "unqualified dotted forms not supported: " + str(sym), sym) if len(sym.name.replace(".", "")): splt.extend((code, attr) for attr in sym.name.split(".")) else: splt.append((code, sym.name)) return splt
def compileMethodAccess(self, form): attrname = form.first().name[1:] if len(form) < 2: raise CompilerException( "Method access must have at least one argument", form) c = self.compile(form.next().first()) c.append((LOAD_ATTR, attrname)) s = form.next().next() while s is not None: c.extend(self.compile(s.first())) s = s.next() c.append((CALL_FUNCTION, (len(form) - 2))) return c
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
def compileRecur(comp, form): s = form.next() or [] code = [] if len(s) > len(comp.recurPoint.first()["args"]): raise CompilerException("too many arguments to recur", form) for recur_val in s: code.extend(comp.compile(recur_val)) sets = comp.recurPoint.first()["args"][:] sets.reverse() for x in sets: code.extend(x) code.append((JUMP_ABSOLUTE, comp.recurPoint.first()["label"])) return code
def compile(self, itm): try: c = [] lineset = False if getattr(itm, "meta", lambda: None)() is not None: line = itm.meta()[LINE_KEY] if line is not None and line > self.lastlineno: lineset = True self.lastlineno = line c.append([SetLineno, line]) if isinstance(itm, Symbol): c.extend(self.compileSymbol(itm)) elif isinstance(itm, PersistentList) or isinstance(itm, Cons): c.extend(self.compileForm(itm)) elif itm is None: c.extend(self.compileNone(itm)) elif type(itm) in [str, int, types.ClassType, type, Var]: c.extend([(LOAD_CONST, itm)]) elif isinstance(itm, IPersistentVector): c.extend(compileVector(self, itm)) elif isinstance(itm, IPersistentMap): c.extend(compileMap(self, itm)) elif isinstance(itm, Keyword): c.extend(compileKeyword(self, itm)) elif isinstance(itm, bool): c.extend(compileBool(self, itm)) elif isinstance(itm, EmptyList): c.append((LOAD_CONST, itm)) elif isinstance(itm, unicode): c.append((LOAD_CONST, itm)) elif isinstance(itm, float): c.append((LOAD_CONST, itm)) elif isinstance(itm, long): c.append((LOAD_CONST, itm)) elif isinstance(itm, fractions.Fraction): c.append((LOAD_CONST, itm)) elif isinstance(itm, IPersistentSet): c.append((LOAD_CONST, itm)) elif isinstance(itm, type(re.compile(""))): c.append((LOAD_CONST, itm)) else: raise CompilerException( " don't know how to compile {0}".format(type(itm)), None) if len(c) < 2 and lineset: return [] return c except: print "Compiling {0}".format(itm) raise
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 emit(self, comp, mode): module = self.ns val = getattr(module, self.name) if isinstance(val, Var): if not val.isDynamic(): val = val.deref() return [(LOAD_CONST, val)] else: if mode is PTR_MODE_DEREF: return [(LOAD_CONST, val), (LOAD_ATTR, "deref"), (CALL_FUNCTION, 0)] else: raise CompilerException("Invalid deref mode", mode) return [(LOAD_CONST, module), (LOAD_ATTR, self.name)]
def compileNS(comp, form): rest = form.next() if len(rest) != 1: raise CompilerException("in-ns only supports one item", rest) ns = rest.first() code = [(LOAD_CONST, comp), (LOAD_ATTR, "setNS")] if isinstance(ns, Symbol): code.append((LOAD_CONST, ns)) else: code.extend(comp.compile(ns)) code.append((CALL_FUNCTION, 1)) set_NS_ = [(LOAD_CONST, comp), (LOAD_ATTR, "_NS_"), (LOAD_ATTR, "set"), (LOAD_CONST, comp), (LOAD_ATTR, "ns"), (CALL_FUNCTION, 1), (LOAD_CONST, comp), (LOAD_ATTR, "ns")] code.extend(set_NS_) return code
def compileRecur(comp, form): s = form.next() idx = 0 code = [] 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) idx += 1 s = s.next() sets = comp.recurPoint.first()["args"][:] sets.reverse() for x in sets: code.extend(x) code.append((JUMP_ABSOLUTE, comp.recurPoint.first()["label"])) return code
def compilePyIf(comp, form): if len(form) != 3 and len(form) != 4: raise CompilerException("if takes 2 or 3 args", form) cmp = comp.compile(form.next().first()) body = comp.compile(form.next().next().first()) if len(form) == 3: body2 = [(LOAD_CONST, None)] else: body2 = comp.compile(form.next().next().next().first()) elseLabel = Label("IfElse") endlabel = Label("IfEnd") code = cmp code.extend(emitJump(elseLabel)) code.extend(body) code.append((JUMP_ABSOLUTE, endlabel)) code.extend(emitLanding(elseLabel)) code.extend(body2) code.append((endlabel, None)) return code
def compile(self, itm): from clojure.lang.persistentlist import PersistentList, EmptyList from clojure.lang.cons import Cons c = [] lineset = False if hasattr(itm, "meta") and itm.meta() is not None: line = itm.meta()[LINE_KEY] if line is not None and line > self.lastlineno: lineset = True self.lastlineno = line c.append([SetLineno, line]) if isinstance(itm, Symbol): c.extend(self.compileSymbol(itm)) elif isinstance(itm, PersistentList) or isinstance(itm, Cons): c.extend(self.compileForm(itm)) elif itm is None: c.extend(self.compileNone(itm)) elif type(itm) in [str, int, new.classobj, type]: c.extend([(LOAD_CONST, itm)]) elif isinstance(itm, IPersistentVector): c.extend(compileVector(self, itm)) elif isinstance(itm, IPersistentMap): c.extend(compileMap(self, itm)) elif isinstance(itm, Keyword): c.extend(compileKeyword(self, itm)) elif isinstance(itm, bool): c.extend(compileBool(self, itm)) elif isinstance(itm, EmptyList): c.append((LOAD_CONST, itm)) elif isinstance(itm, unicode): c.append((LOAD_CONST, itm)) else: raise CompilerException( "Don't know how to compile" + str(type(itm)), None) if len(c) < 2 and lineset: return [] return c
def compileKWApply(comp, form): if len(form) < 3: raise CompilerException("at least two arguments required to kwapply", form) form = form.next() fn = form.first() form = form.next() kws = form.first() args = form.next() code = [] s = args code.extend(comp.compile(fn)) while s is not None: code.extend(comp.compile(s.first())) s = s.next() code.extend(comp.compile(kws)) code.append((LOAD_ATTR, "toDict")) code.append((CALL_FUNCTION, 0)) code.append((CALL_FUNCTION_KW, 0 if args is None else len(args))) return code
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)], c
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 getBuiltin(name): if hasattr(__builtin__, name): return getattr(__builtin__, name) raise CompilerException("Python builtin {0} not found".format(name), name)
def compileBuiltin(comp, form): if len(form) != 2: raise CompilerException("throw requires two arguments", form) name = str(form.next().first()) return [(LOAD_CONST, getBuiltin(name))]