coconut-develop 3.0.4.post0.dev3__tar.gz → 3.0.4.post0.dev4__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 (88) hide show
  1. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/DOCS.md +21 -12
  2. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/PKG-INFO +1 -1
  3. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/compiler.py +22 -0
  4. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/grammar.py +27 -2
  5. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/root.py +1 -1
  6. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/primary_2.coco +9 -0
  7. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/CONTRIBUTING.md +0 -0
  8. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/FAQ.md +0 -0
  9. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/HELP.md +0 -0
  10. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/LICENSE.txt +0 -0
  11. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/MANIFEST.in +0 -0
  12. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/README.rst +0 -0
  13. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/__coconut__/__init__.py +0 -0
  14. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/__coconut__/__init__.pyi +0 -0
  15. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/__coconut__/py.typed +0 -0
  16. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/_coconut/__init__.py +0 -0
  17. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/_coconut/__init__.pyi +0 -0
  18. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/_coconut/py.typed +0 -0
  19. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/__coconut__.py +0 -0
  20. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/__coconut__.pyi +0 -0
  21. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/__init__.py +0 -0
  22. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/__init__.pyi +0 -0
  23. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/__main__.py +0 -0
  24. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/_pyparsing.py +0 -0
  25. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/api.py +0 -0
  26. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/api.pyi +0 -0
  27. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/__init__.py +0 -0
  28. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/__init__.pyi +0 -0
  29. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/cli.py +0 -0
  30. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/command.py +0 -0
  31. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/command.pyi +0 -0
  32. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/mypy.py +0 -0
  33. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/resources/zcoconut.pth +0 -0
  34. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/util.py +0 -0
  35. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/command/watch.py +0 -0
  36. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/__init__.py +0 -0
  37. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/header.py +0 -0
  38. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/matching.py +0 -0
  39. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/templates/header.py_template +0 -0
  40. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/compiler/util.py +0 -0
  41. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/constants.py +0 -0
  42. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/convenience.py +0 -0
  43. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/convenience.pyi +0 -0
  44. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/exceptions.py +0 -0
  45. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/highlighter.py +0 -0
  46. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/__init__.py +0 -0
  47. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/__main__.py +0 -0
  48. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/coconut/kernel.json +0 -0
  49. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/coconut_py/kernel.json +0 -0
  50. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/coconut_py2/kernel.json +0 -0
  51. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/coconut_py3/kernel.json +0 -0
  52. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/embed.py +0 -0
  53. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/icoconut/root.py +0 -0
  54. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/integrations.py +0 -0
  55. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/main.py +0 -0
  56. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/py.typed +0 -0
  57. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/requirements.py +0 -0
  58. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/terminal.py +0 -0
  59. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/__init__.py +0 -0
  60. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/__main__.py +0 -0
  61. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/constants_test.py +0 -0
  62. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/main_test.py +0 -0
  63. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/__init__.coco +0 -0
  64. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/main.coco +0 -0
  65. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/primary_1.coco +0 -0
  66. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/specific.coco +0 -0
  67. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/suite.coco +0 -0
  68. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/tutorial.coco +0 -0
  69. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/agnostic/util.coco +0 -0
  70. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/non_strict/non_strict_test.coco +0 -0
  71. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_2/py2_test.coco +0 -0
  72. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_3/py3_test.coco +0 -0
  73. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_311/py311_test.coco +0 -0
  74. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_35/py35_test.coco +0 -0
  75. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_36/py36_test.coco +0 -0
  76. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_38/py38_test.coco +0 -0
  77. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/cocotest/target_sys/target_sys_test.coco +0 -0
  78. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/extras.coco +0 -0
  79. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/importable.coco +0 -0
  80. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/runnable.coco +0 -0
  81. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/tests/src/runner.coco +0 -0
  82. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut/util.py +0 -0
  83. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/coconut_develop.egg-info/SOURCES.txt +0 -0
  84. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/conf.py +0 -0
  85. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/pyproject.toml +0 -0
  86. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/setup.cfg +0 -0
  87. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/setup.py +0 -0
  88. {coconut-develop-3.0.4.post0.dev3 → coconut-develop-3.0.4.post0.dev4}/xontrib/coconut.py +0 -0
@@ -1853,25 +1853,34 @@ print(list(map(operator.add, range(0, 5), range(5, 10))))
1853
1853
 
1854
1854
  Coconut supports a number of different syntactical aliases for common partial application use cases. These are:
