Skip to content

Commit 171bbaa

Browse files
committed
test: custom operator parsing
1 parent f1c36c2 commit 171bbaa

File tree

2 files changed

+81
-18
lines changed

2 files changed

+81
-18
lines changed

src/Parse.jl

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,38 +249,43 @@ Throws appropriate errors for ambiguous or missing matches.
249249
@unstable function _find_operator_by_name(func_symbol, args, operators)
250250
function_name_offset = 1
251251
degree = length(args) - function_name_offset
252-
252+
253253
matches = Tuple{Function,Int}[]
254-
254+
255255
for arity in 1:length(operators.ops)
256256
for op in operators.ops[arity]
257257
if nameof(op) == func_symbol
258258
push!(matches, (op, arity))
259259
end
260260
end
261261
end
262-
262+
263263
if isempty(matches)
264-
throw(ArgumentError(
265-
"Tried to interpolate function `$(func_symbol)` but failed. " *
266-
"Function not found in operators."
267-
))
264+
throw(
265+
ArgumentError(
266+
"Tried to interpolate function `$(func_symbol)` but failed. " *
267+
"Function not found in operators.",
268+
),
269+
)
268270
end
269-
271+
270272
arity_matches = filter(m -> m[2] == degree, matches)
271-
273+
272274
if length(arity_matches) > 1
273-
ops_str = join([string(m[1]) for m in arity_matches], ", ")
274-
throw(ArgumentError(
275-
"Ambiguous operator `$(func_symbol)` with arity $(degree). " *
276-
"Multiple matches found: $(ops_str)"
277-
))
275+
throw(
276+
ArgumentError(
277+
"Ambiguous operator `$(func_symbol)` with arity $(degree). " *
278+
"Multiple matches found: $(arity_matches)",
279+
),
280+
)
278281
elseif length(arity_matches) == 0
279282
available_arities = [m[2] for m in matches]
280-
throw(ArgumentError(
281-
"Operator `$(func_symbol)` found but not with arity $(degree). " *
282-
"Available arities: $(available_arities)"
283-
))
283+
throw(
284+
ArgumentError(
285+
"Operator `$(func_symbol)` found but not with arity $(degree). " *
286+
"Available arities: $(available_arities)",
287+
),
288+
)
284289
end
285290

286291
return arity_matches[1][1]::Function

test/test_parse.jl

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,61 @@ end
340340
)
341341
@test string_tree(ex) == "x"
342342
end
343+
344+
@testitem "custom operators without passing function object" begin
345+
using DynamicExpressions
346+
347+
custom_mul(x, y) = x * y
348+
custom_cos(x) = cos(x)
349+
custom_max(x, y, z) = max(x, y, z)
350+
351+
operators = OperatorEnum(
352+
1 => [custom_cos], 2 => [+, -, *, /, custom_mul], 3 => [custom_max]
353+
)
354+
355+
# Test nested custom operators
356+
ex = parse_expression(
357+
"custom_max(custom_cos(x1), custom_mul(x2, x3), x4 + 1.5)";
358+
operators=operators,
359+
variable_names=["x1", "x2", "x3"],
360+
)
361+
@test typeof(ex) <: Expression
362+
@test string_tree(ex) == "custom_max(custom_cos(x1), custom_mul(x2, x3), x4 + 1.5)"
363+
364+
# Test error cases for _find_operator_by_name
365+
@test_throws(
366+
ArgumentError(
367+
"Tried to interpolate function `unknown_func` but failed. Function not found in operators.",
368+
),
369+
parse_expression(
370+
Meta.parse("unknown_func(x1)"), operators=operators, variable_names=["x1"]
371+
)
372+
)
373+
374+
# Test ambiguous operator - same name from different modules
375+
module TestMod1
376+
foo(x) = x + 1
377+
end
378+
module TestMod2
379+
foo(x) = x - 1
380+
end
381+
same_name_ops = OperatorEnum(1 => [TestMod1.foo, TestMod2.foo])
382+
@test_throws(
383+
r"Ambiguous operator `foo` with arity 1\. Multiple matches found: Tuple\{Function, Int64\}\[.*foo.*1.*foo.*1.*\]",
384+
parse_expression(
385+
Meta.parse("foo(x1)"), operators=same_name_ops, variable_names=["x1"]
386+
)
387+
)
388+
389+
# Test wrong arity
390+
@test_throws(
391+
ArgumentError(
392+
"Operator `custom_cos` found but not with arity 2. Available arities: [1]"
393+
),
394+
parse_expression(
395+
Meta.parse("custom_cos(x1, x2)"),
396+
operators=operators,
397+
variable_names=["x1", "x2"],
398+
)
399+
)
400+
end

0 commit comments

Comments
 (0)