Skip to content

Commit

Permalink
Release v3.1.0 (#829)
Browse files Browse the repository at this point in the history
See Coconut's
[documentation](http://coconut.readthedocs.io/en/develop/DOCS.html) for
more information on all of the features listed below.

Language changes:
* #814: Changes to statement lambda scoping rules, including capturing
names introduced in the surrounding expression.
* #618: Changes to handling of pattern-matching function defaults
including support for e.g. `match def f(x, y=x) = (x, y)`.
* #809: New array concatenation implicit partials (e.g. `[. ; a]`).
* #823: New `(x := .)` implicit partial syntax (only available in
pipes).
* #807: New `lift_apart` built-in combinator.
* #813: New `(if)` operator function.
* #826 (thanks @JayXon!): Better universalization and `fmap` support for
`bytes` and `bytearray`.
* #816: Support for `xarray` to match existing `numpy`/`pandas` support.
* #817: New `to` argument to `all_equal`.
* #821 (thanks @GolfingSuccess!): Expanded implicit function application
syntax to support string literal methods.

Compiler changes:
* #799: `coconut-run` and `coconut --run` now work on packages rather
than just files.
* #812: Better formatting of Coconut exceptions.

Bugfixes:
* #810: Fixed an issue compiling certain syntax constructs in the
Coconut Jupyter kernel.
* #818, #825 (thanks @kg583, @dokutan!): Fixed parsing of different
Unicode line break characters.
* #822 (thanks @JayXon!): Fixed parsing of Unicode backward pipe
operators.
* #819, #820 (thanks @kg583!): Fixed some incompatibilities between
Python and Coconut syntax.
  • Loading branch information
evhub authored Mar 2, 2024
2 parents e8dd479 + d957068 commit 41ac855
Show file tree
Hide file tree
Showing 35 changed files with 2,134 additions and 1,128 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ repos:
args:
- --autofix
- repo: https://github.com/pycqa/flake8
rev: 6.1.0
rev: 7.0.0
hooks:
- id: flake8
args:
Expand Down
165 changes: 125 additions & 40 deletions DOCS.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ test-any-of: test-univ
.PHONY: test-mypy-univ
test-mypy-univ: export COCONUT_USE_COLOR=TRUE
test-mypy-univ: clean
python ./coconut/tests --strict --keep-lines --force --mypy --follow-imports silent --ignore-missing-imports --allow-redefinition
python ./coconut/tests --strict --keep-lines --force --no-cache --mypy --follow-imports silent --ignore-missing-imports --allow-redefinition
python ./coconut/tests/dest/runner.py
python ./coconut/tests/dest/extras.py

# same as test-mypy-univ but uses --target sys
.PHONY: test-mypy
test-mypy: export COCONUT_USE_COLOR=TRUE
test-mypy: clean
python ./coconut/tests --strict --keep-lines --force --target sys --mypy --follow-imports silent --ignore-missing-imports --allow-redefinition
python ./coconut/tests --strict --keep-lines --force --target sys --no-cache --mypy --follow-imports silent --ignore-missing-imports --allow-redefinition
python ./coconut/tests/dest/runner.py
python ./coconut/tests/dest/extras.py

Expand Down Expand Up @@ -198,7 +198,7 @@ test-mypy-verbose: clean
.PHONY: test-mypy-all
test-mypy-all: export COCONUT_USE_COLOR=TRUE
test-mypy-all: clean
python ./coconut/tests --strict --keep-lines --force --target sys --mypy --follow-imports silent --ignore-missing-imports --allow-redefinition --check-untyped-defs
python ./coconut/tests --strict --keep-lines --force --target sys --no-cache --mypy --follow-imports silent --ignore-missing-imports --allow-redefinition --check-untyped-defs
python ./coconut/tests/dest/runner.py
python ./coconut/tests/dest/extras.py

Expand Down
71 changes: 50 additions & 21 deletions __coconut__/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ if sys.version_info < (3, 7):
...


py_bytes = bytes
py_chr = chr
py_dict = dict
py_hex = hex
Expand Down Expand Up @@ -1216,6 +1217,11 @@ def _coconut_comma_op(*args: _t.Any) -> _Tuple:
...


def _coconut_if_op(cond: _t.Any, if_true: _T, if_false: _U) -> _t.Union[_T, _U]:
"""If operator (if). Equivalent to (cond, if_true, if_false) => if_true if cond else if_false."""
...


if sys.version_info < (3, 5):
@_t.overload
def _coconut_matmul(a: _T, b: _T) -> _T: ...
Expand Down Expand Up @@ -1451,7 +1457,7 @@ def fmap(func: _t.Callable[[_T, _U], _t.Tuple[_V, _W]], obj: _t.Mapping[_T, _U],
Supports:
* Coconut data types
* `str`, `dict`, `list`, `tuple`, `set`, `frozenset`
* `str`, `dict`, `list`, `tuple`, `set`, `frozenset`, `bytes`, `bytearray`
* `dict` (maps over .items())
* asynchronous iterables
* numpy arrays (uses np.vectorize)
Expand All @@ -1461,6 +1467,8 @@ def fmap(func: _t.Callable[[_T, _U], _t.Tuple[_V, _W]], obj: _t.Mapping[_T, _U],
"""
...

_coconut_fmap = fmap


def _coconut_handle_cls_kwargs(**kwargs: _t.Dict[_t.Text, _t.Any]) -> _t.Callable[[_T], _T]: ...

Expand Down Expand Up @@ -1636,22 +1644,44 @@ def lift(func: _t.Callable[[_T, _U], _W]) -> _coconut_lifted_2[_T, _U, _W]: ...
def lift(func: _t.Callable[[_T, _U, _V], _W]) -> _coconut_lifted_3[_T, _U, _V, _W]: ...
@_t.overload
def lift(func: _t.Callable[..., _W]) -> _t.Callable[..., _t.Callable[..., _W]]:
"""Lift a function up so that all of its arguments are functions.
"""Lift a function up so that all of its arguments are functions that all take the same arguments.
For a binary function f(x, y) and two unary functions g(z) and h(z), lift works as the S' combinator:
lift(f)(g, h)(z) == f(g(z), h(z))
In general, lift is equivalent to:
def lift(f) = ((*func_args, **func_kwargs) -> (*args, **kwargs) ->
f(*(g(*args, **kwargs) for g in func_args), **{lbrace}k: h(*args, **kwargs) for k, h in func_kwargs.items(){rbrace}))
def lift(f) = ((*func_args, **func_kwargs) => (*args, **kwargs) => (
f(*(g(*args, **kwargs) for g in func_args), **{k: h(*args, **kwargs) for k, h in func_kwargs.items()}))
)
lift also supports a shortcut form such that lift(f, *func_args, **func_kwargs) is equivalent to lift(f)(*func_args, **func_kwargs).
"""
...
_coconut_lift = lift

@_t.overload
def lift_apart(func: _t.Callable[[_T], _W]) -> _t.Callable[[_t.Callable[[_U], _T]], _t.Callable[[_U], _W]]: ...
@_t.overload
def lift_apart(func: _t.Callable[[_T, _X], _W]) -> _t.Callable[[_t.Callable[[_U], _T], _t.Callable[[_Y], _X]], _t.Callable[[_U, _Y], _W]]: ...
@_t.overload
def lift_apart(func: _t.Callable[..., _W]) -> _t.Callable[..., _t.Callable[..., _W]]:
"""Lift a function up so that all of its arguments are functions that each take separate arguments.
For a binary function f(x, y) and two unary functions g(z) and h(z), lift_apart works as the D2 combinator:
lift_apart(f)(g, h)(z, w) == f(g(z), h(w))
In general, lift_apart is equivalent to:
def lift_apart(func) = (*func_args, **func_kwargs) => (*args, **kwargs) => func(
*map(call, func_args, args, strict=True),
**{k: func_kwargs[k](kwargs[k]) for k in func_kwargs.keys() | kwargs.keys()},
)
def all_equal(iterable: _Iterable) -> bool:
lift_apart also supports a shortcut form such that lift_apart(f, *func_args, **func_kwargs) is equivalent to lift_apart(f)(*func_args, **func_kwargs).
"""
...


def all_equal(iterable: _t.Iterable[_T], to: _T = ...) -> bool:
"""For a given iterable, check whether all elements in that iterable are equal to each other.
Supports numpy arrays. Assumes transitivity and 'x != y' being equivalent to 'not (x == y)'.
Expand Down Expand Up @@ -1828,45 +1858,44 @@ def _coconut_mk_anon_namedtuple(


# @_t.overload
# def _coconut_multi_dim_arr(
# arrs: _t.Tuple[_coconut.npt.NDArray[_DType], ...],
# def _coconut_arr_concat_op(
# dim: int,
# *arrs: _coconut.npt.NDArray[_DType],
# ) -> _coconut.npt.NDArray[_DType]: ...
# @_t.overload
# def _coconut_multi_dim_arr(
# arrs: _t.Tuple[_DType, ...],
# def _coconut_arr_concat_op(
# dim: int,
# *arrs: _DType,
# ) -> _coconut.npt.NDArray[_DType]: ...

@_t.overload
def _coconut_multi_dim_arr(
arrs: _t.Tuple[_t.Sequence[_T], ...],
def _coconut_arr_concat_op(
dim: _t.Literal[1],
*arrs: _t.Sequence[_T],
) -> _t.Sequence[_T]: ...
@_t.overload
def _coconut_multi_dim_arr(
arrs: _t.Tuple[_T, ...],
def _coconut_arr_concat_op(
dim: _t.Literal[1],
*arrs: _T,
) -> _t.Sequence[_T]: ...

@_t.overload
def _coconut_multi_dim_arr(
arrs: _t.Tuple[_t.Sequence[_t.Sequence[_T]], ...],
def _coconut_arr_concat_op(
dim: _t.Literal[2],
*arrs: _t.Sequence[_t.Sequence[_T]],
) -> _t.Sequence[_t.Sequence[_T]]: ...
@_t.overload
def _coconut_multi_dim_arr(
arrs: _t.Tuple[_t.Sequence[_T], ...],
def _coconut_arr_concat_op(
dim: _t.Literal[2],
*arrs: _t.Sequence[_T],
) -> _t.Sequence[_t.Sequence[_T]]: ...
@_t.overload
def _coconut_multi_dim_arr(
arrs: _t.Tuple[_T, ...],
def _coconut_arr_concat_op(
dim: _t.Literal[2],
*arrs: _T,
) -> _t.Sequence[_t.Sequence[_T]]: ...

@_t.overload
def _coconut_multi_dim_arr(arrs: _Tuple, dim: int) -> _Sequence: ...
def _coconut_arr_concat_op(dim: int, *arrs: _t.Any) -> _Sequence: ...


class _coconut_SupportsAdd(_t.Protocol, _t.Generic[_Tco, _Ucontra, _Vco]):
Expand Down
6 changes: 5 additions & 1 deletion _coconut/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ npt = _npt # Fake, like typing
zip_longest = _zip_longest

numpy_modules: _t.Any = ...
pandas_numpy_modules: _t.Any = ...
xarray_modules: _t.Any = ...
pandas_modules: _t.Any = ...
jax_numpy_modules: _t.Any = ...

tee_type: _t.Any = ...
reiterables: _t.Any = ...
fmappables: _t.Any = ...
Expand All @@ -129,6 +131,7 @@ ValueError = _builtins.ValueError
StopIteration = _builtins.StopIteration
RuntimeError = _builtins.RuntimeError
callable = _builtins.callable
chr = _builtins.chr
classmethod = _builtins.classmethod
complex = _builtins.complex
all = _builtins.all
Expand Down Expand Up @@ -157,6 +160,7 @@ min = _builtins.min
max = _builtins.max
next = _builtins.next
object = _builtins.object
ord = _builtins.ord
print = _builtins.print
property = _builtins.property
range = _builtins.range
Expand Down
2 changes: 1 addition & 1 deletion coconut/__coconut__.pyi
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from __coconut__ import *
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_Expected, _coconut_MatchError, _coconut_SupportsAdd, _coconut_SupportsMinus, _coconut_SupportsMul, _coconut_SupportsPow, _coconut_SupportsTruediv, _coconut_SupportsFloordiv, _coconut_SupportsMod, _coconut_SupportsAnd, _coconut_SupportsXor, _coconut_SupportsOr, _coconut_SupportsLshift, _coconut_SupportsRshift, _coconut_SupportsMatmul, _coconut_SupportsInv, _coconut_Expected, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_complex_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul, _coconut_py_str, _coconut_flatten, _coconut_multiset, _coconut_back_none_pipe, _coconut_back_none_star_pipe, _coconut_back_none_dubstar_pipe, _coconut_forward_none_compose, _coconut_back_none_compose, _coconut_forward_none_star_compose, _coconut_back_none_star_compose, _coconut_forward_none_dubstar_compose, _coconut_back_none_dubstar_compose, _coconut_call_or_coefficient, _coconut_in, _coconut_not_in, _coconut_attritemgetter
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_Expected, _coconut_MatchError, _coconut_SupportsAdd, _coconut_SupportsMinus, _coconut_SupportsMul, _coconut_SupportsPow, _coconut_SupportsTruediv, _coconut_SupportsFloordiv, _coconut_SupportsMod, _coconut_SupportsAnd, _coconut_SupportsXor, _coconut_SupportsOr, _coconut_SupportsLshift, _coconut_SupportsRshift, _coconut_SupportsMatmul, _coconut_SupportsInv, _coconut_Expected, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_complex_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_arr_concat_op, _coconut_mk_anon_namedtuple, _coconut_matmul, _coconut_py_str, _coconut_flatten, _coconut_multiset, _coconut_back_none_pipe, _coconut_back_none_star_pipe, _coconut_back_none_dubstar_pipe, _coconut_forward_none_compose, _coconut_back_none_compose, _coconut_forward_none_star_compose, _coconut_back_none_star_compose, _coconut_forward_none_dubstar_compose, _coconut_back_none_dubstar_compose, _coconut_call_or_coefficient, _coconut_in, _coconut_not_in, _coconut_attritemgetter, _coconut_if_op
7 changes: 4 additions & 3 deletions coconut/_pyparsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
warn_on_multiline_regex,
num_displayed_timing_items,
use_cache_file,
use_line_by_line_parser,
)
from coconut.util import get_clock_time # NOQA
from coconut.util import (
Expand Down Expand Up @@ -183,7 +184,6 @@ def _parseCache(self, instring, loc, doActions=True, callPreParse=True):
if isinstance(value, Exception):
raise value
return value[0], value[1].copy()

ParserElement._parseCache = _parseCache

# [CPYPARSING] fix append
Expand Down Expand Up @@ -249,11 +249,12 @@ def enableIncremental(*args, **kwargs):
)

SUPPORTS_ADAPTIVE = (
hasattr(MatchFirst, "setAdaptiveMode")
and USE_COMPUTATION_GRAPH
USE_COMPUTATION_GRAPH
and hasattr(MatchFirst, "setAdaptiveMode")
)

USE_CACHE = SUPPORTS_INCREMENTAL and use_cache_file
USE_LINE_BY_LINE = USE_COMPUTATION_GRAPH and use_line_by_line_parser

if MODERN_PYPARSING:
_trim_arity = _pyparsing.core._trim_arity
Expand Down
Loading

0 comments on commit 41ac855

Please sign in to comment.