1855
1855
  ```coconut
1856
- .attr => operator.attrgetter("attr")
1857
- .method(args) => operator.methodcaller("method", args)
1858
- func$ => ($)$(func)
1859
- seq[] => operator.getitem$(seq)
1860
- iter$[] => # the equivalent of seq[] for iterators
1861
- .[a:b:c] => operator.itemgetter(slice(a, b, c))
1862
- .$[a:b:c] => # the equivalent of .[a:b:c] for iterators
1863
- ```
1856
+ # attribute access and method calling
1857
+ .attr1.attr2 => operator.attrgetter("attr1.attr2")
1858
+ .method(args) => operator.methodcaller("method", args)
1859
+ .attr.method(args) => .attr ..> .method(args)
1860
+
1861
+ # indexing
1862
+ .[a:b:c] => operator.itemgetter(slice(a, b, c))
1863
+ .[x][y] => .[x] ..> .[y]
1864
+ .method[x] => .method ..> .[x]
1865
+ seq[] => operator.getitem$(seq)
1864
1866
 
1865
- Additionally, `.attr.method(args)`, `.[x][y]`, `.$[x]$[y]`, and `.method[x]` are also supported.
1867
+ # iterator indexing
1868
+ .$[a:b:c] => # the equivalent of .[a:b:c] for iterators
1869
+ .$[x]$[y] => .$[x] ..> .$[y]
1870
+ iter$[] => # the equivalent of seq[] for iterators
1871
+
1872
+ # currying
1873
+ func$ => ($)$(func)
1874
+ ```
1866
1875
 
1867
1876
  In addition, for every Coconut [operator function](#operator-functions), Coconut supports syntax for implicitly partially applying that operator function as
1868
1877
  ```
1869
1878
  (. <op> <arg>)
1870
1879
  (<arg> <op> .)
1871
1880
  ```
1872
- where `<op>` is the operator function and `<arg>` is any expression. Note that, as with operator functions themselves, the parentheses are necessary for this type of implicit partial application.
1881
+ where `<op>` is the operator function and `<arg>` is any expression. Note that, as with operator functions themselves, the parentheses are necessary for this type of implicit partial application. This syntax is slightly different for multidimensional array concatenation operator functions, which use brackets instead of parentheses.
1873
1882
 
1874
- Additionally, Coconut also supports implicit operator function partials for arbitrary functions as
1883
+ Furthermore, Coconut also supports implicit operator function partials for arbitrary functions as
1875
1884
  ```
1876
1885
  (. `<name>` <arg>)
1877
1886
  (<arg> `<name>` .)
