import random<EOL>random.seed(<NUM_LIT>)<EOL>filtered = b.filter(lambda x: False)<EOL>res = filtered.toarray()<EOL>assert res.shape == (<NUM_LIT:0>,)<EOL>filtered = b.filter(lambda x: True)<EOL>res = filtered.toarray()<EOL>assert res.shape == b.shape<EOL>def filter_half(x):<EOL><INDENT>random.seed(x.tostring())<EOL>return random.random()<EOL><DEDENT>filtered = b.filter(lambda x: filter_half(x) < <NUM_LIT:0.5>)<EOL>res = filtered.toarray()<EOL>assert res.shape[<NUM_LIT:1>:] == b.shape[<NUM_LIT:1>:]<EOL>assert res.shape[<NUM_LIT:0>] <= b.shape[<NUM_LIT:0>]<EOL>if not b.mode == "<STR_LIT>":<EOL><INDENT>filtered = b.filter(lambda x: filter_half(x) < <NUM_LIT:0.5>, sort=True)<EOL>res = filtered.toarray()<EOL>assert res.shape[<NUM_LIT:1>:] == b.shape[<NUM_LIT:1>:]<EOL>assert res.shape[<NUM_LIT:0>] <= b.shape[<NUM_LIT:0>]<EOL><DEDENT>filtered = b.filter(lambda x: filter_half(x) < <NUM_LIT:0.5>, axis=<NUM_LIT:1>)<EOL>res = filtered.toarray()<EOL>assert res.shape[<NUM_LIT:0>] <= b.shape[<NUM_LIT:1>]<EOL>assert res.shape[<NUM_LIT:1>] == b.shape[<NUM_LIT:0>]<EOL>assert res.shape[<NUM_LIT:2>] == b.shape[<NUM_LIT:2>]<EOL>filtered = b.filter(lambda x: filter_half(x) < <NUM_LIT:0.5>, axis=<NUM_LIT:2>)<EOL>res = filtered.toarray()<EOL>assert res.shape[<NUM_LIT:0>] <= b.shape[<NUM_LIT:2>]<EOL>assert res.shape[<NUM_LIT:1>] == b.shape[<NUM_LIT:0>]<EOL>assert res.shape[<NUM_LIT:2>] == b.shape[<NUM_LIT:1>]<EOL>filtered = b.filter(lambda x: False, axis=(<NUM_LIT:0>, <NUM_LIT:1>))<EOL>res = filtered.toarray()<EOL>assert res.shape == (<NUM_LIT:0>,)<EOL>filtered = b.filter(lambda x: True)<EOL>res = filtered.toarray()<EOL>assert res.shape == b.shape<EOL>filtered = b.filter(lambda x: filter_half(x) < <NUM_LIT:0.5>, axis=(<NUM_LIT:0>, <NUM_LIT:1>))<EOL>res = filtered.toarray()<EOL>assert res.shape[<NUM_LIT:0>] <= b.shape[<NUM_LIT:0>]*b.shape[<NUM_LIT:1>]<EOL>assert res.shape[<NUM_LIT:1>] == b.shape[<NUM_LIT:2>]<EOL>

A set of tests for the filter operator

Parameters
----------
arr: `ndarray`
    A 3D ndarray used in the construction of `b` (used to check results)
b: `BoltArray`
    The BoltArray to be used for testing


if options is not None:<EOL><INDENT>args = argumentsParser.parse_args(options)<EOL><DEDENT>else:<EOL><INDENT>args = argumentsParser.parse_args()<EOL><DEDENT>return args<EOL>


for i in range(<NUM_LIT:0>, len(l), n):<EOL><INDENT>yield l[i:i + n]<EOL><DEDENT>


@_convert_f_to_seqs(<NUM_LIT:2>)<EOL>def floyd(seqs, f=None, start=None, key=lambda x: x):

tortise, hare = seqs<EOL>yield hare.next()<EOL>tortise_value = tortise.next()<EOL>hare_value = hare.next()<EOL>while hare_value != tortise_value:<EOL><INDENT>yield hare_value<EOL>yield hare.next()<EOL>hare_value = hare.next()<EOL>tortise_value = tortise.next()<EOL><DEDENT>if f is None:<EOL><INDENT>raise CycleDetected()<EOL><DEDENT>hare_value = f(hare_value)<EOL>first = <NUM_LIT:0><EOL>tortise_value = start<EOL>while key(tortise_value) != key(hare_value):<EOL><INDENT>tortise_value = f(tortise_value)<EOL>hare_value = f(hare_value)<EOL>first += <NUM_LIT:1><EOL><DEDENT>period = <NUM_LIT:1><EOL>hare_value = f(tortise_value)<EOL>while key(tortise_value) != key(hare_value):<EOL><INDENT>hare_value = f(hare_value)<EOL>period += <NUM_LIT:1><EOL><DEDENT>raise CycleDetected(period=period, first=first)<EOL>

Floyd's Cycle Detector.

    See help(cycle_detector) for more context.

    Args:

      *args: Two iterators issueing the exact same sequence:
      -or-
      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found; if called with f and `start`,
      the parametres `first` and `period` will be defined indicating
      the offset of start of the cycle and the cycle's period.


@_convert_f_to_seqs(<NUM_LIT:1>)<EOL>def naive(seqs, f=None, start=None, key=lambda x: x):

history = {}<EOL>for step, value in enumerate(seqs[<NUM_LIT:0>]):<EOL><INDENT>keyed = key(value)<EOL>yield value<EOL>if keyed in history:<EOL><INDENT>raise CycleDetected(<EOL>first=history[keyed], period=step - history[keyed])<EOL><DEDENT>history[keyed] = step<EOL><DEDENT>

Naive cycle detector

    See help(cycle_detector) for more context.

    Args:

      sequence: A sequence to detect cyles in.

      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found.  Will always generate a first
      and period value no matter which of the `seqs` or `f` interface
      is used.


@_convert_f_to_seqs(<NUM_LIT:1>)<EOL>def gosper(seqs, f=None, start=None, key=lambda x: x):

tab = []<EOL>for c, value in enumerate(seqs[<NUM_LIT:0>], start=<NUM_LIT:1>):<EOL><INDENT>yield value<EOL>try:<EOL><INDENT>e = tab.index(key(value))<EOL>raise CycleDetected(<EOL>period=c - ((((c >> e) - <NUM_LIT:1>) | <NUM_LIT:1>) << e))<EOL><DEDENT>except ValueError:<EOL><INDENT>try:<EOL><INDENT>tab[(c ^ (c - <NUM_LIT:1>)).bit_length() - <NUM_LIT:1>] = key(value)<EOL><DEDENT>except IndexError:<EOL><INDENT>tab.append(value)<EOL><DEDENT><DEDENT><DEDENT>

Gosper's cycle detector

    See help(cycle_detector) for more context.

    Args:

      sequence: A sequence to detect cyles in.

      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found.  Unlike Floyd and Brent's,
      Gosper's can only detect period of a cycle.  It cannot
      compute the first position


@_convert_f_to_seqs(<NUM_LIT:2>)<EOL>def brent(seqs, f=None, start=None, key=lambda x: x):

power = period = <NUM_LIT:1><EOL>tortise, hare = seqs<EOL>yield hare.next()<EOL>tortise_value = tortise.next()<EOL>hare_value = hare.next()<EOL>while key(tortise_value) != key(hare_value):<EOL><INDENT>yield hare_value<EOL>if power == period:<EOL><INDENT>power *= <NUM_LIT:2><EOL>period = <NUM_LIT:0><EOL>if f:<EOL><INDENT>tortise = f_generator(f, hare_value)<EOL>tortise_value = tortise.next()<EOL><DEDENT>else:<EOL><INDENT>while tortise_value != hare_value:<EOL><INDENT>tortise_value = tortise.next()<EOL><DEDENT><DEDENT><DEDENT>hare_value = hare.next()<EOL>period += <NUM_LIT:1><EOL><DEDENT>if f is None:<EOL><INDENT>raise CycleDetected()<EOL><DEDENT>first = <NUM_LIT:0><EOL>tortise_value = hare_value = start<EOL>for _ in xrange(period):<EOL><INDENT>hare_value = f(hare_value)<EOL><DEDENT>while key(tortise_value) != key(hare_value):<EOL><INDENT>tortise_value = f(tortise_value)<EOL>hare_value = f(hare_value)<EOL>first += <NUM_LIT:1><EOL><DEDENT>raise CycleDetected(period=period, first=first)<EOL>

Brent's Cycle Detector.

    See help(cycle_detector) for more context.

    Args:

      *args: Two iterators issueing the exact same sequence:
      -or-
      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found; if called with f and `start`,
      the parametres `first` and `period` will be defined indicating
      the offset of start of the cycle and the cycle's period.


progname = os.path.join(_dir_, '<STR_LIT>')<EOL>cmd = [sys.executable, progname]<EOL>if self.verbose == <NUM_LIT:0>:<EOL><INDENT>cmd.append('<STR_LIT>')<EOL><DEDENT>elif self.verbose >= <NUM_LIT:2>:<EOL><INDENT>cmd.append('<STR_LIT>')<EOL><DEDENT>if self.tests:<EOL><INDENT>cmd.extend(self.tests)<EOL><DEDENT>retcode = subprocess.call(cmd)<EOL>if retcode != <NUM_LIT:0>:<EOL><INDENT>sys.exit(retcode)<EOL><DEDENT>

Run test/tests.py and quit with exit status


@classmethod<EOL><INDENT>def mask(cls, dt, **options):<DEDENT>

raise NotImplemented<EOL>

Return a datetime with the same value as ``dt``, keeping only
significant values.


@classmethod<EOL><INDENT>def start(cls, now, number, **options):<DEDENT>

return (cls.mask(now, **options) -<EOL>timedelta(**{cls.__name__.lower(): number - <NUM_LIT:1>}))<EOL>

Return the starting datetime: ``number`` of units before ``now``.


@classmethod<EOL><INDENT>def filter(cls, datetimes, number, now=None, **options):<DEDENT>

if not isinstance(number, int) or number < <NUM_LIT:0>:<EOL><INDENT>raise ValueError('<STR_LIT>' % number)<EOL><DEDENT>datetimes = tuple(datetimes)<EOL>tzinfo = None<EOL>if datetimes and datetimes[<NUM_LIT:0>].tzinfo is not None:<EOL><INDENT>tzinfo = UTC()<EOL><DEDENT>if now is None:<EOL><INDENT>now = datetime.now(tzinfo)<EOL><DEDENT>if not hasattr(now, '<STR_LIT>'):<EOL><INDENT>now = datetime.combine(now, time(<NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, tzinfo=tzinfo))<EOL><DEDENT>future = set(dt for dt in datetimes if dt > now)<EOL>if number == <NUM_LIT:0>:<EOL><INDENT>return future<EOL><DEDENT>start = cls.start(now, number, **options)<EOL>valid = (dt for dt in datetimes if start <= dt <= now)<EOL>kept = {}<EOL>for dt in sorted(valid):<EOL><INDENT>kept.setdefault(cls.mask(dt, **options), dt)<EOL><DEDENT>return set(kept.values()) | future<EOL>

Return a set of datetimes, after filtering ``datetimes``.

        The result will be the ``datetimes`` which are ``number`` of
        units before ``now``, until ``now``, with approximately one
        unit between each of them.  The first datetime for any unit is
        kept, later duplicates are removed.

        If there are ``datetimes`` after ``now``, they will be
        returned unfiltered.


