# Path: flap/latex/commons.py
# class Context:
# 
#     def __init__(self, parent=None, definitions=None):
#         self._definitions = definitions or dict()
#         self._parent = parent
# 
#     def define(self, macro):
#         logger.debug("Defining macro {}".format(macro.name))
#         self._definitions[macro.name] = macro
# 
#     def look_up(self, symbol):
#         result = self._definitions.get(symbol, None)
#         if not result and self._parent:
#             return self._parent.look_up(symbol)
#         return result
# 
#     @property
#     def available_macros(self):
#         return list(self._definitions.keys())
# 
#     def items(self):
#         return self._definitions.items()
# 
#     def __setitem__(self, key, value):
#         self._definitions[key] = value
# 
#     def __getitem__(self, key):
#         if self._parent and key not in self._definitions:
#             return self._parent[key]
#         else:
#             return self._definitions.get(key)
# 
#     def __contains__(self, key):
#         return key in self._definitions or (
#             self._parent and key in self._parent)
# 
# Path: flap/latex/processor.py
# class Processor:
# 
#     def __init__(self, name, tokens, factory, environment):
#         self._create = factory
#         self._tokens = self._create.as_stream(tokens)
#         self._definitions = environment
#         self._level = 0
#         self._name = name
#         # Outputs
#         self._outputs = [{"is_active": True, "data": []}]
# 
#     def process(self):
#         while not self._tokens.is_empty:
#             token = self._tokens.take()
#             token.send_to(self)
#         self._log("----------- DONE")
#         return self._outputs[-1]["data"]
# 
#     def process_control(self, token):
#         self._default(token)
# 
#     def process_begin_group(self, token):
#         self._default(token)
# 
#     def process_end_group(self, end_group):
#         self._default(end_group)
# 
#     def process_character(self, character):
#         self._default(character)
# 
#     def process_comment(self, comment):
#         self._default(comment)
# 
#     def process_parameter(self, parameter):
#         self._default(parameter)
# 
#     def process_white_spaces(self, space):
#         self._default(space)
# 
#     def process_new_line(self, new_line):
#         self._default(new_line)
# 
#     def process_others(self, other):
#         self._default(other)
# 
#     def process_invocation(self, invocation):
#         self._default(invocation)
# 
#     def _default(self, token):
#         self._log("On " + str(token))
#         self._print([token])
# 
#     # Helpers
# 
#     # Debugging
# 
#     def _log(self, message):
#         logger.debug(self._name + ": " + message)
# 
#     # Methods that manage the output
# 
#     def _print(self, tokens):
#         if self._outputs[-1]["is_active"]:
#             self._outputs[-1]["data"] += tokens
# 
#     def push_new_output(self):
#         self._log("Setup new output")
#         new_output = {"is_active": True, "data": []}
#         self._outputs.append(new_output)
# 
#     def pop_output(self):
#         self._log("Discarding current output: " + self.output_as_text())
#         output = self._outputs.pop()
#         return output["data"]
# 
#     def output_as_text(self):
#         return "".join(each_token.as_text
#                        for each_token in self._outputs[-1]["data"])
# 
#     # Scope and look up
# 
#     def open_scope(self):
#         self._definitions = Context(self._definitions)
# 
#     def close_scope(self):
#         self._definitions = self._definitions._parent
# 
#     def look_up(self, symbol):
#         return self._definitions.look_up(symbol)
# 
#     def find_environment(self, invocation):
#         symbol = "".join(each_token.as_text
#                          for each_token
#                          in invocation.argument("environment")[1:-1])
#         environment = self._definitions.look_up(symbol)
#         return environment
# 
#     def _debug(self, category, action, tokens):
#         text = ""
#         position = "None"
#         if not len(tokens) == 0:
#             text = truncate(self._as_text(tokens), 30)
#             position = tokens[-1].location,
#         logger.debug(
#                 "GL={} {} {} {}".format(
#                     self._level,
#                     action,
#                     category,
#                     text
#                 ))
# 
#     @staticmethod
#     def _as_text(tokens):
#         return "".join(map(str, tokens))


from flap.latex.commons import Context
from flap.latex.processor import Processor
                              self._definitions.available_macros))
            self._print([token])
        else:
            macro = self._definitions[command_name]
            invocation = macro.capture_invocation(self, token)
            self.process_invocation(invocation)

    def process_invocation(self, invocation):
        self._log("On invocation: " + invocation.as_text)
        macro = self.look_up(invocation.command_name)

        if macro.is_user_defined:
            self._log("User defined!")
            self.open_scope()
            for each_argument, tokens in invocation.arguments.items():
                self._log(f"Evaluating argument {each_argument}")
                evaluated = self.evaluate(tokens)
                self._definitions[each_argument] = evaluated
            self._log("Evaluating macro body")
            output = self.evaluate(macro._body)
            self._print(output)
            self.close_scope()

        else:   # Built-in commands
            self._log("Built-in!")
            macro.execute2(self, invocation)

    def evaluate(self, tokens, extra_definitions=None):
        definitions = self._definitions
        if extra_definitions:

