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

db4
John Benediktsson 2009-02-13 15:04:14 -08:00
commit daa0f94db7
257 changed files with 4982 additions and 2087 deletions

1
.gitignore vendored
View File

@ -24,3 +24,4 @@ build-support/wordsize
*.bak *.bak
.#* .#*
*.swo *.swo
checksums.txt

View File

@ -116,16 +116,22 @@ Now if $DISPLAY is set, running ./factor will start the UI.
* Running Factor on Windows XP/Vista * Running Factor on Windows XP/Vista
The Factor runtime is compiled into two binaries:
factor.com - a Windows console application
factor.exe - a Windows native application, without a console
If you did not download the binary package, you can bootstrap Factor in If you did not download the binary package, you can bootstrap Factor in
the command prompt: the command prompt using the console application:
factor.exe -i=boot.<cpu>.image factor.com -i=boot.<cpu>.image
Once bootstrapped, double-clicking factor.exe starts the Factor UI. Once bootstrapped, double-clicking factor.exe or factor.com starts
the Factor UI.
To run the listener in the command prompt: To run the listener in the command prompt:
factor.exe -run=listener factor.com -run=listener
* The Factor FAQ * The Factor FAQ

2
basis/alien/arrays/arrays.factor Normal file → Executable file
View File

@ -26,7 +26,7 @@ M: array box-return drop "void*" box-return ;
M: array stack-size drop "void*" stack-size ; M: array stack-size drop "void*" stack-size ;
M: array c-type-boxer-quot drop f ; M: array c-type-boxer-quot drop [ ] ;
M: array c-type-unboxer-quot drop [ >c-ptr ] ; M: array c-type-unboxer-quot drop [ >c-ptr ] ;

31
basis/alien/c-types/c-types.factor Normal file → Executable file
View File

@ -4,7 +4,7 @@ USING: byte-arrays arrays assocs kernel kernel.private libc math
namespaces make parser sequences strings words assocs splitting namespaces make parser sequences strings words assocs splitting
math.parser cpu.architecture alien alien.accessors quotations math.parser cpu.architecture alien alien.accessors quotations
layouts system compiler.units io.files io.encodings.binary layouts system compiler.units io.files io.encodings.binary
accessors combinators effects continuations fry ; accessors combinators effects continuations fry call classes ;
IN: alien.c-types IN: alien.c-types
DEFER: <int> DEFER: <int>
@ -13,18 +13,20 @@ DEFER: *char
: little-endian? ( -- ? ) 1 <int> *char 1 = ; foldable : little-endian? ( -- ? ) 1 <int> *char 1 = ; foldable
TUPLE: c-type TUPLE: c-type
class { class class initial: object }
boxer boxer-quot unboxer unboxer-quot boxer
getter setter { boxer-quot callable }
reg-class size align stack-align? ; unboxer
{ unboxer-quot callable }
: new-c-type ( class -- type ) { getter callable }
new { setter callable }
int-regs >>reg-class { reg-class initial: int-regs }
object >>class ; inline size
align
stack-align? ;
: <c-type> ( -- type ) : <c-type> ( -- type )
\ c-type new-c-type ; \ c-type new ;
SYMBOL: c-types SYMBOL: c-types
@ -185,6 +187,9 @@ M: f byte-length drop 0 ;
[ "Cannot read struct fields with this type" throw ] [ "Cannot read struct fields with this type" throw ]
] unless* ; ] unless* ;
: c-type-getter-boxer ( name -- quot )
[ c-getter ] [ c-type-boxer-quot ] bi append ;
: c-setter ( name -- quot ) : c-setter ( name -- quot )
c-type-setter [ c-type-setter [
[ "Cannot write struct fields with this type" throw ] [ "Cannot write struct fields with this type" throw ]
@ -221,7 +226,7 @@ M: f byte-length drop 0 ;
TUPLE: long-long-type < c-type ; TUPLE: long-long-type < c-type ;
: <long-long-type> ( -- type ) : <long-long-type> ( -- type )
long-long-type new-c-type ; long-long-type new ;
M: long-long-type unbox-parameter ( n type -- ) M: long-long-type unbox-parameter ( n type -- )
c-type-unboxer %unbox-long-long ; c-type-unboxer %unbox-long-long ;
@ -258,7 +263,7 @@ M: long-long-type box-return ( type -- )
unclip [ unclip [
[ [
dup word? [ dup word? [
def>> { } swap with-datastack first def>> call( -- object )
] when ] when
] map ] map
] dip prefix ] dip prefix

View File

@ -15,4 +15,4 @@ C-STRUCT: complex-holder
C{ 1.0 2.0 } <complex-holder> "h" set C{ 1.0 2.0 } <complex-holder> "h" set
] unit-test ] unit-test
[ C{ 1.0 2.0 } ] [ "h" get complex-holder-z ] unit-test [ C{ 1.0 2.0 } ] [ "h" get complex-holder-z ] unit-test

View File

@ -1,6 +1,13 @@
! Copyright (C) 2009 Slava Pestov. ! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien.complex.functor sequences kernel ; USING: alien.c-types alien.structs alien.complex.functor accessors
sequences kernel ;
IN: alien.complex IN: alien.complex
<< { "float" "double" } [ dup "complex-" prepend define-complex-type ] each >> <<
{ "float" "double" } [ dup "complex-" prepend define-complex-type ] each
! This overrides the fact that small structures are never returned
! in registers on NetBSD, Linux and Solaris running on 32-bit x86.
"complex-float" c-type t >>return-in-registers? drop
>>

View File

@ -12,15 +12,15 @@ T-imaginary DEFINES ${T}-imaginary
set-T-real DEFINES set-${T}-real set-T-real DEFINES set-${T}-real
set-T-imaginary DEFINES set-${T}-imaginary set-T-imaginary DEFINES set-${T}-imaginary
>T DEFINES >${T} <T> DEFINES <${T}>
T> DEFINES ${T}> *T DEFINES *${T}
WHERE WHERE
: >T ( z -- alien ) : <T> ( z -- alien )
>rect T <c-object> [ set-T-imaginary ] [ set-T-real ] [ ] tri ; inline >rect T <c-object> [ set-T-imaginary ] [ set-T-real ] [ ] tri ; inline
: T> ( alien -- z ) : *T ( alien -- z )
[ T-real ] [ T-imaginary ] bi rect> ; inline [ T-real ] [ T-imaginary ] bi rect> ; inline
T in get T in get
@ -28,8 +28,8 @@ T in get
define-struct define-struct
T c-type T c-type
T> 1quotation >>boxer-quot <T> 1quotation >>unboxer-quot
>T 1quotation >>unboxer-quot *T 1quotation >>boxer-quot
drop drop
;FUNCTOR ;FUNCTOR

View File

@ -0,0 +1,73 @@
! Copyright (C) 2009 Joe Groff
! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax kernel quotations sequences strings words.symbol ;
QUALIFIED-WITH: alien.syntax c
IN: alien.fortran
ARTICLE: "alien.fortran-abis" "Fortran ABIs"
"Fortran does not have a standard ABI like C does. Factor supports the following Fortran ABIs:"
{ $list
{ { $subsection gfortran-abi } " is used by gfortran, the Fortran compiler included with GCC 4." }
{ { $subsection f2c-abi } " is used by the F2C Fortran-to-C translator and G77, the Fortran compiler included with GCC 3.x and earlier. It is also used by gfortran when compiling with the -ff2c flag." }
{ { $subsection intel-unix-abi } " is used by the Intel Fortran Compiler on Linux and Mac OS X." }
{ { $subsection intel-windows-abi } " is used by the Intel Fortran Compiler on Windows." }
}
"A library's ABI is specified when that library is opened by the " { $link add-fortran-library } " word." ;
ARTICLE: "alien.fortran-types" "Fortran types"
"The Fortran FFI recognizes the following Fortran types:"
{ $list
{ { $snippet "INTEGER" } " specifies a four-byte integer value. Sized integers can be specified with " { $snippet "INTEGER*1" } ", " { $snippet "INTEGER*2" } ", " { $snippet "INTEGER*4" } ", and " { $snippet "INTEGER*8" } "." }
{ { $snippet "LOGICAL" } " specifies a four-byte boolean value. Sized booleans can be specified with " { $snippet "LOGICAL*1" } ", " { $snippet "LOGICAL*2" } ", " { $snippet "LOGICAL*4" } ", and " { $snippet "LOGICAL*8" } "." }
{ { $snippet "REAL" } " specifies a single-precision floating-point real value." }
{ { $snippet "DOUBLE-PRECISION" } " specifies a double-precision floating-point real value. The alias " { $snippet "REAL*8" } " is also recognized." }
{ { $snippet "COMPLEX" } " specifies a single-precision floating-point complex value." }
{ { $snippet "DOUBLE-COMPLEX" } " specifies a double-precision floating-point complex value. The alias " { $snippet "COMPLEX*16" } " is also recognized." }
{ { $snippet "CHARACTER(n)" } " specifies a character string of length " { $snippet "n" } ". The Fortran 77 syntax " { $snippet "CHARACTER*n" } " is also recognized." }
{ "Fortran arrays can be specified by suffixing a comma-separated set of dimensions in parentheses, e.g. " { $snippet "REAL(2,3,4)" } ". Arrays of unspecified length can be specified using " { $snippet "*" } " as a dimension. Arrays are passed in as flat " { $link "specialized-arrays" } "." }
{ "Fortran records defined by " { $link POSTPONE: RECORD: } " and C structs defined by " { $link POSTPONE: c:C-STRUCT: } " are also supported as parameter and return types." }
}
"When declaring the parameters of Fortran functions, an output argument can be specified by prefixing an exclamation point to the type name. This will cause the function word to leave the final value of the parameter on the stack." ;
HELP: FUNCTION:
{ $syntax "FUNCTION: RETURN-TYPE NAME ( [!]ARGUMENT-TYPE NAME, ... ) ;" }
{ $description "Declares a Fortran function binding with the given return type and arguments. See " { $link "alien.fortran-types" } " for a list of supported types." } ;
HELP: SUBROUTINE:
{ $syntax "SUBROUTINE: NAME ( [!]ARGUMENT-TYPE NAME, ... ) ;" }
{ $description "Declares a Fortran subroutine binding with the given arguments. See " { $link "alien.fortran-types" } " for a list of supported types." } ;
HELP: LIBRARY:
{ $syntax "LIBRARY: name" }
{ $values { "name" "a logical library name" } }
{ $description "Sets the logical library for subsequent " { $link POSTPONE: FUNCTION: } " and " { $link POSTPONE: SUBROUTINE: } " definitions. The given library name must have been opened with a previous call to " { $link add-fortran-library } "." } ;
HELP: RECORD:
{ $syntax "RECORD: NAME { \"TYPE\" \"SLOT\" } ... ;" }
{ $description "Defines a Fortran record type with the given slots. The record is defined as the corresponding C struct and can be used as a type for subsequent Fortran or C function declarations." } ;
HELP: add-fortran-library
{ $values { "name" string } { "soname" string } { "fortran-abi" symbol } }
{ $description "Opens the shared library in the file specified by " { $snippet "soname" } " under the logical name " { $snippet "name" } " so that it may be used in subsequent " { $link POSTPONE: LIBRARY: } " and " { $link fortran-invoke } " calls. Functions and subroutines from the library will be defined using the specified " { $snippet "fortran-abi" } ", which must be one of the supported " { $link "alien.fortran-abis" } "." }
;
HELP: fortran-invoke
{ $values
{ "return" string } { "library" string } { "procedure" string } { "parameters" sequence }
}
{ $description "Invokes the Fortran subroutine or function " { $snippet "procedure" } " in " { $snippet "library" } " with parameters specified by the " { $link "alien.fortran-types" } " specified in the " { $snippet "parameters" } " sequence. If the " { $snippet "return" } " value is " { $link f } ", no return value is expected, otherwise a return value of the specified Fortran type is expected. Input values are taken off the top of the datastack, and output values are left for the return value (if any) and any parameters specified as out parameters by prepending " { $snippet "\"!\"" } "." }
;
ARTICLE: "alien.fortran" "Fortran FFI"
"The " { $vocab-link "alien.fortran" } " vocabulary provides an interface to code in shared libraries written in Fortran."
{ $subsection "alien.fortran-types" }
{ $subsection "alien.fortran-abis" }
{ $subsection add-fortran-library }
{ $subsection POSTPONE: LIBRARY: }
{ $subsection POSTPONE: FUNCTION: }
{ $subsection POSTPONE: SUBROUTINE: }
{ $subsection POSTPONE: RECORD: }
{ $subsection fortran-invoke }
;
ABOUT: "alien.fortran"

View File

@ -0,0 +1,381 @@
! (c) 2009 Joe Groff, see BSD license
USING: accessors alien alien.c-types alien.complex
alien.fortran alien.fortran.private alien.strings alien.structs
arrays assocs byte-arrays combinators fry
generalizations io.encodings.ascii kernel macros
macros.expander namespaces sequences shuffle tools.test ;
IN: alien.fortran.tests
<< intel-unix-abi "(alien.fortran-tests)" (add-fortran-library) >>
LIBRARY: (alien.fortran-tests)
RECORD: FORTRAN_TEST_RECORD
{ "INTEGER" "FOO" }
{ "REAL(2)" "BAR" }
{ "CHARACTER*4" "BAS" } ;
intel-unix-abi fortran-abi [
! fortran-name>symbol-name
[ "fun_" ] [ "FUN" fortran-name>symbol-name ] unit-test
[ "fun_times_" ] [ "Fun_Times" fortran-name>symbol-name ] unit-test
[ "funtimes__" ] [ "FunTimes_" fortran-name>symbol-name ] unit-test
! fortran-type>c-type
[ "short" ]
[ "integer*2" fortran-type>c-type ] unit-test
[ "int" ]
[ "integer*4" fortran-type>c-type ] unit-test
[ "int" ]
[ "INTEGER" fortran-type>c-type ] unit-test
[ "longlong" ]
[ "iNteger*8" fortran-type>c-type ] unit-test
[ "int[0]" ]
[ "integer(*)" fortran-type>c-type ] unit-test
[ "int[0]" ]
[ "integer(3,*)" fortran-type>c-type ] unit-test
[ "int[3]" ]
[ "integer(3)" fortran-type>c-type ] unit-test
[ "int[6]" ]
[ "integer(3,2)" fortran-type>c-type ] unit-test
[ "int[24]" ]
[ "integer(4,3,2)" fortran-type>c-type ] unit-test
[ "char" ]
[ "character" fortran-type>c-type ] unit-test
[ "char" ]
[ "character*1" fortran-type>c-type ] unit-test
[ "char[17]" ]
[ "character*17" fortran-type>c-type ] unit-test
[ "char[17]" ]
[ "character(17)" fortran-type>c-type ] unit-test
[ "int" ]
[ "logical" fortran-type>c-type ] unit-test
[ "float" ]
[ "real" fortran-type>c-type ] unit-test
[ "double" ]
[ "double-precision" fortran-type>c-type ] unit-test
[ "float" ]
[ "real*4" fortran-type>c-type ] unit-test
[ "double" ]
[ "real*8" fortran-type>c-type ] unit-test
[ "complex-float" ]
[ "complex" fortran-type>c-type ] unit-test
[ "complex-double" ]
[ "double-complex" fortran-type>c-type ] unit-test
[ "complex-float" ]
[ "complex*8" fortran-type>c-type ] unit-test
[ "complex-double" ]
[ "complex*16" fortran-type>c-type ] unit-test
[ "fortran_test_record" ]
[ "fortran_test_record" fortran-type>c-type ] unit-test
! fortran-arg-type>c-type
[ "int*" { } ]
[ "integer" fortran-arg-type>c-type ] unit-test
[ "int*" { } ]
[ "integer(3)" fortran-arg-type>c-type ] unit-test
[ "int*" { } ]
[ "integer(*)" fortran-arg-type>c-type ] unit-test
[ "fortran_test_record*" { } ]
[ "fortran_test_record" fortran-arg-type>c-type ] unit-test
[ "char*" { } ]
[ "character" fortran-arg-type>c-type ] unit-test
[ "char*" { } ]
[ "character(1)" fortran-arg-type>c-type ] unit-test
[ "char*" { "long" } ]
[ "character(17)" fortran-arg-type>c-type ] unit-test
! fortran-ret-type>c-type
[ "char" { } ]
[ "character(1)" fortran-ret-type>c-type ] unit-test
[ "void" { "char*" "long" } ]
[ "character(17)" fortran-ret-type>c-type ] unit-test
[ "int" { } ]
[ "integer" fortran-ret-type>c-type ] unit-test
[ "int" { } ]
[ "logical" fortran-ret-type>c-type ] unit-test
[ "float" { } ]
[ "real" fortran-ret-type>c-type ] unit-test
[ "void" { "float*" } ]
[ "real(*)" fortran-ret-type>c-type ] unit-test
[ "double" { } ]
[ "double-precision" fortran-ret-type>c-type ] unit-test
[ "void" { "complex-float*" } ]
[ "complex" fortran-ret-type>c-type ] unit-test
[ "void" { "complex-double*" } ]
[ "double-complex" fortran-ret-type>c-type ] unit-test
[ "void" { "int*" } ]
[ "integer(*)" fortran-ret-type>c-type ] unit-test
[ "void" { "fortran_test_record*" } ]
[ "fortran_test_record" fortran-ret-type>c-type ] unit-test
! fortran-sig>c-sig
[ "float" { "int*" "char*" "float*" "double*" "long" } ]
[ "real" { "integer" "character*17" "real" "real*8" } fortran-sig>c-sig ]
unit-test
[ "char" { "char*" "char*" "int*" "long" } ]
[ "character(1)" { "character*17" "character" "integer" } fortran-sig>c-sig ]
unit-test
[ "void" { "char*" "long" "char*" "char*" "int*" "long" } ]
[ "character*18" { "character*17" "character" "integer" } fortran-sig>c-sig ]
unit-test
[ "void" { "complex-float*" "char*" "char*" "int*" "long" } ]
[ "complex" { "character*17" "character" "integer" } fortran-sig>c-sig ]
unit-test
! fortran-record>c-struct
[ {
{ "double" "ex" }
{ "float" "wye" }
{ "int" "zee" }
{ "char[20]" "woo" }
} ] [
{
{ "DOUBLE-PRECISION" "EX" }
{ "REAL" "WYE" }
{ "INTEGER" "ZEE" }
{ "CHARACTER(20)" "WOO" }
} fortran-record>c-struct
] unit-test
! RECORD:
[ 16 ] [ "fortran_test_record" heap-size ] unit-test
[ 0 ] [ "foo" "fortran_test_record" offset-of ] unit-test
[ 4 ] [ "bar" "fortran_test_record" offset-of ] unit-test
[ 12 ] [ "bas" "fortran_test_record" offset-of ] unit-test
! (fortran-invoke)
[ [
! [fortran-args>c-args]
{
[ {
[ ascii string>alien ]
[ <longlong> ]
[ <float> ]
[ <complex-float> ]
[ 1 0 ? <short> ]
} spread ]
[ { [ length ] [ drop ] [ drop ] [ drop ] [ drop ] } spread ]
} 5 ncleave
! [fortran-invoke]
[
"void" "funpack" "funtimes_"
{ "char*" "longlong*" "float*" "complex-float*" "short*" "long" }
alien-invoke
] 6 nkeep
! [fortran-results>]
shuffle( aa ba ca da ea ab -- aa ab ba ca da ea )
{
[ drop ]
[ drop ]
[ drop ]
[ *float ]
[ drop ]
[ drop ]
} spread
] ] [
f "funpack" "FUNTIMES" { "CHARACTER*12" "INTEGER*8" "!REAL" "COMPLEX" "LOGICAL*2" }
(fortran-invoke)
] unit-test
[ [
! [fortran-args>c-args]
{
[ { [ ] } spread ]
[ { [ drop ] } spread ]
} 1 ncleave
! [fortran-invoke]
[ "float" "funpack" "fun_times_" { "float*" } alien-invoke ]
1 nkeep
! [fortran-results>]
shuffle( reta aa -- reta aa )
{ [ ] [ drop ] } spread
] ] [
"REAL" "funpack" "FUN_TIMES" { "REAL(*)" }
(fortran-invoke)
] unit-test
[ [
! [<fortran-result>]
[ "complex-float" <c-object> ] 1 ndip
! [fortran-args>c-args]
{ [ { [ ] } spread ] [ { [ drop ] } spread ] } 1 ncleave
! [fortran-invoke]
[
"void" "funpack" "fun_times_"
{ "complex-float*" "float*" }
alien-invoke
] 2 nkeep
! [fortran-results>]
shuffle( reta aa -- reta aa )
{ [ *complex-float ] [ drop ] } spread
] ] [
"COMPLEX" "funpack" "FUN_TIMES" { "REAL(*)" }
(fortran-invoke)
] unit-test
[ [
! [<fortran-result>]
[ 20 <byte-array> 20 ] 0 ndip
! [fortran-invoke]
[
"void" "funpack" "fun_times_"
{ "char*" "long" }
alien-invoke
] 2 nkeep
! [fortran-results>]
shuffle( reta retb -- reta retb )
{ [ ] [ ascii alien>nstring ] } spread
] ] [
"CHARACTER*20" "funpack" "FUN_TIMES" { }
(fortran-invoke)
] unit-test
[ [
! [<fortran-result>]
[ 10 <byte-array> 10 ] 3 ndip
! [fortran-args>c-args]
{
[ {
[ ascii string>alien ]
[ <float> ]
[ ascii string>alien ]
} spread ]
[ { [ length ] [ drop ] [ length ] } spread ]
} 3 ncleave
! [fortran-invoke]
[
"void" "funpack" "fun_times_"
{ "char*" "long" "char*" "float*" "char*" "long" "long" }
alien-invoke
] 7 nkeep
! [fortran-results>]
shuffle( reta retb aa ba ca ab cb -- reta retb aa ab ba ca cb )
{
[ ]
[ ascii alien>nstring ]
[ ]
[ ascii alien>nstring ]
[ *float ]
[ ]
[ ascii alien>nstring ]
} spread
] ] [
"CHARACTER*10" "funpack" "FUN_TIMES" { "!CHARACTER*20" "!REAL" "!CHARACTER*30" }
(fortran-invoke)
] unit-test
] with-variable ! intel-unix-abi
intel-windows-abi fortran-abi [
[ "FUN" ] [ "FUN" fortran-name>symbol-name ] unit-test
[ "FUN_TIMES" ] [ "Fun_Times" fortran-name>symbol-name ] unit-test
[ "FUNTIMES_" ] [ "FunTimes_" fortran-name>symbol-name ] unit-test
] with-variable
f2c-abi fortran-abi [
[ "char[1]" ]
[ "character(1)" fortran-type>c-type ] unit-test
[ "char*" { "long" } ]
[ "character" fortran-arg-type>c-type ] unit-test
[ "void" { "char*" "long" } ]
[ "character" fortran-ret-type>c-type ] unit-test
[ "double" { } ]
[ "real" fortran-ret-type>c-type ] unit-test
[ "void" { "float*" } ]
[ "real(*)" fortran-ret-type>c-type ] unit-test
[ "fun_" ] [ "FUN" fortran-name>symbol-name ] unit-test
[ "fun_times__" ] [ "Fun_Times" fortran-name>symbol-name ] unit-test
[ "funtimes___" ] [ "FunTimes_" fortran-name>symbol-name ] unit-test
] with-variable
gfortran-abi fortran-abi [
[ "float" { } ]
[ "real" fortran-ret-type>c-type ] unit-test
[ "void" { "float*" } ]
[ "real(*)" fortran-ret-type>c-type ] unit-test
[ "complex-float" { } ]
[ "complex" fortran-ret-type>c-type ] unit-test
[ "complex-double" { } ]
[ "double-complex" fortran-ret-type>c-type ] unit-test
[ "char[1]" ]
[ "character(1)" fortran-type>c-type ] unit-test
[ "char*" { "long" } ]
[ "character" fortran-arg-type>c-type ] unit-test
[ "void" { "char*" "long" } ]
[ "character" fortran-ret-type>c-type ] unit-test
[ "complex-float" { } ]
[ "complex" fortran-ret-type>c-type ] unit-test
[ "complex-double" { } ]
[ "double-complex" fortran-ret-type>c-type ] unit-test
[ "void" { "complex-double*" } ]
[ "double-complex(3)" fortran-ret-type>c-type ] unit-test
] with-variable

