coconut-develop 3.1.0.post0.dev6__tar.gz → 3.1.0.post0.dev7__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.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/PKG-INFO +1 -1
  2. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/compiler.py +128 -65
  3. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/grammar.py +33 -24
  4. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/util.py +1 -1
  5. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/constants.py +2 -0
  6. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/root.py +1 -1
  7. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/main_test.py +4 -1
  8. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/suite.coco +6 -3
  9. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/util.coco +36 -8
  10. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/CONTRIBUTING.md +0 -0
  11. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/DOCS.md +0 -0
  12. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/FAQ.md +0 -0
  13. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/HELP.md +0 -0
  14. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/LICENSE.txt +0 -0
  15. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/MANIFEST.in +0 -0
  16. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/README.rst +0 -0
  17. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/__coconut__/__init__.py +0 -0
  18. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/__coconut__/__init__.pyi +0 -0
  19. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/__coconut__/py.typed +0 -0
  20. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/_coconut/__init__.py +0 -0
  21. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/_coconut/__init__.pyi +0 -0
  22. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/_coconut/py.typed +0 -0
  23. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/__coconut__.py +0 -0
  24. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/__coconut__.pyi +0 -0
  25. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/__init__.py +0 -0
  26. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/__init__.pyi +0 -0
  27. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/__main__.py +0 -0
  28. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/_pyparsing.py +0 -0
  29. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/api.py +0 -0
  30. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/api.pyi +0 -0
  31. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/__init__.py +0 -0
  32. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/__init__.pyi +0 -0
  33. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/cli.py +0 -0
  34. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/command.py +0 -0
  35. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/command.pyi +0 -0
  36. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/mypy.py +0 -0
  37. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/resources/zcoconut.pth +0 -0
  38. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/util.py +0 -0
  39. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/command/watch.py +0 -0
  40. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/__init__.py +0 -0
  41. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/header.py +0 -0
  42. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/matching.py +0 -0
  43. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/compiler/templates/header.py_template +0 -0
  44. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/convenience.py +0 -0
  45. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/convenience.pyi +0 -0
  46. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/exceptions.py +0 -0
  47. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/highlighter.py +0 -0
  48. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/__init__.py +0 -0
  49. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/__main__.py +0 -0
  50. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/coconut/kernel.json +0 -0
  51. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/coconut_py/kernel.json +0 -0
  52. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/coconut_py2/kernel.json +0 -0
  53. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/coconut_py3/kernel.json +0 -0
  54. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/embed.py +0 -0
  55. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/icoconut/root.py +0 -0
  56. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/integrations.py +0 -0
  57. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/main.py +0 -0
  58. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/py.typed +0 -0
  59. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/requirements.py +0 -0
  60. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/terminal.py +0 -0
  61. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/__init__.py +0 -0
  62. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/__main__.py +0 -0
  63. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/constants_test.py +0 -0
  64. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/__init__.coco +0 -0
  65. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/__main__.coco +0 -0
  66. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/main.coco +0 -0
  67. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/primary_1.coco +0 -0
  68. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/primary_2.coco +0 -0
  69. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/specific.coco +0 -0
  70. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/agnostic/tutorial.coco +0 -0
  71. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/non_strict/non_strict_test.coco +0 -0
  72. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_2/py2_test.coco +0 -0
  73. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_3/py3_test.coco +0 -0
  74. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_311/py311_test.coco +0 -0
  75. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_35/py35_test.coco +0 -0
  76. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_36/py36_test.coco +0 -0
  77. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_38/py38_test.coco +0 -0
  78. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/cocotest/target_sys/target_sys_test.coco +0 -0
  79. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/extras.coco +0 -0
  80. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/importable.coco +0 -0
  81. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/runnable.coco +0 -0
  82. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/tests/src/runner.coco +0 -0
  83. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut/util.py +0 -0
  84. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/coconut_develop.egg-info/SOURCES.txt +0 -0
  85. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/conf.py +0 -0
  86. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/pyproject.toml +0 -0
  87. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/setup.cfg +0 -0
  88. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/setup.py +0 -0
  89. {coconut-develop-3.1.0.post0.dev6 → coconut-develop-3.1.0.post0.dev7}/xontrib/coconut.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: coconut-develop
