coconut-develop 3.1.2.post0.dev2__tar.gz → 3.1.2.post0.dev3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/PKG-INFO +1 -1
  2. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/_pyparsing.py +1 -0
  3. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/compiler.py +304 -33
  4. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/util.py +82 -227
  5. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/constants.py +2 -1
  6. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/root.py +5 -5
  7. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/constants_test.py +2 -1
  8. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/main_test.py +7 -6
  9. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_2/py2_test.coco +1 -1
  10. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/util.py +42 -0
  11. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/CONTRIBUTING.md +0 -0
  12. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/DOCS.md +0 -0
  13. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/FAQ.md +0 -0
  14. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/HELP.md +0 -0
  15. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/LICENSE.txt +0 -0
  16. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/MANIFEST.in +0 -0
  17. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/README.rst +0 -0
  18. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/__coconut__/__init__.py +0 -0
  19. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/__coconut__/__init__.pyi +0 -0
  20. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/__coconut__/py.typed +0 -0
  21. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/_coconut/__init__.py +0 -0
  22. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/_coconut/__init__.pyi +0 -0
  23. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/_coconut/py.typed +0 -0
  24. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/__coconut__.py +0 -0
  25. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/__coconut__.pyi +0 -0
  26. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/__init__.py +0 -0
  27. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/__init__.pyi +0 -0
  28. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/__main__.py +0 -0
  29. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/api.py +0 -0
  30. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/api.pyi +0 -0
  31. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/__init__.py +0 -0
  32. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/__init__.pyi +0 -0
  33. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/cli.py +0 -0
  34. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/command.py +0 -0
  35. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/command.pyi +0 -0
  36. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/mypy.py +0 -0
  37. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/resources/zcoconut.pth +0 -0
  38. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/util.py +0 -0
  39. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/command/watch.py +0 -0
  40. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/__init__.py +0 -0
  41. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/grammar.py +0 -0
  42. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/header.py +0 -0
  43. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/matching.py +0 -0
  44. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/compiler/templates/header.py_template +0 -0
  45. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/convenience.py +0 -0
  46. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/convenience.pyi +0 -0
  47. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/exceptions.py +0 -0
  48. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/highlighter.py +0 -0
  49. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/__init__.py +0 -0
  50. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/__main__.py +0 -0
  51. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/coconut/kernel.json +0 -0
  52. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/coconut_py/kernel.json +0 -0
  53. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/coconut_py2/kernel.json +0 -0
  54. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/coconut_py3/kernel.json +0 -0
  55. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/embed.py +0 -0
  56. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/icoconut/root.py +0 -0
  57. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/integrations.py +0 -0
  58. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/main.py +0 -0
  59. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/py.typed +0 -0
  60. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/requirements.py +0 -0
  61. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/terminal.py +0 -0
  62. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/__init__.py +0 -0
  63. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/__main__.py +0 -0
  64. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/__init__.coco +0 -0
  65. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/__main__.coco +0 -0
  66. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/main.coco +0 -0
  67. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/primary_1.coco +0 -0
  68. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/primary_2.coco +0 -0
  69. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/specific.coco +0 -0
  70. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/suite.coco +0 -0
  71. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/tutorial.coco +0 -0
  72. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/agnostic/util.coco +0 -0
  73. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/non_strict/non_strict_test.coco +0 -0
  74. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_3/py3_test.coco +0 -0
  75. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_311/py311_test.coco +0 -0
  76. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_35/py35_test.coco +0 -0
  77. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_36/py36_test.coco +0 -0
  78. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_38/py38_test.coco +0 -0
  79. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/cocotest/target_sys/target_sys_test.coco +0 -0
  80. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/extras.coco +0 -0
  81. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/importable.coco +0 -0
  82. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/runnable.coco +0 -0
  83. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut/tests/src/runner.coco +0 -0
  84. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/coconut_develop.egg-info/SOURCES.txt +0 -0
  85. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/conf.py +0 -0
  86. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/pyproject.toml +0 -0
  87. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/setup.cfg +0 -0
  88. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/setup.py +0 -0
  89. {coconut-develop-3.1.2.post0.dev2 → coconut-develop-3.1.2.post0.dev3}/xontrib/coconut.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: coconut-develop
