Merge branch 'master' of git://factorcode.org/git/factor into tangle
commit
7ff62f2811
|
@ -204,7 +204,7 @@ ARTICLE: "alien-callback-gc" "Callbacks and code GC"
|
|||
"A callback consits of two parts; the callback word, which pushes the address of the callback on the stack when executed, and the callback body itself. If the callback word is redefined, removed from the dictionary using " { $link forget } ", or recompiled, the callback body will not be reclaimed by the garbage collector, since potentially C code may be holding a reference to the callback body."
|
||||
$nl
|
||||
"This is the safest approach, however it can lead to code heap leaks when repeatedly reloading code which defines callbacks. If you are " { $emphasis "completely sure" } " that no running C code is holding a reference to any callbacks, you can blow them all away:"
|
||||
{ $code "USE: alien callbacks get clear-hash code-gc" }
|
||||
{ $code "USE: alien callbacks get clear-hash gc" }
|
||||
"This will reclaim all callback bodies which are otherwise unreachable from the dictionary (that is, their associated callback words have since been redefined, recompiled or forgotten)." ;
|
||||
|
||||
ARTICLE: "alien-callback" "Calling Factor from C"
|
||||
|
|
|
@ -62,22 +62,16 @@ TUPLE: library path abi dll ;
|
|||
: add-library ( name path abi -- )
|
||||
<library> swap libraries get set-at ;
|
||||
|
||||
TUPLE: alien-callback return parameters abi quot xt ;
|
||||
|
||||
ERROR: alien-callback-error ;
|
||||
|
||||
: alien-callback ( return parameters abi quot -- alien )
|
||||
alien-callback-error ;
|
||||
|
||||
TUPLE: alien-indirect return parameters abi ;
|
||||
|
||||
ERROR: alien-indirect-error ;
|
||||
|
||||
: alien-indirect ( ... funcptr return parameters abi -- )
|
||||
alien-indirect-error ;
|
||||
|
||||
TUPLE: alien-invoke library function return parameters abi ;
|
||||
|
||||
ERROR: alien-invoke-error library symbol ;
|
||||
|
||||
: alien-invoke ( ... return library function parameters -- ... )
|
||||
|
|
|
@ -25,7 +25,7 @@ M: array box-return drop "void*" box-return ;
|
|||
|
||||
M: array stack-size drop "void*" stack-size ;
|
||||
|
||||
M: value-type c-type-reg-class drop T{ int-regs } ;
|
||||
M: value-type c-type-reg-class drop int-regs ;
|
||||
|
||||
M: value-type c-type-prep drop f ;
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ USING: bit-arrays byte-arrays float-arrays arrays
|
|||
generator.registers assocs kernel kernel.private libc math
|
||||
namespaces parser sequences strings words assocs splitting
|
||||
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 ;
|
||||
IN: alien.c-types
|
||||
|
||||
DEFER: <int>
|
||||
|
@ -17,8 +18,12 @@ boxer prep unboxer
|
|||
getter setter
|
||||
reg-class size align stack-align? ;
|
||||
|
||||
: construct-c-type ( class -- type )
|
||||
construct-empty
|
||||
int-regs >>reg-class ;
|
||||
|
||||
: <c-type> ( -- type )
|
||||
T{ int-regs } { set-c-type-reg-class } \ c-type construct ;
|
||||
\ c-type construct-c-type ;
|
||||
|
||||
SYMBOL: c-types
|
||||
|
||||
|
@ -181,10 +186,10 @@ DEFER: >c-ushort-array
|
|||
: define-c-type ( type name vocab -- )
|
||||
>r tuck typedef r> [ define-nth ] 2keep define-set-nth ;
|
||||
|
||||
TUPLE: long-long-type ;
|
||||
TUPLE: long-long-type < c-type ;
|
||||
|
||||
: <long-long-type> ( type -- type )
|
||||
long-long-type construct-delegate ;
|
||||
: <long-long-type> ( -- type )
|
||||
long-long-type construct-c-type ;
|
||||
|
||||
M: long-long-type unbox-parameter ( n type -- )
|
||||
c-type-unboxer %unbox-long-long ;
|
||||
|
@ -235,22 +240,15 @@ M: long-long-type box-return ( type -- )
|
|||
: define-from-array ( type vocab -- )
|
||||
[ from-array-word ] 2keep c-array>quot define ;
|
||||
|
||||
: <primitive-type> ( getter setter width boxer unboxer -- type )
|
||||
<c-type>
|
||||
[ set-c-type-unboxer ] keep
|
||||
[ set-c-type-boxer ] keep
|
||||
[ set-c-type-size ] 2keep
|
||||
[ set-c-type-align ] keep
|
||||
[ set-c-type-setter ] keep
|
||||
[ set-c-type-getter ] keep ;
|
||||
|
||||
: define-primitive-type ( type name -- )
|
||||
"alien.c-types"
|
||||
[ define-c-type ] 2keep
|
||||
[ define-deref ] 2keep
|
||||
[ define-to-array ] 2keep
|
||||
[ define-from-array ] 2keep
|
||||
define-out ;
|
||||
{
|
||||
[ define-c-type ]
|
||||
[ define-deref ]
|
||||
[ define-to-array ]
|
||||
[ define-from-array ]
|
||||
[ define-out ]
|
||||
} 2cleave ;
|
||||
|
||||
: expand-constants ( c-type -- c-type' )
|
||||
#! We use word-def call instead of execute to get around
|
||||
|
@ -264,130 +262,157 @@ M: long-long-type box-return ( type -- )
|
|||
binary file-contents dup malloc-byte-array swap length ;
|
||||
|
||||
[
|
||||
[ alien-cell ]
|
||||
[ set-alien-cell ]
|
||||
bootstrap-cell
|
||||
"box_alien"
|
||||
"alien_offset" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-cell ] >>getter
|
||||
[ set-alien-cell ] >>setter
|
||||
bootstrap-cell >>size
|
||||
bootstrap-cell >>align
|
||||
"box_alien" >>boxer
|
||||
"alien_offset" >>unboxer
|
||||
"void*" define-primitive-type
|
||||
|
||||
[ alien-signed-8 ]
|
||||
[ set-alien-signed-8 ]
|
||||
8
|
||||
"box_signed_8"
|
||||
"to_signed_8" <primitive-type> <long-long-type>
|
||||
<long-long-type>
|
||||
[ alien-signed-8 ] >>getter
|
||||
[ set-alien-signed-8 ] >>setter
|
||||
8 >>size
|
||||
8 >>align
|
||||
"box_signed_8" >>boxer
|
||||
"to_signed_8" >>unboxer
|
||||
"longlong" define-primitive-type
|
||||
|
||||
[ alien-unsigned-8 ]
|
||||
[ set-alien-unsigned-8 ]
|
||||
8
|
||||
"box_unsigned_8"
|
||||
"to_unsigned_8" <primitive-type> <long-long-type>
|
||||
<long-long-type>
|
||||
[ alien-unsigned-8 ] >>getter
|
||||
[ set-alien-unsigned-8 ] >>setter
|
||||
8 >>size
|
||||
8 >>align
|
||||
"box_unsigned_8" >>boxer
|
||||
"to_unsigned_8" >>unboxer
|
||||
"ulonglong" define-primitive-type
|
||||
|
||||
[ alien-signed-cell ]
|
||||
[ set-alien-signed-cell ]
|
||||
bootstrap-cell
|
||||
"box_signed_cell"
|
||||
"to_fixnum" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-signed-cell ] >>getter
|
||||
[ set-alien-signed-cell ] >>setter
|
||||
bootstrap-cell >>size
|
||||
bootstrap-cell >>align
|
||||
"box_signed_cell" >>boxer
|
||||
"to_fixnum" >>unboxer
|
||||
"long" define-primitive-type
|
||||
|
||||
[ alien-unsigned-cell ]
|
||||
[ set-alien-unsigned-cell ]
|
||||
bootstrap-cell
|
||||
"box_unsigned_cell"
|
||||
"to_cell" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-unsigned-cell ] >>getter
|
||||
[ set-alien-unsigned-cell ] >>setter
|
||||
bootstrap-cell >>size
|
||||
bootstrap-cell >>align
|
||||
"box_unsigned_cell" >>boxer
|
||||
"to_cell" >>unboxer
|
||||
"ulong" define-primitive-type
|
||||
|
||||
[ alien-signed-4 ]
|
||||
[ set-alien-signed-4 ]
|
||||
4
|
||||
"box_signed_4"
|
||||
"to_fixnum" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-signed-4 ] >>getter
|
||||
[ set-alien-signed-4 ] >>setter
|
||||
4 >>size
|
||||
4 >>align
|
||||
"box_signed_4" >>boxer
|
||||
"to_fixnum" >>unboxer
|
||||
"int" define-primitive-type
|
||||
|
||||
[ alien-unsigned-4 ]
|
||||
[ set-alien-unsigned-4 ]
|
||||
4
|
||||
"box_unsigned_4"
|
||||
"to_cell" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-unsigned-4 ] >>getter
|
||||
[ set-alien-unsigned-4 ] >>setter
|
||||
4 >>size
|
||||
4 >>align
|
||||
"box_unsigned_4" >>boxer
|
||||
"to_cell" >>unboxer
|
||||
"uint" define-primitive-type
|
||||
|
||||
[ alien-signed-2 ]
|
||||
[ set-alien-signed-2 ]
|
||||
2
|
||||
"box_signed_2"
|
||||
"to_fixnum" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-signed-2 ] >>getter
|
||||
[ set-alien-signed-2 ] >>setter
|
||||
2 >>size
|
||||
2 >>align
|
||||
"box_signed_2" >>boxer
|
||||
"to_fixnum" >>unboxer
|
||||
"short" define-primitive-type
|
||||
|
||||
[ alien-unsigned-2 ]
|
||||
[ set-alien-unsigned-2 ]
|
||||
2
|
||||
"box_unsigned_2"
|
||||
"to_cell" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-unsigned-2 ] >>getter
|
||||
[ set-alien-unsigned-2 ] >>setter
|
||||
2 >>size
|
||||
2 >>align
|
||||
"box_unsigned_2" >>boxer
|
||||
"to_cell" >>unboxer
|
||||
"ushort" define-primitive-type
|
||||
|
||||
[ alien-signed-1 ]
|
||||
[ set-alien-signed-1 ]
|
||||
1
|
||||
"box_signed_1"
|
||||
"to_fixnum" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-signed-1 ] >>getter
|
||||
[ set-alien-signed-1 ] >>setter
|
||||
1 >>size
|
||||
1 >>align
|
||||
"box_signed_1" >>boxer
|
||||
"to_fixnum" >>unboxer
|
||||
"char" define-primitive-type
|
||||
|
||||
[ alien-unsigned-1 ]
|
||||
[ set-alien-unsigned-1 ]
|
||||
1
|
||||
"box_unsigned_1"
|
||||
"to_cell" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-unsigned-1 ] >>getter
|
||||
[ set-alien-unsigned-1 ] >>setter
|
||||
1 >>size
|
||||
1 >>align
|
||||
"box_unsigned_1" >>boxer
|
||||
"to_cell" >>unboxer
|
||||
"uchar" define-primitive-type
|
||||
|
||||
[ alien-unsigned-4 zero? not ]
|
||||
[ 1 0 ? set-alien-unsigned-4 ]
|
||||
4
|
||||
"box_boolean"
|
||||
"to_boolean" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-unsigned-4 zero? not ] >>getter
|
||||
[ 1 0 ? set-alien-unsigned-4 ] >>setter
|
||||
4 >>size
|
||||
4 >>align
|
||||
"box_boolean" >>boxer
|
||||
"to_boolean" >>unboxer
|
||||
"bool" define-primitive-type
|
||||
|
||||
[ alien-float ]
|
||||
[ >r >r >float r> r> set-alien-float ]
|
||||
4
|
||||
"box_float"
|
||||
"to_float" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-float ] >>getter
|
||||
[ >r >r >float r> r> set-alien-float ] >>setter
|
||||
4 >>size
|
||||
4 >>align
|
||||
"box_float" >>boxer
|
||||
"to_float" >>unboxer
|
||||
single-float-regs >>reg-class
|
||||
[ >float ] >>prep
|
||||
"float" define-primitive-type
|
||||
|
||||
T{ float-regs f 4 } "float" c-type set-c-type-reg-class
|
||||
[ >float ] "float" c-type set-c-type-prep
|
||||
|
||||
[ alien-double ]
|
||||
[ >r >r >float r> r> set-alien-double ]
|
||||
8
|
||||
"box_double"
|
||||
"to_double" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-double ] >>getter
|
||||
[ >r >r >float r> r> set-alien-double ] >>setter
|
||||
8 >>size
|
||||
8 >>align
|
||||
"box_double" >>boxer
|
||||
"to_double" >>unboxer
|
||||
double-float-regs >>reg-class
|
||||
[ >float ] >>prep
|
||||
"double" define-primitive-type
|
||||
|
||||
T{ float-regs f 8 } "double" c-type set-c-type-reg-class
|
||||
[ >float ] "double" c-type set-c-type-prep
|
||||
|
||||
[ alien-cell alien>char-string ]
|
||||
[ set-alien-cell ]
|
||||
bootstrap-cell
|
||||
"box_char_string"
|
||||
"alien_offset" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-cell alien>char-string ] >>getter
|
||||
[ set-alien-cell ] >>setter
|
||||
bootstrap-cell >>size
|
||||
bootstrap-cell >>align
|
||||
"box_char_string" >>boxer
|
||||
"alien_offset" >>unboxer
|
||||
[ string>char-alien ] >>prep
|
||||
"char*" define-primitive-type
|
||||
|
||||
"char*" "uchar*" typedef
|
||||
|
||||
[ string>char-alien ] "char*" c-type set-c-type-prep
|
||||
|
||||
[ alien-cell alien>u16-string ]
|
||||
[ set-alien-cell ]
|
||||
4
|
||||
"box_u16_string"
|
||||
"alien_offset" <primitive-type>
|
||||
<c-type>
|
||||
[ alien-cell alien>u16-string ] >>getter
|
||||
[ set-alien-cell ] >>setter
|
||||
4 >>size
|
||||
4 >>align
|
||||
"box_u16_string" >>boxer
|
||||
"alien_offset" >>unboxer
|
||||
[ string>u16-alien ] >>prep
|
||||
"ushort*" define-primitive-type
|
||||
|
||||
[ string>u16-alien ] "ushort*" c-type set-c-type-prep
|
||||
|
||||
os winnt? cpu x86.64? and "longlong" "long" ? "ptrdiff_t" typedef
|
||||
|
||||
] with-compilation-unit
|
||||
|
|
|
@ -87,7 +87,7 @@ FUNCTION: tiny ffi_test_17 int x ;
|
|||
[ -1 indirect-test-1 ] must-fail
|
||||
|
||||
: indirect-test-2
|
||||
"int" { "int" "int" } "cdecl" alien-indirect data-gc ;
|
||||
"int" { "int" "int" } "cdecl" alien-indirect gc ;
|
||||
|
||||
{ 3 1 } [ indirect-test-2 ] must-infer-as
|
||||
|
||||
|
@ -97,7 +97,7 @@ unit-test
|
|||
|
||||
: indirect-test-3
|
||||
"int" { "int" "int" "int" "int" } "stdcall" alien-indirect
|
||||
data-gc ;
|
||||
gc ;
|
||||
|
||||
<< "f-stdcall" f "stdcall" add-library >>
|
||||
|
||||
|
@ -106,13 +106,13 @@ unit-test
|
|||
|
||||
: ffi_test_18 ( w x y z -- int )
|
||||
"int" "f-stdcall" "ffi_test_18" { "int" "int" "int" "int" }
|
||||
alien-invoke data-gc ;
|
||||
alien-invoke gc ;
|
||||
|
||||
[ 25 ] [ 2 3 4 5 ffi_test_18 ] unit-test
|
||||
|
||||
: ffi_test_19 ( x y z -- bar )
|
||||
"bar" "f-stdcall" "ffi_test_19" { "long" "long" "long" }
|
||||
alien-invoke data-gc ;
|
||||
alien-invoke gc ;
|
||||
|
||||
[ 11 6 -7 ] [
|
||||
11 6 -7 ffi_test_19 dup bar-x over bar-y rot bar-z
|
||||
|
@ -143,7 +143,7 @@ FUNCTION: void ffi_test_20 double x1, double x2, double x3,
|
|||
"void"
|
||||
f "ffi_test_31"
|
||||
{ "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" }
|
||||
alien-invoke code-gc 3 ;
|
||||
alien-invoke gc 3 ;
|
||||
|
||||
[ 3 ] [ 42 [ ] each ffi_test_31 ] unit-test
|
||||
|
||||
|
@ -312,14 +312,14 @@ FUNCTION: double ffi_test_36 ( test-struct-12 x ) ;
|
|||
|
||||
: callback-4
|
||||
"void" { } "cdecl" [ "Hello world" write ] alien-callback
|
||||
data-gc ;
|
||||
gc ;
|
||||
|
||||
[ "Hello world" ] [
|
||||
[ callback-4 callback_test_1 ] with-string-writer
|
||||
] unit-test
|
||||
|
||||
: callback-5
|
||||
"void" { } "cdecl" [ data-gc ] alien-callback ;
|
||||
"void" { } "cdecl" [ gc ] alien-callback ;
|
||||
|
||||
[ "testing" ] [
|
||||
"testing" callback-5 callback_test_1
|
||||
|
|
|
@ -9,6 +9,14 @@ kernel.private threads continuations.private libc combinators
|
|||
compiler.errors continuations layouts accessors ;
|
||||
IN: alien.compiler
|
||||
|
||||
TUPLE: #alien-node < node return parameters abi ;
|
||||
|
||||
TUPLE: #alien-callback < #alien-node quot xt ;
|
||||
|
||||
TUPLE: #alien-indirect < #alien-node ;
|
||||
|
||||
TUPLE: #alien-invoke < #alien-node library function ;
|
||||
|
||||
: large-struct? ( ctype -- ? )
|
||||
dup c-struct? [
|
||||
heap-size struct-small-enough? not
|
||||
|
@ -62,29 +70,36 @@ GENERIC: reg-size ( register-class -- n )
|
|||
|
||||
M: int-regs reg-size drop cell ;
|
||||
|
||||
M: float-regs reg-size float-regs-size ;
|
||||
M: single-float-regs reg-size drop 4 ;
|
||||
|
||||
M: double-float-regs reg-size drop 8 ;
|
||||
|
||||
GENERIC: reg-class-variable ( register-class -- symbol )
|
||||
|
||||
M: reg-class reg-class-variable ;
|
||||
|
||||
M: float-regs reg-class-variable drop float-regs ;
|
||||
|
||||
GENERIC: inc-reg-class ( register-class -- )
|
||||
|
||||
: (inc-reg-class)
|
||||
dup class inc
|
||||
M: reg-class inc-reg-class
|
||||
dup reg-class-variable inc
|
||||
fp-shadows-int? [ reg-size stack-params +@ ] [ drop ] if ;
|
||||
|
||||
M: int-regs inc-reg-class
|
||||
(inc-reg-class) ;
|
||||
|
||||
M: float-regs inc-reg-class
|
||||
dup (inc-reg-class)
|
||||
dup call-next-method
|
||||
fp-shadows-int? [ reg-size cell /i int-regs +@ ] [ drop ] if ;
|
||||
|
||||
: reg-class-full? ( class -- ? )
|
||||
dup class get swap param-regs length >= ;
|
||||
[ reg-class-variable get ] [ param-regs length ] bi >= ;
|
||||
|
||||
: spill-param ( reg-class -- n reg-class )
|
||||
reg-size stack-params dup get -rot +@ T{ stack-params } ;
|
||||
stack-params get
|
||||
>r reg-size stack-params +@ r>
|
||||
stack-params ;
|
||||
|
||||
: fastcall-param ( reg-class -- n reg-class )
|
||||
[ dup class get swap inc-reg-class ] keep ;
|
||||
[ reg-class-variable get ] [ inc-reg-class ] [ ] tri ;
|
||||
|
||||
: alloc-parameter ( parameter -- reg reg-class )
|
||||
c-type-reg-class dup reg-class-full?
|
||||
|
@ -229,32 +244,32 @@ M: no-such-symbol compiler-error-type
|
|||
] if ;
|
||||
|
||||
: alien-invoke-dlsym ( node -- symbols dll )
|
||||
dup alien-invoke-function dup pick stdcall-mangle 2array
|
||||
swap alien-invoke-library library dup [ library-dll ] when
|
||||
dup function>> dup pick stdcall-mangle 2array
|
||||
swap library>> library dup [ dll>> ] when
|
||||
2dup check-dlsym ;
|
||||
|
||||
\ alien-invoke [
|
||||
! Four literals
|
||||
4 ensure-values
|
||||
\ alien-invoke empty-node
|
||||
#alien-invoke construct-empty
|
||||
! Compile-time parameters
|
||||
pop-parameters over set-alien-invoke-parameters
|
||||
pop-literal nip over set-alien-invoke-function
|
||||
pop-literal nip over set-alien-invoke-library
|
||||
pop-literal nip over set-alien-invoke-return
|
||||
pop-parameters >>parameters
|
||||
pop-literal nip >>function
|
||||
pop-literal nip >>library
|
||||
pop-literal nip >>return
|
||||
! Quotation which coerces parameters to required types
|
||||
dup make-prep-quot recursive-state get infer-quot
|
||||
! Set ABI
|
||||
dup alien-invoke-library
|
||||
library [ library-abi ] [ "cdecl" ] if*
|
||||
over set-alien-invoke-abi
|
||||
dup library>>
|
||||
library [ abi>> ] [ "cdecl" ] if*
|
||||
>>abi
|
||||
! Add node to IR
|
||||
dup node,
|
||||
! Magic #: consume exactly the number of inputs
|
||||
0 alien-invoke-stack
|
||||
] "infer" set-word-prop
|
||||
|
||||
M: alien-invoke generate-node
|
||||
M: #alien-invoke generate-node
|
||||
dup alien-invoke-frame [
|
||||
end-basic-block
|
||||
%prepare-alien-invoke
|
||||
|
@ -273,11 +288,11 @@ M: alien-indirect-error summary
|
|||
! Three literals and function pointer
|
||||
4 ensure-values
|
||||
4 reify-curries
|
||||
\ alien-indirect empty-node
|
||||
#alien-indirect construct-empty
|
||||
! Compile-time parameters
|
||||
pop-literal nip over set-alien-indirect-abi
|
||||
pop-parameters over set-alien-indirect-parameters
|
||||
pop-literal nip over set-alien-indirect-return
|
||||
pop-literal nip >>abi
|
||||
pop-parameters >>parameters
|
||||
pop-literal nip >>return
|
||||
! Quotation which coerces parameters to required types
|
||||
dup make-prep-quot [ dip ] curry recursive-state get infer-quot
|
||||
! Add node to IR
|
||||
|
@ -286,7 +301,7 @@ M: alien-indirect-error summary
|
|||
1 alien-invoke-stack
|
||||
] "infer" set-word-prop
|
||||
|
||||
M: alien-indirect generate-node
|
||||
M: #alien-indirect generate-node
|
||||
dup alien-invoke-frame [
|
||||
! Flush registers
|
||||
end-basic-block
|
||||
|
@ -315,17 +330,17 @@ M: alien-callback-error summary
|
|||
drop "Words calling ``alien-callback'' must be compiled with the optimizing compiler." ;
|
||||
|
||||
: callback-bottom ( node -- )
|
||||
alien-callback-xt [ word-xt drop <alien> ] curry
|
||||
xt>> [ word-xt drop <alien> ] curry
|
||||
recursive-state get infer-quot ;
|
||||
|
||||
\ alien-callback [
|
||||
4 ensure-values
|
||||
\ alien-callback empty-node dup node,
|
||||
pop-literal nip over set-alien-callback-quot
|
||||
pop-literal nip over set-alien-callback-abi
|
||||
pop-parameters over set-alien-callback-parameters
|
||||
pop-literal nip over set-alien-callback-return
|
||||
gensym dup register-callback over set-alien-callback-xt
|
||||
#alien-callback construct-empty dup node,
|
||||
pop-literal nip >>quot
|
||||
pop-literal nip >>abi
|
||||
pop-parameters >>parameters
|
||||
pop-literal nip >>return
|
||||
gensym dup register-callback >>xt
|
||||
callback-bottom
|
||||
] "infer" set-word-prop
|
||||
|
||||
|
@ -365,8 +380,7 @@ TUPLE: callback-context ;
|
|||
|
||||
: wrap-callback-quot ( node -- quot )
|
||||
[
|
||||
dup alien-callback-quot
|
||||
swap prepare-callback-return append ,
|
||||
[ quot>> ] [ prepare-callback-return ] bi append ,
|
||||
[ callback-context construct-empty do-callback ] %
|
||||
] [ ] make ;
|
||||
|
||||
|
@ -387,7 +401,7 @@ TUPLE: callback-context ;
|
|||
callback-unwind %unwind ;
|
||||
|
||||
: generate-callback ( node -- )
|
||||
dup alien-callback-xt dup [
|
||||
dup xt>> dup [
|
||||
init-templates
|
||||
%save-word-xt
|
||||
%prologue-later
|
||||
|
@ -398,5 +412,5 @@ TUPLE: callback-context ;
|
|||
] with-stack-frame
|
||||
] with-generator ;
|
||||
|
||||
M: alien-callback generate-node
|
||||
M: #alien-callback generate-node
|
||||
end-basic-block generate-callback iterate-next ;
|
||||
|
|
|
@ -19,7 +19,7 @@ IN: bootstrap.compiler
|
|||
enable-compiler
|
||||
|
||||
nl
|
||||
"Compiling some words to speed up bootstrap..." write flush
|
||||
"Compiling..." write flush
|
||||
|
||||
! Compile a set of words ahead of the full compile.
|
||||
! This set of words was determined semi-empirically
|
||||
|
@ -37,8 +37,6 @@ nl
|
|||
|
||||
wrap probe
|
||||
|
||||
delegate
|
||||
|
||||
underlying
|
||||
|
||||
find-pair-next namestack*
|
||||
|
@ -76,4 +74,6 @@ nl
|
|||
malloc calloc free memcpy
|
||||
} compile
|
||||
|
||||
vocabs [ words [ compiled? not ] subset compile "." write flush ] each
|
||||
|
||||
" done" print flush
|
||||
|
|
|
@ -4,9 +4,9 @@ USING: alien arrays bit-arrays byte-arrays generic assocs
|
|||
hashtables assocs hashtables.private io kernel kernel.private
|
||||
math namespaces parser prettyprint sequences sequences.private
|
||||
strings sbufs vectors words quotations assocs system layouts
|
||||
splitting growable classes classes.tuple classes.tuple.private
|
||||
words.private io.binary io.files vocabs vocabs.loader
|
||||
source-files definitions debugger float-arrays
|
||||
splitting growable classes classes.builtin classes.tuple
|
||||
classes.tuple.private words.private io.binary io.files vocabs
|
||||
vocabs.loader source-files definitions debugger float-arrays
|
||||
quotations.private sequences.private combinators
|
||||
io.encodings.binary ;
|
||||
IN: bootstrap.image
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
USING: alien arrays byte-arrays generic hashtables
|
||||
hashtables.private io kernel math namespaces parser sequences
|
||||
strings vectors words quotations assocs layouts classes
|
||||
classes.tuple classes.tuple.private kernel.private vocabs
|
||||
vocabs.loader source-files definitions slots.deprecated
|
||||
classes.union compiler.units bootstrap.image.private io.files
|
||||
accessors combinators ;
|
||||
classes.builtin classes.tuple classes.tuple.private
|
||||
kernel.private vocabs vocabs.loader source-files definitions
|
||||
slots.deprecated classes.union compiler.units
|
||||
bootstrap.image.private io.files accessors combinators ;
|
||||
IN: bootstrap.primitives
|
||||
|
||||
"Creating primitives and basic runtime structures..." print flush
|
||||
|
@ -30,7 +30,7 @@ crossref off
|
|||
! Bring up a bare cross-compiling vocabulary.
|
||||
"syntax" vocab vocab-words bootstrap-syntax set
|
||||
H{ } clone dictionary set
|
||||
H{ } clone changed-words set
|
||||
H{ } clone changed-definitions set
|
||||
H{ } clone forgotten-definitions set
|
||||
H{ } clone root-cache set
|
||||
H{ } clone source-files set
|
||||
|
@ -640,8 +640,7 @@ define-builtin
|
|||
{ "setenv" "kernel.private" }
|
||||
{ "(exists?)" "io.files.private" }
|
||||
{ "(directory)" "io.files.private" }
|
||||
{ "data-gc" "memory" }
|
||||
{ "code-gc" "memory" }
|
||||
{ "gc" "memory" }
|
||||
{ "gc-time" "memory" }
|
||||
{ "save-image" "memory" }
|
||||
{ "save-image-and-exit" "memory" }
|
||||
|
@ -738,6 +737,7 @@ define-builtin
|
|||
{ "resize-bit-array" "bit-arrays" }
|
||||
{ "resize-float-array" "float-arrays" }
|
||||
{ "dll-valid?" "alien" }
|
||||
{ "unimplemented" "kernel.private" }
|
||||
}
|
||||
dup length [ >r first2 r> make-primitive ] 2each
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ SYMBOL: bootstrap-time
|
|||
seq-diff
|
||||
[ "bootstrap." prepend require ] each ;
|
||||
|
||||
: compile-remaining ( -- )
|
||||
"Compiling remaining words..." print flush
|
||||
vocabs [ words [ compiled? not ] subset compile ] each ;
|
||||
! : compile-remaining ( -- )
|
||||
! "Compiling remaining words..." print flush
|
||||
! vocabs [ words [ compiled? not ] subset compile ] each ;
|
||||
|
||||
: count-words ( pred -- )
|
||||
all-words swap subset length number>string write ;
|
||||
|
@ -57,7 +57,7 @@ millis >r
|
|||
|
||||
default-image-name "output-image" set-global
|
||||
|
||||
"math help handbook compiler random tools ui ui.tools io" "include" set-global
|
||||
"math compiler help random tools ui ui.tools io handbook" "include" set-global
|
||||
"" "exclude" set-global
|
||||
|
||||
parse-command-line
|
||||
|
@ -79,10 +79,6 @@ os winnt? [ "windows.nt" require ] when
|
|||
load-components
|
||||
|
||||
run-bootstrap-init
|
||||
|
||||
"bootstrap.compiler" vocab [
|
||||
compile-remaining
|
||||
] when
|
||||
] with-compiler-errors
|
||||
:errors
|
||||
|
||||
|
|
|
@ -68,13 +68,13 @@ UNION: c a b ;
|
|||
[ t ] [ \ tuple-class \ class class< ] unit-test
|
||||
[ f ] [ \ class \ tuple-class class< ] unit-test
|
||||
|
||||
TUPLE: delegate-clone ;
|
||||
TUPLE: tuple-example ;
|
||||
|
||||
[ t ] [ \ null \ delegate-clone class< ] unit-test
|
||||
[ f ] [ \ object \ delegate-clone class< ] unit-test
|
||||
[ f ] [ \ object \ delegate-clone class< ] unit-test
|
||||
[ t ] [ \ delegate-clone \ tuple class< ] unit-test
|
||||
[ f ] [ \ tuple \ delegate-clone class< ] unit-test
|
||||
[ t ] [ \ null \ tuple-example class< ] unit-test
|
||||
[ f ] [ \ object \ tuple-example class< ] unit-test
|
||||
[ f ] [ \ object \ tuple-example class< ] unit-test
|
||||
[ t ] [ \ tuple-example \ tuple class< ] unit-test
|
||||
[ f ] [ \ tuple \ tuple-example class< ] unit-test
|
||||
|
||||
TUPLE: a1 ;
|
||||
TUPLE: b1 ;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
! Copyright (C) 2004, 2008 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: kernel classes combinators accessors sequences arrays
|
||||
vectors assocs namespaces words sorting layouts math hashtables
|
||||
kernel.private ;
|
||||
USING: kernel classes classes.builtin combinators accessors
|
||||
sequences arrays vectors assocs namespaces words sorting layouts
|
||||
math hashtables kernel.private ;
|
||||
IN: classes.algebra
|
||||
|
||||
: 2cache ( key1 key2 assoc quot -- value )
|
||||
|
@ -103,7 +103,7 @@ C: <anonymous-complement> anonymous-complement
|
|||
{
|
||||
{ [ over tuple eq? ] [ 2drop t ] }
|
||||
{ [ over builtin-class? ] [ 2drop f ] }
|
||||
{ [ over tuple-class? ] [ [ class< ] 2keep swap class< or ] }
|
||||
{ [ over tuple-class? ] [ [ class< ] [ swap class< ] 2bi or ] }
|
||||
{ [ t ] [ swap classes-intersect? ] }
|
||||
} cond ;
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
USING: help.syntax help.markup classes layouts ;
|
||||
IN: classes.builtin
|
||||
|
||||
ARTICLE: "builtin-classes" "Built-in classes"
|
||||
"Every object is an instance of exactly one canonical " { $emphasis "built-in class" } " which defines its layout in memory and basic behavior."
|
||||
$nl
|
||||
"The set of built-in classes is a class:"
|
||||
{ $subsection builtin-class }
|
||||
{ $subsection builtin-class? }
|
||||
"See " { $link "type-index" } " for a list of built-in classes." ;
|
||||
|
||||
HELP: builtin-class
|
||||
{ $class-description "The class of built-in classes." }
|
||||
{ $examples
|
||||
"The class of arrays is a built-in class:"
|
||||
{ $example "USING: arrays classes.builtin prettyprint ;" "array builtin-class? ." "t" }
|
||||
"However, an instance of the array class is not a built-in class; it is not even a class:"
|
||||
{ $example "USING: classes.builtin prettyprint ;" "{ 1 2 3 } builtin-class? ." "f" }
|
||||
} ;
|
||||
|
||||
HELP: builtins
|
||||
{ $var-description "Vector mapping type numbers to builtin class words." } ;
|
||||
|
||||
HELP: type>class
|
||||
{ $values { "n" "a non-negative integer" } { "class" class } }
|
||||
{ $description "Outputs a builtin class whose instances are precisely those having a given pointer tag." }
|
||||
{ $notes "The parameter " { $snippet "n" } " must be between 0 and the return value of " { $link num-types } "." } ;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
! Copyright (C) 2004, 2008 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: classes words kernel kernel.private namespaces
|
||||
sequences ;
|
||||
IN: classes.builtin
|
||||
|
||||
SYMBOL: builtins
|
||||
|
||||
PREDICATE: builtin-class < class
|
||||
"metaclass" word-prop builtin-class eq? ;
|
||||
|
||||
: type>class ( n -- class ) builtins get-global nth ;
|
||||
|
||||
: bootstrap-type>class ( n -- class ) builtins get nth ;
|
||||
|
||||
M: hi-tag class hi-tag type>class ;
|
||||
|
||||
M: object class tag type>class ;
|
|
@ -4,14 +4,6 @@ layouts classes.private classes.union classes.mixin
|
|||
classes.predicate quotations ;
|
||||
IN: classes
|
||||
|
||||
ARTICLE: "builtin-classes" "Built-in classes"
|
||||
"Every object is an instance of exactly one canonical " { $emphasis "built-in class" } " which defines its layout in memory and basic behavior."
|
||||
$nl
|
||||
"The set of built-in classes is a class:"
|
||||
{ $subsection builtin-class }
|
||||
{ $subsection builtin-class? }
|
||||
"See " { $link "type-index" } " for a list of built-in classes." ;
|
||||
|
||||
ARTICLE: "class-predicates" "Class predicate words"
|
||||
"With a handful of exceptions, each class has a membership predicate word, named " { $snippet { $emphasis "class" } "?" } " . A quotation calling this predicate is stored in the " { $snippet "\"predicate\"" } " word property."
|
||||
$nl
|
||||
|
@ -38,17 +30,21 @@ $nl
|
|||
{ $subsection class? }
|
||||
"You can ask an object for its class:"
|
||||
{ $subsection class }
|
||||
"Testing if an object is an instance of a class:"
|
||||
{ $subsection instance? }
|
||||
"There is a universal class which all objects are an instance of, and an empty class with no instances:"
|
||||
{ $subsection object }
|
||||
{ $subsection null }
|
||||
"Obtaining a list of all defined classes:"
|
||||
{ $subsection classes }
|
||||
"Other sorts of classes:"
|
||||
"There are several sorts of classes:"
|
||||
{ $subsection "builtin-classes" }
|
||||
{ $subsection "unions" }
|
||||
{ $subsection "singletons" }
|
||||
{ $subsection "mixins" }
|
||||
{ $subsection "predicates" }
|
||||
{ $subsection "singletons" }
|
||||
{ $link "tuples" } " are documented in their own section."
|
||||
$nl
|
||||
"Classes can be inspected and operated upon:"
|
||||
{ $subsection "class-operations" }
|
||||
{ $see-also "class-index" } ;
|
||||
|
@ -58,37 +54,20 @@ ABOUT: "classes"
|
|||
HELP: class
|
||||
{ $values { "object" object } { "class" class } }
|
||||
{ $description "Outputs an object's canonical class. While an object may be an instance of more than one class, the canonical class is either its built-in class, or if the object is a tuple, its tuple class." }
|
||||
{ $class-description "The class of all class words. Subclasses include " { $link builtin-class } ", " { $link union-class } ", " { $link mixin-class } ", " { $link predicate-class } " and " { $link tuple-class } "." }
|
||||
{ $class-description "The class of all class words." }
|
||||
{ $examples { $example "USING: classes prettyprint ;" "1.0 class ." "float" } { $example "USING: classes prettyprint ;" "TUPLE: point x y z ;\nT{ point f 1 2 3 } class ." "point" } } ;
|
||||
|
||||
HELP: classes
|
||||
{ $values { "seq" "a sequence of class words" } }
|
||||
{ $description "Finds all class words in the dictionary." } ;
|
||||
|
||||
HELP: builtin-class
|
||||
{ $class-description "The class of built-in classes." }
|
||||
{ $examples
|
||||
"The class of arrays is a built-in class:"
|
||||
{ $example "USING: arrays classes prettyprint ;" "array builtin-class? ." "t" }
|
||||
"However, an instance of the array class is not a built-in class; it is not even a class:"
|
||||
{ $example "USING: classes prettyprint ;" "{ 1 2 3 } builtin-class? ." "f" }
|
||||
} ;
|
||||
|
||||
HELP: tuple-class
|
||||
{ $class-description "The class of tuple class words." }
|
||||
{ $examples { $example "USING: classes prettyprint ;" "TUPLE: name title first last ;" "name tuple-class? ." "t" } } ;
|
||||
|
||||
HELP: builtins
|
||||
{ $var-description "Vector mapping type numbers to builtin class words." } ;
|
||||
|
||||
HELP: update-map
|
||||
{ $var-description "Hashtable mapping each class to a set of classes defined in terms of this class. The " { $link define-class } " word uses this information to update generic words when classes are redefined." } ;
|
||||
|
||||
HELP: type>class
|
||||
{ $values { "n" "a non-negative integer" } { "class" class } }
|
||||
{ $description "Outputs a builtin class whose instances are precisely those having a given pointer tag." }
|
||||
{ $notes "The parameter " { $snippet "n" } " must be between 0 and the return value of " { $link num-types } "." } ;
|
||||
|
||||
HELP: predicate-word
|
||||
{ $values { "word" "a word" } { "predicate" "a predicate word" } }
|
||||
{ $description "Suffixes the word's name with \"?\" and creates a word with that name in the same vocabulary as the word itself." } ;
|
||||
|
|
|
@ -30,20 +30,11 @@ SYMBOL: update-map
|
|||
PREDICATE: class < word
|
||||
"class" word-prop ;
|
||||
|
||||
SYMBOL: builtins
|
||||
|
||||
PREDICATE: builtin-class < class
|
||||
"metaclass" word-prop builtin-class eq? ;
|
||||
|
||||
PREDICATE: tuple-class < class
|
||||
"metaclass" word-prop tuple-class eq? ;
|
||||
|
||||
: classes ( -- seq ) all-words [ class? ] subset ;
|
||||
|
||||
: type>class ( n -- class ) builtins get-global nth ;
|
||||
|
||||
: bootstrap-type>class ( n -- class ) builtins get nth ;
|
||||
|
||||
: predicate-word ( word -- predicate )
|
||||
[ word-name "?" append ] keep word-vocabulary create ;
|
||||
|
||||
|
@ -130,9 +121,5 @@ GENERIC: update-methods ( assoc -- )
|
|||
|
||||
GENERIC: class ( object -- class )
|
||||
|
||||
M: hi-tag class hi-tag type>class ;
|
||||
|
||||
M: object class tag type>class ;
|
||||
|
||||
: instance? ( obj class -- ? )
|
||||
"predicate" word-prop call ;
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
USING: help.markup help.syntax help words compiler.units
|
||||
classes ;
|
||||
classes sequences ;
|
||||
IN: classes.mixin
|
||||
|
||||
ARTICLE: "mixins" "Mixin classes"
|
||||
"An object is an instance of a union class if it is an instance of one of its members. In this respect, mixin classes are identical to union classes. However, new classes can be made into instances of a mixin class after the original definition of the mixin."
|
||||
"An object is an instance of a union class if it is an instance of one of its members. In this respect, mixin classes are identical to union classes. However, mixin classes have the additional property that they are " { $emphasis "open" } "; new classes can be added to the mixin after the original definition of the mixin."
|
||||
{ $subsection POSTPONE: MIXIN: }
|
||||
{ $subsection POSTPONE: INSTANCE: }
|
||||
{ $subsection define-mixin-class }
|
||||
{ $subsection add-mixin-instance }
|
||||
"The set of mixin classes is a class:"
|
||||
{ $subsection mixin-class }
|
||||
{ $subsection mixin-class? } ;
|
||||
{ $subsection mixin-class? }
|
||||
"Mixins are used to defines suites of behavior which are generally useful and can be applied to user-defined classes. For example, the " { $link immutable-sequence } " mixin can be used with user-defined sequences to make them immutable."
|
||||
{ $see-also "unions" "tuple-subclassing" } ;
|
||||
|
||||
HELP: mixin-class
|
||||
{ $class-description "The class of mixin classes." } ;
|
||||
|
|
|
@ -2,27 +2,33 @@ USING: help.markup help.syntax kernel words ;
|
|||
IN: classes.singleton
|
||||
|
||||
ARTICLE: "singletons" "Singleton classes"
|
||||
"A singleton is a class with only one instance and with no state. Methods may dispatch off of singleton classes."
|
||||
"A singleton is a class with only one instance and with no state."
|
||||
{ $subsection POSTPONE: SINGLETON: }
|
||||
{ $subsection define-singleton-class } ;
|
||||
{ $subsection define-singleton-class }
|
||||
"The set of all singleton classes is itself a class:"
|
||||
{ $subsection singleton-class? }
|
||||
{ $subsection singleton-class } ;
|
||||
|
||||
HELP: SINGLETON:
|
||||
{ $syntax "SINGLETON: class"
|
||||
} { $values
|
||||
{ $syntax "SINGLETON: class" }
|
||||
{ $values
|
||||
{ "class" "a new singleton to define" }
|
||||
} { $description
|
||||
"Defines a new predicate class whose superclass is " { $link word } ". Only one instance of a singleton may exist because classes are " { $link eq? } " to themselves. Methods may be defined on a singleton."
|
||||
} { $examples
|
||||
}
|
||||
{ $description
|
||||
"Defines a new singleton class. The class word itself is the sole instance of the singleton class."
|
||||
}
|
||||
{ $examples
|
||||
{ $example "USING: classes.singleton kernel io ;" "SINGLETON: foo\nGENERIC: bar ( obj -- )\nM: foo bar drop \"a foo!\" print ;\nfoo bar" "a foo!" }
|
||||
} { $see-also
|
||||
POSTPONE: PREDICATE:
|
||||
} ;
|
||||
|
||||
HELP: define-singleton-class
|
||||
{ $values { "word" "a new word" } }
|
||||
{ $description
|
||||
"Defines a newly created word to be a singleton class." } ;
|
||||
"Defines a singleton class. This is the run-time equivalent of " { $link POSTPONE: SINGLETON: } "." } ;
|
||||
|
||||
{ POSTPONE: SINGLETON: define-singleton-class } related-words
|
||||
|
||||
HELP: singleton-class
|
||||
{ $class-description "The class of singleton classes." } ;
|
||||
|
||||
ABOUT: "singletons"
|
||||
|
|
|
@ -3,14 +3,63 @@ classes.tuple.private classes slots quotations words arrays
|
|||
generic.standard sequences definitions compiler.units ;
|
||||
IN: classes.tuple
|
||||
|
||||
ARTICLE: "tuple-constructors" "Constructors"
|
||||
"Tuples are created by calling one of two words:"
|
||||
ARTICLE: "parametrized-constructors" "Parameterized constructors"
|
||||
"A " { $emphasis "parametrized constructor" } " is a word which directly or indirectly calls " { $link construct-empty } " or " { $link construct-boa } ", but instead of passing a literal class symbol, it takes the class symbol as an input from the stack."
|
||||
$nl
|
||||
"Parametrized constructors are useful in many situations, in particular with subclassing. For example, consider the following code:"
|
||||
{ $code
|
||||
"TUPLE: vehicle max-speed occupants ;"
|
||||
""
|
||||
": add-occupant ( person vehicle -- ) occupants>> push ;"
|
||||
""
|
||||
"TUPLE: car < vehicle engine ;"
|
||||
": <car> ( max-speed engine -- car )"
|
||||
" car construct-empty"
|
||||
" V{ } clone >>occupants"
|
||||
" swap >>engine"
|
||||
" swap >>max-speed ;"
|
||||
""
|
||||
"TUPLE: aeroplane < vehicle max-altitude ;"
|
||||
": <aeroplane> ( max-speed max-altitude -- aeroplane )"
|
||||
" aeroplane construct-empty"
|
||||
" V{ } clone >>occupants"
|
||||
" swap >>max-altitude"
|
||||
" swap >>max-speed ;"
|
||||
}
|
||||
"The two constructors depend on the implementation of " { $snippet "vehicle" } " because they are responsible for initializing the " { $snippet "occupants" } " slot to an empty vector. If this slot is changed to contain a hashtable instead, there will be two places instead of one. A better approach is to use a parametrized constructor for vehicles:"
|
||||
{ $code
|
||||
"TUPLE: vehicle max-speed occupants ;"
|
||||
""
|
||||
": add-occupant ( person vehicle -- ) occupants>> push ;"
|
||||
""
|
||||
": construct-vehicle ( class -- vehicle )"
|
||||
" construct-empty"
|
||||
" V{ } clone >>occupants ;"
|
||||
""
|
||||
"TUPLE: car < vehicle engine ;"
|
||||
": <car> ( max-speed engine -- car )"
|
||||
" car construct-vehicle"
|
||||
" swap >>engine"
|
||||
" swap >>max-speed ;"
|
||||
""
|
||||
"TUPLE: aeroplane < vehicle max-altitude ;"
|
||||
": <aeroplane> ( max-speed max-altitude -- aeroplane )"
|
||||
" aeroplane construct-vehicle"
|
||||
" swap >>max-altitude"
|
||||
" swap >>max-speed ;"
|
||||
}
|
||||
"The naming convention for parametrized constructors is " { $snippet "construct-" { $emphasis "class" } } "." ;
|
||||
|
||||
ARTICLE: "tuple-constructors" "Tuple constructors"
|
||||
"Tuples are created by calling one of two constructor primitives:"
|
||||
{ $subsection construct-empty }
|
||||
{ $subsection construct-boa }
|
||||
"By convention, construction logic is encapsulated in a word named after the tuple class surrounded in angle brackets; for example, the constructor word for a " { $snippet "point" } " class might be named " { $snippet "<point>" } "."
|
||||
$nl
|
||||
"A shortcut for defining BOA constructors:"
|
||||
{ $subsection POSTPONE: C: }
|
||||
"By convention, construction logic is encapsulated in a word named after the tuple class surrounded in angle brackets; for example, the constructor word for a " { $snippet "point" } " class might be named " { $snippet "<point>" } "."
|
||||
$nl
|
||||
"All tuple construction should be done through constructor words, and construction primitives should be encapsulated and never called outside of the vocabulary where the class is defined, because this encourages looser coupling. For example, a constructor word could be changed to use memoization instead of always constructing a new instance, or it could be changed to construt a different class, without breaking callers."
|
||||
$nl
|
||||
"Examples of constructors:"
|
||||
{ $code
|
||||
"TUPLE: color red green blue alpha ;"
|
||||
|
@ -22,29 +71,77 @@ $nl
|
|||
""
|
||||
": <color> construct-empty ;"
|
||||
": <color> f f f f <rgba> ; ! identical to above"
|
||||
}
|
||||
{ $subsection "parametrized-constructors" } ;
|
||||
|
||||
ARTICLE: "tuple-inheritance-example" "Tuple subclassing example"
|
||||
"Rectangles, parallelograms and circles are all shapes. We support two operations on shapes:"
|
||||
{ $list
|
||||
"Computing the area"
|
||||
"Computing the perimiter"
|
||||
}
|
||||
"Rectangles and parallelograms use the same algorithm for computing the area, whereas they use different algorithms for computing perimiter. Also, rectangles and parallelograms both have " { $snippet "width" } " and " { $snippet "height" } " slots. We can exploit this with subclassing:"
|
||||
{ $code
|
||||
"GENERIC: area ( shape -- n )"
|
||||
"GENERIC: perimiter ( shape -- n )"
|
||||
""
|
||||
"TUPLE: shape ;"
|
||||
""
|
||||
"TUPLE: circle < shape radius ;"
|
||||
"M: area circle radius>> sq pi * ;"
|
||||
"M: perimiter circle radius>> 2 * pi * ;"
|
||||
""
|
||||
"TUPLE: quad < shape width height"
|
||||
"M: area quad [ width>> ] [ height>> ] bi * ;"
|
||||
""
|
||||
"TUPLE: rectangle < quad ;"
|
||||
"M: rectangle perimiter [ width>> 2 * ] [ height>> 2 * ] bi + ;"
|
||||
""
|
||||
": hypot ( a b -- c ) [ sq ] bi@ + sqrt ;"
|
||||
""
|
||||
"TUPLE: parallelogram < quad skew ;"
|
||||
"M: parallelogram perimiter"
|
||||
" [ width>> 2 * ] [ [ height>> ] [ skew>> ] bi hypot 2 * ] bi + ;"
|
||||
} ;
|
||||
|
||||
ARTICLE: "tuple-delegation" "Tuple delegation"
|
||||
"If a generic word having the " { $link standard-combination } " method combination is called on a tuple for which it does not have an applicable method, the method call is forwarded to the tuple's " { $emphasis "delegate" } ". If no delegate is set, a " { $link no-method } " error is thrown."
|
||||
{ $subsection delegate }
|
||||
{ $subsection set-delegate }
|
||||
"A tuple's delegate should either be another tuple, or " { $link f } ", indicating no delegate is set. Delegation from a tuple to an object of some other type is not fully supported and should be used with caution."
|
||||
ARTICLE: "tuple-inheritance-anti-example" "When not to use tuple subclassing"
|
||||
"Tuple subclassing should only be used for " { $emphasis "is-a" } " relationships; for example, a car " { $emphasis "is a" } " vehicle, and a circle " { $emphasis "is a" } " shape."
|
||||
{ $heading "Anti-pattern #1: subclassing for has-a" }
|
||||
"Subclassing should not be used for " { $emphasis "has-a" } " relationships. For example, if a shape " { $emphasis "has a" } " color, then " { $snippet "shape" } " should not subclass " { $snippet "color" } ". Using tuple subclassing in inappropriate situations leads to code which is more brittle and less flexible than it should be."
|
||||
$nl
|
||||
"Factor uses delegation in place of implementation inheritance, but it is not a direct substitute; in particular, the semantics differ in that a delegated method call receives the delegate on the stack, not the original object."
|
||||
"For example, suppose that " { $snippet "shape" } " inherits from " { $snippet "color" } ":"
|
||||
{ $code
|
||||
"TUPLE: color r g b ;"
|
||||
"TUPLE: shape < color ... ;"
|
||||
}
|
||||
"Now, the implementation of " { $snippet "shape" } " depends on a specific representation of colors as RGB colors. If a new generic color protocol is devised which also allows HSB and YUV colors to be used, the shape class will not be able to take advantage of them without changes. A better approach is to store the color in a slot:"
|
||||
{ $code
|
||||
"TUPLE: rgb-color r g b ;"
|
||||
"TUPLE: hsv-color h s v ;"
|
||||
"..."
|
||||
"TUPLE: shape color ... ;"
|
||||
}
|
||||
"The " { $vocab-link "delegate" } " library provides a language abstraction for expressing has-a relationships."
|
||||
{ $heading "Anti-pattern #2: subclassing for implementation sharing only" }
|
||||
"Tuple subclassing purely for sharing implementations of methods is not a good idea either. If a class " { $snippet "A" } " is a subclass of a class " { $snippet "B" } ", then instances of " { $snippet "A" } " should be usable anywhere that an instance of " { $snippet "B" } " is. If this properly does not hold, then subclassing should not be used."
|
||||
$nl
|
||||
"A pair of words examine delegation chains:"
|
||||
{ $subsection delegates }
|
||||
{ $subsection is? }
|
||||
"An example:"
|
||||
{ $example
|
||||
"TUPLE: ellipse center radius ;"
|
||||
"TUPLE: colored color ;"
|
||||
"{ 0 0 } 10 <ellipse> \"my-ellipse\" set"
|
||||
"{ 1 0 0 } <colored> \"my-shape\" set"
|
||||
"\"my-ellipse\" get \"my-shape\" get set-delegate"
|
||||
"\"my-shape\" get dup color>> swap center>> .s"
|
||||
"{ 0 0 }\n{ 1 0 0 }"
|
||||
} ;
|
||||
"There are two alternatives which are preferred to subclassing in this case. The first is " { $link "mixins" } "."
|
||||
$nl
|
||||
"The second is to use ad-hoc slot polymorphism. If two classes define a slot with the same name, then code which uses " { $link "accessors" } " can operate on instances of both objects, assuming the values stored in that slot implement a common protocol. This allows code to be shared without creating contrieved relationships between classes."
|
||||
{ $heading "Anti-pattern #3: subclassing to override a method definition" }
|
||||
"While method overriding is a very powerful tool, improper use can cause tight coupling of code and lead to difficulty in testing and refactoring. Subclassing should not be used as a means of ``monkey patching'' methods to fix bugs and add features. Only subclass from classes which were designed to be inherited from, and when writing classes of your own which are intended to be subclassed, clearly document that subclasses may and may not do. This includes construction policy; document whether subclasses should use " { $link construct-empty } ", " { $link construct-boa } ", or a custom parametrized constructor."
|
||||
{ $see-also "parametrized-constructors" } ;
|
||||
|
||||
ARTICLE: "tuple-subclassing" "Tuple subclassing"
|
||||
"Tuple subclassing can be used to express natural relationships between classes at the language level. For example, every car " { $emphasis "is a" } " vehicle, so if the " { $snippet "car" } " class subclasses the " { $snippet "vehicle" } " class, it can " { $emphasis "inherit" } " the slots and methods of " { $snippet "vehicle" } "."
|
||||
$nl
|
||||
"To define one tuple class as a subclass of another, use the optional superclass parameter to " { $link POSTPONE: TUPLE: } ":"
|
||||
{ $code
|
||||
"TUPLE: subclass < superclass ... ;"
|
||||
}
|
||||
{ $subsection "tuple-inheritance-example" }
|
||||
{ $subsection "tuple-inheritance-anti-example" }
|
||||
{ $see-also "call-next-method" "parametrized-constructors" "unions" "mixins" } ;
|
||||
|
||||
ARTICLE: "tuple-introspection" "Tuple introspection"
|
||||
"In addition to the slot reader and writer words which " { $link POSTPONE: TUPLE: } " defines for every tuple class, it is possible to construct and take apart entire tuples in a generic way."
|
||||
|
@ -119,7 +216,28 @@ ARTICLE: "tuple-examples" "Tuple examples"
|
|||
": promote ( person -- person )"
|
||||
" [ 1.2 * ] change-salary"
|
||||
" [ next-position ] change-position ;"
|
||||
} ;
|
||||
}
|
||||
"An example using subclassing can be found in " { $link "tuple-inheritance-example" } "." ;
|
||||
|
||||
ARTICLE: "tuple-redefinition" "Tuple redefinition"
|
||||
"In the following, the " { $emphasis "direct slots" } " of a tuple class refers to the slot names specified in the " { $link POSTPONE: TUPLE: } " form defining the tuple class, and the " { $emphasis "effective slots" } " refers to the concatenation of the direct slots together with slots defined on superclasses."
|
||||
$nl
|
||||
"When a tuple class is redefined, all instances of the class, including subclasses, are updated. For each instance, the list of effective slots is compared with the previous list. If any slots were removed, the values are removed from the instance and are lost forever. If any slots were added, the instance gains these slots with an initial value of " { $link f } "."
|
||||
$nl
|
||||
"There are three ways to change the list of effective slots of a class:"
|
||||
{ $list
|
||||
"Adding or removing direct slots of the class"
|
||||
"Adding or removing direct slots of a superclass of the class"
|
||||
"Changing the inheritance hierarchy by redefining a class to have a different superclass"
|
||||
}
|
||||
"In all cases, the new effective slots are compared with the old effective slots, and each instance is updated as follows:"
|
||||
{ $list
|
||||
"If any slots were removed, the values are removed from the instance and are lost forever."
|
||||
{ "If any slots were added, the instance gains these slots with an initial value of " { $link f } "." }
|
||||
"If any slots are permuted, their values in instances do not change; only the layout of the instance changes in memory."
|
||||
"If the number or order of effective slots changes, any BOA constructors are recompiled."
|
||||
}
|
||||
"Note that if a slot is moved from a class to its superclass (or vice versa) in the same compilation unit, the value of the slot is preserved in existing instances, because tuple instance update always runs at the end of a compilation unit. However, if it is removed in one compilation unit and added in another, the value in existing instances is lost." ;
|
||||
|
||||
ARTICLE: "tuples" "Tuples"
|
||||
"Tuples are user-defined classes composed of named slots."
|
||||
|
@ -132,22 +250,16 @@ $nl
|
|||
{ $subsection "accessors" }
|
||||
"Initially, no specific words are defined for constructing new instances of the tuple. Constructors must be defined explicitly:"
|
||||
{ $subsection "tuple-constructors" }
|
||||
"Further topics:"
|
||||
{ $subsection "tuple-delegation" }
|
||||
"Expressing relationships through the object system:"
|
||||
{ $subsection "tuple-subclassing" }
|
||||
"Introspection:"
|
||||
{ $subsection "tuple-introspection" }
|
||||
"Tuple classes can be redefined; this updates existing instances:"
|
||||
{ $subsection "tuple-redefinition" }
|
||||
"Tuple literal syntax is documented in " { $link "syntax-tuples" } "." ;
|
||||
|
||||
ABOUT: "tuples"
|
||||
|
||||
HELP: delegate
|
||||
{ $values { "obj" object } { "delegate" object } }
|
||||
{ $description "Returns an object's delegate, or " { $link f } " if no delegate is set." }
|
||||
{ $notes "A direct consequence of this behavior is that an object may not have a delegate of " { $link f } "." } ;
|
||||
|
||||
HELP: set-delegate
|
||||
{ $values { "delegate" object } { "tuple" tuple } }
|
||||
{ $description "Sets a tuple's delegate. Method calls not handled by the tuple's class will now be passed on to the delegate." } ;
|
||||
|
||||
HELP: tuple=
|
||||
{ $values { "tuple1" tuple } { "tuple2" tuple } { "?" "a boolean" } }
|
||||
{ $description "Low-level tuple equality test. User code should use " { $link = } " instead." }
|
||||
|
@ -179,12 +291,12 @@ $low-level-note ;
|
|||
|
||||
HELP: tuple-slots
|
||||
{ $values { "tuple" tuple } { "seq" sequence } }
|
||||
{ $description "Pushes a sequence of tuple slot values, not including the tuple class word and delegate." } ;
|
||||
{ $description "Pushes a sequence of tuple slot values, not including the tuple class word." } ;
|
||||
|
||||
{ tuple-slots tuple>array } related-words
|
||||
|
||||
HELP: define-tuple-slots
|
||||
{ $values { "class" tuple-class } { "slots" "a sequence of strings" } }
|
||||
{ $values { "class" tuple-class } }
|
||||
{ $description "Defines slot accessor and mutator words for the tuple." }
|
||||
$low-level-note ;
|
||||
|
||||
|
@ -201,26 +313,16 @@ HELP: define-tuple-class
|
|||
|
||||
{ tuple-class define-tuple-class POSTPONE: TUPLE: } related-words
|
||||
|
||||
HELP: delegates
|
||||
{ $values { "obj" object } { "seq" sequence } }
|
||||
{ $description "Outputs the delegation chain of an object. The first element of " { $snippet "seq" } " is " { $snippet "obj" } " itself. If " { $snippet "obj" } " is " { $link f } ", an empty sequence is output." } ;
|
||||
|
||||
HELP: is?
|
||||
{ $values { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "?" "a boolean" } }
|
||||
{ $description "Tests if the object or one of its delegates satisfies the predicate quotation."
|
||||
$nl
|
||||
"Class membership test predicates only test if an object is a direct instance of that class. Sometimes, you need to check delegates, since this gives a clearer picture of what operations the object supports." } ;
|
||||
|
||||
HELP: >tuple
|
||||
{ $values { "seq" sequence } { "tuple" tuple } }
|
||||
{ $description "Creates a tuple with slot values taken from a sequence. The first element of the sequence must be a tuple class word, the second a delegate, and the remainder the declared slots."
|
||||
{ $description "Creates a tuple with slot values taken from a sequence. The first element of the sequence must be a tuple class word and the remainder the declared slots."
|
||||
$nl
|
||||
"If the sequence has too many elements, they are ignored, and if it has too few, the remaining slots in the tuple are set to " { $link f } "." }
|
||||
{ $errors "Throws an error if the first element of the sequence is not a tuple class word." } ;
|
||||
|
||||
HELP: tuple>array ( tuple -- array )
|
||||
{ $values { "tuple" tuple } { "array" array } }
|
||||
{ $description "Outputs an array having the tuple's slots as elements. The first element is the tuple class word and the second is the delegate; the remainder are declared slots." } ;
|
||||
{ $description "Outputs an array having the tuple's slots as elements. The first element is the tuple class word and remainder are declared slots." } ;
|
||||
|
||||
HELP: <tuple> ( layout -- tuple )
|
||||
{ $values { "layout" tuple-layout } { "tuple" tuple } }
|
||||
|
|
|
@ -16,25 +16,6 @@ TUPLE: rect x y w h ;
|
|||
|
||||
[ t ] [ 10 20 30 40 <rect> dup clone 0 swap move = ] unit-test
|
||||
|
||||
GENERIC: delegation-test
|
||||
M: object delegation-test drop 3 ;
|
||||
TUPLE: quux-tuple ;
|
||||
: <quux-tuple> quux-tuple construct-empty ;
|
||||
M: quux-tuple delegation-test drop 4 ;
|
||||
TUPLE: quuux-tuple ;
|
||||
: <quuux-tuple> { set-delegate } quuux-tuple construct ;
|
||||
|
||||
[ 3 ] [ <quux-tuple> <quuux-tuple> delegation-test ] unit-test
|
||||
|
||||
GENERIC: delegation-test-2
|
||||
TUPLE: quux-tuple-2 ;
|
||||
: <quux-tuple-2> quux-tuple-2 construct-empty ;
|
||||
M: quux-tuple-2 delegation-test-2 drop 4 ;
|
||||
TUPLE: quuux-tuple-2 ;
|
||||
: <quuux-tuple-2> { set-delegate } quuux-tuple-2 construct ;
|
||||
|
||||
[ 4 ] [ <quux-tuple-2> <quuux-tuple-2> delegation-test-2 ] unit-test
|
||||
|
||||
! Make sure we handle tuple class redefinition
|
||||
TUPLE: redefinition-test ;
|
||||
|
||||
|
@ -102,11 +83,6 @@ C: <empty> empty
|
|||
|
||||
[ t ] [ <empty> hashcode fixnum? ] unit-test
|
||||
|
||||
TUPLE: delegate-clone ;
|
||||
|
||||
[ T{ delegate-clone T{ empty f } } ]
|
||||
[ T{ delegate-clone T{ empty f } } clone ] unit-test
|
||||
|
||||
! Compiler regression
|
||||
[ t length ] [ object>> t eq? ] must-fail-with
|
||||
|
||||
|
@ -242,7 +218,7 @@ C: <erg's-reshape-problem> erg's-reshape-problem
|
|||
|
||||
[
|
||||
"IN: classes.tuple.tests SYMBOL: not-a-class C: <not-a-class> not-a-class" eval
|
||||
] [ [ no-tuple-class? ] is? ] must-fail-with
|
||||
] [ error>> no-tuple-class? ] must-fail-with
|
||||
|
||||
! Inheritance
|
||||
TUPLE: computer cpu ram ;
|
||||
|
@ -512,7 +488,7 @@ USE: vocabs
|
|||
] with-compilation-unit
|
||||
] unit-test
|
||||
|
||||
[ "USE: words T{ word }" eval ] [ [ no-method? ] is? ] must-fail-with
|
||||
[ "USE: words T{ word }" eval ] [ error>> no-method? ] must-fail-with
|
||||
|
||||
! Accessors not being forgotten...
|
||||
[ [ ] ] [
|
||||
|
|
|
@ -7,10 +7,6 @@ classes classes.private slots.deprecated slots.private slots
|
|||
compiler.units math.private accessors assocs ;
|
||||
IN: classes.tuple
|
||||
|
||||
M: tuple delegate 2 slot ;
|
||||
|
||||
M: tuple set-delegate 2 set-slot ;
|
||||
|
||||
M: tuple class 1 slot 2 slot { word } declare ;
|
||||
|
||||
ERROR: no-tuple-class class ;
|
||||
|
@ -44,7 +40,7 @@ PRIVATE>
|
|||
>r copy-tuple-slots r>
|
||||
layout-class prefix ;
|
||||
|
||||
: tuple-slots ( tuple -- array )
|
||||
: tuple-slots ( tuple -- seq )
|
||||
prepare-tuple>array drop copy-tuple-slots ;
|
||||
|
||||
: slots>tuple ( tuple class -- array )
|
||||
|
@ -52,11 +48,12 @@ PRIVATE>
|
|||
[ tuple-size ] [ [ set-array-nth ] curry ] bi 2each
|
||||
] keep ;
|
||||
|
||||
: >tuple ( tuple -- array )
|
||||
: >tuple ( tuple -- seq )
|
||||
unclip slots>tuple ;
|
||||
|
||||
: slot-names ( class -- seq )
|
||||
"slot-names" word-prop ;
|
||||
"slot-names" word-prop
|
||||
[ dup array? [ second ] when ] map ;
|
||||
|
||||
<PRIVATE
|
||||
|
||||
|
@ -107,7 +104,7 @@ PRIVATE>
|
|||
over superclass-size 2 + simple-slots ;
|
||||
|
||||
: define-tuple-slots ( class -- )
|
||||
dup dup slot-names generate-tuple-slots
|
||||
dup dup "slot-names" word-prop generate-tuple-slots
|
||||
[ "slots" set-word-prop ]
|
||||
[ define-accessors ] ! new
|
||||
[ define-slots ] ! old
|
||||
|
@ -177,7 +174,7 @@ M: tuple-class update-class
|
|||
2drop
|
||||
[
|
||||
[ update-tuples-after ]
|
||||
[ changed-word ]
|
||||
[ changed-definition ]
|
||||
[ redefined ]
|
||||
tri
|
||||
] each-subclass
|
||||
|
@ -228,9 +225,10 @@ M: tuple equal?
|
|||
|
||||
M: tuple hashcode*
|
||||
[
|
||||
dup tuple-size -rot 0 -rot [
|
||||
swapd array-nth hashcode* bitxor
|
||||
] 2curry reduce
|
||||
[ class hashcode ] [ tuple-size ] [ ] tri
|
||||
>r rot r> [
|
||||
swapd array-nth hashcode* sequence-hashcode-step
|
||||
] 2curry each
|
||||
] recursive-hashcode ;
|
||||
|
||||
! Deprecated
|
||||
|
|
|
@ -11,7 +11,9 @@ ARTICLE: "unions" "Union classes"
|
|||
{ $subsection members }
|
||||
"The set of union classes is a class:"
|
||||
{ $subsection union-class }
|
||||
{ $subsection union-class? } ;
|
||||
{ $subsection union-class? }
|
||||
"Unions are used to define behavior shared between a fixed set of classes."
|
||||
{ $see-also "mixins" "tuple-subclassing" } ;
|
||||
|
||||
ABOUT: "unions"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ IN: compiler.tests
|
|||
USING: compiler.units kernel kernel.private memory math
|
||||
math.private tools.test math.floats.private ;
|
||||
|
||||
[ 5.0 ] [ [ 5.0 ] compile-call data-gc data-gc data-gc ] unit-test
|
||||
[ 5.0 ] [ [ 5.0 ] compile-call gc gc gc ] unit-test
|
||||
[ 2.0 3.0 ] [ 3.0 [ 2.0 swap ] compile-call ] unit-test
|
||||
|
||||
[ 1 2 3 4.0 ] [ [ 1 2 3 4.0 ] compile-call ] unit-test
|
||||
|
|
|
@ -48,7 +48,7 @@ IN: compiler.tests
|
|||
[ 4 1 3 ] [ 0 [ { [ bar 1 ] [ 3 1 ] } dispatch 3 ] compile-call ] unit-test
|
||||
[ 3 1 3 ] [ 1 [ { [ bar 1 ] [ 3 1 ] } dispatch 3 ] compile-call ] unit-test
|
||||
|
||||
[ 2 3 ] [ 1 [ { [ code-gc 1 ] [ code-gc 2 ] } dispatch 3 ] compile-call ] unit-test
|
||||
[ 2 3 ] [ 1 [ { [ gc 1 ] [ gc 2 ] } dispatch 3 ] compile-call ] unit-test
|
||||
|
||||
! Labels
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
IN: compiler.tests
|
||||
USING: compiler generator generator.registers
|
||||
generator.registers.private tools.test namespaces sequences
|
||||
words kernel math effects definitions compiler.units ;
|
||||
words kernel math effects definitions compiler.units accessors ;
|
||||
|
||||
: <int-vreg> ( n -- vreg ) T{ int-regs } <vreg> ;
|
||||
: <int-vreg> ( n -- vreg ) int-regs <vreg> ;
|
||||
|
||||
[
|
||||
[ ] [ init-templates ] unit-test
|
||||
|
@ -15,18 +15,18 @@ words kernel math effects definitions compiler.units ;
|
|||
|
||||
[ ] [ compute-free-vregs ] unit-test
|
||||
|
||||
[ f ] [ 0 <int-vreg> T{ int-regs } free-vregs member? ] unit-test
|
||||
[ f ] [ 0 <int-vreg> int-regs free-vregs member? ] unit-test
|
||||
|
||||
[ f ] [
|
||||
[
|
||||
copy-templates
|
||||
1 <int-vreg> phantom-push
|
||||
compute-free-vregs
|
||||
1 <int-vreg> T{ int-regs } free-vregs member?
|
||||
1 <int-vreg> int-regs free-vregs member?
|
||||
] with-scope
|
||||
] unit-test
|
||||
|
||||
[ t ] [ 1 <int-vreg> T{ int-regs } free-vregs member? ] unit-test
|
||||
[ t ] [ 1 <int-vreg> int-regs free-vregs member? ] unit-test
|
||||
] with-scope
|
||||
|
||||
[
|
||||
|
@ -173,12 +173,12 @@ SYMBOL: template-chosen
|
|||
] unit-test
|
||||
|
||||
[ ] [
|
||||
2 phantom-d get phantom-input
|
||||
2 phantom-datastack get phantom-input
|
||||
[ { { f "a" } { f "b" } } lazy-load ] { } make drop
|
||||
] unit-test
|
||||
|
||||
[ t ] [
|
||||
phantom-d get [ cached? ] all?
|
||||
phantom-datastack get stack>> [ cached? ] all?
|
||||
] unit-test
|
||||
|
||||
! >r
|
||||
|
|
|
@ -202,3 +202,47 @@ TUPLE: my-tuple ;
|
|||
] [ 2drop no-case ] if
|
||||
] compile-call
|
||||
] unit-test
|
||||
|
||||
: float-spill-bug
|
||||
{
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
[ dup float+ ]
|
||||
} cleave ;
|
||||
|
||||
[ t ] [ \ float-spill-bug compiled? ] unit-test
|
||||
|
|
|
@ -22,11 +22,3 @@ TUPLE: color red green blue ;
|
|||
|
||||
[ T{ color f f f f } ]
|
||||
[ [ color construct-empty ] compile-call ] unit-test
|
||||
|
||||
[ T{ color "a" f "b" f } ] [
|
||||
"a" "b"
|
||||
[ { set-delegate set-color-green } color construct ]
|
||||
compile-call
|
||||
] unit-test
|
||||
|
||||
[ T{ color f f f f } ] [ [ { } color construct ] compile-call ] unit-test
|
||||
|
|
|
@ -56,12 +56,12 @@ GENERIC: definitions-changed ( assoc obj -- )
|
|||
[ drop word? ] assoc-subset
|
||||
[ drop word-vocabulary dup [ vocab ] when dup ] assoc-map ;
|
||||
|
||||
: changed-definitions ( -- assoc )
|
||||
: updated-definitions ( -- assoc )
|
||||
H{ } clone
|
||||
dup forgotten-definitions get update
|
||||
dup new-definitions get first update
|
||||
dup new-definitions get second update
|
||||
dup changed-words get update
|
||||
dup changed-definitions get update
|
||||
dup dup changed-vocabs update ;
|
||||
|
||||
: compile ( words -- )
|
||||
|
@ -73,7 +73,7 @@ SYMBOL: outdated-tuples
|
|||
SYMBOL: update-tuples-hook
|
||||
|
||||
: call-recompile-hook ( -- )
|
||||
changed-words get keys
|
||||
changed-definitions get keys [ word? ] subset
|
||||
compiled-usages recompile-hook get call ;
|
||||
|
||||
: call-update-tuples-hook ( -- )
|
||||
|
@ -83,11 +83,11 @@ SYMBOL: update-tuples-hook
|
|||
call-recompile-hook
|
||||
call-update-tuples-hook
|
||||
dup [ drop crossref? ] assoc-contains? modify-code-heap
|
||||
changed-definitions notify-definition-observers ;
|
||||
updated-definitions notify-definition-observers ;
|
||||
|
||||
: with-compilation-unit ( quot -- )
|
||||
[
|
||||
H{ } clone changed-words set
|
||||
H{ } clone changed-definitions set
|
||||
H{ } clone forgotten-definitions set
|
||||
H{ } clone outdated-tuples set
|
||||
<definitions> new-definitions set
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
USING: help.markup help.syntax kernel kernel.private
|
||||
continuations.private parser vectors arrays namespaces
|
||||
assocs words quotations ;
|
||||
assocs words quotations io ;
|
||||
IN: continuations
|
||||
|
||||
ARTICLE: "errors-restartable" "Restartable errors"
|
||||
|
@ -17,6 +17,25 @@ ARTICLE: "errors-post-mortem" "Post-mortem error inspection"
|
|||
{ $subsection error-continuation }
|
||||
"Developer tools for inspecting these values are found in " { $link "debugger" } "." ;
|
||||
|
||||
ARTICLE: "errors-anti-examples" "Common error handling pitfalls"
|
||||
"When used correctly, exception handling can lead to more robust code with less duplication of error handling logic. However, there are some pitfalls to keep in mind."
|
||||
{ $heading "Anti-pattern #1: Ignoring errors" }
|
||||
"The " { $link ignore-errors } " word should almost never be used. Ignoring errors does not make code more robust and in fact makes it much harder to debug if an intermittent error does show up when the code is run under previously unforseen circumstances. Never ignore unexpected errors; always report them to the user."
|
||||
{ $heading "Anti-pattern #2: Catching errors too early" }
|
||||
"A less severe form of the previous anti-pattern is code that makes overly zealous use of " { $link recover } ". It is almost always a mistake to catch an error, log a message, and keep going. The only exception is network servers and other long-running processes that must remain running even if individual tasks fail. In these cases, place the " { $link recover } " as high up in the call stack as possible."
|
||||
$nl
|
||||
"In most other cases, " { $link cleanup } " should be used instead to handle an error and rethrow it automatically."
|
||||
{ $heading "Anti-pattern #3: Dropping and rethrowing" }
|
||||
"Do not use " { $link recover } " to handle an error by dropping it and throwing a new error. By losing the original error message, you signal to the user that something failed without leaving any indication of what actually went wrong. Either wrap the error in a new error containing additional information, or rethrow the original error. A more subtle form of this is using " { $link throw } " instead of " { $link rethrow } ". The " { $link throw } " word should only be used when throwing new errors, and never when rethrowing errors that have been caught."
|
||||
{ $heading "Anti-pattern #4: Logging and rethrowing" }
|
||||
"If you are going to rethrow an error, do not log a message. If you do so, the user will see two log messages for the same error, which will clutter logs without adding any useful information."
|
||||
{ $heading "Anti-pattern #5: Leaking external resources" }
|
||||
"Words which create objects corresponding to external resources should always be used with " { $link with-disposal } ". The following code is wrong:"
|
||||
{ $code
|
||||
"<external-resource> ... do stuff ... dispose"
|
||||
}
|
||||
"The reason being that if " { $snippet "do stuff" } " throws an error, the resource will not be disposed of. The most important case where this can occur is with I/O streams, and the correct solution is to always use " { $link with-stream } "; see " { $link "stdio" } " for details." ;
|
||||
|
||||
ARTICLE: "errors" "Error handling"
|
||||
"Support for handling exceptional situations such as bad user input, implementation bugs, and input/output errors is provided by a set of words built using continuations."
|
||||
$nl
|
||||
|
@ -27,10 +46,13 @@ $nl
|
|||
{ $subsection cleanup }
|
||||
{ $subsection recover }
|
||||
{ $subsection ignore-errors }
|
||||
"Syntax sugar for defining errors:"
|
||||
{ $subsection POSTPONE: ERROR: }
|
||||
"Unhandled errors are reported in the listener and can be debugged using various tools. See " { $link "debugger" } "."
|
||||
{ $subsection "errors-restartable" }
|
||||
{ $subsection "debugger" }
|
||||
{ $subsection "errors-post-mortem" }
|
||||
{ $subsection "errors-anti-examples" }
|
||||
"When Factor encouters a critical error, it calls the following word:"
|
||||
{ $subsection die } ;
|
||||
|
||||
|
@ -61,8 +83,7 @@ $nl
|
|||
"Another two words resume continuations:"
|
||||
{ $subsection continue }
|
||||
{ $subsection continue-with }
|
||||
"Continuations serve as the building block for a number of higher-level abstractions."
|
||||
{ $subsection "errors" }
|
||||
"Continuations serve as the building block for a number of higher-level abstractions, such as " { $link "errors" } " and " { $link "threads" } "."
|
||||
{ $subsection "continuations.private" } ;
|
||||
|
||||
ABOUT: "continuations"
|
||||
|
|
|
@ -46,8 +46,8 @@ IN: continuations.tests
|
|||
! Weird PowerPC bug.
|
||||
[ ] [
|
||||
[ "4" throw ] ignore-errors
|
||||
data-gc
|
||||
data-gc
|
||||
gc
|
||||
gc
|
||||
] unit-test
|
||||
|
||||
[ f ] [ { } kernel-error? ] unit-test
|
||||
|
|
|
@ -141,14 +141,9 @@ GENERIC: dispose ( object -- )
|
|||
: with-disposal ( object quot -- )
|
||||
over [ dispose ] curry [ ] cleanup ; inline
|
||||
|
||||
TUPLE: condition restarts continuation ;
|
||||
TUPLE: condition error restarts continuation ;
|
||||
|
||||
: <condition> ( error restarts cc -- condition )
|
||||
{
|
||||
set-delegate
|
||||
set-condition-restarts
|
||||
set-condition-continuation
|
||||
} condition construct ;
|
||||
C: <condition> condition ( error restarts cc -- condition )
|
||||
|
||||
: throw-restarts ( error restarts -- restart )
|
||||
[ <condition> throw ] callcc1 2nip ;
|
||||
|
@ -161,15 +156,14 @@ TUPLE: restart name obj continuation ;
|
|||
C: <restart> restart
|
||||
|
||||
: restart ( restart -- )
|
||||
dup restart-obj swap restart-continuation continue-with ;
|
||||
[ obj>> ] [ continuation>> ] bi continue-with ;
|
||||
|
||||
M: object compute-restarts drop { } ;
|
||||
|
||||
M: tuple compute-restarts delegate compute-restarts ;
|
||||
|
||||
M: condition compute-restarts
|
||||
[ delegate compute-restarts ] keep
|
||||
[ condition-restarts ] keep
|
||||
condition-continuation
|
||||
[ <restart> ] curry { } assoc>map
|
||||
append ;
|
||||
[ error>> compute-restarts ]
|
||||
[
|
||||
[ restarts>> ]
|
||||
[ condition-continuation [ <restart> ] curry ] bi
|
||||
{ } assoc>map
|
||||
] bi append ;
|
||||
|
|
|
@ -6,7 +6,7 @@ byte-arrays bit-arrays float-arrays combinators words ;
|
|||
IN: cpu.architecture
|
||||
|
||||
! A pseudo-register class for parameters spilled on the stack
|
||||
TUPLE: stack-params ;
|
||||
SINGLETON: stack-params
|
||||
|
||||
! Return values of this class go here
|
||||
GENERIC: return-reg ( register-class -- reg )
|
||||
|
|
|
@ -146,11 +146,19 @@ M: int-regs %save-param-reg drop 1 rot local@ STW ;
|
|||
|
||||
M: int-regs %load-param-reg drop 1 rot local@ LWZ ;
|
||||
|
||||
: STF float-regs-size 4 = [ STFS ] [ STFD ] if ;
|
||||
GENERIC: STF ( src dst reg-class -- )
|
||||
|
||||
M: single-float-regs STF drop STFS ;
|
||||
|
||||
M: double-float-regs STF drop STFD ;
|
||||
|
||||
M: float-regs %save-param-reg >r 1 rot local@ r> STF ;
|
||||
|
||||
: LF float-regs-size 4 = [ LFS ] [ LFD ] if ;
|
||||
GENERIC: LF ( src dst reg-class -- )
|
||||
|
||||
M: single-float-regs LF drop LFS ;
|
||||
|
||||
M: double-float-regs LF drop LFD ;
|
||||
|
||||
M: float-regs %load-param-reg >r 1 rot local@ r> LF ;
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ M: x86.32 %box ( n reg-class func -- )
|
|||
#! integer, push [ESP+n]:[ESP+n+4] on the stack; we are
|
||||
#! boxing a parameter being passed to a callback from C.
|
||||
[
|
||||
T{ int-regs } box@
|
||||
int-regs box@
|
||||
EDX over stack@ MOV
|
||||
EAX swap cell - stack@ MOV
|
||||
] when*
|
||||
|
|
|
@ -65,7 +65,7 @@ M: x86.64 %unbox ( n reg-class func -- )
|
|||
over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
|
||||
|
||||
M: x86.64 %unbox-long-long ( n func -- )
|
||||
T{ int-regs } swap %unbox ;
|
||||
int-regs swap %unbox ;
|
||||
|
||||
M: x86.64 %unbox-struct-1 ( -- )
|
||||
#! Alien must be in RDI.
|
||||
|
@ -103,7 +103,7 @@ M: x86.64 %box ( n reg-class func -- )
|
|||
f %alien-invoke ;
|
||||
|
||||
M: x86.64 %box-long-long ( n func -- )
|
||||
T{ int-regs } swap %box ;
|
||||
int-regs swap %box ;
|
||||
|
||||
M: x86.64 struct-small-enough? ( size -- ? ) 2 cells <= ;
|
||||
|
||||
|
@ -170,7 +170,7 @@ USE: cpu.x86.intrinsics
|
|||
|
||||
! The ABI for passing structs by value is pretty messed up
|
||||
<< "void*" c-type clone "__stack_value" define-primitive-type
|
||||
T{ stack-params } "__stack_value" c-type set-c-type-reg-class >>
|
||||
stack-params "__stack_value" c-type set-c-type-reg-class >>
|
||||
|
||||
: struct-types&offset ( struct-type -- pairs )
|
||||
struct-type-fields [
|
||||
|
@ -192,7 +192,7 @@ M: struct-type flatten-value-type ( type -- seq )
|
|||
] [
|
||||
struct-types&offset split-struct [
|
||||
[ c-type c-type-reg-class ] map
|
||||
T{ int-regs } swap member?
|
||||
int-regs swap member?
|
||||
"void*" "double" ? c-type ,
|
||||
] each
|
||||
] if ;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
! Copyright (C) 2005, 2007 Slava Pestov.
|
||||
! Copyright (C) 2005, 2008 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: alien alien.c-types alien.compiler arrays
|
||||
cpu.x86.assembler cpu.architecture kernel kernel.private math
|
||||
|
@ -22,7 +22,11 @@ M: rs-loc v>operand rs-loc-n rs-reg reg-stack ;
|
|||
M: int-regs %save-param-reg drop >r stack@ r> MOV ;
|
||||
M: int-regs %load-param-reg drop swap stack@ MOV ;
|
||||
|
||||
: MOVSS/D float-regs-size 4 = [ MOVSS ] [ MOVSD ] if ;
|
||||
GENERIC: MOVSS/D ( dst src reg-class -- )
|
||||
|
||||
M: single-float-regs MOVSS/D drop MOVSS ;
|
||||
|
||||
M: double-float-regs MOVSS/D drop MOVSD ;
|
||||
|
||||
M: float-regs %save-param-reg >r >r stack@ r> r> MOVSS/D ;
|
||||
M: float-regs %load-param-reg >r swap stack@ r> MOVSS/D ;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
USING: alien arrays generic generic.math help.markup help.syntax
|
||||
kernel math memory strings sbufs vectors io io.files classes
|
||||
help generic.standard continuations system debugger.private ;
|
||||
help generic.standard continuations system debugger.private
|
||||
io.files.private ;
|
||||
IN: debugger
|
||||
|
||||
ARTICLE: "errors-assert" "Assertions"
|
||||
|
|
|
@ -4,9 +4,9 @@ USING: arrays definitions generic hashtables inspector io kernel
|
|||
math namespaces prettyprint sequences assocs sequences.private
|
||||
strings io.styles vectors words system splitting math.parser
|
||||
classes.tuple continuations continuations.private combinators
|
||||
generic.math io.streams.duplex classes compiler.units
|
||||
generic.standard vocabs threads threads.private init
|
||||
kernel.private libc io.encodings ;
|
||||
generic.math io.streams.duplex classes.builtin classes
|
||||
compiler.units generic.standard vocabs threads threads.private
|
||||
init kernel.private libc io.encodings accessors ;
|
||||
IN: debugger
|
||||
|
||||
GENERIC: error. ( error -- )
|
||||
|
@ -202,6 +202,12 @@ M: no-method error.
|
|||
M: no-math-method summary
|
||||
drop "No suitable arithmetic method" ;
|
||||
|
||||
M: no-next-method summary
|
||||
drop "Executing call-next-method from least-specific method" ;
|
||||
|
||||
M: inconsistent-next-method summary
|
||||
drop "Executing call-next-method with inconsistent parameters" ;
|
||||
|
||||
M: stream-closed-twice summary
|
||||
drop "Attempt to perform I/O on closed stream" ;
|
||||
|
||||
|
@ -223,9 +229,11 @@ M: slice-error error.
|
|||
|
||||
M: bounds-error summary drop "Sequence index out of bounds" ;
|
||||
|
||||
M: condition error. delegate error. ;
|
||||
M: condition error. error>> error. ;
|
||||
|
||||
M: condition error-help drop f ;
|
||||
M: condition summary error>> summary ;
|
||||
|
||||
M: condition error-help error>> error-help ;
|
||||
|
||||
M: assert summary drop "Assertion failed" ;
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@ $nl
|
|||
{ $subsection forget }
|
||||
"Definitions can answer a sequence of definitions they directly depend on:"
|
||||
{ $subsection uses }
|
||||
"When a definition is changed, all definitions which depend on it are notified via a hook:"
|
||||
{ $subsection redefined* }
|
||||
"Definitions must implement a few operations used for printing them in source form:"
|
||||
{ $subsection synopsis* }
|
||||
{ $subsection definer }
|
||||
|
@ -108,11 +106,6 @@ HELP: usage
|
|||
{ $description "Outputs a sequence of definitions that directly call the given definition." }
|
||||
{ $notes "The sequence might include the definition itself, if it is a recursive word." } ;
|
||||
|
||||
HELP: redefined*
|
||||
{ $values { "defspec" "a definition specifier" } }
|
||||
{ $contract "Updates the definition to cope with a callee being redefined." }
|
||||
$low-level-note ;
|
||||
|
||||
HELP: unxref
|
||||
{ $values { "defspec" "a definition specifier" } }
|
||||
{ $description "Remove edges leaving the vertex which represents the definition from the " { $link crossref } " graph." }
|
||||
|
|
|
@ -5,6 +5,13 @@ USING: kernel sequences namespaces assocs graphs ;
|
|||
|
||||
ERROR: no-compilation-unit definition ;
|
||||
|
||||
SYMBOL: changed-definitions
|
||||
|
||||
: changed-definition ( defspec -- )
|
||||
dup changed-definitions get
|
||||
[ no-compilation-unit ] unless*
|
||||
set-at ;
|
||||
|
||||
GENERIC: where ( defspec -- loc )
|
||||
|
||||
M: object where drop f ;
|
||||
|
@ -42,13 +49,6 @@ M: object uses drop f ;
|
|||
|
||||
: usage ( defspec -- seq ) \ f or crossref get at keys ;
|
||||
|
||||
GENERIC: redefined* ( defspec -- )
|
||||
|
||||
M: object redefined* drop ;
|
||||
|
||||
: redefined ( defspec -- )
|
||||
[ crossref get at ] closure [ drop redefined* ] assoc-each ;
|
||||
|
||||
: unxref ( defspec -- )
|
||||
dup uses crossref get remove-vertex ;
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
USING: arrays assocs classes classes.private classes.algebra
|
||||
combinators cpu.architecture generator.fixup hashtables kernel
|
||||
layouts math namespaces quotations sequences system vectors
|
||||
words effects alien byte-arrays bit-arrays float-arrays ;
|
||||
words effects alien byte-arrays bit-arrays float-arrays
|
||||
accessors ;
|
||||
IN: generator.registers
|
||||
|
||||
SYMBOL: +input+
|
||||
|
@ -13,9 +14,11 @@ SYMBOL: +clobber+
|
|||
SYMBOL: known-tag
|
||||
|
||||
! Register classes
|
||||
TUPLE: int-regs ;
|
||||
|
||||
TUPLE: float-regs size ;
|
||||
SINGLETON: int-regs
|
||||
SINGLETON: single-float-regs
|
||||
SINGLETON: double-float-regs
|
||||
UNION: float-regs single-float-regs double-float-regs ;
|
||||
UNION: reg-class int-regs float-regs ;
|
||||
|
||||
<PRIVATE
|
||||
|
||||
|
@ -48,13 +51,13 @@ M: value minimal-ds-loc* drop ;
|
|||
M: value lazy-store 2drop ;
|
||||
|
||||
! A scratch register for computations
|
||||
TUPLE: vreg n ;
|
||||
TUPLE: vreg n reg-class ;
|
||||
|
||||
: <vreg> ( n reg-class -- vreg )
|
||||
{ set-vreg-n set-delegate } vreg construct ;
|
||||
C: <vreg> vreg ( n reg-class -- vreg )
|
||||
|
||||
M: vreg v>operand dup vreg-n swap vregs nth ;
|
||||
M: vreg v>operand [ n>> ] [ reg-class>> ] bi vregs nth ;
|
||||
M: vreg live-vregs* , ;
|
||||
M: vreg move-spec reg-class>> move-spec ;
|
||||
|
||||
INSTANCE: vreg value
|
||||
|
||||
|
@ -62,9 +65,9 @@ M: float-regs move-spec drop float ;
|
|||
M: float-regs operand-class* drop float ;
|
||||
|
||||
! Temporary register for stack shuffling
|
||||
TUPLE: temp-reg ;
|
||||
TUPLE: temp-reg reg-class>> ;
|
||||
|
||||
: temp-reg T{ temp-reg T{ int-regs } } ;
|
||||
: temp-reg T{ temp-reg f int-regs } ;
|
||||
|
||||
M: temp-reg move-spec drop f ;
|
||||
|
||||
|
@ -73,7 +76,7 @@ INSTANCE: temp-reg value
|
|||
! A data stack location.
|
||||
TUPLE: ds-loc n class ;
|
||||
|
||||
: <ds-loc> { set-ds-loc-n } ds-loc construct ;
|
||||
: <ds-loc> f ds-loc construct-boa ;
|
||||
|
||||
M: ds-loc minimal-ds-loc* ds-loc-n min ;
|
||||
M: ds-loc operand-class* ds-loc-class ;
|
||||
|
@ -84,8 +87,7 @@ M: ds-loc live-loc?
|
|||
! A retain stack location.
|
||||
TUPLE: rs-loc n class ;
|
||||
|
||||
: <rs-loc> { set-rs-loc-n } rs-loc construct ;
|
||||
|
||||
: <rs-loc> f rs-loc construct-boa ;
|
||||
M: rs-loc operand-class* rs-loc-class ;
|
||||
M: rs-loc set-operand-class set-rs-loc-class ;
|
||||
M: rs-loc live-loc?
|
||||
|
@ -126,7 +128,7 @@ INSTANCE: cached value
|
|||
TUPLE: tagged vreg class ;
|
||||
|
||||
: <tagged> ( vreg -- tagged )
|
||||
{ set-tagged-vreg } tagged construct ;
|
||||
f tagged construct-boa ;
|
||||
|
||||
M: tagged v>operand tagged-vreg v>operand ;
|
||||
M: tagged set-operand-class set-tagged-class ;
|
||||
|
@ -228,48 +230,44 @@ INSTANCE: constant value
|
|||
} case ;
|
||||
|
||||
! A compile-time stack
|
||||
TUPLE: phantom-stack height ;
|
||||
TUPLE: phantom-stack height stack ;
|
||||
|
||||
M: phantom-stack clone
|
||||
call-next-method [ clone ] change-stack ;
|
||||
|
||||
GENERIC: finalize-height ( stack -- )
|
||||
|
||||
SYMBOL: phantom-d
|
||||
SYMBOL: phantom-r
|
||||
|
||||
: <phantom-stack> ( class -- stack )
|
||||
>r
|
||||
V{ } clone 0
|
||||
{ set-delegate set-phantom-stack-height }
|
||||
phantom-stack construct
|
||||
r> construct-delegate ;
|
||||
: construct-phantom-stack ( class -- stack )
|
||||
>r 0 V{ } clone r> construct-boa ; inline
|
||||
|
||||
: (loc)
|
||||
#! Utility for methods on <loc>
|
||||
phantom-stack-height - ;
|
||||
height>> - ;
|
||||
|
||||
: (finalize-height) ( stack word -- )
|
||||
#! We consolidate multiple stack height changes until the
|
||||
#! last moment, and we emit the final height changing
|
||||
#! instruction here.
|
||||
swap [
|
||||
phantom-stack-height
|
||||
dup zero? [ 2drop ] [ swap execute ] if
|
||||
0
|
||||
] keep set-phantom-stack-height ; inline
|
||||
[
|
||||
over zero? [ 2drop ] [ execute ] if 0
|
||||
] curry change-height drop ; inline
|
||||
|
||||
GENERIC: <loc> ( n stack -- loc )
|
||||
|
||||
TUPLE: phantom-datastack ;
|
||||
TUPLE: phantom-datastack < phantom-stack ;
|
||||
|
||||
: <phantom-datastack> phantom-datastack <phantom-stack> ;
|
||||
: <phantom-datastack> ( -- stack )
|
||||
phantom-datastack construct-phantom-stack ;
|
||||
|
||||
M: phantom-datastack <loc> (loc) <ds-loc> ;
|
||||
|
||||
M: phantom-datastack finalize-height
|
||||
\ %inc-d (finalize-height) ;
|
||||
|
||||
TUPLE: phantom-retainstack ;
|
||||
TUPLE: phantom-retainstack < phantom-stack ;
|
||||
|
||||
: <phantom-retainstack> phantom-retainstack <phantom-stack> ;
|
||||
: <phantom-retainstack> ( -- stack )
|
||||
phantom-retainstack construct-phantom-stack ;
|
||||
|
||||
M: phantom-retainstack <loc> (loc) <rs-loc> ;
|
||||
|
||||
|
@ -281,34 +279,33 @@ M: phantom-retainstack finalize-height
|
|||
>r <reversed> r> [ <loc> ] curry map ;
|
||||
|
||||
: phantom-locs* ( phantom -- locs )
|
||||
dup length swap phantom-locs ;
|
||||
[ stack>> length ] keep phantom-locs ;
|
||||
|
||||
: phantoms ( -- phantom phantom )
|
||||
phantom-datastack get phantom-retainstack get ;
|
||||
|
||||
: (each-loc) ( phantom quot -- )
|
||||
>r dup phantom-locs* swap r> 2each ; inline
|
||||
>r [ phantom-locs* ] [ stack>> ] bi r> 2each ; inline
|
||||
|
||||
: each-loc ( quot -- )
|
||||
>r phantom-d get r> phantom-r get over
|
||||
>r >r (each-loc) r> r> (each-loc) ; inline
|
||||
phantoms 2array swap [ (each-loc) ] curry each ; inline
|
||||
|
||||
: adjust-phantom ( n phantom -- )
|
||||
[ phantom-stack-height + ] keep set-phantom-stack-height ;
|
||||
swap [ + ] curry change-height drop ;
|
||||
|
||||
GENERIC: cut-phantom ( n phantom -- seq )
|
||||
|
||||
M: phantom-stack cut-phantom
|
||||
[ delegate swap cut* swap ] keep set-delegate ;
|
||||
: cut-phantom ( n phantom -- seq )
|
||||
swap [ cut* swap ] curry change-stack drop ;
|
||||
|
||||
: phantom-append ( seq stack -- )
|
||||
over length over adjust-phantom push-all ;
|
||||
over length over adjust-phantom stack>> push-all ;
|
||||
|
||||
: add-locs ( n phantom -- )
|
||||
2dup length <= [
|
||||
2dup stack>> length <= [
|
||||
2drop
|
||||
] [
|
||||
[ phantom-locs ] keep
|
||||
[ length head-slice* ] keep
|
||||
[ append >vector ] keep
|
||||
delegate set-delegate
|
||||
[ stack>> length head-slice* ] keep
|
||||
[ append >vector ] change-stack drop
|
||||
] if ;
|
||||
|
||||
: phantom-input ( n phantom -- seq )
|
||||
|
@ -316,18 +313,16 @@ M: phantom-stack cut-phantom
|
|||
2dup cut-phantom
|
||||
>r >r neg r> adjust-phantom r> ;
|
||||
|
||||
: phantoms ( -- phantom phantom ) phantom-d get phantom-r get ;
|
||||
|
||||
: each-phantom ( quot -- ) phantoms rot bi@ ; inline
|
||||
|
||||
: finalize-heights ( -- ) [ finalize-height ] each-phantom ;
|
||||
|
||||
: live-vregs ( -- seq )
|
||||
[ [ [ live-vregs* ] each ] each-phantom ] { } make ;
|
||||
[ [ stack>> [ live-vregs* ] each ] each-phantom ] { } make ;
|
||||
|
||||
: (live-locs) ( phantom -- seq )
|
||||
#! Discard locs which haven't moved
|
||||
dup phantom-locs* swap 2array flip
|
||||
[ phantom-locs* ] [ stack>> ] bi 2array flip
|
||||
[ live-loc? ] assoc-subset
|
||||
values ;
|
||||
|
||||
|
@ -340,15 +335,14 @@ SYMBOL: fresh-objects
|
|||
|
||||
! Computing free registers and initializing allocator
|
||||
: reg-spec>class ( spec -- class )
|
||||
float eq?
|
||||
T{ float-regs f 8 } T{ int-regs } ? ;
|
||||
float eq? double-float-regs int-regs ? ;
|
||||
|
||||
: free-vregs ( reg-class -- seq )
|
||||
#! Free vregs in a given register class
|
||||
\ free-vregs get at ;
|
||||
|
||||
: alloc-vreg ( spec -- reg )
|
||||
dup reg-spec>class free-vregs pop swap {
|
||||
[ reg-spec>class free-vregs pop ] keep {
|
||||
{ f [ <tagged> ] }
|
||||
{ unboxed-alien [ <unboxed-alien> ] }
|
||||
{ unboxed-byte-array [ <unboxed-byte-array> ] }
|
||||
|
@ -374,8 +368,8 @@ SYMBOL: fresh-objects
|
|||
} cond ;
|
||||
|
||||
: alloc-vreg-for ( value spec -- vreg )
|
||||
swap operand-class swap alloc-vreg
|
||||
dup tagged? [ tuck set-tagged-class ] [ nip ] if ;
|
||||
alloc-vreg swap operand-class
|
||||
over tagged? [ >>class ] [ drop ] if ;
|
||||
|
||||
M: value (lazy-load)
|
||||
2dup allocation [
|
||||
|
@ -393,7 +387,7 @@ M: value (lazy-load)
|
|||
: compute-free-vregs ( -- )
|
||||
#! Create a new hashtable for thee free-vregs variable.
|
||||
live-vregs
|
||||
{ T{ int-regs } T{ float-regs f 8 } }
|
||||
{ int-regs double-float-regs }
|
||||
[ 2dup (compute-free-vregs) ] H{ } map>assoc
|
||||
\ free-vregs set
|
||||
drop ;
|
||||
|
@ -418,7 +412,7 @@ M: loc lazy-store
|
|||
#! When shuffling more values than can fit in registers, we
|
||||
#! need to find an area on the data stack which isn't in
|
||||
#! use.
|
||||
dup phantom-stack-height neg [ minimal-ds-loc* ] reduce ;
|
||||
[ stack>> ] [ height>> neg ] bi [ minimal-ds-loc* ] reduce ;
|
||||
|
||||
: find-tmp-loc ( -- n )
|
||||
#! Find an area of the data stack which is not referenced
|
||||
|
@ -442,7 +436,7 @@ M: loc lazy-store
|
|||
: fast-shuffle? ( live-locs -- ? )
|
||||
#! Test if we have enough free registers to load all
|
||||
#! shuffle inputs at once.
|
||||
T{ int-regs } free-vregs [ length ] bi@ <= ;
|
||||
int-regs free-vregs [ length ] bi@ <= ;
|
||||
|
||||
: finalize-locs ( -- )
|
||||
#! Perform any deferred stack shuffling.
|
||||
|
@ -462,13 +456,13 @@ M: loc lazy-store
|
|||
#! Kill register assignments but preserve constants and
|
||||
#! class information.
|
||||
dup phantom-locs*
|
||||
over [
|
||||
over stack>> [
|
||||
dup constant? [ nip ] [
|
||||
operand-class over set-operand-class
|
||||
] if
|
||||
] 2map
|
||||
over delete-all
|
||||
swap push-all ;
|
||||
over stack>> delete-all
|
||||
swap stack>> push-all ;
|
||||
|
||||
: reset-phantoms ( -- )
|
||||
[ reset-phantom ] each-phantom ;
|
||||
|
@ -483,10 +477,11 @@ M: loc lazy-store
|
|||
|
||||
! Loading stacks to vregs
|
||||
: free-vregs? ( int# float# -- ? )
|
||||
T{ float-regs f 8 } free-vregs length <=
|
||||
>r T{ int-regs } free-vregs length <= r> and ;
|
||||
double-float-regs free-vregs length <=
|
||||
>r int-regs free-vregs length <= r> and ;
|
||||
|
||||
: phantom&spec ( phantom spec -- phantom' spec' )
|
||||
>r stack>> r>
|
||||
[ length f pad-left ] keep
|
||||
[ <reversed> ] bi@ ; inline
|
||||
|
||||
|
@ -504,7 +499,7 @@ M: loc lazy-store
|
|||
: substitute-vregs ( values vregs -- )
|
||||
[ vreg-substitution ] 2map
|
||||
[ substitute-vreg? ] assoc-subset >hashtable
|
||||
[ substitute-here ] curry each-phantom ;
|
||||
[ >r stack>> r> substitute-here ] curry each-phantom ;
|
||||
|
||||
: set-operand ( value var -- )
|
||||
>r dup constant? [ constant-value ] when r> set ;
|
||||
|
@ -516,14 +511,15 @@ M: loc lazy-store
|
|||
substitute-vregs ;
|
||||
|
||||
: load-inputs ( -- )
|
||||
+input+ get dup length phantom-d get phantom-input
|
||||
swap lazy-load ;
|
||||
+input+ get
|
||||
[ length phantom-datastack get phantom-input ] keep
|
||||
lazy-load ;
|
||||
|
||||
: output-vregs ( -- seq seq )
|
||||
+output+ +clobber+ [ get [ get ] map ] bi@ ;
|
||||
|
||||
: clash? ( seq -- ? )
|
||||
phantoms append [
|
||||
phantoms [ stack>> ] bi@ append [
|
||||
dup cached? [ cached-vreg ] when swap member?
|
||||
] with contains? ;
|
||||
|
||||
|
@ -534,22 +530,21 @@ M: loc lazy-store
|
|||
|
||||
: count-input-vregs ( phantom spec -- )
|
||||
phantom&spec [
|
||||
>r dup cached? [ cached-vreg ] when r> allocation
|
||||
>r dup cached? [ cached-vreg ] when r> first allocation
|
||||
] 2map count-vregs ;
|
||||
|
||||
: count-scratch-regs ( spec -- )
|
||||
[ first reg-spec>class ] map count-vregs ;
|
||||
|
||||
: guess-vregs ( dinput rinput scratch -- int# float# )
|
||||
H{
|
||||
{ T{ int-regs } 0 }
|
||||
{ T{ float-regs 8 } 0 }
|
||||
} clone [
|
||||
[
|
||||
0 int-regs set
|
||||
0 double-float-regs set
|
||||
count-scratch-regs
|
||||
phantom-r get swap count-input-vregs
|
||||
phantom-d get swap count-input-vregs
|
||||
T{ int-regs } get T{ float-regs 8 } get
|
||||
] bind ;
|
||||
phantom-retainstack get swap count-input-vregs
|
||||
phantom-datastack get swap count-input-vregs
|
||||
int-regs get double-float-regs get
|
||||
] with-scope ;
|
||||
|
||||
: alloc-scratch ( -- )
|
||||
+scratch+ get [ >r alloc-vreg r> set ] assoc-each ;
|
||||
|
@ -566,7 +561,7 @@ M: loc lazy-store
|
|||
outputs-clash? [ finalize-contents ] when ;
|
||||
|
||||
: template-outputs ( -- )
|
||||
+output+ get [ get ] map phantom-d get phantom-append ;
|
||||
+output+ get [ get ] map phantom-datastack get phantom-append ;
|
||||
|
||||
: value-matches? ( value spec -- ? )
|
||||
#! If the spec is a quotation and the value is a literal
|
||||
|
@ -581,12 +576,6 @@ M: loc lazy-store
|
|||
2drop t
|
||||
] if ;
|
||||
|
||||
: class-tags ( class -- tag/f )
|
||||
class-types [
|
||||
dup num-tags get >=
|
||||
[ drop object tag-number ] when
|
||||
] map prune ;
|
||||
|
||||
: class-tag ( class -- tag/f )
|
||||
class-tags dup length 1 = [ first ] [ drop f ] if ;
|
||||
|
||||
|
@ -602,7 +591,7 @@ M: loc lazy-store
|
|||
>r >r operand-class 2 r> ?nth class-matches? r> and ;
|
||||
|
||||
: template-matches? ( spec -- ? )
|
||||
phantom-d get +input+ rot at
|
||||
phantom-datastack get +input+ rot at
|
||||
[ spec-matches? ] phantom&spec-agree? ;
|
||||
|
||||
: ensure-template-vregs ( -- )
|
||||
|
@ -611,14 +600,14 @@ M: loc lazy-store
|
|||
] unless ;
|
||||
|
||||
: clear-phantoms ( -- )
|
||||
[ delete-all ] each-phantom ;
|
||||
[ stack>> delete-all ] each-phantom ;
|
||||
|
||||
PRIVATE>
|
||||
|
||||
: set-operand-classes ( classes -- )
|
||||
phantom-d get
|
||||
phantom-datastack get
|
||||
over length over add-locs
|
||||
[ set-operand-class ] 2reverse-each ;
|
||||
stack>> [ set-operand-class ] 2reverse-each ;
|
||||
|
||||
: end-basic-block ( -- )
|
||||
#! Commit all deferred stacking shuffling, and ensure the
|
||||
|
@ -627,7 +616,7 @@ PRIVATE>
|
|||
finalize-contents
|
||||
clear-phantoms
|
||||
finalize-heights
|
||||
fresh-objects get dup empty? swap delete-all [ %gc ] unless ;
|
||||
fresh-objects get [ empty? [ %gc ] unless ] [ delete-all ] bi ;
|
||||
|
||||
: with-template ( quot hash -- )
|
||||
clone [
|
||||
|
@ -647,16 +636,16 @@ PRIVATE>
|
|||
: init-templates ( -- )
|
||||
#! Initialize register allocator.
|
||||
V{ } clone fresh-objects set
|
||||
<phantom-datastack> phantom-d set
|
||||
<phantom-retainstack> phantom-r set
|
||||
<phantom-datastack> phantom-datastack set
|
||||
<phantom-retainstack> phantom-retainstack set
|
||||
compute-free-vregs ;
|
||||
|
||||
: copy-templates ( -- )
|
||||
#! Copies register allocator state, used when compiling
|
||||
#! branches.
|
||||
fresh-objects [ clone ] change
|
||||
phantom-d [ clone ] change
|
||||
phantom-r [ clone ] change
|
||||
phantom-datastack [ clone ] change
|
||||
phantom-retainstack [ clone ] change
|
||||
compute-free-vregs ;
|
||||
|
||||
: find-template ( templates -- pair/f )
|
||||
|
@ -672,17 +661,17 @@ UNION: immediate fixnum POSTPONE: f ;
|
|||
operand-class immediate class< ;
|
||||
|
||||
: phantom-push ( obj -- )
|
||||
1 phantom-d get adjust-phantom
|
||||
phantom-d get push ;
|
||||
1 phantom-datastack get adjust-phantom
|
||||
phantom-datastack get stack>> push ;
|
||||
|
||||
: phantom-shuffle ( shuffle -- )
|
||||
[ effect-in length phantom-d get phantom-input ] keep
|
||||
shuffle* phantom-d get phantom-append ;
|
||||
[ effect-in length phantom-datastack get phantom-input ] keep
|
||||
shuffle* phantom-datastack get phantom-append ;
|
||||
|
||||
: phantom->r ( n -- )
|
||||
phantom-d get phantom-input
|
||||
phantom-r get phantom-append ;
|
||||
phantom-datastack get phantom-input
|
||||
phantom-retainstack get phantom-append ;
|
||||
|
||||
: phantom-r> ( n -- )
|
||||
phantom-r get phantom-input
|
||||
phantom-d get phantom-append ;
|
||||
phantom-retainstack get phantom-input
|
||||
phantom-datastack get phantom-append ;
|
||||
|
|
|
@ -37,6 +37,8 @@ $nl
|
|||
{ $subsection create-method }
|
||||
"Method definitions can be looked up:"
|
||||
{ $subsection method }
|
||||
"Finding the most specific method for an object:"
|
||||
{ $subsection effective-method }
|
||||
"A generic word contains methods; the list of methods specializing on a class can also be obtained:"
|
||||
{ $subsection implementors }
|
||||
"Low-level word which rebuilds the generic word after methods are added or removed, or the method combination is changed:"
|
||||
|
@ -64,6 +66,19 @@ $nl
|
|||
"The combination quotation passed to " { $link define-generic } " has stack effect " { $snippet "( word -- quot )" } ". It's job is to call various introspection words, including at least obtaining the set of methods defined on the generic word, then combining these methods in some way to produce a quotation."
|
||||
{ $see-also "generic-introspection" } ;
|
||||
|
||||
ARTICLE: "call-next-method" "Calling less-specific methods"
|
||||
"If a generic word is called with an object and multiple methods specialize on classes that this object is an instance of, usually the most specific method is called (" { $link "method-order" } ")."
|
||||
$nl
|
||||
"Less-specific methods can be called directly:"
|
||||
{ $subsection POSTPONE: call-next-method }
|
||||
"A lower-level word which the above expands into:"
|
||||
{ $subsection (call-next-method) }
|
||||
"To look up the next applicable method reflectively:"
|
||||
{ $subsection next-method }
|
||||
"Errors thrown by improper calls to " { $link POSTPONE: call-next-method } ":"
|
||||
{ $subsection inconsistent-next-method }
|
||||
{ $subsection no-next-method } ;
|
||||
|
||||
ARTICLE: "generic" "Generic words and methods"
|
||||
"A " { $emphasis "generic word" } " is composed of zero or more " { $emphasis "methods" } " together with a " { $emphasis "method combination" } ". A method " { $emphasis "specializes" } " on a class; when a generic word executed, the method combination chooses the most appropriate method and calls its definition."
|
||||
$nl
|
||||
|
@ -81,6 +96,7 @@ $nl
|
|||
{ $subsection POSTPONE: M: }
|
||||
"Generic words must declare their stack effect in order to compile. See " { $link "effect-declaration" } "."
|
||||
{ $subsection "method-order" }
|
||||
{ $subsection "call-next-method" }
|
||||
{ $subsection "generic-introspection" }
|
||||
{ $subsection "method-combination" }
|
||||
"Generic words specialize behavior based on the class of an object; sometimes behavior needs to be specialized on the object's " { $emphasis "structure" } "; this is known as " { $emphasis "pattern matching" } " and is implemented in the " { $vocab-link "match" } " vocabulary." ;
|
||||
|
@ -147,3 +163,8 @@ HELP: forget-methods
|
|||
{ $description "Remove all method definitions which specialize on the class." } ;
|
||||
|
||||
{ sort-classes order } related-words
|
||||
|
||||
HELP: (call-next-method)
|
||||
{ $values { "class" class } { "generic" generic } }
|
||||
{ $description "Low-level word implementing " { $link POSTPONE: call-next-method } "." }
|
||||
{ $notes "In most cases, " { $link POSTPONE: call-next-method } " should be used instead." } ;
|
||||
|
|
|
@ -123,17 +123,6 @@ M: integer wii drop 6 ;
|
|||
|
||||
[ 3 ] [ T{ first-one } wii ] unit-test
|
||||
|
||||
! Hooks
|
||||
SYMBOL: my-var
|
||||
HOOK: my-hook my-var ( -- x )
|
||||
|
||||
M: integer my-hook "an integer" ;
|
||||
M: string my-hook "a string" ;
|
||||
|
||||
[ "an integer" ] [ 3 my-var set my-hook ] unit-test
|
||||
[ "a string" ] [ my-hook my-var set my-hook ] unit-test
|
||||
[ 1.0 my-var set my-hook ] [ T{ no-method f 1.0 my-hook } = ] must-fail-with
|
||||
|
||||
GENERIC: tag-and-f ( x -- x x )
|
||||
|
||||
M: fixnum tag-and-f 1 ;
|
||||
|
|
|
@ -29,6 +29,8 @@ PREDICATE: method-spec < pair
|
|||
: order ( generic -- seq )
|
||||
"methods" word-prop keys sort-classes ;
|
||||
|
||||
GENERIC: effective-method ( ... generic -- method )
|
||||
|
||||
: next-method-class ( class generic -- class/f )
|
||||
order [ class< ] with subset reverse dup length 1 =
|
||||
[ drop f ] [ second ] if ;
|
||||
|
@ -36,7 +38,10 @@ PREDICATE: method-spec < pair
|
|||
: next-method ( class generic -- class/f )
|
||||
[ next-method-class ] keep method ;
|
||||
|
||||
GENERIC: next-method-quot ( class generic -- quot )
|
||||
GENERIC: next-method-quot* ( class generic -- quot )
|
||||
|
||||
: next-method-quot ( class generic -- quot )
|
||||
dup "combination" word-prop next-method-quot* ;
|
||||
|
||||
: (call-next-method) ( class generic -- )
|
||||
next-method-quot call ;
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: arrays generic hashtables kernel kernel.private
|
||||
math namespaces sequences words quotations layouts combinators
|
||||
sequences.private classes classes.algebra definitions ;
|
||||
sequences.private classes classes.builtin classes.algebra
|
||||
definitions ;
|
||||
IN: generic.math
|
||||
|
||||
PREDICATE: math-class < class
|
||||
|
|
|
@ -47,3 +47,5 @@ SYMBOL: (dispatch#)
|
|||
} case ;
|
||||
|
||||
: picker ( -- quot ) \ (dispatch#) get (picker) ;
|
||||
|
||||
GENERIC: extra-values ( generic -- n )
|
||||
|
|
|
@ -66,7 +66,9 @@ PREDICATE: tuple-dispatch-engine-word < word
|
|||
"tuple-dispatch-engine" word-prop ;
|
||||
|
||||
M: tuple-dispatch-engine-word stack-effect
|
||||
"tuple-dispatch-generic" word-prop stack-effect ;
|
||||
"tuple-dispatch-generic" word-prop
|
||||
[ extra-values ] [ stack-effect clone ] bi
|
||||
[ length + ] change-in ;
|
||||
|
||||
M: tuple-dispatch-engine-word crossref?
|
||||
drop t ;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
USING: generic help.markup help.syntax sequences ;
|
||||
USING: generic help.markup help.syntax sequences math
|
||||
math.parser ;
|
||||
IN: generic.standard
|
||||
|
||||
HELP: no-method
|
||||
|
@ -10,7 +11,7 @@ HELP: standard-combination
|
|||
{ $class-description
|
||||
"Performs standard method combination."
|
||||
$nl
|
||||
"Generic words using the standard method combination dispatch on the class of the object at the given stack position, where 0 is the top of the stack, 1 is the object underneath, and 2 is the next one under that. If no suitable method is defined on the class of the dispatch object, the generic word is called on the dispatch object's delegate. If the delegate is " { $link f } ", an exception is thrown."
|
||||
"Generic words using the standard method combination dispatch on the class of the object at the given stack position, where 0 is the top of the stack, 1 is the object underneath, and 2 is the next one under that. A " { $link no-method } " error is thrown if no suitable method is defined on the class."
|
||||
}
|
||||
{ $examples
|
||||
"A generic word for append strings and characters to a sequence, dispatching on the object underneath the top of the stack:"
|
||||
|
@ -31,3 +32,38 @@ HELP: define-simple-generic
|
|||
{ $description "Defines a generic word with the " { $link standard-combination } " method combination and a dispatch position of 0." } ;
|
||||
|
||||
{ standard-combination hook-combination } related-words
|
||||
|
||||
HELP: no-next-method
|
||||
{ $error-description "Thrown by " { $link POSTPONE: call-next-method } " if the current method is already the least specific method." }
|
||||
{ $examples
|
||||
"The following code throws this error:"
|
||||
{ $code
|
||||
"GENERIC: error-test ( object -- )"
|
||||
""
|
||||
"M: number error-test 3 + call-next-method ;"
|
||||
""
|
||||
"M: integer error-test recip call-next-method ;"
|
||||
""
|
||||
"123 error-test"
|
||||
}
|
||||
"This results in the method on " { $link integer } " being called, which then calls the method on " { $link number } ". The latter then calls " { $link POSTPONE: call-next-method } ", however there is no method less specific than the method on " { $link number } " and so an error is thrown."
|
||||
} ;
|
||||
|
||||
HELP: inconsistent-next-method
|
||||
{ $error-description "Thrown by " { $link POSTPONE: call-next-method } " if the values on the stack are not compatible with the current method." }
|
||||
{ $examples
|
||||
"The following code throws this error:"
|
||||
{ $code
|
||||
"GENERIC: error-test ( object -- )"
|
||||
""
|
||||
"M: string error-test print ;"
|
||||
""
|
||||
"M: integer error-test number>string call-next-method ;"
|
||||
""
|
||||
"123 error-test"
|
||||
}
|
||||
"This results in the method on " { $link integer } " being called, which then passes a string to " { $link POSTPONE: call-next-method } ". However, this fails because the string is not compatible with the current method."
|
||||
$nl
|
||||
"This usually indicates programmer error; if the intention above was to call the string method on the result of " { $link number>string } ", the code should be rewritten as follows:"
|
||||
{ $code "M: integer error-test number>string error-test ;" }
|
||||
} ;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
IN: generic.standard.tests
|
||||
USING: tools.test math math.functions math.constants
|
||||
generic.standard strings sequences arrays kernel accessors
|
||||
words float-arrays byte-arrays bit-arrays parser namespaces ;
|
||||
words float-arrays byte-arrays bit-arrays parser namespaces
|
||||
quotations inference vectors growable ;
|
||||
|
||||
GENERIC: lo-tag-test
|
||||
|
||||
|
@ -194,7 +195,7 @@ M: ceo salary
|
|||
[ 102000 ] [ executive construct-boa salary ] unit-test
|
||||
|
||||
[ ceo construct-boa salary ]
|
||||
[ T{ inconsistent-next-method f 5 ceo salary } = ] must-fail-with
|
||||
[ T{ inconsistent-next-method f ceo salary } = ] must-fail-with
|
||||
|
||||
[ intern construct-boa salary ]
|
||||
[ T{ no-next-method f intern salary } = ] must-fail-with
|
||||
|
@ -233,3 +234,37 @@ M: c funky* "c" , call-next-method ;
|
|||
T{ a } funky
|
||||
{ { "a" "x" "z" } { "a" "y" "z" } } member?
|
||||
] unit-test
|
||||
|
||||
! Hooks
|
||||
SYMBOL: my-var
|
||||
HOOK: my-hook my-var ( -- x )
|
||||
|
||||
M: integer my-hook "an integer" ;
|
||||
M: string my-hook "a string" ;
|
||||
|
||||
[ "an integer" ] [ 3 my-var set my-hook ] unit-test
|
||||
[ "a string" ] [ my-hook my-var set my-hook ] unit-test
|
||||
[ 1.0 my-var set my-hook ] [ T{ no-method f 1.0 my-hook } = ] must-fail-with
|
||||
|
||||
HOOK: my-tuple-hook my-var ( -- x )
|
||||
|
||||
M: sequence my-tuple-hook my-hook ;
|
||||
|
||||
[ f ] [
|
||||
\ my-tuple-hook [ "engines" word-prop ] keep prefix
|
||||
[ 1quotation infer ] map all-equal?
|
||||
] unit-test
|
||||
|
||||
HOOK: call-next-hooker my-var ( -- x )
|
||||
|
||||
M: sequence call-next-hooker "sequence" ;
|
||||
|
||||
M: array call-next-hooker call-next-method "array " prepend ;
|
||||
|
||||
M: vector call-next-hooker call-next-method "vector " prepend ;
|
||||
|
||||
M: growable call-next-hooker call-next-method "growable " prepend ;
|
||||
|
||||
[ "vector growable sequence" ] [
|
||||
V{ } my-var [ call-next-hooker ] with-variable
|
||||
] unit-test
|
||||
|
|
|
@ -67,7 +67,9 @@ ERROR: no-method object generic ;
|
|||
drop generic get "default-method" word-prop 1quotation
|
||||
] unless ;
|
||||
|
||||
GENERIC: mangle-method ( method generic -- quot )
|
||||
: mangle-method ( method generic -- quot )
|
||||
[ 1quotation ] [ extra-values \ drop <repetition> ] bi*
|
||||
prepend [ ] like ;
|
||||
|
||||
: single-combination ( word -- quot )
|
||||
[
|
||||
|
@ -91,6 +93,23 @@ GENERIC: mangle-method ( method generic -- quot )
|
|||
} cleave
|
||||
] with-scope ;
|
||||
|
||||
ERROR: inconsistent-next-method class generic ;
|
||||
|
||||
ERROR: no-next-method class generic ;
|
||||
|
||||
: single-next-method-quot ( class generic -- quot )
|
||||
[
|
||||
[ drop [ instance? ] curry % ]
|
||||
[
|
||||
2dup next-method
|
||||
[ 2nip 1quotation ]
|
||||
[ [ no-next-method ] 2curry ] if* ,
|
||||
]
|
||||
[ [ inconsistent-next-method ] 2curry , ]
|
||||
2tri
|
||||
\ if ,
|
||||
] [ ] make ;
|
||||
|
||||
TUPLE: standard-combination # ;
|
||||
|
||||
C: <standard-combination> standard-combination
|
||||
|
@ -107,8 +126,7 @@ PREDICATE: simple-generic < standard-generic
|
|||
: with-standard ( combination quot -- quot' )
|
||||
>r #>> (dispatch#) r> with-variable ; inline
|
||||
|
||||
M: standard-generic mangle-method
|
||||
drop 1quotation ;
|
||||
M: standard-generic extra-values drop 0 ;
|
||||
|
||||
M: standard-combination make-default-method
|
||||
[ empty-method ] with-standard ;
|
||||
|
@ -118,25 +136,14 @@ M: standard-combination perform-combination
|
|||
|
||||
M: standard-combination dispatch# #>> ;
|
||||
|
||||
ERROR: inconsistent-next-method object class generic ;
|
||||
|
||||
ERROR: no-next-method class generic ;
|
||||
|
||||
M: standard-generic next-method-quot
|
||||
M: standard-combination next-method-quot*
|
||||
[
|
||||
[
|
||||
[ [ instance? ] curry ]
|
||||
[ dispatch# (picker) ] bi* prepend %
|
||||
]
|
||||
[
|
||||
2dup next-method
|
||||
[ 2nip 1quotation ]
|
||||
[ [ no-next-method ] 2curry ] if* ,
|
||||
]
|
||||
[ [ inconsistent-next-method ] 2curry , ]
|
||||
2tri
|
||||
\ if ,
|
||||
] [ ] make ;
|
||||
single-next-method-quot picker prepend
|
||||
] with-standard ;
|
||||
|
||||
M: standard-generic effective-method
|
||||
[ dispatch# (picker) call ] keep
|
||||
[ order [ instance? ] with find-last nip ] keep method ;
|
||||
|
||||
TUPLE: hook-combination var ;
|
||||
|
||||
|
@ -152,8 +159,7 @@ PREDICATE: hook-generic < generic
|
|||
|
||||
M: hook-combination dispatch# drop 0 ;
|
||||
|
||||
M: hook-generic mangle-method
|
||||
drop 1quotation [ drop ] prepend ;
|
||||
M: hook-generic extra-values drop 1 ;
|
||||
|
||||
M: hook-combination make-default-method
|
||||
[ error-method ] with-hook ;
|
||||
|
@ -161,6 +167,9 @@ M: hook-combination make-default-method
|
|||
M: hook-combination perform-combination
|
||||
[ drop ] [ [ single-combination ] with-hook ] 2bi define ;
|
||||
|
||||
M: hook-combination next-method-quot*
|
||||
[ single-next-method-quot ] with-hook ;
|
||||
|
||||
M: simple-generic definer drop \ GENERIC: f ;
|
||||
|
||||
M: standard-generic definer drop \ GENERIC# f ;
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
! See http://factorcode.org/license.txt for BSD license.
|
||||
|
||||
USING: arrays kernel math namespaces tools.test
|
||||
heaps heaps.private math.parser random assocs sequences sorting ;
|
||||
heaps heaps.private math.parser random assocs sequences sorting
|
||||
accessors ;
|
||||
IN: heaps.tests
|
||||
|
||||
[ <min-heap> heap-pop ] must-fail
|
||||
|
@ -47,7 +48,7 @@ IN: heaps.tests
|
|||
: test-entry-indices ( n -- ? )
|
||||
random-alist
|
||||
<min-heap> [ heap-push-all ] keep
|
||||
heap-data dup length swap [ entry-index ] map sequence= ;
|
||||
data>> dup length swap [ entry-index ] map sequence= ;
|
||||
|
||||
14 [
|
||||
[ t ] swap [ 2^ test-entry-indices ] curry unit-test
|
||||
|
@ -63,9 +64,9 @@ IN: heaps.tests
|
|||
[
|
||||
random-alist
|
||||
<min-heap> [ heap-push-all ] keep
|
||||
dup heap-data clone swap
|
||||
dup data>> clone swap
|
||||
] keep 3 /i [ 2dup >r delete-random r> heap-delete ] times
|
||||
heap-data
|
||||
data>>
|
||||
[ [ entry-key ] map ] bi@
|
||||
[ natural-sort ] bi@ ;
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ GENERIC: heap-size ( heap -- n )
|
|||
|
||||
<PRIVATE
|
||||
|
||||
: heap-data delegate ; inline
|
||||
TUPLE: heap data ;
|
||||
|
||||
: <heap> ( class -- heap )
|
||||
>r V{ } clone r> construct-delegate ; inline
|
||||
>r V{ } clone r> construct-boa ; inline
|
||||
|
||||
TUPLE: entry value key heap index ;
|
||||
|
||||
|
@ -28,11 +28,11 @@ TUPLE: entry value key heap index ;
|
|||
|
||||
PRIVATE>
|
||||
|
||||
TUPLE: min-heap ;
|
||||
TUPLE: min-heap < heap ;
|
||||
|
||||
: <min-heap> ( -- min-heap ) min-heap <heap> ;
|
||||
|
||||
TUPLE: max-heap ;
|
||||
TUPLE: max-heap < heap ;
|
||||
|
||||
: <max-heap> ( -- max-heap ) max-heap <heap> ;
|
||||
|
||||
|
@ -40,10 +40,10 @@ INSTANCE: min-heap priority-queue
|
|||
INSTANCE: max-heap priority-queue
|
||||
|
||||
M: priority-queue heap-empty? ( heap -- ? )
|
||||
heap-data empty? ;
|
||||
data>> empty? ;
|
||||
|
||||
M: priority-queue heap-size ( heap -- n )
|
||||
heap-data length ;
|
||||
data>> length ;
|
||||
|
||||
<PRIVATE
|
||||
|
||||
|
@ -54,7 +54,7 @@ M: priority-queue heap-size ( heap -- n )
|
|||
: up ( n -- m ) 1- 2/ ; inline
|
||||
|
||||
: data-nth ( n heap -- entry )
|
||||
heap-data nth-unsafe ; inline
|
||||
data>> nth-unsafe ; inline
|
||||
|
||||
: up-value ( n heap -- entry )
|
||||
>r up r> data-nth ; inline
|
||||
|
@ -67,24 +67,24 @@ M: priority-queue heap-size ( heap -- n )
|
|||
|
||||
: data-set-nth ( entry n heap -- )
|
||||
>r [ swap set-entry-index ] 2keep r>
|
||||
heap-data set-nth-unsafe ;
|
||||
data>> set-nth-unsafe ;
|
||||
|
||||
: data-push ( entry heap -- n )
|
||||
dup heap-size [
|
||||
swap 2dup heap-data ensure 2drop data-set-nth
|
||||
swap 2dup data>> ensure 2drop data-set-nth
|
||||
] keep ; inline
|
||||
|
||||
: data-pop ( heap -- entry )
|
||||
heap-data pop ; inline
|
||||
data>> pop ; inline
|
||||
|
||||
: data-pop* ( heap -- )
|
||||
heap-data pop* ; inline
|
||||
data>> pop* ; inline
|
||||
|
||||
: data-peek ( heap -- entry )
|
||||
heap-data peek ; inline
|
||||
data>> peek ; inline
|
||||
|
||||
: data-first ( heap -- entry )
|
||||
heap-data first ; inline
|
||||
data>> first ; inline
|
||||
|
||||
: data-exchange ( m n heap -- )
|
||||
[ tuck data-nth >r data-nth r> ] 3keep
|
||||
|
|
|
@ -4,7 +4,7 @@ USING: inference.dataflow inference.state arrays generic io
|
|||
io.streams.string kernel math namespaces parser prettyprint
|
||||
sequences strings vectors words quotations effects classes
|
||||
continuations debugger assocs combinators compiler.errors
|
||||
generic.standard.engines.tuple ;
|
||||
generic.standard.engines.tuple accessors ;
|
||||
IN: inference.backend
|
||||
|
||||
: recursive-label ( word -- label/f )
|
||||
|
@ -32,18 +32,16 @@ M: word inline?
|
|||
: recursive-quotation? ( quot -- ? )
|
||||
local-recursive-state [ first eq? ] with contains? ;
|
||||
|
||||
TUPLE: inference-error rstate type ;
|
||||
TUPLE: inference-error error type rstate ;
|
||||
|
||||
M: inference-error compiler-error-type
|
||||
inference-error-type ;
|
||||
M: inference-error compiler-error-type type>> ;
|
||||
|
||||
M: inference-error error-help error>> error-help ;
|
||||
|
||||
: (inference-error) ( ... class type -- * )
|
||||
>r construct-boa r>
|
||||
recursive-state get {
|
||||
set-delegate
|
||||
set-inference-error-type
|
||||
set-inference-error-rstate
|
||||
} \ inference-error construct throw ; inline
|
||||
recursive-state get
|
||||
\ inference-error construct-boa throw ; inline
|
||||
|
||||
: inference-error ( ... class -- * )
|
||||
+error+ (inference-error) ; inline
|
||||
|
@ -363,7 +361,7 @@ TUPLE: effect-error word effect ;
|
|||
\ effect-error inference-error ;
|
||||
|
||||
: check-effect ( word effect -- )
|
||||
dup pick "declared-effect" word-prop effect<=
|
||||
dup pick stack-effect effect<=
|
||||
[ 2drop ] [ effect-error ] if ;
|
||||
|
||||
: finish-word ( word -- )
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: arrays generic assocs kernel math namespaces parser
|
||||
sequences words vectors math.intervals effects classes
|
||||
inference.state ;
|
||||
inference.state accessors combinators ;
|
||||
IN: inference.dataflow
|
||||
|
||||
! Computed value
|
||||
|
@ -39,12 +39,12 @@ M: node hashcode* drop node hashcode* ;
|
|||
GENERIC: flatten-curry ( value -- )
|
||||
|
||||
M: curried flatten-curry
|
||||
dup curried-obj flatten-curry
|
||||
curried-quot flatten-curry ;
|
||||
[ obj>> flatten-curry ]
|
||||
[ quot>> flatten-curry ] bi ;
|
||||
|
||||
M: composed flatten-curry
|
||||
dup composed-quot1 flatten-curry
|
||||
composed-quot2 flatten-curry ;
|
||||
[ quot1>> flatten-curry ]
|
||||
[ quot2>> flatten-curry ] bi ;
|
||||
|
||||
M: object flatten-curry , ;
|
||||
|
||||
|
@ -57,31 +57,27 @@ M: object flatten-curry , ;
|
|||
meta-d get clone flatten-curries ;
|
||||
|
||||
: modify-values ( node quot -- )
|
||||
[ swap [ node-in-d swap call ] keep set-node-in-d ] 2keep
|
||||
[ swap [ node-in-r swap call ] keep set-node-in-r ] 2keep
|
||||
[ swap [ node-out-d swap call ] keep set-node-out-d ] 2keep
|
||||
swap [ node-out-r swap call ] keep set-node-out-r ; inline
|
||||
{
|
||||
[ change-in-d ]
|
||||
[ change-in-r ]
|
||||
[ change-out-d ]
|
||||
[ change-out-r ]
|
||||
} cleave drop ; inline
|
||||
|
||||
: node-shuffle ( node -- shuffle )
|
||||
dup node-in-d swap node-out-d <effect> ;
|
||||
|
||||
: make-node ( slots class -- node )
|
||||
>r node construct r> construct-delegate ; inline
|
||||
|
||||
: empty-node ( class -- node )
|
||||
{ } swap make-node ; inline
|
||||
[ in-d>> ] [ out-d>> ] bi <effect> ;
|
||||
|
||||
: param-node ( param class -- node )
|
||||
{ set-node-param } swap make-node ; inline
|
||||
construct-empty swap >>param ; inline
|
||||
|
||||
: in-node ( seq class -- node )
|
||||
{ set-node-in-d } swap make-node ; inline
|
||||
construct-empty swap >>in-d ; inline
|
||||
|
||||
: all-in-node ( class -- node )
|
||||
flatten-meta-d swap in-node ; inline
|
||||
|
||||
: out-node ( seq class -- node )
|
||||
{ set-node-out-d } swap make-node ; inline
|
||||
construct-empty swap >>out-d ; inline
|
||||
|
||||
: all-out-node ( class -- node )
|
||||
flatten-meta-d swap out-node ; inline
|
||||
|
@ -94,81 +90,81 @@ M: object flatten-curry , ;
|
|||
|
||||
: node-child node-children first ;
|
||||
|
||||
TUPLE: #label word loop? ;
|
||||
TUPLE: #label < node word loop? ;
|
||||
|
||||
: #label ( word label -- node )
|
||||
\ #label param-node [ set-#label-word ] keep ;
|
||||
\ #label param-node swap >>word ;
|
||||
|
||||
PREDICATE: #loop < #label #label-loop? ;
|
||||
|
||||
TUPLE: #entry ;
|
||||
TUPLE: #entry < node ;
|
||||
|
||||
: #entry ( -- node ) \ #entry all-out-node ;
|
||||
|
||||
TUPLE: #call ;
|
||||
TUPLE: #call < node ;
|
||||
|
||||
: #call ( word -- node ) \ #call param-node ;
|
||||
|
||||
TUPLE: #call-label ;
|
||||
TUPLE: #call-label < node ;
|
||||
|
||||
: #call-label ( label -- node ) \ #call-label param-node ;
|
||||
|
||||
TUPLE: #push ;
|
||||
TUPLE: #push < node ;
|
||||
|
||||
: #push ( -- node ) \ #push empty-node ;
|
||||
: #push ( -- node ) \ #push construct-empty ;
|
||||
|
||||
TUPLE: #shuffle ;
|
||||
TUPLE: #shuffle < node ;
|
||||
|
||||
: #shuffle ( -- node ) \ #shuffle empty-node ;
|
||||
: #shuffle ( -- node ) \ #shuffle construct-empty ;
|
||||
|
||||
TUPLE: #>r ;
|
||||
TUPLE: #>r < node ;
|
||||
|
||||
: #>r ( -- node ) \ #>r empty-node ;
|
||||
: #>r ( -- node ) \ #>r construct-empty ;
|
||||
|
||||
TUPLE: #r> ;
|
||||
TUPLE: #r> < node ;
|
||||
|
||||
: #r> ( -- node ) \ #r> empty-node ;
|
||||
: #r> ( -- node ) \ #r> construct-empty ;
|
||||
|
||||
TUPLE: #values ;
|
||||
TUPLE: #values < node ;
|
||||
|
||||
: #values ( -- node ) \ #values all-in-node ;
|
||||
|
||||
TUPLE: #return ;
|
||||
TUPLE: #return < node ;
|
||||
|
||||
: #return ( label -- node )
|
||||
\ #return all-in-node [ set-node-param ] keep ;
|
||||
\ #return all-in-node swap >>param ;
|
||||
|
||||
TUPLE: #if ;
|
||||
TUPLE: #branch < node ;
|
||||
|
||||
TUPLE: #if < #branch ;
|
||||
|
||||
: #if ( -- node ) peek-d 1array \ #if in-node ;
|
||||
|
||||
TUPLE: #dispatch ;
|
||||
TUPLE: #dispatch < #branch ;
|
||||
|
||||
: #dispatch ( -- node ) peek-d 1array \ #dispatch in-node ;
|
||||
|
||||
TUPLE: #merge ;
|
||||
TUPLE: #merge < node ;
|
||||
|
||||
: #merge ( -- node ) \ #merge all-out-node ;
|
||||
|
||||
TUPLE: #terminate ;
|
||||
TUPLE: #terminate < node ;
|
||||
|
||||
: #terminate ( -- node ) \ #terminate empty-node ;
|
||||
: #terminate ( -- node ) \ #terminate construct-empty ;
|
||||
|
||||
TUPLE: #declare ;
|
||||
TUPLE: #declare < node ;
|
||||
|
||||
: #declare ( classes -- node ) \ #declare param-node ;
|
||||
|
||||
UNION: #branch #if #dispatch ;
|
||||
|
||||
: node-inputs ( d-count r-count node -- )
|
||||
tuck
|
||||
>r r-tail flatten-curries r> set-node-in-r
|
||||
>r d-tail flatten-curries r> set-node-in-d ;
|
||||
[ swap d-tail flatten-curries >>in-d drop ]
|
||||
[ swap r-tail flatten-curries >>in-r drop ] 2bi* ;
|
||||
|
||||
: node-outputs ( d-count r-count node -- )
|
||||
tuck
|
||||
>r r-tail flatten-curries r> set-node-out-r
|
||||
>r d-tail flatten-curries r> set-node-out-d ;
|
||||
[ swap d-tail flatten-curries >>out-d drop ]
|
||||
[ swap r-tail flatten-curries >>out-r drop ] 2bi* ;
|
||||
|
||||
: node, ( node -- )
|
||||
dataflow-graph get [
|
||||
|
@ -178,17 +174,15 @@ UNION: #branch #if #dispatch ;
|
|||
] if ;
|
||||
|
||||
: node-values ( node -- values )
|
||||
dup node-in-d
|
||||
over node-out-d
|
||||
pick node-in-r
|
||||
roll node-out-r 4array concat ;
|
||||
{ [ in-d>> ] [ out-d>> ] [ in-r>> ] [ out-r>> ] } cleave
|
||||
4array concat ;
|
||||
|
||||
: last-node ( node -- last )
|
||||
dup node-successor [ last-node ] [ ] ?if ;
|
||||
dup successor>> [ last-node ] [ ] ?if ;
|
||||
|
||||
: penultimate-node ( node -- penultimate )
|
||||
dup node-successor dup [
|
||||
dup node-successor
|
||||
dup successor>> dup [
|
||||
dup successor>>
|
||||
[ nip penultimate-node ] [ drop ] if
|
||||
] [
|
||||
2drop f
|
||||
|
@ -202,7 +196,7 @@ UNION: #branch #if #dispatch ;
|
|||
2dup 2slip rot [
|
||||
2drop t
|
||||
] [
|
||||
>r dup node-children swap node-successor suffix r>
|
||||
>r [ children>> ] [ successor>> ] bi suffix r>
|
||||
[ node-exists? ] curry contains?
|
||||
] if
|
||||
] [
|
||||
|
@ -213,13 +207,13 @@ GENERIC: calls-label* ( label node -- ? )
|
|||
|
||||
M: node calls-label* 2drop f ;
|
||||
|
||||
M: #call-label calls-label* node-param eq? ;
|
||||
M: #call-label calls-label* param>> eq? ;
|
||||
|
||||
: calls-label? ( label node -- ? )
|
||||
[ calls-label* ] with node-exists? ;
|
||||
|
||||
: recursive-label? ( node -- ? )
|
||||
dup node-param swap calls-label? ;
|
||||
[ param>> ] keep calls-label? ;
|
||||
|
||||
SYMBOL: node-stack
|
||||
|
||||
|
@ -227,7 +221,7 @@ SYMBOL: node-stack
|
|||
: node> node-stack get pop ;
|
||||
: node@ node-stack get peek ;
|
||||
|
||||
: iterate-next ( -- node ) node@ node-successor ;
|
||||
: iterate-next ( -- node ) node@ successor>> ;
|
||||
|
||||
: iterate-nodes ( node quot -- )
|
||||
over [
|
||||
|
@ -255,54 +249,55 @@ SYMBOL: node-stack
|
|||
] iterate-nodes drop
|
||||
] with-node-iterator ; inline
|
||||
|
||||
: change-children ( node quot -- )
|
||||
: map-children ( node quot -- )
|
||||
over [
|
||||
>r dup node-children dup r>
|
||||
[ map swap set-node-children ] curry
|
||||
[ 2drop ] if
|
||||
over children>> [
|
||||
[ map ] curry change-children drop
|
||||
] [
|
||||
2drop
|
||||
] if
|
||||
] [
|
||||
2drop
|
||||
] if ; inline
|
||||
|
||||
: (transform-nodes) ( prev node quot -- )
|
||||
dup >r call dup [
|
||||
dup rot set-node-successor
|
||||
dup node-successor r> (transform-nodes)
|
||||
>>successor
|
||||
successor>> dup successor>>
|
||||
r> (transform-nodes)
|
||||
] [
|
||||
r> drop f swap set-node-successor drop
|
||||
r> 2drop f >>successor drop
|
||||
] if ; inline
|
||||
|
||||
: transform-nodes ( node quot -- new-node )
|
||||
over [
|
||||
[ call dup dup node-successor ] keep (transform-nodes)
|
||||
[ call dup dup successor>> ] keep (transform-nodes)
|
||||
] [ drop ] if ; inline
|
||||
|
||||
: node-literal? ( node value -- ? )
|
||||
dup value? >r swap node-literals key? r> or ;
|
||||
dup value? >r swap literals>> key? r> or ;
|
||||
|
||||
: node-literal ( node value -- obj )
|
||||
dup value?
|
||||
[ nip value-literal ] [ swap node-literals at ] if ;
|
||||
[ nip value-literal ] [ swap literals>> at ] if ;
|
||||
|
||||
: node-interval ( node value -- interval )
|
||||
swap node-intervals at ;
|
||||
swap intervals>> at ;
|
||||
|
||||
: node-class ( node value -- class )
|
||||
swap node-classes at object or ;
|
||||
swap classes>> at object or ;
|
||||
|
||||
: node-input-classes ( node -- seq )
|
||||
dup node-in-d [ node-class ] with map ;
|
||||
dup in-d>> [ node-class ] with map ;
|
||||
|
||||
: node-input-intervals ( node -- seq )
|
||||
dup node-in-d [ node-interval ] with map ;
|
||||
dup in-d>> [ node-interval ] with map ;
|
||||
|
||||
: node-class-first ( node -- class )
|
||||
dup node-in-d first node-class ;
|
||||
dup in-d>> first node-class ;
|
||||
|
||||
: active-children ( node -- seq )
|
||||
node-children
|
||||
[ last-node ] map
|
||||
[ #terminate? not ] subset ;
|
||||
children>> [ last-node ] map [ #terminate? not ] subset ;
|
||||
|
||||
DEFER: #tail?
|
||||
|
||||
|
@ -317,5 +312,5 @@ UNION: #tail
|
|||
#! We don't consider calls which do non-local exits to be
|
||||
#! tail calls, because this gives better error traces.
|
||||
node-stack get [
|
||||
node-successor dup #tail? swap #terminate? not and
|
||||
successor>> [ #tail? ] [ #terminate? not ] bi and
|
||||
] all? ;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
! Copyright (C) 2006, 2007 Slava Pestov.
|
||||
! Copyright (C) 2006, 2008 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
IN: inference.errors
|
||||
USING: inference.backend inference.dataflow kernel generic
|
||||
sequences prettyprint io words arrays inspector effects debugger
|
||||
assocs ;
|
||||
assocs accessors ;
|
||||
|
||||
M: inference-error error.
|
||||
dup inference-error-rstate
|
||||
dup rstate>>
|
||||
keys [ dup value? [ value-literal ] when ] map
|
||||
dup empty? [ "Word: " write dup peek . ] unless
|
||||
swap delegate error. "Nesting: " write . ;
|
||||
swap error>> error. "Nesting: " write . ;
|
||||
|
||||
M: inference-error error-help drop f ;
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ HELP: inference-error
|
|||
{ $error-description
|
||||
"Thrown by " { $link infer } " and " { $link dataflow } " when the stack effect of a quotation cannot be inferred."
|
||||
$nl
|
||||
"This error always delegates to one of the following classes of errors, which indicate the specific issue preventing a stack effect from being inferred:"
|
||||
"The " { $snippet "error" } " slot contains one of the following classes of errors, which indicate the specific issue preventing a stack effect from being inferred:"
|
||||
{ $list
|
||||
{ $link no-effect }
|
||||
{ $link literal-expected }
|
||||
|
|
|
@ -8,6 +8,9 @@ classes.predicate debugger threads.private io.streams.string
|
|||
io.timeouts io.thread sequences.private ;
|
||||
IN: inference.tests
|
||||
|
||||
[ ] [ [ 1 ] dataflow [ ] transform-nodes drop ] unit-test
|
||||
[ ] [ [ 1 2 3 ] dataflow [ ] transform-nodes drop ] unit-test
|
||||
|
||||
{ 0 2 } [ 2 "Hello" ] must-infer-as
|
||||
{ 1 2 } [ dup ] must-infer-as
|
||||
|
||||
|
@ -542,3 +545,5 @@ ERROR: custom-error ;
|
|||
: missing->r-check >r ;
|
||||
|
||||
[ [ missing->r-check ] infer ] must-fail
|
||||
|
||||
{ 1 0 } [ [ ] map-children ] must-infer-as
|
||||
|
|
|
@ -358,9 +358,7 @@ M: object infer-call
|
|||
|
||||
\ (directory) { string } { array } <effect> set-primitive-effect
|
||||
|
||||
\ data-gc { } { } <effect> set-primitive-effect
|
||||
|
||||
\ code-gc { } { } <effect> set-primitive-effect
|
||||
\ gc { } { } <effect> set-primitive-effect
|
||||
|
||||
\ gc-time { } { integer } <effect> set-primitive-effect
|
||||
|
||||
|
@ -596,3 +594,5 @@ set-primitive-effect
|
|||
\ dll-valid? { object } { object } <effect> set-primitive-effect
|
||||
|
||||
\ modify-code-heap { array object } { } <effect> set-primitive-effect
|
||||
|
||||
\ unimplemented { } { } <effect> set-primitive-effect
|
||||
|
|
|
@ -7,12 +7,15 @@ ARTICLE: "file-streams" "Reading and writing files"
|
|||
{ $subsection <file-reader> }
|
||||
{ $subsection <file-writer> }
|
||||
{ $subsection <file-appender> }
|
||||
"Reading and writing the entire contents of a file; this is only recommended for smaller files:"
|
||||
{ $subsection file-contents }
|
||||
{ $subsection set-file-contents }
|
||||
{ $subsection file-lines }
|
||||
{ $subsection set-file-lines }
|
||||
"Utility combinators:"
|
||||
{ $subsection with-file-reader }
|
||||
{ $subsection with-file-writer }
|
||||
{ $subsection with-file-appender }
|
||||
{ $subsection file-contents }
|
||||
{ $subsection file-lines } ;
|
||||
{ $subsection with-file-appender } ;
|
||||
|
||||
ARTICLE: "pathnames" "Pathname manipulation"
|
||||
"Pathname manipulation:"
|
||||
|
@ -27,11 +30,21 @@ ARTICLE: "pathnames" "Pathname manipulation"
|
|||
{ $subsection pathname }
|
||||
{ $subsection <pathname> } ;
|
||||
|
||||
ARTICLE: "symbolic-links" "Symbolic links"
|
||||
"Reading and creating links:"
|
||||
{ $subsection read-link }
|
||||
{ $subsection make-link }
|
||||
"Copying links:"
|
||||
{ $subsection copy-link }
|
||||
"Not all operating systems support symbolic links."
|
||||
{ $see-also link-info } ;
|
||||
|
||||
ARTICLE: "directories" "Directories"
|
||||
"Current and home directories:"
|
||||
{ $subsection cwd }
|
||||
{ $subsection cd }
|
||||
"Current directory:"
|
||||
{ $subsection current-directory }
|
||||
{ $subsection set-current-directory }
|
||||
{ $subsection with-directory }
|
||||
"Home directory:"
|
||||
{ $subsection home }
|
||||
"Directory listing:"
|
||||
{ $subsection directory }
|
||||
|
@ -40,18 +53,26 @@ ARTICLE: "directories" "Directories"
|
|||
{ $subsection make-directory }
|
||||
{ $subsection make-directories } ;
|
||||
|
||||
! ARTICLE: "file-types" "File Types"
|
||||
|
||||
! { $table { +directory+ "" } }
|
||||
|
||||
! ;
|
||||
|
||||
ARTICLE: "fs-meta" "File meta-data"
|
||||
ARTICLE: "file-types" "File Types"
|
||||
"Platform-independent types:"
|
||||
{ $subsection +regular-file+ }
|
||||
{ $subsection +directory+ }
|
||||
"Platform-specific types:"
|
||||
{ $subsection +character-device+ }
|
||||
{ $subsection +block-device+ }
|
||||
{ $subsection +fifo+ }
|
||||
{ $subsection +symbolic-link+ }
|
||||
{ $subsection +socket+ }
|
||||
{ $subsection +unknown+ } ;
|
||||
|
||||
ARTICLE: "fs-meta" "File metadata"
|
||||
"Querying file-system metadata:"
|
||||
{ $subsection file-info }
|
||||
{ $subsection link-info }
|
||||
{ $subsection exists? }
|
||||
{ $subsection directory? } ;
|
||||
{ $subsection directory? }
|
||||
"File types:"
|
||||
{ $subsection "file-types" } ;
|
||||
|
||||
ARTICLE: "delete-move-copy" "Deleting, moving, copying files"
|
||||
"Operations for deleting and copying files come in two forms:"
|
||||
|
@ -120,39 +141,40 @@ HELP: file-name
|
|||
! need a $class-description file-info
|
||||
|
||||
HELP: file-info
|
||||
|
||||
{ $values { "path" "a pathname string" }
|
||||
{ "info" file-info } }
|
||||
{ $description "Queries the file system for meta data. "
|
||||
"If path refers to a symbolic link, it is followed."
|
||||
"If the file does not exist, an exception is thrown." }
|
||||
|
||||
{ $class-description "File meta data" }
|
||||
|
||||
{ $table
|
||||
{ "type" { "One of the following:"
|
||||
{ $list { $link +regular-file+ }
|
||||
{ $link +directory+ }
|
||||
{ $link +symbolic-link+ } } } }
|
||||
|
||||
{ "size" "Size of the file in bytes" }
|
||||
{ "modified" "Last modification timestamp." } }
|
||||
|
||||
;
|
||||
|
||||
! need a see also to link-info
|
||||
{ $values { "path" "a pathname string" } { "info" file-info } }
|
||||
{ $description "Queries the file system for metadata. If " { $snippet "path" } " refers to a symbolic link, it is followed. See the article " { $link "file-types" } " for a list of metadata symbols." }
|
||||
{ $errors "Throws an error if the file does not exist." } ;
|
||||
|
||||
HELP: link-info
|
||||
{ $values { "path" "a pathname string" }
|
||||
{ "info" "a file-info tuple" } }
|
||||
{ $description "Queries the file system for meta data. "
|
||||
"If path refers to a symbolic link, information about "
|
||||
"the symbolic link itself is returned."
|
||||
"If the file does not exist, an exception is thrown." } ;
|
||||
! need a see also to file-info
|
||||
{ $values { "path" "a pathname string" } { "info" "a file-info tuple" } }
|
||||
{ $description "Queries the file system for metadata. If path refers to a symbolic link, information about the symbolic link itself is returned. If the file does not exist, an exception is thrown." } ;
|
||||
|
||||
{ file-info link-info } related-words
|
||||
|
||||
HELP: +regular-file+
|
||||
{ $description "A regular file. This type exists on all platforms. See " { $link "file-streams" } " for words operating on files." } ;
|
||||
|
||||
HELP: +directory+
|
||||
{ $description "A directory. This type exists on all platforms. See " { $link "directories" } " for words operating on directories." } ;
|
||||
|
||||
HELP: +symbolic-link+
|
||||
{ $description "A symbolic link file. This type is currently implemented on Unix platforms only. See " { $link "symbolic-links" } " for words operating on symbolic links." } ;
|
||||
|
||||
HELP: +character-device+
|
||||
{ $description "A Unix character device file. This type exists on unix platforms only." } ;
|
||||
|
||||
HELP: +block-device+
|
||||
{ $description "A Unix block device file. This type exists on unix platforms only." } ;
|
||||
|
||||
HELP: +fifo+
|
||||
{ $description "A Unix fifo file. This type exists on unix platforms only." } ;
|
||||
|
||||
HELP: +socket+
|
||||
{ $description "A Unix socket file. This type exists on unix platforms only." } ;
|
||||
|
||||
HELP: +unknown+
|
||||
{ $description "A unknown file type." } ;
|
||||
|
||||
HELP: <file-reader>
|
||||
{ $values { "path" "a pathname string" } { "encoding" "an encoding descriptor" { "stream" "an input stream" } }
|
||||
{ "stream" "an input stream" } }
|
||||
|
@ -184,37 +206,73 @@ HELP: with-file-appender
|
|||
{ $description "Opens a file for appending using the given encoding and calls the quotation using " { $link with-stream } "." }
|
||||
{ $errors "Throws an error if the file cannot be opened for writing." } ;
|
||||
|
||||
HELP: set-file-lines
|
||||
{ $values { "seq" "an array of strings" } { "path" "a pathname string" } { "encoding" "an encoding descriptor" } }
|
||||
{ $description "Sets the contents of a file to the strings with the given encoding." }
|
||||
{ $errors "Throws an error if the file cannot be opened for writing." } ;
|
||||
|
||||
HELP: file-lines
|
||||
{ $values { "path" "a pathname string" } { "encoding" "an encoding descriptor" } { "seq" "an array of strings" } }
|
||||
{ $description "Opens the file at the given path using the given encoding, and returns a list of the lines in that file." }
|
||||
{ $errors "Throws an error if the file cannot be opened for reading." } ;
|
||||
|
||||
HELP: set-file-contents
|
||||
{ $values { "str" "a string" } { "path" "a pathname string" } { "encoding" "an encoding descriptor" } }
|
||||
{ $description "Sets the contents of a file to a string with the given encoding." }
|
||||
{ $errors "Throws an error if the file cannot be opened for writing." } ;
|
||||
|
||||
HELP: file-contents
|
||||
{ $values { "path" "a pathname string" } { "encoding" "an encoding descriptor" } { "str" "a string" } }
|
||||
{ $description "Opens the file at the given path using the given encoding, and the contents of that file as a string." }
|
||||
{ $errors "Throws an error if the file cannot be opened for writing." } ;
|
||||
{ $errors "Throws an error if the file cannot be opened for reading." } ;
|
||||
|
||||
{ set-file-lines file-lines set-file-contents file-contents } related-words
|
||||
|
||||
HELP: cwd
|
||||
{ $values { "path" "a pathname string" } }
|
||||
{ $description "Outputs the current working directory of the Factor process." }
|
||||
{ $errors "Windows CE has no concept of ``current directory'', so this word throws an error there." } ;
|
||||
{ $errors "Windows CE has no concept of ``current directory'', so this word throws an error there." }
|
||||
{ $notes "User code should use " { $link with-directory } " or " { $link set-current-directory } " instead." } ;
|
||||
|
||||
HELP: cd
|
||||
{ $values { "path" "a pathname string" } }
|
||||
{ $description "Changes the current working directory of the Factor process." }
|
||||
{ $errors "Windows CE has no concept of ``current directory'', so this word throws an error there." } ;
|
||||
{ $errors "Windows CE has no concept of ``current directory'', so this word throws an error there." }
|
||||
{ $notes "User code should use " { $link with-directory } " or " { $link set-current-directory } " instead." } ;
|
||||
|
||||
{ cd cwd with-directory } related-words
|
||||
{ cd cwd current-directory set-current-directory with-directory } related-words
|
||||
|
||||
HELP: current-directory
|
||||
{ $description "A variable holding the current directory. Words that use the filesystem do so in relation to this variable. On startup, an init hook sets this word to the directory from which Factor was run." } ;
|
||||
|
||||
HELP: with-directory
|
||||
{ $values { "path" "a pathname string" } { "quot" quotation } }
|
||||
{ $description "Changes the current working directory for the duration of a quotation's execution." }
|
||||
{ $errors "Windows CE has no concept of ``current directory'', so this word throws an error there." } ;
|
||||
{ $description "Changes the " { $link current-directory } " variable for the duration of a quotation's execution. Words that use the file-system should call " { $link normalize-path } " in order to obtain a path relative to the current directory." } ;
|
||||
|
||||
HELP: append-path
|
||||
{ $values { "str1" "a string" } { "str2" "a string" } { "str" "a string" } }
|
||||
{ $description "Concatenates two pathnames." } ;
|
||||
|
||||
HELP: prepend-path
|
||||
{ $values { "str1" "a string" } { "str2" "a string" } { "str" "a string" } }
|
||||
{ $description "Concatenates two pathnames." } ;
|
||||
|
||||
{ append-path prepend-path } related-words
|
||||
|
||||
HELP: absolute-path?
|
||||
{ $values { "path" "a pathname string" } { "?" "a boolean" } }
|
||||
{ $description "Tests if a pathname is absolute. Examples of absolute pathnames are " { $snippet "/foo/bar" } " on Unix and " { $snippet "c:\\foo\\bar" } " on Windows." } ;
|
||||
|
||||
HELP: windows-absolute-path?
|
||||
{ $values { "path" "a pathname string" } { "?" "a boolean" } }
|
||||
{ $description "Tests if a pathname is absolute on Windows. Examples of absolute pathnames on Windows are " { $snippet "c:\\foo\\bar" } " and " { $snippet "\\\\?\\c:\\foo\\bar" } " for absolute Unicode pathnames." } ;
|
||||
|
||||
HELP: root-directory?
|
||||
{ $values { "path" "a pathname string" } { "?" "a boolean" } }
|
||||
{ $description "Tests if a pathname is a root directory. Examples of root directory pathnames are " { $snippet "/" } " on Unix and " { $snippet "c:\\" } " on Windows." } ;
|
||||
|
||||
{ absolute-path? windows-absolute-path? root-directory? } related-words
|
||||
|
||||
HELP: exists?
|
||||
{ $values { "path" "a pathname string" } { "?" "a boolean" } }
|
||||
{ $description "Tests if the file named by " { $snippet "path" } " exists." } ;
|
||||
|
@ -260,6 +318,20 @@ HELP: <pathname> ( str -- pathname )
|
|||
{ $values { "str" "a pathname string" } { "pathname" pathname } }
|
||||
{ $description "Creates a new " { $link pathname } "." } ;
|
||||
|
||||
HELP: make-link
|
||||
{ $values { "target" "a path to the symbolic link's target" } { "symlink" "a path to new symbolic link" } }
|
||||
{ $description "Creates a symbolic link." } ;
|
||||
|
||||
HELP: read-link
|
||||
{ $values { "symlink" "a path to an existing symbolic link" } { "path" "the path pointed to by the symbolic link" } }
|
||||
{ $description "Reads the symbolic link and returns its target path." } ;
|
||||
|
||||
HELP: copy-link
|
||||
{ $values { "target" "a path to an existing symlink" } { "symlink" "a path to a new symbolic link" } }
|
||||
{ $description "Copies a symbolic link without following the link." } ;
|
||||
|
||||
{ make-link read-link copy-link } related-words
|
||||
|
||||
HELP: home
|
||||
{ $values { "dir" string } }
|
||||
{ $description "Outputs the user's home directory." } ;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
IN: io.files.tests
|
||||
USING: tools.test io.files io threads kernel continuations
|
||||
io.encodings.ascii io.files.unique sequences strings accessors
|
||||
io.encodings.utf8 ;
|
||||
USING: tools.test io.files io.files.private io threads kernel
|
||||
continuations io.encodings.ascii io.files.unique sequences
|
||||
strings accessors io.encodings.utf8 ;
|
||||
|
||||
[ ] [ "blahblah" temp-file dup exists? [ delete-directory ] [ drop ] if ] unit-test
|
||||
[ ] [ "blahblah" temp-file make-directory ] unit-test
|
||||
|
|
|
@ -153,19 +153,19 @@ HOOK: file-info io-backend ( path -- info )
|
|||
! Symlinks
|
||||
HOOK: link-info io-backend ( path -- info )
|
||||
|
||||
HOOK: make-link io-backend ( path1 path2 -- )
|
||||
HOOK: make-link io-backend ( target symlink -- )
|
||||
|
||||
HOOK: read-link io-backend ( path -- info )
|
||||
HOOK: read-link io-backend ( symlink -- path )
|
||||
|
||||
: copy-link ( path1 path2 -- )
|
||||
: copy-link ( target symlink -- )
|
||||
>r read-link r> make-link ;
|
||||
|
||||
SYMBOL: +regular-file+
|
||||
SYMBOL: +directory+
|
||||
SYMBOL: +symbolic-link+
|
||||
SYMBOL: +character-device+
|
||||
SYMBOL: +block-device+
|
||||
SYMBOL: +fifo+
|
||||
SYMBOL: +symbolic-link+
|
||||
SYMBOL: +socket+
|
||||
SYMBOL: +unknown+
|
||||
|
||||
|
@ -176,15 +176,18 @@ SYMBOL: +unknown+
|
|||
: directory? ( path -- ? )
|
||||
file-info file-info-type +directory+ = ;
|
||||
|
||||
! Current working directory
|
||||
<PRIVATE
|
||||
|
||||
HOOK: cd io-backend ( path -- )
|
||||
|
||||
HOOK: cwd io-backend ( -- path )
|
||||
|
||||
SYMBOL: current-directory
|
||||
|
||||
M: object cwd ( -- path ) "." ;
|
||||
|
||||
PRIVATE>
|
||||
|
||||
SYMBOL: current-directory
|
||||
|
||||
[ cwd current-directory set-global ] "io.files" add-init-hook
|
||||
|
||||
: resource-path ( path -- newpath )
|
||||
|
@ -202,12 +205,11 @@ M: object cwd ( -- path ) "." ;
|
|||
M: object normalize-path ( path -- path' )
|
||||
(normalize-path) ;
|
||||
|
||||
: with-directory ( path quot -- )
|
||||
>r (normalize-path) r>
|
||||
current-directory swap with-variable ; inline
|
||||
|
||||
: set-current-directory ( path -- )
|
||||
normalize-path current-directory set ;
|
||||
(normalize-path) current-directory set ;
|
||||
|
||||
: with-directory ( path quot -- )
|
||||
>r (normalize-path) current-directory r> with-variable ; inline
|
||||
|
||||
! Creating directories
|
||||
HOOK: make-directory io-backend ( path -- )
|
||||
|
|
|
@ -10,7 +10,7 @@ ARTICLE: "io.streams.duplex" "Duplex streams"
|
|||
ABOUT: "io.streams.duplex"
|
||||
|
||||
HELP: duplex-stream
|
||||
{ $class-description "A bidirectional stream delegating to a pair of streams, sending input to one delegate and output to another." } ;
|
||||
{ $class-description "A bidirectional stream wrapping an input and output stream." } ;
|
||||
|
||||
HELP: <duplex-stream>
|
||||
{ $values { "in" "an input stream" } { "out" "an output stream" } { "stream" " a duplex stream" } }
|
||||
|
|
|
@ -1,30 +1,59 @@
|
|||
! Copyright (C) 2006, 2008 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
IN: io.streams.nested
|
||||
USING: arrays generic assocs kernel namespaces strings
|
||||
quotations io continuations ;
|
||||
quotations io continuations accessors sequences ;
|
||||
IN: io.streams.nested
|
||||
|
||||
TUPLE: ignore-close-stream ;
|
||||
TUPLE: filter-writer stream ;
|
||||
|
||||
: <ignore-close-stream> ignore-close-stream construct-delegate ;
|
||||
M: filter-writer stream-format
|
||||
stream>> stream-format ;
|
||||
|
||||
M: filter-writer stream-write
|
||||
stream>> stream-write ;
|
||||
|
||||
M: filter-writer stream-write1
|
||||
stream>> stream-write1 ;
|
||||
|
||||
M: filter-writer make-span-stream
|
||||
stream>> make-span-stream ;
|
||||
|
||||
M: filter-writer make-block-stream
|
||||
stream>> make-block-stream ;
|
||||
|
||||
M: filter-writer make-cell-stream
|
||||
stream>> make-cell-stream ;
|
||||
|
||||
M: filter-writer stream-flush
|
||||
stream>> stream-flush ;
|
||||
|
||||
M: filter-writer stream-nl
|
||||
stream>> stream-nl ;
|
||||
|
||||
M: filter-writer stream-write-table
|
||||
stream>> stream-write-table ;
|
||||
|
||||
M: filter-writer dispose
|
||||
stream>> dispose ;
|
||||
|
||||
TUPLE: ignore-close-stream < filter-writer ;
|
||||
|
||||
M: ignore-close-stream dispose drop ;
|
||||
|
||||
TUPLE: style-stream style ;
|
||||
C: <ignore-close-stream> ignore-close-stream
|
||||
|
||||
: do-nested-style ( style stream -- style delegate )
|
||||
[ style-stream-style swap union ] keep
|
||||
delegate ; inline
|
||||
TUPLE: style-stream < filter-writer style ;
|
||||
|
||||
: <style-stream> ( style delegate -- stream )
|
||||
{ set-style-stream-style set-delegate }
|
||||
style-stream construct ;
|
||||
: do-nested-style ( style style-stream -- style stream )
|
||||
[ style>> swap union ] [ stream>> ] bi ; inline
|
||||
|
||||
C: <style-stream> style-stream
|
||||
|
||||
M: style-stream stream-format
|
||||
do-nested-style stream-format ;
|
||||
|
||||
M: style-stream stream-write
|
||||
dup style-stream-style swap delegate stream-format ;
|
||||
[ style>> ] [ stream>> ] bi stream-format ;
|
||||
|
||||
M: style-stream stream-write1
|
||||
>r 1string r> stream-write ;
|
||||
|
@ -33,15 +62,13 @@ M: style-stream make-span-stream
|
|||
do-nested-style make-span-stream ;
|
||||
|
||||
M: style-stream make-block-stream
|
||||
[ do-nested-style make-block-stream ] keep
|
||||
style-stream-style swap <style-stream> ;
|
||||
[ do-nested-style make-block-stream ] [ style>> ] bi
|
||||
<style-stream> ;
|
||||
|
||||
M: style-stream make-cell-stream
|
||||
[ do-nested-style make-cell-stream ] keep
|
||||
style-stream-style swap <style-stream> ;
|
||||
[ do-nested-style make-cell-stream ] [ style>> ] bi
|
||||
<style-stream> ;
|
||||
|
||||
TUPLE: block-stream ;
|
||||
|
||||
: <block-stream> block-stream construct-delegate ;
|
||||
|
||||
M: block-stream dispose drop ;
|
||||
M: style-stream stream-write-table
|
||||
[ [ [ stream>> ] map ] map ] [ ] [ stream>> ] tri*
|
||||
stream-write-table ;
|
||||
|
|
|
@ -12,7 +12,7 @@ M: plain-writer stream-format
|
|||
nip stream-write ;
|
||||
|
||||
M: plain-writer make-span-stream
|
||||
<style-stream> <ignore-close-stream> ;
|
||||
swap <style-stream> <ignore-close-stream> ;
|
||||
|
||||
M: plain-writer make-block-stream
|
||||
nip <ignore-close-stream> ;
|
||||
|
|
|
@ -13,7 +13,7 @@ ABOUT: "io.streams.string"
|
|||
|
||||
HELP: <string-writer>
|
||||
{ $values { "stream" "an output stream" } }
|
||||
{ $description "Creates an output stream that collects text into a delegate string buffer. The contents of the buffer can be recovered by executing " { $link >string } ", and indeed all other sequence operations are permitted by virtue of the delegation." } ;
|
||||
{ $description "Creates an output stream that collects text into a string buffer. The contents of the buffer can be obtained by executing " { $link >string } "." } ;
|
||||
|
||||
HELP: with-string-writer
|
||||
{ $values { "quot" quotation } { "str" string } }
|
||||
|
|
|
@ -217,9 +217,7 @@ $nl
|
|||
{ $example "\\ f class ." "word" }
|
||||
"On the other hand, " { $link t } " is just a word, and there is no class which it is a unique instance of."
|
||||
{ $example "t \\ t eq? ." "t" }
|
||||
"Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "."
|
||||
$nl
|
||||
"A tuple cannot delegate to " { $link f } " at all, since a delegate of " { $link f } " actually denotes that no delegate is set. See " { $link set-delegate } "." ;
|
||||
"Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "." ;
|
||||
|
||||
ARTICLE: "conditionals" "Conditionals and logic"
|
||||
"The basic conditionals:"
|
||||
|
@ -276,9 +274,11 @@ ARTICLE: "dataflow" "Data and control flow"
|
|||
{ $subsection "apply-combinators" }
|
||||
{ $subsection "slip-keep-combinators" }
|
||||
{ $subsection "conditionals" }
|
||||
{ $subsection "compositional-combinators" }
|
||||
{ $subsection "combinators" }
|
||||
"Advanced topics:"
|
||||
{ $subsection "implementing-combinators" }
|
||||
{ $subsection "errors" }
|
||||
{ $subsection "continuations" } ;
|
||||
|
||||
ABOUT: "dataflow"
|
||||
|
@ -341,6 +341,9 @@ HELP: set-callstack ( cs -- )
|
|||
HELP: clear
|
||||
{ $description "Clears the data stack." } ;
|
||||
|
||||
HELP: build
|
||||
{ $description "The current build number. Factor increments this number whenever a new boot image is created." } ;
|
||||
|
||||
HELP: hashcode*
|
||||
{ $values { "depth" integer } { "obj" object } { "code" fixnum } }
|
||||
{ $contract "Outputs the hashcode of an object. The hashcode operation must satisfy the following properties:"
|
||||
|
@ -393,7 +396,7 @@ HELP: identity-tuple
|
|||
HELP: <=>
|
||||
{ $values { "obj1" object } { "obj2" object } { "n" real } }
|
||||
{ $contract
|
||||
"Compares two objects using an intrinsic partial order, for example, the natural order for real numbers and lexicographic order for strings."
|
||||
"Compares two objects using an intrinsic total order, for example, the natural order for real numbers and lexicographic order for strings."
|
||||
$nl
|
||||
"The output value is one of the following:"
|
||||
{ $list
|
||||
|
@ -846,11 +849,15 @@ HELP: with
|
|||
{ $example "USING: kernel math prettyprint sequences ;" "2 { 1 2 3 } [ - ] with map ." "{ 1 0 -1 }" }
|
||||
} ;
|
||||
|
||||
HELP: compose
|
||||
{ $values { "quot1" callable } { "quot2" callable } { "curry" curry } }
|
||||
HELP: compose ( quot1 quot2 -- compose )
|
||||
{ $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
|
||||
{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } " followed by " { $snippet "quot2" } "." }
|
||||
{ $notes
|
||||
"The following two lines are equivalent:"
|
||||
"The two quotations must leave the retain stack in the same state on exit as it was on entry, so the following code is not allowed:"
|
||||
{ $code
|
||||
"[ 3 >r ] [ r> . ] compose"
|
||||
}
|
||||
"Except for this restriction, the following two lines are equivalent:"
|
||||
{ $code
|
||||
"compose call"
|
||||
"append call"
|
||||
|
@ -862,7 +869,15 @@ HELP: 3compose
|
|||
{ $values { "quot1" callable } { "quot2" callable } { "quot3" callable } { "curry" curry } }
|
||||
{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } ", " { $snippet "quot2" } " and then " { $snippet "quot3" } "." }
|
||||
{ $notes
|
||||
"The following two lines are equivalent:"
|
||||
"The three quotations must leave the retain stack in the same state on exit as it was on entry, so for example, the following code is not allowed:"
|
||||
{ $code
|
||||
"[ >r ] swap [ r> ] 3compose"
|
||||
}
|
||||
"The correct way to achieve the effect of the above is the following:"
|
||||
{ $code
|
||||
"[ dip ] curry"
|
||||
}
|
||||
"Excepting the retain stack restriction, the following two lines are equivalent:"
|
||||
{ $code
|
||||
"3compose call"
|
||||
"3append call"
|
||||
|
|
|
@ -108,3 +108,12 @@ IN: kernel.tests
|
|||
H{ } values swap >r dup length swap r> 0 -roll (loop) ;
|
||||
|
||||
[ loop ] must-fail
|
||||
|
||||
! Discovered on Windows
|
||||
: total-failure-1 "" [ ] map unimplemented ;
|
||||
|
||||
[ total-failure-1 ] must-fail
|
||||
|
||||
: total-failure-2 [ ] (call) unimplemented ;
|
||||
|
||||
[ total-failure-2 ] must-fail
|
||||
|
|
|
@ -118,6 +118,8 @@ GENERIC: hashcode* ( depth obj -- code )
|
|||
|
||||
M: object hashcode* 2drop 0 ;
|
||||
|
||||
M: f hashcode* 2drop 31337 ;
|
||||
|
||||
: hashcode ( obj -- code ) 3 swap hashcode* ; inline
|
||||
|
||||
GENERIC: equal? ( obj1 obj2 -- ? )
|
||||
|
@ -194,12 +196,8 @@ M: callstack clone (clone) ;
|
|||
PRIVATE>
|
||||
|
||||
! Deprecated
|
||||
GENERIC: delegate ( obj -- delegate )
|
||||
|
||||
M: object delegate drop f ;
|
||||
|
||||
GENERIC: set-delegate ( delegate tuple -- )
|
||||
|
||||
GENERIC# get-slots 1 ( tuple slots -- ... )
|
||||
|
||||
GENERIC# set-slots 1 ( ... tuple slots -- )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
USING: generic help.markup help.syntax kernel math
|
||||
memory namespaces sequences kernel.private classes
|
||||
sequences.private ;
|
||||
classes.builtin sequences.private ;
|
||||
IN: layouts
|
||||
|
||||
HELP: tag-bits
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
USING: arrays hashtables io kernel math math.parser memory
|
||||
namespaces parser sequences strings io.styles
|
||||
io.streams.duplex vectors words generic system combinators
|
||||
continuations debugger definitions compiler.units ;
|
||||
continuations debugger definitions compiler.units accessors ;
|
||||
IN: listener
|
||||
|
||||
SYMBOL: quit-flag
|
||||
|
@ -19,7 +19,7 @@ GENERIC: stream-read-quot ( stream -- quot/f )
|
|||
|
||||
: read-quot-step ( lines -- quot/f )
|
||||
[ parse-lines-interactive ] [
|
||||
dup delegate unexpected-eof?
|
||||
dup error>> unexpected-eof?
|
||||
[ 2drop f ] [ rethrow ] if
|
||||
] recover ;
|
||||
|
||||
|
|
|
@ -83,6 +83,29 @@ HELP: >=
|
|||
{ $values { "x" real } { "y" real } { "?" "a boolean" } }
|
||||
{ $description "Tests if " { $snippet "x" } " is greater than or equal to " { $snippet "y" } "." } ;
|
||||
|
||||
HELP: before?
|
||||
{ $values { "obj1" "an object" } { "obj2" "an object" } { "?" "a boolean" } }
|
||||
{ $description "Tests if " { $snippet "obj1" } " comes before " { $snippet "obj2" } " using an intrinsic total order." }
|
||||
{ $notes "Implemented using " { $link <=> } "." } ;
|
||||
|
||||
HELP: after?
|
||||
{ $values { "obj1" "an object" } { "obj2" "an object" } { "?" "a boolean" } }
|
||||
{ $description "Tests if " { $snippet "obj1" } " comes after " { $snippet "obj2" } " using an intrinsic total order." }
|
||||
{ $notes "Implemented using " { $link <=> } "." } ;
|
||||
|
||||
HELP: before=?
|
||||
{ $values { "obj1" "an object" } { "obj2" "an object" } { "?" "a boolean" } }
|
||||
{ $description "Tests if " { $snippet "obj1" } " comes before or equals " { $snippet "obj2" } " using an intrinsic total order." }
|
||||
{ $notes "Implemented using " { $link <=> } "." } ;
|
||||
|
||||
HELP: after=?
|
||||
{ $values { "obj1" "an object" } { "obj2" "an object" } { "?" "a boolean" } }
|
||||
{ $description "Tests if " { $snippet "obj1" } " comes after or equals " { $snippet "obj2" } " using an intrinsic total order." }
|
||||
{ $notes "Implemented using " { $link <=> } "." } ;
|
||||
|
||||
{ before? after? before=? after=? } related-words
|
||||
|
||||
|
||||
HELP: +
|
||||
{ $values { "x" number } { "y" number } { "z" number } }
|
||||
{ $description
|
||||
|
|
|
@ -37,12 +37,9 @@ HELP: instances
|
|||
{ $description "Outputs a sequence of all objects in the heap which satisfy the quotation." }
|
||||
{ $notes "This word relies on " { $link each-object } ", so in particular the garbage collector is switched off while it runs and the given quotation must not allocate too much memory." } ;
|
||||
|
||||
HELP: data-gc ( -- )
|
||||
HELP: gc ( -- )
|
||||
{ $description "Performs a full garbage collection." } ;
|
||||
|
||||
HELP: code-gc ( -- )
|
||||
{ $description "Collects all generations up to and including tenured space, and also collects the code heap." } ;
|
||||
|
||||
HELP: gc-time ( -- n )
|
||||
{ $values { "n" "a timestamp in milliseconds" } }
|
||||
{ $description "Outputs the total time spent in garbage collection during this Factor session." } ;
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
USING: generic kernel kernel.private math memory prettyprint
|
||||
sequences tools.test words namespaces layouts classes ;
|
||||
sequences tools.test words namespaces layouts classes
|
||||
classes.builtin arrays quotations ;
|
||||
IN: memory.tests
|
||||
|
||||
! Code GC wasn't kicking in when needed
|
||||
: leak-step 800000 f <array> 1quotation call drop ;
|
||||
|
||||
: leak-loop 100 [ leak-step ] times ;
|
||||
|
||||
[ ] [ leak-loop ] unit-test
|
||||
|
||||
TUPLE: testing x y z ;
|
||||
|
||||
[ save-image-and-exit ] must-fail
|
||||
|
|
|
@ -51,7 +51,7 @@ GENERIC: optimize-node* ( node -- node/t changed? )
|
|||
DEFER: optimize-nodes
|
||||
|
||||
: optimize-children ( node -- )
|
||||
[ optimize-nodes ] change-children ;
|
||||
[ optimize-nodes ] map-children ;
|
||||
|
||||
: optimize-node ( node -- node )
|
||||
dup [
|
||||
|
|
|
@ -100,7 +100,7 @@ M: #r> kill-node* [ node-in-r empty? ] prune-if ;
|
|||
dup [
|
||||
dup [ dead-literals get swap remove-all ] modify-values
|
||||
dup kill-node* dup t eq? [
|
||||
drop dup [ kill-nodes ] change-children
|
||||
drop dup [ kill-nodes ] map-children
|
||||
] [
|
||||
nip kill-node
|
||||
] if
|
||||
|
|
|
@ -140,12 +140,6 @@ GENERIC: void-generic ( obj -- * )
|
|||
[ breakage ] must-fail
|
||||
|
||||
! regression
|
||||
: test-0 ( n -- ) dup 0 = [ drop ] [ 1- test-0 ] if ; inline
|
||||
: test-1 ( n -- ) t [ test-0 ] [ delegate dup [ test-1 ] [ drop ] if ] if ; inline
|
||||
: test-2 ( -- ) 5 test-1 ;
|
||||
|
||||
[ f ] [ f test-2 ] unit-test
|
||||
|
||||
: branch-fold-regression-0 ( m -- n )
|
||||
t [ ] [ 1+ branch-fold-regression-0 ] if ; inline
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
USING: help.markup help.syntax kernel sequences words
|
||||
math strings vectors quotations generic effects classes
|
||||
vocabs.loader definitions io vocabs source-files
|
||||
quotations namespaces compiler.units ;
|
||||
quotations namespaces compiler.units assocs ;
|
||||
IN: parser
|
||||
|
||||
ARTICLE: "vocabulary-search-shadow" "Shadowing word names"
|
||||
|
@ -284,10 +284,6 @@ HELP: use
|
|||
HELP: in
|
||||
{ $var-description "A variable holding the name of the current vocabulary for new definitions." } ;
|
||||
|
||||
HELP: shadow-warnings
|
||||
{ $values { "vocab" "an assoc mapping strings to words" } { "vocabs" "a sequence of assocs" } }
|
||||
{ $description "Tests if any keys in " { $snippet "vocab" } " shadow keys in the elements of " { $snippet "vocabs" } ", and if so, prints a warning message. These warning messages can be disabled by setting " { $link parser-notes } " to " { $link f } "." } ;
|
||||
|
||||
HELP: (use+)
|
||||
{ $values { "vocab" "an assoc mapping strings to words" } }
|
||||
{ $description "Adds an assoc at the front of the search path." }
|
||||
|
@ -445,17 +441,9 @@ HELP: eval
|
|||
{ $description "Parses Factor source code from a string, and calls the resulting quotation." }
|
||||
{ $errors "Throws an error if the input is malformed, or if the evaluation itself throws an error." } ;
|
||||
|
||||
HELP: outside-usages
|
||||
{ $values { "seq" "a sequence of definitions" } { "usages" "an association list mapping definitions to sequences of definitions" } }
|
||||
{ $description "Outputs an association list mapping elements of " { $snippet "seq" } " to lists of usages which exclude the definitions in " { $snippet "seq" } " themselves." } ;
|
||||
|
||||
HELP: filter-moved
|
||||
{ $values { "assoc" "an assoc where the keys are definitions" } { "newassoc" "an assoc where the keys are definitions" } }
|
||||
{ $description "Removes all definitions from the assoc which are no longer present in the current " { $link file } "." } ;
|
||||
|
||||
HELP: smudged-usage
|
||||
{ $values { "usages" "a sequence of definitions which reference removed definitions" } { "referenced" "a sequence of definitions removed from this source file which are still referenced elsewhere" } { "removed" "a sequence of definitions removed from this source file" } }
|
||||
{ $description "Collects information about changed word definitioins after parsing." } ;
|
||||
{ $values { "assoc1" assoc } { "assoc2" assoc } { "seq" "an seqence of definitions" } }
|
||||
{ $description "Removes all definitions from " { $snippet "assoc2" } " which are in " { $snippet "assoc1" } " or are are no longer present in the current " { $link file } "." } ;
|
||||
|
||||
HELP: forget-smudged
|
||||
{ $description "Forgets removed definitions and prints a warning message if any of them are still referenced from other source files." } ;
|
||||
|
|
|
@ -2,7 +2,7 @@ USING: arrays math parser tools.test kernel generic words
|
|||
io.streams.string namespaces classes effects source-files
|
||||
assocs sequences strings io.files definitions continuations
|
||||
sorting classes.tuple compiler.units debugger vocabs
|
||||
vocabs.loader ;
|
||||
vocabs.loader accessors ;
|
||||
IN: parser.tests
|
||||
|
||||
[
|
||||
|
@ -297,12 +297,12 @@ IN: parser.tests
|
|||
[
|
||||
"IN: parser.tests TUPLE: another-pred-test ; GENERIC: another-pred-test?"
|
||||
<string-reader> "removing-the-predicate" parse-stream
|
||||
] [ [ redefine-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> redefine-error? ] must-fail-with
|
||||
|
||||
[
|
||||
"IN: parser.tests TUPLE: class-redef-test ; TUPLE: class-redef-test ;"
|
||||
<string-reader> "redefining-a-class-1" parse-stream
|
||||
] [ [ redefine-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> redefine-error? ] must-fail-with
|
||||
|
||||
[ ] [
|
||||
"IN: parser.tests TUPLE: class-redef-test ; SYMBOL: class-redef-test"
|
||||
|
@ -312,7 +312,7 @@ IN: parser.tests
|
|||
[
|
||||
"IN: parser.tests TUPLE: class-redef-test ; SYMBOL: class-redef-test : class-redef-test ;"
|
||||
<string-reader> "redefining-a-class-3" parse-stream drop
|
||||
] [ [ redefine-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> redefine-error? ] must-fail-with
|
||||
|
||||
[ ] [
|
||||
"IN: parser.tests TUPLE: class-fwd-test ;"
|
||||
|
@ -322,7 +322,7 @@ IN: parser.tests
|
|||
[
|
||||
"IN: parser.tests \\ class-fwd-test"
|
||||
<string-reader> "redefining-a-class-3" parse-stream drop
|
||||
] [ [ no-word-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> no-word-error? ] must-fail-with
|
||||
|
||||
[ ] [
|
||||
"IN: parser.tests TUPLE: class-fwd-test ; SYMBOL: class-fwd-test"
|
||||
|
@ -332,12 +332,12 @@ IN: parser.tests
|
|||
[
|
||||
"IN: parser.tests \\ class-fwd-test"
|
||||
<string-reader> "redefining-a-class-3" parse-stream drop
|
||||
] [ [ no-word-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> no-word-error? ] must-fail-with
|
||||
|
||||
[
|
||||
"IN: parser.tests : foo ; TUPLE: foo ;"
|
||||
<string-reader> "redefining-a-class-4" parse-stream drop
|
||||
] [ [ redefine-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> redefine-error? ] must-fail-with
|
||||
|
||||
[ ] [
|
||||
"IN: parser.tests : foo ( x y -- z ) 1 2 ; : bar ( a -- b ) ;" eval
|
||||
|
@ -348,47 +348,6 @@ IN: parser.tests
|
|||
] must-fail
|
||||
] with-file-vocabs
|
||||
|
||||
[
|
||||
<< file get parsed >> file set
|
||||
|
||||
: ~a ;
|
||||
|
||||
DEFER: ~b
|
||||
|
||||
"IN: parser.tests : ~b ~a ;" <string-reader>
|
||||
"smudgy" parse-stream drop
|
||||
|
||||
: ~c ;
|
||||
: ~d ;
|
||||
|
||||
{ H{ { ~a ~a } { ~b ~b } { ~c ~c } { ~d ~d } } H{ } } old-definitions set
|
||||
|
||||
{ H{ { ~b ~b } { ~d ~d } } H{ } } new-definitions set
|
||||
|
||||
[ V{ ~b } { ~a } { ~a ~c } ] [
|
||||
smudged-usage
|
||||
natural-sort
|
||||
] unit-test
|
||||
] with-scope
|
||||
|
||||
[
|
||||
<< file get parsed >> file set
|
||||
|
||||
GENERIC: ~e
|
||||
|
||||
: ~f ~e ;
|
||||
|
||||
: ~g ;
|
||||
|
||||
{ H{ { ~e ~e } { ~f ~f } { ~g ~g } } H{ } } old-definitions set
|
||||
|
||||
{ H{ { ~g ~g } } H{ } } new-definitions set
|
||||
|
||||
[ V{ } { } { ~e ~f } ]
|
||||
[ smudged-usage natural-sort ]
|
||||
unit-test
|
||||
] with-scope
|
||||
|
||||
[ ] [
|
||||
"IN: parser.tests USE: kernel PREDICATE: foo < object ( x -- y ) ;" eval
|
||||
] unit-test
|
||||
|
|
|
@ -157,23 +157,33 @@ name>char-hook global [
|
|||
[ swap tail-slice (parse-string) ] "" make swap
|
||||
] change-lexer-column ;
|
||||
|
||||
TUPLE: parse-error file line col text ;
|
||||
TUPLE: parse-error file line column line-text error ;
|
||||
|
||||
: <parse-error> ( msg -- error )
|
||||
file get
|
||||
lexer get [ line>> ] [ column>> ] [ line-text>> ] tri
|
||||
parse-error construct-boa
|
||||
[ set-delegate ] keep ;
|
||||
\ parse-error construct-empty
|
||||
file get >>file
|
||||
lexer get line>> >>line
|
||||
lexer get column>> >>column
|
||||
lexer get line-text>> >>line-text
|
||||
swap >>error ;
|
||||
|
||||
: parse-dump ( error -- )
|
||||
dup parse-error-file file.
|
||||
dup parse-error-line number>string print
|
||||
dup parse-error-text dup string? [ print ] [ drop ] if
|
||||
parse-error-col 0 or CHAR: \s <string> write
|
||||
{
|
||||
[ file>> file. ]
|
||||
[ line>> number>string print ]
|
||||
[ line-text>> dup string? [ print ] [ drop ] if ]
|
||||
[ column>> 0 or CHAR: \s <string> write ]
|
||||
} cleave
|
||||
"^" print ;
|
||||
|
||||
M: parse-error error.
|
||||
dup parse-dump delegate error. ;
|
||||
[ parse-dump ] [ error>> error. ] bi ;
|
||||
|
||||
M: parse-error summary
|
||||
error>> summary ;
|
||||
|
||||
M: parse-error compute-restarts
|
||||
error>> compute-restarts ;
|
||||
|
||||
SYMBOL: use
|
||||
SYMBOL: in
|
||||
|
@ -181,22 +191,8 @@ SYMBOL: in
|
|||
: word/vocab% ( word -- )
|
||||
"(" % dup word-vocabulary % " " % word-name % ")" % ;
|
||||
|
||||
: shadow-warning ( new old -- )
|
||||
2dup eq? [
|
||||
2drop
|
||||
] [
|
||||
[ word/vocab% " shadowed by " % word/vocab% ] "" make
|
||||
note.
|
||||
] if ;
|
||||
|
||||
: shadow-warnings ( vocab vocabs -- )
|
||||
[
|
||||
swapd assoc-stack dup
|
||||
[ shadow-warning ] [ 2drop ] if
|
||||
] curry assoc-each ;
|
||||
|
||||
: (use+) ( vocab -- )
|
||||
vocab-words use get 2dup shadow-warnings push ;
|
||||
vocab-words use get push ;
|
||||
|
||||
: use+ ( vocab -- )
|
||||
load-vocab (use+) ;
|
||||
|
@ -409,6 +405,7 @@ SYMBOL: bootstrap-syntax
|
|||
SYMBOL: interactive-vocabs
|
||||
|
||||
{
|
||||
"accessors"
|
||||
"arrays"
|
||||
"assocs"
|
||||
"combinators"
|
||||
|
@ -464,19 +461,6 @@ SYMBOL: interactive-vocabs
|
|||
"Loading " write <pathname> . flush
|
||||
] if ;
|
||||
|
||||
: smudged-usage-warning ( usages removed -- )
|
||||
parser-notes? [
|
||||
"Warning: the following definitions were removed from sources," print
|
||||
"but are still referenced from other definitions:" print
|
||||
nl
|
||||
dup sorted-definitions.
|
||||
nl
|
||||
"The following definitions need to be updated:" print
|
||||
nl
|
||||
over sorted-definitions.
|
||||
nl
|
||||
] when 2drop ;
|
||||
|
||||
: filter-moved ( assoc1 assoc2 -- seq )
|
||||
diff [
|
||||
drop where dup [ first ] when
|
||||
|
@ -491,32 +475,22 @@ SYMBOL: interactive-vocabs
|
|||
new-definitions old-definitions
|
||||
[ get second ] bi@ ;
|
||||
|
||||
: smudged-usage ( -- usages referenced removed )
|
||||
removed-definitions filter-moved [
|
||||
outside-usages
|
||||
[
|
||||
empty? [ drop f ] [
|
||||
{
|
||||
{ [ dup pathname? ] [ f ] }
|
||||
{ [ dup method-body? ] [ f ] }
|
||||
{ [ t ] [ t ] }
|
||||
} cond nip
|
||||
] if
|
||||
] assoc-subset
|
||||
dup values concat prune swap keys
|
||||
] keep ;
|
||||
: forget-removed-definitions ( -- )
|
||||
removed-definitions filter-moved forget-all ;
|
||||
|
||||
: reset-removed-classes ( -- )
|
||||
removed-classes
|
||||
filter-moved [ class? ] subset [ reset-class ] each ;
|
||||
|
||||
: fix-class-words ( -- )
|
||||
#! If a class word had a compound definition which was
|
||||
#! removed, it must go back to being a symbol.
|
||||
new-definitions get first2
|
||||
filter-moved [ [ reset-generic ] [ define-symbol ] bi ] each
|
||||
removed-classes
|
||||
filter-moved [ class? ] subset [ reset-class ] each ;
|
||||
filter-moved [ [ reset-generic ] [ define-symbol ] bi ] each ;
|
||||
|
||||
: forget-smudged ( -- )
|
||||
smudged-usage forget-all
|
||||
over empty? [ 2dup smudged-usage-warning ] unless 2drop
|
||||
forget-removed-definitions
|
||||
reset-removed-classes
|
||||
fix-class-words ;
|
||||
|
||||
: finish-parsing ( lines quot -- )
|
||||
|
|
|
@ -4,12 +4,6 @@ IN: prettyprint.config
|
|||
|
||||
ABOUT: "prettyprint-variables"
|
||||
|
||||
HELP: indent
|
||||
{ $var-description "The prettyprinter's current indent level." } ;
|
||||
|
||||
HELP: pprinter-stack
|
||||
{ $var-description "A stack of " { $link block } " objects currently being constructed by the prettyprinter." } ;
|
||||
|
||||
HELP: tab-size
|
||||
{ $var-description "Prettyprinter tab size. Indent nesting is always a multiple of the tab size." } ;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ ARTICLE: "prettyprint-limitations" "Prettyprinter limitations"
|
|||
"On a final note, the " { $link short. } " and " { $link pprint-short } " words restrict the length and nesting of printed sequences, their output will very likely not be valid syntax. They are only intended for interactive use." ;
|
||||
|
||||
ARTICLE: "prettyprint-section-protocol" "Prettyprinter section protocol"
|
||||
"Prettyprinter sections must delegate to an instance of " { $link section } ", and they must also obey a protocol."
|
||||
"Prettyprinter sections must subclass " { $link section } ", and they must also obey a protocol."
|
||||
$nl
|
||||
"Layout queries:"
|
||||
{ $subsection section-fits? }
|
||||
|
@ -60,8 +60,8 @@ $nl
|
|||
{ $subsection short-section }
|
||||
{ $subsection long-section }
|
||||
"Utilities to use when implementing sections:"
|
||||
{ $subsection <section> }
|
||||
{ $subsection delegate>block }
|
||||
{ $subsection construct-section }
|
||||
{ $subsection construct-block }
|
||||
{ $subsection add-section } ;
|
||||
|
||||
ARTICLE: "prettyprint-sections" "Prettyprinter sections"
|
||||
|
|
|
@ -333,3 +333,6 @@ PREDICATE: predicate-see-test < integer even? ;
|
|||
[ "USING: math ;\nIN: prettyprint.tests\nPREDICATE: predicate-see-test < integer even? ;\n" ] [
|
||||
[ \ predicate-see-test see ] with-string-writer
|
||||
] unit-test
|
||||
|
||||
[ ] [ \ compose see ] unit-test
|
||||
[ ] [ \ curry see ] unit-test
|
||||
|
|
|
@ -5,9 +5,9 @@ USING: alien arrays generic generic.standard assocs io kernel
|
|||
math namespaces sequences strings io.styles io.streams.string
|
||||
vectors words prettyprint.backend prettyprint.sections
|
||||
prettyprint.config sorting splitting math.parser vocabs
|
||||
definitions effects classes.tuple io.files classes continuations
|
||||
hashtables classes.mixin classes.union classes.predicate
|
||||
classes.singleton combinators quotations ;
|
||||
definitions effects classes.builtin classes.tuple io.files
|
||||
classes continuations hashtables classes.mixin classes.union
|
||||
classes.predicate classes.singleton combinators quotations ;
|
||||
|
||||
: make-pprint ( obj quot -- block in use )
|
||||
[
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
USING: prettyprint io kernel help.markup help.syntax
|
||||
prettyprint.sections prettyprint.config words hashtables math
|
||||
prettyprint.config words hashtables math
|
||||
strings definitions ;
|
||||
IN: prettyprint.sections
|
||||
|
||||
HELP: position
|
||||
{ $var-description "The prettyprinter's current character position." } ;
|
||||
|
||||
HELP: last-newline
|
||||
{ $var-description "The character position of the last newline output by the prettyprinter." } ;
|
||||
|
||||
HELP: recursion-check
|
||||
{ $var-description "The current nesting of collections being output by the prettyprinter, used to detect circularity and prevent infinite recursion." } ;
|
||||
|
||||
HELP: line-count
|
||||
{ $var-description "The number of lines output by the prettyprinter so far, used for line limiting (see " { $link line-limit } ")." } ;
|
||||
|
||||
HELP: end-printing
|
||||
{ $var-description "A continuation captured by " { $link do-pprint } " that breaks out of the printer." } ;
|
||||
|
||||
HELP: line-limit?
|
||||
{ $values { "?" "a boolean" } }
|
||||
{ $description "Tests if the line number limit has been reached, and thus if prettyprinting should stop." } ;
|
||||
|
@ -67,7 +59,7 @@ HELP: short-section?
|
|||
{ $contract "Tests if a section should be output as a " { $link short-section } ". The default implementation calls " { $link section-fits? } " but this behavior can be cutomized." } ;
|
||||
|
||||
HELP: section
|
||||
{ $class-description "A piece of prettyprinter output. Instances of this class are not used directly, instead one instantiates various classes which delegate to this class:"
|
||||
{ $class-description "A piece of prettyprinter output. Instances of this class are not used directly, instead one instantiates various subclasses of this class:"
|
||||
{ $list
|
||||
{ $link text }
|
||||
{ $link line-break }
|
||||
|
@ -78,22 +70,18 @@ HELP: section
|
|||
}
|
||||
"Instances of this class have the following slots:"
|
||||
{ $list
|
||||
{ { $link section-start } " - the start of the section, measured in characters from the beginning of the prettyprinted output" }
|
||||
{ { $link section-end } " - the end of the section, measured in characters from the beginning of the prettyprinted output" }
|
||||
{ { $link section-start-group? } " - see " { $link start-group } }
|
||||
{ { $link section-end } " - see " { $link end-group } }
|
||||
{ { $link section-style } " - character and/or paragraph styles to use when outputting this section. See " { $link "styles" } }
|
||||
{ { $link section-overhang } " - number of columns which must be left blank before the wrap margin for the prettyprinter to consider emitting this section as a " { $link short-section } ". Avoids lone hanging closing brackets" }
|
||||
{ { $snippet "start" } " - the start of the section, measured in characters from the beginning of the prettyprinted output" }
|
||||
{ { $snippet "end" } " - the end of the section, measured in characters from the beginning of the prettyprinted output" }
|
||||
{ { $snippet "start-group?" } " - see " { $link start-group } }
|
||||
{ { $snippet "end-group?" } " - see " { $link end-group } }
|
||||
{ { $snippet "style" } " - character and/or paragraph styles to use when outputting this section. See " { $link "styles" } }
|
||||
{ { $snippet "overhang" } " - number of columns which must be left blank before the wrap margin for the prettyprinter to consider emitting this section as a " { $link short-section } ". Avoids lone hanging closing brackets" }
|
||||
} } ;
|
||||
|
||||
HELP: <section>
|
||||
{ $values { "style" hashtable } { "length" integer } { "section" section } }
|
||||
HELP: construct-section
|
||||
{ $values { "length" integer } { "class" "a subclass of " { $link section } } { "section" section } }
|
||||
{ $description "Creates a new section with the given length starting from " { $link position } ", advancing " { $link position } "." } ;
|
||||
|
||||
HELP: change-indent
|
||||
{ $values { "section" section } { "n" integer } }
|
||||
{ $description "If the section requests indentation, adds " { $snippet "n" } " to the indent level, otherwise does nothing." } ;
|
||||
|
||||
HELP: <indent
|
||||
{ $values { "section" section } }
|
||||
{ $description "Increases indentation by the " { $link tab-size } " if requested by the section." } ;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
! Copyright (C) 2003, 2007 Slava Pestov.
|
||||
! Copyright (C) 2003, 2008 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: alien arrays generic hashtables io kernel math assocs
|
||||
namespaces sequences strings io.styles vectors words
|
||||
prettyprint.config splitting classes continuations
|
||||
io.streams.nested ;
|
||||
io.streams.nested accessors ;
|
||||
IN: prettyprint.sections
|
||||
|
||||
! State
|
||||
|
@ -11,37 +11,38 @@ SYMBOL: position
|
|||
SYMBOL: recursion-check
|
||||
SYMBOL: pprinter-stack
|
||||
|
||||
SYMBOL: last-newline
|
||||
SYMBOL: line-count
|
||||
SYMBOL: end-printing
|
||||
SYMBOL: indent
|
||||
|
||||
! We record vocabs of all words
|
||||
SYMBOL: pprinter-in
|
||||
SYMBOL: pprinter-use
|
||||
|
||||
TUPLE: pprinter last-newline line-count end-printing indent ;
|
||||
|
||||
: <pprinter> ( -- pprinter ) 0 1 f 0 pprinter construct-boa ;
|
||||
|
||||
: record-vocab ( word -- )
|
||||
word-vocabulary [ dup pprinter-use get set-at ] when* ;
|
||||
|
||||
! Utility words
|
||||
: line-limit? ( -- ? )
|
||||
line-limit get dup [ line-count get <= ] when ;
|
||||
line-limit get dup [ pprinter get line-count>> <= ] when ;
|
||||
|
||||
: do-indent ( -- ) indent get CHAR: \s <string> write ;
|
||||
: do-indent ( -- ) pprinter get indent>> CHAR: \s <string> write ;
|
||||
|
||||
: fresh-line ( n -- )
|
||||
dup last-newline get = [
|
||||
dup pprinter get last-newline>> = [
|
||||
drop
|
||||
] [
|
||||
last-newline set
|
||||
line-limit? [ "..." write end-printing get continue ] when
|
||||
line-count inc
|
||||
pprinter get (>>last-newline)
|
||||
line-limit? [
|
||||
"..." write pprinter get end-printing>> continue
|
||||
] when
|
||||
pprinter get [ 1+ ] change-line-count drop
|
||||
nl do-indent
|
||||
] if ;
|
||||
|
||||
: text-fits? ( len -- ? )
|
||||
margin get dup zero?
|
||||
[ 2drop t ] [ >r indent get + r> <= ] if ;
|
||||
[ 2drop t ] [ >r pprinter get indent>> + r> <= ] if ;
|
||||
|
||||
! break only if position margin 2 / >
|
||||
SYMBOL: soft
|
||||
|
@ -70,17 +71,17 @@ start end
|
|||
start-group? end-group?
|
||||
style overhang ;
|
||||
|
||||
: <section> ( style length -- section )
|
||||
position [ dup rot + dup ] change 0 {
|
||||
set-section-style
|
||||
set-section-start
|
||||
set-section-end
|
||||
set-section-overhang
|
||||
} section construct ;
|
||||
: construct-section ( length class -- section )
|
||||
construct-empty
|
||||
position get >>start
|
||||
swap position [ + ] change
|
||||
position get >>end
|
||||
0 >>overhang ; inline
|
||||
|
||||
M: section section-fits? ( section -- ? )
|
||||
dup section-end last-newline get -
|
||||
swap section-overhang + text-fits? ;
|
||||
[ end>> pprinter get last-newline>> - ]
|
||||
[ overhang>> ] bi
|
||||
+ text-fits? ;
|
||||
|
||||
M: section indent-section? drop f ;
|
||||
|
||||
|
@ -90,18 +91,20 @@ M: section newline-after? drop f ;
|
|||
|
||||
M: object short-section? section-fits? ;
|
||||
|
||||
: change-indent ( section n -- )
|
||||
swap indent-section? [ indent +@ ] [ drop ] if ;
|
||||
: indent+ ( section n -- )
|
||||
swap indent-section? [
|
||||
pprinter get [ + ] change-indent drop
|
||||
] [ drop ] if ;
|
||||
|
||||
: <indent ( section -- ) tab-size get change-indent ;
|
||||
: <indent ( section -- ) tab-size get indent+ ;
|
||||
|
||||
: indent> ( section -- ) tab-size get neg change-indent ;
|
||||
: indent> ( section -- ) tab-size get neg indent+ ;
|
||||
|
||||
: <fresh-line ( section -- )
|
||||
section-start fresh-line ;
|
||||
start>> fresh-line ;
|
||||
|
||||
: fresh-line> ( section -- )
|
||||
dup newline-after? [ section-end fresh-line ] [ drop ] if ;
|
||||
dup newline-after? [ end>> fresh-line ] [ drop ] if ;
|
||||
|
||||
: <long-section ( section -- )
|
||||
dup unindent-first-line?
|
||||
|
@ -110,67 +113,65 @@ M: object short-section? section-fits? ;
|
|||
: long-section> ( section -- )
|
||||
dup indent> fresh-line> ;
|
||||
|
||||
: with-style* ( style quot -- )
|
||||
swap stdio [ <style-stream> ] change
|
||||
call stdio [ delegate ] change ; inline
|
||||
|
||||
: pprint-section ( section -- )
|
||||
dup short-section? [
|
||||
dup section-style [ short-section ] with-style*
|
||||
dup section-style [ short-section ] with-style
|
||||
] [
|
||||
dup <long-section
|
||||
dup section-style [ dup long-section ] with-style*
|
||||
long-section>
|
||||
[ <long-section ]
|
||||
[ dup section-style [ long-section ] with-style ]
|
||||
[ long-section> ]
|
||||
tri
|
||||
] if ;
|
||||
|
||||
! Break section
|
||||
TUPLE: line-break type ;
|
||||
TUPLE: line-break < section type ;
|
||||
|
||||
: <line-break> ( type -- section )
|
||||
H{ } 0 <section>
|
||||
{ set-line-break-type set-delegate }
|
||||
\ line-break construct ;
|
||||
0 \ line-break construct-section
|
||||
swap >>type ;
|
||||
|
||||
M: line-break short-section drop ;
|
||||
|
||||
M: line-break long-section drop ;
|
||||
|
||||
! Block sections
|
||||
TUPLE: block sections ;
|
||||
TUPLE: block < section sections ;
|
||||
|
||||
: construct-block ( style class -- block )
|
||||
0 swap construct-section
|
||||
V{ } clone >>sections
|
||||
swap >>style ; inline
|
||||
|
||||
: <block> ( style -- block )
|
||||
0 <section> V{ } clone
|
||||
{ set-delegate set-block-sections } block construct ;
|
||||
|
||||
: delegate>block ( obj -- ) H{ } <block> swap set-delegate ;
|
||||
block construct-block ;
|
||||
|
||||
: pprinter-block ( -- block ) pprinter-stack get peek ;
|
||||
|
||||
: add-section ( section -- )
|
||||
pprinter-block block-sections push ;
|
||||
pprinter-block sections>> push ;
|
||||
|
||||
: last-section ( -- section )
|
||||
pprinter-block block-sections
|
||||
pprinter-block sections>>
|
||||
[ line-break? not ] find-last nip ;
|
||||
|
||||
: start-group ( -- )
|
||||
t last-section set-section-start-group? ;
|
||||
last-section t >>start-group? drop ;
|
||||
|
||||
: end-group ( -- )
|
||||
t last-section set-section-end-group? ;
|
||||
last-section t >>end-group? drop ;
|
||||
|
||||
: advance ( section -- )
|
||||
dup section-start last-newline get = not
|
||||
swap short-section? and
|
||||
[ bl ] when ;
|
||||
[ start>> pprinter get last-newline>> = not ]
|
||||
[ short-section? ] bi
|
||||
and [ bl ] when ;
|
||||
|
||||
: line-break ( type -- ) [ <line-break> add-section ] when* ;
|
||||
|
||||
M: block section-fits? ( section -- ? )
|
||||
line-limit? [ drop t ] [ delegate section-fits? ] if ;
|
||||
line-limit? [ drop t ] [ call-next-method ] if ;
|
||||
|
||||
: pprint-sections ( block advancer -- )
|
||||
swap block-sections [ line-break? not ] subset
|
||||
swap sections>> [ line-break? not ] subset
|
||||
unclip pprint-section [
|
||||
dup rot call pprint-section
|
||||
] with each ; inline
|
||||
|
@ -179,28 +180,29 @@ M: block short-section ( block -- )
|
|||
[ advance ] pprint-sections ;
|
||||
|
||||
: do-break ( break -- )
|
||||
dup line-break-type hard eq?
|
||||
over section-end last-newline get - margin get 2/ > or
|
||||
[ <fresh-line ] [ drop ] if ;
|
||||
[ ]
|
||||
[ type>> hard eq? ]
|
||||
[ end>> pprinter get last-newline>> - margin get 2/ > ] tri
|
||||
or [ <fresh-line ] [ drop ] if ;
|
||||
|
||||
: empty-block? ( block -- ? ) block-sections empty? ;
|
||||
: empty-block? ( block -- ? ) sections>> empty? ;
|
||||
|
||||
: if-nonempty ( block quot -- )
|
||||
>r dup empty-block? [ drop ] r> if ; inline
|
||||
|
||||
: (<block) pprinter-stack get push ;
|
||||
|
||||
: <block H{ } <block> (<block) ;
|
||||
: <block f <block> (<block) ;
|
||||
|
||||
: <object ( obj -- ) presented associate <block> (<block) ;
|
||||
|
||||
! Text section
|
||||
TUPLE: text string ;
|
||||
TUPLE: text < section string ;
|
||||
|
||||
: <text> ( string style -- text )
|
||||
over length 1+ <section>
|
||||
{ set-text-string set-delegate }
|
||||
\ text construct ;
|
||||
over length 1+ \ text construct-section
|
||||
swap >>style
|
||||
swap >>string ;
|
||||
|
||||
M: text short-section text-string write ;
|
||||
|
||||
|
@ -211,18 +213,18 @@ M: text long-section short-section ;
|
|||
: text ( string -- ) H{ } styled-text ;
|
||||
|
||||
! Inset section
|
||||
TUPLE: inset narrow? ;
|
||||
TUPLE: inset < block narrow? ;
|
||||
|
||||
: <inset> ( narrow? -- block )
|
||||
2 H{ } <block>
|
||||
{ set-inset-narrow? set-section-overhang set-delegate }
|
||||
inset construct ;
|
||||
H{ } inset construct-block
|
||||
2 >>overhang
|
||||
swap >>narrow? ;
|
||||
|
||||
M: inset long-section
|
||||
dup inset-narrow? [
|
||||
dup narrow?>> [
|
||||
[ <fresh-line ] pprint-sections
|
||||
] [
|
||||
delegate long-section
|
||||
call-next-method
|
||||
] if ;
|
||||
|
||||
M: inset indent-section? drop t ;
|
||||
|
@ -232,25 +234,26 @@ M: inset newline-after? drop t ;
|
|||
: <inset ( narrow? -- ) <inset> (<block) ;
|
||||
|
||||
! Flow section
|
||||
TUPLE: flow ;
|
||||
TUPLE: flow < block ;
|
||||
|
||||
: <flow> ( -- block )
|
||||
H{ } <block> flow construct-delegate ;
|
||||
H{ } flow construct-block ;
|
||||
|
||||
M: flow short-section? ( section -- ? )
|
||||
#! If we can make room for this entire block by inserting
|
||||
#! a newline, do it; otherwise, don't bother, print it as
|
||||
#! a short section
|
||||
dup section-fits?
|
||||
over section-end rot section-start - text-fits? not or ;
|
||||
[ section-fits? ]
|
||||
[ [ end>> ] [ start>> ] bi - text-fits? not ] bi
|
||||
or ;
|
||||
|
||||
: <flow ( -- ) <flow> (<block) ;
|
||||
|
||||
! Colon definition section
|
||||
TUPLE: colon ;
|
||||
TUPLE: colon < block ;
|
||||
|
||||
: <colon> ( -- block )
|
||||
H{ } <block> colon construct-delegate ;
|
||||
H{ } colon construct-block ;
|
||||
|
||||
M: colon long-section short-section ;
|
||||
|
||||
|
@ -261,28 +264,23 @@ M: colon unindent-first-line? drop t ;
|
|||
: <colon ( -- ) <colon> (<block) ;
|
||||
|
||||
: save-end-position ( block -- )
|
||||
position get swap set-section-end ;
|
||||
position get >>end drop ;
|
||||
|
||||
: block> ( -- )
|
||||
pprinter-stack get pop
|
||||
[ dup save-end-position add-section ] if-nonempty ;
|
||||
|
||||
: with-section-state ( quot -- )
|
||||
[
|
||||
0 indent set
|
||||
0 last-newline set
|
||||
1 line-count set
|
||||
call
|
||||
] with-scope ; inline
|
||||
[ [ save-end-position ] [ add-section ] bi ] if-nonempty ;
|
||||
|
||||
: do-pprint ( block -- )
|
||||
[
|
||||
<pprinter> pprinter [
|
||||
[
|
||||
dup section-style [
|
||||
[ end-printing set dup short-section ] callcc0
|
||||
] with-nesting drop
|
||||
dup style>> [
|
||||
[
|
||||
>r pprinter get (>>end-printing) r>
|
||||
short-section
|
||||
] curry callcc0
|
||||
] with-nesting
|
||||
] if-nonempty
|
||||
] with-section-state ;
|
||||
] with-variable ;
|
||||
|
||||
! Long section layout algorithm
|
||||
: chop-break ( seq -- seq )
|
||||
|
@ -298,9 +296,9 @@ M: f section-start-group? drop t ;
|
|||
M: f section-end-group? drop f ;
|
||||
|
||||
: split-before ( section -- )
|
||||
dup section-start-group? prev get section-end-group? and
|
||||
swap flow? prev get flow? not and
|
||||
or split-groups ;
|
||||
[ section-start-group? prev get section-end-group? and ]
|
||||
[ flow? prev get flow? not and ]
|
||||
bi or split-groups ;
|
||||
|
||||
: split-after ( section -- )
|
||||
section-end-group? split-groups ;
|
||||
|
@ -315,19 +313,19 @@ M: f section-end-group? drop f ;
|
|||
] { } make { t } split [ empty? not ] subset ;
|
||||
|
||||
: break-group? ( seq -- ? )
|
||||
dup first section-fits? swap peek section-fits? not and ;
|
||||
[ first section-fits? ] [ peek section-fits? not ] bi and ;
|
||||
|
||||
: ?break-group ( seq -- )
|
||||
dup break-group? [ first <fresh-line ] [ drop ] if ;
|
||||
|
||||
M: block long-section ( block -- )
|
||||
[
|
||||
block-sections chop-break group-flow [
|
||||
sections>> chop-break group-flow [
|
||||
dup ?break-group [
|
||||
dup line-break? [
|
||||
do-break
|
||||
] [
|
||||
dup advance pprint-section
|
||||
[ advance ] [ pprint-section ] bi
|
||||
] if
|
||||
] each
|
||||
] each
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
USING: refs tools.test kernel ;
|
||||
|
||||
[ 3 ] [
|
||||
H{ { "a" 3 } } "a" <value-ref> get-ref
|
||||
] unit-test
|
||||
|
||||
[ 4 ] [
|
||||
4 H{ { "a" 3 } } clone "a" <value-ref>
|
||||
[ set-ref ] keep
|
||||
get-ref
|
||||
] unit-test
|
||||
|
||||
[ "a" ] [
|
||||
H{ { "a" 3 } } "a" <key-ref> get-ref
|
||||
] unit-test
|
||||
|
||||
[ H{ { "b" 3 } } ] [
|
||||
"b" H{ { "a" 3 } } clone [
|
||||
"a" <key-ref>
|
||||
set-ref
|
||||
] keep
|
||||
] unit-test
|
|
@ -5,21 +5,18 @@ IN: refs
|
|||
|
||||
TUPLE: ref assoc key ;
|
||||
|
||||
: <ref> ( assoc key class -- tuple )
|
||||
>r ref construct-boa r> construct-delegate ; inline
|
||||
|
||||
: >ref< ( ref -- key assoc ) [ key>> ] [ assoc>> ] bi ;
|
||||
: >ref< [ key>> ] [ assoc>> ] bi ; inline
|
||||
|
||||
: delete-ref ( ref -- ) >ref< delete-at ;
|
||||
GENERIC: get-ref ( ref -- obj )
|
||||
GENERIC: set-ref ( obj ref -- )
|
||||
|
||||
TUPLE: key-ref ;
|
||||
: <key-ref> ( assoc key -- ref ) key-ref <ref> ;
|
||||
M: key-ref get-ref ref-key ;
|
||||
TUPLE: key-ref < ref ;
|
||||
C: <key-ref> key-ref ( assoc key -- ref )
|
||||
M: key-ref get-ref key>> ;
|
||||
M: key-ref set-ref >ref< rename-at ;
|
||||
|
||||
TUPLE: value-ref ;
|
||||
: <value-ref> ( assoc key -- ref ) value-ref <ref> ;
|
||||
TUPLE: value-ref < ref ;
|
||||
C: <value-ref> value-ref ( assoc key -- ref )
|
||||
M: value-ref get-ref >ref< at ;
|
||||
M: value-ref set-ref >ref< set-at ;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
USING: help.markup help.syntax generic kernel.private parser
|
||||
words kernel quotations namespaces sequences words arrays
|
||||
effects generic.standard classes.tuple slots.private classes
|
||||
strings math ;
|
||||
effects generic.standard classes.tuple classes.builtin
|
||||
slots.private classes strings math ;
|
||||
IN: slots
|
||||
|
||||
ARTICLE: "accessors" "Slot accessors"
|
||||
|
|
|
@ -4,7 +4,7 @@ USING: arrays definitions generic assocs kernel math namespaces
|
|||
prettyprint sequences strings vectors words quotations inspector
|
||||
io.styles io combinators sorting splitting math.parser effects
|
||||
continuations debugger io.files io.crc32 vocabs hashtables
|
||||
graphs compiler.units io.encodings.utf8 ;
|
||||
graphs compiler.units io.encodings.utf8 accessors ;
|
||||
IN: source-files
|
||||
|
||||
SYMBOL: source-files
|
||||
|
@ -56,10 +56,14 @@ uses definitions ;
|
|||
M: pathname where pathname-string 1 2array ;
|
||||
|
||||
: forget-source ( path -- )
|
||||
dup source-file
|
||||
dup unxref-source
|
||||
source-file-definitions [ keys forget-all ] each
|
||||
source-files get delete-at ;
|
||||
[
|
||||
source-file
|
||||
[ unxref-source ]
|
||||
[ definitions>> [ keys forget-all ] each ]
|
||||
bi
|
||||
]
|
||||
[ source-files get delete-at ]
|
||||
bi ;
|
||||
|
||||
M: pathname forget*
|
||||
pathname-string forget-source ;
|
||||
|
@ -78,9 +82,3 @@ SYMBOL: file
|
|||
source-file-definitions old-definitions set
|
||||
[ ] [ file get rollback-source-file ] cleanup
|
||||
] with-scope ; inline
|
||||
|
||||
: outside-usages ( seq -- usages )
|
||||
dup [
|
||||
over usage
|
||||
[ dup pathname? not swap where and ] subset seq-diff
|
||||
] curry { } map>assoc ;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
USING: generic help.syntax help.markup kernel math parser words
|
||||
effects classes generic.standard classes.tuple generic.math
|
||||
arrays io.files vocabs.loader io sequences assocs ;
|
||||
generic.standard arrays io.files vocabs.loader io sequences
|
||||
assocs ;
|
||||
IN: syntax
|
||||
|
||||
ARTICLE: "parser-algorithm" "Parser algorithm"
|
||||
|
@ -332,8 +333,8 @@ HELP: C{
|
|||
{ $description "Parses a complex number given in rectangular form as a pair of real numbers. Literal complex numbers are terminated by " { $link POSTPONE: } } "." } ;
|
||||
|
||||
HELP: T{
|
||||
{ $syntax "T{ class delegate slots... }" }
|
||||
{ $values { "class" "a tuple class word" } { "delegate" "a delegate" } { "slots" "list of objects" } }
|
||||
{ $syntax "T{ class slots... }" }
|
||||
{ $values { "class" "a tuple class word" } { "slots" "list of objects" } }
|
||||
{ $description "Marks the beginning of a literal tuple. Literal tuples are terminated by " { $link POSTPONE: } } "."
|
||||
$nl
|
||||
"The class word must always be specified. If an insufficient number of values is given after the class word, the remaining slots of the tuple are set to " { $link f } ". If too many values are given, they are ignored." } ;
|
||||
|
@ -564,9 +565,17 @@ HELP: TUPLE:
|
|||
HELP: ERROR:
|
||||
{ $syntax "ERROR: class slots... ;" }
|
||||
{ $values { "class" "a new tuple class to define" } { "slots" "a list of slot names" } }
|
||||
{ $description "Defines a new tuple class. Defines a new word " { $snippet "class?" } " that boa-constructs this tuple and throws it." } ;
|
||||
|
||||
{ POSTPONE: ERROR: POSTPONE: TUPLE: } related-words
|
||||
{ $description "Defines a new tuple class whose class word throws a new instance of the error." }
|
||||
{ $notes
|
||||
"The following two snippets are equivalent:"
|
||||
{ $code
|
||||
"ERROR: invalid-values x y ;"
|
||||
""
|
||||
"TUPLE: invalid-values x y ;"
|
||||
": invalid-values ( x y -- * )"
|
||||
" \\ invalid-values construct-boa throw ;"
|
||||
}
|
||||
} ;
|
||||
|
||||
HELP: C:
|
||||
{ $syntax "C: constructor class" }
|
||||
|
@ -633,4 +642,18 @@ HELP: >>
|
|||
{ $syntax ">>" }
|
||||
{ $description "Marks the end of a parse time code block." } ;
|
||||
|
||||
HELP: call-next-method
|
||||
{ $description "Calls the next applicable method. Only valid inside a method definition. The values at the top of the stack are passed on to the next method, and they must be compatible with that method's class specializer." }
|
||||
{ $notes "This is syntax sugar around " { $link (call-next-method) } ". The following two lines are equivalent:"
|
||||
{ $code
|
||||
"M: my-class my-generic ... call-next-method ... ;"
|
||||
"M: my-class my-generic ... \\ my-class \\ my-generic (call-next-method) ... ;"
|
||||
}
|
||||
"In most cases, this word should be called with the original input values on the stack. Calling it with other values is usually a sign of poor design." }
|
||||
{ $errors
|
||||
"Throws a " { $link no-next-method } " error if this is the least specific method, and throws an " { $link inconsistent-next-method } " error if the values at the top of the stack are not compatible with the current method's specializer."
|
||||
} ;
|
||||
|
||||
{ POSTPONE: call-next-method (call-next-method) next-method } related-words
|
||||
|
||||
{ POSTPONE: << POSTPONE: >> } related-words
|
||||
|
|
|
@ -3,7 +3,7 @@ IN: vocabs.loader.tests
|
|||
USING: vocabs.loader tools.test continuations vocabs math
|
||||
kernel arrays sequences namespaces io.streams.string
|
||||
parser source-files words assocs classes.tuple definitions
|
||||
debugger compiler.units tools.vocabs ;
|
||||
debugger compiler.units tools.vocabs accessors ;
|
||||
|
||||
! This vocab should not exist, but just in case...
|
||||
[ ] [
|
||||
|
@ -68,7 +68,7 @@ IN: vocabs.loader.tests
|
|||
<string-reader>
|
||||
"resource:core/vocabs/loader/test/a/a.factor"
|
||||
parse-stream
|
||||
] [ [ no-word-error? ] is? ] must-fail-with
|
||||
] [ error>> error>> no-word-error? ] must-fail-with
|
||||
|
||||
0 "count-me" set-global
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
USING: arrays generic assocs kernel math namespaces
|
||||
sequences tools.test words definitions parser quotations
|
||||
vocabs continuations classes.tuple compiler.units
|
||||
io.streams.string ;
|
||||
io.streams.string accessors ;
|
||||
IN: words.tests
|
||||
|
||||
[ 4 ] [
|
||||
|
@ -147,7 +147,7 @@ SYMBOL: quot-uses-b
|
|||
] when*
|
||||
|
||||
[ "IN: words.tests : undef-test ; << undef-test >>" eval ]
|
||||
[ [ undefined? ] is? ] must-fail-with
|
||||
[ error>> undefined? ] must-fail-with
|
||||
|
||||
[ ] [
|
||||
"IN: words.tests GENERIC: symbol-generic" eval
|
||||
|
|
|
@ -121,22 +121,35 @@ SYMBOL: +called+
|
|||
compiled-usage [ nip +inlined+ eq? ] assoc-subset update
|
||||
] with each keys ;
|
||||
|
||||
M: word redefined* ( word -- )
|
||||
{ "inferred-effect" "no-effect" } reset-props ;
|
||||
<PRIVATE
|
||||
|
||||
SYMBOL: changed-words
|
||||
SYMBOL: visited
|
||||
|
||||
: changed-word ( word -- )
|
||||
dup changed-words get
|
||||
[ no-compilation-unit ] unless*
|
||||
set-at ;
|
||||
: reset-on-redefine { "inferred-effect" "no-effect" } ; inline
|
||||
|
||||
: (redefined) ( word -- )
|
||||
dup visited get key? [ drop ] [
|
||||
[ reset-on-redefine reset-props ]
|
||||
[ dup visited get set-at ]
|
||||
[
|
||||
crossref get at keys [ word? ] subset [
|
||||
reset-on-redefine [ word-prop ] with contains?
|
||||
] subset
|
||||
[ (redefined) ] each
|
||||
] tri
|
||||
] if ;
|
||||
|
||||
PRIVATE>
|
||||
|
||||
: redefined ( word -- )
|
||||
H{ } clone visited [ (redefined) ] with-variable ;
|
||||
|
||||
: define ( word def -- )
|
||||
[ ] like
|
||||
over unxref
|
||||
over redefined
|
||||
over set-word-def
|
||||
dup changed-word
|
||||
dup changed-definition
|
||||
dup crossref? [ dup xref ] when drop ;
|
||||
|
||||
: define-declared ( word def effect -- )
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
USING: kernel namespaces sequences splitting system combinators continuations
|
||||
parser io io.files io.launcher io.sockets prettyprint threads
|
||||
bootstrap.image benchmark vars bake smtp builder.util accessors
|
||||
io.encodings.utf8
|
||||
debugger io.encodings.utf8
|
||||
calendar
|
||||
tools.test
|
||||
builder.common
|
||||
|
@ -13,16 +13,22 @@ IN: builder
|
|||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
! : cd ( path -- ) current-directory set ;
|
||||
|
||||
: cd ( path -- ) set-current-directory ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: builds/factor ( -- path ) builds "factor" append-path ;
|
||||
: build-dir ( -- path ) builds stamp> append-path ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: prepare-build-machine ( -- )
|
||||
builds make-directory
|
||||
builds cd
|
||||
{ "git" "clone" "git://factorcode.org/git/factor.git" } run-process drop ;
|
||||
builds
|
||||
[
|
||||
{ "git" "clone" "git://factorcode.org/git/factor.git" } try-process
|
||||
]
|
||||
with-directory ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
|
@ -51,23 +57,15 @@ IN: builder
|
|||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: gnu-make ( -- string )
|
||||
os { "freebsd" "openbsd" "netbsd" } member?
|
||||
os { freebsd openbsd netbsd } member?
|
||||
[ "gmake" ]
|
||||
[ "make" ]
|
||||
if ;
|
||||
|
||||
! : do-make-clean ( -- ) { "make" "clean" } try-process ;
|
||||
|
||||
: do-make-clean ( -- ) { gnu-make "clean" } to-strings try-process ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
! : make-vm ( -- desc )
|
||||
! <process>
|
||||
! { "make" } >>command
|
||||
! "../compile-log" >>stdout
|
||||
! +stdout+ >>stderr ;
|
||||
|
||||
: make-vm ( -- desc )
|
||||
<process>
|
||||
{ gnu-make } to-strings >>command
|
||||
|
@ -80,8 +78,8 @@ IN: builder
|
|||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: copy-image ( -- )
|
||||
builds "factor" append-path my-boot-image-name append-path ".." copy-file-into
|
||||
builds "factor" append-path my-boot-image-name append-path "." copy-file-into ;
|
||||
builds/factor my-boot-image-name append-path ".." copy-file-into
|
||||
builds/factor my-boot-image-name append-path "." copy-file-into ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
|
@ -94,7 +92,7 @@ IN: builder
|
|||
+closed+ >>stdin
|
||||
"../boot-log" >>stdout
|
||||
+stdout+ >>stderr
|
||||
20 minutes >>timeout ;
|
||||
60 minutes >>timeout ;
|
||||
|
||||
: do-bootstrap ( -- )
|
||||
bootstrap [ "Bootstrap error" print "../boot-log" cat ] run-or-bail ;
|
||||
|
@ -127,10 +125,10 @@ SYMBOL: build-status
|
|||
|
||||
"report" utf8
|
||||
[
|
||||
"Build machine: " write host-name print
|
||||
"CPU: " write cpu print
|
||||
"OS: " write os print
|
||||
"Build directory: " write cwd print
|
||||
"Build machine: " write host-name print
|
||||
"CPU: " write cpu .
|
||||
"OS: " write os .
|
||||
"Build directory: " write current-directory get print
|
||||
|
||||
git-clone [ "git clone failed" print ] run-or-bail
|
||||
|
||||
|
@ -158,8 +156,6 @@ SYMBOL: build-status
|
|||
"Did not pass test-all: " print "test-all-vocabs" cat
|
||||
"test-failures" cat
|
||||
|
||||
! "test-failures" eval-file test-failures.
|
||||
|
||||
"help-lint results:" print "help-lint" cat
|
||||
|
||||
"Benchmarks: " print "benchmarks" eval-file benchmarks.
|
||||
|
@ -196,15 +192,27 @@ SYMBOL: builder-recipients
|
|||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: compress-image ( -- )
|
||||
{ "bzip2" my-boot-image-name } to-strings run-process drop ;
|
||||
: compress-image ( -- ) { "bzip2" my-boot-image-name } to-strings try-process ;
|
||||
|
||||
! : build ( -- )
|
||||
! [ (build) ] try
|
||||
! builds cd stamp> cd
|
||||
! [ send-builder-email ] try
|
||||
! { "rm" "-rf" "factor" } [ ] run-or-bail
|
||||
! [ compress-image ] try ;
|
||||
|
||||
: build ( -- )
|
||||
[ (build) ] failsafe
|
||||
builds cd stamp> cd
|
||||
[ send-builder-email ] [ drop "not sending mail" . ] recover
|
||||
{ "rm" "-rf" "factor" } run-process drop
|
||||
[ compress-image ] failsafe ;
|
||||
[
|
||||
(build)
|
||||
build-dir
|
||||
[
|
||||
{ "rm" "-rf" "factor" } try-process
|
||||
compress-image
|
||||
]
|
||||
with-directory
|
||||
]
|
||||
try
|
||||
send-builder-email ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
|
@ -221,7 +229,7 @@ USE: bootstrap.image.download
|
|||
|
||||
: updates-available? ( -- ? )
|
||||
git-id
|
||||
git-pull run-process drop
|
||||
git-pull try-process
|
||||
git-id
|
||||
= not ;
|
||||
|
||||
|
@ -234,12 +242,15 @@ USE: bootstrap.image.download
|
|||
: build-loop ( -- )
|
||||
builds-check
|
||||
[
|
||||
builds "/factor" append cd
|
||||
updates-available? new-image-available? or
|
||||
[ build ]
|
||||
when
|
||||
builds/factor
|
||||
[
|
||||
updates-available? new-image-available? or
|
||||
[ build ]
|
||||
when
|
||||
]
|
||||
with-directory
|
||||
]
|
||||
failsafe
|
||||
try
|
||||
5 minutes sleep
|
||||
build-loop ;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
USING: kernel system namespaces sequences splitting combinators
|
||||
io io.files io.launcher
|
||||
io io.files io.launcher prettyprint
|
||||
bake combinators.cleave builder.common builder.util ;
|
||||
|
||||
IN: builder.release
|
||||
|
@ -33,22 +33,22 @@ IN: builder.release
|
|||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: cpu- ( -- cpu ) cpu "." split "-" join ;
|
||||
: cpu- ( -- cpu ) cpu unparse "." split "-" join ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: base-name ( -- string ) { "factor" os cpu- stamp> } to-strings "-" join ;
|
||||
: base-name ( -- string )
|
||||
{ "factor" [ os unparse ] cpu- stamp> } to-strings "-" join ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
: extension ( -- extension )
|
||||
os
|
||||
{
|
||||
{ "linux" [ ".tar.gz" ] }
|
||||
{ "winnt" [ ".zip" ] }
|
||||
{ "macosx" [ ".dmg" ] }
|
||||
{ [ os winnt? ] [ ".zip" ] }
|
||||
{ [ os macosx? ] [ ".dmg" ] }
|
||||
{ [ os unix? ] [ ".tar.gz" ] }
|
||||
}
|
||||
case ;
|
||||
cond ;
|
||||
|
||||
: archive-name ( -- string ) base-name extension append ;
|
||||
|
||||
|
@ -69,9 +69,9 @@ IN: builder.release
|
|||
|
||||
: archive-cmd ( -- cmd )
|
||||
{
|
||||
{ [ windows? ] [ windows-archive-cmd ] }
|
||||
{ [ macosx? ] [ macosx-archive-cmd ] }
|
||||
{ [ unix? ] [ unix-archive-cmd ] }
|
||||
{ [ os windows? ] [ windows-archive-cmd ] }
|
||||
{ [ os macosx? ] [ macosx-archive-cmd ] }
|
||||
{ [ os unix? ] [ unix-archive-cmd ] }
|
||||
}
|
||||
cond ;
|
||||
|
||||
|
@ -83,13 +83,13 @@ IN: builder.release
|
|||
{ "rm" "-rf" common-files } to-strings try-process ;
|
||||
|
||||
: remove-factor-app ( -- )
|
||||
macosx? not [ { "rm" "-rf" "Factor.app" } try-process ] when ;
|
||||
os macosx? not [ { "rm" "-rf" "Factor.app" } try-process ] when ;
|
||||
|
||||
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
SYMBOL: upload-to-factorcode
|
||||
|
||||
: platform ( -- string ) { os cpu- } to-strings "-" join ;
|
||||
: platform ( -- string ) { [ os unparse ] cpu- } to-strings "-" join ;
|
||||
|
||||
: remote-location ( -- dest )
|
||||
"factorcode.org:/var/www/factorcode.org/newsite/downloads"
|
||||
|
|
|
@ -1,40 +1,35 @@
|
|||
|
||||
USING: kernel namespaces sequences assocs builder continuations
|
||||
vocabs vocabs.loader
|
||||
io
|
||||
io.files
|
||||
prettyprint
|
||||
tools.vocabs
|
||||
tools.test
|
||||
io.encodings.utf8
|
||||
combinators.cleave
|
||||
! USING: kernel namespaces sequences assocs continuations
|
||||
! vocabs vocabs.loader
|
||||
! io
|
||||
! io.files
|
||||
! prettyprint
|
||||
! tools.vocabs
|
||||
! tools.test
|
||||
! io.encodings.utf8
|
||||
! combinators.cleave
|
||||
! help.lint
|
||||
! bootstrap.stage2 benchmark builder.util ;
|
||||
|
||||
USING: kernel namespaces assocs
|
||||
io.files io.encodings.utf8 prettyprint
|
||||
help.lint
|
||||
bootstrap.stage2 benchmark builder.util ;
|
||||
benchmark
|
||||
bootstrap.stage2
|
||||
tools.test tools.vocabs
|
||||
builder.util ;
|
||||
|
||||
IN: builder.test
|
||||
|
||||
: do-load ( -- )
|
||||
try-everything keys "../load-everything-vocabs" utf8 [ . ] with-file-writer ;
|
||||
|
||||
! : do-tests ( -- )
|
||||
! run-all-tests keys "../test-all-vocabs" utf8 [ . ] with-file-writer ;
|
||||
|
||||
: do-tests ( -- )
|
||||
run-all-tests
|
||||
[ keys "../test-all-vocabs" utf8 [ . ] with-file-writer ]
|
||||
[ "../test-failures" utf8 [ test-failures. ] with-file-writer ]
|
||||
bi ;
|
||||
|
||||
! : do-tests ( -- )
|
||||
! run-all-tests
|
||||
! "../test-all-vocabs" utf8
|
||||
! [
|
||||
! [ keys . ]
|
||||
! [ test-failures. ]
|
||||
! bi
|
||||
! ]
|
||||
! with-file-writer ;
|
||||
|
||||
: do-help-lint ( -- )
|
||||
"" run-help-lint "../help-lint" utf8 [ typos. ] with-file-writer ;
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Joe Groff
|
|
@ -1 +0,0 @@
|
|||
Stanford Bunny rendered with a cel-shading GLSL program
|
|
@ -1,3 +0,0 @@
|
|||
demos
|
||||
opengl
|
||||
glsl
|
|
@ -10,7 +10,7 @@ CLASS: {
|
|||
"foo:"
|
||||
"void"
|
||||
{ "id" "SEL" "NSRect" }
|
||||
[ data-gc "x" set 2drop ]
|
||||
[ gc "x" set 2drop ]
|
||||
} ;
|
||||
|
||||
: test-foo
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue