def compile_fn(form, ctx): form = rt.next(form) if isinstance(rt.first(form), symbol.Symbol): name = rt.first(form) form = rt.next(form) else: name = symbol.symbol(default_fn_name) if rt._satisfies_QMARK_(rt.ISeq.deref(), rt.first(form)): arities = [] while form is not nil: required_arity, argc = compile_fn_body(name, rt.first(rt.first(form)), rt.next(rt.first(form)), ctx) arities.append(argc if required_arity == -1 else required_arity | 256) form = rt.next(form) ctx.bytecode.append(code.MAKE_MULTI_ARITY) ctx.bytecode.append(r_uint(len(arities))) arities.reverse() for x in arities: ctx.bytecode.append(r_uint(x)) ctx.add_sp(1) # result ctx.sub_sp(len(arities)) else: res = compile_fn_body(name, rt.first(form), rt.next(form), ctx) if rt.meta(name) is not nil: compile_meta(rt.meta(name), ctx)
def compile_if(form, ctx): form = form.next() affirm(2 <= rt.count(form) <= 3, u"If must have either 2 or 3 forms") test = rt.first(form) form = rt.next(form) then = rt.first(form) form = rt.next(form) els = rt.first(form) ctx.disable_tail_call() compile_form(test, ctx) ctx.bytecode.append(code.COND_BR) ctx.sub_sp(1) sp1 = ctx.sp() cond_lbl = ctx.label() ctx.enable_tail_call() compile_form(then, ctx) ctx.bytecode.append(code.JMP) ctx.sub_sp(1) affirm(ctx.sp() == sp1, u"If branches stacks are unequal " + unicode(str(ctx.sp())) + u", " + unicode(str(sp1))) else_lbl = ctx.label() ctx.mark(cond_lbl) compile_form(els, ctx) ctx.mark(else_lbl)
def compile_if(form, ctx): form = form.next() affirm(2 <= rt.count(form) <= 3, u"If must have either 2 or 3 forms") test = rt.first(form) form = rt.next(form) then = rt.first(form) form = rt.next(form) els = rt.first(form) ctx.disable_tail_call() compile_form(test, ctx) ctx.bytecode.append(code.COND_BR) ctx.sub_sp(1) sp1 = ctx.sp() cond_lbl = ctx.label() ctx.enable_tail_call() compile_form(then, ctx) ctx.bytecode.append(code.JMP) ctx.sub_sp(1) affirm( ctx.sp() == sp1, u"If branches stacks are unequal " + unicode(str(ctx.sp())) + u", " + unicode(str(sp1))) else_lbl = ctx.label() ctx.mark(cond_lbl) compile_form(els, ctx) ctx.mark(else_lbl)
def expand_list_rfn(ret, item): if is_unquote(item): ret = rt.conj(ret, rt.vector(rt.first(rt.next(item)))) elif is_unquote_splicing(item): ret = rt.conj(ret, rt.first(rt.next(item))) else: ret = rt.conj(ret, rt.vector(SyntaxQuoteReader.syntax_quote(item))) return ret
def call_macro(var, form, ctx): form = rt.next(form) args = [None] * rt.count(form) i = 0 while form is not nil: args[i] = rt.first(form) form = rt.next(form) i += 1 return var.invoke(args)
def compile_do(form, ctx): form = rt.next(form) while True: compile_form(rt.first(form), ctx) form = rt.next(form) if form is nil: return else: ctx.pop()
def compile_def(form, ctx): form = rt.next(form) name = rt.first(form) form = rt.next(form) val = rt.first(form) affirm(isinstance(name, symbol.Symbol), u"Def'd name must be a symbol") var = NS_VAR.deref().intern_or_make(rt.name(name)) ctx.push_const(var) compile_form(val, ctx) ctx.bytecode.append(code.SET_VAR) ctx.sub_sp(1)
def compile_fn_body(name, args, body, ctx): new_ctx = Context(rt.name(name), rt.count(args), ctx) required_args = add_args(rt.name(name), args, new_ctx) bc = 0 if name is not None: affirm(isinstance(name, symbol.Symbol), u"Function names must be symbols") #new_ctx.add_local(name._str, Self()) arg_syms = EMPTY for x in range(rt.count(args)): sym = rt.nth(args, rt.wrap(x)) if not rt.name(sym) == u"&": arg_syms = rt.conj(rt.conj(arg_syms, sym), sym) body = rt.list(rt.cons(LOOP, rt.cons(arg_syms, body))) #new_ctx.push_recur_point(FunctionRecurPoint()) new_ctx.disable_tail_call() if body is nil: compile_form(body, new_ctx) else: while body is not nil: if rt.next(body) is nil: new_ctx.enable_tail_call() compile_form(rt.first(body), new_ctx) body = rt.next(body) if body is not nil: new_ctx.pop() new_ctx.bytecode.append(code.RETURN) closed_overs = new_ctx.closed_overs if len(closed_overs) == 0: ctx.push_const(new_ctx.to_code(required_args)) else: ctx.push_const(new_ctx.to_code(required_args)) for x in closed_overs: x.emit(ctx) ctx.bytecode.append(code.MAKE_CLOSURE) ctx.bytecode.append(r_uint(len(closed_overs))) ctx.sub_sp(len(closed_overs)) if required_args >= 0: ctx.bytecode.append(code.MAKE_VARIADIC) ctx.bytecode.append(r_uint(required_args)) return required_args, intmask(rt.count(args))
def compile_fn_call(form, ctx): macro = is_macro_call(form, ctx) if macro: return compile_form(call_macro(macro, form, ctx), ctx) meta = rt.meta(form) cnt = 0 ctc = ctx.can_tail_call while form is not nil: ctx.disable_tail_call() compile_form(rt.first(form), ctx) cnt += 1 form = rt.next(form) if ctc: ctx.enable_tail_call() #if ctx.can_tail_call: # ctx.bytecode.append(code.TAIL_CALL) #else: if meta is not nil: ctx.debug_points[len(ctx.bytecode)] = rt.interpreter_code_info(meta) ctx.bytecode.append(code.INVOKE) ctx.bytecode.append(cnt) ctx.sub_sp(r_uint(cnt - 1))
def compile_let(form, ctx): form = next(form) bindings = rt.first(form) affirm(isinstance(bindings, PersistentVector), u"Bindings must be a vector") body = next(form) ctc = ctx.can_tail_call ctx.disable_tail_call() binding_count = 0 for i in range(0, rt.count(bindings).int_val(), 2): binding_count += 1 name = rt.nth(bindings, numbers.Integer(i)) affirm(isinstance(name, symbol.Symbol), u"Let locals must be symbols") bind = rt.nth(bindings, numbers.Integer(i + 1)) compile_form(bind, ctx) ctx.add_local(name._str, LetBinding(ctx.sp())) if ctc: ctx.enable_tail_call() while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.bytecode.append(code.POP_UP_N) ctx.sub_sp(binding_count) ctx.bytecode.append(binding_count)
def macroexpand(form): sym = rt.first(form) if isinstance(sym, symbol.Symbol): s = rt.name(sym) if s.startswith(".") and s != u".": if rt.count(form) < 2: raise Exception("malformed dot expression, expecting (.member obj ...)") method = rt.keyword(rt.wrap(rt.name(sym)[1:])) obj = rt.first(rt.next(form)) dot = rt.symbol(rt.wrap(u".")) call = rt.cons(dot, rt.cons(obj, rt.cons(method, rt.next(rt.next(form))))) return call return form
def compile_cons(form, ctx): if isinstance(form.first(), symbol.Symbol) and form.first()._str in builtins: return builtins[form.first()._str](form, ctx) macro = is_macro_call(form, ctx) if macro: return compile_form(call_macro(macro, form, ctx), ctx) cnt = 0 ctc = ctx.can_tail_call while form is not nil: ctx.disable_tail_call() compile_form(rt.first(form), ctx) cnt += 1 form = rt.next(form) if ctc: ctx.enable_tail_call() #if ctx.can_tail_call: # ctx.bytecode.append(code.TAIL_CALL) #else: ctx.bytecode.append(code.INVOKE) ctx.bytecode.append(cnt) ctx.sub_sp(cnt - 1)
def compile_cons(form, ctx): if isinstance(rt.first(form), symbol.Symbol): special = compiler_special(rt.first(form)) if special is not None: return special(form, ctx) macro = is_macro_call(form, ctx) if macro: return compile_form(call_macro(macro, form, ctx), ctx) meta = rt.meta(form) cnt = 0 ctc = ctx.can_tail_call while form is not nil: ctx.disable_tail_call() compile_form(rt.first(form), ctx) cnt += 1 form = rt.next(form) if ctc: ctx.enable_tail_call() #if ctx.can_tail_call: # ctx.bytecode.append(code.TAIL_CALL) #else: if meta is not nil: ctx.debug_points[len(ctx.bytecode)] = meta ctx.bytecode.append(code.INVOKE) ctx.bytecode.append(cnt) ctx.sub_sp(cnt - 1)
def syntax_quote(form): if isinstance(form, Symbol) and compiler.is_compiler_special(form): ret = rt.list(QUOTE, form) elif isinstance(form, Symbol): if rt.namespace(form) is None and rt.name(form).endswith("#"): gmap = rt.deref(GEN_SYM_ENV) affirm(gmap is not nil, u"Gensym literal used outside a syntax quote") gs = rt.get(gmap, form) if gs is nil: gs = rt.symbol(rt.str(form, rt.wrap(u"__"), rt.gensym())) GEN_SYM_ENV.set_value(rt.assoc(gmap, form, gs)) form = gs else: var = rt.resolve_in(compiler.NS_VAR.deref(), form) if var is nil: form = rt.symbol(rt.str(rt.wrap(rt.name(rt.deref(compiler.NS_VAR))), rt.wrap(u"/"), form)) else: form = rt.symbol(rt.str(rt.wrap(rt.namespace(var)), rt.wrap(u"/"), rt.str(rt.wrap(rt.name(var))))) ret = rt.list(QUOTE, form) elif is_unquote(form): ret = rt.first(rt.next(form)) elif is_unquote_splicing(form): return runtime_error(u"Unquote splicing not used inside list") elif rt.vector_QMARK_(form) is true: ret = rt.list(APPLY, CONCAT, SyntaxQuoteReader.expand_list(form)) elif rt.map_QMARK_(form) is true: mes = SyntaxQuoteReader.flatten_map(form) ret = rt.list(APPLY, HASHMAP, rt.list(APPLY, CONCAT, SyntaxQuoteReader.expand_list(mes))) elif form is not nil and rt.seq_QMARK_(form) is true: ret = rt.list(APPLY, LIST, rt.cons(CONCAT, SyntaxQuoteReader.expand_list(rt.seq(form)))) else: ret = rt.list(QUOTE, form) return ret
def syntax_quote(form): if isinstance(form, Symbol) and compiler.is_compiler_special(form): ret = rt.list(QUOTE, form) elif isinstance(form, Symbol): if rt.namespace(form) is None and rt.name(form).endswith("#"): gmap = rt.deref(GEN_SYM_ENV) affirm(gmap is not nil, u"Gensym literal used outside a syntax quote") gs = rt.get(gmap, form) if gs is nil: gs = rt.symbol(rt.str(form, rt.wrap(u"__"), rt.gensym())) GEN_SYM_ENV.set_value(rt.assoc(gmap, form, gs)) form = gs else: var = rt.resolve_in(compiler.NS_VAR.deref(), form) if var is nil: form = rt.symbol(rt.str(rt.wrap(rt.name(rt.deref(compiler.NS_VAR))), rt.wrap(u"/"), form)) else: form = rt.symbol(rt.str(rt.wrap(rt.namespace(var)), rt.wrap(u"/"), rt.str(rt.wrap(rt.name(var))))) ret = rt.list(QUOTE, form) elif is_unquote(form): ret = rt.first(rt.next(form)) elif is_unquote_splicing(form): raise Exception("Unquote splicing not used inside list") elif rt.vector_QMARK_(form) is true: ret = rt.list(APPLY, CONCAT, SyntaxQuoteReader.expand_list(form)) elif rt.seq_QMARK_(form) is true: ret = rt.list(APPLY, LIST, rt.cons(CONCAT, SyntaxQuoteReader.expand_list(rt.seq(form)))) else: ret = rt.list(QUOTE, form) return ret
def write_seq(s, wtr): write_tag(SEQ, wtr) write_int_raw(rt.count(s), wtr) s = rt.seq(s) while s is not nil: write_object(rt.first(s), wtr) s = rt.next(s)
def compile_def(form, ctx): form = rt.next(form) name = rt.first(form) form = rt.next(form) val = rt.first(form) affirm(isinstance(name, symbol.Symbol), u"Def'd name must be a symbol") var = NS_VAR.deref().intern_or_make(rt.name(name)) if rt._val_at(rt.meta(name), DYNAMIC_KW, nil) is true: assert isinstance(var, code.Var) var.set_dynamic() ctx.push_const(var) compile_form(val, ctx) ctx.bytecode.append(code.SET_VAR) ctx.sub_sp(1)
def macroexpand(form): sym = rt.first(form) if isinstance(sym, symbol.Symbol): s = rt.name(sym) if s.startswith(".") and s != u".": if rt.count(form) < 2: raise Exception( "malformed dot expression, expecting (.member obj ...)") method = rt.keyword(rt.wrap(rt.name(sym)[1:])) obj = rt.first(rt.next(form)) dot = rt.symbol(rt.wrap(u".")) call = rt.cons( dot, rt.cons(obj, rt.cons(method, rt.next(rt.next(form))))) return call return form
def compile_local_macro(form, ctx): form = rt.next(form) binding = rt.first(form) body = rt.next(form) sym = rt.nth(binding, rt.wrap(0)) bind_form = rt.nth(binding, rt.wrap(1)) ctx.add_local(rt.name(sym), LocalMacro(bind_form)) while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.pop_locals()
def maybe_oop_invoke(form): head = rt.first(form) if isinstance(rt.first(form), symbol.Symbol) and rt.name(head).startswith(".-"): postfix = rt.next(form) affirm(rt.count(postfix) == 1, u" Attribute lookups must only have one argument") subject = rt.first(postfix) kw = keyword(rt.name(head)[2:]) fn = symbol.symbol(u"pixie.stdlib/-get-attr") return create_from_list([fn, subject, kw]) elif isinstance(rt.first(form), symbol.Symbol) and rt.name(head).startswith("."): subject = rt.first(rt.next(form)) postfix = rt.next(rt.next(form)) form = cons(keyword(rt.name(head)[1:]), postfix) form = cons(subject, form) form = cons(symbol.symbol(u"pixie.stdlib/-call-method"), form) return form else: return form
def compile_ns(form, ctx): affirm(rt.count(form).int_val() == 2, u"ns only takes one argument, a symbol") nm = rt.first(rt.next(form)) affirm(isinstance(nm, symbol.Symbol), u"Namespace name must be a symbol") str_name = rt.name(nm) NS_VAR.set_value(code._ns_registry.find_or_make(str_name)) ctx.push_const(nil)
def compile_fn_body(name, args, body, ctx): new_ctx = Context(name._str, rt.count(args).int_val(), ctx) required_args = add_args(args, new_ctx) bc = 0 if name is not None: affirm(isinstance(name, symbol.Symbol), u"Function names must be symbols") #new_ctx.add_local(name._str, Self()) new_ctx.push_recur_point(FunctionRecurPoint()) new_ctx.disable_tail_call() if body is nil: compile_form(body, new_ctx) else: while body is not nil: if rt.next(body) is nil: new_ctx.enable_tail_call() compile_form(rt.first(body), new_ctx) if rt.next(body) is not nil: new_ctx.pop() bc += 1 body = rt.next(body) new_ctx.bytecode.append(code.RETURN) closed_overs = new_ctx.closed_overs if len(closed_overs) == 0: ctx.push_const(new_ctx.to_code(required_args)) else: ctx.push_const(new_ctx.to_code(required_args)) for x in closed_overs: x.emit(ctx) ctx.bytecode.append(code.MAKE_CLOSURE) ctx.bytecode.append(r_uint(len(closed_overs))) ctx.sub_sp(len(closed_overs)) if required_args >= 0: ctx.bytecode.append(code.MAKE_VARIADIC) ctx.bytecode.append(r_uint(required_args)) return required_args, rt.count(args).int_val()
def compile_var(form, ctx): form = rt.next(form) name = rt.first(form) affirm(isinstance(name, symbol.Symbol), u"var name must be a symbol") if rt.namespace(name) is not None: var = code._ns_registry.find_or_make(rt.namespace(name)) else: var = NS_VAR.deref().intern_or_make(rt.name(name)) ctx.push_const(var)
def compile_ns(form, ctx): affirm(rt.count(form) == 2, u"ns only takes one argument, a symbol") nm = rt.first(rt.next(form)) affirm(isinstance(nm, symbol.Symbol), u"Namespace name must be a symbol") str_name = rt.name(nm) NS_VAR.set_value(code._ns_registry.find_or_make(str_name)) NS_VAR.deref().include_stdlib() ctx.push_const(nil)
def compile_loop(form, ctx): form = rt.next(form) bindings = rt.first(form) affirm(isinstance(bindings, PersistentVector), u"Loop bindings must be a vector") body = rt.next(form) ctx.enable_tail_call() ctc = ctx.can_tail_call ctx.disable_tail_call() binding_count = 0 for i in range(0, rt.count(bindings), 2): binding_count += 1 name = rt.nth(bindings, rt.wrap(i)) affirm(isinstance(name, symbol.Symbol), u"Loop bindings must be symbols") bind = rt.nth(bindings, rt.wrap(i + 1)) compile_form(bind, ctx) ctx.add_local(rt.name(name), LetBinding(ctx.sp())) if ctc: ctx.enable_tail_call() ctx.push_recur_point(LoopRecurPoint(binding_count, ctx)) while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.pop_recur_point() ctx.bytecode.append(code.POP_UP_N) ctx.sub_sp(binding_count) ctx.bytecode.append(binding_count) ctx.pop_locals(binding_count)
def compile_loop(form, ctx): form = rt.next(form) bindings = rt.first(form) affirm(isinstance(bindings, PersistentVector), u"Loop bindings must be a vector") body = rt.next(form) ctc = ctx.can_tail_call ctx.disable_tail_call() binding_count = 0 for i in range(0, rt.count(bindings), 2): binding_count += 1 name = rt.nth(bindings, rt.wrap(i)) affirm(isinstance(name, symbol.Symbol), u"Loop must bindings must be symbols") bind = rt.nth(bindings, rt.wrap(i + 1)) compile_form(bind, ctx) ctx.add_local(rt.name(name), LetBinding(ctx.sp())) if ctc: ctx.enable_tail_call() ctx.push_recur_point(LoopRecurPoint(binding_count, ctx)) while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.pop_recur_point() ctx.bytecode.append(code.POP_UP_N) ctx.sub_sp(binding_count) ctx.bytecode.append(binding_count) ctx.pop_locals(binding_count)
def syntax_quote(form): if isinstance(form, Symbol): ret = rt.list(QUOTE, form) elif is_unquote(form): ret = rt.first(rt.next(form)) elif is_unquote_splicing(form): raise Exception("Unquote splicing not used inside list") elif rt.vector_QMARK_(form) is true: ret = rt.list(APPLY, CONCAT, SyntaxQuoteReader.expand_list(form)) elif rt.seq_QMARK_(form) is true: ret = rt.list(APPLY, LIST, rt.cons(CONCAT, SyntaxQuoteReader.expand_list(rt.seq(form)))) else: ret = rt.list(QUOTE, form) return ret
def _eq(self, obj): assert isinstance(self, PersistentHashSet) if self is obj: return true if not isinstance(obj, PersistentHashSet): return false if self._map._cnt != obj._map._cnt: return false seq = rt.seq(obj) while seq is not nil: if rt._contains_key(self, rt.first(seq)) is false: return false seq = rt.next(seq) return true
def maybe_oop_invoke(form): head = rt.first(form) if isinstance(rt.first(form), symbol.Symbol) and rt.name(head).startswith(".-"): postfix = rt.next(form) affirm( rt.count(postfix) == 1, u" Attribute lookups must only have one argument") subject = rt.first(postfix) kw = keyword(rt.name(head)[2:]) fn = symbol.symbol(u"pixie.stdlib/-get-attr") return create_from_list([fn, subject, kw]) elif isinstance(rt.first(form), symbol.Symbol) and rt.name(head).startswith("."): subject = rt.first(rt.next(form)) postfix = rt.next(rt.next(form)) form = cons(keyword(rt.name(head)[1:]), postfix) form = cons(subject, form) form = cons(symbol.symbol(u"pixie.stdlib/-call-method"), form) return form else: return form
def _eq(self, obj): if self is obj: return true elif isinstance(obj, PersistentVector): if self._cnt != obj._cnt: return false for i in range(0, intmask(self._cnt)): if not rt.eq(self.nth(i), obj.nth(i)): return false return true else: if not rt.satisfies_QMARK_(proto.ISeqable, obj): return false seq = rt.seq(obj) for i in range(0, intmask(self._cnt)): if seq is nil or not rt.eq(self.nth(i), rt.first(seq)): return false seq = rt.next(seq) if seq is not nil: return false return true
def _eq(self, obj): assert isinstance(self, PersistentVector) if self is obj: return true elif isinstance(obj, PersistentVector): if self._cnt != obj._cnt: return false for i in range(0, intmask(self._cnt)): if not rt.eq(self.nth(i), obj.nth(i)): return false return true else: if obj is nil or not rt.satisfies_QMARK_(proto.ISeqable, obj): return false seq = rt.seq(obj) for i in range(0, intmask(self._cnt)): if seq is nil or not rt.eq(self.nth(i), rt.first(seq)): return false seq = rt.next(seq) if seq is not nil: return false return true
def compile_cons(form, ctx): if isinstance(form, EmptyList): ctx.push_const(form) return if isinstance(rt.first(form), symbol.Symbol): special = compiler_special(rt.first(form)) if special is not None: return special(form, ctx) macro = is_macro_call(form, ctx) if macro: return compile_form(call_macro(macro, form, ctx), ctx) meta = rt.meta(form) cnt = 0 ctc = ctx.can_tail_call while form is not nil: ctx.disable_tail_call() compile_form(rt.first(form), ctx) cnt += 1 form = rt.next(form) if ctc: ctx.enable_tail_call() #if ctx.can_tail_call: # ctx.bytecode.append(code.TAIL_CALL) #else: if meta is not nil: ctx.debug_points[len(ctx.bytecode)] = rt.interpreter_code_info(meta) ctx.bytecode.append(code.INVOKE) ctx.bytecode.append(cnt) ctx.sub_sp(r_uint(cnt - 1))
def compile_quote(form, ctx): data = rt.first(rt.next(form)) ctx.push_const(data) if rt.meta(form) is not nil: compile_meta(rt.meta(form), ctx)
def compile_in_ns(form, ctx): affirm(rt.count(form) == 2, u"in-ns requires an argument") arg = rt.first(rt.next(form)) NS_VAR.set_value(code._ns_registry.find_or_make(rt.name(arg))) NS_VAR.deref().include_stdlib() compile_fn_call(form, ctx)
def flatten_map_rfn(ret, item): return rt.conj(rt.conj(ret, rt.first(item)), rt.first(rt.next(item)))
def pop_binding_frame(self): self._vars = rt.next(self._vars)
def _next(self): assert isinstance(self, LazySeq) rt.seq(self) return rt.next(self._s)
def compile_quote(form, ctx): data = rt.first(rt.next(form)) ctx.push_const(data)
def compile_yield(form, ctx): affirm(rt.count(form) == 2, u"yield takes a single argument") arg = rt.first(rt.next(form)) compile_form(arg, ctx) ctx.bytecode.append(code.YIELD)