Fix top-level 'break', 'continue', and 'return'.

* gash/environment.scm (sh:break, sh:continue, sh:return): Wrap
'abort-to-prompt' with 'false-if-exception'.
* gash/built-ins/break.scm (main): Print warning and continue if
'sh:break' returns.
* gash/built-ins/continue.scm (main): Likewise, but for 'sh:continue'.
* gash/built-ins/return.scm (main): Likewise, but for 'sh:return'.
* tests/functions.org (Top-level return): New test.
* tests/spec/oil.scm: Enable previously failing test.
This commit is contained in:
Timothy Sample 2019-08-01 09:02:05 -04:00
parent 150c6eac53
commit 6228064801
6 changed files with 29 additions and 10 deletions

View File

@ -37,7 +37,10 @@
"gash: break: argument must be a positive integer~%") "gash: break: argument must be a positive integer~%")
EXIT_FAILURE) EXIT_FAILURE)
(n (set-status! 0) (n (set-status! 0)
(sh:break (1- n))))) (sh:break (1- n))
(format (current-error-port)
"gash: break: no loop to break from~%")
EXIT_SUCCESS)))
(_ (format (current-error-port) (_ (format (current-error-port)
"gash: break: too many arguments~%") "gash: break: too many arguments~%")
EXIT_FAILURE))) EXIT_FAILURE)))

View File

@ -37,7 +37,10 @@
"gash: continue: argument must be a positive integer~%") "gash: continue: argument must be a positive integer~%")
EXIT_FAILURE) EXIT_FAILURE)
(n (set-status! 0) (n (set-status! 0)
(sh:continue (1- n))))) (sh:continue (1- n))
(format (current-error-port)
"gash: continue: no loop to continue from~%")
EXIT_SUCCESS)))
(_ (format (current-error-port) (_ (format (current-error-port)
"gash: continue: too many arguments~%") "gash: continue: too many arguments~%")
EXIT_FAILURE))) EXIT_FAILURE)))

View File

@ -36,7 +36,11 @@
(#f (format (current-error-port) (#f (format (current-error-port)
"gash: return: argument must be a number from 0 to 255~%") "gash: return: argument must be a number from 0 to 255~%")
EXIT_FAILURE) EXIT_FAILURE)
(n (sh:return n)))) (n (sh:return n)
(format (current-error-port)
(string-append "gash: return: no function "
"or sourced script to return from~%"))
EXIT_SUCCESS)))
(_ (format (current-error-port) (_ (format (current-error-port)
"gash: return: too many arguments~%") "gash: return: too many arguments~%")
EXIT_FAILURE))) EXIT_FAILURE)))

View File

@ -334,8 +334,9 @@ exit the dynamic extent of @var{thunk}."
(define* (sh:continue #:optional (n 0)) (define* (sh:continue #:optional (n 0))
"Exit to the closest invocation of @code{call-with-continue}. If "Exit to the closest invocation of @code{call-with-continue}. If
@var{n} is set, exit to the @math{n + 1}th closest invocation." @var{n} is set, exit to the @math{n + 1}th closest invocation. If not
(abort-to-prompt *continue-tag* n)) called from within @code{call-with-continue}, return @code{#f}."
(false-if-exception (abort-to-prompt *continue-tag* n)))
(define *break-tag* (make-prompt-tag)) (define *break-tag* (make-prompt-tag))
@ -351,8 +352,9 @@ exit the dynamic extent of @var{thunk}."
(define* (sh:break #:optional (n 0)) (define* (sh:break #:optional (n 0))
"Exit to the closest invocation of @code{call-with-break}. If "Exit to the closest invocation of @code{call-with-break}. If
@var{n} is set, exit to the @math{n + 1}th closest invocation." @var{n} is set, exit to the @math{n + 1}th closest invocation. If not
(abort-to-prompt *break-tag* n)) called from within @code{call-with-break}, return @code{#f}."
(false-if-exception (abort-to-prompt *break-tag* n)))
(define *return-tag* (make-prompt-tag)) (define *return-tag* (make-prompt-tag))
@ -367,8 +369,9 @@ exit the dynamic extent of @var{thunk}."
(define* (sh:return #:optional (status (get-status))) (define* (sh:return #:optional (status (get-status)))
"Exit to the closest invocation of @code{call-with-return} setting "Exit to the closest invocation of @code{call-with-return} setting
status to @var{status}. If @var{status} is not set, keep the current status to @var{status}. If @var{status} is not set, keep the current
status." status. If not called from within @code{call-with-return}, return
(abort-to-prompt *return-tag* status)) @code{#f}."
(false-if-exception (abort-to-prompt *return-tag* status)))
(define *atexit* #f) (define *atexit* #f)
(define *exiting?* #f) (define *exiting?* #f)

View File

@ -83,3 +83,10 @@
foo foo
#+end_src #+end_src
:status: 1 :status: 1
* Top-level return
:script:
#+begin_src sh
return
#+end_src
:status: 0

View File

@ -159,7 +159,6 @@
("while in pipe with subshell" ("while in pipe with subshell"
("\\$\\(\\(i\\+1\\)\\)" "$(expr $i + 1)")) ("\\$\\(\\(i\\+1\\)\\)" "$(expr $i + 1)"))
;; Gash needs to be fixed to pass these tests. ;; Gash needs to be fixed to pass these tests.
("continue at top level")
("continue in subshell") ("continue in subshell")
("continue in subshell aborts with errexit") ("continue in subshell aborts with errexit")
;; The Oil shell handles this statically. We ;; The Oil shell handles this statically. We