View File

@ -0,0 +1,452 @@
! (c) 2009 Joe Groff, see BSD license
USING: accessors alien alien.c-types alien.complex alien.parser
alien.strings alien.structs alien.syntax arrays ascii assocs
byte-arrays combinators combinators.short-circuit fry generalizations
kernel lexer macros math math.parser namespaces parser sequences
splitting stack-checker vectors vocabs.parser words locals
io.encodings.ascii io.encodings.string shuffle effects math.ranges
math.order sorting strings system ;
IN: alien.fortran
SINGLETONS: f2c-abi gfortran-abi intel-unix-abi intel-windows-abi ;
<<
: add-f2c-libraries ( -- )
"I77" "libI77.so" "cdecl" add-library
"F77" "libF77.so" "cdecl" add-library ;
os netbsd? [ add-f2c-libraries ] when
>>
: alien>nstring ( alien len encoding -- string )
[ memory>byte-array ] dip decode ;
ERROR: invalid-fortran-type type ;
DEFER: fortran-sig>c-sig
DEFER: fortran-ret-type>c-type
DEFER: fortran-arg-type>c-type
DEFER: fortran-name>symbol-name
SYMBOL: library-fortran-abis
SYMBOL: fortran-abi
library-fortran-abis [ H{ } clone ] initialize
<PRIVATE
: lowercase-name-with-underscore ( name -- name' )
>lower "_" append ;
: lowercase-name-with-extra-underscore ( name -- name' )
>lower CHAR: _ over member?
[ "__" append ] [ "_" append ] if ;
HOOK: fortran-c-abi fortran-abi ( -- abi )
M: f2c-abi fortran-c-abi "cdecl" ;
M: gfortran-abi fortran-c-abi "cdecl" ;
M: intel-unix-abi fortran-c-abi "cdecl" ;
M: intel-windows-abi fortran-c-abi "cdecl" ;
HOOK: real-functions-return-double? fortran-abi ( -- ? )
M: f2c-abi real-functions-return-double? t ;
M: gfortran-abi real-functions-return-double? f ;
M: intel-unix-abi real-functions-return-double? f ;
M: intel-windows-abi real-functions-return-double? f ;
HOOK: complex-functions-return-by-value? fortran-abi ( -- ? )
M: f2c-abi complex-functions-return-by-value? f ;
M: gfortran-abi complex-functions-return-by-value? t ;
M: intel-unix-abi complex-functions-return-by-value? f ;
M: intel-windows-abi complex-functions-return-by-value? f ;
HOOK: character(1)-maps-to-char? fortran-abi ( -- ? )
M: f2c-abi character(1)-maps-to-char? f ;
M: gfortran-abi character(1)-maps-to-char? f ;
M: intel-unix-abi character(1)-maps-to-char? t ;
M: intel-windows-abi character(1)-maps-to-char? t ;
HOOK: mangle-name fortran-abi ( name -- name' )
M: f2c-abi mangle-name lowercase-name-with-extra-underscore ;
M: gfortran-abi mangle-name lowercase-name-with-underscore ;
M: intel-unix-abi mangle-name lowercase-name-with-underscore ;
M: intel-windows-abi mangle-name >upper ;
TUPLE: fortran-type dims size out? ;
TUPLE: number-type < fortran-type ;
TUPLE: integer-type < number-type ;
TUPLE: logical-type < integer-type ;
TUPLE: real-type < number-type ;
TUPLE: double-precision-type < number-type ;
TUPLE: character-type < fortran-type ;
TUPLE: misc-type < fortran-type name ;
TUPLE: complex-type < number-type ;
TUPLE: real-complex-type < complex-type ;
TUPLE: double-complex-type < complex-type ;
CONSTANT: fortran>c-types H{
{ "character" character-type }
{ "integer" integer-type }
{ "logical" logical-type }
{ "real" real-type }
{ "double-precision" double-precision-type }
{ "complex" real-complex-type }
{ "double-complex" double-complex-type }
}
: append-dimensions ( base-c-type type -- c-type )
dims>>
[ product number>string "[" "]" surround append ] when* ;
MACRO: size-case-type ( cases -- )
[ invalid-fortran-type ] suffix
'[ [ size>> _ case ] [ append-dimensions ] bi ] ;
: simple-type ( type base-c-type -- c-type )
swap
[ dup size>> [ invalid-fortran-type ] [ drop ] if ]
[ append-dimensions ] bi ;
: new-fortran-type ( out? dims size class -- type )
new [ [ (>>size) ] [ (>>dims) ] [ (>>out?) ] tri ] keep ;
GENERIC: (fortran-type>c-type) ( type -- c-type )
M: f (fortran-type>c-type) drop "void" ;
M: integer-type (fortran-type>c-type)
{
{ f [ "int" ] }
{ 1 [ "char" ] }
{ 2 [ "short" ] }
{ 4 [ "int" ] }
{ 8 [ "longlong" ] }
} size-case-type ;
M: real-type (fortran-type>c-type)
{
{ f [ "float" ] }
{ 4 [ "float" ] }
{ 8 [ "double" ] }
} size-case-type ;
M: real-complex-type (fortran-type>c-type)
{
{ f [ "complex-float" ] }
{ 8 [ "complex-float" ] }
{ 16 [ "complex-double" ] }
} size-case-type ;
M: double-precision-type (fortran-type>c-type)
"double" simple-type ;
M: double-complex-type (fortran-type>c-type)
"complex-double" simple-type ;
M: misc-type (fortran-type>c-type)
dup name>> simple-type ;
: single-char? ( character-type -- ? )
{ [ drop character(1)-maps-to-char? ] [ dims>> product 1 = ] } 1&& ;
: fix-character-type ( character-type -- character-type' )
clone dup size>>
[ dup dims>> [ invalid-fortran-type ] [ dup size>> 1array >>dims f >>size ] if ]
[ dup dims>> [ ] [ f >>dims ] if ] if
dup single-char? [ f >>dims ] when ;
M: character-type (fortran-type>c-type)
fix-character-type "char" simple-type ;
: dimension>number ( string -- number )
dup "*" = [ drop 0 ] [ string>number ] if ;
: parse-out ( string -- string' out? )
"!" ?head ;
: parse-dims ( string -- string' dim )
"(" split1 dup
[ ")" ?tail drop "," split [ [ blank? ] trim dimension>number ] map ] when ;
: parse-size ( string -- string' size )
"*" split1 dup [ string>number ] when ;
: (parse-fortran-type) ( fortran-type-string -- type )
parse-out swap parse-dims swap parse-size swap
dup >lower fortran>c-types at*
[ nip new-fortran-type ] [ drop misc-type boa ] if ;
: parse-fortran-type ( fortran-type-string/f -- type/f )
dup [ (parse-fortran-type) ] when ;
: c-type>pointer ( c-type -- c-type* )
"[" split1 drop "*" append ;
GENERIC: added-c-args ( type -- args )
M: fortran-type added-c-args drop { } ;
M: character-type added-c-args fix-character-type single-char? [ { } ] [ { "long" } ] if ;
GENERIC: returns-by-value? ( type -- ? )
M: f returns-by-value? drop t ;
M: fortran-type returns-by-value? drop f ;
M: number-type returns-by-value? dims>> not ;
M: character-type returns-by-value? fix-character-type single-char? ;
M: complex-type returns-by-value?
{ [ drop complex-functions-return-by-value? ] [ dims>> not ] } 1&& ;
GENERIC: (fortran-ret-type>c-type) ( type -- c-type )
M: f (fortran-ret-type>c-type) drop "void" ;
M: fortran-type (fortran-ret-type>c-type) (fortran-type>c-type) ;
M: real-type (fortran-ret-type>c-type)
drop real-functions-return-double? [ "double" ] [ "float" ] if ;
: suffix! ( seq elt -- seq ) over push ; inline
: append! ( seq-a seq-b -- seq-a ) over push-all ; inline
GENERIC: (fortran-arg>c-args) ( type -- main-quot added-quot )
: args?dims ( type quot -- main-quot added-quot )
[ dup dims>> [ drop [ ] [ drop ] ] ] dip if ; inline
M: integer-type (fortran-arg>c-args)
[
size>> {
{ f [ [ <int> ] [ drop ] ] }
{ 1 [ [ <char> ] [ drop ] ] }
{ 2 [ [ <short> ] [ drop ] ] }
{ 4 [ [ <int> ] [ drop ] ] }
{ 8 [ [ <longlong> ] [ drop ] ] }
[ invalid-fortran-type ]
} case
] args?dims ;
M: logical-type (fortran-arg>c-args)
[ call-next-method [ [ 1 0 ? ] prepend ] dip ] args?dims ;
M: real-type (fortran-arg>c-args)
[
size>> {
{ f [ [ <float> ] [ drop ] ] }
{ 4 [ [ <float> ] [ drop ] ] }
{ 8 [ [ <double> ] [ drop ] ] }
[ invalid-fortran-type ]
} case
] args?dims ;
M: real-complex-type (fortran-arg>c-args)
[
size>> {
{ f [ [ <complex-float> ] [ drop ] ] }
{ 8 [ [ <complex-float> ] [ drop ] ] }
{ 16 [ [ <complex-double> ] [ drop ] ] }
[ invalid-fortran-type ]
} case
] args?dims ;
M: double-precision-type (fortran-arg>c-args)
[ drop [ <double> ] [ drop ] ] args?dims ;
M: double-complex-type (fortran-arg>c-args)
[ drop [ <complex-double> ] [ drop ] ] args?dims ;
M: character-type (fortran-arg>c-args)
fix-character-type single-char?
[ [ first <char> ] [ drop ] ]
[ [ ascii string>alien ] [ length ] ] if ;
M: misc-type (fortran-arg>c-args)
drop [ ] [ drop ] ;
GENERIC: (fortran-result>) ( type -- quots )
: result?dims ( type quot -- quot )
[ dup dims>> [ drop { [ ] } ] ] dip if ; inline
M: integer-type (fortran-result>)
[ size>> {
{ f [ { [ *int ] } ] }
{ 1 [ { [ *char ] } ] }
{ 2 [ { [ *short ] } ] }
{ 4 [ { [ *int ] } ] }
{ 8 [ { [ *longlong ] } ] }
[ invalid-fortran-type ]
} case ] result?dims ;
M: logical-type (fortran-result>)
[ call-next-method first [ zero? not ] append 1array ] result?dims ;
M: real-type (fortran-result>)
[ size>> {
{ f [ { [ *float ] } ] }
{ 4 [ { [ *float ] } ] }
{ 8 [ { [ *double ] } ] }
[ invalid-fortran-type ]
} case ] result?dims ;
M: real-complex-type (fortran-result>)
[ size>> {
{ f [ { [ *complex-float ] } ] }
{ 8 [ { [ *complex-float ] } ] }
{ 16 [ { [ *complex-double ] } ] }
[ invalid-fortran-type ]
} case ] result?dims ;
M: double-precision-type (fortran-result>)
[ drop { [ *double ] } ] result?dims ;
M: double-complex-type (fortran-result>)
[ drop { [ *complex-double ] } ] result?dims ;
M: character-type (fortran-result>)
fix-character-type single-char?
[ { [ *char 1string ] } ]
[ { [ ] [ ascii alien>nstring ] } ] if ;
M: misc-type (fortran-result>)
drop { [ ] } ;
GENERIC: (<fortran-result>) ( type -- quot )
M: fortran-type (<fortran-result>)
(fortran-type>c-type) \ <c-object> [ ] 2sequence ;
M: character-type (<fortran-result>)
fix-character-type dims>> product dup
[ \ <byte-array> ] dip [ ] 3sequence ;
: [<fortran-result>] ( return parameters -- quot )
[ parse-fortran-type ] dip
over returns-by-value?
[ 2drop [ ] ]
[ [ (<fortran-result>) ] [ length \ ndip [ ] 3sequence ] bi* ] if ;
: [fortran-args>c-args] ( parameters -- quot )
[ [ ] ] [
[ parse-fortran-type (fortran-arg>c-args) 2array ] map flip first2
[ [ \ spread [ ] 2sequence ] bi@ 2array ] [ length ] bi
\ ncleave [ ] 3sequence
] if-empty ;
:: [fortran-invoke] ( [args>args] return library function parameters -- [args>args] quot )
return parameters fortran-sig>c-sig :> c-parameters :> c-return
function fortran-name>symbol-name :> c-function
[args>args]
c-return library c-function c-parameters \ alien-invoke
5 [ ] nsequence
c-parameters length \ nkeep
[ ] 3sequence ;
: [fortran-out-param>] ( parameter -- quot )
parse-fortran-type
[ (fortran-result>) ] [ out?>> ] bi
[ ] [ [ drop [ drop ] ] map ] if ;
: [fortran-return>] ( return -- quot )
parse-fortran-type {
{ [ dup not ] [ drop { } ] }
{ [ dup returns-by-value? ] [ drop { [ ] } ] }
[ (fortran-result>) ]
} cond ;
: letters ( -- seq ) CHAR: a CHAR: z [a,b] ;
: (shuffle-map) ( return parameters -- ret par )
[
fortran-ret-type>c-type length swap "void" = [ 1+ ] unless
letters swap head [ "ret" swap suffix ] map
] [
[ fortran-arg-type>c-type nip length 1+ ] map letters swap zip
[ first2 letters swap head [ "" 2sequence ] with map ] map concat
] bi* ;
: (fortran-in-shuffle) ( ret par -- seq )
[ [ second ] bi@ <=> ] sort append ;
: (fortran-out-shuffle) ( ret par -- seq )
append ;
: [fortran-result-shuffle] ( return parameters -- quot )
(shuffle-map) [ (fortran-in-shuffle) ] [ (fortran-out-shuffle) ] 2bi <effect>
\ shuffle-effect [ ] 2sequence ;
: [fortran-results>] ( return parameters -- quot )
[ [fortran-result-shuffle] ]
[ drop [fortran-return>] ]
[ nip [ [fortran-out-param>] ] map concat ] 2tri
append
\ spread [ ] 2sequence append ;
: (add-fortran-library) ( fortran-abi name -- )
library-fortran-abis get-global set-at ;
PRIVATE>
: add-fortran-library ( name soname fortran-abi -- )
[ fortran-abi [ fortran-c-abi ] with-variable add-library ]
[ nip swap (add-fortran-library) ] 3bi ;
: fortran-name>symbol-name ( fortran-name -- c-name )
mangle-name ;
: fortran-type>c-type ( fortran-type -- c-type )
parse-fortran-type (fortran-type>c-type) ;
: fortran-arg-type>c-type ( fortran-type -- c-type added-args )
parse-fortran-type
[ (fortran-type>c-type) c-type>pointer ]
[ added-c-args ] bi ;
: fortran-ret-type>c-type ( fortran-type -- c-type added-args )
parse-fortran-type dup returns-by-value?
[ (fortran-ret-type>c-type) { } ] [
"void" swap
[ added-c-args ] [ (fortran-type>c-type) c-type>pointer ] bi prefix
] if ;
: fortran-arg-types>c-types ( fortran-types -- c-types )
[ length <vector> 1 <vector> ] keep
[ fortran-arg-type>c-type swapd [ suffix! ] [ append! ] 2bi* ] each
append >array ;
: fortran-sig>c-sig ( fortran-return fortran-args -- c-return c-args )
[ fortran-ret-type>c-type ] [ fortran-arg-types>c-types ] bi* append ;
: fortran-record>c-struct ( record -- struct )
[ first2 [ fortran-type>c-type ] [ >lower ] bi* 2array ] map ;
: define-fortran-record ( name vocab fields -- )
[ >lower ] [ ] [ fortran-record>c-struct ] tri* define-struct ;
: RECORD: scan in get parse-definition define-fortran-record ; parsing
: set-fortran-abi ( library -- )
library-fortran-abis get-global at fortran-abi set ;
: (fortran-invoke) ( return library function parameters -- quot )
{
[ 2nip [<fortran-result>] ]
[ nip nip nip [fortran-args>c-args] ]
[ [fortran-invoke] ]
[ 2nip [fortran-results>] ]
} 4 ncleave 4 nappend ;
MACRO: fortran-invoke ( return library function parameters -- )
{ [ 2drop nip set-fortran-abi ] [ (fortran-invoke) ] } 4 ncleave ;
:: define-fortran-function ( return library function parameters -- )
function create-in dup reset-generic
return library function parameters return [ "void" ] unless* parse-arglist
[ \ fortran-invoke 5 [ ] nsequence ] dip define-declared ;
: SUBROUTINE:
f "c-library" get scan ";" parse-tokens
[ "()" subseq? not ] filter define-fortran-function ; parsing
: FUNCTION:
scan "c-library" get scan ";" parse-tokens
[ "()" subseq? not ] filter define-fortran-function ; parsing
: LIBRARY:
scan
[ "c-library" set ]
[ set-fortran-abi ] bi ; parsing

View File

@ -0,0 +1 @@
GNU Fortran/G77/F2C alien interface

View File

@ -0,0 +1,2 @@
fortran
ffi

View File

@ -58,10 +58,7 @@ PREDICATE: slot-writer < word "writing" word-prop >boolean ;
: define-getter ( type spec -- ) : define-getter ( type spec -- )
[ set-reader-props ] keep [ set-reader-props ] keep
[ reader>> ] [ reader>> ]
[ [ type>> c-type-getter-boxer ]
type>>
[ c-getter ] [ c-type-boxer-quot ] bi append
]
[ ] tri [ ] tri
(( c-ptr -- value )) define-struct-slot-word ; (( c-ptr -- value )) define-struct-slot-word ;

15
basis/alien/structs/structs-tests.factor Normal file → Executable file
View File

@ -42,3 +42,18 @@ C-UNION: barx
[ ] [ \ foox-x "help" get execute ] unit-test [ ] [ \ foox-x "help" get execute ] unit-test
[ ] [ \ set-foox-x "help" get execute ] unit-test [ ] [ \ set-foox-x "help" get execute ] unit-test
] when ] when
C-STRUCT: nested
{ "int" "x" } ;
C-STRUCT: nested-2
{ "nested" "y" } ;
[ 4 ] [
"nested-2" <c-object>
"nested" <c-object>
4 over set-nested-x
over set-nested-2-y
nested-2-y
nested-x
] unit-test

26
basis/alien/structs/structs.factor Normal file → Executable file
View File

@ -1,15 +1,26 @@
! Copyright (C) 2004, 2008 Slava Pestov. ! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays generic hashtables kernel kernel.private USING: accessors arrays assocs generic hashtables kernel kernel.private
math namespaces parser sequences strings words libc fry math namespaces parser sequences strings words libc fry
alien.c-types alien.structs.fields cpu.architecture math.order ; alien.c-types alien.structs.fields cpu.architecture math.order
quotations byte-arrays ;
IN: alien.structs IN: alien.structs
TUPLE: struct-type size align fields boxer-quot unboxer-quot getter setter ; TUPLE: struct-type
size
align
fields
{ boxer-quot callable }
{ unboxer-quot callable }
{ getter callable }
{ setter callable }
return-in-registers? ;
M: struct-type c-type ;
M: struct-type heap-size size>> ; M: struct-type heap-size size>> ;
M: struct-type c-type-class drop object ; M: struct-type c-type-class drop byte-array ;
M: struct-type c-type-align align>> ; M: struct-type c-type-align align>> ;
@ -29,7 +40,7 @@ M: struct-type box-parameter
[ %box-large-struct ] [ box-parameter ] if-value-struct ; [ %box-large-struct ] [ box-parameter ] if-value-struct ;
: if-small-struct ( c-type true false -- ? ) : if-small-struct ( c-type true false -- ? )
[ dup struct-small-enough? ] 2dip '[ f swap @ ] if ; inline [ dup return-struct-in-registers? ] 2dip '[ f swap @ ] if ; inline
M: struct-type unbox-return M: struct-type unbox-return
[ %unbox-small-struct ] [ %unbox-large-struct ] if-small-struct ; [ %unbox-small-struct ] [ %unbox-large-struct ] if-small-struct ;
@ -68,3 +79,8 @@ M: struct-type stack-size
[ expand-constants ] map [ expand-constants ] map
[ [ heap-size ] [ max ] map-reduce ] keep [ [ heap-size ] [ max ] map-reduce ] keep
compute-struct-align f (define-struct) ; compute-struct-align f (define-struct) ;
: offset-of ( field struct -- offset )
c-types get at fields>>
[ name>> = ] with find nip offset>> ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2007, 2008 Slava Pestov. ! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types accessors math alien.accessors kernel USING: alien.c-types accessors math alien.accessors kernel
kernel.private locals sequences sequences.private byte-arrays kernel.private sequences sequences.private byte-arrays
parser prettyprint.custom fry ; parser prettyprint.custom fry ;
IN: bit-arrays IN: bit-arrays
@ -70,16 +70,15 @@ M: bit-array byte-length length 7 + -3 shift ;
: ?{ \ } [ >bit-array ] parse-literal ; parsing : ?{ \ } [ >bit-array ] parse-literal ; parsing
:: integer>bit-array ( n -- bit-array ) : integer>bit-array ( n -- bit-array )
n zero? [ 0 <bit-array> ] [ dup 0 = [
[let | out [ n log2 1+ <bit-array> ] i! [ 0 ] n'! [ n ] | <bit-array>
[ n' zero? ] [ ] [
n' out underlying>> i set-alien-unsigned-1 [ log2 1+ <bit-array> 0 ] keep
n' -8 shift n'! [ dup 0 = ] [
i 1+ i! [ pick underlying>> pick set-alien-unsigned-1 ] keep
] [ ] until [ 1+ ] [ -8 shift ] bi*
out ] [ ] until 2drop
]
] if ; ] if ;
: bit-array>integer ( bit-array -- n ) : bit-array>integer ( bit-array -- n )

View File

@ -0,0 +1 @@
Doug Coleman

View File

@ -0,0 +1,27 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors bitstreams io io.streams.string kernel tools.test
grouping compression.lzw multiline byte-arrays io.encodings.binary
io.streams.byte-array ;
IN: bitstreams.tests
[ 1 t ]
[ B{ 254 } <string-reader> <bitstream-reader> read-bit ] unit-test
[ 254 8 t ]
[ B{ 254 } <string-reader> <bitstream-reader> 8 swap read-bits ] unit-test
[ 4095 12 t ]
[ B{ 255 255 } <string-reader> <bitstream-reader> 12 swap read-bits ] unit-test
[ B{ 254 } ]
[
<string-writer> <bitstream-writer> 254 8 rot
[ write-bits ] keep stream>> >byte-array
] unit-test
[ 255 8 t ]
[ B{ 255 } binary <byte-reader> <bitstream-reader> 8 swap read-bits ] unit-test
[ 255 8 f ]
[ B{ 255 } binary <byte-reader> <bitstream-reader> 9 swap read-bits ] unit-test

View File

@ -0,0 +1,96 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-arrays destructors fry io kernel locals
math sequences ;
IN: bitstreams
TUPLE: bitstream stream end-of-stream? current-bits #bits disposed ;
TUPLE: bitstream-reader < bitstream ;
: reset-bitstream ( stream -- stream )
0 >>#bits 0 >>current-bits ; inline
: new-bitstream ( stream class -- bitstream )
new
swap >>stream
reset-bitstream ; inline
M: bitstream-reader dispose ( stream -- )
stream>> dispose ;
: <bitstream-reader> ( stream -- bitstream )
bitstream-reader new-bitstream ; inline
: read-next-byte ( bitstream -- bitstream )
dup stream>> stream-read1 [
>>current-bits 8 >>#bits
] [
0 >>#bits
t >>end-of-stream?
] if* ;
: maybe-read-next-byte ( bitstream -- bitstream )
dup #bits>> 0 = [ read-next-byte ] when ; inline
: shift-one-bit ( bitstream -- n )
[ current-bits>> ] [ #bits>> ] bi 1- neg shift 1 bitand ; inline
: next-bit ( bitstream -- n/f ? )
maybe-read-next-byte
dup end-of-stream?>> [
drop f
] [
[ shift-one-bit ]
[ [ 1- ] change-#bits maybe-read-next-byte drop ] bi
] if dup >boolean ;
: read-bit ( bitstream -- n ? )
dup #bits>> 1 = [
[ current-bits>> 1 bitand ]
[ read-next-byte drop ] bi t
] [
next-bit
] if ; inline
: bits>integer ( seq -- n )
0 [ [ 1 shift ] dip bitor ] reduce ; inline
: read-bits ( width bitstream -- n width ? )
[
'[ _ read-bit drop ] replicate
[ f = ] trim-tail
[ bits>integer ] [ length ] bi
] 2keep drop over = ;
TUPLE: bitstream-writer < bitstream ;
: <bitstream-writer> ( stream -- bitstream )
bitstream-writer new-bitstream ; inline
: write-bit ( n bitstream -- )
[ 1 shift bitor ] change-current-bits
[ 1+ ] change-#bits
dup #bits>> 8 = [
[ [ current-bits>> ] [ stream>> stream-write1 ] bi ]
[ reset-bitstream drop ] bi
] [
drop
] if ; inline
ERROR: invalid-bit-width n ;
:: write-bits ( n width bitstream -- )
n 0 < [ n invalid-bit-width ] when
n 0 = [
width [ 0 bitstream write-bit ] times
] [
width n log2 1+ dup :> n-length - [ 0 bitstream write-bit ] times
n-length [
n-length swap - 1- neg n swap shift 1 bitand
bitstream write-bit
] each
] if ;
: flush-bits ( bitstream -- ) stream>> stream-flush ;
: bitstream-output ( bitstream -- bytes ) stream>> >byte-array ;

View File

@ -1,4 +1,4 @@
USING: help.markup help.syntax io io.files io.pathnames ; USING: help.markup help.syntax io io.files io.pathnames strings ;
IN: bootstrap.image IN: bootstrap.image
ARTICLE: "bootstrap.image" "Bootstrapping new images" ARTICLE: "bootstrap.image" "Bootstrapping new images"
@ -14,7 +14,7 @@ $nl
ABOUT: "bootstrap.image" ABOUT: "bootstrap.image"
HELP: make-image HELP: make-image
{ $values { "arch" "a string" } } { $values { "arch" string } }
{ $description "Creates a bootstrap image from sources, where " { $snippet "architecture" } " is one of the following:" { $description "Creates a bootstrap image from sources, where " { $snippet "architecture" } " is one of the following:"
{ $code "x86.32" "x86.64" "ppc" "arm" } { $code "x86.32" "unix-x86.64" "winnt-x86.64" "macosx-ppc" "linux-ppc" }
"The new image file is written to the " { $link resource-path } " and is named " { $snippet "boot." { $emphasis "architecture" } ".image" } "." } ; "The new image file is written to the " { $link resource-path } " and is named " { $snippet "boot." { $emphasis "architecture" } ".image" } "." } ;

View File

@ -0,0 +1,32 @@
! Copyright (C) 2009 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax quotations effects words ;
IN: call
ABOUT: "call"
ARTICLE: "call" "Calling code with known stack effects"
"The " { $vocab-link "call" } " vocabulary allows for arbitrary quotations to be called from code accepted by the optimizing compiler. This is done by specifying the stack effect of the quotation literally. It is checked at runtime that the stack effect is accurate."
{ $subsection POSTPONE: call( }
{ $subsection POSTPONE: execute( }
{ $subsection call-effect }
{ $subsection execute-effect } ;
HELP: call(
{ $syntax "[ ] call( foo -- bar )" }
{ $description "Calls the quotation on the top of the stack, asserting that it has the given stack effect. The quotation does not need to be known at compile time." } ;
HELP: call-effect
{ $values { "quot" quotation } { "effect" effect } }
{ $description "Given a quotation and a stack effect, calls the quotation, asserting at runtime that it has the given stack effect. This is a macro which expands given a literal effect parameter, and an arbitrary quotation which is not required at compile time." } ;
HELP: execute(
{ $syntax "word execute( foo -- bar )" }
{ $description "Calls the word on the top of the stack, aserting that it has the given stack effect. The word does not need to be known at compile time." } ;
HELP: execute-effect
{ $values { "word" word } { "effect" effect } }
{ $description "Given a word and a stack effect, executes the word, asserting at runtime that it has the given stack effect. This is a macro which expands given a literal effect parameter, and an arbitrary word which is not required at compile time." } ;
{ execute-effect call-effect } related-words
{ POSTPONE: call( POSTPONE: execute( } related-words

View File

@ -0,0 +1,15 @@
! Copyright (C) 2009 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: math tools.test call kernel ;
IN: call.tests
[ 3 ] [ 1 2 [ + ] call( x y -- z ) ] unit-test
[ 1 2 [ + ] call( -- z ) ] must-fail
[ 1 2 [ + ] call( x y -- z a ) ] must-fail
[ 1 2 3 { 4 } ] [ 1 2 3 4 [ datastack nip ] call( x -- y ) ] unit-test
[ [ + ] call( x y -- z ) ] must-infer
[ 3 ] [ 1 2 \ + execute( x y -- z ) ] unit-test
[ 1 2 \ + execute( -- z ) ] must-fail
[ 1 2 \ + execute( x y -- z a ) ] must-fail
[ \ + execute( x y -- z ) ] must-infer

30
basis/call/call.factor Normal file
View File

@ -0,0 +1,30 @@
! Copyright (C) 2009 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel macros fry summary sequences generalizations accessors
continuations effects.parser parser words ;
IN: call
ERROR: wrong-values values quot length-required ;
M: wrong-values summary
drop "Wrong number of values returned from quotation" ;
<PRIVATE
: firstn-safe ( array quot n -- ... )
3dup nip swap length = [ nip firstn ] [ wrong-values ] if ; inline
PRIVATE>
MACRO: call-effect ( effect -- quot )
[ in>> length ] [ out>> length ] bi
'[ [ _ narray ] dip [ with-datastack ] keep _ firstn-safe ] ;
: call(
")" parse-effect parsed \ call-effect parsed ; parsing
: execute-effect ( word effect -- )
[ [ execute ] curry ] dip call-effect ; inline
: execute(
")" parse-effect parsed \ execute-effect parsed ; parsing

View File

@ -29,7 +29,7 @@ SYMBOL: super-sent-messages
SYMBOL: frameworks SYMBOL: frameworks
frameworks global [ V{ } clone or ] change-at frameworks [ V{ } clone ] initialize
[ frameworks get [ load-framework ] each ] "cocoa.messages" add-init-hook [ frameworks get [ load-framework ] each ] "cocoa.messages" add-init-hook

View File

@ -5,7 +5,7 @@ continuations combinators compiler compiler.alien kernel math
namespaces make parser quotations sequences strings words namespaces make parser quotations sequences strings words
cocoa.runtime io macros memoize io.encodings.utf8 cocoa.runtime io macros memoize io.encodings.utf8
effects libc libc.private parser lexer init core-foundation fry effects libc libc.private parser lexer init core-foundation fry
generalizations specialized-arrays.direct.alien ; generalizations specialized-arrays.direct.alien call ;
IN: cocoa.messages IN: cocoa.messages
: make-sender ( method function -- quot ) : make-sender ( method function -- quot )
@ -19,8 +19,8 @@ IN: cocoa.messages
SYMBOL: message-senders SYMBOL: message-senders
SYMBOL: super-message-senders SYMBOL: super-message-senders
message-senders global [ H{ } assoc-like ] change-at message-senders [ H{ } clone ] initialize
super-message-senders global [ H{ } assoc-like ] change-at super-message-senders [ H{ } clone ] initialize
: cache-stub ( method function hash -- ) : cache-stub ( method function hash -- )
[ [
@ -53,7 +53,7 @@ MEMO: <selector> ( name -- sel ) f \ selector boa ;
SYMBOL: objc-methods SYMBOL: objc-methods
objc-methods global [ H{ } assoc-like ] change-at objc-methods [ H{ } clone ] initialize
: lookup-method ( selector -- method ) : lookup-method ( selector -- method )
dup objc-methods get at dup objc-methods get at
@ -79,11 +79,11 @@ MACRO: (send) ( selector super? -- quot )
! Runtime introspection ! Runtime introspection
SYMBOL: class-init-hooks SYMBOL: class-init-hooks
class-init-hooks global [ H{ } clone or ] change-at class-init-hooks [ H{ } clone ] initialize
: (objc-class) ( name word -- class ) : (objc-class) ( name word -- class )
2dup execute dup [ 2nip ] [ 2dup execute dup [ 2nip ] [
drop over class-init-hooks get at [ assert-depth ] when* drop over class-init-hooks get at [ call( -- ) ] when*
2dup execute dup [ 2nip ] [ 2dup execute dup [ 2nip ] [
2drop "No such class: " prepend throw 2drop "No such class: " prepend throw
] if ] if

View File

@ -44,4 +44,6 @@ IN: combinators.smart.tests
\ nested-smart-combo-test must-infer \ nested-smart-combo-test must-infer
[ { { 1 2 } { 3 4 } } ] [ nested-smart-combo-test ] unit-test [ { { 1 2 } { 3 4 } } ] [ nested-smart-combo-test ] unit-test
[ 14 ] [ [ 1 2 3 ] [ sq ] [ + ] map-reduce-outputs ] unit-test

View File

@ -21,6 +21,12 @@ MACRO: reduce-outputs ( quot operation -- newquot )
: sum-outputs ( quot -- n ) : sum-outputs ( quot -- n )
[ + ] reduce-outputs ; inline [ + ] reduce-outputs ; inline
MACRO: map-reduce-outputs ( quot mapper reducer -- newquot )
[ dup infer out>> ] 2dip
[ swap '[ _ _ napply ] ]
[ [ 1 [-] ] dip n*quot ] bi-curry* bi
'[ @ @ @ ] ;
MACRO: append-outputs-as ( quot exemplar -- newquot ) MACRO: append-outputs-as ( quot exemplar -- newquot )
[ dup infer out>> ] dip '[ @ _ _ nappend-as ] ; [ dup infer out>> ] dip '[ @ _ _ nappend-as ] ;

View File

@ -5,7 +5,7 @@ alien.c-types alien.structs cpu.architecture ;
IN: compiler.alien IN: compiler.alien
: large-struct? ( ctype -- ? ) : large-struct? ( ctype -- ? )
dup c-struct? [ struct-small-enough? not ] [ drop f ] if ; dup c-struct? [ return-struct-in-registers? not ] [ drop f ] if ;
: alien-parameters ( params -- seq ) : alien-parameters ( params -- seq )
dup parameters>> dup parameters>>

View File

@ -1,6 +1,6 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel arrays sequences math math.order USING: accessors kernel arrays sequences math math.order call
math.partial-dispatch generic generic.standard generic.math math.partial-dispatch generic generic.standard generic.math
classes.algebra classes.union sets quotations assocs combinators classes.algebra classes.union sets quotations assocs combinators
words namespaces continuations classes fry combinators.smart words namespaces continuations classes fry combinators.smart
@ -181,8 +181,9 @@ SYMBOL: history
"custom-inlining" word-prop ; "custom-inlining" word-prop ;
: inline-custom ( #call word -- ? ) : inline-custom ( #call word -- ? )
[ dup 1array ] [ "custom-inlining" word-prop ] bi* with-datastack [ dup ] [ "custom-inlining" word-prop ] bi*
first object swap eliminate-dispatch ; call( #call -- word/quot/f )
object swap eliminate-dispatch ;
: inline-instance-check ( #call word -- ? ) : inline-instance-check ( #call word -- ? )
over in-d>> second value-info literal>> dup class? over in-d>> second value-info literal>> dup class?

View File

@ -24,4 +24,4 @@ IN: compiler.utilities
SYMBOL: yield-hook SYMBOL: yield-hook
yield-hook global [ [ ] or ] change-at yield-hook [ [ ] ] initialize

View File

@ -0,0 +1 @@
Doug Coleman

View File

@ -0,0 +1,4 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors tools.test compression.lzw ;
IN: compression.lzw.tests

View File

@ -0,0 +1,204 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs bitstreams byte-vectors combinators io
io.encodings.binary io.streams.byte-array kernel math sequences
vectors ;
IN: compression.lzw
CONSTANT: clear-code 256
CONSTANT: end-of-information 257
TUPLE: lzw input output end-of-input? table count k omega omega-k #bits
code old-code ;
SYMBOL: table-full
ERROR: index-too-big n ;
: lzw-bit-width ( n -- n' )
{
{ [ dup 510 <= ] [ drop 9 ] }
{ [ dup 1022 <= ] [ drop 10 ] }
{ [ dup 2046 <= ] [ drop 11 ] }
{ [ dup 4094 <= ] [ drop 12 ] }
[ drop table-full ]
} cond ;
: lzw-bit-width-compress ( lzw -- n )
count>> lzw-bit-width ;
: lzw-bit-width-uncompress ( lzw -- n )
table>> length lzw-bit-width ;
: initial-compress-table ( -- assoc )
258 iota [ [ 1vector ] keep ] H{ } map>assoc ;
: initial-uncompress-table ( -- seq )
258 iota [ 1vector ] V{ } map-as ;
: reset-lzw ( lzw -- lzw )
257 >>count
V{ } clone >>omega
V{ } clone >>omega-k
9 >>#bits ;
: reset-lzw-compress ( lzw -- lzw )
f >>k
initial-compress-table >>table reset-lzw ;
: reset-lzw-uncompress ( lzw -- lzw )
initial-uncompress-table >>table reset-lzw ;
: <lzw-compress> ( input -- obj )
lzw new
swap >>input
binary <byte-writer> <bitstream-writer> >>output
reset-lzw-compress ;
: <lzw-uncompress> ( input -- obj )
lzw new
swap >>input
BV{ } clone >>output
reset-lzw-uncompress ;
: push-k ( lzw -- lzw )
[ ]
[ k>> ]
[ omega>> clone [ push ] keep ] tri >>omega-k ;
: omega-k-in-table? ( lzw -- ? )
[ omega-k>> ] [ table>> ] bi key? ;
ERROR: not-in-table ;
: write-output ( lzw -- )
[
[ omega>> ] [ table>> ] bi at* [ not-in-table ] unless
] [
[ lzw-bit-width-compress ]
[ output>> write-bits ] bi
] bi ;
: omega-k>omega ( lzw -- lzw )
dup omega-k>> clone >>omega ;
: k>omega ( lzw -- lzw )
dup k>> 1vector >>omega ;
: add-omega-k ( lzw -- )
[ [ 1+ ] change-count count>> ]
[ omega-k>> clone ]
[ table>> ] tri set-at ;
: lzw-compress-char ( lzw k -- )
>>k push-k dup omega-k-in-table? [
omega-k>omega drop
] [
[ write-output ]
[ add-omega-k ]
[ k>omega drop ] tri
] if ;
: (lzw-compress-chars) ( lzw -- )
dup lzw-bit-width-compress table-full = [
drop
] [
dup input>> stream-read1
[ [ lzw-compress-char ] [ drop (lzw-compress-chars) ] 2bi ]
[ t >>end-of-input? drop ] if*
] if ;
: lzw-compress-chars ( lzw -- )
{
! [ [ clear-code lzw-compress-char ] [ drop ] bi ] ! reset-lzw-compress drop ] bi ]
[
[ clear-code ] dip
[ lzw-bit-width-compress ]
[ output>> write-bits ] bi
]
[ (lzw-compress-chars) ]
[
[ k>> ]
[ lzw-bit-width-compress ]
[ output>> write-bits ] tri
]
[
[ end-of-information ] dip
[ lzw-bit-width-compress ]
[ output>> write-bits ] bi
]
[ ]
} cleave dup end-of-input?>> [ drop ] [ lzw-compress-chars ] if ;
: lzw-compress ( byte-array -- seq )
binary <byte-reader> <lzw-compress>
[ lzw-compress-chars ] [ output>> stream>> ] bi ;
: lookup-old-code ( lzw -- vector )
[ old-code>> ] [ table>> ] bi nth ;
: lookup-code ( lzw -- vector )
[ code>> ] [ table>> ] bi nth ;
: code-in-table? ( lzw -- ? )
[ code>> ] [ table>> length ] bi < ;
: code>old-code ( lzw -- lzw )
dup code>> >>old-code ;
: write-code ( lzw -- )
[ lookup-code ] [ output>> ] bi push-all ;
: add-to-table ( seq lzw -- ) table>> push ;
: lzw-read ( lzw -- lzw n )
[ ] [ lzw-bit-width-uncompress ] [ input>> ] tri read-bits 2drop ;
DEFER: lzw-uncompress-char
: handle-clear-code ( lzw -- )
reset-lzw-uncompress
lzw-read dup end-of-information = [
2drop
] [
>>code
[ write-code ]
[ code>old-code ] bi
lzw-uncompress-char
] if ;
: handle-uncompress-code ( lzw -- lzw )
dup code-in-table? [
[ write-code ]
[
[
[ lookup-old-code ]
[ lookup-code first ] bi suffix
] [ add-to-table ] bi
] [ code>old-code ] tri
] [
[
[ lookup-old-code dup first suffix ] keep
[ output>> push-all ] [ add-to-table ] 2bi
] [ code>old-code ] bi
] if ;
: lzw-uncompress-char ( lzw -- )
lzw-read [
>>code
dup code>> end-of-information = [
drop
] [
dup code>> clear-code = [
handle-clear-code
] [
handle-uncompress-code
lzw-uncompress-char
] if
] if
] [
drop
] if* ;
: lzw-uncompress ( seq -- byte-array )
binary <byte-reader> <bitstream-reader>
<lzw-uncompress> [ lzw-uncompress-char ] [ output>> ] bi ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2009 Doug Coleman. ! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.syntax combinators system ; USING: alien alien.syntax combinators system ;
IN: zlib.ffi IN: compression.zlib.ffi
<< "zlib" { << "zlib" {
{ [ os winnt? ] [ "zlib1.dll" ] } { [ os winnt? ] [ "zlib1.dll" ] }

View File

@ -1,7 +1,7 @@
! Copyright (C) 2009 Doug Coleman. ! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel tools.test zlib classes ; USING: kernel tools.test compression.zlib classes ;
IN: zlib.tests IN: compression.zlib.tests
: compress-me ( -- byte-array ) B{ 1 2 3 4 5 } ; : compress-me ( -- byte-array ) B{ 1 2 3 4 5 } ;

View File

@ -3,8 +3,8 @@
USING: alien alien.c-types alien.syntax byte-arrays combinators USING: alien alien.c-types alien.syntax byte-arrays combinators
kernel math math.functions sequences system accessors kernel math math.functions sequences system accessors
libc ; libc ;
QUALIFIED: zlib.ffi QUALIFIED: compression.zlib.ffi
IN: zlib IN: compression.zlib
TUPLE: compressed data length ; TUPLE: compressed data length ;
@ -16,7 +16,7 @@ TUPLE: compressed data length ;
ERROR: zlib-failed n string ; ERROR: zlib-failed n string ;
: zlib-error-message ( n -- * ) : zlib-error-message ( n -- * )
dup zlib.ffi:Z_ERRNO = [ dup compression.zlib.ffi:Z_ERRNO = [
drop errno "native libc error" drop errno "native libc error"
] [ ] [
dup { dup {
@ -27,7 +27,7 @@ ERROR: zlib-failed n string ;
] if zlib-failed ; ] if zlib-failed ;
: zlib-error ( n -- ) : zlib-error ( n -- )
dup zlib.ffi:Z_OK = [ drop ] [ dup zlib-error-message zlib-failed ] if ; dup compression.zlib.ffi:Z_OK = [ drop ] [ dup zlib-error-message zlib-failed ] if ;
: compressed-size ( byte-array -- n ) : compressed-size ( byte-array -- n )
length 1001/1000 * ceiling 12 + ; length 1001/1000 * ceiling 12 + ;
@ -35,7 +35,7 @@ ERROR: zlib-failed n string ;
: compress ( byte-array -- compressed ) : compress ( byte-array -- compressed )
[ [
[ compressed-size <byte-array> dup length <ulong> ] keep [ [ compressed-size <byte-array> dup length <ulong> ] keep [
dup length zlib.ffi:compress zlib-error dup length compression.zlib.ffi:compress zlib-error
] 3keep drop *ulong head ] 3keep drop *ulong head
] keep length <compressed> ; ] keep length <compressed> ;
@ -44,5 +44,5 @@ ERROR: zlib-failed n string ;
length>> [ <byte-array> ] keep <ulong> 2dup length>> [ <byte-array> ] keep <ulong> 2dup
] [ ] [
data>> dup length data>> dup length
zlib.ffi:uncompress zlib-error compression.zlib.ffi:uncompress zlib-error
] bi *ulong head ; ] bi *ulong head ;

View File

@ -85,4 +85,4 @@ PRIVATE>
: get-process ( name -- process ) : get-process ( name -- process )
dup registered-processes at [ ] [ thread ] ?if ; dup registered-processes at [ ] [ thread ] ?if ;
\ registered-processes global [ H{ } assoc-like ] change-at \ registered-processes [ H{ } clone ] initialize

View File

@ -152,7 +152,7 @@ HOOK: %loop-entry cpu ( -- )
HOOK: small-enough? cpu ( n -- ? ) HOOK: small-enough? cpu ( n -- ? )
! Is this structure small enough to be returned in registers? ! Is this structure small enough to be returned in registers?
HOOK: struct-small-enough? cpu ( c-type -- ? ) HOOK: return-struct-in-registers? cpu ( c-type -- ? )
! Do we pass this struct by value or hidden reference? ! Do we pass this struct by value or hidden reference?
HOOK: value-struct? cpu ( c-type -- ? ) HOOK: value-struct? cpu ( c-type -- ? )

View File

@ -659,7 +659,7 @@ M: ppc %callback-value ( ctype -- )
M: ppc small-enough? ( n -- ? ) -32768 32767 between? ; M: ppc small-enough? ( n -- ? ) -32768 32767 between? ;
M: ppc struct-small-enough? ( size -- ? ) drop f ; M: ppc return-struct-in-registers? ( c-type -- ? ) drop f ;
M: ppc %box-small-struct M: ppc %box-small-struct
drop "No small structs" throw ; drop "No small structs" throw ;

View File

@ -48,9 +48,12 @@ M: x86.32 %alien-invoke (CALL) rel-dlsym ;
M: x86.32 %alien-invoke-tail (JMP) rel-dlsym ; M: x86.32 %alien-invoke-tail (JMP) rel-dlsym ;
M: x86.32 struct-small-enough? ( size -- ? ) M: x86.32 return-struct-in-registers? ( c-type -- ? )
heap-size { 1 2 4 8 } member? c-type
os { linux netbsd solaris } member? not and ; [ return-in-registers?>> ]
[ heap-size { 1 2 4 8 } member? ] bi
os { linux netbsd solaris } member? not
and or ;
: struct-return@ ( n -- operand ) : struct-return@ ( n -- operand )
[ next-stack@ ] [ stack-frame get params>> stack@ ] if* ; [ next-stack@ ] [ stack-frame get params>> stack@ ] if* ;

View File

@ -44,7 +44,7 @@ M: struct-type flatten-value-type ( type -- seq )
flatten-small-struct flatten-small-struct
] if ; ] if ;
M: x86.64 struct-small-enough? ( size -- ? ) M: x86.64 return-struct-in-registers? ( c-type -- ? )
heap-size 2 cells <= ; heap-size 2 cells <= ;
M: x86.64 dummy-stack-params? f ; M: x86.64 dummy-stack-params? f ;

View File

@ -10,7 +10,8 @@ M: float-regs param-regs drop { XMM0 XMM1 XMM2 XMM3 } ;
M: x86.64 reserved-area-size 4 cells ; M: x86.64 reserved-area-size 4 cells ;
M: x86.64 struct-small-enough? heap-size { 1 2 4 8 } member? ; M: x86.64 return-struct-in-registers? ( c-type -- ? )
heap-size { 1 2 4 8 } member? ;
M: x86.64 value-struct? heap-size { 1 2 4 8 } member? ; M: x86.64 value-struct? heap-size { 1 2 4 8 } member? ;

View File

@ -1,14 +1,11 @@
USING: io.streams.string csv tools.test shuffle kernel strings USING: io.streams.string csv tools.test kernel strings
io.pathnames io.files.unique io.encodings.utf8 io.files io.pathnames io.files.unique io.encodings.utf8 io.files
io.directories ; io.directories ;
IN: csv.tests IN: csv.tests
! I like to name my unit tests ! I like to name my unit tests
: named-unit-test ( name output input -- ) : named-unit-test ( name output input -- )
nipd unit-test ; inline unit-test drop ; inline
! tests nicked from the wikipedia csv article
! http://en.wikipedia.org/wiki/Comma-separated_values
"Fields are separated by commas" "Fields are separated by commas"
[ { { "1997" "Ford" "E350" } } ] [ { { "1997" "Ford" "E350" } } ]
@ -90,3 +87,5 @@ IN: csv.tests
{ { "writing,some,csv,tests" } } dup "csv-test2-" { { "writing,some,csv,tests" } } dup "csv-test2-"
unique-file utf8 [ csv>file ] [ file>csv ] 2bi = unique-file utf8 [ csv>file ] [ file>csv ] 2bi =
] unit-test ] unit-test
[ { { "hello" "" "" "" "goodbye" "" } } ] [ "hello,,\"\",,goodbye," <string-reader> csv ] unit-test

View File

@ -46,13 +46,15 @@ DEFER: quoted-field ( -- endchar )
: (row) ( -- sep ) : (row) ( -- sep )
field , field ,
dup delimiter get = [ drop (row) ] when ; dup delimiter> = [ drop (row) ] when ;
: row ( -- eof? array[string] ) : row ( -- eof? array[string] )
[ (row) ] { } make ; [ (row) ] { } make ;
: (csv) ( -- ) : (csv) ( -- )
row harvest [ , ] unless-empty [ (csv) ] when ; row
dup [ empty? ] all? [ drop ] [ , ] if
[ (csv) ] when ;
PRIVATE> PRIVATE>
@ -60,7 +62,8 @@ PRIVATE>
[ row nip ] with-input-stream ; [ row nip ] with-input-stream ;
: csv ( stream -- rows ) : csv ( stream -- rows )
[ [ (csv) ] { } make ] with-input-stream ; [ [ (csv) ] { } make ] with-input-stream
dup peek { "" } = [ but-last ] when ;
: file>csv ( path encoding -- csv ) : file>csv ( path encoding -- csv )
<file-reader> csv ; <file-reader> csv ;

View File

@ -11,46 +11,46 @@ IN: db.postgresql.ffi
} cond "cdecl" add-library >> } cond "cdecl" add-library >>
! ConnSatusType ! ConnSatusType
: CONNECTION_OK HEX: 0 ; inline CONSTANT: CONNECTION_OK HEX: 0
: CONNECTION_BAD HEX: 1 ; inline CONSTANT: CONNECTION_BAD HEX: 1
: CONNECTION_STARTED HEX: 2 ; inline CONSTANT: CONNECTION_STARTED HEX: 2
: CONNECTION_MADE HEX: 3 ; inline CONSTANT: CONNECTION_MADE HEX: 3
: CONNECTION_AWAITING_RESPONSE HEX: 4 ; inline CONSTANT: CONNECTION_AWAITING_RESPONSE HEX: 4
: CONNECTION_AUTH_OK HEX: 5 ; inline CONSTANT: CONNECTION_AUTH_OK HEX: 5
: CONNECTION_SETENV HEX: 6 ; inline CONSTANT: CONNECTION_SETENV HEX: 6
: CONNECTION_SSL_STARTUP HEX: 7 ; inline CONSTANT: CONNECTION_SSL_STARTUP HEX: 7
: CONNECTION_NEEDED HEX: 8 ; inline CONSTANT: CONNECTION_NEEDED HEX: 8
! PostgresPollingStatusType ! PostgresPollingStatusType
: PGRES_POLLING_FAILED HEX: 0 ; inline CONSTANT: PGRES_POLLING_FAILED HEX: 0
: PGRES_POLLING_READING HEX: 1 ; inline CONSTANT: PGRES_POLLING_READING HEX: 1
: PGRES_POLLING_WRITING HEX: 2 ; inline CONSTANT: PGRES_POLLING_WRITING HEX: 2
: PGRES_POLLING_OK HEX: 3 ; inline CONSTANT: PGRES_POLLING_OK HEX: 3
: PGRES_POLLING_ACTIVE HEX: 4 ; inline CONSTANT: PGRES_POLLING_ACTIVE HEX: 4
! ExecStatusType; ! ExecStatusType;
: PGRES_EMPTY_QUERY HEX: 0 ; inline CONSTANT: PGRES_EMPTY_QUERY HEX: 0
: PGRES_COMMAND_OK HEX: 1 ; inline CONSTANT: PGRES_COMMAND_OK HEX: 1
: PGRES_TUPLES_OK HEX: 2 ; inline CONSTANT: PGRES_TUPLES_OK HEX: 2
: PGRES_COPY_OUT HEX: 3 ; inline CONSTANT: PGRES_COPY_OUT HEX: 3
: PGRES_COPY_IN HEX: 4 ; inline CONSTANT: PGRES_COPY_IN HEX: 4
: PGRES_BAD_RESPONSE HEX: 5 ; inline CONSTANT: PGRES_BAD_RESPONSE HEX: 5
: PGRES_NONFATAL_ERROR HEX: 6 ; inline CONSTANT: PGRES_NONFATAL_ERROR HEX: 6
: PGRES_FATAL_ERROR HEX: 7 ; inline CONSTANT: PGRES_FATAL_ERROR HEX: 7
! PGTransactionStatusType; ! PGTransactionStatusType;
: PQTRANS_IDLE HEX: 0 ; inline CONSTANT: PQTRANS_IDLE HEX: 0
: PQTRANS_ACTIVE HEX: 1 ; inline CONSTANT: PQTRANS_ACTIVE HEX: 1
: PQTRANS_INTRANS HEX: 2 ; inline CONSTANT: PQTRANS_INTRANS HEX: 2
: PQTRANS_INERROR HEX: 3 ; inline CONSTANT: PQTRANS_INERROR HEX: 3
: PQTRANS_UNKNOWN HEX: 4 ; inline CONSTANT: PQTRANS_UNKNOWN HEX: 4
! PGVerbosity; ! PGVerbosity;
: PQERRORS_TERSE HEX: 0 ; inline CONSTANT: PQERRORS_TERSE HEX: 0
: PQERRORS_DEFAULT HEX: 1 ; inline CONSTANT: PQERRORS_DEFAULT HEX: 1
: PQERRORS_VERBOSE HEX: 2 ; inline CONSTANT: PQERRORS_VERBOSE HEX: 2
: InvalidOid 0 ; inline CONSTANT: InvalidOid 0
TYPEDEF: int ConnStatusType TYPEDEF: int ConnStatusType
TYPEDEF: int ExecStatusType TYPEDEF: int ExecStatusType
@ -348,21 +348,21 @@ FUNCTION: int PQdsplen ( uchar* s, int encoding ) ;
FUNCTION: int PQenv2encoding ( ) ; FUNCTION: int PQenv2encoding ( ) ;
! From git, include/catalog/pg_type.h ! From git, include/catalog/pg_type.h
: BOOL-OID 16 ; inline CONSTANT: BOOL-OID 16
: BYTEA-OID 17 ; inline CONSTANT: BYTEA-OID 17
: CHAR-OID 18 ; inline CONSTANT: CHAR-OID 18
: NAME-OID 19 ; inline CONSTANT: NAME-OID 19
: INT8-OID 20 ; inline CONSTANT: INT8-OID 20
: INT2-OID 21 ; inline CONSTANT: INT2-OID 21
: INT4-OID 23 ; inline CONSTANT: INT4-OID 23
: TEXT-OID 23 ; inline CONSTANT: TEXT-OID 23
: OID-OID 26 ; inline CONSTANT: OID-OID 26
: FLOAT4-OID 700 ; inline CONSTANT: FLOAT4-OID 700
: FLOAT8-OID 701 ; inline CONSTANT: FLOAT8-OID 701
: VARCHAR-OID 1043 ; inline CONSTANT: VARCHAR-OID 1043
: DATE-OID 1082 ; inline CONSTANT: DATE-OID 1082
: TIME-OID 1083 ; inline CONSTANT: TIME-OID 1083
: TIMESTAMP-OID 1114 ; inline CONSTANT: TIMESTAMP-OID 1114
: TIMESTAMPTZ-OID 1184 ; inline CONSTANT: TIMESTAMPTZ-OID 1184
: INTERVAL-OID 1186 ; inline CONSTANT: INTERVAL-OID 1186
: NUMERIC-OID 1700 ; inline CONSTANT: NUMERIC-OID 1700

View File

@ -3,7 +3,7 @@
USING: arrays continuations db io kernel math namespaces USING: arrays continuations db io kernel math namespaces
quotations sequences db.postgresql.ffi alien alien.c-types quotations sequences db.postgresql.ffi alien alien.c-types
db.types tools.walker ascii splitting math.parser combinators db.types tools.walker ascii splitting math.parser combinators
libc shuffle calendar.format byte-arrays destructors prettyprint libc calendar.format byte-arrays destructors prettyprint
accessors strings serialize io.encodings.binary io.encodings.utf8 accessors strings serialize io.encodings.binary io.encodings.utf8
alien.strings io.streams.byte-array summary present urls alien.strings io.streams.byte-array summary present urls
specialized-arrays.uint specialized-arrays.alien db.private ; specialized-arrays.uint specialized-arrays.alien db.private ;
@ -117,7 +117,7 @@ M: postgresql-result-null summary ( obj -- str )
: pq-get-string ( handle row column -- obj ) : pq-get-string ( handle row column -- obj )
3dup PQgetvalue utf8 alien>string 3dup PQgetvalue utf8 alien>string
dup empty? [ [ pq-get-is-null f ] dip ? ] [ 3nip ] if ; dup empty? [ [ pq-get-is-null f ] dip ? ] [ [ 3drop ] dip ] if ;
: pq-get-number ( handle row column -- obj ) : pq-get-number ( handle row column -- obj )
pq-get-string dup [ string>number ] when ; pq-get-string dup [ string>number ] when ;
@ -134,7 +134,7 @@ M: postgresql-malloc-destructor dispose ( obj -- )
: pq-get-blob ( handle row column -- obj/f ) : pq-get-blob ( handle row column -- obj/f )
[ PQgetvalue ] 3keep 3dup PQgetlength [ PQgetvalue ] 3keep 3dup PQgetlength
dup 0 > [ dup 0 > [
3nip [ 3drop ] dip
[ [
memory>byte-array >string memory>byte-array >string
0 <uint> 0 <uint>

View File

@ -44,11 +44,11 @@ M: retryable execute-statement* ( statement type -- )
] bi attempt-all drop ; ] bi attempt-all drop ;
: sql-props ( class -- columns table ) : sql-props ( class -- columns table )
[ db-columns ] [ db-table ] bi ; [ db-columns ] [ db-table-name ] bi ;
: query-make ( class quot -- statements ) : query-make ( class quot -- statements )
#! query, input, outputs, secondary queries #! query, input, outputs, secondary queries
over unparse "table" set over db-table-name "table-name" set
[ sql-props ] dip [ sql-props ] dip
[ 0 sql-counter rot with-variable ] curry [ 0 sql-counter rot with-variable ] curry
{ "" { } { } { } } nmake { "" { } { } { } } nmake

View File

@ -13,33 +13,33 @@ IN: db.sqlite.ffi
} cond "cdecl" add-library >> } cond "cdecl" add-library >>
! Return values from sqlite functions ! Return values from sqlite functions
: SQLITE_OK 0 ; inline ! Successful result CONSTANT: SQLITE_OK 0 ! Successful result
: SQLITE_ERROR 1 ; inline ! SQL error or missing database CONSTANT: SQLITE_ERROR 1 ! SQL error or missing database
: SQLITE_INTERNAL 2 ; inline ! An internal logic error in SQLite CONSTANT: SQLITE_INTERNAL 2 ! An internal logic error in SQLite
: SQLITE_PERM 3 ; inline ! Access permission denied CONSTANT: SQLITE_PERM 3 ! Access permission denied
: SQLITE_ABORT 4 ; inline ! Callback routine requested an abort CONSTANT: SQLITE_ABORT 4 ! Callback routine requested an abort
: SQLITE_BUSY 5 ; inline ! The database file is locked CONSTANT: SQLITE_BUSY 5 ! The database file is locked
: SQLITE_LOCKED 6 ; inline ! A table in the database is locked CONSTANT: SQLITE_LOCKED 6 ! A table in the database is locked
: SQLITE_NOMEM 7 ; inline ! A malloc() failed CONSTANT: SQLITE_NOMEM 7 ! A malloc() failed
: SQLITE_READONLY 8 ; inline ! Attempt to write a readonly database CONSTANT: SQLITE_READONLY 8 ! Attempt to write a readonly database
: SQLITE_INTERRUPT 9 ; inline ! Operation terminated by sqlite_interrupt() CONSTANT: SQLITE_INTERRUPT 9 ! Operation terminated by sqlite_interrupt()
: SQLITE_IOERR 10 ; inline ! Some kind of disk I/O error occurred CONSTANT: SQLITE_IOERR 10 ! Some kind of disk I/O error occurred
: SQLITE_CORRUPT 11 ; inline ! The database disk image is malformed CONSTANT: SQLITE_CORRUPT 11 ! The database disk image is malformed
: SQLITE_NOTFOUND 12 ; inline ! (Internal Only) Table or record not found CONSTANT: SQLITE_NOTFOUND 12 ! (Internal Only) Table or record not found
: SQLITE_FULL 13 ; inline ! Insertion failed because database is full CONSTANT: SQLITE_FULL 13 ! Insertion failed because database is full
: SQLITE_CANTOPEN 14 ; inline ! Unable to open the database file CONSTANT: SQLITE_CANTOPEN 14 ! Unable to open the database file
: SQLITE_PROTOCOL 15 ; inline ! Database lock protocol error CONSTANT: SQLITE_PROTOCOL 15 ! Database lock protocol error
: SQLITE_EMPTY 16 ; inline ! (Internal Only) Database table is empty CONSTANT: SQLITE_EMPTY 16 ! (Internal Only) Database table is empty
: SQLITE_SCHEMA 17 ; inline ! The database schema changed CONSTANT: SQLITE_SCHEMA 17 ! The database schema changed
: SQLITE_TOOBIG 18 ; inline ! Too much data for one row of a table CONSTANT: SQLITE_TOOBIG 18 ! Too much data for one row of a table
: SQLITE_CONSTRAINT 19 ; inline ! Abort due to contraint violation CONSTANT: SQLITE_CONSTRAINT 19 ! Abort due to contraint violation
: SQLITE_MISMATCH 20 ; inline ! Data type mismatch CONSTANT: SQLITE_MISMATCH 20 ! Data type mismatch
: SQLITE_MISUSE 21 ; inline ! Library used incorrectly CONSTANT: SQLITE_MISUSE 21 ! Library used incorrectly
: SQLITE_NOLFS 22 ; inline ! Uses OS features not supported on host CONSTANT: SQLITE_NOLFS 22 ! Uses OS features not supported on host
: SQLITE_AUTH 23 ; inline ! Authorization denied CONSTANT: SQLITE_AUTH 23 ! Authorization denied
: SQLITE_FORMAT 24 ; inline ! Auxiliary database format error CONSTANT: SQLITE_FORMAT 24 ! Auxiliary database format error
: SQLITE_RANGE 25 ; inline ! 2nd parameter to sqlite3_bind out of range CONSTANT: SQLITE_RANGE 25 ! 2nd parameter to sqlite3_bind out of range
: SQLITE_NOTADB 26 ; inline ! File opened that is not a database file CONSTANT: SQLITE_NOTADB 26 ! File opened that is not a database file
: sqlite-error-messages ( -- seq ) { : sqlite-error-messages ( -- seq ) {
"Successful result" "Successful result"
@ -72,32 +72,32 @@ IN: db.sqlite.ffi
} ; } ;
! Return values from sqlite3_step ! Return values from sqlite3_step
: SQLITE_ROW 100 ; inline CONSTANT: SQLITE_ROW 100
: SQLITE_DONE 101 ; inline CONSTANT: SQLITE_DONE 101
! Return values from the sqlite3_column_type function ! Return values from the sqlite3_column_type function
: SQLITE_INTEGER 1 ; inline CONSTANT: SQLITE_INTEGER 1
: SQLITE_FLOAT 2 ; inline CONSTANT: SQLITE_FLOAT 2
: SQLITE_TEXT 3 ; inline CONSTANT: SQLITE_TEXT 3
: SQLITE_BLOB 4 ; inline CONSTANT: SQLITE_BLOB 4
: SQLITE_NULL 5 ; inline CONSTANT: SQLITE_NULL 5
! Values for the 'destructor' parameter of the 'bind' routines. ! Values for the 'destructor' parameter of the 'bind' routines.
: SQLITE_STATIC 0 ; inline CONSTANT: SQLITE_STATIC 0
: SQLITE_TRANSIENT -1 ; inline CONSTANT: SQLITE_TRANSIENT -1
: SQLITE_OPEN_READONLY HEX: 00000001 ; inline CONSTANT: SQLITE_OPEN_READONLY HEX: 00000001
: SQLITE_OPEN_READWRITE HEX: 00000002 ; inline CONSTANT: SQLITE_OPEN_READWRITE HEX: 00000002
: SQLITE_OPEN_CREATE HEX: 00000004 ; inline CONSTANT: SQLITE_OPEN_CREATE HEX: 00000004
: SQLITE_OPEN_DELETEONCLOSE HEX: 00000008 ; inline CONSTANT: SQLITE_OPEN_DELETEONCLOSE HEX: 00000008
: SQLITE_OPEN_EXCLUSIVE HEX: 00000010 ; inline CONSTANT: SQLITE_OPEN_EXCLUSIVE HEX: 00000010
: SQLITE_OPEN_MAIN_DB HEX: 00000100 ; inline CONSTANT: SQLITE_OPEN_MAIN_DB HEX: 00000100
: SQLITE_OPEN_TEMP_DB HEX: 00000200 ; inline CONSTANT: SQLITE_OPEN_TEMP_DB HEX: 00000200
: SQLITE_OPEN_TRANSIENT_DB HEX: 00000400 ; inline CONSTANT: SQLITE_OPEN_TRANSIENT_DB HEX: 00000400
: SQLITE_OPEN_MAIN_JOURNAL HEX: 00000800 ; inline CONSTANT: SQLITE_OPEN_MAIN_JOURNAL HEX: 00000800
: SQLITE_OPEN_TEMP_JOURNAL HEX: 00001000 ; inline CONSTANT: SQLITE_OPEN_TEMP_JOURNAL HEX: 00001000
: SQLITE_OPEN_SUBJOURNAL HEX: 00002000 ; inline CONSTANT: SQLITE_OPEN_SUBJOURNAL HEX: 00002000
: SQLITE_OPEN_MASTER_JOURNAL HEX: 00004000 ; inline CONSTANT: SQLITE_OPEN_MASTER_JOURNAL HEX: 00004000
TYPEDEF: void sqlite3 TYPEDEF: void sqlite3
TYPEDEF: void sqlite3_stmt TYPEDEF: void sqlite3_stmt

View File

@ -73,3 +73,95 @@ IN: db.sqlite.tests
"select * from person" sql-query length "select * from person" sql-query length
] with-db ] with-db
] unit-test ] unit-test
! You don't need a primary key
USING: accessors arrays sorting ;
TUPLE: things one two ;
things "THINGS" {
{ "one" "ONE" INTEGER +not-null+ }
{ "two" "TWO" INTEGER +not-null+ }
} define-persistent
[ { { 0 0 } { 0 1 } { 1 0 } { 1 1 } } ] [
test.db [
things create-table
0 0 things boa insert-tuple
0 1 things boa insert-tuple
1 1 things boa insert-tuple
1 0 things boa insert-tuple
f f things boa select-tuples
[ [ one>> ] [ two>> ] bi 2array ] map natural-sort
things drop-table
] with-db
] unit-test
! Tables can have different names than the name of the tuple
TUPLE: foo slot ;
C: <foo> foo
foo "BAR" { { "slot" "SOMETHING" INTEGER +not-null+ } } define-persistent
TUPLE: hi bye try ;
C: <hi> hi
hi "HELLO" {
{ "bye" "BUHBYE" INTEGER { +foreign-id+ foo "SOMETHING" } }
{ "try" "RETHROW" INTEGER { +foreign-id+ foo "SOMETHING" } }
} define-persistent
[ T{ foo { slot 1 } } T{ hi { bye 1 } { try 1 } } ] [
test.db [
foo create-table
hi create-table
1 <foo> insert-tuple
f <foo> select-tuple
1 1 <hi> insert-tuple
f <hi> select-tuple
hi drop-table
foo drop-table
] with-db
] unit-test
[ ] [
test.db [
hi create-table
hi drop-table
] with-db
] unit-test
TUPLE: show id ;
TUPLE: user username data ;
TUPLE: watch show user ;
user "USER" {
{ "username" "USERNAME" TEXT +not-null+ +user-assigned-id+ }
{ "data" "DATA" TEXT }
} define-persistent
show "SHOW" {
{ "id" "ID" +db-assigned-id+ }
} define-persistent
watch "WATCH" {
{ "user" "USER" TEXT +not-null+
{ +foreign-id+ user "USERNAME" } +user-assigned-id+ }
{ "show" "SHOW" BIG-INTEGER +not-null+
{ +foreign-id+ show "ID" } +user-assigned-id+ }
} define-persistent
[ T{ user { username "littledan" } { data "foo" } } ] [
test.db [
user create-table
show create-table
watch create-table
"littledan" "foo" user boa insert-tuple
"mark" "bar" user boa insert-tuple
show new insert-tuple
show new select-tuple
"littledan" f user boa select-tuple
watch boa insert-tuple
watch new select-tuple
user>> f user boa select-tuple
] with-db
] unit-test
[ \ swap ensure-table ] must-fail

View File

@ -138,11 +138,13 @@ M: sqlite-db-connection create-sql-statement ( class -- statement )
modifiers 0% modifiers 0%
] interleave ] interleave
", " 0% find-primary-key [
find-primary-key ", " 0%
"primary key(" 0% "primary key(" 0%
[ "," 0% ] [ column-name>> 0% ] interleave [ "," 0% ] [ column-name>> 0% ] interleave
"));" 0% ")" 0%
] unless-empty
");" 0%
] query-make ; ] query-make ;
M: sqlite-db-connection drop-sql-statement ( class -- statement ) M: sqlite-db-connection drop-sql-statement ( class -- statement )
@ -223,11 +225,11 @@ M: sqlite-db-connection persistent-table ( -- assoc )
: insert-trigger ( -- string ) : insert-trigger ( -- string )
[ [
<" <"
CREATE TRIGGER fki_${table}_${foreign-table}_id CREATE TRIGGER fki_${table-name}_${foreign-table-name}_id
BEFORE INSERT ON ${table} BEFORE INSERT ON ${table-name}
FOR EACH ROW BEGIN FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'insert on table "${table}" violates foreign key constraint "fk_${foreign-table}_id"') SELECT RAISE(ROLLBACK, 'insert on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL; WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
END; END;
"> interpolate "> interpolate
] with-string-writer ; ] with-string-writer ;
@ -235,12 +237,12 @@ M: sqlite-db-connection persistent-table ( -- assoc )
: insert-trigger-not-null ( -- string ) : insert-trigger-not-null ( -- string )
[ [
<" <"
CREATE TRIGGER fki_${table}_${foreign-table}_id CREATE TRIGGER fki_${table-name}_${foreign-table-name}_id
BEFORE INSERT ON ${table} BEFORE INSERT ON ${table-name}
FOR EACH ROW BEGIN FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'insert on table "${table}" violates foreign key constraint "fk_${foreign-table}_id"') SELECT RAISE(ROLLBACK, 'insert on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
WHERE NEW.${foreign-table-id} IS NOT NULL WHERE NEW.${foreign-table-id} IS NOT NULL
AND (SELECT ${foreign-table-id} FROM ${foreign-table} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL; AND (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
END; END;
"> interpolate "> interpolate
] with-string-writer ; ] with-string-writer ;
@ -248,11 +250,11 @@ M: sqlite-db-connection persistent-table ( -- assoc )
: update-trigger ( -- string ) : update-trigger ( -- string )
[ [
<" <"
CREATE TRIGGER fku_${table}_${foreign-table}_id CREATE TRIGGER fku_${table-name}_${foreign-table-name}_id
BEFORE UPDATE ON ${table} BEFORE UPDATE ON ${table-name}
FOR EACH ROW BEGIN FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'update on table "${table}" violates foreign key constraint "fk_${foreign-table}_id"') SELECT RAISE(ROLLBACK, 'update on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL; WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
END; END;
"> interpolate "> interpolate
] with-string-writer ; ] with-string-writer ;
@ -260,12 +262,12 @@ M: sqlite-db-connection persistent-table ( -- assoc )
: update-trigger-not-null ( -- string ) : update-trigger-not-null ( -- string )
[ [
<" <"
CREATE TRIGGER fku_${table}_${foreign-table}_id CREATE TRIGGER fku_${table-name}_${foreign-table-name}_id
BEFORE UPDATE ON ${table} BEFORE UPDATE ON ${table-name}
FOR EACH ROW BEGIN FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'update on table "${table}" violates foreign key constraint "fk_${foreign-table}_id"') SELECT RAISE(ROLLBACK, 'update on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
WHERE NEW.${foreign-table-id} IS NOT NULL WHERE NEW.${foreign-table-id} IS NOT NULL
AND (SELECT ${foreign-table-id} FROM ${foreign-table} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL; AND (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
END; END;
"> interpolate "> interpolate
] with-string-writer ; ] with-string-writer ;
@ -273,11 +275,11 @@ M: sqlite-db-connection persistent-table ( -- assoc )
: delete-trigger-restrict ( -- string ) : delete-trigger-restrict ( -- string )
[ [
<" <"
CREATE TRIGGER fkd_${table}_${foreign-table}_id CREATE TRIGGER fkd_${table-name}_${foreign-table-name}_id
BEFORE DELETE ON ${foreign-table} BEFORE DELETE ON ${foreign-table-name}
FOR EACH ROW BEGIN FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'delete on table "${foreign-table}" violates foreign key constraint "fk_${foreign-table}_id"') SELECT RAISE(ROLLBACK, 'delete on table "${foreign-table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table} WHERE ${foreign-table-id} = OLD.${foreign-table-id}) IS NOT NULL; WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = OLD.${foreign-table-id}) IS NOT NULL;
END; END;
"> interpolate "> interpolate
] with-string-writer ; ] with-string-writer ;
@ -285,10 +287,10 @@ M: sqlite-db-connection persistent-table ( -- assoc )
: delete-trigger-cascade ( -- string ) : delete-trigger-cascade ( -- string )
[ [
<" <"
CREATE TRIGGER fkd_${table}_${foreign-table}_id CREATE TRIGGER fkd_${table-name}_${foreign-table-name}_id
BEFORE DELETE ON ${foreign-table} BEFORE DELETE ON ${foreign-table-name}
FOR EACH ROW BEGIN FOR EACH ROW BEGIN
DELETE from ${table} WHERE ${table-id} = OLD.${foreign-table-id}; DELETE from ${table-name} WHERE ${table-id} = OLD.${foreign-table-id};
END; END;
"> interpolate "> interpolate
] with-string-writer ; ] with-string-writer ;
@ -321,7 +323,7 @@ M: sqlite-db-connection compound ( string seq -- new-string )
{ "default" [ first number>string " " glue ] } { "default" [ first number>string " " glue ] }
{ "references" [ { "references" [
[ >reference-string ] keep [ >reference-string ] keep
first2 [ "foreign-table" set ] first2 [ db-table-name "foreign-table-name" set ]
[ "foreign-table-id" set ] bi* [ "foreign-table-id" set ] bi*
create-sqlite-triggers create-sqlite-triggers
] } ] }

View File

@ -49,7 +49,7 @@ ERROR: no-slot ;
ERROR: not-persistent class ; ERROR: not-persistent class ;
: db-table ( class -- object ) : db-table-name ( class -- object )
dup "db-table" word-prop [ ] [ not-persistent ] ?if ; dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
: db-columns ( class -- object ) : db-columns ( class -- object )
@ -165,7 +165,7 @@ ERROR: no-column column ;
: >reference-string ( string pair -- string ) : >reference-string ( string pair -- string )
first2 first2
[ [ unparse " " glue ] [ db-columns ] bi ] dip [ [ db-table-name " " glue ] [ db-columns ] bi ] dip
swap [ column-name>> = ] with find nip swap [ column-name>> = ] with find nip
[ no-column ] unless* [ no-column ] unless*
column-name>> "(" ")" surround append ; column-name>> "(" ")" surround append ;

View File

@ -1,9 +1,10 @@
! Copyright (C) 2005, 2008 Slava Pestov. ! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: parser lexer kernel namespaces sequences definitions USING: parser lexer kernel namespaces sequences definitions
io.files io.backend io.pathnames io summary continuations io.files io.backend io.pathnames io summary continuations
tools.crossref tools.vocabs prettyprint source-files assocs tools.crossref tools.vocabs prettyprint source-files assocs
vocabs vocabs.loader splitting accessors ; vocabs vocabs.loader splitting accessors debugger prettyprint
help.topics ;
IN: editors IN: editors
TUPLE: no-edit-hook ; TUPLE: no-edit-hook ;
@ -29,11 +30,21 @@ SYMBOL: edit-hook
[ (normalize-path) ] dip edit-hook get-global [ (normalize-path) ] dip edit-hook get-global
[ call ] [ no-edit-hook edit-location ] if* ; [ call ] [ no-edit-hook edit-location ] if* ;
ERROR: cannot-find-source definition ;
M: cannot-find-source error.
"Cannot find source for ``" write
definition>> pprint-short
"''" print ;
: edit ( defspec -- ) : edit ( defspec -- )
where [ first2 edit-location ] when* ; dup where
[ first2 edit-location ]
[ dup word-link? [ name>> edit ] [ cannot-find-source ] if ]
?if ;
: edit-vocab ( name -- ) : edit-vocab ( name -- )
vocab-source-path 1 edit-location ; >vocab-link edit ;
GENERIC: error-file ( error -- file ) GENERIC: error-file ( error -- file )

View File

@ -1,39 +1,39 @@
! Copyright (C) 2009 Doug Coleman. ! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types namespaces io.binary fry USING: alien.c-types namespaces io.binary fry
kernel math ; kernel math grouping sequences ;
IN: endian IN: endian
SINGLETONS: big-endian little-endian ; SINGLETONS: big-endian little-endian ;
: native-endianness ( -- class ) : compute-native-endianness ( -- class )
1 <int> *char 0 = big-endian little-endian ? ; 1 <int> *char 0 = big-endian little-endian ? ;
: >signed ( x n -- y ) : >signed ( x n -- y )
2dup neg 1+ shift 1 = [ 2^ - ] [ drop ] if ; 2dup neg 1+ shift 1 = [ 2^ - ] [ drop ] if ;
native-endianness \ native-endianness set-global SYMBOL: native-endianness
native-endianness [ compute-native-endianness ] initialize
SYMBOL: endianness SYMBOL: endianness
endianness [ native-endianness get-global ] initialize
\ native-endianness get-global endianness set-global HOOK: >native-endian native-endianness ( obj n -- bytes )
HOOK: >native-endian native-endianness ( obj n -- str )
M: big-endian >native-endian >be ; M: big-endian >native-endian >be ;
M: little-endian >native-endian >le ; M: little-endian >native-endian >le ;
HOOK: unsigned-native-endian> native-endianness ( obj -- str ) HOOK: unsigned-native-endian> native-endianness ( obj -- bytes )
M: big-endian unsigned-native-endian> be> ; M: big-endian unsigned-native-endian> be> ;
M: little-endian unsigned-native-endian> le> ; M: little-endian unsigned-native-endian> le> ;
: signed-native-endian> ( obj n -- str ) : signed-native-endian> ( obj n -- n' )
[ unsigned-native-endian> ] dip >signed ; [ unsigned-native-endian> ] dip >signed ;
HOOK: >endian endianness ( obj n -- str ) HOOK: >endian endianness ( obj n -- bytes )
M: big-endian >endian >be ; M: big-endian >endian >be ;
@ -45,13 +45,13 @@ M: big-endian endian> be> ;
M: little-endian endian> le> ; M: little-endian endian> le> ;
HOOK: unsigned-endian> endianness ( obj -- str ) HOOK: unsigned-endian> endianness ( obj -- bytes )
M: big-endian unsigned-endian> be> ; M: big-endian unsigned-endian> be> ;
M: little-endian unsigned-endian> le> ; M: little-endian unsigned-endian> le> ;
: signed-endian> ( obj n -- str ) : signed-endian> ( obj n -- bytes )
[ unsigned-endian> ] dip >signed ; [ unsigned-endian> ] dip >signed ;
: with-endianness ( endian quot -- ) : with-endianness ( endian quot -- )
@ -65,3 +65,15 @@ M: little-endian unsigned-endian> le> ;
: with-native-endian ( quot -- ) : with-native-endian ( quot -- )
\ native-endianness get-global swap with-endianness ; inline \ native-endianness get-global swap with-endianness ; inline
: seq>native-endianness ( seq n -- seq' )
native-endianness get-global dup endianness get = [
2drop
] [
[ [ <sliced-groups> ] keep ] dip
little-endian = [
'[ be> _ >le ] map
] [
'[ le> _ >be ] map
] if concat
] if ; inline

View File

@ -81,11 +81,18 @@ CHLOE: a
CHLOE: base CHLOE: base
compile-a-url [ [XML <base href=<->/> XML] ] [xml-code] ; compile-a-url [ [XML <base href=<->/> XML] ] [xml-code] ;
: hidden-nested-fields ( -- xml )
nested-forms get " " join f like nested-forms-key
hidden-form-field ;
: render-hidden ( for -- xml )
[ "," split [ hidden render>xml ] map ] [ f ] if* ;
: compile-hidden-form-fields ( for -- ) : compile-hidden-form-fields ( for -- )
'[ '[
_ [ "," split [ hidden render>xml ] map ] [ f ] if* _ render-hidden
nested-forms get " " join f like nested-forms-key hidden-form-field>xml hidden-nested-fields
[ [ modify-form ] each-responder ] with-string-writer <unescaped> form-modifications
[XML <div style="display: none;"><-><-><-></div> XML] [XML <div style="display: none;"><-><-><-></div> XML]
] [code] ; ] [code] ;

View File

@ -1,7 +1,7 @@
IN: furnace.tests IN: furnace.tests
USING: http http.server.dispatchers http.server.responses USING: http http.server.dispatchers http.server.responses
http.server furnace furnace.utilities tools.test kernel http.server furnace furnace.utilities tools.test kernel
namespaces accessors io.streams.string urls ; namespaces accessors io.streams.string urls xml.writer ;
TUPLE: funny-dispatcher < dispatcher ; TUPLE: funny-dispatcher < dispatcher ;
: <funny-dispatcher> funny-dispatcher new-dispatcher ; : <funny-dispatcher> funny-dispatcher new-dispatcher ;
@ -31,7 +31,7 @@ M: base-path-check-responder call-responder*
] unit-test ] unit-test
[ "<input type=\"hidden\" value=\"&amp;&amp;&amp;\" name=\"foo\"/>" ] [ "<input type=\"hidden\" value=\"&amp;&amp;&amp;\" name=\"foo\"/>" ]
[ [ "&&&" "foo" hidden-form-field ] with-string-writer ] [ "&&&" "foo" hidden-form-field xml>string ]
unit-test unit-test
[ f ] [ <request> request [ referrer ] with-variable ] unit-test [ f ] [ <request> request [ referrer ] with-variable ] unit-test

View File

@ -20,13 +20,13 @@ HELP: each-responder
{ $description "Applies the quotation to each responder involved in processing the current request." } ; { $description "Applies the quotation to each responder involved in processing the current request." } ;
HELP: hidden-form-field HELP: hidden-form-field
{ $values { "value" string } { "name" string } } { $values { "value" string } { "name" string } { "xml" "an XML chunk" } }
{ $description "Renders an HTML hidden form field tag." } { $description "Renders an HTML hidden form field tag as XML." }
{ $notes "This word is used by session management, conversation scope and asides." } { $notes "This word is used by session management, conversation scope and asides." }
{ $examples { $examples
{ $example { $example
"USING: furnace.utilities io ;" "USING: furnace.utilities io xml.writer ;"
"\"bar\" \"foo\" hidden-form-field nl" "\"bar\" \"foo\" hidden-form-field write-xml nl"
"<input type=\"hidden\" value=\"bar\" name=\"foo\"/>" "<input type=\"hidden\" value=\"bar\" name=\"foo\"/>"
} }
} ; } ;
@ -38,7 +38,7 @@ HELP: link-attr
{ $examples "Conversation scope adds attributes to link tags." } ; { $examples "Conversation scope adds attributes to link tags." } ;
HELP: modify-form HELP: modify-form
{ $values { "responder" "a responder" } } { $values { "responder" "a responder" } { "xml/f" "an XML chunk or f" } }
{ $contract "Emits hidden form fields using " { $link hidden-form-field } "." } { $contract "Emits hidden form fields using " { $link hidden-form-field } "." }
{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." } { $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
{ $examples "Session management, conversation scope and asides use hidden form fields to pass state." } ; { $examples "Session management, conversation scope and asides use hidden form fields to pass state." } ;

View File

@ -77,18 +77,18 @@ GENERIC: link-attr ( tag responder -- )
M: object link-attr 2drop ; M: object link-attr 2drop ;
GENERIC: modify-form ( responder -- ) GENERIC: modify-form ( responder -- xml/f )
M: object modify-form drop ; M: object modify-form drop f ;
: hidden-form-field>xml ( value name -- xml ) : form-modifications ( -- xml )
[ [ modify-form [ , ] when* ] each-responder ] { } make ;
: hidden-form-field ( value name -- xml )
over [ over [
[XML <input type="hidden" value=<-> name=<->/> XML] [XML <input type="hidden" value=<-> name=<->/> XML]
] [ drop ] if ; ] [ drop ] if ;
: hidden-form-field ( value name -- )
hidden-form-field>xml write-xml ;
: nested-forms-key "__n" ; : nested-forms-key "__n" ;
: request-params ( request -- assoc ) : request-params ( request -- assoc )

View File

@ -30,6 +30,10 @@ HELP: narray
{ nsequence narray } related-words { nsequence narray } related-words
HELP: nsum
{ $values { "n" integer } }
{ $description "Adds the top " { $snippet "n" } " stack values." } ;
HELP: firstn HELP: firstn
{ $values { "n" integer } } { $values { "n" integer } }
{ $description "A generalization of " { $link first } ", " { $description "A generalization of " { $link first } ", "
@ -54,7 +58,7 @@ HELP: npick
"placed on the top of the stack." "placed on the top of the stack."
} }
{ $examples { $examples
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 npick .s" "1\n2\n3\n4\n1" } { $example "USING: kernel prettyprint generalizations ;" "1 2 3 4 4 npick .s clear" "1\n2\n3\n4\n1" }
"Some core words expressed in terms of " { $link npick } ":" "Some core words expressed in terms of " { $link npick } ":"
{ $table { $table
{ { $link dup } { $snippet "1 npick" } } { { $link dup } { $snippet "1 npick" } }
@ -71,7 +75,7 @@ HELP: ndup
"placed on the top of the stack." "placed on the top of the stack."
} }
{ $examples { $examples
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 ndup .s" "1\n2\n3\n4\n1\n2\n3\n4" } { $example "USING: prettyprint generalizations kernel ;" "1 2 3 4 4 ndup .s clear" "1\n2\n3\n4\n1\n2\n3\n4" }
"Some core words expressed in terms of " { $link ndup } ":" "Some core words expressed in terms of " { $link ndup } ":"
{ $table { $table
{ { $link dup } { $snippet "1 ndup" } } { { $link dup } { $snippet "1 ndup" } }
@ -87,7 +91,7 @@ HELP: nnip
"for any number of items." "for any number of items."
} }
{ $examples { $examples
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 3 nnip .s" "4" } { $example "USING: prettyprint generalizations kernel ;" "1 2 3 4 3 nnip .s clear" "4" }
"Some core words expressed in terms of " { $link nnip } ":" "Some core words expressed in terms of " { $link nnip } ":"
{ $table { $table
{ { $link nip } { $snippet "1 nnip" } } { { $link nip } { $snippet "1 nnip" } }
@ -102,7 +106,7 @@ HELP: ndrop
"for any number of items." "for any number of items."
} }
{ $examples { $examples
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 3 ndrop .s" "1" } { $example "USING: prettyprint generalizations kernel ;" "1 2 3 4 3 ndrop .s clear" "1" }
"Some core words expressed in terms of " { $link ndrop } ":" "Some core words expressed in terms of " { $link ndrop } ":"
{ $table { $table
{ { $link drop } { $snippet "1 ndrop" } } { { $link drop } { $snippet "1 ndrop" } }
@ -117,7 +121,7 @@ HELP: nrot
"number of items on the stack. " "number of items on the stack. "
} }
{ $examples { $examples
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 nrot .s" "2\n3\n4\n1" } { $example "USING: prettyprint generalizations kernel ;" "1 2 3 4 4 nrot .s clear" "2\n3\n4\n1" }
"Some core words expressed in terms of " { $link nrot } ":" "Some core words expressed in terms of " { $link nrot } ":"
{ $table { $table
{ { $link swap } { $snippet "1 nrot" } } { { $link swap } { $snippet "1 nrot" } }
@ -131,7 +135,7 @@ HELP: -nrot
"number of items on the stack. " "number of items on the stack. "
} }
{ $examples { $examples
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 -nrot .s" "4\n1\n2\n3" } { $example "USING: prettyprint generalizations kernel ;" "1 2 3 4 4 -nrot .s clear" "4\n1\n2\n3" }
"Some core words expressed in terms of " { $link -nrot } ":" "Some core words expressed in terms of " { $link -nrot } ":"
{ $table { $table
{ { $link swap } { $snippet "1 -nrot" } } { { $link swap } { $snippet "1 -nrot" } }
@ -147,8 +151,8 @@ HELP: ndip
"stack. The quotation can consume and produce any number of items." "stack. The quotation can consume and produce any number of items."
} }
{ $examples { $examples
{ $example "USING: generalizations kernel prettyprint ;" "1 2 [ dup ] 1 ndip .s" "1\n1\n2" } { $example "USING: generalizations kernel prettyprint kernel ;" "1 2 [ dup ] 1 ndip .s clear" "1\n1\n2" }
{ $example "USING: generalizations kernel prettyprint ;" "1 2 3 [ drop ] 2 ndip .s" "2\n3" } { $example "USING: generalizations kernel prettyprint kernel ;" "1 2 3 [ drop ] 2 ndip .s clear" "2\n3" }
"Some core words expressed in terms of " { $link ndip } ":" "Some core words expressed in terms of " { $link ndip } ":"
{ $table { $table
{ { $link dip } { $snippet "1 ndip" } } { { $link dip } { $snippet "1 ndip" } }
@ -164,7 +168,7 @@ HELP: nslip
"removed from the stack, the quotation called, and the items restored." "removed from the stack, the quotation called, and the items restored."
} }
{ $examples { $examples
{ $example "USING: generalizations prettyprint ;" "[ 99 ] 1 2 3 4 5 5 nslip .s" "99\n1\n2\n3\n4\n5" } { $example "USING: generalizations kernel prettyprint ;" "[ 99 ] 1 2 3 4 5 5 nslip .s clear" "99\n1\n2\n3\n4\n5" }
"Some core words expressed in terms of " { $link nslip } ":" "Some core words expressed in terms of " { $link nslip } ":"
{ $table { $table
{ { $link slip } { $snippet "1 nslip" } } { { $link slip } { $snippet "1 nslip" } }
@ -180,7 +184,7 @@ HELP: nkeep
"saved, the quotation called, and the items restored." "saved, the quotation called, and the items restored."
} }
{ $examples { $examples
{ $example "USING: generalizations kernel prettyprint ;" "1 2 3 4 5 [ drop drop drop drop drop 99 ] 5 nkeep .s" "99\n1\n2\n3\n4\n5" } { $example "USING: generalizations kernel prettyprint ;" "1 2 3 4 5 [ drop drop drop drop drop 99 ] 5 nkeep .s clear" "99\n1\n2\n3\n4\n5" }
"Some core words expressed in terms of " { $link nkeep } ":" "Some core words expressed in terms of " { $link nkeep } ":"
{ $table { $table
{ { $link keep } { $snippet "1 nkeep" } } { { $link keep } { $snippet "1 nkeep" } }
@ -238,6 +242,11 @@ HELP: ncleave
} }
} ; } ;
HELP: nspread
{ $values { "quots" "a sequence of quotations" } { "n" integer } }
{ $description "A generalization of " { $link spread } " that can work for any quotation arity."
} ;
HELP: mnswap HELP: mnswap
{ $values { "m" integer } { "n" integer } } { $values { "m" integer } { "n" integer } }
{ $description "Swaps the top " { $snippet "m" } " stack elements with the " { $snippet "n" } " elements directly underneath." } { $description "Swaps the top " { $snippet "m" } " stack elements with the " { $snippet "n" } " elements directly underneath." }
@ -250,6 +259,17 @@ HELP: mnswap
} }
} ; } ;
HELP: nweave
{ $values { "n" integer } }
{ $description "Copies the top " { $snippet "n" } " stack elements underneath each one of the " { $snippet "n" } " elements below." }
{ $examples
{ $example
"USING: arrays kernel generalizations prettyprint ;"
"\"e1\" \"e2\" \"o1\" \"o2\" 2 nweave [ 3array ] 3dip 3array 2array ."
"{ { \"e1\" \"o1\" \"o2\" } { \"e2\" \"o1\" \"o2\" } }"
}
} ;
HELP: n*quot HELP: n*quot
{ $values { $values
{ "n" integer } { "seq" sequence } { "n" integer } { "seq" sequence }
@ -299,18 +319,14 @@ HELP: ntuck
} }
{ $description "A generalization of " { $link tuck } " that can work for any stack depth. The top item will be copied and placed " { $snippet "n" } " items down on the stack." } ; { $description "A generalization of " { $link tuck } " that can work for any stack depth. The top item will be copied and placed " { $snippet "n" } " items down on the stack." } ;
ARTICLE: "generalizations" "Generalized shuffle words and combinators" ARTICLE: "sequence-generalizations" "Generalized sequence operations"
"The " { $vocab-link "generalizations" } " vocabulary defines a number of stack shuffling words and combinators for use in "
"macros where the arity of the input quotations depends on an "
"input parameter."
$nl
"Generalized sequence operations:"
{ $subsection narray } { $subsection narray }
{ $subsection nsequence } { $subsection nsequence }
{ $subsection firstn } { $subsection firstn }
{ $subsection nappend } { $subsection nappend }
{ $subsection nappend-as } { $subsection nappend-as } ;
"Generated stack shuffle operations:"
ARTICLE: "shuffle-generalizations" "Generalized shuffle words"
{ $subsection ndup } { $subsection ndup }
{ $subsection npick } { $subsection npick }
{ $subsection nrot } { $subsection nrot }
@ -319,14 +335,28 @@ $nl
{ $subsection ndrop } { $subsection ndrop }
{ $subsection ntuck } { $subsection ntuck }
{ $subsection mnswap } { $subsection mnswap }
"Generalized combinators:" { $subsection nweave } ;
ARTICLE: "combinator-generalizations" "Generalized combinators"
{ $subsection ndip } { $subsection ndip }
{ $subsection nslip } { $subsection nslip }
{ $subsection nkeep } { $subsection nkeep }
{ $subsection napply } { $subsection napply }
{ $subsection ncleave } { $subsection ncleave }
"Generalized quotation construction:" { $subsection nspread } ;
ARTICLE: "other-generalizations" "Additional generalizations"
{ $subsection ncurry } { $subsection ncurry }
{ $subsection nwith } ; { $subsection nwith }
{ $subsection nsum } ;
ARTICLE: "generalizations" "Generalized shuffle words and combinators"
"The " { $vocab-link "generalizations" } " vocabulary defines a number of stack shuffling words and combinators for use in "
"macros where the arity of the input quotations depends on an "
"input parameter."
{ $subsection "sequence-generalizations" }
{ $subsection "shuffle-generalizations" }
{ $subsection "combinator-generalizations" }
{ $subsection "other-generalizations" } ;
ABOUT: "generalizations" ABOUT: "generalizations"

View File

@ -53,3 +53,12 @@ IN: generalizations.tests
[ 4 nappend ] must-infer [ 4 nappend ] must-infer
[ 4 { } nappend-as ] must-infer [ 4 { } nappend-as ] must-infer
[ 17 ] [ 3 1 3 3 7 5 nsum ] unit-test
{ 4 1 } [ 4 nsum ] must-infer-as
[ "e1" "o1" "o2" "e2" "o1" "o2" ] [ "e1" "e2" "o1" "o2" 2 nweave ] unit-test
{ 3 5 } [ 2 nweave ] must-infer-as
[ { 0 1 2 } { 3 5 4 } { 7 8 6 } ]
[ 9 [ ] each { [ 3array ] [ swap 3array ] [ rot 3array ] } 3 nspread ] unit-test

View File

@ -1,4 +1,4 @@
! Copyright (C) 2007, 2008 Chris Double, Doug Coleman, Eduardo ! Copyright (C) 2007, 2009 Chris Double, Doug Coleman, Eduardo
! Cavazos, Slava Pestov. ! Cavazos, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences sequences.private math combinators USING: kernel sequences sequences.private math combinators
@ -23,6 +23,9 @@ MACRO: nsequence ( n seq -- )
MACRO: narray ( n -- ) MACRO: narray ( n -- )
'[ _ { } nsequence ] ; '[ _ { } nsequence ] ;
MACRO: nsum ( n -- )
1- [ + ] n*quot ;
MACRO: firstn ( n -- ) MACRO: firstn ( n -- )
dup zero? [ drop [ drop ] ] [ dup zero? [ drop [ drop ] ] [
[ [ '[ [ _ ] dip nth-unsafe ] ] map ] [ [ '[ [ _ ] dip nth-unsafe ] ] map ]
@ -70,11 +73,23 @@ MACRO: ncleave ( quots n -- )
[ '[ _ '[ _ _ nkeep ] ] map [ ] join ] [ '[ _ ndrop ] ] bi [ '[ _ '[ _ _ nkeep ] ] map [ ] join ] [ '[ _ ndrop ] ] bi
compose ; compose ;
MACRO: nspread ( quots n -- )
over empty? [ 2drop [ ] ] [
[ [ but-last ] dip ]
[ [ peek ] dip ] 2bi
swap
'[ [ _ _ nspread ] _ ndip @ ]
] if ;
MACRO: napply ( quot n -- ) MACRO: napply ( quot n -- )
swap <repetition> spread>quot ; swap <repetition> spread>quot ;
MACRO: mnswap ( m n -- ) MACRO: mnswap ( m n -- )
1+ '[ _ -nrot ] <repetition> spread>quot ; 1+ '[ _ -nrot ] swap '[ _ _ napply ] ;
MACRO: nweave ( n -- )
[ dup <reversed> [ '[ _ _ mnswap ] ] with map ] keep
'[ _ _ ncleave ] ;
: nappend-as ( n exemplar -- seq ) : nappend-as ( n exemplar -- seq )
[ narray concat ] dip like ; inline [ narray concat ] dip like ; inline

View File

@ -118,7 +118,7 @@ M: word set-article-parent swap "help-parent" set-word-prop ;
SYMBOL: help-hook SYMBOL: help-hook
help-hook global [ [ print-topic ] or ] change-at help-hook [ [ print-topic ] ] initialize
: help ( topic -- ) : help ( topic -- )
help-hook get call ; help-hook get call ;

View File

@ -7,7 +7,7 @@ combinators combinators.short-circuit splitting debugger
hashtables sorting effects vocabs vocabs.loader assocs editors hashtables sorting effects vocabs vocabs.loader assocs editors
continuations classes.predicate macros math sets eval continuations classes.predicate macros math sets eval
vocabs.parser words.symbol values grouping unicode.categories vocabs.parser words.symbol values grouping unicode.categories
sequences.deep ; sequences.deep call ;
IN: help.lint IN: help.lint
SYMBOL: vocabs-quot SYMBOL: vocabs-quot
@ -15,9 +15,9 @@ SYMBOL: vocabs-quot
: check-example ( element -- ) : check-example ( element -- )
[ [
rest [ rest [
but-last "\n" join 1vector but-last "\n" join
[ (eval>string) ] with-datastack [ (eval>string) ] call( code -- output )
peek "\n" ?tail drop "\n" ?tail drop
] keep ] keep
peek assert= peek assert=
] vocabs-quot get call ; ] vocabs-quot get call ;
@ -145,7 +145,7 @@ M: help-error error.
bi ; bi ;
: check-something ( obj quot -- ) : check-something ( obj quot -- )
flush '[ _ assert-depth ] swap '[ _ <help-error> , ] recover ; inline flush '[ _ call( -- ) ] swap '[ _ <help-error> , ] recover ; inline
: check-word ( word -- ) : check-word ( word -- )
[ with-file-vocabs ] vocabs-quot set [ with-file-vocabs ] vocabs-quot set

View File

@ -27,11 +27,11 @@ M: link summary
! Help articles ! Help articles
SYMBOL: articles SYMBOL: articles
articles global [ H{ } assoc-like ] change-at articles [ H{ } clone ] initialize
SYMBOL: article-xref SYMBOL: article-xref
article-xref global [ H{ } assoc-like ] change-at article-xref [ H{ } clone ] initialize
GENERIC: article-name ( topic -- string ) GENERIC: article-name ( topic -- string )
GENERIC: article-title ( topic -- string ) GENERIC: article-title ( topic -- string )

View File

@ -57,7 +57,10 @@ HELP: hidden
{ $description "Hidden components render as a hidden form field. For example, a page for editing a weblog post might contain a hidden field with the post ID." } ; { $description "Hidden components render as a hidden form field. For example, a page for editing a weblog post might contain a hidden field with the post ID." } ;
HELP: html HELP: html
{ $description "HTML components render HTML verbatim, without any escaping. Care must be taken to only render trusted input, to avoid cross-site scripting attacks." } ; { $description "HTML components render HTML verbatim from a string, without any escaping. Care must be taken to only render trusted input, to avoid cross-site scripting attacks." } ;
HELP: xml
{ $description "XML components render XML verbatim, from an XML chunk. Care must be taken to only render trusted input, to avoid cross-site scripting attacks." } ;
HELP: inspector HELP: inspector
{ $description "Inspector components render an arbitrary object by passing it to the " { $link describe } " word." } ; { $description "Inspector components render an arbitrary object by passing it to the " { $link describe } " word." } ;
@ -90,6 +93,7 @@ $nl
{ $subsection inspector } { $subsection inspector }
{ $subsection comparison } { $subsection comparison }
{ $subsection html } { $subsection html }
{ $subsection xml }
"Tuple components:" "Tuple components:"
{ $subsection field } { $subsection field }
{ $subsection password } { $subsection password }

View File

@ -171,3 +171,8 @@ M: comparison render*
SINGLETON: html SINGLETON: html
M: html render* 2drop <unescaped> ; M: html render* 2drop <unescaped> ;
! XML component
SINGLETON: xml
M: xml render* 2drop ;

View File

@ -0,0 +1,7 @@
USING: help.markup help.syntax strings xml.data ;
IN: html
HELP: simple-page
{ $values { "title" string } { "head" "XML data" } { "body" "XML data" }
{ "xml" xml } }
{ $description "Constructs a simple XHTML page with a " { $snippet "head" } " and " { $snippet "body" } " tag. The given XML data is spliced into the two child tags, and a title is also added to the head tag." } ;

View File

@ -15,7 +15,7 @@ IN: html
</head> </head>
<body><-></body> <body><-></body>
</html> </html>
XML> ; inline XML> ;
: render-error ( message -- xml ) : render-error ( message -- xml )
[XML <span class="error"><-></span> XML] ; [XML <span class="error"><-></span> XML] ;

View File

@ -1,8 +1,8 @@
IN: html.templates.chloe IN: html.templates.chloe
USING: help.markup help.syntax html.components html.forms USING: xml.data help.markup help.syntax html.components html.forms
html.templates html.templates.chloe.syntax html.templates html.templates.chloe.syntax
html.templates.chloe.compiler html.templates.chloe.components html.templates.chloe.compiler html.templates.chloe.components
math xml.data strings quotations namespaces ; math strings quotations namespaces ;
HELP: <chloe> HELP: <chloe>
{ $values { "path" "a pathname string without the trailing " { $snippet ".xml" } " extension" } { "chloe" chloe } } { $values { "path" "a pathname string without the trailing " { $snippet ".xml" } " extension" } { "chloe" chloe } }
@ -70,6 +70,7 @@ ARTICLE: "html.templates.chloe.tags.component" "Component Chloe tags"
{ { $snippet "t:field" } { $link field } } { { $snippet "t:field" } { $link field } }
{ { $snippet "t:hidden" } { $link hidden } } { { $snippet "t:hidden" } { $link hidden } }
{ { $snippet "t:html" } { $link html } } { { $snippet "t:html" } { $link html } }
{ { $snippet "t:xml" } { $link xml } }
{ { $snippet "t:inspector" } { $link inspector } } { { $snippet "t:inspector" } { $link inspector } }
{ { $snippet "t:label" } { $link label } } { { $snippet "t:label" } { $link label } }
{ { $snippet "t:link" } { $link link } } { { $snippet "t:link" } { $link link } }

View File

@ -4,7 +4,7 @@ USING: accessors kernel sequences combinators kernel fry
namespaces make classes.tuple assocs splitting words arrays io namespaces make classes.tuple assocs splitting words arrays io
io.files io.files.info io.encodings.utf8 io.streams.string io.files io.files.info io.encodings.utf8 io.streams.string
unicode.case mirrors math urls present multiline quotations xml unicode.case mirrors math urls present multiline quotations xml
logging continuations logging call
xml.data xml.writer xml.syntax strings xml.data xml.writer xml.syntax strings
html.forms html.forms
html html
@ -95,6 +95,7 @@ COMPONENT: password
COMPONENT: choice COMPONENT: choice
COMPONENT: checkbox COMPONENT: checkbox
COMPONENT: code COMPONENT: code
COMPONENT: xml
SYMBOL: template-cache SYMBOL: template-cache
@ -130,6 +131,6 @@ TUPLE: cached-template path last-modified quot ;
template-cache get clear-assoc ; template-cache get clear-assoc ;
M: chloe call-template* M: chloe call-template*
template-quot assert-depth ; template-quot call( -- ) ;
INSTANCE: chloe template INSTANCE: chloe template

View File

@ -2,8 +2,8 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: assocs namespaces make kernel sequences accessors USING: assocs namespaces make kernel sequences accessors
combinators strings splitting io io.streams.string present combinators strings splitting io io.streams.string present
xml.writer xml.data xml.entities html.forms xml.writer xml.data xml.entities html.forms call
html.templates html.templates.chloe.syntax continuations ; html.templates html.templates.chloe.syntax ;
IN: html.templates.chloe.compiler IN: html.templates.chloe.compiler
: chloe-attrs-only ( assoc -- assoc' ) : chloe-attrs-only ( assoc -- assoc' )
@ -83,7 +83,7 @@ ERROR: unknown-chloe-tag tag ;
: compile-chloe-tag ( tag -- ) : compile-chloe-tag ( tag -- )
dup main>> dup tags get at dup main>> dup tags get at
[ curry assert-depth ] [ call( tag -- ) ]
[ unknown-chloe-tag ] [ unknown-chloe-tag ]
?if ; ?if ;

View File

@ -11,7 +11,7 @@ html.templates ;
SYMBOL: tags SYMBOL: tags
tags global [ H{ } clone or ] change-at tags [ H{ } clone ] initialize
: define-chloe-tag ( name quot -- ) swap tags get set-at ; : define-chloe-tag ( name quot -- ) swap tags get set-at ;

View File

@ -3,7 +3,7 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: continuations sequences kernel namespaces debugger USING: continuations sequences kernel namespaces debugger
combinators math quotations generic strings splitting accessors combinators math quotations generic strings splitting accessors
assocs fry vocabs.parser parser lexer io io.files assocs fry vocabs.parser parser lexer io io.files call
io.streams.string io.encodings.utf8 html.templates ; io.streams.string io.encodings.utf8 html.templates ;
IN: html.templates.fhtml IN: html.templates.fhtml
@ -72,6 +72,6 @@ TUPLE: fhtml path ;
C: <fhtml> fhtml C: <fhtml> fhtml
M: fhtml call-template* ( filename -- ) M: fhtml call-template* ( filename -- )
'[ _ path>> utf8 file-contents eval-template ] assert-depth ; [ path>> utf8 file-contents eval-template ] call( filename -- ) ;
INSTANCE: fhtml template INSTANCE: fhtml template

View File

@ -56,8 +56,7 @@ HELP: http-request
HELP: with-http-request HELP: with-http-request
{ $values { "request" request } { "quot" { $quotation "( chunk -- )" } } { "response" response } } { $values { "request" request } { "quot" { $quotation "( chunk -- )" } } { "response" response } }
{ $description "Sends an HTTP request to an HTTP server, and reads the response incrementally. Chunks of data are passed to the quotation as they are read." } { $description "Sends an HTTP request to an HTTP server, and reads the response incrementally. Chunks of data are passed to the quotation as they are read. Does not throw an error if the HTTP request fails; to do so, call " { $link check-response } " on the " { $snippet "response" } "." } ;
{ $errors "Throws an error if the HTTP request fails." } ;
ARTICLE: "http.client.get" "GET requests with the HTTP client" ARTICLE: "http.client.get" "GET requests with the HTTP client"
"Basic usage involves passing a " { $link url } " and getting a " { $link response } " and data back:" "Basic usage involves passing a " { $link url } " and getting a " { $link response } " and data back:"

View File

@ -141,12 +141,15 @@ ERROR: download-failed response ;
: check-response ( response -- response ) : check-response ( response -- response )
dup code>> success? [ download-failed ] unless ; dup code>> success? [ download-failed ] unless ;
: check-response-with-body ( response body -- response body )
[ >>body check-response ] keep ;
: with-http-request ( request quot -- response ) : with-http-request ( request quot -- response )
[ (with-http-request) check-response ] with-destructors ; inline [ (with-http-request) ] with-destructors ; inline
: http-request ( request -- response data ) : http-request ( request -- response data )
[ [ % ] with-http-request ] B{ } make [ [ % ] with-http-request ] B{ } make
over content-charset>> decode ; over content-charset>> decode check-response-with-body ;
: <get-request> ( url -- request ) : <get-request> ( url -- request )
"GET" <client-request> ; "GET" <client-request> ;

View File

@ -113,6 +113,12 @@ HELP: set-header
{ $notes "This word always returns the same object that was input. This allows for a “pipeline” coding style, where several header parameters are set in a row." } { $notes "This word always returns the same object that was input. This allows for a “pipeline” coding style, where several header parameters are set in a row." }
{ $side-effects "request/response" } ; { $side-effects "request/response" } ;
HELP: set-basic-auth
{ $values { "request" request } { "username" string } { "password" string } }
{ $description "Sets the " { $snippet "Authorization" } " header of " { $snippet "request" } " to perform HTTP Basic authentication with the given " { $snippet "username" } " and " { $snippet "password" } "." }
{ $notes "This word always returns the same object that was input. This allows for a “pipeline” coding style, where several header parameters are set in a row." }
{ $side-effects "request" } ;
ARTICLE: "http.cookies" "HTTP cookies" ARTICLE: "http.cookies" "HTTP cookies"
"Every " { $link request } " and " { $link response } " instance can contain cookies." "Every " { $link request } " and " { $link response } " instance can contain cookies."
$nl $nl

View File

@ -359,3 +359,8 @@ SYMBOL: a
! Test cloning ! Test cloning
[ f ] [ <404> dup clone "b" "a" set-header drop "a" header ] unit-test [ f ] [ <404> dup clone "b" "a" set-header drop "a" header ] unit-test
[ f ] [ <404> dup clone "b" "a" <cookie> put-cookie drop "a" get-cookie ] unit-test [ f ] [ <404> dup clone "b" "a" <cookie> put-cookie drop "a" get-cookie ] unit-test
! Test basic auth
[ "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" ] [ <request> "Aladdin" "open sesame" set-basic-auth "Authorization" header ] unit-test

View File

@ -7,7 +7,8 @@ calendar.format present urls fry
io io.encodings io.encodings.iana io.encodings.binary io io.encodings io.encodings.iana io.encodings.binary
io.encodings.8-bit io.crlf io.encodings.8-bit io.crlf
unicode.case unicode.categories unicode.case unicode.categories
http.parsers ; http.parsers
base64 ;
IN: http IN: http
: (read-header) ( -- alist ) : (read-header) ( -- alist )
@ -142,6 +143,9 @@ cookies ;
: set-header ( request/response value key -- request/response ) : set-header ( request/response value key -- request/response )
pick header>> set-at ; pick header>> set-at ;
: set-basic-auth ( request username password -- request )
":" glue >base64 "Basic " prepend "Authorization" set-header ;
: <request> ( -- request ) : <request> ( -- request )
request new request new
"1.1" >>version "1.1" >>version
@ -156,6 +160,7 @@ cookies ;
: header ( request/response key -- value ) : header ( request/response key -- value )
swap header>> at ; swap header>> at ;
TUPLE: response TUPLE: response
version version
code code

View File

@ -161,7 +161,7 @@ C: <trivial-responder> trivial-responder
M: trivial-responder call-responder* nip response>> clone ; M: trivial-responder call-responder* nip response>> clone ;
main-responder global [ <404> <trivial-responder> or ] change-at main-responder [ <404> <trivial-responder> ] initialize
: invert-slice ( slice -- slice' ) : invert-slice ( slice -- slice' )
dup slice? [ [ seq>> ] [ from>> ] bi head-slice ] [ drop { } ] if ; dup slice? [ [ seq>> ] [ from>> ] bi head-slice ] [ drop { } ] if ;

View File

@ -38,7 +38,7 @@ $nl
"If all you want to do is serve files from a directory, the following phrase does the trick:" "If all you want to do is serve files from a directory, the following phrase does the trick:"
{ $code { $code
"USING: namespaces http.server http.server.static ;" "USING: namespaces http.server http.server.static ;"
"/var/www/mysite.com/ <static> main-responder set" "\"/var/www/mysite.com/\" <static> main-responder set"
"8080 httpd" "8080 httpd"
} }
{ $subsection "http.server.static.extend" } ; { $subsection "http.server.static.extend" } ;

View File

@ -45,9 +45,8 @@ TUPLE: file-responder root hook special allow-listings ;
[ file-responder get hook>> call ] [ 2drop <304> ] if ; [ file-responder get hook>> call ] [ 2drop <304> ] if ;
: serving-path ( filename -- filename ) : serving-path ( filename -- filename )
file-responder get root>> trim-tail-separators [ file-responder get root>> trim-tail-separators "/" ] dip
"/" "" or trim-head-separators 3append ;
rot "" or trim-head-separators 3append ;
: serve-file ( filename -- response ) : serve-file ( filename -- response )
dup mime-type dup mime-type

1
basis/images/authors.txt Normal file
View File

@ -0,0 +1 @@
Doug Coleman

View File

View File

@ -0,0 +1,24 @@
USING: images.bitmap images.viewer io.encodings.binary
io.files io.files.unique kernel tools.test ;
IN: images.bitmap.tests
: test-bitmap24 ( -- path )
"resource:basis/images/test-images/thiswayup24.bmp" ;
: test-bitmap8 ( -- path )
"resource:basis/images/test-images/rgb8bit.bmp" ;
: test-bitmap4 ( -- path )
"resource:basis/images/test-images/rgb4bit.bmp" ;
: test-bitmap1 ( -- path )
"resource:basis/images/test-images/1bit.bmp" ;
[ t ]
[
test-bitmap24
[ binary file-contents ] [ load-bitmap ] bi
"test-bitmap24" unique-file
[ save-bitmap ] [ binary file-contents ] bi =
] unit-test

View File

@ -1,11 +1,12 @@
! Copyright (C) 2007, 2009 Doug Coleman. ! Copyright (C) 2007, 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.c-types arrays byte-arrays columns USING: accessors alien alien.c-types arrays byte-arrays columns
combinators fry grouping io io.binary io.encodings.binary combinators fry grouping io io.binary io.encodings.binary io.files
io.files kernel libc macros math math.bitwise math.functions kernel macros math math.bitwise math.functions namespaces sequences
namespaces opengl opengl.gl prettyprint sequences strings strings images endian summary ;
summary ui ui.gadgets.panes ; IN: images.bitmap
IN: graphics.bitmap
TUPLE: bitmap-image < image ;
! Currently can only handle 24/32bit bitmaps. ! Currently can only handle 24/32bit bitmaps.
! Handles row-reversed bitmaps (their height is negative) ! Handles row-reversed bitmaps (their height is negative)
@ -13,41 +14,24 @@ IN: graphics.bitmap
TUPLE: bitmap magic size reserved offset header-length width TUPLE: bitmap magic size reserved offset header-length width
height planes bit-count compression size-image height planes bit-count compression size-image
x-pels y-pels color-used color-important rgb-quads color-index x-pels y-pels color-used color-important rgb-quads color-index
alpha-channel-zero? buffer ;
array ;
: array-copy ( bitmap array -- bitmap array' ) : array-copy ( bitmap array -- bitmap array' )
over size-image>> abs memory>byte-array ; over size-image>> abs memory>byte-array ;
MACRO: (nbits>bitmap) ( bits -- ) : 8bit>buffer ( bitmap -- array )
[ -3 shift ] keep '[
bitmap new
2over * _ * >>size-image
swap >>height
swap >>width
swap array-copy [ >>array ] [ >>color-index ] bi
_ >>bit-count
] ;
: bgr>bitmap ( array height width -- bitmap )
24 (nbits>bitmap) ;
: bgra>bitmap ( array height width -- bitmap )
32 (nbits>bitmap) ;
: 8bit>array ( bitmap -- array )
[ rgb-quads>> 4 <sliced-groups> [ 3 head-slice ] map ] [ rgb-quads>> 4 <sliced-groups> [ 3 head-slice ] map ]
[ color-index>> >array ] bi [ swap nth ] with map concat ; [ color-index>> >array ] bi [ swap nth ] with map concat ;
ERROR: bmp-not-supported n ; ERROR: bmp-not-supported n ;
: raw-bitmap>array ( bitmap -- array ) : raw-bitmap>buffer ( bitmap -- array )
dup bit-count>> dup bit-count>>
{ {
{ 32 [ color-index>> ] } { 32 [ color-index>> ] }
{ 24 [ color-index>> ] } { 24 [ color-index>> ] }
{ 16 [ bmp-not-supported ] } { 16 [ bmp-not-supported ] }
{ 8 [ 8bit>array ] } { 8 [ 8bit>buffer ] }
{ 4 [ bmp-not-supported ] } { 4 [ bmp-not-supported ] }
{ 2 [ bmp-not-supported ] } { 2 [ bmp-not-supported ] }
{ 1 [ bmp-not-supported ] } { 1 [ bmp-not-supported ] }
@ -95,19 +79,58 @@ M: bitmap-magic summary
dup rgb-quads-length read >>rgb-quads dup rgb-quads-length read >>rgb-quads
dup color-index-length read >>color-index ; dup color-index-length read >>color-index ;
: (load-bitmap) ( path -- bitmap ) : load-bitmap-data ( path -- bitmap )
binary [ binary [
bitmap new bitmap new
parse-file-header parse-bitmap-header parse-bitmap parse-file-header parse-bitmap-header parse-bitmap
] with-file-reader ; ] with-file-reader ;
: alpha-channel-zero? ( bitmap -- ? ) : process-bitmap-data ( bitmap -- bitmap )
array>> 4 <sliced-groups> 3 <column> [ 0 = ] all? ; dup raw-bitmap>buffer >>buffer ;
: load-bitmap ( path -- bitmap ) : load-bitmap ( path -- bitmap )
(load-bitmap) load-bitmap-data process-bitmap-data ;
dup raw-bitmap>array >>array
dup alpha-channel-zero? >>alpha-channel-zero? ; ERROR: unknown-component-order bitmap ;
: bitmap>component-order ( bitmap -- object )
bit-count>> {
{ 32 [ BGRA ] }
{ 24 [ BGR ] }
{ 8 [ BGR ] }
[ unknown-component-order ]
} case ;
: >image ( bitmap -- bitmap-image )
{
[ [ width>> ] [ height>> ] bi 2array ]
[ bitmap>component-order ]
[ buffer>> ]
} cleave bitmap-image boa ;
M: bitmap-image load-image* ( path bitmap -- bitmap-image )
drop load-bitmap >image ;
M: bitmap-image normalize-scan-line-order
dup dim>> '[
_ first 4 * <sliced-groups> reverse concat
] change-bitmap ;
MACRO: (nbits>bitmap) ( bits -- )
[ -3 shift ] keep '[
bitmap new
2over * _ * >>size-image
swap >>height
swap >>width
swap array-copy [ >>buffer ] [ >>color-index ] bi
_ >>bit-count >image
] ;
: bgr>bitmap ( array height width -- bitmap )
24 (nbits>bitmap) ;
: bgra>bitmap ( array height width -- bitmap )
32 (nbits>bitmap) ;
: write2 ( n -- ) 2 >le write ; : write2 ( n -- ) 2 >le write ;
: write4 ( n -- ) 4 >le write ; : write4 ( n -- ) 4 >le write ;
@ -116,7 +139,7 @@ M: bitmap-magic summary
binary [ binary [
B{ CHAR: B CHAR: M } write B{ CHAR: B CHAR: M } write
[ [
array>> length 14 + 40 + write4 buffer>> length 14 + 40 + write4
0 write4 0 write4
54 write4 54 write4
40 write4 40 write4

View File

@ -0,0 +1,62 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors grouping sequences combinators
math specialized-arrays.direct.uint byte-arrays
specialized-arrays.direct.ushort ;
IN: images
SINGLETONS: BGR RGB BGRA RGBA ABGR ARGB RGBX XRGB BGRX XBGR
R16G16B16 R32G32B32 ;
TUPLE: image dim component-order bitmap ;
: <image> ( -- image ) image new ; inline
GENERIC: load-image* ( path tuple -- image )
: add-dummy-alpha ( seq -- seq' )
3 <sliced-groups>
[ 255 suffix ] map concat ;
: normalize-component-order ( image -- image )
dup component-order>>
{
{ RGBA [ ] }
{ R32G32B32 [
[
dup length 4 / <direct-uint-array>
[ bits>float 255.0 * >integer ] map
>byte-array add-dummy-alpha
] change-bitmap
] }
{ R16G16B16 [
[
dup length 2 / <direct-ushort-array>
[ -8 shift ] map
>byte-array add-dummy-alpha
] change-bitmap
] }
{ BGRA [
[
4 <sliced-groups> dup [ [ 0 3 ] dip <slice> reverse-here ] each
] change-bitmap
] }
{ RGB [ [ add-dummy-alpha ] change-bitmap ] }
{ BGR [
[
3 <sliced-groups>
[ [ [ 0 3 ] dip <slice> reverse-here ] each ]
[ add-dummy-alpha ] bi
] change-bitmap
] }
} case
RGBA >>component-order ;
GENERIC: normalize-scan-line-order ( image -- image )
M: image normalize-scan-line-order ;
: normalize-image ( image -- image )
[ >byte-array ] change-bitmap
normalize-component-order
normalize-scan-line-order ;

View File

View File

@ -0,0 +1,19 @@
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: constructors kernel splitting unicode.case combinators
accessors images.bitmap images.tiff images io.backend
io.pathnames ;
IN: images.loader
ERROR: unknown-image-extension extension ;
: image-class ( path -- class )
file-extension >lower {
{ "bmp" [ bitmap-image ] }
{ "tif" [ tiff-image ] }
{ "tiff" [ tiff-image ] }
[ unknown-image-extension ]
} case ;
: load-image ( path -- image )
dup image-class new load-image* normalize-image ;

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

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