diff --git a/srcpkgs/firefox/patches/ply-python3.11.patch b/srcpkgs/firefox/patches/ply-python3.11.patch new file mode 100644 index 00000000000..8d1415a4b36 --- /dev/null +++ b/srcpkgs/firefox/patches/ply-python3.11.patch @@ -0,0 +1,85 @@ +The Ply lexer, which doesn't seem too active a project, wraps regular +expressions from grammar definitions in its own regular expressions that name +groups. This breaks re.compile in Python >= 3.11 when the original expressions +contain global flags, because the compiler requires that global flags appear at +the start of the expression instead of inside the named group. + +This patch wraps re.compile to scan the expression for any global flags and, +when found, moves them to the start of the expression. + +--- a/third_party/python/ply/ply/lex.py ++++ b/third_party/python/ply/ply/lex.py +@@ -49,6 +49,37 @@ + # Python 3.0 + StringTypes = (str, bytes) + ++ ++def _re_compile(expression, *args, **kwargs): ++ ''' ++ Rearrange global flags in the regular expression to appear at the ++ beginning, avoiding deprecation warnings on Python < 3.11 and hard ++ errors on Python >= 3.11. ++ ''' ++ flags = set() ++ remainder = '' ++ ++ pattern = re.compile(r'\(\?([aiLmsux]+)\)') ++ while m := pattern.search(expression): ++ # Location of the global flag spec ++ l, h = m.span(0) ++ # Accumulate global flags from this spec ++ flags.update(m.group(1)) ++ # Capture all text leading up to the match ++ remainder += expression[:l] ++ # Trim to the end fo the flag spec ++ expression = expression[h:] ++ ++ # Any remaining expression contains no flags ++ remainder += expression ++ ++ # If there are flags, they belong at the beginning ++ if flags: ++ remainder = f'(?{"".join(sorted(flags))})' + remainder ++ ++ return re.compile(remainder, *args, **kwargs) ++ ++ + # This regular expression is used to match valid token names + _is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') + +@@ -230,7 +261,7 @@ + titem = [] + txtitem = [] + for pat, func_name in lre: +- titem.append((re.compile(pat, lextab._lexreflags), _names_to_funcs(func_name, fdict))) ++ titem.append((_re_compile(pat, lextab._lexreflags), _names_to_funcs(func_name, fdict))) + + self.lexstatere[statename] = titem + self.lexstateretext[statename] = txtitem +@@ -495,7 +526,7 @@ + return [] + regex = '|'.join(relist) + try: +- lexre = re.compile(regex, reflags) ++ lexre = _re_compile(regex, reflags) + + # Build the index to function map for the matching engine + lexindexfunc = [None] * (max(lexre.groupindex.values()) + 1) +@@ -758,7 +789,7 @@ + continue + + try: +- c = re.compile('(?P<%s>%s)' % (fname, _get_regex(f)), self.reflags) ++ c = _re_compile('(?P<%s>%s)' % (fname, _get_regex(f)), self.reflags) + if c.match(''): + self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file, line, f.__name__) + self.error = True +@@ -782,7 +813,7 @@ + continue + + try: +- c = re.compile('(?P<%s>%s)' % (name, r), self.reflags) ++ c = _re_compile('(?P<%s>%s)' % (name, r), self.reflags) + if (c.match('')): + self.log.error("Regular expression for rule '%s' matches empty string", name) + self.error = True