removed ?when and ?unless

cvs
Slava Pestov 2005-03-21 19:39:46 +00:00
parent e0455ee52c
commit c6039606c6
14 changed files with 101 additions and 71 deletions

View File

@ -248,29 +248,70 @@ You can even start the HTTP in a separate thread, and look at code in your web b
Since Factor does very little ``static'' or compile-time checking, you will have to learn how to deal with and fix runtime errors. On the upside, the tools available are pretty nice. Since Factor does very little ``static'' or compile-time checking, you will have to learn how to deal with and fix runtime errors. On the upside, the tools available are pretty nice.
\subsection{The debugger} \subsection{Looking at stacks}
Talk about .s/.r/.n/.c, and how to read .r. To see the contents of the data stack, use the \texttt{.s} word. Similarly, the other stacks can be shown with \texttt{.r} (return stack), \texttt{.n} (name stack), and \texttt{.c} (catch stack). Each stack is printed with each element on its own line; the top of the stack is the first element printed.
\subsection{The debugger}
If the execution of a phrase in the listener causes an error to be thrown, the error If the execution of a phrase in the listener causes an error to be thrown, the error
is printed and the stacks at the time of the error are saved. If you're spent any is printed and the stacks at the time of the error are saved. If you're spent any
time with Factor at all, you are probably familiar with this type of message: time with Factor at all, you are probably familiar with this type of message:
\begin{alltt} \begin{alltt}
\textbf{ok} "quadratic.factor" run-file \textbf{ok} [ 1 2 3 ] 4 append reverse
\textbf{/home/slava/quadratic.factor:2: Not a number \textbf{The generic word car does not have a suitable method for 4
2 * / neg ;
^
:s :r :n :c show stacks at time of error. :s :r :n :c show stacks at time of error.
:get ( var -- value ) inspects the error namestack.} :get ( var -- value ) inspects the error namestack.}
\end{alltt} \end{alltt}
The message there pretty much sums it up; you can look at the stacks at the time of the error, as well as look up variables in the scope that was active. The words \texttt{:s}, \texttt{:r}, \texttt{:n} and \texttt{:s} behave like their counterparts that are prefixed with \texttt{.}, except they show the stacks as they were when the error was thrown.
In the future, the debugger will be linked with the walker, documented below. Right now, the walker is a separate tool. The return stack warrants some special attention. To successfully develop Factor, you will need to learn to understand how it works. Lets look at the first few lines of the return stack at the time of the above error:
\begin{verbatim}
[ swap cdr ]
uncons
[ r> tuck 2slip ]
(each)
[ swons ]
[ each ]
each
\end{verbatim}
You can see the sequence of calls leading up to the error was \texttt{each} calling \texttt{(each)} calling \texttt{uncons}. The error tells us that the \texttt{car} word is the one that failed. Now, you can stare at the stack dump, at notice that if the call to \texttt{car} was successful and execution returned to \texttt{(each)}, the quotation \texttt{[ r> tuck 2slip ]} would resume executing. The first word there, \texttt{r>}, would take the quotation \texttt{[ swons ]} and put it back on the data stack. After \texttt{(each)} returned, it would then continue executing the quotation \texttt{[ each ]}. So what is going on here is a recursive loop, \texttt{[ swons ] each}. If you look at the definition of \texttt{reverse}, you will see that this is exactly what is being done:
\begin{verbatim}
: reverse ( list -- list ) [ ] swap [ swons ] each ;
\end{verbatim}
So a list is being reversed, but at some stage, the \texttt{car} is taken of something that is not a number. Now, you can look at the data stack with \texttt{:s}:
\begin{verbatim}
<< no-method [ ] 4 car >>
car
4
4
[ 3 2 1 ]
\end{verbatim}
So now, the mystery has been solved: as \texttt{reverse} iterates down the input value, it hits a cons cells whose \texttt{cdr} is not a list. Indeed, if you look at the value we are passing to \texttt{reverse}, you will see why:
\begin{alltt}
\textbf{ok} [ 1 2 3 ] 4 append .
[[ 1 [[ 2 [[ 3 4 ]] ]] ]]
\end{alltt}
In the future, the debugger will be linked with the walker, documented below. Right now, the walker is a separate tool. Another caveat is that in compiled code, the return stack is not reconstructed if there is an error. Until this is fixed, you should only compile code once it is debugged. Finally, remember that unit testing is a great way to ensure that old bugs do not re-appear once they've been fixed.
\subsection{The walker} \subsection{The walker}
The walker lets you step through the execution of a qotation. When a colon definition is reached, you can either keep walking inside the definition, or execute it in one step. The stacks can be inspected at each stage.
There are two ways to use the walker. The first is to invoke it at the listener with an explicit quotation:
\begin{alltt}
\textbf{ok}
walker walker
annotations: watch and break annotations: watch and break

