diff --git a/core/assocs/assocs-docs.factor b/core/assocs/assocs-docs.factor index 68be9c9b06..d660436783 100755 --- a/core/assocs/assocs-docs.factor +++ b/core/assocs/assocs-docs.factor @@ -139,7 +139,7 @@ HELP: new-assoc 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" } } -{ $contract "Applies a predicate quotation to each entry in the assoc. Returns the key or 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." } +{ $contract "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." } { $notes "The " { $link assoc } " mixin has a default implementation for this generic word which first converts the assoc to an association list, then iterates over that with the " { $link find } " combinator for sequences." } ; HELP: clear-assoc diff --git a/core/io/files/files.factor b/core/io/files/files.factor index 87e927304b..ff265e43b1 100755 --- a/core/io/files/files.factor +++ b/core/io/files/files.factor @@ -147,6 +147,9 @@ PRIVATE> ] if ] unless ; +: file-extension ( filename -- extension ) + "." last-split1 nip ; + ! File info TUPLE: file-info type size permissions modified ; diff --git a/core/kernel/kernel-docs.factor b/core/kernel/kernel-docs.factor index c39010f228..82f0db1364 100755 --- a/core/kernel/kernel-docs.factor +++ b/core/kernel/kernel-docs.factor @@ -219,6 +219,16 @@ $nl { $example "t \\ t eq? ." "t" } "Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "." ; +ARTICLE: "conditionals-boolean-equivalence" "Expressing conditionals with boolean logic" +"Certain simple conditional forms can be expressed in a simpler manner using boolean logic." +$nl +"The following two lines are equivalent:" +{ $code "[ drop f ] unless" "swap and" } +"The following two lines are equivalent:" +{ $code "[ ] [ ] ?if" "swap or" } +"The following two lines are equivalent, where " { $snippet "L" } " is a literal:" +{ $code "[ L ] unless*" "L or" } ; + ARTICLE: "conditionals" "Conditionals and logic" "The basic conditionals:" { $subsection if } @@ -238,6 +248,7 @@ ARTICLE: "conditionals" "Conditionals and logic" { $subsection and } { $subsection or } { $subsection xor } +{ $subsection "conditionals-boolean-equivalence" } "See " { $link "combinators" } " for forms which abstract away common patterns involving multiple nested branches." { $see-also "booleans" "bitwise-arithmetic" both? either? } ; @@ -720,9 +731,7 @@ HELP: unless* { $description "Variant of " { $link if* } " with no true quotation." } { $notes "The following two lines are equivalent:" -{ $code "X [ Y ] unless*" "X dup [ ] [ drop Y ] if" } -"The following two lines are equivalent, where " { $snippet "L" } " is a literal:" -{ $code "[ L ] unless*" "L or" } } ; +{ $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 -- )" } } } diff --git a/core/syntax/syntax-docs.factor b/core/syntax/syntax-docs.factor index 0dc834ad6b..314d9697e7 100755 --- a/core/syntax/syntax-docs.factor +++ b/core/syntax/syntax-docs.factor @@ -346,7 +346,7 @@ HELP: \ { $syntax "\\ word" } { $values { "word" "a word" } } { $description "Reads the next word from the input and appends a wrapper holding the word to the parse tree. When the evaluator encounters a wrapper, it pushes the wrapped word literally on the data stack." } -{ $examples "The following two lines are equivalent:" { $code "0 \\ execute\n0 " } } ; +{ $examples "The following two lines are equivalent:" { $code "0 \\ execute\n0 " } "If " { $snippet "foo" } " is a symbol, the following two lines are equivalent:" { $code "foo" "\\ foo" } } ; HELP: DEFER: { $syntax "DEFER: word" } @@ -526,6 +526,9 @@ HELP: PREDICATE: "it satisfies the predicate" } "Each predicate must be defined as a subclass of some other class. This ensures that predicates inheriting from disjoint classes do not need to be exhaustively tested during method dispatch." +} +{ $examples + { $code "USING: math ;" "PREDICATE: positive < integer 0 > ;" } } ; HELP: TUPLE: diff --git a/extra/cairo/gadgets/gadgets.factor b/extra/cairo/gadgets/gadgets.factor index f5f4d3e965..c9fef618f8 100644 --- a/extra/cairo/gadgets/gadgets.factor +++ b/extra/cairo/gadgets/gadgets.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: sequences math opengl.gadgets kernel byte-arrays cairo.ffi cairo io.backend -opengl.gl arrays ; +ui.gadgets accessors opengl.gl +arrays ; IN: cairo.gadgets @@ -12,11 +13,23 @@ IN: cairo.gadgets >r first2 over width>stride [ * nip dup CAIRO_FORMAT_ARGB32 ] [ cairo_image_surface_create_for_data ] 3bi - r> with-cairo-from-surface ; + r> with-cairo-from-surface ; inline -: ( dim quot -- ) - over 2^-bounds swap copy-cairo - GL_BGRA rot ; +TUPLE: cairo-gadget < texture-gadget dim quot ; + +: ( dim quot -- gadget ) + cairo-gadget construct-gadget + swap >>quot + swap >>dim ; + +M: cairo-gadget cache-key* [ dim>> ] [ quot>> ] bi 2array ; + +: render-cairo ( dim quot -- bytes format ) + >r 2^-bounds r> copy-cairo GL_BGRA ; inline + +! M: cairo-gadget render* +! [ dim>> dup ] [ quot>> ] bi +! render-cairo render-bytes* ; ! maybe also texture>png ! : cairo>png ( gadget path -- ) @@ -29,11 +42,16 @@ IN: cairo.gadgets cr swap 0 0 cairo_set_source_surface cr cairo_paint ; -: ( path -- gadget ) - normalize-path cairo_image_surface_create_from_png +TUPLE: png-gadget < texture-gadget path ; +: ( path -- gadget ) + png-gadget construct-gadget + swap >>path ; + +M: png-gadget render* + path>> normalize-path cairo_image_surface_create_from_png [ cairo_image_surface_get_width ] [ cairo_image_surface_get_height 2array dup 2^-bounds ] [ [ copy-surface ] curry copy-cairo ] tri - GL_BGRA rot ; - + GL_BGRA render-bytes* ; +M: png-gadget cache-key* path>> ; diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor index bac141d6d2..0fe2f3577e 100755 --- a/extra/db/tuples/tuples.factor +++ b/extra/db/tuples/tuples.factor @@ -149,6 +149,9 @@ M: retryable execute-statement* ( statement type -- ) : select-tuples ( tuple -- tuples ) dup dup class do-select ; +: count-tuples ( tuple -- n ) + select-tuples length ; + : select-tuple ( tuple -- tuple/f ) dup dup class f f f 1 do-select ?first ; diff --git a/extra/freetype/freetype.factor b/extra/freetype/freetype.factor index f34bdc9920..8572a8bd91 100755 --- a/extra/freetype/freetype.factor +++ b/extra/freetype/freetype.factor @@ -155,6 +155,16 @@ C-STRUCT: face { "face-size*" "size" } { "void*" "charmap" } ; +C-STRUCT: FT_Bitmap + { "int" "rows" } + { "int" "width" } + { "int" "pitch" } + { "void*" "buffer" } + { "short" "num_grays" } + { "char" "pixel_mode" } + { "char" "palette_mode" } + { "void*" "palette" } ; + FUNCTION: FT_Error FT_New_Face ( void* library, FT_Char* font, FT_Long index, face* face ) ; FUNCTION: FT_Error FT_New_Memory_Face ( void* library, FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face* aface ) ; @@ -170,6 +180,15 @@ C-ENUM: FT_RENDER_MODE_LCD FT_RENDER_MODE_LCD_V ; +C-ENUM: + FT_PIXEL_MODE_NONE + FT_PIXEL_MODE_MONO + FT_PIXEL_MODE_GRAY + FT_PIXEL_MODE_GRAY2 + FT_PIXEL_MODE_GRAY4 + FT_PIXEL_MODE_LCD + FT_PIXEL_MODE_LCD_V ; + FUNCTION: int FT_Render_Glyph ( glyph* slot, int render_mode ) ; FUNCTION: void FT_Done_Face ( face* face ) ; @@ -177,3 +196,4 @@ FUNCTION: void FT_Done_Face ( face* face ) ; FUNCTION: void FT_Done_FreeType ( void* library ) ; FUNCTION: FT_Long FT_MulFix ( FT_Long a, FT_Long b ) ; + diff --git a/extra/http/server/actions/actions-tests.factor b/extra/furnace/actions/actions-tests.factor similarity index 55% rename from extra/http/server/actions/actions-tests.factor rename to extra/furnace/actions/actions-tests.factor index 480cbc8e96..60a526fb24 100755 --- a/extra/http/server/actions/actions-tests.factor +++ b/extra/furnace/actions/actions-tests.factor @@ -1,7 +1,7 @@ -USING: kernel http.server.actions validators +USING: kernel furnace.actions validators tools.test math math.parser multiline namespaces http io.streams.string http.server sequences splitting accessors ; -IN: http.server.actions.tests +IN: furnace.actions.tests [ "a" param "b" param [ string>number ] bi@ + ] >>display @@ -16,9 +16,26 @@ blah ; [ 25 ] [ - init-request action-request-test-1 lf>crlf [ read-request ] with-string-reader - request set + init-request { } "action-1" get call-responder ] unit-test + + + "a" >>rest + [ "a" param string>number sq ] >>display +"action-2" set + +STRING: action-request-test-2 +GET http://foo/bar/123 HTTP/1.1 + +blah +; + +[ 25 ] [ + action-request-test-2 lf>crlf + [ read-request ] with-string-reader + init-request + { "5" } "action-2" get call-responder +] unit-test diff --git a/extra/furnace/actions/actions.factor b/extra/furnace/actions/actions.factor new file mode 100755 index 0000000000..1cef8e24e5 --- /dev/null +++ b/extra/furnace/actions/actions.factor @@ -0,0 +1,123 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors sequences kernel assocs combinators +validators http hashtables namespaces fry continuations locals +io arrays math boxes splitting urls +xml.entities +http.server +http.server.responses +furnace +furnace.flash +html.elements +html.components +html.components +html.templates.chloe +html.templates.chloe.syntax ; +IN: furnace.actions + +SYMBOL: params + +SYMBOL: rest + +: render-validation-messages ( -- ) + validation-messages get + dup empty? [ drop ] [ +
    + [
  • message>> escape-string write
  • ] each +
+ ] if ; + +CHLOE: validation-messages drop render-validation-messages ; + +TUPLE: action rest init display validate submit ; + +: new-action ( class -- action ) + new + [ ] >>init + [ <400> ] >>display + [ ] >>validate + [ <400> ] >>submit ; + +: ( -- action ) + action new-action ; + +: flashed-variables ( -- seq ) + { validation-messages named-validation-messages } ; + +: handle-get ( action -- response ) + '[ + , + [ init>> call ] + [ drop flashed-variables restore-flash ] + [ display>> call ] + tri + ] with-exit-continuation ; + +: validation-failed ( -- * ) + request get method>> "POST" = [ f ] [ <400> ] if exit-with ; + +: (handle-post) ( action -- response ) + [ validate>> call ] [ submit>> call ] bi ; + +: param ( name -- value ) + params get at ; + +: revalidate-url-key "__u" ; + +: check-url ( url -- ? ) + request get url>> + [ [ protocol>> ] [ host>> ] [ port>> ] tri 3array ] bi@ = ; + +: revalidate-url ( -- url/f ) + revalidate-url-key param dup [ >url dup check-url swap and ] when ; + +: handle-post ( action -- response ) + '[ + form-nesting-key params get at " " split + [ , (handle-post) ] + [ swap '[ , , nest-values ] ] reduce + call + ] with-exit-continuation + [ + revalidate-url + [ flashed-variables ] [ <403> ] if* + ] unless* ; + +: handle-rest ( path action -- assoc ) + rest>> dup [ [ "/" join ] dip associate ] [ 2drop f ] if ; + +: init-action ( path action -- ) + blank-values + init-validation + handle-rest + request get request-params assoc-union params set ; + +M: action call-responder* ( path action -- response ) + [ init-action ] keep + request get method>> { + { "GET" [ handle-get ] } + { "HEAD" [ handle-get ] } + { "POST" [ handle-post ] } + } case ; + +M: action modify-form + drop request get url>> revalidate-url-key hidden-form-field ; + +: check-validation ( -- ) + validation-failed? [ validation-failed ] when ; + +: validate-params ( validators -- ) + params get swap validate-values from-object + check-validation ; + +: validate-integer-id ( -- ) + { { "id" [ v-number ] } } validate-params ; + +TUPLE: page-action < action template ; + +: ( path -- response ) + resolve-template-path "text/html" ; + +: ( -- page ) + page-action new-action + dup '[ , template>> ] >>display ; diff --git a/extra/furnace/asides/asides.factor b/extra/furnace/asides/asides.factor new file mode 100644 index 0000000000..f6b4e2c15f --- /dev/null +++ b/extra/furnace/asides/asides.factor @@ -0,0 +1,73 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors namespaces sequences arrays kernel +assocs assocs.lib hashtables math.parser urls combinators +furnace http http.server http.server.filters furnace.sessions +html.elements html.templates.chloe.syntax ; +IN: furnace.asides + +TUPLE: asides < filter-responder ; + +C: asides + +: begin-aside* ( -- id ) + request get + [ url>> ] [ post-data>> ] [ method>> ] tri 3array + asides sget set-at-unique + session-changed ; + +: end-aside-post ( url post-data -- response ) + request [ + clone + swap >>post-data + swap >>url + ] change + request get url>> path>> split-path + asides get responder>> call-responder ; + +ERROR: end-aside-in-get-error ; + +: end-aside* ( url id -- response ) + request get method>> "POST" = [ end-aside-in-get-error ] unless + asides sget at [ + first3 { + { "GET" [ drop ] } + { "HEAD" [ drop ] } + { "POST" [ end-aside-post ] } + } case + ] [ ] ?if ; + +SYMBOL: aside-id + +: aside-id-key "__a" ; + +: begin-aside ( -- ) + begin-aside* aside-id set ; + +: end-aside ( default -- response ) + aside-id [ f ] change end-aside* ; + +M: asides call-responder* + dup asides set + aside-id-key request get request-params at aside-id set + call-next-method ; + +M: asides init-session* + H{ } clone asides sset + call-next-method ; + +M: asides link-attr ( tag -- ) + drop + "aside" optional-attr { + { "none" [ aside-id off ] } + { "begin" [ begin-aside ] } + { "current" [ ] } + { f [ ] } + } case ; + +M: asides modify-query ( query responder -- query' ) + drop + aside-id get [ aside-id-key associate assoc-union ] when* ; + +M: asides modify-form ( responder -- ) + drop aside-id get aside-id-key hidden-form-field ; diff --git a/extra/http/server/auth/auth.factor b/extra/furnace/auth/auth.factor similarity index 85% rename from extra/http/server/auth/auth.factor rename to extra/furnace/auth/auth.factor index 4b34fbe804..f78cea3835 100755 --- a/extra/http/server/auth/auth.factor +++ b/extra/furnace/auth/auth.factor @@ -2,9 +2,11 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs namespaces kernel sequences sets http.server -http.server.sessions -http.server.auth.providers ; -IN: http.server.auth +http.server.filters +http.server.dispatchers +furnace.sessions +furnace.auth.providers ; +IN: furnace.auth SYMBOL: logged-in-user diff --git a/extra/http/server/auth/basic/basic.factor b/extra/furnace/auth/basic/basic.factor similarity index 83% rename from extra/http/server/auth/basic/basic.factor rename to extra/furnace/auth/basic/basic.factor index ff071b34e3..c8d542c219 100755 --- a/extra/http/server/auth/basic/basic.factor +++ b/extra/furnace/auth/basic/basic.factor @@ -1,10 +1,10 @@ ! Copyright (c) 2007 Chris Double. ! See http://factorcode.org/license.txt for BSD license. USING: accessors quotations assocs kernel splitting -base64 html.elements io combinators http.server -http.server.auth.providers http.server.auth.login -http sequences ; -IN: http.server.auth.basic +base64 html.elements io combinators sequences +http http.server.filters http.server.responses http.server +furnace.auth.providers furnace.auth.login ; +IN: furnace.auth.basic TUPLE: basic-auth < filter-responder realm provider ; diff --git a/extra/http/server/auth/login/boilerplate.xml b/extra/furnace/auth/login/boilerplate.xml similarity index 100% rename from extra/http/server/auth/login/boilerplate.xml rename to extra/furnace/auth/login/boilerplate.xml diff --git a/extra/http/server/auth/login/edit-profile.xml b/extra/furnace/auth/login/edit-profile.xml similarity index 100% rename from extra/http/server/auth/login/edit-profile.xml rename to extra/furnace/auth/login/edit-profile.xml diff --git a/extra/http/server/auth/login/login-tests.factor b/extra/furnace/auth/login/login-tests.factor similarity index 52% rename from extra/http/server/auth/login/login-tests.factor rename to extra/furnace/auth/login/login-tests.factor index b69630a930..5095ebdb85 100755 --- a/extra/http/server/auth/login/login-tests.factor +++ b/extra/furnace/auth/login/login-tests.factor @@ -1,5 +1,5 @@ -IN: http.server.auth.login.tests -USING: tools.test http.server.auth.login ; +IN: furnace.auth.login.tests +USING: tools.test furnace.auth.login ; \ must-infer \ allow-registration must-infer diff --git a/extra/http/server/auth/login/login.factor b/extra/furnace/auth/login/login.factor similarity index 76% rename from extra/http/server/auth/login/login.factor rename to extra/furnace/auth/login/login.factor index fd4fbab8e8..d0c4e00953 100755 --- a/extra/http/server/auth/login/login.factor +++ b/extra/furnace/auth/login/login.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors quotations assocs kernel splitting combinators sequences namespaces hashtables sets -fry arrays threads qualified random validators +fry arrays threads qualified random validators words io io.sockets io.encodings.utf8 @@ -15,22 +15,40 @@ checksums.sha2 validators html.components html.elements -html.templates -html.templates.chloe +urls http http.server -http.server.auth -http.server.auth.providers -http.server.auth.providers.db -http.server.actions -http.server.flows -http.server.sessions -http.server.boilerplate ; +http.server.dispatchers +http.server.filters +http.server.responses +furnace +furnace.auth +furnace.auth.providers +furnace.auth.providers.db +furnace.actions +furnace.asides +furnace.flash +furnace.sessions +furnace.boilerplate ; QUALIFIED: smtp -IN: http.server.auth.login +IN: furnace.auth.login + +: word>string ( word -- string ) + [ word-vocabulary ] [ drop ":" ] [ word-name ] tri 3append ; + +: words>strings ( seq -- seq' ) + [ word>string ] map ; + +: string>word ( string -- word ) + ":" split1 swap lookup ; + +: strings>words ( seq -- seq' ) + [ string>word ] map ; TUPLE: login < dispatcher users checksum ; +TUPLE: protected < filter-responder description capabilities ; + : users ( -- provider ) login get users>> ; @@ -59,21 +77,24 @@ M: user-saver dispose : save-user-after ( user -- ) &dispose drop ; -: login-template ( name -- template ) - "resource:extra/http/server/auth/login/" swap ".xml" - 3append ; - ! ! ! Login : successful-login ( user -- response ) - username>> set-uid "$login" end-flow ; + username>> set-uid URL" $login" end-aside ; : login-failed ( -- * ) "invalid username or password" validation-error validation-failed ; : ( -- action ) - - [ "login" login-template ] >>display + + [ + protected fget [ + [ description>> "description" set-value ] + [ capabilities>> words>strings "capabilities" set-value ] bi + ] when* + ] >>init + + { login "login" } >>template [ { @@ -102,7 +123,7 @@ M: user-saver dispose : ( -- action ) - "register" login-template >>template + { login "register" } >>template [ { @@ -134,7 +155,7 @@ M: user-saver dispose ! ! ! Editing user profile : ( -- action ) - + [ logged-in-user get [ username>> "username" set-value ] @@ -143,7 +164,7 @@ M: user-saver dispose tri ] >>init - [ "edit-profile" login-template ] >>display + { login "edit-profile" } >>template [ uid "username" set-value @@ -178,7 +199,7 @@ M: user-saver dispose drop - "$login" end-flow + URL" $login" end-aside ] >>submit ; ! ! ! Password recovery @@ -186,10 +207,10 @@ M: user-saver dispose SYMBOL: lost-password-from : current-host ( -- string ) - request get host>> host-name or ; + request get url>> host>> host-name or ; : new-password-url ( user -- url ) - "new-password" + "recover-3" swap [ [ username>> "username" set ] [ ticket>> "ticket" set ] @@ -223,8 +244,8 @@ SYMBOL: lost-password-from "E-mail send thread" spawn drop ; : ( -- action ) - - [ "recover-1" login-template ] >>display + + { login "recover-1" } >>template [ { @@ -240,11 +261,15 @@ SYMBOL: lost-password-from send-password-email ] when* - "recover-2" login-template + URL" $login/recover-2" ] >>submit ; +: ( -- action ) + + { login "recover-2" } >>template ; + : ( -- action ) - + [ { { "username" [ v-username ] } @@ -252,7 +277,7 @@ SYMBOL: lost-password-from } validate-params ] >>init - [ "recover-3" login-template ] >>display + { login "recover-3" } >>template [ { @@ -272,34 +297,38 @@ SYMBOL: lost-password-from "new-password" value >>encoded-password users update-user - "recover-4" login-template + URL" $login/recover-4" ] [ - <400> + <403> ] if* ] >>submit ; +: ( -- action ) + + { login "recover-4" } >>template ; + ! ! ! Logout : ( -- action ) [ f set-uid - "$login/login" end-flow + URL" $login" end-aside ] >>submit ; ! ! ! Authentication logic - -TUPLE: protected < filter-responder capabilities ; - -C: protected +: ( responder -- protected ) + protected new + swap >>responder ; : show-login-page ( -- response ) - begin-flow - "$login/login" f ; + begin-aside + URL" $login/login" { protected } ; : check-capabilities ( responder user -- ? ) [ capabilities>> ] bi@ subset? ; M: protected call-responder* ( path responder -- response ) + dup protected set uid dup [ users get-user 2dup check-capabilities [ [ logged-in-user set ] [ save-user-after ] bi @@ -317,7 +346,7 @@ M: login call-responder* ( path responder -- response ) : ( responder -- responder' ) - "boilerplate" login-template >>template ; + { login "boilerplate" } >>template ; : ( responder -- auth ) login new-dispatcher @@ -330,7 +359,9 @@ M: login call-responder* ( path responder -- response ) ! ! ! Configuration : allow-edit-profile ( login -- login ) - f + + "edit your profile" >>description + "edit-profile" add-responder ; : allow-registration ( login -- login ) @@ -340,8 +371,12 @@ M: login call-responder* ( path responder -- response ) : allow-password-recovery ( login -- login ) "recover-password" add-responder + + "recover-2" add-responder - "new-password" add-responder ; + "recover-3" add-responder + + "recover-4" add-responder ; : allow-edit-profile? ( -- ? ) login get responders>> "edit-profile" swap key? ; diff --git a/extra/http/server/auth/login/login.xml b/extra/furnace/auth/login/login.xml similarity index 59% rename from extra/http/server/auth/login/login.xml rename to extra/furnace/auth/login/login.xml index 545d7e0990..a7ac92bf44 100644 --- a/extra/http/server/auth/login/login.xml +++ b/extra/furnace/auth/login/login.xml @@ -4,6 +4,19 @@ Login + +

You must log in to .

+
+ + +

Your user must have the following capabilities:

+
    + +
  • +
    +
+
+ @@ -30,11 +43,11 @@

- + Register | - + Recover Password

diff --git a/extra/http/server/auth/login/recover-1.xml b/extra/furnace/auth/login/recover-1.xml similarity index 100% rename from extra/http/server/auth/login/recover-1.xml rename to extra/furnace/auth/login/recover-1.xml diff --git a/extra/http/server/auth/login/recover-2.xml b/extra/furnace/auth/login/recover-2.xml similarity index 100% rename from extra/http/server/auth/login/recover-2.xml rename to extra/furnace/auth/login/recover-2.xml diff --git a/extra/http/server/auth/login/recover-3.xml b/extra/furnace/auth/login/recover-3.xml similarity index 100% rename from extra/http/server/auth/login/recover-3.xml rename to extra/furnace/auth/login/recover-3.xml diff --git a/extra/http/server/auth/login/recover-4.xml b/extra/furnace/auth/login/recover-4.xml similarity index 100% rename from extra/http/server/auth/login/recover-4.xml rename to extra/furnace/auth/login/recover-4.xml diff --git a/extra/http/server/auth/login/register.xml b/extra/furnace/auth/login/register.xml similarity index 100% rename from extra/http/server/auth/login/register.xml rename to extra/furnace/auth/login/register.xml diff --git a/extra/http/server/auth/providers/assoc/assoc-tests.factor b/extra/furnace/auth/providers/assoc/assoc-tests.factor similarity index 79% rename from extra/http/server/auth/providers/assoc/assoc-tests.factor rename to extra/furnace/auth/providers/assoc/assoc-tests.factor index 91e802b91c..8f9eeaa7a5 100755 --- a/extra/http/server/auth/providers/assoc/assoc-tests.factor +++ b/extra/furnace/auth/providers/assoc/assoc-tests.factor @@ -1,6 +1,6 @@ -IN: http.server.auth.providers.assoc.tests -USING: http.server.actions http.server.auth.providers -http.server.auth.providers.assoc http.server.auth.login +IN: furnace.auth.providers.assoc.tests +USING: furnace.actions furnace.auth.providers +furnace.auth.providers.assoc furnace.auth.login tools.test namespaces accessors kernel ; diff --git a/extra/http/server/auth/providers/assoc/assoc.factor b/extra/furnace/auth/providers/assoc/assoc.factor similarity index 80% rename from extra/http/server/auth/providers/assoc/assoc.factor rename to extra/furnace/auth/providers/assoc/assoc.factor index d6ba587aa0..f5a79d701b 100755 --- a/extra/http/server/auth/providers/assoc/assoc.factor +++ b/extra/furnace/auth/providers/assoc/assoc.factor @@ -1,8 +1,7 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -IN: http.server.auth.providers.assoc -USING: accessors assocs kernel -http.server.auth.providers ; +IN: furnace.auth.providers.assoc +USING: accessors assocs kernel furnace.auth.providers ; TUPLE: users-in-memory assoc ; diff --git a/extra/http/server/auth/providers/db/db-tests.factor b/extra/furnace/auth/providers/db/db-tests.factor similarity index 83% rename from extra/http/server/auth/providers/db/db-tests.factor rename to extra/furnace/auth/providers/db/db-tests.factor index a6a92356b6..714dcb416f 100755 --- a/extra/http/server/auth/providers/db/db-tests.factor +++ b/extra/furnace/auth/providers/db/db-tests.factor @@ -1,8 +1,8 @@ -IN: http.server.auth.providers.db.tests -USING: http.server.actions -http.server.auth.login -http.server.auth.providers -http.server.auth.providers.db tools.test +IN: furnace.auth.providers.db.tests +USING: furnace.actions +furnace.auth.login +furnace.auth.providers +furnace.auth.providers.db tools.test namespaces db db.sqlite db.tuples continuations io.files accessors kernel ; diff --git a/extra/http/server/auth/providers/db/db.factor b/extra/furnace/auth/providers/db/db.factor similarity index 92% rename from extra/http/server/auth/providers/db/db.factor rename to extra/furnace/auth/providers/db/db.factor index 3ed4845609..90306e5181 100755 --- a/extra/http/server/auth/providers/db/db.factor +++ b/extra/furnace/auth/providers/db/db.factor @@ -1,9 +1,9 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: db db.tuples db.types accessors -http.server.auth.providers kernel continuations +furnace.auth.providers kernel continuations classes.singleton ; -IN: http.server.auth.providers.db +IN: furnace.auth.providers.db user "USERS" { diff --git a/extra/http/server/auth/providers/null/null.factor b/extra/furnace/auth/providers/null/null.factor similarity index 71% rename from extra/http/server/auth/providers/null/null.factor rename to extra/furnace/auth/providers/null/null.factor index 30f6dbd06e..39ea812ae7 100755 --- a/extra/http/server/auth/providers/null/null.factor +++ b/extra/furnace/auth/providers/null/null.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: http.server.auth.providers kernel ; -IN: http.server.auth.providers.null +USING: furnace.auth.providers kernel ; +IN: furnace.auth.providers.null TUPLE: no-users ; diff --git a/extra/http/server/auth/providers/providers.factor b/extra/furnace/auth/providers/providers.factor similarity index 94% rename from extra/http/server/auth/providers/providers.factor rename to extra/furnace/auth/providers/providers.factor index a51c4da1b9..1933fc8c59 100755 --- a/extra/http/server/auth/providers/providers.factor +++ b/extra/furnace/auth/providers/providers.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors random math.parser locals sequences math ; -IN: http.server.auth.providers +IN: furnace.auth.providers TUPLE: user username realname diff --git a/extra/http/server/boilerplate/boilerplate.factor b/extra/furnace/boilerplate/boilerplate.factor similarity index 55% rename from extra/http/server/boilerplate/boilerplate.factor rename to extra/furnace/boilerplate/boilerplate.factor index 96c59edd10..42f132ada1 100644 --- a/extra/http/server/boilerplate/boilerplate.factor +++ b/extra/furnace/boilerplate/boilerplate.factor @@ -1,8 +1,12 @@ ! Copyright (c) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel namespaces http.server html.templates -locals ; -IN: http.server.boilerplate +USING: accessors kernel namespaces +html.templates html.templates.chloe +locals +http.server +http.server.filters +furnace ; +IN: furnace.boilerplate TUPLE: boilerplate < filter-responder template ; @@ -12,6 +16,10 @@ M:: boilerplate call-responder* ( path responder -- ) path responder call-next-method dup content-type>> "text/html" = [ clone [| body | - [ body responder template>> with-boilerplate ] + [ + body + responder template>> resolve-template-path + with-boilerplate + ] ] change-body ] when ; diff --git a/extra/furnace/db/db-tests.factor b/extra/furnace/db/db-tests.factor new file mode 100644 index 0000000000..34357ae701 --- /dev/null +++ b/extra/furnace/db/db-tests.factor @@ -0,0 +1,4 @@ +IN: furnace.db.tests +USING: tools.test furnace.db ; + +\ must-infer diff --git a/extra/http/server/db/db.factor b/extra/furnace/db/db.factor similarity index 71% rename from extra/http/server/db/db.factor rename to extra/furnace/db/db.factor index 73d4c35e2c..8487b4b3fc 100755 --- a/extra/http/server/db/db.factor +++ b/extra/furnace/db/db.factor @@ -1,8 +1,9 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: db db.pools io.pools http.server http.server.sessions -kernel accessors continuations namespaces destructors ; -IN: http.server.db +USING: kernel accessors continuations namespaces destructors +db db.pools io.pools http.server http.server.filters +furnace.sessions ; +IN: furnace.db TUPLE: db-persistence < filter-responder pool ; diff --git a/extra/furnace/flash/flash.factor b/extra/furnace/flash/flash.factor new file mode 100644 index 0000000000..21fd20ccb4 --- /dev/null +++ b/extra/furnace/flash/flash.factor @@ -0,0 +1,38 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: namespaces assocs assocs.lib kernel sequences urls +http http.server http.server.filters http.server.redirection +furnace furnace.sessions ; +IN: furnace.flash + +: flash-id-key "__f" ; + +TUPLE: flash-scopes < filter-responder ; + +C: flash-scopes + +SYMBOL: flash-scope + +: fget ( key -- value ) flash-scope get at ; + +M: flash-scopes call-responder* + flash-id-key + request get request-params at + flash-scopes sget at flash-scope set + call-next-method ; + +M: flash-scopes init-session* + H{ } clone flash-scopes sset + call-next-method ; + +: make-flash-scope ( seq -- id ) + [ dup get ] H{ } map>assoc flash-scopes sget set-at-unique + session-changed ; + +: ( url seq -- response ) + make-flash-scope + [ clone ] dip flash-id-key set-query-param + ; + +: restore-flash ( seq -- ) + [ flash-scope get key? ] filter [ [ fget ] keep set ] each ; diff --git a/extra/furnace/furnace-tests.factor b/extra/furnace/furnace-tests.factor new file mode 100644 index 0000000000..223b20455d --- /dev/null +++ b/extra/furnace/furnace-tests.factor @@ -0,0 +1,35 @@ +IN: furnace.tests +USING: http.server.dispatchers http.server.responses +http.server furnace tools.test kernel namespaces accessors +io.streams.string ; +TUPLE: funny-dispatcher < dispatcher ; + +: funny-dispatcher new-dispatcher ; + +TUPLE: base-path-check-responder ; + +C: base-path-check-responder + +M: base-path-check-responder call-responder* + 2drop + "$funny-dispatcher" resolve-base-path + "text/plain" ; + +[ ] [ + + + + "c" add-responder + "b" add-responder + "a" add-responder + main-responder set +] unit-test + +[ "/a/b/" ] [ + V{ } responder-nesting set + "a/b/c" split-path main-responder get call-responder body>> +] unit-test + +[ "" ] +[ [ "&&&" "foo" hidden-form-field ] with-string-writer ] +unit-test diff --git a/extra/furnace/furnace.factor b/extra/furnace/furnace.factor new file mode 100644 index 0000000000..3566d45c5b --- /dev/null +++ b/extra/furnace/furnace.factor @@ -0,0 +1,192 @@ +! Copyright (C) 2003, 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors arrays kernel combinators assocs +continuations namespaces sequences splitting words +vocabs.loader classes strings +fry urls multiline present +xml +xml.data +xml.entities +xml.writer +html.components +html.elements +html.templates +html.templates.chloe +html.templates.chloe.syntax +http +http.server +http.server.redirection +http.server.responses +qualified ; +QUALIFIED-WITH: assocs a +EXCLUDE: xml.utilities => children>string ; +IN: furnace + +: nested-responders ( -- seq ) + responder-nesting get a:values ; + +: each-responder ( quot -- ) + nested-responders swap each ; inline + +: base-path ( string -- pair ) + dup responder-nesting get + [ second class word-name = ] with find nip + [ first ] [ "No such responder: " swap append throw ] ?if ; + +: resolve-base-path ( string -- string' ) + "$" ?head [ + [ + "/" split1 [ base-path [ "/" % % ] each "/" % ] dip % + ] "" make + ] when ; + +: vocab-path ( vocab -- path ) + dup vocab-dir vocab-append-path ; + +: resolve-template-path ( pair -- path ) + [ + first2 [ word-vocabulary vocab-path % ] [ "/" % % ] bi* + ] "" make ; + +GENERIC: modify-query ( query responder -- query' ) + +M: object modify-query drop ; + +GENERIC: adjust-url ( url -- url' ) + +M: url adjust-url + clone + [ [ modify-query ] each-responder ] change-query + [ resolve-base-path ] change-path + relative-to-request ; + +M: string adjust-url ; + +: ( url -- response ) + adjust-url request get method>> { + { "GET" [ ] } + { "HEAD" [ ] } + { "POST" [ ] } + } case ; + +GENERIC: modify-form ( responder -- ) + +M: object modify-form drop ; + +: request-params ( request -- assoc ) + dup method>> { + { "GET" [ url>> query>> ] } + { "HEAD" [ url>> query>> ] } + { "POST" [ + post-data>> + dup content-type>> "application/x-www-form-urlencoded" = + [ content>> ] [ drop f ] if + ] } + } case ; + +SYMBOL: exit-continuation + +: exit-with exit-continuation get continue-with ; + +: with-exit-continuation ( quot -- ) + '[ exit-continuation set @ ] callcc1 exit-continuation off ; + +! Chloe tags +: parse-query-attr ( string -- assoc ) + dup empty? + [ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ; + +CHLOE: atom + [ children>string ] + [ "href" required-attr ] + [ "query" optional-attr parse-query-attr ] tri + + swap >>query + swap >>path + adjust-url relative-to-request + add-atom-feed ; + +CHLOE: write-atom drop write-atom-feeds ; + +GENERIC: link-attr ( tag responder -- ) + +M: object link-attr 2drop ; + +: link-attrs ( tag -- ) + '[ , _ link-attr ] each-responder ; + +: a-start-tag ( tag -- ) + [ + + swap >>query + swap >>path + adjust-url relative-to-request =href + a> + ] with-scope ; + +CHLOE: a + [ a-start-tag ] + [ process-tag-children ] + [ drop ] + tri ; + +: hidden-form-field ( value name -- ) + over [ + + ] [ 2drop ] if ; + +: form-nesting-key "__n" ; + +: form-magic ( tag -- ) + [ modify-form ] each-responder + nested-values get " " join f like form-nesting-key hidden-form-field + "for" optional-attr [ "," split [ hidden render ] each ] when* ; + +: form-start-tag ( tag -- ) + [ + [ +
+ ] + [ form-magic ] bi + ] with-scope ; + +CHLOE: form + [ form-start-tag ] + [ process-tag-children ] + [ drop ] + tri ; + +STRING: button-tag-markup + + + +; + +: add-tag-attrs ( attrs tag -- ) + tag-attrs swap update ; + +CHLOE: button + button-tag-markup string>xml delegate + { + [ [ tag-attrs chloe-attrs-only ] dip add-tag-attrs ] + [ [ tag-attrs non-chloe-attrs-only ] dip "button" tag-named add-tag-attrs ] + [ [ children>string 1array ] dip "button" tag-named set-tag-children ] + [ nip ] + } 2cleave process-chloe-tag ; diff --git a/extra/furnace/json/json.factor b/extra/furnace/json/json.factor new file mode 100644 index 0000000000..a5188cd355 --- /dev/null +++ b/extra/furnace/json/json.factor @@ -0,0 +1,7 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: json.writer http.server.responses ; +IN: furnace.json + +: ( body -- response ) + >json "application/json" ; diff --git a/extra/http/server/sessions/authors.txt b/extra/furnace/sessions/authors.txt similarity index 100% rename from extra/http/server/sessions/authors.txt rename to extra/furnace/sessions/authors.txt diff --git a/extra/http/server/sessions/sessions-tests.factor b/extra/furnace/sessions/sessions-tests.factor similarity index 78% rename from extra/http/server/sessions/sessions-tests.factor rename to extra/furnace/sessions/sessions-tests.factor index 8ea312dcb5..a7a663ffa8 100755 --- a/extra/http/server/sessions/sessions-tests.factor +++ b/extra/furnace/sessions/sessions-tests.factor @@ -1,8 +1,10 @@ -IN: http.server.sessions.tests -USING: tools.test http http.server.sessions -http.server.actions http.server math namespaces kernel accessors +IN: furnace.sessions.tests +USING: tools.test http furnace.sessions +furnace.actions http.server http.server.responses +math namespaces kernel accessors prettyprint io.streams.string io.files splitting destructors -sequences db db.sqlite continuations ; +sequences db db.sqlite continuations urls math.parser +furnace ; : with-session [ @@ -18,15 +20,16 @@ M: foo init-session* drop 0 "x" sset ; M: foo call-responder* 2drop "x" [ 1+ ] schange - [ "x" sget pprint ] ; + "x" sget number>string "text/html" ; : url-responder-mock-test [ "GET" >>method - "id" get session-id-key set-query-param - "/" >>path - request set + dup url>> + "id" get session-id-key set-query-param + "/" >>path drop + init-request { } sessions get call-responder [ write-response-body drop ] with-string-writer ] with-destructors ; @@ -36,21 +39,21 @@ M: foo call-responder* "GET" >>method "cookies" get >>cookies - "/" >>path - request set + dup url>> "/" >>path drop + init-request { } sessions get call-responder [ write-response-body drop ] with-string-writer ] with-destructors ; : - [ [ ] exit-with ] >>display ; + [ [ ] "text/plain" exit-with ] >>display ; [ "auth-test.db" temp-file sqlite-db delete-file ] ignore-errors "auth-test.db" temp-file sqlite-db [ - init-request + init-request init-sessions-table [ ] [ @@ -112,8 +115,8 @@ M: foo call-responder* [ - "GET" >>method - "/" >>path + "GET" >>method + dup url>> "/" >>path drop request set { "etc" } sessions get call-responder response set [ "1" ] [ [ response get write-response-body drop ] with-string-writer ] unit-test @@ -131,8 +134,9 @@ M: foo call-responder* [ ] [ "GET" >>method - "id" get session-id-key set-query-param - "/" >>path + dup url>> + "id" get session-id-key set-query-param + "/" >>path drop request set [ diff --git a/extra/http/server/sessions/sessions.factor b/extra/furnace/sessions/sessions.factor similarity index 91% rename from extra/http/server/sessions/sessions.factor rename to extra/furnace/sessions/sessions.factor index a7e1a141c4..16fefe42fc 100755 --- a/extra/http/server/sessions/sessions.factor +++ b/extra/furnace/sessions/sessions.factor @@ -4,8 +4,9 @@ USING: assocs kernel math.intervals math.parser namespaces random accessors quotations hashtables sequences continuations fry calendar combinators destructors alarms db db.tuples db.types -http http.server html.elements ; -IN: http.server.sessions +http http.server http.server.dispatchers http.server.filters +html.elements furnace ; +IN: furnace.sessions TUPLE: session id expires uid namespace changed? ; @@ -108,14 +109,14 @@ M: session-saver dispose [ session set ] [ save-session-after ] bi sessions get responder>> call-responder ; -: session-id-key "factorsessid" ; +: session-id-key "__s" ; : cookie-session-id ( request -- id/f ) session-id-key get-cookie dup [ value>> string>number ] when ; : post-session-id ( request -- id/f ) - session-id-key swap post-data>> at string>number ; + session-id-key swap request-params at string>number ; : request-session-id ( -- id/f ) request get dup method>> { @@ -136,15 +137,10 @@ M: session-saver dispose : put-session-cookie ( response -- response' ) session get id>> number>string put-cookie ; -: session-form-field ( -- ) - > number>string =value - input/> ; +M: sessions modify-form ( responder -- ) + drop session get id>> session-id-key hidden-form-field ; M: sessions call-responder* ( path responder -- response ) - [ session-form-field ] add-form-hook sessions set request-session [ begin-session ] unless* existing-session put-session-cookie ; diff --git a/extra/furnace/syndication/syndication.factor b/extra/furnace/syndication/syndication.factor new file mode 100644 index 0000000000..7f60bcc746 --- /dev/null +++ b/extra/furnace/syndication/syndication.factor @@ -0,0 +1,53 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors kernel sequences fry sequences.lib +combinators syndication +http.server.responses http.server.redirection +furnace furnace.actions ; +IN: furnace.syndication + +GENERIC: feed-entry-title ( object -- string ) + +GENERIC: feed-entry-date ( object -- timestamp ) + +GENERIC: feed-entry-url ( object -- url ) + +GENERIC: feed-entry-description ( object -- description ) + +M: object feed-entry-description drop f ; + +GENERIC: >entry ( object -- entry ) + +M: entry >entry ; + +M: object >entry + + swap { + [ feed-entry-title >>title ] + [ feed-entry-date >>date ] + [ feed-entry-url >>url ] + [ feed-entry-description >>description ] + } cleave ; + +: process-entries ( seq -- seq' ) + 20 short head-slice [ + >entry clone + [ adjust-url relative-to-request ] change-url + ] map ; + +: ( body -- response ) + feed>xml "application/atom+xml" ; + +TUPLE: feed-action < action title url entries ; + +: ( -- action ) + feed-action new-action + dup '[ + feed new + , + [ title>> call >>title ] + [ url>> call adjust-url relative-to-request >>url ] + [ entries>> call process-entries >>entries ] + tri + + ] >>display ; diff --git a/extra/globs/globs.factor b/extra/globs/globs.factor index 4fa56bcf93..d131946ffb 100755 --- a/extra/globs/globs.factor +++ b/extra/globs/globs.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2007 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: parser-combinators regexp lazy-lists sequences kernel +USING: parser-combinators regexp lists sequences kernel promises strings unicode.case ; IN: globs diff --git a/extra/help/html/html.factor b/extra/help/html/html.factor new file mode 100644 index 0000000000..b1bf8958a8 --- /dev/null +++ b/extra/help/html/html.factor @@ -0,0 +1,5 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +IN: help.html + + diff --git a/extra/html/components/components-tests.factor b/extra/html/components/components-tests.factor index 1a0f849a8f..2ae120b527 100644 --- a/extra/html/components/components-tests.factor +++ b/extra/html/components/components-tests.factor @@ -1,7 +1,7 @@ IN: html.components.tests USING: tools.test kernel io.streams.string io.streams.null accessors inspector html.streams -html.components namespaces ; +html.elements html.components namespaces ; [ ] [ blank-values ] unit-test @@ -11,14 +11,12 @@ html.components namespaces ; TUPLE: color red green blue ; -[ ] [ 1 2 3 color boa from-tuple ] unit-test +[ ] [ 1 2 3 color boa from-object ] unit-test [ 1 ] [ "red" value ] unit-test [ ] [ "jimmy" "red" set-value ] unit-test -[ "123.5" ] [ 123.5 object>string ] unit-test - [ "jimmy" ] [ [ "red" label render @@ -107,7 +105,7 @@ TUPLE: color red green blue ; [ ] [ t "delivery" set-value ] unit-test -[ "Delivery" ] [ +[ "Delivery" ] [ [ "delivery" diff --git a/extra/html/components/components.factor b/extra/html/components/components.factor index efac730af6..72dabad84e 100644 --- a/extra/html/components/components.factor +++ b/extra/html/components/components.factor @@ -5,7 +5,7 @@ classes.tuple words arrays sequences sequences.lib splitting mirrors hashtables combinators continuations math strings fry locals calendar calendar.format xml.entities validators html.elements html.streams xmode.code2html farkup inspector -lcs.diff2html ; +lcs.diff2html urls present ; IN: html.components SYMBOL: values @@ -19,9 +19,9 @@ SYMBOL: values : prepare-value ( name object -- value name object ) [ [ value ] keep ] dip ; inline -: from-assoc ( assoc -- ) values get swap update ; - -: from-tuple ( tuple -- ) from-assoc ; +: from-object ( object -- ) + dup assoc? [ ] unless + values get swap update ; : deposit-values ( destination names -- ) [ dup value ] H{ } map>assoc update ; @@ -29,27 +29,36 @@ SYMBOL: values : deposit-slots ( destination names -- ) [ ] dip deposit-values ; -: with-each-index ( seq quot -- ) - '[ +: with-each-value ( name quot -- ) + [ value ] dip '[ [ - blank-values 1+ "index" set-value @ + values [ clone ] change + 1+ "index" set-value + "value" set-value + @ ] with-scope ] each-index ; inline -: with-each-value ( seq quot -- ) - '[ "value" set-value @ ] with-each-index ; inline +: with-each-object ( name quot -- ) + [ value ] dip '[ + [ + blank-values + 1+ "index" set-value + from-object + @ + ] with-scope + ] each-index ; inline -: with-each-assoc ( seq quot -- ) - '[ from-assoc @ ] with-each-index ; inline +SYMBOL: nested-values -: with-each-tuple ( seq quot -- ) - '[ from-tuple @ ] with-each-index ; inline - -: with-assoc-values ( assoc quot -- ) - '[ blank-values , from-assoc @ ] with-scope ; inline - -: with-tuple-values ( assoc quot -- ) - '[ blank-values , from-tuple @ ] with-scope ; inline +: with-values ( name quot -- ) + '[ + , + [ nested-values [ swap prefix ] change ] + [ value blank-values from-object ] + bi + @ + ] with-scope ; inline : nest-values ( name quot -- ) swap [ @@ -58,22 +67,6 @@ SYMBOL: values ] with-scope ] dip set-value ; inline -: nest-tuple ( name quot -- ) - swap [ - [ - H{ } clone [ values set call ] keep - ] with-scope - ] dip set-value ; inline - -: object>string ( object -- string ) - { - { [ dup real? ] [ number>string ] } - { [ dup timestamp? ] [ timestamp>string ] } - { [ dup string? ] [ ] } - { [ dup word? ] [ word-name ] } - { [ dup not ] [ drop "" ] } - } cond ; - GENERIC: render* ( value name render -- ) : render ( name renderer -- ) @@ -88,13 +81,13 @@ GENERIC: render* ( value name render -- ) string =value input/> ; + ; PRIVATE> SINGLETON: label -M: label render* 2drop object>string escape-string write ; +M: label render* 2drop present escape-string write ; SINGLETON: hidden @@ -103,9 +96,9 @@ M: hidden render* drop "hidden" render-input ; : render-field ( value name size type -- ) string =size ] when* + [ present =size ] when* =name - object>string =value + present =value input/> ; TUPLE: field size ; @@ -132,11 +125,11 @@ TUPLE: textarea rows cols ; M: textarea render* ; ! Choice @@ -147,7 +140,7 @@ TUPLE: choice size multiple choices ; : render-option ( text selected? -- ) ; : render-options ( options selected -- ) @@ -156,7 +149,7 @@ TUPLE: choice size multiple choices ; M: choice render* label>> escape-string write ; @@ -183,12 +176,18 @@ M: checkbox render* GENERIC: link-title ( obj -- string ) GENERIC: link-href ( obj -- url ) +M: string link-title ; +M: string link-href ; + +M: url link-title ; +M: url link-href ; + SINGLETON: link M: link render* 2drop - link-title object>string escape-string write + link-title present escape-string write ; ! XMode code component diff --git a/extra/html/elements/elements.factor b/extra/html/elements/elements.factor index e5377cedf8..1c56ee8031 100644 --- a/extra/html/elements/elements.factor +++ b/extra/html/elements/elements.factor @@ -4,7 +4,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: io kernel namespaces prettyprint quotations -sequences strings words xml.entities compiler.units effects ; +sequences strings words xml.entities compiler.units effects +urls math math.parser combinators present ; IN: html.elements @@ -130,7 +131,7 @@ SYMBOL: html " " write-html write-html "='" write-html - escape-quoted-string write-html + present escape-quoted-string write-html "'" write-html ; : attribute-effect T{ effect f { "string" } 0 } ; @@ -162,7 +163,7 @@ SYMBOL: html "id" "onclick" "style" "valign" "accesskey" "src" "language" "colspan" "onchange" "rel" "width" "selected" "onsubmit" "xmlns" "lang" "xml:lang" - "media" "title" "multiple" + "media" "title" "multiple" "checked" ] [ define-attribute-word ] each >> @@ -178,7 +179,7 @@ SYMBOL: html swap write call - ; + ; inline : render-error ( message -- ) escape-string write ; diff --git a/extra/html/parser/analyzer/analyzer.factor b/extra/html/parser/analyzer/analyzer.factor index 9ce45b5c47..47d352b6b8 100755 --- a/extra/html/parser/analyzer/analyzer.factor +++ b/extra/html/parser/analyzer/analyzer.factor @@ -1,6 +1,6 @@ USING: assocs html.parser kernel math sequences strings ascii arrays shuffle unicode.case namespaces splitting http -sequences.lib accessors io combinators http.client ; +sequences.lib accessors io combinators http.client urls ; IN: html.parser.analyzer TUPLE: link attributes clickable ; diff --git a/extra/html/templates/chloe/chloe-tests.factor b/extra/html/templates/chloe/chloe-tests.factor index eaa0f0dc3d..6ca596f503 100644 --- a/extra/html/templates/chloe/chloe-tests.factor +++ b/extra/html/templates/chloe/chloe-tests.factor @@ -1,7 +1,7 @@ USING: html.templates html.templates.chloe tools.test io.streams.string kernel sequences ascii boxes namespaces xml html.components -splitting unicode.categories ; +splitting unicode.categories furnace ; IN: html.templates.chloe.tests [ f ] [ f parse-query-attr ] unit-test @@ -27,8 +27,7 @@ IN: html.templates.chloe.tests : test-template ( name -- template ) "resource:extra/html/templates/chloe/test/" - swap - ".xml" 3append ; + prepend ; [ "Hello world" ] [ [ @@ -70,24 +69,6 @@ IN: html.templates.chloe.tests ] run-template ] unit-test -SYMBOL: test6-aux? - -[ "True" ] [ - [ - test6-aux? on - "test6" test-template call-template - ] run-template -] unit-test - -SYMBOL: test7-aux? - -[ "" ] [ - [ - test7-aux? off - "test7" test-template call-template - ] run-template -] unit-test - [ ] [ blank-values ] unit-test [ ] [ "A label" "label" set-value ] unit-test @@ -128,7 +109,7 @@ M: link-test link-href drop "http://www.apple.com/foo&bar" ; [ "
  • 1
  • 2
  • 3
" ] [ [ - "test9" test-template call-template + "test7" test-template call-template ] run-template [ blank? not ] filter ] unit-test @@ -143,7 +124,7 @@ TUPLE: person first-name last-name ; [ "
RBaxterUnknown
DougColeman
" ] [ [ - "test10" test-template call-template + "test8" test-template call-template ] run-template [ blank? not ] filter ] unit-test @@ -155,7 +136,47 @@ TUPLE: person first-name last-name ; ] unit-test [ "
RBaxterUnknown
DougColeman
" ] [ + [ + "test8" test-template call-template + ] run-template [ blank? not ] filter +] unit-test + +[ ] [ 1 "id" set-value ] unit-test + +[ "Hello" ] [ + [ + "test9" test-template call-template + ] run-template +] unit-test + +[ ] [ H{ { "a" H{ { "b" "c" } } } } values set ] unit-test + +[ "
" ] [ + [ + "test10" test-template call-template + ] run-template +] unit-test + +[ ] [ blank-values ] unit-test + +[ ] [ + H{ { "first-name" "RBaxter" } { "last-name" "Unknown" } } "person" set-value +] unit-test + +[ "
RBaxterUnknown
" ] [ [ "test11" test-template call-template ] run-template [ blank? not ] filter ] unit-test + +[ ] [ + blank-values + { "a" "b" } "choices" set-value + "true" "b" set-value +] unit-test + +[ "ab" ] [ + [ + "test12" test-template call-template + ] run-template +] unit-test diff --git a/extra/html/templates/chloe/chloe.factor b/extra/html/templates/chloe/chloe.factor index 092f79bb36..08d6b873fc 100644 --- a/extra/html/templates/chloe/chloe.factor +++ b/extra/html/templates/chloe/chloe.factor @@ -3,19 +3,16 @@ USING: accessors kernel sequences combinators kernel namespaces classes.tuple assocs splitting words arrays memoize io io.files io.encodings.utf8 io.streams.string -unicode.case tuple-syntax mirrors fry math +unicode.case tuple-syntax mirrors fry math urls present multiline xml xml.data xml.writer xml.utilities html.elements html.components html.templates -http.server -http.server.auth -http.server.flows -http.server.actions -http.server.sessions ; +html.templates.chloe.syntax ; IN: html.templates.chloe ! Chloe is Ed's favorite web designer +SYMBOL: tag-stack TUPLE: chloe path ; @@ -23,8 +20,6 @@ C: chloe DEFER: process-template -: chloe-ns "http://factorcode.org/chloe/1.0" ; inline - : chloe-attrs-only ( assoc -- assoc' ) [ drop name-url chloe-ns = ] assoc-filter ; @@ -38,35 +33,23 @@ DEFER: process-template [ t ] } cond nip ; -SYMBOL: tags - -MEMO: chloe-name ( string -- name ) - name new - swap >>tag - chloe-ns >>url ; - -: required-attr ( tag name -- value ) - dup chloe-name rot at* - [ nip ] [ drop " attribute is required" append throw ] if ; - -: optional-attr ( tag name -- value ) - chloe-name swap at ; - : process-tag-children ( tag -- ) [ process-template ] each ; +CHLOE: chloe process-tag-children ; + : children>string ( tag -- string ) [ process-tag-children ] with-string-writer ; -: title-tag ( tag -- ) - children>string set-title ; +CHLOE: title children>string set-title ; -: write-title-tag ( tag -- ) +CHLOE: write-title drop - "head" tags get member? "title" tags get member? not and + "head" tag-stack get member? + "title" tag-stack get member? not and [ write-title ] [ write-title ] if ; -: style-tag ( tag -- ) +CHLOE: style dup "include" optional-attr dup [ swap children>string empty? [ "style tag cannot have both an include attribute and a body" throw @@ -76,241 +59,80 @@ MEMO: chloe-name ( string -- name ) drop children>string ] if add-style ; -: write-style-tag ( tag -- ) +CHLOE: write-style drop ; -: atom-tag ( tag -- ) - [ "title" required-attr ] - [ "href" required-attr ] - bi set-atom-feed ; +CHLOE: even "index" value even? [ process-tag-children ] [ drop ] if ; -: write-atom-tag ( tag -- ) - drop - "head" tags get member? [ - write-atom-feed - ] [ - atom-feed get value>> second write - ] if ; +CHLOE: odd "index" value odd? [ process-tag-children ] [ drop ] if ; -: parse-query-attr ( string -- assoc ) - dup empty? - [ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ; - -: flow-attr ( tag -- ) - "flow" optional-attr { - { "none" [ flow-id off ] } - { "begin" [ begin-flow ] } - { "current" [ ] } - { f [ ] } - } case ; - -: session-attr ( tag -- ) - "session" optional-attr { - { "none" [ session off flow-id off ] } - { "current" [ ] } - { f [ ] } - } case ; - -: a-start-tag ( tag -- ) +: (bind-tag) ( tag quot -- ) [ - string =href - a> - ] with-scope ; + [ "name" required-attr ] keep + '[ , process-tag-children ] + ] dip call ; inline -: a-tag ( tag -- ) - [ a-start-tag ] - [ process-tag-children ] - [ drop ] - tri ; +CHLOE: each [ with-each-value ] (bind-tag) ; -: form-start-tag ( tag -- ) - [ - [ -
- ] [ - hidden-form-field - "for" optional-attr [ hidden render ] when* - ] bi - ] with-scope ; +CHLOE: bind-each [ with-each-object ] (bind-tag) ; -: form-tag ( tag -- ) - [ form-start-tag ] - [ process-tag-children ] - [ drop
] - tri ; +CHLOE: bind [ with-values ] (bind-tag) ; -DEFER: process-chloe-tag +: error-message-tag ( tag -- ) + children>string render-error ; -STRING: button-tag-markup - - - -; +CHLOE: comment drop ; -: add-tag-attrs ( attrs tag -- ) - tag-attrs swap update ; - -: button-tag ( tag -- ) - button-tag-markup string>xml delegate - { - [ [ tag-attrs chloe-attrs-only ] dip add-tag-attrs ] - [ [ tag-attrs non-chloe-attrs-only ] dip "button" tag-named add-tag-attrs ] - [ [ children>string 1array ] dip "button" tag-named set-tag-children ] - [ nip ] - } 2cleave process-chloe-tag ; +CHLOE: call-next-template drop call-next-template ; : attr>word ( value -- word/f ) dup ":" split1 swap lookup [ ] [ "No such word: " swap append throw ] ?if ; -: attr>var ( value -- word/f ) - attr>word dup symbol? [ - "Must be a symbol: " swap append throw - ] unless ; - : if-satisfied? ( tag -- ? ) - t swap - { - [ "code" optional-attr [ attr>word execute and ] when* ] - [ "var" optional-attr [ attr>var get and ] when* ] - [ "svar" optional-attr [ attr>var sget and ] when* ] - [ "uvar" optional-attr [ attr>var uget and ] when* ] - [ "value" optional-attr [ value and ] when* ] - } cleave ; + [ "code" optional-attr [ attr>word execute ] [ t ] if* ] + [ "value" optional-attr [ value ] [ t ] if* ] + bi and ; -: if-tag ( tag -- ) - dup if-satisfied? [ process-tag-children ] [ drop ] if ; +CHLOE: if dup if-satisfied? [ process-tag-children ] [ drop ] if ; -: even-tag ( tag -- ) - "index" value even? [ process-tag-children ] [ drop ] if ; +CHLOE-SINGLETON: label +CHLOE-SINGLETON: link +CHLOE-SINGLETON: farkup +CHLOE-SINGLETON: inspector +CHLOE-SINGLETON: comparison +CHLOE-SINGLETON: html +CHLOE-SINGLETON: hidden -: odd-tag ( tag -- ) - "index" value odd? [ process-tag-children ] [ drop ] if ; - -: (each-tag) ( tag quot -- ) - [ - [ "values" required-attr value ] keep - '[ , process-tag-children ] - ] dip call ; inline - -: each-tag ( tag -- ) - [ with-each-value ] (each-tag) ; - -: each-tuple-tag ( tag -- ) - [ with-each-tuple ] (each-tag) ; - -: each-assoc-tag ( tag -- ) - [ with-each-assoc ] (each-tag) ; - -: (bind-tag) ( tag quot -- ) - [ - [ "name" required-attr value ] keep - '[ , process-tag-children ] - ] dip call ; inline - -: bind-tuple-tag ( tag -- ) - [ with-tuple-values ] (bind-tag) ; - -: bind-assoc-tag ( tag -- ) - [ with-assoc-values ] (bind-tag) ; - -: error-message-tag ( tag -- ) - children>string render-error ; - -: validation-messages-tag ( tag -- ) - drop render-validation-messages ; - -: singleton-component-tag ( tag class -- ) - [ "name" required-attr ] dip render ; - -: attrs>slots ( tag tuple -- ) - [ attrs>> ] [ ] bi* - '[ - swap tag>> dup "name" = - [ 2drop ] [ , set-at ] if - ] assoc-each ; - -: tuple-component-tag ( tag class -- ) - [ drop "name" required-attr ] - [ new [ attrs>slots ] keep ] - 2bi render ; +CHLOE-TUPLE: field +CHLOE-TUPLE: textarea +CHLOE-TUPLE: password +CHLOE-TUPLE: choice +CHLOE-TUPLE: checkbox +CHLOE-TUPLE: code : process-chloe-tag ( tag -- ) - dup name-tag { - { "chloe" [ process-tag-children ] } - - ! HTML head - { "title" [ title-tag ] } - { "write-title" [ write-title-tag ] } - { "style" [ style-tag ] } - { "write-style" [ write-style-tag ] } - { "atom" [ atom-tag ] } - { "write-atom" [ write-atom-tag ] } - - ! HTML elements - { "a" [ a-tag ] } - { "button" [ button-tag ] } - - ! Components - { "label" [ label singleton-component-tag ] } - { "link" [ link singleton-component-tag ] } - { "code" [ code tuple-component-tag ] } - { "farkup" [ farkup singleton-component-tag ] } - { "inspector" [ inspector singleton-component-tag ] } - { "comparison" [ comparison singleton-component-tag ] } - { "html" [ html singleton-component-tag ] } - - ! Forms - { "form" [ form-tag ] } - { "error-message" [ error-message-tag ] } - { "validation-messages" [ validation-messages-tag ] } - { "hidden" [ hidden singleton-component-tag ] } - { "field" [ field tuple-component-tag ] } - { "password" [ password tuple-component-tag ] } - { "textarea" [ textarea tuple-component-tag ] } - { "choice" [ choice tuple-component-tag ] } - { "checkbox" [ checkbox tuple-component-tag ] } - - ! Control flow - { "if" [ if-tag ] } - { "even" [ even-tag ] } - { "odd" [ odd-tag ] } - { "each" [ each-tag ] } - { "each-assoc" [ each-assoc-tag ] } - { "each-tuple" [ each-tuple-tag ] } - { "bind-assoc" [ bind-assoc-tag ] } - { "bind-tuple" [ bind-tuple-tag ] } - { "comment" [ drop ] } - { "call-next-template" [ drop call-next-template ] } - - [ "Unknown chloe tag: " prepend throw ] - } case ; + dup name-tag dup tags get at + [ call ] [ "Unknown chloe tag: " prepend throw ] ?if ; : process-tag ( tag -- ) { - [ name-tag >lower tags get push ] + [ name-tag >lower tag-stack get push ] [ write-start-tag ] [ process-tag-children ] [ write-end-tag ] - [ drop tags get pop* ] + [ drop tag-stack get pop* ] } cleave ; +: expand-attrs ( tag -- tag ) + dup [ tag? ] is? [ + clone [ + [ "@" ?head [ value present ] when ] assoc-map + ] change-attrs + ] when ; + : process-template ( xml -- ) + expand-attrs { { [ dup [ chloe-tag? ] is? ] [ process-chloe-tag ] } { [ dup [ tag? ] is? ] [ process-tag ] } @@ -319,7 +141,7 @@ STRING: button-tag-markup : process-chloe ( xml -- ) [ - V{ } clone tags set + V{ } clone tag-stack set nested-template? get [ process-template @@ -334,6 +156,6 @@ STRING: button-tag-markup ] with-scope ; M: chloe call-template* - path>> utf8 read-xml process-chloe ; + path>> ".xml" append utf8 read-xml process-chloe ; INSTANCE: chloe template diff --git a/extra/html/templates/chloe/syntax/syntax.factor b/extra/html/templates/chloe/syntax/syntax.factor new file mode 100644 index 0000000000..7eeb756a39 --- /dev/null +++ b/extra/html/templates/chloe/syntax/syntax.factor @@ -0,0 +1,61 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +IN: html.templates.chloe.syntax +USING: accessors kernel sequences combinators kernel namespaces +classes.tuple assocs splitting words arrays memoize parser +io io.files io.encodings.utf8 io.streams.string +unicode.case tuple-syntax mirrors fry math urls +multiline xml xml.data xml.writer xml.utilities +html.elements +html.components +html.templates ; + +SYMBOL: tags + +tags global [ H{ } clone or ] change-at + +: define-chloe-tag ( name quot -- ) swap tags get set-at ; + +: CHLOE: + scan parse-definition define-chloe-tag ; parsing + +: chloe-ns "http://factorcode.org/chloe/1.0" ; inline + +MEMO: chloe-name ( string -- name ) + name new + swap >>tag + chloe-ns >>url ; + +: required-attr ( tag name -- value ) + dup chloe-name rot at* + [ nip ] [ drop " attribute is required" append throw ] if ; + +: optional-attr ( tag name -- value ) + chloe-name swap at ; + +: singleton-component-tag ( tag class -- ) + [ "name" required-attr ] dip render ; + +: CHLOE-SINGLETON: + scan-word + [ word-name ] [ '[ , singleton-component-tag ] ] bi + define-chloe-tag ; + parsing + +: attrs>slots ( tag tuple -- ) + [ attrs>> ] [ ] bi* + '[ + swap tag>> dup "name" = + [ 2drop ] [ , set-at ] if + ] assoc-each ; + +: tuple-component-tag ( tag class -- ) + [ drop "name" required-attr ] + [ new [ attrs>slots ] keep ] + 2bi render ; + +: CHLOE-TUPLE: + scan-word + [ word-name ] [ '[ , tuple-component-tag ] ] bi + define-chloe-tag ; + parsing diff --git a/extra/html/templates/chloe/test/test10.xml b/extra/html/templates/chloe/test/test10.xml index afded9366f..33fe2008a5 100644 --- a/extra/html/templates/chloe/test/test10.xml +++ b/extra/html/templates/chloe/test/test10.xml @@ -1,14 +1,3 @@ - - - - - - - - - -
- -
+ diff --git a/extra/html/templates/chloe/test/test11.xml b/extra/html/templates/chloe/test/test11.xml index 17e31b1a59..f74256bd84 100644 --- a/extra/html/templates/chloe/test/test11.xml +++ b/extra/html/templates/chloe/test/test11.xml @@ -3,12 +3,12 @@ - + - +
diff --git a/extra/html/templates/chloe/test/test12.xml b/extra/html/templates/chloe/test/test12.xml new file mode 100644 index 0000000000..b26778c96e --- /dev/null +++ b/extra/html/templates/chloe/test/test12.xml @@ -0,0 +1,3 @@ + + + diff --git a/extra/html/templates/chloe/test/test6.xml b/extra/html/templates/chloe/test/test6.xml index b3f649333f..8e2ff2e8ad 100644 --- a/extra/html/templates/chloe/test/test6.xml +++ b/extra/html/templates/chloe/test/test6.xml @@ -2,8 +2,26 @@ - - True - + + + + + + + + + + + + + + + + + + + + + Checkbox diff --git a/extra/html/templates/chloe/test/test7.xml b/extra/html/templates/chloe/test/test7.xml index 338595e556..6166c800ed 100644 --- a/extra/html/templates/chloe/test/test7.xml +++ b/extra/html/templates/chloe/test/test7.xml @@ -2,8 +2,10 @@ - - True - +
    + +
  • +
    +
diff --git a/extra/html/templates/chloe/test/test8.xml b/extra/html/templates/chloe/test/test8.xml index 8e2ff2e8ad..fd4a64ad0a 100644 --- a/extra/html/templates/chloe/test/test8.xml +++ b/extra/html/templates/chloe/test/test8.xml @@ -2,26 +2,13 @@ - - - - - - - - - - - - - - - - - - - - - Checkbox + + + + + + + +
diff --git a/extra/html/templates/chloe/test/test9.xml b/extra/html/templates/chloe/test/test9.xml index bcfc468738..a9b2769445 100644 --- a/extra/html/templates/chloe/test/test9.xml +++ b/extra/html/templates/chloe/test/test9.xml @@ -1,11 +1,3 @@ - - -
    - -
  • -
    -
- -
+Hello diff --git a/extra/html/templates/templates.factor b/extra/html/templates/templates.factor index 580af58ecc..de774f0864 100644 --- a/extra/html/templates/templates.factor +++ b/extra/html/templates/templates.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel fry io io.encodings.utf8 io.files debugger prettyprint continuations namespaces boxes sequences -arrays strings html.elements io.streams.string quotations ; +arrays strings html.elements io.streams.string +quotations xml.data xml.writer ; IN: html.templates MIXIN: template @@ -13,6 +14,8 @@ M: string call-template* write ; M: callable call-template* call ; +M: xml call-template* write-xml ; + M: object call-template* output-stream get stream-copy ; ERROR: template-error template error ; @@ -43,17 +46,17 @@ SYMBOL: style : write-style ( -- ) style get >string write ; -SYMBOL: atom-feed +SYMBOL: atom-feeds -: set-atom-feed ( title url -- ) - 2array atom-feed get >box ; +: add-atom-feed ( title url -- ) + 2array atom-feeds get push ; -: write-atom-feed ( -- ) - atom-feed get value>> [ +: write-atom-feeds ( -- ) + atom-feeds get [ - ] when* ; + ] each ; SYMBOL: nested-template? @@ -66,9 +69,9 @@ M: f call-template* drop call-next-template ; : with-boilerplate ( body template -- ) [ - title get [ title set ] unless - atom-feed get [ atom-feed set ] unless - style get [ SBUF" " clone style set ] unless + title [ or ] change + style [ SBUF" " clone or ] change + atom-feeds [ V{ } like ] change [ [ diff --git a/extra/http/client/client-tests.factor b/extra/http/client/client-tests.factor index db90f746ac..daf4ad88d3 100755 --- a/extra/http/client/client-tests.factor +++ b/extra/http/client/client-tests.factor @@ -1,5 +1,5 @@ USING: http.client http.client.private http tools.test -tuple-syntax namespaces ; +tuple-syntax namespaces urls ; [ "localhost" f ] [ "localhost" parse-host ] unit-test [ "localhost" 8888 ] [ "localhost:8888" parse-host ] unit-test @@ -10,36 +10,26 @@ tuple-syntax namespaces ; [ TUPLE{ request - protocol: http + url: TUPLE{ url protocol: "http" host: "www.apple.com" port: 80 path: "/index.html" } method: "GET" - host: "www.apple.com" - port: 80 - path: "/index.html" version: "1.1" cookies: V{ } header: H{ { "connection" "close" } { "user-agent" "Factor http.client vocabulary" } } } ] [ - [ - "http://www.apple.com/index.html" - - ] with-scope + "http://www.apple.com/index.html" + ] unit-test [ TUPLE{ request - protocol: https + url: TUPLE{ url protocol: "https" host: "www.amazon.com" port: 443 path: "/index.html" } method: "GET" - host: "www.amazon.com" - port: 443 - path: "/index.html" version: "1.1" cookies: V{ } header: H{ { "connection" "close" } { "user-agent" "Factor http.client vocabulary" } } } ] [ - [ - "https://www.amazon.com/index.html" - - ] with-scope + "https://www.amazon.com/index.html" + ] unit-test diff --git a/extra/http/client/client.factor b/extra/http/client/client.factor index 7b156a4b9b..7b48bf93af 100755 --- a/extra/http/client/client.factor +++ b/extra/http/client/client.factor @@ -4,7 +4,7 @@ USING: assocs http kernel math math.parser namespaces sequences io io.sockets io.streams.string io.files io.timeouts strings splitting calendar continuations accessors vectors math.order io.encodings.8-bit io.encodings.binary io.streams.duplex -fry debugger inspector ascii ; +fry debugger inspector ascii urls ; IN: http.client : max-redirects 10 ; @@ -21,14 +21,16 @@ DEFER: http-request SYMBOL: redirects +: redirect-url ( request url -- request ) + '[ , >url ensure-port derive-url ensure-port ] change-url ; + : do-redirect ( response data -- response data ) over code>> 300 399 between? [ drop redirects inc redirects get max-redirects < [ request get - swap "location" header dup absolute-url? - [ request-with-url ] [ request-with-path ] if + swap "location" header redirect-url "GET" >>method http-request ] [ too-many-redirects @@ -51,7 +53,7 @@ PRIVATE> : http-request ( request -- response data ) dup request [ - dup request-addr latin1 [ + dup url>> url-addr latin1 [ 1 minutes timeouts write-request read-response @@ -62,8 +64,8 @@ PRIVATE> : ( url -- request ) - swap request-with-url - "GET" >>method ; + "GET" >>method + swap >url ensure-port >>url ; : http-get* ( url -- response data ) http-request ; @@ -98,12 +100,11 @@ M: download-failed error. : download ( url -- ) dup download-name download-to ; -: ( content-type content url -- request ) +: ( post-data url -- request ) "POST" >>method - swap request-with-url - swap >>post-data - swap >>post-data-type ; + swap >url ensure-port >>url + swap >>post-data ; -: http-post ( content-type content url -- response data ) +: http-post ( post-data url -- response data ) http-request ; diff --git a/extra/http/http-tests.factor b/extra/http/http-tests.factor index 151d1ce84f..c1d5b46aa4 100755 --- a/extra/http/http-tests.factor +++ b/extra/http/http-tests.factor @@ -1,58 +1,27 @@ USING: http tools.test multiline tuple-syntax io.streams.string kernel arrays splitting sequences -assocs io.sockets db db.sqlite continuations ; +assocs io.sockets db db.sqlite continuations urls hashtables ; IN: http.tests -[ "hello%20world" ] [ "hello world" url-encode ] unit-test -[ "hello world" ] [ "hello%20world" url-decode ] unit-test -[ "~hello world" ] [ "%7ehello+world" url-decode ] unit-test -[ f ] [ "%XX%XX%XX" url-decode ] unit-test -[ f ] [ "%XX%XX%X" url-decode ] unit-test - -[ "hello world" ] [ "hello+world" url-decode ] unit-test -[ "hello world" ] [ "hello%20world" url-decode ] unit-test -[ " ! " ] [ "%20%21%20" url-decode ] unit-test -[ "hello world" ] [ "hello world%" url-decode ] unit-test -[ "hello world" ] [ "hello world%x" url-decode ] unit-test -[ "hello%20world" ] [ "hello world" url-encode ] unit-test -[ "%20%21%20" ] [ " ! " url-encode ] unit-test - -[ "\u001234hi\u002045" ] [ "\u001234hi\u002045" url-encode url-decode ] unit-test - -[ "/" ] [ "http://foo.com" url>path ] unit-test -[ "/" ] [ "http://foo.com/" url>path ] unit-test -[ "/bar" ] [ "http://foo.com/bar" url>path ] unit-test -[ "/bar" ] [ "/bar" url>path ] unit-test - -[ "a=b&a=c" ] [ { { "a" { "b" "c" } } } assoc>query ] unit-test - -[ H{ { "a" "b" } } ] [ "a=b" query>assoc ] unit-test - -[ H{ { "a" { "b" "c" } } } ] [ "a=b&a=c" query>assoc ] unit-test - -[ "a=3" ] [ { { "a" 3 } } assoc>query ] unit-test - : lf>crlf "\n" split "\r\n" join ; STRING: read-request-test-1 -GET http://foo/bar HTTP/1.1 +POST http://foo/bar HTTP/1.1 Some-Header: 1 Some-Header: 2 Content-Length: 4 +Content-type: application/octet-stream blah ; [ TUPLE{ request - protocol: http - port: 80 - method: "GET" - path: "/bar" - query: H{ } + url: TUPLE{ url protocol: "http" port: 80 path: "/bar" } + method: "POST" version: "1.1" - header: H{ { "some-header" "1; 2" } { "content-length" "4" } } - post-data: "blah" + header: H{ { "some-header" "1; 2" } { "content-length" "4" } { "content-type" "application/octet-stream" } } + post-data: TUPLE{ post-data content: "blah" raw: "blah" content-type: "application/octet-stream" } cookies: V{ } } ] [ @@ -62,8 +31,9 @@ blah ] unit-test STRING: read-request-test-1' -GET /bar HTTP/1.1 +POST /bar HTTP/1.1 content-length: 4 +content-type: application/octet-stream some-header: 1; 2 blah @@ -85,14 +55,10 @@ Host: www.sex.com [ TUPLE{ request - protocol: http - port: 80 + url: TUPLE{ url protocol: "http" port: 80 host: "www.sex.com" path: "/bar" } method: "HEAD" - path: "/bar" - query: H{ } version: "1.1" header: H{ { "host" "www.sex.com" } } - host: "www.sex.com" cookies: V{ } } ] [ @@ -101,6 +67,15 @@ Host: www.sex.com ] with-string-reader ] unit-test +STRING: read-request-test-3 +GET nested HTTP/1.0 + +; + +[ read-request-test-3 [ read-request ] with-string-reader ] +[ "Bad request: URL" = ] +must-fail-with + STRING: read-response-test-1 HTTP/1.1 404 not found Content-Type: text/html; charset=UTF8 @@ -114,7 +89,7 @@ blah code: 404 message: "not found" header: H{ { "content-type" "text/html; charset=UTF8" } } - cookies: V{ } + cookies: { } content-type: "text/html" content-charset: "UTF8" } @@ -145,14 +120,16 @@ read-response-test-1' 1array [ ] unit-test ! Live-fire exercise -USING: http.server http.server.static http.server.sessions -http.server.actions http.server.auth.login http.server.db http.client +USING: http.server http.server.static furnace.sessions +furnace.actions furnace.auth.login furnace.db http.client io.server io.files io io.encodings.ascii -accessors namespaces threads ; +accessors namespaces threads +http.server.responses http.server.redirection +http.server.dispatchers ; : add-quit-action - [ stop-server [ "Goodbye" write ] ] >>display + [ stop-server "Goodbye" "text/html" ] >>display "quit" add-responder ; : test-db "test.db" temp-file sqlite-db ; @@ -171,7 +148,7 @@ test-db [ "resource:extra/http/test" >>default "nested" add-responder - [ "redirect-loop" f ] >>display + [ URL" redirect-loop" ] >>display "redirect-loop" add-responder main-responder set @@ -186,16 +163,6 @@ test-db [ "http://localhost:1237/nested/foo.html" http-get = ] unit-test -! Try with a slightly malformed request -[ t ] [ - "localhost" 1237 ascii [ - "GET nested HTTP/1.0\r\n" write flush - "\r\n" write flush - read-crlf drop - read-header - ] with-client "location" swap at "/" head? -] unit-test - [ "http://localhost:1237/redirect-loop" http-get ] [ too-many-redirects? ] must-fail-with @@ -207,7 +174,7 @@ test-db [ [ ] [ [ - f + "" add-responder @@ -237,7 +204,7 @@ test-db [ [ ] [ [ - [ [ "Hi" write ] ] >>display + [ [ "Hi" write ] "text/plain" ] >>display "" add-responder @@ -254,3 +221,56 @@ test-db [ [ "Hi" ] [ "http://localhost:1237/" http-get ] unit-test [ "Goodbye" ] [ "http://localhost:1237/quit" http-get ] unit-test + +USING: html.components html.elements xml xml.utilities validators +furnace furnace.flash ; + +SYMBOL: a + +[ ] [ + [ + + + [ a get-global "a" set-value ] >>init + [ [ "a" render ] "text/html" ] >>display + [ { { "a" [ v-integer ] } } validate-params ] >>validate + [ "a" value a set-global URL" " ] >>submit + + + >>default + add-quit-action + test-db + main-responder set + + [ 1237 httpd ] "HTTPD test" spawn drop + ] with-scope +] unit-test + +[ ] [ 100 sleep ] unit-test + +3 a set-global + +: test-a string>xml "input" tag-named "value" swap at ; + +[ "3" ] [ + "http://localhost:1237/" http-get* + swap dup cookies>> "cookies" set session-id-key get-cookie + value>> "session-id" set test-a +] unit-test + +[ "4" ] [ + H{ { "a" "4" } { "__u" "http://localhost:1237/" } } "session-id" get session-id-key associate assoc-union + "http://localhost:1237/" "cookies" get >>cookies http-request nip test-a +] unit-test + +[ 4 ] [ a get-global ] unit-test + +! Test flash scope +[ "xyz" ] [ + H{ { "a" "xyz" } { "__u" "http://localhost:1237/" } } "session-id" get session-id-key associate assoc-union + "http://localhost:1237/" "cookies" get >>cookies http-request nip test-a +] unit-test + +[ 4 ] [ a get-global ] unit-test + +[ "Goodbye" ] [ "http://localhost:1237/quit" http-get ] unit-test diff --git a/extra/http/http.factor b/extra/http/http.factor index 89c8f62d5c..abbf79f860 100755 --- a/extra/http/http.factor +++ b/extra/http/http.factor @@ -4,92 +4,18 @@ USING: accessors kernel combinators math namespaces assocs sequences splitting sorting sets debugger strings vectors hashtables quotations arrays byte-arrays -math.parser calendar calendar.format +math.parser calendar calendar.format present -io io.streams.string io.encodings.utf8 io.encodings.string -io.sockets io.sockets.secure +io io.server io.sockets.secure unicode.case unicode.categories qualified -html.templates ; +urls html.templates xml xml.data xml.writer ; EXCLUDE: fry => , ; IN: http -SINGLETON: http - -SINGLETON: https - -GENERIC: http-port ( protocol -- port ) - -M: http http-port drop 80 ; - -M: https http-port drop 443 ; - -GENERIC: protocol>string ( protocol -- string ) - -M: http protocol>string drop "http" ; - -M: https protocol>string drop "https" ; - -: string>protocol ( string -- protocol ) - { - { "http" [ http ] } - { "https" [ https ] } - [ "Unknown protocol: " swap append throw ] - } case ; - -: absolute-url? ( url -- ? ) - [ "http://" head? ] [ "https://" head? ] bi or ; - -: url-quotable? ( ch -- ? ) - #! In a URL, can this character be used without - #! URL-encoding? - { - { [ dup letter? ] [ t ] } - { [ dup LETTER? ] [ t ] } - { [ dup digit? ] [ t ] } - { [ dup "/_-.:" member? ] [ t ] } - [ f ] - } cond nip ; foldable - -: push-utf8 ( ch -- ) - 1string utf8 encode - [ CHAR: % , >hex 2 CHAR: 0 pad-left % ] each ; - -: url-encode ( str -- str ) - [ - [ dup url-quotable? [ , ] [ push-utf8 ] if ] each - ] "" make ; - -: url-decode-hex ( index str -- ) - 2dup length 2 - >= [ - 2drop - ] [ - [ 1+ dup 2 + ] dip subseq hex> [ , ] when* - ] if ; - -: url-decode-% ( index str -- index str ) - 2dup url-decode-hex [ 3 + ] dip ; - -: url-decode-+-or-other ( index str ch -- index str ) - dup CHAR: + = [ drop CHAR: \s ] when , [ 1+ ] dip ; - -: url-decode-iter ( index str -- ) - 2dup length >= [ - 2drop - ] [ - 2dup nth dup CHAR: % = [ - drop url-decode-% - ] [ - url-decode-+-or-other - ] if url-decode-iter - ] if ; - -: url-decode ( str -- str ) - [ 0 swap url-decode-iter ] "" make utf8 decode ; - : crlf "\r\n" write ; : add-header ( value key assoc -- ) @@ -128,10 +54,9 @@ M: https protocol>string drop "https" ; : header-value>string ( value -- string ) { - { [ dup number? ] [ number>string ] } { [ dup timestamp? ] [ timestamp>http-string ] } - { [ dup string? ] [ ] } - { [ dup sequence? ] [ [ header-value>string ] map "; " join ] } + { [ dup array? ] [ [ header-value>string ] map "; " join ] } + [ present ] } cond ; : check-header-string ( str -- str ) @@ -145,42 +70,6 @@ M: https protocol>string drop "https" ; header-value>string check-header-string write crlf ] assoc-each crlf ; -: add-query-param ( value key assoc -- ) - [ - at [ - { - { [ dup string? ] [ swap 2array ] } - { [ dup array? ] [ swap suffix ] } - { [ dup not ] [ drop ] } - } cond - ] when* - ] 2keep set-at ; - -: query>assoc ( query -- assoc ) - dup [ - "&" split H{ } clone [ - [ - [ "=" split1 [ dup [ url-decode ] when ] bi@ swap ] dip - add-query-param - ] curry each - ] keep - ] when ; - -: assoc>query ( hash -- str ) - [ - { - { [ dup number? ] [ number>string 1array ] } - { [ dup string? ] [ 1array ] } - { [ dup sequence? ] [ ] } - } cond - ] assoc-map - [ - [ - [ url-encode ] dip - [ url-encode "=" swap 3append , ] with each - ] assoc-each - ] { } make "&" join ; - TUPLE: cookie name value path domain expires max-age http-only ; : ( value name -- cookie ) @@ -236,16 +125,11 @@ TUPLE: cookie name value path domain expires max-age http-only ; [ unparse-cookie ] map concat "; " join ; TUPLE: request -protocol -host -port method -path -query +url version header post-data -post-data-type cookies ; : set-header ( request/response value key -- request/response ) @@ -254,51 +138,30 @@ cookies ; : request new "1.1" >>version - http >>protocol + + "http" >>protocol + H{ } clone >>query + >>url H{ } clone >>header - H{ } clone >>query V{ } clone >>cookies "close" "connection" set-header "Factor http.client vocabulary" "user-agent" set-header ; -: query-param ( request key -- value ) - swap query>> at ; - -: set-query-param ( request value key -- request ) - pick query>> set-at ; - -: chop-hostname ( str -- str' ) - ":" split1 "//" ?head drop nip - CHAR: / over index over length or tail - dup empty? [ drop "/" ] when ; - -: url>path ( url -- path ) - #! Technically, only proxies are meant to support hostnames - #! in HTTP requests, but IE sends these sometimes so we - #! just chop the hostname part. - url-decode - dup { "http://" "https://" } [ head? ] with contains? - [ chop-hostname ] when ; - : read-method ( request -- request ) " " read-until [ "Bad request: method" throw ] unless >>method ; -: read-query ( request -- request ) - " " read-until - [ "Bad request: query params" throw ] unless - query>assoc >>query ; +: check-absolute ( url -- url ) + dup path>> "/" head? [ "Bad request: URL" throw ] unless ; inline : read-url ( request -- request ) - " ?" read-until { - { CHAR: \s [ dup empty? [ drop read-url ] [ url>path >>path ] if ] } - { CHAR: ? [ url>path >>path read-query ] } - [ "Bad request: URL" throw ] - } case ; + " " read-until [ + dup empty? [ drop read-url ] [ >url check-absolute >>url ] if + ] [ "Bad request: URL" throw ] if ; : parse-version ( string -- version ) - "HTTP/" ?head [ "Bad version" throw ] unless - dup { "1.0" "1.1" } member? [ "Bad version" throw ] unless ; + "HTTP/" ?head [ "Bad request: version" throw ] unless + dup { "1.0" "1.1" } member? [ "Bad request: version" throw ] unless ; : read-request-version ( request -- request ) read-crlf [ CHAR: \s = ] left-trim @@ -311,34 +174,33 @@ cookies ; : header ( request/response key -- value ) swap header>> at ; -SYMBOL: max-post-request +TUPLE: post-data raw content content-type ; -1024 256 * max-post-request set-global +: ( raw content-type -- post-data ) + post-data new + swap >>content-type + swap >>raw ; -: content-length ( header -- n ) - "content-length" swap at string>number dup [ - dup max-post-request get > [ - "content-length > max-post-request" throw - ] when - ] when ; +: parse-post-data ( post-data -- post-data ) + [ ] [ raw>> ] [ content-type>> ] tri { + { "application/x-www-form-urlencoded" [ query>assoc ] } + { "text/xml" [ string>xml ] } + [ drop ] + } case >>content ; : read-post-data ( request -- request ) - dup header>> content-length [ read >>post-data ] when* ; - -: parse-host ( string -- host port ) - "." ?tail drop ":" split1 - dup [ string>number ] when ; + dup method>> "POST" = [ + [ ] + [ "content-length" header string>number read ] + [ "content-type" header ] tri + parse-post-data >>post-data + ] when ; : extract-host ( request -- request ) - dup [ "host" header parse-host ] keep protocol>> http-port or - [ >>host ] [ >>port ] bi* ; - -: extract-post-data-type ( request -- request ) - dup "content-type" header >>post-data-type ; - -: parse-post-data ( request -- request ) - dup post-data-type>> "application/x-www-form-urlencoded" = - [ dup post-data>> query>assoc >>post-data ] when ; + [ ] [ url>> ] [ "host" header parse-host ] tri + [ >>host ] [ >>port ] bi* + ensure-port + drop ; : extract-cookies ( request -- request ) dup "cookie" header [ parse-cookies >>cookies ] when* ; @@ -349,6 +211,9 @@ SYMBOL: max-post-request : parse-content-type ( content-type -- type encoding ) ";" split1 parse-content-type-attributes "charset" swap at ; +: detect-protocol ( request -- request ) + dup url>> remote-address get secure? "https" "http" ? >>protocol drop ; + : read-request ( -- request ) read-method @@ -356,58 +221,53 @@ SYMBOL: max-post-request read-request-version read-request-header read-post-data + detect-protocol extract-host - extract-post-data-type - parse-post-data extract-cookies ; : write-method ( request -- request ) dup method>> write bl ; -: (link>string) ( url query -- url' ) - [ url-encode ] [ assoc>query ] bi* - dup empty? [ drop ] [ "?" swap 3append ] if ; - -: write-url ( request -- ) - [ path>> ] [ query>> ] bi (link>string) write ; - : write-request-url ( request -- request ) - dup write-url bl ; + dup url>> relative-url present write bl ; : write-version ( request -- request ) "HTTP/" write dup request-version write crlf ; -: unparse-post-data ( request -- request ) - dup post-data>> dup sequence? [ drop ] [ - assoc>query >>post-data - "application/x-www-form-urlencoded" >>post-data-type - ] if ; - -GENERIC: protocol-addr ( request protocol -- addr ) - -M: object protocol-addr - drop [ host>> ] [ port>> ] bi ; - -M: https protocol-addr - call-next-method ; - -: request-addr ( request -- addr ) - dup protocol>> protocol-addr ; - -: request-host ( request -- string ) - [ host>> ] [ port>> ] bi dup http http-port = +: url-host ( url -- string ) + [ host>> ] [ port>> ] bi dup "http" protocol-port = [ drop ] [ ":" swap number>string 3append ] if ; : write-request-header ( request -- request ) dup header>> >hashtable - over host>> [ over request-host "host" pick set-at ] when - over post-data>> [ length "content-length" pick set-at ] when* - over post-data-type>> [ "content-type" pick set-at ] when* + over url>> host>> [ over url>> url-host "host" pick set-at ] when + over post-data>> [ + [ raw>> length "content-length" pick set-at ] + [ content-type>> "content-type" pick set-at ] + bi + ] when* over cookies>> f like [ unparse-cookies "cookie" pick set-at ] when* write-header ; +GENERIC: >post-data ( object -- post-data ) + +M: post-data >post-data ; + +M: string >post-data "application/octet-stream" ; + +M: byte-array >post-data "application/octet-stream" ; + +M: xml >post-data xml>string "text/xml" ; + +M: assoc >post-data assoc>query "application/x-www-form-urlencoded" ; + +M: f >post-data ; + +: unparse-post-data ( request -- request ) + [ >post-data ] change-post-data ; + : write-post-data ( request -- request ) - dup post-data>> [ write ] when* ; + dup method>> "POST" = [ dup post-data>> raw>> write ] when ; : write-request ( request -- ) unparse-post-data @@ -419,39 +279,6 @@ M: https protocol-addr flush drop ; -: request-with-path ( request path -- request ) - [ "/" prepend ] [ "/" ] if* - "?" split1 [ >>path ] [ dup [ query>assoc ] when >>query ] bi* ; - -: request-with-url ( request url -- request ) - ":" split1 - [ string>protocol >>protocol ] - [ - "//" ?head [ "Invalid URL" throw ] unless - "/" split1 - [ - parse-host [ >>host ] [ >>port ] bi* - dup protocol>> http-port '[ , or ] change-port - ] - [ request-with-path ] - bi* - ] bi* ; - -: request-url ( request -- url ) - [ - [ - dup host>> [ - [ protocol>> protocol>string write "://" write ] - [ host>> url-encode write ":" write ] - [ [ port>> ] [ protocol>> http-port or ] bi number>string write ] - tri - ] [ drop ] if - ] - [ path>> "/" head? [ "/" write ] unless ] - [ write-url ] - tri - ] with-string-writer ; - GENERIC: write-response ( response -- ) GENERIC: write-full-response ( request response -- ) @@ -490,7 +317,7 @@ body ; : read-response-header read-header >>header - extract-cookies + dup "set-cookie" header parse-cookies >>cookies dup "content-type" header [ parse-content-type [ >>content-type ] [ >>content-charset ] bi* ] when* ; @@ -556,7 +383,7 @@ body ; : ( -- response ) raw-response new - "1.1" >>version ; + "1.1" >>version ; M: raw-response write-response ( respose -- ) write-response-version diff --git a/extra/http/mime/mime.factor b/extra/http/mime/mime.factor deleted file mode 100755 index f9097ecce3..0000000000 --- a/extra/http/mime/mime.factor +++ /dev/null @@ -1,35 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: io assocs kernel sequences math namespaces splitting ; - -IN: http.mime - -: file-extension ( filename -- extension ) - "." split dup length 1 <= [ drop f ] [ peek ] if ; - -: mime-type ( filename -- mime-type ) - file-extension "mime-types" get at "application/octet-stream" or ; - -H{ - { "html" "text/html" } - { "txt" "text/plain" } - { "xml" "text/xml" } - { "css" "text/css" } - - { "gif" "image/gif" } - { "png" "image/png" } - { "jpg" "image/jpeg" } - { "jpeg" "image/jpeg" } - - { "jar" "application/octet-stream" } - { "zip" "application/octet-stream" } - { "tgz" "application/octet-stream" } - { "tar.gz" "application/octet-stream" } - { "gz" "application/octet-stream" } - - { "pdf" "application/pdf" } - - { "factor" "text/plain" } - { "cgi" "application/x-cgi-script" } - { "fhtml" "application/x-factor-server-page" } -} "mime-types" set-global diff --git a/extra/http/server/actions/actions.factor b/extra/http/server/actions/actions.factor deleted file mode 100755 index eb5b8bfe68..0000000000 --- a/extra/http/server/actions/actions.factor +++ /dev/null @@ -1,94 +0,0 @@ -! Copyright (C) 2008 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors sequences kernel assocs combinators http.server -validators http hashtables namespaces fry continuations locals -boxes xml.entities html.elements html.components io arrays math ; -IN: http.server.actions - -SYMBOL: params - -SYMBOL: rest-param - -: render-validation-messages ( -- ) - validation-messages get - dup empty? [ drop ] [ -
    - [
  • message>> escape-string write
  • ] each -
- ] if ; - -TUPLE: action rest-param init display validate submit ; - -: new-action ( class -- action ) - new - [ ] >>init - [ <400> ] >>display - [ ] >>validate - [ <400> ] >>submit ; - -: ( -- action ) - action new-action ; - -: handle-get ( action -- response ) - blank-values - [ init>> call ] - [ display>> call ] - bi ; - -: validation-failed ( -- * ) - request get method>> "POST" = - [ action get display>> call ] [ <400> ] if exit-with ; - -: handle-post ( action -- response ) - init-validation - blank-values - [ validate>> call ] - [ submit>> call ] bi ; - -: handle-rest-param ( arg -- ) - dup length 1 > action get rest-param>> not or - [ <404> exit-with ] [ - action get rest-param>> associate rest-param set - ] if ; - -M: action call-responder* ( path action -- response ) - dup action set - '[ - , dup empty? [ drop ] [ handle-rest-param ] if - - init-validation - , - request get - [ request-params rest-param get assoc-union params set ] - [ method>> ] bi - { - { "GET" [ handle-get ] } - { "HEAD" [ handle-get ] } - { "POST" [ handle-post ] } - } case - ] with-exit-continuation ; - -: param ( name -- value ) - params get at ; - -: check-validation ( -- ) - validation-failed? [ validation-failed ] when ; - -: validate-params ( validators -- ) - params get swap validate-values from-assoc - check-validation ; - -: validate-integer-id ( -- ) - { { "id" [ v-number ] } } validate-params ; - -TUPLE: page-action < action template ; - -: ( -- page ) - page-action new-action - dup '[ , template>> ] >>display ; - -TUPLE: feed-action < action feed ; - -: ( -- feed ) - feed-action new - dup '[ , feed>> call ] >>display ; diff --git a/extra/http/server/cgi/cgi.factor b/extra/http/server/cgi/cgi.factor index 20eb7318d0..a6d8948790 100755 --- a/extra/http/server/cgi/cgi.factor +++ b/extra/http/server/cgi/cgi.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: namespaces kernel assocs io.files io.streams.duplex combinators arrays io.launcher io http.server.static http.server -http accessors sequences strings math.parser fry ; +http accessors sequences strings math.parser fry urls ; IN: http.server.cgi : post? request get method>> "POST" = ; @@ -14,13 +14,12 @@ IN: http.server.cgi "HTTP/" request get version>> append "SERVER_PROTOCOL" set "Factor" "SERVER_SOFTWARE" set - dup "PATH_TRANSLATED" set - "SCRIPT_FILENAME" set + [ "PATH_TRANSLATED" set ] [ "SCRIPT_FILENAME" set ] bi - request get path>> "SCRIPT_NAME" set + request get url>> path>> "SCRIPT_NAME" set - request get host>> "SERVER_NAME" set - request get port>> number>string "SERVER_PORT" set + request get url>> host>> "SERVER_NAME" set + request get url>> port>> number>string "SERVER_PORT" set "" "PATH_INFO" set "" "REMOTE_HOST" set "" "REMOTE_ADDR" set @@ -29,15 +28,17 @@ IN: http.server.cgi "" "REMOTE_IDENT" set request get method>> "REQUEST_METHOD" set - request get query>> assoc>query "QUERY_STRING" set + request get url>> query>> assoc>query "QUERY_STRING" set request get "cookie" header "HTTP_COOKIE" set request get "user-agent" header "HTTP_USER_AGENT" set request get "accept" header "HTTP_ACCEPT" set post? [ - request get post-data-type>> "CONTENT_TYPE" set - request get post-data>> length number>string "CONTENT_LENGTH" set + request get post-data>> raw>> + [ "CONTENT_TYPE" set ] + [ length number>string "CONTENT_LENGTH" set ] + bi ] when ] H{ } make-assoc ; @@ -52,7 +53,7 @@ IN: http.server.cgi "CGI output follows" >>message swap '[ , output-stream get swap [ - post? [ request get post-data>> write flush ] when + post? [ request get post-data>> raw>> write flush ] when input-stream get swap (stream-copy) ] with-stream ] >>body ; diff --git a/extra/http/server/db/db-tests.factor b/extra/http/server/db/db-tests.factor deleted file mode 100644 index 0c34745c00..0000000000 --- a/extra/http/server/db/db-tests.factor +++ /dev/null @@ -1,4 +0,0 @@ -IN: http.server.db.tests -USING: tools.test http.server.db ; - -\ must-infer diff --git a/extra/http/server/dispatchers/dispatchers-tests.factor b/extra/http/server/dispatchers/dispatchers-tests.factor new file mode 100644 index 0000000000..5b5b30adde --- /dev/null +++ b/extra/http/server/dispatchers/dispatchers-tests.factor @@ -0,0 +1,97 @@ +USING: http.server http.server.dispatchers http.server.responses +tools.test kernel namespaces accessors io http math sequences +assocs arrays classes words urls ; +IN: http.server.dispatchers.tests + +\ find-responder must-infer +\ http-error. must-infer + +TUPLE: mock-responder path ; + +C: mock-responder + +M: mock-responder call-responder* + nip + path>> on + [ ] "text/plain" ; + +: check-dispatch ( tag path -- ? ) + V{ } clone responder-nesting set + over off + split-path + main-responder get call-responder + write-response get ; + +[ + + "foo" "foo" add-responder + "bar" "bar" add-responder + + "123" "123" add-responder + "default" >>default + "baz" add-responder + main-responder set + + [ "foo" ] [ + { "foo" } main-responder get find-responder path>> nip + ] unit-test + + [ "bar" ] [ + { "bar" } main-responder get find-responder path>> nip + ] unit-test + + [ t ] [ "foo" "foo" check-dispatch ] unit-test + [ f ] [ "foo" "bar" check-dispatch ] unit-test + [ t ] [ "bar" "bar" check-dispatch ] unit-test + [ t ] [ "default" "baz/xxx" check-dispatch ] unit-test + [ t ] [ "default" "baz/xxx//" check-dispatch ] unit-test + [ t ] [ "default" "/baz/xxx//" check-dispatch ] unit-test + [ t ] [ "123" "baz/123" check-dispatch ] unit-test + [ t ] [ "123" "baz///123" check-dispatch ] unit-test + +] with-scope + +[ + + "default" >>default + main-responder set + + [ "/default" ] [ "/default" main-responder get find-responder drop ] unit-test +] with-scope + +! Make sure path for default responder isn't chopped +TUPLE: path-check-responder ; + +C: path-check-responder + +M: path-check-responder call-responder* + drop + >array "text/plain" ; + +[ { "c" } ] [ + V{ } clone responder-nesting set + + { "b" "c" } + + + >>default + "b" add-responder + call-responder + body>> +] unit-test + +! Test that "" dispatcher works with default>> +[ ] [ + + "" "" add-responder + "bar" "bar" add-responder + "baz" >>default + main-responder set + + [ t ] [ "" "" check-dispatch ] unit-test + [ f ] [ "" "quux" check-dispatch ] unit-test + [ t ] [ "baz" "quux" check-dispatch ] unit-test + [ f ] [ "foo" "bar" check-dispatch ] unit-test + [ t ] [ "bar" "bar" check-dispatch ] unit-test + [ t ] [ "baz" "xxx" check-dispatch ] unit-test +] unit-test diff --git a/extra/http/server/dispatchers/dispatchers.factor b/extra/http/server/dispatchers/dispatchers.factor new file mode 100644 index 0000000000..2da2695992 --- /dev/null +++ b/extra/http/server/dispatchers/dispatchers.factor @@ -0,0 +1,50 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: kernel namespaces sequences assocs accessors splitting +unicode.case http http.server http.server.responses ; +IN: http.server.dispatchers + +TUPLE: dispatcher default responders ; + +: new-dispatcher ( class -- dispatcher ) + new + <404> >>default + H{ } clone >>responders ; inline + +: ( -- dispatcher ) + dispatcher new-dispatcher ; + +: find-responder ( path dispatcher -- path responder ) + over empty? [ + "" over responders>> at* + [ nip ] [ drop default>> ] if + ] [ + over first over responders>> at* + [ [ drop rest-slice ] dip ] [ drop default>> ] if + ] if ; + +M: dispatcher call-responder* ( path dispatcher -- response ) + find-responder call-responder ; + +TUPLE: vhost-dispatcher default responders ; + +: ( -- dispatcher ) + vhost-dispatcher new-dispatcher ; + +: canonical-host ( host -- host' ) + >lower "www." ?head drop "." ?tail drop ; + +: find-vhost ( dispatcher -- responder ) + request get url>> host>> canonical-host over responders>> at* + [ nip ] [ drop default>> ] if ; + +M: vhost-dispatcher call-responder* ( path dispatcher -- response ) + find-vhost call-responder ; + +: add-responder ( dispatcher responder path -- dispatcher ) + pick responders>> set-at ; + +: add-main-responder ( dispatcher responder path -- dispatcher ) + [ add-responder drop ] + [ drop "" add-responder drop ] + [ 2drop ] 3tri ; diff --git a/extra/http/server/filters/filters.factor b/extra/http/server/filters/filters.factor new file mode 100644 index 0000000000..4f70113292 --- /dev/null +++ b/extra/http/server/filters/filters.factor @@ -0,0 +1,9 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: http.server accessors ; +IN: http.server.filters + +TUPLE: filter-responder responder ; + +M: filter-responder call-responder* + responder>> call-responder ; diff --git a/extra/http/server/flows/flows.factor b/extra/http/server/flows/flows.factor deleted file mode 100644 index 7a9b362111..0000000000 --- a/extra/http/server/flows/flows.factor +++ /dev/null @@ -1,64 +0,0 @@ -! Copyright (C) 2008 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors namespaces sequences arrays kernel -assocs assocs.lib hashtables math.parser -html.elements http http.server http.server.sessions ; -IN: http.server.flows - -TUPLE: flows < filter-responder ; - -C: flows - -: begin-flow* ( -- id ) - request get - [ path>> ] [ request-params ] [ method>> ] tri 3array - flows sget set-at-unique - session-changed ; - -: end-flow-post ( path params -- response ) - request [ - clone - "POST" >>method - swap >>post-data - swap >>path - ] change - request get path>> split-path - flows get responder>> call-responder ; - -: end-flow* ( default id -- response ) - flows sget at - [ first3 "POST" = [ end-flow-post ] [ ] if ] - [ f ] ?if ; - -SYMBOL: flow-id - -: flow-id-key "factorflowid" ; - -: begin-flow ( -- ) - begin-flow* flow-id set ; - -: end-flow ( default -- response ) - flow-id get end-flow* ; - -: add-flow-id ( query -- query' ) - flow-id get [ flow-id-key associate assoc-union ] when* ; - -: flow-form-field ( -- ) - flow-id get [ - - ] when* ; - -M: flows call-responder* - dup flows set - [ add-flow-id ] add-link-hook - [ flow-form-field ] add-form-hook - flow-id-key request get request-params at flow-id set - call-next-method ; - -M: flows init-session* - H{ } clone flows sset - call-next-method ; diff --git a/extra/http/server/redirection/redirection-tests.factor b/extra/http/server/redirection/redirection-tests.factor new file mode 100644 index 0000000000..04af89ec98 --- /dev/null +++ b/extra/http/server/redirection/redirection-tests.factor @@ -0,0 +1,48 @@ +IN: http.server.redirection.tests +USING: http http.server.redirection urls accessors +namespaces tools.test present ; + +\ relative-to-request must-infer + +[ + + + "http" >>protocol + "www.apple.com" >>host + "/xxx/bar" >>path + { { "a" "b" } } >>query + >>url + request set + + [ "http://www.apple.com:80/xxx/bar" ] [ + relative-to-request present + ] unit-test + + [ "http://www.apple.com:80/xxx/baz" ] [ + "baz" >>path relative-to-request present + ] unit-test + + [ "http://www.apple.com:80/xxx/baz?c=d" ] [ + "baz" >>path { { "c" "d" } } >>query relative-to-request present + ] unit-test + + [ "http://www.apple.com:80/xxx/bar?c=d" ] [ + { { "c" "d" } } >>query relative-to-request present + ] unit-test + + [ "http://www.apple.com:80/flip" ] [ + "/flip" >>path relative-to-request present + ] unit-test + + [ "http://www.apple.com:80/flip?c=d" ] [ + "/flip" >>path { { "c" "d" } } >>query relative-to-request present + ] unit-test + + [ "http://www.jedit.org:80/" ] [ + "http://www.jedit.org" >url relative-to-request present + ] unit-test + + [ "http://www.jedit.org:80/?a=b" ] [ + "http://www.jedit.org" >url { { "a" "b" } } >>query relative-to-request present + ] unit-test +] with-scope diff --git a/extra/http/server/redirection/redirection.factor b/extra/http/server/redirection/redirection.factor new file mode 100644 index 0000000000..3cd01345aa --- /dev/null +++ b/extra/http/server/redirection/redirection.factor @@ -0,0 +1,24 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: kernel accessors combinators namespaces +logging urls http http.server http.server.responses ; +IN: http.server.redirection + +: relative-to-request ( url -- url' ) + request get url>> + clone + f >>query + swap derive-url ensure-port ; + +: ( url code message -- response ) + + swap dup url? [ relative-to-request ] when + "location" set-header ; + +\ DEBUG add-input-logging + +: ( url -- response ) + 301 "Moved Permanently" ; + +: ( url -- response ) + 307 "Temporary Redirect" ; diff --git a/extra/http/server/responses/responses.factor b/extra/http/server/responses/responses.factor new file mode 100644 index 0000000000..277ca392b7 --- /dev/null +++ b/extra/http/server/responses/responses.factor @@ -0,0 +1,37 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: html.elements math.parser http accessors kernel +io io.streams.string ; +IN: http.server.responses + +: ( body content-type -- response ) + + 200 >>code + "Document follows" >>message + swap >>content-type + swap >>body ; + +: trivial-response-body ( code message -- ) + + +

[ number>string write bl ] [ write ] bi*

+ + ; + +: ( code message -- response ) + 2dup [ trivial-response-body ] with-string-writer + "text/html" + swap >>message + swap >>code ; + +: <304> ( -- response ) + 304 "Not modified" ; + +: <403> ( -- response ) + 403 "Forbidden" ; + +: <400> ( -- response ) + 400 "Bad request" ; + +: <404> ( -- response ) + 404 "Not found" ; diff --git a/extra/http/server/server-tests.factor b/extra/http/server/server-tests.factor old mode 100755 new mode 100644 index 0aed425ade..c29912b8c7 --- a/extra/http/server/server-tests.factor +++ b/extra/http/server/server-tests.factor @@ -1,142 +1,4 @@ -USING: http.server tools.test kernel namespaces accessors -io http math sequences assocs arrays classes words ; +USING: http http.server math sequences continuations tools.test ; IN: http.server.tests -\ find-responder must-infer - -[ - - http >>protocol - "www.apple.com" >>host - "/xxx/bar" >>path - { { "a" "b" } } >>query - request set - - [ ] link-hook set - - [ "http://www.apple.com:80/xxx/bar?a=b" ] [ f f derive-url ] unit-test - [ "http://www.apple.com:80/xxx/baz?a=b" ] [ "baz" f derive-url ] unit-test - [ "http://www.apple.com:80/xxx/baz?c=d" ] [ "baz" { { "c" "d" } } derive-url ] unit-test - [ "http://www.apple.com:80/xxx/bar?c=d" ] [ f { { "c" "d" } } derive-url ] unit-test - [ "http://www.apple.com:80/flip?a=b" ] [ "/flip" f derive-url ] unit-test - [ "http://www.apple.com:80/flip?c=d" ] [ "/flip" { { "c" "d" } } derive-url ] unit-test - [ "http://www.jedit.org" ] [ "http://www.jedit.org" f derive-url ] unit-test - [ "http://www.jedit.org?a=b" ] [ "http://www.jedit.org" { { "a" "b" } } derive-url ] unit-test -] with-scope - -TUPLE: mock-responder path ; - -C: mock-responder - -M: mock-responder call-responder* - nip - path>> on - [ ] ; - -: check-dispatch ( tag path -- ? ) - H{ } clone base-paths set - over off - split-path - main-responder get call-responder - write-response get ; - -[ - - "foo" "foo" add-responder - "bar" "bar" add-responder - - "123" "123" add-responder - "default" >>default - "baz" add-responder - main-responder set - - [ "foo" ] [ - { "foo" } main-responder get find-responder path>> nip - ] unit-test - - [ "bar" ] [ - { "bar" } main-responder get find-responder path>> nip - ] unit-test - - [ t ] [ "foo" "foo" check-dispatch ] unit-test - [ f ] [ "foo" "bar" check-dispatch ] unit-test - [ t ] [ "bar" "bar" check-dispatch ] unit-test - [ t ] [ "default" "baz/xxx" check-dispatch ] unit-test - [ t ] [ "default" "baz/xxx//" check-dispatch ] unit-test - [ t ] [ "default" "/baz/xxx//" check-dispatch ] unit-test - [ t ] [ "123" "baz/123" check-dispatch ] unit-test - [ t ] [ "123" "baz///123" check-dispatch ] unit-test - -] with-scope - -[ - - "default" >>default - main-responder set - - [ "/default" ] [ "/default" main-responder get find-responder drop ] unit-test -] with-scope - -! Make sure path for default responder isn't chopped -TUPLE: path-check-responder ; - -C: path-check-responder - -M: path-check-responder call-responder* - drop - >array ; - -[ { "c" } ] [ - H{ } clone base-paths set - - { "b" "c" } - - - >>default - "b" add-responder - call-responder - body>> -] unit-test - -! Test that "" dispatcher works with default>> -[ ] [ - - "" "" add-responder - "bar" "bar" add-responder - "baz" >>default - main-responder set - - [ t ] [ "" "" check-dispatch ] unit-test - [ f ] [ "" "quux" check-dispatch ] unit-test - [ t ] [ "baz" "quux" check-dispatch ] unit-test - [ f ] [ "foo" "bar" check-dispatch ] unit-test - [ t ] [ "bar" "bar" check-dispatch ] unit-test - [ t ] [ "baz" "xxx" check-dispatch ] unit-test -] unit-test - -TUPLE: funny-dispatcher < dispatcher ; - -: funny-dispatcher new-dispatcher ; - -TUPLE: base-path-check-responder ; - -C: base-path-check-responder - -M: base-path-check-responder call-responder* - 2drop - "$funny-dispatcher" resolve-base-path - ; - -[ ] [ - - - - "c" add-responder - "b" add-responder - "a" add-responder - main-responder set -] unit-test - -[ "/a/b/" ] [ - "a/b/c" split-path main-responder get call-responder body>> -] unit-test +[ t ] [ [ \ + first ] [ <500> ] recover response? ] unit-test diff --git a/extra/http/server/server.factor b/extra/http/server/server.factor index d68c66b829..10d6070f7b 100755 --- a/extra/http/server/server.factor +++ b/extra/http/server/server.factor @@ -1,276 +1,74 @@ ! Copyright (C) 2003, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: assocs kernel namespaces io io.timeouts strings splitting -threads sequences prettyprint io.server logging calendar http -html.streams html.elements accessors math.parser -combinators.lib tools.vocabs debugger continuations random -combinators destructors io.encodings.8-bit fry classes words -math rss json.writer ; +USING: kernel accessors sequences arrays namespaces splitting +vocabs.loader http http.server.responses logging calendar +destructors html.elements html.streams io.server +io.encodings.8-bit io.timeouts io assocs debugger continuations +fry tools.vocabs math ; IN: http.server +SYMBOL: responder-nesting + +SYMBOL: main-responder + +SYMBOL: development-mode + ! path is a sequence of path component strings - GENERIC: call-responder* ( path responder -- response ) -: request-params ( request -- assoc ) - dup method>> { - { "GET" [ query>> ] } - { "HEAD" [ query>> ] } - { "POST" [ post-data>> ] } - } case ; - -: ( body content-type -- response ) - - 200 >>code - "Document follows" >>message - swap >>content-type - swap >>body ; - -: ( body -- response ) - "text/plain" ; - -: ( body -- response ) - "text/html" ; - -: ( body -- response ) - "text/xml" ; - -: ( feed -- response ) - '[ , feed>xml ] "text/xml" ; - -: ( obj -- response ) - '[ , >json ] "application/json" ; - TUPLE: trivial-responder response ; C: trivial-responder -M: trivial-responder call-responder* nip response>> call ; +M: trivial-responder call-responder* nip response>> clone ; -: trivial-response-body ( code message -- ) - - -

[ number>string write bl ] [ write ] bi*

- - ; - -: ( code message -- response ) - 2dup '[ , , trivial-response-body ] - swap >>message - swap >>code ; - -: <400> ( -- response ) - 400 "Bad request" ; - -: <404> ( -- response ) - 404 "Not Found" ; - -SYMBOL: 404-responder - -[ <404> ] 404-responder set-global - -SYMBOL: base-paths +main-responder global [ <404> or ] change-at : invert-slice ( slice -- slice' ) - dup slice? [ - [ seq>> ] [ from>> ] bi head-slice - ] [ - drop { } - ] if ; + dup slice? [ [ seq>> ] [ from>> ] bi head-slice ] [ drop { } ] if ; -: add-base-path ( path dispatcher -- ) - [ invert-slice ] [ class word-name ] bi* - base-paths get set-at ; +: add-responder-nesting ( path responder -- ) + [ invert-slice ] dip 2array responder-nesting get push ; : call-responder ( path responder -- response ) - [ add-base-path ] [ call-responder* ] 2bi ; - -SYMBOL: link-hook - -: add-link-hook ( quot -- ) - link-hook [ compose ] change ; inline - -: modify-query ( query -- query ) - link-hook get call ; - -: base-path ( string -- path ) - dup base-paths get at - [ ] [ "No such responder: " swap append throw ] ?if ; - -: resolve-base-path ( string -- string' ) - "$" ?head [ - [ - "/" split1 [ base-path [ "/" % % ] each "/" % ] dip % - ] "" make - ] when ; - -: link>string ( url query -- url' ) - [ resolve-base-path ] [ modify-query ] bi* (link>string) ; - -: write-link ( url query -- ) - link>string write ; - -SYMBOL: form-hook - -: add-form-hook ( quot -- ) - form-hook [ compose ] change ; - -: hidden-form-field ( -- ) - form-hook get call ; - -: absolute-redirect ( to query -- url ) - #! Same host. - request get clone - swap [ >>query ] when* - swap url-encode >>path - [ modify-query ] change-query - request-url ; - -: replace-last-component ( path with -- path' ) - [ "/" last-split1 drop "/" ] dip 3append ; - -: relative-redirect ( to query -- url ) - request get clone - swap [ >>query ] when* - swap [ '[ , replace-last-component ] change-path ] when* - [ modify-query ] change-query - request-url ; - -: derive-url ( to query -- url ) - { - { [ over "http://" head? ] [ link>string ] } - { [ over "/" head? ] [ absolute-redirect ] } - { [ over "$" head? ] [ [ resolve-base-path ] dip derive-url ] } - [ relative-redirect ] - } cond ; - -: ( to query code message -- response ) - -rot derive-url "location" set-header ; - -\ DEBUG add-input-logging - -: ( to query -- response ) - 301 "Moved Permanently" ; - -: ( to query -- response ) - 307 "Temporary Redirect" ; - -: ( to query -- response ) - request get method>> "POST" = - [ ] [ ] if ; - -TUPLE: dispatcher default responders ; - -: new-dispatcher ( class -- dispatcher ) - new - 404-responder get >>default - H{ } clone >>responders ; inline - -: ( -- dispatcher ) - dispatcher new-dispatcher ; - -: find-responder ( path dispatcher -- path responder ) - over empty? [ - "" over responders>> at* - [ nip ] [ drop default>> ] if - ] [ - over first over responders>> at* - [ [ drop rest-slice ] dip ] [ drop default>> ] if - ] if ; - -M: dispatcher call-responder* ( path dispatcher -- response ) - find-responder call-responder ; - -TUPLE: vhost-dispatcher default responders ; - -: ( -- dispatcher ) - 404-responder get H{ } clone vhost-dispatcher boa ; - -: find-vhost ( dispatcher -- responder ) - request get host>> over responders>> at* - [ nip ] [ drop default>> ] if ; - -M: vhost-dispatcher call-responder* ( path dispatcher -- response ) - find-vhost call-responder ; - -: add-responder ( dispatcher responder path -- dispatcher ) - pick responders>> set-at ; - -: add-main-responder ( dispatcher responder path -- dispatcher ) - [ add-responder drop ] - [ drop "" add-responder drop ] - [ 2drop ] 3tri ; - -TUPLE: filter-responder responder ; - -M: filter-responder call-responder* - responder>> call-responder ; - -SYMBOL: main-responder - -main-responder global -[ drop 404-responder get-global ] cache -drop - -SYMBOL: development-mode + [ add-responder-nesting ] [ call-responder* ] 2bi ; : http-error. ( error -- ) "Internal server error" [ - development-mode get [ - [ print-error nl :c ] with-html-stream - ] [ - 500 "Internal server error" - trivial-response-body - ] if + [ print-error nl :c ] with-html-stream ] simple-page ; : <500> ( error -- response ) 500 "Internal server error" - swap '[ , http-error. ] >>body ; + swap development-mode get [ '[ , http-error. ] >>body ] [ drop ] if ; : do-response ( response -- ) dup write-response request get method>> "HEAD" = - [ drop ] [ - '[ - , write-response-body - ] [ - http-error. - ] recover - ] if ; + [ drop ] [ '[ , write-response-body ] [ http-error. ] recover ] if ; LOG: httpd-hit NOTICE : log-request ( request -- ) - { method>> host>> path>> } map-exec-with httpd-hit ; - -SYMBOL: exit-continuation - -: exit-with exit-continuation get continue-with ; - -: with-exit-continuation ( quot -- ) - '[ exit-continuation set @ ] callcc1 exit-continuation off ; + [ method>> ] [ url>> [ host>> ] [ path>> ] bi ] bi 3array httpd-hit ; : split-path ( string -- path ) "/" split harvest ; -: init-request ( -- ) - H{ } clone base-paths set - [ ] link-hook set - [ ] form-hook set ; +: init-request ( request -- ) + request set + V{ } clone responder-nesting set ; + +: dispatch-request ( request -- response ) + url>> path>> split-path main-responder get call-responder ; : do-request ( request -- response ) - [ - init-request - [ request set ] + '[ + , + [ init-request ] [ log-request ] - [ path>> split-path main-responder get call-responder ] tri - [ <404> ] unless* - ] [ - [ \ do-request log-error ] - [ <500> ] - bi - ] recover ; + [ dispatch-request ] tri + ] [ [ \ do-request log-error ] [ <500> ] bi ] recover ; : ?refresh-all ( -- ) development-mode get-global @@ -287,8 +85,7 @@ SYMBOL: exit-continuation : httpd ( port -- ) dup integer? [ internet-server ] when - "http.server" latin1 - [ handle-client ] with-server ; + "http.server" latin1 [ handle-client ] with-server ; : httpd-main ( -- ) 8888 httpd ; diff --git a/extra/http/server/static/static.factor b/extra/http/server/static/static.factor index 8814004589..1d86a73cfa 100755 --- a/extra/http/server/static/static.factor +++ b/extra/http/server/static/static.factor @@ -1,10 +1,15 @@ ! Copyright (C) 2004, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: calendar io io.files kernel math math.order -math.parser http http.server namespaces parser sequences strings -assocs hashtables debugger http.mime sorting html.elements -html.templates.fhtml logging calendar.format accessors -io.encodings.binary fry xml.entities destructors ; +math.parser namespaces parser sequences strings +assocs hashtables debugger mime-types sorting logging +calendar.format accessors +io.encodings.binary fry xml.entities destructors urls +html.elements html.templates.fhtml +http +http.server +http.server.responses +http.server.redirection ; IN: http.server.static ! special maps mime types to quots with effect ( path -- ) @@ -17,12 +22,6 @@ TUPLE: file-responder root hook special allow-listings ; 2drop t ] if ; -: <304> ( -- response ) - 304 "Not modified" ; - -: <403> ( -- response ) - 403 "Forbidden" ; - : ( root hook -- responder ) file-responder new swap >>hook @@ -71,7 +70,7 @@ TUPLE: file-responder root hook special allow-listings ; : list-directory ( directory -- response ) file-responder get allow-listings>> [ - '[ , directory. ] + '[ , directory. ] "text/html" ] [ drop <403> ] if ; @@ -85,7 +84,7 @@ TUPLE: file-responder root hook special allow-listings ; find-index [ serve-file ] [ list-directory ] ?if ] [ drop - request get path>> "/" append f + request get url>> clone [ "/" append ] change-path ] if ; : serve-object ( filename -- response ) @@ -101,6 +100,6 @@ M: file-responder call-responder* ( path responder -- response ) ! file responder integration : enable-fhtml ( responder -- responder ) - [ ] + [ "text/html" ] "application/x-factor-server-page" pick special>> set-at ; diff --git a/extra/io/pools/pools.factor b/extra/io/pools/pools.factor index 7ee14e03e5..033ba3cbfb 100644 --- a/extra/io/pools/pools.factor +++ b/extra/io/pools/pools.factor @@ -1,13 +1,22 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel arrays namespaces sequences continuations -destructors io.sockets ; +destructors io.sockets alien alien.syntax ; IN: io.pools -TUPLE: pool connections disposed ; +TUPLE: pool connections disposed expired ; + +: check-pool ( pool -- ) + dup check-disposed + dup expired>> expired? [ + ALIEN: 31337 >>expired + connections>> [ delete-all ] [ dispose-each ] bi + ] [ drop ] if ; : ( class -- pool ) - new V{ } clone >>connections ; inline + new V{ } clone + >>connections + dup check-pool ; inline M: pool dispose* connections>> dispose-each ; @@ -17,15 +26,14 @@ M: pool dispose* connections>> dispose-each ; TUPLE: return-connection conn pool ; : return-connection ( conn pool -- ) - dup check-disposed connections>> push ; + dup check-pool connections>> push ; GENERIC: make-connection ( pool -- conn ) : new-connection ( pool -- ) - [ make-connection ] keep return-connection ; + dup check-pool [ make-connection ] keep return-connection ; : acquire-connection ( pool -- conn ) - dup check-disposed [ dup connections>> empty? ] [ dup new-connection ] [ ] while connections>> pop ; diff --git a/extra/io/unix/launcher/parser/parser.factor b/extra/io/unix/launcher/parser/parser.factor index f3bb82343a..e5e83ab4e9 100755 --- a/extra/io/unix/launcher/parser/parser.factor +++ b/extra/io/unix/launcher/parser/parser.factor @@ -1,7 +1,6 @@ ! Copyright (C) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. -USING: peg peg.parsers kernel sequences strings words -memoize ; +USING: peg peg.parsers kernel sequences strings words ; IN: io.unix.launcher.parser ! Our command line parser. Supported syntax: @@ -9,20 +8,20 @@ IN: io.unix.launcher.parser ! foo\ bar -- escaping the space ! 'foo bar' -- quotation ! "foo bar" -- quotation -MEMO: 'escaped-char' ( -- parser ) - "\\" token [ drop t ] satisfy 2seq [ second ] action ; +: 'escaped-char' ( -- parser ) + "\\" token any-char 2seq [ second ] action ; -MEMO: 'quoted-char' ( delimiter -- parser' ) +: 'quoted-char' ( delimiter -- parser' ) 'escaped-char' swap [ member? not ] curry satisfy 2choice ; inline -MEMO: 'quoted' ( delimiter -- parser ) +: 'quoted' ( delimiter -- parser ) dup 'quoted-char' repeat0 swap dup surrounded-by ; -MEMO: 'unquoted' ( -- parser ) " '\"" 'quoted-char' repeat1 ; +: 'unquoted' ( -- parser ) " '\"" 'quoted-char' repeat1 ; -MEMO: 'argument' ( -- parser ) +: 'argument' ( -- parser ) "\"" 'quoted' "'" 'quoted' 'unquoted' 3choice diff --git a/extra/jamshred/gl/gl.factor b/extra/jamshred/gl/gl.factor index fffc97b4c6..4171c79a0a 100644 --- a/extra/jamshred/gl/gl.factor +++ b/extra/jamshred/gl/gl.factor @@ -1,8 +1,6 @@ ! Copyright (C) 2007 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors alien.c-types colors jamshred.game jamshred.oint -jamshred.player jamshred.tunnel kernel math math.vectors opengl -opengl.gl opengl.glu sequences ; +USING: accessors alien.c-types colors jamshred.game jamshred.oint jamshred.player jamshred.tunnel kernel math math.constants math.functions math.vectors opengl opengl.gl opengl.glu sequences ; IN: jamshred.gl : min-vertices 6 ; inline @@ -14,6 +12,35 @@ IN: jamshred.gl : n-segments-ahead ( -- n ) 60 ; inline : n-segments-behind ( -- n ) 40 ; inline +: wall-drawing-offset ( -- n ) + #! so that we can't see through the wall, we draw it a bit further away + 0.15 ; + +: wall-drawing-radius ( segment -- r ) + radius>> wall-drawing-offset + ; + +: wall-up ( segment -- v ) + [ wall-drawing-radius ] [ up>> ] bi n*v ; + +: wall-left ( segment -- v ) + [ wall-drawing-radius ] [ left>> ] bi n*v ; + +: segment-vertex ( theta segment -- vertex ) + [ + [ wall-up swap sin v*n ] [ wall-left swap cos v*n ] 2bi v+ + ] [ + location>> v+ + ] bi ; + +: segment-vertex-normal ( vertex segment -- normal ) + location>> swap v- normalize ; + +: segment-vertex-and-normal ( segment theta -- vertex normal ) + swap [ segment-vertex ] keep dupd segment-vertex-normal ; + +: equally-spaced-radians ( n -- seq ) + #! return a sequence of n numbers between 0 and 2pi + dup [ / pi 2 * * ] curry map ; : draw-segment-vertex ( segment theta -- ) over segment-color gl-color segment-vertex-and-normal gl-normal gl-vertex ; diff --git a/extra/jamshred/jamshred.factor b/extra/jamshred/jamshred.factor index 078a23f5db..b7764894d1 100755 --- a/extra/jamshred/jamshred.factor +++ b/extra/jamshred/jamshred.factor @@ -88,7 +88,7 @@ jamshred-gadget H{ { T{ mouse-scroll } [ handle-mouse-scroll ] } } set-gestures -: jamshred-window ( -- ) - [ "Jamshred" open-window ] with-ui ; +: jamshred-window ( -- jamshred ) + [ dup "Jamshred" open-window ] with-ui ; MAIN: jamshred-window diff --git a/extra/jamshred/oint/oint.factor b/extra/jamshred/oint/oint.factor index d50a93a3d2..7a37646a6d 100644 --- a/extra/jamshred/oint/oint.factor +++ b/extra/jamshred/oint/oint.factor @@ -39,8 +39,11 @@ C: oint : random-turn ( oint theta -- ) 2 / 2dup random-float+- left-pivot random-float+- up-pivot ; +: location+ ( v oint -- ) + [ location>> v+ ] [ (>>location) ] bi ; + : go-forward ( distance oint -- ) - [ forward>> n*v ] [ location>> v+ ] [ (>>location) ] tri ; + [ forward>> n*v ] [ location+ ] bi ; : distance-vector ( oint oint -- vector ) [ location>> ] bi@ swap v- ; @@ -62,3 +65,9 @@ C: oint :: reflect ( v n -- v' ) #! bounce v on a surface with normal n v v n v. n n v. / 2 * n n*v v- ; + +: half-way ( p1 p2 -- p3 ) + over v- 2 v/n v+ ; + +: half-way-between-oints ( o1 o2 -- p ) + [ location>> ] bi@ half-way ; diff --git a/extra/jamshred/player/player.factor b/extra/jamshred/player/player.factor index 8dc5125143..c40729e35b 100644 --- a/extra/jamshred/player/player.factor +++ b/extra/jamshred/player/player.factor @@ -1,6 +1,7 @@ -! Copyright (C) 2007 Alex Chapman +! Copyright (C) 2007, 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors colors combinators jamshred.log jamshred.oint jamshred.sound jamshred.tunnel kernel math math.constants math.order math.ranges shuffle sequences system ; +USING: accessors colors combinators jamshred.log jamshred.oint jamshred.sound jamshred.tunnel kernel locals math math.constants math.order math.ranges math.vectors math.matrices shuffle sequences system ; +USE: tools.walker IN: jamshred.player TUPLE: player < oint name sounds tunnel nearest-segment last-move speed ; @@ -30,6 +31,9 @@ TUPLE: player < oint name sounds tunnel nearest-segment last-move speed ; [ tunnel>> ] [ dup nearest-segment>> nearest-segment ] [ (>>nearest-segment) ] tri ; +: update-time ( player -- seconds-passed ) + millis swap [ last-move>> - 1000 / ] [ (>>last-move) ] 2bi ; + : moved ( player -- ) millis swap (>>last-move) ; : speed-range ( -- range ) @@ -41,38 +45,82 @@ TUPLE: player < oint name sounds tunnel nearest-segment last-move speed ; : multiply-player-speed ( n player -- ) [ * speed-range clamp-to-range ] change-speed drop ; -: distance-to-move ( player -- distance ) - [ speed>> ] [ last-move>> millis dup >r swap - 1000 / * r> ] - [ (>>last-move) ] tri ; +: distance-to-move ( seconds-passed player -- distance ) + speed>> * ; -DEFER: (move-player) +: bounce ( d-left player -- d-left' player ) + { + [ dup nearest-segment>> bounce-off-wall ] + [ sounds>> bang ] + [ 3/4 swap multiply-player-speed ] + [ ] + } cleave ; -: ?bounce ( distance-remaining player -- ) +:: (distance) ( heading player -- current next location heading ) + player nearest-segment>> + player [ tunnel>> ] [ nearest-segment>> ] bi heading heading-segment + player location>> heading ; + +: distance-to-heading-segment ( heading player -- distance ) + (distance) distance-to-next-segment ; + +: distance-to-heading-segment-area ( heading player -- distance ) + (distance) distance-to-next-segment-area ; + +: distance-to-collision ( player -- distance ) + dup nearest-segment>> (distance-to-collision) ; + +: from ( player -- radius distance-from-centre ) + [ nearest-segment>> dup radius>> swap ] [ location>> ] bi + distance-from-centre ; + +: distance-from-wall ( player -- distance ) from - ; +: fraction-from-centre ( player -- fraction ) from swap / ; +: fraction-from-wall ( player -- fraction ) + fraction-from-centre 1 swap - ; + +: update-nearest-segment2 ( heading player -- ) + 2dup distance-to-heading-segment-area 0 <= [ + [ tunnel>> ] [ nearest-segment>> rot heading-segment ] + [ (>>nearest-segment) ] tri + ] [ + 2drop + ] if ; + +:: move-player-on-heading ( d-left player distance heading -- d-left' player ) + [let* | d-to-move [ d-left distance min ] + move-v [ d-to-move heading n*v ] | + move-v player location+ + heading player update-nearest-segment2 + d-left d-to-move - player ] ; + +: move-toward-wall ( d-left player d-to-wall -- d-left' player ) + over [ forward>> ] keep distance-to-heading-segment-area min + over forward>> move-player-on-heading ; + +: ?move-player-freely ( d-left player -- d-left' player ) over 0 > [ - { - [ dup nearest-segment>> bounce ] - [ sounds>> bang ] - [ 3/4 swap multiply-player-speed ] - [ (move-player) ] - } cleave - ] [ - 2drop - ] if ; + dup distance-to-collision dup 0.2 > [ ! bug! should be 0, not 0.2 + move-toward-wall ?move-player-freely + ] [ drop ] if + ] when ; -: move-player-distance ( distance-remaining player distance -- distance-remaining player ) - pick min tuck over go-forward [ - ] dip ; +: drag-heading ( player -- heading ) + [ forward>> ] [ nearest-segment>> forward>> proj ] bi ; -: (move-player) ( distance-remaining player -- ) - over 0 <= [ - 2drop - ] [ - dup dup nearest-segment>> distance-to-collision - move-player-distance ?bounce - ] if ; +: drag-player ( d-left player -- d-left' player ) + dup [ [ drag-heading ] keep distance-to-heading-segment-area ] + [ drag-heading move-player-on-heading ] bi ; + +: (move-player) ( d-left player -- d-left' player ) + ?move-player-freely over 0 > [ + ! bounce + drag-player + (move-player) + ] when ; : move-player ( player -- ) - [ distance-to-move ] [ (move-player) ] [ update-nearest-segment ] tri ; + [ update-time ] [ distance-to-move ] [ (move-player) 2drop ] tri ; : update-player ( player -- ) - dup move-player nearest-segment>> - white swap set-segment-color ; + [ move-player ] [ nearest-segment>> white swap (>>color) ] bi ; diff --git a/extra/jamshred/tunnel/tunnel-tests.factor b/extra/jamshred/tunnel/tunnel-tests.factor index 903ff94739..722609851a 100644 --- a/extra/jamshred/tunnel/tunnel-tests.factor +++ b/extra/jamshred/tunnel/tunnel-tests.factor @@ -42,4 +42,4 @@ IN: jamshred.tunnel.tests [ { 0 1 0 } ] [ simple-collision-up sideways-heading ] unit-test [ { 0 0 0 } ] [ simple-collision-up sideways-relative-location ] unit-test [ { 0 1 0 } ] -[ simple-collision-up collision-vector 0 bounce-offset 0 3array v+ ] unit-test +[ simple-collision-up collision-vector 0 0 0 3array v+ ] unit-test diff --git a/extra/jamshred/tunnel/tunnel.factor b/extra/jamshred/tunnel/tunnel.factor index 5cf1e33e64..99c396bebd 100755 --- a/extra/jamshred/tunnel/tunnel.factor +++ b/extra/jamshred/tunnel/tunnel.factor @@ -1,6 +1,7 @@ -! Copyright (C) 2007 Alex Chapman +! Copyright (C) 2007, 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays combinators float-arrays kernel jamshred.oint locals math math.functions math.constants math.matrices math.order math.ranges math.vectors math.quadratic random sequences vectors ; +USING: accessors arrays combinators float-arrays kernel jamshred.oint locals math math.constants math.matrices math.order math.ranges math.vectors math.quadratic random sequences vectors ; +USE: tools.walker IN: jamshred.tunnel : n-segments ( -- n ) 5000 ; inline @@ -8,21 +9,6 @@ IN: jamshred.tunnel TUPLE: segment < oint number color radius ; C: segment -: segment-vertex ( theta segment -- vertex ) - tuck 2dup up>> swap sin v*n - >r left>> swap cos v*n r> v+ - swap location>> v+ ; - -: segment-vertex-normal ( vertex segment -- normal ) - location>> swap v- normalize ; - -: segment-vertex-and-normal ( segment theta -- vertex normal ) - swap [ segment-vertex ] keep dupd segment-vertex-normal ; - -: equally-spaced-radians ( n -- seq ) - #! return a sequence of n numbers between 0 and 2pi - dup [ / pi 2 * * ] curry map ; - : segment-number++ ( segment -- ) [ number>> 1+ ] keep (>>number) ; @@ -40,9 +26,7 @@ C: segment : (random-segments) ( segments n -- segments ) dup 0 > [ >r dup peek random-segment over push r> 1- (random-segments) - ] [ - drop - ] if ; + ] [ drop ] if ; : default-segment-radius ( -- r ) 1 ; @@ -66,7 +50,7 @@ C: segment : ( -- segments ) n-segments simple-segments ; -: sub-tunnel ( from to sements -- segments ) +: sub-tunnel ( from to segments -- segments ) #! return segments between from and to, after clamping from and to to #! valid values [ sequence-index-range [ clamp-to-range ] curry bi@ ] keep ; @@ -97,6 +81,32 @@ C: segment [ nearest-segment-forward ] 3keep nearest-segment-backward r> nearer-segment ; +: get-segment ( segments n -- segment ) + over sequence-index-range clamp-to-range swap nth ; + +: next-segment ( segments current-segment -- segment ) + number>> 1+ get-segment ; + +: previous-segment ( segments current-segment -- segment ) + number>> 1- get-segment ; + +: heading-segment ( segments current-segment heading -- segment ) + #! the next segment on the given heading + over forward>> v. 0 <=> { + { +gt+ [ next-segment ] } + { +lt+ [ previous-segment ] } + { +eq+ [ nip ] } ! current segment + } case ; + +:: distance-to-next-segment ( current next location heading -- distance ) + [let | cf [ current forward>> ] | + cf next location>> v. cf location v. - cf heading v. / ] ; + +:: distance-to-next-segment-area ( current next location heading -- distance ) + [let | cf [ current forward>> ] + h [ next current half-way-between-oints ] | + cf h v. cf location v. - cf heading v. / ] ; + : vector-to-centre ( seg loc -- v ) over location>> swap v- swap forward>> proj-perp ; @@ -106,19 +116,25 @@ C: segment : wall-normal ( seg oint -- n ) location>> vector-to-centre normalize ; -: from ( seg loc -- radius d-f-c ) - dupd location>> distance-from-centre [ radius>> ] dip ; +: distant ( -- n ) 1000 ; -: distance-from-wall ( seg loc -- distance ) from - ; -: fraction-from-centre ( seg loc -- fraction ) from / ; -: fraction-from-wall ( seg loc -- fraction ) - fraction-from-centre 1 swap - ; +: max-real ( a b -- c ) + #! sometimes collision-coefficient yields complex roots, so we ignore these (hack) + dup real? [ + over real? [ max ] [ nip ] if + ] [ + drop dup real? [ drop distant ] unless + ] if ; :: collision-coefficient ( v w r -- c ) - [let* | a [ v dup v. ] - b [ v w v. 2 * ] - c [ w dup v. r sq - ] | - c b a quadratic max ] ; + v norm 0 = [ + distant + ] [ + [let* | a [ v dup v. ] + b [ v w v. 2 * ] + c [ w dup v. r sq - ] | + c b a quadratic max-real ] + ] if ; : sideways-heading ( oint segment -- v ) [ forward>> ] bi@ proj-perp ; @@ -126,18 +142,12 @@ C: segment : sideways-relative-location ( oint segment -- loc ) [ [ location>> ] bi@ v- ] keep forward>> proj-perp ; -: bounce-offset 0.1 ; inline - -: bounce-radius ( segment -- r ) - radius>> bounce-offset - ; ! bounce before we hit so that we can't see through the wall (hack?) +: (distance-to-collision) ( oint segment -- distance ) + [ sideways-heading ] [ sideways-relative-location ] + [ nip radius>> ] 2tri collision-coefficient ; : collision-vector ( oint segment -- v ) - [ sideways-heading ] [ sideways-relative-location ] - [ bounce-radius ] 2tri - swap [ collision-coefficient ] dip forward>> n*v ; - -: distance-to-collision ( oint segment -- distance ) - collision-vector norm ; + dupd (distance-to-collision) swap forward>> n*v ; : bounce-forward ( segment oint -- ) [ wall-normal ] [ forward>> swap reflect ] [ (>>forward) ] tri ; @@ -151,6 +161,6 @@ C: segment #! must be done after forward and left! nip [ forward>> ] [ left>> cross ] [ (>>up) ] tri ; -: bounce ( oint segment -- ) +: bounce-off-wall ( oint segment -- ) swap [ bounce-forward ] [ bounce-left ] [ bounce-up ] 2tri ; diff --git a/extra/json/reader/reader.factor b/extra/json/reader/reader.factor index 5e6b16dc2f..6bd6905804 100755 --- a/extra/json/reader/reader.factor +++ b/extra/json/reader/reader.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: kernel parser-combinators namespaces sequences promises strings assocs math math.parser math.vectors math.functions math.order - lazy-lists hashtables ascii ; + lists hashtables ascii ; IN: json.reader ! Grammar for JSON from RFC 4627 diff --git a/extra/lazy-lists/lazy-lists.factor b/extra/lazy-lists/lazy-lists.factor deleted file mode 100644 index 6db82ed2c1..0000000000 --- a/extra/lazy-lists/lazy-lists.factor +++ /dev/null @@ -1,445 +0,0 @@ -! Copyright (C) 2004 Chris Double. -! See http://factorcode.org/license.txt for BSD license. -! -! Updated by Matthew Willis, July 2006 -! Updated by Chris Double, September 2006 -! -USING: kernel sequences math vectors arrays namespaces -quotations promises combinators io ; -IN: lazy-lists - -! Lazy List Protocol -MIXIN: list -GENERIC: car ( cons -- car ) -GENERIC: cdr ( cons -- cdr ) -GENERIC: nil? ( cons -- ? ) - -M: promise car ( promise -- car ) - force car ; - -M: promise cdr ( promise -- cdr ) - force cdr ; - -M: promise nil? ( cons -- bool ) - force nil? ; - -TUPLE: cons car cdr ; - -C: cons cons - -M: cons car ( cons -- car ) - cons-car ; - -M: cons cdr ( cons -- cdr ) - cons-cdr ; - -: nil ( -- cons ) - T{ cons f f f } ; - -M: cons nil? ( cons -- bool ) - nil eq? ; - -: 1list ( obj -- cons ) - nil cons ; - -: 2list ( a b -- cons ) - nil cons cons ; - -: 3list ( a b c -- cons ) - nil cons cons cons ; - -! Both 'car' and 'cdr' are promises -TUPLE: lazy-cons car cdr ; - -: lazy-cons ( car cdr -- promise ) - [ promise ] bi@ \ lazy-cons boa - T{ promise f f t f } clone - [ set-promise-value ] keep ; - -M: lazy-cons car ( lazy-cons -- car ) - lazy-cons-car force ; - -M: lazy-cons cdr ( lazy-cons -- cdr ) - lazy-cons-cdr force ; - -M: lazy-cons nil? ( lazy-cons -- bool ) - nil eq? ; - -: 1lazy-list ( a -- lazy-cons ) - [ nil ] lazy-cons ; - -: 2lazy-list ( a b -- lazy-cons ) - 1lazy-list 1quotation lazy-cons ; - -: 3lazy-list ( a b c -- lazy-cons ) - 2lazy-list 1quotation lazy-cons ; - -: lnth ( n list -- elt ) - swap [ cdr ] times car ; - -: (llength) ( list acc -- n ) - over nil? [ nip ] [ [ cdr ] dip 1+ (llength) ] if ; - -: llength ( list -- n ) - 0 (llength) ; - -: uncons ( cons -- car cdr ) - #! Return the car and cdr of the lazy list - dup car swap cdr ; - -: leach ( list quot -- ) - swap dup nil? [ 2drop ] [ uncons swapd over 2slip leach ] if ; inline - -: lreduce ( list identity quot -- result ) - swapd leach ; inline - -TUPLE: memoized-cons original car cdr nil? ; - -: not-memoized ( -- obj ) - { } ; - -: not-memoized? ( obj -- bool ) - not-memoized eq? ; - -: ( cons -- memoized-cons ) - not-memoized not-memoized not-memoized - memoized-cons boa ; - -M: memoized-cons car ( memoized-cons -- car ) - dup memoized-cons-car not-memoized? [ - dup memoized-cons-original car [ swap set-memoized-cons-car ] keep - ] [ - memoized-cons-car - ] if ; - -M: memoized-cons cdr ( memoized-cons -- cdr ) - dup memoized-cons-cdr not-memoized? [ - dup memoized-cons-original cdr [ swap set-memoized-cons-cdr ] keep - ] [ - memoized-cons-cdr - ] if ; - -M: memoized-cons nil? ( memoized-cons -- bool ) - dup memoized-cons-nil? not-memoized? [ - dup memoized-cons-original nil? [ swap set-memoized-cons-nil? ] keep - ] [ - memoized-cons-nil? - ] if ; - -TUPLE: lazy-map cons quot ; - -C: lazy-map - -: lmap ( list quot -- result ) - over nil? [ 2drop nil ] [ ] if ; - -M: lazy-map car ( lazy-map -- car ) - [ lazy-map-cons car ] keep - lazy-map-quot call ; - -M: lazy-map cdr ( lazy-map -- cdr ) - [ lazy-map-cons cdr ] keep - lazy-map-quot lmap ; - -M: lazy-map nil? ( lazy-map -- bool ) - lazy-map-cons nil? ; - -: lmap-with ( value list quot -- result ) - with lmap ; - -TUPLE: lazy-take n cons ; - -C: lazy-take - -: ltake ( n list -- result ) - over zero? [ 2drop nil ] [ ] if ; - -M: lazy-take car ( lazy-take -- car ) - lazy-take-cons car ; - -M: lazy-take cdr ( lazy-take -- cdr ) - [ lazy-take-n 1- ] keep - lazy-take-cons cdr ltake ; - -M: lazy-take nil? ( lazy-take -- bool ) - dup lazy-take-n zero? [ - drop t - ] [ - lazy-take-cons nil? - ] if ; - -TUPLE: lazy-until cons quot ; - -C: lazy-until - -: luntil ( list quot -- result ) - over nil? [ drop ] [ ] if ; - -M: lazy-until car ( lazy-until -- car ) - lazy-until-cons car ; - -M: lazy-until cdr ( lazy-until -- cdr ) - [ lazy-until-cons uncons swap ] keep lazy-until-quot tuck call - [ 2drop nil ] [ luntil ] if ; - -M: lazy-until nil? ( lazy-until -- bool ) - drop f ; - -TUPLE: lazy-while cons quot ; - -C: lazy-while - -: lwhile ( list quot -- result ) - over nil? [ drop ] [ ] if ; - -M: lazy-while car ( lazy-while -- car ) - lazy-while-cons car ; - -M: lazy-while cdr ( lazy-while -- cdr ) - [ lazy-while-cons cdr ] keep lazy-while-quot lwhile ; - -M: lazy-while nil? ( lazy-while -- bool ) - [ car ] keep lazy-while-quot call not ; - -TUPLE: lazy-filter cons quot ; - -C: lazy-filter - -: lfilter ( list quot -- result ) - over nil? [ 2drop nil ] [ ] if ; - -: car-filter? ( lazy-filter -- ? ) - [ lazy-filter-cons car ] keep - lazy-filter-quot call ; - -: skip ( lazy-filter -- ) - [ lazy-filter-cons cdr ] keep - set-lazy-filter-cons ; - -M: lazy-filter car ( lazy-filter -- car ) - dup car-filter? [ lazy-filter-cons ] [ dup skip ] if car ; - -M: lazy-filter cdr ( lazy-filter -- cdr ) - dup car-filter? [ - [ lazy-filter-cons cdr ] keep - lazy-filter-quot lfilter - ] [ - dup skip cdr - ] if ; - -M: lazy-filter nil? ( lazy-filter -- bool ) - dup lazy-filter-cons nil? [ - drop t - ] [ - dup car-filter? [ - drop f - ] [ - dup skip nil? - ] if - ] if ; - -: list>vector ( list -- vector ) - [ [ , ] leach ] V{ } make ; - -: list>array ( list -- array ) - [ [ , ] leach ] { } make ; - -TUPLE: lazy-append list1 list2 ; - -C: lazy-append - -: lappend ( list1 list2 -- result ) - over nil? [ nip ] [ ] if ; - -M: lazy-append car ( lazy-append -- car ) - lazy-append-list1 car ; - -M: lazy-append cdr ( lazy-append -- cdr ) - [ lazy-append-list1 cdr ] keep - lazy-append-list2 lappend ; - -M: lazy-append nil? ( lazy-append -- bool ) - drop f ; - -TUPLE: lazy-from-by n quot ; - -C: lfrom-by lazy-from-by ( n quot -- list ) - -: lfrom ( n -- list ) - [ 1+ ] lfrom-by ; - -M: lazy-from-by car ( lazy-from-by -- car ) - lazy-from-by-n ; - -M: lazy-from-by cdr ( lazy-from-by -- cdr ) - [ lazy-from-by-n ] keep - lazy-from-by-quot dup slip lfrom-by ; - -M: lazy-from-by nil? ( lazy-from-by -- bool ) - drop f ; - -TUPLE: lazy-zip list1 list2 ; - -C: lazy-zip - -: lzip ( list1 list2 -- lazy-zip ) - over nil? over nil? or - [ 2drop nil ] [ ] if ; - -M: lazy-zip car ( lazy-zip -- car ) - [ lazy-zip-list1 car ] keep lazy-zip-list2 car 2array ; - -M: lazy-zip cdr ( lazy-zip -- cdr ) - [ lazy-zip-list1 cdr ] keep lazy-zip-list2 cdr lzip ; - -M: lazy-zip nil? ( lazy-zip -- bool ) - drop f ; - -TUPLE: sequence-cons index seq ; - -C: sequence-cons - -: seq>list ( index seq -- list ) - 2dup length >= [ - 2drop nil - ] [ - - ] if ; - -M: sequence-cons car ( sequence-cons -- car ) - [ sequence-cons-index ] keep - sequence-cons-seq nth ; - -M: sequence-cons cdr ( sequence-cons -- cdr ) - [ sequence-cons-index 1+ ] keep - sequence-cons-seq seq>list ; - -M: sequence-cons nil? ( sequence-cons -- bool ) - drop f ; - -: >list ( object -- list ) - { - { [ dup sequence? ] [ 0 swap seq>list ] } - { [ dup list? ] [ ] } - [ "Could not convert object to a list" throw ] - } cond ; - -TUPLE: lazy-concat car cdr ; - -C: lazy-concat - -DEFER: lconcat - -: (lconcat) ( car cdr -- list ) - over nil? [ - nip lconcat - ] [ - - ] if ; - -: lconcat ( list -- result ) - dup nil? [ - drop nil - ] [ - uncons (lconcat) - ] if ; - -M: lazy-concat car ( lazy-concat -- car ) - lazy-concat-car car ; - -M: lazy-concat cdr ( lazy-concat -- cdr ) - [ lazy-concat-car cdr ] keep lazy-concat-cdr (lconcat) ; - -M: lazy-concat nil? ( lazy-concat -- bool ) - dup lazy-concat-car nil? [ - lazy-concat-cdr nil? - ] [ - drop f - ] if ; - -: lcartesian-product ( list1 list2 -- result ) - swap [ swap [ 2array ] lmap-with ] lmap-with lconcat ; - -: lcartesian-product* ( lists -- result ) - dup nil? [ - drop nil - ] [ - [ car ] keep cdr [ car lcartesian-product ] keep cdr list>array swap [ - swap [ swap [ suffix ] lmap-with ] lmap-with lconcat - ] reduce - ] if ; - -: lcomp ( list quot -- result ) - [ lcartesian-product* ] dip lmap ; - -: lcomp* ( list guards quot -- result ) - [ [ lcartesian-product* ] dip [ lfilter ] each ] dip lmap ; - -DEFER: lmerge - -: (lmerge) ( list1 list2 -- result ) - over [ car ] curry -rot - [ - dup [ car ] curry -rot - [ - [ cdr ] bi@ lmerge - ] 2curry lazy-cons - ] 2curry lazy-cons ; - -: lmerge ( list1 list2 -- result ) - { - { [ over nil? ] [ nip ] } - { [ dup nil? ] [ drop ] } - { [ t ] [ (lmerge) ] } - } cond ; - -TUPLE: lazy-io stream car cdr quot ; - -C: lazy-io - -: lcontents ( stream -- result ) - f f [ stream-read1 ] ; - -: llines ( stream -- result ) - f f [ stream-readln ] ; - -M: lazy-io car ( lazy-io -- car ) - dup lazy-io-car dup [ - nip - ] [ - drop dup lazy-io-stream over lazy-io-quot call - swap dupd set-lazy-io-car - ] if ; - -M: lazy-io cdr ( lazy-io -- cdr ) - dup lazy-io-cdr dup [ - nip - ] [ - drop dup - [ lazy-io-stream ] keep - [ lazy-io-quot ] keep - car [ - [ f f ] dip [ swap set-lazy-io-cdr ] keep - ] [ - 3drop nil - ] if - ] if ; - -M: lazy-io nil? ( lazy-io -- bool ) - car not ; - -INSTANCE: cons list -INSTANCE: sequence-cons list -INSTANCE: memoized-cons list -INSTANCE: promise list -INSTANCE: lazy-io list -INSTANCE: lazy-concat list -INSTANCE: lazy-cons list -INSTANCE: lazy-map list -INSTANCE: lazy-take list -INSTANCE: lazy-append list -INSTANCE: lazy-from-by list -INSTANCE: lazy-zip list -INSTANCE: lazy-while list -INSTANCE: lazy-until list -INSTANCE: lazy-filter list diff --git a/extra/lcs/diff2html/diff2html.factor b/extra/lcs/diff2html/diff2html.factor index a8f649e2c9..754e69a476 100644 --- a/extra/lcs/diff2html/diff2html.factor +++ b/extra/lcs/diff2html/diff2html.factor @@ -38,7 +38,7 @@ M: delete diff-line ; : htmlize-diff ( diff -- ) - +
[ diff-line ] each
"Old" write "New" write
; diff --git a/extra/lisp/lisp-tests.factor b/extra/lisp/lisp-tests.factor index 0312080907..c4090e1098 100644 --- a/extra/lisp/lisp-tests.factor +++ b/extra/lisp/lisp-tests.factor @@ -1,17 +1,19 @@ ! Copyright (C) 2008 James Cash ! See http://factorcode.org/license.txt for BSD license. -USING: lisp lisp.parser tools.test sequences math kernel parser ; +USING: lisp lisp.parser tools.test sequences math kernel parser arrays ; IN: lisp.test [ init-env - "#f" [ f ] lisp-define - "#t" [ t ] lisp-define + [ f ] "#f" lisp-define + [ t ] "#t" lisp-define - "+" "math" "+" define-primitve - "-" "math" "-" define-primitve + "+" "math" "+" define-primitive + "-" "math" "-" define-primitive + +! "list" [ >array ] lisp-define { 5 } [ [ 2 3 ] "+" funcall @@ -22,26 +24,39 @@ IN: lisp.test ] unit-test { 3 } [ - "((lambda (x y) (+ x y)) 1 2)" lisp-string>factor call + "((lambda (x y) (+ x y)) 1 2)" lisp-eval ] unit-test { 42 } [ - "((lambda (x y z) (+ x (- y z))) 40 3 1)" lisp-string>factor call + "((lambda (x y z) (+ x (- y z))) 40 3 1)" lisp-eval + ] unit-test + + { T{ lisp-symbol f "if" } } [ + "(defmacro if (pred tr fl) (quasiquote (cond ((unquote pred) (unquote tr)) (#t (unquote fl)))))" lisp-eval + ] unit-test + + { t } [ + T{ lisp-symbol f "if" } lisp-macro? ] unit-test { 1 } [ - "(if #t 1 2)" lisp-string>factor call + "(if #t 1 2)" lisp-eval ] unit-test { "b" } [ - "(cond (#f \"a\") (#t \"b\"))" lisp-string>factor call + "(cond (#f \"a\") (#t \"b\"))" lisp-eval ] unit-test { 5 } [ - "(begin (+ 1 4))" lisp-string>factor call + "(begin (+ 1 4))" lisp-eval ] unit-test { 3 } [ - "((lambda (x) (if x (begin (+ 1 2)) (- 3 5))) #t)" lisp-string>factor call + "((lambda (x) (if x (begin (+ 1 2)) (- 3 5))) #t)" lisp-eval ] unit-test -] with-interactive-vocabs \ No newline at end of file + +! { { 1 2 3 4 5 } } [ +! "(list 1 2 3 4 5)" lisp-eval +! ] unit-test + +] with-interactive-vocabs diff --git a/extra/lisp/lisp.factor b/extra/lisp/lisp.factor index 82a331f2ca..e865a2e3ed 100644 --- a/extra/lisp/lisp.factor +++ b/extra/lisp/lisp.factor @@ -1,48 +1,47 @@ ! Copyright (C) 2008 James Cash ! See http://factorcode.org/license.txt for BSD license. USING: kernel peg sequences arrays strings combinators.lib -namespaces combinators math bake locals locals.private accessors -vectors syntax lisp.parser assocs parser sequences.lib words quotations -fry ; +namespaces combinators math locals locals.private accessors +vectors syntax lisp.parser assocs parser sequences.lib words +quotations fry lists inspector ; IN: lisp DEFER: convert-form DEFER: funcall DEFER: lookup-var - +DEFER: lookup-macro +DEFER: lisp-macro? +DEFER: macro-expand +DEFER: define-lisp-macro + ! Functions to convert s-exps to quotations ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: convert-body ( s-exp -- quot ) - [ ] [ convert-form compose ] reduce ; inline - -: convert-if ( s-exp -- quot ) - rest first3 [ convert-form ] tri@ '[ @ , , if ] ; +: convert-body ( cons -- quot ) + [ ] [ convert-form compose ] foldl ; inline -: convert-begin ( s-exp -- quot ) - rest [ convert-form ] [ ] map-as '[ , [ funcall ] each ] ; +: convert-begin ( cons -- quot ) + cdr [ convert-form ] [ ] lmap-as '[ , [ funcall ] each ] ; -: convert-cond ( s-exp -- quot ) - rest [ body>> first2 [ convert-form ] bi@ [ '[ @ funcall ] ] dip 2array ] - { } map-as '[ , cond ] ; +: convert-cond ( cons -- quot ) + cdr [ 2car [ convert-form ] bi@ [ '[ @ funcall ] ] dip 2array ] + { } lmap-as '[ , cond ] ; -: convert-general-form ( s-exp -- quot ) - unclip convert-form swap convert-body swap '[ , @ funcall ] ; +: convert-general-form ( cons -- quot ) + uncons [ convert-body ] [ convert-form ] bi* '[ , @ funcall ] ; ! words for convert-lambda > ] dip at swap or ] - [ dup s-exp? [ body>> localize-body ] when ] if - ] map ; - + [ lisp-symbol? ] pick '[ [ name>> , at ] [ ] bi or ] traverse ; + : localize-lambda ( body vars -- newbody newvars ) make-locals dup push-locals swap - [ swap localize-body convert-form swap pop-locals ] dip swap ; + [ swap localize-body convert-form swap pop-locals ] dip swap ; -: split-lambda ( s-exp -- body vars ) - first3 -rot nip [ body>> ] bi@ [ name>> ] map ; inline +: split-lambda ( cons -- body-cons vars-seq ) + 3car -rot nip [ name>> ] lmap>array ; inline -: rest-lambda ( body vars -- quot ) +: rest-lambda ( body vars -- quot ) "&rest" swap [ index ] [ remove ] 2bi localize-lambda '[ , cut '[ @ , ] , compose ] ; @@ -51,46 +50,80 @@ DEFER: lookup-var localize-lambda '[ , compose ] ; PRIVATE> -: convert-lambda ( s-exp -- quot ) +: convert-lambda ( cons -- quot ) split-lambda "&rest" over member? [ rest-lambda ] [ normal-lambda ] if ; -: convert-quoted ( s-exp -- quot ) - second 1quotation ; +: convert-quoted ( cons -- quot ) + cdr 1quotation ; -: convert-list-form ( s-exp -- quot ) - dup first dup lisp-symbol? - [ name>> - { { "lambda" [ convert-lambda ] } - { "quote" [ convert-quoted ] } - { "if" [ convert-if ] } - { "begin" [ convert-begin ] } - { "cond" [ convert-cond ] } - [ drop convert-general-form ] - } case ] - [ drop convert-general-form ] if ; +: convert-unquoted ( cons -- quot ) + "unquote not valid outside of quasiquote!" throw ; -: convert-form ( lisp-form -- quot ) - { { [ dup s-exp? ] [ body>> convert-list-form ] } - { [ dup lisp-symbol? ] [ '[ , lookup-var ] ] } - [ 1quotation ] +: convert-quasiquoted ( cons -- newcons ) + [ { [ dup list? ] [ car dup lisp-symbol? ] [ name>> "unquote" equal? dup ] } && nip ] + [ cadr ] traverse ; + +: convert-defmacro ( cons -- quot ) + cdr [ car ] keep [ convert-lambda ] [ car name>> ] bi define-lisp-macro 1quotation ; + +: form-dispatch ( cons lisp-symbol -- quot ) + name>> + { { "lambda" [ convert-lambda ] } + { "defmacro" [ convert-defmacro ] } + { "quote" [ convert-quoted ] } + { "unquote" [ convert-unquoted ] } + { "quasiquote" [ convert-quasiquoted ] } + { "begin" [ convert-begin ] } + { "cond" [ convert-cond ] } + [ drop convert-general-form ] + } case ; + +: convert-list-form ( cons -- quot ) + dup car + { { [ dup lisp-macro? ] [ drop macro-expand ] } + { [ dup lisp-symbol? ] [ form-dispatch ] } + [ drop convert-general-form ] } cond ; +: convert-form ( lisp-form -- quot ) + { + { [ dup cons? ] [ convert-list-form ] } + { [ dup lisp-symbol? ] [ '[ , lookup-var ] ] } + [ 1quotation ] + } cond ; + +: compile-form ( lisp-ast -- quot ) + convert-form lambda-rewrite call ; inline + +: macro-call ( lambda -- cons ) + call ; inline + +: macro-expand ( cons -- quot ) + uncons [ list>seq [ ] like ] [ lookup-macro macro-call compile-form ] bi* call ; + : lisp-string>factor ( str -- quot ) - lisp-expr parse-result-ast convert-form lambda-rewrite call ; + lisp-expr parse-result-ast compile-form ; + +: lisp-eval ( str -- * ) + lisp-string>factor call ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SYMBOL: lisp-env -ERROR: no-such-var var ; +SYMBOL: macro-env + +ERROR: no-such-var variable-name ; +M: no-such-var summary drop "No such variable" ; : init-env ( -- ) - H{ } clone lisp-env set ; + H{ } clone lisp-env set + H{ } clone macro-env set ; -: lisp-define ( name quot -- ) - swap lisp-env get set-at ; +: lisp-define ( quot name -- ) + lisp-env get set-at ; : lisp-get ( name -- word ) - dup lisp-env get at [ ] [ no-such-var throw ] ?if ; + dup lisp-env get at [ ] [ no-such-var ] ?if ; : lookup-var ( lisp-symbol -- quot ) name>> lisp-get ; @@ -98,5 +131,14 @@ ERROR: no-such-var var ; : funcall ( quot sym -- * ) dup lisp-symbol? [ lookup-var ] when call ; inline -: define-primitve ( name vocab word -- ) - swap lookup 1quotation '[ , compose call ] lisp-define ; \ No newline at end of file +: define-primitive ( name vocab word -- ) + swap lookup 1quotation '[ , compose call ] swap lisp-define ; + +: lookup-macro ( lisp-symbol -- lambda ) + name>> macro-env get at ; + +: define-lisp-macro ( quot name -- ) + macro-env get set-at ; + +: lisp-macro? ( car -- ? ) + dup lisp-symbol? [ name>> macro-env get key? ] [ drop f ] if ; diff --git a/extra/lisp/parser/parser-tests.factor b/extra/lisp/parser/parser-tests.factor index 98a6d2a6ba..4aa8154690 100644 --- a/extra/lisp/parser/parser-tests.factor +++ b/extra/lisp/parser/parser-tests.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 James Cash ! See http://factorcode.org/license.txt for BSD license. -USING: lisp.parser tools.test peg peg.ebnf ; +USING: lisp.parser tools.test peg peg.ebnf lists ; IN: lisp.parser.tests @@ -9,38 +9,60 @@ IN: lisp.parser.tests ] unit-test { -42 } [ - "-42" "atom" \ lisp-expr rule parse parse-result-ast + "-42" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { 37/52 } [ - "37/52" "atom" \ lisp-expr rule parse parse-result-ast + "37/52" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { 123.98 } [ - "123.98" "atom" \ lisp-expr rule parse parse-result-ast + "123.98" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { "" } [ - "\"\"" "atom" \ lisp-expr rule parse parse-result-ast + "\"\"" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { "aoeu" } [ - "\"aoeu\"" "atom" \ lisp-expr rule parse parse-result-ast + "\"aoeu\"" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { "aoeu\"de" } [ - "\"aoeu\\\"de\"" "atom" \ lisp-expr rule parse parse-result-ast + "\"aoeu\\\"de\"" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { T{ lisp-symbol f "foobar" } } [ - "foobar" "atom" \ lisp-expr rule parse parse-result-ast + "foobar" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test { T{ lisp-symbol f "+" } } [ - "+" "atom" \ lisp-expr rule parse parse-result-ast + "+" "atom" \ lisp-expr rule parse parse-result-ast ] unit-test -{ T{ s-exp f - V{ T{ lisp-symbol f "foo" } 1 2 "aoeu" } } } [ - "(foo 1 2 \"aoeu\")" lisp-expr parse-result-ast +{ +nil+ } [ + "()" lisp-expr parse-result-ast +] unit-test + +{ T{ + cons + f + T{ lisp-symbol f "foo" } + T{ + cons + f + 1 + T{ cons f 2 T{ cons f "aoeu" +nil+ } } + } } } [ + "(foo 1 2 \"aoeu\")" lisp-expr parse-result-ast +] unit-test + +{ T{ cons f + 1 + T{ cons f + T{ cons f 3 T{ cons f 4 +nil+ } } + T{ cons f 2 +nil+ } } + } +} [ + "(1 (3 4) 2)" lisp-expr parse-result-ast ] unit-test \ No newline at end of file diff --git a/extra/lisp/parser/parser.factor b/extra/lisp/parser/parser.factor index cf5ff56331..1e37193d3a 100644 --- a/extra/lisp/parser/parser.factor +++ b/extra/lisp/parser/parser.factor @@ -1,16 +1,13 @@ ! Copyright (C) 2008 James Cash ! See http://factorcode.org/license.txt for BSD license. -USING: kernel peg.ebnf peg.expr math.parser sequences arrays strings -combinators.lib math ; +USING: kernel peg peg.ebnf peg.expr math.parser sequences arrays strings +combinators.lib math fry accessors lists ; IN: lisp.parser TUPLE: lisp-symbol name ; C: lisp-symbol -TUPLE: s-exp body ; -C: s-exp - EBNF: lisp-expr _ = (" " | "\t" | "\n")* LPAREN = "(" @@ -24,8 +21,9 @@ rational = integer "/" (digit)+ => [[ first3 nip string number = float | rational | integer -id-specials = "!" | "$" | "%" | "&" | "*" | "/" | ":" | "<" | "#" - | " =" | ">" | "?" | "^" | "_" | "~" | "+" | "-" | "." | "@" +id-specials = "!" | "$" | "%" | "&" | "*" | "/" | ":" + | "<" | "#" | " =" | ">" | "?" | "^" | "_" + | "~" | "+" | "-" | "." | "@" letters = [a-zA-Z] => [[ 1array >string ]] initials = letters | id-specials numbers = [0-9] => [[ 1array >string ]] @@ -36,6 +34,6 @@ string = dquote ( escaped | !(dquote) . )* dquote => [[ second >string ]] atom = number | identifier | string -list-item = _ (atom|s-expression) _ => [[ second ]] -s-expression = LPAREN (list-item)* RPAREN => [[ second ]] +list-item = _ ( atom | s-expression ) _ => [[ second ]] +s-expression = LPAREN (list-item)* RPAREN => [[ second seq>cons ]] ;EBNF \ No newline at end of file diff --git a/extra/lists/authors.txt b/extra/lists/authors.txt new file mode 100644 index 0000000000..4b7af4aac0 --- /dev/null +++ b/extra/lists/authors.txt @@ -0,0 +1 @@ +James Cash diff --git a/extra/lazy-lists/authors.txt b/extra/lists/lazy/authors.txt similarity index 100% rename from extra/lazy-lists/authors.txt rename to extra/lists/lazy/authors.txt diff --git a/extra/lazy-lists/examples/authors.txt b/extra/lists/lazy/examples/authors.txt similarity index 100% rename from extra/lazy-lists/examples/authors.txt rename to extra/lists/lazy/examples/authors.txt diff --git a/extra/lazy-lists/examples/examples-tests.factor b/extra/lists/lazy/examples/examples-tests.factor similarity index 100% rename from extra/lazy-lists/examples/examples-tests.factor rename to extra/lists/lazy/examples/examples-tests.factor diff --git a/extra/lazy-lists/examples/examples.factor b/extra/lists/lazy/examples/examples.factor similarity index 75% rename from extra/lazy-lists/examples/examples.factor rename to extra/lists/lazy/examples/examples.factor index 844ae31085..f85344651d 100644 --- a/extra/lazy-lists/examples/examples.factor +++ b/extra/lists/lazy/examples/examples.factor @@ -2,8 +2,8 @@ ! Copyright (C) 2004 Chris Double. ! See http://factorcode.org/license.txt for BSD license. -USING: lazy-lists math kernel sequences quotations ; -IN: lazy-lists.examples +USING: lists.lazy math kernel sequences quotations ; +IN: lists.lazy.examples : naturals 0 lfrom ; : positives 1 lfrom ; @@ -11,5 +11,5 @@ IN: lazy-lists.examples : odds 1 lfrom [ 2 mod 1 = ] lfilter ; : powers-of-2 1 [ 2 * ] lfrom-by ; : ones 1 [ ] lfrom-by ; -: squares naturals [ dup * ] lmap ; +: squares naturals [ dup * ] lazy-map ; : first-five-squares 5 squares ltake list>array ; diff --git a/extra/lazy-lists/lazy-lists-docs.factor b/extra/lists/lazy/lazy-docs.factor similarity index 76% rename from extra/lazy-lists/lazy-lists-docs.factor rename to extra/lists/lazy/lazy-docs.factor index b240b3fbc2..6a9359027d 100644 --- a/extra/lazy-lists/lazy-lists-docs.factor +++ b/extra/lists/lazy/lazy-docs.factor @@ -1,48 +1,8 @@ ! Copyright (C) 2006 Chris Double. ! See http://factorcode.org/license.txt for BSD license. -USING: help.markup help.syntax sequences strings ; -IN: lazy-lists - -{ car cons cdr nil nil? list? uncons } related-words - -HELP: cons -{ $values { "car" "the head of the lazy list" } { "cdr" "the tail of the lazy list" } { "cons" "a cons object" } } -{ $description "Constructs a cons cell." } ; - -HELP: car -{ $values { "cons" "a cons object" } { "car" "the first item in the list" } } -{ $description "Returns the first item in the list." } ; - -HELP: cdr -{ $values { "cons" "a cons object" } { "cdr" "a cons object" } } -{ $description "Returns the tail of the list." } ; - -HELP: nil -{ $values { "cons" "An empty cons" } } -{ $description "Returns a representation of an empty list" } ; - -HELP: nil? -{ $values { "cons" "a cons object" } { "?" "a boolean" } } -{ $description "Return true if the cons object is the nil cons." } ; - -HELP: list? ( object -- ? ) -{ $values { "object" "an object" } { "?" "a boolean" } } -{ $description "Returns true if the object conforms to the list protocol." } ; - -{ 1list 2list 3list } related-words - -HELP: 1list -{ $values { "obj" "an object" } { "cons" "a cons object" } } -{ $description "Create a list with 1 element." } ; - -HELP: 2list -{ $values { "a" "an object" } { "b" "an object" } { "cons" "a cons object" } } -{ $description "Create a list with 2 elements." } ; - -HELP: 3list -{ $values { "a" "an object" } { "b" "an object" } { "c" "an object" } { "cons" "a cons object" } } -{ $description "Create a list with 3 elements." } ; +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" } } @@ -68,37 +28,15 @@ HELP: { $description "Constructs a cons object that wraps an existing cons object. Requests for the car, cdr and nil? will be remembered after the first call, and the previous result returned on subsequent calls." } { $see-also cons car cdr nil nil? } ; -HELP: lnth -{ $values { "n" "an integer index" } { "list" "a cons object" } { "elt" "the element at the nth index" } } -{ $description "Outputs the nth element of the list." } -{ $see-also llength cons car cdr } ; +{ lazy-map lazy-map-with ltake lfilter lappend lfrom lfrom-by lconcat lcartesian-product lcartesian-product* lcomp lcomp* lmerge lwhile luntil } related-words -HELP: llength -{ $values { "list" "a cons object" } { "n" "a non-negative integer" } } -{ $description "Outputs the length of the list. This should not be called on an infinite list." } -{ $see-also lnth cons car cdr } ; - -HELP: uncons -{ $values { "cons" "a cons object" } { "car" "the head of the list" } { "cdr" "the tail of the list" } } -{ $description "Put the head and tail of the list on the stack." } ; - -{ leach lreduce lmap lmap-with ltake lfilter lappend lfrom lfrom-by lconcat lcartesian-product lcartesian-product* lcomp lcomp* lmerge lreduce lwhile luntil } related-words - -HELP: leach -{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( obj -- )" } } -{ $description "Call the quotation for each item in the list." } ; - -HELP: lreduce -{ $values { "list" "a cons object" } { "identity" "an object" } { "quot" "a quotation with stack effect ( prev elt -- next )" } { "result" "the final result" } } -{ $description "Combines successive elements of the list using a binary operation, and outputs the final result." } ; - -HELP: lmap +HELP: lazy-map { $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( 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 } " 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: lmap-with +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" } } -{ $description "Variant of " { $link lmap } " which pushes a retained object on each invocation of the quotation." } ; +{ $description "Variant of " { $link lazy-map } " which pushes a retained object on each invocation of the quotation." } ; HELP: ltake { $values { "n" "a non negative integer" } { "list" "a cons object" } { "result" "resulting cons object" } } @@ -147,6 +85,8 @@ HELP: >list { $values { "object" "an object" } { "list" "a list" } } { $description "Convert the object into a list. Existing lists are passed through intact, sequences are converted using " { $link seq>list } " and other objects cause an error to be thrown." } { $see-also seq>list } ; + +{ leach foldl lazy-map lazy-map-with ltake lfilter lappend lfrom lfrom-by lconcat lcartesian-product lcartesian-product* lcomp lcomp* lmerge lwhile luntil } related-words HELP: lconcat { $values { "list" "a list of lists" } { "result" "a list" } } @@ -175,7 +115,7 @@ HELP: lmerge { $values { "list1" "a list" } { "list2" "a list" } { "result" "lazy list merging list1 and list2" } } { $description "Return the result of merging the two lists in a lazy manner." } { $examples - { $example "USING: lazy-lists prettyprint ;" "{ 1 2 3 } >list { 4 5 6 } >list lmerge list>array ." "{ 1 4 2 5 3 6 }" } + { $example "USING: lists.lazy prettyprint ;" "{ 1 2 3 } >list { 4 5 6 } >list lmerge list>array ." "{ 1 4 2 5 3 6 }" } } ; HELP: lcontents @@ -187,4 +127,3 @@ HELP: llines { $values { "stream" "a stream" } { "result" "a list" } } { $description "Returns a lazy list of all lines in the file. " { $link car } " returns the next lines in the file, " { $link cdr } " returns the remaining lines as a lazy list. " { $link nil? } " indicates end of file." } { $see-also lcontents } ; - diff --git a/extra/lazy-lists/lazy-lists-tests.factor b/extra/lists/lazy/lazy-tests.factor similarity index 83% rename from extra/lazy-lists/lazy-lists-tests.factor rename to extra/lists/lazy/lazy-tests.factor index 302299b452..5749f94364 100644 --- a/extra/lazy-lists/lazy-lists-tests.factor +++ b/extra/lists/lazy/lazy-tests.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2006 Matthew Willis and Chris Double. ! See http://factorcode.org/license.txt for BSD license. ! -USING: lazy-lists tools.test kernel math io sequences ; -IN: lazy-lists.tests +USING: lists lists.lazy tools.test kernel math io sequences ; +IN: lists.lazy.tests [ { 1 2 3 4 } ] [ { 1 2 3 4 } >list list>array @@ -25,5 +25,5 @@ IN: lazy-lists.tests ] unit-test [ { 4 5 6 } ] [ - 3 { 1 2 3 } >list [ + ] lmap-with list>array + 3 { 1 2 3 } >list [ + ] lazy-map-with list>array ] unit-test diff --git a/extra/lists/lazy/lazy.factor b/extra/lists/lazy/lazy.factor new file mode 100644 index 0000000000..6beb6e402d --- /dev/null +++ b/extra/lists/lazy/lazy.factor @@ -0,0 +1,392 @@ +! Copyright (C) 2004 Chris Double. +! See http://factorcode.org/license.txt for BSD license. +! +! Updated by Matthew Willis, July 2006 +! Updated by Chris Double, September 2006 +! Updated by James Cash, June 2008 +! +USING: kernel sequences math vectors arrays namespaces +quotations promises combinators io lists accessors ; +IN: lists.lazy + +M: promise car ( promise -- car ) + force car ; + +M: promise cdr ( promise -- cdr ) + force cdr ; + +M: promise nil? ( cons -- bool ) + force nil? ; + +! Both 'car' and 'cdr' are promises +TUPLE: lazy-cons car cdr ; + +: lazy-cons ( car cdr -- promise ) + [ promise ] bi@ \ lazy-cons boa + T{ promise f f t f } clone + [ set-promise-value ] keep ; + +M: lazy-cons car ( lazy-cons -- car ) + car>> force ; + +M: lazy-cons cdr ( lazy-cons -- cdr ) + cdr>> force ; + +M: lazy-cons nil? ( lazy-cons -- bool ) + nil eq? ; + +: 1lazy-list ( a -- lazy-cons ) + [ nil ] lazy-cons ; + +: 2lazy-list ( a b -- lazy-cons ) + 1lazy-list 1quotation lazy-cons ; + +: 3lazy-list ( a b c -- lazy-cons ) + 2lazy-list 1quotation lazy-cons ; + +TUPLE: memoized-cons original car cdr nil? ; + +: not-memoized ( -- obj ) + { } ; + +: not-memoized? ( obj -- bool ) + not-memoized eq? ; + +: ( cons -- memoized-cons ) + not-memoized not-memoized not-memoized + memoized-cons boa ; + +M: memoized-cons car ( memoized-cons -- car ) + dup car>> not-memoized? [ + dup original>> car [ >>car drop ] keep + ] [ + car>> + ] if ; + +M: memoized-cons cdr ( memoized-cons -- cdr ) + dup cdr>> not-memoized? [ + dup original>> cdr [ >>cdr drop ] keep + ] [ + cdr>> + ] if ; + +M: memoized-cons nil? ( memoized-cons -- bool ) + dup nil?>> not-memoized? [ + dup original>> nil? [ >>nil? drop ] keep + ] [ + nil?>> + ] if ; + +TUPLE: lazy-map cons quot ; + +C: lazy-map + +: lazy-map ( list quot -- result ) + over nil? [ 2drop nil ] [ ] if ; + +M: lazy-map car ( lazy-map -- car ) + [ cons>> car ] keep + quot>> call ; + +M: lazy-map cdr ( lazy-map -- cdr ) + [ cons>> cdr ] keep + quot>> lazy-map ; + +M: lazy-map nil? ( lazy-map -- bool ) + cons>> nil? ; + +: lazy-map-with ( value list quot -- result ) + with lazy-map ; + +TUPLE: lazy-take n cons ; + +C: lazy-take + +: ltake ( n list -- result ) + over zero? [ 2drop nil ] [ ] if ; + +M: lazy-take car ( lazy-take -- car ) + cons>> car ; + +M: lazy-take cdr ( lazy-take -- cdr ) + [ n>> 1- ] keep + cons>> cdr ltake ; + +M: lazy-take nil? ( lazy-take -- bool ) + dup n>> zero? [ + drop t + ] [ + cons>> nil? + ] if ; + +TUPLE: lazy-until cons quot ; + +C: lazy-until + +: luntil ( list quot -- result ) + over nil? [ drop ] [ ] if ; + +M: lazy-until car ( lazy-until -- car ) + cons>> car ; + +M: lazy-until cdr ( lazy-until -- cdr ) + [ cons>> uncons ] keep quot>> tuck call + [ 2drop nil ] [ luntil ] if ; + +M: lazy-until nil? ( lazy-until -- bool ) + drop f ; + +TUPLE: lazy-while cons quot ; + +C: lazy-while + +: lwhile ( list quot -- result ) + over nil? [ drop ] [ ] if ; + +M: lazy-while car ( lazy-while -- car ) + cons>> car ; + +M: lazy-while cdr ( lazy-while -- cdr ) + [ cons>> cdr ] keep quot>> lwhile ; + +M: lazy-while nil? ( lazy-while -- bool ) + [ car ] keep quot>> call not ; + +TUPLE: lazy-filter cons quot ; + +C: lazy-filter + +: lfilter ( list quot -- result ) + over nil? [ 2drop nil ] [ ] if ; + +: car-filter? ( lazy-filter -- ? ) + [ cons>> car ] [ quot>> ] bi call ; + +: skip ( lazy-filter -- ) + dup cons>> cdr >>cons drop ; + +M: lazy-filter car ( lazy-filter -- car ) + dup car-filter? [ cons>> ] [ dup skip ] if car ; + +M: lazy-filter cdr ( lazy-filter -- cdr ) + dup car-filter? [ + [ cons>> cdr ] [ quot>> ] bi lfilter + ] [ + dup skip cdr + ] if ; + +M: lazy-filter nil? ( lazy-filter -- bool ) + dup cons>> nil? [ + drop t + ] [ + dup car-filter? [ + drop f + ] [ + dup skip nil? + ] if + ] if ; + +: list>vector ( list -- vector ) + [ [ , ] leach ] V{ } make ; + +: list>array ( list -- array ) + [ [ , ] leach ] { } make ; + +TUPLE: lazy-append list1 list2 ; + +C: lazy-append + +: lappend ( list1 list2 -- result ) + over nil? [ nip ] [ ] if ; + +M: lazy-append car ( lazy-append -- car ) + list1>> car ; + +M: lazy-append cdr ( lazy-append -- cdr ) + [ list1>> cdr ] keep + list2>> lappend ; + +M: lazy-append nil? ( lazy-append -- bool ) + drop f ; + +TUPLE: lazy-from-by n quot ; + +C: lfrom-by lazy-from-by ( n quot -- list ) + +: lfrom ( n -- list ) + [ 1+ ] lfrom-by ; + +M: lazy-from-by car ( lazy-from-by -- car ) + n>> ; + +M: lazy-from-by cdr ( lazy-from-by -- cdr ) + [ n>> ] keep + quot>> dup slip lfrom-by ; + +M: lazy-from-by nil? ( lazy-from-by -- bool ) + drop f ; + +TUPLE: lazy-zip list1 list2 ; + +C: lazy-zip + +: lzip ( list1 list2 -- lazy-zip ) + over nil? over nil? or + [ 2drop nil ] [ ] if ; + +M: lazy-zip car ( lazy-zip -- car ) + [ list1>> car ] keep list2>> car 2array ; + +M: lazy-zip cdr ( lazy-zip -- cdr ) + [ list1>> cdr ] keep list2>> cdr lzip ; + +M: lazy-zip nil? ( lazy-zip -- bool ) + drop f ; + +TUPLE: sequence-cons index seq ; + +C: sequence-cons + +: seq>list ( index seq -- list ) + 2dup length >= [ + 2drop nil + ] [ + + ] if ; + +M: sequence-cons car ( sequence-cons -- car ) + [ index>> ] keep + seq>> nth ; + +M: sequence-cons cdr ( sequence-cons -- cdr ) + [ index>> 1+ ] keep + seq>> seq>list ; + +M: sequence-cons nil? ( sequence-cons -- bool ) + drop f ; + +: >list ( object -- list ) + { + { [ dup sequence? ] [ 0 swap seq>list ] } + { [ dup list? ] [ ] } + [ "Could not convert object to a list" throw ] + } cond ; + +TUPLE: lazy-concat car cdr ; + +C: lazy-concat + +DEFER: lconcat + +: (lconcat) ( car cdr -- list ) + over nil? [ + nip lconcat + ] [ + + ] if ; + +: lconcat ( list -- result ) + dup nil? [ + drop nil + ] [ + uncons swap (lconcat) + ] if ; + +M: lazy-concat car ( lazy-concat -- car ) + car>> car ; + +M: lazy-concat cdr ( lazy-concat -- cdr ) + [ car>> cdr ] keep cdr>> (lconcat) ; + +M: lazy-concat nil? ( lazy-concat -- bool ) + dup car>> nil? [ + cdr>> nil? + ] [ + drop f + ] if ; + +: lcartesian-product ( list1 list2 -- result ) + swap [ swap [ 2array ] lazy-map-with ] lazy-map-with lconcat ; + +: lcartesian-product* ( lists -- result ) + dup nil? [ + drop nil + ] [ + [ car ] keep cdr [ car lcartesian-product ] keep cdr list>array swap [ + swap [ swap [ suffix ] lazy-map-with ] lazy-map-with lconcat + ] reduce + ] if ; + +: lcomp ( list quot -- result ) + [ lcartesian-product* ] dip lazy-map ; + +: lcomp* ( list guards quot -- result ) + [ [ lcartesian-product* ] dip [ lfilter ] each ] dip lazy-map ; + +DEFER: lmerge + +: (lmerge) ( list1 list2 -- result ) + over [ car ] curry -rot + [ + dup [ car ] curry -rot + [ + [ cdr ] bi@ lmerge + ] 2curry lazy-cons + ] 2curry lazy-cons ; + +: lmerge ( list1 list2 -- result ) + { + { [ over nil? ] [ nip ] } + { [ dup nil? ] [ drop ] } + { [ t ] [ (lmerge) ] } + } cond ; + +TUPLE: lazy-io stream car cdr quot ; + +C: lazy-io + +: lcontents ( stream -- result ) + f f [ stream-read1 ] ; + +: llines ( stream -- result ) + f f [ stream-readln ] ; + +M: lazy-io car ( lazy-io -- car ) + dup car>> dup [ + nip + ] [ + drop dup stream>> over quot>> call + swap dupd set-lazy-io-car + ] if ; + +M: lazy-io cdr ( lazy-io -- cdr ) + dup cdr>> dup [ + nip + ] [ + drop dup + [ stream>> ] keep + [ quot>> ] keep + car [ + [ f f ] dip [ >>cdr drop ] keep + ] [ + 3drop nil + ] if + ] if ; + +M: lazy-io nil? ( lazy-io -- bool ) + car not ; + +INSTANCE: sequence-cons list +INSTANCE: memoized-cons list +INSTANCE: promise list +INSTANCE: lazy-io list +INSTANCE: lazy-concat list +INSTANCE: lazy-cons list +INSTANCE: lazy-map list +INSTANCE: lazy-take list +INSTANCE: lazy-append list +INSTANCE: lazy-from-by list +INSTANCE: lazy-zip list +INSTANCE: lazy-while list +INSTANCE: lazy-until list +INSTANCE: lazy-filter list diff --git a/extra/lazy-lists/old-doc.html b/extra/lists/lazy/old-doc.html similarity index 100% rename from extra/lazy-lists/old-doc.html rename to extra/lists/lazy/old-doc.html diff --git a/extra/lazy-lists/summary.txt b/extra/lists/lazy/summary.txt similarity index 100% rename from extra/lazy-lists/summary.txt rename to extra/lists/lazy/summary.txt diff --git a/extra/lazy-lists/tags.txt b/extra/lists/lazy/tags.txt similarity index 100% rename from extra/lazy-lists/tags.txt rename to extra/lists/lazy/tags.txt diff --git a/extra/lists/lists-docs.factor b/extra/lists/lists-docs.factor new file mode 100644 index 0000000000..15faf8d002 --- /dev/null +++ b/extra/lists/lists-docs.factor @@ -0,0 +1,104 @@ +! Copyright (C) 2006 Chris Double. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; + +IN: lists + +{ car cons cdr nil nil? list? uncons } related-words + +HELP: cons +{ $values { "car" "the head of the lazy list" } { "cdr" "the tail of the lazy list" } { "cons" "a cons object" } } +{ $description "Constructs a cons cell." } ; + +HELP: car +{ $values { "cons" "a cons object" } { "car" "the first item in the list" } } +{ $description "Returns the first item in the list." } ; + +HELP: cdr +{ $values { "cons" "a cons object" } { "cdr" "a cons object" } } +{ $description "Returns the tail of the list." } ; + +HELP: nil +{ $values { "symbol" "The empty cons (+nil+)" } } +{ $description "Returns a symbol representing the empty list" } ; + +HELP: nil? +{ $values { "cons" "a cons object" } { "?" "a boolean" } } +{ $description "Return true if the cons object is the nil cons." } ; + +HELP: list? ( object -- ? ) +{ $values { "object" "an object" } { "?" "a boolean" } } +{ $description "Returns true if the object conforms to the list protocol." } ; + +{ 1list 2list 3list } related-words + +HELP: 1list +{ $values { "obj" "an object" } { "cons" "a cons object" } } +{ $description "Create a list with 1 element." } ; + +HELP: 2list +{ $values { "a" "an object" } { "b" "an object" } { "cons" "a cons object" } } +{ $description "Create a list with 2 elements." } ; + +HELP: 3list +{ $values { "a" "an object" } { "b" "an object" } { "c" "an object" } { "cons" "a cons object" } } +{ $description "Create a list with 3 elements." } ; + +HELP: lnth +{ $values { "n" "an integer index" } { "list" "a cons object" } { "elt" "the element at the nth index" } } +{ $description "Outputs the nth element of the list." } +{ $see-also llength cons car cdr } ; + +HELP: llength +{ $values { "list" "a cons object" } { "n" "a non-negative integer" } } +{ $description "Outputs the length of the list. This should not be called on an infinite list." } +{ $see-also lnth cons car cdr } ; + +HELP: uncons +{ $values { "cons" "a cons object" } { "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 + +HELP: leach +{ $values { "list" "a cons object" } { "quot" "a quotation with stack effect ( 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" } } +{ $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" } } +{ $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" } } +{ $description "Applies the quotation to each element of the list in order, collecting the new elements into a new list." } ; + +HELP: lreverse +{ $values { "list" "a cons object" } { "newlist" "a new cons object" } } +{ $description "Reverses the input list, outputing a new, reversed list" } ; + +HELP: list>seq +{ $values { "list" "a cons object" } { "array" "an array object" } } +{ $description "Turns the given cons object into an array, maintaing order." } ; + +HELP: seq>list +{ $values { "seq" "a sequence" } { "list" "a cons object" } } +{ $description "Turns the given array into a cons object, maintaing order." } ; + +HELP: cons>seq +{ $values { "cons" "a cons object" } { "array" "an array object" } } +{ $description "Recursively turns the given cons object into an array, maintaing order and also converting nested lists." } ; + +HELP: seq>cons +{ $values { "seq" "a sequence object" } { "cons" "a cons object" } } +{ $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" } } +{ $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." } ; + diff --git a/extra/lists/lists-tests.factor b/extra/lists/lists-tests.factor new file mode 100644 index 0000000000..cdc51b76e8 --- /dev/null +++ b/extra/lists/lists-tests.factor @@ -0,0 +1,66 @@ +! Copyright (C) 2008 James Cash +! See http://factorcode.org/license.txt for BSD license. +USING: tools.test lists math ; + +IN: lists.tests + +{ { 3 4 5 6 7 } } [ + { 1 2 3 4 5 } seq>list [ 2 + ] lmap list>seq +] unit-test + +{ { 3 4 5 6 } } [ + T{ cons f 1 + T{ cons f 2 + T{ cons f 3 + T{ cons f 4 + +nil+ } } } } [ 2 + ] lmap>array +] unit-test + +{ 10 } [ + T{ cons f 1 + T{ cons f 2 + T{ cons f 3 + T{ cons f 4 + +nil+ } } } } 0 [ + ] foldl +] unit-test + +{ T{ cons f + 1 + T{ cons f + 2 + T{ cons f + T{ cons f + 3 + T{ cons f + 4 + T{ cons f + T{ cons f 5 +nil+ } + +nil+ } } } + +nil+ } } } +} [ + { 1 2 { 3 4 { 5 } } } seq>cons +] unit-test + +{ { 1 2 { 3 4 { 5 } } } } [ + { 1 2 { 3 4 { 5 } } } seq>cons cons>seq +] unit-test + +{ T{ cons f 2 T{ cons f 3 T{ cons f 4 T{ cons f 5 +nil+ } } } } } [ + { 1 2 3 4 } seq>cons [ 1+ ] lmap +] unit-test + +{ 15 } [ + { 1 2 3 4 5 } seq>list 0 [ + ] foldr +] unit-test + +{ { 5 4 3 2 1 } } [ + { 1 2 3 4 5 } seq>list lreverse list>seq +] unit-test + +{ 5 } [ + { 1 2 3 4 5 } seq>list llength +] unit-test + +{ { 3 4 { 5 6 { 7 } } } } [ + { 1 2 { 3 4 { 5 } } } seq>cons [ atom? ] [ 2 + ] traverse cons>seq +] unit-test \ No newline at end of file diff --git a/extra/lists/lists.factor b/extra/lists/lists.factor new file mode 100644 index 0000000000..13d77f757a --- /dev/null +++ b/extra/lists/lists.factor @@ -0,0 +1,107 @@ +! Copyright (C) 2008 Chris Double & James Cash +! See http://factorcode.org/license.txt for BSD license. +USING: kernel sequences accessors math arrays vectors classes words locals ; + +IN: lists + +! List Protocol +MIXIN: list +GENERIC: car ( cons -- car ) +GENERIC: cdr ( cons -- cdr ) +GENERIC: nil? ( object -- ? ) + +TUPLE: cons car cdr ; + +C: cons cons + +M: cons car ( cons -- car ) + car>> ; + +M: cons cdr ( cons -- cdr ) + cdr>> ; + +SYMBOL: +nil+ +M: word nil? +nil+ eq? ; +M: object nil? drop f ; + +: atom? ( obj -- ? ) [ list? ] [ nil? ] bi or not ; + +: nil ( -- symbol ) +nil+ ; + +: uncons ( cons -- cdr car ) + [ cdr ] [ car ] bi ; + +: 1list ( obj -- cons ) + nil cons ; + +: 2list ( a b -- cons ) + nil cons cons ; + +: 3list ( a b c -- cons ) + nil cons cons cons ; + +: cadr ( cons -- elt ) + cdr car ; + +: 2car ( cons -- car caar ) + [ car ] [ cdr car ] bi ; + +: 3car ( cons -- car caar caaar ) + [ car ] [ cdr car ] [ cdr cdr car ] tri ; + +: lnth ( n list -- elt ) + swap [ cdr ] times car ; + +: (leach) ( list quot -- cdr quot ) + [ [ car ] dip call ] [ [ cdr ] dip ] 2bi ; inline + +: leach ( list quot -- ) + over nil? [ 2drop ] [ (leach) leach ] if ; inline + +: lmap ( list quot -- result ) + over nil? [ drop ] [ (leach) lmap cons ] if ; inline + +: foldl ( list identity quot -- result ) swapd leach ; inline + +: foldr ( list identity quot -- result ) + pick nil? [ [ drop ] [ ] [ drop ] tri* ] [ + [ [ cdr ] 2dip foldr ] [ nip [ car ] dip ] 3bi + call + ] if ; inline + +: llength ( list -- n ) + 0 [ drop 1+ ] foldl ; + +: lreverse ( list -- newlist ) + nil [ swap cons ] foldl ; + +: seq>list ( seq -- list ) + nil [ swap cons ] reduce ; + +: same? ( obj1 obj2 -- ? ) + [ class ] bi@ = ; + +: seq>cons ( seq -- cons ) + [ ] keep nil [ tuck same? [ seq>cons ] when f cons swap >>cdr ] with reduce ; + +: (lmap>array) ( acc cons quot -- newcons ) + over nil? [ 2drop ] + [ [ uncons ] dip [ call ] keep swapd [ suffix ] 2dip (lmap>array) ] if ; inline + +: lmap>array ( cons quot -- newcons ) + { } -rot (lmap>array) ; inline + +: lmap-as ( cons quot exemplar -- seq ) + [ lmap>array ] dip like ; + +: cons>seq ( cons -- array ) + [ dup cons? [ cons>seq ] when ] lmap>array ; + +: list>seq ( list -- array ) + [ ] lmap>array ; + +: traverse ( list pred quot -- result ) + [ 2over call [ tuck [ call ] 2dip ] when + pick list? [ traverse ] [ 2drop ] if ] 2curry lmap ; + +INSTANCE: cons list \ No newline at end of file diff --git a/extra/lists/summary.txt b/extra/lists/summary.txt new file mode 100644 index 0000000000..60a18867ab --- /dev/null +++ b/extra/lists/summary.txt @@ -0,0 +1 @@ +Implementation of lisp-style linked lists diff --git a/extra/lists/tags.txt b/extra/lists/tags.txt new file mode 100644 index 0000000000..e44334b2b5 --- /dev/null +++ b/extra/lists/tags.txt @@ -0,0 +1,3 @@ +cons +lists +sequences diff --git a/extra/math/erato/erato-tests.factor b/extra/math/erato/erato-tests.factor index 9244fa62e2..041cb8dc3a 100644 --- a/extra/math/erato/erato-tests.factor +++ b/extra/math/erato/erato-tests.factor @@ -1,6 +1,6 @@ ! Copyright (c) 2007 Samuel Tardieu. ! See http://factorcode.org/license.txt for BSD license. -USING: lazy-lists math.erato tools.test ; +USING: lists.lazy math.erato tools.test ; IN: math.erato.tests [ { 2 3 5 7 11 13 17 19 } ] [ 20 lerato list>array ] unit-test diff --git a/extra/math/erato/erato.factor b/extra/math/erato/erato.factor index 40de92e3b1..b9d997c038 100644 --- a/extra/math/erato/erato.factor +++ b/extra/math/erato/erato.factor @@ -1,6 +1,6 @@ ! Copyright (c) 2007 Samuel Tardieu. ! See http://factorcode.org/license.txt for BSD license. -USING: bit-arrays kernel lazy-lists math math.functions math.primes.list +USING: bit-arrays kernel lists.lazy math math.functions math.primes.list math.ranges sequences ; IN: math.erato diff --git a/extra/math/primes/factors/factors.factor b/extra/math/primes/factors/factors.factor index 2f70ab24b4..aba7e90bc9 100644 --- a/extra/math/primes/factors/factors.factor +++ b/extra/math/primes/factors/factors.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2007 Samuel Tardieu. ! See http://factorcode.org/license.txt for BSD license. -USING: arrays kernel lazy-lists math math.primes namespaces sequences ; +USING: arrays kernel lists math math.primes namespaces sequences ; IN: math.primes.factors [ swap uncons >r pick call r> swap (factors) ] [ 3drop ] if ; + dup 1 > [ swap uncons swap >r pick call r> swap (factors) ] [ 3drop ] if ; : (decompose) ( n quot -- seq ) [ lprimes rot (factors) ] { } make ; diff --git a/extra/math/primes/primes-tests.factor b/extra/math/primes/primes-tests.factor index b1bcf79a49..186acc9b11 100644 --- a/extra/math/primes/primes-tests.factor +++ b/extra/math/primes/primes-tests.factor @@ -1,4 +1,4 @@ -USING: arrays math.primes tools.test lazy-lists ; +USING: arrays math.primes tools.test lists.lazy ; { 1237 } [ 1234 next-prime ] unit-test { f t } [ 1234 prime? 1237 prime? ] unit-test diff --git a/extra/math/primes/primes.factor b/extra/math/primes/primes.factor index 2eeaca6c92..59aebbf0dd 100644 --- a/extra/math/primes/primes.factor +++ b/extra/math/primes/primes.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2007 Samuel Tardieu. ! See http://factorcode.org/license.txt for BSD license. -USING: combinators kernel lazy-lists math math.functions math.miller-rabin +USING: combinators kernel lists.lazy math math.functions math.miller-rabin math.order math.primes.list math.ranges sequences sorting ; IN: math.primes diff --git a/extra/http/mime/authors.txt b/extra/mime-types/authors.txt similarity index 100% rename from extra/http/mime/authors.txt rename to extra/mime-types/authors.txt diff --git a/extra/mime-types/mime-types-tests.factor b/extra/mime-types/mime-types-tests.factor new file mode 100644 index 0000000000..925eca2e9d --- /dev/null +++ b/extra/mime-types/mime-types-tests.factor @@ -0,0 +1,6 @@ +IN: mime-types.tests +USING: mime-types tools.test ; + +[ "application/postscript" ] [ "foo.ps" mime-type ] unit-test +[ "application/octet-stream" ] [ "foo.ps.gz" mime-type ] unit-test +[ "text/plain" ] [ "foo.factor" mime-type ] unit-test diff --git a/extra/mime-types/mime-types.factor b/extra/mime-types/mime-types.factor new file mode 100755 index 0000000000..a228a8904c --- /dev/null +++ b/extra/mime-types/mime-types.factor @@ -0,0 +1,23 @@ +! Copyright (C) 2004, 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: io.files io.encodings.ascii assocs sequences splitting +kernel namespaces fry memoize ; +IN: mime-types + +MEMO: mime-db ( -- seq ) + "resource:extra/mime-types/mime.types" ascii file-lines + [ "#" head? not ] filter [ " \t" split harvest ] map harvest ; + +: nonstandard-mime-types ( -- assoc ) + H{ + { "factor" "text/plain" } + { "cgi" "application/x-cgi-script" } + { "fhtml" "application/x-factor-server-page" } + } ; + +MEMO: mime-types ( -- assoc ) + [ mime-db [ unclip '[ , _ set ] each ] each ] H{ } make-assoc + nonstandard-mime-types assoc-union ; + +: mime-type ( filename -- mime-type ) + file-extension mime-types at "application/octet-stream" or ; diff --git a/extra/mime-types/mime.types b/extra/mime-types/mime.types new file mode 100644 index 0000000000..b602e9dc68 --- /dev/null +++ b/extra/mime-types/mime.types @@ -0,0 +1,988 @@ +# This is a comment. I love comments. + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# MIME type Extensions +application/activemessage +application/andrew-inset ez +application/applefile +application/atom+xml atom +application/atomcat+xml atomcat +application/atomicmail +application/atomsvc+xml atomsvc +application/auth-policy+xml +application/batch-smtp +application/beep+xml +application/cals-1840 +application/ccxml+xml ccxml +application/cellml+xml +application/cnrp+xml +application/commonground +application/conference-info+xml +application/cpl+xml +application/csta+xml +application/cstadata+xml +application/cybercash +application/davmount+xml davmount +application/dca-rft +application/dec-dx +application/dialog-info+xml +application/dicom +application/dns +application/dvcs +application/ecmascript ecma +application/edi-consent +application/edi-x12 +application/edifact +application/epp+xml +application/eshop +application/fastinfoset +application/fastsoap +application/fits +application/font-tdpfr pfr +application/h224 +application/http +application/hyperstudio stk +application/iges +application/im-iscomposing+xml +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/javascript js +application/json json +application/kpml-request+xml +application/kpml-response+xml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc mrc +application/mathematica ma nb mb +application/mathml+xml mathml +application/mbms-associated-procedure-description+xml +application/mbms-deregister+xml +application/mbms-envelope+xml +application/mbms-msk+xml +application/mbms-msk-response+xml +application/mbms-protection-description+xml +application/mbms-reception-report+xml +application/mbms-register+xml +application/mbms-register-response+xml +application/mbms-user-service-description+xml +application/mbox mbox +application/mediaservercontrol+xml mscml +application/mikey +application/mp4 mp4s +application/mpeg4-generic +application/mpeg4-iod +application/mpeg4-iod-xmt +application/msword doc dot +application/mxf mxf +application/nasdata +application/news-message-id +application/news-transmission +application/nss +application/ocsp-request +application/ocsp-response +application/octet-stream bin dms lha lzh class so iso dmg dist distz pkg bpk dump elc scpt +application/oda oda +application/oebps-package+xml +application/ogg ogg +application/parityfec +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +application/pidf+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/poc-settings+xml +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww cww +application/prs.nprend +application/prs.plucker +application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/remote-printing +application/resource-lists+xml rl +application/riscos +application/rlmi+xml +application/rls-services+xml rs +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/rtx +application/samlassertion+xml +application/samlmetadata+xml +application/sbml+xml sbml +application/sdp sdp +application/set-payment +application/set-payment-initiation setpay +application/set-registration +application/set-registration-initiation setreg +application/sgml +application/sgml-open-catalog +application/shf+xml shf +application/sieve +application/simple-filter+xml +application/simple-message-summary +application/simplesymbolcontainer +application/slate +application/smil +application/smil+xml smi smil +application/soap+fastinfoset +application/soap+xml +application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/ssml+xml ssml +application/timestamp-query +application/timestamp-reply +application/tve-trigger +application/vemmi +application/vividence.scriptfile +application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp.sms +application/vnd.3gpp2.bcmcsinfo+xml +application/vnd.3gpp2.sms +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.aether.imp +application/vnd.amiga.ami ami +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.audiograph aep +application/vnd.autopackage +application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.cab-jscript +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.commerce-battelle +application/vnd.commonspace csp cst +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.cups-pdf +application/vnd.cups-postscript +application/vnd.cups-ppd ppd +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.curl curl +application/vnd.cybank +application/vnd.data-vision.rdz rdz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.dvb.esgcontainer +application/vnd.dvb.ipdcesgaccess +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart mag +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.fdf fdf +application/vnd.ffsns +application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.framemaker fm frame maker +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.art-ex +application/vnd.fujixerox.art4 +application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.httphone +application/vnd.hzn-3d-crossword x3d +application/vnd.ibm.afplinedata +application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.informedcontrol.rms+xml +application/vnd.intercon.formnet xpw xpx +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.jam jam +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.marlin.drm.actiontoken+xml +application/vnd.marlin.drm.conftoken+xml +application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-asf asf +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-project mpp mpt +application/vnd.ms-tnef +application/vnd.ms-wmdrm.lic-chlg-req +application/vnd.ms-wmdrm.lic-resp +application/vnd.ms-wmdrm.meter-chlg-req +application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.msign +application/vnd.music-niff +application/vnd.musician mus +application/vnd.ncd.control +application/vnd.nervana +application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.catalogs +application/vnd.nokia.conml+wbxml +application/vnd.nokia.conml+xml +application/vnd.nokia.isds-radio-presets +application/vnd.nokia.iptv.config+xml +application/vnd.nokia.landmark+wbxml +application/vnd.nokia.landmark+xml +application/vnd.nokia.landmarkcollection+xml +application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.ncd +application/vnd.nokia.pcd+wbxml +application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template otf +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master otm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.obn +application/vnd.olpc-sugar xo +application/vnd.oma-scws-config +application/vnd.oma-scws-http-request +application/vnd.oma-scws-http-response +application/vnd.oma.bcast.associated-procedure-parameter+xml +application/vnd.oma.bcast.drm-trigger+xml +application/vnd.oma.bcast.imd+xml +application/vnd.oma.bcast.notification+xml +application/vnd.oma.bcast.sgboot +application/vnd.oma.bcast.sgdd+xml +application/vnd.oma.bcast.sgdu +application/vnd.oma.bcast.simple-symbol-container +application/vnd.oma.bcast.smartcard-trigger+xml +application/vnd.oma.bcast.sprov+xml +application/vnd.oma.dd2+xml dd2 +application/vnd.oma.drm.risd+xml +application/vnd.oma.group-usage-list+xml +application/vnd.oma.poc.groups+xml +application/vnd.oma.xcap-directory+xml +application/vnd.omads-email+xml +application/vnd.omads-file+xml +application/vnd.omads-folder+xml +application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +application/vnd.osa.netdeploy +application/vnd.osgi.dp dp +application/vnd.otps.ct-kip+xml +application/vnd.palm prc pdb pqa oprc +application/vnd.paos.xml +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.pwg-multiplexed +application/vnd.pwg-xhtml-print+xml +application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +application/vnd.rapid +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml +application/vnd.renlearn.rlprint +application/vnd.rn-realmedia rm +application/vnd.ruckus.download +application/vnd.s3sms +application/vnd.scribus +application/vnd.sealed.3df +application/vnd.sealed.csf +application/vnd.sealed.doc +application/vnd.sealed.eml +application/vnd.sealed.mht +application/vnd.sealed.net +application/vnd.sealed.ppt +application/vnd.sealed.tiff +application/vnd.sealed.xls +application/vnd.sealedmedia.softseal.html +application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.street-stream +application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +application/vnd.swiftview-ics +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.truedoc +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx vcx +application/vnd.vd-study +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +application/vnd.vividence.scriptfile +application/vnd.vsf vsf +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wfa.wsc +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +application/vnd.wv.csp+wbxml +application/vnd.wv.csp+xml +application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.xmpie.cpkg +application/vnd.xmpie.dpkg +application/vnd.xmpie.plan +application/vnd.xmpie.ppkg +application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/watcherinfo+xml +application/whoispp-query +application/whoispp-response +application/winhlp hlp +application/wita +application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-ace-compressed ace +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cdlink vcd +application/x-chat chat +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr fgd +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-stuffit sit +application/x-stuffitx sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x400-bp +application/xcap-att+xml +application/xcap-caps+xml +application/xcap-el+xml +application/xcap-error+xml +application/xcap-ns+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +application/xml xml xsl +application/xml-dtd dtd +application/xml-external-parsed-entity +application/xmpp+xml +application/xop+xml xop +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/zip zip +audio/32kadpcm +audio/3gpp +audio/3gpp2 +audio/ac3 +audio/amr +audio/amr-wb +audio/amr-wb+ +audio/asc +audio/basic au snd +audio/bv16 +audio/bv32 +audio/clearmode +audio/cn +audio/dat12 +audio/dls +audio/dsr-es201108 +audio/dsr-es202050 +audio/dsr-es202211 +audio/dsr-es202212 +audio/dvi4 +audio/eac3 +audio/evrc +audio/evrc-qcp +audio/evrc0 +audio/evrc1 +audio/evrcb +audio/evrcb0 +audio/evrcb1 +audio/g722 +audio/g7221 +audio/g723 +audio/g726-16 +audio/g726-24 +audio/g726-32 +audio/g726-40 +audio/g728 +audio/g729 +audio/g7291 +audio/g729d +audio/g729e +audio/gsm +audio/gsm-efr +audio/ilbc +audio/l16 +audio/l20 +audio/l24 +audio/l8 +audio/lpc +audio/midi mid midi kar rmi +audio/mobile-xmf +audio/mp4 mp4a +audio/mp4a-latm m4a m4p +audio/mpa +audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +audio/mpeg4-generic +audio/parityfec +audio/pcma +audio/pcmu +audio/prs.sid +audio/qcelp +audio/red +audio/rtp-enc-aescm128 +audio/rtp-midi +audio/rtx +audio/smv +audio/smv0 +audio/smv-qcp +audio/sp-midi +audio/t140c +audio/t38 +audio/telephone-event +audio/tone +audio/vdvi +audio/vmr-wb +audio/vnd.3gpp.iufp +audio/vnd.4sb +audio/vnd.audiokoz +audio/vnd.celp +audio/vnd.cisco.nse +audio/vnd.cmles.radio-events +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds eol +audio/vnd.dlna.adts +audio/vnd.dolby.mlp +audio/vnd.everad.plj +audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.nokia.mobile-xmf +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.sealedmedia.softseal.mpeg +audio/vnd.vmx.cvsd +audio/wav wav +audio/x-aiff aif aiff aifc +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +audio/x-wav wav +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +chemical/x-pdb pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +image/fits +image/g3fax g3 +image/gif gif +image/ief ief +image/jp2 jp2 +image/jpeg jpeg jpg jpe +image/jpm +image/jpx +image/naplps +image/pict pict pic pct +image/png png +image/prs.btif btif +image/prs.pti +image/svg+xml svg svgz +image/t38 +image/tiff tiff tif +image/tiff-fx +image/vnd.adobe.photoshop psd +image/vnd.cns.inf2 +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.globalgraphics.pgb +image/vnd.microsoft.icon ico +image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.net-fpx npx +image/vnd.sealed.png +image/vnd.sealedmedia.softseal.gif +image/vnd.sealedmedia.softseal.jpg +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/x-cmu-raster ras +image/x-cmx cmx +image/x-icon +image/x-macpaint pntg pnt mac +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-quicktime qtif qti +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/cpim +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/news +message/partial +message/rfc822 eml mime +message/s-http +message/sip +message/sipfrag +message/tracking-status +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf dwf +model/vnd.flatland.3dml +model/vnd.gdl gdl +model/vnd.gs.gdl +model/vnd.gtw gtw +model/vnd.moml+xml +model/vnd.mts mts +model/vnd.parasolid.transmit.binary +model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/calendar ics ifb +text/css css +text/csv csv +text/directory +text/dns +text/enriched +text/html html htm +text/parityfec +text/plain txt text conf def list log in +text/prs.fallenstein.rst +text/prs.lines.tag dsc +text/red +text/rfc822-headers +text/richtext rtx +text/rtf +text/rtp-enc-aescm128 +text/rtx +text/sgml sgml sgm +text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/uri-list uri uris urls +text/vnd.abc +text/vnd.curl +text/vnd.dmclientscript +text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.iptc.newsml +text/vnd.iptc.nitf +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.net2phone.commcenter.command +text/vnd.sun.j2me.app-descriptor jad +text/vnd.trolltech.linguist +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-pascal p pas +text/x-java-source java +text/x-setext etx +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +text/xml +text/xml-external-parsed-entity +video/3gpp 3gp +video/3gpp-tt +video/3gpp2 3g2 +video/bmpeg +video/bt656 +video/celb +video/dv +video/h261 h261 +video/h263 h263 +video/h263-1998 +video/h263-2000 +video/h264 h264 +video/jpeg jpgv +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +video/mp1s +video/mp2p +video/mp2t +video/mp4 mp4 mp4v mpg4 m4v +video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +video/mpeg4-generic +video/mpv +video/nv +video/parityfec +video/pointer +video/quicktime qt mov +video/raw +video/rtp-enc-aescm128 +video/rtx +video/smpte292m +video/vc1 +video/vnd.dlna.mpeg-tts +video/vnd.fvt fvt +video/vnd.hns.video +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.nokia.interleaved-multimedia +video/vnd.nokia.videovoip +video/vnd.objectvideo +video/vnd.sealed.mpeg1 +video/vnd.sealed.mpeg4 +video/vnd.sealed.swf +video/vnd.sealedmedia.softseal.mov +video/vnd.vivo viv +video/x-dv dv dif +video/x-fli fli +video/x-ms-asf asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice diff --git a/extra/monads/monads-tests.factor b/extra/monads/monads-tests.factor index 52cdc47ac6..d0014b5abe 100644 --- a/extra/monads/monads-tests.factor +++ b/extra/monads/monads-tests.factor @@ -1,4 +1,4 @@ -USING: tools.test monads math kernel sequences lazy-lists promises ; +USING: tools.test monads math kernel sequences lists promises ; IN: monads.tests [ 5 ] [ 1 identity-monad return [ 4 + ] fmap run-identity ] unit-test diff --git a/extra/monads/monads.factor b/extra/monads/monads.factor index 0f4138c985..c1ab4400ba 100644 --- a/extra/monads/monads.factor +++ b/extra/monads/monads.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: arrays kernel sequences sequences.deep splitting -accessors fry locals combinators namespaces lazy-lists +accessors fry locals combinators namespaces lists lists.lazy shuffle ; IN: monads @@ -124,7 +124,7 @@ M: list-monad fail 2drop nil ; M: list monad-of drop list-monad ; -M: list >>= '[ , _ lmap lconcat ] ; +M: list >>= '[ , _ lazy-map lconcat ] ; ! State SINGLETON: state-monad diff --git a/extra/morse/morse.factor b/extra/morse/morse.factor index 9d335896be..591915b317 100644 --- a/extra/morse/morse.factor +++ b/extra/morse/morse.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2007, 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs combinators hashtables kernel lazy-lists math namespaces openal parser-combinators promises sequences strings symbols synth synth.buffers unicode.case ; +USING: accessors assocs combinators hashtables kernel lists math namespaces openal parser-combinators promises sequences strings symbols synth synth.buffers unicode.case ; IN: morse r cache-key* refcounts get + [ [ 0 ] unless* ] r> compose change-at ; + +TUPLE: cache-entry tex dims ; +C: cache-entry + +: make-entry ( gadget -- entry ) + dup render* + [ swap cache-key* textures get set-at ] keep ; + +: get-entry ( gadget -- {texture,dims} ) + dup cache-key* textures get at + [ nip ] [ make-entry ] if* ; + +: get-dims ( gadget -- dims ) + get-entry dims>> ; + +: get-texture ( gadget -- texture ) + get-entry tex>> ; + +: release-texture ( gadget -- ) + cache-key* textures get delete-at* + [ tex>> delete-texture ] [ drop ] if ; + +M: texture-gadget graft* ( gadget -- ) [ 1+ ] refcount-change ; + +M: texture-gadget ungraft* ( gadget -- ) + dup [ 1- ] refcount-change + dup cache-key* refcounts get at + zero? [ release-texture ] [ drop ] if ; : 2^-ceil ( x -- y ) dup 2 < [ 2 * ] [ 1- log2 1+ 2^ ] if ; foldable flushable @@ -13,29 +60,29 @@ TUPLE: texture-gadget bytes format dim tex ; : 2^-bounds ( dim -- dim' ) [ 2^-ceil ] map ; foldable flushable -: ( bytes format dim -- gadget ) - texture-gadget construct-gadget - swap >>dim - swap >>format - swap >>bytes ; - -:: render ( gadget -- ) +:: (render-bytes) ( dims bytes format texture -- ) GL_ENABLE_BIT [ GL_TEXTURE_2D glEnable - GL_TEXTURE_2D gadget tex>> glBindTexture + GL_TEXTURE_2D texture glBindTexture GL_TEXTURE_2D 0 GL_RGBA - gadget dim>> 2^-bounds first2 + dims 2^-bounds first2 0 - gadget format>> + format GL_UNSIGNED_BYTE - gadget bytes>> + bytes glTexImage2D init-texture GL_TEXTURE_2D 0 glBindTexture ] do-attribs ; +: render-bytes ( dims bytes format -- texture ) + gen-texture [ (render-bytes) ] keep ; + +: render-bytes* ( dims bytes format -- texture dims ) + pick >r render-bytes r> ; + :: four-corners ( dim -- ) [let* | w [ dim first ] h [ dim second ] @@ -54,19 +101,12 @@ M: texture-gadget draw-gadget* ( gadget -- ) white gl-color 1.0 -1.0 glPixelZoom GL_TEXTURE_2D glEnable - GL_TEXTURE_2D over tex>> glBindTexture + GL_TEXTURE_2D over get-texture glBindTexture GL_QUADS [ - dim>> four-corners + get-dims four-corners ] do-state GL_TEXTURE_2D 0 glBindTexture ] do-attribs ] with-translation ; -M: texture-gadget graft* ( gadget -- ) - gen-texture >>tex [ render ] - [ f >>bytes f >>format drop ] bi ; - -M: texture-gadget ungraft* ( gadget -- ) - tex>> delete-texture ; - -M: texture-gadget pref-dim* ( gadget -- dim ) dim>> ; +M: texture-gadget pref-dim* ( gadget -- dim ) get-dims ; diff --git a/extra/openssl/openssl.factor b/extra/openssl/openssl.factor index 03343820db..28fa49dfce 100755 --- a/extra/openssl/openssl.factor +++ b/extra/openssl/openssl.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors byte-arrays kernel debugger sequences namespaces math math.order combinators init alien alien.c-types alien.strings libc -continuations destructors debugger inspector +continuations destructors debugger inspector splitting locals unicode.case openssl.libcrypto openssl.libssl io.backend io.ports io.files io.encodings.8-bit io.sockets.secure @@ -188,8 +188,12 @@ M: ssl-handle dispose* [ 256 X509_NAME_get_text_by_NID ] keep swap -1 = [ drop f ] [ latin1 alien>string ] if ; +: common-names-match? ( expected actual -- ? ) + [ >lower ] bi@ "*." ?head [ tail? ] [ = ] if ; + : check-common-name ( host ssl-handle -- ) - SSL_get_peer_certificate common-name 2dup [ >lower ] bi@ = + SSL_get_peer_certificate common-name + 2dup common-names-match? [ 2drop ] [ common-name-verify-error ] if ; M: openssl check-certificate ( host ssl -- ) diff --git a/extra/pango/cairo/cairo.factor b/extra/pango/cairo/cairo.factor index 889052c385..1ff5328ee0 100644 --- a/extra/pango/cairo/cairo.factor +++ b/extra/pango/cairo/cairo.factor @@ -4,12 +4,13 @@ ! pangocairo bindings, from pango/pangocairo.h USING: cairo.ffi alien.c-types math alien.syntax system combinators alien +memoize arrays pango pango.fonts ; IN: pango.cairo << "pangocairo" { -! { [ os winnt? ] [ "libpangocairo-1.dll" ] } -! { [ os macosx? ] [ "libpangocairo.dylib" ] } + { [ os winnt? ] [ "libpangocairo-1.0-0.dll" ] } + { [ os macosx? ] [ "libpangocairo-1.0.0.dylib" ] } { [ os unix? ] [ "libpangocairo-1.0.so" ] } } cond "cdecl" add-library >> @@ -92,40 +93,26 @@ pango_cairo_error_underline_path ( cairo_t* cr, double x, double y, double width ! Higher level words and combinators ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -USING: destructors accessors namespaces kernel cairo ; - -TUPLE: pango-layout alien ; -C: pango-layout -M: pango-layout dispose ( alien -- ) alien>> g_object_unref ; - -: layout ( -- pango-layout ) pango-layout get ; +USING: pango.layouts +destructors accessors namespaces kernel cairo ; : (with-pango) ( layout quot -- ) >r alien>> pango-layout r> with-variable ; inline -: with-pango ( quot -- ) - cr pango_cairo_create_layout swap - [ (with-pango) ] curry with-disposal ; inline +: with-pango-cairo ( quot -- ) + cr pango_cairo_create_layout swap with-layout ; inline -: pango-layout-get-pixel-size ( layout -- width height ) - 0 0 [ pango_layout_get_pixel_size ] 2keep - [ *int ] bi@ ; +MEMO: dummy-cairo ( -- cr ) + CAIRO_FORMAT_ARGB32 0 0 cairo_image_surface_create cairo_create ; : dummy-pango ( quot -- ) - >r CAIRO_FORMAT_ARGB32 0 0 cairo_image_surface_create - r> [ with-pango ] curry with-cairo-from-surface ; inline + >r dummy-cairo cairo r> [ with-pango-cairo ] curry with-variable ; inline : layout-size ( quot -- dim ) [ layout pango-layout-get-pixel-size 2array ] compose dummy-pango ; inline -: layout-font ( str -- ) - pango_font_description_from_string - dup zero? [ "pango: not a valid font." throw ] when - layout over pango_layout_set_font_description - pango_font_description_free ; - -: layout-text ( str -- ) - layout swap -1 pango_layout_set_text ; +: show-layout ( -- ) + cr layout pango_cairo_show_layout ; : families ( -- families ) pango_cairo_font_map_get_default list-families ; diff --git a/extra/pango/cairo/gadgets/gadgets.factor b/extra/pango/cairo/gadgets/gadgets.factor index 9e8a99515e..a21affc364 100644 --- a/extra/pango/cairo/gadgets/gadgets.factor +++ b/extra/pango/cairo/gadgets/gadgets.factor @@ -1,30 +1,27 @@ ! Copyright (C) 2008 Matthew Willis. ! See http://factorcode.org/license.txt for BSD license. -USING: pango.cairo cairo cairo.ffi cairo.gadgets -alien.c-types kernel math ; +USING: pango.cairo pango.gadgets +cairo.gadgets arrays namespaces +fry accessors ui.gadgets +sequences opengl.gadgets +kernel pango.layouts ; + IN: pango.cairo.gadgets -: (pango-gadget) ( setup show -- gadget ) - [ drop layout-size ] - [ compose [ with-pango ] curry ] 2bi ; +TUPLE: pango-cairo-gadget < pango-gadget ; -: ( quot -- gadget ) - [ cr layout pango_cairo_show_layout ] (pango-gadget) ; +SINGLETON: pango-cairo-backend +pango-cairo-backend pango-backend set-global -USING: prettyprint sequences ui.gadgets.panes -threads io.backend io.encodings.utf8 io.files ; -: hello-pango ( -- ) - 50 [ 6 + ] map [ - "Sans " swap unparse append - [ - cr 0 1 0.2 0.6 cairo_set_source_rgba - layout-font "今日は、 Pango!" layout-text - ] curry - gadget. yield - ] each +M: pango-cairo-backend construct-pango + pango-cairo-gadget construct-gadget ; + +: setup-layout ( gadget -- quot ) + [ font>> ] [ text>> ] bi + '[ , layout-font , layout-text ] ; inline + +M: pango-cairo-gadget render* ( gadget -- ) + setup-layout [ layout-size dup ] [ - "resource:extra/pango/cairo/gadgets/gadgets.factor" - normalize-path utf8 file-contents layout-text - ] gadget. ; - -MAIN: hello-pango + '[ [ @ show-layout ] with-pango-cairo ] + ] bi render-cairo render-bytes* ; diff --git a/extra/pango/cairo/samples/samples.factor b/extra/pango/cairo/samples/samples.factor new file mode 100644 index 0000000000..644d731d70 --- /dev/null +++ b/extra/pango/cairo/samples/samples.factor @@ -0,0 +1,23 @@ +! Copyright (C) 2008 Matthew Willis. +! See http://factorcode.org/license.txt for BSD license. +USING: prettyprint sequences ui.gadgets.panes +pango.cairo.gadgets math kernel cairo cairo.ffi +pango.cairo tools.time namespaces assocs +threads io.backend io.encodings.utf8 io.files ; + +IN: pango.cairo.samples + +: hello-pango ( -- ) + "monospace 10" "resource:extra/pango/cairo/gadgets/gadgets.factor" + normalize-path utf8 file-contents + gadget. ; + +: time-pango ( -- ) + [ hello-pango ] time ; + +! clear the caches, for testing. +: clear-pango ( -- ) + dims get clear-assoc + textures get clear-assoc ; + +MAIN: time-pango diff --git a/extra/pango/ft2/ft2.factor b/extra/pango/ft2/ft2.factor new file mode 100644 index 0000000000..5ce59c7095 --- /dev/null +++ b/extra/pango/ft2/ft2.factor @@ -0,0 +1,56 @@ +USING: alien alien.c-types +math kernel byte-arrays freetype +opengl.gadgets accessors pango +ui.gadgets memoize +arrays sequences libc opengl.gl +system combinators alien.syntax +pango.layouts ; +IN: pango.ft2 + +<< "pangoft2" { + { [ os winnt? ] [ "libpangocairo-1.0-0.dll" ] } + { [ os macosx? ] [ "libpangocairo-1.0.0.dylib" ] } + { [ os unix? ] [ "libpangoft2-1.0.so" ] } +} cond "cdecl" add-library >> + +LIBRARY: pangoft2 + +FUNCTION: PangoFontMap* +pango_ft2_font_map_new ( ) ; + +FUNCTION: PangoContext* +pango_ft2_font_map_create_context ( PangoFT2FontMap* fontmap ) ; + +FUNCTION: void +pango_ft2_render_layout ( FT_Bitmap* bitmap, PangoLayout* layout, int x, int y ) ; + +: 4*-ceil ( n -- k*4 ) + 3 + 4 /i 4 * ; + +: ( width height -- ft-bitmap ) + swap dup + 2dup * 4*-ceil + "uchar" malloc-array + 256 + FT_PIXEL_MODE_GRAY + "FT_Bitmap" dup >r + { + set-FT_Bitmap-rows + set-FT_Bitmap-width + set-FT_Bitmap-pitch + set-FT_Bitmap-buffer + set-FT_Bitmap-num_grays + set-FT_Bitmap-pixel_mode + } set-slots r> ; + +: render-layout ( layout -- dims alien ) + [ + pango-layout-get-pixel-size + 2array dup 2^-bounds first2 dup + ] [ 0 0 pango_ft2_render_layout ] bi FT_Bitmap-buffer ; + +MEMO: ft2-context ( -- PangoContext* ) + pango_ft2_font_map_new pango_ft2_font_map_create_context ; + +: with-ft2-layout ( quot -- ) + ft2-context pango_layout_new swap with-layout ; inline diff --git a/extra/pango/ft2/gadgets/gadgets.factor b/extra/pango/ft2/gadgets/gadgets.factor new file mode 100644 index 0000000000..43ddc954ee --- /dev/null +++ b/extra/pango/ft2/gadgets/gadgets.factor @@ -0,0 +1,20 @@ +! Copyright (C) 2008 Matthew Willis. +! See http://factorcode.org/license.txt for BSD license. +USING: pango.ft2 pango.gadgets opengl.gadgets +accessors kernel opengl.gl libc +sequences namespaces ui.gadgets pango.layouts ; +IN: pango.ft2.gadgets + +TUPLE: pango-ft2-gadget < pango-gadget ; + +SINGLETON: pango-ft2-backend +pango-ft2-backend pango-backend set-global + +M: pango-ft2-backend construct-pango + pango-ft2-gadget construct-gadget ; + +M: pango-ft2-gadget render* + [ + [ text>> layout-text ] [ font>> layout-font ] bi + layout render-layout + ] with-ft2-layout [ GL_ALPHA render-bytes* ] keep free ; diff --git a/extra/pango/gadgets/gadgets.factor b/extra/pango/gadgets/gadgets.factor new file mode 100644 index 0000000000..f9442a4613 --- /dev/null +++ b/extra/pango/gadgets/gadgets.factor @@ -0,0 +1,19 @@ +! Copyright (C) 2008 Matthew Willis. +! See http://factorcode.org/license.txt for BSD license. +USING: opengl.gadgets kernel +arrays +accessors ; + +IN: pango.gadgets + +TUPLE: pango-gadget < texture-gadget text font ; + +M: pango-gadget cache-key* [ font>> ] [ text>> ] bi 2array ; + +SYMBOL: pango-backend +HOOK: construct-pango pango-backend ( -- gadget ) + +: ( font text -- gadget ) + construct-pango + swap >>text + swap >>font ; diff --git a/extra/pango/layouts/layouts.factor b/extra/pango/layouts/layouts.factor new file mode 100644 index 0000000000..71317ce552 --- /dev/null +++ b/extra/pango/layouts/layouts.factor @@ -0,0 +1,30 @@ +USING: alien alien.c-types +math +destructors accessors namespaces +pango kernel ; +IN: pango.layouts + +: pango-layout-get-pixel-size ( layout -- width height ) + 0 0 [ pango_layout_get_pixel_size ] 2keep + [ *int ] bi@ ; + +TUPLE: pango-layout alien ; +C: pango-layout +M: pango-layout dispose ( alien -- ) alien>> g_object_unref ; + +: layout ( -- pango-layout ) pango-layout get ; + +: (with-layout) ( pango-layout quot -- ) + >r alien>> pango-layout r> with-variable ; inline + +: with-layout ( layout quot -- ) + >r r> [ (with-layout) ] curry with-disposal ; inline + +: layout-font ( str -- ) + pango_font_description_from_string + dup zero? [ "pango: not a valid font." throw ] when + layout over pango_layout_set_font_description + pango_font_description_free ; + +: layout-text ( str -- ) + layout swap -1 pango_layout_set_text ; diff --git a/extra/pango/pango.factor b/extra/pango/pango.factor index 3549d9abb4..be5c257cb0 100644 --- a/extra/pango/pango.factor +++ b/extra/pango/pango.factor @@ -9,8 +9,8 @@ IN: pango ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! << "pango" { -! { [ os winnt? ] [ "libpango-1.dll" ] } -! { [ os macosx? ] [ "libpango.dylib" ] } + { [ os winnt? ] [ "libpango-1.0-0.dll" ] } + { [ os macosx? ] [ "libpango-1.0.0.dylib" ] } { [ os unix? ] [ "libpango-1.0.so" ] } } cond "cdecl" add-library >> @@ -18,6 +18,9 @@ LIBRARY: pango : PANGO_SCALE 1024 ; +FUNCTION: PangoLayout* +pango_layout_new ( PangoContext* context ) ; + FUNCTION: void pango_layout_set_text ( PangoLayout* layout, char* text, int length ) ; diff --git a/extra/parser-combinators/parser-combinators-docs.factor b/extra/parser-combinators/parser-combinators-docs.factor index 41171ce822..c08243d17d 100755 --- a/extra/parser-combinators/parser-combinators-docs.factor +++ b/extra/parser-combinators/parser-combinators-docs.factor @@ -23,4 +23,4 @@ HELP: any-char-parser "from the input string. The value consumed is the " "result of the parse." } { $examples -{ $example "USING: lazy-lists parser-combinators prettyprint ;" "\"foo\" any-char-parser parse-1 ." "102" } } ; +{ $example "USING: lists.lazy parser-combinators prettyprint ;" "\"foo\" any-char-parser parse-1 ." "102" } } ; diff --git a/extra/parser-combinators/parser-combinators-tests.factor b/extra/parser-combinators/parser-combinators-tests.factor index 2dd3fd911c..70698daa0b 100755 --- a/extra/parser-combinators/parser-combinators-tests.factor +++ b/extra/parser-combinators/parser-combinators-tests.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2005 Chris Double. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel lazy-lists tools.test strings math +USING: kernel lists.lazy tools.test strings math sequences parser-combinators arrays math.parser unicode.categories ; IN: parser-combinators.tests diff --git a/extra/parser-combinators/parser-combinators.factor b/extra/parser-combinators/parser-combinators.factor index 9537a0c88c..2414c1ced3 100755 --- a/extra/parser-combinators/parser-combinators.factor +++ b/extra/parser-combinators/parser-combinators.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2004 Chris Double. ! See http://factorcode.org/license.txt for BSD license. -USING: lazy-lists promises kernel sequences strings math +USING: lists lists.lazy promises kernel sequences strings math arrays splitting quotations combinators namespaces unicode.case unicode.categories sequences.deep ; IN: parser-combinators @@ -147,8 +147,8 @@ TUPLE: and-parser parsers ; >r parse-result-parsed r> [ parse-result-parsed 2array ] keep parse-result-unparsed - ] lmap-with - ] lmap-with lconcat ; + ] lazy-map-with + ] lazy-map-with lconcat ; M: and-parser parse ( input parser -- list ) #! Parse 'input' by sequentially combining the @@ -171,7 +171,7 @@ M: or-parser parse ( input parser1 -- list ) #! of parser1 and parser2 being applied to the same #! input. This implements the choice parsing operator. or-parser-parsers 0 swap seq>list - [ parse ] lmap-with lconcat ; + [ parse ] lazy-map-with lconcat ; : left-trim-slice ( string -- string ) #! Return a new string without any leading whitespace @@ -216,7 +216,7 @@ M: apply-parser parse ( input parser -- result ) -rot parse [ [ parse-result-parsed swap call ] keep parse-result-unparsed - ] lmap-with ; + ] lazy-map-with ; TUPLE: some-parser p1 ; diff --git a/extra/parser-combinators/simple/simple-docs.factor b/extra/parser-combinators/simple/simple-docs.factor index 78b731f5b0..fdf32bddb1 100755 --- a/extra/parser-combinators/simple/simple-docs.factor +++ b/extra/parser-combinators/simple/simple-docs.factor @@ -11,7 +11,7 @@ HELP: 'digit' "the input string. The numeric value of the digit " " consumed is the result of the parse." } { $examples -{ $example "USING: lazy-lists parser-combinators parser-combinators.simple prettyprint ;" "\"123\" 'digit' parse-1 ." "1" } } ; +{ $example "USING: lists.lazy parser-combinators parser-combinators.simple prettyprint ;" "\"123\" 'digit' parse-1 ." "1" } } ; HELP: 'integer' { $values @@ -21,7 +21,7 @@ HELP: 'integer' "the input string. The numeric value of the integer " " consumed is the result of the parse." } { $examples -{ $example "USING: lazy-lists parser-combinators parser-combinators.simple prettyprint ;" "\"123\" 'integer' parse-1 ." "123" } } ; +{ $example "USING: lists.lazy parser-combinators parser-combinators.simple prettyprint ;" "\"123\" 'integer' parse-1 ." "123" } } ; HELP: 'string' { $values { "parser" "a parser object" } } @@ -30,7 +30,7 @@ HELP: 'string' "quotations from the input string. The string value " " consumed is the result of the parse." } { $examples -{ $example "USING: lazy-lists parser-combinators parser-combinators.simple prettyprint ;" "\"\\\"foo\\\"\" 'string' parse-1 ." "\"foo\"" } } ; +{ $example "USING: lists.lazy parser-combinators parser-combinators.simple prettyprint ;" "\"\\\"foo\\\"\" 'string' parse-1 ." "\"foo\"" } } ; HELP: 'bold' { $values @@ -62,6 +62,6 @@ HELP: comma-list "'element' should be a parser that can parse the elements. The " "result of the parser is a sequence of the parsed elements." } { $examples -{ $example "USING: lazy-lists parser-combinators parser-combinators.simple prettyprint ;" "\"1,2,3,4\" 'integer' comma-list parse-1 ." "{ 1 2 3 4 }" } } ; +{ $example "USING: lists.lazy parser-combinators parser-combinators.simple prettyprint ;" "\"1,2,3,4\" 'integer' comma-list parse-1 ." "{ 1 2 3 4 }" } } ; { $see-also 'digit' 'integer' 'string' 'bold' 'italic' comma-list } related-words diff --git a/extra/parser-combinators/simple/simple.factor b/extra/parser-combinators/simple/simple.factor index 745442610c..f7a696ca35 100755 --- a/extra/parser-combinators/simple/simple.factor +++ b/extra/parser-combinators/simple/simple.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2006 Chris Double. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel strings math sequences lazy-lists words +USING: kernel strings math sequences lists.lazy words math.parser promises parser-combinators unicode.categories ; IN: parser-combinators.simple diff --git a/extra/persistent-vectors/authors.txt b/extra/persistent-vectors/authors.txt new file mode 100644 index 0000000000..1901f27a24 --- /dev/null +++ b/extra/persistent-vectors/authors.txt @@ -0,0 +1 @@ +Slava Pestov diff --git a/extra/persistent-vectors/persistent-vectors-docs.factor b/extra/persistent-vectors/persistent-vectors-docs.factor new file mode 100644 index 0000000000..dc9222cedb --- /dev/null +++ b/extra/persistent-vectors/persistent-vectors-docs.factor @@ -0,0 +1,53 @@ +USING: help.markup help.syntax kernel math sequences ; +IN: persistent-vectors + +HELP: new-nth +{ $values { "val" object } { "i" integer } { "seq" sequence } { "seq'" sequence } } +{ $contract "Persistent analogue of " { $link set-nth } ". Outputs a new sequence with the " { $snippet "i" } "th element replaced by " { $snippet "val" } "." } +{ $notes "This operation runs in " { $snippet "O(log_32 n)" } " time on " { $link persistent-vector } " instances and " { $snippet "O(n)" } " time on all other sequences." } ; + +HELP: ppush +{ $values { "val" object } { "seq" sequence } { "seq'" sequence } } +{ $contract "Persistent analogue of " { $link push } ". Outputs a new sequence with all elements of " { $snippet "seq" } " together with " { $snippet "val" } " added at the end." } +{ $notes "This operation runs in amortized " { $snippet "O(1)" } " time on " { $link persistent-vector } " instances and " { $snippet "O(n)" } " time on all other sequences." } ; + +HELP: ppop +{ $values { "seq" sequence } { "seq'" sequence } } +{ $contract "Persistent analogue of " { $link pop* } ". Outputs a new sequence with all elements of " { $snippet "seq" } " except for the final element." } +{ $notes "This operation runs in amortized " { $snippet "O(1)" } " time on " { $link persistent-vector } " instances and " { $snippet "O(n)" } " time on all other sequences." } ; + +HELP: PV{ +{ $syntax "elements... }" } +{ $description "Parses a literal " { $link persistent-vector } "." } ; + +HELP: >persistent-vector +{ $values { "seq" sequence } { "pvec" persistent-vector } } +{ $description "Creates a " { $link persistent-vector } " with the same elements as " { $snippet "seq" } "." } ; + +HELP: persistent-vector +{ $class-description "The class of persistent vectors." } ; + +HELP: pempty +{ $values { "pvec" persistent-vector } } +{ $description "Outputs an empty " { $link persistent-vector } "." } ; + +ARTICLE: "persistent-vectors" "Persistent vectors" +"A " { $emphasis "persistent vector" } " differs from an ordinary vector (" { $link "vectors" } ") in that it is immutable, and all operations yield new persistent vectors instead of modifying inputs. Unlike immutable operations on ordinary sequences, persistent vector operations are efficient and run in sub-linear time." +$nl +"The class of persistent vectors:" +{ $subsection persistent-vector } +"Persistent vectors support the immutable sequence protocol, namely as " { $link length } " and " { $link nth } ", and so can be used with most sequence words (" { $link "sequences" } ")." +$nl +"In addition to standard sequence operations, persistent vectors implement efficient operations specific to them. They run in sub-linear time on persistent vectors, and degrate to linear-time algorithms on ordinary sequences:" +{ $subsection new-nth } +{ $subsection ppush } +{ $subsection ppop } +"The empty persistent vector, used for building up all other persistent vectors:" +{ $subsection pempty } +"Converting a sequence into a persistent vector:" +{ $subsection >persistent-vector } +"Persistent vectors have a literal syntax:" +{ $subsection POSTPONE: PV{ } +"This implementation of persistent vectors is based on the " { $snippet "clojure.lang.PersistentVector" } " class from Rich Hickey's Clojure language for the JVM (" { $url "http://clojure.org" } ")." ; + +ABOUT: "persistent-vectors" diff --git a/extra/persistent-vectors/persistent-vectors-tests.factor b/extra/persistent-vectors/persistent-vectors-tests.factor new file mode 100644 index 0000000000..f871c95e16 --- /dev/null +++ b/extra/persistent-vectors/persistent-vectors-tests.factor @@ -0,0 +1,63 @@ +IN: persistent-vectors.tests +USING: tools.test persistent-vectors sequences kernel arrays +random namespaces vectors math math.order ; + +\ new-nth must-infer +\ ppush must-infer +\ ppop must-infer + +[ 0 ] [ pempty length ] unit-test + +[ 1 ] [ 3 pempty ppush length ] unit-test + +[ 3 ] [ 3 pempty ppush first ] unit-test + +[ PV{ 3 1 3 3 7 } ] [ + pempty { 3 1 3 3 7 } [ swap ppush ] each +] unit-test + +[ { 3 1 3 3 7 } ] [ + pempty { 3 1 3 3 7 } [ swap ppush ] each >array +] unit-test + +{ 100 1060 2000 10000 100000 1000000 } [ + [ t ] swap [ dup >persistent-vector sequence= ] curry unit-test +] each + +[ ] [ 10000 [ drop 16 random-bits ] PV{ } map-as "1" set ] unit-test +[ ] [ "1" get >vector "2" set ] unit-test + +[ t ] [ + 3000 [ + drop + 16 random-bits 10000 random + [ "1" [ new-nth ] change ] + [ "2" [ new-nth ] change ] 2bi + "1" get "2" get sequence= + ] all? +] unit-test + +[ PV{ } ppop ] [ empty-error? ] must-fail-with + +[ t ] [ PV{ 3 } ppop empty? ] unit-test + +[ PV{ 3 7 } ] [ PV{ 3 7 6 } ppop ] unit-test + +[ PV{ 3 7 6 5 } ] [ 5 PV{ 3 7 6 } ppush ] unit-test + +[ ] [ PV{ } "1" set ] unit-test +[ ] [ V{ } clone "2" set ] unit-test + +[ t ] [ + 100 [ + drop + 100 random [ + 16 random-bits [ "1" [ ppush ] change ] [ "2" get push ] bi + ] times + 100 random "1" get length min [ + "1" [ ppop ] change + "2" get pop* + ] times + "1" get "2" get sequence= + ] all? +] unit-test diff --git a/extra/persistent-vectors/persistent-vectors.factor b/extra/persistent-vectors/persistent-vectors.factor new file mode 100644 index 0000000000..f9f4b68933 --- /dev/null +++ b/extra/persistent-vectors/persistent-vectors.factor @@ -0,0 +1,183 @@ +! Based on Clojure's PersistentVector by Rich Hickey. + +USING: math accessors kernel sequences.private sequences arrays +combinators parser prettyprint.backend ; +IN: persistent-vectors + +ERROR: empty-error pvec ; + +GENERIC: ppush ( val seq -- seq' ) + +M: sequence ppush swap suffix ; + +GENERIC: ppop ( seq -- seq' ) + +M: sequence ppop 1 head* ; + +GENERIC: new-nth ( val i seq -- seq' ) + +M: sequence new-nth clone [ set-nth ] keep ; + +TUPLE: persistent-vector count root tail ; + +M: persistent-vector length count>> ; + +> ] bi* nth ; inline + +: body-nth ( i node -- i node' ) + dup level>> [ + dupd [ level>> node-shift ] keep node-nth + ] times ; inline + +: tail-offset ( pvec -- n ) + [ count>> ] [ tail>> children>> length ] bi - ; + +M: persistent-vector nth-unsafe + 2dup tail-offset >= + [ tail>> ] [ root>> body-nth ] if + node-nth ; + +: node-add ( val node -- node' ) + clone [ ppush ] change-children ; + +: ppush-tail ( val pvec -- pvec' ) + [ node-add ] change-tail ; + +: full? ( node -- ? ) + children>> length node-size = ; + +: 1node ( val level -- node ) + node new + swap >>level + swap 1array >>children ; + +: 2node ( first second -- node ) + [ 2array ] [ drop level>> 1+ ] 2bi node boa ; + +: new-child ( new-child node -- node' expansion/f ) + dup full? [ tuck level>> 1node ] [ node-add f ] if ; + +: new-last ( val seq -- seq' ) + [ length 1- ] keep new-nth ; + +: node-set-last ( child node -- node' ) + clone [ new-last ] change-children ; + +: (ppush-new-tail) ( tail node -- node' expansion/f ) + dup level>> 1 = [ + new-child + ] [ + tuck children>> peek (ppush-new-tail) + [ swap new-child ] [ swap node-set-last f ] ?if + ] if ; + +: do-expansion ( pvec root expansion/f -- pvec ) + [ 2node ] when* >>root ; + +: ppush-new-tail ( val pvec -- pvec' ) + [ ] [ tail>> ] [ root>> ] tri + (ppush-new-tail) do-expansion + swap 0 1node >>tail ; + +M: persistent-vector ppush ( val pvec -- pvec' ) + clone + dup tail>> full? + [ ppush-new-tail ] [ ppush-tail ] if + [ 1+ ] change-count ; + +: node-set-nth ( val i node -- node' ) + clone [ new-nth ] change-children ; + +: node-change-nth ( i node quot -- node' ) + [ clone ] dip [ + [ clone ] dip [ change-nth ] 2keep drop + ] curry change-children ; inline + +: (new-nth) ( val i node -- node' ) + dup level>> 0 = [ + [ node-mask ] dip node-set-nth + ] [ + [ dupd level>> node-shift node-mask ] keep + [ (new-nth) ] node-change-nth + ] if ; + +M: persistent-vector new-nth ( obj i pvec -- pvec' ) + 2dup count>> = [ nip ppush ] [ + clone + 2dup tail-offset >= [ + [ node-mask ] dip + [ node-set-nth ] change-tail + ] [ + [ (new-nth) ] change-root + ] if + ] if ; + +: (ppop-contraction) ( node -- node' tail' ) + clone [ unclip-last swap ] change-children swap ; + +: ppop-contraction ( node -- node' tail' ) + [ (ppop-contraction) ] [ level>> 1 = ] bi swap and ; + +: (ppop-new-tail) ( root -- root' tail' ) + dup level>> 1 > [ + dup children>> peek (ppop-new-tail) over children>> empty? + [ 2drop ppop-contraction ] [ [ swap node-set-last ] dip ] if + ] [ + ppop-contraction + ] if ; + +: ppop-tail ( pvec -- pvec' ) + [ clone [ ppop ] change-children ] change-tail ; + +: ppop-new-tail ( pvec -- pvec' ) + dup root>> (ppop-new-tail) + [ + dup [ level>> 1 > ] [ children>> length 1 = ] bi and + [ children>> first ] when + ] dip + [ >>root ] [ >>tail ] bi* ; + +PRIVATE> + +: pempty ( -- pvec ) + T{ persistent-vector f 0 T{ node f { } 1 } T{ node f { } 0 } } ; inline + +M: persistent-vector ppop ( pvec -- pvec' ) + dup count>> { + { 0 [ empty-error ] } + { 1 [ drop pempty ] } + [ + [ + clone + dup tail>> children>> length 1 > + [ ppop-tail ] [ ppop-new-tail ] if + ] dip 1- >>count + ] + } case ; + +M: persistent-vector like + drop pempty [ swap ppush ] reduce ; + +M: persistent-vector equal? + over persistent-vector? [ sequence= ] [ 2drop f ] if ; + +: >persistent-vector ( seq -- pvec ) pempty like ; inline + +: PV{ \ } [ >persistent-vector ] parse-literal ; parsing + +M: persistent-vector pprint-delims drop \ PV{ \ } ; + +M: persistent-vector >pprint-sequence ; + +INSTANCE: persistent-vector immutable-sequence diff --git a/extra/persistent-vectors/summary.txt b/extra/persistent-vectors/summary.txt new file mode 100644 index 0000000000..19f3f66ca3 --- /dev/null +++ b/extra/persistent-vectors/summary.txt @@ -0,0 +1 @@ +Immutable vectors with O(log_32 n) random access and amortized O(1) push/pop diff --git a/extra/persistent-vectors/tags.txt b/extra/persistent-vectors/tags.txt new file mode 100644 index 0000000000..42d711b32b --- /dev/null +++ b/extra/persistent-vectors/tags.txt @@ -0,0 +1 @@ +collections diff --git a/extra/present/present.factor b/extra/present/present.factor new file mode 100644 index 0000000000..1fae84184a --- /dev/null +++ b/extra/present/present.factor @@ -0,0 +1,15 @@ +USING: math math.parser calendar calendar.format strings words +kernel ; +IN: present + +GENERIC: present ( object -- string ) + +M: real present number>string ; + +M: timestamp present timestamp>string ; + +M: string present ; + +M: word present word-name ; + +M: f present drop "" ; diff --git a/extra/project-euler/007/007.factor b/extra/project-euler/007/007.factor index 93754b69d1..04686a8328 100644 --- a/extra/project-euler/007/007.factor +++ b/extra/project-euler/007/007.factor @@ -1,6 +1,6 @@ ! Copyright (c) 2007 Aaron Schaefer. ! See http://factorcode.org/license.txt for BSD license. -USING: lazy-lists math math.primes ; +USING: lists math math.primes ; IN: project-euler.007 ! http://projecteuler.net/index.php?section=problems&id=7 diff --git a/extra/project-euler/134/134.factor b/extra/project-euler/134/134.factor index 11af1960ed..4e54a18f19 100644 --- a/extra/project-euler/134/134.factor +++ b/extra/project-euler/134/134.factor @@ -1,6 +1,6 @@ ! Copyright (c) 2007 Samuel Tardieu. ! See http://factorcode.org/license.txt for BSD license. -USING: arrays kernel lazy-lists math.algebra math math.functions +USING: arrays kernel lists lists.lazy math.algebra math math.functions math.order math.primes math.ranges project-euler.common sequences ; IN: project-euler.134 @@ -39,7 +39,7 @@ IN: project-euler.134 PRIVATE> : euler134 ( -- answer ) - 0 5 lprimes-from uncons [ 1000000 > ] luntil + 0 5 lprimes-from uncons swap [ 1000000 > ] luntil [ [ s + ] keep ] leach drop ; ! [ euler134 ] 10 ave-time diff --git a/extra/regexp/regexp.factor b/extra/regexp/regexp.factor index 78ffaf5eeb..91dea0dd56 100755 --- a/extra/regexp/regexp.factor +++ b/extra/regexp/regexp.factor @@ -1,4 +1,4 @@ -USING: arrays combinators kernel lazy-lists math math.parser +USING: arrays combinators kernel lists math math.parser namespaces parser parser-combinators parser-combinators.simple promises quotations sequences combinators.lib strings math.order assocs prettyprint.backend memoize unicode.case unicode.categories ; diff --git a/extra/rss/authors.txt b/extra/rss/authors.txt deleted file mode 100755 index f990dd0ed2..0000000000 --- a/extra/rss/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Daniel Ehrenberg diff --git a/extra/rss/rss.factor b/extra/rss/rss.factor deleted file mode 100644 index 364c24b91f..0000000000 --- a/extra/rss/rss.factor +++ /dev/null @@ -1,120 +0,0 @@ -! Copyright (C) 2006 Chris Double, Daniel Ehrenberg. -! See http://factorcode.org/license.txt for BSD license. -USING: xml.utilities kernel assocs xml.generator math.order - strings sequences xml.data xml.writer - io.streams.string combinators xml xml.entities io.files io - http.client namespaces xml.generator hashtables - calendar.format accessors continuations ; -IN: rss - -: any-tag-named ( tag names -- tag-inside ) - f -rot [ tag-named nip dup ] with find 2drop ; - -TUPLE: feed title link entries ; - -C: feed - -TUPLE: entry title link description pub-date ; - -C: entry - -: try-parsing-timestamp ( string -- timestamp ) - [ rfc822>timestamp ] [ drop rfc3339>timestamp ] recover ; - -: rss1.0-entry ( tag -- entry ) - { - [ "title" tag-named children>string ] - [ "link" tag-named children>string ] - [ "description" tag-named children>string ] - [ - f "date" "http://purl.org/dc/elements/1.1/" - tag-named dup [ children>string try-parsing-timestamp ] when - ] - } cleave ; - -: rss1.0 ( xml -- feed ) - [ - "channel" tag-named - [ "title" tag-named children>string ] - [ "link" tag-named children>string ] bi - ] [ "item" tags-named [ rss1.0-entry ] map ] bi - ; - -: rss2.0-entry ( tag -- entry ) - { - [ "title" tag-named children>string ] - [ { "link" "guid" } any-tag-named children>string ] - [ "description" tag-named children>string ] - [ - { "date" "pubDate" } any-tag-named - children>string try-parsing-timestamp - ] - } cleave ; - -: rss2.0 ( xml -- feed ) - "channel" tag-named - [ "title" tag-named children>string ] - [ "link" tag-named children>string ] - [ "item" tags-named [ rss2.0-entry ] map ] - tri ; - -: atom1.0-entry ( tag -- entry ) - { - [ "title" tag-named children>string ] - [ "link" tag-named "href" swap at ] - [ - { "content" "summary" } any-tag-named - dup tag-children [ string? not ] contains? - [ tag-children [ write-chunk ] with-string-writer ] - [ children>string ] if - ] - [ - { "published" "updated" "issued" "modified" } - any-tag-named children>string try-parsing-timestamp - ] - } cleave ; - -: atom1.0 ( xml -- feed ) - [ "title" tag-named children>string ] - [ "link" tag-named "href" swap at ] - [ "entry" tags-named [ atom1.0-entry ] map ] - tri ; - -: xml>feed ( xml -- feed ) - dup name-tag { - { "RDF" [ rss1.0 ] } - { "rss" [ rss2.0 ] } - { "feed" [ atom1.0 ] } - } case ; - -: read-feed ( string -- feed ) - [ string>xml xml>feed ] with-html-entities ; - -: download-feed ( url -- feed ) - #! Retrieve an news syndication file, return as a feed tuple. - http-get read-feed ; - -! Atom generation -: simple-tag, ( content name -- ) - [ , ] tag, ; - -: simple-tag*, ( content name attrs -- ) - [ , ] tag*, ; - -: entry, ( entry -- ) - "entry" [ - dup entry-title "title" { { "type" "html" } } simple-tag*, - "link" over entry-link "href" associate contained*, - dup entry-pub-date timestamp>rfc3339 "published" simple-tag, - entry-description [ "content" { { "type" "html" } } simple-tag*, ] when* - ] tag, ; - -: feed>xml ( feed -- xml ) - "feed" { { "xmlns" "http://www.w3.org/2005/Atom" } } [ - dup feed-title "title" simple-tag, - "link" over feed-link "href" associate contained*, - feed-entries [ entry, ] each - ] make-xml* ; - -: write-feed ( feed -- ) - feed>xml write-xml ; diff --git a/extra/syndication/authors.txt b/extra/syndication/authors.txt new file mode 100755 index 0000000000..89b32cecee --- /dev/null +++ b/extra/syndication/authors.txt @@ -0,0 +1,3 @@ +Daniel Ehrenberg +Chris Double +Slava Pestov diff --git a/extra/rss/readme.txt b/extra/syndication/readme.txt similarity index 100% rename from extra/rss/readme.txt rename to extra/syndication/readme.txt diff --git a/extra/rss/summary.txt b/extra/syndication/summary.txt similarity index 100% rename from extra/rss/summary.txt rename to extra/syndication/summary.txt diff --git a/extra/rss/rss-tests.factor b/extra/syndication/syndication-tests.factor similarity index 63% rename from extra/rss/rss-tests.factor rename to extra/syndication/syndication-tests.factor index 0e6bb0b9c1..73541e7908 100755 --- a/extra/rss/rss-tests.factor +++ b/extra/syndication/syndication-tests.factor @@ -1,6 +1,9 @@ -USING: rss io kernel io.files tools.test io.encodings.utf8 -calendar ; -IN: rss.tests +USING: syndication io kernel io.files tools.test io.encodings.utf8 +calendar urls ; +IN: syndication.tests + +\ download-feed must-infer +\ feed>xml must-infer : load-news-file ( filename -- feed ) #! Load an news syndication file and process it, returning @@ -11,32 +14,32 @@ IN: rss.tests feed f "Meerkat" - "http://meerkat.oreillynet.com" + URL" http://meerkat.oreillynet.com" { T{ entry f "XML: A Disruptive Technology" - "http://c.moreover.com/click/here.pl?r123" + URL" http://c.moreover.com/click/here.pl?r123" "\n XML is placing increasingly heavy loads on the existing technical\n infrastructure of the Internet.\n " f } } -} ] [ "resource:extra/rss/rss1.xml" load-news-file ] unit-test +} ] [ "resource:extra/syndication/test/rss1.xml" load-news-file ] unit-test [ T{ feed f "dive into mark" - "http://example.org/" + URL" http://example.org/" { T{ entry f "Atom draft-07 snapshot" - "http://example.org/2005/04/02/atom" + URL" http://example.org/2005/04/02/atom" "\n
\n

[Update: The Atom draft is finished.]

\n
\n " T{ timestamp f 2003 12 13 8 29 29 T{ duration f 0 0 0 -4 0 0 } } } } -} ] [ "resource:extra/rss/atom.xml" load-news-file ] unit-test +} ] [ "resource:extra/syndication/test/atom.xml" load-news-file ] unit-test diff --git a/extra/syndication/syndication.factor b/extra/syndication/syndication.factor new file mode 100644 index 0000000000..12beaf4cd7 --- /dev/null +++ b/extra/syndication/syndication.factor @@ -0,0 +1,135 @@ +! Copyright (C) 2006 Chris Double, Daniel Ehrenberg. +! Portions copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: xml.utilities kernel assocs xml.generator math.order + strings sequences xml.data xml.writer + io.streams.string combinators xml xml.entities io.files io + http.client namespaces xml.generator hashtables + calendar.format accessors continuations urls present ; +IN: syndication + +: any-tag-named ( tag names -- tag-inside ) + f -rot [ tag-named nip dup ] with find 2drop ; + +TUPLE: feed title url entries ; + +: ( -- feed ) feed new ; + +TUPLE: entry title url description date ; + +: set-entries ( feed entries -- feed ) + [ dup url>> ] dip + [ [ derive-url ] change-url ] with map + >>entries ; + +: ( -- entry ) entry new ; + +: try-parsing-timestamp ( string -- timestamp ) + [ rfc822>timestamp ] [ drop rfc3339>timestamp ] recover ; + +: rss1.0-entry ( tag -- entry ) + entry new + swap { + [ "title" tag-named children>string >>title ] + [ "link" tag-named children>string >url >>url ] + [ "description" tag-named children>string >>description ] + [ + f "date" "http://purl.org/dc/elements/1.1/" + tag-named dup [ children>string try-parsing-timestamp ] when + >>date + ] + } cleave ; + +: rss1.0 ( xml -- feed ) + feed new + swap [ + "channel" tag-named + [ "title" tag-named children>string >>title ] + [ "link" tag-named children>string >url >>url ] bi + ] [ "item" tags-named [ rss1.0-entry ] map set-entries ] bi ; + +: rss2.0-entry ( tag -- entry ) + entry new + swap { + [ "title" tag-named children>string >>title ] + [ { "link" "guid" } any-tag-named children>string >url >>url ] + [ "description" tag-named children>string >>description ] + [ + { "date" "pubDate" } any-tag-named + children>string try-parsing-timestamp >>date + ] + } cleave ; + +: rss2.0 ( xml -- feed ) + feed new + swap + "channel" tag-named + [ "title" tag-named children>string >>title ] + [ "link" tag-named children>string >url >>url ] + [ "item" tags-named [ rss2.0-entry ] map set-entries ] + tri ; + +: atom1.0-entry ( tag -- entry ) + entry new + swap { + [ "title" tag-named children>string >>title ] + [ "link" tag-named "href" swap at >url >>url ] + [ + { "content" "summary" } any-tag-named + dup tag-children [ string? not ] contains? + [ tag-children [ write-chunk ] with-string-writer ] + [ children>string ] if >>description + ] + [ + { "published" "updated" "issued" "modified" } + any-tag-named children>string try-parsing-timestamp + >>date + ] + } cleave ; + +: atom1.0 ( xml -- feed ) + feed new + swap + [ "title" tag-named children>string >>title ] + [ "link" tag-named "href" swap at >url >>url ] + [ "entry" tags-named [ atom1.0-entry ] map set-entries ] + tri ; + +: xml>feed ( xml -- feed ) + dup name-tag { + { "RDF" [ rss1.0 ] } + { "rss" [ rss2.0 ] } + { "feed" [ atom1.0 ] } + } case ; + +: read-feed ( string -- feed ) + [ string>xml xml>feed ] with-html-entities ; + +: download-feed ( url -- feed ) + #! Retrieve an news syndication file, return as a feed tuple. + http-get read-feed ; + +! Atom generation +: simple-tag, ( content name -- ) + [ , ] tag, ; + +: simple-tag*, ( content name attrs -- ) + [ , ] tag*, ; + +: entry, ( entry -- ) + "entry" [ + { + [ title>> "title" { { "type" "html" } } simple-tag*, ] + [ url>> present "href" associate "link" swap contained*, ] + [ date>> timestamp>rfc3339 "published" simple-tag, ] + [ description>> [ "content" { { "type" "html" } } simple-tag*, ] when* ] + } cleave + ] tag, ; + +: feed>xml ( feed -- xml ) + "feed" { { "xmlns" "http://www.w3.org/2005/Atom" } } [ + [ title>> "title" simple-tag, ] + [ url>> present "href" associate "link" swap contained*, ] + [ entries>> [ entry, ] each ] + tri + ] make-xml* ; diff --git a/extra/syndication/tags.txt b/extra/syndication/tags.txt new file mode 100644 index 0000000000..c0772185a0 --- /dev/null +++ b/extra/syndication/tags.txt @@ -0,0 +1 @@ +web diff --git a/extra/rss/atom.xml b/extra/syndication/test/atom.xml similarity index 100% rename from extra/rss/atom.xml rename to extra/syndication/test/atom.xml diff --git a/extra/rss/rss1.xml b/extra/syndication/test/rss1.xml similarity index 100% rename from extra/rss/rss1.xml rename to extra/syndication/test/rss1.xml diff --git a/extra/tangle/tangle.factor b/extra/tangle/tangle.factor index 8a4c6146de..1f567a5f0d 100644 --- a/extra/tangle/tangle.factor +++ b/extra/tangle/tangle.factor @@ -1,6 +1,10 @@ ! Copyright (C) 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs db db.sqlite db.postgresql http http.server http.server.actions http.server.static io io.files json.writer kernel math.parser namespaces semantic-db sequences strings tangle.path ; +USING: accessors assocs db db.sqlite db.postgresql +http http.server http.server.dispatchers http.server.responses +http.server.static furnace.actions furnace.json +io io.files json.writer kernel math.parser namespaces +semantic-db sequences strings tangle.path ; IN: tangle GENERIC: render* ( content templater -- output ) @@ -20,7 +24,7 @@ C: tangle [ [ db>> ] [ seq>> ] bi ] dip with-db ; : node-response ( id -- response ) - load-node [ node-content ] [ <404> ] if* ; + load-node [ node-content "text/plain" ] [ <404> ] if* ; : display-node ( params -- response ) [ @@ -36,7 +40,7 @@ C: tangle : submit-node ( params -- response ) [ "node_content" swap at* [ - create-node id>> number>string + create-node id>> number>string "text/plain" ] [ drop <400> ] if @@ -52,7 +56,7 @@ TUPLE: path-responder ; C: path-responder M: path-responder call-responder* ( path responder -- response ) - drop path>file [ node-content ] [ <404> ] if* ; + drop path>file [ node-content "text/plain" ] [ <404> ] if* ; TUPLE: tangle-dispatcher < dispatcher tangle ; diff --git a/extra/tetris/game/game.factor b/extra/tetris/game/game.factor index 644a9be1b5..90df619ff7 100644 --- a/extra/tetris/game/game.factor +++ b/extra/tetris/game/game.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2006, 2007 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences math math.functions tetris.board -tetris.piece tetris.tetromino lazy-lists combinators system ; +tetris.piece tetris.tetromino lists combinators system ; IN: tetris.game TUPLE: tetris pieces last-update update-interval rows score game-state paused? running? ; diff --git a/extra/tetris/piece/piece.factor b/extra/tetris/piece/piece.factor index 981b509bfa..55215dbf6a 100644 --- a/extra/tetris/piece/piece.factor +++ b/extra/tetris/piece/piece.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2006, 2007 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. USING: kernel arrays tetris.tetromino math math.vectors -sequences quotations lazy-lists ; +sequences quotations lists.lazy ; IN: tetris.piece #! A piece adds state to the tetromino that is the piece's delegate. The diff --git a/extra/unicode/collation/collation-docs.factor b/extra/unicode/collation/collation-docs.factor index 23538229a4..0e92042ddd 100644 --- a/extra/unicode/collation/collation-docs.factor +++ b/extra/unicode/collation/collation-docs.factor @@ -1,7 +1,42 @@ -USING: help.syntax help.markup ; +USING: help.syntax help.markup strings byte-arrays ; IN: unicode.collation ABOUT: "unicode.collation" ARTICLE: "unicode.collation" "Unicode collation algorithm" -"The Unicode Collation Algorithm (UTS #10) forms a reasonable way to sort strings when accouting for all of the characters in Unicode." ; +"The Unicode Collation Algorithm (UTS #10) forms a reasonable way to sort strings when accouting for all of the characters in Unicode. At the moment, only the default Unicode collation element table (DUCET) is used, but a more accurate collation would take locale into account. The following words are defined:" +{ $subsection sort-strings } +{ $subsection collation-key } +{ $subsection string<=> } +{ $subsection primary= } +{ $subsection secondary= } +{ $subsection tertiary= } +{ $subsection quaternary= } ; + +HELP: sort-strings +{ $values { "strings" "a sequence of strings" } { "sorted" "the strings in DUCET order" } } +{ $description "This word takes a sequence of strings and sorts them according to the UCA, using code point order as a tie-breaker." } ; + +HELP: collation-key +{ $values { "string" string } { "key" byte-array } } +{ $description "This takes a string and gives a representation of the collation key, which can be compared with <=>" } ; + +HELP: string<=> +{ $values { "str1" string } { "str2" string } { "<=>" "one of +lt+, +gt+ or +eq+" } } +{ $description "This word takes two strings and compares them using the UCA with the DUCET, using code point order as a tie-breaker." } ; + +HELP: primary= +{ $values { "str1" string } { "str2" string } { "?" "t or f" } } +{ $description "This checks whether the first level of collation is identical. This is the least specific kind of equality test. In Latin script, it can be understood as ignoring case, punctuation and accent marks." } ; + +HELP: secondary= +{ $values { "str1" string } { "str2" string } { "?" "t or f" } } +{ $description "This checks whether the first two levels of collation are equal. For Latin script, this means accent marks are significant again, and it is otherwise similar to primary=." } ; + +HELP: tertiary= +{ $values { "str1" string } { "str2" string } { "?" "t or f" } } +{ $description "Along the same lines as secondary=, but case is significant." } ; + +HELP: quaternary= +{ $values { "str1" string } { "str2" string } { "?" "t or f" } } +{ $description "This is similar to tertiary= but it makes punctuation significant again, while still leaving out things like null bytes and Hebrew vowel marks, which mean absolutely nothing in collation." } ; diff --git a/extra/unicode/collation/collation-tests.factor b/extra/unicode/collation/collation-tests.factor index b4a54bb11d..16ac50d5a9 100755 --- a/extra/unicode/collation/collation-tests.factor +++ b/extra/unicode/collation/collation-tests.factor @@ -24,6 +24,9 @@ IN: unicode.collation.tests [ t t f f ] [ "hello" "HELLO" test-equality ] unit-test [ t t t f ] [ "hello" "h e l l o." test-equality ] unit-test [ t t t t ] [ "hello" "\0hello\0" test-equality ] unit-test +[ { "good bye" "goodbye" "hello" "HELLO" } ] +[ { "HELLO" "goodbye" "good bye" "hello" } sort-strings ] +unit-test parse-test 2 [ [ test-two ] assoc-each ] with-null-writer diff --git a/extra/unicode/collation/collation.factor b/extra/unicode/collation/collation.factor index b12a10709e..f71a58be85 100755 --- a/extra/unicode/collation/collation.factor +++ b/extra/unicode/collation/collation.factor @@ -6,6 +6,7 @@ unicode.syntax macros sequences.deep words unicode.breaks quotations ; IN: unicode.collation + : completely-ignorable? ( weight -- ? ) [ primary>> ] [ secondary>> ] [ tertiary>> ] tri @@ -131,11 +133,13 @@ ducet insert-helpers nfd string>graphemes graphemes>weights filter-ignorable weights>bytes ; + : primary= ( str1 str2 -- ? ) 3 insensitive= ; @@ -149,17 +153,14 @@ ducet insert-helpers : quaternary= ( str1 str2 -- ? ) 0 insensitive= ; -: compare-collation ( {str1,key} {str2,key} -- <=> ) - 2dup [ second ] bi@ <=> dup +eq+ = - [ drop <=> ] [ 2nip ] if ; - + : sort-strings ( strings -- sorted ) [ w/collation-key ] map - [ compare-collation ] sort - keys ; + natural-sort values ; : string<=> ( str1 str2 -- <=> ) - [ w/collation-key ] bi@ compare-collation ; + [ w/collation-key ] compare ; diff --git a/extra/urls/urls-tests.factor b/extra/urls/urls-tests.factor index e28816fdb3..87c9b91950 100644 --- a/extra/urls/urls-tests.factor +++ b/extra/urls/urls-tests.factor @@ -1,5 +1,7 @@ IN: urls.tests -USING: urls tools.test tuple-syntax arrays kernel assocs ; +USING: urls urls.private tools.test +tuple-syntax arrays kernel assocs +present accessors ; [ "hello%20world" ] [ "hello world" url-encode ] unit-test [ "hello world" ] [ "hello%20world" url-decode ] unit-test @@ -77,14 +79,40 @@ USING: urls tools.test tuple-syntax arrays kernel assocs ; } "a/relative/path" } + { + TUPLE{ url + path: "bar" + query: H{ { "a" "b" } } + } + "bar?a=b" + } + { + TUPLE{ url + protocol: "ftp" + host: "ftp.kernel.org" + username: "slava" + path: "/" + } + "ftp://slava@ftp.kernel.org/" + } + { + TUPLE{ url + protocol: "ftp" + host: "ftp.kernel.org" + username: "slava" + password: "secret" + path: "/" + } + "ftp://slava:secret@ftp.kernel.org/" + } } ; urls [ - [ 1array ] [ [ string>url ] curry ] bi* unit-test + [ 1array ] [ [ >url ] curry ] bi* unit-test ] assoc-each urls [ - swap [ 1array ] [ [ url>string ] curry ] bi* unit-test + swap [ 1array ] [ [ present ] curry ] bi* unit-test ] assoc-each [ "b" ] [ "a" "b" url-append-path ] unit-test @@ -192,3 +220,9 @@ urls [ derive-url ] unit-test + +[ "a" ] [ + "a" "b" set-query-param "b" query-param +] unit-test + +[ "foo#3" ] [ URL" foo" clone 3 >>anchor present ] unit-test diff --git a/extra/urls/urls.factor b/extra/urls/urls.factor index e20df65656..7e74fd1115 100644 --- a/extra/urls/urls.factor +++ b/extra/urls/urls.factor @@ -1,9 +1,10 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel unicode.categories combinators sequences splitting -fry namespaces assocs arrays strings mirrors -io.encodings.string io.encodings.utf8 -math math.parser accessors namespaces.lib ; +fry namespaces assocs arrays strings io.sockets +io.sockets.secure io.encodings.string io.encodings.utf8 +math math.parser accessors mirrors parser +prettyprint.backend hashtables present ; IN: urls : url-quotable? ( ch -- ? ) @@ -13,19 +14,25 @@ IN: urls { [ dup letter? ] [ t ] } { [ dup LETTER? ] [ t ] } { [ dup digit? ] [ t ] } - { [ dup "/_-.:" member? ] [ t ] } + { [ dup "/_-." member? ] [ t ] } [ f ] } cond nip ; foldable +hex 2 CHAR: 0 pad-left % ] each ; +PRIVATE> + : url-encode ( str -- str ) [ [ dup url-quotable? [ , ] [ push-utf8 ] if ] each ] "" make ; += [ 2drop @@ -50,9 +57,13 @@ IN: urls ] if url-decode-iter ] if ; +PRIVATE> + : url-decode ( str -- str ) [ 0 swap url-decode-iter ] "" make utf8 decode ; + + : query>assoc ( query -- assoc ) dup [ "&" split H{ } clone [ @@ -76,11 +89,7 @@ IN: urls : assoc>query ( hash -- str ) [ - { - { [ dup number? ] [ number>string 1array ] } - { [ dup string? ] [ 1array ] } - { [ dup sequence? ] [ ] } - } cond + dup array? [ [ present ] map ] [ present 1array ] if ] assoc-map [ [ @@ -89,13 +98,15 @@ IN: urls ] assoc-each ] { } make "&" join ; -TUPLE: url protocol host port path query anchor ; +TUPLE: url protocol username password host port path query anchor ; -: query-param ( request key -- value ) +: ( -- url ) url new ; + +: query-param ( url key -- value ) swap query>> at ; -: set-query-param ( request value key -- request ) - pick query>> set-at ; +: set-query-param ( url value key -- url ) + '[ , , _ ?set-at ] change-query ; : parse-host ( string -- host port ) ":" split1 [ url-decode ] [ @@ -105,40 +116,62 @@ TUPLE: url protocol host port path query anchor ; ] when ] bi* ; -: parse-host-part ( protocol rest -- string' ) - [ "protocol" set ] [ +>protocol ] [ "//" ?head [ "Invalid URL" throw ] unless + "@" split1 [ + [ + ":" split1 [ >>username ] [ >>password ] bi* + ] dip + ] when* "/" split1 [ - parse-host [ "host" set ] [ "port" set ] bi* + parse-host [ >>host ] [ >>port ] bi* ] [ "/" prepend ] bi* ] bi* ; -: string>url ( string -- url ) - [ - ":" split1 [ parse-host-part ] when* - "#" split1 [ - "?" split1 [ query>assoc "query" set ] when* - url-decode "path" set - ] [ - url-decode "anchor" set - ] bi* - ] url make-object ; +PRIVATE> -: unparse-host-part ( protocol -- ) +GENERIC: >url ( obj -- url ) + +M: url >url ; + +M: string >url + swap + ":" split1 [ parse-host-part ] when* + "#" split1 [ + "?" split1 + [ url-decode >>path ] + [ [ query>assoc >>query ] when* ] bi* + ] + [ url-decode >>anchor ] bi* ; + +> dup [ + % password>> [ ":" % % ] when* "@" % + ] [ 2drop ] if ; + +: unparse-host-part ( url protocol -- ) % "://" % - "host" get url-encode % - "port" get [ ":" % # ] when* - "path" get "/" head? [ "Invalid URL" throw ] unless ; + { + [ unparse-username-password ] + [ host>> url-encode % ] + [ port>> [ ":" % # ] when* ] + [ path>> "/" head? [ "/" % ] unless ] + } cleave ; -: url>string ( url -- string ) +M: url present [ - [ - "protocol" get [ unparse-host-part ] when* - "path" get url-encode % - "query" get [ "?" % assoc>query % ] when* - "anchor" get [ "#" % url-encode % ] when* - ] bind + { + [ dup protocol>> dup [ unparse-host-part ] [ 2drop ] if ] + [ path>> url-encode % ] + [ query>> dup assoc-empty? [ drop ] [ "?" % assoc>query % ] if ] + [ anchor>> [ "#" % present url-encode % ] when* ] + } cleave ] "" make ; : url-append-path ( path1 path2 -- path ) @@ -150,6 +183,8 @@ TUPLE: url protocol host port path query anchor ; [ [ "/" last-split1 drop "/" ] dip 3append ] } cond ; +PRIVATE> + : derive-url ( base url -- url' ) [ clone dup ] dip 2dup [ path>> ] bi@ url-append-path @@ -158,3 +193,26 @@ TUPLE: url protocol host port path query anchor ; : relative-url ( url -- url' ) clone f >>protocol f >>host f >>port ; + +! Half-baked stuff follows +: secure-protocol? ( protocol -- ? ) + "https" = ; + +: url-addr ( url -- addr ) + [ [ host>> ] [ port>> ] bi ] [ protocol>> ] bi + secure-protocol? [ ] when ; + +: protocol-port ( protocol -- port ) + { + { "http" [ 80 ] } + { "https" [ 443 ] } + { "ftp" [ 21 ] } + } case ; + +: ensure-port ( url -- url' ) + dup protocol>> '[ , protocol-port or ] change-port ; + +! Literal syntax +: URL" lexer get skip-blank parse-string >url parsed ; parsing + +M: url pprint* dup present "URL\" " "\"" pprint-string ; diff --git a/extra/webapps/blogs/blogs-common.xml b/extra/webapps/blogs/blogs-common.xml new file mode 100644 index 0000000000..38005e6f1c --- /dev/null +++ b/extra/webapps/blogs/blogs-common.xml @@ -0,0 +1,31 @@ + + + + + Recent Posts + + + + + +

+ + + +
diff --git a/extra/webapps/blogs/blogs.css b/extra/webapps/blogs/blogs.css new file mode 100644 index 0000000000..66676796a4 --- /dev/null +++ b/extra/webapps/blogs/blogs.css @@ -0,0 +1,15 @@ +.post-form { + border: 2px solid #666; + padding: 10px; + background: #eee; +} + +.post-title { + background-color:#f5f5ff; + padding: 3px; +} + +.post-footer { + text-align: right; + font-size:90%; +} diff --git a/extra/webapps/blogs/blogs.factor b/extra/webapps/blogs/blogs.factor new file mode 100644 index 0000000000..60911b4947 --- /dev/null +++ b/extra/webapps/blogs/blogs.factor @@ -0,0 +1,253 @@ +! Copyright (C) 2008 Slava Pestov +! See http://factorcode.org/license.txt for BSD license. +USING: kernel accessors sequences sorting math.order math.parser +urls validators html.components db.types db.tuples calendar +http.server.dispatchers +furnace furnace.actions furnace.auth.login furnace.boilerplate +furnace.sessions furnace.syndication ; +IN: webapps.blogs + +TUPLE: blogs < dispatcher ; + +: view-post-url ( id -- url ) + number>string "$blogs/post/" prepend >url ; + +: view-comment-url ( parent id -- url ) + [ view-post-url ] dip >>anchor ; + +: list-posts-url ( -- url ) + URL" $blogs/" ; + +: user-posts-url ( author -- url ) + "$blogs/by/" prepend >url ; + +TUPLE: entity id author date content ; + +GENERIC: entity-url ( entity -- url ) + +M: entity feed-entry-url entity-url ; + +entity f { + { "id" "ID" INTEGER +db-assigned-id+ } + { "author" "AUTHOR" { VARCHAR 256 } +not-null+ } ! uid + { "date" "DATE" TIMESTAMP +not-null+ } + { "content" "CONTENT" TEXT +not-null+ } +} define-persistent + +M: entity feed-entry-date date>> ; + +TUPLE: post < entity title comments ; + +M: post feed-entry-title + [ author>> ] [ drop ": " ] [ title>> ] tri 3append ; + +M: post entity-url + id>> view-post-url ; + +\ post "BLOG_POSTS" { + { "title" "TITLE" { VARCHAR 256 } +not-null+ } +} define-persistent + +: ( id -- post ) \ post new swap >>id ; + +: init-posts-table \ post ensure-table ; + +TUPLE: comment < entity parent ; + +comment "COMMENTS" { + { "parent" "PARENT" INTEGER +not-null+ } ! post id +} define-persistent + +M: comment feed-entry-title + author>> "Comment by " prepend ; + +M: comment entity-url + [ parent>> ] [ id>> ] bi view-comment-url ; + +: ( parent id -- post ) + comment new + swap >>id + swap >>parent ; + +: init-comments-table comment ensure-table ; + +: post ( id -- post ) + [ select-tuple ] [ f select-tuples ] bi + >>comments ; + +: reverse-chronological-order ( seq -- sorted ) + [ [ date>> ] compare invert-comparison ] sort ; + +: validate-author ( -- ) + { { "author" [ [ v-username ] v-optional ] } } validate-params ; + +: list-posts ( -- posts ) + f "author" value >>author + select-tuples [ dup id>> f count-tuples >>comments ] map + reverse-chronological-order ; + +: ( -- action ) + + [ + list-posts "posts" set-value + ] >>init + + { blogs "list-posts" } >>template ; + +: ( -- action ) + + [ "Recent Posts" ] >>title + [ list-posts ] >>entries + [ list-posts-url ] >>url ; + +: ( -- action ) + + "author" >>rest + [ + validate-author + list-posts "posts" set-value + ] >>init + { blogs "user-posts" } >>template ; + +: ( -- action ) + + [ validate-author ] >>init + [ "Recent Posts by " "author" value append ] >>title + [ list-posts ] >>entries + [ "author" value user-posts-url ] >>url ; + +: ( -- action ) + + [ validate-integer-id "id" value post "post" set-value ] >>init + [ "post" value feed-entry-title ] >>title + [ "post" value entity-url ] >>url + [ "post" value comments>> ] >>entries ; + +: ( -- action ) + + "id" >>rest + + [ + validate-integer-id + "id" value post from-object + + "id" value + "new-comment" [ + "parent" set-value + ] nest-values + ] >>init + + { blogs "view-post" } >>template ; + +: validate-post ( -- ) + { + { "title" [ v-one-line ] } + { "content" [ v-required ] } + } validate-params ; + +: ( -- action ) + + [ + validate-post + uid "author" set-value + ] >>validate + + [ + f + dup { "title" "content" } deposit-slots + uid >>author + now >>date + [ insert-tuple ] [ entity-url ] bi + ] >>submit + + { blogs "new-post" } >>template ; + +: ( -- action ) + + [ + validate-integer-id + "id" value select-tuple from-object + ] >>init + + [ + validate-integer-id + validate-post + ] >>validate + + [ + "id" value select-tuple + dup { "title" "content" } deposit-slots + [ update-tuple ] [ entity-url ] bi + ] >>submit + + { blogs "edit-post" } >>template ; + +: ( -- action ) + + [ + validate-integer-id + { { "author" [ v-username ] } } validate-params + ] >>validate + [ + "id" value delete-tuples + "author" value user-posts-url + ] >>submit ; + +: validate-comment ( -- ) + { + { "parent" [ v-integer ] } + { "content" [ v-required ] } + } validate-params ; + +: ( -- action ) + + + [ + validate-comment + uid "author" set-value + ] >>validate + + [ + "parent" value f + "content" value >>content + uid >>author + now >>date + [ insert-tuple ] [ entity-url ] bi + ] >>submit ; + +: ( -- action ) + + [ + validate-integer-id + { { "parent" [ v-integer ] } } validate-params + ] >>validate + [ + f "id" value delete-tuples + "parent" value view-post-url + ] >>submit ; + +: ( -- dispatcher ) + blogs new-dispatcher + "" add-responder + "posts.atom" add-responder + "by" add-responder + "by.atom" add-responder + "post" add-responder + "post.atom" add-responder + + "make a new blog post" >>description + "new-post" add-responder + + "edit a blog post" >>description + "edit-post" add-responder + + "delete a blog post" >>description + "delete-post" add-responder + + "make a comment" >>description + "new-comment" add-responder + + "delete a comment" >>description + "delete-comment" add-responder + + { blogs "blogs-common" } >>template ; diff --git a/extra/webapps/blogs/edit-post.xml b/extra/webapps/blogs/edit-post.xml new file mode 100644 index 0000000000..da88a78ab0 --- /dev/null +++ b/extra/webapps/blogs/edit-post.xml @@ -0,0 +1,29 @@ + + + + + Edit: + +
+ + +

Title:

+

+ +
+
+ + + +
diff --git a/extra/webapps/blogs/list-posts.xml b/extra/webapps/blogs/list-posts.xml new file mode 100644 index 0000000000..9c9685fe74 --- /dev/null +++ b/extra/webapps/blogs/list-posts.xml @@ -0,0 +1,35 @@ + + + + + Recent Posts + + + +

+ + + +

+ +

+ +

+ + + +
+ +
diff --git a/extra/webapps/blogs/new-post.xml b/extra/webapps/blogs/new-post.xml new file mode 100644 index 0000000000..9cb0250518 --- /dev/null +++ b/extra/webapps/blogs/new-post.xml @@ -0,0 +1,17 @@ + + + + + New Post + +
+ + +

Title:

+

+ +
+
+ + +
diff --git a/extra/webapps/blogs/user-posts.xml b/extra/webapps/blogs/user-posts.xml new file mode 100644 index 0000000000..95fae23b34 --- /dev/null +++ b/extra/webapps/blogs/user-posts.xml @@ -0,0 +1,41 @@ + + + + + + Recent Posts by + + + + Recent Posts by + + + + +

+ + + +

+ +

+ +

+ + + +
+ +
diff --git a/extra/webapps/blogs/view-post.xml b/extra/webapps/blogs/view-post.xml new file mode 100644 index 0000000000..3489f1e331 --- /dev/null +++ b/extra/webapps/blogs/view-post.xml @@ -0,0 +1,60 @@ + + + + + + : + + + + Recent Posts by + + + + +

+ +

+ + + + +
+ +

+ Comment by on : +

+ +

+ +

+ + Delete Comment + +
+ + + +

New Comment

+ +
+ +

+

+
+
+ +
+ +
diff --git a/extra/webapps/counter/counter.factor b/extra/webapps/counter/counter.factor index 04194adb29..da646fb76f 100644 --- a/extra/webapps/counter/counter.factor +++ b/extra/webapps/counter/counter.factor @@ -1,6 +1,7 @@ -USING: math kernel accessors html.components -http.server http.server.actions -http.server.sessions html.templates.chloe fry ; +USING: math kernel accessors http.server http.server.dispatchers +furnace furnace.actions furnace.sessions +html.components html.templates.chloe +fry urls ; IN: webapps.counter SYMBOL: count @@ -11,15 +12,15 @@ M: counter-app init-session* drop 0 count sset ; : ( quot -- action ) - swap '[ count , schange "" f ] >>submit ; - -: counter-template ( -- template ) - "resource:extra/webapps/counter/counter.xml" ; + swap '[ + count , schange + URL" $counter-app" + ] >>submit ; : ( -- action ) [ count sget "counter" set-value ] >>init - counter-template >>template ; + { counter-app "counter" } >>template ; : ( -- responder ) counter-app new-dispatcher diff --git a/extra/webapps/factor-website/factor-website.factor b/extra/webapps/factor-website/factor-website.factor index 9ad4a05492..d17a912ad8 100644 --- a/extra/webapps/factor-website/factor-website.factor +++ b/extra/webapps/factor-website/factor-website.factor @@ -4,25 +4,25 @@ USING: accessors kernel sequences assocs io.files io.sockets io.server namespaces db db.sqlite smtp http.server -http.server.db -http.server.flows -http.server.sessions -http.server.auth.login -http.server.auth.providers.db -http.server.boilerplate -html.templates.chloe +http.server.dispatchers +furnace.db +furnace.asides +furnace.flash +furnace.sessions +furnace.auth.login +furnace.auth.providers.db +furnace.boilerplate +webapps.blogs webapps.pastebin webapps.planet webapps.todo webapps.wiki +webapps.wee-url webapps.user-admin ; IN: webapps.factor-website : test-db "resource:test.db" sqlite-db ; -: factor-template ( path -- template ) - "resource:extra/webapps/factor-website/" swap ".xml" 3append ; - : init-factor-db ( -- ) test-db [ init-users-table @@ -38,14 +38,23 @@ IN: webapps.factor-website init-articles-table init-revisions-table + + init-postings-table + init-comments-table + + init-short-url-table ] with-db ; +TUPLE: factor-website < dispatcher ; + : ( -- responder ) - + factor-website new-dispatcher + "blogs" add-responder "todo" add-responder "pastebin" add-responder "planet" add-responder "wiki" add-responder + "wee-url" add-responder "user-admin" add-responder users-in-db >>users @@ -53,9 +62,8 @@ IN: webapps.factor-website allow-password-recovery allow-edit-profile - "page" factor-template >>template - - + { factor-website "page" } >>template + test-db ; : init-factor-website ( -- ) diff --git a/extra/webapps/factor-website/page.xml b/extra/webapps/factor-website/page.xml index f7080643b4..32e1223c58 100644 --- a/extra/webapps/factor-website/page.xml +++ b/extra/webapps/factor-website/page.xml @@ -15,6 +15,8 @@ + + diff --git a/extra/webapps/pastebin/paste.xml b/extra/webapps/pastebin/paste.xml index 57c2fdb7c2..1c138fc8c0 100644 --- a/extra/webapps/pastebin/paste.xml +++ b/extra/webapps/pastebin/paste.xml @@ -2,7 +2,9 @@ - + + Paste: + Paste: @@ -12,15 +14,13 @@ Date: -
+
Delete Paste - | - Annotate - + -

Annotation:

+

Annotation:

@@ -30,21 +30,21 @@
- Delete Annotation + Delete Annotation - + - +

New Annotation

- +
Author:
- + @@ -53,8 +53,9 @@
Summary:
Author:
Mode:
Body:
Body:
Captcha:
+
- + diff --git a/extra/webapps/pastebin/pastebin-common.xml b/extra/webapps/pastebin/pastebin-common.xml index f785fceb6b..47f7666b22 100644 --- a/extra/webapps/pastebin/pastebin-common.xml +++ b/extra/webapps/pastebin/pastebin-common.xml @@ -2,6 +2,8 @@ + Pastebin + diff --git a/extra/webapps/planet/planet.factor b/extra/webapps/planet/planet.factor index 414a59f3b2..5af96cd4f7 100755 --- a/extra/webapps/planet/planet.factor +++ b/extra/webapps/planet/planet.factor @@ -3,18 +3,22 @@ USING: kernel accessors sequences sorting math math.order calendar alarms logging concurrency.combinators namespaces sequences.lib db.types db.tuples db fry locals hashtables -html.components html.templates.chloe -rss xml.writer +html.components +syndication urls xml.writer validators http.server -http.server.actions -http.server.boilerplate -http.server.auth.login -http.server.auth ; +http.server.dispatchers +furnace +furnace.actions +furnace.boilerplate +furnace.auth.login +furnace.auth +furnace.syndication ; IN: webapps.planet -: planet-template ( name -- template ) - "resource:extra/webapps/planet/" swap ".xml" 3append ; +TUPLE: planet-factor < dispatcher ; + +TUPLE: planet-factor-admin < dispatcher ; TUPLE: blog id name www-url feed-url ; @@ -30,16 +34,15 @@ blog "BLOGS" { "feed-url" "FEEDURL" { VARCHAR 256 } +not-null+ } } define-persistent -! TUPLE: posting < entry id ; -TUPLE: posting id title link description pub-date ; +TUPLE: posting < entry id ; posting "POSTINGS" { { "id" "ID" INTEGER +db-assigned-id+ } { "title" "TITLE" { VARCHAR 256 } +not-null+ } - { "link" "LINK" { VARCHAR 256 } +not-null+ } + { "url" "LINK" { VARCHAR 256 } +not-null+ } { "description" "DESCRIPTION" TEXT +not-null+ } - { "pub-date" "DATE" TIMESTAMP +not-null+ } + { "date" "DATE" TIMESTAMP +not-null+ } } define-persistent : init-blog-table blog ensure-table ; @@ -56,12 +59,12 @@ posting "POSTINGS" : postings ( -- seq ) posting new select-tuples - [ [ pub-date>> ] compare invert-comparison ] sort ; + [ [ date>> ] compare invert-comparison ] sort ; : ( -- action ) [ blogroll "blogroll" set-value ] >>init - "admin" planet-template >>template ; + { planet-factor "admin" } >>template ; : ( -- action ) @@ -70,23 +73,20 @@ posting "POSTINGS" postings "postings" set-value ] >>init - "planet" planet-template >>template ; - -: planet-feed ( -- feed ) - feed new - "Planet Factor" >>title - "http://planet.factorcode.org" >>link - postings >>entries ; + { planet-factor "planet" } >>template ; : ( -- action ) - [ planet-feed ] >>feed ; + + [ "Planet Factor" ] >>title + [ URL" $planet-factor" ] >>url + [ postings ] >>entries ; :: ( entry name -- entry' ) posting new name ": " entry title>> 3append >>title - entry link>> >>link + entry url>> >>url entry description>> >>description - entry pub-date>> >>pub-date ; + entry date>> >>date ; : fetch-feed ( url -- feed ) download-feed entries>> ; @@ -98,7 +98,7 @@ posting "POSTINGS" [ '[ , ] map ] 2map concat ; : sort-entries ( entries -- entries' ) - [ [ pub-date>> ] compare invert-comparison ] sort ; + [ [ date>> ] compare invert-comparison ] sort ; : update-cached-postings ( -- ) blogroll fetch-blogroll sort-entries 8 short head [ @@ -110,7 +110,7 @@ posting "POSTINGS" [ update-cached-postings - "" f + URL" $planet-factor/admin" ] >>submit ; : ( -- action ) @@ -119,7 +119,7 @@ posting "POSTINGS" [ "id" value delete-tuples - "$planet-factor/admin" f + URL" $planet-factor/admin" ] >>submit ; : validate-blog ( -- ) @@ -129,15 +129,12 @@ posting "POSTINGS" { "feed-url" [ v-url ] } } validate-params ; -: ( id next -- response ) - swap "id" associate ; - : deposit-blog-slots ( blog -- ) { "name" "www-url" "feed-url" } deposit-slots ; : ( -- action ) - "new-blog" planet-template >>template + { planet-factor "new-blog" } >>template [ validate-blog ] >>validate @@ -145,7 +142,12 @@ posting "POSTINGS" f [ deposit-blog-slots ] [ insert-tuple ] - [ id>> "$planet-factor/admin/edit-blog" ] + [ + + "$planet-factor/admin/edit-blog" >>path + swap id>> "id" set-query-param + + ] tri ] >>submit ; @@ -153,10 +155,10 @@ posting "POSTINGS" [ validate-integer-id - "id" value select-tuple from-tuple + "id" value select-tuple from-object ] >>init - "edit-blog" planet-template >>template + { planet-factor "edit-blog" } >>template [ validate-integer-id @@ -167,12 +169,15 @@ posting "POSTINGS" f [ deposit-blog-slots ] [ update-tuple ] - [ id>> "$planet-factor/admin" ] + [ + + "$planet-factor/admin" >>path + swap id>> "id" set-query-param + + ] tri ] >>submit ; -TUPLE: planet-factor-admin < dispatcher ; - : ( -- responder ) planet-factor-admin new-dispatcher "blogroll" add-main-responder @@ -185,15 +190,16 @@ SYMBOL: can-administer-planet-factor? can-administer-planet-factor? define-capability -TUPLE: planet-factor < dispatcher ; - : ( -- responder ) planet-factor new-dispatcher "list" add-main-responder - "feed.xml" add-responder - { can-administer-planet-factor? } "admin" add-responder + "feed.xml" add-responder + + "administer Planet Factor" >>description + { can-administer-planet-factor? } >>capabilities + "admin" add-responder - "planet-common" planet-template >>template ; + { planet-factor "planet-common" } >>template ; : start-update-task ( db params -- ) '[ , , [ update-cached-postings ] with-db ] 10 minutes every drop ; diff --git a/extra/webapps/planet/planet.xml b/extra/webapps/planet/planet.xml index 526a9b306b..fe4d23bd3b 100644 --- a/extra/webapps/planet/planet.xml +++ b/extra/webapps/planet/planet.xml @@ -8,10 +8,10 @@ - +

- +

@@ -19,10 +19,10 @@

- +

-
+ @@ -31,7 +31,7 @@

Blogroll

    - +
  • diff --git a/extra/webapps/todo/edit-todo.xml b/extra/webapps/todo/edit-todo.xml index 0974c8ce1b..6bae6e705e 100644 --- a/extra/webapps/todo/edit-todo.xml +++ b/extra/webapps/todo/edit-todo.xml @@ -14,12 +14,8 @@ - - - View - | - Delete - - + View + | + Delete diff --git a/extra/webapps/todo/new-todo.xml b/extra/webapps/todo/new-todo.xml new file mode 100644 index 0000000000..f557d5307b --- /dev/null +++ b/extra/webapps/todo/new-todo.xml @@ -0,0 +1,17 @@ + + + + + New Item + + + + + + +
    Summary:
    Priority:
    Description:
    + + +
    + +
    diff --git a/extra/webapps/todo/todo-list.xml b/extra/webapps/todo/todo-list.xml index 845c38dbf7..036c590306 100644 --- a/extra/webapps/todo/todo-list.xml +++ b/extra/webapps/todo/todo-list.xml @@ -13,7 +13,7 @@ Edit - + @@ -30,7 +30,7 @@ - + diff --git a/extra/webapps/todo/todo.factor b/extra/webapps/todo/todo.factor index e3b174eaea..a588b880d3 100755 --- a/extra/webapps/todo/todo.factor +++ b/extra/webapps/todo/todo.factor @@ -1,18 +1,22 @@ ! Copyright (c) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel sequences namespaces -db db.types db.tuples validators hashtables +db db.types db.tuples validators hashtables urls html.components html.templates.chloe -http.server.sessions -http.server.boilerplate -http.server.auth -http.server.actions -http.server.db -http.server.auth.login -http.server ; +http.server +http.server.dispatchers +furnace +furnace.sessions +furnace.boilerplate +furnace.auth +furnace.actions +furnace.db +furnace.auth.login ; IN: webapps.todo +TUPLE: todo-list < dispatcher ; + TUPLE: todo uid id priority summary description ; todo "TODO" @@ -31,20 +35,14 @@ todo "TODO" swap >>id uid >>uid ; -: todo-template ( name -- template ) - "resource:extra/webapps/todo/" swap ".xml" 3append ; - : ( -- action ) [ validate-integer-id - "id" value select-tuple from-tuple + "id" value select-tuple from-object ] >>init - "view-todo" todo-template >>template ; - -: ( id next -- response ) - swap "id" associate ; + { todo-list "view-todo" } >>template ; : validate-todo ( -- ) { @@ -53,30 +51,31 @@ todo "TODO" { "description" [ v-required ] } } validate-params ; +: view-todo-url ( id -- url ) + "$todo-list/view" >>path swap "id" set-query-param ; + : ( -- action ) [ 0 "priority" set-value ] >>init - "edit-todo" todo-template >>template + { todo-list "new-todo" } >>template [ validate-todo ] >>validate [ f - dup { "summary" "description" } deposit-slots - [ insert-tuple ] - [ id>> "$todo-list/view" ] - bi + dup { "summary" "priority" "description" } deposit-slots + [ insert-tuple ] [ id>> view-todo-url ] bi ] >>submit ; : ( -- action ) [ validate-integer-id - "id" value select-tuple from-tuple + "id" value select-tuple from-object ] >>init - "edit-todo" todo-template >>template + { todo-list "edit-todo" } >>template [ validate-integer-id @@ -86,26 +85,25 @@ todo "TODO" [ f dup { "id" "summary" "priority" "description" } deposit-slots - [ update-tuple ] - [ id>> "$todo-list/view" ] - bi + [ update-tuple ] [ id>> view-todo-url ] bi ] >>submit ; +: todo-list-url ( -- url ) + URL" $todo-list/list" ; + : ( -- action ) [ validate-integer-id ] >>validate [ "id" get delete-tuples - "$todo-list/list" f + todo-list-url ] >>submit ; : ( -- action ) [ f select-tuples "items" set-value ] >>init - "todo-list" todo-template >>template ; - -TUPLE: todo-list < dispatcher ; + { todo-list "todo-list" } >>template ; : ( -- responder ) todo-list new-dispatcher @@ -115,5 +113,6 @@ TUPLE: todo-list < dispatcher ; "edit" add-responder "delete" add-responder - "todo" todo-template >>template - f ; + { todo-list "todo" } >>template + + "view your todo list" >>description ; diff --git a/extra/webapps/todo/todo.xml b/extra/webapps/todo/todo.xml index 39ab5cda8b..e087fbfcfc 100644 --- a/extra/webapps/todo/todo.xml +++ b/extra/webapps/todo/todo.xml @@ -6,13 +6,13 @@

    diff --git a/extra/webapps/user-admin/edit-user.xml b/extra/webapps/user-admin/edit-user.xml index 3f9ac8d690..0c55f8ca76 100644 --- a/extra/webapps/user-admin/edit-user.xml +++ b/extra/webapps/user-admin/edit-user.xml @@ -35,7 +35,11 @@ Capabilities: - + + +
    +
    + diff --git a/extra/webapps/user-admin/new-user.xml b/extra/webapps/user-admin/new-user.xml index 881dca9c16..b1f35c979b 100644 --- a/extra/webapps/user-admin/new-user.xml +++ b/extra/webapps/user-admin/new-user.xml @@ -35,7 +35,11 @@ Capabilities: - + + +

  • + + diff --git a/extra/webapps/user-admin/user-admin.factor b/extra/webapps/user-admin/user-admin.factor index cdaf3f5ea9..19153e1354 100644 --- a/extra/webapps/user-admin/user-admin.factor +++ b/extra/webapps/user-admin/user-admin.factor @@ -1,45 +1,47 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences accessors namespaces combinators words -assocs db.tuples arrays splitting strings validators +assocs db.tuples arrays splitting strings validators urls html.elements html.components -html.templates.chloe -http.server.boilerplate -http.server.auth.providers -http.server.auth.providers.db -http.server.auth.login -http.server.auth -http.server.sessions -http.server.actions -http.server ; +furnace +furnace.boilerplate +furnace.auth.providers +furnace.auth.providers.db +furnace.auth.login +furnace.auth +furnace.sessions +furnace.actions +http.server +http.server.dispatchers ; IN: webapps.user-admin -: admin-template ( name -- template ) - "resource:extra/webapps/user-admin/" swap ".xml" 3append ; - -: words>strings ( seq -- seq' ) - [ [ word-vocabulary ] [ drop ":" ] [ word-name ] tri 3append ] map ; - -: strings>words ( seq -- seq' ) - [ ":" split1 swap lookup ] map ; +TUPLE: user-admin < dispatcher ; : ( -- action ) [ f select-tuples "users" set-value ] >>init - "user-list" admin-template >>template ; + { user-admin "user-list" } >>template ; + +: init-capabilities ( -- ) + capabilities get words>strings "capabilities" set-value ; + +: selected-capabilities ( -- seq ) + "capabilities" value + [ param empty? not ] filter + [ string>word ] map ; : ( -- action ) [ - "username" param from-tuple - capabilities get words>strings "all-capabilities" set-value + "username" param from-object + init-capabilities ] >>init - "new-user" admin-template >>template + { user-admin "new-user" } >>template [ - capabilities get words>strings "all-capabilities" set-value + init-capabilities { { "username" [ v-username ] } @@ -62,10 +64,11 @@ IN: webapps.user-admin "email" value >>email "new-password" value >>encoded-password H{ } clone >>profile + selected-capabilities >>capabilities insert-tuple - "$user-admin" f + URL" $user-admin" ] >>submit ; : validate-username ( -- ) @@ -77,15 +80,16 @@ IN: webapps.user-admin validate-username "username" value select-tuple - [ from-tuple ] [ capabilities>> words>strings "capabilities" set-value ] bi + [ from-object ] + [ capabilities>> [ "true" swap word>string set-value ] each ] bi - capabilities get words>strings "all-capabilities" set-value + init-capabilities ] >>init - "edit-user" admin-template >>template + { user-admin "edit-user" } >>template [ - capabilities get words>strings "all-capabilities" set-value + init-capabilities { { "username" [ v-username ] } @@ -93,7 +97,6 @@ IN: webapps.user-admin { "new-password" [ [ v-password ] v-optional ] } { "verify-password" [ [ v-password ] v-optional ] } { "email" [ [ v-email ] v-optional ] } - { "capabilities" [ ] } } validate-params "new-password" "verify-password" @@ -106,19 +109,15 @@ IN: webapps.user-admin "username" value select-tuple "realname" value >>realname "email" value >>email + selected-capabilities >>capabilities "new-password" value empty? [ "new-password" value >>encoded-password ] unless - "capabilities" value { - { [ dup string? ] [ 1array ] } - { [ dup array? ] [ ] } - } cond strings>words >>capabilities - update-tuple - "$user-admin" f + URL" $user-admin" ] >>submit ; : ( -- action ) @@ -130,11 +129,9 @@ IN: webapps.user-admin [ logout-all-sessions ] bi - "$user-admin" f + URL" $user-admin" ] >>submit ; -TUPLE: user-admin < dispatcher ; - SYMBOL: can-administer-users? can-administer-users? define-capability @@ -146,8 +143,10 @@ can-administer-users? define-capability "edit" add-responder "delete" add-responder - "user-admin" admin-template >>template - { can-administer-users? } ; + { user-admin "user-admin" } >>template + + "administer users" >>description + { can-administer-users? } >>capabilities ; : make-admin ( username -- ) diff --git a/extra/webapps/user-admin/user-admin.xml b/extra/webapps/user-admin/user-admin.xml index 05817565ed..9cb9ef0a0a 100644 --- a/extra/webapps/user-admin/user-admin.xml +++ b/extra/webapps/user-admin/user-admin.xml @@ -6,11 +6,11 @@ List Users | Add User - - | Edit Profile + + | Edit Profile - | Logout + | Logout

    diff --git a/extra/webapps/user-admin/user-list.xml b/extra/webapps/user-admin/user-list.xml index 020d053e03..83b3f97cf9 100644 --- a/extra/webapps/user-admin/user-list.xml +++ b/extra/webapps/user-admin/user-list.xml @@ -6,13 +6,13 @@
      - +
    • -
      +
    diff --git a/extra/webapps/wee-url/shorten.xml b/extra/webapps/wee-url/shorten.xml new file mode 100644 index 0000000000..8df7774fba --- /dev/null +++ b/extra/webapps/wee-url/shorten.xml @@ -0,0 +1,10 @@ + + + + + +

    Shorten URL:

    + +
    + +
    diff --git a/extra/webapps/wee-url/show.xml b/extra/webapps/wee-url/show.xml new file mode 100644 index 0000000000..ba44629bb1 --- /dev/null +++ b/extra/webapps/wee-url/show.xml @@ -0,0 +1,11 @@ + + + + +

    The URL:

    +
    +

    has been shortened to:

    +
    +

    enjoy!

    + +
    diff --git a/extra/webapps/wee-url/wee-url.factor b/extra/webapps/wee-url/wee-url.factor new file mode 100644 index 0000000000..afdacf9add --- /dev/null +++ b/extra/webapps/wee-url/wee-url.factor @@ -0,0 +1,74 @@ +! Copyright (C) 2007 Doug Coleman. +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: math.ranges sequences random accessors combinators.lib +kernel namespaces fry db.types db.tuples urls validators +html.components http http.server.dispatchers furnace +furnace.actions furnace.boilerplate ; +IN: webapps.wee-url + +TUPLE: wee-url < dispatcher ; + +TUPLE: short-url short url ; + +short-url "SHORT_URLS" { + { "short" "SHORT" TEXT +user-assigned-id+ } + { "url" "URL" TEXT +not-null+ } +} define-persistent + +: init-short-url-table ( -- ) + short-url ensure-table ; + +: letter-bank ( -- seq ) + CHAR: a CHAR: z [a,b] + CHAR: A CHAR: Z [a,b] + CHAR: 1 CHAR: 0 [a,b] + 3append ; foldable + +: random-url ( -- string ) + 1 6 [a,b] random [ drop letter-bank random ] "" map-as ; + +: insert-short-url ( short-url -- short-url ) + '[ , dup random-url >>short insert-tuple ] 10 retry ; + +: shorten ( url -- short ) + short-url new swap >>url dup select-tuple + [ ] [ insert-short-url ] ?if short>> ; + +: short>url ( short -- url ) + "$wee-url/go/" prepend >url adjust-url ; + +: expand-url ( string -- url ) + short-url new swap >>short select-tuple url>> ; + +: ( -- action ) + + { wee-url "shorten" } >>template + [ { { "url" [ v-url ] } } validate-params ] >>validate + [ + "$wee-url/show/" "url" value shorten append >url + ] >>submit ; + +: ( -- action ) + + "short" >>rest + [ + { { "short" [ v-one-word ] } } validate-params + "short" value expand-url "url" set-value + "short" value short>url "short" set-value + ] >>init + { wee-url "show" } >>template ; + +: ( -- action ) + + "short" >>rest + [ { { "short" [ v-one-word ] } } validate-params ] >>init + [ "short" value expand-url ] >>display ; + +: ( -- wee-url ) + wee-url new-dispatcher + "" add-responder + "show" add-responder + "go" add-responder + + { wee-url "wee-url" } >>template ; diff --git a/extra/webapps/wee-url/wee-url.xml b/extra/webapps/wee-url/wee-url.xml new file mode 100644 index 0000000000..98d1095ed6 --- /dev/null +++ b/extra/webapps/wee-url/wee-url.xml @@ -0,0 +1,13 @@ + + + + + WeeURL! + + + +

    + + + +
    diff --git a/extra/webapps/wiki/articles.xml b/extra/webapps/wiki/articles.xml index a552c2618f..e19c531d3d 100644 --- a/extra/webapps/wiki/articles.xml +++ b/extra/webapps/wiki/articles.xml @@ -5,11 +5,11 @@ All Articles
      - +
    • -
      +
    diff --git a/extra/webapps/wiki/changes.xml b/extra/webapps/wiki/changes.xml index 5efa0c045a..5b3e9de2c4 100644 --- a/extra/webapps/wiki/changes.xml +++ b/extra/webapps/wiki/changes.xml @@ -5,15 +5,15 @@ Recent Changes
      - +
    • - + on by
    • -
      +
    diff --git a/extra/webapps/wiki/diff.xml b/extra/webapps/wiki/diff.xml index 0fb0d6bae6..35afe51b66 100644 --- a/extra/webapps/wiki/diff.xml +++ b/extra/webapps/wiki/diff.xml @@ -2,34 +2,23 @@ - - Diff: - + Diff: - + - + - + - +
    Old revision:Created on by .
    New revision:Created on by .
    - - - -
    diff --git a/extra/webapps/wiki/edit.xml b/extra/webapps/wiki/edit.xml index 85c8490c5d..057b7f8f71 100644 --- a/extra/webapps/wiki/edit.xml +++ b/extra/webapps/wiki/edit.xml @@ -16,5 +16,4 @@ - Delete diff --git a/extra/webapps/wiki/page-common.xml b/extra/webapps/wiki/page-common.xml new file mode 100644 index 0000000000..675cb8cd65 --- /dev/null +++ b/extra/webapps/wiki/page-common.xml @@ -0,0 +1,18 @@ + + + + + + Revisions of + + + + + + + diff --git a/extra/webapps/wiki/revisions.xml b/extra/webapps/wiki/revisions.xml index 4b7bdadf50..2a909e6ab3 100644 --- a/extra/webapps/wiki/revisions.xml +++ b/extra/webapps/wiki/revisions.xml @@ -4,15 +4,23 @@ Revisions of -
      - -
    • - - by - -
    • -
      -
    +
    + + + + + + + + + + + + + + +
    RevisionAuthorRollback
    Rollback
    +

    View Differences

    @@ -23,9 +31,9 @@ @@ -34,9 +42,9 @@ diff --git a/extra/webapps/wiki/user-edits.xml b/extra/webapps/wiki/user-edits.xml index cf19a38370..6f22982f12 100644 --- a/extra/webapps/wiki/user-edits.xml +++ b/extra/webapps/wiki/user-edits.xml @@ -2,16 +2,20 @@ + + Edits by + + Edits by
      - +
    • on
    • -
      +
    diff --git a/extra/webapps/wiki/view.xml b/extra/webapps/wiki/view.xml index 56c8b37a1d..30dfb71270 100644 --- a/extra/webapps/wiki/view.xml +++ b/extra/webapps/wiki/view.xml @@ -8,12 +8,6 @@ - +

    This revision created on by .

    diff --git a/extra/webapps/wiki/wiki-common.xml b/extra/webapps/wiki/wiki-common.xml index 23e61e55fe..4c6d1a5b5c 100644 --- a/extra/webapps/wiki/wiki-common.xml +++ b/extra/webapps/wiki/wiki-common.xml @@ -2,6 +2,10 @@ + + Recent Changes + +