diff --git a/Factor.app/Contents/Info.plist b/Factor.app/Contents/Info.plist index c54acd7179..ca0e6d5f8a 100644 --- a/Factor.app/Contents/Info.plist +++ b/Factor.app/Contents/Info.plist @@ -22,7 +22,7 @@ CFBundleExecutable factor CFBundleIconFile - FRaptorMix.icns + Factor.icns CFBundleIdentifier org.factorcode.Factor CFBundleInfoDictionaryVersion diff --git a/Factor.app/Contents/Resources/FRaptorMix.icns b/Factor.app/Contents/Resources/FRaptorMix.icns deleted file mode 100644 index 5cbe894480..0000000000 Binary files a/Factor.app/Contents/Resources/FRaptorMix.icns and /dev/null differ diff --git a/Factor.app/Contents/Resources/Factor.icns b/Factor.app/Contents/Resources/Factor.icns new file mode 100644 index 0000000000..ab70230e9b Binary files /dev/null and b/Factor.app/Contents/Resources/Factor.icns differ diff --git a/core/bootstrap/image/image.factor b/core/bootstrap/image/image.factor index 0f61eb4c83..c749ec3dad 100644 --- a/core/bootstrap/image/image.factor +++ b/core/bootstrap/image/image.factor @@ -36,7 +36,7 @@ IN: bootstrap.image : wrapper@ bootstrap-cell object tag-number - ; : word-xt@ 8 bootstrap-cells object tag-number - ; : quot-array@ bootstrap-cell object tag-number - ; -: quot-xt@ 2 bootstrap-cells object tag-number - ; +: quot-xt@ 3 bootstrap-cells object tag-number - ; ! The image being constructed; a vector of word-size integers SYMBOL: image @@ -312,6 +312,7 @@ M: quotation ' quotation-array ' quotation type-number object tag-number [ emit ! array + f ' emit ! compiled? 0 emit ! XT ] emit-object ] cache ; diff --git a/core/bootstrap/primitives.factor b/core/bootstrap/primitives.factor index 5e7bc1f338..edd1d42dcf 100644 --- a/core/bootstrap/primitives.factor +++ b/core/bootstrap/primitives.factor @@ -452,6 +452,13 @@ num-types get f builtins set { "quotation-array" "quotations.private" } f } + { + { "object" "kernel" } + "compiled?" + 2 + { "quotation-compiled?" "quotations" } + f + } } define-builtin "dll" "alien" create "dll?" "alien" create diff --git a/core/optimizer/debugger/debugger.factor b/core/optimizer/debugger/debugger.factor index 6c323fce1e..ed0358fe7f 100644 --- a/core/optimizer/debugger/debugger.factor +++ b/core/optimizer/debugger/debugger.factor @@ -3,7 +3,7 @@ USING: classes inference inference.dataflow io kernel kernel.private math.parser namespaces optimizer prettyprint prettyprint.backend sequences words arrays match macros -assocs ; +assocs combinators.private ; IN: optimizer.debugger ! A simple tool for turning dataflow IR into quotations, for diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index 8d883ddcbb..1a8e5c9561 100644 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -191,14 +191,14 @@ TUPLE: slice from to seq ; TUPLE: slice-error reason ; : slice-error ( str -- * ) \ slice-error construct-boa throw ; -: check-slice ( from to seq -- ) +: check-slice ( from to seq -- from to seq ) pick 0 < [ "start < 0" slice-error ] when - length over < [ "end > sequence" slice-error ] when - > [ "start > end" slice-error ] when ; + dup length pick < [ "end > sequence" slice-error ] when + pick pick > [ "start > end" slice-error ] when ; : ( from to seq -- slice ) dup slice? [ collapse-slice ] when - 3dup check-slice + check-slice slice construct-boa ; M: slice virtual-seq slice-seq ; @@ -259,7 +259,7 @@ INSTANCE: repetition immutable-sequence PRIVATE> : subseq ( from to seq -- subseq ) - [ 3dup check-slice prepare-subseq (copy) ] keep like ; + [ check-slice prepare-subseq (copy) ] keep like ; : head ( seq n -- headseq ) (head) subseq ; @@ -525,7 +525,7 @@ M: sequence <=> ] if ; : delete-slice ( from to seq -- ) - 3dup check-slice >r over >r - r> r> open-slice ; + check-slice >r over >r - r> r> open-slice ; : delete-nth ( n seq -- ) >r dup 1+ r> delete-slice ; diff --git a/extra/benchmark/dispatch4/dispatch4.factor b/extra/benchmark/dispatch4/dispatch4.factor index 3ad41337d5..a5bb983151 100644 --- a/extra/benchmark/dispatch4/dispatch4.factor +++ b/extra/benchmark/dispatch4/dispatch4.factor @@ -1,4 +1,5 @@ -USING: kernel.private kernel sequences math combinators ; +USING: kernel.private kernel sequences math combinators +combinators.private ; IN: benchmark.dispatch4 : foobar-1 diff --git a/extra/boids/boids.factor b/extra/boids/boids.factor index 397ce6eb5a..3c29f895d7 100644 --- a/extra/boids/boids.factor +++ b/extra/boids/boids.factor @@ -56,7 +56,7 @@ VAR: separation-radius ! random-boid and random-boids ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: random-range ( a b -- n ) 1 + dupd swap - random + ; +: random-range ( a b -- n ) 1+ over - random + ; : random-pos ( -- pos ) world-size> [ random ] map ; @@ -68,7 +68,7 @@ VAR: separation-radius ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: distance ( boid boid -- n ) boid-pos swap boid-pos v- norm ; +: distance ( boid boid -- n ) [ boid-pos ] [ boid-pos ] bi* v- norm ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -79,7 +79,7 @@ VAR: separation-radius ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: relative-position ( self other -- v ) boid-pos swap boid-pos v- ; +: relative-position ( self other -- v ) swap [ boid-pos ] 2apply v- ; : relative-angle ( self other -- angle ) over boid-vel -rot relative-position angle-between ; @@ -88,7 +88,7 @@ over boid-vel -rot relative-position angle-between ; : vsum ( vector-of-vectors -- vec ) { 0 0 } [ v+ ] reduce ; -: vaverage ( seq-of-vectors -- seq ) dup vsum swap length v/n ; +: vaverage ( seq-of-vectors -- seq ) [ vsum ] [ length ] bi v/n ; : average-position ( boids -- pos ) [ boid-pos ] map vaverage ; @@ -204,14 +204,14 @@ cond ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: new-pos ( boid -- pos ) dup boid-vel time-slice> v*n swap boid-pos v+ ; +: new-pos ( boid -- pos ) [ boid-pos ] [ boid-vel time-slice> v*n ] bi v+ ; : new-vel ( boid -- vel ) -dup acceleration time-slice> v*n swap boid-vel v+ normalize* ; + [ boid-vel ] [ acceleration time-slice> v*n ] bi v+ normalize* ; : wrap-pos ( pos -- pos ) { [ wrap-x ] [ wrap-y ] } parallel-call ; -: iterate-boid ( self -- self ) dup >r new-pos wrap-pos r> new-vel ; +: iterate-boid ( self -- self ) [ new-pos wrap-pos ] [ new-vel ] bi ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/extra/boids/ui/ui.factor b/extra/boids/ui/ui.factor index 8b8b4665b8..2bd86f49f6 100644 --- a/extra/boids/ui/ui.factor +++ b/extra/boids/ui/ui.factor @@ -18,7 +18,7 @@ USING: kernel namespaces ui.gadgets.packs ui.gadgets.grids ui.gestures - hashtables.lib vars rewrite-closures boids ; + combinators.lib hashtables.lib vars rewrite-closures boids ; IN: boids.ui @@ -26,16 +26,13 @@ IN: boids.ui ! draw-boid ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: boid-point-a ( boid -- a ) boid-pos ; +: point-a ( boid -- a ) boid-pos ; -: boid-point-b ( boid -- b ) dup boid-pos swap boid-vel normalize* 20 v*n v+ ; +: point-b ( boid -- b ) [ boid-pos ] [ boid-vel normalize* 20 v*n ] bi v+ ; -: boid-points ( boid -- point-a point-b ) dup boid-point-a swap boid-point-b ; +: boid-points ( boid -- point-a point-b ) [ point-a ] [ point-b ] bi ; -: draw-line ( a b -- ) -GL_LINES glBegin first2 glVertex2d first2 glVertex2d glEnd ; - -: draw-boid ( boid -- ) boid-points draw-line ; +: draw-boid ( boid -- ) boid-points gl-line ; : draw-boids ( -- ) boids> [ draw-boid ] each ; diff --git a/extra/cairo-demo/cairo-demo.factor b/extra/cairo-demo/cairo-demo.factor new file mode 100644 index 0000000000..9d7af090a7 --- /dev/null +++ b/extra/cairo-demo/cairo-demo.factor @@ -0,0 +1,72 @@ +! Cairo "Hello World" demo +! Copyright (c) 2007 Sampo Vuori +! License: http://factorcode.org/license.txt +! +! This example is an adaptation of the following cairo sample code: +! http://cairographics.org/samples/text/ + + +USING: cairo math math.constants byte-arrays kernel ui ui.render + ui.gadgets opengl.gl ; + +IN: cairo-demo + + +: make-image-array ( -- array ) + 384 256 4 * * ; + +: convert-array-to-surface ( array -- cairo_surface_t ) + CAIRO_FORMAT_ARGB32 384 256 over 4 * + cairo_image_surface_create_for_data ; + + +TUPLE: cairo-gadget image-array cairo-t ; + +M: cairo-gadget draw-gadget* ( gadget -- ) + 0 0 glRasterPos2i + 1.0 -1.0 glPixelZoom + >r 384 256 GL_RGBA GL_UNSIGNED_BYTE r> + cairo-gadget-image-array glDrawPixels ; + +: create-surface ( gadget -- cairo_surface_t ) + make-image-array dup >r swap set-cairo-gadget-image-array r> convert-array-to-surface ; + +: init-cairo ( gadget -- cairo_t ) + create-surface cairo_create ; + +M: cairo-gadget pref-dim* drop { 384 256 0 } ; + +: draw-hello-world ( gadget -- ) + cairo-gadget-cairo-t + dup "Sans" CAIRO_FONT_SLANT_NORMAL CAIRO_FONT_WEIGHT_BOLD cairo_select_font_face + dup 90.0 cairo_set_font_size + dup 10.0 135.0 cairo_move_to + dup "Hello" cairo_show_text + dup 70.0 165.0 cairo_move_to + dup "World" cairo_text_path + dup 0.5 0.5 1 cairo_set_source_rgb + dup cairo_fill_preserve + dup 0 0 0 cairo_set_source_rgb + dup 2.56 cairo_set_line_width + dup cairo_stroke + dup 1 0.2 0.2 0.6 cairo_set_source_rgba + dup 10.0 135.0 5.12 0 pi 2 * cairo_arc + dup cairo_close_path + dup 70.0 165.0 5.12 0 pi 2 * cairo_arc + cairo_fill ; + +M: cairo-gadget graft* ( gadget -- ) + dup dup init-cairo swap set-cairo-gadget-cairo-t draw-hello-world ; + +M: cairo-gadget ungraft* ( gadget -- ) + cairo-gadget-cairo-t cairo_destroy ; + +: ( -- gadget ) + cairo-gadget construct-gadget ; + +: run ( -- ) + [ + "Hello World from Factor!" open-window + ] with-ui ; + +MAIN: run diff --git a/extra/cairo/cairo.factor b/extra/cairo/cairo.factor index 8cf79da9b4..5c4907e5bb 100644 --- a/extra/cairo/cairo.factor +++ b/extra/cairo/cairo.factor @@ -1,6 +1,25 @@ -! Cairo binding +! Bindings for Cairo library +! Copyright (c) 2007 Sampo Vuori +! License: http://factorcode.org/license.txt + +! Unimplemented: +! - most of the font stuff +! - most of the matrix stuff +! - most of the query functions + + +USING: alien alien.syntax combinators system ; + IN: cairo -USING: alien alien.syntax ; + +: load-cairo-library ( -- ) + "cairo" { + { [ win32? ] [ "cairo.dll" ] } + { [ macosx? ] [ "libcairo.dylib" ] } + { [ unix? ] [ "libcairo.so.2" ] } + } cond "cdecl" add-library ; parsing + +load-cairo-library ! cairo_status_t C-ENUM: @@ -10,24 +29,43 @@ C-ENUM: CAIRO_STATUS_INVALID_POP_GROUP CAIRO_STATUS_NO_CURRENT_POINT CAIRO_STATUS_INVALID_MATRIX - CAIRO_STATUS_NO_TARGET_SURFACE + CAIRO_STATUS_INVALID_STATUS CAIRO_STATUS_NULL_POINTER CAIRO_STATUS_INVALID_STRING + CAIRO_STATUS_INVALID_PATH_DATA + CAIRO_STATUS_READ_ERROR + CAIRO_STATUS_WRITE_ERROR + CAIRO_STATUS_SURFACE_FINISHED + CAIRO_STATUS_SURFACE_TYPE_MISMATCH + CAIRO_STATUS_PATTERN_TYPE_MISMATCH + CAIRO_STATUS_INVALID_CONTENT + CAIRO_STATUS_INVALID_FORMAT + CAIRO_STATUS_INVALID_VISUAL + CAIRO_STATUS_FILE_NOT_FOUND + CAIRO_STATUS_INVALID_DASH + CAIRO_STATUS_INVALID_DSC_COMMENT + CAIRO_STATUS_INVALID_INDEX + CAIRO_STATUS_CLIP_NOT_REPRESENTABLE ; +! cairo_content_t +: CAIRO_CONTENT_COLOR HEX: 1000 ; +: CAIRO_CONTENT_ALPHA HEX: 2000 ; +: CAIRO_CONTENT_COLOR_ALPHA HEX: 3000 ; + ! cairo_operator_t C-ENUM: CAIRO_OPERATOR_CLEAR - CAIRO_OPERATOR_SRC - CAIRO_OPERATOR_DST + CAIRO_OPERATOR_SOURCE CAIRO_OPERATOR_OVER - CAIRO_OPERATOR_OVER_REVERSE CAIRO_OPERATOR_IN - CAIRO_OPERATOR_IN_REVERSE CAIRO_OPERATOR_OUT - CAIRO_OPERATOR_OUT_REVERSE CAIRO_OPERATOR_ATOP - CAIRO_OPERATOR_ATOP_REVERSE + CAIRO_OPERATOR_DEST + CAIRO_OPERATOR_DEST_OVER + CAIRO_OPERATOR_DEST_IN + CAIRO_OPERATOR_DEST_OUT + CAIRO_OPERATOR_DEST_ATOP CAIRO_OPERATOR_XOR CAIRO_OPERATOR_ADD CAIRO_OPERATOR_SATURATE @@ -116,6 +154,14 @@ C-STRUCT: cairo_t { "cairo_gstate_t*" "gstate" } { "uint" "status ! cairo_status_t" } ; +C-STRUCT: cairo_matrix_t + { "double" "xx" } + { "double" "yx" } + { "double" "xy" } + { "double" "yy" } + { "double" "x0" } + { "double" "y0" } ; + ! cairo_format_t C-ENUM: CAIRO_FORMAT_ARGB32 @@ -160,15 +206,24 @@ C-ENUM: : cairo_create ( cairo_surface_t -- cairo_t ) "cairo_t*" "cairo" "cairo_create" [ "void*" ] alien-invoke ; +: cairo_reference ( cairo_t -- cairo_t ) + "cairo_t*" "cairo" "cairo_reference" [ "cairo_t*" ] alien-invoke ; + : cairo_destroy ( cairo_t -- ) "void" "cairo" "cairo_destroy" [ "cairo_t*" ] alien-invoke ; +: cairo_save ( cairo_t -- ) + "void" "cairo" "cairo_save" [ "cairo_t*" ] alien-invoke ; + +: cairo_restore ( cairo_t -- ) + "void" "cairo" "cairo_restore" [ "cairo_t*" ] alien-invoke ; + : cairo_set_operator ( cairo_t cairo_operator_t -- ) "void" "cairo" "cairo_set_operator" [ "cairo_t*" "int" ] alien-invoke ; -: cairo_image_surface_create_for_data ( data format width height stride -- cairo_surface_t ) - "void*" "cairo" "cairo_image_surface_create_for_data" [ "void*" "uint" "int" "int" "int" ] alien-invoke ; - +: cairo_set_source ( cairo_t cairo_pattern_t -- ) + "void" "cairo" "cairo_set_source" [ "cairo_t*" "void*" ] alien-invoke ; + : cairo_set_source_rgb ( cairo_t red green blue -- ) "void" "cairo" "cairo_set_source_rgb" [ "cairo_t*" "double" "double" "double" ] alien-invoke ; @@ -181,6 +236,10 @@ C-ENUM: : cairo_set_tolerance ( cairo_t tolerance -- ) "void" "cairo" "cairo_set_tolerance" [ "cairo_t*" "double" ] alien-invoke ; +: cairo_image_surface_create_for_data ( data format width height stride -- cairo_surface_t ) + "void*" "cairo" "cairo_image_surface_create_for_data" [ "void*" "uint" "int" "int" "int" ] alien-invoke ; + + : cairo_set_antialias ( cairo_t cairo_antialias_t -- ) "void" "cairo" "cairo_set_antialias" [ "cairo_t*" "int" ] alien-invoke ; @@ -211,6 +270,14 @@ C-ENUM: : cairo_rotate ( cairo_t angle -- ) "void" "cairo" "cairo_rotate" [ "cairo_t*" "double" ] alien-invoke ; +: cairo_transform ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_transform" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + +: cairo_set_matrix ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_set_matrix" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + +: cairo_identity_matrix ( cairo_t -- ) + "void" "cairo" "cairo_identity_matrix" [ "cairo_t*" ] alien-invoke ; ! cairo path creating functions @@ -219,6 +286,9 @@ C-ENUM: : cairo_move_to ( cairo_t x y -- ) "void" "cairo" "cairo_move_to" [ "cairo_t*" "double" "double" ] alien-invoke ; + +: cairo_new_sub_path ( cairo_t -- ) + "void" "cairo" "cairo_new_sub_path" [ "cairo_t*" ] alien-invoke ; : cairo_line_to ( cairo_t x y -- ) "void" "cairo" "cairo_line_to" [ "cairo_t*" "double" "double" ] alien-invoke ; @@ -247,6 +317,29 @@ C-ENUM: : cairo_close_path ( cairo_t -- ) "void" "cairo" "cairo_close_path" [ "cairo_t*" ] alien-invoke ; +! Surface manipulation + +: cairo_surface_create_similar ( cairo_surface_t cairo_content_t width height -- cairo_surface_t ) + "cairo_surface_t*" "cairo" "cairo_surface_create_similar" [ "cairo_surface_t*" "uint" "int" "int" ] alien-invoke ; + +: cairo_surface_reference ( cairo_surface_t -- cairo_surface_t ) + "cairo_surface_t*" "cairo" "cairo_surface_reference" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_finish ( cairo_surface_t -- ) + "void" "cairo" "cairo_surface_finish" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_destroy ( cairo_surface_t -- ) + "void" "cairo" "cairo_surface_destroy" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_get_reference_count ( cairo_surface_t -- count ) + "uint" "cairo" "cairo_surface_get_reference_count" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_status ( cairo_surface_t -- cairo_status_t ) + "uint" "cairo" "cairo_surface_status" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_flush ( cairo_surface_t -- ) + "void" "cairo" "cairo_surface_flush" [ "cairo_surface_t*" ] alien-invoke ; + ! painting functions : cairo_paint ( cairo_t -- ) "void" "cairo" "cairo_paint" [ "cairo_t*" ] alien-invoke ; @@ -302,8 +395,6 @@ C-ENUM: : cairo_clip_preserve ( cairo_t -- ) "void" "cairo" "cairo_clip_preserve" [ "cairo_t*" ] alien-invoke ; -: cairo_set_source ( cairo_t cairo_pattern_t -- ) - "void" "cairo" "cairo_set_source" [ "cairo_t*" "void*" ] alien-invoke ; : cairo_pattern_create_linear ( x0 y0 x1 y1 -- cairo_pattern_t ) "void*" "cairo" "cairo_pattern_create_linear" [ "double" "double" "double" "double" ] alien-invoke ; @@ -326,5 +417,26 @@ C-ENUM: : cairo_set_font_size ( cairo_t scale -- ) "void" "cairo" "cairo_set_font_size" [ "cairo_t*" "double" ] alien-invoke ; -: cairo_identity_matrix ( cairo_t -- ) - "void" "cairo" "cairo_identity_matrix" [ "cairo_t*" ] alien-invoke ; +: cairo_set_font_matrix ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_set_font_matrix" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + +: cairo_get_font_matrix ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_get_font_matrix" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + + + +! Cairo pdf + +: cairo_pdf_surface_create ( filename width height -- surface ) + "void*" "cairo" "cairo_pdf_surface_create" [ "char*" "double" "double" ] alien-invoke ; + +! Missing: + +! cairo_public cairo_surface_t * +! cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, +! void *closure, +! double width_in_points, +! double height_in_points); + +: cairo_pdf_surface_set_size ( surface width height -- ) + "void" "cairo" "cairo_pdf_surface_set_size" [ "void*" "double" "double" ] alien-invoke ; diff --git a/extra/cfdg/hsv/hsv.factor b/extra/cfdg/hsv/hsv.factor index bd33eb3529..3714416d2e 100644 --- a/extra/cfdg/hsv/hsv.factor +++ b/extra/cfdg/hsv/hsv.factor @@ -1,5 +1,5 @@ -USING: kernel combinators arrays sequences math ; +USING: kernel combinators arrays sequences math combinators.lib ; IN: cfdg.hsv @@ -15,13 +15,13 @@ IN: cfdg.hsv : Hi ( hsv -- Hi ) H 60 / floor 6 mod ; -: f ( hsv -- f ) dup H 60 / swap Hi - ; +: f ( hsv -- f ) [ H 60 / ] [ Hi ] bi - ; -: p ( hsv -- p ) 1 over S - swap V * ; +: p ( hsv -- p ) [ S 1 swap - ] [ V ] bi * ; -: q ( hsv -- q ) dup f over S * 1 swap - swap V * ; +: q ( hsv -- q ) [ [ f ] [ S ] bi * 1 swap - ] [ V ] bi * ; -: t ( hsv -- t ) 1 over f - over S * 1 swap - swap V * ; +: t ( hsv -- t ) [ [ f 1 swap - ] [ S ] bi * 1 swap - ] [ V ] bi * ; PRIVATE> @@ -31,9 +31,9 @@ PRIVATE> : hsv>rgb ( hsv -- rgb ) dup Hi -{ { 0 [ dup V swap dup t swap p ] } - { 1 [ dup q over V rot p ] } - { 2 [ dup p over V rot t ] } - { 3 [ dup p over q rot V ] } - { 4 [ dup t over p rot V ] } - { 5 [ dup V over p rot q ] } } case 3array ; \ No newline at end of file +{ { 0 [ [ V ] [ t ] [ p ] tri ] } + { 1 [ [ q ] [ V ] [ p ] tri ] } + { 2 [ [ p ] [ V ] [ t ] tri ] } + { 3 [ [ p ] [ q ] [ V ] tri ] } + { 4 [ [ t ] [ p ] [ V ] tri ] } + { 5 [ [ V ] [ p ] [ q ] tri ] } } case 3array ; diff --git a/extra/cfdg/models/flower6/flower6.factor b/extra/cfdg/models/flower6/flower6.factor index cae8024b50..b77968c863 100644 --- a/extra/cfdg/models/flower6/flower6.factor +++ b/extra/cfdg/models/flower6/flower6.factor @@ -19,6 +19,7 @@ iterate? [ ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : run ( -- ) +[ ] >background { -1 2 -1 2 } viewport set 0.01 threshold set [ flower6 ] start-shape set diff --git a/extra/cfdg/models/lesson/lesson.factor b/extra/cfdg/models/lesson/lesson.factor index bd3f7914d8..26934aa182 100644 --- a/extra/cfdg/models/lesson/lesson.factor +++ b/extra/cfdg/models/lesson/lesson.factor @@ -97,6 +97,7 @@ iterate? [ ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : run ( -- ) +[ ] >background { -5 25 -15 25 } viewport set 0.03 threshold set [ toc ] start-shape set diff --git a/extra/cfdg/models/snowflake/snowflake.factor b/extra/cfdg/models/snowflake/snowflake.factor index 42e0b3e304..e42c297581 100644 --- a/extra/cfdg/models/snowflake/snowflake.factor +++ b/extra/cfdg/models/snowflake/snowflake.factor @@ -26,6 +26,7 @@ spike ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : run ( -- ) +[ ] >background { -40 80 -40 80 } viewport set 0.1 threshold set [ snowflake ] start-shape set diff --git a/extra/channels/sniffer/bsd/bsd.factor b/extra/channels/sniffer/bsd/bsd.factor index dd72279e4b..ba8e5ceeb9 100644 --- a/extra/channels/sniffer/bsd/bsd.factor +++ b/extra/channels/sniffer/bsd/bsd.factor @@ -3,7 +3,7 @@ ! ! Wrap a sniffer in a channel USING: kernel channels channels.sniffer concurrency io -io.sniffer io.sniffer.bsd ; +io.sniffer io.sniffer.bsd io.unix.backend ; M: unix-io sniff-channel ( -- channel ) "/dev/bpf0" "en1" [ diff --git a/extra/concurrency/concurrency.factor b/extra/concurrency/concurrency.factor index 391e6b4c4b..32ae3e5940 100644 --- a/extra/concurrency/concurrency.factor +++ b/extra/concurrency/concurrency.factor @@ -239,7 +239,7 @@ PRIVATE> "Exiting process: " write self process-pid print ] curry spawn-link ; -: server-cc ( -- cc | process ) +: server-cc ( -- cc|process ) #! Captures the current continuation and returns the value. #! If that CC is called with a process on the stack it will #! set 'self' for the current process to it. Otherwise it will diff --git a/extra/cpu/8080/8080.factor b/extra/cpu/8080/8080.factor index 34666b3288..87c3a235fd 100644 --- a/extra/cpu/8080/8080.factor +++ b/extra/cpu/8080/8080.factor @@ -3,7 +3,8 @@ ! USING: kernel math sequences words arrays io io.files namespaces math.parser kernel.private - assocs quotations parser parser-combinators tools.time ; + assocs quotations parser parser-combinators tools.time + combinators.private ; IN: cpu.8080 TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles ram ; diff --git a/extra/furnace/furnace.factor b/extra/furnace/furnace.factor index 8a475b98db..330c486817 100644 --- a/extra/furnace/furnace.factor +++ b/extra/furnace/furnace.factor @@ -118,18 +118,18 @@ SYMBOL: model : render-page* ( model body-template head-template -- ) [ - [ render-template ] [ f rot render-template ] html-document* + [ render-template ] [ f rot render-template ] html-document ] serve-html ; : render-titled-page* ( model body-template head-template title -- ) [ - [ render-template ] swap [ write f rot render-template ] curry html-document* + [ render-template ] swap [ write f rot render-template ] curry html-document ] serve-html ; : render-page ( model template title -- ) [ - [ render-template ] html-document + [ render-template ] simple-html-document ] serve-html ; : web-app ( name default path -- ) diff --git a/extra/html/elements/elements.factor b/extra/html/elements/elements.factor index 09ef3a4c03..0b70f5aa5c 100644 --- a/extra/html/elements/elements.factor +++ b/extra/html/elements/elements.factor @@ -152,5 +152,5 @@ SYMBOL: html "size" "href" "class" "border" "rows" "cols" "id" "onclick" "style" "valign" "accesskey" "src" "language" "colspan" "onchange" "rel" - "width" "selected" "onsubmit" + "width" "selected" "onsubmit" "xmlns" "lang" "xml:lang" ] [ define-attribute-word ] each diff --git a/extra/html/html-tests.factor b/extra/html/html-tests.factor index 5beb81b29a..798d5563fe 100644 --- a/extra/html/html-tests.factor +++ b/extra/html/html-tests.factor @@ -1,30 +1,39 @@ USING: html http io io.streams.string io.styles kernel -namespaces tools.test xml.writer ; +namespaces tools.test xml.writer sbufs sequences html.private ; IN: temporary -[ - "/responder/foo?z=%20" -] [ - "/responder/foo" H{ { "z" " " } } build-url +: make-html-string + [ with-html-stream ] string-out ; + +[ ] [ + 512 drop ] unit-test -[ - "<html>&'sgml'" -] [ "&'sgml'" chars>entities ] unit-test +[ "" ] [ + [ "" write ] make-html-string +] unit-test -[ "" ] -[ +[ "a" ] [ + [ CHAR: a write1 ] make-html-string +] unit-test + +[ "<" ] [ + [ "<" write ] make-html-string +] unit-test + +[ "<" ] [ + [ "<" H{ } stdio get format-html-span ] make-html-string +] unit-test + +TUPLE: funky town ; + +M: funky browser-link-href + "http://www.funky-town.com/" swap funky-town append ; + +[ "<" ] [ [ - H{ } [ drop ] span-tag - ] string-out -] unit-test - -: html-format ( string style -- string ) - [ format ] with-html-stream ; - -[ "hello world" ] -[ - [ "hello world" H{ } html-format ] string-out + "<" "austin" funky construct-boa write-object + ] make-html-string ] unit-test [ "car" ] @@ -32,8 +41,8 @@ IN: temporary [ "car" H{ { font "monospace" } } - html-format - ] string-out + format + ] make-html-string ] unit-test [ "car" ] @@ -41,6 +50,14 @@ IN: temporary [ "car" H{ { foreground { 1 0 1 1 } } } - html-format - ] string-out + format + ] make-html-string +] unit-test + +[ "
cdr
" ] +[ + [ + H{ { page-color { 1 0 1 1 } } } + [ "cdr" write ] with-nesting + ] make-html-string ] unit-test diff --git a/extra/html/html.factor b/extra/html/html.factor index 8d151906dc..9db97957a5 100644 --- a/extra/html/html.factor +++ b/extra/html/html.factor @@ -1,10 +1,43 @@ ! Copyright (C) 2004, 2006 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: generic assocs help http io io.styles io.files io.streams.string -kernel math math.parser namespaces xml.writer quotations -assocs sequences strings words html.elements ; +USING: generic assocs help http io io.styles io.files +io.streams.string kernel math math.parser namespaces +quotations assocs sequences strings words html.elements +xml.writer sbufs ; IN: html +GENERIC: browser-link-href ( presented -- href ) + +M: object browser-link-href drop f ; + +TUPLE: html-stream ; + +: ( stream -- stream ) + html-stream construct-delegate ; + + over set-delegate ; + +: ( style stream class -- stream ) + >r (html-sub-stream) r> construct-delegate ; inline + +: end-sub-stream ( substream -- string style stream ) + dup delegate >string + over html-sub-stream-style + rot html-sub-stream-stream ; + +: delegate-write ( string -- ) + stdio get delegate stream-write ; + +: object-link-tag ( style quot -- ) + presented pick at browser-link-href + [ call ] [ call ] if* ; inline + : hex-color, ( triplet -- ) 3 head-slice [ 255 * >fixnum >hex 2 CHAR: 0 pad-left % ] each ; @@ -28,166 +61,149 @@ IN: html : font-css, ( font -- ) "font-family: " % % "; " % ; -: hash-apply ( value-hash quot-hash -- ) - #! Looks up the key of each pair in the first list in the - #! second list to produce a quotation. The quotation is - #! applied to the value of the pair. If there is no - #! corresponding quotation, the value is popped off the - #! stack. - [ swapd at dup [ call ] [ 2drop ] if ] curry assoc-each ; +: apply-style ( style key quot -- style gadget ) + >r over at r> when* ; inline + +: make-css ( style quot -- str ) + "" make nip ; inline : span-css-style ( style -- str ) [ - H{ - { foreground [ fg-css, ] } - { background [ bg-css, ] } - { font [ font-css, ] } - { font-style [ style-css, ] } - { font-size [ size-css, ] } - } hash-apply - ] "" make ; + foreground [ fg-css, ] apply-style + background [ bg-css, ] apply-style + font [ font-css, ] apply-style + font-style [ style-css, ] apply-style + font-size [ size-css, ] apply-style + ] make-css ; : span-tag ( style quot -- ) over span-css-style dup empty? [ drop call ] [ call - ] if ; + ] if ; inline + +: format-html-span ( string style stream -- ) + [ + [ [ drop delegate-write ] span-tag ] object-link-tag + ] with-stream* ; + +TUPLE: html-span-stream ; + +M: html-span-stream stream-close + end-sub-stream format-html-span ; : border-css, ( border -- ) "border: 1px solid #" % hex-color, "; " % ; : padding-css, ( padding -- ) "padding: " % # "px; " % ; -: pre-css, ( -- ) - "white-space: pre; font-family: monospace; " % ; +: pre-css, ( margin -- ) + [ "white-space: pre; font-family: monospace; " % ] unless ; : div-css-style ( style -- str ) [ - H{ - { page-color [ bg-css, ] } - { border-color [ border-css, ] } - { border-width [ padding-css, ] } - { wrap-margin [ [ pre-css, ] unless ] } - } hash-apply - ] "" make ; + page-color [ bg-css, ] apply-style + border-color [ border-css, ] apply-style + border-width [ padding-css, ] apply-style + wrap-margin [ pre-css, ] apply-style + ] make-css ; : div-tag ( style quot -- ) swap div-css-style dup empty? [ drop call ] [
call
- ] if ; + ] if ; inline -: do-escaping ( string style -- string ) - html swap at [ chars>entities ] unless ; - -GENERIC: browser-link-href ( presented -- href ) - -M: object browser-link-href drop f ; - -: object-link-tag ( style quot -- ) - presented pick at browser-link-href - [ call ] [ call ] if* ; - -TUPLE: nested-stream ; - -: ( stream -- stream ) - nested-stream construct-delegate ; - -M: nested-stream stream-close drop ; - -TUPLE: html-stream ; - -: ( stream -- stream ) - html-stream construct-delegate ; - -M: html-stream stream-write1 ( char stream -- ) - >r 1string r> stream-write ; - -: delegate-write delegate stream-write ; - -M: html-stream stream-write ( str stream -- ) - >r chars>entities r> delegate-write ; - -: with-html-style ( quot style stream -- ) - [ [ swap span-tag ] object-link-tag ] with-stream* ; inline - -M: html-stream with-stream-style ( quot style stream -- ) - [ drop call ] -rot with-html-style ; - -M: html-stream stream-format ( str style stream -- ) - [ do-escaping stdio get delegate-write ] -rot - with-html-style ; - -: with-html-stream ( quot -- ) - stdio get swap with-stream* ; - -M: html-stream with-nested-stream ( quot style stream -- ) +: format-html-div ( string style stream -- ) [ - [ - [ - stdio get swap with-stream* - ] div-tag - ] object-link-tag + [ [ delegate-write ] div-tag ] object-link-tag ] with-stream* ; +TUPLE: html-block-stream ; + +M: html-block-stream stream-close ( quot style stream -- ) + end-sub-stream format-html-div ; + : border-spacing-css, "padding: " % first2 max 2 /i # "px; " % ; : table-style ( style -- str ) [ - H{ - { table-border [ border-css, ] } - { table-gap [ border-spacing-css, ] } - } hash-apply - ] "" make ; + table-border [ border-css, ] apply-style + table-gap [ border-spacing-css, ] apply-style + ] make-css ; : table-attrs ( style -- ) table-style " border-collapse: collapse;" append =style ; +: do-escaping ( string style -- string ) + html swap at [ chars>entities ] unless ; + +PRIVATE> + +! Stream protocol +M: html-stream stream-write1 ( char stream -- ) + >r 1string r> stream-write ; + +M: html-stream stream-write ( str stream -- ) + >r chars>entities r> delegate stream-write ; + +M: html-stream make-span-stream ( style stream -- stream' ) + html-span-stream ; + +M: html-stream stream-format ( str style stream -- ) + >r html over at [ >r chars>entities r> ] unless r> + format-html-span ; + +M: html-stream make-block-stream ( style stream -- stream' ) + html-block-stream ; + M: html-stream stream-write-table ( grid style stream -- ) [ swap [ [ ] curry* each ] curry* each
- write-html + >string write-html
] with-stream* ; -M: html-stream make-table-cell ( quot style stream -- table-cell ) - 2drop [ with-html-stream ] string-out ; +M: html-stream make-cell-stream ( style stream -- stream' ) + (html-sub-stream) ; -M: html-stream stream-nl [
] with-stream* ; +M: html-stream stream-nl ( stream -- ) + [
] with-stream* ; -: default-css ( -- ) - ; +! Utilities +: with-html-stream ( quot -- ) + stdio get swap with-stream* ; : xhtml-preamble "" write-html "" write-html ; -: html-document* ( body-quot head-quot -- ) +: html-document ( body-quot head-quot -- ) #! head-quot is called to produce output to go #! in the html head portion of the document. #! body-quot is called to produce output to go #! in the html body portion of the document. xhtml-preamble - + call call ; - -: html-document ( title quot -- ) + +: default-css ( -- ) + ; + +: simple-html-document ( title quot -- ) swap [ write default-css - ] html-document* ; - -: simple-html-document ( title quot -- ) - swap [
 with-html-stream 
] html-document ; + ] html-document ; diff --git a/extra/http/server/resources/stylesheet.css b/extra/html/stylesheet.css similarity index 100% rename from extra/http/server/resources/stylesheet.css rename to extra/html/stylesheet.css diff --git a/extra/http/http.factor b/extra/http/http.factor index 687fa807f5..a358c449af 100644 --- a/extra/http/http.factor +++ b/extra/http/http.factor @@ -7,7 +7,7 @@ IN: http : header-line ( line -- ) ": " split1 dup [ swap set ] [ 2drop ] if ; -: (read-header) ( hash -- hash ) +: (read-header) ( -- ) readln dup empty? [ drop ] [ header-line (read-header) ] if ; diff --git a/extra/http/server/resources/prototype.js b/extra/http/server/resources/prototype.js deleted file mode 100644 index 0e85338bab..0000000000 --- a/extra/http/server/resources/prototype.js +++ /dev/null @@ -1,1781 +0,0 @@ -/* Prototype JavaScript framework, version 1.4.0 - * (c) 2005 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.4.0', - ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', - - emptyFunction: function() {}, - K: function(x) {return x} -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.extend = function(destination, source) { - for (property in source) { - destination[property] = source[property]; - } - return destination; -} - -Object.inspect = function(object) { - try { - if (object == undefined) return 'undefined'; - if (object == null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } -} - -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var __method = this; - return function(event) { - return __method.call(object, event || window.event); - } -} - -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - } -}); - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - } -} - -/*--------------------------------------------------------------------------*/ - -function $() { - var elements = new Array(); - - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - - if (arguments.length == 1) - return element; - - elements.push(element); - } - - return elements; -} -Object.extend(String.prototype, { - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(eval); - }, - - escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; - }, - - unescapeHTML: function() { - var div = document.createElement('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; - }, - - toQueryParams: function() { - var pairs = this.match(/^\??(.*)$/)[1].split('&'); - return pairs.inject({}, function(params, pairString) { - var pair = pairString.split('='); - params[pair[0]] = pair[1]; - return params; - }); - }, - - toArray: function() { - return this.split(''); - }, - - camelize: function() { - var oStringList = this.split('-'); - if (oStringList.length == 1) return oStringList[0]; - - var camelizedString = this.indexOf('-') == 0 - ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) - : oStringList[0]; - - for (var i = 1, len = oStringList.length; i < len; i++) { - var s = oStringList[i]; - camelizedString += s.charAt(0).toUpperCase() + s.substring(1); - } - - return camelizedString; - }, - - inspect: function() { - return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; - } -}); - -String.prototype.parseQuery = String.prototype.toQueryParams; - -var $break = new Object(); -var $continue = new Object(); - -var Enumerable = { - each: function(iterator) { - var index = 0; - try { - this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } - }); - } catch (e) { - if (e != $break) throw e; - } - }, - - all: function(iterator) { - var result = true; - this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator) { - var result = true; - this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator) { - var results = []; - this.each(function(value, index) { - results.push(iterator(value, index)); - }); - return results; - }, - - detect: function (iterator) { - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator) { - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(pattern, iterator) { - var results = []; - this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) - return results; - }, - - include: function(object) { - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inject: function(memo, iterator) { - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.collect(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value >= (result || value)) - result = value; - }); - return result; - }, - - min: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value <= (result || value)) - result = value; - }); - return result; - }, - - partition: function(iterator) { - var trues = [], falses = []; - this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value, index) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator) { - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator) { - return this.collect(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.collect(Prototype.K); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - iterator(value = collections.pluck(index)); - return value; - }); - }, - - inspect: function() { - return '#'; - } -} - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0; i < iterable.length; i++) - results.push(iterable[i]); - return results; - } -} - -Object.extend(Array.prototype, Enumerable); - -Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0; i < this.length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != undefined || value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(value.constructor == Array ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - indexOf: function(object) { - for (var i = 0; i < this.length; i++) - if (this[i] == object) return i; - return -1; - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - shift: function() { - var result = this[0]; - for (var i = 0; i < this.length - 1; i++) - this[i] = this[i + 1]; - this.length--; - return result; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } -}); -var Hash = { - _each: function(iterator) { - for (key in this) { - var value = this[key]; - if (typeof value == 'function') continue; - - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - merge: function(hash) { - return $H(hash).inject($H(this), function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, - - toQueryString: function() { - return this.map(function(pair) { - return pair.map(encodeURIComponent).join('='); - }).join('&'); - }, - - inspect: function() { - return '#'; - } -} - -function $H(object) { - var hash = Object.extend({}, object || {}); - Object.extend(hash, Enumerable); - Object.extend(hash, Hash); - return hash; -} -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - do { - iterator(value); - value = value.succ(); - } while (this.include(value)); - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')}, - function() {return new XMLHttpRequest()} - ) || false; - }, - - activeRequestCount: 0 -} - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responderToAdd) { - if (!this.include(responderToAdd)) - this.responders.push(responderToAdd); - }, - - unregister: function(responderToRemove) { - this.responders = this.responders.without(responderToRemove); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (responder[callback] && typeof responder[callback] == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - - onComplete: function() { - Ajax.activeRequestCount--; - } -}); - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - parameters: '' - } - Object.extend(this.options, options || {}); - }, - - responseIsSuccess: function() { - return this.transport.status == undefined - || this.transport.status == 0 - || (this.transport.status >= 200 && this.transport.status < 300); - }, - - responseIsFailure: function() { - return !this.responseIsSuccess(); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.request(url); - }, - - request: function(url) { - var parameters = this.options.parameters || ''; - if (parameters.length > 0) parameters += '&_='; - - try { - this.url = url; - if (this.options.method == 'get' && parameters.length > 0) - this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.options.method, this.url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.setRequestHeaders(); - - var body = this.options.postBody ? this.options.postBody : parameters; - this.transport.send(this.options.method == 'post' ? body : null); - - } catch (e) { - this.dispatchException(e); - } - }, - - setRequestHeaders: function() { - var requestHeaders = - ['X-Requested-With', 'XMLHttpRequest', - 'X-Prototype-Version', Prototype.Version]; - - if (this.options.method == 'post') { - requestHeaders.push('Content-type', - 'application/x-www-form-urlencoded'); - - /* Force "Connection: close" for Mozilla browsers to work around - * a bug where XMLHttpReqeuest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType) - requestHeaders.push('Connection', 'close'); - } - - if (this.options.requestHeaders) - requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); - - for (var i = 0; i < requestHeaders.length; i += 2) - this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - header: function(name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) {} - }, - - evalJSON: function() { - try { - return eval(this.header('X-JSON')); - } catch (e) {} - }, - - evalResponse: function() { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (event == 'Complete') { - try { - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.header('Content-type') || '').match(/^text\/javascript/i)) - this.evalResponse(); - } - - try { - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Updater = Class.create(); - -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { - this.containers = { - success: container.success ? $(container.success) : $(container), - failure: container.failure ? $(container.failure) : - (container.success ? null : $(container)) - } - - this.transport = Ajax.getTransport(); - this.setOptions(options); - - var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function(transport, object) { - this.updateContent(); - onComplete(transport, object); - }).bind(this); - - this.request(url); - }, - - updateContent: function() { - var receiver = this.responseIsSuccess() ? - this.containers.success : this.containers.failure; - var response = this.transport.responseText; - - if (!this.options.evalScripts) - response = response.stripScripts(); - - if (receiver) { - if (this.options.insertion) { - new this.options.insertion(receiver, response); - } else { - Element.update(receiver, response); - } - } - - if (this.responseIsSuccess()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.setOptions(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = {}; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(request) { - if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = request.responseText; - } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - return $A(children).inject([], function(elements, child) { - if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - elements.push(child); - return elements; - }); -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Element) { - var Element = new Object(); -} - -Object.extend(Element, { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - Element[Element.visible(element) ? 'hide' : 'show'](element); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - update: function(element, html) { - $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).include(className); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).add(className); - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).remove(className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - for (var i = 0; i < element.childNodes.length; i++) { - var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - Element.remove(node); - } - }, - - empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); - }, - - scrollTo: function(element) { - element = $(element); - var x = element.x ? element.x : element.offsetLeft, - y = element.y ? element.y : element.offsetTop; - window.scrollTo(x, y); - }, - - getStyle: function(element, style) { - element = $(element); - var value = element.style[style.camelize()]; - if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css.getPropertyValue(style) : null; - } else if (element.currentStyle) { - value = element.currentStyle[style.camelize()]; - } - } - - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; - - return value == 'auto' ? null : value; - }, - - setStyle: function(element, style) { - element = $(element); - for (name in style) - element.style[name.camelize()] = style[name]; - }, - - getDimensions: function(element) { - element = $(element); - if (Element.getStyle(element, 'display') != 'none') - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = ''; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = 'none'; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return; - element._overflow = element.style.overflow; - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') - element.style.overflow = 'hidden'; - }, - - undoClipping: function(element) { - element = $(element); - if (element._overflow) return; - element.style.overflow = element._overflow; - element._overflow = undefined; - } -}); - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content.stripScripts(); - - if (this.adjacency && this.element.insertAdjacentHTML) { - try { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } catch (e) { - if (this.element.tagName.toLowerCase() == 'tbody') { - this.insertContent(this.contentFromAnonymousTable()); - } else { - throw e; - } - } - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.insertContent([this.range.createContextualFragment(this.content)]); - } - - setTimeout(function() {content.evalScripts()}, 10); - }, - - contentFromAnonymousTable: function() { - var div = document.createElement('div'); - div.innerHTML = '' + this.content + '
'; - return $A(div.childNodes[0].childNodes[0].childNodes); - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, this.element); - }).bind(this)); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function(fragments) { - fragments.reverse(false).each((function(fragment) { - this.element.insertBefore(fragment, this.element.firstChild); - }).bind(this)); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.appendChild(fragment); - }).bind(this)); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, - this.element.nextSibling); - }).bind(this)); - } -}); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set(this.toArray().concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set(this.select(function(className) { - return className != classNameToRemove; - }).join(' ')); - }, - - toString: function() { - return this.toArray().join(' '); - } -} - -Object.extend(Element.ClassNames.prototype, Enumerable); -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select) - element.select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) - return inputs; - - var matchingInputs = new Array(); - for (var i = 0; i < inputs.length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || - (name && input.name != name)) - continue; - matchingInputs.push(input); - } - - return matchingInputs; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disabled = 'true'; - } - }, - - enable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.disabled = ''; - } - }, - - findFirstElement: function(form) { - return Form.getElements(form).find(function(element) { - return element.type != 'hidden' && !element.disabled && - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - Field.activate(Form.findFirstElement(form)); - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length == 0) return; - - if (parameter[1].constructor != Array) - parameter[1] = [parameter[1]]; - - return parameter[1].map(function(value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); - } - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - return Form.Element.Serializers[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - - selectOne: function(element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value; - if (!value && !('value' in opt)) - value = opt.text; - } - return [element.name, value]; - }, - - selectMany: function(element) { - var value = new Array(); - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) { - var optValue = opt.value; - if (!optValue && !('value' in opt)) - optValue = opt.text; - value.push(optValue); - } - } - return [element.name, value]; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - var elements = Form.getElements(this.element); - for (var i = 0; i < elements.length; i++) - this.registerCallback(elements[i]); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - case 'password': - case 'text': - case 'textarea': - case 'select-one': - case 'select-multiple': - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -} - -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) { - var Event = new Object(); -} - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - - element: function(event) { - return event.target || event.srcElement; - }, - - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - pointerX: function(event) { - return event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)); - }, - - pointerY: function(event) { - return event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)); - }, - - stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } else { - event.returnValue = false; - event.cancelBubble = true; - } - }, - - // find the first node with the given tagName, starting from the - // node the event was triggered on; traverses the DOM upwards - findElement: function(event, tagName) { - var element = Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) - element = element.parentNode; - return element; - }, - - observers: false, - - _observeAndCache: function(element, name, observer, useCapture) { - if (!this.observers) this.observers = []; - if (element.addEventListener) { - this.observers.push([element, name, observer, useCapture]); - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - this.observers.push([element, name, observer, useCapture]); - element.attachEvent('on' + name, observer); - } - }, - - unloadCache: function() { - if (!Event.observers) return; - for (var i = 0; i < Event.observers.length; i++) { - Event.stopObserving.apply(this, Event.observers[i]); - Event.observers[i][0] = null; - } - Event.observers = false; - }, - - observe: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) - name = 'keydown'; - - this._observeAndCache(element, name, observer, useCapture); - }, - - stopObserving: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) - name = 'keydown'; - - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element.detachEvent) { - element.detachEvent('on' + name, observer); - } - } -}); - -/* prevent memory leaks in IE */ -Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { - // set to true if needed, warning: firefox performance problems - // NOT neeeded for page scrolling, only if draggable contained in - // scrollable elements - includeScrollOffsets: false, - - // must be called before calling withinIncludingScrolloffset, every time the - // page is scrolled - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - realOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return [valueL, valueT]; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return [valueL, valueT]; - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - p = Element.getStyle(element, 'position'); - if (p == 'relative' || p == 'absolute') break; - } - } while (element); - return [valueL, valueT]; - }, - - offsetParent: function(element) { - if (element.offsetParent) return element.offsetParent; - if (element == document.body) return element; - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return element; - - return document.body; - }, - - // caches x/y coordinate pair to use with overlap - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = this.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = this.realOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = this.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - clone: function(source, target) { - source = $(source); - target = $(target); - target.style.position = 'absolute'; - var offsets = this.cumulativeOffset(source); - target.style.top = offsets[1] + 'px'; - target.style.left = offsets[0] + 'px'; - target.style.width = source.offsetWidth + 'px'; - target.style.height = source.offsetHeight + 'px'; - }, - - page: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent==document.body) - if (Element.getStyle(element,'position')=='absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } while (element = element.parentNode); - - return [valueL, valueT]; - }, - - clone: function(source, target) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || {}) - - // find page position of source - source = $(source); - var p = Position.page(source); - - // find coordinate system to use - target = $(target); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(target,'position') == 'absolute') { - parent = Position.offsetParent(target); - delta = Position.page(parent); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if(options.setWidth) target.style.width = source.offsetWidth + 'px'; - if(options.setHeight) target.style.height = source.offsetHeight + 'px'; - }, - - absolutize: function(element) { - element = $(element); - if (element.style.position == 'absolute') return; - Position.prepare(); - - var offsets = Position.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px';; - element.style.left = left + 'px';; - element.style.width = width + 'px';; - element.style.height = height + 'px';; - }, - - relativize: function(element) { - element = $(element); - if (element.style.position == 'relative') return; - Position.prepare(); - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - } -} - -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - Position.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return [valueL, valueT]; - } -} \ No newline at end of file diff --git a/extra/http/server/responders/continuation/examples/examples.factor b/extra/http/server/responders/continuation/examples/examples.factor index 2a2eae72d7..e6abcc7a72 100644 --- a/extra/http/server/responders/continuation/examples/examples.factor +++ b/extra/http/server/responders/continuation/examples/examples.factor @@ -34,7 +34,7 @@ IN: http.server.responders.continuation.examples

