Merge branch 'master' of erg@factorcode.org:/git/factor

db4
Doug Coleman 2008-11-16 15:51:56 -06:00
commit 7ef3b503aa
131 changed files with 1485 additions and 649 deletions

View File

@ -5,7 +5,7 @@ HELP: alarm
{ $class-description "An alarm. Can be passed to " { $link cancel-alarm } "." } ; { $class-description "An alarm. Can be passed to " { $link cancel-alarm } "." } ;
HELP: add-alarm HELP: add-alarm
{ $values { "quot" quotation } { "time" timestamp } { "frequency" "a " { $link duration } " or " { $link f } } { "alarm" alarm } } { $values { "quot" quotation } { "time" timestamp } { "frequency" { $maybe duration } } { "alarm" alarm } }
{ $description "Creates and registers an alarm. If " { $snippet "frequency" } " is " { $link f } ", this will be a one-time alarm, otherwise it will fire with the given frequency. The quotation will be called from the alarm thread." } ; { $description "Creates and registers an alarm. If " { $snippet "frequency" } " is " { $link f } ", this will be a one-time alarm, otherwise it will fire with the given frequency. The quotation will be called from the alarm thread." } ;
HELP: later HELP: later

View File

@ -39,12 +39,12 @@ HELP: byte-length
{ $contract "Outputs the size of the byte array or float array data in bytes as presented to the C library interface." } ; { $contract "Outputs the size of the byte array or float array data in bytes as presented to the C library interface." } ;
HELP: c-getter HELP: c-getter
{ $values { "name" string } { "quot" "a quotation with stack effect " { $snippet "( c-ptr n -- obj )" } } } { $values { "name" string } { "quot" { $quotation "( c-ptr n -- obj )" } } }
{ $description "Outputs a quotation which reads values of this C type from a C structure." } { $description "Outputs a quotation which reads values of this C type from a C structure." }
{ $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ; { $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ;
HELP: c-setter HELP: c-setter
{ $values { "name" string } { "quot" "a quotation with stack effect " { $snippet "( obj c-ptr n -- )" } } } { $values { "name" string } { "quot" { $quotation "( obj c-ptr n -- )" } } }
{ $description "Outputs a quotation which writes values of this C type to a C structure." } { $description "Outputs a quotation which writes values of this C type to a C structure." }
{ $errors "Throws an error if the type does not exist." } ; { $errors "Throws an error if the type does not exist." } ;

View File

@ -2,7 +2,7 @@ IN: binary-search
USING: help.markup help.syntax sequences kernel math.order ; USING: help.markup help.syntax sequences kernel math.order ;
HELP: search HELP: search
{ $values { "seq" "a sorted sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- <=> )" } } { "i" "an index, or " { $link f } } { "elt" "an element, or " { $link f } } } { $values { "seq" "a sorted sequence" } { "quot" { $quotation "( elt -- <=> )" } } { "i" "an index, or " { $link f } } { "elt" "an element, or " { $link f } } }
{ $description "Performs a binary search on a sequence, calling the quotation to decide whether to end the search (" { $link +eq+ } "), search lower (" { $link +lt+ } ") or search higher (" { $link +gt+ } ")." { $description "Performs a binary search on a sequence, calling the quotation to decide whether to end the search (" { $link +eq+ } "), search lower (" { $link +lt+ } ") or search higher (" { $link +gt+ } ")."
$nl $nl
"If the sequence is non-empty, outputs the index and value of the closest match, which is either an element for which the quotation output " { $link +eq+ } ", or failing that, least element for which the quotation output " { $link +lt+ } "." "If the sequence is non-empty, outputs the index and value of the closest match, which is either an element for which the quotation output " { $link +eq+ } ", or failing that, least element for which the quotation output " { $link +lt+ } "."

View File

@ -31,7 +31,7 @@ HELP: alien>objc-types
{ objc>alien-types alien>objc-types } related-words { objc>alien-types alien>objc-types } related-words
HELP: import-objc-class HELP: import-objc-class
{ $values { "name" string } { "quot" "a quotation with stack effect " { $snippet "( -- )" } } } { $values { "name" string } { "quot" { $quotation "( -- )" } } }
{ $description "If a class named " { $snippet "name" } " is already known to the Objective C interface, does nothing. Otherwise, first calls the quotation. The quotation should make the class available to the Objective C runtime if necessary, either by loading a framework or defining it directly. After the quotation returns, this word makes the class available to Factor programs by importing methods and creating a class word the class object in the " { $vocab-link "cocoa.classes" } " vocabulary." } ; { $description "If a class named " { $snippet "name" } " is already known to the Objective C interface, does nothing. Otherwise, first calls the quotation. The quotation should make the class available to the Objective C runtime if necessary, either by loading a framework or defining it directly. After the quotation returns, this word makes the class available to Factor programs by importing methods and creating a class word the class object in the " { $vocab-link "cocoa.classes" } " vocabulary." } ;
HELP: root-class HELP: root-class

View File

@ -1,8 +1,8 @@
! Copyright (C) 2004, 2008 Slava Pestov. ! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel namespaces arrays sequences io debugger USING: accessors kernel namespaces arrays sequences io debugger
words fry continuations vocabs assocs dlists definitions math words fry continuations vocabs assocs dlists definitions
threads graphs generic combinators deques search-deques math threads graphs generic combinators deques search-deques
prettyprint io stack-checker stack-checker.state prettyprint io stack-checker stack-checker.state
stack-checker.inlining compiler.errors compiler.units stack-checker.inlining compiler.errors compiler.units
compiler.tree.builder compiler.tree.optimizer compiler.tree.builder compiler.tree.optimizer

View File

@ -1,8 +1,9 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: fry accessors namespaces assocs deques search-deques USING: fry accessors namespaces assocs deques search-deques
kernel sequences sequences.deep words sets stack-checker.branches dlists kernel sequences sequences.deep words sets
compiler.tree compiler.tree.def-use compiler.tree.combinators ; stack-checker.branches compiler.tree compiler.tree.def-use
compiler.tree.combinators ;
IN: compiler.tree.dead-code.liveness IN: compiler.tree.dead-code.liveness
SYMBOL: work-list SYMBOL: work-list

View File

@ -18,12 +18,16 @@ TUPLE: definition value node uses ;
swap >>node swap >>node
V{ } clone >>uses ; V{ } clone >>uses ;
ERROR: no-def-error value ;
: def-of ( value -- definition ) : def-of ( value -- definition )
def-use get at* [ "No def" throw ] unless ; dup def-use get at* [ nip ] [ no-def-error ] if ;
ERROR: multiple-defs-error ;
: def-value ( node value -- ) : def-value ( node value -- )
def-use get 2dup key? [ def-use get 2dup key? [
"Multiple defs" throw multiple-defs-error
] [ ] [
[ [ <definition> ] keep ] dip set-at [ [ <definition> ] keep ] dip set-at
] if ; ] if ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel assocs arrays namespaces accessors sequences deques USING: kernel assocs arrays namespaces accessors sequences deques
search-deques compiler.tree compiler.tree.combinators ; search-deques dlists compiler.tree compiler.tree.combinators ;
IN: compiler.tree.recursive IN: compiler.tree.recursive
! Collect label info ! Collect label info

View File

@ -2,27 +2,27 @@ USING: help.markup help.syntax sequences ;
IN: concurrency.combinators IN: concurrency.combinators
HELP: parallel-map HELP: parallel-map
{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- newelt )" } } { "newseq" sequence } } { $values { "seq" sequence } { "quot" { $quotation "( elt -- newelt )" } } { "newseq" sequence } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the results at the end." } { $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the results at the end." }
{ $errors "Throws an error if one of the iterations throws an error." } ; { $errors "Throws an error if one of the iterations throws an error." } ;
HELP: 2parallel-map HELP: 2parallel-map
{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- newelt )" } } { "newseq" sequence } } { $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt -- newelt )" } } { "newseq" sequence } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", collecting the results at the end." } { $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", collecting the results at the end." }
{ $errors "Throws an error if one of the iterations throws an error." } ; { $errors "Throws an error if one of the iterations throws an error." } ;
HELP: parallel-each HELP: parallel-each
{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } } { $values { "seq" sequence } { "quot" { $quotation "( elt -- )" } } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", blocking until all quotations complete." } { $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", blocking until all quotations complete." }
{ $errors "Throws an error if one of the iterations throws an error." } ; { $errors "Throws an error if one of the iterations throws an error." } ;
HELP: 2parallel-each HELP: 2parallel-each
{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } } { $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt -- )" } } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", blocking until all quotations complete." } { $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", blocking until all quotations complete." }
{ $errors "Throws an error if one of the iterations throws an error." } ; { $errors "Throws an error if one of the iterations throws an error." } ;
HELP: parallel-filter HELP: parallel-filter
{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "newseq" sequence } } { $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "newseq" sequence } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the elements for which the quotation yielded a true value." } { $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the elements for which the quotation yielded a true value." }
{ $errors "Throws an error if one of the iterations throws an error." } ; { $errors "Throws an error if one of the iterations throws an error." } ;

View File

@ -5,7 +5,7 @@ continuations help.markup help.syntax quotations ;
IN: concurrency.futures IN: concurrency.futures
HELP: future HELP: future
{ $values { "quot" "a quotation with stack effect " { $snippet "( -- value )" } } { "future" future } } { $values { "quot" { $quotation "( -- value )" } } { "future" future } }
{ $description "Creates a deferred computation." { $description "Creates a deferred computation."
$nl $nl
"The quotation begins with an empty data stack, an empty catch stack, and a name stack containing the global namespace only. This means that the only way to pass data to the quotation is to partially apply the data, for example using " { $link curry } " or " { $link compose } "." } ; "The quotation begins with an empty data stack, an empty catch stack, and a name stack containing the global namespace only. This means that the only way to pass data to the quotation is to partially apply the data, for example using " { $link curry } " or " { $link compose } "." } ;

View File

@ -14,7 +14,7 @@ HELP: <reentrant-lock>
{ $description "Creates a reentrant lock." } ; { $description "Creates a reentrant lock." } ;
HELP: with-lock-timeout HELP: with-lock-timeout
{ $values { "lock" lock } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } } { $values { "lock" lock } { "timeout" { $maybe duration } } { "quot" quotation } }
{ $description "Calls the quotation, ensuring that only one thread executes with the lock held at a time. If another thread is holding the lock, blocks until the thread releases the lock." } { $description "Calls the quotation, ensuring that only one thread executes with the lock held at a time. If another thread is holding the lock, blocks until the thread releases the lock." }
{ $errors "Throws an error if the lock could not be acquired before the timeout expires. A timeout value of " { $link f } " means the thread is willing to wait indefinitely." } ; { $errors "Throws an error if the lock could not be acquired before the timeout expires. A timeout value of " { $link f } " means the thread is willing to wait indefinitely." } ;
@ -36,7 +36,7 @@ HELP: rw-lock
{ $class-description "The class of reader/writer locks." } ; { $class-description "The class of reader/writer locks." } ;
HELP: with-read-lock-timeout HELP: with-read-lock-timeout
{ $values { "lock" lock } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } } { $values { "lock" lock } { "timeout" { $maybe duration } } { "quot" quotation } }
{ $description "Calls the quotation, ensuring that no other thread is holding a write lock at the same time. If another thread is holding a write lock, blocks until the thread releases the lock." } { $description "Calls the quotation, ensuring that no other thread is holding a write lock at the same time. If another thread is holding a write lock, blocks until the thread releases the lock." }
{ $errors "Throws an error if the lock could not be acquired before the timeout expires. A timeout value of " { $link f } " means the thread is willing to wait indefinitely." } ; { $errors "Throws an error if the lock could not be acquired before the timeout expires. A timeout value of " { $link f } " means the thread is willing to wait indefinitely." } ;
@ -45,7 +45,7 @@ HELP: with-read-lock
{ $description "Calls the quotation, ensuring that no other thread is holding a write lock at the same time. If another thread is holding a write lock, blocks until the thread releases the lock." } ; { $description "Calls the quotation, ensuring that no other thread is holding a write lock at the same time. If another thread is holding a write lock, blocks until the thread releases the lock." } ;
HELP: with-write-lock-timeout HELP: with-write-lock-timeout
{ $values { "lock" lock } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } } { $values { "lock" lock } { "timeout" { $maybe duration } } { "quot" quotation } }
{ $description "Calls the quotation, ensuring that no other thread is holding a read or write lock at the same time. If another thread is holding a read or write lock, blocks until the thread releases the lock." } { $description "Calls the quotation, ensuring that no other thread is holding a read or write lock at the same time. If another thread is holding a read or write lock, blocks until the thread releases the lock." }
{ $errors "Throws an error if the lock could not be acquired before the timeout expires. A timeout value of " { $link f } " means the thread is willing to wait indefinitely." } ; { $errors "Throws an error if the lock could not be acquired before the timeout expires. A timeout value of " { $link f } " means the thread is willing to wait indefinitely." } ;

View File

@ -1,4 +1,4 @@
USING: help.markup help.syntax kernel arrays ; USING: help.markup help.syntax kernel arrays calendar ;
IN: concurrency.mailboxes IN: concurrency.mailboxes
HELP: <mailbox> HELP: <mailbox>
@ -18,46 +18,41 @@ HELP: mailbox-put
{ $description "Put the object into the mailbox. Any threads that have a blocking get on the mailbox are resumed. Only one of those threads will successfully get the object, the rest will immediately block waiting for the next item in the mailbox." } ; { $description "Put the object into the mailbox. Any threads that have a blocking get on the mailbox are resumed. Only one of those threads will successfully get the object, the rest will immediately block waiting for the next item in the mailbox." } ;
HELP: block-unless-pred HELP: block-unless-pred
{ $values { "pred" "a quotation with stack effect " { $snippet "( X -- bool )" } } { $values { "pred" { $quotation "( obj -- ? )" } }
{ "mailbox" mailbox } { "mailbox" mailbox }
{ "timeout" "a timeout in milliseconds, or " { $link f } } { "timeout" "a " { $link duration } " or " { $link f } }
} }
{ $description "Block the thread if there are no items in the mailbox that return true when the predicate is called with the item on the stack." } ; { $description "Block the thread if there are no items in the mailbox that return true when the predicate is called with the item on the stack." } ;
HELP: block-if-empty HELP: block-if-empty
{ $values { "mailbox" mailbox } { $values { "mailbox" mailbox }
{ "timeout" "a timeout in milliseconds, or " { $link f } } { "timeout" "a " { $link duration } " or " { $link f } }
} }
{ $description "Block the thread if the mailbox is empty." } ; { $description "Block the thread if the mailbox is empty." } ;
HELP: mailbox-get HELP: mailbox-get
{ $values { "mailbox" mailbox } { $values { "mailbox" mailbox } { "obj" object } }
{ "obj" object }
}
{ $description "Get the first item put into the mailbox. If it is empty the thread blocks until an item is put into it. The thread then resumes, leaving the item on the stack." } ; { $description "Get the first item put into the mailbox. If it is empty the thread blocks until an item is put into it. The thread then resumes, leaving the item on the stack." } ;
HELP: mailbox-get-all HELP: mailbox-get-all
{ $values { "mailbox" mailbox } { $values { "mailbox" mailbox } { "array" array } }
{ "array" array }
}
{ $description "Blocks the thread if the mailbox is empty, otherwise removes all objects in the mailbox and returns an array containing the objects." } ; { $description "Blocks the thread if the mailbox is empty, otherwise removes all objects in the mailbox and returns an array containing the objects." } ;
HELP: while-mailbox-empty HELP: while-mailbox-empty
{ $values { "mailbox" mailbox } { $values { "mailbox" mailbox }
{ "quot" "a quotation with stack effect " { $snippet "( -- )" } } { "quot" { $quotation "( -- )" } }
} }
{ $description "Repeatedly call the quotation while there are no items in the mailbox." } ; { $description "Repeatedly call the quotation while there are no items in the mailbox." } ;
HELP: mailbox-get? HELP: mailbox-get?
{ $values { "mailbox" mailbox } { $values { "mailbox" mailbox }
{ "pred" "a quotation with stack effect " { $snippet "( X -- bool )" } } { "pred" { $quotation "( obj -- ? )" } }
{ "obj" object } { "obj" object }
} }
{ $description "Get the first item in the mailbox which satisfies the predicate. 'pred' will be called repeatedly for each item in the mailbox. When 'pred' returns true that item will be returned. If nothing in the mailbox satisfies the predicate then the thread will block until something does." } ; { $description "Get the first item in the mailbox which satisfies the predicate. When the predicate returns true that item will be returned. If nothing in the mailbox satisfies the predicate then the thread will block until something does." } ;
ARTICLE: "concurrency.mailboxes" "Mailboxes" ARTICLE: "concurrency.mailboxes" "Mailboxes"
"A " { $emphasis "mailbox" } " is a first-in-first-out queue where the operation of removing an element blocks if the queue is empty, instead of throwing an error. Mailboxes are implemented in the " { $vocab-link "concurrency.mailboxes" } " vocabulary." "A " { $emphasis "mailbox" } " is a first-in-first-out queue where the operation of removing an element blocks if the queue is empty. Mailboxes are implemented in the " { $vocab-link "concurrency.mailboxes" } " vocabulary."
{ $subsection mailbox } { $subsection mailbox }
{ $subsection <mailbox> } { $subsection <mailbox> }
"Removing the first element:" "Removing the first element:"

View File

@ -12,7 +12,7 @@ HELP: promise-fulfilled?
{ $description "Tests if " { $link fulfill } " has previously been called on the promise, in which case " { $link ?promise } " will return immediately without blocking." } ; { $description "Tests if " { $link fulfill } " has previously been called on the promise, in which case " { $link ?promise } " will return immediately without blocking." } ;
HELP: ?promise-timeout HELP: ?promise-timeout
{ $values { "promise" promise } { "timeout" "a " { $link duration } " or " { $link f } } { "result" object } } { $values { "promise" promise } { "timeout" { $maybe duration } } { "result" object } }
{ $description "Waits for another thread to fulfill a promise, returning immediately if the promise has already been fulfilled. A timeout of " { $link f } " indicates that the thread may block indefinitely, otherwise it will wait up to " { $snippet "timeout" } " milliseconds." } { $description "Waits for another thread to fulfill a promise, returning immediately if the promise has already been fulfilled. A timeout of " { $link f } " indicates that the thread may block indefinitely, otherwise it will wait up to " { $snippet "timeout" } " milliseconds." }
{ $errors "Throws an error if the timeout expires before the promise has been fulfilled." } ; { $errors "Throws an error if the timeout expires before the promise has been fulfilled." } ;

View File

@ -9,7 +9,7 @@ HELP: <semaphore>
{ $description "Creates a counting semaphore with the specified initial count." } ; { $description "Creates a counting semaphore with the specified initial count." } ;
HELP: acquire-timeout HELP: acquire-timeout
{ $values { "semaphore" semaphore } { "timeout" "a " { $link duration } " or " { $link f } } } { $values { "semaphore" semaphore } { "timeout" { $maybe duration } } }
{ $description "If the semaphore has a non-zero count, decrements it and returns immediately. Otherwise, if the timeout is " { $link f } ", waits indefinitely for the semaphore to be released. If the timeout is not " { $link f } ", waits a certain period of time, and if the semaphore still has not been released, throws an error." } { $description "If the semaphore has a non-zero count, decrements it and returns immediately. Otherwise, if the timeout is " { $link f } ", waits indefinitely for the semaphore to be released. If the timeout is not " { $link f } ", waits a certain period of time, and if the semaphore still has not been released, throws an error." }
{ $errors "Throws an error if the timeout expires before the semaphore is released." } ; { $errors "Throws an error if the timeout expires before the semaphore is released." } ;
@ -22,7 +22,7 @@ HELP: release
{ $description "Increments a semaphore's count. If the count was previously zero, any threads waiting on the semaphore are woken up." } ; { $description "Increments a semaphore's count. If the count was previously zero, any threads waiting on the semaphore are woken up." } ;
HELP: with-semaphore-timeout HELP: with-semaphore-timeout
{ $values { "semaphore" semaphore } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } } { $values { "semaphore" semaphore } { "timeout" { $maybe duration } } { "quot" quotation } }
{ $description "Calls the quotation with the semaphore held." } ; { $description "Calls the quotation with the semaphore held." } ;
HELP: with-semaphore HELP: with-semaphore

View File

