Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ML-style guards which are patterns of the form if e end #110

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Match"
uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
version = "2.1.2"
version = "2.2.0"
authors = ["Neal Gafter <[email protected]>", "Kevin Squire <[email protected]>"]

[deps]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ for examples of this and other features.
* `x && y` matches values which match both patterns `x` and `y`
* `x, if condition end` matches only if `condition` is true (`condition` may use any variables that occur earlier in the pattern eg `(x, y, z where x + y > z)`)
* `x where condition` An alternative form for `x, if condition end`
* `if condition end` A boolean computed pattern. `x && if condition end` is another way of writing `x where condition`.
* Anything else is treated as a constant and tested for equality
* Expressions can be interpolated in as constants via standard interpolation syntax `\$(x)`. Interpolations may use previously bound variables.

Expand Down
8 changes: 8 additions & 0 deletions src/binding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ function bind_pattern!(
pattern0, assigned = bind_pattern!(location, subpattern, input, binder, assigned)
pattern1 = shred_where_clause(guard, false, location, binder, assigned)
pattern = BoundAndPattern(location, source, BoundPattern[pattern0, pattern1])

elseif is_expr(source, :if, 2)
# if expr end
if !is_empty_block(source.args[2])
error("$(location.file):$(location.line): Unrecognized @match guard syntax: `$source`.")
end
guard = source.args[1]
pattern = shred_where_clause(guard, false, location, binder, assigned)

elseif is_expr(source, :call) && source.args[1] == :(:) && length(source.args) in 3:4
# A range pattern. We depend on the Range API to make sense of it.
Expand Down
37 changes: 36 additions & 1 deletion test/matchtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@testset "tests from Match.jl" begin
@testset "tests for Match.jl" begin

@testset "Type matching" begin
# Type matching
Expand Down Expand Up @@ -410,4 +410,39 @@ end

end

@testset "Test support for ML-style guards, which are patterns of the form `if expr end`" begin
t = true
f = false
@test @match 1 begin
if f end => false
if t end => true
end
# The original feature request was for ML-style guards of the form
# pattern && if condition end => result
# as an alternative to guards of the forms
# pattern, if condition end => result
# pattern where condition => result
@test @match 1 begin
1 && if !t end => false
1 && if !f end => true
end
end

@testset "Test an error when ML-style guards are not used correctly" begin
let line = 0, file = Symbol(@__FILE__)
try
line = (@__LINE__) + 2
@eval @match Foo(1, 2) begin
if t; nothing; end => true
end
@test false
catch ex
@test ex isa LoadError
e = ex.error
@test e isa ErrorException
@test startswith(e.msg, "$file:$line: Unrecognized @match guard syntax:")
end
end
end

end
Loading