# Path: flap/latex/commons.py
# class Context:
# 
#     def __init__(self, parent=None, definitions=None):
#         self._definitions = definitions or dict()
#         self._parent = parent
# 
#     def define(self, macro):
#         logger.debug("Defining macro {}".format(macro.name))
#         self._definitions[macro.name] = macro
# 
#     def look_up(self, symbol):
#         result = self._definitions.get(symbol, None)
#         if not result and self._parent:
#             return self._parent.look_up(symbol)
#         return result
# 
#     @property
#     def available_macros(self):
#         return list(self._definitions.keys())
# 
#     def items(self):
#         return self._definitions.items()
# 
#     def __setitem__(self, key, value):
#         self._definitions[key] = value
# 
#     def __getitem__(self, key):
#         if self._parent and key not in self._definitions:
#             return self._parent[key]
#         else:
#             return self._definitions.get(key)
# 
#     def __contains__(self, key):
#         return key in self._definitions or (
#             self._parent and key in self._parent)
# 
# Path: flap/latex/processor.py
# class Processor:
# 
#     def __init__(self, name, tokens, factory, environment):
#         self._create = factory
#         self._tokens = self._create.as_stream(tokens)
#         self._definitions = environment
#         self._level = 0
#         self._name = name
#         # Outputs
#         self._outputs = [{"is_active": True, "data": []}]
# 
#     def process(self):
#         while not self._tokens.is_empty:
#             token = self._tokens.take()
#             token.send_to(self)
#         self._log("----------- DONE")
#         return self._outputs[-1]["data"]
# 
#     def process_control(self, token):
#         self._default(token)
# 
#     def process_begin_group(self, token):
#         self._default(token)
# 
#     def process_end_group(self, end_group):
#         self._default(end_group)
# 
#     def process_character(self, character):
#         self._default(character)
# 
#     def process_comment(self, comment):
#         self._default(comment)
# 
#     def process_parameter(self, parameter):
#         self._default(parameter)
# 
#     def process_white_spaces(self, space):
#         self._default(space)
# 
#     def process_new_line(self, new_line):
#         self._default(new_line)
# 
#     def process_others(self, other):
#         self._default(other)
# 
#     def process_invocation(self, invocation):
#         self._default(invocation)
# 
#     def _default(self, token):
#         self._log("On " + str(token))
#         self._print([token])
# 
#     # Helpers
# 
#     # Debugging
# 
#     def _log(self, message):
#         logger.debug(self._name + ": " + message)
# 
#     # Methods that manage the output
# 
#     def _print(self, tokens):
#         if self._outputs[-1]["is_active"]:
#             self._outputs[-1]["data"] += tokens
# 
#     def push_new_output(self):
#         self._log("Setup new output")
#         new_output = {"is_active": True, "data": []}
#         self._outputs.append(new_output)
# 
#     def pop_output(self):
#         self._log("Discarding current output: " + self.output_as_text())
#         output = self._outputs.pop()
#         return output["data"]
# 
#     def output_as_text(self):
#         return "".join(each_token.as_text
#                        for each_token in self._outputs[-1]["data"])
# 
#     # Scope and look up
# 
#     def open_scope(self):
#         self._definitions = Context(self._definitions)
# 
#     def close_scope(self):
#         self._definitions = self._definitions._parent
# 
#     def look_up(self, symbol):
#         return self._definitions.look_up(symbol)
# 
#     def find_environment(self, invocation):
#         symbol = "".join(each_token.as_text
#                          for each_token
#                          in invocation.argument("environment")[1:-1])
#         environment = self._definitions.look_up(symbol)
#         return environment
# 
#     def _debug(self, category, action, tokens):
#         text = ""
#         position = "None"
#         if not len(tokens) == 0:
#             text = truncate(self._as_text(tokens), 30)
#             position = tokens[-1].location,
#         logger.debug(
#                 "GL={} {} {} {}".format(
#                     self._level,
#                     action,
#                     category,
#                     text
#                 ))
# 
#     @staticmethod
#     def _as_text(tokens):
#         return "".join(map(str, tokens))


# Path: flap/latex/interpreter.py
from flap.latex.commons import Context
from flap.latex.processor import Processor

                              self._definitions.available_macros))
            self._print([token])
        else:
            macro = self._definitions[command_name]
            invocation = macro.capture_invocation(self, token)
            self.process_invocation(invocation)

    def process_invocation(self, invocation):
        self._log("On invocation: " + invocation.as_text)
        macro = self.look_up(invocation.command_name)

        if macro.is_user_defined:
            self._log("User defined!")
            self.open_scope()
            for each_argument, tokens in invocation.arguments.items():
                self._log(f"Evaluating argument {each_argument}")
                evaluated = self.evaluate(tokens)
                self._definitions[each_argument] = evaluated
            self._log("Evaluating macro body")
            output = self.evaluate(macro._body)
            self._print(output)
            self.close_scope()

        else:   # Built-in commands
            self._log("Built-in!")
            macro.execute2(self, invocation)

    def evaluate(self, tokens, extra_definitions=None):
        definitions = self._definitions
        if extra_definitions:

            definitions = Context(self._definitions, extra_definitions)