Source code for margate.compiler

"""The compiler module contains the public interface to the library.

"""

import re
import io
from bytecode import Bytecode, Instr

from . import parser, block_parser


[docs]class TemplateLocator: """The template locator abstracts the details of locating templates when one template extends another (such as with the ``{% extends %}`` tag)self. """ def find_template(self, template_name): pass
[docs]class Compiler: """The Compiler takes a template in string form and returns bytecode that implements the template. """ def __init__(self, template_locator=None): if template_locator is None: template_locator = TemplateLocator() self._template_locator = template_locator
[docs] def compile(self, source): """Compile the template source code into a callable function. :return: A callable function that returns rendered content as a string when called. """ bytecode = self._make_bytecode(source, self._template_locator) def inner(**local_scope): local_scope["_output"] = io.StringIO() exec(bytecode, {}, local_scope) return local_scope['_output'].getvalue() return inner
def _get_chunks(self, source): state = block_parser.LiteralState(source) while state: match = re.search(r"\{\{|\}\}|\{%|%\}", state.text) if match is None: (state, chunk) = state.accept_end_input() else: separator = match.group(0) if separator == "{{": action = state.accept_open_expression elif separator == "}}": action = state.accept_close_expression elif separator == "{%": action = state.accept_open_execution elif separator == "%}": action = state.accept_close_execution else: raise Exception("Unrecognised separator") (state, chunk) = action(match.start(0), len(match.group(0))) yield chunk def _make_bytecode(self, source, template_locator): instructions = [] symbol_table = { "write_func": io.StringIO.write } parser_obj = parser.Parser(self._template_locator) sequence = parser_obj.parse(self._get_chunks(source)) for item in sequence.elements: instructions += item.make_bytecode(symbol_table) bytecode = Bytecode(instructions + [Instr("LOAD_CONST", None), Instr("RETURN_VALUE")]) return bytecode.to_code()