Skip to content

Commit 2aee608

Browse files
authored
Merge pull request #825 from JuliaOpt/bl/parser_error
More detailed parser errors
2 parents 3b4479b + 916964c commit 2aee608

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

src/Utilities/parser.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ function parsefunction(ex)
108108
if ex isa Number
109109
ex = Expr(:call,:+,ex)
110110
end
111-
@assert isexpr(ex, :call) && ex.args[1] == :+
111+
@assert isexpr(ex, :call)
112+
if ex.args[1] != :+
113+
error("Expected `+`, got `$(ex.args[1])`.")
114+
end
112115
affine_terms = ParsedScalarAffineTerm[]
113116
quadratic_terms = ParsedScalarQuadraticTerm[]
114117
constant = 0.0
@@ -169,7 +172,11 @@ function separatelabel(ex)
169172
end
170173

171174
function parsedtoMOI(model, s::Symbol)
172-
return MOI.get(model, MOI.VariableIndex, String(s))
175+
index = MOI.get(model, MOI.VariableIndex, String(s))
176+
if index === nothing
177+
error("Invalid variable name $s.")
178+
end
179+
return index
173180
end
174181

175182
# Used for Vector{Symbol}, Vector{ParsedScalarAffineTerm}, Vector{ParsedVectorAffineTerm},

test/Utilities/parser.jl

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
using Test
2+
using MathOptInterface
3+
const MOI = MathOptInterface
4+
const MOIU = MOI.Utilities
15

26
structeq(a::T, b::T) where {T} = all(f->getfield(a, f) == getfield(b, f), fieldnames(T))
37

@@ -14,7 +18,8 @@ structeq(a::T, b::T) where {T} = all(f->getfield(a, f) == getfield(b, f), fieldn
1418
@test structeq(MOIU.parsefunction(:(2*x*y + y + 1.0)),
1519
MOIU.ParsedScalarQuadraticFunction(MOIU.ParsedScalarAffineTerm.([1.0],[:y]), MOIU.ParsedScalarQuadraticTerm.([2.0],[:x],[:y]), 1.0))
1620

17-
@test_throws AssertionError MOIU.parsefunction(:(x - y))
21+
err = ErrorException("Expected `+`, got `-`.")
22+
@test_throws err MOIU.parsefunction(:(x - y))
1823

1924
@test structeq(MOIU.parsefunction(:([x, 2x+y+5.0])),
2025
MOIU.ParsedVectorAffineFunction(MOIU.ParsedVectorAffineTerm.([1,2,2],MOIU.ParsedScalarAffineTerm.([1.0,2.0,1.0],[:x,:x,:y])), [0.0,5.0]))
@@ -31,21 +36,19 @@ end
3136
@test MOIU.separatelabel(:(con1: [x,y] in S)) == (:con1, :([x,y] in S))
3237
end
3338

34-
@MOIU.model GeneralModel (MOI.ZeroOne, MOI.Integer) (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval) (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.PositiveSemidefiniteConeTriangle) () () (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) (MOI.VectorOfVariables,) (MOI.VectorAffineFunction,)
35-
3639
@testset "loadfromstring" begin
3740
@testset "one variable" begin
3841
s = """
3942
variables: x
4043
bound: x >= 1.0
4144
"""
42-
model = GeneralModel{Float64}()
45+
model = MOIU.Model{Float64}()
4346
x = MOI.add_variable(model)
4447
MOI.set(model, MOI.VariableName(), x, "x")
4548
bound = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(1.0))
4649
MOI.set(model, MOI.ConstraintName(), bound, "bound")
4750

48-
model2 = GeneralModel{Float64}()
51+
model2 = MOIU.Model{Float64}()
4952
MOIU.loadfromstring!(model2, s)
5053
MOIU.test_models_equal(model, model2, ["x"], ["bound"])
5154
end
@@ -57,7 +60,7 @@ end
5760
linear2: x + y <= 1.0
5861
linear3: x + y == 1.0
5962
"""
60-
model = GeneralModel{Float64}()
63+
model = MOIU.Model{Float64}()
6164
x = MOI.add_variable(model)
6265
y = MOI.add_variable(model)
6366
MOI.set(model, MOI.VariableName(), x, "x")
@@ -69,7 +72,7 @@ end
6972
MOI.set(model, MOI.ConstraintName(), linear2, "linear2")
7073
MOI.set(model, MOI.ConstraintName(), linear3, "linear3")
7174

72-
model2 = GeneralModel{Float64}()
75+
model2 = MOIU.Model{Float64}()
7376
MOIU.loadfromstring!(model2, s)
7477
MOIU.test_models_equal(model, model2, ["x", "y"], ["linear1", "linear2", "linear3"])
7578
end
@@ -79,15 +82,15 @@ end
7982
variables: x, y
8083
minobjective: x + -2y + 1.0
8184
"""
82-
model = GeneralModel{Float64}()
85+
model = MOIU.Model{Float64}()
8386
x = MOI.add_variable(model)
8487
y = MOI.add_variable(model)
8588
MOI.set(model, MOI.VariableName(), x, "x")
8689
MOI.set(model, MOI.VariableName(), y, "y")
8790
MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -2.0], [x, y]), 1.0))
8891
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
8992

90-
model2 = GeneralModel{Float64}()
93+
model2 = MOIU.Model{Float64}()
9194
MOIU.loadfromstring!(model2, s)
9295
MOIU.test_models_equal(model, model2, ["x", "y"], String[])
9396
end
@@ -97,15 +100,15 @@ end
97100
variables: x, y
98101
maxobjective: x + -2y + 1.0
99102
"""
100-
model = GeneralModel{Float64}()
103+
model = MOIU.Model{Float64}()
101104
x = MOI.add_variable(model)
102105
y = MOI.add_variable(model)
103106
MOI.set(model, MOI.VariableName(), x, "x")
104107
MOI.set(model, MOI.VariableName(), y, "y")
105108
MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -2.0], [x, y]), 1.0))
106109
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
107110

108-
model2 = GeneralModel{Float64}()
111+
model2 = MOIU.Model{Float64}()
109112
MOIU.loadfromstring!(model2, s)
110113
MOIU.test_models_equal(model, model2, ["x", "y"], String[])
111114
end
@@ -117,7 +120,7 @@ end
117120
affsoc: [2x,y+1,-1*z] in SecondOrderCone(3)
118121
affsoc2: [1.0,2.0,3.0] in SecondOrderCone(3)
119122
"""
120-
model = GeneralModel{Float64}()
123+
model = MOIU.Model{Float64}()
121124
x = MOI.add_variable(model)
122125
y = MOI.add_variable(model)
123126
z = MOI.add_variable(model)
@@ -131,9 +134,19 @@ end
131134
MOI.set(model, MOI.ConstraintName(), affsoc, "affsoc")
132135
MOI.set(model, MOI.ConstraintName(), affsoc2, "affsoc2")
133136

134-
model2 = GeneralModel{Float64}()
137+
model2 = MOIU.Model{Float64}()
135138
MOIU.loadfromstring!(model2, s)
136139
MOIU.test_models_equal(model, model2, ["x", "y", "z"], ["varsoc", "affsoc", "affsoc2"])
137140
end
138141

142+
@testset "Invalid variable name" begin
143+
s = """
144+
variables: x
145+
bound: y >= 1.0
146+
"""
147+
model = MOIU.Model{Float64}()
148+
err = ErrorException("Invalid variable name y.")
149+
@test_throws err MOIU.loadfromstring!(model, s)
150+
end
151+
139152
end

0 commit comments

Comments
 (0)