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 find_compiled(self, namesym: Symbol, env=None): """ Search for and return a Compiled instance within the activated environment for this compiler. Returns None if nothing was found. """ env = self.env if env is None else env # self.require_active() if is_lazygensym(namesym): # I might make this work some day, with macrolet, but for # now ... no. return None for tmp_env in reversed(self.env_tmp_compiled): if namesym in tmp_env: return tmp_env[namesym] else: return env_find_compiled(env, namesym)
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_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)