<commit_before># Author: <NAME>
# Email: <EMAIL>
# Date: 4 December 2011
# Class: CS655

"""
Includes the basic things needed to make the interpreter work. There's some
weirdness in 'cdr' related to the fact that the parser produces non-canonical
lists. This is done for performance and does not affect the user.
"""

from functools import wraps

__all__ = [
    'cons', 'car', 'cdr', 'isnil', 'isatom', 'ispair', 'append',
    'str_list', 'Symbol', 'Environment'
]

class Symbol(str):
    """
    We need to use something string-like for symbols but we want to be able to
    differentiate them using isinstance(thing, type)
    """
    pass

class Environment(object):
    """
    Environments are still represented as association lists. This just wraps
    an association list so closures aren't printing huge lists. Purely
    aesthetic.
    """
    def __init__(self, list):
        self.list = list

    def __repr__(self):
        return "(ENV)"

def type_check(types):
    """Certain functions should check their arguments"""
    def make_decorator(function):
        @wraps(function)
        def checked(*args):
            for thing in args:
                if not isinstance(thing, types):
                    raise TypeError("Wrong argument type")
            return function(*args)
        return checked
    return make_decorator

def cons(a, b):
    """Tuples instantiate fast and have random access"""
    return [a] + b

@type_check(list)
def car(x):
    return x[0]

@type_check(list)
def cdr(x):
    return x[1:]

def isnil(thing):
    return thing == []

def isatom(thing):
    return not isinstance(thing, list)

def ispair(thing):
    if isatom(thing):
        return False
    else:
        first, *rest = thing
        return isatom(first) and not isnil(rest) and isatom(rest)

def isenv(thing):
    return isinstance(thing, Environment)

def str_list(ls, sep=' '):
    """Print lists, atoms, and dotted pairs"""
    out = []
    if isatom(ls):
        if ls is True:
            return '#t'
        elif ls is False:
            return '#f'
        else:
            return str(ls)
    while not isnil(ls):
        if isatom(ls):
            if isenv(ls):
                out.append(str_list(ls))
            else:
                out.append('.' + sep + str_list(ls))
            break
        elif isnil(cdr(ls)):
            out.append(str_list(car(ls)))
        else:
            out.append(str_list(car(ls)) + sep)
        ls = cdr(ls)
    return '(' + ''.join(out) + ')'

@type_check(list)
def append(ls1, ls2):
    return ls1 + ls2<commit_msg>Make type_check() decorator more general.<commit_after># Author: <NAME>
# Email: <EMAIL>
# Date: 4 December 2011
# Class: CS655

"""
Includes the basic things needed to make the interpreter work. There's some
weirdness in 'cdr' related to the fact that the parser produces non-canonical
lists. This is done for performance and does not affect the user.
"""

from functools import wraps

__all__ = [
    'cons', 'car', 'cdr', 'isnil', 'isatom', 'ispair', 'append',
    'str_list', 'Symbol', 'Environment'
]

class Symbol(str):
    """
    We need to use something string-like for symbols but we want to be able to
    differentiate them using isinstance(thing, type)
    """
    pass

class Environment(object):
    """
    Environments are still represented as association lists. This just wraps
    an association list so closures aren't printing huge lists. Purely
    aesthetic.
    """
    def __init__(self, list):
        self.list = list

    def __repr__(self):
        return "(ENV)"

def type_check(*arg_types, **kw_types):
    def make_decorator(function):
        @wraps(function)
        def checked(*args, **kwargs):
            if len(args) != len(arg_types):
                raise TypeError("Wrong number of positional arguments")
            for arg, type in zip(args, arg_types):
                if not isinstance(arg, type):
                    raise TypeError("Wrong argument type")
            for key, value in kwargs.items():
                if key in kw_types and not isinstance(value, kw_types[kw]):
                    raise TypeError("Wrong argument type")
            return function(*args, **kwargs)
        return checked
    return make_decorator


@type_check(object, list)
def cons(a, b):
    return [a] + b

@type_check(list)
def car(x):
    return x[0]

@type_check(list)
def cdr(x):
    return x[1:]

def isnil(thing):
    return thing == []

def isatom(thing):
    return not isinstance(thing, list)

def ispair(thing):
    if isatom(thing):
        return False
    else:
        first, *rest = thing
        return isatom(first) and not isnil(rest) and isatom(rest)

def isenv(thing):
    return isinstance(thing, Environment)

def str_list(ls, sep=' '):
    """Print lists, atoms, and dotted pairs"""
    out = []
    if isatom(ls):
        if ls is True:
            return '#t'
        elif ls is False:
            return '#f'
        else:
            return str(ls)
    while not isnil(ls):
        if isatom(ls):
            if isenv(ls):
                out.append(str_list(ls))
            else:
                out.append('.' + sep + str_list(ls))
            break
        elif isnil(cdr(ls)):
            out.append(str_list(car(ls)))
        else:
            out.append(str_list(car(ls)) + sep)
        ls = cdr(ls)
    return '(' + ''.join(out) + ')'

@type_check(list, list)
def append(ls1, ls2):
    return ls1 + ls2
{'fraction_non_alphanumeric': 0.11568123393316196, 'fraction_numerical': 0.005141388174807198, 'mean_word_length': 2.387437810945274, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5065899', 'n_tokens_mistral': 1701, 'n_tokens_neox': 1639, 'n_words': 544}