diff --git a/Factor.app/Contents/Info.plist b/Factor.app/Contents/Info.plist
index 7f58d46485..4669858677 100644
--- a/Factor.app/Contents/Info.plist
+++ b/Factor.app/Contents/Info.plist
@@ -32,7 +32,7 @@
CFBundlePackageType
APPL
CFBundleVersion
- 0.96
+ 0.97
NSHumanReadableCopyright
Copyright © 2003-2013 Factor developers
NSServices
diff --git a/GNUmakefile b/GNUmakefile
index eec78a9f6a..b4ccd5f7b7 100755
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,8 +1,5 @@
ifdef CONFIG
- CC = gcc
- CPP = g++
-
- VERSION = 0.96
+ VERSION = 0.97
BUNDLE = Factor.app
LIBPATH = -L/usr/X11R6/lib
@@ -14,7 +11,7 @@ ifdef CONFIG
ifdef DEBUG
CFLAGS += -g -DFACTOR_DEBUG
else
- CFLAGS += -O3
+ CFLAGS += -O3 -g
endif
ENGINE = $(DLL_PREFIX)factor$(DLL_SUFFIX)$(DLL_EXTENSION)
@@ -26,7 +23,6 @@ ifdef CONFIG
vm/alien.o \
vm/arrays.o \
vm/bignum.o \
- vm/booleans.o \
vm/byte_arrays.o \
vm/callbacks.o \
vm/callstack.o \
@@ -99,13 +95,10 @@ ifdef CONFIG
vm/data_heap.hpp \
vm/code_heap.hpp \
vm/gc.hpp \
- vm/debug.hpp \
vm/strings.hpp \
- vm/words.hpp \
vm/float_bits.hpp \
vm/io.hpp \
vm/image.hpp \
- vm/alien.hpp \
vm/callbacks.hpp \
vm/dispatch.hpp \
vm/entry_points.hpp \
@@ -124,7 +117,6 @@ ifdef CONFIG
vm/aging_collector.hpp \
vm/to_tenured_collector.hpp \
vm/code_block_visitor.hpp \
- vm/compaction.hpp \
vm/full_collector.hpp \
vm/arrays.hpp \
vm/math.hpp \
@@ -215,11 +207,11 @@ $(ENGINE): $(DLL_OBJS)
factor-lib: $(ENGINE)
factor: $(EXE_OBJS) $(DLL_OBJS)
- $(TOOLCHAIN_PREFIX)$(CPP) $(LIBPATH) -L. $(DLL_OBJS) \
+ $(TOOLCHAIN_PREFIX)$(CXX) $(LIBPATH) -L. $(DLL_OBJS) \
$(CFLAGS) -o $(EXECUTABLE) $(LIBS) $(EXE_OBJS)
factor-console: $(EXE_OBJS) $(DLL_OBJS)
- $(TOOLCHAIN_PREFIX)$(CPP) $(LIBPATH) -L. $(DLL_OBJS) \
+ $(TOOLCHAIN_PREFIX)$(CXX) $(LIBPATH) -L. $(DLL_OBJS) \
$(CFLAGS) $(CFLAGS_CONSOLE) -o $(CONSOLE_EXECUTABLE) $(LIBS) $(EXE_OBJS)
factor-ffi-test: $(FFI_TEST_LIBRARY)
@@ -234,16 +226,16 @@ vm/ffi_test.o: vm/ffi_test.c
$(TOOLCHAIN_PREFIX)$(CC) -c $(CFLAGS) $(FFI_TEST_CFLAGS) -o $@ $<
vm/master.hpp.gch: vm/master.hpp $(MASTER_HEADERS)
- $(TOOLCHAIN_PREFIX)$(CPP) -c -x c++-header $(CFLAGS) -o $@ $<
+ $(TOOLCHAIN_PREFIX)$(CXX) -c -x c++-header $(CFLAGS) -o $@ $<
%.o: %.cpp vm/master.hpp.gch
- $(TOOLCHAIN_PREFIX)$(CPP) -c $(CFLAGS) -o $@ $<
+ $(TOOLCHAIN_PREFIX)$(CXX) -c $(CFLAGS) -o $@ $<
%.o: %.S
$(TOOLCHAIN_PREFIX)$(CC) -c $(CFLAGS) -o $@ $<
%.o: %.mm vm/master.hpp.gch
- $(TOOLCHAIN_PREFIX)$(CPP) -c $(CFLAGS) -o $@ $<
+ $(TOOLCHAIN_PREFIX)$(CXX) -c $(CFLAGS) -o $@ $<
.SUFFIXES: .mm
diff --git a/Nmakefile b/Nmakefile
index 05aa8cb562..02dbfd4fa9 100755
--- a/Nmakefile
+++ b/Nmakefile
@@ -6,17 +6,28 @@ BOOTIMAGE_VERSION = latest
LINK_FLAGS = /nologo shell32.lib
CL_FLAGS = /nologo /O2 /WX /W3 /D_CRT_SECURE_NO_WARNINGS
-
-!IF DEFINED(DEBUG)
-LINK_FLAGS = $(LINK_FLAGS) /DEBUG
-CL_FLAGS = $(CL_FLAGS) /Zi /DFACTOR_DEBUG
-!ENDIF
+CL_FLAGS_VISTA = /D_WIN32_WINNT=0x0600
!IF "$(PLATFORM)" == "x86-32"
LINK_FLAGS = $(LINK_FLAGS) /safeseh
PLAF_DLL_OBJS = vm\os-windows-x86.32.obj vm\safeseh.obj vm\cpu-x86.obj
+
+!ELSEIF "$(PLATFORM)" == "x86-32-vista"
+LINK_FLAGS = $(LINK_FLAGS) /safeseh
+CL_FLAGS = $(CL_FLAGS) $(CL_FLAGS_VISTA)
+PLAF_DLL_OBJS = vm\os-windows-x86.32.obj vm\safeseh.obj vm\cpu-x86.obj
+
!ELSEIF "$(PLATFORM)" == "x86-64"
PLAF_DLL_OBJS = vm\os-windows-x86.64.obj vm\cpu-x86.obj
+
+!ELSEIF "$(PLATFORM)" == "x86-64-vista"
+CL_FLAGS = $(CL_FLAGS) $(CL_FLAGS_VISTA)
+PLAF_DLL_OBJS = vm\os-windows-x86.64.obj vm\cpu-x86.obj
+!ENDIF
+
+!IF DEFINED(DEBUG)
+LINK_FLAGS = $(LINK_FLAGS) /DEBUG
+CL_FLAGS = $(CL_FLAGS) /Zi /DFACTOR_DEBUG
!ENDIF
ML_FLAGS = /nologo /safeseh
@@ -29,7 +40,6 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
vm\alien.obj \
vm\arrays.obj \
vm\bignum.obj \
- vm\booleans.obj \
vm\byte_arrays.obj \
vm\callbacks.obj \
vm\callstack.obj \
@@ -104,6 +114,8 @@ default:
@echo Where platform is one of:
@echo x86-32
@echo x86-64
+ @echo x86-32-vista
+ @echo x86-64-vista
@exit 1
x86-32:
@@ -112,6 +124,12 @@ x86-32:
x86-64:
nmake /nologo PLATFORM=x86-64 /f Nmakefile all
+x86-32-vista:
+ nmake /nologo PLATFORM=x86-32-vista /f Nmakefile all
+
+x86-64-vista:
+ nmake /nologo PLATFORM=x86-64-vista /f Nmakefile all
+
clean:
del vm\*.obj
if exist factor.lib del factor.lib
@@ -121,6 +139,6 @@ clean:
if exist factor.dll del factor.dll
if exist factor.dll.lib del factor.dll.lib
-.PHONY: all default x86-32 x86-64 clean
+.PHONY: all default x86-32 x86-64 x86-32-vista x86-64-vista clean
.SUFFIXES: .rs
diff --git a/basis/alien/c-types/c-types.factor b/basis/alien/c-types/c-types.factor
index f8cdf9c197..f65080046b 100644
--- a/basis/alien/c-types/c-types.factor
+++ b/basis/alien/c-types/c-types.factor
@@ -318,6 +318,7 @@ M: pointer lookup-c-type
\ double typedef
cell 8 = [
+ ! 64bit-vm int
fixnum >>class
fixnum >>boxed-class
@@ -332,6 +333,7 @@ M: pointer lookup-c-type
[ >fixnum ] >>unboxer-quot
\ int typedef
+ ! 64bit-vm uint
fixnum >>class
fixnum >>boxed-class
@@ -345,6 +347,7 @@ M: pointer lookup-c-type
[ >fixnum ] >>unboxer-quot
\ uint typedef
+ ! 64bit-vm longlong
integer >>class
integer >>boxed-class
@@ -355,10 +358,11 @@ M: pointer lookup-c-type
8 >>align
8 >>align-first
"from_signed_cell" >>boxer
- "to_fixnum" >>unboxer
+ "to_signed_8" >>unboxer
[ >integer ] >>unboxer-quot
\ longlong typedef
+ ! 64bit-vm ulonglong
integer >>class
integer >>boxed-class
@@ -386,6 +390,7 @@ M: pointer lookup-c-type
\ ulonglong lookup-c-type \ uintptr_t typedef
\ ulonglong lookup-c-type \ size_t typedef
] [
+ ! 32bit-vm int
integer >>class
integer >>boxed-class
@@ -400,6 +405,7 @@ M: pointer lookup-c-type
[ >integer ] >>unboxer-quot
\ int typedef
+ ! 32bit-vm uint
integer >>class
integer >>boxed-class
@@ -413,6 +419,7 @@ M: pointer lookup-c-type
[ >integer ] >>unboxer-quot
\ uint typedef
+ ! 32bit-vm longlong
integer >>class
integer >>boxed-class
@@ -426,6 +433,7 @@ M: pointer lookup-c-type
[ >integer ] >>unboxer-quot
\ longlong typedef
+ ! 32bit-vm ulonglong
integer >>class
integer >>boxed-class
diff --git a/basis/alien/data/data.factor b/basis/alien/data/data.factor
index f8bd14456b..789094fb8b 100644
--- a/basis/alien/data/data.factor
+++ b/basis/alien/data/data.factor
@@ -8,7 +8,7 @@ QUALIFIED: math
IN: alien.data
: [ ( value c-type -- c-ptr )
- [ heap-size ] keep
+ [ heap-size (byte-array) ] keep
'[ 0 _ set-alien-value ] keep ; inline
: deref ( c-ptr c-type -- value )
diff --git a/basis/alien/endian/endian.factor b/basis/alien/endian/endian.factor
index f7cc0b0f97..ff0a0d09eb 100644
--- a/basis/alien/endian/endian.factor
+++ b/basis/alien/endian/endian.factor
@@ -4,7 +4,7 @@ USING: accessors alien alien.accessors alien.c-types alien.data
classes.struct.private combinators compiler.units endian fry
generalizations kernel macros math namespaces sequences words
arrays slots math.bitwise ;
-QUALIFIED-WITH: alien.c-types ac
+QUALIFIED-WITH: alien.c-types c
IN: alien.endian
ERROR: invalid-signed-conversion n ;
@@ -12,7 +12,7 @@ ERROR: invalid-signed-conversion n ;
: convert-signed-quot ( n -- quot )
{
{ 1 [ [ char ][ char deref ] ] }
- { 2 [ [ ac:short ][ ac:short deref ] ] }
+ { 2 [ [ c:short ][ c:short deref ] ] }
{ 4 [ [ int ][ int deref ] ] }
{ 8 [ [ longlong ][ longlong deref ] ] }
[ invalid-signed-conversion ]
@@ -47,7 +47,7 @@ ERROR: unknown-endian-c-type symbol ;
: endian-c-type>c-type-symbol ( symbol -- symbol' )
{
{ [ dup { ule16 ube16 } member? ] [ drop ushort ] }
- { [ dup { le16 be16 } member? ] [ drop ac:short ] }
+ { [ dup { le16 be16 } member? ] [ drop c:short ] }
{ [ dup { ule32 ube32 } member? ] [ drop uint ] }
{ [ dup { le32 be32 } member? ] [ drop int ] }
{ [ dup { ule64 ube64 } member? ] [ drop ulonglong ] }
@@ -111,7 +111,7 @@ ERROR: unknown-endian-c-type symbol ;
! otherwise return the opposite of our endianness
: endian-slot ( endian c-type pair -- endian-slot )
[ native-endianness get = ] 2dip rot [ drop ] [ nip pair>c-type ] if ;
-
+
ERROR: unsupported-endian-type endian slot ;
: slot>endian-slot ( endian slot -- endian-slot )
@@ -121,7 +121,7 @@ ERROR: unsupported-endian-type endian slot ;
{
{ [ dup char = ] [ 2drop char ] }
{ [ dup uchar = ] [ 2drop uchar ] }
- { [ dup ac:short = ] [ { le16 be16 } endian-slot ] }
+ { [ dup c:short = ] [ { le16 be16 } endian-slot ] }
{ [ dup ushort = ] [ { ule16 ube16 } endian-slot ] }
{ [ dup int = ] [ { le32 be32 } endian-slot ] }
{ [ dup uint = ] [ { ule32 ube32 } endian-slot ] }
diff --git a/basis/alien/enums/enums.factor b/basis/alien/enums/enums.factor
index cd4225c4ab..2056a5ad52 100644
--- a/basis/alien/enums/enums.factor
+++ b/basis/alien/enums/enums.factor
@@ -1,7 +1,7 @@
! (c)2010 Joe Groff, Erik Charlebois bsd license
-USING: accessors alien.c-types arrays combinators delegate fry
-generic.parser kernel macros math parser sequences words words.symbol
-classes.singleton assocs ;
+USING: accessors alien.c-types arrays assocs classes.singleton
+combinators delegate fry kernel macros math parser sequences
+words ;
IN: alien.enums
: define-enum ( word base-type members -- )
[ (define-enum) ]
[ [ define-enum-value ] assoc-each ] bi ;
-
+
PREDICATE: enum-c-type-word < c-type-word
"c-type" word-prop enum-c-type? ;
diff --git a/basis/alien/libraries/finder/finder-docs.factor b/basis/alien/libraries/finder/finder-docs.factor
new file mode 100644
index 0000000000..598fd3d214
--- /dev/null
+++ b/basis/alien/libraries/finder/finder-docs.factor
@@ -0,0 +1,24 @@
+USING: help.markup help.syntax ;
+IN: alien.libraries.finder
+
+HELP: find-library*
+{ $values
+ { "name" "a shared library name" }
+ { "path/f" "a filesystem path or f" }
+}
+{ $description
+ "Returns a filesystem path for a plain shared library name, or f if no library can be found."
+} ;
+
+HELP: find-library
+{ $values
+ { "name" "a shared library name" }
+ { "path/library-not-found" "a filesystem path or " { $snippet "name" } }
+}
+{ $description
+ "Used to load libraries whose exact filenames is not known in advance:"
+ { $code
+ "<< \"sqlite\" \"sqlite3\" find-library cdecl add-library >>"
+ }
+ "Note the parse time evaluation with " { $link POSTPONE: << } "."
+} ;
diff --git a/basis/alien/libraries/finder/finder-tests.factor b/basis/alien/libraries/finder/finder-tests.factor
new file mode 100644
index 0000000000..c0731a8464
--- /dev/null
+++ b/basis/alien/libraries/finder/finder-tests.factor
@@ -0,0 +1,5 @@
+USING: alien alien.libraries.finder tools.test ;
+IN: alien.libraries.finder
+
+{ f } [ "dont-exist" find-library* ] unit-test
+{ "dont-exist" } [ "dont-exist" find-library ] unit-test
diff --git a/basis/alien/libraries/finder/finder.factor b/basis/alien/libraries/finder/finder.factor
new file mode 100644
index 0000000000..3a763cf1b8
--- /dev/null
+++ b/basis/alien/libraries/finder/finder.factor
@@ -0,0 +1,21 @@
+USING: combinators kernel sequences system vocabs
+alien.libraries ;
+IN: alien.libraries.finder
+
+HOOK: find-library* os ( name -- path/f )
+
+: find-library ( name -- path/library-not-found )
+ dup find-library* [ nip ] when* ;
+
+! Try to find the library from a list, but if it's not found,
+! try to open a library that is the first name in that list anyway
+! or "library_not_found" as a last resort for better debugging.
+: find-library-from-list ( seq -- path/f )
+ dup [ find-library* ] map-find drop
+ [ nip ] [ ?first "library_not_found" or ] if* ;
+
+{
+ { [ os macosx? ] [ "alien.libraries.finder.macosx" ] }
+ { [ os linux? ] [ "alien.libraries.finder.linux" ] }
+ { [ os windows? ] [ "alien.libraries.finder.windows" ] }
+} cond require
diff --git a/basis/alien/libraries/finder/linux/linux-tests.factor b/basis/alien/libraries/finder/linux/linux-tests.factor
new file mode 100644
index 0000000000..416217560f
--- /dev/null
+++ b/basis/alien/libraries/finder/linux/linux-tests.factor
@@ -0,0 +1,5 @@
+USING: alien.libraries.finder sequences tools.test ;
+IN: alien.libraries.fidner.linux
+
+{ t } [ "libm.so" "m" find-library subseq? ] unit-test
+{ t } [ "libc.so" "c" find-library subseq? ] unit-test
diff --git a/basis/alien/libraries/finder/linux/linux.factor b/basis/alien/libraries/finder/linux/linux.factor
new file mode 100644
index 0000000000..5d2446fbf8
--- /dev/null
+++ b/basis/alien/libraries/finder/linux/linux.factor
@@ -0,0 +1,52 @@
+! Copyright (C) 2013 Björn Lindqvist, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license
+USING: alien.libraries.finder arrays assocs
+combinators.short-circuit io io.encodings.utf8 io.files
+io.files.info io.launcher kernel sequences sets splitting system
+unicode.categories ;
+IN: alien.libraries.finder.linux
+
+" split1 [ [ blank? ] trim ] bi@
+ [
+ " " split1 [ "()" in? ] trim "," split
+ [ [ blank? ] trim ] map
+ [ "OS ABI:" head? not ] filter
+ ] dip 3array
+ ] map ;
+
+: load-ldconfig-cache ( -- seq )
+ "/sbin/ldconfig -p" utf8 [ lines ] with-process-reader
+ rest parse-ldconfig-lines ;
+
+: ldconfig-arch ( -- str )
+ mach-map cpu of { "libc6" } or ;
+
+: name-matches? ( lib triple -- ? )
+ first swap ?head [ ?first CHAR: . = ] [ drop f ] if ;
+
+: arch-matches? ( lib triple -- ? )
+ [ drop ldconfig-arch ] [ second swap subset? ] bi* ;
+
+: ldconfig-matches? ( lib triple -- ? )
+ { [ name-matches? ] [ arch-matches? ] } 2&& ;
+
+: ldconfig-find-soname ( lib -- seq )
+ load-ldconfig-cache [ ldconfig-matches? ] with filter
+ [ third ] map ;
+
+PRIVATE>
+
+M: linux find-library*
+ "lib" prepend ldconfig-find-soname [
+ { [ exists? ] [ file-info regular-file? ] } 1&&
+ ] map-find nip ;
diff --git a/basis/tools/ps/platforms.txt b/basis/alien/libraries/finder/linux/platforms.txt
similarity index 100%
rename from basis/tools/ps/platforms.txt
rename to basis/alien/libraries/finder/linux/platforms.txt
diff --git a/basis/alien/libraries/finder/macosx/macosx-tests.factor b/basis/alien/libraries/finder/macosx/macosx-tests.factor
new file mode 100644
index 0000000000..3fe2f938c2
--- /dev/null
+++ b/basis/alien/libraries/finder/macosx/macosx-tests.factor
@@ -0,0 +1,50 @@
+
+USING: alien.libraries.finder
+alien.libraries.finder.macosx.private sequences tools.test ;
+
+IN: alien.libraries.finder.macosx
+
+{
+ {
+ f
+ f
+ f
+ f
+ T{ framework-info f "Location" "Name.framework/Name" "Name" f f }
+ T{ framework-info f "Location" "Name.framework/Name_suffix" "Name" f "suffix" }
+ f
+ f
+ T{ framework-info f "Location" "Name.framework/Versions/A/Name" "Name" "A" f }
+ T{ framework-info f "Location" "Name.framework/Versions/A/Name_suffix" "Name" "A" "suffix" }
+ }
+} [
+ {
+ "broken/path"
+ "broken/path/_suffix"
+ "Location/Name.framework"
+ "Location/Name.framework/_suffix"
+ "Location/Name.framework/Name"
+ "Location/Name.framework/Name_suffix"
+ "Location/Name.framework/Versions"
+ "Location/Name.framework/Versions/A"
+ "Location/Name.framework/Versions/A/Name"
+ "Location/Name.framework/Versions/A/Name_suffix"
+ } [ make-framework-info ] map
+] unit-test
+
+{
+ {
+ "/usr/lib/libSystem.dylib"
+ "/System/Library/Frameworks/System.framework/System"
+ }
+} [
+ {
+ "libSystem.dylib"
+ "System.framework/System"
+ } [ dyld-find ] map
+] unit-test
+
+{ t } [ "libm.dylib" "m" find-library subseq? ] unit-test
+{ t } [ "libc.dylib" "c" find-library subseq? ] unit-test
+{ t } [ "libbz2.dylib" "bz2" find-library subseq? ] unit-test
+{ t } [ "AGL.framework" "AGL" find-library subseq? ] unit-test
diff --git a/basis/alien/libraries/finder/macosx/macosx.factor b/basis/alien/libraries/finder/macosx/macosx.factor
new file mode 100644
index 0000000000..c6d260b6d9
--- /dev/null
+++ b/basis/alien/libraries/finder/macosx/macosx.factor
@@ -0,0 +1,135 @@
+! Copyright (C) 2013 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: accessors alien.libraries.finder arrays assocs
+combinators.short-circuit environment io.files io.files.info
+io.pathnames kernel locals make namespaces sequences splitting
+system ;
+
+IN: alien.libraries.finder.macosx
+
+>location ] [ >>name ] bi*
+ ] keep [
+ rest dup ?first "Versions" = [
+ rest dup empty? [
+ unclip swap [ >>version ] dip
+ ] unless
+ ] when ?first "_" split1 [ >>shortname ] [ >>suffix ] bi*
+ ] unless-empty
+ ] [ drop ] if* dup shortname>> empty? [ drop f ] when ;
+
+CONSTANT: default-framework-fallback {
+ "~/Library/Frameworks"
+ "/Library/Frameworks"
+ "/Network/Library/Frameworks"
+ "/System/Library/Frameworks"
+}
+
+CONSTANT: default-library-fallback {
+ "~/lib"
+ "/usr/local/lib"
+ "/lib"
+ "/usr/lib"
+}
+
+SYMBOL: dyld-environment
+
+: dyld-env ( name -- seq )
+ dyld-environment get [ at ] [ os-env ] if* ;
+
+: dyld-paths ( name -- seq )
+ dyld-env [ ":" split ] [ f ] if* ;
+
+: paths% ( name seq -- )
+ [ prepend-path , ] with each ;
+
+: dyld-override-search ( name -- seq )
+ [
+ dup make-framework-info [
+ name>> "DYLD_FRAMEWORK_PATH" dyld-paths paths%
+ ] when*
+
+ file-name "DYLD_LIBRARY_PATH" dyld-paths paths%
+ ] { } make ;
+
+SYMBOL: dyld-executable-path
+
+: dyld-executable-path-search ( name -- seq )
+ "@executable_path/" ?head dyld-executable-path get and [
+ dyld-executable-path get prepend-path
+ ] [
+ drop f
+ ] if ;
+
+:: dyld-default-search ( name -- seq )
+ name make-framework-info :> framework
+ name file-name :> basename
+ "DYLD_FALLBACK_FRAMEWORK_PATH" dyld-paths :> fallback-framework-path
+ "DYLD_FALLBACK_LIBRARY_PATH" dyld-paths :> fallback-library-path
+ [
+ name ,
+
+ framework [
+ name>> fallback-framework-path paths%
+ ] when*
+
+ basename fallback-library-path paths%
+
+ framework fallback-framework-path empty? and [
+ framework name>> default-framework-fallback paths%
+ ] when
+
+ fallback-library-path empty? [
+ basename default-library-fallback paths%
+ ] when
+ ] { } make ;
+
+: dyld-image-suffix-search ( seq -- str )
+ "DYLD_IMAGE_SUFFIX" dyld-env [
+ swap [
+ [
+ [
+ ".dylib" ?tail [ prepend ] dip
+ [ ".dylib" append ] when ,
+ ] [
+ ,
+ ] bi
+ ] with each
+ ] { } make
+ ] when* ;
+
+: dyld-search-paths ( name -- paths )
+ [ dyld-override-search ]
+ [ dyld-executable-path-search ]
+ [ dyld-default-search ] tri 3append
+ dyld-image-suffix-search ;
+
+PRIVATE>
+
+: dyld-find ( name -- path/f )
+ dyld-search-paths
+ [ { [ exists? ] [ file-info regular-file? ] } 1&& ] find
+ [ nip ] when* ;
+
+: framework-find ( name -- path )
+ dup dyld-find [ nip ] [
+ ".framework" over start [
+ dupd head
+ ] [
+ [ ".framework" append ] keep
+ ] if* file-name append-path dyld-find
+ ] if* ;
+
+M: macosx find-library*
+ [ "lib" ".dylib" surround ]
+ [ ".dylib" append ]
+ [ ".framework/" over 3append ] tri 3array
+ [ dyld-find ] map-find drop ;
diff --git a/basis/alien/libraries/finder/macosx/platforms.txt b/basis/alien/libraries/finder/macosx/platforms.txt
new file mode 100644
index 0000000000..6e806f449e
--- /dev/null
+++ b/basis/alien/libraries/finder/macosx/platforms.txt
@@ -0,0 +1 @@
+macosx
diff --git a/basis/alien/libraries/finder/windows/platforms.txt b/basis/alien/libraries/finder/windows/platforms.txt
new file mode 100644
index 0000000000..8e1a55995e
--- /dev/null
+++ b/basis/alien/libraries/finder/windows/platforms.txt
@@ -0,0 +1 @@
+windows
diff --git a/basis/alien/libraries/finder/windows/windows.factor b/basis/alien/libraries/finder/windows/windows.factor
new file mode 100644
index 0000000000..1f1fbbe38d
--- /dev/null
+++ b/basis/alien/libraries/finder/windows/windows.factor
@@ -0,0 +1,34 @@
+! Copyright (C) 2013 Björn Lindqvist, John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: alien.libraries.finder arrays combinators.short-circuit
+environment io.backend io.files io.files.info io.pathnames kernel
+sequences splitting system system-info.windows ;
+
+IN: alien.libraries.finder.windows
+
+
+
+M: windows find-library*
+ candidate-paths [
+ { [ exists? ] [ file-info regular-file? ] } 1&&
+ ] map-find nip ;
diff --git a/basis/alien/libraries/libraries-docs.factor b/basis/alien/libraries/libraries-docs.factor
index f9828e2835..b09cc904df 100644
--- a/basis/alien/libraries/libraries-docs.factor
+++ b/basis/alien/libraries/libraries-docs.factor
@@ -4,7 +4,7 @@ USING: accessors alien alien.syntax assocs help.markup
help.syntax io.backend kernel namespaces strings ;
IN: alien.libraries
-HELP:
+HELP: make-library
{ $values
{ "path" "a pathname string" } { "abi" "the ABI used by the library, either " { $link cdecl } " or " { $link stdcall } }
{ "library" library } }
diff --git a/basis/alien/libraries/libraries.factor b/basis/alien/libraries/libraries.factor
index 7e8611405e..5a06b01a84 100755
--- a/basis/alien/libraries/libraries.factor
+++ b/basis/alien/libraries/libraries.factor
@@ -17,16 +17,20 @@ SYMBOL: libraries
libraries [ H{ } clone ] initialize
-TUPLE: library { path string } { abi abi initial: cdecl } dll dlerror ;
+TUPLE: library { path string } dll dlerror { abi abi initial: cdecl } ;
+
+C: library
ERROR: no-library name ;
: lookup-library ( name -- library ) libraries get at ;
-: ( path abi -- library )
- over dup
- [ dlopen dup dll-valid? [ f ] [ dlerror ] if ] [ f ] if
- \ library boa ;
+: open-dll ( path -- dll dll-error/f )
+ [ dlopen dup dll-valid? [ f ] [ dlerror ] if ]
+ [ f f ] if* ;
+
+: make-library ( path abi -- library )
+ [ dup open-dll ] dip ;
: library-dll ( library -- dll )
dup [ dll>> ] when ;
@@ -48,7 +52,8 @@ M: library dispose dll>> [ dispose ] when* ;
: add-library ( name path abi -- )
3dup add-library? [
[ 2drop remove-library ]
- [ swap libraries get set-at ] 3bi
+ [ [ nip ] dip make-library ]
+ [ 2drop libraries get set-at ] 3tri
] [ 3drop ] if ;
: library-abi ( library -- abi )
diff --git a/basis/alien/parser/parser-tests.factor b/basis/alien/parser/parser-tests.factor
index 2333eb3725..ecbb92a03e 100644
--- a/basis/alien/parser/parser-tests.factor
+++ b/basis/alien/parser/parser-tests.factor
@@ -1,7 +1,7 @@
! (c)2009 Joe Groff bsd license
USING: accessors alien.c-types alien.parser alien.syntax
-tools.test vocabs.parser parser eval debugger kernel
-continuations words ;
+continuations debugger eval parser tools.test vocabs.parser
+words ;
IN: alien.parser.tests
TYPEDEF: char char2
diff --git a/basis/ascii/ascii-docs.factor b/basis/ascii/ascii-docs.factor
index ba94b11238..9242460718 100644
--- a/basis/ascii/ascii-docs.factor
+++ b/basis/ascii/ascii-docs.factor
@@ -1,44 +1,44 @@
-USING: help.markup help.syntax ;
+USING: help.markup help.syntax kernel strings ;
IN: ascii
HELP: blank?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for an ASCII whitespace character." } ;
HELP: letter?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for a lowercase alphabet ASCII character." } ;
HELP: LETTER?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for a uppercase alphabet ASCII character." } ;
HELP: digit?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for an ASCII decimal digit character." } ;
HELP: Letter?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for an ASCII alphabet character, both upper and lower case." } ;
HELP: alpha?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for an alphanumeric ASCII character." } ;
HELP: printable?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for a printable ASCII character." } ;
HELP: control?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for an ASCII control character." } ;
HELP: quotable?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for characters which may appear in a Factor string literal without escaping." } ;
HELP: ascii?
-{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $values { "ch" "a character" } { "?" boolean } }
{ $description "Tests for whether a number is an ASCII character." } ;
HELP: ch>lower
@@ -50,23 +50,23 @@ HELP: ch>upper
{ $description "Converts an ASCII character to upper case." } ;
HELP: >lower
-{ $values { "str" "a string" } { "lower" "a string" } }
+{ $values { "str" string } { "lower" string } }
{ $description "Converts an ASCII string to lower case." } ;
HELP: >upper
-{ $values { "str" "a string" } { "upper" "a string" } }
+{ $values { "str" string } { "upper" string } }
{ $description "Converts an ASCII string to upper case." } ;
HELP: >title
-{ $values { "str" "a string" } { "title" "a string" } }
+{ $values { "str" string } { "title" string } }
{ $description "Converts a string to title case." } ;
HELP: >words
-{ $values { "str" "a string" } { "words" "an array of slices" } }
+{ $values { "str" string } { "words" "an array of slices" } }
{ $description "Divides the string up into words." } ;
HELP: capitalize
-{ $values { "str" "a string" } { "str'" "a string" } }
+{ $values { "str" string } { "str'" string } }
{ $description "Capitalize all the words in a string." } ;
ARTICLE: "ascii" "ASCII"
diff --git a/basis/atk/ffi/ffi.factor b/basis/atk/ffi/ffi.factor
index 8a7be511c6..3f7ad28b91 100644
--- a/basis/atk/ffi/ffi.factor
+++ b/basis/atk/ffi/ffi.factor
@@ -13,7 +13,8 @@ LIBRARY: atk
<<
"atk" {
{ [ os windows? ] [ "libatk-1.0-0.dll" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
+ { [ os macosx? ] [ "libatk-1.0.dylib" cdecl add-library ] }
+ { [ os unix? ] [ "libatk-1.0.so" cdecl add-library ] }
} cond
>>
diff --git a/basis/base64/base64.factor b/basis/base64/base64.factor
index c3847f5d51..0f25a812be 100644
--- a/basis/base64/base64.factor
+++ b/basis/base64/base64.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2008 Doug Coleman, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: combinators fry io io.binary io.encodings.binary
-io.streams.byte-array kernel math namespaces
+io.streams.byte-array kernel math namespaces sbufs
sequences strings ;
IN: base64
@@ -11,12 +11,15 @@ ERROR: malformed-base64 ;
: read1-ignoring ( ignoring stream -- ch )
dup stream-read1 pick dupd member?
- [ drop read1-ignoring ] [ 2nip ] if ;
+ [ drop read1-ignoring ] [ 2nip ] if ; inline recursive
-: read-ignoring ( n ignoring stream -- str )
- '[ _ _ read1-ignoring ] replicate
- [ { f 0 } member-eq? not ] "" filter-as
- [ f ] when-empty ;
+: push-ignoring ( accum ch -- accum )
+ dup { f 0 } member-eq? [ drop ] [ over push ] if ; inline
+
+: read-ignoring ( n ignoring stream -- str/f )
+ [ [ ] keep ] 2dip
+ '[ _ _ read1-ignoring push-ignoring ] times
+ [ f ] [ "" like ] if-empty ; inline
: ch>base64 ( ch -- ch )
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
@@ -47,8 +50,8 @@ SYMBOL: column
: encode3 ( seq -- )
column output-stream get '[
- swap be> { 3 2 1 0 } [
- -6 * shift 0x3f bitand ch>base64 _ write1-lines
+ swap be> { -18 -12 -6 0 } [
+ shift 0x3f bitand ch>base64 _ write1-lines
] with each
] change ; inline
diff --git a/basis/binary-search/binary-search-docs.factor b/basis/binary-search/binary-search-docs.factor
index da71d34dce..289435c5b3 100644
--- a/basis/binary-search/binary-search-docs.factor
+++ b/basis/binary-search/binary-search-docs.factor
@@ -2,7 +2,7 @@ IN: binary-search
USING: help.markup help.syntax sequences kernel math.order ;
HELP: search
-{ $values { "seq" "a sorted sequence" } { "quot" { $quotation "( elt -- <=> )" } } { "i" "an index, or " { $link f } } { "elt" "an element, or " { $link f } } }
+{ $values { "seq" "a sorted sequence" } { "quot" { $quotation ( elt -- <=> ) } } { "i" "an index, or " { $link f } } { "elt" "an element, or " { $link f } } }
{ $description "Performs a binary search on a sequence, calling the quotation to decide whether to end the search (" { $link +eq+ } "), search lower (" { $link +lt+ } ") or search higher (" { $link +gt+ } ")."
$nl
"If the sequence is non-empty, outputs the index and value of the closest match, which is either an element for which the quotation output " { $link +eq+ } ", or failing that, least element for which the quotation output " { $link +lt+ } "."
@@ -34,13 +34,13 @@ HELP: sorted-index
{ index index-from last-index last-index-from sorted-index } related-words
HELP: sorted-member?
-{ $values { "obj" object } { "seq" "a sorted sequence" } { "?" "a boolean" } }
+{ $values { "obj" object } { "seq" "a sorted sequence" } { "?" boolean } }
{ $description "Tests if the sorted sequence contains " { $snippet "elt" } ". Equality is tested with " { $link = } "." } ;
{ member? sorted-member? } related-words
HELP: sorted-member-eq?
-{ $values { "obj" object } { "seq" "a sorted sequence" } { "?" "a boolean" } }
+{ $values { "obj" object } { "seq" "a sorted sequence" } { "?" boolean } }
{ $description "Tests if the sorted sequence contains " { $snippet "elt" } ". Equality is tested with " { $link eq? } "." } ;
{ member-eq? sorted-member-eq? } related-words
diff --git a/basis/bit-arrays/bit-arrays-docs.factor b/basis/bit-arrays/bit-arrays-docs.factor
index df81771ae0..899cfebcaf 100644
--- a/basis/bit-arrays/bit-arrays-docs.factor
+++ b/basis/bit-arrays/bit-arrays-docs.factor
@@ -1,5 +1,4 @@
-USING: arrays help.markup help.syntax kernel
-kernel.private math prettyprint strings vectors sbufs ;
+USING: help.markup help.syntax math sequences ;
IN: bit-arrays
ARTICLE: "bit-arrays" "Bit arrays"
@@ -48,7 +47,7 @@ HELP:
{ $description "Creates a new bit array with the given length and all elements initially set to " { $link f } "." } ;
HELP: >bit-array
-{ $values { "seq" "a sequence" } { "bit-array" bit-array } }
+{ $values { "seq" sequence } { "bit-array" bit-array } }
{ $description "Outputs a freshly-allocated bit array whose elements have the same boolean values as a given sequence." } ;
HELP: clear-bits
diff --git a/basis/bit-sets/bit-sets.factor b/basis/bit-sets/bit-sets.factor
index b70b62a74b..0f1bca7999 100644
--- a/basis/bit-sets/bit-sets.factor
+++ b/basis/bit-sets/bit-sets.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors sequences byte-arrays bit-arrays math
-math.bitwise hints sets ;
+USING: accessors bit-arrays fry kernel math math.bitwise
+sequences sequences.private sets ;
IN: bit-sets
TUPLE: bit-set { table bit-array read-only } ;
@@ -22,9 +22,7 @@ M: bit-set adjoin
M: bit-set delete
! This isn't allowed to throw an error if the elt wasn't
! in the set
- over integer? [
- [ f ] 2dip table>> ?set-nth
- ] [ 2drop ] if ;
+ over integer? [ [ f ] 2dip table>> ?set-nth ] [ 2drop ] if ;
! If you do binary set operations with a bit-set, it's expected
! that the other thing can also be represented as a bit-set
@@ -37,13 +35,9 @@ ERROR: check-bit-set-failed ;
dup bit-set? [ check-bit-set-failed ] unless ; inline
: bit-set-map ( seq1 seq2 quot -- seq )
- [ 2drop length>> ]
- [
- [
- [ [ length ] bi@ assert= ]
- [ [ underlying>> ] bi@ ] 2bi
- ] dip 2map
- ] 3bi bit-array boa ; inline
+ [ drop [ length ] bi@ [ assert= ] keep ]
+ [ [ [ underlying>> ] bi@ ] dip 2map ] 3bi
+ bit-array boa ; inline
: (bit-set-op) ( set1 set2 -- table1 table2 )
[ set-like ] keep [ table>> ] bi@ ; inline
@@ -66,7 +60,7 @@ M: bit-set subset?
[ intersect ] keep = ;
M: bit-set members
- [ table>> length iota ] keep [ in? ] curry filter ;
+ table>> [ length iota ] keep '[ _ nth-unsafe ] filter ;
{ $description "Creates a new bit vector that can hold " { $snippet "n" } " bits before resizing." } ;
HELP: >bit-vector
-{ $values { "seq" "a sequence" } { "vector" bit-vector } }
+{ $values { "seq" sequence } { "vector" bit-vector } }
{ $description "Outputs a freshly-allocated bit vector with the same elements as a given sequence." } ;
HELP: ?V{
diff --git a/basis/boxes/boxes-docs.factor b/basis/boxes/boxes-docs.factor
index 7b28682910..5c0514b213 100644
--- a/basis/boxes/boxes-docs.factor
+++ b/basis/boxes/boxes-docs.factor
@@ -19,7 +19,7 @@ HELP: box>
{ $errors "Throws an error if the box is empty." } ;
HELP: ?box
-{ $values { "box" box } { "value/f" "the value of the box or " { $link f } } { "?" "a boolean" } }
+{ $values { "box" box } { "value/f" "the value of the box or " { $link f } } { "?" boolean } }
{ $description "If the box is full, removes the value from the box and pushes " { $link t } ". If the box is empty pushes " { $snippet "f f" } "." } ;
ARTICLE: "boxes" "Boxes"
diff --git a/basis/cache/cache.factor b/basis/cache/cache.factor
index 1babfde23f..f623b878a2 100755
--- a/basis/cache/cache.factor
+++ b/basis/cache/cache.factor
@@ -38,9 +38,9 @@ M: cache-assoc dispose* clear-assoc ;
PRIVATE>
: purge-cache ( cache -- )
- [ assoc>> ] [ max-age>> ] bi '[
- [
+ [ assoc>> ] [ max-age>> ] bi V{ } clone [
+ '[
nip dup age>> 1 + [ >>age ] keep
- _ < [ drop t ] [ dispose, f ] if
+ _ < [ drop t ] [ _ dispose-to f ] if
] assoc-filter! drop
- ] { } make [ last rethrow ] unless-empty ;
+ ] keep [ last rethrow ] unless-empty ;
diff --git a/basis/cairo/ffi/ffi.factor b/basis/cairo/ffi/ffi.factor
index 6f0001d5d8..d04564c8d5 100644
--- a/basis/cairo/ffi/ffi.factor
+++ b/basis/cairo/ffi/ffi.factor
@@ -8,10 +8,10 @@ IN: cairo.ffi
! Adapted from cairo.h, version 1.8.10
-<< {
- { [ os windows? ] [ "cairo" "libcairo-2.dll" cdecl add-library ] }
- { [ os macosx? ] [ "cairo" "libcairo.dylib" cdecl add-library ] }
- { [ os unix? ] [ ] }
+<< "cairo" {
+ { [ os windows? ] [ "libcairo-2.dll" cdecl add-library ] }
+ { [ os macosx? ] [ "libcairo.dylib" cdecl add-library ] }
+ { [ os unix? ] [ "libcairo.so" cdecl add-library ] }
} cond >>
LIBRARY: cairo
diff --git a/basis/calendar/calendar-docs.factor b/basis/calendar/calendar-docs.factor
index 6442c232a3..b2e42958ef 100644
--- a/basis/calendar/calendar-docs.factor
+++ b/basis/calendar/calendar-docs.factor
@@ -175,7 +175,7 @@ HELP: nanoseconds
{ years months days hours minutes seconds milliseconds microseconds nanoseconds } related-words
HELP: leap-year?
-{ $values { "obj" object } { "?" "a boolean" } }
+{ $values { "obj" object } { "?" boolean } }
{ $description "Returns " { $link t } " if the object represents a leap year." }
{ $examples
{ $example "USING: calendar prettyprint ;"
@@ -357,7 +357,7 @@ HELP:
{ $description "Returns a zero timestamp that consists of zeros for every slot. Used to see if timestamps are valid." } ;
HELP: valid-timestamp?
-{ $values { "timestamp" timestamp } { "?" "a boolean" } }
+{ $values { "timestamp" timestamp } { "?" boolean } }
{ $description "Tests if a timestamp is valid or not." } ;
HELP: unix-1970
diff --git a/basis/calendar/calendar.factor b/basis/calendar/calendar.factor
index 0fd023ee04..a0c111fb5e 100644
--- a/basis/calendar/calendar.factor
+++ b/basis/calendar/calendar.factor
@@ -33,6 +33,8 @@ TUPLE: timestamp
C: timestamp
+M: timestamp clone (clone) [ clone ] change-gmt-offset ;
+
: gmt-offset-duration ( -- duration )
0 0 0 gmt-offset ; inline
@@ -324,10 +326,10 @@ GENERIC: time- ( time1 time2 -- time3 )
] if ;
: >local-time ( timestamp -- timestamp' )
- gmt-offset-duration convert-timezone ;
+ clone gmt-offset-duration convert-timezone ;
: >gmt ( timestamp -- timestamp' )
- dup gmt-offset>> dup instant =
+ clone dup gmt-offset>> dup instant =
[ drop ] [
[ neg +second 0 ] change-second
[ neg +minute 0 ] change-minute
diff --git a/basis/calendar/format/format-tests.factor b/basis/calendar/format/format-tests.factor
index cb1ff0b60f..b1598df2fe 100644
--- a/basis/calendar/format/format-tests.factor
+++ b/basis/calendar/format/format-tests.factor
@@ -1,85 +1,120 @@
-USING: calendar.format calendar kernel math tools.test
-io.streams.string accessors io math.order sequences ;
-IN: calendar.format.tests
-
-[ 0 ] [
- "Z" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
-] unit-test
-
-[ 1 ] [
- "+01" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
-] unit-test
-
-[ -1 ] [
- "-01" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
-] unit-test
-
-[ -1-1/2 ] [
- "-01:30" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
-] unit-test
-
-[ 1+1/2 ] [
- "+01:30" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
-] unit-test
-
-[ ] [ now timestamp>rfc3339 drop ] unit-test
-[ ] [ now timestamp>rfc822 drop ] unit-test
-
-[ 8/1000 -4 ] [
- "2008-04-19T04:56:00.008-04:00" rfc3339>timestamp
- [ second>> ] [ gmt-offset>> hour>> ] bi
-] unit-test
-
-[ T{ duration f 0 0 0 0 0 0 } ] [
- "GMT" parse-rfc822-gmt-offset
-] unit-test
-
-[ T{ duration f 0 0 0 -5 0 0 } ] [
- "-0500" parse-rfc822-gmt-offset
-] unit-test
-
-[ T{ timestamp f 2008 4 22 14 36 12 T{ duration f 0 0 0 0 0 0 } } ] [
- "Tue, 22 Apr 2008 14:36:12 GMT" rfc822>timestamp
-] unit-test
-
-[ t ] [ now dup timestamp>rfc822 rfc822>timestamp time- 1 seconds before? ] unit-test
-
-[ t ] [ now dup timestamp>cookie-string cookie-string>timestamp time- 1 seconds before? ] unit-test
-
-[ "Sun, 4 May 2008 07:00:00" ] [
- "Sun May 04 07:00:00 2008 GMT" cookie-string>timestamp
- timestamp>string
-] unit-test
-
-[ "20080504070000" ] [
- "Sun May 04 07:00:00 2008 GMT" cookie-string>timestamp
- timestamp>mdtm
-] unit-test
-
-[
- T{ timestamp f
- 2008
- 5
- 26
- 0
- 37
- 42+2469/20000
- T{ duration f 0 0 0 -5 0 0 }
- }
-] [ "2008-05-26T00:37:42.12345-05:00" rfc3339>timestamp ] unit-test
-
-[
- T{ timestamp
- { year 2008 }
- { month 10 }
- { day 2 }
- { hour 23 }
- { minute 59 }
- { second 59 }
- { gmt-offset T{ duration f 0 0 0 0 0 0 } }
- }
-] [ "Thursday, 02-Oct-2008 23:59:59 GMT" cookie-string>timestamp ] unit-test
-
-
-[ ]
-[ { 2008 2009 } [ year. ] each ] unit-test
+USING: calendar.format calendar kernel math tools.test
+io.streams.string accessors io math.order sequences ;
+IN: calendar.format.tests
+
+[ 0 ] [
+ "Z" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
+] unit-test
+
+[ 1 ] [
+ "+01" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
+] unit-test
+
+[ -1 ] [
+ "-01" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
+] unit-test
+
+[ -1-1/2 ] [
+ "-01:30" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
+] unit-test
+
+[ 1+1/2 ] [
+ "+01:30" [ read1 read-rfc3339-gmt-offset ] with-string-reader duration>hours
+] unit-test
+
+[ ] [ now timestamp>rfc3339 drop ] unit-test
+[ ] [ now timestamp>rfc822 drop ] unit-test
+
+[ 8/1000 -4 ] [
+ "2008-04-19T04:56:00.008-04:00" rfc3339>timestamp
+ [ second>> ] [ gmt-offset>> hour>> ] bi
+] unit-test
+
+[ T{ duration f 0 0 0 0 0 0 } ] [
+ "GMT" parse-rfc822-gmt-offset
+] unit-test
+
+[ T{ duration f 0 0 0 -5 0 0 } ] [
+ "-0500" parse-rfc822-gmt-offset
+] unit-test
+
+[ T{ timestamp f 2008 4 22 14 36 12 T{ duration f 0 0 0 0 0 0 } } ] [
+ "Tue, 22 Apr 2008 14:36:12 GMT" rfc822>timestamp
+] unit-test
+
+[ t ] [ now dup timestamp>rfc822 rfc822>timestamp time- 1 seconds before? ] unit-test
+
+[ t ] [ now dup timestamp>cookie-string cookie-string>timestamp time- 1 seconds before? ] unit-test
+
+[ "Sun, 4 May 2008 07:00:00" ] [
+ "Sun May 04 07:00:00 2008 GMT" cookie-string>timestamp
+ timestamp>string
+] unit-test
+
+[ "20080504070000" ] [
+ "Sun May 04 07:00:00 2008 GMT" cookie-string>timestamp
+ timestamp>mdtm
+] unit-test
+
+[
+ T{ timestamp f
+ 2008
+ 5
+ 26
+ 0
+ 37
+ 42+2469/20000
+ T{ duration f 0 0 0 -5 0 0 }
+ }
+] [ "2008-05-26T00:37:42.12345-05:00" rfc3339>timestamp ] unit-test
+
+[
+ T{ timestamp
+ { year 2008 }
+ { month 10 }
+ { day 2 }
+ { hour 23 }
+ { minute 59 }
+ { second 59 }
+ { gmt-offset T{ duration f 0 0 0 0 0 0 } }
+ }
+] [ "Thursday, 02-Oct-2008 23:59:59 GMT" cookie-string>timestamp ] unit-test
+
+
+[ ]
+[ { 2008 2009 } [ year. ] each ] unit-test
+
+[
+ T{ timestamp
+ { year 2013 }
+ { month 4 }
+ { day 23 }
+ { hour 13 }
+ { minute 50 }
+ { second 24 }
+ }
+] [ "2013-04-23T13:50:24" rfc3339>timestamp ] unit-test
+
+{ "2001-12-14T21:59:43.100000-05:00" } [ "2001-12-14T21:59:43.1-05:00" rfc3339>timestamp timestamp>rfc3339 ] unit-test
+
+[
+ T{ timestamp
+ { year 2001 }
+ { month 12 }
+ { day 15 }
+ { hour 02 }
+ { minute 59 }
+ { second 43+1/10 }
+ }
+] [ "2001-12-15 02:59:43.1Z" rfc3339>timestamp ] unit-test
+
+[
+ T{ timestamp
+ { year 2001 }
+ { month 12 }
+ { day 15 }
+ { hour 02 }
+ { minute 59 }
+ { second 43+1/10 }
+ }
+] [ "2001-12-15 02:59:43.1Z" rfc3339>timestamp ] unit-test
diff --git a/basis/calendar/format/format.factor b/basis/calendar/format/format.factor
index e2af02a3cc..aa02460607 100644
--- a/basis/calendar/format/format.factor
+++ b/basis/calendar/format/format.factor
@@ -1,328 +1,338 @@
-! Copyright (C) 2008, 2010 Slava Pestov, Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays calendar calendar.format.macros
-combinators io io.streams.string kernel math math.functions
-math.order math.parser present sequences typed ;
-IN: calendar.format
-
-: pad-00 ( n -- str ) number>string 2 CHAR: 0 pad-head ;
-
-: pad-0000 ( n -- str ) number>string 4 CHAR: 0 pad-head ;
-
-: pad-00000 ( n -- str ) number>string 5 CHAR: 0 pad-head ;
-
-: write-00 ( n -- ) pad-00 write ;
-
-: write-0000 ( n -- ) pad-0000 write ;
-
-: write-00000 ( n -- ) pad-00000 write ;
-
-: hh ( time -- ) hour>> write-00 ;
-
-: mm ( time -- ) minute>> write-00 ;
-
-: ss ( time -- ) second>> >integer write-00 ;
-
-: D ( time -- ) day>> number>string write ;
-
-: DD ( time -- ) day>> write-00 ;
-
-: DAY ( time -- ) day-of-week day-abbreviation3 write ;
-
-: MM ( time -- ) month>> write-00 ;
-
-: MONTH ( time -- ) month>> month-abbreviation write ;
-
-: YYYY ( time -- ) year>> write-0000 ;
-
-: YYYYY ( time -- ) year>> write-00000 ;
-
-: expect ( str -- )
- read1 swap member? [ "Parse error" throw ] unless ;
-
-: read-00 ( -- n ) 2 read string>number ;
-
-: read-000 ( -- n ) 3 read string>number ;
-
-: read-0000 ( -- n ) 4 read string>number ;
-
-: hhmm>timestamp ( hhmm -- timestamp )
- [
- 0 0 0 read-00 read-00 0 instant
- ] with-string-reader ;
-
-GENERIC: day. ( obj -- )
-
-M: integer day. ( n -- )
- number>string dup length 2 < [ bl ] when write ;
-
-M: timestamp day. ( timestamp -- )
- day>> day. ;
-
-GENERIC: month. ( obj -- )
-
-M: array month. ( pair -- )
- first2
- [ month-name write bl number>string print ]
- [ 1 zeller-congruence ]
- [ (days-in-month) day-abbreviations2 " " join print ] 2tri
- over " " "" concat-as write
- [
- [ 1 + day. ] keep
- 1 + + 7 mod zero? [ nl ] [ bl ] if
- ] with each-integer nl ;
-
-M: timestamp month. ( timestamp -- )
- [ year>> ] [ month>> ] bi 2array month. ;
-
-GENERIC: year. ( obj -- )
-
-M: integer year. ( n -- )
- 12 [ 1 + 2array month. nl ] with each-integer ;
-
-M: timestamp year. ( timestamp -- )
- year>> year. ;
-
-: timestamp>mdtm ( timestamp -- str )
- [ { YYYY MM DD hh mm ss } formatted ] with-string-writer ;
-
-: (timestamp>string) ( timestamp -- )
- { DAY ", " D " " MONTH " " YYYY " " hh ":" mm ":" ss } formatted ;
-
-: timestamp>string ( timestamp -- str )
- [ (timestamp>string) ] with-string-writer ;
-
-: (write-gmt-offset) ( duration -- )
- [ hh ] [ mm ] bi ;
-
-: write-gmt-offset ( gmt-offset -- )
- dup instant <=> {
- { +eq+ [ drop "GMT" write ] }
- { +lt+ [ "-" write before (write-gmt-offset) ] }
- { +gt+ [ "+" write (write-gmt-offset) ] }
- } case ;
-
-: timestamp>rfc822 ( timestamp -- str )
- #! RFC822 timestamp format
- #! Example: Tue, 15 Nov 1994 08:12:31 +0200
- [
- [ (timestamp>string) bl ]
- [ gmt-offset>> write-gmt-offset ]
- bi
- ] with-string-writer ;
-
-: timestamp>http-string ( timestamp -- str )
- #! http timestamp format
- #! Example: Tue, 15 Nov 1994 08:12:31 GMT
- >gmt timestamp>rfc822 ;
-
-: (timestamp>cookie-string) ( timestamp -- )
- >gmt
- { DAY ", " DD "-" MONTH "-" YYYY " " hh ":" mm ":" ss " GMT" } formatted ;
-
-: timestamp>cookie-string ( timestamp -- str )
- [ (timestamp>cookie-string) ] with-string-writer ;
-
-: (write-rfc3339-gmt-offset) ( duration -- )
- [ hh ":" write ] [ mm ] bi ;
-
-: write-rfc3339-gmt-offset ( duration -- )
- dup instant <=> {
- { +eq+ [ drop "Z" write ] }
- { +lt+ [ "-" write before (write-rfc3339-gmt-offset) ] }
- { +gt+ [ "+" write (write-rfc3339-gmt-offset) ] }
- } case ;
-
-: (timestamp>rfc3339) ( timestamp -- )
- {
- YYYY "-" MM "-" DD "T" hh ":" mm ":" ss
- [ gmt-offset>> write-rfc3339-gmt-offset ]
- } formatted ;
-
-: timestamp>rfc3339 ( timestamp -- str )
- [ (timestamp>rfc3339) ] with-string-writer ;
-
-: signed-gmt-offset ( dt ch -- dt' )
- { { CHAR: + [ 1 ] } { CHAR: - [ -1 ] } } case time* ;
-
-: read-rfc3339-gmt-offset ( ch -- dt )
- dup CHAR: Z = [ drop instant ] [
- [
- read-00 hours
- read1 { { CHAR: : [ read-00 ] } { f [ 0 ] } } case minutes
- time+
- ] dip signed-gmt-offset
- ] if ;
-
-: read-ymd ( -- y m d )
- read-0000 "-" expect read-00 "-" expect read-00 ;
-
-: read-hms ( -- h m s )
- read-00 ":" expect read-00 ":" expect read-00 ;
-
-: read-rfc3339-seconds ( s -- s' ch )
- "+-Z" read-until [
- [ string>number ] [ length 10^ ] bi / +
- ] dip ;
-
-: (rfc3339>timestamp) ( -- timestamp )
- read-ymd
- "Tt" expect
- read-hms
- read1 { { CHAR: . [ read-rfc3339-seconds ] } [ ] } case
- read-rfc3339-gmt-offset
- ;
-
-: rfc3339>timestamp ( str -- timestamp )
- [ (rfc3339>timestamp) ] with-string-reader ;
-
-ERROR: invalid-timestamp-format ;
-
-: check-timestamp ( obj/f -- obj )
- [ invalid-timestamp-format ] unless* ;
-
-: read-token ( seps -- token )
- [ read-until ] keep member? check-timestamp drop ;
-
-: read-sp ( -- token ) " " read-token ;
-
-: checked-number ( str -- n )
- string>number check-timestamp ;
-
-: parse-rfc822-gmt-offset ( string -- dt )
- dup "GMT" = [ drop instant ] [
- unclip [
- 2 cut [ string>number ] bi@ [ hours ] [ minutes ] bi* time+
- ] dip signed-gmt-offset
- ] if ;
-
-: (rfc822>timestamp) ( -- timestamp )
- timestamp new
- "," read-token day-abbreviations3 member? check-timestamp drop
- read1 CHAR: \s assert=
- read-sp checked-number >>day
- read-sp month-abbreviations index 1 + check-timestamp >>month
- read-sp checked-number >>year
- ":" read-token checked-number >>hour
- ":" read-token checked-number >>minute
- read-sp checked-number >>second
- readln parse-rfc822-gmt-offset >>gmt-offset ;
-
-: rfc822>timestamp ( str -- timestamp )
- [ (rfc822>timestamp) ] with-string-reader ;
-
-: check-day-name ( str -- )
- [ day-abbreviations3 member? ] [ day-names member? ] bi or
- check-timestamp drop ;
-
-: (cookie-string>timestamp-1) ( -- timestamp )
- timestamp new
- "," read-token check-day-name
- read1 CHAR: \s assert=
- "-" read-token checked-number >>day
- "-" read-token month-abbreviations index 1 + check-timestamp >>month
- read-sp checked-number >>year
- ":" read-token checked-number >>hour
- ":" read-token checked-number >>minute
- read-sp checked-number >>second
- readln parse-rfc822-gmt-offset >>gmt-offset ;
-
-: cookie-string>timestamp-1 ( str -- timestamp )
- [ (cookie-string>timestamp-1) ] with-string-reader ;
-
-: (cookie-string>timestamp-2) ( -- timestamp )
- timestamp new
- read-sp check-day-name
- read-sp month-abbreviations index 1 + check-timestamp >>month
- read-sp checked-number >>day
- ":" read-token checked-number >>hour
- ":" read-token checked-number >>minute
- read-sp checked-number >>second
- read-sp checked-number >>year
- readln parse-rfc822-gmt-offset >>gmt-offset ;
-
-: cookie-string>timestamp-2 ( str -- timestamp )
- [ (cookie-string>timestamp-2) ] with-string-reader ;
-
-: cookie-string>timestamp ( str -- timestamp )
- {
- [ cookie-string>timestamp-1 ]
- [ cookie-string>timestamp-2 ]
- [ rfc822>timestamp ]
- } attempt-all-quots ;
-
-: (ymdhms>timestamp) ( -- timestamp )
- read-ymd " " expect read-hms instant ;
-
-: ymdhms>timestamp ( str -- timestamp )
- [ (ymdhms>timestamp) ] with-string-reader ;
-
-: (hms>timestamp) ( -- timestamp )
- 0 0 0 read-hms instant ;
-
-: hms>timestamp ( str -- timestamp )
- [ (hms>timestamp) ] with-string-reader ;
-
-: (ymd>timestamp) ( -- timestamp )
- read-ymd ;
-
-: ymd>timestamp ( str -- timestamp )
- [ (ymd>timestamp) ] with-string-reader ;
-
-: (timestamp>ymd) ( timestamp -- )
- { YYYY "-" MM "-" DD } formatted ;
-
-TYPED: timestamp>ymd ( timestamp: timestamp -- str )
- [ (timestamp>ymd) ] with-string-writer ;
-
-: (timestamp>hms) ( timestamp -- )
- { hh ":" mm ":" ss } formatted ;
-
-TYPED: timestamp>hms ( timestamp: timestamp -- str )
- [ (timestamp>hms) ] with-string-writer ;
-
-: (timestamp>hm) ( timestamp -- )
- { hh ":" mm } formatted ;
-
-TYPED: timestamp>hm ( timestamp: timestamp -- str )
- [ (timestamp>hm) ] with-string-writer ;
-
-TYPED: timestamp>ymdhms ( timestamp: timestamp -- str )
- [
- >gmt
- { (timestamp>ymd) " " (timestamp>hms) } formatted
- ] with-string-writer ;
-
-: file-time-string ( timestamp -- string )
- [
- {
- MONTH " " DD " "
- [
- dup now [ year>> ] same?
- [ [ hh ":" write ] [ mm ] bi ] [ YYYYY ] if
- ]
- } formatted
- ] with-string-writer ;
-
-M: timestamp present timestamp>string ;
-
-TYPED: duration>hm ( duration: duration -- string )
- [ duration>hours >integer 24 mod pad-00 ]
- [ duration>minutes >integer 60 mod pad-00 ] bi ":" glue ;
-
-TYPED: duration>human-readable ( duration: duration -- string )
- [
- [
- duration>years >integer
- [
- [ number>string write ]
- [ 1 > " years, " " year, " ? write ] bi
- ] unless-zero
- ] [
- duration>days >integer 365 mod
- [
- [ number>string write ]
- [ 1 > " days, " " day, " ? write ] bi
- ] unless-zero
- ] [ duration>hm write ] tri
- ] with-string-writer ;
+! Copyright (C) 2008, 2010 Slava Pestov, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays calendar calendar.format.macros
+combinators io io.streams.string kernel math math.functions
+math.order math.parser math.parser.private present sequences
+typed ;
+IN: calendar.format
+
+: pad-00 ( n -- str ) number>string 2 CHAR: 0 pad-head ;
+
+: pad-0000 ( n -- str ) number>string 4 CHAR: 0 pad-head ;
+
+: pad-00000 ( n -- str ) number>string 5 CHAR: 0 pad-head ;
+
+: write-00 ( n -- ) pad-00 write ;
+
+: write-0000 ( n -- ) pad-0000 write ;
+
+: write-00000 ( n -- ) pad-00000 write ;
+
+: hh ( time -- ) hour>> write-00 ;
+
+: mm ( time -- ) minute>> write-00 ;
+
+: ss ( time -- ) second>> >integer write-00 ;
+
+: D ( time -- ) day>> number>string write ;
+
+: DD ( time -- ) day>> write-00 ;
+
+: DAY ( time -- ) day-of-week day-abbreviation3 write ;
+
+: MM ( time -- ) month>> write-00 ;
+
+: MONTH ( time -- ) month>> month-abbreviation write ;
+
+: YYYY ( time -- ) year>> write-0000 ;
+
+: YYYYY ( time -- ) year>> write-00000 ;
+
+: expect ( str -- )
+ read1 swap member? [ "Parse error" throw ] unless ;
+
+: read-00 ( -- n ) 2 read string>number ;
+
+: read-000 ( -- n ) 3 read string>number ;
+
+: read-0000 ( -- n ) 4 read string>number ;
+
+: hhmm>timestamp ( hhmm -- timestamp )
+ [
+ 0 0 0 read-00 read-00 0 instant
+ ] with-string-reader ;
+
+GENERIC: day. ( obj -- )
+
+M: integer day. ( n -- )
+ number>string dup length 2 < [ bl ] when write ;
+
+M: timestamp day. ( timestamp -- )
+ day>> day. ;
+
+GENERIC: month. ( obj -- )
+
+M: array month. ( pair -- )
+ first2
+ [ month-name write bl number>string print ]
+ [ 1 zeller-congruence ]
+ [ (days-in-month) day-abbreviations2 " " join print ] 2tri
+ over " " "" concat-as write
+ [
+ [ 1 + day. ] keep
+ 1 + + 7 mod zero? [ nl ] [ bl ] if
+ ] with each-integer nl ;
+
+M: timestamp month. ( timestamp -- )
+ [ year>> ] [ month>> ] bi 2array month. ;
+
+GENERIC: year. ( obj -- )
+
+M: integer year. ( n -- )
+ 12 [ 1 + 2array month. nl ] with each-integer ;
+
+M: timestamp year. ( timestamp -- )
+ year>> year. ;
+
+: timestamp>mdtm ( timestamp -- str )
+ [ { YYYY MM DD hh mm ss } formatted ] with-string-writer ;
+
+: (timestamp>string) ( timestamp -- )
+ { DAY ", " D " " MONTH " " YYYY " " hh ":" mm ":" ss } formatted ;
+
+: timestamp>string ( timestamp -- str )
+ [ (timestamp>string) ] with-string-writer ;
+
+: (write-gmt-offset) ( duration -- )
+ [ hh ] [ mm ] bi ;
+
+: write-gmt-offset ( gmt-offset -- )
+ dup instant <=> {
+ { +eq+ [ drop "GMT" write ] }
+ { +lt+ [ "-" write before (write-gmt-offset) ] }
+ { +gt+ [ "+" write (write-gmt-offset) ] }
+ } case ;
+
+: timestamp>rfc822 ( timestamp -- str )
+ #! RFC822 timestamp format
+ #! Example: Tue, 15 Nov 1994 08:12:31 +0200
+ [
+ [ (timestamp>string) bl ]
+ [ gmt-offset>> write-gmt-offset ]
+ bi
+ ] with-string-writer ;
+
+: timestamp>http-string ( timestamp -- str )
+ #! http timestamp format
+ #! Example: Tue, 15 Nov 1994 08:12:31 GMT
+ >gmt timestamp>rfc822 ;
+
+: (timestamp>cookie-string) ( timestamp -- )
+ >gmt
+ { DAY ", " DD "-" MONTH "-" YYYY " " hh ":" mm ":" ss " GMT" } formatted ;
+
+: timestamp>cookie-string ( timestamp -- str )
+ [ (timestamp>cookie-string) ] with-string-writer ;
+
+: (write-rfc3339-gmt-offset) ( duration -- )
+ [ hh ":" write ] [ mm ] bi ;
+
+: write-rfc3339-gmt-offset ( duration -- )
+ dup instant <=> {
+ { +eq+ [ drop "Z" write ] }
+ { +lt+ [ "-" write before (write-rfc3339-gmt-offset) ] }
+ { +gt+ [ "+" write (write-rfc3339-gmt-offset) ] }
+ } case ;
+
+! Should be enough for anyone, allows to not do a fancy
+! algorithm to detect infinite decimals (e.g 1/3)
+: ss.SSSSSS ( timestamp -- )
+ second>> >float "%.6f" format-float 9 CHAR: 0 pad-head write ;
+
+: (timestamp>rfc3339) ( timestamp -- )
+ {
+ YYYY "-" MM "-" DD "T" hh ":" mm ":" ss.SSSSSS
+ [ gmt-offset>> write-rfc3339-gmt-offset ]
+ } formatted ;
+
+: timestamp>rfc3339 ( timestamp -- str )
+ [ (timestamp>rfc3339) ] with-string-writer ;
+
+: signed-gmt-offset ( dt ch -- dt' )
+ { { CHAR: + [ 1 ] } { CHAR: - [ -1 ] } } case time* ;
+
+: read-rfc3339-gmt-offset ( ch -- dt )
+ {
+ { f [ instant ] }
+ { CHAR: Z [ instant ] }
+ [
+ [
+ read-00 hours
+ read1 { { CHAR: : [ read-00 ] } { f [ 0 ] } } case minutes
+ time+
+ ] dip signed-gmt-offset
+ ]
+ } case ;
+
+: read-ymd ( -- y m d )
+ read-0000 "-" expect read-00 "-" expect read-00 ;
+
+: read-hms ( -- h m s )
+ read-00 ":" expect read-00 ":" expect read-00 ;
+
+: read-rfc3339-seconds ( s -- s' ch )
+ "+-Z" read-until [
+ [ string>number ] [ length 10^ ] bi / +
+ ] dip ;
+
+: (rfc3339>timestamp) ( -- timestamp )
+ read-ymd
+ "Tt \t" expect
+ read-hms
+ read1 { { CHAR: . [ read-rfc3339-seconds ] } [ ] } case
+ read-rfc3339-gmt-offset
+ ;
+
+: rfc3339>timestamp ( str -- timestamp )
+ [ (rfc3339>timestamp) ] with-string-reader ;
+
+ERROR: invalid-timestamp-format ;
+
+: check-timestamp ( obj/f -- obj )
+ [ invalid-timestamp-format ] unless* ;
+
+: read-token ( seps -- token )
+ [ read-until ] keep member? check-timestamp drop ;
+
+: read-sp ( -- token ) " " read-token ;
+
+: checked-number ( str -- n )
+ string>number check-timestamp ;
+
+: parse-rfc822-gmt-offset ( string -- dt )
+ dup "GMT" = [ drop instant ] [
+ unclip [
+ 2 cut [ string>number ] bi@ [ hours ] [ minutes ] bi* time+
+ ] dip signed-gmt-offset
+ ] if ;
+
+: (rfc822>timestamp) ( -- timestamp )
+ timestamp new
+ "," read-token day-abbreviations3 member? check-timestamp drop
+ read1 CHAR: \s assert=
+ read-sp checked-number >>day
+ read-sp month-abbreviations index 1 + check-timestamp >>month
+ read-sp checked-number >>year
+ ":" read-token checked-number >>hour
+ ":" read-token checked-number >>minute
+ read-sp checked-number >>second
+ readln parse-rfc822-gmt-offset >>gmt-offset ;
+
+: rfc822>timestamp ( str -- timestamp )
+ [ (rfc822>timestamp) ] with-string-reader ;
+
+: check-day-name ( str -- )
+ [ day-abbreviations3 member? ] [ day-names member? ] bi or
+ check-timestamp drop ;
+
+: (cookie-string>timestamp-1) ( -- timestamp )
+ timestamp new
+ "," read-token check-day-name
+ read1 CHAR: \s assert=
+ "-" read-token checked-number >>day
+ "-" read-token month-abbreviations index 1 + check-timestamp >>month
+ read-sp checked-number >>year
+ ":" read-token checked-number >>hour
+ ":" read-token checked-number >>minute
+ read-sp checked-number >>second
+ readln parse-rfc822-gmt-offset >>gmt-offset ;
+
+: cookie-string>timestamp-1 ( str -- timestamp )
+ [ (cookie-string>timestamp-1) ] with-string-reader ;
+
+: (cookie-string>timestamp-2) ( -- timestamp )
+ timestamp new
+ read-sp check-day-name
+ read-sp month-abbreviations index 1 + check-timestamp >>month
+ read-sp checked-number >>day
+ ":" read-token checked-number >>hour
+ ":" read-token checked-number >>minute
+ read-sp checked-number >>second
+ read-sp checked-number >>year
+ readln parse-rfc822-gmt-offset >>gmt-offset ;
+
+: cookie-string>timestamp-2 ( str -- timestamp )
+ [ (cookie-string>timestamp-2) ] with-string-reader ;
+
+: cookie-string>timestamp ( str -- timestamp )
+ {
+ [ cookie-string>timestamp-1 ]
+ [ cookie-string>timestamp-2 ]
+ [ rfc822>timestamp ]
+ } attempt-all-quots ;
+
+: (ymdhms>timestamp) ( -- timestamp )
+ read-ymd " " expect read-hms instant ;
+
+: ymdhms>timestamp ( str -- timestamp )
+ [ (ymdhms>timestamp) ] with-string-reader ;
+
+: (hms>timestamp) ( -- timestamp )
+ 0 0 0 read-hms instant ;
+
+: hms>timestamp ( str -- timestamp )
+ [ (hms>timestamp) ] with-string-reader ;
+
+: (ymd>timestamp) ( -- timestamp )
+ read-ymd ;
+
+: ymd>timestamp ( str -- timestamp )
+ [ (ymd>timestamp) ] with-string-reader ;
+
+: (timestamp>ymd) ( timestamp -- )
+ { YYYY "-" MM "-" DD } formatted ;
+
+TYPED: timestamp>ymd ( timestamp: timestamp -- str )
+ [ (timestamp>ymd) ] with-string-writer ;
+
+: (timestamp>hms) ( timestamp -- )
+ { hh ":" mm ":" ss } formatted ;
+
+TYPED: timestamp>hms ( timestamp: timestamp -- str )
+ [ (timestamp>hms) ] with-string-writer ;
+
+: (timestamp>hm) ( timestamp -- )
+ { hh ":" mm } formatted ;
+
+TYPED: timestamp>hm ( timestamp: timestamp -- str )
+ [ (timestamp>hm) ] with-string-writer ;
+
+TYPED: timestamp>ymdhms ( timestamp: timestamp -- str )
+ [
+ >gmt
+ { (timestamp>ymd) " " (timestamp>hms) } formatted
+ ] with-string-writer ;
+
+: file-time-string ( timestamp -- string )
+ [
+ {
+ MONTH " " DD " "
+ [
+ dup now [ year>> ] same?
+ [ [ hh ":" write ] [ mm ] bi ] [ YYYYY ] if
+ ]
+ } formatted
+ ] with-string-writer ;
+
+M: timestamp present timestamp>string ;
+
+TYPED: duration>hm ( duration: duration -- string )
+ [ duration>hours >integer 24 mod pad-00 ]
+ [ duration>minutes >integer 60 mod pad-00 ] bi ":" glue ;
+
+TYPED: duration>human-readable ( duration: duration -- string )
+ [
+ [
+ duration>years >integer
+ [
+ [ number>string write ]
+ [ 1 > " years, " " year, " ? write ] bi
+ ] unless-zero
+ ] [
+ duration>days >integer 365 mod
+ [
+ [ number>string write ]
+ [ 1 > " days, " " day, " ? write ] bi
+ ] unless-zero
+ ] [ duration>hm write ] tri
+ ] with-string-writer ;
diff --git a/basis/calendar/threads/threads.factor b/basis/calendar/threads/threads.factor
index efdbb6923d..cc2c495c78 100644
--- a/basis/calendar/threads/threads.factor
+++ b/basis/calendar/threads/threads.factor
@@ -1,7 +1,8 @@
! Copyright (C) 2011 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: calendar math system threads ;
+USING: calendar threads ;
IN: calendar.threads
-M: duration sleep
- duration>nanoseconds >integer nano-count + sleep-until ;
+M: duration sleep duration>nanoseconds sleep ;
+
+M: timestamp sleep-until now time- sleep ;
diff --git a/basis/calendar/unix/unix.factor b/basis/calendar/unix/unix.factor
index f106f8810e..ac729a5cef 100644
--- a/basis/calendar/unix/unix.factor
+++ b/basis/calendar/unix/unix.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.data calendar calendar.private
-classes.struct kernel math system unix unix.time unix.types ;
+classes.struct kernel math system libc unix unix.time unix.types ;
IN: calendar.unix
: timeval>seconds ( timeval -- seconds )
@@ -35,7 +35,7 @@ M: unix gmt-offset ( -- hours minutes seconds )
get-time gmtoff>> 3600 /mod 60 /mod ;
: current-timeval ( -- timeval )
- timeval f [ gettimeofday io-error ] 2keep drop ; inline
+ timeval [ f gettimeofday io-error ] keep ; inline
: system-micros ( -- n )
current-timeval timeval>micros ;
diff --git a/basis/channels/channels-docs.factor b/basis/channels/channels-docs.factor
index 09dac901fe..931d424195 100644
--- a/basis/channels/channels-docs.factor
+++ b/basis/channels/channels-docs.factor
@@ -1,10 +1,10 @@
! Copyright (C) 2007 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
-USING: help.syntax help.markup ;
+USING: help.syntax help.markup kernel ;
IN: channels
HELP:
-{ $values { "channel" "a channel object" }
+{ $values { "channel" channel }
}
{ $description "Create a channel that can be used for communicating between "
"concurrent processes and threads. " { $link to } " and " { $link from }
@@ -15,19 +15,19 @@ HELP:
{ $see-also from to } ;
HELP: to
-{ $values { "value" "an object" }
- { "channel" "a channel object" }
+{ $values { "value" object }
+ { "channel" channel }
}
{ $description "Sends an object to a channel. The send operation is synchronous."
" It will block the calling thread until there is a receiver waiting "
"for data on the channel. It will return when the receiver has received "
-"the data successfully."
+"the data successfully."
}
{ $see-also from } ;
HELP: from
-{ $values { "channel" "a channel object" }
- { "value" "an object" }
+{ $values { "channel" channel }
+ { "value" object }
}
{ $description "Receives an object from a channel. The operation is synchronous."
" It will block the calling thread until there is data in the channel."
diff --git a/basis/channels/remote/remote-docs.factor b/basis/channels/remote/remote-docs.factor
index 2215d959a3..bbecb361ea 100644
--- a/basis/channels/remote/remote-docs.factor
+++ b/basis/channels/remote/remote-docs.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2007 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
USING: channels concurrency.distributed help.markup help.syntax
-io.servers ;
+io.servers strings ;
IN: channels.remote
HELP:
@@ -20,7 +20,7 @@ HELP:
{ $see-also publish unpublish } ;
HELP: unpublish
-{ $values { "id" "a string" }
+{ $values { "id" string }
}
{ $description "Stop a previously published channel from being "
"accessible by remote nodes."
@@ -32,7 +32,7 @@ HELP: unpublish
HELP: publish
{ $values { "channel" "a channel object" }
- { "id" "a string" }
+ { "id" string }
}
{ $description "Make a channel accessible via remote Factor nodes. "
"An id is returned that can be used by another node to use "
diff --git a/basis/checksums/fletcher/authors.txt b/basis/checksums/fletcher/authors.txt
new file mode 100644
index 0000000000..e091bb8164
--- /dev/null
+++ b/basis/checksums/fletcher/authors.txt
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/checksums/fletcher/fletcher-docs.factor b/basis/checksums/fletcher/fletcher-docs.factor
new file mode 100644
index 0000000000..82d111aebb
--- /dev/null
+++ b/basis/checksums/fletcher/fletcher-docs.factor
@@ -0,0 +1,17 @@
+USING: help.markup help.syntax ;
+IN: checksums.fletcher
+
+HELP: fletcher-16
+{ $class-description "Fletcher's 16-bit checksum algorithm." } ;
+
+HELP: fletcher-32
+{ $class-description "Fletcher's 32-bit checksum algorithm." } ;
+
+HELP: fletcher-64
+{ $class-description "Fletcher's 64-bit checksum algorithm." } ;
+
+ARTICLE: "checksums.fletcher" "Fletcher's checksum"
+"The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John G. Fletcher at Lawrence Livermore Labs in the late 1970s."
+{ $subsections fletcher-16 fletcher-32 fletcher-64 } ;
+
+ABOUT: "checksums.fletcher"
diff --git a/basis/checksums/fletcher/fletcher-tests.factor b/basis/checksums/fletcher/fletcher-tests.factor
new file mode 100644
index 0000000000..8f3a1f0421
--- /dev/null
+++ b/basis/checksums/fletcher/fletcher-tests.factor
@@ -0,0 +1,10 @@
+USING: checksums kernel sequences tools.test ;
+IN: checksums.fletcher
+
+{
+ { 51440 3948201259 14034561336514601929 }
+} [
+ "abcde" { fletcher-16 fletcher-32 fletcher-64 }
+ [ checksum-bytes ] with map
+] unit-test
+
diff --git a/basis/checksums/fletcher/fletcher.factor b/basis/checksums/fletcher/fletcher.factor
new file mode 100644
index 0000000000..257912d8a8
--- /dev/null
+++ b/basis/checksums/fletcher/fletcher.factor
@@ -0,0 +1,27 @@
+! Copyright (C) 2013 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: checksums grouping io.binary kernel locals math sequences
+;
+
+IN: checksums.fletcher
+
+SINGLETON: fletcher-16
+SINGLETON: fletcher-32
+SINGLETON: fletcher-64
+
+INSTANCE: fletcher-16 checksum
+INSTANCE: fletcher-32 checksum
+INSTANCE: fletcher-64 checksum
+
+:: fletcher ( seq k -- n )
+ k 16 / :> chars
+ k 2 / 2^ :> base
+ base 1 - :> modulo
+ 0 0 seq chars [
+ be> + modulo mod [ + modulo mod ] keep
+ ] each [ base * ] [ + ] bi* ; inline
+
+M: fletcher-16 checksum-bytes drop 16 fletcher ;
+M: fletcher-32 checksum-bytes drop 32 fletcher ;
+M: fletcher-64 checksum-bytes drop 64 fletcher ;
diff --git a/basis/checksums/fletcher/summary.txt b/basis/checksums/fletcher/summary.txt
new file mode 100644
index 0000000000..489839537f
--- /dev/null
+++ b/basis/checksums/fletcher/summary.txt
@@ -0,0 +1 @@
+Fletcher's checksum algorithm
diff --git a/basis/checksums/internet/internet.factor b/basis/checksums/internet/internet.factor
index 5d3b24b3e0..b8175a61d4 100644
--- a/basis/checksums/internet/internet.factor
+++ b/basis/checksums/internet/internet.factor
@@ -10,7 +10,7 @@ SINGLETON: internet ! RFC 1071
INSTANCE: internet checksum
M: internet checksum-bytes
- drop 0 swap 2 [ le> + ] each
+ drop 2 [ le> ] map-sum
[ -16 shift ] [ 0xffff bitand ] bi +
[ -16 shift ] keep + bitnot 2 >le ;
diff --git a/basis/checksums/md5/md5.factor b/basis/checksums/md5/md5.factor
index 3f813dd387..13edf0ed50 100644
--- a/basis/checksums/md5/md5.factor
+++ b/basis/checksums/md5/md5.factor
@@ -1,11 +1,9 @@
! Copyright (C) 2006, 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types alien.data kernel io io.binary io.files
-io.streams.byte-array math math.functions math.parser namespaces
-splitting grouping strings sequences byte-arrays locals
-sequences.private macros fry io.encodings.binary math.bitwise
-checksums accessors checksums.common checksums.stream
-combinators combinators.smart specialized-arrays literals hints ;
+USING: accessors alien.c-types alien.data byte-arrays checksums
+checksums.common checksums.stream combinators fry grouping hints
+kernel kernel.private literals locals macros math math.bitwise
+math.functions sequences sequences.private specialized-arrays ;
FROM: sequences.private => change-nth-unsafe ;
SPECIALIZED-ARRAY: uint
IN: checksums.md5
@@ -14,7 +12,9 @@ SINGLETON: md5
INSTANCE: md5 stream-checksum
-TUPLE: md5-state < checksum-state state old-state ;
+TUPLE: md5-state < checksum-state
+{ state uint-array }
+{ old-state uint-array } ;
: ( -- md5 )
md5-state new-checksum-state
@@ -26,16 +26,13 @@ M: md5 initialize-checksum-state drop ;
> ] [ old-state>> v-w+ dup clone ] [ ] tri
- [ old-state<< ] [ state<< ] bi ;
+ [ state>> ] [ old-state>> [ w+ ] 2map dup clone ] [ ] tri
+ [ old-state<< ] [ state<< ] bi ; inline
-CONSTANT: T
- $[
- 80 iota [ sin abs 32 2^ * >integer ] uint-array{ } map-as
- ]
+CONSTANT: T $[
+ 80 iota [ sin abs 32 2^ * >integer ] uint-array{ } map-as
+]
:: F ( X Y Z -- FXYZ )
#! F(X,Y,Z) = XY v not(X) Z
@@ -84,14 +81,14 @@ CONSTANT: d 3
k x nth-unsafe w+
i T nth-unsafe w+
s bitroll-32
- b state nth-unsafe w+ 32 bits
+ b state nth-unsafe w+
] change-nth-unsafe ; inline
MACRO: with-md5-round ( ops quot -- )
'[ [ _ (ABCD) ] compose ] map '[ _ 2cleave ] ;
: (process-md5-block-F) ( block state -- )
- {
+ { uint-array uint-array } declare {
[ a b c d 0 S11 1 ]
[ d a b c 1 S12 2 ]
[ c d a b 2 S13 3 ]
@@ -111,7 +108,7 @@ MACRO: with-md5-round ( ops quot -- )
} [ F ] with-md5-round ;
: (process-md5-block-G) ( block state -- )
- {
+ { uint-array uint-array } declare {
[ a b c d 1 S21 17 ]
[ d a b c 6 S22 18 ]
[ c d a b 11 S23 19 ]
@@ -131,7 +128,7 @@ MACRO: with-md5-round ( ops quot -- )
} [ G ] with-md5-round ;
: (process-md5-block-H) ( block state -- )
- {
+ { uint-array uint-array } declare {
[ a b c d 5 S31 33 ]
[ d a b c 8 S32 34 ]
[ c d a b 11 S33 35 ]
@@ -151,7 +148,7 @@ MACRO: with-md5-round ( ops quot -- )
} [ H ] with-md5-round ;
: (process-md5-block-I) ( block state -- )
- {
+ { uint-array uint-array } declare {
[ a b c d 0 S41 49 ]
[ d a b c 7 S42 50 ]
[ c d a b 14 S43 51 ]
@@ -170,11 +167,6 @@ MACRO: with-md5-round ( ops quot -- )
[ b c d a 9 S44 64 ]
} [ I ] with-md5-round ;
-HINTS: (process-md5-block-F) { uint-array md5-state } ;
-HINTS: (process-md5-block-G) { uint-array md5-state } ;
-HINTS: (process-md5-block-H) { uint-array md5-state } ;
-HINTS: (process-md5-block-I) { uint-array md5-state } ;
-
: byte-array>le ( byte-array -- byte-array )
little-endian? [
dup 4 [
@@ -183,19 +175,11 @@ HINTS: (process-md5-block-I) { uint-array md5-state } ;
] each
] unless ;
-: uint-array-cast-le ( byte-array -- uint-array )
- byte-array>le uint cast-array ;
+HINTS: byte-array>le byte-array ;
-HINTS: uint-array-cast-le byte-array ;
-
-: uint-array>byte-array-le ( uint-array -- byte-array )
- underlying>> byte-array>le ;
-
-HINTS: uint-array>byte-array-le uint-array ;
-
-M: md5-state checksum-block ( block state -- )
+M: md5-state checksum-block
[
- [ uint-array-cast-le ] [ state>> ] bi* {
+ [ byte-array>le uint cast-array ] [ state>> ] bi* {
[ (process-md5-block-F) ]
[ (process-md5-block-G) ]
[ (process-md5-block-H) ]
@@ -205,18 +189,20 @@ M: md5-state checksum-block ( block state -- )
nip update-md5
] 2bi ;
-: md5>checksum ( md5 -- bytes ) state>> uint-array>byte-array-le ;
+: md5>checksum ( md5 -- bytes )
+ state>> underlying>> byte-array>le ;
-M: md5-state clone ( md5 -- new-md5 )
+M: md5-state clone
call-next-method
[ clone ] change-state
[ clone ] change-old-state ;
-M: md5-state get-checksum ( md5 -- bytes )
- clone [ bytes>> f ] [ bytes-read>> pad-last-block ] [ ] tri
+M: md5-state get-checksum
+ clone
+ [ bytes>> f ] [ bytes-read>> pad-last-block ] [ ] tri
[ [ checksum-block ] curry each ] [ md5>checksum ] bi ;
-M: md5 checksum-stream ( stream checksum -- byte-array )
+M: md5 checksum-stream
drop
[ ] dip add-checksum-stream get-checksum ;
diff --git a/basis/checksums/murmur/authors.txt b/basis/checksums/murmur/authors.txt
new file mode 100644
index 0000000000..e091bb8164
--- /dev/null
+++ b/basis/checksums/murmur/authors.txt
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/checksums/murmur/murmur-docs.factor b/basis/checksums/murmur/murmur-docs.factor
new file mode 100644
index 0000000000..da9f612075
--- /dev/null
+++ b/basis/checksums/murmur/murmur-docs.factor
@@ -0,0 +1,11 @@
+USING: help.markup help.syntax ;
+IN: checksums.murmur
+
+HELP: murmur3-32
+{ $class-description "MurmurHash3 32-bit checksum algorithm." } ;
+
+ARTICLE: "checksums.murmur" "MurmurHash checksum"
+"MurmurHash is a non-cryptographic hash function suitable for general hash-based lookup, created by Austin Appleby in 2008."
+{ $subsections murmur3-32 } ;
+
+ABOUT: "checksums.murmur"
diff --git a/basis/checksums/murmur/murmur-tests.factor b/basis/checksums/murmur/murmur-tests.factor
new file mode 100644
index 0000000000..8a16c5a905
--- /dev/null
+++ b/basis/checksums/murmur/murmur-tests.factor
@@ -0,0 +1,38 @@
+USING: byte-arrays checksums fry kernel math sequences
+tools.test ;
+IN: checksums.murmur
+
+{ 455139366 } [ "asdf" >byte-array 0 checksum-bytes ] unit-test
+{ 417250299 } [ "asdf" >byte-array 156 checksum-bytes ] unit-test
+{ 3902511862 } [ "abcde" >byte-array 0 checksum-bytes ] unit-test
+{ 2517562459 } [ "abcde" >byte-array 156 checksum-bytes ] unit-test
+{ 2444432334 } [ "12345678" >byte-array 0 checksum-bytes ] unit-test
+{ 2584512840 } [ "12345678" >byte-array 156 checksum-bytes ] unit-test
+{ 3560398725 } [ "hello, world!!!" >byte-array 156 checksum-bytes ] unit-test
+
+{
+ {
+ 3903553677
+ 3120384252
+ 3928660296
+ 2995164002
+ 500661690
+ 2764333444
+ 1941147762
+ 161439790
+ 2584512840
+ 3803370487
+ 626154228
+ }
+} [
+ "1234567890" [ length 1 + ] keep 156
+ '[ _ swap head _ checksum-bytes ] { } map-integers
+] unit-test
+
+
+{ t } [
+ "1234567890" dup >byte-array [
+ [ length 1 + ] keep 156
+ '[ _ swap head _ checksum-bytes ] { } map-integers
+ ] bi@ =
+] unit-test
diff --git a/basis/checksums/murmur/murmur.factor b/basis/checksums/murmur/murmur.factor
new file mode 100644
index 0000000000..441a59eaee
--- /dev/null
+++ b/basis/checksums/murmur/murmur.factor
@@ -0,0 +1,53 @@
+! Copyright (C) 2013 John Benediktsson.
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: accessors alien alien.c-types alien.data byte-arrays
+checksums fry grouping io.binary kernel math math.bitwise
+math.ranges sequences ;
+
+IN: checksums.murmur
+
+TUPLE: murmur3-32 seed ;
+
+C: murmur3-32
+
+CONSTANT: c1 0xcc9e2d51
+CONSTANT: c2 0x1b873593
+CONSTANT: r1 15
+CONSTANT: r2 13
+CONSTANT: m 5
+CONSTANT: n 0xe6546b64
+
+ ] dip
+ [ pick int deref hash-chunk ] reduce
+ ] [
+ [ dup length 4 mod dupd head-slice* 4 ] dip
+ [ le> hash-chunk ] reduce
+ ] if ; inline
+
+: end-case ( seq hash -- hash' )
+ swap dup length
+ [ 4 mod tail-slice* be> (hash-chunk) bitxor ]
+ [ bitxor ] bi 32 bits ; inline
+
+: avalanche ( hash -- hash' )
+ [ -16 shift ] [ bitxor 0x85ebca6b w* ] bi
+ [ -13 shift ] [ bitxor 0xc2b2ae35 w* ] bi
+ [ -16 shift ] [ bitxor ] bi ; inline
+
+PRIVATE>
+
+M: murmur3-32 checksum-bytes ( bytes checksum -- value )
+ seed>> 32 bits main-loop end-case avalanche ;
+
+INSTANCE: murmur3-32 checksum
diff --git a/basis/checksums/murmur/summary.txt b/basis/checksums/murmur/summary.txt
new file mode 100644
index 0000000000..4ac7b4acb2
--- /dev/null
+++ b/basis/checksums/murmur/summary.txt
@@ -0,0 +1 @@
+MurmurHash checksum algorithm
diff --git a/basis/checksums/sha/sha.factor b/basis/checksums/sha/sha.factor
index fc4e96aee7..182dbe5e42 100644
--- a/basis/checksums/sha/sha.factor
+++ b/basis/checksums/sha/sha.factor
@@ -1,10 +1,9 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors checksums checksums.common checksums.stream
-combinators combinators.smart fry generalizations grouping
-io.binary kernel literals locals make math math.bitwise
-math.ranges multiline namespaces sbufs sequences
-sequences.generalizations sequences.private splitting strings ;
+USING: accessors arrays checksums checksums.common
+checksums.stream combinators combinators.smart fry grouping
+io.binary kernel literals locals math math.bitwise math.ranges
+sequences sequences.generalizations sequences.private ;
IN: checksums.sha
SINGLETON: sha1
@@ -16,10 +15,14 @@ SINGLETON: sha-256
INSTANCE: sha-224 stream-checksum
INSTANCE: sha-256 stream-checksum
-TUPLE: sha1-state < checksum-state K H W word-size ;
+TUPLE: sha1-state < checksum-state
+{ K array }
+{ H array }
+{ W array }
+{ word-size fixnum } ;
CONSTANT: initial-H-sha1
- {
+ {
0x67452301
0xefcdab89
0x98badcfe
@@ -36,7 +39,10 @@ CONSTANT: K-sha1
4 { } nappend-as
]
-TUPLE: sha2-state < checksum-state K H word-size ;
+TUPLE: sha2-state < checksum-state
+{ K array }
+{ H array }
+{ word-size fixnum } ;
TUPLE: sha2-short < sha2-state ;
@@ -308,21 +314,21 @@ M: sha2-short checksum-block
[ prepare-message-schedule ]
[ [ block-size>> ] [ H>> clone ] [ ] tri process-chunk ] bi ;
-: sequence>byte-array ( seq n -- string )
- '[ _ >be ] map B{ } concat-as ;
+: sequence>byte-array ( seq n -- bytes )
+ '[ _ >be ] map B{ } concat-as ; inline
: sha1>checksum ( sha2 -- bytes )
- H>> 4 sequence>byte-array ;
+ H>> 4 sequence>byte-array ; inline
: sha-224>checksum ( sha2 -- bytes )
- H>> 7 head 4 sequence>byte-array ;
+ H>> 7 head 4 sequence>byte-array ; inline
: sha-256>checksum ( sha2 -- bytes )
- H>> 4 sequence>byte-array ;
+ H>> 4 sequence>byte-array ; inline
: pad-last-short-block ( state -- )
[ bytes>> t ] [ bytes-read>> pad-last-block ] [ ] tri
- [ checksum-block ] curry each ;
+ [ checksum-block ] curry each ; inline
PRIVATE>
@@ -349,7 +355,7 @@ M: sha-256 checksum-stream ( stream checksum -- byte-array )
[ [ 14 - ] dip nth-unsafe bitxor ]
[ [ 16 - ] dip nth-unsafe bitxor 1 bitroll-32 ]
[ ]
- } 2cleave set-nth-unsafe ;
+ } 2cleave set-nth-unsafe ; inline
: prepare-sha1-message-schedule ( seq -- w-seq )
4 [ be> ] map
@@ -363,7 +369,7 @@ M: sha-256 checksum-stream ( stream checksum -- byte-array )
{ 1 [ bitxor bitxor ] }
{ 2 [ 2dup bitand [ pick bitand [ bitand ] dip ] dip bitor bitor ] }
{ 3 [ bitxor bitxor ] }
- } case ;
+ } case ; inline
:: inner-loop ( n H W K -- temp )
a H nth-unsafe :> A
@@ -374,16 +380,16 @@ M: sha-256 checksum-stream ( stream checksum -- byte-array )
[
A 5 bitroll-32
- B C D n sha1-f
+ B C D n sha1-f
E
n K nth-unsafe
n W nth-unsafe
- ] sum-outputs 32 bits ;
+ ] sum-outputs 32 bits ; inline
-:: process-sha1-chunk ( bytes H W K state -- )
+:: process-sha1-chunk ( H W K state -- )
80 [
H W K inner-loop
d H nth-unsafe e H set-nth-unsafe
@@ -397,7 +403,6 @@ M: sha-256 checksum-stream ( stream checksum -- byte-array )
M:: sha1-state checksum-block ( bytes state -- )
bytes prepare-sha1-message-schedule state W<<
- bytes
state [ H>> clone ] [ W>> ] [ K>> ] tri state process-sha1-chunk ;
M: sha1-state get-checksum
diff --git a/basis/checksums/superfast/authors.txt b/basis/checksums/superfast/authors.txt
new file mode 100644
index 0000000000..e091bb8164
--- /dev/null
+++ b/basis/checksums/superfast/authors.txt
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/checksums/superfast/summary.txt b/basis/checksums/superfast/summary.txt
new file mode 100644
index 0000000000..fe5345add9
--- /dev/null
+++ b/basis/checksums/superfast/summary.txt
@@ -0,0 +1 @@
+SuperFastHash checksum algorithm
diff --git a/basis/checksums/superfast/superfast-docs.factor b/basis/checksums/superfast/superfast-docs.factor
new file mode 100644
index 0000000000..b20659cd66
--- /dev/null
+++ b/basis/checksums/superfast/superfast-docs.factor
@@ -0,0 +1,12 @@
+USING: help.markup help.syntax ;
+IN: checksums.superfast
+
+HELP: superfast
+{ $class-description "SuperFastHash checksum algorithm." } ;
+
+ARTICLE: "checksums.superfast" "SuperFastHash checksum"
+"SuperFastHash is a hash, created by Paul Hsieh. For more information see: "
+{ $url "http://www.azillionmonkeys.com/qed/hash.html" }
+{ $subsections superfast } ;
+
+ABOUT: "checksums.superfast"
diff --git a/basis/checksums/superfast/superfast-tests.factor b/basis/checksums/superfast/superfast-tests.factor
new file mode 100644
index 0000000000..54b9bbc520
--- /dev/null
+++ b/basis/checksums/superfast/superfast-tests.factor
@@ -0,0 +1,30 @@
+USING: byte-arrays checksums fry kernel math sequences
+tools.test ;
+IN: checksums.superfast
+
+{
+ {
+ 0
+ 4064760690
+ 2484602674
+ 1021960881
+ 3514307704
+ 762925594
+ 95280079
+ 516333699
+ 1761749771
+ 3841726064
+ 2549850032
+ }
+} [
+ "1234567890" [ length 1 + ] keep 0
+ '[ _ swap head _ checksum-bytes ] { } map-integers
+] unit-test
+
+
+{ t } [
+ "1234567890" dup >byte-array [
+ [ length 1 + ] keep 0
+ '[ _ swap head _ checksum-bytes ] { } map-integers
+ ] bi@ =
+] unit-test
diff --git a/basis/checksums/superfast/superfast.factor b/basis/checksums/superfast/superfast.factor
new file mode 100644
index 0000000000..c3b1545c50
--- /dev/null
+++ b/basis/checksums/superfast/superfast.factor
@@ -0,0 +1,57 @@
+! Copyright (C) 2013 John Benediktsson.
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: accessors alien alien.c-types alien.data byte-arrays
+checksums combinators fry grouping io.binary kernel math
+math.bitwise math.ranges sequences sequences.private ;
+
+IN: checksums.superfast
+
+TUPLE: superfast seed ;
+C: superfast
+
+ ] dip
+ [ pick int deref (main-loop) ] reduce
+ ] [
+ [ dup length 4 mod dupd head-slice* 4 ] dip
+ [ le> (main-loop) ] reduce
+ ] if ; inline
+
+: end-case ( seq hash -- hash' )
+ swap dup length 4 mod [ tail-slice* ] keep {
+ [ drop ]
+ [
+ first + [ 10 shift ] [ bitxor ] bi 32 bits
+ [ -1 shift ] [ + ] bi
+ ]
+ [
+ le> + [ 11 shift ] [ bitxor ] bi 32 bits
+ [ -17 shift ] [ + ] bi
+ ]
+ [
+ unclip-last-slice
+ [ le> + [ 16 shift ] [ bitxor ] bi ]
+ [ 18 shift bitxor ] bi* 32 bits
+ [ -11 shift ] [ + ] bi
+ ]
+ } dispatch ; inline
+
+: avalanche ( hash -- hash' )
+ [ 3 shift ] [ bitxor ] bi 32 bits [ -5 shift ] [ + ] bi
+ [ 4 shift ] [ bitxor ] bi 32 bits [ -17 shift ] [ + ] bi
+ [ 25 shift ] [ bitxor ] bi 32 bits [ -6 shift ] [ + ] bi ; inline
+
+PRIVATE>
+
+M: superfast checksum-bytes
+ seed>> 32 bits main-loop end-case avalanche ;
diff --git a/basis/checksums/xxhash/authors.txt b/basis/checksums/xxhash/authors.txt
new file mode 100644
index 0000000000..e091bb8164
--- /dev/null
+++ b/basis/checksums/xxhash/authors.txt
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/checksums/xxhash/summary.txt b/basis/checksums/xxhash/summary.txt
new file mode 100644
index 0000000000..4d3a9eafab
--- /dev/null
+++ b/basis/checksums/xxhash/summary.txt
@@ -0,0 +1 @@
+xxHash checksum algorithm
diff --git a/basis/checksums/xxhash/xxhash-docs.factor b/basis/checksums/xxhash/xxhash-docs.factor
new file mode 100644
index 0000000000..f5b18b6504
--- /dev/null
+++ b/basis/checksums/xxhash/xxhash-docs.factor
@@ -0,0 +1,11 @@
+USING: help.markup help.syntax ;
+IN: checksums.xxhash
+
+HELP: xxhash
+{ $class-description "xxHash 32-bit checksum algorithm." } ;
+
+ARTICLE: "checksums.xxhash" "XxHash checksum"
+"xxHash is a non-cryptographic hash function suitable for general hash-based lookup."
+{ $subsections xxhash } ;
+
+ABOUT: "checksums.xxhash"
diff --git a/basis/checksums/xxhash/xxhash-tests.factor b/basis/checksums/xxhash/xxhash-tests.factor
new file mode 100644
index 0000000000..052807b0ae
--- /dev/null
+++ b/basis/checksums/xxhash/xxhash-tests.factor
@@ -0,0 +1,8 @@
+USING: byte-arrays checksums tools.test ;
+IN: checksums.xxhash
+
+{ 1584409650 } [ "asdf" 0 checksum-bytes ] unit-test
+{ 4257502458 } [ "Hello World!" 12345 checksum-bytes ] unit-test
+
+{ 1584409650 } [ "asdf" >byte-array 0 checksum-bytes ] unit-test
+{ 4257502458 } [ "Hello World!" >byte-array 12345 checksum-bytes ] unit-test
diff --git a/basis/checksums/xxhash/xxhash.factor b/basis/checksums/xxhash/xxhash.factor
new file mode 100644
index 0000000000..ea6869e482
--- /dev/null
+++ b/basis/checksums/xxhash/xxhash.factor
@@ -0,0 +1,74 @@
+! Copyright (C) 2014 John Benediktsson.
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: accessors alien alien.c-types alien.data byte-arrays
+checksums combinators generalizations grouping io.binary kernel
+locals math math.bitwise math.ranges sequences ;
+
+IN: checksums.xxhash
+
+CONSTANT: prime1 2654435761
+CONSTANT: prime2 2246822519
+CONSTANT: prime3 3266489917
+CONSTANT: prime4 668265263
+CONSTANT: prime5 374761393
+
+TUPLE: xxhash seed ;
+
+C: xxhash
+
+
+ bytes byte-array? little-endian? and
+ [ c-type cast-array ]
+ [ c-type heap-size [ le> ] map ] if ; inline
+
+PRIVATE>
+
+M:: xxhash checksum-bytes ( bytes checksum -- value )
+ checksum seed>> :> seed
+ bytes length :> len
+
+ len dup 16 mod - :> len/16
+ len dup 4 mod - :> len/4
+
+ len 16 >= [
+
+ seed prime1 w+ prime2 w+
+ seed prime2 w+
+ seed
+ seed prime1 w-
+
+ 0 len/16 bytes uint native-mapper
+
+ 4 [
+ first4
+ [ prime2 w* w+ 13 bitroll-32 prime1 w* ]
+ 4 napply
+ ] each
+
+ {
+ [ 1 bitroll-32 ]
+ [ 7 bitroll-32 ]
+ [ 12 bitroll-32 ]
+ [ 18 bitroll-32 ]
+ } spread w+ w+ w+
+ ] [
+ seed prime5 w+
+ ] if
+
+ len w+
+
+ len/16 len/4 bytes uint native-mapper
+ [ prime3 w* w+ 17 bitroll-32 prime4 w* ] each
+
+ bytes len/4 tail-slice
+ [ prime5 w* w+ 11 bitroll-32 prime1 w* ] each
+
+ [ -15 shift ] [ bitxor ] bi prime2 w*
+ [ -13 shift ] [ bitxor ] bi prime3 w*
+ [ -16 shift ] [ bitxor ] bi ;
+
+INSTANCE: xxhash checksum
diff --git a/basis/circular/circular-docs.factor b/basis/circular/circular-docs.factor
index 93d137d626..9dcf4817ce 100644
--- a/basis/circular/circular-docs.factor
+++ b/basis/circular/circular-docs.factor
@@ -55,6 +55,14 @@ HELP: circular-while
}
{ $description "Calls " { $snippet "quot" } " on each element of the sequence until each call yields " { $link f } " in succession." } ;
+HELP: circular-loop
+{ $values
+ { "circular" circular }
+ { "quot" quotation }
+}
+{ $description "Calls " { $snippet "quot" } " on each element of the sequence until one call yields " { $link f } "." }
+{ $notes "This rotates the " { $link circular } " object after each call, so the next element to be applied will always be the first element." } ;
+
ARTICLE: "circular" "Circular sequences"
"The " { $vocab-link "circular" } " vocabulary implements the " { $link "sequence-protocol" } " to allow an arbitrary start index and wrap-around indexing." $nl
"Creating a new circular object:"
@@ -74,6 +82,6 @@ ARTICLE: "circular" "Circular sequences"
growing-circular-push
}
"Iterating over a circular until a stop condition:"
-{ $subsections circular-while } ;
+{ $subsections circular-while circular-loop } ;
ABOUT: "circular"
diff --git a/basis/circular/circular-tests.factor b/basis/circular/circular-tests.factor
index a3b1d5541c..c83d4eb897 100644
--- a/basis/circular/circular-tests.factor
+++ b/basis/circular/circular-tests.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2005, 2006 Alex Chapman, Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license
-USING: arrays kernel tools.test sequences sequences.private
-circular strings ;
+USING: arrays circular kernel math sequences sequences.private
+strings tools.test ;
IN: circular.tests
[ 0 ] [ { 0 1 2 3 4 } 0 swap virtual@ drop ] unit-test
@@ -42,3 +42,35 @@ IN: circular.tests
swap growing-circular-push
] with each >array
] unit-test
+
+[ V{ 1 2 3 } ] [
+ { 1 2 3 } V{ } [
+ [ push f ] curry circular-while
+ ] keep
+] unit-test
+
+CONSTANT: test-sequence1 { t f f f }
+[ V{ 1 2 3 1 } ] [
+ { 1 2 3 } V{ } [
+ [ [ push ] [ length 1 - test-sequence1 nth ] bi ] curry circular-while
+ ] keep
+] unit-test
+
+CONSTANT: test-sequence2 { t f t t f f t t t f f f }
+[ V{ 1 2 3 1 2 3 1 2 3 1 2 3 } ] [
+ { 1 2 3 } V{ } [
+ [ [ push ] [ length 1 - test-sequence2 nth ] bi ] curry circular-while
+ ] keep
+] unit-test
+
+[ V{ 1 2 3 1 2 } ] [
+ { 1 2 3 } V{ } [
+ [ [ push ] [ length 5 < ] bi ] curry circular-loop
+ ] keep
+] unit-test
+
+[ V{ 1 } ] [
+ { 1 2 3 } V{ } [
+ [ push f ] curry circular-loop
+ ] keep
+] unit-test
diff --git a/basis/circular/circular.factor b/basis/circular/circular.factor
index f199413f86..9eba3c94ad 100644
--- a/basis/circular/circular.factor
+++ b/basis/circular/circular.factor
@@ -60,14 +60,14 @@ TUPLE: circular-iterator
{ circular read-only } { n integer } { last-start integer } ;
: ( circular -- obj )
- 0 0 circular-iterator boa ; inline
+ 0 -1 circular-iterator boa ; inline
> ] [ circular>> ] bi nth ] dip call ] 2keep
rot [ [ dup n>> >>last-start ] dip ] when
- over [ n>> ] [ [ last-start>> ] [ circular>> length ] bi + 1 - ] bi = [
+ over [ n>> ] [ [ last-start>> ] [ circular>> length ] bi + ] bi = [
2drop
] [
[ [ 1 + ] change-n ] dip (circular-while)
@@ -77,3 +77,6 @@ PRIVATE>
: circular-while ( ... circular quot: ( ... obj -- ... ? ) -- ... )
[ clone ] dip [ ] dip (circular-while) ; inline
+
+: circular-loop ( ... circular quot: ( ... obj -- ... ? ) -- ... )
+ [ clone ] dip '[ [ first @ ] [ rotate-circular ] bi ] curry loop ; inline
diff --git a/basis/classes/struct/struct.factor b/basis/classes/struct/struct.factor
index c90ae52211..d603e3233a 100644
--- a/basis/classes/struct/struct.factor
+++ b/basis/classes/struct/struct.factor
@@ -250,7 +250,9 @@ M: struct-bit-slot-spec compute-slot-offset
PRIVATE>
-M: struct byte-length class-of "struct-size" word-prop ; inline foldable
+: struct-size ( class -- n ) "struct-size" word-prop ; inline
+
+M: struct byte-length class-of struct-size ; inline foldable
M: struct binary-zero? binary-object uchar [ 0 = ] all? ; inline
! class definition
diff --git a/basis/cocoa/apple-script/apple-script-docs.factor b/basis/cocoa/apple-script/apple-script-docs.factor
new file mode 100644
index 0000000000..8013bd2f9f
--- /dev/null
+++ b/basis/cocoa/apple-script/apple-script-docs.factor
@@ -0,0 +1,13 @@
+USING: help.markup help.syntax strings ;
+
+IN: cocoa.apple-script
+
+HELP: run-apple-script
+{ $values { "str" string } }
+{ $description "Runs the provided uncompiled AppleScript code." }
+{ $notes "Currently, return values are unsupported." } ;
+
+HELP: APPLESCRIPT:
+{ $syntax "APPLESCRIPT: word ...applescript... ;APPLESCRIPT" }
+{ $values { "word" "a new word to define" } { "...applescript..." "AppleScript source text" } }
+{ $description "Defines a word that when called will run the provided uncompiled AppleScript. The word has stack effect " { $snippet "( -- )" } " due to return values being currently unsupported." } ;
diff --git a/basis/cocoa/apple-script/apple-script.factor b/basis/cocoa/apple-script/apple-script.factor
new file mode 100644
index 0000000000..f3cb8ec798
--- /dev/null
+++ b/basis/cocoa/apple-script/apple-script.factor
@@ -0,0 +1,16 @@
+! Copyright (C) 2013 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: cocoa cocoa.application cocoa.classes kernel parser
+multiline words ;
+
+IN: cocoa.apple-script
+
+: run-apple-script ( str -- )
+ [ NSAppleScript -> alloc ] dip
+ -> initWithSource: -> autorelease
+ f -> executeAndReturnError: drop ;
+
+SYNTAX: APPLESCRIPT:
+ scan-new-word ";APPLESCRIPT" parse-multiline-string
+ [ run-apple-script ] curry ( -- ) define-declared ;
diff --git a/basis/cocoa/apple-script/authors.txt b/basis/cocoa/apple-script/authors.txt
new file mode 100644
index 0000000000..e091bb8164
--- /dev/null
+++ b/basis/cocoa/apple-script/authors.txt
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/cocoa/apple-script/platforms.txt b/basis/cocoa/apple-script/platforms.txt
new file mode 100644
index 0000000000..6e806f449e
--- /dev/null
+++ b/basis/cocoa/apple-script/platforms.txt
@@ -0,0 +1 @@
+macosx
diff --git a/basis/cocoa/cocoa.factor b/basis/cocoa/cocoa.factor
index c90e238ede..58d7bb133a 100644
--- a/basis/cocoa/cocoa.factor
+++ b/basis/cocoa/cocoa.factor
@@ -1,17 +1,15 @@
! Copyright (C) 2006, 2009 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: compiler io kernel cocoa.runtime cocoa.subclassing
-cocoa.messages cocoa.types sequences words vocabs parser
-core-foundation.bundles namespaces assocs hashtables
-compiler.units lexer init ;
+USING: cocoa.messages compiler.units core-foundation.bundles
+hashtables init io kernel lexer namespaces sequences vocabs ;
FROM: cocoa.messages => selector ;
IN: cocoa
+SYMBOL: sent-messages
+
: (remember-send) ( selector variable -- )
[ dupd ?set-at ] change-global ;
-SYMBOL: sent-messages
-
: remember-send ( selector -- )
sent-messages (remember-send) ;
@@ -22,12 +20,6 @@ SYNTAX: SEL:
[ remember-send ]
[ suffix! \ selector suffix! ] bi ;
-SYNTAX: SEND:
- scan-token
- [ remember-send ]
- [ suffix! \ selector suffix! ]
- [ suffix! \ lookup-sender suffix! ] tri ;
-
SYMBOL: super-sent-messages
: remember-super-send ( selector -- )
@@ -52,6 +44,7 @@ SYNTAX: IMPORT: scan-token [ ] import-objc-class ;
[
{
"NSAlert"
+ "NSAppleScript"
"NSApplication"
"NSArray"
"NSAutoreleasePool"
diff --git a/basis/cocoa/enumeration/enumeration.factor b/basis/cocoa/enumeration/enumeration.factor
index f4d1053f0a..a78a29bd7f 100644
--- a/basis/cocoa/enumeration/enumeration.factor
+++ b/basis/cocoa/enumeration/enumeration.factor
@@ -1,7 +1,8 @@
! Copyright (C) 2008 Joe Groff.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel classes.struct cocoa cocoa.runtime cocoa.types alien.data
-locals math sequences vectors fry libc destructors specialized-arrays ;
+USING: accessors alien.data assocs classes.struct cocoa
+cocoa.runtime cocoa.types destructors fry hashtables kernel libc
+locals sequences specialized-arrays vectors ;
SPECIALIZED-ARRAY: id
IN: cocoa.enumeration
@@ -32,3 +33,7 @@ CONSTANT: NS-EACH-BUFFER-SIZE 16
: NSFastEnumeration>vector ( object -- vector )
[ ] NSFastEnumeration-map ;
+
+: NSFastEnumeration>hashtable ( ... object quot: ( ... elt -- ... key value ) -- ... vector )
+ NS-EACH-BUFFER-SIZE
+ [ '[ @ swap _ set-at ] NSFastEnumeration-each ] keep ; inline
diff --git a/basis/cocoa/messages/messages-docs.factor b/basis/cocoa/messages/messages-docs.factor
index 7dee15d2e2..a0eed26c5b 100644
--- a/basis/cocoa/messages/messages-docs.factor
+++ b/basis/cocoa/messages/messages-docs.factor
@@ -31,7 +31,7 @@ HELP: alien>objc-types
{ objc>alien-types alien>objc-types } related-words
HELP: import-objc-class
-{ $values { "name" string } { "quot" { $quotation "( -- )" } } }
+{ $values { "name" string } { "quot" { $quotation ( -- ) } } }
{ $description "If a class named " { $snippet "name" } " is already known to the Objective C interface, does nothing. Otherwise, first calls the quotation. The quotation should make the class available to the Objective C runtime if necessary, either by loading a framework or defining it directly. After the quotation returns, this word makes the class available to Factor programs by importing methods and creating a class word the class object in the " { $vocab-link "cocoa.classes" } " vocabulary." } ;
HELP: root-class
diff --git a/basis/cocoa/messages/messages-tests.factor b/basis/cocoa/messages/messages-tests.factor
new file mode 100644
index 0000000000..c51511ce24
--- /dev/null
+++ b/basis/cocoa/messages/messages-tests.factor
@@ -0,0 +1,8 @@
+USING: alien.c-types cocoa.runtime tools.test ;
+IN: cocoa.messages
+
+{ "( sender-stub:void() )" }
+[ { void { } } sender-stub-name ] unit-test
+
+{ "( sender-stub:id(id,SEL,void*,Class) )" }
+[ { id { id SEL void* Class } } sender-stub-name ] unit-test
diff --git a/basis/cocoa/messages/messages.factor b/basis/cocoa/messages/messages.factor
index de3d6c3d94..155c39c25c 100644
--- a/basis/cocoa/messages/messages.factor
+++ b/basis/cocoa/messages/messages.factor
@@ -14,8 +14,13 @@ SPECIALIZED-ARRAY: void*
: make-sender ( signature function -- quot )
[ over first , f , , second , \ alien-invoke , ] [ ] make ;
-: sender-stub ( name signature function -- word )
- [ "( sender-stub:" ")" surround f dup ] 2dip
+: sender-stub-name ( signature -- str )
+ first2 [ name>> ] [
+ [ name>> ] map "," join "(" ")" surround
+ ] bi* append "( sender-stub:" " )" surround ;
+
+: sender-stub ( signature function -- word )
+ [ [ sender-stub-name f dup ] keep ] dip
over first large-struct? [ "_stret" append ] when
make-sender dup infer define-declared ;
@@ -25,13 +30,13 @@ SYMBOL: super-message-senders
message-senders [ H{ } clone ] initialize
super-message-senders [ H{ } clone ] initialize
-:: cache-stub ( name signature function assoc -- )
- signature assoc [ [ name ] dip function sender-stub ] cache drop ;
+:: cache-stub ( signature function assoc -- )
+ signature assoc [ function sender-stub ] cache drop ;
-: cache-stubs ( name signature -- )
+: cache-stubs ( signature -- )
[ "objc_msgSendSuper" super-message-senders get cache-stub ]
[ "objc_msgSend" message-senders get cache-stub ]
- 2bi ;
+ bi ;
: ( receiver -- super )
[ ] [ object_getClass class_getSuperclass ] bi
@@ -224,7 +229,7 @@ ERROR: no-objc-type name ;
: register-objc-method ( method -- )
[ method-name ]
[ [ method-return-type ] [ method-arg-types ] bi 2array ] bi
- [ cache-stubs ] [ swap objc-methods get set-at ] 2bi ;
+ [ nip cache-stubs ] [ swap objc-methods get set-at ] 2bi ;
: each-method-in-class ( class quot -- )
[ { uint } [ class_copyMethodList ] with-out-parameters ] dip
diff --git a/basis/cocoa/nibs/nibs-docs.factor b/basis/cocoa/nibs/nibs-docs.factor
index ff53cb0b58..b1c3f2a04e 100644
--- a/basis/cocoa/nibs/nibs-docs.factor
+++ b/basis/cocoa/nibs/nibs-docs.factor
@@ -1,4 +1,4 @@
-USING: help.markup help.syntax strings ;
+USING: help.markup help.syntax sequences strings ;
IN: cocoa.nibs
HELP: load-nib
@@ -11,6 +11,6 @@ HELP: nib-named
{ $see-also nib-objects } ;
HELP: nib-objects
-{ $values { "anNSNib" "an instance of NSNib" } { "objects/f" "a sequence" } }
+{ $values { "anNSNib" "an instance of NSNib" } { "objects/f" { $maybe sequence } } }
{ $description "Instantiates the top-level objects of the " { $snippet ".nib" } " file loaded by anNSNib. First create an NSNib instance using " { $link nib-named } "." }
-{ $see-also nib-named } ;
\ No newline at end of file
+{ $see-also nib-named } ;
diff --git a/basis/cocoa/pasteboard/pasteboard-docs.factor b/basis/cocoa/pasteboard/pasteboard-docs.factor
index f63bc0ec47..e6af5ab6b6 100644
--- a/basis/cocoa/pasteboard/pasteboard-docs.factor
+++ b/basis/cocoa/pasteboard/pasteboard-docs.factor
@@ -1,8 +1,8 @@
-USING: help.markup help.syntax strings ;
+USING: help.markup help.syntax kernel strings ;
IN: cocoa.pasteboard
HELP: pasteboard-string?
-{ $values { "pasteboard" "an " { $snippet "NSPasteBoard" } } { "?" "a boolean" } }
+{ $values { "pasteboard" "an " { $snippet "NSPasteBoard" } } { "?" boolean } }
{ $description "Tests if the pasteboard holds a string." } ;
HELP: pasteboard-string
diff --git a/basis/cocoa/plists/plists.factor b/basis/cocoa/plists/plists.factor
index 0ac7a43229..63662d5489 100644
--- a/basis/cocoa/plists/plists.factor
+++ b/basis/cocoa/plists/plists.factor
@@ -30,8 +30,8 @@ DEFER: plist>
[ plist> ] NSFastEnumeration-map ;
: (plist-NSDictionary>) ( NSDictionary -- hashtable )
- dup [ [ nip ] [ -> valueForKey: ] 2bi [ plist> ] bi@ 2array ] with
- NSFastEnumeration-map >hashtable ;
+ dup [ [ nip ] [ -> valueForKey: ] 2bi [ plist> ] bi@ ] with
+ NSFastEnumeration>hashtable ;
: (read-plist) ( NSData -- id )
NSPropertyListSerialization swap kCFPropertyListImmutable f
diff --git a/basis/colors/colors.factor b/basis/colors/colors.factor
index 5932d0ff15..9e5fef1134 100644
--- a/basis/colors/colors.factor
+++ b/basis/colors/colors.factor
@@ -16,11 +16,11 @@ C: rgba
GENERIC: >rgba ( color -- rgba )
-M: rgba >rgba ( rgba -- rgba ) ; inline
+M: rgba >rgba ; inline
-M: color red>> ( color -- red ) >rgba red>> ;
-M: color green>> ( color -- green ) >rgba green>> ;
-M: color blue>> ( color -- blue ) >rgba blue>> ;
+M: color red>> >rgba red>> ;
+M: color green>> >rgba green>> ;
+M: color blue>> >rgba blue>> ;
: >rgba-components ( object -- r g b a )
>rgba { [ red>> ] [ green>> ] [ blue>> ] [ alpha>> ] } cleave ; inline
diff --git a/basis/colors/gray/gray.factor b/basis/colors/gray/gray.factor
index 532a091c07..c6f576f58c 100644
--- a/basis/colors/gray/gray.factor
+++ b/basis/colors/gray/gray.factor
@@ -16,7 +16,11 @@ M: gray green>> gray>> ;
M: gray blue>> gray>> ;
-: rgba>gray ( rgba -- gray )
+GENERIC: >gray ( color -- gray )
+
+M: object >gray >rgba >gray ;
+
+M: rgba >gray
>rgba-components [
[ 0.3 * ] [ 0.59 * ] [ 0.11 * ] tri* + +
] dip ;
diff --git a/basis/colors/hsv/hsv.factor b/basis/colors/hsv/hsv.factor
index d00df1a8f1..194845efd1 100644
--- a/basis/colors/hsv/hsv.factor
+++ b/basis/colors/hsv/hsv.factor
@@ -49,7 +49,13 @@ M: hsva >rgba ( hsva -- rgba )
PRIVATE>
-:: rgba>hsva ( rgba -- hsva )
+GENERIC: >hsva ( color -- hsva )
+
+M: object >hsva >rgba >hsva ;
+
+M: hsva >hsva ; inline
+
+M:: rgba >hsva ( rgba -- hsva )
rgba >rgba-components :> ( r g b a )
r g b sort-triple :> ( z y x )
x z = x zero? or [ 0 0 x a ] [
@@ -64,7 +70,7 @@ PRIVATE>
] if ;
: complimentary-color ( color -- color' )
- dup hsva? [ >rgba rgba>hsva ] unless
+ dup hsva? [ >hsva ] unless
{
[ hue>> 180 + 360 mod ]
[ saturation>> ]
diff --git a/basis/combinators/short-circuit/short-circuit.factor b/basis/combinators/short-circuit/short-circuit.factor
index f775c2f24c..9e59d5ee9e 100644
--- a/basis/combinators/short-circuit/short-circuit.factor
+++ b/basis/combinators/short-circuit/short-circuit.factor
@@ -29,8 +29,8 @@ PRIVATE>
: 0&& ( quots -- ? ) [ ] unoptimized-&& ;
: 1&& ( obj quots -- ? ) [ with ] unoptimized-&& ;
-: 2&& ( obj1 obj2 quots -- ? ) [ with with ] unoptimized-&& ;
-: 3&& ( obj1 obj2 obj3 quots -- ? ) [ with with with ] unoptimized-&& ;
+: 2&& ( obj1 obj2 quots -- ? ) [ 2with ] unoptimized-&& ;
+: 3&& ( obj1 obj2 obj3 quots -- ? ) [ 3 nwith ] unoptimized-&& ;
MACRO: n|| ( quots n -- quot )
[
@@ -51,5 +51,5 @@ PRIVATE>
: 0|| ( quots -- ? ) [ ] unoptimized-|| ;
: 1|| ( obj quots -- ? ) [ with ] unoptimized-|| ;
-: 2|| ( obj1 obj2 quots -- ? ) [ with with ] unoptimized-|| ;
-: 3|| ( obj1 obj2 obj3 quots -- ? ) [ with with with ] unoptimized-|| ;
+: 2|| ( obj1 obj2 quots -- ? ) [ 2with ] unoptimized-|| ;
+: 3|| ( obj1 obj2 obj3 quots -- ? ) [ 3 nwith ] unoptimized-|| ;
diff --git a/basis/combinators/smart/smart-docs.factor b/basis/combinators/smart/smart-docs.factor
index cab79ad675..a92067d34d 100644
--- a/basis/combinators/smart/smart-docs.factor
+++ b/basis/combinators/smart/smart-docs.factor
@@ -228,7 +228,7 @@ HELP: smart-when*
HELP: smart-with
{ $values
- { "param" object } { "obj" object } { "quot" { $quotation "( param ..a -- ..b" } } { "curry" curry } }
+ { "param" object } { "obj" object } { "quot" { $quotation "( param ..a -- ..b )" } } { "curry" curry } }
{ $description "A version of " { $link with } " that puts the parameter before any inputs the quotation uses." } ;
HELP: smart-reduce
diff --git a/basis/combinators/smart/smart.factor b/basis/combinators/smart/smart.factor
index 493b39a9eb..e97c65038c 100644
--- a/basis/combinators/smart/smart.factor
+++ b/basis/combinators/smart/smart.factor
@@ -67,7 +67,7 @@ M: object infer-known* drop f ;
: output>array ( quot -- array )
{ } output>sequence ; inline
-: cleave>array ( x seq -- array )
+: cleave>array ( obj quots -- array )
'[ _ cleave ] output>array ; inline
: cleave>sequence ( x seq exemplar -- array )
diff --git a/basis/command-line/command-line-tests.factor b/basis/command-line/command-line-tests.factor
new file mode 100644
index 0000000000..01099ae19d
--- /dev/null
+++ b/basis/command-line/command-line-tests.factor
@@ -0,0 +1,32 @@
+USING: namespaces splitting tools.test ;
+IN: command-line
+
+{ f { "a" "b" "c" } } [
+ { "-run=test-voc" "a" "b" "c" } parse-command-line
+ script get command-line get
+] unit-test
+
+{ f { "-a" "b" "c" } } [
+ { "-run=test-voc" "-a" "b" "c" } parse-command-line
+ script get command-line get
+] unit-test
+
+{ f { "a" "-b" "c" } } [
+ { "-run=test-voc" "a" "-b" "c" } parse-command-line
+ script get command-line get
+] unit-test
+
+{ f { "a" "b" "-c" } } [
+ { "-run=test-voc" "a" "b" "-c" } parse-command-line
+ script get command-line get
+] unit-test
+
+{ "a" { "b" "c" } } [
+ { "a" "b" "c" } parse-command-line
+ script get command-line get
+] unit-test
+
+{ "a" { "b" "c" } } [
+ { "-foo" "a" "b" "c" } parse-command-line
+ script get command-line get
+] unit-test
diff --git a/basis/command-line/command-line.factor b/basis/command-line/command-line.factor
index 8f38208c89..37511dae90 100644
--- a/basis/command-line/command-line.factor
+++ b/basis/command-line/command-line.factor
@@ -62,18 +62,21 @@ SYMBOL: command-line
[ source-file main>> [ execute( -- ) ] when* ] bi
] with-variable ;
-: (parse-command-line) ( run? args -- )
- [ command-line off script off drop ] [
- unclip "-" ?head
- [ param (parse-command-line) ]
- [
- rot [ prefix f ] when
+: (parse-command-line) ( args -- )
+ [
+ unclip "-" ?head [
+ [ param ] [ "run=" head? ] bi
+ [ command-line set ]
+ [ (parse-command-line) ] if
+ ] [
script set command-line set
] if
- ] if-empty ;
+ ] unless-empty ;
: parse-command-line ( args -- )
- [ [ "-run=" head? ] any? ] keep (parse-command-line) ;
+ command-line off
+ script off
+ (parse-command-line) ;
SYMBOL: main-vocab-hook
diff --git a/basis/compiler/cfg/block-joining/block-joining-docs.factor b/basis/compiler/cfg/block-joining/block-joining-docs.factor
new file mode 100644
index 0000000000..c16e6b46fa
--- /dev/null
+++ b/basis/compiler/cfg/block-joining/block-joining-docs.factor
@@ -0,0 +1,6 @@
+USING: compiler.cfg help.markup help.syntax ;
+IN: compiler.cfg.block-joining
+
+HELP: join-block?
+{ $values { "bb" basic-block } { "?" "a boolean" } }
+{ $description "Whether the block can be joined with its predecessor or not." } ;
diff --git a/basis/compiler/cfg/branch-splitting/branch-splitting.factor b/basis/compiler/cfg/branch-splitting/branch-splitting.factor
index 0222df9ad0..157fd355cd 100644
--- a/basis/compiler/cfg/branch-splitting/branch-splitting.factor
+++ b/basis/compiler/cfg/branch-splitting/branch-splitting.factor
@@ -44,7 +44,7 @@ IN: compiler.cfg.branch-splitting
: update-successor-predecessors ( copies old-bb -- )
dup successors>>
- [ update-successor-predecessor ] with with each ;
+ [ update-successor-predecessor ] 2with each ;
: split-branch ( bb -- )
[ new-blocks ] keep
diff --git a/basis/compiler/cfg/builder/alien/alien-docs.factor b/basis/compiler/cfg/builder/alien/alien-docs.factor
new file mode 100644
index 0000000000..0899fd4918
--- /dev/null
+++ b/basis/compiler/cfg/builder/alien/alien-docs.factor
@@ -0,0 +1,21 @@
+USING: help.markup help.syntax literals make multiline stack-checker.alien ;
+IN: compiler.cfg.builder.alien
+
+<<
+STRING: ex-caller-return
+USING: compiler.cfg.builder.alien make prettyprint ;
+[
+ T{ ##alien-invoke { reg-outputs { { 1 int-rep RAX } } } } ,
+ T{ alien-invoke-params { return pointer: void } } caller-return
+] { } make .
+{
+ T{ ##alien-invoke { reg-outputs { { 1 int-rep RAX } } } }
+ T{ ##box-alien { dst 116 } { src 1 } { temp 115 } }
+}
+;
+>>
+
+HELP: caller-return
+{ $values { "params" alien-node-params } }
+{ $description "If the last alien call returns a value, then this word will emit an instruction to the current sequence being constructed by " { $link make } " that boxes it." }
+{ $examples { $unchecked-example $[ ex-caller-return ] } } ;
diff --git a/basis/compiler/cfg/builder/alien/boxing/boxing-docs.factor b/basis/compiler/cfg/builder/alien/boxing/boxing-docs.factor
new file mode 100644
index 0000000000..742ed07f6e
--- /dev/null
+++ b/basis/compiler/cfg/builder/alien/boxing/boxing-docs.factor
@@ -0,0 +1,52 @@
+USING: alien.c-types compiler.cfg.instructions help.markup help.syntax make
+math ;
+IN: compiler.cfg.builder.alien.boxing
+
+HELP: box
+{ $values
+ { "vregs" "a one-element sequence containing a virtual register indentifier" }
+ { "reps" "a one-element sequence containing a representation symbol" }
+ { "c-type" c-type }
+ { "dst" "box" }
+}
+{ $description "Emits a " { $link ##box-alien } " instruction which boxes an alien value contained in the given register." }
+{ $examples
+ { $unchecked-example
+ "USING: compiler.cfg.builder.alien.boxing make prettyprint ;"
+ "{ 71 } { int-rep } void* base-type [ box ] { } make nip ."
+ "{ T{ ##box-alien { dst 105 } { src 71 } { temp 104 } } }"
+ }
+}
+{ $see-also ##box-alien } ;
+
+HELP: box-return
+{ $values
+ { "vregs" "vregs that contains the return value of the alien call" }
+ { "reps" "representations of the vregs" }
+ { "c-type" abstract-c-type }
+ { "dst" "vreg in which the boxed value, or a reference to it, will be placed" }
+}
+{ $description "Emits instructions for boxing the return value from an alien function call." }
+{ $examples
+ { $unchecked-example
+ "USING: compiler.cfg.builder.alien.boxing kernel make prettyprint ;"
+ "[ { 10 } { tagged-rep } int base-type box-return drop ] { } make ."
+ "{ T{ ##convert-integer { dst 118 } { src 10 } { c-type int } } }"
+ }
+}
+{ $see-also ##box-alien } ;
+
+HELP: stack-size
+{ $values
+ { "c-type" c-type }
+ { "n" number }
+}
+{ $description "Calculates how many bytes of stack space an instance of the C type requires." }
+{ $examples
+ { $unchecked-example
+ "USING: compiler.cfg.builder.alien.boxing prettyprint vm ;"
+ "context base-type stack-size ."
+ "144"
+ }
+}
+{ $see-also heap-size } ;
diff --git a/basis/compiler/cfg/builder/alien/params/params-docs.factor b/basis/compiler/cfg/builder/alien/params/params-docs.factor
new file mode 100644
index 0000000000..f6599ebc11
--- /dev/null
+++ b/basis/compiler/cfg/builder/alien/params/params-docs.factor
@@ -0,0 +1,17 @@
+USING: cpu.architecture help.markup help.syntax math ;
+IN: compiler.cfg.builder.alien.params
+
+HELP: stack-params
+{ $var-description "Count of the number of bytes of stack allocation required to store the current call frames parameters." } ;
+
+HELP: alloc-stack-param
+{ $values { "rep" representation } { "n" integer } }
+{ $description "Allocates space for a stack parameter value of the given representation and returns the previous stack parameter offset." }
+{ $examples
+ "On 32-bit architectures, the offsets will be aligned to four byte boundaries."
+ { $unchecked-example
+ "0 stack-params set float-rep alloc-stack-param stack-params get . ."
+ "4"
+ "0"
+ }
+} ;
diff --git a/basis/compiler/cfg/builder/alien/params/params.factor b/basis/compiler/cfg/builder/alien/params/params.factor
index ff7d11b4e3..7b45d247c7 100644
--- a/basis/compiler/cfg/builder/alien/params/params.factor
+++ b/basis/compiler/cfg/builder/alien/params/params.factor
@@ -6,7 +6,7 @@ IN: compiler.cfg.builder.alien.params
SYMBOL: stack-params
-GENERIC: alloc-stack-param ( reg -- n )
+GENERIC: alloc-stack-param ( rep -- n )
M: object alloc-stack-param ( rep -- n )
stack-params get
diff --git a/basis/compiler/cfg/builder/blocks/blocks-docs.factor b/basis/compiler/cfg/builder/blocks/blocks-docs.factor
new file mode 100644
index 0000000000..b8cb49a224
--- /dev/null
+++ b/basis/compiler/cfg/builder/blocks/blocks-docs.factor
@@ -0,0 +1,55 @@
+USING: compiler.cfg compiler.tree help.markup help.syntax literals math
+multiline quotations ;
+IN: compiler.cfg.builder.blocks
+
+<<
+STRING: ex-emit-trivial-block
+USING: compiler.cfg.builder.blocks prettyprint ;
+initial-basic-block [ [ gensym ##call, ] emit-trivial-block ] { } make drop
+basic-block get .
+T{ basic-block
+ { id 2040412 }
+ { successors
+ V{
+ T{ basic-block
+ { id 2040413 }
+ { instructions
+ V{
+ T{ ##call { word ( gensym ) } }
+ T{ ##branch }
+ }
+ }
+ { successors
+ V{ T{ basic-block { id 2040414 } } }
+ }
+ }
+ }
+ }
+}
+;
+>>
+
+HELP: begin-basic-block
+{ $description "Terminates the current block and initializes a new " { $link basic-block } " to begin outputting instructions to. The new block is included in the old blocks " { $slot "successors" } "." } ;
+
+HELP: call-height
+{ $values { "#call" #call } { "n" number } }
+{ $description "Calculates how many items a " { $link #call } " will add or remove from the data stack." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.builder.blocks compiler.tree.builder prettyprint sequences ;"
+ "[ 3append ] build-tree second call-height ."
+ "-2"
+ }
+} ;
+
+HELP: emit-trivial-block
+{ $values { "quot" quotation } }
+{ $description "Combinator that emits a trivial block, constructed by calling the supplied quotation." }
+{ $examples { $unchecked-example $[ ex-emit-trivial-block ] } } ;
+
+HELP: initial-basic-block
+{ $description "Creates an initial empty " { $link basic-block } " and stores it in the basic-block dynamic variable." } ;
+
+HELP: make-kill-block
+{ $description "Marks the current " { $link basic-block } " being processed as a kill block." } ;
diff --git a/basis/compiler/cfg/builder/builder-docs.factor b/basis/compiler/cfg/builder/builder-docs.factor
new file mode 100644
index 0000000000..9f0671388b
--- /dev/null
+++ b/basis/compiler/cfg/builder/builder-docs.factor
@@ -0,0 +1,82 @@
+USING: assocs compiler.cfg compiler.cfg.builder.blocks
+compiler.cfg.stacks.local compiler.tree help.markup help.syntax literals math
+multiline sequences words ;
+IN: compiler.cfg.builder
+
+<<
+STRING: ex-emit-call
+USING: compiler.cfg.builder compiler.cfg.builder.blocks compiler.cfg.stacks
+kernel make prettyprint ;
+begin-stack-analysis initial-basic-block \ dummy 3 [ emit-call ] { } make drop
+current-height basic-block [ get . ] bi@ .
+T{ current-height { d 3 } }
+T{ basic-block
+ { id 134 }
+ { successors
+ V{
+ T{ basic-block
+ { id 135 }
+ { instructions
+ V{
+ T{ ##call { word dummy } }
+ T{ ##branch }
+ }
+ }
+ { successors V{ T{ basic-block { id 136 } } } }
+ { kill-block? t }
+ }
+ }
+ }
+}
+;
+
+STRING: ex-make-input-map
+USING: compiler.cfg.builder prettyprint ;
+T{ #shuffle { in-d { 37 81 92 } } } make-input-map .
+H{
+ { 81 T{ ds-loc { n 1 } } }
+ { 37 T{ ds-loc { n 2 } } }
+ { 92 T{ ds-loc } }
+}
+;
+>>
+
+HELP: procedures
+{ $var-description "Used as a temporary storage for the current cfg during construction of all cfgs." } ;
+
+HELP: make-input-map
+{ $values { "#shuffle" #shuffle } { "assoc" assoc } }
+{ $description "Creates an " { $link assoc } " that maps input values to the shuffle operation to stack locations." }
+{ $examples { $unchecked-example $[ ex-make-input-map ] } } ;
+
+HELP: emit-call
+{ $values { "word" word } { "height" number } }
+{ $description "Emits a call to the given word to the " { $link cfg } " being constructed. \"height\" is the number of items being added to or removed from the data stack. Side effects of the word is that it modifies the \"basic-block\" and " { $link current-height } " variables." }
+{ $examples
+ "In this example, a call to a dummy word is emitted which pushes three items onto the stack."
+ { $unchecked-example $[ ex-emit-call ] }
+}
+{ $see-also call-height } ;
+
+HELP: emit-node
+{ $values { "node" node } }
+{ $description "Emits CFG instructions for the given SSA node." } ;
+
+HELP: trivial-branch?
+{ $values
+ { "nodes" "a " { $link sequence } " of " { $link node } " instances" }
+ { "value" "the pushed value or " { $link f } }
+ { "?" "a boolean" }
+}
+{ $description "Checks whether nodes is a trivial branch or not. The branch is counted as trivial if all it does is push a literal value on the stack." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.builder compiler.tree prettyprint ;"
+ "{ T{ #push { literal 25 } } } trivial-branch? . ."
+ "t\n25"
+ }
+} ;
+
+HELP: build-cfg
+{ $values { "nodes" sequence } { "word" word } { "procedures" sequence } }
+{ $description "Builds one or more cfgs from the given word." } ;
diff --git a/basis/compiler/cfg/cfg-docs.factor b/basis/compiler/cfg/cfg-docs.factor
new file mode 100644
index 0000000000..67e3a81254
--- /dev/null
+++ b/basis/compiler/cfg/cfg-docs.factor
@@ -0,0 +1,36 @@
+USING: compiler.cfg compiler.cfg.instructions compiler.cfg.rpo
+compiler.cfg.stack-frame compiler.tree help.markup help.syntax namespaces
+sequences vectors words ;
+IN: compiler.cfg
+
+HELP: basic-block
+{ $class-description
+ "Factors representation of a basic block in the Call Flow Graph (CFG). A basic block is a sequence of instructions that always are executed sequentially and doesn't contain any branching. It has the following slots:"
+ { $table
+ { { $slot "successors" } { "A " { $link vector } " of basic blocks that may be executed directly after this block. Most blocks only have one successor but a block that checks where an if-condition should branch to would have two for example." } }
+ { { $slot "predecessors" } { "The opposite of successors -- a " { $link vector } " of basic blocks from which the execution may have arrived into this block." } }
+ { { $slot "instructions" } { "A " { $link vector } " of " { $link insn } " tuples which form the instructions of the basic block." } }
+ { { $slot "unlikely?" } { "Unused boolean slot." } }
+ }
+} ;
+
+HELP:
+{ $values { "bb" basic-block } }
+{ $description "Creates a new empty basic block. The " { $slot "id" } " slot is initialized with the value of the basic-block " { $link counter } "." } ;
+
+HELP: cfg
+{ $class-description
+ "Call flow graph. It has the following slots:"
+ { $table
+ { { $slot "entry" } { "Root " { $link basic-block } " of the graph." } }
+ { { $slot "word" } { "The " { $link word } " the cfg is produced from." } }
+ { { $slot "post-order" } { "The blocks of the cfg in a post order traversal " { $link sequence } "." } }
+ { { $slot "stack-frame" } { { $link stack-frame } " of the cfg." } }
+ { { $slot "frame-pointer?" } { "Whether the cfg needs a frame pointer. Only cfgs generated for " { $link #alien-callback } " nodes does need it." } }
+ }
+}
+{ $see-also post-order } ;
+
+HELP: cfg-changed
+{ $values { "cfg" cfg } }
+{ $description "Resets all \"calculated\" slots in the cfg which forces them to be recalculated." } ;
diff --git a/basis/compiler/cfg/dataflow-analysis/dataflow-analysis-docs.factor b/basis/compiler/cfg/dataflow-analysis/dataflow-analysis-docs.factor
new file mode 100644
index 0000000000..4f7081b4da
--- /dev/null
+++ b/basis/compiler/cfg/dataflow-analysis/dataflow-analysis-docs.factor
@@ -0,0 +1,52 @@
+USING: classes compiler.cfg help.markup help.syntax sequences ;
+IN: compiler.cfg.dataflow-analysis
+
+HELP: predecessors
+{ $values { "bb" basic-block } { "dfa" "a dataflow analysis symbol" } { "seq" sequence } }
+{ $description "Generic word that returns the predecessors for a block. It's purpose is to facilitate backward analysis in which the blocks successors are seen as the predecessors." } ;
+
+HELP: successors
+{ $values { "bb" basic-block } { "dfa" "a dataflow analysis symbol" } { "seq" sequence } }
+{ $description "Generic word that returns the successors for a block. It's purpose is to facilitate backward analysis in which the blocks predecessors are seen as the successors." } ;
+
+HELP: transfer-set
+{ $values
+ { "in-set" "input state" }
+ { "bb" basic-block }
+ { "dfa" class }
+ { "out-set" "output state" }
+}
+{ $description "Generic word which is called during the dataflow analysis to process each basic block in the cfg. It is supposed to be implemented by all forward and backward dataflow analysis subclasses to perform analysis." } ;
+
+HELP: join-sets
+{ $values
+ { "sets" "input states" }
+ { "bb" basic-block }
+ { "dfa" class }
+ { "set" "merged state" }
+}
+{ $description "Generic word which merges multiple states into one. A block in the cfg might have multiple predecessors and then this word is used to compute the merged input state to use to analyze the block." } ;
+
+
+
+
+HELP: FORWARD-ANALYSIS:
+{ $syntax "FORWARD-ANALYSIS: word" }
+{ $values { "word" "name of the compiler pass" } }
+{ $description "Syntax word for defining a forward analysis compiler pass." } ;
+
+HELP: BACKWARD-ANALYSIS:
+{ $syntax "BACKWARD-ANALYSIS: word" }
+{ $values { "word" "name of the compiler pass" } }
+{ $description "Syntax word for defining a backward analysis compiler pass." } ;
diff --git a/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor b/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor
index b5e9535d97..30017f87ec 100644
--- a/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor
+++ b/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor
@@ -10,6 +10,7 @@ GENERIC: transfer-set ( in-set bb dfa -- out-set )
GENERIC: block-order ( cfg dfa -- bbs )
GENERIC: successors ( bb dfa -- seq )
GENERIC: predecessors ( bb dfa -- seq )
+GENERIC: ignore-block? ( bb dfa -- ? )
> [ f ] [
+ bb dfa ignore-block? [ f ] [
bb dfa predecessors
[ out-sets key? ] filter
[ out-sets at ] map
@@ -32,7 +33,7 @@ MIXIN: dataflow-analysis
bb in-sets maybe-set-at ; inline
:: compute-out-set ( bb in-sets dfa -- set )
- bb kill-block?>> [ f ] [ bb in-sets at bb dfa transfer-set ] if ;
+ bb dfa ignore-block? [ f ] [ bb in-sets at bb dfa transfer-set ] if ;
:: update-out-set ( bb in-sets out-sets dfa -- ? )
bb in-sets dfa compute-out-set
@@ -55,6 +56,7 @@ MIXIN: dataflow-analysis
out-sets ; inline
M: dataflow-analysis join-sets 2drop assoc-refine ;
+M: dataflow-analysis ignore-block? drop kill-block?>> ;
FUNCTOR: define-analysis ( name -- )
diff --git a/basis/compiler/cfg/def-use/def-use-docs.factor b/basis/compiler/cfg/def-use/def-use-docs.factor
new file mode 100644
index 0000000000..cfcfe601b7
--- /dev/null
+++ b/basis/compiler/cfg/def-use/def-use-docs.factor
@@ -0,0 +1,24 @@
+USING: compiler.cfg.instructions help.markup help.syntax sequences ;
+IN: compiler.cfg.def-use
+
+HELP: defs-vregs
+{ $values { "insn" insn } { "seq" sequence } }
+{ $description "Returns the sequence of vregs defined, or introduced, by this instruction." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.def-use compiler.cfg.instructions compiler.cfg.registers prettyprint ;"
+ "T{ ##peek f 37 D 0 0 } defs-vregs ."
+ "{ 37 }"
+ }
+} ;
+
+HELP: uses-vregs
+{ $values { "insn" insn } { "seq" sequence } }
+{ $description "Returns the sequence of vregs used by this instruction." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.def-use compiler.cfg.instructions compiler.cfg.registers prettyprint ;"
+ "T{ ##replace f 37 D 1 6 } uses-vregs ."
+ "{ 37 }"
+ }
+} ;
diff --git a/basis/compiler/cfg/def-use/def-use.factor b/basis/compiler/cfg/def-use/def-use.factor
index 36e6bdd46e..9f750f16dc 100644
--- a/basis/compiler/cfg/def-use/def-use.factor
+++ b/basis/compiler/cfg/def-use/def-use.factor
@@ -109,7 +109,7 @@ SYMBOLS: defs insns ;
: insn-of ( vreg -- insn ) insns get at ;
: set-def-of ( obj insn assoc -- )
- swap defs-vregs [ swap set-at ] with with each ;
+ swap defs-vregs [ swap set-at ] 2with each ;
: compute-defs ( cfg -- )
H{ } clone [
diff --git a/basis/compiler/cfg/dependence/dependence-docs.factor b/basis/compiler/cfg/dependence/dependence-docs.factor
new file mode 100644
index 0000000000..cc9cdbd47c
--- /dev/null
+++ b/basis/compiler/cfg/dependence/dependence-docs.factor
@@ -0,0 +1,6 @@
+USING: compiler.cfg.instructions help.markup help.syntax sequences ;
+IN: compiler.cfg.dependence
+
+HELP:
+{ $values { "insn" insn } { "node" node } }
+{ $description "Creates a new dependency graph node from an CFG instruction." } ;
diff --git a/basis/compiler/cfg/finalization/finalization.factor b/basis/compiler/cfg/finalization/finalization.factor
index a0bb29cdf0..2e904464c6 100644
--- a/basis/compiler/cfg/finalization/finalization.factor
+++ b/basis/compiler/cfg/finalization/finalization.factor
@@ -4,7 +4,7 @@ USING: kernel compiler.cfg.representations
compiler.cfg.scheduling compiler.cfg.gc-checks
compiler.cfg.write-barrier compiler.cfg.save-contexts
compiler.cfg.ssa.destruction compiler.cfg.build-stack-frame
-compiler.cfg.linear-scan compiler.cfg.stacks.uninitialized ;
+compiler.cfg.linear-scan compiler.cfg.stacks.vacant ;
IN: compiler.cfg.finalization
: finalize-cfg ( cfg -- cfg' )
@@ -12,7 +12,7 @@ IN: compiler.cfg.finalization
schedule-instructions
insert-gc-checks
eliminate-write-barriers
- dup compute-uninitialized-sets
+ dup compute-vacant-sets
insert-save-contexts
destruct-ssa
linear-scan
diff --git a/basis/compiler/cfg/gc-checks/gc-checks-docs.factor b/basis/compiler/cfg/gc-checks/gc-checks-docs.factor
new file mode 100644
index 0000000000..eaf21a39b8
--- /dev/null
+++ b/basis/compiler/cfg/gc-checks/gc-checks-docs.factor
@@ -0,0 +1,41 @@
+USING: compiler.cfg compiler.cfg.instructions help.markup help.syntax kernel
+layouts math sequences slots.private ;
+IN: compiler.cfg.gc-checks
+
+> successors>> first instructions>> allocation-size ."
+ "32 ! 16 on 32-bit"
+ }
+} ;
+
+PRIVATE>
+
+ARTICLE: "compiler.cfg.gc-checks" "Garbage collection check insertion"
+"This pass runs after representation selection, since it needs to know which vregs can contain tagged pointers." ;
+
+HELP: process-block
+{ $values { "bb" basic-block } }
+{ $description "Process a block that needs a gc check. New blocks are allocated and connected for the gc branches." } ;
diff --git a/basis/compiler/cfg/gc-checks/gc-checks.factor b/basis/compiler/cfg/gc-checks/gc-checks.factor
index c7f79b5ef5..42b32dbb28 100644
--- a/basis/compiler/cfg/gc-checks/gc-checks.factor
+++ b/basis/compiler/cfg/gc-checks/gc-checks.factor
@@ -12,10 +12,6 @@ compiler.cfg.instructions
compiler.cfg.predecessors ;
IN: compiler.cfg.gc-checks
-! Garbage collection check insertion. This pass runs after
-! representation selection, since it needs to know which vregs
-! can contain tagged pointers.
-
( -- gc-map ) gc-map new ;
diff --git a/basis/compiler/cfg/instructions/syntax/syntax-docs.factor b/basis/compiler/cfg/instructions/syntax/syntax-docs.factor
new file mode 100644
index 0000000000..856b927bb0
--- /dev/null
+++ b/basis/compiler/cfg/instructions/syntax/syntax-docs.factor
@@ -0,0 +1,34 @@
+USING: help.markup help.syntax literals multiline sequences splitting ;
+IN: compiler.cfg.instructions.syntax
+
+<<
+STRING: parse-insn-slot-specs-code
+USING: compiler.cfg.instructions.syntax prettyprint splitting ;
+"use: src/int-rep temp: temp/int-rep" " " split parse-insn-slot-specs .
+;
+
+STRING: parse-insn-slot-specs-result
+{
+ T{ insn-slot-spec
+ { type use }
+ { name "src" }
+ { rep int-rep }
+ }
+ T{ insn-slot-spec
+ { type temp }
+ { name "temp" }
+ { rep int-rep }
+ }
+}
+;
+>>
+
+HELP: parse-insn-slot-specs
+{ $values
+ { "seq" "a " { $link sequence } " of tokens" }
+ { "specs" "a " { $link sequence } " of " { $link insn-slot-spec } " items." }
+}
+{ $description "Parses a sequence of tokens into a sequence of instruction slot specifiers." }
+{ $examples
+ { $example $[ parse-insn-slot-specs-code parse-insn-slot-specs-result ] }
+} ;
diff --git a/basis/compiler/cfg/intrinsics/intrinsics-docs.factor b/basis/compiler/cfg/intrinsics/intrinsics-docs.factor
new file mode 100644
index 0000000000..53d268d216
--- /dev/null
+++ b/basis/compiler/cfg/intrinsics/intrinsics-docs.factor
@@ -0,0 +1,5 @@
+USING: compiler.tree help.markup help.syntax words ;
+IN: compiler.cfg.intrinsics
+HELP: emit-intrinsic
+{ $values { "node" node } { "word" word } }
+{ $description "Emit optimized intrinsic code for a word instead of merely calling it. The \"intrinsic\" property of the word (which is expected to be a quotation) is called with the node as input." } ;
diff --git a/basis/compiler/cfg/intrinsics/simd/simd.factor b/basis/compiler/cfg/intrinsics/simd/simd.factor
index b35efc0d97..06b8dfbfb9 100644
--- a/basis/compiler/cfg/intrinsics/simd/simd.factor
+++ b/basis/compiler/cfg/intrinsics/simd/simd.factor
@@ -164,7 +164,7 @@ PREDICATE: fixnum-vector-rep < int-vector-rep
: ^(sum-vector-2) ( src rep -- dst )
{
[ dupd ^^horizontal-add-vector ]
- [| src rep |
+ [| src rep |
src src rep ^^merge-vector-head :> head
src src rep ^^merge-vector-tail :> tail
head tail rep ^^add-vector
@@ -177,7 +177,7 @@ PREDICATE: fixnum-vector-rep < int-vector-rep
[ dupd ^^horizontal-add-vector ]
[ dupd ^^horizontal-add-vector ] bi
]
- [| src rep |
+ [| src rep |
src src rep ^^merge-vector-head :> head
src src rep ^^merge-vector-tail :> tail
head tail rep ^^add-vector :> src'
@@ -196,7 +196,7 @@ PREDICATE: fixnum-vector-rep < int-vector-rep
[ dupd ^^horizontal-add-vector ]
[ dupd ^^horizontal-add-vector ] tri
]
- [| src rep |
+ [| src rep |
src src rep ^^merge-vector-head :> head
src src rep ^^merge-vector-tail :> tail
head tail rep ^^add-vector :> src'
@@ -223,7 +223,7 @@ PREDICATE: fixnum-vector-rep < int-vector-rep
[ dupd ^^horizontal-add-vector ]
} cleave
]
- [| src rep |
+ [| src rep |
src src rep ^^merge-vector-head :> head
src src rep ^^merge-vector-tail :> tail
head tail rep ^^add-vector :> src'
diff --git a/basis/compiler/cfg/intrinsics/slots/slots-docs.factor b/basis/compiler/cfg/intrinsics/slots/slots-docs.factor
new file mode 100644
index 0000000000..95b1cd4cc4
--- /dev/null
+++ b/basis/compiler/cfg/intrinsics/slots/slots-docs.factor
@@ -0,0 +1,41 @@
+USING: classes classes.builtin compiler.cfg.instructions compiler.tree
+compiler.tree.propagation.info help.markup help.syntax math layouts sequences
+slots.private words ;
+IN: compiler.cfg.intrinsics.slots
+
+HELP: class-tag
+{ $values { "class" class } { "tag/f" "a number or f" } }
+{ $description "Finds the class number for this class if it is a subclass of a builtin class, or " { $link f } " if it isn't." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.intrinsics.slots math prettyprint ;"
+ "complex class-tag ."
+ "7"
+ }
+} ;
+
+HELP: immediate-slot-offset?
+{ $values { "value-info" value-info-state } { "?" "true or false" } }
+{ $description
+ { $link t } " if the value info is a literal " { $link fixnum } " that is small enough to fit into a machine register." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.intrinsics.slots compiler.tree.propagation.info prettyprint ;"
+ "33 immediate-slot-offset? ."
+ "t"
+ }
+} ;
+
+HELP: value-tag
+{ $values { "info" value-info-state } { "n" number } }
+{ $description "Finds the class number for this value-info-states class (an index in the " { $link builtins } " list), or " { $link f } " if it hasn't one." } ;
+
+HELP: emit-write-barrier?
+{ $values { "infos" "a " { $link sequence } " of " { $link value-info-state } " tuples." } { "?" "true or false" } }
+{ $description
+ "Whether a given call to " { $link set-slot } " requires a write barrier to be emitted or not. Write barriers are always needed except when the element to set in the slot is known by the compiler to be " { $link immediate } "." }
+{ $see-also ##write-barrier } ;
+
+HELP: emit-set-slot
+{ $values { "node" node } }
+{ $description "Emits intrinsic code for a " { $link set-slot } " call." } ;
diff --git a/basis/compiler/cfg/linear-scan/linear-scan-docs.factor b/basis/compiler/cfg/linear-scan/linear-scan-docs.factor
new file mode 100644
index 0000000000..5cb837a72a
--- /dev/null
+++ b/basis/compiler/cfg/linear-scan/linear-scan-docs.factor
@@ -0,0 +1,6 @@
+USING: assocs compiler.cfg help.markup help.syntax ;
+IN: compiler.cfg.linear-scan
+
+HELP: admissible-registers
+{ $values { "cfg" cfg } { "regs" assoc } }
+{ $description "Lists all registers usable by the cfg by register class. In general, that's all registers except the frame pointer register that might be used by the cfg for other purposes." } ;
diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor
index c24b52b310..ad97fd48c2 100644
--- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor
+++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor
@@ -779,3 +779,12 @@ H{
}
register-status
] unit-test
+
+{ t } [
+ T{ cfg { frame-pointer? f } } admissible-registers machine-registers =
+] unit-test
+
+{ f } [
+ T{ cfg { frame-pointer? t } } admissible-registers
+ int-regs of frame-reg swap member?
+] unit-test
diff --git a/basis/compiler/cfg/linear-scan/linear-scan.factor b/basis/compiler/cfg/linear-scan/linear-scan.factor
index d3ee2f6fbb..684c232564 100644
--- a/basis/compiler/cfg/linear-scan/linear-scan.factor
+++ b/basis/compiler/cfg/linear-scan/linear-scan.factor
@@ -39,10 +39,8 @@ IN: compiler.cfg.linear-scan
cfg check-numbering ;
: admissible-registers ( cfg -- regs )
- [ machine-registers ] dip
- frame-pointer?>> [
- [ int-regs ] dip [ clone ] map
- [ [ [ frame-reg ] dip remove ] change-at ] keep
+ machine-registers swap frame-pointer?>> [
+ [ [ frame-reg = not ] filter ] assoc-map
] when ;
: linear-scan ( cfg -- cfg' )
diff --git a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals-docs.factor b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals-docs.factor
new file mode 100644
index 0000000000..3b0f0fc5d8
--- /dev/null
+++ b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals-docs.factor
@@ -0,0 +1,10 @@
+USING: help.markup help.syntax ;
+IN: compiler.cfg.linear-scan.live-intervals
+
+HELP:
+{ $values
+ { "vreg" "virtual register" }
+ { "reg-class" "register class" }
+ { "live-interval" live-interval-state }
+}
+{ $description "Creates a new live interval for a virtual register. Initially the range is empty." } ;
diff --git a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor
index 5a9da37d03..ad4ab4fe16 100644
--- a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor
+++ b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor
@@ -162,7 +162,7 @@ M: hairy-clobber-insn compute-live-intervals* ( insn -- )
: handle-live-out ( bb -- )
live-out dup assoc-empty? [ drop ] [
[ from get to get ] dip keys
- [ live-interval add-range ] with with each
+ [ live-interval add-range ] 2with each
] if ;
! A location where all registers have to be spilled
diff --git a/basis/compiler/cfg/linear-scan/resolve/resolve-docs.factor b/basis/compiler/cfg/linear-scan/resolve/resolve-docs.factor
new file mode 100644
index 0000000000..624c13b039
--- /dev/null
+++ b/basis/compiler/cfg/linear-scan/resolve/resolve-docs.factor
@@ -0,0 +1,5 @@
+USING: help.markup help.syntax ;
+IN: compiler.cfg.linear-scan.resolve
+
+HELP: location
+{ $class-description "Represents an abstract location such as a cpu register or a spill slot." } ;
diff --git a/basis/compiler/cfg/linearization/linearization-docs.factor b/basis/compiler/cfg/linearization/linearization-docs.factor
new file mode 100644
index 0000000000..934a574978
--- /dev/null
+++ b/basis/compiler/cfg/linearization/linearization-docs.factor
@@ -0,0 +1,19 @@
+USING: compiler.cfg compiler.cfg.linearization compiler.codegen help.markup
+help.syntax kernel macros math sequences ;
+IN: compiler.cfg.linearization
+
+HELP: linearization-order
+{ $values
+ { "cfg" cfg }
+ { "bbs" sequence }
+}
+{ $description "Lists the basic blocks in linearization order. That is, the order in which they will be written in the generated assembly code." }
+{ $see-also generate } ;
+
+HELP: block-number
+{ $values { "bb" basic-block } { "n" integer } }
+{ $description "Retrieves this blocks block number. Must not be called before " { $link number-blocks } "." } ;
+
+HELP: number-blocks
+{ $values { "bbs" sequence } }
+{ $description "Associate each block with a block number and save the result in the " { $link numbers } " map." } ;
diff --git a/basis/compiler/cfg/predecessors/predecessors-docs.factor b/basis/compiler/cfg/predecessors/predecessors-docs.factor
new file mode 100644
index 0000000000..1977d727fb
--- /dev/null
+++ b/basis/compiler/cfg/predecessors/predecessors-docs.factor
@@ -0,0 +1,6 @@
+USING: compiler.cfg help.markup help.syntax kernel ;
+IN: compiler.cfg.predecessors
+
+HELP: needs-predecessors
+{ $values { "cfg" cfg } { "cfg'" cfg } }
+{ $description "Computes predecessor info for the cfg unless it already is up-to-date." } ;
diff --git a/basis/compiler/cfg/registers/registers-docs.factor b/basis/compiler/cfg/registers/registers-docs.factor
new file mode 100644
index 0000000000..dddba48334
--- /dev/null
+++ b/basis/compiler/cfg/registers/registers-docs.factor
@@ -0,0 +1,25 @@
+USING: compiler.cfg.instructions cpu.architecture help.markup help.syntax
+math ;
+IN: compiler.cfg.registers
+
+HELP: next-vreg
+{ $values { "vreg" number } }
+{ $description "Creates a new virtual register identifier." }
+{ $notes "This word cannot be called after representation selection has run; use " { $link next-vreg-rep } " in that case." } ;
+
+HELP: rep-of
+{ $values { "vreg" number } { "rep" representation } }
+{ $description "Gets the representation for a virtual register. This word cannot be called before representation selection has run; use any-rep for " { $link ##copy } " instructions and so on." }
+{ $notes "Throws " { $link bad-vreg } " if the representation for the vreg isn't known." } ;
+
+HELP: set-rep-of
+{ $values { "rep" representation } { "vreg" number } }
+{ $description "Sets the representation for a virtual register." } ;
+
+HELP: next-vreg-rep
+{ $values { "rep" representation } { "vreg" number } }
+{ $description "Creates a new virtual register identifier and sets its representation." }
+{ $notes "This word cannot be called before representation selection has run; use " { $link next-vreg } " in that case." } ;
+
+HELP: loc
+{ $class-description "Represents a location on the stack. 'n' is an index starting from the top of the stack going down. So 0 is the top of the stack, 1 is what would be the top of the stack after a 'drop', and so on. It has two subclasses, " { $link ds-loc } " for data stack location and " { $link rs-loc } " for locations on the retain stack." } ;
diff --git a/basis/compiler/cfg/registers/registers.factor b/basis/compiler/cfg/registers/registers.factor
index d70d9316a2..6b93b46be6 100644
--- a/basis/compiler/cfg/registers/registers.factor
+++ b/basis/compiler/cfg/registers/registers.factor
@@ -7,8 +7,6 @@ IN: compiler.cfg.registers
SYMBOL: vreg-counter
: next-vreg ( -- vreg )
- ! This word cannot be called AFTER representation selection has run;
- ! use next-vreg-rep in that case
vreg-counter counter ;
SYMBOL: representations
@@ -16,22 +14,14 @@ SYMBOL: representations
ERROR: bad-vreg vreg ;
: rep-of ( vreg -- rep )
- ! This word cannot be called BEFORE representation selection has run;
- ! use any-rep for ##copy instructions and so on
representations get ?at [ bad-vreg ] unless ;
: set-rep-of ( rep vreg -- )
representations get set-at ;
: next-vreg-rep ( rep -- vreg )
- ! This word cannot be called BEFORE representation selection has run;
- ! use next-vreg in that case
next-vreg [ set-rep-of ] keep ;
-! Stack locations -- 'n' is an index starting from the top of the stack
-! going down. So 0 is the top of the stack, 1 is what would be the top
-! of the stack after a 'drop', and so on.
-
! ##inc-d and ##inc-r affect locations as follows. Location D 0 before
! an ##inc-d 1 becomes D 1 after ##inc-d 1.
TUPLE: loc { n integer read-only } ;
diff --git a/basis/compiler/cfg/rpo/rpo-docs.factor b/basis/compiler/cfg/rpo/rpo-docs.factor
new file mode 100644
index 0000000000..22f91bdc50
--- /dev/null
+++ b/basis/compiler/cfg/rpo/rpo-docs.factor
@@ -0,0 +1,25 @@
+USING: compiler.cfg help.markup help.syntax quotations sequences ;
+IN: compiler.cfg.rpo
+
+HELP: number-blocks
+{ $values { "blocks" sequence } }
+{ $description "Initializes the " { $slot "number" } " slot of each " { $link basic-block } "." }
+{ $examples
+ { $example
+ "USING: accessors compiler.cfg compiler.cfg.rpo kernel prettyprint sequences ;"
+ "10 [ ] replicate dup number-blocks [ number>> ] map ."
+ "{ 9 8 7 6 5 4 3 2 1 0 }"
+ }
+} ;
+
+HELP: post-order
+{ $values { "cfg" cfg } { "blocks" sequence } }
+{ $description "Lists the blocks in the cfg sorted in descending order on the " { $slot "number" } " slot. The blocks are first numbered if they haven't already been." } ;
+
+HELP: each-basic-block
+{ $values { "cfg" cfg } { "quot" quotation } }
+{ $description "Applies a quotation to each basic block in the cfg." } ;
+
+HELP: optimize-basic-block
+{ $values { "bb" basic-block } { "quot" quotation } }
+{ $description "Performs one " { $link simple-optimization } " step. The quotation takes the instructions of the basic block and returns them back in an optimized form." } ;
diff --git a/basis/compiler/cfg/save-contexts/save-contexts-docs.factor b/basis/compiler/cfg/save-contexts/save-contexts-docs.factor
new file mode 100644
index 0000000000..e66bf53554
--- /dev/null
+++ b/basis/compiler/cfg/save-contexts/save-contexts-docs.factor
@@ -0,0 +1,17 @@
+USING: compiler.cfg compiler.cfg.instructions help.markup help.syntax ;
+IN: compiler.cfg.save-contexts
+
+HELP: insert-save-contexts
+{ $values { "cfg" cfg } { "cfg'" cfg } }
+{ $description "Inserts " { $link ##save-context } " instructions in each " { $link basic-block } " in the cfg that needs them. Save contexts are needed after instructions that modify the context, or instructions that read parameter registers." }
+{ $see-also needs-save-context? } ;
+
+HELP: bb-needs-save-context?
+{ $values { "bb" basic-block } { "?" "a boolean" } }
+{ $description "Whether to insert a " { $link ##save-context } " instruction in the block or not." }
+{ $see-also needs-save-context? } ;
+
+HELP: needs-save-context?
+{ $values { "insn" "an instruction" } { "?" "a boolean" } }
+{ $description "Whether the given instruction needs to be preceeded by a " { $link ##save-context } " instruction or not. Only instructions that can allocate memory mandates save contexts." }
+{ $see-also gc-map-insn } ;
diff --git a/basis/compiler/cfg/save-contexts/save-contexts.factor b/basis/compiler/cfg/save-contexts/save-contexts.factor
index f51499d791..0622ca7201 100644
--- a/basis/compiler/cfg/save-contexts/save-contexts.factor
+++ b/basis/compiler/cfg/save-contexts/save-contexts.factor
@@ -12,7 +12,7 @@ GENERIC: needs-save-context? ( insn -- ? )
M: gc-map-insn needs-save-context? drop t ;
M: insn needs-save-context? drop f ;
-: bb-needs-save-context? ( insn -- ? )
+: bb-needs-save-context? ( bb -- ? )
{
[ kill-block?>> not ]
[ instructions>> [ needs-save-context? ] any? ]
diff --git a/basis/compiler/cfg/scheduling/scheduling-docs.factor b/basis/compiler/cfg/scheduling/scheduling-docs.factor
new file mode 100644
index 0000000000..5a61168c86
--- /dev/null
+++ b/basis/compiler/cfg/scheduling/scheduling-docs.factor
@@ -0,0 +1,10 @@
+USING: compiler.cfg compiler.cfg.height help.markup help.syntax sequences ;
+IN: compiler.cfg.scheduling
+
+HELP: number-insns
+{ $values { "insns" sequence } }
+{ $description "Assigns a sequence number to the " { $slot "insn#" } " slot of each instruction in the sequence." } ;
+
+HELP: schedule-instructions
+{ $values { "cfg" cfg } { "cfg'" cfg } }
+{ $description "Performs a instruction scheduling optimization pass over the CFG to attempt to reduce the number of spills. The step must be performed after " { $link normalize-height } " or else invalid peeks might be inserted into the CFG." } ;
diff --git a/basis/compiler/cfg/stack-frame/stack-frame-docs.factor b/basis/compiler/cfg/stack-frame/stack-frame-docs.factor
new file mode 100644
index 0000000000..f284ce2b7c
--- /dev/null
+++ b/basis/compiler/cfg/stack-frame/stack-frame-docs.factor
@@ -0,0 +1,10 @@
+USING: help.markup help.syntax ;
+IN: compiler.cfg.stack-frame
+
+HELP: stack-frame
+{ $class-description "Counts of, among other things, how much stack a compiled word needs. It has the following slots:"
+ { $table
+ { { $slot "total-size" } { "Total size of the stack frame." } }
+ { { $slot "spill-area-size" } { "Number of bytes requires for all spill slots." } }
+ }
+} ;
diff --git a/basis/compiler/cfg/stacks/height/height-docs.factor b/basis/compiler/cfg/stacks/height/height-docs.factor
new file mode 100644
index 0000000000..59f53706b6
--- /dev/null
+++ b/basis/compiler/cfg/stacks/height/height-docs.factor
@@ -0,0 +1,12 @@
+USING: compiler.cfg compiler.cfg.registers help.markup help.syntax math ;
+IN: compiler.cfg.stacks.height
+
+HELP: record-stack-heights
+{ $values { "ds-height" number } { "rs-height" number } { "bb" basic-block } }
+{ $description "Does something." } ;
+
+HELP: ds-heights
+{ $var-description "Assoc that records the data stacks height at the entry of each " { $link basic-block } "." } ;
+
+HELP: rs-heights
+{ $var-description "Assoc that records the retain stacks height at the entry of each " { $link basic-block } "." } ;
diff --git a/basis/compiler/cfg/stacks/local/local-docs.factor b/basis/compiler/cfg/stacks/local/local-docs.factor
new file mode 100644
index 0000000000..c24da16e78
--- /dev/null
+++ b/basis/compiler/cfg/stacks/local/local-docs.factor
@@ -0,0 +1,33 @@
+USING: compiler.cfg compiler.cfg.registers help.markup help.syntax ;
+IN: compiler.cfg.stacks.local
+
+HELP: current-height
+{ $class-description "A tuple used to keep track of the heights of the data and retain stacks in a " { $link basic-block } " The idea is that if the stack change instructions are tracked, then multiple changes can be folded into one. It has the following slots:"
+ { $table
+ { { $slot "d" } { "Current datastack height." } }
+ { { $slot "r" } { "Current retainstack height." } }
+ { { $slot "emit-d" } { "Queued up datastack height change." } }
+ { { $slot "emit-r" } { "Queued up retainstack height change." } }
+ }
+} ;
+
+HELP: translate-local-loc
+{ $values { "loc" loc } { "loc'" loc } }
+{ $description "Translates an absolute stack location to one that is relative to the current stacks height as given in " { $link current-height } "." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.stacks.local compiler.cfg.registers compiler.cfg.debugger namespaces prettyprint ;"
+ "T{ current-height { d 3 } } current-height set D 7 translate-local-loc ."
+ "D 4"
+ }
+} ;
+
+HELP: emit-height-changes
+{ $description "Emits stack height change instructions to the CFG being built. This is done when a " { $link basic-block } " is begun or ended." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.stacks.local make namespaces prettyprint ;"
+ "T{ current-height { emit-d 4 } { emit-r -2 } } current-height set [ emit-height-changes ] { } make ."
+ "{ T{ ##inc-d { n 4 } } T{ ##inc-r { n -2 } } }"
+ }
+} ;
diff --git a/basis/compiler/cfg/stacks/stacks-docs.factor b/basis/compiler/cfg/stacks/stacks-docs.factor
new file mode 100644
index 0000000000..9baf0de036
--- /dev/null
+++ b/basis/compiler/cfg/stacks/stacks-docs.factor
@@ -0,0 +1,22 @@
+USING: compiler.cfg.stacks.local help.markup help.syntax math sequences ;
+IN: compiler.cfg.stacks
+
+HELP: begin-stack-analysis
+{ $description "Initializes a set of variables related to stack analysis of Factor words." }
+{ $see-also current-height } ;
+
+HELP: adjust-d
+{ $values { "n" number } }
+{ $description "Changes the height of the current data stack." } ;
+
+HELP: rs-store
+{ $values { "vregs" "a " { $link sequence } " of vregs." } }
+{ $description "Stores one or more virtual register values on the retain stack. This modifies the " { $link current-height } " dynamic variable." } ;
+
+HELP: 2inputs
+{ $values { "vreg1" "a vreg" } { "vreg2" "a vreg" } }
+{ $description "Lifts the two topmost values from the datastack and stores them in virtual registers. The datastacks height is adjusted afterwards." } ;
+
+HELP: 3inputs
+{ $values { "vreg1" "a vreg" } { "vreg2" "a vreg" } { "vreg3" "a vreg" } }
+{ $description "Lifts the three topmost values from the datastack and stores them in virtual registers. The datastacks height is adjusted afterwards." } ;
diff --git a/basis/compiler/cfg/stacks/uninitialized/uninitialized-docs.factor b/basis/compiler/cfg/stacks/uninitialized/uninitialized-docs.factor
new file mode 100644
index 0000000000..a39d4cfdc9
--- /dev/null
+++ b/basis/compiler/cfg/stacks/uninitialized/uninitialized-docs.factor
@@ -0,0 +1,6 @@
+USING: compiler.cfg compiler.cfg.instructions help.markup help.syntax ;
+IN: compiler.cfg.stacks.uninitialized
+
+HELP: compute-uninitialized-sets
+{ $values { "cfg" cfg } }
+{ $description "Runs the uninitialized compiler pass. The pass serves two purposes; if a " { $link ##peek } " reads an uninitialized stack location, then an error is thrown. Second, it assigns the " { $slot "scrub-d" } " and " { $slot "scrub-r" } " slots of all " { $link gc-map } " instances in the cfg." } ;
diff --git a/basis/compiler/cfg/stacks/vacant/vacant-docs.factor b/basis/compiler/cfg/stacks/vacant/vacant-docs.factor
new file mode 100644
index 0000000000..1bab1d594a
--- /dev/null
+++ b/basis/compiler/cfg/stacks/vacant/vacant-docs.factor
@@ -0,0 +1,39 @@
+USING: compiler.cfg.instructions help.markup help.syntax sequences strings ;
+IN: compiler.cfg.stacks.vacant
+
+ARTICLE: "compiler.cfg.stacks.vacant" "Uninitialized/overinitialized stack location analysis"
+"Consider the following sequence of instructions:"
+{ $code
+ "##inc-d 2"
+ "..."
+ "##allot"
+ "##replace ... D 0"
+ "##replace ... D 1"
+}
+"The GC check runs before stack locations 0 and 1 have been initialized, and so the GC needs to scrub them so that they don't get traced. This is achieved by computing uninitialized locations with a dataflow analysis, and recording the information in GC maps. The call_frame_slot_visitor object in vm/slot_visitor.hpp reads this information from GC maps and performs the scrubbing." ;
+
+HELP: initial-state
+{ $description "Initially the stack bottom is at 0 for both the data and retain stacks and no replaces have been registered." } ;
+
+HELP: vacant>bits
+{ $values
+ { "vacant" "sequence of uninitialized stack locations" }
+ { "bits" "sequence of 1:s and 0:s" }
+}
+{ $description "Converts a sequence of uninitialized stack locations to the pattern of 1:s and 0:s that can be put in the " { $slot "scrub-d" } " and " { $slot "scrub-r" } " slots of a " { $link gc-map } ". 0:s are uninitialized locations and 1:s are initialized." }
+{ $examples
+ { $example
+ "USING: compiler.cfg.stacks.vacant prettyprint ;"
+ "{ 0 1 3 } vacant>bits ."
+ "{ 0 0 1 0 }"
+ }
+} ;
+
+HELP: overinitialized>bits
+{ $values
+ { "overinitialized" "sequence of overinitialized stack locations" }
+ { "bits" "sequence of 1:s and 0:s" }
+}
+{ $description "Converts a sequence of overinitialized stack locations to the pattern of 1:s and 0:s that can be put in the " { $slot "check-d" } " and " { $slot "check-r" } " slots of a " { $link gc-map } ". 0:s are initialized locations and 0:s are empty ones. First element is stack location -1,second -2 and so on." } ;
+
+ABOUT: "compiler.cfg.stacks.vacant"
diff --git a/basis/compiler/cfg/stacks/vacant/vacant-tests.factor b/basis/compiler/cfg/stacks/vacant/vacant-tests.factor
new file mode 100644
index 0000000000..b15ebedda3
--- /dev/null
+++ b/basis/compiler/cfg/stacks/vacant/vacant-tests.factor
@@ -0,0 +1,246 @@
+USING: accessors arrays assocs compiler.cfg
+compiler.cfg.dataflow-analysis.private compiler.cfg.instructions
+compiler.cfg.linearization compiler.cfg.registers compiler.cfg.stacks.vacant
+kernel math sequences sorting tools.test vectors ;
+IN: compiler.cfg.stacks.vacant.tests
+
+! Utils
+: create-block ( insns n -- bb )
+ swap >>number swap >>instructions ;
+
+: block>cfg ( bb -- cfg )
+ cfg new swap >>entry ;
+
+: create-cfg ( insns -- cfg )
+ 0 create-block block>cfg ;
+
+: output-stack-map ( cfg -- map )
+ vacant-analysis run-dataflow-analysis
+ nip [ [ number>> ] dip ] assoc-map >alist natural-sort last second ;
+
+! Initially both the d and r stacks are empty.
+{
+ { { 0 { } } { 0 { } } }
+} [ V{ } create-cfg output-stack-map ] unit-test
+
+! Raise d stack.
+{
+ { { 1 { } } { 0 { } } }
+} [ V{ T{ ##inc-d f 1 } } create-cfg output-stack-map ] unit-test
+
+! Raise r stack.
+{
+ { { 0 { } } { 1 { } } }
+} [ V{ T{ ##inc-r f 1 } } create-cfg output-stack-map ] unit-test
+
+! Uninitialized peeks
+[
+ V{
+ T{ ##inc-d f 1 }
+ T{ ##peek { dst 0 } { loc D 0 } }
+ } create-cfg
+ compute-vacant-sets
+] [ vacant-peek? ] must-fail-with
+
+[
+ V{
+ T{ ##inc-r f 1 }
+ T{ ##peek { dst 0 } { loc R 0 } }
+ } create-cfg
+ compute-vacant-sets
+] [ vacant-peek? ] must-fail-with
+
+
+! Here the peek refers to a parameter of the word.
+[ ] [
+ V{
+ T{ ##peek { dst 0 } { loc D 0 } }
+ } create-cfg
+ compute-vacant-sets
+] unit-test
+
+! Replace -1 then peek is ok.
+[ ] [
+ V{
+ T{ ##replace { src 10 } { loc D -1 } }
+ T{ ##peek { dst 0 } { loc D -1 } }
+ } create-cfg
+ compute-vacant-sets
+] unit-test
+
+! Replace -1, then gc. Peek is ok here because the -1 should be
+! checked.
+{ { 0 } } [
+ V{
+ T{ ##replace { src 10 } { loc D -1 } }
+ T{ ##alien-invoke { gc-map T{ gc-map { scrub-d { } } } } }
+ T{ ##peek { dst 0 } { loc D -1 } }
+ }
+ [ create-cfg compute-vacant-sets ]
+ [ second gc-map>> check-d>> ] bi
+] unit-test
+
+! Should be ok because the value was at 0 when the gc ran.
+{ { -1 { -1 } } } [
+ V{
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##alien-invoke { gc-map T{ gc-map { scrub-d { } } } } }
+ T{ ##inc-d f -1 }
+ T{ ##peek { dst 0 } { loc D -1 } }
+ } create-cfg output-stack-map first
+] unit-test
+
+! Should not be ok because the value wasn't initialized when gc ran.
+[
+ V{
+ T{ ##inc-d f 1 }
+ T{ ##alien-invoke { gc-map T{ gc-map { scrub-d { } } } } }
+ T{ ##peek { dst 0 } { loc D 0 } }
+ } create-cfg
+ compute-vacant-sets
+] [ vacant-peek? ] must-fail-with
+
+! visit-insn should set the gc info.
+{ { 0 0 } { } } [
+ { { 2 { } } { 0 { } } }
+ T{ ##alien-invoke { gc-map T{ gc-map } } }
+ [ visit-insn drop ] keep gc-map>> [ scrub-d>> ] [ scrub-r>> ] bi
+] unit-test
+
+{
+ { { 0 { } } { 0 { } } }
+} [
+ V{ T{ ##safepoint } T{ ##prologue } T{ ##branch } }
+ create-cfg output-stack-map
+] unit-test
+
+{
+ { { 0 { 0 1 2 } } { 0 { } } }
+} [
+ V{
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##replace { src 10 } { loc D 1 } }
+ T{ ##replace { src 10 } { loc D 2 } }
+ } create-cfg output-stack-map
+] unit-test
+
+{
+ { { 1 { 1 0 } } { 0 { } } }
+} [
+ V{
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##inc-d f 1 }
+ T{ ##replace { src 10 } { loc D 0 } }
+ } create-cfg output-stack-map
+] unit-test
+
+{
+ { 0 { 0 -1 } }
+} [
+ V{
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##inc-d f 1 }
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##inc-d f -1 }
+ } create-cfg output-stack-map first
+] unit-test
+
+{
+ { 0 { -1 } }
+} [
+ V{
+ T{ ##inc-d f 1 }
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##inc-d f -1 }
+ } create-cfg output-stack-map first
+] unit-test
+
+{
+ { { { } { 0 0 0 } } { { } { 0 } } }
+} [
+ { { 4 { 3 2 1 -3 0 -2 -1 } } { 0 { -1 } } } state>gc-data
+] unit-test
+
+! ##call clears the overinitialized slots.
+{
+ { -1 { } }
+} [
+ V{
+ T{ ##replace { src 10 } { loc D 0 } }
+ T{ ##inc-d f -1 }
+ T{ ##call }
+ } create-cfg output-stack-map first
+] unit-test
+
+: cfg1 ( -- cfg )
+ V{
+ T{ ##inc-d f 1 }
+ T{ ##replace { src 10 } { loc D 0 } }
+ } 0 create-block
+ V{
+ T{ ##peek { dst 37 } { loc D 0 } }
+ T{ ##inc-d f -1 }
+ } 1 create-block
+ 1vector >>successors block>cfg ;
+
+{ { 0 { -1 } } } [ cfg1 output-stack-map first ] unit-test
+
+: connect-bbs ( from to -- )
+ [ [ successors>> ] dip suffix! drop ]
+ [ predecessors>> swap suffix! drop ] 2bi ;
+
+: make-edges ( block-map edgelist -- )
+ [ [ of ] with map first2 connect-bbs ] with each ;
+
+! Same cfg structure as the bug1021:run-test word but with
+! non-datastack instructions mostly omitted.
+: bug1021-cfg ( -- cfg )
+ {
+ { 0 V{ T{ ##safepoint } T{ ##prologue } T{ ##branch } } }
+ {
+ 1 V{
+ T{ ##inc-d f 2 }
+ T{ ##replace { src 0 } { loc D 1 } }
+ T{ ##replace { src 0 } { loc D 0 } }
+ }
+ }
+ {
+ 2 V{
+ T{ ##call { word } }
+ }
+ }
+ {
+ 3 V{
+ T{ ##inc-d f 2 }
+ T{ ##peek { dst 0 } { loc D 2 } }
+ T{ ##peek { dst 0 } { loc D 3 } }
+ T{ ##replace { src 0 } { loc D 2 } }
+ T{ ##replace { src 0 } { loc D 3 } }
+ T{ ##replace { src 0 } { loc D 1 } }
+ }
+ }
+ {
+ 8 V{
+ T{ ##inc-d f 3 }
+ T{ ##peek { dst 0 } { loc D 5 } }
+ T{ ##replace { src 0 } { loc D 0 } }
+ T{ ##replace { src 0 } { loc D 3 } }
+ T{ ##peek { dst 0 } { loc D 4 } }
+ T{ ##replace { src 0 } { loc D 1 } }
+ T{ ##replace { src 0 } { loc D 2 } }
+ }
+ }
+ {
+ 10 V{
+
+ T{ ##inc-d f -3 }
+ T{ ##peek { dst 0 } { loc D -3 } }
+ T{ ##alien-invoke { gc-map T{ gc-map { scrub-d { } } } } }
+ }
+ }
+ } [ over create-block ] assoc-map dup
+ { { 0 1 } { 1 2 } { 2 3 } { 3 8 } { 8 10 } } make-edges 0 of block>cfg ;
+
+{ { 4 { 3 2 1 -3 0 -2 -1 } } } [
+ bug1021-cfg output-stack-map first
+] unit-test
diff --git a/basis/compiler/cfg/stacks/vacant/vacant.factor b/basis/compiler/cfg/stacks/vacant/vacant.factor
new file mode 100644
index 0000000000..6a6e859acc
--- /dev/null
+++ b/basis/compiler/cfg/stacks/vacant/vacant.factor
@@ -0,0 +1,96 @@
+USING: accessors arrays assocs classes.tuple compiler.cfg.dataflow-analysis
+compiler.cfg.instructions compiler.cfg.registers fry kernel math math.order
+sequences sets ;
+IN: compiler.cfg.stacks.vacant
+
+! Utils
+: write-slots ( tuple values slots -- )
+ [ execute( x y -- z ) ] 2each drop ;
+
+! Operations on the stack info
+: register-write ( n stack -- stack' )
+ first2 rot suffix members 2array ;
+
+: adjust-stack ( n stack -- stack' )
+ first2 pick '[ _ + ] map [ + ] dip 2array ;
+
+: read-ok? ( n stack -- ? )
+ [ first >= ] [ second in? ] 2bi or ;
+
+: stack>vacant ( stack -- seq )
+ first2 [ 0 max iota ] dip diff ;
+
+: vacant>bits ( vacant -- bits )
+ [ { } ] [
+ dup supremum 1 + 1
+ [ '[ _ 0 -rot set-nth ] each ] keep
+ ] if-empty ;
+
+: stack>overinitialized ( stack -- seq )
+ second [ 0 < ] filter ;
+
+: overinitialized>bits ( overinitialized -- bits )
+ [ neg 1 - ] map vacant>bits ;
+
+: stack>scrub-and-check ( stack -- pair )
+ [ stack>vacant vacant>bits ]
+ [ stack>overinitialized overinitialized>bits ] bi 2array ;
+
+! Operations on the analysis state
+: state>gc-data ( state -- gc-data )
+ [ stack>scrub-and-check ] map ;
+
+CONSTANT: initial-state { { 0 { } } { 0 { } } }
+
+: insn>location ( insn -- n ds? )
+ loc>> [ n>> ] [ ds-loc? ] bi ;
+
+: visit-replace ( state insn -- state' )
+ [ first2 ] dip insn>location
+ [ rot register-write swap ] [ swap register-write ] if 2array ;
+
+ERROR: vacant-peek insn ;
+
+: peek-loc-ok? ( state insn -- ? )
+ insn>location 0 1 ? rot nth read-ok? ;
+
+GENERIC: visit-insn ( state insn -- state' )
+
+M: ##inc-d visit-insn ( state insn -- state' )
+ n>> swap first2 [ adjust-stack ] dip 2array ;
+
+M: ##inc-r visit-insn ( state insn -- state' )
+ n>> swap first2 swapd adjust-stack 2array ;
+
+M: ##replace-imm visit-insn visit-replace ;
+M: ##replace visit-insn visit-replace ;
+
+M: ##peek visit-insn ( state insn -- state' )
+ 2dup peek-loc-ok? [ drop ] [ vacant-peek ] if ;
+
+M: ##call visit-insn ( state insn -- state' )
+ ! After a word call, we can't trust any overinitialized locations
+ ! to contain valid pointers anymore.
+ drop [ first2 [ 0 >= ] filter 2array ] map ;
+
+: set-gc-map ( state gc-map -- )
+ swap state>gc-data concat
+ { >>scrub-d >>check-d >>scrub-r >>check-r } write-slots ;
+
+M: gc-map-insn visit-insn ( state insn -- state' )
+ dupd gc-map>> set-gc-map ;
+
+M: insn visit-insn ( state insn -- state' )
+ drop ;
+
+FORWARD-ANALYSIS: vacant
+
+M: vacant-analysis transfer-set ( in-set bb dfa -- out-set )
+ drop instructions>> swap [ visit-insn ] reduce ;
+
+M: vacant-analysis ignore-block? ( bb dfa -- ? )
+ 2drop f ;
+
+! Picking the first means that a block will only be analyzed once.
+M: vacant-analysis join-sets ( sets bb dfa -- set )
+ 2drop [ initial-state ] [ first ] if-empty ;
diff --git a/basis/compiler/codegen/codegen-docs.factor b/basis/compiler/codegen/codegen-docs.factor
new file mode 100644
index 0000000000..15e47ceb22
--- /dev/null
+++ b/basis/compiler/codegen/codegen-docs.factor
@@ -0,0 +1,97 @@
+USING: alien byte-arrays compiler.cfg compiler.codegen.labels
+compiler.codegen.relocation hashtables help.markup help.syntax literals make
+multiline sequences ;
+IN: compiler.codegen
+
+<<
+STRING: generate-ex
+USING: compiler.cfg.debugger io prettyprint ;
+[ "hello\n" write ] test-regs first dup cfg set generate [ . ] [ 4 swap nth disassemble ] bi
+;
+
+STRING: generate-ex-answer
+{
+ { }
+ { "hello\n" output-stream assoc-stack stream-write }
+ B{
+ 6 0 0 242 24 0 0 96 49 0 0 96 58 0 0 34 64 0 0 242 80 0
+ 0 50
+ }
+ { }
+ B{
+ 137 5 0 0 0 0 72 131 236 8 73 131 198 24 72 185 0 0 0 0
+ 0 0 0 0 73 137 78 240 73 139 77 0 72 139 73 64 73 137 14
+ 72 185 0 0 0 0 0 0 0 0 73 137 78 248 232 0 0 0 0 137 5 0
+ 0 0 0 72 131 196 8 72 141 29 5 0 0 0 233 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0
+ }
+ 16
+}
+0000000001cc4ca0: 890500000000 mov [rip], eax
+0000000001cc4ca6: 4883ec08 sub rsp, 0x8
+0000000001cc4caa: 4983c618 add r14, 0x18
+0000000001cc4cae: 48b90000000000000000 mov rcx, 0x0
+0000000001cc4cb8: 49894ef0 mov [r14-0x10], rcx
+0000000001cc4cbc: 498b4d00 mov rcx, [r13]
+0000000001cc4cc0: 488b4940 mov rcx, [rcx+0x40]
+0000000001cc4cc4: 49890e mov [r14], rcx
+0000000001cc4cc7: 48b90000000000000000 mov rcx, 0x0
+0000000001cc4cd1: 49894ef8 mov [r14-0x8], rcx
+0000000001cc4cd5: e800000000 call 0x1cc4cda
+0000000001cc4cda: 890500000000 mov [rip], eax
+0000000001cc4ce0: 4883c408 add rsp, 0x8
+0000000001cc4ce4: 488d1d05000000 lea rbx, [rip+0x5]
+0000000001cc4ceb: e900000000 jmp 0x1cc4cf0
+0000000001cc4cf0: 0000 add [rax], al
+0000000001cc4cf2: 0000 add [rax], al
+0000000001cc4cf4: 0000 add [rax], al
+0000000001cc4cf6: 0000 add [rax], al
+0000000001cc4cf8: 0000 add [rax], al
+0000000001cc4cfa: 0000 add [rax], al
+0000000001cc4cfc: 0000 add [rax], al
+0000000001cc4cfe: 0000 add [rax], al
+;
+>>
+
+HELP: labels
+{ $description { $link hashtable } " of mappings from " { $link basic-block } " to " { $link label } "." } ;
+
+HELP: lookup-label
+{ $values { "bb" basic-block } { "label" label } }
+{ $description "Sets and gets a " { $link label } " for the " { $link basic-block } ". The labels are used to generate branch instructions from one block to another." } ;
+
+HELP: generate-block
+{ $values { "bb" basic-block } }
+{ $description "Emits machine code to the current " { $link make } " sequence for one basic block." } ;
+
+HELP: generate
+{ $values { "cfg" cfg } { "code" sequence } }
+{ $description "Generates assembly code for the given cfg. The output " { $link sequence } " has six items with the following interpretations:"
+ { $list
+ { "The first element is a sequence of alien function symbols and " { $link dll } "s used by the cfg interleaved. That is, the " { $link parameter-table } "." }
+ { "The second item is the " { $link literal-table } "." }
+ { "The third item is the relocation table as a " { $link byte-array } "." }
+ { "The fourth item is the " { $link label-table } "." }
+ { "The fifth item is the generated assembly code as a " { $link byte-array } ". It still contains unresolved crossreferences." }
+ "The sixth item is the size of the stack frame in bytes."
+ }
+}
+{ $examples
+ "A small quotation is compiled and then disassembled:"
+ { $unchecked-example $[ generate-ex generate-ex-answer ] }
+} ;
+
+HELP: useless-branch?
+{ $values
+ { "bb" basic-block }
+ { "successor" "The successor block of bb" }
+ { "?" "A boolean value" }
+}
+{ $description "If successor immediately follows bb in the linearization order, then a branch is is not needed." } ;
+
+HELP: init-fixup
+{ $description "Initializes variables needed for fixup." } ;
+
+HELP: check-fixup
+{ $values { "seq" "a " { $link sequence } " of generated machine code." } }
+{ $description "Used by " { $link with-fixup } " to ensure that the generated machine code is properly aligned." } ;
diff --git a/basis/compiler/codegen/gc-maps/gc-maps-docs.factor b/basis/compiler/codegen/gc-maps/gc-maps-docs.factor
new file mode 100644
index 0000000000..bd1d3ec0aa
--- /dev/null
+++ b/basis/compiler/codegen/gc-maps/gc-maps-docs.factor
@@ -0,0 +1,73 @@
+USING: bit-arrays byte-arrays compiler.cfg.instructions help.markup help.syntax
+kernel math ;
+IN: compiler.codegen.gc-maps
+
+ARTICLE: "compiler.codegen.gc-maps" "GC maps"
+"The " { $vocab-link "compiler.codegen.gc-maps" } " handles generating code for keeping track of garbage collection maps. Every code block either ends with:"
+{ $list "uint 0" }
+"or"
+{ $list
+ {
+ "bitmap, byte aligned, five subsequences:"
+ { $list
+ "scrubbed data stack locations"
+ "scrubbed retain stack locations"
+ "checked data stack locations"
+ "checked retain stack locations"
+ "GC root spill slots"
+ }
+ }
+ "uint[] base pointers"
+ "uint[] return addresses"
+ "uint largest scrubbed data stack location"
+ "uint largest scrubbed retain stack location"
+ "uint largest checked data stack location"
+ "uint largest checked retain stack location"
+ "uint largest GC root spill slot"
+ "uint largest derived root spill slot"
+ "int number of return addresses"
+} ;
+
+HELP: emit-gc-info-bitmaps
+{ $values { "scrub-and-check-counts" "counts of the five different types of gc checks" } }
+{ $description "Emits the scrub location data in all gc-maps registered in the " { $link gc-maps } " variable to the make sequence being created. The result is a concatenation of all datastack scrub locations, retainstack scrub locations and gc root locations converted into a byte-array. Given that byte-array and knowledge of the number of scrub locations, the original gc-map can be reconstructed." } ;
+
+HELP: emit-scrub
+{ $values
+ { "seqs" "a sequence of sequences of 0/1" }
+ { "n" "length of the longest sequence" }
+}
+{ $description "Emits a space-efficient " { $link bit-array } " to the make sequence being created. The outputted array will be of length n times the number of sequences given. Each group of n elements in the array contains true values if the stack location should be scrubbed, and false if it shouldn't." }
+{ $examples
+ { $example
+ "USING: bit-arrays byte-arrays compiler.codegen.gc-maps make prettyprint ;"
+ "[ { B{ 0 } B{ 0 } B{ 1 1 1 0 } } emit-scrub ] ?{ } make . ."
+ "?{ t f f f t f f f f f f t }\n4"
+ }
+} ;
+
+{ emit-gc-info-bitmaps emit-scrub } related-words
+
+HELP: emit-uint
+{ $values { "n" integer } }
+{ $description "Emits an unsigned 32 bit integer to the make sequence being created. The word takes care of ensuring that the byte order is correct for the current machine." }
+{ $examples
+ { $example
+ "USING: compiler.codegen.gc-maps make prettyprint ;"
+ "[ 0xffff emit-uint ] B{ } make ."
+ "B{ 255 255 0 0 }"
+ }
+} ;
+
+HELP: gc-maps
+{ $var-description "Variable that holds a sequence of " { $link gc-map } " tuples." } ;
+
+HELP: gc-map-needed?
+{ $values { "gc-map/f" "a " { $link gc-map } " or f" } { "?" "a boolean" } }
+{ $description "If all slots in the gc-map are empty, then it doesn't need to be emitted." } ;
+
+HELP: serialize-gc-maps
+{ $values { "byte-array" byte-array } }
+{ $description "Serializes the gc-maps that have been registered in the " { $link gc-maps } " variable into a byte-array." } ;
+
+ABOUT: "compiler.codegen.gc-maps"
diff --git a/basis/compiler/codegen/gc-maps/gc-maps-tests.factor b/basis/compiler/codegen/gc-maps/gc-maps-tests.factor
index 6f9f799bf7..2dbf5ea3c9 100644
--- a/basis/compiler/codegen/gc-maps/gc-maps-tests.factor
+++ b/basis/compiler/codegen/gc-maps/gc-maps-tests.factor
@@ -2,78 +2,164 @@ USING: namespaces byte-arrays make compiler.codegen.gc-maps
compiler.codegen.relocation bit-arrays accessors classes.struct
tools.test kernel math sequences alien.c-types
specialized-arrays boxes compiler.cfg.instructions system
-cpu.architecture ;
+cpu.architecture vm ;
SPECIALIZED-ARRAY: uint
IN: compiler.codegen.gc-maps.tests
-STRUCT: gc-info
-{ scrub-d-count uint }
-{ scrub-r-count uint }
-{ gc-root-count uint }
-{ derived-root-count uint }
-{ return-address-count uint } ;
-
SINGLETON: fake-cpu
fake-cpu \ cpu set
M: fake-cpu gc-root-offset ;
-[ ] [
- [
- init-relocation
- init-gc-maps
+[
+ init-relocation
+ init-gc-maps
- 50 %
+ 50 %
- T{ gc-map f B{ } B{ } V{ } } gc-map-here
+ gc-map-here
- 50 %
+ 50 %
- T{ gc-map f B{ 0 1 1 1 0 } B{ 1 0 } V{ 1 3 } V{ { 2 4 } } } gc-map-here
-
- emit-gc-maps
- ] B{ } make
- "result" set
-] unit-test
+ T{ gc-map
+ { scrub-d { 0 1 1 1 0 } }
+ { scrub-r { 1 0 } }
+ { gc-roots V{ 1 3 } }
+ { derived-roots V{ { 2 4 } } }
+ } gc-map-here
+ emit-gc-maps
+] B{ } make
+"result" set
[ 0 ] [ "result" get length 16 mod ] unit-test
-[ ] [
- [
- 100 %
+[
+ 100 %
- ! The below data is 22 bytes -- 6 bytes padding needed to
- ! align
- 6 %
+ ! The below data is 46 bytes -- 14 bytes padding needed to
+ ! align
+ 14 %
- ! Bitmap - 2 bytes
- ?{
- ! scrub-d
- t f f f t
- ! scrub-r
- f t
- ! gc-roots
- f t f t
- } underlying>> %
+ ! Bitmap - 2 bytes
+ ?{
+ ! scrub-d
+ t f f f t
+ ! scrub-r
+ f t
+ ! gc-roots
+ f t f t
+ } underlying>> %
- ! Derived pointers
- uint-array{ -1 -1 4 } underlying>> %
+ ! Derived pointers
+ uint-array{ -1 -1 4 } underlying>> %
- ! Return addresses
- uint-array{ 100 } underlying>> %
+ ! Return addresses
+ uint-array{ 100 } underlying>> %
- ! GC info footer - 16 bytes
- S{ gc-info
- { scrub-d-count 5 }
- { scrub-r-count 2 }
- { gc-root-count 4 }
- { derived-root-count 3 }
- { return-address-count 1 }
- } (underlying)>> %
- ] B{ } make
- "expect" set
+ ! GC info footer - 28 bytes
+ S{ gc-info
+ { scrub-d-count 5 }
+ { scrub-r-count 2 }
+ { check-d-count 0 }
+ { check-r-count 0 }
+ { gc-root-count 4 }
+ { derived-root-count 3 }
+ { return-address-count 1 }
+ } (underlying)>> %
+] B{ } make
+"expect" set
+
+[ t ] [ "result" get length "expect" get length = ] unit-test
+[ t ] [ "result" get "expect" get = ] unit-test
+
+! gc-map-needed?
+{ t t } [
+ T{ gc-map { scrub-d { 0 1 1 1 0 } } { scrub-r { 1 0 } } } gc-map-needed?
+ T{ gc-map { check-d { 0 1 1 1 } } } gc-map-needed?
] unit-test
-[ ] [ "result" get length "expect" get length assert= ] unit-test
-[ ] [ "result" get "expect" get assert= ] unit-test
+! emit-scrub
+{ 3 V{ t t t f f f } } [
+ [ { { 0 0 0 } { 1 1 1 } } emit-scrub ] V{ } make
+] unit-test
+
+! emit-gc-info-bitmaps
+{
+ { 4 2 0 0 0 }
+ V{ 1 }
+} [
+ { T{ gc-map { scrub-d { 0 1 1 1 } } { scrub-r { 1 1 } } } } gc-maps set
+ [ emit-gc-info-bitmaps ] V{ } make
+] unit-test
+
+{
+ { 1 0 1 0 0 }
+ V{ 3 }
+} [
+ { T{ gc-map { scrub-d { 0 } } { check-d { 0 } } } } gc-maps set
+ [ emit-gc-info-bitmaps ] V{ } make
+] unit-test
+
+! derived-root-offsets
+USING: present prettyprint ;
+{
+ V{ { 2 4 } }
+} [
+ T{ gc-map { derived-roots V{ { 2 4 } } } }
+ derived-root-offsets
+] unit-test
+
+! emit-base-tables
+{
+ 3 B{ 255 255 255 255 255 255 255 255 4 0 0 0 }
+} [
+ { T{ gc-map { derived-roots V{ { 2 4 } } } } } gc-maps set
+ [ emit-base-tables ] B{ } make
+] unit-test
+
+
+! serialize-gc-maps
+{
+ B{ 0 0 0 0 }
+} [
+ { } return-addresses set serialize-gc-maps
+] unit-test
+
+{
+ B{
+ 17 123 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 0 0 0
+ }
+} [
+ { 123 } return-addresses set
+ { T{ gc-map { scrub-d { 0 1 1 1 0 } } } } gc-maps set
+ serialize-gc-maps
+] unit-test
+
+! gc-info + ret-addr + 9bits (5+2+2) = 28 + 4 + 2 = 34
+{ 34 } [
+ {
+ T{ gc-map
+ { scrub-d { 0 1 1 1 0 } }
+ { scrub-r { 1 0 } }
+ { gc-roots V{ 1 3 } }
+ }
+ } gc-maps set
+ { 123 } return-addresses set
+ serialize-gc-maps length
+] unit-test
+
+! gc-info + ret-addr + 3 base-pointers + 9bits = 28 + 4 + 12 + 2 = 46
+{ 46 } [
+ {
+ T{ gc-map
+ { scrub-d { 0 1 1 1 0 } }
+ { scrub-r { 1 0 } }
+ { gc-roots V{ 1 3 } }
+ { derived-roots V{ { 2 4 } } }
+ }
+ } gc-maps set
+ { 123 } return-addresses set
+ serialize-gc-maps length
+] unit-test
diff --git a/basis/compiler/codegen/gc-maps/gc-maps.factor b/basis/compiler/codegen/gc-maps/gc-maps.factor
index 474781ea95..d5a9c0fe8c 100644
--- a/basis/compiler/codegen/gc-maps/gc-maps.factor
+++ b/basis/compiler/codegen/gc-maps/gc-maps.factor
@@ -1,44 +1,17 @@
! Copyright (C) 2011 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs bit-arrays combinators
+USING: accessors arrays assocs bit-arrays classes.tuple combinators
combinators.short-circuit compiler.cfg.instructions
compiler.codegen.relocation cpu.architecture fry kernel layouts
-make math math.order namespaces sequences ;
+make math math.order namespaces sequences sequences.generalizations ;
IN: compiler.codegen.gc-maps
-! GC maps
-
-! Every code block either ends with
-!
-! uint 0
-!
-! or
-!
-! bitmap, byte aligned, three subsequences:
-! -
-! -
-! -
-! uint[]
-! uint[]
-! uint
-! uint
-! uint
-! uint
-! int
-
SYMBOLS: return-addresses gc-maps ;
-: gc-map-needed? ( gc-map -- ? )
- ! If there are no stack locations to scrub and no GC roots,
- ! there's no point storing the GC map.
- dup [
- {
- [ scrub-d>> empty? ]
- [ scrub-r>> empty? ]
- [ gc-roots>> empty? ]
- [ derived-roots>> empty? ]
- } 1&& not
- ] when ;
+: gc-map-needed? ( gc-map/f -- ? )
+ ! If there are no stack locations to scrub or check, and no GC
+ ! roots, there's no point storing the GC map.
+ dup [ tuple-slots [ empty? ] all? not ] when ;
: gc-map-here ( gc-map -- )
dup gc-map-needed? [
@@ -71,13 +44,15 @@ SYMBOLS: return-addresses gc-maps ;
: gc-root-offsets ( gc-map -- offsets )
gc-roots>> [ gc-root-offset ] map ;
-: emit-gc-info-bitmaps ( -- scrub-d-count scrub-r-count gc-root-count )
+: emit-gc-info-bitmaps ( -- scrub-and-check-counts )
[
gc-maps get {
[ [ scrub-d>> ] map emit-scrub ]
[ [ scrub-r>> ] map emit-scrub ]
+ [ [ check-d>> ] map emit-scrub ]
+ [ [ check-r>> ] map emit-scrub ]
[ [ gc-root-offsets ] map emit-gc-roots ]
- } cleave
+ } cleave 5 narray
] ?{ } make underlying>> % ;
: emit-base-table ( alist longest -- )
@@ -98,9 +73,9 @@ SYMBOLS: return-addresses gc-maps ;
[
return-addresses get empty? [ 0 emit-uint ] [
emit-gc-info-bitmaps
- emit-base-tables
+ emit-base-tables suffix
emit-return-addresses
- 4array emit-uints
+ emit-uints
return-addresses get length emit-uint
] if
] B{ } make ;
diff --git a/basis/compiler/codegen/labels/labels-docs.factor b/basis/compiler/codegen/labels/labels-docs.factor
new file mode 100644
index 0000000000..f84978ee0e
--- /dev/null
+++ b/basis/compiler/codegen/labels/labels-docs.factor
@@ -0,0 +1,10 @@
+USING: compiler.codegen.relocation help.markup help.syntax strings ;
+IN: compiler.codegen.labels
+
+HELP: define-label
+{ $values { "name" string } }
+{ $description "Defines a new label with the given name. The " { $slot "offset" } " slot is filled in later." } ;
+
+HELP: resolve-label
+{ $values { "label/name" { $link label } " or " { $link string } } }
+{ $description "Assigns the current " { $link compiled-offset } " to the given label." } ;
diff --git a/basis/compiler/codegen/relocation/relocation-docs.factor b/basis/compiler/codegen/relocation/relocation-docs.factor
new file mode 100644
index 0000000000..145b1d50c3
--- /dev/null
+++ b/basis/compiler/codegen/relocation/relocation-docs.factor
@@ -0,0 +1,42 @@
+USING: byte-vectors compiler.codegen.labels compiler.constants cpu.architecture
+help.markup help.syntax make strings ;
+IN: compiler.codegen.relocation
+
+HELP: relocation-table
+{ $description "A " { $link byte-vector } " holding the relocations for the current compilation. Each sequence of four bytes in the vector represents one relocation." }
+{ $see-also init-relocation } ;
+
+HELP: add-relocation
+{ $values
+ { "class" "a relocation class such as " { $link rc-relative } }
+ { "type" "a relocation type such as " { $link rt-safepoint } }
+}
+{ $description "Adds one relocation to the relocation table." } ;
+
+HELP: add-literal
+{ $values { "obj" "a symbol" } }
+{ $description "Adds a symbol to the " { $link literal-table } "." } ;
+
+HELP: init-relocation
+{ $description "Initializes the dynamic variables related to code relocation." } ;
+
+HELP: rel-safepoint
+{ $values { "class" "a relocation class" } }
+{ $description "Adds a safe point to the " { $link relocation-table } " for the current code offset. This word is used by the " { $link %safepoint } " generator." } ;
+
+HELP: compiled-offset
+{ $values { "n" "offset of the code being constructed in the current " { $link make } " sequence." } }
+{ $description "The current compiled code offset. Used for (among other things) calculating jump labels." }
+{ $examples
+ { $example
+ "USING: compiler.codegen.relocation cpu.x86.assembler"
+ "cpu.x86.assembler.operands kernel layouts make prettyprint ;"
+ "[ init-relocation RAX 0 MOV compiled-offset ] B{ } make"
+ "cell-bits 64 = ["
+ " [ 10 = ] [ B{ 72 184 0 0 0 0 0 0 0 0 } = ] bi*"
+ "] ["
+ " [ 6 = ] [ B{ 72 184 0 0 0 0 } = ] bi*"
+ "] if . ."
+ "t\nt"
+ }
+} ;
diff --git a/basis/compiler/compiler-docs.factor b/basis/compiler/compiler-docs.factor
index 76c93a8422..d961674282 100644
--- a/basis/compiler/compiler-docs.factor
+++ b/basis/compiler/compiler-docs.factor
@@ -1,4 +1,4 @@
-USING: assocs compiler.cfg.builder compiler.cfg.optimizer
+USING: assocs compiler.cfg compiler.cfg.builder compiler.cfg.optimizer
compiler.errors compiler.tree.builder compiler.tree.optimizer
compiler.units compiler.codegen help.markup help.syntax io
parser quotations sequences words ;
@@ -19,7 +19,7 @@ ARTICLE: "compiler-usage" "Calling the optimizing compiler"
"More words can be found in " { $link "compilation-units" } "." ;
ARTICLE: "compiler-impl" "Compiler implementation"
-"The " { $vocab-link "compiler" } "vocabulary, in addition to providing the user-visible words of the compiler, implements the main compilation loop."
+"The " { $vocab-link "compiler" } " vocabulary, in addition to providing the user-visible words of the compiler, implements the main compilation loop."
$nl
"Once compiled, a word is added to the assoc stored in the " { $link compiled } " variable. When compilation is complete, this assoc is passed to " { $link modify-code-heap } "."
$nl
@@ -54,6 +54,18 @@ $nl
ABOUT: "compiler"
+HELP: frontend
+{ $values { "word" word } { "tree" sequence } }
+{ $description "First step of the compilation process. It outputs a high-level tree in SSA form." } ;
+
+HELP: backend
+{ $values { "tree" "a " { $link sequence } " of SSA nodes" } { "word" word } }
+{ $description "The second last step of the compilation process. A word and its SSA tree is taken as input and a " { $link cfg } " is built from which assembly code is generated." }
+{ $see-also generate } ;
+
+HELP: compiled
+{ $var-description { "An " { $link assoc } " used by the optimizing compiler for intermediate storage of generated code. The keys are the labels to the CFG:s and the values the generated code as given by the " { $link generate } " word." } } ;
+
HELP: compile-word
{ $values { "word" word } }
{ $description "Compile a single word." }
diff --git a/basis/compiler/tests/alien.factor b/basis/compiler/tests/alien.factor
index 10be5ff8f9..1760318432 100755
--- a/basis/compiler/tests/alien.factor
+++ b/basis/compiler/tests/alien.factor
@@ -1,12 +1,13 @@
USING: accessors alien alien.c-types alien.libraries
alien.syntax arrays classes.struct combinators
-compiler continuations effects generalizations io
+compiler continuations destructors effects generalizations io
io.backend io.pathnames io.streams.string kernel
math memory namespaces namespaces.private parser
quotations sequences specialized-arrays stack-checker
stack-checker.errors system threads tools.test words
alien.complex concurrency.promises alien.data
-byte-arrays classes compiler.test libc ;
+byte-arrays classes compiler.test libc layouts
+math.bitwise ;
FROM: alien.c-types => float short ;
SPECIALIZED-ARRAY: float
SPECIALIZED-ARRAY: char
@@ -337,28 +338,30 @@ FUNCTION: ulonglong ffi_test_38 ( ulonglong x, ulonglong y ) ;
: callback-throws ( -- x )
int { } cdecl [ "Hi" throw ] alien-callback ;
-[ t ] [ callback-throws alien? ] unit-test
+{ t } [
+ callback-throws [ alien? ] with-callback
+] unit-test
: callback-1 ( -- callback ) void { } cdecl [ ] alien-callback ;
[ 0 1 ] [ [ callback-1 ] infer [ in>> length ] [ out>> length ] bi ] unit-test
-[ t ] [ callback-1 alien? ] unit-test
+{ t } [ callback-1 [ alien? ] with-callback ] unit-test
: callback_test_1 ( ptr -- ) void { } cdecl alien-indirect ;
-[ ] [ callback-1 callback_test_1 ] unit-test
+{ } [ callback-1 [ callback_test_1 ] with-callback ] unit-test
: callback-2 ( -- callback ) void { } cdecl [ [ 5 throw ] ignore-errors ] alien-callback ;
-[ ] [ callback-2 callback_test_1 ] unit-test
+{ } [ callback-2 [ callback_test_1 ] with-callback ] unit-test
: callback-3 ( -- callback ) void { } cdecl [ 5 "x" set ] alien-callback ;
-[ t 3 5 ] [
+{ t 3 5 } [
[
namestack*
- 3 "x" set callback-3 callback_test_1
+ 3 "x" set callback-3 [ callback_test_1 ] with-callback
namestack* eq?
"x" get "x" get-global
] with-scope
@@ -367,33 +370,35 @@ FUNCTION: ulonglong ffi_test_38 ( ulonglong x, ulonglong y ) ;
: callback-5 ( -- callback )
void { } cdecl [ gc ] alien-callback ;
-[ "testing" ] [
- "testing" callback-5 callback_test_1
+{ "testing" } [
+ "testing" callback-5 [ callback_test_1 ] with-callback
] unit-test
: callback-5b ( -- callback )
void { } cdecl [ compact-gc ] alien-callback ;
[ "testing" ] [
- "testing" callback-5b callback_test_1
+ "testing" callback-5b [ callback_test_1 ] with-callback
] unit-test
: callback-6 ( -- callback )
void { } cdecl [ [ continue ] callcc0 ] alien-callback ;
-[ 1 2 3 ] [ callback-6 callback_test_1 1 2 3 ] unit-test
+[ 1 2 3 ] [
+ callback-6 [ callback_test_1 1 2 3 ] with-callback
+] unit-test
: callback-7 ( -- callback )
void { } cdecl [ 1000000 sleep ] alien-callback ;
-[ 1 2 3 ] [ callback-7 callback_test_1 1 2 3 ] unit-test
+[ 1 2 3 ] [ callback-7 [ callback_test_1 1 2 3 ] with-callback ] unit-test
[ f ] [ namespace global eq? ] unit-test
: callback-8 ( -- callback )
void { } cdecl [ [ ] in-thread yield ] alien-callback ;
-[ ] [ callback-8 callback_test_1 ] unit-test
+[ ] [ callback-8 [ callback_test_1 ] with-callback ] unit-test
: callback-9 ( -- callback )
int { int int int } cdecl [
@@ -406,9 +411,9 @@ FUNCTION: void ffi_test_36_point_5 ( ) ;
FUNCTION: int ffi_test_37 ( void* func ) ;
-[ 1 ] [ callback-9 ffi_test_37 ] unit-test
+[ 1 ] [ callback-9 [ ffi_test_37 ] with-callback ] unit-test
-[ 7 ] [ callback-9 ffi_test_37 ] unit-test
+[ 7 ] [ callback-9 [ ffi_test_37 ] with-callback ] unit-test
STRUCT: test_struct_13
{ x1 float }
@@ -462,11 +467,12 @@ STRUCT: double-rect
void { void* void* double-rect } cdecl alien-indirect
"example" get-global ;
-[ byte-array 1.0 2.0 3.0 4.0 ]
-[
+{ byte-array 1.0 2.0 3.0 4.0 } [
1.0 2.0 3.0 4.0
- double-rect-callback double-rect-test
- [ >c-ptr class-of ] [ >double-rect< ] bi
+ double-rect-callback [
+ double-rect-test
+ [ >c-ptr class-of ] [ >double-rect< ] bi
+ ] with-callback
] unit-test
STRUCT: test_struct_14
@@ -490,9 +496,10 @@ FUNCTION: test_struct_14 ffi_test_40 ( double x1, double x2 ) ;
: callback-10-test ( x1 x2 callback -- result )
test_struct_14 { double double } cdecl alien-indirect ;
-[ 1.0 2.0 ] [
- 1.0 2.0 callback-10 callback-10-test
- [ x1>> ] [ x2>> ] bi
+{ 1.0 2.0 } [
+ 1.0 2.0 callback-10 [
+ callback-10-test [ x1>> ] [ x2>> ] bi
+ ] with-callback
] unit-test
FUNCTION: test-struct-12 ffi_test_41 ( int a, double x ) ;
@@ -513,9 +520,10 @@ FUNCTION: test-struct-12 ffi_test_41 ( int a, double x ) ;
: callback-11-test ( x1 x2 callback -- result )
test-struct-12 { int double } cdecl alien-indirect ;
-[ 1 2.0 ] [
- 1 2.0 callback-11 callback-11-test
- [ a>> ] [ x>> ] bi
+{ 1 2.0 } [
+ 1 2.0 callback-11 [
+ callback-11-test [ a>> ] [ x>> ] bi
+ ] with-callback
] unit-test
STRUCT: test_struct_15
@@ -538,7 +546,9 @@ FUNCTION: test_struct_15 ffi_test_42 ( float x, float y ) ;
test_struct_15 { float float } cdecl alien-indirect ;
[ 1.0 2.0 ] [
- 1.0 2.0 callback-12 callback-12-test [ x>> ] [ y>> ] bi
+ 1.0 2.0 callback-12 [
+ callback-12-test [ x>> ] [ y>> ] bi
+ ] with-callback
] unit-test
STRUCT: test_struct_16
@@ -560,9 +570,10 @@ FUNCTION: test_struct_16 ffi_test_43 ( float x, int a ) ;
: callback-13-test ( x1 x2 callback -- result )
test_struct_16 { float int } cdecl alien-indirect ;
-[ 1.0 2 ] [
- 1.0 2 callback-13 callback-13-test
- [ x>> ] [ a>> ] bi
+{ 1.0 2 } [
+ 1.0 2 callback-13 [
+ callback-13-test [ x>> ] [ a>> ] bi
+ ] with-callback
] unit-test
FUNCTION: test_struct_14 ffi_test_44 ( ) ; inline
@@ -618,8 +629,14 @@ FUNCTION: short ffi_test_48 ( bool-field-test x ) ;
int { } cdecl alien-indirect ;
"p" set
-[ thread-callback-1 thread-callback-invoker "p" get fulfill ] in-thread
-[ 200 ] [ thread-callback-2 thread-callback-invoker ] unit-test
+[
+ thread-callback-1 [
+ thread-callback-invoker
+ ] with-callback "p" get fulfill
+] in-thread
+{ 200 } [
+ thread-callback-2 [ thread-callback-invoker ] with-callback
+] unit-test
[ 100 ] [ "p" get ?promise ] unit-test
! More alien-assembly tests are in cpu.* vocabs
@@ -643,7 +660,7 @@ FUNCTION: short ffi_test_48 ( bool-field-test x ) ;
[ int "f-fastcall" "ffi_test_51" { int int int } alien-invoke ]
3dip
int "f-fastcall" "ffi_test_51" { int int int } alien-invoke gc ;
-
+
[ 4 ] [ 3 ffi_test_49 ] unit-test
[ 8 ] [ 3 4 ffi_test_50 ] unit-test
[ 13 ] [ 3 4 5 ffi_test_51 ] unit-test
@@ -662,6 +679,18 @@ FUNCTION: short ffi_test_48 ( bool-field-test x ) ;
test-struct-11 "f-fastcall" "ffi_test_58" { int int int }
alien-invoke gc ;
+! Make sure that large longlong/ulonglong are correctly dealt with
+FUNCTION: longlong ffi_test_59 ( longlong x ) ;
+FUNCTION: ulonglong ffi_test_60 ( ulonglong x ) ;
+
+[ t ] [ most-positive-fixnum 1 + [ ffi_test_59 ] keep = ] unit-test
+[ t ] [ most-positive-fixnum 1 + [ ffi_test_60 ] keep = ] unit-test
+
+[ -1 ] [ -1 ffi_test_59 ] unit-test
+[ -1 ] [ 0xffffffffffffffff ffi_test_59 ] unit-test
+[ 0xffffffffffffffff ] [ -1 ffi_test_60 ] unit-test
+[ 0xffffffffffffffff ] [ 0xffffffffffffffff ffi_test_60 ] unit-test
+
! GCC bugs
mingw? [
[ 13 ] [ 3 4.0 5 ffi_test_52 ] unit-test
@@ -755,19 +784,33 @@ mingw? [
test-struct-11 { int int int } fastcall
[ [ drop + ] [ - nip ] 3bi test-struct-11 ] alien-callback ;
-[ 8 ] [ 3 4 fastcall-ii-callback fastcall-ii-indirect ] unit-test
+{ 8 } [
+ 3 4 fastcall-ii-callback [ fastcall-ii-indirect ] with-callback
+] unit-test
-[ 13 ] [ 3 4 5 fastcall-iii-callback fastcall-iii-indirect ] unit-test
+[ 13 ] [
+ 3 4 5 fastcall-iii-callback [ fastcall-iii-indirect ] with-callback
+] unit-test
-[ 13 ] [ 3 4.0 5 fastcall-ifi-callback fastcall-ifi-indirect ] unit-test
+[ 13 ] [
+ 3 4.0 5 fastcall-ifi-callback [ fastcall-ifi-indirect ] with-callback
+] unit-test
-[ 19 ] [ 3 4.0 5 6 fastcall-ifii-callback fastcall-ifii-indirect ] unit-test
+[ 19 ] [
+ 3 4.0 5 6 fastcall-ifii-callback [ fastcall-ifii-indirect ] with-callback
+] unit-test
-[ S{ test-struct-11 f 7 -1 } ]
-[ 3 4 fastcall-struct-return-ii-callback fastcall-struct-return-ii-indirect ] unit-test
+[ S{ test-struct-11 f 7 -1 } ] [
+ 3 4 fastcall-struct-return-ii-callback [
+ fastcall-struct-return-ii-indirect
+ ] with-callback
+] unit-test
-[ S{ test-struct-11 f 7 -3 } ]
-[ 3 4 7 fastcall-struct-return-iii-callback fastcall-struct-return-iii-indirect ] unit-test
+[ S{ test-struct-11 f 7 -3 } ] [
+ 3 4 7 fastcall-struct-return-iii-callback [
+ fastcall-struct-return-iii-indirect
+ ] with-callback
+] unit-test
: x64-regression-1 ( -- c )
int { int int int int int } cdecl [ + + + + ] alien-callback ;
@@ -775,10 +818,14 @@ mingw? [
: x64-regression-2 ( x x x x x c -- y )
int { int int int int int } cdecl alien-indirect ; inline
-[ 661 ] [ 100 500 50 10 1 x64-regression-1 x64-regression-2 ] unit-test
+[ 661 ] [
+ 100 500 50 10 1 x64-regression-1 [ x64-regression-2 ] with-callback
+] unit-test
! Stack allocation
-: blah ( -- x ) { RECT } [ 1.5 >>x 2.0 >>y [ x>> ] [ y>> ] bi * >fixnum ] with-scoped-allocation ;
+: blah ( -- x ) { RECT } [
+ 1.5 >>x 2.0 >>y [ x>> ] [ y>> ] bi * >fixnum
+] with-scoped-allocation ;
[ 3 ] [ blah ] unit-test
@@ -809,7 +856,9 @@ mingw? [
alien-indirect
] with-out-parameters ;
-[ 12 ] [ 6 out-param-callback out-param-indirect ] unit-test
+[ 12 ] [
+ 6 out-param-callback [ out-param-indirect ] with-callback
+] unit-test
! Alias analysis regression
: aa-callback-1 ( -- c )
@@ -823,8 +872,9 @@ TUPLE: some-tuple x ;
[ T{ some-tuple f 5.0 } ] [
[
some-tuple new
- aa-callback-1
- aa-indirect-1 >>x
+ aa-callback-1 [
+ aa-indirect-1
+ ] with-callback >>x
] compile-call
] unit-test
diff --git a/basis/compiler/tests/linkage-errors.factor b/basis/compiler/tests/linkage-errors.factor
index 98a07899f3..b622ccc09d 100644
--- a/basis/compiler/tests/linkage-errors.factor
+++ b/basis/compiler/tests/linkage-errors.factor
@@ -1,48 +1,48 @@
-USING: tools.test namespaces assocs alien.syntax kernel
-compiler.errors accessors alien alien.c-types alien.strings
-debugger literals ;
-FROM: alien.libraries => add-library load-library ;
-IN: compiler.tests.linkage-errors
-
-! Regression: calling an undefined function would raise a protection fault
-FUNCTION: void this_does_not_exist ( ) ;
-
-[ this_does_not_exist ] try
-
-[ this_does_not_exist ] [
- { "kernel-error" 9 $[ "this_does_not_exist" string>symbol ] f }
- =
-] must-fail-with
-
-[ T{ no-such-symbol { name "this_does_not_exist" } } ]
-[
- \ this_does_not_exist linkage-errors get at error>>
- ! We don't care about the error message from dlerror, just
- ! wipe it out
- clone f >>message
-] unit-test
-
-<< "no_such_library" "no_such_library" cdecl add-library >>
-
-LIBRARY: no_such_library
-
-FUNCTION: void no_such_function ( ) ;
-
-[ no_such_function ] try
-
-[ no_such_function ] [
- {
- "kernel-error" 9
- $[ "no_such_function" string>symbol ]
- $[ "no_such_library" load-library ]
- }
- =
-] must-fail-with
-
-[ T{ no-such-library { name "no_such_library" } } ]
-[
- \ no_such_function linkage-errors get at error>>
- ! We don't care about the error message from dlerror, just
- ! wipe it out
- clone f >>message
-] unit-test
+USING: tools.test namespaces assocs alien.syntax kernel
+compiler.errors accessors alien alien.c-types alien.strings
+debugger literals kernel.private ;
+FROM: alien.libraries => add-library load-library ;
+IN: compiler.tests.linkage-errors
+
+! Regression: calling an undefined function would raise a protection fault
+FUNCTION: void this_does_not_exist ( ) ;
+
+[ this_does_not_exist ] try
+
+[ this_does_not_exist ] [
+ ${ "kernel-error" ERROR-UNDEFINED-SYMBOL "this_does_not_exist" string>symbol f }
+ =
+] must-fail-with
+
+[ T{ no-such-symbol { name "this_does_not_exist" } } ]
+[
+ \ this_does_not_exist linkage-errors get at error>>
+ ! We don't care about the error message from dlerror, just
+ ! wipe it out
+ clone f >>message
+] unit-test
+
+<< "no_such_library" "no_such_library" cdecl add-library >>
+
+LIBRARY: no_such_library
+
+FUNCTION: void no_such_function ( ) ;
+
+[ no_such_function ] try
+
+[ no_such_function ] [
+ ${
+ "kernel-error" ERROR-UNDEFINED-SYMBOL
+ "no_such_function" string>symbol
+ "no_such_library" load-library
+ }
+ =
+] must-fail-with
+
+[ T{ no-such-library { name "no_such_library" } } ]
+[
+ \ no_such_function linkage-errors get at error>>
+ ! We don't care about the error message from dlerror, just
+ ! wipe it out
+ clone f >>message
+] unit-test
diff --git a/basis/compiler/tree/builder/builder-docs.factor b/basis/compiler/tree/builder/builder-docs.factor
index 83093470c9..5f761be681 100644
--- a/basis/compiler/tree/builder/builder-docs.factor
+++ b/basis/compiler/tree/builder/builder-docs.factor
@@ -1,5 +1,5 @@
-USING: help.markup help.syntax sequences quotations words
-compiler.tree stack-checker.errors ;
+USING: compiler.tree help.markup help.syntax literals quotations sequences
+stack-checker.errors words ;
IN: compiler.tree.builder
HELP: build-tree
@@ -10,4 +10,20 @@ HELP: build-tree
HELP: build-sub-tree
{ $values { "in-d" "a sequence of values" } { "out-d" "a sequence of values" } { "word/quot" { $or word quotation } } { "nodes/f" { $maybe "a sequence of nodes" } } }
-{ $description "Attempts to construct tree SSA IR from a quotation, starting with an initial data stack of values from the call site. Outputs " { $link f } " if stack effect inference fails." } ;
+{ $description "Attempts to construct tree SSA IR from a quotation, starting with an initial data stack of values from the call site. Outputs " { $link f } " if stack effect inference fails." }
+{ $examples
+ { $unchecked-example
+ ! The out-d numbers are unpredicable.
+ "USING: compiler.tree.builder math prettyprint ;"
+ "{ \"x\" } { \"y\" } [ 4 * ] build-sub-tree ."
+ $[
+ {
+ "V{"
+ " T{ #push { literal 4 } { out-d { 1 } } }"
+ " T{ #call { word * } { in-d V{ \"x\" 1 } } { out-d { 2 } } }"
+ " T{ #copy { in-d V{ 2 } } { out-d { \"y\" } } }"
+ "}"
+ } "\n" join
+ ]
+ }
+} ;
diff --git a/basis/compiler/tree/cleanup/cleanup-docs.factor b/basis/compiler/tree/cleanup/cleanup-docs.factor
new file mode 100644
index 0000000000..73ca20baa2
--- /dev/null
+++ b/basis/compiler/tree/cleanup/cleanup-docs.factor
@@ -0,0 +1,9 @@
+USING: help.markup help.syntax sequences ;
+IN: compiler.tree.cleanup
+
+ARTICLE: "compiler.tree.cleanup" "Cleanup Phase"
+"A phase run after propagation to finish the job, so to speak. Codifies speculative inlining decisions, deletes branches marked as never taken, and flattens local recursive blocks that do not call themselves." ;
+
+HELP: cleanup
+{ $values { "nodes" sequence } { "nodes'" sequence } }
+{ $description "Main entry point for the cleanup optimization phase." } ;
diff --git a/basis/compiler/tree/cleanup/cleanup.factor b/basis/compiler/tree/cleanup/cleanup.factor
index 5cf2a4f469..6c9d846da8 100644
--- a/basis/compiler/tree/cleanup/cleanup.factor
+++ b/basis/compiler/tree/cleanup/cleanup.factor
@@ -12,11 +12,6 @@ compiler.tree.propagation.info
compiler.tree.propagation.branches ;
IN: compiler.tree.cleanup
-! A phase run after propagation to finish the job, so to speak.
-! Codifies speculative inlining decisions, deletes branches
-! marked as never taken, and flattens local recursive blocks
-! that do not call themselves.
-
GENERIC: delete-node ( node -- )
M: #call-recursive delete-node
diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor
index 8b7c3a57f5..7369c0dced 100644
--- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor
+++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor
@@ -23,7 +23,11 @@ TUPLE: declared-fixnum { x fixnum } ;
[ t ] [
[ { declared-fixnum } declare [ 1 + ] change-x ]
- { + fixnum+ >fixnum } inlined?
+ { + } inlined?
+ ! XXX: As of .97, we do a bounds check and throw an error on
+ ! overflow, so we no longer convert fixnum+ to fixnum+fast.
+ ! If this is too big a regression, we can revert it.
+ ! { + fixnum+ >fixnum } inlined?
] unit-test
[ t ] [
diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor
index 65a7e889ee..135a63692d 100644
--- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor
+++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor
@@ -39,7 +39,7 @@ IN: compiler.tree.modular-arithmetic
! is a modular arithmetic word, then the input can be converted into
! a form that is cheaper to compute.
{
- >fixnum bignum>fixnum integer>fixnum integer>fixnum-strict
+ >fixnum bignum>fixnum integer>fixnum
float>fixnum
set-alien-unsigned-1 set-alien-signed-1
set-alien-unsigned-2 set-alien-signed-2
diff --git a/basis/compiler/tree/propagation/branches/branches.factor b/basis/compiler/tree/propagation/branches/branches.factor
index aae41f9c2d..29fb38005e 100644
--- a/basis/compiler/tree/propagation/branches/branches.factor
+++ b/basis/compiler/tree/propagation/branches/branches.factor
@@ -57,6 +57,8 @@ SYMBOL: infer-children-data
value-infos off
constraints off ;
+DEFER: collect-variables
+
: infer-children ( node -- )
[ live-children ] [ child-constraints ] bi [
[
@@ -64,7 +66,8 @@ SYMBOL: infer-children-data
[ copy-value-info assume (propagate) ]
[ 2drop no-value-info ]
if
- ] H{ } make-assoc
+ collect-variables
+ ] with-scope
] 2map infer-children-data set ;
: compute-phi-input-infos ( phi-in -- phi-info )
@@ -86,6 +89,14 @@ SYMBOL: infer-children-data
SYMBOL: condition-value
+: collect-variables ( -- hash )
+ {
+ condition-value
+ constraints
+ infer-children-data
+ value-infos
+ } [ dup get ] H{ } map>assoc ;
+
M: #phi propagate-before ( #phi -- )
[ annotate-phi-inputs ]
[ [ phi-info-d>> flip ] [ out-d>> ] bi merge-value-infos ]
diff --git a/basis/compiler/tree/propagation/info/info-docs.factor b/basis/compiler/tree/propagation/info/info-docs.factor
new file mode 100644
index 0000000000..4e11f5bacc
--- /dev/null
+++ b/basis/compiler/tree/propagation/info/info-docs.factor
@@ -0,0 +1,21 @@
+USING: compiler.tree help.markup help.syntax sequences ;
+IN: compiler.tree.propagation.info
+
+HELP: value-info-state
+{ $class-description "Represents constraints the compiler knows about the input and output variables to an SSA tree node. It has the following slots:"
+ { $table
+ { { $slot "class" } { "Class of values the variable can take." } }
+ { { $slot "interval" } { "Range of values the variable can take." } }
+ { { $slot "literal" } { "Literal value, if present." } }
+ { { $slot "literal?" } { "Whether the value of the variable is known at compile-time or not." } }
+ { { $slot "slots" } { "If the value is a literal tuple or fixed length type, then slots is a " { $link sequence } " of " { $link value-info-state } " encoding what is known about its slots at compile-time." } }
+ }
+} ;
+
+HELP: node-input-infos
+{ $values { "node" node } { "seq" sequence } }
+{ $description "Lists the value infos for the input variables of an SSA tree node." } ;
+
+HELP: node-output-infos
+{ $values { "node" node } { "seq" sequence } }
+{ $description "Lists the value infos for the output variables of an SSA tree node." } ;
diff --git a/basis/compiler/tree/propagation/known-words/known-words-docs.factor b/basis/compiler/tree/propagation/known-words/known-words-docs.factor
new file mode 100644
index 0000000000..9a981d46cd
--- /dev/null
+++ b/basis/compiler/tree/propagation/known-words/known-words-docs.factor
@@ -0,0 +1,38 @@
+USING: classes compiler.tree.propagation.info help.markup
+help.syntax kernel math math.intervals ;
+IN: compiler.tree.propagation.known-words
+
+HELP: binary-op-class
+{ $values { "info1" value-info-state } { "info2" value-info-state } { "newclass" class } }
+{ $description "Given two value infos return the math class which is large enough for both of them." }
+{ $examples
+ { $example
+ "USING: compiler.tree.propagation.known-words compiler.tree.propagation.info"
+ "kernel math prettyprint ;"
+ "bignum real [ ] bi@ binary-op-class ."
+ "real"
+ }
+} ;
+
+HELP: unary-op-class
+{ $values { "info" value-info-state } { "newclass" class } }
+{ $description "Returns the smallest math class large enough to hold values of the value infos class." }
+{ $see-also binary-op-class } ;
+
+HELP: number-valued
+{ $values
+ { "class" class } { "interval" interval }
+ { "class'" class } { "interval'" interval }
+}
+{ $description "Ensure that the class is a subclass of " { $link number } "." } ;
+
+HELP: fits-in-fixnum?
+{ $values { "interval" interval } { "?" boolean } }
+{ $description "Checks if the interval is a subset of the " { $link fixnum } " interval. Used to see if arithmetic may overflow." }
+{ $examples
+ { $example
+ "USING: compiler.tree.propagation.known-words math.intervals prettyprint ;"
+ "full-interval fits-in-fixnum? ."
+ "f"
+ }
+} ;
diff --git a/basis/compiler/tree/propagation/known-words/known-words.factor b/basis/compiler/tree/propagation/known-words/known-words.factor
index d158c931b3..206ad633a9 100644
--- a/basis/compiler/tree/propagation/known-words/known-words.factor
+++ b/basis/compiler/tree/propagation/known-words/known-words.factor
@@ -225,6 +225,7 @@ generic-comparison-ops [
{
{ >fixnum fixnum }
{ bignum>fixnum fixnum }
+ { bignum>fixnum-strict fixnum }
{ integer>fixnum fixnum }
{ integer>fixnum-strict fixnum }
diff --git a/basis/compiler/tree/propagation/nodes/nodes-docs.factor b/basis/compiler/tree/propagation/nodes/nodes-docs.factor
new file mode 100644
index 0000000000..92886f45a8
--- /dev/null
+++ b/basis/compiler/tree/propagation/nodes/nodes-docs.factor
@@ -0,0 +1,6 @@
+USING: compiler.tree help.markup help.syntax ;
+IN: compiler.tree.propagation.nodes
+
+HELP: annotate-node
+{ $values { "node" node } }
+{ $description "Initializes the info slot for SSA tree nodes that have it." } ;
diff --git a/basis/compiler/tree/propagation/propagation-docs.factor b/basis/compiler/tree/propagation/propagation-docs.factor
new file mode 100644
index 0000000000..039ea44692
--- /dev/null
+++ b/basis/compiler/tree/propagation/propagation-docs.factor
@@ -0,0 +1,52 @@
+USING: help.markup help.syntax literals multiline ;
+IN: compiler.tree.propagation
+
+<<
+STRING: propagate-ex
+USING: compiler.tree.builder compiler.tree.propagation math prettyprint ;
+[ 3 + ] build-tree propagate third .
+T{ #call
+ { word + }
+ { in-d V{ 9450187 9450186 } }
+ { out-d { 9450188 } }
+ { info
+ H{
+ {
+ 9450186
+ T{ value-info-state
+ { class fixnum }
+ { interval
+ T{ interval
+ { from ~array~ }
+ { to ~array~ }
+ }
+ }
+ { literal 3 }
+ { literal? t }
+ }
+ }
+ {
+ 9450187
+ T{ value-info-state
+ { class object }
+ { interval full-interval }
+ }
+ }
+ {
+ 9450188
+ T{ value-info-state
+ { class number }
+ { interval full-interval }
+ }
+ }
+ }
+ }
+}
+;
+>>
+
+HELP: propagate
+{ $values { "nodes" "a sequence of nodes" } }
+{ $description "Performs the propagation pass of the AST optimization. All nodes info slots are initialized here." }
+{ $examples { $unchecked-example $[ propagate-ex ] }
+} ;
diff --git a/basis/compiler/tree/propagation/propagation.factor b/basis/compiler/tree/propagation/propagation.factor
index a11264fb7f..81309088c4 100644
--- a/basis/compiler/tree/propagation/propagation.factor
+++ b/basis/compiler/tree/propagation/propagation.factor
@@ -15,7 +15,7 @@ IN: compiler.tree.propagation
! This pass must run after normalization
-: propagate ( node -- node )
+: propagate ( nodes -- nodes )
H{ } clone copies set
H{ } clone 1array value-infos set
H{ } clone 1array constraints set
diff --git a/basis/compiler/tree/propagation/simple/simple.factor b/basis/compiler/tree/propagation/simple/simple.factor
index c9148e2f18..b07e8d4bca 100644
--- a/basis/compiler/tree/propagation/simple/simple.factor
+++ b/basis/compiler/tree/propagation/simple/simple.factor
@@ -74,9 +74,17 @@ M: #declare propagate-before
] [ 2drop ] if
] if* ;
+ERROR: invalid-outputs #call infos ;
+
+: check-outputs ( #call infos -- infos )
+ over out-d>> over [ length ] bi@ =
+ [ nip ] [ invalid-outputs ] if ;
+
: call-outputs-quot ( #call word -- infos )
- [ in-d>> [ value-info ] map ] [ "outputs" word-prop ] bi*
- with-datastack ;
+ dupd
+ [ in-d>> [ value-info ] map ]
+ [ "outputs" word-prop ] bi*
+ with-datastack check-outputs ;
: literal-inputs? ( #call -- ? )
in-d>> [ value-info literal?>> ] all? ;
diff --git a/basis/compiler/tree/propagation/transforms/transforms.factor b/basis/compiler/tree/propagation/transforms/transforms.factor
index 6fc10b797b..689ae20202 100644
--- a/basis/compiler/tree/propagation/transforms/transforms.factor
+++ b/basis/compiler/tree/propagation/transforms/transforms.factor
@@ -9,7 +9,7 @@ math.integers.private layouts math.order vectors hashtables
combinators effects generalizations sequences.generalizations
assocs sets combinators.short-circuit sequences.private locals
growable stack-checker namespaces compiler.tree.propagation.info
-hash-sets ;
+hash-sets arrays hashtables.private ;
FROM: math => float ;
FROM: sets => set members ;
IN: compiler.tree.propagation.transforms
@@ -45,11 +45,11 @@ IN: compiler.tree.propagation.transforms
in-d>> rem-custom-inlining
] "custom-inlining" set-word-prop
-: positive-fixnum? ( obj -- ? )
+: non-negative-fixnum? ( obj -- ? )
{ [ fixnum? ] [ 0 >= ] } 1&& ;
: simplify-bitand? ( value1 value2 -- ? )
- [ literal>> positive-fixnum? ]
+ [ literal>> non-negative-fixnum? ]
[ class>> fixnum swap class<= ]
bi* and ;
@@ -318,7 +318,7 @@ M\ set intersects? [ intersects?-quot ] 1 define-partial-eval
: bit-quot ( #call -- quot/f )
in-d>> second value-info interval>> 0 fixnum-bits [a,b] interval-subset?
- [ [ >fixnum ] dip fixnum-bit? ] f ? ;
+ [ [ integer>fixnum ] dip fixnum-bit? ] f ? ;
\ bit? [ bit-quot ] "custom-inlining" set-word-prop
diff --git a/basis/compiler/tree/tree-docs.factor b/basis/compiler/tree/tree-docs.factor
new file mode 100644
index 0000000000..3d15f35de4
--- /dev/null
+++ b/basis/compiler/tree/tree-docs.factor
@@ -0,0 +1,52 @@
+USING: assocs help.markup help.syntax kernel sequences stack-checker.alien
+stack-checker.visitor words ;
+IN: compiler.tree
+
+HELP: node
+{ $class-description "Base class for all SSA tree nodes." } ;
+
+HELP: #alien-node
+{ $class-description "Base class for alien nodes. Its " { $snippet "params" } " slot holds an instance of the " { $link alien-node-params } " class." } ;
+
+HELP: #alien-invoke
+{ $class-description "SSA tree node that calls a function in a dynamically linked library." } ;
+
+HELP: #alien-callback
+{ $class-description "SSA tree node that constructs an alien callback." } ;
+
+HELP: #call
+{ $class-description "SSA tree node that calls a word. It has the following slots:"
+ { $table
+ { { $slot "word" } { "The " { $link word } " to call." } }
+ { { $slot "in-d" } { "Sequence of input variables to the call. The items are ordered from top to bottom of the stack." } }
+ { { $slot "out-d" } { "Output values of the call." } }
+ { { $slot "info" } { "An assoc that contains various annotations for the words input and output values. It is set during the propagation pass of the optimizer." } }
+ }
+} ;
+
+HELP: #introduce
+{ $class-description "SSA tree node that puts an input value from the \"outside\" on the stack." } ;
+
+HELP: #push
+{ $class-description "SSA tree node that puts a literal value on the stack." }
+{ $notes "A quotation is also a literal." } ;
+
+HELP: #shuffle
+{ $class-description "SSA tree node that represents a stack shuffling operation such as " { $link swap } ". It has the following slots:"
+ { $table
+ { { $slot "mapping" } { "An " { $link assoc } " that shows how the shuffle output values (the keys) correspond to their inputs (the values)." } }
+ }
+} ;
+
+HELP: #if
+{ $class-description "SSA tree node that implements conditional branching. It has the following slots:"
+ { $table
+ { { $slot "children" }
+ { "A two item " { $link sequence } ". The first item holds the instructions executed if the condition is true and the second those that are executed if it is not true." }
+ }
+ }
+} ;
+
+HELP: node,
+{ $values { "node" node } }
+{ $description "Emits a node to the " { $link stack-visitor } " variable." } ;
diff --git a/basis/compression/snappy/authors.txt b/basis/compression/snappy/authors.txt
new file mode 100644
index 0000000000..7c1b2f2279
--- /dev/null
+++ b/basis/compression/snappy/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/compression/snappy/ffi/authors.txt b/basis/compression/snappy/ffi/authors.txt
new file mode 100644
index 0000000000..7c1b2f2279
--- /dev/null
+++ b/basis/compression/snappy/ffi/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/compression/snappy/ffi/ffi.factor b/basis/compression/snappy/ffi/ffi.factor
new file mode 100644
index 0000000000..5cdad5bd35
--- /dev/null
+++ b/basis/compression/snappy/ffi/ffi.factor
@@ -0,0 +1,32 @@
+! Copyright (C) 2014 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries
+alien.libraries.finder alien.syntax classes.struct ;
+USE: nested-comments
+IN: compression.snappy.ffi
+
+<< "snappy" "snappy" find-library cdecl add-library >>
+
+LIBRARY: snappy
+
+ENUM: snappy_status SNAPPY_OK SNAPPY_INVALID_INPUT SNAPPY_BUFFER_TOO_SMALL ;
+
+FUNCTION: snappy_status snappy_compress ( char* input,
+ size_t input_length,
+ char* compressed,
+ size_t* compressed_length ) ;
+
+FUNCTION: snappy_status snappy_uncompress ( char* compressed,
+ size_t compressed_length,
+ char* uncompressed,
+ size_t* uncompressed_length ) ;
+
+FUNCTION: size_t snappy_max_compressed_length ( size_t source_length ) ;
+
+FUNCTION: snappy_status snappy_uncompressed_length ( char* compressed,
+ size_t compressed_length,
+ size_t* result ) ;
+
+FUNCTION: snappy_status snappy_validate_compressed_buffer ( char* compressed,
+ size_t compressed_length ) ;
+
diff --git a/basis/compression/snappy/snappy-tests.factor b/basis/compression/snappy/snappy-tests.factor
new file mode 100644
index 0000000000..9411ac0f1f
--- /dev/null
+++ b/basis/compression/snappy/snappy-tests.factor
@@ -0,0 +1,24 @@
+! Copyright (C) 2014 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays byte-arrays compression.snappy kernel tools.test ;
+IN: compression.snappy.tests
+
+[ t ] [
+ 1000 2 >byte-array [ snappy-compress snappy-uncompress ] keep =
+] unit-test
+
+[ t ] [
+ B{ } [ snappy-compress snappy-uncompress ] keep =
+] unit-test
+
+[ t ] [
+ B{ 1 } [ snappy-compress snappy-uncompress ] keep =
+] unit-test
+
+[ t ] [
+ B{ 1 2 } [ snappy-compress snappy-uncompress ] keep =
+] unit-test
+
+[ t ] [
+ B{ 1 2 3 } [ snappy-compress snappy-uncompress ] keep =
+] unit-test
diff --git a/basis/compression/snappy/snappy.factor b/basis/compression/snappy/snappy.factor
new file mode 100644
index 0000000000..10bd78f8c3
--- /dev/null
+++ b/basis/compression/snappy/snappy.factor
@@ -0,0 +1,33 @@
+! Copyright (C) 2014 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.c-types alien.data byte-arrays compression.snappy.ffi
+kernel sequences ;
+IN: compression.snappy
+
+ERROR: snappy-error error ;
+
+outs ( n -- byte-array size_t* )
+ [ ] [ size_t ][ ] bi ;
+
+PRIVATE>
+
+: snappy-compress ( byte-array -- compressed )
+ dup length
+ dup snappy_max_compressed_length
+ n>outs
+ [ snappy_compress check-snappy ] 2keep size_t deref head ;
+
+: snappy-uncompress ( compressed -- byte-array )
+ dup length
+ over
+ dup length 0 size_t ][
+ [ snappy_uncompressed_length check-snappy ] keep
+ size_t deref
+ n>outs
+ [ snappy_uncompress check-snappy ] 2keep drop >byte-array ;
+
diff --git a/basis/concurrency/combinators/combinators-docs.factor b/basis/concurrency/combinators/combinators-docs.factor
index c3389a1aec..28d6d11bd5 100644
--- a/basis/concurrency/combinators/combinators-docs.factor
+++ b/basis/concurrency/combinators/combinators-docs.factor
@@ -2,27 +2,27 @@ USING: help.markup help.syntax sequences ;
IN: concurrency.combinators
HELP: parallel-map
-{ $values { "seq" sequence } { "quot" { $quotation "( elt -- newelt )" } } { "newseq" sequence } }
+{ $values { "seq" sequence } { "quot" { $quotation ( elt -- newelt ) } } { "newseq" sequence } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the results at the end." }
{ $errors "Throws an error if one of the iterations throws an error." } ;
HELP: 2parallel-map
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt -- newelt )" } } { "newseq" sequence } }
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation ( elt1 elt2 -- newelt ) } } { "newseq" sequence } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", collecting the results at the end." }
{ $errors "Throws an error if one of the iterations throws an error." } ;
HELP: parallel-each
-{ $values { "seq" sequence } { "quot" { $quotation "( elt -- )" } } }
+{ $values { "seq" sequence } { "quot" { $quotation ( elt -- ) } } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", blocking until all quotations complete." }
{ $errors "Throws an error if one of the iterations throws an error." } ;
HELP: 2parallel-each
-{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation "( elt -- )" } } }
+{ $values { "seq1" sequence } { "seq2" sequence } { "quot" { $quotation ( elt1 elt2 -- ) } } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to pairwise elements of " { $snippet "seq1" } " and " { $snippet "seq2" } ", blocking until all quotations complete." }
{ $errors "Throws an error if one of the iterations throws an error." } ;
HELP: parallel-filter
-{ $values { "seq" sequence } { "quot" { $quotation "( elt -- ? )" } } { "newseq" sequence } }
+{ $values { "seq" sequence } { "quot" { $quotation ( elt -- ? ) } } { "newseq" sequence } }
{ $description "Spawns a new thread for applying " { $snippet "quot" } " to every element of " { $snippet "seq" } ", collecting the elements for which the quotation yielded a true value." }
{ $errors "Throws an error if one of the iterations throws an error." } ;
@@ -37,6 +37,13 @@ $nl
2parallel-map
parallel-filter
}
+"Concurrent product sequence combinators:"
+{ $subsections
+ parallel-product-each
+ parallel-cartesian-each
+ parallel-product-map
+ parallel-cartesian-map
+}
"Concurrent cleave combinators:"
{ $subsections
parallel-cleave
diff --git a/basis/concurrency/combinators/combinators-tests.factor b/basis/concurrency/combinators/combinators-tests.factor
index f33f6513a9..74363e6af0 100644
--- a/basis/concurrency/combinators/combinators-tests.factor
+++ b/basis/concurrency/combinators/combinators-tests.factor
@@ -53,3 +53,9 @@ IN: concurrency.combinators.tests
[ number>string ] 3 parallel-napply
{ [ "a" append ] [ "b" append ] [ "c" append ] } parallel-spread
] unit-test
+
+{ H{ { 0 4 } { 2 6 } { 4 8 } } } [
+ H{ { 1 2 } { 3 4 } { 5 6 } } [
+ [ 1 - ] [ 2 + ] bi*
+ ] parallel-assoc-map
+] unit-test
diff --git a/basis/concurrency/combinators/combinators.factor b/basis/concurrency/combinators/combinators.factor
index 306242d3ac..e7c42bc644 100644
--- a/basis/concurrency/combinators/combinators.factor
+++ b/basis/concurrency/combinators/combinators.factor
@@ -1,7 +1,8 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: concurrency.futures concurrency.count-downs sequences
-kernel macros fry combinators generalizations ;
+USING: arrays assocs combinators concurrency.count-downs
+concurrency.futures fry generalizations kernel macros sequences
+sequences.private sequences.product ;
IN: concurrency.combinators
-: parallel-each ( seq quot -- )
+: parallel-each ( seq quot: ( elt -- ) -- )
over length [
'[ _ curry _ spawn-stage ] each
] (parallel-each) ; inline
-: 2parallel-each ( seq1 seq2 quot -- )
+: 2parallel-each ( seq1 seq2 quot: ( elt1 elt2 -- ) -- )
2over min-length [
'[ _ 2curry _ spawn-stage ] 2each
] (parallel-each) ; inline
-: parallel-filter ( seq quot -- newseq )
+: parallel-product-each ( seq quot: ( elt -- ) -- )
+ [ ] dip parallel-each ;
+
+: parallel-cartesian-each ( seq1 seq2 quot: ( elt1 elt2 -- ) -- )
+ [ 2array ] dip [ first2-unsafe ] prepose parallel-product-each ;
+
+: parallel-filter ( seq quot: ( elt -- ? ) -- newseq )
over [ selector [ parallel-each ] dip ] dip like ; inline
PRIVATE>
-: parallel-map ( seq quot -- newseq )
+: parallel-map ( seq quot: ( elt -- newelt ) -- newseq )
[future] map future-values ; inline
-: 2parallel-map ( seq1 seq2 quot -- newseq )
+: parallel-assoc-map-as ( assoc quot: ( key value -- newkey newvalue ) exemplar -- newassoc )
+ [
+ [ 2array ] compose '[ _ 2curry future ] { } assoc>map future-values
+ ] dip assoc-like ;
+
+: parallel-assoc-map ( assoc quot: ( key value -- newkey newvalue ) -- newassoc )
+ over parallel-assoc-map-as ;
+
+: 2parallel-map ( seq1 seq2 quot: ( elt1 elt2 -- newelt ) -- newseq )
'[ _ 2curry future ] 2map future-values ;
+: parallel-product-map ( seq quot: ( elt -- newelt ) -- newseq )
+ [ ] dip parallel-map ;
+
+: parallel-cartesian-map ( seq1 seq2 quot: ( elt1 elt2 -- newelt ) -- newseq )
+ [ 2array ] dip [ first2-unsafe ] prepose parallel-product-map ;
+
{ $description "A mailbox is an object that can be used for safe thread communication. Items can be put in the mailbox and retrieved in a FIFO order. If the mailbox is empty when a get operation is performed then the thread will block until another thread places something in the mailbox. If multiple threads are waiting on the same mailbox, only one of the waiting threads will be unblocked to thread the get operation." } ;
HELP: mailbox-empty?
-{ $values { "mailbox" mailbox }
- { "bool" "a boolean" }
+{ $values { "mailbox" mailbox }
+ { "bool" boolean }
}
{ $description "Return true if the mailbox is empty." } ;
HELP: mailbox-put
-{ $values { "obj" object }
- { "mailbox" mailbox }
+{ $values { "obj" object }
+ { "mailbox" mailbox }
}
{ $description "Put the object into the mailbox. Any threads that have a blocking get on the mailbox are resumed. Only one of those threads will successfully get the object, the rest will immediately block waiting for the next item in the mailbox." } ;
HELP: block-unless-pred
{ $values
{ "mailbox" mailbox }
- { "timeout" "a " { $link duration } " or " { $link f } }
- { "pred" { $quotation "( ... message -- ... ? )" } }
+ { "timeout" { $maybe duration } }
+ { "pred" { $quotation ( ... message -- ... ? ) } }
}
{ $description "Block the thread if there are no items in the mailbox that return true when the predicate is called with the item on the stack." } ;
HELP: block-if-empty
-{ $values { "mailbox" mailbox }
- { "timeout" "a " { $link duration } " or " { $link f } }
+{ $values { "mailbox" mailbox }
+ { "timeout" { $maybe duration } }
}
{ $description "Block the thread if the mailbox is empty." } ;
@@ -40,14 +40,14 @@ HELP: mailbox-get-all
{ $description "Blocks the thread if the mailbox is empty, otherwise removes all objects in the mailbox and returns an array containing the objects." } ;
HELP: while-mailbox-empty
-{ $values { "mailbox" mailbox }
- { "quot" { $quotation "( -- )" } }
+{ $values { "mailbox" mailbox }
+ { "quot" { $quotation ( -- ) } }
}
{ $description "Repeatedly call the quotation while there are no items in the mailbox." } ;
HELP: mailbox-get?
-{ $values { "mailbox" mailbox }
- { "pred" { $quotation "( obj -- ? )" } }
+{ $values { "mailbox" mailbox }
+ { "pred" { $quotation ( obj -- ? ) } }
{ "obj" object }
}
{ $description "Get the first item in the mailbox which satisfies the predicate. When the predicate returns true that item will be returned. If nothing in the mailbox satisfies the predicate then the thread will block until something does." } ;
diff --git a/basis/concurrency/mailboxes/mailboxes-tests.factor b/basis/concurrency/mailboxes/mailboxes-tests.factor
index 87a4c3cdba..9acce4971a 100644
--- a/basis/concurrency/mailboxes/mailboxes-tests.factor
+++ b/basis/concurrency/mailboxes/mailboxes-tests.factor
@@ -51,4 +51,4 @@ IN: concurrency.mailboxes.tests
[
1 seconds mailbox-get-timeout
-] [ wait-timeout? ] must-fail-with
+] [ timed-out-error? ] must-fail-with
diff --git a/basis/concurrency/promises/promises-docs.factor b/basis/concurrency/promises/promises-docs.factor
index 3d7390ae28..9760d842dc 100644
--- a/basis/concurrency/promises/promises-docs.factor
+++ b/basis/concurrency/promises/promises-docs.factor
@@ -1,7 +1,6 @@
! Copyright (C) 2005, 2008 Chris Double, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: concurrency.messaging kernel arrays
-continuations help.markup help.syntax quotations calendar ;
+USING: calendar help.markup help.syntax kernel ;
IN: concurrency.promises
HELP: promise
@@ -12,7 +11,7 @@ HELP:
{ $description "Creates a new promise which may be fulfilled by calling " { $link fulfill } "." } ;
HELP: promise-fulfilled?
-{ $values { "promise" promise } { "?" "a boolean" } }
+{ $values { "promise" promise } { "?" boolean } }
{ $description "Tests if " { $link fulfill } " has previously been called on the promise, in which case " { $link ?promise } " will return immediately without blocking." } ;
HELP: ?promise-timeout
diff --git a/basis/concurrency/semaphores/semaphores-docs.factor b/basis/concurrency/semaphores/semaphores-docs.factor
index a922431d48..06c951f586 100644
--- a/basis/concurrency/semaphores/semaphores-docs.factor
+++ b/basis/concurrency/semaphores/semaphores-docs.factor
@@ -53,9 +53,7 @@ fry http.client kernel urls ;
URL" http://www.oracle.com"
}
2 '[
- _ [
- http-get nip
- ] with-semaphore
+ _ [ http-get nip ] with-semaphore
] parallel-map"""
} ;
diff --git a/basis/core-foundation/file-descriptors/file-descriptors.factor b/basis/core-foundation/file-descriptors/file-descriptors.factor
index f3f2b577c1..28b8b681f3 100644
--- a/basis/core-foundation/file-descriptors/file-descriptors.factor
+++ b/basis/core-foundation/file-descriptors/file-descriptors.factor
@@ -1,12 +1,18 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types alien.syntax kernel math.bitwise core-foundation
+USING: alien.c-types alien.syntax core-foundation kernel
literals ;
IN: core-foundation.file-descriptors
TYPEDEF: void* CFFileDescriptorRef
TYPEDEF: int CFFileDescriptorNativeDescriptor
-TYPEDEF: void* CFFileDescriptorCallBack
+
+CALLBACK: void CFFileDescriptorCallBack (
+ CFFileDescriptorRef f,
+ CFOptionFlags callBackTypes,
+ void *info
+) ;
+
C-TYPE: CFFileDescriptorContext
FUNCTION: CFFileDescriptorRef CFFileDescriptorCreate (
@@ -19,16 +25,18 @@ FUNCTION: CFFileDescriptorRef CFFileDescriptorCreate (
CONSTANT: kCFFileDescriptorReadCallBack 1
CONSTANT: kCFFileDescriptorWriteCallBack 2
-
+
FUNCTION: void CFFileDescriptorEnableCallBacks (
CFFileDescriptorRef f,
CFOptionFlags callBackTypes
) ;
: enable-all-callbacks ( fd -- )
- flags{ kCFFileDescriptorReadCallBack kCFFileDescriptorWriteCallBack }
- CFFileDescriptorEnableCallBacks ; inline
+ flags{
+ kCFFileDescriptorReadCallBack
+ kCFFileDescriptorWriteCallBack
+ } CFFileDescriptorEnableCallBacks ; inline
: ( fd callback -- handle )
- [ f swap ] [ t swap ] bi* f CFFileDescriptorCreate
+ [ f ] 2dip [ t ] dip f CFFileDescriptorCreate
[ "CFFileDescriptorCreate failed" throw ] unless* ;
diff --git a/basis/core-foundation/fsevents/fsevents.factor b/basis/core-foundation/fsevents/fsevents.factor
index cbd2fca5e4..da45e0cde2 100644
--- a/basis/core-foundation/fsevents/fsevents.factor
+++ b/basis/core-foundation/fsevents/fsevents.factor
@@ -27,7 +27,7 @@ CONSTANT: kFSEventStreamEventFlagUnmount 128
TYPEDEF: int FSEventStreamCreateFlags
TYPEDEF: int FSEventStreamEventFlags
-TYPEDEF: longlong FSEventStreamEventId
+TYPEDEF: ulonglong FSEventStreamEventId
TYPEDEF: void* FSEventStreamRef
STRUCT: FSEventStreamContext
diff --git a/basis/core-foundation/launch-services/launch-services.factor b/basis/core-foundation/launch-services/launch-services.factor
index 88a5dc9843..c021b36693 100644
--- a/basis/core-foundation/launch-services/launch-services.factor
+++ b/basis/core-foundation/launch-services/launch-services.factor
@@ -21,7 +21,94 @@ FUNCTION: OSStatus FSRefMakePath (
UInt32 maxPathSize
) ;
-CONSTANT: kCFAllocatorDefault f
+! Abstract base types
+CFSTRING: kUTTypeItem "public.item"
+CFSTRING: kUTTypeContent "public.content"
+CFSTRING: kUTTypeCompositeContent "public.composite-content"
+CFSTRING: kUTTypeApplication "com.apple.application"
+CFSTRING: kUTTypeMessage "public.message"
+CFSTRING: kUTTypeContact "public.contact"
+CFSTRING: kUTTypeArchive "public.archive"
+CFSTRING: kUTTypeDiskImage "public.disk-image"
+
+! Concrete base types
+CFSTRING: kUTTypeData "public.data"
+CFSTRING: kUTTypeDirectory "public.directory"
+CFSTRING: kUTTypeResolvable "com.apple.resolvable"
+CFSTRING: kUTTypeSymLink "public.symlink"
+CFSTRING: kUTTypeMountPoint "com.apple.mount-point"
+CFSTRING: kUTTypeAliasFile "com.apple.alias-file"
+CFSTRING: kUTTypeAliasRecord "com.apple.alias-record"
+CFSTRING: kUTTypeURL "public.url"
+CFSTRING: kUTTypeFileURL "public.file-url"
+
+! Text types
+CFSTRING: kUTTypeText "public.text"
+CFSTRING: kUTTypePlainText "public.plain-text"
+CFSTRING: kUTTypeUTF8PlainText "public.utf8-plain-text"
+CFSTRING: kUTTypeUTF16ExternalPlainText "public.utf16-external-plain-text"
+CFSTRING: kUTTypeUTF16PlainText "public.utf16-plain-text"
+CFSTRING: kUTTypeRTF "public.rtf"
+CFSTRING: kUTTypeHTML "public.html"
+CFSTRING: kUTTypeXML "public.xml"
+CFSTRING: kUTTypeSourceCode "public.source-code"
+CFSTRING: kUTTypeCSource "public.c-source"
+CFSTRING: kUTTypeObjectiveCSource "public.objective-c-source"
+CFSTRING: kUTTypeCPlusPlusSource "public.c-plus-plus-source"
+CFSTRING: kUTTypeObjectiveCPlusPlusSource "public.objective-c-plus-plus-source"
+CFSTRING: kUTTypeCHeader "public.c-header"
+CFSTRING: kUTTypeCPlusPlusHeader "public.c-plus-plus-header"
+CFSTRING: kUTTypeJavaSource "com.sun.java-source"
+
+! Composite content types
+CFSTRING: kUTTypePDF "com.adobe.pdf"
+CFSTRING: kUTTypeRTFD "com.apple.rtfd"
+CFSTRING: kUTTypeFlatRTFD "com.apple.flat-rtfd"
+CFSTRING: kUTTypeTXNTextAndMultimediaData "com.apple.txn.text-multimedia-data"
+CFSTRING: kUTTypeWebArchive "com.apple.webarchive"
+
+! Image content types
+CFSTRING: kUTTypeImage "public.image"
+CFSTRING: kUTTypeJPEG "public.jpeg"
+CFSTRING: kUTTypeJPEG2000 "public.jpeg-2000"
+CFSTRING: kUTTypeTIFF "public.tiff"
+CFSTRING: kUTTypePICT "com.apple.pict"
+CFSTRING: kUTTypeGIF "com.compuserve.gif"
+CFSTRING: kUTTypePNG "public.png"
+CFSTRING: kUTTypeQuickTimeImage "com.apple.quicktime-image"
+CFSTRING: kUTTypeAppleICNS "com.apple.icns"
+CFSTRING: kUTTypeBMP "com.microsoft.bmp"
+CFSTRING: kUTTypeICO "com.microsoft.ico"
+
+! Audiovisual content types
+CFSTRING: kUTTypeAudiovisualContent "public.audiovisual-content"
+CFSTRING: kUTTypeMovie "public.movie"
+CFSTRING: kUTTypeVideo "public.video"
+CFSTRING: kUTTypeAudio "public.audio"
+CFSTRING: kUTTypeQuickTimeMovie "com.apple.quicktime-movie"
+CFSTRING: kUTTypeMPEG "public.mpeg"
+CFSTRING: kUTTypeMPEG4 "public.mpeg-4"
+CFSTRING: kUTTypeMP3 "public.mp3"
+CFSTRING: kUTTypeMPEG4Audio "public.mpeg-4-audio"
+CFSTRING: kUTTypeAppleProtectedMPEG4Audio "com.apple.protected-mpeg-4-audio"
+
+! Directory types
+CFSTRING: kUTTypeFolder "public.folder"
+CFSTRING: kUTTypeVolume "public.volume"
+CFSTRING: kUTTypePackage "com.apple.package"
+CFSTRING: kUTTypeBundle "com.apple.bundle"
+CFSTRING: kUTTypeFramework "com.apple.framework"
+
+! Application types
+CFSTRING: kUTTypeApplicationBundle "com.apple.application-bundle"
+CFSTRING: kUTTypeApplicationFile "com.apple.application-file"
+
+! Contact types
+CFSTRING: kUTTypeVCard "public.vcard"
+
+! Misc. types
+CFSTRING: kUTTypeInkText "com.apple.ink.inktext"
+
CONSTANT: kLSUnknownCreator f
ERROR: core-foundation-error n ;
@@ -46,4 +133,3 @@ ERROR: core-foundation-error n ;
: launch-services-path ( string -- path/f )
[ (launch-services-path) ] [ 2drop f ] recover ;
-
diff --git a/basis/core-foundation/run-loop/run-loop.factor b/basis/core-foundation/run-loop/run-loop.factor
index 2e09c52215..724812d3c2 100644
--- a/basis/core-foundation/run-loop/run-loop.factor
+++ b/basis/core-foundation/run-loop/run-loop.factor
@@ -60,14 +60,16 @@ CFSTRING: CFRunLoopDefaultMode "kCFRunLoopDefaultMode"
TUPLE: run-loop-state fds sources timers ;
+SYMBOL: run-loop
+
: ( -- run-loop )
V{ } clone V{ } clone V{ } clone \ run-loop-state boa ;
-: run-loop ( -- run-loop )
- \ run-loop-state [ ] initialize-alien ;
+: get-run-loop ( -- run-loop )
+ \ run-loop [ ] initialize-alien ;
: add-source-to-run-loop ( source -- )
- [ run-loop sources>> push ]
+ [ get-run-loop sources>> push ]
[
CFRunLoopGetMain
swap CFRunLoopDefaultMode
@@ -81,7 +83,7 @@ TUPLE: run-loop-state fds sources timers ;
[
|CFRelease
[ enable-all-callbacks ]
- [ run-loop fds>> push ]
+ [ get-run-loop fds>> push ]
[ create-fd-source |CFRelease add-source-to-run-loop ]
tri
] with-destructors ;
@@ -100,7 +102,7 @@ PRIVATE>
: add-timer-to-run-loop ( timer -- )
[ reset-timer ]
- [ run-loop timers>> push ]
+ [ get-run-loop timers>> push ]
[
CFRunLoopGetMain
swap CFRunLoopDefaultMode
@@ -108,19 +110,18 @@ PRIVATE>
] tri ;
: invalidate-run-loop-timers ( -- )
- run-loop [
+ get-run-loop [
[ [ CFRunLoopTimerInvalidate ] [ CFRelease ] bi ] each
V{ } clone
] change-timers drop ;
: reset-run-loop ( -- )
- run-loop
+ get-run-loop
[ timers>> [ reset-timer ] each ]
[ fds>> [ enable-all-callbacks ] each ] bi ;
: timer-callback ( -- callback )
- void { CFRunLoopTimerRef void* } cdecl
- [ drop reset-timer yield ] alien-callback ;
+ [ drop reset-timer yield ] CFRunLoopTimerCallBack ;
: init-thread-timer ( -- )
60 timer-callback add-timer-to-run-loop ;
diff --git a/basis/core-foundation/time/time.factor b/basis/core-foundation/time/time.factor
index 37c4ff5d0e..9d22e4752d 100644
--- a/basis/core-foundation/time/time.factor
+++ b/basis/core-foundation/time/time.factor
@@ -1,6 +1,6 @@
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: calendar math alien.c-types alien.syntax memoize system ;
+USING: alien.c-types alien.syntax calendar literals math ;
IN: core-foundation.time
TYPEDEF: double CFTimeInterval
@@ -8,8 +8,10 @@ TYPEDEF: double CFAbsoluteTime
ALIAS: >CFTimeInterval duration>seconds
-MEMO: epoch ( -- micros )
- T{ timestamp { year 2001 } { month 1 } { day 1 } } timestamp>micros ;
+CONSTANT: epoch $[
+ T{ timestamp { year 2001 } { month 1 } { day 1 } }
+ timestamp>micros
+]
: >CFAbsoluteTime ( micros -- time )
epoch - 1,000,000 /f ; inline
diff --git a/basis/core-foundation/timers/timers.factor b/basis/core-foundation/timers/timers.factor
index adf4e8a1c6..595b68df88 100644
--- a/basis/core-foundation/timers/timers.factor
+++ b/basis/core-foundation/timers/timers.factor
@@ -5,7 +5,12 @@ core-foundation.time calendar.unix kernel locals math system ;
IN: core-foundation.timers
TYPEDEF: void* CFRunLoopTimerRef
-TYPEDEF: void* CFRunLoopTimerCallBack
+
+CALLBACK: void CFRunLoopTimerCallBack (
+ CFRunLoopTimerRef timer,
+ void *info
+) ;
+
TYPEDEF: void* CFRunLoopTimerContext
FUNCTION: CFRunLoopTimerRef CFRunLoopTimerCreate (
diff --git a/basis/core-graphics/core-graphics.factor b/basis/core-graphics/core-graphics.factor
index 3e4a17c020..cf04630748 100644
--- a/basis/core-graphics/core-graphics.factor
+++ b/basis/core-graphics/core-graphics.factor
@@ -1,9 +1,13 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.c-types alien.data alien.destructors
-alien.syntax accessors destructors fry kernel math math.bitwise
-sequences libc colors images images.memory core-graphics.types
-core-foundation.utilities opengl.gl literals ;
+
+USING: accessors alien alien.c-types alien.data
+alien.destructors alien.syntax colors
+core-foundation.dictionaries core-foundation.strings
+core-foundation.urls core-foundation.utilities
+core-graphics.types destructors fry images images.memory kernel
+libc math opengl.gl sequences ;
+
IN: core-graphics
TYPEDEF: int CGImageAlphaInfo
@@ -59,6 +63,10 @@ FUNCTION: CGContextRef CGBitmapContextCreate (
CGBitmapInfo bitmapInfo
) ;
+FUNCTION: CGImageRef CGBitmapContextCreateImage
+ CGContextRef c
+) ;
+
FUNCTION: void CGColorSpaceRelease ( CGColorSpaceRef ref ) ;
DESTRUCTOR: CGColorSpaceRelease
@@ -74,7 +82,7 @@ FUNCTION: void CGContextSetRGBStrokeColor (
CGFloat blue,
CGFloat alpha
) ;
-
+
FUNCTION: void CGContextSetRGBFillColor (
CGContextRef c,
CGFloat red,
@@ -113,6 +121,23 @@ FUNCTION: size_t CGImageGetHeight (
CGImageRef image
) ;
+FUNCTION: CGImageDestinationRef CGImageDestinationCreateWithURL (
+ CFURLRef url,
+ CFStringRef type,
+ size_t count,
+ CFDictionaryRef options
+) ;
+
+FUNCTION: void CGImageDestinationAddImage (
+ CGImageDestinationRef idst,
+ CGImageRef image,
+ CFDictionaryRef properties
+) ;
+
+FUNCTION: bool CGImageDestinationFinalize (
+ CGImageDestinationRef idst
+) ;
+
FUNCTION: void* CGBitmapContextGetData ( CGContextRef c ) ;
CONSTANT: kCGLRendererGenericFloatID 0x00020400
diff --git a/basis/core-graphics/types/types.factor b/basis/core-graphics/types/types.factor
index d6df20de90..13dc128f4b 100644
--- a/basis/core-graphics/types/types.factor
+++ b/basis/core-graphics/types/types.factor
@@ -77,6 +77,7 @@ TYPEDEF: void* CGColorRef
TYPEDEF: void* CGColorSpaceRef
TYPEDEF: void* CGContextRef
TYPEDEF: void* CGImageRef
+TYPEDEF: void* CGImageDestinationRef
TYPEDEF: uint CGBitmapInfo
diff --git a/basis/core-text/fonts/fonts.factor b/basis/core-text/fonts/fonts.factor
index 43a527de0b..0ebc40f523 100644
--- a/basis/core-text/fonts/fonts.factor
+++ b/basis/core-text/fonts/fonts.factor
@@ -78,7 +78,7 @@ FUNCTION: CGFloat CTFontGetXHeight ( CTFontRef font ) ;
CONSTANT: font-names
H{
{ "monospace" "Monaco" }
- { "sans-serif" "Lucida Grande" }
+ { "sans-serif" "LucidaGrande" }
{ "serif" "Times" }
}
diff --git a/basis/cpu/architecture/architecture-docs.factor b/basis/cpu/architecture/architecture-docs.factor
new file mode 100644
index 0000000000..34df497020
--- /dev/null
+++ b/basis/cpu/architecture/architecture-docs.factor
@@ -0,0 +1,168 @@
+USING: assocs alien compiler.cfg.instructions cpu.x86.assembler
+cpu.x86.assembler.operands help.markup help.syntax kernel
+layouts literals math multiline system words ;
+IN: cpu.architecture
+
+<<
+STRING: ex-%box-alien
+USING: compiler.codegen compiler.codegen.relocation cpu.architecture make ;
+init-fixup init-relocation [ RAX RBX RCX %box-alien ] B{ } make disassemble
+000000e9fcc720a0: 48b80100000000000000 mov rax, 0x1
+000000e9fcc720aa: 4885db test rbx, rbx
+000000e9fcc720ad: 0f8400000000 jz dword 0xe9fcc720b3
+000000e9fcc720b3: 498d4d10 lea rcx, [r13+0x10]
+000000e9fcc720b7: 488b01 mov rax, [rcx]
+000000e9fcc720ba: 48c70018000000 mov qword [rax], 0x18
+000000e9fcc720c1: 4883c806 or rax, 0x6
+000000e9fcc720c5: 48830130 add qword [rcx], 0x30
+000000e9fcc720c9: 48c7400201000000 mov qword [rax+0x2], 0x1
+000000e9fcc720d1: 48c7400a01000000 mov qword [rax+0xa], 0x1
+000000e9fcc720d9: 48895812 mov [rax+0x12], rbx
+000000e9fcc720dd: 4889581a mov [rax+0x1a], rbx
+;
+
+STRING: ex-%allot
+USING: cpu.architecture make ;
+[ RAX 40 tuple RCX %allot ] B{ } make disassemble
+0000000002270cc0: 498d4d10 lea rcx, [r13+0x10]
+0000000002270cc4: 488b01 mov rax, [rcx]
+0000000002270cc7: 48c7001c000000 mov qword [rax], 0x1c
+0000000002270cce: 4883c807 or rax, 0x7
+0000000002270cd2: 48830130 add qword [rcx], 0x30
+;
+
+STRING: ex-%context
+USING: cpu.architecture make ;
+[ EAX %context ] B{ } make disassemble
+00000000010f5ed0: 418b4500 mov eax, [r13]
+;
+
+STRING: ex-%safepoint
+USING: cpu.architecture make ;
+init-relocation [ %safepoint ] B{ } make disassemble
+00000000010b05a0: 890500000000 mov [rip], eax
+;
+
+STRING: ex-%save-context
+USING: cpu.architecture make ;
+[ RAX RBX %save-context ] B{ } make disassemble
+0000000000e63ab0: 498b4500 mov rax, [r13]
+0000000000e63ab4: 488d5c24f8 lea rbx, [rsp-0x8]
+0000000000e63ab9: 488918 mov [rax], rbx
+0000000000e63abc: 4c897010 mov [rax+0x10], r14
+0000000000e63ac0: 4c897818 mov [rax+0x18], r15
+;
+>>
+
+HELP: signed-rep
+{ $values { "rep" representation } { "rep'" representation } }
+{ $description "Maps any representation to its signed counterpart, if it has one." } ;
+
+HELP: immediate-arithmetic?
+{ $values { "n" number } { "?" boolean } }
+{ $description
+ "Can this value be an immediate operand for " { $link %add-imm } ", "
+ { $link %sub-imm } ", or " { $link %mul-imm } "?"
+} ;
+
+HELP: machine-registers
+{ $values { "assoc" assoc } }
+{ $description "Mapping from register class to machine registers. Only registers not reserved by the Factor VM are included." } ;
+
+HELP: vm-stack-space
+{ $values { "n" number } }
+{ $description "Parameter space to reserve in anything making VM calls." } ;
+
+HELP: complex-addressing?
+{ $values { "?" boolean } }
+{ $description "Specifies if " { $link %slot } ", " { $link %set-slot } " and " { $link %write-barrier } " accept the 'scale' and 'tag' parameters, and if %load-memory and %store-memory work." } ;
+
+HELP: param-regs
+{ $values { "abi" "a calling convention symbol" } { "regs" assoc } }
+{ $description "Retrieves the order in which machine registers are used for parameters for the given calling convention." } ;
+
+HELP: %load-immediate
+{ $values { "reg" "a register symbol" } { "val" "a value" } }
+{ $description "Emits code for loading an immediate value into a register. On " { $link x86 } ", if val is 0, then an " { $link XOR } " instruction is emitted instead of " { $link MOV } "." } ;
+
+HELP: %call
+{ $values { "word" word } }
+{ $description "Emits code for calling a word in Factor." } ;
+
+HELP: %box-alien
+{ $values { "dst" "destination register" } { "src" "source register" } { "temp" "temporary register" } }
+{ $description "Emits machine code for boxing an alien value. If the alien is not a NULL pointer, then five " { $link cells } " will be allocated in the nursery space to wrap the object. See vm/layouts.hpp for details." }
+{ $examples { $unchecked-example $[ ex-%box-alien ] } }
+{ $see-also ##box-alien %allot } ;
+
+HELP: %context
+{ $values { "dst" "a register symbol" } }
+{ $description "Emits machine code for putting a pointer to the context field of the " { $link vm } " in a register." }
+{ $examples { $unchecked-example $[ ex-%context ] } } ;
+
+HELP: %safepoint
+{ $description "Emits a safe point to the current code sequence being generated." }
+{ $examples { $unchecked-example $[ ex-%safepoint ] } } ;
+
+HELP: %save-context
+{ $values { "temp1" "a register symbol" } { "temp2" "a register symbol" } }
+{ $description "Emits machine code for saving pointers to the callstack, datastack and retainstack in the current context field struct." }
+{ $examples { $unchecked-example $[ ex-%save-context ] } } ;
+
+
+HELP: %allot
+{ $values
+ { "dst" "destination register symbol" }
+ { "size" "number of bytes to allocate" }
+ { "class" "one of the built-in classes listed in " { $link type-numbers } }
+ { "temp" "temporary register symbol" }
+}
+{ $description "Emits machine code for allocating memory." }
+{ $examples
+ "In this example 40 bytes is allocated and a tagged pointer to the memory is put in " { $link RAX } ":"
+ { $unchecked-example $[ ex-%allot ] }
+} ;
+
+HELP: test-instruction?
+{ $values { "?" "a boolean" } }
+{ $description "Does the current architecture have a test instruction? Used on x86 to rewrite some " { $link CMP } " instructions to less expensive " { $link TEST } "s." } ;
+
+HELP: fused-unboxing?
+{ $values { "?" boolean } }
+{ $description "Whether this architecture support " { $link %load-float } ", " { $link %load-double } ", and " { $link %load-vector } "." } ;
+
+HELP: return-regs
+{ $values { "regs" assoc } }
+{ $description "What registers that will be used for function return values of which class." } ;
+
+HELP: stack-cleanup
+{ $values
+ { "stack-size" integer }
+ { "return" "a c type" }
+ { "abi" abi }
+ { "n" integer }
+}
+{ $description "Calculates how many bytes of stack space the caller of the procedure being constructed need to cleanup. For modern abi's the value is almost always 0." }
+{ $examples
+ { $unchecked-example
+ "USING: cpu.architecture prettyprint ;"
+ "20 void stdcall stack-cleanup ."
+ "20"
+ }
+} ;
+
+ARTICLE: "cpu.architecture" "CPU architecture description model"
+"The " { $vocab-link "cpu.architecture" } " vocab contains generic words and hooks that serves as an api for the compiler towards the cpu architecture."
+$nl
+"Register categories:"
+{ $subsections machine-registers param-regs return-regs }
+"Architecture support checks:"
+{ $subsections
+ complex-addressing?
+ float-on-stack?
+ float-right-align-on-stack?
+ fused-unboxing?
+ test-instruction?
+}
+"Control flow code emitters:"
+{ $subsections %call %jump %jump-label %return } ;
diff --git a/basis/cpu/architecture/architecture.factor b/basis/cpu/architecture/architecture.factor
index 272e08ab80..af55954540 100644
--- a/basis/cpu/architecture/architecture.factor
+++ b/basis/cpu/architecture/architecture.factor
@@ -209,20 +209,15 @@ M: uint-4-rep scalar-rep-of drop uint-scalar-rep ;
M: longlong-2-rep scalar-rep-of drop longlong-scalar-rep ;
M: ulonglong-2-rep scalar-rep-of drop ulonglong-scalar-rep ;
-! Mapping from register class to machine registers
HOOK: machine-registers cpu ( -- assoc )
! Callbacks are not allowed to clobber this
HOOK: frame-reg cpu ( -- reg )
-! Parameter space to reserve in anything making VM calls
HOOK: vm-stack-space cpu ( -- n )
M: object vm-stack-space 0 ;
-! Specifies if %slot, %set-slot and %write-barrier accept the
-! 'scale' and 'tag' parameters, and if %load-memory and
-! %store-memory work
HOOK: complex-addressing? cpu ( -- ? )
HOOK: gc-root-offset cpu ( spill-slot -- n )
@@ -524,12 +519,8 @@ HOOK: %reload cpu ( dst rep src -- )
HOOK: %loop-entry cpu ( -- )
-! Does this architecture support %load-float, %load-double,
-! and %load-vector?
HOOK: fused-unboxing? cpu ( -- ? )
-! Can this value be an immediate operand for %add-imm, %sub-imm,
-! or %mul-imm?
HOOK: immediate-arithmetic? cpu ( n -- ? )
! Can this value be an immediate operand for %and-imm, %or-imm,
@@ -555,7 +546,6 @@ M: object immediate-comparand? ( n -- ? )
! FFI stuff
-! Return values of this class go here
HOOK: return-regs cpu ( -- regs )
! Registers used for parameter passing
diff --git a/basis/cpu/x86/64/64-docs.factor b/basis/cpu/x86/64/64-docs.factor
new file mode 100644
index 0000000000..cd58ecfb69
--- /dev/null
+++ b/basis/cpu/x86/64/64-docs.factor
@@ -0,0 +1,13 @@
+USING: help.markup help.syntax math vm ;
+IN: cpu.x86.64
+
+HELP: vm-reg
+{ $values { "reg" "a register symbol" } }
+{ $description
+ "Symbol of the machine register that holds the address of the virtual machine."
+}
+{ $see-also vm } ;
+
+HELP: param-reg
+{ $values { "n" number } { "reg" "a register symbol" } }
+{ $description "Symbol of the machine register for the nth function parameter (0-based)." } ;
diff --git a/basis/cpu/x86/assembler/assembler-docs.factor b/basis/cpu/x86/assembler/assembler-docs.factor
new file mode 100644
index 0000000000..e922e8e4f4
--- /dev/null
+++ b/basis/cpu/x86/assembler/assembler-docs.factor
@@ -0,0 +1,13 @@
+USING: compiler.codegen.labels cpu.x86.assembler help.markup help.syntax ;
+IN: cpu.x86.assembler
+
+HELP: JE
+{ $values { "dst" "destination address or " { $link label } } }
+{ $description "Emits a conditional jump instruction to the given address relative to the current code offset." }
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86.assembler make ;"
+ "[ 0x0 JE ] B{ } make disassemble"
+ "000000e9fcc71fe0: 0f8400000000 jz dword 0xe9fcc71fe6"
+ }
+} ;
diff --git a/basis/cpu/x86/assembler/operands/operands-docs.factor b/basis/cpu/x86/assembler/operands/operands-docs.factor
new file mode 100644
index 0000000000..18906a3fe4
--- /dev/null
+++ b/basis/cpu/x86/assembler/operands/operands-docs.factor
@@ -0,0 +1,42 @@
+USING: cpu.x86.assembler.operands.private help.markup help.syntax math ;
+IN: cpu.x86.assembler.operands
+
+HELP: indirect
+{ $class-description "Tuple that represents an indirect addressing operand. It has the following slots:"
+ { $table
+ { { $slot "index" } { "Register for the index value. It must not be " { $link ESP } " or " { $link RSP } "." } }
+ { { $slot "displacement" } { "An integer offset." } }
+ }
+} ;
+
+HELP: [RIP+]
+{ $values { "displacement" number } { "indirect" indirect } }
+{ $description "Creates an indirect operand relative to the RIP register." }
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86.assembler cpu.x86.assembler.operands make tools.disassembler ;"
+ "[ 0x1234 [RIP+] EAX MOV ] B{ } make disassemble"
+ "00000000015cef50: 890534120000 mov [rip+0x1234], eax"
+ }
+} ;
+
+HELP: []
+{ $values { "base/displacement" "register or an integer" } { "indirect" indirect } }
+{ $description "Creates an indirect operand from a given address or " { $link register } "." } ;
+
+HELP: n-bit-version-of
+{ $values { "register" register } { "n" integer } { "register'" register } }
+{ $description "Returns a less wide version of the given register." } ;
+
+ARTICLE: "cpu.x86.assembler.operands" "CPU x86 registers and memory operands"
+"Indirect operand constructors for various addressing formats:"
+{ $subsections [] [RIP+] [+] [++] [+*2+] [+*4+] [+*8+] }
+"Register correspondances:"
+{ $subsections
+ 8-bit-version-of
+ 16-bit-version-of
+ 32-bit-version-of
+ 64-bit-version-of
+ n-bit-version-of
+ native-version-of
+} ;
diff --git a/basis/cpu/x86/assembler/operands/operands-tests.factor b/basis/cpu/x86/assembler/operands/operands-tests.factor
new file mode 100644
index 0000000000..4325011c58
--- /dev/null
+++ b/basis/cpu/x86/assembler/operands/operands-tests.factor
@@ -0,0 +1,14 @@
+USING: cpu.x86.assembler cpu.x86.assembler.operands
+cpu.x86.assembler.operands.private make tools.test ;
+IN: cpu.x86.assembler.operands.tests
+
+[ RCX RSP 2 0 ] [ bad-index? ] must-fail-with
+
+{ B{ 72 137 12 153 } } [
+ [ RCX RBX 2 0 RCX MOV ] B{ } make
+] unit-test
+
+! No specific encoding for RBP and R13
+{ B{ 73 137 76 157 0 } } [
+ [ R13 RBX 2 f RCX MOV ] B{ } make
+] unit-test
diff --git a/basis/cpu/x86/x86-docs.factor b/basis/cpu/x86/x86-docs.factor
new file mode 100644
index 0000000000..9e904eac7a
--- /dev/null
+++ b/basis/cpu/x86/x86-docs.factor
@@ -0,0 +1,88 @@
+USING: help.markup help.syntax math ;
+IN: cpu.x86
+
+HELP: stack-reg
+{ $values { "reg" "a register symbol" } }
+{ $description
+ "Symbol of the machine register that holds the (cpu) stack address."
+} ;
+
+HELP: reserved-stack-space
+{ $values { "n" integer } }
+{ $description "Size in bytes of the register parameter area. It only exists on the windows x86.64 architecture, where it is 32 bytes and allocated by the caller. On all other platforms it is 0." } ;
+
+HELP: ds-reg
+{ $values { "reg" "a register symbol" } }
+{ $description
+ "Symbol of the machine register that holds the address to the data stack's location."
+} ;
+
+HELP: (%inc)
+{ $values { "n" number } { "reg" "a register symbol" } }
+{ $description
+ "Emits machine code for increasing or decreasing the given register a number of cell sizes bytes."
+}
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86 make prettyprint ;"
+ "[ 8 ECX (%inc) ] B{ } make disassemble"
+ "00000000615e5140: 83c140 add ecx, 0x40"
+ }
+} ;
+
+HELP: decr-stack-reg
+{ $values { "n" number } }
+{ $description "Emits an instruction for decrementing the stack register the given number of bytes." } ;
+
+HELP: load-zone-offset
+{ $values { "nursery-ptr" "a register symbol" } }
+{ $description
+ "Emits machine code for loading the address to the nursery into the machine register."
+}
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86 make ;"
+ "[ RCX load-zone-offset ] B{ } make disassemble"
+ "0000000001b48f80: 498d4d10 lea rcx, [r13+0x10]"
+ }
+} ;
+
+HELP: store-tagged
+{ $values { "dst" "a register symbol" } { "tag" "a builtin class" } }
+{ $description "Tags the register with the tag number for the given class." }
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86 make ;"
+ "[ RAX alien store-tagged ] B{ } make disassemble"
+ "0000000002275f10: 4883c806 or rax, 0x6"
+ }
+} ;
+
+HELP: copy-register*
+{ $values
+ { "dst" "a register symbol" }
+ { "src" "a register symbol" }
+ { "rep" "a value representation singleton" }
+}
+{ $description
+ "Emits machine code for copying from a register to another."
+}
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86 make ;"
+ "[ XMM1 XMM2 double-rep copy-register* ] B{ } make disassemble"
+ "0000000533c61fe0: 0f28ca movaps xmm1, xmm2"
+ }
+} ;
+
+HELP: %mov-vm-ptr
+{ $values { "reg" "a register symbol" } }
+{ $description
+ "Emits machine code for moving the vm pointer to a register." }
+{ $examples
+ { $unchecked-example
+ "USING: cpu.x86.64 make ;"
+ "[ RAX %mov-vm-ptr ] B{ } make disassemble"
+ "0000000002290b30: 4c89e8 mov rax, r13"
+ }
+} ;
diff --git a/basis/csv/csv-docs.factor b/basis/csv/csv-docs.factor
index 96a0575926..1738c2bb59 100644
--- a/basis/csv/csv-docs.factor
+++ b/basis/csv/csv-docs.factor
@@ -1,5 +1,4 @@
-USING: help.syntax help.markup kernel prettyprint sequences
-io.pathnames strings ;
+USING: help.markup help.syntax io.pathnames quotations strings ;
IN: csv
HELP: read-row
@@ -48,7 +47,7 @@ HELP: write-csv
HELP: with-delimiter
{ $values { "ch" "field delimiter (e.g. CHAR: \\t)" }
- { "quot" "a quotation" } }
+ { "quot" quotation } }
{ $description "Sets the field delimiter for read-csv, read-row, write-csv, or write-row words." } ;
ARTICLE: "csv" "Comma-separated-values parsing and writing"
diff --git a/basis/csv/csv-tests.factor b/basis/csv/csv-tests.factor
index 3c12b14f84..5beefe283c 100644
--- a/basis/csv/csv-tests.factor
+++ b/basis/csv/csv-tests.factor
@@ -4,11 +4,11 @@ io.directories ;
IN: csv.tests
! I like to name my unit tests
-: named-unit-test ( name output input -- )
- unit-test drop ; inline
+: named-unit-test ( name output input -- )
+ unit-test drop ; inline
"Fields are separated by commas"
-[ { { "1997" "Ford" "E350" } } ]
+[ { { "1997" "Ford" "E350" } } ]
[ "1997,Ford,E350" string>csv ] named-unit-test
"ignores whitespace before and after elements. n.b.specifically prohibited by RFC 4180, which states, 'Spaces are considered part of a field and should not be ignored.'"
@@ -21,29 +21,29 @@ IN: csv.tests
"double quotes mean escaped in quotes"
[ { { "1997" "Ford" "E350" "Super \"luxurious\" truck" } } ]
-[ "1997,Ford,E350,\"Super \"\"luxurious\"\" truck\""
- string>csv ] named-unit-test
+[ "1997,Ford,E350,\"Super \"\"luxurious\"\" truck\""
+ string>csv ] named-unit-test
"Fields with embedded line breaks must be delimited by double-quote characters."
[ { { "1997" "Ford" "E350" "Go get one now\nthey are going fast" } } ]
[ "1997,Ford,E350,\"Go get one now\nthey are going fast\""
- string>csv ] named-unit-test
+ string>csv ] named-unit-test
"Fields with leading or trailing spaces must be delimited by double-quote characters. (See comment about leading and trailing spaces above)"
[ { { "1997" "Ford" "E350" " Super luxurious truck " } } ]
[ "1997,Ford,E350,\" Super luxurious truck \""
- string>csv ] named-unit-test
+ string>csv ] named-unit-test
"Fields may always be delimited by double-quote characters, whether necessary or not."
[ { { "1997" "Ford" "E350" } } ]
[ "\"1997\",\"Ford\",\"E350\"" string>csv ] named-unit-test
"The first record in a csv file may contain column names in each of the fields."
-[ { { "Year" "Make" "Model" }
+[ { { "Year" "Make" "Model" }
{ "1997" "Ford" "E350" }
{ "2000" "Mercury" "Cougar" } } ]
-[ "Year,Make,Model\n1997,Ford,E350\n2000,Mercury,Cougar"
- string>csv ] named-unit-test
+[ "Year,Make,Model\n1997,Ford,E350\n2000,Mercury,Cougar"
+ string>csv ] named-unit-test
! !!!!!!!! other tests
@@ -100,3 +100,12 @@ IN: csv.tests
! FIXME: { { { "as,df" "asdf" } } } [ "\"as,\"df ,asdf" string>csv ] unit-test
! FIXME: { { { "asd\"f\"" "asdf" } } } [ "\"asd\"\"\"f\",asdf" string>csv ] unit-test
{ { { "as,d\"f" "asdf" } } } [ "\"as,\"d\"\"\"\"f,asdf" string>csv ] unit-test
+
+[ { } ] [ "" string>csv ] unit-test
+
+[
+ { { "Year" "Make" "Model" }
+ { "1997" "Ford" "E350" }
+ }
+]
+[ "Year,Make,\"Model\"\r\n1997,Ford,E350" string>csv ] unit-test
diff --git a/basis/csv/csv.factor b/basis/csv/csv.factor
index 27f39190ec..008c0b2e38 100644
--- a/basis/csv/csv.factor
+++ b/basis/csv/csv.factor
@@ -12,7 +12,7 @@ CHAR: , delimiter set-global
: stream-read-csv ( stream -- rows )
[ (stream-read-csv) ] { } make
- dup last { "" } = [ but-last ] when ; inline
+ dup ?last { "" } = [ but-last ] when ; inline
: read-csv ( -- rows )
input-stream get stream-read-csv ; inline
@@ -85,7 +86,7 @@ PRIVATE>
> swap sql>> PQexec dup postgresql-result-ok? [
@@ -147,7 +148,7 @@ M: postgresql-malloc-destructor dispose ( obj -- )
&postgresql-free
] if
] with-out-parameters memory>byte-array
- ] with-destructors
+ ] with-destructors
] [
drop pq-get-is-null nip [ f ] [ B{ } clone ] if
] if ;
diff --git a/basis/db/postgresql/postgresql-tests.factor b/basis/db/postgresql/postgresql-tests.factor
index eb1370fc74..66e1bd8b64 100644
--- a/basis/db/postgresql/postgresql-tests.factor
+++ b/basis/db/postgresql/postgresql-tests.factor
@@ -1,89 +1,110 @@
-USING: kernel db.postgresql alien continuations io classes
-prettyprint sequences namespaces tools.test db db.private
-db.tuples db.types unicode.case accessors system db.tester ;
+USING: accessors alien continuations db db.errors db.queries db.postgresql
+db.private db.tester db.tuples db.types io classes kernel math namespaces
+prettyprint sequences system tools.test unicode.case ;
IN: db.postgresql.tests
+: nonexistant-db ( -- db )
+
+ "localhost" >>host
+ "fake-user" >>username
+ "no-pass" >>password
+ "dont-exist" >>database ;
-os windows? cpu x86.64? and [
- ! Ensure the table exists
- [ ] [ postgresql-test-db [ ] with-db ] unit-test
+! Don't leak connections
+[ ] [
+ 2000 [ [ nonexistant-db [ ] with-db ] ignore-errors ] times
+] unit-test
- [ ] [
- postgresql-test-db [
- [ "drop table person;" sql-command ] ignore-errors
- "create table person (name varchar(30), country varchar(30));"
- sql-command
+! Ensure the test database exists
+postgresql-template1-db [
+ postgresql-test-db-name ensure-database
+] with-db
- "insert into person values('John', 'America');" sql-command
- "insert into person values('Jane', 'New Zealand');" sql-command
- ] with-db
- ] unit-test
+! Triggers a two line error message (ERROR + DETAIL) because two
+! connections can't simultaneously use the template1 database.
+! [
+ ! postgresql-template1-db [
+ ! postgresql-template1-db [
+ ! "will_never_exist" ensure-database
+ ! ] with-db
+ ! ] with-db
+! ] [ sql-unknown-error? ] must-fail-with
- [
- {
- { "John" "America" }
- { "Jane" "New Zealand" }
- }
- ] [
- postgresql-test-db [
- "select * from person" sql-query
- ] with-db
- ] unit-test
-
- [
- {
- { "John" "America" }
- { "Jane" "New Zealand" }
- }
- ] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
-
- [
- ] [
- postgresql-test-db [
- "insert into person(name, country) values('Jimmy', 'Canada')"
+[ ] [
+ postgresql-test-db [
+ [ "drop table person;" sql-command ] ignore-errors
+ "create table person (name varchar(30), country varchar(30));"
sql-command
- ] with-db
- ] unit-test
- [
- {
- { "John" "America" }
- { "Jane" "New Zealand" }
- { "Jimmy" "Canada" }
- }
- ] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
+ "insert into person values('John', 'America');" sql-command
+ "insert into person values('Jane', 'New Zealand');" sql-command
+ ] with-db
+] unit-test
- [
- postgresql-test-db [
- [
- "insert into person(name, country) values('Jose', 'Mexico')" sql-command
- "insert into person(name, country) values('Jose', 'Mexico')" sql-command
- "oops" throw
- ] with-transaction
- ] with-db
- ] must-fail
+[
+ {
+ { "John" "America" }
+ { "Jane" "New Zealand" }
+ }
+] [
+ postgresql-test-db [
+ "select * from person" sql-query
+ ] with-db
+] unit-test
- [ 3 ] [
- postgresql-test-db [
- "select * from person" sql-query length
- ] with-db
- ] unit-test
+[
+ {
+ { "John" "America" }
+ { "Jane" "New Zealand" }
+ }
+] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
- [
- ] [
- postgresql-test-db [
- [
- "insert into person(name, country) values('Jose', 'Mexico')"
- sql-command
- "insert into person(name, country) values('Jose', 'Mexico')"
- sql-command
- ] with-transaction
- ] with-db
- ] unit-test
+[
+] [
+ postgresql-test-db [
+ "insert into person(name, country) values('Jimmy', 'Canada')"
+ sql-command
+ ] with-db
+] unit-test
- [ 5 ] [
- postgresql-test-db [
- "select * from person" sql-query length
- ] with-db
- ] unit-test
-] unless
+[
+ {
+ { "John" "America" }
+ { "Jane" "New Zealand" }
+ { "Jimmy" "Canada" }
+ }
+] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
+
+[
+ postgresql-test-db [
+ [
+ "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+ "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+ "oops" throw
+ ] with-transaction
+ ] with-db
+] must-fail
+
+[ 3 ] [
+ postgresql-test-db [
+ "select * from person" sql-query length
+ ] with-db
+] unit-test
+
+[
+] [
+ postgresql-test-db [
+ [
+ "insert into person(name, country) values('Jose', 'Mexico')"
+ sql-command
+ "insert into person(name, country) values('Jose', 'Mexico')"
+ sql-command
+ ] with-transaction
+ ] with-db
+] unit-test
+
+[ 5 ] [
+ postgresql-test-db [
+ "select * from person" sql-query length
+ ] with-db
+] unit-test
diff --git a/basis/db/postgresql/postgresql.factor b/basis/db/postgresql/postgresql.factor
index a002175ea8..12acded9c0 100644
--- a/basis/db/postgresql/postgresql.factor
+++ b/basis/db/postgresql/postgresql.factor
@@ -284,10 +284,10 @@ M: postgresql-db-connection compound ( string object -- string' )
M: postgresql-db-connection parse-db-error
"\n" split dup length {
{ 1 [ first parse-postgresql-sql-error ] }
+ { 2 [ concat parse-postgresql-sql-error ] }
{ 3 [
first3
[ parse-postgresql-sql-error ] 2dip
postgresql-location >>location
] }
} case ;
-
diff --git a/basis/db/sqlite/ffi/ffi.factor b/basis/db/sqlite/ffi/ffi.factor
index 7fcb4babf5..6afe4da607 100644
--- a/basis/db/sqlite/ffi/ffi.factor
+++ b/basis/db/sqlite/ffi/ffi.factor
@@ -2,41 +2,38 @@
! See http://factorcode.org/license.txt for BSD license.
! An interface to the sqlite database. Tested against sqlite v3.1.3.
! Not all functions have been wrapped.
-USING: alien compiler kernel math namespaces sequences strings alien.syntax
-system combinators alien.c-types alien.libraries ;
+USING: alien alien.libraries alien.libraries.finder compiler kernel
+math namespaces sequences strings alien.syntax system combinators
+alien.c-types ;
IN: db.sqlite.ffi
-<< "sqlite" {
- { [ os windows? ] [ "sqlite3.dll" ] }
- { [ os macosx? ] [ "/usr/lib/libsqlite3.dylib" ] }
- { [ os unix? ] [ "libsqlite3.so" ] }
- } cond cdecl add-library >>
+<< "sqlite" "sqlite3" find-library cdecl add-library >>
! Return values from sqlite functions
CONSTANT: SQLITE_OK 0 ! Successful result
CONSTANT: SQLITE_ERROR 1 ! SQL error or missing database
-CONSTANT: SQLITE_INTERNAL 2 ! An internal logic error in SQLite
-CONSTANT: SQLITE_PERM 3 ! Access permission denied
-CONSTANT: SQLITE_ABORT 4 ! Callback routine requested an abort
-CONSTANT: SQLITE_BUSY 5 ! The database file is locked
-CONSTANT: SQLITE_LOCKED 6 ! A table in the database is locked
-CONSTANT: SQLITE_NOMEM 7 ! A malloc() failed
-CONSTANT: SQLITE_READONLY 8 ! Attempt to write a readonly database
-CONSTANT: SQLITE_INTERRUPT 9 ! Operation terminated by sqlite_interrupt()
-CONSTANT: SQLITE_IOERR 10 ! Some kind of disk I/O error occurred
-CONSTANT: SQLITE_CORRUPT 11 ! The database disk image is malformed
-CONSTANT: SQLITE_NOTFOUND 12 ! (Internal Only) Table or record not found
-CONSTANT: SQLITE_FULL 13 ! Insertion failed because database is full
-CONSTANT: SQLITE_CANTOPEN 14 ! Unable to open the database file
-CONSTANT: SQLITE_PROTOCOL 15 ! Database lock protocol error
-CONSTANT: SQLITE_EMPTY 16 ! (Internal Only) Database table is empty
-CONSTANT: SQLITE_SCHEMA 17 ! The database schema changed
-CONSTANT: SQLITE_TOOBIG 18 ! Too much data for one row of a table
-CONSTANT: SQLITE_CONSTRAINT 19 ! Abort due to contraint violation
-CONSTANT: SQLITE_MISMATCH 20 ! Data type mismatch
-CONSTANT: SQLITE_MISUSE 21 ! Library used incorrectly
-CONSTANT: SQLITE_NOLFS 22 ! Uses OS features not supported on host
-CONSTANT: SQLITE_AUTH 23 ! Authorization denied
+CONSTANT: SQLITE_INTERNAL 2 ! An internal logic error in SQLite
+CONSTANT: SQLITE_PERM 3 ! Access permission denied
+CONSTANT: SQLITE_ABORT 4 ! Callback routine requested an abort
+CONSTANT: SQLITE_BUSY 5 ! The database file is locked
+CONSTANT: SQLITE_LOCKED 6 ! A table in the database is locked
+CONSTANT: SQLITE_NOMEM 7 ! A malloc() failed
+CONSTANT: SQLITE_READONLY 8 ! Attempt to write a readonly database
+CONSTANT: SQLITE_INTERRUPT 9 ! Operation terminated by sqlite_interrupt()
+CONSTANT: SQLITE_IOERR 10 ! Some kind of disk I/O error occurred
+CONSTANT: SQLITE_CORRUPT 11 ! The database disk image is malformed
+CONSTANT: SQLITE_NOTFOUND 12 ! (Internal Only) Table or record not found
+CONSTANT: SQLITE_FULL 13 ! Insertion failed because database is full
+CONSTANT: SQLITE_CANTOPEN 14 ! Unable to open the database file
+CONSTANT: SQLITE_PROTOCOL 15 ! Database lock protocol error
+CONSTANT: SQLITE_EMPTY 16 ! (Internal Only) Database table is empty
+CONSTANT: SQLITE_SCHEMA 17 ! The database schema changed
+CONSTANT: SQLITE_TOOBIG 18 ! Too much data for one row of a table
+CONSTANT: SQLITE_CONSTRAINT 19 ! Abort due to contraint violation
+CONSTANT: SQLITE_MISMATCH 20 ! Data type mismatch
+CONSTANT: SQLITE_MISUSE 21 ! Library used incorrectly
+CONSTANT: SQLITE_NOLFS 22 ! Uses OS features not supported on host
+CONSTANT: SQLITE_AUTH 23 ! Authorization denied
CONSTANT: SQLITE_FORMAT 24 ! Auxiliary database format error
CONSTANT: SQLITE_RANGE 25 ! 2nd parameter to sqlite3_bind out of range
CONSTANT: SQLITE_NOTADB 26 ! File opened that is not a database file
diff --git a/basis/db/tester/tester.factor b/basis/db/tester/tester.factor
index 4471ae4979..b8b00e52c6 100644
--- a/basis/db/tester/tester.factor
+++ b/basis/db/tester/tester.factor
@@ -1,8 +1,8 @@
! Copyright (C) 2008 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: concurrency.combinators db.pools db.sqlite db.tuples
-db.types kernel math random threads tools.test db sequences
-io prettyprint db.postgresql accessors io.files.temp
+USING: concurrency.combinators db db.pools db.sqlite db.tuples
+db.types destructors kernel math random threads tools.test sequences
+io io.pools prettyprint db.postgresql accessors io.files.temp
namespaces fry system math.parser db.queries assocs ;
IN: db.tester
@@ -11,24 +11,16 @@ IN: db.tester
H{ { CHAR: - CHAR: _ } { CHAR: . CHAR: _ } } substitute ;
: postgresql-test-db ( -- postgresql-db )
-
- "localhost" >>host
- "postgres" >>username
- "thepasswordistrust" >>password
- postgresql-test-db-name >>database ;
+ \ postgresql-db get-global clone postgresql-test-db-name >>database ;
: postgresql-template1-db ( -- postgresql-db )
-
- "localhost" >>host
- "postgres" >>username
- "thepasswordistrust" >>password
- "template1" >>database ;
+ \ postgresql-db get-global clone "template1" >>database ;
: sqlite-test-db ( -- sqlite-db )
cpu name>> "tuples-test." ".db" surround
temp-file ;
-! These words leak resources, but are useful for interactivel testing
+! These words leak resources, but are useful for interactive testing
: set-sqlite-db ( -- )
sqlite-db db-open db-connection set ;
@@ -100,10 +92,12 @@ test-2 "TEST2" {
] with-db
] [
[
- 10 iota [
- 10 [
- test-1-tuple insert-tuple yield
- ] times
- ] parallel-each
- ] with-pooled-db
+ [
+ 10 iota [
+ 10 [
+ test-1-tuple insert-tuple yield
+ ] times
+ ] parallel-each
+ ] with-pooled-db
+ ] with-disposal
] bi ;
diff --git a/basis/db/tuples/tuples.factor b/basis/db/tuples/tuples.factor
index fcb7df53cc..0bdb2978ee 100644
--- a/basis/db/tuples/tuples.factor
+++ b/basis/db/tuples/tuples.factor
@@ -35,9 +35,9 @@ GENERIC: eval-generator ( singleton -- object )
: query-tuples ( exemplar-tuple statement -- seq )
[ out-params>> ] keep query-results [
- [ sql-row-typed swap resulting-tuple ] with with query-map
+ [ sql-row-typed swap resulting-tuple ] 2with query-map
] with-disposal ;
-
+
: query-modify-tuple ( tuple statement -- )
[ query-results [ sql-row-typed ] with-disposal ] keep
out-params>> rot [
diff --git a/basis/db/types/types-docs.factor b/basis/db/types/types-docs.factor
index 2ac358982e..60b032a02d 100644
--- a/basis/db/types/types-docs.factor
+++ b/basis/db/types/types-docs.factor
@@ -1,7 +1,6 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: classes hashtables help.markup help.syntax io.streams.string
-kernel sequences strings math ;
+USING: help.markup help.syntax kernel strings ;
IN: db.types
HELP: +db-assigned-id+
@@ -90,7 +89,7 @@ HELP: VARCHAR
HELP: user-assigned-id-spec?
{ $values
{ "specs" "a sequence of SQL specs" }
- { "?" "a boolean" } }
+ { "?" boolean } }
{ $description "Tests if any of the SQL specs has the type " { $link +user-assigned-id+ } "." } ;
HELP: bind#
@@ -106,7 +105,7 @@ HELP: bind%
HELP: db-assigned-id-spec?
{ $values
{ "specs" "a sequence of SQL specs" }
- { "?" "a boolean" } }
+ { "?" boolean } }
{ $description "Tests if any of the SQL specs has the type " { $link +db-assigned-id+ } "." } ;
HELP: find-primary-key
@@ -129,13 +128,13 @@ HELP: normalize-spec
HELP: primary-key?
{ $values
{ "spec" "a SQL spec" }
- { "?" "a boolean" } }
+ { "?" boolean } }
{ $description "Returns true if a SQL spec is a primary key." } ;
HELP: relation?
{ $values
{ "spec" "a SQL spec" }
- { "?" "a boolean" } }
+ { "?" boolean } }
{ $description "Returns true if a SQL spec is a relation." } ;
HELP: unknown-modifier
diff --git a/basis/debugger/debugger-docs.factor b/basis/debugger/debugger-docs.factor
index 50461226b5..e673fb0b2f 100644
--- a/basis/debugger/debugger-docs.factor
+++ b/basis/debugger/debugger-docs.factor
@@ -1,7 +1,6 @@
-USING: alien arrays generic generic.math help.markup help.syntax
-kernel math memory strings sbufs vectors io io.files classes
-help generic.single continuations io.files.private listener
-alien.libraries ;
+USING: alien alien.libraries arrays continuations generic.math
+generic.single help help.markup help.syntax io kernel math
+quotations sbufs strings vectors ;
IN: debugger
ARTICLE: "debugger" "The debugger"
@@ -48,7 +47,7 @@ HELP: :c
{ $description "Prints the call stack at the time of the most recent error. Used for interactive debugging." } ;
HELP: :get
-{ $values { "variable" "an object" } { "value" "the value, or f" } }
+{ $values { "variable" object } { "value" "the value, or f" } }
{ $description "Looks up the value of a variable at the time of the most recent error." } ;
HELP: :res
@@ -84,7 +83,7 @@ HELP: restarts.
{ $description "Print a list of restarts for the most recently thrown error to " { $link output-stream } "." } ;
HELP: try
-{ $values { "quot" "a quotation" } }
+{ $values { "quot" quotation } }
{ $description "Attempts to call a quotation; if it throws an error, the error is printed to " { $link output-stream } ", stacks are restored, and execution continues after the call to " { $link try } "." }
{ $examples
"The following example prints an error and keeps going:"
@@ -106,7 +105,7 @@ HELP: type-check-error.
{ $error-description "Thrown by various primitives if one of the inputs does not have the expected type. Generic words throw " { $link no-method } " and " { $link no-math-method } " errors in such cases instead." } ;
HELP: divide-by-zero-error.
-{ $error-description "This error is thrown when " { $link / } " or " { $link /i } " is called with with a zero denominator." }
+{ $error-description "This error is thrown when " { $link / } " or " { $link /i } " is called with a zero denominator." }
{ $see-also "division-by-zero" } ;
HELP: signal-error.
diff --git a/basis/debugger/debugger-tests.factor b/basis/debugger/debugger-tests.factor
index 6800c83a9c..25b46c2fdb 100644
--- a/basis/debugger/debugger-tests.factor
+++ b/basis/debugger/debugger-tests.factor
@@ -1,7 +1,40 @@
-USING: debugger kernel continuations tools.test ;
+USING: alien.syntax debugger kernel continuations tools.test ;
IN: debugger.tests
[ ] [ [ drop ] [ error. ] recover ] unit-test
[ f ] [ { } vm-error? ] unit-test
[ f ] [ { "A" "B" } vm-error? ] unit-test
+
+[ ] [
+T{ test-failure
+ { error
+ {
+ "kernel-error"
+ 10
+ {
+ B{
+ 88 73 110 112 117 116 69 110 97 98 108 101 0
+ }
+ B{
+ 88 73 110 112 117 116 69 110 97 98 108 101
+ 64 56 0
+ }
+ B{
+ 95 88 73 110 112 117 116 69 110 97 98 108
+ 101 64 56 0
+ }
+ B{
+ 64 88 73 110 112 117 116 69 110 97 98 108
+ 101 64 56 0
+ }
+ }
+ DLL" xinput1_3.dll"
+ }
+ }
+ { asset { "Unit Test" [ ] [ dup ] } }
+ { file "resource:basis/game/input/input-tests.factor" }
+ { line# 6 }
+ { continuation f }
+} error.
+] unit-test
diff --git a/basis/debugger/debugger.factor b/basis/debugger/debugger.factor
index 09d215b136..e1c23923a1 100755
--- a/basis/debugger/debugger.factor
+++ b/basis/debugger/debugger.factor
@@ -1,16 +1,16 @@
! Copyright (C) 2004, 2011 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.strings slots arrays definitions generic hashtables
-summary io kernel math namespaces make prettyprint
-prettyprint.config sequences assocs sequences.private strings
-io.styles io.pathnames vectors words system splitting
-math.parser classes.mixin classes.tuple continuations
-continuations.private combinators generic.math classes.builtin
-classes compiler.units generic.standard generic.single vocabs
-init kernel.private io.encodings accessors math.order
-destructors source-files parser classes.tuple.parser
-effects.parser lexer generic.parser strings.parser vocabs.loader
-vocabs.parser source-files.errors grouping ;
+USING: accessors alien.strings arrays assocs classes
+classes.builtin classes.mixin classes.tuple classes.tuple.parser
+combinators combinators.short-circuit compiler.errors
+compiler.units continuations definitions destructors
+effects.parser fry generic generic.math generic.parser
+generic.single grouping io io.encodings io.styles kernel
+kernel.private lexer make math math.order math.parser namespaces
+parser prettyprint sequences sequences.private slots
+source-files.errors strings strings.parser summary system vocabs
+vocabs.loader vocabs.parser words ;
+FROM: namespaces => change-global ;
IN: debugger
GENERIC: error-help ( error -- topic )
@@ -43,8 +43,7 @@ M: string error. print ;
error-continuation get name>> assoc-stack ;
: :res ( n -- * )
- 1 - restarts get-global nth f restarts set-global
- continue-restart ;
+ 1 - restarts [ nth f ] change-global continue-restart ;
: :1 ( -- * ) 1 :res ;
: :2 ( -- * ) 2 :res ;
@@ -102,17 +101,26 @@ HOOK: signal-error. os ( obj -- )
"Invalid array size: " write dup third .
"Maximum: " write fourth 1 - . ;
+: fixnum-range-error. ( obj -- )
+ "Cannot convert to fixnum: " write third . ;
+
: c-string-error. ( obj -- )
"Cannot convert to C string: " write third . ;
: ffi-error. ( obj -- )
"FFI error" print drop ;
+: find-ffi-error ( string -- error )
+ [ linkage-errors get ] dip
+ '[ nip asset>> name>> _ = ] assoc-find drop nip
+ [ error>> message>> ] [ "none" ] if* ;
+
: undefined-symbol-error. ( obj -- )
"Cannot resolve C library function" print
- "Symbol: " write dup third symbol>string print
- "Library: " write fourth .
- "You are probably missing a library or the library path is wrong." print
+ "Library: " write dup fourth .
+ third symbol>string
+ [ "Symbol: " write print ]
+ [ "DlError: " write find-ffi-error print ] bi
"See http://concatenative.org/wiki/view/Factor/Requirements" print ;
: stack-underflow. ( obj name -- )
@@ -131,7 +139,7 @@ HOOK: signal-error. os ( obj -- )
: memory-error. ( error -- )
"Memory protection fault at address " write third .h ;
-: primitive-error. ( error -- )
+: primitive-error. ( error -- )
"Unimplemented primitive" print drop ;
: fp-trap-error. ( error -- )
@@ -140,41 +148,47 @@ HOOK: signal-error. os ( obj -- )
: interrupt-error. ( error -- )
"Interrupt" print drop ;
+: callback-space-overflow. ( error -- )
+ "Callback space overflow" print drop ;
+
PREDICATE: vm-error < array
- {
- { [ dup empty? ] [ drop f ] }
- { [ dup first "kernel-error" = not ] [ drop f ] }
- [ second 0 18 between? ]
- } cond ;
+ dup length 2 < [ drop f ] [
+ {
+ [ first-unsafe "kernel-error" = ]
+ [ second-unsafe 0 kernel-error-count 1 - between? ]
+ } 1&&
+ ] if ;
: vm-errors ( error -- n errors )
second {
- { 0 [ expired-error. ] }
- { 1 [ io-error. ] }
- { 2 [ primitive-error. ] }
- { 3 [ type-check-error. ] }
- { 4 [ divide-by-zero-error. ] }
- { 5 [ signal-error. ] }
- { 6 [ array-size-error. ] }
- { 7 [ c-string-error. ] }
- { 8 [ ffi-error. ] }
- { 9 [ undefined-symbol-error. ] }
- { 10 [ datastack-underflow. ] }
- { 11 [ datastack-overflow. ] }
- { 12 [ retainstack-underflow. ] }
- { 13 [ retainstack-overflow. ] }
- { 14 [ callstack-underflow. ] }
- { 15 [ callstack-overflow. ] }
- { 16 [ memory-error. ] }
- { 17 [ fp-trap-error. ] }
- { 18 [ interrupt-error. ] }
+ [ expired-error. ]
+ [ io-error. ]
+ [ primitive-error. ]
+ [ type-check-error. ]
+ [ divide-by-zero-error. ]
+ [ signal-error. ]
+ [ array-size-error. ]
+ [ fixnum-range-error. ]
+ [ c-string-error. ]
+ [ ffi-error. ]
+ [ undefined-symbol-error. ]
+ [ datastack-underflow. ]
+ [ datastack-overflow. ]
+ [ retainstack-underflow. ]
+ [ retainstack-overflow. ]
+ [ callstack-underflow. ]
+ [ callstack-overflow. ]
+ [ memory-error. ]
+ [ fp-trap-error. ]
+ [ interrupt-error. ]
+ [ callback-space-overflow. ]
} ; inline
M: vm-error summary drop "VM error" ;
-M: vm-error error. dup vm-errors case ;
+M: vm-error error. dup vm-errors dispatch ;
-M: vm-error error-help vm-errors at first ;
+M: vm-error error-help vm-errors nth first ;
M: no-method summary
drop "No suitable method" ;
@@ -351,8 +365,7 @@ M: row-variable-can't-have-type summary
drop "Stack effect row variables cannot have a declared type" ;
M: bad-escape error.
- "Bad escape code: \\" write
- char>> 1string print ;
+ "Bad escape code: \\" write char>> write nl ;
M: bad-literal-tuple summary drop "Bad literal tuple" ;
diff --git a/basis/deques/deques-docs.factor b/basis/deques/deques-docs.factor
index 8b86fd2f3f..3a3e9d11e7 100644
--- a/basis/deques/deques-docs.factor
+++ b/basis/deques/deques-docs.factor
@@ -3,9 +3,16 @@ quotations ;
IN: deques
HELP: deque-empty?
-{ $values { "deque" deque } { "?" "a boolean" } }
+{ $values { "deque" deque } { "?" boolean } }
{ $contract "Returns true if a deque is empty." }
-{ $notes "This operation is O(1)." } ;
+{ $notes "This operation is O(1)." }
+{ $examples
+ { $example
+ "USING: deques prettyprint unrolled-lists ;"
+ " deque-empty? ."
+ "t"
+ }
+} ;
HELP: clear-deque
{ $values
@@ -15,27 +22,34 @@ HELP: clear-deque
HELP: deque-member?
{ $values
{ "value" object } { "deque" deque }
- { "?" "a boolean" } }
+ { "?" boolean } }
{ $description "Returns true if the " { $snippet "value" } " is found in the deque." } ;
HELP: push-front
{ $values { "obj" object } { "deque" deque } }
-{ $description "Push the object onto the front of the deque." }
+{ $description "Push the object onto the front of the deque." }
{ $notes "This operation is O(1)." } ;
HELP: push-front*
{ $values { "obj" object } { "deque" deque } { "node" "a node" } }
-{ $contract "Push the object onto the front of the deque and return the newly created node." }
-{ $notes "This operation is O(1)." } ;
+{ $contract "Push the object onto the front of the deque and return the newly created node." }
+{ $notes "This operation is O(1)." }
+{ $examples
+ { $example
+ "USING: deques dlists kernel prettyprint ;"
+ "33 push-front* node-value ."
+ "33"
+ }
+} ;
HELP: push-back
{ $values { "obj" object } { "deque" deque } }
-{ $description "Push the object onto the back of the deque." }
+{ $description "Push the object onto the back of the deque." }
{ $notes "This operation is O(1)." } ;
HELP: push-back*
{ $values { "obj" object } { "deque" deque } { "node" "a node" } }
-{ $contract "Push the object onto the back of the deque and return the newly created node." }
+{ $contract "Push the object onto the back of the deque and return the newly created node." }
{ $notes "This operation is O(1)." } ;
HELP: push-all-back
@@ -111,7 +125,14 @@ HELP: node-value
HELP: slurp-deque
{ $values
{ "deque" deque } { "quot" quotation } }
-{ $description "Pops off the back element of the deque and calls the quotation in a loop until the deque is empty." } ;
+{ $description "Pops off the back element of the deque and calls the quotation in a loop until the deque is empty." }
+{ $examples
+ { $example
+ "USING: deques dlists io kernel ;"
+ "{ \"one\" \"two\" \"three\" } [ push-all-front ] keep [ print ] slurp-deque"
+ "one\ntwo\nthree"
+ }
+} ;
ARTICLE: "deques" "Deques"
"The " { $vocab-link "deques" } " vocabulary implements the deque data structure which has constant-time insertion and removal of elements at both ends."
diff --git a/basis/disjoint-sets/disjoint-sets-docs.factor b/basis/disjoint-sets/disjoint-sets-docs.factor
index 589f99f6dc..98ad9f2340 100644
--- a/basis/disjoint-sets/disjoint-sets-docs.factor
+++ b/basis/disjoint-sets/disjoint-sets-docs.factor
@@ -14,7 +14,7 @@ HELP: equiv-set-size
{ $description "Outputs the number of elements in the equivalence class of " { $snippet "a" } "." } ;
HELP: equiv?
-{ $values { "a" object } { "b" object } { "disjoint-set" disjoint-set } { "?" "a boolean" } }
+{ $values { "a" object } { "b" object } { "disjoint-set" disjoint-set } { "?" boolean } }
{ $description "Tests if two elements belong to the same equivalence class." } ;
HELP: equate
diff --git a/basis/dlists/dlists-docs.factor b/basis/dlists/dlists-docs.factor
index 5036441f60..8138feee6a 100644
--- a/basis/dlists/dlists-docs.factor
+++ b/basis/dlists/dlists-docs.factor
@@ -40,7 +40,7 @@ HELP:
{ $description "Creates a new " { $link search-deque } " backed by a " { $link dlist } ", with a " { $link hashtable } " for fast membership tests." } ;
HELP: dlist-find
-{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
+{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" 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
@@ -53,12 +53,12 @@ HELP: dlist-filter
{ $side-effects { "dlist" } } ;
HELP: dlist-any?
-{ $values { "dlist" { $link dlist } } { "quot" quotation } { "?" "a boolean" } }
+{ $values { "dlist" { $link dlist } } { "quot" quotation } { "?" 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 { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" "a boolean" } }
+{ $values { "dlist" { $link dlist } } { "quot" quotation } { "obj/f" "an object or " { $link f } } { "?" 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)." } ;
diff --git a/basis/dlists/dlists-tests.factor b/basis/dlists/dlists-tests.factor
index a4879d6ea3..5c650adabe 100644
--- a/basis/dlists/dlists-tests.factor
+++ b/basis/dlists/dlists-tests.factor
@@ -1,5 +1,5 @@
USING: accessors arrays classes deques dlists kernel locals
-math tools.test ;
+math sequences tools.test ;
IN: dlists.tests
[ t ] [ deque-empty? ] unit-test
@@ -148,3 +148,8 @@ TUPLE: my-node < dlist-link { obj fixnum } ;
] unit-test
+{ DL{ 0 1 2 3 4 } } [
+ [
+ { 3 2 4 1 0 } [ swap push-sorted drop ] with each
+ ] keep
+] unit-test
diff --git a/basis/dlists/dlists.factor b/basis/dlists/dlists.factor
index 297e5a5c25..8d1d47f5a4 100644
--- a/basis/dlists/dlists.factor
+++ b/basis/dlists/dlists.factor
@@ -1,9 +1,9 @@
! Copyright (C) 2007, 2009 Mackenzie Straight, Doug Coleman,
-! Slava Pestov.
+! Slava Pestov, John Benediktsson.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays combinators combinators.short-circuit
-deques fry hashtables kernel parser search-deques sequences
-summary vocabs.loader ;
+deques fry hashtables kernel math.order parser search-deques
+sequences summary vocabs.loader ;
IN: dlists
TUPLE: dlist-link { prev maybe{ dlist-link } } { next maybe{ dlist-link } } ;
@@ -192,6 +192,31 @@ M: dlist clear-deque ( dlist -- )
M: dlist clone
[ '[ _ push-back ] dlist-each ] keep ;
+> ] keep ] keep {
+ [ prev>> [ next<< ] [ drop ] if* ]
+ [ prev<< ]
+ [ drop ]
+ } 2cleave ; inline
+
+: push-before-node ( obj dlist-node dlist -- new-dlist-node )
+ 2dup front>> eq? [
+ nip push-front*
+ ] [
+ drop (push-before-node)
+ ] if ; inline
+
+PRIVATE>
+
+: push-before ( ... obj dlist quot: ( ... obj -- ... ? ) -- ... dlist-node )
+ [ obj>> ] prepose over [ dlist-find-node ] dip swap
+ [ swap push-before-node ] [ push-back* ] if* ; inline
+
+: push-sorted ( obj dlist -- dlist-node )
+ dupd [ before? ] with push-before ; inline
+
INSTANCE: dlist deque
SYNTAX: DL{ \ } [ >dlist ] parse-literal ;
diff --git a/basis/documents/documents-docs.factor b/basis/documents/documents-docs.factor
index 203a6e3b09..c540a149b3 100644
--- a/basis/documents/documents-docs.factor
+++ b/basis/documents/documents-docs.factor
@@ -1,4 +1,5 @@
-USING: help.markup help.syntax math models strings sequences ;
+USING: help.markup help.syntax kernel math models sequences
+strings ;
IN: documents
HELP: +col
@@ -20,7 +21,7 @@ HELP: =line
{ $description "Sets the line number of a line/column pair." } ;
HELP: lines-equal?
-{ $values { "loc1" "a pair of integers" } { "loc2" "a pair of integers" } { "?" "a boolean" } }
+{ $values { "loc1" "a pair of integers" } { "loc2" "a pair of integers" } { "?" boolean } }
{ $description "Tests if both line/column pairs have the same line number." } ;
HELP: document
@@ -42,7 +43,7 @@ HELP: doc-lines
{ $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;
HELP: each-line
-{ $values { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "quot" { $quotation "( ... line -- ... )" } } }
+{ $values { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "quot" { $quotation ( ... line -- ... ) } } }
{ $description "Applies the quotation to each line in the range." }
{ $notes "The range is created by calling " { $link } "." }
{ $errors "Throws an error if " { $snippet "from" } " or " { $snippet "to" } " is out of bounds." } ;
diff --git a/basis/documents/elements/elements-docs.factor b/basis/documents/elements/elements-docs.factor
index 6a3f57c15a..90c4a5f9e3 100644
--- a/basis/documents/elements/elements-docs.factor
+++ b/basis/documents/elements/elements-docs.factor
@@ -28,7 +28,7 @@ HELP: one-line-elt
{ one-line-elt line-elt } related-words
HELP: line-elt
-{ $class-description "An element representing a single line. The " { $link prev-elt } " and " { $link next-elt } " words return the location of the previous and next line from the current location." } ;
+{ $description "An element representing a single line. The " { $link prev-elt } " and " { $link next-elt } " words return the location of the previous and next line from the current location." } ;
HELP: doc-elt
{ $class-description "An element representing the entire document. The " { $link prev-elt } " word outputs the start of the document and the " { $link next-elt } " word outputs the end of the document." } ;
@@ -51,4 +51,4 @@ $nl
next-elt
} ;
-ABOUT: "documents.elements"
\ No newline at end of file
+ABOUT: "documents.elements"
diff --git a/basis/editors/atom/atom.factor b/basis/editors/atom/atom.factor
new file mode 100644
index 0000000000..b6e81ed430
--- /dev/null
+++ b/basis/editors/atom/atom.factor
@@ -0,0 +1,16 @@
+! Copyright (C) 2014 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: editors kernel make math.parser namespaces sequences ;
+IN: editors.atom
+
+SINGLETON: atom-editor
+atom-editor \ editor-class set-global
+
+SYMBOL: atom-path
+
+M: atom-editor editor-command ( file line -- command )
+ [
+ atom-path get "atom" or ,
+ number>string ":" glue ,
+ ] { } make ;
+
diff --git a/basis/editors/atom/authors.txt b/basis/editors/atom/authors.txt
new file mode 100644
index 0000000000..7c1b2f2279
--- /dev/null
+++ b/basis/editors/atom/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/editors/atom/summary.txt b/basis/editors/atom/summary.txt
new file mode 100644
index 0000000000..e29aa24b06
--- /dev/null
+++ b/basis/editors/atom/summary.txt
@@ -0,0 +1 @@
+Atom editor integration
diff --git a/basis/editors/atom/tags.txt b/basis/editors/atom/tags.txt
new file mode 100644
index 0000000000..ebb74b4d5f
--- /dev/null
+++ b/basis/editors/atom/tags.txt
@@ -0,0 +1 @@
+not loaded
diff --git a/basis/editors/geany/summary.txt b/basis/editors/geany/summary.txt
new file mode 100644
index 0000000000..8c602b0534
--- /dev/null
+++ b/basis/editors/geany/summary.txt
@@ -0,0 +1 @@
+Geany editor integration
diff --git a/basis/editors/notepad/summary.txt b/basis/editors/notepad/summary.txt
new file mode 100644
index 0000000000..c1575b834f
--- /dev/null
+++ b/basis/editors/notepad/summary.txt
@@ -0,0 +1 @@
+Notepad editor integration
diff --git a/basis/editors/sublime/sublime.factor b/basis/editors/sublime/sublime.factor
index 11ac974402..ff860bd194 100644
--- a/basis/editors/sublime/sublime.factor
+++ b/basis/editors/sublime/sublime.factor
@@ -12,7 +12,7 @@ HOOK: find-sublime-path os ( -- path )
M: object find-sublime-path "sublime" ;
M: macosx find-sublime-path
- "com.sublimetext.2" find-native-bundle [
+ { "com.sublimetext.3" "com.sublimetext.2" } [ find-native-bundle ] map-find drop [
"Contents/SharedSupport/bin/subl" append-path
] [
f
diff --git a/basis/editors/sublime/summary.txt b/basis/editors/sublime/summary.txt
new file mode 100644
index 0000000000..c4f74246b2
--- /dev/null
+++ b/basis/editors/sublime/summary.txt
@@ -0,0 +1 @@
+Sublime Text editor integration
diff --git a/basis/endian/endian.factor b/basis/endian/endian.factor
index 4dd5ecf407..4956d341d3 100644
--- a/basis/endian/endian.factor
+++ b/basis/endian/endian.factor
@@ -7,7 +7,7 @@ IN: endian
SINGLETONS: big-endian little-endian ;
: compute-native-endianness ( -- class )
- 1 int ][ char deref 0 = big-endian little-endian ? ;
+ 1 int ][ char deref 0 = big-endian little-endian ? ; foldable
SYMBOL: native-endianness
native-endianness [ compute-native-endianness ] initialize
diff --git a/basis/environment/environment-docs.factor b/basis/environment/environment-docs.factor
index 8e5ef8b352..823c9b35a4 100644
--- a/basis/environment/environment-docs.factor
+++ b/basis/environment/environment-docs.factor
@@ -31,7 +31,7 @@ HELP: os-env
} ;
HELP: change-os-env
-{ $values { "key" string } { "quot" { $quotation "( old -- new )" } } }
+{ $values { "key" string } { "quot" { $quotation ( old -- new ) } } }
{ $description "Applies a quotation to change the value stored in an environment variable." }
{ $examples
"This is an operating system-specific feature. On Unix, you can do:"
@@ -81,7 +81,11 @@ HELP: unset-os-env
"Names and values of environment variables are operating system-specific."
} ;
-{ os-env os-envs set-os-env unset-os-env set-os-envs set-os-envs-pointer change-os-env } related-words
+HELP: with-os-env
+{ $values { "value" string } { "key" string } { "quot" "quotation" } }
+{ $description "Calls a quotation with the " { $snippet "key" } " environment variable set to " { $snippet "value" } ", resetting the environment variable afterwards to its previous value." } ;
+
+{ os-env os-envs set-os-env unset-os-env set-os-envs set-os-envs-pointer change-os-env with-os-env } related-words
ARTICLE: "environment" "Environment variables"
diff --git a/basis/environment/environment-tests.factor b/basis/environment/environment-tests.factor
index 524cf89ccf..a34d1db452 100644
--- a/basis/environment/environment-tests.factor
+++ b/basis/environment/environment-tests.factor
@@ -35,3 +35,9 @@ os unix? [
! Issue #794, setting something to ``f`` is a memory protection fault on mac
[ ] [ f "dummy-env-variable-for-factor-test" set-os-env ] unit-test
+
+{ f "value" f } [
+ "factor-test-key" os-env
+ "value" "factor-test-key" [ "factor-test-key" os-env ] with-os-env
+ "factor-test-key" os-env
+] unit-test
diff --git a/basis/environment/environment.factor b/basis/environment/environment.factor
index 121751e07d..79c83733a3 100644
--- a/basis/environment/environment.factor
+++ b/basis/environment/environment.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: assocs combinators init kernel sequences splitting
-system vocabs vocabs.loader ;
+USING: assocs combinators continuations init kernel sequences
+splitting system vocabs vocabs.loader ;
IN: environment
HOOK: os-env os ( key -- value )
@@ -25,6 +25,10 @@ HOOK: set-os-envs-pointer os ( malloc -- )
: set-os-envs ( assoc -- )
[ "=" glue ] { } assoc>map (set-os-envs) ;
+: with-os-env ( value key quot -- )
+ over [ [ [ set-os-env ] 2curry ] [ compose ] bi* ] dip
+ [ os-env ] keep [ set-os-env ] 2curry [ ] cleanup ; inline
+
{
{ [ os unix? ] [ "environment.unix" require ] }
{ [ os windows? ] [ "environment.windows" require ] }
diff --git a/basis/environment/unix/unix.factor b/basis/environment/unix/unix.factor
index 96ad3759c4..855a4d1404 100644
--- a/basis/environment/unix/unix.factor
+++ b/basis/environment/unix/unix.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.data alien.strings
-alien.syntax kernel layouts sequences system unix
+alien.syntax kernel layouts libc sequences system unix
environment io.encodings.utf8 unix.utilities vocabs
combinators alien.accessors unix.ffi ;
IN: environment.unix
diff --git a/basis/formatting/formatting-docs.factor b/basis/formatting/formatting-docs.factor
index 314db36183..ce7800cdbd 100755
--- a/basis/formatting/formatting-docs.factor
+++ b/basis/formatting/formatting-docs.factor
@@ -6,7 +6,7 @@ IN: formatting
HELP: printf
{ $values { "format-string" string } }
{ $description
- "Writes the arguments (specified on the stack) formatted according to the format string."
+ "Writes the arguments (specified on the stack) formatted according to the format string."
$nl
"Several format specifications exist for handling arguments of different types, and "
"specifying attributes for the result string, including such things as maximum width, "
@@ -16,14 +16,17 @@ HELP: printf
{ { $snippet "%%" } "Single %" "" }
{ { $snippet "%P.Ds" } "String format" "string" }
{ { $snippet "%P.DS" } "String format uppercase" "string" }
- { { $snippet "%c" } "Character format" "char" }
- { { $snippet "%C" } "Character format uppercase" "char" }
- { { $snippet "%+Pd" } "Integer format" "fixnum" }
- { { $snippet "%+P.De" } "Scientific notation" "fixnum, float" }
- { { $snippet "%+P.DE" } "Scientific notation" "fixnum, float" }
- { { $snippet "%+P.Df" } "Fixed format" "fixnum, float" }
- { { $snippet "%+Px" } "Hexadecimal" "hex" }
- { { $snippet "%+PX" } "Hexadecimal uppercase" "hex" }
+ { { $snippet "%P.Du" } "Unparsed format" "object" }
+ { { $snippet "%c" } "Character format" "char" }
+ { { $snippet "%C" } "Character format uppercase" "char" }
+ { { $snippet "%+Pd" } "Integer format (base 10)" "integer" }
+ { { $snippet "%+Po" } "Octal format (base 8)" "integer" }
+ { { $snippet "%+Pb" } "Binary format (base 2)" "integer" }
+ { { $snippet "%+P.De" } "Scientific notation" "integer, float" }
+ { { $snippet "%+P.DE" } "Scientific notation" "integer, float" }
+ { { $snippet "%+P.Df" } "Fixed format" "integer, float" }
+ { { $snippet "%+Px" } "Hexadecimal (base 16)" "integer" }
+ { { $snippet "%+PX" } "Hexadecimal (base 16) uppercase" "integer" }
{ { $snippet "%[%?, %]" } "Sequence format" "sequence" }
{ { $snippet "%[%?: %? %]" } "Assocs format" "assocs" }
}
@@ -61,6 +64,10 @@ HELP: printf
"USING: formatting ;"
"0xff \"%04X\" printf"
"00FF" }
+ { $example
+ "USING: formatting ;"
+ "12 \"%b\" printf"
+ "1100" }
{ $example
"USING: formatting ;"
"1.23456789 \"%.3f\" printf"
@@ -81,11 +88,15 @@ HELP: printf
"USING: formatting ;"
"H{ { 1 2 } { 3 4 } } \"%[%d: %d %]\" printf"
"{ 1:2, 3:4 }" }
+ { $example
+ "USING: calendar formatting ;"
+ "3 years \"%u\" printf"
+ "T{ duration { year 3 } }" }
} ;
HELP: sprintf
{ $values { "format-string" string } { "result" string } }
-{ $description "Returns the arguments (specified on the stack) formatted according to the format string as a result string." }
+{ $description "Returns the arguments (specified on the stack) formatted according to the format string as a result string." }
{ $see-also printf } ;
HELP: strftime
@@ -136,5 +147,3 @@ ARTICLE: "formatting" "Formatted printing"
} ;
ABOUT: "formatting"
-
-
diff --git a/basis/formatting/formatting-tests.factor b/basis/formatting/formatting-tests.factor
index 0d70484b0b..a5a463ff04 100755
--- a/basis/formatting/formatting-tests.factor
+++ b/basis/formatting/formatting-tests.factor
@@ -3,7 +3,7 @@
USING: calendar kernel formatting tools.test system ;
IN: formatting.tests
-[ "%s" printf ] must-infer
+[ "%s" printf ] must-infer
[ "%s" sprintf ] must-infer
[ "" ] [ "" sprintf ] unit-test
@@ -20,6 +20,10 @@ IN: formatting.tests
[ "123.10" ] [ 123.1 "%01.2f" sprintf ] unit-test
[ "1.2346" ] [ 1.23456789 "%.4f" sprintf ] unit-test
[ " 1.23" ] [ 1.23456789 "%6.2f" sprintf ] unit-test
+[ "001100" ] [ 12 "%06b" sprintf ] unit-test
+[ "==14" ] [ 12 "%'=4o" sprintf ] unit-test
+
+{ "foo: 1 bar: 2" } [ { 1 2 3 } "foo: %d bar: %s" vsprintf ] unit-test
os windows? [
[ "1.234000e+008" ] [ 123400000 "%e" sprintf ] unit-test
diff --git a/basis/formatting/formatting.factor b/basis/formatting/formatting.factor
index c7e51581ad..1aedd07afb 100644
--- a/basis/formatting/formatting.factor
+++ b/basis/formatting/formatting.factor
@@ -1,10 +1,10 @@
! Copyright (C) 2008 John Benediktsson
! See http://factorcode.org/license.txt for BSD license
-USING: accessors arrays assocs calendar combinators fry kernel
-generalizations io io.streams.string macros math math.functions
-math.parser peg.ebnf quotations sequences splitting strings
-unicode.categories unicode.case vectors combinators.smart
-present ;
+USING: accessors arrays assocs calendar combinators
+combinators.smart fry generalizations io io.streams.string
+kernel macros math math.functions math.parser namespaces
+peg.ebnf present prettyprint quotations sequences strings
+unicode.case unicode.categories vectors ;
FROM: math.parser.private => format-float ;
IN: formatting
@@ -20,7 +20,7 @@ IN: formatting
{
{ CHAR: - [ [ 1 - ] dip remove-nth "-" prepend ] }
{ CHAR: + [ [ 1 - ] dip remove-nth "+" prepend ] }
- [ drop swap drop ]
+ [ drop nip ]
} case
] [ drop ] if
] when ;
@@ -56,12 +56,15 @@ width = (width_)? => [[ [ ] or ]]
digits_ = "." ([0-9])* => [[ second >digits ]]
digits = (digits_)? => [[ 6 or ]]
-fmt-% = "%" => [[ [ "%" ] ]]
+fmt-% = "%" => [[ "%" ]]
fmt-c = "c" => [[ [ 1string ] ]]
fmt-C = "C" => [[ [ 1string >upper ] ]]
fmt-s = "s" => [[ [ present ] ]]
fmt-S = "S" => [[ [ present >upper ] ]]
+fmt-u = "u" => [[ [ unparse ] ]]
fmt-d = "d" => [[ [ >integer number>string ] ]]
+fmt-o = "o" => [[ [ >integer >oct ] ]]
+fmt-b = "b" => [[ [ >integer >bin ] ]]
fmt-e = digits "e" => [[ first '[ _ format-scientific ] ]]
fmt-E = digits "E" => [[ first '[ _ format-scientific >upper ] ]]
fmt-f = digits "f" => [[ first '[ _ format-decimal ] ]]
@@ -69,10 +72,10 @@ fmt-x = "x" => [[ [ >hex ] ]]
fmt-X = "X" => [[ [ >hex >upper ] ]]
unknown = (.)* => [[ unknown-printf-directive ]]
-strings_ = fmt-c|fmt-C|fmt-s|fmt-S
+strings_ = fmt-c|fmt-C|fmt-s|fmt-S|fmt-u
strings = pad width strings_ => [[ compose-all ]]
-numbers_ = fmt-d|fmt-e|fmt-E|fmt-f|fmt-x|fmt-X
+numbers_ = fmt-d|fmt-o|fmt-b|fmt-e|fmt-E|fmt-f|fmt-x|fmt-X
numbers = sign pad numbers_ => [[ unclip-last prefix compose-all [ fix-sign ] append ]]
types = strings|numbers
@@ -81,23 +84,37 @@ lists = "[%" types ", %]" => [[ second '[ _ map ", " join "{ " prepend "
assocs = "[%" types ": %" types " %]" => [[ [ second ] [ fourth ] bi '[ unzip [ _ map ] dip _ map zip [ ":" join ] map ", " join "{ " prepend " }" append ] ]]
-formats = "%" (types|fmt-%|lists|assocs|unknown) => [[ second '[ _ dip ] ]]
+formats = "%" (types|fmt-%|lists|assocs|unknown) => [[ second ]]
-plain-text = (!("%").)+ => [[ >string '[ _ swap ] ]]
+plain-text = (!("%").)+ => [[ >string ]]
-text = (formats|plain-text)* => [[ [ [ [ push ] keep ] append ] map ]]
+text = (formats|plain-text)* => [[ ]]
;EBNF
PRIVATE>
MACRO: printf ( format-string -- )
- parse-printf [ length ] keep compose-all
- '[ _ @ [ write ] each ] ;
+ parse-printf [ [ callable? ] count ] keep [
+ dup string? [ 1quotation ] [ [ 1 - ] dip ] if
+ over [ ndip ] 2curry
+ ] map nip [ compose-all ] [ length ] bi '[
+ @ output-stream get [ stream-write ] curry _ napply
+ ] ;
: sprintf ( format-string -- result )
[ printf ] with-string-writer ; inline
+: vprintf ( seq format-string -- )
+ parse-printf output-stream get '[
+ dup string? [
+ [ unclip-slice ] dip call( x -- y )
+ ] unless _ stream-write
+ ] each drop ;
+
+: vsprintf ( seq format-string -- result )
+ [ vprintf ] with-string-writer ; inline
+
string 2 CHAR: 0 pad-head ; inline
@@ -133,27 +150,27 @@ MACRO: printf ( format-string -- )
EBNF: parse-strftime
-fmt-% = "%" => [[ [ "%" ] ]]
-fmt-a = "a" => [[ [ dup day-of-week day-abbreviation3 ] ]]
-fmt-A = "A" => [[ [ dup day-of-week day-name ] ]]
-fmt-b = "b" => [[ [ dup month>> month-abbreviation ] ]]
-fmt-B = "B" => [[ [ dup month>> month-name ] ]]
-fmt-c = "c" => [[ [ dup >datetime ] ]]
-fmt-d = "d" => [[ [ dup day>> pad-00 ] ]]
-fmt-H = "H" => [[ [ dup hour>> pad-00 ] ]]
-fmt-I = "I" => [[ [ dup hour>> dup 12 > [ 12 - ] when pad-00 ] ]]
-fmt-j = "j" => [[ [ dup day-of-year pad-000 ] ]]
-fmt-m = "m" => [[ [ dup month>> pad-00 ] ]]
-fmt-M = "M" => [[ [ dup minute>> pad-00 ] ]]
-fmt-p = "p" => [[ [ dup hour>> 12 < "AM" "PM" ? ] ]]
-fmt-S = "S" => [[ [ dup second>> floor pad-00 ] ]]
-fmt-U = "U" => [[ [ dup week-of-year-sunday pad-00 ] ]]
-fmt-w = "w" => [[ [ dup day-of-week number>string ] ]]
-fmt-W = "W" => [[ [ dup week-of-year-monday pad-00 ] ]]
-fmt-x = "x" => [[ [ dup >date ] ]]
-fmt-X = "X" => [[ [ dup >time ] ]]
-fmt-y = "y" => [[ [ dup year>> 100 mod pad-00 ] ]]
-fmt-Y = "Y" => [[ [ dup year>> number>string ] ]]
+fmt-% = "%" => [[ "%" ]]
+fmt-a = "a" => [[ [ day-of-week day-abbreviation3 ] ]]
+fmt-A = "A" => [[ [ day-of-week day-name ] ]]
+fmt-b = "b" => [[ [ month>> month-abbreviation ] ]]
+fmt-B = "B" => [[ [ month>> month-name ] ]]
+fmt-c = "c" => [[ [ >datetime ] ]]
+fmt-d = "d" => [[ [ day>> pad-00 ] ]]
+fmt-H = "H" => [[ [ hour>> pad-00 ] ]]
+fmt-I = "I" => [[ [ hour>> dup 12 > [ 12 - ] when pad-00 ] ]]
+fmt-j = "j" => [[ [ day-of-year pad-000 ] ]]
+fmt-m = "m" => [[ [ month>> pad-00 ] ]]
+fmt-M = "M" => [[ [ minute>> pad-00 ] ]]
+fmt-p = "p" => [[ [ hour>> 12 < "AM" "PM" ? ] ]]
+fmt-S = "S" => [[ [ second>> floor pad-00 ] ]]
+fmt-U = "U" => [[ [ week-of-year-sunday pad-00 ] ]]
+fmt-w = "w" => [[ [ day-of-week number>string ] ]]
+fmt-W = "W" => [[ [ week-of-year-monday pad-00 ] ]]
+fmt-x = "x" => [[ [ >date ] ]]
+fmt-X = "X" => [[ [ >time ] ]]
+fmt-y = "y" => [[ [ year>> 100 mod pad-00 ] ]]
+fmt-Y = "Y" => [[ [ year>> number>string ] ]]
fmt-Z = "Z" => [[ [ "Not yet implemented" throw ] ]]
unknown = (.)* => [[ "Unknown directive" throw ]]
@@ -161,16 +178,23 @@ formats_ = fmt-%|fmt-a|fmt-A|fmt-b|fmt-B|fmt-c|fmt-d|fmt-H|fmt-I|
fmt-j|fmt-m|fmt-M|fmt-p|fmt-S|fmt-U|fmt-w|fmt-W|fmt-x|
fmt-X|fmt-y|fmt-Y|fmt-Z|unknown
-formats = "%" (formats_) => [[ second '[ _ dip ] ]]
+formats = "%" (formats_) => [[ second ]]
-plain-text = (!("%").)+ => [[ >string '[ _ swap ] ]]
+plain-text = (!("%").)+ => [[ >string ]]
-text = (formats|plain-text)* => [[ reverse [ [ [ push ] keep ] append ] map ]]
+text = (formats|plain-text)* => [[ ]]
;EBNF
PRIVATE>
MACRO: strftime ( format-string -- )
- parse-strftime [ length ] keep [ ] join
- '[ _ @ reverse concat nip ] ;
+ parse-strftime [
+ dup string? [
+ '[ _ swap push-all ]
+ ] [
+ '[ over @ swap push-all ]
+ ] if
+ ] map '[
+ SBUF" " clone [ _ cleave drop ] keep "" like
+ ] ;
diff --git a/basis/ftp/server/server.factor b/basis/ftp/server/server.factor
index 80d699fd1f..acd106d2de 100644
--- a/basis/ftp/server/server.factor
+++ b/basis/ftp/server/server.factor
@@ -137,7 +137,7 @@ ERROR: type-error type ;
: handle-PWD ( obj -- )
drop
- display-directory get "\"" dup surround 257 server-response ;
+ display-directory "\"" dup surround 257 server-response ;
: handle-SYST ( obj -- )
drop
diff --git a/basis/furnace/actions/actions.factor b/basis/furnace/actions/actions.factor
index 19491acfc3..e01fb9e6e7 100644
--- a/basis/furnace/actions/actions.factor
+++ b/basis/furnace/actions/actions.factor
@@ -113,7 +113,7 @@ M: action modify-form
TUPLE: page-action < action template ;
: ( path -- response )
- resolve-template-path "text/html" ;
+ resolve-template-path ;
: ( -- page )
page-action new-action
diff --git a/basis/furnace/auth/auth-docs.factor b/basis/furnace/auth/auth-docs.factor
index b81edbd2bb..7aa771e37d 100644
--- a/basis/furnace/auth/auth-docs.factor
+++ b/basis/furnace/auth/auth-docs.factor
@@ -36,7 +36,7 @@ HELP: encode-password
HELP: have-capabilities?
{ $values
{ "capabilities" "a sequence of capabilities" }
- { "?" "a boolean" }
+ { "?" boolean }
}
{ $description "Tests if the currently logged-in user possesses the given capabilities." } ;
@@ -63,7 +63,7 @@ HELP: realm
{ $class-description "The class of authentication realms. See " { $link "furnace.auth.realms" } " for details." } ;
HELP: uchange
-{ $values { "quot" { $quotation "( old -- new )" } } { "key" symbol } }
+{ $values { "quot" { $quotation ( old -- new ) } } { "key" symbol } }
{ $description "Applies the quotation to the old value of the user profile variable, and assigns the resulting value back to the variable." } ;
HELP: uget
@@ -196,7 +196,7 @@ $nl
"Authentication realms can be adorned with additional functionality."
{ $subsections "furnace.auth.features" }
"An administration tool."
-{ $subsections "furnace.auth.user-admin" }
+{ $subsections "webapps.user-admin" }
"A concrete example."
{ $subsections "furnace.auth.example" } ;
diff --git a/basis/furnace/auth/basic/basic-tests.factor b/basis/furnace/auth/basic/basic-tests.factor
new file mode 100644
index 0000000000..63797607b3
--- /dev/null
+++ b/basis/furnace/auth/basic/basic-tests.factor
@@ -0,0 +1,13 @@
+! Copyright (C) 2013 Jon Harper.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors tools.test furnace.auth.basic http.server
+http.server.responses kernel http namespaces ;
+IN: furnace.auth.basic.tests
+
+CONSTANT: GET-AUTH "Basic Zm9vOmJhcg=="
+{ "foo" "bar" } [ GET-AUTH parse-basic-auth ] unit-test
+
+{ t } [ [ "GET" >>method init-request
+ "path" <304> "name"
+ call-responder* >boolean
+] with-scope ] unit-test
diff --git a/basis/furnace/auth/basic/basic.factor b/basis/furnace/auth/basic/basic.factor
index a9b367c5c9..802e489e74 100644
--- a/basis/furnace/auth/basic/basic.factor
+++ b/basis/furnace/auth/basic/basic.factor
@@ -27,3 +27,5 @@ M: basic-auth-realm logged-in-username ( realm -- uid )
drop
request get "authorization" header parse-basic-auth
dup [ over check-login swap and ] [ 2drop f ] if ;
+
+M: basic-auth-realm init-realm drop ;
diff --git a/basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor b/basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor
index a652e734a1..7758afd212 100644
--- a/basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor
+++ b/basis/furnace/auth/features/deactivate-user/deactivate-user-docs.factor
@@ -6,7 +6,7 @@ HELP: allow-deactivation
{ $description "Adds a " { $snippet "deactivate-user" } " action to an authentication realm." } ;
HELP: allow-deactivation?
-{ $values { "?" "a boolean" } }
+{ $values { "?" boolean } }
{ $description "Outputs true if the current authentication realm allows user profile deactivation." } ;
ARTICLE: "furnace.auth.features.deactivate-user" "User profile deactivation"
diff --git a/basis/furnace/auth/features/edit-profile/edit-profile-docs.factor b/basis/furnace/auth/features/edit-profile/edit-profile-docs.factor
index 1124ad43ec..be1276239c 100644
--- a/basis/furnace/auth/features/edit-profile/edit-profile-docs.factor
+++ b/basis/furnace/auth/features/edit-profile/edit-profile-docs.factor
@@ -6,7 +6,7 @@ HELP: allow-edit-profile
{ $description "Adds an " { $snippet "edit-profile" } " action to an authentication realm." } ;
HELP: allow-edit-profile?
-{ $values { "?" "a boolean" } }
+{ $values { "?" boolean } }
{ $description "Outputs true if the current authentication realm allows user profile editing." } ;
ARTICLE: "furnace.auth.features.edit-profile" "User profile editing"
diff --git a/basis/furnace/auth/features/recover-password/recover-password-docs.factor b/basis/furnace/auth/features/recover-password/recover-password-docs.factor
index 22fa95f23e..3248bb1952 100644
--- a/basis/furnace/auth/features/recover-password/recover-password-docs.factor
+++ b/basis/furnace/auth/features/recover-password/recover-password-docs.factor
@@ -6,7 +6,7 @@ HELP: allow-password-recovery
{ $description "Adds a " { $snippet "recover-password" } " action to an authentication realm." } ;
HELP: allow-password-recovery?
-{ $values { "?" "a boolean" } }
+{ $values { "?" boolean } }
{ $description "Outputs true if the current authentication realm allows user password recovery." } ;
HELP: lost-password-from
diff --git a/basis/furnace/auth/features/registration/registration-docs.factor b/basis/furnace/auth/features/registration/registration-docs.factor
index d64a14c869..49f397c829 100644
--- a/basis/furnace/auth/features/registration/registration-docs.factor
+++ b/basis/furnace/auth/features/registration/registration-docs.factor
@@ -6,7 +6,7 @@ HELP: allow-registration
{ $description "Adds a " { $snippet "registration" } " action to an authentication realm." } ;
HELP: allow-registration?
-{ $values { "?" "a boolean" } }
+{ $values { "?" boolean } }
{ $description "Outputs true if the current authentication realm allows user registration." } ;
ARTICLE: "furnace.auth.features.registration" "User registration"
diff --git a/basis/furnace/auth/providers/db/db-tests.factor b/basis/furnace/auth/providers/db/db-tests.factor
index f23a4a8527..18a9a350d2 100644
--- a/basis/furnace/auth/providers/db/db-tests.factor
+++ b/basis/furnace/auth/providers/db/db-tests.factor
@@ -4,14 +4,18 @@ furnace.auth.login
furnace.auth.providers
furnace.auth.providers.db tools.test
namespaces db db.sqlite db.tuples continuations
-io.files io.files.temp io.directories accessors kernel ;
+io.files io.files.temp io.directories accessors kernel
+sequences system ;
IN: furnace.auth.providers.db.tests
"test" realm set
-[ "auth-test.db" temp-file delete-file ] ignore-errors
+: auth-test-db-name ( -- string )
+ cpu name>> "auth-test." ".db" surround ;
-"auth-test.db" temp-file [
+[ auth-test-db-name temp-file delete-file ] ignore-errors
+
+auth-test-db-name temp-file [
user ensure-table
diff --git a/basis/furnace/conversations/conversations-docs.factor b/basis/furnace/conversations/conversations-docs.factor
index 443384147d..2f935c33e6 100644
--- a/basis/furnace/conversations/conversations-docs.factor
+++ b/basis/furnace/conversations/conversations-docs.factor
@@ -28,7 +28,7 @@ HELP: cset
{ $description "Sets the value of a conversation variable." } ;
HELP: cchange
-{ $values { "key" symbol } { "quot" { $quotation "( old -- new )" } } }
+{ $values { "key" symbol } { "quot" { $quotation ( old -- new ) } } }
{ $description "Applies the quotation to the old value of the conversation variable, and assigns the resulting value back to the variable." } ;
ARTICLE: "furnace.conversations" "Furnace conversation scope"
diff --git a/basis/furnace/db/db.factor b/basis/furnace/db/db.factor
index d771d1d2d7..c09be983bb 100644
--- a/basis/furnace/db/db.factor
+++ b/basis/furnace/db/db.factor
@@ -4,10 +4,10 @@ USING: kernel accessors continuations namespaces destructors
db db.private db.pools io.pools http.server http.server.filters ;
IN: furnace.db
-TUPLE: db-persistence < filter-responder pool ;
+TUPLE: db-persistence < filter-responder pool disposed ;
: ( responder db -- responder' )
- db-persistence boa ;
+ f db-persistence boa ;
M: db-persistence call-responder*
[
@@ -15,3 +15,5 @@ M: db-persistence call-responder*
[ return-connection-later ] [ drop db-connection set ] 2bi
]
[ call-next-method ] bi ;
+
+M: db-persistence dispose* pool>> dispose ;
diff --git a/basis/furnace/furnace-tests.factor b/basis/furnace/furnace-tests.factor
index 6fe2633031..ca1faa7729 100644
--- a/basis/furnace/furnace-tests.factor
+++ b/basis/furnace/furnace-tests.factor
@@ -14,7 +14,7 @@ C: base-path-check-responder
M: base-path-check-responder call-responder*
2drop
"$funny-dispatcher" resolve-base-path
- "text/plain" ;
+ ;
[ ] [
diff --git a/basis/furnace/sessions/sessions-docs.factor b/basis/furnace/sessions/sessions-docs.factor
index 605b04785c..e272f36fa1 100644
--- a/basis/furnace/sessions/sessions-docs.factor
+++ b/basis/furnace/sessions/sessions-docs.factor
@@ -11,7 +11,7 @@ HELP:
{ $description "Wraps a responder in a session manager responder." } ;
HELP: schange
-{ $values { "key" symbol } { "quot" { $quotation "( old -- new )" } } }
+{ $values { "key" symbol } { "quot" { $quotation ( old -- new ) } } }
{ $description "Applies the quotation to the old value of the session variable, and assigns the resulting value back to the variable." } ;
HELP: sget
diff --git a/basis/furnace/sessions/sessions-tests.factor b/basis/furnace/sessions/sessions-tests.factor
index 1ac3dbd51a..5e9e10591f 100644
--- a/basis/furnace/sessions/sessions-tests.factor
+++ b/basis/furnace/sessions/sessions-tests.factor
@@ -20,7 +20,7 @@ M: foo init-session* drop 0 "x" sset ;
M: foo call-responder*
2drop
"x" [ 1 + ] schange
- "x" sget number>string "text/html" ;
+ "x" sget number>string ;
: url-responder-mock-test ( -- string )
[
@@ -47,7 +47,7 @@ M: foo call-responder*
: ( -- action )
- [ [ ] "text/plain" exit-with ] >>display ;
+ [ [ ] exit-with ] >>display ;
[ "auth-test.db" temp-file delete-file ] ignore-errors
diff --git a/basis/furnace/utilities/utilities-docs.factor b/basis/furnace/utilities/utilities-docs.factor
index fc1828bbb6..1e5d89f889 100644
--- a/basis/furnace/utilities/utilities-docs.factor
+++ b/basis/furnace/utilities/utilities-docs.factor
@@ -16,7 +16,7 @@ HELP: client-state
{ $notes "This word is used by session management, conversation scope and asides." } ;
HELP: each-responder
-{ $values { "quot" { $quotation "( responder -- )" } } }
+{ $values { "quot" { $quotation ( ... responder -- ... ) } } }
{ $description "Applies the quotation to each responder involved in processing the current request." } ;
HELP: hidden-form-field
@@ -72,7 +72,7 @@ HELP: resolve-template-path
{ $description "Resolves a responder-relative template path." } ;
HELP: same-host?
-{ $values { "url" url } { "?" "a boolean" } }
+{ $values { "url" url } { "?" boolean } }
{ $description "Tests if the given URL is located on the same host as the URL of the current request." } ;
HELP: user-agent
@@ -88,7 +88,7 @@ HELP: exit-with
{ $description "Exits from an outer " { $link with-exit-continuation } "." } ;
HELP: with-exit-continuation
-{ $values { "quot" { $quotation { "( -- value )" } } } { "value" "a value returned by the quotation or an " { $link exit-with } " invocation" } }
+{ $values { "quot" { $quotation ( -- value ) } } { "value" "a value returned by the quotation or an " { $link exit-with } " invocation" } }
{ $description "Runs a quotation with the " { $link exit-continuation } " variable bound. Calling " { $link exit-with } " in the quotation will immediately return." }
{ $notes "Furnace actions and authentication realms wrap their execution in this combinator, allowing form validation failures and login requests, respectively, to immediately return an HTTP response to the client without running any more responder code." } ;
diff --git a/basis/furnace/utilities/utilities.factor b/basis/furnace/utilities/utilities.factor
index 9a82490482..61547131fc 100644
--- a/basis/furnace/utilities/utilities.factor
+++ b/basis/furnace/utilities/utilities.factor
@@ -24,7 +24,7 @@ ERROR: no-such-word name vocab ;
: nested-responders ( -- seq )
responder-nesting get values ;
-: each-responder ( quot -- )
+: each-responder ( quot: ( ... responder -- ... ) -- )
nested-responders swap each ; inline
ERROR: no-such-responder responder ;
diff --git a/basis/game/input/input-docs.factor b/basis/game/input/input-docs.factor
index 1ea5dcc650..58cc35af1c 100644
--- a/basis/game/input/input-docs.factor
+++ b/basis/game/input/input-docs.factor
@@ -47,7 +47,7 @@ HELP: close-game-input
{ $description "Closes the game input interface, releasing any allocated resources. Once this word is called, any remaining " { $link controller } " objects are invalid." } ;
HELP: game-input-opened?
-{ $values { "?" "a boolean" } }
+{ $values { "?" boolean } }
{ $description "Returns true if the game input interface is open, false otherwise." } ;
HELP: with-game-input
@@ -176,10 +176,10 @@ HELP: buttons-delta-as
{ button-delta buttons-delta buttons-delta-as } related-words
HELP: pressed
-{ $class-description "This symbol is returned by " { $link button-delta } " or " { $link buttons-delta } " to represent a button or key being pressed between two samples of its state." } ;
+{ $description "This symbol is returned by " { $link button-delta } " or " { $link buttons-delta } " to represent a button or key being pressed between two samples of its state." } ;
HELP: released
-{ $class-description "This symbol is returned by " { $link button-delta } " or " { $link buttons-delta } " to represent a button or key being released between two samples of its state." } ;
+{ $description "This symbol is returned by " { $link button-delta } " or " { $link buttons-delta } " to represent a button or key being released between two samples of its state." } ;
{ pressed released } related-words
diff --git a/basis/game/input/input.factor b/basis/game/input/input.factor
index edd30b89fa..51e1b84ec9 100644
--- a/basis/game/input/input.factor
+++ b/basis/game/input/input.factor
@@ -45,7 +45,7 @@ ERROR: game-input-not-open ;
: open-game-input ( -- )
game-input-opened? [
- (open-game-input)
+ (open-game-input)
] unless
game-input-opened [ 1 + ] change-global
reset-mouse ;
@@ -55,7 +55,7 @@ ERROR: game-input-not-open ;
1 -
] change-global
game-input-opened? [
- (close-game-input)
+ (close-game-input)
reset-game-input
] unless ;
@@ -79,7 +79,7 @@ SYMBOLS:
get-controllers [
[ product-id = ]
[ instance-id = ] bi-curry bi* and
- ] with with find nip ;
+ ] 2with find nip ;
TUPLE: keyboard-state keys ;
diff --git a/basis/game/input/xinput/xinput.factor b/basis/game/input/xinput/xinput.factor
index 70b5e14fa2..c51ec1e098 100644
--- a/basis/game/input/xinput/xinput.factor
+++ b/basis/game/input/xinput/xinput.factor
@@ -17,7 +17,7 @@ xinput-game-input-backend game-input-backend set-global
65535 * >fixnum 0 65535 clamp ; inline
MACRO: map-index-compose ( seq quot -- seq )
'[ '[ _ execute _ ] _ compose ] map-index 1quotation ;
-
+
: fill-buttons ( button-bitmap -- button-array )
10 0.0 dup rot >fixnum
{ XINPUT_GAMEPAD_START
@@ -114,8 +114,8 @@ M: xinput-game-input-backend instance-id
if ;
M: xinput-game-input-backend read-controller
- XINPUT_STATE [ XInputGetState ] keep
- swap drop fill-controller-state ;
+ XINPUT_STATE [ XInputGetState drop ] keep
+ fill-controller-state ;
M: xinput-game-input-backend calibrate-controller drop ;
diff --git a/basis/gdk/ffi/ffi.factor b/basis/gdk/ffi/ffi.factor
index 8a3f0da6d3..ad095ba66e 100644
--- a/basis/gdk/ffi/ffi.factor
+++ b/basis/gdk/ffi/ffi.factor
@@ -16,7 +16,8 @@ LIBRARY: gdk
<<
"gdk" {
{ [ os windows? ] [ "libgdk-win32-2.0-0.dll" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
+ { [ os macosx? ] [ drop ] }
+ { [ os unix? ] [ "libgdk-x11-2.0.so" cdecl add-library ] }
} cond
>>
diff --git a/basis/gdk/gl/ffi/ffi.factor b/basis/gdk/gl/ffi/ffi.factor
index 507550ff98..a1ff666c2e 100644
--- a/basis/gdk/gl/ffi/ffi.factor
+++ b/basis/gdk/gl/ffi/ffi.factor
@@ -10,4 +10,12 @@ IN: gdk.gl.ffi
LIBRARY: gdk.gl
+<<
+"gdk.gl" {
+ { [ os windows? ] [ "libgdkglext-win32-1.0-0.dll" cdecl add-library ] }
+ { [ os macosx? ] [ drop ] }
+ { [ os unix? ] [ "libgdkglext-x11-1.0.so" cdecl add-library ] }
+} cond
+>>
+
GIR: vocab:gdk/gl/GdkGLExt-1.0.gir
diff --git a/basis/gdk/pixbuf/ffi/ffi.factor b/basis/gdk/pixbuf/ffi/ffi.factor
index f8a8c7db88..f51f554bb5 100644
--- a/basis/gdk/pixbuf/ffi/ffi.factor
+++ b/basis/gdk/pixbuf/ffi/ffi.factor
@@ -1,6 +1,6 @@
! Copyright (C) 2010 Anton Gorenko.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.data alien.libraries alien.syntax
+USING: alien alien.c-types alien.data alien.libraries alien.syntax
combinators gio.ffi glib.ffi gobject-introspection
gobject-introspection.standard-types kernel libc
sequences system vocabs ;
@@ -15,17 +15,39 @@ LIBRARY: gdk.pixbuf
<<
"gdk.pixbuf" {
{ [ os windows? ] [ "libgdk_pixbuf-2.0-0.dll" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
+ { [ os macosx? ] [ "libgdk_pixbuf-2.0.dylib" cdecl add-library ] }
+ { [ os unix? ] [ "libgdk_pixbuf-2.0.so" cdecl add-library ] }
} cond
>>
GIR: vocab:gdk/pixbuf/GdkPixbuf-2.0.gir
-!
: data>GInputStream ( data -- GInputStream )
diff --git a/basis/generalizations/generalizations-docs.factor b/basis/generalizations/generalizations-docs.factor
index ea579aa83a..7a219522eb 100644
--- a/basis/generalizations/generalizations-docs.factor
+++ b/basis/generalizations/generalizations-docs.factor
@@ -97,8 +97,8 @@ HELP: nrot
{ $example "USING: arrays generalizations kernel prettyprint ;" "1 2 3 4 4 nrot 4array ." "{ 2 3 4 1 }" }
"Some core words expressed in terms of " { $link nrot } ":"
{ $table
- { { $link swap } { $snippet "1 nrot" } }
- { { $link rot } { $snippet "2 nrot" } }
+ { { $link swap } { $snippet "2 nrot" } }
+ { { $link rot } { $snippet "3 nrot" } }
}
} ;
@@ -111,8 +111,8 @@ HELP: -nrot
{ $example "USING: arrays generalizations kernel prettyprint ;" "1 2 3 4 4 -nrot 4array ." "{ 4 1 2 3 }" }
"Some core words expressed in terms of " { $link -nrot } ":"
{ $table
- { { $link swap } { $snippet "1 -nrot" } }
- { { $link -rot } { $snippet "2 -nrot" } }
+ { { $link swap } { $snippet "2 -nrot" } }
+ { { $link -rot } { $snippet "3 -nrot" } }
}
} ;
diff --git a/basis/gio/ffi/ffi.factor b/basis/gio/ffi/ffi.factor
index 96227b4679..e4df71e69b 100644
--- a/basis/gio/ffi/ffi.factor
+++ b/basis/gio/ffi/ffi.factor
@@ -13,7 +13,8 @@ LIBRARY: gio
<<
"gio" {
{ [ os windows? ] [ "libgio-2.0-0.dll" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
+ { [ os macosx? ] [ "libgio-2.0.dylib" cdecl add-library ] }
+ { [ os unix? ] [ "libgio-2.0.so" cdecl add-library ] }
} cond
>>
diff --git a/basis/glib/ffi/ffi.factor b/basis/glib/ffi/ffi.factor
index c7bca2e8be..eb96dd0133 100644
--- a/basis/glib/ffi/ffi.factor
+++ b/basis/glib/ffi/ffi.factor
@@ -12,7 +12,7 @@ LIBRARY: glib
"glib" {
{ [ os windows? ] [ "libglib-2.0-0.dll" cdecl add-library ] }
{ [ os macosx? ] [ "libglib-2.0.0.dylib" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
+ { [ os unix? ] [ "libglib-2.0.so" cdecl add-library ] }
} cond
>>
diff --git a/basis/gobject/ffi/ffi.factor b/basis/gobject/ffi/ffi.factor
index 919f9daa0f..ccdf210a1e 100644
--- a/basis/gobject/ffi/ffi.factor
+++ b/basis/gobject/ffi/ffi.factor
@@ -16,7 +16,8 @@ LIBRARY: gobject
<<
"gobject" {
{ [ os windows? ] [ "libobject-2.0-0.dll" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
+ { [ os macosx? ] [ "libgobject-2.0.dylib" cdecl add-library ] }
+ { [ os unix? ] [ "libgobject-2.0.so" cdecl add-library ] }
} cond
>>
diff --git a/basis/graphs/graphs-docs.factor b/basis/graphs/graphs-docs.factor
index 66e896065c..45f7f81ae7 100644
--- a/basis/graphs/graphs-docs.factor
+++ b/basis/graphs/graphs-docs.factor
@@ -28,5 +28,5 @@ HELP: remove-vertex
{ $side-effects "graph" } ;
HELP: closure
-{ $values { "vertex" object } { "quot" { $quotation "( vertex -- assoc )" } } { "assoc" "a new assoc" } }
+{ $values { "vertex" object } { "quot" { $quotation ( vertex -- assoc ) } } { "assoc" "a new assoc" } }
{ $description "Outputs a set of all vertices reachable from " { $snippet "vertex" } " via edges given by the quotation. The set always includes " { $snippet "vertex" } "." } ;
diff --git a/basis/graphs/graphs.factor b/basis/graphs/graphs.factor
index a1ab6c5dc3..ce561d96c9 100644
--- a/basis/graphs/graphs.factor
+++ b/basis/graphs/graphs.factor
@@ -14,7 +14,7 @@ IN: graphs
PRIVATE>
: add-vertex ( vertex edges graph -- )
- [ [ nest dupd set-at ] curry with each ] if-graph ; inline
+ [ [ nest conjoin ] curry with each ] if-graph ; inline
: add-vertex* ( vertex edges graph -- )
[
diff --git a/basis/grouping/grouping-docs.factor b/basis/grouping/grouping-docs.factor
index 80ec52faf5..2401db1a1a 100644
--- a/basis/grouping/grouping-docs.factor
+++ b/basis/grouping/grouping-docs.factor
@@ -1,4 +1,4 @@
-USING: help.markup help.syntax sequences strings ;
+USING: help.markup help.syntax kernel sequences strings ;
IN: grouping
ARTICLE: "grouping" "Groups and clumps"
@@ -65,7 +65,7 @@ $nl
"New groups are created by calling " { $link } "." } ;
HELP: group
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
{ $description "Splits the sequence into disjoint groups of " { $snippet "n" } " elements and collects the groups into a new array." }
{ $notes "If the sequence length is not a multiple of " { $snippet "n" } ", the final subsequence in the list will be shorter than " { $snippet "n" } " elements." }
{ $examples
@@ -73,7 +73,7 @@ HELP: group
} ;
HELP:
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "groups" groups } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "groups" groups } }
{ $description "Outputs a virtual sequence whose elements are slices of disjoint subsequences of " { $snippet "n" } " elements from the underlying sequence." }
{ $examples
{ $example
@@ -100,7 +100,7 @@ $nl
"New clumps are created by calling " { $link } "." } ;
HELP: clump
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
{ $description "Splits the sequence into overlapping clumps of " { $snippet "n" } " elements and collects the clumps into a new array." }
{ $notes "For an empty sequence, the result is an empty sequence. For a non empty sequence with a length smaller than " { $snippet "n" } ", the result will be an empty sequence." }
{ $examples
@@ -108,7 +108,7 @@ HELP: clump
} ;
HELP: circular-clump
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "array" "a sequence of sequences" } }
{ $description "Splits the sequence into overlapping clumps of " { $snippet "n" } " elements, wrapping around the end of the sequence, and collects the clumps into a new array." }
{ $notes "For an empty sequence, the result is an empty sequence." }
{ $examples
@@ -116,7 +116,7 @@ HELP: circular-clump
} ;
HELP:
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "clumps" clumps } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "clumps" clumps } }
{ $description "Outputs a virtual sequence whose elements are overlapping subsequences of " { $snippet "n" } " elements from the underlying sequence." }
{ $examples
"Running averages:"
@@ -136,7 +136,7 @@ HELP:
} ;
HELP:
-{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } { "clumps" clumps } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "clumps" clumps } }
{ $description "Outputs a virtual sequence whose elements are overlapping slices of " { $snippet "n" } " elements from the underlying sequence, starting with each of its elements and wrapping around the end of the sequence." }
{ $examples
{ $example
@@ -153,7 +153,7 @@ HELP:
{ } related-words
HELP: monotonic?
-{ $values { "seq" sequence } { "quot" { $quotation "( elt1 elt2 -- ? )" } } { "?" "a boolean" } }
+{ $values { "seq" sequence } { "quot" { $quotation ( elt1 elt2 -- ? ) } } { "?" boolean } }
{ $description "Applies the relation to successive pairs of elements in the sequence, testing for a truth value. The relation should be a transitive relation, such as a total order or an equality relation." }
{ $examples
"Testing if a sequence is non-decreasing:"
@@ -163,11 +163,11 @@ HELP: monotonic?
} ;
HELP: all-equal?
-{ $values { "seq" sequence } { "?" "a boolean" } }
+{ $values { "seq" sequence } { "?" boolean } }
{ $description "Tests if all elements in the sequence are equal. Yields true with an empty sequence." } ;
HELP: all-eq?
-{ $values { "seq" sequence } { "?" "a boolean" } }
+{ $values { "seq" sequence } { "?" boolean } }
{ $description "Tests if all elements in the sequence are the same identical object. Yields true with an empty sequence." } ;
{ monotonic? all-eq? all-equal? } related-words
diff --git a/basis/gtk/ffi/ffi.factor b/basis/gtk/ffi/ffi.factor
index 18e5615c70..e9b3238ba7 100644
--- a/basis/gtk/ffi/ffi.factor
+++ b/basis/gtk/ffi/ffi.factor
@@ -1,7 +1,7 @@
! Copyright (C) 2010 Anton Gorenko.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.destructors alien.libraries
-alien.syntax combinators gobject-introspection
+alien.libraries.finder alien.syntax assocs gobject-introspection
gobject-introspection.standard-types kernel pango.ffi system
vocabs ;
IN: gtk.ffi
@@ -15,9 +15,9 @@ LIBRARY: gtk
<<
"gtk" {
- { [ os windows? ] [ "libgtk-win32-2.0-0.dll" cdecl add-library ] }
- { [ os unix? ] [ drop ] }
-} cond
+ { linux "gtk-x11-2.0" }
+ { windows "libgtk-win32-2.0-0" }
+} os of [ find-library cdecl add-library ] [ drop ] if*
>>
IMPLEMENT-STRUCTS: GtkTreeIter ;
diff --git a/basis/heaps/heaps-docs.factor b/basis/heaps/heaps-docs.factor
index 8ceb7bb78f..3888951f6b 100644
--- a/basis/heaps/heaps-docs.factor
+++ b/basis/heaps/heaps-docs.factor
@@ -53,49 +53,49 @@ HELP:
{ $description "Create a new " { $link max-heap } "." } ;
HELP: heap-push
-{ $values { "value" object } { "key" "a comparable object" } { "heap" "a heap" } }
+{ $values { "value" object } { "key" "a comparable object" } { "heap" heap } }
{ $description "Push a pair onto a heap. The key must be comparable with all other keys by the " { $link <=> } " generic word." }
{ $side-effects "heap" } ;
HELP: heap-push*
-{ $values { "value" object } { "key" "a comparable object" } { "heap" "a heap" } { "entry" entry } }
+{ $values { "value" object } { "key" "a comparable object" } { "heap" heap } { "entry" entry } }
{ $description "Push a pair onto a heap, and output an entry which may later be passed to " { $link heap-delete } "." }
{ $side-effects "heap" } ;
HELP: heap-push-all
-{ $values { "assoc" assoc } { "heap" "a heap" } }
+{ $values { "assoc" assoc } { "heap" heap } }
{ $description "Push every key/value pair of an assoc onto a heap." }
{ $side-effects "heap" } ;
HELP: heap-peek
-{ $values { "heap" "a heap" } { "value" object } { "key" object } }
+{ $values { "heap" heap } { "value" object } { "key" object } }
{ $description "Output the first element in the heap, leaving it in the heap." } ;
HELP: heap-pop*
-{ $values { "heap" "a heap" } }
+{ $values { "heap" heap } }
{ $description "Remove the first element from the heap." }
{ $side-effects "heap" } ;
HELP: heap-pop
-{ $values { "heap" "a heap" } { "value" object } { "key" object } }
+{ $values { "heap" heap } { "value" object } { "key" object } }
{ $description "Output and remove the first element in the heap." }
{ $side-effects "heap" } ;
HELP: heap-empty?
-{ $values { "heap" "a heap" } { "?" "a boolean" } }
+{ $values { "heap" heap } { "?" boolean } }
{ $description "Tests if a heap has no nodes." } ;
HELP: heap-size
-{ $values { "heap" "a heap" } { "n" integer } }
+{ $values { "heap" heap } { "n" integer } }
{ $description "Returns the number of key/value pairs in the heap." } ;
HELP: heap-delete
-{ $values { "entry" entry } { "heap" "a heap" } }
+{ $values { "entry" entry } { "heap" heap } }
{ $description "Remove the specified entry from the heap." }
{ $errors "Throws an error if the entry is from another heap or if it has already been deleted." }
{ $side-effects "heap" } ;
HELP: slurp-heap
{ $values
- { "heap" "a heap" } { "quot" quotation } }
+ { "heap" heap } { "quot" quotation } }
{ $description "Removes values from a heap and processes them with the quotation until the heap is empty." } ;
diff --git a/basis/heaps/heaps.factor b/basis/heaps/heaps.factor
index 6193d9fa2c..dccf1e5e55 100644
--- a/basis/heaps/heaps.factor
+++ b/basis/heaps/heaps.factor
@@ -64,14 +64,15 @@ M: heap heap-size ( heap -- n )
[ right ] dip data-nth ; inline
: data-set-nth ( entry n heap -- )
- [ [ >>index drop ] [ ] 2bi ] dip
+ [ [ swap index<< ] 2keep ] dip
data>> set-nth-unsafe ; inline
: data-push ( entry heap -- n )
dup heap-size [
- swap 2dup data>> ensure 2drop data-set-nth
- ] [
- ] bi ; inline
+ swap
+ [ data>> ensure 2drop ]
+ [ data-set-nth ] 2bi
+ ] keep ; inline
: data-first ( heap -- entry )
data>> first ; inline
@@ -82,12 +83,11 @@ M: heap heap-size ( heap -- n )
GENERIC: heap-compare ( entry1 entry2 heap -- ? )
-: (heap-compare) ( entry1 entry2 heap -- <=> )
- drop [ key>> ] compare ; inline
+M: min-heap heap-compare
+ drop { entry entry } declare [ key>> ] bi@ after? ; inline
-M: min-heap heap-compare (heap-compare) +gt+ eq? ;
-
-M: max-heap heap-compare (heap-compare) +lt+ eq? ;
+M: max-heap heap-compare
+ drop { entry entry } declare [ key>> ] bi@ before? ; inline
: heap-bounds-check? ( m heap -- ? )
heap-size >= ; inline
@@ -135,12 +135,13 @@ DEFER: down-heap
] if ; inline recursive
: down-heap ( m heap -- )
- 2dup left-bounds-check? [ 2drop ] [ (down-heap) ] if ; inline recursive
+ 2dup left-bounds-check?
+ [ 2drop ] [ (down-heap) ] if ; inline recursive
PRIVATE>
M: heap heap-push* ( value key heap -- entry )
- [ dup ] [ data-push ] [ ] tri up-heap ;
+ [ dup ] [ data-push ] [ up-heap ] tri ;
: heap-push ( value key heap -- ) heap-push* drop ;
@@ -163,22 +164,20 @@ M: bad-heap-delete summary
index>> { fixnum } declare ; inline
M: heap heap-delete ( entry heap -- )
- [ entry>index ] [ ] bi
+ [ entry>index ] keep
2dup heap-size 1 - = [
nip data>> pop*
] [
[ nip data>> pop ]
[ data-set-nth ]
- [ ] 2tri
- down-heap
+ [ down-heap ] 2tri
] if ;
M: heap heap-pop* ( heap -- )
[ data-first ] keep heap-delete ;
M: heap heap-pop ( heap -- value key )
- [ data-first ] keep
- [ heap-delete ] [ drop ] 2bi >entry< ;
+ [ data-first dup ] keep heap-delete >entry< ;
: heap-pop-all ( heap -- alist )
[ dup heap-empty? not ]
@@ -198,5 +197,5 @@ ERROR: not-a-heap obj ;
: >min-heap ( assoc -- min-heap )
[ heap-push-all ] keep ;
-: >max-heap ( assoc -- min-heap )
+: >max-heap ( assoc -- max-heap )
[ heap-push-all ] keep ;
diff --git a/basis/help/cookbook/cookbook.factor b/basis/help/cookbook/cookbook.factor
index a10d49f6f7..f7a6133d97 100644
--- a/basis/help/cookbook/cookbook.factor
+++ b/basis/help/cookbook/cookbook.factor
@@ -239,10 +239,8 @@ command-line get [
"Now, the " { $snippet "grep.factor" } " script will start up much faster. See " { $link "images" } " for details."
{ $heading "Executable scripts" }
"It is also possible to make executable scripts. A Factor file can begin with a comment like the following:"
-{ $code "#! /usr/bin/env factor" }
+{ $code "#!/usr/bin/env factor" }
"If the text file is made executable, then it can be run, assuming the " { $snippet "factor" } " binary is in your " { $snippet "$PATH" } "."
-$nl
-"The space between " { $snippet "#!" } " and " { $snippet "/usr/bin/env" } " is necessary, since " { $link POSTPONE: #! } " is a parsing word, and a syntax error would otherwise result."
{ $references
{ }
"command-line"
diff --git a/basis/help/help-docs.factor b/basis/help/help-docs.factor
index bc1cbd7f64..9b0528080a 100644
--- a/basis/help/help-docs.factor
+++ b/basis/help/help-docs.factor
@@ -1,6 +1,6 @@
-USING: help.markup help.crossref help.stylesheet help.topics
-help.syntax definitions io prettyprint summary arrays math
-sequences vocabs strings see ;
+USING: arrays help.crossref help.markup help.stylesheet
+help.syntax help.topics io kernel math prettyprint quotations
+see sequences strings summary vocabs ;
IN: help
ARTICLE: "printing-elements" "Printing markup elements"
@@ -239,11 +239,11 @@ HELP: simple-element
{ $class-description "Class of simple elements, which are just arrays of elements." } ;
HELP: ($span)
-{ $values { "quot" "a quotation" } }
+{ $values { "quot" quotation } }
{ $description "Prints an inline markup element." } ;
HELP: ($block)
-{ $values { "quot" "a quotation" } }
+{ $values { "quot" quotation } }
{ $description "Prints a block markup element with newlines before and after." } ;
HELP: $heading
@@ -340,7 +340,7 @@ HELP: $link
} ;
HELP: textual-list
-{ $values { "seq" "a sequence" } { "quot" { $quotation "( elt -- )" } } }
+{ $values { "seq" sequence } { "quot" { $quotation ( elt -- ) } } }
{ $description "Applies the quotation to each element of the sequence, printing a comma between each pair of elements." }
{ $examples
{ $example "USING: help.markup io namespaces ;" "last-element off" "{ \"fish\" \"chips\" \"salt\" } [ write ] textual-list" "fish, chips, salt" }
@@ -406,7 +406,7 @@ HELP: $quotation
"Produces the text “a quotation with stack effect " { $emphasis "effect" } "”."
}
{ $examples
- { $markup-example { $quotation "( obj -- )" } }
+ { $markup-example { $quotation ( obj -- ) } }
} ;
HELP: $list
@@ -487,7 +487,7 @@ HELP: HELP:
HELP: ARTICLE:
{ $syntax "ARTICLE: topic title content... ;" }
-{ $values { "topic" "an object" } { "title" "a string" } { "content" "markup elements" } }
+{ $values { "topic" object } { "title" string } { "content" "markup elements" } }
{ $description "Defines a help article. String topic names are reserved for core documentation. Contributed modules should name articles by arrays, where the first element of an array identifies the module; for example, " { $snippet "{ \"httpd\" \"intro\" }" } "." }
{ $examples
{ $code
diff --git a/basis/help/help.factor b/basis/help/help.factor
index 60cba2fc88..afbcc7c849 100644
--- a/basis/help/help.factor
+++ b/basis/help/help.factor
@@ -16,7 +16,7 @@ GENERIC: word-help* ( word -- content )
] ?if ;
: $predicate ( element -- )
- { { "object" object } { "?" "a boolean" } } $values
+ { { "object" object } { "?" boolean } } $values
[
"Tests if the object is an instance of the " ,
first "predicating" word-prop <$link> ,
diff --git a/basis/help/html/html.factor b/basis/help/html/html.factor
index dc8bacc8e0..7930f165b6 100644
--- a/basis/help/html/html.factor
+++ b/basis/help/html/html.factor
@@ -1,11 +1,11 @@
! Copyright (C) 2008, 2011 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs debugger fry hashtables help
-help.home help.topics help.vocabs html html.streams
-io.directories io.encodings.binary io.encodings.utf8 io.files
-io.files.temp io.pathnames kernel make math.parser memoize
-namespaces sequences serialize sorting splitting unicode.case
-vocabs vocabs.hierarchy words xml.syntax xml.writer ;
+USING: accessors arrays assocs debugger fry help help.home
+help.topics help.vocabs html html.streams io.directories
+io.encodings.binary io.encodings.utf8 io.files io.files.temp
+io.pathnames kernel make math.parser memoize namespaces
+sequences serialize splitting tools.completion vocabs
+vocabs.hierarchy words xml.syntax xml.writer ;
FROM: io.encodings.ascii => ascii ;
FROM: ascii => ascii? ;
IN: help.html
@@ -47,7 +47,7 @@ M: vocab-author topic>filename* name>> "author" ;
M: f topic>filename* drop \ f topic>filename* ;
: topic>filename ( topic -- filename )
- topic>filename* dup [
+ topic>filename* [
[
% "-" %
dup array?
@@ -55,7 +55,7 @@ M: f topic>filename* drop \ f topic>filename* ;
[ escape-filename ]
if % ".html" %
] "" make
- ] [ 2drop f ] if ;
+ ] [ drop f ] if* ;
M: topic url-of topic>filename ;
@@ -98,7 +98,7 @@ M: pathname url-of
dup topic>filename utf8 [ help>html write-xml ] with-file-writer ;
: all-vocabs-really ( -- seq )
- all-vocabs-recursive >hashtable no-roots remove-redundant-prefixes
+ all-vocabs-recursive no-roots remove-redundant-prefixes
[ vocab-name "scratchpad" = not ] filter ;
: all-topics ( -- topics )
@@ -111,16 +111,26 @@ M: pathname url-of
] { } make ;
: serialize-index ( index file -- )
- [ [ [ topic>filename ] dip ] { } assoc-map-as object>bytes ] dip
- binary set-file-contents ;
+ binary [
+ [ [ topic>filename ] dip ] { } assoc-map-as serialize
+ ] with-file-writer ;
+
+: generate-article-index ( -- )
+ articles get [ [ >link ] [ article-title ] bi* ] assoc-map
+ "articles.idx" serialize-index ;
+
+: generate-word-index ( -- )
+ all-words [ dup name>> ] { } map>assoc
+ "words.idx" serialize-index ;
+
+: generate-vocab-index ( -- )
+ all-vocabs-really [ dup vocab-name ] { } map>assoc
+ "vocabs.idx" serialize-index ;
: generate-indices ( -- )
- articles get keys [ [ >link ] [ article-title ] bi ] { } map>assoc "articles.idx" serialize-index
- all-words [ dup name>> ] { } map>assoc "words.idx" serialize-index
- all-vocabs-really [ dup vocab-name ] { } map>assoc "vocabs.idx" serialize-index ;
-
-: (generate-help-files) ( -- )
- all-topics [ '[ _ generate-help-file ] try ] each ;
+ generate-article-index
+ generate-word-index
+ generate-vocab-index ;
: generate-help-files ( -- )
H{
@@ -128,7 +138,9 @@ M: pathname url-of
{ recent-words f }
{ recent-articles f }
{ recent-vocabs f }
- } [ (generate-help-files) ] with-variables ;
+ } [
+ all-topics [ '[ _ generate-help-file ] try ] each
+ ] with-variables ;
: generate-help ( -- )
"docs" cache-file
@@ -143,17 +155,8 @@ M: pathname url-of
MEMO: load-index ( name -- index )
binary file-contents bytes>object ;
-TUPLE: result title href ;
-
-: partition-exact ( string results -- results' )
- [ title>> = ] with partition append ;
-
: offline-apropos ( string index -- results )
- load-index over >lower
- '[ [ drop _ ] dip >lower subseq? ] assoc-filter
- [ swap result boa ] { } assoc>map
- [ title>> ] sort-with
- partition-exact ;
+ load-index completions ;
: article-apropos ( string -- results )
"articles.idx" offline-apropos ;
diff --git a/basis/help/lint/checks/checks-docs.factor b/basis/help/lint/checks/checks-docs.factor
new file mode 100644
index 0000000000..640337aec1
--- /dev/null
+++ b/basis/help/lint/checks/checks-docs.factor
@@ -0,0 +1,18 @@
+USING: help.markup help.syntax sequences words ;
+IN: help.lint.checks
+
+HELP: check-example
+{ $values { "element" sequence } }
+{ $description "Throws an error if the expected output from the $example is different from the expected, or if it leaks disposables." } ;
+
+HELP: check-values
+{ $values { "word" word } { "element" sequence } }
+{ $description "Throws an error if the $values pair doesnt match the declared stack effect." }
+{ $examples
+ { $unchecked-example
+ "USING: help.lint.checks math ;"
+ ": foo ( x -- y ) ;"
+ "\\ foo { $values { \"a\" number } { \"b\" number } } check-values"
+ "$values don't match stack effect; expected { \"x\" \"y\" }, got { \"a\" \"b\" }\n\nType :help for debugging help."
+ }
+} ;
diff --git a/basis/help/lint/checks/checks.factor b/basis/help/lint/checks/checks.factor
index b7cb680e87..a916a1bdcb 100644
--- a/basis/help/lint/checks/checks.factor
+++ b/basis/help/lint/checks/checks.factor
@@ -1,11 +1,12 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs classes combinators
-combinators.short-circuit definitions effects eval fry grouping
-help help.markup help.topics io.streams.string kernel macros
-namespaces sequences sequences.deep sets sorting splitting
-strings unicode.categories vocabs vocabs.loader words
-words.symbol summary debugger io ;
+USING: accessors arrays assocs classes classes.struct
+classes.tuple combinators combinators.short-circuit debugger
+definitions effects eval formatting fry grouping help
+help.markup help.topics io io.streams.string kernel macros
+namespaces sequences sequences.deep sets splitting strings
+summary unicode.categories vocabs vocabs.loader words
+words.constant words.symbol ;
FROM: sets => members ;
IN: help.lint.checks
@@ -20,31 +21,34 @@ SYMBOL: all-vocabs
SYMBOL: vocab-articles
: check-example ( element -- )
- '[
- _ rest [
- but-last "\n" join
- [ (eval>string) ] call( code -- output )
- "\n" ?tail drop
- ] keep
- last assert=
- ] vocabs-quot get call( quot -- ) ;
+ ! [
+ '[
+ _ rest [
+ but-last "\n" join
+ [ (eval>string) ] call( code -- output )
+ "\n" ?tail drop
+ ] keep
+ last assert=
+ ] vocabs-quot get call( quot -- ) ;
+ ! ] leaks members length [
+ ! "%d disposable(s) leaked in example" sprintf simple-lint-error
+ ! ] unless-zero ;
: check-examples ( element -- )
\ $example swap elements [ check-example ] each ;
: extract-values ( element -- seq )
- \ $values swap elements dup empty? [
- first rest keys
- ] unless ;
+ \ $values swap elements
+ [ f ] [ first rest keys ] if-empty ;
: extract-value-effects ( element -- seq )
- \ $values swap elements dup empty? [
- first rest [
- \ $quotation swap elements dup empty? [ drop f ] [
- first second
- ] if
+ \ $values swap elements [ f ] [
+ first rest [
+ \ $quotation swap elements [ f ] [
+ first second dup effect? [ effect>string ] when
+ ] if-empty
] map
- ] unless ;
+ ] if-empty ;
: effect-values ( word -- seq )
stack-effect
@@ -74,27 +78,27 @@ SYMBOL: vocab-articles
[ symbol? ]
[ parsing-word? ]
[ "declared-effect" word-prop not ]
+ [ constant? ]
} 1|| ;
+: skip-check-values? ( word element -- ? )
+ [ don't-check-word? ] [ contains-funky-elements? ] bi* or ;
+
: check-values ( word element -- )
- {
- [
- [ don't-check-word? ]
- [ contains-funky-elements? ]
- bi* or
- ] [
- [ effect-values ]
- [ extract-values ]
- bi* sequence=
- ]
- } 2|| [ "$values don't match stack effect" simple-lint-error ] unless ;
+ 2dup skip-check-values? [ 2drop ] [
+ [ effect-values ] [ extract-values ] bi* 2dup
+ sequence= [ 2drop ] [
+ "$values don't match stack effect; expected %u, got %u" sprintf
+ simple-lint-error
+ ] if
+ ] if ;
: check-value-effects ( word element -- )
- [ effect-effects ]
- [ extract-value-effects ]
- bi* [ 2dup and [ = ] [ 2drop t ] if ] 2all?
- [ "$quotation documentation in $values don't match stack effect" simple-lint-error ]
- unless ;
+ [ effect-effects ] [ extract-value-effects ] bi*
+ [ 2dup and [ = ] [ 2drop t ] if ] 2all? [
+ "$quotation stack effects in $values don't match"
+ simple-lint-error
+ ] unless ;
: check-nulls ( element -- )
\ $values swap elements
@@ -102,9 +106,8 @@ SYMBOL: vocab-articles
[ "$values should not contain null" simple-lint-error ] when ;
: check-see-also ( element -- )
- \ $see-also swap elements [
- rest all-unique? t assert=
- ] each ;
+ \ $see-also swap elements [ rest all-unique? ] all?
+ [ "$see-also are not unique" simple-lint-error ] unless ;
: vocab-exists? ( name -- ? )
[ lookup-vocab ] [ all-vocabs get member? ] bi or ;
@@ -144,10 +147,26 @@ SYMBOL: vocab-articles
simple-lint-error
] when ;
+: extract-slots ( elements -- seq )
+ [ dup pair? [ first \ $slot = ] [ drop f ] if ] deep-filter
+ [ second ] map ;
+
: check-class-description ( word element -- )
- [ class? not ]
- [ { $class-description } swap elements empty? not ] bi* and
- [ "A word that is not a class has a $class-description" simple-lint-error ] when ;
+ \ $class-description swap elements over class? [
+ [
+ dup struct-class? [ struct-slots ] [ all-slots ] if
+ [ name>> ] map
+ ] [ extract-slots ] bi*
+ [ swap member? not ] with filter [
+ ", " join "Described $slot does not exist: " prepend
+ simple-lint-error
+ ] unless-empty
+ ] [
+ nip empty? not [
+ "A word that is not a class has a $class-description"
+ simple-lint-error
+ ] when
+ ] if ;
: check-article-title ( article -- )
article-title first LETTER?
diff --git a/basis/help/lint/lint.factor b/basis/help/lint/lint.factor
index 7e8c2e8c94..890445f442 100644
--- a/basis/help/lint/lint.factor
+++ b/basis/help/lint/lint.factor
@@ -67,7 +67,7 @@ PRIVATE>
] check-something ;
: check-about ( vocab -- )
- vocab-link boa dup
+ dup
'[ _ vocab-help [ lookup-article drop ] when* ] check-something ;
: check-vocab ( vocab -- )
@@ -100,5 +100,3 @@ PRIVATE>
[ word-help not ] filter
[ article-parent ] filter
[ predicate? not ] filter ;
-
-MAIN: help-lint
diff --git a/basis/help/markup/markup.factor b/basis/help/markup/markup.factor
index f4a000ac64..eba7bfed52 100644
--- a/basis/help/markup/markup.factor
+++ b/basis/help/markup/markup.factor
@@ -43,6 +43,7 @@ M: simple-element print-element [ print-element ] each ;
M: string print-element [ write ] ($span) ;
M: array print-element unclip execute( arg -- ) ;
M: word print-element { } swap execute( arg -- ) ;
+M: effect print-element effect>string print-element ;
M: f print-element drop ;
: print-element* ( element style -- )
diff --git a/basis/help/search/summary b/basis/help/search/summary.txt
similarity index 100%
rename from basis/help/search/summary
rename to basis/help/search/summary.txt
diff --git a/basis/help/topics/topics-docs.factor b/basis/help/topics/topics-docs.factor
index 82cf78e70d..74dd405806 100644
--- a/basis/help/topics/topics-docs.factor
+++ b/basis/help/topics/topics-docs.factor
@@ -1,5 +1,5 @@
-USING: help.markup help.syntax help.crossref help io io.styles
-hashtables strings ;
+USING: help help.crossref help.markup help.syntax io.styles
+sequences strings words ;
IN: help.topics
HELP: articles
@@ -23,11 +23,11 @@ HELP: article-content
{ $description "Outputs the content of a specific help article." } ;
HELP: all-articles
-{ $values { "seq" "a sequence" } }
+{ $values { "seq" sequence } }
{ $description "Outputs a sequence of all help article names, and all words with documentation." } ;
HELP: elements
-{ $values { "elt-type" "a word" } { "element" "a markup element" } { "seq" "a new sequence" } }
+{ $values { "elt-type" word } { "element" "a markup element" } { "seq" "a new sequence" } }
{ $description "Outputs a sequence of all elements of type " { $snippet "elt-type" } " found by traversing " { $snippet "element" } "." } ;
HELP: collect-elements
diff --git a/basis/help/topics/topics.factor b/basis/help/topics/topics.factor
index 322b92eee3..995fcbca52 100644
--- a/basis/help/topics/topics.factor
+++ b/basis/help/topics/topics.factor
@@ -17,6 +17,7 @@ INSTANCE: word topic
GENERIC: >link ( obj -- obj )
M: link >link ;
+M: wrapper >link wrapped>> >link ;
M: vocab-spec >link ;
M: object >link link boa ;
M: f >link drop \ f >link ;
@@ -33,7 +34,7 @@ M: link summary
SYMBOL: articles
articles [ H{ } clone ] initialize
-
+
SYMBOL: article-xref
article-xref [ H{ } clone ] initialize
diff --git a/basis/help/tutorial/tutorial.factor b/basis/help/tutorial/tutorial.factor
index abdaf77e78..a87f005e35 100644
--- a/basis/help/tutorial/tutorial.factor
+++ b/basis/help/tutorial/tutorial.factor
@@ -113,7 +113,15 @@ $nl
"Now, you can run unit tests:"
{ $code "\"palindrome\" test" }
$nl
-"It should report that all tests have passed. Now you can read about " { $link "first-program-extend" } "." ;
+"It should report that all your tests have been run and there were no test failures, displaying the following output:"
+$nl
+{ $snippet
+ "Unit Test: { [ f ] [ \"hello\" palindrome? ] }"
+ "\n"
+ "Unit Test: { [ t ] [ \"racecar\" palindrome? ] }"
+}
+$nl
+"Now you can read about " { $link "first-program-extend" } "." ;
ARTICLE: "first-program-extend" "Extending your first program"
"Our palindrome program works well, however we'd like to extend it to ignore spaces and non-alphabetical characters in the input."
diff --git a/basis/hints/hints.factor b/basis/hints/hints.factor
index cb2fb94dff..9177b81cd9 100644
--- a/basis/hints/hints.factor
+++ b/basis/hints/hints.factor
@@ -119,7 +119,7 @@ set-specializer
\ member? { { array } { string } } set-specializer
-\ member-eq? { array } set-specializer
+\ member-eq? { { array } { string } } set-specializer
\ assoc-stack { vector } set-specializer
@@ -128,6 +128,10 @@ set-specializer
set-specializer
] each
+{ le> be> } [
+ { byte-array } set-specializer
+] each
+
\ base> { string fixnum } set-specializer
M\ hashtable at*
diff --git a/basis/html/forms/forms-docs.factor b/basis/html/forms/forms-docs.factor
index 9203ad31ae..bc678191ba 100644
--- a/basis/html/forms/forms-docs.factor
+++ b/basis/html/forms/forms-docs.factor
@@ -1,5 +1,6 @@
+USING: assocs help.markup help.syntax kernel quotations strings
+;
IN: html.forms
-USING: help.markup help.syntax strings quotations kernel assocs ;
HELP: ]