Skip to content

Commit e5c7583

Browse files
authored
Remove global mutable state from galgebra._utils.parser (#306)
This state is just an artefact of the weird two-stage printer API, and isn't part of the parsing at all.
1 parent 77ca0bf commit e5c7583

File tree

2 files changed

+33
-30
lines changed

2 files changed

+33
-30
lines changed

galgebra/_utils/parser.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
11
""" A private module to parse multivector expressions """
22
import re
3+
from typing import List
34

4-
op_cntrct = re.compile(r'(([A-Za-z0-9\_\#]+)(\||<|>)([A-Za-z0-9\_\#]+))')
5-
op_wedge = re.compile(r'(([A-Za-z0-9\_\#]+)[\^]{1}([A-Za-z0-9\_\#]+)([\^]{1}([A-Za-z0-9\_\#]+))*)')
6-
ops = r'[\^\|\<\>]+'
7-
ops_search = re.compile(r'(\^|\||<|>)+')
8-
parse_paren_calls = 0
9-
op_dict = {}
10-
op_lst = []
115

12-
OPS = {'<>|': r'(([A-Za-z0-9\_\#]+)(\||<|>)([A-Za-z0-9\_\#]+))',
13-
'^': r'(([A-Za-z0-9\_\#]+)[\^]{1}([A-Za-z0-9\_\#]+)([\^]{1}([A-Za-z0-9\_\#]+))*)',
14-
'*': r'(([A-Za-z0-9\_\#]+)[\*]{1}([A-Za-z0-9\_\#]+)([\*]{1}([A-Za-z0-9\_\#]+))*)'}
6+
# The `#` character is included because we generate tokens containing it in
7+
# _parse_paren.
8+
_operand_re = r"([A-Za-z0-9\_\#]+)"
159

16-
17-
def set_precedence(op_ord: str = '<>|,^,*') -> None:
18-
global op_dict, op_lst
19-
op_lst = op_ord.split(',')
20-
op_dict = {}
21-
for op in op_lst:
22-
op_dict[op] = re.compile(OPS[op])
10+
_operator_res = {
11+
'<>|': re.compile(r'(ARG(\||<|>)ARG)'.replace('ARG', _operand_re)),
12+
'^': re.compile(r'(ARG[\^]ARG([\^]ARG)*)'.replace('ARG', _operand_re)),
13+
'*': re.compile(r'(ARG[\*]ARG([\*]ARG)*)'.replace('ARG', _operand_re)),
14+
}
2315

2416

2517
def _contains_interval(interval1, interval2): # interval1 inside interval2
@@ -29,9 +21,13 @@ def _contains_interval(interval1, interval2): # interval1 inside interval2
2921
return False
3022

3123

24+
# counter to generate unique tokens
25+
_parse_paren_calls = 0
26+
27+
3228
def _parse_paren(line):
33-
global parse_paren_calls
34-
parse_paren_calls += 1
29+
global _parse_paren_calls
30+
_parse_paren_calls += 1
3531

3632
if ('(' not in line) or (')' not in line):
3733
return [[[line]]]
@@ -82,7 +78,7 @@ def _parse_paren(line):
8278
for level in level_lst[1:]:
8379
igroup = 0
8480
for group in level:
85-
token = '#' + str(parse_paren_calls) + '_' + str(ilevel) + '_' + str(igroup) + '#'
81+
token = '#' + str(_parse_paren_calls) + '_' + str(ilevel) + '_' + str(igroup) + '#'
8682
level_lst[ilevel][igroup].append(line[group[0]:group[1] + 1])
8783
level_lst[ilevel][igroup].append(token)
8884
igroup += 1
@@ -150,17 +146,21 @@ def _add_paren(line, re_exprs):
150146
return line
151147

152148

153-
def parse_line(line: str) -> str:
154-
global op_lst, op_dict
149+
def validate_op_order(op_order: List[str]) -> None:
150+
if not all(op in _operator_res for op in op_order):
151+
raise ValueError("Illegal operator")
152+
153+
154+
def parse_line(line: str, op_order: List[str]) -> str:
155155
line = line.replace(' ', '')
156156
level_lst = _parse_paren(line)
157157
ilevel = 0
158158
for level in level_lst:
159159
igroup = 0
160160
for group in level:
161161
string = group[-1]
162-
for op in op_lst:
163-
string = _add_paren(string, op_dict[op])
162+
for op in op_order:
163+
string = _add_paren(string, _operator_res[op])
164164
level_lst[ilevel][igroup][-1] = string
165165
igroup += 1
166166
ilevel += 1

galgebra/printer.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,8 @@ def Print_Function():
11821182
return
11831183

11841184

1185-
global_dict = {}
1185+
_eval_global_dict = {}
1186+
_eval_parse_order = []
11861187

11871188

11881189
def def_prec(gd: dict, op_ord: str = '<>|,^,*') -> None:
@@ -1197,9 +1198,11 @@ def def_prec(gd: dict, op_ord: str = '<>|,^,*') -> None:
11971198
The order of operator precedence from high to low with groups of equal precedence separated by commas.
11981199
The default precedence, ``'<>|,^,*'``, is that used by Hestenes (:cite:`Hestenes`, p7, :cite:`Doran`, p38).
11991200
"""
1200-
global global_dict
1201-
global_dict = gd
1202-
_parser.set_precedence(op_ord)
1201+
global _eval_global_dict, _eval_parse_order
1202+
op_ord = op_ord.split(',')
1203+
_parser.validate_op_order(op_ord)
1204+
_eval_global_dict = gd
1205+
_eval_parse_order = op_ord
12031206

12041207

12051208
def GAeval(s: str, pstr: bool = False):
@@ -1219,11 +1222,11 @@ def GAeval(s: str, pstr: bool = False):
12191222
enforce operator precedence are printed.
12201223
"""
12211224

1222-
seval = _parser.parse_line(s)
1225+
seval = _parser.parse_line(s, _eval_parse_order)
12231226
if pstr:
12241227
print(s)
12251228
print(seval)
1226-
return eval(seval, global_dict)
1229+
return eval(seval, _eval_global_dict)
12271230

12281231

12291232
r"""

0 commit comments

Comments
 (0)