Merge branch 'master' of git://factorcode.org/git/factor

db4
Matthew Willis 2008-03-22 00:28:47 -07:00
commit 297978b7d2
401 changed files with 5456 additions and 2970 deletions

2
.gitignore vendored
View File

@ -18,4 +18,4 @@ factor
temp
logs
work
misc/wordsize
buildsupport/wordsize

View File

@ -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

168
build-support/grovel.c Normal file
View File

@ -0,0 +1,168 @@
#include <stdio.h>
#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 <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#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;
}

38
build-support/target Executable file
View File

@ -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

View File

@ -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" }

View File

@ -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> alien-address 0 > ] unit-test
@ -68,3 +68,7 @@ cell 8 = [
[ f ] [ 0 B{ 1 2 3 } <displaced-alien> pinned-c-ptr? ] unit-test
[ "( displaced alien )" ] [ 0 B{ 1 2 3 } <displaced-alien> unparse ] unit-test
[ f ] [ DLL" fadfasdfsada" dll-valid? ] unit-test
[ f ] [ "does not exist" DLL" fadsfasfdsaf" dlsym ] unit-test

View File

@ -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 -- )
<library> 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 ;

View File

@ -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 <c-object> }
{ $subsection <c-array> }
{ $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:"

View File

@ -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 ]

View File

@ -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 ;

View File

@ -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>>
[ <reversed> (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 ;

View File

@ -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 ;

View File

@ -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 )

View File

@ -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
<PRIVATE
: parse-arglist ( return seq -- types effect )
2 group dup keys swap values
2 group dup keys swap values [ "," ?tail drop ] map
rot dup "void" = [ drop { } ] [ 1array ] if <effect> ;
: 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 <alien> parsed ; parsing

View File

@ -79,7 +79,7 @@ nl
"." write flush
{
malloc free memcpy
malloc calloc free memcpy
} compile
" done" print flush

View File

@ -349,7 +349,7 @@ M: curry '
[
{
dictionary source-files
typemap builtins class<map update-map
typemap builtins class<map class-map update-map
} [ dup get swap bootstrap-word set ] each
] H{ } make-assoc
bootstrap-global set

View File

@ -1,12 +1,12 @@
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: bootstrap.primitives
USING: alien arrays byte-arrays generic hashtables
hashtables.private io kernel math namespaces parser sequences
strings vectors words quotations assocs layouts classes tuples
kernel.private vocabs vocabs.loader source-files definitions
slots classes.union compiler.units bootstrap.image.private
io.files ;
slots.deprecated classes.union compiler.units
bootstrap.image.private io.files ;
IN: bootstrap.primitives
"Creating primitives and basic runtime structures..." print flush
@ -30,6 +30,10 @@ crossref off
"syntax" vocab vocab-words bootstrap-syntax set
H{ } clone dictionary set
H{ } clone changed-words set
H{ } clone root-cache set
! Vocabulary for slot accessors
"accessors" create-vocab drop
! Trivial recompile hook. We don't want to touch the code heap
! during stage1 bootstrap, it would just waste time.
@ -87,15 +91,12 @@ call
"words.private"
"vectors"
"vectors.private"
} [
dup find-vocab-root swap create-vocab
[ set-vocab-root ] keep
f swap set-vocab-source-loaded?
] each
} [ create-vocab drop ] each
H{ } clone source-files set
H{ } clone class<map set
H{ } clone update-map set
H{ } clone class<map set
H{ } clone class-map set
! Builtin classes
: builtin-predicate-quot ( class -- quot )
@ -550,7 +551,7 @@ builtins get num-tags get tail f union-class define-class
{ "eq?" "kernel" }
{ "getenv" "kernel.private" }
{ "setenv" "kernel.private" }
{ "(stat)" "io.files.private" }
{ "(exists?)" "io.files.private" }
{ "(directory)" "io.files.private" }
{ "data-gc" "memory" }
{ "code-gc" "memory" }

View File