@@ -2071,7 +2080,7 @@ If multiple different concatenation operators are used, the operators with the l
2071
2080
  [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
2072
2081
  ```
2073
2082
 
2074
- _Note: the [operator functions](#operator-functions) for multidimensional array concatenation are spelled `[;]`, `[;;]`, etc. (for any number of parentheses)._
2083
+ _Note: the [operator functions](#operator-functions) for multidimensional array concatenation are spelled `[;]`, `[;;]`, etc. (with any number of parentheses). The [implicit partials](#implicit-partial-application) are similarly spelled `[. ; x]`, `[x ; .]`, etc._
2075
2084
 
2076
2085
  ##### Comparison to Julia
2077
2086
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: coconut-develop
3
- Version: 3.0.4.post0.dev3
3
+ Version: 3.0.4.post0.dev4
4
4
  Summary: Simple, elegant, Pythonic functional programming.
5
5
  Home-page: http://coconut-lang.org
6
6
  Author: Evan Hubinger
@@ -130,6 +130,7 @@ from coconut.compiler.grammar import (
130
130
  attrgetter_atom_handle,
131
131
  itemgetter_handle,
132
132
  partial_op_item_handle,
133
+ partial_arr_concat_handle,
133
134
  )
134
135
  from coconut.compiler.util import (
135
136
  ExceptionNode,
@@ -2763,6 +2764,7 @@ else:
2763
2764
  - (name, args) for attr/method
2764
2765
  - (attr, [(op, args)]) for itemgetter
2765
2766
  - (op, arg) for right op partial
2767
+ - (op, arg) for right arr concat partial
2766
2768
  """
2767
2769
  # list implies artificial tokens, which must be expr
2768
2770
  if isinstance(tokens, list) or "expr" in tokens:
@@ -2792,6 +2794,18 @@ else:
2792
2794
  return "right op partial", (op, arg)
2793
2795
  else:
2794
2796
  raise CoconutInternalException("invalid op partial tokens in pipe_item", inner_toks)
2797
+ elif "arr concat partial" in tokens:
2798
+ inner_toks, = tokens
2799
+ if "left arr concat partial" in inner_toks:
2800
+ arg, op = inner_toks
2801
+ internal_assert(op.lstrip(";") == "", "invalid arr concat op", op)
2802
+ return "partial", ("_coconut_arr_concat_op", str(len(op)) + ", " + arg, "")
2803
+ elif "right arr concat partial" in inner_toks:
2804
+ op, arg = inner_toks
2805
+ internal_assert(op.lstrip(";") == "", "invalid arr concat op", op)
2806
+ return "right arr concat partial", (op, arg)
2807
+ else:
2808
+ raise CoconutInternalException("invalid arr concat partial tokens in pipe_item", inner_toks)
2795
2809
  elif "await" in tokens:
2796
2810
  internal_assert(len(tokens) == 1 and tokens[0] == "await", "invalid await pipe item tokens", tokens)
2797
2811
  return "await", []
@@ -2821,6 +2835,8 @@ else:
2821
2835
  return itemgetter_handle(item)
2822
2836
  elif name == "right op partial":
2823
2837
  return partial_op_item_handle(item)
2838
+ elif name == "right arr concat partial":
2839
+ return partial_arr_concat_handle(item)
2824
2840
  elif name == "await":
2825
2841
  raise CoconutDeferredSyntaxError("await in pipe must have something piped into it", loc)
2826
2842
  else:
@@ -2889,6 +2905,12 @@ else:
2889
2905
  raise CoconutDeferredSyntaxError("cannot star pipe into operator partial", loc)
2890
2906
  op, arg = split_item
2891
2907
  return "({op})({x}, {arg})".format(op=op, x=subexpr, arg=arg)
2908
+ elif name == "right arr concat partial":
2909
+ if stars:
2910
+ raise CoconutDeferredSyntaxError("cannot star pipe into array concatenation operator partial", loc)
2911
+ op, arg = split_item
2912
+ internal_assert(op.lstrip(";") == "", "invalid arr concat op", op)
2913
+ return "_coconut_arr_concat_op({dim}, {x}, {arg})".format(dim=len(op), x=subexpr, arg=arg)
2892
2914
  elif name == "await":
2893
2915
  internal_assert(not split_item, "invalid split await pipe item tokens", split_item)
2894
2916
  if stars:
@@ -550,6 +550,21 @@ def partial_op_item_handle(tokens):
550
550
  raise CoconutInternalException("invalid operator function implicit partial token group", tok_grp)
551
551
 
552
552
 
553
+ def partial_arr_concat_handle(tokens):
554
+ """Handle array concatenation operator function implicit partials."""
555
+ tok_grp, = tokens
556
+ if "left arr concat partial" in tok_grp:
557
+ arg, op = tok_grp
558
+ internal_assert(op.lstrip(";") == "", "invalid arr concat op", op)
559
+ return "_coconut_partial(_coconut_arr_concat_op, " + str(len(op)) + ", " + arg + ")"
560
+ elif "right arr concat partial" in tok_grp:
561
+ op, arg = tok_grp
562
+ internal_assert(op.lstrip(";") == "", "invalid arr concat op", op)
563
+ return "_coconut_complex_partial(_coconut_arr_concat_op, {{0: {dim}, 2: {arg}}}, 3, ())".format(dim=len(op), arg=arg)
564
+ else:
565
+ raise CoconutInternalException("invalid array concatenation operator function implicit partial token group", tok_grp)
566
+
567
+
553
568
  def array_literal_handle(loc, tokens):
554
569
  """Handle multidimensional array literals."""
555
570
  internal_assert(len(tokens) >= 1, "invalid array literal tokens", tokens)
@@ -1071,7 +1086,7 @@ class Grammar(object):
1071
1086
  )
1072
1087
  partial_op_item = attach(partial_op_item_tokens, partial_op_item_handle)
1073
1088
  op_item = (
1074
- # partial_op_item must come first, then typedef_op_item must come after base_op_item
1089
+ # must stay in exactly this order
1075
1090
  partial_op_item
1076
1091
  | typedef_op_item
1077
1092
  | base_op_item
@@ -1079,6 +1094,12 @@ class Grammar(object):
1079
1094
 
1080
1095
  partial_op_atom_tokens = lparen.suppress() + partial_op_item_tokens + rparen.suppress()
1081
1096
 
1097
+ partial_arr_concat_tokens = lbrack.suppress() + (
1098
+ labeled_group(dot.suppress() + multisemicolon + test_no_infix + rbrack.suppress(), "right arr concat partial")
1099
+ | labeled_group(test_no_infix + multisemicolon + dot.suppress() + rbrack.suppress(), "left arr concat partial")
1100
+ )
1101
+ partial_arr_concat = attach(partial_arr_concat_tokens, partial_arr_concat_handle)
1102
+
1082
1103
  # we include (var)arg_comma to ensure the pattern matches the whole arg
1083
1104
  arg_comma = comma | fixto(FollowedBy(rparen), "")
1084
1105
  setarg_comma = arg_comma | fixto(FollowedBy(colon), "")
@@ -1234,7 +1255,8 @@ class Grammar(object):
1234
1255
  list_item = (
1235
1256
  lbrack.suppress() + list_expr + rbrack.suppress()
1236
1257
  | condense(lbrack + Optional(comprehension_expr) + rbrack)
1237
- # array_literal must come last
1258
+ # partial_arr_concat and array_literal must come last
1259
+ | partial_arr_concat
1238
1260
  | array_literal
1239
1261
  )
1240
1262
 
@@ -1544,6 +1566,7 @@ class Grammar(object):
1544
1566
  | labeled_group(itemgetter_atom_tokens, "itemgetter") + pipe_op
1545
1567
  | labeled_group(attrgetter_atom_tokens, "attrgetter") + pipe_op
1546
1568
  | labeled_group(partial_op_atom_tokens, "op partial") + pipe_op
1569
+ | labeled_group(partial_arr_concat_tokens, "arr concat partial") + pipe_op
1547
1570
  # expr must come at end
1548
1571
  | labeled_group(comp_pipe_expr, "expr") + pipe_op
1549
1572
  )
@@ -1554,6 +1577,7 @@ class Grammar(object):
1554
1577
  | labeled_group(itemgetter_atom_tokens, "itemgetter") + end_simple_stmt_item
1555
1578
  | labeled_group(attrgetter_atom_tokens, "attrgetter") + end_simple_stmt_item
1556
1579
  | labeled_group(partial_op_atom_tokens, "op partial") + end_simple_stmt_item
1580
+ | labeled_group(partial_arr_concat_tokens, "arr concat partial") + end_simple_stmt_item
1557
1581
  )
1558
1582
  last_pipe_item = Group(
1559
1583
  lambdef("expr")
@@ -1564,6 +1588,7 @@ class Grammar(object):
1564
1588
  attrgetter_atom_tokens("attrgetter"),
1565
1589
  partial_atom_tokens("partial"),
1566
1590
  partial_op_atom_tokens("op partial"),
1591
+ partial_arr_concat_tokens("arr concat partial"),
1567
1592
  comp_pipe_expr("expr"),
1568
1593
  )
1569
1594
  )
@@ -26,7 +26,7 @@ import sys as _coconut_sys
26
26
  VERSION = "3.0.4"
27
27
  VERSION_NAME = None
28
28
  # False for release, int >= 1 for develop
29
- DEVELOP = 3
29
+ DEVELOP = 4
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"
@@ -411,6 +411,15 @@ def primary_test_2() -> bool:
411
411
  assert 0xff == 255 == 0x100-1
412
412
  assert 11259375 == 0xabcdef
413
413
  assert [[] ;; [] ;;;] == [[[], []]]
414
+ assert (
415
+ 1
416
+ |> [. ; 2]
417
+ |> [[3; 4] ;; .]
418
+ ) == [3; 4;; 1; 2] == [[3; 4] ;; .]([. ; 2](1))
419
+ arr: Any = 1
420
+ arr |>= [. ; 2]
421
+ arr |>= [[3; 4] ;; .]
422
+ assert arr == [3; 4;; 1; 2] == [[3; 4] ;; .] |> call$(?, [. ; 2] |> call$(?, 1))
414
423
 
415
424
  with process_map.multiple_sequential_calls(): # type: ignore
416
425
  assert map((+), range(3), range(4)$[:-1], strict=True) |> list == [0, 2, 4] == process_map((+), range(3), range(4)$[:-1], strict=True) |> list # type: ignore