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. """ self.require_active() 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 CompilerException(msg) try: return dispatch(source_obj, tc, cont or self._compile_cont) except (CompilerException, SibilantSyntaxError): # these two should be propogated unchanged raise except Exception as ex: raise UncaughtCompilerException(ex, source_obj)
def test_symbol(self): x = symbol('x') y = symbol('x') z = symbol(x) self.assertTrue(is_symbol(x)) self.assertIsInstance(x, symbol) self.assertEqual(x, x) self.assertEqual(x, y) self.assertEqual(x, z) self.assertEqual(y, x) self.assertEqual(y, y) self.assertEqual(y, z) self.assertEqual(z, x) self.assertEqual(z, y) self.assertEqual(z, z) self.assertEqual(id(x), id(y)) self.assertEqual(id(y), id(z)) self.assertTrue(x is y) self.assertTrue(y is z) w = symbol('w') self.assertNotEqual(x, w) self.assertNotEqual(w, x) self.assertFalse(x is w)
def test_symbol(self): x = symbol('x') y = symbol('x') z = symbol(x) self.assertTrue(is_symbol(x)) self.assertIsInstance(x, symbol) self.assertEqual(x, x) self.assertEqual(x, y) self.assertEqual(x, z) self.assertEqual(y, x) self.assertEqual(y, y) self.assertEqual(y, z) self.assertEqual(z, x) self.assertEqual(z, y) self.assertEqual(z, z) self.assertEqual(id(x), id(y)) self.assertEqual(id(y), id(z)) self.assertTrue(x is y) self.assertTrue(y is z) w = symbol('w') self.assertNotEqual(x, w) self.assertNotEqual(w, x) self.assertFalse(x is w)
def find_expander(self, source_obj, env=None): """ Find an expander function for the given source obj in the specified environment. """ env = self.env if env is None else env if not isinstance(env, Mapping): env = vars(env) expander = None if source_obj is nil: return None elif is_symbol(source_obj): namesym = source_obj found = self.find_compiled(namesym, env) if is_alias(found): expander = found.expand elif is_proper(source_obj): namesym, params = source_obj if is_symbol(namesym): found = self.find_compiled(namesym, env) if is_alias(found): def expander(): expanded = cons(found.expand(), params) expanded.set_position(source_obj.get_position()) return expanded elif is_macro(found): if found._proper: # FIXME: this is some garbage right here. we need # to make sure macros aren't being invoked this # way with a variadic. position = params.get_position() args, kwargs = simple_parameters(params, position) expander = partial(found.expand, *args, **kwargs) else: expander = partial(found.expand, *params.unpack()) return expander
def find_expander(self, source_obj, env=None): """ Find an expander function for the given source obj in the specified environment. """ env = self.env if env is None else env if not isinstance(env, Mapping): env = vars(env) expander = None if source_obj is nil: return None elif is_symbol(source_obj): namesym = source_obj found = self.find_compiled(namesym, env) if is_alias(found): expander = found.expand elif is_proper(source_obj): namesym, params = source_obj if is_symbol(namesym): found = self.find_compiled(namesym, env) if is_alias(found): def expander(): expanded = cons(found.expand(), params) expanded.set_position(source_obj.get_position()) return expanded elif is_macro(found): if found._proper: # FIXME: this is some garbage right here. we need # to make sure macros aren't being invoked this # way with a variadic. position = params.get_position() args, kwargs = simple_parameters(params, position) expander = partial(found.expand, *args, **kwargs) else: expander = partial(found.expand, *params.unpack()) return expander
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_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_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_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(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 gather_formals(args, declared_at=None, filename=None): """ parses formals pair args into five values: (positional, keywords, defaults, stararg, starstararg) - positional is a list of symbols defining positional arguments - defaults is a list of keywords and expr pairs defining keyword arguments and their default value expression - kwonly is a list of keywords and expr pairs which are keyword-only arguments and theid default value expression - stararg is a symbol for variadic positional arguments - starstararg is a symbol for variadic keyword arguments """ undefined = object() err = partial(SibilantSyntaxError, location=declared_at, filename=filename) if is_symbol(args): return ((), (), (), args, None) elif isinstance(args, (list, tuple)): improper = False args = cons(*args, nil) elif is_proper(args): improper = False elif is_pair(args): improper = True else: raise err("formals must be symbol or pair, not %r" % args) positional = [] iargs = iter(args.unpack()) for arg in iargs: if is_keyword(arg): if improper: raise err("cannot mix improper formal with keywords") else: break elif is_symbol(arg) or is_lazygensym(arg): positional.append(arg) else: raise err("positional formals must be symbols, not %r" % arg) else: # handled all of args, done deal. if improper: return (positional[:-1], (), (), positional[-1], None) else: return (positional, (), (), None, None) defaults = [] kwonly = [] while arg not in (_keyword_star, _keyword_starstar): value = next(iargs, undefined) if value is undefined: raise err("missing value for keyword formal %s" % args) else: defaults.append((arg, value)) arg = next(iargs, undefined) if arg is undefined: break elif is_keyword(arg): continue else: raise err("keyword formals must be alternating keywords and" " values, not %r" % arg) star = None starstar = None if arg is undefined: return (positional, defaults, kwonly, None, None) if arg is _keyword_star: star = next(iargs, undefined) if star is undefined: raise err("* keyword requires symbol binding") elif star is nil: # nil means an ignored star arg, this is allowed. pass elif not (is_symbol(star) or is_lazygensym(star)): raise err("* keyword requires symbol binding, not %r" % star) arg = next(iargs, undefined) if arg is undefined: return (positional, defaults, kwonly, star, starstar) # while is_symbol(arg): # kwonly.append(arg) # arg = next(iargs, undefined) # # if arg is undefined: # return (positional, defaults, kwonly, star, starstar) if not is_keyword(arg): raise err("expected keyword in formals, got %r" % arg) # keyword formals after *: are considered keyword-only while arg not in (_keyword_star, _keyword_starstar): value = next(iargs, undefined) if value is undefined: raise err("missing value for keyword-only formal %s" % arg) else: kwonly.append((arg, value)) arg = next(iargs, undefined) if arg is undefined: break elif is_keyword(arg): continue else: raise err("keyword-only formals must be alternating keywords" " and values, not %r" % arg) if arg is _keyword_starstar: starstar = next(iargs, undefined) if starstar is undefined: raise err("** keyword requires symbol binding") elif not (is_symbol(starstar) or is_lazygensym(starstar)): raise err("** keyword requires symbol binding, not %r" % star) arg = next(iargs, undefined) if arg is not undefined: raise err("leftover formals %r" % arg) return (positional, defaults, kwonly, star, starstar)
def gather_parameters(args, declared_at=None, filename=None): """ parses parameter args into five values: (positional, keywords, values, stararg, starstararg) - positional is a list of expressions for positional arguments - keywords is a list of keywords defining keyword arguments - values is a list of expressions defining values for keywords - stararg is a symbol for variadic positional expression - starstararg is a symbol for variadic keyword expression """ undefined = object() def err(msg): return SibilantSyntaxError(msg, location=declared_at, filename=filename) if is_symbol(args) or is_lazygensym(args): return ((), (), (), args, None) elif isinstance(args, (list, tuple)): improper = False args = cons(*args, nil) if args else nil elif is_proper(args): improper = False elif is_pair(args): improper = True else: raise err("parameters must be symbol or pair, not %r" % args) positional = [] iargs = iter(args.unpack()) for arg in iargs: if is_keyword(arg): break else: positional.append(arg) else: # handled all of args, done deal. if improper: return (positional[:-1], (), (), positional[-1], None) else: return (positional, (), (), None, None) keywords = [] defaults = [] while arg not in (_keyword_star, _keyword_starstar): keywords.append(arg) value = next(iargs, undefined) if value is undefined: raise err("missing value for keyword parameter %s" % arg) else: defaults.append(value) arg = next(iargs, undefined) if arg is undefined: break elif is_keyword(arg): continue else: raise err("keyword parameters must be alternating keywords and" " values, not %r" % arg) star = None starstar = None if arg is undefined: return (positional, keywords, defaults, None, None) if arg is _keyword_star: star = next(iargs, undefined) if star is undefined: raise err("* keyword parameter needs value") arg = next(iargs, undefined) if arg is _keyword_starstar: starstar = next(iargs, undefined) if starstar is undefined: raise err("** keyword parameter needs value") arg = next(iargs, undefined) if arg is not undefined: raise err("leftover parameters %r" % arg) return (positional, keywords, defaults, star, starstar)
def gather_formals(args, declared_at=None, filename=None): """ parses formals pair args into five values: (positional, keywords, defaults, stararg, starstararg) - positional is a list of symbols defining positional arguments - defaults is a list of keywords and expr pairs defining keyword arguments and their default value expression - kwonly is a list of keywords and expr pairs which are keyword-only arguments and theid default value expression - stararg is a symbol for variadic positional arguments - starstararg is a symbol for variadic keyword arguments """ undefined = object() err = partial(SibilantSyntaxError, location=declared_at, filename=filename) if is_symbol(args): return ((), (), (), args, None) elif isinstance(args, (list, tuple)): improper = False args = cons(*args, nil) elif is_proper(args): improper = False elif is_pair(args): improper = True else: raise err("formals must be symbol or pair, not %r" % args) positional = [] iargs = iter(args.unpack()) for arg in iargs: if is_keyword(arg): if improper: raise err("cannot mix improper formal with keywords") else: break elif is_symbol(arg) or is_lazygensym(arg): positional.append(arg) else: raise err("positional formals must be symbols, nor %r" % arg) else: # handled all of args, done deal. if improper: return (positional[:-1], (), (), positional[-1], None) else: return (positional, (), (), None, None) defaults = [] kwonly = [] while arg not in (_keyword_star, _keyword_starstar): value = next(iargs, undefined) if value is undefined: raise err("missing value for keyword formal %s" % args) else: defaults.append((arg, value)) arg = next(iargs, undefined) if arg is undefined: break elif is_keyword(arg): continue else: raise err("keyword formals must be alternating keywords and" " values, not %r" % arg) star = None starstar = None if arg is undefined: return (positional, defaults, kwonly, None, None) if arg is _keyword_star: star = next(iargs, undefined) if star is undefined: raise err("* keyword requires symbol binding") elif star is nil: # nil means an ignored star arg, this is allowed. pass elif not (is_symbol(star) or is_lazygensym(star)): raise err("* keyword requires symbol binding, not %r" % star) arg = next(iargs, undefined) if arg is undefined: return (positional, defaults, kwonly, star, starstar) # while is_symbol(arg): # kwonly.append(arg) # arg = next(iargs, undefined) # # if arg is undefined: # return (positional, defaults, kwonly, star, starstar) if not is_keyword(arg): raise err("expected keyword in formals, got %r" % arg) # keyword formals after *: are considered keyword-only while arg not in (_keyword_star, _keyword_starstar): value = next(iargs, undefined) if value is undefined: raise err("missing value for keyword-only formal %s" % arg) else: kwonly.append((arg, value)) arg = next(iargs, undefined) if arg is undefined: break elif is_keyword(arg): continue else: raise err("keyword-only formals must be alternating keywords" " and values, not %r" % arg) if arg is _keyword_starstar: starstar = next(iargs, undefined) if starstar is undefined: raise err("** keyword requires symbol binding") elif not (is_symbol(starstar) or is_lazygensym(starstar)): raise err("** keyword requires symbol binding, not %r" % star) arg = next(iargs, undefined) if arg is not undefined: raise err("leftover formals %r" % arg) return (positional, defaults, kwonly, star, starstar)
def gather_parameters(args, declared_at=None, filename=None): """ parses parameter args into five values: (positional, keywords, values, stararg, starstararg) - positional is a list of expressions for positional arguments - keywords is a list of keywords defining keyword arguments - values is a list of expressions defining values for keywords - stararg is a symbol for variadic positional expression - starstararg is a symbol for variadic keyword expression """ undefined = object() def err(msg): return SibilantSyntaxError(msg, location=declared_at, filename=filename) if is_symbol(args) or is_lazygensym(args): return ((), (), (), args, None) elif isinstance(args, (list, tuple)): improper = False args = cons(*args, nil) if args else nil elif is_proper(args): improper = False elif is_pair(args): improper = True else: raise err("parameters must be symbol or pair, not %r" % args) positional = [] iargs = iter(args.unpack()) for arg in iargs: if is_keyword(arg): break else: positional.append(arg) else: # handled all of args, done deal. if improper: return (positional[:-1], (), (), positional[-1], None) else: return (positional, (), (), None, None) keywords = [] defaults = [] while arg not in (_keyword_star, _keyword_starstar): keywords.append(arg) value = next(iargs, undefined) if value is undefined: raise err("missing value for keyword parameter %s" % arg) else: defaults.append(value) arg = next(iargs, undefined) if arg is undefined: break elif is_keyword(arg): continue else: raise err("keyword parameters must be alternating keywords and" " values, not %r" % arg) star = None starstar = None if arg is undefined: return (positional, keywords, defaults, None, None) if arg is _keyword_star: star = next(iargs, undefined) if star is undefined: raise err("* keyword parameter needs value") arg = next(iargs, undefined) if arg is _keyword_starstar: starstar = next(iargs, undefined) if starstar is undefined: raise err("** keyword parameter needs value") arg = next(iargs, undefined) if arg is not undefined: raise err("leftover parameters %r" % arg) return (positional, keywords, defaults, star, starstar)