Source code for parce.lang.tex

# -*- coding: utf-8 -*-
#
# This file is part of the parce Python package.
#
# Copyright © 2019-2020 by Wilbert Berendsen <info@wilbertberendsen.nl>
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This module is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

"""
TeX and LaTeX.
"""

__all__ = ('Latex',)

import re

from parce import Language, lexicon, default_action
from parce.action import (
    Character, Comment, Delimiter, Escape, Name, Number, Operator, Pseudo, Text)
from parce.rule import arg, MATCH, bygroup, ifgroup, ifmember


MATH_ENVIRONMENTS = (
    "math", "displaymath", "equation", "eqnarray", "aqnarray*")


[docs]class Latex(Language): @lexicon def root(cls): yield from cls.common() yield default_action, Text
[docs] @classmethod def common(cls): yield r'(\\begin)(?:\s*(?:(\{)(.*?)(\})|(\[))|(?=[\W\d]))', \ bygroup(Name.Builtin, Delimiter, Name.Tag, Delimiter, Delimiter.Bracket), \ ifgroup(5, cls.environment_option, cls.get_environment_target(MATCH[3])) yield r'(\\[^\W\d]+)(?:\s*(\[))?', bygroup(Name.Command, Delimiter.Bracket), \ ifgroup(2, cls.option) yield r'\{\\(oe|OE|ae|AE|aa|AA|o|O|l|L|ss|SS)\}', Escape yield r"[!?]'", Escape yield r"""\\[`'^"~=.]([a-zA-Z]{1,2}|\\[ij])(?=[\W\d])""", Escape yield r"""\\[`'^"~=.uvHtcdbr]\{([a-zA-Z]{1,2}|\\[ij])\}""", Escape yield r'\{', Delimiter.Brace, cls.brace yield r'\\\[', Delimiter, cls.math(r'\]') yield r'\$\$', Delimiter, cls.math(r'$$') yield r'\\\(', Delimiter, cls.math(r'\)') yield r'\$', Delimiter, cls.math(r'$') yield from cls.base()
[docs] @classmethod def base(cls): """Basic stuff.""" yield r'\\[#$&~^%{}_ ]', Escape yield r'[&_^~]', Character.Special yield r'\\\\', Delimiter.Terminator # line termination TODO: better action? yield r'%', Comment, cls.comment
@lexicon(consume=True) def brace(cls): yield r'\}', Delimiter.Brace, -1 yield from cls.root @lexicon def option(cls): yield r'(\])(?:\s*(\[))?', Delimiter.Bracket, ifgroup(2, 0, -1) yield from cls.common() yield default_action, Pseudo # TODO: find better action @lexicon def environment_option(cls): yield r'(\])\s*(?:(\{)(.*?)(\})|(\[))?', \ bygroup(Delimiter.Bracket, Delimiter, Name.Tag, Delimiter, Delimiter.Bracket), \ ifgroup(5, 0, (-1, ifgroup(4, cls.get_environment_target(MATCH[3])))) yield from list(cls.option())[1:] # not the first rule @lexicon def environment(cls): yield r'(\\end)(?:\s*(\{)(.*?)(\})|(?=[\W\d]))', \ bygroup(Name.Builtin, Delimiter, Name.Tag, Delimiter), -1 yield from cls.root # ------------------------------ math ------------------------------------ @lexicon def environment_math(cls): yield r'(\\end)(?:\s*(\{)(.*?)(\})|(?=[\W\d]))', \ bygroup(Name.Builtin, Delimiter, Name.Tag, Delimiter), -1 yield from cls.math_common() @lexicon(consume=True) def math(cls): yield arg(default=r'\}'), Delimiter, -1 yield from cls.math_common()
[docs] @classmethod def math_common(cls): """Stuff in math mode.""" yield r'\{', Delimiter.Brace, cls.math yield r"[\-+=<>/:!']", Operator yield r"[\|\[\]\(\)]", Delimiter yield r'\\[A-Za-z]+', Name.Function yield r'[A-Za-z]+', Name.Variable yield r'\d+(?:\.\d+)*', Number yield from cls.base() yield default_action, Text.Math
[docs] @classmethod def get_environment_target(cls, name): """Return environment target for environment ``name``. Can be overridden to support special environments. """ return ifmember(name, MATH_ENVIRONMENTS, cls.environment_math, cls.environment)
# ----------------------------- comments --------------------------------- @lexicon(re_flags=re.MULTILINE, consume=True) def comment(cls): yield '$', None, -1 yield from cls.comment_common()