def compile_apply(self, source_obj: pair, tc, cont): """ Compile a runtime function apply expression. """ tc = tc and self.tco_enabled and not self.generator head, tail = source_obj if tc and self.self_ref and \ is_symbol(head) and (str(head) == self.name): return tcf(self.compile_tcr_apply, source_obj, tc, cont) pos = source_obj.get_position() if is_pair(head): # @trampoline def ccp(new_head, tc): # Continue Compiling Pair. This is how we finish # compiling a function invocation after first # compiling the head if new_head is None: # the original head pair compiled down to a None, # which means it pushed bytecode and left a value # on the stack. Complete the apply based on that. return tcf(self.complete_apply, tail, pos, tc, cont) else: # the original head pair was transformed, so now # we need to start over in a new compile_pair call # using a newly assembled expression. expr = pair(new_head, tail) expr.set_position(pos) return tcf(self.compile_pair, expr, tc, cont) # we need to compile the head first, to figure out if it # expands into a symbolic reference or something. We'll # use ccp as a temporary continuation. Note that the # evaluation of the head of the pair is never a tailcall # itself, even if it would be a tailcall to apply it as a # function afterwards. return tcf(self.compile_pair, head, False, ccp) elif tc: self.declare_tailcall() self.pseudop_get_global(_symbol_tailcall_full) return tcf(self.complete_apply, source_obj, pos, False, cont) else: self.add_expression(head) return tcf(self.complete_apply, tail, pos, tc, cont)
def compile_keyword(self, kwd: keyword, tc, cont): """ Compile a keyword expression """ source = cons(_symbol_keyword, str(kwd), nil) return tcf(self.compile, source, False, cont)
def ccp(new_head, tc): # Continue Compiling Pair. This is how we finish # compiling a function invocation after first # compiling the head if new_head is None: # the original head pair compiled down to a None, # which means it pushed bytecode and left a value # on the stack. Complete the apply based on that. return tcf(self.complete_apply, tail, pos, tc, cont) else: # the original head pair was transformed, so now # we need to start over in a new compile_pair call # using a newly assembled expression. expr = pair(new_head, tail) expr.set_position(pos) return tcf(self.compile_pair, expr, tc, cont)
def compile(self, compiler, source_obj, tc, cont): expanded = self.expand() expanded = _symbol_None if expanded is None else expanded if is_pair(source_obj): called_by, source = source_obj res = cons(expanded, source) fill_position(res, source_obj.get_position()) expanded = res return tcf(cont, expanded, tc)
def complete_tcr_apply(self, cont): # print("completing a tcr apply") non_tcr = self.gen_label() self.pseudop_jump_if_true_or_pop(non_tcr) self.pseudop_jump(0) self.pseudop_label(non_tcr) self.pseudop_unpack_sequence(1) self.declare_tailcall() return tcf(cont, None, False)
def compile_tcr_apply(self, source_obj: pair, tc, cont): assert tc # print("compiling a tcr apply", source_obj) pos = source_obj.get_position() maybe = self.helper_inline_tcr(source_obj) if maybe: fun, args = source_obj return tcf(self.complete_apply, args, pos, True, cont) else: def ccp(done_source, tc): assert done_source is None return tcf(self.complete_tcr_apply, cont) tcr_source = cons(self.self_ref, source_obj) tcr_source.set_position(pos) self.pseudop_get_global(_symbol_tcr_frame) return tcf(self.complete_apply, tcr_source, pos, False, ccp)
def compile_pair(self, source_obj: pair, tc, cont): """ Compile a pair expression. This will become either a literal nil, a macro expansion, a special invocation, or a runtime function application. """ if is_nil(source_obj): return tcf(self.compile_nil, source_obj, tc, cont) if not is_proper(source_obj): # print("** WUT", self, source_obj, tc, cont) msg = "cannot evaluate improper lists as expressions" raise self.error(msg, source_obj) self.pseudop_position_of(source_obj) head, tail = source_obj if is_symbol(head) or is_lazygensym(head): comp = self.find_compiled(head) if comp: # the head of the pair is a symbolic reference which # resolved to a compile-time object. Invoke that. return tcf(comp.compile, self, source_obj, tc, cont) else: return tcf(self.compile_apply, source_obj, tc, cont) elif is_pair(head): return tcf(self.compile_apply, source_obj, tc, cont) else: # TODO: should this be a compile-time error? If we have # something that isn't a symbolic reference or isn't a # pair, then WTF else would it be? Let's just let it break # at runtime, for now. return tcf(self.compile_apply, source_obj, tc, cont)
def _compile_cont(self, source_obj, tc): """ The default continuation for compile. If the result was a new source object (anything other than None), will restart the compile. """ if source_obj is None: # None explicitly means that the compilation resulted in # no new forms, so we're done. return None else: # anything else is a transformation, and needs to be # compiled. return tcf(self.compile, source_obj, tc, None)
def compile(self, compiler, source_obj, tc, cont): called_by, source = source_obj if self._proper: position = source_obj.get_position() args, kwargs = simple_parameters(source, position) expr = self.expand(*args, **kwargs) else: expr = self.expand(*source.unpack()) expr = _symbol_None if expr is None else expr fill_position(expr, source_obj.get_position()) return tcf(cont, expr, tc)
def compile_symbol(self, sym: Symbol, tc, cont): """ Compile a symbol expression. This can result in a constant for certain specialty Python values (None, True, False, and ...) Dotted symbols will be compiled into attr calls. Non-dotted symbols will be compiled into variable references. If a symbol correlates to an Alias in the module namespace, then that alias will be expanded and compilation will continue from the expanded form. """ comp = self.find_compiled(sym) if comp and is_alias(comp): return tcf(comp.compile, self, sym, tc, cont) elif sym is _symbol_None: return tcf(self.compile_constant, None, tc, cont) elif sym is _symbol_True: return tcf(self.compile_constant, True, tc, cont) elif sym is _symbol_False: return tcf(self.compile_constant, False, tc, cont) elif sym is _symbol_ellipsis: return tcf(self.compile_constant, ..., tc, cont) elif is_lazygensym(sym): return tcf(cont, self.pseudop_get_var(sym), tc) else: ex = sym.rsplit(".", 1) if len(ex) == 1: return tcf(cont, self.pseudop_get_var(sym), None) else: source = cons(_symbol_attr, *ex, nil) return tcf(self.compile, source, tc, cont)
def compile(self, compiler, source_obj, tc, cont): called_by, source = source_obj if self._proper: position = source_obj.get_position() args, kwargs = simple_parameters(source, position) try: expr = self.expand(*args, **kwargs) except Exception as exc: work = MacroException(self.__name__, exc) work = work.with_traceback(exc.__traceback__) raise work from None else: expr = self.expand(*source.unpack()) expr = _symbol_None if expr is None else expr fill_position(expr, source_obj.get_position()) return tcf(cont, expr, tc)
def compile(self, source_obj, tc, cont): """ Compile a supported source object into an expression. pair, symbol, keyword, and the pythonic constant types are valid source obj types. """ tc = self.tco_enabled and tc if is_pair(source_obj): dispatch = self.compile_pair elif is_symbol(source_obj) or is_lazygensym(source_obj): dispatch = self.compile_symbol elif is_keyword(source_obj): dispatch = self.compile_keyword elif isinstance(source_obj, CONST_TYPES): dispatch = self.compile_constant else: msg = "Unsupported source object %r" % source_obj raise self.error(msg, source_obj) return tcf(dispatch, source_obj, tc, cont or self._compile_cont)
def compile_constant(self, value: Constant, tc, cont): """ Compile a constant value expression """ return tcf(cont, self.pseudop_const(value), tc)
def compile(self, compiler, source_obj, tc, cont): result = self.compile_impl(compiler, source_obj, tc) return tcf(cont, result, tc)
def ccp(done_source, tc): assert done_source is None return tcf(self.complete_tcr_apply, cont)
def compile_nil(self, nilv: nil, tc, cont): """ Compile a literal nil expression """ return tcf(cont, self.pseudop_get_global(_symbol_nil), tc)