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.
\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
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:
\begin{alltt}
\textbf{ok} "quadratic.factor" run-file
\textbf{/home/slava/quadratic.factor:2: Not a number
2 * / neg ;
^
\textbf{ok} [ 1 2 3 ] 4 append reverse
\textbf{The generic word car does not have a suitable method for 4
:s :r :n :c show stacks at time of error.
:get ( var -- value ) inspects the error namestack.}
\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}
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
annotations: watch and break

View File

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

View File

@ -66,12 +66,6 @@ IN: kernel
#! value than it produces.
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 -- )
#! Execute a quotation only when the condition is not f. The
#! condition is popped off the stack.
@ -89,12 +83,6 @@ IN: kernel
#! value than it produces.
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 -- )
#! The code is evaluated in an infinite loop. Typically, a
#! continuation is used to escape the infinite loop.

View File

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

View File

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

View File

@ -2,7 +2,7 @@
! See http://factor.sf.net/license.txt for BSD license.
IN: compiler
USING: assembler errors generic kernel lists math namespaces
strings vectors words ;
prettyprint strings vectors words ;
! To support saving compiled code to disk, generator words
! append relocation instructions to this vector.
@ -53,7 +53,7 @@ SYMBOL: compiled-xts
compiled-xts off ;
: 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
! is encountered that has not been previously compiled, it is
@ -74,7 +74,7 @@ TUPLE: relative word where to ;
: just-compiled compiled-offset 4 - ;
C: relative ( word -- )
dup t rel-word
over t rel-word
[ set-relative-word ] keep
[ just-compiled swap set-relative-where ] keep
[ compiled-offset swap set-relative-to ] keep ;

View File

@ -1,9 +1,9 @@
! Copyright (C) 2004, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
IN: kernel DEFER: callcc1
IN: streams DEFER: line-number
IN: parser DEFER: file
IN: errors USING: kernel-internals lists namespaces streams ;
IN: kernel
DEFER: callcc1
IN: errors
USING: kernel-internals lists namespaces streams ;
TUPLE: no-method object generic ;
@ -20,27 +20,6 @@ TUPLE: no-method object generic ;
: >c ( catch -- ) catchstack cons 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 -- )
#! Call the try quotation. If an error occurs restore the
#! datastack, push the error, and call the catch block.

View File

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

View File

@ -76,7 +76,7 @@ strings vectors ;
: nest ( variable -- hash )
#! If the variable is set in the current namespace, return
#! 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 -- )
#! Execute the quotation with the variable value on the

View File

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

View File

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

View File

@ -30,6 +30,3 @@ USE: prettyprint
[ "2\n" ] [ [ 1 2 [ . ] [ 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.
! See http://factor.sf.net/license.txt for BSD license.
IN: errors USING: kernel kernel-internals lists namespaces
prettyprint stdio strings unparser vectors words math generic ;
IN: errors USING: generic kernel kernel-internals lists math namespaces
parser prettyprint stdio streams strings unparser vectors words ;
: expired-error ( obj -- )
"Object did not survive image save/load: " write . ;
@ -135,10 +135,35 @@ M: object error. ( error -- )
#! and return to the caller.
[ [ 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 ( -- )
[ die ] >c ( last resort )
[ 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 ;
M: no-method error. ( error -- )

View File

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