View File

@ -210,10 +210,10 @@ M: f ' ( obj -- ptr )
: transfer-word ( word -- word ) : transfer-word ( word -- word )
#! This is a hack. See doc/bootstrap.txt. #! This is a hack. See doc/bootstrap.txt.
dup dup word-name swap word-vocabulary unit search dup dup word-name swap word-vocabulary unit search
[ dup "Missing DEFER: " word-error ] ?unless ; [ ] [ dup "Missing DEFER: " word-error ] ?ifte ;
: fixup-word ( word -- offset ) : fixup-word ( word -- offset )
dup pooled-object [ "Not in image: " word-error ] ?unless ; dup pooled-object [ ] [ "Not in image: " word-error ] ?ifte ;
: fixup-words ( -- ) : fixup-words ( -- )
image get [ image get [
@ -260,9 +260,9 @@ M: cons ' ( c -- tagged )
M: string ' ( string -- pointer ) M: string ' ( string -- pointer )
#! We pool strings so that each string is only written once #! We pool strings so that each string is only written once
#! to the image #! to the image
dup pooled-object [ dup pooled-object [ ] [
dup emit-string dup >r pool-object r> dup emit-string dup >r pool-object r>
] ?unless ; ] ?ifte ;
( Arrays and vectors ) ( Arrays and vectors )
@ -303,9 +303,9 @@ M: vector ' ( vector -- pointer )
M: hashtable ' ( hashtable -- pointer ) M: hashtable ' ( hashtable -- pointer )
#! Only hashtables are pooled, not vectors! #! Only hashtables are pooled, not vectors!
dup pooled-object [ dup pooled-object [ ] [
dup emit-hashtable [ pool-object ] keep dup emit-hashtable [ pool-object ] keep
] ?unless ; ] ?ifte ;
( End of the image ) ( End of the image )

View File

@ -66,12 +66,6 @@ IN: kernel
#! value than it produces. #! value than it produces.
over [ drop ] [ nip call ] ifte ; inline over [ drop ] [ nip call ] ifte ; inline
: ?unless ( default cond false -- )
#! If cond is true, drop default and leave cond on the
#! stack. Otherwise, drop default, and apply false
#! quotation to default.
>r dup [ nip r> drop ] [ drop r> call ] ifte ; inline
: when ( cond quot -- ) : when ( cond quot -- )
#! Execute a quotation only when the condition is not f. The #! Execute a quotation only when the condition is not f. The
#! condition is popped off the stack. #! condition is popped off the stack.
@ -89,12 +83,6 @@ IN: kernel
#! value than it produces. #! value than it produces.
dupd [ drop ] ifte ; inline dupd [ drop ] ifte ; inline
: ?when ( default cond true -- )
#! If cond is true, drop default and apply true
#! quotation to cond. Otherwise, drop cond, and leave
#! default on the stack.
>r dup [ nip r> call ] [ r> 2drop ] ifte ; inline
: forever ( quot -- ) : forever ( quot -- )
#! The code is evaluated in an infinite loop. Typically, a #! The code is evaluated in an infinite loop. Typically, a
#! continuation is used to escape the infinite loop. #! continuation is used to escape the infinite loop.

View File

@ -39,9 +39,9 @@ namespaces parser strings words ;
: c-type ( name -- type ) : c-type ( name -- type )
global [ global [
dup "c-types" get hash [ dup "c-types" get hash [ ] [
"No such C type: " swap cat2 throw f "No such C type: " swap cat2 throw f
] ?unless ] ?ifte
] bind ; ] bind ;
: size ( name -- size ) : size ( name -- size )

View File

@ -17,14 +17,14 @@ SYMBOL: interned-literals
compiled-offset cell 2 * align set-compiled-offset ; inline compiled-offset cell 2 * align set-compiled-offset ; inline
: intern-literal ( obj -- lit# ) : intern-literal ( obj -- lit# )
dup interned-literals get hash [ dup interned-literals get hash [ ] [
[ [
address address
literal-top set-compiled-cell literal-top set-compiled-cell
literal-top dup cell + set-literal-top literal-top dup cell + set-literal-top
dup dup
] keep interned-literals get set-hash ] keep interned-literals get set-hash
] ?unless ; ] ?ifte ;
: compile-byte ( n -- ) : compile-byte ( n -- )
compiled-offset set-compiled-byte compiled-offset set-compiled-byte

View File

@ -2,7 +2,7 @@
! See http://factor.sf.net/license.txt for BSD license. ! See http://factor.sf.net/license.txt for BSD license.
IN: compiler IN: compiler
USING: assembler errors generic kernel lists math namespaces USING: assembler errors generic kernel lists math namespaces
strings vectors words ; prettyprint strings vectors words ;
! To support saving compiled code to disk, generator words ! To support saving compiled code to disk, generator words
! append relocation instructions to this vector. ! append relocation instructions to this vector.
@ -53,7 +53,7 @@ SYMBOL: compiled-xts
compiled-xts off ; compiled-xts off ;
: compiled-xt ( word -- xt ) : compiled-xt ( word -- xt )
dup compiled-xts get assoc [ word-xt ] ?unless ; dup compiled-xts get assoc [ ] [ word-xt ] ?ifte ;
! Words being compiled are consed onto this list. When a word ! Words being compiled are consed onto this list. When a word
! is encountered that has not been previously compiled, it is ! is encountered that has not been previously compiled, it is
@ -74,7 +74,7 @@ TUPLE: relative word where to ;
: just-compiled compiled-offset 4 - ; : just-compiled compiled-offset 4 - ;
C: relative ( word -- ) C: relative ( word -- )
dup t rel-word over t rel-word
[ set-relative-word ] keep [ set-relative-word ] keep
[ just-compiled swap set-relative-where ] keep [ just-compiled swap set-relative-where ] keep
[ compiled-offset swap set-relative-to ] keep ; [ compiled-offset swap set-relative-to ] keep ;

View File

@ -1,9 +1,9 @@
! Copyright (C) 2004, 2005 Slava Pestov. ! Copyright (C) 2004, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license. ! See http://factor.sf.net/license.txt for BSD license.
IN: kernel DEFER: callcc1 IN: kernel
IN: streams DEFER: line-number DEFER: callcc1
IN: parser DEFER: file IN: errors
IN: errors USING: kernel-internals lists namespaces streams ; USING: kernel-internals lists namespaces streams ;
TUPLE: no-method object generic ; TUPLE: no-method object generic ;
@ -20,27 +20,6 @@ TUPLE: no-method object generic ;
: >c ( catch -- ) catchstack cons set-catchstack ; : >c ( catch -- ) catchstack cons set-catchstack ;
: c> ( catch -- ) catchstack uncons set-catchstack ; : c> ( catch -- ) catchstack uncons set-catchstack ;
: save-error ( error -- )
#! Save the stacks and parser state for post-mortem
#! inspection after an error.
namespace [
"col" get
"line" get
line-number get
file get
global [
"error-file" set
"error-line-number" set
"error-line" set
"error-col" set
"error" set
datastack "error-datastack" set
callstack "error-callstack" set
namestack "error-namestack" set
catchstack "error-catchstack" set
] bind
] when ;
: catch ( try catch -- ) : catch ( try catch -- )
#! Call the try quotation. If an error occurs restore the #! Call the try quotation. If an error occurs restore the
#! datastack, push the error, and call the catch block. #! datastack, push the error, and call the catch block.

View File

@ -79,9 +79,9 @@ SYMBOL: cloned
: deep-clone ( obj -- obj ) : deep-clone ( obj -- obj )
#! Clone an object if it hasn't already been cloned in this #! Clone an object if it hasn't already been cloned in this
#! with-deep-clone scope. #! with-deep-clone scope.
dup cloned get assq [ dup cloned get assq [ ] [
dup clone [ swap cloned [ acons ] change ] keep dup clone [ swap cloned [ acons ] change ] keep
] ?unless ; ] ?ifte ;
: deep-clone-vector ( vector -- vector ) : deep-clone-vector ( vector -- vector )
#! Clone a vector of vectors. #! Clone a vector of vectors.

View File

@ -76,7 +76,7 @@ strings vectors ;
: nest ( variable -- hash ) : nest ( variable -- hash )
#! If the variable is set in the current namespace, return #! If the variable is set in the current namespace, return
#! its value, otherwise set its value to a new namespace. #! its value, otherwise set its value to a new namespace.
dup namespace hash [ >r <namespace> dup r> set ] ?unless ; dup namespace hash [ ] [ >r <namespace> dup r> set ] ?ifte ;
: change ( var quot -- ) : change ( var quot -- )
#! Execute the quotation with the variable value on the #! Execute the quotation with the variable value on the

View File

@ -66,7 +66,7 @@ global [ string-mode off ] bind
: scan-word ( -- obj ) : scan-word ( -- obj )
scan dup [ scan dup [
dup ";" = not string-mode get and [ dup ";" = not string-mode get and [
dup "use" get search [ str>number ] ?unless dup "use" get search [ ] [ str>number ] ?ifte
] unless ] unless
] when ; ] when ;

View File

@ -85,7 +85,7 @@ M: complex unparse ( num -- str )
: unparse-ch ( ch -- ch/str ) : unparse-ch ( ch -- ch/str )
dup quotable? [ dup quotable? [
dup ch>ascii-escape [ ch>unicode-escape ] ?unless dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?ifte
] unless ; ] unless ;
M: string unparse ( str -- str ) M: string unparse ( str -- str )

View File

@ -30,6 +30,3 @@ USE: prettyprint
[ "2\n" ] [ [ 1 2 [ . ] [ sq . ] ?ifte ] with-string ] unit-test [ "2\n" ] [ [ 1 2 [ . ] [ sq . ] ?ifte ] with-string ] unit-test
[ "9\n" ] [ [ 3 f [ . ] [ sq . ] ?ifte ] with-string ] unit-test [ "9\n" ] [ [ 3 f [ . ] [ sq . ] ?ifte ] with-string ] unit-test
[ "4\n" ] [ [ 3 4 [ . ] ?when ] with-string ] unit-test
[ 3 ] [ 3 f [ . ] ?when ] unit-test
[ t ] [ 3 t [ . ] ?unless ] unit-test

View File

@ -1,7 +1,7 @@
! Copyright (C) 2004, 2005 Slava Pestov. ! Copyright (C) 2004, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license. ! See http://factor.sf.net/license.txt for BSD license.
IN: errors USING: kernel kernel-internals lists namespaces IN: errors USING: generic kernel kernel-internals lists math namespaces
prettyprint stdio strings unparser vectors words math generic ; parser prettyprint stdio streams strings unparser vectors words ;
: expired-error ( obj -- ) : expired-error ( obj -- )
"Object did not survive image save/load: " write . ; "Object did not survive image save/load: " write . ;
@ -135,10 +135,35 @@ M: object error. ( error -- )
#! and return to the caller. #! and return to the caller.
[ [ print-error debug-help ] when* ] catch ; [ [ print-error debug-help ] when* ] catch ;
: save-error ( error ds rs ns cs -- )
#! Save the stacks and parser state for post-mortem
#! inspection after an error.
namespace [
"col" get
"line" get
line-number get
file get
global [
"error-file" set
"error-line-number" set
"error-line" set
"error-col" set
"error-catchstack" set
"error-namestack" set
"error-callstack" set
"error-datastack" set
"error" set
] bind
] when ;
: init-error-handler ( -- ) : init-error-handler ( -- )
[ die ] >c ( last resort ) [ die ] >c ( last resort )
[ print-error die ] >c [ print-error die ] >c
[ dup save-error rethrow ] 5 setenv ( kernel calls on error ) ( kernel calls on error )
[
datastack dupd callstack namestack catchstack
save-error rethrow
] 5 setenv
kernel-error 12 setenv ; kernel-error 12 setenv ;
M: no-method error. ( error -- ) M: no-method error. ( error -- )

View File

@ -80,10 +80,10 @@ SYMBOL: inspectors
: inspector ( obj -- gadget ) : inspector ( obj -- gadget )
#! Return an existing inspector gadget for this object, or #! Return an existing inspector gadget for this object, or
#! create a new one. #! create a new one.
dup inspectors get assq [ dup inspectors get assq [ ] [
dup <inspector> dup <inspector>
[ swap inspectors [ acons ] change ] keep [ swap inspectors [ acons ] change ] keep
] ?unless ; ] ?ifte ;
: inspector-tile ( obj -- tile ) : inspector-tile ( obj -- tile )
inspector <scroller> "Inspector" <tile> ; inspector <scroller> "Inspector" <tile> ;