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~%")
EXIT_FAILURE)
(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)
"gash: break: too many arguments~%")
EXIT_FAILURE)))

View File

@ -37,7 +37,10 @@
"gash: continue: argument must be a positive integer~%")
EXIT_FAILURE)
(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)
"gash: continue: too many arguments~%")
EXIT_FAILURE)))

View File

@ -36,7 +36,11 @@
(#f (format (current-error-port)
"gash: return: argument must be a number from 0 to 255~%")
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)
"gash: return: too many arguments~%")
EXIT_FAILURE)))

View File

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

View File

@ -83,3 +83,10 @@
foo
#+end_src
: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"
("\\$\\(\\(i\\+1\\)\\)" "$(expr $i + 1)"))
;; Gash needs to be fixed to pass these tests.
("continue at top level")
("continue in subshell")
("continue in subshell aborts with errexit")
;; The Oil shell handles this statically. We