|
14 | 14 | import numpy as np
|
15 | 15 | from pyparsing import (
|
16 | 16 | Empty, Forward, Literal, NotAny, oneOf, OneOrMore, Optional,
|
17 |
| - ParseBaseException, ParseFatalException, ParserElement, ParseResults, |
18 |
| - QuotedString, Regex, StringEnd, ZeroOrMore, pyparsing_common) |
| 17 | + ParseBaseException, ParseExpression, ParseFatalException, ParserElement, |
| 18 | + ParseResults, QuotedString, Regex, StringEnd, ZeroOrMore, pyparsing_common) |
19 | 19 |
|
20 | 20 | import matplotlib as mpl
|
21 | 21 | from . import _api, cbook
|
@@ -1559,9 +1559,7 @@ def Error(msg):
|
1559 | 1559 | def raise_error(s, loc, toks):
|
1560 | 1560 | raise ParseFatalException(s, loc, msg)
|
1561 | 1561 |
|
1562 |
| - empty = Empty() |
1563 |
| - empty.setParseAction(raise_error) |
1564 |
| - return empty |
| 1562 | + return Empty().setParseAction(raise_error) |
1565 | 1563 |
|
1566 | 1564 |
|
1567 | 1565 | class ParserState:
|
@@ -1601,6 +1599,31 @@ def get_current_underline_thickness(self):
|
1601 | 1599 | self.font, self.fontsize, self.dpi)
|
1602 | 1600 |
|
1603 | 1601 |
|
| 1602 | +def cmd(expr, args): |
| 1603 | + r""" |
| 1604 | + Helper to define TeX commands. |
| 1605 | +
|
| 1606 | + ``cmd("\cmd", args)`` is equivalent to |
| 1607 | + ``"\cmd" - (args | Error("Expected \cmd{arg}{...}"))`` where the names in |
| 1608 | + the error message are taken from element names in *args*. If *expr* |
| 1609 | + already includes arguments (e.g. "\cmd{arg}{...}"), then they are stripped |
| 1610 | + when constructing the parse element, but kept (and *expr* is used as is) in |
| 1611 | + the error message. |
| 1612 | + """ |
| 1613 | + |
| 1614 | + def names(elt): |
| 1615 | + if isinstance(elt, ParseExpression): |
| 1616 | + for expr in elt.exprs: |
| 1617 | + yield from names(expr) |
| 1618 | + elif elt.resultsName: |
| 1619 | + yield elt.resultsName |
| 1620 | + |
| 1621 | + csname = expr.split("{", 1)[0] |
| 1622 | + err = (csname + "".join("{%s}" % name for name in names(args)) |
| 1623 | + if expr == csname else expr) |
| 1624 | + return csname - (args | Error(f"Expected {err}")) |
| 1625 | + |
| 1626 | + |
1604 | 1627 | class Parser:
|
1605 | 1628 | """
|
1606 | 1629 | A pyparsing-based parser for strings containing math expressions.
|
@@ -1742,69 +1765,60 @@ def set_names_and_parse_actions():
|
1742 | 1765 | p.placeable = Forward()
|
1743 | 1766 | p.required_group = Forward()
|
1744 | 1767 | p.simple = Forward()
|
1745 |
| - p.simple_group = Forward() |
| 1768 | + p.optional_group = Forward() |
1746 | 1769 | p.sqrt = Forward()
|
1747 | 1770 | p.subsuper = Forward()
|
1748 | 1771 | p.token = Forward()
|
1749 | 1772 | p.underset = Forward()
|
1750 | 1773 |
|
1751 | 1774 | set_names_and_parse_actions() # for mutually recursive definitions.
|
1752 | 1775 |
|
1753 |
| - p.customspace <<= r"\hspace" - ( |
1754 |
| - "{" + p.float_literal("space") + "}" |
1755 |
| - | Error(r"Expected \hspace{n}")) |
| 1776 | + p.customspace <<= cmd(r"\hspace", "{" + p.float_literal("space") + "}") |
1756 | 1777 |
|
1757 |
| - p.accent <<= ( |
| 1778 | + p.accent <<= ( |
1758 | 1779 | "\\"
|
1759 | 1780 | + oneOf([*self._accent_map, *self._wide_accents])("accent")
|
1760 | 1781 | - p.placeable("sym"))
|
1761 | 1782 |
|
1762 |
| - p.function <<= "\\" + oneOf(self._function_names)("name") |
1763 |
| - p.operatorname <<= r"\operatorname" - ( |
1764 |
| - "{" + ZeroOrMore(p.simple | p.unknown_symbol)("name") + "}" |
1765 |
| - | Error(r"Expected \operatorname{name}")) |
| 1783 | + p.function <<= "\\" + oneOf(self._function_names)("name") |
| 1784 | + p.operatorname <<= cmd( |
| 1785 | + r"\operatorname", |
| 1786 | + "{" + ZeroOrMore(p.simple | p.unknown_symbol)("name") + "}") |
1766 | 1787 |
|
1767 |
| - p.group <<= ( |
1768 |
| - p.start_group + ZeroOrMore(p.token)("group") + p.end_group) |
| 1788 | + p.group <<= p.start_group + ZeroOrMore(p.token)("group") + p.end_group |
1769 | 1789 |
|
1770 |
| - p.simple_group <<= "{" + ZeroOrMore(p.token)("group") + "}" |
| 1790 | + p.optional_group <<= "{" + ZeroOrMore(p.token)("group") + "}" |
1771 | 1791 | p.required_group <<= "{" + OneOrMore(p.token)("group") + "}"
|
1772 | 1792 |
|
1773 |
| - p.frac <<= r"\frac" - ( |
1774 |
| - p.required_group("num") + p.required_group("den") |
1775 |
| - | Error(r"Expected \frac{num}{den}")) |
1776 |
| - p.dfrac <<= r"\dfrac" - ( |
1777 |
| - p.required_group("num") + p.required_group("den") |
1778 |
| - | Error(r"Expected \dfrac{num}{den}")) |
1779 |
| - p.binom <<= r"\binom" - ( |
1780 |
| - p.required_group("num") + p.required_group("den") |
1781 |
| - | Error(r"Expected \binom{num}{den}")) |
1782 |
| - |
1783 |
| - p.genfrac <<= r"\genfrac" - ( |
| 1793 | + p.frac <<= cmd( |
| 1794 | + r"\frac", p.required_group("num") + p.required_group("den")) |
| 1795 | + p.dfrac <<= cmd( |
| 1796 | + r"\dfrac", p.required_group("num") + p.required_group("den")) |
| 1797 | + p.binom <<= cmd( |
| 1798 | + r"\binom", p.required_group("num") + p.required_group("den")) |
| 1799 | + |
| 1800 | + p.genfrac <<= cmd( |
| 1801 | + r"\genfrac", |
1784 | 1802 | "{" + Optional(p.ambi_delim | p.left_delim)("ldelim") + "}"
|
1785 | 1803 | + "{" + Optional(p.ambi_delim | p.right_delim)("rdelim") + "}"
|
1786 | 1804 | + "{" + p.float_literal("rulesize") + "}"
|
1787 |
| - + p.simple_group("style") |
| 1805 | + + p.optional_group("style") |
1788 | 1806 | + p.required_group("num")
|
1789 |
| - + p.required_group("den") |
1790 |
| - | Error("Expected " |
1791 |
| - r"\genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) |
| 1807 | + + p.required_group("den")) |
1792 | 1808 |
|
1793 |
| - p.sqrt <<= r"\sqrt" - ( |
| 1809 | + p.sqrt <<= cmd( |
| 1810 | + r"\sqrt{value}", |
1794 | 1811 | Optional("[" + OneOrMore(NotAny("]") + p.token)("root") + "]")
|
1795 |
| - + p.required_group("value") |
1796 |
| - | Error(r"Expected \sqrt{value}")) |
| 1812 | + + p.required_group("value")) |
1797 | 1813 |
|
1798 |
| - p.overline <<= r"\overline" - ( |
1799 |
| - p.required_group("body") |
1800 |
| - | Error(r"Expected \overline{value}")) |
| 1814 | + p.overline <<= cmd(r"\overline", p.required_group("body")) |
1801 | 1815 |
|
1802 |
| - p.overset <<= r"\overset" - ( |
1803 |
| - p.simple_group("annotation") + p.simple_group("body") |
1804 |
| - | Error(r"Expected \overset{annotation}{body}")) |
1805 |
| - p.underset <<= r"\underset" - ( |
1806 |
| - p.simple_group("annotation") + p.simple_group("body") |
1807 |
| - | Error(r"Expected \underset{annotation}{body}")) |
| 1816 | + p.overset <<= cmd( |
| 1817 | + r"\overset", |
| 1818 | + p.optional_group("annotation") + p.optional_group("body")) |
| 1819 | + p.underset <<= cmd( |
| 1820 | + r"\underset", |
| 1821 | + p.optional_group("annotation") + p.optional_group("body")) |
1808 | 1822 |
|
1809 | 1823 | p.placeable <<= (
|
1810 | 1824 | p.accentprefixed # Must be before accent so named symbols that are
|
@@ -2110,7 +2124,7 @@ def group(self, s, loc, toks):
|
2110 | 2124 | def required_group(self, s, loc, toks):
|
2111 | 2125 | return Hlist(toks.get("group", []))
|
2112 | 2126 |
|
2113 |
| - simple_group = required_group |
| 2127 | + optional_group = required_group |
2114 | 2128 |
|
2115 | 2129 | def end_group(self, s, loc, tok
D6DF
s):
|
2116 | 2130 | self.pop_state()
|
|
0 commit comments