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 try/catch/else #42211

Merged
merged 5 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 4 additions & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2131,12 +2131,15 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int, quote_level::In
elseif head === :line && 1 <= nargs <= 2
show_linenumber(io, args...)

elseif head === :try && 3 <= nargs <= 4
elseif head === :try && 3 <= nargs <= 5
iob = IOContext(io, beginsym=>false)
show_block(iob, "try", args[1], indent, quote_level)
if is_expr(args[3], :block)
show_block(iob, "catch", args[2] === false ? Any[] : args[2], args[3]::Expr, indent, quote_level)
end
if nargs >= 5 && is_expr(args[5], :block)
show_block(iob, "else", Any[], args[5]::Expr, indent, quote_level)
end
if nargs >= 4 && is_expr(args[4], :block)
show_block(iob, "finally", Any[], args[4]::Expr, indent, quote_level)
end
Expand Down
7 changes: 7 additions & 0 deletions src/ast.scm
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,13 @@
"\n"
(indented-block (cdr (cadddr e)) ilvl))
"")
(if (length> e 5)
(let ((els (cadddddr e)))
(if (and (pair? els) (eq? (car els) 'block))
(string (string.rep " " ilvl) "else\n"
(indented-block (cdr els) ilvl))
""))
"")
(if (length> e 4)
(let ((fin (caddddr e)))
(if (and (pair? fin) (eq? (car fin) 'block))
Expand Down
34 changes: 26 additions & 8 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1509,29 +1509,33 @@
(let loop ((nxt (peek-token s))
(catchb #f)
(catchv #f)
(finalb #f))
(finalb #f)
(elseb #f))
(take-token s)
(cond
((eq? nxt 'end)
(list* 'try try-block (or catchv '(false))
(or catchb (if finalb '(false) (error "try without catch or finally")))
(if finalb (list finalb) '())))
(cond (elseb (list (or finalb '(false)) elseb))
(finalb (list finalb))
(else '()))))
((and (eq? nxt 'catch)
(not catchb))
(let ((nl (memv (peek-token s) '(#\newline #\;))))
(if (eqv? (peek-token s) #\;)
(take-token s))
(if (memq (require-token s) '(end finally))
(if (memq (require-token s) '(end finally else))
(loop (require-token s)
'(block)
#f
finalb)
finalb
elseb)
(let* ((loc (line-number-node s))
(var (if nl #f (parse-eq* s)))
(var? (and (not nl) (or (symbol? var)
(and (length= var 2) (eq? (car var) '$))
(error (string "invalid syntax \"catch " (deparse var) "\"")))))
(catch-block (if (eq? (require-token s) 'finally)
(catch-block (if (memq (require-token s) '(finally else))
`(block ,(line-number-node s))
(parse-block s))))
(loop (require-token s)
Expand All @@ -1543,16 +1547,30 @@
'()
(cdr catch-block))))
(if var? var '(false))
finalb)))))
finalb
elseb)))))
((and (eq? nxt 'finally)
(not finalb))
(let ((fb (if (eq? (require-token s) 'catch)
(let ((fb (if (eq? (require-token s) '(catch else))
simeonschaub marked this conversation as resolved.
Show resolved Hide resolved
'(block)
(parse-block s))))
(loop (require-token s)
catchb
catchv
fb)))
fb
elseb)))
((and (eq? nxt 'else)
(not elseb))
(if (or (not catchb) finalb)
(error "else inside try block needs to be immediately after catch"))
StefanKarpinski marked this conversation as resolved.
Show resolved Hide resolved
(let ((eb (if (eq? (require-token s) '(catch finally))
simeonschaub marked this conversation as resolved.
Show resolved Hide resolved
'(block)
(parse-block s))))
(loop (require-token s)
catchb
catchv
finalb
eb)))
(else (expect-end-error nxt 'try))))))
((return) (let ((t (peek-token s)))
(if (or (eqv? t #\newline) (closing-token? t))
Expand Down
52 changes: 33 additions & 19 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1332,25 +1332,29 @@
(let ((tryb (cadr e))
(var (caddr e))
(catchb (cadddr e)))
(cond ((length= e 5)
(cond ((and (length> e 4) (not (equal? (caddddr e) '(false))))
(if (has-unmatched-symbolic-goto? tryb)
(error "goto from a try/finally block is not permitted"))
(let ((finalb (cadddr (cdr e))))
(let ((finalb (caddddr e)))
(expand-forms
`(tryfinally
,(if (not (equal? catchb '(false)))
`(try ,tryb ,var ,catchb)
`(scope-block ,tryb))
,(if (and (equal? catchb '(false)) (length= e 5))
`(scope-block ,tryb)
`(try ,tryb ,var ,catchb (false) ,@(cdddddr e)))
(scope-block ,finalb)))))
((length= e 4)
(expand-forms
(if (symbol-like? var)
`(trycatch (scope-block ,tryb)
(scope-block
(block (= ,var (the_exception))
,catchb)))
`(trycatch (scope-block ,tryb)
(scope-block ,catchb)))))
((length> e 3)
(and (length> e 6) (error "invalid \"try\" form"))
(let ((elseb (if (length= e 6) (cdddddr e) '())))
(expand-forms
`(,(if (null? elseb) 'trycatch 'trycatchelse)
(scope-block ,tryb)
(scope-block
,(if (symbol-like? var)
`(scope-block
(block (= ,var (the_exception))
,catchb))
`(scope-block ,catchb)))
,@elseb))))
(else
(error "invalid \"try\" form")))))

Expand Down Expand Up @@ -3587,7 +3591,7 @@ f(x) = yt(x)
((eq? (car e) 'symboliclabel)
(kill)
#t)
((memq (car e) '(if elseif trycatch tryfinally))
((memq (car e) '(if elseif trycatch tryfinally trycatchelse))
(let ((prev (table.clone live)))
(if (eager-any (lambda (e) (begin0 (visit e)
(kill)))
Expand Down Expand Up @@ -3653,7 +3657,7 @@ f(x) = yt(x)
(and cv (vinfo:asgn cv) (vinfo:capt cv)))))

(define (toplevel-preserving? e)
(and (pair? e) (memq (car e) '(if elseif block trycatch tryfinally))))
(and (pair? e) (memq (car e) '(if elseif block trycatch tryfinally trycatchelse))))

(define (map-cl-convert exprs fname lam namemap defined toplevel interp opaq)
(if toplevel
Expand Down Expand Up @@ -4446,9 +4450,10 @@ f(x) = yt(x)
;; (= tok (enter L)) - push handler with catch block at label L, yielding token
;; (leave n) - pop N exception handlers
;; (pop_exception tok) - pop exception stack back to state of associated enter
((trycatch tryfinally)
((trycatch tryfinally trycatchelse)
(let ((handler-token (make-ssavalue))
(catch (make-label))
(els (and (eq? (car e) 'trycatchelse) (make-label)))
(endl (make-label))
(last-finally-handler finally-handler)
(finally (if (eq? (car e) 'tryfinally) (new-mutable-var) #f))
Expand All @@ -4465,11 +4470,20 @@ f(x) = yt(x)
;; handler block postfix
(if (and val v1) (emit-assignment val v1))
(if tail
(begin (if v1 (emit-return v1))
(begin (if els
(begin (if (and (not val) v1) (emit v1))
(emit '(leave 1)))
(if v1 (emit-return v1)))
(if (not finally) (set! endl #f)))
(begin (emit '(leave 1))
(emit `(goto ,endl))))
(emit `(goto ,(or els endl)))))
(set! handler-level (- handler-level 1))
;; emit else block
(if els
(begin (mark-label els)
(let ((v3 (compile (cadddr e) break-labels value tail))) ;; emit else block code
(if val (emit-assignment val v3)))
(emit `(goto ,endl))))
;; emit either catch or finally block
(mark-label catch)
(emit `(leave 1))
Expand Down
1 change: 1 addition & 0 deletions src/utils.scm
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@

(define (caddddr x) (car (cdr (cdr (cdr (cdr x))))))
(define (cdddddr x) (cdr (cdr (cdr (cdr (cdr x))))))
(define (cadddddr x) (car (cdddddr x)))

(define (table.clone t)
(let ((nt (table)))
Expand Down
73 changes: 73 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2977,3 +2977,76 @@ macro m42220()
end
@test @m42220()() isa Vector{Float64}
@test @m42220()(Bool) isa Vector{Bool}

@testset "try else" begin
fails(f) = try f() catch; true else false end
@test fails(error)
@test !fails(() -> 1 + 2)

@test_throws ParseError Meta.parse("try foo() else bar() end")
@test_throws ParseError Meta.parse("try foo() else bar() catch; baz() end")
@test_throws ParseError Meta.parse("try foo() catch; baz() finally foobar() else bar() end")
@test_throws ParseError Meta.parse("try foo() finally foobar() else bar() catch; baz() end")

err = try
try
1 + 2
catch
else
error("foo")
end
catch e
e
end
@test err == ErrorException("foo")

x = 0
err = try
try
1 + 2
catch
else
error("foo")
finally
x += 1
end
catch e
e
end
@test err == ErrorException("foo")
@test x == 1

x = 0
err = try
try
1 + 2
catch
5 + 6
else
3 + 4
finally
x += 1
end
catch e
e
end
@test err == 3 + 4
@test x == 1

x = 0
err = try
try
error()
catch
5 + 6
else
3 + 4
finally
x += 1
end
catch e
e
end
@test err == 5 + 6
@test x == 1
end