diff env/lib/python3.7/site-packages/docutils/utils/math/latex2mathml.py @ 5:9b1c78e6ba9c draft default tip

"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author shellac
date Mon, 01 Jun 2020 08:59:25 -0400
parents 79f47841a781
children
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/docutils/utils/math/latex2mathml.py	Thu May 14 16:47:39 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,568 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# :Id: $Id: latex2mathml.py 8366 2019-08-27 12:09:19Z milde $
-# :Copyright: © 2010 Günter Milde.
-#             Based on rst2mathml.py from the latex_math sandbox project
-#             © 2005 Jens Jørgen Mortensen
-# :License: Released under the terms of the `2-Clause BSD license`_, in short:
-#
-#    Copying and distribution of this file, with or without modification,
-#    are permitted in any medium without royalty provided the copyright
-#    notice and this notice are preserved.
-#    This file is offered as-is, without any warranty.
-#
-# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
-
-
-"""Convert LaTex math code into presentational MathML"""
-
-# Based on the `latex_math` sandbox project by Jens Jørgen Mortensen
-
-import docutils.utils.math.tex2unichar as tex2unichar
-
-#        TeX      spacing    combining
-over = {'acute':    u'\u00B4', # u'\u0301',
-        'bar':      u'\u00AF', # u'\u0304',
-        'breve':    u'\u02D8', # u'\u0306',
-        'check':    u'\u02C7', # u'\u030C',
-        'dot':      u'\u02D9', # u'\u0307',
-        'ddot':     u'\u00A8', # u'\u0308',
-        'dddot':               u'\u20DB',
-        'grave':    u'`',      # u'\u0300',
-        'hat':      u'^',      # u'\u0302',
-        'mathring': u'\u02DA', # u'\u030A',
-        'overleftrightarrow':  u'\u20e1',
-        # 'overline':        # u'\u0305',
-        'tilde':    u'\u02DC', # u'\u0303',
-        'vec':               u'\u20D7'}
-
-Greek = { # Capital Greek letters: (upright in TeX style)
-    'Phi':u'\u03a6', 'Xi':u'\u039e', 'Sigma':u'\u03a3',
-    'Psi':u'\u03a8', 'Delta':u'\u0394', 'Theta':u'\u0398',
-    'Upsilon':u'\u03d2', 'Pi':u'\u03a0', 'Omega':u'\u03a9',
-    'Gamma':u'\u0393', 'Lambda':u'\u039b'}
-
-letters = tex2unichar.mathalpha
-
-special = tex2unichar.mathbin         # Binary symbols
-special.update(tex2unichar.mathrel)   # Relation symbols, arrow symbols
-special.update(tex2unichar.mathord)   # Miscellaneous symbols
-special.update(tex2unichar.mathop)    # Variable-sized symbols
-special.update(tex2unichar.mathopen)  # Braces
-special.update(tex2unichar.mathclose) # Braces
-special.update(tex2unichar.mathfence)
-
-sumintprod = ''.join([special[symbol] for symbol in
-                      ['sum', 'int', 'oint', 'prod']])
-
-functions = ['arccos', 'arcsin', 'arctan', 'arg', 'cos',  'cosh',
-             'cot',    'coth',   'csc',    'deg', 'det',  'dim',
-             'exp',    'gcd',    'hom',    'inf', 'ker',  'lg',
-             'lim',    'liminf', 'limsup', 'ln',  'log',  'max',
-             'min',    'Pr',     'sec',    'sin', 'sinh', 'sup',
-             'tan',    'tanh',
-             'injlim',  'varinjlim', 'varlimsup',
-             'projlim', 'varliminf', 'varprojlim']
-
-
-mathbb = {
-          'A': u'\U0001D538',
-          'B': u'\U0001D539',
-          'C': u'\u2102',
-          'D': u'\U0001D53B',
-          'E': u'\U0001D53C',
-          'F': u'\U0001D53D',
-          'G': u'\U0001D53E',
-          'H': u'\u210D',
-          'I': u'\U0001D540',
-          'J': u'\U0001D541',
-          'K': u'\U0001D542',
-          'L': u'\U0001D543',
-          'M': u'\U0001D544',
-          'N': u'\u2115',
-          'O': u'\U0001D546',
-          'P': u'\u2119',
-          'Q': u'\u211A',
-          'R': u'\u211D',
-          'S': u'\U0001D54A',
-          'T': u'\U0001D54B',
-          'U': u'\U0001D54C',
-          'V': u'\U0001D54D',
-          'W': u'\U0001D54E',
-          'X': u'\U0001D54F',
-          'Y': u'\U0001D550',
-          'Z': u'\u2124',
-         }
-
-mathscr = {
-           'A': u'\U0001D49C',
-           'B': u'\u212C',     # bernoulli function
-           'C': u'\U0001D49E',
-           'D': u'\U0001D49F',
-           'E': u'\u2130',
-           'F': u'\u2131',
-           'G': u'\U0001D4A2',
-           'H': u'\u210B',     # hamiltonian
-           'I': u'\u2110',
-           'J': u'\U0001D4A5',
-           'K': u'\U0001D4A6',
-           'L': u'\u2112',     # lagrangian
-           'M': u'\u2133',     # physics m-matrix
-           'N': u'\U0001D4A9',
-           'O': u'\U0001D4AA',
-           'P': u'\U0001D4AB',
-           'Q': u'\U0001D4AC',
-           'R': u'\u211B',
-           'S': u'\U0001D4AE',
-           'T': u'\U0001D4AF',
-           'U': u'\U0001D4B0',
-           'V': u'\U0001D4B1',
-           'W': u'\U0001D4B2',
-           'X': u'\U0001D4B3',
-           'Y': u'\U0001D4B4',
-           'Z': u'\U0001D4B5',
-           'a': u'\U0001D4B6',
-           'b': u'\U0001D4B7',
-           'c': u'\U0001D4B8',
-           'd': u'\U0001D4B9',
-           'e': u'\u212F',
-           'f': u'\U0001D4BB',
-           'g': u'\u210A',
-           'h': u'\U0001D4BD',
-           'i': u'\U0001D4BE',
-           'j': u'\U0001D4BF',
-           'k': u'\U0001D4C0',
-           'l': u'\U0001D4C1',
-           'm': u'\U0001D4C2',
-           'n': u'\U0001D4C3',
-           'o': u'\u2134',     # order of
-           'p': u'\U0001D4C5',
-           'q': u'\U0001D4C6',
-           'r': u'\U0001D4C7',
-           's': u'\U0001D4C8',
-           't': u'\U0001D4C9',
-           'u': u'\U0001D4CA',
-           'v': u'\U0001D4CB',
-           'w': u'\U0001D4CC',
-           'x': u'\U0001D4CD',
-           'y': u'\U0001D4CE',
-           'z': u'\U0001D4CF',
-          }
-
-negatables = {'=': u'\u2260',
-              r'\in': u'\u2209',
-              r'\equiv': u'\u2262'}
-
-# LaTeX to MathML translation stuff:
-class math(object):
-    """Base class for MathML elements."""
-
-    nchildren = 1000000
-    """Required number of children"""
-
-    def __init__(self, children=None, inline=None):
-        """math([children]) -> MathML element
-
-        children can be one child or a list of children."""
-
-        self.children = []
-        if children is not None:
-            if isinstance(children, list):
-                for child in children:
-                    self.append(child)
-            else:
-                # Only one child:
-                self.append(children)
-
-        if inline is not None:
-            self.inline = inline
-
-    def __repr__(self):
-        if hasattr(self, 'children'):
-            return self.__class__.__name__ + '(%s)' % \
-                   ','.join([repr(child) for child in self.children])
-        else:
-            return self.__class__.__name__
-
-    def full(self):
-        """Room for more children?"""
-
-        return len(self.children) >= self.nchildren
-
-    def append(self, child):
-        """append(child) -> element
-
-        Appends child and returns self if self is not full or first
-        non-full parent."""
-
-        assert not self.full()
-        self.children.append(child)
-        child.parent = self
-        node = self
-        while node.full():
-            node = node.parent
-        return node
-
-    def delete_child(self):
-        """delete_child() -> child
-
-        Delete last child and return it."""
-
-        child = self.children[-1]
-        del self.children[-1]
-        return child
-
-    def close(self):
-        """close() -> parent
-
-        Close element and return first non-full element."""
-
-        parent = self.parent
-        while parent.full():
-            parent = parent.parent
-        return parent
-
-    def xml(self):
-        """xml() -> xml-string"""
-
-        return self.xml_start() + self.xml_body() + self.xml_end()
-
-    def xml_start(self):
-        if not hasattr(self, 'inline'):
-            return ['<%s>' % self.__class__.__name__]
-        xmlns = 'http://www.w3.org/1998/Math/MathML'
-        if self.inline:
-            return ['<math xmlns="%s">' % xmlns]
-        else:
-            return ['<math xmlns="%s" mode="display">' % xmlns]
-
-    def xml_end(self):
-        return ['</%s>' % self.__class__.__name__]
-
-    def xml_body(self):
-        xml = []
-        for child in self.children:
-            xml.extend(child.xml())
-        return xml
-
-class mrow(math):
-    def xml_start(self):
-        return ['\n<%s>' % self.__class__.__name__]
-
-class mtable(math):
-    def xml_start(self):
-        return ['\n<%s>' % self.__class__.__name__]
-
-class mtr(mrow): pass
-class mtd(mrow): pass
-
-class mx(math):
-    """Base class for mo, mi, and mn"""
-
-    nchildren = 0
-    def __init__(self, data):
-        self.data = data
-
-    def xml_body(self):
-        return [self.data]
-
-class mo(mx):
-    translation = {'<': '&lt;', '>': '&gt;'}
-    def xml_body(self):
-        return [self.translation.get(self.data, self.data)]
-
-class mi(mx): pass
-class mn(mx): pass
-
-class msub(math):
-    nchildren = 2
-
-class msup(math):
-    nchildren = 2
-
-class msqrt(math):
-    nchildren = 1
-
-class mroot(math):
-    nchildren = 2
-
-class mfrac(math):
-    nchildren = 2
-
-class msubsup(math):
-    nchildren = 3
-    def __init__(self, children=None, reversed=False):
-        self.reversed = reversed
-        math.__init__(self, children)
-
-    def xml(self):
-        if self.reversed:
-##            self.children[1:3] = self.children[2:0:-1]
-            self.children[1:3] = [self.children[2], self.children[1]]
-            self.reversed = False
-        return math.xml(self)
-
-class mfenced(math):
-    translation = {'\\{': '{', '\\langle': u'\u2329',
-                   '\\}': '}', '\\rangle': u'\u232A',
-                   '.': ''}
-    def __init__(self, par):
-        self.openpar = par
-        math.__init__(self)
-
-    def xml_start(self):
-        open = self.translation.get(self.openpar, self.openpar)
-        close = self.translation.get(self.closepar, self.closepar)
-        return ['<mfenced open="%s" close="%s">' % (open, close)]
-
-class mspace(math):
-    nchildren = 0
-
-class mstyle(math):
-    def __init__(self, children=None, nchildren=None, **kwargs):
-        if nchildren is not None:
-            self.nchildren = nchildren
-        math.__init__(self, children)
-        self.attrs = kwargs
-
-    def xml_start(self):
-        return ['<mstyle '] + ['%s="%s"' % item
-                               for item in self.attrs.items()] + ['>']
-
-class mover(math):
-    nchildren = 2
-    def __init__(self, children=None, reversed=False):
-        self.reversed = reversed
-        math.__init__(self, children)
-
-    def xml(self):
-        if self.reversed:
-            self.children.reverse()
-            self.reversed = False
-        return math.xml(self)
-
-class munder(math):
-    nchildren = 2
-
-class munderover(math):
-    nchildren = 3
-    def __init__(self, children=None):
-        math.__init__(self, children)
-
-class mtext(math):
-    nchildren = 0
-    def __init__(self, text):
-        self.text = text
-
-    def xml_body(self):
-        return [self.text]
-
-def parse_latex_math(string, inline=True):
-    """parse_latex_math(string [,inline]) -> MathML-tree
-
-    Returns a MathML-tree parsed from string.  inline=True is for
-    inline math and inline=False is for displayed math.
-
-    tree is the whole tree and node is the current element."""
-
-    # Normalize white-space:
-    string = ' '.join(string.split())
-
-    if inline:
-        node = mrow()
-        tree = math(node, inline=True)
-    else:
-        node = mtd()
-        tree = math(mtable(mtr(node)), inline=False)
-
-    while len(string) > 0:
-        n = len(string)
-        c = string[0]
-        skip = 1  # number of characters consumed
-        if n > 1:
-            c2 = string[1]
-        else:
-            c2 = ''
-        if c == ' ':
-            pass
-        elif c == '\\':
-            if c2 in '{}':
-                node = node.append(mo(c2))
-                skip = 2
-            elif c2 == ' ':
-                node = node.append(mspace())
-                skip = 2
-            elif c2 == ',': # TODO: small space
-                node = node.append(mspace())
-                skip = 2
-            elif c2.isalpha():
-                # We have a LaTeX-name:
-                i = 2
-                while i < n and string[i].isalpha():
-                    i += 1
-                name = string[1:i]
-                node, skip = handle_keyword(name, node, string[i:])
-                skip += i
-            elif c2 == '\\':
-                # End of a row:
-                entry = mtd()
-                row = mtr(entry)
-                node.close().close().append(row)
-                node = entry
-                skip = 2
-            else:
-                raise SyntaxError(u'Syntax error: "%s%s"' % (c, c2))
-        elif c.isalpha():
-            node = node.append(mi(c))
-        elif c.isdigit():
-            node = node.append(mn(c))
-        elif c in "+-*/=()[]|<>,.!?':;@":
-            node = node.append(mo(c))
-        elif c == '_':
-            child = node.delete_child()
-            if isinstance(child, msup):
-                sub = msubsup(child.children, reversed=True)
-            elif isinstance(child, mo) and child.data in sumintprod:
-                sub = munder(child)
-            else:
-                sub = msub(child)
-            node.append(sub)
-            node = sub
-        elif c == '^':
-            child = node.delete_child()
-            if isinstance(child, msub):
-                sup = msubsup(child.children)
-            elif isinstance(child, mo) and child.data in sumintprod:
-                sup = mover(child)
-            elif (isinstance(child, munder) and
-                  child.children[0].data in sumintprod):
-                sup = munderover(child.children)
-            else:
-                sup = msup(child)
-            node.append(sup)
-            node = sup
-        elif c == '{':
-            row = mrow()
-            node.append(row)
-            node = row
-        elif c == '}':
-            node = node.close()
-        elif c == '&':
-            entry = mtd()
-            node.close().append(entry)
-            node = entry
-        else:
-            raise SyntaxError(u'Illegal character: "%s"' % c)
-        string = string[skip:]
-    return tree
-
-
-def handle_keyword(name, node, string):
-    skip = 0
-    if len(string) > 0 and string[0] == ' ':
-        string = string[1:]
-        skip = 1
-    if name == 'begin':
-        if not string.startswith('{matrix}'):
-            raise SyntaxError(u'Environment not supported! '
-                              u'Supported environment: "matrix".')
-        skip += 8
-        entry = mtd()
-        table = mtable(mtr(entry))
-        node.append(table)
-        node = entry
-    elif name == 'end':
-        if not string.startswith('{matrix}'):
-            raise SyntaxError(u'Expected "\\end{matrix}"!')
-        skip += 8
-        node = node.close().close().close()
-    elif name in ('text', 'mathrm'):
-        if string[0] != '{':
-            raise SyntaxError(u'Expected "\\text{...}"!')
-        i = string.find('}')
-        if i == -1:
-            raise SyntaxError(u'Expected "\\text{...}"!')
-        node = node.append(mtext(string[1:i]))
-        skip += i + 1
-    elif name == 'sqrt':
-        sqrt = msqrt()
-        node.append(sqrt)
-        node = sqrt
-    elif name == 'frac':
-        frac = mfrac()
-        node.append(frac)
-        node = frac
-    elif name == 'left':
-        for par in ['(', '[', '|', '\\{', '\\langle', '.']:
-            if string.startswith(par):
-                break
-        else:
-            raise SyntaxError(u'Missing left-brace!')
-        fenced = mfenced(par)
-        node.append(fenced)
-        row = mrow()
-        fenced.append(row)
-        node = row
-        skip += len(par)
-    elif name == 'right':
-        for par in [')', ']', '|', '\\}', '\\rangle', '.']:
-            if string.startswith(par):
-                break
-        else:
-            raise SyntaxError(u'Missing right-brace!')
-        node = node.close()
-        node.closepar = par
-        node = node.close()
-        skip += len(par)
-    elif name == 'not':
-        for operator in negatables:
-            if string.startswith(operator):
-                break
-        else:
-            raise SyntaxError(u'Expected something to negate: "\\not ..."!')
-        node = node.append(mo(negatables[operator]))
-        skip += len(operator)
-    elif name == 'mathbf':
-        style = mstyle(nchildren=1, fontweight='bold')
-        node.append(style)
-        node = style
-    elif name == 'mathbb':
-        if string[0] != '{' or not string[1].isupper() or string[2] != '}':
-            raise SyntaxError(u'Expected something like "\\mathbb{A}"!')
-        node = node.append(mi(mathbb[string[1]]))
-        skip += 3
-    elif name in ('mathscr', 'mathcal'):
-        if string[0] != '{' or string[2] != '}':
-            raise SyntaxError(u'Expected something like "\\mathscr{A}"!')
-        node = node.append(mi(mathscr[string[1]]))
-        skip += 3
-    elif name == 'colon': # "normal" colon, not binary operator
-        node = node.append(mo(':')) # TODO: add ``lspace="0pt"``
-    elif name in Greek:   # Greek capitals (upright in "TeX style")
-        node = node.append(mo(Greek[name]))
-        # TODO: "ISO style" sets them italic. Could we use a class argument
-        # to enable styling via CSS?
-    elif name in letters:
-        node = node.append(mi(letters[name]))
-    elif name in special:
-        node = node.append(mo(special[name]))
-    elif name in functions:
-        node = node.append(mo(name))
-    elif name in over:
-        ovr = mover(mo(over[name]), reversed=True)
-        node.append(ovr)
-        node = ovr
-    else:
-        raise SyntaxError(u'Unknown LaTeX command: ' + name)
-
-    return node, skip
-
-def tex2mathml(tex_math, inline=True):
-    """Return string with MathML code corresponding to `tex_math`.
-
-    `inline`=True is for inline math and `inline`=False for displayed math.
-    """
-
-    mathml_tree = parse_latex_math(tex_math, inline=inline)
-    return ''.join(mathml_tree.xml())