From 83a442c30fadd952750d6a30e3ad566e76e76168 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Wed, 21 Oct 2009 17:39:53 -0500 Subject: [PATCH 01/21] don't natural-sort the stack effects or $values in help-lint -- catches a lot more documentation errors --- basis/help/lint/checks/checks.factor | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/basis/help/lint/checks/checks.factor b/basis/help/lint/checks/checks.factor index 56f104a1a1..dac3900cc9 100644 --- a/basis/help/lint/checks/checks.factor +++ b/basis/help/lint/checks/checks.factor @@ -33,14 +33,13 @@ SYMBOL: vocab-articles : extract-values ( element -- seq ) \ $values swap elements dup empty? [ - first rest [ first ] map prune natural-sort + first rest [ first ] map prune ] unless ; : effect-values ( word -- seq ) stack-effect [ in>> ] [ out>> ] bi append - [ dup pair? [ first ] when effect>string ] map - prune natural-sort ; + [ dup pair? [ first ] when effect>string ] map prune ; : contains-funky-elements? ( element -- ? ) { From 0d4b9132d73bb4d9089b87d52e1498f6d1b97a25 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Wed, 21 Oct 2009 17:40:43 -0500 Subject: [PATCH 02/21] fix a bunch of typos in docs --- basis/cocoa/messages/messages-docs.factor | 4 ++-- basis/cocoa/subclassing/subclassing-docs.factor | 2 +- basis/concurrency/mailboxes/mailboxes-docs.factor | 3 ++- basis/delegate/delegate-docs.factor | 2 +- basis/documents/documents-docs.factor | 4 ++-- basis/heaps/heaps-docs.factor | 8 ++++---- basis/lists/lists-docs.factor | 2 +- basis/logging/logging-docs.factor | 8 ++++---- basis/math/functions/functions-docs.factor | 2 +- basis/tools/walker/walker-docs.factor | 2 +- basis/ui/gadgets/menus/menus-docs.factor | 2 +- basis/ui/gadgets/scrollers/scrollers-docs.factor | 2 +- basis/ui/gadgets/tracks/tracks-docs.factor | 2 +- basis/ui/pens/pens-docs.factor | 6 +++--- core/combinators/combinators-docs.factor | 2 +- core/continuations/continuations-docs.factor | 4 ++-- core/generic/generic-docs.factor | 2 +- core/io/streams/byte-array/byte-array-docs.factor | 5 +++-- core/kernel/kernel-docs.factor | 12 ++++++------ core/kernel/kernel.factor | 2 +- core/parser/parser-docs.factor | 2 +- core/sequences/sequences-docs.factor | 12 ++++++------ core/source-files/source-files-docs.factor | 2 +- 23 files changed, 47 insertions(+), 45 deletions(-) diff --git a/basis/cocoa/messages/messages-docs.factor b/basis/cocoa/messages/messages-docs.factor index 400599383f..7dee15d2e2 100644 --- a/basis/cocoa/messages/messages-docs.factor +++ b/basis/cocoa/messages/messages-docs.factor @@ -2,13 +2,13 @@ USING: help.markup help.syntax strings alien ; IN: cocoa.messages HELP: send -{ $values { "args..." "method arguments" } { "receiver" alien } { "selector" string } { "return..." "value returned by method, if any" } } +{ $values { "receiver" alien } { "args..." "method arguments" } { "selector" string } { "return..." "value returned by method, if any" } } { $description "Sends an Objective C message named by " { $snippet "selector" } " to " { $snippet "receiver" } ". The arguments must be on the stack in left-to-right order." } { $errors "Throws an error if the receiver does not recognize the message, or if the arguments have inappropriate types." } { $notes "This word uses a special fast code path if " { $snippet "selector" } " is a literal and the word containing the call to " { $link send } " is compiled." } ; HELP: super-send -{ $values { "args..." "method arguments" } { "receiver" alien } { "selector" string } { "return..." "value returned by method, if any" } } +{ $values { "receiver" alien } { "args..." "method arguments" } { "selector" string } { "return..." "value returned by method, if any" } } { $description "Sends an Objective C message named by " { $snippet "selector" } " to the super class of " { $snippet "receiver" } ". Otherwise behaves identically to " { $link send } "." } ; HELP: objc-class diff --git a/basis/cocoa/subclassing/subclassing-docs.factor b/basis/cocoa/subclassing/subclassing-docs.factor index 181912b0f0..0944727e46 100644 --- a/basis/cocoa/subclassing/subclassing-docs.factor +++ b/basis/cocoa/subclassing/subclassing-docs.factor @@ -2,7 +2,7 @@ USING: help.markup help.syntax strings alien hashtables ; IN: cocoa.subclassing HELP: define-objc-class -{ $values { "hash" hashtable } { "imeth" "a sequence of instance method definitions" } } +{ $values { "imeth" "a sequence of instance method definitions" } { "hash" hashtable } } { $description "Defines a new Objective C class. The hashtable can contain the following keys:" { $list { { $link +name+ } " - a string naming the new class. Required." } diff --git a/basis/concurrency/mailboxes/mailboxes-docs.factor b/basis/concurrency/mailboxes/mailboxes-docs.factor index a58a1a4cc6..727efd45d0 100644 --- a/basis/concurrency/mailboxes/mailboxes-docs.factor +++ b/basis/concurrency/mailboxes/mailboxes-docs.factor @@ -18,9 +18,10 @@ 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." } ; HELP: block-unless-pred -{ $values { "pred" { $quotation "( obj -- ? )" } } +{ $values { "mailbox" mailbox } { "timeout" "a " { $link duration } " or " { $link f } } + { "pred" { $quotation "( obj -- ? )" } } } { $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." } ; diff --git a/basis/delegate/delegate-docs.factor b/basis/delegate/delegate-docs.factor index 4ce3776277..d4867714d3 100644 --- a/basis/delegate/delegate-docs.factor +++ b/basis/delegate/delegate-docs.factor @@ -2,7 +2,7 @@ USING: help.syntax help.markup delegate.private ; IN: delegate HELP: define-protocol -{ $values { "wordlist" "a sequence of words" } { "protocol" "a word for the new protocol" } } +{ $values { "protocol" "a word for the new protocol" } { "wordlist" "a sequence of words" } } { $description "Defines a symbol as a protocol." } { $notes "Usually, " { $link POSTPONE: PROTOCOL: } " should be used instead. This is only for runtime use." } ; diff --git a/basis/documents/documents-docs.factor b/basis/documents/documents-docs.factor index 850c68fd9d..a4e02009df 100644 --- a/basis/documents/documents-docs.factor +++ b/basis/documents/documents-docs.factor @@ -12,11 +12,11 @@ HELP: +line { $description "Adds an integer to the line number of a line/column pair." } ; HELP: =col -{ $values { "loc" "a pair of integers" } { "n" integer } { "newloc" "a pair of integers" } } +{ $values { "n" integer } { "loc" "a pair of integers" } { "newloc" "a pair of integers" } } { $description "Sets the column number of a line/column pair." } ; HELP: =line -{ $values { "loc" "a pair of integers" } { "n" integer } { "newloc" "a pair of integers" } } +{ $values { "n" integer } { "loc" "a pair of integers" } { "newloc" "a pair of integers" } } { $description "Sets the line number of a line/column pair." } ; HELP: lines-equal? diff --git a/basis/heaps/heaps-docs.factor b/basis/heaps/heaps-docs.factor index 32b6ffe7ed..8ceb7bb78f 100644 --- a/basis/heaps/heaps-docs.factor +++ b/basis/heaps/heaps-docs.factor @@ -53,12 +53,12 @@ HELP: { $description "Create a new " { $link max-heap } "." } ; HELP: heap-push -{ $values { "key" "a comparable object" } { "value" object } { "heap" "a heap" } } +{ $values { "value" object } { "key" "a comparable object" } { "heap" "a heap" } } { $description "Push a pair onto a heap. The key must be comparable with all other keys by the " { $link <=> } " generic word." } { $side-effects "heap" } ; HELP: heap-push* -{ $values { "key" "a comparable object" } { "value" object } { "heap" "a heap" } { "entry" entry } } +{ $values { "value" object } { "key" "a comparable object" } { "heap" "a heap" } { "entry" entry } } { $description "Push a pair onto a heap, and output an entry which may later be passed to " { $link heap-delete } "." } { $side-effects "heap" } ; @@ -68,7 +68,7 @@ HELP: heap-push-all { $side-effects "heap" } ; HELP: heap-peek -{ $values { "heap" "a heap" } { "key" object } { "value" object } } +{ $values { "heap" "a heap" } { "value" object } { "key" object } } { $description "Output the first element in the heap, leaving it in the heap." } ; HELP: heap-pop* @@ -77,7 +77,7 @@ HELP: heap-pop* { $side-effects "heap" } ; HELP: heap-pop -{ $values { "heap" "a heap" } { "key" object } { "value" object } } +{ $values { "heap" "a heap" } { "value" object } { "key" object } } { $description "Output and remove the first element in the heap." } { $side-effects "heap" } ; diff --git a/basis/lists/lists-docs.factor b/basis/lists/lists-docs.factor index f70b6ff4a1..7fba57a4bb 100644 --- a/basis/lists/lists-docs.factor +++ b/basis/lists/lists-docs.factor @@ -122,7 +122,7 @@ HELP: uncons { $description "Put the head and tail of the list on the stack." } ; HELP: unswons -{ $values { "cons" list } { "car" "the head of the list" } { "cdr" "the tail of the list" } } +{ $values { "cons" list } { "cdr" "the tail of the list" } { "car" "the head of the list" } } { $description "Put the head and tail of the list on the stack." } ; { leach foldl lmap>array } related-words diff --git a/basis/logging/logging-docs.factor b/basis/logging/logging-docs.factor index 2dc5918bda..4af3f01ef7 100644 --- a/basis/logging/logging-docs.factor +++ b/basis/logging/logging-docs.factor @@ -47,19 +47,19 @@ HELP: log-message { $description "Sends a message to the current log if the level is more urgent than " { $link log-level } ". Does nothing if not executing in a dynamic scope established by " { $link with-logging } "." } ; HELP: add-logging -{ $values { "level" "a log level" } { "word" word } } +{ $values { "word" word } { "level" "a log level" } } { $description "Causes the word to log a message every time it is called." } ; HELP: add-input-logging -{ $values { "level" "a log level" } { "word" word } } +{ $values { "word" word } { "level" "a log level" } } { $description "Causes the word to log its input values every time it is called. The word must have a stack effect declaration." } ; HELP: add-output-logging -{ $values { "level" "a log level" } { "word" word } } +{ $values { "word" word } { "level" "a log level" } } { $description "Causes the word to log its output values every time it is called. The word must have a stack effect declaration." } ; HELP: add-error-logging -{ $values { "level" "a log level" } { "word" word } } +{ $values { "word" word } { "level" "a log level" } } { $description "Causes the word to log its input values and any errors it throws." $nl "If the word is not executed in a dynamic scope established by " { $link with-logging } ", its behavior is unchanged, and any errors it throws are passed to the caller." diff --git a/basis/math/functions/functions-docs.factor b/basis/math/functions/functions-docs.factor index 5b1920f572..1939de4f97 100644 --- a/basis/math/functions/functions-docs.factor +++ b/basis/math/functions/functions-docs.factor @@ -239,7 +239,7 @@ HELP: cis { cis exp } related-words HELP: polar> -{ $values { "z" number } { "abs" "a non-negative real number" } { "arg" real } } +{ $values { "abs" "a non-negative real number" } { "arg" real } { "z" number } } { $description "Converts an absolute value and argument (polar form) to a complex number." } ; HELP: [-1,1]? diff --git a/basis/tools/walker/walker-docs.factor b/basis/tools/walker/walker-docs.factor index bbfb9cbd9f..318f7e065c 100644 --- a/basis/tools/walker/walker-docs.factor +++ b/basis/tools/walker/walker-docs.factor @@ -6,7 +6,7 @@ HELP: breakpoint { $description "Annotates a word definition to enter the single stepper when executed." } ; HELP: breakpoint-if -{ $values { "quot" { $quotation "( -- ? )" } } { "word" word } } +{ $values { "word" word } { "quot" { $quotation "( -- ? )" } } } { $description "Annotates a word definition to enter the single stepper if the quotation yields true." } ; HELP: B diff --git a/basis/ui/gadgets/menus/menus-docs.factor b/basis/ui/gadgets/menus/menus-docs.factor index bebfaf13fe..b1ae421f52 100644 --- a/basis/ui/gadgets/menus/menus-docs.factor +++ b/basis/ui/gadgets/menus/menus-docs.factor @@ -3,7 +3,7 @@ kernel ; IN: ui.gadgets.menus HELP: -{ $values { "target" object } { "commands" "a sequence of commands" } { "hook" { $quotation "( button -- )" } } { "menu" "a new " { $link gadget } } } +{ $values { "target" object } { "hook" { $quotation "( button -- )" } } { "commands" "a sequence of commands" } { "menu" "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 diff --git a/basis/ui/gadgets/scrollers/scrollers-docs.factor b/basis/ui/gadgets/scrollers/scrollers-docs.factor index 1e4b875f28..17adb2bd64 100644 --- a/basis/ui/gadgets/scrollers/scrollers-docs.factor +++ b/basis/ui/gadgets/scrollers/scrollers-docs.factor @@ -24,7 +24,7 @@ HELP: { } related-words HELP: set-scroll-position -{ $values { "scroller" scroller } { "value" "a pair of integers" } } +{ $values { "value" "a pair of integers" } { "scroller" scroller } } { $description "Sets the offset of the top-left corner of the scroller's " { $link viewport } "'s child." } ; HELP: relative-scroll-rect diff --git a/basis/ui/gadgets/tracks/tracks-docs.factor b/basis/ui/gadgets/tracks/tracks-docs.factor index 0bbedc8d0d..cf5c94aa6b 100644 --- a/basis/ui/gadgets/tracks/tracks-docs.factor +++ b/basis/ui/gadgets/tracks/tracks-docs.factor @@ -18,7 +18,7 @@ HELP: { $description "Creates a new track which lays out children along the given orientation, either " { $link horizontal } " or " { $link vertical } "." } ; HELP: track-add -{ $values { "gadget" gadget } { "track" track } { "constraint" "a number between 0 and 1, or " { $link f } } } +{ $values { "track" track } { "gadget" gadget } { "constraint" "a number between 0 and 1, or " { $link f } } } { $description "Adds a new child to a track. If the constraint is " { $link f } ", the child always occupies its preferred size. Otherwise, the constrant is a fraction of the total size which is allocated for the child." } ; ABOUT: "ui-track-layout" diff --git a/basis/ui/pens/pens-docs.factor b/basis/ui/pens/pens-docs.factor index 4aa0e50945..4a5ec277f0 100644 --- a/basis/ui/pens/pens-docs.factor +++ b/basis/ui/pens/pens-docs.factor @@ -2,11 +2,11 @@ IN: ui.pens USING: help.markup help.syntax kernel ui.gadgets ; HELP: draw-interior -{ $values { "pen" object } { "gadget" gadget } } +{ $values { "gadget" gadget } { "pen" object } } { $contract "Draws the interior of a gadget by making OpenGL calls. The " { $snippet "interior" } " slot may be set to objects implementing this generic word." } ; HELP: draw-boundary -{ $values { "pen" object } { "gadget" gadget } } +{ $values { "gadget" gadget } { "pen" object } } { $contract "Draws the boundary of a gadget by making OpenGL calls. The " { $snippet "boundary" } " slot may be set to objects implementing this generic word." } ; ARTICLE: "ui-pen-protocol" "UI pen protocol" @@ -23,4 +23,4 @@ $nl { $vocab-subsection "Polygon pens" "ui.pens.polygon" } { $vocab-subsection "Solid pens" "ui.pens.solid" } { $vocab-subsection "Tile pens" "ui.pens.tile" } -"Custom implementations must follow the guidelines set forth in " { $link "ui-paint-custom" } "." ; \ No newline at end of file +"Custom implementations must follow the guidelines set forth in " { $link "ui-paint-custom" } "." ; diff --git a/core/combinators/combinators-docs.factor b/core/combinators/combinators-docs.factor index 4701476d2a..1717359fa8 100755 --- a/core/combinators/combinators-docs.factor +++ b/core/combinators/combinators-docs.factor @@ -438,7 +438,7 @@ $nl { $notes "This word is used behind the scenes to compile " { $link cond } " forms efficiently; it can also be called directly, which is useful for meta-programming." } ; HELP: case>quot -{ $values { "assoc" "a sequence of pairs of quotations" } { "default" quotation } { "quot" quotation } } +{ $values { "default" quotation } { "assoc" "a sequence of pairs of quotations" } { "quot" quotation } } { $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "." $nl "This word uses three strategies:" diff --git a/core/continuations/continuations-docs.factor b/core/continuations/continuations-docs.factor index 5fb5a38af2..84da26a082 100644 --- a/core/continuations/continuations-docs.factor +++ b/core/continuations/continuations-docs.factor @@ -122,7 +122,7 @@ HELP: continuation { $description "Reifies the current continuation from the point immediately after which the caller returns." } ; HELP: >continuation< -{ $values { "continuation" continuation } { "data" vector } { "retain" vector } { "call" vector } { "name" vector } { "catch" vector } } +{ $values { "continuation" continuation } { "data" vector } { "call" vector } { "retain" vector } { "name" vector } { "catch" vector } } { $description "Takes a continuation apart into its constituents." } ; HELP: ifcc @@ -271,4 +271,4 @@ HELP: with-return HELP: restart { $values { "restart" restart } } { $description "Invokes a restart." } -{ $class-description "The class of restarts." } ; \ No newline at end of file +{ $class-description "The class of restarts." } ; diff --git a/core/generic/generic-docs.factor b/core/generic/generic-docs.factor index 0f80aac2f3..dea523538e 100644 --- a/core/generic/generic-docs.factor +++ b/core/generic/generic-docs.factor @@ -124,7 +124,7 @@ HELP: make-generic $low-level-note ; HELP: define-generic -{ $values { "word" word } { "effect" effect } { "combination" "a method combination" } } +{ $values { "word" word } { "combination" "a method combination" } { "effect" effect } } { $description "Defines a generic word. A method combination is an object which responds to the " { $link perform-combination } " generic word." } { $contract "The method combination quotation is called each time the generic word has to be updated (for example, when a method is added), and thus must be side-effect free." } ; diff --git a/core/io/streams/byte-array/byte-array-docs.factor b/core/io/streams/byte-array/byte-array-docs.factor index 1bc09429dc..eeada8d0c9 100644 --- a/core/io/streams/byte-array/byte-array-docs.factor +++ b/core/io/streams/byte-array/byte-array-docs.factor @@ -27,8 +27,9 @@ HELP: { $description "Creates an output stream writing data to a byte array using an encoding." } ; HELP: with-byte-reader -{ $values { "encoding" "an encoding descriptor" } - { "quot" quotation } { "byte-array" byte-array } } +{ $values { "byte-array" byte-array } + { "encoding" "an encoding descriptor" } + { "quot" quotation } } { $description "Calls the quotation in a new dynamic scope with " { $link input-stream } " rebound to an input stream for reading from a byte array using an encoding." } ; HELP: with-byte-writer diff --git a/core/kernel/kernel-docs.factor b/core/kernel/kernel-docs.factor index 3f1e715448..d4f8f3c28c 100644 --- a/core/kernel/kernel-docs.factor +++ b/core/kernel/kernel-docs.factor @@ -168,7 +168,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" { $quotation "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } } +{ $values { "x" object } { "y" object } { "quot" { $quotation "( obj -- ? )" } } { "?" "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" } @@ -176,7 +176,7 @@ HELP: both? } ; HELP: either? -{ $values { "quot" { $quotation "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } } +{ $values { "x" object } { "y" object } { "quot" { $quotation "( obj -- ? )" } } { "?" "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" } @@ -213,18 +213,18 @@ HELP: call-clear ( quot -- ) { $notes "Used to implement " { $link "threads" } "." } ; HELP: keep -{ $values { "quot" { $quotation "( x -- ... )" } } { "x" object } } +{ $values { "x" object } { "quot" { $quotation "( x -- ... )" } } } { $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." } { $examples { $example "USING: arrays kernel prettyprint ;" "2 \"greetings\" [ ] keep 2array ." "{ { \"greetings\" \"greetings\" } \"greetings\" }" } } ; HELP: 2keep -{ $values { "quot" { $quotation "( x y -- ... )" } } { "x" object } { "y" object } } +{ $values { "x" object } { "y" object } { "quot" { $quotation "( x y -- ... )" } } } { $description "Call a quotation with two values on the stack, restoring the values when the quotation returns." } ; HELP: 3keep -{ $values { "quot" { $quotation "( x y z -- ... )" } } { "x" object } { "y" object } { "z" object } } +{ $values { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( x y z -- ... )" } } } { $description "Call a quotation with three values on the stack, restoring the values when the quotation returns." } ; HELP: bi @@ -664,7 +664,7 @@ HELP: getenv ( n -- obj ) { $description "Reads an object from the Factor VM's environment table. User code never has to read the environment table directly; instead, use one of the callers of this word." } ; HELP: setenv ( obj n -- ) -{ $values { "n" "a non-negative integer" } { "obj" object } } +{ $values { "obj" object } { "n" "a non-negative integer" } } { $description "Writes an object to the Factor VM's environment table. User code never has to write to the environment table directly; instead, use one of the callers of this word." } ; HELP: object diff --git a/core/kernel/kernel.factor b/core/kernel/kernel.factor index 838d877a40..6538109687 100644 --- a/core/kernel/kernel.factor +++ b/core/kernel/kernel.factor @@ -122,7 +122,7 @@ DEFER: if : 2bi@ ( w x y z quot -- ) dup 2bi* ; inline -: 2tri@ ( u v w y x z quot -- ) +: 2tri@ ( u v w x y z quot -- ) dup dup 2tri* ; inline ! Quotation building diff --git a/core/parser/parser-docs.factor b/core/parser/parser-docs.factor index 7e94d71c29..888f9f3b4c 100644 --- a/core/parser/parser-docs.factor +++ b/core/parser/parser-docs.factor @@ -188,7 +188,7 @@ HELP: parse-lines { $errors "Throws a " { $link lexer-error } " if the input is malformed." } ; HELP: parse-base -{ $values { "base" "an integer between 2 and 36" } { "parsed" integer } } +{ $values { "parsed" integer } { "base" "an integer between 2 and 36" } { "parsed" integer } } { $description "Reads an integer in a specific numerical base from the parser input." } $parsing-note ; diff --git a/core/sequences/sequences-docs.factor b/core/sequences/sequences-docs.factor index ef02754a60..9fd48796d6 100755 --- a/core/sequences/sequences-docs.factor +++ b/core/sequences/sequences-docs.factor @@ -218,7 +218,7 @@ HELP: 3sequence { $description "Creates a three-element sequence of the same type as " { $snippet "exemplar" } "." } ; HELP: 4sequence -{ $values { "obj1" object } { "obj2" object } { "exemplar" sequence } { "obj3" object } { "obj4" object } { "seq" sequence } } +{ $values { "obj1" object } { "obj2" object } { "obj3" object } { "obj4" object } { "exemplar" sequence } { "seq" sequence } } { $description "Creates a four-element sequence of the same type as " { $snippet "exemplar" } "." } ; HELP: first2 @@ -277,7 +277,7 @@ HELP: reduce-index } } ; HELP: accumulate-as -{ $values { "identity" object } { "seq" sequence } { "quot" { $quotation "( prev elt -- next )" } } { "exemplar" sequence } { "final" "the final result" } { "newseq" "a new sequence" } } +{ $values { "seq" sequence } { "identity" object } { "quot" { $quotation "( prev elt -- next )" } } { "exemplar" sequence } { "final" "the final result" } { "newseq" "a new sequence" } } { $description "Combines successive elements of the sequence using a binary operation, and outputs a sequence of the same type as " { $snippet "exemplar" } " containing intermediate results, together with the final result." $nl "The first element of the new sequence is " { $snippet "identity" } ". Then, on the first iteration, the two inputs to the quotation are " { $snippet "identity" } ", and the first element of the old sequence. On successive iterations, the first input is the result of the previous iteration, and the second input is the corresponding element of the old sequence." @@ -285,7 +285,7 @@ $nl "When given the empty sequence, outputs an empty sequence together with the " { $snippet "identity" } "." } ; HELP: accumulate -{ $values { "identity" object } { "seq" sequence } { "quot" { $quotation "( prev elt -- next )" } } { "final" "the final result" } { "newseq" "a new array" } } +{ $values { "seq" sequence } { "identity" object } { "quot" { $quotation "( prev elt -- next )" } } { "final" "the final result" } { "newseq" "a new array" } } { $description "Combines successive elements of the sequence using a binary operation, and outputs an array of intermediate results, together with the final result." $nl "The first element of the new sequence is " { $snippet "identity" } ". Then, on the first iteration, the two inputs to the quotation are " { $snippet "identity" } ", and the first element of the old sequence. On successive iterations, the first input is the result of the previous iteration, and the second input is the corresponding element of the old sequence." @@ -300,7 +300,7 @@ HELP: map { $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" { $quotation "( old -- new )" } } { "newseq" "a new sequence" } { "exemplar" sequence } } +{ $values { "seq" sequence } { "quot" { $quotation "( old -- new )" } } { "exemplar" sequence } { "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 " { $snippet "exemplar" } "." } { $examples "The following example converts a string into an array of one-element strings:" @@ -483,7 +483,7 @@ HELP: remove-nth } } ; HELP: move -{ $values { "from" "an index in " { $snippet "seq" } } { "to" "an index in " { $snippet "seq" } } { "seq" "a mutable sequence" } } +{ $values { "to" "an index in " { $snippet "seq" } } { "from" "an index in " { $snippet "seq" } } { "seq" "a mutable sequence" } } { $description "Sets the element with index " { $snippet "m" } " to the element with index " { $snippet "n" } "." } { $side-effects "seq" } ; @@ -510,7 +510,7 @@ HELP: delete-slice { $side-effects "seq" } ; HELP: replace-slice -{ $values { "new" sequence } { "seq" sequence } { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "seq'" sequence } } +{ $values { "new" sequence } { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "seq" sequence } { "seq'" sequence } } { $description "Replaces a range of elements beginning at index " { $snippet "from" } " and ending before index " { $snippet "to" } " with a new sequence." } { $errors "Throws an error if " { $snippet "new" } " contains elements whose types are not permissible in " { $snippet "seq" } "." } ; diff --git a/core/source-files/source-files-docs.factor b/core/source-files/source-files-docs.factor index ef19d16351..cb1e5e6017 100644 --- a/core/source-files/source-files-docs.factor +++ b/core/source-files/source-files-docs.factor @@ -38,7 +38,7 @@ HELP: source-file } ; HELP: record-checksum -{ $values { "source-file" source-file } { "lines" "a sequence of strings" } } +{ $values { "lines" "a sequence of strings" } { "source-file" source-file } } { $description "Records the CRC32 checksm of the source file's contents." } $low-level-note ; From 1b4e3cb7a6735200104fe1fec57b30e4a01b2b97 Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Wed, 21 Oct 2009 18:11:24 -0500 Subject: [PATCH 03/21] fix more docs typos --- basis/furnace/auth/auth-docs.factor | 2 +- basis/math/primes/primes-docs.factor | 3 ++- basis/persistent/heaps/heaps-docs.factor | 2 +- extra/models/combinators/combinators-docs.factor | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/basis/furnace/auth/auth-docs.factor b/basis/furnace/auth/auth-docs.factor index c7fc0d5f0b..5aab808763 100644 --- a/basis/furnace/auth/auth-docs.factor +++ b/basis/furnace/auth/auth-docs.factor @@ -63,7 +63,7 @@ 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 )" } } } +{ $values { "quot" { $quotation "( old -- new )" } } { "key" symbol } } { $description "Applies the quotation to the old value of the user profile variable, and assigns the resulting value back to the variable." } ; HELP: uget diff --git a/basis/math/primes/primes-docs.factor b/basis/math/primes/primes-docs.factor index 7f525debfe..74aa2ebca3 100644 --- a/basis/math/primes/primes-docs.factor +++ b/basis/math/primes/primes-docs.factor @@ -44,7 +44,8 @@ HELP: random-prime HELP: unique-primes { $values - { "numbits" integer } { "n" integer } + { "n" integer } + { "numbits" integer } { "seq" sequence } } { $description "Generates a sequence of " { $snippet "n" } " unique prime numbers with exactly " { $snippet "numbits" } " bits." } ; diff --git a/basis/persistent/heaps/heaps-docs.factor b/basis/persistent/heaps/heaps-docs.factor index 49852bac4d..31422f23b9 100644 --- a/basis/persistent/heaps/heaps-docs.factor +++ b/basis/persistent/heaps/heaps-docs.factor @@ -18,7 +18,7 @@ HELP: pheap-peek { $description "Gets the object in the heap with minumum priority." } ; HELP: pheap-push -{ $values { "heap" "a persistent heap" } { "value" object } { "prio" "a priority" } { "newheap" "a new persistent heap" } } +{ $values { "value" object } { "prio" "a priority" } { "heap" "a persistent heap" } { "newheap" "a new persistent heap" } } { $description "Creates a new persistent heap also containing the given object of the given priority." } ; HELP: pheap-pop* diff --git a/extra/models/combinators/combinators-docs.factor b/extra/models/combinators/combinators-docs.factor index 5ccfe1f758..8ac3657105 100644 --- a/extra/models/combinators/combinators-docs.factor +++ b/extra/models/combinators/combinators-docs.factor @@ -10,7 +10,7 @@ HELP: filter-model { $description "Creates a model that uses the updates of another model only when they satisfy a given predicate" } ; HELP: fold -{ $values { "oldval" "starting value" } { "quot" "applied to update and previous values" } { "model" model } { "model" model } } +{ $values { "model" model } { "oldval" "starting value" } { "quot" "applied to update and previous values" } { "model" model } } { $description "Similar to " { $link reduce } " but works on models, applying a quotation to the previous and new values at each update" } ; HELP: switch-models @@ -38,4 +38,4 @@ ARTICLE: "models.combinators" "Extending models" "Also, it provides methods of manipulating and combining models, expecially useful when programming user interfaces: " "The output models of some gadgets (see " { $vocab-link "ui.gadgets.controls" } " ) can be manipulated and used as the input models of others. " ; -ABOUT: "models.combinators" \ No newline at end of file +ABOUT: "models.combinators" From 3f1b664b74b57f1ef1f845f28419171f514fea74 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 13:31:03 -0500 Subject: [PATCH 04/21] break off a "sequences.generalizations" vocab for neach, nmap, and mnmap --- .../generalizations-docs.factor | 28 +---- .../generalizations-tests.factor | 102 ----------------- basis/generalizations/generalizations.factor | 54 --------- .../generalizations-docs.factor | 36 ++++++ .../generalizations-tests.factor | 107 ++++++++++++++++++ .../generalizations/generalizations.factor | 59 ++++++++++ extra/alien/data/map/map.factor | 3 +- 7 files changed, 206 insertions(+), 183 deletions(-) create mode 100644 basis/sequences/generalizations/generalizations-docs.factor create mode 100644 basis/sequences/generalizations/generalizations-tests.factor create mode 100644 basis/sequences/generalizations/generalizations.factor diff --git a/basis/generalizations/generalizations-docs.factor b/basis/generalizations/generalizations-docs.factor index f5c0de2ea2..e9a709030e 100644 --- a/basis/generalizations/generalizations-docs.factor +++ b/basis/generalizations/generalizations-docs.factor @@ -266,26 +266,6 @@ HELP: spread-curry { $description "Curries the " { $snippet "n" } " quotations on the top of the datastack with the " { $snippet "n" } " values just below them. A generalization of " { $link bi-curry* } " and " { $link tri-curry* } "." } { $notes "This word can be used with " { $link cleave* } " and " { $link spread* } " to generalize dataflow patterns such as " { $snippet "bi-curry* bi" } ", " { $snippet "tri-curry* tri" } ", " { $snippet "bi-curry* bi*" } ", and " { $snippet "tri-curry* tri*" } "." } ; -HELP: neach -{ $values { "...seq" { $snippet "n" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( ...element -- )" } } { "n" integer } } -{ $description "A generalization of " { $link each } ", " { $link 2each } ", and " { $link 3each } " that can iterate over any number of sequences in parallel." } ; - -HELP: nmap -{ $values { "...seq" { $snippet "n" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( ...element -- result )" } } { "n" integer } { "result" "a sequence of the same type as the first " { $snippet "seq" } } } -{ $description "A generalization of " { $link map } ", " { $link 2map } ", and " { $link 3map } " that can map over any number of sequences in parallel." } ; - -HELP: nmap-as -{ $values { "...seq" { $snippet "n" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( ...element -- result )" } } { "exemplar" sequence } { "n" integer } { "result" "a sequence of the same type as " { $snippet "exemplar" } } } -{ $description "A generalization of " { $link map-as } ", " { $link 2map-as } ", and " { $link 3map-as } " that can map over any number of sequences in parallel." } ; - -HELP: mnmap -{ $values { "m*seq" { $snippet "m" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( m*element -- result*n )" } } { "m" integer } { "n" integer } { "result*n" { $snippet "n" } " sequences of the same type as the first " { $snippet "seq" } } } -{ $description "A generalization of " { $link map } ", " { $link 2map } ", and " { $link 3map } " that can map over any number of sequences in parallel and provide any number of output sequences." } ; - -HELP: mnmap-as -{ $values { "m*seq" { $snippet "m" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( m*element -- result*n )" } } { "n*exemplar" { $snippet "n" } " sequences on the datastack" } { "m" integer } { "n" integer } { "result*n" { $snippet "n" } " sequences of the same type as the " { $snippet "exemplar" } "s" } } -{ $description "A generalization of " { $link map-as } ", " { $link 2map-as } ", and " { $link 3map-as } " that can map over any number of sequences in parallel and provide any number of output sequences of distinct types." } ; - HELP: mnswap { $values { "m" integer } { "n" integer } } { $description "Swaps the top " { $snippet "m" } " stack elements with the " { $snippet "n" } " elements directly underneath." } @@ -401,11 +381,6 @@ ARTICLE: "combinator-generalizations" "Generalized combinators" apply-curry cleave-curry spread-curry - neach - nmap - nmap-as - mnmap - mnmap-as } ; ARTICLE: "other-generalizations" "Additional generalizations" @@ -424,6 +399,7 @@ ARTICLE: "generalizations" "Generalized shuffle words and combinators" "shuffle-generalizations" "combinator-generalizations" "other-generalizations" -} ; +} +"Also see the " { $vocab-link "sequences.generalizations" } " vocabulary for generalized sequence iteration combinators." ; ABOUT: "generalizations" diff --git a/basis/generalizations/generalizations-tests.factor b/basis/generalizations/generalizations-tests.factor index cb2c40ca0a..c54e35002f 100644 --- a/basis/generalizations/generalizations-tests.factor +++ b/basis/generalizations/generalizations-tests.factor @@ -82,108 +82,6 @@ IN: generalizations.tests [ '[ number>string _ append ] 4 napply ] must-infer -: neach-test ( a b c d -- ) - [ 4 nappend print ] 4 neach ; -: nmap-test ( a b c d -- e ) - [ 4 nappend ] 4 nmap ; -: nmap-as-test ( a b c d -- e ) - [ 4 nappend ] [ ] 4 nmap-as ; -: mnmap-3-test ( a b c d -- e f g ) - [ append ] 4 3 mnmap ; -: mnmap-2-test ( a b c d -- e f ) - [ [ append ] 2bi@ ] 4 2 mnmap ; -: mnmap-as-test ( a b c d -- e f ) - [ [ append ] 2bi@ ] { } [ ] 4 2 mnmap-as ; -: mnmap-1-test ( a b c d -- e ) - [ 4 nappend ] 4 1 mnmap ; -: mnmap-0-test ( a b c d -- ) - [ 4 nappend print ] 4 0 mnmap ; - -[ """A1a! -B2b@ -C3c# -D4d$ -""" ] [ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - [ neach-test ] with-string-writer -] unit-test - -[ { "A1a!" "B2b@" "C3c#" "D4d$" } ] -[ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - nmap-test -] unit-test - -[ [ "A1a!" "B2b@" "C3c#" "D4d$" ] ] -[ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - nmap-as-test -] unit-test - -[ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a!" "b@" "c#" "d$" } -] [ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - mnmap-3-test -] unit-test - -[ - { "A1" "B2" "C3" "D4" } - { "a!" "b@" "c#" "d$" } -] [ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - mnmap-2-test -] unit-test - -[ - { "A1" "B2" "C3" "D4" } - [ "a!" "b@" "c#" "d$" ] -] [ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - mnmap-as-test -] unit-test - -[ { "A1a!" "B2b@" "C3c#" "D4d$" } ] -[ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - mnmap-1-test -] unit-test - -[ """A1a! -B2b@ -C3c# -D4d$ -""" ] [ - { "A" "B" "C" "D" } - { "1" "2" "3" "4" } - { "a" "b" "c" "d" } - { "!" "@" "#" "$" } - [ mnmap-0-test ] with-string-writer -] unit-test - [ 6 8 10 12 ] [ 1 2 3 4 5 6 7 8 [ + ] 4 apply-curry 4 spread* diff --git a/basis/generalizations/generalizations.factor b/basis/generalizations/generalizations.factor index 2ae076655e..8d6d6f2ac0 100644 --- a/basis/generalizations/generalizations.factor +++ b/basis/generalizations/generalizations.factor @@ -142,57 +142,3 @@ MACRO: nbi-curry ( n -- ) MACRO: nspin ( n -- ) [ [ ] ] swap [ swap [ ] curry compose ] n*quot [ call ] 3append ; -MACRO: nmin-length ( n -- ) - dup 1 - [ min ] n*quot - '[ [ length ] _ napply @ ] ; - -: nnth-unsafe ( n ...seq n -- ) - [ nth-unsafe ] swap [ apply-curry ] [ cleave* ] bi ; inline -MACRO: nset-nth-unsafe ( n -- ) - [ [ drop ] ] - [ '[ [ set-nth-unsafe ] _ [ apply-curry ] [ cleave-curry ] [ spread* ] tri ] ] - if-zero ; - -: (neach) ( ...seq quot n -- len quot' ) - dup dup dup - '[ [ _ nmin-length ] _ nkeep [ _ nnth-unsafe ] _ ncurry ] dip compose ; inline - -: neach ( ...seq quot n -- ) - (neach) each-integer ; inline - -: nmap-as ( ...seq quot exemplar n -- result ) - '[ _ (neach) ] dip map-integers ; inline - -: nmap ( ...seq quot n -- result ) - dup '[ [ _ npick ] dip swap ] dip nmap-as ; inline - -MACRO: nnew-sequence ( n -- ) - [ [ drop ] ] - [ dup '[ [ new-sequence ] _ apply-curry _ cleave* ] ] if-zero ; - -: nnew-like ( len ...exemplar quot n -- result... ) - dup dup dup dup '[ - _ nover - [ [ _ nnew-sequence ] dip call ] - _ ndip [ like ] - _ apply-curry - _ spread* - ] call ; inline - -MACRO: (ncollect) ( n -- ) - dup dup 1 + - '[ [ [ keep ] _ ndip _ nset-nth-unsafe ] _ ncurry ] ; - -: ncollect ( len quot ...into n -- ) - (ncollect) each-integer ; inline - -: nmap-integers ( len quot ...exemplar n -- result... ) - dup dup dup - '[ [ over ] _ ndip [ [ _ ncollect ] _ nkeep ] _ nnew-like ] call ; inline - -: mnmap-as ( m*seq quot n*exemplar m n -- result*n ) - dup '[ [ _ (neach) ] _ ndip _ nmap-integers ] call ; inline - -: mnmap ( m*seq quot m n -- result*n ) - 2dup '[ [ _ npick ] dip swap _ dupn ] 2dip mnmap-as ; inline - diff --git a/basis/sequences/generalizations/generalizations-docs.factor b/basis/sequences/generalizations/generalizations-docs.factor new file mode 100644 index 0000000000..d2e8c0c5fc --- /dev/null +++ b/basis/sequences/generalizations/generalizations-docs.factor @@ -0,0 +1,36 @@ +! (c)2009 Joe Groff bsd license +USING: help.syntax help.markup kernel sequences quotations +math arrays combinators ; +IN: sequences.generalizations + +HELP: neach +{ $values { "...seq" { $snippet "n" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( ...element -- )" } } { "n" integer } } +{ $description "A generalization of " { $link each } ", " { $link 2each } ", and " { $link 3each } " that can iterate over any number of sequences in parallel." } ; + +HELP: nmap +{ $values { "...seq" { $snippet "n" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( ...element -- result )" } } { "n" integer } { "result" "a sequence of the same type as the first " { $snippet "seq" } } } +{ $description "A generalization of " { $link map } ", " { $link 2map } ", and " { $link 3map } " that can map over any number of sequences in parallel." } ; + +HELP: nmap-as +{ $values { "...seq" { $snippet "n" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( ...element -- result )" } } { "exemplar" sequence } { "n" integer } { "result" "a sequence of the same type as " { $snippet "exemplar" } } } +{ $description "A generalization of " { $link map-as } ", " { $link 2map-as } ", and " { $link 3map-as } " that can map over any number of sequences in parallel." } ; + +HELP: mnmap +{ $values { "m*seq" { $snippet "m" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( m*element -- result*n )" } } { "m" integer } { "n" integer } { "result*n" { $snippet "n" } " sequences of the same type as the first " { $snippet "seq" } } } +{ $description "A generalization of " { $link map } ", " { $link 2map } ", and " { $link 3map } " that can map over any number of sequences in parallel and provide any number of output sequences." } ; + +HELP: mnmap-as +{ $values { "m*seq" { $snippet "m" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( m*element -- result*n )" } } { "n*exemplar" { $snippet "n" } " sequences on the datastack" } { "m" integer } { "n" integer } { "result*n" { $snippet "n" } " sequences of the same type as the " { $snippet "exemplar" } "s" } } +{ $description "A generalization of " { $link map-as } ", " { $link 2map-as } ", and " { $link 3map-as } " that can map over any number of sequences in parallel and provide any number of output sequences of distinct types." } ; + +ARTICLE: "sequences.generalizations" "Generalized sequence iteration combinators" +"The " { $vocab-link "sequences.generalizations" } " vocabulary defines generalized versions of the iteration " { $link "sequences-combinators" } "." +{ $subsections + neach + nmap + nmap-as + mnmap + mnmap-as +} ; + +ABOUT: "sequences.generalizations" diff --git a/basis/sequences/generalizations/generalizations-tests.factor b/basis/sequences/generalizations/generalizations-tests.factor new file mode 100644 index 0000000000..ac1990743e --- /dev/null +++ b/basis/sequences/generalizations/generalizations-tests.factor @@ -0,0 +1,107 @@ +! (c)2009 Joe Groff bsd license +USING: tools.test generalizations kernel math arrays sequences +sequences.generalizations ascii fry math.parser io io.streams.string ; +IN: sequences.generalizations.tests + +: neach-test ( a b c d -- ) + [ 4 nappend print ] 4 neach ; +: nmap-test ( a b c d -- e ) + [ 4 nappend ] 4 nmap ; +: nmap-as-test ( a b c d -- e ) + [ 4 nappend ] [ ] 4 nmap-as ; +: mnmap-3-test ( a b c d -- e f g ) + [ append ] 4 3 mnmap ; +: mnmap-2-test ( a b c d -- e f ) + [ [ append ] 2bi@ ] 4 2 mnmap ; +: mnmap-as-test ( a b c d -- e f ) + [ [ append ] 2bi@ ] { } [ ] 4 2 mnmap-as ; +: mnmap-1-test ( a b c d -- e ) + [ 4 nappend ] 4 1 mnmap ; +: mnmap-0-test ( a b c d -- ) + [ 4 nappend print ] 4 0 mnmap ; + +[ """A1a! +B2b@ +C3c# +D4d$ +""" ] [ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + [ neach-test ] with-string-writer +] unit-test + +[ { "A1a!" "B2b@" "C3c#" "D4d$" } ] +[ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + nmap-test +] unit-test + +[ [ "A1a!" "B2b@" "C3c#" "D4d$" ] ] +[ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + nmap-as-test +] unit-test + +[ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a!" "b@" "c#" "d$" } +] [ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + mnmap-3-test +] unit-test + +[ + { "A1" "B2" "C3" "D4" } + { "a!" "b@" "c#" "d$" } +] [ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + mnmap-2-test +] unit-test + +[ + { "A1" "B2" "C3" "D4" } + [ "a!" "b@" "c#" "d$" ] +] [ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + mnmap-as-test +] unit-test + +[ { "A1a!" "B2b@" "C3c#" "D4d$" } ] +[ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + mnmap-1-test +] unit-test + +[ """A1a! +B2b@ +C3c# +D4d$ +""" ] [ + { "A" "B" "C" "D" } + { "1" "2" "3" "4" } + { "a" "b" "c" "d" } + { "!" "@" "#" "$" } + [ mnmap-0-test ] with-string-writer +] unit-test + diff --git a/basis/sequences/generalizations/generalizations.factor b/basis/sequences/generalizations/generalizations.factor new file mode 100644 index 0000000000..4365c1494d --- /dev/null +++ b/basis/sequences/generalizations/generalizations.factor @@ -0,0 +1,59 @@ +USING: kernel sequences sequences.private math +combinators macros math.order math.ranges quotations fry effects +memoize.private generalizations ; +IN: sequences.generalizations + +MACRO: nmin-length ( n -- ) + dup 1 - [ min ] n*quot + '[ [ length ] _ napply @ ] ; + +: nnth-unsafe ( n ...seq n -- ) + [ nth-unsafe ] swap [ apply-curry ] [ cleave* ] bi ; inline +MACRO: nset-nth-unsafe ( n -- ) + [ [ drop ] ] + [ '[ [ set-nth-unsafe ] _ [ apply-curry ] [ cleave-curry ] [ spread* ] tri ] ] + if-zero ; + +: (neach) ( ...seq quot n -- len quot' ) + dup dup dup + '[ [ _ nmin-length ] _ nkeep [ _ nnth-unsafe ] _ ncurry ] dip compose ; inline + +: neach ( ...seq quot n -- ) + (neach) each-integer ; inline + +: nmap-as ( ...seq quot exemplar n -- result ) + '[ _ (neach) ] dip map-integers ; inline + +: nmap ( ...seq quot n -- result ) + dup '[ [ _ npick ] dip swap ] dip nmap-as ; inline + +MACRO: nnew-sequence ( n -- ) + [ [ drop ] ] + [ dup '[ [ new-sequence ] _ apply-curry _ cleave* ] ] if-zero ; + +: nnew-like ( len ...exemplar quot n -- result... ) + dup dup dup dup '[ + _ nover + [ [ _ nnew-sequence ] dip call ] + _ ndip [ like ] + _ apply-curry + _ spread* + ] call ; inline + +MACRO: (ncollect) ( n -- ) + dup dup 1 + + '[ [ [ keep ] _ ndip _ nset-nth-unsafe ] _ ncurry ] ; + +: ncollect ( len quot ...into n -- ) + (ncollect) each-integer ; inline + +: nmap-integers ( len quot ...exemplar n -- result... ) + dup dup dup + '[ [ over ] _ ndip [ [ _ ncollect ] _ nkeep ] _ nnew-like ] call ; inline + +: mnmap-as ( m*seq quot n*exemplar m n -- result*n ) + dup '[ [ _ (neach) ] _ ndip _ nmap-integers ] call ; inline + +: mnmap ( m*seq quot m n -- result*n ) + 2dup '[ [ _ npick ] dip swap _ dupn ] 2dip mnmap-as ; inline + diff --git a/extra/alien/data/map/map.factor b/extra/alien/data/map/map.factor index 72f5cb5517..62bd45938b 100644 --- a/extra/alien/data/map/map.factor +++ b/extra/alien/data/map/map.factor @@ -1,7 +1,8 @@ ! (c)Joe Groff bsd license USING: accessors alien alien.c-types alien.data alien.parser arrays byte-arrays combinators effects.parser fry generalizations grouping kernel -lexer locals macros make math math.ranges parser sequences sequences.private ; +lexer locals macros make math math.ranges parser sequences +sequences.generalizations sequences.private ; FROM: alien.arrays => array-length ; IN: alien.data.map From fdea9b09f2aab1553dcafc9f41f81e4eb04f19ce Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 14:35:27 -0500 Subject: [PATCH 05/21] change produce-as so it uses an intermediate vector of a type appropriate to the destination type --- core/sequences/sequences.factor | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index c64095cb73..6e7d8984b2 100755 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -498,11 +498,14 @@ PRIVATE> : partition ( seq quot -- trueseq falseseq ) over [ 2pusher [ each ] 2dip ] dip [ like ] curry bi@ ; inline +: accumulator-for ( quot exemplar -- quot' vec ) + [ length ] keep new-resizable [ [ push ] curry compose ] keep ; inline + : accumulator ( quot -- quot' vec ) - V{ } clone [ [ push ] curry compose ] keep ; inline + V{ } accumulator-for ; inline : produce-as ( pred quot exemplar -- seq ) - [ accumulator [ while ] dip ] dip like ; inline + dup '[ _ accumulator-for [ while ] dip ] dip like ; inline : produce ( pred quot -- seq ) { } produce-as ; inline From ba5429e7720a40e7cd37080163e274ee69518b79 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 14:53:16 -0500 Subject: [PATCH 06/21] fix sequences bootstrap --- core/sequences/sequences.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index 6e7d8984b2..b46645d433 100755 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -505,7 +505,7 @@ PRIVATE> V{ } accumulator-for ; inline : produce-as ( pred quot exemplar -- seq ) - dup '[ _ accumulator-for [ while ] dip ] dip like ; inline + dup [ accumulator-for [ while ] dip ] curry dip like ; inline : produce ( pred quot -- seq ) { } produce-as ; inline From e4f108714a3d6b7dfb68e556773385e4c5a367e7 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 15:32:34 -0500 Subject: [PATCH 07/21] add nproduce and nproduce-as combinators to sequences.generalizations --- .../generalizations-docs.factor | 12 ++++++++- .../generalizations-tests.factor | 13 ++++++++++ .../generalizations/generalizations.factor | 26 ++++++++++++++++--- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/basis/sequences/generalizations/generalizations-docs.factor b/basis/sequences/generalizations/generalizations-docs.factor index d2e8c0c5fc..7940427e69 100644 --- a/basis/sequences/generalizations/generalizations-docs.factor +++ b/basis/sequences/generalizations/generalizations-docs.factor @@ -20,9 +20,17 @@ HELP: mnmap { $description "A generalization of " { $link map } ", " { $link 2map } ", and " { $link 3map } " that can map over any number of sequences in parallel and provide any number of output sequences." } ; HELP: mnmap-as -{ $values { "m*seq" { $snippet "m" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( m*element -- result*n )" } } { "n*exemplar" { $snippet "n" } " sequences on the datastack" } { "m" integer } { "n" integer } { "result*n" { $snippet "n" } " sequences of the same type as the " { $snippet "exemplar" } "s" } } +{ $values { "m*seq" { $snippet "m" } " sequences on the datastack" } { "quot" "a quotation with stack effect " { $snippet "( m*element -- result*n )" } } { "n*exemplar" { $snippet "n" } " sequences on the datastack" } { "m" integer } { "n" integer } { "result*n" { $snippet "n" } " sequences on the datastack of the same types as the " { $snippet "exemplar" } "s" } } { $description "A generalization of " { $link map-as } ", " { $link 2map-as } ", and " { $link 3map-as } " that can map over any number of sequences in parallel and provide any number of output sequences of distinct types." } ; +HELP: nproduce +{ $values { "pred" { $quotation "( -- ? )" } } { "quot" { $quotation "( -- obj1 obj2 ... objn )" } } { "n" integer } { "seq..." { $snippet "n" } " arrays on the datastack" } } +{ $description "A generalization of " { $link produce } " that generates " { $snippet "n" } " arrays in parallel by calling " { $snippet "quot" } " repeatedly until " { $snippet "pred" } " outputs false." } ; + +HELP: nproduce-as +{ $values { "pred" { $quotation "( -- ? )" } } { "quot" { $quotation "( -- obj1 obj2 ... objn )" } } { "...exemplar" { $snippet "n" } " sequences on the datastack" } { "n" integer } { "seq..." { $snippet "n" } " sequences on the datastack of the same types as the " { $snippet "exemplar" } "s" } } +{ $description "A generalization of " { $link produce-as } " that generates " { $snippet "n" } " sequences in parallel by calling " { $snippet "quot" } " repeatedly until " { $snippet "pred" } " outputs false." } ; + ARTICLE: "sequences.generalizations" "Generalized sequence iteration combinators" "The " { $vocab-link "sequences.generalizations" } " vocabulary defines generalized versions of the iteration " { $link "sequences-combinators" } "." { $subsections @@ -31,6 +39,8 @@ ARTICLE: "sequences.generalizations" "Generalized sequence iteration combinators nmap-as mnmap mnmap-as + nproduce + nproduce-as } ; ABOUT: "sequences.generalizations" diff --git a/basis/sequences/generalizations/generalizations-tests.factor b/basis/sequences/generalizations/generalizations-tests.factor index ac1990743e..d1861b8f9d 100644 --- a/basis/sequences/generalizations/generalizations-tests.factor +++ b/basis/sequences/generalizations/generalizations-tests.factor @@ -19,6 +19,14 @@ IN: sequences.generalizations.tests [ 4 nappend ] 4 1 mnmap ; : mnmap-0-test ( a b c d -- ) [ 4 nappend print ] 4 0 mnmap ; +: nproduce-as-test ( n -- a b ) + [ dup zero? not ] + [ [ 2 - ] [ ] [ 1 - ] tri ] { } B{ } 2 nproduce-as + [ drop ] 2dip ; +: nproduce-test ( n -- a b ) + [ dup zero? not ] + [ [ 2 - ] [ ] [ 1 - ] tri ] 2 nproduce + [ drop ] 2dip ; [ """A1a! B2b@ @@ -105,3 +113,8 @@ D4d$ [ mnmap-0-test ] with-string-writer ] unit-test +[ { 10 8 6 4 2 } B{ 9 7 5 3 1 } ] +[ 10 nproduce-as-test ] unit-test + +[ { 10 8 6 4 2 } { 9 7 5 3 1 } ] +[ 10 nproduce-test ] unit-test diff --git a/basis/sequences/generalizations/generalizations.factor b/basis/sequences/generalizations/generalizations.factor index 4365c1494d..210b27f3f3 100644 --- a/basis/sequences/generalizations/generalizations.factor +++ b/basis/sequences/generalizations/generalizations.factor @@ -1,3 +1,4 @@ +! (c)2009 Joe Groff bsd license USING: kernel sequences sequences.private math combinators macros math.order math.ranges quotations fry effects memoize.private generalizations ; @@ -32,7 +33,7 @@ MACRO: nnew-sequence ( n -- ) [ dup '[ [ new-sequence ] _ apply-curry _ cleave* ] ] if-zero ; : nnew-like ( len ...exemplar quot n -- result... ) - dup dup dup dup '[ + 5 dupn '[ _ nover [ [ _ nnew-sequence ] dip call ] _ ndip [ like ] @@ -41,14 +42,14 @@ MACRO: nnew-sequence ( n -- ) ] call ; inline MACRO: (ncollect) ( n -- ) - dup dup 1 + + 3 dupn 1 + '[ [ [ keep ] _ ndip _ nset-nth-unsafe ] _ ncurry ] ; : ncollect ( len quot ...into n -- ) (ncollect) each-integer ; inline : nmap-integers ( len quot ...exemplar n -- result... ) - dup dup dup + 4 dupn '[ [ over ] _ ndip [ [ _ ncollect ] _ nkeep ] _ nnew-like ] call ; inline : mnmap-as ( m*seq quot n*exemplar m n -- result*n ) @@ -57,3 +58,22 @@ MACRO: (ncollect) ( n -- ) : mnmap ( m*seq quot m n -- result*n ) 2dup '[ [ _ npick ] dip swap _ dupn ] 2dip mnmap-as ; inline +: naccumulator-for ( quot ...exemplar n -- quot' vec... ) + 5 dupn '[ + [ [ length ] keep new-resizable ] _ napply + [ [ [ push ] _ apply-curry _ spread* ] _ ncurry compose ] _ nkeep + ] call ; inline + +: naccumulator ( quot n -- quot' vec... ) + [ V{ } swap dupn ] keep naccumulator-for ; inline + +: nproduce-as ( pred quot ...exemplar n -- seq... ) + 7 dupn '[ + _ ndup + [ _ naccumulator-for [ while ] _ ndip ] + _ ncurry _ ndip + [ like ] _ apply-curry _ spread* + ] call ; inline + +: nproduce ( pred quot n -- seq... ) + [ { } swap dupn ] keep nproduce-as ; inline From 84f203afcc363f81822acb7f46d6df9a8b466eaf Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 16:26:25 -0500 Subject: [PATCH 08/21] math.matrices: vectorizable definition of cross --- basis/math/matrices/matrices.factor | 4 +++- basis/math/vectors/vectors.factor | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/basis/math/matrices/matrices.factor b/basis/math/matrices/matrices.factor index 4a76a20598..8f75cb9442 100644 --- a/basis/math/matrices/matrices.factor +++ b/basis/math/matrices/matrices.factor @@ -122,7 +122,9 @@ IN: math.matrices PRIVATE> -: cross ( vec1 vec2 -- vec3 ) [ [ i ] [ j ] [ k ] 2tri ] keep 3sequence ; +: cross ( vec1 vec2 -- vec3 ) + [ [ { 1 2 1 } vshuffle ] [ { 2 0 0 } vshuffle ] bi* v* ] + [ [ { 2 0 0 } vshuffle ] [ { 1 2 1 } vshuffle ] bi* v* ] 2bi v- ; inline : proj ( v u -- w ) [ [ v. ] [ norm-sq ] bi / ] keep n*v ; diff --git a/basis/math/vectors/vectors.factor b/basis/math/vectors/vectors.factor index 81af5c12d2..63564f064d 100644 --- a/basis/math/vectors/vectors.factor +++ b/basis/math/vectors/vectors.factor @@ -96,6 +96,7 @@ PRIVATE> :: vbroadcast ( u n -- v ) u length n u nth u like ; : vshuffle-elements ( u perm -- v ) + over length 0 pad-tail swap [ '[ _ nth ] ] keep map-as ; : vshuffle-bytes ( u perm -- v ) From 27100ae094a5b76c01a9495ae7fcdad535ffd90d Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 16:53:40 -0500 Subject: [PATCH 09/21] improve gpu.demos.bunny mesh generation performance --- extra/gpu/demos/bunny/bunny.factor | 47 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/extra/gpu/demos/bunny/bunny.factor b/extra/gpu/demos/bunny/bunny.factor index 2e292f0141..0d3226c394 100755 --- a/extra/gpu/demos/bunny/bunny.factor +++ b/extra/gpu/demos/bunny/bunny.factor @@ -3,13 +3,15 @@ USING: accessors alien.c-types arrays classes.struct combinators combinators.short-circuit game.worlds gpu gpu.buffers gpu.util.wasd gpu.framebuffers gpu.render gpu.shaders gpu.state gpu.textures gpu.util grouping http.client images images.loader -io io.encodings.ascii io.files io.files.temp kernel math -math.matrices math.parser math.vectors method-chains sequences -splitting threads ui ui.gadgets ui.gadgets.worlds -ui.pixel-formats specialized-arrays specialized-vectors ; +io io.encodings.ascii io.files io.files.temp kernel locals math +math.matrices math.vectors.simd math.parser math.vectors +method-chains sequences splitting threads ui ui.gadgets +ui.gadgets.worlds ui.pixel-formats specialized-arrays +specialized-vectors ; FROM: alien.c-types => float ; SPECIALIZED-ARRAY: float SPECIALIZED-VECTOR: uint +SIMD: float IN: gpu.demos.bunny GLSL-SHADER-FILE: bunny-vertex-shader vertex-shader "bunny.v.glsl" @@ -52,7 +54,10 @@ VERTEX-FORMAT: bunny-vertex { f float-components 1 f } { "normal" float-components 3 f } { f float-components 1 f } ; -VERTEX-STRUCT: bunny-vertex-struct bunny-vertex + +STRUCT: bunny-vertex-struct + { vertex float-4 } + { normal float-4 } ; SPECIALIZED-VECTOR: bunny-vertex-struct @@ -75,42 +80,40 @@ UNIFORM-TUPLE: loading-uniforms { "loading-texture" texture-uniform f } ; : numbers ( str -- seq ) - " " split [ string>number ] map sift ; + " " split [ empty? not ] filter [ string>number ] map ; inline : ( vertex -- struct ) bunny-vertex-struct - swap >float-array >>vertex ; inline + swap first3 0.0 float-4-boa >>vertex ; inline : (parse-bunny-model) ( vs is -- vs is ) - readln [ + [ numbers { { [ dup length 5 = ] [ 3 head pick push ] } { [ dup first 3 = ] [ rest over push-all ] } [ drop ] - } cond (parse-bunny-model) - ] when* ; + } cond + ] each-line ; inline : parse-bunny-model ( -- vertexes indexes ) 100000 100000 - (parse-bunny-model) ; + (parse-bunny-model) ; inline -: normal ( vertexes -- normal ) - [ [ second ] [ first ] bi v- ] - [ [ third ] [ first ] bi v- ] bi cross - vneg normalize ; inline +:: normal ( a b c -- normal ) + c a v- + b a v- cross normalize ; inline -: calc-bunny-normal ( vertexes indexes -- ) - swap - [ [ nth vertex>> ] curry { } map-as normal ] - [ [ nth [ v+ ] change-normal drop ] curry with each ] 2bi ; +:: calc-bunny-normal ( a b c vertexes -- ) + a b c [ vertexes nth vertex>> ] tri@ normal :> n + a b c [ vertexes nth [ n v+ ] change-normal drop ] tri@ ; inline : calc-bunny-normals ( vertexes indexes -- ) - 3 - [ calc-bunny-normal ] with each ; + 3 swap + [ [ first3 ] dip calc-bunny-normal ] curry each ; inline : normalize-bunny-normals ( vertexes -- ) - [ [ normalize ] change-normal drop ] each ; + [ [ normalize ] change-normal drop ] each ; inline : bunny-data ( filename -- vertexes indexes ) ascii [ parse-bunny-model ] with-file-reader From 1a7b4d7c63435ce1da031c5339de2fa6b4cfaf4f Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 17:26:22 -0500 Subject: [PATCH 10/21] inline the trivial words in math.parser --- core/math/parser/parser.factor | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/core/math/parser/parser.factor b/core/math/parser/parser.factor index a53604ddf9..eaa58ac177 100644 --- a/core/math/parser/parser.factor +++ b/core/math/parser/parser.factor @@ -111,10 +111,10 @@ SYMBOL: negative? { { 16 [ hex>float ] } [ drop dec>float ] - } case ; + } case ; inline : number-char? ( char -- ? ) - "0123456789ABCDEFabcdef." member? ; + "0123456789ABCDEFabcdef." member? ; inline : numeric-looking? ( str -- ? ) "-" ?head drop @@ -127,7 +127,7 @@ SYMBOL: negative? PRIVATE> : string>float ( str -- n/f ) - 10 base>float ; + 10 base>float ; inline : base> ( str radix -- n/f ) over numeric-looking? [ @@ -138,13 +138,13 @@ PRIVATE> } case ] [ 2drop f ] if ; -: string>number ( str -- n/f ) 10 base> ; -: bin> ( str -- n/f ) 2 base> ; -: oct> ( str -- n/f ) 8 base> ; -: hex> ( str -- n/f ) 16 base> ; +: string>number ( str -- n/f ) 10 base> ; inline +: bin> ( str -- n/f ) 2 base> ; inline +: oct> ( str -- n/f ) 8 base> ; inline +: hex> ( str -- n/f ) 16 base> ; inline : >digit ( n -- ch ) - dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] if ; + dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] if ; inline : positive>base ( num radix -- str ) dup 1 <= [ "Invalid radix" throw ] when @@ -234,12 +234,12 @@ M: ratio >base { { 16 [ float>hex ] } [ drop float>decimal ] - } case ; + } case ; inline PRIVATE> : float>string ( n -- str ) - 10 float>base ; + 10 float>base ; inline M: float >base { @@ -251,9 +251,9 @@ M: float >base [ float>base ] } cond ; -: number>string ( n -- str ) 10 >base ; -: >bin ( n -- str ) 2 >base ; -: >oct ( n -- str ) 8 >base ; -: >hex ( n -- str ) 16 >base ; +: number>string ( n -- str ) 10 >base ; inline +: >bin ( n -- str ) 2 >base ; inline +: >oct ( n -- str ) 8 >base ; inline +: >hex ( n -- str ) 16 >base ; inline -: # ( n -- ) number>string % ; +: # ( n -- ) number>string % ; inline From e31ed3eda4785af12b45eabcbfdd0de9cb79527d Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 17:28:01 -0500 Subject: [PATCH 11/21] add filter-as to sequences --- core/sequences/sequences-docs.factor | 5 +++++ core/sequences/sequences.factor | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/core/sequences/sequences-docs.factor b/core/sequences/sequences-docs.factor index 9fd48796d6..2156557fff 100755 --- a/core/sequences/sequences-docs.factor +++ b/core/sequences/sequences-docs.factor @@ -426,6 +426,10 @@ HELP: filter { $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-as +{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "exemplar" sequence } { "subseq" "a new sequence" } } +{ $description "Applies the quotation to each element in turn, and outputs a new sequence of the same type as " { $snippet "exemplar" } " 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" { $quotation "( elt -- ? )" } } } { $description "Applies the quotation to each element in turn, and removes elements for which the quotation outputs a false value." } @@ -1512,6 +1516,7 @@ ARTICLE: "sequences-combinators" "Sequence combinators" "Filtering:" { $subsections filter + filter-as partition } "Testing if a sequence contains elements satisfying a predicate:" diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index b46645d433..93709122c7 100755 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -483,11 +483,17 @@ PRIVATE> : push-if ( elt quot accum -- ) [ keep ] dip rot [ push ] [ 2drop ] if ; inline +: pusher-for ( quot exemplar -- quot accum ) + [ length ] keep new-resizable [ [ push-if ] 2curry ] keep ; inline + : pusher ( quot -- quot accum ) - V{ } clone [ [ push-if ] 2curry ] keep ; inline + V{ } pusher-for ; inline + +: filter-as ( seq quot exemplar -- subseq ) + dup [ pusher-for [ each ] dip ] curry dip like ; inline : filter ( seq quot -- subseq ) - over [ pusher [ each ] dip ] dip like ; inline + over filter-as ; inline : push-either ( elt quot accum1 accum2 -- ) [ keep swap ] 2dip ? push ; inline From cdd0e5774e0ccb4f7cf50f70ea3d7092e85df581 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 18:55:00 -0500 Subject: [PATCH 12/21] make new-resizable on growable sequences return a growable of the same type --- basis/vectors/functor/functor.factor | 2 ++ core/byte-vectors/byte-vectors.factor | 2 ++ core/growable/growable.factor | 2 ++ core/sbufs/sbufs.factor | 4 ++-- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/basis/vectors/functor/functor.factor b/basis/vectors/functor/functor.factor index b70c7c5050..a2a67d58bc 100644 --- a/basis/vectors/functor/functor.factor +++ b/basis/vectors/functor/functor.factor @@ -24,6 +24,8 @@ M: V new-sequence drop [ ] [ >fixnum ] bi V boa ; inline M: A new-resizable drop ; inline +M: V new-resizable drop ; inline + M: V equal? over V instance? [ sequence= ] [ 2drop f ] if ; : >V ( seq -- vector ) V new clone-like ; inline diff --git a/core/byte-vectors/byte-vectors.factor b/core/byte-vectors/byte-vectors.factor index 287e972405..4f6ade8580 100644 --- a/core/byte-vectors/byte-vectors.factor +++ b/core/byte-vectors/byte-vectors.factor @@ -43,4 +43,6 @@ M: byte-array like M: byte-array new-resizable drop ; inline +M: byte-vector new-resizable drop ; inline + INSTANCE: byte-vector growable diff --git a/core/growable/growable.factor b/core/growable/growable.factor index 68a8de3d43..2ca11e2e24 100644 --- a/core/growable/growable.factor +++ b/core/growable/growable.factor @@ -66,4 +66,6 @@ M: growable shorten ( n seq -- ) 2dup (>>length) ] when 2drop ; inline +M: growable new-resizable new-sequence 0 over set-length ; inline + INSTANCE: growable sequence diff --git a/core/sbufs/sbufs.factor b/core/sbufs/sbufs.factor index 49b6ec1374..db2649142d 100644 --- a/core/sbufs/sbufs.factor +++ b/core/sbufs/sbufs.factor @@ -23,13 +23,13 @@ M: sbuf like dup string? [ dup length sbuf boa ] [ >sbuf ] if ] unless ; inline -M: sbuf new-resizable drop ; inline - M: sbuf equal? over sbuf? [ sequence= ] [ 2drop f ] if ; M: string new-resizable drop ; inline +M: sbuf new-resizable drop ; inline + M: string like #! If we have a string, we're done. #! If we have an sbuf, and it's at full capacity, we're done. From 943bde59f9f30c7205efd704485ed5670cfbd5f7 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 18:55:32 -0500 Subject: [PATCH 13/21] speed up dec>float a little --- core/math/parser/parser.factor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/math/parser/parser.factor b/core/math/parser/parser.factor index eaa58ac177..32bacf5f49 100644 --- a/core/math/parser/parser.factor +++ b/core/math/parser/parser.factor @@ -83,8 +83,8 @@ SYMBOL: negative? ] if ; inline : dec>float ( str -- n/f ) - [ CHAR: , eq? not ] filter - >byte-array 0 suffix (string>float) ; + [ CHAR: , eq? not ] BV{ } filter-as + 0 over push B{ } like (string>float) ; : hex>float-parts ( str -- neg? mantissa-str expt ) "-" ?head swap "p" split1 [ 10 base> ] [ 0 ] if* ; From 34027e46b60e71f56b15a9acea55d46031622b8a Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 20:26:43 -0500 Subject: [PATCH 14/21] remove a redundant head from parse-bunny-model --- extra/gpu/demos/bunny/bunny.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/gpu/demos/bunny/bunny.factor b/extra/gpu/demos/bunny/bunny.factor index 0d3226c394..bea137c8a3 100755 --- a/extra/gpu/demos/bunny/bunny.factor +++ b/extra/gpu/demos/bunny/bunny.factor @@ -89,7 +89,7 @@ UNIFORM-TUPLE: loading-uniforms : (parse-bunny-model) ( vs is -- vs is ) [ numbers { - { [ dup length 5 = ] [ 3 head pick push ] } + { [ dup length 5 = ] [ pick push ] } { [ dup first 3 = ] [ rest over push-all ] } [ drop ] } cond From 28f5347e71a3b6754b4f60fbc9615df417ec7250 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 22 Oct 2009 20:28:00 -0500 Subject: [PATCH 15/21] tighten some screws in math.parser --- core/math/parser/parser.factor | 59 ++++++++++++++-------------------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/core/math/parser/parser.factor b/core/math/parser/parser.factor index 32bacf5f49..60fb5559c5 100644 --- a/core/math/parser/parser.factor +++ b/core/math/parser/parser.factor @@ -5,39 +5,18 @@ strings arrays combinators splitting math assocs byte-arrays make ; IN: math.parser : digit> ( ch -- n ) - H{ - { CHAR: 0 0 } - { CHAR: 1 1 } - { CHAR: 2 2 } - { CHAR: 3 3 } - { CHAR: 4 4 } - { CHAR: 5 5 } - { CHAR: 6 6 } - { CHAR: 7 7 } - { CHAR: 8 8 } - { CHAR: 9 9 } - { CHAR: A 10 } - { CHAR: B 11 } - { CHAR: C 12 } - { CHAR: D 13 } - { CHAR: E 14 } - { CHAR: F 15 } - { CHAR: a 10 } - { CHAR: b 11 } - { CHAR: c 12 } - { CHAR: d 13 } - { CHAR: e 14 } - { CHAR: f 15 } - { CHAR: , f } - } at* [ drop 255 ] unless ; inline + 127 bitand { + { [ dup CHAR: 9 <= ] [ CHAR: 0 - ] } + { [ dup CHAR: a < ] [ CHAR: A 10 - - ] } + [ CHAR: a 10 - - ] + } cond + dup 0 < [ drop 255 ] [ dup 16 >= [ drop 255 ] when ] if ; inline : string>digits ( str -- digits ) [ digit> ] B{ } map-as ; inline : (digits>integer) ( valid? accum digit radix -- valid? accum ) - over [ - 2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if - ] [ 2drop ] if ; inline + 2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if ; inline : each-digit ( seq radix quot -- n/f ) [ t 0 ] 3dip curry each swap [ drop f ] unless ; inline @@ -54,8 +33,8 @@ SYMBOL: negative? : string>natural ( seq radix -- n/f ) over empty? [ 2drop f ] [ - [ [ digit> ] dip (digits>integer) ] each-digit - ] if ; inline + [ over CHAR: , eq? [ 2drop ] [ [ digit> ] dip (digits>integer) ] if ] each-digit + ] if ; : sign ( -- str ) negative? get "-" "+" ? ; @@ -116,13 +95,23 @@ SYMBOL: negative? : number-char? ( char -- ? ) "0123456789ABCDEFabcdef." member? ; inline +: last-unsafe ( seq -- elt ) + [ length 1 - ] [ nth-unsafe ] bi ; inline + : numeric-looking? ( str -- ? ) - "-" ?head drop dup empty? [ drop f ] [ - dup first number-char? [ - last number-char? - ] [ drop f ] if - ] if ; + dup first-unsafe number-char? [ + last-unsafe number-char? + ] [ + dup first-unsafe CHAR: - eq? [ + dup length 1 eq? [ drop f ] [ + 1 over nth-unsafe number-char? [ + last-unsafe number-char? + ] [ drop f ] if + ] if + ] [ drop f ] if + ] if + ] if ; inline PRIVATE> From d5d89f03a79c18068ae4009e464ca597acd28158 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 23 Oct 2009 00:07:19 -0500 Subject: [PATCH 16/21] swap around io combinators to avoid a bunch of redundant "input-stream get"s in each-line, each-block, contents, etc. --- core/io/io.factor | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/core/io/io.factor b/core/io/io.factor index e240467c07..ca36bc3b36 100644 --- a/core/io/io.factor +++ b/core/io/io.factor @@ -87,42 +87,51 @@ SYMBOL: error-stream : bl ( -- ) " " write ; - -: each-line ( quot -- ) - [ readln ] each-morsel ; inline +: each-stream-line ( stream quot -- ) + swap [ stream-readln ] curry each-morsel ; inline -: lines ( -- seq ) - [ ] accumulator [ each-line ] dip { } like ; +: each-line ( quot -- ) + input-stream get swap each-stream-line ; inline : stream-lines ( stream -- seq ) - [ lines ] with-input-stream ; + [ [ ] accumulator [ each-stream-line ] dip { } like ] with-disposal ; -: contents ( -- seq ) - [ 65536 read-partial dup ] [ ] produce nip - element-exemplar concat-as ; +: lines ( -- seq ) + input-stream get stream-lines ; inline : stream-contents ( stream -- seq ) - [ contents ] with-input-stream ; + [ + [ [ 65536 swap stream-read-partial dup ] curry [ ] produce nip ] + [ stream-element-exemplar concat-as ] bi + ] with-disposal ; + +: contents ( -- seq ) + input-stream get stream-contents ; inline + +: each-stream-block ( stream quot: ( block -- ) -- ) + swap [ 8192 swap stream-read-partial ] curry each-morsel ; inline : each-block ( quot: ( block -- ) -- ) - [ 8192 read-partial ] each-morsel ; inline + input-stream get swap each-stream-block ; inline : stream-copy ( in out -- ) [ [ [ write ] each-block ] with-output-stream ] From 15f4196d438ef4730d33369a3619918b3ef4b60f Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 23 Oct 2009 00:08:14 -0500 Subject: [PATCH 17/21] gpu.demos.bunny: tokenize model file as it's read to avoid an extra splitting-and-filtering pass --- extra/gpu/demos/bunny/bunny.factor | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/extra/gpu/demos/bunny/bunny.factor b/extra/gpu/demos/bunny/bunny.factor index bea137c8a3..a741af8002 100755 --- a/extra/gpu/demos/bunny/bunny.factor +++ b/extra/gpu/demos/bunny/bunny.factor @@ -5,7 +5,7 @@ gpu.util.wasd gpu.framebuffers gpu.render gpu.shaders gpu.state gpu.textures gpu.util grouping http.client images images.loader io io.encodings.ascii io.files io.files.temp kernel locals math math.matrices math.vectors.simd math.parser math.vectors -method-chains sequences splitting threads ui ui.gadgets +method-chains namespaces sequences splitting threads ui ui.gadgets ui.gadgets.worlds ui.pixel-formats specialized-arrays specialized-vectors ; FROM: alien.c-types => float ; @@ -79,13 +79,30 @@ UNIFORM-TUPLE: loading-uniforms { "texcoord-scale" vec2-uniform f } { "loading-texture" texture-uniform f } ; -: numbers ( str -- seq ) - " " split [ empty? not ] filter [ string>number ] map ; inline +: numbers ( tokens -- seq ) + [ string>number ] map ; inline : ( vertex -- struct ) bunny-vertex-struct swap first3 0.0 float-4-boa >>vertex ; inline +: (read-line-tokens) ( seq stream -- seq ) + " \n" over stream-read-until + [ [ pick push ] unless-empty ] + [ + { + { CHAR: \s [ (read-line-tokens) ] } + { CHAR: \n [ drop ] } + [ 2drop [ f ] when-empty ] + } case + ] bi* ; inline recursive + +: stream-read-line-tokens ( stream -- seq ) + V{ } clone swap (read-line-tokens) ; + +: each-line-tokens ( quot -- ) + input-stream get [ stream-read-line-tokens ] curry each-morsel ; inline + : (parse-bunny-model) ( vs is -- vs is ) [ numbers { @@ -93,7 +110,7 @@ UNIFORM-TUPLE: loading-uniforms { [ dup first 3 = ] [ rest over push-all ] } [ drop ] } cond - ] each-line ; inline + ] each-line-tokens ; inline : parse-bunny-model ( -- vertexes indexes ) 100000 From a36e7ff40a1cbbc343071051a4698f2735a303c4 Mon Sep 17 00:00:00 2001 From: Sascha Matzke Date: Sun, 27 Sep 2009 17:31:02 +0200 Subject: [PATCH 18/21] added with-local-address to bind the local address of a socket to a specific IP or IP/port combination (sometimes required to get through firewalls) --- basis/io/sockets/sockets.factor | 14 ++++++++++++++ basis/io/sockets/unix/unix.factor | 6 +++++- basis/io/sockets/windows/windows.factor | 6 +++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/basis/io/sockets/sockets.factor b/basis/io/sockets/sockets.factor index a542575446..e45224fcc2 100755 --- a/basis/io/sockets/sockets.factor +++ b/basis/io/sockets/sockets.factor @@ -173,6 +173,8 @@ GENERIC: (get-remote-address) ( handle remote -- sockaddr ) [ |dispose ] [ |dispose ] bi ] with-destructors ; +SYMBOL: bind-local-address + GENERIC: establish-connection ( client-out remote -- ) GENERIC: ((client)) ( remote -- handle ) @@ -321,6 +323,18 @@ M: invalid-inet-server summary M: inet (server) invalid-inet-server ; +ERROR: invalid-local-address addrspec ; + +M: invalid-local-address summary + drop "Cannot use with-local-address with ; use or instead" ; + +: with-local-address ( addr quot -- ) + [ + [ ] [ inet4? ] [ inet6? ] tri or + [ bind-local-address ] + [ invalid-local-address ] if + ] dip with-variable ; inline + { { [ os unix? ] [ "io.sockets.unix" require ] } { [ os winnt? ] [ "io.sockets.windows.nt" require ] } diff --git a/basis/io/sockets/unix/unix.factor b/basis/io/sockets/unix/unix.factor index fa46a71ca0..3564b32890 100755 --- a/basis/io/sockets/unix/unix.factor +++ b/basis/io/sockets/unix/unix.factor @@ -69,8 +69,12 @@ M: object establish-connection ( client-out remote -- ) [ (io-error) ] } cond ; +: ?bind-client ( socket -- ) + bind-local-address get [ [ fd>> ] dip make-sockaddr/size bind io-error ] [ drop ] if* ; inline + M: object ((client)) ( addrspec -- fd ) - protocol-family SOCK_STREAM socket-fd dup init-client-socket ; + protocol-family SOCK_STREAM socket-fd + [ init-client-socket ] [ ?bind-client ] [ ] tri ; ! Server sockets - TCP and Unix domain : init-server-socket ( fd -- ) diff --git a/basis/io/sockets/windows/windows.factor b/basis/io/sockets/windows/windows.factor index ccf86ca308..fa5e3833bc 100755 --- a/basis/io/sockets/windows/windows.factor +++ b/basis/io/sockets/windows/windows.factor @@ -55,7 +55,11 @@ M: object (get-remote-address) ( socket addrspec -- sockaddr ) M: object ((client)) ( addrspec -- handle ) [ SOCK_STREAM open-socket ] keep - [ unspecific-sockaddr/size bind-socket ] [ drop ] 2bi ; + [ + bind-local-address get + [ nip make-sockaddr/size ] + [ unspecific-sockaddr/size ] if* bind-socket + ] [ drop ] 2bi ; : server-socket ( addrspec type -- fd ) [ open-socket ] [ drop ] 2bi From a5d4f9cf16d62c285855979662724d1e7744c07e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 23 Oct 2009 02:58:15 -0500 Subject: [PATCH 19/21] grouping: clump on empty sequence was trying to make a sequence of length -1 --- basis/grouping/grouping-tests.factor | 11 ++++++++++- basis/grouping/grouping.factor | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/basis/grouping/grouping-tests.factor b/basis/grouping/grouping-tests.factor index c91e5a56d6..52b436507e 100644 --- a/basis/grouping/grouping-tests.factor +++ b/basis/grouping/grouping-tests.factor @@ -1,5 +1,5 @@ USING: grouping tools.test kernel sequences arrays -math ; +math accessors ; IN: grouping.tests [ { 1 2 3 } 0 group ] must-fail @@ -12,6 +12,15 @@ IN: grouping.tests >array ] unit-test +[ 0 ] [ { } 2 length ] unit-test +[ 0 ] [ { 1 } 2 length ] unit-test +[ 1 ] [ { 1 2 } 2 length ] unit-test +[ 2 ] [ { 1 2 3 } 2 length ] unit-test + +[ 1 ] [ V{ } 2 0 over set-length seq>> length ] unit-test +[ 2 ] [ V{ } 2 1 over set-length seq>> length ] unit-test +[ 3 ] [ V{ } 2 2 over set-length seq>> length ] unit-test + [ { { 1 2 } { 2 3 } } ] [ { 1 2 3 } 2 [ >array ] map ] unit-test [ f ] [ [ { } { } "Hello" ] all-equal? ] unit-test diff --git a/basis/grouping/grouping.factor b/basis/grouping/grouping.factor index 83579d2beb..8a39a5d5cf 100644 --- a/basis/grouping/grouping.factor +++ b/basis/grouping/grouping.factor @@ -46,7 +46,7 @@ M: abstract-groups group@ TUPLE: abstract-clumps < chunking-seq ; M: abstract-clumps length - [ seq>> length ] [ n>> ] bi - 1 + ; inline + [ seq>> length 1 + ] [ n>> ] bi [-] ; inline M: abstract-clumps set-length [ n>> + 1 - ] [ seq>> ] bi set-length ; inline From e8fd85437b45888e3f54b165540b537b7c741dcc Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 23 Oct 2009 03:27:25 -0500 Subject: [PATCH 20/21] compiler: fix stack effect inference bug discovered by x6j8x; it was possible to define a word which did not compile but could be called anyway --- basis/compiler/compiler.factor | 24 +++++++++--------------- basis/compiler/tests/simple.factor | 13 ++++++++++++- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/basis/compiler/compiler.factor b/basis/compiler/compiler.factor index 626ab678c0..e58cf0c834 100755 --- a/basis/compiler/compiler.factor +++ b/basis/compiler/compiler.factor @@ -55,28 +55,22 @@ SYMBOL: compiled GENERIC: no-compile? ( word -- ? ) -M: word no-compile? "no-compile" word-prop ; - M: method-body no-compile? "method-generic" word-prop no-compile? ; M: predicate-engine-word no-compile? "owner-generic" word-prop no-compile? ; +M: word no-compile? + { + [ macro? ] + [ inline? ] + [ "special" word-prop ] + [ "no-compile" word-prop ] + } 1|| ; + : ignore-error? ( word error -- ? ) #! Ignore some errors on inline combinators, macros, and special #! words such as 'call'. - [ - { - [ macro? ] - [ inline? ] - [ no-compile? ] - [ "special" word-prop ] - } 1|| - ] [ - { - [ do-not-compile? ] - [ literal-expected? ] - } 1|| - ] bi* and ; + [ no-compile? ] [ { [ do-not-compile? ] [ literal-expected? ] } 1|| ] bi* and ; : finish ( word -- ) #! Recompile callers if the word's stack effect changed, then diff --git a/basis/compiler/tests/simple.factor b/basis/compiler/tests/simple.factor index da021412fe..a86d5b8c52 100644 --- a/basis/compiler/tests/simple.factor +++ b/basis/compiler/tests/simple.factor @@ -1,6 +1,7 @@ USING: compiler compiler.units tools.test kernel kernel.private sequences.private math.private math combinators strings alien -arrays memory vocabs parser eval ; +arrays memory vocabs parser eval quotations compiler.errors +definitions ; IN: compiler.tests.simple ! Test empty word @@ -238,3 +239,13 @@ M: f single-combination-test-2 single-combination-test-4 ; "USING: prettyprint words accessors ; IN: compiler.tests.foo : (recursive) ( -- ) (recursive) (recursive) ; inline recursive : recursive ( -- ) (recursive) ; \\ (recursive) optimized?" eval( -- obj ) ] unit-test ] times + +! This should not compile +GENERIC: bad-effect-test ( a -- ) +M: quotation bad-effect-test call ; inline +: bad-effect-test* ( -- ) [ 1 2 3 ] bad-effect-test ; + +[ bad-effect-test* ] [ not-compiled? ] must-fail-with + +! Don't want compiler error to stick around +[ ] [ [ M\ quotation bad-effect-test forget ] with-compilation-unit ] unit-test From 9d4df482c8f929db14d5958318ff407767a5c1cf Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 23 Oct 2009 03:27:45 -0500 Subject: [PATCH 21/21] help: don't consider children of $markup-examples for cross-referencing --- basis/help/crossref/crossref-tests.factor | 11 ++++++++++- basis/help/markup/markup.factor | 4 ++-- basis/help/vocabs/vocabs-tests.factor | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/basis/help/crossref/crossref-tests.factor b/basis/help/crossref/crossref-tests.factor index 4022d3bd38..6fb4c562cf 100644 --- a/basis/help/crossref/crossref-tests.factor +++ b/basis/help/crossref/crossref-tests.factor @@ -1,6 +1,7 @@ USING: help.crossref help.topics help.markup tools.test words definitions assocs sequences kernel namespaces parser arrays -io.streams.string continuations debugger compiler.units eval ; +io.streams.string continuations debugger compiler.units eval +help.syntax ; IN: help.crossref.tests [ ] [ @@ -54,3 +55,11 @@ IN: help.crossref.tests ] unit-test [ "xxx" ] [ "yyy" article-parent ] unit-test + +ARTICLE: "crossref-test-1" "Crossref test 1" +"Hello world" ; + +ARTICLE: "crossref-test-2" "Crossref test 2" +{ $markup-example { $subsection "crossref-test-1" } } ; + +[ V{ } ] [ "crossref-test-2" >link article-children ] unit-test diff --git a/basis/help/markup/markup.factor b/basis/help/markup/markup.factor index ea64df3edc..229a025442 100644 --- a/basis/help/markup/markup.factor +++ b/basis/help/markup/markup.factor @@ -430,8 +430,8 @@ M: simple-element elements* M: object elements* 2drop ; M: array elements* - [ [ elements* ] with each ] 2keep - [ first eq? ] keep swap [ , ] [ drop ] if ; + [ dup first \ $markup-example eq? [ 2drop ] [ [ elements* ] with each ] if ] + [ [ first eq? ] keep swap [ , ] [ drop ] if ] 2bi ; : elements ( elt-type element -- seq ) [ elements* ] { } make ; diff --git a/basis/help/vocabs/vocabs-tests.factor b/basis/help/vocabs/vocabs-tests.factor index 5637dd92f4..aca1ae43c9 100644 --- a/basis/help/vocabs/vocabs-tests.factor +++ b/basis/help/vocabs/vocabs-tests.factor @@ -1,5 +1,6 @@ -USING: help.vocabs tools.test help.markup help vocabs ; +USING: help.vocabs tools.test help.markup help vocabs io ; IN: help.vocabs.tests [ ] [ { $vocab "scratchpad" } print-content ] unit-test [ ] [ "classes" vocab print-topic ] unit-test +[ ] [ nl ] unit-test