return dt.replace(microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of seconds.


return dt.replace(second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of minutes.


return dt.replace(minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of hours.


return dt.replace(hour=<NUM_LIT:0>, minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of days.


@classmethod<EOL><INDENT>def start(cls, now, number, firstweekday=calendar.SATURDAY, **options):<DEDENT>

week = cls.mask(now, firstweekday=firstweekday, **options)<EOL>days = (number - <NUM_LIT:1>) * cls.DAYS_IN_WEEK<EOL>return week - timedelta(days=days)<EOL>

Return the starting datetime: ``number`` of weeks before ``now``.

``firstweekday`` determines when the week starts. It defaults
to Saturday.


@classmethod<EOL><INDENT>def mask(cls, dt, firstweekday=calendar.SATURDAY, **options):<DEDENT>

correction = (dt.weekday() - firstweekday) % cls.DAYS_IN_WEEK<EOL>week = dt - timedelta(days=correction)<EOL>return week.replace(hour=<NUM_LIT:0>, minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of weeks.

``firstweekday`` determines when the week starts. It defaults
to Saturday.


year = now.year<EOL>month = now.month - number + <NUM_LIT:1><EOL>if month < <NUM_LIT:0>:<EOL><INDENT>year = year + (month // cls.MONTHS_IN_YEAR)<EOL>month = month % cls.MONTHS_IN_YEAR<EOL><DEDENT>if month == <NUM_LIT:0>:<EOL><INDENT>year = year - <NUM_LIT:1><EOL>month = <NUM_LIT:12><EOL><DEDENT>return cls.mask(now, **options).replace(year=year, month=month)<EOL>

Return the starting datetime: ``number`` of months before ``now``.


return dt.replace(day=<NUM_LIT:1>,<EOL>hour=<NUM_LIT:0>, minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of months.


return cls.mask(now).replace(year=(now.year - number + <NUM_LIT:1>))<EOL>

Return the starting datetime: ``number`` of years before ``now``.


return dt.replace(month=<NUM_LIT:1>, day=<NUM_LIT:1>,<EOL>hour=<NUM_LIT:0>, minute=<NUM_LIT:0>, second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL>

Return a datetime with the same value as ``dt``, to a
resolution of years.


def to_keep(datetimes,<EOL>years=<NUM_LIT:0>, months=<NUM_LIT:0>, weeks=<NUM_LIT:0>, days=<NUM_LIT:0>,<EOL>hours=<NUM_LIT:0>, minutes=<NUM_LIT:0>, seconds=<NUM_LIT:0>,<EOL>firstweekday=SATURDAY, now=None):

datetimes = set(datetimes)<EOL>return (filters.Years.filter(datetimes, number=years, now=now) |<EOL>filters.Months.filter(datetimes, number=months, now=now) |<EOL>filters.Weeks.filter(datetimes, number=weeks,<EOL>firstweekday=firstweekday, now=now) |<EOL>filters.Days.filter(datetimes, number=days, now=now) |<EOL>filters.Hours.filter(datetimes, number=hours, now=now) |<EOL>filters.Minutes.filter(datetimes, number=minutes, now=now) |<EOL>filters.Seconds.filter(datetimes, number=seconds, now=now))<EOL>

Return a set of datetimes that should be kept, out of ``datetimes``.

Keeps up to ``years``, ``months``, ``weeks``, ``days``,
``hours``, ``minutes``, and ``seconds`` in the past.

When keeping weeks, it prefers to keep ``firstweekday``, which
defaults to Saturday.

If ``now`` is None, it will base its calculations on
``datetime.datetime.now()``. Datetimes after this point will always be
kept.


def to_delete(datetimes,<EOL>years=<NUM_LIT:0>, months=<NUM_LIT:0>, weeks=<NUM_LIT:0>, days=<NUM_LIT:0>,<EOL>hours=<NUM_LIT:0>, minutes=<NUM_LIT:0>, seconds=<NUM_LIT:0>,<EOL>firstweekday=SATURDAY, now=None):

datetimes = set(datetimes)<EOL>return datetimes - to_keep(datetimes,<EOL>years=years, months=months,<EOL>weeks=weeks, days=days,<EOL>hours=hours, minutes=minutes, seconds=seconds,<EOL>firstweekday=firstweekday, now=now)<EOL>

Return a set of datetimes that should be deleted, out of ``datetimes``.

See ``to_keep`` for a description of arguments.


def dates_to_keep(dates,<EOL>years=<NUM_LIT:0>, months=<NUM_LIT:0>, weeks=<NUM_LIT:0>, days=<NUM_LIT:0>, firstweekday=SATURDAY,<EOL>now=None):

datetimes = to_keep((datetime.combine(d, time()) for d in dates),<EOL>years=years, months=months, weeks=weeks, days=days,<EOL>hours=<NUM_LIT:0>, minutes=<NUM_LIT:0>, seconds=<NUM_LIT:0>,<EOL>firstweekday=firstweekday, now=now)<EOL>return set(dt.date() for dt in datetimes)<EOL>

Return a set of dates that should be kept, out of ``dates``.

See ``to_keep`` for a description of arguments.


def dates_to_delete(dates,<EOL>years=<NUM_LIT:0>, months=<NUM_LIT:0>, weeks=<NUM_LIT:0>, days=<NUM_LIT:0>, firstweekday=SATURDAY,<EOL>now=None):

dates = set(dates)<EOL>return dates - dates_to_keep(dates,<EOL>years=years, months=months,<EOL>weeks=weeks, days=days,<EOL>firstweekday=firstweekday, now=now)<EOL>

Return a set of date that should be deleted, out of ``dates``.

See ``to_keep`` for a description of arguments.


def lcompile(<EOL>s: str,<EOL>resolver: Optional[reader.Resolver] = None,<EOL>opts: Optional[Dict[str, bool]] = None,<EOL>mod: Optional[types.ModuleType] = None,<EOL>):

ctx = compiler.CompilerContext(COMPILER_FILE_PATH, opts=opts)<EOL>mod = Maybe(mod).or_else(lambda: runtime._new_module(COMPILER_FILE_PATH))<EOL>last = None<EOL>for form in reader.read_str(s, resolver=resolver):<EOL><INDENT>last = compiler.compile_and_exec_form(form, ctx, mod)<EOL><DEDENT>return last<EOL>

Compile and execute the code in the input string.

    Return the resulting expression.


def read_str_first(<EOL>s: str,<EOL>resolver: reader.Resolver = None,<EOL>data_readers=None,<EOL>is_eof_error: bool = False,<EOL>):

Read the first form from the input string. If no form
    is found, return None.


ctx = compiler.CompilerContext(COMPILER_FILE_PATH)<EOL>mod = runtime._new_module(COMPILER_FILE_PATH)<EOL>last = None<EOL>for form in reader.read_str(s):<EOL><INDENT>last = compiler.compile_and_exec_form(form, ctx, mod)<EOL><DEDENT>return last<EOL>


@contextlib.contextmanager<EOL>def timed(f: Optional[Callable[[int], None]] = None):

start = time.perf_counter()<EOL>yield<EOL>end = time.perf_counter()<EOL>if f:<EOL><INDENT>ns = int((end - start) * <NUM_LIT>)<EOL>f(ns)<EOL><DEDENT>

Time the execution of code in the with-block, calling the function
    f (if it is given) with the resulting time in nanoseconds.


assert n > <NUM_LIT:0><EOL>start = <NUM_LIT:0><EOL>stop = n<EOL>while stop <= len(coll):<EOL><INDENT>yield tuple(e for e in coll[start:stop])<EOL>start += n<EOL>stop += n<EOL><DEDENT>if start < len(coll) < stop:<EOL><INDENT>stop = len(coll)<EOL>yield tuple(e for e in coll[start:stop])<EOL><DEDENT>


return int.from_bytes(int_bytes, "<STR_LIT>")<EOL>

Convert 4 bytes in little-endian to an integer.


return (int(x) & <NUM_LIT>).to_bytes(<NUM_LIT:4>, "<STR_LIT>")<EOL>

Convert a 32-bit integer to little-endian.


def _basilisp_bytecode(<EOL>mtime: int, source_size: int, code: List[types.CodeType]<EOL>) -> bytes:

data = bytearray(MAGIC_NUMBER)<EOL>data.extend(_w_long(mtime))<EOL>data.extend(_w_long(source_size))<EOL>data.extend(marshal.dumps(code))  <EOL>return data<EOL>

Return the bytes for a Basilisp bytecode cache file.


def _get_basilisp_bytecode(<EOL>fullname: str, mtime: int, source_size: int, cache_data: bytes<EOL>) -> List[types.CodeType]:

exc_details = {"<STR_LIT:name>": fullname}<EOL>magic = cache_data[:<NUM_LIT:4>]<EOL>raw_timestamp = cache_data[<NUM_LIT:4>:<NUM_LIT:8>]<EOL>raw_size = cache_data[<NUM_LIT:8>:<NUM_LIT:12>]<EOL>if magic != MAGIC_NUMBER:<EOL><INDENT>message = (<EOL>f"<STR_LIT>"<EOL>)<EOL>logger.debug(message)<EOL>raise ImportError(message, **exc_details)  <EOL><DEDENT>elif len(raw_timestamp) != <NUM_LIT:4>:<EOL><INDENT>message = f"<STR_LIT>"<EOL>logger.debug(message)<EOL>raise EOFError(message)<EOL><DEDENT>elif _r_long(raw_timestamp) != mtime:<EOL><INDENT>message = f"<STR_LIT>"<EOL>logger.debug(message)<EOL>raise ImportError(message, **exc_details)  <EOL><DEDENT>elif len(raw_size) != <NUM_LIT:4>:<EOL><INDENT>message = f"<STR_LIT>"<EOL>logger.debug(message)<EOL>raise EOFError(message)<EOL><DEDENT>elif _r_long(raw_size) != source_size:<EOL><INDENT>message = f"<STR_LIT>"<EOL>logger.debug(message)<EOL>raise ImportError(message, **exc_details)  <EOL><DEDENT>return marshal.loads(cache_data[<NUM_LIT:12>:])<EOL>

Unmarshal the bytes from a Basilisp bytecode cache file, validating the
    file header prior to returning. If the file header does not match, throw
    an exception.


def _cache_from_source(path: str) -> str:

cache_path, cache_file = os.path.split(importlib.util.cache_from_source(path))<EOL>filename, _ = os.path.splitext(cache_file)<EOL>return os.path.join(cache_path, filename + "<STR_LIT>")<EOL>

Return the path to the cached file for the given path. The original path
    does not have to exist.


if any([isinstance(o, BasilispImporter) for o in sys.meta_path]):<EOL><INDENT>return<EOL><DEDENT>sys.meta_path.insert(<EOL><NUM_LIT:0>, BasilispImporter()  <EOL>)<EOL>

Hook into Python's import machinery with a custom Basilisp code
    importer.

    Once this is called, Basilisp code may be called from within Python code
    using standard `import module.submodule` syntax.


def find_spec(<EOL>self,<EOL>fullname: str,<EOL>path,  <EOL>target: types.ModuleType = None,<EOL>) -> Optional[importlib.machinery.ModuleSpec]:

package_components = fullname.split("<STR_LIT:.>")<EOL>if path is None:<EOL><INDENT>path = sys.path<EOL>module_name = package_components<EOL><DEDENT>else:<EOL><INDENT>module_name = [package_components[-<NUM_LIT:1>]]<EOL><DEDENT>for entry in path:<EOL><INDENT>filenames = [<EOL>f"<STR_LIT>",<EOL>f"<STR_LIT>",<EOL>]<EOL>for filename in filenames:<EOL><INDENT>if os.path.exists(filename):<EOL><INDENT>state = {<EOL>"<STR_LIT>": fullname,<EOL>"<STR_LIT:filename>": filename,<EOL>"<STR_LIT:path>": entry,<EOL>"<STR_LIT:target>": target,<EOL>"<STR_LIT>": _cache_from_source(filename),<EOL>}<EOL>logger.debug(<EOL>f"<STR_LIT>"<EOL>)<EOL>return importlib.machinery.ModuleSpec(<EOL>fullname, self, origin=filename, loader_state=state<EOL>)<EOL><DEDENT><DEDENT><DEDENT>return None<EOL>

Find the ModuleSpec for the specified Basilisp module.

        Returns None if the module is not a Basilisp module to allow import processing to continue.


def _exec_cached_module(<EOL>self,<EOL>fullname: str,<EOL>loader_state: Mapping[str, str],<EOL>path_stats: Mapping[str, int],<EOL>module: types.ModuleType,<EOL>):

filename = loader_state["<STR_LIT:filename>"]<EOL>cache_filename = loader_state["<STR_LIT>"]<EOL>with timed(<EOL>lambda duration: logger.debug(<EOL>f"<STR_LIT>"<EOL>)<EOL>):<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>cache_data = self.get_data(cache_filename)<EOL>cached_code = _get_basilisp_bytecode(<EOL>fullname, path_stats["<STR_LIT>"], path_stats["<STR_LIT:size>"], cache_data<EOL>)<EOL>compiler.compile_bytecode(<EOL>cached_code,<EOL>compiler.GeneratorContext(filename=filename),<EOL>compiler.PythonASTOptimizer(),<EOL>module,<EOL>)<EOL><DEDENT>

Load and execute a cached Basilisp module.


def _exec_module(<EOL>self,<EOL>fullname: str,<EOL>loader_state: Mapping[str, str],<EOL>path_stats: Mapping[str, int],<EOL>module: types.ModuleType,<EOL>):

filename = loader_state["<STR_LIT:filename>"]<EOL>cache_filename = loader_state["<STR_LIT>"]<EOL>with timed(<EOL>lambda duration: logger.debug(<EOL>f"<STR_LIT>"<EOL>)<EOL>):<EOL><INDENT>all_bytecode = []<EOL>def add_bytecode(bytecode: types.CodeType):<EOL><INDENT>all_bytecode.append(bytecode)<EOL><DEDENT>logger.debug(f"<STR_LIT>")<EOL>forms = reader.read_file(filename, resolver=runtime.resolve_alias)<EOL>compiler.compile_module(  <EOL>forms,<EOL>compiler.CompilerContext(filename=filename),<EOL>module,<EOL>collect_bytecode=add_bytecode,<EOL>)<EOL><DEDENT>cache_file_bytes = _basilisp_bytecode(<EOL>path_stats["<STR_LIT>"], path_stats["<STR_LIT:size>"], all_bytecode<EOL>)<EOL>self._cache_bytecode(filename, cache_filename, cache_file_bytes)<EOL>

Load and execute a non-cached Basilisp module.


fullname = module.__name__<EOL>cached = self._cache[fullname]<EOL>cached["<STR_LIT>"] = module<EOL>spec = cached["<STR_LIT>"]<EOL>filename = spec.loader_state["<STR_LIT:filename>"]<EOL>path_stats = self.path_stats(filename)<EOL>ns_name = demunge(fullname)<EOL>ns: runtime.Namespace = runtime.set_current_ns(ns_name).value<EOL>ns.module = module<EOL>if os.getenv(_NO_CACHE_ENVVAR, None) == "<STR_LIT:true>":<EOL><INDENT>self._exec_module(fullname, spec.loader_state, path_stats, module)<EOL><DEDENT>else:<EOL><INDENT>try:<EOL><INDENT>self._exec_cached_module(<EOL>fullname, spec.loader_state, path_stats, module<EOL>)<EOL><DEDENT>except (EOFError, ImportError, IOError, OSError) as e:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>self._exec_module(fullname, spec.loader_state, path_stats, module)<EOL><DEDENT><DEDENT>runtime.Namespace.add_default_import(ns_name)<EOL>

Compile the Basilisp module into Python code.

        Basilisp is fundamentally a form-at-a-time compilation, meaning that
        each form in a module may require code compiled from an earlier form, so
        we incrementally compile a Python module by evaluating a single top-level
        form at a time and inserting the resulting AST nodes into the Pyton module.


def munge(s: str, allow_builtins: bool = False) -> str:

new_str = []<EOL>for c in s:<EOL><INDENT>new_str.append(_MUNGE_REPLACEMENTS.get(c, c))<EOL><DEDENT>new_s = "<STR_LIT>".join(new_str)<EOL>if keyword.iskeyword(new_s):<EOL><INDENT>return f"<STR_LIT>"<EOL><DEDENT>if not allow_builtins and new_s in builtins.__dict__:<EOL><INDENT>return f"<STR_LIT>"<EOL><DEDENT>return new_s<EOL>

Replace characters which are not valid in Python symbols
    with valid replacement strings.


def demunge_replacer(match: Match) -> str:<EOL><INDENT>full_match = match.group(<NUM_LIT:0>)<EOL>replacement = _DEMUNGE_REPLACEMENTS.get(full_match, None)<EOL>if replacement:<EOL><INDENT>return replacement<EOL><DEDENT>return full_match<EOL><DEDENT>return re.sub(_DEMUNGE_PATTERN, demunge_replacer, s).replace("<STR_LIT:_>", "<STR_LIT:->")<EOL>

Replace munged string components with their original
    representation.


return _NAME_COUNTER.swap(lambda x: x + <NUM_LIT:1>)<EOL>

Increment the name counter and return the next value.


i = next_name_id()<EOL>return f"<STR_LIT>"<EOL>

Generate a unique function name with the given prefix.


def decimal_from_str(decimal_str: str) -> Decimal:

return Decimal(decimal_str)<EOL>


def fraction(numerator: int, denominator: int) -> Fraction:

return Fraction(numerator=numerator, denominator=denominator)<EOL>

Create a Fraction from a numerator and denominator.


def inst_from_str(inst_str: str) -> datetime.datetime:

return dateparser.parse(inst_str)<EOL>

Create a datetime instance from an RFC 3339 formatted date string.


def regex_from_str(regex_str: str) -> Pattern:

return re.compile(regex_str)<EOL>

Create a new regex pattern from the input string.


def uuid_from_str(uuid_str: str) -> uuid.UUID:

return uuid.UUID(f"<STR_LIT>")<EOL>

Create a new UUID instance from the canonical string representation
    of a UUID.


def _new_module(name: str, doc=None) -> types.ModuleType:

mod = types.ModuleType(name, doc=doc)<EOL>mod.__loader__ = None<EOL>mod.__package__ = None<EOL>mod.__spec__ = None<EOL>mod.__basilisp_bootstrapped__ = False  <EOL>return mod<EOL>

Create a new empty Basilisp Python module.
    Modules are created for each Namespace when it is created.


if o is None:<EOL><INDENT>return None<EOL><DEDENT>if isinstance(o, ISeq):<EOL><INDENT>return o.first<EOL><DEDENT>s = to_seq(o)<EOL>if s is None:<EOL><INDENT>return None<EOL><DEDENT>return s.first<EOL>

If o is a ISeq, return the first element from o. If o is None, return
    None. Otherwise, coerces o to a Seq and returns the first.


if o is None:<EOL><INDENT>return None<EOL><DEDENT>if isinstance(o, ISeq):<EOL><INDENT>s = o.rest<EOL>if s is None:<EOL><INDENT>return lseq.EMPTY<EOL><DEDENT>return s<EOL><DEDENT>n = to_seq(o)<EOL>if n is None:<EOL><INDENT>return lseq.EMPTY<EOL><DEDENT>return n.rest<EOL>

If o is a ISeq, return the elements after the first in o. If o is None,
    returns an empty seq. Otherwise, coerces o to a seq and returns the rest.


while True:<EOL><INDENT>if coll is None:<EOL><INDENT>return None<EOL><DEDENT>if i == <NUM_LIT:0>:<EOL><INDENT>return coll<EOL><DEDENT>i -= <NUM_LIT:1><EOL>coll = rest(coll)<EOL><DEDENT>

Returns the nth rest sequence of coll, or coll if i is 0.


s = rest(o)<EOL>if not s:<EOL><INDENT>return None<EOL><DEDENT>return s<EOL>

Calls rest on o. If o returns an empty sequence or None, returns None.
    Otherwise, returns the elements after the first in o.


def nthnext(coll, i: int) -> Optional[ISeq]:

while True:<EOL><INDENT>if coll is None:<EOL><INDENT>return None<EOL><DEDENT>if i == <NUM_LIT:0>:<EOL><INDENT>return to_seq(coll)<EOL><DEDENT>i -= <NUM_LIT:1><EOL>coll = next_(coll)<EOL><DEDENT>


if seq is None:<EOL><INDENT>return llist.l(o)<EOL><DEDENT>if isinstance(seq, ISeq):<EOL><INDENT>return seq.cons(o)<EOL><DEDENT>return Maybe(to_seq(seq)).map(lambda s: s.cons(o)).or_else(lambda: llist.l(o))<EOL>

Creates a new sequence where o is the first element and seq is the rest.
    If seq is None, return a list containing o. If seq is not a ISeq, attempt
    to coerce it to a ISeq and then cons o onto the resulting sequence.


def _seq_or_nil(s: ISeq) -> Optional[ISeq]:

if s.is_empty:<EOL><INDENT>return None<EOL><DEDENT>return s<EOL>

Return None if a ISeq is empty, the ISeq otherwise.


if o is None:<EOL><INDENT>return None<EOL><DEDENT>if isinstance(o, ISeq):<EOL><INDENT>return _seq_or_nil(o)<EOL><DEDENT>if isinstance(o, ISeqable):<EOL><INDENT>return _seq_or_nil(o.seq())<EOL><DEDENT>return _seq_or_nil(lseq.sequence(o))<EOL>

Coerce the argument o to a ISeq. If o is None, return None.


allseqs = lseq.sequence(itertools.chain(*filter(None, map(to_seq, seqs))))<EOL>if allseqs is None:<EOL><INDENT>return lseq.EMPTY<EOL><DEDENT>return allseqs<EOL>

Concatenate the sequences given by seqs into a single ISeq.


final = list(args[:-<NUM_LIT:1>])<EOL>try:<EOL><INDENT>last = args[-<NUM_LIT:1>]<EOL><DEDENT>except TypeError as e:<EOL><INDENT>logger.debug("<STR_LIT>", type(e).__name__, e)<EOL><DEDENT>s = to_seq(last)<EOL>if s is not None:<EOL><INDENT>final.extend(s)<EOL><DEDENT>return f(*final)<EOL>

Apply function f to the arguments provided.
    The last argument must always be coercible to a Seq. Intermediate
    arguments are not modified.
    For example:
        (apply max [1 2 3])   ;=> 3
        (apply max 4 [1 2 3]) ;=> 4


final = list(args[:-<NUM_LIT:1>])<EOL>try:<EOL><INDENT>last = args[-<NUM_LIT:1>]<EOL><DEDENT>except TypeError as e:<EOL><INDENT>logger.debug("<STR_LIT>", type(e).__name__, e)<EOL><DEDENT>kwargs = to_py(last, lambda kw: munge(kw.name, allow_builtins=True))<EOL>return f(*final, **kwargs)<EOL>

Apply function f to the arguments provided.
    The last argument must always be coercible to a Mapping. Intermediate
    arguments are not modified.
    For example:
        (apply builtins/dict {:a 1} {:b 2})   ;=> #py {:a 1 :b 2}
        (apply builtins/dict {:a 1} {:a 2})   ;=> #py {:a 2}


def nth(coll, i, notfound=__nth_sentinel):

if coll is None:<EOL><INDENT>return None<EOL><DEDENT>try:<EOL><INDENT>return coll[i]<EOL><DEDENT>except IndexError as ex:<EOL><INDENT>if notfound is not __nth_sentinel:<EOL><INDENT>return notfound<EOL><DEDENT>raise ex<EOL><DEDENT>except TypeError as ex:<EOL><INDENT>logger.log(TRACE, "<STR_LIT>", type(ex).__name__, ex)<EOL><DEDENT>try:<EOL><INDENT>for j, e in enumerate(coll):<EOL><INDENT>if i == j:<EOL><INDENT>return e<EOL><DEDENT><DEDENT>if notfound is not __nth_sentinel:<EOL><INDENT>return notfound<EOL><DEDENT>raise IndexError(f"<STR_LIT>")<EOL><DEDENT>except TypeError:<EOL><INDENT>pass<EOL><DEDENT>raise TypeError(f"<STR_LIT>")<EOL>

Returns the ith element of coll (0-indexed), if it exists.
    None otherwise. If i is out of bounds, throws an IndexError unless
    notfound is specified.


if m is None:<EOL><INDENT>return lmap.Map.empty().assoc(*kvs)<EOL><DEDENT>if isinstance(m, IAssociative):<EOL><INDENT>return m.assoc(*kvs)<EOL><DEDENT>raise TypeError(<EOL>f"<STR_LIT>"<EOL>)<EOL>

Associate keys to values in associative data structure m. If m is None,
    returns a new Map with key-values kvs.


if m is None:<EOL><INDENT>return lmap.Map.empty().assoc(k, f(None, *args))<EOL><DEDENT>if isinstance(m, IAssociative):<EOL><INDENT>old_v = m.entry(k)<EOL>new_v = f(old_v, *args)<EOL>return m.assoc(k, new_v)<EOL><DEDENT>raise TypeError(<EOL>f"<STR_LIT>"<EOL>)<EOL>

Updates the value for key k in associative data structure m with the return value from
    calling f(old_v, *args). If m is None, use an empty map. If k is not in m, old_v will be
    None.


if coll is None:<EOL><INDENT>l = llist.List.empty()<EOL>return l.cons(*xs)<EOL><DEDENT>if isinstance(coll, IPersistentCollection):<EOL><INDENT>return coll.cons(*xs)<EOL><DEDENT>raise TypeError(<EOL>f"<STR_LIT>"<EOL>)<EOL>

Conjoin xs to collection. New elements may be added in different positions
    depending on the type of coll. conj returns the same type as coll. If coll
    is None, return a list with xs conjoined.


@functools.wraps(f)<EOL>def partial_f(*inner_args):<EOL><INDENT>return f(*itertools.chain(args, inner_args))<EOL><DEDENT>return partial_f<EOL>

Return a function which is the partial application of f with args.


def deref(o, timeout_s=None, timeout_val=None):

if isinstance(o, IDeref):<EOL><INDENT>return o.deref()<EOL><DEDENT>elif isinstance(o, IBlockingDeref):<EOL><INDENT>return o.deref(timeout_s, timeout_val)<EOL><DEDENT>raise TypeError(f"<STR_LIT>")<EOL>

Dereference a Deref object and return its contents.

    If o is an object implementing IBlockingDeref and timeout_s and
    timeout_val are supplied, deref will wait at most timeout_s seconds,
    returning timeout_val if timeout_s seconds elapse and o has not
    returned.


return a.swap(f, *args)<EOL>

Atomically swap the value of an atom to the return value of (apply f
    current-value args). The function f may be called multiple times while
    swapping, so should be free of side effects. Return the new value.


if isinstance(v1, (bool, type(None))) or isinstance(v2, (bool, type(None))):<EOL><INDENT>return v1 is v2<EOL><DEDENT>return v1 == v2<EOL>

Compare two objects by value. Unlike the standard Python equality operator,
    this function does not consider 1 == True or 0 == False. All other equality
    operations are the same and performed using Python's equality operator.


def divide(x: LispNumber, y: LispNumber) -> LispNumber:

if isinstance(x, int) and isinstance(y, int):<EOL><INDENT>return Fraction(x, y)<EOL><DEDENT>return x / y<EOL>

Division reducer. If both arguments are integers, return a Fraction.
    Otherwise, return the true division of x and y.


return math.trunc(num / div)<EOL>

Return the integral quotient resulting from the division of num by div.


def sort(coll, f=None) -> Optional[ISeq]:

return to_seq(sorted(coll, key=Maybe(f).map(functools.cmp_to_key).value))<EOL>

Return a sorted sequence of the elements in coll. If a comparator
    function f is provided, compare elements in coll using f.


if isinstance(coll, IAssociative):<EOL><INDENT>return coll.contains(k)<EOL><DEDENT>return k in coll<EOL>


if isinstance(m, IAssociative):<EOL><INDENT>return m.entry(k, default=default)<EOL><DEDENT>try:<EOL><INDENT>return m[k]<EOL><DEDENT>except (KeyError, IndexError, TypeError) as e:<EOL><INDENT>logger.debug("<STR_LIT>", type(e).__name__, e)<EOL>return default<EOL><DEDENT>

Return the value of k in m. Return default if k not found in m.


def is_special_form(s: sym.Symbol) -> bool:

return s in _SPECIAL_FORMS<EOL>


@functools.singledispatch<EOL>def to_lisp(o, keywordize_keys: bool = True):

if not isinstance(o, (dict, frozenset, list, set, tuple)):<EOL><INDENT>return o<EOL><DEDENT>else:  <EOL><INDENT>return _to_lisp_backup(o, keywordize_keys=keywordize_keys)<EOL><DEDENT>

Recursively convert Python collections into Lisp collections.


@functools.singledispatch<EOL>def to_py(o, keyword_fn: Callable[[kw.Keyword], Any] = _kw_name):

if isinstance(o, ISeq):<EOL><INDENT>return _to_py_list(o, keyword_fn=keyword_fn)<EOL><DEDENT>elif not isinstance(<EOL>o, (IPersistentList, IPersistentMap, IPersistentSet, IPersistentVector)<EOL>):<EOL><INDENT>return o<EOL><DEDENT>else:  <EOL><INDENT>return _to_py_backup(o, keyword_fn=keyword_fn)<EOL><DEDENT>

Recursively convert Lisp collections into Python collections.


def lrepr(o, human_readable: bool = False) -> str:

core_ns = Namespace.get(sym.symbol(CORE_NS))<EOL>assert core_ns is not None<EOL>return lobj.lrepr(<EOL>o,<EOL>human_readable=human_readable,<EOL>print_dup=core_ns.find(sym.symbol(_PRINT_DUP_VAR_NAME)).value,  <EOL>print_length=core_ns.find(  <EOL>sym.symbol(_PRINT_LENGTH_VAR_NAME)<EOL>).value,<EOL>print_level=core_ns.find(  <EOL>sym.symbol(_PRINT_LEVEL_VAR_NAME)<EOL>).value,<EOL>print_meta=core_ns.find(sym.symbol(_PRINT_META_VAR_NAME)).value,  <EOL>print_readably=core_ns.find(  <EOL>sym.symbol(_PRINT_READABLY_VAR_NAME)<EOL>).value,<EOL>)<EOL>

Produce a string representation of an object. If human_readable is False,
    the string representation of Lisp objects is something that can be read back
    in by the reader as the same object.


return lrepr(o, human_readable=True)<EOL>

Produce a human readable string representation of an object.


def repl_complete(text: str, state: int) -> Optional[str]:

<EOL>if __NOT_COMPLETEABLE.match(text):<EOL><INDENT>return None<EOL><DEDENT>elif text.startswith("<STR_LIT::>"):<EOL><INDENT>completions = kw.complete(text)<EOL><DEDENT>else:<EOL><INDENT>ns = get_current_ns()<EOL>completions = ns.complete(text)<EOL><DEDENT>return list(completions)[state] if completions is not None else None<EOL>

Completer function for Python's readline/libedit implementation.


if isinstance(args, tuple):<EOL><INDENT>return llist.list(args)<EOL><DEDENT>raise TypeError("<STR_LIT>")<EOL>

Collect Python starred arguments into a Basilisp list.


@functools.wraps(f)<EOL>def trampoline(*args, **kwargs):<EOL><INDENT>while True:<EOL><INDENT>ret = f(*args, **kwargs)<EOL>if isinstance(ret, _TrampolineArgs):<EOL><INDENT>args = ret.args<EOL>kwargs = ret.kwargs<EOL>continue<EOL><DEDENT>return ret<EOL><DEDENT><DEDENT>return trampoline<EOL>

Trampoline a function repeatedly until it is finished recurring to help
    avoid stack growth.


def decorator(f):<EOL><INDENT>for k, v in kwargs.items():<EOL><INDENT>setattr(f, k, v)<EOL><DEDENT>return f<EOL><DEDENT>return decorator<EOL>

Decorator to set attributes on a function. Returns the original
    function after setting the attributes named by the keyword arguments.


def _fn_with_meta(f, meta: Optional[lmap.Map]):

if not isinstance(meta, lmap.Map):<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>if inspect.iscoroutinefunction(f):<EOL><INDENT>@functools.wraps(f)<EOL>async def wrapped_f(*args, **kwargs):<EOL><INDENT>return await f(*args, **kwargs)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>@functools.wraps(f)  <EOL>def wrapped_f(*args, **kwargs):<EOL><INDENT>return f(*args, **kwargs)<EOL><DEDENT><DEDENT>wrapped_f.meta = (  <EOL>f.meta.update(meta)<EOL>if hasattr(f, "<STR_LIT>") and isinstance(f.meta, lmap.Map)<EOL>else meta<EOL>)<EOL>wrapped_f.with_meta = partial(_fn_with_meta, wrapped_f)  <EOL>return wrapped_f<EOL>

Return a new function with the given meta. If the function f already
    has a meta map, then merge the


assert not hasattr(f, "<STR_LIT>")<EOL>f._basilisp_fn = True<EOL>f.meta = None<EOL>f.with_meta = partial(_fn_with_meta, f)<EOL>return f<EOL>

Create a Basilisp function, setting meta and supplying a with_meta
    method implementation.


def init_ns_var(which_ns: str = CORE_NS, ns_var_name: str = NS_VAR_NAME) -> Var:

core_sym = sym.Symbol(which_ns)<EOL>core_ns = Namespace.get_or_create(core_sym)<EOL>ns_var = Var.intern(core_sym, sym.Symbol(ns_var_name), core_ns, dynamic=True)<EOL>logger.debug(f"<STR_LIT>")<EOL>return ns_var<EOL>

Initialize the dynamic `*ns*` variable in the Namespace `which_ns`.


def set_current_ns(<EOL>ns_name: str,<EOL>module: types.ModuleType = None,<EOL>ns_var_name: str = NS_VAR_NAME,<EOL>ns_var_ns: str = NS_VAR_NS,<EOL>) -> Var:

symbol = sym.Symbol(ns_name)<EOL>ns = Namespace.get_or_create(symbol, module=module)<EOL>ns_var_sym = sym.Symbol(ns_var_name, ns=ns_var_ns)<EOL>ns_var = Maybe(Var.find(ns_var_sym)).or_else_raise(<EOL>lambda: RuntimeException(<EOL>f"<STR_LIT>"<EOL>)<EOL>)<EOL>ns_var.push_bindings(ns)<EOL>logger.debug(f"<STR_LIT>")<EOL>return ns_var<EOL>

Set the value of the dynamic variable `*ns*` in the current thread.


@contextlib.contextmanager<EOL>def ns_bindings(<EOL>ns_name: str,<EOL>module: types.ModuleType = None,<EOL>ns_var_name: str = NS_VAR_NAME,<EOL>ns_var_ns: str = NS_VAR_NS,<EOL>):

symbol = sym.Symbol(ns_name)<EOL>ns = Namespace.get_or_create(symbol, module=module)<EOL>ns_var_sym = sym.Symbol(ns_var_name, ns=ns_var_ns)<EOL>ns_var = Maybe(Var.find(ns_var_sym)).or_else_raise(<EOL>lambda: RuntimeException(<EOL>f"<STR_LIT>"<EOL>)<EOL>)<EOL>try:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>ns_var.push_bindings(ns)<EOL>yield ns_var.value<EOL><DEDENT>finally:<EOL><INDENT>ns_var.pop_bindings()<EOL>logger.debug(f"<STR_LIT>")<EOL><DEDENT>

Context manager for temporarily changing the value of basilisp.core/*ns*.


@contextlib.contextmanager<EOL>def remove_ns_bindings(ns_var_name: str = NS_VAR_NAME, ns_var_ns: str = NS_VAR_NS):

ns_var_sym = sym.Symbol(ns_var_name, ns=ns_var_ns)<EOL>ns_var = Maybe(Var.find(ns_var_sym)).or_else_raise(<EOL>lambda: RuntimeException(<EOL>f"<STR_LIT>"<EOL>)<EOL>)<EOL>try:<EOL><INDENT>yield<EOL><DEDENT>finally:<EOL><INDENT>ns_var.pop_bindings()<EOL>logger.debug(f"<STR_LIT>")<EOL><DEDENT>

Context manager to pop the most recent bindings for basilisp.core/*ns* after
    completion of the code under management.


def get_current_ns(<EOL>ns_var_name: str = NS_VAR_NAME, ns_var_ns: str = NS_VAR_NS<EOL>) -> Namespace:

ns_sym = sym.Symbol(ns_var_name, ns=ns_var_ns)<EOL>ns: Namespace = Maybe(Var.find(ns_sym)).map(lambda v: v.value).or_else_raise(<EOL>lambda: RuntimeException(f"<STR_LIT>")<EOL>)<EOL>return ns<EOL>

Get the value of the dynamic variable `*ns*` in the current thread.


def resolve_alias(s: sym.Symbol, ns: Optional[Namespace] = None) -> sym.Symbol:

if s in _SPECIAL_FORMS:<EOL><INDENT>return s<EOL><DEDENT>ns = Maybe(ns).or_else(get_current_ns)<EOL>if s.ns is not None:<EOL><INDENT>aliased_ns = ns.get_alias(sym.symbol(s.ns))<EOL>if aliased_ns is not None:<EOL><INDENT>return sym.symbol(s.name, aliased_ns.name)<EOL><DEDENT>else:<EOL><INDENT>return s<EOL><DEDENT><DEDENT>else:<EOL><INDENT>which_var = ns.find(sym.symbol(s.name))<EOL>if which_var is not None:<EOL><INDENT>return sym.symbol(which_var.name.name, which_var.ns.name)<EOL><DEDENT>else:<EOL><INDENT>return sym.symbol(s.name, ns=ns.name)<EOL><DEDENT><DEDENT>

Resolve the aliased symbol in the current namespace.


def resolve_var(s: sym.Symbol, ns: Optional[Namespace] = None) -> Optional[Var]:

return Var.find(resolve_alias(s, ns))<EOL>

Resolve the aliased symbol to a Var from the specified
    namespace, or the current namespace if none is specified.


def add_generated_python(<EOL>generated_python: str,<EOL>var_name: str = _GENERATED_PYTHON_VAR_NAME,<EOL>which_ns: Optional[str] = None,<EOL>) -> None:

if which_ns is None:<EOL><INDENT>which_ns = get_current_ns().name<EOL><DEDENT>ns_sym = sym.Symbol(var_name, ns=which_ns)<EOL>v = Maybe(Var.find(ns_sym)).or_else(<EOL>lambda: Var.intern(<EOL>sym.symbol(which_ns),  <EOL>sym.symbol(var_name),<EOL>"<STR_LIT>",<EOL>dynamic=True,<EOL>meta=lmap.map({_PRIVATE_META_KEY: True}),<EOL>)<EOL>)<EOL>v.value = v.value + generated_python<EOL>

Add generated Python code to a dynamic variable in which_ns.


def print_generated_python(<EOL>var_name: str = _PRINT_GENERATED_PY_VAR_NAME, core_ns_name: str = CORE_NS<EOL>) -> bool:

ns_sym = sym.Symbol(var_name, ns=core_ns_name)<EOL>return (<EOL>Maybe(Var.find(ns_sym))<EOL>.map(lambda v: v.value)<EOL>.or_else_raise(lambda: RuntimeException(f"<STR_LIT>"))<EOL>)<EOL>

Return the value of the `*print-generated-python*` dynamic variable.


def bootstrap(ns_var_name: str = NS_VAR_NAME, core_ns_name: str = CORE_NS) -> None:

core_ns_sym = sym.symbol(core_ns_name)<EOL>ns_var_sym = sym.symbol(ns_var_name, ns=core_ns_name)<EOL>__NS = Maybe(Var.find(ns_var_sym)).or_else_raise(<EOL>lambda: RuntimeException(f"<STR_LIT>")<EOL>)<EOL>def in_ns(s: sym.Symbol):<EOL><INDENT>ns = Namespace.get_or_create(s)<EOL>__NS.value = ns<EOL>return ns<EOL><DEDENT>Var.intern_unbound(core_ns_sym, sym.symbol("<STR_LIT>"))<EOL>Var.intern_unbound(core_ns_sym, sym.symbol("<STR_LIT>"))<EOL>Var.intern(<EOL>core_ns_sym, sym.symbol("<STR_LIT>"), in_ns, meta=lmap.map({_REDEF_META_KEY: True})<EOL>)<EOL>Var.intern(<EOL>core_ns_sym,<EOL>sym.symbol(_PRINT_GENERATED_PY_VAR_NAME),<EOL>False,<EOL>dynamic=True,<EOL>meta=lmap.map({_PRIVATE_META_KEY: True}),<EOL>)<EOL>Var.intern(<EOL>core_ns_sym,<EOL>sym.symbol(_GENERATED_PYTHON_VAR_NAME),<EOL>"<STR_LIT>",<EOL>dynamic=True,<EOL>meta=lmap.map({_PRIVATE_META_KEY: True}),<EOL>)<EOL>Var.intern(<EOL>core_ns_sym, sym.symbol(_PRINT_DUP_VAR_NAME), lobj.PRINT_DUP, dynamic=True<EOL>)<EOL>Var.intern(<EOL>core_ns_sym, sym.symbol(_PRINT_LENGTH_VAR_NAME), lobj.PRINT_LENGTH, dynamic=True<EOL>)<EOL>Var.intern(<EOL>core_ns_sym, sym.symbol(_PRINT_LEVEL_VAR_NAME), lobj.PRINT_LEVEL, dynamic=True<EOL>)<EOL>Var.intern(<EOL>core_ns_sym, sym.symbol(_PRINT_META_VAR_NAME), lobj.PRINT_META, dynamic=True<EOL>)<EOL>Var.intern(<EOL>core_ns_sym,<EOL>sym.symbol(_PRINT_READABLY_VAR_NAME),<EOL>lobj.PRINT_READABLY,<EOL>dynamic=True,<EOL>)<EOL>

Bootstrap the environment with functions that are are difficult to
    express with the very minimal lisp environment.


@staticmethod<EOL><INDENT>def intern(<EOL>ns: sym.Symbol, name: sym.Symbol, val, dynamic: bool = False, meta=None<EOL>) -> "<STR_LIT>":<DEDENT>

var_ns = Namespace.get_or_create(ns)<EOL>var = var_ns.intern(name, Var(var_ns, name, dynamic=dynamic, meta=meta))<EOL>var.root = val<EOL>return var<EOL>

Intern the value bound to the symbol `name` in namespace `ns`.


@staticmethod<EOL><INDENT>def intern_unbound(<EOL>ns: sym.Symbol, name: sym.Symbol, dynamic: bool = False, meta=None<EOL>) -> "<STR_LIT>":<DEDENT>

var_ns = Namespace.get_or_create(ns)<EOL>return var_ns.intern(name, Var(var_ns, name, dynamic=dynamic, meta=meta))<EOL>

Create a new unbound `Var` instance to the symbol `name` in namespace `ns`.


@staticmethod<EOL><INDENT>def find_in_ns(ns_sym: sym.Symbol, name_sym: sym.Symbol) -> "<STR_LIT>":<DEDENT>

ns = Namespace.get(ns_sym)<EOL>if ns:<EOL><INDENT>return ns.find(name_sym)<EOL><DEDENT>return None<EOL>

Return the value current bound to the name `name_sym` in the namespace
        specified by `ns_sym`.


@staticmethod<EOL><INDENT>def find(ns_qualified_sym: sym.Symbol) -> "<STR_LIT>":<DEDENT>

ns = Maybe(ns_qualified_sym.ns).or_else_raise(<EOL>lambda: ValueError(<EOL>f"<STR_LIT>"<EOL>)<EOL>)<EOL>ns_sym = sym.symbol(ns)<EOL>name_sym = sym.symbol(ns_qualified_sym.name)<EOL>return Var.find_in_ns(ns_sym, name_sym)<EOL>

Return the value currently bound to the name in the namespace specified
        by `ns_qualified_sym`.


@staticmethod<EOL><INDENT>def find_safe(ns_qualified_sym: sym.Symbol) -> "<STR_LIT>":<DEDENT>

v = Var.find(ns_qualified_sym)<EOL>if v is None:<EOL><INDENT>raise RuntimeException(<EOL>f"<STR_LIT>"<EOL>)<EOL><DEDENT>return v<EOL>

Return the Var currently bound to the name in the namespace specified
        by `ns_qualified_sym`. If no Var is bound to that name, raise an exception.

        This is a utility method to return useful debugging information when code
        refers to an invalid symbol at runtime.


@classmethod<EOL><INDENT>def add_default_import(cls, module: str):<DEDENT>

if module in cls.GATED_IMPORTS:<EOL><INDENT>cls.DEFAULT_IMPORTS.swap(lambda s: s.cons(sym.symbol(module)))<EOL><DEDENT>

Add a gated default import to the default imports.

        In particular, we need to avoid importing 'basilisp.core' before we have
        finished macro-expanding.


@module.setter<EOL><INDENT>def module(self, m: types.ModuleType):<DEDENT>

self._module = m<EOL>

Override the Python module for this Namespace.

        ***WARNING**
        This should only be done by basilisp.importer code to make sure the
        correct module is generated for `basilisp.core`.


@property<EOL><INDENT>def aliases(self) -> NamespaceMap:<DEDENT>

return self._aliases.deref()<EOL>

A mapping between a symbolic alias and another Namespace. The
        fully qualified name of a namespace is also an alias for itself.


@property<EOL><INDENT>def imports(self) -> ModuleMap:<DEDENT>

return self._imports.deref()<EOL>

A mapping of names to Python modules imported into the current
        namespace.


@property<EOL><INDENT>def import_aliases(self) -> AliasMap:<DEDENT>

return self._import_aliases.deref()<EOL>

A mapping of a symbolic alias and a Python module name.


@property<EOL><INDENT>def interns(self) -> VarMap:<DEDENT>

return self._interns.deref()<EOL>

A mapping between a symbolic name and a Var. The Var may point to
        code, data, or nothing, if it is unbound. Vars in `interns` are
        interned in _this_ namespace.


@property<EOL><INDENT>def refers(self) -> VarMap:<DEDENT>

return self._refers.deref()<EOL>

A mapping between a symbolic name and a Var. Vars in refers are
        interned in another namespace and are only referred to without an
        alias in this namespace.


def add_alias(self, alias: sym.Symbol, namespace: "<STR_LIT>") -> None:

self._aliases.swap(lambda m: m.assoc(alias, namespace))<EOL>

Add a Symbol alias for the given Namespace.


def get_alias(self, alias: sym.Symbol) -> "<STR_LIT>":

return self.aliases.entry(alias, None)<EOL>

Get the Namespace aliased by Symbol or None if it does not exist.


def intern(self, sym: sym.Symbol, var: Var, force: bool = False) -> Var:

m: lmap.Map = self._interns.swap(Namespace._intern, sym, var, force=force)<EOL>return m.entry(sym)<EOL>

Intern the Var given in this namespace mapped by the given Symbol.
        If the Symbol already maps to a Var, this method _will not overwrite_
        the existing Var mapping unless the force keyword argument is given
        and is True.


@staticmethod<EOL><INDENT>def _intern(<EOL>m: lmap.Map, sym: sym.Symbol, new_var: Var, force: bool = False<EOL>) -> lmap.Map:<DEDENT>

var = m.entry(sym, None)<EOL>if var is None or force:<EOL><INDENT>return m.assoc(sym, new_var)<EOL><DEDENT>return m<EOL>

Swap function used by intern to atomically intern a new variable in
        the symbol mapping for this Namespace.


def find(self, sym: sym.Symbol) -> Optional[Var]:

v = self.interns.entry(sym, None)<EOL>if v is None:<EOL><INDENT>return self.refers.entry(sym, None)<EOL><DEDENT>return v<EOL>

Find Vars mapped by the given Symbol input or None if no Vars are
        mapped by that Symbol.


def add_import(<EOL>self, sym: sym.Symbol, module: types.ModuleType, *aliases: sym.Symbol<EOL>) -> None:

self._imports.swap(lambda m: m.assoc(sym, module))<EOL>if aliases:<EOL><INDENT>self._import_aliases.swap(<EOL>lambda m: m.assoc(<EOL>*itertools.chain.from_iterable([(alias, sym) for alias in aliases])<EOL>)<EOL>)<EOL><DEDENT>

Add the Symbol as an imported Symbol in this Namespace. If aliases are given,
        the aliases will be applied to the


def get_import(self, sym: sym.Symbol) -> Optional[types.ModuleType]:

mod = self.imports.entry(sym, None)<EOL>if mod is None:<EOL><INDENT>alias = self.import_aliases.get(sym, None)<EOL>if alias is None:<EOL><INDENT>return None<EOL><DEDENT>return self.imports.entry(alias, None)<EOL><DEDENT>return mod<EOL>

Return the module if a moduled named by sym has been imported into
        this Namespace, None otherwise.

        First try to resolve a module directly with the given name. If no module
        can be resolved, attempt to resolve the module using import aliases.


def add_refer(self, sym: sym.Symbol, var: Var) -> None:

if not var.is_private:<EOL><INDENT>self._refers.swap(lambda s: s.assoc(sym, var))<EOL><DEDENT>

Refer var in this namespace under the name sym.


def get_refer(self, sym: sym.Symbol) -> Optional[Var]:

return self.refers.entry(sym, None)<EOL>

Get the Var referred by Symbol or None if it does not exist.


@classmethod<EOL><INDENT>def __refer_all(cls, refers: lmap.Map, other_ns_interns: lmap.Map) -> lmap.Map:<DEDENT>

final_refers = refers<EOL>for entry in other_ns_interns:<EOL><INDENT>s: sym.Symbol = entry.key<EOL>var: Var = entry.value<EOL>if not var.is_private:<EOL><INDENT>final_refers = final_refers.assoc(s, var)<EOL><DEDENT><DEDENT>return final_refers<EOL>

Refer all _public_ interns from another namespace.


def refer_all(self, other_ns: "<STR_LIT>"):

self._refers.swap(Namespace.__refer_all, other_ns.interns)<EOL>

Refer all the Vars in the other namespace.


@classmethod<EOL><INDENT>def ns_cache(cls) -> lmap.Map:<DEDENT>

return cls._NAMESPACES.deref()<EOL>

Return a snapshot of the Namespace cache.


@staticmethod<EOL><INDENT>def __get_or_create(<EOL>ns_cache: NamespaceMap,<EOL>name: sym.Symbol,<EOL>module: types.ModuleType = None,<EOL>core_ns_name=CORE_NS,<EOL>) -> lmap.Map:<DEDENT>

ns = ns_cache.entry(name, None)<EOL>if ns is not None:<EOL><INDENT>return ns_cache<EOL><DEDENT>new_ns = Namespace(name, module=module)<EOL>if name.name != core_ns_name:<EOL><INDENT>core_ns = ns_cache.entry(sym.symbol(core_ns_name), None)<EOL>assert core_ns is not None, "<STR_LIT>"<EOL>new_ns.refer_all(core_ns)<EOL><DEDENT>return ns_cache.assoc(name, new_ns)<EOL>

Private swap function used by `get_or_create` to atomically swap
        the new namespace map into the global cache.


@classmethod<EOL><INDENT>def get_or_create(<EOL>cls, name: sym.Symbol, module: types.ModuleType = None<EOL>) -> "<STR_LIT>":<DEDENT>

return cls._NAMESPACES.swap(Namespace.__get_or_create, name, module=module)[<EOL>name<EOL>]<EOL>

Get the namespace bound to the symbol `name` in the global namespace
        cache, creating it if it does not exist.
        Return the namespace.


@classmethod<EOL><INDENT>def get(cls, name: sym.Symbol) -> "<STR_LIT>":<DEDENT>

return cls._NAMESPACES.deref().entry(name, None)<EOL>

Get the namespace bound to the symbol `name` in the global namespace
        cache. Return the namespace if it exists or None otherwise..


@classmethod<EOL><INDENT>def remove(cls, name: sym.Symbol) -> Optional["<STR_LIT>"]:<DEDENT>

while True:<EOL><INDENT>oldval: lmap.Map = cls._NAMESPACES.deref()<EOL>ns: Optional[Namespace] = oldval.entry(name, None)<EOL>newval = oldval<EOL>if ns is not None:<EOL><INDENT>newval = oldval.dissoc(name)<EOL><DEDENT>if cls._NAMESPACES.compare_and_set(oldval, newval):<EOL><INDENT>return ns<EOL><DEDENT><DEDENT>

Remove the namespace bound to the symbol `name` in the global
        namespace cache and return that namespace.
        Return None if the namespace did not exist in the cache.


@staticmethod<EOL><INDENT>def __completion_matcher(text: str) -> CompletionMatcher:<DEDENT>

def is_match(entry: Tuple[sym.Symbol, Any]) -> bool:<EOL><INDENT>return entry[<NUM_LIT:0>].name.startswith(text)<EOL><DEDENT>return is_match<EOL>

Return a function which matches any symbol keys from map entries
        against the given text.


def __complete_alias(<EOL>self, prefix: str, name_in_ns: Optional[str] = None<EOL>) -> Iterable[str]:

candidates = filter(<EOL>Namespace.__completion_matcher(prefix), [(s, n) for s, n in self.aliases]<EOL>)<EOL>if name_in_ns is not None:<EOL><INDENT>for _, candidate_ns in candidates:<EOL><INDENT>for match in candidate_ns.__complete_interns(<EOL>name_in_ns, include_private_vars=False<EOL>):<EOL><INDENT>yield f"<STR_LIT>"<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for alias, _ in candidates:<EOL><INDENT>yield f"<STR_LIT>"<EOL><DEDENT><DEDENT>

Return an iterable of possible completions matching the given
        prefix from the list of aliased namespaces. If name_in_ns is given,
        further attempt to refine the list to matching names in that namespace.


def __complete_imports_and_aliases(<EOL>self, prefix: str, name_in_module: Optional[str] = None<EOL>) -> Iterable[str]:

imports = self.imports<EOL>aliases = lmap.map(<EOL>{<EOL>alias: imports.entry(import_name)<EOL>for alias, import_name in self.import_aliases<EOL>}<EOL>)<EOL>candidates = filter(<EOL>Namespace.__completion_matcher(prefix), itertools.chain(aliases, imports)<EOL>)<EOL>if name_in_module is not None:<EOL><INDENT>for _, module in candidates:<EOL><INDENT>for name in module.__dict__:<EOL><INDENT>if name.startswith(name_in_module):<EOL><INDENT>yield f"<STR_LIT>"<EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for candidate_name, _ in candidates:<EOL><INDENT>yield f"<STR_LIT>"<EOL><DEDENT><DEDENT>

Return an iterable of possible completions matching the given
        prefix from the list of imports and aliased imports. If name_in_module
        is given, further attempt to refine the list to matching names in that
        namespace.


def __complete_interns(<EOL>self, value: str, include_private_vars: bool = True<EOL>) -> Iterable[str]:

if include_private_vars:<EOL><INDENT>is_match = Namespace.__completion_matcher(value)<EOL><DEDENT>else:<EOL><INDENT>_is_match = Namespace.__completion_matcher(value)<EOL>def is_match(entry: Tuple[sym.Symbol, Var]) -> bool:<EOL><INDENT>return _is_match(entry) and not entry[<NUM_LIT:1>].is_private<EOL><DEDENT><DEDENT>return map(<EOL>lambda entry: f"<STR_LIT>",<EOL>filter(is_match, [(s, v) for s, v in self.interns]),<EOL>)<EOL>

Return an iterable of possible completions matching the given
        prefix from the list of interned Vars.


def __complete_refers(self, value: str) -> Iterable[str]:

return map(<EOL>lambda entry: f"<STR_LIT>",<EOL>filter(<EOL>Namespace.__completion_matcher(value), [(s, v) for s, v in self.refers]<EOL>),<EOL>)<EOL>

Return an iterable of possible completions matching the given
        prefix from the list of referred Vars.


def complete(self, text: str) -> Iterable[str]:

assert not text.startswith("<STR_LIT::>")<EOL>if "<STR_LIT:/>" in text:<EOL><INDENT>prefix, suffix = text.split("<STR_LIT:/>", maxsplit=<NUM_LIT:1>)<EOL>results = itertools.chain(<EOL>self.__complete_alias(prefix, name_in_ns=suffix),<EOL>self.__complete_imports_and_aliases(prefix, name_in_module=suffix),<EOL>)<EOL><DEDENT>else:<EOL><INDENT>results = itertools.chain(<EOL>self.__complete_alias(text),<EOL>self.__complete_imports_and_aliases(text),<EOL>self.__complete_interns(text),<EOL>self.__complete_refers(text),<EOL>)<EOL><DEDENT>return results<EOL>

Return an iterable of possible completions for the given text in
        this namespace.


@property<EOL><INDENT>def args(self) -> Tuple:<DEDENT>

if not self._has_varargs:<EOL><INDENT>return self._args<EOL><DEDENT>try:<EOL><INDENT>final = self._args[-<NUM_LIT:1>]<EOL>if isinstance(final, ISeq):<EOL><INDENT>inits = self._args[:-<NUM_LIT:1>]<EOL>return tuple(itertools.chain(inits, final))<EOL><DEDENT>return self._args<EOL><DEDENT>except IndexError:<EOL><INDENT>return ()<EOL><DEDENT>

Return the arguments for a trampolined function. If the function
        that is being trampolined has varargs, unroll the final argument if
        it is a sequence.


return List(  <EOL>plist(iterable=members), meta=meta<EOL>)<EOL>


try:<EOL><INDENT>i = iter(s)<EOL>return _Sequence(i, next(i))<EOL><DEDENT>except StopIteration:<EOL><INDENT>return EMPTY<EOL><DEDENT>


def multifn(dispatch: DispatchFunction, default=None) -> MultiFunction[T]:

name = sym.symbol(dispatch.__qualname__, ns=dispatch.__module__)<EOL>return MultiFunction(name, dispatch, default)<EOL>

Decorator function which can be used to make Python multi functions.


@staticmethod<EOL><INDENT>def __add_method(m: lmap.Map, key: T, method: Method) -> lmap.Map:<DEDENT>

return m.assoc(key, method)<EOL>

Swap the methods atom to include method with key.


def add_method(self, key: T, method: Method) -> None:

self._methods.swap(MultiFunction.__add_method, key, method)<EOL>

Add a new method to this function which will respond for
        key returned from the dispatch function.


def get_method(self, key: T) -> Optional[Method]:

method_cache = self.methods<EOL>return Maybe(method_cache.entry(key, None)).or_else(<EOL>lambda: method_cache.entry(self._default, None)  <EOL>)<EOL>

Return the method which would handle this dispatch key or
        None if no method defined for this key and no default.


@staticmethod<EOL><INDENT>def __remove_method(m: lmap.Map, key: T) -> lmap.Map:<DEDENT>

return m.dissoc(key)<EOL>

Swap the methods atom to remove method with key.


def remove_method(self, key: T) -> Optional[Method]:

method = self.methods.entry(key, None)<EOL>if method:<EOL><INDENT>self._methods.swap(MultiFunction.__remove_method, key)<EOL><DEDENT>return method<EOL>

Remove the method defined for this key and return it.


self._methods.reset(lmap.Map.empty())<EOL>

Remove all methods defined for this multi-function.


@property<EOL><INDENT>@abstractmethod<EOL>def op(self) -> NodeOp:<DEDENT>

Enumerated keyword uniquely identifying this type of Node.

        The type and NodeOp should always be in sync.

        Having a simple enum value in addition to the type allows us to use
        switch-like syntax with Python dictionaries in compiler code, which
        is much faster than performing isinstance checks.


@property<EOL><INDENT>@abstractmethod<EOL>def form(self) -> T:<DEDENT>

The original Lisp form corresponding to this Node.


@property<EOL><INDENT>@abstractmethod<EOL>def children(self) -> Iterable[kw.Keyword]:<DEDENT>

An iterable of keywords naming the attributes on the node which
        contain child nodes used for visiting all nodes in a tree.

        In most cases, children are safely defaulted at class definition.
        For certain nodes, the children may be variable and must be set at
        construction.

        Initially, this property was typed as a typing.Collection. In practice,
        children is always a Vector. However, MyPy seems to have trouble
        identifying IPersistentVector-typed attributes as typing.Collection, so
        this type was set as typing.Iterable which seems to work for now.


@property<EOL><INDENT>@abstractmethod<EOL>def raw_forms(self) -> IPersistentVector[LispForm]:<DEDENT>

A collection of intermediate forms produced by macros before emitting
        the final form.

        As with children above, this was formerly a more generic typing.Collection
        type, but MyPy was returning an error. If this error is ever fixed,
        this should be returned to a more protocol type.


@property<EOL><INDENT>@abstractmethod<EOL>def top_level(self) -> bool:<DEDENT>

True if this node is the root of the entire syntax tree, False
        otherwise.

        In practice, things such as def forms will end up being top level nodes,
        though at the REPL even something simple like a Const node could be top
        level.


@property<EOL><INDENT>@abstractmethod<EOL>def env(self) -> "<STR_LIT>":<DEDENT>

Details about the environment of the original form such as line and
        column numbers.


def visit(self, f: Callable[..., None], *args, **kwargs):

for child_kw in self.children:<EOL><INDENT>child_attr = munge(child_kw.name)<EOL>if child_attr.endswith("<STR_LIT:s>"):<EOL><INDENT>iter_child: Iterable[Node] = getattr(self, child_attr)<EOL>assert iter_child is not None, "<STR_LIT>"<EOL>for item in iter_child:<EOL><INDENT>f(item, *args, **kwargs)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>child: Node = getattr(self, child_attr)<EOL>assert child is not None, "<STR_LIT>"<EOL>f(child, *args, **kwargs)<EOL><DEDENT><DEDENT>

Visit all immediate children of this node, calling
        f(child, *args, **kwargs) on each child.


def fix_missing_locations(<EOL>self, start_loc: Optional[Tuple[int, int]] = None<EOL>) -> "<STR_LIT>":

if self.env.line is None or self.env.col is None:<EOL><INDENT>loc = start_loc<EOL><DEDENT>else:<EOL><INDENT>loc = (self.env.line, self.env.col)<EOL><DEDENT>assert loc is not None and all(<EOL>[e is not None for e in loc]<EOL>), "<STR_LIT>"<EOL>new_attrs: MutableMapping[str, Union[NodeEnv, Node, Iterable[Node]]] = {<EOL>"<STR_LIT>": attr.evolve(self.env, line=loc[<NUM_LIT:0>], col=loc[<NUM_LIT:1>])<EOL>}<EOL>for child_kw in self.children:<EOL><INDENT>child_attr = munge(child_kw.name)<EOL>assert child_attr != "<STR_LIT>", "<STR_LIT>"<EOL>if child_attr.endswith("<STR_LIT:s>"):<EOL><INDENT>iter_child: Iterable[Node] = getattr(self, child_attr)<EOL>assert iter_child is not None, "<STR_LIT>"<EOL>new_children = []<EOL>for item in iter_child:<EOL><INDENT>new_children.append(item.fix_missing_locations(start_loc))<EOL><DEDENT>new_attrs[child_attr] = vec.vector(new_children)<EOL><DEDENT>else:<EOL><INDENT>child: Node = getattr(self, child_attr)<EOL>assert child is not None, "<STR_LIT>"<EOL>new_attrs[child_attr] = child.fix_missing_locations(start_loc)<EOL><DEDENT><DEDENT>return self.assoc(**new_attrs)<EOL>

Return a transformed copy of this node with location in this node's
        environment updated to match the `start_loc` if given, or using its
        existing location otherwise. All child nodes will be recursively
        transformed and replaced. Child nodes will use their parent node
        location if they do not have one.


@property<EOL><INDENT>@abstractmethod<EOL>def is_assignable(self) -> bool:<DEDENT>

True if this Node can be assigned in a set! form, False otherwise.


def _filter_dead_code(nodes: Iterable[ast.AST]) -> List[ast.AST]:

new_nodes: List[ast.AST] = []<EOL>for node in nodes:<EOL><INDENT>if isinstance(node, (ast.Break, ast.Continue, ast.Return)):<EOL><INDENT>new_nodes.append(node)<EOL>break<EOL><DEDENT>new_nodes.append(node)<EOL><DEDENT>return new_nodes<EOL>

Return a list of body nodes, trimming out unreachable code (any
    statements appearing after `break`, `continue`, and `return` nodes).


def visit_ExceptHandler(self, node: ast.ExceptHandler) -> Optional[ast.AST]:

new_node = self.generic_visit(node)<EOL>assert isinstance(new_node, ast.ExceptHandler)<EOL>return ast.copy_location(<EOL>ast.ExceptHandler(<EOL>type=new_node.type,<EOL>name=new_node.name,<EOL>body=_filter_dead_code(new_node.body),<EOL>),<EOL>new_node,<EOL>)<EOL>

Eliminate dead code from except handler bodies.


def visit_Expr(self, node: ast.Expr) -> Optional[ast.Expr]:

if isinstance(<EOL>node.value,<EOL>(<EOL>ast.Constant,  <EOL>ast.Name,<EOL>ast.NameConstant,<EOL>ast.Num,<EOL>ast.Str,<EOL>),<EOL>):<EOL><INDENT>return None<EOL><DEDENT>return node<EOL>

Eliminate no-op constant expressions which are in the tree
        as standalone statements.


def visit_FunctionDef(self, node: ast.FunctionDef) -> Optional[ast.AST]:

Eliminate dead code from function bodies.


def visit_If(self, node: ast.If) -> Optional[ast.AST]:

new_node = self.generic_visit(node)<EOL>assert isinstance(new_node, ast.If)<EOL>return ast.copy_location(<EOL>ast.If(<EOL>test=new_node.test,<EOL>body=_filter_dead_code(new_node.body),<EOL>orelse=_filter_dead_code(new_node.orelse),<EOL>),<EOL>new_node,<EOL>)<EOL>

Eliminate dead code from if/elif bodies.


def visit_While(self, node: ast.While) -> Optional[ast.AST]:

new_node = self.generic_visit(node)<EOL>assert isinstance(new_node, ast.While)<EOL>return ast.copy_location(<EOL>ast.While(<EOL>test=new_node.test,<EOL>body=_filter_dead_code(new_node.body),<EOL>orelse=_filter_dead_code(new_node.orelse),<EOL>),<EOL>new_node,<EOL>)<EOL>


def visit_Try(self, node: ast.Try) -> Optional[ast.AST]:

Eliminate dead code from except try bodies.


return (  <EOL>Maybe(o.meta)<EOL>.map(lambda m: m.entry(SYM_ASYNC_META_KEY, None))<EOL>.or_else_get(False)<EOL>)<EOL>

Return True if the meta contains :async keyword.


return (<EOL>Maybe(v.meta)<EOL>.map(lambda m: m.entry(SYM_MACRO_META_KEY, None))  <EOL>.or_else_get(False)<EOL>)<EOL>

Return True if the Var holds a macro function.


def _loc(form: Union[LispForm, ISeq]) -> Optional[Tuple[int, int]]:

try:<EOL><INDENT>meta = form.meta  <EOL>line = meta.get(reader.READER_LINE_KW)  <EOL>col = meta.get(reader.READER_COL_KW)  <EOL><DEDENT>except AttributeError:<EOL><INDENT>return None<EOL><DEDENT>else:<EOL><INDENT>assert isinstance(line, int) and isinstance(col, int)<EOL>return line, col<EOL><DEDENT>

Fetch the location of the form in the original filename from the
    input form, if it has metadata.


@wraps(f)<EOL>def _parse_form(ctx: ParserContext, form: Union[LispForm, ISeq]) -> Node:<EOL><INDENT>form_loc = _loc(form)<EOL>if form_loc is None:<EOL><INDENT>return f(ctx, form)<EOL><DEDENT>else:<EOL><INDENT>return f(ctx, form).fix_missing_locations(form_loc)<EOL><DEDENT><DEDENT>return _parse_form<EOL>

Attach any available location information from the input form to
    the node environment returned from the parsing function.


def _clean_meta(meta: Optional[lmap.Map]) -> Optional[lmap.Map]:

if meta is None:<EOL><INDENT>return None<EOL><DEDENT>else:<EOL><INDENT>new_meta = meta.dissoc(reader.READER_LINE_KW, reader.READER_COL_KW)<EOL>return None if len(new_meta) == <NUM_LIT:0> else new_meta<EOL><DEDENT>

Remove reader metadata from the form's meta map.


@wraps(gen_node)<EOL>def with_meta(<EOL>ctx: ParserContext,<EOL>form: Union[llist.List, lmap.Map, ISeq, lset.Set, vec.Vector],<EOL>) -> Node:<EOL><INDENT>assert not ctx.is_quoted, "<STR_LIT>"<EOL>descriptor = gen_node(ctx, form)<EOL>if isinstance(form, IMeta):<EOL><INDENT>assert isinstance(form.meta, (lmap.Map, type(None)))<EOL>form_meta = _clean_meta(form.meta)<EOL>if form_meta is not None:<EOL><INDENT>meta_ast = _parse_ast(ctx, form_meta)<EOL>assert isinstance(meta_ast, MapNode) or (<EOL>isinstance(meta_ast, Const) and meta_ast.type == ConstType.MAP<EOL>)<EOL>return WithMeta(<EOL>form=form, meta=meta_ast, expr=descriptor, env=ctx.get_node_env()<EOL>)<EOL><DEDENT><DEDENT>return descriptor<EOL><DEDENT>return with_meta<EOL>

Wraps the node generated by gen_node in a :with-meta AST node if the
    original form has meta.

    :with-meta AST nodes are used for non-quoted collection literals and for
    function expressions.


def __deftype_impls(  <EOL>ctx: ParserContext, form: ISeq<EOL>) -> Tuple[List[DefTypeBase], List[Method]]:

current_interface_sym: Optional[sym.Symbol] = None<EOL>current_interface: Optional[DefTypeBase] = None<EOL>interfaces = []<EOL>methods: List[Method] = []<EOL>interface_methods: MutableMapping[sym.Symbol, List[Method]] = {}<EOL>for elem in form:<EOL><INDENT>if isinstance(elem, sym.Symbol):<EOL><INDENT>if current_interface is not None:<EOL><INDENT>if current_interface_sym in interface_methods:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>",<EOL>form=elem,<EOL>)<EOL><DEDENT>assert (<EOL>current_interface_sym is not None<EOL>), "<STR_LIT>"<EOL>interface_methods[current_interface_sym] = methods<EOL><DEDENT>current_interface_sym = elem<EOL>current_interface = _parse_ast(ctx, elem)<EOL>methods = []<EOL>if not isinstance(current_interface, (MaybeClass, MaybeHostForm, VarRef)):<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>",<EOL>form=elem,<EOL>)<EOL><DEDENT>interfaces.append(current_interface)<EOL><DEDENT>elif isinstance(elem, ISeq):<EOL><INDENT>if current_interface is None:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>", form=elem<EOL>)<EOL><DEDENT>methods.append(__deftype_method(ctx, elem, current_interface))<EOL><DEDENT>else:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>",<EOL>form=elem,<EOL>)<EOL><DEDENT><DEDENT>if current_interface is not None:<EOL><INDENT>if len(methods) > <NUM_LIT:0>:<EOL><INDENT>if current_interface_sym in interface_methods:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>",<EOL>form=current_interface_sym,<EOL>)<EOL><DEDENT>assert (<EOL>current_interface_sym is not None<EOL>), "<STR_LIT>"<EOL>interface_methods[current_interface_sym] = methods<EOL><DEDENT>else:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>",<EOL>form=current_interface_sym,<EOL>)<EOL><DEDENT><DEDENT>return interfaces, list(chain.from_iterable(interface_methods.values()))<EOL>

Roll up deftype* declared bases and method implementations.


def _assert_no_recur(node: Node) -> None:

if node.op == NodeOp.RECUR:<EOL><INDENT>raise ParserException(<EOL>"<STR_LIT>", form=node.form, lisp_ast=node<EOL>)<EOL><DEDENT>elif node.op in {NodeOp.FN, NodeOp.LOOP}:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>node.visit(_assert_no_recur)<EOL><DEDENT>

Assert that `recur` forms do not appear in any position of this or
    child AST nodes.


def _assert_recur_is_tail(node: Node) -> None:

if node.op == NodeOp.DO:<EOL><INDENT>assert isinstance(node, Do)<EOL>for child in node.statements:<EOL><INDENT>_assert_no_recur(child)<EOL><DEDENT>_assert_recur_is_tail(node.ret)<EOL><DEDENT>elif node.op in {NodeOp.FN, NodeOp.FN_METHOD, NodeOp.METHOD}:<EOL><INDENT>assert isinstance(node, (Fn, FnMethod, Method))<EOL>node.visit(_assert_recur_is_tail)<EOL><DEDENT>elif node.op == NodeOp.IF:<EOL><INDENT>assert isinstance(node, If)<EOL>_assert_no_recur(node.test)<EOL>_assert_recur_is_tail(node.then)<EOL>_assert_recur_is_tail(node.else_)<EOL><DEDENT>elif node.op in {NodeOp.LET, NodeOp.LETFN}:<EOL><INDENT>assert isinstance(node, (Let, LetFn))<EOL>for binding in node.bindings:<EOL><INDENT>assert binding.init is not None<EOL>_assert_no_recur(binding.init)<EOL><DEDENT>_assert_recur_is_tail(node.body)<EOL><DEDENT>elif node.op == NodeOp.LOOP:<EOL><INDENT>assert isinstance(node, Loop)<EOL>for binding in node.bindings:<EOL><INDENT>assert binding.init is not None<EOL>_assert_no_recur(binding.init)<EOL><DEDENT><DEDENT>elif node.op == NodeOp.RECUR:<EOL><INDENT>pass<EOL><DEDENT>elif node.op == NodeOp.TRY:<EOL><INDENT>assert isinstance(node, Try)<EOL>_assert_recur_is_tail(node.body)<EOL>for catch in node.catches:<EOL><INDENT>_assert_recur_is_tail(catch)<EOL><DEDENT>if node.finally_:<EOL><INDENT>_assert_no_recur(node.finally_)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>node.visit(_assert_no_recur)<EOL><DEDENT>

Assert that `recur` forms only appear in the tail position of this
    or child AST nodes.

    `recur` forms may only appear in `do` nodes (both literal and synthetic
    `do` nodes) and in either the :then or :else expression of an `if` node.


def __resolve_namespaced_symbol(  <EOL>ctx: ParserContext, form: sym.Symbol<EOL>) -> Union[MaybeClass, MaybeHostForm, VarRef]:

assert form.ns is not None<EOL>if form.ns == ctx.current_ns.name:<EOL><INDENT>v = ctx.current_ns.find(sym.symbol(form.name))<EOL>if v is not None:<EOL><INDENT>return VarRef(form=form, var=v, env=ctx.get_node_env())<EOL><DEDENT><DEDENT>elif form.ns == _BUILTINS_NS:<EOL><INDENT>class_ = munge(form.name, allow_builtins=True)<EOL>target = getattr(builtins, class_, None)<EOL>if target is None:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>", form=form<EOL>)<EOL><DEDENT>return MaybeClass(<EOL>form=form, class_=class_, target=target, env=ctx.get_node_env()<EOL>)<EOL><DEDENT>if "<STR_LIT:.>" in form.name:<EOL><INDENT>raise ParserException(<EOL>"<STR_LIT>", form=form<EOL>)<EOL><DEDENT>ns_sym = sym.symbol(form.ns)<EOL>if ns_sym in ctx.current_ns.imports or ns_sym in ctx.current_ns.import_aliases:<EOL><INDENT>v = Var.find(form)<EOL>if v is not None:<EOL><INDENT>return VarRef(form=form, var=v, env=ctx.get_node_env())<EOL><DEDENT>if ns_sym in ctx.current_ns.import_aliases:<EOL><INDENT>ns = ctx.current_ns.import_aliases[ns_sym]<EOL>assert ns is not None<EOL>ns_name = ns.name<EOL><DEDENT>else:<EOL><INDENT>ns_name = ns_sym.name<EOL><DEDENT>safe_module_name = munge(ns_name)<EOL>assert (<EOL>safe_module_name in sys.modules<EOL>), f"<STR_LIT>"<EOL>ns_module = sys.modules[safe_module_name]<EOL>safe_name = munge(form.name)<EOL>if safe_name in vars(ns_module):<EOL><INDENT>return MaybeHostForm(<EOL>form=form,<EOL>class_=munge(ns_sym.name),<EOL>field=safe_name,<EOL>target=vars(ns_module)[safe_name],<EOL>env=ctx.get_node_env(),<EOL>)<EOL><DEDENT>safe_name = munge(form.name, allow_builtins=True)<EOL>if safe_name not in vars(ns_module):<EOL><INDENT>raise ParserException("<STR_LIT>", form=form)<EOL><DEDENT>return MaybeHostForm(<EOL>form=form,<EOL>class_=munge(ns_sym.name),<EOL>field=safe_name,<EOL>target=vars(ns_module)[safe_name],<EOL>env=ctx.get_node_env(),<EOL>)<EOL><DEDENT>elif ns_sym in ctx.current_ns.aliases:<EOL><INDENT>aliased_ns: runtime.Namespace = ctx.current_ns.aliases[ns_sym]<EOL>v = Var.find(sym.symbol(form.name, ns=aliased_ns.name))<EOL>if v is None:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>",<EOL>form=form,<EOL>)<EOL><DEDENT>return VarRef(form=form, var=v, env=ctx.get_node_env())<EOL><DEDENT>else:<EOL><INDENT>raise ParserException(<EOL>f"<STR_LIT>", form=form<EOL>)<EOL><DEDENT>

Resolve a namespaced symbol into a Python name or Basilisp Var.


def __resolve_bare_symbol(<EOL>ctx: ParserContext, form: sym.Symbol<EOL>) -> Union[MaybeClass, VarRef]:

assert form.ns is None<EOL>v = ctx.current_ns.find(form)<EOL>if v is not None:<EOL><INDENT>return VarRef(form=form, var=v, env=ctx.get_node_env())<EOL><DEDENT>if "<STR_LIT:.>" in form.name:<EOL><INDENT>raise ParserException(<EOL>"<STR_LIT>", form=form<EOL>)<EOL><DEDENT>munged = munge(form.name, allow_builtins=True)<EOL>if munged in vars(builtins):<EOL><INDENT>return MaybeClass(<EOL>form=form,<EOL>class_=munged,<EOL>target=vars(builtins)[munged],<EOL>env=ctx.get_node_env(),<EOL>)<EOL><DEDENT>assert munged not in vars(ctx.current_ns.module)<EOL>raise ParserException(<EOL>f"<STR_LIT>", form=form<EOL>)<EOL>

Resolve a non-namespaced symbol into a Python name or a local
    Basilisp Var.


def _resolve_sym(<EOL>ctx: ParserContext, form: sym.Symbol<EOL>) -> Union[MaybeClass, MaybeHostForm, VarRef]:

<EOL>if form.ns is None and form.name.endswith("<STR_LIT:.>"):<EOL><INDENT>try:<EOL><INDENT>ns, name = form.name[:-<NUM_LIT:1>].rsplit("<STR_LIT:.>", maxsplit=<NUM_LIT:1>)<EOL>form = sym.symbol(name, ns=ns)<EOL><DEDENT>except ValueError:<EOL><INDENT>form = sym.symbol(form.name[:-<NUM_LIT:1>])<EOL><DEDENT><DEDENT>if form.ns is not None:<EOL><INDENT>return __resolve_namespaced_symbol(ctx, form)<EOL><DEDENT>else:<EOL><INDENT>return __resolve_bare_symbol(ctx, form)<EOL><DEDENT>

Resolve a Basilisp symbol as a Var or Python name.


def parse_ast(ctx: ParserContext, form: ReaderForm) -> Node:

return _parse_ast(ctx, form).assoc(top_level=True)<EOL>

Take a Lisp form as an argument and produce a Basilisp syntax
    tree matching the clojure.tools.analyzer AST spec.


def mark_used(self, s: sym.Symbol) -> None:

if s in self._table:<EOL><INDENT>old: SymbolTableEntry = self._table[s]<EOL>if old.used:<EOL><INDENT>return<EOL><DEDENT>self._table[s] = attr.evolve(old, used=True)<EOL><DEDENT>elif self._parent is not None:<EOL><INDENT>self._parent.mark_used(s)<EOL><DEDENT>else:  <EOL><INDENT>assert False, f"<STR_LIT>"<EOL><DEDENT>

Mark the symbol s used in the current table or the first ancestor table
        which contains the symbol.


assert logger.isEnabledFor(<EOL>logging.WARNING<EOL>), "<STR_LIT>"<EOL>ns = runtime.get_current_ns()<EOL>for _, entry in self._table.items():<EOL><INDENT>if entry.symbol in _NO_WARN_UNUSED_SYMS:<EOL><INDENT>continue<EOL><DEDENT>if entry.warn_if_unused and not entry.used:<EOL><INDENT>code_loc = (<EOL>Maybe(entry.symbol.meta)<EOL>.map(<EOL>lambda m: f"<STR_LIT>"  <EOL>)<EOL>.or_else_get("<STR_LIT>")<EOL>)<EOL>logger.warning(<EOL>f"<STR_LIT>"<EOL>)<EOL><DEDENT><DEDENT>

Log a warning message for locally bound names whose values are not used
        by the time the symbol table frame is being popped off the stack.

        The symbol table contains locally-bound symbols, recur point symbols, and
        symbols bound to var-args in generated Python functions. Only the locally-
        bound symbols are eligible for an unused warning, since it is not common
        that recur points will be used and user code is not permitted to directly
        access the var-args symbol (the compiler inserts an intermediate symbol
        which user code uses).

        Warnings will not be issued for symbols named '_', '&form', and '&env'. The
        latter symbols appear in macros and a great many macros will never use them.


@contextlib.contextmanager<EOL><INDENT>def new_frame(self, name, warn_on_unused_names):<DEDENT>

new_frame = self.append_frame(name, parent=self)<EOL>yield new_frame<EOL>if warn_on_unused_names and logger.isEnabledFor(logging.WARNING):<EOL><INDENT>new_frame._warn_unused_names()<EOL><DEDENT>self.pop_frame(name)<EOL>

Context manager for creating a new stack frame. If warn_on_unused_names is
        True and the logger is enabled for WARNING, call _warn_unused_names() on the
        child SymbolTable before it is popped.


return lmap.map(self._as_env_map())<EOL>

Return a map of symbols to the local binding objects in the
        local symbol table as of this call.


@property<EOL><INDENT>def warn_on_unused_names(self) -> bool:<DEDENT>

return self._opts.entry(WARN_ON_UNUSED_NAMES, True)<EOL>

If True, warn when local names are unused.


@property<EOL><INDENT>def warn_on_shadowed_name(self) -> bool:<DEDENT>

return self._opts.entry(WARN_ON_SHADOWED_NAME, False)<EOL>

If True, warn when a name is shadowed in an inner scope.

        Implies warn_on_shadowed_var.


@property<EOL><INDENT>def warn_on_shadowed_var(self) -> bool:<DEDENT>

return self.warn_on_shadowed_name or self._opts.entry(<EOL>WARN_ON_SHADOWED_VAR, False<EOL>)<EOL>

If True, warn when a def'ed Var name is shadowed in an inner scope.

        Implied by warn_on_shadowed_name. The value of warn_on_shadowed_name
        supersedes the value of this flag.


def put_new_symbol(  <EOL>self,<EOL>s: sym.Symbol,<EOL>binding: Binding,<EOL>warn_on_shadowed_name: bool = True,<EOL>warn_on_shadowed_var: bool = True,<EOL>warn_if_unused: bool = True,<EOL>):

st = self.symbol_table<EOL>if warn_on_shadowed_name and self.warn_on_shadowed_name:<EOL><INDENT>if st.find_symbol(s) is not None:<EOL><INDENT>logger.warning(f"<STR_LIT>")<EOL><DEDENT><DEDENT>if (<EOL>warn_on_shadowed_name or warn_on_shadowed_var<EOL>) and self.warn_on_shadowed_var:<EOL><INDENT>if self.current_ns.find(s) is not None:<EOL><INDENT>logger.warning(f"<STR_LIT>")<EOL><DEDENT><DEDENT>if s.meta is not None and s.meta.entry(SYM_NO_WARN_WHEN_UNUSED_META_KEY, None):<EOL><INDENT>warn_if_unused = False<EOL><DEDENT>st.new_symbol(s, binding, warn_if_unused=warn_if_unused)<EOL>

Add a new symbol to the symbol table.

        This function allows individual warnings to be disabled for one run
        by supplying keyword arguments temporarily disabling those warnings.
        In certain cases, we do not want to issue warnings again for a
        previously checked case, so this is a simple way of disabling these
        warnings for those cases.

        If WARN_ON_SHADOWED_NAME compiler option is active and the
        warn_on_shadowed_name keyword argument is True, then a warning will be
        emitted if a local name is shadowed by another local name. Note that
        WARN_ON_SHADOWED_NAME implies WARN_ON_SHADOWED_VAR.

        If WARN_ON_SHADOWED_VAR compiler option is active and the
        warn_on_shadowed_var keyword argument is True, then a warning will be
        emitted if a named var is shadowed by a local name.


return codegen.to_source(t)<EOL>

Return a string of the Python code which would generate the input
    AST node.


def _emit_ast_string(module: ast.AST) -> None:

<EOL>if os.getenv("<STR_LIT>", "<STR_LIT:true>") != "<STR_LIT:true>":<EOL><INDENT>return<EOL><DEDENT>if runtime.print_generated_python():<EOL><INDENT>print(to_py_str(module))<EOL><DEDENT>else:<EOL><INDENT>runtime.add_generated_python(to_py_str(module))<EOL><DEDENT>

Emit the generated Python AST string either to standard out or to the
    *generated-python* dynamic Var for the current namespace. If the
    BASILISP_EMIT_GENERATED_PYTHON env var is not set True, this method is a
    no-op.


def compile_and_exec_form(  <EOL>form: ReaderForm,<EOL>ctx: CompilerContext,<EOL>module: types.ModuleType,<EOL>wrapped_fn_name: str = _DEFAULT_FN,<EOL>collect_bytecode: Optional[BytecodeCollector] = None,<EOL>) -> Any:

if form is None:<EOL><INDENT>return None<EOL><DEDENT>if not module.__basilisp_bootstrapped__:  <EOL><INDENT>_bootstrap_module(ctx.generator_context, ctx.py_ast_optimizer, module)<EOL><DEDENT>final_wrapped_name = genname(wrapped_fn_name)<EOL>lisp_ast = parse_ast(ctx.parser_context, form)<EOL>py_ast = gen_py_ast(ctx.generator_context, lisp_ast)<EOL>form_ast = list(<EOL>map(<EOL>_statementize,<EOL>itertools.chain(<EOL>py_ast.dependencies,<EOL>[_expressionize(GeneratedPyAST(node=py_ast.node), final_wrapped_name)],<EOL>),<EOL>)<EOL>)<EOL>ast_module = ast.Module(body=form_ast)<EOL>ast_module = ctx.py_ast_optimizer.visit(ast_module)<EOL>ast.fix_missing_locations(ast_module)<EOL>_emit_ast_string(ast_module)<EOL>bytecode = compile(ast_module, ctx.filename, "<STR_LIT>")<EOL>if collect_bytecode:<EOL><INDENT>collect_bytecode(bytecode)<EOL><DEDENT>exec(bytecode, module.__dict__)<EOL>return getattr(module, final_wrapped_name)()<EOL>

Compile and execute the given form. This function will be most useful
    for the REPL and testing purposes. Returns the result of the executed expression.

    Callers may override the wrapped function name, which is used by the
    REPL to evaluate the result of an expression and print it back out.


def _incremental_compile_module(<EOL>optimizer: PythonASTOptimizer,<EOL>py_ast: GeneratedPyAST,<EOL>mod: types.ModuleType,<EOL>source_filename: str,<EOL>collect_bytecode: Optional[BytecodeCollector] = None,<EOL>) -> None:

module_body = list(<EOL>map(_statementize, itertools.chain(py_ast.dependencies, [py_ast.node]))<EOL>)<EOL>module = ast.Module(body=list(module_body))<EOL>module = optimizer.visit(module)<EOL>ast.fix_missing_locations(module)<EOL>_emit_ast_string(module)<EOL>bytecode = compile(module, source_filename, "<STR_LIT>")<EOL>if collect_bytecode:<EOL><INDENT>collect_bytecode(bytecode)<EOL><DEDENT>exec(bytecode, mod.__dict__)<EOL>

Incrementally compile a stream of AST nodes in module mod.

    The source_filename will be passed to Python's native compile.

    Incremental compilation is an integral part of generating a Python module
    during the same process as macro-expansion.


def _bootstrap_module(<EOL>gctx: GeneratorContext,<EOL>optimizer: PythonASTOptimizer,<EOL>mod: types.ModuleType,<EOL>collect_bytecode: Optional[BytecodeCollector] = None,<EOL>) -> None:

Bootstrap a new module with imports and other boilerplate.


def compile_module(<EOL>forms: Iterable[ReaderForm],<EOL>ctx: CompilerContext,<EOL>module: types.ModuleType,<EOL>collect_bytecode: Optional[BytecodeCollector] = None,<EOL>) -> None:

_bootstrap_module(ctx.generator_context, ctx.py_ast_optimizer, module)<EOL>for form in forms:<EOL><INDENT>nodes = gen_py_ast(ctx.generator_context, parse_ast(ctx.parser_context, form))<EOL>_incremental_compile_module(<EOL>ctx.py_ast_optimizer,<EOL>nodes,<EOL>module,<EOL>source_filename=ctx.filename,<EOL>collect_bytecode=collect_bytecode,<EOL>)<EOL><DEDENT>

Compile an entire Basilisp module into Python bytecode which can be
    executed as a Python module.

    This function is designed to generate bytecode which can be used for the
    Basilisp import machinery, to allow callers to import Basilisp modules from
    Python code.


def compile_bytecode(<EOL>code: List[types.CodeType],<EOL>gctx: GeneratorContext,<EOL>optimizer: PythonASTOptimizer,<EOL>module: types.ModuleType,<EOL>) -> None:

_bootstrap_module(gctx, optimizer, module)<EOL>for bytecode in code:<EOL><INDENT>exec(bytecode, module.__dict__)<EOL><DEDENT>

Compile cached bytecode into the given module.

    The Basilisp import hook attempts to cache bytecode while compiling Basilisp
    namespaces. When the cached bytecode is reloaded from disk, it needs to be
    compiled within a bootstrapped module. This function bootstraps the module
    and then proceeds to compile a collection of bytecodes into the module.


def _chain_py_ast(*genned: GeneratedPyAST,) -> Tuple[PyASTStream, PyASTStream]:

deps = chain.from_iterable(map(lambda n: n.dependencies, genned))<EOL>nodes = map(lambda n: n.node, genned)<EOL>return deps, nodes<EOL>

Chain a sequence of generated Python ASTs into a tuple of dependency nodes


def _load_attr(name: str, ctx: ast.AST = ast.Load()) -> ast.Attribute:

attrs = name.split("<STR_LIT:.>")<EOL>def attr_node(node, idx):<EOL><INDENT>if idx >= len(attrs):<EOL><INDENT>node.ctx = ctx<EOL>return node<EOL><DEDENT>return attr_node(<EOL>ast.Attribute(value=node, attr=attrs[idx], ctx=ast.Load()), idx + <NUM_LIT:1><EOL>)<EOL><DEDENT>return attr_node(ast.Name(id=attrs[<NUM_LIT:0>], ctx=ast.Load()), <NUM_LIT:1>)<EOL>

Generate recursive Python Attribute AST nodes for resolving nested
    names.


@wraps(gen_ast)<EOL>def wrapped_ast_generator(ctx: GeneratorContext, form: LispForm) -> GeneratedPyAST:<EOL><INDENT>return GeneratedPyAST(node=gen_ast(ctx, form))<EOL><DEDENT>return wrapped_ast_generator<EOL>

Wrap simpler AST generators to return a GeneratedPyAST.


def _collection_ast(<EOL>ctx: GeneratorContext, form: Iterable[Node]<EOL>) -> Tuple[PyASTStream, PyASTStream]:

return _chain_py_ast(*map(partial(gen_py_ast, ctx), form))<EOL>

Turn a collection of Lisp forms into Python AST nodes.


def _clean_meta(form: IMeta) -> LispForm:

assert form.meta is not None, "<STR_LIT>"<EOL>meta = form.meta.dissoc(reader.READER_LINE_KW, reader.READER_COL_KW)<EOL>if len(meta) == <NUM_LIT:0>:<EOL><INDENT>return None<EOL><DEDENT>return cast(lmap.Map, meta)<EOL>

Remove reader metadata from the form's meta map.


def _ast_with_loc(<EOL>py_ast: GeneratedPyAST, env: NodeEnv, include_dependencies: bool = False<EOL>) -> GeneratedPyAST:

if env.line is not None:<EOL><INDENT>py_ast.node.lineno = env.line<EOL>if include_dependencies:<EOL><INDENT>for dep in py_ast.dependencies:<EOL><INDENT>dep.lineno = env.line<EOL><DEDENT><DEDENT><DEDENT>if env.col is not None:<EOL><INDENT>py_ast.node.col_offset = env.col<EOL>if include_dependencies:<EOL><INDENT>for dep in py_ast.dependencies:<EOL><INDENT>dep.col_offset = env.col<EOL><DEDENT><DEDENT><DEDENT>return py_ast<EOL>

Hydrate Generated Python AST nodes with line numbers and column offsets
    if they exist in the node environment.


@wraps(f)<EOL>def with_lineno_and_col(<EOL>ctx: GeneratorContext, node: Node, *args, **kwargs<EOL>) -> GeneratedPyAST:<EOL><INDENT>py_ast = f(ctx, node, *args, **kwargs)<EOL>return _ast_with_loc(py_ast, node.env)<EOL><DEDENT>return with_lineno_and_col<EOL>

Wrap a generator function in a decorator to supply line and column
    information to the returned Python AST node. Dependency nodes will not
    be hydrated, functions whose returns need dependency nodes to be
    hydrated should use `_with_ast_loc_deps` below.


@wraps(f)<EOL>def with_lineno_and_col(<EOL>ctx: GeneratorContext, node: Node, *args, **kwargs<EOL>) -> GeneratedPyAST:<EOL><INDENT>py_ast = f(ctx, node, *args, **kwargs)<EOL>return _ast_with_loc(py_ast, node.env, include_dependencies=True)<EOL><DEDENT>return with_lineno_and_col<EOL>

Wrap a generator function in a decorator to supply line and column
    information to the returned Python AST node and dependency nodes.

    Dependency nodes should likely only be included if they are new nodes
    created in the same function wrapped by this function. Otherwise, dependencies
    returned from e.g. calling `gen_py_ast` should be assumed to already have
    their location information hydrated.


return (<EOL>Maybe(v.meta)<EOL>.map(lambda m: m.get(SYM_DYNAMIC_META_KEY, None))  <EOL>.or_else_get(False)<EOL>)<EOL>

Return True if the Var holds a value which should be compiled to a dynamic
    Var access.


return (<EOL>Maybe(v.meta)<EOL>.map(lambda m: m.get(SYM_REDEF_META_KEY, None))  <EOL>.or_else_get(False)<EOL>)<EOL>

Return True if the Var can be redefined.


def statementize(e: ast.AST) -> ast.AST:

Transform non-statements into ast.Expr nodes so they can
    stand alone as statements.


def expressionize(<EOL>body: GeneratedPyAST,<EOL>fn_name: str,<EOL>args: Optional[Iterable[ast.arg]] = None,<EOL>vargs: Optional[ast.arg] = None,<EOL>) -> ast.FunctionDef:

args = Maybe(args).or_else_get([])<EOL>body_nodes: List[ast.AST] = list(map(statementize, body.dependencies))<EOL>body_nodes.append(ast.Return(value=body.node))<EOL>return ast.FunctionDef(<EOL>name=fn_name,<EOL>args=ast.arguments(<EOL>args=args,<EOL>kwarg=None,<EOL>vararg=vargs,<EOL>kwonlyargs=[],<EOL>defaults=[],<EOL>kw_defaults=[],<EOL>),<EOL>body=body_nodes,<EOL>decorator_list=[],<EOL>returns=None,<EOL>)<EOL>

Given a series of expression AST nodes, create a function AST node
    with the given name that can be called and will return the result of
    the final expression in the input body nodes.

    This helps to fix the impedance mismatch of Python, which includes
    statements and expressions, and Lisps, which have only expressions.


def __should_warn_on_redef(<EOL>ctx: GeneratorContext, defsym: sym.Symbol, safe_name: str, def_meta: lmap.Map<EOL>) -> bool:

no_warn_on_redef = def_meta.entry(SYM_NO_WARN_ON_REDEF_META_KEY, False)<EOL>if no_warn_on_redef:<EOL><INDENT>return False<EOL><DEDENT>elif safe_name in ctx.current_ns.module.__dict__:<EOL><INDENT>return True<EOL><DEDENT>elif defsym in ctx.current_ns.interns:<EOL><INDENT>var = ctx.current_ns.find(defsym)<EOL>assert var is not None, f"<STR_LIT>"<EOL>if var.meta is not None and var.meta.entry(SYM_REDEF_META_KEY):<EOL><INDENT>return False<EOL><DEDENT>elif var.is_bound:<EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT>

Return True if the compiler should emit a warning about this name being redefined.


@_with_ast_loc<EOL>def _def_to_py_ast(  <EOL>ctx: GeneratorContext, node: Def<EOL>) -> GeneratedPyAST:

assert node.op == NodeOp.DEF<EOL>defsym = node.name<EOL>is_defn = False<EOL>if node.init is not None:<EOL><INDENT>if node.init.op == NodeOp.FN:<EOL><INDENT>assert isinstance(node.init, Fn)<EOL>def_ast = _fn_to_py_ast(ctx, node.init, def_name=defsym.name)<EOL>is_defn = True<EOL><DEDENT>elif (<EOL>node.init.op == NodeOp.WITH_META<EOL>and isinstance(node.init, WithMeta)<EOL>and node.init.expr.op == NodeOp.FN<EOL>):<EOL><INDENT>assert isinstance(node.init, WithMeta)<EOL>def_ast = _with_meta_to_py_ast(ctx, node.init, def_name=defsym.name)<EOL>is_defn = True<EOL><DEDENT>else:<EOL><INDENT>def_ast = gen_py_ast(ctx, node.init)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>def_ast = GeneratedPyAST(node=ast.NameConstant(None))<EOL><DEDENT>ns_name = ast.Call(func=_NEW_SYM_FN_NAME, args=[_NS_VAR_NAME], keywords=[])<EOL>def_name = ast.Call(func=_NEW_SYM_FN_NAME, args=[ast.Str(defsym.name)], keywords=[])<EOL>safe_name = munge(defsym.name)<EOL>assert node.meta is not None, "<STR_LIT>"<EOL>def_meta = node.meta.form<EOL>assert isinstance(def_meta, lmap.Map), "<STR_LIT>"<EOL>is_dynamic = def_meta.entry(SYM_DYNAMIC_META_KEY, False)<EOL>dynamic_kwarg = (<EOL>[ast.keyword(arg="<STR_LIT>", value=ast.NameConstant(is_dynamic))]<EOL>if is_dynamic<EOL>else []<EOL>)<EOL>if __should_warn_on_redef(ctx, defsym, safe_name, def_meta):<EOL><INDENT>logger.warning(<EOL>f"<STR_LIT>"<EOL>)<EOL><DEDENT>meta_ast = gen_py_ast(ctx, node.meta)<EOL>if is_defn:<EOL><INDENT>def_dependencies = list(<EOL>chain(<EOL>[] if node.top_level else [ast.Global(names=[safe_name])],<EOL>def_ast.dependencies,<EOL>[] if meta_ast is None else meta_ast.dependencies,<EOL>)<EOL>)<EOL><DEDENT>else:<EOL><INDENT>def_dependencies = list(<EOL>chain(<EOL>def_ast.dependencies,<EOL>[] if node.top_level else [ast.Global(names=[safe_name])],<EOL>[<EOL>ast.Assign(<EOL>targets=[ast.Name(id=safe_name, ctx=ast.Store())],<EOL>value=def_ast.node,<EOL>)<EOL>],<EOL>[] if meta_ast is None else meta_ast.dependencies,<EOL>)<EOL>)<EOL><DEDENT>return GeneratedPyAST(<EOL>node=ast.Call(<EOL>func=_INTERN_VAR_FN_NAME,<EOL>args=[ns_name, def_name, ast.Name(id=safe_name, ctx=ast.Load())],<EOL>keywords=list(<EOL>chain(<EOL>dynamic_kwarg,<EOL>[]<EOL>if meta_ast is None<EOL>else [ast.keyword(arg="<STR_LIT>", value=meta_ast.node)],<EOL>)<EOL>),<EOL>),<EOL>dependencies=def_dependencies,<EOL>)<EOL>

Return a Python AST Node for a `def` expression.


@_with_ast_loc<EOL>def _deftype_to_py_ast(  <EOL>ctx: GeneratorContext, node: DefType<EOL>) -> GeneratedPyAST:

assert node.op == NodeOp.DEFTYPE<EOL>type_name = munge(node.name)<EOL>ctx.symbol_table.new_symbol(sym.symbol(node.name), type_name, LocalType.DEFTYPE)<EOL>bases = []<EOL>for base in node.interfaces:<EOL><INDENT>base_node = gen_py_ast(ctx, base)<EOL>assert (<EOL>count(base_node.dependencies) == <NUM_LIT:0><EOL>), "<STR_LIT>"<EOL>bases.append(base_node.node)<EOL><DEDENT>decorator = ast.Call(<EOL>func=_ATTR_CLASS_DECORATOR_NAME,<EOL>args=[],<EOL>keywords=[<EOL>ast.keyword(arg="<STR_LIT>", value=ast.NameConstant(False)),<EOL>ast.keyword(arg="<STR_LIT>", value=ast.NameConstant(node.is_frozen)),<EOL>ast.keyword(arg="<STR_LIT>", value=ast.NameConstant(True)),<EOL>],<EOL>)<EOL>with ctx.new_symbol_table(node.name):<EOL><INDENT>type_nodes = []<EOL>for field in node.fields:<EOL><INDENT>safe_field = munge(field.name)<EOL>type_nodes.append(<EOL>ast.Assign(<EOL>targets=[ast.Name(id=safe_field, ctx=ast.Store())],<EOL>value=ast.Call(func=_ATTRIB_FIELD_FN_NAME, args=[], keywords=[]),<EOL>)<EOL>)<EOL>ctx.symbol_table.new_symbol(sym.symbol(field.name), safe_field, field.local)<EOL><DEDENT>type_deps: List[ast.AST] = []<EOL>for method in node.methods:<EOL><INDENT>type_ast = __deftype_method_to_py_ast(ctx, method)<EOL>type_nodes.append(type_ast.node)<EOL>type_deps.extend(type_ast.dependencies)<EOL><DEDENT>return GeneratedPyAST(<EOL>node=ast.Name(id=type_name, ctx=ast.Load()),<EOL>dependencies=list(<EOL>chain(<EOL>type_deps,<EOL>[<EOL>ast.ClassDef(<EOL>name=type_name,<EOL>bases=bases,<EOL>keywords=[],<EOL>body=type_nodes,<EOL>decorator_list=[decorator],<EOL>)<EOL>],<EOL>)<EOL>),<EOL>)<EOL><DEDENT>

Return a Python AST Node for a `deftype*` expression.


@_with_ast_loc_deps<EOL>def _do_to_py_ast(ctx: GeneratorContext, node: Do) -> GeneratedPyAST:

assert node.op == NodeOp.DO<EOL>assert not node.is_body<EOL>body_ast = GeneratedPyAST.reduce(<EOL>*map(partial(gen_py_ast, ctx), chain(node.statements, [node.ret]))<EOL>)<EOL>fn_body_ast: List[ast.AST] = []<EOL>do_result_name = genname(_DO_PREFIX)<EOL>fn_body_ast.extend(map(statementize, body_ast.dependencies))<EOL>fn_body_ast.append(<EOL>ast.Assign(<EOL>targets=[ast.Name(id=do_result_name, ctx=ast.Store())], value=body_ast.node<EOL>)<EOL>)<EOL>return GeneratedPyAST(<EOL>node=ast.Name(id=do_result_name, ctx=ast.Load()), dependencies=fn_body_ast<EOL>)<EOL>

Return a Python AST Node for a `do` expression.


@_with_ast_loc<EOL>def _synthetic_do_to_py_ast(ctx: GeneratorContext, node: Do) -> GeneratedPyAST:

assert node.op == NodeOp.DO<EOL>assert node.is_body<EOL>return GeneratedPyAST.reduce(<EOL>*map(partial(gen_py_ast, ctx), chain(node.statements, [node.ret]))<EOL>)<EOL>

Return AST elements generated from reducing a synthetic Lisp :do node
    (e.g. a :do node which acts as a body for another node).


return genname("<STR_LIT>" + munge(Maybe(s).or_else_get(_FN_PREFIX)))<EOL>

Generate a safe Python function name from a function name symbol.
    If no symbol is provided, generate a name with a default prefix.


def __fn_args_to_py_ast(<EOL>ctx: GeneratorContext, params: Iterable[Binding], body: Do<EOL>) -> Tuple[List[ast.arg], Optional[ast.arg], List[ast.AST]]:

fn_args, varg = [], None<EOL>fn_body_ast: List[ast.AST] = []<EOL>for binding in params:<EOL><INDENT>assert binding.init is None, "<STR_LIT>"<EOL>assert varg is None, "<STR_LIT>"<EOL>arg_name = genname(munge(binding.name))<EOL>if not binding.is_variadic:<EOL><INDENT>fn_args.append(ast.arg(arg=arg_name, annotation=None))<EOL>ctx.symbol_table.new_symbol(<EOL>sym.symbol(binding.name), arg_name, LocalType.ARG<EOL>)<EOL><DEDENT>else:<EOL><INDENT>varg = ast.arg(arg=arg_name, annotation=None)<EOL>safe_local = genname(munge(binding.name))<EOL>fn_body_ast.append(<EOL>ast.Assign(<EOL>targets=[ast.Name(id=safe_local, ctx=ast.Store())],<EOL>value=ast.Call(<EOL>func=_COLLECT_ARGS_FN_NAME,<EOL>args=[ast.Name(id=arg_name, ctx=ast.Load())],<EOL>keywords=[],<EOL>),<EOL>)<EOL>)<EOL>ctx.symbol_table.new_symbol(<EOL>sym.symbol(binding.name), safe_local, LocalType.ARG<EOL>)<EOL><DEDENT><DEDENT>body_ast = _synthetic_do_to_py_ast(ctx, body)<EOL>fn_body_ast.extend(map(statementize, body_ast.dependencies))<EOL>fn_body_ast.append(ast.Return(value=body_ast.node))<EOL>return fn_args, varg, fn_body_ast<EOL>

Generate a list of Python AST nodes from function method parameters.