3
- Version: 3.1.2.post0.dev2
3
+ Version: 3.1.2.post0.dev3
4
4
  Summary: Simple, elegant, Pythonic functional programming.
5
5
  Home-page: http://coconut-lang.org
6
6
  Author: Evan Hubinger
@@ -263,6 +263,7 @@ if MODERN_PYPARSING:
263
263
  else:
264
264
  _trim_arity = _pyparsing._trim_arity
265
265
  _ParseResultsWithOffset = _pyparsing._ParseResultsWithOffset
266
+ _trim_arity.inspect_tracebacks = False
266
267
 
267
268
  maybe_make_safe = getattr(_pyparsing, "maybe_make_safe", None)
268
269
 
@@ -34,7 +34,7 @@ import sys
34
34
  import os
35
35
  import re
36
36
  from contextlib import contextmanager
37
- from functools import partial, wraps
37
+ from functools import partial, update_wrapper
38
38
  from collections import defaultdict
39
39
  from threading import Lock
40
40
  from copy import copy
@@ -42,12 +42,16 @@ from copy import copy
42
42
  from coconut._pyparsing import (
43
43
  USE_COMPUTATION_GRAPH,
44
44
  USE_CACHE,
45
+ SUPPORTS_INCREMENTAL,
45
46
  ParseBaseException,
46
47
  ParseResults,
48
+ ParserElement,
47
49
  col as getcol,
48
50
  lineno,
49
51
  nums,
50
52
  _trim_arity,
53
+ all_parse_elements,
54
+ __version__ as pyparsing_version,
51
55
  )
52
56
 
