<commit_before>from thinglang.execution.errors import UnknownVariable
from thinglang.lexer.tokens.base import LexicalIdentifier
from thinglang.parser.symbols.functions import Access

UNRESOLVABLE_REFERENCE = object()


class Resolver(object):

    def __init__(self, stack, heap):
        self.stack, self.heap = stack, heap

    def resolve(self, identifier):
        if isinstance(identifier, LexicalIdentifier):
            if identifier in self.stack:
                return self.stack[identifier]

            if identifier in self.heap:
                return self.heap[identifier]

            self.validate(identifier, UNRESOLVABLE_REFERENCE)

        if identifier[0].is_self():
            return self.validate(identifier, self.search(identifier[1:], self.stack.instance))

        stack_value = self.search(identifier, self.stack)
        if stack_value is not UNRESOLVABLE_REFERENCE:
            return stack_value

        return self.validate(identifier, self.search(identifier, self.heap))

    @staticmethod
    def search(identifier, context):
        for component in identifier:
            if component not in context:
                return UNRESOLVABLE_REFERENCE

            context = context[component]

        return context

    def validate(self, identifier, value):
        if value is UNRESOLVABLE_REFERENCE:
            raise UnknownVariable(f'Cannot find reference {identifier} in stack={self.stack}, heap={self.heap}')
        return value

    def set(self, key, value):
        if isinstance(key, Access):
            container = self.resolve(key[:-1])
            container[key[-1]] = value
        else:
            self.stack[key] = value<commit_msg>Added option to resolve references without throwing an exception<commit_after>from thinglang.execution.errors import UnresolvedReference
from thinglang.lexer.tokens.base import LexicalIdentifier
from thinglang.parser.symbols.functions import Access




class Resolver(object):

    UNRESOLVED_REFERENCE = object()

    def __init__(self, stack, heap):
        self.stack, self.heap = stack, heap

    def resolve(self, identifier):
        return self.validate(identifier, self.lookup(identifier))

    def lookup(self, identifier):
        if isinstance(identifier, LexicalIdentifier):
            if identifier in self.stack:
                return self.stack[identifier]

            if identifier in self.heap:
                return self.heap[identifier]

            return self.UNRESOLVED_REFERENCE

        if identifier[0].is_self():
            return self.search(identifier[1:], self.stack.instance)

        stack_value = self.search(identifier, self.stack)
        if stack_value is not self.UNRESOLVED_REFERENCE:
            return stack_value

        return self.search(identifier, self.heap)

    @classmethod
    def search(cls, identifier, context):
        for component in identifier:
            if component not in context:
                return cls.UNRESOLVED_REFERENCE

            context = context[component]

        return context

    def validate(self, identifier, value):
        if value is self.UNRESOLVED_REFERENCE:
            raise UnresolvedReference(f'Cannot find reference {identifier} in stack={self.stack}, heap={self.heap}')
        return value

    def set(self, key, value):
        if isinstance(key, Access):
            container = self.resolve(key[:-1])
            container[key[-1]] = value
        else:
            self.stack[key] = value
{'fraction_non_alphanumeric': 0.08330939385234128, 'fraction_numerical': 0.002298190175237001, 'mean_word_length': 2.5896907216494847, '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': '4309869', 'n_tokens_mistral': 920, 'n_tokens_neox': 885, 'n_words': 242}