@ -47,6 +47,7 @@ vocabs.loader system debugger continuations ;
"listener" vocab
[ restarts. vocab-main execute ]
[ die ] if*
1 exit
] recover
] [
"Cannot find " write write "." print

View File

@ -12,7 +12,7 @@ SYMBOL: bootstrap-time
: default-image-name ( -- string )
vm file-name windows? [ "." split1 drop ] when
".image" append ;
".image" append resource-path ;
: do-crossref ( -- )
"Cross-referencing..." print flush
@ -25,7 +25,7 @@ SYMBOL: bootstrap-time
"exclude" "include"
[ get-global " " split [ empty? not ] subset ] 2apply
seq-diff
[ "bootstrap." swap append require ] each ;
[ "bootstrap." prepend require ] each ;
: compile-remaining ( -- )
"Compiling remaining words..." print flush
@ -57,7 +57,7 @@ millis >r
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

View File

@ -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:"

View File

@ -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

View File

@ -8,11 +8,12 @@ vectors math quotations combinators sorting effects graphs ;
PREDICATE: word class ( obj -- ? ) "class" word-prop ;
SYMBOL: typemap
SYMBOL: class-map
SYMBOL: class<map
SYMBOL: update-map
SYMBOL: builtins
PREDICATE: word builtin-class
PREDICATE: class builtin-class
"metaclass" word-prop builtin-class eq? ;
PREDICATE: class tuple-class
@ -58,6 +59,7 @@ PREDICATE: word predicate "predicating" word-prop >boolean ;
{ [ 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 class<map+ update-map+ ;
dup typemap+ dup class-map+ dup class<map+ update-map+ ;
: cache-classes ( assoc -- )
[ drop cache-class ] assoc-each ;
@ -229,7 +258,7 @@ M: word reset-class drop ;
GENERIC: uncache-class ( class -- )
M: class uncache-class
dup update-map- dup class<map- typemap- ;
dup update-map- dup class<map- dup class-map- typemap- ;
M: word uncache-class drop ;

View File

@ -13,7 +13,7 @@ PREDICATE: class union-class
drop [ drop f ]
] [
unclip first "predicate" word-prop swap
[ >r "predicate" word-prop [ dup ] swap append r> ]
[ >r "predicate" word-prop [ dup ] prepend r> ]
assoc-map alist>quot
] if ;

View File

@ -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? [

View File

@ -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 ;

View File

@ -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:"

View File

@ -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 <char> [ { byte-array } declare *char ] compile-call ] unit-test
[ 156 ] [ -100 <uchar> [ { byte-array } declare *uchar ] compile-call ] unit-test

View File

@ -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" } "):"

View File

@ -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:"

View File

@ -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 ]

View File

@ -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" ;
<PRIVATE
: init-debugger ( -- )

View File

