Skip to content

Commit

Permalink
Merge 128420e into 2201c60
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed May 26, 2019
2 parents 2201c60 + 128420e commit 44faf60
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 5 deletions.
41 changes: 36 additions & 5 deletions src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ Helper function for macros to construct container objects. Takes an `Expr` that
"""
_build_ref_sets(c) = _build_ref_sets(c, _get_name(c))

function _expr_contains_splat(ex::Expr)
if ex.head == :(...)
return true
end
return any(_expr_contains_splat.(ex.args))
end
_expr_contains_splat(::Any) = false

"""
JuMP._get_looped_code(varname, code, condition, idxvars, idxsets, sym, requestedcontainer::Symbol; lowertri=false)
Expand Down Expand Up @@ -576,6 +584,10 @@ function _constraint_macro(args, macro_name::Symbol, parsefun::Function)
c = length(extra) == 1 ? x : gensym()
x = length(extra) == 1 ? extra[1] : x

if _expr_contains_splat(c)
_error("cannot use splatting operator `...`.")
end

anonvar = isexpr(c, :vect) || isexpr(c, :vcat) || length(extra) != 1
variable = gensym()
name = _get_name(c)
Expand Down Expand Up @@ -1008,7 +1020,7 @@ expr = @expression(m, [i=1:3], i*sum(x[j] for j=1:3))
```
"""
macro expression(args...)

macro_error(str...) = _macro_error(:expression, args, str...)
args, kw_args, requestedcontainer = _extract_kw_args(args)
if length(args) == 3
m = esc(args[1])
Expand All @@ -1019,14 +1031,18 @@ macro expression(args...)
c = gensym()
x = args[2]
else
error("@expression: needs at least two arguments.")
macro_error("needs at least two arguments.")
end
length(kw_args) == 0 || macro_error("unrecognized keyword argument")
if _expr_contains_splat(c)
macro_error("cannot use splatting operator `...`.")
end
length(kw_args) == 0 || error("@expression: unrecognized keyword argument")

anonvar = isexpr(c, :vect) || isexpr(c, :vcat) || length(args) == 2
variable = gensym()

refcall, idxvars, idxsets, condition = _build_ref_sets(c, variable)

newaff, parsecode = _parse_expr_toplevel(x, :q)
code = quote
q = Val{false}()
Expand Down Expand Up @@ -1393,10 +1409,13 @@ macro variable(args...)
final_variable = variable
else
isa(var,Expr) || _error("Expected $var to be a variable name")

if _expr_contains_splat(var)
_error("cannot use splatting operator `...`.")
end
# We now build the code to generate the variables (and possibly the
# SparseAxisArray to contain them)
refcall, idxvars, idxsets, condition = _build_ref_sets(var, variable)

clear_dependencies(i) = (Containers.is_dependent(idxvars,idxsets[i],i) ? () : idxsets[i])

# Code to be used to create each variable of the container.
Expand Down Expand Up @@ -1504,12 +1523,17 @@ macro NLconstraint(m, x, extra...)
c = length(extra) == 1 ? x : gensym()
x = length(extra) == 1 ? extra[1] : x

if _expr_contains_splat(c)
error("@NLconstraint: cannot use splatting operator `...`.")
end

anonvar = isexpr(c, :vect) || isexpr(c, :vcat) || length(extra) != 1
variable = gensym()

# Strategy: build up the code for non-macro add_constraint, and if needed
# we will wrap in loops to assign to the ConstraintRefs
refcall, idxvars, idxsets, condition = _build_ref_sets(c, variable)

# Build the constraint
if isexpr(x, :call) # one-sided constraint
# Simple comparison - move everything to the LHS
Expand Down Expand Up @@ -1601,11 +1625,15 @@ macro NLexpression(args...)
if length(args) > 3 || length(kw_args) > 0
error("in @NLexpression: To many arguments ($(length(args))).")
end
if _expr_contains_splat(c)
error("@NLexpression: cannot use splatting operator `...`.")
end

anonvar = isexpr(c, :vect) || isexpr(c, :vcat) || length(args) == 2
variable = gensym()

refcall, idxvars, idxsets, condition = _build_ref_sets(c, variable)

code = quote
$(refcall) = NonlinearExpression($(esc(m)), $(_process_NL_expr(m, x)))
end
Expand Down Expand Up @@ -1663,7 +1691,9 @@ macro NLparameter(m, ex, extra...)
end
c = ex.args[2]
x = ex.args[3]

if _expr_contains_splat(c)
error("@NLparameter: cannot use splatting operator `...`.")
end
anonvar = isexpr(c, :vect) || isexpr(c, :vcat)
if anonvar
error("In @NLparameter($m, $ex): Anonymous nonlinear parameter syntax is not currently supported")
Expand All @@ -1672,6 +1702,7 @@ macro NLparameter(m, ex, extra...)
variable = gensym()

refcall, idxvars, idxsets, condition = _build_ref_sets(c, variable)

code = quote
if !isa($(esc(x)), Number)
error(string("in @NLparameter (", $(string(ex)), "): expected ",
Expand Down
27 changes: 27 additions & 0 deletions test/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,33 @@ end
c = @NLconstraint(model, x == sum(1.0 for i in 1:0))
@test sprint(show, c) == "x - 0 = 0" || sprint(show, c) == "x - 0 == 0"
end

@testset "Splatting error" begin
model = Model()
A = [1 0; 0 1]
@variable(model, x)

@test_macro_throws ErrorException(
"In `@variable(model, y[axes(A)...])`: cannot use splatting operator `...`."
) @variable(model, y[axes(A)...])

@test_macro_throws ErrorException(
"In `@constraint(model, [i = [axes(A)...]], x >= i)`: cannot use splatting operator `...`."
) @constraint(model, [i=[axes(A)...]], x >= i)

@test_macro_throws ErrorException(
"@NLconstraint: cannot use splatting operator `...`."
) @NLconstraint(model, [i=[axes(A)...]], x >= i)

@test_macro_throws ErrorException(
"In `@expression(model, [i = [axes(A)...]], i * x)`: cannot use splatting operator `...`."
) @expression(model, [i=[axes(A)...]], i * x)

@test_macro_throws ErrorException(
"@NLexpression: cannot use splatting operator `...`."
) @NLexpression(model, [i=[axes(A)...]], i * x)
end

end

@testset "Macros for JuMPExtension.MyModel" begin
Expand Down

0 comments on commit 44faf60

Please sign in to comment.