@ -4,7 +4,7 @@ IN: deques
HELP: deque-empty? HELP: deque-empty?
{ $values { "deque" deque } { "?" "a boolean" } } { $values { "deque" deque } { "?" "a boolean" } }
{ $description "Returns true if a deque is empty." } { $contract "Returns true if a deque is empty." }
{ $notes "This operation is O(1)." } ; { $notes "This operation is O(1)." } ;
HELP: clear-deque HELP: clear-deque
@ -12,12 +12,6 @@ HELP: clear-deque
{ "deque" deque } } { "deque" deque } }
{ $description "Removes all elements from a deque." } ; { $description "Removes all elements from a deque." } ;
HELP: deque-length
{ $values
{ "deque" deque }
{ "n" integer } }
{ $description "Returns the number of elements in a deque." } ;
HELP: deque-member? HELP: deque-member?
{ $values { $values
{ "value" object } { "deque" deque } { "value" object } { "deque" deque }
@ -31,7 +25,7 @@ HELP: push-front
HELP: push-front* HELP: push-front*
{ $values { "obj" object } { "deque" deque } { "node" "a node" } } { $values { "obj" object } { "deque" deque } { "node" "a node" } }
{ $description "Push the object onto the front of the deque and return the newly created node." } { $contract "Push the object onto the front of the deque and return the newly created node." }
{ $notes "This operation is O(1)." } ; { $notes "This operation is O(1)." } ;
HELP: push-back HELP: push-back
@ -41,7 +35,7 @@ HELP: push-back
HELP: push-back* HELP: push-back*
{ $values { "obj" object } { "deque" deque } { "node" "a node" } } { $values { "obj" object } { "deque" deque } { "node" "a node" } }
{ $description "Push the object onto the back of the deque and return the newly created node." } { $contract "Push the object onto the back of the deque and return the newly created node." }
{ $notes "This operation is O(1)." } ; { $notes "This operation is O(1)." } ;
HELP: push-all-back HELP: push-all-back
@ -56,7 +50,7 @@ HELP: push-all-front
HELP: peek-front HELP: peek-front
{ $values { "deque" deque } { "obj" object } } { $values { "deque" deque } { "obj" object } }
{ $description "Returns the object at the front of the deque." } ; { $contract "Returns the object at the front of the deque." } ;
HELP: pop-front HELP: pop-front
{ $values { "deque" deque } { "obj" object } } { $values { "deque" deque } { "obj" object } }
@ -65,12 +59,12 @@ HELP: pop-front
HELP: pop-front* HELP: pop-front*
{ $values { "deque" deque } } { $values { "deque" deque } }
{ $description "Pop the object off the front of the deque." } { $contract "Pop the object off the front of the deque." }
{ $notes "This operation is O(1)." } ; { $notes "This operation is O(1)." } ;
HELP: peek-back HELP: peek-back
{ $values { "deque" deque } { "obj" object } } { $values { "deque" deque } { "obj" object } }
{ $description "Returns the object at the back of the deque." } ; { $contract "Returns the object at the back of the deque." } ;
HELP: pop-back HELP: pop-back
{ $values { "deque" deque } { "obj" object } } { $values { "deque" deque } { "obj" object } }
@ -79,13 +73,13 @@ HELP: pop-back
HELP: pop-back* HELP: pop-back*
{ $values { "deque" deque } } { $values { "deque" deque } }
{ $description "Pop the object off the back of the deque." } { $contract "Pop the object off the back of the deque." }
{ $notes "This operation is O(1)." } ; { $notes "This operation is O(1)." } ;
HELP: delete-node HELP: delete-node
{ $values { $values
{ "node" object } { "deque" deque } } { "node" object } { "deque" deque } }
{ $description "Deletes the node from the deque." } ; { $contract "Deletes the node from the deque." } ;
HELP: deque HELP: deque
{ $description "A data structure that has constant-time insertion and removal of elements at both ends." } ; { $description "A data structure that has constant-time insertion and removal of elements at both ends." } ;
@ -111,7 +105,7 @@ $nl
"Querying the deque:" "Querying the deque:"
{ $subsection peek-front } { $subsection peek-front }
{ $subsection peek-back } { $subsection peek-back }
{ $subsection deque-length } { $subsection deque-empty? }
{ $subsection deque-member? } { $subsection deque-member? }
"Adding and removing elements:" "Adding and removing elements:"
{ $subsection push-front* } { $subsection push-front* }
@ -123,7 +117,6 @@ $nl
{ $subsection delete-node } { $subsection delete-node }
{ $subsection node-value } { $subsection node-value }
"Utility operations built in terms of the above:" "Utility operations built in terms of the above:"
{ $subsection deque-empty? }
{ $subsection push-front } { $subsection push-front }
{ $subsection push-all-front } { $subsection push-all-front }
{ $subsection push-back } { $subsection push-back }

View File

@ -10,13 +10,10 @@ GENERIC: peek-back ( deque -- obj )
GENERIC: pop-front* ( deque -- ) GENERIC: pop-front* ( deque -- )
GENERIC: pop-back* ( deque -- ) GENERIC: pop-back* ( deque -- )
GENERIC: delete-node ( node deque -- ) GENERIC: delete-node ( node deque -- )
GENERIC: deque-length ( deque -- n )
GENERIC: deque-member? ( value deque -- ? ) GENERIC: deque-member? ( value deque -- ? )
GENERIC: clear-deque ( deque -- ) GENERIC: clear-deque ( deque -- )
GENERIC: node-value ( node -- value ) GENERIC: node-value ( node -- value )
GENERIC: deque-empty? ( deque -- ? )
: deque-empty? ( deque -- ? )
deque-length zero? ;
: push-front ( obj deque -- ) : push-front ( obj deque -- )
push-front* drop ; push-front* drop ;

View File

@ -1,5 +1,5 @@
USING: help.markup help.syntax kernel quotations USING: help.markup help.syntax kernel quotations
deques ; deques search-deques hashtables ;
IN: dlists IN: dlists
ARTICLE: "dlists" "Double-linked lists" ARTICLE: "dlists" "Double-linked lists"
@ -18,10 +18,20 @@ $nl
{ $subsection dlist-contains? } { $subsection dlist-contains? }
"Deleting a node matching a predicate:" "Deleting a node matching a predicate:"
{ $subsection delete-node-if* } { $subsection delete-node-if* }
{ $subsection delete-node-if } ; { $subsection delete-node-if }
"Search deque implementation:"
{ $subsection <hashed-dlist> } ;
ABOUT: "dlists" ABOUT: "dlists"
HELP: <dlist>
{ $values { "list" dlist } }
{ $description "Creates a new double-linked list." } ;
HELP: <hashed-dlist>
{ $values { "search-deque" search-deque } }
{ $description "Creates a new " { $link search-deque } " backed by a " { $link dlist } ", with a " { $link hashtable } " for fast membership tests." } ;
HELP: dlist-find HELP: dlist-find
{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } } { $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
{ $description "Applies the quotation to each element of the " { $link dlist } " in turn, until it outputs a true value or the end of the " { $link dlist } " is reached. Outputs either the object it found or " { $link f } ", and a boolean which is true if an object is found." } { $description "Applies the quotation to each element of the " { $link dlist } " in turn, until it outputs a true value or the end of the " { $link dlist } " is reached. Outputs either the object it found or " { $link f } ", and a boolean which is true if an object is found." }

View File

@ -5,7 +5,7 @@ IN: dlists.tests
[ t ] [ <dlist> deque-empty? ] unit-test [ t ] [ <dlist> deque-empty? ] unit-test
[ T{ dlist f T{ dlist-node f 1 f f } T{ dlist-node f 1 f f } 1 } ] [ T{ dlist f T{ dlist-node f 1 f f } T{ dlist-node f 1 f f } } ]
[ <dlist> 1 over push-front ] unit-test [ <dlist> 1 over push-front ] unit-test
! Make sure empty lists are empty ! Make sure empty lists are empty
@ -17,10 +17,10 @@ IN: dlists.tests
[ 1 ] [ <dlist> 1 over push-front pop-back ] unit-test [ 1 ] [ <dlist> 1 over push-front pop-back ] unit-test
[ 1 ] [ <dlist> 1 over push-back pop-front ] unit-test [ 1 ] [ <dlist> 1 over push-back pop-front ] unit-test
[ 1 ] [ <dlist> 1 over push-back pop-back ] unit-test [ 1 ] [ <dlist> 1 over push-back pop-back ] unit-test
[ T{ dlist f f f 0 } ] [ <dlist> 1 over push-front dup pop-front* ] unit-test [ T{ dlist f f f } ] [ <dlist> 1 over push-front dup pop-front* ] unit-test
[ T{ dlist f f f 0 } ] [ <dlist> 1 over push-front dup pop-back* ] unit-test [ T{ dlist f f f } ] [ <dlist> 1 over push-front dup pop-back* ] unit-test
[ T{ dlist f f f 0 } ] [ <dlist> 1 over push-back dup pop-front* ] unit-test [ T{ dlist f f f } ] [ <dlist> 1 over push-back dup pop-front* ] unit-test
[ T{ dlist f f f 0 } ] [ <dlist> 1 over push-back dup pop-back* ] unit-test [ T{ dlist f f f } ] [ <dlist> 1 over push-back dup pop-back* ] unit-test
! Test the prev,next links for two nodes ! Test the prev,next links for two nodes
[ f ] [ [ f ] [
@ -52,15 +52,6 @@ IN: dlists.tests
[ 1 ] [ <dlist> 1 over push-back [ 1 = ] delete-node-if ] unit-test [ 1 ] [ <dlist> 1 over push-back [ 1 = ] delete-node-if ] unit-test
[ t ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop deque-empty? ] unit-test [ t ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop deque-empty? ] unit-test
[ t ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop deque-empty? ] unit-test [ t ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop deque-empty? ] unit-test
[ 0 ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop deque-length ] unit-test
[ 1 ] [ <dlist> 1 over push-back 2 over push-back dup [ 1 = ] delete-node-if drop deque-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back dup [ 1 = ] delete-node-if drop deque-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back dup [ 2 = ] delete-node-if drop deque-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back dup [ 3 = ] delete-node-if drop deque-length ] unit-test
[ 0 ] [ <dlist> deque-length ] unit-test
[ 1 ] [ <dlist> 1 over push-front deque-length ] unit-test
[ 0 ] [ <dlist> 1 over push-front dup pop-front* deque-length ] unit-test
[ t ] [ <dlist> 4 over push-back 5 over push-back [ obj>> 4 = ] dlist-find-node drop class dlist-node = ] unit-test [ t ] [ <dlist> 4 over push-back 5 over push-back [ obj>> 4 = ] dlist-find-node drop class dlist-node = ] unit-test
[ t ] [ <dlist> 4 over push-back 5 over push-back [ obj>> 5 = ] dlist-find-node drop class dlist-node = ] unit-test [ t ] [ <dlist> 4 over push-back 5 over push-back [ obj>> 5 = ] dlist-find-node drop class dlist-node = ] unit-test

View File

@ -2,51 +2,57 @@
! Slava Pestov. ! Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: combinators kernel math sequences accessors deques USING: combinators kernel math sequences accessors deques
summary ; search-deques summary hashtables ;
IN: dlists IN: dlists
TUPLE: dlist front back length ;
: <dlist> ( -- obj )
dlist new
0 >>length ;
M: dlist deque-length length>> ;
<PRIVATE <PRIVATE
TUPLE: dlist-node obj prev next ; MIXIN: ?dlist-node
INSTANCE: f ?dlist-node
TUPLE: dlist-node obj { prev ?dlist-node } { next ?dlist-node } ;
INSTANCE: dlist-node ?dlist-node
C: <dlist-node> dlist-node C: <dlist-node> dlist-node
PRIVATE>
TUPLE: dlist
{ front ?dlist-node }
{ back ?dlist-node } ;
: <dlist> ( -- list )
dlist new ; inline
: <hashed-dlist> ( -- search-deque )
20 <hashtable> <dlist> <search-deque> ;
M: dlist deque-empty? front>> not ;
M: dlist-node node-value obj>> ; M: dlist-node node-value obj>> ;
: inc-length ( dlist -- )
[ 1+ ] change-length drop ; inline
: dec-length ( dlist -- )
[ 1- ] change-length drop ; inline
: set-prev-when ( dlist-node dlist-node/f -- ) : set-prev-when ( dlist-node dlist-node/f -- )
[ (>>prev) ] [ drop ] if* ; [ (>>prev) ] [ drop ] if* ; inline
: set-next-when ( dlist-node dlist-node/f -- ) : set-next-when ( dlist-node dlist-node/f -- )
[ (>>next) ] [ drop ] if* ; [ (>>next) ] [ drop ] if* ; inline
: set-next-prev ( dlist-node -- ) : set-next-prev ( dlist-node -- )
dup next>> set-prev-when ; dup next>> set-prev-when ; inline
: normalize-front ( dlist -- ) : normalize-front ( dlist -- )
dup back>> [ f >>front ] unless drop ; dup back>> [ f >>front ] unless drop ; inline
: normalize-back ( dlist -- ) : normalize-back ( dlist -- )
dup front>> [ f >>back ] unless drop ; dup front>> [ f >>back ] unless drop ; inline
: set-back-to-front ( dlist -- ) : set-back-to-front ( dlist -- )
dup back>> [ dup front>> >>back ] unless drop ; dup back>> [ dup front>> >>back ] unless drop ; inline
: set-front-to-back ( dlist -- ) : set-front-to-back ( dlist -- )
dup front>> [ dup back>> >>front ] unless drop ; dup front>> [ dup back>> >>front ] unless drop ; inline
: (dlist-find-node) ( dlist-node quot: ( node -- ? ) -- node/f ? ) : (dlist-find-node) ( dlist-node quot: ( node -- ? ) -- node/f ? )
over [ over [
@ -62,22 +68,20 @@ M: dlist-node node-value obj>> ;
: unlink-node ( dlist-node -- ) : unlink-node ( dlist-node -- )
dup prev>> over next>> set-prev-when dup prev>> over next>> set-prev-when
dup next>> swap prev>> set-next-when ; dup next>> swap prev>> set-next-when ; inline
PRIVATE> PRIVATE>
M: dlist push-front* ( obj dlist -- dlist-node ) M: dlist push-front* ( obj dlist -- dlist-node )
[ front>> f swap <dlist-node> dup dup set-next-prev ] keep [ front>> f swap <dlist-node> dup dup set-next-prev ] keep
[ (>>front) ] keep [ (>>front) ] keep
[ set-back-to-front ] keep set-back-to-front ;
inc-length ;
M: dlist push-back* ( obj dlist -- dlist-node ) M: dlist push-back* ( obj dlist -- dlist-node )
[ back>> f <dlist-node> ] keep [ back>> f <dlist-node> ] keep
[ back>> set-next-when ] 2keep [ back>> set-next-when ] 2keep
[ (>>back) ] 2keep [ (>>back) ] 2keep
[ set-front-to-back ] keep set-front-to-back ;
inc-length ;
ERROR: empty-dlist ; ERROR: empty-dlist ;
@ -88,31 +92,27 @@ M: dlist peek-front ( dlist -- obj )
front>> [ obj>> ] [ empty-dlist ] if* ; front>> [ obj>> ] [ empty-dlist ] if* ;
M: dlist pop-front* ( dlist -- ) M: dlist pop-front* ( dlist -- )
dup front>> [ empty-dlist ] unless
[ [
dup front>> dup front>> [ empty-dlist ] unless*
dup next>> dup next>>
f rot (>>next) f rot (>>next)
f over set-prev-when f over set-prev-when
swap (>>front) swap (>>front)
] keep ] keep
[ normalize-back ] keep normalize-back ;
dec-length ;
M: dlist peek-back ( dlist -- obj ) M: dlist peek-back ( dlist -- obj )
back>> [ obj>> ] [ empty-dlist ] if* ; back>> [ obj>> ] [ empty-dlist ] if* ;
M: dlist pop-back* ( dlist -- ) M: dlist pop-back* ( dlist -- )
dup back>> [ empty-dlist ] unless
[ [
dup back>> dup back>> [ empty-dlist ] unless*
dup prev>> dup prev>>
f rot (>>prev) f rot (>>prev)
f over set-next-when f over set-next-when
swap (>>back) swap (>>back)
] keep ] keep
[ normalize-front ] keep normalize-front ;
dec-length ;
: dlist-find ( dlist quot -- obj/f ? ) : dlist-find ( dlist quot -- obj/f ? )
[ obj>> ] prepose [ obj>> ] prepose
@ -128,7 +128,7 @@ M: dlist delete-node ( dlist-node dlist -- )
{ {
{ [ 2dup front>> eq? ] [ nip pop-front* ] } { [ 2dup front>> eq? ] [ nip pop-front* ] }
{ [ 2dup back>> eq? ] [ nip pop-back* ] } { [ 2dup back>> eq? ] [ nip pop-back* ] }
[ dec-length unlink-node ] [ drop unlink-node ]
} cond ; } cond ;
: delete-node-if* ( dlist quot -- obj/f ? ) : delete-node-if* ( dlist quot -- obj/f ? )
@ -148,7 +148,6 @@ M: dlist delete-node ( dlist-node dlist -- )
M: dlist clear-deque ( dlist -- ) M: dlist clear-deque ( dlist -- )
f >>front f >>front
f >>back f >>back
0 >>length
drop ; drop ;
: dlist-each ( dlist quot -- ) : dlist-each ( dlist quot -- )

View File

@ -42,7 +42,7 @@ HELP: doc-lines
{ $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ; { $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;
HELP: each-line HELP: each-line
{ $values { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "quot" "a quotation with stack effect " { $snippet "( string -- )" } } } { $values { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "quot" { $quotation "( string -- )" } } }
{ $description "Applies the quotation to each line in the range." } { $description "Applies the quotation to each line in the range." }
{ $notes "The range is created by calling " { $link <slice> } "." } { $notes "The range is created by calling " { $link <slice> } "." }
{ $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ; { $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;

View File

@ -0,0 +1,193 @@
USING: assocs classes help.markup help.syntax kernel
quotations strings words furnace.auth.providers.db
checksums.sha2 furnace.auth.providers math byte-arrays
http multiline ;
IN: furnace.auth
HELP: <protected>
{ $values
{ "responder" "a responder" }
{ "protected" "a new responder" }
}
{ $description "Wraps a responder in a protected responder. Access to the wrapped responder will be conditional upon the client authenticating with the current authentication realm." } ;
HELP: >>encoded-password
{ $values { "user" user } { "string" string } }
{ $description "Sets the user's password by combining it with a random salt and encoding it with the current authentication realm's checksum." } ;
HELP: capabilities
{ $var-description "Global variable holding all defined capabilities. New capabilities may be defined with " { $link define-capability } "." } ;
HELP: check-login
{ $values { "password" string } { "username" string } { "user/f" { $maybe user } } }
{ $description "Checks a username/password pair with the current authentication realm. Outputs a user if authentication succeeded, otherwise outputs " { $link f } "." } ;
HELP: define-capability
{ $values { "word" symbol } }
{ $description "Defines a new capability by adding it to the " { $link capabilities } " global variable." } ;
HELP: encode-password
{ $values
{ "string" string } { "salt" integer }
{ "bytes" byte-array }
}
{ $description "Encodes a password with the current authentication realm's checksum." } ;
HELP: have-capabilities?
{ $values
{ "capabilities" "a sequence of capabilities" }
{ "?" "a boolean" }
}
{ $description "Tests if the currently logged-in user possesses the given capabilities." } ;
HELP: logged-in-user
{ $var-description "Holds the currently logged-in user." } ;
HELP: login-required
{ $values
{ "description" string } { "capabilities" "a sequence of capabilities" }
}
{ $description "Redirects the client to a login page." } ;
HELP: login-required*
{ $values
{ "description" string } { "capabilities" "a sequence of capabilities" } { "realm" "an authenticaiton realm" }
{ "response" response }
}
{ $contract "Constructs an HTTP response for redirecting the client to a login page." } ;
HELP: protected
{ $class-description "The class of protected responders. See " { $link "furnace.auth.protected" } " for a description of usage and slots." } ;
HELP: realm
{ $class-description "The class of authentication realms. See " { $link "furnace.auth.realms" } " for details." } ;
HELP: uchange
{ $values { "key" symbol } { "quot" { $quotation "( old -- new )" } } }
{ $description "Applies the quotation to the old value of the user profile variable, and assigns the resulting value back to the variable." } ;
HELP: uget
{ $values { "key" symbol } { "value" object } }
{ $description "Outputs the value of a user profile variable." } ;
HELP: uset
{ $values { "value" object } { "key" symbol } }
{ $description "Sets the value of a user profile variable." } ;
HELP: username
{ $values { "string/f" { $maybe string } }
}
{ $description "Outputs the currently logged-in username, or " { $link f } " if no user is logged in." } ;
HELP: users
{ $values { "provider" "an authentication provider" } }
{ $description "Outputs the current authentication provider." } ;
ARTICLE: "furnace.auth.capabilities" "Authentication capabilities"
"Every user in the authentication framework has a set of associated capabilities."
$nl
"Defining new capabilities:"
{ $subsection define-capability }
"Capabilities are stored in a global variable:"
{ $subsection capabilities }
"Protected resources can be restricted to users possessing certain capabilities only by storing a sequence of capabilities in the " { $slot "capabilities" } " slot of a " { $link protected } " instance." ;
ARTICLE: "furnace.auth.protected" "Protected resources"
"To restrict access to authenticated clients only, wrap a responder in a protected responder."
{ $subsection protected }
{ $subsection <protected> }
"Protected responders have the following two slots which may be set:"
{ $table
{ { $slot "description" } "A string identifying the protected resource for user interface purposes" }
{ { $slot "capabilities" } { "A sequence of capabilities; see " { $link "furnace.auth.capabilities" } } }
} ;
ARTICLE: "furnace.auth.realm-config" "Authentication realm configuration"
"Instances of subclasses of " { $link realm } " have the following slots which may be set:"
{ $table
{ { $slot "name" } "A string identifying the realm for user interface purposes" }
{ { $slot "users" } { "An authentication provider (see " { $link "furnace.auth.providers" } ". By default, the " { $link users-in-db } " provider is used." } }
{ { $slot "checksum" } { "An implementation of the checksum protocol used for verifying passwords (see " { $link "checksums" } "). The " { $link sha-256 } " checksum is used by default." } }
{ { $slot "users" } { "An authentication provider (see " { $link "furnace.auth.providers" } } }
{ { $slot "secure" } { "A boolean, that when set to a true value, forces the client to access the authentication realm via HTTPS. An attempt to access the realm via HTTP results in a redirect to the corresponding HTTPS URL. On by default." } }
} ;
ARTICLE: "furnace.auth.providers" "Authentication providers"
"The " { $vocab-link "furnace.auth" } " framework looks up users using an authentication provider. Different authentication providers can be swapped in to implement various authentication strategies."
$nl
"Each authentication realm has a provider stored in the " { $slot "users" } " slot. The default provider is " { $link users-in-db } "."
{ $subsection "furnace.auth.providers.protocol" }
{ $subsection "furnace.auth.providers.null" }
{ $subsection "furnace.auth.providers.assoc" }
{ $subsection "furnace.auth.providers.db" } ;
ARTICLE: "furnace.auth.features" "Optional authentication features"
"Vocabularies having names prefixed by " { $code "furnace.auth.features" } " implement optional features which can be enabled by calling special words. These words define new actions on an authentication realm."
{ $subsection "furnace.auth.features.deactivate-user" }
{ $subsection "furnace.auth.features.edit-profile" }
{ $subsection "furnace.auth.features.recover-password" }
{ $subsection "furnace.auth.features.registration" } ;
ARTICLE: "furnace.auth.realms" "Authentication realms"
"The superclass of authentication realms:"
{ $subsection realm }
"There are two concrete implementations:"
{ $subsection "furnace.auth.basic" }
{ $subsection "furnace.auth.login" }
"Authentication realms need to be configured after construction."
{ $subsection "furnace.auth.realm-config" } ;
ARTICLE: "furnace.auth.users" "User profiles"
"A responder wrapped in an authentication realm may access the currently logged-in user,"
{ $subsection logged-in-user }
"as well as the logged-in username:"
{ $subsection username }
"Values can also be stored in user profile variables:"
{ $subsection uget }
{ $subsection uset }
{ $subsection uchange }
"User profile variables have the same restrictions on their values as session variables; see " { $link "furnace.sessions.serialize" } " for a discussion." ;
ARTICLE: "furnace.auth.example" "Furnace authentication example"
"The " { $vocab-link "webapps.todo" } " vocabulary wraps all of its responders in a protected responder. The " { $slot "description" } " slot is set so that the login page contains the message ``You must log in to view your todo list'':"
{ $code
<" <protected>
"view your todo list" >>description">
}
"The " { $vocab-link "webapps.wiki" } " vocabulary defines a mix of protected and unprotected actions. One example of a protected action is that for deleting wiki pages, an action normally reserved for administrators. This action is protected with the following code:"
{ $code
<" <protected>
"delete wiki articles" >>description
{ can-delete-wiki-articles? } >>capabilities">
}
"The " { $vocab-link "websites.concatenative" } " vocabulary wraps all of its responders, including the wiki, in a login authentication realm:"
{ $code
<" : <login-config> ( responder -- responder' )
"Factor website" <login-realm>
"Factor website" >>name
allow-registration
allow-password-recovery
allow-edit-profile
allow-deactivation ;">
} ;
ARTICLE: "furnace.auth" "Furnace authentication"
"The " { $vocab-link "furnace.auth" } " vocabulary implements a pluggable authentication framework."
$nl
"Usernames and passwords are verified using an " { $emphasis "authentication provider" } "."
{ $subsection "furnace.auth.providers" }
"Users have capabilities assigned to them."
{ $subsection "furnace.auth.capabilities" }
"An " { $emphasis "authentication realm" } " is a responder which manages access to protected resources."
{ $subsection "furnace.auth.realms" }
"Actions contained inside an authentication realm can be protected by wrapping them with a responder."
{ $subsection "furnace.auth.protected" }
"Actions contained inside an authentication realm can access the currently logged-in user profile."
{ $subsection "furnace.auth.users" }
"Authentication realms can be adorned with additional functionality."
{ $subsection "furnace.auth.features" }
"An administration tool."
{ $subsection "furnace.auth.user-admin" }
"A concrete example."
{ $subsection "furnace.auth.example" } ;
ABOUT: "furnace.auth"

View File

@ -0,0 +1,16 @@
USING: help.markup help.syntax ;
IN: furnace.auth.basic
HELP: <basic-auth-realm>
{ $values { "responder" "a responder" } { "name" "an authentication realm name" } { "realm" basic-auth-realm } }
{ $description "Wraps a responder in a basic authentication realm. The realm must be configured before use; see " { $link "furnace.auth.realm-config" } "." } ;
HELP: basic-auth-realm
{ $class-description "The basic authentication realm class. Slots are described in " { $link "furnace.auth.realm-config" } "." } ;
ARTICLE: "furnace.auth.basic" "Basic authentication"
"The " { $vocab-link "furnace.auth.basic" } " vocabulary implements HTTP basic authentication."
{ $subsection basic-auth-realm }
{ $subsection <basic-auth-realm> } ;
ABOUT: "furnace.auth.basic"

View File

@ -0,0 +1,26 @@
USING: help.markup help.syntax kernel ;
IN: furnace.auth.features.deactivate-user
HELP: allow-deactivation
{ $values { "realm" "an authentication realm" } }
{ $description "Adds a " { $snippet "deactivate-user" } " action to an authentication realm." } ;
HELP: allow-deactivation?
{ $values { "?" "a boolean" } }
{ $description "Outputs true if the current authentication realm allows user profile deactivation." } ;
ARTICLE: "furnace.auth.features.deactivate-user" "User profile deactivation"
"The " { $vocab-link "furnace.auth.features.deactivate-user" } " vocabulary implements an authentication feature for user profile deactivation, allowing users to voluntarily deactivate their account."
$nl
"To enable this feature, call the following word on an authentication realm:"
{ $subsection allow-deactivation }
"To check if deactivation is enabled:"
{ $subsection allow-deactivation? }
"This feature adds a " { $snippet "deactivate-user" } " action to the realm, and a link to this action can be inserted in Chloe templates using the following XML snippet:"
{ $code
"<t:if t:code=\"furnace.auth.features.deactivate-user:allow-deactivation?\">"
" <t:button t:action=\"$realm/deactivate-user\">Deactivate user</t:button>"
"</t:if>"
} ;
ABOUT: "furnace.auth.features.deactivate-user"

View File

@ -0,0 +1,24 @@
USING: help.markup help.syntax kernel ;
IN: furnace.auth.features.edit-profile
HELP: allow-edit-profile
{ $values { "realm" "an authentication realm" } }
{ $description "Adds an " { $snippet "edit-profile" } " action to an authentication realm." } ;
HELP: allow-edit-profile?
{ $values { "?" "a boolean" } }
{ $description "Outputs true if the current authentication realm allows user profile editing." } ;
ARTICLE: "furnace.auth.features.edit-profile" "User profile editing"
"The " { $vocab-link "furnace.auth.features.edit-profile" } " vocabulary implements an authentication feature for user profile editing, allowing users to change some details of their account."
$nl
"To enable this feature, call the following word on an authentication realm:"
{ $subsection allow-edit-profile }
"To check if profile editing is enabled:"
{ $subsection allow-edit-profile? }
"This feature adds an " { $snippet "edit-profile" } " action to the realm, and a link to this action can be inserted in Chloe templates using the following XML snippet:"
{ $code
"<t:if t:code=\"furnace.auth.features.edit-profile:allow-edit-profile?\">"
" <t:button t:action=\"$realm/edit-profile\">Edit profile</t:button>"
"</t:if>"
} ;

View File

@ -58,7 +58,7 @@ IN: furnace.auth.features.edit-profile
<protected> <protected>
"edit your profile" >>description ; "edit your profile" >>description ;
: allow-edit-profile ( login -- login ) : allow-edit-profile ( realm -- realm )
<edit-profile-action> <auth-boilerplate> "edit-profile" add-responder ; <edit-profile-action> <auth-boilerplate> "edit-profile" add-responder ;
: allow-edit-profile? ( -- ? ) : allow-edit-profile? ( -- ? )

View File

@ -0,0 +1,34 @@
USING: help.markup help.syntax kernel strings urls ;
IN: furnace.auth.features.recover-password
HELP: allow-password-recovery
{ $values { "realm" "an authentication realm" } }
{ $description "Adds a " { $snippet "recover-password" } " action to an authentication realm." } ;
HELP: allow-password-recovery?
{ $values { "?" "a boolean" } }
{ $description "Outputs true if the current authentication realm allows user password recovery." } ;
HELP: lost-password-from
{ $var-description "A variable with the source e-mail address of password recovery e-mails." } ;
ARTICLE: "furnace.auth.features.recover-password" "User password recovery"
"The " { $vocab-link "furnace.auth.features.recover-password" }
" vocabulary implements an authentication feature for user password recovery, allowing users to get a new password e-mailed to them in the event they forget their current one."
$nl
"To enable this feature, first call the following word on an authentication realm,"
{ $subsection allow-password-recovery }
"Then set a global configuration variable:"
{ $subsection lost-password-from }
"In addition, the " { $link "smtp" } " may need to be configured as well."
$nl
"To check if password recovery is enabled:"
{ $subsection allow-password-recovery? }
"This feature adds a " { $snippet "recover-password" } " action to the realm, and a link to this action can be inserted in Chloe templates using the following XML snippet:"
{ $code
"<t:if t:code=\"furnace.auth.features.recover-password:allow-password-recovery?\">"
" <t:button t:action=\"$realm/recover-password\">Recover password</t:button>"
"</t:if>"
} ;
ABOUT: "furnace.auth.features.recover-password"

View File

@ -110,7 +110,7 @@ SYMBOL: lost-password-from
<page-action> <page-action>
{ realm "features/recover-password/recover-4" } >>template ; { realm "features/recover-password/recover-4" } >>template ;
: allow-password-recovery ( login -- login ) : allow-password-recovery ( realm -- realm )
<recover-action-1> <auth-boilerplate> <recover-action-1> <auth-boilerplate>
"recover-password" add-responder "recover-password" add-responder
<recover-action-2> <auth-boilerplate> <recover-action-2> <auth-boilerplate>

View File

@ -0,0 +1,24 @@
USING: help.markup help.syntax kernel ;
IN: furnace.auth.features.registration
HELP: allow-registration
{ $values { "realm" "an authentication realm" } }
{ $description "Adds a " { $snippet "registration" } " action to an authentication realm." } ;
HELP: allow-registration?
{ $values { "?" "a boolean" } }
{ $description "Outputs true if the current authentication realm allows user registration." } ;
ARTICLE: "furnace.auth.features.registration" "User registration"
"The " { $vocab-link "furnace.auth.features.registration" } " vocabulary implements an authentication feature for user registration, allowing new users to create accounts."
$nl
"To enable this feature, call the following word on an authentication realm:"
{ $subsection allow-registration }
"To check if user registration is enabled:"
{ $subsection allow-registration? }
"This feature adds a " { $snippet "register" } " action to the realm. A link to this action is inserted on the login page if the " { $vocab-link "furnace.auth.login" } " authentication realm is used. Links to this action can be inserted from other pages using the following Chloe XML snippet:"
{ $code
"<t:if t:code=\"furnace.auth.features.registration:allow-registration?\">"
" <t:button t:action=\"$realm/register\">Register</t:button>"
"</t:if>"
} ;

View File

@ -38,7 +38,7 @@ IN: furnace.auth.features.registration
<auth-boilerplate> <auth-boilerplate>
<secure-realm-only> ; <secure-realm-only> ;
: allow-registration ( login -- login ) : allow-registration ( realm -- realm )
<register-action> "register" add-responder ; <register-action> "register" add-responder ;
: allow-registration? ( -- ? ) : allow-registration? ( -- ? )

View File

@ -0,0 +1,23 @@
USING: help.markup help.syntax kernel strings ;
IN: furnace.auth.login
HELP: <login-realm>
{ $values
{ "responder" "a responder" } { "name" string }
{ "realm" "a new responder" }
}
{ $description "Wraps a responder in a new login realm with the given name. The realm must be configured before use; see " { $link "furnace.auth.realm-config" } "." } ;
HELP: login-realm
{ $class-description "The login realm class. Slots are described in " { $link "furnace.auth.realm-config" } "." } ;
ARTICLE: "furnace.auth.login" "Login authentication"
"The " { $vocab-link "furnace.auth.login" } " vocabulary implements an authentication realm which displays a login page with a username and password field."
{ $subsection login-realm }
{ $subsection <login-realm> }
"The " { $snippet "logout" } " action logs the user out of the realm, and a link to this action can be inserted in Chloe templates using the following XML snippet:"
{ $code
"<t:button t:action=\"$login-realm/logout\">Logout</t:button>"
} ;
ABOUT: "furnace.auth.login"

View File

@ -58,9 +58,13 @@ M: login-realm modify-form ( responder -- )
permit-id get [ delete-permit ] when* permit-id get [ delete-permit ] when*
URL" $realm" end-aside ; URL" $realm" end-aside ;
<PRIVATE
SYMBOL: description SYMBOL: description
SYMBOL: capabilities SYMBOL: capabilities
PRIVATE>
: flashed-variables { description capabilities } ; : flashed-variables { description capabilities } ;
: login-failed ( -- * ) : login-failed ( -- * )
@ -107,7 +111,7 @@ M: login-realm login-required* ( description capabilities login -- response )
M: login-realm user-registered ( user realm -- ) M: login-realm user-registered ( user realm -- )
drop successful-login ; drop successful-login ;
: <login-realm> ( responder name -- auth ) : <login-realm> ( responder name -- realm )
login-realm new-realm login-realm new-realm
<login-action> "login" add-responder <login-action> "login" add-responder
<logout-action> "logout" add-responder <logout-action> "logout" add-responder

View File

@ -0,0 +1,14 @@
USING: help.markup help.syntax io.streams.string ;
IN: furnace.auth.providers.assoc
HELP: <users-in-memory>
{ $values { "provider" users-in-memory } }
{ $description "Creates a new authentication provider which stores the usernames and passwords in an associative mapping." } ;
ARTICLE: "furnace.auth.providers.assoc" "In-memory authentication provider"
"The " { $vocab-link "furnace.auth.providers.assoc" } " vocabulary implements an authentication provider which looks up usernames and passwords in an associative mapping."
{ $subsection users-in-memory }
{ $subsection <users-in-memory> }
"The " { $slot "assoc" } " slot of the " { $link users-in-memory } " tuple maps usernames to checksums of passwords." ;
ABOUT: "furnace.auth.providers.assoc"

View File

@ -0,0 +1,13 @@
USING: help.markup help.syntax ;
IN: furnace.auth.providers.db
HELP: users-in-db
{ $class-description "Singleton class implementing the database authentication provider." } ;
ARTICLE: "furnace.auth.providers.db" "Database authentication provider"
"The " { $vocab-link "furnace.auth.providers.db" } " vocabulary implements an authentication provider which looks up authentication requests in the " { $snippet "USERS" } " table of the current database. The database schema is Factor-specific, and the table should be initialized by calling"
{ $code "users create-table" }
"The authentication provider class:"
{ $subsection users-in-db } ;
ABOUT: "furnace.auth.providers.db"

View File

@ -0,0 +1,10 @@
USING: help.markup help.syntax ;
IN: furnace.auth.providers.null
HELP: no-users
{ $class-description "Singleton class implementing the dummy authentication provider." } ;
ARTICLE: "furnace.auth.providers.null" "Dummy authentication provider"
"The " { $vocab-link "furnace.auth.providers.null" } " vocabulary implements an authentication provider which refuses all authentication requests. It is only useful for testing purposes." ;
ABOUT: "furnace.auth.providers.null"

View File

@ -0,0 +1,45 @@
USING: help.markup help.syntax strings ;
IN: furnace.auth.providers
HELP: user
{ $class-description "The class of users. Instances have the following slots:"
{ $table
{ { $slot "username" } { "The username, used to identify the user for login purposes" } }
{ { $slot "realname" } { "The user's real name, optional" } }
{ { $slot "password" } { "The user's password, encoded with a checksum" } }
{ { $slot "salt" } { "A random salt prepended to the password to ensure that two users with the same plain-text password still have different checksum output" } }
{ { $slot "email" } { "The user's e-mail address, optional" } }
{ { $slot "ticket" } { "Used for password recovery" } }
{ { $slot "capabilities" } { "A sequence of capabilities; see " { $link "furnace.auth.capabilities" } } }
{ { $slot "profile" } { "A hashtable with webapp-specific configuration" } }
{ { $slot "deleted" } { "A boolean indicating whether the user is active or not. This allows a user account to be deactivated without removing the user from the database" } }
{ { $slot "changed?" } { "A boolean indicating whether the user has changed since being retrieved from the database" } }
} } ;
HELP: add-user
{ $values { "provider" "an authentication provider" } { "user" user } }
{ $description "A utility word which calls " { $link new-user } " and throws an error if the user already exists." } ;
HELP: get-user
{ $values { "username" string } { "provider" "an authentication provider" } { "user/f" { $maybe user } } }
{ $contract "Looks up a username in the authentication provider." } ;
HELP: new-user
{ $values { "user" user } { "provider" "an authentication provider" } { "user/f" { $maybe user } } }
{ $contract "Adds a new user to the authentication provider. Outputs " { $link f } " if a user with this username already exists." } ;
HELP: update-user
{ $values { "user" user } { "provider" "an authentication provider" } }
{ $contract "Stores a user back to an authentication provider after being changed. This is a no-op with in-memory providers; providers which use an external store will save the user in this word. " } ;
ARTICLE: "furnace.auth.providers.protocol" "Authentication provider protocol"
"The " { $vocab-link "furnace.auth.providers" } " vocabulary implements a protocol for persistence and authentication of users."
$nl
"The class of users:"
{ $subsection user }
"Generic protocol:"
{ $subsection get-user }
{ $subsection new-user }
{ $subsection update-user } ;
ABOUT: "furnace.auth.providers.protocol"

View File

@ -28,7 +28,7 @@ HELP: cset
{ $description "Sets the value of a conversation variable." } ; { $description "Sets the value of a conversation variable." } ;
HELP: cchange HELP: cchange
{ $values { "key" symbol } { "quot" "a quotation with stack effect " { $snippet "( old -- new )" } } } { $values { "key" symbol } { "quot" { $quotation "( old -- new )" } } }
{ $description "Applies the quotation to the old value of the conversation variable, and assigns the resulting value back to the variable." } ; { $description "Applies the quotation to the old value of the conversation variable, and assigns the resulting value back to the variable." } ;
ARTICLE: "furnace.conversations" "Furnace conversation scope" ARTICLE: "furnace.conversations" "Furnace conversation scope"

View File

@ -1,159 +1,129 @@
USING: assocs help.markup help.syntax io.streams.string quotations sequences strings urls ; USING: assocs help.markup help.syntax kernel
quotations sequences strings urls xml.data http ;
IN: furnace IN: furnace
HELP: adjust-redirect-url HELP: adjust-redirect-url
{ $values { $values { "url" url } { "url'" url } }
{ "url" url } { $description "Adjusts a redirection URL by filtering the URL's query parameters through the " { $link modify-redirect-query } " generic word on every responder involved in handling the current request." } ;
{ "url'" url }
}
{ $description "" } ;
HELP: adjust-url HELP: adjust-url
{ $values { $values { "url" url } { "url'" url } }
{ "url" url } { $description "Adjusts a link URL by filtering the URL's query parameters through the " { $link modify-query } " generic word on every responder involved in handling the current request." } ;
{ "url'" url }
}
{ $description "" } ;
HELP: base-path
{ $values
{ "string" string }
{ "pair" null }
}
{ $description "" } ;
HELP: client-state HELP: client-state
{ $values { $values { "key" string } { "value/f" { $maybe string } } }
{ "key" null } { $description "Looks up a cookie (if the current request is a GET or HEAD request) or a POST parameter (if the current request is a POST request)." }
{ "value/f" null } { $notes "This word is used by session management, conversation scope and asides." } ;
}
{ $description "" } ;
HELP: cookie-client-state
{ $values
{ "key" null } { "request" null }
{ "value/f" null }
}
{ $description "" } ;
HELP: each-responder HELP: each-responder
{ $values { $values { "quot" { $quotation "( responder -- )" } } }
{ "quot" quotation } { $description "Applies the quotation to each responder involved in processing the current request." } ;
}
{ $description "" } ;
HELP: exit-continuation
{ $description "" } ;
HELP: exit-with
{ $values
{ "value" null }
}
{ $description "" } ;
HELP: hidden-form-field HELP: hidden-form-field
{ $values { $values { "value" string } { "name" string } }
{ "value" null } { "name" null } { $description "Renders an HTML hidden form field tag." }
} { $notes "This word is used by session management, conversation scope and asides." }
{ $description "" } ; { $examples
{ $example
"USING: furnace io ;"
"\"bar\" \"foo\" hidden-form-field nl"
"<input type='hidden' name='foo' value='bar'/>"
}
} ;
HELP: link-attr HELP: link-attr
{ $values { $values { "tag" tag } { "responder" "a responder" } }
{ "tag" null } { "responder" null } { $contract "Modifies an XHTML " { $snippet "a" } " tag." }
} { $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
{ $description "" } ; { $examples "Conversation scope adds attributes to link tags." } ;
HELP: modify-form HELP: modify-form
{ $values { $values { "responder" "a responder" } }
{ "responder" null } { $contract "Emits hidden form fields using " { $link hidden-form-field } "." }
} { $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
{ $description "" } ; { $examples "Session management, conversation scope and asides use hidden form fields to pass state." } ;
HELP: modify-query HELP: modify-query
{ $values { $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
{ "query" null } { "responder" null } { $contract "Modifies the query parameters of a URL destined to be displayed as a link." }
{ "query'" null } { $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
} { $examples "Asides add query parameters to URLs." } ;
{ $description "" } ;
HELP: modify-redirect-query HELP: modify-redirect-query
{ $values { $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
{ "query" null } { "responder" null } { $contract "Modifies the query parameters of a URL destined to be used with a redirect." }
{ "query'" null } { $notes "This word is called by " { $link "furnace.redirection" } "." }
} { $examples "Conversation scope and asides add query parameters to redirect URLs." } ;
{ $description "" } ;
HELP: nested-forms-key
{ $description "" } ;
HELP: nested-responders HELP: nested-responders
{ $values { $values { "seq" "a sequence of responders" } }
{ "seq" sequence }
}
{ $description "" } ;
HELP: post-client-state
{ $values
{ "key" null } { "request" null }
{ "value/f" null }
}
{ $description "" } ; { $description "" } ;
HELP: referrer HELP: referrer
{ $values { $values { "referrer/f" { $maybe string } } }
{ $description "Outputs the current request's referrer URL." } ;
{ "referrer/f" null }
}
{ $description "" } ;
HELP: request-params HELP: request-params
{ $values { $values { "request" request } { "assoc" assoc } }
{ "request" null } { $description "Outputs the query parameters (if the current request is a GET or HEAD request) or the POST parameters (if the current request is a POST request)." } ;
{ "assoc" assoc }
}
{ $description "" } ;
HELP: resolve-base-path HELP: resolve-base-path
{ $values { $values { "string" string } { "string'" string } }
{ "string" string }
{ "string'" string }
}
{ $description "" } ; { $description "" } ;
HELP: resolve-template-path HELP: resolve-template-path
{ $values { $values { "pair" "a pair with shape " { $snippet "{ class string }" } } { "path" "a pathname string" } }
{ "pair" null }
{ "path" "a pathname string" }
}
{ $description "" } ; { $description "" } ;
HELP: same-host? HELP: same-host?
{ $values { $values { "url" url } { "?" "a boolean" } }
{ "url" url } { $description "Tests if the given URL is located on the same host as the URL of the current request." } ;
{ "?" "a boolean" }
}
{ $description "" } ;
HELP: user-agent HELP: user-agent
{ $values { $values { "user-agent" { $maybe string } } }
{ $description "Outputs the user agent reported by the client for the current request." } ;
{ "user-agent" null }
}
{ $description "" } ;
HELP: vocab-path HELP: vocab-path
{ $values { $values { "vocab" "a vocabulary specifier" } { "path" "a pathname string" } }
{ "vocab" "a vocabulary specifier" }
{ "path" "a pathname string" }
}
{ $description "" } ; { $description "" } ;
HELP: exit-with
{ $values { "value" object } }
{ $description "Exits from an outer " { $link with-exit-continuation } "." } ;
HELP: with-exit-continuation HELP: with-exit-continuation
{ $values { $values { "quot" { $quotation { "( -- value )" } } } { "value" "a value returned by the quotation or an " { $link exit-with } " invocation" } }
{ "quot" quotation } { $description "Runs a quotation with the " { $link exit-continuation } " variable bound. Calling " { $link exit-with } " in the quotation will immediately return." }
} { $notes "Furnace actions and authentication realms wrap their execution in this combinator, allowing form validation failures and login requests, respectively, to immediately return an HTTP response to the client without running any more responder code." } ;
{ $description "" } ;
ARTICLE: "furnace.extension-points" "Furnace extension points"
"Furnace features such as session management, conversation scope and asides need to modify URLs in links and redirects, and insert hidden form fields, to implement state on top of the setateless HTTP protocol. In order to decouple the server-side state management code from the HTML templating code, a series of hooks are used."
$nl
"Responders can implement methods on the following generic words:"
{ $subsection modify-query }
{ $subsection modify-redirect-query }
{ $subsection link-attr }
{ $subsection modify-form }
"Presentation-level code can call the following words:"
{ $subsection adjust-url }
{ $subsection adjust-redirect-url } ;
ARTICLE: "furnace.misc" "Miscellaneous Furnace features"
"Inspecting the chain of responders handling the current request:"
{ $subsection nested-responders }
{ $subsection each-responder }
{ $subsection resolve-base-path }
"Vocabulary root-relative resources:"
{ $subsection vocab-path }
{ $subsection resolve-template-path }
"Early return from a responder:"
{ $subsection with-exit-continuation }
{ $subsection exit-with }
"Other useful words:"
{ $subsection hidden-form-field }
{ $subsection request-params }
{ $subsection client-state }
{ $subsection user-agent } ;
ARTICLE: "furnace.persistence" "Furnace persistence layer" ARTICLE: "furnace.persistence" "Furnace persistence layer"
{ $subsection "furnace.db" } { $subsection "furnace.db" }
@ -193,10 +163,13 @@ ARTICLE: "furnace" "Furnace framework"
{ $subsection "furnace.alloy" } { $subsection "furnace.alloy" }
{ $subsection "furnace.persistence" } { $subsection "furnace.persistence" }
{ $subsection "furnace.presentation" } { $subsection "furnace.presentation" }
{ $subsection "furnace.auth" }
{ $subsection "furnace.load-balancing" } { $subsection "furnace.load-balancing" }
"Utilities:" "Utilities:"
{ $subsection "furnace.referrer" } { $subsection "furnace.referrer" }
{ $subsection "furnace.redirection" } { $subsection "furnace.redirection" }
{ $subsection "furnace.extension-points" }
{ $subsection "furnace.misc" }
"Related frameworks:" "Related frameworks:"
{ $subsection "db" } { $subsection "db" }
{ $subsection "xml" } { $subsection "xml" }

View File

@ -90,7 +90,7 @@ M: object modify-form drop ;
} case ; } case ;
: referrer ( -- referrer/f ) : referrer ( -- referrer/f )
#! Typo is intentional, its in the HTTP spec! #! Typo is intentional, it's in the HTTP spec!
"referer" request get header>> at "referer" request get header>> at
dup [ >url ensure-port [ remap-port ] change-port ] when ; dup [ >url ensure-port [ remap-port ] change-port ] when ;
@ -125,7 +125,7 @@ SYMBOL: exit-continuation
: exit-with ( value -- ) : exit-with ( value -- )
exit-continuation get continue-with ; exit-continuation get continue-with ;
: with-exit-continuation ( quot -- ) : with-exit-continuation ( quot -- value )
'[ exit-continuation set @ ] callcc1 exit-continuation off ; '[ exit-continuation set @ ] callcc1 exit-continuation off ;
USE: vocabs.loader USE: vocabs.loader
@ -152,3 +152,4 @@ USE: vocabs.loader
"furnace.scopes" require "furnace.scopes" require
"furnace.sessions" require "furnace.sessions" require
"furnace.syndication" require "furnace.syndication" require
"webapps.user-admin" require

View File

@ -1,4 +1,5 @@
USING: help.markup help.syntax io.streams.string ; USING: help.markup help.syntax io.streams.string
furnace ;
IN: furnace.referrer IN: furnace.referrer
HELP: <check-form-submissions> HELP: <check-form-submissions>
@ -10,6 +11,9 @@ HELP: <check-form-submissions>
ARTICLE: "furnace.referrer" "Form submission referrer checking" ARTICLE: "furnace.referrer" "Form submission referrer checking"
"The " { $vocab-link "furnace.referrer" } " implements a simple security measure which can be used to thwart cross-site scripting attacks." "The " { $vocab-link "furnace.referrer" } " implements a simple security measure which can be used to thwart cross-site scripting attacks."
{ $subsection <check-form-submissions> } ; { $subsection <check-form-submissions> }
"Explicit referrer checking:"
{ $subsection referrer }
{ $subsection same-host? } ;
ABOUT: "furnace.referrer" ABOUT: "furnace.referrer"

View File

@ -9,7 +9,7 @@ HELP: <sessions>
{ $description "Wraps a responder in a session manager responder." } ; { $description "Wraps a responder in a session manager responder." } ;
HELP: schange HELP: schange
{ $values { "key" symbol } { "quot" "a quotation with stack effect " { $snippet "( old -- new )" } } } { $values { "key" symbol } { "quot" { $quotation "( old -- new )" } } }
{ $description "Applies the quotation to the old value of the session variable, and assigns the resulting value back to the variable." } ; { $description "Applies the quotation to the old value of the session variable, and assigns the resulting value back to the variable." } ;
HELP: sget HELP: sget

View File

@ -0,0 +1 @@
Furnace web framework

View File

@ -1,6 +1,6 @@
USING: help.markup help.crossref help.stylesheet help.topics USING: help.markup help.crossref help.stylesheet help.topics
help.syntax definitions io prettyprint summary arrays math help.syntax definitions io prettyprint summary arrays math
sequences vocabs ; sequences vocabs strings ;
IN: help IN: help
ARTICLE: "printing-elements" "Printing markup elements" ARTICLE: "printing-elements" "Printing markup elements"
@ -33,6 +33,10 @@ ARTICLE: "block-elements" "Block elements"
{ $subsection $side-effects } { $subsection $side-effects }
{ $subsection $errors } { $subsection $errors }
{ $subsection $see-also } { $subsection $see-also }
"Elements used in " { $link $values } " forms:"
{ $subsection $instance }
{ $subsection $maybe }
{ $subsection $quotation }
"Boilerplate paragraphs:" "Boilerplate paragraphs:"
{ $subsection $low-level-note } { $subsection $low-level-note }
{ $subsection $io-error } { $subsection $io-error }
@ -281,7 +285,7 @@ HELP: $link
} ; } ;
HELP: textual-list HELP: textual-list
{ $values { "seq" "a sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } } { $values { "seq" "a sequence" } { "quot" { $quotation "( elt -- )" } } }
{ $description "Applies the quotation to each element of the sequence, printing a comma between each pair of elements." } { $description "Applies the quotation to each element of the sequence, printing a comma between each pair of elements." }
{ $examples { $examples
{ $example "USING: help.markup io ;" "{ \"fish\" \"chips\" \"salt\" } [ write ] textual-list" "fish, chips, salt" } { $example "USING: help.markup io ;" "{ \"fish\" \"chips\" \"salt\" } [ write ] textual-list" "fish, chips, salt" }
@ -318,7 +322,37 @@ HELP: $table
HELP: $values HELP: $values
{ $values { "element" "an array of pairs of markup elements" } } { $values { "element" "an array of pairs of markup elements" } }
{ $description "Prints the description of arguments and values found on every word help page. The first element of a pair is the argument name and is output with " { $link $snippet } ". The remainder can be an element of any form." } ; { $description "Prints the description of arguments and values found on every word help page. The first element of a pair is the argument name and is output with " { $link $snippet } ". The remainder is either a single class word, or an element. If it is a class word " { $snippet "class" } ", it is intereted as if it were shorthand for " { $snippet "{ $instance class }" } "." }
{ $see-also $maybe $instance $quotation } ;
HELP: $instance
{ $values { "element" "an array with shape " { $snippet "{ class }" } } }
{ $description
"Produces the text ``a " { $emphasis "class" } "'' or ``an " { $emphasis "class" } "'', depending on the first letter of " { $emphasis "class" } "."
}
{ $examples
{ $markup-example { $instance string } }
{ $markup-example { $instance integer } }
{ $markup-example { $instance f } }
} ;
HELP: $maybe
{ $values { "element" "an array with shape " { $snippet "{ class }" } } }
{ $description
"Produces the text ``a " { $emphasis "class" } " or f'' or ``an " { $emphasis "class" } " or f'', depending on the first letter of " { $emphasis "class" } "."
}
{ $examples
{ $markup-example { $maybe string } }
} ;
HELP: $quotation
{ $values { "element" "an array with shape " { $snippet "{ effect }" } } }
{ $description
"Produces the text ``a quotation with stack effect " { $emphasis "effect" } "''."
}
{ $examples
{ $markup-example { $quotation "( obj -- )" } }
} ;
HELP: $list HELP: $list
{ $values { "element" "an array of markup elements" } } { $values { "element" "an array of markup elements" } }

View File

@ -5,7 +5,7 @@ io.files html.streams html.elements html.components help kernel
assocs sequences make words accessors arrays help.topics vocabs assocs sequences make words accessors arrays help.topics vocabs
tools.vocabs tools.vocabs.browser namespaces prettyprint io tools.vocabs tools.vocabs.browser namespaces prettyprint io
vocabs.loader serialize fry memoize unicode.case math.order vocabs.loader serialize fry memoize unicode.case math.order
sorting ; sorting debugger ;
IN: help.html IN: help.html
: escape-char ( ch -- ) : escape-char ( ch -- )
@ -22,6 +22,7 @@ IN: help.html
{ CHAR: / "__slash__" } { CHAR: / "__slash__" }
{ CHAR: \\ "__backslash__" } { CHAR: \\ "__backslash__" }
{ CHAR: , "__comma__" } { CHAR: , "__comma__" }
{ CHAR: @ "__at__" }
} at [ % ] [ , ] ?if ; } at [ % ] [ , ] ?if ;
: escape-filename ( string -- filename ) : escape-filename ( string -- filename )
@ -88,19 +89,17 @@ M: topic browser-link-href topic>filename ;
all-vocabs-really [ dup vocab-name ] { } map>assoc "vocabs.idx" serialize-index ; all-vocabs-really [ dup vocab-name ] { } map>assoc "vocabs.idx" serialize-index ;
: generate-help-files ( -- ) : generate-help-files ( -- )
all-topics [ help>html ] each ; all-topics [ '[ _ help>html ] try ] each ;
: generate-help ( -- ) : generate-help ( -- )
{ "resource:core" "resource:basis" "resource:extra" } vocab-roots [ "docs" temp-file
load-everything [ make-directories ]
[
"/tmp/docs/" make-directory [
"/tmp/docs/" [
generate-indices generate-indices
generate-help-files generate-help-files
] with-directory ] with-directory
] with-variable ; ] bi ;
MEMO: load-index ( name -- index ) MEMO: load-index ( name -- index )
binary file-contents bytes>object ; binary file-contents bytes>object ;
@ -118,10 +117,10 @@ M: result link-href href>> ;
[ [ title>> ] compare ] sort ; [ [ title>> ] compare ] sort ;
: article-apropos ( string -- results ) : article-apropos ( string -- results )
"articles.idx" offline-apropos ; "articles.idx" temp-file offline-apropos ;
: word-apropos ( string -- results ) : word-apropos ( string -- results )
"words.idx" offline-apropos ; "words.idx" temp-file offline-apropos ;
: vocab-apropos ( string -- results ) : vocab-apropos ( string -- results )
"vocabs.idx" offline-apropos ; "vocabs.idx" temp-file offline-apropos ;

View File

@ -3,7 +3,8 @@
USING: accessors arrays definitions generic io kernel assocs USING: accessors arrays definitions generic io kernel assocs
hashtables namespaces make parser prettyprint sequences strings hashtables namespaces make parser prettyprint sequences strings
io.styles vectors words math sorting splitting classes slots io.styles vectors words math sorting splitting classes slots
vocabs help.stylesheet help.topics vocabs.loader alias ; vocabs help.stylesheet help.topics vocabs.loader alias
quotations ;
IN: help.markup IN: help.markup
! Simple markup language. ! Simple markup language.
@ -234,7 +235,8 @@ ALIAS: $slot $snippet
] ($grid) ; ] ($grid) ;
: a/an ( str -- str ) : a/an ( str -- str )
first "aeiou" member? "an" "a" ? ; [ first ] [ length ] bi 1 =
"afhilmnorsx" "aeiou" ? member? "an" "a" ? ;
GENERIC: ($instance) ( element -- ) GENERIC: ($instance) ( element -- )
@ -244,7 +246,17 @@ M: word ($instance)
M: string ($instance) M: string ($instance)
dup a/an write bl $snippet ; dup a/an write bl $snippet ;
: $instance ( children -- ) first ($instance) ; M: f ($instance)
drop { f } $link ;
: $instance ( element -- ) first ($instance) ;
: $maybe ( element -- )
$instance " or " print-element { f } $instance ;
: $quotation ( element -- )
{ "a " { $link quotation } " with stack effect " } print-element
$snippet ;
: values-row ( seq -- seq ) : values-row ( seq -- seq )
unclip \ $snippet swap ?word-name 2array unclip \ $snippet swap ?word-name 2array

View File

@ -14,7 +14,7 @@ HELP: required-attr
{ $errors "Throws an error if the attribute is not specified." } ; { $errors "Throws an error if the attribute is not specified." } ;
HELP: optional-attr HELP: optional-attr
{ $values { "tag" tag } { "name" string } { "value" "a " { $link string } " or " { $link f } } } { $values { "tag" tag } { "name" string } { "value" { $maybe string } } }
{ $description "Extracts an attribute from a tag." } { $description "Extracts an attribute from a tag." }
{ $notes "Outputs " { $link f } " if the attribute is not specified." } ; { $notes "Outputs " { $link f } " if the attribute is not specified." } ;
@ -24,7 +24,7 @@ HELP: compile-attr
HELP: CHLOE: HELP: CHLOE:
{ $syntax "name definition... ;" } { $syntax "name definition... ;" }
{ $values { "name" "the tag name" } { "definition" "a quotation with stack effect " { $snippet "( tag -- )" } } } { $values { "name" "the tag name" } { "definition" { $quotation "( tag -- )" } } }
{ $description "Defines compilation semantics for the Chloe tag named " { $snippet "tag" } ". The definition body receives a " { $link tag } " on the stack." } ; { $description "Defines compilation semantics for the Chloe tag named " { $snippet "tag" } ". The definition body receives a " { $link tag } " on the stack." } ;
HELP: COMPONENT: HELP: COMPONENT:
@ -46,7 +46,7 @@ HELP: [code]
{ $description "Compiles the quotation. It will be called when the template is called." } ; { $description "Compiles the quotation. It will be called when the template is called." } ;
HELP: process-children HELP: process-children
{ $values { "tag" tag } { "quot" "a quotation with stack effect " { $snippet "( compiled-tag -- )" } } } { $values { "tag" tag } { "quot" { $quotation "( compiled-tag -- )" } } }
{ $description "Compiles the tag. The quotation will be applied to the resulting quotation when the template is called." } { $description "Compiles the tag. The quotation will be applied to the resulting quotation when the template is called." }
{ $examples "See " { $link "html.templates.chloe.extend.tags.example" } " for an example which uses this word to implement a custom control flow tag." } ; { $examples "See " { $link "html.templates.chloe.extend.tags.example" } " for an example which uses this word to implement a custom control flow tag." } ;

View File

@ -40,7 +40,7 @@ HELP: http-post
{ $errors "Throws an error if the HTTP request fails." } ; { $errors "Throws an error if the HTTP request fails." } ;
HELP: with-http-get HELP: with-http-get
{ $values { "url" "a " { $link url } " or " { $link string } } { "quot" "a quotation with stack effect " { $snippet "( chunk -- )" } } { "response" response } } { $values { "url" "a " { $link url } " or " { $link string } } { "quot" { $quotation "( chunk -- )" } } { "response" response } }
{ $description "Downloads the contents of a URL. Chunks of data are passed to the quotation as they are read." } { $description "Downloads the contents of a URL. Chunks of data are passed to the quotation as they are read." }
{ $errors "Throws an error if the HTTP request fails." } ; { $errors "Throws an error if the HTTP request fails." } ;
@ -50,7 +50,7 @@ HELP: http-request
{ $errors "Throws an error if the HTTP request fails." } ; { $errors "Throws an error if the HTTP request fails." } ;
HELP: with-http-request HELP: with-http-request
{ $values { "request" request } { "quot" "a quotation with stack effect " { $snippet "( chunk -- )" } } { "response" response } } { $values { "request" request } { "quot" { $quotation "( chunk -- )" } } { "response" response } }
{ $description "Sends an HTTP request to an HTTP server, and reads the response incrementally. Chunks of data are passed to the quotation as they are read." } { $description "Sends an HTTP request to an HTTP server, and reads the response incrementally. Chunks of data are passed to the quotation as they are read." }
{ $errors "Throws an error if the HTTP request fails." } ; { $errors "Throws an error if the HTTP request fails." } ;

View File

@ -81,7 +81,7 @@ HELP: delete-cookie
{ $side-effects "request/response" } ; { $side-effects "request/response" } ;
HELP: get-cookie HELP: get-cookie
{ $values { "request/response" "a " { $link request } " or a " { $link response } } { "name" string } { "cookie/f" "a " { $link cookie } " or " { $link f } } } { $values { "request/response" "a " { $link request } " or a " { $link response } } { "name" string } { "cookie/f" { $maybe cookie } } }
{ $description "Gets a named cookie from a request or response." } ; { $description "Gets a named cookie from a request or response." } ;
HELP: put-cookie HELP: put-cookie

View File

@ -4,7 +4,7 @@ USING: help.markup help.syntax io.streams.string ;
IN: http.server.static IN: http.server.static
HELP: <file-responder> HELP: <file-responder>
{ $values { "root" "a pathname string" } { "hook" "a quotation with stack effect " { $snippet "( path mime-type -- response )" } } { "responder" file-responder } } { $values { "root" "a pathname string" } { "hook" { $quotation "( path mime-type -- response )" } } { "responder" file-responder } }
{ $description "Creates a file responder which serves content from " { $snippet "path" } " by using the hook to generate a response." } ; { $description "Creates a file responder which serves content from " { $snippet "path" } " by using the hook to generate a response." } ;
HELP: <static> HELP: <static>

View File

@ -17,7 +17,7 @@ HELP: <mapped-file>
{ $errors "Throws an error if a memory mapping could not be established." } ; { $errors "Throws an error if a memory mapping could not be established." } ;
HELP: with-mapped-file HELP: with-mapped-file
{ $values { "path" "a pathname string" } { "length" integer } { "quot" "a quotation with stack effect " { $snippet "( mmap -- )" } } } { $values { "path" "a pathname string" } { "length" integer } { "quot" { $quotation "( mmap -- )" } } }
{ $contract "Opens a file and maps its contents into memory, passing the " { $link mapped-file } " instance to the quotation. The mapped file is disposed of when the quotation returns, or if an error is thrown." } { $contract "Opens a file and maps its contents into memory, passing the " { $link mapped-file } " instance to the quotation. The mapped file is disposed of when the quotation returns, or if an error is thrown." }
{ $errors "Throws an error if a memory mapping could not be established." } ; { $errors "Throws an error if a memory mapping could not be established." } ;

View File

@ -23,7 +23,7 @@ HELP: next-change
{ $errors "Throws an error if the monitor is closed from another thread." } ; { $errors "Throws an error if the monitor is closed from another thread." } ;
HELP: with-monitor HELP: with-monitor
{ $values { "path" "a pathname string" } { "recursive?" "a boolean" } { "quot" "a quotation with stack effect " { $snippet "( monitor -- )" } } } { $values { "path" "a pathname string" } { "recursive?" "a boolean" } { "quot" { $quotation "( monitor -- )" } } }
{ $description "Opens a file system change monitor and passes it to the quotation. Closes the monitor after the quotation returns or throws an error." } { $description "Opens a file system change monitor and passes it to the quotation. Closes the monitor after the quotation returns or throws an error." }
{ $errors "Throws an error if the pathname does not exist, if a monitor could not be created or if the platform does not support monitors." } ; { $errors "Throws an error if the pathname does not exist, if a monitor could not be created or if the platform does not support monitors." } ;

View File

@ -22,7 +22,7 @@ HELP: return-connection
{ $description "Returns a connection to the pool." } ; { $description "Returns a connection to the pool." } ;
HELP: with-pooled-connection HELP: with-pooled-connection
{ $values { "pool" pool } { "quot" "a quotation with stack effect " { $snippet "( conn -- )" } } } { $values { "pool" pool } { "quot" { $quotation "( conn -- )" } } }
{ $description "Calls a quotation with a pooled connection on the stack. If the quotation returns successfully, the connection is returned to the pool; if the quotation throws an error, the connection is disposed of with " { $link dispose } "." } ; { $description "Calls a quotation with a pooled connection on the stack. If the quotation returns successfully, the connection is returned to the pool; if the quotation throws an error, the connection is disposed of with " { $link dispose } "." } ;
HELP: make-connection HELP: make-connection

View File

@ -114,11 +114,11 @@ HELP: stop-this-server
{ $description "Stops the current threaded server, preventing it from accepting any more connections and returning to the caller of " { $link start-server } ". All client connections which have already been opened continue to be serviced." } ; { $description "Stops the current threaded server, preventing it from accepting any more connections and returning to the caller of " { $link start-server } ". All client connections which have already been opened continue to be serviced." } ;
HELP: secure-port HELP: secure-port
{ $values { "n" "an " { $link integer } " or " { $link f } } } { $values { "n" { $maybe integer } } }
{ $description "Outputs the port number on which the current threaded server accepts secure socket connections. Outputs " { $link f } " if the current threaded server does not accept secure socket connections." } { $description "Outputs the port number on which the current threaded server accepts secure socket connections. Outputs " { $link f } " if the current threaded server does not accept secure socket connections." }
{ $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ; { $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ;
HELP: insecure-port HELP: insecure-port
{ $values { "n" "an " { $link integer } " or " { $link f } } } { $values { "n" { $maybe integer } } }
{ $description "Outputs the port number on which the current threaded server accepts ordinary socket connections. Outputs " { $link f } " if the current threaded server does not accept ordinary socket connections." } { $description "Outputs the port number on which the current threaded server accepts ordinary socket connections. Outputs " { $link f } " if the current threaded server does not accept ordinary socket connections." }
{ $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ; { $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ;

View File

@ -56,7 +56,7 @@ ARTICLE: "network-streams" "Networking"
{ $subsection "network-addressing" } { $subsection "network-addressing" }
{ $subsection "network-connection" } { $subsection "network-connection" }
{ $subsection "network-packet" } { $subsection "network-packet" }
{ $subsection "io.sockets.secure" } { $vocab-subsection "Secure sockets (SSL, TLS)" "io.sockets.secure" }
{ $see-also "io.pipes" } ; { $see-also "io.pipes" } ;
ABOUT: "network-streams" ABOUT: "network-streams"

View File

@ -2,11 +2,11 @@ IN: io.timeouts
USING: help.markup help.syntax math kernel calendar ; USING: help.markup help.syntax math kernel calendar ;
HELP: timeout HELP: timeout
{ $values { "obj" object } { "dt/f" "a " { $link duration } " or " { $link f } } } { $values { "obj" object } { "dt/f" { $maybe duration } } }
{ $contract "Outputs an object's timeout." } ; { $contract "Outputs an object's timeout." } ;
HELP: set-timeout HELP: set-timeout
{ $values { "dt/f" "a " { $link duration } " or " { $link f } } { "obj" object } } { $values { "dt/f" { $maybe duration } } { "obj" object } }
{ $contract "Sets an object's timeout." } ; { $contract "Sets an object's timeout." } ;
HELP: cancel-operation HELP: cancel-operation
@ -14,7 +14,7 @@ HELP: cancel-operation
{ $contract "Handles a timeout, usually by waking up all threads waiting on the object." } ; { $contract "Handles a timeout, usually by waking up all threads waiting on the object." } ;
HELP: with-timeout HELP: with-timeout
{ $values { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } } { $values { "obj" object } { "quot" { $quotation "( obj -- )" } } }
{ $description "Applies the quotation to the object. If the object's timeout expires before the quotation returns, " { $link cancel-operation } " is called on the object." } ; { $description "Applies the quotation to the object. If the object's timeout expires before the quotation returns, " { $link cancel-operation } " is called on the object." } ;
ARTICLE: "io.timeouts" "I/O timeout protocol" ARTICLE: "io.timeouts" "I/O timeout protocol"

View File

@ -33,7 +33,7 @@ HELP: free
{ $description "Deallocates a block of memory allocated by " { $link malloc } ", " { $link calloc } " or " { $link realloc } "." } ; { $description "Deallocates a block of memory allocated by " { $link malloc } ", " { $link calloc } " or " { $link realloc } "." } ;
HELP: with-malloc HELP: with-malloc
{ $values { "size" "a positive integer" } { "quot" "a quotation with stack effect " { $snippet "( c-ptr -- )" } } } { $values { "size" "a positive integer" } { "quot" { $quotation "( c-ptr -- )" } } }
{ $description "Allocates a zeroed block of " { $snippet "n" } " bytes and passes it to the quotation. When the quotation returns, the block is freed." } ; { $description "Allocates a zeroed block of " { $snippet "n" } " bytes and passes it to the quotation. When the quotation returns, the block is freed." } ;
HELP: &free HELP: &free

View File

@ -279,7 +279,7 @@ HELP: mod-inv
} ; } ;
HELP: each-bit HELP: each-bit
{ $values { "n" integer } { "quot" "a quotation with stack effect " { $snippet "( ? -- )" } } } { $values { "n" integer } { "quot" { $quotation "( ? -- )" } } }
{ $description "Applies the quotation to each bit of the integer, starting from the least significant bit, and stopping at the last bit from which point on all bits are either clear (if the integer is positive) or all bits are set (if the integer is negataive)." } { $description "Applies the quotation to each bit of the integer, starting from the least significant bit, and stopping at the last bit from which point on all bits are either clear (if the integer is positive) or all bits are set (if the integer is negataive)." }
{ $examples { $examples
{ $example "USING: math.functions make prettyprint ;" "[ BIN: 1101 [ , ] each-bit ] { } make ." "{ t f t t }" } { $example "USING: math.functions make prettyprint ;" "[ BIN: 1101 [ , ] each-bit ] { } make ." "{ t f t t }" }

View File

@ -156,8 +156,8 @@ HELP: interval*
{ $description "Multiplies two intervals." } ; { $description "Multiplies two intervals." } ;
HELP: interval-shift HELP: interval-shift
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } } { $values { "i1" interval } { "i2" interval } { "i3" interval } }
{ $description "Shifts " { $snippet "i1" } " to the left by " { $snippet "i2" } " bits. Outputs " { $link f } " if the endpoints of either " { $snippet "i1" } " or " { $snippet "i2" } " are not integers." } ; { $description "Shifts " { $snippet "i1" } " to the left by " { $snippet "i2" } " bits. Outputs " { $link full-interval } " if the endpoints of either " { $snippet "i1" } " or " { $snippet "i2" } " are not integers." } ;
HELP: interval-max HELP: interval-max
{ $values { "i1" interval } { "i2" interval } { "i3" interval } } { $values { "i1" interval } { "i2" interval } { "i3" interval } }
@ -253,8 +253,8 @@ HELP: points>interval
; ;
HELP: interval-shift-safe HELP: interval-shift-safe
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } } { $values { "i1" interval } { "i2" interval } { "i3" interval } }
{ $description "Shifts " { $snippet "i1" } " to the left by " { $snippet "i2" } " bits. Outputs " { $link f } " if the endpoints of either " { $snippet "i1" } " or " { $snippet "i2" } " are not integers, or if the endpoints of " { $snippet "i2" } " are so large that the resulting interval will consume too much memory." } ; { $description "Shifts " { $snippet "i1" } " to the left by " { $snippet "i2" } " bits. Outputs " { $link full-interval } " if the endpoints of either " { $snippet "i1" } " or " { $snippet "i2" } " are not integers, or if the endpoints of " { $snippet "i2" } " are so large that the resulting interval will consume too much memory." } ;
HELP: incomparable HELP: incomparable
{ $description "Output value from " { $link interval<= } ", " { $link interval< } ", " { $link interval>= } " and " { $link interval> } " in the case where the result of the comparison is ambiguous." } ; { $description "Output value from " { $link interval<= } ", " { $link interval< } ", " { $link interval>= } " and " { $link interval> } " in the case where the result of the comparison is ambiguous." } ;
@ -304,20 +304,20 @@ HELP: interval>points
{ $description "Outputs both endpoints of the interval." } ; { $description "Outputs both endpoints of the interval." } ;
HELP: assume< HELP: assume<
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } } { $values { "i1" interval } { "i2" interval } { "i3" interval } }
{ $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are less than all points in " { $snippet "i2" } ". If the resulting interval is empty, outputs " { $link f } "." } ; { $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are less than all points in " { $snippet "i2" } "." } ;
HELP: assume<= HELP: assume<=
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } } { $values { "i1" interval } { "i2" interval } { "i3" interval } }
{ $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are less or equal to all points in " { $snippet "i2" } ". If the resulting interval is empty, outputs " { $link f } "." } ; { $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are less or equal to all points in " { $snippet "i2" } "." } ;
HELP: assume> HELP: assume>
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } } { $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } }
{ $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are greater than all points in " { $snippet "i2" } ". If the resulting interval is empty, outputs " { $link f } "." } ; { $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are greater than all points in " { $snippet "i2" } ". If the resulting interval is empty, outputs " { $link f } "." } ;
HELP: assume>= HELP: assume>=
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } } { $values { "i1" interval } { "i2" interval } { "i3" interval } }
{ $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are greater than or equal to all points in " { $snippet "i2" } ". If the resulting interval is empty, outputs " { $link f } "." } ; { $description "Outputs the interval consisting of points from " { $snippet "i1" } " which are greater than or equal to all points in " { $snippet "i2" } "." } ;
HELP: integral-closure HELP: integral-closure
{ $values { "i1" "an " { $link interval } " with integer end-points" } { "i2" "a closed " { $link interval } " with integer end-points" } } { $values { "i1" "an " { $link interval } " with integer end-points" } { "i2" "a closed " { $link interval } " with integer end-points" } }

View File

@ -15,7 +15,7 @@ HELP: filter
} ; } ;
HELP: <filter> HELP: <filter>
{ $values { "model" model } { "quot" "a quotation with stack effect " { $snippet "( obj -- newobj )" } } { "filter" "a new " { $link filter } } } { $values { "model" model } { "quot" { $quotation "( obj -- newobj )" } } { "filter" "a new " { $link filter } } }
{ $description "Creates a new instance of " { $link filter } ". The value of the new filter model is computed by applying the quotation to the value." } { $description "Creates a new instance of " { $link filter } ". The value of the new filter model is computed by applying the quotation to the value." }
{ $examples "See the example in the documentation for " { $link filter } "." } ; { $examples "See the example in the documentation for " { $link filter } "." } ;

View File

@ -66,11 +66,11 @@ HELP: set-model
{ set-model change-model (change-model) } related-words { set-model change-model (change-model) } related-words
HELP: change-model HELP: change-model
{ $values { "model" model } { "quot" "a quotation with stack effect " { $snippet "( obj -- newobj )" } } } { $values { "model" model } { "quot" { $quotation "( obj -- newobj )" } } }
{ $description "Applies the quotation to the current value of the model to yield a new value, then changes the value of the model to the new value, and calls " { $link model-changed } " on all observers registered with " { $link add-connection } "." } ; { $description "Applies the quotation to the current value of the model to yield a new value, then changes the value of the model to the new value, and calls " { $link model-changed } " on all observers registered with " { $link add-connection } "." } ;
HELP: (change-model) HELP: (change-model)
{ $values { "model" model } { "quot" "a quotation with stack effect " { $snippet "( obj -- newobj )" } } } { $values { "model" model } { "quot" { $quotation "( obj -- newobj )" } } }
{ $description "Applies the quotation to the current value of the model to yield a new value, then changes the value of the model to the new value without notifying any observers registered with " { $link add-connection } "." } { $description "Applies the quotation to the current value of the model to yield a new value, then changes the value of the model to the new value without notifying any observers registered with " { $link add-connection } "." }
{ $notes "There are very few reasons for user code to call this word. Instead, call " { $link change-model } ", which notifies observers." } ; { $notes "There are very few reasons for user code to call this word. Instead, call " { $link change-model } ", which notifies observers." } ;

View File

@ -98,7 +98,7 @@ HELP: optional
HELP: semantic HELP: semantic
{ $values { $values
{ "parser" "a parser" } { "parser" "a parser" }
{ "quot" "a quotation with stack effect ( object -- bool )" } { "quot" { $quotation "( object -- ? )" } }
} }
{ $description { $description
"Returns a parser that succeeds if the 'p1' parser succeeds and the quotation called with " "Returns a parser that succeeds if the 'p1' parser succeeds and the quotation called with "
@ -130,7 +130,7 @@ HELP: ensure-not
HELP: action HELP: action
{ $values { $values
{ "parser" "a parser" } { "parser" "a parser" }
{ "quot" "a quotation with stack effect ( ast -- ast )" } { "quot" { $quotation "( ast -- ast )" } }
} }
{ $description { $description
"Returns a parser that calls the 'p1' parser and applies the quotation to the AST resulting " "Returns a parser that calls the 'p1' parser and applies the quotation to the AST resulting "

View File

@ -37,7 +37,7 @@ HELP: nesting-limit?
$prettyprinting-note ; $prettyprinting-note ;
HELP: check-recursion HELP: check-recursion
{ $values { "obj" "an object" } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } } { $values { "obj" "an object" } { "quot" { $quotation "( obj -- )" } } }
{ $description "If the object is already being printed, that is, if the prettyprinter has encountered a cycle in the object graph, or if the maximum nesting depth has been reached, outputs a dummy string. Otherwise applies the quotation to the object." } { $description "If the object is already being printed, that is, if the prettyprinter has encountered a cycle in the object graph, or if the maximum nesting depth has been reached, outputs a dummy string. Otherwise applies the quotation to the object." }
$prettyprinting-note ; $prettyprinting-note ;

View File

@ -145,7 +145,7 @@ HELP: save-end-position
{ $description "Save the current position as the end position of the block." } ; { $description "Save the current position as the end position of the block." } ;
HELP: pprint-sections HELP: pprint-sections
{ $values { "block" block } { "advancer" "a quotation with stack effect " { $snippet "( block -- )" } } } { $values { "block" block } { "advancer" { $quotation "( block -- )" } } }
{ $description "Prints child sections of a block, ignoring any " { $link line-break } " sections. The " { $snippet "advancer" } " quotation is called between every pair of sections." } ; { $description "Prints child sections of a block, ignoring any " { $link line-break } " sections. The " { $snippet "advancer" } " quotation is called between every pair of sections." } ;
HELP: do-break HELP: do-break
@ -157,7 +157,7 @@ HELP: empty-block?
{ $description "Tests if the block has no child sections." } ; { $description "Tests if the block has no child sections." } ;
HELP: if-nonempty HELP: if-nonempty
{ $values { "block" block } { "quot" "a quotation with stack effect " { $snippet "( block -- )" } } } { $values { "block" block } { "quot" { $quotation "( block -- )" } } }
{ $description "If the block has child sections, calls the quotation, otherwise does nothing." } ; { $description "If the block has child sections, calls the quotation, otherwise does nothing." } ;
HELP: (<block) HELP: (<block)

View File

@ -1,21 +1,15 @@
IN: search-deques IN: search-deques
USING: help.markup help.syntax kernel dlists hashtables USING: help.markup help.syntax kernel hashtables
deques assocs ; deques assocs ;
ARTICLE: "search-deques" "Search deques" ARTICLE: "search-deques" "Search deques"
"A search deque is a data structure with constant-time insertion and removal of elements at both ends, and constant-time membership tests. Inserting an element more than once has no effect. Search deques implement all deque operations in terms of an underlying deque, and membership testing with " { $link deque-member? } " is implemented with an underlying assoc. Search deques are defined in the " { $vocab-link "search-deques" } " vocabulary." "A search deque is a data structure with constant-time insertion and removal of elements at both ends, and constant-time membership tests. Inserting an element more than once has no effect. Search deques implement all deque operations in terms of an underlying deque, and membership testing with " { $link deque-member? } " is implemented with an underlying assoc. Search deques are defined in the " { $vocab-link "search-deques" } " vocabulary."
$nl $nl
"Creating a search deque:" "Creating a search deque:"
{ $subsection <search-deque> } { $subsection <search-deque> } ;
"Default implementation:"
{ $subsection <hashed-dlist> } ;
ABOUT: "search-deques" ABOUT: "search-deques"
HELP: <search-deque> ( assoc deque -- search-deque ) HELP: <search-deque> ( assoc deque -- search-deque )
{ $values { "assoc" assoc } { "deque" deque } { "search-deque" search-deque } } { $values { "assoc" assoc } { "deque" deque } { "search-deque" search-deque } }
{ $description "Creates a new " { $link search-deque } "." } ; { $description "Creates a new " { $link search-deque } "." } ;
HELP: <hashed-dlist> ( -- search-deque )
{ $values { "search-deque" search-deque } }
{ $description "Creates a new " { $link search-deque } " backed by a " { $link dlist } ", with a " { $link hashtable } " for fast membership tests." } ;

View File

@ -1,6 +1,6 @@
IN: search-deques.tests IN: search-deques.tests
USING: search-deques tools.test namespaces USING: search-deques tools.test namespaces
kernel sequences words deques vocabs ; kernel sequences words deques vocabs dlists ;
<hashed-dlist> "h" set <hashed-dlist> "h" set
@ -15,13 +15,11 @@ kernel sequences words deques vocabs ;
[ t ] [ "1" get "2" get eq? ] unit-test [ t ] [ "1" get "2" get eq? ] unit-test
[ t ] [ "2" get "3" get eq? ] unit-test [ t ] [ "2" get "3" get eq? ] unit-test
[ 3 ] [ "h" get deque-length ] unit-test
[ t ] [ 7 "h" get deque-member? ] unit-test [ t ] [ 7 "h" get deque-member? ] unit-test
[ 3 ] [ "1" get node-value ] unit-test [ 3 ] [ "1" get node-value ] unit-test
[ ] [ "1" get "h" get delete-node ] unit-test [ ] [ "1" get "h" get delete-node ] unit-test
[ 2 ] [ "h" get deque-length ] unit-test
[ 1 ] [ "h" get pop-back ] unit-test [ 1 ] [ "h" get pop-back ] unit-test
[ 7 ] [ "h" get pop-back ] unit-test [ 7 ] [ "h" get pop-back ] unit-test

View File

@ -1,16 +1,13 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel assocs deques dlists hashtables ; USING: accessors kernel assocs deques ;
IN: search-deques IN: search-deques
TUPLE: search-deque assoc deque ; TUPLE: search-deque assoc deque ;
C: <search-deque> search-deque C: <search-deque> search-deque
: <hashed-dlist> ( -- search-deque ) M: search-deque deque-empty? deque>> deque-empty? ;
0 <hashtable> <dlist> <search-deque> ;
M: search-deque deque-length deque>> deque-length ;
M: search-deque peek-front deque>> peek-front ; M: search-deque peek-front deque>> peek-front ;

View File

@ -5,6 +5,7 @@ math.vectors math.order sorting binary-search sets assocs fry ;
IN: suffix-arrays IN: suffix-arrays
<PRIVATE <PRIVATE
: suffixes ( string -- suffixes-seq ) : suffixes ( string -- suffixes-seq )
dup length [ tail-slice ] with map ; dup length [ tail-slice ] with map ;

View File

@ -1,5 +1,5 @@
USING: help.markup help.syntax kernel kernel.private io USING: help.markup help.syntax kernel kernel.private io
threads.private continuations dlists init quotations strings threads.private continuations init quotations strings
assocs heaps boxes namespaces deques ; assocs heaps boxes namespaces deques ;
IN: threads IN: threads
@ -82,7 +82,7 @@ $nl
{ $notes "In most cases, user code should call " { $link spawn } " instead, however for control over the error handler quotation, threads can be created with " { $link <thread> } " then passed to " { $link (spawn) } "." } ; { $notes "In most cases, user code should call " { $link spawn } " instead, however for control over the error handler quotation, threads can be created with " { $link <thread> } " then passed to " { $link (spawn) } "." } ;
HELP: run-queue HELP: run-queue
{ $values { "queue" dlist } } { $values { "queue" deque } }
{ $var-description "Global variable holding the queue of runnable threads. Calls to " { $link yield } " switch to the thread which has been in the queue for the longest period of time." { $var-description "Global variable holding the queue of runnable threads. Calls to " { $link yield } " switch to the thread which has been in the queue for the longest period of time."
$nl $nl
"By convention, threads are queued with " { $link push-front } "By convention, threads are queued with " { $link push-front }
@ -129,7 +129,7 @@ HELP: interrupt
{ $description "Interrupts a sleeping thread." } ; { $description "Interrupts a sleeping thread." } ;
HELP: suspend HELP: suspend
{ $values { "quot" "a quotation with stack effect " { $snippet "( thread -- )" } } { "state" string } { "obj" object } } { $values { "quot" { $quotation "( thread -- )" } } { "state" string } { "obj" object } }
{ $description "Suspends the current thread and passes it to the quotation." { $description "Suspends the current thread and passes it to the quotation."
$nl $nl
"After the quotation returns, control yields to the next runnable thread and the current thread does not execute again until it is resumed, and so the quotation must arrange for another thread to later resume the suspended thread with a call to " { $link resume } " or " { $link resume-with } "." "After the quotation returns, control yields to the next runnable thread and the current thread does not execute again until it is resumed, and so the quotation must arrange for another thread to later resume the suspended thread with a call to " { $link resume } " or " { $link resume-with } "."
@ -149,7 +149,7 @@ $nl
} ; } ;
HELP: spawn-server HELP: spawn-server
{ $values { "quot" "a quotation with stack effect " { $snippet "( -- ? )" } } { "name" string } { "thread" thread } } { $values { "quot" { $quotation "( -- ? )" } } { "name" string } { "thread" thread } }
{ $description "Convenience wrapper around " { $link spawn } " which repeatedly calls the quotation in a new thread until it outputs " { $link f } "." } { $description "Convenience wrapper around " { $link spawn } " which repeatedly calls the quotation in a new thread until it outputs " { $link f } "." }
{ $examples { $examples
"A thread that runs forever:" "A thread that runs forever:"
@ -172,5 +172,5 @@ HELP: tset
{ $description "Sets the value of a thread-local variable." } ; { $description "Sets the value of a thread-local variable." } ;
HELP: tchange HELP: tchange
{ $values { "key" object } { "quot" "a quotation with stack effect " { $snippet "( value -- newvalue )" } } } { $values { "key" object } { "quot" { $quotation "( value -- newvalue )" } } }
{ $description "Applies the quotation to the current value of a thread-local variable, storing the result back to the same variable." } ; { $description "Applies the quotation to the current value of a thread-local variable, storing the result back to the same variable." } ;

View File

@ -13,7 +13,7 @@ ARTICLE: "tools.annotations" "Word annotations"
ABOUT: "tools.annotations" ABOUT: "tools.annotations"
HELP: annotate HELP: annotate
{ $values { "word" "a word" } { "quot" "a quotation with stack effect " { $snippet "( word def -- def )" } } } { $values { "word" "a word" } { "quot" { $quotation "( word def -- def )" } } }
{ $description "Changes a word definition to the result of applying a quotation to the old definition." } { $description "Changes a word definition to the result of applying a quotation to the old definition." }
{ $notes "This word is used to implement " { $link watch } "." } ; { $notes "This word is used to implement " { $link watch } "." } ;
@ -28,7 +28,7 @@ HELP: breakpoint
{ $description "Annotates a word definition to enter the single stepper when executed." } ; { $description "Annotates a word definition to enter the single stepper when executed." } ;
HELP: breakpoint-if HELP: breakpoint-if
{ $values { "quot" "a quotation with stack effect" { $snippet "( -- ? )" } } { "word" word } } { $values { "quot" { $quotation "( -- ? )" } } { "word" word } }
{ $description "Annotates a word definition to enter the single stepper if the quotation yields true." } ; { $description "Annotates a word definition to enter the single stepper if the quotation yields true." } ;
HELP: annotate-methods HELP: annotate-methods

View File

@ -9,7 +9,7 @@ sorting compiler.units definitions ;
QUALIFIED: bootstrap.stage2 QUALIFIED: bootstrap.stage2
QUALIFIED: classes QUALIFIED: classes
QUALIFIED: command-line QUALIFIED: command-line
QUALIFIED: compiler.errors.private QUALIFIED: compiler.errors
QUALIFIED: continuations QUALIFIED: continuations
QUALIFIED: definitions QUALIFIED: definitions
QUALIFIED: init QUALIFIED: init
@ -291,7 +291,7 @@ IN: tools.deploy.shaker
strip-debugger? [ strip-debugger? [
{ {
compiler.errors.private:compiler-errors compiler.errors:compiler-errors
continuations:thread-error-hook continuations:thread-error-hook
} % } %
] when ] when

View File

@ -60,7 +60,7 @@ HELP: must-fail
{ $notes "This word is used to test boundary conditions and fail-fast behavior." } ; { $notes "This word is used to test boundary conditions and fail-fast behavior." } ;
HELP: must-fail-with HELP: must-fail-with
{ $values { "quot" "a quotation run with an empty stack" } { "pred" "a quotation with stack effect " { $snippet "( error -- ? )" } } } { $values { "quot" "a quotation run with an empty stack" } { "pred" { $quotation "( error -- ? )" } } }
{ $description "Runs a quotation with an empty stack, expecting it to throw an error which must satisfy " { $snippet "pred" } ". If the quotation does not throw an error, or if the error does not match the predicate, the unit test fails." } { $description "Runs a quotation with an empty stack, expecting it to throw an error which must satisfy " { $snippet "pred" } ". If the quotation does not throw an error, or if the error does not match the predicate, the unit test fails." }
{ $notes "This word is used to test error handling code, ensuring that errors thrown by code contain the relevant debugging information." } ; { $notes "This word is used to test error handling code, ensuring that errors thrown by code contain the relevant debugging information." } ;

View File

@ -71,7 +71,7 @@ HELP: command-word
{ $description "Outputs the word that will be executed by " { $link invoke-command } ". This is only used for documentation purposes." } ; { $description "Outputs the word that will be executed by " { $link invoke-command } ". This is only used for documentation purposes." } ;
HELP: command-map HELP: command-map
{ $values { "group" string } { "class" "a class word" } { "command-map" "a " { $link command-map } " or " { $link f } } } { $values { "group" string } { "class" "a class word" } { "command-map" { $maybe command-map } } }
{ $description "Outputs a named command map defined on a class." } { $description "Outputs a named command map defined on a class." }
{ $class-description "A command map stores a group of related commands. The " { $snippet "commands" } " slot stores an association list mapping gestures to commands, and the " { $snippet "blurb" } " slot stores an optional one-line description string of this command map." { $class-description "A command map stores a group of related commands. The " { $snippet "commands" } " slot stores an association list mapping gestures to commands, and the " { $snippet "blurb" } " slot stores an optional one-line description string of this command map."
$nl $nl
@ -82,7 +82,7 @@ HELP: commands
{ $description "Outputs a hashtable mapping command map names to " { $link command-map } " instances." } ; { $description "Outputs a hashtable mapping command map names to " { $link command-map } " instances." } ;
HELP: define-command-map HELP: define-command-map
{ $values { "class" "a class word" } { "group" string } { "blurb" "a " { $link string } " or " { $link f } } { "pairs" "a sequence of gesture/word pairs" } } { $values { "class" "a class word" } { "group" string } { "blurb" { $maybe string } } { "pairs" "a sequence of gesture/word pairs" } }
{ $description { $description
"Defines a command map on the specified gadget class. The " { $snippet "specs" } " parameter is a sequence of pairs " { $snippet "{ gesture word }" } ". The words must be valid commands; see " { $link define-command } "." "Defines a command map on the specified gadget class. The " { $snippet "specs" } " parameter is a sequence of pairs " { $snippet "{ gesture word }" } ". The words must be valid commands; see " { $link define-command } "."
} }

View File

@ -10,19 +10,19 @@ $nl
"A button can be selected, which is distinct from being pressed. This state is held in the " { $snippet "selected?" } " slot, and is used by the " { $link <toggle-buttons> } " word to construct a row of buttons for choosing among several alternatives." } ; "A button can be selected, which is distinct from being pressed. This state is held in the " { $snippet "selected?" } " slot, and is used by the " { $link <toggle-buttons> } " word to construct a row of buttons for choosing among several alternatives." } ;
HELP: <button> HELP: <button>
{ $values { "label" gadget } { "quot" "a quotation with stack effect " { $snippet "( button -- )" } } { "button" "a new " { $link button } } } { $values { "label" gadget } { "quot" { $quotation "( button -- )" } } { "button" "a new " { $link button } } }
{ $description "Creates a new " { $link button } " which calls the quotation when clicked. The given gadget becomes the button's only child." } ; { $description "Creates a new " { $link button } " which calls the quotation when clicked. The given gadget becomes the button's only child." } ;
HELP: <roll-button> HELP: <roll-button>
{ $values { "label" "a label specifier" } { "quot" "a quotation with stack effect " { $snippet "( button -- )" } } { "button" button } } { $values { "label" "a label specifier" } { "quot" { $quotation "( button -- )" } } { "button" button } }
{ $description "Creates a new " { $link button } " which is displayed with a solid border when it is under the mouse, informing the user that the gadget is clickable." } ; { $description "Creates a new " { $link button } " which is displayed with a solid border when it is under the mouse, informing the user that the gadget is clickable." } ;
HELP: <bevel-button> HELP: <bevel-button>
{ $values { "label" "a label specifier" } { "quot" "a quotation with stack effect " { $snippet "( button -- )" } } { "button" button } } { $values { "label" "a label specifier" } { "quot" { $quotation "( button -- )" } } { "button" button } }
{ $description "Creates a new " { $link button } " with a shaded border which is always visible. The button appearance changes in response to mouse gestures using a " { $link button-paint } "." } ; { $description "Creates a new " { $link button } " with a shaded border which is always visible. The button appearance changes in response to mouse gestures using a " { $link button-paint } "." } ;
HELP: <repeat-button> HELP: <repeat-button>
{ $values { "label" object } { "quot" "a quotation with stack effect " { $snippet "( button -- )" } } { "button" repeat-button } } { $values { "label" object } { "quot" { $quotation "( button -- )" } } { "button" repeat-button } }
{ $description "Creates a new " { $link button } " derived from a " { $link <bevel-button> } " which calls the quotation every 100 milliseconds as long as the mouse button is held down." } ; { $description "Creates a new " { $link button } " derived from a " { $link <bevel-button> } " which calls the quotation every 100 milliseconds as long as the mouse button is held down." } ;
HELP: button-paint HELP: button-paint

View File

@ -41,7 +41,7 @@ HELP: editor-mark*
{ $description "Outputs the current mark location as a line/column number pair." } ; { $description "Outputs the current mark location as a line/column number pair." } ;
HELP: change-caret HELP: change-caret
{ $values { "editor" editor } { "quot" "a quotation with stack effect " { $snippet "( loc -- newloc )" } } } { $values { "editor" editor } { "quot" { $quotation "( loc -- newloc )" } } }
{ $description "Applies a quotation to the current caret location and moves the caret to the location output by the quotation." } ; { $description "Applies a quotation to the current caret location and moves the caret to the location output by the quotation." } ;
{ change-caret change-caret&mark mark>caret } related-words { change-caret change-caret&mark mark>caret } related-words
@ -51,7 +51,7 @@ HELP: mark>caret
{ $description "Moves the mark to the caret location, effectively deselecting any selected text." } ; { $description "Moves the mark to the caret location, effectively deselecting any selected text." } ;
HELP: change-caret&mark HELP: change-caret&mark
{ $values { "editor" editor } { "quot" "a quotation with stack effect " { $snippet "( loc -- newloc )" } } } { $values { "editor" editor } { "quot" { $quotation "( loc -- newloc )" } } }
{ $description "Applies a quotation to the current caret location and moves the caret and the mark to the location output by the quotation." } ; { $description "Applies a quotation to the current caret location and moves the caret and the mark to the location output by the quotation." } ;
HELP: point>loc HELP: point>loc

View File

@ -34,7 +34,7 @@ HELP: children-on
{ $notes "This does not have to be an accurate intersection test, and simply returning " { $snippet "children" } " is a valid implementation. However, an accurate intersection test reduces the amount of work done when drawing this gadget if it is partially clipped and not all children are visible." } ; { $notes "This does not have to be an accurate intersection test, and simply returning " { $snippet "children" } " is a valid implementation. However, an accurate intersection test reduces the amount of work done when drawing this gadget if it is partially clipped and not all children are visible." } ;
HELP: pick-up HELP: pick-up
{ $values { "point" "a pair of integers" } { "gadget" gadget } { "child/f" "a " { $link gadget } " or " { $link f } } } { $values { "point" "a pair of integers" } { "gadget" gadget } { "child/f" { $maybe gadget } } }
{ $description "Outputs the child at a point in the gadget's co-ordinate system. This word recursively descends the gadget hierarchy, and so outputs the deepest child." } ; { $description "Outputs the child at a point in the gadget's co-ordinate system. This word recursively descends the gadget hierarchy, and so outputs the deepest child." } ;
HELP: max-dim HELP: max-dim
@ -44,7 +44,7 @@ HELP: max-dim
{ pref-dims max-dim dim-sum } related-words { pref-dims max-dim dim-sum } related-words
HELP: each-child HELP: each-child
{ $values { "gadget" gadget } { "quot" "a quotation with stack effect " { $snippet "( child -- )" } } } { $values { "gadget" gadget } { "quot" { $quotation "( child -- )" } } }
{ $description "Applies the quotation to each child of the gadget." } ; { $description "Applies the quotation to each child of the gadget." } ;
HELP: gadget-selection? HELP: gadget-selection?
@ -52,7 +52,7 @@ HELP: gadget-selection?
{ $contract "Outputs if the gadget has an active text selection; if so, the selected text can be obtained with a call to " { $link gadget-selection } "." } ; { $contract "Outputs if the gadget has an active text selection; if so, the selected text can be obtained with a call to " { $link gadget-selection } "." } ;
HELP: gadget-selection HELP: gadget-selection
{ $values { "gadget" gadget } { "string/f" "a " { $link string } " or " { $link f } } } { $values { "gadget" gadget } { "string/f" { $maybe string } } }
{ $contract "Outputs the gadget's text selection, or " { $link f } " if nothing is selected." } ; { $contract "Outputs the gadget's text selection, or " { $link f } " if nothing is selected." } ;
HELP: relayout HELP: relayout
@ -146,11 +146,11 @@ HELP: parents
{ $description "Outputs a sequence of all parents of the gadget, with the first element being the gadget itself." } ; { $description "Outputs a sequence of all parents of the gadget, with the first element being the gadget itself." } ;
HELP: each-parent HELP: each-parent
{ $values { "gadget" gadget } { "quot" "a quotation with stack effect " { $snippet "( gadget -- ? )" } } { "?" "a boolean" } } { $values { "gadget" gadget } { "quot" { $quotation "( gadget -- ? )" } } { "?" "a boolean" } }
{ $description "Applies the quotation to every parent of the gadget, starting from the gadget itself, stopping if the quotation yields " { $link f } ". Outputs " { $link t } " if the iteration completed, and outputs " { $link f } " if it was stopped prematurely." } ; { $description "Applies the quotation to every parent of the gadget, starting from the gadget itself, stopping if the quotation yields " { $link f } ". Outputs " { $link t } " if the iteration completed, and outputs " { $link f } " if it was stopped prematurely." } ;
HELP: find-parent HELP: find-parent
{ $values { "gadget" gadget } { "quot" "a quotation with stack effect " { $snippet "( gadget -- ? )" } } { "parent" gadget } } { $values { "gadget" gadget } { "quot" { $quotation "( gadget -- ? )" } } { "parent" gadget } }
{ $description "Outputs the first parent of the gadget, starting from the gadget itself, for which the quotation outputs a true value, or " { $link f } " if the quotation outputs " { $link f } " for every parent." } ; { $description "Outputs the first parent of the gadget, starting from the gadget itself, for which the quotation outputs a true value, or " { $link f } " if the quotation outputs " { $link f } " for every parent." } ;
HELP: screen-loc HELP: screen-loc

View File

@ -138,7 +138,7 @@ M: mock-gadget ungraft*
[ V{ { f t } } ] [ status-flags ] unit-test [ V{ { f t } } ] [ status-flags ] unit-test
dup [ [ ] [ notify-queued ] unit-test ] when dup [ [ ] [ notify-queued ] unit-test ] when
[ ] [ "g" get clear-gadget ] unit-test [ ] [ "g" get clear-gadget ] unit-test
[ [ 1 ] [ graft-queue length>> ] unit-test ] unless [ [ t ] [ graft-queue [ front>> ] [ back>> ] bi eq? ] unit-test ] unless
[ [ ] [ notify-queued ] unit-test ] when [ [ ] [ notify-queued ] unit-test ] when
[ ] [ add-some-children ] unit-test [ ] [ add-some-children ] unit-test
[ { f t } ] [ "1" get graft-state>> ] unit-test [ { f t } ] [ "1" get graft-state>> ] unit-test

View File

@ -13,12 +13,12 @@ HELP: closable-gadget
{ $class-description "A closable gadget displays a title bar with a close box on top of another gadget. Clicking the close box invokes a quotation. Closable gadgets are created by calling " { $link <closable-gadget> } "." } ; { $class-description "A closable gadget displays a title bar with a close box on top of another gadget. Clicking the close box invokes a quotation. Closable gadgets are created by calling " { $link <closable-gadget> } "." } ;
HELP: <closable-gadget> HELP: <closable-gadget>
{ $values { "gadget" gadget } { "title" string } { "quot" "a quotation with stack effect " { $snippet "( button -- )" } } } { $values { "gadget" gadget } { "title" string } { "quot" { $quotation "( button -- )" } } }
{ $description "Creates a new " { $link closable-gadget } ". Clicking the close box calls " { $snippet "quot" } "." } { $description "Creates a new " { $link closable-gadget } ". Clicking the close box calls " { $snippet "quot" } "." }
{ $notes "The quotation can find the " { $link closable-gadget } " instance, or any other parent gadget by calling " { $link find-parent } " with the gadget it receives on the stack." } ; { $notes "The quotation can find the " { $link closable-gadget } " instance, or any other parent gadget by calling " { $link find-parent } " with the gadget it receives on the stack." } ;
HELP: <labelled-pane> HELP: <labelled-pane>
{ $values { "model" model } { "quot" "a quotation with stack effect " { $snippet "( value -- )" } } { "scrolls?" "a boolean" } { "title" string } { "gadget" "a new " { $link gadget } } } { $values { "model" model } { "quot" { $quotation "( value -- )" } } { "scrolls?" "a boolean" } { "title" string } { "gadget" "a new " { $link gadget } } }
{ $description "Creates a new control delegating to a " { $link pane } ", and wraps it in a " { $link labelled-gadget } ". When the value of the model changes, the value is pushed on the stack and the quotation is called using " { $link with-pane } "." } ; { $description "Creates a new control delegating to a " { $link pane } ", and wraps it in a " { $link labelled-gadget } ". When the value of the model changes, the value is pushed on the stack and the quotation is called using " { $link with-pane } "." } ;
{ <labelled-pane> <pane-control> } related-words { <labelled-pane> <pane-control> } related-words

View File

@ -14,7 +14,7 @@ HELP: list
} ; } ;
HELP: <list> HELP: <list>
{ $values { "hook" "a quotation with stack effect " { $snippet "( list -- )" } } { "presenter" "a quotation with stack effect " { $snippet "( object -- label )" } } { "model" model } { "gadget" list } } { $values { "hook" { $quotation "( list -- )" } } { "presenter" { $quotation "( object -- label )" } } { "model" model } { "gadget" list } }
{ $description "Creates a new " { $link list } "." { $description "Creates a new " { $link list } "."
$nl $nl
"The model value must be a sequence. The list displays presentations of elements with labels obtained by applying the " { $snippet "presenter" } " quotation to each object. The " { $snippet "hook" } " quotation is called when a presentation is selected." } ; "The model value must be a sequence. The list displays presentations of elements with labels obtained by applying the " { $snippet "presenter" } " quotation to each object. The " { $snippet "hook" } " quotation is called when a presentation is selected." } ;

View File

@ -3,7 +3,7 @@ kernel ;
IN: ui.gadgets.menus IN: ui.gadgets.menus
HELP: <commands-menu> HELP: <commands-menu>
{ $values { "hook" "a quotation with stack effect " { $snippet "( button -- )" } } { "target" object } { "commands" "a sequence of commands" } { "gadget" "a new " { $link gadget } } } { $values { "hook" { $quotation "( button -- )" } } { "target" object } { "commands" "a sequence of commands" } { "gadget" "a new " { $link gadget } } }
{ $description "Creates a popup menu of commands which are to be invoked on " { $snippet "target" } ". The " { $snippet "hook" } " quotation is run before a command is invoked." } ; { $description "Creates a popup menu of commands which are to be invoked on " { $snippet "target" } ". The " { $snippet "hook" } " quotation is run before a command is invoked." } ;
HELP: show-menu HELP: show-menu

View File

@ -43,7 +43,7 @@ HELP: <scrolling-pane>
{ $description "Creates a new " { $link pane } " gadget which scrolls any scroll pane containing it to the bottom on output. behaving much like a terminal or logger." } ; { $description "Creates a new " { $link pane } " gadget which scrolls any scroll pane containing it to the bottom on output. behaving much like a terminal or logger." } ;
HELP: <pane-control> HELP: <pane-control>
{ $values { "model" model } { "quot" "a quotation with stack effect " { $snippet "( value -- )" } } { "pane" "a new " { $link pane } } } { $values { "model" model } { "quot" { $quotation "( value -- )" } } { "pane" "a new " { $link pane } } }
{ $description "Creates a new control delegating to a " { $link pane } ". When the value of the model changes, the value is pushed on the stack and the quotation is called using " { $link with-pane } "." } ; { $description "Creates a new control delegating to a " { $link pane } ". When the value of the model changes, the value is pushed on the stack and the quotation is called using " { $link with-pane } "." } ;
HELP: pane-stream HELP: pane-stream

View File

@ -8,7 +8,7 @@ $nl
"Scroller gadgets are created by calling " { $link <scroller> } "." } ; "Scroller gadgets are created by calling " { $link <scroller> } "." } ;
HELP: find-scroller HELP: find-scroller
{ $values { "gadget" gadget } { "scroller/f" "a " { $link scroller } " or " { $link f } } } { $values { "gadget" gadget } { "scroller/f" { $maybe scroller } } }
{ $description "Finds the first parent of " { $snippet "gadget" } " which is a " { $link scroller } ". Outputs " { $link f } " if the gadget is not contained in a " { $link scroller } "." } ; { $description "Finds the first parent of " { $snippet "gadget" } " which is a " { $link scroller } ". Outputs " { $link f } " if the gadget is not contained in a " { $link scroller } "." } ;
HELP: scroller-value HELP: scroller-value

View File

@ -5,7 +5,7 @@ HELP: elevator
{ $class-description "An elevator is the part of a " { $link slider } " between the up/down arrow buttons, where a " { $link thumb } " may be moved up and down." } ; { $class-description "An elevator is the part of a " { $link slider } " between the up/down arrow buttons, where a " { $link thumb } " may be moved up and down." } ;
HELP: find-elevator HELP: find-elevator
{ $values { "gadget" gadget } { "elevator/f" "an " { $link elevator } " or " { $link f } } } { $values { "gadget" gadget } { "elevator/f" { $maybe elevator } } }
{ $description "Finds the first parent of " { $snippet "gadget" } " which is an " { $link elevator } ". Outputs " { $link f } " if the gadget is not contained in an " { $link elevator } "." } ; { $description "Finds the first parent of " { $snippet "gadget" } " which is an " { $link elevator } ". Outputs " { $link f } " if the gadget is not contained in an " { $link elevator } "." } ;
HELP: slider HELP: slider
@ -14,7 +14,7 @@ $nl
"Sliders are created by calling " { $link <x-slider> } " or " { $link <y-slider> } "." } ; "Sliders are created by calling " { $link <x-slider> } " or " { $link <y-slider> } "." } ;
HELP: find-slider HELP: find-slider
{ $values { "gadget" gadget } { "slider/f" "a " { $link slider } " or " { $link f } } } { $values { "gadget" gadget } { "slider/f" { $maybe slider } } }
{ $description "Finds the first parent of " { $snippet "gadget" } " which is a " { $link slider } ". Outputs " { $link f } " if the gadget is not contained in a " { $link slider } "." } ; { $description "Finds the first parent of " { $snippet "gadget" } " which is a " { $link slider } ". Outputs " { $link f } " if the gadget is not contained in a " { $link slider } "." } ;
HELP: thumb HELP: thumb

View File

@ -46,7 +46,7 @@ HELP: <world>
{ $description "Creates a new " { $link world } " delegating to the given gadget." } ; { $description "Creates a new " { $link world } " delegating to the given gadget." } ;
HELP: find-world HELP: find-world
{ $values { "gadget" gadget } { "world/f" "a " { $link world } " or " { $link f } } } { $values { "gadget" gadget } { "world/f" { $maybe world } } }
{ $description "Finds the " { $link world } " containing the gadget, or outputs " { $link f } " if the gadget is not grafted." } ; { $description "Finds the " { $link world } " containing the gadget, or outputs " { $link f } " if the gadget is not grafted." } ;
HELP: draw-world HELP: draw-world

View File

@ -189,7 +189,7 @@ HELP: under-hand
{ $description "Outputs a sequence where the first element is the " { $link hand-world } " and the last is the " { $link hand-gadget } ", with all parents in between." } ; { $description "Outputs a sequence where the first element is the " { $link hand-world } " and the last is the " { $link hand-gadget } ", with all parents in between." } ;
HELP: gesture>string HELP: gesture>string
{ $values { "gesture" "a gesture" } { "string/f" "a " { $link string } " or " { $link f } } } { $values { "gesture" "a gesture" } { "string/f" { $maybe string } } }
{ $contract "Creates a human-readable string from a gesture object, returning " { $link f } " if the gesture does not have a human-readable form." } { $contract "Creates a human-readable string from a gesture object, returning " { $link f } " if the gesture does not have a human-readable form." }
{ $examples { $examples
{ $example "USING: io ui.gestures ;" "T{ key-down f { C+ } \"x\" } gesture>string print" "C+x" } { $example "USING: io ui.gestures ;" "T{ key-down f { C+ } \"x\" } gesture>string print" "C+x" }

View File

@ -41,15 +41,15 @@ HELP: object-operations
{ $description "Outputs a sequence of operations applicable to the given object, by testing each defined operation's " { $snippet "predicate" } " quotation in turn." } ; { $description "Outputs a sequence of operations applicable to the given object, by testing each defined operation's " { $snippet "predicate" } " quotation in turn." } ;
HELP: primary-operation HELP: primary-operation
{ $values { "obj" object } { "operation" "an " { $link operation } " or " { $link f } } } { $values { "obj" object } { "operation" { $maybe operation } } }
{ $description "Outputs the operation which should be invoked when a presentation of " { $snippet "obj" } " is clicked." } ; { $description "Outputs the operation which should be invoked when a presentation of " { $snippet "obj" } " is clicked." } ;
HELP: secondary-operation HELP: secondary-operation
{ $values { "obj" object } { "operation" "an " { $link operation } " or " { $link f } } } { $values { "obj" object } { "operation" { $maybe operation } } }
{ $description "Outputs the operation which should be invoked when a " { $snippet "RET" } " is pressed while a presentation of " { $snippet "obj" } " is selected in a list." } ; { $description "Outputs the operation which should be invoked when a " { $snippet "RET" } " is pressed while a presentation of " { $snippet "obj" } " is selected in a list." } ;
HELP: define-operation HELP: define-operation
{ $values { "pred" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "command" word } { "flags" hashtable } } { $values { "pred" { $quotation "( obj -- ? )" } } { "command" word } { "flags" hashtable } }
{ $description "Defines an operation on objects matching the predicate. The hashtable can contain the following keys:" { $description "Defines an operation on objects matching the predicate. The hashtable can contain the following keys:"
{ $list { $list
{ { $link +listener+ } " - if set to a true value, the operation will run in the listener" } { { $link +listener+ } " - if set to a true value, the operation will run in the listener" }
@ -61,7 +61,7 @@ HELP: define-operation
} ; } ;
HELP: define-operation-map HELP: define-operation-map
{ $values { "class" "a class word" } { "group" string } { "blurb" "a " { $link string } " or " { $link f } } { "object" object } { "hook" "a quotation with stack effect " { $snippet "( obj -- newobj )" } ", or " { $link f } } { "translator" "a quotation with stack effect " { $snippet "( obj -- newobj )" } ", or " { $link f } } } { $values { "class" "a class word" } { "group" string } { "blurb" { $maybe string } } { "object" object } { "hook" { $quotation "( obj -- newobj )" } ", or " { $link f } } { "translator" { $quotation "( obj -- newobj )" } ", or " { $link f } } }
{ $description "Defines a command map named " { $snippet "group" } " on " { $snippet "class" } " consisting of operations applicable to " { $snippet "object" } ". The hook quotation is applied to the target gadget; the translator quotation is applied to the result of the hook. Finally the result of the translator is passed to the operation. A distinction is drawn between the hook and the translator because for listener operations, the hook runs in the event loop and the translator runs in the listener. This avoids polluting the listener output with large prettyprinted gadgets and long quotations." } ; { $description "Defines a command map named " { $snippet "group" } " on " { $snippet "class" } " consisting of operations applicable to " { $snippet "object" } ". The hook quotation is applied to the target gadget; the translator quotation is applied to the result of the hook. Finally the result of the translator is passed to the operation. A distinction is drawn between the hook and the translator because for listener operations, the hook runs in the event loop and the translator runs in the listener. This avoids polluting the listener output with large prettyprinted gadgets and long quotations." } ;
HELP: $operations HELP: $operations

View File

@ -3,7 +3,7 @@ continuations debugger ui ;
IN: ui.tools.debugger IN: ui.tools.debugger
HELP: <debugger> HELP: <debugger>
{ $values { "error" "an error" } { "restarts" "a sequence of " { $link restart } " instances" } { "restart-hook" "a quotation with stack effect " { $snippet "( list -- )" } } { "gadget" "a new " { $link gadget } } } { $values { "error" "an error" } { "restarts" "a sequence of " { $link restart } " instances" } { "restart-hook" { $quotation "( list -- )" } } { "gadget" "a new " { $link gadget } } }
{ $description { $description
"Creates a gadget displaying a description of the error, along with buttons to print the contents of the stacks in the listener, and a list of restarts." "Creates a gadget displaying a description of the error, along with buttons to print the contents of the stacks in the listener, and a list of restarts."
} ; } ;

View File

@ -23,7 +23,7 @@ HELP: fullscreen?
{ fullscreen? set-fullscreen? } related-words { fullscreen? set-fullscreen? } related-words
HELP: find-window HELP: find-window
{ $values { "quot" "a quotation with stack effect " { $snippet "( world -- ? )" } } { "world" "a " { $link world } " or " { $link f } } } { $values { "quot" { $quotation "( world -- ? )" } } { "world" { $maybe world } } }
{ $description "Finds a native window such that the gadget passed to " { $link open-window } " satisfies the quotation, outputting " { $link f } " if no such gadget could be found. The front-most native window is checked first." } ; { $description "Finds a native window such that the gadget passed to " { $link open-window } " satisfies the quotation, outputting " { $link f } " if no such gadget could be found. The front-most native window is checked first." } ;
HELP: register-window HELP: register-window

View File

@ -0,0 +1,22 @@
IN: unrolled-lists
USING: help.markup help.syntax hashtables search-deques dlists
deques ;
HELP: unrolled-list
{ $class-description "The class of unrolled lists." } ;
HELP: <unrolled-list>
{ $values { "list" unrolled-list } }
{ $description "Creates a new unrolled list." } ;
HELP: <hashed-unrolled-list>
{ $values { "search-deque" search-deque } }
{ $description "Creates a new " { $link search-deque } " backed by an " { $link unrolled-list } ", with a " { $link hashtable } " for fast membership tests." } ;
ARTICLE: "unrolled-lists" "Unrolled lists"
"The " { $vocab-link "unrolled-lists" } " vocabulary provides an implementation of the " { $link deque } " protocol with constant time insertion and removal at both ends, and lower memory overhead than a " { $link dlist } " due to packing 32 elements per every node. The one tradeoff is that unlike dlists, " { $link delete-node } " is not supported for unrolled lists."
{ $subsection unrolled-list }
{ $subsection <unrolled-list> }
{ $subsection <hashed-unrolled-list> } ;
ABOUT: "unrolled-lists"

View File

@ -0,0 +1,130 @@
USING: unrolled-lists tools.test deques kernel sequences
random prettyprint grouping ;
IN: unrolled-lists.tests
[ 1 ] [ <unrolled-list> 1 over push-front pop-front ] unit-test
[ 1 ] [ <unrolled-list> 1 over push-front pop-back ] unit-test
[ 1 ] [ <unrolled-list> 1 over push-back pop-front ] unit-test
[ 1 ] [ <unrolled-list> 1 over push-back pop-back ] unit-test
[ 1 2 ] [
<unrolled-list> 1 over push-back 2 over push-back
[ pop-front ] [ pop-front ] bi
] unit-test
[ 2 1 ] [
<unrolled-list> 1 over push-back 2 over push-back
[ pop-back ] [ pop-back ] bi
] unit-test
[ 1 2 3 ] [
<unrolled-list>
1 over push-back
2 over push-back
3 over push-back
[ pop-front ] [ pop-front ] [ pop-front ] tri
] unit-test
[ 3 2 1 ] [
<unrolled-list>
1 over push-back
2 over push-back
3 over push-back
[ pop-back ] [ pop-back ] [ pop-back ] tri
] unit-test
[ { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 } ] [
<unrolled-list>
32 [ over push-front ] each
32 [ dup pop-back ] replicate
nip
] unit-test
[ { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 } ] [
<unrolled-list>
32 [ over push-front ] each
32 [ dup pop-front ] replicate reverse
nip
] unit-test
[ t ] [
<unrolled-list>
1000 [ 1000 random ] replicate
[ [ over push-front ] each ]
[ [ dup pop-back ] replicate ]
[ ]
tri
=
nip
] unit-test
[ t ] [
<unrolled-list>
1000 [ 1000 random ] replicate
[
10 group [
[ [ over push-front ] each ]
[ [ dup pop-back ] replicate ]
bi
] map concat
] keep
=
nip
] unit-test
[ t ] [ <unrolled-list> deque-empty? ] unit-test
[ t ] [
<unrolled-list>
1 over push-front
dup pop-front*
deque-empty?
] unit-test
[ t ] [
<unrolled-list>
1 over push-back
dup pop-front*
deque-empty?
] unit-test
[ t ] [
<unrolled-list>
1 over push-front
dup pop-back*
deque-empty?
] unit-test
[ t ] [
<unrolled-list>
1 over push-back
dup pop-back*
deque-empty?
] unit-test
[ t ] [
<unrolled-list>
21 over push-front
22 over push-front
25 over push-front
26 over push-front
dup pop-back 21 assert=
28 over push-front
dup pop-back 22 assert=
29 over push-front
dup pop-back 25 assert=
24 over push-front
dup pop-back 26 assert=
23 over push-front
dup pop-back 28 assert=
dup pop-back 29 assert=
dup pop-back 24 assert=
17 over push-front
dup pop-back 23 assert=
27 over push-front
dup pop-back 17 assert=
30 over push-front
dup pop-back 27 assert=
dup pop-back 30 assert=
deque-empty?
] unit-test

View File

@ -0,0 +1,140 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays math kernel accessors sequences sequences.private
deques search-deques hashtables ;
IN: unrolled-lists
: unroll-factor 32 ; inline
<PRIVATE
MIXIN: ?node
INSTANCE: f ?node
TUPLE: node { data array } { prev ?node } { next ?node } ;
INSTANCE: node ?node
PRIVATE>
TUPLE: unrolled-list
{ front ?node } { front-pos fixnum }
{ back ?node } { back-pos fixnum } ;
: <unrolled-list> ( -- list )
unrolled-list new
unroll-factor >>back-pos ; inline
: <hashed-unrolled-list> ( -- search-deque )
20 <hashtable> <unrolled-list> <search-deque> ;
ERROR: empty-unrolled-list list ;
<PRIVATE
M: unrolled-list deque-empty?
dup [ front>> ] [ back>> ] bi dup [
eq? [ [ front-pos>> ] [ back-pos>> ] bi eq? ] [ drop f ] if
] [ 3drop t ] if ;
M: unrolled-list clear-deque
f >>front
0 >>front-pos
f >>back
unroll-factor >>back-pos
drop ;
: <front-node> ( elt front -- node )
[
unroll-factor 0 <array>
[ unroll-factor 1- swap set-nth ] keep f
] dip [ node boa dup ] keep
dup [ (>>prev) ] [ 2drop ] if ; inline
: normalize-back ( list -- )
dup back>> [
dup prev>> [ drop ] [ swap front>> >>prev ] if
] [ dup front>> >>back ] if* drop ; inline
: push-front/new ( elt list -- )
unroll-factor 1- >>front-pos
[ <front-node> ] change-front
normalize-back ; inline
: push-front/existing ( elt list front -- )
[ [ 1- ] change-front-pos ] dip
[ front-pos>> ] [ data>> ] bi* set-nth-unsafe ; inline
M: unrolled-list push-front*
dup [ front>> ] [ front-pos>> 0 eq? not ] bi
[ drop ] [ and ] 2bi
[ push-front/existing ] [ drop push-front/new ] if f ;
M: unrolled-list peek-front
dup front>>
[ [ front-pos>> ] dip data>> nth-unsafe ]
[ empty-unrolled-list ]
if* ;
: pop-front/new ( list front -- )
[ 0 >>front-pos ] dip
[ f ] change-next drop dup [ f >>prev ] when >>front
dup front>> [ normalize-back ] [ f >>back drop ] if ; inline
: pop-front/existing ( list front -- )
[ dup front-pos>> ] [ data>> ] bi* [ 0 ] 2dip set-nth-unsafe
[ 1+ ] change-front-pos
drop ; inline
M: unrolled-list pop-front*
dup front>> [ empty-unrolled-list ] unless*
over front-pos>> unroll-factor 1- eq?
[ pop-front/new ] [ pop-front/existing ] if ;
: <back-node> ( elt back -- node )
[
unroll-factor 0 <array> [ set-first ] keep
] dip [ f node boa dup ] keep
dup [ (>>next) ] [ 2drop ] if ; inline
: normalize-front ( list -- )
dup front>> [
dup next>> [ drop ] [ swap back>> >>next ] if
] [ dup back>> >>front ] if* drop ; inline
: push-back/new ( elt list -- )
1 >>back-pos
[ <back-node> ] change-back
normalize-front ; inline
: push-back/existing ( elt list back -- )
[ [ 1+ ] change-back-pos ] dip
[ back-pos>> 1- ] [ data>> ] bi* set-nth-unsafe ; inline
M: unrolled-list push-back*
dup [ back>> ] [ back-pos>> unroll-factor eq? not ] bi
[ drop ] [ and ] 2bi
[ push-back/existing ] [ drop push-back/new ] if f ;
M: unrolled-list peek-back
dup back>>
[ [ back-pos>> 1- ] dip data>> nth-unsafe ]
[ empty-unrolled-list ]
if* ;
: pop-back/new ( list back -- )
[ unroll-factor >>back-pos ] dip
[ f ] change-prev drop dup [ f >>next ] when >>back
dup back>> [ normalize-front ] [ f >>front drop ] if ; inline
: pop-back/existing ( list back -- )
[ [ 1- ] change-back-pos ] dip
[ dup back-pos>> ] [ data>> ] bi* [ 0 ] 2dip set-nth-unsafe
drop ; inline
M: unrolled-list pop-back*
dup back>> [ empty-unrolled-list ] unless*
over back-pos>> 1 eq?
[ pop-back/new ] [ pop-back/existing ] if ;
PRIVATE>
INSTANCE: unrolled-list deque

View File

@ -77,7 +77,7 @@ HELP: ensure-port
} ; } ;
HELP: parse-host HELP: parse-host
{ $values { "string" string } { "host" string } { "port" "an " { $link integer } " or " { $link f } } } { $values { "string" string } { "host" string } { "port" { $maybe integer } } }
{ $description "Splits a string of the form " { $snippet "host:port" } " into a host and a port number. If the port number is not specified, outputs " { $link f } "." } { $description "Splits a string of the form " { $snippet "host:port" } " into a host and a port number. If the port number is not specified, outputs " { $link f } "." }
{ $notes "This word is used by " { $link >url } ". It can also be used directly to parse " { $snippet "host:port" } " strings which are not full URLs." } { $notes "This word is used by " { $link >url } ". It can also be used directly to parse " { $snippet "host:port" } " strings which are not full URLs." }
{ $examples { $examples
@ -89,13 +89,13 @@ HELP: parse-host
} ; } ;
HELP: protocol-port HELP: protocol-port
{ $values { "protocol" "a protocol string" } { "port" "an " { $link integer } " or " { $link f } } } { $values { "protocol" "a protocol string" } { "port" { $maybe integer } } }
{ $description "Outputs the port number associated with a protocol, or " { $link f } " if the protocol is unknown." } ; { $description "Outputs the port number associated with a protocol, or " { $link f } " if the protocol is unknown." } ;
HELP: query-param HELP: query-param
{ $values { $values
{ "url" url } { "key" string } { "url" url } { "key" string }
{ "value" "a " { $link string } " or " { $link f } } } { "value" { $maybe string } } }
{ $description "Outputs the URL-decoded value of a URL query parameter." } { $description "Outputs the URL-decoded value of a URL query parameter." }
{ $examples { $examples
{ $example { $example

View File

@ -35,5 +35,5 @@ HELP: to:
} ; } ;
HELP: change-value HELP: change-value
{ $values { "word" "a value word" } { "quot" "a quotation with stack effect " { $snippet "( oldvalue -- newvalue )" } } } { $values { "word" "a value word" } { "quot" { $quotation "( oldvalue -- newvalue )" } } }
{ $description "Changes the value using the given quotation." } ; { $description "Changes the value using the given quotation." } ;

View File

@ -161,7 +161,7 @@ HELP: new-assoc
{ $contract "Creates a new assoc of the same size as " { $snippet "exemplar" } " which can hold " { $snippet "capacity" } " entries before growing." } ; { $contract "Creates a new assoc of the same size as " { $snippet "exemplar" } " which can hold " { $snippet "capacity" } " entries before growing." } ;
HELP: assoc-find HELP: assoc-find
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- ? )" } } { "key" "the successful key, or f" } { "value" "the successful value, or f" } { "?" "a boolean" } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "key" "the successful key, or f" } { "value" "the successful value, or f" } { "?" "a boolean" } }
{ $description "Applies a predicate quotation to each entry in the assoc. Returns the key and value that the quotation succeeds on, or " { $link f } " for both if the quotation fails. It also returns a boolean describing whether there was anything found; this can be used to distinguish between a key and a value equal to " { $link f } ", or nothing being found." } ; { $description "Applies a predicate quotation to each entry in the assoc. Returns the key and value that the quotation succeeds on, or " { $link f } " for both if the quotation fails. It also returns a boolean describing whether there was anything found; this can be used to distinguish between a key and a value equal to " { $link f } ", or nothing being found." } ;
HELP: clear-assoc HELP: clear-assoc
@ -197,7 +197,7 @@ HELP: at
{ $description "Looks up the value associated with a key. This word makes no distinction between a missing value and a value set to " { $link f } "; if the difference is important, use " { $link at* } "." } ; { $description "Looks up the value associated with a key. This word makes no distinction between a missing value and a value set to " { $link f } "; if the difference is important, use " { $link at* } "." } ;
HELP: assoc-each HELP: assoc-each
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- )" } } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- )" } } }
{ $description "Applies a quotation to each entry in the assoc." } { $description "Applies a quotation to each entry in the assoc." }
{ $examples { $examples
{ $example { $example
@ -209,7 +209,7 @@ HELP: assoc-each
} ; } ;
HELP: assoc-map HELP: assoc-map
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- newkey newvalue )" } } { "newassoc" "a new assoc" } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- newkey newvalue )" } } { "newassoc" "a new assoc" } }
{ $description "Applies the quotation to each entry in the input assoc and collects the results in a new assoc of the same type as the input." } { $description "Applies the quotation to each entry in the input assoc and collects the results in a new assoc of the same type as the input." }
{ $examples { $examples
{ $unchecked-example { $unchecked-example
@ -224,19 +224,19 @@ HELP: assoc-map
{ assoc-map assoc-map-as } related-words { assoc-map assoc-map-as } related-words
HELP: assoc-push-if HELP: assoc-push-if
{ $values { "accum" "a resizable mutable sequence" } { "quot" "a quotation with stack effect " { $snippet "( key value -- ? )" } } { "key" object } { "value" object } } { $values { "accum" "a resizable mutable sequence" } { "quot" { $quotation "( key value -- ? )" } } { "key" object } { "value" object } }
{ $description "If the quotation yields true when applied to the key/value pair, adds the key/value pair at the end of " { $snippet "accum" } "." } ; { $description "If the quotation yields true when applied to the key/value pair, adds the key/value pair at the end of " { $snippet "accum" } "." } ;
HELP: assoc-filter HELP: assoc-filter
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- ? )" } } { "subassoc" "a new assoc" } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "subassoc" "a new assoc" } }
{ $description "Outputs an assoc of the same type as " { $snippet "assoc" } " consisting of all entries for which the predicate quotation yields true." } ; { $description "Outputs an assoc of the same type as " { $snippet "assoc" } " consisting of all entries for which the predicate quotation yields true." } ;
HELP: assoc-contains? HELP: assoc-contains?
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- ? )" } } { "?" "a boolean" } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "?" "a boolean" } }
{ $description "Tests if the assoc contains an entry satisfying a predicate by applying the quotation to each entry in turn. Iteration stops if an entry is found for which the quotation outputs a true value." } ; { $description "Tests if the assoc contains an entry satisfying a predicate by applying the quotation to each entry in turn. Iteration stops if an entry is found for which the quotation outputs a true value." } ;
HELP: assoc-all? HELP: assoc-all?
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- ? )" } } { "?" "a boolean" } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "?" "a boolean" } }
{ $description "Tests if all entries in the assoc satisfy a predicate by applying the quotation to each entry in turn. a predicate quotation to entry in the assoc. Iteration stops if an entry is found for which the quotation outputs " { $link f } ". If the assoc is empty, always outputs " { $link t } "." } ; { $description "Tests if all entries in the assoc satisfy a predicate by applying the quotation to each entry in turn. a predicate quotation to entry in the assoc. Iteration stops if an entry is found for which the quotation outputs " { $link f } ". If the assoc is empty, always outputs " { $link t } "." } ;
HELP: assoc-subset? HELP: assoc-subset?
@ -325,20 +325,20 @@ HELP: substitute
{ $description "Creates a new sequence where elements of " { $snippet "seq" } " which appear as keys in " { $snippet "assoc" } " are replaced by the corresponding values, and all other elements are unchanged." } ; { $description "Creates a new sequence where elements of " { $snippet "seq" } " which appear as keys in " { $snippet "assoc" } " are replaced by the corresponding values, and all other elements are unchanged." } ;
HELP: cache HELP: cache
{ $values { "key" "a key" } { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key -- value )" } } { "value" "a previously-retained or freshly-computed value" } } { $values { "key" "a key" } { "assoc" assoc } { "quot" { $quotation "( key -- value )" } } { "value" "a previously-retained or freshly-computed value" } }
{ $description "If the key is present in the assoc, outputs the associated value, otherwise calls the quotation to produce a value and stores the key/value pair into the assoc." } { $description "If the key is present in the assoc, outputs the associated value, otherwise calls the quotation to produce a value and stores the key/value pair into the assoc." }
{ $side-effects "assoc" } ; { $side-effects "assoc" } ;
HELP: map>assoc HELP: map>assoc
{ $values { "seq" "a sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- key value )" } } { "exemplar" assoc } { "assoc" "a new assoc" } } { $values { "seq" "a sequence" } { "quot" { $quotation "( elt -- key value )" } } { "exemplar" assoc } { "assoc" "a new assoc" } }
{ $description "Applies the quotation to each element of the sequence, and collects the keys and values into a new assoc having the same type as " { $snippet "exemplar" } "." } ; { $description "Applies the quotation to each element of the sequence, and collects the keys and values into a new assoc having the same type as " { $snippet "exemplar" } "." } ;
HELP: assoc>map HELP: assoc>map
{ $values { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( key value -- elt )" } } { "exemplar" "a sequence" } { "seq" "a new sequence" } } { $values { "assoc" assoc } { "quot" { $quotation "( key value -- elt )" } } { "exemplar" "a sequence" } { "seq" "a new sequence" } }
{ $description "Applies the quotation to each entry of the assoc and collects the results into a new sequence of the same type as the exemplar." } ; { $description "Applies the quotation to each entry of the assoc and collects the results into a new sequence of the same type as the exemplar." } ;
HELP: change-at HELP: change-at
{ $values { "key" object } { "assoc" assoc } { "quot" "a quotation with stack effect " { $snippet "( value -- newvalue )" } } } { $values { "key" object } { "assoc" assoc } { "quot" { $quotation "( value -- newvalue )" } } }
{ $description "Applies the quotation to the value associated with " { $snippet "key" } ", storing the new value back in the assoc." } { $description "Applies the quotation to the value associated with " { $snippet "key" } ", storing the new value back in the assoc." }
{ $side-effects "assoc" } ; { $side-effects "assoc" } ;

View File

@ -14,7 +14,7 @@ ARTICLE: "predicates" "Predicate classes"
ABOUT: "predicates" ABOUT: "predicates"
HELP: define-predicate-class HELP: define-predicate-class
{ $values { "class" class } { "superclass" class } { "definition" "a quotation with stack effect " { $snippet "( superclass -- ? )" } } } { $values { "class" class } { "superclass" class } { "definition" { $quotation "( superclass -- ? )" } } }
{ $description "Defines a predicate class. This is the run time equivalent of " { $link POSTPONE: PREDICATE: } "." } { $description "Defines a predicate class. This is the run time equivalent of " { $link POSTPONE: PREDICATE: } "." }
{ $notes "This word must be called from inside " { $link with-compilation-unit } "." } { $notes "This word must be called from inside " { $link with-compilation-unit } "." }
{ $side-effects "class" } ; { $side-effects "class" } ;

View File

@ -137,7 +137,7 @@ HELP: no-case
{ $error-description "Thrown by " { $link case } " if the object at the top of the stack does not match any case, and no default case is given." } ; { $error-description "Thrown by " { $link case } " if the object at the top of the stack does not match any case, and no default case is given." } ;
HELP: recursive-hashcode HELP: recursive-hashcode
{ $values { "n" integer } { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( n obj -- code )" } } { "code" integer } } { $values { "n" integer } { "obj" object } { "quot" { $quotation "( n obj -- code )" } } { "code" integer } }
{ $description "A combinator used to implement methods for the " { $link hashcode* } " generic word. If " { $snippet "n" } " is less than or equal to zero, outputs 0, otherwise calls the quotation." } ; { $description "A combinator used to implement methods for the " { $link hashcode* } " generic word. If " { $snippet "n" } " is less than or equal to zero, outputs 0, otherwise calls the quotation." } ;
HELP: cond>quot HELP: cond>quot
@ -159,7 +159,7 @@ $nl
} } ; } } ;
HELP: distribute-buckets HELP: distribute-buckets
{ $values { "alist" "an alist" } { "initial" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- assoc )" } } { "buckets" "a new array" } } { $values { "alist" "an alist" } { "initial" object } { "quot" { $quotation "( obj -- assoc )" } } { "buckets" "a new array" } }
{ $description "Sorts the entries of " { $snippet "assoc" } " into buckets, using the quotation to yield a set of keys for each entry. The hashcode of each key is computed, and the entry is placed in all corresponding buckets. Each bucket is initially cloned from " { $snippet "initial" } "; this should either be an empty vector or a one-element vector containing a pair." } { $description "Sorts the entries of " { $snippet "assoc" } " into buckets, using the quotation to yield a set of keys for each entry. The hashcode of each key is computed, and the entry is placed in all corresponding buckets. Each bucket is initially cloned from " { $snippet "initial" } "; this should either be an empty vector or a one-element vector containing a pair." }
{ $notes "This word is used in the implemention of " { $link hash-case-quot } " and " { $link standard-combination } "." } ; { $notes "This word is used in the implemention of " { $link hash-case-quot } " and " { $link standard-combination } "." } ;

View File

@ -1,6 +1,6 @@
IN: compiler.errors IN: compiler.errors
USING: help.markup help.syntax vocabs.loader words io USING: help.markup help.syntax vocabs.loader words io
quotations compiler.errors.private ; quotations ;
ARTICLE: "compiler-errors" "Compiler warnings and errors" ARTICLE: "compiler-errors" "Compiler warnings and errors"
"The compiler saves various notifications in a global variable:" "The compiler saves various notifications in a global variable:"

View File

@ -14,8 +14,6 @@ M: object compiler-error-type drop +error+ ;
GENERIC# compiler-error. 1 ( error word -- ) GENERIC# compiler-error. 1 ( error word -- )
<PRIVATE
SYMBOL: compiler-errors SYMBOL: compiler-errors
SYMBOL: with-compiler-errors? SYMBOL: with-compiler-errors?
@ -47,8 +45,6 @@ SYMBOL: with-compiler-errors?
"semantic warnings" +warning+ "warnings" (compiler-report) "semantic warnings" +warning+ "warnings" (compiler-report)
"linkage errors" +linkage+ "linkage" (compiler-report) ; "linkage errors" +linkage+ "linkage" (compiler-report) ;
PRIVATE>
: :errors ( -- ) +error+ compiler-errors. ; : :errors ( -- ) +error+ compiler-errors. ;
: :warnings ( -- ) +warning+ compiler-errors. ; : :warnings ( -- ) +warning+ compiler-errors. ;

View File

@ -108,17 +108,17 @@ HELP: >continuation<
{ $description "Takes a continuation apart into its constituents." } ; { $description "Takes a continuation apart into its constituents." } ;
HELP: ifcc HELP: ifcc
{ $values { "capture" "a quotation with stack effect " { $snippet "( continuation -- )" } } { "restore" quotation } } { $values { "capture" { $quotation "( continuation -- )" } } { "restore" quotation } }
{ $description "Reifies a continuation from the point immediately after which this word returns, and passes it to " { $snippet "capture" } ". When the continuation is restored, execution resumes and "{ $snippet "restore" } " is called." } ; { $description "Reifies a continuation from the point immediately after which this word returns, and passes it to " { $snippet "capture" } ". When the continuation is restored, execution resumes and "{ $snippet "restore" } " is called." } ;
{ callcc0 continue callcc1 continue-with ifcc } related-words { callcc0 continue callcc1 continue-with ifcc } related-words
HELP: callcc0 HELP: callcc0
{ $values { "quot" "a quotation with stack effect " { $snippet "( continuation -- )" } } } { $values { "quot" { $quotation "( continuation -- )" } } }
{ $description "Applies the quotation to the current continuation, which is reified from the point immediately after which the caller returns. The " { $link continue } " word resumes the continuation." } ; { $description "Applies the quotation to the current continuation, which is reified from the point immediately after which the caller returns. The " { $link continue } " word resumes the continuation." } ;
HELP: callcc1 HELP: callcc1
{ $values { "quot" "a quotation with stack effect " { $snippet "( continuation -- )" } } { "obj" "an object provided when resuming the continuation" } } { $values { "quot" { $quotation "( continuation -- )" } } { "obj" "an object provided when resuming the continuation" } }
{ $description "Applies the quotation to the current continuation, which is reified from the point immediately after which the caller returns. The " { $link continue-with } " word resumes the continuation, passing a value back to the original execution context." } ; { $description "Applies the quotation to the current continuation, which is reified from the point immediately after which the caller returns. The " { $link continue-with } " word resumes the continuation, passing a value back to the original execution context." } ;
HELP: continue HELP: continue
@ -160,7 +160,7 @@ HELP: cleanup
{ $description "Calls the " { $snippet "try" } " quotation. If no error is thrown, calls " { $snippet "cleanup-always" } " without restoring the data stack. If an error is thrown, restores the data stack, calls " { $snippet "cleanup-always" } " followed by " { $snippet "cleanup-error" } ", and rethrows the error." } ; { $description "Calls the " { $snippet "try" } " quotation. If no error is thrown, calls " { $snippet "cleanup-always" } " without restoring the data stack. If an error is thrown, restores the data stack, calls " { $snippet "cleanup-always" } " followed by " { $snippet "cleanup-error" } ", and rethrows the error." } ;
HELP: recover HELP: recover
{ $values { "try" quotation } { "recovery" "a quotation with stack effect " { $snippet "( error -- )" } } } { $values { "try" quotation } { "recovery" { $quotation "( error -- )" } } }
{ $description "Calls the " { $snippet "try" } " quotation. If an exception is thrown in the dynamic extent of the " { $snippet "try" } " quotation, restores the data stack and calls the " { $snippet "recovery" } " quotation to handle the error." } ; { $description "Calls the " { $snippet "try" } " quotation. If an exception is thrown in the dynamic extent of the " { $snippet "try" } " quotation, restores the data stack and calls the " { $snippet "recovery" } " quotation to handle the error." } ;
HELP: ignore-errors HELP: ignore-errors

View File

@ -21,7 +21,7 @@ HELP: dispose*
} ; } ;
HELP: with-disposal HELP: with-disposal
{ $values { "object" "a disposable object" } { "quot" "a quotation with stack effect " { $snippet "( object -- )" } } } { $values { "object" "a disposable object" } { "quot" { $quotation "( object -- )" } } }
{ $description "Calls the quotation, disposing the object with " { $link dispose } " after the quotation returns or if it throws an error." } ; { $description "Calls the quotation, disposing the object with " { $link dispose } " after the quotation returns or if it throws an error." } ;
HELP: with-destructors HELP: with-destructors