@ -1,10 +1,10 @@
IN: definitions.tests
USING: tools.test generic kernel definitions sequences
compiler.units ;
compiler.units words ;
TUPLE: combination-1 ;
M: combination-1 perform-combination 2drop { } [ ] each [ ] ;
M: combination-1 perform-combination 2drop [ ] ;
M: combination-1 make-default-method 2drop [ "No method" throw ] ;
@ -13,7 +13,7 @@ SYMBOL: generic-1
[
generic-1 T{ combination-1 } define-generic
[ ] object \ generic-1 define-method
object \ generic-1 create-method [ ] define
] with-compilation-unit
[ ] [

View File

@ -3,10 +3,7 @@
IN: definitions
USING: kernel sequences namespaces assocs graphs ;
TUPLE: no-compilation-unit definition ;
: no-compilation-unit ( definition -- * )
\ no-compilation-unit construct-boa throw ;
ERROR: no-compilation-unit definition ;
GENERIC: where ( defspec -- loc )

View File

@ -85,7 +85,7 @@ HELP: pop-back*
{ $see-also push-front push-back pop-front pop-front* pop-back } ;
HELP: dlist-find
{ $values { "quot" quotation } { "dlist" { $link dlist } } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
{ $description "Applies the quotation to each element of the " { $link dlist } " in turn, until it outputs a true value or the end of the " { $link dlist } " is reached. Outputs either the object it found or " { $link f } ", and a boolean which is true if an object is found." }
{ $notes "Returns a boolean to allow dlists to store " { $link f } "."
$nl
@ -93,20 +93,20 @@ HELP: dlist-find
} ;
HELP: dlist-contains?
{ $values { "quot" quotation } { "dlist" { $link dlist } } { "?" "a boolean" } }
{ $values { "dlist" { $link dlist } } { "quot" quotation } { "?" "a boolean" } }
{ $description "Just like " { $link dlist-find } " except it doesn't return the object." }
{ $notes "This operation is O(n)." } ;
HELP: delete-node-if*
{ $values { "quot" quotation } { "dlist" { $link dlist } } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
{ $description "Calls " { $link dlist-find } " on the " { $link dlist } " and deletes the node returned, if any. Returns the value of the deleted node and a boolean to allow the deleted value to distinguished from " { $link f } ", for nothing deleted." }
{ $notes "This operation is O(n)." } ;
HELP: delete-node-if
{ $values { "quot" quotation } { "dlist" { $link dlist } } { "obj/f" "an object or " { $link f } } }
{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } }
{ $description "Like " { $link delete-node-if* } " but cannot distinguish from deleting a node whose value is " { $link f } " or not deleting an element." }
{ $notes "This operation is O(n)." } ;
HELP: dlist-each
{ $values { "quot" quotation } { "dlist" { $link dlist } } }
{ $values { "dlist" { $link dlist } } { "quot" quotation } }
{ $description "Iterate a " { $link dlist } ", calling quot on each element." } ;

View File

@ -43,20 +43,20 @@ IN: dlists.tests
dlist-front dlist-node-next dlist-node-next
] unit-test
[ f f ] [ <dlist> [ 1 = ] swap dlist-find ] unit-test
[ 1 t ] [ <dlist> 1 over push-back [ 1 = ] swap dlist-find ] unit-test
[ f f ] [ <dlist> 1 over push-back [ 2 = ] swap dlist-find ] unit-test
[ f ] [ <dlist> 1 over push-back [ 2 = ] swap dlist-contains? ] unit-test
[ t ] [ <dlist> 1 over push-back [ 1 = ] swap dlist-contains? ] unit-test
[ f f ] [ <dlist> [ 1 = ] dlist-find ] unit-test
[ 1 t ] [ <dlist> 1 over push-back [ 1 = ] dlist-find ] unit-test
[ f f ] [ <dlist> 1 over push-back [ 2 = ] dlist-find ] unit-test
[ f ] [ <dlist> 1 over push-back [ 2 = ] dlist-contains? ] unit-test
[ t ] [ <dlist> 1 over push-back [ 1 = ] dlist-contains? ] unit-test
[ 1 ] [ <dlist> 1 over push-back [ 1 = ] swap delete-node-if ] unit-test
[ t ] [ <dlist> 1 over push-back [ 1 = ] over delete-node-if drop dlist-empty? ] unit-test
[ t ] [ <dlist> 1 over push-back [ 1 = ] over delete-node-if drop dlist-empty? ] unit-test
[ 0 ] [ <dlist> 1 over push-back [ 1 = ] over delete-node-if drop dlist-length ] unit-test
[ 1 ] [ <dlist> 1 over push-back 2 over push-back [ 1 = ] over delete-node-if drop dlist-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back [ 1 = ] over delete-node-if drop dlist-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back [ 2 = ] over delete-node-if drop dlist-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back [ 3 = ] over delete-node-if drop dlist-length ] unit-test
[ 1 ] [ <dlist> 1 over push-back [ 1 = ] delete-node-if ] unit-test
[ t ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop dlist-empty? ] unit-test
[ t ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop dlist-empty? ] unit-test
[ 0 ] [ <dlist> 1 over push-back dup [ 1 = ] delete-node-if drop dlist-length ] unit-test
[ 1 ] [ <dlist> 1 over push-back 2 over push-back dup [ 1 = ] delete-node-if drop dlist-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back dup [ 1 = ] delete-node-if drop dlist-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back dup [ 2 = ] delete-node-if drop dlist-length ] unit-test
[ 2 ] [ <dlist> 1 over push-back 2 over push-back 3 over push-back dup [ 3 = ] delete-node-if drop dlist-length ] unit-test
[ 0 ] [ <dlist> dlist-length ] unit-test
[ 1 ] [ <dlist> 1 over push-front dlist-length ] unit-test

View File

@ -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 ;
: <dlist> ( -- obj )
dlist construct-empty
0 over set-dlist-length ;
0 >>length ;
: dlist-empty? ( dlist -- ? ) dlist-front not ;
: dlist-empty? ( dlist -- ? ) front>> not ;
<PRIVATE
TUPLE: dlist-node obj prev next ;
C: <dlist-node> 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 <dlist-node> dup dup set-next-prev ] keep
[ set-dlist-front ] keep
[ front>> f swap <dlist-node> 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 <dlist-node> ] keep
[ dlist-back set-next-when ] 2keep
[ set-dlist-back ] 2keep
[ back>> f <dlist-node> ] 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 ) <dlist> [ push-front ] keep ;

