<commit_before>from __future__ import print_function

from values import NIL, MinimalispType, Symbol, Value, Pair

from parse import parse_token_prompt 

class Context(dict):
    """stack-like dictionary."""
    def __init__(self, *args, **kwargs):
        # default arg that can only be specified by keyword. Python 3 fixes this problem.
        parent = kwargs.pop('parent', None)
        self.parent = parent
        super(Context, self).__init__(*args, **kwargs)

    def __getitem__(self, key):
        try:
            return super(Context, self).__getitem__(key)
        except KeyError:
            if self.parent is None:
                raise

        return self.parent[key]


class LispRuntimeError(BaseException):
    pass

# evaluate - should be an object or a pair.
def peval(o, context):
    # if object is literal or quoted:
    if isinstance(o, Value) or (isinstance(o, Pair) and o.quoted):
        return o

    # if object is a bound symbol, substitute its value:
    if isinstance(o, Symbol):
        if o.quoted:
            return o
        return context[o]

    # if o is a function:
    if isinstance(o, LispFunction):
        raise LispRuntimeError("cannot evaluate a function")

    # in other cases, o must be a pair.
    if not isinstance(o, Pair):
        raise LispRuntimeError("cannot evaluate %s", o)
    pair = o

    # in which case, if we have been asked to run a function!
    # note that if 
    if isinstance(pair.left, Symbol):
        try:
            function = context[pair.left]
        except KeyError:
            raise LispRuntimeError("unbound symbol %s" % pair.left)

        if not isinstance(function, LispFunction):
            raise LispRuntimeError("symbol %s is not bound to a function, but %s" % (repr(pair.left), repr(function)))
    elif isinstance(pair.left, Pair):
        # pair.left is a pair, it is important to eval it and check we get a function, rather than dying here.
        function = peval(pair.left, context)

        if not isinstance(function, LispFunction):
            raise LispRuntimeError("result %s cannot be executed as a function" % repr(function))

    return function.execute(pair.right, context)


class LispFunction(MinimalispType):
    pass


class UserLispFunction(LispFunction):
    def __init__(self, argbindings, functionbody):
        self.argbindings = argbindings

        # functionbody should be copied into a new head pair, minus the quoted status.
        self.functionbody = Pair(functionbody.left, functionbody.right)

    def execute(self, ap, outer_context):
        # initialise a new context, with arguments bound to names specified (or NIL if none passed):
        context = Context(parent=outer_context)
        ab = self.argbindings
        while type(ab) is not NIL:
            try:
                context[ab.left] = ap.left
            except AttributeError:
                context[ab.left] = NIL()
            ab = ab.right<commit_msg>fixing bug in WITH implementation (arguments bound to values, not symbols passed)<commit_after>from __future__ import print_function

from values import NIL, MinimalispType, Symbol, Value, Pair

from parse import parse_token_prompt 

class Context(dict):
    """stack-like dictionary."""
    def __init__(self, *args, **kwargs):
        # default arg that can only be specified by keyword. Python 3 fixes this problem.
        parent = kwargs.pop('parent', None)
        self.parent = parent
        super(Context, self).__init__(*args, **kwargs)

    def __getitem__(self, key):
        try:
            return super(Context, self).__getitem__(key)
        except KeyError:
            if self.parent is None:
                raise

        return self.parent[key]


class LispRuntimeError(BaseException):
    pass

# evaluate - should be an object or a pair.
def peval(o, context):
    # if object is literal or quoted:
    if isinstance(o, Value) or (isinstance(o, Pair) and o.quoted):
        return o

    # if object is a bound symbol, substitute its value:
    if isinstance(o, Symbol):
        if o.quoted:
            return o
        return context[o]

    # if o is a function:
    if isinstance(o, LispFunction):
        raise LispRuntimeError("cannot evaluate a function")

    # in other cases, o must be a pair.
    if not isinstance(o, Pair):
        raise LispRuntimeError("cannot evaluate %s", o)
    pair = o

    # in which case, if we have been asked to run a function!
    # note that if 
    if isinstance(pair.left, Symbol):
        try:
            function = context[pair.left]
        except KeyError:
            raise LispRuntimeError("unbound symbol %s" % pair.left)

        if not isinstance(function, LispFunction):
            raise LispRuntimeError("symbol %s is not bound to a function, but %s" % (repr(pair.left), repr(function)))
    elif isinstance(pair.left, Pair):
        # pair.left is a pair, it is important to eval it and check we get a function, rather than dying here.
        function = peval(pair.left, context)

        if not isinstance(function, LispFunction):
            raise LispRuntimeError("result %s cannot be executed as a function" % repr(function))

    return function.execute(pair.right, context)


class LispFunction(MinimalispType):
    pass


class UserLispFunction(LispFunction):
    def __init__(self, argbindings, functionbody):
        self.argbindings = argbindings

        # functionbody should be copied into a new head pair, minus the quoted status.
        self.functionbody = Pair(functionbody.left, functionbody.right)

    def execute(self, ap, outer_context):
        # initialise a new context, with arguments bound to names specified (or NIL if none passed):
        context = Context(parent=outer_context)
        ab = self.argbindings
        while type(ab) is not NIL:
            try:
                if isinstance(ap.left, Symbol) and not ap.left.quoted:
                    context[ab.left] = context[ap.left]
                else:
                    context[ab.left] = ap.left
            except AttributeError:
                context[ab.left] = NIL()
            except KeyError:
                raise ValueError("cannot bind argument %s which is unbound in outer scope." % repr(ap.left))
            ab = ab.right
{'fraction_non_alphanumeric': 0.08550423525651271, 'fraction_numerical': 0.000319642000958926, 'mean_word_length': 2.5, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '1096392', 'n_tokens_mistral': 1752, 'n_tokens_neox': 1683, 'n_words': 623}