53
57
  from coconut.constants import (
@@ -94,8 +98,16 @@ from coconut.constants import (
94
98
  use_adaptive_any_of,
95
99
  reverse_any_of,
96
100
  tempsep,
101
+ disable_incremental_for_len,
102
+ save_new_cache_items,
103
+ cache_validation_info,
104
+ incremental_mode_cache_size,
105
+ incremental_cache_limit,
106
+ use_line_by_line_parser,
107
+ coconut_cache_dir,
97
108
  )
98
109
  from coconut.util import (
110
+ pickle,
99
111
  pickleable_obj,
100
112
  checksum,
101
113
  clip,
@@ -109,6 +121,9 @@ from coconut.util import (
109
121
  dictset,
110
122
  noop_ctx,
111
123
  create_method,
124
+ univ_open,
125
+ staledict,
126
+ ensure_dir,
112
127
  )
113
128
  from coconut.exceptions import (
114
129
  CoconutException,
@@ -141,6 +156,10 @@ from coconut.compiler.grammar import (
141
156
  )
142
157
  from coconut.compiler.util import (
143
158
  ExceptionNode,
159
+ ComputationNode,
160
+ StartOfStrGrammar,
161
+ MatchAny,
162
+ CombineToNode,
144
163
  sys_target,
145
164
  getline,
146
165
  addskip,
@@ -180,16 +199,20 @@ from coconut.compiler.util import (
180
199
  close_char_for,
181
200
  base_keyword,
182
201
  enable_incremental_parsing,
202
+ disable_incremental_parsing,
183
203
  get_psf_target,
184
204
  move_loc_to_non_whitespace,
185
205
  move_endpt_to_non_whitespace,
186
- load_cache_for,
187
- pickle_cache,
188
206
  handle_and_manage,
189
207
  manage,
190
208
  sub_all,
191
- ComputationNode,
192
- StartOfStrGrammar,
209
+ get_cache_items_for,
210
+ clear_packrat_cache,
211
+ add_packrat_cache_items,
212
+ parse_elem_to_identifier,
213
+ identifier_to_parse_elem,
214
+ _lookup_loc,
215
+ _value_exc_loc_or_ret,
193
216
  )
194
217
  from coconut.compiler.header import (
195
218
  minify_header,
@@ -396,6 +419,47 @@ def call_decorators(decorators, func_name):
396
419
  return out
397
420
 
398
421
 
422
+ def get_cache_path(codepath):
423
+ """Get the cache filename to use for the given codepath."""
424
+ code_dir, code_fname = os.path.split(codepath)
425
+
426
+ cache_dir = os.path.join(code_dir, coconut_cache_dir)
427
+ ensure_dir(cache_dir, logger=logger)
428
+
429
+ pickle_fname = code_fname + ".pkl"
430
+ return os.path.join(cache_dir, pickle_fname)
431
+
432
+
433
+ class CompilerMethodCaller(object):
434
+ """Create a function that will call the given compiler method."""
435
+ # don't set anything up here since it'll be overwritten by update_wrapper
436
+
437
+ def __init__(self, method_name, trim_arity, kwargs):
438
+ update_wrapper(self, getattr(Compiler, method_name))
439
+ self.trim_arity = False
440
+ self._method_name = method_name
441
+ self._trim_arity = trim_arity
442
+ self._kwargs = kwargs
443
+ if kwargs:
444
+ self.__name__ = py_str(self.__name__ + "$(" + ", ".join(str(k) + "=" + repr(v) for k, v in kwargs.items()) + ")")
445
+
446
+ def __reduce__(self):
447
+ return (self.__class__, (self._method_name, self._trim_arity, self._kwargs))
448
+
449
+ def __call__(self, original, loc, tokens_or_item):
450
+ """Performance sensitive."""
451
+ method = getattr(Compiler.current_compiler, self._method_name)
452
+ if self._kwargs:
453
+ if self._trim_arity:
454
+ return _trim_arity(partial(method, **self._kwargs))(original, loc, tokens_or_item)
455
+ else:
456
+ return method(original, loc, tokens_or_item, **self._kwargs)
457
+ else:
458
+ if self._trim_arity:
459
+ method = _trim_arity(method)
460
+ return method(original, loc, tokens_or_item)
461
+
462
+
399
463
  # end: UTILITIES
400
464
  # -----------------------------------------------------------------------------------------------------------------------
401
465
  # COMPILER:
@@ -406,7 +470,6 @@ class Compiler(Grammar, pickleable_obj):
406
470
  """The Coconut compiler."""
407
471
  lock = Lock()
408
472
  current_compiler = None
409
- computation_graph_caches = defaultdict(dict)
410
473
 
411
474
  preprocs = [
412
475
  lambda self: self.prepare,
@@ -555,6 +618,7 @@ class Compiler(Grammar, pickleable_obj):
555
618
  self.add_code_before_ignore_names = {}
556
619
  self.remaining_original = None
557
620
  self.shown_warnings = set()
621
+ self.computation_graph_caches = defaultdict(staledict)
558
622
 
559
623
  @contextmanager
560
624
  def inner_environment(self, ln=None):
@@ -634,28 +698,26 @@ class Compiler(Grammar, pickleable_obj):
634
698
  cls_method = getattr(cls, method_name)
635
699
  if is_action is None:
636
700
  is_action = not method_name.endswith("_manage")
637
- trim_arity = should_trim_arity(cls_method) if is_action else False
638
-
639
- @wraps(cls_method)
640
- def method(original, loc, tokens_or_item):
641
- self_method = getattr(cls.current_compiler, method_name)
642
- if kwargs:
643
- self_method = partial(self_method, **kwargs)
644
- if trim_arity:
645
- self_method = _trim_arity(self_method)
646
- return self_method(original, loc, tokens_or_item)
647
- if kwargs:
648
- method.__name__ = py_str(method.__name__ + "$(" + ", ".join(str(k) + "=" + repr(v) for k, v in kwargs.items()) + ")")
701
+ method = CompilerMethodCaller(
702
+ method_name=method_name,
703
+ trim_arity=should_trim_arity(cls_method) if is_action else False,
704
+ kwargs=kwargs,
705
+ )
649
706
  internal_assert(
650
- hasattr(cls_method, "ignore_arguments") is hasattr(method, "ignore_arguments")
707
+ not method.trim_arity
708
+ and hasattr(cls_method, "ignore_arguments") is hasattr(method, "ignore_arguments")
651
709
  and hasattr(cls_method, "ignore_no_tokens") is hasattr(method, "ignore_no_tokens")
652
710
  and hasattr(cls_method, "ignore_one_token") is hasattr(method, "ignore_one_token"),
653
711
  "failed to properly wrap method",
654
712
  method_name,
655
713
  )
656
- method.trim_arity = False
657
714
  return method
658
715
 
716
+ @classmethod
717
+ def method_of(cls, method_name, is_action, kwargs):
718
+ """Version of Compiler.method for use in pickling."""
719
+ return cls.method(method_name, is_action, **kwargs)
720
+
659
721
  @classmethod
660
722
  def bind(cls):
661
723
  """Binds reference objects to the proper parse actions."""
@@ -1310,7 +1372,7 @@ class Compiler(Grammar, pickleable_obj):
1310
1372
  with self.inner_environment(ln=outer_ln):
1311
1373
  self.streamline(parser, inputstring, inner=True)
1312
1374
  pre_procd = self.pre(inputstring, **preargs)
1313
- parsed = parse(parser, pre_procd)
1375
+ parsed = self.cached_parse("inner_parse_eval", parser, pre_procd)
1314
1376
  return self.post(parsed, **postargs)
1315
1377
 
1316
1378
  @contextmanager
@@ -1366,6 +1428,216 @@ class Compiler(Grammar, pickleable_obj):
1366
1428
  for loc in info["referenced"]:
1367
1429
  self.qa_error("found undefined name " + repr(self.reformat(name, ignore_errors=True)), original, loc)
1368
1430
 
1431
+ def pickle_cache(self, original, cache_path, include_incremental=True):
1432
+ """Pickle the pyparsing cache for original to cache_path."""
1433
+ internal_assert(all_parse_elements is not None, "pickle_cache requires cPyparsing")
1434
+ if not save_new_cache_items:
1435
+ logger.log("Skipping saving cache items due to environment variable.")
1436
+ return
1437
+
1438
+ validation_dict = {} if cache_validation_info else None
1439
+
1440
+ # incremental cache
1441
+ pickleable_cache_items = []
1442
+ if ParserElement._incrementalEnabled and include_incremental:
1443
+ # note that exclude_stale is fine here because that means it was never used,
1444
+ # since _parseIncremental sets usefullness to True when a cache item is used
1445
+ for lookup, value in get_cache_items_for(original, only_useful=True):
1446
+ if incremental_mode_cache_size is not None and len(pickleable_cache_items) > incremental_mode_cache_size:
1447
+ logger.log(
1448
+ "Got too large incremental cache: "
1449
+ + str(len(get_pyparsing_cache())) + " > " + str(incremental_mode_cache_size)
1450
+ )
1451
+ break
1452
+ if len(pickleable_cache_items) >= incremental_cache_limit:
1453
+ break
1454
+ loc = lookup[_lookup_loc]
1455
+ # only include cache items that aren't at the start or end, since those
1456
+ # are the only ones that parseIncremental will reuse
1457
+ if 0 < loc < len(original) - 1:
1458
+ elem = lookup[0]
1459
+ identifier = parse_elem_to_identifier(elem, validation_dict)
1460
+ pickleable_lookup = (identifier,) + lookup[1:]
1461
+ internal_assert(value[_value_exc_loc_or_ret] is True or isinstance(value[_value_exc_loc_or_ret], int), "cache must be dehybridized before pickling", value[_value_exc_loc_or_ret])
1462
+ pickleable_cache_items.append((pickleable_lookup, value))
1463
+
1464
+ # adaptive cache
1465
+ all_adaptive_items = []
1466
+ for wkref in MatchAny.all_match_anys:
1467
+ match_any = wkref()
1468
+ if match_any is not None and match_any.adaptive_usage is not None:
1469
+ identifier = parse_elem_to_identifier(match_any, validation_dict)
1470
+ match_any.expr_order.sort(key=lambda i: (-match_any.adaptive_usage[i], i))
1471
+ all_adaptive_items.append((identifier, (match_any.adaptive_usage, match_any.expr_order)))
1472
+ logger.log("Caching adaptive item:", match_any, (match_any.adaptive_usage, match_any.expr_order))
1473
+
1474
+ # computation graph cache
1475
+ computation_graph_cache_items = []
1476
+ for (call_site_name, grammar_elem), cache in self.computation_graph_caches.items():
1477
+ identifier = parse_elem_to_identifier(grammar_elem, validation_dict)
1478
+ computation_graph_cache_items.append(((call_site_name, identifier), cache))
1479
+
1480
+ logger.log("Saving {num_inc} incremental, {num_adapt} adaptive, and {num_comp_graph} computation graph cache items to {cache_path!r}.".format(
1481
+ num_inc=len(pickleable_cache_items),
1482
+ num_adapt=len(all_adaptive_items),
1483
+ num_comp_graph=sum(len(cache) for _, cache in computation_graph_cache_items) if computation_graph_cache_items else 0,
1484
+ cache_path=cache_path,
1485
+ ))
1486
+ pickle_info_obj = {
1487
+ "VERSION": VERSION,
1488
+ "pyparsing_version": pyparsing_version,
1489
+ "validation_dict": validation_dict,
1490
+ "pickleable_cache_items": pickleable_cache_items,
1491
+ "all_adaptive_items": all_adaptive_items,
1492
+ "computation_graph_cache_items": computation_graph_cache_items,
1493
+ }
1494
+ try:
1495
+ with CombineToNode.enable_pickling(validation_dict):
1496
+ with univ_open(cache_path, "wb") as pickle_file:
1497
+ pickle.dump(pickle_info_obj, pickle_file, protocol=pickle.HIGHEST_PROTOCOL)
1498
+ except Exception:
1499
+ logger.log_exc()
1500
+ return False
1501
+ else:
1502
+ return True
1503
+ finally:
1504
+ # clear the packrat cache when we're done so we don't interfere with anything else happening in this process
1505
+ clear_packrat_cache(force=True)
1506
+
1507
+ def unpickle_cache(self, cache_path):
1508
+ """Unpickle and load the given incremental cache file."""
1509
+ internal_assert(all_parse_elements is not None, "unpickle_cache requires cPyparsing")
1510
+
1511
+ if not os.path.exists(cache_path):
1512
+ return False
1513
+ try:
1514
+ with univ_open(cache_path, "rb") as pickle_file:
1515
+ pickle_info_obj = pickle.load(pickle_file)
1516
+ except Exception:
1517
+ logger.log_exc()
1518
+ return False
1519
+ if (
1520
+ pickle_info_obj["VERSION"] != VERSION
1521
+ or pickle_info_obj["pyparsing_version"] != pyparsing_version
1522
+ ):
1523
+ return False
1524
+
1525
+ # unpack pickle_info_obj
1526
+ validation_dict = pickle_info_obj["validation_dict"]
1527
+ if ParserElement._incrementalEnabled:
1528
+ pickleable_cache_items = pickle_info_obj["pickleable_cache_items"]
1529
+ else:
1530
+ pickleable_cache_items = []
1531
+ all_adaptive_items = pickle_info_obj["all_adaptive_items"]
1532
+ computation_graph_cache_items = pickle_info_obj["computation_graph_cache_items"]
1533
+
1534
+ # incremental cache
1535
+ new_cache_items = []
1536
+ for pickleable_lookup, value in pickleable_cache_items:
1537
+ maybe_elem = identifier_to_parse_elem(pickleable_lookup[0], validation_dict)
1538
+ if maybe_elem is not None:
1539
+ internal_assert(value[_value_exc_loc_or_ret] is True or isinstance(value[_value_exc_loc_or_ret], int), "attempting to unpickle hybrid cache item", value[_value_exc_loc_or_ret])
1540
+ lookup = (maybe_elem,) + pickleable_lookup[1:]
1541
+ usefullness = value[-1][0]
1542
+ internal_assert(usefullness, "loaded useless cache item", (lookup, value))
1543
+ stale_value = value[:-1] + ([usefullness + 1],)
1544
+ new_cache_items.append((lookup, stale_value))
1545
+ add_packrat_cache_items(new_cache_items)
1546
+
1547
+ # adaptive cache
1548
+ for identifier, (adaptive_usage, expr_order) in all_adaptive_items:
1549
+ maybe_elem = identifier_to_parse_elem(identifier, validation_dict)
1550
+ if maybe_elem is not None:
1551
+ maybe_elem.adaptive_usage = adaptive_usage
1552
+ maybe_elem.expr_order = expr_order
1553
+
1554
+ max_cache_size = min(
1555
+ incremental_mode_cache_size or float("inf"),
1556
+ incremental_cache_limit or float("inf"),
1557
+ )
1558
+ if max_cache_size != float("inf"):
1559
+ pickleable_cache_items = pickleable_cache_items[-max_cache_size:]
1560
+
1561
+ # computation graph cache
1562
+ for (call_site_name, identifier), cache in computation_graph_cache_items:
1563
+ maybe_elem = identifier_to_parse_elem(identifier, validation_dict)
1564
+ if maybe_elem is not None:
1565
+ self.computation_graph_caches[(call_site_name, maybe_elem)].update(cache)
1566
+
1567
+ num_inc = len(pickleable_cache_items)
1568
+ num_adapt = len(all_adaptive_items)
1569
+ num_comp_graph = sum(len(cache) for _, cache in computation_graph_cache_items) if computation_graph_cache_items else 0
1570
+ return num_inc, num_adapt, num_comp_graph
1571
+
1572
+ def load_cache_for(self, inputstring, codepath):
1573
+ """Load cache_path (for the given inputstring and filename)."""
1574
+ if not SUPPORTS_INCREMENTAL:
1575
+ raise CoconutException("the parsing cache requires cPyparsing (run '{python} -m pip install --upgrade cPyparsing' to fix)".format(python=sys.executable))
1576
+ filename = os.path.basename(codepath)
1577
+
1578
+ if len(inputstring) < disable_incremental_for_len:
1579
+ incremental_enabled = enable_incremental_parsing(reason="input length")
1580
+ if incremental_enabled:
1581
+ incremental_info = "incremental parsing mode enabled due to len == {input_len} < {max_len}".format(
1582
+ input_len=len(inputstring),
1583
+ max_len=disable_incremental_for_len,
1584
+ )
1585
+ else:
1586
+ incremental_info = "failed to enable incremental parsing mode"
1587
+ else:
1588
+ disable_incremental_parsing()
1589
+ incremental_enabled = False
1590
+ incremental_info = "not using incremental parsing mode due to len == {input_len} >= {max_len}".format(
1591
+ input_len=len(inputstring),
1592
+ max_len=disable_incremental_for_len,
1593
+ )
1594
+
1595
+ if (
1596
+ # only load the cache if we're using anything that makes use of it
1597
+ incremental_enabled
1598
+ or use_adaptive_any_of
1599
+ or use_line_by_line_parser
1600
+ ):
1601
+ cache_path = get_cache_path(codepath)
1602
+ did_load_cache = self.unpickle_cache(cache_path)
1603
+ if did_load_cache:
1604
+ num_inc, num_adapt, num_comp_graph = did_load_cache
1605
+ logger.log("Loaded {num_inc} incremental, {num_adapt} adaptive, and {num_comp_graph} computation graph cache items for {filename!r} ({incremental_info}).".format(
1606
+ num_inc=num_inc,
1607
+ num_adapt=num_adapt,
1608
+ num_comp_graph=num_comp_graph,
1609
+ filename=filename,
1610
+ incremental_info=incremental_info,
1611
+ ))
1612
+ else:
1613
+ logger.log("Failed to load cache for {filename!r} from {cache_path!r} ({incremental_info}).".format(
1614
+ filename=filename,
1615
+ cache_path=cache_path,
1616
+ incremental_info=incremental_info,
1617
+ ))
1618
+ if incremental_enabled:
1619
+ logger.warn("Populating initial parsing cache (initial compilation may take a while; pass --no-cache to disable)...")
1620
+ else:
1621
+ cache_path = None
1622
+ logger.log("Declined to load cache for {filename!r} ({incremental_info}).".format(
1623
+ filename=filename,
1624
+ incremental_info=incremental_info,
1625
+ ))
1626
+
1627
+ return cache_path, incremental_enabled
1628
+
1629
+ def cached_parse(self, call_site_name, parser, text, **kwargs):
1630
+ """Call cached_parse using self.computation_graph_caches."""
1631
+ return cached_parse(self.computation_graph_caches[(call_site_name, parser)], parser, text, **kwargs)
1632
+
1633
+ def cached_try_parse(self, call_site_name, parser, text, **kwargs):
1634
+ """Call cached_try_parse using self.computation_graph_caches."""
1635
+ return try_parse(parser, text, computation_graph_cache=self.computation_graph_caches[(call_site_name, parser)], **kwargs)
1636
+
1637
+ def cached_does_parse(self, call_site_name, parser, text, **kwargs):
1638
+ """Call cached_does_parse using self.computation_graph_caches."""
1639
+ return does_parse(parser, text, computation_graph_cache=self.computation_graph_caches[(call_site_name, parser)], **kwargs)
1640
+
1369
1641
  def parse_line_by_line(self, init_parser, line_parser, original):
1370
1642
  """Apply init_parser then line_parser repeatedly."""
1371
1643
  if not USE_COMPUTATION_GRAPH:
@@ -1379,8 +1651,8 @@ class Compiler(Grammar, pickleable_obj):
1379
1651
  self.remaining_original = original[cur_loc:]
1380
1652
  ComputationNode.add_to_loc = cur_loc
1381
1653
  parser = init_parser if init else line_parser
1382
- results = cached_parse(
1383
- self.computation_graph_caches[("line_by_line", parser)],
1654
+ results = self.cached_parse(
1655
+ "parse_line_by_line",
1384
1656
  parser,
1385
1657
  self.remaining_original,
1386
1658
  inner=False,
@@ -1417,7 +1689,7 @@ class Compiler(Grammar, pickleable_obj):
1417
1689
  # unpickling must happen after streamlining and must occur in the
1418
1690
  # compiler so that it happens in the same process as compilation
1419
1691
  if use_cache:
1420
- cache_path, incremental_enabled = load_cache_for(inputstring, codepath)
1692
+ cache_path, incremental_enabled = self.load_cache_for(inputstring, codepath)
1421
1693
  else:
1422
1694
  cache_path = None
1423
1695
  pre_procd = parsed = None
@@ -1444,7 +1716,7 @@ class Compiler(Grammar, pickleable_obj):
1444
1716
  )
1445
1717
  finally:
1446
1718
  if cache_path is not None and pre_procd is not None:
1447
- pickle_cache(pre_procd, cache_path, include_incremental=incremental_enabled)
1719
+ self.pickle_cache(pre_procd, cache_path, include_incremental=incremental_enabled)
1448
1720
  self.run_final_checks(pre_procd, keep_state)
1449
1721
  return out
1450
1722
 
@@ -1540,7 +1812,7 @@ class Compiler(Grammar, pickleable_obj):
1540
1812
  hold["exprs"][-1] += c
1541
1813
  elif hold["paren_level"] > 0:
1542
1814
  raise self.make_err(CoconutSyntaxError, "imbalanced parentheses in format string expression", inputstring, i, reformat=False)
1543
- elif does_parse(self.end_f_str_expr, remaining_text):
1815
+ elif self.cached_does_parse("str_proc", self.end_f_str_expr, remaining_text):
1544
1816
  hold["in_expr"] = False
1545
1817
  hold["str_parts"].append(c)
1546
1818
  else:
@@ -1733,9 +2005,9 @@ class Compiler(Grammar, pickleable_obj):
1733
2005
  stripped_line = base_line.lstrip()
1734
2006
 
1735
2007
  imp_from = None
1736
- op = try_parse(self.operator_stmt, stripped_line)
2008
+ op = self.cached_try_parse("operator_proc", self.operator_stmt, stripped_line)
1737
2009
  if op is None:
1738
- op_imp_toks = try_parse(self.from_import_operator, base_line)
2010
+ op_imp_toks = self.cached_try_parse("operator_proc", self.from_import_operator, base_line)
1739
2011
  if op_imp_toks is not None:
1740
2012
  imp_from, op = op_imp_toks
1741
2013
  if op is not None:
@@ -2367,7 +2639,7 @@ else:
2367
2639
  # extract information about the function
2368
2640
  with self.complain_on_err():
2369
2641
  try:
2370
- split_func_tokens = parse(self.split_func, def_stmt)
2642
+ split_func_tokens = self.cached_parse("proc_funcdef", self.split_func, def_stmt)
2371
2643
 
2372
2644
  self.internal_assert(len(split_func_tokens) == 2, original, loc, "invalid function definition splitting tokens", split_func_tokens)
2373
2645
  func_name, func_arg_tokens = split_func_tokens
@@ -4394,7 +4666,7 @@ __annotations__["{name}"] = {annotation}
4394
4666
  py_expr = self.inner_parse_eval(original, loc, co_expr)
4395
4667
  except ParseBaseException:
4396
4668
  raise CoconutDeferredSyntaxError("parsing failed for format string expression: " + co_expr, loc)
4397
- if not does_parse(self.no_unquoted_newlines, py_expr):
4669
+ if not self.cached_does_parse("f_string_handle", self.no_unquoted_newlines, py_expr):
4398
4670
  raise CoconutDeferredSyntaxError("illegal complex expression in format string: " + co_expr, loc)
4399
4671
  compiled_exprs.append(py_expr)
4400
4672
 
@@ -4652,9 +4924,9 @@ async with {iter_item} as {temp_var}:
4652
4924
  def impl_call_handle(self, loc, tokens):
4653
4925
  """Process implicit function application or coefficient syntax."""
4654
4926
  internal_assert(len(tokens) >= 2, "invalid implicit call / coefficient tokens", tokens)
4655
- first_is_num = does_parse(self.number, tokens[0])
4927
+ first_is_num = self.cached_does_parse("impl_call_handle", self.number, tokens[0])
4656
4928
  if first_is_num:
4657
- if does_parse(self.number, tokens[1]):
4929
+ if self.cached_does_parse("impl_call_handle", self.number, tokens[1]):
4658
4930
  raise CoconutDeferredSyntaxError("multiplying two or more numeric literals with implicit coefficient syntax is prohibited", loc)
4659
4931
  return "(" + " * ".join(tokens) + ")"
4660
4932
  else:
@@ -4894,7 +5166,6 @@ class {protocol_var}({tokens}, _coconut.typing.Protocol): pass
4894
5166
 
4895
5167
  where_assigns = self.current_parsing_context("where")["assigns"]
4896
5168
  internal_assert(lambda: where_assigns is not None, "missing where_assigns")
4897
- print(where_assigns)
4898
5169
 
4899
5170
  where_init = "".join(body_stmts)
4900
5171
  where_final = main_stmt + "\n"