over write

swap [ "Next" write - ] html-document + ] simple-html-document ] show 2drop ; : display-get-name-page ( -- name ) @@ -47,7 +47,7 @@ IN: http.server.responders.continuation.examples - ] html-document + ] simple-html-document ] show "name" swap at ; : test-cont-responder ( -- ) @@ -71,7 +71,7 @@ IN: http.server.responders.continuation.examples
  • "Test responder1" [ test-cont-responder ] quot-href
  • "Test responder2" [ test-cont-responder2 ] quot-href
  • - ] html-document + ] simple-html-document ] show-final ; : counter-example ( count -- ) @@ -87,7 +87,7 @@ IN: http.server.responders.continuation.examples "++" over 1quotation [ f ] swap append [ 1 + counter-example ] append quot-href "--" over 1quotation [ f ] swap append [ 1 - counter-example ] append quot-href drop - ] html-document + ] simple-html-document ] show drop ; : counter-example2 ( -- ) @@ -102,7 +102,7 @@ IN: http.server.responders.continuation.examples

    "counter" get unparse write

    "++" [ "counter" get 1 + "counter" set ] quot-href "--" [ "counter" get 1 - "counter" set ] quot-href - ] html-document + ] simple-html-document ] show drop ; diff --git a/extra/http/server/responders/file/file.factor b/extra/http/server/responders/file/file.factor index e6af805462..4f83e8fa98 100644 --- a/extra/http/server/responders/file/file.factor +++ b/extra/http/server/responders/file/file.factor @@ -1,8 +1,9 @@ ! Copyright (C) 2004, 2006 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: calendar html io io.files kernel math math.parser http.server.responders -http.server.templating namespaces parser sequences strings assocs hashtables -debugger http.mime sorting ; +USING: calendar html io io.files kernel math math.parser +http.server.responders http.server.templating namespaces parser +sequences strings assocs hashtables debugger http.mime sorting +html.elements ; IN: http.server.responders.file @@ -55,19 +56,25 @@ SYMBOL: page dup mime-type dup "application/x-factor-server-page" = [ drop serving-html run-page ] [ serve-static ] if ; -: file. ( path name dirp -- ) - "[DIR] " " " ? write - dup write-object nl ; +: file. ( name dirp -- ) + [ "/" append ] when + dup write ; -: directory. ( path -- ) - directory sort-keys [ first2 file. ] each ; +: directory. ( path request -- ) + dup [ +

    write

    +
      + directory sort-keys + [
    • file.
    • ] assoc-each +
    + ] simple-html-document ; : list-directory ( directory -- ) serving-html "method" get "head" = [ drop ] [ - "request" get [ directory. ] simple-html-document + "request" get directory. ] if ; : find-index ( filename -- path ) @@ -98,17 +105,17 @@ SYMBOL: page ] if ; global [ - ! Javascript source used by ajax libraries + ! Serve up our own source code "resources" [ [ - "extra/http/server/resources/" resource-path "doc-root" set + "" resource-path "doc-root" set file-responder ] with-scope ] add-simple-responder ! Serves files from a directory stored in the "doc-root" - ! variable. You can set the variable in the global namespace, - ! or inside the responder. + ! variable. You can set the variable in the global + ! namespace, or inside the responder. "file" [ file-responder ] add-simple-responder ! The root directory is served by... diff --git a/extra/http/server/responders/responders.factor b/extra/http/server/responders/responders.factor index 725cb515b0..aadf513aea 100644 --- a/extra/http/server/responders/responders.factor +++ b/extra/http/server/responders/responders.factor @@ -16,16 +16,16 @@ SYMBOL: responders : response ( header msg -- ) "HTTP/1.0 " write print print-header ; -: error-body ( error -- body ) +: error-body ( error -- )

    write

    ; : error-head ( error -- ) dup log-error - H{ { "Content-Type" "text/html" } } over response ; + H{ { "Content-Type" "text/html" } } swap response ; : httpd-error ( error -- ) #! This must be run from handle-request - error-head + dup error-head "head" "method" get = [ drop ] [ nl error-body ] if ; : bad-request ( -- ) @@ -101,7 +101,8 @@ SYMBOL: max-post-request dup "request" set ; : prepare-header ( -- ) - read-header dup "header" set + read-header + dup "header" set dup log-headers read-post-request "response" set "raw-response" set ; diff --git a/extra/icfp/2006/2006.factor b/extra/icfp/2006/2006.factor index 317a5ae83b..2b42cddc6a 100644 --- a/extra/icfp/2006/2006.factor +++ b/extra/icfp/2006/2006.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: kernel math sequences kernel.private namespaces arrays -io io.files splitting io.binary math.functions vectors ; +io io.files splitting io.binary math.functions vectors +quotations combinators.private ; IN: universal-machine SYMBOL: regs diff --git a/extra/io/sniffer/filter/bsd/bsd.factor b/extra/io/sniffer/filter/bsd/bsd.factor index c986a09664..fc34b3448b 100644 --- a/extra/io/sniffer/filter/bsd/bsd.factor +++ b/extra/io/sniffer/filter/bsd/bsd.factor @@ -1,7 +1,7 @@ USING: alien.c-types hexdump io io.backend io.sockets.headers io.sockets.headers.bsd kernel io.sniffer io.sniffer.bsd io.sniffer.filter io.streams.string io.unix.backend math -sequences system ; +sequences system byte-arrays ; IN: io.sniffer.filter.bsd ! http://www.iana.org/assignments/ethernet-numbers diff --git a/extra/io/streams/null/null.factor b/extra/io/streams/null/null.factor index 7c11130397..12a36091ce 100644 --- a/extra/io/streams/null/null.factor +++ b/extra/io/streams/null/null.factor @@ -16,7 +16,10 @@ M: null-stream stream-write 2drop ; M: null-stream stream-nl drop ; M: null-stream stream-flush drop ; M: null-stream stream-format 3drop ; -M: null-stream with-nested-stream rot drop with-stream* ; +M: null-stream make-span-stream nip ; +M: null-stream make-block-stream nip ; +M: null-stream make-cell-stream nip ; +M: null-stream stream-write-table 3drop ; : with-null-stream ( quot -- ) T{ null-stream } swap with-stream* ; inline diff --git a/extra/locals/locals.factor b/extra/locals/locals.factor index ca157fa2a7..688507be78 100644 --- a/extra/locals/locals.factor +++ b/extra/locals/locals.factor @@ -4,7 +4,8 @@ USING: kernel namespaces sequences sequences.private assocs math inference.transforms parser words quotations debugger macros arrays macros splitting combinators prettyprint.backend - definitions prettyprint hashtables combinators.lib ; + definitions prettyprint hashtables combinators.lib + prettyprint.sections ; IN: locals diff --git a/extra/openal/macosx/macosx.factor b/extra/openal/macosx/macosx.factor index 21c918e33e..77484aca74 100644 --- a/extra/openal/macosx/macosx.factor +++ b/extra/openal/macosx/macosx.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. ! IN: openal.macosx -USING: openal alien.c-types kernel alien alien.syntax shuffle ; +USING: openal alien.c-types kernel alien alien.syntax shuffle +combinators.lib ; LIBRARY: alut diff --git a/extra/space-invaders/space-invaders.factor b/extra/space-invaders/space-invaders.factor index 287e6eebb8..3f695a4f60 100644 --- a/extra/space-invaders/space-invaders.factor +++ b/extra/space-invaders/space-invaders.factor @@ -4,7 +4,8 @@ USING: cpu.8080 openal math alien.c-types sequences kernel shuffle arrays io.files combinators kernel.private ui.gestures ui.gadgets ui.render opengl.gl system - threads concurrency match ui byte-arrays combinators.lib ; + threads concurrency match ui byte-arrays combinators.lib + combinators.private ; IN: space-invaders TUPLE: space-invaders port1 port2i port2o port3o port4lo port4hi port5o bitmap sounds looping? ; diff --git a/extra/state-machine/state-machine.factor b/extra/state-machine/state-machine.factor index 671150b10a..85f4812d9a 100644 --- a/extra/state-machine/state-machine.factor +++ b/extra/state-machine/state-machine.factor @@ -1,5 +1,5 @@ -USING: kernel parser strings math namespaces sequences words io arrays -quotations debugger kernel.private ; +USING: kernel parser strings math namespaces sequences words io +arrays quotations debugger kernel.private combinators.private ; IN: state-machine : STATES: diff --git a/extra/ui/gadgets/slate/slate.factor b/extra/ui/gadgets/slate/slate.factor index 05e36c48b0..5ea1ec20fa 100644 --- a/extra/ui/gadgets/slate/slate.factor +++ b/extra/ui/gadgets/slate/slate.factor @@ -8,7 +8,9 @@ TUPLE: slate action dim graft ungraft ; : ( action -- slate ) slate construct-gadget tuck set-slate-action - { 100 100 } over set-slate-dim ; + { 100 100 } over set-slate-dim + [ ] over set-slate-graft + [ ] over set-slate-ungraft ; M: slate pref-dim* ( slate -- dim ) slate-dim ; diff --git a/extra/webapps/help/help.factor b/extra/webapps/help/help.factor index ec0590df34..366baffcb9 100644 --- a/extra/webapps/help/help.factor +++ b/extra/webapps/help/help.factor @@ -10,7 +10,7 @@ IN: webapps.help serving-html dup article-title [ [ help ] with-html-stream - ] html-document ; + ] simple-html-document ; : string>topic ( string -- topic ) " " split dup length 1 = [ first ] when ; @@ -73,9 +73,10 @@ M: vocab-author browser-link-href "help" "show-help" "extra/webapps/help" web-app ! Hard-coding for factorcode.org -M: pathname browser-link-href - pathname-string "resource:" ?head [ - "http://factorcode.org/repos/Factor/" swap append - ] [ - drop f - ] if ; +PREDICATE: pathname resource-pathname + pathname-string "resource:" head? ; + +M: resource-pathname browser-link-href + pathname-string + "resource:" ?head drop + "/responder/resources/" swap append ; diff --git a/extra/xml/utilities/utilities.factor b/extra/xml/utilities/utilities.factor index f88d4c5863..303de4295e 100644 --- a/extra/xml/utilities/utilities.factor +++ b/extra/xml/utilities/utilities.factor @@ -10,9 +10,9 @@ IN: xml.utilities TUPLE: process-missing process tag ; M: process-missing error. "Tag <" write - process-missing-tag print-name + dup process-missing-tag print-name "> not implemented on process process " write - dup process-missing-process word-name print ; + process-missing-process word-name print ; : run-process ( tag word -- ) 2dup "xtable" word-prop diff --git a/misc/icons/FRaptorMix.ico b/misc/icons/FRaptorMix.ico deleted file mode 100644 index 6d199e7182..0000000000 Binary files a/misc/icons/FRaptorMix.ico and /dev/null differ diff --git a/misc/icons/FRaptorMix_128x128.png b/misc/icons/FRaptorMix_128x128.png deleted file mode 100644 index bc08801196..0000000000 Binary files a/misc/icons/FRaptorMix_128x128.png and /dev/null differ diff --git a/misc/icons/FRaptorMix_16x16.png b/misc/icons/FRaptorMix_16x16.png deleted file mode 100644 index 1613566968..0000000000 Binary files a/misc/icons/FRaptorMix_16x16.png and /dev/null differ diff --git a/misc/icons/FRaptorMix_32x32.png b/misc/icons/FRaptorMix_32x32.png deleted file mode 100644 index d93a4a6e3f..0000000000 Binary files a/misc/icons/FRaptorMix_32x32.png and /dev/null differ diff --git a/misc/icons/FRaptorMix_48x48.png b/misc/icons/FRaptorMix_48x48.png deleted file mode 100644 index 1200571100..0000000000 Binary files a/misc/icons/FRaptorMix_48x48.png and /dev/null differ diff --git a/misc/icons/Factor.ico b/misc/icons/Factor.ico new file mode 100644 index 0000000000..fa4baa8cbd Binary files /dev/null and b/misc/icons/Factor.ico differ diff --git a/misc/icons/Factor_128x128.png b/misc/icons/Factor_128x128.png new file mode 100644 index 0000000000..1854aa6f72 Binary files /dev/null and b/misc/icons/Factor_128x128.png differ diff --git a/misc/icons/Factor_16x16.png b/misc/icons/Factor_16x16.png new file mode 100644 index 0000000000..2361ef4b4a Binary files /dev/null and b/misc/icons/Factor_16x16.png differ diff --git a/misc/icons/Factor_32x32.png b/misc/icons/Factor_32x32.png new file mode 100644 index 0000000000..9d6368e79f Binary files /dev/null and b/misc/icons/Factor_32x32.png differ diff --git a/misc/icons/Factor_48x48.png b/misc/icons/Factor_48x48.png new file mode 100644 index 0000000000..364bb44d05 Binary files /dev/null and b/misc/icons/Factor_48x48.png differ diff --git a/misc/icons/license.txt b/misc/icons/license.txt index 3a886d770c..7979a793a9 100644 --- a/misc/icons/license.txt +++ b/misc/icons/license.txt @@ -1,4 +1,4 @@ The icons/images/jackets contained in this archive are -Copyright (C) 2007 Elie CHAFTARI. All Rights Reserved. +Copyright (C) 2007 Elie Chaftari. All Rights Reserved. See http://factorcode.org/license.txt for BSD license. \ No newline at end of file diff --git a/vm/cpu-ppc.S b/vm/cpu-ppc.S index 295e16f04c..295fffa1a5 100644 --- a/vm/cpu-ppc.S +++ b/vm/cpu-ppc.S @@ -4,7 +4,7 @@ in the public domain. */ /* Note that the XT is passed to the quotation in r11 */ #define CALL_OR_JUMP_QUOT \ - lwz r11,5(r3) /* load quotation-xt slot */ XX \ + lwz r11,9(r3) /* load quotation-xt slot */ XX \ #define CALL_QUOT \ CALL_OR_JUMP_QUOT XX \ @@ -40,11 +40,19 @@ in the public domain. */ #define RESTORE(register,offset) lwz register,SAVE_AT(offset)(r1) -DEF(void,c_to_factor,(CELL quot)): - mflr r0 /* get caller's return address */ - stwu r1,-FRAME(r1) /* create a stack frame to hold non-volatile registers */ +#define PROLOGUE \ + mflr r0 XX /* get caller's return address */ \ + stwu r1,-FRAME(r1) XX /* create a stack frame to hold non-volatile registers */ \ SAVE_LR(r0) +#define EPILOGUE \ + LOAD_LR(r0) XX \ + lwz r1,0(r1) XX /* destroy the stack frame */ \ + mtlr r0 /* get ready to return */ + +DEF(void,c_to_factor,(CELL quot)): + PROLOGUE + SAVE(r13,0) /* save GPRs */ /* don't save ds pointer */ /* don't save rs pointer */ @@ -92,9 +100,7 @@ DEF(void,c_to_factor,(CELL quot)): /* don't restore ds pointer */ RESTORE(r13,0) - LOAD_LR(r0) - lwz r1,0(r1) /* destroy the stack frame */ - mtlr r0 /* get ready to return */ + EPILOGUE blr /* The JIT compiles an 'mr r4,r1' in front of every primitive call, since a @@ -164,6 +170,13 @@ DEF(void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): mtlr r0 JUMP_QUOT /* call the quotation */ +DEF(void,lazy_jit_compile,(CELL quot)): + mr r4,r1 /* save stack pointer */ + PROLOGUE + bl MANGLE(jit_compile) + EPILOGUE + JUMP_QUOT /* call the quotation */ + /* Thanks to Joshua Grams for this code. On PowerPC processors, we must flush the instruction cache manually diff --git a/vm/cpu-ppc.h b/vm/cpu-ppc.h index e4ff35c15c..c74e13e68b 100644 --- a/vm/cpu-ppc.h +++ b/vm/cpu-ppc.h @@ -11,6 +11,7 @@ void docol(CELL word); void undefined(CELL word); void set_callstack(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy); void throw_impl(CELL quot, F_STACK_FRAME *rewind); +void lazy_jit_compile(CELL quot); void flush_icache(CELL start, CELL len); #define FRAME_SUCCESSOR(frame) (frame)->previous diff --git a/vm/cpu-x86.32.S b/vm/cpu-x86.32.S index 19a735ec88..6233b4a14f 100644 --- a/vm/cpu-x86.32.S +++ b/vm/cpu-x86.32.S @@ -9,6 +9,7 @@ and the callstack top is passed in EDX */ #define XT_REG %ecx #define STACK_REG %esp #define DS_REG %esi +#define RETURN_REG %eax #define CELL_SIZE 4 @@ -20,7 +21,7 @@ and the callstack top is passed in EDX */ pop %ebp ; \ pop %ebx -#define QUOT_XT_OFFSET 5 +#define QUOT_XT_OFFSET 9 #define PROFILING_OFFSET 25 #define WORD_DEF_OFFSET 13 #define WORD_XT_OFFSET 29 diff --git a/vm/cpu-x86.64.S b/vm/cpu-x86.64.S index 1725c0cbd5..4e8faa18de 100644 --- a/vm/cpu-x86.64.S +++ b/vm/cpu-x86.64.S @@ -5,6 +5,7 @@ #define XT_REG %rcx #define STACK_REG %rsp #define DS_REG %r14 +#define RETURN_REG %rax #define CELL_SIZE 8 @@ -20,7 +21,7 @@ pop %rbp ; \ pop %rbx -#define QUOT_XT_OFFSET 13 +#define QUOT_XT_OFFSET 21 #define PROFILING_OFFSET 53 #define WORD_DEF_OFFSET 29 #define WORD_XT_OFFSET 61 diff --git a/vm/cpu-x86.S b/vm/cpu-x86.S index 3e2a97dd5c..ec5d09291e 100644 --- a/vm/cpu-x86.S +++ b/vm/cpu-x86.S @@ -51,3 +51,15 @@ DEF(FASTCALL void,primitive_execute,(void)): DEF(FASTCALL void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): mov ARG1,STACK_REG /* rewind_to */ JUMP_QUOT + +DEF(FASTCALL void,lazy_jit_compile,(CELL quot)): + mov STACK_REG,ARG1 /* Save stack pointer */ + push XT_REG /* Alignment */ + push XT_REG + push XT_REG + call MANGLE(jit_compile) + mov RETURN_REG,ARG0 /* No-op on 32-bit */ + pop XT_REG /* OK to clobber XT_REG here */ + pop XT_REG + pop XT_REG + JUMP_QUOT /* Call the quotation */ diff --git a/vm/cpu-x86.h b/vm/cpu-x86.h index a535038eef..63bf2b08e1 100644 --- a/vm/cpu-x86.h +++ b/vm/cpu-x86.h @@ -28,5 +28,6 @@ FASTCALL void undefined(CELL word); FASTCALL void dosym(CELL word); FASTCALL void docol_profiling(CELL word); FASTCALL void docol(CELL word); +FASTCALL void lazy_jit_compile(CELL quot); void set_callstack(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy); diff --git a/vm/data_gc.c b/vm/data_gc.c index eaf88f31c5..a94dcadf81 100644 --- a/vm/data_gc.c +++ b/vm/data_gc.c @@ -553,7 +553,7 @@ CELL collect_next(CELL scan) break; case QUOTATION_TYPE: quot = (F_QUOTATION *)scan; - if(collecting_code && quot->xt != NULL) + if(collecting_code && quot->xt != lazy_jit_compile) recursive_mark(quot->xt); break; case CALLSTACK_TYPE: diff --git a/vm/debug.c b/vm/debug.c index b7fb4ff68f..57d195e2ba 100644 --- a/vm/debug.c +++ b/vm/debug.c @@ -3,7 +3,12 @@ void print_word(F_WORD* word, CELL nesting) { if(type_of(word->name) == STRING_TYPE) - printf("%s",to_char_string(untag_string(word->name),true)); + { + F_STRING *string = untag_string(word->name); + CELL i; + for(i = 0; i < string_capacity(string); i++) + putchar(cget(SREF(string,i))); + } else { printf("#xt) - { - /* This can only happen when we're starting a stage2 bootstrap. - The stage1 bootstrapper doesn't attempt to compile quotations, - so we do it here. */ - jit_compile_all(); - } - nest_stacks(); c_to_factor_toplevel(userenv[BOOT_ENV]); unnest_stacks(); diff --git a/vm/factor.rs b/vm/factor.rs index ffe83d00ab..5b983cacba 100644 --- a/vm/factor.rs +++ b/vm/factor.rs @@ -1,2 +1,2 @@ -fraptor ICON "misc/icons/FRaptorMix.ico" +fraptor ICON "misc/icons/Factor.ico" diff --git a/vm/image.c b/vm/image.c index 32e628f902..a4fd08af00 100644 --- a/vm/image.c +++ b/vm/image.c @@ -154,17 +154,17 @@ void fixup_word(F_WORD *word) { /* If this is a compiled word, relocate the code pointer. Otherwise, reset it based on the primitive number of the word. */ - if(word->compiledp != F) - code_fixup(&word->xt); + if(word->compiledp == F) + word->xt = default_word_xt(word); else - update_xt(word); + code_fixup(&word->xt); } void fixup_quotation(F_QUOTATION *quot) { - /* quot->xt is only ever NULL at the start of stage2 bootstrap, - in this case the JIT compiles all quotations */ - if(quot->xt) + if(quot->compiled == F) + quot->xt = lazy_jit_compile; + else code_fixup("->xt); } diff --git a/vm/jit.c b/vm/jit.c index 7cdd645683..6faf0a6a17 100644 --- a/vm/jit.c +++ b/vm/jit.c @@ -34,8 +34,13 @@ bool jit_stack_frame_p(F_ARRAY *array) return false; } -void jit_compile(F_QUOTATION *quot) +FASTCALL CELL jit_compile(CELL tagged, F_STACK_FRAME *stack) { + stack_chain->callstack_top = stack; + + REGISTER_ROOT(tagged); + + F_QUOTATION *quot = untag_quotation(tagged); F_ARRAY *array = untag_object(quot->array); REGISTER_UNTAGGED(quot); @@ -150,21 +155,10 @@ void jit_compile(F_QUOTATION *quot) UNREGISTER_UNTAGGED(quot); quot->xt = xt; -} + quot->compiled = T; -void jit_compile_all(void) -{ - begin_scan(); - - CELL obj; - while((obj = next_object()) != F) - { - if(type_of(obj) == QUOTATION_TYPE) - jit_compile(untag_quotation(obj)); - } - - /* End the scan */ - gc_off = false; + UNREGISTER_ROOT(tagged); + return tagged; } XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset) diff --git a/vm/jit.h b/vm/jit.h index 1758a24ff1..a9f1399472 100644 --- a/vm/jit.h +++ b/vm/jit.h @@ -1,3 +1,2 @@ -void jit_compile(F_QUOTATION *quot); -void jit_compile_all(void); +DLLEXPORT FASTCALL CELL jit_compile(CELL tagged, F_STACK_FRAME *stack); XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset); diff --git a/vm/layouts.h b/vm/layouts.h index e5419d1470..fc59802f36 100644 --- a/vm/layouts.h +++ b/vm/layouts.h @@ -194,6 +194,8 @@ typedef struct { CELL header; /* tagged */ CELL array; + /* tagged */ + CELL compiled; /* untagged */ XT xt; } F_QUOTATION; diff --git a/vm/run.c b/vm/run.c index 2b946b0722..255be845d3 100644 --- a/vm/run.c +++ b/vm/run.c @@ -20,23 +20,21 @@ void uncurry(CELL obj) } } -void update_xt(F_WORD* word) +XT default_word_xt(F_WORD *word) { - word->compiledp = F; - if(word->def == T) - word->xt = dosym; + return dosym; else if(type_of(word->def) == QUOTATION_TYPE) { if(profiling) - word->xt = docol_profiling; + return docol_profiling; else - word->xt = docol; + return docol; } else if(type_of(word->def) == FIXNUM_TYPE) - word->xt = primitives[to_fixnum(word->def)]; + return primitives[to_fixnum(word->def)]; else - word->xt = undefined; + return undefined; } DEFINE_PRIMITIVE(uncurry) diff --git a/vm/run.h b/vm/run.h index 4d031350d3..72ee7eea17 100644 --- a/vm/run.h +++ b/vm/run.h @@ -145,7 +145,7 @@ INLINE CELL type_of(CELL tagged) DEFPUSHPOP(d,ds) DEFPUSHPOP(r,rs) -void update_xt(F_WORD* word); +XT default_word_xt(F_WORD *word); DECLARE_PRIMITIVE(execute); DECLARE_PRIMITIVE(call); diff --git a/vm/stack.c b/vm/stack.c index cf3c1df00a..b2a05b9181 100644 --- a/vm/stack.c +++ b/vm/stack.c @@ -407,13 +407,12 @@ void stack_frame_to_array(F_STACK_FRAME *frame) offset = F; #ifdef CALLSTACK_UP_P - #define I(n) (n) + set_array_nth(array,frame_index++,frame_executing(frame)); + set_array_nth(array,frame_index++,offset); #else - #define I(n) (array_capacity(array) - (n) - 1) + set_array_nth(array,frame_index--,offset); + set_array_nth(array,frame_index--,frame_executing(frame)); #endif - - set_array_nth(array,I(frame_index++),frame_executing(frame)); - set_array_nth(array,I(frame_index++),offset); } DEFINE_PRIMITIVE(callstack_to_array) @@ -429,7 +428,12 @@ DEFINE_PRIMITIVE(callstack_to_array) /* frame_count is equal to the total length now */ +#ifdef CALLSTACK_UP_P frame_index = 0; +#else + frame_index = frame_count - 1; +#endif + iterate_callstack_object(stack,stack_frame_to_array); dpush(tag_object(array)); diff --git a/vm/types.c b/vm/types.c index 1b9b3513dc..d6cb96508a 100644 --- a/vm/types.c +++ b/vm/types.c @@ -131,12 +131,8 @@ DEFINE_PRIMITIVE(array_to_quotation) { F_QUOTATION *quot = allot_object(QUOTATION_TYPE,sizeof(F_QUOTATION)); quot->array = dpeek(); - quot->xt = NULL; - - REGISTER_UNTAGGED(quot); - jit_compile(quot); - UNREGISTER_UNTAGGED(quot); - + quot->xt = lazy_jit_compile; + quot->compiled = F; drepl(tag_object(quot)); } @@ -482,7 +478,8 @@ F_WORD *allot_word(CELL vocab, CELL name) word->def = F; word->props = F; word->counter = tag_fixnum(0); - update_xt(word); + word->compiledp = F; + word->xt = default_word_xt(word); return word; } @@ -495,7 +492,9 @@ DEFINE_PRIMITIVE(word) DEFINE_PRIMITIVE(update_xt) { - update_xt(untag_word(dpop())); + F_WORD *word = untag_word(dpop()); + word->compiledp = F; + word->xt = default_word_xt(word); } DEFINE_PRIMITIVE(word_xt)