3
- Version: 3.1.0.post0.dev6
3
+ Version: 3.1.0.post0.dev7
4
4
  Summary: Simple, elegant, Pythonic functional programming.
5
5
  Home-page: http://coconut-lang.org
6
6
  Author: Evan Hubinger
@@ -93,6 +93,7 @@ from coconut.constants import (
93
93
  import_existing,
94
94
  use_adaptive_any_of,
95
95
  reverse_any_of,
96
+ tempsep,
96
97
  )
97
98
  from coconut.util import (
98
99
  pickleable_obj,
@@ -774,6 +775,7 @@ class Compiler(Grammar, pickleable_obj):
774
775
  cls.testlist_star_namedexpr <<= attach(cls.testlist_star_namedexpr_tokens, cls.method("testlist_star_expr_handle"))
775
776
  cls.ellipsis <<= attach(cls.ellipsis_tokens, cls.method("ellipsis_handle"))
776
777
  cls.f_string <<= attach(cls.f_string_tokens, cls.method("f_string_handle"))
778
+ cls.funcname_typeparams <<= attach(cls.funcname_typeparams_tokens, cls.method("funcname_typeparams_handle"))
777
779
 
778
780
  # standard handlers of the form name <<= attach(name_ref, method("name_handle"))
779
781
  cls.term <<= attach(cls.term_ref, cls.method("term_handle"))
@@ -806,7 +808,6 @@ class Compiler(Grammar, pickleable_obj):
806
808
  cls.base_match_for_stmt <<= attach(cls.base_match_for_stmt_ref, cls.method("base_match_for_stmt_handle"))
807
809
  cls.async_with_for_stmt <<= attach(cls.async_with_for_stmt_ref, cls.method("async_with_for_stmt_handle"))
808
810
  cls.unsafe_typedef_tuple <<= attach(cls.unsafe_typedef_tuple_ref, cls.method("unsafe_typedef_tuple_handle"))
809
- cls.funcname_typeparams <<= attach(cls.funcname_typeparams_ref, cls.method("funcname_typeparams_handle"))
810
811
  cls.impl_call <<= attach(cls.impl_call_ref, cls.method("impl_call_handle"))
811
812
  cls.protocol_intersect_expr <<= attach(cls.protocol_intersect_expr_ref, cls.method("protocol_intersect_expr_handle"))
812
813
 
@@ -2297,9 +2298,10 @@ else:
2297
2298
  def_stmt = raw_lines.pop(0)
2298
2299
  out = []
2299
2300
 
2300
- # detect addpattern/copyclosure functions
2301
+ # detect keyword functions
2301
2302
  addpattern = False
2302
2303
  copyclosure = False
2304
+ typed_case_def = False
2303
2305
  done = False
2304
2306
  while not done:
2305
2307
  if def_stmt.startswith("addpattern "):
@@ -2308,6 +2310,11 @@ else:
2308
2310
  elif def_stmt.startswith("copyclosure "):
2309
2311
  def_stmt = assert_remove_prefix(def_stmt, "copyclosure ")
2310
2312
  copyclosure = True
2313
+ elif def_stmt.startswith("case "):
2314
+ def_stmt = assert_remove_prefix(def_stmt, "case ")
2315
+ case_def_ref, def_stmt = def_stmt.split(unwrapper, 1)
2316
+ type_param_code, all_type_defs = self.get_ref("case_def", case_def_ref)
2317
+ typed_case_def = True
2311
2318
  elif def_stmt.startswith("def"):
2312
2319
  done = True
2313
2320
  else:
@@ -2547,6 +2554,37 @@ def {mock_var}({mock_paramdef}):
2547
2554
  if is_match_func:
2548
2555
  decorators += "@_coconut_mark_as_match\n" # binds most tightly
2549
2556
 
2557
+ # handle typed case def functions (must happen before decorators are cleared out)
2558
+ type_code = None
2559
+ if typed_case_def:
2560
+ if undotted_name is not None:
2561
+ all_type_defs = [
2562
+ "def " + def_name + assert_remove_prefix(type_def, "def " + func_name)
2563
+ for type_def in all_type_defs
2564
+ ]
2565
+ type_code = (
2566
+ self.deferred_code_proc(type_param_code)
2567
+ + "\n".join(
2568
+ ("@_coconut.typing.overload\n" if len(all_type_defs) > 1 else "")
2569
+ + decorators
2570
+ + self.deferred_code_proc(type_def)
2571
+ for type_def in all_type_defs
2572
+ )
2573
+ )
2574
+ if len(all_type_defs) > 1:
2575
+ type_code += "\n" + decorators + handle_indentation("""
2576
+ def {def_name}(*_coconut_args, **_coconut_kwargs):
2577
+ return {any_type_ellipsis}
2578
+ """).format(
2579
+ def_name=def_name,
2580
+ any_type_ellipsis=self.any_type_ellipsis(),
2581
+ )
2582
+ if undotted_name is not None:
2583
+ type_code += "\n{func_name} = {def_name}".format(
2584
+ func_name=func_name,
2585
+ def_name=def_name,
2586
+ )
2587
+
2550
2588
  # handle dotted function definition
2551
2589
  if undotted_name is not None:
2552
2590
  out.append(
@@ -2578,7 +2616,7 @@ if {temp_var} is not None:
2578
2616
  out += [decorators, def_stmt, func_code]
2579
2617
  decorators = ""
2580
2618
 
2581
- # handle copyclosure functions
2619
+ # handle copyclosure functions and type_code
2582
2620
  if copyclosure:
2583
2621
  vars_var = self.get_temp_var("func_vars", loc)
2584
2622
  func_from_vars = vars_var + '["' + def_name + '"]'
@@ -2591,24 +2629,39 @@ if {temp_var} is not None:
2591
2629
  handle_indentation(
2592
2630
  '''
2593
2631
  if _coconut.typing.TYPE_CHECKING:
2594
- {code}
2632
+ {type_code}
2595
2633
  {vars_var} = {{"{def_name}": {def_name}}}
2596
2634
  else:
2597
2635
  {vars_var} = _coconut.globals().copy()
2598
2636
  {vars_var}.update(_coconut.locals())
2599
2637
  _coconut_exec({code_str}, {vars_var})
2600
2638
  {func_name} = {func_from_vars}
2601
- ''',
2639
+ ''',
2602
2640
  add_newline=True,
2603
2641
  ).format(
2604
2642
  func_name=func_name,
2605
2643
  def_name=def_name,
2606
2644
  vars_var=vars_var,
2607
- code=code,
2645
+ type_code=code if type_code is None else type_code,
2608
2646
  code_str=self.wrap_str_of(self.reformat_post_deferred_code_proc(code)),
2609
2647
  func_from_vars=func_from_vars,
2610
2648
  ),
2611
2649
  ]
2650
+ elif type_code:
2651
+ out = [
2652
+ handle_indentation(
2653
+ '''
2654
+ if _coconut.typing.TYPE_CHECKING:
2655
+ {type_code}
2656
+ else:
2657
+ {code}
2658
+ ''',
2659
+ add_newline=True,
2660
+ ).format(
2661
+ type_code=type_code,
2662
+ code="".join(out),
2663
+ ),
2664
+ ]
2612
2665
 
2613
2666
  internal_assert(not decorators, "unhandled decorators", decorators)
2614
2667
  return "".join(out)
@@ -2664,29 +2717,21 @@ else:
2664
2717
  func_id = int(assert_remove_prefix(line, funcwrapper))
2665
2718
  original, loc, decorators, funcdef, is_async, in_method, is_stmt_lambda = self.get_ref("func", func_id)
2666
2719
 
2667
- # process inner code
2720
+ # process inner code (we use tempsep to tell what was newly added before the funcdef)
2668
2721
  decorators = self.deferred_code_proc(decorators, add_code_at_start=True, ignore_names=ignore_names, **kwargs)
2669
- funcdef = self.deferred_code_proc(funcdef, ignore_names=ignore_names, **kwargs)
2670
-
2671
- # handle any non-function code that was added before the funcdef
2672
- pre_def_lines = []
2673
- post_def_lines = []
2674
- funcdef_lines = list(literal_lines(funcdef, True))
2675
- for i, line in enumerate(funcdef_lines):
2676
- line_indent, line_base = split_leading_indent(line)
2677
- if self.def_regex.match(line_base):
2678
- pre_def_lines = funcdef_lines[:i]
2679
- post_def_lines = funcdef_lines[i:]
2680
- break
2681
- internal_assert(post_def_lines, "no def statement found in funcdef", funcdef)
2682
-
2683
- out.append(bef_ind)
2684
- out += pre_def_lines
2685
- func_indent, func_code, func_dedent = split_leading_trailing_indent("".join(post_def_lines), symmetric=True)
2686
- out.append(func_indent)
2687
- out.append(self.proc_funcdef(original, loc, decorators, func_code, is_async, in_method, is_stmt_lambda))
2688
- out.append(func_dedent)
2689
- out.append(aft_ind)
2722
+ raw_funcdef = self.deferred_code_proc(tempsep + funcdef, ignore_names=ignore_names, **kwargs)
2723
+
2724
+ pre_funcdef, post_funcdef = raw_funcdef.split(tempsep)
2725
+ func_indent, func_code, func_dedent = split_leading_trailing_indent(post_funcdef, symmetric=True)
2726
+
2727
+ out += [
2728
+ bef_ind,
2729
+ pre_funcdef,
2730
+ func_indent,
2731
+ self.proc_funcdef(original, loc, decorators, func_code, is_async, in_method, is_stmt_lambda),
2732
+ func_dedent,
2733
+ aft_ind,
2734
+ ]
2690
2735
 
2691
2736
  # look for add_code_before regexes
2692
2737
  else:
@@ -3451,7 +3496,6 @@ def __new__(_coconut_cls, {all_args}):
3451
3496
  IMPORTANT: Any changes to assemble_data must be reflected in the
3452
3497
  definition of Expected in header.py_template.
3453
3498
  """
3454
- print(paramdefs)
3455
3499
  # create class
3456
3500
  out = []
3457
3501
  if paramdefs:
@@ -3491,7 +3535,7 @@ __ne__ = _coconut.object.__ne__
3491
3535
  def __eq__(self, other):
3492
3536
  return self.__class__ is other.__class__ and _coconut.tuple.__eq__(self, other)
3493
3537
  def __hash__(self):
3494
- return _coconut.tuple.__hash__(self) ^ hash(self.__class__)
3538
+ return _coconut.tuple.__hash__(self) ^ _coconut.hash(self.__class__)
3495
3539
  """,
3496
3540
  add_newline=True,
3497
3541
  ).format(
@@ -3825,45 +3869,70 @@ if not {check_var}:
3825
3869
 
3826
3870
  def base_case_funcdef_handle(self, original, loc, tokens):
3827
3871
  """Process case def function definitions."""
3828
- if len(tokens) == 3:
3829
- name, typedef_grp, cases = tokens
3872
+ if len(tokens) == 2:
3873
+ name_toks, cases = tokens
3830
3874
  docstring = None
3831
- elif len(tokens) == 4:
3832
- name, typedef_grp, docstring, cases = tokens
3875
+ elif len(tokens) == 3:
3876
+ name_toks, docstring, cases = tokens
3833
3877
  else:
3834
3878
  raise CoconutInternalException("invalid case function definition tokens", tokens)
3835
- if typedef_grp:
3836
- typedef, = typedef_grp
3879
+
3880
+ type_param_code = ""
3881
+ if len(name_toks) == 1:
3882
+ name, = name_toks
3837
3883
  else:
3838
- typedef = None
3884
+ name, paramdefs = name_toks
3885
+ # paramdefs are type params on >= 3.12 and type var assignments on < 3.12
3886
+ if self.target_info >= (3, 12):
3887
+ name += "[" + ", ".join(paramdefs) + "]"
3888
+ else:
3889
+ type_param_code = "".join(paramdefs)
3839
3890
 
3840
3891
  check_var = self.get_temp_var("match_check", loc)
3841
3892
 
3842
3893
  all_case_code = []
3894
+ all_type_defs = []
3843
3895
  for case_toks in cases:
3844
- if len(case_toks) == 2:
3845
- matches, body = case_toks
3846
- cond = None
3847
- else:
3848
- matches, cond, body = case_toks
3849
- matcher = self.get_matcher(original, loc, check_var)
3850
- matcher.match_function_toks(matches, include_setup=False)
3851
- if cond is not None:
3852
- matcher.add_guard(cond)
3853
- all_case_code.append(handle_indentation("""
3896
+ if "match" in case_toks:
3897
+ if len(case_toks) == 2:
3898
+ matches, body = case_toks
3899
+ cond = None
3900
+ else:
3901
+ matches, cond, body = case_toks
3902
+ matcher = self.get_matcher(original, loc, check_var)
3903
+ matcher.match_function_toks(matches, include_setup=False)
3904
+ if cond is not None:
3905
+ matcher.add_guard(cond)
3906
+ all_case_code.append(handle_indentation("""
3854
3907
  if not {check_var}:
3855
3908
  {match_to_kwargs_var} = {match_to_kwargs_var}_store.copy()
3856
3909
  {match_out}
3857
3910
  if {check_var}:
3858
3911
  {body}
3859
- """).format(
3860
- check_var=check_var,
3861
- match_to_kwargs_var=match_to_kwargs_var,
3862
- match_out=matcher.out(),
3863
- body=body,
3864
- ))
3912
+ """).format(
3913
+ check_var=check_var,
3914
+ match_to_kwargs_var=match_to_kwargs_var,
3915
+ match_out=matcher.out(),
3916
+ body=body,
3917
+ ))
3918
+ elif "type" in case_toks:
3919
+ typed_params, typed_ret = case_toks
3920
+ all_type_defs.append(handle_indentation("""
3921
+ def {name}{typed_params}{typed_ret}
3922
+ return {ellipsis}
3923
+ """).format(
3924
+ name=name,
3925
+ typed_params=typed_params,
3926
+ typed_ret=typed_ret,
3927
+ ellipsis=self.any_type_ellipsis(),
3928
+ ))
3929
+ else:
3930
+ raise CoconutInternalException("invalid case_funcdef case_toks", case_toks)
3931
+
3932
+ if type_param_code and not all_type_defs:
3933
+ raise CoconutDeferredSyntaxError("type parameters in case def but no type declaration cases", loc)
3865
3934
 
3866
- code = handle_indentation("""
3935
+ func_code = handle_indentation("""
3867
3936
  def {name}({match_func_paramdef}):
3868
3937
  {docstring}
3869
3938
  {check_var} = False
@@ -3881,17 +3950,11 @@ def {name}({match_func_paramdef}):
3881
3950
  all_case_code="\n".join(all_case_code),
3882
3951
  error=self.pattern_error(original, loc, match_to_args_var, check_var, function_match_error_var),
3883
3952
  )
3884
- if typedef is None:
3885
- return code
3886
- else:
3887
- return handle_indentation("""
3888
- {typedef_stmt}
3889
- if not _coconut.typing.TYPE_CHECKING:
3890
- {code}
3891
- """).format(
3892
- code=code,
3893
- typedef_stmt=self.typed_assign_stmt_handle([name, typedef, self.any_type_ellipsis()]),
3894
- )
3953
+
3954
+ if not (type_param_code or all_type_defs):
3955
+ return func_code
3956
+
3957
+ return "case " + self.add_ref("case_def", (type_param_code, all_type_defs)) + unwrapper + func_code
3895
3958
 
3896
3959
  def set_literal_handle(self, tokens):
3897
3960
  """Converts set literals to the right form for the target Python."""
@@ -2251,7 +2251,7 @@ class Grammar(object):
2251
2251
  with_stmt = Forward()
2252
2252
 
2253
2253
  funcname_typeparams = Forward()
2254
- funcname_typeparams_ref = dotted_setname + Optional(type_params)
2254
+ funcname_typeparams_tokens = dotted_setname + Optional(type_params)
2255
2255
  name_funcdef = condense(funcname_typeparams + parameters)
2256
2256
  op_tfpdef = unsafe_typedef_default | condense(setname + Optional(default))
2257
2257
  op_funcdef_arg = setname | condense(lparen.suppress() + op_tfpdef + rparen.suppress())
@@ -2359,39 +2359,48 @@ class Grammar(object):
2359
2359
  base_case_funcdef = Forward()
2360
2360
  base_case_funcdef_ref = (
2361
2361
  keyword("def").suppress()
2362
- + funcname_typeparams
2362
+ + Group(funcname_typeparams_tokens)
2363
2363
  + colon.suppress()
2364
- - Group(Optional(typedef_test))
2365
2364
  - newline.suppress()
2366
2365
  - indent.suppress()
2367
2366
  - Optional(docstring)
2368
- - Group(OneOrMore(Group(
2369
- keyword("match").suppress()
2370
- + lparen.suppress()
2371
- + match_args_list
2372
- + rparen.suppress()
2373
- + match_guard
2374
- + (
2375
- colon.suppress()
2376
- + (
2377
- newline.suppress()
2378
- + indent.suppress()
2379
- + attach(condense(OneOrMore(stmt)), make_suite_handle)
2380
- + dedent.suppress()
2381
- | attach(simple_stmt, make_suite_handle)
2382
- )
2383
- | equals.suppress()
2367
+ - Group(OneOrMore(
2368
+ labeled_group(
2369
+ keyword("match").suppress()
2370
+ + lparen.suppress()
2371
+ + match_args_list
2372
+ + match_guard
2373
+ + rparen.suppress()
2384
2374
  + (
2385
- (
2375
+ colon.suppress()
2376
+ + (
2386
2377
  newline.suppress()
2387
2378
  + indent.suppress()
2388
- + attach(math_funcdef_body, make_suite_handle)
2379
+ + attach(condense(OneOrMore(stmt)), make_suite_handle)
2389
2380
  + dedent.suppress()
2381
+ | attach(simple_stmt, make_suite_handle)
2390
2382
  )
2391
- | attach(implicit_return_stmt, make_suite_handle)
2392
- )
2383
+ | equals.suppress()
2384
+ + (
2385
+ (
2386
+ newline.suppress()
2387
+ + indent.suppress()
2388
+ + attach(math_funcdef_body, make_suite_handle)
2389
+ + dedent.suppress()
2390
+ )
2391
+ | attach(implicit_return_stmt, make_suite_handle)
2392
+ )
2393
+ ),
2394
+ "match",
2393
2395
  )
2394
- )))
2396
+ | labeled_group(
2397
+ keyword("type").suppress()
2398
+ + parameters
2399
+ + return_typedef
2400
+ + newline.suppress(),
2401
+ "type",
2402
+ )
2403
+ ))
2395
2404
  - dedent.suppress()
2396
2405
  )
2397
2406
  case_funcdef = keyword("case").suppress() + base_case_funcdef
@@ -1077,7 +1077,7 @@ def load_cache_for(inputstring, codepath):
1077
1077
  incremental_info=incremental_info,
1078
1078
  ))
1079
1079
  if incremental_enabled:
1080
- logger.warn("Populating initial parsing cache (compilation may take longer than usual)...")
1080
+ logger.warn("Populating initial parsing cache (initial compilation may take a while; pass --no-cache to disable)...")
1081
1081
  else:
1082
1082
  cache_path = None
1083
1083
  logger.log("Declined to load cache for {filename!r} ({incremental_info}).".format(
@@ -291,6 +291,7 @@ errwrapper = "\u24d8" # circled letter i
291
291
  early_passthrough_wrapper = "\u2038" # caret
292
292
  lnwrapper = "\u2021" # double dagger
293
293
  unwrapper = "\u23f9" # stop square
294
+ tempsep = "\u22ee" # vertical ellipsis
294
295
  funcwrapper = "def:"
295
296
 
296
297
  # must be tuples for .startswith / .endswith purposes
@@ -314,6 +315,7 @@ delimiter_symbols = tuple(open_chars + close_chars + str_chars) + (
314
315
  ) + indchars + comment_chars
315
316
  reserved_compiler_symbols = delimiter_symbols + (
316
317
  reserved_prefix,
318
+ tempsep,
317
319
  funcwrapper,
318
320
  )
319
321
 
@@ -26,7 +26,7 @@ import sys as _coconut_sys
26
26
  VERSION = "3.1.0"
27
27
  VERSION_NAME = None
28
28
  # False for release, int >= 1 for develop
29
- DEVELOP = 6
29
+ DEVELOP = 7
30
30
  ALPHA = False # for pre releases rather than post releases
31
31
 
32
32
  assert DEVELOP is False or DEVELOP >= 1, "DEVELOP must be False or an int >= 1"
@@ -339,7 +339,7 @@ def call(
339
339
  continue
340
340
 
341
341
  # combine mypy error lines
342
- if any(infix in line for infix in mypy_err_infixes):
342
+ if any(infix in line for infix in mypy_err_infixes) and i < len(raw_lines) - 1:
343
343
  # always add the next line, since it might be a continuation of the error message
344
344
  line += "\n" + raw_lines[i + 1]
345
345
  i += 1
@@ -680,6 +680,9 @@ def run(
680
680
  """Compiles and runs tests."""
681
681
  assert use_run_arg + run_directory < 2
682
682
 
683
+ if manage_cache and "--no-cache" not in args:
684
+ args += ["--no-cache"]
685
+
683
686
  if agnostic_target is None:
684
687
  agnostic_args = args
685
688
  else:
@@ -437,6 +437,7 @@ def suite_test() -> bool:
437
437
  assert partition([1, 2, 3], 2) |> map$(tuple) |> list == [(1,), (3, 2)] == partition_([1, 2, 3], 2) |> map$(tuple) |> list
438
438
  assert myreduce((+), (1, 2, 3)) == 6
439
439
  assert recurse_n_times(10000)
440
+ assert recurse_n_times_(10000)
440
441
  assert fake_recurse_n_times(10000)
441
442
  a = clsA()
442
443
  assert ((not)..a.true)() is False
@@ -535,7 +536,7 @@ def suite_test() -> bool:
535
536
  assert False
536
537
  tv = typed_vector()
537
538
  assert repr(tv) == "typed_vector(x=0, y=0)"
538
- for obj in (factorial, iadd, collatz, recurse_n_times):
539
+ for obj in (factorial, iadd, collatz, recurse_n_times, recurse_n_times_):
539
540
  assert obj.__doc__ == "this is a docstring", obj
540
541
  assert list_type((|1,2|)) == "at least 2"
541
542
  assert list_type((|1|)) == "at least 1"
@@ -632,8 +633,8 @@ def suite_test() -> bool:
632
633
  assert dt.N()$[:2] |> list == [(dt, 0), (dt, 1)] == dt.N_()$[:2] |> list
633
634
  assert map(HasDefs().a_def, range(5)) |> list == range(1, 6) |> list
634
635
  assert HasDefs().a_def 1 == 2
635
- assert HasDefs().case_def 1 == 0
636
- assert HasDefs.__annotations__.keys() |> list == ["a_def", "case_def"]
636
+ assert HasDefs().case_def 1 == 0 == HasDefs().case_def_ 1
637
+ assert HasDefs.__annotations__.keys() |> set == {"a_def"}, HasDefs.__annotations__
637
638
  assert store.plus1 store.one == store.two
638
639
  assert ret_locals()["my_loc"] == 1
639
640
  assert ret_globals()["my_glob"] == 1
@@ -1085,6 +1086,8 @@ forward 2""") == 900
1085
1086
  assert ret_args_kwargs ↤** dict(a=1) == ((), dict(a=1))
1086
1087
  assert ret_args_kwargs ↤**? None is None
1087
1088
  assert [1, 2, 3] |> reduce_with_init$(+) == 6 == (1, 2, 3) |> iter |> reduce_with_init$((+), init=0)
1089
+ assert min(1, 2) == 1 == my_min(1, 2)
1090
+ assert min([1, 2]) == 1 == my_min([1, 2])
1088
1091
 
1089
1092
  with process_map.multiple_sequential_calls(): # type: ignore
1090
1093
  assert process_map(tuple <.. (|>)$(to_sort), qsorts) |> list == [to_sort |> sorted |> tuple] * len(qsorts)
@@ -2,6 +2,7 @@
2
2
  import sys
3
3
  import random
4
4
  import pickle
5
+ import typing
5
6
  import operator # NOQA
6
7
  from contextlib import contextmanager
7
8
  from functools import wraps
@@ -10,6 +11,8 @@ from collections import defaultdict, deque
10
11
  __doc__ = "docstring"
11
12
 
12
13
  # Helpers:
14
+ ___ = typing.cast(typing.Any, ...)
15
+
13
16
  def rand_list(n):
14
17
  '''Generate a random list of length n.'''
15
18
  return [random.randrange(10) for x in range(0, n)]
@@ -243,7 +246,6 @@ addpattern def x! if x = False # type: ignore
243
246
  addpattern def x! = True # type: ignore
244
247
 
245
248
  # Type aliases:
246
- import typing
247
249
  if sys.version_info >= (3, 5) or TYPE_CHECKING:
248
250
  type list_or_tuple = list | tuple
249
251
 
@@ -395,6 +397,11 @@ def recurse_n_times(n) =
395
397
  return True
396
398
  recurse_n_times(n-1)
397
399
 
400
+ case def recurse_n_times_:
401
+ """this is a docstring"""
402
+ match(0) = True
403
+ match(n) = recurse_n_times_(n-1)
404
+
398
405
  def is_even(n) =
399
406
  if not n:
400
407
  return True
@@ -632,18 +639,20 @@ def factorial5(value):
632
639
  else:
633
640
  return None
634
641
  raise TypeError()
635
- case def factorial6[Num: (int, float)]: (Num, Num) -> Num
642
+ case def factorial6[Num: (int, float)]:
636
643
  """Factorial function"""
644
+ type(n: Num, acc: Num = ___) -> Num
637
645
  match (0, acc=1):
638
646
  return acc
639
- match (int(n), acc=1) if n > 0:
647
+ match (int(n), acc=1 if n > 0):
640
648
  return factorial6(n - 1, acc * n)
641
- match (int(n), acc=...) if n < 0:
649
+ match (int(n), acc=... if n < 0):
642
650
  return None
643
- case def factorial7[Num <: int | float]: (Num, Num) -> Num
651
+ case def factorial7[Num <: int | float]:
652
+ type(n: Num, acc: Num = ___) -> Num
644
653
  match(0, acc=1) = acc
645
- match(int(n), acc=1) if n > 0 = factorial7(n - 1, acc * n)
646
- match(int(n), acc=...) if n < 0 = None
654
+ match(int(n), acc=1 if n > 0) = factorial7(n - 1, acc * n)
655
+ match(int(n), acc=... if n < 0) = None
647
656
 
648
657
  match def fact(n) = fact(n, 1)
649
658
  match addpattern def fact(0, acc) = acc # type: ignore
@@ -1414,13 +1423,20 @@ class HasDefs:
1414
1423
  a_def: typing.Callable
1415
1424
 
1416
1425
  @staticmethod
1417
- case def case_def: int -> int
1426
+ case def case_def:
1427
+ type(_: int) -> int
1418
1428
  match(0) = 1
1419
1429
  match(1) = 0
1420
1430
 
1421
1431
  def HasDefs.a_def(self, 0) = 1 # type: ignore
1422
1432
  addpattern def HasDefs.a_def(self, x) = x + 1 # type: ignore
1423
1433
 
1434
+ @staticmethod # type: ignore
1435
+ case def HasDefs.case_def_: # type: ignore
1436
+ type(_: int) -> int
1437
+ match(0) = 1
1438
+ match(1) = 0
1439
+
1424
1440
 
1425
1441
  # Storage class
1426
1442
  class store:
@@ -2080,3 +2096,15 @@ def outer_func_6():
2080
2096
  match() = x
2081
2097
  funcs.append(inner_func)
2082
2098
  return funcs
2099
+
2100
+
2101
+ # case def
2102
+
2103
+ case def my_min[T]:
2104
+ type(xs: T[]) -> T
2105
+ match([x]) = x
2106
+ match([x] + xs) = my_min(x, my_min(xs))
2107
+
2108
+ type(x: T, y: T) -> T
2109
+ match(x, y if x <= y) = x
2110
+ match(x, y) = y