View File

@ -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: <method>
{ $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" } }

View File

@ -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

View File

@ -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 ;
: <method> ( quot class generic -- method )
: <method> ( class generic -- method )
check-method
[ make-method-def ] 3keep
[ method-word-props ] 2keep
method-word-name f <word>
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
] [
[ <method> ] 2keep
[ set-at ] with-methods
drop [ <method> dup ] 2keep reveal-method
] if ;
: <default-method> ( generic combination -- method )
object bootstrap-word pick <method>
[ -rot make-default-method define ] keep ;
: define-default-method ( generic combination -- )
dupd make-default-method object bootstrap-word pick <method>
"default-method" set-word-prop ;
dupd <default-method> "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 ;

2
core/generic/math/math-docs.factor Normal file → Executable file
View File

@ -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 } "." } ;

View File

@ -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 ;

View File

@ -8,10 +8,6 @@ IN: generic.standard
TUPLE: standard-combination # ;
M: standard-combination method-prologue
standard-combination-# object
<array> swap add* [ declare ] curry ;
C: <standard-combination> 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> 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 ;

View File

@ -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 ;

View File

@ -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

View File

@ -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

View File

@ -354,7 +354,7 @@ M: object infer-call
\ setenv { object fixnum } { } <effect> set-primitive-effect
\ (stat) { string } { object object object object } <effect> set-primitive-effect
\ exists? { string } { object } <effect> set-primitive-effect
\ (directory) { string } { array } <effect> set-primitive-effect

View File

@ -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?
[ <reversed> [get-slots] ] [ duplicated-slots-error ] if

View File

@ -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 <encoder> drop ;
M: binary <decoder> drop ;

View File

@ -14,19 +14,19 @@ ARTICLE: "encodings-constructors" "Constructing an encoded stream"
{ $subsection <decoder> }
{ $subsection <encoder-duplex> } ;
HELP: <encoder> ( stream encoding -- newstream )
HELP: <encoder>
{ $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: <decoder> ( stream encoding -- newstream )
HELP: <decoder>
{ $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: <encoder-duplex> ( stream-in stream-out encoding -- duplex )
HELP: <encoder-duplex>
{ $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 <encoder> }
{ $subsection <decoder> } ;
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

View File

@ -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: <decoder> ( stream encoding -- newstream )
: replacement-char HEX: fffd ;
TUPLE: decoder stream code cr ;
ERROR: decode-error ;
GENERIC: <encoder> ( stream encoding -- newstream )
TUPLE: encoder stream code ;
ERROR: encode-error ;
! Decoding
TUPLE: decode-error ;
<PRIVATE
: decode-error ( -- * ) \ decode-error construct-empty throw ;
M: tuple-class <decoder> construct-empty <decoder> ;
M: tuple <decoder> 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 <sbuf> -rot decode-read-loop ;
TUPLE: decoder code cr ;
: <decoder> ( 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 <encoder> construct-empty <encoder> ;
M: tuple <encoder> encoder construct-boa ;
TUPLE: encode-error ;
: encode-error ( -- * ) \ encode-error construct-empty throw ;
TUPLE: encoder code ;
: <encoder> ( 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 <encoder> ;
over encoder? [ >r encoder-stream r> ] when <encoder> ;
: redecode ( stream encoding -- newstream )
over decoder? [ >r delegate r> ] when <decoder> ;
over decoder? [ >r decoder-stream r> ] when <decoder> ;
PRIVATE>
: <encoder-duplex> ( stream-in stream-out encoding -- duplex )
tuck reencode >r redecode r> <duplex-stream> ;

View File

@ -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
<PRIVATE
: starts-2? ( char -- ? )
-6 shift BIN: 10 number= ;
dup [ -6 shift BIN: 10 number= ] when ;
: append-nums ( buf bottom top state-out -- buf num state )
>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>

View File

@ -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 <file-reader> } " and " { $link <file-writer> } ", to prepare a pathname before passing it to underlying code." } ;
{ $description "Called by words such as " { $link <file-reader> } " and " { $link <file-writer> } " to prepare a pathname before passing it to underlying code." } ;
HELP: <pathname> ( str -- pathname )
{ $values { "str" "a pathname string" } { "pathname" pathname } }

View File

@ -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 <file-appender> dispose ] unit-test
[ 123 ] [
"core" ".test" [
[
ascii [
123 CHAR: a <repetition> >string write
] with-file-writer
] keep file-info size>>
] with-unique-file
] unit-test

View File

@ -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 <file-reader> 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 ;
<file-reader> contents ;
: with-file-writer ( path encoding quot -- )
>r <file-writer> 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 )

