Blame lib/dbtexmf/dblatex/grubber/texparser.py

Packit Service 76cb02
# This file is part of Rubber and thus covered by the GPL
Packit Service 76cb02
# (c) Emmanuel Beffara, 2002--2006
Packit Service 76cb02
"""
Packit Service 76cb02
LaTeX document building system for Rubber.
Packit Service 76cb02
Packit Service 76cb02
This module defines the class that parses the input LaTeX to load the expected
Packit Service 76cb02
modules.
Packit Service 76cb02
"""
Packit Service 76cb02
import re
Packit Service 76cb02
Packit Service 76cb02
class TexParser:
Packit Service 76cb02
    re_input = re.compile("\\\\input +(?P<arg>[^{} \n\\\\]+)")
Packit Service 76cb02
    re_comment = re.compile(r"(?P<line>([^\\%]|\\%|\\)*)(%.*)?")
Packit Service 76cb02
Packit Service 76cb02
    def __init__(self, doc):
Packit Service 76cb02
        self.doc = doc
Packit Service 76cb02
        self.comment_mark = "%"
Packit Service 76cb02
        self.exclude_mods = []
Packit Service 76cb02
        self.hooks = {
Packit Service 76cb02
            "usepackage"   : self.h_usepackage,
Packit Service 76cb02
            "begin{btSect}": self.h_bibtopic,
Packit Service 76cb02
        }
Packit Service 76cb02
        self.update_rehooks()
Packit Service 76cb02
Packit Service 76cb02
    def update_rehooks(self):
Packit Service 76cb02
        """
Packit Service 76cb02
        Update the regular expression used to match macro calls using the keys
Packit Service 76cb02
        in the `hook' dictionary. We don't match all control sequences for
Packit Service 76cb02
        obvious efficiency reasons.
Packit Service 76cb02
        """
Packit Service 76cb02
        # Make a "foo|bar\*stub" list
Packit Service 76cb02
        hooklist = [x.replace("*", "\\*") for x in self.hooks]
Packit Service 76cb02
Packit Service 76cb02
        pattern = "\\\\(?P<name>%s)\*?"\
Packit Service 76cb02
                  " *(\\[(?P<opt>[^\\]]*)\\])?"\
Packit Service 76cb02
                  " *({(?P<arg>[^{}]*)}|(?=[^A-Za-z]))"
Packit Service 76cb02
Packit Service 76cb02
        self.rehooks = re.compile(pattern % "|".join(hooklist))
Packit Service 76cb02
Packit Service 76cb02
    def add_hook(self, name, fun):
Packit Service 76cb02
        """
Packit Service 76cb02
        Register a given function to be called (with no arguments) when a
Packit Service 76cb02
        given macro is found.
Packit Service 76cb02
        """
Packit Service 76cb02
        self.hooks[name] = fun
Packit Service 76cb02
        self.update_rehooks()
Packit Service 76cb02
Packit Service 76cb02
    def parse(self, fd, exclude_mods=None):
Packit Service 76cb02
        """
Packit Service 76cb02
        Process a LaTeX source. The file must be open, it is read to the end
Packit Service 76cb02
        calling the handlers for the macro calls. This recursively processes
Packit Service 76cb02
        the included sources.
Packit Service 76cb02
Packit Service 76cb02
        If the optional argument 'dump' is not None, then it is considered as
Packit Service 76cb02
        a stream on which all text not matched as a macro is written.
Packit Service 76cb02
        """
Packit Service 76cb02
        self.exclude_mods = exclude_mods or []
Packit Service 76cb02
        self.lineno = 0
Packit Service 76cb02
        for line in fd:
Packit Service 76cb02
            self.parse_line(line)
Packit Service 76cb02
Packit Service 76cb02
    def parse_line(self, line, dump=None):
Packit Service 76cb02
        self.lineno += 1
Packit Service 76cb02
Packit Service 76cb02
        # Remove comments
Packit Service 76cb02
        line = self.re_comment.match(line).group("line")
Packit Service 76cb02
Packit Service 76cb02
        match = self.rehooks.search(line)
Packit Service 76cb02
        while match:
Packit Service 76cb02
            dict = match.groupdict()
Packit Service 76cb02
            name = dict["name"]
Packit Service 76cb02
            
Packit Service 76cb02
            # The case of \input is handled specifically, because of the
Packit Service 76cb02
            # TeX syntax with no braces
Packit Service 76cb02
Packit Service 76cb02
            if name == "input" and not dict["arg"]:
Packit Service 76cb02
                match2 = self.re_input.search(line)
Packit Service 76cb02
                if match2:
Packit Service 76cb02
                    match = match2
Packit Service 76cb02
                    dict = match.groupdict()
Packit Service 76cb02
Packit Service 76cb02
            if dump: dump.write(line[:match.start()])
Packit Service 76cb02
            dict["match"] = line[match.start():match.end()]
Packit Service 76cb02
            dict["line"] = line[match.end():]
Packit Service 76cb02
            #dict["pos"] = { 'file': self.vars["file"], 'line': self.lineno }
Packit Service 76cb02
            dict["pos"] = { 'file': "file", 'line': self.lineno }
Packit Service 76cb02
            dict["dump"] = dump
Packit Service 76cb02
Packit Service 76cb02
#            if self.env.caching:
Packit Service 76cb02
#                self.cache_list.append(("hook", name, dict))
Packit Service 76cb02
Packit Service 76cb02
            self.hooks[name](dict)
Packit Service 76cb02
            line = dict["line"]
Packit Service 76cb02
            match = self.rehooks.search(line)
Packit Service 76cb02
Packit Service 76cb02
        if dump: dump.write(line)
Packit Service 76cb02
Packit Service 76cb02
    def h_usepackage(self, dict):
Packit Service 76cb02
        """
Packit Service 76cb02
        Called when a \\usepackage macro is found. If there is a package in the
Packit Service 76cb02
        directory of the source file, then it is treated as an include file
Packit Service 76cb02
        unless there is a supporting module in the current directory,
Packit Service 76cb02
        otherwise it is treated as a package.
Packit Service 76cb02
        """
Packit Service 76cb02
        if not dict["arg"]: return
Packit Service 76cb02
        for name in dict["arg"].split(","):
Packit Service 76cb02
            name = name.strip()
Packit Service 76cb02
#            file = self.env.find_file(name + ".sty")
Packit Service 76cb02
#            if file and not exists(name + ".py"):
Packit Service 76cb02
#                self.process(file)
Packit Service 76cb02
#            else:
Packit Service 76cb02
            if (name in self.exclude_mods):
Packit Service 76cb02
                continue
Packit Service 76cb02
            self.doc.modules.register(name, dict)
Packit Service 76cb02
Packit Service 76cb02
    def h_bibtopic(self, dict):
Packit Service 76cb02
        """
Packit Service 76cb02
        Called when a \\btSect macro is found. It can also be loaded by a
Packit Service 76cb02
        usepackage of bibtopic. Note that once loaded the btSect hook will be
Packit Service 76cb02
        preempted by the bibtopic module hook.
Packit Service 76cb02
        """
Packit Service 76cb02
        if ("bibtopic" in self.exclude_mods):
Packit Service 76cb02
            return
Packit Service 76cb02
        self.doc.modules.register("bibtopic", dict)
Packit Service 76cb02