diff --git a/.gitignore b/.gitignore index 19ace1f500..7e1e52d866 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ factor temp logs work -misc/wordsize \ No newline at end of file +buildsupport/wordsize diff --git a/Makefile b/Makefile index 054d57b641..ecb333a0b2 100755 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \ EXE_OBJS = $(PLAF_EXE_OBJS) -default: misc/wordsize - $(MAKE) `./misc/target` +default: build-support/wordsize + $(MAKE) `./build-support/target` help: @echo "Run '$(MAKE)' with one of the following parameters:" @@ -162,8 +162,8 @@ factor: $(DLL_OBJS) $(EXE_OBJS) $(CC) $(LIBS) $(LIBPATH) -L. $(LINK_WITH_ENGINE) \ $(CFLAGS) -o $@$(EXE_SUFFIX)$(EXE_EXTENSION) $(EXE_OBJS) -misc/wordsize: misc/wordsize.c - gcc misc/wordsize.c -o misc/wordsize +build-support/wordsize: build-support/wordsize.c + gcc build-support/wordsize.c -o build-support/wordsize clean: rm -f vm/*.o diff --git a/build-support/grovel.c b/build-support/grovel.c new file mode 100644 index 0000000000..8422ec197c --- /dev/null +++ b/build-support/grovel.c @@ -0,0 +1,168 @@ +#include + +#if defined(__FreeBSD__) + #define BSD + #define FREEBSD + #define UNIX +#endif + +#if defined(__NetBSD__) + #define BSD + #define NETBSD + #define UNIX +#endif + +#if defined(__OpenBSD__) + #define BSD + #define OPENBSD + #define UNIX +#endif + +#if defined(__APPLE__) + #define BSD + #define MACOSX + #define UNIX +#endif + +#if defined(linux) + #define LINUX + #define UNIX +#endif + +#if defined(__amd64__) || defined(__x86_64__) + #define BIT64 +#else + #define BIT32 +#endif + +#if defined(UNIX) + #include + #include + #include + #include + #include + #include + #include +#endif + +#define BL printf(" "); +#define QUOT printf("\""); +#define NL printf("\n"); +#define LB printf("{"); BL +#define RB BL printf("}"); +#define SEMI printf(";"); +#define grovel(t) printf("TYPEDEF: "); printf("%d", sizeof(t)); BL printf(#t); NL +#define grovel2impl(t,n) BL BL BL BL LB QUOT printf(#t); QUOT BL QUOT printf((n)); QUOT RB +#define grovel2(t,n) grovel2impl(t,n) NL +#define grovel2end(t,n) grovel2impl(t,n) BL SEMI NL +#define header(os) printf("vvv %s vvv", (os)); NL +#define footer(os) printf("^^^ %s ^^^", (os)); NL +#define header2(os,struct) printf("vvv %s %s vvv", (os), (struct)); NL +#define footer2(os,struct) printf("^^^ %s %s ^^^", (os), (struct)); NL +#define struct(n) printf("C-STRUCT: %s\n", (n)); +#define constant(n) printf("#define "); printf(#n); printf(" %d (HEX: %04x)", (n), (n)); NL + +void openbsd_types() +{ + header2("openbsd", "types"); + grovel(dev_t); + grovel(gid_t); + grovel(ino_t); + grovel(int32_t); + grovel(int64_t); + grovel(mode_t); + grovel(nlink_t); + grovel(off_t); + grovel(struct timespec); + grovel(uid_t); + footer2("openbsd", "types"); +} + +void openbsd_stat() +{ + header2("openbsd", "stat"); + struct("stat"); + grovel2(dev_t, "st_dev"); + grovel2(ino_t, "st_ino"); + grovel2(mode_t, "st_mode"); + grovel2(nlink_t, "st_nlink"); + grovel2(uid_t, "st_uid"); + grovel2(gid_t, "st_gid"); + grovel2(dev_t, "st_rdev"); + grovel2(int32_t, "st_lspare0"); + grovel2(struct timespec, "st_atim"); + grovel2(struct timespec, "st_mtim"); + grovel2(struct timespec, "st_ctim"); + grovel2(off_t, "st_size"); + grovel2(int64_t, "st_blocks"); + grovel2(u_int32_t, "st_blksize"); + grovel2(u_int32_t, "st_flags"); + grovel2(u_int32_t, "st_gen"); + grovel2(int32_t, "st_lspare1"); + grovel2(struct timespec, "st_birthtimespec"); + grovel2(int64_t, "st_qspare1"); + grovel2end(int64_t, "st_qspare2"); + footer2("openbsd", "stat"); +} + +void unix_types() +{ + grovel(dev_t); + grovel(gid_t); + grovel(ino_t); + grovel(int32_t); + grovel(int64_t); + grovel(mode_t); + grovel(nlink_t); + grovel(off_t); + grovel(struct timespec); + grovel(struct stat); + grovel(time_t); + grovel(uid_t); +} + +void unix_constants() +{ + constant(O_RDONLY); + constant(O_WRONLY); + constant(O_RDWR); + constant(O_APPEND); + constant(O_CREAT); + constant(O_TRUNC); + constant(O_EXCL); + constant(FD_SETSIZE); + constant(SOL_SOCKET); + constant(SO_REUSEADDR); + constant(SO_OOBINLINE); + constant(SO_SNDTIMEO); + constant(SO_RCVTIMEO); + constant(F_SETFL); + constant(O_NONBLOCK); + constant(EINTR); + constant(EAGAIN); + constant(EINPROGRESS); + constant(PROT_READ); + constant(PROT_WRITE); + constant(MAP_FILE); + constant(MAP_SHARED); +} + +int main() { +#ifdef FREEBSD + grovel(blkcnt_t); + grovel(blksize_t); + grovel(fflags_t); +#endif + +#ifdef OPENBSD + openbsd_stat(); + openbsd_types(); +#endif + +#ifdef UNIX + unix_types(); + unix_constants(); +#endif + + return 0; +} diff --git a/build-support/target b/build-support/target new file mode 100755 index 0000000000..1903a6da64 --- /dev/null +++ b/build-support/target @@ -0,0 +1,38 @@ +#!/bin/sh + +if [ \( `uname -s ` = FreeBSD \) -a \( `uname -p` = i386 \) ] +then + echo freebsd-x86-32 +elif [ \( `uname -s` = FreeBSD \) -a \( `uname -m` = amd64 \) ] +then + echo freebsd-x86-64 +elif [ \( `uname -s` = OpenBSD \) -a \( `uname -m` = i386 \) ] +then + echo openbsd-x86-32 +elif [ \( `uname -s` = OpenBSD \) -a \( `uname -m` = amd64 \) ] +then + echo openbsd-x86-64 +elif [ \( `uname -s` = NetBSD \) -a \( `uname -p` = i386 \) ] +then + echo netbsd-x86-32 +elif [ \( `uname -s` = NetBSD \) -a \( `uname -p` = x86_64 \) ] +then + echo netbsd-x86-64 +elif [ \( `uname -s` = Darwin \) -a \( `uname -p` = powerpc \) ] +then + echo macosx-ppc +elif [ `uname -s` = Darwin ] +then + echo macosx-x86-`./build-support/wordsize` +elif [ \( `uname -s` = Linux \) -a \( `uname -m` = i686 \) ] +then + echo linux-x86-32 +elif [ \( `uname -s` = Linux \) -a \( `uname -m` = x86_64 \) ] +then + echo linux-x86-64 +elif [ \( `uname -o` = Cygwin \) -a \( `uname -m` = i686 \) ] +then + echo winnt-x86-`./build-support/wordsize` +else + echo help +fi diff --git a/misc/wordsize.c b/build-support/wordsize.c similarity index 100% rename from misc/wordsize.c rename to build-support/wordsize.c diff --git a/core/alien/alien-docs.factor b/core/alien/alien-docs.factor index 475cf72d28..7bba9d7332 100755 --- a/core/alien/alien-docs.factor +++ b/core/alien/alien-docs.factor @@ -65,8 +65,7 @@ HELP: dlclose ( dll -- ) HELP: load-library { $values { "name" "a string" } { "dll" "a DLL handle" } } -{ $description "Loads a library by logical name and outputs a handle which may be passed to " { $link dlsym } " or " { $link dlclose } ". If the library is already loaded, returns the existing handle." } -{ $errors "Throws an error if the library could not be found, or if loading fails for some other reason." } ; +{ $description "Loads a library by logical name and outputs a handle which may be passed to " { $link dlsym } " or " { $link dlclose } ". If the library is already loaded, returns the existing handle." } ; HELP: add-library { $values { "name" "a string" } { "path" "a string" } { "abi" "one of " { $snippet "\"cdecl\"" } " or " { $snippet "\"stdcall\"" } } } @@ -211,8 +210,9 @@ $nl ARTICLE: "alien-callback" "Calling Factor from C" "Callbacks can be defined and passed to C code as function pointers; the C code can then invoke the callback and run Factor code:" { $subsection alien-callback } -"There are some details concerning the conversion of Factor objects to C values, and vice versa. See " { $link "c-data" } "." -{ $subsection "alien-callback-gc" } ; +"There are some caveats concerning the conversion of Factor objects to C values, and vice versa. See " { $link "c-data" } "." +{ $subsection "alien-callback-gc" } +{ $see-also "byte-arrays-gc" } ; ARTICLE: "dll.private" "DLL handles" "DLL handles are a built-in class of objects which represent loaded native libraries. DLL handles are instances of the " { $link dll } " class, and have a literal syntax used for debugging prinouts; see " { $link "syntax-aliens" } "." @@ -291,7 +291,7 @@ $nl "The C library interface is entirely self-contained; there is no C code which one must write in order to wrap a library." $nl "C library interface words are found in the " { $vocab-link "alien" } " vocabulary." -{ $warning "Since C does not retain runtime type information or do any kind of runtime type checking, any C library interface is not pointer safe. Improper use of C functions can crash the runtime or corrupt memory in unpredictible ways." } +{ $warning "C does not perform runtime type checking, automatic memory management or array bounds checks. Incorrect usage of C library functions can lead to crashes, data corruption, and security exploits." } { $subsection "loading-libs" } { $subsection "alien-invoke" } { $subsection "alien-callback" } diff --git a/core/alien/alien-tests.factor b/core/alien/alien-tests.factor index 5f7b9fff21..28a1e98710 100755 --- a/core/alien/alien-tests.factor +++ b/core/alien/alien-tests.factor @@ -1,7 +1,7 @@ IN: alien.tests -USING: alien alien.accessors byte-arrays arrays kernel -kernel.private namespaces tools.test sequences libc math system -prettyprint layouts ; +USING: alien alien.accessors alien.syntax byte-arrays arrays +kernel kernel.private namespaces tools.test sequences libc math +system prettyprint layouts ; [ t ] [ -1 alien-address 0 > ] unit-test @@ -68,3 +68,7 @@ cell 8 = [ [ f ] [ 0 B{ 1 2 3 } pinned-c-ptr? ] unit-test [ "( displaced alien )" ] [ 0 B{ 1 2 3 } unparse ] unit-test + +[ f ] [ DLL" fadfasdfsada" dll-valid? ] unit-test + +[ f ] [ "does not exist" DLL" fadsfasfdsaf" dlsym ] unit-test diff --git a/core/alien/alien.factor b/core/alien/alien.factor index 0369d55fb3..436d73e874 100755 --- a/core/alien/alien.factor +++ b/core/alien/alien.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2004, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: assocs kernel math namespaces sequences system -kernel.private tuples bit-arrays byte-arrays float-arrays ; +kernel.private tuples bit-arrays byte-arrays float-arrays +arrays ; IN: alien ! Some predicate classes used by the compiler for optimization @@ -57,28 +58,28 @@ TUPLE: library path abi dll ; over dup [ dlopen ] when \ library construct-boa ; : load-library ( name -- dll ) - library library-dll ; + library dup [ library-dll ] when ; : add-library ( name path abi -- ) swap libraries get set-at ; TUPLE: alien-callback return parameters abi quot xt ; -TUPLE: alien-callback-error ; +ERROR: alien-callback-error ; : alien-callback ( return parameters abi quot -- alien ) - \ alien-callback-error construct-empty throw ; + alien-callback-error ; TUPLE: alien-indirect return parameters abi ; -TUPLE: alien-indirect-error ; +ERROR: alien-indirect-error ; : alien-indirect ( ... funcptr return parameters abi -- ) - \ alien-indirect-error construct-empty throw ; + alien-indirect-error ; -TUPLE: alien-invoke library function return parameters ; +TUPLE: alien-invoke library function return parameters abi ; -TUPLE: alien-invoke-error library symbol ; +ERROR: alien-invoke-error library symbol ; : alien-invoke ( ... return library function parameters -- ... ) - 2over \ alien-invoke-error construct-boa throw ; + 2over alien-invoke-error ; diff --git a/core/alien/c-types/c-types-docs.factor b/core/alien/c-types/c-types-docs.factor index fe6873ac3a..8d2b03467b 100755 --- a/core/alien/c-types/c-types-docs.factor +++ b/core/alien/c-types/c-types-docs.factor @@ -158,6 +158,19 @@ HELP: define-out { $description "Defines a word " { $snippet "<" { $emphasis "name" } ">" } " with stack effect " { $snippet "( value -- array )" } ". This word allocates a byte array large enough to hold a value with C type " { $snippet "name" } ", and writes the value at the top of the stack to the array." } { $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ; +ARTICLE: "byte-arrays-gc" "Byte arrays and the garbage collector" +"The Factor garbage collector can move byte arrays around, and it is only safe to pass byte arrays to C functions if the garbage collector will not run while C code still has a reference to the data." +$nl +"In particular, a byte array can only be passed as a parameter if the the C function does not use the parameter after one of the following occurs:" +{ $list + "the C function returns" + "the C function calls Factor code via a callback" +} +"Returning from C to Factor, as well as invoking Factor code via a callback, may trigger garbage collection, and if the function had stored a pointer to the byte array somewhere, this pointer may cease to be valid." +$nl +"If this condition is not satisfied, " { $link "malloc" } " must be used instead." +{ $warning "Failure to comply with these requirements can lead to crashes, data corruption, and security exploits." } ; + ARTICLE: "c-out-params" "Output parameters in C" "A frequently-occurring idiom in C code is the \"out parameter\". If a C function returns more than one value, the caller passes pointers of the correct type, and the C function writes its return values to those locations." $nl @@ -229,13 +242,11 @@ $nl { $subsection } { $subsection } { $warning -"The Factor garbage collector can move byte arrays around, and it is only safe to pass byte arrays to C functions if the function does not store a pointer to the byte array in some global structure, or retain it in any way after returning." -$nl -"Long-lived data for use by C libraries can be allocated manually, just as when programming in C. See " { $link "malloc" } "." } +"The Factor garbage collector can move byte arrays around, and code passing byte arrays to C must obey important guidelines. See " { $link "byte-arrays-gc" } "." } { $see-also "c-arrays" } ; ARTICLE: "malloc" "Manual memory management" -"Sometimes data passed to C functions must be allocated at a fixed address, and so garbage collector managed byte arrays cannot be used. See the warning at the bottom of " { $link "c-byte-arrays" } " for a description of when this is the case." +"Sometimes data passed to C functions must be allocated at a fixed address. See " { $link "byte-arrays-gc" } " for an explanation of when this is the case." $nl "Allocating a C datum with a fixed address:" { $subsection malloc-object } @@ -245,8 +256,6 @@ $nl { $subsection malloc } { $subsection calloc } { $subsection realloc } -"The return value of the above three words must always be checked for a memory allocation failure:" -{ $subsection check-ptr } "You must always free pointers returned by any of the above words when the block of memory is no longer in use:" { $subsection free } "You can unsafely copy a range of bytes from one memory location to another:" @@ -271,20 +280,25 @@ ARTICLE: "c-strings" "C strings" { $subsection string>u16-alien } { $subsection malloc-char-string } { $subsection malloc-u16-string } -"The first two allocate " { $link byte-array } "s, and the latter allocates manually-managed memory which is not moved by the garbage collector and has to be explicitly freed by calling " { $link free } "." +"The first two allocate " { $link byte-array } "s, and the latter allocates manually-managed memory which is not moved by the garbage collector and has to be explicitly freed by calling " { $link free } ". See " { $link "byte-arrays-gc" } " for a discussion of the two approaches." $nl "Finally, a set of words can be used to read and write " { $snippet "char*" } " and " { $snippet "ushort*" } " strings at arbitrary addresses:" { $subsection alien>char-string } -{ $subsection alien>u16-string } ; +{ $subsection alien>u16-string } +"For example, if a C function returns a " { $snippet "char*" } " but stipulates that the caller must deallocate the memory afterward, you must define the function as returning " { $snippet "void*" } ", and call one of the above words before passing the pointer to " { $link free } "." ; ARTICLE: "c-data" "Passing data between Factor and C" -"Two defining characteristics of Factor are dynamic typing and automatic memory management, which are somewhat incompatible with the machine-level data model exposed by C. Factor's C library interface defines its own set of C data types, distinct from Factor language types, together with automatic conversion between Factor values and C types. For example, C integer types must be declared and are fixed-width, whereas Factor supports arbitrary-precision integers. Also Factor's garbage collector can move objects in memory, which means that special support has to be provided for passing blocks of memory to C code." +"Two defining characteristics of Factor are dynamic typing and automatic memory management, which are somewhat incompatible with the machine-level data model exposed by C. Factor's C library interface defines its own set of C data types, distinct from Factor language types, together with automatic conversion between Factor values and C types. For example, C integer types must be declared and are fixed-width, whereas Factor supports arbitrary-precision integers." +$nl +"Furthermore, Factor's garbage collector can move objects in memory; for a discussion of the consequences, see " { $link "byte-arrays-gc" } "." { $subsection "c-types-specs" } { $subsection "c-byte-arrays" } { $subsection "malloc" } { $subsection "c-strings" } { $subsection "c-arrays" } { $subsection "c-out-params" } +"Important guidelines for passing data in byte arrays:" +{ $subsection "byte-arrays-gc" } "C-style enumerated types are supported:" { $subsection POSTPONE: C-ENUM: } "C types can be aliased for convenience and consitency with native library documentation:" diff --git a/core/alien/c-types/c-types.factor b/core/alien/c-types/c-types.factor index c3f5c64b29..d874243d71 100755 --- a/core/alien/c-types/c-types.factor +++ b/core/alien/c-types/c-types.factor @@ -26,9 +26,7 @@ global [ c-types [ H{ } assoc-like ] change ] bind -TUPLE: no-c-type name ; - -: no-c-type ( type -- * ) \ no-c-type construct-boa throw ; +ERROR: no-c-type name ; : (c-type) ( name -- type/f ) c-types get-global at dup [ @@ -262,8 +260,8 @@ M: long-long-type box-return ( type -- ) r> add* ] when ; -: malloc-file-contents ( path -- alien ) - binary file-contents malloc-byte-array ; +: malloc-file-contents ( path -- alien len ) + binary file-contents dup malloc-byte-array swap length ; [ [ alien-cell ] diff --git a/core/alien/compiler/compiler-tests.factor b/core/alien/compiler/compiler-tests.factor index 7e2e23726b..f9dc426de1 100755 --- a/core/alien/compiler/compiler-tests.factor +++ b/core/alien/compiler/compiler-tests.factor @@ -330,11 +330,11 @@ FUNCTION: double ffi_test_36 ( test-struct-12 x ) ; ! Hack; if we're on ARM, we probably don't have much RAM, so ! skip this test. -cpu "arm" = [ - [ "testing" ] [ - "testing" callback-5a callback_test_1 - ] unit-test -] unless +! cpu "arm" = [ +! [ "testing" ] [ +! "testing" callback-5a callback_test_1 +! ] unit-test +! ] unless : callback-6 "void" { } "cdecl" [ [ continue ] callcc0 ] alien-callback ; diff --git a/core/alien/compiler/compiler.factor b/core/alien/compiler/compiler.factor index fb7d50e882..3e0062c85a 100755 --- a/core/alien/compiler/compiler.factor +++ b/core/alien/compiler/compiler.factor @@ -6,14 +6,9 @@ inference.state inference.backend inference.dataflow system math.parser classes alien.arrays alien.c-types alien.structs alien.syntax cpu.architecture alien inspector quotations assocs kernel.private threads continuations.private libc combinators -compiler.errors continuations layouts ; +compiler.errors continuations layouts accessors ; IN: alien.compiler -! Common protocol for alien-invoke/alien-callback/alien-indirect -GENERIC: alien-node-parameters ( node -- seq ) -GENERIC: alien-node-return ( node -- ctype ) -GENERIC: alien-node-abi ( node -- str ) - : large-struct? ( ctype -- ? ) dup c-struct? [ heap-size struct-small-enough? not @@ -22,11 +17,11 @@ GENERIC: alien-node-abi ( node -- str ) ] if ; : alien-node-parameters* ( node -- seq ) - dup alien-node-parameters - swap alien-node-return large-struct? [ "void*" add* ] when ; + dup parameters>> + swap return>> large-struct? [ "void*" add* ] when ; : alien-node-return* ( node -- ctype ) - alien-node-return dup large-struct? [ drop "void" ] when ; + return>> dup large-struct? [ drop "void" ] when ; : c-type-stack-align ( type -- align ) dup c-type-stack-align? [ c-type-align ] [ drop cell ] if ; @@ -51,7 +46,7 @@ GENERIC: alien-node-abi ( node -- str ) : alien-invoke-frame ( node -- n ) #! One cell is temporary storage, temp@ - dup alien-node-return return-size + dup return>> return-size swap alien-stack-frame + cell + ; @@ -147,9 +142,9 @@ M: long-long-type flatten-value-type ( type -- ) pick "void" = [ drop nip call ] [ nip call ] if ; inline : alien-invoke-stack ( node extra -- ) - over alien-node-parameters length + dup reify-curries + over parameters>> length + dup reify-curries over consume-values - dup alien-node-return "void" = 0 1 ? + dup return>> "void" = 0 1 ? swap produce-values ; : (make-prep-quot) ( parameters -- ) @@ -161,11 +156,11 @@ M: long-long-type flatten-value-type ( type -- ) ] if ; : make-prep-quot ( node -- quot ) - alien-node-parameters + parameters>> [ (make-prep-quot) ] [ ] make ; : unbox-parameters ( offset node -- ) - alien-node-parameters [ + parameters>> [ %prepare-unbox >r over + r> unbox-parameter ] reverse-each-parameter drop ; @@ -174,7 +169,7 @@ M: long-long-type flatten-value-type ( type -- ) #! parameters. If the C function is returning a structure, #! the first parameter is an implicit target area pointer, #! so we need to use a different offset. - alien-node-return dup large-struct? + return>> dup large-struct? [ heap-size %prepare-box-struct cell ] [ drop 0 ] if ; : objects>registers ( node -- ) @@ -188,14 +183,7 @@ M: long-long-type flatten-value-type ( type -- ) ] with-param-regs ; : box-return* ( node -- ) - alien-node-return [ ] [ box-return ] if-void ; - -M: alien-invoke alien-node-parameters alien-invoke-parameters ; -M: alien-invoke alien-node-return alien-invoke-return ; - -M: alien-invoke alien-node-abi - alien-invoke-library library - [ library-abi ] [ "cdecl" ] if* ; + return>> [ ] [ box-return ] if-void ; M: alien-invoke-error summary drop @@ -205,7 +193,7 @@ M: alien-invoke-error summary : stdcall-mangle ( symbol node -- symbol ) "@" - swap alien-node-parameters parameter-sizes drop + swap parameters>> parameter-sizes drop number>string 3append ; TUPLE: no-such-library name ; @@ -256,6 +244,10 @@ M: no-such-symbol compiler-error-type pop-literal nip over set-alien-invoke-return ! Quotation which coerces parameters to required types dup make-prep-quot recursive-state get infer-quot + ! Set ABI + dup alien-invoke-library + library [ library-abi ] [ "cdecl" ] if* + over set-alien-invoke-abi ! Add node to IR dup node, ! Magic #: consume exactly the number of inputs @@ -274,10 +266,6 @@ M: alien-invoke generate-node iterate-next ] with-stack-frame ; -M: alien-indirect alien-node-parameters alien-indirect-parameters ; -M: alien-indirect alien-node-return alien-indirect-return ; -M: alien-indirect alien-node-abi alien-indirect-abi ; - M: alien-indirect-error summary drop "Words calling ``alien-indirect'' must be compiled with the optimizing compiler." ; @@ -323,10 +311,6 @@ callbacks global [ H{ } assoc-like ] change-at : register-callback ( word -- ) dup callbacks get set-at ; -M: alien-callback alien-node-parameters alien-callback-parameters ; -M: alien-callback alien-node-return alien-callback-return ; -M: alien-callback alien-node-abi alien-callback-abi ; - M: alien-callback-error summary drop "Words calling ``alien-callback'' must be compiled with the optimizing compiler." ; @@ -373,7 +357,7 @@ TUPLE: callback-context ; wait-to-return ; inline : prepare-callback-return ( ctype -- quot ) - alien-node-return { + return>> { { [ dup "void" = ] [ drop [ ] ] } { [ dup large-struct? ] [ heap-size [ memcpy ] curry ] } { [ t ] [ c-type c-type-prep ] } @@ -390,8 +374,8 @@ TUPLE: callback-context ; : callback-unwind ( node -- n ) { - { [ dup alien-node-abi "stdcall" = ] [ alien-stack-frame ] } - { [ dup alien-node-return large-struct? ] [ drop 4 ] } + { [ dup abi>> "stdcall" = ] [ alien-stack-frame ] } + { [ dup return>> large-struct? ] [ drop 4 ] } { [ t ] [ drop 0 ] } } cond ; diff --git a/core/alien/structs/structs-docs.factor b/core/alien/structs/structs-docs.factor index fe19f29766..6c7775de2b 100755 --- a/core/alien/structs/structs-docs.factor +++ b/core/alien/structs/structs-docs.factor @@ -1,6 +1,65 @@ IN: alien.structs USING: alien.c-types strings help.markup help.syntax -alien.syntax sequences io arrays ; +alien.syntax sequences io arrays slots.deprecated +kernel words slots assocs namespaces ; + +! Deprecated code +: ($spec-reader-values) ( slot-spec class -- element ) + dup ?word-name swap 2array + over slot-spec-name + rot slot-spec-type 2array 2array + [ { $instance } swap add ] assoc-map ; + +: $spec-reader-values ( slot-spec class -- ) + ($spec-reader-values) $values ; + +: $spec-reader-description ( slot-spec class -- ) + [ + "Outputs the value stored in the " , + { $snippet } rot slot-spec-name add , + " slot of " , + { $instance } swap add , + " instance." , + ] { } make $description ; + +: $spec-reader ( reader slot-specs class -- ) + >r slot-of-reader r> + over [ + 2dup $spec-reader-values + 2dup $spec-reader-description + ] when 2drop ; + +GENERIC: slot-specs ( help-type -- specs ) + +M: word slot-specs "slots" word-prop ; + +: $slot-reader ( reader -- ) + first dup "reading" word-prop [ slot-specs ] keep + $spec-reader ; + +: $spec-writer-values ( slot-spec class -- ) + ($spec-reader-values) reverse $values ; + +: $spec-writer-description ( slot-spec class -- ) + [ + "Stores a new value to the " , + { $snippet } rot slot-spec-name add , + " slot of " , + { $instance } swap add , + " instance." , + ] { } make $description ; + +: $spec-writer ( writer slot-specs class -- ) + >r slot-of-writer r> + over [ + 2dup $spec-writer-values + 2dup $spec-writer-description + dup ?word-name 1array $side-effects + ] when 2drop ; + +: $slot-writer ( reader -- ) + first dup "writing" word-prop [ slot-specs ] keep + $spec-writer ; M: string slot-specs c-type struct-type-fields ; diff --git a/core/alien/structs/structs.factor b/core/alien/structs/structs.factor index aec09621cb..e5de8ab83e 100755 --- a/core/alien/structs/structs.factor +++ b/core/alien/structs/structs.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: arrays generic hashtables kernel kernel.private math namespaces parser sequences strings words libc slots -alien.c-types cpu.architecture ; +slots.deprecated alien.c-types cpu.architecture ; IN: alien.structs : align-offset ( offset type -- offset ) diff --git a/core/alien/syntax/syntax.factor b/core/alien/syntax/syntax.factor index b81a91efcb..6e4b8b4e21 100755 --- a/core/alien/syntax/syntax.factor +++ b/core/alien/syntax/syntax.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2005, 2007 Slava Pestov, Alex Chapman. +! Copyright (C) 2005, 2008 Slava Pestov, Alex Chapman. ! See http://factorcode.org/license.txt for BSD license. USING: arrays alien alien.c-types alien.structs alien.arrays kernel math namespaces parser sequences words quotations @@ -9,7 +9,7 @@ IN: alien.syntax ; : function-quot ( type lib func types -- quot ) @@ -32,7 +32,7 @@ PRIVATE> >r >r swapd roll indirect-quot r> r> -rot define-declared ; -: DLL" skip-blank parse-string dlopen parsed ; parsing +: DLL" lexer get skip-blank parse-string dlopen parsed ; parsing : ALIEN: scan string>number parsed ; parsing diff --git a/core/bootstrap/compiler/compiler.factor b/core/bootstrap/compiler/compiler.factor index 5ccde88e28..04d57dff16 100755 --- a/core/bootstrap/compiler/compiler.factor +++ b/core/bootstrap/compiler/compiler.factor @@ -79,7 +79,7 @@ nl "." write flush { - malloc free memcpy + malloc calloc free memcpy } compile " done" print flush diff --git a/core/bootstrap/image/image.factor b/core/bootstrap/image/image.factor index f5f4d70d14..52a2496755 100755 --- a/core/bootstrap/image/image.factor +++ b/core/bootstrap/image/image.factor @@ -349,7 +349,7 @@ M: curry ' [ { dictionary source-files - typemap builtins classr default-image-name "output-image" set-global -"math help handbook compiler tools ui ui.tools io" "include" set-global +"math help handbook compiler random tools ui ui.tools io" "include" set-global "" "exclude" set-global parse-command-line @@ -106,5 +106,5 @@ f error-continuation set-global millis r> - dup bootstrap-time set-global print-report - "output-image" get resource-path save-image-and-exit + "output-image" get save-image-and-exit ] if diff --git a/core/bootstrap/syntax.factor b/core/bootstrap/syntax.factor index 4df5a68e97..e7e90d8dd0 100755 --- a/core/bootstrap/syntax.factor +++ b/core/bootstrap/syntax.factor @@ -3,9 +3,7 @@ USING: words sequences vocabs kernel ; IN: bootstrap.syntax -"syntax" create-vocab -"resource:core" over set-vocab-root -f swap set-vocab-source-loaded? +"syntax" create-vocab drop { "!" @@ -23,6 +21,7 @@ f swap set-vocab-source-loaded? "C:" "CHAR:" "DEFER:" + "ERROR:" "F{" "FV{" "FORGET:" diff --git a/core/classes/classes-tests.factor b/core/classes/classes-tests.factor index dbc1bcace2..3322c3b043 100755 --- a/core/classes/classes-tests.factor +++ b/core/classes/classes-tests.factor @@ -1,6 +1,6 @@ USING: alien arrays definitions generic assocs hashtables io kernel math namespaces parser prettyprint sequences strings -tools.test vectors words quotations classes io.streams.string +tools.test vectors words quotations classes classes.private classes.union classes.mixin classes.predicate vectors definitions source-files compiler.units ; IN: classes.tests @@ -22,12 +22,16 @@ H{ } "s" set [ number ] [ number object class-and ] unit-test [ number ] [ object number class-and ] unit-test [ null ] [ slice reversed class-and ] unit-test +[ null ] [ general-t \ f class-and ] unit-test +[ object ] [ general-t \ f class-or ] unit-test TUPLE: first-one ; TUPLE: second-one ; UNION: both first-one union-class ; [ t ] [ both tuple classes-intersect? ] unit-test +[ null ] [ vector virtual-sequence class-and ] unit-test +[ f ] [ vector virtual-sequence classes-intersect? ] unit-test [ t ] [ \ fixnum \ integer class< ] unit-test [ t ] [ \ fixnum \ fixnum class< ] unit-test @@ -61,10 +65,6 @@ UNION: c a b ; UNION: bah fixnum alien ; [ bah ] [ \ bah? "predicating" word-prop ] unit-test -! Test generic see and parsing -[ "USING: alien math ;\nIN: classes.tests\nUNION: bah fixnum alien ;\n" ] -[ [ \ bah see ] with-string-writer ] unit-test - ! Test redefinition of classes UNION: union-1 fixnum float ; @@ -178,6 +178,8 @@ UNION: forget-class-bug-2 forget-class-bug-1 dll ; [ f ] [ forget-class-bug-2 typemap get values [ memq? ] with contains? ] unit-test +USE: io.streams.string + 2 [ [ "mixin-forget-test" forget-source ] with-compilation-unit @@ -222,3 +224,7 @@ MIXIN: flat-mx-2 INSTANCE: flat-mx-2 flat-mx-1 TUPLE: flat-mx-2-1 ; INSTANCE: flat-mx-2-1 flat-mx-2 [ t ] [ T{ flat-mx-2-1 } flat-mx-1? ] unit-test + +! Test generic see and parsing +[ "USING: alien math ;\nIN: classes.tests\nUNION: bah fixnum alien ;\n" ] +[ [ \ bah see ] with-string-writer ] unit-test diff --git a/core/classes/classes.factor b/core/classes/classes.factor index e60d3ba223..e47dbd20e5 100755 --- a/core/classes/classes.factor +++ b/core/classes/classes.factor @@ -8,11 +8,12 @@ vectors math quotations combinators sorting effects graphs ; PREDICATE: word class ( obj -- ? ) "class" word-prop ; SYMBOL: typemap +SYMBOL: class-map SYMBOL: classboolean ; { [ dup builtin-class? ] [ dup set ] } { [ dup members ] [ members [ (flatten-class) ] each ] } { [ dup superclass ] [ superclass (flatten-class) ] } + { [ t ] [ drop ] } } cond ; : flatten-class ( class -- assoc ) @@ -108,11 +110,31 @@ DEFER: (class<) : lookup-union ( classes -- class ) typemap get at dup empty? [ drop object ] [ first ] if ; +: lookup-tuple-union ( classes -- class ) + class-map get at dup empty? [ drop object ] [ first ] if ; + +! : (class-or) ( class class -- class ) +! [ flatten-builtin-class ] 2apply union lookup-union ; +! +! : (class-and) ( class class -- class ) +! [ flatten-builtin-class ] 2apply intersect lookup-union ; + +: class-or-fixup ( set set -- set ) + union + tuple over key? + [ [ drop tuple-class? not ] assoc-subset ] when ; + : (class-or) ( class class -- class ) - [ flatten-builtin-class ] 2apply union lookup-union ; + [ flatten-class ] 2apply class-or-fixup lookup-tuple-union ; : (class-and) ( class class -- class ) - [ flatten-builtin-class ] 2apply intersect lookup-union ; + 2dup [ tuple swap class< ] either? [ + [ flatten-builtin-class ] 2apply + intersect lookup-union + ] [ + [ flatten-class ] 2apply + intersect lookup-tuple-union + ] if ; : tuple-class-and ( class1 class2 -- class ) dupd eq? [ drop null ] unless ; @@ -219,9 +241,16 @@ M: word reset-class drop ; : typemap- ( class -- ) dup flatten-builtin-class typemap get pop-at ; +! class-map +: class-map+ ( class -- ) + dup flatten-class class-map get push-at ; + +: class-map- ( class -- ) + dup flatten-class class-map get pop-at ; + ! Class definition : cache-class ( class -- ) - dup typemap+ dup classr "predicate" word-prop [ dup ] swap append r> ] + [ >r "predicate" word-prop [ dup ] prepend r> ] assoc-map alist>quot ] if ; diff --git a/core/combinators/combinators.factor b/core/combinators/combinators.factor index ffd1576e6e..807b372e1d 100755 --- a/core/combinators/combinators.factor +++ b/core/combinators/combinators.factor @@ -5,16 +5,12 @@ USING: arrays sequences sequences.private math.private kernel kernel.private math assocs quotations vectors hashtables sorting ; -TUPLE: no-cond ; - -: no-cond ( -- * ) \ no-cond construct-empty throw ; +ERROR: no-cond ; : cond ( assoc -- ) [ first call ] find nip dup [ second call ] [ no-cond ] if ; -TUPLE: no-case ; - -: no-case ( -- * ) \ no-case construct-empty throw ; +ERROR: no-case ; : case ( obj assoc -- ) [ dup array? [ dupd first = ] [ quotation? ] if ] find nip @@ -80,7 +76,7 @@ M: hashtable hashcode* : hash-case-quot ( default assoc -- quot ) hash-case-table hash-dispatch-quot - [ dup hashcode >fixnum ] swap append ; + [ dup hashcode >fixnum ] prepend ; : contiguous-range? ( keys -- from to ? ) dup [ fixnum? ] all? [ diff --git a/core/command-line/command-line.factor b/core/command-line/command-line.factor index ed4fb9f606..72c1e063e0 100644 --- a/core/command-line/command-line.factor +++ b/core/command-line/command-line.factor @@ -7,12 +7,12 @@ splitting io.files ; : run-bootstrap-init ( -- ) "user-init" get [ - home ".factor-boot-rc" path+ ?run-file + home ".factor-boot-rc" append-path ?run-file ] when ; : run-user-init ( -- ) "user-init" get [ - home ".factor-rc" path+ ?run-file + home ".factor-rc" append-path ?run-file ] when ; : cli-var-param ( name value -- ) swap set-global ; diff --git a/core/compiler/compiler-docs.factor b/core/compiler/compiler-docs.factor index 7196a4b4fb..3520104e1f 100755 --- a/core/compiler/compiler-docs.factor +++ b/core/compiler/compiler-docs.factor @@ -8,7 +8,8 @@ $nl "The main entry point to the optimizing compiler:" { $subsection optimized-recompile-hook } "Removing a word's optimized definition:" -{ $subsection decompile } ; +{ $subsection decompile } +"These words are not usually used directly. Instead, use " { $link "compilation-units" } "." ; ARTICLE: "compiler" "Optimizing compiler" "Factor is a fully compiled language implementation with two distinct compilers:" diff --git a/core/compiler/tests/intrinsics.factor b/core/compiler/tests/intrinsics.factor index dd9a453cfc..7a8fe5d735 100755 --- a/core/compiler/tests/intrinsics.factor +++ b/core/compiler/tests/intrinsics.factor @@ -261,7 +261,7 @@ cell 8 = [ : compiled-fixnum* fixnum* ; : test-fixnum* - (random) >fixnum (random) >fixnum + 32 random-bits >fixnum 32 random-bits >fixnum 2dup [ fixnum* ] 2keep compiled-fixnum* = [ 2drop ] [ "Oops" throw ] if ; @@ -271,7 +271,7 @@ cell 8 = [ : compiled-fixnum>bignum fixnum>bignum ; : test-fixnum>bignum - (random) >fixnum + 32 random-bits >fixnum dup [ fixnum>bignum ] keep compiled-fixnum>bignum = [ drop ] [ "Oops" throw ] if ; @@ -280,7 +280,7 @@ cell 8 = [ : compiled-bignum>fixnum bignum>fixnum ; : test-bignum>fixnum - 5 random [ drop (random) ] map product >bignum + 5 random [ drop 32 random-bits ] map product >bignum dup [ bignum>fixnum ] keep compiled-bignum>fixnum = [ drop ] [ "Oops" throw ] if ; @@ -385,7 +385,7 @@ cell 8 = [ [ 252 ] [ B{ 1 2 3 -4 5 } 3 [ { byte-array fixnum } declare alien-unsigned-1 ] compile-call ] unit-test [ -4 ] [ B{ 1 2 3 -4 5 } 3 [ { byte-array fixnum } declare alien-signed-1 ] compile-call ] unit-test -: xword-def word-def [ { fixnum } declare ] swap append ; +: xword-def word-def [ { fixnum } declare ] prepend ; [ -100 ] [ -100 [ { byte-array } declare *char ] compile-call ] unit-test [ 156 ] [ -100 [ { byte-array } declare *uchar ] compile-call ] unit-test diff --git a/core/compiler/units/units-docs.factor b/core/compiler/units/units-docs.factor index 74dac17be8..09baf91018 100755 --- a/core/compiler/units/units-docs.factor +++ b/core/compiler/units/units-docs.factor @@ -9,7 +9,9 @@ $nl $nl "The parser groups all definitions in a source file into one compilation unit, and parsing words do not need to concern themselves with compilation units. However, if definitions are being created at run time, a compilation unit must be created explicitly:" { $subsection with-compilation-unit } -"Words called to associate a definition with a source file location:" +"Compiling a set of words:" +{ $subsection compile } +"Words called to associate a definition with a compilation unit and a source file location:" { $subsection remember-definition } { $subsection remember-class } "Forward reference checking (see " { $link "definition-checking" } "):" diff --git a/core/continuations/continuations-docs.factor b/core/continuations/continuations-docs.factor index 81063031f9..7209b7ec4d 100755 --- a/core/continuations/continuations-docs.factor +++ b/core/continuations/continuations-docs.factor @@ -29,7 +29,9 @@ $nl { $subsection ignore-errors } "Unhandled errors are reported in the listener and can be debugged using various tools. See " { $link "debugger" } "." { $subsection "errors-restartable" } -{ $subsection "errors-post-mortem" } ; +{ $subsection "errors-post-mortem" } +"When Factor encouters a critical error, it calls the following word:" +{ $subsection die } ; ARTICLE: "continuations.private" "Continuation implementation details" "A continuation is simply a tuple holding the contents of the five stacks:" diff --git a/core/cpu/x86/32/32.factor b/core/cpu/x86/32/32.factor index 19b913541c..81a7d7cd02 100755 --- a/core/cpu/x86/32/32.factor +++ b/core/cpu/x86/32/32.factor @@ -5,7 +5,7 @@ cpu.x86.architecture cpu.x86.intrinsics cpu.x86.allot cpu.architecture kernel kernel.private math namespaces sequences generator.registers generator.fixup generator system layouts alien.compiler combinators command-line -compiler compiler.units io vocabs.loader ; +compiler compiler.units io vocabs.loader accessors ; IN: cpu.x86.32 PREDICATE: x86-backend x86-32-backend @@ -244,10 +244,10 @@ M: x86-32-backend %cleanup ( alien-node -- ) #! have to fix ESP. { { - [ dup alien-node-abi "stdcall" = ] + [ dup abi>> "stdcall" = ] [ alien-stack-frame ESP swap SUB ] } { - [ dup alien-node-return large-struct? ] + [ dup return>> large-struct? ] [ drop EAX PUSH ] } { [ t ] [ drop ] diff --git a/core/debugger/debugger.factor b/core/debugger/debugger.factor index 40bcbe78b1..4775093ba7 100755 --- a/core/debugger/debugger.factor +++ b/core/debugger/debugger.factor @@ -6,7 +6,7 @@ strings io.styles vectors words system splitting math.parser tuples continuations continuations.private combinators generic.math io.streams.duplex classes compiler.units generic.standard vocabs threads threads.private init -kernel.private libc ; +kernel.private libc io.encodings ; IN: debugger GENERIC: error. ( error -- ) @@ -75,9 +75,7 @@ SYMBOL: error-hook : try ( quot -- ) [ error-hook get call ] recover ; -TUPLE: assert got expect ; - -: assert ( got expect -- * ) \ assert construct-boa throw ; +ERROR: assert got expect ; : assert= ( a b -- ) 2dup = [ 2drop ] [ assert ] if ; @@ -86,28 +84,22 @@ TUPLE: assert got expect ; : trim-datastacks ( seq1 seq2 -- seq1' seq2' ) 2dup [ length ] 2apply min tuck tail >r tail r> ; -TUPLE: relative-underflow stack ; - -: relative-underflow ( before after -- * ) - trim-datastacks nip \ relative-underflow construct-boa throw ; +ERROR: relative-underflow stack ; M: relative-underflow summary drop "Too many items removed from data stack" ; -TUPLE: relative-overflow stack ; +ERROR: relative-overflow stack ; M: relative-overflow summary drop "Superfluous items pushed to data stack" ; -: relative-overflow ( before after -- * ) - trim-datastacks drop \ relative-overflow construct-boa throw ; - : assert-depth ( quot -- ) >r datastack r> swap slip >r datastack r> 2dup [ length ] compare sgn { - { -1 [ relative-underflow ] } + { -1 [ trim-datastacks nip relative-underflow ] } { 0 [ 2drop ] } - { 1 [ relative-overflow ] } + { 1 [ trim-datastacks drop relative-overflow ] } } case ; inline : expired-error. ( obj -- ) @@ -210,13 +202,13 @@ M: no-method error. M: no-math-method summary drop "No suitable arithmetic method" ; -M: check-closed summary +M: stream-closed-twice summary drop "Attempt to perform I/O on closed stream" ; M: check-method summary - drop "Invalid parameters for define-method" ; + drop "Invalid parameters for create-method" ; -M: check-tuple summary +M: no-tuple-class summary drop "Invalid class for define-constructor" ; M: no-cond summary @@ -254,7 +246,7 @@ M: no-compilation-unit error. M: no-vocab summary drop "Vocabulary does not exist" ; -M: check-ptr summary +M: bad-ptr summary drop "Memory allocation failed" ; M: double-free summary @@ -282,6 +274,10 @@ M: thread error-in-thread ( error thread -- ) ] bind ] if ; +M: encode-error summary drop "Character encoding error" ; + +M: decode-error summary drop "Character decoding error" ; + [ 1 = ] swap dlist-find ] unit-test -[ 1 t ] [ 1 over push-back [ 1 = ] swap dlist-find ] unit-test -[ f f ] [ 1 over push-back [ 2 = ] swap dlist-find ] unit-test -[ f ] [ 1 over push-back [ 2 = ] swap dlist-contains? ] unit-test -[ t ] [ 1 over push-back [ 1 = ] swap dlist-contains? ] unit-test +[ f f ] [ [ 1 = ] dlist-find ] unit-test +[ 1 t ] [ 1 over push-back [ 1 = ] dlist-find ] unit-test +[ f f ] [ 1 over push-back [ 2 = ] dlist-find ] unit-test +[ f ] [ 1 over push-back [ 2 = ] dlist-contains? ] unit-test +[ t ] [ 1 over push-back [ 1 = ] dlist-contains? ] unit-test -[ 1 ] [ 1 over push-back [ 1 = ] swap delete-node-if ] unit-test -[ t ] [ 1 over push-back [ 1 = ] over delete-node-if drop dlist-empty? ] unit-test -[ t ] [ 1 over push-back [ 1 = ] over delete-node-if drop dlist-empty? ] unit-test -[ 0 ] [ 1 over push-back [ 1 = ] over delete-node-if drop dlist-length ] unit-test -[ 1 ] [ 1 over push-back 2 over push-back [ 1 = ] over delete-node-if drop dlist-length ] unit-test -[ 2 ] [ 1 over push-back 2 over push-back 3 over push-back [ 1 = ] over delete-node-if drop dlist-length ] unit-test -[ 2 ] [ 1 over push-back 2 over push-back 3 over push-back [ 2 = ] over delete-node-if drop dlist-length ] unit-test -[ 2 ] [ 1 over push-back 2 over push-back 3 over push-back [ 3 = ] over delete-node-if drop dlist-length ] unit-test +[ 1 ] [ 1 over push-back [ 1 = ] delete-node-if ] unit-test +[ t ] [ 1 over push-back dup [ 1 = ] delete-node-if drop dlist-empty? ] unit-test +[ t ] [ 1 over push-back dup [ 1 = ] delete-node-if drop dlist-empty? ] unit-test +[ 0 ] [ 1 over push-back dup [ 1 = ] delete-node-if drop dlist-length ] unit-test +[ 1 ] [ 1 over push-back 2 over push-back dup [ 1 = ] delete-node-if drop dlist-length ] unit-test +[ 2 ] [ 1 over push-back 2 over push-back 3 over push-back dup [ 1 = ] delete-node-if drop dlist-length ] unit-test +[ 2 ] [ 1 over push-back 2 over push-back 3 over push-back dup [ 2 = ] delete-node-if drop dlist-length ] unit-test +[ 2 ] [ 1 over push-back 2 over push-back 3 over push-back dup [ 3 = ] delete-node-if drop dlist-length ] unit-test [ 0 ] [ dlist-length ] unit-test [ 1 ] [ 1 over push-front dlist-length ] unit-test diff --git a/core/dlists/dlists.factor b/core/dlists/dlists.factor index 38c4ee233e..56134f3b54 100755 --- a/core/dlists/dlists.factor +++ b/core/dlists/dlists.factor @@ -1,71 +1,67 @@ -! Copyright (C) 2007 Mackenzie Straight, Doug Coleman. +! Copyright (C) 2007, 2008 Mackenzie Straight, Doug Coleman, +! Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: combinators kernel math sequences ; +USING: combinators kernel math sequences accessors ; IN: dlists TUPLE: dlist front back length ; : ( -- obj ) dlist construct-empty - 0 over set-dlist-length ; + 0 >>length ; -: dlist-empty? ( dlist -- ? ) dlist-front not ; +: dlist-empty? ( dlist -- ? ) front>> not ; dlist-node : inc-length ( dlist -- ) - [ dlist-length 1+ ] keep set-dlist-length ; inline + [ 1+ ] change-length drop ; inline : dec-length ( dlist -- ) - [ dlist-length 1- ] keep set-dlist-length ; inline + [ 1- ] change-length drop ; inline : set-prev-when ( dlist-node dlist-node/f -- ) - [ set-dlist-node-prev ] [ drop ] if* ; + [ (>>prev) ] [ drop ] if* ; : set-next-when ( dlist-node dlist-node/f -- ) - [ set-dlist-node-next ] [ drop ] if* ; + [ (>>next) ] [ drop ] if* ; : set-next-prev ( dlist-node -- ) - dup dlist-node-next set-prev-when ; + dup next>> set-prev-when ; : normalize-front ( dlist -- ) - dup dlist-back [ drop ] [ f swap set-dlist-front ] if ; + dup back>> [ f >>front ] unless drop ; : normalize-back ( dlist -- ) - dup dlist-front [ drop ] [ f swap set-dlist-back ] if ; + dup front>> [ f >>back ] unless drop ; : set-back-to-front ( dlist -- ) - dup dlist-back - [ drop ] [ dup dlist-front swap set-dlist-back ] if ; + dup back>> [ dup front>> >>back ] unless drop ; : set-front-to-back ( dlist -- ) - dup dlist-front - [ drop ] [ dup dlist-back swap set-dlist-front ] if ; + dup front>> [ dup back>> >>front ] unless drop ; -: (dlist-find-node) ( quot dlist-node -- node/f ? ) - dup dlist-node-obj pick dupd call [ - drop nip t - ] [ - drop dlist-node-next [ (dlist-find-node) ] [ drop f f ] if* - ] if ; inline +: (dlist-find-node) ( dlist-node quot -- node/f ? ) + over [ + [ >r obj>> r> call ] 2keep rot + [ drop t ] [ >r next>> r> (dlist-find-node) ] if + ] [ 2drop f f ] if ; inline -: dlist-find-node ( quot dlist -- node/f ? ) - dlist-front [ (dlist-find-node) ] [ drop f f ] if* ; inline +: dlist-find-node ( dlist quot -- node/f ? ) + >r front>> r> (dlist-find-node) ; inline -: (dlist-each-node) ( quot dlist -- ) - over - [ 2dup call >r dlist-node-next r> (dlist-each-node) ] - [ 2drop ] if ; inline +: dlist-each-node ( dlist quot -- ) + [ t ] compose dlist-find-node 2drop ; inline -: dlist-each-node ( quot dlist -- ) - >r dlist-front r> (dlist-each-node) ; inline PRIVATE> : push-front* ( obj dlist -- dlist-node ) - [ dlist-front f swap dup dup set-next-prev ] keep - [ set-dlist-front ] keep + [ front>> f swap dup dup set-next-prev ] keep + [ (>>front) ] keep [ set-back-to-front ] keep inc-length ; @@ -76,9 +72,9 @@ PRIVATE> [ push-front ] curry each ; : push-back* ( obj dlist -- dlist-node ) - [ dlist-back f ] keep - [ dlist-back set-next-when ] 2keep - [ set-dlist-back ] 2keep + [ back>> f ] keep + [ back>> set-next-when ] 2keep + [ (>>back) ] 2keep [ set-front-to-back ] keep inc-length ; @@ -89,70 +85,75 @@ PRIVATE> [ push-back ] curry each ; : peek-front ( dlist -- obj ) - dlist-front dlist-node-obj ; + front>> obj>> ; : pop-front ( dlist -- obj ) - dup dlist-front [ - dup dlist-node-next - f rot set-dlist-node-next + dup front>> [ + dup next>> + f rot (>>next) f over set-prev-when - swap set-dlist-front - ] 2keep dlist-node-obj + swap (>>front) + ] 2keep obj>> swap [ normalize-back ] keep dec-length ; : pop-front* ( dlist -- ) pop-front drop ; : peek-back ( dlist -- obj ) - dlist-back dlist-node-obj ; + back>> obj>> ; : pop-back ( dlist -- obj ) - dup dlist-back [ - dup dlist-node-prev - f rot set-dlist-node-prev + dup back>> [ + dup prev>> + f rot (>>prev) f over set-next-when - swap set-dlist-back - ] 2keep dlist-node-obj + swap (>>back) + ] 2keep obj>> swap [ normalize-front ] keep dec-length ; : pop-back* ( dlist -- ) pop-back drop ; -: dlist-find ( quot dlist -- obj/f ? ) - dlist-find-node dup [ >r dlist-node-obj r> ] when ; inline +: dlist-find ( dlist quot -- obj/f ? ) + dlist-find-node [ obj>> t ] [ drop f f ] if ; inline -: dlist-contains? ( quot dlist -- ? ) +: dlist-contains? ( dlist quot -- ? ) dlist-find nip ; inline : unlink-node ( dlist-node -- ) - dup dlist-node-prev over dlist-node-next set-prev-when - dup dlist-node-next swap dlist-node-prev set-next-when ; + dup prev>> over next>> set-prev-when + dup next>> swap prev>> set-next-when ; : delete-node ( dlist dlist-node -- ) { - { [ over dlist-front over eq? ] [ drop pop-front* ] } - { [ over dlist-back over eq? ] [ drop pop-back* ] } + { [ over front>> over eq? ] [ drop pop-front* ] } + { [ over back>> over eq? ] [ drop pop-back* ] } { [ t ] [ unlink-node dec-length ] } } cond ; -: delete-node-if* ( quot dlist -- obj/f ? ) - tuck dlist-find-node [ - [ delete-node ] keep [ dlist-node-obj t ] [ f f ] if* +: delete-node-if* ( dlist quot -- obj/f ? ) + dupd dlist-find-node [ + dup [ + [ delete-node ] keep obj>> t + ] [ + 2drop f f + ] if ] [ 2drop f f ] if ; inline -: delete-node-if ( quot dlist -- obj/f ) +: delete-node-if ( dlist quot -- obj/f ) delete-node-if* drop ; inline : dlist-delete ( obj dlist -- obj/f ) - >r [ eq? ] curry r> delete-node-if ; + swap [ eq? ] curry delete-node-if ; : dlist-delete-all ( dlist -- ) - f over set-dlist-front - f over set-dlist-back - 0 swap set-dlist-length ; + f >>front + f >>back + 0 >>length + drop ; : dlist-each ( dlist quot -- ) - [ dlist-node-obj ] swap compose dlist-each-node ; inline + [ obj>> ] swap compose dlist-each-node ; inline : dlist-slurp ( dlist quot -- ) over dlist-empty? @@ -160,4 +161,3 @@ PRIVATE> inline : 1dlist ( obj -- dlist ) [ push-front ] keep ; - diff --git a/core/generic/generic-docs.factor b/core/generic/generic-docs.factor index 9b799d9143..b59c92c798 100755 --- a/core/generic/generic-docs.factor +++ b/core/generic/generic-docs.factor @@ -34,7 +34,7 @@ $nl { $subsection define-generic } { $subsection define-simple-generic } "Methods can be added to existing generic words:" -{ $subsection define-method } +{ $subsection create-method } "Method definitions can be looked up:" { $subsection method } { $subsection methods } @@ -123,10 +123,10 @@ HELP: method { $values { "class" class } { "generic" generic } { "method/f" "a " { $link method-body } " or " { $link f } } } { $description "Looks up a method definition." } ; -{ method define-method POSTPONE: M: } related-words +{ method create-method POSTPONE: M: } related-words HELP: -{ $values { "quot" quotation } { "class" class } { "generic" generic } { "method" "a new method definition" } } +{ $values { "class" class } { "generic" generic } { "method" "a new method definition" } } { $description "Creates a new method." } ; HELP: methods @@ -140,16 +140,17 @@ HELP: order HELP: check-method { $values { "class" class } { "generic" generic } } { $description "Asserts that " { $snippet "class" } " is a class word and " { $snippet "generic" } " is a generic word, throwing a " { $link check-method } " error if the assertion fails." } -{ $error-description "Thrown if " { $link POSTPONE: M: } " or " { $link define-method } " is given an invalid class or generic word." } ; +{ $error-description "Thrown if " { $link POSTPONE: M: } " or " { $link create-method } " is given an invalid class or generic word." } ; HELP: with-methods -{ $values { "word" generic } { "quot" "a quotation with stack effect " { $snippet "( methods -- )" } } } +{ $values { "generic" generic } { "quot" "a quotation with stack effect " { $snippet "( methods -- )" } } } { $description "Applies a quotation to the generic word's methods hashtable, and regenerates the generic word's definition when the quotation returns." } $low-level-note ; -HELP: define-method -{ $values { "quot" quotation } { "class" class } { "generic" generic } } -{ $description "Defines a method. This is the runtime equivalent of " { $link POSTPONE: M: } "." } ; +HELP: create-method +{ $values { "class" class } { "generic" generic } { "method" method-body } } +{ $description "Creates a method or returns an existing one. This is the runtime equivalent of " { $link POSTPONE: M: } "." } +{ $notes "To define a method, pass the output value to " { $link define } "." } ; HELP: implementors { $values { "class" class } { "seq" "a sequence of generic words" } } diff --git a/core/generic/generic-tests.factor b/core/generic/generic-tests.factor index 2dc699f87b..785600cfb0 100755 --- a/core/generic/generic-tests.factor +++ b/core/generic/generic-tests.factor @@ -238,3 +238,31 @@ M: sequence generic-forget-test-2 = ; \ = usage [ word? ] subset [ word-name "generic-forget-test-2/sequence" = ] contains? ] unit-test + +GENERIC: generic-forget-test-3 + +M: f generic-forget-test-3 ; + +[ ] [ \ f \ generic-forget-test-3 method "m" set ] unit-test + +[ ] [ [ "m" get forget ] with-compilation-unit ] unit-test + +[ ] [ "IN: generic.tests M: f generic-forget-test-3 ;" eval ] unit-test + +[ ] [ [ "m" get forget ] with-compilation-unit ] unit-test + +[ f ] [ f generic-forget-test-3 ] unit-test + +: a-word ; + +GENERIC: a-generic + +M: integer a-generic a-word ; + +[ ] [ \ integer \ a-generic method "m" set ] unit-test + +[ t ] [ "m" get \ a-word usage memq? ] unit-test + +[ ] [ "IN: generic.tests : a-generic ;" eval ] unit-test + +[ f ] [ "m" get \ a-word usage memq? ] unit-test diff --git a/core/generic/generic.factor b/core/generic/generic.factor index 3c83b87d49..8fe5e4921a 100755 --- a/core/generic/generic.factor +++ b/core/generic/generic.factor @@ -17,10 +17,6 @@ M: object perform-combination #! the method will throw an error. We don't want that. nip [ "Invalid method combination" throw ] curry [ ] like ; -GENERIC: method-prologue ( class combination -- quot ) - -M: object method-prologue 2drop [ ] ; - GENERIC: make-default-method ( generic combination -- method ) PREDICATE: word generic "combination" word-prop >boolean ; @@ -50,55 +46,49 @@ TUPLE: check-method class generic ; : check-method ( class generic -- class generic ) over class? over generic? and [ \ check-method construct-boa throw - ] unless ; + ] unless ; inline -: with-methods ( word quot -- ) +: with-methods ( generic quot -- ) swap [ "methods" word-prop swap call ] keep make-generic ; inline : method-word-name ( class word -- string ) word-name "/" rot word-name 3append ; -: make-method-def ( quot class generic -- quot ) - "combination" word-prop method-prologue swap append ; - -PREDICATE: word method-body "method-def" word-prop >boolean ; +PREDICATE: word method-body + "method-generic" word-prop >boolean ; M: method-body stack-effect "method-generic" word-prop stack-effect ; -: method-word-props ( quot class generic -- assoc ) +: method-word-props ( class generic -- assoc ) [ "method-generic" set "method-class" set - "method-def" set ] H{ } make-assoc ; -: ( quot class generic -- method ) +: ( class generic -- method ) check-method - [ make-method-def ] 3keep [ method-word-props ] 2keep method-word-name f - tuck set-word-props - dup rot define ; + [ set-word-props ] keep ; -: redefine-method ( quot class generic -- ) - [ method swap "method-def" set-word-prop ] 3keep - [ make-method-def ] 2keep - method swap define ; +: reveal-method ( method class generic -- ) + [ set-at ] with-methods ; -: define-method ( quot class generic -- ) - >r bootstrap-word r> - 2dup method [ - redefine-method +: create-method ( class generic -- method ) + 2dup method dup [ + 2nip ] [ - [ ] 2keep - [ set-at ] with-methods + drop [ dup ] 2keep reveal-method ] if ; +: ( generic combination -- method ) + object bootstrap-word pick + [ -rot make-default-method define ] keep ; + : define-default-method ( generic combination -- ) - dupd make-default-method object bootstrap-word pick - "default-method" set-word-prop ; + dupd "default-method" set-word-prop ; ! Definition protocol M: method-spec where @@ -108,30 +98,31 @@ M: method-spec set-where first2 method set-where ; M: method-spec definer - drop \ M: \ ; ; + first2 method definer ; M: method-spec definition - first2 method dup - [ "method-def" word-prop ] when ; + first2 method definition ; : forget-method ( class generic -- ) - check-method - [ delete-at* ] with-methods - [ forget-word ] [ drop ] if ; + dup generic? [ + [ delete-at* ] with-methods + [ forget-word ] [ drop ] if + ] [ + 2drop + ] if ; M: method-spec forget* - first2 forget-method ; + first2 method forget* ; M: method-body definer drop \ M: \ ; ; -M: method-body definition - "method-def" word-prop ; - M: method-body forget* - dup "method-class" word-prop - swap "method-generic" word-prop - forget-method ; + dup "forgotten" word-prop [ drop ] [ + dup "method-class" word-prop + over "method-generic" word-prop forget-method + t "forgotten" set-word-prop + ] if ; : implementors* ( classes -- words ) all-words [ @@ -163,16 +154,12 @@ M: assoc update-methods ( assoc -- ) make-generic ] if ; -GENERIC: subwords ( word -- seq ) - -M: word subwords drop f ; - M: generic subwords dup "methods" word-prop values swap "default-method" word-prop add ; M: generic forget-word - dup subwords [ forget-word ] each (forget-word) ; + dup subwords [ forget ] each (forget-word) ; : xref-generics ( -- ) all-words [ subwords [ xref ] each ] each ; diff --git a/core/generic/math/math-docs.factor b/core/generic/math/math-docs.factor old mode 100644 new mode 100755 index cbbf070398..5c15e43eb5 --- a/core/generic/math/math-docs.factor +++ b/core/generic/math/math-docs.factor @@ -15,7 +15,7 @@ HELP: no-math-method HELP: math-method { $values { "word" generic } { "class1" class } { "class2" class } { "quot" quotation } } { $description "Generates a definition for " { $snippet "word" } " when the two inputs are instances of " { $snippet "class1" } " and " { $snippet "class2" } ", respectively." } -{ $examples { $example "USING: generic.math math prettyprint ;" "\\ + fixnum float math-method ." "[ [ >float ] dip float+ ]" } } ; +{ $examples { $example "USING: generic.math math prettyprint ;" "\\ + fixnum float math-method ." "[ [ >float ] dip +/float ]" } } ; HELP: math-class { $class-description "The class of subtypes of " { $link number } " which are not " { $link null } "." } ; diff --git a/core/generic/math/math.factor b/core/generic/math/math.factor index 27b0ddb7a2..46f57a1629 100755 --- a/core/generic/math/math.factor +++ b/core/generic/math/math.factor @@ -33,17 +33,14 @@ PREDICATE: class math-class ( object -- ? ) dup empty? [ [ dip ] curry [ ] like ] unless r> append ; -TUPLE: no-math-method left right generic ; - -: no-math-method ( left right generic -- * ) - \ no-math-method construct-boa throw ; +ERROR: no-math-method left right generic ; : default-math-method ( generic -- quot ) [ no-math-method ] curry [ ] like ; : applicable-method ( generic class -- quot ) over method - [ word-def ] + [ 1quotation ] [ default-math-method ] ?if ; : object-method ( generic -- quot ) @@ -53,7 +50,7 @@ TUPLE: no-math-method left right generic ; 2dup and [ 2dup math-upgrade >r math-class-max over order min-class applicable-method - r> swap append + r> prepend ] [ 2drop object-method ] if ; diff --git a/core/generic/standard/standard.factor b/core/generic/standard/standard.factor index 313f487c99..37f72e7d95 100755 --- a/core/generic/standard/standard.factor +++ b/core/generic/standard/standard.factor @@ -8,10 +8,6 @@ IN: generic.standard TUPLE: standard-combination # ; -M: standard-combination method-prologue - standard-combination-# object - swap add* [ declare ] curry ; - C: standard-combination SYMBOL: (dispatch#) @@ -30,10 +26,7 @@ SYMBOL: (dispatch#) : unpicker ( -- quot ) \ (dispatch#) get unpickers nth ; -TUPLE: no-method object generic ; - -: no-method ( object generic -- * ) - \ no-method construct-boa throw ; +ERROR: no-method object generic ; : error-method ( word -- quot ) picker swap [ no-method ] curry append ; @@ -165,7 +158,7 @@ C: hook-combination 0 (dispatch#) [ swap slip hook-combination-var [ get ] curry - swap append + prepend ] with-variable ; inline M: hook-combination make-default-method @@ -174,7 +167,7 @@ M: hook-combination make-default-method M: hook-combination perform-combination [ standard-methods - [ [ drop ] swap append ] assoc-map + [ [ drop ] prepend ] assoc-map single-combination ] with-hook ; diff --git a/core/heaps/heaps-tests.factor b/core/heaps/heaps-tests.factor index 61e09d894e..0b3123c87b 100755 --- a/core/heaps/heaps-tests.factor +++ b/core/heaps/heaps-tests.factor @@ -33,7 +33,7 @@ IN: heaps.tests : random-alist ( n -- alist ) [ [ - (random) dup number>string swap set + 32 random-bits dup number>string swap set ] times ] H{ } make-assoc ; diff --git a/core/inference/class/class-tests.factor b/core/inference/class/class-tests.factor index 17197db667..67b8616c61 100755 --- a/core/inference/class/class-tests.factor +++ b/core/inference/class/class-tests.factor @@ -4,7 +4,7 @@ inference.dataflow optimizer tools.test kernel.private generic sequences words inference.class quotations alien alien.c-types strings sbufs sequences.private slots.private combinators definitions compiler.units -system layouts ; +system layouts vectors ; ! Make sure these compile even though this is invalid code [ ] [ [ 10 mod 3.0 /i ] dataflow optimize drop ] unit-test @@ -294,4 +294,6 @@ cell-bits 32 = [ \ >= inlined? ] unit-test - +[ t ] [ + [ { vector } declare nth-unsafe ] \ nth-unsafe inlined? +] unit-test diff --git a/core/inference/inference-tests.factor b/core/inference/inference-tests.factor index 3c12e388c4..4f5d199264 100755 --- a/core/inference/inference-tests.factor +++ b/core/inference/inference-tests.factor @@ -514,10 +514,10 @@ DEFER: an-inline-word { 0 1 } [ [ 2 ] [ 2 ] [ + ] compose compose call ] must-infer-as -TUPLE: custom-error ; +ERROR: custom-error ; [ T{ effect f 0 0 t } ] [ - [ custom-error construct-boa throw ] infer + [ custom-error ] infer ] unit-test : funny-throw throw ; inline diff --git a/core/inference/known-words/known-words.factor b/core/inference/known-words/known-words.factor index 235c2924bb..08fb56ced7 100755 --- a/core/inference/known-words/known-words.factor +++ b/core/inference/known-words/known-words.factor @@ -354,7 +354,7 @@ M: object infer-call \ setenv { object fixnum } { } set-primitive-effect -\ (stat) { string } { object object object object } set-primitive-effect +\ exists? { string } { object } set-primitive-effect \ (directory) { string } { array } set-primitive-effect diff --git a/core/inference/transforms/transforms.factor b/core/inference/transforms/transforms.factor index 240f39218b..a829bad47e 100755 --- a/core/inference/transforms/transforms.factor +++ b/core/inference/transforms/transforms.factor @@ -64,14 +64,11 @@ M: pair (bitfield-quot) ( spec -- quot ) \ get-slots [ [get-slots] ] 1 define-transform -TUPLE: duplicated-slots-error names ; +ERROR: duplicated-slots-error names ; M: duplicated-slots-error summary drop "Calling set-slots with duplicate slot setters" ; -: duplicated-slots-error ( names -- * ) - \ duplicated-slots-error construct-boa throw ; - \ set-slots [ dup all-unique? [ [get-slots] ] [ duplicated-slots-error ] if diff --git a/core/io/encodings/binary/binary.factor b/core/io/encodings/binary/binary.factor index b8bcc0f87a..5038628ed9 100644 --- a/core/io/encodings/binary/binary.factor +++ b/core/io/encodings/binary/binary.factor @@ -1,3 +1,8 @@ ! Copyright (C) 2008 Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. -IN: io.encodings.binary SYMBOL: binary +USING: io.encodings kernel ; +IN: io.encodings.binary + +TUPLE: binary ; +M: binary drop ; +M: binary drop ; diff --git a/core/io/encodings/encodings-docs.factor b/core/io/encodings/encodings-docs.factor index e5e71b05f0..fd5ddaa82d 100644 --- a/core/io/encodings/encodings-docs.factor +++ b/core/io/encodings/encodings-docs.factor @@ -14,19 +14,19 @@ ARTICLE: "encodings-constructors" "Constructing an encoded stream" { $subsection } { $subsection } ; -HELP: ( stream encoding -- newstream ) +HELP: { $values { "stream" "an output stream" } { "encoding" "an encoding descriptor" } { "newstream" "an encoded output stream" } } { $description "Wraps the given stream in a new stream using the given encoding for all output. The encoding descriptor can either be a class or an instance of something conforming to the " { $link "encodings-protocol" } "." } ; -HELP: ( stream encoding -- newstream ) +HELP: { $values { "stream" "an input stream" } { "encoding" "an encoding descriptor" } { "newstream" "an encoded output stream" } } { $description "Wraps the given stream in a new stream using the given encoding for all input. The encoding descriptor can either be a class or an instance of something conforming to the " { $link "encodings-protocol" } "." } ; -HELP: ( stream-in stream-out encoding -- duplex ) +HELP: { $values { "stream-in" "an input stream" } { "stream-out" "an output stream" } { "encoding" "an encoding descriptor" } @@ -44,25 +44,21 @@ $nl { $vocab-link "io.encodings.utf16" } ; ARTICLE: "encodings-protocol" "Encoding protocol" "An encoding descriptor must implement the following methods. The methods are implemented on tuple classes by instantiating the class and calling the method again." -{ $subsection decode-step } -{ $subsection init-decoder } -{ $subsection stream-write-encoded } ; +{ $subsection decode-char } +{ $subsection encode-char } +"The following methods are optional:" +{ $subsection } +{ $subsection } ; -HELP: decode-step ( buf char encoding -- ) -{ $values { "buf" "A string buffer which characters can be pushed to" } - { "char" "An octet which is read from a stream" } - { "encoding" "An encoding descriptor tuple" } } -{ $description "A single step in the decoding process must be defined for the decoding descriptor. When each octet is read, this word is called, and depending on the decoder's internal state, something may be pushed to the buffer or the state may change. This should not be used directly." } ; +HELP: decode-char +{ $values { "stream" "an underlying input stream" } + { "encoding" "An encoding descriptor tuple" } { "char/f" "a code point or " { $link f } } } +{ $description "Reads a single code point from the underlying stream, interpreting it by the encoding. This should not be used directly." } ; -HELP: stream-write-encoded ( string stream encoding -- ) -{ $values { "string" "a string" } - { "stream" "an output stream" } +HELP: encode-char +{ $values { "char" "a character" } + { "stream" "an underlying output stream" } { "encoding" "an encoding descriptor" } } -{ $description "Encodes the string with the given encoding descriptor, outputing the result to the given stream. This should not be used directly." } ; +{ $description "Writes the code point in the encoding to the underlying stream given. This should not be used directly." } ; -HELP: init-decoder ( stream encoding -- encoding ) -{ $values { "stream" "an input stream" } - { "encoding" "an encoding descriptor" } } -{ $description "Initializes the decoder tuple's state. The stream is exposed so that it can be read, eg for a BOM. This should not be used directly." } ; - -{ init-decoder decode-step stream-write-encoded } related-words +{ encode-char decode-char } related-words diff --git a/core/io/encodings/encodings.factor b/core/io/encodings/encodings.factor index 2f68334bde..a781b63ad5 100755 --- a/core/io/encodings/encodings.factor +++ b/core/io/encodings/encodings.factor @@ -2,62 +2,39 @@ ! See http://factorcode.org/license.txt for BSD license. USING: math kernel sequences sbufs vectors namespaces growable strings io classes continuations combinators -io.styles io.streams.plain io.encodings.binary splitting -io.streams.duplex byte-arrays ; +io.styles io.streams.plain splitting +io.streams.duplex byte-arrays sequences.private ; IN: io.encodings ! The encoding descriptor protocol -GENERIC: decode-step ( buf char encoding -- ) -M: object decode-step drop swap push ; +GENERIC: decode-char ( stream encoding -- char/f ) -GENERIC: init-decoder ( stream encoding -- encoding ) -M: tuple-class init-decoder construct-empty init-decoder ; -M: object init-decoder nip ; +GENERIC: encode-char ( char stream encoding -- ) -GENERIC: stream-write-encoded ( string stream encoding -- byte-array ) -M: object stream-write-encoded drop stream-write ; +GENERIC: ( stream encoding -- newstream ) + +: replacement-char HEX: fffd ; + +TUPLE: decoder stream code cr ; + +ERROR: decode-error ; + +GENERIC: ( stream encoding -- newstream ) + +TUPLE: encoder stream code ; + +ERROR: encode-error ; ! Decoding -TUPLE: decode-error ; + construct-empty ; +M: tuple f decoder construct-boa ; -SYMBOL: begin - -: push-decoded ( buf ch -- buf ch state ) - over push 0 begin ; - -: push-replacement ( buf -- buf ch state ) - ! This is the replacement character - HEX: fffd push-decoded ; - -: space ( resizable -- room-left ) - dup underlying swap [ length ] 2apply - ; - -: full? ( resizable -- ? ) space zero? ; - -: end-read-loop ( buf ch state stream quot -- string/f ) - 2drop 2drop >string f like ; - -: decode-read-loop ( buf stream encoding -- string/f ) - pick full? [ 2drop >string ] [ - over stream-read1 [ - -rot tuck >r >r >r dupd r> decode-step r> r> - decode-read-loop - ] [ 2drop >string f like ] if* - ] if ; - -: decode-read ( length stream encoding -- string ) - rot -rot decode-read-loop ; - -TUPLE: decoder code cr ; -: ( stream encoding -- newstream ) - dup binary eq? [ drop ] [ - dupd init-decoder { set-delegate set-decoder-code } - decoder construct - ] if ; +: >decoder< ( decoder -- stream encoding ) + { decoder-stream decoder-code } get-slots ; : cr+ t swap set-decoder-cr ; inline @@ -82,72 +59,78 @@ TUPLE: decoder code cr ; over decoder-cr [ over cr- "\n" ?head [ - swap stream-read1 [ add ] when* - ] [ nip ] if - ] [ nip ] if ; + over stream-read1 [ add ] when* + ] when + ] when nip ; + +: read-loop ( n stream -- string ) + SBUF" " clone [ + [ + >r nip stream-read1 dup + [ r> push f ] [ r> 2drop t ] if + ] 2curry find-integer drop + ] keep "" like f like ; M: decoder stream-read - tuck { delegate decoder-code } get-slots decode-read fix-read ; + tuck read-loop fix-read ; M: decoder stream-read-partial stream-read ; -: decoder-read-until ( stream delim -- ch ) - ! Copied from { c-reader stream-read-until }!!! - over stream-read1 dup [ - dup pick memq? [ 2nip ] [ , decoder-read-until ] if - ] [ - 2nip - ] if ; +: (read-until) ( buf quot -- string/f sep/f ) + ! quot: -- char stop? + dup call + [ >r drop "" like r> ] + [ pick push (read-until) ] if ; inline M: decoder stream-read-until - ! Copied from { c-reader stream-read-until }!!! - [ swap decoder-read-until ] "" make - swap over empty? over not and [ 2drop f f ] when ; + SBUF" " clone -rot >decoder< + [ decode-char [ dup rot memq? ] [ drop f t ] if* ] 3curry + (read-until) ; : fix-read1 ( stream char -- char ) over decoder-cr [ over cr- dup CHAR: \n = [ - drop stream-read1 - ] [ nip ] if - ] [ nip ] if ; + drop dup stream-read1 + ] when + ] when nip ; M: decoder stream-read1 - 1 swap stream-read f like [ first ] [ f ] if* ; + dup >decoder< decode-char fix-read1 ; M: decoder stream-readln ( stream -- str ) "\r\n" over stream-read-until handle-readln ; +M: decoder dispose decoder-stream dispose ; + ! Encoding +M: tuple-class construct-empty ; +M: tuple encoder construct-boa ; -TUPLE: encode-error ; - -: encode-error ( -- * ) \ encode-error construct-empty throw ; - -TUPLE: encoder code ; -: ( stream encoding -- newstream ) - dup binary eq? [ drop ] [ - construct-empty { set-delegate set-encoder-code } - encoder construct - ] if ; +: >encoder< ( encoder -- stream encoding ) + { encoder-stream encoder-code } get-slots ; M: encoder stream-write1 - >r 1string r> stream-write ; + >encoder< encode-char ; M: encoder stream-write - { delegate encoder-code } get-slots stream-write-encoded ; + >encoder< [ encode-char ] 2curry each ; -M: encoder dispose delegate dispose ; +M: encoder dispose encoder-stream dispose ; + +M: encoder stream-flush encoder-stream stream-flush ; INSTANCE: encoder plain-writer ! Rebinding duplex streams which have not read anything yet : reencode ( stream encoding -- newstream ) - over encoder? [ >r delegate r> ] when ; + over encoder? [ >r encoder-stream r> ] when ; : redecode ( stream encoding -- newstream ) - over decoder? [ >r delegate r> ] when ; + over decoder? [ >r decoder-stream r> ] when ; + +PRIVATE> : ( stream-in stream-out encoding -- duplex ) tuck reencode >r redecode r> ; diff --git a/core/io/encodings/utf8/utf8.factor b/core/io/encodings/utf8/utf8.factor index 5887a8375e..e98860f25d 100644 --- a/core/io/encodings/utf8/utf8.factor +++ b/core/io/encodings/utf8/utf8.factor @@ -6,82 +6,68 @@ IN: io.encodings.utf8 ! Decoding UTF-8 -TUPLE: utf8 ch state ; +TUPLE: utf8 ; -SYMBOL: double -SYMBOL: triple -SYMBOL: triple2 -SYMBOL: quad -SYMBOL: quad2 -SYMBOL: quad3 +r over starts-2? - [ 6 shift swap BIN: 111111 bitand bitor r> ] - [ r> 3drop push-replacement ] if ; +: append-nums ( stream byte -- stream char ) + over stream-read1 dup starts-2? + [ swap 6 shift swap BIN: 111111 bitand bitor ] + [ 2drop replacement-char ] if ; -: begin-utf8 ( buf byte -- buf ch state ) +: double ( stream byte -- stream char ) + BIN: 11111 bitand append-nums ; + +: triple ( stream byte -- stream char ) + BIN: 1111 bitand append-nums append-nums ; + +: quad ( stream byte -- stream char ) + BIN: 111 bitand append-nums append-nums append-nums ; + +: begin-utf8 ( stream byte -- stream char ) { - { [ dup -7 shift zero? ] [ push-decoded ] } - { [ dup -5 shift BIN: 110 number= ] [ BIN: 11111 bitand double ] } - { [ dup -4 shift BIN: 1110 number= ] [ BIN: 1111 bitand triple ] } - { [ dup -3 shift BIN: 11110 number= ] [ BIN: 111 bitand quad ] } - { [ t ] [ drop push-replacement ] } + { [ dup -7 shift zero? ] [ ] } + { [ dup -5 shift BIN: 110 number= ] [ double ] } + { [ dup -4 shift BIN: 1110 number= ] [ triple ] } + { [ dup -3 shift BIN: 11110 number= ] [ quad ] } + { [ t ] [ drop replacement-char ] } } cond ; -: end-multibyte ( buf byte ch -- buf ch state ) - f append-nums [ push-decoded ] unless* ; +: decode-utf8 ( stream -- char/f ) + dup stream-read1 dup [ begin-utf8 ] when nip ; -: decode-utf8-step ( buf byte ch state -- buf ch state ) - { - { begin [ drop begin-utf8 ] } - { double [ end-multibyte ] } - { triple [ triple2 append-nums ] } - { triple2 [ end-multibyte ] } - { quad [ quad2 append-nums ] } - { quad2 [ quad3 append-nums ] } - { quad3 [ end-multibyte ] } - } case ; - -: unpack-state ( encoding -- ch state ) - { utf8-ch utf8-state } get-slots ; - -: pack-state ( ch state encoding -- ) - { set-utf8-ch set-utf8-state } set-slots ; - -M: utf8 decode-step ( buf char encoding -- ) - [ unpack-state decode-utf8-step ] keep pack-state drop ; - -M: utf8 init-decoder nip begin over set-utf8-state ; +M: utf8 decode-char + drop decode-utf8 ; ! Encoding UTF-8 -: encoded ( char -- ) - BIN: 111111 bitand BIN: 10000000 bitor write1 ; +: encoded ( stream char -- ) + BIN: 111111 bitand BIN: 10000000 bitor swap stream-write1 ; -: char>utf8 ( char -- ) +: char>utf8 ( stream char -- ) { - { [ dup -7 shift zero? ] [ write1 ] } + { [ dup -7 shift zero? ] [ swap stream-write1 ] } { [ dup -11 shift zero? ] [ - dup -6 shift BIN: 11000000 bitor write1 + 2dup -6 shift BIN: 11000000 bitor swap stream-write1 encoded ] } { [ dup -16 shift zero? ] [ - dup -12 shift BIN: 11100000 bitor write1 - dup -6 shift encoded + 2dup -12 shift BIN: 11100000 bitor swap stream-write1 + 2dup -6 shift encoded encoded ] } { [ t ] [ - dup -18 shift BIN: 11110000 bitor write1 - dup -12 shift encoded - dup -6 shift encoded + 2dup -18 shift BIN: 11110000 bitor swap stream-write1 + 2dup -12 shift encoded + 2dup -6 shift encoded encoded ] } } cond ; -M: utf8 stream-write-encoded - ! For efficiency, this should be modified to avoid variable reads - drop [ [ char>utf8 ] each ] with-stream* ; +M: utf8 encode-char + drop swap char>utf8 ; + +PRIVATE> diff --git a/core/io/files/files-docs.factor b/core/io/files/files-docs.factor index df9c78fe47..1a3bde0e5c 100755 --- a/core/io/files/files-docs.factor +++ b/core/io/files/files-docs.factor @@ -19,7 +19,7 @@ ARTICLE: "pathnames" "Pathname manipulation" { $subsection parent-directory } { $subsection file-name } { $subsection last-path-separator } -{ $subsection path+ } +{ $subsection append-path } "Pathnames relative to Factor's install directory:" { $subsection resource-path } { $subsection ?resource-path } @@ -54,9 +54,7 @@ ARTICLE: "fs-meta" "File meta-data" { $subsection file-info } { $subsection link-info } { $subsection exists? } -{ $subsection directory? } -! { $subsection file-modified } -{ $subsection stat } ; +{ $subsection directory? } ; ARTICLE: "delete-move-copy" "Deleting, moving, copying files" "Operations for deleting and copying files come in two forms:" @@ -216,15 +214,7 @@ HELP: with-directory { $description "Changes the current working directory for the duration of a quotation's execution." } { $errors "Windows CE has no concept of ``current directory'', so this word throws an error there." } ; -HELP: stat ( path -- directory? permissions length modified ) -{ $values { "path" "a pathname string" } { "directory?" "boolean indicating if the file is a directory" } { "permissions" "a Unix permission bitmap (0 on Windows)" } { "length" "the length in bytes as an integer" } { "modified" "the last modification time, as milliseconds since midnight, January 1st 1970 GMT" } } -{ $description - "Queries the file system for file meta data. If the file does not exist, outputs " { $link f } " for all four values." -} ; - -{ stat exists? directory? } related-words - -HELP: path+ +HELP: append-path { $values { "str1" "a string" } { "str2" "a string" } { "str" "a string" } } { $description "Concatenates two pathnames." } ; @@ -273,7 +263,7 @@ HELP: normalize-directory HELP: normalize-pathname { $values { "str" "a pathname string" } { "newstr" "a new pathname string" } } -{ $description "Called by the " { $link stat } " word, and possibly " { $link } " and " { $link } ", to prepare a pathname before passing it to underlying code." } ; +{ $description "Called by words such as " { $link } " and " { $link } " to prepare a pathname before passing it to underlying code." } ; HELP: ( str -- pathname ) { $values { "str" "a pathname string" } { "pathname" pathname } } diff --git a/core/io/files/files-tests.factor b/core/io/files/files-tests.factor index e2eeef6528..4cda463983 100755 --- a/core/io/files/files-tests.factor +++ b/core/io/files/files-tests.factor @@ -1,5 +1,10 @@ IN: io.files.tests -USING: tools.test io.files io threads kernel continuations io.encodings.ascii ; +USING: tools.test io.files io threads kernel continuations io.encodings.ascii +io.files.unique sequences strings accessors ; + +[ ] [ "blahblah" temp-file dup exists? [ delete-directory ] [ drop ] if ] unit-test +[ ] [ "blahblah" temp-file make-directory ] unit-test +[ t ] [ "blahblah" temp-file directory? ] unit-test [ "passwd" ] [ "/etc/passwd" file-name ] unit-test [ "awk" ] [ "/usr/libexec/awk/" file-name ] unit-test @@ -123,3 +128,19 @@ USING: tools.test io.files io threads kernel continuations io.encodings.ascii ; [ ] [ "copy-tree-test" temp-file delete-tree ] unit-test [ t ] [ cwd "misc" resource-path [ ] with-directory cwd = ] unit-test + +[ ] [ "append-test" temp-file dup exists? [ delete-file ] [ drop ] if ] unit-test + +[ ] [ "append-test" temp-file ascii dispose ] unit-test + + + +[ 123 ] [ + "core" ".test" [ + [ + ascii [ + 123 CHAR: a >string write + ] with-file-writer + ] keep file-info size>> + ] with-unique-file +] unit-test diff --git a/core/io/files/files.factor b/core/io/files/files.factor index 3ab489739b..21cc7c8f0a 100755 --- a/core/io/files/files.factor +++ b/core/io/files/files.factor @@ -32,10 +32,13 @@ HOOK: rename-file io-backend ( from to -- ) : left-trim-separators ( str -- newstr ) [ path-separator? ] left-trim ; -: path+ ( str1 str2 -- str ) +: append-path ( str1 str2 -- str ) >r right-trim-separators "/" r> left-trim-separators 3append ; +: prepend-path ( str1 str2 -- str ) + swap append-path ; inline + : last-path-separator ( path -- n ? ) [ length 1- ] keep [ path-separator? ] find-last* ; @@ -45,10 +48,7 @@ M: object root-directory? ( path -- ? ) path-separator? ; : special-directory? ( name -- ? ) { "." ".." } member? ; -TUPLE: no-parent-directory path ; - -: no-parent-directory ( path -- * ) - \ no-parent-directory construct-boa throw ; +ERROR: no-parent-directory path ; : parent-directory ( path -- parent ) right-trim-separators { @@ -83,18 +83,11 @@ SYMBOL: +socket+ SYMBOL: +unknown+ ! File metadata -: stat ( path -- directory? permissions length modified ) - normalize-pathname (stat) ; +: exists? ( path -- ? ) + normalize-pathname (exists?) ; -! : file-length ( path -- n ) stat drop 2nip ; - -: file-modified ( path -- n ) stat >r 3drop r> ; - -! : file-permissions ( path -- perm ) stat 2drop nip ; - -: exists? ( path -- ? ) file-modified >boolean ; - -: directory? ( path -- ? ) stat 3drop ; +: directory? ( path -- ? ) + file-info file-info-type +directory+ = ; ! Current working directory HOOK: cd io-backend ( path -- ) @@ -123,7 +116,7 @@ HOOK: make-directory io-backend ( path -- ) : fixup-directory ( path seq -- newseq ) [ dup string? - [ tuck path+ directory? 2array ] [ nip ] if + [ tuck append-path directory? 2array ] [ nip ] if ] with map [ first special-directory? not ] subset ; @@ -131,7 +124,7 @@ HOOK: make-directory io-backend ( path -- ) normalize-directory dup (directory) fixup-directory ; : directory* ( path -- seq ) - dup directory [ first2 >r path+ r> 2array ] with map ; + dup directory [ first2 >r append-path r> 2array ] with map ; ! Touching files HOOK: touch-file io-backend ( path -- ) @@ -150,7 +143,7 @@ HOOK: delete-directory io-backend ( path -- ) : delete-tree ( path -- ) dup directory? (delete-tree) ; -: to-directory over file-name path+ ; +: to-directory over file-name append-path ; ! Moving and renaming files HOOK: move-file io-backend ( from to -- ) @@ -183,7 +176,7 @@ DEFER: copy-tree-into : copy-tree ( from to -- ) over directory? [ >r dup directory swap r> [ - >r swap first path+ r> copy-tree-into + >r swap first append-path r> copy-tree-into ] 2curry each ] [ copy-file @@ -197,8 +190,8 @@ DEFER: copy-tree-into ! Special paths : resource-path ( path -- newpath ) - \ resource-path get [ image parent-directory ] unless* - swap path+ ; + "resource-path" get [ image parent-directory ] unless* + prepend-path ; : ?resource-path ( path -- newpath ) "resource:" ?head [ resource-path ] when ; @@ -220,10 +213,7 @@ M: pathname <=> [ pathname-string ] compare ; >r r> with-stream ; inline : file-contents ( path encoding -- str ) - dupd [ file-info file-info-size read ] with-file-reader ; - -! : file-contents ( path encoding -- str ) -! dupd [ file-length read ] with-file-reader ; + contents ; : with-file-writer ( path encoding quot -- ) >r r> with-stream ; inline @@ -243,7 +233,7 @@ M: pathname <=> [ pathname-string ] compare ; [ dup make-directory ] when ; -: temp-file ( name -- path ) temp-directory swap path+ ; +: temp-file ( name -- path ) temp-directory prepend-path ; ! Home directory : home ( -- dir ) diff --git a/core/io/io-tests.factor b/core/io/io-tests.factor index 22c942d2d9..8a9089a564 100755 --- a/core/io/io-tests.factor +++ b/core/io/io-tests.factor @@ -28,15 +28,6 @@ IN: io.tests ! Make sure we use correct to_c_string form when writing [ ] [ "\0" write ] unit-test -[ "" ] [ 0 read ] unit-test - -! [ ] [ "123" write 9000 CHAR: x write flush ] unit-test - -[ - "/core/io/test/binary.txt" - [ 0.2 read ] with-stream -] must-fail - [ { { "It seems " CHAR: J } @@ -58,3 +49,12 @@ IN: io.tests 10 [ 65536 read drop ] times ] with-file-reader ] unit-test + +! [ "" ] [ 0 read ] unit-test + +! [ ] [ "123" write 9000 CHAR: x write flush ] unit-test + +! [ +! "/core/io/test/binary.txt" +! [ 0.2 read ] with-stream +! ] must-fail diff --git a/core/io/io.factor b/core/io/io.factor index 2d927d088a..ef9eae7902 100755 --- a/core/io/io.factor +++ b/core/io/io.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2003, 2007 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: hashtables generic kernel math namespaces sequences strings - continuations assocs io.styles sbufs ; +USING: hashtables generic kernel math namespaces sequences +continuations assocs io.styles ; IN: io GENERIC: stream-readln ( stream -- str ) @@ -88,4 +88,6 @@ SYMBOL: stderr [ [ readln dup ] [ ] [ drop ] unfold ] with-stream ; : contents ( stream -- str ) - 2048 [ stream-copy ] keep >string ; + [ + [ 65536 read dup ] [ ] [ drop ] unfold concat f like + ] with-stream ; diff --git a/core/io/streams/byte-array/byte-array.factor b/core/io/streams/byte-array/byte-array.factor index d5ca8eac68..2a8441ff23 100644 --- a/core/io/streams/byte-array/byte-array.factor +++ b/core/io/streams/byte-array/byte-array.factor @@ -1,5 +1,5 @@ USING: byte-arrays byte-vectors kernel io.encodings io.streams.string -sequences io namespaces ; +sequences io namespaces io.encodings.private ; IN: io.streams.byte-array : ( encoding -- stream ) @@ -7,7 +7,7 @@ IN: io.streams.byte-array : with-byte-writer ( encoding quot -- byte-array ) >r r> [ stdio get ] compose with-stream* - >byte-array ; inline + dup encoder? [ encoder-stream ] when >byte-array ; inline : ( byte-array encoding -- stream ) >r >byte-vector dup reverse-here r> ; diff --git a/core/io/streams/c/c-docs.factor b/core/io/streams/c/c-docs.factor old mode 100644 new mode 100755 index 5d9c7b1a53..6c640bbdeb --- a/core/io/streams/c/c-docs.factor +++ b/core/io/streams/c/c-docs.factor @@ -1,5 +1,5 @@ USING: help.markup help.syntax io io.files threads -strings byte-arrays io.streams.lines io.streams.plain ; +strings byte-arrays io.streams.plain ; IN: io.streams.c ARTICLE: "io.streams.c" "ANSI C streams" diff --git a/core/io/streams/duplex/duplex.factor b/core/io/streams/duplex/duplex.factor index 97e60b4a60..83e991b713 100755 --- a/core/io/streams/duplex/duplex.factor +++ b/core/io/streams/duplex/duplex.factor @@ -11,11 +11,10 @@ TUPLE: duplex-stream in out closed? ; : ( in out -- stream ) f duplex-stream construct-boa ; -TUPLE: check-closed ; +ERROR: stream-closed-twice ; : check-closed ( stream -- ) - duplex-stream-closed? - [ \ check-closed construct-boa throw ] when ; + duplex-stream-closed? [ stream-closed-twice ] when ; : duplex-stream-in+ ( duplex -- stream ) dup check-closed duplex-stream-in ; diff --git a/core/io/streams/string/string.factor b/core/io/streams/string/string.factor index 7833e0aa47..b7ff37a971 100755 --- a/core/io/streams/string/string.factor +++ b/core/io/streams/string/string.factor @@ -1,9 +1,9 @@ ! Copyright (C) 2003, 2007 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -IN: io.streams.string USING: io kernel math namespaces sequences sbufs strings generic splitting growable continuations io.streams.plain -io.encodings ; +io.encodings io.encodings.private ; +IN: io.streams.string M: growable dispose drop ; @@ -49,8 +49,11 @@ M: growable stream-read M: growable stream-read-partial stream-read ; +TUPLE: null ; +M: null decode-char drop stream-read1 ; + : ( str -- stream ) - >sbuf dup reverse-here f ; + >sbuf dup reverse-here null ; : with-string-reader ( str quot -- ) >r r> with-stream ; inline diff --git a/core/kernel/kernel-docs.factor b/core/kernel/kernel-docs.factor index 8e107975bb..0babb14fa7 100755 --- a/core/kernel/kernel-docs.factor +++ b/core/kernel/kernel-docs.factor @@ -429,7 +429,14 @@ $nl { $code "[ X ] [ Y ] ?if" "dup [ nip X ] [ drop Y ] if" } } ; HELP: die -{ $description "Starts the front-end processor (FEP), which is a low-level debugger which can inspect memory addresses and the like. The FEP is also entered when a critical error occurs." } ; +{ $description "Starts the front-end processor (FEP), which is a low-level debugger which can inspect memory addresses and the like. The FEP is also entered when a critical error occurs." } +{ $notes + "The term FEP originates from the Lisp machines of old. According to the Jargon File," + $nl + { $strong "fepped out" } " /fept owt/ " { $emphasis "adj." } " The Symbolics 3600 LISP Machine has a Front-End Processor called a `FEP' (compare sense 2 of box). When the main processor gets wedged, the FEP takes control of the keyboard and screen. Such a machine is said to have `fepped out' or `dropped into the fep'." + $nl + { $url "http://www.jargon.net/jargonfile/f/feppedout.html" } +} ; HELP: (clone) ( obj -- newobj ) { $values { "obj" object } { "newobj" "a shallow copy" } } diff --git a/core/libc/libc.factor b/core/libc/libc.factor index e82b244d6d..756d29e551 100755 --- a/core/libc/libc.factor +++ b/core/libc/libc.factor @@ -23,20 +23,14 @@ SYMBOL: mallocs PRIVATE> -TUPLE: check-ptr ; +ERROR: bad-ptr ; : check-ptr ( c-ptr -- c-ptr ) - [ \ check-ptr construct-boa throw ] unless* ; + [ bad-ptr ] unless* ; -TUPLE: double-free ; +ERROR: double-free ; -: double-free ( -- * ) - \ double-free construct-empty throw ; - -TUPLE: realloc-error ptr size ; - -: realloc-error ( alien size -- * ) - \ realloc-error construct-boa throw ; +ERROR: realloc-error ptr size ; } -"A view of a sequence as an associative structure:" +"An enum provides such a view of a sequence:" { $subsection enum } { $subsection } "Utility word used by developer tools which inspect objects:" -{ $subsection make-mirror } ; +{ $subsection make-mirror } +{ $see-also "slots" } ; ABOUT: "mirrors" diff --git a/core/optimizer/specializers/specializers.factor b/core/optimizer/specializers/specializers.factor index 10a9fda3ea..560a174289 100755 --- a/core/optimizer/specializers/specializers.factor +++ b/core/optimizer/specializers/specializers.factor @@ -24,20 +24,40 @@ IN: optimizer.specializers \ dispatch , ] [ ] make ; -: specializer-methods ( quot word -- default alist ) +: specializer-cases ( quot word -- default alist ) dup [ array? ] all? [ 1array ] unless [ [ make-specializer ] keep [ declare ] curry pick append ] { } map>assoc ; +: method-declaration ( method -- quot ) + dup "method-generic" word-prop dispatch# object + swap "method-class" word-prop add* ; + +: specialize-method ( quot method -- quot' ) + method-declaration [ declare ] curry prepend ; + +: specialize-quot ( quot specializer -- quot' ) + dup { number } = [ + drop tag-specializer + ] [ + specializer-cases alist>quot + ] if ; + +: standard-method? ( method -- ? ) + dup method-body? [ + "method-generic" word-prop standard-generic? + ] [ drop f ] if ; + : specialized-def ( word -- quot ) - dup word-def swap "specializer" word-prop [ - dup { number } = [ - drop tag-specializer - ] [ - specializer-methods alist>quot - ] if - ] when* ; + dup word-def swap { + { [ dup standard-method? ] [ specialize-method ] } + { + [ dup "specializer" word-prop ] + [ "specializer" word-prop specialize-quot ] + } + { [ t ] [ drop ] } + } cond ; : specialized-length ( specializer -- n ) dup [ array? ] all? [ first ] when length ; diff --git a/core/parser/parser-docs.factor b/core/parser/parser-docs.factor index 48f929b836..4d200c17d2 100755 --- a/core/parser/parser-docs.factor +++ b/core/parser/parser-docs.factor @@ -224,7 +224,7 @@ HELP: skip { $values { "i" "a starting index" } { "seq" sequence } { "?" "a boolean" } { "n" integer } } { $description "Skips to the first space character (if " { $snippet "boolean" } " is " { $link f } ") or the first non-space character (otherwise)." } ; -HELP: change-column +HELP: change-lexer-column { $values { "lexer" lexer } { "quot" "a quotation with stack effect " { $snippet "( col line -- newcol )" } } } { $description "Applies a quotation to the current column and line text to produce a new column, and moves the lexer position." } ; diff --git a/core/parser/parser-tests.factor b/core/parser/parser-tests.factor index a69e28ab97..f024eda54c 100755 --- a/core/parser/parser-tests.factor +++ b/core/parser/parser-tests.factor @@ -1,7 +1,7 @@ USING: arrays math parser tools.test kernel generic words io.streams.string namespaces classes effects source-files assocs sequences strings io.files definitions continuations -sorting tuples compiler.units debugger ; +sorting tuples compiler.units debugger vocabs vocabs.loader ; IN: parser.tests [ @@ -397,35 +397,47 @@ IN: parser.tests ] unit-test [ ] [ - "IN: parser.tests TUPLE: foo ; GENERIC: foo" - "redefining-a-class-5" parse-stream drop + [ + "redefining-a-class-5" forget-source + "redefining-a-class-6" forget-source + "redefining-a-class-7" forget-source + ] with-compilation-unit ] unit-test -[ ] [ - "IN: parser.tests M: f foo ;" - "redefining-a-class-6" parse-stream drop -] unit-test +2 [ + [ ] [ + "IN: parser.tests TUPLE: foo ; GENERIC: foo" + "redefining-a-class-5" parse-stream drop + ] unit-test -[ f ] [ f "foo" "parser.tests" lookup execute ] unit-test + [ ] [ + "IN: parser.tests M: f foo ;" + "redefining-a-class-6" parse-stream drop + ] unit-test -[ ] [ - "IN: parser.tests TUPLE: foo ; GENERIC: foo" - "redefining-a-class-5" parse-stream drop -] unit-test + [ f ] [ f "foo" "parser.tests" lookup execute ] unit-test -[ f ] [ f "foo" "parser.tests" lookup execute ] unit-test + [ ] [ + "IN: parser.tests TUPLE: foo ; GENERIC: foo" + "redefining-a-class-5" parse-stream drop + ] unit-test -[ ] [ - "IN: parser.tests TUPLE: foo ; GENERIC: foo" + [ f ] [ f "foo" "parser.tests" lookup execute ] unit-test + + [ ] [ + "IN: parser.tests TUPLE: foo ; GENERIC: foo" "redefining-a-class-7" parse-stream drop -] unit-test + ] unit-test -[ ] [ - "IN: parser.tests TUPLE: foo ;" - "redefining-a-class-7" parse-stream drop -] unit-test + [ f ] [ f "foo" "parser.tests" lookup execute ] unit-test -[ t ] [ "foo" "parser.tests" lookup symbol? ] unit-test + [ ] [ + "IN: parser.tests TUPLE: foo ;" + "redefining-a-class-7" parse-stream drop + ] unit-test + + [ t ] [ "foo" "parser.tests" lookup symbol? ] unit-test +] times [ "resource:core/parser/test/assert-depth.factor" run-file ] [ relative-overflow-stack { 1 2 3 } sequence= ] @@ -447,3 +459,13 @@ must-fail-with "d-f-s-test" parse-stream drop ] unit-test ] times + +[ ] [ "parser" reload ] unit-test + +[ ] [ + [ "this-better-not-exist" forget-vocab ] with-compilation-unit +] unit-test + +[ + "USE: this-better-not-exist" eval +] must-fail diff --git a/core/parser/parser.factor b/core/parser/parser.factor index 50f8f582d3..28822db708 100755 --- a/core/parser/parser.factor +++ b/core/parser/parser.factor @@ -60,7 +60,7 @@ t parser-notes set-global [ swap CHAR: \s eq? xor ] curry find* drop [ r> drop ] [ r> length ] if* ; -: change-column ( lexer quot -- ) +: change-lexer-column ( lexer quot -- ) swap [ dup lexer-column swap lexer-line-text rot call ] keep set-lexer-column ; inline @@ -68,14 +68,14 @@ t parser-notes set-global GENERIC: skip-blank ( lexer -- ) M: lexer skip-blank ( lexer -- ) - [ t skip ] change-column ; + [ t skip ] change-lexer-column ; GENERIC: skip-word ( lexer -- ) M: lexer skip-word ( lexer -- ) [ 2dup nth CHAR: " eq? [ drop 1+ ] [ f skip ] if - ] change-column ; + ] change-lexer-column ; : still-parsing? ( lexer -- ? ) dup lexer-line swap lexer-text length <= ; @@ -98,10 +98,7 @@ M: lexer skip-word ( lexer -- ) : scan ( -- str/f ) lexer get parse-token ; -TUPLE: bad-escape ; - -: bad-escape ( -- * ) - \ bad-escape construct-empty throw ; +ERROR: bad-escape ; M: bad-escape summary drop "Bad escape code" ; @@ -156,7 +153,7 @@ name>char-hook global [ : parse-string ( -- str ) lexer get [ [ swap tail-slice (parse-string) ] "" make swap - ] change-column ; + ] change-lexer-column ; TUPLE: parse-error file line col text ; @@ -215,13 +212,7 @@ SYMBOL: in : set-in ( name -- ) check-vocab-string dup in set create-vocab (use+) ; -: create-in ( string -- word ) - in get create dup set-word dup save-location ; - -TUPLE: unexpected want got ; - -: unexpected ( want got -- * ) - \ unexpected construct-boa throw ; +ERROR: unexpected want got ; PREDICATE: unexpected unexpected-eof unexpected-got not ; @@ -238,8 +229,15 @@ PREDICATE: unexpected unexpected-eof : parse-tokens ( end -- seq ) 100 swap (parse-tokens) >array ; +: create-in ( string -- word ) + in get create dup set-word dup save-location ; + : CREATE ( -- word ) scan create-in ; +: CREATE-GENERIC ( -- word ) CREATE dup reset-word ; + +: CREATE-WORD ( -- word ) CREATE dup reset-generic ; + : create-class-in ( word -- word ) in get create dup save-class-location @@ -284,10 +282,13 @@ M: no-word summary ] ?if ] when ; -TUPLE: staging-violation word ; +: create-method-in ( class generic -- method ) + create-method f set-word dup save-location ; -: staging-violation ( word -- * ) - \ staging-violation construct-boa throw ; +: CREATE-METHOD ( -- method ) + scan-word bootstrap-word scan-word create-method-in ; + +ERROR: staging-violation word ; M: staging-violation summary drop @@ -342,9 +343,7 @@ SYMBOL: lexer-factory ] if ] if ; -TUPLE: bad-number ; - -: bad-number ( -- * ) \ bad-number construct-boa throw ; +ERROR: bad-number ; : parse-base ( parsed base -- parsed ) scan swap base> [ bad-number ] unless* parsed ; @@ -355,7 +354,9 @@ TUPLE: bad-number ; : parse-definition ( -- quot ) \ ; parse-until >quotation ; -: (:) CREATE dup reset-generic parse-definition ; +: (:) CREATE-WORD parse-definition ; + +: (M:) CREATE-METHOD parse-definition ; GENERIC: expected>string ( obj -- str ) @@ -466,7 +467,15 @@ SYMBOL: interactive-vocabs : smudged-usage ( -- usages referenced removed ) removed-definitions filter-moved keys [ outside-usages - [ empty? swap pathname? or not ] assoc-subset + [ + empty? [ drop f ] [ + { + { [ dup pathname? ] [ f ] } + { [ dup method-body? ] [ f ] } + { [ t ] [ t ] } + } cond nip + ] if + ] assoc-subset dup values concat prune swap keys ] keep ; diff --git a/core/prettyprint/prettyprint-tests.factor b/core/prettyprint/prettyprint-tests.factor index 20130d7f7e..8df97effb6 100755 --- a/core/prettyprint/prettyprint-tests.factor +++ b/core/prettyprint/prettyprint-tests.factor @@ -317,3 +317,15 @@ unit-test [ ] [ 1 \ + curry unparse drop ] unit-test [ ] [ 1 \ + compose unparse drop ] unit-test + +GENERIC: generic-see-test-with-f ( obj -- obj ) + +M: f generic-see-test-with-f ; + +[ "USING: prettyprint.tests ;\nM: f generic-see-test-with-f ;\n" ] [ + [ { POSTPONE: f generic-see-test-with-f } see ] with-string-writer +] unit-test + +[ "USING: prettyprint.tests ;\nM: f generic-see-test-with-f ;\n" ] [ + [ \ f \ generic-see-test-with-f method see ] with-string-writer +] unit-test diff --git a/core/prettyprint/prettyprint.factor b/core/prettyprint/prettyprint.factor index 6cb03e4199..8bce81650f 100755 --- a/core/prettyprint/prettyprint.factor +++ b/core/prettyprint/prettyprint.factor @@ -172,13 +172,13 @@ M: hook-generic synopsis* stack-effect. ; M: method-spec synopsis* - dup definer. [ pprint-word ] each ; + first2 method synopsis* ; M: method-body synopsis* dup dup definer. - "method-class" word-prop pprint* - "method-generic" word-prop pprint* ; + "method-class" word-prop pprint-word + "method-generic" word-prop pprint-word ; M: mixin-instance synopsis* dup definer. diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index 9fc5264440..14674ba2f2 100755 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -41,19 +41,14 @@ M: sequence lengthen 2dup length > [ set-length ] [ 2drop ] if ; : bounds-check? ( n seq -- ? ) length 1- 0 swap between? ; inline -TUPLE: bounds-error index seq ; - -: bounds-error ( n seq -- * ) - \ bounds-error construct-boa throw ; +ERROR: bounds-error index seq ; : bounds-check ( n seq -- n seq ) 2dup bounds-check? [ bounds-error ] unless ; inline MIXIN: immutable-sequence -TUPLE: immutable seq ; - -: immutable ( seq -- * ) \ immutable construct-boa throw ; +ERROR: immutable seq ; M: immutable-sequence set-nth immutable ; @@ -190,8 +185,7 @@ TUPLE: slice from to seq ; : collapse-slice ( m n slice -- m' n' seq ) dup slice-from swap slice-seq >r tuck + >r + r> r> ; inline -TUPLE: slice-error reason ; -: slice-error ( str -- * ) \ slice-error construct-boa throw ; +ERROR: slice-error reason ; : check-slice ( from to seq -- from to seq ) pick 0 < [ "start < 0" slice-error ] when @@ -299,6 +293,8 @@ M: immutable-sequence clone-like like ; : append ( seq1 seq2 -- newseq ) over (append) ; +: prepend ( seq1 seq2 -- newseq ) swap append ; inline + : 3append ( seq1 seq2 seq3 -- newseq ) pick (3append) ; : change-nth ( i seq quot -- ) diff --git a/core/slots/deprecated/deprecated.factor b/core/slots/deprecated/deprecated.factor new file mode 100755 index 0000000000..cc93aeeff2 --- /dev/null +++ b/core/slots/deprecated/deprecated.factor @@ -0,0 +1,95 @@ +! Copyright (C) 2005, 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: arrays kernel kernel.private math namespaces +sequences strings words effects generic generic.standard +classes slots.private combinators slots ; +IN: slots.deprecated + +: reader-effect ( class spec -- effect ) + >r ?word-name 1array r> slot-spec-name 1array ; + +PREDICATE: word slot-reader "reading" word-prop >boolean ; + +: set-reader-props ( class spec -- ) + 2dup reader-effect + over slot-spec-reader + swap "declared-effect" set-word-prop + slot-spec-reader swap "reading" set-word-prop ; + +: define-reader ( class spec -- ) + dup slot-spec-reader [ + [ set-reader-props ] 2keep + dup slot-spec-offset + over slot-spec-reader + rot slot-spec-type reader-quot + define-slot-word + ] [ + 2drop + ] if ; + +: writer-effect ( class spec -- effect ) + slot-spec-name swap ?word-name 2array 0 ; + +PREDICATE: word slot-writer "writing" word-prop >boolean ; + +: set-writer-props ( class spec -- ) + 2dup writer-effect + over slot-spec-writer + swap "declared-effect" set-word-prop + slot-spec-writer swap "writing" set-word-prop ; + +: define-writer ( class spec -- ) + dup slot-spec-writer [ + [ set-writer-props ] 2keep + dup slot-spec-offset + swap slot-spec-writer + [ set-slot ] + define-slot-word + ] [ + 2drop + ] if ; + +: define-slot ( class spec -- ) + 2dup define-reader define-writer ; + +: define-slots ( class specs -- ) + [ define-slot ] with each ; + +: reader-word ( class name vocab -- word ) + >r >r "-" r> 3append r> create ; + +: writer-word ( class name vocab -- word ) + >r [ swap "set-" % % "-" % % ] "" make r> create ; + +: (simple-slot-word) ( class name -- class name vocab ) + over word-vocabulary >r >r word-name r> r> ; + +: simple-reader-word ( class name -- word ) + (simple-slot-word) reader-word ; + +: simple-writer-word ( class name -- word ) + (simple-slot-word) writer-word ; + +: short-slot ( class name # -- spec ) + >r object bootstrap-word over r> f f + 2over simple-reader-word over set-slot-spec-reader + -rot simple-writer-word over set-slot-spec-writer ; + +: long-slot ( spec # -- spec ) + >r [ dup array? [ first2 create ] when ] map first4 r> + -rot ; + +: simple-slots ( class slots base -- specs ) + over length [ + ] with map [ + { + { [ over not ] [ 2drop f ] } + { [ over string? ] [ >r dupd r> short-slot ] } + { [ over array? ] [ long-slot ] } + } cond + ] 2map [ ] subset nip ; + +: slot-of-reader ( reader specs -- spec/f ) + [ slot-spec-reader eq? ] with find nip ; + +: slot-of-writer ( writer specs -- spec/f ) + [ slot-spec-writer eq? ] with find nip ; diff --git a/core/slots/slots-docs.factor b/core/slots/slots-docs.factor old mode 100644 new mode 100755 index d57c4053e6..e4bb307829 --- a/core/slots/slots-docs.factor +++ b/core/slots/slots-docs.factor @@ -4,25 +4,86 @@ effects generic.standard tuples slots.private classes strings math ; IN: slots +ARTICLE: "accessors" "Slot accessors" +"For each tuple slot, methods are defined on two accessor words in the " { $vocab-link "accessors" } " vocabulary:" +{ $list + { "The " { $emphasis "reader" } " is named " { $snippet { $emphasis "slot" } ">>" } " and pushes the value of a slot on the stack." } + { "The " { $emphasis "writer" } " is named " { $snippet "(>>" { $emphasis "slot" } ")" } " and stores a value into a slot. It has stack effect " { $snippet "( value object -- )" } "." } +} +"In addition, two utility words are defined for each distinct slot name used in the system:" +{ $list + { "The " { $emphasis "setter" } " is named " { $snippet "(>>" { $emphasis "slot" } ")" } " and stores a value into a slot. It has stack effect " { $snippet "( object value -- object )" } "." } + { "The " { $emphasis "changer" } " is named " { $snippet "change-" { $emphasis "slot" } } ". It applies a quotation to the current slot value and stores the result back in the slot; it has stack effect " { $snippet "( object quot -- object )" } "." } +} +"Since the reader and writer are generic, words can be written which do not depend on the specific class of tuple passed in, but instead work on any tuple that defines slots with certain names." +$nl +"In most cases, using the setter is preferred over the writer because the stack effect is better suited to the common case where the tuple is needed again, and where the new slot value was just computed and so is at the top of the stack. For example, consider the case where you want to create a tuple and fill in the slots with literals. The following version uses setters:" +{ $code + "" + " \"Happy birthday\" >>subject" + " { \"bob@bigcorp.com\" } >>to" + " \"alice@bigcorp.com\" >>from" + "send-email" +} +"The following uses writers, and requires some stack shuffling:" +{ $code + "" + " \"Happy birthday\" over (>>subject)" + " { \"bob@bigcorp.com\" } over (>>to)" + " \"alice@bigcorp.com\" over (>>from)" + "send-email" +} +"Even if some of the slot values come from the stack underneath the tuple being constructed, setters win:" +{ $code + "" + " swap >>subject" + " swap >>to" + " \"alice@bigcorp.com\" >>from" + "send-email" +} +"This is because " { $link swap } " is easier to understand than " { $link tuck } ":" +{ $code + "" + " tuck (>>subject)" + " tuck (>>to)" + " \"alice@bigcorp.com\" over (>>from)" + "send-email" +} +"The changer word abstracts a common pattern where a slot value is read then stored again; so the following is not idiomatic code:" +{ $code + "find-manager" + " salary>> 0.75 * >>salary" +} +"The following version is preferred:" +{ $code + "find-manager" + " [ 0.75 * ] change-salary" +} +{ $see-also "slots" "mirrors" } ; + ARTICLE: "slots" "Slots" -"A " { $emphasis "slot" } " is a component of an object which can store a value. The " { $vocab-link "slots" } " vocabulary contains words for introspecting the slots of an object." +"A " { $emphasis "slot" } " is a component of an object which can store a value." $nl { $link "tuples" } " are composed entirely of slots, and instances of " { $link "builtin-classes" } " consist of slots together with intrinsic data." +"The " { $vocab-link "slots" } " vocabulary contains words for introspecting the slots of an object." $nl "The " { $snippet "\"slots\"" } " word property of built-in and tuple classes holds an array of " { $emphasis "slot specifiers" } " describing the slot layout of each instance." { $subsection slot-spec } -"Each slot has a reader word; mutable slots have an optional writer word. All tuple slots are mutable, but some slots on built-in classes are not." -{ $subsection slot-spec-reader } -{ $subsection slot-spec-writer } -"Given a reader or writer word and a class, it is possible to find the slot specifier corresponding to this word:" -{ $subsection slot-of-reader } -{ $subsection slot-of-writer } -"Reader and writer words form classes:" -{ $subsection slot-reader } -{ $subsection slot-writer } -"Slot readers and writers type check, then call unsafe primitives:" -{ $subsection slot } -{ $subsection set-slot } ; +"The four words associated with a slot can be looked up in the " { $vocab-link "accessors" } " vocabulary:" +{ $subsection reader-word } +{ $subsection writer-word } +{ $subsection setter-word } +{ $subsection changer-word } +"Looking up a slot by name:" +{ $subsection slot-named } +"Defining slots dynamically:" +{ $subsection define-reader } +{ $subsection define-writer } +{ $subsection define-setter } +{ $subsection define-changer } +{ $subsection define-slot-methods } +{ $subsection define-accessors } +{ $see-also "accessors" "mirrors" } ; ABOUT: "slots" @@ -59,53 +120,32 @@ $low-level-note ; HELP: reader-effect { $values { "class" class } { "spec" slot-spec } { "effect" "an instance of " { $link effect } } } -{ $description "The stack effect of slot reader words is " { $snippet "( obj -- value )" } "." } ; - -HELP: reader-quot -{ $values { "decl" class } { "quot" "a quotation with stack effect " { $snippet "( obj n -- value )" } } } -{ $description "Outputs a quotation which reads the " { $snippet "n" } "th slot of an object and declares it as an instance of a class." } ; - -HELP: slot-reader -{ $class-description "The class of slot reader words." } -{ $examples - { $example "USING: classes prettyprint slots ;" "TUPLE: circle center radius ;" "\\ circle-center slot-reader? ." "t" } -} ; +{ $description "The stack effect of slot reader words is " { $snippet "( object -- value )" } "." } ; HELP: define-reader -{ $values { "class" class } { "spec" slot-spec } } -{ $description "Defines a generic word " { $snippet "reader" } " to read a slot from instances of " { $snippet "class" } "." } +{ $values { "class" class } { "name" string } { "slot" integer } } +{ $description "Defines a reader word to read a slot from instances of " { $snippet "class" } "." } $low-level-note ; HELP: writer-effect { $values { "class" class } { "spec" slot-spec } { "effect" "an instance of " { $link effect } } } { $description "The stack effect of slot writer words is " { $snippet "( value obj -- )" } "." } ; -HELP: slot-writer -{ $class-description "The class of slot writer words." } -{ $examples - { $example "USING: classes prettyprint slots ;" "TUPLE: circle center radius ;" "\\ set-circle-center slot-writer? ." "t" } -} ; - HELP: define-writer -{ $values { "class" class } { "spec" slot-spec } } +{ $values { "class" class } { "name" string } { "slot" integer } } { $description "Defines a generic word " { $snippet "writer" } " to write a new value to a slot in instances of " { $snippet "class" } "." } $low-level-note ; -HELP: define-slot -{ $values { "class" class } { "spec" slot-spec } } -{ $description "Defines a pair of generic words for reading and writing a slot value in instances of " { $snippet "class" } "." } +HELP: define-slot-methods +{ $values { "class" class } { "name" string } { "slot" integer } } +{ $description "Defines a reader, writer, setter and changer for a slot in instances of " { $snippet "class" } "." } $low-level-note ; -HELP: define-slots +HELP: define-accessors { $values { "class" class } { "specs" "a sequence of " { $link slot-spec } " instances" } } -{ $description "Defines a set of slot reader/writer words." } +{ $description "Defines slot methods." } $low-level-note ; -HELP: simple-slots -{ $values { "class" class } { "slots" "a sequence of strings" } { "base" "a slot number" } { "specs" "a sequence of " { $link slot-spec } " instances" } } -{ $description "Constructs a slot specification for " { $link define-slots } " where each slot is named by an element of " { $snippet "slots" } " prefixed by the name of the class. Slots are numbered consecutively starting from " { $snippet "base" } ". Reader and writer words are defined in the current vocabulary, with the reader word having the same name as the slot, and the writer word name prefixed by " { $snippet "\"set-\"" } "." } -{ $notes "This word is used by " { $link define-tuple-class } " and " { $link POSTPONE: TUPLE: } "." } ; - HELP: slot ( obj m -- value ) { $values { "obj" object } { "m" "a non-negative fixnum" } { "value" object } } { $description "Reads the object stored at the " { $snippet "n" } "th slot of " { $snippet "obj" } "." } @@ -116,18 +156,6 @@ HELP: set-slot ( value obj n -- ) { $description "Writes " { $snippet "value" } " to the " { $snippet "n" } "th slot of " { $snippet "obj" } "." } { $warning "This word is in the " { $vocab-link "slots.private" } " vocabulary because it does not perform type or bounds checks, and slot numbers are implementation detail." } ; -HELP: slot-of-reader -{ $values { "reader" slot-reader } { "specs" "a sequence of " { $link slot-spec } " instances" } { "spec/f" "a " { $link slot-spec } " or " { $link f } } } -{ $description "Outputs the " { $link slot-spec } " whose " { $link slot-spec-reader } " is equal to " { $snippet "reader" } "." } ; - -HELP: slot-of-writer -{ $values { "writer" slot-writer } { "specs" "a sequence of " { $link slot-spec } " instances" } { "spec/f" "a " { $link slot-spec } " or " { $link f } } } -{ $description "Outputs the " { $link slot-spec } " whose " { $link slot-spec-writer } " is equal to " { $snippet "writer" } "." } ; - -HELP: reader-word -{ $values { "class" string } { "name" string } { "vocab" string } { "word" word } } -{ $description "Creates a word named " { $snippet { $emphasis "class" } "-" { $emphasis "name" } } " in the " { $snippet "vocab" } " vocabulary." } ; - -HELP: writer-word -{ $values { "class" string } { "name" string } { "vocab" string } { "word" word } } -{ $description "Creates a word named " { $snippet "set-" { $emphasis "class" } "-" { $emphasis "name" } } " in the " { $snippet "vocab" } " vocabulary." } ; +HELP: slot-named +{ $values { "name" string } { "specs" "a sequence of " { $link slot-spec } " instances" } { "spec/f" "a " { $link slot-spec } " or " { $link f } } } +{ $description "Outputs the " { $link slot-spec } " with the given name." } ; diff --git a/core/slots/slots.factor b/core/slots/slots.factor index 92d22247bd..ed5de3a439 100755 --- a/core/slots/slots.factor +++ b/core/slots/slots.factor @@ -10,14 +10,12 @@ TUPLE: slot-spec type name offset reader writer ; C: slot-spec : define-typecheck ( class generic quot -- ) - over define-simple-generic -rot define-method ; + over define-simple-generic + >r create-method r> define ; : define-slot-word ( class slot word quot -- ) rot >fixnum add* define-typecheck ; -: reader-effect ( class spec -- effect ) - >r ?word-name 1array r> slot-spec-name 1array ; - : reader-quot ( decl -- quot ) [ \ slot , @@ -25,91 +23,62 @@ C: slot-spec [ drop ] [ 1array , \ declare , ] if ] [ ] make ; -PREDICATE: word slot-reader "reading" word-prop >boolean ; - -: set-reader-props ( class spec -- ) - 2dup reader-effect - over slot-spec-reader - swap "declared-effect" set-word-prop - slot-spec-reader swap "reading" set-word-prop ; - -: define-reader ( class spec -- ) - dup slot-spec-reader [ - [ set-reader-props ] 2keep - dup slot-spec-offset - over slot-spec-reader - rot slot-spec-type reader-quot - define-slot-word - ] [ - 2drop - ] if ; - -: writer-effect ( class spec -- effect ) - slot-spec-name swap ?word-name 2array 0 ; - -PREDICATE: word slot-writer "writing" word-prop >boolean ; - -: set-writer-props ( class spec -- ) - 2dup writer-effect - over slot-spec-writer - swap "declared-effect" set-word-prop - slot-spec-writer swap "writing" set-word-prop ; - -: define-writer ( class spec -- ) - dup slot-spec-writer [ - [ set-writer-props ] 2keep - dup slot-spec-offset - swap slot-spec-writer - [ set-slot ] - define-slot-word - ] [ - 2drop - ] if ; - -: define-slot ( class spec -- ) - 2dup define-reader define-writer ; - -: define-slots ( class specs -- ) - [ define-slot ] with each ; - -: reader-word ( class name vocab -- word ) - >r >r "-" r> 3append r> create ; - -: writer-word ( class name vocab -- word ) - >r [ swap "set-" % % "-" % % ] "" make r> create ; - -: (simple-slot-word) ( class name -- class name vocab ) - over word-vocabulary >r >r word-name r> r> ; - -: simple-reader-word ( class name -- word ) - (simple-slot-word) reader-word ; - -: simple-writer-word ( class name -- word ) - (simple-slot-word) writer-word ; - -: short-slot ( class name # -- spec ) - >r object bootstrap-word over r> f f - 2over simple-reader-word over set-slot-spec-reader - -rot simple-writer-word over set-slot-spec-writer ; - -: long-slot ( spec # -- spec ) - >r [ dup array? [ first2 create ] when ] map first4 r> - -rot ; - -: simple-slots ( class slots base -- specs ) - over length [ + ] with map [ - { - { [ over not ] [ 2drop f ] } - { [ over string? ] [ >r dupd r> short-slot ] } - { [ over array? ] [ long-slot ] } - } cond - ] 2map [ ] subset nip ; - -: slot-of-reader ( reader specs -- spec/f ) - [ slot-spec-reader eq? ] with find nip ; - -: slot-of-writer ( writer specs -- spec/f ) - [ slot-spec-writer eq? ] with find nip ; - -: slot-named ( string specs -- spec/f ) +: slot-named ( name specs -- spec/f ) [ slot-spec-name = ] with find nip ; + +: create-accessor ( name effect -- word ) + >r "accessors" create dup r> + "declared-effect" set-word-prop ; + +: reader-effect T{ effect f { "object" } { "value" } } ; inline + +: reader-word ( name -- word ) + ">>" append reader-effect create-accessor ; + +: define-reader ( class slot name -- ) + reader-word object reader-quot define-slot-word ; + +: writer-effect T{ effect f { "value" "object" } { } } ; inline + +: writer-word ( name -- word ) + "(>>" swap ")" 3append writer-effect create-accessor ; + +: define-writer ( class slot name -- ) + writer-word [ set-slot ] define-slot-word ; + +: setter-effect T{ effect f { "object" "value" } { "value" } } ; inline + +: setter-word ( name -- word ) + ">>" prepend setter-effect create-accessor ; + +: define-setter ( name -- ) + dup setter-word dup deferred? [ + [ \ over , swap writer-word , ] [ ] make define-inline + ] [ 2drop ] if ; + +: changer-effect T{ effect f { "object" "quot" } { "object" } } ; inline + +: changer-word ( name -- word ) + "change-" prepend changer-effect create-accessor ; + +: define-changer ( name -- ) + dup changer-word dup deferred? [ + [ + [ over >r >r ] % + over reader-word , + [ r> call r> swap ] % + swap setter-word , + ] [ ] make define-inline + ] [ 2drop ] if ; + +: define-slot-methods ( class slot name -- ) + dup define-changer + dup define-setter + 3dup define-reader + define-writer ; + +: define-accessors ( class specs -- ) + [ + dup slot-spec-offset swap slot-spec-name + define-slot-methods + ] with each ; diff --git a/core/splitting/splitting-tests.factor b/core/splitting/splitting-tests.factor index d60403362c..34757e6b22 100644 --- a/core/splitting/splitting-tests.factor +++ b/core/splitting/splitting-tests.factor @@ -1,4 +1,4 @@ -USING: splitting tools.test ; +USING: splitting tools.test kernel sequences arrays ; IN: splitting.tests [ { 1 2 3 } 0 group ] must-fail @@ -56,3 +56,9 @@ unit-test [ { "hello" "hi" } ] [ "hello\nhi" string-lines ] unit-test [ { "hello" "hi" } ] [ "hello\rhi" string-lines ] unit-test [ { "hello" "hi" } ] [ "hello\r\nhi" string-lines ] unit-test + +[ { V{ "a" "b" } V{ f f } } ] [ + V{ "a" "b" } clone 2 + 2 over set-length + >array +] unit-test diff --git a/core/splitting/splitting.factor b/core/splitting/splitting.factor index 6416e27eaf..419a30dda4 100755 --- a/core/splitting/splitting.factor +++ b/core/splitting/splitting.factor @@ -17,7 +17,7 @@ M: groups length dup groups-seq length swap groups-n [ + 1- ] keep /i ; M: groups set-length - [ groups-n * ] keep delegate set-length ; + [ groups-n * ] keep groups-seq set-length ; : group@ ( n groups -- from to seq ) [ groups-n [ * dup ] keep + ] keep diff --git a/core/syntax/syntax-docs.factor b/core/syntax/syntax-docs.factor index dc06a239de..c0ceb4119a 100755 --- a/core/syntax/syntax-docs.factor +++ b/core/syntax/syntax-docs.factor @@ -227,6 +227,9 @@ HELP: foldable } "The last restriction ensures that words such as " { $link clone } " do not satisfy the foldable word contract. Indeed, " { $link clone } " will output a mutable object if its input is mutable, and so it is undesirable to evaluate it at compile-time, since doing so would give incorrect semantics for code that clones mutable objects and proceeds to mutate them." } +{ $notes + "Folding optimizations are not applied if the call site of a word is in the same source file as the word. This is a side-effect of the compilation unit system; see " { $link "compilation-units" } "." +} { $examples "Most operations on numbers are foldable. For example, " { $snippet "2 2 +" } " compiles to a literal 4, since " { $link + } " is declared foldable." } ; HELP: flushable @@ -556,10 +559,17 @@ HELP: PREDICATE: HELP: TUPLE: { $syntax "TUPLE: class slots... ;" } { $values { "class" "a new tuple class to define" } { "slots" "a list of slot names" } } -{ $description "Defines a new tuple class with membership predicate " { $snippet "name?" } "." +{ $description "Defines a new tuple class." $nl "Tuples are user-defined classes with instances composed of named slots. All tuple classes are subtypes of the built-in " { $link tuple } " type." } ; +HELP: ERROR: +{ $syntax "ERROR: class slots... ;" } +{ $values { "class" "a new tuple class to define" } { "slots" "a list of slot names" } } +{ $description "Defines a new tuple class. Defines a new word " { $snippet "class?" } " that boa-constructs this tuple and throws it." } ; + +{ POSTPONE: ERROR: POSTPONE: TUPLE: } related-words + HELP: C: { $syntax "C: constructor class" } { $values { "constructor" "a new word to define" } { "class" tuple-class } } diff --git a/core/syntax/syntax.factor b/core/syntax/syntax.factor index 79a5553228..843f372542 100755 --- a/core/syntax/syntax.factor +++ b/core/syntax/syntax.factor @@ -97,7 +97,7 @@ IN: bootstrap.syntax "parsing" [ word t "parsing" set-word-prop ] define-syntax "SYMBOL:" [ - CREATE dup reset-generic define-symbol + CREATE-WORD define-symbol ] define-syntax "DEFER:" [ @@ -111,31 +111,26 @@ IN: bootstrap.syntax ] define-syntax "GENERIC:" [ - CREATE dup reset-word - define-simple-generic + CREATE-GENERIC define-simple-generic ] define-syntax "GENERIC#" [ - CREATE dup reset-word + CREATE-GENERIC scan-word define-generic ] define-syntax "MATH:" [ - CREATE dup reset-word + CREATE-GENERIC T{ math-combination } define-generic ] define-syntax "HOOK:" [ - CREATE dup reset-word scan-word + CREATE-GENERIC scan-word define-generic ] define-syntax "M:" [ - f set-word - location >r - scan-word bootstrap-word scan-word - [ parse-definition -rot define-method ] 2keep - 2array r> remember-definition + (M:) define ] define-syntax "UNION:" [ @@ -163,11 +158,17 @@ IN: bootstrap.syntax ] define-syntax "C:" [ - CREATE dup reset-generic + CREATE-WORD scan-word dup check-tuple [ construct-boa ] curry define-inline ] define-syntax + "ERROR:" [ + CREATE-CLASS dup ";" parse-tokens define-tuple-class + dup save-location + dup [ construct-boa throw ] curry define + ] define-syntax + "FORGET:" [ scan-word dup parsing? [ V{ } clone swap execute first ] when diff --git a/core/threads/threads-tests.factor b/core/threads/threads-tests.factor index c2e627e7bf..d746404cba 100755 --- a/core/threads/threads-tests.factor +++ b/core/threads/threads-tests.factor @@ -14,3 +14,5 @@ yield [ 3 ] [ [ 3 swap resume-with ] "Test suspend" suspend ] unit-test + +[ f ] [ f get-global ] unit-test diff --git a/core/threads/threads.factor b/core/threads/threads.factor index b4fd6eee60..d7d7988893 100755 --- a/core/threads/threads.factor +++ b/core/threads/threads.factor @@ -32,8 +32,6 @@ mailbox variables sleep-entry ; : threads 41 getenv ; -threads global [ H{ } assoc-like ] change-at - : thread ( id -- thread ) threads at ; : thread-registered? ( thread -- ? ) diff --git a/core/tuples/tuples-docs.factor b/core/tuples/tuples-docs.factor index c03b9784ee..09d93884ad 100755 --- a/core/tuples/tuples-docs.factor +++ b/core/tuples/tuples-docs.factor @@ -3,18 +3,28 @@ tuples.private classes slots quotations words arrays generic.standard sequences definitions compiler.units ; IN: tuples -ARTICLE: "tuple-constructors" "Constructors and slots" -"Tuples are created by calling one of a number of words:" +ARTICLE: "tuple-constructors" "Constructors" +"Tuples are created by calling one of two words:" { $subsection construct-empty } { $subsection construct-boa } -{ $subsection construct } "By convention, construction logic is encapsulated in a word named after the tuple class surrounded in angle brackets; for example, the constructor word for a " { $snippet "point" } " class might be named " { $snippet "" } "." $nl "A shortcut for defining BOA constructors:" { $subsection POSTPONE: C: } -"After construction, slots are read and written using various automatically-defined words with names of the form " { $snippet { $emphasis "class-slot" } } " and " { $snippet "set-" { $emphasis "class-slot" } } "." ; +"Examples of constructors:" +{ $code + "TUPLE: color red green blue alpha ;" + "" + "C: rgba" + ": color construct-boa ; ! identical to above" + "" + ": f ;" + "" + ": construct-empty ;" + ": f f f f ; ! identical to above" +} ; -ARTICLE: "tuple-delegation" "Delegation" +ARTICLE: "tuple-delegation" "Tuple delegation" "If a generic word having the " { $link standard-combination } " method combination is called on a tuple for which it does not have an applicable method, the method call is forwarded to the tuple's " { $emphasis "delegate" } ". If no delegate is set, a " { $link no-method } " error is thrown." { $subsection delegate } { $subsection set-delegate } @@ -32,7 +42,7 @@ $nl "{ 0 0 } 10 \"my-ellipse\" set" "{ 1 0 0 } \"my-shape\" set" "\"my-ellipse\" get \"my-shape\" get set-delegate" - "\"my-shape\" get dup colored-color swap ellipse-center .s" + "\"my-shape\" get dup color>> swap center>> .s" "{ 0 0 }\n{ 1 0 0 }" } ; @@ -42,25 +52,90 @@ ARTICLE: "tuple-introspection" "Tuple introspection" { $subsection tuple>array } { $subsection tuple-slots } "Tuple classes can also be defined at run time:" -{ $subsection define-tuple-class } ; +{ $subsection define-tuple-class } +{ $see-also "slots" "mirrors" } ; + +ARTICLE: "tuple-examples" "Tuple examples" +"An example:" +{ $code "TUPLE: employee name salary position ;" } +"This defines a class word named " { $snippet "employee" } ", a predicate " { $snippet "employee?" } ", and the following slot accessors:" +{ $table + { "Reader" "Writer" "Setter" "Changer" } + { { $snippet "name>>" } { $snippet "(>>name)" } { $snippet ">>name" } { $snippet "change-name" } } + { { $snippet "salary>>" } { $snippet "(>>salary)" } { $snippet ">>salary" } { $snippet "change-salary" } } + { { $snippet "position>>" } { $snippet "(>>position)" } { $snippet ">>position" } { $snippet "change-position" } } +} +"We can define a constructor which makes an empty employee:" +{ $code ": ( -- employee )" + " employee construct-empty ;" } +"Or we may wish the default constructor to always give employees a starting salary:" +{ $code + ": ( -- employee )" + " employee construct-empty" + " 40000 >>salary ;" +} +"We can define more refined constructors:" +{ $code + ": ( -- manager )" + " \"project manager\" >>position ;" } +"An alternative strategy is to define the most general BOA constructor first:" +{ $code + ": ( name position -- person )" + " 40000 employee construct-boa ;" +} +"Now we can define more specific constructors:" +{ $code + ": ( name -- person )" + " \"manager\" ;" } +"An example using reader words:" +{ $code + "TUPLE: check to amount number ;" + "" + "SYMBOL: checks" + "" + ": ( to amount -- check )" + " checks counter check construct-boa ;" + "" + ": biweekly-paycheck ( employee -- check )" + " dup name>> swap salary>> 26 / ;" +} +"An example of using a changer:" +{ $code + ": positions" + " {" + " \"junior programmer\"" + " \"senior programmer\"" + " \"project manager\"" + " \"department manager\"" + " \"executive\"" + " \"CTO\"" + " \"CEO\"" + " \"enterprise Java world dictator\"" + " } ;" + "" + ": next-position ( role -- newrole )" + " positions [ index 1+ ] keep nth ;" + "" + ": promote ( person -- person )" + " [ 1.2 * ] change-salary" + " [ next-position ] change-position ;" +} ; ARTICLE: "tuples" "Tuples" -"Tuples are user-defined classes composed of named slots. A parsing word defines tuple classes:" +"Tuples are user-defined classes composed of named slots." +{ $subsection "tuple-examples" } +"A parsing word defines tuple classes:" { $subsection POSTPONE: TUPLE: } -"An example:" -{ $code "TUPLE: person name address phone ;" } -"This defines a class word named " { $snippet "person" } ", along with a predicate " { $snippet "person?" } ", and the following reader/writer words:" -{ $table - { "Reader" "Writer" } - { { $snippet "person-name" } { $snippet "set-person-name" } } - { { $snippet "person-address" } { $snippet "set-person-address" } } - { { $snippet "person-phone" } { $snippet "set-person-phone" } } -} +"For each tuple class, several words are defined. First, there is the class word, a class predicate, and accessor words for each slot." +$nl +"The class word is used for defining methods on the tuple class; it has the same name as the tuple class. The predicate is named " { $snippet { $emphasis "name" } "?" } ". Tuple slots are accessed via accessor words:" +{ $subsection "accessors" } "Initially, no specific words are defined for constructing new instances of the tuple. Constructors must be defined explicitly:" { $subsection "tuple-constructors" } "Further topics:" { $subsection "tuple-delegation" } -{ $subsection "tuple-introspection" } ; +{ $subsection "tuple-introspection" } +"Tuple literal syntax is documented in " { $link "syntax-tuples" } "." ; ABOUT: "tuples" diff --git a/core/tuples/tuples-tests.factor b/core/tuples/tuples-tests.factor index 63bb233654..b5076ea22b 100755 --- a/core/tuples/tuples-tests.factor +++ b/core/tuples/tuples-tests.factor @@ -236,7 +236,7 @@ C: erg's-reshape-problem [ "IN: tuples.tests SYMBOL: not-a-class C: not-a-class" eval -] [ [ check-tuple? ] is? ] must-fail-with +] [ [ no-tuple-class? ] is? ] must-fail-with ! Hardcore unit tests USE: threads diff --git a/core/tuples/tuples.factor b/core/tuples/tuples.factor index e48a803659..02ce49d779 100755 --- a/core/tuples/tuples.factor +++ b/core/tuples/tuples.factor @@ -3,7 +3,8 @@ USING: arrays definitions hashtables kernel kernel.private math namespaces sequences sequences.private strings vectors words quotations memory combinators generic -classes classes.private slots slots.private compiler.units ; +classes classes.private slots slots.deprecated slots.private +compiler.units ; IN: tuples M: tuple delegate 3 slot ; @@ -85,13 +86,14 @@ PRIVATE> dupd 4 simple-slots 2dup [ slot-spec-name ] map "slot-names" set-word-prop 2dup delegate-slot-spec add* "slots" set-word-prop - define-slots ; + 2dup define-slots + define-accessors ; -TUPLE: check-tuple class ; +ERROR: no-tuple-class class ; : check-tuple ( class -- ) dup tuple-class? - [ drop ] [ \ check-tuple construct-boa throw ] if ; + [ drop ] [ no-tuple-class ] if ; : define-tuple-class ( class slots -- ) 2dup check-shape diff --git a/core/vocabs/loader/loader-docs.factor b/core/vocabs/loader/loader-docs.factor index c7652c34c7..c0542f7b96 100755 --- a/core/vocabs/loader/loader-docs.factor +++ b/core/vocabs/loader/loader-docs.factor @@ -43,8 +43,6 @@ HELP: find-vocab-root { $values { "vocab" "a vocabulary specifier" } { "path/f" "a pathname string" } } { $description "Searches for a vocabulary in the vocabulary roots." } ; -{ vocab-root find-vocab-root } related-words - HELP: no-vocab { $values { "name" "a vocabulary name" } } { $description "Throws a " { $link no-vocab } "." } diff --git a/core/vocabs/loader/loader-tests.factor b/core/vocabs/loader/loader-tests.factor index 514e45f10f..85399ca9e7 100755 --- a/core/vocabs/loader/loader-tests.factor +++ b/core/vocabs/loader/loader-tests.factor @@ -13,15 +13,15 @@ debugger compiler.units tools.vocabs ; ] unit-test [ T{ vocab-link f "vocabs.loader.test" } ] -[ "vocabs.loader.test" f >vocab-link ] unit-test +[ "vocabs.loader.test" >vocab-link ] unit-test [ t ] -[ "kernel" f >vocab-link "kernel" vocab = ] unit-test +[ "kernel" >vocab-link "kernel" vocab = ] unit-test [ t ] [ "kernel" vocab-files "kernel" vocab vocab-files - "kernel" f vocab-files + "kernel" vocab-files 3array all-equal? ] unit-test @@ -36,7 +36,7 @@ IN: vocabs.loader.tests [ { 3 3 3 } ] [ "vocabs.loader.test.2" run "vocabs.loader.test.2" vocab run - "vocabs.loader.test.2" f run + "vocabs.loader.test.2" run 3array ] unit-test @@ -78,6 +78,8 @@ IN: vocabs.loader.tests ] with-compilation-unit ] unit-test +[ f ] [ "vocabs.loader.test.b" vocab-files empty? ] unit-test + [ ] [ [ "vocabs.loader.test.b" vocab-files @@ -113,11 +115,18 @@ IN: vocabs.loader.tests [ 3 ] [ "count-me" get-global ] unit-test [ { "resource:core/kernel/kernel.factor" 1 } ] -[ "kernel" f where ] unit-test +[ "kernel" where ] unit-test [ { "resource:core/kernel/kernel.factor" 1 } ] [ "kernel" vocab where ] unit-test +[ ] [ + [ + "vocabs.loader.test.c" forget-vocab + "vocabs.loader.test.d" forget-vocab + ] with-compilation-unit +] unit-test + [ t ] [ [ "vocabs.loader.test.d" require ] [ :1 ] recover "vocabs.loader.test.d" vocab-source-loaded? @@ -127,7 +136,7 @@ IN: vocabs.loader.tests [ { "2" "a" "b" "d" "e" "f" } [ - "vocabs.loader.test." swap append forget-vocab + "vocabs.loader.test." prepend forget-vocab ] each ] with-compilation-unit ; diff --git a/core/vocabs/loader/loader.factor b/core/vocabs/loader/loader.factor index fa9ff5b504..9478c1f4f7 100755 --- a/core/vocabs/loader/loader.factor +++ b/core/vocabs/loader/loader.factor @@ -23,30 +23,30 @@ V{ [ >r dup peek r> append add ] when* "/" join ; -: vocab-path+ ( vocab path -- newpath ) - swap vocab-root dup [ swap path+ ] [ 2drop f ] if ; - -: vocab-source-path ( vocab -- path/f ) - dup ".factor" vocab-dir+ vocab-path+ ; - -: vocab-docs-path ( vocab -- path/f ) - dup "-docs.factor" vocab-dir+ vocab-path+ ; - : vocab-dir? ( root name -- ? ) over [ - ".factor" vocab-dir+ path+ resource-exists? + ".factor" vocab-dir+ append-path resource-exists? ] [ 2drop f ] if ; +SYMBOL: root-cache + +H{ } clone root-cache set-global + : find-vocab-root ( vocab -- path/f ) - vocab-roots get swap [ vocab-dir? ] curry find nip ; + vocab-name root-cache get [ + vocab-roots get swap [ vocab-dir? ] curry find nip + ] cache ; -M: string vocab-root - dup vocab [ vocab-root ] [ find-vocab-root ] ?if ; +: vocab-append-path ( vocab path -- newpath ) + swap find-vocab-root dup [ prepend-path ] [ 2drop f ] if ; -M: vocab-link vocab-root - vocab-link-root ; +: vocab-source-path ( vocab -- path/f ) + dup ".factor" vocab-dir+ vocab-append-path ; + +: vocab-docs-path ( vocab -- path/f ) + dup "-docs.factor" vocab-dir+ vocab-append-path ; SYMBOL: load-help? @@ -56,7 +56,7 @@ SYMBOL: load-help? : load-source ( vocab -- ) [ source-wasn't-loaded ] keep - [ vocab-source-path bootstrap-file ] keep + [ vocab-source-path [ bootstrap-file ] when* ] keep source-was-loaded ; : docs-were-loaded t swap set-vocab-docs-loaded? ; @@ -66,24 +66,13 @@ SYMBOL: load-help? : load-docs ( vocab -- ) load-help? get [ [ docs-weren't-loaded ] keep - [ vocab-docs-path ?run-file ] keep + [ vocab-docs-path [ ?run-file ] when* ] keep docs-were-loaded ] [ drop ] if ; -: create-vocab-with-root ( vocab-link -- vocab ) - dup vocab-name create-vocab - swap vocab-root over set-vocab-root ; - : reload ( name -- ) [ - f >vocab-link - dup vocab-root [ - dup vocab-source-path resource-exists? [ - create-vocab-with-root - dup load-source - load-docs - ] [ no-vocab ] if - ] [ no-vocab ] if + dup vocab [ dup load-source load-docs ] [ no-vocab ] ?if ] with-compiler-errors ; : require ( vocab -- ) @@ -100,33 +89,37 @@ SYMBOL: load-help? SYMBOL: blacklist -GENERIC: (load-vocab) ( name -- vocab ) - : add-to-blacklist ( error vocab -- ) vocab-name blacklist get dup [ set-at ] [ 3drop ] if ; +GENERIC: (load-vocab) ( name -- ) + M: vocab (load-vocab) [ - dup vocab-root [ - dup vocab-source-loaded? [ dup load-source ] unless - dup vocab-docs-loaded? [ dup load-docs ] unless - ] when + dup vocab-source-loaded? [ dup load-source ] unless + dup vocab-docs-loaded? [ dup load-docs ] unless + drop ] [ [ swap add-to-blacklist ] keep rethrow ] recover ; -M: string (load-vocab) - [ ".private" ?tail drop reload ] keep vocab ; - M: vocab-link (load-vocab) - vocab-name (load-vocab) ; + vocab-name create-vocab (load-vocab) ; + +M: string (load-vocab) + create-vocab (load-vocab) ; [ - dup vocab-name blacklist get at* [ - rethrow - ] [ - drop - [ dup vocab swap or (load-vocab) ] with-compiler-errors - ] if - + [ + dup vocab-name blacklist get at* [ + rethrow + ] [ + drop + dup find-vocab-root [ + [ (load-vocab) ] with-compiler-errors + ] [ + dup vocab [ drop ] [ no-vocab ] if + ] if + ] if + ] with-compiler-errors ] load-vocab-hook set-global : vocab-where ( vocab -- loc ) diff --git a/core/vocabs/vocabs-docs.factor b/core/vocabs/vocabs-docs.factor index f16a33f0d5..0d55499620 100755 --- a/core/vocabs/vocabs-docs.factor +++ b/core/vocabs/vocabs-docs.factor @@ -16,7 +16,6 @@ $nl { $subsection vocab } "Accessors for various vocabulary attributes:" { $subsection vocab-name } -{ $subsection vocab-root } { $subsection vocab-main } { $subsection vocab-help } "Looking up existing vocabularies and creating new vocabularies:" @@ -50,10 +49,6 @@ HELP: vocab-name { $values { "vocab" "a vocabulary specifier" } { "name" string } } { $description "Outputs the name of a vocabulary." } ; -HELP: vocab-root -{ $values { "vocab" "a vocabulary specifier" } { "root" "a pathname string or " { $link f } } } -{ $description "Outputs the vocabulary root where the source code for a vocabulary is located, or " { $link f } " if the vocabulary is not defined in source files." } ; - HELP: vocab-words { $values { "vocab" "a vocabulary specifier" } { "words" "an assoc mapping strings to words" } } { $description "Outputs the words defined in a vocabulary." } ; @@ -101,11 +96,11 @@ HELP: child-vocabs } ; HELP: vocab-link -{ $class-description "Instances of this class identify vocabularies which are potentially not loaded. The " { $link vocab-name } " slot is the vocabulary name, and " { $link vocab-root } " is a pathname string identifying the vocabulary root where the sources to this vocabulary are located, or " { $link f } " if the root is not known." +{ $class-description "Instances of this class identify vocabularies which are potentially not loaded. The " { $link vocab-name } " slot is the vocabulary name." $nl "Vocabulary links are created by calling " { $link >vocab-link } "." } ; HELP: >vocab-link -{ $values { "name" string } { "root" "a pathname string or " { $link f } } { "vocab" "a vocabulary specifier" } } +{ $values { "name" string } { "vocab" "a vocabulary specifier" } } { $description "If the vocabulary is loaded, outputs the corresponding " { $link vocab } " instance, otherwise creates a new " { $link vocab-link } "." } ; diff --git a/core/vocabs/vocabs.factor b/core/vocabs/vocabs.factor index 1a3fecc3fb..f111b5bc74 100755 --- a/core/vocabs/vocabs.factor +++ b/core/vocabs/vocabs.factor @@ -7,16 +7,15 @@ IN: vocabs SYMBOL: dictionary TUPLE: vocab -name root -words +name words main help source-loaded? docs-loaded? ; M: vocab equal? 2drop f ; : ( name -- vocab ) - H{ } clone t - { set-vocab-name set-vocab-words set-vocab-source-loaded? } + H{ } clone + { set-vocab-name set-vocab-words } \ vocab construct ; GENERIC: vocab ( vocab-spec -- vocab ) @@ -60,9 +59,12 @@ M: f vocab-help ; : create-vocab ( name -- vocab ) dictionary get [ ] cache ; -SYMBOL: load-vocab-hook +ERROR: no-vocab name ; -: load-vocab ( name -- vocab ) load-vocab-hook get call ; +SYMBOL: load-vocab-hook ! ( name -- ) + +: load-vocab ( name -- vocab ) + dup load-vocab-hook get call vocab ; : vocabs ( -- seq ) dictionary get keys natural-sort ; @@ -85,10 +87,10 @@ SYMBOL: load-vocab-hook : child-vocabs ( vocab -- seq ) vocab-name vocabs [ child-vocab? ] with subset ; -TUPLE: vocab-link name root ; +TUPLE: vocab-link name ; -: ( name root -- vocab-link ) - [ dup vocab-root ] unless* vocab-link construct-boa ; +: ( name -- vocab-link ) + vocab-link construct-boa ; M: vocab-link equal? over vocab-link? @@ -99,24 +101,16 @@ M: vocab-link hashcode* M: vocab-link vocab-name vocab-link-name ; -GENERIC# >vocab-link 1 ( name root -- vocab ) - -M: vocab >vocab-link drop ; - -M: vocab-link >vocab-link drop ; - -M: string >vocab-link - over vocab dup [ 2nip ] [ drop ] if ; - UNION: vocab-spec vocab vocab-link ; +GENERIC: >vocab-link ( name -- vocab ) + +M: vocab-spec >vocab-link ; + +M: string >vocab-link dup vocab [ ] [ ] ?if ; + : forget-vocab ( vocab -- ) dup words forget-all vocab-name dictionary get delete-at ; M: vocab-spec forget* forget-vocab ; - -TUPLE: no-vocab name ; - -: no-vocab ( name -- * ) - vocab-name \ no-vocab construct-boa throw ; diff --git a/core/words/words.factor b/core/words/words.factor index ce69c1ff2e..de253e6fee 100755 --- a/core/words/words.factor +++ b/core/words/words.factor @@ -21,9 +21,7 @@ M: word definer drop \ : \ ; ; M: word definition word-def ; -TUPLE: undefined ; - -: undefined ( -- * ) \ undefined construct-empty throw ; +ERROR: undefined ; PREDICATE: word deferred ( obj -- ? ) word-def [ undefined ] = ; @@ -68,7 +66,7 @@ SYMBOL: bootstrapping? : crossref? ( word -- ? ) { { [ dup "forgotten" word-prop ] [ f ] } - { [ dup "method-def" word-prop ] [ t ] } + { [ dup "method-generic" word-prop ] [ t ] } { [ dup word-vocabulary ] [ t ] } { [ t ] [ f ] } } cond nip ; @@ -169,7 +167,12 @@ SYMBOL: changed-words "declared-effect" "constructor-quot" "delimiter" } reset-props ; +GENERIC: subwords ( word -- seq ) + +M: word subwords drop f ; + : reset-generic ( word -- ) + dup subwords [ forget ] each dup reset-word { "methods" "combination" "default-method" } reset-props ; @@ -184,12 +187,11 @@ SYMBOL: changed-words [ ] [ no-vocab ] ?if set-at ; -TUPLE: check-create name vocab ; +ERROR: bad-create name vocab ; : check-create ( name vocab -- name vocab ) - 2dup [ string? ] both? [ - \ check-create construct-boa throw - ] unless ; + 2dup [ string? ] both? + [ bad-create ] unless ; : create ( name vocab -- word ) check-create 2dup lookup diff --git a/extra/asn1/asn1.factor b/extra/asn1/asn1.factor index 99d1e0a19d..8954ffd8cc 100644 --- a/extra/asn1/asn1.factor +++ b/extra/asn1/asn1.factor @@ -135,18 +135,18 @@ SYMBOL: end GENERIC: >ber ( obj -- byte-array ) M: fixnum >ber ( n -- byte-array ) >128-ber dup length 2 swap 2array - "cc" pack-native swap append ; + "cc" pack-native prepend ; : >ber-enumerated ( n -- byte-array ) >128-ber >byte-array dup length 10 swap 2array - "CC" pack-native swap append ; + "CC" pack-native prepend ; : >ber-length-encoding ( n -- byte-array ) dup 127 <= [ 1array "C" pack-be ] [ 1array "I" pack-be 0 swap remove dup length - HEX: 80 + 1array "C" pack-be swap append + HEX: 80 + 1array "C" pack-be prepend ] if ; ! ========================================================= @@ -158,7 +158,7 @@ M: bignum >ber ( n -- byte-array ) dup 126 > [ "range error in bignum" throw ] [ - 2 swap 2array "CC" pack-native swap append + 2 swap 2array "CC" pack-native prepend ] if ; ! ========================================================= diff --git a/extra/assocs/lib/lib.factor b/extra/assocs/lib/lib.factor index 88095759e6..b23ee1f830 100755 --- a/extra/assocs/lib/lib.factor +++ b/extra/assocs/lib/lib.factor @@ -1,4 +1,5 @@ -USING: assocs kernel vectors sequences namespaces ; +USING: arrays assocs kernel vectors sequences namespaces +random math.parser ; IN: assocs.lib : >set ( seq -- hash ) @@ -35,3 +36,13 @@ IN: assocs.lib [ with each ] curry assoc-each ; inline : insert ( value variable -- ) namespace insert-at ; + +: 2seq>assoc ( keys values exemplar -- assoc ) + >r 2array flip r> assoc-like ; + +: generate-key ( assoc -- str ) + >r 256 random-bits >hex r> + 2dup key? [ nip generate-key ] [ drop ] if ; + +: set-at-unique ( value assoc -- key ) + dup generate-key [ swap set-at ] keep ; diff --git a/extra/automata/automata.factor b/extra/automata/automata.factor index cd799d477e..b6d4152d0e 100644 --- a/extra/automata/automata.factor +++ b/extra/automata/automata.factor @@ -46,7 +46,7 @@ dup >rule-number rule-values rule-keys [ rule> set-at ] 2each ; : pattern>state ( {_a_b_c_} -- state ) rule> at ; -: cap-line ( line -- 0-line-0 ) { 0 } swap append { 0 } append ; +: cap-line ( line -- 0-line-0 ) { 0 } prepend { 0 } append ; : wrap-line ( a-line-z -- za-line-za ) dup peek 1array swap dup first 1array append append ; diff --git a/extra/bitfields/bitfields.factor b/extra/bitfields/bitfields.factor index 211ab28c92..175f66f4a6 100644 --- a/extra/bitfields/bitfields.factor +++ b/extra/bitfields/bitfields.factor @@ -88,7 +88,7 @@ M: check< summary drop "Number exceeds upper bound" ; >r keys r> define-slots ; : define-setters ( classname slots -- ) - >r "with-" swap append r> + >r "with-" prepend r> dup values [setters] >r keys r> define-slots ; diff --git a/extra/bootstrap/help/help.factor b/extra/bootstrap/help/help.factor index 1680278fad..4326fcf61b 100755 --- a/extra/bootstrap/help/help.factor +++ b/extra/bootstrap/help/help.factor @@ -9,11 +9,10 @@ IN: bootstrap.help t load-help? set-global - [ vocab ] load-vocab-hook [ + [ drop ] load-vocab-hook [ vocabs - [ vocab-root ] subset - [ vocab-source-loaded? ] subset - [ dup vocab-docs-loaded? [ drop ] [ load-docs ] if ] each + [ vocab-docs-loaded? not ] subset + [ load-docs ] each ] with-variable ; load-help diff --git a/extra/bootstrap/image/download/download.factor b/extra/bootstrap/image/download/download.factor index df559f49da..a186954ef0 100644 --- a/extra/bootstrap/image/download/download.factor +++ b/extra/bootstrap/image/download/download.factor @@ -18,7 +18,7 @@ bootstrap.image sequences io ; : download-image ( arch -- ) boot-image-name dup need-new-image? [ "Downloading " write dup write "..." print - url swap append download + url prepend download ] [ "Boot image up to date" print drop diff --git a/extra/bootstrap/random/random.factor b/extra/bootstrap/random/random.factor new file mode 100755 index 0000000000..b61e002526 --- /dev/null +++ b/extra/bootstrap/random/random.factor @@ -0,0 +1,13 @@ +USING: vocabs.loader sequences system +random random.mersenne-twister combinators init +namespaces ; + +"random.mersenne-twister" require + +{ + { [ windows? ] [ "random.windows" require ] } + { [ unix? ] [ "random.unix" require ] } +} cond + +[ millis random-generator set-global ] +"generator.random" add-init-hook diff --git a/extra/bootstrap/tools/tools.factor b/extra/bootstrap/tools/tools.factor index 0bf7a032ee..670bca4903 100755 --- a/extra/bootstrap/tools/tools.factor +++ b/extra/bootstrap/tools/tools.factor @@ -13,5 +13,6 @@ USING: vocabs.loader sequences ; "tools.threads" "tools.vocabs" "tools.vocabs.browser" + "tools.vocabs.monitor" "editors" } [ require ] each diff --git a/extra/bootstrap/ui/tools/tools.factor b/extra/bootstrap/ui/tools/tools.factor index c4a555b3e2..a3d02a0016 100755 --- a/extra/bootstrap/ui/tools/tools.factor +++ b/extra/bootstrap/ui/tools/tools.factor @@ -1,7 +1,7 @@ USING: kernel vocabs vocabs.loader sequences system ; { "ui" "help" "tools" } -[ "bootstrap." swap append vocab ] all? [ +[ "bootstrap." prepend vocab ] all? [ "ui.tools" require "ui.cocoa" vocab [ diff --git a/extra/bootstrap/ui/ui.factor b/extra/bootstrap/ui/ui.factor index 86538e0000..f8db831dbc 100644 --- a/extra/bootstrap/ui/ui.factor +++ b/extra/bootstrap/ui/ui.factor @@ -8,7 +8,7 @@ vocabs vocabs.loader ; { [ windows? ] [ "windows" ] } { [ unix? ] [ "x11" ] } } cond - ] unless* "ui." swap append require + ] unless* "ui." prepend require "ui.freetype" require ] when diff --git a/extra/builder/benchmark/benchmark.factor b/extra/builder/benchmark/benchmark.factor index 444e5b6ea7..2f38462976 100644 --- a/extra/builder/benchmark/benchmark.factor +++ b/extra/builder/benchmark/benchmark.factor @@ -4,10 +4,12 @@ USING: kernel continuations arrays assocs sequences sorting math IN: builder.benchmark -: passing-benchmarks ( table -- table ) - [ second first2 number? swap number? and ] subset ; +! : passing-benchmarks ( table -- table ) +! [ second first2 number? swap number? and ] subset ; -: simplify-table ( table -- table ) [ first2 second 2array ] map ; +: passing-benchmarks ( table -- table ) [ second number? ] subset ; + +! : simplify-table ( table -- table ) [ first2 second 2array ] map ; : benchmark-difference ( old-table benchmark-result -- result-diff ) first2 >r @@ -17,7 +19,7 @@ IN: builder.benchmark 2array ; : compare-tables ( old new -- table ) - [ passing-benchmarks simplify-table ] 2apply + [ passing-benchmarks ] 2apply [ benchmark-difference ] with map ; : benchmark-deltas ( -- table ) diff --git a/extra/builder/builder.factor b/extra/builder/builder.factor index 52150b07a8..19734a3266 100644 --- a/extra/builder/builder.factor +++ b/extra/builder/builder.factor @@ -58,8 +58,8 @@ IN: builder ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : copy-image ( -- ) - builds "factor" path+ my-boot-image-name path+ ".." copy-file-into - builds "factor" path+ my-boot-image-name path+ "." copy-file-into ; + builds "factor" append-path my-boot-image-name append-path ".." copy-file-into + builds "factor" append-path my-boot-image-name append-path "." copy-file-into ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -86,7 +86,7 @@ IN: builder +closed+ >>stdin "../test-log" >>stdout +stdout+ >>stderr - 45 minutes >>timeout ; + 120 minutes >>timeout ; : do-builder-test ( -- ) builder-test [ "Test error" print "../test-log" 100 cat-n ] run-or-bail ; @@ -134,7 +134,9 @@ SYMBOL: build-status "Did not pass load-everything: " print "load-everything-vocabs" cat "Did not pass test-all: " print "test-all-vocabs" cat - "test-all-vocabs" eval-file test-failures. + "test-failures" cat + +! "test-failures" eval-file test-failures. "help-lint results:" print "help-lint" cat diff --git a/extra/builder/release/release.factor b/extra/builder/release/release.factor index f0cf0ee113..0e26abe02f 100644 --- a/extra/builder/release/release.factor +++ b/extra/builder/release/release.factor @@ -8,7 +8,7 @@ IN: builder.release ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : releases ( -- path ) - builds "releases" path+ + builds "releases" append-path dup exists? not [ dup make-directory ] when ; diff --git a/extra/builder/util/util.factor b/extra/builder/util/util.factor index 82514ca43d..55ff38d408 100644 --- a/extra/builder/util/util.factor +++ b/extra/builder/util/util.factor @@ -3,7 +3,7 @@ USING: kernel words namespaces classes parser continuations io io.files io.launcher io.sockets math math.parser combinators sequences splitting quotations arrays strings tools.time - sequences.deep new-slots accessors assocs.lib + sequences.deep accessors assocs.lib io.encodings.utf8 combinators.cleave bake calendar calendar.format ; diff --git a/extra/bunny/deploy.factor b/extra/bunny/deploy.factor index a3f6174726..643737b23c 100755 --- a/extra/bunny/deploy.factor +++ b/extra/bunny/deploy.factor @@ -1,14 +1,15 @@ USING: tools.deploy.config ; H{ - { deploy-math? t } - { deploy-reflection 1 } + { deploy-word-defs? f } + { deploy-random? f } { deploy-name "Bunny" } { deploy-threads? t } - { deploy-word-props? f } - { "stop-after-last-window?" t } - { deploy-ui? t } - { deploy-io 3 } { deploy-compiler? t } - { deploy-word-defs? f } + { deploy-math? t } { deploy-c-types? f } + { deploy-io 3 } + { deploy-reflection 1 } + { deploy-ui? t } + { "stop-after-last-window?" t } + { deploy-word-props? f } } diff --git a/extra/bunny/outlined/outlined.factor b/extra/bunny/outlined/outlined.factor index 012aa1fd78..6295e3b9de 100755 --- a/extra/bunny/outlined/outlined.factor +++ b/extra/bunny/outlined/outlined.factor @@ -1,5 +1,5 @@ USING: arrays bunny.model bunny.cel-shaded -combinators.lib continuations kernel math multiline +combinators.cleave continuations kernel math multiline opengl opengl.shaders opengl.framebuffers opengl.gl opengl.capabilities sequences ui.gadgets combinators.cleave ; IN: bunny.outlined diff --git a/extra/cairo-demo/cairo-demo.factor b/extra/cairo-demo/cairo-demo.factor index 316479d53c..29fb99a301 100644 --- a/extra/cairo-demo/cairo-demo.factor +++ b/extra/cairo-demo/cairo-demo.factor @@ -6,7 +6,7 @@ ! http://cairographics.org/samples/text/ -USING: cairo math math.constants byte-arrays kernel ui ui.render +USING: cairo.ffi math math.constants byte-arrays kernel ui ui.render ui.gadgets opengl.gl ; IN: cairo-demo @@ -23,13 +23,15 @@ IN: cairo-demo 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 ; + 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 ; + make-image-array + [ swap set-cairo-gadget-image-array ] keep + convert-array-to-surface ; : init-cairo ( gadget -- cairo_t ) create-surface cairo_create ; @@ -56,7 +58,7 @@ M: cairo-gadget pref-dim* drop { 384 256 0 } ; cairo_fill ; M: cairo-gadget graft* ( gadget -- ) - dup dup init-cairo swap set-cairo-gadget-cairo-t draw-hello-world ; + dup dup init-cairo swap set-cairo-gadget-cairo-t draw-hello-world ; M: cairo-gadget ungraft* ( gadget -- ) cairo-gadget-cairo-t cairo_destroy ; diff --git a/extra/cairo/authors.txt b/extra/cairo/authors.txt index 4a2736dd93..68d35d192b 100644 --- a/extra/cairo/authors.txt +++ b/extra/cairo/authors.txt @@ -1 +1,2 @@ Sampo Vuori +Doug Coleman diff --git a/extra/cairo/cairo.factor b/extra/cairo/ffi/ffi.factor similarity index 99% rename from extra/cairo/cairo.factor rename to extra/cairo/ffi/ffi.factor index 0d3e0c27e6..76ce27975b 100644 --- a/extra/cairo/cairo.factor +++ b/extra/cairo/ffi/ffi.factor @@ -10,10 +10,10 @@ USING: alien alien.syntax combinators system ; -IN: cairo +IN: cairo.ffi << "cairo" { - { [ win32? ] [ "cairo.dll" ] } + { [ win32? ] [ "libcairo-2.dll" ] } ! { [ macosx? ] [ "libcairo.dylib" ] } { [ macosx? ] [ "/opt/local/lib/libcairo.dylib" ] } { [ unix? ] [ "libcairo.so.2" ] } diff --git a/extra/cairo/lib/lib.factor b/extra/cairo/lib/lib.factor new file mode 100755 index 0000000000..1b969978a3 --- /dev/null +++ b/extra/cairo/lib/lib.factor @@ -0,0 +1,40 @@ +! Copyright (C) 2008 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: alien.c-types cairo.ffi continuations destructors +kernel libc locals math combinators.cleave shuffle +accessors ; +IN: cairo.lib + +TUPLE: cairo-t alien ; +C: cairo-t +M: cairo-t dispose ( alien -- ) alien>> cairo_destroy ; +: cairo-t-destroy-always ( alien -- ) add-always-destructor ; +: cairo-t-destroy-later ( alien -- ) add-error-destructor ; + +TUPLE: cairo-surface-t alien ; +C: cairo-surface-t +M: cairo-surface-t dispose ( alien -- ) alien>> cairo_surface_destroy ; + +: cairo-surface-t-destroy-always ( alien -- ) + add-always-destructor ; + +: cairo-surface-t-destroy-later ( alien -- ) + add-error-destructor ; + +: cairo-surface>array ( surface -- cairo-t byte-array ) + [ + dup + [ drop CAIRO_FORMAT_ARGB32 ] + [ cairo_image_surface_get_width ] + [ cairo_image_surface_get_height ] tri + over 4 * + 2dup * [ + malloc dup free-always [ + 5 -nrot cairo_image_surface_create_for_data + dup cairo-surface-t-destroy-always + cairo_create dup cairo-t-destroy-later + [ swap 0 0 cairo_set_source_surface ] keep + dup cairo_paint + ] keep + ] keep memory>byte-array + ] with-destructors ; diff --git a/extra/cairo/png/png.factor b/extra/cairo/png/png.factor new file mode 100755 index 0000000000..55828cde9c --- /dev/null +++ b/extra/cairo/png/png.factor @@ -0,0 +1,45 @@ +! Copyright (C) 2008 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: arrays combinators.cleave kernel +accessors math ui.gadgets ui.render opengl.gl byte-arrays +namespaces opengl cairo.ffi cairo.lib ; +IN: cairo.png + +TUPLE: png surface width height cairo-t array ; +TUPLE: png-gadget png ; + +: ( path -- png ) + cairo_image_surface_create_from_png + dup [ cairo_image_surface_get_width ] + [ cairo_image_surface_get_height ] [ ] tri + cairo-surface>array png construct-boa ; + +: write-png ( png path -- ) + >r png-surface r> + cairo_surface_write_to_png + zero? [ "write png failed" throw ] unless ; + +: ( path -- gadget ) + png-gadget construct-gadget swap + >>png ; + +M: png-gadget pref-dim* ( gadget -- ) + png>> + [ width>> ] [ height>> ] bi 2array ; + +M: png-gadget draw-gadget* ( gadget -- ) + origin get [ + 0 0 glRasterPos2i + 1.0 -1.0 glPixelZoom + png>> + [ width>> ] + [ height>> GL_RGBA GL_UNSIGNED_BYTE ] + [ array>> ] tri + glDrawPixels + ] with-translation ; + +M: png-gadget graft* ( gadget -- ) + drop ; + +M: png-gadget ungraft* ( gadget -- ) + png>> surface>> cairo_destroy ; diff --git a/extra/calendar/backend/backend.factor b/extra/calendar/backend/backend.factor index 15b5e7cb8d..01c36c65ae 100644 --- a/extra/calendar/backend/backend.factor +++ b/extra/calendar/backend/backend.factor @@ -2,4 +2,4 @@ USING: kernel ; IN: calendar.backend SYMBOL: calendar-backend -HOOK: gmt-offset calendar-backend +HOOK: gmt-offset calendar-backend ( -- hours minutes seconds ) diff --git a/extra/calendar/calendar-tests.factor b/extra/calendar/calendar-tests.factor index 1041c79691..e49d3ad894 100755 --- a/extra/calendar/calendar-tests.factor +++ b/extra/calendar/calendar-tests.factor @@ -2,14 +2,14 @@ USING: arrays calendar kernel math sequences tools.test continuations system ; IN: calendar.tests -[ f ] [ 2004 12 32 0 0 0 0 valid-timestamp? ] unit-test -[ f ] [ 2004 2 30 0 0 0 0 valid-timestamp? ] unit-test -[ f ] [ 2003 2 29 0 0 0 0 valid-timestamp? ] unit-test -[ f ] [ 2004 -2 9 0 0 0 0 valid-timestamp? ] unit-test -[ f ] [ 2004 12 0 0 0 0 0 valid-timestamp? ] unit-test -[ f ] [ 2004 12 1 24 0 0 0 valid-timestamp? ] unit-test -[ f ] [ 2004 12 1 23 60 0 0 valid-timestamp? ] unit-test -[ f ] [ 2004 12 1 23 59 60 0 valid-timestamp? ] unit-test +[ f ] [ 2004 12 32 0 0 0 instant valid-timestamp? ] unit-test +[ f ] [ 2004 2 30 0 0 0 instant valid-timestamp? ] unit-test +[ f ] [ 2003 2 29 0 0 0 instant valid-timestamp? ] unit-test +[ f ] [ 2004 -2 9 0 0 0 instant valid-timestamp? ] unit-test +[ f ] [ 2004 12 0 0 0 0 instant valid-timestamp? ] unit-test +[ f ] [ 2004 12 1 24 0 0 instant valid-timestamp? ] unit-test +[ f ] [ 2004 12 1 23 60 0 instant valid-timestamp? ] unit-test +[ f ] [ 2004 12 1 23 59 60 instant valid-timestamp? ] unit-test [ t ] [ now valid-timestamp? ] unit-test [ f ] [ 1900 leap-year? ] unit-test @@ -18,126 +18,126 @@ IN: calendar.tests [ f ] [ 2001 leap-year? ] unit-test [ f ] [ 2006 leap-year? ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 1 seconds time+ - 2006 10 10 0 0 1 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 100 seconds time+ - 2006 10 10 0 1 40 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 -100 seconds time+ - 2006 10 9 23 58 20 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 86400 seconds time+ - 2006 10 11 0 0 0 0 = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 1 seconds time+ + 2006 10 10 0 0 1 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 100 seconds time+ + 2006 10 10 0 1 40 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant -100 seconds time+ + 2006 10 9 23 58 20 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 86400 seconds time+ + 2006 10 11 0 0 0 instant = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 10 minutes time+ - 2006 10 10 0 10 0 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 10.5 minutes time+ - 2006 10 10 0 10 30 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 3/4 minutes time+ - 2006 10 10 0 0 45 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 -3/4 minutes time+ - 2006 10 9 23 59 15 0 = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 10 minutes time+ + 2006 10 10 0 10 0 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 10.5 minutes time+ + 2006 10 10 0 10 30 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 3/4 minutes time+ + 2006 10 10 0 0 45 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant -3/4 minutes time+ + 2006 10 9 23 59 15 instant = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 7200 minutes time+ - 2006 10 15 0 0 0 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 -10 minutes time+ - 2006 10 9 23 50 0 0 = ] unit-test -[ t ] [ 2006 10 10 0 0 0 0 -100 minutes time+ - 2006 10 9 22 20 0 0 = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant 7200 minutes time+ + 2006 10 15 0 0 0 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant -10 minutes time+ + 2006 10 9 23 50 0 instant = ] unit-test +[ t ] [ 2006 10 10 0 0 0 instant -100 minutes time+ + 2006 10 9 22 20 0 instant = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 1 hours time+ - 2006 1 1 1 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 24 hours time+ - 2006 1 2 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -24 hours time+ - 2005 12 31 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 12 hours time+ - 2006 1 1 12 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 72 hours time+ - 2006 1 4 0 0 0 0 = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 1 hours time+ + 2006 1 1 1 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 24 hours time+ + 2006 1 2 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -24 hours time+ + 2005 12 31 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 12 hours time+ + 2006 1 1 12 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 72 hours time+ + 2006 1 4 0 0 0 instant = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 1 days time+ - 2006 1 2 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -1 days time+ - 2005 12 31 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 365 days time+ - 2007 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -365 days time+ - 2005 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2004 1 1 0 0 0 0 365 days time+ - 2004 12 31 0 0 0 0 = ] unit-test -[ t ] [ 2004 1 1 0 0 0 0 366 days time+ - 2005 1 1 0 0 0 0 = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 1 days time+ + 2006 1 2 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -1 days time+ + 2005 12 31 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 365 days time+ + 2007 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -365 days time+ + 2005 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2004 1 1 0 0 0 instant 365 days time+ + 2004 12 31 0 0 0 instant = ] unit-test +[ t ] [ 2004 1 1 0 0 0 instant 366 days time+ + 2005 1 1 0 0 0 instant = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 11 months time+ - 2006 12 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 12 months time+ - 2007 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 24 months time+ - 2008 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 13 months time+ - 2007 2 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 1 months time+ - 2006 2 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 0 months time+ - 2006 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -1 months time+ - 2005 12 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -2 months time+ - 2005 11 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -13 months time+ - 2004 12 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -24 months time+ - 2004 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2004 2 29 0 0 0 0 12 months time+ - 2005 3 1 0 0 0 0 = ] unit-test -[ t ] [ 2004 2 29 0 0 0 0 -12 months time+ - 2003 3 1 0 0 0 0 = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 11 months time+ + 2006 12 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 12 months time+ + 2007 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 24 months time+ + 2008 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 13 months time+ + 2007 2 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 1 months time+ + 2006 2 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 0 months time+ + 2006 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -1 months time+ + 2005 12 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -2 months time+ + 2005 11 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -13 months time+ + 2004 12 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -24 months time+ + 2004 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2004 2 29 0 0 0 instant 12 months time+ + 2005 3 1 0 0 0 instant = ] unit-test +[ t ] [ 2004 2 29 0 0 0 instant -12 months time+ + 2003 3 1 0 0 0 instant = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 0 years time+ - 2006 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 1 years time+ - 2007 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -1 years time+ - 2005 1 1 0 0 0 0 = ] unit-test -[ t ] [ 2006 1 1 0 0 0 0 -100 years time+ - 1906 1 1 0 0 0 0 = ] unit-test -! [ t ] [ 2004 2 29 0 0 0 0 -1 years time+ -! 2003 2 28 0 0 0 0 = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 0 years time+ + 2006 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant 1 years time+ + 2007 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -1 years time+ + 2005 1 1 0 0 0 instant = ] unit-test +[ t ] [ 2006 1 1 0 0 0 instant -100 years time+ + 1906 1 1 0 0 0 instant = ] unit-test +! [ t ] [ 2004 2 29 0 0 0 instant -1 years time+ +! 2003 2 28 0 0 0 instant = ] unit-test -[ 5 ] [ 2006 7 14 0 0 0 0 day-of-week ] unit-test +[ 5 ] [ 2006 7 14 0 0 0 instant day-of-week ] unit-test -[ t ] [ 2006 7 14 [ julian-day-number julian-day-number>date 0 0 0 0 ] 3keep 0 0 0 0 = ] unit-test +[ t ] [ 2006 7 14 [ julian-day-number julian-day-number>date 0 0 0 instant ] 3keep 0 0 0 instant = ] unit-test -[ 1 ] [ 2006 1 1 0 0 0 0 day-of-year ] unit-test -[ 60 ] [ 2004 2 29 0 0 0 0 day-of-year ] unit-test -[ 61 ] [ 2004 3 1 0 0 0 0 day-of-year ] unit-test -[ 366 ] [ 2004 12 31 0 0 0 0 day-of-year ] unit-test -[ 365 ] [ 2003 12 31 0 0 0 0 day-of-year ] unit-test -[ 60 ] [ 2003 3 1 0 0 0 0 day-of-year ] unit-test +[ 1 ] [ 2006 1 1 0 0 0 instant day-of-year ] unit-test +[ 60 ] [ 2004 2 29 0 0 0 instant day-of-year ] unit-test +[ 61 ] [ 2004 3 1 0 0 0 instant day-of-year ] unit-test +[ 366 ] [ 2004 12 31 0 0 0 instant day-of-year ] unit-test +[ 365 ] [ 2003 12 31 0 0 0 instant day-of-year ] unit-test +[ 60 ] [ 2003 3 1 0 0 0 instant day-of-year ] unit-test -[ t ] [ 2004 12 31 0 0 0 0 dup = ] unit-test -[ t ] [ 2004 1 1 0 0 0 0 10 seconds 5 years time+ time+ - 2009 1 1 0 0 10 0 = ] unit-test -[ t ] [ 2004 1 1 0 0 0 0 -10 seconds -5 years time+ time+ - 1998 12 31 23 59 50 0 = ] unit-test +[ t ] [ 2004 12 31 0 0 0 instant dup = ] unit-test +[ t ] [ 2004 1 1 0 0 0 instant 10 seconds 5 years time+ time+ + 2009 1 1 0 0 10 instant = ] unit-test +[ t ] [ 2004 1 1 0 0 0 instant -10 seconds -5 years time+ time+ + 1998 12 31 23 59 50 instant = ] unit-test -[ t ] [ 2004 1 1 23 0 0 12 0 convert-timezone - 2004 1 1 11 0 0 0 = ] unit-test -[ t ] [ 2004 1 1 5 0 0 -11 0 convert-timezone - 2004 1 1 16 0 0 0 = ] unit-test -[ t ] [ 2004 1 1 23 0 0 9+1/2 0 convert-timezone - 2004 1 1 13 30 0 0 = ] unit-test +[ t ] [ 2004 1 1 23 0 0 12 hours >gmt + 2004 1 1 11 0 0 instant = ] unit-test +[ t ] [ 2004 1 1 5 0 0 -11 hours >gmt + 2004 1 1 16 0 0 instant = ] unit-test +[ t ] [ 2004 1 1 23 0 0 9+1/2 hours >gmt + 2004 1 1 13 30 0 instant = ] unit-test -[ 0 ] [ 2004 1 1 13 30 0 0 - 2004 1 1 12 30 0 -1 <=> ] unit-test +[ 0 ] [ 2004 1 1 13 30 0 instant + 2004 1 1 12 30 0 -1 hours <=> ] unit-test -[ 1 ] [ 2004 1 1 13 30 0 0 - 2004 1 1 12 30 0 0 <=> ] unit-test +[ 1 ] [ 2004 1 1 13 30 0 instant + 2004 1 1 12 30 0 instant <=> ] unit-test -[ -1 ] [ 2004 1 1 12 30 0 0 - 2004 1 1 13 30 0 0 <=> ] unit-test +[ -1 ] [ 2004 1 1 12 30 0 instant + 2004 1 1 13 30 0 instant <=> ] unit-test -[ 1 ] [ 2005 1 1 12 30 0 0 - 2004 1 1 13 30 0 0 <=> ] unit-test +[ 1 ] [ 2005 1 1 12 30 0 instant + 2004 1 1 13 30 0 instant <=> ] unit-test [ t ] [ now timestamp>millis millis - 1000 < ] unit-test [ t ] [ 0 millis>timestamp unix-1970 = ] unit-test diff --git a/extra/calendar/calendar.factor b/extra/calendar/calendar.factor index 2b80a8dce6..06425975d4 100755 --- a/extra/calendar/calendar.factor +++ b/extra/calendar/calendar.factor @@ -3,20 +3,23 @@ USING: arrays kernel math math.functions namespaces sequences strings tuples system vocabs.loader calendar.backend threads -new-slots accessors combinators ; +accessors combinators locals ; IN: calendar TUPLE: timestamp year month day hour minute second gmt-offset ; C: timestamp -: ( year month day -- timestamp ) - 0 0 0 gmt-offset ; - TUPLE: duration year month day hour minute second ; C: duration +: gmt-offset-duration ( -- duration ) + 0 0 0 gmt-offset ; + +: ( year month day -- timestamp ) + 0 0 0 gmt-offset-duration ; + : month-names { "Not a month" "January" "February" "March" "April" "May" "June" @@ -56,31 +59,29 @@ SYMBOL: m PRIVATE> -: julian-day-number ( year month day -- n ) +:: julian-day-number ( year month day -- n ) #! Returns a composite date number #! Not valid before year -4800 - [ - 14 pick - 12 /i a set - pick 4800 + a get - y set - over 12 a get * + 3 - m set - 2nip 153 m get * 2 + 5 /i + 365 y get * + - y get 4 /i + y get 100 /i - y get 400 /i + 32045 - - ] with-scope ; + [let* | a [ 14 month - 12 /i ] + y [ year 4800 + a - ] + m [ month 12 a * + 3 - ] | + day 153 m * 2 + 5 /i + 365 y * + + y 4 /i + y 100 /i - y 400 /i + 32045 - + ] ; -: julian-day-number>date ( n -- year month day ) +:: julian-day-number>date ( n -- year month day ) #! Inverse of julian-day-number - [ - 32044 + a set - 4 a get * 3 + 146097 /i b set - a get 146097 b get * 4 /i - c set - 4 c get * 3 + 1461 /i d set - c get 1461 d get * 4 /i - e set - 5 e get * 2 + 153 /i m set - 100 b get * d get + 4800 - - m get 10 /i + m get 3 + - 12 m get 10 /i * - - e get 153 m get * 2 + 5 /i - 1+ - ] with-scope ; + [let* | a [ n 32044 + ] + b [ 4 a * 3 + 146097 /i ] + c [ a 146097 b * 4 /i - ] + d [ 4 c * 3 + 1461 /i ] + e [ c 1461 d * 4 /i - ] + m [ 5 e * 2 + 153 /i ] | + 100 b * d + 4800 - + m 10 /i + m 3 + + 12 m 10 /i * - + e 153 m * 2 + 5 /i - 1+ + ] ; : >date< ( timestamp -- year month day ) { year>> month>> day>> } get-slots ; @@ -226,16 +227,18 @@ M: duration <=> [ dt>years ] compare ; : dt>seconds ( dt -- x ) dt>years seconds-per-year * ; : dt>milliseconds ( dt -- x ) dt>seconds 1000 * ; -: convert-timezone ( timestamp n -- timestamp ) +GENERIC: time- ( time1 time2 -- time ) + +: convert-timezone ( timestamp duration -- timestamp ) over gmt-offset>> over = [ drop ] [ - [ over gmt-offset>> - hours time+ ] keep >>gmt-offset + [ over gmt-offset>> time- time+ ] keep >>gmt-offset ] if ; : >local-time ( timestamp -- timestamp ) - gmt-offset convert-timezone ; + gmt-offset-duration convert-timezone ; : >gmt ( timestamp -- timestamp ) - 0 convert-timezone ; + instant convert-timezone ; M: timestamp <=> ( ts1 ts2 -- n ) [ >gmt tuple-slots ] compare ; @@ -245,8 +248,6 @@ M: timestamp <=> ( ts1 ts2 -- n ) [ [ >date< julian-day-number ] 2apply - 86400 * ] 2keep [ >time< >r >r 3600 * r> 60 * r> + + ] 2apply - + ; -GENERIC: time- ( time1 time2 -- time ) - M: timestamp time- #! Exact calendar-time difference (time-) seconds ; @@ -263,14 +264,14 @@ M: timestamp time- M: duration time- before time+ ; -: 0 0 0 0 0 0 0 ; +: 0 0 0 0 0 0 instant ; : valid-timestamp? ( timestamp -- ? ) - clone 0 >>gmt-offset + clone instant >>gmt-offset dup time- time+ = ; : unix-1970 ( -- timestamp ) - 1970 1 1 0 0 0 0 ; foldable + 1970 1 1 0 0 0 instant ; foldable : millis>timestamp ( n -- timestamp ) >r unix-1970 r> milliseconds time+ ; diff --git a/extra/calendar/format/format-tests.factor b/extra/calendar/format/format-tests.factor index eb32ce5b43..88bd0733c0 100755 --- a/extra/calendar/format/format-tests.factor +++ b/extra/calendar/format/format-tests.factor @@ -1,5 +1,6 @@ +USING: calendar.format calendar kernel tools.test +io.streams.string ; IN: calendar.format.tests -USING: calendar.format tools.test io.streams.string ; [ 0 ] [ "Z" [ read-rfc3339-gmt-offset ] with-string-reader @@ -20,3 +21,6 @@ USING: calendar.format tools.test io.streams.string ; [ 1+1/2 ] [ "+01:30" [ read-rfc3339-gmt-offset ] with-string-reader ] unit-test + +[ ] [ now timestamp>rfc3339 drop ] unit-test +[ ] [ now timestamp>rfc822 drop ] unit-test diff --git a/extra/calendar/format/format.factor b/extra/calendar/format/format.factor index 89e09e0d0c..0ac0ebb2c3 100755 --- a/extra/calendar/format/format.factor +++ b/extra/calendar/format/format.factor @@ -1,6 +1,7 @@ -IN: calendar.format USING: math math.parser kernel sequences io calendar -accessors arrays io.streams.string combinators accessors ; +accessors arrays io.streams.string combinators accessors +combinators.cleave ; +IN: calendar.format GENERIC: day. ( obj -- ) @@ -54,17 +55,17 @@ M: timestamp year. ( timestamp -- ) : timestamp>string ( timestamp -- str ) [ (timestamp>string) ] with-string-writer ; -: (write-gmt-offset) ( ratio -- ) - 1 /mod swap write-00 60 * write-00 ; +: (write-gmt-offset) ( duration -- ) + [ hour>> write-00 ] [ minute>> write-00 ] bi ; : write-gmt-offset ( gmt-offset -- ) - { - { [ dup zero? ] [ drop "GMT" write ] } - { [ dup 0 < ] [ "-" write neg (write-gmt-offset) ] } - { [ dup 0 > ] [ "+" write (write-gmt-offset) ] } + dup instant <=> { + { [ dup 0 = ] [ 2drop "GMT" write ] } + { [ dup 0 < ] [ drop "-" write before (write-gmt-offset) ] } + { [ dup 0 > ] [ drop "+" write (write-gmt-offset) ] } } cond ; -: timestamp>rfc822-string ( timestamp -- str ) +: timestamp>rfc822 ( timestamp -- str ) #! RFC822 timestamp format #! Example: Tue, 15 Nov 1994 08:12:31 +0200 [ @@ -76,14 +77,19 @@ M: timestamp year. ( timestamp -- ) : timestamp>http-string ( timestamp -- str ) #! http timestamp format #! Example: Tue, 15 Nov 1994 08:12:31 GMT - >gmt timestamp>rfc822-string ; + >gmt timestamp>rfc822 ; -: write-rfc3339-gmt-offset ( n -- ) - dup zero? [ drop "Z" write ] [ - dup 0 < [ CHAR: - write1 neg ] [ CHAR: + write1 ] if - 60 * 60 /mod swap write-00 CHAR: : write1 write-00 - ] if ; +: (write-rfc3339-gmt-offset) ( duration -- ) + [ hour>> write-00 CHAR: : write1 ] + [ minute>> write-00 ] bi ; +: write-rfc3339-gmt-offset ( duration -- ) + dup instant <=> { + { [ dup 0 = ] [ 2drop "Z" write ] } + { [ dup 0 < ] [ drop CHAR: - write1 before (write-rfc3339-gmt-offset) ] } + { [ dup 0 > ] [ drop CHAR: + write1 (write-rfc3339-gmt-offset) ] } + } cond ; + : (timestamp>rfc3339) ( timestamp -- ) dup year>> number>string write CHAR: - write1 dup month>> write-00 CHAR: - write1 diff --git a/extra/calendar/unix/unix.factor b/extra/calendar/unix/unix.factor index 30e22c487b..2877fa07b5 100644 --- a/extra/calendar/unix/unix.factor +++ b/extra/calendar/unix/unix.factor @@ -1,6 +1,5 @@ - USING: alien alien.c-types arrays calendar.backend - kernel structs math unix.time namespaces ; +kernel structs math unix.time namespaces ; IN: calendar.unix @@ -8,11 +7,11 @@ TUPLE: unix-calendar ; T{ unix-calendar } calendar-backend set-global -: get-time +: get-time ( -- alien ) f time localtime ; -: timezone-name +: timezone-name ( -- string ) get-time tm-zone ; -M: unix-calendar gmt-offset - get-time tm-gmtoff 3600 / ; +M: unix-calendar gmt-offset ( -- hours minutes seconds ) + get-time tm-gmtoff 3600 /mod 60 /mod ; diff --git a/extra/calendar/windows/windows.factor b/extra/calendar/windows/windows.factor index 9e34fdac00..6986902ff1 100755 --- a/extra/calendar/windows/windows.factor +++ b/extra/calendar/windows/windows.factor @@ -1,15 +1,21 @@ USING: calendar.backend namespaces alien.c-types -windows windows.kernel32 kernel math ; +windows windows.kernel32 kernel math combinators.cleave +combinators ; IN: calendar.windows TUPLE: windows-calendar ; T{ windows-calendar } calendar-backend set-global -: TIME_ZONE_ID_INVALID HEX: ffffffff ; inline - -M: windows-calendar gmt-offset ( -- float ) +M: windows-calendar gmt-offset ( -- hours minutes seconds ) "TIME_ZONE_INFORMATION" - dup GetTimeZoneInformation - TIME_ZONE_ID_INVALID = [ win32-error ] when - TIME_ZONE_INFORMATION-Bias 60 / neg ; + dup GetTimeZoneInformation { + { [ dup TIME_ZONE_ID_INVALID = ] [ win32-error-string throw ] } + { [ dup [ TIME_ZONE_ID_UNKNOWN = ] [ TIME_ZONE_ID_STANDARD = ] bi or ] [ + drop TIME_ZONE_INFORMATION-Bias ] } + { [ dup TIME_ZONE_ID_DAYLIGHT = ] [ + drop + [ TIME_ZONE_INFORMATION-Bias ] + [ TIME_ZONE_INFORMATION-DaylightBias ] bi + + ] } + } cond neg 60 /mod 0 ; diff --git a/extra/channels/remote/remote.factor b/extra/channels/remote/remote.factor index 2d8d003b8d..c9cfc83d27 100755 --- a/extra/channels/remote/remote.factor +++ b/extra/channels/remote/remote.factor @@ -14,7 +14,7 @@ IN: channels.remote PRIVATE> : publish ( channel -- id ) - random-256 dup >r remote-channels set-at r> ; + 256 random-bits dup >r remote-channels set-at r> ; : get-channel ( id -- channel ) remote-channels at ; diff --git a/extra/circular/circular-tests.factor b/extra/circular/circular-tests.factor old mode 100644 new mode 100755 index 8ca4574885..9023ab1dba --- a/extra/circular/circular-tests.factor +++ b/extra/circular/circular-tests.factor @@ -9,7 +9,6 @@ circular strings ; [ CHAR: t ] [ "test" 0 swap nth ] unit-test [ "test" ] [ "test" >string ] unit-test -[ "test" 5 swap nth ] must-fail [ CHAR: e ] [ "test" 5 swap nth-unsafe ] unit-test [ [ 1 2 3 ] ] [ { 1 2 3 } [ ] like ] unit-test @@ -18,10 +17,13 @@ circular strings ; [ [ 3 1 2 ] ] [ { 1 2 3 } -100 over change-circular-start [ ] like ] unit-test [ "fob" ] [ "foo" CHAR: b 2 pick set-nth >string ] unit-test -[ "foo" CHAR: b 3 rot set-nth ] must-fail [ "boo" ] [ "foo" CHAR: b 3 pick set-nth-unsafe >string ] unit-test [ "ornact" ] [ "factor" 4 over change-circular-start CHAR: n 2 pick set-nth >string ] unit-test [ "bcd" ] [ 3 "abcd" [ over push-circular ] each >string ] unit-test [ { 0 0 } ] [ { 0 0 } -1 over change-circular-start >array ] unit-test + +! This no longer fails +! [ "test" 5 swap nth ] must-fail +! [ "foo" CHAR: b 3 rot set-nth ] must-fail diff --git a/extra/circular/circular.factor b/extra/circular/circular.factor old mode 100644 new mode 100755 index 8760e26586..08deb004e8 --- a/extra/circular/circular.factor +++ b/extra/circular/circular.factor @@ -18,9 +18,9 @@ M: circular length circular-seq length ; M: circular virtual@ circular-wrap circular-seq ; -M: circular nth bounds-check virtual@ nth ; +M: circular nth virtual@ nth ; -M: circular set-nth bounds-check virtual@ set-nth ; +M: circular set-nth virtual@ set-nth ; : change-circular-start ( n circular -- ) #! change start to (start + n) mod length diff --git a/extra/cocoa/messages/messages.factor b/extra/cocoa/messages/messages.factor index e2072f441c..480e19b005 100755 --- a/extra/cocoa/messages/messages.factor +++ b/extra/cocoa/messages/messages.factor @@ -59,7 +59,7 @@ objc-methods global [ H{ } assoc-like ] change-at : lookup-method ( selector -- method ) dup objc-methods get at - [ ] [ "No such method: " swap append throw ] ?if ; + [ ] [ "No such method: " prepend throw ] ?if ; : make-dip ( quot n -- quot' ) dup @@ -90,7 +90,7 @@ MACRO: (send) ( selector super? -- quot ) ! Runtime introspection : (objc-class) ( string word -- class ) dupd execute - [ ] [ "No such class: " swap append throw ] ?if ; inline + [ ] [ "No such class: " prepend throw ] ?if ; inline : objc-class ( string -- class ) \ objc_getClass (objc-class) ; diff --git a/extra/cocoa/windows/windows.factor b/extra/cocoa/windows/windows.factor index b45acaf852..74a181f9a2 100755 --- a/extra/cocoa/windows/windows.factor +++ b/extra/cocoa/windows/windows.factor @@ -30,7 +30,8 @@ IN: cocoa.windows : ( view rect -- window ) [ swap -> setContentView: ] keep dup dup -> contentView -> setInitialFirstResponder: - dup 1 -> setAcceptsMouseMovedEvents: ; + dup 1 -> setAcceptsMouseMovedEvents: + dup 0 -> setReleasedWhenClosed: ; : window-content-rect ( window -- rect ) NSWindow over -> frame rot -> styleMask diff --git a/extra/combinators/cleave/cleave.factor b/extra/combinators/cleave/cleave.factor index fd66536c12..1bc7480198 100644 --- a/extra/combinators/cleave/cleave.factor +++ b/extra/combinators/cleave/cleave.factor @@ -54,6 +54,8 @@ MACRO: 2cleave ( seq -- ) : bi* ( x y p q -- p(x) q(y) ) >r swap slip r> call ; inline +: 2bi* ( w x y z p q -- p(x) q(y) ) >r -rot 2slip r> call ; inline + : tri* ( x y z p q r -- p(x) q(y) r(z) ) >r rot >r bi* r> r> call ; inline @@ -68,5 +70,31 @@ MACRO: spread ( seq -- ) dup [ drop [ >r ] ] map concat swap - [ [ r> ] swap append ] map concat + [ [ r> ] prepend ] map concat append ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! Cleave into array +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +USING: words quotations fry arrays.lib ; + +: >quot ( obj -- quot ) dup word? [ 1quotation ] when ; + +: >quots ( seq -- seq ) [ >quot ] map ; + +MACRO: ( seq -- ) + [ >quots ] [ length ] bi + '[ , cleave , narray ] ; + +MACRO: <2arr> ( seq -- ) + [ >quots ] [ length ] bi + '[ , 2cleave , narray ] ; + +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! Spread into array +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +MACRO: ( seq -- ) + [ >quots ] [ length ] bi + '[ , spread , narray ] ; diff --git a/extra/combinators/lib/lib.factor b/extra/combinators/lib/lib.factor index 7c93f805cd..459938c885 100755 --- a/extra/combinators/lib/lib.factor +++ b/extra/combinators/lib/lib.factor @@ -8,13 +8,6 @@ continuations ; IN: combinators.lib -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -: generate ( generator predicate -- obj ) - #! Call 'generator' until the result satisfies 'predicate'. - [ slip over slip ] 2keep - roll [ 2drop ] [ rot drop generate ] if ; inline - ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Generalized versions of core combinators ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -82,11 +75,11 @@ MACRO: && ( quots -- ? ) [ [ not ] append [ f ] ] t short-circuit ; MACRO: <-&& ( quots -- ) - [ [ dup ] swap append [ not ] append [ f ] ] t short-circuit + [ [ dup ] prepend [ not ] append [ f ] ] t short-circuit [ nip ] append ; MACRO: <--&& ( quots -- ) - [ [ 2dup ] swap append [ not ] append [ f ] ] t short-circuit + [ [ 2dup ] prepend [ not ] append [ f ] ] t short-circuit [ 2nip ] append ; MACRO: || ( quots -- ? ) [ [ t ] ] f short-circuit ; @@ -137,11 +130,14 @@ MACRO: map-call-with ( quots -- ) [ (make-call-with) ] keep length [ narray ] curry compose ; : (make-call-with2) ( quots -- quot ) - [ [ 2dup >r >r ] swap append [ r> r> ] append ] map concat + [ [ 2dup >r >r ] prepend [ r> r> ] append ] map concat [ 2drop ] append ; MACRO: map-call-with2 ( quots -- ) - [ (make-call-with2) ] keep length [ narray ] curry append ; + [ + [ [ 2dup >r >r ] prepend [ r> r> ] append ] map concat + [ 2drop ] append + ] keep length [ narray ] curry append ; MACRO: map-exec-with ( words -- ) [ 1quotation ] map [ map-call-with ] curry ; @@ -163,5 +159,19 @@ MACRO: construct-slots ( assoc tuple-class -- tuple ) : and? ( obj quot1 quot2 -- ? ) >r keep r> rot [ call ] [ 2drop f ] if ; inline +MACRO: multikeep ( word out-indexes -- ... ) + [ + dup >r [ \ npick \ >r 3array % ] each + % + r> [ drop \ r> , ] each + ] [ ] make ; + : retry ( quot n -- ) [ drop ] rot compose attempt-all ; inline + +: do-while ( pred body tail -- ) + >r tuck 2slip r> while ; + +: generate ( generator predicate -- obj ) + [ dup ] swap [ dup [ nip ] unless not ] 3compose + swap [ ] do-while ; diff --git a/extra/concurrency/distributed/distributed.factor b/extra/concurrency/distributed/distributed.factor index c0787a96a2..c007e9f152 100755 --- a/extra/concurrency/distributed/distributed.factor +++ b/extra/concurrency/distributed/distributed.factor @@ -3,7 +3,7 @@ USING: serialize sequences concurrency.messaging threads io io.server qualified arrays namespaces kernel io.encodings.binary combinators.cleave -new-slots accessors ; +accessors ; QUALIFIED: io.sockets IN: concurrency.distributed diff --git a/extra/concurrency/mailboxes/mailboxes-docs.factor b/extra/concurrency/mailboxes/mailboxes-docs.factor index 4937ef1fb9..50694776c5 100755 --- a/extra/concurrency/mailboxes/mailboxes-docs.factor +++ b/extra/concurrency/mailboxes/mailboxes-docs.factor @@ -49,8 +49,8 @@ HELP: while-mailbox-empty { $description "Repeatedly call the quotation while there are no items in the mailbox." } ; HELP: mailbox-get? -{ $values { "pred" "a quotation with stack effect " { $snippet "( X -- bool )" } } - { "mailbox" mailbox } +{ $values { "mailbox" mailbox } + { "pred" "a quotation with stack effect " { $snippet "( X -- bool )" } } { "obj" object } } { $description "Get the first item in the mailbox which satisfies the predicate. 'pred' will be called repeatedly for each item in the mailbox. When 'pred' returns true that item will be returned. If nothing in the mailbox satisfies the predicate then the thread will block until something does." } ; diff --git a/extra/concurrency/mailboxes/mailboxes-tests.factor b/extra/concurrency/mailboxes/mailboxes-tests.factor index 24d83b2961..2cb12bcaba 100755 --- a/extra/concurrency/mailboxes/mailboxes-tests.factor +++ b/extra/concurrency/mailboxes/mailboxes-tests.factor @@ -16,9 +16,9 @@ tools.test math kernel strings ; [ V{ 1 2 3 } ] [ 0 - [ [ integer? ] swap mailbox-get? swap push ] in-thread - [ [ integer? ] swap mailbox-get? swap push ] in-thread - [ [ integer? ] swap mailbox-get? swap push ] in-thread + [ [ integer? ] mailbox-get? swap push ] in-thread + [ [ integer? ] mailbox-get? swap push ] in-thread + [ [ integer? ] mailbox-get? swap push ] in-thread 1 over mailbox-put 2 over mailbox-put 3 swap mailbox-put @@ -27,10 +27,10 @@ tools.test math kernel strings ; [ V{ 1 "junk" 3 "junk2" } [ 456 ] ] [ 0 - [ [ integer? ] swap mailbox-get? swap push ] in-thread - [ [ integer? ] swap mailbox-get? swap push ] in-thread - [ [ string? ] swap mailbox-get? swap push ] in-thread - [ [ string? ] swap mailbox-get? swap push ] in-thread + [ [ integer? ] mailbox-get? swap push ] in-thread + [ [ integer? ] mailbox-get? swap push ] in-thread + [ [ string? ] mailbox-get? swap push ] in-thread + [ [ string? ] mailbox-get? swap push ] in-thread 1 over mailbox-put "junk" over mailbox-put [ 456 ] over mailbox-put diff --git a/extra/concurrency/mailboxes/mailboxes.factor b/extra/concurrency/mailboxes/mailboxes.factor index 28b2fb7221..7b6405679f 100755 --- a/extra/concurrency/mailboxes/mailboxes.factor +++ b/extra/concurrency/mailboxes/mailboxes.factor @@ -17,17 +17,17 @@ TUPLE: mailbox threads data ; [ mailbox-data push-front ] keep mailbox-threads notify-all yield ; -: block-unless-pred ( pred mailbox timeout -- ) - 2over mailbox-data dlist-contains? [ +: block-unless-pred ( mailbox timeout pred -- ) + pick mailbox-data over dlist-contains? [ 3drop ] [ - 2dup >r mailbox-threads r> "mailbox" wait + >r over mailbox-threads over "mailbox" wait r> block-unless-pred ] if ; inline : block-if-empty ( mailbox timeout -- mailbox ) over mailbox-empty? [ - 2dup >r mailbox-threads r> "mailbox" wait + over mailbox-threads over "mailbox" wait block-if-empty ] [ drop @@ -58,12 +58,12 @@ TUPLE: mailbox threads data ; 2drop ] if ; inline -: mailbox-get-timeout? ( pred mailbox timeout -- obj ) - [ block-unless-pred ] 3keep drop - mailbox-data delete-node-if ; inline +: mailbox-get-timeout? ( mailbox timeout pred -- obj ) + 3dup block-unless-pred + nip >r mailbox-data r> delete-node-if ; inline -: mailbox-get? ( pred mailbox -- obj ) - f mailbox-get-timeout? ; inline +: mailbox-get? ( mailbox pred -- obj ) + f swap mailbox-get-timeout? ; inline TUPLE: linked-error thread ; diff --git a/extra/concurrency/messaging/messaging.factor b/extra/concurrency/messaging/messaging.factor index cfa2aea30d..2cd83d43f5 100755 --- a/extra/concurrency/messaging/messaging.factor +++ b/extra/concurrency/messaging/messaging.factor @@ -26,10 +26,10 @@ M: thread send ( message thread -- ) my-mailbox swap mailbox-get-timeout ?linked ; : receive-if ( pred -- message ) - my-mailbox mailbox-get? ?linked ; inline + my-mailbox swap mailbox-get? ?linked ; inline -: receive-if-timeout ( pred timeout -- message ) - my-mailbox swap mailbox-get-timeout? ?linked ; inline +: receive-if-timeout ( timeout pred -- message ) + my-mailbox -rot mailbox-get-timeout? ?linked ; inline : rethrow-linked ( error process supervisor -- ) >r r> send ; @@ -40,7 +40,7 @@ M: thread send ( message thread -- ) TUPLE: synchronous data sender tag ; : ( data -- sync ) - self random-256 synchronous construct-boa ; + self 256 random-bits synchronous construct-boa ; TUPLE: reply data tag ; diff --git a/extra/core-foundation/core-foundation.factor b/extra/core-foundation/core-foundation.factor index 297e4aec87..73b8fce229 100644 --- a/extra/core-foundation/core-foundation.factor +++ b/extra/core-foundation/core-foundation.factor @@ -83,7 +83,7 @@ FUNCTION: void CFRelease ( void* cf ) ; dup [ CFBundleLoadExecutable drop ] [ - "Cannot load bundled named " swap append throw + "Cannot load bundled named " prepend throw ] ?if ; FUNCTION: CFRunLoopRef CFRunLoopGetMain ( ) ; diff --git a/extra/core-foundation/fsevents/fsevents.factor b/extra/core-foundation/fsevents/fsevents.factor index 41d2844811..55f2462061 100644 --- a/extra/core-foundation/fsevents/fsevents.factor +++ b/extra/core-foundation/fsevents/fsevents.factor @@ -150,7 +150,8 @@ SYMBOL: event-stream-callbacks : event-stream-counter \ event-stream-counter counter ; [ - H{ } clone event-stream-callbacks set-global + event-stream-callbacks global + [ [ drop expired? not ] assoc-subset ] change-at 1 \ event-stream-counter set-global ] "core-foundation" add-init-hook diff --git a/extra/cpu/8080/emulator/emulator.factor b/extra/cpu/8080/emulator/emulator.factor index 24eceee744..d4574119b2 100755 --- a/extra/cpu/8080/emulator/emulator.factor +++ b/extra/cpu/8080/emulator/emulator.factor @@ -446,7 +446,7 @@ M: cpu reset ( cpu -- ) SYMBOL: rom-root : rom-dir ( -- string ) - rom-root get [ home "roms" path+ dup exists? [ drop f ] unless ] unless* ; + rom-root get [ home "roms" append-path dup exists? [ drop f ] unless ] unless* ; : load-rom* ( seq cpu -- ) #! 'seq' is an array of arrays. Each array contains @@ -455,7 +455,7 @@ SYMBOL: rom-root #! file path shoul dbe relative to the '/roms' resource path. rom-dir [ cpu-ram [ - swap first2 rom-dir swap path+ binary [ + swap first2 rom-dir prepend-path binary [ swap (load-rom) ] with-file-reader ] curry each @@ -1027,14 +1027,14 @@ SYMBOL: $4 8-bit-registers sp <&> "," token <& 8-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : ADC-R,(RR)-instruction ( -- parser ) "ADC-R,(RR)" "ADC" complex-instruction 8-bit-registers sp <&> "," token <& 16-bit-registers indirect <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : SBC-R,N-instruction ( -- parser ) "SBC-R,N" "SBC" complex-instruction @@ -1047,14 +1047,14 @@ SYMBOL: $4 8-bit-registers sp <&> "," token <& 8-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : SBC-R,(RR)-instruction ( -- parser ) "SBC-R,(RR)" "SBC" complex-instruction 8-bit-registers sp <&> "," token <& 16-bit-registers indirect <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : SUB-R-instruction ( -- parser ) "SUB-R" "SUB" complex-instruction @@ -1082,21 +1082,21 @@ SYMBOL: $4 8-bit-registers sp <&> "," token <& 8-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : ADD-RR,RR-instruction ( -- parser ) "ADD-RR,RR" "ADD" complex-instruction 16-bit-registers sp <&> "," token <& 16-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : ADD-R,(RR)-instruction ( -- parser ) "ADD-R,(RR)" "ADD" complex-instruction 8-bit-registers sp <&> "," token <& 16-bit-registers indirect <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : LD-RR,NN-instruction #! LD BC,nn @@ -1124,28 +1124,28 @@ SYMBOL: $4 16-bit-registers indirect sp <&> "," token <& 8-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : LD-R,R-instruction "LD-R,R" "LD" complex-instruction 8-bit-registers sp <&> "," token <& 8-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : LD-RR,RR-instruction "LD-RR,RR" "LD" complex-instruction 16-bit-registers sp <&> "," token <& 16-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : LD-R,(RR)-instruction "LD-R,(RR)" "LD" complex-instruction 8-bit-registers sp <&> "," token <& 16-bit-registers indirect <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : LD-(NN),RR-instruction "LD-(NN),RR" "LD" complex-instruction @@ -1194,14 +1194,14 @@ SYMBOL: $4 16-bit-registers indirect sp <&> "," token <& 16-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : EX-RR,RR-instruction "EX-RR,RR" "EX" complex-instruction 16-bit-registers sp <&> "," token <& 16-bit-registers <&> - just [ first2 swap first2 swap >r swap append r> curry ] <@ ; + just [ first2 swap first2 swap >r prepend r> curry ] <@ ; : 8080-generator-parser NOP-instruction diff --git a/extra/crypto/blum-blum-shub.factor b/extra/crypto/blum-blum-shub.factor deleted file mode 100644 index a1c196d08e..0000000000 --- a/extra/crypto/blum-blum-shub.factor +++ /dev/null @@ -1,36 +0,0 @@ -USING: kernel math sequences namespaces crypto math-contrib ; -IN: crypto-internals - -! TODO: take (log log M) bits instead of 1 bit -! Blum Blum Shub, M = pq -TUPLE: bbs x n ; - -: generate-bbs-primes ( numbits -- p q ) - #! two primes congruent to 3 (mod 4) - dup [ random-miller-rabin-prime==3(mod4) ] 2apply ; - -IN: crypto -: make-bbs ( numbits -- blum-blum-shub ) - #! returns a Blum-Blum-Shub tuple - generate-bbs-primes * [ find-relative-prime ] keep ; - -IN: crypto-internals -SYMBOL: blum-blum-shub 256 make-bbs blum-blum-shub set-global - -: next-bbs-bit ( bbs -- bit ) - #! x = x^2 mod n, return low bit of calculated x - [ [ bbs-x ] keep 2 swap bbs-n ^mod ] keep - [ set-bbs-x ] keep bbs-x 1 bitand ; - -SYMBOL: temp-bbs -: (bbs-bits) ( numbits bbs -- n ) - temp-bbs set [ [ temp-bbs get next-bbs-bit ] swap make-bits ] with-scope ; - -IN: crypto -: random-bbs-bits* ( numbits bbs -- n ) (bbs-bits) ; -: random-bits ( numbits -- n ) blum-blum-shub get (bbs-bits) ; -: random-bytes ( numbits -- n ) 8 * random-bits ; -: random ( n -- n ) - ! #! Cryptographically secure random number using Blum-Blum-Shub 256 - [ log2 1+ random-bits ] keep dupd >= [ -1 shift ] when ; - diff --git a/extra/db/db-tests.factor b/extra/db/db-tests.factor new file mode 100755 index 0000000000..9c32f9e326 --- /dev/null +++ b/extra/db/db-tests.factor @@ -0,0 +1,5 @@ +IN: db.tests +USING: tools.test db kernel ; + +{ 1 0 } [ [ drop ] query-each ] must-infer-as +{ 1 1 } [ [ ] query-map ] must-infer-as diff --git a/extra/db/db.factor b/extra/db/db.factor index 309847209f..f9e946fc20 100755 --- a/extra/db/db.factor +++ b/extra/db/db.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: arrays assocs classes continuations kernel math namespaces sequences sequences.lib tuples words strings -tools.walker new-slots accessors ; +tools.walker accessors ; IN: db TUPLE: db @@ -33,6 +33,19 @@ HOOK: db-close db ( handle -- ) TUPLE: statement handle sql in-params out-params bind-params bound? ; TUPLE: simple-statement ; TUPLE: prepared-statement ; +TUPLE: nonthrowable-statement ; +: make-nonthrowable ( obj -- obj' ) + dup sequence? [ + [ make-nonthrowable ] map + ] [ + nonthrowable-statement construct-delegate + ] if ; + +MIXIN: throwable-statement +INSTANCE: statement throwable-statement +INSTANCE: simple-statement throwable-statement +INSTANCE: prepared-statement throwable-statement + TUPLE: result-set sql in-params out-params handle n max ; : ( sql in out -- statement ) { (>>sql) (>>in-params) (>>out-params) } statement construct ; @@ -50,13 +63,22 @@ GENERIC# row-column-typed 1 ( result-set column -- sql ) GENERIC: advance-row ( result-set -- ) GENERIC: more-rows? ( result-set -- ? ) -: execute-statement ( statement -- ) +GENERIC: execute-statement ( statement -- ) + +M: throwable-statement execute-statement ( statement -- ) dup sequence? [ [ execute-statement ] each ] [ query-results dispose ] if ; +M: nonthrowable-statement execute-statement ( statement -- ) + dup sequence? [ + [ execute-statement ] each + ] [ + [ query-results dispose ] [ 2drop ] recover + ] if ; + : bind-statement ( obj statement -- ) swap >>bind-params [ bind-statement* ] keep diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor index b48c87f0ca..270be886c5 100755 --- a/extra/db/postgresql/lib/lib.factor +++ b/extra/db/postgresql/lib/lib.factor @@ -4,7 +4,7 @@ USING: arrays continuations db io kernel math namespaces quotations sequences db.postgresql.ffi alien alien.c-types db.types tools.walker ascii splitting math.parser combinators combinators.cleave libc shuffle calendar.format -byte-arrays destructors prettyprint new-slots accessors +byte-arrays destructors prettyprint accessors strings serialize io.encodings.binary io.streams.byte-array ; IN: db.postgresql.lib @@ -73,7 +73,7 @@ IN: db.postgresql.lib sql-spec-type { { FACTOR-BLOB [ dup [ - binary [ serialize ] with-byte-writer + object>bytes malloc-byte-array/length ] [ 0 ] if ] } { BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] } @@ -164,7 +164,7 @@ M: postgresql-malloc-destructor dispose ( obj -- ) { BLOB [ pq-get-blob ] } { FACTOR-BLOB [ pq-get-blob - dup [ binary [ deserialize ] with-byte-reader ] when ] } + dup [ bytes>object ] when ] } [ no-sql-type ] } case ; ! PQgetlength PQgetisnull diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 26b6cbe75c..8a6f8632ec 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -10,6 +10,7 @@ IN: db.postgresql TUPLE: postgresql-db host port pgopts pgtty db user pass ; TUPLE: postgresql-statement ; +INSTANCE: postgresql-statement throwable-statement TUPLE: postgresql-result-set ; : ( statement in out -- postgresql-statement ) @@ -119,8 +120,8 @@ M: postgresql-db bind% ( spec -- ) : postgresql-make ( class quot -- ) >r sql-props r> - [ postgresql-counter off ] swap compose - { "" { } { } } nmake ; + [ postgresql-counter off call ] { "" { } { } } nmake + ; inline : create-table-sql ( class -- statement ) [ @@ -194,7 +195,7 @@ M: postgresql-db ( class -- statement ) ");" 0% ] postgresql-make ; -M: postgresql-db ( class -- statement ) +M: postgresql-db ( class -- statement ) [ "insert into " 0% 0% "(" 0% diff --git a/extra/db/sqlite/ffi/ffi.factor b/extra/db/sqlite/ffi/ffi.factor index 63bce0a8c3..1d356b1592 100755 --- a/extra/db/sqlite/ffi/ffi.factor +++ b/extra/db/sqlite/ffi/ffi.factor @@ -127,6 +127,6 @@ FUNCTION: char* sqlite3_column_decltype ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_int ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: sqlite3_int64 sqlite3_column_int64 ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: double sqlite3_column_double ( sqlite3_stmt* pStmt, int col ) ; -FUNCTION: int sqlite3_column_name ( sqlite3_stmt* pStmt, int col ) ; +FUNCTION: char* sqlite3_column_name ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: char* sqlite3_column_text ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_type ( sqlite3_stmt* pStmt, int col ) ; diff --git a/extra/db/sqlite/lib/lib.factor b/extra/db/sqlite/lib/lib.factor index dbada854fb..f81d7de4b8 100755 --- a/extra/db/sqlite/lib/lib.factor +++ b/extra/db/sqlite/lib/lib.factor @@ -94,7 +94,7 @@ IN: db.sqlite.lib { TIMESTAMP [ sqlite-bind-text-by-name ] } { BLOB [ sqlite-bind-blob-by-name ] } { FACTOR-BLOB [ - binary [ serialize ] with-byte-writer + object>bytes sqlite-bind-blob-by-name ] } { +native-id+ [ sqlite-bind-int-by-name ] } @@ -102,17 +102,12 @@ IN: db.sqlite.lib [ no-sql-type ] } case ; -: sqlite-finalize ( handle -- ) - sqlite3_finalize sqlite-check-result ; - -: sqlite-reset ( handle -- ) - sqlite3_reset sqlite-check-result ; - -: sqlite-#columns ( query -- int ) - sqlite3_column_count ; - -: sqlite-column ( handle index -- string ) - sqlite3_column_text ; +: sqlite-finalize ( handle -- ) sqlite3_finalize sqlite-check-result ; +: sqlite-reset ( handle -- ) sqlite3_reset sqlite-check-result ; +: sqlite-#columns ( query -- int ) sqlite3_column_count ; +: sqlite-column ( handle index -- string ) sqlite3_column_text ; +: sqlite-column-name ( handle index -- string ) sqlite3_column_name ; +: sqlite-column-type ( handle index -- string ) sqlite3_column_type ; : sqlite-column-blob ( handle index -- byte-array/f ) [ sqlite3_column_bytes ] 2keep @@ -126,6 +121,7 @@ IN: db.sqlite.lib dup array? [ first ] when { { +native-id+ [ sqlite3_column_int64 ] } + { +random-id+ [ sqlite3_column_int64 ] } { INTEGER [ sqlite3_column_int ] } { BIG-INTEGER [ sqlite3_column_int64 ] } { DOUBLE [ sqlite3_column_double ] } @@ -138,7 +134,7 @@ IN: db.sqlite.lib { BLOB [ sqlite-column-blob ] } { FACTOR-BLOB [ sqlite-column-blob - dup [ binary [ deserialize ] with-byte-reader ] when + dup [ bytes>object ] when ] } ! { NULL [ 2drop f ] } [ no-sql-type ] @@ -147,7 +143,7 @@ IN: db.sqlite.lib : sqlite-row ( handle -- seq ) dup sqlite-#columns [ sqlite-column ] with map ; -: sqlite-step-has-more-rows? ( step-result -- bool ) +: sqlite-step-has-more-rows? ( prepared -- bool ) dup SQLITE_ROW = [ drop t ] [ diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index b72d788605..d7d954c0dc 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -6,6 +6,7 @@ prettyprint sequences strings tuples alien.c-types continuations db.sqlite.lib db.sqlite.ffi db.tuples words combinators.lib db.types combinators combinators.cleave io namespaces.lib ; +USE: tools.walker IN: db.sqlite TUPLE: sqlite-db path ; @@ -17,15 +18,12 @@ M: sqlite-db db-open ( db -- ) dup sqlite-db-path sqlite-open swap set-delegate ; -M: sqlite-db db-close ( handle -- ) - sqlite-close ; - +M: sqlite-db db-close ( handle -- ) sqlite-close ; M: sqlite-db dispose ( db -- ) dispose-db ; - -: with-sqlite ( path quot -- ) - sqlite-db swap with-db ; inline +: with-sqlite ( path quot -- ) sqlite-db swap with-db ; inline TUPLE: sqlite-statement ; +INSTANCE: sqlite-statement throwable-statement TUPLE: sqlite-result-set has-more? ; @@ -38,12 +36,20 @@ M: sqlite-db ( str in out -- obj ) set-statement-in-params set-statement-out-params } statement construct - db get db-handle over statement-sql sqlite-prepare - over set-statement-handle sqlite-statement construct-delegate ; +: sqlite-maybe-prepare ( statement -- statement ) + dup statement-handle [ + [ + delegate + db get db-handle over statement-sql sqlite-prepare + swap set-statement-handle + ] keep + ] unless ; + M: sqlite-statement dispose ( statement -- ) - statement-handle sqlite-finalize ; + statement-handle + [ [ sqlite3_reset drop ] keep sqlite-finalize ] when* ; M: sqlite-result-set dispose ( result-set -- ) f swap set-result-set-handle ; @@ -52,9 +58,11 @@ M: sqlite-result-set dispose ( result-set -- ) swap [ first3 sqlite-bind-type ] with each ; : reset-statement ( statement -- ) + sqlite-maybe-prepare statement-handle sqlite-reset ; M: sqlite-statement bind-statement* ( statement -- ) + sqlite-maybe-prepare dup statement-bound? [ dup reset-statement ] when [ statement-bind-params ] [ statement-handle ] bi sqlite-bind ; @@ -63,7 +71,7 @@ M: sqlite-statement bind-tuple ( tuple statement -- ) [ statement-in-params [ - [ sql-spec-column-name ":" swap append ] + [ sql-spec-column-name ":" prepend ] [ sql-spec-slot-name rot get-slot-named ] [ sql-spec-type ] tri 3array ] with map @@ -95,21 +103,17 @@ M: sqlite-result-set more-rows? ( result-set -- ? ) sqlite-result-set-has-more? ; M: sqlite-statement query-results ( query -- result-set ) + sqlite-maybe-prepare dup statement-handle sqlite-result-set dup advance-row ; -M: sqlite-db begin-transaction ( -- ) - "BEGIN" sql-command ; - -M: sqlite-db commit-transaction ( -- ) - "COMMIT" sql-command ; - -M: sqlite-db rollback-transaction ( -- ) - "ROLLBACK" sql-command ; +M: sqlite-db begin-transaction ( -- ) "BEGIN" sql-command ; +M: sqlite-db commit-transaction ( -- ) "COMMIT" sql-command ; +M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; : sqlite-make ( class quot -- ) >r sql-props r> - { "" { } { } } nmake ; + { "" { } { } } nmake ; inline M: sqlite-db create-sql-statement ( class -- statement ) [ @@ -123,9 +127,7 @@ M: sqlite-db create-sql-statement ( class -- statement ) ] sqlite-make ; M: sqlite-db drop-sql-statement ( class -- statement ) - [ - "drop table " 0% 0% ";" 0% drop - ] sqlite-make ; + [ "drop table " 0% 0% ";" 0% drop ] sqlite-make ; M: sqlite-db ( tuple -- statement ) [ @@ -138,7 +140,7 @@ M: sqlite-db ( tuple -- statement ) ");" 0% ] sqlite-make ; -M: sqlite-db ( tuple -- statement ) +M: sqlite-db ( tuple -- statement ) ; : where-primary-key% ( specs -- ) @@ -171,7 +173,7 @@ M: sqlite-db ( specs table -- sql ) ! : select-sequence ( seq name -- ) ; M: sqlite-db bind% ( spec -- ) - dup 1, sql-spec-column-name ":" swap append 0% ; + dup 1, sql-spec-column-name ":" prepend 0% ; M: sqlite-db ( tuple class -- statement ) [ @@ -188,6 +190,8 @@ M: sqlite-db modifier-table ( -- hashtable ) H{ { +native-id+ "primary key" } { +assigned-id+ "primary key" } + { +random-id+ "primary key" } + ! { +nonnative-id+ "primary key" } { +autoincrement+ "autoincrement" } { +unique+ "unique" } { +default+ "default" } @@ -195,10 +199,9 @@ M: sqlite-db modifier-table ( -- hashtable ) { +not-null+ "not null" } } ; -M: sqlite-db compound-modifier ( str obj -- newstr ) - compound-type ; +M: sqlite-db compound-modifier ( str obj -- str' ) compound-type ; -M: sqlite-db compound-type ( str seq -- newstr ) +M: sqlite-db compound-type ( str seq -- str' ) over { { "default" [ first number>string join-space ] } [ 2drop ] ! "no sqlite compound data type" 3array throw ] @@ -207,6 +210,7 @@ M: sqlite-db compound-type ( str seq -- newstr ) M: sqlite-db type-table ( -- assoc ) H{ { +native-id+ "integer primary key" } + { +random-id+ "integer primary key" } { INTEGER "integer" } { TEXT "text" } { VARCHAR "text" } @@ -219,5 +223,4 @@ M: sqlite-db type-table ( -- assoc ) { FACTOR-BLOB "blob" } } ; -M: sqlite-db create-type-table - type-table ; +M: sqlite-db create-type-table ( symbol -- str ) type-table ; diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 4c47066d35..6b61981119 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -9,7 +9,7 @@ IN: db.tuples.tests TUPLE: person the-id the-name the-number the-real ts date time blob factor-blob ; -: ( name age real ts date time blob -- person ) +: ( name age real ts date time blob factor-blob -- person ) { set-person-the-name set-person-the-number @@ -190,11 +190,11 @@ TUPLE: annotation n paste-id summary author mode contents ; : test-postgresql ( -- ) >r { "localhost" "postgres" "foob" "factor-test" } postgresql-db r> with-db ; -[ native-person-schema test-tuples ] test-sqlite -[ assigned-person-schema test-tuples ] test-sqlite - -! [ native-person-schema test-tuples ] test-postgresql -! [ assigned-person-schema test-tuples ] test-postgresql +: test-repeated-insert + [ ] [ person ensure-table ] unit-test + + [ ] [ person1 get insert-tuple ] unit-test + [ person1 get insert-tuple ] must-fail ; TUPLE: serialize-me id data ; @@ -239,3 +239,34 @@ TUPLE: exam id name score ; ; ! [ test-ranges ] test-sqlite + +TUPLE: secret n message ; +C: secret + +: test-random-id + secret "SECRET" + { + { "n" "ID" +random-id+ } + { "message" "MESSAGE" TEXT } + } define-persistent + + [ ] [ secret ensure-table ] unit-test + [ ] [ f "kilroy was here" insert-tuple ] unit-test + [ ] [ T{ secret } select-tuples ] unit-test + ; + + + +! [ test-random-id ] test-sqlite + [ native-person-schema test-tuples ] test-sqlite + [ assigned-person-schema test-tuples ] test-sqlite +! [ assigned-person-schema test-repeated-insert ] test-sqlite +! [ native-person-schema test-tuples ] test-postgresql +! [ assigned-person-schema test-tuples ] test-postgresql +! [ assigned-person-schema test-repeated-insert ] test-postgresql + +! \ insert-tuple must-infer +! \ update-tuple must-infer +! \ delete-tuple must-infer +! \ select-tuple must-infer +! \ define-persistent must-infer diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor index 82147a2efa..0f69b0fafb 100755 --- a/extra/db/tuples/tuples.factor +++ b/extra/db/tuples/tuples.factor @@ -28,7 +28,7 @@ HOOK: create-sql-statement db ( class -- obj ) HOOK: drop-sql-statement db ( class -- obj ) HOOK: db ( class -- obj ) -HOOK: db ( class -- obj ) +HOOK: db ( class -- obj ) HOOK: db ( class -- obj ) HOOK: db ( class -- obj ) @@ -36,7 +36,7 @@ HOOK: db ( class -- obj ) HOOK: db ( class -- obj ) HOOK: db ( class -- obj ) -HOOK: db ( tuple -- tuple ) +HOOK: db ( tuple class -- tuple ) HOOK: insert-tuple* db ( tuple statement -- ) @@ -75,21 +75,25 @@ HOOK: insert-tuple* db ( tuple statement -- ) drop-sql-statement [ execute-statement ] with-disposals ; : ensure-table ( class -- ) - [ dup drop-table ] ignore-errors create-table ; + [ + drop-sql-statement make-nonthrowable + [ execute-statement ] with-disposals + ] [ create-table ] bi ; : insert-native ( tuple -- ) dup class db get db-insert-statements [ ] cache [ bind-tuple ] 2keep insert-tuple* ; -: insert-assigned ( tuple -- ) +: insert-nonnative ( tuple -- ) +! TODO logic here for unique ids dup class - db get db-insert-statements [ ] cache + db get db-insert-statements [ ] cache [ bind-tuple ] keep execute-statement ; : insert-tuple ( tuple -- ) - dup class db-columns find-primary-key assigned-id? [ - insert-assigned + dup class db-columns find-primary-key nonnative-id? [ + insert-nonnative ] [ insert-native ] if ; diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index 7014aaa943..94a8d6f392 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -3,7 +3,8 @@ USING: arrays assocs db kernel math math.parser sequences continuations sequences.deep sequences.lib words namespaces tools.walker slots slots.private classes -mirrors tuples combinators calendar.format symbols ; +mirrors tuples combinators calendar.format symbols +singleton ; IN: db.types HOOK: modifier-table db ( -- hash ) @@ -14,22 +15,30 @@ HOOK: compound-type db ( str n -- hash ) TUPLE: sql-spec class slot-name column-name type modifiers primary-key ; -SYMBOLS: +native-id+ +assigned-id+ +autoincrement+ -+serial+ +unique+ +default+ +null+ +not-null+ +SINGLETON: +native-id+ +SINGLETON: +assigned-id+ +SINGLETON: +random-id+ +UNION: +primary-key+ +native-id+ +assigned-id+ +random-id+ ; +UNION: +nonnative-id+ +random-id+ +assigned-id+ ; + +SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+ +foreign-id+ +has-many+ ; -: (primary-key?) ( obj -- ? ) - { +native-id+ +assigned-id+ } member? ; - : primary-key? ( spec -- ? ) - sql-spec-primary-key (primary-key?) ; + sql-spec-primary-key +primary-key+? ; + +: native-id? ( spec -- ? ) + sql-spec-primary-key +native-id+? ; + +: nonnative-id? ( spec -- ? ) + sql-spec-primary-key +nonnative-id+? ; : normalize-spec ( spec -- ) - dup sql-spec-type dup (primary-key?) [ + dup sql-spec-type dup +primary-key+? [ swap set-sql-spec-primary-key ] [ drop dup sql-spec-modifiers [ - (primary-key?) + +primary-key+? ] deep-find [ swap set-sql-spec-primary-key ] [ drop ] if* ] if ; @@ -37,12 +46,6 @@ SYMBOLS: +native-id+ +assigned-id+ +autoincrement+ : find-primary-key ( specs -- obj ) [ sql-spec-primary-key ] find nip ; -: native-id? ( spec -- ? ) - sql-spec-primary-key +native-id+ = ; - -: assigned-id? ( spec -- ? ) - sql-spec-primary-key +assigned-id+ = ; - : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ; SYMBOLS: INTEGER BIG-INTEGER DOUBLE REAL BOOLEAN TEXT VARCHAR @@ -69,7 +72,7 @@ TUPLE: no-sql-modifier ; dup number? [ number>string ] when ; : maybe-remove-id ( specs -- obj ) - [ native-id? not ] subset ; + [ +native-id+? not ] subset ; : remove-relations ( specs -- newcolumns ) [ relation? not ] subset ; @@ -124,7 +127,7 @@ TUPLE: no-sql-modifier ; : modifiers ( spec -- str ) sql-spec-modifiers [ lookup-modifier ] map " " join - dup empty? [ " " swap append ] unless ; + dup empty? [ " " prepend ] unless ; HOOK: bind% db ( spec -- ) diff --git a/extra/delegate/delegate.factor b/extra/delegate/delegate.factor index 654d096b26..67b8a39320 100755 --- a/extra/delegate/delegate.factor +++ b/extra/delegate/delegate.factor @@ -7,7 +7,7 @@ IN: delegate swap { } like "protocol-words" set-word-prop ; : PROTOCOL: - CREATE dup reset-generic dup define-symbol + CREATE-WORD dup define-symbol parse-definition swap define-protocol ; parsing PREDICATE: word protocol "protocol-words" word-prop ; @@ -27,11 +27,11 @@ M: tuple-class group-words swap [ slot-spec-writer ] map append ; : define-consult-method ( word class quot -- ) - pick add spin define-method ; + pick add >r swap create-method r> define ; : define-consult ( class group quot -- ) - >r group-words r> - swapd [ define-consult-method ] 2curry each ; + >r group-words swap r> + [ define-consult-method ] 2curry each ; : CONSULT: scan-word scan-word parse-definition swapd define-consult ; parsing @@ -39,7 +39,7 @@ M: tuple-class group-words : define-mimic ( group mimicker mimicked -- ) >r >r group-words r> r> [ pick "methods" word-prop at dup - [ "method-def" word-prop spin define-method ] + [ >r swap create-method r> word-def define ] [ 3drop ] if ] 2curry each ; diff --git a/extra/destructors/destructors.factor b/extra/destructors/destructors.factor index b2561c7439..1b98d2ee0d 100755 --- a/extra/destructors/destructors.factor +++ b/extra/destructors/destructors.factor @@ -26,11 +26,14 @@ M: destructor dispose : add-always-destructor ( obj -- ) always-destructors get push ; +: dispose-each ( seq -- ) + [ dispose ] each ; + : do-always-destructors ( -- ) - always-destructors get [ dispose ] each ; + always-destructors get dispose-each ; : do-error-destructors ( -- ) - error-destructors get [ dispose ] each ; + error-destructors get dispose-each ; : with-destructors ( quot -- ) [ diff --git a/extra/digraphs/digraphs.factor b/extra/digraphs/digraphs.factor old mode 100644 new mode 100755 index 5c6fa9b2a1..1776c916ad --- a/extra/digraphs/digraphs.factor +++ b/extra/digraphs/digraphs.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008 Alex Chapman ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs kernel new-slots sequences vectors ; +USING: accessors assocs kernel sequences vectors ; IN: digraphs TUPLE: digraph ; diff --git a/extra/documents/documents.factor b/extra/documents/documents.factor index 993e69ec14..60ae592d4c 100755 --- a/extra/documents/documents.factor +++ b/extra/documents/documents.factor @@ -74,7 +74,7 @@ TUPLE: document locs ; 0 swap [ append ] change-nth ; : append-last ( str seq -- ) - [ length 1- ] keep [ swap append ] change-nth ; + [ length 1- ] keep [ prepend ] change-nth ; : loc-col/str ( loc document -- str col ) >r first2 swap r> nth swap ; diff --git a/extra/editors/editpadpro/editpadpro.factor b/extra/editors/editpadpro/editpadpro.factor index eb31b2aa47..9da57e16bf 100755 --- a/extra/editors/editpadpro/editpadpro.factor +++ b/extra/editors/editpadpro/editpadpro.factor @@ -5,7 +5,7 @@ IN: editors.editpadpro : editpadpro-path \ editpadpro-path get-global [ - program-files "JGsoft" path+ + program-files "JGsoft" append-path t [ >lower "editpadpro.exe" tail? ] find-file ] unless* ; diff --git a/extra/editors/editplus/editplus.factor b/extra/editors/editplus/editplus.factor index ee24c99463..363d202f6c 100755 --- a/extra/editors/editplus/editplus.factor +++ b/extra/editors/editplus/editplus.factor @@ -4,7 +4,7 @@ IN: editors.editplus : editplus-path ( -- path ) \ editplus-path get-global [ - program-files "\\EditPlus 2\\editplus.exe" path+ + program-files "\\EditPlus 2\\editplus.exe" append-path ] unless* ; : editplus ( file line -- ) diff --git a/extra/editors/emeditor/emeditor.factor b/extra/editors/emeditor/emeditor.factor index bed333694c..8aecb49ae5 100755 --- a/extra/editors/emeditor/emeditor.factor +++ b/extra/editors/emeditor/emeditor.factor @@ -4,7 +4,7 @@ IN: editors.emeditor : emeditor-path ( -- path ) \ emeditor-path get-global [ - program-files "\\EmEditor\\EmEditor.exe" path+ + program-files "\\EmEditor\\EmEditor.exe" append-path ] unless* ; : emeditor ( file line -- ) diff --git a/extra/editors/gvim/windows/windows.factor b/extra/editors/gvim/windows/windows.factor index 030c968e81..489000498e 100755 --- a/extra/editors/gvim/windows/windows.factor +++ b/extra/editors/gvim/windows/windows.factor @@ -4,6 +4,6 @@ IN: editors.gvim.windows M: windows-io gvim-path \ gvim-path get-global [ - program-files "vim" path+ + program-files "vim" append-path t [ "gvim.exe" tail? ] find-file ] unless* ; diff --git a/extra/editors/jedit/jedit.factor b/extra/editors/jedit/jedit.factor index 3ce2c40192..7b6066df7c 100644 --- a/extra/editors/jedit/jedit.factor +++ b/extra/editors/jedit/jedit.factor @@ -8,7 +8,7 @@ io.encodings.utf8 ; IN: editors.jedit : jedit-server-info ( -- port auth ) - home "/.jedit/server" path+ ascii [ + home "/.jedit/server" append-path ascii [ readln drop readln string>number readln string>number @@ -32,7 +32,7 @@ IN: editors.jedit ] with-stream ; : jedit-location ( file line -- ) - number>string "+line:" swap append 2array + number>string "+line:" prepend 2array make-jedit-request send-jedit-request ; : jedit-file ( file -- ) diff --git a/extra/editors/notepadpp/notepadpp.factor b/extra/editors/notepadpp/notepadpp.factor index 72ac6c72d7..959e633cc3 100755 --- a/extra/editors/notepadpp/notepadpp.factor +++ b/extra/editors/notepadpp/notepadpp.factor @@ -4,7 +4,7 @@ IN: editors.notepadpp : notepadpp-path \ notepadpp-path get-global [ - program-files "notepad++\\notepad++.exe" path+ + program-files "notepad++\\notepad++.exe" append-path ] unless* ; : notepadpp ( file line -- ) diff --git a/extra/editors/scite/scite.factor b/extra/editors/scite/scite.factor index ac9a032abc..a0bacaabba 100755 --- a/extra/editors/scite/scite.factor +++ b/extra/editors/scite/scite.factor @@ -14,7 +14,7 @@ IN: editors.scite : scite-path ( -- path ) \ scite-path get-global [ - program-files "wscite\\SciTE.exe" path+ + program-files "wscite\\SciTE.exe" append-path ] unless* ; : scite-command ( file line -- cmd ) diff --git a/extra/editors/ted-notepad/ted-notepad.factor b/extra/editors/ted-notepad/ted-notepad.factor index 5d58e182a3..9b341dd2a8 100755 --- a/extra/editors/ted-notepad/ted-notepad.factor +++ b/extra/editors/ted-notepad/ted-notepad.factor @@ -4,7 +4,7 @@ IN: editors.ted-notepad : ted-notepad-path \ ted-notepad-path get-global [ - program-files "\\TED Notepad\\TedNPad.exe" path+ + program-files "\\TED Notepad\\TedNPad.exe" append-path ] unless* ; : ted-notepad ( file line -- ) diff --git a/extra/editors/ultraedit/ultraedit.factor b/extra/editors/ultraedit/ultraedit.factor index f9d27174b3..1fef9f3350 100755 --- a/extra/editors/ultraedit/ultraedit.factor +++ b/extra/editors/ultraedit/ultraedit.factor @@ -5,7 +5,7 @@ IN: editors.ultraedit : ultraedit-path ( -- path ) \ ultraedit-path get-global [ program-files - "\\IDM Computer Solutions\\UltraEdit-32\\uedit32.exe" path+ + "\\IDM Computer Solutions\\UltraEdit-32\\uedit32.exe" append-path ] unless* ; : ultraedit ( file line -- ) diff --git a/extra/editors/wordpad/wordpad.factor b/extra/editors/wordpad/wordpad.factor index 5ad08b613b..d1f979e0f3 100755 --- a/extra/editors/wordpad/wordpad.factor +++ b/extra/editors/wordpad/wordpad.factor @@ -5,7 +5,7 @@ IN: editors.wordpad : wordpad-path ( -- path ) \ wordpad-path get [ - program-files "\\Windows NT\\Accessories\\wordpad.exe" path+ + program-files "\\Windows NT\\Accessories\\wordpad.exe" append-path ] unless* ; : wordpad ( file line -- ) diff --git a/extra/faq/faq.factor b/extra/faq/faq.factor index 7ad3900163..d7624466f7 100644 --- a/extra/faq/faq.factor +++ b/extra/faq/faq.factor @@ -79,7 +79,7 @@ C: faq "br" contained, nl, ; : toc-link, ( question-list number -- ) - number>string "#" swap append "href" swap 2array 1array + number>string "#" prepend "href" swap 2array 1array "a" swap [ question-list-title , ] tag*, br, ; : toc, ( faq -- ) diff --git a/extra/fry/fry-docs.factor b/extra/fry/fry-docs.factor index 31b544d488..739e7d012c 100755 --- a/extra/fry/fry-docs.factor +++ b/extra/fry/fry-docs.factor @@ -46,7 +46,7 @@ $nl } "The " { $link , } " and " { $link @ } " specifiers may be freely mixed:" { $code - "{ 8 13 14 27 } [ even? ] 5 [ @ dup , ? ] map" + "{ 8 13 14 27 } [ even? ] 5 '[ @ dup , ? ] map" "{ 8 13 14 27 } [ even? ] 5 [ dup ] swap [ ? ] curry 3compose map" "{ 8 13 14 27 } [ even? dup 5 ? ] map" } diff --git a/extra/graphics/bitmap/bitmap.factor b/extra/graphics/bitmap/bitmap.factor old mode 100644 new mode 100755 index ec4d6b79e1..861894c8f4 --- a/extra/graphics/bitmap/bitmap.factor +++ b/extra/graphics/bitmap/bitmap.factor @@ -117,16 +117,16 @@ M: bitmap height ( bitmap -- ) bitmap-height ; load-bitmap [ "bitmap" open-window ] keep ; : test-bitmap24 ( -- ) - "misc/graphics/bmps/thiswayup24.bmp" resource-path bitmap. ; + "extra/graphics/bitmap/test-data/thiswayup24.bmp" resource-path bitmap. ; : test-bitmap8 ( -- ) - "misc/graphics/bmps/rgb8bit.bmp" resource-path bitmap. ; + "extra/graphics/bitmap/test-data/rgb8bit.bmp" resource-path bitmap. ; : test-bitmap4 ( -- ) - "misc/graphics/bmps/rgb4bit.bmp" resource-path + "extra/graphics/bitmap/test-data/rgb4bit.bmp" resource-path load-bitmap ; ! bitmap. ; : test-bitmap1 ( -- ) - "misc/graphics/bmps/1bit.bmp" resource-path bitmap. ; + "extra/graphics/bitmap/test-data/1bit.bmp" resource-path bitmap. ; diff --git a/misc/graphics/bmps/1bit.bmp b/extra/graphics/bitmap/test-images/1bit.bmp similarity index 100% rename from misc/graphics/bmps/1bit.bmp rename to extra/graphics/bitmap/test-images/1bit.bmp diff --git a/misc/graphics/bmps/rgb4bit.bmp b/extra/graphics/bitmap/test-images/rgb4bit.bmp similarity index 100% rename from misc/graphics/bmps/rgb4bit.bmp rename to extra/graphics/bitmap/test-images/rgb4bit.bmp diff --git a/misc/graphics/bmps/rgb8bit.bmp b/extra/graphics/bitmap/test-images/rgb8bit.bmp similarity index 100% rename from misc/graphics/bmps/rgb8bit.bmp rename to extra/graphics/bitmap/test-images/rgb8bit.bmp diff --git a/misc/graphics/bmps/thiswayup24.bmp b/extra/graphics/bitmap/test-images/thiswayup24.bmp similarity index 100% rename from misc/graphics/bmps/thiswayup24.bmp rename to extra/graphics/bitmap/test-images/thiswayup24.bmp diff --git a/extra/hello-ui/deploy.factor b/extra/hello-ui/deploy.factor index 43d8ca21ef..31f1181be2 100755 --- a/extra/hello-ui/deploy.factor +++ b/extra/hello-ui/deploy.factor @@ -1,14 +1,15 @@ USING: tools.deploy.config ; H{ - { deploy-io 1 } - { deploy-compiler? t } { deploy-word-defs? f } - { deploy-word-props? f } - { deploy-math? t } + { deploy-random? f } { deploy-name "Hello world" } - { deploy-c-types? f } - { deploy-ui? t } { deploy-threads? t } + { deploy-compiler? t } + { deploy-math? t } + { deploy-c-types? f } + { deploy-io 1 } { deploy-reflection 1 } + { deploy-ui? t } { "stop-after-last-window?" t } + { deploy-word-props? f } } diff --git a/extra/hello-world/deploy.factor b/extra/hello-world/deploy.factor index 45d19cb891..77421938a9 100755 --- a/extra/hello-world/deploy.factor +++ b/extra/hello-world/deploy.factor @@ -1,14 +1,15 @@ USING: tools.deploy.config ; H{ - { deploy-io 2 } - { deploy-math? f } + { deploy-word-defs? f } + { deploy-random? f } + { deploy-name "Hello world (console)" } { deploy-threads? f } { deploy-compiler? f } - { deploy-word-props? f } - { deploy-word-defs? f } - { deploy-name "Hello world (console)" } - { deploy-reflection 2 } + { deploy-math? f } { deploy-c-types? f } + { deploy-io 2 } + { deploy-reflection 1 } { deploy-ui? f } { "stop-after-last-window?" t } + { deploy-word-props? f } } diff --git a/extra/help/help-tests.factor b/extra/help/help-tests.factor new file mode 100644 index 0000000000..e38f2fc15d --- /dev/null +++ b/extra/help/help-tests.factor @@ -0,0 +1,5 @@ +IN: help.tests +USING: tools.test help kernel ; + +[ 3 throw ] must-fail +[ ] [ :help ] unit-test diff --git a/extra/help/help.factor b/extra/help/help.factor index 85f5a35a5c..9e4d02802b 100755 --- a/extra/help/help.factor +++ b/extra/help/help.factor @@ -25,10 +25,6 @@ GENERIC: word-help* ( word -- content ) M: word word-help* drop f ; -M: slot-reader word-help* drop \ $slot-reader ; - -M: slot-writer word-help* drop \ $slot-writer ; - M: predicate word-help* drop \ $predicate ; : all-articles ( -- seq ) @@ -98,7 +94,7 @@ M: word set-article-parent swap "help-parent" set-word-prop ; : about ( vocab -- ) dup require dup vocab [ ] [ - "No such vocabulary: " swap append throw + "No such vocabulary: " prepend throw ] ?if dup vocab-help [ help @@ -136,7 +132,7 @@ M: word set-article-parent swap "help-parent" set-word-prop ; ":edit - jump to source location (parse errors only)" print ":get ( var -- value ) accesses variables at time of the error" print - ":vars - list all variables at error time"; + ":vars - list all variables at error time" print ; : :help ( -- ) error get delegates [ error-help ] map [ ] subset diff --git a/extra/help/lint/lint.factor b/extra/help/lint/lint.factor index d8a4f83169..b65e44fda4 100755 --- a/extra/help/lint/lint.factor +++ b/extra/help/lint/lint.factor @@ -39,8 +39,6 @@ IN: help.lint { $shuffle $values-x/y - $slot-reader - $slot-writer $predicate $class-description $error-description diff --git a/extra/help/markup/markup-tests.factor b/extra/help/markup/markup-tests.factor index 0b4b69bf59..6b138a18ab 100644 --- a/extra/help/markup/markup-tests.factor +++ b/extra/help/markup/markup-tests.factor @@ -4,18 +4,6 @@ IN: help.markup.tests TUPLE: blahblah quux ; -: test-slot blahblah "slots" word-prop second ; - -[ - { { "blahblah" { $instance blahblah } } { "quux" { $instance object } } } -] [ - test-slot blahblah ($spec-reader-values) -] unit-test - -[ ] [ - test-slot blahblah $spec-reader-values -] unit-test - [ "an int" ] [ [ { "int" } $instance ] with-string-writer ] unit-test [ ] [ \ blahblah-quux help ] unit-test diff --git a/extra/help/markup/markup.factor b/extra/help/markup/markup.factor index 710671857e..9c3615f629 100755 --- a/extra/help/markup/markup.factor +++ b/extra/help/markup/markup.factor @@ -158,7 +158,8 @@ M: f print-element drop ; : $subsection ( element -- ) [ first ($long-link) ] ($subsection) ; -: ($vocab-link) ( text vocab -- ) f >vocab-link write-link ; +: ($vocab-link) ( text vocab -- ) + >vocab-link write-link ; : $vocab-subsection ( element -- ) [ @@ -295,63 +296,6 @@ M: string ($instance) { $link with-pprint } " combinator." } $notes ; -: ($spec-reader-values) ( slot-spec class -- element ) - dup ?word-name swap 2array - over slot-spec-name - rot slot-spec-type 2array 2array - [ { $instance } swap add ] assoc-map ; - -: $spec-reader-values ( slot-spec class -- ) - ($spec-reader-values) $values ; - -: $spec-reader-description ( slot-spec class -- ) - [ - "Outputs the value stored in the " , - { $snippet } rot slot-spec-name add , - " slot of " , - { $instance } swap add , - " instance." , - ] { } make $description ; - -: $spec-reader ( reader slot-specs class -- ) - >r slot-of-reader r> - over [ - 2dup $spec-reader-values - 2dup $spec-reader-description - ] when 2drop ; - -GENERIC: slot-specs ( help-type -- specs ) - -M: word slot-specs "slots" word-prop ; - -: $slot-reader ( reader -- ) - first dup "reading" word-prop [ slot-specs ] keep - $spec-reader ; - -: $spec-writer-values ( slot-spec class -- ) - ($spec-reader-values) reverse $values ; - -: $spec-writer-description ( slot-spec class -- ) - [ - "Stores a new value to the " , - { $snippet } rot slot-spec-name add , - " slot of " , - { $instance } swap add , - " instance." , - ] { } make $description ; - -: $spec-writer ( writer slot-specs class -- ) - >r slot-of-writer r> - over [ - 2dup $spec-writer-values - 2dup $spec-writer-description - dup ?word-name 1array $side-effects - ] when 2drop ; - -: $slot-writer ( reader -- ) - first dup "writing" word-prop [ slot-specs ] keep - $spec-writer ; - GENERIC: elements* ( elt-type element -- ) M: simple-element elements* [ elements* ] with each ; diff --git a/extra/help/stylesheet/stylesheet.factor b/extra/help/stylesheet/stylesheet.factor index 945d9a4ce1..68810e2369 100755 --- a/extra/help/stylesheet/stylesheet.factor +++ b/extra/help/stylesheet/stylesheet.factor @@ -82,6 +82,7 @@ H{ { page-color { 0.95 0.95 0.95 1 } } { border-color { 1 0 0 1 } } { border-width 5 } + { wrap-margin 500 } } warning-style set-global SYMBOL: table-content-style diff --git a/extra/html/elements/elements.factor b/extra/html/elements/elements.factor index 286037d4dc..754afb1ea7 100644 --- a/extra/html/elements/elements.factor +++ b/extra/html/elements/elements.factor @@ -38,7 +38,7 @@ IN: html.elements ! "Click me" write ! ! (url -- ) -! "click" write +! "click" write ! ! (url -- ) ! "click" write @@ -72,7 +72,7 @@ SYMBOL: html dup swap [ write-html ] curry empty-effect html-word ; -: >version http-port >>port + H{ } clone >>header H{ } clone >>query V{ } clone >>cookies ; diff --git a/extra/http/server/actions/actions-tests.factor b/extra/http/server/actions/actions-tests.factor index 45f7ff385d..ebf8e8770b 100755 --- a/extra/http/server/actions/actions-tests.factor +++ b/extra/http/server/actions/actions-tests.factor @@ -1,11 +1,16 @@ IN: http.server.actions.tests -USING: http.server.actions tools.test math math.parser -multiline namespaces http io.streams.string http.server -sequences accessors ; +USING: http.server.actions http.server.validators +tools.test math math.parser multiline namespaces http +io.streams.string http.server sequences accessors ; + +[ + "a" [ v-number ] { { "a" "123" } } validate-param + [ 123 ] [ "a" get ] unit-test +] with-scope [ "a" get "b" get + ] >>display - { { "a" [ string>number ] } { "b" [ string>number ] } } >>get-params + { { "a" [ v-number ] } { "b" [ v-number ] } } >>get-params "action-1" set STRING: action-request-test-1 @@ -22,8 +27,8 @@ blah ] unit-test - [ +path+ get "xxx" get "X" concat append ] >>submit - { { +path+ [ ] } { "xxx" [ string>number ] } } >>post-params + [ +append-path get "xxx" get "X" concat append ] >>submit + { { +append-path [ ] } { "xxx" [ v-number ] } } >>post-params "action-2" set STRING: action-request-test-2 diff --git a/extra/http/server/actions/actions.factor b/extra/http/server/actions/actions.factor index 72c2d2df8e..f39980037d 100755 --- a/extra/http/server/actions/actions.factor +++ b/extra/http/server/actions/actions.factor @@ -1,11 +1,11 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors new-slots sequences kernel assocs combinators +USING: accessors sequences kernel assocs combinators http.server http.server.validators http hashtables namespaces -combinators.cleave fry continuations ; +combinators.cleave fry continuations locals ; IN: http.server.actions -SYMBOL: +path+ +SYMBOL: +append-path SYMBOL: params @@ -17,17 +17,13 @@ TUPLE: action init display submit get-params post-params ; [ <400> ] >>display [ <400> ] >>submit ; -: with-validator ( string quot -- result error? ) - '[ , @ f ] [ - dup validation-error? [ t ] [ rethrow ] if - ] recover ; inline - -: validate-param ( name validator assoc -- error? ) - swap pick - >r >r at r> with-validator swap r> set ; +:: validate-param ( name validator assoc -- ) + name assoc at validator with-validator name set ; inline : action-params ( validators -- error? ) - [ params get validate-param ] { } assoc>map [ ] contains? ; + validation-failed? off + params get '[ , validate-param ] assoc-each + validation-failed? get ; : handle-get ( -- response ) action get get-params>> action-params [ <400> ] [ @@ -42,10 +38,13 @@ TUPLE: action init display submit get-params post-params ; action get display>> call exit-with ; M: action call-responder ( path action -- response ) - [ +path+ associate request-params union params set ] - [ action set ] bi* - request get method>> { - { "GET" [ handle-get ] } - { "HEAD" [ handle-get ] } - { "POST" [ handle-post ] } - } case ; + '[ + , , + [ +append-path associate request-params union params set ] + [ action set ] bi* + request get method>> { + { "GET" [ handle-get ] } + { "HEAD" [ handle-get ] } + { "POST" [ handle-post ] } + } case + ] with-exit-continuation ; diff --git a/extra/http/server/auth/auth.factor b/extra/http/server/auth/auth.factor index 1b1534b85e..69a3c76c2b 100755 --- a/extra/http/server/auth/auth.factor +++ b/extra/http/server/auth/auth.factor @@ -1,9 +1,26 @@ ! Copyright (c) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. USING: http.server.sessions accessors -http.server.auth.providers ; +http.server.auth.providers assocs namespaces kernel ; IN: http.server.auth SYMBOL: logged-in-user +SYMBOL: user-profile-changed? + +GENERIC: init-user-profile ( responder -- ) + +M: object init-user-profile drop ; : uid ( -- string ) logged-in-user sget username>> ; + +: profile ( -- assoc ) logged-in-user sget profile>> ; + +: uget ( key -- value ) + profile at ; + +: uset ( value key -- ) + profile set-at user-profile-changed? on ; + +: uchange ( quot key -- ) + profile swap change-at + user-profile-changed? on ; inline diff --git a/extra/http/server/auth/basic/basic.factor b/extra/http/server/auth/basic/basic.factor index 2ea74febba..04c0e62d07 100755 --- a/extra/http/server/auth/basic/basic.factor +++ b/extra/http/server/auth/basic/basic.factor @@ -1,6 +1,6 @@ ! Copyright (c) 2007 Chris Double. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors new-slots quotations assocs kernel splitting +USING: accessors quotations assocs kernel splitting base64 html.elements io combinators http.server http.server.auth.providers http.server.auth.providers.null http sequences ; diff --git a/extra/http/server/auth/login/edit-profile.fhtml b/extra/http/server/auth/login/edit-profile.fhtml new file mode 100755 index 0000000000..7d94ca1791 --- /dev/null +++ b/extra/http/server/auth/login/edit-profile.fhtml @@ -0,0 +1,77 @@ +<% USING: http.server.components http.server.auth.login +http.server namespaces kernel combinators ; %> + + +

Edit profile

+ +
+<% hidden-form-field %> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
User name:<% "username" component render-view %>
Real name:<% "realname" component render-edit %>
Specifying a real name is optional.
Current password:<% "password" component render-edit %>
If you don't want to change your current password, leave this field blank.
New password:<% "new-password" component render-edit %>
Verify:<% "verify-password" component render-edit %>
If you are changing your password, enter it twice to ensure it is correct.
E-mail:<% "email" component render-edit %>
Specifying an e-mail address is optional. It enables the "recover password" feature.
+ +

+ +<% { + { [ login-failed? get ] [ "invalid password" render-error ] } + { [ password-mismatch? get ] [ "passwords do not match" render-error ] } + { [ t ] [ ] } +} cond %> + +

+ +
+ + + diff --git a/extra/http/server/auth/login/login.factor b/extra/http/server/auth/login/login.factor index 9b2648158d..8c61a9dd47 100755 --- a/extra/http/server/auth/login/login.factor +++ b/extra/http/server/auth/login/login.factor @@ -1,21 +1,36 @@ ! Copyright (c) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. -USING: accessors new-slots quotations assocs kernel splitting +USING: accessors quotations assocs kernel splitting base64 html.elements io combinators http.server http.server.auth.providers http.server.auth.providers.null http.server.actions http.server.components http.server.sessions http.server.templating.fhtml http.server.validators http.server.auth http sequences io.files namespaces hashtables fry io.sockets combinators.cleave arrays threads locals -qualified ; +qualified continuations destructors ; IN: http.server.auth.login QUALIFIED: smtp -TUPLE: login users ; - SYMBOL: post-login-url SYMBOL: login-failed? +TUPLE: login users ; + +: users login get users>> ; + +! Destructor +TUPLE: user-saver user ; + +C: user-saver + +M: user-saver dispose + user-profile-changed? get [ + user>> users update-user + ] [ drop ] if ; + +: save-user-after ( user -- ) + add-always-destructor ; + ! ! ! Login : @@ -49,7 +64,7 @@ SYMBOL: login-failed? form validate-form "password" value "username" value - login get users>> check-login [ + users check-login [ successful-login ] [ login-failed? on @@ -67,7 +82,7 @@ SYMBOL: login-failed? t >>required add-field "realname" add-field - "password" + "new-password" t >>required add-field "verify-password" @@ -80,7 +95,7 @@ SYMBOL: password-mismatch? SYMBOL: user-exists? : same-password-twice ( -- ) - "password" value "verify-password" value = [ + "new-password" value "verify-password" value = [ password-mismatch? on validation-failed ] unless ; @@ -102,19 +117,76 @@ SYMBOL: user-exists? same-password-twice - values get [ - "username" get >>username - "realname" get >>realname - "password" get >>password - "email" get >>email - ] bind + + "username" value >>username + "realname" value >>realname + "new-password" value >>password + "email" value >>email - login get users>> new-user [ + users new-user [ user-exists? on validation-failed ] unless* successful-login + + login get responder>> init-user-profile + ] >>submit + ] ; + +! ! ! Editing user profile + +: ( -- form ) + "edit-profile"
+ "resource:extra/http/server/auth/login/edit-profile.fhtml" >>edit-template + "username" add-field + "realname" add-field + "password" add-field + "new-password" add-field + "verify-password" add-field + "email" add-field ; + +SYMBOL: previous-page + +:: ( -- action ) + [let | form [ ] | + + [ + blank-values + logged-in-user sget + dup username>> "username" set-value + dup realname>> "realname" set-value + dup email>> "email" set-value + ] >>init + + [ + "text/html" + [ form edit-form ] >>body + ] >>display + + [ + blank-values + uid "username" set-value + + form validate-form + + logged-in-user sget + + "password" value empty? [ + same-password-twice + + "password" value uid users check-login + [ login-failed? on validation-failed ] unless + + "new-password" value set-password + ] unless + + "realname" value >>realname + "email" value >>email + + user-profile-changed? on + + previous-page sget f ] >>submit ] ; @@ -186,7 +258,7 @@ SYMBOL: lost-password-from form validate-form "email" value "username" value - login get users>> issue-ticket [ + users issue-ticket [ send-password-email ] when* @@ -200,7 +272,7 @@ SYMBOL: lost-password-from "username" t >>required add-field - "password" + "new-password" t >>required add-field "verify-password" @@ -239,9 +311,9 @@ SYMBOL: lost-password-from "ticket" value "username" value - login get users>> claim-ticket [ - "password" value >>password - login get users>> update-user + users claim-ticket [ + "new-password" value >>password + users update-user "resource:extra/http/server/auth/login/recover-4.fhtml" serve-template @@ -265,13 +337,19 @@ TUPLE: protected responder ; C: protected +: show-login-page ( -- response ) + request get request-url post-login-url sset + "login" f ; + M: protected call-responder ( path responder -- response ) - logged-in-user sget [ responder>> call-responder ] [ + logged-in-user sget [ + dup save-user-after + request get request-url previous-page sset + responder>> call-responder + ] [ 2drop - request get method>> { "GET" "HEAD" } member? [ - request get request-url post-login-url sset - "login" f - ] [ <400> ] if + request get method>> { "GET" "HEAD" } member? + [ show-login-page ] [ <400> ] if ] if ; M: login call-responder ( path responder -- response ) @@ -283,10 +361,13 @@ M: login call-responder ( path responder -- response ) swap >>default "login" add-responder "logout" add-responder - no >>users ; + no-users >>users ; ! ! ! Configuration +: allow-edit-profile ( login -- login ) + "edit-profile" add-responder ; + : allow-registration ( login -- login ) "register" add-responder ; @@ -294,6 +375,9 @@ M: login call-responder ( path responder -- response ) "recover-password" add-responder "new-password" add-responder ; +: allow-edit-profile? ( -- ? ) + login get responders>> "edit-profile" swap key? ; + : allow-registration? ( -- ? ) login get responders>> "register" swap key? ; diff --git a/extra/http/server/auth/login/recover-3.fhtml b/extra/http/server/auth/login/recover-3.fhtml index edd32fffe8..ca4823baab 100755 --- a/extra/http/server/auth/login/recover-3.fhtml +++ b/extra/http/server/auth/login/recover-3.fhtml @@ -17,7 +17,7 @@ namespaces kernel combinators ; %> Password: -<% "password" component render-edit %> +<% "new-password" component render-edit %> diff --git a/extra/http/server/auth/login/register.fhtml b/extra/http/server/auth/login/register.fhtml index 99d1547d03..9106497def 100755 --- a/extra/http/server/auth/login/register.fhtml +++ b/extra/http/server/auth/login/register.fhtml @@ -26,7 +26,7 @@ http.server namespaces kernel combinators ; %> Password: -<% "password" component render-edit %> +<% "new-password" component render-edit %> diff --git a/extra/http/server/auth/providers/assoc/assoc-tests.factor b/extra/http/server/auth/providers/assoc/assoc-tests.factor index 12c799816d..f99e4d3d2e 100755 --- a/extra/http/server/auth/providers/assoc/assoc-tests.factor +++ b/extra/http/server/auth/providers/assoc/assoc-tests.factor @@ -3,7 +3,7 @@ USING: http.server.auth.providers http.server.auth.providers.assoc tools.test namespaces accessors kernel ; - "provider" set + "provider" set [ t ] [ @@ -22,11 +22,11 @@ namespaces accessors kernel ; [ f ] [ "fdasf" "slava" "provider" get check-login >boolean ] unit-test -[ t ] [ "foobar" "slava" "provider" get check-login >boolean ] unit-test +[ ] [ "foobar" "slava" "provider" get check-login "user" set ] unit-test -[ f ] [ "xx" "blah" "provider" get set-password ] unit-test +[ t ] [ "user" get >boolean ] unit-test -[ t ] [ "fdasf" "slava" "provider" get set-password ] unit-test +[ ] [ "user" get "fdasf" set-password drop ] unit-test [ t ] [ "fdasf" "slava" "provider" get check-login >boolean ] unit-test diff --git a/extra/http/server/auth/providers/assoc/assoc.factor b/extra/http/server/auth/providers/assoc/assoc.factor index 8433e54fda..18ec8da62a 100755 --- a/extra/http/server/auth/providers/assoc/assoc.factor +++ b/extra/http/server/auth/providers/assoc/assoc.factor @@ -1,19 +1,19 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. IN: http.server.auth.providers.assoc -USING: new-slots accessors assocs kernel +USING: accessors assocs kernel http.server.auth.providers ; -TUPLE: in-memory assoc ; +TUPLE: users-in-memory assoc ; -: ( -- provider ) - H{ } clone in-memory construct-boa ; +: ( -- provider ) + H{ } clone users-in-memory construct-boa ; -M: in-memory get-user ( username provider -- user/f ) +M: users-in-memory get-user ( username provider -- user/f ) assoc>> at ; -M: in-memory update-user ( user provider -- ) 2drop ; +M: users-in-memory update-user ( user provider -- ) 2drop ; -M: in-memory new-user ( user provider -- user/f ) +M: users-in-memory new-user ( user provider -- user/f ) >r dup username>> r> assoc>> 2dup key? [ 3drop f ] [ pick >r set-at r> ] if ; diff --git a/extra/http/server/auth/providers/db/db-tests.factor b/extra/http/server/auth/providers/db/db-tests.factor index 247359aea4..340e1bb35d 100755 --- a/extra/http/server/auth/providers/db/db-tests.factor +++ b/extra/http/server/auth/providers/db/db-tests.factor @@ -4,35 +4,36 @@ http.server.auth.providers.db tools.test namespaces db db.sqlite db.tuples continuations io.files accessors kernel ; -from-db "provider" set +users-in-db "provider" set "auth-test.db" temp-file sqlite-db [ - [ user drop-table ] ignore-errors - [ user create-table ] ignore-errors + init-users-table [ t ] [ - "slava" >>username - "foobar" >>password - "slava@factorcode.org" >>email - "provider" get new-user - username>> "slava" = + "slava" >>username + "foobar" >>password + "slava@factorcode.org" >>email + "provider" get new-user + username>> "slava" = ] unit-test [ f ] [ - "slava" >>username + "slava" >>username "provider" get new-user ] unit-test [ f ] [ "fdasf" "slava" "provider" get check-login >boolean ] unit-test - [ t ] [ "foobar" "slava" "provider" get check-login >boolean ] unit-test + [ ] [ "foobar" "slava" "provider" get check-login "user" set ] unit-test - [ f ] [ "xx" "blah" "provider" get set-password ] unit-test + [ t ] [ "user" get >boolean ] unit-test - [ t ] [ "fdasf" "slava" "provider" get set-password ] unit-test + [ ] [ "user" get "fdasf" set-password drop ] unit-test + + [ ] [ "user" get "provider" get update-user ] unit-test [ t ] [ "fdasf" "slava" "provider" get check-login >boolean ] unit-test diff --git a/extra/http/server/auth/providers/db/db.factor b/extra/http/server/auth/providers/db/db.factor index c9e1328052..1e84e544b8 100755 --- a/extra/http/server/auth/providers/db/db.factor +++ b/extra/http/server/auth/providers/db/db.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: db db.tuples db.types new-slots accessors -http.server.auth.providers kernel continuations ; +USING: db db.tuples db.types accessors +http.server.auth.providers kernel continuations +singleton ; IN: http.server.auth.providers.db user "USERS" @@ -16,20 +17,18 @@ user "USERS" : init-users-table user ensure-table ; -TUPLE: from-db ; - -: from-db T{ from-db } ; +SINGLETON: users-in-db : find-user ( username -- user ) swap >>username select-tuple ; -M: from-db get-user +M: users-in-db get-user drop find-user ; -M: from-db new-user +M: users-in-db new-user drop [ dup username>> find-user [ @@ -39,5 +38,5 @@ M: from-db new-user ] if ] with-transaction ; -M: from-db update-user +M: users-in-db update-user drop update-tuple ; diff --git a/extra/http/server/auth/providers/null/null.factor b/extra/http/server/auth/providers/null/null.factor index 7b8bfc627c..30f6dbd06e 100755 --- a/extra/http/server/auth/providers/null/null.factor +++ b/extra/http/server/auth/providers/null/null.factor @@ -3,14 +3,12 @@ USING: http.server.auth.providers kernel ; IN: http.server.auth.providers.null -! Named "no" because we can say no >>users +TUPLE: no-users ; -TUPLE: no ; +: no-users T{ no-users } ; -: no T{ no } ; +M: no-users get-user 2drop f ; -M: no get-user 2drop f ; +M: no-users new-user 2drop f ; -M: no new-user 2drop f ; - -M: no update-user 2drop ; +M: no-users update-user 2drop ; diff --git a/extra/http/server/auth/providers/providers.factor b/extra/http/server/auth/providers/providers.factor index 0aa27f870d..eda3babf0f 100755 --- a/extra/http/server/auth/providers/providers.factor +++ b/extra/http/server/auth/providers/providers.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel new-slots accessors random math.parser locals -sequences math ; +USING: kernel accessors random math.parser locals +sequences math crypto.sha2 ; IN: http.server.auth.providers TUPLE: user username realname password email ticket profile ; @@ -17,14 +17,7 @@ GENERIC: new-user ( user provider -- user/f ) : check-login ( password username provider -- user/f ) get-user dup [ [ password>> = ] keep and ] [ 2drop f ] if ; -:: set-password ( password username provider -- ? ) - [let | user [ username provider get-user ] | - user [ - user - password >>password - provider update-user t - ] [ f ] if - ] ; +: set-password ( user password -- user ) >>password ; ! Password recovery support @@ -34,7 +27,7 @@ GENERIC: new-user ( user provider -- user/f ) user email>> length 0 > [ user email>> email = [ user - random-256 >hex >>ticket + 256 random-bits >hex >>ticket dup provider update-user ] [ f ] if ] [ f ] if diff --git a/extra/http/server/callbacks/callbacks.factor b/extra/http/server/callbacks/callbacks.factor index ac03e0efc8..ab629ae236 100755 --- a/extra/http/server/callbacks/callbacks.factor +++ b/extra/http/server/callbacks/callbacks.factor @@ -2,9 +2,9 @@ ! Copyright (C) 2006, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: html http http.server io kernel math namespaces -continuations calendar sequences assocs new-slots hashtables +continuations calendar sequences assocs hashtables accessors arrays alarms quotations combinators -combinators.cleave fry ; +combinators.cleave fry assocs.lib ; IN: http.server.callbacks SYMBOL: responder @@ -98,11 +98,18 @@ SYMBOL: current-show cont-id query-param swap callbacks>> at ; M: callback-responder call-responder ( path responder -- response ) - [ callback-responder set ] - [ request get resuming-callback ] bi + '[ + , , - [ invoke-callback ] - [ callback-responder get responder>> call-responder ] ?if ; + [ callback-responder set ] + [ request get resuming-callback ] bi + + [ + invoke-callback + ] [ + callback-responder get responder>> call-responder + ] ?if + ] with-exit-continuation ; : show-page ( quot -- ) >r redirect-to-here store-current-show r> diff --git a/extra/http/server/components/components-tests.factor b/extra/http/server/components/components-tests.factor index 2a507e6416..d372865b7e 100755 --- a/extra/http/server/components/components-tests.factor +++ b/extra/http/server/components/components-tests.factor @@ -1,6 +1,6 @@ IN: http.server.components.tests USING: http.server.components http.server.validators -namespaces tools.test kernel accessors new-slots +namespaces tools.test kernel accessors tuple-syntax mirrors http.server.actions ; validation-failed? off @@ -86,3 +86,24 @@ TUPLE: test-tuple text number more-text ; [ t ] [ "number" value validation-error? ] unit-test ] with-scope + +[ + [ ] [ + "n" + 0 >>min-value + 10 >>max-value + "n" set + ] unit-test + + [ "123" ] [ + "123" "n" get validate value>> + ] unit-test + + [ ] [ "n" get t >>integer drop ] unit-test + + [ 3 ] [ + "3" "n" get validate + ] unit-test +] with-scope + +[ t ] [ "wake up sheeple" dup "n" validate = ] unit-test diff --git a/extra/http/server/components/components.factor b/extra/http/server/components/components.factor index bb0fc4b3dd..516abe79a5 100755 --- a/extra/http/server/components/components.factor +++ b/extra/http/server/components/components.factor @@ -1,21 +1,19 @@ ! Copyright (C) 2008 Slava Pestov ! See http://factorcode.org/license.txt for BSD license. -USING: new-slots html.elements http.server.validators accessors +USING: html.elements http.server.validators accessors namespaces kernel io math.parser assocs classes words tuples arrays sequences io.files http.server.templating.fhtml http.server.actions splitting mirrors hashtables combinators.cleave fry continuations math ; IN: http.server.components -SYMBOL: validation-failed? - SYMBOL: components TUPLE: component id required default ; : component ( name -- component ) dup components get at - [ ] [ "No such component: " swap append throw ] ?if ; + [ ] [ "No such component: " prepend throw ] ?if ; GENERIC: validate* ( value component -- result ) GENERIC: render-view* ( value component -- ) @@ -30,16 +28,13 @@ SYMBOL: values : validate ( value component -- result ) '[ - , , + , over empty? [ [ default>> [ v-default ] when* ] [ required>> [ v-required ] when ] bi ] [ validate* ] if - ] [ - dup validation-error? - [ validation-failed? on ] [ rethrow ] if - ] recover ; + ] with-validator ; : render-view ( component -- ) [ id>> value ] [ render-view* ] bi ; @@ -192,15 +187,16 @@ M: password render-error* render-edit* render-error ; ! Number fields -TUPLE: number min-value max-value ; +TUPLE: number min-value max-value integer ; : ( id -- component ) number ; M: number validate* [ v-number ] [ + [ integer>> [ v-integer ] when ] [ min-value>> [ v-min-value ] when* ] [ max-value>> [ v-max-value ] when* ] - bi + tri ] bi* ; M: number render-view* @@ -215,7 +211,12 @@ M: number render-error* ! Text areas TUPLE: text ; -: ( id -- component ) text construct-delegate ; +: ( id -- component ) text ; + +M: text validate* drop ; + +M: text render-view* + drop write ; : render-textarea