]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorBruno Deferrari <utizoc@gmail.com>
Sun, 16 Nov 2008 18:35:27 +0000 (16:35 -0200)
committerBruno Deferrari <utizoc@gmail.com>
Sun, 16 Nov 2008 18:35:27 +0000 (16:35 -0200)
329 files changed:
basis/alarms/alarms-docs.factor
basis/alias/alias-docs.factor
basis/alien/c-types/c-types-docs.factor
basis/binary-search/binary-search-docs.factor
basis/bootstrap/image/image.factor
basis/cocoa/messages/messages-docs.factor
basis/compiler/cfg/builder/builder.factor
basis/compiler/cfg/instructions/instructions.factor
basis/compiler/cfg/linearization/linearization.factor
basis/compiler/cfg/rpo/rpo.factor
basis/compiler/cfg/stacks/stacks.factor
basis/compiler/cfg/value-numbering/rewrite/rewrite.factor
basis/compiler/cfg/value-numbering/value-numbering-tests.factor
basis/compiler/codegen/codegen.factor
basis/compiler/codegen/fixup/fixup.factor
basis/compiler/compiler.factor
basis/compiler/constants/constants.factor
basis/compiler/tests/codegen.factor [new file with mode: 0644]
basis/compiler/tests/templates.factor [deleted file]
basis/compiler/tree/builder/builder.factor
basis/compiler/tree/checker/checker.factor
basis/compiler/tree/dead-code/branches/branches.factor
basis/compiler/tree/dead-code/liveness/liveness.factor
basis/compiler/tree/dead-code/simple/simple.factor
basis/compiler/tree/debugger/debugger.factor
basis/compiler/tree/def-use/def-use.factor
basis/compiler/tree/escape-analysis/allocations/allocations.factor
basis/compiler/tree/finalization/finalization.factor
basis/compiler/tree/identities/identities.factor
basis/compiler/tree/normalization/renaming/renaming.factor
basis/compiler/tree/recursive/recursive.factor
basis/compiler/tree/tree.factor
basis/compiler/tree/tuple-unboxing/tuple-unboxing.factor
basis/concurrency/combinators/combinators-docs.factor
basis/concurrency/futures/futures-docs.factor
basis/concurrency/locks/locks-docs.factor
basis/concurrency/mailboxes/mailboxes-docs.factor
basis/concurrency/promises/promises-docs.factor
basis/concurrency/semaphores/semaphores-docs.factor
basis/cpu/architecture/architecture.factor
basis/cpu/ppc/bootstrap.factor
basis/cpu/ppc/ppc.factor
basis/cpu/x86/32/32.factor
basis/cpu/x86/32/bootstrap.factor
basis/cpu/x86/64/64.factor
basis/cpu/x86/64/bootstrap.factor
basis/cpu/x86/bootstrap.factor
basis/cpu/x86/x86.factor
basis/deques/deques-docs.factor
basis/deques/deques.factor
basis/dlists/dlists-docs.factor
basis/dlists/dlists-tests.factor
basis/dlists/dlists.factor
basis/documents/documents-docs.factor
basis/editors/emacs/emacs.factor
basis/editors/etexteditor/authors.txt [new file with mode: 0755]
basis/editors/etexteditor/etexteditor.factor [new file with mode: 0755]
basis/editors/etexteditor/summary.txt [new file with mode: 0755]
basis/editors/etexteditor/tags.txt [new file with mode: 0755]
basis/furnace/actions/actions-docs.factor [new file with mode: 0644]
basis/furnace/actions/actions.factor
basis/furnace/alloy/alloy-docs.factor [new file with mode: 0644]
basis/furnace/asides/asides-docs.factor [new file with mode: 0644]
basis/furnace/auth/auth-docs.factor [new file with mode: 0644]
basis/furnace/auth/basic/basic-docs.factor [new file with mode: 0644]
basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor [new file with mode: 0644]
basis/furnace/auth/features/edit-profile/edit-profile-docs.factor [new file with mode: 0644]
basis/furnace/auth/features/edit-profile/edit-profile.factor
basis/furnace/auth/features/edit-profile/edit-profile.xml
basis/furnace/auth/features/recover-password/recover-3.xml
basis/furnace/auth/features/recover-password/recover-password-docs.factor [new file with mode: 0644]
basis/furnace/auth/features/recover-password/recover-password.factor
basis/furnace/auth/features/registration/register.xml
basis/furnace/auth/features/registration/registration-docs.factor [new file with mode: 0644]
basis/furnace/auth/features/registration/registration.factor
basis/furnace/auth/login/login-docs.factor [new file with mode: 0644]
basis/furnace/auth/login/login.factor
basis/furnace/auth/login/login.xml
basis/furnace/auth/providers/assoc/assoc-docs.factor [new file with mode: 0644]
basis/furnace/auth/providers/db/db-docs.factor [new file with mode: 0644]
basis/furnace/auth/providers/null/null-docs.factor [new file with mode: 0644]
basis/furnace/auth/providers/providers-docs.factor [new file with mode: 0644]
basis/furnace/boilerplate/boilerplate-docs.factor [new file with mode: 0644]
basis/furnace/conversations/conversations-docs.factor [new file with mode: 0644]
basis/furnace/db/db-docs.factor [new file with mode: 0644]
basis/furnace/furnace-docs.factor [new file with mode: 0644]
basis/furnace/furnace.factor
basis/furnace/json/json-docs.factor [new file with mode: 0644]
basis/furnace/redirection/redirection-docs.factor [new file with mode: 0644]
basis/furnace/referrer/referrer-docs.factor [new file with mode: 0644]
basis/furnace/sessions/sessions-docs.factor [new file with mode: 0644]
basis/furnace/summary.txt [new file with mode: 0644]
basis/furnace/syndication/syndication-docs.factor [new file with mode: 0644]
basis/grouping/authors.txt [new file with mode: 0644]
basis/grouping/grouping-docs.factor [new file with mode: 0644]
basis/grouping/grouping-tests.factor [new file with mode: 0644]
basis/grouping/grouping.factor [new file with mode: 0644]
basis/grouping/summary.txt [new file with mode: 0644]
basis/grouping/tags.txt [new file with mode: 0644]
basis/heaps/heaps.factor
basis/help/handbook/handbook.factor
basis/help/help-docs.factor
basis/help/html/html.factor
basis/help/markup/markup.factor
basis/html/forms/forms-docs.factor
basis/html/forms/forms.factor
basis/html/templates/chloe/chloe-docs.factor
basis/html/templates/chloe/chloe.factor
basis/http/client/client-docs.factor
basis/http/http-docs.factor
basis/http/server/static/static-docs.factor
basis/io/files/listing/authors.txt [new file with mode: 0644]
basis/io/files/listing/listing-docs.factor [new file with mode: 0644]
basis/io/files/listing/listing-tests.factor [new file with mode: 0644]
basis/io/files/listing/listing.factor [new file with mode: 0755]
basis/io/files/listing/tags.txt [new file with mode: 0644]
basis/io/files/listing/unix/authors.txt [new file with mode: 0755]
basis/io/files/listing/unix/tags.txt [new file with mode: 0644]
basis/io/files/listing/unix/unix.factor [new file with mode: 0755]
basis/io/files/listing/windows/authors.txt [new file with mode: 0755]
basis/io/files/listing/windows/tags.txt [new file with mode: 0644]
basis/io/files/listing/windows/windows.factor [new file with mode: 0755]
basis/io/mmap/mmap-docs.factor
basis/io/monitors/monitors-docs.factor
basis/io/pools/pools-docs.factor
basis/io/servers/connection/connection-docs.factor
basis/io/sockets/sockets-docs.factor
basis/io/timeouts/timeouts-docs.factor
basis/io/unix/files/files.factor
basis/io/windows/files/files.factor
basis/json/authors.txt
basis/json/json-docs.factor [new file with mode: 0644]
basis/json/json.factor [new file with mode: 0644]
basis/json/reader/reader-docs.factor
basis/json/reader/reader-tests.factor
basis/json/reader/reader.factor
basis/json/writer/writer-docs.factor
basis/json/writer/writer-tests.factor [new file with mode: 0644]
basis/json/writer/writer.factor
basis/libc/libc-docs.factor
basis/linked-assocs/linked-assocs-docs.factor
basis/locals/locals.factor
basis/macros/expander/expander.factor
basis/macros/macros.factor
basis/math/functions/functions-docs.factor
basis/math/intervals/intervals-docs.factor
basis/models/filter/filter-docs.factor
basis/models/models-docs.factor
basis/peg/peg-docs.factor
basis/persistent/hashtables/hashtables.factor
basis/persistent/sequences/sequences.factor
basis/prettyprint/backend/backend-docs.factor
basis/prettyprint/backend/backend.factor
basis/prettyprint/sections/sections-docs.factor
basis/random/random.factor
basis/search-deques/search-deques-docs.factor
basis/search-deques/search-deques-tests.factor
basis/search-deques/search-deques.factor
basis/serialize/serialize-docs.factor
basis/serialize/serialize-tests.factor
basis/serialize/serialize.factor
basis/sorting/human/tags.txt
basis/sorting/insertion/tags.txt
basis/stack-checker/backend/backend-tests.factor [new file with mode: 0644]
basis/stack-checker/backend/backend.factor
basis/stack-checker/branches/branches.factor
basis/stack-checker/errors/errors.factor
basis/stack-checker/inlining/inlining.factor
basis/stack-checker/known-words/known-words.factor
basis/stack-checker/recursive-state/recursive-state.factor [new file with mode: 0644]
basis/stack-checker/recursive-state/tree/tree.factor [new file with mode: 0644]
basis/stack-checker/stack-checker-docs.factor
basis/stack-checker/state/state.factor
basis/stack-checker/transforms/transforms.factor
basis/stack-checker/values/values.factor [new file with mode: 0644]
basis/stack-checker/visitor/dummy/dummy.factor
basis/stack-checker/visitor/visitor.factor
basis/suffix-arrays/authors.txt [new file with mode: 0755]
basis/suffix-arrays/suffix-arrays-docs.factor [new file with mode: 0755]
basis/suffix-arrays/suffix-arrays-tests.factor [new file with mode: 0755]
basis/suffix-arrays/suffix-arrays.factor [new file with mode: 0755]
basis/suffix-arrays/summary.txt [new file with mode: 0755]
basis/suffix-arrays/tags.txt [new file with mode: 0755]
basis/suffix-arrays/words/words.factor [new file with mode: 0755]
basis/threads/threads-docs.factor
basis/tools/annotations/annotations-docs.factor
basis/tools/hexdump/authors.txt [new file with mode: 0644]
basis/tools/hexdump/hexdump-docs.factor [new file with mode: 0644]
basis/tools/hexdump/hexdump-tests.factor [new file with mode: 0644]
basis/tools/hexdump/hexdump.factor [new file with mode: 0644]
basis/tools/hexdump/summary.txt [new file with mode: 0644]
basis/tools/profiler/profiler-tests.factor
basis/tools/scaffold/scaffold.factor
basis/tools/test/test-docs.factor
basis/ui/commands/commands-docs.factor
basis/ui/gadgets/buttons/buttons-docs.factor
basis/ui/gadgets/editors/editors-docs.factor
basis/ui/gadgets/gadgets-docs.factor
basis/ui/gadgets/gadgets-tests.factor
basis/ui/gadgets/labelled/labelled-docs.factor
basis/ui/gadgets/lists/lists-docs.factor
basis/ui/gadgets/menus/menus-docs.factor
basis/ui/gadgets/panes/panes-docs.factor
basis/ui/gadgets/scrollers/scrollers-docs.factor
basis/ui/gadgets/sliders/sliders-docs.factor
basis/ui/gadgets/worlds/worlds-docs.factor
basis/ui/gestures/gestures-docs.factor
basis/ui/operations/operations-docs.factor
basis/ui/tools/debugger/debugger-docs.factor
basis/ui/ui-docs.factor
basis/unrolled-lists/unrolled-lists-docs.factor [new file with mode: 0644]
basis/unrolled-lists/unrolled-lists-tests.factor [new file with mode: 0644]
basis/unrolled-lists/unrolled-lists.factor [new file with mode: 0644]
basis/urls/urls-docs.factor
basis/validators/validators-docs.factor
basis/validators/validators.factor
basis/values/values-docs.factor
basis/vlists/vlists-tests.factor [new file with mode: 0644]
basis/vlists/vlists.factor [new file with mode: 0644]
basis/xml/xml-docs.factor
core/assocs/assocs-docs.factor
core/byte-vectors/byte-vectors-tests.factor
core/classes/predicate/predicate-docs.factor
core/combinators/combinators-docs.factor
core/combinators/combinators.factor
core/continuations/continuations-docs.factor
core/destructors/destructors-docs.factor
core/effects/effects-docs.factor
core/generic/generic-docs.factor
core/generic/generic.factor
core/generic/math/math-docs.factor
core/generic/math/math.factor
core/generic/standard/engines/tag/tag.factor
core/generic/standard/engines/tuple/tuple.factor
core/grouping/authors.txt [deleted file]
core/grouping/grouping-docs.factor [deleted file]
core/grouping/grouping-tests.factor [deleted file]
core/grouping/grouping.factor [deleted file]
core/grouping/summary.txt [deleted file]
core/grouping/tags.txt [deleted file]
core/hashtables/hashtables.factor
core/io/streams/string/string.factor
core/kernel/kernel-docs.factor
core/lexer/lexer-docs.factor
core/math/math-docs.factor
core/math/order/order-docs.factor
core/memory/memory-docs.factor
core/namespaces/namespaces-docs.factor
core/parser/parser-docs.factor
core/sbufs/sbufs.factor
core/sequences/sequences-docs.factor
core/slots/slots-docs.factor
core/slots/slots-tests.factor
core/slots/slots.factor
core/sorting/sorting-docs.factor
core/sorting/tags.txt
core/strings/strings.factor
core/vocabs/vocabs-docs.factor
core/words/words.factor
extra/advice/advice-docs.factor
extra/advice/tags.txt
extra/ftp/client/client.factor
extra/ftp/client/listing-parser/authors.txt [new file with mode: 0644]
extra/ftp/client/listing-parser/listing-parser.factor [new file with mode: 0644]
extra/ftp/ftp.factor
extra/ftp/server/server.factor
extra/hexdump/authors.txt [deleted file]
extra/hexdump/hexdump-docs.factor [deleted file]
extra/hexdump/hexdump-tests.factor [deleted file]
extra/hexdump/hexdump.factor [deleted file]
extra/hexdump/summary.txt [deleted file]
extra/lists/lazy/lazy-docs.factor
extra/lists/lists-docs.factor
extra/mason/common/common.factor
extra/mason/config/config.factor
extra/mason/help/help.factor [new file with mode: 0644]
extra/mason/release/branch/branch.factor
extra/mason/release/upload/upload-tests.factor
extra/mason/release/upload/upload.factor
extra/mason/report/report.factor
extra/mason/test/test.factor
extra/partial-continuations/partial-continuations-docs.factor
extra/promises/promises-docs.factor
extra/suffix-arrays/authors.txt [deleted file]
extra/suffix-arrays/suffix-arrays-docs.factor [deleted file]
extra/suffix-arrays/suffix-arrays-tests.factor [deleted file]
extra/suffix-arrays/suffix-arrays.factor [deleted file]
extra/suffix-arrays/summary.txt [deleted file]
extra/suffix-arrays/tags.txt [deleted file]
extra/suffix-arrays/words/words.factor [deleted file]
extra/tar/tar.factor
extra/webapps/blogs/new-post.xml
extra/webapps/user-admin/edit-user.xml
extra/webapps/user-admin/new-user.xml
extra/webapps/user-admin/user-admin-docs.factor [new file with mode: 0644]
misc/factor.el
vm/alien.c
vm/alien.h
vm/callstack.c
vm/callstack.h
vm/code_gc.c
vm/code_gc.h
vm/code_heap.c
vm/code_heap.h
vm/data_gc.c
vm/data_gc.h
vm/debug.c
vm/debug.h
vm/errors.c
vm/errors.h
vm/image.c
vm/image.h
vm/io.c
vm/io.h
vm/layouts.h
vm/math.c
vm/math.h
vm/os-unix.c
vm/os-windows-ce.c
vm/os-windows.c
vm/primitives.h
vm/profiler.c
vm/profiler.h
vm/quotations.c
vm/quotations.h
vm/run.c
vm/run.h
vm/types.c
vm/types.h

index dac8b72dd50d78260663471b288e917ad10d7b6e..2d494afca3b5d1d45df87633297d19d10e9d16ce 100644 (file)
@@ -5,7 +5,7 @@ HELP: alarm
 { $class-description "An alarm. Can be passed to " { $link cancel-alarm } "." } ;\r
 \r
 HELP: add-alarm\r
-{ $values { "quot" quotation } { "time" timestamp } { "frequency" "a " { $link duration } " or " { $link f } } { "alarm" alarm } }\r
+{ $values { "quot" quotation } { "time" timestamp } { "frequency" { $maybe duration } } { "alarm" alarm } }\r
 { $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." } ;\r
 \r
 HELP: later\r
index 4dcf1a77387a44013c79972d2a2d558ec7c55ef2..3f2eee64600645c35b195151460298cf4bfbfadb 100644 (file)
@@ -16,7 +16,7 @@ HELP: ALIAS:
     }
 } ;
 
-ARTICLE: "alias" "Alias"
+ARTICLE: "alias" "Word aliasing"
 "The " { $vocab-link "alias" } " vocabulary implements a way to make many different names for the same word. Although creating new names for words is generally frowned upon, aliases are useful for the Win32 API and other cases where words need to be renamed for symmetry." $nl 
 "Make a new word that aliases another word:"
 { $subsection define-alias }
index 03208de63a1e8708dc0ed2b7de54f69f635e8a93..739b45486f0fe89ae4224cc2978912115fb8a750 100644 (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." } ;
 
 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." }
 { $errors "Throws a " { $link no-c-type } " error if the type does not exist." } ;
 
 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." }
 { $errors "Throws an error if the type does not exist." } ;
 
index caabbd74190d7b0e266b8cb58957b51b882237b0..cf7915159abb5a4dc1cba1c2a3b3d80a7ef47a83 100644 (file)
@@ -2,7 +2,7 @@ IN: binary-search
 USING: help.markup help.syntax sequences kernel math.order ;
 
 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+ } ")."
 $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+ } "."
index 8b0051148f158190d327f151d98f018612aeca9e..c0fafdc0f53ac0b7d2b624b45cd368d86bc5ee5f 100644 (file)
@@ -134,6 +134,7 @@ SYMBOL: jit-epilog
 SYMBOL: jit-return
 SYMBOL: jit-profiling
 SYMBOL: jit-declare-word
+SYMBOL: jit-save-stack
 
 ! Default definition for undefined words
 SYMBOL: undefined-quot
@@ -158,6 +159,7 @@ SYMBOL: undefined-quot
         { jit-profiling 35 }
         { jit-push-immediate 36 }
         { jit-declare-word 42 }
+        { jit-save-stack 43 }
         { undefined-quot 60 }
     } at header-size + ;
 
@@ -459,6 +461,7 @@ M: quotation '
         jit-return
         jit-profiling
         jit-declare-word
+        jit-save-stack
         undefined-quot
     } [ emit-userenv ] each ;
 
index 9b5e3fdfd9920f598a01df9d32247da32efb7cb8..400599383fba5347bfd2615a30e57d7aa732adc0 100644 (file)
@@ -31,7 +31,7 @@ HELP: alien>objc-types
 { objc>alien-types alien>objc-types } related-words
 
 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." } ;
 
 HELP: root-class
index 17a5942af2006c0c46c140635deda808a33120fc..7bad44f7a60cacc18839d1760c002c5edd5e9fb2 100755 (executable)
@@ -190,7 +190,7 @@ M: #if emit-node
 
 : emit-dispatch ( node -- )
     ##epilogue
-    ds-pop ^^offset>slot i ##dispatch
+    ds-pop ^^offset>slot i ##dispatch
     dispatch-branches ;
 
 : <dispatch-block> ( -- word )
@@ -221,21 +221,14 @@ M: #push emit-node
     literal>> ^^load-literal ds-push iterate-next ;
 
 ! #shuffle
-: emit-shuffle ( effect -- )
-    [ out>> ] [ in>> dup length ds-load zip ] bi
-    '[ _ at ] map ds-store ;
-
 M: #shuffle emit-node
-    shuffle-effect emit-shuffle iterate-next ;
-
-M: #>r emit-node
-    [ in-d>> length ] [ out-r>> empty? ] bi
-    [ neg ##inc-d ] [ ds-load rs-store ] if
-    iterate-next ;
-
-M: #r> emit-node
-    [ in-r>> length ] [ out-d>> empty? ] bi
-    [ neg ##inc-r ] [ rs-load ds-store ] if
+    dup
+    H{ } clone
+    [ [ in-d>> [ length ds-load ] keep ] dip '[ _ set-at ] 2each ]
+    [ [ in-r>> [ length rs-load ] keep ] dip '[ _ set-at ] 2each ]
+    [ nip ] 2tri
+    [ [ [ out-d>> ] [ mapping>> ] bi ] dip '[ _ at _ at ] map ds-store ]
+    [ [ [ out-r>> ] [ mapping>> ] bi ] dip '[ _ at _ at ] map rs-store ] 2bi
     iterate-next ;
 
 ! #return
index c39f517671bc21912cf6dd623229a54687c4aa7c..b2c752e6121ec07c61e8529aec04c29eed859e5b 100644 (file)
@@ -62,7 +62,7 @@ INSN: ##jump word ;
 INSN: ##return ;
 
 ! Jump tables
-INSN: ##dispatch src temp ;
+INSN: ##dispatch src temp offset ;
 INSN: ##dispatch-label label ;
 
 ! Slot access
index d397c9d448b683ff02c1feee0834837f8ed7880d..7433df9617cbab44cbfe28c660f25f457e17c9df 100644 (file)
@@ -43,8 +43,8 @@ M: ##branch linearize-insn
 
 : binary-conditional ( basic-block insn -- basic-block successor label2 src1 src2 cc )
     [ (binary-conditional) ]
-    [ drop dup successors>> first useless-branch? ] 2bi
-    [ [ number>> ] 3dip negate-cc ] [ [ swap number>> ] 3dip ] if ;
+    [ drop dup successors>> second useless-branch? ] 2bi
+    [ [ swap number>> ] 3dip ] [ [ number>> ] 3dip negate-cc ] if ;
 
 M: ##compare-branch linearize-insn
     binary-conditional _compare-branch emit-branch ;
index 7f4b09e68fddb3d0f768df8213f5ae2714c70552..158903b4bf4be368cbcdc1044e2c48bb93a1716c 100644 (file)
@@ -9,7 +9,10 @@ SYMBOL: visited
 : post-order-traversal ( bb -- )
     dup id>> visited get key? [ drop ] [
         dup id>> visited get conjoin
-        [ successors>> [ post-order-traversal ] each ] [ , ] bi
+        [
+            successors>> <reversed>
+            [ post-order-traversal ] each
+        ] [ , ] bi
     ] if ;
 
 : post-order ( bb -- blocks )
index f138f673e0c10fb6b5e423864dfb1f4dc4c21186..c8fcae87c0ac985547ba15e2b28fb3dcb7b8202c 100755 (executable)
@@ -15,16 +15,28 @@ IN: compiler.cfg.stacks
     1 ##inc-d D 0 ##replace ;
 
 : ds-load ( n -- vregs )
-    [ <reversed> [ <ds-loc> ^^peek ] map ] [ neg ##inc-d ] bi ;
+    dup 0 =
+    [ drop f ]
+    [ [ <reversed> [ <ds-loc> ^^peek ] map ] [ neg ##inc-d ] bi ] if ;
 
 : ds-store ( vregs -- )
-    <reversed> [ length ##inc-d ] [ [ <ds-loc> ##replace ] each-index ] bi ;
+    [
+        <reversed>
+        [ length ##inc-d ]
+        [ [ <ds-loc> ##replace ] each-index ] bi
+    ] unless-empty ;
 
 : rs-load ( n -- vregs )
-    [ <reversed> [ <rs-loc> ^^peek ] map ] [ neg ##inc-r ] bi ;
+    dup 0 =
+    [ drop f ]
+    [ [ <reversed> [ <rs-loc> ^^peek ] map ] [ neg ##inc-r ] bi ] if ;
 
 : rs-store ( vregs -- )
-    <reversed> [ length ##inc-r ] [ [ <rs-loc> ##replace ] each-index ] bi ;
+    [
+        <reversed>
+        [ length ##inc-r ]
+        [ [ <rs-loc> ##replace ] each-index ] bi
+    ] unless-empty ;
 
 : 2inputs ( -- vreg1 vreg2 )
     D 1 ^^peek D 0 ^^peek -2 ##inc-d ;
index 94c3f0d6f9b32bd128dcc927775c4ea1ec6a9cc3..5f67f8097eec07db89e594f179ed39f60e4333ed 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel sequences layouts accessors combinators namespaces
-math
+math fry
 compiler.cfg.instructions
 compiler.cfg.value-numbering.graph
 compiler.cfg.value-numbering.simplify
@@ -113,4 +113,18 @@ M: ##compare-imm rewrite
         ] when
     ] when ;
 
+: dispatch-offset ( expr -- n )
+    [ in2>> vn>constant tag-bits get neg shift ] [ op>> ] bi
+    \ ##sub-imm eq? [ neg ] when ;
+
+: add-dispatch-offset? ( insn -- expr ? )
+    src>> vreg>expr dup op>> { ##add-imm ##sub-imm } memq? ; inline
+
+M: ##dispatch rewrite
+    dup add-dispatch-offset? [
+        [ clone ] dip
+        [ in1>> vn>vreg >>src ]
+        [ dispatch-offset '[ _ + ] change-offset ] bi
+    ] [ drop ] if ;
+
 M: insn rewrite ;
index d3be68c3c9036b9e4a7629afb0ad386284f4dc38..b73736ed1427be93f6a73bd899496cece7ce8d20 100644 (file)
@@ -34,7 +34,7 @@ compiler.cfg.registers cpu.architecture tools.test kernel math ;
 [ t ] [
     {
         T{ ##peek f V int-regs 1 D 0 }
-        T{ ##dispatch f V int-regs 1 V int-regs 2 }
+        T{ ##dispatch f V int-regs 1 V int-regs 2 }
     } dup value-numbering =
 ] unit-test
 
index 35d4d59253f36250a6acc06fbce257a28dffc82f..0d45b281262d74c925bea8b5ceb97e0c48105267 100644 (file)
@@ -93,7 +93,7 @@ M: ##return generate-insn drop %return ;
 M: ##dispatch-label generate-insn label>> %dispatch-label ;
 
 M: ##dispatch generate-insn
-    [ src>> register ] [ temp>> register ] bi %dispatch ;
+    [ src>> register ] [ temp>> register ] [ offset>> ] tri %dispatch ;
 
 : >slot<
     {
index fe270f4410618cb34be04a064c253af8df732de8..b25f1fa8fe7da8b29cbf8caec42e565cdea871cb 100755 (executable)
@@ -72,8 +72,8 @@ SYMBOL: literal-table
 : rel-this ( class -- )
     0 swap rt-label rel-fixup ;
 
-: rel-here ( class -- )
-    0 swap rt-here rel-fixup ;
+: rel-here ( offset class -- )
+    rt-here rel-fixup ;
 
 : init-fixup ( -- )
     BV{ } clone relocation-table set
index b01a835b4a806a1a3650c0033decd6ca37ec739b..a6afc4b243af077ff2d4cbdfed3bb8eacebcb198 100644 (file)
@@ -1,8 +1,8 @@
 ! Copyright (C) 2004, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors kernel namespaces arrays sequences io debugger
-words fry continuations vocabs assocs dlists definitions math
-threads graphs generic combinators deques search-deques
+words fry continuations vocabs assocs dlists definitions
+math threads graphs generic combinators deques search-deques
 prettyprint io stack-checker stack-checker.state
 stack-checker.inlining compiler.errors compiler.units
 compiler.tree.builder compiler.tree.optimizer
index cd68602768ded9ea3bb6a6097a0c212bac08a409..86c1f6504900f359cd84fd0c89a7f328ed853921 100644 (file)
@@ -37,14 +37,15 @@ IN: compiler.constants
 : rc-indirect-arm-pc  8 ; inline
 
 ! Relocation types
-: rt-primitive 0 ; inline
-: rt-dlsym     1 ; inline
-: rt-literal   2 ; inline
-: rt-dispatch  3 ; inline
-: rt-xt        4 ; inline
-: rt-here      5 ; inline
-: rt-label     6 ; inline
-: rt-immediate 7 ; inline
+: rt-primitive   0 ; inline
+: rt-dlsym       1 ; inline
+: rt-literal     2 ; inline
+: rt-dispatch    3 ; inline
+: rt-xt          4 ; inline
+: rt-here        5 ; inline
+: rt-label       6 ; inline
+: rt-immediate   7 ; inline
+: rt-stack-chain 8 ; inline
 
 : rc-absolute? ( n -- ? )
     [ rc-absolute-ppc-2/2 = ]
diff --git a/basis/compiler/tests/codegen.factor b/basis/compiler/tests/codegen.factor
new file mode 100644 (file)
index 0000000..a56ee55
--- /dev/null
@@ -0,0 +1,243 @@
+USING: generalizations accessors arrays compiler kernel
+kernel.private math hashtables.private math.private namespaces
+sequences sequences.private tools.test namespaces.private
+slots.private sequences.private byte-arrays alien
+alien.accessors layouts words definitions compiler.units io
+combinators vectors float-arrays ;
+IN: compiler.tests
+
+! Originally, this file did black box testing of templating
+! optimization. We now have a different codegen, but the tests
+! in here are still useful.
+
+! Oops!
+[ 5000 ] [ [ 5000 ] compile-call ] unit-test
+[ "hi" ] [ [ "hi" ] compile-call ] unit-test
+
+[ 1 2 3 4 ] [ [ 1 2 3 4 ] compile-call ] unit-test
+
+[ 1 1 ] [ 1 [ dup ] compile-call ] unit-test
+[ 0 ] [ 3 [ tag ] compile-call ] unit-test
+[ 0 3 ] [ 3 [ [ tag ] keep ] compile-call ] unit-test
+
+[ 2 3 ] [ 3 [ 2 swap ] compile-call ] unit-test
+
+[ 2 1 3 4 ] [ 1 2 [ swap 3 4 ] compile-call ] unit-test
+
+[ 2 3 4 ] [ 3 [ 2 swap 4 ] compile-call ] unit-test
+
+[ { 1 2 3 } { 1 4 3 } 3 3 ]
+[ { 1 2 3 } { 1 4 3 } [ over tag over tag ] compile-call ]
+unit-test
+
+! Test literals in either side of a shuffle
+[ 4 1 ] [ 1 [ [ 3 fixnum+ ] keep ] compile-call ] unit-test
+
+[ 2 ] [ 1 2 [ swap fixnum/i ] compile-call ] unit-test
+
+: foo ( -- ) ;
+
+[ 5 5 ]
+[ 1.2 [ tag [ foo ] keep ] compile-call ]
+unit-test
+
+[ 1 2 2 ]
+[ { 1 2 } [ dup 2 slot swap 3 slot [ foo ] keep ] compile-call ]
+unit-test
+
+[ 3 ]
+[
+    global [ 3 \ foo set ] bind
+    \ foo [ global >n get ndrop ] compile-call
+] unit-test
+
+: blech drop ;
+
+[ 3 ]
+[
+    global [ 3 \ foo set ] bind
+    \ foo [ global [ get ] swap blech call ] compile-call
+] unit-test
+
+[ 3 ]
+[
+    global [ 3 \ foo set ] bind
+    \ foo [ global [ get ] swap >n call ndrop ] compile-call
+] unit-test
+
+[ 3 ]
+[
+    global [ 3 \ foo set ] bind
+    \ foo [ global [ get ] bind ] compile-call
+] unit-test
+
+[ 12 13 ] [
+    -12 -13 [ [ 0 swap fixnum-fast ] bi@ ] compile-call
+] unit-test
+
+[ -1 2 ] [ 1 2 [ >r 0 swap fixnum- r> ] compile-call ] unit-test
+
+[ 12 13 ] [
+    -12 -13 [ [ 0 swap fixnum- ] bi@ ] compile-call
+] unit-test
+
+[ 1 ] [
+    SBUF" " [ 1 slot 1 [ slot ] keep ] compile-call nip
+] unit-test
+
+! Test slow shuffles
+[ 3 1 2 3 4 5 6 7 8 9 ] [
+    1 2 3 4 5 6 7 8 9
+    [ >r >r >r >r >r >r >r >r >r 3 r> r> r> r> r> r> r> r> r> ]
+    compile-call
+] unit-test
+
+[ 2 2 2 2 2 2 2 2 2 2 1 ] [
+    1 2
+    [ swap >r dup dup dup dup dup dup dup dup dup r> ] compile-call
+] unit-test
+
+[ ] [ [ 9 [ ] times ] compile-call ] unit-test
+
+[ ] [
+    [
+        [ 200 dup [ 200 3array ] curry map drop ] times
+    ] [ define-temp ] with-compilation-unit drop
+] unit-test
+
+! Test how dispatch handles the end of a basic block
+: try-breaking-dispatch ( n a b -- x str )
+    float+ swap { [ "hey" ] [ "bye" ] } dispatch ;
+
+: try-breaking-dispatch-2 ( -- ? )
+    1 1.0 2.5 try-breaking-dispatch "bye" = >r 3.5 = r> and ;
+
+[ t ] [
+    10000000 [ drop try-breaking-dispatch-2 ] all?
+] unit-test
+
+! Regression
+: (broken) ( x -- y ) ;
+
+[ 2.0 { 2.0 0.0 } ] [
+    2.0 1.0
+    [ float/f 0.0 [ drop (broken) ] 2keep 2array ] compile-call
+] unit-test
+
+! Regression
+: hellish-bug-1 ( a b -- ) 2drop ;
+
+: hellish-bug-2 ( i array x -- x ) 
+    2dup 1 slot eq? [ 2drop ] [ 
+        2dup array-nth tombstone? [ 
+            [
+                [ array-nth ] 2keep >r 1 fixnum+fast r> array-nth
+                pick 2dup hellish-bug-1 3drop
+            ] 2keep
+        ] unless >r 2 fixnum+fast r> hellish-bug-2
+    ] if ; inline recursive
+
+: hellish-bug-3 ( hash array -- ) 
+    0 swap hellish-bug-2 drop ;
+
+[ ] [
+    H{ { 1 2 } { 3 4 } } dup array>>
+    [ 0 swap hellish-bug-2 drop ] compile-call
+] unit-test
+
+! Regression
+: foox ( obj -- obj )
+    dup not
+    [ drop 3 ] [ dup tuple? [ drop 4 ] [ drop 5 ] if ] if ;
+
+[ 3 ] [ f foox ] unit-test
+
+TUPLE: my-tuple ;
+
+[ 4 ] [ T{ my-tuple } foox ] unit-test
+
+[ 5 ] [ "hi" foox ] unit-test
+
+! Making sure we don't needlessly unbox/rebox
+[ t 3.0 ] [ 1.0 dup [ dup 2.0 float+ >r eq? r> ] compile-call ] unit-test
+
+[ t 3.0 ] [ 1.0 dup [ dup 2.0 float+ ] compile-call >r eq? r> ] unit-test
+
+[ t ] [ 1.0 dup [ [ 2.0 float+ ] keep ] compile-call nip eq? ] unit-test
+
+[ 1 B{ 1 2 3 4 } ] [
+    B{ 1 2 3 4 } [
+        { byte-array } declare
+        [ 0 alien-unsigned-1 ] keep
+    ] compile-call
+] unit-test
+
+[ 1 t ] [
+    B{ 1 2 3 4 } [
+        { c-ptr } declare
+        [ 0 alien-unsigned-1 ] keep hi-tag
+    ] compile-call byte-array type-number =
+] unit-test
+
+[ t ] [
+    B{ 1 2 3 4 } [
+        { c-ptr } declare
+        0 alien-cell hi-tag
+    ] compile-call alien type-number =
+] unit-test
+
+[ 2 1 ] [
+    2 1
+    [ 2dup fixnum< [ >r die r> ] when ] compile-call
+] unit-test
+
+! Regression
+: a-dummy ( a -- ) drop "hi" print ;
+
+[ ] [
+    1 [
+        dup 0 2 3dup pick >= [ >= ] [ 2drop f ] if [
+            drop - >fixnum {
+                [ a-dummy ]
+                [ a-dummy ]
+                [ a-dummy ]
+            } dispatch
+        ] [ 2drop no-case ] if
+    ] compile-call
+] unit-test
+
+! Regression
+: dispatch-alignment-regression ( -- c )
+    { tuple vector } 3 slot { word } declare
+    dup 1 slot 0 fixnum-bitand { [ ] } dispatch ;
+
+[ t ] [ \ dispatch-alignment-regression compiled>> ] unit-test
+
+[ vector ] [ dispatch-alignment-regression ] unit-test
+
+! Regression
+: bad-value-bug ( a -- b ) [ 3 ] [ 3 ] if f <array> ;
+
+[ { f f f } ] [ t bad-value-bug ] unit-test
+
+! PowerPC regression
+TUPLE: id obj ;
+
+: (gc-check-bug) ( a b -- c )
+    { [ id boa ] [ id boa ] } dispatch ;
+
+: gc-check-bug ( -- )
+    10000000 [ "hi" 0 (gc-check-bug) drop ] times ;
+
+[ ] [ gc-check-bug ] unit-test
+
+! New optimization
+: test-1 ( a -- b ) 8 fixnum-fast { [ "a" ] [ "b" ] } dispatch ;
+
+[ "a" ] [ 8 test-1 ] unit-test
+[ "b" ] [ 9 test-1 ] unit-test
+
+: test-2 ( a -- b ) 1 fixnum-fast { [ "a" ] [ "b" ] } dispatch ;
+
+[ "a" ] [ 1 test-2 ] unit-test
+[ "b" ] [ 2 test-2 ] unit-test
diff --git a/basis/compiler/tests/templates.factor b/basis/compiler/tests/templates.factor
deleted file mode 100644 (file)
index 0a109a1..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-USING: generalizations accessors arrays compiler kernel
-kernel.private math hashtables.private math.private namespaces
-sequences sequences.private tools.test namespaces.private
-slots.private sequences.private byte-arrays alien
-alien.accessors layouts words definitions compiler.units io
-combinators vectors float-arrays ;
-IN: compiler.tests
-
-! Originally, this file did black box testing of templating
-! optimization. We now have a different codegen, but the tests
-! in here are still useful.
-
-! Oops!
-[ 5000 ] [ [ 5000 ] compile-call ] unit-test
-[ "hi" ] [ [ "hi" ] compile-call ] unit-test
-
-[ 1 2 3 4 ] [ [ 1 2 3 4 ] compile-call ] unit-test
-
-[ 1 1 ] [ 1 [ dup ] compile-call ] unit-test
-[ 0 ] [ 3 [ tag ] compile-call ] unit-test
-[ 0 3 ] [ 3 [ [ tag ] keep ] compile-call ] unit-test
-
-[ 2 3 ] [ 3 [ 2 swap ] compile-call ] unit-test
-
-[ 2 1 3 4 ] [ 1 2 [ swap 3 4 ] compile-call ] unit-test
-
-[ 2 3 4 ] [ 3 [ 2 swap 4 ] compile-call ] unit-test
-
-[ { 1 2 3 } { 1 4 3 } 3 3 ]
-[ { 1 2 3 } { 1 4 3 } [ over tag over tag ] compile-call ]
-unit-test
-
-! Test literals in either side of a shuffle
-[ 4 1 ] [ 1 [ [ 3 fixnum+ ] keep ] compile-call ] unit-test
-
-[ 2 ] [ 1 2 [ swap fixnum/i ] compile-call ] unit-test
-
-: foo ( -- ) ;
-
-[ 5 5 ]
-[ 1.2 [ tag [ foo ] keep ] compile-call ]
-unit-test
-
-[ 1 2 2 ]
-[ { 1 2 } [ dup 2 slot swap 3 slot [ foo ] keep ] compile-call ]
-unit-test
-
-[ 3 ]
-[
-    global [ 3 \ foo set ] bind
-    \ foo [ global >n get ndrop ] compile-call
-] unit-test
-
-: blech drop ;
-
-[ 3 ]
-[
-    global [ 3 \ foo set ] bind
-    \ foo [ global [ get ] swap blech call ] compile-call
-] unit-test
-
-[ 3 ]
-[
-    global [ 3 \ foo set ] bind
-    \ foo [ global [ get ] swap >n call ndrop ] compile-call
-] unit-test
-
-[ 3 ]
-[
-    global [ 3 \ foo set ] bind
-    \ foo [ global [ get ] bind ] compile-call
-] unit-test
-
-[ 12 13 ] [
-    -12 -13 [ [ 0 swap fixnum-fast ] bi@ ] compile-call
-] unit-test
-
-[ -1 2 ] [ 1 2 [ >r 0 swap fixnum- r> ] compile-call ] unit-test
-
-[ 12 13 ] [
-    -12 -13 [ [ 0 swap fixnum- ] bi@ ] compile-call
-] unit-test
-
-[ 1 ] [
-    SBUF" " [ 1 slot 1 [ slot ] keep ] compile-call nip
-] unit-test
-
-! Test slow shuffles
-[ 3 1 2 3 4 5 6 7 8 9 ] [
-    1 2 3 4 5 6 7 8 9
-    [ >r >r >r >r >r >r >r >r >r 3 r> r> r> r> r> r> r> r> r> ]
-    compile-call
-] unit-test
-
-[ 2 2 2 2 2 2 2 2 2 2 1 ] [
-    1 2
-    [ swap >r dup dup dup dup dup dup dup dup dup r> ] compile-call
-] unit-test
-
-[ ] [ [ 9 [ ] times ] compile-call ] unit-test
-
-[ ] [
-    [
-        [ 200 dup [ 200 3array ] curry map drop ] times
-    ] [ define-temp ] with-compilation-unit drop
-] unit-test
-
-! Test how dispatch handles the end of a basic block
-: try-breaking-dispatch ( n a b -- x str )
-    float+ swap { [ "hey" ] [ "bye" ] } dispatch ;
-
-: try-breaking-dispatch-2 ( -- ? )
-    1 1.0 2.5 try-breaking-dispatch "bye" = >r 3.5 = r> and ;
-
-[ t ] [
-    10000000 [ drop try-breaking-dispatch-2 ] all?
-] unit-test
-
-! Regression
-: (broken) ( x -- y ) ;
-
-[ 2.0 { 2.0 0.0 } ] [
-    2.0 1.0
-    [ float/f 0.0 [ drop (broken) ] 2keep 2array ] compile-call
-] unit-test
-
-! Regression
-: hellish-bug-1 ( a b -- ) 2drop ;
-
-: hellish-bug-2 ( i array x -- x ) 
-    2dup 1 slot eq? [ 2drop ] [ 
-        2dup array-nth tombstone? [ 
-            [
-                [ array-nth ] 2keep >r 1 fixnum+fast r> array-nth
-                pick 2dup hellish-bug-1 3drop
-            ] 2keep
-        ] unless >r 2 fixnum+fast r> hellish-bug-2
-    ] if ; inline recursive
-
-: hellish-bug-3 ( hash array -- ) 
-    0 swap hellish-bug-2 drop ;
-
-[ ] [
-    H{ { 1 2 } { 3 4 } } dup array>>
-    [ 0 swap hellish-bug-2 drop ] compile-call
-] unit-test
-
-! Regression
-: foox ( obj -- obj )
-    dup not
-    [ drop 3 ] [ dup tuple? [ drop 4 ] [ drop 5 ] if ] if ;
-
-[ 3 ] [ f foox ] unit-test
-
-TUPLE: my-tuple ;
-
-[ 4 ] [ T{ my-tuple } foox ] unit-test
-
-[ 5 ] [ "hi" foox ] unit-test
-
-! Making sure we don't needlessly unbox/rebox
-[ t 3.0 ] [ 1.0 dup [ dup 2.0 float+ >r eq? r> ] compile-call ] unit-test
-
-[ t 3.0 ] [ 1.0 dup [ dup 2.0 float+ ] compile-call >r eq? r> ] unit-test
-
-[ t ] [ 1.0 dup [ [ 2.0 float+ ] keep ] compile-call nip eq? ] unit-test
-
-[ 1 B{ 1 2 3 4 } ] [
-    B{ 1 2 3 4 } [
-        { byte-array } declare
-        [ 0 alien-unsigned-1 ] keep
-    ] compile-call
-] unit-test
-
-[ 1 t ] [
-    B{ 1 2 3 4 } [
-        { c-ptr } declare
-        [ 0 alien-unsigned-1 ] keep hi-tag
-    ] compile-call byte-array type-number =
-] unit-test
-
-[ t ] [
-    B{ 1 2 3 4 } [
-        { c-ptr } declare
-        0 alien-cell hi-tag
-    ] compile-call alien type-number =
-] unit-test
-
-[ 2 1 ] [
-    2 1
-    [ 2dup fixnum< [ >r die r> ] when ] compile-call
-] unit-test
-
-! Regression
-: a-dummy ( a -- ) drop "hi" print ;
-
-[ ] [
-    1 [
-        dup 0 2 3dup pick >= [ >= ] [ 2drop f ] if [
-            drop - >fixnum {
-                [ a-dummy ]
-                [ a-dummy ]
-                [ a-dummy ]
-            } dispatch
-        ] [ 2drop no-case ] if
-    ] compile-call
-] unit-test
-
-! Regression
-: dispatch-alignment-regression ( -- c )
-    { tuple vector } 3 slot { word } declare
-    dup 1 slot 0 fixnum-bitand { [ ] } dispatch ;
-
-[ t ] [ \ dispatch-alignment-regression compiled>> ] unit-test
-
-[ vector ] [ dispatch-alignment-regression ] unit-test
-
-! Regression
-: bad-value-bug ( a -- b ) [ 3 ] [ 3 ] if f <array> ;
-
-[ { f f f } ] [ t bad-value-bug ] unit-test
-
-! PowerPC regression
-TUPLE: id obj ;
-
-: (gc-check-bug) ( a b -- c )
-    { [ id boa ] [ id boa ] } dispatch ;
-
-: gc-check-bug ( -- )
-    10000000 [ "hi" 0 (gc-check-bug) drop ] times ;
-
-[ ] [ gc-check-bug ] unit-test
index 19d80ec14fce4062ad7896a6b28f2cd894dd6a87..c2ec6552cd6219e06304b6c2dd108f58b993ea0b 100644 (file)
@@ -1,9 +1,13 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: fry accessors quotations kernel sequences namespaces
-assocs words arrays vectors hints combinators stack-checker
-stack-checker.state stack-checker.visitor stack-checker.errors
-stack-checker.backend compiler.tree ;
+assocs words arrays vectors hints combinators compiler.tree
+stack-checker
+stack-checker.state
+stack-checker.errors
+stack-checker.visitor
+stack-checker.backend
+stack-checker.recursive-state ;
 IN: compiler.tree.builder
 
 : with-tree-builder ( quot -- nodes )
@@ -12,12 +16,13 @@ IN: compiler.tree.builder
 
 : build-tree ( quot -- nodes )
     #! Not safe to call from inference transforms.
-    [ f infer-quot ] with-tree-builder nip ;
+    [ f initial-recursive-state infer-quot ] with-tree-builder nip ;
 
 : build-tree-with ( in-stack quot -- nodes out-stack )
     #! Not safe to call from inference transforms.
     [
-        [ >vector meta-d set ] [ f infer-quot ] bi*
+        [ >vector meta-d set ]
+        [ f initial-recursive-state infer-quot ] bi*
     ] with-tree-builder nip
     unclip-last in-d>> ;
 
@@ -32,10 +37,10 @@ IN: compiler.tree.builder
     dup
     [ "inline" word-prop ]
     [ "recursive" word-prop ] bi and [
-        1quotation f infer-quot
+        1quotation f initial-recursive-state infer-quot
     ] [
-        [ specialized-def ]
-        [ dup 2array 1array ] bi infer-quot
+        [ specialized-def ] [ initial-recursive-state ] bi
+        infer-quot
     ] if ;
 
 : check-cannot-infer ( word -- )
index b712a6e354accd0e92fd1b7cc7aa2ae0025f2551..4f99fa015d83f7f5ab4cedba19593191a26ecd91 100644 (file)
@@ -22,8 +22,8 @@ ERROR: check-use-error value message ;
 GENERIC: check-node* ( node -- )
 
 M: #shuffle check-node*
-    [ [ mapping>> values ] [ in-d>> ] bi subset? [ "Bad mapping inputs" throw ] unless ]
-    [ [ mapping>> keys ] [ out-d>> ] bi set= [ "Bad mapping outputs" throw ] unless ]
+    [ [ mapping>> values ] [ [ in-d>> ] [ in-r>> ] bi append ] bi subset? [ "Bad mapping inputs" throw ] unless ]
+    [ [ mapping>> keys ] [ [ out-d>> ] [ out-r>> ] bi append ] bi set= [ "Bad mapping outputs" throw ] unless ]
     bi ;
 
 : check-lengths ( seq -- )
@@ -31,13 +31,6 @@ M: #shuffle check-node*
 
 M: #copy check-node* inputs/outputs 2array check-lengths ;
 
-: check->r/r> ( node -- )
-    inputs/outputs [ drop ] [ 2array check-lengths ] if-empty ;
-
-M: #>r check-node* check->r/r> ;
-
-M: #r> check-node* check->r/r> ;
-
 M: #return-recursive check-node* inputs/outputs 2array check-lengths ;
 
 M: #phi check-node*
@@ -113,11 +106,8 @@ M: #push check-stack-flow* check-out-d ;
 
 M: #call check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
 
-M: #shuffle check-stack-flow* [ check-in-d ] [ check-out-d ] bi ;
-
-M: #>r check-stack-flow* [ check-in-d ] [ check-out-r ] bi ;
-
-M: #r> check-stack-flow* [ check-in-r ] [ check-out-d ] bi ;
+M: #shuffle check-stack-flow*
+    { [ check-in-d ] [ check-in-r ] [ check-out-d ] [ check-out-r ] } cleave ;
 
 : assert-datastack-empty ( -- )
     datastack get empty? [ "Data stack not empty" throw ] unless ;
index 719c80f911120c6985d32fffc2699bbd737a5921..eba82384ab362b2fa8b9171bbbbefb4055458ba2 100644 (file)
@@ -39,7 +39,7 @@ M: #branch remove-dead-code*
     [ drop filter-live ] [ swap nths ] 2bi
     [ make-values ] keep
     [ drop ] [ zip ] 2bi
-    #shuffle ;
+    #data-shuffle ;
 
 : insert-drops ( nodes values indices -- nodes' )
     '[
index 08bfde55b2c85b856ab31b1501863fc1f0900cf9..44b71935c8f0fea7a6be46e18bf409329cf6bc9f 100644 (file)
@@ -1,8 +1,9 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: fry accessors namespaces assocs deques search-deques
-kernel sequences sequences.deep words sets stack-checker.branches
-compiler.tree compiler.tree.def-use compiler.tree.combinators ;
+dlists kernel sequences sequences.deep words sets
+stack-checker.branches compiler.tree compiler.tree.def-use
+compiler.tree.combinators ;
 IN: compiler.tree.dead-code.liveness
 
 SYMBOL: work-list
index addb13ced3a2e8462e012899631aeca39545daeb..185c776c4e37590fe8446a9bc2a1341e573e8ea7 100644 (file)
@@ -39,12 +39,6 @@ M: #copy compute-live-values*
 
 M: #call compute-live-values* nip look-at-inputs ;
 
-M: #>r compute-live-values*
-    [ out-r>> ] [ in-d>> ] bi look-at-mapping ;
-
-M: #r> compute-live-values*
-    [ out-d>> ] [ in-r>> ] bi look-at-mapping ;
-
 M: #shuffle compute-live-values*
     mapping>> at look-at-value ;
 
@@ -61,7 +55,7 @@ M: #alien-indirect compute-live-values* nip look-at-inputs ;
     zip filter-mapping values ;
 
 : filter-live ( values -- values' )
-    [ live-value? ] filter ;
+    dup empty? [ [ live-value? ] filter ] unless ;
 
 :: drop-values ( inputs outputs mapping-keys mapping-values -- #shuffle )
     inputs
@@ -69,7 +63,7 @@ M: #alien-indirect compute-live-values* nip look-at-inputs ;
     outputs
     mapping-keys
     mapping-values
-    filter-corresponding zip #shuffle ; inline
+    filter-corresponding zip #data-shuffle ; inline
 
 :: drop-dead-values ( outputs -- #shuffle )
     [let* | new-outputs [ outputs make-values ]
@@ -95,16 +89,6 @@ M: #alien-indirect compute-live-values* nip look-at-inputs ;
 M: #introduce remove-dead-code* ( #introduce -- nodes )
     maybe-drop-dead-outputs ;
 
-M: #>r remove-dead-code*
-    [ filter-live ] change-out-r
-    [ filter-live ] change-in-d
-    dup in-d>> empty? [ drop f ] when ;
-
-M: #r> remove-dead-code*
-    [ filter-live ] change-out-d
-    [ filter-live ] change-in-r
-    dup in-r>> empty? [ drop f ] when ;
-
 M: #push remove-dead-code*
     dup out-d>> first live-value? [ drop f ] unless ;
 
@@ -125,12 +109,14 @@ M: #call remove-dead-code*
 M: #shuffle remove-dead-code*
     [ filter-live ] change-in-d
     [ filter-live ] change-out-d
+    [ filter-live ] change-in-r
+    [ filter-live ] change-out-r
     [ filter-mapping ] change-mapping
-    dup in-d>> empty? [ drop f ] when ;
+    dup [ in-d>> empty? ] [ in-r>> empty? ] bi and [ drop f ] when ;
 
 M: #copy remove-dead-code*
     [ in-d>> ] [ out-d>> ] bi
-    2dup swap zip #shuffle
+    2dup swap zip #data-shuffle
     remove-dead-code* ;
 
 M: #terminate remove-dead-code*
index 59a028a4f42ea31b038c290143e13e80922cf613..a1d87734843f14af03f258b551c4a51b68d0dad4 100644 (file)
@@ -3,7 +3,7 @@
 USING: kernel assocs match fry accessors namespaces make effects
 sequences sequences.private quotations generic macros arrays
 prettyprint prettyprint.backend prettyprint.sections math words
-combinators io sorting hints qualified
+combinators combinators.short-circuit io sorting hints qualified
 compiler.tree
 compiler.tree.recursive
 compiler.tree.normalization
@@ -57,9 +57,41 @@ TUPLE: shuffle-node { effect effect } ;
 
 M: shuffle-node pprint* effect>> effect>string text ;
  
+: (shuffle-effect) ( in out #shuffle -- effect )
+    mapping>> '[ _ at ] map <effect> ;
+
+: shuffle-effect ( #shuffle -- effect )
+    [ in-d>> ] [ out-d>> ] [ ] tri (shuffle-effect) ;
+
+: #>r? ( #shuffle -- ? )
+    {
+        [ in-d>> length 1 = ]
+        [ out-r>> length 1 = ]
+        [ in-r>> empty? ]
+        [ out-d>> empty? ]
+    } 1&& ;
+
+: #r>? ( #shuffle -- ? )
+    {
+        [ in-d>> empty? ]
+        [ out-r>> empty? ]
+        [ in-r>> length 1 = ]
+        [ out-d>> length 1 = ]
+    } 1&& ;
+
 M: #shuffle node>quot
-    shuffle-effect dup pretty-shuffle
-    [ % ] [ shuffle-node boa , ] ?if ;
+    {
+        { [ dup #>r? ] [ drop \ >r , ] }
+        { [ dup #r>? ] [ drop \ r> , ] }
+        {
+            [ dup [ in-r>> empty? ] [ out-r>> empty? ] bi and ]
+            [
+                shuffle-effect dup pretty-shuffle
+                [ % ] [ shuffle-node boa , ] ?if
+            ]
+        }
+        [ drop "COMPLEX SHUFFLE" , ]
+    } cond ;
 
 M: #push node>quot literal>> , ;
 
@@ -82,16 +114,6 @@ M: #if node>quot
 M: #dispatch node>quot
     children>> [ nodes>quot ] map , \ dispatch , ;
 
-M: #>r node>quot
-    [ in-d>> length ] [ out-r>> empty? \ drop \ >r ? ] bi
-    <repetition> % ;
-
-DEFER: rdrop
-
-M: #r> node>quot
-    [ in-r>> length ] [ out-d>> empty? \ rdrop \ r> ? ] bi
-    <repetition> % ;
-
 M: #alien-invoke node>quot params>> , \ #alien-invoke , ;
 
 M: #alien-indirect node>quot params>> , \ #alien-indirect , ;
index 2379f3918d46b76404d7bf075c8a6155584a0ccb..705f44eeb66105c3032cfb23ef9723aa460ef6bf 100644 (file)
@@ -18,12 +18,16 @@ TUPLE: definition value node uses ;
         swap >>node
         V{ } clone >>uses ;
 
+ERROR: no-def-error value ;
+
 : 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-use get 2dup key? [
-        "Multiple defs" throw
+        multiple-defs-error
     ] [
         [ [ <definition> ] keep ] dip set-at
     ] if ;
@@ -38,16 +42,16 @@ GENERIC: node-uses-values ( node -- values )
 
 M: #introduce node-uses-values drop f ;
 M: #push node-uses-values drop f ;
-M: #r> node-uses-values in-r>> ;
 M: #phi node-uses-values phi-in-d>> concat remove-bottom prune ;
 M: #declare node-uses-values declaration>> keys ;
 M: #terminate node-uses-values [ in-d>> ] [ in-r>> ] bi append ;
+M: #shuffle node-uses-values [ in-d>> ] [ in-r>> ] bi append ;
 M: #alien-callback node-uses-values drop f ;
 M: node node-uses-values in-d>> ;
 
 GENERIC: node-defs-values ( node -- values )
 
-M: #>r node-defs-values out-r>> ;
+M: #shuffle node-defs-values [ out-d>> ] [ out-r>> ] bi append ;
 M: #branch node-defs-values drop f ;
 M: #declare node-defs-values drop f ;
 M: #return node-defs-values drop f ;
index 4c197d7fc03d6613763baaf191749ac852003fce..5d34eaad1561b9e8a8dcb08e0b799d716f2f5646 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors assocs namespaces sequences kernel math
-combinators sets disjoint-sets fry stack-checker.state ;
+combinators sets disjoint-sets fry stack-checker.values ;
 IN: compiler.tree.escape-analysis.allocations
 
 ! A map from values to one of the following:
index 2d2e42999461c3292e47d45a9122e602a9b2b01b..16a27e020a13dfa6b8aab38619ba74638d1eedc5 100644 (file)
@@ -1,6 +1,7 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel accessors sequences words memoize classes.builtin
+fry assocs
 compiler.tree
 compiler.tree.combinators
 compiler.tree.propagation.info
@@ -27,9 +28,10 @@ GENERIC: finalize* ( node -- nodes )
 M: #copy finalize* drop f ;
 
 M: #shuffle finalize*
-    dup shuffle-effect
-    [ in>> ] [ out>> ] bi sequence=
-    [ drop f ] when ;
+    dup
+    [ [ in-d>> ] [ out-d>> ] [ mapping>> ] tri '[ _ at ] map sequence= ]
+    [ [ in-r>> ] [ out-r>> ] [ mapping>> ] tri '[ _ at ] map sequence= ]
+    bi and [ drop f ] when ;
 
 : builtin-predicate? ( #call -- ? )
     word>> "predicating" word-prop builtin-class? ;
index d6ed59cbaa3cca1946fca5e71e04571b30e95434..00632ec6f6bc5af37025a151d3f635db802e60c8 100644 (file)
@@ -79,7 +79,7 @@ GENERIC: apply-identities* ( node -- node )
 
 : select-input ( node n -- #shuffle )
     [ [ in-d>> ] [ out-d>> ] bi ] dip
-    pick nth over first associate #shuffle ;
+    pick nth over first associate #data-shuffle ;
 
 M: #call apply-identities*
     dup word>> "identities" word-prop [
index 3050df2611397859fc2dbf9c847aa231d98f8c5f..9d68f4a733bf5f9df42a165b86516bc14f4a1562 100644 (file)
@@ -10,7 +10,7 @@ SYMBOL: rename-map
     [ rename-map get at ] keep or ;
 
 : rename-values ( values -- values' )
-    rename-map get '[ [ _ at ] keep or ] map ;
+    dup empty? [ rename-map get '[ [ _ at ] keep or ] map ] unless ;
 
 : add-renamings ( old new -- )
     [ rename-values ] dip
@@ -22,13 +22,11 @@ M: #introduce rename-node-values* ;
 
 M: #shuffle rename-node-values*
     [ rename-values ] change-in-d
+    [ rename-values ] change-in-r
     [ [ rename-value ] assoc-map ] change-mapping ;
 
 M: #push rename-node-values* ;
 
-M: #r> rename-node-values*
-    [ rename-values ] change-in-r ;
-
 M: #terminate rename-node-values*
     [ rename-values ] change-in-d
     [ rename-values ] change-in-r ;
index d257cd660078fd74a30d5425ed2ad94f34313e5e..2e40693e6982df2fa5961eec6d964a87a940d5eb 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 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
 
 ! Collect label info
index 05f33902ecd805b6d52c90a14e16f52d181e871f..9f9a43df6460043c8064149ab4a486b7dffc6172 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2004, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: fry arrays generic assocs kernel math namespaces parser
-sequences words vectors math.intervals effects classes
+sequences words vectors math.intervals classes
 accessors combinators stack-checker.state stack-checker.visitor
 stack-checker.inlining ;
 IN: compiler.tree
@@ -42,30 +42,21 @@ TUPLE: #push < node literal out-d ;
 
 TUPLE: #renaming < node ;
 
-TUPLE: #shuffle < #renaming mapping in-d out-d ;
+TUPLE: #shuffle < #renaming mapping in-d out-d in-r out-r ;
 
-: #shuffle ( inputs outputs mapping -- node )
+: #shuffle ( in-d out-d in-r out-r mapping -- node )
     \ #shuffle new
         swap >>mapping
-        swap >>out-d
-        swap >>in-d ;
-
-: #drop ( inputs -- node )
-    { } { } #shuffle ;
-
-TUPLE: #>r < #renaming in-d out-r ;
-
-: #>r ( inputs outputs -- node )
-    \ #>r new
         swap >>out-r
+        swap >>in-r
+        swap >>out-d
         swap >>in-d ;
 
-TUPLE: #r> < #renaming in-r out-d ;
+: #data-shuffle ( in-d out-d mapping -- node )
+    [ f f ] dip #shuffle ; inline
 
-: #r> ( inputs outputs -- node )
-    \ #r> new
-        swap >>out-d
-        swap >>in-r ;
+: #drop ( inputs -- node )
+    { } { } #data-shuffle ;
 
 TUPLE: #terminate < node in-d in-r ;
 
@@ -171,16 +162,9 @@ TUPLE: #alien-callback < #alien-node ;
 GENERIC: inputs/outputs ( #renaming -- inputs outputs )
 
 M: #shuffle inputs/outputs mapping>> unzip swap ;
-M: #>r inputs/outputs [ in-d>> ] [ out-r>> ] bi ;
-M: #r> inputs/outputs [ in-r>> ] [ out-d>> ] bi ;
 M: #copy inputs/outputs [ in-d>> ] [ out-d>> ] bi ;
 M: #return-recursive inputs/outputs [ in-d>> ] [ out-d>> ] bi ;
 
-: shuffle-effect ( #shuffle -- effect )
-    [ in-d>> ] [ out-d>> ] [ mapping>> ] tri
-    '[ _ at ] map
-    <effect> ;
-
 : recursive-phi-in ( #enter-recursive -- seq )
     [ label>> calls>> [ in-d>> ] map ] [ in-d>> ] bi suffix ;
 
@@ -193,8 +177,8 @@ M: vector #call, #call node, ;
 M: vector #push, #push node, ;
 M: vector #shuffle, #shuffle node, ;
 M: vector #drop, #drop node, ;
-M: vector #>r, #>r node, ;
-M: vector #r>, #r> node, ;
+M: vector #>r, [ [ f f ] dip ] [ swap zip ] 2bi #shuffle, ;
+M: vector #r>, [ swap [ f swap ] dip f ] [ swap zip ] 2bi #shuffle, ;
 M: vector #return, #return node, ;
 M: vector #enter-recursive, #enter-recursive node, ;
 M: vector #return-recursive, #return-recursive node, ;
index 8e07c081942ca79c7de040bbc0f0e111e77e8748..52903fce8de3064ba14d6fc322f3b908720488de 100644 (file)
@@ -42,7 +42,7 @@ M: #push unbox-tuples* ( #push -- nodes )
     [ dup unboxed-allocation [ (flatten-values) ] [ ] ?if ] map ;
 
 : flatten-values ( values -- values' )
-    (flatten-values) flatten ;
+    dup empty? [ (flatten-values) flatten ] unless ;
 
 : prepare-slot-access ( #call -- tuple-values outputs slot-values )
     [ in-d>> flatten-values ]
@@ -54,7 +54,7 @@ M: #push unbox-tuples* ( #push -- nodes )
     ] tri ;
 
 : slot-access-shuffle ( tuple-values outputs slot-values -- #shuffle )
-    [ drop ] [ zip ] 2bi #shuffle ;
+    [ drop ] [ zip ] 2bi #data-shuffle ;
 
 : unbox-slot-access ( #call -- nodes )
     dup out-d>> first unboxed-slot-access? [
@@ -77,17 +77,11 @@ M: #copy unbox-tuples*
     [ flatten-values ] change-in-d
     [ flatten-values ] change-out-d ;
 
-M: #>r unbox-tuples*
-    [ flatten-values ] change-in-d
-    [ flatten-values ] change-out-r ;
-
-M: #r> unbox-tuples*
-    [ flatten-values ] change-in-r
-    [ flatten-values ] change-out-d ;
-
 M: #shuffle unbox-tuples*
     [ flatten-values ] change-in-d
     [ flatten-values ] change-out-d
+    [ flatten-values ] change-in-r
+    [ flatten-values ] change-out-r
     [ unzip [ flatten-values ] bi@ zip ] change-mapping ;
 
 M: #terminate unbox-tuples*
index a23301c1e281a238def0312b3ec0159b0da5b2b9..cb07e5a8d6e148e65c7ec6aad162232e968c899a 100644 (file)
@@ -2,27 +2,27 @@ USING: help.markup help.syntax sequences ;
 IN: concurrency.combinators\r
 \r
 HELP: parallel-map\r
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- newelt )" } } { "newseq" sequence } }\r
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- newelt )" } } { "newseq" sequence } }\r
 { $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the results at the end." }\r
 { $errors "Throws an error if one of the iterations throws an error." } ;\r
 \r
 HELP: 2parallel-map\r
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- newelt )" } } { "newseq" sequence } }\r
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt -- newelt )" } } { "newseq" sequence } }\r
 { $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", collecting the results at the end." }\r
 { $errors "Throws an error if one of the iterations throws an error." } ;\r
 \r
 HELP: parallel-each\r
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } }\r
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- )" } } }\r
 { $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", blocking until all quotations complete." }\r
 { $errors "Throws an error if one of the iterations throws an error." } ;\r
 \r
 HELP: 2parallel-each\r
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } }\r
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt -- )" } } }\r
 { $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", blocking until all quotations complete." }\r
 { $errors "Throws an error if one of the iterations throws an error." } ;\r
 \r
 HELP: parallel-filter\r
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "newseq" sequence } }\r
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "newseq" sequence } }\r
 { $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." }\r
 { $errors "Throws an error if one of the iterations throws an error." } ;\r
 \r
index 99b4bb6e81219de00233456aef94b7fb08f809e2..22549c1720260dfc8f3e82bc4b6e79193e70407c 100644 (file)
@@ -5,7 +5,7 @@ continuations help.markup help.syntax quotations ;
 IN: concurrency.futures\r
 \r
 HELP: future\r
-{ $values { "quot" "a quotation with stack effect " { $snippet "( -- value )" } } { "future" future } }\r
+{ $values { "quot" { $quotation "( -- value )" } } { "future" future } }\r
 { $description "Creates a deferred computation."\r
 $nl\r
 "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 } "." } ;\r
index a3cf2fc7824417d9f7b0e83a09a8566c67d74ded..b74dcec384bb5502ef59a2539fa42bc93241c5ba 100644 (file)
@@ -14,7 +14,7 @@ HELP: <reentrant-lock>
 { $description "Creates a reentrant lock." } ;\r
 \r
 HELP: with-lock-timeout\r
-{ $values { "lock" lock } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } }\r
+{ $values { "lock" lock } { "timeout" { $maybe duration } } { "quot" quotation } }\r
 { $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." }\r
 { $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." } ;\r
 \r
@@ -36,7 +36,7 @@ HELP: rw-lock
 { $class-description "The class of reader/writer locks." } ;\r
 \r
 HELP: with-read-lock-timeout\r
-{ $values { "lock" lock } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } }\r
+{ $values { "lock" lock } { "timeout" { $maybe duration } } { "quot" quotation } }\r
 { $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." }\r
 { $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." } ;\r
 \r
@@ -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." } ;\r
 \r
 HELP: with-write-lock-timeout\r
-{ $values { "lock" lock } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } }\r
+{ $values { "lock" lock } { "timeout" { $maybe duration } } { "quot" quotation } }\r
 { $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." }\r
 { $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." } ;\r
 \r
index a9b86e3bcdef714046410bfcc82568cf9c89826f..234fb27d60806cec467b0253b45b2cddd24ab46a 100644 (file)
@@ -1,4 +1,4 @@
-USING: help.markup help.syntax kernel arrays ;\r
+USING: help.markup help.syntax kernel arrays calendar ;\r
 IN: concurrency.mailboxes\r
 \r
 HELP: <mailbox>\r
@@ -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." } ;\r
 \r
 HELP: block-unless-pred\r
-{ $values { "pred" "a quotation with stack effect " { $snippet "( X -- bool )" } } \r
-          { "mailbox" mailbox }\r
-          { "timeout" "a timeout in milliseconds, or " { $link f } }\r
+{ $values { "pred" { $quotation "( obj -- ? )" } } \r
+    { "mailbox" mailbox }\r
+    { "timeout" "a " { $link duration } " or " { $link f } }\r
 }\r
 { $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." } ;\r
 \r
 HELP: block-if-empty\r
 { $values { "mailbox" mailbox } \r
-      { "timeout" "a timeout in milliseconds, or " { $link f } }\r
+    { "timeout" "a " { $link duration } " or " { $link f } }\r
 }\r
 { $description "Block the thread if the mailbox is empty." } ;\r
 \r
 HELP: mailbox-get\r
-{ $values { "mailbox" mailbox } \r
-          { "obj" object }\r
-}\r
+{ $values { "mailbox" mailbox } { "obj" object } }\r
 { $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." } ;\r
 \r
 HELP: mailbox-get-all\r
-{ $values { "mailbox" mailbox } \r
-          { "array" array }\r
-}\r
+{ $values { "mailbox" mailbox } { "array" array } }\r
 { $description "Blocks the thread if the mailbox is empty, otherwise removes all objects in the mailbox and returns an array containing the objects." } ;\r
 \r
 HELP: while-mailbox-empty\r
 { $values { "mailbox" mailbox } \r
-          { "quot" "a quotation with stack effect " { $snippet "( -- )" } }\r
+          { "quot" { $quotation "( -- )" } }\r
 }\r
 { $description "Repeatedly call the quotation while there are no items in the mailbox." } ;\r
 \r
 HELP: mailbox-get?\r
 { $values { "mailbox" mailbox } \r
-          { "pred" "a quotation with stack effect " { $snippet "( X -- bool )" } }\r
+          { "pred" { $quotation "( obj -- ? )" } }\r
           { "obj" object }\r
 }\r
-{ $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." } ;\r
-\r
+{ $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." } ;\r
 \r
 ARTICLE: "concurrency.mailboxes" "Mailboxes"\r
-"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."\r
+"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."\r
 { $subsection mailbox }\r
 { $subsection <mailbox> }\r
 "Removing the first element:"\r
index 6a4a2bf8d6fd1fbdf8230709b87621c6dc0919b7..be7a8cf65b932b0d4b941fe459dd2221bc293b64 100644 (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." } ;\r
 \r
 HELP: ?promise-timeout\r
-{ $values { "promise" promise } { "timeout" "a " { $link duration } " or " { $link f } } { "result" object } }\r
+{ $values { "promise" promise } { "timeout" { $maybe duration } } { "result" object } }\r
 { $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." }\r
 { $errors "Throws an error if the timeout expires before the promise has been fulfilled." } ;\r
 \r
index 379fd6a3a0b5c37e667687d973ab780faf120b5d..c86623f86f10f1bf63bedde39db9ffee15967ad6 100644 (file)
@@ -9,7 +9,7 @@ HELP: <semaphore>
 { $description "Creates a counting semaphore with the specified initial count." } ;\r
 \r
 HELP: acquire-timeout\r
-{ $values { "semaphore" semaphore } { "timeout" "a " { $link duration } " or " { $link f } } }\r
+{ $values { "semaphore" semaphore } { "timeout" { $maybe duration } } }\r
 { $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." }\r
 { $errors "Throws an error if the timeout expires before the semaphore is released." } ;\r
 \r
@@ -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." } ;\r
 \r
 HELP: with-semaphore-timeout\r
-{ $values { "semaphore" semaphore } { "timeout" "a " { $link duration } " or " { $link f } } { "quot" quotation } }\r
+{ $values { "semaphore" semaphore } { "timeout" { $maybe duration } } { "quot" quotation } }\r
 { $description "Calls the quotation with the semaphore held." } ;\r
 \r
 HELP: with-semaphore\r
index b0b5b048d9f9be0af14e8e1027893a8637eb5ce2..96dd577c10be6615a5e9c2eaa1d04b79bffaf7c8 100644 (file)
@@ -50,7 +50,7 @@ HOOK: %call cpu ( word -- )
 HOOK: %jump-label cpu ( label -- )
 HOOK: %return cpu ( -- )
 
-HOOK: %dispatch cpu ( src temp -- )
+HOOK: %dispatch cpu ( src temp offset -- )
 HOOK: %dispatch-label cpu ( word -- )
 
 HOOK: %slot cpu ( dst obj slot tag temp -- )
index 9bf88185c5d8a0c156f7723468fb64707cef5c1d..aee0f3f4f38c66f6c2f603846e11e02f975b2e31 100644 (file)
@@ -57,7 +57,12 @@ big-endian on
 \r
 [\r
     0 6 LOAD32\r
-    4 1 MR\r
+    7 6 0 LWZ\r
+    1 7 0 STW\r
+] rc-absolute-ppc-2/2 rt-stack-chain 1 jit-save-stack jit-define\r
+\r
+[\r
+    0 6 LOAD32\r
     6 MTCTR\r
     BCTR\r
 ] rc-absolute-ppc-2/2 rt-primitive 1 jit-primitive jit-define\r
index 49caae4bb8616699c9fea6e2f2458e9730534523..c656ae4d89aaadcf86afe1aa5f7b08614b5f0c33 100644 (file)
@@ -111,10 +111,10 @@ M: ppc %call ( label -- ) BL ;
 M: ppc %jump-label ( label -- ) B ;
 M: ppc %return ( -- ) BLR ;
 
-M:: ppc %dispatch ( src temp -- )
-    0 temp LOAD32 rc-absolute-ppc-2/2 rel-here
-    temp temp src ADD
-    temp temp 5 cells LWZ
+M:: ppc %dispatch ( src temp offset -- )
+    0 temp LOAD32
+    4 offset + cells rc-absolute-ppc-2/2 rel-here
+    temp temp src LWZX
     temp MTCTR
     BCTR ;
 
index f26d76551aa16e24e10f2a1d126325588e0e5362..f892271fd5b2d22254b0288ed1409568b9043d83 100644 (file)
@@ -6,7 +6,7 @@ accessors init combinators command-line cpu.x86.assembler
 cpu.x86 cpu.architecture compiler compiler.units
 compiler.constants compiler.alien compiler.codegen
 compiler.codegen.fixup compiler.cfg.instructions
-compiler.cfg.builder compiler.cfg.intrinsics ;
+compiler.cfg.builder compiler.cfg.intrinsics make ;
 IN: cpu.x86.32
 
 ! We implement the FFI for Linux, OS X and Windows all at once.
@@ -26,6 +26,18 @@ M: x86.32 stack-reg ESP ;
 M: x86.32 temp-reg-1 EAX ;
 M: x86.32 temp-reg-2 ECX ;
 
+M:: x86.32 %dispatch ( src temp offset -- )
+    ! Load jump table base.
+    src HEX: ffffffff ADD
+    offset cells rc-absolute-cell rel-here
+    ! Go
+    src HEX: 7f [+] JMP
+    ! Fix up the displacement above
+    cell code-alignment
+    [ 7 + building get dup pop* push ]
+    [ align-code ]
+    bi ;
+
 M: x86.32 reserved-area-size 0 ;
 
 M: x86.32 %alien-global 0 [] MOV rc-absolute-cell rel-dlsym ;
index 44f840e66aa2179264d44172f92f5698f3ca07a7..ba963ab477d2f087df299394f8fb1319255558f9 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2007 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: bootstrap.image.private kernel namespaces system
-cpu.x86.assembler layouts vocabs parser ;
+cpu.x86.assembler layouts vocabs parser compiler.constants ;
 IN: bootstrap.x86
 
 4 \ cell set
@@ -19,5 +19,14 @@ IN: bootstrap.x86
 : fixnum>slot@ ( -- ) arg0 1 SAR ;
 : rex-length ( -- n ) 0 ;
 
+[
+    arg0 0 [] MOV                              ! load stack_chain
+    arg0 [] stack-reg MOV                      ! save stack pointer
+] rc-absolute-cell rt-stack-chain 2 jit-save-stack jit-define
+
+[
+    (JMP) drop
+] rc-relative rt-primitive 1 jit-primitive jit-define
+
 << "resource:basis/cpu/x86/bootstrap.factor" parse-file parsed >>
 call
index 0d2066002176f1abfa139e63de045faac5569110..75c808b50a405bec492dd04d46375825289a02e5 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays kernel math namespaces make sequences
 system layouts alien alien.c-types alien.accessors alien.structs
-slots splitting assocs combinators cpu.x86.assembler
+slots splitting assocs combinators make locals cpu.x86.assembler
 cpu.x86 cpu.architecture compiler.constants
 compiler.codegen compiler.codegen.fixup
 compiler.cfg.instructions compiler.cfg.builder
@@ -24,6 +24,19 @@ M: x86.64 stack-reg RSP ;
 M: x86.64 temp-reg-1 RAX ;
 M: x86.64 temp-reg-2 RCX ;
 
+M:: x86.64 %dispatch ( src temp offset -- )
+    ! Load jump table base.
+    temp HEX: ffffffff MOV
+    offset cells rc-absolute-cell rel-here
+    ! Add jump table base
+    src temp ADD
+    src HEX: 7f [+] JMP
+    ! Fix up the displacement above
+    cell code-alignment
+    [ 15 + building get dup pop* push ]
+    [ align-code ]
+    bi ;
+
 : param-reg-1 int-regs param-regs first ; inline
 : param-reg-2 int-regs param-regs second ; inline
 : param-reg-3 int-regs param-regs third ; inline
index acac8b55bc14f7df5418de33fd24d7bc456aea9e..83a72d6dd308ade8135c68a27ce0f883033a6721 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2007 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: bootstrap.image.private kernel namespaces system
-cpu.x86.assembler layouts vocabs parser ;
+cpu.x86.assembler layouts vocabs parser compiler.constants math ;
 IN: bootstrap.x86
 
 8 \ cell set
@@ -16,5 +16,16 @@ IN: bootstrap.x86
 : fixnum>slot@ ( -- ) ;
 : rex-length ( -- n ) 1 ;
 
+[
+    arg0 0 MOV                                 ! load stack_chain
+    arg0 arg0 [] MOV
+    arg0 [] stack-reg MOV                      ! save stack pointer
+] rc-absolute-cell rt-stack-chain 1 rex-length + jit-save-stack jit-define
+
+[
+    arg1 0 MOV                                 ! load XT
+    arg1 JMP                                   ! go
+] rc-absolute-cell rt-primitive 1 rex-length + jit-primitive jit-define
+
 << "resource:basis/cpu/x86/bootstrap.factor" parse-file parsed >>
 call
index 6dadbc096cbd868bee902ad8b84e34fa6b217c19..1ee74a434b0bc611aeb82399ab53325dfc17d46f 100644 (file)
@@ -44,12 +44,6 @@ big-endian off
     ds-reg [] arg0 MOV                         ! store literal on datastack
 ] rc-absolute-cell rt-immediate 1 rex-length + jit-push-immediate jit-define
 
-[
-    arg0 0 MOV                                 ! load XT
-    arg1 stack-reg MOV                         ! pass callstack pointer as arg 2
-    arg0 JMP                                   ! go
-] rc-absolute-cell rt-primitive 1 rex-length + jit-primitive jit-define
-
 [
     (JMP) drop
 ] rc-relative rt-xt 1 jit-word-jump jit-define
index 4f72fe45e1c84653bd3b4c10a36c25272904a1b6..dfe3d3e55e55fc59cc4294dafb8129e7224e79a8 100644 (file)
@@ -60,19 +60,6 @@ M: x86 %return ( -- ) 0 RET ;
 : align-code ( n -- )
     0 <repetition> % ;
 
-M:: x86 %dispatch ( src temp -- )
-    ! Load jump table base. We use a temporary register
-    ! since on AMD64 we have to load a 64-bit immediate. On
-    ! x86, this is redundant.
-    ! Add jump table base
-    temp HEX: ffffffff MOV rc-absolute-cell rel-here
-    src temp ADD
-    src HEX: 7f [+] JMP
-    ! Fix up the displacement above
-    cell code-alignment dup bootstrap-cell 8 = 15 9 ? +
-    building get dup pop* push
-    align-code ;
-
 M: x86 %dispatch-label ( word -- )
     0 cell, rc-absolute-cell rel-word ;
 
index 58f077ed1e44618eec2fd9f7f5325b686bfaf5e1..e747bd93164385ea129aeff3fa8977eb2767ba82 100644 (file)
@@ -4,7 +4,7 @@ IN: deques
 
 HELP: deque-empty?
 { $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)." } ;
 
 HELP: clear-deque
@@ -12,12 +12,6 @@ HELP: clear-deque
      { "deque" 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?
 { $values
      { "value" object } { "deque" deque }
@@ -31,7 +25,7 @@ HELP: push-front
 
 HELP: push-front*
 { $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)." } ;
 
 HELP: push-back
@@ -41,7 +35,7 @@ HELP: push-back
 
 HELP: push-back*
 { $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)." } ;
 
 HELP: push-all-back
@@ -56,7 +50,7 @@ HELP: push-all-front
 
 HELP: peek-front
 { $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
 { $values { "deque" deque } { "obj" object } }
@@ -65,12 +59,12 @@ HELP: pop-front
 
 HELP: pop-front*
 { $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)." } ;
 
 HELP: peek-back
 { $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
 { $values { "deque" deque } { "obj" object } }
@@ -79,13 +73,13 @@ HELP: pop-back
 
 HELP: pop-back*
 { $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)." } ;
 
 HELP: delete-node
 { $values
      { "node" object } { "deque" deque } }
-{ $description "Deletes the node from the deque." } ;
+{ $contract "Deletes the node from the deque." } ;
 
 HELP: deque
 { $description "A data structure that has constant-time insertion and removal of elements at both ends." } ;
@@ -111,7 +105,7 @@ $nl
 "Querying the deque:"
 { $subsection peek-front }
 { $subsection peek-back }
-{ $subsection deque-length }
+{ $subsection deque-empty? }
 { $subsection deque-member? }
 "Adding and removing elements:"
 { $subsection push-front* }
@@ -123,7 +117,6 @@ $nl
 { $subsection delete-node }
 { $subsection node-value }
 "Utility operations built in terms of the above:"
-{ $subsection deque-empty? }
 { $subsection push-front }
 { $subsection push-all-front }
 { $subsection push-back }
index 1d86a3f1db5ee0e6bfea219c0a5278a5e04f9967..f4e68c214b2a921b390984f43f55099032a43cd4 100644 (file)
@@ -10,13 +10,10 @@ GENERIC: peek-back ( deque -- obj )
 GENERIC: pop-front* ( deque -- )
 GENERIC: pop-back* ( deque -- )
 GENERIC: delete-node ( node deque -- )
-GENERIC: deque-length ( deque -- n )
 GENERIC: deque-member? ( value deque -- ? )
 GENERIC: clear-deque ( deque -- )
 GENERIC: node-value ( node -- value )
-
-: deque-empty? ( deque -- ? )
-    deque-length zero? ;
+GENERIC: deque-empty? ( deque -- ? )
 
 : push-front ( obj deque -- )
     push-front* drop ;
index 557010cf7c636c033fc67e505b0341051ff919d7..ef6087f852fc9a0ced9a3b1d5f83a55783a07e7d 100644 (file)
@@ -1,5 +1,5 @@
 USING: help.markup help.syntax kernel quotations
-deques ;
+deques search-deques hashtables ;
 IN: dlists
 
 ARTICLE: "dlists" "Double-linked lists"
@@ -18,10 +18,20 @@ $nl
 { $subsection dlist-contains? }
 "Deleting a node matching a predicate:"
 { $subsection delete-node-if* }
-{ $subsection delete-node-if } ;
+{ $subsection delete-node-if }
+"Search deque implementation:"
+{ $subsection <hashed-dlist> } ;
 
 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
 { $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." }
index 92b141dca8608e1aa387315ab5c5a4cfc55ce9ee..6df3e306ddb97345a7a5962ebce82aad427fc583 100644 (file)
@@ -5,7 +5,7 @@ IN: dlists.tests
 
 [ t ] [ <dlist> deque-empty? ] unit-test
 
-[ T{ dlist f T{ dlist-node f 1 f f } T{ dlist-node f 1 f f } } ]
+[ T{ dlist f T{ dlist-node f 1 f f } T{ dlist-node f 1 f f } } ]
 [ <dlist> 1 over push-front ] unit-test
 
 ! 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-back pop-front ] unit-test
 [ 1 ] [ <dlist> 1 over push-back pop-back ] unit-test
-[ T{ dlist f f f } ] [ <dlist> 1 over push-front dup pop-front* ] unit-test
-[ T{ dlist f f f } ] [ <dlist> 1 over push-front dup pop-back* ] unit-test
-[ T{ dlist f f f } ] [ <dlist> 1 over push-back dup pop-front* ] unit-test
-[ T{ dlist f f f } ] [ <dlist> 1 over push-back dup pop-back* ] unit-test
+[ T{ dlist f f f } ] [ <dlist> 1 over push-front dup pop-front* ] unit-test
+[ T{ dlist f f f } ] [ <dlist> 1 over push-front dup pop-back* ] unit-test
+[ T{ dlist f f f } ] [ <dlist> 1 over push-back dup pop-front* ] 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
 [ f ] [
@@ -52,15 +52,6 @@ IN: dlists.tests
 [ 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
-[ 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>> 5 = ] dlist-find-node drop class dlist-node = ] unit-test
index 5072c3edfd94b8a99327cabebd19563c67b88c07..549dbf947de90910d631b9447ef0bdc1a67ac468 100644 (file)
@@ -2,51 +2,57 @@
 ! Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: combinators kernel math sequences accessors deques
-summary ;
+search-deques summary hashtables ;
 IN: dlists
 
-TUPLE: dlist front back length ;
+<PRIVATE
 
-: <dlist> ( -- obj )
-    dlist new
-        0 >>length ;
+MIXIN: ?dlist-node
 
-M: dlist deque-length length>> ;
+INSTANCE: f ?dlist-node
 
-<PRIVATE
+TUPLE: dlist-node obj { prev ?dlist-node } { next ?dlist-node } ;
 
-TUPLE: dlist-node obj prev next ;
+INSTANCE: dlist-node ?dlist-node
 
 C: <dlist-node> dlist-node
 
-M: dlist-node node-value obj>> ;
+PRIVATE>
 
-: inc-length ( dlist -- )
-    [ 1+ ] change-length drop ; inline
+TUPLE: dlist
+{ front ?dlist-node }
+{ back ?dlist-node } ;
 
-: dec-length ( dlist -- )
-    [ 1- ] change-length drop ; inline
+: <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>> ;
 
 : set-prev-when ( dlist-node dlist-node/f -- )
-    [ (>>prev) ] [ drop ] if* ;
+    [ (>>prev) ] [ drop ] if* ; inline
 
 : set-next-when ( dlist-node dlist-node/f -- )
-    [ (>>next) ] [ drop ] if* ;
+    [ (>>next) ] [ drop ] if* ; inline
 
 : set-next-prev ( dlist-node -- )
-    dup next>> set-prev-when ;
+    dup next>> set-prev-when ; inline
 
 : normalize-front ( dlist -- )
-    dup back>> [ f >>front ] unless drop ;
+    dup back>> [ f >>front ] unless drop ; inline
 
 : normalize-back ( dlist -- )
-    dup front>> [ f >>back ] unless drop ;
+    dup front>> [ f >>back ] unless drop ; inline
 
 : 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 -- )
-    dup front>> [ dup back>> >>front ] unless drop ;
+    dup front>> [ dup back>> >>front ] unless drop ; inline
 
 : (dlist-find-node) ( dlist-node quot: ( node -- ? ) -- node/f ? )
     over [
@@ -62,22 +68,20 @@ M: dlist-node node-value obj>> ;
 
 : unlink-node ( dlist-node -- )
     dup prev>> over next>> set-prev-when
-    dup next>> swap prev>> set-next-when ;
+    dup next>> swap prev>> set-next-when ; inline
 
 PRIVATE>
 
 M: dlist push-front* ( obj dlist -- dlist-node )
     [ front>> f swap <dlist-node> dup dup set-next-prev ] keep
     [ (>>front) ] keep
-    [ set-back-to-front ] keep
-    inc-length ;
+    set-back-to-front ;
 
 M: dlist push-back* ( obj dlist -- dlist-node )
     [ back>> f <dlist-node> ] keep
     [ back>> set-next-when ] 2keep
     [ (>>back) ] 2keep
-    [ set-front-to-back ] keep
-    inc-length ;
+    set-front-to-back ;
 
 ERROR: empty-dlist ;
 
@@ -88,31 +92,27 @@ M: dlist peek-front ( dlist -- obj )
     front>> [ obj>> ] [ empty-dlist ] if* ;
 
 M: dlist pop-front* ( dlist -- )
-    dup front>> [ empty-dlist ] unless
     [
-        dup front>>
+        dup front>> [ empty-dlist ] unless*
         dup next>>
         f rot (>>next)
         f over set-prev-when
         swap (>>front)
     ] keep
-    [ normalize-back ] keep
-    dec-length ;
+    normalize-back ;
 
 M: dlist peek-back ( dlist -- obj )
     back>> [ obj>> ] [ empty-dlist ] if* ;
 
 M: dlist pop-back* ( dlist -- )
-    dup back>> [ empty-dlist ] unless
     [
-        dup back>>
+        dup back>> [ empty-dlist ] unless*
         dup prev>>
         f rot (>>prev)
         f over set-next-when
         swap (>>back)
     ] keep
-    [ normalize-front ] keep
-    dec-length ;
+    normalize-front ;
 
 : dlist-find ( dlist quot -- obj/f ? )
     [ obj>> ] prepose
@@ -128,7 +128,7 @@ M: dlist delete-node ( dlist-node dlist -- )
     {
         { [ 2dup front>> eq? ] [ nip pop-front* ] }
         { [ 2dup back>> eq? ] [ nip pop-back* ] }
-        [ dec-length unlink-node ]
+        [ drop unlink-node ]
     } cond ;
 
 : delete-node-if* ( dlist quot -- obj/f ? )
@@ -148,7 +148,6 @@ M: dlist delete-node ( dlist-node dlist -- )
 M: dlist clear-deque ( dlist -- )
     f >>front
     f >>back
-    0 >>length
     drop ;
 
 : dlist-each ( dlist quot -- )
index 61fab306a2b341c567d1a0b536580437465a86e6..974645b2841d88d533d9dc859afa37d92725b44e 100644 (file)
@@ -42,7 +42,7 @@ HELP: doc-lines
 { $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;
 
 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." }
 { $notes "The range is created by calling " { $link <slice> } "." }
 { $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;
index 1d9f72f8c35eea4540b465963c6edf1a19202f13..1550fccc0b3ae3f132058000bea721d18b8876c5 100644 (file)
@@ -4,7 +4,7 @@ IN: editors.emacs
 
 : emacsclient ( file line -- )
     [
-        "emacsclient" ,
+        \ emacsclient get "emacsclient" or ,
         "--no-wait" ,
         "+" swap number>string append ,
         ,
diff --git a/basis/editors/etexteditor/authors.txt b/basis/editors/etexteditor/authors.txt
new file mode 100755 (executable)
index 0000000..7b1e3b7
--- /dev/null
@@ -0,0 +1 @@
+Kibleur Christophe
\ No newline at end of file
diff --git a/basis/editors/etexteditor/etexteditor.factor b/basis/editors/etexteditor/etexteditor.factor
new file mode 100755 (executable)
index 0000000..316bd24
--- /dev/null
@@ -0,0 +1,18 @@
+! Copyright (C) 2008 Kibleur Christophe.
+! See http://factorcode.org/license.txt for BSD license.
+USING: editors io.files io.launcher kernel math.parser
+namespaces sequences windows.shell32 make ;
+IN: editors.etexteditor
+
+: etexteditor-path ( -- str )
+    \ etexteditor-path get-global [
+        program-files "e\\e.exe" append-path
+    ] unless* ;
+
+: etexteditor ( file line -- )
+    [
+        etexteditor-path ,
+        [ , ] [ "--line" , number>string , ] bi*
+    ] { } make run-detached drop ;
+
+[ etexteditor ] edit-hook set-global
diff --git a/basis/editors/etexteditor/summary.txt b/basis/editors/etexteditor/summary.txt
new file mode 100755 (executable)
index 0000000..4653700
--- /dev/null
@@ -0,0 +1 @@
+etexteditor integration
diff --git a/basis/editors/etexteditor/tags.txt b/basis/editors/etexteditor/tags.txt
new file mode 100755 (executable)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/basis/furnace/actions/actions-docs.factor b/basis/furnace/actions/actions-docs.factor
new file mode 100644 (file)
index 0000000..dd453ae
--- /dev/null
@@ -0,0 +1,170 @@
+USING: assocs classes help.markup help.syntax io.streams.string
+http http.server.dispatchers http.server.responses
+furnace.redirection strings multiline ;
+IN: furnace.actions
+
+HELP: <action>
+{ $values { "action" action } }
+{ $description "Creates a new action." } ;
+
+HELP: <chloe-content>
+{ $values
+     { "path" "a pathname string" }
+     { "response" response }
+}
+{ $description "Creates an HTTP response which serves a Chloe template. See " { $link "html.templates.chloe" } "." } ;
+
+HELP: <page-action>
+{ $values { "page" action } }
+{ $description "Creates a new action which serves a Chloe template when servicing a GET request." } ;
+
+HELP: action
+{ $class-description "The class of Furnace actions. New instances are created with " { $link <action> } ". New instances of subclasses can be created with " { $link new-action } ". The " { $link page-action } " class is a useful subclass."
+$nl
+"Action slots are documented in " { $link "furnace.actions.config" } "." } ;
+
+HELP: new-action
+{ $values
+     { "class" class }
+     { "action" action }
+}
+{ $description "Constructs a subclass of " { $link action } "." } ;
+
+HELP: page-action
+{ $class-description "The class of Chloe page actions. These are actions whose " { $slot "display" } " slot is pre-set to serve the Chloe template stored in the " { $slot "page" } " slot." } ;
+
+HELP: param
+{ $values
+     { "name" string }
+     { "value" string }
+}
+{ $description "Outputs the value of a query parameter (if the current request is a GET or HEAD request) or a POST parameter (if the current request is a POST request)." }
+{ $notes "Instead of using this word, it is better to use " { $link validate-params } " and then access parameters via " { $link "html.forms.values" } " words." } ;
+
+HELP: params
+{ $var-description "A variable holding an assoc of query parameters (if the current request is a GET or HEAD request) or POST parameters (if the current request is a POST request)." }
+{ $notes "Instead of using this word, it is better to use " { $link validate-params } " and then access parameters via " { $link "html.forms.values" } " words." } ;
+
+HELP: validate-integer-id
+{ $description "A utility word which validates an integer parameter named " { $snippet "id" } "." }
+{ $examples
+    { $code
+        "<action>"
+        "    ["
+        "        validate-integer-id"
+        "        \"id\" value <person> select-tuple from-object"
+        "    ] >>init"
+    }
+} ;
+
+HELP: validate-params
+{ $values
+     { "validators" "an association list mapping parameter names to validator quotations" }
+}
+{ $description "Validates query or POST parameters, depending on the request type, and stores them in " { $link "html.forms.values" } ". The validator quotations can execute " { $link "validators" } "." }
+{ $examples
+    "A simple validator from " { $vocab-link "webapps.todo" } "; this word is invoked from the " { $slot "validate" } " quotation of action for editing a todo list item:"
+    { $code
+        <" : validate-todo ( -- )
+    {
+        { "summary" [ v-one-line ] }
+        { "priority" [ v-integer 0 v-min-value 10 v-max-value ] }
+        { "description" [ v-required ] }
+    } validate-params ;">
+    }
+} ;
+
+HELP: validation-failed
+{ $description "Stops processing the current request and takes action depending on the type of the current request:"
+    { $list
+        { "For GET or HEAD requests, the client receives a " { $link <400> } " response." }
+        { "For POST requests, the client is sent back to the page containing the form submission, with current form values and validation errors passed in a " { $link "furnace.conversations" } "." }
+    }
+"This word is called by " { $link validate-params } " and can also be called directly. For more details, see " { $link "furnace.actions.lifecycle" } "." } ;
+
+ARTICLE: "furnace.actions.page.example" "Furnace page action example"
+"The " { $vocab-link "webapps.counter" } " vocabulary defines a subclass of " { $link dispatcher } ":"
+{ $code "TUPLE: counter-app < dispatcher ;" }
+"The " { $snippet "<counter-app>" } " constructor word creates a new instance of the " { $snippet "counter-app" } " class, and adds a " { $link page-action } " instance to the dispatcher. This " { $link page-action } " has its " { $slot "template" } " slot set as follows,"
+{ $code "{ counter-app \"counter\" } >>template" }
+"This means the action will serve the Chloe template located at " { $snippet "resource:extra/webapps/counter/counter.xml" } " upon receiving a GET request." ;
+
+ARTICLE: "furnace.actions.page" "Furnace page actions"
+"Page actions implement the common case of an action that simply serves a Chloe template in response to a GET request."
+{ $subsection page-action }
+{ $subsection <page-action> }
+"When using a page action, instead of setting the " { $slot "display" } " slot, the " { $slot "template" } " slot is set instead. The " { $slot "init" } ", " { $slot "authorize" } ", " { $slot "validate" } " and " { $slot "submit" } " slots can still be set as usual."
+$nl
+"The " { $slot "template" } " slot of a " { $link page-action } " contains a pair with shape " { $snippet "{ responder name }" } ", where " { $snippet "responder" } " is a responder class, usually a subclass of " { $link dispatcher } ", and " { $snippet "name" } " is the name of a template file, without the " { $snippet ".xml" } " extension, relative to the directory containing the responder's vocabulary source file."
+{ $subsection "furnace.actions.page.example" } ;
+
+ARTICLE: "furnace.actions.config" "Furnace action configuration"
+"Actions have the following slots:"
+{ $table
+    { { $slot "rest" } { "A parameter name to map the rest of the URL, after the action name, to. If this is not set, then navigating to a URL where the action is not the last path component will return to the client with an error." } }
+    { { $slot "init" } { "A quotation called at the beginning of a GET or HEAD request. Typically this quotation configures " { $link "html.forms" } " and parses query parameters." } }
+    { { $slot "authorize" } { "A quotation called at the beginning of a GET, HEAD or POST request. In GET requests, it is called after the " { $slot "init" } " quotation; in POST requests, it is called after the " { $slot "validate" } " quotation. By convention, this quotation performs custom authorization checks which depend on query parameters or POST parameters." } }
+    { { $slot "display" } { "A quotation called after the " { $slot "init" } " quotation in a GET request. This quotation must return an HTTP " { $link response } "." } }
+    { { $slot "validate" } { "A quotation called at the beginning of a POST request to validate POST parameters." } }
+    { { $slot "submit" } { "A quotation called after the " { $slot "validate" } " quotation in a POST request. This quotation must return an HTTP " { $link response } "." } }
+}
+"At least one of the " { $slot "display" } " and " { $slot "submit" } " slots must be set, otherwise the action will be useless." ;
+
+ARTICLE: "furnace.actions.validation" "Form validation with actions"
+"The action code is set up so that the " { $slot "init" } " quotation can validate query parameters, and the " { $slot "validate" } " quotation can validate POST parameters."
+$nl
+"A word to validate parameters and make them available as HTML form values (see " { $link "html.forms.values" } "); typically this word is invoked from the " { $slot "init" } " and " { $slot "validate" } " quotations:"
+{ $subsection validate-params }
+"The above word expects an association list mapping parameter names to validator quotations; validator quotations can use the words in the " 
+"Custom validation logic can invoke a word when validation fails; " { $link validate-params } " invokes this word for you:"
+{ $subsection validation-failed }
+"If validation fails, no more action code is executed, and the client is redirected back to the originating page, where validation errors can be displayed. Note that validation errors are rendered automatically by the " { $link "html.components" } " words, and in particular, " { $link "html.templates.chloe" } " use these words." ;
+
+ARTICLE: "furnace.actions.lifecycle" "Furnace action lifecycle"
+{ $heading "GET request lifecycle" }
+"A GET request results in the following sequence of events:"
+{ $list
+    { "The " { $snippet "init" } " quotation is called." }
+    { "The " { $snippet "authorize" } " quotation is called." }
+    { "If the GET request was generated as a result of form validation failing during a POST, then the form values entered by the user, along with validation errors, are stored in " { $link "html.forms.values" } "." }
+    { "The " { $snippet "display" } " quotation is called; it is expected to output an HTTP " { $link response } " on the stack." }
+}
+"Any one of the above steps can perform validation; if " { $link validation-failed } " is called during a GET request, the client receives a " { $link <400> } " error."
+{ $heading "HEAD request lifecycle" }
+"A HEAD request proceeds exactly like a GET request. The only difference is that the " { $slot "body" } " slot of the " { $link response } " object is never rendered."
+{ $heading "POST request lifecycle" }
+"A POST request results in the following sequence of events:"
+{ $list
+    { "The " { $snippet "validate" } " quotation is called." }
+    { "The " { $snippet "authorize" } " quotation is called." }
+    { "The " { $snippet "submit" } " quotation is called; it is expected to output an HTTP " { $link response } " on the stack. By convention, this response should be a " { $link <redirect> } "." }
+}
+"Any one of the above steps can perform validation; if " { $link validation-failed } " is called during a POST request, the client is sent back to the page containing the form submission, with current form values and validation errors passed in a " { $link "furnace.conversations" } "." ;
+
+ARTICLE: "furnace.actions.impl" "Furnace actions implementation"
+"The following words are used by the action implementation and there is rarely any reason to call them directly:"
+{ $subsection new-action }
+{ $subsection param }
+{ $subsection params } ;
+
+ARTICLE: "furnace.actions" "Furnace actions"
+"The " { $vocab-link "furnace.actions" } " vocabulary implements a type of responder, called an " { $emphasis "action" } ", which handles the form validation lifecycle."
+$nl
+"Other than form validation capability, actions are also often simpler to use than implementing new responders directly, since creating a new class is not required, and the action dispatches on the request type (GET, HEAD, or POST)."
+$nl
+"The class of actions:"
+{ $subsection action }
+"Creating a new action:"
+{ $subsection <action> }
+"Once created, an action needs to be configured; typically the creation and configuration of an action is encapsulated into a single word:"
+{ $subsection "furnace.actions.config" }
+"Validating forms with actions:"
+{ $subsection "furnace.actions.validation" }
+"More about the form validation lifecycle:"
+{ $subsection "furnace.actions.lifecycle" }
+"A convenience class:"
+{ $subsection "furnace.actions.page" }
+"Low-level features:"
+{ $subsection "furnace.actions.impl" } ;
+
+ABOUT: "furnace.actions"
index 7505b3c6126f7588be4bdfc0fac0db318cb71546..6c56a8ad7babe82ad3d98a762c6ab59381e352eb 100644 (file)
@@ -22,18 +22,7 @@ SYMBOL: params
 \r
 SYMBOL: rest\r
 \r
-: render-validation-messages ( -- )\r
-    form get errors>>\r
-    [\r
-        <ul "errors" =class ul>\r
-            [ <li> escape-string write </li> ] each\r
-        </ul>\r
-    ] unless-empty ;\r
-\r
-CHLOE: validation-messages\r
-    drop [ render-validation-messages ] [code] ;\r
-\r
-TUPLE: action rest authorize init display validate submit ;\r
+TUPLE: action rest init authorize display validate submit ;\r
 \r
 : new-action ( class -- action )\r
     new [ ] >>init [ ] >>validate [ ] >>authorize ; inline\r
diff --git a/basis/furnace/alloy/alloy-docs.factor b/basis/furnace/alloy/alloy-docs.factor
new file mode 100644 (file)
index 0000000..f108428
--- /dev/null
@@ -0,0 +1,42 @@
+IN: furnace.alloy
+USING: help.markup help.syntax db multiline ;
+
+HELP: init-furnace-tables
+{ $description "Initializes database tables used by asides, conversations and session management. This word must be invoked inside a " { $link with-db } " scope." } ;
+
+HELP: <alloy>
+{ $values { "responder" "a responder" } { "db" db } { "responder'" "an alloy responder" } }
+{ $description "Wraps the responder with support for asides, conversations, sessions and database persistence." }
+{ $examples
+    "The " { $vocab-link "webapps.counter" } " vocabulary uses an alloy to configure the counter:"
+    { $code
+        <" : counter-db ( -- db ) "counter.db" <sqlite-db> ;
+
+: run-counter ( -- )
+    <counter-app>
+        counter-db <alloy>
+        main-responder set-global
+    8080 httpd ;">
+    }
+} ;
+
+HELP: start-expiring
+{ $values { "db" db } }
+{ $description "Starts a timer which expires old session state from the given database." } ;
+
+ARTICLE: "furnace.alloy" "Furnace alloy responder"
+"The " { $vocab-link "furnace.alloy" } " vocabulary implements a convenience responder which combines several Furnace features into one easy-to-use wrapper:"
+{ $list
+    { $link "furnace.asides" }
+    { $link "furnace.conversations" }
+    { $link "furnace.sessions" }
+    { $link "furnace.db" }
+}
+"A word to wrap a responder in an alloy:"
+{ $subsection <alloy> }
+"Initializing database tables for asides, conversations and sessions:"
+{ $subsection init-furnace-tables }
+"Start a timer to expire asides, conversations and sessions:"
+{ $subsection start-expiring } ;
+
+ABOUT: "furnace.alloy"
diff --git a/basis/furnace/asides/asides-docs.factor b/basis/furnace/asides/asides-docs.factor
new file mode 100644 (file)
index 0000000..c5b7bdd
--- /dev/null
@@ -0,0 +1,33 @@
+USING: help.markup help.syntax io.streams.string urls
+furnace.redirection http furnace.sessions furnace.db ;
+IN: furnace.asides
+
+HELP: <asides>
+{ $values
+     { "responder" "a responder" }
+     { "responder'" "a new responder" }
+}
+{ $description "Creates a new " { $link asides } " responder wrapping an existing responder." } ;
+
+HELP: begin-aside
+{ $values { "url" url } }
+{ $description "Begins an aside. When the current action returns a " { $link <redirect> } ", the redirect will have query parameters which reference the current page via an opaque handle." } ;
+
+HELP: end-aside
+{ $values { "default" url } { "response" response } }
+{ $description "Ends an aside. If an aside is currently active, the response redirects the client " } ;
+
+ARTICLE: "furnace.asides" "Furnace asides"
+"The " { $vocab-link "furnace.asides" } " vocabulary provides support for sending a user to a page which can then return to the former location."
+$nl
+"To use asides, wrap your responder in an aside responder:"
+{ $subsection <asides> }
+"The asides responder must be wrapped inside a session responder (" { $link <sessions> } "), which in turn must be wrapped inside a database persistence responder (" { $link <db-persistence> } "). The " { $vocab-link "furnace.alloy" } " vocabulary combines all of these responders into one."
+$nl
+"Saving the current page in an aside which propagates through " { $link <redirect> } " responses:"
+{ $subsection begin-aside }
+"Returning from an aside:"
+{ $subsection end-aside }
+"Asides are used by " { $vocab-link "furnace.auth.login" } "; when the client requests a protected page, an aside begins and the client is redirected to a login page. Upon a successful login, the aside ends and the client returns to the protected page. If the client directly visits the login page and logs in, there is no current aside, so the client is sent to the default URL passed to " { $link end-aside } ", which in the case of login is the root URL." ;
+
+ABOUT: "furnace.asides"
diff --git a/basis/furnace/auth/auth-docs.factor b/basis/furnace/auth/auth-docs.factor
new file mode 100644 (file)
index 0000000..e7e7223
--- /dev/null
@@ -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"
diff --git a/basis/furnace/auth/basic/basic-docs.factor b/basis/furnace/auth/basic/basic-docs.factor
new file mode 100644 (file)
index 0000000..c0d3184
--- /dev/null
@@ -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"
diff --git a/basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor b/basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor
new file mode 100644 (file)
index 0000000..ef4f2e1
--- /dev/null
@@ -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"
diff --git a/basis/furnace/auth/features/edit-profile/edit-profile-docs.factor b/basis/furnace/auth/features/edit-profile/edit-profile-docs.factor
new file mode 100644 (file)
index 0000000..6f3c9d1
--- /dev/null
@@ -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>"
+} ;
index 243ea7bfffc80299421de8053afe3a5b9001952a..cefb472b228f168dbc5b6910fb4a09ff9b2ee36f 100644 (file)
@@ -58,7 +58,7 @@ IN: furnace.auth.features.edit-profile
     <protected>
         "edit your profile" >>description ;
 
-: allow-edit-profile ( login -- login )
+: allow-edit-profile ( realm -- realm )
     <edit-profile-action> <auth-boilerplate> "edit-profile" add-responder ;
 
 : allow-edit-profile? ( -- ? )
index f486f4e246cf10bfddad3055651a0fe7df2741e4..878bdd64fb5fb73a2239546c8e416d716f809280 100644 (file)
@@ -62,7 +62,7 @@
 
        <p>
                <button>Update</button>
-               <t:validation-messages />
+               <t:validation-errors />
        </p>
 
        </t:form>
index a8ea635a1f9826e05306c832d2b6335b8c8b12e1..2df400ffe23ef1b00a068af96924f270d8e6c14f 100644 (file)
@@ -32,7 +32,7 @@
 
                <p>
                        <button>Set password</button>
-                       <t:validation-messages />
+                       <t:validation-errors />
                </p>
 
        </t:form>
diff --git a/basis/furnace/auth/features/recover-password/recover-password-docs.factor b/basis/furnace/auth/features/recover-password/recover-password-docs.factor
new file mode 100644 (file)
index 0000000..1dc7e99
--- /dev/null
@@ -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"
index 49e692d5a6319a269e5b719501a67eac445b3285..5885aaef616d238def6106072dbd3b7cd94d6887 100644 (file)
@@ -110,7 +110,7 @@ SYMBOL: lost-password-from
     <page-action>
         { realm "features/recover-password/recover-4" } >>template ;
 
-: allow-password-recovery ( login -- login )
+: allow-password-recovery ( realm -- realm )
     <recover-action-1> <auth-boilerplate>
         "recover-password" add-responder
     <recover-action-2> <auth-boilerplate>
index b0d6971d1bfac7fcd3e7e85769b021b9460e4173..45c090905e8e0bc6db0c22911406c359b5606836 100644 (file)
@@ -63,7 +63,7 @@
                <p>
 
                        <button>Register</button>
-                       <t:validation-messages />
+                       <t:validation-errors />
 
                </p>
 
diff --git a/basis/furnace/auth/features/registration/registration-docs.factor b/basis/furnace/auth/features/registration/registration-docs.factor
new file mode 100644 (file)
index 0000000..1f12570
--- /dev/null
@@ -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>"
+} ;
index ef8923c98b8d80a4b5ba58b20a8a178dd704a601..0484c11727dd4e47f5a6773240da7bdd20adf3d8 100644 (file)
@@ -38,7 +38,7 @@ IN: furnace.auth.features.registration
     <auth-boilerplate>
     <secure-realm-only> ;
 
-: allow-registration ( login -- login )
+: allow-registration ( realm -- realm )
     <register-action> "register" add-responder ;
 
 : allow-registration? ( -- ? )
diff --git a/basis/furnace/auth/login/login-docs.factor b/basis/furnace/auth/login/login-docs.factor
new file mode 100644 (file)
index 0000000..08b7d93
--- /dev/null
@@ -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"
index 2c98672490def526fcd02369ae63f05124251e65..4fc4e7e8be517783d15b8365d43df58a4b5946c3 100644 (file)
@@ -58,9 +58,13 @@ M: login-realm modify-form ( responder -- )
     permit-id get [ delete-permit ] when*\r
     URL" $realm" end-aside ;\r
 \r
+<PRIVATE\r
+\r
 SYMBOL: description\r
 SYMBOL: capabilities\r
 \r
+PRIVATE>\r
+\r
 : flashed-variables { description capabilities } ;\r
 \r
 : login-failed ( -- * )\r
@@ -107,7 +111,7 @@ M: login-realm login-required* ( description capabilities login -- response )
 M: login-realm user-registered ( user realm -- )\r
     drop successful-login ;\r
 \r
-: <login-realm> ( responder name -- auth )\r
+: <login-realm> ( responder name -- realm )\r
     login-realm new-realm\r
         <login-action> "login" add-responder\r
         <logout-action> "logout" add-responder\r
index 766c097ca5fa5b39d8999bdd6d9cac4010b4cd24..917c182fb305d7d06fa5f0f6f4814d10a7240072 100644 (file)
@@ -36,7 +36,7 @@
                <p>
 
                        <button>Log in</button>
-                       <t:validation-messages />
+                       <t:validation-errors />
 
                </p>
 
diff --git a/basis/furnace/auth/providers/assoc/assoc-docs.factor b/basis/furnace/auth/providers/assoc/assoc-docs.factor
new file mode 100644 (file)
index 0000000..61c2ac4
--- /dev/null
@@ -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"
diff --git a/basis/furnace/auth/providers/db/db-docs.factor b/basis/furnace/auth/providers/db/db-docs.factor
new file mode 100644 (file)
index 0000000..219edf9
--- /dev/null
@@ -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"
diff --git a/basis/furnace/auth/providers/null/null-docs.factor b/basis/furnace/auth/providers/null/null-docs.factor
new file mode 100644 (file)
index 0000000..100b16c
--- /dev/null
@@ -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"
diff --git a/basis/furnace/auth/providers/providers-docs.factor b/basis/furnace/auth/providers/providers-docs.factor
new file mode 100644 (file)
index 0000000..5d15bf4
--- /dev/null
@@ -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"
diff --git a/basis/furnace/boilerplate/boilerplate-docs.factor b/basis/furnace/boilerplate/boilerplate-docs.factor
new file mode 100644 (file)
index 0000000..ad983c8
--- /dev/null
@@ -0,0 +1,35 @@
+USING: help.markup help.syntax io.streams.string
+http.server.dispatchers ;
+IN: furnace.boilerplate
+
+HELP: <boilerplate>
+{ $values
+     { "responder" "a responder" }
+     { "boilerplate" "a new boilerplate responder" }
+}
+{ $description "Wraps a responder in a boilerplate responder. The boilerplate responder needs to be configured before use; see " { $link "furnace.boilerplate.config" } "." } ;
+
+HELP: boilerplate
+{ $class-description "The class of boilerplate responders. Slots are documented in " { $link "furnace.boilerplate.config" } "." } ;
+
+ARTICLE: "furnace.boilerplate.config" "Boilerplate configuration"
+"The " { $link boilerplate } " tuple has two slots which can be set:"
+{ $table
+    { { $slot "template" } { "A pair with shape " { $snippet "{ responder name }" } ", where " { $snippet "responder" } " is a responder class, usually a subclass of " { $link dispatcher } ", and " { $snippet "name" } " is the name of a template file, without the " { $snippet ".xml" } " extension, relative to the directory containing the responder's vocabulary source file." } }
+    { { $slot "init" } { "A quotation run before the boilerplate template is rendered. This quotation can set values which the template can then display." } }
+} ;
+
+ARTICLE: "furnace.boilerplate.example" "Boilerplate example"
+"The " { $vocab-link "webapps.wiki" } " vocabulary uses boilerplate to add a footer and sidebar to every page. Since the footer and sidebar are themselves dynamic content, it sets the " { $slot "init" } " quotation as well as the " { $slot "template" } " slot:"
+{ $code "<boilerplate>"
+"    [ init-sidebars init-relative-link-prefix ] >>init"
+"    { wiki \"wiki-common\" } >>template" } ;
+
+ARTICLE: "furnace.boilerplate" "Furnace boilerplate support"
+"The " { $vocab-link "furnace.boilerplate" } " vocabulary implements a facility for sharing a common header and footer between different pages on a web site. It builds on top of " { $link "html.templates.boilerplate" } "."
+{ $subsection <boilerplate> }
+{ $subsection "furnace.boilerplate.config" }
+{ $subsection "furnace.boilerplate.example" }
+{ $see-also "html.templates.chloe.tags.boilerplate" } ;
+
+ABOUT: "furnace.boilerplate"
diff --git a/basis/furnace/conversations/conversations-docs.factor b/basis/furnace/conversations/conversations-docs.factor
new file mode 100644 (file)
index 0000000..4ad2c8a
--- /dev/null
@@ -0,0 +1,53 @@
+USING: help.markup help.syntax urls http words kernel
+furnace.sessions furnace.db ;
+IN: furnace.conversations
+
+HELP: <conversations>
+{ $values
+     { "responder" "a responder" }
+     { "responder'" "a new responder" }
+}
+{ $description "Creates a new " { $link conversations } " responder wrapping an existing responder." } ;
+
+HELP: begin-conversation
+{ $description "Starts a new conversation scope. Values can be stored in the conversation scope with " { $link cset } ", and the conversation can be continued with " { $link <continue-conversation> } "." } ;
+
+HELP: end-conversation
+{ $description "Ends the current conversation scope." } ;
+
+HELP: <continue-conversation>
+{ $values { "url" url } { "response" response } }
+{ $description "Creates an HTTP response which redirects the client to the specified URL while continuing the conversation. Any values set in the current conversation scope will be visible to the resonder handling the URL." } ;
+
+HELP: cget
+{ $values { "key" symbol } { "value" object } }
+{ $description "Outputs the value of a conversation variable." } ;
+
+HELP: cset
+{ $values { "value" object } { "key" symbol } }
+{ $description "Sets the value of a conversation variable." } ;
+
+HELP: cchange
+{ $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." } ;
+
+ARTICLE: "furnace.conversations" "Furnace conversation scope"
+"The " { $vocab-link "furnace.conversations" } " vocabulary implements conversation scope, which allows data to be passed between requests on a finer level of granularity than session scope."
+$nl
+"Conversation scope is used by form validation to pass validation errors between requests."
+$nl
+"To use conversation scope, wrap your responder in an conversation responder:"
+{ $subsection <conversations> }
+"The conversations responder must be wrapped inside a session responder (" { $link <sessions> } "), which in turn must be wrapped inside a database persistence responder (" { $link <db-persistence> } "). The " { $vocab-link "furnace.alloy" } " vocabulary combines all of these responders into one."
+$nl
+"Managing conversation scopes:"
+{ $subsection begin-conversation }
+{ $subsection end-conversation }
+{ $subsection <continue-conversation> }
+"Reading and writing conversation variables:"
+{ $subsection cget }
+{ $subsection cset }
+{ $subsection cchange }
+"Note that conversation scope is serialized as part of the session, which means that only serializable objects can be stored there. See " { $link "furnace.sessions.serialize" } " for details." ;
+
+ABOUT: "furnace.conversations"
diff --git a/basis/furnace/db/db-docs.factor b/basis/furnace/db/db-docs.factor
new file mode 100644 (file)
index 0000000..a7ef02b
--- /dev/null
@@ -0,0 +1,16 @@
+USING: help.markup help.syntax db http.server ;
+IN: furnace.db
+
+HELP: <db-persistence>
+{ $values
+     { "responder" "a responder" } { "db" db }
+     { "responder'" db-persistence }
+}
+{ $description "Wraps a responder with database persistence support. The responder's " { $link call-responder* } " method will run in a " { $link with-db } " scope." } ;
+
+ARTICLE: "furnace.db" "Furnace database support"
+"The " { $vocab-link "furnace.db" } " vocabulary implements a responder which maintains a database connection pool and runs each request in a " { $link with-db } " scope."
+{ $subsection <db-persistence> }
+"The " { $vocab-link "furnace.alloy" } " vocabulary combines database persistence with several other features." ;
+
+ABOUT: "furnace.db"
diff --git a/basis/furnace/furnace-docs.factor b/basis/furnace/furnace-docs.factor
new file mode 100644 (file)
index 0000000..b86d4c3
--- /dev/null
@@ -0,0 +1,180 @@
+USING: assocs help.markup help.syntax kernel
+quotations sequences strings urls xml.data http ;
+IN: furnace
+
+HELP: adjust-redirect-url
+{ $values { "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." } ;
+
+HELP: adjust-url
+{ $values { "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." } ;
+
+HELP: client-state
+{ $values { "key" string } { "value/f" { $maybe string } } }
+{ $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)." }
+{ $notes "This word is used by session management, conversation scope and asides." } ;
+
+HELP: each-responder
+{ $values { "quot" { $quotation "( responder -- )" } } }
+{ $description "Applies the quotation to each responder involved in processing the current request." } ;
+
+HELP: hidden-form-field
+{ $values { "value" string } { "name" string } }
+{ $description "Renders an HTML hidden form field tag." }
+{ $notes "This word is used by session management, conversation scope and asides." }
+{ $examples
+    { $example
+        "USING: furnace io ;"
+        "\"bar\" \"foo\" hidden-form-field nl"
+        "<input type='hidden' name='foo' value='bar'/>"
+    }
+} ;
+
+HELP: link-attr
+{ $values { "tag" tag } { "responder" "a responder" } }
+{ $contract "Modifies an XHTML " { $snippet "a" } " tag." }
+{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
+{ $examples "Conversation scope adds attributes to link tags." } ;
+
+HELP: modify-form
+{ $values { "responder" "a responder" } }
+{ $contract "Emits hidden form fields using " { $link hidden-form-field } "." }
+{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
+{ $examples "Session management, conversation scope and asides use hidden form fields to pass state." } ;
+
+HELP: modify-query
+{ $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
+{ $contract "Modifies the query parameters of a URL destined to be displayed as a link." }
+{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
+{ $examples "Asides add query parameters to URLs." } ;
+
+HELP: modify-redirect-query
+{ $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
+{ $contract "Modifies the query parameters of a URL destined to be used with a redirect." }
+{ $notes "This word is called by " { $link "furnace.redirection" } "." }
+{ $examples "Conversation scope and asides add query parameters to redirect URLs." } ;
+
+HELP: nested-responders
+{ $values { "seq" "a sequence of responders" } }
+{ $description "" } ;
+
+HELP: referrer
+{ $values { "referrer/f" { $maybe string } } }
+{ $description "Outputs the current request's referrer URL." } ;
+
+HELP: request-params
+{ $values { "request" request } { "assoc" assoc } }
+{ $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)." } ;
+
+HELP: resolve-base-path
+{ $values { "string" string } { "string'" string } }
+{ $description "" } ;
+
+HELP: resolve-template-path
+{ $values { "pair" "a pair with shape " { $snippet "{ class string }" } } { "path" "a pathname string" } }
+{ $description "" } ;
+
+HELP: same-host?
+{ $values { "url" url } { "?" "a boolean" } }
+{ $description "Tests if the given URL is located on the same host as the URL of the current request." } ;
+
+HELP: user-agent
+{ $values { "user-agent" { $maybe string } } }
+{ $description "Outputs the user agent reported by the client for the current request." } ;
+
+HELP: vocab-path
+{ $values { "vocab" "a vocabulary specifier" } { "path" "a pathname string" } }
+{ $description "" } ;
+
+HELP: exit-with
+{ $values { "value" object } }
+{ $description "Exits from an outer " { $link with-exit-continuation } "." } ;
+
+HELP: with-exit-continuation
+{ $values { "quot" { $quotation { "( -- value )" } } } { "value" "a value returned by the quotation or an " { $link exit-with } " invocation" } }
+{ $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." } ;
+
+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"
+{ $subsection "furnace.db" }
+"Server-side state:"
+{ $subsection "furnace.sessions" }
+{ $subsection "furnace.conversations" }
+{ $subsection "furnace.asides" }
+{ $subsection "furnace.presentation" } ;
+
+ARTICLE: "furnace.presentation" "Furnace presentation layer"
+"HTML components:"
+{ $subsection "html.components" }
+{ $subsection "html.forms" }
+"Content templates:"
+{ $subsection "html.templates" }
+{ $subsection "html.templates.chloe" }
+{ $subsection "html.templates.fhtml" }
+{ $subsection "furnace.boilerplate" }
+"Other types of content:"
+{ $subsection "furnace.syndication" }
+{ $subsection "furnace.json" } ;
+
+ARTICLE: "furnace.load-balancing" "Load balancing and fail-over with Furnace"
+"The Furnace session manager persists sessions to a database. This means that HTTP requests can be transparently distributed between multiple Factor HTTP server instances, running the same web app on top of the same database, as long as the web applications do not use mutable global state, such as global variables. The Furnace framework itself does not use any mutable global state." ;
+
+ARTICLE: "furnace" "Furnace framework"
+"The " { $vocab-link "furnace" } " vocabulary implements a full-featured web framework on top of the " { $link "http.server" } ". Some of its features include:"
+{ $list
+    "Session management capable of load-balancing and fail-over"
+    "Form components and validation"
+    "Authentication system with basic authentication or login pages, and pluggable authentication backends"
+    "Easy Atom feed syndication"
+    "Conversation scope and asides for complex page flow"
+}
+"Major functionality:"
+{ $subsection "furnace.actions" }
+{ $subsection "furnace.alloy" }
+{ $subsection "furnace.persistence" }
+{ $subsection "furnace.presentation" }
+{ $subsection "furnace.auth" }
+{ $subsection "furnace.load-balancing" }
+"Utilities:"
+{ $subsection "furnace.referrer" }
+{ $subsection "furnace.redirection" }
+{ $subsection "furnace.extension-points" }
+{ $subsection "furnace.misc" }
+"Related frameworks:"
+{ $subsection "db" }
+{ $subsection "xml" }
+{ $subsection "http.server" }
+{ $subsection "logging" }
+{ $subsection "urls" } ;
+
+ABOUT: "furnace"
index 7285c436bcbd658822b0b0afb94d7be9e1b6c545..29eb00a8f4a44f8fd1dea230ea6a4c9fda9fdafb 100644 (file)
@@ -90,7 +90,7 @@ M: object modify-form drop ;
     } case ;
 
 : 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
     dup [ >url ensure-port [ remap-port ] change-port ] when ;
 
@@ -125,7 +125,31 @@ SYMBOL: exit-continuation
 : exit-with ( value -- )
     exit-continuation get continue-with ;
 
-: with-exit-continuation ( quot -- )
+: with-exit-continuation ( quot -- value )
     '[ exit-continuation set @ ] callcc1 exit-continuation off ;
 
+USE: vocabs.loader
+"furnace.actions" require
+"furnace.alloy" require
+"furnace.asides" require
+"furnace.auth" require
+"furnace.auth.basic" require
+"furnace.auth.features.deactivate-user" require
+"furnace.auth.features.edit-profile" require
+"furnace.auth.features.recover-password" require
+"furnace.auth.features.registration" require
+"furnace.auth.login" require
+"furnace.auth.providers.assoc" require
+"furnace.auth.providers.db" require
+"furnace.auth.providers.null" require
+"furnace.boilerplate" require
 "furnace.chloe-tags" require
+"furnace.conversations" require
+"furnace.db" require
+"furnace.json" require
+"furnace.redirection" require
+"furnace.referrer" require
+"furnace.scopes" require
+"furnace.sessions" require
+"furnace.syndication" require
+"webapps.user-admin" require
diff --git a/basis/furnace/json/json-docs.factor b/basis/furnace/json/json-docs.factor
new file mode 100644 (file)
index 0000000..c20c2e6
--- /dev/null
@@ -0,0 +1,12 @@
+USING: kernel http.server help.markup help.syntax http ;
+IN: furnace.json
+
+HELP: <json-content>
+{ $values { "body" object } { "response" response } }
+{ $description "Creates an HTTP response which serves a serialized JSON object to the client." } ;
+
+ARTICLE: "furnace.json" "Furnace JSON support"
+"The " { $vocab-link "furnace.json" } " vocabulary provides a utility word for serving HTTP responses with JSON content."
+{ $subsection <json-content> } ;
+
+ABOUT: "furnace.json"
diff --git a/basis/furnace/redirection/redirection-docs.factor b/basis/furnace/redirection/redirection-docs.factor
new file mode 100644 (file)
index 0000000..fd3671f
--- /dev/null
@@ -0,0 +1,59 @@
+USING: help.markup help.syntax io.streams.string quotations urls
+http.server http ;
+IN: furnace.redirection
+
+HELP: <redirect-responder>
+{ $values { "url" url } { "responder" "a responder" } }
+{ $description "Creates a responder which unconditionally redirects the client to the given URL." } ;
+
+HELP: <redirect>
+{ $values { "url" url } { "response" response } }
+{ $description "Creates a response which redirects the client to the given URL." } ;
+
+HELP: <secure-only> ( responder -- responder' )
+{ $values { "responder" "a responder" } { "responder'" "a responder" } }
+{ $description "Creates a new responder which ensures that the client is connecting via HTTPS before delegating to the underlying responder. If the client is connecting via HTTP, a redirect is sent instead." } ;
+
+HELP: <secure-redirect>
+{ $values
+     { "url" url }
+     { "response" response }
+}
+{ $description "Creates a responder which unconditionally redirects the client to the given URL after setting its protocol to HTTPS." }
+{ $notes "This word is intended to be used with a relative URL. The client is redirected to the relative URL, but with HTTPS instead of HTTP." } ;
+
+HELP: >secure-url
+{ $values
+     { "url" url }
+     { "url'" url }
+}
+{ $description "Sets the protocol of a URL to HTTPS." } ;
+
+HELP: if-secure
+{ $values
+     { "quot" quotation }
+     { "response" response }
+}
+{ $description "Runs a quotation if the current request was made over HTTPS, otherwise returns a redirect to have the client request the current page again via HTTPS." } ;
+
+ARTICLE: "furnace.redirection.secure" "Secure redirection"
+"The words in this section help with implementing sites which require SSL/TLS for additional security."
+$nl
+"Converting a HTTP URL into an HTTPS URL:"
+{ $subsection >secure-url }
+"Redirecting the client to an HTTPS URL:"
+{ $subsection <secure-redirect> }
+"Tools for writing responders which require SSL/TLS connections:"
+{ $subsection if-secure }
+{ $subsection <secure-only> } ;
+
+ARTICLE: "furnace.redirection" "Furnace redirection support"
+"The " { $vocab-link "furnace.redirection" } " vocabulary builds additional functionality on top of " { $vocab-link "http.server.redirection" } ", and integrates with various Furnace features such as " { $link "furnace.asides" } " and " { $link "furnace.conversations" } "."
+$nl
+"A redirection response which takes asides and conversations into account:"
+{ $subsection <redirect> }
+"A responder which unconditionally redirects the client to another URL:"
+{ $subsection <redirect-responder> }
+{ $subsection "furnace.redirection.secure" } ;
+
+ABOUT: "furnace.redirection"
diff --git a/basis/furnace/referrer/referrer-docs.factor b/basis/furnace/referrer/referrer-docs.factor
new file mode 100644 (file)
index 0000000..599461c
--- /dev/null
@@ -0,0 +1,19 @@
+USING: help.markup help.syntax io.streams.string
+furnace ;
+IN: furnace.referrer
+
+HELP: <check-form-submissions>
+{ $values
+     { "responder" "a responder" }
+     { "responder'" "a responder" }
+}
+{ $description "Wraps the responder in a filter responder which ensures that form submissions originate from a page on the same server. Any submissions which do not are sent back with a 403 error." } ;
+
+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."
+{ $subsection <check-form-submissions> }
+"Explicit referrer checking:"
+{ $subsection referrer }
+{ $subsection same-host? } ;
+
+ABOUT: "furnace.referrer"
diff --git a/basis/furnace/sessions/sessions-docs.factor b/basis/furnace/sessions/sessions-docs.factor
new file mode 100644 (file)
index 0000000..959d6b6
--- /dev/null
@@ -0,0 +1,55 @@
+USING: help.markup help.syntax io.streams.string quotations strings calendar serialize kernel furnace.db words kernel ;
+IN: furnace.sessions
+
+HELP: <sessions>
+{ $values
+     { "responder" "a responder" }
+     { "responder'" "a new responder" }
+}
+{ $description "Wraps a responder in a session manager responder." } ;
+
+HELP: schange
+{ $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." } ;
+
+HELP: sget
+{ $values { "key" symbol } { "value" object } }
+{ $description "Outputs the value of a session variable." } ;
+
+HELP: sset
+{ $values { "value" object } { "key" symbol } }
+{ $description "Sets the value of a session variable." } ;
+
+ARTICLE: "furnace.sessions.config" "Session manager configuration"
+"The " { $link sessions } " tuple has two slots which contain configuration parameters:"
+{ $table
+    { { $slot "verify?" } { "If set to a true value, the client IP address and user agent of each session is tracked, and checked every time a client attempts to re-establish a session. While this does not offer any real security, it can thwart unskilled packet-sniffing attacks. On by default." } }
+    { { $slot "timeout" } { "A " { $link duration } " storing the maximum time that inactive sessions will be stored on the server. The default timeout is 20 minutes. Note that for sessions to actually expire, you must start a thread to do so; see the " { $vocab-link "furnace.alloy" } " vocabulary for an easy way of doing this." } }
+} ;
+
+ARTICLE: "furnace.sessions.serialize" "Session state serialization"
+"Session variable values are serialized to the database using the " { $link "serialize" } " library."
+$nl
+"This means that there are three restrictions on the values stored in the session:"
+{ $list
+    "Continuations cannot be stored at all."
+    { "Object identity is not preserved between serialization and deserialization. That is, if an object is stored with " { $link sset } " and later retrieved with " { $link sget } ", the retrieved value will be " { $link = } " to the original, but not necessarily " { $link eq? } "." }
+    { "All objects reachable from the value passed to " { $link sset } " are serialized, so large structures should not be stored in the session state, and neither should anything that can reference the global namespace. Large structures should be persisted in the database directly instead, using " { $vocab-link "db.tuples" } "." }
+} ;
+
+ARTICLE: "furnace.sessions" "Furnace sessions"
+"The " { $vocab-link "furnace.sessions" } " vocabulary implements session management, which allows state to be maintained between HTTP requests. The session state is stored on the server; the client receives an opaque ID which is saved in a cookie (for GET requests) or a hidden form field (for POST requests)."
+$nl
+"To use session management, wrap your responder in an session manager:"
+{ $subsection <sessions> }
+"The sessions responder must be wrapped inside a database persistence responder (" { $link <db-persistence> } "). The " { $vocab-link "furnace.alloy" } " vocabulary combines all of these responders into one."
+$nl
+"Reading and writing session variables from a request:"
+{ $subsection sget }
+{ $subsection sset }
+{ $subsection schange }
+"Additional topics:"
+{ $subsection "furnace.sessions.config" }
+{ $subsection "furnace.sessions.serialize" } ;
+
+ABOUT: "furnace.sessions"
diff --git a/basis/furnace/summary.txt b/basis/furnace/summary.txt
new file mode 100644 (file)
index 0000000..afbc1b9
--- /dev/null
@@ -0,0 +1 @@
+Furnace web framework
diff --git a/basis/furnace/syndication/syndication-docs.factor b/basis/furnace/syndication/syndication-docs.factor
new file mode 100644 (file)
index 0000000..94a69cc
--- /dev/null
@@ -0,0 +1,73 @@
+USING: help.markup help.syntax io.streams.string kernel sequences strings urls syndication calendar ;
+IN: furnace.syndication
+
+HELP: <feed-action>
+{ $values { "action" feed-action } }
+{ $description "Creates a new Atom feed action." } ;
+
+HELP: >entry
+{ $values
+     { "object" object }
+     { "entry" entry }
+}
+{ $contract "Converts an object into an Atom feed entry. The default implementation constructs an entry by calling "
+{ $link feed-entry-title } ", "
+{ $link feed-entry-description } ", "
+{ $link feed-entry-date } ", and "
+{ $link feed-entry-url } "." } ;
+
+HELP: feed-action
+{ $class-description "The class of feed actions. Contains several slots, documented in " { $link "furnace.syndication.config" } "." } ;
+
+HELP: feed-entry-date
+{ $values
+     { "object" object }
+     { "timestamp" timestamp }
+}
+{ $contract "Outputs a feed entry timestmap." } ;
+
+HELP: feed-entry-description
+{ $values
+     { "object" object }
+     { "description" null }
+}
+{ $contract "Outputs a feed entry description." } ;
+
+HELP: feed-entry-title
+{ $values
+     { "object" object }
+     { "string" string }
+}
+{ $contract "Outputs a feed entry title." } ;
+
+HELP: feed-entry-url
+{ $values
+     { "object" object }
+     { "url" url }
+}
+{ $contract "Outputs a feed entry URL." } ;
+
+ARTICLE: "furnace.syndication.config" "Configuring Atom feed actions"
+"Instances of " { $link feed-action } " have three slots which need to be set:"
+{ $table
+    { { $slot "title" } "The title of the feed as a string" }
+    { { $slot "url" } { "The feed " { $link url } } }
+    { { $slot "entries" } { "A quotation with stack effect " { $snippet "( -- seq )" } ", which produces a sequence of objects responding to the " { $link "furnace.syndication.protocol" } " protocol" } }
+} ;
+
+ARTICLE: "furnace.syndication.protocol" "Atom feed entry protocol"
+"An Atom feed action takes a sequence of objects and converts them into Atom feed entries. The objects must implement a protocol consisting of either a single generic word:"
+{ $subsection >entry }
+"Or a series of generic words, called by the default implementation of " { $link >entry } ":"
+{ $subsection feed-entry-title }
+{ $subsection feed-entry-description }
+{ $subsection feed-entry-date }
+{ $subsection feed-entry-url } ;
+
+ARTICLE: "furnace.syndication" "Furnace Atom syndication support"
+"The " { $vocab-link "furnace.syndication" } " vocabulary builds on the " { $link "syndication" } " library by providing easy support for generating Atom feeds from " { $link "furnace.actions" } "."
+{ $subsection <feed-action> }
+{ $subsection "furnace.syndication.config" }
+{ $subsection "furnace.syndication.protocol" } ;
+
+ABOUT: "furnace.syndication"
diff --git a/basis/grouping/authors.txt b/basis/grouping/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/grouping/grouping-docs.factor b/basis/grouping/grouping-docs.factor
new file mode 100644 (file)
index 0000000..3b3a98e
--- /dev/null
@@ -0,0 +1,104 @@
+USING: help.markup help.syntax sequences strings ;
+IN: grouping
+
+ARTICLE: "grouping" "Groups and clumps"
+"Splitting a sequence into disjoint, fixed-length subsequences:"
+{ $subsection group }
+"A virtual sequence for splitting a sequence into disjoint, fixed-length subsequences:"
+{ $subsection groups }
+{ $subsection <groups> }
+{ $subsection <sliced-groups> }
+"Splitting a sequence into overlapping, fixed-length subsequences:"
+{ $subsection clump }
+"A virtual sequence for splitting a sequence into overlapping, fixed-length subsequences:"
+{ $subsection clumps }
+{ $subsection <clumps> }
+{ $subsection <sliced-clumps> }
+"The difference can be summarized as the following:"
+{ $list
+    { "With groups, the subsequences form the original sequence when concatenated:"
+        { $unchecked-example "dup n groups concat sequence= ." "t" }
+    }
+    { "With clumps, collecting the first element of each subsequence but the last one, together with the last subseqence, yields the original sequence:"
+        { $unchecked-example "dup n clumps unclip-last >r [ first ] map r> append sequence= ." "t" }
+    }
+} ;
+
+ABOUT: "grouping"
+
+HELP: groups
+{ $class-description "Instances are virtual sequences whose elements are disjoint fixed-length subsequences of an underlying sequence. Groups are mutable and resizable if the underlying sequence is mutable and resizable, respectively."
+$nl
+"New groups are created by calling " { $link <groups> } " and " { $link <sliced-groups> } "." }
+{ $see-also group } ;
+
+HELP: group
+{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
+{ $description "Splits the sequence into disjoint groups of " { $snippet "n" } " elements and collects the groups into a new array." }
+{ $notes "If the sequence length is not a multiple of " { $snippet "n" } ", the final subsequence in the list will be shorter than " { $snippet "n" } " elements." }
+{ $examples
+    { $example "USING: grouping prettyprint ;" "{ 3 1 3 3 7 } 2 group ." "{ { 3 1 } { 3 3 } { 7 } }" }
+} ;
+
+HELP: <groups>
+{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "groups" groups } }
+{ $description "Outputs a virtual sequence whose elements are disjoint subsequences of " { $snippet "n" } " elements from the underlying sequence." }
+{ $examples
+    { $example
+        "USING: arrays kernel prettyprint sequences grouping ;"
+        "9 >array 3 <groups> dup reverse-here concat >array ." "{ 6 7 8 3 4 5 0 1 2 }"
+    }
+} ;
+
+HELP: <sliced-groups>
+{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "groups" groups } }
+{ $description "Outputs a virtual sequence whose elements are overlapping subsequences of " { $snippet "n" } " elements from the underlying sequence." }
+{ $examples
+    { $example
+        "USING: arrays kernel prettyprint sequences grouping ;"
+        "9 >array 3 <sliced-groups>"
+        "dup [ reverse-here ] each concat >array ."
+        "{ 2 1 0 5 4 3 8 7 6 }"
+    }
+} ;
+
+HELP: clumps
+{ $class-description "Instances are virtual sequences whose elements are overlapping fixed-length subsequences o an underlying sequence. Clumps are mutable and resizable if the underlying sequence is mutable and resizable, respectively."
+$nl
+"New clumps are created by calling " { $link <clumps> } " and " { $link <sliced-clumps> } "." } ;
+
+HELP: clump
+{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
+{ $description "Splits the sequence into overlapping clumps of " { $snippet "n" } " elements and collects the clumps into a new array." }
+{ $errors "Throws an error if " { $snippet "n" } " is smaller than the length of the sequence." }
+{ $examples
+    { $example "USING: grouping prettyprint ;" "{ 3 1 3 3 7 } 2 clump ." "{ { 3 1 } { 1 3 } { 3 3 } { 3 7 } }" }
+} ;
+
+HELP: <clumps>
+{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "clumps" clumps } }
+{ $description "Outputs a virtual sequence whose elements are overlapping subsequences of " { $snippet "n" } " elements from the underlying sequence." }
+{ $examples
+    "Running averages:"
+    { $example
+        "USING: grouping sequences math prettyprint kernel ;"
+        "IN: scratchpad"
+        ": share-price"
+        "    { 13/50 51/100 13/50 1/10 4/5 17/20 33/50 3/25 19/100 3/100 } ;"
+        ""
+        "share-price 4 <clumps> [ [ sum ] [ length ] bi / ] map ."
+        "{ 113/400 167/400 201/400 241/400 243/400 91/200 1/4 }"
+    }
+} ;
+
+HELP: <sliced-clumps>
+{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "clumps" clumps } }
+{ $description "Outputs a virtual sequence whose elements are overlapping slices of " { $snippet "n" } " elements from the underlying sequence." } ;
+
+{ clumps groups } related-words
+
+{ clump group } related-words
+
+{ <clumps> <groups> } related-words
+
+{ <sliced-clumps> <sliced-groups> } related-words
diff --git a/basis/grouping/grouping-tests.factor b/basis/grouping/grouping-tests.factor
new file mode 100644 (file)
index 0000000..dc3d970
--- /dev/null
@@ -0,0 +1,14 @@
+USING: grouping tools.test kernel sequences arrays ;
+IN: grouping.tests
+
+[ { 1 2 3 } 0 group ] must-fail
+
+[ { "hell" "o wo" "rld" } ] [ "hello world" 4 group ] unit-test
+
+[ { V{ "a" "b" } V{ f f } } ] [
+    V{ "a" "b" } clone 2 <groups>
+    2 over set-length
+    >array
+] unit-test
+
+[ { { 1 2 } { 2 3 } } ] [ { 1 2 3 } 2 <sliced-clumps> [ >array ] map ] unit-test
diff --git a/basis/grouping/grouping.factor b/basis/grouping/grouping.factor
new file mode 100644 (file)
index 0000000..4a1b8c7
--- /dev/null
@@ -0,0 +1,88 @@
+! Copyright (C) 2005, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math math.order strings arrays vectors sequences
+sequences.private accessors ;
+IN: grouping
+
+<PRIVATE
+
+TUPLE: chunking-seq { seq read-only } { n read-only } ;
+
+: check-groups dup 0 <= [ "Invalid group count" throw ] when ; inline
+
+: new-groups ( seq n class -- groups )
+    >r check-groups r> boa ; inline
+
+GENERIC: group@ ( n groups -- from to seq )
+
+M: chunking-seq set-nth group@ <slice> 0 swap copy ;
+
+M: chunking-seq like drop { } like ;
+
+INSTANCE: chunking-seq sequence
+
+MIXIN: subseq-chunking
+
+M: subseq-chunking nth group@ subseq ;
+
+MIXIN: slice-chunking
+
+M: slice-chunking nth group@ <slice> ;
+
+M: slice-chunking nth-unsafe group@ slice boa ;
+
+TUPLE: abstract-groups < chunking-seq ;
+
+M: abstract-groups length
+    [ seq>> length ] [ n>> ] bi [ + 1- ] keep /i ;
+
+M: abstract-groups set-length
+    [ n>> * ] [ seq>> ] bi set-length ;
+
+M: abstract-groups group@
+    [ n>> [ * dup ] keep + ] [ seq>> ] bi [ length min ] keep ;
+
+TUPLE: abstract-clumps < chunking-seq ;
+
+M: abstract-clumps length
+    [ seq>> length ] [ n>> ] bi - 1+ ;
+
+M: abstract-clumps set-length
+    [ n>> + 1- ] [ seq>> ] bi set-length ;
+
+M: abstract-clumps group@
+    [ n>> over + ] [ seq>> ] bi ;
+
+PRIVATE>
+
+TUPLE: groups < abstract-groups ;
+
+: <groups> ( seq n -- groups )
+    groups new-groups ; inline
+
+INSTANCE: groups subseq-chunking
+
+TUPLE: sliced-groups < abstract-groups ;
+
+: <sliced-groups> ( seq n -- groups )
+    sliced-groups new-groups ; inline
+
+INSTANCE: sliced-groups slice-chunking
+
+TUPLE: clumps < abstract-clumps ;
+
+: <clumps> ( seq n -- clumps )
+    clumps new-groups ; inline
+
+INSTANCE: clumps subseq-chunking
+
+TUPLE: sliced-clumps < abstract-clumps ;
+
+: <sliced-clumps> ( seq n -- clumps )
+    sliced-clumps new-groups ; inline
+
+INSTANCE: sliced-clumps slice-chunking
+
+: group ( seq n -- array ) <groups> { } like ;
+
+: clump ( seq n -- array ) <clumps> { } like ;
diff --git a/basis/grouping/summary.txt b/basis/grouping/summary.txt
new file mode 100644 (file)
index 0000000..3695129
--- /dev/null
@@ -0,0 +1 @@
+Grouping sequence elements into subsequences
diff --git a/basis/grouping/tags.txt b/basis/grouping/tags.txt
new file mode 100644 (file)
index 0000000..42d711b
--- /dev/null
@@ -0,0 +1 @@
+collections
index 6c387632ed526e202e9d6fbfb855ca2842cabfe5..92146755d9db30cb2060510961b220340a825a00 100644 (file)
@@ -62,7 +62,7 @@ M: heap heap-size ( heap -- n )
 
 : data-set-nth ( entry n heap -- )
     >r [ >>index drop ] 2keep r>
-    data>> set-nth-unsafe ;
+    data>> set-nth-unsafe ; inline
 
 : data-push ( entry heap -- n )
     dup heap-size [
index 5b60102e467062b3a3cc2e7a10157fef21629a43..d1d9ca049a2708ed5bd6e3523ed0ab9d265a2d01 100644 (file)
@@ -166,16 +166,16 @@ ARTICLE: "io" "Input and output"
 { $heading "Encodings" }
 { $subsection "encodings-introduction" }
 { $subsection "io.encodings" }
-"Wrapper streams:"
+{ $heading "Wrapper streams" }
 { $subsection "io.streams.duplex" }
 { $subsection "io.streams.plain" }
 { $subsection "io.streams.string" }
 { $subsection "io.streams.byte-array" }
-"Utilities:"
+{ $heading "Utilities" }
 { $subsection "stream-binary" }
 { $subsection "styles" }
 { $subsection "checksums" }
-"Implementation:"
+{ $heading "Implementation" }
 { $subsection "io.streams.c" }
 { $subsection "io.ports" }
 { $see-also "destructors" } ;
index 2fe4edfe7fe6879a775958eb6cd3c737245cec1b..277d965e390b735306fed7ebb8a33b1de57fb55e 100644 (file)
@@ -1,6 +1,6 @@
 USING: help.markup help.crossref help.stylesheet help.topics
 help.syntax definitions io prettyprint summary arrays math
-sequences vocabs ;
+sequences vocabs strings ;
 IN: help
 
 ARTICLE: "printing-elements" "Printing markup elements"
@@ -33,6 +33,10 @@ ARTICLE: "block-elements" "Block elements"
 { $subsection $side-effects }
 { $subsection $errors }
 { $subsection $see-also }
+"Elements used in " { $link $values } " forms:"
+{ $subsection $instance }
+{ $subsection $maybe }
+{ $subsection $quotation }
 "Boilerplate paragraphs:"
 { $subsection $low-level-note }
 { $subsection $io-error }
@@ -281,7 +285,7 @@ HELP: $link
 } ;
 
 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." }
 { $examples
     { $example "USING: help.markup io ;" "{ \"fish\" \"chips\" \"salt\" } [ write ] textual-list" "fish, chips, salt" }
@@ -318,7 +322,37 @@ HELP: $table
 
 HELP: $values
 { $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
 { $values { "element" "an array of markup elements" } }
index 386dca9576bcd9a463c4d9ffb54435fc4fafa9cf..4100a34d7228f180871ccd8911cb9ca27338af09 100644 (file)
@@ -5,7 +5,7 @@ io.files html.streams html.elements html.components help kernel
 assocs sequences make words accessors arrays help.topics vocabs
 tools.vocabs tools.vocabs.browser namespaces prettyprint io
 vocabs.loader serialize fry memoize unicode.case math.order
-sorting ;
+sorting debugger ;
 IN: help.html
 
 : escape-char ( ch -- )
@@ -22,6 +22,7 @@ IN: help.html
         { CHAR: / "__slash__" }
         { CHAR: \\ "__backslash__" }
         { CHAR: , "__comma__" }
+        { CHAR: @ "__at__" }
     } at [ % ] [ , ] ?if ;
 
 : 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 ;
 
 : generate-help-files ( -- )
-    all-topics [ help>html ] each ;
+    all-topics [ '[ _ help>html ] try ] each ;
 
 : generate-help ( -- )
-    { "resource:core" "resource:basis" "resource:extra" } vocab-roots [
-        load-everything
-
-        "/tmp/docs/" make-directory
-
-        "/tmp/docs/" [
+    "docs" temp-file
+    [ make-directories ]
+    [
+        [
             generate-indices
             generate-help-files
         ] with-directory
-    ] with-variable ;
+    ] bi ;
 
 MEMO: load-index ( name -- index )
     binary file-contents bytes>object ;
@@ -118,10 +117,10 @@ M: result link-href href>> ;
     [ [ title>> ] compare ] sort ;
 
 : article-apropos ( string -- results )
-    "articles.idx" offline-apropos ;
+    "articles.idx" temp-file offline-apropos ;
 
 : word-apropos ( string -- results )
-    "words.idx" offline-apropos ;
+    "words.idx" temp-file offline-apropos ;
 
 : vocab-apropos ( string -- results )
-    "vocabs.idx" offline-apropos ;
+    "vocabs.idx" temp-file offline-apropos ;
index 1eae56cfcc6cb7c7e00ed3fca36e9448cbef84d7..a3078333387ba76a93be7c2fae420395537ad4b5 100644 (file)
@@ -3,7 +3,8 @@
 USING: accessors arrays definitions generic io kernel assocs
 hashtables namespaces make parser prettyprint sequences strings
 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
 
 ! Simple markup language.
@@ -234,7 +235,8 @@ ALIAS: $slot $snippet
     ] ($grid) ;
 
 : a/an ( str -- str )
-    first "aeiou" member? "an" "a" ? ;
+    [ first ] [ length ] bi 1 =
+    "afhilmnorsx" "aeiou" ? member? "an" "a" ? ;
 
 GENERIC: ($instance) ( element -- )
 
@@ -244,7 +246,17 @@ M: word ($instance)
 M: string ($instance)
     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 )
     unclip \ $snippet swap ?word-name 2array
index 6556d2eac2cf4767e9dd1b9978ca021eb5f27666..089a516072dec0030ff4807cf3ca40024b70c8ab 100644 (file)
@@ -85,6 +85,14 @@ HELP: validate-values
 { $values { "assoc" assoc } { "validators" "an assoc mapping value names to quotations" } }
 { $description "Validates values in the assoc by looking up the corresponding validation quotation, and storing the results in named values of the current form." } ;
 
+HELP: validation-error
+{ $values { "message" string } }
+{ $description "Reports a validation error not associated with a specific form field." }
+{ $notes "Such errors can be rendered by calling the " { $link render-validation-errors } " word." } ;
+
+HELP: render-validation-errors
+{ $description "Renders any validation errors reported by calls to the " { $link validation-error } " word." } ;
+
 ARTICLE: "html.forms.forms" "HTML form infrastructure"
 "The below words are used to implement the " { $vocab-link "furnace.actions" } " vocabulary. Calling them directly is rarely necessary."
 $nl
index c1c1aa3def13e4e21cd49d4ac2d9161006a7644e..f92f8d0764036ea58777f3bbdc6ce59376450569 100644 (file)
@@ -1,7 +1,8 @@
 ! Copyright (C) 2008 Slava Pestov
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors strings namespaces assocs hashtables
-mirrors math fry sequences words continuations ;
+USING: kernel accessors strings namespaces assocs hashtables io
+mirrors math fry sequences words continuations html.elements
+xml.entities ;
 IN: html.forms
 
 TUPLE: form errors values validation-failed ;
@@ -104,3 +105,11 @@ C: <validation-error> validation-error
 
 : validate-values ( assoc validators -- )
     swap '[ [ dup _ at ] dip validate-value ] assoc-each ;
+
+: render-validation-errors ( -- )
+    form get errors>>
+    [
+        <ul "errors" =class ul>
+            [ <li> escape-string write </li> ] each
+        </ul>
+    ] unless-empty ;
index f390aad23824b17e13865a2b0401e529786c77b1..1f2975bce1923ce0b40ea940d367b8a277a3a918 100644 (file)
@@ -14,7 +14,7 @@ HELP: required-attr
 { $errors "Throws an error if the attribute is not specified." } ;
 
 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." }
 { $notes "Outputs " { $link f } " if the attribute is not specified." } ;
 
@@ -24,7 +24,7 @@ HELP: compile-attr
 
 HELP: CHLOE:
 { $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." } ;
 
 HELP: COMPONENT:
@@ -46,7 +46,7 @@ HELP: [code]
 { $description "Compiles the quotation. It will be called when the template is called." } ;
 
 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." }
 { $examples "See " { $link "html.templates.chloe.extend.tags.example" } " for an example which uses this word to implement a custom control flow tag." } ;
 
@@ -154,6 +154,9 @@ ARTICLE: "html.templates.chloe.tags.form" "Chloe link and form tags"
             "</t:button>"
         }
     } }
+    { { $snippet "t:validation-errors" } {
+        "Renders validation errors in the current form which are not associated with any field. Such errors are reported by invoking " { $link validation-error } "."
+    } }
 } ;
 
 ARTICLE: "html.templates.chloe.tags" "Standard Chloe tags"
index 1bc4684d5c41488e16c78c7bd40bdc2615783363..da3f80e9a5d9c54440cab55f48b3066cb0f9db8c 100644 (file)
@@ -65,6 +65,9 @@ CHLOE: comment drop ;
 CHLOE: call-next-template
     drop reset-buffer \ call-next-template , ;
 
+CHLOE: validation-errors
+    drop [ render-validation-errors ] [code] ;
+
 : attr>word ( value -- word/f )
     ":" split1 swap lookup ;
 
index d4f277a7c31f46b3e916d993871d9e3a56fa7eaf..7a35ba812b351c72d66f0d4b38783c0d76c97c4b 100644 (file)
@@ -40,7 +40,7 @@ HELP: http-post
 { $errors "Throws an error if the HTTP request fails." } ;
 
 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." }
 { $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." } ;
 
 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." }
 { $errors "Throws an error if the HTTP request fails." } ;
 
index 4db04f04aa6b197cd0bef80ec3232e43337b0c1b..6fb5b73fadf24ea0f0a34864834a7a049d1af78f 100644 (file)
@@ -81,7 +81,7 @@ HELP: delete-cookie
 { $side-effects "request/response" } ;
 
 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." } ;
 
 HELP: put-cookie
index bca72a6126d7d546a52ae77a6a92479d0622b40b..fbe20b5fcdcb0f56ddb278c09fa8a64446e487e4 100644 (file)
@@ -4,7 +4,7 @@ USING: help.markup help.syntax io.streams.string ;
 IN: http.server.static
 
 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." } ;
 
 HELP: <static>
diff --git a/basis/io/files/listing/authors.txt b/basis/io/files/listing/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/io/files/listing/listing-docs.factor b/basis/io/files/listing/listing-docs.factor
new file mode 100644 (file)
index 0000000..6b19e9b
--- /dev/null
@@ -0,0 +1,17 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string strings ;
+IN: io.files.listing
+
+HELP: directory.
+{ $values
+     { "path" "a pathname string" }
+}
+{ $description "Prints information about all files in a directory to the output stream in a cross-platform way similar to the Unix " { $snippet "ls" } " command." } ;
+
+ARTICLE: "io.files.listing" "Listing files"
+"The " { $vocab-link "io.files.listing" } " vocabulary implements directory file listing in a cross-platform way." $nl
+"Listing a directory:"
+{ $subsection directory. } ;
+
+ABOUT: "io.files.listing"
diff --git a/basis/io/files/listing/listing-tests.factor b/basis/io/files/listing/listing-tests.factor
new file mode 100644 (file)
index 0000000..a2347c8
--- /dev/null
@@ -0,0 +1,6 @@
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test io.files.listing strings kernel ;
+IN: io.files.listing.tests
+
+[ ] [ "" directory. ] unit-test
diff --git a/basis/io/files/listing/listing.factor b/basis/io/files/listing/listing.factor
new file mode 100755 (executable)
index 0000000..f88fcec
--- /dev/null
@@ -0,0 +1,39 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays combinators io io.files kernel
+math.parser sequences system vocabs.loader calendar ;
+
+IN: io.files.listing
+
+<PRIVATE
+
+: ls-time ( timestamp -- string )
+    [ hour>> ] [ minute>> ] bi
+    [ number>string 2 CHAR: 0 pad-left ] bi@ ":" swap 3append ;
+
+: ls-timestamp ( timestamp -- string )
+    [ month>> month-abbreviation ]
+    [ day>> number>string 2 CHAR: \s pad-left ]
+    [
+        dup year>> dup now year>> =
+        [ drop ls-time ] [ nip number>string ] if
+        5 CHAR: \s pad-left
+    ] tri 3array " " join ;
+
+: read>string ( ? -- string ) "r" "-" ? ; inline
+
+: write>string ( ? -- string ) "w" "-" ? ; inline
+
+: execute>string ( ? -- string ) "x" "-" ? ; inline
+
+HOOK: (directory.) os ( path -- lines )
+
+PRIVATE>
+
+: directory. ( path -- )
+    [ (directory.) ] with-directory-files [ print ] each ;
+
+{
+    { [ os unix? ] [ "io.files.listing.unix" ] }
+    { [ os windows? ] [ "io.files.listing.windows" ] }
+} cond require
diff --git a/basis/io/files/listing/tags.txt b/basis/io/files/listing/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/basis/io/files/listing/unix/authors.txt b/basis/io/files/listing/unix/authors.txt
new file mode 100755 (executable)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/io/files/listing/unix/tags.txt b/basis/io/files/listing/unix/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/basis/io/files/listing/unix/unix.factor b/basis/io/files/listing/unix/unix.factor
new file mode 100755 (executable)
index 0000000..313ce1f
--- /dev/null
@@ -0,0 +1,48 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators kernel system unicode.case
+io.unix.files io.files.listing generalizations strings
+arrays sequences io.files math.parser unix.groups unix.users
+io.files.listing.private ;
+IN: io.files.listing.unix
+
+<PRIVATE
+
+: unix-execute>string ( str bools -- str' )
+    swap {
+        { { t t } [ >lower ] }
+        { { t f } [ >upper ] }
+        { { f t } [ drop "x" ] }
+        [ 2drop "-" ]
+    } case ;
+
+: permissions-string ( permissions -- str )
+    {
+        [ type>> file-type>ch 1string ]
+        [ user-read? read>string ]
+        [ user-write? write>string ]
+        [ [ uid? ] [ user-execute? ] bi 2array "s" unix-execute>string ]
+        [ group-read? read>string ]
+        [ group-write? write>string ]
+        [ [ gid? ] [ group-execute? ] bi 2array "s" unix-execute>string ]
+        [ other-read? read>string ]
+        [ other-write? write>string ]
+        [ [ sticky? ] [ other-execute? ] bi 2array "t" unix-execute>string ]
+    } cleave 10 narray concat ;
+
+M: unix (directory.) ( path -- lines )
+    [ [
+        [
+            dup file-info
+            {
+                [ permissions-string ]
+                [ nlink>> number>string 3 CHAR: \s pad-left ]
+                ! [ uid>> ]
+                ! [ gid>> ]
+                [ size>> number>string 15 CHAR: \s pad-left ]
+                [ modified>> ls-timestamp ]
+            } cleave 4 narray swap suffix " " join
+        ] map
+    ] with-group-cache ] with-user-cache ;
+
+PRIVATE>
diff --git a/basis/io/files/listing/windows/authors.txt b/basis/io/files/listing/windows/authors.txt
new file mode 100755 (executable)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/io/files/listing/windows/tags.txt b/basis/io/files/listing/windows/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/basis/io/files/listing/windows/windows.factor b/basis/io/files/listing/windows/windows.factor
new file mode 100755 (executable)
index 0000000..33ab47a
--- /dev/null
@@ -0,0 +1,25 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors calendar.format combinators io.files
+kernel math.parser sequences splitting system io.files.listing
+generalizations io.files.listing.private ;
+IN: io.files.listing.windows
+
+<PRIVATE
+
+: directory-or-size ( file-info -- str )
+    dup directory? [
+        drop "<DIR>" 20 CHAR: \s pad-right
+    ] [
+        size>> number>string 20 CHAR: \s pad-left
+    ] if ;
+
+M: windows (directory.) ( entries -- lines )
+    [
+        dup file-info {
+            [ modified>> timestamp>ymdhms ]
+            [ directory-or-size ]
+        } cleave 2 narray swap suffix " " join
+    ] map ;
+
+PRIVATE>
index c774103fca61032479bcae3ae2986619c8e4b933..09922fc9290f5c8d9dd725ef0d6afae14ed4100d 100644 (file)
@@ -17,7 +17,7 @@ HELP: <mapped-file>
 { $errors "Throws an error if a memory mapping could not be established." } ;
 
 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." }
 { $errors "Throws an error if a memory mapping could not be established." } ;
 
index ce59e23b459e53855f12cb67d5a0eee55e28781e..3242b276e6494de6567902032b91102bfcae600c 100644 (file)
@@ -23,7 +23,7 @@ HELP: next-change
 { $errors "Throws an error if the monitor is closed from another thread." } ;\r
 \r
 HELP: with-monitor\r
-{ $values { "path" "a pathname string" } { "recursive?" "a boolean" } { "quot" "a quotation with stack effect " { $snippet "( monitor -- )" } } }\r
+{ $values { "path" "a pathname string" } { "recursive?" "a boolean" } { "quot" { $quotation "( monitor -- )" } } }\r
 { $description "Opens a file system change monitor and passes it to the quotation. Closes the monitor after the quotation returns or throws an error." }\r
 { $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." } ;\r
 \r
index aae1698349515ca50e9f80b0b07405076ea5bba4..36f437dd0929b72bfaa7b827a88e42169e57497c 100644 (file)
@@ -22,7 +22,7 @@ HELP: return-connection
 { $description "Returns a connection to the pool." } ;
 
 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 } "." } ;
 
 HELP: make-connection
index 22c40da3d7a7bcc9ec8df8d83a1d456bef206c97..b093840987d7545f5aea06c23c5cf4815faa1dc0 100644 (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." } ;
 
 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." }
 { $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ;
 
 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." }
 { $notes "Can only be used from the dynamic scope of a " { $link handle-client* } " call." } ;
index 3454f3384eec9e69b12b39c998fcc298684723eb..25401293f5c3130af4f333f308adf44962736d01 100644 (file)
@@ -56,7 +56,7 @@ ARTICLE: "network-streams" "Networking"
 { $subsection "network-addressing" }
 { $subsection "network-connection" }
 { $subsection "network-packet" }
-{ $subsection "io.sockets.secure" }
+{ $vocab-subsection "Secure sockets (SSL, TLS)" "io.sockets.secure" }
 { $see-also "io.pipes" } ;
 
 ABOUT: "network-streams"
index b2927af362611c60c35bffb6ced30ddbaf5dfb62..5d72bde0f562df9cd4f517e39ca07ef05a387332 100644 (file)
@@ -2,11 +2,11 @@ IN: io.timeouts
 USING: help.markup help.syntax math kernel calendar ;\r
 \r
 HELP: timeout\r
-{ $values { "obj" object } { "dt/f" "a " { $link duration } " or " { $link f } } }\r
+{ $values { "obj" object } { "dt/f" { $maybe duration } } }\r
 { $contract "Outputs an object's timeout." } ;\r
 \r
 HELP: set-timeout\r
-{ $values { "dt/f" "a " { $link duration } " or " { $link f } } { "obj" object } }\r
+{ $values { "dt/f" { $maybe duration } } { "obj" object } }\r
 { $contract "Sets an object's timeout." } ;\r
 \r
 HELP: cancel-operation\r
@@ -14,7 +14,7 @@ HELP: cancel-operation
 { $contract "Handles a timeout, usually by waking up all threads waiting on the object." } ;\r
 \r
 HELP: with-timeout\r
-{ $values { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } }\r
+{ $values { "obj" object } { "quot" { $quotation "( obj -- )" } } }\r
 { $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." } ;\r
 \r
 ARTICLE: "io.timeouts" "I/O timeout protocol"\r
index 9ebfdaaa5a6b2ea9d2ac42552478a5cf291afe16..3f254e771341d203b8ab76dc23f972883d55a8a5 100644 (file)
@@ -172,6 +172,30 @@ M: unix (directory-entries) ( path -- seq )
 
 PRIVATE>
 
+: ch>file-type ( ch -- type )
+    {
+        { CHAR: b [ +block-device+ ] }
+        { CHAR: c [ +character-device+ ] }   
+        { CHAR: d [ +directory+ ] }
+        { CHAR: l [ +symbolic-link+ ] }
+        { CHAR: s [ +socket+ ] }
+        { CHAR: p [ +fifo+ ] }
+        { CHAR: - [ +regular-file+ ] }
+        [ drop +unknown+ ]
+    } case ;
+
+: file-type>ch ( type -- string )
+    {
+        { +block-device+ [ CHAR: b ] }
+        { +character-device+ [ CHAR: c ] }
+        { +directory+ [ CHAR: d ] }
+        { +symbolic-link+ [ CHAR: l ] }
+        { +socket+ [ CHAR: s ] }
+        { +fifo+ [ CHAR: p ] }
+        { +regular-file+ [ CHAR: - ] }
+        [ drop CHAR: - ]
+    } case ;
+
 : UID           OCT: 0004000 ; inline
 : GID           OCT: 0002000 ; inline
 : STICKY        OCT: 0001000 ; inline
index e3b96b98d889758967c44f86f5cd10b5a093de00..d0409ce59a10f754ab6019be8a25fb586a6daa78 100755 (executable)
@@ -149,35 +149,39 @@ SYMBOLS: +read-only+ +hidden+ +system+
 +sparse-file+ +reparse-point+ +compressed+ +offline+
 +not-content-indexed+ +encrypted+ ;
 
-: win32-file-attribute ( n attr symbol -- n )
-    >r dupd mask? r> swap [ , ] [ drop ] if ;
+TUPLE: windows-file-info < file-info attributes ;
+
+: win32-file-attribute ( n attr symbol -- )
+    rot mask? [ , ] [ drop ] if ;
 
 : win32-file-attributes ( n -- seq )
     [
-        FILE_ATTRIBUTE_READONLY +read-only+ win32-file-attribute
-        FILE_ATTRIBUTE_HIDDEN +hidden+ win32-file-attribute
-        FILE_ATTRIBUTE_SYSTEM +system+ win32-file-attribute
-        FILE_ATTRIBUTE_DIRECTORY +directory+ win32-file-attribute
-        FILE_ATTRIBUTE_ARCHIVE +archive+ win32-file-attribute
-        FILE_ATTRIBUTE_DEVICE +device+ win32-file-attribute
-        FILE_ATTRIBUTE_NORMAL +normal+ win32-file-attribute
-        FILE_ATTRIBUTE_TEMPORARY +temporary+ win32-file-attribute
-        FILE_ATTRIBUTE_SPARSE_FILE +sparse-file+ win32-file-attribute
-        FILE_ATTRIBUTE_REPARSE_POINT +reparse-point+ win32-file-attribute
-        FILE_ATTRIBUTE_COMPRESSED +compressed+ win32-file-attribute
-        FILE_ATTRIBUTE_OFFLINE +offline+ win32-file-attribute
-        FILE_ATTRIBUTE_NOT_CONTENT_INDEXED +not-content-indexed+ win32-file-attribute
-        FILE_ATTRIBUTE_ENCRYPTED +encrypted+ win32-file-attribute
-        drop
+        {
+            [ +read-only+ FILE_ATTRIBUTE_READONLY win32-file-attribute ]
+            [ +hidden+ FILE_ATTRIBUTE_HIDDEN win32-file-attribute ]
+            [ +system+ FILE_ATTRIBUTE_SYSTEM win32-file-attribute ]
+            [ +directory+ FILE_ATTRIBUTE_DIRECTORY win32-file-attribute ]
+            [ +archive+ FILE_ATTRIBUTE_ARCHIVE win32-file-attribute ]
+            [ +device+ FILE_ATTRIBUTE_DEVICE win32-file-attribute ]
+            [ +normal+ FILE_ATTRIBUTE_NORMAL win32-file-attribute ]
+            [ +temporary+ FILE_ATTRIBUTE_TEMPORARY win32-file-attribute ]
+            [ +sparse-file+ FILE_ATTRIBUTE_SPARSE_FILE win32-file-attribute ]
+            [ +reparse-point+ FILE_ATTRIBUTE_REPARSE_POINT win32-file-attribute ]
+            [ +compressed+ FILE_ATTRIBUTE_COMPRESSED win32-file-attribute ]
+            [ +offline+ FILE_ATTRIBUTE_OFFLINE win32-file-attribute ]
+            [ +not-content-indexed+ FILE_ATTRIBUTE_NOT_CONTENT_INDEXED win32-file-attribute ]
+            [ +encrypted+ FILE_ATTRIBUTE_ENCRYPTED win32-file-attribute ]
+        } cleave
     ] { } make ;
 
 : win32-file-type ( n -- symbol )
     FILE_ATTRIBUTE_DIRECTORY mask? +directory+ +regular-file+ ? ;
 
 : WIN32_FIND_DATA>file-info ( WIN32_FIND_DATA -- file-info )
-    [ \ file-info new ] dip
+    [ \ windows-file-info new ] dip
     {
         [ WIN32_FIND_DATA-dwFileAttributes win32-file-type >>type ]
+        [ WIN32_FIND_DATA-dwFileAttributes win32-file-attributes >>attributes ]
         [
             [ WIN32_FIND_DATA-nFileSizeLow ]
             [ WIN32_FIND_DATA-nFileSizeHigh ] bi >64bit >>size
@@ -196,9 +200,10 @@ SYMBOLS: +read-only+ +hidden+ +system+
     ] keep ;
 
 : BY_HANDLE_FILE_INFORMATION>file-info ( HANDLE_FILE_INFORMATION -- file-info )
-    [ \ file-info new ] dip
+    [ \ windows-file-info new ] dip
     {
         [ BY_HANDLE_FILE_INFORMATION-dwFileAttributes win32-file-type >>type ]
+        [ BY_HANDLE_FILE_INFORMATION-dwFileAttributes win32-file-attributes >>attributes ]
         [
             [ BY_HANDLE_FILE_INFORMATION-nFileSizeLow ]
             [ BY_HANDLE_FILE_INFORMATION-nFileSizeHigh ] bi >64bit >>size
index 44b06f94bce2ac1f87c75319d38703e6ad205a53..914f8182787cb52aad59250d58868741a7a7c0a9 100755 (executable)
@@ -1 +1,2 @@
 Chris Double
+Peter Burns
\ No newline at end of file
diff --git a/basis/json/json-docs.factor b/basis/json/json-docs.factor
new file mode 100644 (file)
index 0000000..816e723
--- /dev/null
@@ -0,0 +1,8 @@
+IN: json
+USING: help.markup help.syntax ;
+
+ARTICLE: "json" "JSON serialization"
+{ $subsection "json.reader" }
+{ $subsection "json.writer" } ;
+
+ABOUT: "json"
diff --git a/basis/json/json.factor b/basis/json/json.factor
new file mode 100644 (file)
index 0000000..d7cfc0e
--- /dev/null
@@ -0,0 +1,7 @@
+IN: json
+USE: vocabs.loader
+
+SINGLETON: json-null
+
+"json.reader" require
+"json.writer" require
index ea4dcbf954e77bbad8664b803470e3d57f9436fb..4446c385d3424085c06291a5fe53a5ca580d6f60 100644 (file)
@@ -3,6 +3,12 @@
 USING: help.markup help.syntax ;
 IN: json.reader
 
-HELP: json> "( string -- object )"
-{ $values { "string" "a string in JSON format" } { "object" "yhe object deserialized from the JSON string" } }
+HELP: json>
+{ $values { "string" "a string in JSON format" } { "object" "a deserialized object" } }
 { $description "Deserializes the JSON formatted string into a Factor object. JSON objects are converted to Factor hashtables. All other JSON objects convert to their obvious Factor equivalents." } ;
+
+ARTICLE: "json.reader" "JSON reader"
+"The " { $vocab-link "json.reader" } " vocabulary defines a word for parsing strings in JSON format."
+{ $subsection json> } ;
+
+ABOUT: "json.reader"
index 995ae0e0b8b8027014d4c1303a5585f62330e3b1..e97d45babe179f928e83cc285dc50a60ea680b9b 100644 (file)
@@ -1,4 +1,5 @@
-USING: arrays json.reader kernel multiline strings tools.test ;
+USING: arrays json.reader kernel multiline strings tools.test
+hashtables json ;
 IN: json.reader.tests
 
 { f } [ "false" json> ] unit-test
@@ -8,21 +9,35 @@ IN: json.reader.tests
 { 102 } [ "102" json> ] unit-test
 { -102 } [ "-102" json> ] unit-test
 { 102 } [ "+102" json> ] unit-test
+{ 1000.0 } [ "1.0e3" json> ] unit-test
+{ 1000.0 } [ "10e2" json> ] unit-test
 { 102.0 } [ "102.0" json> ] unit-test
 { 102.5 } [ "102.5" json> ] unit-test
 { 102.5 } [ "102.50" json> ] unit-test
 { -10250.0 } [ "-102.5e2" json> ] unit-test
 { -10250.0 } [ "-102.5E+2" json> ] unit-test
-{ 10+1/4 } [ "1025e-2" json> ] unit-test
+{ 10.25 } [ "1025e-2" json> ] unit-test
 { 0.125 } [ "0.125" json> ] unit-test
 { -0.125 } [ "-0.125" json> ] unit-test
 
+! not widely supported by javascript, but allowed in the grammar, and a nice
+! feature to get
+{ -0.0 } [ "-0.0" json> ] unit-test
+
 { " fuzzy  pickles " } [ <" " fuzzy  pickles " "> json> ] unit-test
 { "while 1:\n\tpass" } [ <" "while 1:\n\tpass" "> json> ] unit-test
+! unicode is allowed in json
+{ "ß∂¬ƒ˚∆" } [ <" "ß∂¬ƒ˚∆""> json> ] unit-test
 { 8 9 10 12 13 34 47 92 } >string 1array [ <" "\b\t\n\f\r\"\/\\" "> json> ] unit-test
 { HEX: abcd } >string 1array [ <" "\uaBCd" "> json> ] unit-test
 
+{ { } } [ "[]" json> ] unit-test 
 { { 1 "two" 3.0 } } [ <" [1, "two", 3.0] "> json> ] unit-test
+{ H{ } } [ "{}" json> ] unit-test
+
+! the returned hashtable should be different every time
+{ H{ } } [ "key" "value" "{}" json> ?set-at "{}" json> nip ] unit-test
+
 { H{ { "US$" 1.0 } { "EU€" 1.5 } } } [ <" { "US$":1.00, "EU\u20AC":1.50 } "> json> ] unit-test
 { H{
     { "fib" { 1 1 2 3 5 8 H{ { "etc" "etc" } } } }
@@ -40,4 +55,3 @@ IN: json.reader.tests
 { 0 } [ "      0" json> ] unit-test
 { 0 } [ "0      " json> ] unit-test
 { 0 } [ "   0   " json> ] unit-test
-
index dd1ab8d5d8e1354b8065e62f662913a2ee05edac..0014ba1eb19d9491254d093308d3223b33d606e7 100644 (file)
-! Copyright (C) 2006 Chris Double.
+! Copyright (C) 2008 Peter Burns.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel parser-combinators namespaces make sequences promises strings 
-       assocs math math.parser math.vectors math.functions math.order
-       lists hashtables ascii accessors ;
+USING: kernel peg peg.ebnf math.parser math.private strings math
+math.functions sequences arrays vectors hashtables assocs
+prettyprint json ;
 IN: json.reader
 
-! Grammar for JSON from RFC 4627
-
-SYMBOL: json-null
-
-: [<&>] ( quot -- quot )
-  { } make unclip [ <&> ] reduce ;
-
-: [<|>] ( quot -- quot )
-  { } make unclip [ <|> ] reduce ;
-
-LAZY: 'ws' ( -- parser )
-  " " token 
-  "\n" token <|>
-  "\r" token <|>
-  "\t" token <|> <*> ;
-
-LAZY: spaced ( parser -- parser )
-  'ws' swap &> 'ws' <& ;
-
-LAZY: 'begin-array' ( -- parser )
-  "[" token spaced ;
-
-LAZY: 'begin-object' ( -- parser )
-  "{" token spaced ;
-
-LAZY: 'end-array' ( -- parser )
-  "]" token spaced ;
-
-LAZY: 'end-object' ( -- parser )
-  "}" token spaced ;
-
-LAZY: 'name-separator' ( -- parser )
-  ":" token spaced ;
-
-LAZY: 'value-separator' ( -- parser )
-  "," token spaced ;
-
-LAZY: 'false' ( -- parser )
-  "false" token [ drop f ] <@ ;
-
-LAZY: 'null' ( -- parser )
-  "null" token [ drop json-null ] <@ ;
-
-LAZY: 'true' ( -- parser )
-  "true" token [ drop t ] <@ ;
-
-LAZY: 'quot' ( -- parser )
-  "\"" token ;
-
-LAZY: 'hex-digit' ( -- parser )
-  [ digit> ] satisfy [ digit> ] <@ ;
-
-: hex-digits>ch ( digits -- ch )
-    0 [ swap 16 * + ] reduce ;
-
-LAZY: 'string-char' ( -- parser )
-  [ quotable? ] satisfy
-  "\\b" token [ drop 8 ] <@ <|>
-  "\\t" token [ drop CHAR: \t ] <@ <|>
-  "\\n" token [ drop CHAR: \n ] <@ <|>
-  "\\f" token [ drop 12 ] <@ <|>
-  "\\r" token [ drop CHAR: \r ] <@ <|>
-  "\\\"" token [ drop CHAR: " ] <@ <|>
-  "\\/" token [ drop CHAR: / ] <@ <|>
-  "\\\\" token [ drop CHAR: \\ ] <@ <|>
-  "\\u" token 'hex-digit' 4 exactly-n &>
-  [ hex-digits>ch ] <@ <|> ;
-
-LAZY: 'string' ( -- parser )
-  'quot' 
-  'string-char' <*> &> 
-  'quot' <& [ >string ] <@  ;
+<PRIVATE
 
-DEFER: 'value'
+: grammar-list>vector ( seq -- vec ) first2 values swap prefix ;
 
-LAZY: 'member' ( -- parser )
-  'string'
-  'name-separator' <&  
-  'value' <&> ;
-
-USE: prettyprint 
-LAZY: 'object' ( -- parser )
-  'begin-object' 
-  'member' 'value-separator' list-of &>
-  'end-object' <& [ >hashtable ] <@ ;
-
-LAZY: 'array' ( -- parser )
-  'begin-array' 
-  'value' 'value-separator' list-of &>
-  'end-array' <&  ;
-  
-LAZY: 'minus' ( -- parser )
-  "-" token ;
-
-LAZY: 'plus' ( -- parser )
-  "+" token ;
-
-LAZY: 'sign' ( -- parser )
-  'minus' 'plus' <|> ;
-
-LAZY: 'zero' ( -- parser )
-  "0" token [ drop 0 ] <@ ;
-
-LAZY: 'decimal-point' ( -- parser )
-  "." token ;
-
-LAZY: 'digit1-9' ( -- parser )
-  [ 
-    dup integer? [ 
-      CHAR: 1 CHAR: 9 between? 
-    ] [ 
-      drop f 
-    ] if 
-  ] satisfy [ digit> ] <@ ;
-
-LAZY: 'digit0-9' ( -- parser )
-  [ digit? ] satisfy [ digit> ] <@ ;
-
-: decimal>integer ( seq -- num ) 10 digits>integer ;
-
-LAZY: 'int' ( -- parser )
-  'zero' 
-  'digit1-9' 'digit0-9' <*> <&:> [ decimal>integer ] <@ <|>  ;
-
-LAZY: 'e' ( -- parser )
-  "e" token "E" token <|> ;
-
-: sign-number ( pair -- number )
-  #! Pair is { minus? num }
-  #! Convert the json number value to a factor number
-  dup second swap first [ first "-" = [ -1 * ] when ] when* ;
-
-LAZY: 'exp' ( -- parser )
-    'e' 
-    'sign' <?> &>
-    'digit0-9' <+> [ decimal>integer ] <@ <&> [ sign-number ] <@ ;
-
-: sequence>frac ( seq -- num ) 
-  #! { 1 2 3 } => 0.123
-  reverse 0 [ swap 10 / + ] reduce 10 / >float ;
-
-LAZY: 'frac' ( -- parser )
-  'decimal-point' 'digit0-9' <+> &> [ sequence>frac ] <@ ;
-
-: raise-to-power ( pair -- num )
-  #! Pair is { num exp }.
-  #! Multiply 'num' by 10^exp
-  dup second dup [ 10 swap first ^ swap first * ] [ drop first ] if ;
-
-LAZY: 'number' ( -- parser )
-  'sign' <?>
-  [ 'int' , 'frac' 0 succeed <|> , ] [<&>] [ sum ] <@ 
-  'exp' <?> <&> [ raise-to-power ] <@ <&> [ sign-number ] <@ ;
-
-LAZY: 'value' ( -- parser )
-  [
-    'false' ,
-    'null' ,
-    'true' ,
-    'string' ,
-    'object' ,
-    'array' ,
-    'number' ,
-  ] [<|>] spaced ;
-ERROR: could-not-parse-json ;
-
-: json> ( string -- object )
-  #! Parse a json formatted string to a factor object
-  'value' parse dup nil? [ 
-      could-not-parse-json
-  ] [ 
-    car parsed>> 
-  ] if ;
+! Grammar for JSON from RFC 4627
+EBNF: (json>)
+
+ws = (" " | "\r" | "\t" | "\n")*
+
+true = "true" => [[ t ]]
+false = "false" => [[ f ]]
+null = "null" => [[ json-null ]]
+
+hex = [0-9a-fA-F]
+char = '\\"'  [[ CHAR: "  ]]
+     | "\\\\" [[ CHAR: \  ]]
+     | "\\/"  [[ CHAR: /  ]]
+     | "\\b"  [[ 8        ]]
+     | "\\f"  [[ 12       ]]
+     | "\\n"  [[ CHAR: \n ]]
+     | "\\r"  [[ CHAR: \r ]]
+     | "\\t"  [[ CHAR: \t ]]
+     | "\\u" (hex hex hex hex) [[ hex> ]] => [[ second ]]
+     | [^"\]
+string = '"' char*:cs '"' => [[ cs >string ]]
+
+sign = ("-" | "+")? => [[ "-" = "-" "" ? ]]
+digits = [0-9]+     => [[ >string ]]
+decimal = "." digits  => [[ concat ]]
+exp = ("e" | "E") sign digits => [[ concat ]]
+number = sign digits decimal? exp? => [[ dup concat swap fourth [ string>float ] [ string>number ] if ]]
+
+elements = value ("," value)* => [[ grammar-list>vector ]]
+array = "[" elements?:arr "]" => [[ arr >array ]]
+
+pair = ws string:key ws ":" value:val => [[ { key val } ]]
+members = pair ("," pair)* => [[ grammar-list>vector ]]
+object = "{" members?:hash "}" => [[ hash >hashtable ]]
+
+val = true
+    | false
+    | null
+    | string
+    | number
+    | array
+    | object
+
+value = ws val:v ws => [[ v ]]
+
+;EBNF
+
+PRIVATE>
+
+: json> ( string -- object ) (json>) ;
\ No newline at end of file
index 21aa8b2cb5d453405a870d2748b7e8bd2215f47e..8512d80384454f7ca0c0aa7384953fdd81c03c2e 100644 (file)
@@ -3,13 +3,19 @@
 USING: help.markup help.syntax ;
 IN: json.writer
 
-HELP: >json "( obj -- string )"
+HELP: >json
 { $values { "obj" "an object" } { "string" "the object converted to JSON format" } }
 { $description "Serializes the object into a JSON formatted string." } 
 { $see-also json-print } ;
 
-HELP: json-print "( obj -- )"
+HELP: json-print
 { $values { "obj" "an object" } }
 { $description "Serializes the object into a JSON formatted string and outputs it to the standard output stream." } 
 { $see-also >json } ;
 
+ARTICLE: "json.writer" "JSON writer"
+"The " { $vocab-link "json.writer" } " vocabulary defines words for converting objects to JSON format."
+{ $subsection >json }
+{ $subsection json-print } ;
+
+ABOUT: "json.writer"
diff --git a/basis/json/writer/writer-tests.factor b/basis/json/writer/writer-tests.factor
new file mode 100644 (file)
index 0000000..6b6118c
--- /dev/null
@@ -0,0 +1,20 @@
+USING: json.writer tools.test multiline json.reader json ;
+IN: json.writer.tests
+
+{ "false" } [ f >json ] unit-test
+{ "true" } [ t >json ] unit-test
+{ "null" } [ json-null >json ] unit-test
+{ "0" } [ 0 >json ] unit-test
+{ "102" } [ 102 >json ] unit-test
+{ "-102" } [ -102 >json ] unit-test
+{ "102.0" } [ 102.0 >json ] unit-test
+{ "102.5" } [ 102.5 >json ] unit-test
+
+{ "[1,\"two\",3.0]" } [ { 1 "two" 3.0 } >json ] unit-test
+{ <" {"US$":1.0,"EU€":1.5}"> } [ H{ { "US$" 1.0 } { "EU€" 1.5 } } >json ] unit-test
+
+! Random symbols are written simply as strings
+SYMBOL: testSymbol
+{ <" "testSymbol""> } [ testSymbol >json ] unit-test
+
+[ { 0.5 } ] [ { 1/2 } >json json> ] unit-test
\ No newline at end of file
index cbcf426545943e363da36bc0d851e38e72812040..e374919039aedeb2bb0ab078552df33597b822a7 100644 (file)
@@ -1,44 +1,52 @@
 ! Copyright (C) 2006 Chris Double.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel io.streams.string io strings splitting sequences
-math math.parser assocs classes words namespaces make
-prettyprint hashtables mirrors tr ;
+USING: accessors kernel io.streams.string io strings splitting
+sequences math math.parser assocs classes words namespaces make
+prettyprint hashtables mirrors tr json ;
 IN: json.writer
 
 #! Writes the object out to a stream in JSON format
 GENERIC: json-print ( obj -- )
 
 : >json ( obj -- string )
-  #! Returns a string representing the factor object in JSON format
-  [ json-print ] with-string-writer ;
+    #! Returns a string representing the factor object in JSON format
+    [ json-print ] with-string-writer ;
 
 M: f json-print ( f -- )
-  drop "false" write ;
+    drop "false" write ;
+
+M: t json-print ( t -- )
+    drop "true" write ;
+
+M: json-null json-print ( null -- )
+    drop "null" write ;
 
 M: string json-print ( obj -- )
-  CHAR: " write1 "\"" split "\\\"" join CHAR: \r swap remove "\n" split "\\r\\n" join write CHAR: " write1 ;
+    CHAR: " write1 "\"" split "\\\"" join CHAR: \r swap remove "\n" split "\\r\\n" join write CHAR: " write1 ;
+
+M: integer json-print ( num -- )
+    number>string write ;
 
-M: number json-print ( num -- )  
-  number>string write ;
+M: real json-print ( num -- )
+    >float number>string write ;
 
 M: sequence json-print ( array -- ) 
-  CHAR: [ write1 [ >json ] map "," join write CHAR: ] write1 ;
+    CHAR: [ write1 [ >json ] map "," join write CHAR: ] write1 ;
 
 TR: jsvar-encode "-" "_" ;
   
 : tuple>fields ( object -- seq )
-  <mirror> [
-    [ swap jsvar-encode >json % " : " % >json % ] "" make
-  ] { } assoc>map ;
+    <mirror> [
+        [ swap jsvar-encode >json % " : " % >json % ] "" make
+    ] { } assoc>map ;
 
 M: tuple json-print ( tuple -- )
-  CHAR: { write1 tuple>fields "," join write CHAR: } write1 ;
+    CHAR: { write1 tuple>fields "," join write CHAR: } write1 ;
 
 M: hashtable json-print ( hashtable -- )
-  CHAR: { write1 
-  [ [ swap jsvar-encode >json % CHAR: : , >json % ] "" make ]
-  { } assoc>map "," join write 
-  CHAR: } write1 ;
+    CHAR: { write1 
+    [ [ swap jsvar-encode >json % CHAR: : , >json % ] "" make ]
+    { } assoc>map "," join write 
+    CHAR: } write1 ;
 
-M: object json-print ( object -- )
-    unparse json-print ;
+M: word json-print name>> json-print ;
index 5e285bf26db8bc91030ae2a46114e6564803d1ad..37a3b7068fd20a5262aabe83b3892171ba5fe4d7 100644 (file)
@@ -33,7 +33,7 @@ HELP: free
 { $description "Deallocates a block of memory allocated by " { $link malloc } ", " { $link calloc } " or " { $link realloc } "." } ;
 
 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." } ;
 
 HELP: &free
index 31f387aeb98428394f5ef946fc36f250819b29a9..6fd42954aadd482eba4795c15bd3eb3eb5923ef1 100644 (file)
@@ -5,7 +5,7 @@ HELP: linked-assoc
 { $class-description "The class of linked assocs. Linked assoc are implemented by combining an assoc with a dlist.  The assoc is used for lookup and retrieval of single values, while the dlist is used for getting lists of keys/values, which will be in insertion order." } ;
 
 HELP: <linked-assoc>
-{ $values { "exemplar" "an exemplar assoc" } }
+{ $values { "exemplar" "an exemplar assoc" } { "assoc" linked-assoc } }
 { $description "Creates an empty linked assoc backed by a new instance of the same type as the exemplar." } ;
 
 HELP: <linked-hash>
index c588269284ebd5b27a31b8b4aefa79c8f7aebe10..e74ecf3dc9fa55da59eb939a2c144ae79138f4bb 100644 (file)
@@ -6,8 +6,7 @@ quotations debugger macros arrays macros splitting combinators
 prettyprint.backend definitions prettyprint hashtables
 prettyprint.sections sets sequences.private effects
 effects.parser generic generic.parser compiler.units accessors
-locals.backend memoize macros.expander lexer classes
-stack-checker.known-words ;
+locals.backend memoize macros.expander lexer classes ;
 IN: locals
 
 ! Inspired by
@@ -49,8 +48,7 @@ PREDICATE: local < word "local?" word-prop ;
 : <local> ( name -- word )
     #! Create a local variable identifier
     f <word>
-    dup t "local?" set-word-prop
-    dup { } { object } define-primitive ;
+    dup t "local?" set-word-prop ;
 
 PREDICATE: local-word < word "local-word?" word-prop ;
 
@@ -61,14 +59,12 @@ PREDICATE: local-reader < word "local-reader?" word-prop ;
 
 : <local-reader> ( name -- word )
     f <word>
-    dup t "local-reader?" set-word-prop
-    dup { } { object } define-primitive ;
+    dup t "local-reader?" set-word-prop ;
 
 PREDICATE: local-writer < word "local-writer?" word-prop ;
 
 : <local-writer> ( reader -- word )
     dup name>> "!" append f <word> {
-        [ nip { object } { } define-primitive ]
         [ nip t "local-writer?" set-word-prop ]
         [ swap "local-reader" set-word-prop ]
         [ "local-writer" set-word-prop ]
index c2fceffae69da82fda726b4855767e2a581bb21c..3666fa2423c7e2d579ae772caaeeacd17a57e183 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel sequences sequences.private namespaces make
 quotations accessors words continuations vectors effects math
-generalizations stack-checker.transforms fry ;
+generalizations fry ;
 IN: macros.expander
 
 GENERIC: expand-macros ( quot -- quot' )
index 0a6621f044b4ce27158f857ff22d873565994b22..794d523d006c11504c32aeb16db8ea3950d3cfd7 100644 (file)
@@ -1,21 +1,18 @@
 ! Copyright (C) 2007, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: parser kernel sequences words effects
-stack-checker.transforms combinators assocs definitions
-quotations namespaces memoize accessors ;
+USING: parser kernel sequences words effects combinators assocs
+definitions quotations namespaces memoize accessors ;
 IN: macros
 
 : real-macro-effect ( word -- effect' )
     "declared-effect" word-prop in>> 1 <effect> ;
 
 : define-macro ( word definition -- )
-    over "declared-effect" word-prop in>> length >r
-    2dup "macro" set-word-prop
-    2dup over real-macro-effect memoize-quot [ call ] append define
-    r> define-transform ;
+    [ "macro" set-word-prop ]
+    [ over real-macro-effect memoize-quot [ call ] append define ]
+    2bi ;
 
-: MACRO:
-    (:) define-macro ; parsing
+: MACRO: (:) define-macro ; parsing
 
 PREDICATE: macro < word "macro" word-prop >boolean ;
 
index f9bb8e9897779d40b0a506943699ead163431451..ea3da550829cebc94fab39344282fcde22320c2a 100644 (file)
@@ -279,7 +279,7 @@ HELP: mod-inv
 } ;
 
 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)." }
 { $examples
     { $example "USING: math.functions make prettyprint ;" "[ BIN: 1101 [ , ] each-bit ] { } make ." "{ t f t t }" }
index c5e5a6e7b83c1cd43ddaaec6ca37666a93d1f52c..5a96c7aceba076d6474996e7e5cec16bf1cd605c 100644 (file)
@@ -156,8 +156,8 @@ HELP: interval*
 { $description "Multiplies two intervals." } ;
 
 HELP: interval-shift
-{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } }
-{ $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." } ;
+{ $values { "i1" interval } { "i2" interval } { "i3" interval } }
+{ $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
 { $values { "i1" interval } { "i2" interval } { "i3" interval } }
@@ -253,8 +253,8 @@ HELP: points>interval
 ;
 
 HELP: interval-shift-safe
-{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } }
-{ $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." } ;
+{ $values { "i1" interval } { "i2" interval } { "i3" interval } }
+{ $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
 { $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." } ;
 
 HELP: assume<
-{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } }
-{ $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 } "." } ;
+{ $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" } "." } ;
 
 HELP: assume<=
-{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } }
-{ $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 } "." } ;
+{ $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" } "." } ;
 
 HELP: assume>
 { $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 } "." } ;
 
 HELP: assume>=
-{ $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 or equal to all points in " { $snippet "i2" } ". If the resulting interval is empty, outputs " { $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" } "." } ;
 
 HELP: integral-closure
 { $values { "i1" "an " { $link interval } " with integer end-points" } { "i2" "a closed " { $link interval } " with integer end-points" } }
index 8c50aac65b42c5b1b7c8647e2d6d09cc7200f3dd..c3f4df3250331dbace6bfac1ecd3255fa67c0c35 100644 (file)
@@ -15,7 +15,7 @@ HELP: filter
 } ;\r
 \r
 HELP: <filter>\r
-{ $values { "model" model } { "quot" "a quotation with stack effect " { $snippet "( obj -- newobj )" } } { "filter" "a new " { $link filter } } }\r
+{ $values { "model" model } { "quot" { $quotation "( obj -- newobj )" } } { "filter" "a new " { $link filter } } }\r
 { $description "Creates a new instance of " { $link filter } ". The value of the new filter model is computed by applying the quotation to the value." }\r
 { $examples "See the example in the documentation for " { $link filter } "." } ;\r
 \r
index 97e4557adaa7bf1d967546c3e7609c38ecd1a226..5295420ee31bab34412eb5623c2962f55fa36e73 100644 (file)
@@ -66,11 +66,11 @@ HELP: set-model
 { set-model change-model (change-model) } related-words
 
 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 } "." } ;
 
 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 } "." }
 { $notes "There are very few reasons for user code to call this word. Instead, call " { $link change-model } ", which notifies observers." } ;
 
index 00390c1b1e31520aa71351cf1a87151fdd59cf4f..976c32d1025ec0a5ef786b2400ae02e988e9166d 100644 (file)
@@ -98,7 +98,7 @@ HELP: optional
 HELP: semantic\r
 { $values \r
   { "parser" "a parser" } \r
-  { "quot" "a quotation with stack effect ( object -- bool )" } \r
+  { "quot" { $quotation "( object -- ? )" } } \r
 }\r
 { $description \r
     "Returns a parser that succeeds if the 'p1' parser succeeds and the quotation called with "\r
@@ -130,7 +130,7 @@ HELP: ensure-not
 HELP: action\r
 { $values \r
   { "parser" "a parser" } \r
-  { "quot" "a quotation with stack effect ( ast -- ast )" } \r
+  { "quot" { $quotation "( ast -- ast )" } } \r
 }\r
 { $description \r
     "Returns a parser that calls the 'p1' parser and applies the quotation to the AST resulting "\r
index a867dbb2e31859e059f01b1e92f5ebc6fa5684bb..e50fd52c1051eb52391929295546f852deb2475b 100644 (file)
@@ -53,3 +53,6 @@ M: persistent-hash clone ;
 M: persistent-hash pprint-delims drop \ PH{ \ } ;
 M: persistent-hash >pprint-sequence >alist ;
 M: persistent-hash pprint* pprint-object ;
+
+: passociate ( value key -- phash )
+    T{ persistent-hash } new-at ; inline
index 961e8bfce748508f5256b65b7a95f371c40f6702..5503e369b4699f89b048802c0d0e0eb7cec54f35 100644 (file)
@@ -14,3 +14,6 @@ M: sequence ppop 1 head* ;
 GENERIC: new-nth ( val i seq -- seq' )
 
 M: sequence new-nth clone [ set-nth ] keep ;
+
+: changed-nth ( i seq quot -- seq' )
+    [ [ nth ] dip call ] [ drop new-nth ] 3bi ; inline
index cc4f5cedb53881244b216d3127ec9598d089af7c..64e1fd45ff1b3c51532aa01d0707185d005deec5 100644 (file)
@@ -37,7 +37,7 @@ HELP: nesting-limit?
 $prettyprinting-note ;
 
 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." }
 $prettyprinting-note ;
 
index b749bd63eb83b575a96293cfa44a619067fabb0c..31b6ba3f2612de4c42224c190b4ce5c496c2522c 100644 (file)
@@ -214,6 +214,7 @@ M: tuple pprint-narrow? drop t ;
 
 M: object pprint* pprint-object ;
 M: vector pprint* pprint-object ;
+M: byte-vector pprint* pprint-object ;
 M: hashtable pprint* pprint-object ;
 
 M: curry pprint*
index 842a36a13b5163feff5409e9032b1541f05d93c8..4f1c073a2d45b18bd9c2636e5873b948590413e0 100644 (file)
@@ -145,7 +145,7 @@ HELP: save-end-position
 { $description "Save the current position as the end position of the block." } ;
 
 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." } ;
 
 HELP: do-break
@@ -157,7 +157,7 @@ HELP: empty-block?
 { $description "Tests if the block has no child sections." } ;
 
 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." } ;
 
 HELP: (<block)
index a0b62cf7de59aecb0729e36fc6e1191cc4501a5f..5c93606ab5eda41355a9feb93317b736c7f268b4 100755 (executable)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: alien.c-types kernel math namespaces sequences
 io.backend io.binary combinators system vocabs.loader
-summary math.bitwise ;
+summary math.bitwise byte-vectors fry byte-arrays ;
 IN: random
 
 SYMBOL: system-random-generator
@@ -14,7 +14,12 @@ GENERIC: random-32* ( tuple -- r )
 GENERIC: random-bytes* ( n tuple -- byte-array )
 
 M: object random-bytes* ( n tuple -- byte-array )
-    [ random-32* ] curry replicate [ 4 >le ] map concat ;
+    [ [ <byte-vector> ] keep 4 /mod ] dip tuck
+    [ pick '[ _ random-32* 4 >le _ push-all ] times ]
+    [
+        over zero?
+        [ 2drop ] [ random-32* 4 >le swap head over push-all ] if
+    ] 2bi* ;
 
 M: object random-32* ( tuple -- r ) 4 random-bytes* le> ;
 
@@ -28,16 +33,13 @@ M: f random-bytes* ( n obj -- * ) no-random-number-generator ;
 M: f random-32* ( obj -- * ) no-random-number-generator ;
 
 : random-bytes ( n -- byte-array )
-    [
-        dup 3 mask zero? [ 1+ ] unless
-        random-generator get random-bytes*
-    ] keep head ;
+    random-generator get random-bytes* ;
 
 <PRIVATE
 
 : random-integer ( n -- n' )
     dup log2 7 + 8 /i 1+
-    [ random-bytes byte-array>bignum ]
+    [ random-bytes >byte-array byte-array>bignum ]
     [ 3 shift 2^ ] bi / * >integer ;
 
 PRIVATE>
index fef770b0f877b83bcdb3d2122bceed1961041f9a..fe0ce7c1574663add50091d6e97f8d7d29f3c1c6 100644 (file)
@@ -1,21 +1,15 @@
 IN: search-deques
-USING: help.markup help.syntax kernel dlists hashtables
+USING: help.markup help.syntax kernel hashtables
 deques assocs ;
 
 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."
 $nl
 "Creating a search deque:"
-{ $subsection <search-deque> }
-"Default implementation:"
-{ $subsection <hashed-dlist> } ;
+{ $subsection <search-deque> } ;
 
 ABOUT: "search-deques"
 
 HELP: <search-deque> ( assoc deque -- search-deque )
 { $values { "assoc" assoc } { "deque" deque } { "search-deque" 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." } ;
index cf2837a84cba3fdb03f0136cb709ed5be5623f28..7c40c60f7a30931ecab4a5a045e70450dc145143 100644 (file)
@@ -1,6 +1,6 @@
 IN: search-deques.tests
 USING: search-deques tools.test namespaces
-kernel sequences words deques vocabs ;
+kernel sequences words deques vocabs dlists ;
 
 <hashed-dlist> "h" set
 
@@ -15,13 +15,11 @@ kernel sequences words deques vocabs ;
 [ t ] [ "1" get "2" 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
 
 [ 3 ] [ "1" get node-value ] unit-test
 [ ] [ "1" get "h" get delete-node ] unit-test
 
-[ 2 ] [ "h" get deque-length ] unit-test
 [ 1 ] [ "h" get pop-back ] unit-test
 [ 7 ] [ "h" get pop-back ] unit-test
 
index 8e5506090c4ee20de39d50459e3dc4bc99377f85..5546a9766dd86eb48f34ac9538b5a4bcbd286938 100644 (file)
@@ -1,16 +1,13 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel assocs deques dlists hashtables ;
+USING: accessors kernel assocs deques ;
 IN: search-deques
 
 TUPLE: search-deque assoc deque ;
 
 C: <search-deque> search-deque
 
-: <hashed-dlist> ( -- search-deque )
-    0 <hashtable> <dlist> <search-deque> ;
-
-M: search-deque deque-length deque>> deque-length ;
+M: search-deque deque-empty? deque>> deque-empty? ;
 
 M: search-deque peek-front deque>> peek-front ;
 
index fc060d6b33ae751e9033d7d52a0c7f55ddc8f158..34922a5eae4f52b76d91efd791b9e90293757fe8 100644 (file)
@@ -1,22 +1,34 @@
 ! Copyright (C) 2006 Chris Double.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: help.syntax help.markup ;
+USING: help.syntax help.markup byte-arrays io ;
 IN: serialize
 
 HELP: serialize
-{ $values { "obj" "object to serialize" } 
-}
-{ $description "Serializes the object to the current output stream. Object references within the structure being serialized are maintained." } 
-{ $examples 
-    { $example "USING: serialize io.encodings.binary io.streams.byte-array prettyprint ;" "binary [ { 1 2 } serialize ] with-byte-writer\n\nbinary [ deserialize ] with-byte-reader ." "{ 1 2 }" }
-}
-{ $see-also deserialize } ;
+{ $values { "obj" "object to serialize" } }
+{ $description "Serializes the object to " { $link output-stream } "." } ;
 
 HELP: deserialize
-{ $values { "obj" "deserialized object" } 
+{ $values { "obj" "deserialized object" } }
+{ $description "Deserializes an object by reading from " { $link input-stream } "." } ;
+
+HELP: object>bytes
+{ $values { "obj" "object to serialize" } { "bytes" byte-array }
 }
-{ $description "Deserializes an object by reading from the current input stream. Object references within the structure that was originally serialized are maintained." } 
-{ $examples 
-    { $example "USING: serialize io.encodings.binary io.streams.byte-array prettyprint ;" "binary [ { 1 2 } serialize ] with-byte-writer\n\nbinary [ deserialize ] with-byte-reader ." "{ 1 2 }" }
+{ $description "Serializes the object to a byte array." } ;
+
+HELP: bytes>object
+{ $values { "bytes" byte-array } { "obj" "deserialized object" } 
 }
-{ $see-also serialize } ;
+{ $description "Deserializes an object from a byte array." } ;
+
+ARTICLE: "serialize" "Binary object serialization"
+"The " { $vocab-link "serialize" } " vocabulary implements binary serialization for all Factor data types except for continuations. Unlike the prettyprinter, shared structure and circularity is preserved."
+$nl
+"Storing objects on streams:"
+{ $subsection serialize }
+{ $subsection deserialize }
+"Storing objects as byte arrays:"
+{ $subsection object>bytes }
+{ $subsection bytes>object } ;
+
+ABOUT: "serialize"
index 3a75ad65b60687a7e7e85c20fac28f34f161e6c4..4ed534151b0de86cb429ac1a9290bb89c4f26276 100644 (file)
@@ -1,10 +1,10 @@
 ! Copyright (C) 2006 Chris Double.
 ! See http://factorcode.org/license.txt for BSD license.
 ! 
-USING: tools.test kernel serialize io io.streams.byte-array math
-alien arrays byte-arrays bit-arrays float-arrays sequences math
-prettyprint parser classes math.constants io.encodings.binary
-random assocs ;
+USING: tools.test kernel serialize serialize.private io
+io.streams.byte-array math alien arrays byte-arrays bit-arrays
+float-arrays sequences math prettyprint parser classes
+math.constants io.encodings.binary random assocs ;
 IN: serialize.tests
 
 : test-serialize-cell
index 52c1535886fe14dde59cc0e694da100db2a9dccf..f062548482edb8f5d5572a1936e6de05cd6e4b78 100644 (file)
@@ -15,6 +15,10 @@ locals prettyprint compiler.units sequences.private
 classes.tuple.private ;
 IN: serialize
 
+GENERIC: (serialize) ( obj -- )
+
+<PRIVATE
+
 ! Variable holding a assoc of objects already serialized
 SYMBOL: serialized
 
@@ -35,9 +39,6 @@ M: id equal? over id? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
     #! Return the id of an already serialized object 
     <id> serialized get at ;
 
-! Serialize object
-GENERIC: (serialize) ( obj -- )
-
 ! Numbers are serialized as follows:
 ! 0 => B{ 0 }
 ! 1<=x<=126 => B{ x | 0x80 }
@@ -299,11 +300,11 @@ SYMBOL: deserialized
 : (deserialize) ( -- obj )
     deserialize* [ "End of stream" throw ] unless ;
 
+PRIVATE>
+
 : deserialize ( -- obj )
-    ! [
     V{ } clone deserialized
     [ (deserialize) ] with-variable ;
-    ! ] with-compilation-unit ;
 
 : serialize ( obj -- )
     H{ } clone serialized [ (serialize) ] with-variable ;
index 3ab2d731fe756759e305e10a908d1674eb291abf..93a2a0fa14feb0cf954f1ecbb1e77cc463fbe155 100644 (file)
@@ -1,2 +1,3 @@
 collections
 text
+algorithms
index 42d711b32ba66957d114e76b2aedcc5a59c9c58a..1e3d675068069c79aa420adc0a2e43d7814a6f10 100644 (file)
@@ -1 +1,2 @@
 collections
+algorithms
diff --git a/basis/stack-checker/backend/backend-tests.factor b/basis/stack-checker/backend/backend-tests.factor
new file mode 100644 (file)
index 0000000..3bbba0f
--- /dev/null
@@ -0,0 +1,22 @@
+USING: stack-checker.backend tools.test kernel namespaces
+stack-checker.state sequences ;
+IN: stack-checker.backend.tests
+
+[ ] [
+    V{ } clone meta-d set
+    V{ } clone meta-r set
+    0 d-in set
+] unit-test
+
+[ 0 ] [ 0 ensure-d length ] unit-test
+
+[ 2 ] [ 2 ensure-d length ] unit-test
+[ 2 ] [ meta-d get length ] unit-test
+
+[ 3 ] [ 3 ensure-d length ] unit-test
+[ 3 ] [ meta-d get length ] unit-test
+
+[ 1 ] [ 1 ensure-d length ] unit-test
+[ 3 ] [ meta-d get length ] unit-test
+
+[ ] [ 1 consume-d drop ] unit-test
index f8dec5f823c84cc079e95edd40c264206ffd087f..94e59950f74f20d5778171175716e93b9b582aca 100644 (file)
@@ -5,7 +5,8 @@ namespaces parser prettyprint sequences strings vectors words
 quotations effects classes continuations debugger assocs
 combinators compiler.errors accessors math.order definitions
 sets generic.standard.engines.tuple stack-checker.state
-stack-checker.visitor stack-checker.errors ;
+stack-checker.visitor stack-checker.errors
+stack-checker.values stack-checker.recursive-state ;
 IN: stack-checker.backend
 
 : push-d ( obj -- ) meta-d get push ;
@@ -17,14 +18,24 @@ IN: stack-checker.backend
 
 : peek-d ( -- obj ) pop-d dup push-d ;
 
-: consume-d ( n -- seq ) [ pop-d ] replicate reverse ;
+: make-values ( n -- values )
+    [ <value> ] replicate ;
 
-: output-d ( values -- ) meta-d get push-all ;
+: ensure-d ( n -- values )
+    meta-d get 2dup length > [
+        2dup
+        [ nip >array ] [ length - make-values ] [ nip delete-all ] 2tri
+        [ length d-in +@ ] [ #introduce, ] [ meta-d get push-all ] tri
+        meta-d get push-all
+    ] when swap tail* ;
 
-: ensure-d ( n -- values ) consume-d dup output-d ;
+: shorten-by ( n seq -- )
+    [ length swap - ] keep shorten ; inline
 
-: make-values ( n -- values )
-    [ <value> ] replicate ;
+: consume-d ( n -- seq )
+    [ ensure-d ] [ meta-d get shorten-by ] bi ;
+
+: output-d ( values -- ) meta-d get push-all ;
 
 : produce-d ( n -- values )
     make-values dup meta-d get push-all ;
@@ -35,7 +46,10 @@ IN: stack-checker.backend
     meta-r get dup empty?
     [ too-many-r> inference-error ] [ pop ] if ;
 
-: consume-r ( n -- seq ) [ pop-r ] replicate reverse ;
+: consume-r ( n -- seq )
+    meta-r get 2dup length >
+    [ too-many-r> inference-error ] when
+    [ swap tail* ] [ shorten-by ] 2bi ;
 
 : output-r ( seq -- ) meta-r get push-all ;
 
@@ -69,9 +83,6 @@ M: object apply-object push-literal ;
         infer-quot-here
     ] dip recursive-state set ;
 
-: infer-quot-recursive ( quot word label -- )
-    2array recursive-state get swap prefix infer-quot ;
-
 : time-bomb ( error -- )
     '[ _ throw ] infer-quot-here ;
 
@@ -84,7 +95,7 @@ M: object apply-object push-literal ;
     ] [
         dup value>> callable? [
             [ value>> ]
-            [ [ recursion>> ] keep f 2array prefix ]
+            [ [ recursion>> ] keep add-local-quotation ]
             bi infer-quot
         ] [
             drop bad-call
@@ -113,6 +124,9 @@ M: object apply-object push-literal ;
         terminated?>> [ terminate ] when
     ] 2bi ; inline
 
+: infer-word-def ( word -- )
+    [ def>> ] [ add-recursive-state ] bi infer-quot ;
+
 : check->r ( -- )
     meta-r get empty? terminated? get or
     [ \ too-many->r inference-error ] unless ;
@@ -161,7 +175,7 @@ M: object apply-object push-literal ;
             stack-visitor off
             dependencies off
             generic-dependencies off
-            [ [ def>> ] [ ] [ ] tri infer-quot-recursive end-infer ]
+            [ infer-word-def end-infer ]
             [ finish-word current-effect ]
             bi
         ] with-scope
index d1417d035ce64c461b35948fe74d24bd79cfe845..7b461d0028bbde2f9653fec50eb32c27e380bd34 100644 (file)
@@ -3,7 +3,7 @@
 USING: fry vectors sequences assocs math accessors kernel
 combinators quotations namespaces stack-checker.state
 stack-checker.backend stack-checker.errors stack-checker.visitor
-;
+stack-checker.values stack-checker.recursive-state ;
 IN: stack-checker.branches
 
 : balanced? ( pairs -- ? )
index bab6c17c85e93151037cf61ba272643e3f2e6615..efdc7e23b2e0e1e7a77d2b91d83c68098d747a06 100644 (file)
@@ -2,12 +2,11 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel generic sequences prettyprint io words arrays
 summary effects debugger assocs accessors namespaces
-compiler.errors ;
+compiler.errors stack-checker.values
+stack-checker.recursive-state ;
 IN: stack-checker.errors
 
-SYMBOL: recursive-state
-
-TUPLE: inference-error error type rstate ;
+TUPLE: inference-error error type word ;
 
 M: inference-error compiler-error-type type>> ;
 
@@ -15,7 +14,7 @@ M: inference-error error-help error>> error-help ;
 
 : (inference-error) ( ... class type -- * )
     >r boa r>
-    recursive-state get
+    recursive-state get word>>
     \ inference-error boa throw ; inline
 
 : inference-error ( ... class -- * )
@@ -25,16 +24,15 @@ M: inference-error error-help error>> error-help ;
     +warning+ (inference-error) ; inline
 
 M: inference-error error.
-    [
-        rstate>>
-        [ "Nesting:" print stack. ] unless-empty
-    ] [ error>> error. ] bi ;
+    [ "In word: " write word>> . ] [ error>> error. ] bi ;
 
 TUPLE: literal-expected ;
 
 M: literal-expected summary
     drop "Literal value expected" ;
 
+M: object (literal) \ literal-expected inference-warning ;
+
 TUPLE: unbalanced-branches-error branches quots ;
 
 : unbalanced-branches-error ( branches quots -- * )
index 7847fdfdcf194d4db13e226e53c205dcd814d917..b6a988652b8415a648b5e27f3d4ae02f7dae7277 100644 (file)
@@ -4,18 +4,20 @@ USING: fry namespaces assocs kernel sequences words accessors
 definitions math math.order effects classes arrays combinators
 vectors arrays
 stack-checker.state
+stack-checker.errors
+stack-checker.values
 stack-checker.visitor
 stack-checker.backend
 stack-checker.branches
-stack-checker.errors
-stack-checker.known-words ;
+stack-checker.known-words
+stack-checker.recursive-state ;
 IN: stack-checker.inlining
 
 ! Code to handle inline words. Much of the complexity stems from
 ! having to handle recursive inline words.
 
-: (inline-word) ( word label -- )
-    [ [ def>> ] keep ] dip infer-quot-recursive ;
+: infer-inline-word-def ( word label -- )
+    [ drop def>> ] [ add-inline-word ] 2bi infer-quot ;
 
 TUPLE: inline-recursive < identity-tuple
 id
@@ -88,7 +90,7 @@ SYMBOL: enter-out
         nest-visitor
 
         dup <inline-recursive>
-        [ dup emit-enter-recursive (inline-word) ]
+        [ dup emit-enter-recursive infer-inline-word-def ]
         [ end-recursive-word ]
         [ nip ]
         2tri
@@ -133,20 +135,23 @@ SYMBOL: enter-out
     object <repetition> '[ _ prepend ] bi@
     <effect> ;
 
-: call-recursive-inline-word ( word -- )
-    dup "recursive" word-prop [
-        [ required-stack-effect adjust-stack-effect ] [ ] [ recursive-label ] tri
-        [ 2nip check-call ] [ nip '[ _ #call-recursive, ] consume/produce ] 3bi
-    ] [ undeclared-recursion-error inference-error ] if ;
+: call-recursive-inline-word ( word label -- )
+    over "recursive" word-prop [
+        [ required-stack-effect adjust-stack-effect ] dip
+        [ check-call ] [ '[ _ #call-recursive, ] consume/produce ] bi
+    ] [ drop undeclared-recursion-error inference-error ] if ;
 
 : inline-word ( word -- )
     [ inlined-dependency depends-on ]
     [
-        {
-            { [ dup inline-recursive-label ] [ call-recursive-inline-word ] }
-            { [ dup "recursive" word-prop ] [ inline-recursive-word ] }
-            [ dup (inline-word) ]
-        } cond
+        dup inline-recursive-label [
+            call-recursive-inline-word
+        ] [
+            dup "recursive" word-prop
+            [ inline-recursive-word ]
+            [ dup infer-inline-word-def ]
+            if
+        ] if*
     ] bi ;
 
 M: word apply-object
index c40b94fd3ce757b2a5fb35aacceb9fc3476477b3..4aea0f2d28129a0388642661ccbd1a18d0d51846 100644 (file)
@@ -10,14 +10,16 @@ sequences sequences.private slots.private strings
 strings.private system threads.private classes.tuple
 classes.tuple.private vectors vectors.private words definitions
 words.private assocs summary compiler.units system.private
-combinators locals.backend words.private quotations.private
+combinators locals locals.backend locals.private words.private
+quotations.private stack-checker.values
+stack-checker.alien
 stack-checker.state
+stack-checker.errors
+stack-checker.visitor
 stack-checker.backend
 stack-checker.branches
-stack-checker.errors
 stack-checker.transforms
-stack-checker.visitor
-stack-checker.alien ;
+stack-checker.recursive-state ;
 IN: stack-checker.known-words
 
 : infer-primitive ( word -- )
@@ -48,7 +50,7 @@ IN: stack-checker.known-words
 : infer-shuffle ( shuffle -- )
     [ in>> length consume-d ] keep ! inputs shuffle
     [ drop ] [ shuffle dup copy-values dup output-d ] 2bi ! inputs outputs copies
-    [ nip ] [ swap zip ] 2bi ! inputs copies mapping
+    [ nip f f ] [ swap zip ] 2bi ! in-d out-d in-r out-r mapping
     #shuffle, ;
 
 : infer-shuffle-word ( word -- )
@@ -123,21 +125,23 @@ M: object infer-call*
 
 : infer-load-locals ( -- )
     pop-literal nip
-    [ dup reverse <effect> infer-shuffle ]
-    [ infer->r ]
-    bi ;
+    consume-d dup reverse copy-values dup output-r
+    [ [ f f ] dip ] [ reverse swap zip ] 2bi #shuffle, ;
 
 : infer-get-local ( -- )
-    pop-literal nip
-    [ infer-r> ]
-    [ dup 0 prefix <effect> infer-shuffle ]
-    [ infer->r ]
-    tri ;
+    [let* | n [ pop-literal nip ]
+            in-r [ n consume-r ]
+            out-d [ in-r first copy-value 1array ]
+            out-r [ in-r copy-values ] |
+         out-d output-d
+         out-r output-r
+         f out-d in-r out-r
+         out-r in-r zip out-d first in-r first 2array suffix
+         #shuffle,
+    ] ;
 
 : infer-drop-locals ( -- )
-    pop-literal nip
-    [ infer-r> ]
-    [ { } <effect> infer-shuffle ] bi ;
+    f f pop-literal nip consume-r f f #shuffle, ;
 
 : infer-special ( word -- )
     {
@@ -164,6 +168,12 @@ M: object infer-call*
         { \ alien-callback [ infer-alien-callback ] }
     } case ;
 
+: infer-local-reader ( word -- )
+    (( -- value )) apply-word/effect ;
+
+: infer-local-writer ( word -- )
+    (( value -- )) apply-word/effect ;
+
 {
     >r r> declare call (call) curry compose execute (execute) if
 dispatch <tuple-boa> (throw) load-locals get-local drop-locals
@@ -183,7 +193,10 @@ do-primitive alien-invoke alien-indirect alien-callback
         { [ dup "macro" word-prop ] [ apply-macro ] }
         { [ dup "cannot-infer" word-prop ] [ cannot-infer-effect ] }
         { [ dup "inferred-effect" word-prop ] [ cached-infer ] }
-        { [ dup recursive-label ] [ call-recursive-word ] }
+        { [ dup local? ] [ infer-local-reader ] }
+        { [ dup local-reader? ] [ infer-local-reader ] }
+        { [ dup local-writer? ] [ infer-local-writer ] }
+        { [ dup recursive-word? ] [ call-recursive-word ] }
         [ dup infer-word apply-word/effect ]
     } cond ;
 
diff --git a/basis/stack-checker/recursive-state/recursive-state.factor b/basis/stack-checker/recursive-state/recursive-state.factor
new file mode 100644 (file)
index 0000000..41d7331
--- /dev/null
@@ -0,0 +1,43 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays sequences kernel sequences assocs
+namespaces stack-checker.recursive-state.tree ;
+IN: stack-checker.recursive-state
+
+TUPLE: recursive-state words word quotations inline-words ;
+
+C: <recursive-state> recursive-state
+
+: prepare-recursive-state ( word rstate -- rstate )
+    swap >>word
+    f >>quotations
+    f >>inline-words ; inline
+
+: initial-recursive-state ( word -- state )
+    recursive-state new
+        f >>words
+        prepare-recursive-state ; inline
+
+f initial-recursive-state recursive-state set-global
+
+: add-recursive-state ( word -- rstate )
+    recursive-state get clone
+        [ word>> dup ] keep [ store ] change-words
+        prepare-recursive-state ;
+
+: add-local-quotation ( recursive-state quot -- rstate )
+    swap clone [ dupd store ] change-quotations ;
+
+: add-inline-word ( word label -- rstate )
+    swap recursive-state get clone
+    [ store ] change-inline-words ;
+
+: recursive-word? ( word -- ? )
+    recursive-state get 2dup word>> eq?
+    [ 2drop t ] [ words>> lookup ] if ;
+
+: inline-recursive-label ( word -- label/f )
+    recursive-state get inline-words>> lookup ;
+
+: recursive-quotation? ( quot -- ? )
+    recursive-state get quotations>> lookup ;
diff --git a/basis/stack-checker/recursive-state/tree/tree.factor b/basis/stack-checker/recursive-state/tree/tree.factor
new file mode 100644 (file)
index 0000000..dd392af
--- /dev/null
@@ -0,0 +1,31 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel sequences math math.order ;
+IN: stack-checker.recursive-state.tree
+
+! Persistent unbalanced hash tree using eq? comparison.
+! We use this to speed up stack-checker.recursive-state.
+! Perhaps this should go somewhere else
+
+TUPLE: node value key hashcode left right ;
+
+GENERIC: lookup ( key node -- value/f )
+
+M: f lookup nip ;
+
+: decide ( key node -- key node ? )
+    over hashcode over hashcode>> <= ; inline
+
+M: node lookup
+    2dup key>> eq?
+    [ nip value>> ]
+    [ decide [ left>> ] [ right>> ] if lookup ] if ;
+
+GENERIC: store ( value key node -- node' )
+
+M: f store drop dup hashcode f f node boa ;
+
+M: node store
+    clone decide
+    [ [ store ] change-left ]
+    [ [ store ] change-right ] if ;
index a9df463703465d0929b61a83b58ff1147b9c349f..f208178b10f335d239341c46ba7c59983100c417 100644 (file)
@@ -27,7 +27,7 @@ ARTICLE: "inference-combinators" "Combinator stack effects"
 "Consider a combinator such as " { $link keep } ". The combinator itself does not have a stack effect, because it applies " { $link call } " to a potentially arbitrary quotation. However, since the combinator is declared " { $link POSTPONE: inline } ", a given usage of it can have a stack effect:"
 { $example "[ [ 2 + ] keep ] infer." "( object -- object object )" }
 "Another example is the " { $link compose } " combinator. Because it is decared " { $link POSTPONE: inline } ", we can infer the stack effect of applying " { $link call } " to the result of " { $link compose } ":"
-{ $example "[ 2 [ + ] curry [ sq ] compose ] infer." "( -- object object )" }
+{ $example "[ 2 [ + ] curry [ sq ] compose ] infer." "( -- object )" }
 "Incidentally, this example demonstrates that the stack effect of nested currying and composition can also be inferred."
 $nl
 "A general rule of thumb is that any word which applies " { $link call } " or " { $link curry } " to one of its inputs must be declared " { $link POSTPONE: inline } "."
index 11dc6f9ef8d1cceb34d5f66f068f4ead7cb10727..2706ec60ef490782c7da033dfb5f1bac5e27e665 100644 (file)
@@ -1,48 +1,10 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: assocs namespaces sequences kernel definitions math
-effects accessors words fry classes.algebra stack-checker.errors
+USING: assocs arrays namespaces sequences kernel definitions
+math effects accessors words fry classes.algebra
 compiler.units ;
 IN: stack-checker.state
 
-: <value> ( -- value ) \ <value> counter ;
-
-SYMBOL: known-values
-
-: known ( value -- known ) known-values get at ;
-
-: set-known ( known value -- )
-    over [ known-values get set-at ] [ 2drop ] if ;
-
-: make-known ( known -- value )
-    <value> [ set-known ] keep ;
-
-: copy-value ( value -- value' )
-    known make-known ;
-
-: copy-values ( values -- values' )
-    [ copy-value ] map ;
-
-! Literal value
-TUPLE: literal < identity-tuple value recursion ;
-
-: <literal> ( obj -- value )
-    recursive-state get \ literal boa ;
-
-: literal ( value -- literal )
-    known dup literal?
-    [  \ literal-expected inference-warning ] unless ;
-
-! Result of curry
-TUPLE: curried obj quot ;
-
-C: <curried> curried
-
-! Result of compose
-TUPLE: composed quot1 quot2 ;
-
-C: <composed> composed
-
 ! Did the current control-flow path throw an error?
 SYMBOL: terminated?
 
@@ -68,23 +30,6 @@ SYMBOL: meta-r
     V{ } clone meta-r set
     0 d-in set ;
 
-: init-known-values ( -- )
-    H{ } clone known-values set ;
-
-: recursive-label ( word -- label/f )
-    recursive-state get at ;
-
-: local-recursive-state ( -- assoc )
-    recursive-state get dup
-    [ first dup word? [ inline? ] when not ] find drop
-    [ head-slice ] when* ;
-
-: inline-recursive-label ( word -- label/f )
-    local-recursive-state at ;
-
-: recursive-quotation? ( quot -- ? )
-    local-recursive-state [ first eq? ] with contains? ;
-
 ! Words that the current quotation depends on
 SYMBOL: dependencies
 
@@ -98,9 +43,12 @@ SYMBOL: dependencies
 ! Generic words that the current quotation depends on
 SYMBOL: generic-dependencies
 
+: ?class-or ( class/f class -- class' )
+    swap [ class-or ] when* ;
+
 : depends-on-generic ( generic class -- )
     generic-dependencies get dup
-    [ swap '[ null or _ class-or ] change-at ] [ 3drop ] if ;
+    [ swap '[ _ ?class-or ] change-at ] [ 3drop ] if ;
 
 ! Words we've inferred the stack effect of, for rollback
 SYMBOL: recorded
index abc3ae1950962550730774b2e392585e25c4181c..e4f8c50eeb9d3ee9b04d11cee4f7b8ed49b3432c 100644 (file)
@@ -5,11 +5,12 @@ namespaces make quotations assocs combinators classes.tuple
 classes.tuple.private effects summary hashtables classes generic
 sets definitions generic.standard slots.private continuations
 stack-checker.backend stack-checker.state stack-checker.visitor
-stack-checker.errors ;
+stack-checker.errors stack-checker.values
+stack-checker.recursive-state ;
 IN: stack-checker.transforms
 
 : give-up-transform ( word -- )
-    dup recursive-label
+    dup recursive-word?
     [ call-recursive-word ]
     [ dup infer-word apply-word/effect ]
     if ;
diff --git a/basis/stack-checker/values/values.factor b/basis/stack-checker/values/values.factor
new file mode 100644 (file)
index 0000000..97aa774
--- /dev/null
@@ -0,0 +1,52 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors namespaces kernel assocs sequences
+stack-checker.recursive-state ;
+IN: stack-checker.values
+
+! Values
+: <value> ( -- value ) \ <value> counter ;
+
+SYMBOL: known-values
+
+: init-known-values ( -- )
+    H{ } clone known-values set ;
+
+: known ( value -- known ) known-values get at ;
+
+: set-known ( known value -- )
+    over [ known-values get set-at ] [ 2drop ] if ;
+
+: make-known ( known -- value )
+    <value> [ set-known ] keep ;
+
+: copy-value ( value -- value' )
+    known make-known ;
+
+: copy-values ( values -- values' )
+    [ copy-value ] map ;
+
+! Literal value
+TUPLE: literal < identity-tuple value recursion hashcode ;
+
+M: literal hashcode* nip hashcode>> ;
+
+: <literal> ( obj -- value )
+    recursive-state get over hashcode \ literal boa ;
+
+GENERIC: (literal) ( value -- literal )
+
+M: literal (literal) ;
+
+: literal ( value -- literal )
+    known (literal) ;
+
+! Result of curry
+TUPLE: curried obj quot ;
+
+C: <curried> curried
+
+! Result of compose
+TUPLE: composed quot1 quot2 ;
+
+C: <composed> composed
index a24d8e226d02fdb03f717b0e4ed39b517846022a..5f05d97d1a4d1970f3eb75c736f61df467c77a28 100644 (file)
@@ -8,7 +8,7 @@ M: f #introduce, drop ;
 M: f #call, 3drop ;
 M: f #call-recursive, 3drop ;
 M: f #push, 2drop ;
-M: f #shuffle, 3drop ;
+M: f #shuffle, 2drop 2drop drop ;
 M: f #>r, 2drop ;
 M: f #r>, 2drop ;
 M: f #return, drop ;
index 7d8ec90453024070d5b4596a5c9f2aebaab513df..6093cd008af0d077157283e51eae0bb6903cfc1e 100644 (file)
@@ -13,7 +13,7 @@ HOOK: #introduce, stack-visitor ( values -- )
 HOOK: #call, stack-visitor ( inputs outputs word -- )
 HOOK: #call-recursive, stack-visitor ( inputs outputs word -- )
 HOOK: #push, stack-visitor ( literal value -- )
-HOOK: #shuffle, stack-visitor ( inputs outputs mapping -- )
+HOOK: #shuffle, stack-visitor ( in-d out-d in-r out-r mapping -- )
 HOOK: #drop, stack-visitor ( values -- )
 HOOK: #>r, stack-visitor ( inputs outputs -- )
 HOOK: #r>, stack-visitor ( inputs outputs -- )
diff --git a/basis/suffix-arrays/authors.txt b/basis/suffix-arrays/authors.txt
new file mode 100755 (executable)
index 0000000..e4a36df
--- /dev/null
@@ -0,0 +1 @@
+Marc Fauconneau
\ No newline at end of file
diff --git a/basis/suffix-arrays/suffix-arrays-docs.factor b/basis/suffix-arrays/suffix-arrays-docs.factor
new file mode 100755 (executable)
index 0000000..87df272
--- /dev/null
@@ -0,0 +1,45 @@
+! Copyright (C) 2008 Marc Fauconneau.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays help.markup help.syntax io.streams.string
+sequences strings math suffix-arrays.private ;
+IN: suffix-arrays
+
+HELP: >suffix-array
+{ $values
+     { "seq" sequence }
+     { "array" array } }
+{ $description "Creates a suffix array from the input sequence.  Suffix arrays are arrays of slices." } ;
+
+HELP: SA{
+{ $description "Creates a new literal suffix array at parse-time." } ;
+
+HELP: suffixes
+{ $values
+     { "string" string }
+     { "suffixes-seq" "a sequence of slices" } }
+{ $description "Returns a sequence of tail slices of the input string." } ;
+
+HELP: from-to
+{ $values
+     { "index" integer } { "begin" sequence } { "suffix-array" "a suffix-array" }
+     { "from/f" "an integer or f" } { "to/f" "an integer or f" } }
+{ $description "Finds the bounds of the suffix array that match the input sequence. A return value of " { $link f } " means that the endpoint is included." }
+{ $notes "Slices are [m,n) and we want (m,n) so we increment." } ;
+
+HELP: query
+{ $values
+     { "begin" sequence } { "suffix-array" "a suffix-array" }
+     { "matches" array } }
+{ $description "Returns a sequence of sequences from the suffix-array that contain the input sequence. An empty array is returned when there are no matches." } ;
+
+ARTICLE: "suffix-arrays" "Suffix arrays"
+"The " { $vocab-link "suffix-arrays" } " vocabulary implements the suffix array data structure for efficient lookup of subsequences. This suffix array implementation is a sorted array of suffixes. Querying it for matches uses binary search for efficiency." $nl
+
+"Creating new suffix arrays:"
+{ $subsection >suffix-array }
+"Literal suffix arrays:"
+{ $subsection POSTPONE: SA{ }
+"Querying suffix arrays:"
+{ $subsection query } ;
+
+ABOUT: "suffix-arrays"
diff --git a/basis/suffix-arrays/suffix-arrays-tests.factor b/basis/suffix-arrays/suffix-arrays-tests.factor
new file mode 100755 (executable)
index 0000000..5149804
--- /dev/null
@@ -0,0 +1,38 @@
+! Copyright (C) 2008 Marc Fauconneau.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test suffix-arrays kernel namespaces sequences ;
+IN: suffix-arrays.tests
+
+! built from [ all-words 10 head [ name>> ] map ]
+[ ] [ 
+     {
+        "run-tests"
+        "must-fail-with"
+        "test-all"
+        "short-effect"
+        "failure"
+        "test"
+        "<failure>"
+        "this-test"
+        "(unit-test)"
+        "unit-test"
+    } >suffix-array "suffix-array" set
+] unit-test
+
+[ t ]
+[ "suffix-array" get "" swap query empty? not ] unit-test
+
+[ { } ]
+[ SA{ } "something" swap query ] unit-test
+
+[ V{ "unit-test" "(unit-test)" } ]
+[ "suffix-array" get "unit-test" swap query ] unit-test
+
+[ t ]
+[ "suffix-array" get "something else" swap query empty? ] unit-test
+
+[ V{ "rofl" } ] [ SA{ "rofl" } "r" swap query ] unit-test
+[ V{ "rofl" } ] [ SA{ "rofl" } "o" swap query ] unit-test
+[ V{ "rofl" } ] [ SA{ "rofl" } "f" swap query ] unit-test
+[ V{ "rofl" } ] [ SA{ "rofl" } "l" swap query ] unit-test
+[ V{ } ] [ SA{ "rofl" } "t" swap query ] unit-test
diff --git a/basis/suffix-arrays/suffix-arrays.factor b/basis/suffix-arrays/suffix-arrays.factor
new file mode 100755 (executable)
index 0000000..fa68cc0
--- /dev/null
@@ -0,0 +1,40 @@
+! Copyright (C) 2008 Marc Fauconneau.
+! See http://factorcode.org/license.txt for BSD license.
+USING: parser kernel arrays math accessors sequences
+math.vectors math.order sorting binary-search sets assocs fry ;
+IN: suffix-arrays
+
+<PRIVATE
+
+: suffixes ( string -- suffixes-seq )
+    dup length [ tail-slice ] with map ;
+
+: prefix<=> ( begin seq -- <=> )
+    [ <=> ] [ swap head? ] 2bi [ drop +eq+ ] when ;
+: find-index ( begin suffix-array -- index/f )
+    [ prefix<=> ] with search drop ;
+
+: from-to ( index begin suffix-array -- from/f to/f )
+    swap '[ _ head? not ]
+    [ find-last-from drop dup [ 1+ ] when ]
+    [ find-from drop ] 3bi ;
+
+: <funky-slice> ( from/f to/f seq -- slice )
+    [
+        tuck
+        [ drop 0 or ] [ length or ] 2bi*
+        [ min ] keep
+    ] keep <slice> ; inline
+
+PRIVATE>
+
+: >suffix-array ( seq -- array )
+    [ suffixes ] map concat natural-sort ;
+
+: SA{ \ } [ >suffix-array ] parse-literal ; parsing
+
+: query ( begin suffix-array -- matches )
+    2dup find-index dup
+    [ -rot [ from-to ] keep <funky-slice> [ seq>> ] map prune ]
+    [ 3drop { } ] if ;
diff --git a/basis/suffix-arrays/summary.txt b/basis/suffix-arrays/summary.txt
new file mode 100755 (executable)
index 0000000..71eda47
--- /dev/null
@@ -0,0 +1 @@
+Suffix arrays
diff --git a/basis/suffix-arrays/tags.txt b/basis/suffix-arrays/tags.txt
new file mode 100755 (executable)
index 0000000..42d711b
--- /dev/null
@@ -0,0 +1 @@
+collections
diff --git a/basis/suffix-arrays/words/words.factor b/basis/suffix-arrays/words/words.factor
new file mode 100755 (executable)
index 0000000..74e2fc2
--- /dev/null
@@ -0,0 +1,19 @@
+! Copyright (C) 2008 Marc Fauconneau.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+USING: kernel arrays math accessors sequences math.vectors\r
+math.order sorting binary-search sets assocs fry suffix-arrays ;\r
+IN: suffix-arrays.words\r
+\r
+! to search on word names\r
+\r
+: new-word-sa ( words -- sa )\r
+    [ name>> ] map >suffix-array ;\r
+\r
+: name>word-map ( words -- map )\r
+    dup [ name>> V{ } clone ] H{ } map>assoc\r
+    [ '[ dup name>> _ at push ] each ] keep ;\r
+\r
+: query-word-sa ( map begin sa -- matches ) query '[ _ at ] map concat ;\r
+\r
+! usage example :\r
+! clear all-words 100 head dup name>word-map "test" rot new-word-sa query .\r
index 3c4715d3e3de43833030f4e0da20a7b4bba28db0..471cd2bd34f5eaace074a3fbd9ccaddddf385b7d 100644 (file)
@@ -1,5 +1,5 @@
 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 ;
 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) } "." } ;
 
 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."
 $nl
 "By convention, threads are queued with " { $link push-front } 
@@ -129,7 +129,7 @@ HELP: interrupt
 { $description "Interrupts a sleeping thread." } ;
 
 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."
 $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 } "."
@@ -149,7 +149,7 @@ $nl
 } ;
 
 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 } "." }
 { $examples
     "A thread that runs forever:"
@@ -172,5 +172,5 @@ HELP: tset
 { $description "Sets the value of a thread-local variable." } ;
 
 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." } ;
index f0a3235e62ec6d2dd3ea39892c4e8ff0381e3914..c61b4547a94a0226e6184d10080a08ffdb872433 100644 (file)
@@ -13,7 +13,7 @@ ARTICLE: "tools.annotations" "Word annotations"
 ABOUT: "tools.annotations"
 
 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." }
 { $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." } ;
 
 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." } ;
 
 HELP: annotate-methods
diff --git a/basis/tools/hexdump/authors.txt b/basis/tools/hexdump/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/tools/hexdump/hexdump-docs.factor b/basis/tools/hexdump/hexdump-docs.factor
new file mode 100644 (file)
index 0000000..9579fb7
--- /dev/null
@@ -0,0 +1,22 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel sequences strings ;
+IN: tools.hexdump
+
+HELP: hexdump.
+{ $values { "seq" sequence } }
+{ $description "Converts a sequence to its hexadecimal and ASCII representation sixteen characters at a time and writes it to standard out." } ;
+
+HELP: hexdump
+{ $values { "seq" sequence } { "str" string } }
+{ $description "Converts a sequence to its hexadecimal and ASCII representation sixteen characters at a time.  Lines are separated by a newline character." }
+{ $see-also hexdump. } ;
+
+ARTICLE: "tools.hexdump" "Hexdump"
+"The " { $vocab-link "tools.hexdump" } " vocabulary provides a traditional hexdump view of a sequence." $nl
+"Write hexdump to string:"
+{ $subsection hexdump }
+"Write the hexdump to the output stream:"
+{ $subsection hexdump. } ;
+
+ABOUT: "tools.hexdump"
diff --git a/basis/tools/hexdump/hexdump-tests.factor b/basis/tools/hexdump/hexdump-tests.factor
new file mode 100644 (file)
index 0000000..7202e44
--- /dev/null
@@ -0,0 +1,11 @@
+USING: tools.hexdump kernel sequences tools.test ;
+IN: tools.hexdump.tests
+
+[ t ] [ "" hexdump "Length: 0, 0h\n" = ] unit-test
+[ t ] [ "abcdefghijklmnopqrstuvwxyz" hexdump "Length: 26, 1ah\n00000000h: 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 abcdefghijklmnop\n00000010h: 71 72 73 74 75 76 77 78 79 7a                   qrstuvwxyz\n" = ] unit-test
+
+[ t ] [ 256 [ ] map hexdump "Length: 256, 100h\n00000000h: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n00000010h: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................\n00000020h: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f  !\"#$%&'()*+,-./\n00000030h: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?\n00000040h: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO\n00000050h: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\\]^_\n00000060h: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno\n00000070h: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.\n00000080h: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ................\n00000090h: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ................\n000000a0h: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ................\n000000b0h: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ................\n000000c0h: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ................\n000000d0h: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ................\n000000e0h: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ................\n000000f0h: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ................\n" = ] unit-test
+
+
+[
+    "Length: 3, 3h\n00000000h: 01 02 03                                        ...\n" ] [ B{ 1 2 3 } hexdump ] unit-test
diff --git a/basis/tools/hexdump/hexdump.factor b/basis/tools/hexdump/hexdump.factor
new file mode 100644 (file)
index 0000000..c8b9f4a
--- /dev/null
@@ -0,0 +1,36 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays io io.streams.string kernel math math.parser
+namespaces sequences splitting grouping strings ascii ;
+IN: tools.hexdump
+
+<PRIVATE
+
+: write-header ( len -- )
+    "Length: " write
+    [ number>string write ", " write ]
+    [ >hex write "h" write nl ] bi ;
+
+: write-offset ( lineno -- )
+    16 * >hex 8 CHAR: 0 pad-left write "h: " write ;
+
+: >hex-digit ( digit -- str )
+    >hex 2 CHAR: 0 pad-left " " append ;
+
+: >hex-digits ( bytes -- str )
+    [ >hex-digit ] { } map-as concat 48 CHAR: \s pad-right ;
+
+: >ascii ( bytes -- str )
+    [ [ printable? ] keep CHAR: . ? ] "" map-as ;
+
+: write-hex-line ( bytes lineno -- )
+    write-offset [ >hex-digits write ] [ >ascii write ] bi nl ;
+
+PRIVATE>
+
+: hexdump. ( seq -- )
+    [ length write-header ]
+    [ 16 <sliced-groups> [ write-hex-line ] each-index ] bi ;
+
+: hexdump ( seq -- str )
+    [ hexdump. ] with-string-writer ;
diff --git a/basis/tools/hexdump/summary.txt b/basis/tools/hexdump/summary.txt
new file mode 100644 (file)
index 0000000..d860bd7
--- /dev/null
@@ -0,0 +1 @@
+Prints formatted hex dump of an arbitrary sequence
index 75ca5ede8c4060f9c6bcf63714d4d8ef2546880a..f0c71aa311d68f579061511ade1fa7db4bda38c5 100644 (file)
@@ -1,6 +1,7 @@
 IN: tools.profiler.tests
 USING: accessors tools.profiler tools.test kernel memory math
-threads alien tools.profiler.private sequences compiler.units ;
+threads alien tools.profiler.private sequences compiler.units
+words ;
 
 [ t ] [
     \ length counter>>
@@ -54,3 +55,7 @@ threads alien tools.profiler.private sequences compiler.units ;
 ] unit-test
 
 [ 666 ] [ \ recompile-while-profiling-test counter>> ] unit-test
+
+[ ] [ [ [ ] compile-call ] profile ] unit-test
+
+[ [ gensym execute ] profile ] [ T{ undefined } = ] must-fail-with
index e1076775face5135c04c6a7397d81ff2b8fc19de..281180126695f6abf69bfb0d639fb87666c7c6ee 100644 (file)
@@ -263,3 +263,12 @@ SYMBOL: examples-flag
         [ example ] times
         "}" print
     ] with-variable ;
+
+: scaffold-rc ( path -- )
+    [ touch-file ] [ "Click to edit: " write <pathname> . ] bi ;
+
+: scaffold-factor-boot-rc ( -- )
+    home ".factor-boot-rc" append-path scaffold-rc ;
+
+: scaffold-factor-rc ( -- )
+    home ".factor-rc" append-path scaffold-rc ;
index 02c0ad126df6f240feee713e40e58381ab485f5f..f19ffb83a48fef4a78bbc454ead25de32be69b8c 100644 (file)
@@ -60,7 +60,7 @@ HELP: must-fail
 { $notes "This word is used to test boundary conditions and fail-fast behavior." } ;
 
 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." }
 { $notes "This word is used to test error handling code, ensuring that errors thrown by code contain the relevant debugging information." } ;
 
index 25312ad868c1bcac88b343fa410cae5664a4485f..5f1ff6dabd71dcce0e8d676d1cd657d97628671d 100644 (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." } ;
 
 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." }
 { $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
@@ -82,7 +82,7 @@ HELP: commands
 { $description "Outputs a hashtable mapping command map names to " { $link command-map } " instances." } ;
 
 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
     "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 } "."
 }
index c4edaac144c6a1e463bf6ff302c1a0ceb34797f9..4a428404c1bb65e1fe5893ac16ee578dd275778c 100644 (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." } ;
 
 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." } ;
 
 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." } ;
 
 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 } "." } ;
 
 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." } ;
 
 HELP: button-paint
index b691668206a112493dff959ab2546f31e481857b..0cf60ff5e8848a9715d9af72bb765daf69363a09 100644 (file)
@@ -41,7 +41,7 @@ HELP: editor-mark*
 { $description "Outputs the current mark location as a line/column number pair." } ;
 
 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." } ;
 
 { 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." } ;
 
 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." } ;
 
 HELP: point>loc
index 394841c5995572db9cd36eb10108c1e849215b50..169f97f0b95e51cbaea4c47f8f9c0e6000824a89 100644 (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." } ;
 
 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." } ;
 
 HELP: max-dim
@@ -44,7 +44,7 @@ HELP: max-dim
 { pref-dims max-dim dim-sum } related-words
 
 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." } ;
 
 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 } "." } ;
 
 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." } ;
 
 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." } ;
 
 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." } ;
 
 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." } ;
 
 HELP: screen-loc
index 877d4ad145ee0a1a29ed8ad83d3cbb33837c78e5..01d695c28194fd88855959a6cd380f575b880dea 100644 (file)
@@ -138,7 +138,7 @@ M: mock-gadget ungraft*
             [ V{ { f t } } ] [ status-flags ] unit-test
             dup [ [ ] [ notify-queued ] unit-test ] when
             [ ] [ "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
             [ ] [ add-some-children ] unit-test
             [ { f t } ] [ "1" get graft-state>> ] unit-test
index f09bcaa8259cc84d0c90a6b580f99fe8f1f79b47..4ad14abfd175b2def24e982247ce73e00e253287 100644 (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> } "." } ;
 
 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" } "." }
 { $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>
-{ $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 } "." } ;
 
 { <labelled-pane> <pane-control> } related-words
index b698d558adc2472adde76e79b63d8b6ff053dd1b..6341e0950586dc6df0334ee0a868363bc61ecabe 100644 (file)
@@ -14,7 +14,7 @@ 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 } "."
 $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." } ;
index 505eb2231f9f6724f192437bdce21d7120bd8402..303eb0a13ea60b77dbdad49fc1bb86e4adfa9b5a 100644 (file)
@@ -3,7 +3,7 @@ kernel ;
 IN: ui.gadgets.menus
 
 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." } ;
 
 HELP: show-menu
index 99f8b2e82ac1cabcee12f082852d19e164c10177..d53cba5f76516f47d224666f1dba0ca57c560ed8 100644 (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." } ;
 
 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 } "." } ;
 
 HELP: pane-stream
index 3554c735a7711a069c1e68010533a301d0efaa5d..b248527c37db4629c2f8bab8c3a7a4ddf143bc78 100644 (file)
@@ -8,7 +8,7 @@ $nl
 "Scroller gadgets are created by calling " { $link <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 } "." } ;
 
 HELP: scroller-value
index 63284f135d6f7f4e9a1d7c180f5d0011b89adb13..c130c724d0eef790829c7ecee21eb6698d03d2de 100644 (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." } ;
 
 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 } "." } ;
 
 HELP: slider
@@ -14,7 +14,7 @@ $nl
 "Sliders are created by calling " { $link <x-slider> } " or " { $link <y-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 } "." } ;
 
 HELP: thumb
index 122d14eed7f4e29e201afbba4e9aab08d4d02ae1..9dd152885e2ba09d308962dda108f6d3b8ff851c 100644 (file)
@@ -46,7 +46,7 @@ HELP: <world>
 { $description "Creates a new " { $link world } " delegating to the given gadget." } ;
 
 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." } ;
 
 HELP: draw-world
index 0575ff17f04e7f00235e58fc27f054adf02fd110..3471bd2cdb21a47319960fcf1d314dd0333e706c 100644 (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." } ;
 
 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." }
 { $examples
     { $example "USING: io ui.gestures ;" "T{ key-down f { C+ } \"x\" } gesture>string print" "C+x" }
index ebdf3eee1f876d1c22ba6bfdac1229da09140996..d05519f46a499098b486f09951ed61d1cd77b726 100644 (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." } ;
 
 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." } ;
 
 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." } ;
 
 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:"
     { $list
         { { $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
-{ $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." } ;
 
 HELP: $operations
index b57dafaf49ff46ca1f87610bad75358760ef9638..12a2e0d806177817904674a1b7b28e9e1080ab8c 100644 (file)
@@ -3,7 +3,7 @@ continuations debugger ui ;
 IN: ui.tools.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
     "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."
 } ;
index d8c816d71750a76fb8954e783adece8ba573244e..58509fc2df78c8fc13f3a49f677ed9feac4a877b 100644 (file)
@@ -23,7 +23,7 @@ HELP: fullscreen?
 { fullscreen? set-fullscreen? } related-words
 
 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." } ;
 
 HELP: register-window
diff --git a/basis/unrolled-lists/unrolled-lists-docs.factor b/basis/unrolled-lists/unrolled-lists-docs.factor
new file mode 100644 (file)
index 0000000..387bb3d
--- /dev/null
@@ -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"
diff --git a/basis/unrolled-lists/unrolled-lists-tests.factor b/basis/unrolled-lists/unrolled-lists-tests.factor
new file mode 100644 (file)
index 0000000..89eb1cd
--- /dev/null
@@ -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
diff --git a/basis/unrolled-lists/unrolled-lists.factor b/basis/unrolled-lists/unrolled-lists.factor
new file mode 100644 (file)
index 0000000..d434632
--- /dev/null
@@ -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
index b423e6b751c9857a4d92f05ab553dedd93911ed7..ce8a7be88ccebd9bc3213fde2d9002370e9e5a50 100644 (file)
@@ -77,7 +77,7 @@ HELP: ensure-port
 } ;
 
 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 } "." }
 { $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
@@ -89,13 +89,13 @@ HELP: parse-host
 } ;
 
 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." } ;
 
 HELP: query-param
 { $values
      { "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." }
 { $examples
     { $example
index fc16c48ca01c27e565d012a1d202efb1e5146dfe..4f03fa915b8b53b2672bb5115cb624141af0361c 100644 (file)
@@ -1,5 +1,5 @@
 USING: help.markup help.syntax io.streams.string quotations 
-strings math parser-combinators.regexp ;
+strings math regexp regexp.backend ;
 IN: validators
 
 HELP: v-captcha
index 30e1eadc7a627607fc80dbc5a937ad083fdb4318..0ddced63e885e15bce8e8acb9e3ea05d0376df92 100644 (file)
@@ -1,9 +1,8 @@
 ! Copyright (C) 2006, 2008 Slava Pestov
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel continuations sequences math namespaces make sets
-math.parser math.ranges assocs parser-combinators.regexp
-unicode.categories arrays hashtables words classes quotations
-xmode.catalog ;
+math.parser math.ranges assocs regexp unicode.categories arrays
+hashtables words classes quotations xmode.catalog ;
 IN: validators
 
 : v-default ( str def -- str/def )
index c96ea0f8cfbdc5a0512d79eb1633ac4c9bd2ce23..69e2801110c81deb5fd3d2601b20f6f6f37919aa 100644 (file)
@@ -35,5 +35,5 @@ HELP: to:
 } ;\r
 \r
 HELP: change-value\r
-{ $values { "word" "a value word" } { "quot" "a quotation with stack effect " { $snippet "( oldvalue -- newvalue )" } } }\r
+{ $values { "word" "a value word" } { "quot" { $quotation "( oldvalue -- newvalue )" } } }\r
 { $description "Changes the value using the given quotation." } ;\r
diff --git a/basis/vlists/vlists-tests.factor b/basis/vlists/vlists-tests.factor
new file mode 100644 (file)
index 0000000..3546051
--- /dev/null
@@ -0,0 +1,41 @@
+USING: vlists kernel persistent.sequences arrays tools.test
+namespaces accessors sequences assocs ;
+IN: vlists.tests
+
+[ { "hi" "there" } ]
+[ VL{ } "hi" swap ppush "there" swap ppush >array ] unit-test
+
+[ VL{ "hi" "there" "foo" } VL{ "hi" "there" "bar" } t ]
+[
+    VL{ } "hi" swap ppush "there" swap ppush "v" set
+    "foo" "v" get ppush
+    "bar" "v" get ppush
+    dup "baz" over ppush [ vector>> ] bi@ eq?
+] unit-test
+
+[ "foo" VL{ "hi" "there" } t ]
+[
+    VL{ "hi" "there" "foo" } dup "v" set
+    [ peek ] [ ppop ] bi
+    dup "v" get [ vector>> ] bi@ eq?
+] unit-test
+
+[ VL{ } 3 over push ] must-fail
+
+[ 4 VL{ "hi" } set-first ] must-fail
+
+[ 5 t ] [
+    "rice" VA{ { "rice" 5 } { "beans" 10 } } at*
+] unit-test
+
+[ 6 t ] [
+    "rice" VA{ { "rice" 5 } { "beans" 10 } { "rice" 6 } } at*
+] unit-test
+
+[ 3 ] [
+    VA{ { "rice" 5 } { "beans" 10 } { "rice" 6 } } assoc-size
+] unit-test
+
+[ f f ] [
+    "meat" VA{ { "rice" 5 } { "beans" 10 } { "rice" 6 } } at*
+] unit-test
diff --git a/basis/vlists/vlists.factor b/basis/vlists/vlists.factor
new file mode 100644 (file)
index 0000000..e0f7e55
--- /dev/null
@@ -0,0 +1,93 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays accessors sequences sequences.private
+persistent.sequences assocs persistent.assocs kernel math
+vectors parser prettyprint.backend ;
+IN: vlists
+
+TUPLE: vlist
+{ length array-capacity read-only }
+{ vector vector read-only } ;
+
+: <vlist> ( -- vlist ) 0 V{ } clone vlist boa ; inline
+
+M: vlist length length>> ;
+
+M: vlist nth-unsafe vector>> nth-unsafe ;
+
+<PRIVATE
+
+: >vlist< [ length>> ] [ vector>> ] bi ; inline
+
+: unshare ( len vec -- len vec' )
+    clone [ set-length ] 2keep ; inline
+
+PRIVATE>
+
+M: vlist ppush
+    >vlist<
+    2dup length = [ unshare ] unless
+    [ [ 1+ swap ] dip push ] keep vlist boa ;
+
+ERROR: empty-vlist-error ;
+
+M: vlist ppop
+    [ empty-vlist-error ]
+    [ [ length>> 1- ] [ vector>> ] bi vlist boa ] if-empty ;
+
+M: vlist clone
+    [ length>> ] [ vector>> >vector ] bi vlist boa ;
+
+M: vlist equal?
+    over vlist? [ sequence= ] [ 2drop f ] if ;
+
+: >vlist ( seq -- vlist )
+    [ length ] [ >vector ] bi vlist boa ; inline
+
+M: vlist like
+    drop dup vlist? [ >vlist ] unless ;
+
+INSTANCE: vlist immutable-sequence
+
+: VL{ \ } [ >vlist ] parse-literal ; parsing
+
+M: vlist pprint-delims drop \ VL{ \ } ;
+M: vlist >pprint-sequence ;
+M: vlist pprint* pprint-object ;
+
+TUPLE: valist { vlist vlist read-only } ;
+
+: <valist> ( -- valist ) <vlist> valist boa ; inline
+
+M: valist assoc-size vlist>> length 2/ ;
+
+: valist-at ( key i array -- value ? )
+    over 0 >= [
+        3dup nth-unsafe = [
+            [ 1+ ] dip nth-unsafe nip t
+        ] [
+            [ 2 - ] dip valist-at
+        ] if
+    ] [ 3drop f f ] if ; inline recursive
+
+M: valist at*
+    vlist>> >vlist< [ 2 - ] [ underlying>> ] bi* valist-at ;
+
+M: valist new-at
+    vlist>> ppush ppush valist boa ;
+
+M: valist >alist vlist>> ;
+
+: >valist ( assoc -- valist )
+    >alist concat >vlist valist boa ; inline
+
+M: valist assoc-like
+    drop dup valist? [ >valist ] unless ;
+
+INSTANCE: valist assoc
+
+: VA{ \ } [ >valist ] parse-literal ; parsing
+
+M: valist pprint-delims drop \ VA{ \ } ;
+M: valist >pprint-sequence >alist ;
+M: valist pprint* pprint-object ;
index 6a2ff1109ec67c8cc076dafa8ee7f15cac06a2af..248a43ed6347fed72fb2d7213ccf78d5cd6e674f 100644 (file)
@@ -460,10 +460,8 @@ ARTICLE: { "xml" "entities" } "XML entities"
     { $subsection with-entities }\r
     { $subsection with-html-entities } ;\r
 \r
-ARTICLE: { "xml" "intro" } "XML"\r
-    "The XML module attempts to implement the XML 1.1 standard, converting strings of text into XML and vice versa. It currently is a work in progress."\r
-    $nl\r
-    "The XML module was implemented by Daniel Ehrenberg, with contributions from the Factor community"\r
+ARTICLE: "xml" "XML parser"\r
+"The " { $vocab-link "xml" } " vocabulary implements the XML 1.1 standard, converting strings of text into XML and vice versa."\r
     { $subsection { "xml" "reading" } }\r
     { $subsection { "xml" "writing" } }\r
     { $subsection { "xml" "classes" } }\r
@@ -476,4 +474,4 @@ ARTICLE: { "xml" "intro" } "XML"
 \r
 IN: xml\r
 \r
-ABOUT: { "xml" "intro" }\r
+ABOUT: "xml"\r
index f969b208ebaf2d9f22af134584b94f9ba292c657..b02e0189b2f2d2c792880e05ec6b02a110f7fce0 100644 (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." } ;
 
 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." } ;
 
 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* } "." } ;
 
 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." }
 { $examples
     { $example
@@ -209,7 +209,7 @@ HELP: assoc-each
 } ;
 
 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." }
 { $examples
     { $unchecked-example
@@ -224,19 +224,19 @@ HELP: assoc-map
 { assoc-map assoc-map-as } related-words
 
 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" } "." } ;
 
 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." } ;
 
 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." } ;
 
 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 } "." } ;
 
 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." } ;
 
 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." }
 { $side-effects "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" } "." } ;
 
 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." } ;
 
 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." }
 { $side-effects "assoc" } ;
 
index d457d6805e5371a2c1e8902a512886ac4a7f5c2c..9a100d9795a36442696f1638c90574c25c0aa32e 100644 (file)
@@ -1,5 +1,6 @@
 IN: byte-vectors.tests\r
-USING: tools.test byte-vectors vectors sequences kernel ;\r
+USING: tools.test byte-vectors vectors sequences kernel\r
+prettyprint ;\r
 \r
 [ 0 ] [ 123 <byte-vector> length ] unit-test\r
 \r
@@ -12,3 +13,5 @@ USING: tools.test byte-vectors vectors sequences kernel ;
 ] unit-test\r
 \r
 [ t ] [ BV{ } byte-vector? ] unit-test\r
+\r
+[ "BV{ }" ] [ BV{ } unparse ] unit-test\r
index d03d97cd4c6d4018a71bc471871225d0a1f6bd89..3ea0a24674b457af0822642ed986dbff1be34c6a 100644 (file)
@@ -14,7 +14,7 @@ ARTICLE: "predicates" "Predicate classes"
 ABOUT: "predicates"
 
 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: } "." }
 { $notes "This word must be called from inside " { $link with-compilation-unit } "." }
 { $side-effects "class" } ;
index a494c09b05097ba9b6aaa48b3315347da46812fb..0caabf2fad7104a487db3c5fb3fadcb29a26662e 100644 (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." } ;
 
 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." } ;
 
 HELP: cond>quot
@@ -159,7 +159,7 @@ $nl
 } } ;
 
 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." }
 { $notes "This word is used in the implemention of " { $link hash-case-quot } " and " { $link standard-combination } "." } ;
 
index 577dd153a12a2f6e4e64305944a4340a349aef34..8cfa671a8b2ef4b2a8dcd106dc48bce09863a9af 100644 (file)
@@ -167,6 +167,6 @@ M: slice hashcode* [ sequence-hashcode ] recursive-hashcode ;
 
 M: hashtable hashcode*
     [
-        dup assoc-size 1 number=
+        dup assoc-size 1 eq?
         [ assoc-hashcode ] [ nip assoc-size ] if
     ] recursive-hashcode ;
index f5ebc2a3389f3145da505e5d918baa3a1c1acb8d..7a22306c50279368a336ddc5a1ede247648113a4 100644 (file)
@@ -108,17 +108,17 @@ HELP: >continuation<
 { $description "Takes a continuation apart into its constituents." } ;
 
 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." } ;
 
 { callcc0 continue callcc1 continue-with ifcc } related-words
 
 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." } ;
 
 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." } ;
 
 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." } ;
 
 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." } ;
 
 HELP: ignore-errors
index c82f92dc102817117472b25dc179dc3d5140e463..0b6ca15f3185ba019fd1de6ce5bf93a2494970a4 100644 (file)
@@ -21,7 +21,7 @@ HELP: dispose*
 } ;
 
 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." } ;
 
 HELP: with-destructors
index f9c18e410da12ebc3f52a5727ec4595e73ae8134..b209dcf259eaf149b1a1bcc52074200cdbb48842 100644 (file)
@@ -68,5 +68,5 @@ HELP: effect>string
 } ;
 
 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" } "." } ;
index 396b3e8f9a7cfa1ea48a380a8ed897733ac2a793..b5f22ec1207a81e7d6a3dcf81ff54dab4d3689bf 100644 (file)
@@ -127,7 +127,7 @@ HELP: method-body
 { $class-description "The class of method bodies, which are words with special word properties set." } ;
 
 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." } ;
 
 { 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." } ;
 
 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." }
 $low-level-note ;
 
index cb5f9f37919625e24f90fe44496021964e599c56..e2818a51b21958db220c5230e9c94a9106f774d1 100644 (file)
@@ -76,9 +76,6 @@ TUPLE: check-method class generic ;
 PREDICATE: method-body < word
     "method-generic" word-prop >boolean ;
 
-M: method-body inline?
-    "method-generic" word-prop inline? ;
-
 M: method-body stack-effect
     "method-generic" word-prop stack-effect ;
 
index b0201f3248679e1fa6b8c72e06e9df566711f71d..da5d4f9eedd40e0629aff10eef96a08249d89a04 100644 (file)
@@ -3,7 +3,7 @@ sequences quotations ;
 IN: generic.math
 
 HELP: math-upgrade
-{ $values { "class1" class } { "class2" class } { "quot" "a quotation with stack effect " { $snippet "( n n -- n n )" } } }
+{ $values { "class1" class } { "class2" class } { "quot" { $quotation "( n n -- n n )" } } }
 { $description "Outputs a quotation for upgrading numberical types. It takes two numbers on the stack, an instance of " { $snippet "class1" } ", and an instance of " { $snippet "class2" } ", and converts the one with the lower priority to the higher priority type." }
 { $examples { $example "USING: generic.math math kernel prettyprint ;" "fixnum bignum math-upgrade ." "[ [ >bignum ] dip ]" } } ;
 
index 077795c4b786a8101e0a67954a807412720af8eb..ebe1c08cb3d1e426018736f739c0ffd3fb953c63 100644 (file)
@@ -3,7 +3,7 @@
 USING: arrays generic hashtables kernel kernel.private math
 namespaces make sequences words quotations layouts combinators
 sequences.private classes classes.builtin classes.algebra
-definitions math.order ;
+definitions math.order math.private ;
 IN: generic.math
 
 PREDICATE: math-class < class
@@ -62,13 +62,17 @@ ERROR: no-math-method left right generic ;
         2drop object-method
     ] if ;
 
+SYMBOL: picker
+
 : math-vtable ( picker quot -- quot )
     [
-        >r
-        , \ tag ,
-        num-tags get [ bootstrap-type>class ]
-        r> compose map ,
-        \ dispatch ,
+        swap picker set
+        picker get , [ tag 0 eq? ] %
+        num-tags get swap [ bootstrap-type>class ] prepose map
+        unclip ,
+        [
+            picker get , [ tag 1 fixnum-fast ] % , \ dispatch ,
+        ] [ ] make , \ if ,
     ] [ ] make ; inline
 
 TUPLE: math-combination ;
@@ -85,8 +89,7 @@ M: math-combination perform-combination
         ] [
             over object-method
         ] if nip
-    ] math-vtable nip
-    define ;
+    ] math-vtable nip define ;
 
 PREDICATE: math-generic < generic ( word -- ? )
     "combination" word-prop math-combination? ;
index 87e2f1c9b1c35774428570b0d33d4ca3e569a0c6..d1bc6d7417d883e8518f21225d884f7e407f2b72 100644 (file)
@@ -22,13 +22,14 @@ C: <lo-tag-dispatch-engine> lo-tag-dispatch-engine
         "type" word-prop
     ] if ;
 
+: sort-tags ( assoc -- alist ) >alist sort-keys reverse ;
+
 M: lo-tag-dispatch-engine engine>quot
     methods>> engines>quots*
     [ >r lo-tag-number r> ] assoc-map
     [
         picker % [ tag ] % [
-            >alist sort-keys reverse
-            linear-dispatch-quot
+            sort-tags linear-dispatch-quot
         ] [
             num-tags get direct-dispatch-quot
         ] if-small? %
@@ -51,10 +52,11 @@ C: <hi-tag-dispatch-engine> hi-tag-dispatch-engine
     \ hi-tag def>> ;
 
 M: hi-tag-dispatch-engine engine>quot
-    methods>> engines>quots* [ >r hi-tag-number r> ] assoc-map
+    methods>> engines>quots*
+    [ >r hi-tag-number r> ] assoc-map
     [
         picker % hi-tag-quot % [
-            linear-dispatch-quot
+            sort-tags linear-dispatch-quot
         ] [
             num-tags get , \ fixnum-fast ,
             [ >r num-tags get - r> ] assoc-map
index 04368099fb54b055aaa1fc49d7c544a8570079ce..78a97547fdd7619e857d6b3cb4fa058d56dff858 100644 (file)
@@ -79,9 +79,6 @@ M: engine-word stack-effect
     [ extra-values ] [ stack-effect ] bi
     dup [ clone [ length + ] change-in ] [ 2drop f ] if ;
 
-M: engine-word inline?
-    "tuple-dispatch-generic" word-prop inline? ;
-
 M: engine-word crossref? "forgotten" word-prop not ;
 
 M: engine-word irrelevant? drop t ;
diff --git a/core/grouping/authors.txt b/core/grouping/authors.txt
deleted file mode 100644 (file)
index 1901f27..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Slava Pestov
diff --git a/core/grouping/grouping-docs.factor b/core/grouping/grouping-docs.factor
deleted file mode 100644 (file)
index 3b3a98e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-USING: help.markup help.syntax sequences strings ;
-IN: grouping
-
-ARTICLE: "grouping" "Groups and clumps"
-"Splitting a sequence into disjoint, fixed-length subsequences:"
-{ $subsection group }
-"A virtual sequence for splitting a sequence into disjoint, fixed-length subsequences:"
-{ $subsection groups }
-{ $subsection <groups> }
-{ $subsection <sliced-groups> }
-"Splitting a sequence into overlapping, fixed-length subsequences:"
-{ $subsection clump }
-"A virtual sequence for splitting a sequence into overlapping, fixed-length subsequences:"
-{ $subsection clumps }
-{ $subsection <clumps> }
-{ $subsection <sliced-clumps> }
-"The difference can be summarized as the following:"
-{ $list
-    { "With groups, the subsequences form the original sequence when concatenated:"
-        { $unchecked-example "dup n groups concat sequence= ." "t" }
-    }
-    { "With clumps, collecting the first element of each subsequence but the last one, together with the last subseqence, yields the original sequence:"
-        { $unchecked-example "dup n clumps unclip-last >r [ first ] map r> append sequence= ." "t" }
-    }
-} ;
-
-ABOUT: "grouping"
-
-HELP: groups
-{ $class-description "Instances are virtual sequences whose elements are disjoint fixed-length subsequences of an underlying sequence. Groups are mutable and resizable if the underlying sequence is mutable and resizable, respectively."
-$nl
-"New groups are created by calling " { $link <groups> } " and " { $link <sliced-groups> } "." }
-{ $see-also group } ;
-
-HELP: group
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
-{ $description "Splits the sequence into disjoint groups of " { $snippet "n" } " elements and collects the groups into a new array." }
-{ $notes "If the sequence length is not a multiple of " { $snippet "n" } ", the final subsequence in the list will be shorter than " { $snippet "n" } " elements." }
-{ $examples
-    { $example "USING: grouping prettyprint ;" "{ 3 1 3 3 7 } 2 group ." "{ { 3 1 } { 3 3 } { 7 } }" }
-} ;
-
-HELP: <groups>
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "groups" groups } }
-{ $description "Outputs a virtual sequence whose elements are disjoint subsequences of " { $snippet "n" } " elements from the underlying sequence." }
-{ $examples
-    { $example
-        "USING: arrays kernel prettyprint sequences grouping ;"
-        "9 >array 3 <groups> dup reverse-here concat >array ." "{ 6 7 8 3 4 5 0 1 2 }"
-    }
-} ;
-
-HELP: <sliced-groups>
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "groups" groups } }
-{ $description "Outputs a virtual sequence whose elements are overlapping subsequences of " { $snippet "n" } " elements from the underlying sequence." }
-{ $examples
-    { $example
-        "USING: arrays kernel prettyprint sequences grouping ;"
-        "9 >array 3 <sliced-groups>"
-        "dup [ reverse-here ] each concat >array ."
-        "{ 2 1 0 5 4 3 8 7 6 }"
-    }
-} ;
-
-HELP: clumps
-{ $class-description "Instances are virtual sequences whose elements are overlapping fixed-length subsequences o an underlying sequence. Clumps are mutable and resizable if the underlying sequence is mutable and resizable, respectively."
-$nl
-"New clumps are created by calling " { $link <clumps> } " and " { $link <sliced-clumps> } "." } ;
-
-HELP: clump
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
-{ $description "Splits the sequence into overlapping clumps of " { $snippet "n" } " elements and collects the clumps into a new array." }
-{ $errors "Throws an error if " { $snippet "n" } " is smaller than the length of the sequence." }
-{ $examples
-    { $example "USING: grouping prettyprint ;" "{ 3 1 3 3 7 } 2 clump ." "{ { 3 1 } { 1 3 } { 3 3 } { 3 7 } }" }
-} ;
-
-HELP: <clumps>
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "clumps" clumps } }
-{ $description "Outputs a virtual sequence whose elements are overlapping subsequences of " { $snippet "n" } " elements from the underlying sequence." }
-{ $examples
-    "Running averages:"
-    { $example
-        "USING: grouping sequences math prettyprint kernel ;"
-        "IN: scratchpad"
-        ": share-price"
-        "    { 13/50 51/100 13/50 1/10 4/5 17/20 33/50 3/25 19/100 3/100 } ;"
-        ""
-        "share-price 4 <clumps> [ [ sum ] [ length ] bi / ] map ."
-        "{ 113/400 167/400 201/400 241/400 243/400 91/200 1/4 }"
-    }
-} ;
-
-HELP: <sliced-clumps>
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "clumps" clumps } }
-{ $description "Outputs a virtual sequence whose elements are overlapping slices of " { $snippet "n" } " elements from the underlying sequence." } ;
-
-{ clumps groups } related-words
-
-{ clump group } related-words
-
-{ <clumps> <groups> } related-words
-
-{ <sliced-clumps> <sliced-groups> } related-words
diff --git a/core/grouping/grouping-tests.factor b/core/grouping/grouping-tests.factor
deleted file mode 100644 (file)
index dc3d970..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-USING: grouping tools.test kernel sequences arrays ;
-IN: grouping.tests
-
-[ { 1 2 3 } 0 group ] must-fail
-
-[ { "hell" "o wo" "rld" } ] [ "hello world" 4 group ] unit-test
-
-[ { V{ "a" "b" } V{ f f } } ] [
-    V{ "a" "b" } clone 2 <groups>
-    2 over set-length
-    >array
-] unit-test
-
-[ { { 1 2 } { 2 3 } } ] [ { 1 2 3 } 2 <sliced-clumps> [ >array ] map ] unit-test
diff --git a/core/grouping/grouping.factor b/core/grouping/grouping.factor
deleted file mode 100644 (file)
index 4a1b8c7..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-! Copyright (C) 2005, 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math math.order strings arrays vectors sequences
-sequences.private accessors ;
-IN: grouping
-
-<PRIVATE
-
-TUPLE: chunking-seq { seq read-only } { n read-only } ;
-
-: check-groups dup 0 <= [ "Invalid group count" throw ] when ; inline
-
-: new-groups ( seq n class -- groups )
-    >r check-groups r> boa ; inline
-
-GENERIC: group@ ( n groups -- from to seq )
-
-M: chunking-seq set-nth group@ <slice> 0 swap copy ;
-
-M: chunking-seq like drop { } like ;
-
-INSTANCE: chunking-seq sequence
-
-MIXIN: subseq-chunking
-
-M: subseq-chunking nth group@ subseq ;
-
-MIXIN: slice-chunking
-
-M: slice-chunking nth group@ <slice> ;
-
-M: slice-chunking nth-unsafe group@ slice boa ;
-
-TUPLE: abstract-groups < chunking-seq ;
-
-M: abstract-groups length
-    [ seq>> length ] [ n>> ] bi [ + 1- ] keep /i ;
-
-M: abstract-groups set-length
-    [ n>> * ] [ seq>> ] bi set-length ;
-
-M: abstract-groups group@
-    [ n>> [ * dup ] keep + ] [ seq>> ] bi [ length min ] keep ;
-
-TUPLE: abstract-clumps < chunking-seq ;
-
-M: abstract-clumps length
-    [ seq>> length ] [ n>> ] bi - 1+ ;
-
-M: abstract-clumps set-length
-    [ n>> + 1- ] [ seq>> ] bi set-length ;
-
-M: abstract-clumps group@
-    [ n>> over + ] [ seq>> ] bi ;
-
-PRIVATE>
-
-TUPLE: groups < abstract-groups ;
-
-: <groups> ( seq n -- groups )
-    groups new-groups ; inline
-
-INSTANCE: groups subseq-chunking
-
-TUPLE: sliced-groups < abstract-groups ;
-
-: <sliced-groups> ( seq n -- groups )
-    sliced-groups new-groups ; inline
-
-INSTANCE: sliced-groups slice-chunking
-
-TUPLE: clumps < abstract-clumps ;
-
-: <clumps> ( seq n -- clumps )
-    clumps new-groups ; inline
-
-INSTANCE: clumps subseq-chunking
-
-TUPLE: sliced-clumps < abstract-clumps ;
-
-: <sliced-clumps> ( seq n -- clumps )
-    sliced-clumps new-groups ; inline
-
-INSTANCE: sliced-clumps slice-chunking
-
-: group ( seq n -- array ) <groups> { } like ;
-
-: clump ( seq n -- array ) <clumps> { } like ;
diff --git a/core/grouping/summary.txt b/core/grouping/summary.txt
deleted file mode 100644 (file)
index 3695129..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Grouping sequence elements into subsequences
diff --git a/core/grouping/tags.txt b/core/grouping/tags.txt
deleted file mode 100644 (file)
index 42d711b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-collections
index 32fda7d2fb02a8d329f2a742a3a0f5c5618d19d5..0fde459a25b129dadba2b9c97d9b55165882cac1 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2005, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays kernel kernel.private slots.private math
-assocs math.private sequences sequences.private vectors grouping ;
+assocs math.private sequences sequences.private vectors ;
 IN: hashtables
 
 TUPLE: hashtable
@@ -128,15 +128,32 @@ M: hashtable set-at ( value key hash -- )
 : associate ( value key -- hash )
     2 <hashtable> [ set-at ] keep ;
 
+<PRIVATE
+
+: push-unsafe ( elt seq -- )
+    [ length ] keep
+    [ underlying>> set-array-nth ]
+    [ >r 1+ r> (>>length) ]
+    2bi ; inline
+
+PRIVATE>
+
 M: hashtable >alist
-    array>> 2 <groups> [ first tombstone? not ] filter ;
+    [ array>> [ length 2/ ] keep ] [ assoc-size <vector> ] bi [
+        [
+            >r
+            >r 1 fixnum-shift-fast r>
+            [ array-nth ] [ >r 1 fixnum+fast r> array-nth ] 2bi r>
+            pick tombstone? [ 3drop ] [ [ 2array ] dip push-unsafe ] if
+        ] 2curry each
+    ] keep { } like ;
 
 M: hashtable clone
     (clone) [ clone ] change-array ;
 
 M: hashtable equal?
     over hashtable? [
-        2dup [ assoc-size ] bi@ number=
+        2dup [ assoc-size ] bi@ eq?
         [ assoc= ] [ 2drop f ] if
     ] [ 2drop f ] if ;
 
index b2b75509e9874a4a458e409e4886c0d1df3806b1..184b5e1c15db56116d695c1d8b7140f8d2044190 100644 (file)
@@ -5,6 +5,33 @@ strings generic splitting continuations destructors
 io.streams.plain io.encodings math.order growable ;
 IN: io.streams.string
 
+<PRIVATE
+
+: harden-as ( seq growble-exemplar -- newseq )
+    underlying>> like ;
+
+: growable-read-until ( growable n -- str )
+    >fixnum dupd tail-slice swap harden-as dup reverse-here ;
+
+SINGLETON: null-encoding
+
+M: null-encoding decode-char drop stream-read1 ;
+
+: format-column ( seq ? -- seq )
+    [
+        [ 0 [ length max ] reduce ] keep
+        swap [ CHAR: \s pad-right ] curry map
+    ] unless ;
+
+: map-last ( seq quot -- seq )
+    >r dup length <reversed> [ zero? ] r> compose 2map ; inline
+
+: format-table ( table -- seq )
+    flip [ format-column ] map-last
+    flip [ " " join ] map ;
+
+PRIVATE>
+
 M: growable dispose drop ;
 
 M: growable stream-write1 push ;
@@ -20,12 +47,6 @@ M: growable stream-flush drop ;
 
 M: growable stream-read1 [ f ] [ pop ] if-empty ;
 
-: harden-as ( seq growble-exemplar -- newseq )
-    underlying>> like ;
-
-: growable-read-until ( growable n -- str )
-    >fixnum dupd tail-slice swap harden-as dup reverse-here ;
-
 : find-last-sep ( seq seps -- n )
     swap [ memq? ] curry find-last drop ;
 
@@ -50,30 +71,14 @@ M: growable stream-read
 M: growable stream-read-partial
     stream-read ;
 
-SINGLETON: null
-M: null decode-char drop stream-read1 ;
-
 : <string-reader> ( str -- stream )
-    >sbuf dup reverse-here null <decoder> ;
+    >sbuf dup reverse-here null-encoding <decoder> ;
 
 : with-string-reader ( str quot -- )
     >r <string-reader> r> with-input-stream ; inline
 
 INSTANCE: growable plain-writer
 
-: format-column ( seq ? -- seq )
-    [
-        [ 0 [ length max ] reduce ] keep
-        swap [ CHAR: \s pad-right ] curry map
-    ] unless ;
-
-: map-last ( seq quot -- seq )
-    >r dup length <reversed> [ zero? ] r> compose 2map ; inline
-
-: format-table ( table -- seq )
-    flip [ format-column ] map-last
-    flip [ " " join ] map ;
-
 M: plain-writer stream-write-table
     [ drop format-table [ print ] each ] with-output-stream* ;
 
index 71f3980a6c2c412d8a3a9c82dbf4a5f7d996c142..289d39868cb74f326dff799bd8609f9ca6e2b150 100644 (file)
@@ -170,7 +170,7 @@ HELP: xor
 { $notes "This word implements boolean exclusive or, so applying it to integers will not yield useful results (all integers have a true value). Bitwise exclusive or is the " { $link bitxor } " word." } ;
 
 HELP: both?
-{ $values { "quot" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
+{ $values { "quot" { $quotation "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
 { $description "Tests if the quotation yields a true value when applied to both " { $snippet "x" } " and " { $snippet "y" } "." }
 { $examples
     { $example "USING: kernel math prettyprint ;" "3 5 [ odd? ] both? ." "t" }
@@ -178,7 +178,7 @@ HELP: both?
 } ;
 
 HELP: either?
-{ $values { "quot" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
+{ $values { "quot" { $quotation "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
 { $description "Tests if the quotation yields a true value when applied to either " { $snippet "x" } " or " { $snippet "y" } "." }
 { $examples
     { $example "USING: kernel math prettyprint ;" "3 6 [ odd? ] either? ." "t" }
@@ -211,19 +211,19 @@ HELP: 3slip
 { $description "Calls a quotation while hiding the top three stack elements." } ;
 
 HELP: keep
-{ $values { "quot" "a quotation with stack effect " { $snippet "( x -- )" } } { "x" object } }
+{ $values { "quot" { $quotation "( x -- )" } } { "x" object } }
 { $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." } ;
 
 HELP: 2keep
-{ $values { "quot" "a quotation with stack effect " { $snippet "( x y -- )" } } { "x" object } { "y" object } }
+{ $values { "quot" { $quotation "( x y -- )" } } { "x" object } { "y" object } }
 { $description "Call a quotation with two values on the stack, restoring the values when the quotation returns." } ;
 
 HELP: 3keep
-{ $values { "quot" "a quotation with stack effect " { $snippet "( x y z -- )" } } { "x" object } { "y" object } { "z" object } }
+{ $values { "quot" { $quotation "( x y z -- )" } } { "x" object } { "y" object } { "z" object } }
 { $description "Call a quotation with three values on the stack, restoring the values when the quotation returns." } ;
 
 HELP: bi
-{ $values { "x" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x -- ... )" } } }
+{ $values { "x" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( x -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "x" } "." }
 { $examples
     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x -- )" } ", then the following two lines are equivalent:"
@@ -245,7 +245,7 @@ HELP: bi
 } ;
 
 HELP: 2bi
-{ $values { "x" object } { "y" object } { "p" "a quotation with stack effect " { $snippet "( x y -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y -- ... )" } } }
+{ $values { "x" object } { "y" object } { "p" { $quotation "( x y -- ... )" } } { "q" { $quotation "( x y -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values." }
 { $examples
     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y -- )" } ", then the following two lines are equivalent:"
@@ -266,7 +266,7 @@ HELP: 2bi
 } ;
 
 HELP: 3bi
-{ $values { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } }
+{ $values { "x" object } { "y" object } { "z" object } { "p" { $quotation "( x y z -- ... )" } } { "q" { $quotation "( x y z -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to the three input values, then applies " { $snippet "q" } " to the three input values." }
 { $examples
     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y z -- )" } ", then the following two lines are equivalent:"
@@ -287,7 +287,7 @@ HELP: 3bi
 } ;
 
 HELP: tri
-{ $values { "x" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( x -- ... )" } } }
+{ $values { "x" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( x -- ... )" } } { "r" { $quotation "( x -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "x" } ", and finally applies " { $snippet "r" } " to " { $snippet "x" } "." }
 { $examples
     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x -- )" } ", then the following two lines are equivalent:"
@@ -308,7 +308,7 @@ HELP: tri
 } ;
 
 HELP: 2tri
-{ $values { "x" object } { "y" object } { "p" "a quotation with stack effect " { $snippet "( x y -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( x y -- ... )" } } }
+{ $values { "x" object } { "y" object } { "p" { $quotation "( x y -- ... )" } } { "q" { $quotation "( x y -- ... )" } } { "r" { $quotation "( x y -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values, and finally applies " { $snippet "r" } " to the two input values." }
 { $examples
     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x y -- )" } ", then the following two lines are equivalent:"
@@ -324,7 +324,7 @@ HELP: 2tri
 } ;
 
 HELP: 3tri
-{ $values { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } }
+{ $values { "x" object } { "y" object } { "z" object } { "p" { $quotation "( x y z -- ... )" } } { "q" { $quotation "( x y z -- ... )" } } { "r" { $quotation "( x y z -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to the three input values, then applies " { $snippet "q" } " to the three input values, and finally applies " { $snippet "r" } " to the three input values." }
 { $examples
     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x y z -- )" } ", then the following two lines are equivalent:"
@@ -341,7 +341,7 @@ HELP: 3tri
 
 
 HELP: bi*
-{ $values { "x" object } { "y" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( y -- ... )" } } }
+{ $values { "x" object } { "y" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( y -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } "." }
 { $examples
     "The following two lines are equivalent:"
@@ -352,7 +352,7 @@ HELP: bi*
 } ;
 
 HELP: 2bi*
-{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( w x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( y z -- ... )" } } }
+{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "p" { $quotation "( w x -- ... )" } } { "q" { $quotation "( y z -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to " { $snippet "w" } " and " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } " and " { $snippet "z" } "." }
 { $examples
     "The following two lines are equivalent:"
@@ -363,7 +363,7 @@ HELP: 2bi*
 } ;
 
 HELP: tri*
-{ $values { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( y -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( z -- ... )" } } }
+{ $values { "x" object } { "y" object } { "z" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( y -- ... )" } } { "r" { $quotation "( z -- ... )" } } }
 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } ", and finally applies " { $snippet "r" } " to " { $snippet "z" } "." }
 { $examples
     "The following two lines are equivalent:"
@@ -374,7 +374,7 @@ HELP: tri*
 } ;
 
 HELP: bi@
-{ $values { "x" object } { "y" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } }
+{ $values { "x" object } { "y" object } { "quot" { $quotation "( obj -- )" } } }
 { $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } "." }
 { $examples
     "The following two lines are equivalent:"
@@ -390,7 +390,7 @@ HELP: bi@
 } ;
 
 HELP: 2bi@
-{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" "a quotation with stack effect " { $snippet "( obj1 obj2 -- )" } } }
+{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj1 obj2 -- )" } } }
 { $description "Applies the quotation to " { $snippet "w" } " and " { $snippet "x" } ", then to " { $snippet "y" } " and " { $snippet "z" } "." }
 { $examples
     "The following two lines are equivalent:"
@@ -406,7 +406,7 @@ HELP: 2bi@
 } ;
 
 HELP: tri@
-{ $values { "x" object } { "y" object } { "z" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } }
+{ $values { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj -- )" } } }
 { $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } ", and finally to " { $snippet "z" } "." }
 { $examples
     "The following two lines are equivalent:"
@@ -440,7 +440,7 @@ $nl
 "The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
 
 HELP: if*
-{ $values { "?" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } { "false" quotation } }
+{ $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- )" } } { "false" quotation } }
 { $description "Alternative conditional form that preserves the " { $snippet "cond" } " value if it is true."
 $nl
 "If the condition is true, it is retained on the stack before the " { $snippet "true" } " quotation is called. Otherwise, the condition is removed from the stack and the " { $snippet "false" } " quotation is called."
@@ -449,7 +449,7 @@ $nl
 { $code "X [ Y ] [ Z ] if*" "X dup [ Y ] [ drop Z ] if" } } ;
 
 HELP: when*
-{ $values { "?" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } }
+{ $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- )" } } }
 { $description "Variant of " { $link if* } " with no false quotation."
 $nl
 "The following two lines are equivalent:"
@@ -463,7 +463,7 @@ HELP: unless*
 { $code "X [ Y ] unless*" "X dup [ ] [ drop Y ] if" } } ;
 
 HELP: ?if
-{ $values { "default" object } { "cond" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } { "false" "a quotation with stack effect " { $snippet "( default -- )" } } }
+{ $values { "default" object } { "cond" "a generalized boolean" } { "true" { $quotation "( cond -- )" } } { "false" { $quotation "( default -- )" } } }
 { $description "If the condition is " { $link f } ", the " { $snippet "false" } " quotation is called with the " { $snippet "default" } " value on the stack. Otherwise, the " { $snippet "true" } " quotation is called with the condition on the stack." }
 { $notes
 "The following two lines are equivalent:"
@@ -520,7 +520,7 @@ HELP: null
 } ;
 
 HELP: most
-{ $values { "x" object } { "y" object } { "quot" "a quotation with stack effect " { $snippet "( x y -- ? )" } } { "z" "either " { $snippet "x" } " or " { $snippet "y" } } }
+{ $values { "x" object } { "y" object } { "quot" { $quotation "( x y -- ? )" } } { "z" "either " { $snippet "x" } " or " { $snippet "y" } } }
 { $description "If the quotation yields a true value when applied to " { $snippet "x" } " and " { $snippet "y" } ", outputs " { $snippet "x" } ", otherwise outputs " { $snippet "y" } "." } ;
 
 HELP: curry
@@ -550,7 +550,7 @@ HELP: 3curry
 { $notes "This operation is efficient and does not copy the quotation." } ;
 
 HELP: with
-{ $values { "param" object } { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( param elt -- ... )" } } { "obj" object } { "curry" curry } }
+{ $values { "param" object } { "obj" object } { "quot" { $quotation "( param elt -- ... )" } } { "obj" object } { "curry" curry } }
 { $description "Partial application on the left. The following two lines are equivalent:"
     { $code "swap [ swap A ] curry B" }
     { $code "[ A ] with B" }
@@ -630,7 +630,7 @@ HELP: 3dip
 } ;
 
 HELP: while
-{ $values { "pred" "a quotation with stack effect " { $snippet "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
 { $description "Repeatedly calls " { $snippet "pred" } ". If it yields " { $link f } ", iteration stops, otherwise " { $snippet "body" } " is called. After iteration stops, " { $snippet "tail" } " is called." }
 { $notes "In most cases, tail recursion should be used, because it is simpler both in terms of implementation and conceptually. However in some cases this combinator expresses intent better and should be used."
 $nl
index 67948cc8f9a1c96f0605b1d1190c1a4ca7c78955..31f5a3f72e64ae97f6c1abe75d2416bf2d27e806 100644 (file)
@@ -32,7 +32,7 @@ HELP: skip
 { $description "Skips to the first space character (if " { $snippet "boolean" } " is " { $link f } ") or the first non-space character (otherwise)." } ;
 
 HELP: change-lexer-column
-{ $values { "lexer" lexer } { "quot" "a quotation with stack effect " { $snippet "( col line -- newcol )" } } }
+{ $values { "lexer" lexer } { "quot" { $quotation "( col line -- newcol )" } } }
 { $description "Applies a quotation to the current column and line text to produce a new column, and moves the lexer position." } ;
 
 HELP: skip-blank
@@ -54,11 +54,11 @@ HELP: still-parsing-line?
 { $description "Outputs " { $link f } " if the end of the current line has been reached, " { $link t } " otherwise." } ;
 
 HELP: parse-token
-{ $values { "lexer" lexer } { "str/f" "a " { $link string } " or " { $link f } } }
+{ $values { "lexer" lexer } { "str/f" { $maybe string } } }
 { $description "Reads the next token from the lexer. Tokens are delimited by whitespace, with the exception that " { $snippet "\"" } " is treated like a single token even when not followed by whitespace." } ;
 
 HELP: scan
-{ $values { "str/f" "a " { $link string } " or " { $link f } } }
+{ $values { "str/f" { $maybe string } } }
 { $description "Reads the next token from the lexer. See " { $link parse-token } " for details." }
 $parsing-note ;
 
@@ -73,7 +73,7 @@ HELP: parse-tokens
 $parsing-note ;
 
 HELP: unexpected
-{ $values { "want" "a " { $link word } " or " { $link f } } { "got" word } }
+{ $values { "want" { $maybe word } } { "got" word } }
 { $description "Throws an " { $link unexpected } " error." }
 { $error-description "Thrown by the parser if an unmatched closing delimiter is encountered." }
 { $examples
index a863715d33257e9049c5fd06f3b77a7e404363d0..20b4e0bbbebe73a335f199e276ff6cff7be42913 100644 (file)
@@ -284,22 +284,22 @@ HELP: power-of-2?
 { $description "Tests if " { $snippet "n" } " is a power of 2." } ;
 
 HELP: each-integer
-{ $values { "n" integer } { "quot" "a quotation with stack effect " { $snippet "( i -- )" } } }
+{ $values { "n" integer } { "quot" { $quotation "( i -- )" } } }
 { $description "Applies the quotation to each integer from 0 up to " { $snippet "n" } ", excluding " { $snippet "n" } "." }
 { $notes "This word is used to implement " { $link each } "." } ;
 
 HELP: all-integers?
-{ $values { "n" integer } { "quot" "a quotation with stack effect " { $snippet "( i -- ? )" } } { "?" "a boolean" } }
+{ $values { "n" integer } { "quot" { $quotation "( i -- ? )" } } { "?" "a boolean" } }
 { $description "Applies the quotation to each integer from 0 up to " { $snippet "n" } ", excluding " { $snippet "n" } ". Iterationi stops when the quotation outputs " { $link f } " or the end is reached. If the quotation yields a false value for some integer, this word outputs " { $link f } ". Otherwise, this word outputs " { $link t } "." }
 { $notes "This word is used to implement " { $link all? } "." } ;
 
 HELP: find-integer
-{ $values { "n" integer } { "quot" "a quotation with stack effect " { $snippet "( i -- ? )" } } { "i" "an integer or " { $link f } } }
+{ $values { "n" integer } { "quot" { $quotation "( i -- ? )" } } { "i" "an integer or " { $link f } } }
 { $description "Applies the quotation to each integer from 0 up to " { $snippet "n" } ", excluding " { $snippet "n" } ". Iterationi stops when the quotation outputs a true value or the end is reached. If the quotation yields a true value for some integer, this word outputs that integer. Otherwise, this word outputs " { $link f } "." }
 { $notes "This word is used to implement " { $link find } "." } ;
 
 HELP: find-last-integer
-{ $values { "n" integer } { "quot" "a quotation with stack effect " { $snippet "( i -- ? )" } } { "i" "an integer or " { $link f } } }
+{ $values { "n" integer } { "quot" { $quotation "( i -- ? )" } } { "i" "an integer or " { $link f } } }
 { $description "Applies the quotation to each integer from " { $snippet "n" } " down to 0, inclusive. Iteration stops when the quotation outputs a true value or 0 is reached. If the quotation yields a true value for some integer, the word outputs that integer. Otherwise, the word outputs " { $link f } "." }
 { $notes "This word is used to implement " { $link find-last } "." } ;
 
index 65edbdaaae076357928a11d0244fa6d61b4d3c36..c8d3095ce651abba62209671e83fe8346b4364f2 100644 (file)
@@ -32,7 +32,7 @@ HELP: invert-comparison
     { $example "USING: math.order prettyprint ;" "+lt+ invert-comparison ." "+gt+" } } ;
 
 HELP: compare
-{ $values { "obj1" object } { "obj2" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- newobj )" } } { "<=>" "an ordering specifier" } }
+{ $values { "obj1" object } { "obj2" object } { "quot" { $quotation "( obj -- newobj )" } } { "<=>" "an ordering specifier" } }
 { $description "Compares the results of applying the quotation to both objects via " { $link <=> } "." }
 { $examples { $example "USING: kernel math.order prettyprint sequences ;" "\"hello\" \"hi\" [ length ] compare ." "+gt+" }
 } ;
index fb1d4a336f32864c8d49fa1e46b068e4c9c008d7..8f49d882ee9826b3fb58b3035c5cbd8787711d03 100644 (file)
@@ -19,12 +19,12 @@ HELP: end-scan ( -- )
 { $notes "This is a low-level facility and can be dangerous. Use the " { $link each-object } " combinator instead." } ;
 
 HELP: each-object
-{ $values { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } }
+{ $values { "quot" { $quotation "( obj -- )" } } }
 { $description "Applies a quotation to each object in the heap. The garbage collector is switched off while this combinator runs, so the given quotation must not allocate too much memory." }
 { $notes "This word is the low-level facility used to implement the " { $link instances } " word." } ;
 
 HELP: instances
-{ $values { "quot" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "seq" "a fresh sequence" } }
+{ $values { "quot" { $quotation "( obj -- ? )" } } { "seq" "a fresh sequence" } }
 { $description "Outputs a sequence of all objects in the heap which satisfy the quotation." }
 { $notes "This word relies on " { $link each-object } ", so in particular the garbage collector is switched off while it runs and the given quotation must not allocate too much memory." } ;
 
index c84699539d8f2024e21a78b1afd8dcdd4f7fef5a..4716a8fe999190488c5c70a4bf86be63295bb023 100644 (file)
@@ -69,7 +69,7 @@ HELP: on
 { $side-effects "variable" } ;
 
 HELP: change
-{ $values { "variable" "a variable, by convention a symbol" } { "quot" "a quotation with stack effect " { $snippet "( old -- new )" } } }
+{ $values { "variable" "a variable, by convention a symbol" } { "quot" { $quotation "( old -- new )" } } }
 { $description "Applies the quotation to the old value of the variable, and assigns the resulting value to the variable." }
 { $side-effects "variable" } ;
 
index d33f5cd6d93d5424fa5b9a9745b64e8c54fafe40..d3c2cff19d1a4db200e399b76d0ec32c2a5ebf34 100644 (file)
@@ -294,7 +294,7 @@ HELP: parse-base
 $parsing-note ;
 
 HELP: parse-literal
-{ $values { "accum" vector } { "end" word } { "quot" "a quotation with stack effect " { $snippet "( seq -- obj )" } } }
+{ $values { "accum" vector } { "end" word } { "quot" { $quotation "( seq -- obj )" } } }
 { $description "Parses objects from parser input until " { $snippet "end" } ", applies the quotation to the resulting sequence, and adds the output value to the accumulator." }
 { $examples "This word is used to implement " { $link POSTPONE: [ } "." }
 $parsing-note ;
index e45d98a3df1dfbbda1b59a93b98368fd010e5b91..5a30654f03677a00c34a14ea3b6d97c9a01a0c62 100644 (file)
@@ -33,7 +33,7 @@ M: string new-resizable drop <sbuf> ;
 M: string like
     drop dup string? [
         dup sbuf? [
-            dup length over underlying>> length number= [
+            dup length over underlying>> length eq? [
                 underlying>> dup reset-string-hashcode
             ] [
                 >string
index 8cb7f1c0882a84c9261d632dd0de75e51e8ef914..cc8daba8c0a812bc9daa947a7507dfc5e8de0ebd 100644 (file)
@@ -247,15 +247,15 @@ HELP: set-array-nth
 { $warning "This word is in the " { $vocab-link "sequences.private" } " vocabulary because it is unsafe. It does not check types or array bounds, and improper use can corrupt memory." } ;
 
 HELP: collect
-{ $values { "n" "a non-negative integer" } { "quot" "a quotation with stack effect " { $snippet "( n -- value )" } } { "into" "a sequence of length at least " { $snippet "n" } } }
+{ $values { "n" "a non-negative integer" } { "quot" { $quotation "( n -- value )" } } { "into" "a sequence of length at least " { $snippet "n" } } }
 { $description "A primitive mapping operation that applies a quotation to all integers from 0 up to but not including " { $snippet "n" } ", and collects the results in a new array. User code should use " { $link map } " instead." } ;
 
 HELP: each
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } }
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- )" } } }
 { $description "Applies the quotation to each element of the sequence in order." } ;
 
 HELP: reduce
-{ $values { "seq" sequence } { "identity" object } { "quot" "a quotation with stack effect " { $snippet "( prev elt -- next )" } } { "result" "the final result" } }
+{ $values { "seq" sequence } { "identity" object } { "quot" { $quotation "( prev elt -- next )" } } { "result" "the final result" } }
 { $description "Combines successive elements of the sequence using a binary operation, and outputs the final result. On the first iteration, the two inputs to the quotation are " { $snippet "identity" } ", and the first element of the sequence. On successive iterations, the first input is the result of the previous iteration, and the second input is the corresponding element of the sequence." }
 { $examples
     { $example "USING: math prettyprint sequences ;" "{ 1 5 3 } 0 [ + ] reduce ." "9" }
@@ -271,7 +271,7 @@ HELP: reduce-index
 } } ;
 
 HELP: accumulate
-{ $values { "identity" object } { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( prev elt -- next )" } } { "final" "the final result" } { "newseq" "a new sequence" } }
+{ $values { "identity" object } { "seq" sequence } { "quot" { $quotation "( prev elt -- next )" } } { "final" "the final result" } { "newseq" "a new sequence" } }
 { $description "Combines successive elements of the sequence using a binary operation, and outputs a sequence of intermediate results together with the final result. On the first iteration, the two inputs to the quotation are " { $snippet "identity" } ", and the first element of the sequence. On successive iterations, the first input is the result of the previous iteration, and the second input is the corresponding element of the sequence."
 $nl
 "When given the empty sequence, outputs an empty sequence together with the " { $snippet "identity" } "." }
@@ -280,11 +280,11 @@ $nl
 } ;
 
 HELP: map
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( old -- new )" } } { "newseq" "a new sequence" } }
+{ $values { "seq" sequence } { "quot" { $quotation "( old -- new )" } } { "newseq" "a new sequence" } }
 { $description "Applies the quotation to each element of the sequence in order. The new elements are collected into a sequence of the same class as the input sequence." } ;
 
 HELP: map-as
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( old -- new )" } } { "newseq" "a new sequence" } { "exemplar" sequence } }
+{ $values { "seq" sequence } { "quot" { $quotation "( old -- new )" } } { "newseq" "a new sequence" } { "exemplar" sequence } }
 { $description "Applies the quotation to each element of the sequence in order. The new elements are collected into a sequence of the same class as " { $snippet "exemplar" } "." }
 { $examples
     "The following example converts a string into an array of one-element strings:"
@@ -311,13 +311,13 @@ HELP: map-index
 } } ;
 
 HELP: change-nth
-{ $values { "i" "a non-negative integer" } { "seq" "a mutable sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- newelt )" } } }
+{ $values { "i" "a non-negative integer" } { "seq" "a mutable sequence" } { "quot" { $quotation "( elt -- newelt )" } } }
 { $description "Applies the quotation to the " { $snippet "i" } "th element of the sequence, storing the result back into the sequence." }
 { $errors "Throws an error if the sequence is immutable, if the index is out of bounds, or the sequence cannot hold elements of the type output by " { $snippet "quot" } "." }
 { $side-effects "seq" } ;
 
 HELP: change-each
-{ $values { "seq" "a mutable sequence" } { "quot" "a quotation with stack effect " { $snippet "( old -- new )" } } }
+{ $values { "seq" "a mutable sequence" } { "quot" { $quotation "( old -- new )" } } }
 { $description "Applies the quotation to each element yielding a new element, storing the new elements back in the original sequence." }
 { $errors "Throws an error if the sequence is immutable, or the sequence cannot hold elements of the type output by " { $snippet "quot" } "." }
 { $side-effects "seq" } ;
@@ -331,79 +331,76 @@ HELP: max-length
 { $description "Outputs the maximum of the lengths of the two sequences." } ;
 
 HELP: 2each
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt1 elt2 -- )" } } }
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt1 elt2 -- )" } } }
 { $description "Applies the quotation to pairs of elements from " { $snippet "seq1" } " and " { $snippet "seq2" } "." } ;
 
 HELP: 2reduce
 { $values { "seq1" sequence }
           { "seq2" sequence }
           { "identity" object }
-          { "quot" "a quotation with stack effect "
-                   { $snippet "( prev elt1 elt2 -- next )" } }
+          { "quot" { $quotation "( prev elt1 elt2 -- next )" } }
           { "result" "the final result" } }
 { $description "Combines successive pairs of elements from the two sequences using a ternary operation. The first input value at each iteration except the first one is the result of the previous iteration. The first input value at the first iteration is " { $snippet "identity" } "." } ;
 
 HELP: 2map
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt1 elt2 -- new )" } } { "newseq" "a new sequence" } }
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt1 elt2 -- new )" } } { "newseq" "a new sequence" } }
 { $description "Applies the quotation to each pair of elements in turn, yielding new elements which are collected into a new sequence having the same class as " { $snippet "seq1" } "." } ;
 
 HELP: 2map-as
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt1 elt2 -- new )" } } { "exemplar" sequence } { "newseq" "a new sequence" } }
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt1 elt2 -- new )" } } { "exemplar" sequence } { "newseq" "a new sequence" } }
 { $description "Applies the quotation to each pair of elements in turn, yielding new elements which are collected into a new sequence having the same class as " { $snippet "exemplar" } "." } ;
 
 HELP: 2all?
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt1 elt2 -- ? )" } } { "?" "a boolean" } }
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt1 elt2 -- ? )" } } { "?" "a boolean" } }
 { $description "Tests the predicate pairwise against elements of " { $snippet "seq1" } " and " { $snippet "seq2" } "." } ;
 
 HELP: find
 { $values { "seq" sequence }
-          { "quot" "a quotation with stack effect "
-                   { $snippet "( elt -- ? )" } }
-          { "i" "the index of the first match, or f" }
+          { "quot" { $quotation "( elt -- ? )" } }
+          { "i" "the index of the first match, or " { $link f } }
           { "elt" "the first matching element, or " { $link f } } }
 { $description "A simpler variant of " { $link find-from } " where the starting index is 0." } ;
 
 HELP: find-from
 { $values { "n" "a starting index" }
           { "seq" sequence }
-          { "quot" "a quotation with stack effect "
-                   { $snippet "( elt -- ? )" } }
-          { "i" "the index of the first match, or f" }
+          { "quot" { $quotation "( elt -- ? )" } }
+          { "i" "the index of the first match, or " { $link f } }
           { "elt" "the first matching element, or " { $link f } } }
 { $description "Applies the quotation to each element of the sequence in turn, until it outputs a true value or the end of the sequence is reached. If the quotation yields a true value for some sequence element, the word outputs the element index and the element itself. Otherwise, the word outputs an index of f and " { $link f } " as the element." } ;
 
 HELP: find-last
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "i" "the index of the first match, or f" } { "elt" "the first matching element, or " { $link f } } }
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "i" "the index of the first match, or f" } { "elt" "the first matching element, or " { $link f } } }
 { $description "A simpler variant of " { $link find-last-from } " where the starting index is one less than the length of the sequence." } ;
 
 HELP: find-last-from
-{ $values { "n" "a starting index" } { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "i" "the index of the first match, or f" } { "elt" "the first matching element, or " { $link f } } }
+{ $values { "n" "a starting index" } { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "i" "the index of the first match, or f" } { "elt" "the first matching element, or " { $link f } } }
 { $description "Applies the quotation to each element of the sequence in reverse order, until it outputs a true value or the start of the sequence is reached. If the quotation yields a true value for some sequence element, the word outputs the element index and the element itself. Otherwise, the word outputs an index of f and " { $link f } " as the element." } ;
 
 HELP: contains?
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "?" "a boolean" } }
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "?" "a boolean" } }
 { $description "Tests if the sequence contains an element satisfying the predicate, by applying the predicate to each element in turn until a true value is found. If the sequence is empty or if the end of the sequence is reached, outputs " { $link f } "." } ;
 
 HELP: all?
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "?" "a boolean" } }
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "?" "a boolean" } }
 { $description "Tests if all elements in the sequence satisfy the predicate by checking each element in turn. Given an empty sequence, vacuously outputs " { $link t } "." } ;
 
 HELP: push-if
-{ $values { "elt" object } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "accum" "a resizable mutable sequence" } }
+{ $values { "elt" object } { "quot" { $quotation "( elt -- ? )" } } { "accum" "a resizable mutable sequence" } }
 { $description "Adds the element at the end of the sequence if the quotation yields a true value." } 
 { $notes "This word is a factor of " { $link filter } "." } ;
 
 HELP: filter
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "subseq" "a new sequence" } }
+{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "subseq" "a new sequence" } }
 { $description "Applies the quotation to each element in turn, and outputs a new sequence containing the elements of the original sequence for which the quotation output a true value." } ;
 
 HELP: filter-here
-{ $values { "seq" "a resizable mutable sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } }
+{ $values { "seq" "a resizable mutable sequence" } { "quot" { $quotation "( elt -- ? )" } } }
 { $description "Applies the quotation to each element in turn, and removes elements for which the quotation outputs a false value." }
 { $side-effects "seq" } ;
 
 HELP: monotonic?
-{ $values { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( elt elt -- ? )" } } { "?" "a boolean" } }
+{ $values { "seq" sequence } { "quot" { $quotation "( elt elt -- ? )" } } { "?" "a boolean" } }
 { $description "Applies the relation to successive pairs of elements in the sequence, testing for a truth value. The relation should be a transitive relation, such as a total order or an equality relation." }
 { $examples
     "Testing if a sequence is non-decreasing:"
@@ -415,12 +412,12 @@ HELP: monotonic?
 { monotonic? all-eq? all-equal? } related-words
 
 HELP: interleave
-{ $values { "seq" sequence } { "between" "a quotation" } { "quot" "a quotation with stack effect " { $snippet "( elt -- )" } } }
+{ $values { "seq" sequence } { "between" "a quotation" } { "quot" { $quotation "( elt -- )" } } }
 { $description "Applies " { $snippet "quot" } " to each element in turn, also invoking " { $snippet "between" } " in-between each pair of elements." }
 { $example "USING: io sequences ;" "{ \"a\" \"b\" \"c\" } [ \"X\" write ] [ write ] interleave" "aXbXc" } ;
 
 HELP: cache-nth
-{ $values { "i" "a non-negative integer" } { "seq" "a mutable sequence" } { "quot" "a quotation with stack effect " { $snippet "( i -- elt )" } } { "elt" object } }
+{ $values { "i" "a non-negative integer" } { "seq" "a mutable sequence" } { "quot" { $quotation "( i -- elt )" } } { "elt" object } }
 { $description "If the sequence does not contain at least " { $snippet "i" } " elements or if the " { $snippet "i" } "th element of the sequence is " { $link f } ", calls the quotation to produce a new value, and stores it back into the sequence. Otherwise, this word outputs the " { $snippet "i" } "th element of the sequence." }
 { $side-effects "seq" } ;
 
@@ -584,7 +581,7 @@ HELP: reverse-here
 { $side-effects "seq" } ;
 
 HELP: padding
-{ $values { "seq" sequence } { "n" "a non-negative integer" } { "elt" object } { "quot" "a quotation with stack effect " { $snippet "( seq1 seq2 -- newseq )" } } { "newseq" "a new sequence" } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "elt" object } { "quot" { $quotation "( seq1 seq2 -- newseq )" } } { "newseq" "a new sequence" } }
 { $description "Outputs a new string sequence of " { $snippet "elt" } " repeated, that when appended to " { $snippet "seq" } ", yields a sequence of length " { $snippet "n" } ". If the length of " { $snippet "seq" } " is greater than " { $snippet "n" } ", this word outputs an empty sequence." } ;
 
 HELP: pad-left
@@ -874,7 +871,7 @@ HELP: supremum
 { $errors "Throws an error if the sequence is empty." } ;
 
 HELP: produce
-{ $values { "pred" "a quotation with stack effect " { $snippet "( -- ? )" } } { "quot" "a quotation with stack effect " { $snippet "( -- obj )" } } { "tail" "a quotation" } { "seq" "a sequence" } }
+{ $values { "pred" { $quotation "( -- ? )" } } { "quot" { $quotation "( -- obj )" } } { "tail" "a quotation" } { "seq" "a sequence" } }
 { $description "Calls " { $snippet "pred" } " repeatedly. If the predicate yields " { $link f } ", stops, otherwise, calls " { $snippet "quot" } " to yield a value. Values are accumulated and returned in a sequence at the end." }
 { $examples
     "The following example divides a number by two until we reach zero, and accumulates intermediate results:"
index d2d7dc110264d910e1f08fe36814178443940c52..c9ce33438809c225c0c280e58d1c9495ed6f6a35 100644 (file)
@@ -166,5 +166,5 @@ HELP: set-slot ( value obj n -- )
 { $warning "This word is in the " { $vocab-link "slots.private" } " vocabulary because it does not perform type or bounds checks, and slot numbers are implementation detail." } ;
 
 HELP: slot-named
-{ $values { "name" string } { "specs" "a sequence of " { $link slot-spec } " instances" } { "spec/f" "a " { $link slot-spec } " or " { $link f } } }
+{ $values { "name" string } { "specs" "a sequence of " { $link slot-spec } " instances" } { "spec/f" { $maybe slot-spec } } }
 { $description "Outputs the " { $link slot-spec } " with the given name." } ;
index 4f4a0cadad627f36825507b8074f45259dbcf207..767cec48301c0ac4f1d969b3f5e746af888b1fc7 100644 (file)
@@ -1,6 +1,6 @@
 IN: slots.tests
 USING: math accessors slots strings generic.standard kernel
-tools.test generic words parser eval ;
+tools.test generic words parser eval math.functions ;
 
 TUPLE: r/w-test foo ;
 
@@ -34,3 +34,18 @@ TUPLE: hello length ;
 
 [ f ] [ r/w-test \ foo>> method "foldable" word-prop ] unit-test
 [ t ] [ r/w-test \ foo>> method "flushable" word-prop ] unit-test
+
+! Test protocol slots
+SLOT: my-protocol-slot-test
+
+TUPLE: protocol-slot-test-tuple x ;
+
+M: protocol-slot-test-tuple my-protocol-slot-test>> x>> sq ;
+M: protocol-slot-test-tuple (>>my-protocol-slot-test) [ sqrt ] dip (>>x) ;
+
+[ 9 ] [ T{ protocol-slot-test-tuple { x 3 } } my-protocol-slot-test>> ] unit-test
+
+[ 4.0 ] [
+    T{ protocol-slot-test-tuple { x 3 } } clone
+    [ 7 + ] change-my-protocol-slot-test x>>
+] unit-test
index d4ae60ca9469852b11fbfb09cd2ce79fd1744611..72c79928cb34bb50888f859c5193b23da11045d9 100644 (file)
@@ -97,16 +97,16 @@ ERROR: bad-slot-value value class ;
 : setter-word ( name -- word )
     ">>" prepend (( object value -- object )) create-accessor ;
 
-: define-setter ( slot-spec -- )
-    name>> dup setter-word dup deferred? [
+: define-setter ( name -- )
+    dup setter-word dup deferred? [
         [ \ over , swap writer-word , ] [ ] make define-inline
     ] [ 2drop ] if ;
 
 : changer-word ( name -- word )
     "change-" prepend (( object quot -- object )) create-accessor ;
 
-: define-changer ( slot-spec -- )
-    name>> dup changer-word dup deferred? [
+: define-changer ( name -- )
+    dup changer-word dup deferred? [
         [
             [ over >r >r ] %
             over reader-word ,
@@ -119,8 +119,8 @@ ERROR: bad-slot-value value class ;
     [ define-reader ]
     [
         dup read-only>> [ 2drop ] [
-            [ define-setter drop ]
-            [ define-changer drop ]
+            [ name>> define-setter drop ]
+            [ name>> define-changer drop ]
             [ define-writer ]
             2tri
         ] if
@@ -131,10 +131,10 @@ ERROR: bad-slot-value value class ;
 
 : define-protocol-slot ( name -- )
     {
-        [ reader-word drop ]
-        [ writer-word drop ]
-        [ setter-word drop ]
-        [ changer-word drop ]
+        [ reader-word define-simple-generic ]
+        [ writer-word define-simple-generic ]
+        [ define-setter ]
+        [ define-changer ]
     } cleave ;
 
 ERROR: no-initial-value class ;
index 036ff2f759b1af151b4d0748bb87f35e8272b53c..6ea1485425c3b5aad12229d6656853bdb926abf2 100644 (file)
@@ -19,7 +19,7 @@ $nl
 ABOUT: "sequences-sorting"
 
 HELP: sort
-{ $values { "seq" "a sequence" } { "quot" "a quotation with stack effect " { $snippet "( obj1 obj2 -- <=> )" } } { "sortedseq" "a new sorted sequence" } }
+{ $values { "seq" "a sequence" } { "quot" { $quotation "( obj1 obj2 -- <=> )" } } { "sortedseq" "a new sorted sequence" } }
 { $description "Sorts the elements into a new array." } ;
 
 HELP: sort-keys
index 42d711b32ba66957d114e76b2aedcc5a59c9c58a..1e3d675068069c79aa420adc0a2e43d7814a6f10 100644 (file)
@@ -1 +1,2 @@
 collections
+algorithms
index 8ff5a7caf4b63981cd531ce4d796822c4b739cbb..944286cce567d72bbd5f01b30c015e76a22cc297 100644 (file)
@@ -20,7 +20,7 @@ PRIVATE>
 
 M: string equal?
     over string? [
-        over hashcode over hashcode number=
+        over hashcode over hashcode eq?
         [ sequence= ] [ 2drop f ] if
     ] [
         2drop f
index 328dce9b03a03049dbe81acb10e9476ee465a941..64a5a589dc6b0f23bb33086e85293cb5842cd782 100644 (file)
@@ -75,7 +75,7 @@ HELP: forget-vocab
 { $notes "This word must be called from inside " { $link with-compilation-unit } "." } ;
 
 HELP: load-vocab-hook
-{ $var-description "a quotation with stack effect " { $snippet "( name -- vocab )" } " which loads a vocabulary. This quotation is called by " { $link load-vocab } ". The default value should not need to be changed; this functinality is implemented via a hook stored in a variable to break a circular dependency which would otherwise exist from " { $vocab-link "vocabs" } " to " { $vocab-link "vocabs.loader" } " to " { $vocab-link "parser" } " back to " { $vocab-link "vocabs" } "." } ;
+{ $var-description { $quotation "( name -- vocab )" } " which loads a vocabulary. This quotation is called by " { $link load-vocab } ". The default value should not need to be changed; this functinality is implemented via a hook stored in a variable to break a circular dependency which would otherwise exist from " { $vocab-link "vocabs" } " to " { $vocab-link "vocabs.loader" } " to " { $vocab-link "parser" } " back to " { $vocab-link "vocabs" } "." } ;
 
 HELP: words-named
 { $values { "str" string } { "seq" "a sequence of words" } }
index 8a4f7e7bd25ad5a2610cdc1f5b1c8ad29509ec87..66c60dc06e5c322b1a94820e428903749f7817f3 100644 (file)
@@ -135,9 +135,7 @@ compiled-generic-crossref global [ H{ } assoc-like ] change-at
     [ compiled-generic-crossref get delete-at ]
     tri ;
 
-GENERIC: inline? ( word -- ? )
-
-M: word inline? "inline" word-prop ;
+: inline? ( word -- ? ) "inline" word-prop ; inline
 
 SYMBOL: visited
 
index 2c470d04b32a90985037b44ec084714d6d500937..0a5d5f8703e888a42aeb786101aa099f61eecd4c 100644 (file)
@@ -17,7 +17,7 @@ HELP: advised?
 { $description "Determines whether or not the given word has any advice on it." } ;
 
 HELP: ad-do-it
-{ $values { "input" "an object" } { "output" "an object" } }
+{ $values { "input" "an object" } { "result" "an object" } }
 { $description "Calls either the next applicable around advice or the main body, returning back to the point it was called from when finished.  This word should only be called from inside advice." }
 { $see-also coyield } ;
 
index a87b65d9385e1d7bacdffbd0fafa7325f17ffd3e..f4274299b1c36db85f10b2e3f3e38f18fded1061 100644 (file)
@@ -1,3 +1 @@
-advice
-aspect
-annotations
+extensions
index 8413331c0078561cdad9607e75dfd58c42b5f5f6..9c82cdbb509b29e91de1adf7a7becd183a679823 100644 (file)
@@ -3,7 +3,8 @@
 USING: accessors arrays classes.singleton combinators
 continuations io io.encodings.binary io.encodings.utf8
 io.files io.sockets kernel io.streams.duplex math
-math.parser sequences splitting namespaces strings fry ftp ;
+math.parser sequences splitting namespaces strings fry ftp
+ftp.client.listing-parser urls ;
 IN: ftp.client
 
 : (ftp-response-code) ( str -- n )
@@ -24,145 +25,86 @@ IN: ftp.client
     [ fourth CHAR: - = ] tri
     [ read-response-loop ] when ;
 
+ERROR: ftp-error got expected ;
+
+: ftp-assert ( ftp-response n -- )
+    2dup [ n>> ] dip = [ 2drop ] [ ftp-error ] if ;
+
 : ftp-command ( string -- ftp-response )
     ftp-send read-response ;
 
-: ftp-user ( ftp-client -- ftp-response )
-    user>> "USER " prepend ftp-command ;
+: ftp-user ( url -- ftp-response )
+    username>> "USER " prepend ftp-command ;
 
-: ftp-password ( ftp-client -- ftp-response )
+: ftp-password ( url -- ftp-response )
     password>> "PASS " prepend ftp-command ;
 
-: ftp-set-binary ( -- ftp-response )
-    "TYPE I" ftp-command ;
-
-: ftp-pwd ( -- ftp-response )
-    "PWD" ftp-command ;
-
-: ftp-list ( -- ftp-response )
-    "LIST" ftp-command ;
-
-: ftp-quit ( -- ftp-response )
-    "QUIT" ftp-command ;
-
 : ftp-cwd ( directory -- ftp-response )
     "CWD " prepend ftp-command ;
 
 : ftp-retr ( filename -- ftp-response )
     "RETR " prepend ftp-command ;
 
-: parse-epsv ( ftp-response -- port )
-    strings>> first
-    "|" split 2 tail* first string>number ;
-
-TUPLE: remote-file
-type permissions links owner group size month day time year
-name target ;
-
-: <remote-file> ( -- remote-file ) remote-file new ;
-
-: parse-permissions ( remote-file str -- remote-file )
-    [ first ch>type >>type ] [ rest >>permissions ] bi ;
-
-: parse-list-11 ( lines -- seq )
-    [
-        11 f pad-right
-        <remote-file> swap {
-            [ 0 swap nth parse-permissions ]
-            [ 1 swap nth string>number >>links ]
-            [ 2 swap nth >>owner ]
-            [ 3 swap nth >>group ]
-            [ 4 swap nth string>number >>size ]
-            [ 5 swap nth >>month ]
-            [ 6 swap nth >>day ]
-            [ 7 swap nth >>time ]
-            [ 8 swap nth >>name ]
-            [ 10 swap nth >>target ]
-        } cleave
-    ] map ;
-
-: parse-list-8 ( lines -- seq )
-    [
-        <remote-file> swap {
-            [ 0 swap nth parse-permissions ]
-            [ 1 swap nth string>number >>links ]
-            [ 2 swap nth >>owner ]
-            [ 3 swap nth >>size ]
-            [ 4 swap nth >>month ]
-            [ 5 swap nth >>day ]
-            [ 6 swap nth >>time ]
-            [ 7 swap nth >>name ]
-        } cleave
-    ] map ;
-
-: parse-list-3 ( lines -- seq )
-    [
-        <remote-file> swap {
-            [ 0 swap nth parse-permissions ]
-            [ 1 swap nth string>number >>links ]
-            [ 2 swap nth >>name ]
-        } cleave
-    ] map ;
-
-: parse-list ( ftp-response -- ftp-response )
-    dup strings>>
-    [ " " split harvest ] map
-    dup length {
-        { 11 [ parse-list-11 ] }
-        { 9 [ parse-list-11 ] }
-        { 8 [ parse-list-8 ] }
-        { 3 [ parse-list-3 ] }
-        [ drop ]
-    } case >>parsed ;
+: ftp-set-binary ( -- ftp-response ) "TYPE I" ftp-command ;
 
-: ftp-epsv ( -- ftp-response )
-    "EPSV" ftp-command ;
+: ftp-pwd ( -- ftp-response ) "PWD" ftp-command ;
 
-ERROR: ftp-error got expected ;
-: ftp-assert ( ftp-response n -- )
-    2dup [ n>> ] dip = [ 2drop ] [ ftp-error ] if ;
+: ftp-list ( -- )
+    "LIST" ftp-command 150 ftp-assert ;
 
-: ftp-login ( ftp-client -- )
-    read-response 220 ftp-assert
-    [ ftp-user 331 ftp-assert ]
-    [ ftp-password 230 ftp-assert ] bi
-    ftp-set-binary 200 ftp-assert ;
+: ftp-quit ( -- ftp-response ) "QUIT" ftp-command ;
+
+: ftp-epsv ( -- ftp-response )
+    "EPSV" ftp-command dup 229 ftp-assert ;
 
-: open-remote-port ( -- port )
-    ftp-epsv
-    [ 229 ftp-assert ] [ parse-epsv ] bi ;
+: parse-epsv ( ftp-response -- port )
+    strings>> first "|" split 2 tail* first string>number ;
+
+: open-passive-client ( url protocol -- stream )
+    [ host>> ftp-epsv parse-epsv <inet> ] dip <client> drop ;
 
-: list ( ftp-client -- ftp-response )
-    host>> open-remote-port <inet> utf8 <client> drop
-    ftp-list 150 ftp-assert
+: list ( url -- ftp-response )
+    utf8 open-passive-client
+    ftp-list
     lines
     <ftp-response> swap >>strings
     read-response 226 ftp-assert
     parse-list ;
 
-: ftp-get ( filename ftp-client -- ftp-response )
-    host>> open-remote-port <inet> binary <client> drop
-    swap
+: (ftp-get) ( url path -- )
+    [ binary open-passive-client ] dip
     [ ftp-retr 150 ftp-assert drop ]
     [ binary <file-writer> stream-copy ] 2bi
-    read-response dup 226 ftp-assert ;
+    read-response 226 ftp-assert ;
 
-: ftp-connect ( ftp-client -- stream )
+: ftp-login ( url -- )
+    read-response 220 ftp-assert
+    [ ftp-user 331 ftp-assert ]
+    [ ftp-password 230 ftp-assert ] bi
+    ftp-set-binary 200 ftp-assert ;
+
+: ftp-connect ( url -- stream )
     [ host>> ] [ port>> ] bi <inet> utf8 <client> drop ;
 
-GENERIC: ftp-download ( path obj -- )
+: with-ftp-client ( url quot -- )
+    [ [ ftp-connect ] keep ] dip
+    '[ _ [ ftp-login ] _ bi ftp-quit drop ] with-stream ; inline
+
+: ensure-login ( url -- url )
+    dup username>> [
+        "anonymous" >>username
+        "ftp-client" >>password
+    ] unless ;
 
-: with-ftp-client ( ftp-client quot -- )
-    dupd '[
-        _ [ ftp-login ] [ @ ] bi
-        ftp-quit drop
-    ] [ ftp-connect ] dip with-stream ; inline
+: >ftp-url ( url -- url' ) >url ensure-port ensure-login ;
 
-M: ftp-client ftp-download ( path ftp-client -- )
-    [
-        [ drop parent-directory ftp-cwd drop ]
-        [ [ file-name ] dip ftp-get drop ] 2bi
+: ftp-get ( url -- )
+    >ftp-url [
+        dup path>>
+        [ nip parent-directory ftp-cwd drop ]
+        [ file-name (ftp-get) ] 2bi
     ] with-ftp-client ;
 
-M: string ftp-download ( path string -- )
-    <ftp-client> ftp-download ;
+
+
+
diff --git a/extra/ftp/client/listing-parser/authors.txt b/extra/ftp/client/listing-parser/authors.txt
new file mode 100644 (file)
index 0000000..b4bd0e7
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
\ No newline at end of file
diff --git a/extra/ftp/client/listing-parser/listing-parser.factor b/extra/ftp/client/listing-parser/listing-parser.factor
new file mode 100644 (file)
index 0000000..04e96ed
--- /dev/null
@@ -0,0 +1,89 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators io.files kernel math.parser
+sequences splitting ;
+IN: ftp.client.listing-parser
+
+: ch>file-type ( ch -- type )
+    {
+        { CHAR: b [ +block-device+ ] }
+        { CHAR: c [ +character-device+ ] }
+        { CHAR: d [ +directory+ ] }
+        { CHAR: l [ +symbolic-link+ ] }
+        { CHAR: s [ +socket+ ] }
+        { CHAR: p [ +fifo+ ] }
+        { CHAR: - [ +regular-file+ ] }
+        [ drop +unknown+ ]
+    } case ;
+
+: file-type>ch ( type -- string )
+    {
+        { +block-device+ [ CHAR: b ] }
+        { +character-device+ [ CHAR: c ] }
+        { +directory+ [ CHAR: d ] }
+        { +symbolic-link+ [ CHAR: l ] }
+        { +socket+ [ CHAR: s ] }
+        { +fifo+ [ CHAR: p ] }
+        { +regular-file+ [ CHAR: - ] }
+        [ drop CHAR: - ]
+    } case ;
+
+: parse-permissions ( remote-file str -- remote-file )
+    [ first ch>file-type >>type ] [ rest >>permissions ] bi ;
+
+TUPLE: remote-file
+type permissions links owner group size month day time year
+name target ;
+
+: <remote-file> ( -- remote-file ) remote-file new ;
+
+: parse-list-11 ( lines -- seq )
+    [
+        11 f pad-right
+        <remote-file> swap {
+            [ 0 swap nth parse-permissions ]
+            [ 1 swap nth string>number >>links ]
+            [ 2 swap nth >>owner ]
+            [ 3 swap nth >>group ]
+            [ 4 swap nth string>number >>size ]
+            [ 5 swap nth >>month ]
+            [ 6 swap nth >>day ]
+            [ 7 swap nth >>time ]
+            [ 8 swap nth >>name ]
+            [ 10 swap nth >>target ]
+        } cleave
+    ] map ;
+
+: parse-list-8 ( lines -- seq )
+    [
+        <remote-file> swap {
+            [ 0 swap nth parse-permissions ]
+            [ 1 swap nth string>number >>links ]
+            [ 2 swap nth >>owner ]
+            [ 3 swap nth >>size ]
+            [ 4 swap nth >>month ]
+            [ 5 swap nth >>day ]
+            [ 6 swap nth >>time ]
+            [ 7 swap nth >>name ]
+        } cleave
+    ] map ;
+
+: parse-list-3 ( lines -- seq )
+    [
+        <remote-file> swap {
+            [ 0 swap nth parse-permissions ]
+            [ 1 swap nth string>number >>links ]
+            [ 2 swap nth >>name ]
+        } cleave
+    ] map ;
+
+: parse-list ( ftp-response -- ftp-response )
+    dup strings>>
+    [ " " split harvest ] map
+    dup length {
+        { 11 [ parse-list-11 ] }
+        { 9 [ parse-list-11 ] }
+        { 8 [ parse-list-8 ] }
+        { 3 [ parse-list-3 ] }
+        [ drop ]
+    } case >>parsed ;
index 8f0b48bd4d760c8c831bfd34ecaa1f1ef4413f6c..adf7d5b41b77437315ececa45f93a1cf21f5d661 100644 (file)
@@ -7,21 +7,6 @@ IN: ftp
 SINGLETON: active
 SINGLETON: passive
 
-TUPLE: ftp-client host port user password mode state
-command-promise ;
-
-: <ftp-client> ( host -- ftp-client )
-    ftp-client new
-        swap >>host
-        21 >>port
-        "anonymous" >>user
-        "ftp@my.org" >>password ;
-
-: reset-ftp-client ( ftp-client -- )
-    f >>user
-    f >>password
-    drop ;
-
 TUPLE: ftp-response n strings parsed ;
 
 : <ftp-response> ( -- ftp-response )
@@ -32,35 +17,5 @@ TUPLE: ftp-response n strings parsed ;
     over strings>> push ;
 
 : ftp-send ( string -- ) write "\r\n" write flush ;
-
 : ftp-ipv4 1 ; inline
 : ftp-ipv6 2 ; inline
-
-: ch>type ( ch -- type )
-    {
-        { CHAR: d [ +directory+ ] }
-        { CHAR: l [ +symbolic-link+ ] }
-        { CHAR: - [ +regular-file+ ] }
-        [ drop +unknown+ ]
-    } case ;
-
-: type>ch ( type -- string )
-    {   
-        { +directory+ [ CHAR: d ] }
-        { +symbolic-link+ [ CHAR: l ] }
-        { +regular-file+ [ CHAR: - ] }
-        [ drop CHAR: - ]
-    } case ;
-
-: file-info>string ( file-info name -- string )
-    [
-        [
-            [ type>> type>ch 1string ]
-            [ drop "rwx------" append ] bi
-        ]
-        [ size>> number>string 15 CHAR: \s pad-left ] bi
-    ] dip 3array " " join ;
-
-: directory-list ( -- seq )
-    "" directory-files
-    [ [ link-info ] keep file-info>string ] map ;
index 170155bd435384e2d9a1c21f32af15f8d0f4f1fb..f8ab04ed00a2a2f4ac14e427b8d5b14a627c7f56 100644 (file)
@@ -6,12 +6,22 @@ io.encodings.utf8 io.files io.sockets kernel math.parser
 namespaces make sequences ftp io.unix.launcher.parser
 unicode.case splitting assocs classes io.servers.connection
 destructors calendar io.timeouts io.streams.duplex threads
-continuations math concurrency.promises byte-arrays sequences.lib
-hexdump ;
+continuations math concurrency.promises byte-arrays
+io.backend sequences.lib tools.hexdump io.files.listing ;
 IN: ftp.server
 
+TUPLE: ftp-client url mode state command-promise ;
+
+: <ftp-client> ( url -- ftp-client )
+    ftp-client new
+        swap >>url ;
+    
 SYMBOL: client
 
+: ftp-server-directory ( -- str )
+    \ ftp-server-directory get-global "resource:temp" or
+    normalize-path ;
+
 TUPLE: ftp-command raw tokenized ;
 
 : <ftp-command> ( -- obj )
@@ -139,7 +149,7 @@ M: ftp-list service-command ( stream obj -- )
     start-directory
     [
         utf8 encode-output
-        directory-list [ ftp-send ] each
+        directory. [ ftp-send ] each
     ] with-output-stream
     finish-directory ;
 
@@ -238,10 +248,16 @@ M: ftp-put service-command ( stream obj -- )
 ! : handle-LPRT ( obj -- ) tokenized>> "," split ;
 
 ERROR: not-a-directory ;
+ERROR: no-permissions ;
 
 : handle-CWD ( obj -- )
     [
-        tokenized>> second dup directory? [
+        tokenized>> second dup normalize-path
+        dup ftp-server-directory head? [
+            no-permissions
+        ] unless
+
+        file-info directory? [
             set-current-directory
             250 "Directory successully changed." server-response
         ] [
@@ -256,6 +272,7 @@ ERROR: not-a-directory ;
 
 : handle-client-loop ( -- )
     <ftp-command> readln
+    USE: prettyprint    global [ dup . flush ] bind
     [ >>raw ]
     [ tokenize-command >>tokenized ] bi
     dup tokenized>> first >upper {
@@ -313,7 +330,7 @@ TUPLE: ftp-server < threaded-server ;
 M: ftp-server handle-client* ( server -- )
     drop
     [
-        "" [
+        ftp-server-directory [
             host-name <ftp-client> client set
             send-banner handle-client-loop
         ] with-directory
@@ -323,6 +340,7 @@ M: ftp-server handle-client* ( server -- )
     ftp-server new-threaded-server
         swap >>insecure
         "ftp.server" >>name
+        5 minutes >>timeout
         latin1 >>encoding ;
 
 : ftpd ( port -- )
diff --git a/extra/hexdump/authors.txt b/extra/hexdump/authors.txt
deleted file mode 100644 (file)
index 7c1b2f2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Doug Coleman
diff --git a/extra/hexdump/hexdump-docs.factor b/extra/hexdump/hexdump-docs.factor
deleted file mode 100644 (file)
index 4278e92..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: help.markup help.syntax kernel sequences strings ;
-IN: hexdump
-
-HELP: hexdump.
-{ $values { "seq" sequence } }
-{ $description "Converts a sequence to its hexadecimal and ASCII representation sixteen characters at a time and writes it to standard out." } ;
-
-HELP: hexdump
-{ $values { "seq" sequence } { "str" string } }
-{ $description "Converts a sequence to its hexadecimal and ASCII representation sixteen characters at a time.  Lines are separated by a newline character." }
-{ $see-also hexdump. } ;
-
-ARTICLE: "hexdump" "Hexdump"
-"The " { $vocab-link "hexdump" } " vocabulary provides a traditional hexdump view of a sequence." $nl
-"Write hexdump to string:"
-{ $subsection hexdump }
-"Write the hexdump to the output stream:"
-{ $subsection hexdump. } ;
-
-ABOUT: "hexdump"
diff --git a/extra/hexdump/hexdump-tests.factor b/extra/hexdump/hexdump-tests.factor
deleted file mode 100644 (file)
index b3c0319..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-IN: hexdump.tests
-USING: hexdump kernel sequences tools.test ;
-
-[ t ] [ "" hexdump "Length: 0, 0h\n" = ] unit-test
-[ t ] [ "abcdefghijklmnopqrstuvwxyz" hexdump "Length: 26, 1ah\n00000000h: 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 abcdefghijklmnop\n00000010h: 71 72 73 74 75 76 77 78 79 7a                   qrstuvwxyz\n" = ] unit-test
-
-[ t ] [ 256 [ ] map hexdump "Length: 256, 100h\n00000000h: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n00000010h: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................\n00000020h: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f  !\"#$%&'()*+,-./\n00000030h: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?\n00000040h: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO\n00000050h: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\\]^_\n00000060h: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno\n00000070h: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.\n00000080h: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ................\n00000090h: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ................\n000000a0h: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ................\n000000b0h: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ................\n000000c0h: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ................\n000000d0h: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ................\n000000e0h: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ................\n000000f0h: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ................\n" = ] unit-test
-
-
-[
-    "Length: 3, 3h\n00000000h: 01 02 03                                        ...\n" ] [ B{ 1 2 3 } hexdump ] unit-test
diff --git a/extra/hexdump/hexdump.factor b/extra/hexdump/hexdump.factor
deleted file mode 100644 (file)
index ecbc2d6..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays io io.streams.string kernel math math.parser
-namespaces sequences splitting grouping strings ascii ;
-IN: hexdump
-
-<PRIVATE
-
-: write-header ( len -- )
-    "Length: " write
-    [ number>string write ", " write ]
-    [ >hex write "h" write nl ] bi ;
-
-: write-offset ( lineno -- )
-    16 * >hex 8 CHAR: 0 pad-left write "h: " write ;
-
-: >hex-digit ( digit -- str )
-    >hex 2 CHAR: 0 pad-left " " append ;
-
-: >hex-digits ( bytes -- str )
-    [ >hex-digit ] { } map-as concat 48 CHAR: \s pad-right ;
-
-: >ascii ( bytes -- str )
-    [ [ printable? ] keep CHAR: . ? ] "" map-as ;
-
-: write-hex-line ( bytes lineno -- )
-    write-offset [ >hex-digits write ] [ >ascii write ] bi nl ;
-
-PRIVATE>
-
-: hexdump. ( seq -- )
-    [ length write-header ]
-    [ 16 <sliced-groups> [ write-hex-line ] each-index ] bi ;
-
-: hexdump ( seq -- str )
-    [ hexdump. ] with-string-writer ;
diff --git a/extra/hexdump/summary.txt b/extra/hexdump/summary.txt
deleted file mode 100644 (file)
index d860bd7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Prints formatted hex dump of an arbitrary sequence
index 6a9359027d72947ab908d536dff8a2e3c53739b3..c402cdf15b3e7a6bdb71a737d4a66c790ac8deaf 100644 (file)
@@ -5,22 +5,22 @@ USING: help.markup help.syntax sequences strings lists ;
 IN: lists.lazy 
 
 HELP: lazy-cons
-{ $values { "car" "a quotation with stack effect ( -- X )" } { "cdr" "a quotation with stack effect ( -- cons )" } { "promise" "the resulting cons object" } }
+{ $values { "car" { $quotation "( -- X )" } } { "cdr" { $quotation "( -- cons )" } } { "promise" "the resulting cons object" } }
 { $description "Constructs a cons object for a lazy list from two quotations. The " { $snippet "car" } " quotation should return the head of the list, and the " { $snippet "cons" } " quotation the tail when called. When " { $link cons } " or " { $link cdr } " are called on the lazy-cons object then the appropriate quotation is called." } 
 { $see-also cons car cdr nil nil? } ;
 
 { 1lazy-list 2lazy-list 3lazy-list } related-words
 
 HELP: 1lazy-list
-{ $values { "a" "a quotation with stack effect ( -- X )" } { "lazy-cons" "a lazy-cons object" } }
+{ $values { "a" { $quotation "( -- X )" } } { "lazy-cons" "a lazy-cons object" } }
 { $description "Create a lazy list with 1 element. The element is the result of calling the quotation. The quotation is only called when the list element is requested." } ;
 
 HELP: 2lazy-list
-{ $values { "a" "a quotation with stack effect ( -- X )" } { "b" "a quotation with stack effect ( -- X )" } { "lazy-cons" "a lazy-cons object" } }
+{ $values { "a" { $quotation "( -- X )" } } { "b" { $quotation "( -- X )" } } { "lazy-cons" "a lazy-cons object" } }
 { $description "Create a lazy list with 2 elements. The elements are the result of calling the quotations. The quotations are only called when the list elements are requested." } ;
 
 HELP: 3lazy-list
-{ $values { "a" "a quotation with stack effect ( -- X )" } { "b" "a quotation with stack effect ( -- X )" } { "c" "a quotation with stack effect ( -- X )" } { "lazy-cons" "a lazy-cons object" } }
+{ $values { "a" { $quotation "( -- X )" } } { "b" { $quotation "( -- X )" } } { "c" { $quotation "( -- X )" } } { "lazy-cons" "a lazy-cons object" } }
 { $description "Create a lazy list with 3 elements. The elements are the result of calling the quotations. The quotations are only called when the list elements are requested." } ;
 
 HELP: <memoized-cons>
@@ -31,11 +31,11 @@ HELP: <memoized-cons>
 { lazy-map lazy-map-with ltake lfilter lappend lfrom lfrom-by lconcat lcartesian-product lcartesian-product* lcomp lcomp* lmerge lwhile luntil } related-words
 
 HELP: lazy-map
-{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( obj -- X )" } { "result" "resulting cons object" } }
+{ $values { "list" "a cons object" } { "quot" { $quotation "( obj -- X )" } } { "result" "resulting cons object" } }
 { $description "Perform a similar functionality to that of the " { $link map } " word, but in a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-map> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } ;
 
 HELP: lazy-map-with
-{ $values { "value" "an object" } { "list" "a cons object" } { "quot" "a quotation with stack effect ( obj elt -- X )" } { "result" "resulting cons object" } }
+{ $values { "value" "an object" } { "list" "a cons object" } { "quot" { $quotation "( obj elt -- X )" } } { "result" "resulting cons object" } }
 { $description "Variant of " { $link lazy-map } " which pushes a retained object on each invocation of the quotation." } ;
 
 HELP: ltake
@@ -43,15 +43,15 @@ HELP: ltake
 { $description "Outputs a lazy list containing the first n items in the list. This is done a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-take> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } ;
 
 HELP: lfilter
-{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( -- X )" } { "result" "resulting cons object" } }
+{ $values { "list" "a cons object" } { "quot" { $quotation "( -- X )" } } { "result" "resulting cons object" } }
 { $description "Perform a similar functionality to that of the " { $link filter } " word, but in a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-filter> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } ;
 
 HELP: lwhile
-{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( X -- bool )" } { "result" "resulting cons object" } }
+{ $values { "list" "a cons object" } { "quot" { $quotation "( X -- ? )" } } { "result" "resulting cons object" } }
 { $description "Outputs a lazy list containing the first items in the list as long as " { $snippet "quot" } " evaluates to t. No evaluation of the list elements occurs initially but a " { $link <lazy-while> } " object is returned with conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } ;
 
 HELP: luntil
-{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( X -- bool )" } { "result" "resulting cons object" } }
+{ $values { "list" "a cons object" } { "quot" { $quotation "( X -- ? )" } } { "result" "resulting cons object" } }
 { $description "Outputs a lazy list containing the first items in the list until after " { $snippet "quot" } " evaluates to t. No evaluation of the list elements occurs initially but a " { $link <lazy-while> } " object is returned with conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required." } ;
 
 HELP: list>vector
@@ -69,7 +69,7 @@ HELP: lappend
 { $description "Perform a similar functionality to that of the " { $link append } " word, but in a lazy manner. No evaluation of the list elements occurs initially but a " { $link <lazy-append> } " object is returned which conforms to the list protocol. Calling " { $link car } ", " { $link cdr } " or " { $link nil? } " on this will evaluate elements as required. Successive calls to " { $link cdr } " will iterate through list1, followed by list2." } ;
 
 HELP: lfrom-by
-{ $values { "n" "an integer" } { "quot" "a quotation with stack effect ( -- int )" } { "list" "a lazy list of integers" } }
+{ $values { "n" "an integer" } { "quot" { $quotation "( -- int )" } } { "list" "a lazy list of integers" } }
 { $description "Return an infinite lazy list of values starting from n, with each successive value being the result of applying quot to n." } ;
 
 HELP: lfrom
@@ -101,11 +101,11 @@ HELP: lcartesian-product*
 { $description "Given a list of lists, return a list containing the cartesian product of those lists." } ;
 
 HELP: lcomp
-{ $values { "list" "a list of lists" } { "quot" "a quotation with stack effect ( seq -- X )" } { "result" "the resulting list" } }
+{ $values { "list" "a list of lists" } { "quot" { $quotation "( seq -- X )" } } { "result" "the resulting list" } }
 { $description "Get the cartesian product of the lists in " { $snippet "list" } " and call " { $snippet "quot" } " call with each element from the cartesian product on the stack, the result of which is returned in the final " { $snippet "list" } "." } ;
 
 HELP: lcomp*
-{ $values { "list" "a list of lists" } { "guards" "a sequence of quotations with stack effect ( seq -- bool )" } { "quot" "a quotation with stack effect ( seq -- X )" } { "list" "the resulting list" } { "result" "a list" } }
+{ $values { "list" "a list of lists" } { "guards" "a sequence of quotations with stack effect ( seq -- bool )" } { "quot" { $quotation "( seq -- X )" } } { "list" "the resulting list" } { "result" "a list" } }
 { $description "Get the cartesian product of the lists in " { $snippet "list" } ", filter it by applying each guard quotation to it and call " { $snippet "quot" } " call with each element from the remaining cartesian product items on the stack, the result of which is returned in the final " { $snippet "list" } "." }
 { $examples
   { $code "{ 1 2 3 } >list { 4 5 6 } >list 2list { [ first odd? ] } [ first2 + ] lcomp*" }
index cd2e6f7081d3883dc6c6197b9aaad93f8f19114a..8807c8cf8a783e65607786e6ddef9a4f0597464c 100644 (file)
@@ -61,19 +61,19 @@ HELP: uncons
 { leach foldl lmap>array } related-words
 
 HELP: leach
-{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( obj -- )" } }
+{ $values { "list" "a cons object" } { "quot" { $quotation "( obj -- )" } } }
 { $description "Call the quotation for each item in the list." } ;
 
 HELP: foldl
-{ $values { "list" "a cons object" } { "identity" "an object" } { "quot" "a quotation with stack effect ( prev elt -- next )" } { "result" "the final result" } }
+{ $values { "list" "a cons object" } { "identity" "an object" } { "quot" { $quotation "( prev elt -- next )" } } { "result" "the final result" } }
 { $description "Combines successive elements of the list (in a left-assocative order) using a binary operation and outputs the final result." } ;
 
 HELP: foldr
-{ $values { "list" "a cons object" } { "identity" "an object" } { "quot" "a quotation with stack effect ( prev elt -- next )" } { "result" "the final result" } }
+{ $values { "list" "a cons object" } { "identity" "an object" } { "quot" { $quotation "( prev elt -- next )" } } { "result" "the final result" } }
 { $description "Combines successive elements of the list (in a right-assocative order) using a binary operation, and outputs the final result." } ;
 
 HELP: lmap
-{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( old -- new )" } { "result" "the final result" } }
+{ $values { "list" "a cons object" } { "quot" { $quotation "( old -- new )" } } { "result" "the final result" } }
 { $description "Applies the quotation to each element of the list in order, collecting the new elements into a new list." } ;
     
 HELP: lreverse
@@ -97,8 +97,8 @@ HELP: seq>cons
 { $description "Recursively turns the given sequence into a cons object, maintaing order and also converting nested lists." } ;
     
 HELP: traverse    
-{ $values { "list"  "a cons object" } { "pred" "a quotation with stack effect ( list/elt -- ? )" }
-          { "quot" "a quotation with stack effect ( list/elt -- result)" }  { "result" "a new cons object" } }
+{ $values { "list"  "a cons object" } { "pred" { $quotation "( list/elt -- ? )" } }
+          { "quot" { $quotation "( list/elt -- result)" } }  { "result" "a new cons object" } }
 { $description "Recursively traverses the list object, replacing any elements (which can themselves be sublists) that pred" 
     " returns true for with the result of applying quot to." } ;
     
index dfda85e4d75626663135769cc6283b54fb510f78..24a1292be352b5815fe9603a6d8a2ea551854850 100644 (file)
@@ -3,7 +3,7 @@
 USING: kernel namespaces sequences splitting system accessors
 math.functions make io io.files io.launcher io.encodings.utf8
 prettyprint combinators.short-circuit parser combinators
-calendar calendar.format arrays mason.config ;
+calendar calendar.format arrays mason.config locals ;
 IN: mason.common
 
 : short-running-process ( command -- )
@@ -13,6 +13,13 @@ IN: mason.common
         15 minutes >>timeout
     try-process ;
 
+:: upload-safely ( local username host remote -- )
+    [let* | temp [ remote ".incomplete" append ]
+            scp-remote [ { username "@" host ":" temp } concat ] |
+        { "scp" local scp-remote } short-running-process
+        { "ssh" host "-l" username "mv" temp remote } short-running-process
+    ] ;
+
 : eval-file ( file -- obj )
     dup utf8 file-lines parse-fresh
     [ "Empty file: " swap append throw ] [ nip first ] if-empty ;
@@ -71,6 +78,7 @@ SYMBOL: stamp
 : test-time-file "test-time" ;
 : help-lint-time-file "help-lint-time" ;
 : benchmark-time-file "benchmark-time" ;
+: html-help-time-file "html-help-time" ;
 
 : benchmarks-file "benchmarks" ;
 
index 0ce059c995605fbf36b1014f18ea8dd27a271bf5..e4ef127413d88e33bf2177f99926a01adc56b35f 100644 (file)
@@ -33,10 +33,23 @@ target-os get-global [
 ! Keep test-log around?
 SYMBOL: builder-debug
 
+SYMBOL: upload-help?
+
+! The below are only needed if upload-help is true.
+
+! Host with HTML help
+SYMBOL: help-host
+
+! Username to log in.
+SYMBOL: help-username
+
+! Directory to upload docs to.
+SYMBOL: help-directory
+
 ! Boolean. Do we release binaries and update the clean branch?
-SYMBOL: upload-to-factorcode
+SYMBOL: upload-to-factorcode?
 
-! The below are only needed if upload-to-factorcode is true.
+! The below are only needed if upload-to-factorcode? is true.
 
 ! Host with clean git repo.
 SYMBOL: branch-host
diff --git a/extra/mason/help/help.factor b/extra/mason/help/help.factor
new file mode 100644 (file)
index 0000000..1e3e150
--- /dev/null
@@ -0,0 +1,23 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.html sequences io.files io.launcher make namespaces
+kernel arrays mason.common mason.config ;
+IN: mason.help
+
+: make-help-archive ( -- )
+    "factor/temp" [
+        { "tar" "cfz" "docs.tar.gz" "docs" } try-process
+    ] with-directory ;
+
+: upload-help-archive ( -- )
+    "factor/temp/docs.tar.gz"
+    help-username get
+    help-host get
+    help-directory get "/docs.tar.gz" append
+    upload-safely ;
+
+: upload-help ( -- )
+    upload-help? get [
+        make-help-archive
+        upload-help-archive
+    ] when ;
index 8872cda5b51b6cdc60627b84370647933aa263a6..ff2632a9b3a709a39959f9f9cf0b439c0c682ce6 100644 (file)
@@ -45,4 +45,4 @@ IN: mason.release.branch
     ] with-directory ;
 
 : update-clean-branch ( -- )
-    upload-to-factorcode get [ (update-clean-branch) ] when ;
+    upload-to-factorcode? get [ (update-clean-branch) ] when ;
index 9f5300b129fc35446220680f586f7884d6414288..73fc311399465537879c25a0e8a8dc3475bfc49f 100644 (file)
@@ -1,38 +1,4 @@
 IN: mason.release.upload.tests
-USING: mason.release.upload mason.common mason.config
-mason.common namespaces calendar tools.test ;
-
-[
-    {
-        "scp"
-        "factor-linux-ppc-2008-09-11-23-12.tar.gz"
-        "slava@www.apple.com:/uploads/linux-ppc/factor-linux-ppc-2008-09-11-23-12.tar.gz.incomplete"
-    }
-    {
-        "ssh"
-        "www.apple.com"
-        "-l" "slava"
-        "mv"
-        "/uploads/linux-ppc/factor-linux-ppc-2008-09-11-23-12.tar.gz.incomplete"
-        "/uploads/linux-ppc/factor-linux-ppc-2008-09-11-23-12.tar.gz"
-    }
-] [
-    [
-        "slava" upload-username set
-        "www.apple.com" upload-host set
-        "/uploads" upload-directory set
-        "linux" target-os set
-        "ppc" target-cpu set
-        T{ timestamp
-            { year 2008 }
-            { month 09 }
-            { day 11 }
-            { hour 23 }
-            { minute 12 }
-        } datestamp stamp set
-        upload-command
-        rename-command
-    ] with-scope
-] unit-test
+USING: mason.release.upload tools.test ;
 
 \ upload must-infer
index 2bf18f11265ef75790ffb33a092c4ad6fc580e2e..68f2ffcdb5f866bd8be8b17bcfd7f2b4bdbbe531 100644 (file)
@@ -11,37 +11,11 @@ IN: mason.release.upload
 : remote-archive-name ( -- dest )
     remote-location "/" archive-name 3append ;
 
-: temp-archive-name ( -- dest )
-    remote-archive-name ".incomplete" append ;
-
-: upload-command ( -- args )
-    "scp"
-    archive-name
-    [
-        upload-username get % "@" %
-        upload-host get % ":" %
-        temp-archive-name %
-    ] "" make
-    3array ;
-
-: rename-command ( -- args )
-    [
-        "ssh" ,
-        upload-host get ,
-        "-l" ,
-        upload-username get ,
-        "mv" ,
-        temp-archive-name ,
-        remote-archive-name ,
-    ] { } make ;
-
-: upload-temp-file ( -- )
-    upload-command short-running-process ;
-
-: rename-temp-file ( -- )
-    rename-command short-running-process ;
-
 : upload ( -- )
-    upload-to-factorcode get
-    [ upload-temp-file rename-temp-file ]
-    when ;
+    upload-to-factorcode? get [
+        archive-name
+        upload-username get
+        upload-host get
+        remote-archive-name
+        upload-safely
+    ] when ;
index 145686d6217279fe833b22b1e5481f963e4c5e6c..0b5f21540aaf1f4fc98d4dc294b6e2f7af83ab20 100644 (file)
@@ -46,6 +46,7 @@ IN: mason.report
         test-time-file time.
         help-lint-time-file time.
         benchmark-time-file time.
+        html-help-time-file time.
 
         nl
 
index 58884175a311ba031bd398647e418f406bacc0c1..cc83c9db44b27aaa7d0e5adf5efe9c56fad39f90 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel namespaces assocs io.files io.encodings.utf8
 prettyprint help.lint benchmark tools.time bootstrap.stage2
-tools.test tools.vocabs mason.common ;
+tools.test tools.vocabs help.html mason.common ;
 IN: mason.test
 
 : do-load ( -- )
@@ -30,6 +30,7 @@ IN: mason.test
     ".." [
         bootstrap-time get boot-time-file to-file
         [ do-load ] benchmark load-time-file to-file
+        [ generate-help ] benchmark html-help-time-file to-file
         [ do-tests ] benchmark test-time-file to-file
         [ do-help-lint ] benchmark help-lint-time-file to-file
         [ do-benchmarks ] benchmark benchmark-time-file to-file
index 93e68eac4a709738dce99c5de68df83b42b55b17..a70109347bdbc6295e76ff3b884d5d75556f71f8 100644 (file)
@@ -2,12 +2,12 @@ IN: partial-continuations
 USING: help.markup help.syntax kernel ;
 
 HELP: breset
-{ $values { "quot" "a quotation with stack effect " { $snippet "( r -- v )" } } }
+{ $values { "quot" { $quotation "( r -- v )" } } }
 { $description "Marks the boundary of the partial continuation. The quotation has stack effect " { $snippet "( r -- v )" } ", where " { $snippet "r" } " identifies the " { $link breset } " in scope and should be passed to  "{ $link bshift } " to mark the boundary of the continuation." }
 { $notes "It is important to note that even if the quotation discards items on the stack, the stack will be restored to the way it was before it is called (which is true of continuation usage in general)." } ;
 
 HELP: bshift
-{ $values { "r" "the " { $link breset } " in scope" } { "quot" "a quotation with stack effect " { $snippet "( pcc -- v )" } } }
+{ $values { "r" "the " { $link breset } " in scope" } { "quot" { $quotation "( pcc -- v )" } } }
 { $description "Calls the quotation with the partial continuation  on the stack. The quotation should have stack effect " { $snippet "( pcc -- v )" } ". The partial continuation can be called with " { $link call } " and has stack effect " { $snippet "( a -- b )" } "." }
 { $notes "It is important to note that even if the quotation discards items on the stack, the stack will be restored to the way it was before it is called (which is true of continuation usage in general)." } ;
 
index c482df0d1574f593e50ffc5221988d6a998fb20a..4e8dc9a9a2ed5201673463c7400b4fe0897b4312 100755 (executable)
@@ -5,17 +5,17 @@ USING: help.markup help.syntax ;
 IN: promises
 
 HELP: promise 
-{ $values { "quot" "a quotation with stack effect ( -- X )" } { "promise" "a promise object" } }
+{ $values { "quot" { $quotation "( -- X )" } } { "promise" "a promise object" } }
 { $description "Creates a promise to return a value. When forced this quotation is called and the value returned. The value is memorised so that calling " { $link force } " again does not call the quotation again, instead the previous value is returned directly." } 
 { $see-also force promise-with promise-with2 } ;
 
 HELP: promise-with
-{ $values { "value" "an object" } { "quot" "a quotation with stack effect ( value -- X )" } { "promise" "a promise object" } }
+{ $values { "value" "an object" } { "quot" { $quotation "( value -- X )" } } { "promise" "a promise object" } }
 { $description "Creates a promise to return a value. When forced this quotation is called with the given value on the stack and the result returned. The value is memorised so that calling " { $link force } " again does not call the quotation again, instead the previous value is returned directly." } 
 { $see-also force promise promise-with2 } ;
 
 HELP: promise-with2
-{ $values { "value1" "an object" } { "value2" "an object" } { "quot" "a quotation with stack effect ( value1 value2 -- X )" } { "promise" "a promise object" } }
+{ $values { "value1" "an object" } { "value2" "an object" } { "quot" { $quotation "( value1 value2 -- X )" } } { "promise" "a promise object" } }
 { $description "Creates a promise to return a value. When forced this quotation is called with the given values on the stack and the result returned. The value is memorised so that calling " { $link force } " again does not call the quotation again, instead the previous value is returned directly." } 
 { $see-also force promise promise-with2 } ;
 
diff --git a/extra/suffix-arrays/authors.txt b/extra/suffix-arrays/authors.txt
deleted file mode 100755 (executable)
index e4a36df..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Marc Fauconneau
\ No newline at end of file
diff --git a/extra/suffix-arrays/suffix-arrays-docs.factor b/extra/suffix-arrays/suffix-arrays-docs.factor
deleted file mode 100755 (executable)
index 87df272..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-! Copyright (C) 2008 Marc Fauconneau.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays help.markup help.syntax io.streams.string
-sequences strings math suffix-arrays.private ;
-IN: suffix-arrays
-
-HELP: >suffix-array
-{ $values
-     { "seq" sequence }
-     { "array" array } }
-{ $description "Creates a suffix array from the input sequence.  Suffix arrays are arrays of slices." } ;
-
-HELP: SA{
-{ $description "Creates a new literal suffix array at parse-time." } ;
-
-HELP: suffixes
-{ $values
-     { "string" string }
-     { "suffixes-seq" "a sequence of slices" } }
-{ $description "Returns a sequence of tail slices of the input string." } ;
-
-HELP: from-to
-{ $values
-     { "index" integer } { "begin" sequence } { "suffix-array" "a suffix-array" }
-     { "from/f" "an integer or f" } { "to/f" "an integer or f" } }
-{ $description "Finds the bounds of the suffix array that match the input sequence. A return value of " { $link f } " means that the endpoint is included." }
-{ $notes "Slices are [m,n) and we want (m,n) so we increment." } ;
-
-HELP: query
-{ $values
-     { "begin" sequence } { "suffix-array" "a suffix-array" }
-     { "matches" array } }
-{ $description "Returns a sequence of sequences from the suffix-array that contain the input sequence. An empty array is returned when there are no matches." } ;
-
-ARTICLE: "suffix-arrays" "Suffix arrays"
-"The " { $vocab-link "suffix-arrays" } " vocabulary implements the suffix array data structure for efficient lookup of subsequences. This suffix array implementation is a sorted array of suffixes. Querying it for matches uses binary search for efficiency." $nl
-
-"Creating new suffix arrays:"
-{ $subsection >suffix-array }
-"Literal suffix arrays:"
-{ $subsection POSTPONE: SA{ }
-"Querying suffix arrays:"
-{ $subsection query } ;
-
-ABOUT: "suffix-arrays"
diff --git a/extra/suffix-arrays/suffix-arrays-tests.factor b/extra/suffix-arrays/suffix-arrays-tests.factor
deleted file mode 100755 (executable)
index 5149804..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-! Copyright (C) 2008 Marc Fauconneau.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test suffix-arrays kernel namespaces sequences ;
-IN: suffix-arrays.tests
-
-! built from [ all-words 10 head [ name>> ] map ]
-[ ] [ 
-     {
-        "run-tests"
-        "must-fail-with"
-        "test-all"
-        "short-effect"
-        "failure"
-        "test"
-        "<failure>"
-        "this-test"
-        "(unit-test)"
-        "unit-test"
-    } >suffix-array "suffix-array" set
-] unit-test
-
-[ t ]
-[ "suffix-array" get "" swap query empty? not ] unit-test
-
-[ { } ]
-[ SA{ } "something" swap query ] unit-test
-
-[ V{ "unit-test" "(unit-test)" } ]
-[ "suffix-array" get "unit-test" swap query ] unit-test
-
-[ t ]
-[ "suffix-array" get "something else" swap query empty? ] unit-test
-
-[ V{ "rofl" } ] [ SA{ "rofl" } "r" swap query ] unit-test
-[ V{ "rofl" } ] [ SA{ "rofl" } "o" swap query ] unit-test
-[ V{ "rofl" } ] [ SA{ "rofl" } "f" swap query ] unit-test
-[ V{ "rofl" } ] [ SA{ "rofl" } "l" swap query ] unit-test
-[ V{ } ] [ SA{ "rofl" } "t" swap query ] unit-test
diff --git a/extra/suffix-arrays/suffix-arrays.factor b/extra/suffix-arrays/suffix-arrays.factor
deleted file mode 100755 (executable)
index b181ba9..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-! Copyright (C) 2008 Marc Fauconneau.
-! See http://factorcode.org/license.txt for BSD license.
-USING: parser kernel arrays math accessors sequences
-math.vectors math.order sorting binary-search sets assocs fry ;
-IN: suffix-arrays
-
-<PRIVATE
-: suffixes ( string -- suffixes-seq )
-    dup length [ tail-slice ] with map ;
-
-: prefix<=> ( begin seq -- <=> )
-    [ <=> ] [ swap head? ] 2bi [ drop +eq+ ] when ;
-: find-index ( begin suffix-array -- index/f )
-    [ prefix<=> ] with search drop ;
-
-: from-to ( index begin suffix-array -- from/f to/f )
-    swap '[ _ head? not ]
-    [ find-last-from drop dup [ 1+ ] when ]
-    [ find-from drop ] 3bi ;
-
-: <funky-slice> ( from/f to/f seq -- slice )
-    [
-        tuck
-        [ drop 0 or ] [ length or ] 2bi*
-        [ min ] keep
-    ] keep <slice> ; inline
-
-PRIVATE>
-
-: >suffix-array ( seq -- array )
-    [ suffixes ] map concat natural-sort ;
-
-: SA{ \ } [ >suffix-array ] parse-literal ; parsing
-
-: query ( begin suffix-array -- matches )
-    2dup find-index dup
-    [ -rot [ from-to ] keep <funky-slice> [ seq>> ] map prune ]
-    [ 3drop { } ] if ;
diff --git a/extra/suffix-arrays/summary.txt b/extra/suffix-arrays/summary.txt
deleted file mode 100755 (executable)
index 71eda47..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Suffix arrays
diff --git a/extra/suffix-arrays/tags.txt b/extra/suffix-arrays/tags.txt
deleted file mode 100755 (executable)
index 42d711b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-collections
diff --git a/extra/suffix-arrays/words/words.factor b/extra/suffix-arrays/words/words.factor
deleted file mode 100755 (executable)
index 74e2fc2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-! Copyright (C) 2008 Marc Fauconneau.\r
-! See http://factorcode.org/license.txt for BSD license.\r
-USING: kernel arrays math accessors sequences math.vectors\r
-math.order sorting binary-search sets assocs fry suffix-arrays ;\r
-IN: suffix-arrays.words\r
-\r
-! to search on word names\r
-\r
-: new-word-sa ( words -- sa )\r
-    [ name>> ] map >suffix-array ;\r
-\r
-: name>word-map ( words -- map )\r
-    dup [ name>> V{ } clone ] H{ } map>assoc\r
-    [ '[ dup name>> _ at push ] each ] keep ;\r
-\r
-: query-word-sa ( map begin sa -- matches ) query '[ _ at ] map concat ;\r
-\r
-! usage example :\r
-! clear all-words 100 head dup name>word-map "test" rot new-word-sa query .\r
index 286ac0183a0d2398b7fc9486a7f0cf78b6447cb5..e3c14854d3b29aa861679fd1533858766645ab0d 100755 (executable)
@@ -1,6 +1,6 @@
 USING: combinators io io.files io.streams.string kernel math
 math.parser continuations namespaces pack prettyprint sequences
-strings system hexdump io.encodings.binary summary accessors
+strings system tools.hexdump io.encodings.binary summary accessors
 io.backend symbols byte-arrays ;
 IN: tar
 
index 9cb0250518424253d7114fb2dcc88b6fc3617740..a2741ccd4ea133186c98dfd439e6a97aff94a6d5 100644 (file)
@@ -13,5 +13,5 @@
                </t:form>
        </div>
 
-       <t:validation-messages />
+       <t:validation-errors />
 </t:chloe>
index f41e8a97b481e2713ca6e5e719525f05cedb347a..27b6beaec67feadb597d937dd06761035dcd08f0 100644 (file)
@@ -51,7 +51,7 @@
        
        <p>
                <button type="submit" >Update</button>
-               <t:validation-messages />
+               <t:validation-errors />
        </p>
 
        </t:form>
index 7acdd384ba920e3c17715e866178551775465162..d3cf681165868caadcfac5e2de48d1e37e8dea85 100644 (file)
@@ -46,7 +46,7 @@
        
        <p>
                <button type="submit" class="link-button link">Create</button>
-               <t:validation-messages />
+               <t:validation-errors />
        </p>
 
        </t:form>
diff --git a/extra/webapps/user-admin/user-admin-docs.factor b/extra/webapps/user-admin/user-admin-docs.factor
new file mode 100644 (file)
index 0000000..3551210
--- /dev/null
@@ -0,0 +1,22 @@
+USING: help.markup help.syntax db strings ;
+IN: webapps.user-admin
+
+HELP: <user-admin>
+{ $values { "responder" "a new responder" } }
+{ $description "Creates a new instance of the user admin tool. This tool must be added to an authentication realm, and access is restricted to users having the " { $link can-administer-users? } " capability." } ;
+
+HELP: can-administer-users?
+{ $description "A user capability. Users having this capability may use the " { $link user-admin } " tool." }
+{ $notes "See " { $link "furnace.auth.capabilities" } " for information about capabilities." } ;
+
+HELP: make-admin
+{ $values { "username" string } }
+{ $description "Makes an existing user into an administrator by giving them the " { $link can-administer-users? } " capability, thus allowing them to use the user admin tool." } ;
+
+ARTICLE: "furnace.auth.user-admin" "Furnace user administration tool"
+"The " { $vocab-link "webapps.user-admin" } " vocabulary implements a web application for adding, removing and editing users in authentication realms that use " { $link "furnace.auth.providers.db" } "."
+{ $subsection <user-admin> }
+"Access to the web app itself is protected, and only users having an administrative capability can access it:"
+{ $subsection can-administer-users? }
+"To make an existing user an administrator, call the following word in a " { $link with-db } " scope:"
+{ $subsection make-admin } ;
index 1ae8919559ca0d56779d302f02612a3e9bfbbe13..2d222187e49ccefc6f5c2fc4c6d719c5cd227bf3 100644 (file)
 
 ;; M-x run-factor === Start a Factor listener inside Emacs
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;; BUG: A double quote character on a commented line will break the
-;; syntax highlighting for that line.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Customization
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defgroup factor nil
   "Factor mode"
   :group 'languages)
 
-(defvar factor-mode-syntax-table nil
-  "Syntax table used while in Factor mode.")
+(defcustom factor-default-indent-width 4
+  "Default indentantion width for factor-mode.
+
+This value will be used for the local variable
+`factor-indent-width' in new factor buffers. For existing code,
+we first check if `factor-indent-width' is set explicitly in a
+local variable section or line (e.g. '! -*- factor-indent-witdth: 2 -*-').
+If that's not the case, `factor-mode' tries to infer its correct
+value from the existing code in the buffer."
+  :type 'integer
+  :group 'factor)
 
 (defcustom factor-display-compilation-output t
   "Display the REPL buffer before compiling files."
   :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil))
   :group 'factor)
 
+(defcustom factor-mode-hook nil
+  "Hook run when entering Factor mode."
+  :type 'hook
+  :group 'factor)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; factor-mode syntax
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar factor-mode-syntax-table nil
+  "Syntax table used while in Factor mode.")
 
 (if factor-mode-syntax-table
     ()
     (modify-syntax-entry ?\) ")(" factor-mode-syntax-table)
     (modify-syntax-entry ?\" "\"    " factor-mode-syntax-table)))
 
-(defvar factor-mode-map (make-sparse-keymap))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; factor-mode font lock
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defcustom factor-mode-hook nil
-  "Hook run when entering Factor mode."
-  :type 'hook
-  :group 'factor)
+(require 'font-lock)
 
-(defconst factor-font-lock-keywords
-  '(("#!.*$" . font-lock-comment-face)
-    ("!( .* )" . font-lock-comment-face)
-    ("^!.*$" . font-lock-comment-face)
-    (" !.*$" . font-lock-comment-face)
-    ("( .* )" . font-lock-comment-face)
-    "BIN:"
-    "MAIN:"
-    "IN:" "USING:" "TUPLE:" "^C:" "^M:"
-    "METHOD:"
-    "USE:" "REQUIRE:" "PROVIDE:"
-    "REQUIRES:"
-    "GENERIC:" "GENERIC#" "SYMBOL:" "PREDICATE:" "VAR:" "VARS:"
-    "C-STRUCT:"
-    "C-UNION:" "<PRIVATE" "PRIVATE>" "MACRO:" "MACRO::" "DEFER:" "TYPEDEF:"
-    "SYMBOLS:"
-))
+(defgroup factor-faces nil
+  "Faces used in Factor mode"
+  :group 'factor
+  :group 'faces)
 
-(defun factor-indent-line ()
-  "Indent current line as Factor code"
-  (indent-line-to (+ (current-indentation) 4)))
+(defsubst factor--face (face) `((t ,(face-attr-construct face))))
 
-(defun factor-mode ()
-  "A mode for editing programs written in the Factor programming language."
-  (interactive)
-  (kill-all-local-variables)
-  (use-local-map factor-mode-map)
-  (setq major-mode 'factor-mode)
-  (setq mode-name "Factor")
-  (set (make-local-variable 'indent-line-function) #'factor-indent-line)
-  (make-local-variable 'comment-start)
-  (setq comment-start "! ")
-  (make-local-variable 'font-lock-defaults)
-  (setq font-lock-defaults
-       '(factor-font-lock-keywords nil nil nil nil))
-  (set-syntax-table factor-mode-syntax-table)
-  (make-local-variable 'indent-line-function)
-  (setq indent-line-function 'factor-indent-line)
-  (run-hooks 'factor-mode-hook))
+(defface factor-font-lock-parsing-word (factor--face font-lock-keyword-face)
+  "Face for parsing words."
+  :group 'factor-faces)
 
-(add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
+(defface factor-font-lock-comment (factor--face font-lock-comment-face)
+  "Face for comments."
+  :group 'factor-faces)
+
+(defface factor-font-lock-string (factor--face font-lock-string-face)
+  "Face for strings."
+  :group 'factor-faces)
+
+(defface factor-font-lock-stack-effect (factor--face font-lock-comment-face)
+  "Face for stack effect specifications."
+  :group 'factor-faces)
+
+(defface factor-font-lock-word-definition (factor--face font-lock-function-name-face)
+  "Face for word, generic or method being defined."
+  :group 'factor-faces)
 
+(defface factor-font-lock-symbol-definition (factor--face font-lock-variable-name-face)
+  "Face for name of symbol being defined."
+  :group 'factor-faces)
+
+(defface factor-font-lock-vocabulary-name (factor--face font-lock-constant-face)
+  "Face for names of vocabularies in USE or USING."
+  :group 'factor-faces)
+
+(defface factor-font-lock-type-definition (factor--face font-lock-type-face)
+  "Face for type (tuple) names."
+  :group 'factor-faces)
+
+(defface factor-font-lock-parsing-word (factor--face font-lock-keyword-face)
+  "Face for parsing words."
+  :group 'factor-faces)
+
+(defconst factor--parsing-words
+  '("{" "}" "^:" "^::" ";" "<<" "<PRIVATE" ">>"
+    "BIN:" "BV{" "B{" "C:" "C-STRUCT:" "C-UNION:" "CHAR:" "CS{" "C{"
+    "DEFER:" "ERROR:" "EXCLUDE:" "FORGET:"
+    "GENERIC#" "GENERIC:" "HEX:" "HOOK:" "H{"
+    "IN:" "INSTANCE:" "INTERSECTION:"
+    "M:" "MACRO:" "MACRO::" "MAIN:" "MATH:" "METHOD:" "MIXIN:"
+    "OCT:" "POSTPONE:" "PREDICATE:" "PRIMITIVE:" "PRIVATE>" "PROVIDE:"
+    "REQUIRE:"  "REQUIRES:" "SINGLETON:" "SLOT:" "SYMBOL:" "SYMBOLS:"
+    "TUPLE:" "T{" "t\\??" "TYPEDEF:"
+    "UNION:" "USE:" "USING:" "V{" "VAR:" "VARS:" "W{"))
+
+(defconst factor--regex-parsing-words-ext
+  (regexp-opt '("B" "call-next-method" "delimiter" "f" "flushable" "foldable"
+                "initial:" "inline" "parsing" "read-only" "recursive")
+              'words))
+
+(defsubst factor--regex-second-word (prefixes)
+  (format "^%s +\\([^ \r\n]+\\)" (regexp-opt prefixes t)))
+
+(defconst factor--regex-word-definition
+  (factor--regex-second-word '(":" "::" "M:" "GENERIC:")))
+
+(defconst factor--regex-type-definition
+  (factor--regex-second-word '("TUPLE:")))
+
+(defconst factor--regex-symbol-definition
+  (factor--regex-second-word '("SYMBOL:")))
+
+(defconst factor--regex-using-line "^USING: +\\([^;]*\\);")
+(defconst factor--regex-use-line "^USE: +\\(.*\\)$")
+
+(defconst factor-font-lock-keywords
+  `(("#!.*$" . 'factor-font-lock-comment)
+    ("!( .* )" . 'factor-font-lock-comment)
+    ("^!.*$" . 'factor-font-lock-comment)
+    (" !.*$" . 'factor-font-lock-comment)
+    ("( .* )" . 'factor-font-lock-stack-effect)
+    ("\"\\(\\\\\"\\|[^\"]\\)*\"" . 'factor-font-lock-string)
+    ("\\(P\\|SBUF\\)\"" 1 'factor-font-lock-parsing-word)
+    ,@(mapcar #'(lambda (w) (cons (concat "\\(^\\| \\)\\(" w "\\)\\($\\| \\)")
+                             '(2 'factor-font-lock-parsing-word)))
+              factor--parsing-words)
+    (,factor--regex-parsing-words-ext . 'factor-font-lock-parsing-word)
+    (,factor--regex-word-definition 2 'factor-font-lock-word-definition)
+    (,factor--regex-type-definition 2 'factor-font-lock-type-definition)
+    (,factor--regex-symbol-definition 2 'factor-font-lock-symbol-definition)
+    (,factor--regex-using-line 1 'factor-font-lock-vocabulary-name)
+    (,factor--regex-use-line 1 'factor-font-lock-vocabulary-name)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; factor-mode commands
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (require 'comint)
   (beginning-of-line)
   (insert "! "))
 
+(defvar factor-mode-map (make-sparse-keymap))
+
 (define-key factor-mode-map "\C-c\C-f" 'factor-run-file)
 (define-key factor-mode-map "\C-c\C-r" 'factor-send-region)
 (define-key factor-mode-map "\C-c\C-d" 'factor-send-definition)
 (define-key factor-mode-map [tab]      'indent-for-tab-command)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; indentation
+;; factor-mode indentation
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defconst factor-word-starting-keywords
     "^\\(%s\\): "
     (mapconcat 'identity ,keywords "\\|")))
 
+(defvar factor-indent-width factor-default-indent-width
+  "Indentation width in factor buffers. A local variable.")
+
+(make-variable-buffer-local 'factor-indent-width)
+
+(defun factor--guess-indent-width ()
+  "Chooses an indentation value from existing code."
+  (let ((word-def (factor-word-start-re factor-word-starting-keywords))
+        (word-cont "^ +[^ ]")
+        (iw))
+    (save-excursion
+      (beginning-of-buffer)
+      (while (not iw)
+        (if (not (re-search-forward word-def nil t))
+            (setq iw factor-default-indent-width)
+          (forward-line)
+          (when (looking-at word-cont)
+            (setq iw (current-indentation))))))
+    iw))
+
 (defun factor-calculate-indentation ()
   "Calculate Factor indentation for line at point."
   (let ((not-indented t)
               (let ((cur-depth (factor-brackets-depth)))
                 (forward-line -1)
                 (setq cur-indent (+ (current-indentation)
-                                    (* default-tab-width
+                                    (* factor-indent-width
                                        (- cur-depth (factor-brackets-depth)))))
                 (setq not-indented nil)))
             (forward-line -1)
               ;; Check that we are after the end of previous word
               (if (looking-at ".*;[ \t]*$")
                   (progn
-                    (setq cur-indent (- (current-indentation) default-tab-width))
+                    (setq cur-indent (- (current-indentation) factor-indent-width))
                     (setq not-indented nil))
                 ;; Check that we are after the start of word
                 (if (looking-at (factor-word-start-re factor-word-starting-keywords))
 ;                (if (looking-at "^[A-Z:]*: ")
                     (progn
                       (message "inword")
-                      (setq cur-indent (+ (current-indentation) default-tab-width))
+                      (setq cur-indent (+ (current-indentation) factor-indent-width))
                       (setq not-indented nil))
                   (if (bobp)
                       (setq not-indented nil))))))))
       (if (> (- (point-max) pos) (point))
           (goto-char (- (point-max) pos))))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; factor-mode
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun factor-mode ()
+  "A mode for editing programs written in the Factor programming language.
+\\{factor-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map factor-mode-map)
+  (setq major-mode 'factor-mode)
+  (setq mode-name "Factor")
+  (set (make-local-variable 'indent-line-function) #'factor-indent-line)
+  (set (make-local-variable 'comment-start) "! ")
+  (set (make-local-variable 'font-lock-defaults)
+       '(factor-font-lock-keywords t nil nil nil))
+  (set-syntax-table factor-mode-syntax-table)
+  (set (make-local-variable 'indent-line-function) 'factor-indent-line)
+  (setq factor-indent-width (factor--guess-indent-width))
+  (setq indent-tabs-mode nil)
+  (run-hooks 'factor-mode-hook))
+
+(add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; factor-listener-mode
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
index 5b4ff3b8321c341cb82b6e0d5d9ff0d0c8240912..8b7df45e9ada4bb060c01020064ce178bdb4a3c9 100755 (executable)
@@ -82,7 +82,7 @@ void box_alien(void *ptr)
 }
 
 /* make an alien pointing at an offset of another alien */
-DEFINE_PRIMITIVE(displaced_alien)
+void primitive_displaced_alien(void)
 {
        CELL alien = dpop();
        CELL displacement = to_cell(dpop());
@@ -107,7 +107,7 @@ DEFINE_PRIMITIVE(displaced_alien)
 
 /* address of an object representing a C pointer. Explicitly throw an error
 if the object is a byte array, as a sanity check. */
-DEFINE_PRIMITIVE(alien_address)
+void primitive_alien_address(void)
 {
        box_unsigned_cell((CELL)pinned_alien_offset(dpop()));
 }
@@ -121,11 +121,11 @@ INLINE void *alien_pointer(void)
 
 /* define words to read/write values at an alien address */
 #define DEFINE_ALIEN_ACCESSOR(name,type,boxer,to) \
-       DEFINE_PRIMITIVE(alien_##name) \
+       void primitive_alien_##name(void) \
        { \
                boxer(*(type*)alien_pointer()); \
        } \
-       DEFINE_PRIMITIVE(set_alien_##name) \
+       void primitive_set_alien_##name(void) \
        { \
                type* ptr = alien_pointer(); \
                type value = to(dpop()); \
@@ -170,7 +170,7 @@ void box_small_struct(CELL x, CELL y, CELL size)
 }
 
 /* open a native library and push a handle */
-DEFINE_PRIMITIVE(dlopen)
+void primitive_dlopen(void)
 {
        CELL path = tag_object(string_to_native_alien(
                untag_string(dpop())));
@@ -183,7 +183,7 @@ DEFINE_PRIMITIVE(dlopen)
 }
 
 /* look up a symbol in a native library */
-DEFINE_PRIMITIVE(dlsym)
+void primitive_dlsym(void)
 {
        CELL dll = dpop();
        REGISTER_ROOT(dll);
@@ -205,12 +205,12 @@ DEFINE_PRIMITIVE(dlsym)
 }
 
 /* close a native library handle */
-DEFINE_PRIMITIVE(dlclose)
+void primitive_dlclose(void)
 {
        ffi_dlclose(untag_dll(dpop()));
 }
 
-DEFINE_PRIMITIVE(dll_validp)
+void primitive_dll_validp(void)
 {
        CELL dll = dpop();
        if(dll == F)
index babfbc358d76809c7a1df92231b43360c180143c..ec1eb08acf9fcaece8760195883d4bfa4003c8b0 100755 (executable)
@@ -1,7 +1,7 @@
 CELL allot_alien(CELL delegate, CELL displacement);
 
-DECLARE_PRIMITIVE(displaced_alien);
-DECLARE_PRIMITIVE(alien_address);
+void primitive_displaced_alien(void);
+void primitive_alien_address(void);
 
 DLLEXPORT void *alien_offset(CELL object);
 
@@ -10,32 +10,32 @@ void fixup_alien(F_ALIEN* d);
 DLLEXPORT void *unbox_alien(void);
 DLLEXPORT void box_alien(void *ptr);
 
-DECLARE_PRIMITIVE(alien_signed_cell);
-DECLARE_PRIMITIVE(set_alien_signed_cell);
-DECLARE_PRIMITIVE(alien_unsigned_cell);
-DECLARE_PRIMITIVE(set_alien_unsigned_cell);
-DECLARE_PRIMITIVE(alien_signed_8);
-DECLARE_PRIMITIVE(set_alien_signed_8);
-DECLARE_PRIMITIVE(alien_unsigned_8);
-DECLARE_PRIMITIVE(set_alien_unsigned_8);
-DECLARE_PRIMITIVE(alien_signed_4);
-DECLARE_PRIMITIVE(set_alien_signed_4);
-DECLARE_PRIMITIVE(alien_unsigned_4);
-DECLARE_PRIMITIVE(set_alien_unsigned_4);
-DECLARE_PRIMITIVE(alien_signed_2);
-DECLARE_PRIMITIVE(set_alien_signed_2);
-DECLARE_PRIMITIVE(alien_unsigned_2);
-DECLARE_PRIMITIVE(set_alien_unsigned_2);
-DECLARE_PRIMITIVE(alien_signed_1);
-DECLARE_PRIMITIVE(set_alien_signed_1);
-DECLARE_PRIMITIVE(alien_unsigned_1);
-DECLARE_PRIMITIVE(set_alien_unsigned_1);
-DECLARE_PRIMITIVE(alien_float);
-DECLARE_PRIMITIVE(set_alien_float);
-DECLARE_PRIMITIVE(alien_double);
-DECLARE_PRIMITIVE(set_alien_double);
-DECLARE_PRIMITIVE(alien_cell);
-DECLARE_PRIMITIVE(set_alien_cell);
+void primitive_alien_signed_cell(void);
+void primitive_set_alien_signed_cell(void);
+void primitive_alien_unsigned_cell(void);
+void primitive_set_alien_unsigned_cell(void);
+void primitive_alien_signed_8(void);
+void primitive_set_alien_signed_8(void);
+void primitive_alien_unsigned_8(void);
+void primitive_set_alien_unsigned_8(void);
+void primitive_alien_signed_4(void);
+void primitive_set_alien_signed_4(void);
+void primitive_alien_unsigned_4(void);
+void primitive_set_alien_unsigned_4(void);
+void primitive_alien_signed_2(void);
+void primitive_set_alien_signed_2(void);
+void primitive_alien_unsigned_2(void);
+void primitive_set_alien_unsigned_2(void);
+void primitive_alien_signed_1(void);
+void primitive_set_alien_signed_1(void);
+void primitive_alien_unsigned_1(void);
+void primitive_set_alien_unsigned_1(void);
+void primitive_alien_float(void);
+void primitive_set_alien_float(void);
+void primitive_alien_double(void);
+void primitive_set_alien_double(void);
+void primitive_alien_cell(void);
+void primitive_set_alien_cell(void);
 
 DLLEXPORT void to_value_struct(CELL src, void *dest, CELL size);
 DLLEXPORT void box_value_struct(void *src, CELL size);
@@ -43,7 +43,7 @@ DLLEXPORT void box_small_struct(CELL x, CELL y, CELL size);
 
 DEFINE_UNTAG(F_DLL,DLL_TYPE,dll)
 
-DECLARE_PRIMITIVE(dlopen);
-DECLARE_PRIMITIVE(dlsym);
-DECLARE_PRIMITIVE(dlclose);
-DECLARE_PRIMITIVE(dll_validp);
+void primitive_dlopen(void);
+void primitive_dlsym(void);
+void primitive_dlclose(void);
+void primitive_dll_validp(void);
index b7e99b418c9d15df6119f80f3724f9ff0ea80db7..dfa7dd5f4a8f5c28e362b50ff4d041c99d8cb242 100755 (executable)
@@ -6,11 +6,6 @@ F_FASTCALL void save_callstack_bottom(F_STACK_FRAME *callstack_bottom)
        stack_chain->callstack_bottom = callstack_bottom;
 }
 
-F_FASTCALL __attribute__((noinline)) void save_callstack_top(F_STACK_FRAME *callstack_top)
-{
-       stack_chain->callstack_top = callstack_top;
-}
-
 void iterate_callstack(CELL top, CELL bottom, CALLSTACK_ITER iterator)
 {
        F_STACK_FRAME *frame = (F_STACK_FRAME *)bottom - 1;
@@ -68,7 +63,7 @@ F_STACK_FRAME *capture_start(void)
        return frame + 1;
 }
 
-DEFINE_PRIMITIVE(callstack)
+void primitive_callstack(void)
 {
        F_STACK_FRAME *top = capture_start();
        F_STACK_FRAME *bottom = stack_chain->callstack_bottom;
@@ -82,7 +77,7 @@ DEFINE_PRIMITIVE(callstack)
        dpush(tag_object(callstack));
 }
 
-DEFINE_PRIMITIVE(set_callstack)
+void primitive_set_callstack(void)
 {
        F_CALLSTACK *stack = untag_callstack(dpop());
 
@@ -158,7 +153,7 @@ void stack_frame_to_array(F_STACK_FRAME *frame)
        set_array_nth(array,frame_index++,frame_scan(frame));
 }
 
-DEFINE_PRIMITIVE(callstack_to_array)
+void primitive_callstack_to_array(void)
 {
        F_CALLSTACK *stack = untag_callstack(dpop());
 
@@ -190,7 +185,7 @@ F_STACK_FRAME *innermost_stack_frame(F_CALLSTACK *callstack)
 
 /* Some primitives implementing a limited form of callstack mutation.
 Used by the single stepper. */
-DEFINE_PRIMITIVE(innermost_stack_frame_quot)
+void primitive_innermost_stack_frame_quot(void)
 {
        F_STACK_FRAME *inner = innermost_stack_frame(
                untag_callstack(dpop()));
@@ -199,7 +194,7 @@ DEFINE_PRIMITIVE(innermost_stack_frame_quot)
        dpush(frame_executing(inner));
 }
 
-DEFINE_PRIMITIVE(innermost_stack_frame_scan)
+void primitive_innermost_stack_frame_scan(void)
 {
        F_STACK_FRAME *inner = innermost_stack_frame(
                untag_callstack(dpop()));
@@ -208,7 +203,7 @@ DEFINE_PRIMITIVE(innermost_stack_frame_scan)
        dpush(frame_scan(inner));
 }
 
-DEFINE_PRIMITIVE(set_innermost_stack_frame_quot)
+void primitive_set_innermost_stack_frame_quot(void)
 {
        F_CALLSTACK *callstack = untag_callstack(dpop());
        F_QUOTATION *quot = untag_quotation(dpop());
index 6c38cd01177e16b28e660642b05a5036ba1c8a98..da0748b07191d11bbf9e54d5b6d1cef579d730e3 100755 (executable)
@@ -1,5 +1,4 @@
 F_FASTCALL void save_callstack_bottom(F_STACK_FRAME *callstack_bottom);
-F_FASTCALL __attribute__((noinline)) void save_callstack_top(F_STACK_FRAME *callstack_top);
 
 #define FIRST_STACK_FRAME(stack) (F_STACK_FRAME *)((stack) + 1)
 
@@ -14,11 +13,11 @@ CELL frame_executing(F_STACK_FRAME *frame);
 CELL frame_scan(F_STACK_FRAME *frame);
 CELL frame_type(F_STACK_FRAME *frame);
 
-DECLARE_PRIMITIVE(callstack);
-DECLARE_PRIMITIVE(set_datastack);
-DECLARE_PRIMITIVE(set_retainstack);
-DECLARE_PRIMITIVE(set_callstack);
-DECLARE_PRIMITIVE(callstack_to_array);
-DECLARE_PRIMITIVE(innermost_stack_frame_quot);
-DECLARE_PRIMITIVE(innermost_stack_frame_scan);
-DECLARE_PRIMITIVE(set_innermost_stack_frame_quot);
+void primitive_callstack(void);
+void primitive_set_datastack(void);
+void primitive_set_retainstack(void);
+void primitive_set_callstack(void);
+void primitive_callstack_to_array(void);
+void primitive_innermost_stack_frame_quot(void);
+void primitive_innermost_stack_frame_scan(void);
+void primitive_set_innermost_stack_frame_quot(void);
index 03661999c52fc49811bf08d25b0ca28efcb5ef81..bd6384408b61795e6606e1bc964ba8ee798dc6ec 100755 (executable)
@@ -295,7 +295,7 @@ void recursive_mark(F_BLOCK *block)
 }
 
 /* Push the free space and total size of the code heap */
-DEFINE_PRIMITIVE(code_room)
+void primitive_code_room(void)
 {
        CELL used, total_free, max_free;
        heap_usage(&code_heap,&used,&total_free,&max_free);
index f93cba9c7aec3f6b8f2ce53ef3964ccd727960da..72ad8d451c6ffea36a1ba9f8f7ab055a6c7a4d0c 100644 (file)
@@ -82,4 +82,4 @@ void recursive_mark(F_BLOCK *block);
 void dump_heap(F_HEAP *heap);
 void compact_code_heap(void);
 
-DECLARE_PRIMITIVE(code_room);
+void primitive_code_room(void);
index 1435caa9d2caf659cd76e00ac561d3eaccb1fb0d..2268df27e30c26e4e0113f5c08f5ac63d12de1fc 100755 (executable)
@@ -68,9 +68,11 @@ INLINE CELL compute_code_rel(F_REL *rel,
        case RT_XT:
                return (CELL)untag_word(get(CREF(literals_start,REL_ARGUMENT(rel))))->xt;
        case RT_HERE:
-               return rel->offset + code_start;
+               return rel->offset + code_start + (short)REL_ARGUMENT(rel);
        case RT_LABEL:
                return code_start + REL_ARGUMENT(rel);
+       case RT_STACK_CHAIN:
+               return (CELL)&stack_chain;
        default:
                critical_error("Bad rel type",rel->type);
                return -1; /* Can't happen */
@@ -322,7 +324,7 @@ void default_word_code(F_WORD *word, bool relocate)
        word->compiledp = F;
 }
 
-DEFINE_PRIMITIVE(modify_code_heap)
+void primitive_modify_code_heap(void)
 {
        bool rescan_code_heap = to_boolean(dpop());
        F_ARRAY *alist = untag_array(dpop());
index c3b476c4b53dc111bc19b06882ff22ba633baa79..7b1545ddf57d803799ec1045f22f90cb69c10834 100755 (executable)
@@ -13,8 +13,10 @@ typedef enum {
        RT_HERE,
        /* a local label */
        RT_LABEL,
-       /* immeditae literal */
-       RT_IMMEDIATE
+       /* immediate literal */
+       RT_IMMEDIATE,
+       /* address of stack_chain var */
+       RT_STACK_CHAIN
 } F_RELTYPE;
 
 typedef enum {
@@ -71,4 +73,4 @@ F_COMPILED *add_compiled_block(
 CELL compiled_code_format(void);
 bool stack_traces_p(void);
 
-DECLARE_PRIMITIVE(modify_code_heap);
+void primitive_modify_code_heap(void);
index 5342ff04d927983e9446d227a670fe97776b1f1b..cf1632811c1803343b2cbe38afd5d6c589d79ab6 100755 (executable)
@@ -250,13 +250,13 @@ CELL unaligned_object_size(CELL pointer)
        }
 }
 
-DEFINE_PRIMITIVE(size)
+void primitive_size(void)
 {
        box_unsigned_cell(object_size(dpop()));
 }
 
 /* Push memory usage statistics in data heap */
-DEFINE_PRIMITIVE(data_room)
+void primitive_data_room(void)
 {
        F_ARRAY *a = allot_array(ARRAY_TYPE,data_heap->gen_count * 2,F);
        int gen;
@@ -281,7 +281,7 @@ void begin_scan(void)
        gc_off = true;
 }
 
-DEFINE_PRIMITIVE(begin_scan)
+void primitive_begin_scan(void)
 {
        gc();
        begin_scan();
@@ -306,13 +306,13 @@ CELL next_object(void)
 }
 
 /* Push object at heap scan cursor and advance; pushes f when done */
-DEFINE_PRIMITIVE(next_object)
+void primitive_next_object(void)
 {
        dpush(next_object());
 }
 
 /* Re-enables GC */
-DEFINE_PRIMITIVE(end_scan)
+void primitive_end_scan(void)
 {
        gc_off = false;
 }
@@ -911,12 +911,12 @@ void minor_gc(void)
        garbage_collection(NURSERY,false,0);
 }
 
-DEFINE_PRIMITIVE(gc)
+void primitive_gc(void)
 {
        gc();
 }
 
-DEFINE_PRIMITIVE(gc_stats)
+void primitive_gc_stats(void)
 {
        GROWABLE_ARRAY(stats);
 
@@ -945,12 +945,12 @@ DEFINE_PRIMITIVE(gc_stats)
        dpush(stats);
 }
 
-DEFINE_PRIMITIVE(gc_reset)
+void primitive_gc_reset(void)
 {
        gc_reset();
 }
 
-DEFINE_PRIMITIVE(become)
+void primitive_become(void)
 {
        F_ARRAY *new_objects = untag_array(dpop());
        F_ARRAY *old_objects = untag_array(dpop());
index 3c21695c2c485874191e7fc287c02ddf2f19a365..0d63cc6bfee00173ec902ce27defb79f6f579def 100755 (executable)
@@ -13,11 +13,11 @@ CELL binary_payload_start(CELL pointer);
 void begin_scan(void);
 CELL next_object(void);
 
-DECLARE_PRIMITIVE(data_room);
-DECLARE_PRIMITIVE(size);
-DECLARE_PRIMITIVE(begin_scan);
-DECLARE_PRIMITIVE(next_object);
-DECLARE_PRIMITIVE(end_scan);
+void primitive_data_room(void);
+void primitive_size(void);
+void primitive_begin_scan(void);
+void primitive_next_object(void);
+void primitive_end_scan(void);
 
 void gc(void);
 DLLEXPORT void minor_gc(void);
@@ -388,9 +388,9 @@ INLINE void* allot_object(CELL type, CELL a)
 
 CELL collect_next(CELL scan);
 
-DECLARE_PRIMITIVE(gc);
-DECLARE_PRIMITIVE(gc_stats);
-DECLARE_PRIMITIVE(gc_reset);
-DECLARE_PRIMITIVE(become);
+void primitive_gc(void);
+void primitive_gc_stats(void);
+void primitive_gc_reset(void);
+void primitive_become(void);
 
 CELL find_all_words(void);
index 2550931c727196a8f5c94155770130862cf01a6f..41205d4aff6399d51a994d5726154ea69f1e245f 100755 (executable)
@@ -474,7 +474,7 @@ void factorbug(void)
        }
 }
 
-DEFINE_PRIMITIVE(die)
+void primitive_die(void)
 {
        fprintf(stderr,"The die word was called by the library. Unless you called it yourself,\n");
        fprintf(stderr,"you have triggered a bug in Factor. Please report.\n");
index 547fdba4367fbc38824ca8a481d3dad05c048204..594d8ec9197c71a191fb3493714b445cb682a4e4 100755 (executable)
@@ -6,4 +6,4 @@ void dump_zone(F_ZONE *z);
 
 bool fep_disabled;
 
-DECLARE_PRIMITIVE(die);
+void primitive_die(void);
index 36072920fea5c40b81e4e2605b6d1dd5074eae7f..fe6e79be6d4650abf0daff074f49131fa27de9ac 100755 (executable)
@@ -142,19 +142,19 @@ void misc_signal_handler_impl(void)
        signal_error(signal_number,signal_callstack_top);
 }
 
-DEFINE_PRIMITIVE(throw)
+void primitive_throw(void)
 {
        dpop();
        throw_impl(dpop(),stack_chain->callstack_top);
 }
 
-DEFINE_PRIMITIVE(call_clear)
+void primitive_call_clear(void)
 {
        throw_impl(dpop(),stack_chain->callstack_bottom);
 }
 
 /* For testing purposes */
-DEFINE_PRIMITIVE(unimplemented)
+void primitive_unimplemented(void)
 {
        not_implemented_error();
 }
index 22cd6533c30842fe74babf1b4f1b63d09281ed6a..c7f8bc8712a5a918235c5199f7dbd9f91949cd41 100755 (executable)
@@ -22,7 +22,7 @@ typedef enum
 void out_of_memory(void);
 void fatal_error(char* msg, CELL tagged);
 void critical_error(char* msg, CELL tagged);
-DECLARE_PRIMITIVE(die);
+void primitive_die(void);
 
 void throw_error(CELL error, F_STACK_FRAME *native_stack);
 void general_error(F_ERRORTYPE error, CELL arg1, CELL arg2, F_STACK_FRAME *native_stack);
@@ -32,8 +32,8 @@ void signal_error(int signal, F_STACK_FRAME *native_stack);
 void type_error(CELL type, CELL tagged);
 void not_implemented_error(void);
 
-DECLARE_PRIMITIVE(throw);
-DECLARE_PRIMITIVE(call_clear);
+void primitive_throw(void);
+void primitive_call_clear(void);
 
 INLINE void type_check(CELL type, CELL tagged)
 {
@@ -57,4 +57,4 @@ void memory_signal_handler_impl(void);
 void divide_by_zero_signal_handler_impl(void);
 void misc_signal_handler_impl(void);
 
-DECLARE_PRIMITIVE(unimplemented);
+void primitive_unimplemented(void);
index 62f9e1c906c2ea83f832e19f9b8e77ddfa6d2fd7..289c1e94c8eb33416b97335e1de7a16093238bf8 100755 (executable)
@@ -161,7 +161,7 @@ bool save_image(const F_CHAR *filename)
        return true;
 }
 
-DEFINE_PRIMITIVE(save_image)
+void primitive_save_image(void)
 {
        /* do a full GC to push everything into tenured space */
        gc();
@@ -184,7 +184,7 @@ void strip_compiled_quotations(void)
        gc_off = false;
 }
 
-DEFINE_PRIMITIVE(save_image_and_exit)
+void primitive_save_image_and_exit(void)
 {
        /* We unbox this before doing anything else. This is the only point
        where we might throw an error, so we have to throw an error here since
index 9e582fc6c661f54d0f4c8fa5a3e3cbd43078a6ef..6e1b03af0dcc0965dcd7d52b37c09bdbe1e791f0 100755 (executable)
@@ -40,8 +40,8 @@ void load_image(F_PARAMETERS *p);
 void init_objects(F_HEADER *h);
 bool save_image(const F_CHAR *file);
 
-DECLARE_PRIMITIVE(save_image);
-DECLARE_PRIMITIVE(save_image_and_exit);
+void primitive_save_image(void);
+void primitive_save_image_and_exit(void);
 
 /* relocation base of currently loaded image's data heap */
 CELL data_relocation_base;
diff --git a/vm/io.c b/vm/io.c
index bc561f5e5b86bf5cbf3147c3a2899a0e563f9103..bad4854775279ea82c276268c855af9f07237164 100755 (executable)
--- a/vm/io.c
+++ b/vm/io.c
@@ -29,7 +29,7 @@ void io_error(void)
        general_error(ERROR_IO,error,F,NULL);
 }
 
-DEFINE_PRIMITIVE(fopen)
+void primitive_fopen(void)
 {
        char *mode = unbox_char_string();
        REGISTER_C_STRING(mode);
@@ -49,7 +49,7 @@ DEFINE_PRIMITIVE(fopen)
        }
 }
 
-DEFINE_PRIMITIVE(fgetc)
+void primitive_fgetc(void)
 {
        FILE* file = unbox_alien();
 
@@ -74,7 +74,7 @@ DEFINE_PRIMITIVE(fgetc)
        }
 }
 
-DEFINE_PRIMITIVE(fread)
+void primitive_fread(void)
 {
        FILE* file = unbox_alien();
        CELL size = unbox_array_size();
@@ -116,7 +116,7 @@ DEFINE_PRIMITIVE(fread)
        }
 }
 
-DEFINE_PRIMITIVE(fputc)
+void primitive_fputc(void)
 {
        FILE *file = unbox_alien();
        F_FIXNUM ch = to_fixnum(dpop());
@@ -134,7 +134,7 @@ DEFINE_PRIMITIVE(fputc)
        }
 }
 
-DEFINE_PRIMITIVE(fwrite)
+void primitive_fwrite(void)
 {
        FILE *file = unbox_alien();
        F_BYTE_ARRAY *text = untag_byte_array(dpop());
@@ -163,7 +163,7 @@ DEFINE_PRIMITIVE(fwrite)
        }
 }
 
-DEFINE_PRIMITIVE(fflush)
+void primitive_fflush(void)
 {
        FILE *file = unbox_alien();
        for(;;)
@@ -175,7 +175,7 @@ DEFINE_PRIMITIVE(fflush)
        }
 }
 
-DEFINE_PRIMITIVE(fclose)
+void primitive_fclose(void)
 {
        FILE *file = unbox_alien();
        for(;;)
diff --git a/vm/io.h b/vm/io.h
index f4af9b8bec3a0c8469a6744a65a20865ed3d682e..08c9dd780793d3dca0b3c7a854c25c55d34544cc 100755 (executable)
--- a/vm/io.h
+++ b/vm/io.h
@@ -3,15 +3,15 @@ void io_error(void);
 int err_no(void);
 void clear_err_no(void);
 
-DECLARE_PRIMITIVE(fopen);
-DECLARE_PRIMITIVE(fgetc);
-DECLARE_PRIMITIVE(fread);
-DECLARE_PRIMITIVE(fputc);
-DECLARE_PRIMITIVE(fwrite);
-DECLARE_PRIMITIVE(fflush);
-DECLARE_PRIMITIVE(fclose);
+void primitive_fopen(void);
+void primitive_fgetc(void);
+void primitive_fread(void);
+void primitive_fputc(void);
+void primitive_fwrite(void);
+void primitive_fflush(void);
+void primitive_fclose(void);
 
 /* Platform specific primitives */
-DECLARE_PRIMITIVE(open_file);
-DECLARE_PRIMITIVE(existsp);
-DECLARE_PRIMITIVE(read_dir);
+void primitive_open_file(void);
+void primitive_existsp(void);
+void primitive_read_dir(void);
index 6dc29efdae773ac9d44c1d9d9f68ba6b9382d3fb..e55a5e9fd369e0128b24f6ce52fbb515b4edf9b6 100755 (executable)
@@ -201,14 +201,6 @@ typedef struct {
        void *dll;
 } F_DLL;
 
-typedef struct {
-       CELL header;
-       /* tagged */
-       CELL obj;
-       /* tagged */
-       CELL quot;
-} F_CURRY;
-
 typedef struct {
        CELL header;
        /* tagged */
index 7d3b64ed39461152fe60da458aa8aa2c9b7bdbfd..388a472f2e9edde841943ddb3b701e90893a42fb 100644 (file)
--- a/vm/math.c
+++ b/vm/math.c
@@ -21,12 +21,12 @@ CELL to_cell(CELL tagged)
        return (CELL)to_fixnum(tagged);
 }
 
-DEFINE_PRIMITIVE(bignum_to_fixnum)
+void primitive_bignum_to_fixnum(void)
 {
        drepl(tag_fixnum(bignum_to_fixnum(untag_object(dpeek()))));
 }
 
-DEFINE_PRIMITIVE(float_to_fixnum)
+void primitive_float_to_fixnum(void)
 {
        drepl(tag_fixnum(float_to_fixnum(dpeek())));
 }
@@ -35,13 +35,13 @@ DEFINE_PRIMITIVE(float_to_fixnum)
        F_FIXNUM y = untag_fixnum_fast(dpop()); \
        F_FIXNUM x = untag_fixnum_fast(dpop());
 
-DEFINE_PRIMITIVE(fixnum_add)
+void primitive_fixnum_add(void)
 {
        POP_FIXNUMS(x,y)
        box_signed_cell(x + y);
 }
 
-DEFINE_PRIMITIVE(fixnum_subtract)
+void primitive_fixnum_subtract(void)
 {
        POP_FIXNUMS(x,y)
        box_signed_cell(x - y);
@@ -49,7 +49,7 @@ DEFINE_PRIMITIVE(fixnum_subtract)
 
 /* Multiply two integers, and trap overflow.
 Thanks to David Blaikie (The_Vulture from freenode #java) for the hint. */
-DEFINE_PRIMITIVE(fixnum_multiply)
+void primitive_fixnum_multiply(void)
 {
        POP_FIXNUMS(x,y)
 
@@ -72,13 +72,13 @@ DEFINE_PRIMITIVE(fixnum_multiply)
        }
 }
 
-DEFINE_PRIMITIVE(fixnum_divint)
+void primitive_fixnum_divint(void)
 {
        POP_FIXNUMS(x,y)
        box_signed_cell(x / y);
 }
 
-DEFINE_PRIMITIVE(fixnum_divmod)
+void primitive_fixnum_divmod(void)
 {
        POP_FIXNUMS(x,y)
        box_signed_cell(x / y);
@@ -90,7 +90,7 @@ DEFINE_PRIMITIVE(fixnum_divmod)
  * If we're shifting right by n bits, we won't overflow as long as none of the
  * high WORD_SIZE-TAG_BITS-n bits are set.
  */
-DEFINE_PRIMITIVE(fixnum_shift)
+void primitive_fixnum_shift(void)
 {
        POP_FIXNUMS(x,y)
 
@@ -122,12 +122,12 @@ DEFINE_PRIMITIVE(fixnum_shift)
 }
 
 /* Bignums */
-DEFINE_PRIMITIVE(fixnum_to_bignum)
+void primitive_fixnum_to_bignum(void)
 {
        drepl(tag_bignum(fixnum_to_bignum(untag_fixnum_fast(dpeek()))));
 }
 
-DEFINE_PRIMITIVE(float_to_bignum)
+void primitive_float_to_bignum(void)
 {
        drepl(tag_bignum(float_to_bignum(dpeek())));
 }
@@ -136,37 +136,37 @@ DEFINE_PRIMITIVE(float_to_bignum)
        F_ARRAY *y = untag_object(dpop()); \
        F_ARRAY *x = untag_object(dpop());
 
-DEFINE_PRIMITIVE(bignum_eq)
+void primitive_bignum_eq(void)
 {
        POP_BIGNUMS(x,y);
        box_boolean(bignum_equal_p(x,y));
 }
 
-DEFINE_PRIMITIVE(bignum_add)
+void primitive_bignum_add(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_add(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_subtract)
+void primitive_bignum_subtract(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_subtract(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_multiply)
+void primitive_bignum_multiply(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_multiply(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_divint)
+void primitive_bignum_divint(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_quotient(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_divmod)
+void primitive_bignum_divmod(void)
 {
        F_ARRAY *q, *r;
        POP_BIGNUMS(x,y);
@@ -175,74 +175,74 @@ DEFINE_PRIMITIVE(bignum_divmod)
        dpush(tag_bignum(r));
 }
 
-DEFINE_PRIMITIVE(bignum_mod)
+void primitive_bignum_mod(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_remainder(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_and)
+void primitive_bignum_and(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_bitwise_and(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_or)
+void primitive_bignum_or(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_bitwise_ior(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_xor)
+void primitive_bignum_xor(void)
 {
        POP_BIGNUMS(x,y);
        dpush(tag_bignum(bignum_bitwise_xor(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_shift)
+void primitive_bignum_shift(void)
 {
        F_FIXNUM y = to_fixnum(dpop());
         F_ARRAY* x = untag_object(dpop());
        dpush(tag_bignum(bignum_arithmetic_shift(x,y)));
 }
 
-DEFINE_PRIMITIVE(bignum_less)
+void primitive_bignum_less(void)
 {
        POP_BIGNUMS(x,y);
        box_boolean(bignum_compare(x,y) == bignum_comparison_less);
 }
 
-DEFINE_PRIMITIVE(bignum_lesseq)
+void primitive_bignum_lesseq(void)
 {
        POP_BIGNUMS(x,y);
        box_boolean(bignum_compare(x,y) != bignum_comparison_greater);
 }
 
-DEFINE_PRIMITIVE(bignum_greater)
+void primitive_bignum_greater(void)
 {
        POP_BIGNUMS(x,y);
        box_boolean(bignum_compare(x,y) == bignum_comparison_greater);
 }
 
-DEFINE_PRIMITIVE(bignum_greatereq)
+void primitive_bignum_greatereq(void)
 {
        POP_BIGNUMS(x,y);
        box_boolean(bignum_compare(x,y) != bignum_comparison_less);
 }
 
-DEFINE_PRIMITIVE(bignum_not)
+void primitive_bignum_not(void)
 {
        drepl(tag_bignum(bignum_bitwise_not(untag_object(dpeek()))));
 }
 
-DEFINE_PRIMITIVE(bignum_bitp)
+void primitive_bignum_bitp(void)
 {
        F_FIXNUM bit = to_fixnum(dpop());
        F_ARRAY *x = untag_object(dpop());
        box_boolean(bignum_logbitp(bit,x));
 }
 
-DEFINE_PRIMITIVE(bignum_log2)
+void primitive_bignum_log2(void)
 {
        drepl(tag_bignum(bignum_integer_length(untag_object(dpeek()))));
 }
@@ -253,7 +253,7 @@ unsigned int bignum_producer(unsigned int digit)
        return *(ptr + digit);
 }
 
-DEFINE_PRIMITIVE(byte_array_to_bignum)
+void primitive_byte_array_to_bignum(void)
 {
        type_check(BYTE_ARRAY_TYPE,dpeek());
        CELL n_digits = array_capacity(untag_object(dpeek()));
@@ -383,7 +383,7 @@ CELL unbox_array_size(void)
 
 /* Does not reduce to lowest terms, so should only be used by math
 library implementation, to avoid breaking invariants. */
-DEFINE_PRIMITIVE(from_fraction)
+void primitive_from_fraction(void)
 {
        F_RATIO* ratio = allot_object(RATIO_TYPE,sizeof(F_RATIO));
        ratio->denominator = dpop();
@@ -392,17 +392,17 @@ DEFINE_PRIMITIVE(from_fraction)
 }
 
 /* Floats */
-DEFINE_PRIMITIVE(fixnum_to_float)
+void primitive_fixnum_to_float(void)
 {
        drepl(allot_float(fixnum_to_float(dpeek())));
 }
 
-DEFINE_PRIMITIVE(bignum_to_float)
+void primitive_bignum_to_float(void)
 {
        drepl(allot_float(bignum_to_float(dpeek())));
 }
 
-DEFINE_PRIMITIVE(str_to_float)
+void primitive_str_to_float(void)
 {
        char *c_str, *end;
        double f;
@@ -418,7 +418,7 @@ DEFINE_PRIMITIVE(str_to_float)
                drepl(allot_float(f));
 }
 
-DEFINE_PRIMITIVE(float_to_str)
+void primitive_float_to_str(void)
 {
        char tmp[33];
        snprintf(tmp,32,"%.16g",untag_float(dpop()));
@@ -430,82 +430,82 @@ DEFINE_PRIMITIVE(float_to_str)
        double y = untag_float_fast(dpop()); \
        double x = untag_float_fast(dpop());
 
-DEFINE_PRIMITIVE(float_eq)
+void primitive_float_eq(void)
 {
        POP_FLOATS(x,y);
        box_boolean(x == y);
 }
 
-DEFINE_PRIMITIVE(float_add)
+void primitive_float_add(void)
 {
        POP_FLOATS(x,y);
        box_double(x + y);
 }
 
-DEFINE_PRIMITIVE(float_subtract)
+void primitive_float_subtract(void)
 {
        POP_FLOATS(x,y);
        box_double(x - y);
 }
 
-DEFINE_PRIMITIVE(float_multiply)
+void primitive_float_multiply(void)
 {
        POP_FLOATS(x,y);
        box_double(x * y);
 }
 
-DEFINE_PRIMITIVE(float_divfloat)
+void primitive_float_divfloat(void)
 {
        POP_FLOATS(x,y);
        box_double(x / y);
 }
 
-DEFINE_PRIMITIVE(float_mod)
+void primitive_float_mod(void)
 {
        POP_FLOATS(x,y);
        box_double(fmod(x,y));
 }
 
-DEFINE_PRIMITIVE(float_less)
+void primitive_float_less(void)
 {
        POP_FLOATS(x,y);
        box_boolean(x < y);
 }
 
-DEFINE_PRIMITIVE(float_lesseq)
+void primitive_float_lesseq(void)
 {
        POP_FLOATS(x,y);
        box_boolean(x <= y);
 }
 
-DEFINE_PRIMITIVE(float_greater)
+void primitive_float_greater(void)
 {
        POP_FLOATS(x,y);
        box_boolean(x > y);
 }
 
-DEFINE_PRIMITIVE(float_greatereq)
+void primitive_float_greatereq(void)
 {
        POP_FLOATS(x,y);
        box_boolean(x >= y);
 }
 
-DEFINE_PRIMITIVE(float_bits)
+void primitive_float_bits(void)
 {
        box_unsigned_4(float_bits(untag_float(dpop())));
 }
 
-DEFINE_PRIMITIVE(bits_float)
+void primitive_bits_float(void)
 {
        box_float(bits_float(to_cell(dpop())));
 }
 
-DEFINE_PRIMITIVE(double_bits)
+void primitive_double_bits(void)
 {
        box_unsigned_8(double_bits(untag_float(dpop())));
 }
 
-DEFINE_PRIMITIVE(bits_double)
+void primitive_bits_double(void)
 {
        box_double(bits_double(to_unsigned_8(dpop())));
 }
@@ -532,7 +532,7 @@ void box_double(double flo)
 
 /* Complex numbers */
 
-DEFINE_PRIMITIVE(from_rect)
+void primitive_from_rect(void)
 {
        F_COMPLEX* complex = allot_object(COMPLEX_TYPE,sizeof(F_COMPLEX));
        complex->imaginary = dpop();
index 07d7fa91990bca49f0d8572a0b70ebe4f62341c8..4fa3c8d35f086d1a60e85404a4c87ed38f878e57 100644 (file)
--- a/vm/math.h
+++ b/vm/math.h
@@ -6,15 +6,15 @@
 DLLEXPORT F_FIXNUM to_fixnum(CELL tagged);
 DLLEXPORT CELL to_cell(CELL tagged);
 
-DECLARE_PRIMITIVE(bignum_to_fixnum);
-DECLARE_PRIMITIVE(float_to_fixnum);
+void primitive_bignum_to_fixnum(void);
+void primitive_float_to_fixnum(void);
 
-DECLARE_PRIMITIVE(fixnum_add);
-DECLARE_PRIMITIVE(fixnum_subtract);
-DECLARE_PRIMITIVE(fixnum_multiply);
-DECLARE_PRIMITIVE(fixnum_divint);
-DECLARE_PRIMITIVE(fixnum_divmod);
-DECLARE_PRIMITIVE(fixnum_shift);
+void primitive_fixnum_add(void);
+void primitive_fixnum_subtract(void);
+void primitive_fixnum_multiply(void);
+void primitive_fixnum_divint(void);
+void primitive_fixnum_divmod(void);
+void primitive_fixnum_shift(void);
 
 CELL bignum_zero;
 CELL bignum_pos_one;
@@ -25,27 +25,27 @@ INLINE CELL tag_bignum(F_ARRAY* bignum)
        return RETAG(bignum,BIGNUM_TYPE);
 }
 
-DECLARE_PRIMITIVE(fixnum_to_bignum);
-DECLARE_PRIMITIVE(float_to_bignum);
-DECLARE_PRIMITIVE(bignum_eq);
-DECLARE_PRIMITIVE(bignum_add);
-DECLARE_PRIMITIVE(bignum_subtract);
-DECLARE_PRIMITIVE(bignum_multiply);
-DECLARE_PRIMITIVE(bignum_divint);
-DECLARE_PRIMITIVE(bignum_divmod);
-DECLARE_PRIMITIVE(bignum_mod);
-DECLARE_PRIMITIVE(bignum_and);
-DECLARE_PRIMITIVE(bignum_or);
-DECLARE_PRIMITIVE(bignum_xor);
-DECLARE_PRIMITIVE(bignum_shift);
-DECLARE_PRIMITIVE(bignum_less);
-DECLARE_PRIMITIVE(bignum_lesseq);
-DECLARE_PRIMITIVE(bignum_greater);
-DECLARE_PRIMITIVE(bignum_greatereq);
-DECLARE_PRIMITIVE(bignum_not);
-DECLARE_PRIMITIVE(bignum_bitp);
-DECLARE_PRIMITIVE(bignum_log2);
-DECLARE_PRIMITIVE(byte_array_to_bignum);
+void primitive_fixnum_to_bignum(void);
+void primitive_float_to_bignum(void);
+void primitive_bignum_eq(void);
+void primitive_bignum_add(void);
+void primitive_bignum_subtract(void);
+void primitive_bignum_multiply(void);
+void primitive_bignum_divint(void);
+void primitive_bignum_divmod(void);
+void primitive_bignum_mod(void);
+void primitive_bignum_and(void);
+void primitive_bignum_or(void);
+void primitive_bignum_xor(void);
+void primitive_bignum_shift(void);
+void primitive_bignum_less(void);
+void primitive_bignum_lesseq(void);
+void primitive_bignum_greater(void);
+void primitive_bignum_greatereq(void);
+void primitive_bignum_not(void);
+void primitive_bignum_bitp(void);
+void primitive_bignum_log2(void);
+void primitive_byte_array_to_bignum(void);
 
 INLINE CELL allot_integer(F_FIXNUM x)
 {
@@ -80,7 +80,7 @@ DLLEXPORT u64 to_unsigned_8(CELL obj);
 
 CELL unbox_array_size(void);
 
-DECLARE_PRIMITIVE(from_fraction);
+void primitive_from_fraction(void);
 
 INLINE double untag_float_fast(CELL tagged)
 {
@@ -125,26 +125,26 @@ DLLEXPORT float to_float(CELL value);
 DLLEXPORT void box_double(double flo);
 DLLEXPORT double to_double(CELL value);
 
-DECLARE_PRIMITIVE(fixnum_to_float);
-DECLARE_PRIMITIVE(bignum_to_float);
-DECLARE_PRIMITIVE(str_to_float);
-DECLARE_PRIMITIVE(float_to_str);
-DECLARE_PRIMITIVE(float_to_bits);
-
-DECLARE_PRIMITIVE(float_eq);
-DECLARE_PRIMITIVE(float_add);
-DECLARE_PRIMITIVE(float_subtract);
-DECLARE_PRIMITIVE(float_multiply);
-DECLARE_PRIMITIVE(float_divfloat);
-DECLARE_PRIMITIVE(float_mod);
-DECLARE_PRIMITIVE(float_less);
-DECLARE_PRIMITIVE(float_lesseq);
-DECLARE_PRIMITIVE(float_greater);
-DECLARE_PRIMITIVE(float_greatereq);
-
-DECLARE_PRIMITIVE(float_bits);
-DECLARE_PRIMITIVE(bits_float);
-DECLARE_PRIMITIVE(double_bits);
-DECLARE_PRIMITIVE(bits_double);
-
-DECLARE_PRIMITIVE(from_rect);
+void primitive_fixnum_to_float(void);
+void primitive_bignum_to_float(void);
+void primitive_str_to_float(void);
+void primitive_float_to_str(void);
+void primitive_float_to_bits(void);
+
+void primitive_float_eq(void);
+void primitive_float_add(void);
+void primitive_float_subtract(void);
+void primitive_float_multiply(void);
+void primitive_float_divfloat(void);
+void primitive_float_mod(void);
+void primitive_float_less(void);
+void primitive_float_lesseq(void);
+void primitive_float_greater(void);
+void primitive_float_greatereq(void);
+
+void primitive_float_bits(void);
+void primitive_bits_float(void);
+void primitive_double_bits(void);
+void primitive_bits_double(void);
+
+void primitive_from_rect(void);
index 4ca62e6623168475679804587c8a2eba6960f6eb..c11962f6e1dde1249b4605719a99387657cdc77a 100755 (executable)
@@ -55,7 +55,7 @@ void ffi_dlclose(F_DLL *dll)
        dll->dll = NULL;
 }
 
-DEFINE_PRIMITIVE(existsp)
+void primitive_existsp(void)
 {
        struct stat sb;
        box_boolean(stat(unbox_char_string(),&sb) >= 0);
index 9b73692aa05f1ee12483c9b7800ecfa216358d4b..02b51b82ed4fe2fb999e0d4f5082607003a63e74 100755 (executable)
@@ -27,7 +27,7 @@ char *getenv(char *name)
        return 0; /* unreachable */
 }
 
-DEFINE_PRIMITIVE(os_envs)
+void primitive_os_envs(void)
 {
        not_implemented_error();
 }
index c19aa5c4b501afa22370377288638046b38f5496..fc289c288ea8f97fd89f2fe24ad6e3fbb32a39de 100755 (executable)
@@ -87,7 +87,7 @@ const F_CHAR *vm_executable_path(void)
        return safe_strdup(full_path);
 }
 
-DEFINE_PRIMITIVE(existsp)
+void primitive_existsp(void)
 {
        BY_HANDLE_FILE_INFORMATION bhfi;
 
index 811b473acdc72c77aa9070359bf9d74069f31357..30e0a4af964da03b9a2cb51dfe3c4d40e06f5d98 100644 (file)
@@ -1,42 +1 @@
 extern void *primitives[];
-
-/* Primitives are called with two parameters, the word itself and the current
-callstack pointer. The DEFINE_PRIMITIVE() macro takes care of boilerplate to
-save the current callstack pointer so that GC and other facilities can proceed
-to inspect Factor stack frames below the primitive's C stack frame.
-
-Usage:
-
-DEFINE_PRIMITIVE(name)
-{
-       ... CODE ...
-}
-
-Becomes
-
-F_FASTCALL void primitive_name(CELL word, F_STACK_FRAME *callstack_top)
-{
-       save_callstack_top(callstack_top);
-       ... CODE ...
-}
-
-On x86, F_FASTCALL expands into a GCC declaration which forces the two
-parameters to be passed in registers. This simplifies the quotation compiler
-and support code in cpu-x86.S.
-
-We do the assignment of stack_chain->callstack_top in a ``noinline'' function
-to inhibit assignment re-ordering. */
-#define DEFINE_PRIMITIVE(name) \
-       INLINE void primitive_##name##_impl(void); \
-       \
-       F_FASTCALL void primitive_##name(CELL word, F_STACK_FRAME *callstack_top) \
-       { \
-               save_callstack_top(callstack_top); \
-               primitive_##name##_impl(); \
-       } \
-       \
-       INLINE void primitive_##name##_impl(void) \
-
-/* Prototype for header files */
-#define DECLARE_PRIMITIVE(name) \
-       F_FASTCALL void primitive_##name(CELL word, F_STACK_FRAME *callstack_top)
index 27e903178b3b8427b835234e70d9db6ed661dee1..e3db67964f664d1515e3b79e346d1ac23affdd1e 100755 (executable)
@@ -32,7 +32,6 @@ F_COMPILED *compile_profiling_stub(F_WORD *word)
 /* Allocates memory */
 void update_word_xt(F_WORD *word)
 {
-       /* If we just enabled the profiler, reset call count */
        if(profiling_p)
        {
                if(!word->profiling)
@@ -80,7 +79,7 @@ void set_profiling(bool profiling)
        iterate_code_heap(relocate_code_block);
 }
 
-DEFINE_PRIMITIVE(profiling)
+void primitive_profiling(void)
 {
        set_profiling(to_boolean(dpop()));
 }
index d14ceb283b2fe502da2c22c3ce714c6699c20d1c..26a3a78d4b9dc0728513288b736bddffc3fb3977 100755 (executable)
@@ -1,4 +1,4 @@
 bool profiling_p;
-DECLARE_PRIMITIVE(profiling);
+void primitive_profiling(void);
 F_COMPILED *compile_profiling_stub(F_WORD *word);
 void update_word_xt(F_WORD *word);
index b75d3f79e00c6776c3964cd7cec72ffe05e3ca95..bf917aeec06a7c40155870ee2c42d3dc6e7306dd 100755 (executable)
@@ -209,6 +209,7 @@ void jit_compile(CELL quot, bool relocate)
                case FIXNUM_TYPE:
                        if(jit_primitive_call_p(untag_object(array),i))
                        {
+                               EMIT(userenv[JIT_SAVE_STACK],0);
                                EMIT(userenv[JIT_PRIMITIVE],to_fixnum(obj));
 
                                i++;
@@ -344,6 +345,7 @@ F_FIXNUM quot_code_offset_to_scan(CELL quot, F_FIXNUM offset)
                case FIXNUM_TYPE:
                        if(jit_primitive_call_p(untag_object(array),i))
                        {
+                               COUNT(userenv[JIT_SAVE_STACK],i);
                                COUNT(userenv[JIT_PRIMITIVE],i);
 
                                i++;
@@ -412,7 +414,7 @@ F_FASTCALL CELL primitive_jit_compile(CELL quot, F_STACK_FRAME *stack)
 }
 
 /* push a new quotation on the stack */
-DEFINE_PRIMITIVE(array_to_quotation)
+void primitive_array_to_quotation(void)
 {
        F_QUOTATION *quot = allot_object(QUOTATION_TYPE,sizeof(F_QUOTATION));
        quot->array = dpeek();
@@ -421,7 +423,7 @@ DEFINE_PRIMITIVE(array_to_quotation)
        drepl(tag_object(quot));
 }
 
-DEFINE_PRIMITIVE(quotation_xt)
+void primitive_quotation_xt(void)
 {
        F_QUOTATION *quot = untag_quotation(dpeek());
        drepl(allot_cell((CELL)quot->xt));
index 0845957c0b84372f152e28b7af89b598794ec2d8..45bf78d14fb384d299f0a0ae5e392d8ab1f2f0aa 100755 (executable)
@@ -2,5 +2,5 @@ void set_quot_xt(F_QUOTATION *quot, F_COMPILED *code);
 void jit_compile(CELL quot, bool relocate);
 F_FASTCALL CELL primitive_jit_compile(CELL quot, F_STACK_FRAME *stack);
 F_FIXNUM quot_code_offset_to_scan(CELL quot, F_FIXNUM offset);
-DECLARE_PRIMITIVE(array_to_quotation);
-DECLARE_PRIMITIVE(quotation_xt);
+void primitive_array_to_quotation(void);
+void primitive_quotation_xt(void);
index c4a3e115c13708c336a67cf6c7677ee3458c248e..c7d93d29c81768644439bdc2ac175ee3f5732787 100755 (executable)
--- a/vm/run.c
+++ b/vm/run.c
@@ -105,13 +105,13 @@ bool stack_to_array(CELL bottom, CELL top)
        }
 }
 
-DEFINE_PRIMITIVE(datastack)
+void primitive_datastack(void)
 {
        if(!stack_to_array(ds_bot,ds))
                general_error(ERROR_DS_UNDERFLOW,F,F,NULL);
 }
 
-DEFINE_PRIMITIVE(retainstack)
+void primitive_retainstack(void)
 {
        if(!stack_to_array(rs_bot,rs))
                general_error(ERROR_RS_UNDERFLOW,F,F,NULL);
@@ -125,45 +125,45 @@ CELL array_to_stack(F_ARRAY *array, CELL bottom)
        return bottom + depth - CELLS;
 }
 
-DEFINE_PRIMITIVE(set_datastack)
+void primitive_set_datastack(void)
 {
        ds = array_to_stack(untag_array(dpop()),ds_bot);
 }
 
-DEFINE_PRIMITIVE(set_retainstack)
+void primitive_set_retainstack(void)
 {
        rs = array_to_stack(untag_array(dpop()),rs_bot);
 }
 
-DEFINE_PRIMITIVE(getenv)
+void primitive_getenv(void)
 {
        F_FIXNUM e = untag_fixnum_fast(dpeek());
        drepl(userenv[e]);
 }
 
-DEFINE_PRIMITIVE(setenv)
+void primitive_setenv(void)
 {
        F_FIXNUM e = untag_fixnum_fast(dpop());
        CELL value = dpop();
        userenv[e] = value;
 }
 
-DEFINE_PRIMITIVE(exit)
+void primitive_exit(void)
 {
        exit(to_fixnum(dpop()));
 }
 
-DEFINE_PRIMITIVE(millis)
+void primitive_millis(void)
 {
        box_unsigned_8(current_millis());
 }
 
-DEFINE_PRIMITIVE(sleep)
+void primitive_sleep(void)
 {
        sleep_millis(to_cell(dpop()));
 }
 
-DEFINE_PRIMITIVE(set_slot)
+void primitive_set_slot(void)
 {
        F_FIXNUM slot = untag_fixnum_fast(dpop());
        CELL obj = dpop();
index 96e606e38cba5302edad54ff3e7b9f015e7345df..2dbbcc8c0640e646a7cefab8ed89e7ee120de1a1 100755 (executable)
--- a/vm/run.h
+++ b/vm/run.h
@@ -48,8 +48,8 @@ typedef enum {
        JIT_RETURN,
        JIT_PROFILING,
        JIT_PUSH_IMMEDIATE,
-
        JIT_DECLARE_WORD    = 42,
+       JIT_SAVE_STACK,
 
        STACK_TRACES_ENV    = 59,
 
@@ -226,18 +226,18 @@ DLLEXPORT void nest_stacks(void);
 DLLEXPORT void unnest_stacks(void);
 void init_stacks(CELL ds_size, CELL rs_size);
 
-DECLARE_PRIMITIVE(datastack);
-DECLARE_PRIMITIVE(retainstack);
-DECLARE_PRIMITIVE(getenv);
-DECLARE_PRIMITIVE(setenv);
-DECLARE_PRIMITIVE(exit);
-DECLARE_PRIMITIVE(os_env);
-DECLARE_PRIMITIVE(os_envs);
-DECLARE_PRIMITIVE(set_os_env);
-DECLARE_PRIMITIVE(unset_os_env);
-DECLARE_PRIMITIVE(set_os_envs);
-DECLARE_PRIMITIVE(millis);
-DECLARE_PRIMITIVE(sleep);
-DECLARE_PRIMITIVE(set_slot);
+void primitive_datastack(void);
+void primitive_retainstack(void);
+void primitive_getenv(void);
+void primitive_setenv(void);
+void primitive_exit(void);
+void primitive_os_env(void);
+void primitive_os_envs(void);
+void primitive_set_os_env(void);
+void primitive_unset_os_env(void);
+void primitive_set_os_envs(void);
+void primitive_millis(void);
+void primitive_sleep(void);
+void primitive_set_slot(void);
 
 bool stage2;
index 5e2ed4bed9a039ab2aa58955ee3168d48ade34c0..f1588465a4dae398fb45659060dc8ef9f9c780ef 100755 (executable)
@@ -29,7 +29,7 @@ CELL clone_object(CELL object)
        }
 }
 
-DEFINE_PRIMITIVE(clone)
+void primitive_clone(void)
 {
        drepl(clone_object(dpeek()));
 }
@@ -61,11 +61,14 @@ F_WORD *allot_word(CELL vocab, CELL name)
        update_word_xt(word);
        UNREGISTER_UNTAGGED(word);
 
+       if(profiling_p)
+               iterate_code_heap_step(word->profiling,relocate_code_block);
+
        return word;
 }
 
 /* <word> ( name vocabulary -- word ) */
-DEFINE_PRIMITIVE(word)
+void primitive_word(void)
 {
        CELL vocab = dpop();
        CELL name = dpop();
@@ -73,15 +76,15 @@ DEFINE_PRIMITIVE(word)
 }
 
 /* word-xt ( word -- start end ) */
-DEFINE_PRIMITIVE(word_xt)
+void primitive_word_xt(void)
 {
        F_WORD *word = untag_word(dpop());
-       F_COMPILED *code = word->code;
+       F_COMPILED *code = (profiling_p ? word->profiling : word->code);
        dpush(allot_cell((CELL)code + sizeof(F_COMPILED)));
        dpush(allot_cell((CELL)code + sizeof(F_COMPILED) + code->code_length));
 }
 
-DEFINE_PRIMITIVE(wrapper)
+void primitive_wrapper(void)
 {
        F_WRAPPER *wrapper = allot_object(WRAPPER_TYPE,sizeof(F_WRAPPER));
        wrapper->object = dpeek();
@@ -120,7 +123,7 @@ F_ARRAY *allot_array(CELL type, CELL capacity, CELL fill)
 }
 
 /* push a new array on the stack */
-DEFINE_PRIMITIVE(array)
+void primitive_array(void)
 {
        CELL initial = dpop();
        CELL size = unbox_array_size();
@@ -191,7 +194,7 @@ F_ARRAY *reallot_array(F_ARRAY* array, CELL capacity, CELL fill)
        return new_array;
 }
 
-DEFINE_PRIMITIVE(resize_array)
+void primitive_resize_array(void)
 {
        F_ARRAY* array = untag_array(dpop());
        CELL capacity = unbox_array_size();
@@ -256,7 +259,7 @@ F_BYTE_ARRAY *allot_byte_array(CELL size)
 }
 
 /* push a new byte array on the stack */
-DEFINE_PRIMITIVE(byte_array)
+void primitive_byte_array(void)
 {
        CELL size = unbox_array_size();
        dpush(tag_object(allot_byte_array(size)));
@@ -277,7 +280,7 @@ F_BYTE_ARRAY *reallot_byte_array(F_BYTE_ARRAY *array, CELL capacity)
        return new_array;
 }
 
-DEFINE_PRIMITIVE(resize_byte_array)
+void primitive_resize_byte_array(void)
 {
        F_BYTE_ARRAY* array = untag_byte_array(dpop());
        CELL capacity = unbox_array_size();
@@ -310,7 +313,7 @@ F_TUPLE *allot_tuple(F_TUPLE_LAYOUT *layout)
        return tuple;
 }
 
-DEFINE_PRIMITIVE(tuple)
+void primitive_tuple(void)
 {
        F_TUPLE_LAYOUT *layout = untag_object(dpop());
        F_FIXNUM size = untag_fixnum_fast(layout->size);
@@ -324,7 +327,7 @@ DEFINE_PRIMITIVE(tuple)
 }
 
 /* push a new tuple on the stack, filling its slots from the stack */
-DEFINE_PRIMITIVE(tuple_boa)
+void primitive_tuple_boa(void)
 {
        F_TUPLE_LAYOUT *layout = untag_object(dpop());
        F_FIXNUM size = untag_fixnum_fast(layout->size);
@@ -431,7 +434,7 @@ F_STRING *allot_string(CELL capacity, CELL fill)
        return string;
 }
 
-DEFINE_PRIMITIVE(string)
+void primitive_string(void)
 {
        CELL initial = to_cell(dpop());
        CELL length = unbox_array_size();
@@ -474,7 +477,7 @@ F_STRING* reallot_string(F_STRING* string, CELL capacity, CELL fill)
        return new_string;
 }
 
-DEFINE_PRIMITIVE(resize_string)
+void primitive_resize_string(void)
 {
        F_STRING* string = untag_string(dpop());
        CELL capacity = unbox_array_size();
@@ -541,7 +544,7 @@ F_BYTE_ARRAY *allot_c_string(CELL capacity, CELL size)
                for(i = 0; i < capacity; i++) \
                        string[i] = string_nth(s,i); \
        } \
-       DEFINE_PRIMITIVE(type##_string_to_memory) \
+       void primitive_##type##_string_to_memory(void) \
        { \
                type *address = unbox_alien(); \
                F_STRING *str = untag_string(dpop()); \
@@ -573,14 +576,14 @@ F_BYTE_ARRAY *allot_c_string(CELL capacity, CELL size)
 STRING_TO_MEMORY(char);
 STRING_TO_MEMORY(u16);
 
-DEFINE_PRIMITIVE(string_nth)
+void primitive_string_nth(void)
 {
        F_STRING *string = untag_object(dpop());
        CELL index = untag_fixnum_fast(dpop());
        dpush(tag_fixnum(string_nth(string,index)));
 }
 
-DEFINE_PRIMITIVE(set_string_nth)
+void primitive_set_string_nth(void)
 {
        F_STRING *string = untag_object(dpop());
        CELL index = untag_fixnum_fast(dpop());
index 6efae35f5e41eee3461748e7becb94483892ebf4..ebbb8a264241aa22382e0e7cd11c542323f6f32c 100755 (executable)
@@ -112,23 +112,23 @@ CELL allot_array_1(CELL obj);
 CELL allot_array_2(CELL v1, CELL v2);
 CELL allot_array_4(CELL v1, CELL v2, CELL v3, CELL v4);
 
-DECLARE_PRIMITIVE(array);
-DECLARE_PRIMITIVE(tuple);
-DECLARE_PRIMITIVE(tuple_boa);
-DECLARE_PRIMITIVE(tuple_layout);
-DECLARE_PRIMITIVE(byte_array);
-DECLARE_PRIMITIVE(clone);
+void primitive_array(void);
+void primitive_tuple(void);
+void primitive_tuple_boa(void);
+void primitive_tuple_layout(void);
+void primitive_byte_array(void);
+void primitive_clone(void);
 
 F_ARRAY *reallot_array(F_ARRAY* array, CELL capacity, CELL fill);
 F_BYTE_ARRAY *reallot_byte_array(F_BYTE_ARRAY *array, CELL capacity);
-DECLARE_PRIMITIVE(resize_array);
-DECLARE_PRIMITIVE(resize_byte_array);
+void primitive_resize_array(void);
+void primitive_resize_byte_array(void);
 
 F_STRING* allot_string_internal(CELL capacity);
 F_STRING* allot_string(CELL capacity, CELL fill);
-DECLARE_PRIMITIVE(string);
+void primitive_string(void);
 F_STRING *reallot_string(F_STRING *string, CELL capacity, CELL fill);
-DECLARE_PRIMITIVE(resize_string);
+void primitive_resize_string(void);
 
 F_STRING *memory_to_char_string(const char *string, CELL length);
 F_STRING *from_char_string(const char *c_string);
@@ -152,14 +152,14 @@ DLLEXPORT u16 *unbox_u16_string(void);
 CELL string_nth(F_STRING* string, CELL index);
 void set_string_nth(F_STRING* string, CELL index, CELL value);
 
-DECLARE_PRIMITIVE(string_nth);
-DECLARE_PRIMITIVE(set_string_nth);
+void primitive_string_nth(void);
+void primitive_set_string_nth(void);
 
 F_WORD *allot_word(CELL vocab, CELL name);
-DECLARE_PRIMITIVE(word);
-DECLARE_PRIMITIVE(word_xt);
+void primitive_word(void);
+void primitive_word_xt(void);
 
-DECLARE_PRIMITIVE(wrapper);
+void primitive_wrapper(void);
 
 /* Macros to simulate a vector in C */
 #define GROWABLE_ARRAY(result) \