Last active
September 23, 2019 07:37
Revisions
-
c42f revised this gist
Sep 22, 2019 . 1 changed file with 20 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,7 +15,7 @@ isquoted(ex) = ex isa QuoteNode || isexpr(ex, (:quote, :meta)) function has_throws(ex) if ex isa Expr if (ex.head == :call && ex.args[1] == :throw) || (ex.head == :macrocall && ex.args[1] == Symbol("@th")) return true elseif !isquoted(ex) return any(has_throws, ex.args) @@ -43,11 +43,12 @@ function expand_throws_body!(ex) end end end elseif ex.head == :macrocall && ex.args[1] == Symbol("@th") # `@th ex1 throws exc_type` is a standin for "real syntax" like # `ex1 throws exc_type` ex1 = ex.args[3] @assert ex.args[4] == :throws exc_type = ex.args[5] res = gensym("res") matcher = gensym("exc_matcher") ex = quote @@ -165,7 +166,7 @@ end @throws function foo(x::Int) if x > 1 y = @th bar() throws Exception else y = 2 end @@ -179,6 +180,16 @@ end # @inline foo(_match_expected_errors_1, s::String) = foo(s) # New try form: # # x = 10 # try # z = foo(x) throws Exception # @show z # catch exc::ErrorException # @show exc # end x = 2 # catch _match_expected_errors_0(e) = e isa ErrorException ? ErrorResult(e) : e @@ -194,6 +205,10 @@ else @show exc end # @try foo() ErrorException=>1 # Normal try try z = foo(x) @show z -
c42f revised this gist
Sep 21, 2019 . 1 changed file with 119 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,9 +1,102 @@ using Base.Meta struct ErrorResult{E} e::E end function insert_wraparg!(ex, name) @assert isexpr(ex, :call) # todo insert!(ex.args, 2, name) ex end isquoted(ex) = ex isa QuoteNode || isexpr(ex, (:quote, :meta)) function has_throws(ex) if ex isa Expr if (ex.head == :call && ex.args[1] == :throw) || (ex.head == :macrocall && ex.args[1] == Symbol("@throws")) return true elseif !isquoted(ex) return any(has_throws, ex.args) end else return false end end function expand_throws_body!(ex) if ex isa Expr if ex.head == :call && ex.args[1] == :throw # `throw(e)` is implicitly # `throw(e) throws Exception` exc = gensym("exc") mexc = gensym("matched_exc") ex = quote $exc = $(ex.args[2]) if $exc isa Exception $mexc = __exception_matcher__($exc) if $mexc isa $ErrorResult return $mexc else throw($exc) end end end elseif ex.head == :macrocall && ex.args[1] == Symbol("@throws") # `@throws ex1 exc_type` is a standin for "real syntax" like # `ex1 throws exc_type` ex1 = ex.args[3] exc_type = ex.args[4] res = gensym("res") matcher = gensym("exc_matcher") ex = quote $matcher(e) = e isa $exc_type ? __exception_matcher__(e) : e $res = $(insert_wraparg!(ex1, matcher)) if $res isa $ErrorResult # TODO (top ErrorResult) ? return $res end $res end elseif !isquoted(ex) map!(expand_throws_body!, ex.args, ex.args) end end ex end function argname(ex) if ex isa Symbol return ex end if isexpr(ex, :(::)) argname(ex.args[1]) elseif isexpr(ex, :(=)) argname(ex.args[1]) else error("invalid function argument $ex") # TODO more cases... end end function expand_throws!(ex) @assert isexpr(ex, :function) @assert isexpr(ex.args[1], :call) # FIXME `where`, etc callex = ex.args[1] if has_throws(ex) # FIXME parameters shim = Expr(:function, copy(callex), Expr(:call, callex.args[1], Base.identity, map(argname, callex.args[2:end])...)) insert_wraparg!(ex.args[1], :__exception_matcher__) expand_throws_body!(ex.args[2]) ex = Expr(:toplevel, ex, shim) end ex end macro throws(ex) esc(expand_throws!(ex)) end #= function bar() throw ErrorException("Blah") @@ -39,22 +132,20 @@ end foo("A") # Turns into: function bar(_match_expected_errors_1) e = _match_expected_errors_1(ErrorException("Blah")) if e isa ErrorResult return e else throw(e) end end function foo(_match_expected_errors_1, x::Int) if x > 1 _match_expected_errors_2(e) = e isa Exception ? _match_expected_errors_1(e) : e y = bar(_match_expected_errors_2) if y isa ErrorResult return y end @@ -64,21 +155,36 @@ function _foo(_maybe_wrap_error_1, x::Int) y + 2 end @inline foo(x::Int) = foo(identity, x) =# @throws function bar() throw(ErrorException("Blah")) end @throws function foo(x::Int) if x > 1 y = @throws bar() Exception else y = 2 end y + 2 end function foo(s::String) "Hi "*s end # Don't really need the following definition, as cannot throw # @inline foo(_match_expected_errors_1, s::String) = foo(s) x = 2 # catch _match_expected_errors_0(e) = e isa ErrorException ? ErrorResult(e) : e # try body _match_expected_errors_1(e) = e isa Exception ? _match_expected_errors_0(e) : e z_ = foo(_match_expected_errors_1, x) if !(z_ isa ErrorResult) z = z_ @show z @@ -97,4 +203,3 @@ end @show foo("A") -
c42f created this gist
Sep 20, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,100 @@ module Asdf struct ErrorResult{E} e::E end #= function bar() throw ErrorException("Blah") end function foo(x::Int) if x > 1 y = bar() throws Exception else y = 2 end y + 2 end function foo(s::String) "Hi "*s end x = 10 try z = foo(x) throws Exception @show z catch exc::ErrorException @show exc end try z = foo(x) @show z catch exc @show exc end foo("A") =# # Turns into: function bar(_maybe_wrap_error_1) e = _maybe_wrap_error_1(ErrorException("Blah")) if e isa ErrorResult return e else throw(e) end end function _foo(_maybe_wrap_error_1, x::Int) if x > 1 _maybe_wrap_error_2(e) = e isa Exception ? _maybe_wrap_error_1(e) : e y = bar(_maybe_wrap_error_2) if y isa ErrorResult return y end else y = 2 end y + 2 end @inline foo(x::Int) = _foo(identity, x) function foo(s::String) "Hi "*s end # Don't really need the following definition, as cannot throw # @inline _foo(_maybe_wrap_error_1, s::String) = foo(s) x = 2 # catch _maybe_wrap_error_0(e) = e isa ErrorException ? ErrorResult(e) : e # try body _maybe_wrap_error_1(e) = e isa Exception ? _maybe_wrap_error_0(e) : e z_ = _foo(_maybe_wrap_error_1, x) if !(z_ isa ErrorResult) z = z_ @show z else exc = z_.e # catch body @show exc end try z = foo(x) @show z catch exc @show exc end @show foo("A") end