View File

@ -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 <string> write flush ] unit-test
[
"/core/io/test/binary.txt" <resource-reader>
[ 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 <string> write flush ] unit-test
! [
! "/core/io/test/binary.txt" <resource-reader>
! [ 0.2 read ] with-stream
! ] must-fail

View File

@ -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 <sbuf> [ stream-copy ] keep >string ;
[
[ 65536 read dup ] [ ] [ drop ] unfold concat f like
] with-stream ;

View File

@ -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
: <byte-writer> ( encoding -- stream )
@ -7,7 +7,7 @@ IN: io.streams.byte-array
: with-byte-writer ( encoding quot -- byte-array )
>r <byte-writer> r> [ stdio get ] compose with-stream*
>byte-array ; inline
dup encoder? [ encoder-stream ] when >byte-array ; inline
: <byte-reader> ( byte-array encoding -- stream )
>r >byte-vector dup reverse-here r> <decoder> ;

2
core/io/streams/c/c-docs.factor Normal file → Executable file
View File

@ -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"

View File

@ -11,11 +11,10 @@ TUPLE: duplex-stream in out closed? ;
: <duplex-stream> ( 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 ;

View File

@ -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 ;
: <string-reader> ( str -- stream )
>sbuf dup reverse-here f <decoder> ;
>sbuf dup reverse-here null <decoder> ;
: with-string-reader ( str quot -- )
>r <string-reader> r> with-stream ; inline

View File

@ -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" } }

View File

@ -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 ;
<PRIVATE

View File

@ -2,14 +2,17 @@ USING: help.markup help.syntax slots kernel assocs sequences ;
IN: mirrors
ARTICLE: "mirrors" "Mirrors"
"A reflective view of an object's slots and their values:"
"The " { $vocab-link "mirrors" } " vocabulary defines data types which present an object's slots and slot values as an associative structure. This enables idioms such as iteration over all slots in a tuple, or editing of tuples, sequences and assocs in a generic fashion. This functionality is used by developer tools and meta-programming utilities."
$nl
"A mirror provides such a view of a tuple:"
{ $subsection mirror }
{ $subsection <mirror> }
"A view of a sequence as an associative structure:"
"An enum provides such a view of a sequence:"
{ $subsection enum }
{ $subsection <enum> }
"Utility word used by developer tools which inspect objects:"
{ $subsection make-mirror } ;
{ $subsection make-mirror }
{ $see-also "slots" } ;
ABOUT: "mirrors"

View File

@ -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 <array>
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 ;

View File

@ -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." } ;

View File

@ -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"
<string-reader> "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 ;"
<string-reader> "redefining-a-class-6" parse-stream drop
] unit-test
2 [
[ ] [
"IN: parser.tests TUPLE: foo ; GENERIC: foo"
<string-reader> "redefining-a-class-5" parse-stream drop
] unit-test
[ f ] [ f "foo" "parser.tests" lookup execute ] unit-test
[ ] [
"IN: parser.tests M: f foo ;"
<string-reader> "redefining-a-class-6" parse-stream drop
] unit-test
[ ] [
"IN: parser.tests TUPLE: foo ; GENERIC: foo"
<string-reader> "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"
<string-reader> "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"
<string-reader> "redefining-a-class-7" parse-stream drop
] unit-test
] unit-test
[ ] [
"IN: parser.tests TUPLE: foo ;"
<string-reader> "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 ;"
<string-reader> "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
<string-reader> "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

View File

@ -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 <vector> 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 ;

View File

@ -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

View File

@ -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.

View File

@ -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 -- )

View File

@ -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 <effect> ;
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 <effect> ;
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 <slot-spec>
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 <slot-spec> ;
: 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 ;

144
core/slots/slots-docs.factor Normal file → Executable file
View File

@ -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
"<email>"
" \"Happy birthday\" >>subject"
" { \"bob@bigcorp.com\" } >>to"
" \"alice@bigcorp.com\" >>from"
"send-email"
}
"The following uses writers, and requires some stack shuffling:"
{ $code
"<email>"
" \"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
"<email>"
" swap >>subject"
" swap >>to"
" \"alice@bigcorp.com\" >>from"
"send-email"
}
"This is because " { $link swap } " is easier to understand than " { $link tuck } ":"
{ $code
"<email>"
" 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." } ;

