more documentation

cvs
Slava Pestov 2006-01-07 03:42:07 +00:00
parent 454ae53442
commit c8266adc45
9 changed files with 392 additions and 102 deletions

View File

@ -85,6 +85,14 @@ USE: image
</li>
<li>Contributed libraries:
<ul>
<li>Added splay tree library in <code>contrib/splay-trees.factor</code> (Mackenzie Straight)</li>
</ul>
</li>
</ul>
<h1>Factor 0.79:</h1>

121
doc/handbook/parser.facts Normal file
View File

@ -0,0 +1,121 @@
USING: help io parser words ;
ARTICLE: "parser" "The parser"
"This section concerns itself with reflective access and extension of the Factor parser. The parser algorithm and standard syntax is described in " { $link "syntax" } ". Before the parser proper is documented, we draw attention to a set of words for parsing numbers. They are called by the parser, and are useful in their own right."
$terpri
"The set of words making up the parser are found in the " { $snippet "parser" } " and " { $snippet "syntax" } " vocabularies."
$terpri
"As documented in " { $link "vocabulary-search" } ", the parser looks up words in the vocabulary search path. New word definitions are added to the current vocabulary. These two parameters are stored in a pair of variables:"
{ $subsection use }
{ $subsection in }
"There are two simple ways to call the parser:"
{ $subsection parse }
{ $subsection eval }
"More sophisticated facilities exist, too."
{ $subsection "parse-stream" }
{ $subsection "parsing-words" } ;
ARTICLE: "parse-stream" "Parsing from streams"
"By convention, words for parsing input from streams use a certain default vocabulary search path:"
{ $subsection file-vocabs }
"The central word for parsing input from a stream:"
{ $subsection parse-stream }
"Utilities for working with files:"
{ $subsection parse-file }
{ $subsection run-file }
"Utilities for working with Factor libarary files:"
{ $subsection resource-path }
{ $subsection parse-resource }
{ $subsection run-resource } ;
ARTICLE: "parsing-words" "Parsing words"
"Parsing words execute at parse time, and therefore can access and modify the state of the parser, as well as add objects to the parse tree. Parsing words are a difficult concept to grasp, so this section has several examples and explains the workings of some of the parsing words provided in the library."
$terpri
"Parsing words are marked by suffixing the definition with a declaration:"
{ $subsection POSTPONE: parsing }
{ $subsection "parsing-word-nest" }
{ $subsection "reading-ahead" }
{ $subsection "defining-words" }
{ $subsection "string-mode" } ;
ARTICLE: "parsing-word-nest" "Nested structure"
"The first thing to look at is how the parse tree is built. When parsing begins, the empty list is pushed on the data stack; whenever the parser algorithm appends an object to the parse tree, it conses the object onto the quotation at the top of the stack. This builds the quotation in reverse order, so when parsing is done, the quotation is reversed before it is called."
$terpri
"Lets look at a simple example; the parsing of " { $snippet "1 2 3" } ":"
$terpri
{ $list
{ "Token: " { $snippet "1" } " - stack: " { $snippet "[ 1 ]" } }
{ "Token: " { $snippet "2" } " - stack: " { $snippet "[ 2 1 ]" } }
{ "Token: " { $snippet "3" } " - stack: " { $snippet "[ 3 2 1 ]" } }
}
"Once the end of the string has been reached, the quotation is reversed, leaving the following output:"
{ $code "[ 1 2 3 ]" }
"Nested structure is a bit more involved. The basic idea is that parsing words can push an empty list on the stack, then all subsequent tokens are consed onto this list, until another parsing word adds this list to the list underneath."
$terpri
"The parsing words that delimit the beginning and the end of a quotation illustrate the idiom:"
{ $subsection POSTPONE: [ }
{ $subsection POSTPONE: ] }
"Let us ponder, then, how one particular string will parse::"
{ $snippet "\"1 [ 2 3 ] 4\"" }
{ $list
{ "Token: " { $snippet "1" } " - stack: " { $snippet "[ 1 ]" } }
{ "Token: " { $snippet "[" } " - stack: " { $snippet "[ ] [ 1 ]" } }
{ "Token: " { $snippet "2" } " - stack: " { $snippet "[ 2 ] [ 1 ]" } }
{ "Token: " { $snippet "3" } " - stack: " { $snippet "[ 3 2 ] [ 1 ]" } }
{ "Token: " { $snippet "]" } " - stack: " { $snippet "[ [ 2 3 ] 1 ]" } }
{ "Token: " { $snippet "4" } " - stack: " { $snippet "[ 4 [ 2 3 ] 1 ]" } }
}
"Having done all that, the parser reverses the original quotation, and the expected output is now on the stack:"
{ $code "[ 1 [ 2 3 ] 4 ]" }
"Notice how in the definition of the list parsing words, the final word " { $link POSTPONE: ] } " does all the work. A closely related set of parsing words for reading various other literal types implements another useful idiom."
$terpri
"The word set in question consists of various start delimiters, such a " { $link POSTPONE: { } " for arrays and " { $link POSTPONE: H{ } " for hashtables, together with one end delimiter " { $link POSTPONE: } } ". The start words push a quotation in addition to an empty list; the end word reverses the empty list, and applies the quotation to the newly-parsed list; the quotation converts it to the appropriate type of literal."
{ $subsection POSTPONE: { }
{ $subsection POSTPONE: H{ }
{ $subsection POSTPONE: } } ;
GLOSSARY: "reading ahead" "a parsing word reads ahead of it scans following tokens from the input string" ;
ARTICLE: "reading-ahead" "Reading ahead"
"Parsing words can consume input from the current line to implement various forms of custom syntax."
{ $subsection scan }
{ $subsection scan-word }
"For example, the " { $link POSTPONE: HEX: } " word, for reading hexadecimal literals, uses this facility. It is defined in terms of a lower-level " { $link (BASE) } " word that takes the numerical base on the data stack, but reads the number from the parser and then adds it to the parse tree:"
{ $subsection POSTPONE: HEX: }
{ $subsection (BASE) }
"Another simple example is the " { $link POSTPONE: \ } " word:"
{ $subsection POSTPONE: \ } ;
ARTICLE: "defining-words" "Defining words"
"Defining words add definitions to the dictionary without modifying the parse tree. The simplest example is the " { $link POSTPONE: SYMBOL: } " word:"
{ $subsection POSTPONE: SYMBOL: }
"The key factor the above definition is " { $link CREATE } ", which reads a token from the input and creates a word with that name. This word is then passed to " { $link define-symbol } "."
{ $subsection CREATE }
"Colon definitions are defined in a more elaborate way. The definition of " { $link POSTPONE: : } " introduces the next idiom, and that is building a quotation and then adding a definition using " { $link POSTPONE: ; } "."
$terpri
"Recall the colon definition syntax. When the " { $link POSTPONE: : } " word executes, it reads ahead from the input and defines a word. Then, it places a quotation and an empty list on the stack. The parser conses tokens onto the empty list, and the quotation is called by " { $link POSTPONE: ; } "."
{ $subsection POSTPONE: : }
{ $subsection POSTPONE: ; }
"There are additional parsing words whose syntax is delimited by " { $link POSTPONE: ; } ", and they are all implemented in the same way -- first they read some input, then they leave a quotation followed by an empty list on the stack."
{ $subsection POSTPONE: M: }
{ $subsection POSTPONE: C: } ;
ARTICLE: "string-mode" "String mode and parser internals"
"String mode allows custom parsing of tokenized input. For even more esoteric situations, the input text can be accessed directly."
$terpri
"String mode is controlled by a boolean variable in the parser scope:"
{ $subsection string-mode }
"An illustration of this idiom is found in the " { $link POSTPONE: USING: } " parsing word. It reads a list of vocabularies, terminated by " { $link POSTPONE: ; } ". However, the vocabulary names do not name words, except by coincidence; so string mode is used to read them."
{ $subsection POSTPONE: USING: }
"Make note of the quotation that is left in position for " { $link POSTPONE: ; } " to call. It switches off string mode, so that normal parsing can resume, then adds the given vocabularies to the search path."
$terpri
"Some additional variables that encapsulate internal parser state:"
{ $subsection file }
{ $subsection line-number }
{ $subsection line-text }
{ $subsection column }
"Some utilities used when parsing comments:"
{ $subsection until }
{ $subsection until-eol }
"A utility used when parsing string literals:"
{ $subsection parse-string } ;

View File

@ -197,6 +197,7 @@ vectors words ;
"/library/help/commands.factor"
"/library/kernel.facts"
"/library/vocabularies.facts"
"/library/words.facts"
"/library/collections/growable.facts"
@ -222,6 +223,7 @@ vectors words ;
"/library/syntax/see.facts"
"/doc/handbook/collections.facts"
"/doc/handbook/parser.facts"
"/doc/handbook/sequences.facts"
"/doc/handbook/syntax.facts"
"/doc/handbook/tutorial.facts"

View File

@ -224,39 +224,7 @@ call
{ "<string>" "strings" }
} dup length 3 swap [ + ] map-with [ make-primitive ] 2each
: set-stack-effect ( { vocab word effect } -- )
first3 >r lookup r> "stack-effect" set-word-prop ;
{
{ "drop" "kernel" " x -- " }
{ "2drop" "kernel" " x y -- " }
{ "3drop" "kernel" " x y z -- " }
{ "dup" "kernel" " x -- x x " }
{ "2dup" "kernel" " x y -- x y x y " }
{ "3dup" "kernel" " x y z -- x y z x y z " }
{ "rot" "kernel" " x y z -- y z x " }
{ "-rot" "kernel" " x y z -- z x y " }
{ "dupd" "kernel" " x y -- x x y " }
{ "swapd" "kernel" " x y z -- y x z " }
{ "nip" "kernel" " x y -- y " }
{ "2nip" "kernel" " x y z -- z " }
{ "tuck" "kernel" " x y -- y x y " }
{ "over" "kernel" " x y -- x y x " }
{ "pick" "kernel" " x y z -- x y z x " }
{ "swap" "kernel" " x y -- y x " }
{ ">r" "kernel" " x -- r: x " }
{ "r>" "kernel" " r: x -- x " }
{ "datastack" "kernel" " -- ds " }
{ "callstack" "kernel" " -- cs " }
{ "set-datastack" "kernel" " ds -- " }
{ "set-callstack" "kernel" " cs -- " }
{ "flush-icache" "assembler" " -- " }
} [
set-stack-effect
] each
FORGET: make-primitive
FORGET: set-stack-effect
! Okay, now we have primitives fleshed out. Bring up the generic
! word system.

View File

@ -199,3 +199,7 @@ DEFER: help
: $notes ( content -- )
"Notes" $subheading print-element ;
: $shuffle ( content -- )
drop
"Shuffle word. Re-arranges the stack according to the stack effect pattern." $description ;

View File

@ -1,15 +1,11 @@
! Copyright (C) 2004, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
IN: kernel
USING: generic kernel-internals math-internals vectors ;
USING: generic kernel-internals math-internals ;
: 2swap ( x y z t -- z t x y ) rot >r rot r> ; inline
: clear ( -- )
#! Clear the datastack. For interactive use only; invoking
#! this from a word definition will clobber any values left
#! on the data stack by the caller.
V{ } set-datastack ;
: clear V{ } set-datastack ;
GENERIC: hashcode ( obj -- n ) flushable
M: object hashcode drop 0 ;
@ -20,17 +16,11 @@ M: object = eq? ;
GENERIC: clone ( obj -- obj ) flushable
M: object clone ;
: set-boot ( quot -- )
#! Set the boot quotation.
8 setenv ;
: set-boot ( quot -- ) 8 setenv ;
: num-types ( -- n )
#! One more than the maximum value from type primitive.
20 ; inline
: num-types ( -- n ) 20 ; inline
: ? ( cond t f -- t/f )
#! Push t if cond is true, otherwise push f.
rot [ drop ] [ nip ] if ; inline
: ? ( cond t f -- t/f ) rot [ drop ] [ nip ] if ; inline
: >boolean t f ? ; inline
: and ( a b -- a&b ) f ? ; inline
@ -39,65 +29,38 @@ M: object clone ;
: cpu ( -- arch ) 7 getenv ;
: os ( -- os ) 11 getenv ;
: slip ( quot x -- x | quot: -- )
>r call r> ; inline
: slip >r call r> ; inline
: 2slip ( quot x y -- x y | quot: -- )
>r >r call r> r> ; inline
: 2slip >r >r call r> r> ; inline
: keep ( x quot -- x | quot: x -- )
over >r call r> ; inline
: keep over >r call r> ; inline
: 2keep ( x y quot -- x y | quot: x y -- )
over >r pick >r call r> r> ; inline
: 2keep over >r pick >r call r> r> ; inline
: 3keep ( x y z quot -- x y z | quot: x y z -- )
>r 3dup r> swap >r swap >r swap >r call r> r> r> ; inline
: 3keep >r 3dup r> swap >r swap >r swap >r call r> r> r> ;
inline
: 2apply ( x y quot -- | quot: x/y -- )
tuck 2slip call ; inline
: 2apply tuck 2slip call ; inline
: if* ( cond true false -- | true: cond -- | false: -- )
#! [ X ] [ Y ] if* ==> dup [ X ] [ drop Y ] if
pick [ drop call ] [ 2nip call ] if ; inline
: if* pick [ drop call ] [ 2nip call ] if ; inline
: ?if ( default cond true false -- )
#! [ X ] [ Y ] ?if ==> dup [ nip X ] [ drop Y ] if
>r >r dup [
nip r> r> drop call
] [
drop r> drop r> call
] if ; inline
: ?if >r >r [ nip r> r> drop call ] [ r> drop r> call ] if* ;
inline
: unless ( cond quot -- | quot: -- )
#! Execute a quotation only when the condition is f. The
#! condition is popped off the stack.
[ ] swap if ; inline
: unless [ ] swap if ; inline
: unless* ( cond quot -- | quot: -- )
#! If cond is f, pop it off the stack and evaluate the
#! quotation. Otherwise, leave cond on the stack.
over [ drop ] [ nip call ] if ; inline
: unless* over [ drop ] [ nip call ] if ; inline
: when ( cond quot -- | quot: -- )
#! Execute a quotation only when the condition is not f. The
#! condition is popped off the stack.
[ ] if ; inline
: when [ ] if ; inline
: when* ( cond quot -- | quot: cond -- )
#! If the condition is true, it is left on the stack, and
#! the quotation is evaluated. Otherwise, the condition is
#! popped off the stack.
dupd [ drop ] if ; inline
: when* dupd [ drop ] if ; inline
: with ( obj quot elt -- obj quot )
#! Utility word for each-with, map-with.
pick pick >r >r swap call r> r> ; inline
: keep-datastack ( quot -- )
datastack slip set-datastack drop ; inline
: keep-datastack datastack slip set-datastack drop ; inline
M: wrapper = ( obj wrapper -- ? )
M: wrapper =
over wrapper? [ [ wrapped ] 2apply = ] [ 2drop f ] if ;
GENERIC: literalize ( obj -- obj )
@ -110,16 +73,11 @@ IN: kernel-internals
! These words are unsafe. Don't use them.
: array-capacity ( a -- n ) 1 slot ; inline
: array-nth ( n a -- obj ) swap 2 fixnum+ slot ; inline
: set-array-nth ( obj n a -- ) swap 2 fixnum+ set-slot ; inline
: array-capacity 1 slot ; inline
: array-nth swap 2 fixnum+ slot ; inline
: set-array-nth swap 2 fixnum+ set-slot ; inline
: make-tuple ( class size -- tuple )
#! Internal allocation function. Do not call it directly,
#! since you can fool the runtime and corrupt memory by
#! specifying an incorrect size. Note that this word is also
#! handled specially by the compiler's type inferencer.
<tuple> [ 2 set-slot ] keep ; flushable
: make-tuple <tuple> [ 2 set-slot ] keep ; flushable
! Some runtime implementation details
: tag-mask BIN: 111 ; inline

220
library/kernel.facts Normal file
View File

@ -0,0 +1,220 @@
USING: help kernel kernel-internals ;
HELP: eq? "( obj1 obj2 -- ? )"
{ $values { "obj1" "an object" } { "obj2" "an object" } }
{ $description "Tests if two references point at the same object." } ;
HELP: drop "( x -- )" $shuffle ;
HELP: 2drop "( x y -- )" $shuffle ;
HELP: 3drop "( x y z -- )" $shuffle ;
HELP: dup "( x -- x x )" $shuffle ;
HELP: 2dup "( x y -- x y x y )" $shuffle ;
HELP: 3dup "( x y z -- x y z x y z )" $shuffle ;
HELP: rot "( x y z -- y z x )" $shuffle ;
HELP: -rot "( x y z -- z x y )" $shuffle ;
HELP: dupd "( x y -- x x y )" $shuffle ;
HELP: swapd "( x y z -- y x z )" $shuffle ;
HELP: nip "( x y -- y )" $shuffle ;
HELP: 2nip "( x y z -- z )" $shuffle ;
HELP: tuck "( x y -- y x y )" $shuffle ;
HELP: over "( x y -- x y x )" $shuffle ;
HELP: pick "( x y z -- x y z x )" $shuffle ;
HELP: swap "( x y -- y x )" $shuffle ;
HELP: 2swap "( x y z t -- z t x y )" $shuffle ;
HELP: >r "( x -- r: x )" $shuffle ;
HELP: r> "( r: x -- x )" $shuffle ;
HELP: datastack "( -- ds )"
{ $values { "ds" "a vector" } }
{ $description "Outputs the a vector containing a copy of the datastack contents right before the call to this word, with the top of the stack at the end of the vector." } ;
HELP: set-datastack "( ds -- )"
{ $values { "ds" "a vector" } }
{ $description "Replaces the datastack contents with a copy of a vector. The end of the vector becomes the top of the stack." } ;
HELP: callstack "( -- cs )"
{ $values { "cs" "a vector" } }
{ $description "Outputs the a vector containing a copy of the callstack contents right before the call to this word, with the top of the stack at the end of the vector. The call frame of the caller word is " { $emphasis "not" } " included." } ;
HELP: set-callstack "( cs -- )"
{ $values { "cs" "a vector" } }
{ $description "Replaces the callstack contents with a copy of a vector. The end of the vector becomes the top of the stack. The current quotation continues executing. The new callstack takes effect when the current quotation returns, resulting in a callframe being popped." } ;
HELP: clear "( -- )"
{ $description "Clears the datastack." } ;
HELP: hashcode "( obj -- n )"
{ $values { "obj" "an object" } { "n" "a fixnum" } }
{ $contract "Outputs the hashcode of the object. The hashcode operation must satisfy the following properties:"
{ $list
"the hashcode must be a fixnum. Returning a bignum will not cause any problems other than potential performance degradation. Returning other types will result in type errors."
{ "if two objects are equal under " { $link = } ", they must have equal hashcodes" }
"the hashcode is only permitted to change if the object is mutated in some way"
{ "the word must satisfy the " { $link POSTPONE: flushable } " contract" }
}
"If mutable objects are used as hashtable keys, they must not be mutated in such a way that their hashcode changes. Doing so will violate bucket sorting invariants and result in undefined behavior." } ;
HELP: = "( obj1 obj2 -- ? )"
{ $values { "obj1" "an object" } { "obj2" "an object" } }
{ $contract
"Tests if two objects are equal. If two objects are equal, they should the same printed representation, although the converse is not always true."
$terpri
"Two objects being " { $link = } " is an equivalence relation, which means,"
{ $list
{ $snippet "a = a" }
{ { $snippet "a = b" } " implies " { $snippet "b = a" } }
{ { $snippet "a = b" } " and " { $snippet "b = c" } " implies " { $snippet "a = c" } }
}
"The precise contract is as follows:"
{ $list
{ "methods must satisfy the " { $link POSTPONE: flushable } " contract" }
{ "if no more specific method is defined, " { $link = } " calls " { $link eq? } }
{ "two numbers are equal if they have the same numerical value after being upgraded to the highest type of the two (see " { $link "number-protocol" } ")" }
"two sequences are equal if they have the same type and elements"
"two tuples are equal if their classes and slot values are equal"
}
} ;
HELP: clone "( obj -- cloned )"
{ $values { "obj" "an object" } { "cloned" "a new object" } }
{ $contract "Outputs a new object equal to the given object. This is not guaranteed to actually copy the object; it does nothing with immutable objects, and does not copy words either. However, sequences and tuples can be cloned to obtain a shallow copy of the original."
$terpri
"Methods must satisfy the " { $link POSTPONE: flushable } " contract." } ;
HELP: set-boot "( quot -- )"
{ $values { "quot" "a quotation" } }
{ $description "Sets the initial quotation called by the runtime as the last stage of startup. The image must be saved for changes to the boot quotation to take effect. Usually the boot quotation should not be changed." } ;
HELP: num-types "( -- n )"
{ $values { "n" "a postiive integer" } }
{ $description "Outputs one more than the maximum value from the " { $link type } " primitive." } ;
HELP: ? "( cond true false -- true/false )"
{ $values { "cond" "a generalized boolean" } { "true" "an object" } { "false" "an object" } { "true/false" "one two input objects" } }
{ $description "Chooses between two values depending on the boolean value of " { $snippet "cond" } "." } ;
HELP: >boolean "( obj -- ? )"
{ $values { "obj" "a generalized boolean" } { "?" "a boolean" } }
{ $description "Convert a generalized boolean into a boolean. That is, " { $link f } " retains its value, whereas anything else becomes " { $link t } "." } ;
HELP: not "( obj -- ? )"
{ $values { "obj" "a generalized boolean" } { "?" "a boolean" } }
{ $description "For " { $link f } " outputs " { $link t } " and for anything else outputs " { $link f } "." } ;
HELP: and "( obj1 obj2 -- ? )"
{ $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "obj" "a generalized boolean" } }
{ $description "Tests if neither object is " { $link f } "." } ;
HELP: or "( obj1 obj2 -- ? )"
{ $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "obj" "a generalized boolean" } }
{ $description "Tests if at least one object is not " { $link f } "." } ;
HELP: cpu "( -- cpu )"
{ $values { "cpu" "a string" } }
{ $description
"Outputs a string descriptor of the current CPU architecture. Currently, this set of descriptors is:"
{ $code "amd64" "ppc" "x86" }
} ;
HELP: os "( -- os )"
{ $values { "os" "a string" } }
{ $description
"Outputs a string descriptor of the current operating system family. Currently, this set of descriptors is:"
{ $code "freebsd" "linux" "macosx" "win32" "unix" }
} ;
HELP: slip "( quot x -- x )"
{ $values { "quot" "a quotation" } { "x" "an object" } }
{ $description "Calls a quotation while hiding the top of the stack." } ;
HELP: 2slip "( quot x y -- x y )"
{ $values { "quot" "a quotation" } { "x" "an object" } { "y" "an object" } }
{ $description "Calls a quotation while hiding the top two stack elements." } ;
HELP: keep "( x quot -- x )"
{ $values { "quot" "a quotation with stack effect " { $snippet "( x -- )" } } { "x" "an object" } }
{ $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." } ;
HELP: 2keep "( x y quot -- x y )"
{ $values { "quot" "a quotation with stack effect " { $snippet "( x y -- )" } } { "x" "an object" } { "y" "an object" } }
{ $description "Call a quotation with two values on the stack, restoring the values when the quotation returns." } ;
HELP: 3keep "( x y z quot -- x y z )"
{ $values { "quot" "a quotation with stack effect " { $snippet "( x y -- )" } } { "x" "an object" } { "y" "an object" } { "z" "an object" } }
{ $description "Call a quotation with three values on the stack, restoring the values when the quotation returns." } ;
HELP: 2apply "( x y quot -- )"
{ $values { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } { "x" "an object" } { "y" "an object" } }
{ $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } "." } ;
HELP: if "( cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "true" "a quotation" } { "false" "a quotation" } }
{ $description "If " { $snippet "cond" } " is " { $link f } ", calls the " { $snippet "false" } " quotation. Otherwise calls the " { $snippet "true" } " quotation."
$terpri
"The " { $snippet "cond" } " value is removed from the stack before either quotation is called." } ;
HELP: when "( cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "true" "a quotation" } }
{ $description "If " { $snippet "cond" } " is not " { $link f } ", calls the " { $snippet "true" } " quotation."
$terpri
"The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
HELP: unless "( cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "false" "a quotation" } }
{ $description "If " { $snippet "cond" } " is " { $link f } ", calls the " { $snippet "false" } " quotation."
$terpri
"The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
HELP: if* "( cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } { "false" "a quotation" } }
{ $description "Alternative conditional form that preserves the " { $snippet "cond" } " value if it is true."
$terpri
"If the condition is true, it is retained on the stack before the " { $snippet "true" } " quotation is called. Otherwise, the condition is removed from the stack and the " { $snippet "false" } " quotation is called."
$terpri
"The following two lines are equivalent:"
{ $code "X [ Y ] [ Z ] if*" "X dup [ Y ] [ drop Z ] if" } } ;
HELP: when* "( cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } }
{ $description "Variant of " { $link if* } " with no false quotation."
$terpri
"The following two lines are equivalent:"
{ $code "X [ Y ] when*" "X dup [ Y ] [ drop ] if" } } ;
HELP: unless* "( cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "false" "a quotation " } }
{ $description "Variant of " { $link if* } " with no true quotation."
$terpri
"The following two lines are equivalent:"
{ $code "X [ Y ] unless*" "X dup [ ] [ drop Y ] if" } } ;
HELP: ?if "( default cond true false -- )"
{ $values { "cond" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } { "false" "a quotation with stack effect " { $snippet "( default -- )" } } }
{ $description "If the condition is " { $link f } ", the " { $snippet "false" } " quotation is called with the " { $snippet "default" } " value on the stack. Otherwise, the " { $snippet "true" } " quotation is called with the condition on the stack."
$terpri
"The following two lines are equivalent:"
{ $code "X [ Y ] [ Z ] ?if" "X dup [ nip Y ] [ drop Z ] if" } } ;
HELP: keep-datastack "( quot -- )"
{ $values { "quot" "a quotation" } }
{ $description "Calls a quotation, saving the datastack before calling it and restoring it after it returns." } ;
HELP: literalize "( obj -- wrapper )"
{ $values { "obj" "an object" } { "wrapper" "a wrapper or the original object" } }
{ $description "Turns non-self-evaluating objects (words and wrappers) into wrappers that push those objects, and is a no-op on everything else." } ;
HELP: array-capacity "( array -- n )"
{ $values { "array" "an array" } { "n" "a non-negative fixnum" } }
{ $description "Low-level array length accessor." }
{ $safety "This word is in the " { $snippet "kernel-internals" } " vocabulary because it is unsafe. It does not check types, so improper use can corrupt memory." } ;
HELP: array-nth "( n array -- elt )"
{ $values { "n" "a non-negative fixnum" } { "array" "an array" } { "elt" "an object" } }
{ $description "Low-level array element accessor." }
{ $safety "This word is in the " { $snippet "kernel-internals" } " vocabulary because it is unsafe. It does not check types or array bounds, and improper use can corrupt memory." } ;
HELP: set-array-nth "( elt n array --)"
{ $values { "elt" "an object" } { "n" "a non-negative fixnum" } { "array" "an array" } }
{ $description "Low-level array element mutator." }
{ $safety "This word is in the " { $snippet "kernel-internals" } " vocabulary because it is unsafe. It does not check types or array bounds, and improper use can corrupt memory." } ;

View File

@ -115,7 +115,7 @@ HELP: SYMBOL: "word"
HELP: \ "word"
{ $values { "word" "a word" } }
{ $description "Reads the next word from the input and appends a wrapper holding the word to the parse tree. When the evaluator encounters a wrapper, it pushes the wrapped word literally on the data stack." }
{ $examples { $example "\\ + ." "+" } } ;
{ $examples "The following two lines are equivalent:" { $code "0 \\ <vector> execute\n<vector>" } } ;
HELP: DEFER: "word"
{ $values { "word" "a new word to define" } }

View File

@ -156,9 +156,18 @@ M: block pprint-section* ( block -- )
GENERIC: pprint* ( obj -- )
: word-style ( word -- style )
[
dup presented set
parsing? [
bold font-style
] [
{ 0 0 0.3 1 } foreground
] if set
] make-hash ;
: pprint-word ( obj -- )
dup word-name [ "( unnamed )" ] unless*
swap presented associate text ;
dup word-name [ "( ? )" ] unless* swap word-style text ;
M: object pprint* ( obj -- )
"( unprintable object: " swap class word-name " )" append3