View File

@ -68,5 +68,5 @@ HELP: effect>string
} ; } ;
HELP: stack-effect HELP: stack-effect
{ $values { "word" word } { "effect/f" "an " { $link effect } " or " { $link f } } } { $values { "word" word } { "effect/f" { $maybe effect } } }
{ $description "Outputs the stack effect of a word; either a stack effect declared with " { $link POSTPONE: ( } ", or an inferred stack effect (see " { $link "inference" } "." } ; { $description "Outputs the stack effect of a word; either a stack effect declared with " { $link POSTPONE: ( } ", or an inferred stack effect (see " { $link "inference" } "." } ;

View File

@ -127,7 +127,7 @@ HELP: method-body
{ $class-description "The class of method bodies, which are words with special word properties set." } ; { $class-description "The class of method bodies, which are words with special word properties set." } ;
HELP: method HELP: method
{ $values { "class" class } { "generic" generic } { "method/f" "a " { $link method-body } " or " { $link f } } } { $values { "class" class } { "generic" generic } { "method/f" { $maybe method-body } } }
{ $description "Looks up a method definition." } ; { $description "Looks up a method definition." } ;
{ method create-method POSTPONE: M: } related-words { method create-method POSTPONE: M: } related-words
@ -146,7 +146,7 @@ HELP: check-method
{ $error-description "Thrown if " { $link POSTPONE: M: } " or " { $link create-method } " is given an invalid class or generic word." } ; { $error-description "Thrown if " { $link POSTPONE: M: } " or " { $link create-method } " is given an invalid class or generic word." } ;
HELP: with-methods HELP: with-methods
{ $values { "class" class } { "generic" generic } { "quot" "a quotation with stack effect " { $snippet "( methods -- )" } } } { $values { "class" class } { "generic" generic } { "quot" { $quotation "( methods -- )" } } }
{ $description "Applies a quotation to the generic word's methods hashtable, and regenerates the generic word's definition when the quotation returns." } { $description "Applies a quotation to the generic word's methods hashtable, and regenerates the generic word's definition when the quotation returns." }
$low-level-note ; $low-level-note ;

Some files were not shown because too many files have changed in this diff Show More