View File

@ -10,14 +10,12 @@ TUPLE: slot-spec type name offset reader writer ;
C: <slot-spec> 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 <effect> ;
: reader-quot ( decl -- quot )
[
\ slot ,
@ -25,91 +23,62 @@ C: <slot-spec> 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 <effect> ;
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 <slot-spec>
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 <slot-spec> ;
: 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 ;

View File

@ -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 <groups>
2 over set-length
>array
] unit-test

View File

@ -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

View File

@ -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 } }

View File

@ -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 <standard-combination> 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
<hook-combination> 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

View File

@ -14,3 +14,5 @@ yield
[ 3 ] [
[ 3 swap resume-with ] "Test suspend" suspend
] unit-test
[ f ] [ f get-global ] unit-test

View File

@ -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 -- ? )

View File

@ -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 "<point>" } "."
$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> rgba"
": <rgba> color construct-boa ; ! identical to above"
""
": <rgb> f <rgba> ;"
""
": <color> construct-empty ;"
": <color> f f f f <rgba> ; ! 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 <ellipse> \"my-ellipse\" set"
"{ 1 0 0 } <colored> \"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 )"
" employee construct-empty ;" }
"Or we may wish the default constructor to always give employees a starting salary:"
{ $code
": <employee> ( -- employee )"
" employee construct-empty"
" 40000 >>salary ;"
}
"We can define more refined constructors:"
{ $code
": <manager> ( -- manager )"
" <employee> \"project manager\" >>position ;" }
"An alternative strategy is to define the most general BOA constructor first:"
{ $code
": <employee> ( name position -- person )"
" 40000 employee construct-boa ;"
}
"Now we can define more specific constructors:"
{ $code
": <manager> ( name -- person )"
" \"manager\" <person> ;" }
"An example using reader words:"
{ $code
"TUPLE: check to amount number ;"
""
"SYMBOL: checks"
""
": <check> ( to amount -- check )"
" checks counter check construct-boa ;"
""
": biweekly-paycheck ( employee -- check )"
" dup name>> swap salary>> 26 / <check> ;"
}
"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"

View File

@ -236,7 +236,7 @@ C: <erg's-reshape-problem> erg's-reshape-problem
[
"IN: tuples.tests SYMBOL: not-a-class C: <not-a-class> not-a-class" eval
] [ [ check-tuple? ] is? ] must-fail-with
] [ [ no-tuple-class? ] is? ] must-fail-with
! Hardcore unit tests
USE: threads

View File

@ -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

View File

@ -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 } "." }

View File

@ -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-link> vocab-files
"kernel" <vocab-link> 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 <vocab-link> run
"vocabs.loader.test.2" <vocab-link> 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 <vocab-link> where ] unit-test
[ "kernel" <vocab-link> 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 ;

View File

@ -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 )

View File

@ -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 } "." } ;

View File

@ -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 ;
: <vocab> ( 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 [ <vocab> ] 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 ;
: <vocab-link> ( name root -- vocab-link )
[ dup vocab-root ] unless* vocab-link construct-boa ;
: <vocab-link> ( 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 <vocab-link> ] if ;
UNION: vocab-spec vocab vocab-link ;
GENERIC: >vocab-link ( name -- vocab )
M: vocab-spec >vocab-link ;
M: string >vocab-link dup vocab [ ] [ <vocab-link> ] ?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 ;

View File

@ -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

View File

@ -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 ;
! =========================================================

View File

@ -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 ;

View File

@ -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 ;

View File

@ -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 ;

View File

@ -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

View File

@ -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

View File

@ -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 <mersenne-twister> random-generator set-global ]
"generator.random" add-init-hook

View File

@ -13,5 +13,6 @@ USING: vocabs.loader sequences ;
"tools.threads"
"tools.vocabs"
"tools.vocabs.browser"
"tools.vocabs.monitor"
"editors"
} [ require ] each

View File

@ -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 [

View File

@ -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

View File

@ -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 )

Some files were not shown because too many files have changed in this diff Show More