diff --git a/Factor.manifest b/Factor.manifest
index 11bf154602..f874bfe283 100644
--- a/Factor.manifest
+++ b/Factor.manifest
@@ -1 +1 @@
-Main-Class: factor.listener.FactorDesktop
+Main-Class: factor.FactorInterpreter
diff --git a/Makefile b/Makefile
index c49df74e8e..e610263b2f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CC = gcc
-DEFAULT_CFLAGS = -Os -Wall -export-dynamic -fomit-frame-pointer $(SITE_CFLAGS)
+DEFAULT_CFLAGS = -Wall -export-dynamic -g $(SITE_CFLAGS)
DEFAULT_LIBS = -lm
STRIP = strip
@@ -54,7 +54,7 @@ solaris:
f: $(OBJS)
$(CC) $(LIBS) $(CFLAGS) -o $@ $(OBJS)
- $(STRIP) $@
+ # $(STRIP) $@
clean:
rm -f $(OBJS)
diff --git a/TODO.FACTOR.txt b/TODO.FACTOR.txt
index ebc7af5d93..4cf6d494ab 100644
--- a/TODO.FACTOR.txt
+++ b/TODO.FACTOR.txt
@@ -1,54 +1,23 @@
FFI:
+
++ compiler/ffi:
+
- is signed -vs- unsigned pointers an issue?
- bitfields in C structs
- SDL_Rect** type
- struct membres that are not *
- float types
-- SDL_MapRGB broken
-
-- command line parsing cleanup
-- > 1 ( ) inside word def
-- parsing-word test fails
-
-- when* compilation in jvm
- compile word twice; no more 'cannot compile' error!
-- doc comments in image, inferior
- compiler: drop literal peephole optimization
- compiling when*
- compiling unless*
- getenv/setenv: if literal arg, compile as a load/store
- inline words
- perhaps /i should work with all numbers
-- profiler is inaccurate: wrong word on cs
-- buffer change handler in sidekick is screwed
-- eval with multilien strings and #!
-- quit responder breaks with multithreading
-- nicer way to combine two paths
-- don't show listener on certain commands
-- plugin should not exit jEdit on fatal errors
-- wordpreview: don't show for string literals and comments
-- alist -vs- assoc terminology
-- file responder: don't show full path in title
-
-- clean up listener's action popups
-- jedit ==> jedit-word, jedit takes a file name
-- add a socket timeout
-- fix error postoning -- not all errors thrown by i/o code are
- postponed
-- some way to run httpd from command line
-
-+ bignums:
-
-- move some s48_ functions into bignum.c
-- remove unused functions
-
-- >lower, >upper for strings
-- accept multi-line input in listener
+ docs:
- explain how log uses >polar and rect>
-- when* unless*
- simple i/o section
- unparse examples, and difference from prettyprint
- review doc formatting with latex2html
@@ -63,14 +32,12 @@ FFI:
multitasking
unit testing
-+ tests:
-
-- java factor: equal numbers have non-equal hashcodes!
-- FactorLib.equal() not very good
-- investigate mandel.factor
-
+ listener/plugin:
+- clean up listener's action popups
+- accept multi-line input in listener
+- don't show listener on certain commands
+- wordpreview: don't show for string literals and comments
- NPE in ErrorHighlight
- some way to not have previous definitions from a source file
clutter the namespace
@@ -83,11 +50,42 @@ FFI:
- special completion for USE:/IN:
- inspector links when describe called without object path
-+ native:
++ kernel:
+- profiler is inaccurate: wrong word on cs
- better i/o scheduler
+- move some s48_ functions into bignum.c
+- remove unused functions
+- >lower, >upper for strings
+- add a socket timeout
+- fix error postoning -- not all errors thrown by i/o code are
+ postponed
+- don't rehash strings on every startup
-+ JVM compiler:
++ misc:
+
+- jedit ==> jedit-word, jedit takes a file name
+- 'cascading' styles
+- command line parsing cleanup
+- > 1 ( ) inside word def
+- parsing-word test fails
+- doc comments in image, inferior
+- eval with multilien strings and #!
+- nicer way to combine two paths
+- alist -vs- assoc terminology
+
++ httpd:
+
+- file responder: don't show full path in title
+- wiki responder:
+ - port to native
+ - text styles
+- log with date
+ basic authentication, using httpdAuth function from a config file
+- file responder; last-modified field
+- quit responder breaks with multithreading
+
++ java factor is going away:
- compiled stack traces broken
- save classes to disk
@@ -99,18 +97,8 @@ FFI:
- direct stack access leaks memory on stack
- unnecessary local allocation: max is instance var, but several methods
get compiled.
-
-+ misc:
-
-- don't rehash strings on every startup
-- 'cascading' styles
- ditch expand
-
-+ httpd:
-
-- wiki responder:
- - port to native
- - text styles
-- log with date
- basic authentication, using httpdAuth function from a config file
-- file responder; last-modified field
+- when* compilation in jvm
+- plugin should not exit jEdit on fatal errors
+- java factor: equal numbers have non-equal hashcodes!
+- FactorLib.equal() not very good
diff --git a/contrib/mandel.factor b/contrib/mandel.factor
index 7aa51955a1..f35ec5fa2c 100644
--- a/contrib/mandel.factor
+++ b/contrib/mandel.factor
@@ -84,12 +84,12 @@ SYMBOL: center
] with-pixels ;
: mandel ( -- )
- 1280 1024 32 SDL_HWSURFACE SDL_FULLSCREEN bitor SDL_SetVideoMode drop
+ 640 480 32 SDL_HWSURFACE SDL_FULLSCREEN bitor SDL_SetVideoMode drop
[
3 zoom-fact set
-0.65 center set
- 50 nb-iter set
+ 100 nb-iter set
[ render ] time
"Done." print flush
] with-surface
diff --git a/doc/devel-guide.tex b/doc/devel-guide.tex
index 82ac4961c7..bfd1424f71 100644
--- a/doc/devel-guide.tex
+++ b/doc/devel-guide.tex
@@ -1,4 +1,4 @@
-% :indentSize=4:tabSize=4:noTabs=true:
+% :indentSize=4:tabSize=4:noTabs=true:mode=tex:
\documentclass[english]{article}
\usepackage[T1]{fontenc}
@@ -31,7 +31,7 @@
\newpage
\section*{Introduction}
-Factor is an imperative programming language with functional and object-oriented
+Factor is a programming language with functional and object-oriented
influences. Factor borrows heavily from Forth, Joy and Lisp. Programmers familiar with these languages will recognize many similarities with Factor.
Factor is \emph{interactive}. This means it is possible to run a Factor interpreter that reads from the keyboard, and immediately executes expressions as they are entered. This allows words to be defined and tested one at a time.
@@ -361,75 +361,270 @@ USE: math
USE: strings
\end{alltt}
-\subsection{Booleans and logic}
+\section{PRACTICAL: Numbers game}
-Words that return a boolean truth value are known as \emph{predicates}. Predicates are usually used to decide what to execute next at branch points. In Factor, there is no special boolean data type
--- instead, a special object \texttt{f} is the only object with a
-``false'' boolean value. Every other object is a boolean ``true''.
-The special object \texttt{t} is the ``canonical'' truth value. Note that words that return booleans don't return \texttt{t} as a rule; any object that is not equal to \texttt{f} can be returned as the true value.
-
-The usual boolean operations are found in the \texttt{logic} vocabulary. Note that these are not integer bitwise operations; bitwise operations are described in the next chapter.
-
-\texttt{not ( ?~-{}- ?~)} returns \texttt{t} if the top of stack is \texttt{f}, and \texttt{f} otherwise.
-
-\texttt{and ( ?~?~-{}- ?~)} returns a true value if both input parameters are true.
-
-\texttt{or ( ?~?~-{}- ?~)} returns a true value if at least one of the input parameters is true.
-
-\texttt{xor ( ?~?~-{}- ?~)} returns a true value if exactly one of the input parameters is true.
+In this section, basic input/output and flow control is introduced.
+We construct a program that repeatedly prompts the user to guess a
+number -- they are informed if their guess is correct, too low, or
+too high. The game ends on a correct guess.
\begin{alltt}
-t t and .
+numbers-game
+\emph{I'm thinking of a number between 0 and 100.}
+\emph{Enter your guess:} 25
+\emph{Too low}
+\emph{Enter your guess:} 38
+\emph{Too high}
+\emph{Enter your guess:} 31
+\emph{Correct - you win!}
+\end{alltt}
+
+\subsection{Getting started}
+
+Start a text editor and create a file named \texttt{numbers-game.factor}.
+
+Write a short comment at the top of the file. Two examples of commenting style supported by Factor:
+
+\begin{alltt}
+! Numbers game.
+( The great numbers game )
+\end{alltt}
+
+It is always a good idea to comment your code. Try to write simple
+code that does not need detailed comments to describe; similarly,
+avoid redundant comments. These two principles are hard to quantify
+in a concrete way, and will become more clear as your skills with
+Factor increase.
+
+We will be defining new words in the \texttt{numbers-game} vocabulary; add
+an \texttt{IN:} statement at the top of the source file:
+
+\begin{alltt}
+IN: numbers-game
+\end{alltt}
+Also in order to be able to test the words, issue a \texttt{USE:}
+statement in the interactive interpreter:
+
+\begin{alltt}
+USE: numbers-game
+\end{alltt}
+This section will develop the numbers game in an incremental fashion.
+After each addition, issue a command like the following to load the
+source file into the Factor interpreter:
+
+\begin{alltt}
+"numbers-game.factor" run-file
+\end{alltt}
+
+\subsection{Reading a number from the keyboard}
+
+A fundamental operation required for the numbers game is to be able
+to read a number from the keyboard. The \texttt{read} word \texttt{(
+-{}- str )} reads a line of input and pushes it on the stack.
+The \texttt{parse-number} word \texttt{( str -{}- n )} turns a decimal
+string representation of an integer into the integer itself. These
+two words can be combined into a single colon definition:
+
+\begin{alltt}
+: read-number ( -{}- n ) read parse-number ;
+\end{alltt}
+You should add this definition to the source file, and try loading
+the file into the interpreter. As you will soon see, this raises an
+error! The problem is that the two words \texttt{read} and \texttt{parse-number}
+are not part of the default, minimal, vocabulary search path used
+when reading files. The solution is to use \texttt{apropos.} to find
+out which vocabularies contain those words, and add the appropriate
+\texttt{USE:} statements to the source file:
+
+\begin{alltt}
+USE: parser
+USE: stdio
+\end{alltt}
+After adding the above two statements, the file should now parse,
+and testing should confirm that the \texttt{read-number} word works correctly.%
+\footnote{There is the possibility of an invalid number being entered at the
+keyboard. In this case, \texttt{parse-number} returns \texttt{f},
+the boolean false value. For the sake of simplicity, we ignore this
+case in the numbers game example. However, proper error handling is
+an essential part of any large program and is covered later.%
+}
+
+
+\subsection{Printing some messages}
+
+Now we need to make some words for printing various messages. They
+are given here without further ado:
+
+\begin{alltt}
+: guess-banner
+ "I'm thinking of a number between 0 and 100." print ;
+: guess-prompt "Enter your guess: " write ;
+: too-high "Too high" print ;
+: too-low "Too low" print ;
+: correct "Correct - you win!" print ;
+\end{alltt}
+Note that in the above, stack effect comments are omitted, since they
+are obvious from context. You should ensure the words work correctly
+after loading the source file into the interpreter.
+
+
+\subsection{Taking action based on a guess}
+
+The next logical step is to write a word \texttt{judge-guess} that
+takes the user's guess along with the actual number to be guessed,
+and prints one of the messages \texttt{too-high}, \texttt{too-low},
+or \texttt{correct}. This word will also push a boolean flag, indicating
+if the game should continue or not -- in the case of a correct guess,
+the game does not continue.
+
+This description of judge-guess is a mouthful -- and it suggests that
+it may be best to split it into two words. The first word we write
+handles the more specific case of an \emph{inexact} guess -- so it
+prints either \texttt{too-low} or \texttt{too-high}.
+
+\begin{alltt}
+: inexact-guess ( actual guess -{}- )
+ < {[} too-high {]} {[} too-low {]} ifte ;
+\end{alltt}
+Note that the word gives incorrect output if the two parameters are
+equal. However, it will never be called this way.
+
+With this out of the way, the implementation of judge-guess is an
+easy task to tackle. Using the words \texttt{inexact-guess}, \texttt{2dup}, \texttt{2drop} and \texttt{=}, we can write:
+
+\begin{alltt}
+: judge-guess ( actual guess -{}- ? )
+ 2dup = {[}
+ 2drop correct f
+ {]} {[}
+ inexact-guess t
+ {]} ifte ;
+\end{alltt}
+
+The word \texttt{=} is found in the \texttt{kernel} vocabulary, and the words \texttt{2dup} and \texttt{2drop} are found in the \texttt{stack} vocabulary. Since \texttt{=}
+consumes both its inputs, we must first duplicate the \texttt{actual} and \texttt{guess} parameters using \texttt{2dup}. The word \texttt{correct} does not need to do anything with these two numbers, so they are popped off the stack using \texttt{2drop}. Try evaluating the following
+in the interpreter to see what's going on:
+
+\begin{alltt}
+clear 1 2 2dup = .s
+\emph{\{ 1 2 f \}}
+clear 4 4 2dup = .s
+\emph{\{ 4 4 t \}}
+\end{alltt}
+
+Test \texttt{judge-guess} with a few inputs:
+
+\begin{alltt}
+1 10 judge-guess .
+\emph{Too low}
\emph{t}
-5 f and .
-\emph{f}
-f "hi" or .
-\emph{"hi"}
-f f or .
-\emph{f}
-t t xor .
-\emph{f}
-t f xor .
+89 43 judge-guess .
+\emph{Too high}
\emph{t}
+64 64 judge-guess .
+\emph{Correct}
+\emph{f}
\end{alltt}
-\texttt{?~( cond~true false -{}- obj~)} returns the second argument if the first argument is true, and returns the third argument if the first argument is false.
+\subsection{Generating random numbers}
+
+The \texttt{random-int} word \texttt{( min max -{}- n )} pushes a
+random number in a specified range. The range is inclusive, so both
+the minimum and maximum indexes are candidate random numbers. Use
+\texttt{apropos.} to determine that this word is in the \texttt{random}
+vocabulary. For the purposes of this game, random numbers will be
+in the range of 0 to 100, so we can define a word that generates a
+random number in the range of 0 to 100:
\begin{alltt}
-: sgn 0 < -1 1 ? ;
--10 sgn .
-\emph{-1}
-5 sgn .
-\emph{1}
+: number-to-guess ( -{}- n ) 0 100 random-int ;
\end{alltt}
+Add the word definition to the source file, along with the appropriate
+\texttt{USE:} statement. Load the source file in the interpreter,
+and confirm that the word functions correctly, and that its stack
+effect comment is accurate.
-\subsection{\label{sub:Conditionals}Conditionals}
-\texttt{ifte} \texttt{( cond true false -{}- )} executes either the
-\texttt{true} or \texttt{false} quotations, depending on the boolean
-value of \texttt{cond}. A quotation a list of objects that can be executed. Quotations are input
-using the following syntax:
+\subsection{The game loop}
+
+The game loop consists of repeated calls to \texttt{guess-prompt},
+\texttt{read-number} and \texttt{judge-guess}. If \texttt{judge-guess}
+returns \texttt{f}, the loop stops, otherwise it continues. This is
+realized with a recursive implementation:
\begin{alltt}
-{[} 2 3 + . {]}
+: numbers-game-loop ( actual -{}- )
+ dup guess-prompt read-number judge-guess {[}
+ numbers-game-loop
+ {]} {[}
+ drop
+ {]} ifte ;
\end{alltt}
+In Factor, tail-recursive words consume a bounded amount of call stack
+space. This means you are free to pick recursion or iteration based
+on their own merits when solving a problem. In many other languages,
+the usefulness of recursion is severely limited by the lack of tail-recursive
+call optimization.
-Here is an example of \texttt{ifte} usage:
+
+\subsection{Finishing off}
+
+The last task is to combine everything into the main \texttt{numbers-game}
+word. This is easier than it seems:
\begin{alltt}
-1 2 < {[} "1 is less than 2." print {]} {[} "bug!" print {]} ifte
+: numbers-game number-to-guess numbers-game-loop ;
\end{alltt}
+Try it out! Simply invoke the \texttt{numbers-game} word in the interpreter.
+It should work flawlessly, assuming you tested each component of this
+design incrementally!
-Compare the order of parameters here with the order of parameters in
-the stack effect of \texttt{ifte}.
-The stack effects of the two \texttt{ifte} branches should be
-the same. If they differ, the word becomes harder to document and
-debug.
+\subsection{The complete program}
-\texttt{when} \texttt{( cond true -{}- )} and \texttt{unless} \texttt{( cond false -{}- )} are variations of \texttt{ifte} with only one active branch. The branches should produce as many values as they consume; this ensures that the stack effect of the entire \texttt{when} or \texttt{unless} expression is consistent regardless of which branch was taken.
+\begin{verbatim}
+! Numbers game example
-\section{Numbers}
+IN: numbers-game
+USE: kernel
+USE: math
+USE: parser
+USE: random
+USE: stdio
+USE: stack
+
+: read-number ( -- n ) read parse-number ;
+
+: guess-banner
+ "I'm thinking of a number between 0 and 100." print ;
+: guess-prompt "Enter your guess: " write ;
+: too-high "Too high" print ;
+: too-low "Too low" print ;
+: correct "Correct - you win!" print ;
+
+: inexact-guess ( actual guess -- )
+ < [ too-high ] [ too-low ] ifte ;
+
+: judge-guess ( actual guess -- ? )
+ 2dup = [
+ 2drop correct f
+ ] [
+ inexact-guess t
+ ] ifte ;
+
+: number-to-guess ( -- n ) 0 100 random-int ;
+
+: numbers-game-loop ( actual -- )
+ dup guess-prompt read-number judge-guess [
+ numbers-game-loop
+ ] [
+ drop
+ ] ifte ;
+
+: numbers-game number-to-guess numbers-game-loop ;
+\end{verbatim}
+
+\section{More about numbers}
Factor provides a rich set of math words. Factor numbers more closely model the mathematical concept of a number than other languages. Where possible, exact answers are given -- for example, adding or multiplying two integers never results in overflow, and dividing two integers yields a fraction rather than a truncated result. Complex numbers are supported, allowing many functions to be computed with parameters that would raise errors or return ``not a number'' in other languages.
@@ -704,269 +899,6 @@ BIN: 11111 -2 shift .b
The attentive reader will notice that shifting to the left is equivalent to multiplying by a power of two, and shifting to the right is equivalent to performing a truncating division by a power of two.
-\section{PRACTICAL: Numbers game}
-
-In this section, basic input/output and flow control is introduced.
-We construct a program that repeatedly prompts the user to guess a
-number -- they are informed if their guess is correct, too low, or
-too high. The game ends on a correct guess.
-
-\begin{alltt}
-numbers-game
-\emph{I'm thinking of a number between 0 and 100.}
-\emph{Enter your guess:} 25
-\emph{Too low}
-\emph{Enter your guess:} 38
-\emph{Too high}
-\emph{Enter your guess:} 31
-\emph{Correct - you win!}
-\end{alltt}
-
-\subsection{Getting started}
-
-Start a text editor and create a file named \texttt{numbers-game.factor}.
-
-Write a short comment at the top of the file. Two examples of commenting style supported by Factor:
-
-\begin{alltt}
-! Numbers game.
-( The great numbers game )
-\end{alltt}
-
-It is always a good idea to comment your code. Try to write simple
-code that does not need detailed comments to describe; similarly,
-avoid redundant comments. These two principles are hard to quantify
-in a concrete way, and will become more clear as your skills with
-Factor increase.
-
-We will be defining new words in the \texttt{numbers-game} vocabulary; add
-an \texttt{IN:} statement at the top of the source file:
-
-\begin{alltt}
-IN: numbers-game
-\end{alltt}
-Also in order to be able to test the words, issue a \texttt{USE:}
-statement in the interactive interpreter:
-
-\begin{alltt}
-USE: numbers-game
-\end{alltt}
-This section will develop the numbers game in an incremental fashion.
-After each addition, issue a command like the following to load the
-source file into the Factor interpreter:
-
-\begin{alltt}
-"numbers-game.factor" run-file
-\end{alltt}
-
-\subsection{Reading a number from the keyboard}
-
-A fundamental operation required for the numbers game is to be able
-to read a number from the keyboard. The \texttt{read} word \texttt{(
--{}- str )} reads a line of input and pushes it on the stack.
-The \texttt{parse-number} word \texttt{( str -{}- n )} turns a decimal
-string representation of an integer into the integer itself. These
-two words can be combined into a single colon definition:
-
-\begin{alltt}
-: read-number ( -{}- n ) read parse-number ;
-\end{alltt}
-You should add this definition to the source file, and try loading
-the file into the interpreter. As you will soon see, this raises an
-error! The problem is that the two words \texttt{read} and \texttt{parse-number}
-are not part of the default, minimal, vocabulary search path used
-when reading files. The solution is to use \texttt{apropos.} to find
-out which vocabularies contain those words, and add the appropriate
-\texttt{USE:} statements to the source file:
-
-\begin{alltt}
-USE: parser
-USE: stdio
-\end{alltt}
-After adding the above two statements, the file should now parse,
-and testing should confirm that the \texttt{read-number} word works correctly.%
-\footnote{There is the possibility of an invalid number being entered at the
-keyboard. In this case, \texttt{parse-number} returns \texttt{f},
-the boolean false value. For the sake of simplicity, we ignore this
-case in the numbers game example. However, proper error handling is
-an essential part of any large program and is covered later.%
-}
-
-
-\subsection{Printing some messages}
-
-Now we need to make some words for printing various messages. They
-are given here without further ado:
-
-\begin{alltt}
-: guess-banner
- "I'm thinking of a number between 0 and 100." print ;
-: guess-prompt "Enter your guess: " write ;
-: too-high "Too high" print ;
-: too-low "Too low" print ;
-: correct "Correct - you win!" print ;
-\end{alltt}
-Note that in the above, stack effect comments are omitted, since they
-are obvious from context. You should ensure the words work correctly
-after loading the source file into the interpreter.
-
-
-\subsection{Taking action based on a guess}
-
-The next logical step is to write a word \texttt{judge-guess} that
-takes the user's guess along with the actual number to be guessed,
-and prints one of the messages \texttt{too-high}, \texttt{too-low},
-or \texttt{correct}. This word will also push a boolean flag, indicating
-if the game should continue or not -- in the case of a correct guess,
-the game does not continue.
-
-This description of judge-guess is a mouthful -- and it suggests that
-it may be best to split it into two words. The first word we write
-handles the more specific case of an \emph{inexact} guess -- so it
-prints either \texttt{too-low} or \texttt{too-high}.
-
-\begin{alltt}
-: inexact-guess ( actual guess -{}- )
- < {[} too-high {]} {[} too-low {]} ifte ;
-\end{alltt}
-Note that the word gives incorrect output if the two parameters are
-equal. However, it will never be called this way.
-
-With this out of the way, the implementation of judge-guess is an
-easy task to tackle. Using the words \texttt{inexact-guess}, \texttt{2dup}, \texttt{2drop} and \texttt{=}, we can write:
-
-\begin{alltt}
-: judge-guess ( actual guess -{}- ? )
- 2dup = {[}
- 2drop correct f
- {]} {[}
- inexact-guess t
- {]} ifte ;
-\end{alltt}
-
-The word \texttt{=} is found in the \texttt{kernel} vocabulary, and the words \texttt{2dup} and \texttt{2drop} are found in the \texttt{stack} vocabulary. Since \texttt{=}
-consumes both its inputs, we must first duplicate the \texttt{actual} and \texttt{guess} parameters using \texttt{2dup}. The word \texttt{correct} does not need to do anything with these two numbers, so they are popped off the stack using \texttt{2drop}. Try evaluating the following
-in the interpreter to see what's going on:
-
-\begin{alltt}
-clear 1 2 2dup = .s
-\emph{\{ 1 2 f \}}
-clear 4 4 2dup = .s
-\emph{\{ 4 4 t \}}
-\end{alltt}
-
-Test \texttt{judge-guess} with a few inputs:
-
-\begin{alltt}
-1 10 judge-guess .
-\emph{Too low}
-\emph{t}
-89 43 judge-guess .
-\emph{Too high}
-\emph{t}
-64 64 judge-guess .
-\emph{Correct}
-\emph{f}
-\end{alltt}
-
-\subsection{Generating random numbers}
-
-The \texttt{random-int} word \texttt{( min max -{}- n )} pushes a
-random number in a specified range. The range is inclusive, so both
-the minimum and maximum indexes are candidate random numbers. Use
-\texttt{apropos.} to determine that this word is in the \texttt{random}
-vocabulary. For the purposes of this game, random numbers will be
-in the range of 0 to 100, so we can define a word that generates a
-random number in the range of 0 to 100:
-
-\begin{alltt}
-: number-to-guess ( -{}- n ) 0 100 random-int ;
-\end{alltt}
-Add the word definition to the source file, along with the appropriate
-\texttt{USE:} statement. Load the source file in the interpreter,
-and confirm that the word functions correctly, and that its stack
-effect comment is accurate.
-
-
-\subsection{The game loop}
-
-The game loop consists of repeated calls to \texttt{guess-prompt},
-\texttt{read-number} and \texttt{judge-guess}. If \texttt{judge-guess}
-returns \texttt{f}, the loop stops, otherwise it continues. This is
-realized with a recursive implementation:
-
-\begin{alltt}
-: numbers-game-loop ( actual -{}- )
- dup guess-prompt read-number judge-guess {[}
- numbers-game-loop
- {]} {[}
- drop
- {]} ifte ;
-\end{alltt}
-In Factor, tail-recursive words consume a bounded amount of call stack
-space. This means you are free to pick recursion or iteration based
-on their own merits when solving a problem. In many other languages,
-the usefulness of recursion is severely limited by the lack of tail-recursive
-call optimization.
-
-
-\subsection{Finishing off}
-
-The last task is to combine everything into the main \texttt{numbers-game}
-word. This is easier than it seems:
-
-\begin{alltt}
-: numbers-game number-to-guess numbers-game-loop ;
-\end{alltt}
-Try it out! Simply invoke the \texttt{numbers-game} word in the interpreter.
-It should work flawlessly, assuming you tested each component of this
-design incrementally!
-
-
-\subsection{The complete program}
-
-\begin{verbatim}
-! Numbers game example
-
-IN: numbers-game
-USE: kernel
-USE: math
-USE: parser
-USE: random
-USE: stdio
-USE: stack
-
-: read-number ( -- n ) read parse-number ;
-
-: guess-banner
- "I'm thinking of a number between 0 and 100." print ;
-: guess-prompt "Enter your guess: " write ;
-: too-high "Too high" print ;
-: too-low "Too low" print ;
-: correct "Correct - you win!" print ;
-
-: inexact-guess ( actual guess -- )
- < [ too-high ] [ too-low ] ifte ;
-
-: judge-guess ( actual guess -- ? )
- 2dup = [
- 2drop correct f
- ] [
- inexact-guess t
- ] ifte ;
-
-: number-to-guess ( -- n ) 0 100 random-int ;
-
-: numbers-game-loop ( actual -- )
- dup guess-prompt read-number judge-guess [
- numbers-game-loop
- ] [
- drop
- ] ifte ;
-
-: numbers-game number-to-guess numbers-game-loop ;
-\end{verbatim}
-
\section{Sequences}
Factor supports two primary types for storing sequential data; lists and vectors.
@@ -1092,9 +1024,7 @@ an error, or disregard the hanging cdr at the end of the list.
List manipulation words usually return newly-created
lists only. The original parameters are not modified. This may seem
inefficient, however the absence of side effects makes code much easier
-to test and debug.%
-\footnote{Side effect-free code is the fundamental idea underlying functional
-programming languages.
+to test and debug.
\texttt{append ( list list -{}- list )} Append two lists at the
top of the stack:
@@ -1500,6 +1430,150 @@ The syntax for the quotations there looks an aweful lot like the syntax for lite
Essentially, the interpreter iterates through code quotations, pushing literals and executing words. When a word is executed, one of two things happen -- either the word has a colon definition, and the interpreter is invoked recursively on the definition, or the word is primitive, and it is executed by the underlying virtual machine.
+\subsection{Booleans and logic}
+
+Words that return a boolean truth value are known as \emph{predicates}. Predicates are usually used to decide what to execute next at branch points. In Factor, there is no special boolean data type
+-- instead, a special object \texttt{f} is the only object with a
+``false'' boolean value. Every other object is a boolean ``true''.
+The special object \texttt{t} is the ``canonical'' truth value. Note that words that return booleans don't return \texttt{t} as a rule; any object that is not equal to \texttt{f} can be returned as the true value.
+
+The usual boolean operations are found in the \texttt{logic} vocabulary. Note that these are not integer bitwise operations; bitwise operations are described in the next chapter.
+
+\texttt{not ( ?~-{}- ?~)} returns \texttt{t} if the top of stack is \texttt{f}, and \texttt{f} otherwise.
+
+\texttt{and ( ?~?~-{}- ?~)} returns a true value if both input parameters are true.
+
+\texttt{or ( ?~?~-{}- ?~)} returns a true value if at least one of the input parameters is true.
+
+\texttt{xor ( ?~?~-{}- ?~)} returns a true value if exactly one of the input parameters is true.
+
+\begin{alltt}
+t t and .
+\emph{t}
+5 f and .
+\emph{f}
+f "hi" or .
+\emph{"hi"}
+f f or .
+\emph{f}
+t t xor .
+\emph{f}
+t f xor .
+\emph{t}
+\end{alltt}
+
+\texttt{?~( cond~true false -{}- obj~)} returns the second argument if the first argument is true, and returns the third argument if the first argument is false.
+
+\begin{alltt}
+: sgn 0 < -1 1 ? ;
+-10 sgn .
+\emph{-1}
+5 sgn .
+\emph{1}
+\end{alltt}
+
+\subsection{\label{sub:Conditionals}Conditionals}
+
+The \texttt{ifte} combinator was already glossed over and hand-waved in the numbers game example. Now, we will take a closer look at \texttt{ifte} and related forms.
+
+\texttt{ifte} \texttt{( cond true false -{}- )} executes either the
+\texttt{true} or \texttt{false} quotations, depending on the boolean
+value of \texttt{cond}. The condition is removed from the stack before one of the two quotations is executed; if it is required as a parameter to a word called by one of the quotations, it must be duplicated first.
+
+A quotation a list of objects that can be executed. Quotations are input
+using the following syntax:
+
+\begin{alltt}
+{[} 2 3 + . {]}
+\end{alltt}
+
+Here is an example of \texttt{ifte} usage:
+
+\begin{alltt}
+1 2 < {[} "1 is less than 2." print {]} {[} "bug!" print {]} ifte
+\end{alltt}
+
+Compare the order of parameters here with the order of parameters in
+the stack effect of \texttt{ifte}.
+
+The stack effects of the two \texttt{ifte} branches should be
+the same. If they differ, the word becomes harder to document and
+debug.
+
+Two minor variations are \texttt{when} \texttt{( cond true -{}- )} and \texttt{unless} \texttt{( cond false -{}- )}. They only have one branch; the other branch is a no-op. The branch should produce as many values as they consume; this ensures that the stack effect of the entire \texttt{when} or \texttt{unless} expression is consistent regardless of which branch was taken.
+
+The following definition pushes the first element of a list if the top of the stack is a list, otherwise it leaves it intact:
+
+\begin{verbatim}
+: first ( obj -- obj )
+ dup cons? [ car ] when ;
+\end{verbatim}
+
+Note that regardless of the value at the top of the stack, the stack height is consistent at the end of the \texttt{when} expression, since \texttt{car} produces as many values as it consumes.
+
+Because the \texttt{ifte} combinator considers any value not equal to \texttt{f} to be true, it is often the case that the same object that was used as the condition is needed for further processing. One solution is to \texttt{dup} the object, so that it is on the stack for the ``true'' branch to use. However, usually the ``false'' branch does not need the extra \texttt{f} on the stack, so it has to \texttt{drop}. This pattern is very common; here is the general shape of the code:
+
+\begin{verbatim}
+dup [
+ do-something
+] [
+ drop handle-failure
+] ifte
+\end{verbatim}
+
+In fact, this pattern is so common that it is embodied by the \texttt{ifte*} combinator. Using \texttt{ifte*}, one would write the above code as follows:
+
+\begin{verbatim}
+[
+ do-something
+] [
+ handle-failure
+] ifte*
+\end{verbatim}
+
+An example of \texttt{ifte*} use can be found in the definition of the \texttt{list?} word. If the top of the stack is not \texttt{f}, further processing needs to be performed; if it is \texttt{f}, it can be discarded, and \texttt{t} must be pushed on the stack, since \texttt{f} is the empty list:
+
+\begin{verbatim}
+: list? ( list -- boolean )
+ #! Proper list test. A proper list is either f, or a cons
+ #! cell whose cdr is a proper list.
+ [
+ dup cons? [ cdr list? ] [ drop f ] ifte
+ ] [
+ t
+ ] ifte* ;
+\end{verbatim}
+
+Similarly, there is a \texttt{when*} combinator, with only one branch. A code snippet to print the top of the stack if it is not \texttt{f} might look as follows:
+
+\begin{verbatim}
+[ . ] when*
+\end{verbatim}
+
+It is equivalent to either of the following two lines:
+
+\begin{verbatim}
+[ . ] [ ] ifte*
+dup [ . ] [ drop ] ifte
+\end{verbatim}
+
+The \texttt{unless*} combinator provides a convinient way to place another value on the stack if the top of the stack is \texttt{f}, and leave the stack intact otherwise. The \texttt{mime-type} word uses it to provide a default value in case an association list lookup fails:
+
+\begin{verbatim}
+: mime-type ( filename -- mime-type )
+ file-extension mime-types assoc [ "text/plain" ] unless* ;
+\end{verbatim}
+
+If \texttt{unless*} was not available, the above word could be written as
+follows:
+
+\begin{verbatim}
+: mime-type ( filename -- mime-type )
+ file-extension mime-types assoc dup [
+ drop "text/plain"
+ ] unless ;
+\end{verbatim}
+
\subsection{The call stack}
So far, we have seen what we called ``the stack'' store intermediate values between computations. In fact Factor maintains a number of other stacks, and the formal name for the stack we've been dealing with so far is the \emph{data stack}.
@@ -1527,6 +1601,8 @@ Note that usages of \texttt{>r} and \texttt{r>} must be balanced within a single
Basically, the rule is you must leave the call stack in the same state as you found it so that when the current quotation finishes executing, the interpreter can continue executing without seeing your data on the call stack.
+One exception is that when \texttt{ifte} occurs as the last word in a definition, values may be pushed on the call stack before the condition value is computed, as long as both branches of the \texttt{ifte} pop the values off the callstack before returning.
+
\subsection{Recursion}
The idea of \emph{recursion} is key to understanding Factor. A \emph{recursive} word definition is one that refers to itself, usually in one branch of a conditional. The general form of a recursive word looks as follows:
@@ -2181,7 +2257,11 @@ set to \texttt{f}, or an undefined value.
\texttt{set-hash ( value key hash -{}- )} stores a key/value pair in a hashtable.
-examples, and hash>alist, alist>hash, hash-keys, hash-values
+Hashtables can be converted to association lists and vice versa using
+the \texttt{hash>alist} and \texttt{alist>hash} words. The list of keys and
+list of values can be extracted using the \texttt{hash-keys} and \texttt{hash-values} words.
+
+examples
\subsection{Variables}
diff --git a/dockables.xml b/dockables.xml
index ec4a365905..1e3555b2da 100644
--- a/dockables.xml
+++ b/dockables.xml
@@ -6,7 +6,7 @@
- new factor.listener.FactorListenerPanel(
+ new factor.jedit.FactorListenerPanel(
factor.jedit.FactorPlugin.getInterpreter());
diff --git a/factor/listener/EvalListener.java b/factor/jedit/EvalListener.java
similarity index 98%
rename from factor/listener/EvalListener.java
rename to factor/jedit/EvalListener.java
index 2db9c49a7c..745146e99b 100644
--- a/factor/listener/EvalListener.java
+++ b/factor/jedit/EvalListener.java
@@ -27,7 +27,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package factor.listener;
+package factor.jedit;
import factor.Cons;
import java.util.EventListener;
diff --git a/factor/listener/FactorListener.java b/factor/jedit/FactorListener.java
similarity index 77%
rename from factor/listener/FactorListener.java
rename to factor/jedit/FactorListener.java
index 773f2807ff..ca792cedae 100644
--- a/factor/listener/FactorListener.java
+++ b/factor/jedit/FactorListener.java
@@ -27,7 +27,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package factor.listener;
+package factor.jedit;
import factor.*;
import java.awt.*;
@@ -55,6 +55,7 @@ public class FactorListener extends JTextPane
private Cons readLineContinuation;
private int cmdStart = -1;
+ private ListenerHistoryText history;
//{{{ FactorListener constructor
public FactorListener()
@@ -63,24 +64,35 @@ public class FactorListener extends JTextPane
addMouseListener(mouse);
addMouseMotionListener(mouse);
+ history = new ListenerHistoryText(this,"factor");
+
listenerList = new EventListenerList();
InputMap inputMap = getInputMap();
- /* Replace enter to evaluate the input */
+ /* Press enter to evaluate the input */
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),
new EnterAction());
- /* Replace backspace to stop backspacing over the prompt */
+ /* Press backspace to stop backspacing over the prompt */
inputMap.put(KeyStroke.getKeyStroke('\b'),
new BackspaceAction());
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME,0),
new HomeAction());
+ /* Press Up/Down to access history */
+ inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),
+ new HistoryUpAction());
+
+ inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),
+ new HistoryDownAction());
+
/* Workaround */
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE,0),
new DummyAction());
+
+ getDocument().addDocumentListener(new DocumentHandler());
} //}}}
//{{{ insertWithAttrs() method
@@ -104,30 +116,11 @@ public class FactorListener extends JTextPane
{
StyledDocument doc = (StyledDocument)getDocument();
cmdStart = doc.getLength();
- Element elem = doc.getParagraphElement(cmdStart);
- /* System.err.println(elem.getAttributes().getClass()); */
setCursor(DefaultCursor);
this.readLineContinuation = continuation;
setCaretPosition(cmdStart);
} //}}}
- //{{{ getLine() method
- private String getLine() throws BadLocationException
- {
- StyledDocument doc = (StyledDocument)getDocument();
- int length = doc.getLength();
- if(cmdStart > length)
- return "";
- else
- {
- String line = doc.getText(cmdStart,length - cmdStart);
- if(line.endsWith("\n"))
- return line.substring(0,line.length() - 1);
- else
- return line;
- }
- } //}}}
-
//{{{ addEvalListener() method
public void addEvalListener(EvalListener l)
{
@@ -241,6 +234,49 @@ public class FactorListener extends JTextPane
}
} //}}}
+ //{{{ getInput() method
+ public String getInput()
+ {
+ try
+ {
+ Document doc = getDocument();
+ String line = doc.getText(cmdStart,doc.getLength() - cmdStart);
+ if(line.endsWith("\n"))
+ return line.substring(0,line.length() - 1);
+ else
+ return line;
+ }
+ catch(BadLocationException e)
+ {
+ throw new RuntimeException(e);
+ }
+ } //}}}
+
+ //{{{ setInput() method
+ public void setInput(String line)
+ {
+ System.err.println("Set input: " + line + ", " + cmdStart);
+ try
+ {
+ Document doc = getDocument();
+ doc.remove(cmdStart,doc.getLength() - cmdStart);
+ doc.insertString(cmdStart,line,null);
+ }
+ catch(BadLocationException e)
+ {
+ throw new RuntimeException(e);
+ }
+ } //}}}
+
+ /**
+ * Subclasses can override this to provide funky history behavior,
+ * for JTextPanes and such.
+ */
+ public int getInputStart()
+ {
+ return cmdStart;
+ }
+
//{{{ MouseHandler class
class MouseHandler extends MouseInputAdapter
{
@@ -287,14 +323,9 @@ public class FactorListener extends JTextPane
setCaretPosition(getDocument().getLength());
replaceSelection("\n");
- try
- {
- fireEvalEvent(getLine());
- }
- catch(BadLocationException e)
- {
- e.printStackTrace();
- }
+ history.addCurrentToHistory();
+ history.setIndex(-1);
+ fireEvalEvent(getInput());
}
} //}}}
@@ -336,6 +367,24 @@ public class FactorListener extends JTextPane
}
} //}}}
+ //{{{ HistoryUpAction class
+ class HistoryUpAction extends AbstractAction
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ history.historyPrevious();
+ }
+ } //}}}
+
+ //{{{ HistoryDownAction class
+ class HistoryDownAction extends AbstractAction
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ history.historyNext();
+ }
+ } //}}}
+
//{{{ DummyAction class
class DummyAction extends AbstractAction
{
@@ -343,4 +392,33 @@ public class FactorListener extends JTextPane
{
}
} //}}}
+
+ //{{{ DocumentHandler class
+ class DocumentHandler implements DocumentListener
+ {
+ public void insertUpdate(DocumentEvent e)
+ {
+ int offset = e.getOffset();
+ int length = e.getLength();
+
+ if(offset < cmdStart)
+ cmdStart += length;
+ }
+
+ public void removeUpdate(DocumentEvent e)
+ {
+ int offset = e.getOffset();
+ int length = e.getLength();
+
+ if(offset < cmdStart)
+ {
+ if(offset + length > cmdStart)
+ cmdStart = offset;
+ else
+ cmdStart -= length;
+ }
+ }
+
+ public void changedUpdate(DocumentEvent e) {}
+ } //}}}
}
diff --git a/factor/listener/FactorListenerPanel.java b/factor/jedit/FactorListenerPanel.java
similarity index 99%
rename from factor/listener/FactorListenerPanel.java
rename to factor/jedit/FactorListenerPanel.java
index 68930b5ca3..291b158c1f 100644
--- a/factor/listener/FactorListenerPanel.java
+++ b/factor/jedit/FactorListenerPanel.java
@@ -27,7 +27,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package factor.listener;
+package factor.jedit;
import factor.*;
import java.awt.*;
diff --git a/factor/jedit/FactorPlugin.java b/factor/jedit/FactorPlugin.java
index b696260ce5..ecfdf83c32 100644
--- a/factor/jedit/FactorPlugin.java
+++ b/factor/jedit/FactorPlugin.java
@@ -29,7 +29,6 @@
package factor.jedit;
-import factor.listener.FactorListenerPanel;
import factor.*;
import java.io.InputStreamReader;
import java.util.*;
diff --git a/factor/jedit/FactorPlugin.props b/factor/jedit/FactorPlugin.props
index bbb1e4e056..c80a99d698 100644
--- a/factor/jedit/FactorPlugin.props
+++ b/factor/jedit/FactorPlugin.props
@@ -3,11 +3,11 @@
plugin.factor.jedit.FactorPlugin.activate=startup
plugin.factor.jedit.FactorPlugin.name=Factor
-plugin.factor.jedit.FactorPlugin.version=0.66
+plugin.factor.jedit.FactorPlugin.version=0.68
plugin.factor.jedit.FactorPlugin.author=Slava Pestov
plugin.factor.jedit.FactorPlugin.docs=/doc/jedit/index.html
-plugin.factor.jedit.FactorPlugin.depend.0=jedit 04.02.15.00
+plugin.factor.jedit.FactorPlugin.depend.0=jedit 04.03.01.00
plugin.factor.jedit.FactorPlugin.depend.1=plugin errorlist.ErrorListPlugin 1.3.2
plugin.factor.jedit.FactorPlugin.depend.2=plugin sidekick.SideKickPlugin 0.3.1
diff --git a/factor/listener/FactorDesktop.java b/factor/jedit/ListenerHistoryText.java
similarity index 63%
rename from factor/listener/FactorDesktop.java
rename to factor/jedit/ListenerHistoryText.java
index 0e4913f974..edccdcc5a0 100644
--- a/factor/listener/FactorDesktop.java
+++ b/factor/jedit/ListenerHistoryText.java
@@ -27,43 +27,34 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package factor.listener;
+package factor.jedit;
-import factor.*;
-import java.awt.*;
-import java.awt.event.*;
-import java.util.*;
-import javax.swing.*;
-import javax.swing.text.*;
-import javax.swing.text.html.*;
+import javax.swing.text.JTextComponent;
+import org.gjt.sp.jedit.gui.HistoryText;
-public class FactorDesktop extends JFrame
+public class ListenerHistoryText extends HistoryText
{
- //{{{ main() method
- public static void main(final String[] args)
+ private FactorListener listener;
+
+ public ListenerHistoryText(FactorListener listener, String model)
{
- SwingUtilities.invokeLater(new Runnable()
- {
- public void run()
- {
- new FactorDesktop(args,true);
- }
- });
- } //}}}
+ super(listener,model);
+ this.listener = listener;
+ }
- //{{{ FactorDesktop constructor
- public FactorDesktop(String[] args, boolean standalone)
+ public int getInputStart()
{
- super("Factor");
-
- getContentPane().add(BorderLayout.CENTER,
- new FactorListenerPanel(
- FactorListenerPanel.newInterpreter(args)));
-
- setSize(640,480);
- setDefaultCloseOperation(standalone
- ? EXIT_ON_CLOSE
- : DISPOSE_ON_CLOSE);
- show();
- } //}}}
+ return listener.getInputStart();
+ }
+
+ public String getText()
+ {
+ return listener.getInput();
+ }
+
+ public void setText(String text)
+ {
+ setIndex(-1);
+ listener.setInput(text);
+ }
}
diff --git a/library/compiler/alien.factor b/library/compiler/alien.factor
index 58922377fe..f86079bef6 100644
--- a/library/compiler/alien.factor
+++ b/library/compiler/alien.factor
@@ -72,7 +72,7 @@ USE: words
] bind ;
: alien-function ( function library -- )
- library dlsym ;
+ [ library dlsym ] [ dlsym-self ] ifte* ;
: compile-alien-call
pop-literal reverse PARAMETERS >r
diff --git a/library/debugger.factor b/library/debugger.factor
index 5da4fa3b36..5f339c78cd 100644
--- a/library/debugger.factor
+++ b/library/debugger.factor
@@ -61,9 +61,8 @@ USE: unparser
: default-error-handler ( error -- )
#! Print the error and return to the top level.
[
- in-parser? [ parse-dump ] [ standard-dump ] ifte terpri
+ in-parser? [ parse-dump ] [ standard-dump ] ifte
- "Stacks have been reset." print
":s :r :n :c show stacks at time of error." print
java? [ ":j shows Java stack trace." print ] when
@@ -71,7 +70,7 @@ USE: unparser
] when* ;
-: :s ( -- ) "error-datastack" get . ;
-: :r ( -- ) "error-callstack" get . ;
-: :n ( -- ) "error-namestack" get . ;
-: :c ( -- ) "error-catchstack" get . ;
+: :s ( -- ) "error-datastack" get {.} ;
+: :r ( -- ) "error-callstack" get {.} ;
+: :n ( -- ) "error-namestack" get {.} ;
+: :c ( -- ) "error-catchstack" get {.} ;
diff --git a/library/httpd/default-responders.factor b/library/httpd/default-responders.factor
index 320eac1cde..73ae64fbd2 100644
--- a/library/httpd/default-responders.factor
+++ b/library/httpd/default-responders.factor
@@ -36,7 +36,6 @@ USE: inspect-responder
USE: quit-responder
USE: file-responder
USE: resource-responder
-USE: wiki-responder
#! Remove all existing responders, and create a blank
#! responder table.
@@ -76,11 +75,3 @@ global [ "httpd-responders" set ] bind
] extend add-responder
"file" set-default-responder
-
-! [
-! "wiki" "responder" set
-! [ wiki-get-responder ] "get" set
-! [ wiki-post-responder ] "post" set
-! "wiki" set
-! "WikiHome" "default-argument" set
-! ] extend add-responder
diff --git a/library/httpd/wiki-responder.factor b/library/httpd/wiki-responder.factor
deleted file mode 100644
index f05a2b6bd8..0000000000
--- a/library/httpd/wiki-responder.factor
+++ /dev/null
@@ -1,72 +0,0 @@
-! :folding=indent:collapseFolds=0:
-
-! $Id$
-!
-! Copyright (C) 2004 Slava Pestov.
-!
-! Redistribution and use in source and binary forms, with or without
-! modification, are permitted provided that the following conditions are met:
-!
-! 1. Redistributions of source code must retain the above copyright notice,
-! this list of conditions and the following disclaimer.
-!
-! 2. Redistributions in binary form must reproduce the above copyright notice,
-! this list of conditions and the following disclaimer in the documentation
-! and/or other materials provided with the distribution.
-!
-! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-IN: wiki-responder
-USE: combinators
-USE: format
-USE: html
-USE: lists
-USE: logic
-USE: kernel
-USE: math
-USE: namespaces
-USE: parser
-USE: regexp
-USE: stdio
-USE: stack
-USE: strings
-USE: words
-
-USE: httpd
-USE: httpd-responder
-
-! : wiki-word? ( word -- ? )
-! #! A WikiWord starts with a capital and contains more than
-! #! one capital letter.
-! dup str-length 0 > [
-! 0 over str-nth LETTER? [
-! 0 swap [ LETTER? [ succ ] when ] str-each 1 = not
-! ] [
-! drop f
-! ] ifte
-! ] [
-! drop f
-! ] ifte ;
-!
-! : wiki-formatting ( str -- )
-! #! If a word with this name exists in the wiki-formatting
-! #! vocabulary, its a special text style sequence.
-! [ "wiki-formatting" ] search ;
-!
-! : (wiki-parser) ( text -- )
-! [
-! scan dup wiki-word? [
-! write
-! ] [
-! write
-! ] ifte " " write
-! ] with-parser ;
diff --git a/library/init.factor b/library/init.factor
index 0ee0997fc9..b461109ae6 100644
--- a/library/init.factor
+++ b/library/init.factor
@@ -99,8 +99,6 @@ USE: words
parse-switches run-files ;
: init-interpreter ( -- )
- init-history
-
print-banner
room.
diff --git a/library/interpreter.factor b/library/interpreter.factor
index 567b36f707..e0fe1c97ed 100644
--- a/library/interpreter.factor
+++ b/library/interpreter.factor
@@ -50,43 +50,12 @@ USE: vectors
"Copyright (C) 2004 Chris Double" print
"Type ``exit'' to exit, ``help'' for help." print ;
-: init-history ( -- )
- 64 "history" set ;
-
-: history+ ( cmd -- )
- "history" get vector-push ;
-
-: print-numbered-entry ( index vector -- )
- <% over unparse % ": " % vector-nth % %> print ;
-
-: print-numbered-vector ( list -- )
- dup vector-length [ over print-numbered-entry ] times* drop ;
-
-: history. ( -- )
- "X redo -- evaluate the expression with number X." print
- "X re-edit -- edit the expression with number X." print
- "history" get print-numbered-vector ;
-
-: get-history ( index -- str )
- "history" get vector-nth ;
-
-: redo ( index -- )
- get-history dup " ( " write write " )" print eval ;
-
-: re-edit ( index -- )
- get-history edit ;
-
-: history# ( -- number )
- "history" get vector-length ;
-
: print-prompt ( -- )
- <% " ( " % history# unparse % " )" % %>
- "prompt" get-style write-attr
+ "ok" "prompt" get-style write-attr
! Print the space without a style, to workaround a bug in
! the GUI listener where the style from the prompt carries
! over to the input
- " " write
- flush ;
+ " " write flush ;
: exit ( -- )
"quit-flag" on ;
@@ -95,11 +64,7 @@ USE: vectors
[ eval ] [ [ default-error-handler drop ] when* ] catch ;
: interpret ( -- )
- print-prompt read dup [
- dup history+ eval-catch
- ] [
- drop exit
- ] ifte ;
+ print-prompt read [ eval-catch ] [ exit ] ifte* ;
: interpreter-loop ( -- )
"quit-flag" get [
@@ -118,7 +83,6 @@ USE: vectors
native? [
"\"foo.image\" save-image -- save heap to a file" print
] when
- "history. -- show previous commands" print
"room. -- show memory usage" print
"garbage-collection -- force a GC" print
"exit -- exit interpreter" print
@@ -126,9 +90,9 @@ USE: vectors
"WORDS:" print
"vocabs. -- list vocabularies" print
"\"math\" words. -- list the math vocabulary" print
- "\"neg\" see -- show word definition" print
"\"str\" apropos. -- list all words containing str" print
- "\"car\" usages. -- list all words invoking car" print
+ "\\ neg see -- show word definition" print
+ "\\ car usages. -- list all words invoking car" print
terpri
"STACKS:" print
".s .r .n .c -- show contents of the 4 stacks" print
diff --git a/library/platform/jvm/listener.factor b/library/jedit/listener.factor
similarity index 97%
rename from library/platform/jvm/listener.factor
rename to library/jedit/listener.factor
index 51244310d2..ec8e0ef09e 100644
--- a/library/platform/jvm/listener.factor
+++ b/library/jedit/listener.factor
@@ -77,7 +77,7 @@ USE: unparser
jnew ;
: actions-key ( -- attr )
- "factor.listener.FactorListener" "Actions" jvar-static-get
+ "factor.jedit.FactorListener" "Actions" jvar-static-get
; inline
: ( path pair -- pair )
@@ -161,7 +161,7 @@ USE: unparser
: listener-readln* ( continuation -- )
"listener" get
[ "factor.Cons" ]
- "factor.listener.FactorListener"
+ "factor.jedit.FactorListener"
"readLine" jinvoke ;
: listener-readln ( -- line )
@@ -170,14 +170,14 @@ USE: unparser
: listener-write-attr ( string style -- )
style>attribute-set "listener" get
[ "java.lang.String" "javax.swing.text.AttributeSet" ]
- "factor.listener.FactorListener"
+ "factor.jedit.FactorListener"
"insertWithAttrs"
jinvoke ;
!: listener-edit ( string -- )
! "listener" get
! [ "java.lang.String" ]
-! "factor.listener.FactorListener"
+! "factor.jedit.FactorListener"
! "editLine" jinvoke ;
: ( listener -- stream )
diff --git a/library/math/math.factor b/library/math/math.factor
index 371019dd65..2f81a03834 100644
--- a/library/math/math.factor
+++ b/library/math/math.factor
@@ -33,10 +33,6 @@ USE: math
USE: real-math
USE: stack
-: fib ( n -- nth fibonacci number )
- ! This is the naive implementation, for benchmarking purposes.
- dup 1 <= [ drop 1 ] [ pred dup fib swap pred fib + ] ifte ;
-
: fac ( n -- n! )
! This is the naive implementation, for benchmarking purposes.
1 swap [ succ * ] times* ;
diff --git a/library/namespaces.factor b/library/namespaces.factor
index 4c1cfc3083..108143deb0 100644
--- a/library/namespaces.factor
+++ b/library/namespaces.factor
@@ -53,14 +53,6 @@ USE: vectors
! bind ( namespace quot -- ) executes a quotation with a
! namespace pushed on the namespace stack.
-: >n ( namespace -- n:namespace )
- #! Push a namespace on the namespace stack.
- namestack* vector-push ; inline
-
-: n> ( n:namespace -- namespace )
- #! Pop the top of the namespace stack.
- namestack* vector-pop ; inline
-
: namespace ( -- namespace )
#! Push the current namespace.
namestack* vector-peek ; inline
diff --git a/library/platform/jvm/boot-sumo.factor b/library/platform/jvm/boot-sumo.factor
index 2ea4fa6057..18246ce068 100644
--- a/library/platform/jvm/boot-sumo.factor
+++ b/library/platform/jvm/boot-sumo.factor
@@ -120,15 +120,14 @@ USE: parser
"/library/httpd/quit-responder.factor" run-resource ! quit-responder
"/library/httpd/resource-responder.factor" run-resource ! resource-responder
"/library/httpd/test-responder.factor" run-resource ! test-responder
-"/library/httpd/wiki-responder.factor" run-resource ! wiki-responder
"/library/httpd/default-responders.factor" run-resource ! default-responders
-!!! jEdit integration.
-"/library/jedit/jedit-local.factor" run-resource ! jedit
-"/library/jedit/jedit-remote.factor" run-resource ! jedit
-"/library/jedit/jedit.factor" run-resource ! jedit
-
!!! Final initialization...
-"/library/init.factor" run-resource ! init
-"/library/platform/jvm/init.factor" run-resource ! init
-"/library/platform/jvm/listener.factor" run-resource ! listener
+"/library/init.factor" run-resource ! init
+"/library/platform/jvm/init.factor" run-resource ! init
+
+!!! jEdit integration.
+"/library/jedit/jedit-local.factor" run-resource ! jedit
+"/library/jedit/jedit-remote.factor" run-resource ! jedit
+"/library/jedit/jedit.factor" run-resource ! jedit
+"/library/jedit/listener.factor" run-resource ! listener
diff --git a/library/platform/jvm/namespaces.factor b/library/platform/jvm/namespaces.factor
index affc8e5f35..3de6e9574c 100644
--- a/library/platform/jvm/namespaces.factor
+++ b/library/platform/jvm/namespaces.factor
@@ -32,10 +32,9 @@ USE: lists
USE: logic
USE: stack
USE: strings
+USE: vectors
DEFER: namespace
-DEFER: >n
-DEFER: n>
: namestack* ( -- stack )
#! Push the namespace stack.
@@ -47,6 +46,14 @@ DEFER: n>
interpreter
"factor.FactorInterpreter" "namestack" jvar-set ; inline
+: >n ( namespace -- n:namespace )
+ #! Push a namespace on the namespace stack.
+ namestack* vector-push ; inline
+
+: n> ( n:namespace -- namespace )
+ #! Pop the top of the namespace stack.
+ namestack* vector-pop ; inline
+
: namestack ( -- stack )
namestack* clone ; inline
diff --git a/library/platform/native/init-stage2.factor b/library/platform/native/init-stage2.factor
index cb9b882e7b..6b6c3880ae 100644
--- a/library/platform/native/init-stage2.factor
+++ b/library/platform/native/init-stage2.factor
@@ -64,11 +64,11 @@ USE: words
t "ansi" set
t "compile" set
- "ansi" get [ "stdio" get "stdio" set ] when
-
! The first CLI arg is the image name.
cli-args uncons parse-command-line "image" set
+ "ansi" get [ "stdio" get "stdio" set ] when
+
"compile" get [ init-compiler ] when
run-user-init ;
diff --git a/library/platform/native/namespaces.factor b/library/platform/native/namespaces.factor
index 9304a36849..ab2d04597b 100644
--- a/library/platform/native/namespaces.factor
+++ b/library/platform/native/namespaces.factor
@@ -36,12 +36,18 @@ USE: strings
USE: vectors
DEFER: namespace
-DEFER: >n
-DEFER: n>
: namestack* ( -- ns ) 3 getenv ;
: set-namestack* ( ns -- ) 3 setenv ;
+: >n ( namespace -- n:namespace )
+ #! Push a namespace on the namespace stack.
+ namestack* vector-push ; inline
+
+: n> ( n:namespace -- namespace )
+ #! Pop the top of the namespace stack.
+ namestack* vector-pop ; inline
+
: namestack ( -- stack ) namestack* vector-clone ;
: set-namestack ( stack -- ) vector-clone set-namestack* ;
diff --git a/library/prettyprint.factor b/library/prettyprint.factor
index b45256ced4..f08643e669 100644
--- a/library/prettyprint.factor
+++ b/library/prettyprint.factor
@@ -213,10 +213,14 @@ DEFER: prettyprint*
#! Unparse each element on its own line.
[ . ] each ;
-: .n namestack . ;
-: .s datastack . ;
-: .r callstack . ;
-: .c catchstack . ;
+: {.} ( vector -- )
+ #! Unparse each element on its own line.
+ [ . ] vector-each ;
+
+: .n namestack {.} ;
+: .s datastack {.} ;
+: .r callstack {.} ;
+: .c catchstack {.} ;
! For integers only
: .b >bin print ;
diff --git a/library/telnetd.factor b/library/telnetd.factor
index 9df3b1777a..38256c946f 100644
--- a/library/telnetd.factor
+++ b/library/telnetd.factor
@@ -42,7 +42,6 @@ USE: threads
dup [
"client" set
log-client
- init-history
interpreter-loop
] with-stream ;
diff --git a/library/test/benchmark/ack.factor b/library/test/benchmark/ack.factor
new file mode 100644
index 0000000000..ca7ecdd51e
--- /dev/null
+++ b/library/test/benchmark/ack.factor
@@ -0,0 +1,21 @@
+USE: stack
+USE: math
+USE: kernel
+USE: combinators
+USE: compiler
+USE: test
+
+! http://inferno.bell-labs.com/cm/cs/who/bwk/interps/pap.html
+
+: ack ( m n -- )
+ over 0 = [
+ nip succ
+ ] [
+ dup 0 = [
+ drop pred 1 ack
+ ] [
+ dupd pred ack >r pred r> ack
+ ] ifte
+ ] ifte ; compiled
+
+[ 4093 ] [ 3 9 ack ] unit-test
diff --git a/library/test/benchmark/empty-loop.factor b/library/test/benchmark/empty-loop.factor
index b43130f828..111b344aef 100644
--- a/library/test/benchmark/empty-loop.factor
+++ b/library/test/benchmark/empty-loop.factor
@@ -3,5 +3,11 @@ USE: math
USE: stack
USE: test
-[ ] [ 5000000 [ ] times ] unit-test
-[ ] [ 5000000 [ drop ] times* ] unit-test
+: empty-loop-1 ( n -- )
+ [ ] times ;
+
+: empty-loop-2 ( n -- )
+ [ drop ] times* ;
+
+[ ] [ 5000000 empty-loop-1 ] unit-test
+[ ] [ 5000000 empty-loop-2 ] unit-test
diff --git a/library/test/benchmark/fib.factor b/library/test/benchmark/fib.factor
index a83e7d4482..5dc327f41c 100644
--- a/library/test/benchmark/fib.factor
+++ b/library/test/benchmark/fib.factor
@@ -1,6 +1,12 @@
IN: scratchpad
+USE: compiler
USE: math
USE: stack
USE: test
+USE: combinators
+
+: fib ( n -- nth fibonacci number )
+ dup 1 <= [ drop 1 ] [ pred dup fib swap pred fib + ] ifte ;
+ compiled
[ 9227465 ] [ 34 fib ] unit-test
diff --git a/library/test/benchmark/hashtables.factor b/library/test/benchmark/hashtables.factor
new file mode 100644
index 0000000000..cbd90d97eb
--- /dev/null
+++ b/library/test/benchmark/hashtables.factor
@@ -0,0 +1,20 @@
+USE: stack
+USE: strings
+USE: math
+USE: combinators
+USE: test
+USE: unparser
+USE: hashtables
+
+! http://inferno.bell-labs.com/cm/cs/who/bwk/interps/pap.html
+
+: store-hash ( hashtable n -- )
+ [ dup >hex swap pick set-hash ] times* drop ;
+
+: lookup-hash ( hashtable n -- )
+ [ unparse over hash drop ] times* drop ;
+
+: hashtable-benchmark ( n -- )
+ 60000 swap 2dup store-hash lookup-hash ;
+
+[ ] [ 80000 hashtable-benchmark ] unit-test
diff --git a/library/test/benchmark/strings.factor b/library/test/benchmark/strings.factor
new file mode 100644
index 0000000000..5dd7df6c30
--- /dev/null
+++ b/library/test/benchmark/strings.factor
@@ -0,0 +1,22 @@
+USE: stack
+USE: strings
+USE: math
+USE: combinators
+USE: test
+
+! http://inferno.bell-labs.com/cm/cs/who/bwk/interps/pap.html
+
+: string-step ( n str -- )
+ 2dup str-length > [
+ dup <% "123" % % "456" % % "789" % %>
+ dup dup str-length 2 /i 0 transp substring
+ swap dup str-length 2 /i succ 1 transp substring cat2
+ string-step
+ ] [
+ 2drop
+ ] ifte ;
+
+: string-benchmark ( n -- )
+ "abcdef" 10 [ 2dup string-step ] times 2drop ;
+
+[ ] [ 1000000 string-benchmark ] unit-test
diff --git a/library/test/benchmark/vectors.factor b/library/test/benchmark/vectors.factor
new file mode 100644
index 0000000000..87dcdb0857
--- /dev/null
+++ b/library/test/benchmark/vectors.factor
@@ -0,0 +1,23 @@
+USE: vectors
+USE: stack
+USE: math
+USE: compiler
+USE: test
+
+! http://inferno.bell-labs.com/cm/cs/who/bwk/interps/pap.html
+
+: fill-vector ( n -- vector )
+ dup swap [ dup pick set-vector-nth ] times* ;
+
+: copy-elt ( vec-y vec-x n -- )
+ #! Copy first nth element from vec-x to vec-y.
+ tuck swap vector-nth transp set-vector-nth ;
+
+: copy-vector ( vec-y vec-x n -- )
+ #! Copy first n-1 elements from vec-x to vec-y.
+ [ >r 2dup r> copy-elt ] times* 2drop ;
+
+: vector-benchmark ( n -- )
+ 0 over fill-vector rot copy-vector ; ! compiled
+
+[ ] [ 400000 vector-benchmark ] unit-test
diff --git a/library/test/interpreter.factor b/library/test/interpreter.factor
index 2f5b9e7fa0..7594e2f2cd 100644
--- a/library/test/interpreter.factor
+++ b/library/test/interpreter.factor
@@ -5,11 +5,6 @@ USE: stdio
USE: test
[
- init-history
- "2 2 +" history+
- history.
- [ "2 2 +" ] [ 0 get-history ] unit-test
- [ 4 ] [ 0 redo ] unit-test
[ 4 ] [ "2 2 +" eval-catch ] unit-test
"The following will print an error; ignore it." print terpri
[ ] [ "clear drop" eval-catch ] unit-test
diff --git a/library/test/math/namespaces.factor b/library/test/math/namespaces.factor
index cdae40ba88..b6789c3b34 100644
--- a/library/test/math/namespaces.factor
+++ b/library/test/math/namespaces.factor
@@ -9,5 +9,5 @@ USE: math
[ 5 ] [ 1 "x" -@ "x" get ] unit-test
[ 10 ] [ 2 "x" *@ "x" get ] unit-test
[ 2 ] [ 5 "x" /@ "x" get ] unit-test
-[ -3 ] [ "x" pred@ "x" get ] unit-test
-[ -2 ] [ "x" succ@ "x" get ] unit-test
+[ 1 ] [ "x" pred@ "x" get ] unit-test
+[ 2 ] [ "x" succ@ "x" get ] unit-test
diff --git a/library/test/test.factor b/library/test/test.factor
index 374ac0f978..996f758af1 100644
--- a/library/test/test.factor
+++ b/library/test/test.factor
@@ -113,7 +113,7 @@ USE: unparser
"crashes" test
"sbuf" test
"threads" test
- "parsing-word" test
+ ! "parsing-word" test
cpu "x86" = [
[
@@ -147,4 +147,8 @@ USE: unparser
"benchmark/fac" test
"benchmark/fib" test
"benchmark/sort" test
- "benchmark/continuations" test ;
+ "benchmark/continuations" test
+ "benchmark/ack" test
+ "benchmark/hashtables" test
+ "benchmark/strings" test
+ "benchmark/vectors" test ;
diff --git a/native/bignum.h b/native/bignum.h
index d779e962b7..3d58cdfbf7 100644
--- a/native/bignum.h
+++ b/native/bignum.h
@@ -33,6 +33,7 @@ void primitive_bignum_greater(void);
void primitive_bignum_greatereq(void);
void primitive_bignum_not(void);
void copy_bignum_constants(void);
+CELL three_test(void* x, unsigned char r, unsigned char g, unsigned char b);
INLINE CELL tag_integer(FIXNUM x)
{
diff --git a/native/run.c b/native/run.c
index 3590b28b8a..b0dd9ab66a 100644
--- a/native/run.c
+++ b/native/run.c
@@ -4,7 +4,7 @@ void clear_environment(void)
{
int i;
for(i = 0; i < USER_ENV; i++)
- userenv[i] = 0;
+ userenv[i] = F;
profile_depth = 0;
}