Skip to content

Commit

Permalink
Base.Cartesian: add @ncallkw and allow else branch inside if (J…
Browse files Browse the repository at this point in the history
  • Loading branch information
matthias314 committed Oct 28, 2023
1 parent 4975c02 commit 98542d7
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 4 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ New language features
difference between `public` and `export` is that `public` names do not become
available when `using` a package/module. ([#50105])
* `ScopedValue` implement dynamic scope with inheritance across tasks ([#50958]).
* The new macro `Base.Cartesian.@ncallkw` is analogous to `Base.Cartesian.@ncall`,
but allows to add keyword arguments to the function call ([#51501]).
* Support for Unicode 15.1 ([#51799]).
* A new `AbstractString` type, `AnnotatedString`, is introduced that allows for
regional annotations to be attached to an underlying string. This type is
Expand Down
44 changes: 40 additions & 4 deletions base/cartesian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module Cartesian

export @nloops, @nref, @ncall, @nexprs, @nextract, @nall, @nany, @ntuple, @nif
export @nloops, @nref, @ncall, @ncallkw, @nexprs, @nextract, @nall, @nany, @ntuple, @nif

### Cartesian-specific macros

Expand Down Expand Up @@ -104,10 +104,38 @@ while `@ncall 2 func a b i->c[i]` yields
macro ncall(N::Int, f, args...)
pre = args[1:end-1]
ex = args[end]
vars = Any[ inlineanonymous(ex,i) for i = 1:N ]
vars = (inlineanonymous(ex, i) for i = 1:N)
Expr(:escape, Expr(:call, f, pre..., vars...))
end

"""
@ncallkw N f kw sym...
Generate a function call expression with keyword arguments `kw...`. As
in the case of [`@ncall`](@ref), `sym` represents any number of function arguments, the
last of which may be an anonymous-function expression and is expanded into `N` arguments.
# Example
```jldoctest
julia> using Base.Cartesian
julia> f(x...; a, b = 1, c = 2, d = 3) = +(x..., a, b, c, d);
julia> x_1, x_2 = (-1, -2); b = 0; kw = (c = 0, d = 0);
julia> @ncallkw 2 f (; a = 0, b, kw...) x
-3
```
"""
macro ncallkw(N::Int, f, kw, args...)
pre = args[1:end-1]
ex = args[end]
vars = (inlineanonymous(ex, i) for i = 1:N)
param = Expr(:parameters, Expr(:(...), kw))
Expr(:escape, Expr(:call, f, param, pre..., vars...))
end

"""
@nexprs N expr
Expand Down Expand Up @@ -374,6 +402,8 @@ function exprresolve_conditional(ex::Expr)
return true, exprresolve_cond_dict[callee](ex.args[2], ex.args[3])
end
end
elseif Meta.isexpr(ex, :block, 2) && ex.args[1] isa LineNumberNode
return exprresolve_conditional(ex.args[2])
end
false, false
end
Expand Down Expand Up @@ -402,10 +432,16 @@ function exprresolve(ex::Expr)
return ex.args[1][ex.args[2:end]...]
end
# Resolve conditionals
if ex.head === :if
if ex.head === :if || ex.head === :elseif
can_eval, tf = exprresolve_conditional(ex.args[1])
if can_eval
ex = tf ? ex.args[2] : ex.args[3]
if tf
return ex.args[2]
elseif length(ex.args) == 3
return ex.args[3]
else
return nothing
end
end
end
ex
Expand Down
1 change: 1 addition & 0 deletions doc/src/devdocs/cartesian.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ Base.Cartesian.@nref
Base.Cartesian.@nextract
Base.Cartesian.@nexprs
Base.Cartesian.@ncall
Base.Cartesian.@ncallkw
Base.Cartesian.@ntuple
Base.Cartesian.@nall
Base.Cartesian.@nany
Expand Down
32 changes: 32 additions & 0 deletions test/cartesian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -533,3 +533,35 @@ end
inds2 = (1, CI(1, 2), 1, CI(1, 2), 1, CI(1, 2), 1)
@test (@inferred CI(inds2)) == CI(1, 1, 2, 1, 1, 2, 1, 1, 2, 1)
end

@testset "@ncallkw" begin
f(x...; a, b = 1, c = 2, d = 3) = +(x..., a, b, c, d)
x_1, x_2 = (-1, -2)
kw = (a = 0, c = 0, d = 0)
@test x_1 + x_2 + 1 + 4 == Base.Cartesian.@ncallkw 2 f kw 4 x
b = 0
kw = (c = 0, d = 0)
@test x_1 + x_2 + 4 == Base.Cartesian.@ncallkw 2 f (; a = 0, b, kw...) 4 x
end

@testset "if with and without else branch" begin
t1 = Base.Cartesian.@ntuple 3 i -> i == 1 ? 1 : 0
t2 = Base.Cartesian.@ntuple 3 i -> begin
m = 0
if i == 1
m = 1
end
m
end
@test t1 == t2
t3 = Base.Cartesian.@ntuple 3 i -> begin
m = 0
if i == 1
m = 1
elseif i == 2
m = 2
end
m
end
@test t3 == (1, 2, 0)
end

0 comments on commit 98542d7

Please sign in to comment.