<plist version="1.0">
<dict>
<key>IBFramework Version</key>
- <string>629</string>
+ <string>677</string>
<key>IBOldestOS</key>
<integer>5</integer>
<key>IBOpenObjects</key>
- <array>
- <integer>305</integer>
- </array>
+ <array/>
<key>IBSystem Version</key>
- <string>9G55</string>
+ <string>9J61</string>
<key>targetFramework</key>
<string>IBCocoaFramework</string>
</dict>
-{
- IBClasses = (
- {
- ACTIONS = {
- newFactorWorkspace = id;
- runFactorFile = id;
- saveFactorImage = id;
- saveFactorImageAs = id;
- showFactorHelp = id;
- };
- CLASS = FirstResponder;
- LANGUAGE = ObjC;
- SUPERCLASS = NSObject;
- }
- );
- IBVersion = 1;
-}
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBClasses</key>
+ <array>
+ <dict>
+ <key>ACTIONS</key>
+ <dict>
+ <key>newFactorWorkspace</key>
+ <string>id</string>
+ <key>runFactorFile</key>
+ <string>id</string>
+ <key>saveFactorImage</key>
+ <string>id</string>
+ <key>saveFactorImageAs</key>
+ <string>id</string>
+ <key>showFactorHelp</key>
+ <string>id</string>
+ </dict>
+ <key>CLASS</key>
+ <string>FirstResponder</string>
+ <key>LANGUAGE</key>
+ <string>ObjC</string>
+ <key>SUPERCLASS</key>
+ <string>NSObject</string>
+ </dict>
+ </array>
+ <key>IBVersion</key>
+ <string>1</string>
+</dict>
+</plist>
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>IBDocumentLocation</key>
- <string>1266 155 525 491 0 0 2560 1578 </string>
- <key>IBEditorPositions</key>
- <dict>
- <key>29</key>
- <string>326 905 270 44 0 0 2560 1578 </string>
- </dict>
<key>IBFramework Version</key>
- <string>439.0</string>
+ <string>677</string>
+ <key>IBOldestOS</key>
+ <integer>5</integer>
<key>IBOpenObjects</key>
<array>
- <integer>29</integer>
+ <integer>293</integer>
</array>
<key>IBSystem Version</key>
- <string>8R218</string>
+ <string>9J61</string>
+ <key>targetFramework</key>
+ <string>IBCocoaFramework</string>
</dict>
</plist>
Pango, X11, and OpenGL. On a Debian-derived Linux distribution
(like Ubuntu), you can use the following line to grab everything:
- sudo apt-get install libc6-dev libpango-1.0-dev libx11-dev
+ sudo apt-get install libc6-dev libpango1.0-dev libx11-dev libgl1-mesa-dev
+
+Note that if you are using a proprietary OpenGL driver, you should
+probably leave out the last package in the list.
If your DISPLAY environment variable is set, the UI will start
-automatically:
+automatically when you run Factor:
./factor
-IN: alarms.tests\r
USING: alarms alarms.private kernel calendar sequences\r
tools.test threads concurrency.count-downs ;\r
+IN: alarms.tests\r
\r
[ ] [\r
1 <count-down>\r
! Copyright (C) 2005, 2008 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays calendar combinators generic init
-kernel math namespaces sequences heaps boxes threads
-quotations assocs math.order ;
+USING: accessors assocs boxes calendar
+combinators.short-circuit fry heaps init kernel math.order
+namespaces quotations threads ;
IN: alarms
TUPLE: alarm
ERROR: bad-alarm-frequency frequency ;
: check-alarm ( frequency/f -- frequency/f )
- dup [ duration? ] [ not ] bi or [ bad-alarm-frequency ] unless ;
+ dup { [ duration? ] [ not ] } 1|| [ bad-alarm-frequency ] unless ;
: <alarm> ( quot time frequency -- alarm )
check-alarm <box> alarm boa ;
: register-alarm ( alarm -- )
- dup dup time>> alarms get-global heap-push*
- swap entry>> >box
+ [ dup time>> alarms get-global heap-push* ]
+ [ entry>> >box ] bi
notify-alarm-thread ;
: alarm-expired? ( alarm now -- ? )
[ time>> ] dip before=? ;
: reschedule-alarm ( alarm -- )
- dup [ swap interval>> time+ now max ] change-time register-alarm ;
+ dup '[ _ interval>> time+ now max ] change-time register-alarm ;
: call-alarm ( alarm -- )
[ entry>> box> drop ]
ARTICLE: "c-arrays" "C arrays"\r
"C arrays are allocated in the same manner as other C data; see " { $link "c-byte-arrays" } " and " { $link "malloc" } "."\r
$nl\r
-"C type specifiers for array types are documented in " { $link "c-types-specs" } "." ;\r
+"C type specifiers for array types are documented in " { $link "c-types-specs" } "."\r
+$nl\r
+"Specialized sequences are provided for accessing memory as an array of primitive type values. These sequences are implemented in the " { $vocab-link "specialized-arrays" } " and " { $vocab-link "specialized-arrays.direct" } " vocabulary sets. They can also be loaded and constructed through their primitive C types:"\r
+{ $subsection require-c-type-arrays }\r
+{ $subsection <c-type-array> }\r
+{ $subsection <c-type-direct-array> } ;\r
M: array c-type-class drop object ;
+M: array c-type-boxed-class drop object ;
+
M: array heap-size unclip [ product ] [ heap-size ] bi* * ;
M: array c-type-align first c-type-align ;
M: array stack-size drop "void*" stack-size ;
-M: array c-type-boxer-quot drop [ ] ;
+M: array c-type-boxer-quot
+ unclip
+ [ product ]
+ [ [ require-c-type-arrays ] keep ] bi*
+ [ <c-type-direct-array> ] 2curry ;
M: array c-type-unboxer-quot drop [ >c-ptr ] ;
-M: value-type c-type-reg-class drop int-regs ;
+M: value-type c-type-rep drop int-rep ;
M: value-type c-type-getter
drop [ swap <displaced-alien> ] ;
M: string-type c-type ;
-M: string-type c-type-class
- drop object ;
+M: string-type c-type-class drop object ;
+
+M: string-type c-type-boxed-class drop object ;
M: string-type heap-size
drop "void*" heap-size ;
M: string-type stack-size
drop "void*" stack-size ;
-M: string-type c-type-reg-class
- drop int-regs ;
+M: string-type c-type-rep
+ drop int-rep ;
M: string-type c-type-boxer
drop "void*" c-type-boxer ;
IN: alien.c-types
USING: alien help.syntax help.markup libc kernel.private
byte-arrays math strings hashtables alien.syntax alien.strings sequences
-io.encodings.string debugger destructors ;
+io.encodings.string debugger destructors vocabs.loader ;
HELP: <c-type>
{ $values { "type" hashtable } }
}
} ;
+HELP: require-c-type-arrays
+{ $values { "c-type" "a C type" } }
+{ $description { $link require } "s any unloaded vocabularies needed to construct a specialized array or direct array of " { $snippet "c-type" } " using the " { $link <c-type-array> } " or " { $link <c-type-direct-array> } " vocabularies." }
+{ $notes "This word must be called inside a compilation unit. See the " { $vocab-link "specialized-arrays" } " and " { $vocab-link "specialized-arrays.direct" } " vocabulary sets for details on the underlying sequence types loaded." } ;
+
+HELP: <c-type-array>
+{ $values { "len" integer } { "c-type" "a C type" } { "array" "a specialized array" } }
+{ $description "Constructs a new specialized array of length " { $snippet "len" } " and element type " { $snippet "c-type" } "." }
+{ $notes "The appropriate specialized array vocabulary must be loaded; otherwise, a " { $link specialized-array-vocab-not-loaded } " error will be thrown. The vocabulary can be loaded with a " { $link POSTPONE: USING: } " form as usual, or with the " { $link require-c-type-arrays } " word. See the " { $vocab-link "specialized-arrays" } " vocabulary set for details on the underlying sequence type constructed." } ;
+
+HELP: <c-type-direct-array>
+{ $values { "alien" c-ptr } { "len" integer } { "c-type" "a C type" } { "array" "a specialized direct array" } }
+{ $description "Constructs a new specialized array of length " { $snippet "len" } " and element type " { $snippet "c-type" } " over the range of memory referenced by " { $snippet "alien" } "." }
+{ $notes "The appropriate direct specialized array vocabulary must be loaded; otherwise, a " { $link specialized-array-vocab-not-loaded } " error will be thrown. The vocabulary can be loaded with a " { $link POSTPONE: USING: } " form as usual, or with the " { $link require-c-type-arrays } " word. See the " { $vocab-link "specialized-arrays.direct" } " vocabulary set for details on the underlying sequence type constructed." } ;
+
ARTICLE: "c-strings" "C strings"
"C string types are arrays with shape " { $snippet "{ \"char*\" encoding }" } ", where " { $snippet "encoding" } " is an encoding descriptor. The type " { $snippet "\"char*\"" } " is an alias for " { $snippet "{ \"char*\" utf8 }" } ". See " { $link "encodings-descriptors" } " for information about encoding descriptors."
$nl
-IN: alien.c-types.tests
USING: alien alien.syntax alien.c-types kernel tools.test
sequences system libc alien.strings io.encodings.utf8 ;
+IN: alien.c-types.tests
CONSTANT: xyz 123
cpu.architecture alien alien.accessors alien.strings quotations
layouts system compiler.units io io.files io.encodings.binary
io.streams.memory accessors combinators effects continuations fry
-classes ;
+classes vocabs vocabs.loader ;
IN: alien.c-types
DEFER: <int>
: little-endian? ( -- ? ) 1 <int> *char 1 = ; foldable
-TUPLE: c-type
+TUPLE: abstract-c-type
{ class class initial: object }
-boxer
+{ boxed-class class initial: object }
{ boxer-quot callable }
-unboxer
{ unboxer-quot callable }
{ getter callable }
{ setter callable }
-{ reg-class initial: int-regs }
size
align
+array-class
+array-constructor
+direct-array-class
+direct-array-constructor
+sequence-mixin-class ;
+
+TUPLE: c-type < abstract-c-type
+boxer
+unboxer
+{ rep initial: int-rep }
stack-align? ;
: <c-type> ( -- type )
] ?if
] if ;
+: ?require-word ( word/pair -- )
+ dup word? [ drop ] [ first require ] ?if ;
+
+GENERIC: require-c-type-arrays ( c-type -- )
+
+M: object require-c-type-arrays
+ drop ;
+
+M: c-type require-c-type-arrays
+ [ array-class>> ?require-word ]
+ [ sequence-mixin-class>> ?require-word ]
+ [ direct-array-class>> ?require-word ] tri ;
+
+M: string require-c-type-arrays
+ c-type require-c-type-arrays ;
+
+M: array require-c-type-arrays
+ first c-type require-c-type-arrays ;
+
+ERROR: specialized-array-vocab-not-loaded vocab word ;
+
+: c-type-array-constructor ( c-type -- word )
+ array-constructor>> dup array?
+ [ first2 specialized-array-vocab-not-loaded ] when ; foldable
+
+: c-type-direct-array-constructor ( c-type -- word )
+ direct-array-constructor>> dup array?
+ [ first2 specialized-array-vocab-not-loaded ] when ; foldable
+
+GENERIC: <c-type-array> ( len c-type -- array )
+M: object <c-type-array>
+ c-type-array-constructor execute( len -- array ) ; inline
+M: string <c-type-array>
+ c-type <c-type-array> ; inline
+M: array <c-type-array>
+ first c-type <c-type-array> ; inline
+
+GENERIC: <c-type-direct-array> ( alien len c-type -- array )
+M: object <c-type-direct-array>
+ c-type-direct-array-constructor execute( alien len -- array ) ; inline
+M: string <c-type-direct-array>
+ c-type <c-type-direct-array> ; inline
+M: array <c-type-direct-array>
+ first c-type <c-type-direct-array> ; inline
+
GENERIC: c-type-class ( name -- class )
-M: c-type c-type-class class>> ;
+M: abstract-c-type c-type-class class>> ;
M: string c-type-class c-type c-type-class ;
+GENERIC: c-type-boxed-class ( name -- class )
+
+M: abstract-c-type c-type-boxed-class boxed-class>> ;
+
+M: string c-type-boxed-class c-type c-type-boxed-class ;
+
GENERIC: c-type-boxer ( name -- boxer )
M: c-type c-type-boxer boxer>> ;
GENERIC: c-type-boxer-quot ( name -- quot )
-M: c-type c-type-boxer-quot boxer-quot>> ;
+M: abstract-c-type c-type-boxer-quot boxer-quot>> ;
M: string c-type-boxer-quot c-type c-type-boxer-quot ;
GENERIC: c-type-unboxer-quot ( name -- quot )
-M: c-type c-type-unboxer-quot unboxer-quot>> ;
+M: abstract-c-type c-type-unboxer-quot unboxer-quot>> ;
M: string c-type-unboxer-quot c-type c-type-unboxer-quot ;
-GENERIC: c-type-reg-class ( name -- reg-class )
+GENERIC: c-type-rep ( name -- rep )
-M: c-type c-type-reg-class reg-class>> ;
+M: c-type c-type-rep rep>> ;
-M: string c-type-reg-class c-type c-type-reg-class ;
+M: string c-type-rep c-type c-type-rep ;
GENERIC: c-type-getter ( name -- quot )
GENERIC: c-type-align ( name -- n )
-M: c-type c-type-align align>> ;
+M: abstract-c-type c-type-align align>> ;
M: string c-type-align c-type c-type-align ;
M: string c-type-stack-align? c-type c-type-stack-align? ;
: c-type-box ( n type -- )
- dup c-type-reg-class
- swap c-type-boxer [ "No boxer" throw ] unless*
+ [ c-type-rep ] [ c-type-boxer [ "No boxer" throw ] unless* ] bi
%box ;
: c-type-unbox ( n ctype -- )
- dup c-type-reg-class
- swap c-type-unboxer [ "No unboxer" throw ] unless*
+ [ c-type-rep ] [ c-type-unboxer [ "No unboxer" throw ] unless* ] bi
%unbox ;
GENERIC: box-parameter ( n ctype -- )
M: string heap-size c-type heap-size ;
-M: c-type heap-size size>> ;
+M: abstract-c-type heap-size size>> ;
GENERIC: stack-size ( type -- size ) foldable
: if-void ( type true false -- )
pick "void" = [ drop nip call ] [ nip call ] if ; inline
+: ?lookup ( vocab word -- word/pair )
+ over vocab [ swap lookup ] [ 2array ] if ;
+
+: set-array-class* ( c-type vocab-stem type-stem -- c-type )
+ {
+ [
+ [ "specialized-arrays." prepend ]
+ [ "-array" append ] bi* ?lookup >>array-class
+ ]
+ [
+ [ "specialized-arrays." prepend ]
+ [ "<" "-array>" surround ] bi* ?lookup >>array-constructor
+ ]
+ [
+ [ "specialized-arrays." prepend ]
+ [ "-sequence" append ] bi* ?lookup >>sequence-mixin-class
+ ]
+ [
+ [ "specialized-arrays.direct." prepend ]
+ [ "direct-" "-array" surround ] bi* ?lookup >>direct-array-class
+ ]
+ [
+ [ "specialized-arrays.direct." prepend ]
+ [ "<direct-" "-array>" surround ] bi* ?lookup >>direct-array-constructor
+ ]
+ } 2cleave ;
+
+: set-array-class ( c-type stem -- c-type )
+ dup set-array-class* ;
+
CONSTANT: primitive-types
{
"char" "uchar"
[
<c-type>
c-ptr >>class
+ c-ptr >>boxed-class
[ alien-cell ] >>getter
[ [ >c-ptr ] 2dip set-alien-cell ] >>setter
bootstrap-cell >>size
[ >c-ptr ] >>unboxer-quot
"box_alien" >>boxer
"alien_offset" >>unboxer
+ "alien" "void*" set-array-class*
"void*" define-primitive-type
<long-long-type>
integer >>class
+ integer >>boxed-class
[ alien-signed-8 ] >>getter
[ set-alien-signed-8 ] >>setter
8 >>size
8 >>align
"box_signed_8" >>boxer
"to_signed_8" >>unboxer
+ "longlong" set-array-class
"longlong" define-primitive-type
<long-long-type>
integer >>class
+ integer >>boxed-class
[ alien-unsigned-8 ] >>getter
[ set-alien-unsigned-8 ] >>setter
8 >>size
8 >>align
"box_unsigned_8" >>boxer
"to_unsigned_8" >>unboxer
+ "ulonglong" set-array-class
"ulonglong" define-primitive-type
<c-type>
integer >>class
+ integer >>boxed-class
[ alien-signed-cell ] >>getter
[ set-alien-signed-cell ] >>setter
bootstrap-cell >>size
bootstrap-cell >>align
"box_signed_cell" >>boxer
"to_fixnum" >>unboxer
+ "long" set-array-class
"long" define-primitive-type
<c-type>
integer >>class
+ integer >>boxed-class
[ alien-unsigned-cell ] >>getter
[ set-alien-unsigned-cell ] >>setter
bootstrap-cell >>size
bootstrap-cell >>align
"box_unsigned_cell" >>boxer
"to_cell" >>unboxer
+ "ulong" set-array-class
"ulong" define-primitive-type
<c-type>
integer >>class
+ integer >>boxed-class
[ alien-signed-4 ] >>getter
[ set-alien-signed-4 ] >>setter
4 >>size
4 >>align
"box_signed_4" >>boxer
"to_fixnum" >>unboxer
+ "int" set-array-class
"int" define-primitive-type
<c-type>
integer >>class
+ integer >>boxed-class
[ alien-unsigned-4 ] >>getter
[ set-alien-unsigned-4 ] >>setter
4 >>size
4 >>align
"box_unsigned_4" >>boxer
"to_cell" >>unboxer
+ "uint" set-array-class
"uint" define-primitive-type
<c-type>
fixnum >>class
+ fixnum >>boxed-class
[ alien-signed-2 ] >>getter
[ set-alien-signed-2 ] >>setter
2 >>size
2 >>align
"box_signed_2" >>boxer
"to_fixnum" >>unboxer
+ "short" set-array-class
"short" define-primitive-type
<c-type>
fixnum >>class
+ fixnum >>boxed-class
[ alien-unsigned-2 ] >>getter
[ set-alien-unsigned-2 ] >>setter
2 >>size
2 >>align
"box_unsigned_2" >>boxer
"to_cell" >>unboxer
+ "ushort" set-array-class
"ushort" define-primitive-type
<c-type>
fixnum >>class
+ fixnum >>boxed-class
[ alien-signed-1 ] >>getter
[ set-alien-signed-1 ] >>setter
1 >>size
1 >>align
"box_signed_1" >>boxer
"to_fixnum" >>unboxer
+ "char" set-array-class
"char" define-primitive-type
<c-type>
fixnum >>class
+ fixnum >>boxed-class
[ alien-unsigned-1 ] >>getter
[ set-alien-unsigned-1 ] >>setter
1 >>size
1 >>align
"box_unsigned_1" >>boxer
"to_cell" >>unboxer
+ "uchar" set-array-class
"uchar" define-primitive-type
<c-type>
1 >>align
"box_boolean" >>boxer
"to_boolean" >>unboxer
+ "bool" set-array-class
"bool" define-primitive-type
<c-type>
float >>class
+ float >>boxed-class
[ alien-float ] >>getter
[ [ >float ] 2dip set-alien-float ] >>setter
4 >>size
4 >>align
"box_float" >>boxer
"to_float" >>unboxer
- single-float-regs >>reg-class
+ single-float-rep >>rep
[ >float ] >>unboxer-quot
+ "float" set-array-class
"float" define-primitive-type
<c-type>
float >>class
+ float >>boxed-class
[ alien-double ] >>getter
[ [ >float ] 2dip set-alien-double ] >>setter
8 >>size
8 >>align
"box_double" >>boxer
"to_double" >>unboxer
- double-float-regs >>reg-class
+ double-float-rep >>rep
[ >float ] >>unboxer-quot
+ "double" set-array-class
"double" define-primitive-type
"long" "ptrdiff_t" typedef
"long" "intptr_t" typedef
"ulong" "size_t" typedef
] with-compilation-unit
+
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test alien.complex kernel alien.c-types alien.syntax
-namespaces ;
+namespaces math ;
IN: alien.complex.tests
C-STRUCT: complex-holder
] unit-test
[ C{ 1.0 2.0 } ] [ "h" get complex-holder-z ] unit-test
+
+[ number ] [ "complex-float" c-type-boxed-class ] unit-test
+
+[ number ] [ "complex-double" c-type-boxed-class ] unit-test
\ No newline at end of file
! This overrides the fact that small structures are never returned
! in registers on NetBSD, Linux and Solaris running on 32-bit x86.
"complex-float" c-type t >>return-in-registers? drop
- >>
+>>
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test alien.complex.functor ;
-IN: alien.complex.functor.tests
T c-type
<T> 1quotation >>unboxer-quot
*T 1quotation >>boxer-quot
+number >>boxed-class
+T set-array-class
drop
;FUNCTOR
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test alien.destructors ;
-IN: alien.destructors.tests
effects generalizations sequences ;
IN: alien.destructors
-SLOT: alien
+TUPLE: alien-destructor alien ;
FUNCTOR: define-destructor ( F -- )
WHERE
-TUPLE: F-destructor alien disposed ;
+TUPLE: F-destructor < alien-destructor ;
-: <F-destructor> ( alien -- destructor ) f F-destructor boa ; inline
+: <F-destructor> ( alien -- destructor )
+ F-destructor boa ; inline
-M: F-destructor dispose* alien>> F N ndrop ;
+M: F-destructor dispose alien>> F N ndrop ;
: &F ( alien -- alien ) dup <F-destructor> &dispose drop ; inline
: (shuffle-map) ( return parameters -- ret par )
[
- fortran-ret-type>c-type length swap "void" = [ 1+ ] unless
+ fortran-ret-type>c-type length swap "void" = [ 1 + ] unless
letters swap head [ "ret" swap suffix ] map
] [
- [ fortran-arg-type>c-type nip length 1+ ] map letters swap zip
+ [ fortran-arg-type>c-type nip length 1 + ] map letters swap zip
[ first2 letters swap head [ "" 2sequence ] with map ] map concat
] bi* ;
: (fortran-in-shuffle) ( ret par -- seq )
- [ [ second ] bi@ <=> ] sort append ;
+ [ second ] sort-with append ;
: (fortran-out-shuffle) ( ret par -- seq )
append ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.syntax assocs help.markup
-help.syntax io.backend kernel namespaces ;
+help.syntax io.backend kernel namespaces strings ;
IN: alien.libraries
HELP: <library>
{ $description "A global hashtable that keeps a list of open libraries. Use the " { $link add-library } " word to construct a library and add it with a single call." } ;
HELP: library
-{ $values { "name" "a string" } { "library" assoc } }
+{ $values { "name" string } { "library" assoc } }
{ $description "Looks up a library by its logical name. The library object is a hashtable with the following keys:"
{ $list
{ { $snippet "name" } " - the full path of the C library binary" }
{ $description "Closes a DLL handle created by " { $link dlopen } ". This word might not be implemented on all platforms." } ;
HELP: load-library
-{ $values { "name" "a string" } { "dll" "a DLL handle" } }
+{ $values { "name" string } { "dll" "a DLL handle" } }
{ $description "Loads a library by logical name and outputs a handle which may be passed to " { $link dlsym } " or " { $link dlclose } ". If the library is already loaded, returns the existing handle." } ;
HELP: add-library
-{ $values { "name" "a string" } { "path" "a string" } { "abi" "one of " { $snippet "\"cdecl\"" } " or " { $snippet "\"stdcall\"" } } }
+{ $values { "name" string } { "path" string } { "abi" "one of " { $snippet "\"cdecl\"" } " or " { $snippet "\"stdcall\"" } } }
{ $description "Defines a new logical library named " { $snippet "name" } " located in the file system at " { $snippet "path" } "and the specified ABI." }
{ $notes "Because the entire source file is parsed before top-level forms are executed, " { $link add-library } " cannot be used in the same file as " { $link POSTPONE: FUNCTION: } " definitions from that library. The " { $link add-library } " call will happen too late, after compilation, and the alien calls will not work."
$nl
}
"Note the parse time evaluation with " { $link POSTPONE: << } "." } ;
+HELP: remove-library
+{ $values { "name" string } }
+{ $description "Unloads a library and removes it from the internal list of libraries. The " { $snippet "name" } " parameter should be a name that was previously passed to " { $link add-library } ". If no library with that name exists, this word does nothing." } ;
+
ARTICLE: "loading-libs" "Loading native libraries"
"Before calling a C library, you must associate its path name on disk with a logical name which Factor uses to identify the library:"
{ $subsection add-library }
+{ $subsection remove-library }
"Once a library has been defined, you can try loading it to see if the path name is correct:"
{ $subsection load-library }
"If the compiler cannot load a library, or cannot resolve a symbol in a library, a linkage error is reported using the compiler error mechanism (see " { $link "compiler-errors" } "). Once you install the right library, reload the source file containing the " { $link add-library } " form to force the compiler to try loading the library again." ;
--- /dev/null
+USING: alien.libraries alien.syntax tools.test kernel ;
+IN: alien.libraries.tests
+
+[ f ] [ DLL" fadfasdfsada" dll-valid? ] unit-test
+
+[ f ] [ "does not exist" DLL" fadsfasfdsaf" dlsym ] unit-test
+
+[ ] [ "doesnotexist" dlopen dlclose ] unit-test
+
+[ "fdasfsf" dll-valid? drop ] must-fail
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien alien.strings assocs io.backend kernel namespaces ;
+USING: accessors alien alien.strings assocs io.backend
+kernel namespaces destructors ;
IN: alien.libraries
: dlopen ( path -- dll ) native-string>alien (dlopen) ;
: load-library ( name -- dll )
library dup [ dll>> ] when ;
+M: dll dispose dlclose ;
+
+M: library dispose dll>> [ dispose ] when* ;
+
+: remove-library ( name -- )
+ libraries get delete-at* [ dispose ] [ drop ] if ;
+
: add-library ( name path abi -- )
- <library> swap libraries get set-at ;
\ No newline at end of file
+ [ 2drop remove-library ]
+ [ <library> swap libraries get set-at ] 3bi ;
\ No newline at end of file
-! Copyright (C) 2008, 2009 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types arrays assocs effects grouping kernel
-parser sequences splitting words fry locals lexer namespaces ;
+parser sequences splitting words fry locals lexer namespaces
+summary math ;
IN: alien.parser
+: normalize-c-arg ( type name -- type' name' )
+ [ length ]
+ [
+ [ CHAR: * = ] trim-head
+ [ length - CHAR: * <array> append ] keep
+ ] bi ;
+
: parse-arglist ( parameters return -- types effect )
- [ 2 group unzip [ "," ?tail drop ] map ]
+ [
+ 2 group [ first2 normalize-c-arg 2array ] map
+ unzip [ "," ?tail drop ] map
+ ]
[ [ { } ] [ 1array ] if-void ]
bi* <effect> ;
: function-quot ( return library function types -- quot )
'[ _ _ _ _ alien-invoke ] ;
-:: make-function ( return library function parameters -- word quot effect )
+:: make-function ( return! library function! parameters -- word quot effect )
+ return function normalize-c-arg function! return!
function create-in dup reset-generic
return library function
parameters return parse-arglist [ function-quot ] dip ;
}
"C structure objects can be allocated by calling " { $link <c-object> } " or " { $link malloc-object } "."
$nl
-"Arrays of C structures can be created by calling " { $link <c-array> } " or " { $link malloc-array } ". Elements can be read and written using words named " { $snippet { $emphasis "type" } "-nth" } " and " { $snippet "set-" { $emphasis "type" } "-nth" } "; these words are automatically generated by " { $link POSTPONE: C-STRUCT: } "." ;
+"Arrays of C structures can be created with the " { $vocab-link "struct-arrays" } " vocabulary." ;
ARTICLE: "c-unions" "C unions"
"A " { $snippet "union" } " in C defines a type large enough to hold its largest member. This is usually used to allocate a block of memory which can hold one of several types of values."
{ $subsection POSTPONE: C-UNION: }
"C union objects can be allocated by calling " { $link <c-object> } " or " { $link malloc-object } "."
$nl
-"Arrays of C unions can be created by calling " { $link <c-array> } " or " { $link malloc-array } ". Elements can be read and written using words named " { $snippet { $emphasis "type" } "-nth" } " and " { $snippet "set-" { $emphasis "type" } "-nth" } "; these words are automatically generated by " { $link POSTPONE: C-UNION: } "." ;
+"Arrays of C unions can be created with the " { $vocab-link "struct-arrays" } " vocabulary." ;
\ No newline at end of file
-IN: alien.structs.tests
USING: alien alien.syntax alien.c-types kernel tools.test
sequences system libc words vocabs namespaces layouts ;
+IN: alien.structs.tests
C-STRUCT: bar
{ "int" "x" }
quotations byte-arrays ;
IN: alien.structs
-TUPLE: struct-type
-size
-align
-fields
-{ boxer-quot callable }
-{ unboxer-quot callable }
-{ getter callable }
-{ setter callable }
-return-in-registers? ;
+TUPLE: struct-type < abstract-c-type fields return-in-registers? ;
M: struct-type c-type ;
-M: struct-type heap-size size>> ;
-
-M: struct-type c-type-class drop byte-array ;
-
-M: struct-type c-type-align align>> ;
-
M: struct-type c-type-stack-align? drop f ;
-M: struct-type c-type-boxer-quot boxer-quot>> ;
-
-M: struct-type c-type-unboxer-quot unboxer-quot>> ;
-
: if-value-struct ( ctype true false -- )
[ dup value-struct? ] 2dip '[ drop "void*" @ ] if ; inline
: c-struct? ( type -- ? ) (c-type) struct-type? ;
-: (define-struct) ( name size align fields -- )
- [ [ align ] keep ] dip
- struct-type new
+: (define-struct) ( name size align fields class -- )
+ [ [ align ] keep ] 2dip new
+ byte-array >>class
+ byte-array >>boxed-class
swap >>fields
swap >>align
swap >>size
[ 2drop ] [ make-fields ] 3bi
[ struct-offsets ] keep
[ [ type>> ] map compute-struct-align ] keep
- [ (define-struct) ] keep
+ [ struct-type (define-struct) ] keep
[ define-field ] each ;
: define-union ( name members -- )
[ expand-constants ] map
[ [ heap-size ] [ max ] map-reduce ] keep
- compute-struct-align f (define-struct) ;
+ compute-struct-align f struct-type (define-struct) ;
: offset-of ( field struct -- offset )
c-types get at fields>>
[ name>> = ] with find nip offset>> ;
+
+USE: vocabs.loader
+"struct-arrays" require
";" parse-tokens
[ [ create-in ] dip define-constant ] each-index ;
+ERROR: no-such-symbol name library ;
+
: address-of ( name library -- value )
- load-library dlsym [ "No such symbol" throw ] unless* ;
+ 2dup load-library dlsym [ 2nip ] [ no-such-symbol ] if* ;
SYNTAX: &:
scan "c-library" get '[ _ _ address-of ] over push-all ;
[ 4 ] [
0 "There are Four Upper Case characters"
- [ LETTER? [ 1+ ] when ] each
+ [ LETTER? [ 1 + ] when ] each
] unit-test
[ t f ] [ CHAR: \s ascii? 400 ascii? ] unit-test
: write1-lines ( ch -- )
write1
column get [
- 1+ [ 76 = [ crlf ] when ]
+ 1 + [ 76 = [ crlf ] when ]
[ 76 mod column set ] bi
] when* ;
: encode-pad ( seq n -- )
[ 3 0 pad-tail binary [ encode3 ] with-byte-writer ]
- [ 1+ ] bi* head-slice 4 CHAR: = pad-tail write-lines ; inline
+ [ 1 + ] bi* head-slice 4 CHAR: = pad-tail write-lines ; inline
: decode4 ( seq -- )
[ 0 [ base64>ch swap 6 shift bitor ] reduce 3 >be ]
+USING: biassocs assocs namespaces tools.test hashtables kernel ;
IN: biassocs.tests
-USING: biassocs assocs namespaces tools.test ;
<bihash> "h" set
[ "A" ] [ "a" "b" get at ] unit-test
-[ "a" ] [ "A" "b" get value-at ] unit-test
\ No newline at end of file
+[ "a" ] [ "A" "b" get value-at ] unit-test
+
+[ ] [ H{ { 1 2 } } >biassoc "h" set ] unit-test
+
+[ ] [ "h" get clone "g" set ] unit-test
+
+[ ] [ 3 4 "g" get set-at ] unit-test
+
+[ H{ { 1 2 } } ] [ "h" get >hashtable ] unit-test
+
+[ H{ { 1 2 } { 4 3 } } ] [ "g" get >hashtable ] unit-test
INSTANCE: biassoc assoc
: >biassoc ( assoc -- biassoc )
- T{ biassoc } assoc-clone-like ;
\ No newline at end of file
+ T{ biassoc } assoc-clone-like ;
+
+M: biassoc clone
+ [ from>> ] [ to>> ] bi [ clone ] bi@ biassoc boa ;
-IN: binary-search.tests
USING: binary-search math.order vectors kernel tools.test ;
+IN: binary-search.tests
[ f ] [ 3 { } [ <=> ] with search drop ] unit-test
[ 0 ] [ 3 { 3 } [ <=> ] with search drop ] unit-test
[ 4 ] [ 5.5 { 1 2 3 4 5 6 7 8 } [ <=> ] with search drop ] unit-test
[ 10 ] [ 10 20 >vector [ <=> ] with search drop ] unit-test
-[ t ] [ "hello" { "alligrator" "cat" "fish" "hello" "ikarus" "java" } sorted-member? ] unit-test
-[ 3 ] [ "hey" { "alligrator" "cat" "fish" "hello" "ikarus" "java" } sorted-index ] unit-test
-[ f ] [ "hello" { "alligrator" "cat" "fish" "ikarus" "java" } sorted-member? ] unit-test
-[ f ] [ "zebra" { "alligrator" "cat" "fish" "ikarus" "java" } sorted-member? ] unit-test
+[ t ] [ "hello" { "alligator" "cat" "fish" "hello" "ikarus" "java" } sorted-member? ] unit-test
+[ 3 ] [ "hey" { "alligator" "cat" "fish" "hello" "ikarus" "java" } sorted-index ] unit-test
+[ f ] [ "hello" { "alligator" "cat" "fish" "ikarus" "java" } sorted-member? ] unit-test
+[ f ] [ "zebra" { "alligator" "cat" "fish" "ikarus" "java" } sorted-member? ] unit-test
[ [ length bits>cells ] keep ] dip swap underlying>>
'[ 2 shift [ _ _ ] dip set-alien-unsigned-4 ] each ; inline
+: clean-up ( bit-array -- )
+ ! Zero bits after the end.
+ dup underlying>> empty? [ drop ] [
+ [
+ [ underlying>> length 8 * ] [ length ] bi -
+ 8 swap - -1 swap shift bitnot
+ ]
+ [ underlying>> last bitand ]
+ [ underlying>> set-last ]
+ tri
+ ] if ; inline
+
PRIVATE>
: <bit-array> ( n -- bit-array )
dup bits>bytes <byte-array> bit-array boa ; inline
-M: bit-array length length>> ;
+M: bit-array length length>> ; inline
M: bit-array nth-unsafe
- [ >fixnum ] [ underlying>> ] bi* byte/bit bit? ;
+ [ >fixnum ] [ underlying>> ] bi* byte/bit bit? ; inline
M: bit-array set-nth-unsafe
[ >fixnum ] [ underlying>> ] bi*
[ byte/bit set-bit ] 2keep
- swap n>byte set-alien-unsigned-1 ;
+ swap n>byte set-alien-unsigned-1 ; inline
+
+GENERIC: clear-bits ( bit-array -- )
+
+M: bit-array clear-bits 0 (set-bits) ; inline
-: clear-bits ( bit-array -- ) 0 (set-bits) ;
+GENERIC: set-bits ( bit-array -- )
-: set-bits ( bit-array -- ) -1 (set-bits) ;
+M: bit-array set-bits -1 (set-bits) ; inline
M: bit-array clone
- [ length>> ] [ underlying>> clone ] bi bit-array boa ;
+ [ length>> ] [ underlying>> clone ] bi bit-array boa ; inline
: >bit-array ( seq -- bit-array )
T{ bit-array f 0 B{ } } clone-like ; inline
-M: bit-array like drop dup bit-array? [ >bit-array ] unless ;
+M: bit-array like drop dup bit-array? [ >bit-array ] unless ; inline
-M: bit-array new-sequence drop <bit-array> ;
+M: bit-array new-sequence drop <bit-array> ; inline
M: bit-array equal?
- over bit-array? [ sequence= ] [ 2drop f ] if ;
+ over bit-array? [ [ underlying>> ] bi@ sequence= ] [ 2drop f ] if ;
M: bit-array resize
[ drop ] [
[ bits>bytes ] [ underlying>> ] bi*
resize-byte-array
] 2bi
- bit-array boa ;
+ bit-array boa
+ dup clean-up ; inline
M: bit-array byte-length length 7 + -3 shift ;
dup 0 = [
<bit-array>
] [
- [ log2 1+ <bit-array> 0 ] keep
+ [ log2 1 + <bit-array> 0 ] keep
[ dup 0 = ] [
[ pick underlying>> pick set-alien-unsigned-1 ] keep
- [ 1+ ] [ -8 shift ] bi*
+ [ 1 + ] [ -8 shift ] bi*
] until 2drop
] if ;
--- /dev/null
+Slava Pestov
--- /dev/null
+USING: bit-sets tools.test bit-arrays ;
+IN: bit-sets.tests
+
+[ ?{ t f t f t f } ] [
+ ?{ t f f f t f }
+ ?{ f f t f t f } bit-set-union
+] unit-test
+
+[ ?{ f f f f t f } ] [
+ ?{ t f f f t f }
+ ?{ f f t f t f } bit-set-intersect
+] unit-test
+
+[ ?{ t f t f f f } ] [
+ ?{ t t t f f f }
+ ?{ f t f f t t } bit-set-diff
+] unit-test
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors sequences byte-arrays bit-arrays math hints ;
+IN: bit-sets
+
+<PRIVATE
+
+: bit-set-map ( seq1 seq2 quot -- seq )
+ [ 2drop length>> ]
+ [
+ [
+ [ [ length ] bi@ assert= ]
+ [ [ underlying>> ] bi@ ] 2bi
+ ] dip 2map
+ ] 3bi bit-array boa ; inline
+
+PRIVATE>
+
+: bit-set-union ( seq1 seq2 -- seq ) [ bitor ] bit-set-map ;
+
+HINTS: bit-set-union bit-array bit-array ;
+
+: bit-set-intersect ( seq1 seq2 -- seq ) [ bitand ] bit-set-map ;
+
+HINTS: bit-set-intersect bit-array bit-array ;
+
+: bit-set-diff ( seq1 seq2 -- seq ) [ bitnot bitand ] bit-set-map ;
+
+HINTS: bit-set-diff bit-array bit-array ;
+
+: bit-set-subset? ( seq1 seq2 -- ? ) dupd bit-set-intersect = ;
\ No newline at end of file
--- /dev/null
+Efficient bitwise operations on bit arrays
{ $description "The class of resizable bit vectors. See " { $link "bit-vectors" } " for information." } ;\r
\r
HELP: <bit-vector>\r
-{ $values { "n" "a positive integer specifying initial capacity" } { "bit-vector" bit-vector } }\r
+{ $values { "capacity" "a positive integer specifying initial capacity" } { "vector" bit-vector } }\r
{ $description "Creates a new bit vector that can hold " { $snippet "n" } " bits before resizing." } ;\r
\r
HELP: >bit-vector\r
-{ $values { "seq" "a sequence" } { "bit-vector" bit-vector } }\r
+{ $values { "seq" "a sequence" } { "vector" bit-vector } }\r
{ $description "Outputs a freshly-allocated bit vector with the same elements as a given sequence." } ;\r
\r
HELP: ?V{\r
-IN: bit-vectors.tests\r
USING: tools.test bit-vectors vectors sequences kernel math ;\r
+IN: bit-vectors.tests\r
\r
[ 0 ] [ 123 <bit-vector> length ] unit-test\r
\r
-! Copyright (C) 2008 Slava Pestov.\r
+! Copyright (C) 2008, 2009 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: arrays kernel kernel.private math sequences\r
sequences.private growable bit-arrays prettyprint.custom\r
-parser accessors ;\r
+parser accessors vectors.functor classes.parser ;\r
IN: bit-vectors\r
\r
-TUPLE: bit-vector\r
-{ underlying bit-array initial: ?{ } }\r
-{ length array-capacity } ;\r
-\r
-: <bit-vector> ( n -- bit-vector )\r
- <bit-array> 0 bit-vector boa ; inline\r
-\r
-: >bit-vector ( seq -- bit-vector )\r
- T{ bit-vector f ?{ } 0 } clone-like ;\r
-\r
-M: bit-vector like\r
- drop dup bit-vector? [\r
- dup bit-array?\r
- [ dup length bit-vector boa ] [ >bit-vector ] if\r
- ] unless ;\r
-\r
-M: bit-vector new-sequence\r
- drop [ <bit-array> ] [ >fixnum ] bi bit-vector boa ;\r
-\r
-M: bit-vector equal?\r
- over bit-vector? [ sequence= ] [ 2drop f ] if ;\r
-\r
-M: bit-array new-resizable drop <bit-vector> ;\r
-\r
-INSTANCE: bit-vector growable\r
+<< "bit-vector" create-class-in \ bit-array \ <bit-array> define-vector >>\r
\r
SYNTAX: ?V{ \ } [ >bit-vector ] parse-literal ;\r
\r
+M: bit-vector contract 2drop ;\r
M: bit-vector >pprint-sequence ;\r
M: bit-vector pprint-delims drop \ ?V{ \ } ;\r
M: bit-vector pprint* pprint-object ;\r
io.streams.byte-array ;
IN: bitstreams.tests
-
[ BIN: 1111111111 ]
[
B{ HEX: 0f HEX: ff HEX: ff HEX: ff } <msb0-bit-reader>
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.accessors assocs byte-arrays combinators
-constructors destructors fry io io.binary io.encodings.binary
-io.streams.byte-array kernel locals macros math math.ranges
-multiline sequences sequences.private vectors byte-vectors
-combinators.short-circuit math.bitwise ;
+destructors fry io io.binary io.encodings.binary io.streams.byte-array
+kernel locals macros math math.ranges multiline sequences
+sequences.private vectors byte-vectors combinators.short-circuit
+math.bitwise ;
IN: bitstreams
TUPLE: widthed { bits integer read-only } { #bits integer read-only } ;
TUPLE: msb0-bit-reader < bit-reader ;
TUPLE: lsb0-bit-reader < bit-reader ;
-CONSTRUCTOR: msb0-bit-reader ( bytes -- bs ) ;
-CONSTRUCTOR: lsb0-bit-reader ( bytes -- bs ) ;
+
+: <msb0-bit-reader> ( bytes -- bs )
+ msb0-bit-reader new swap >>bytes ; inline
+
+: <lsb0-bit-reader> ( bytes -- bs )
+ lsb0-bit-reader new swap >>bytes ; inline
TUPLE: msb0-bit-writer < bit-writer ;
TUPLE: lsb0-bit-writer < bit-writer ;
[ get-abp + ] [ set-abp ] bi ; inline
: (align) ( n m -- n' )
- [ /mod 0 > [ 1+ ] when ] [ * ] bi ; inline
+ [ /mod 0 > [ 1 + ] when ] [ * ] bi ; inline
: align ( n bitstream -- )
[ get-abp swap (align) ] [ set-abp ] bi ; inline
hashtables.private sequences.private math classes.tuple.private
growable namespaces.private assocs words command-line vocabs io
io.encodings.string libc splitting math.parser memory compiler.units
-math.order compiler.tree.builder compiler.tree.optimizer
-compiler.cfg.optimizer ;
-FROM: compiler => enable-optimizer compile-word ;
+math.order quotations quotations.private assocs.private ;
+FROM: compiler => enable-optimizer ;
IN: bootstrap.compiler
+"profile-compiler" get [
+ "bootstrap.compiler.timing" require
+] when
+
! Don't bring this in when deploying, since it will store a
! reference to 'eval' in a global variable
"deploy-vocab" get "staging" get or [
: compile-unoptimized ( words -- )
[ optimized? not ] filter compile ;
-nl
-"Compiling..." write flush
-
-! Compile a set of words ahead of the full compile.
-! This set of words was determined semi-empirically
-! using the profiler. It improves bootstrap time
-! significantly, because frequenly called words
-! which are also quick to compile are replaced by
-! compiled definitions as soon as possible.
-{
- not
-
- array? hashtable? vector?
- tuple? sbuf? tombstone?
-
- array-nth set-array-nth
-
- wrap probe
+"debug-compiler" get [
+
+ nl
+ "Compiling..." write flush
- namestack*
-} compile-unoptimized
+ ! Compile a set of words ahead of the full compile.
+ ! This set of words was determined semi-empirically
+ ! using the profiler. It improves bootstrap time
+ ! significantly, because frequenly called words
+ ! which are also quick to compile are replaced by
+ ! compiled definitions as soon as possible.
+ {
+ not ?
-"." write flush
+ 2over roll -roll
-{
- bitand bitor bitxor bitnot
-} compile-unoptimized
+ array? hashtable? vector?
+ tuple? sbuf? tombstone?
+ curry? compose? callable?
+ quotation?
-"." write flush
+ curry compose uncurry
-{
- + 1+ 1- 2/ < <= > >= shift
-} compile-unoptimized
+ array-nth set-array-nth length>>
-"." write flush
+ wrap probe
-{
- new-sequence nth push pop last flip
-} compile-unoptimized
+ namestack*
-"." write flush
+ layout-of
+ } compile-unoptimized
-{
- hashcode* = get set
-} compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ bitand bitor bitxor bitnot
+ } compile-unoptimized
-{
- memq? split harvest sift cut cut-slice start index clone
- set-at reverse push-all class number>string string>number
-} compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ + 2/ < <= > >= shift
+ } compile-unoptimized
-{
- lines prefix suffix unclip new-assoc update
- word-prop set-word-prop 1array 2array 3array ?nth
-} compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ new-sequence nth push pop last flip
+ } compile-unoptimized
-{
- malloc calloc free memcpy
-} compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ hashcode* = equal? assoc-stack (assoc-stack) get set
+ } compile-unoptimized
-{ build-tree } compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ memq? split harvest sift cut cut-slice start index clone
+ set-at reverse push-all class number>string string>number
+ like clone-like
+ } compile-unoptimized
-{ optimize-tree } compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ lines prefix suffix unclip new-assoc update
+ word-prop set-word-prop 1array 2array 3array ?nth
+ } compile-unoptimized
-{ optimize-cfg } compile-unoptimized
+ "." write flush
-"." write flush
+ {
+ malloc calloc free memcpy
+ } compile-unoptimized
-{ compile-word } compile-unoptimized
+ "." write flush
-"." write flush
+ vocabs [ words compile-unoptimized "." write flush ] each
-vocabs [ words compile-unoptimized "." write flush ] each
+ " done" print flush
-" done" print flush
+] unless
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel make sequences tools.annotations tools.crossref ;
+QUALIFIED: compiler.cfg.builder
+QUALIFIED: compiler.cfg.linear-scan
+QUALIFIED: compiler.cfg.mr
+QUALIFIED: compiler.cfg.optimizer
+QUALIFIED: compiler.cfg.stacks.finalize
+QUALIFIED: compiler.cfg.stacks.global
+QUALIFIED: compiler.codegen
+QUALIFIED: compiler.tree.builder
+QUALIFIED: compiler.tree.optimizer
+IN: bootstrap.compiler.timing
+
+: passes ( word -- seq )
+ def>> uses [ vocabulary>> "compiler." head? ] filter ;
+
+: high-level-passes ( -- seq ) \ compiler.tree.optimizer:optimize-tree passes ;
+
+: low-level-passes ( -- seq ) \ compiler.cfg.optimizer:optimize-cfg passes ;
+
+: machine-passes ( -- seq ) \ compiler.cfg.mr:build-mr passes ;
+
+: linear-scan-passes ( -- seq ) \ compiler.cfg.linear-scan:(linear-scan) passes ;
+
+: all-passes ( -- seq )
+ [
+ \ compiler.tree.builder:build-tree ,
+ \ compiler.tree.optimizer:optimize-tree ,
+ high-level-passes %
+ \ compiler.cfg.builder:build-cfg ,
+ \ compiler.cfg.stacks.global:compute-global-sets ,
+ \ compiler.cfg.stacks.finalize:finalize-stack-shuffling ,
+ \ compiler.cfg.optimizer:optimize-cfg ,
+ low-level-passes %
+ \ compiler.cfg.mr:build-mr ,
+ machine-passes %
+ linear-scan-passes %
+ \ compiler.codegen:generate ,
+ ] { } make ;
+
+all-passes [ [ reset ] [ add-timing ] bi ] each
\ No newline at end of file
-IN: bootstrap.image.tests
USING: bootstrap.image bootstrap.image.private tools.test
kernel math ;
+IN: bootstrap.image.tests
[ f ] [ { 1 2 3 } [ 1 2 3 ] eql? ] unit-test
! Object cache; we only consider numbers equal if they have the
! same type
-TUPLE: id obj ;
+TUPLE: eql-wrapper obj ;
-C: <id> id
+C: <eql-wrapper> eql-wrapper
-M: id hashcode* obj>> hashcode* ;
+M: eql-wrapper hashcode* obj>> hashcode* ;
GENERIC: (eql?) ( obj1 obj2 -- ? )
M: object (eql?) = ;
-M: id equal?
- over id? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
+M: eql-wrapper equal?
+ over eql-wrapper? [ [ obj>> ] bi@ eql? ] [ 2drop f ] if ;
+
+TUPLE: eq-wrapper obj ;
+
+C: <eq-wrapper> eq-wrapper
+
+M: eq-wrapper equal?
+ over eq-wrapper? [ [ obj>> ] bi@ eq? ] [ 2drop f ] if ;
SYMBOL: objects
-: (objects) ( obj -- id assoc ) <id> objects get ; inline
+: cache-eql-object ( obj quot -- value )
+ [ <eql-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
-: lookup-object ( obj -- n/f ) (objects) at ;
+: cache-eq-object ( obj quot -- value )
+ [ <eq-wrapper> objects get ] dip '[ obj>> @ ] cache ; inline
-: put-object ( n obj -- ) (objects) set-at ;
+: lookup-object ( obj -- n/f ) <eq-wrapper> objects get at ;
-: cache-object ( obj quot -- value )
- [ (objects) ] dip '[ obj>> @ ] cache ; inline
+: put-object ( n obj -- ) <eq-wrapper> objects get set-at ;
! Constants
: bignum-bits ( -- n ) bootstrap-cell-bits 2 - ;
-: bignum-radix ( -- n ) bignum-bits 2^ 1- ;
+: bignum-radix ( -- n ) bignum-bits 2^ 1 - ;
: bignum>seq ( n -- seq )
#! n is positive or zero.
: emit-bignum ( n -- )
dup dup 0 < [ neg ] when bignum>seq
- [ nip length 1+ emit-fixnum ]
+ [ nip length 1 + emit-fixnum ]
[ drop 0 < 1 0 ? emit ]
[ nip emit-seq ]
2tri ;
M: bignum '
[
bignum [ emit-bignum ] emit-object
- ] cache-object ;
+ ] cache-eql-object ;
! Fixnums
float [
align-here double>bits emit-64
] emit-object
- ] cache-object ;
+ ] cache-eql-object ;
! Special objects
! Wrappers
M: wrapper '
- wrapped>> ' wrapper [ emit ] emit-object ;
+ [ wrapped>> ' wrapper [ emit ] emit-object ] cache-eql-object ;
! Strings
: native> ( object -- object )
M: string '
#! We pool strings so that each string is only written once
#! to the image
- [ emit-string ] cache-object ;
+ [ emit-string ] cache-eql-object ;
: assert-empty ( seq -- )
length 0 assert= ;
] bi* ;
M: byte-array '
- byte-array [
- dup length emit-fixnum
- pad-bytes emit-bytes
- ] emit-object ;
+ [
+ byte-array [
+ dup length emit-fixnum
+ pad-bytes emit-bytes
+ ] emit-object
+ ] cache-eq-object ;
! Tuples
ERROR: tuple-removed class ;
: emit-tuple ( tuple -- pointer )
dup class name>> "tombstone" =
- [ [ (emit-tuple) ] cache-object ] [ (emit-tuple) ] if ;
+ [ [ (emit-tuple) ] cache-eql-object ]
+ [ [ (emit-tuple) ] cache-eq-object ]
+ if ;
M: tuple ' emit-tuple ;
M: tombstone '
state>> "((tombstone))" "((empty))" ?
"hashtables.private" lookup def>> first
- [ emit-tuple ] cache-object ;
+ [ emit-tuple ] cache-eql-object ;
! Arrays
: emit-array ( array -- offset )
[ ' ] map array [ [ length emit-fixnum ] [ emit-seq ] bi ] emit-object ;
-M: array ' emit-array ;
+M: array ' [ emit-array ] cache-eq-object ;
! This is a hack. We need to detect arrays which are tuple
! layout arrays so that they can be internalized, but making
[
[ dup integer? [ <fake-bignum> ] when ] map
emit-array
- ] cache-object ;
+ ] cache-eql-object ;
! Quotations
0 emit ! xt
0 emit ! code
] emit-object
- ] cache-object ;
+ ] cache-eql-object ;
! End of the image
SYMBOL: upload-images-destination
: destination ( -- dest )
- upload-images-destination get
- "slava@factorcode.org:/var/www/factorcode.org/newsite/images/latest/"
- or ;
+ upload-images-destination get
+ "slava@factorcode.org:/var/www/factorcode.org/newsite/images/latest/"
+ or ;
: checksums ( -- temp ) "checksums.txt" temp-file ;
"math.ratios" require
"math.floats" require
-"math.complex" require
\ No newline at end of file
+"math.complex" require
"tools.crossref"
"tools.errors"
"tools.deploy"
+ "tools.destructors"
"tools.disassembler"
"tools.memory"
"tools.profiler"
"tools.test"
"tools.time"
"tools.threads"
+ "tools.deprecation"
"vocabs.hierarchy"
"vocabs.refresh"
"vocabs.refresh.monitor"
-IN: boxes.tests\r
USING: boxes namespaces tools.test accessors ;\r
+IN: boxes.tests\r
\r
[ ] [ <box> "b" set ] unit-test\r
\r
--- /dev/null
+Maxim Savchenko
+Slava Pestov
--- /dev/null
+! Copyright (C) 2009 Maxim Savchenko, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: byte-arrays.hex
+USING: byte-arrays help.markup help.syntax ;
+
+HELP: HEX{
+{ $syntax "HEX{ 0123 45 67 89abcdef }" }
+{ $description "Constructs a " { $link byte-array } " from data specified in hexadecimal format. Whitespace between the curly braces is ignored." } ;
--- /dev/null
+! Copyright (C) 2009 Maxim Savchenko, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: grouping lexer ascii parser sequences kernel math.parser ;
+IN: byte-arrays.hex
+
+SYNTAX: HEX{
+ "}" parse-tokens "" join
+ [ blank? not ] filter
+ 2 group [ hex> ] B{ } map-as
+ parsed ;
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test cache ;
-IN: cache.tests
USING: kernel assocs math accessors destructors fry sequences ;
IN: cache
-TUPLE: cache-assoc assoc max-age disposed ;
+TUPLE: cache-assoc < disposable assoc max-age ;
: <cache-assoc> ( -- cache )
- H{ } clone 10 f cache-assoc boa ;
+ cache-assoc new-disposable H{ } clone >>assoc 10 >>max-age ;
<PRIVATE
: purge-cache ( cache -- )
dup max-age>> '[
- [ nip [ 1+ ] change-age age>> _ >= ] assoc-partition
+ [ nip [ 1 + ] change-age age>> _ >= ] assoc-partition
[ values dispose-each ] dip
- ] change-assoc drop ;
\ No newline at end of file
+ ] change-assoc drop ;
-IN: cairo.tests
USING: cairo tools.test math.rectangles accessors ;
+IN: cairo.tests
[ { 10 20 } ] [
{ 10 20 } [
{ 0 1 } { 3 4 } <rect> fill-rect
] make-bitmap-image dim>>
-] unit-test
\ No newline at end of file
+] unit-test
<cairo> &cairo_destroy
@
] make-memory-bitmap
- BGRA >>component-order ; inline
+ BGRA >>component-order
+ ubyte-components >>component-type ; inline
: dummy-cairo ( -- cr )
#! Sometimes we want a dummy context; eg with Pango, we want
cairo_pattern_get_rgba ( cairo_pattern_t* pattern, double* red, double* green, double* blue, double* alpha ) ;
FUNCTION: cairo_status_t
-cairo_pattern_get_surface ( cairo_pattern_t* pattern, cairo_surface_t* *surface ) ;
+cairo_pattern_get_surface ( cairo_pattern_t* pattern, cairo_surface_t** surface ) ;
FUNCTION: cairo_status_t
cairo_pattern_get_color_stop_rgba ( cairo_pattern_t* pattern, int index, double* offset, double* red, double* green, double* blue, double* alpha ) ;
{ $values { "year" integer } { "month" integer } { "day" integer } { "timestamp" timestamp } }
{ $description "Returns a timestamp object representing the start of the specified day in your current timezone." }
{ $examples
- { $example "USING: calendar prettyprint ;"
- "2010 12 25 <date> >gmt midnight ."
+ { $example "USING: accessors calendar prettyprint ;"
+ "2010 12 25 <date> instant >>gmt-offset ."
"T{ timestamp { year 2010 } { month 12 } { day 25 } }"
}
} ;
HELP: month-names
-{ $values { "array" array } }
+{ $values { "value" object } }
{ $description "Returns an array with the English names of all the months." }
{ $warning "Do not use this array for looking up a month name directly. Use month-name instead." } ;
: <date> ( year month day -- timestamp )
0 0 0 gmt-offset-duration <timestamp> ;
-ERROR: not-a-month n ;
+ERROR: not-a-month ;
M: not-a-month summary
drop "Months are indexed starting at 1" ;
<PRIVATE
: check-month ( n -- n )
- dup zero? [ not-a-month ] when ;
+ [ not-a-month ] when-zero ;
PRIVATE>
-: month-names ( -- array )
+CONSTANT: month-names
{
"January" "February" "March" "April" "May" "June"
"July" "August" "September" "October" "November" "December"
- } ;
+ }
: month-name ( n -- string )
- check-month 1- month-names nth ;
+ check-month 1 - month-names nth ;
CONSTANT: month-abbreviations
{
}
: month-abbreviation ( n -- string )
- check-month 1- month-abbreviations nth ;
+ check-month 1 - month-abbreviations nth ;
CONSTANT: day-counts { 0 31 28 31 30 31 30 31 31 30 31 30 31 }
100 b * d + 4800 -
m 10 /i + m 3 +
12 m 10 /i * -
- e 153 m * 2 + 5 /i - 1+ ;
+ e 153 m * 2 + 5 /i - 1 + ;
GENERIC: easter ( obj -- obj' )
{ [ day>> 29 = ] [ month>> 2 = ] [ leap-year? not ] } 1&&
[ 3 >>month 1 >>day ] when ;
-: unless-zero ( n quot -- )
- [ dup zero? [ drop ] ] dip if ; inline
-
M: integer +year ( timestamp n -- timestamp )
[ [ + ] curry change-year adjust-leap-year ] unless-zero ;
[ float>whole-part swapd days-per-year * +day swap +year ] unless-zero ;
: months/years ( n -- months years )
- 12 /rem dup zero? [ drop 1- 12 ] when swap ; inline
+ 12 /rem [ 1 - 12 ] when-zero swap ; inline
M: integer +month ( timestamp n -- timestamp )
[ over month>> + months/years [ >>month ] dip +year ] unless-zero ;
#! http://web.textfiles.com/computers/formulas.txt
#! good for any date since October 15, 1582
[
- dup 2 <= [ [ 1- ] [ 12 + ] bi* ] when
+ dup 2 <= [ [ 1 - ] [ 12 + ] bi* ] when
[ dup [ 4 /i + ] [ 100 /i - ] [ 400 /i + ] tri ] dip
- [ 1+ 3 * 5 /i + ] keep 2 * +
- ] dip 1+ + 7 mod ;
+ [ 1 + 3 * 5 /i + ] keep 2 * +
+ ] dip 1 + + 7 mod ;
GENERIC: days-in-year ( obj -- n )
year leap-year? [
year month day <date>
year 3 1 <date>
- after=? [ 1+ ] when
+ after=? [ 1 + ] when
] when ;
: day-of-year ( timestamp -- n )
[ (days-in-month) day-abbreviations2 " " join print ] 2tri\r
over " " <repetition> concat write\r
[\r
- [ 1+ day. ] keep\r
- 1+ + 7 mod zero? [ nl ] [ bl ] if\r
+ [ 1 + day. ] keep\r
+ 1 + + 7 mod zero? [ nl ] [ bl ] if\r
] with each nl ;\r
\r
M: timestamp month. ( timestamp -- )\r
GENERIC: year. ( obj -- )\r
\r
M: integer year. ( n -- )\r
- 12 [ 1+ 2array month. nl ] with each ;\r
+ 12 [ 1 + 2array month. nl ] with each ;\r
\r
M: timestamp year. ( timestamp -- )\r
year>> year. ;\r
\r
: read-rfc3339-seconds ( s -- s' ch )\r
"+-Z" read-until [\r
- [ string>number ] [ length 10 swap ^ ] bi / +\r
+ [ string>number ] [ length 10^ ] bi / +\r
] dip ;\r
\r
: (rfc3339>timestamp) ( -- timestamp )\r
"," read-token day-abbreviations3 member? check-timestamp drop\r
read1 CHAR: \s assert=\r
read-sp checked-number >>day\r
- read-sp month-abbreviations index 1+ check-timestamp >>month\r
+ read-sp month-abbreviations index 1 + check-timestamp >>month\r
read-sp checked-number >>year\r
":" read-token checked-number >>hour\r
":" read-token checked-number >>minute\r
"," read-token check-day-name\r
read1 CHAR: \s assert=\r
"-" read-token checked-number >>day\r
- "-" read-token month-abbreviations index 1+ check-timestamp >>month\r
+ "-" read-token month-abbreviations index 1 + check-timestamp >>month\r
read-sp checked-number >>year\r
":" read-token checked-number >>hour\r
":" read-token checked-number >>minute\r
: (cookie-string>timestamp-2) ( -- timestamp )\r
timestamp new\r
read-sp check-day-name\r
- read-sp month-abbreviations index 1+ check-timestamp >>month\r
+ read-sp month-abbreviations index 1 + check-timestamp >>month\r
read-sp checked-number >>day\r
":" read-token checked-number >>hour\r
":" read-token checked-number >>minute\r
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.syntax arrays calendar
-kernel math unix unix.time namespaces system ;
+kernel math unix unix.time unix.types namespaces system ;
IN: calendar.unix
: timeval>seconds ( timeval -- seconds )
timespec>seconds since-1970 ;
: get-time ( -- alien )
- f time <uint> localtime ;
+ f time <time_t> localtime ;
: timezone-name ( -- string )
get-time tm-zone ;
IN: channels.examples
: (counter) ( channel n -- )
- [ swap to ] 2keep 1+ (counter) ;
+ [ swap to ] 2keep 1 + (counter) ;
: counter ( channel -- )
2 (counter) ;
--- /dev/null
+Alaric Snell-Pym
\ No newline at end of file
--- /dev/null
+USING: help.markup help.syntax ;
+IN: checksums.fnv1
+
+HELP: fnv1-32
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1, 32-bit." } ;
+
+HELP: fnv1a-32
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1a, 32-bit." } ;
+
+
+HELP: fnv1-64
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1, 64-bit." } ;
+
+HELP: fnv1a-64
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1a, 64-bit." } ;
+
+
+HELP: fnv1-128
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1, 128-bit." } ;
+
+HELP: fnv1a-128
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1a, 128-bit." } ;
+
+
+HELP: fnv1-256
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1, 256-bit." } ;
+
+HELP: fnv1a-256
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1a, 256-bit." } ;
+
+
+HELP: fnv1-512
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1, 512-bit." } ;
+
+HELP: fnv1a-512
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1a, 512-bit." } ;
+
+
+HELP: fnv1-1024
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1, 1024-bit." } ;
+
+HELP: fnv1a-1024
+{ $class-description "Fowler-Noll-Vo checksum algorithm, v1a, 1024-bit." } ;
+
+ARTICLE: "checksums.fnv1" "Fowler-Noll-Vo checksum"
+ "The Fowler-Noll-Vo checksum algorithm is another simple and fast checksum. It comes in 32, 64, 128, 256, 512 and 1024-bit versions, each in 1 and 1a variants. The 1a variants tend to produce a slightly better result. See http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash for more details."
+
+ { $subsection fnv1-32 }
+ { $subsection fnv1a-32 }
+
+ { $subsection fnv1-64 }
+ { $subsection fnv1a-64 }
+
+ { $subsection fnv1-128 }
+ { $subsection fnv1a-128 }
+
+ { $subsection fnv1-256 }
+ { $subsection fnv1a-256 }
+
+ { $subsection fnv1-512 }
+ { $subsection fnv1a-512 }
+
+ { $subsection fnv1-1024 }
+ { $subsection fnv1a-1024 }
+ ;
+
+ABOUT: "checksums.fnv1"
--- /dev/null
+USING: checksums.fnv1 checksums strings tools.test ;
+IN: checksums.fnv1.tests
+
+! A few test vectors taken from http://www.isthe.com/chongo/src/fnv/test_fnv.c
+
+[ HEX: 811c9dc5 ] [ "" fnv1-32 checksum-bytes ] unit-test
+[ HEX: 811c9dc5 ] [ "" fnv1a-32 checksum-bytes ] unit-test
+[ HEX: cbf29ce484222325 ] [ "" fnv1-64 checksum-bytes ] unit-test
+[ HEX: cbf29ce484222325 ] [ "" fnv1a-64 checksum-bytes ] unit-test
+
+[ HEX: 050c5d7e ] [ "a" fnv1-32 checksum-bytes ] unit-test
+[ HEX: e40c292c ] [ "a" fnv1a-32 checksum-bytes ] unit-test
+[ HEX: af63bd4c8601b7be ] [ "a" fnv1-64 checksum-bytes ] unit-test
+[ HEX: af63dc4c8601ec8c ] [ "a" fnv1a-64 checksum-bytes ] unit-test
+
+[ HEX: 050c5d7d ] [ "b" fnv1-32 checksum-bytes ] unit-test
+[ HEX: e70c2de5 ] [ "b" fnv1a-32 checksum-bytes ] unit-test
+[ HEX: af63bd4c8601b7bd ] [ "b" fnv1-64 checksum-bytes ] unit-test
+[ HEX: af63df4c8601f1a5 ] [ "b" fnv1a-64 checksum-bytes ] unit-test
+
+[ HEX: 31f0b262 ] [ "foobar" fnv1-32 checksum-bytes ] unit-test
+[ HEX: bf9cf968 ] [ "foobar" fnv1a-32 checksum-bytes ] unit-test
+[ HEX: 340d8765a4dda9c2 ] [ "foobar" fnv1-64 checksum-bytes ] unit-test
+[ HEX: 85944171f73967e8 ] [ "foobar" fnv1a-64 checksum-bytes ] unit-test
+
+! I couldn't find any test vectors for 128, 256, 512, or 1024 versions of FNV1 hashes.
+! So, just to check that your maths works the same as my maths, here's a few samples computed on my laptop.
+! So they may be right or wrong, but either way, them failing is cause for concern somewhere...
+
+[ 3897470310 ] [ "Hello, world!" fnv1-32 checksum-bytes ] unit-test
+[ 3985698964 ] [ "Hello, world!" fnv1a-32 checksum-bytes ] unit-test
+[ 7285062107457560934 ] [ "Hello, world!" fnv1-64 checksum-bytes ] unit-test
+[ 4094109891673226228 ] [ "Hello, world!" fnv1a-64 checksum-bytes ] unit-test
+[ 281580511747867177735318995358496831158 ] [ "Hello, world!" fnv1-128 checksum-bytes ] unit-test
+[ 303126633380056630368940439484674414572 ] [ "Hello, world!" fnv1a-128 checksum-bytes ] unit-test
+[ 104295939182568077644846978685759236849634734810631820736486253421270219742822 ] [ "Hello, world!" fnv1-256 checksum-bytes ] unit-test
+[ 9495445728692795332446740615588417456874414534608540692485745371050033741380 ] [ "Hello, world!" fnv1a-256 checksum-bytes ] unit-test
+[ 3577308325596719252093726711895047340166329831006673109476042102918876665433235513101496175651226507162015890004121912850661561110326527625579463564626958 ] [ "Hello, world!" fnv1-512 checksum-bytes ] unit-test
+[ 3577308325596719162840652138474318309664256091923081930027929425092517582111473988451078821416039944023089883981242376700859598441397004715365740906054208 ] [ "Hello, world!" fnv1a-512 checksum-bytes ] unit-test
+[ 52692754922840008511959888105094366091401994235075816792707658326855733053286986999719949898492311786648795846192078757217437117165934438286601534984230194601365788544275827382423366672856972872132009691615382991251544423521887009322211754219117294019951276080952271766377222613325328591830596794468813260226 ] [ "Hello, world!" fnv1-1024 checksum-bytes ] unit-test
+[ 52692754922840008511959888105094366091401994235075816792707658326855804920671100511873485674717442819607149127986090276849364757610838433887624184145636764448608707614141109841761957788887305179569455221243999538336208648824673027111352338809582124430199044921035232455717748500524777795242051756321605065326 ] [ "Hello, world!" fnv1a-1024 checksum-bytes ] unit-test
--- /dev/null
+! Copyright (C) 2009 Alaric Snell-Pym
+! See http://factorcode.org/license.txt for BSD license.
+USING: checksums classes.singleton kernel math math.ranges
+math.vectors sequences ;
+IN: checksums.fnv1
+
+SINGLETON: fnv1-32
+SINGLETON: fnv1a-32
+SINGLETON: fnv1-64
+SINGLETON: fnv1a-64
+SINGLETON: fnv1-128
+SINGLETON: fnv1a-128
+SINGLETON: fnv1-256
+SINGLETON: fnv1a-256
+SINGLETON: fnv1-512
+SINGLETON: fnv1a-512
+SINGLETON: fnv1-1024
+SINGLETON: fnv1a-1024
+
+CONSTANT: fnv1-32-prime 16777619
+CONSTANT: fnv1-64-prime 1099511628211
+CONSTANT: fnv1-128-prime 309485009821345068724781371
+CONSTANT: fnv1-256-prime 374144419156711147060143317175368453031918731002211
+CONSTANT: fnv1-512-prime 35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759
+CONSTANT: fnv1-1024-prime 5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573
+
+CONSTANT: fnv1-32-mod HEX: ffffffff
+CONSTANT: fnv1-64-mod HEX: ffffffffffffffff
+CONSTANT: fnv1-128-mod HEX: ffffffffffffffffffffffffffffffff
+CONSTANT: fnv1-256-mod HEX: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+CONSTANT: fnv1-512-mod HEX: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+CONSTANT: fnv1-1024-mod HEX: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+
+CONSTANT: fnv1-32-basis HEX: 811c9dc5
+CONSTANT: fnv1-64-basis HEX: cbf29ce484222325
+CONSTANT: fnv1-128-basis HEX: 6c62272e07bb014262b821756295c58d
+CONSTANT: fnv1-256-basis HEX: dd268dbcaac550362d98c384c4e576ccc8b1536847b6bbb31023b4c8caee0535
+CONSTANT: fnv1-512-basis HEX: b86db0b1171f4416dca1e50f309990acac87d059c90000000000000000000d21e948f68a34c192f62ea79bc942dbe7ce182036415f56e34bac982aac4afe9fd9
+CONSTANT: fnv1-1024-basis HEX: 5f7a76758ecc4d32e56d5a591028b74b29fc4223fdada16c3bf34eda3674da9a21d9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6d7eb6e73802734510a555f256cc005ae556bde8cc9c6a93b21aff4b16c71ee90b3
+
+M: fnv1-32 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-32-basis swap
+ [ swap fnv1-32-prime * bitxor fnv1-32-mod bitand ] each ;
+
+M: fnv1a-32 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-32-basis swap
+ [ bitxor fnv1-32-prime * fnv1-32-mod bitand ] each ;
+
+
+M: fnv1-64 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-64-basis swap
+ [ swap fnv1-64-prime * bitxor fnv1-64-mod bitand ] each ;
+
+M: fnv1a-64 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-64-basis swap
+ [ bitxor fnv1-64-prime * fnv1-64-mod bitand ] each ;
+
+
+M: fnv1-128 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-128-basis swap
+ [ swap fnv1-128-prime * bitxor fnv1-128-mod bitand ] each ;
+
+M: fnv1a-128 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-128-basis swap
+ [ bitxor fnv1-128-prime * fnv1-128-mod bitand ] each ;
+
+
+M: fnv1-256 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-256-basis swap
+ [ swap fnv1-256-prime * bitxor fnv1-256-mod bitand ] each ;
+
+M: fnv1a-256 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-256-basis swap
+ [ bitxor fnv1-256-prime * fnv1-256-mod bitand ] each ;
+
+
+M: fnv1-512 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-512-basis swap
+ [ swap fnv1-512-prime * bitxor fnv1-512-mod bitand ] each ;
+
+M: fnv1a-512 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-512-basis swap
+ [ bitxor fnv1-512-prime * fnv1-512-mod bitand ] each ;
+
+
+M: fnv1-1024 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-1024-basis swap
+ [ swap fnv1-1024-prime * bitxor fnv1-1024-mod bitand ] each ;
+
+M: fnv1a-1024 checksum-bytes ( bytes checksum -- value )
+ drop
+ fnv1-1024-basis swap
+ [ bitxor fnv1-1024-prime * fnv1-1024-mod bitand ] each ;
--- /dev/null
+Fowler-Noll-Vo checksum algorithm
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
USING: byte-arrays checksums checksums.md5 io.encodings.binary
io.streams.byte-array kernel math namespaces tools.test ;
-
+IN: checksums.md5.tests
[ "d41d8cd98f00b204e9800998ecf8427e" ] [ "" >byte-array md5 checksum-bytes hex-string ] unit-test
[ "0cc175b9c0f1b6a831c399e269772661" ] [ "a" >byte-array md5 checksum-bytes hex-string ] unit-test
<PRIVATE
-TUPLE: evp-md-context handle ;
+TUPLE: evp-md-context < disposable handle ;
: <evp-md-context> ( -- ctx )
- "EVP_MD_CTX" <c-object>
- dup EVP_MD_CTX_init evp-md-context boa ;
+ evp-md-context new-disposable
+ "EVP_MD_CTX" <c-object> dup EVP_MD_CTX_init >>handle ;
-M: evp-md-context dispose
+M: evp-md-context dispose*
handle>> EVP_MD_CTX_cleanup drop ;
: with-evp-md-context ( quot -- )
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel splitting grouping math sequences namespaces make
-io.binary math.bitwise checksums checksums.common
-sbufs strings combinators.smart math.ranges fry combinators
-accessors locals checksums.stream multiline literals
-generalizations ;
+USING: accessors checksums checksums.common checksums.stream
+combinators combinators.smart fry generalizations grouping
+io.binary kernel literals locals make math math.bitwise
+math.ranges multiline namespaces sbufs sequences
+sequences.private splitting strings ;
IN: checksums.sha
SINGLETON: sha1
: prepare-M-256 ( n seq -- )
{
- [ [ 16 - ] dip nth ]
- [ [ 15 - ] dip nth s0-256 ]
- [ [ 7 - ] dip nth ]
- [ [ 2 - ] dip nth s1-256 w+ w+ w+ ]
+ [ [ 16 - ] dip nth-unsafe ]
+ [ [ 15 - ] dip nth-unsafe s0-256 ]
+ [ [ 7 - ] dip nth-unsafe ]
+ [ [ 2 - ] dip nth-unsafe s1-256 w+ w+ w+ ]
[ ]
- } 2cleave set-nth ; inline
+ } 2cleave set-nth-unsafe ; inline
: prepare-M-512 ( n seq -- )
{
- [ [ 16 - ] dip nth ]
- [ [ 15 - ] dip nth s0-512 ]
- [ [ 7 - ] dip nth ]
- [ [ 2 - ] dip nth s1-512 w+ w+ w+ ]
+ [ [ 16 - ] dip nth-unsafe ]
+ [ [ 15 - ] dip nth-unsafe s0-512 ]
+ [ [ 7 - ] dip nth-unsafe ]
+ [ [ 2 - ] dip nth-unsafe s1-512 w+ w+ w+ ]
[ ]
- } 2cleave set-nth ; inline
+ } 2cleave set-nth-unsafe ; inline
: ch ( x y z -- x' )
[ bitxor bitand ] keep bitxor ; inline
GENERIC: pad-initial-bytes ( string sha2 -- padded-string )
:: T1-256 ( n M H sha2 -- T1 )
- n M nth
- n sha2 K>> nth +
+ n M nth-unsafe
+ n sha2 K>> nth-unsafe +
e H slice3 ch w+
- e H nth S1-256 w+
- h H nth w+ ; inline
+ e H nth-unsafe S1-256 w+
+ h H nth-unsafe w+ ; inline
: T2-256 ( H -- T2 )
- [ a swap nth S0-256 ]
+ [ a swap nth-unsafe S0-256 ]
[ a swap slice3 maj w+ ] bi ; inline
:: T1-512 ( n M H sha2 -- T1 )
- n M nth
- n sha2 K>> nth +
+ n M nth-unsafe
+ n sha2 K>> nth-unsafe +
e H slice3 ch w+
- e H nth S1-512 w+
- h H nth w+ ; inline
+ e H nth-unsafe S1-512 w+
+ h H nth-unsafe w+ ; inline
: T2-512 ( H -- T2 )
- [ a swap nth S0-512 ]
+ [ a swap nth-unsafe S0-512 ]
[ a swap slice3 maj w+ ] bi ; inline
: update-H ( T1 T2 H -- )
- h g pick exchange
- g f pick exchange
- f e pick exchange
- pick d pick nth w+ e pick set-nth
- d c pick exchange
- c b pick exchange
- b a pick exchange
- [ w+ a ] dip set-nth ; inline
+ h g pick exchange-unsafe
+ g f pick exchange-unsafe
+ f e pick exchange-unsafe
+ pick d pick nth-unsafe w+ e pick set-nth-unsafe
+ d c pick exchange-unsafe
+ c b pick exchange-unsafe
+ b a pick exchange-unsafe
+ [ w+ a ] dip set-nth-unsafe ; inline
: prepare-message-schedule ( seq sha2 -- w-seq )
[ word-size>> <sliced-groups> [ be> ] map ]
[ [ block-size>> ] [ H>> clone ] [ ] tri process-chunk ] bi ;
: seq>byte-array ( seq n -- string )
- '[ _ >be ] map B{ } join ;
+ '[ _ >be ] map B{ } concat-as ;
: sha1>checksum ( sha2 -- bytes )
H>> 4 seq>byte-array ;
drop
[ <sha-256-state> ] dip add-checksum-stream get-checksum ;
-
-
: sha1-W ( t seq -- )
{
- [ [ 3 - ] dip nth ]
- [ [ 8 - ] dip nth bitxor ]
- [ [ 14 - ] dip nth bitxor ]
- [ [ 16 - ] dip nth bitxor 1 bitroll-32 ]
+ [ [ 3 - ] dip nth-unsafe ]
+ [ [ 8 - ] dip nth-unsafe bitxor ]
+ [ [ 14 - ] dip nth-unsafe bitxor ]
+ [ [ 16 - ] dip nth-unsafe bitxor 1 bitroll-32 ]
[ ]
- } 2cleave set-nth ;
+ } 2cleave set-nth-unsafe ;
: prepare-sha1-message-schedule ( seq -- w-seq )
4 <sliced-groups> [ be> ] map
} case ;
:: inner-loop ( n H W K -- temp )
- a H nth :> A
- b H nth :> B
- c H nth :> C
- d H nth :> D
- e H nth :> E
+ a H nth-unsafe :> A
+ b H nth-unsafe :> B
+ c H nth-unsafe :> C
+ d H nth-unsafe :> D
+ e H nth-unsafe :> E
[
A 5 bitroll-32
E
- n K nth
+ n K nth-unsafe
- n W nth
+ n W nth-unsafe
] sum-outputs 32 bits ;
:: process-sha1-chunk ( bytes H W K state -- )
80 [
H W K inner-loop
- d H nth e H set-nth
- c H nth d H set-nth
- b H nth 30 bitroll-32 c H set-nth
- a H nth b H set-nth
- a H set-nth
+ d H nth-unsafe e H set-nth-unsafe
+ c H nth-unsafe d H set-nth-unsafe
+ b H nth-unsafe 30 bitroll-32 c H set-nth-unsafe
+ a H nth-unsafe b H set-nth-unsafe
+ a H set-nth-unsafe
] each
state [ H [ w+ ] 2map ] change-H drop ; inline
! See http;//factorcode.org/license.txt for BSD license
USING: arrays kernel tools.test sequences sequences.private
circular strings ;
+IN: circular.tests
[ 0 ] [ { 0 1 2 3 4 } <circular> 0 swap virtual@ drop ] unit-test
[ 2 ] [ { 0 1 2 3 4 } <circular> 2 swap virtual@ drop ] unit-test
[ [ 1 2 3 ] ] [ { 1 2 3 } <circular> [ ] like ] unit-test
[ [ 2 3 1 ] ] [ { 1 2 3 } <circular> [ rotate-circular ] keep [ ] like ] unit-test
+[ [ 3 1 2 ] ] [ { 1 2 3 } <circular> [ rotate-circular ] keep [ rotate-circular ] keep [ ] like ] unit-test
[ [ 2 3 1 ] ] [ { 1 2 3 } <circular> 1 over change-circular-start [ ] like ] unit-test
[ [ 3 1 2 ] ] [ { 1 2 3 } <circular> 1 over change-circular-start 1 over change-circular-start [ ] like ] unit-test
[ [ 3 1 2 ] ] [ { 1 2 3 } <circular> -100 over change-circular-start [ ] like ] unit-test
circular-wrap (>>start) ;
: rotate-circular ( circular -- )
- [ start>> 1 + ] keep circular-wrap (>>start) ;
+ [ 1 ] dip change-circular-start ;
: push-circular ( elt circular -- )
- [ set-first ] [ 1 swap change-circular-start ] bi ;
+ [ set-first ] [ rotate-circular ] bi ;
: <circular-string> ( n -- circular )
0 <string> <circular> ;
M: growing-circular length length>> ;
<PRIVATE
+
: full? ( circular -- ? )
[ length ] [ seq>> length ] bi = ;
-: set-last ( elt seq -- )
- [ length 1- ] keep set-nth ;
PRIVATE>
: push-growing-circular ( elt circular -- )
dup full? [ push-circular ]
- [ [ 1+ ] change-length set-last ] if ;
+ [ [ 1 + ] change-length set-last ] if ;
: <growing-circular> ( capacity -- growing-circular )
{ } new-sequence 0 0 growing-circular boa ;
--- /dev/null
+! (c)Joe Groff bsd license
+USING: accessors assocs classes classes.struct combinators
+kernel math prettyprint.backend prettyprint.custom
+prettyprint.sections see.private sequences words ;
+IN: classes.struct.prettyprint
+
+<PRIVATE
+
+: struct-definer-word ( class -- word )
+ struct-slots dup length 2 >=
+ [ second offset>> 0 = \ UNION-STRUCT: \ STRUCT: ? ]
+ [ drop \ STRUCT: ] if ;
+
+: struct>assoc ( struct -- assoc )
+ [ class struct-slots ] [ struct-slot-values ] bi zip filter-tuple-assoc ;
+
+: pprint-struct-slot ( slot -- )
+ <flow \ { pprint-word
+ {
+ [ name>> text ]
+ [ c-type>> text ]
+ [ read-only>> [ \ read-only pprint-word ] when ]
+ [ initial>> [ \ initial: pprint-word pprint* ] when* ]
+ } cleave
+ \ } pprint-word block> ;
+
+PRIVATE>
+
+M: struct-class see-class*
+ <colon dup struct-definer-word pprint-word dup pprint-word
+ <block struct-slots [ pprint-struct-slot ] each
+ block> pprint-; block> ;
+
+M: struct pprint-delims
+ drop \ S{ \ } ;
+
+M: struct >pprint-sequence
+ [ class ] [ struct-slot-values ] bi class-slot-sequence ;
+
+M: struct pprint*
+ [ [ \ S{ ] dip [ class ] [ struct>assoc ] bi \ } (pprint-tuple) ] ?pprint-tuple ;
--- /dev/null
+! (c)Joe Groff bsd license
+USING: alien classes help.markup help.syntax kernel libc
+quotations slots ;
+IN: classes.struct
+
+HELP: <struct-boa>
+{ $values
+ { "class" class }
+}
+{ $description "This macro implements " { $link boa } " for " { $link struct } " classes. A struct of the given class is constructed, and its slots are initialized using values off the top of the datastack." } ;
+
+HELP: <struct>
+{ $values
+ { "class" class }
+ { "struct" struct }
+}
+{ $description "Allocates garbage-collected heap memory for a new " { $link struct } " of the specified " { $snippet "class" } ". The new struct's slots are initialized with the initial values specified in the struct definition." } ;
+
+{ <struct> <struct-boa> malloc-struct memory>struct } related-words
+
+HELP: STRUCT:
+{ $syntax "STRUCT: class { slot type } { slot type } ... ;" }
+{ $values { "class" "a new " { $link struct } " class to define" } { "slots" "a list of slot specifiers" } }
+{ $description "Defines a new " { $link struct } " type. The syntax is nearly identical to " { $link POSTPONE: TUPLE: } "; however, there are some additional restrictions on struct types:"
+{ $list
+{ "Struct classes cannot have a superclass defined." }
+{ "The slots of a struct must all have a type declared. The type must be a C type." }
+{ { $link read-only } " slots on structs are not enforced, though they may be declared." }
+} } ;
+
+HELP: S{
+{ $syntax "S{ class slots... }" }
+{ $values { "class" "a " { $link struct } " class word" } { "slots" "slot values" } }
+{ $description "Marks the beginning of a literal struct. The syntax is identical to tuple literal syntax with " { $link POSTPONE: T{ } { $snippet " }" } "; either the assoc syntax (that is, " { $snippet "S{ class { slot value } { slot value } ... }" } ") or the simple syntax (" { $snippet "S{ class f value value ... }" } ") can be used." } ;
+
+HELP: UNION-STRUCT:
+{ $syntax "UNION-STRUCT: class { slot type } { slot type } ... ;" }
+{ $values { "class" "a new " { $link struct } " class to define" } { "slots" "a list of slot specifiers" } }
+{ $description "Defines a new " { $link struct } " type where all of the slots share the same storage. See " { $link POSTPONE: STRUCT: } " for details on the syntax." } ;
+
+HELP: define-struct-class
+{ $values
+ { "class" class } { "slots" "a sequence of " { $link slot-spec } "s" }
+}
+{ $description "Defines a new " { $link struct } " class. This is the runtime equivalent of the " { $link POSTPONE: STRUCT: } " syntax." } ;
+
+HELP: define-union-struct-class
+{ $values
+ { "class" class } { "slots" "a sequence of " { $link slot-spec } "s" }
+}
+{ $description "Defines a new " { $link struct } " class where all of the slots share the same storage. This is the runtime equivalent of the " { $link POSTPONE: UNION-STRUCT: } " syntax." } ;
+
+HELP: malloc-struct
+{ $values
+ { "class" class }
+ { "struct" struct }
+}
+{ $description "Allocates unmanaged C heap memory for a new " { $link struct } " of the specified " { $snippet "class" } ". The new struct's slots are left uninitialized. The struct should be " { $link free } "d when it is no longer needed." } ;
+
+HELP: memory>struct
+{ $values
+ { "ptr" c-ptr } { "class" class }
+ { "struct" struct }
+}
+{ $description "Constructs a new " { $link struct } " of the specified " { $snippet "class" } " at the memory location referenced by " { $snippet "ptr" } ". The referenced memory is unchanged." } ;
+
+HELP: struct
+{ $class-description "The parent class of all struct types." } ;
+
+{ struct POSTPONE: STRUCT: POSTPONE: UNION-STRUCT: } related-words
+
+HELP: struct-class
+{ $class-description "The metaclass of all " { $link struct } " classes." } ;
+
+ARTICLE: "classes.struct" "Struct classes"
+{ $link struct } " classes are similar to " { $link tuple } "s, but their slots exhibit value semantics, and they are backed by a contiguous structured block of memory. Structs can be used for structured access to C memory or Factor byte arrays and for passing struct values in and out of the FFI. Struct types are defined using a syntax similar to tuple syntax:"
+{ $subsection POSTPONE: STRUCT: }
+"Structs can be allocated with " { $link new } "- and " { $link boa } "-like constructor words. Additional words are provided for building structs from C memory and from existing buffers:"
+{ $subsection <struct> }
+{ $subsection <struct-boa> }
+{ $subsection malloc-struct }
+{ $subsection memory>struct }
+"Structs have literal syntax like tuples:"
+{ $subsection POSTPONE: S{ }
+"Union structs are also supported, which behave like structs but share the same memory for all the type's slots."
+{ $subsection POSTPONE: UNION-STRUCT: }
+;
+
+ABOUT: "classes.struct"
--- /dev/null
+! (c)Joe Groff bsd license
+USING: accessors alien.c-types alien.libraries
+alien.structs.fields alien.syntax ascii classes.struct combinators
+destructors io.encodings.utf8 io.pathnames io.streams.string
+kernel libc literals math multiline namespaces prettyprint
+prettyprint.config see sequences specialized-arrays.ushort
+system tools.test compiler.tree.debugger struct-arrays
+classes.tuple.private specialized-arrays.direct.int
+compiler.units ;
+IN: classes.struct.tests
+
+<<
+: libfactor-ffi-tests-path ( -- string )
+ "resource:" (normalize-path)
+ {
+ { [ os winnt? ] [ "libfactor-ffi-test.dll" ] }
+ { [ os macosx? ] [ "libfactor-ffi-test.dylib" ] }
+ { [ os unix? ] [ "libfactor-ffi-test.so" ] }
+ } cond append-path ;
+
+"f-cdecl" libfactor-ffi-tests-path "cdecl" add-library
+
+"f-stdcall" libfactor-ffi-tests-path "stdcall" add-library
+>>
+
+SYMBOL: struct-test-empty
+
+[ [ struct-test-empty { } define-struct-class ] with-compilation-unit ]
+[ struct-must-have-slots? ] must-fail-with
+
+STRUCT: struct-test-foo
+ { x char }
+ { y int initial: 123 }
+ { z bool } ;
+
+STRUCT: struct-test-bar
+ { w ushort initial: HEX: ffff }
+ { foo struct-test-foo } ;
+
+[ 12 ] [ struct-test-foo heap-size ] unit-test
+[ 12 ] [ struct-test-foo <struct> byte-length ] unit-test
+[ 16 ] [ struct-test-bar heap-size ] unit-test
+[ 123 ] [ struct-test-foo <struct> y>> ] unit-test
+[ 123 ] [ struct-test-bar <struct> foo>> y>> ] unit-test
+
+[ 1 2 3 t ] [
+ 1 2 3 t struct-test-foo <struct-boa> struct-test-bar <struct-boa>
+ {
+ [ w>> ]
+ [ foo>> x>> ]
+ [ foo>> y>> ]
+ [ foo>> z>> ]
+ } cleave
+] unit-test
+
+[ 7654 ] [ S{ struct-test-foo f 98 7654 f } y>> ] unit-test
+[ 7654 ] [ S{ struct-test-foo { y 7654 } } y>> ] unit-test
+
+UNION-STRUCT: struct-test-float-and-bits
+ { f float }
+ { bits uint } ;
+
+[ 1.0 ] [ struct-test-float-and-bits <struct> 1.0 float>bits >>bits f>> ] unit-test
+[ 4 ] [ struct-test-float-and-bits heap-size ] unit-test
+
+[ ] [ [ struct-test-foo malloc-struct &free drop ] with-destructors ] unit-test
+
+STRUCT: struct-test-string-ptr
+ { x char* } ;
+
+[ "hello world" ] [
+ [
+ struct-test-string-ptr <struct>
+ "hello world" utf8 malloc-string &free >>x
+ x>>
+ ] with-destructors
+] unit-test
+
+[ "S{ struct-test-foo { y 7654 } }" ]
+[
+ f boa-tuples?
+ [ struct-test-foo <struct> 7654 >>y [ pprint ] with-string-writer ]
+ with-variable
+] unit-test
+
+[ "S{ struct-test-foo f 0 7654 f }" ]
+[
+ t boa-tuples?
+ [ struct-test-foo <struct> 7654 >>y [ pprint ] with-string-writer ]
+ with-variable
+] unit-test
+
+[ <" USING: classes.struct ;
+IN: classes.struct.tests
+STRUCT: struct-test-foo
+ { x char initial: 0 } { y int initial: 123 } { z bool } ;
+"> ]
+[ [ struct-test-foo see ] with-string-writer ] unit-test
+
+[ <" USING: classes.struct ;
+IN: classes.struct.tests
+UNION-STRUCT: struct-test-float-and-bits
+ { f float initial: 0.0 } { bits uint initial: 0 } ;
+"> ]
+[ [ struct-test-float-and-bits see ] with-string-writer ] unit-test
+
+[ {
+ T{ field-spec
+ { name "x" }
+ { offset 0 }
+ { type "char" }
+ { reader x>> }
+ { writer (>>x) }
+ }
+ T{ field-spec
+ { name "y" }
+ { offset 4 }
+ { type "int" }
+ { reader y>> }
+ { writer (>>y) }
+ }
+ T{ field-spec
+ { name "z" }
+ { offset 8 }
+ { type "bool" }
+ { reader z>> }
+ { writer (>>z) }
+ }
+} ] [ "struct-test-foo" c-type fields>> ] unit-test
+
+[ {
+ T{ field-spec
+ { name "f" }
+ { offset 0 }
+ { type "float" }
+ { reader f>> }
+ { writer (>>f) }
+ }
+ T{ field-spec
+ { name "bits" }
+ { offset 0 }
+ { type "uint" }
+ { reader bits>> }
+ { writer (>>bits) }
+ }
+} ] [ "struct-test-float-and-bits" c-type fields>> ] unit-test
+
+STRUCT: struct-test-equality-1
+ { x int } ;
+STRUCT: struct-test-equality-2
+ { y int } ;
+
+[ t ] [
+ [
+ struct-test-equality-1 <struct> 5 >>x
+ struct-test-equality-1 malloc-struct &free 5 >>x =
+ ] with-destructors
+] unit-test
+
+[ f ] [
+ [
+ struct-test-equality-1 <struct> 5 >>x
+ struct-test-equality-2 malloc-struct &free 5 >>y =
+ ] with-destructors
+] unit-test
+
+STRUCT: struct-test-ffi-foo
+ { x int }
+ { y int } ;
+
+LIBRARY: f-cdecl
+FUNCTION: int ffi_test_11 ( int a, struct-test-ffi-foo b, int c ) ;
+
+[ 14 ] [ 1 2 3 struct-test-ffi-foo <struct-boa> 4 ffi_test_11 ] unit-test
+
+STRUCT: struct-test-array-slots
+ { x int }
+ { y ushort[6] initial: ushort-array{ 2 3 5 7 11 13 } }
+ { z int } ;
+
+[ 11 ] [ struct-test-array-slots <struct> y>> 4 swap nth ] unit-test
+
+[ t ] [
+ struct-test-array-slots <struct>
+ [ y>> [ 8 3 ] dip set-nth ]
+ [ y>> ushort-array{ 2 3 5 8 11 13 } sequence= ] bi
+] unit-test
+
+STRUCT: struct-test-optimization
+ { x int[3] } { y int } ;
+
+[ t ] [ [ struct-test-optimization memory>struct y>> ] { memory>struct y>> } inlined? ] unit-test
+[ t ] [
+ [ 3 struct-test-optimization <direct-struct-array> third y>> ]
+ { <tuple> <tuple-boa> memory>struct y>> } inlined?
+] unit-test
+
+[ t ] [ [ struct-test-optimization memory>struct y>> ] { memory>struct y>> } inlined? ] unit-test
+
+[ t ] [
+ [ struct-test-optimization memory>struct x>> second ]
+ { memory>struct x>> <direct-int-array> <tuple> <tuple-boa> } inlined?
+] unit-test
+
+[ f ] [ [ memory>struct y>> ] { memory>struct y>> } inlined? ] unit-test
--- /dev/null
+! (c)Joe Groff bsd license
+USING: accessors alien alien.c-types alien.structs
+alien.structs.fields arrays byte-arrays classes classes.parser
+classes.tuple classes.tuple.parser classes.tuple.private
+combinators combinators.short-circuit combinators.smart fry
+generalizations generic.parser kernel kernel.private lexer
+libc macros make math math.order parser quotations sequences
+slots slots.private struct-arrays vectors words
+compiler.tree.propagation.transforms ;
+FROM: slots => reader-word writer-word ;
+IN: classes.struct
+
+! struct class
+
+ERROR: struct-must-have-slots ;
+
+TUPLE: struct
+ { (underlying) c-ptr read-only } ;
+
+TUPLE: struct-slot-spec < slot-spec
+ c-type ;
+
+PREDICATE: struct-class < tuple-class
+ { [ \ struct subclass-of? ] [ all-slots length 1 = ] } 1&& ;
+
+: struct-slots ( struct -- slots )
+ "struct-slots" word-prop ;
+
+! struct allocation
+
+M: struct >c-ptr
+ 2 slot { c-ptr } declare ; inline
+
+M: struct equal?
+ {
+ [ [ class ] bi@ = ]
+ [ [ >c-ptr ] [ [ >c-ptr ] [ byte-length ] bi ] bi* memory= ]
+ } 2&& ;
+
+: memory>struct ( ptr class -- struct )
+ [ 1array ] dip slots>tuple ;
+
+\ memory>struct [
+ dup struct-class? [ '[ _ boa ] ] [ drop f ] if
+] 1 define-partial-eval
+
+: malloc-struct ( class -- struct )
+ [ heap-size malloc ] keep memory>struct ; inline
+
+: (struct) ( class -- struct )
+ [ heap-size <byte-array> ] keep memory>struct ; inline
+
+: struct-prototype ( class -- prototype ) "prototype" word-prop ; foldable
+
+: <struct> ( class -- struct )
+ dup struct-prototype
+ [ >c-ptr clone swap memory>struct ] [ (struct) ] if* ; inline
+
+MACRO: <struct-boa> ( class -- quot: ( ... -- struct ) )
+ [
+ [ <wrapper> \ (struct) [ ] 2sequence ]
+ [
+ struct-slots
+ [ length \ ndip ]
+ [ [ name>> setter-word 1quotation ] map \ spread ] bi
+ ] bi
+ ] [ ] output>sequence ;
+
+: pad-struct-slots ( values class -- values' class )
+ [ struct-slots [ initial>> ] map over length tail append ] keep ;
+
+: (reader-quot) ( slot -- quot )
+ [ c-type>> c-type-getter-boxer ]
+ [ offset>> [ >c-ptr ] swap suffix ] bi prepend ;
+
+: (writer-quot) ( slot -- quot )
+ [ c-type>> c-setter ]
+ [ offset>> [ >c-ptr ] swap suffix ] bi prepend ;
+
+: (boxer-quot) ( class -- quot )
+ '[ _ memory>struct ] ;
+
+: (unboxer-quot) ( class -- quot )
+ drop [ >c-ptr ] ;
+
+M: struct-class boa>object
+ swap pad-struct-slots
+ [ (struct) ] [ struct-slots ] bi
+ [ [ (writer-quot) call( value struct -- ) ] with 2each ] curry keep ;
+
+! Struct slot accessors
+
+GENERIC: struct-slot-values ( struct -- sequence )
+
+M: struct-class reader-quot
+ nip (reader-quot) ;
+
+M: struct-class writer-quot
+ nip (writer-quot) ;
+
+: struct-slot-values-quot ( class -- quot )
+ struct-slots
+ [ name>> reader-word 1quotation ] map
+ \ cleave [ ] 2sequence
+ \ output>array [ ] 2sequence ;
+
+: (define-struct-slot-values-method) ( class -- )
+ [ \ struct-slot-values create-method-in ]
+ [ struct-slot-values-quot ] bi define ;
+
+: (define-byte-length-method) ( class -- )
+ [ \ byte-length create-method-in ]
+ [ heap-size \ drop swap [ ] 2sequence ] bi define ;
+
+! Struct as c-type
+
+: slot>field ( slot -- field )
+ field-spec new swap {
+ [ name>> >>name ]
+ [ offset>> >>offset ]
+ [ c-type>> >>type ]
+ [ name>> reader-word >>reader ]
+ [ name>> writer-word >>writer ]
+ } cleave ;
+
+: define-struct-for-class ( class -- )
+ [
+ {
+ [ name>> ]
+ [ "struct-size" word-prop ]
+ [ "struct-align" word-prop ]
+ [ struct-slots [ slot>field ] map ]
+ } cleave
+ struct-type (define-struct)
+ ] [
+ {
+ [ name>> c-type ]
+ [ (unboxer-quot) >>unboxer-quot ]
+ [ (boxer-quot) >>boxer-quot ]
+ [ >>boxed-class ]
+ } cleave drop
+ ] bi ;
+
+: align-offset ( offset class -- offset' )
+ c-type-align align ;
+
+: struct-offsets ( slots -- size )
+ 0 [
+ [ c-type>> align-offset ] keep
+ [ (>>offset) ] [ c-type>> heap-size + ] 2bi
+ ] reduce ;
+
+: union-struct-offsets ( slots -- size )
+ [ 0 >>offset c-type>> heap-size ] [ max ] map-reduce ;
+
+: struct-align ( slots -- align )
+ [ c-type>> c-type-align ] [ max ] map-reduce ;
+
+M: struct-class c-type
+ name>> c-type ;
+
+M: struct-class c-type-align
+ "struct-align" word-prop ;
+
+M: struct-class c-type-getter
+ drop [ swap <displaced-alien> ] ;
+
+M: struct-class c-type-setter
+ [ c-type-getter ] [ c-type-unboxer-quot ] [ heap-size ] tri
+ '[ @ swap @ _ memcpy ] ;
+
+M: struct-class c-type-boxer-quot
+ (boxer-quot) ;
+
+M: struct-class c-type-unboxer-quot
+ (unboxer-quot) ;
+
+M: struct-class heap-size
+ "struct-size" word-prop ;
+
+! class definition
+
+: make-struct-prototype ( class -- prototype )
+ [ heap-size <byte-array> ]
+ [ memory>struct ]
+ [ struct-slots ] tri
+ [
+ [ initial>> ]
+ [ (writer-quot) ] bi
+ over [ swapd [ call( value struct -- ) ] curry keep ] [ 2drop ] if
+ ] each ;
+
+: (struct-methods) ( class -- )
+ [ (define-struct-slot-values-method) ]
+ [ (define-byte-length-method) ] bi ;
+
+: (struct-word-props) ( class slots size align -- )
+ [
+ [ "struct-slots" set-word-prop ]
+ [ define-accessors ] 2bi
+ ]
+ [ "struct-size" set-word-prop ]
+ [ "struct-align" set-word-prop ] tri-curry*
+ [ tri ] 3curry
+ [ dup make-struct-prototype "prototype" set-word-prop ]
+ [ (struct-methods) ] tri ;
+
+: check-struct-slots ( slots -- )
+ [ c-type>> c-type drop ] each ;
+
+: (define-struct-class) ( class slots offsets-quot -- )
+ [
+ [ struct-must-have-slots ]
+ [ drop struct f define-tuple-class ] if-empty
+ ]
+ swap '[
+ make-slots dup
+ [ check-struct-slots ] _ [ struct-align [ align ] keep ] tri
+ (struct-word-props)
+ ]
+ [ drop define-struct-for-class ] 2tri ; inline
+
+: define-struct-class ( class slots -- )
+ [ struct-offsets ] (define-struct-class) ;
+
+: define-union-struct-class ( class slots -- )
+ [ union-struct-offsets ] (define-struct-class) ;
+
+ERROR: invalid-struct-slot token ;
+
+: struct-slot-class ( c-type -- class' )
+ c-type c-type-boxed-class
+ dup \ byte-array = [ drop \ c-ptr ] when ;
+
+: parse-struct-slot ( -- slot )
+ struct-slot-spec new
+ scan >>name
+ scan [ >>c-type ] [ struct-slot-class >>class ] bi
+ \ } parse-until [ dup empty? ] [ peel-off-attributes ] until drop ;
+
+: parse-struct-slots ( slots -- slots' more? )
+ scan {
+ { ";" [ f ] }
+ { "{" [ parse-struct-slot over push t ] }
+ [ invalid-struct-slot ]
+ } case ;
+
+: parse-struct-definition ( -- class slots )
+ CREATE-CLASS 8 <vector> [ parse-struct-slots ] [ ] while >array ;
+
+SYNTAX: STRUCT:
+ parse-struct-definition define-struct-class ;
+SYNTAX: UNION-STRUCT:
+ parse-struct-definition define-union-struct-class ;
+
+SYNTAX: S{
+ scan-word dup struct-slots parse-tuple-literal-slots parsed ;
+
+USING: vocabs vocabs.loader ;
+
+"prettyprint" vocab [ "classes.struct.prettyprint" require ] when
! Copyright (C) 2005, 2006 Kevin Reid.
! See http://factorcode.org/license.txt for BSD license.
-IN: cocoa.callbacks
USING: assocs kernel namespaces cocoa cocoa.classes
cocoa.subclassing debugger ;
+IN: cocoa.callbacks
SYMBOL: callbacks
-IN: cocoa.tests
USING: cocoa cocoa.messages cocoa.subclassing cocoa.types
compiler kernel namespaces cocoa.classes tools.test memory
compiler.units math core-graphics.types ;
+IN: cocoa.tests
CLASS: {
{ +superclass+ "NSObject" }
"NSOpenGLPixelFormat"
"NSOpenGLView"
"NSOpenPanel"
+ "NSPanel"
"NSPasteboard"
"NSPropertyListSerialization"
"NSResponder"
[ ] [ no-objc-type ] ?if ;
: (parse-objc-type) ( i string -- ctype )
- [ [ 1+ ] dip ] [ nth ] 2bi {
+ [ [ 1 + ] dip ] [ nth ] 2bi {
{ [ dup "rnNoORV" member? ] [ drop (parse-objc-type) ] }
{ [ dup CHAR: ^ = ] [ 3drop "void*" ] }
{ [ dup CHAR: { = ] [ drop objc-struct-type ] }
-IN: cocoa.plists.tests
USING: tools.test cocoa.plists colors kernel hashtables
core-foundation.utilities core-foundation destructors
assocs cocoa.enumeration ;
+IN: cocoa.plists.tests
[
[ V{ } ] [ H{ } >cf &CFRelease [ ] NSFastEnumeration-map ] unit-test
[ 3.5 ] [
3.5 >cf &CFRelease plist>
] unit-test
-] with-destructors
\ No newline at end of file
+] with-destructors
! Copyright (C) 2006, 2009 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: specialized-arrays.int arrays kernel math namespaces make
+USING: arrays kernel math namespaces make
cocoa cocoa.messages cocoa.classes core-graphics
core-graphics.types sequences continuations accessors ;
IN: cocoa.views
IN: cocoa.windows
HELP: <NSWindow>
-{ $values { "rect" "an " { $snippet "NSRect" } } { "window" "an " { $snippet "NSWindow" } } }
+{ $values { "rect" "an " { $snippet "NSRect" } } { "style" "a style mask" } { "class" "an Objective-C class" } { "window" "an " { $snippet "NSWindow" } } }
{ $description "Creates a new " { $snippet "NSWindow" } " with the specified dimensions." } ;
HELP: <ViewWindow>
-{ $values { "view" "an " { $snippet "NSView" } } { "rect" "an " { $snippet "NSRect" } } { "window" "an " { $snippet "NSWindow" } } }
+{ $values { "view" "an " { $snippet "NSView" } } { "rect" "an " { $snippet "NSRect" } } { "style" "a style mask" } { "window" "an " { $snippet "NSWindow" } } }
{ $description "Creates a new " { $snippet "NSWindow" } " with the specified dimensions, containing the given view." } ;
ARTICLE: "cocoa-window-utils" "Cocoa window utilities"
sequences math.bitwise ;
IN: cocoa.windows
+! Window styles
CONSTANT: NSBorderlessWindowMask 0
CONSTANT: NSTitledWindowMask 1
CONSTANT: NSClosableWindowMask 2
CONSTANT: NSMiniaturizableWindowMask 4
CONSTANT: NSResizableWindowMask 8
+! Additional panel-only styles
+CONSTANT: NSUtilityWindowMask 16
+CONSTANT: NSDocModalWindowMask 64
+CONSTANT: NSNonactivatingPanelMask 128
+CONSTANT: NSHUDWindowMask HEX: 1000
+
CONSTANT: NSBackingStoreRetained 0
CONSTANT: NSBackingStoreNonretained 1
CONSTANT: NSBackingStoreBuffered 2
-: standard-window-type ( -- n )
- {
- NSTitledWindowMask
- NSClosableWindowMask
- NSMiniaturizableWindowMask
- NSResizableWindowMask
- } flags ; inline
-
-: <NSWindow> ( rect -- window )
- NSWindow -> alloc swap
- standard-window-type NSBackingStoreBuffered 1
+: <NSWindow> ( rect style class -- window )
+ [ -> alloc ] curry 2dip NSBackingStoreBuffered 1
-> initWithContentRect:styleMask:backing:defer: ;
-: <ViewWindow> ( view rect -- window )
- <NSWindow> [ swap -> setContentView: ] keep
+: class-for-style ( style -- NSWindow/NSPanel )
+ HEX: 1ff0 bitand zero? NSWindow NSPanel ? ;
+
+: <ViewWindow> ( view rect style -- window )
+ dup class-for-style <NSWindow> [ swap -> setContentView: ] keep
dup dup -> contentView -> setInitialFirstResponder:
dup 1 -> setAcceptsMouseMovedEvents:
dup 0 -> setReleasedWhenClosed: ;
: window-content-rect ( window -- rect )
- [ NSWindow ] dip
+ dup -> class swap
[ -> frame ] [ -> styleMask ] bi
-> contentRectForFrameRect:styleMask: ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel assocs math math.parser memoize
-io.encodings.ascii io.files lexer parser
-colors sequences splitting combinators.smart ascii ;
+USING: kernel assocs math math.parser memoize io.encodings.utf8
+io.files lexer parser colors sequences splitting
+combinators.smart ascii ;
IN: colors.constants
<PRIVATE
[ parse-color ] H{ } map>assoc ;
MEMO: rgb.txt ( -- assoc )
- "resource:basis/colors/constants/rgb.txt" ascii file-lines parse-rgb.txt ;
+ "resource:basis/colors/constants/rgb.txt" utf8 file-lines parse-rgb.txt ;
PRIVATE>
-IN: colors.hsv.tests
USING: accessors kernel colors colors.hsv tools.test math ;
+IN: colors.hsv.tests
: hsv>rgb ( h s v -- r g b )
[ 360 * ] 2dip
[ 5/6 5/36 5/6 ] [ 5/6 5/6 5/6 hsv>rgb ] unit-test
[ 1/6 0 1/6 ] [ 5/6 1 1/6 hsv>rgb ] unit-test
-[ 0.5 ] [ 180 0.1 0.2 0.5 <hsva> alpha>> ] unit-test
\ No newline at end of file
+[ 0.5 ] [ 180 0.1 0.2 0.5 <hsva> alpha>> ] unit-test
-IN: columns.tests
USING: columns sequences kernel namespaces arrays tools.test math ;
+IN: columns.tests
! Columns
{ { 1 2 3 } { 4 5 6 } { 7 8 9 } } [ clone ] map "seq" set
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax io.streams.string quotations
-math ;
+math kernel ;
IN: combinators.short-circuit
HELP: 0&&
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
-{ $description "Returns true if every quotation in the sequence of quotations returns true." } ;
+{ $values { "quots" "a sequence of quotations with stack effect " { $snippet "( -- )" } } { "?" "the result of the last quotation, or " { $link f } } }
+{ $description "If every quotation in the sequence outputs a true value, outputs the result of the last quotation, otherwise outputs " { $link f } "." } ;
HELP: 0||
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
-{ $description "Returns true if any quotation in the sequence returns true." } ;
+{ $values { "quots" "a sequence of quotations with stack effect " { $snippet "( -- )" } } { "?" "the first true result, or " { $link f } } }
+{ $description "If every quotation in the sequence outputs " { $link f } ", outputs " { $link f } ", otherwise outputs the result of the first quotation that did not yield " { $link f } "." } ;
HELP: 1&&
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
-{ $description "Returns true if every quotation in the sequence of quotations returns true. Each quotation gets the same element from the datastack and must output a boolean." } ;
+{ $values { "obj" object } { "quots" "a sequence of quotations with stack effect " { $snippet "( obj -- )" } } { "?" "the result of the last quotation, or " { $link f } } }
+{ $description "If every quotation in the sequence outputs a true value, outputs the result of the last quotation, otherwise outputs " { $link f } "." } ;
HELP: 1||
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
+{ $values { "obj" object } { "quots" "a sequence of quotations with stack effect " { $snippet "( obj -- )" } } { "?" "the first true result, or " { $link f } } }
{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same element from the datastack and must return a boolean." } ;
HELP: 2&&
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
-{ $description "Returns true if every quotation in the sequence of quotations returns true. Each quotation gets the same two elements from the datastack and must output a boolean." } ;
+{ $values { "obj1" object } { "obj2" object } { "quots" "a sequence of quotations with stack effect " { $snippet "( obj1 obj2 -- )" } } { "?" "the result of the last quotation, or " { $link f } } }
+{ $description "If every quotation in the sequence outputs a true value, outputs the result of the last quotation, otherwise outputs " { $link f } "." } ;
HELP: 2||
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
+{ $values { "obj1" object } { "obj2" object } { "quots" "a sequence of quotations with stack effect " { $snippet "( obj1 obj2 -- )" } } { "?" "the first true result, or " { $link f } } }
{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same two elements from the datastack and must return a boolean." } ;
HELP: 3&&
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
-{ $description "Returns true if every quotation in the sequence of quotations returns true. Each quotation gets the same three elements from the datastack and must output a boolean." } ;
+{ $values { "obj1" object } { "obj2" object } { "obj3" object } { "quots" "a sequence of quotations with stack effect " { $snippet "( obj1 obj2 obj3 -- )" } } { "?" "the result of the last quotation, or " { $link f } } }
+{ $description "If every quotation in the sequence outputs a true value, outputs the result of the last quotation, otherwise outputs " { $link f } "." } ;
HELP: 3||
-{ $values
- { "quots" "a sequence of quotations" }
- { "quot" quotation } }
+{ $values { "obj1" object } { "obj2" object } { "obj3" object } { "quots" "a sequence of quotations with stack effect " { $snippet "( obj1 obj2 obj3 -- )" } } { "?" "the first true result, or " { $link f } } }
{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same three elements from the datastack and must return a boolean." } ;
HELP: n&&
{ $values
- { "quots" "a sequence of quotations" } { "N" integer }
+ { "quots" "a sequence of quotations" } { "n" integer }
{ "quot" quotation } }
-{ $description "A macro that rewrites the code to pass " { $snippet "n" } " parameters from the stack to each AND quotation." } ;
+{ $description "A macro that rewrites the code to pass " { $snippet "n" } " parameters from the stack to each quotation, evaluating the result in the same manner as " { $link 0&& } "." } ;
HELP: n||
{ $values
-
USING: kernel math tools.test combinators.short-circuit ;
-
IN: combinators.short-circuit.tests
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: must-be-t ( in -- ) [ t ] swap unit-test ;
-: must-be-f ( in -- ) [ f ] swap unit-test ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-[ { [ 1 ] [ 2 ] [ 3 ] } 0&& 3 = ] must-be-t
-[ 3 { [ 0 > ] [ odd? ] [ 2 + ] } 1&& 5 = ] must-be-t
-[ 10 20 { [ + 0 > ] [ - even? ] [ + ] } 2&& 30 = ] must-be-t
-
-[ { [ 1 ] [ f ] [ 3 ] } 0&& 3 = ] must-be-f
-[ 3 { [ 0 > ] [ even? ] [ 2 + ] } 1&& ] must-be-f
-[ 10 20 { [ + 0 > ] [ - odd? ] [ + ] } 2&& 30 = ] must-be-f
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+[ 3 ] [ { [ 1 ] [ 2 ] [ 3 ] } 0&& ] unit-test
+[ 5 ] [ 3 { [ 0 > ] [ odd? ] [ 2 + ] } 1&& ] unit-test
+[ 30 ] [ 10 20 { [ + 0 > ] [ - even? ] [ + ] } 2&& ] unit-test
-[ { [ 10 0 < ] [ f ] [ "factor" ] } 0|| "factor" = ] must-be-t
+[ f ] [ { [ 1 ] [ f ] [ 3 ] } 0&& ] unit-test
+[ f ] [ 3 { [ 0 > ] [ even? ] [ 2 + ] } 1&& ] unit-test
+[ f ] [ 10 20 { [ + 0 > ] [ - odd? ] [ + ] } 2&& ] unit-test
-[ 10 { [ odd? ] [ 100 > ] [ 1 + ] } 1|| 11 = ] must-be-t
+[ "factor" ] [ { [ 10 0 < ] [ f ] [ "factor" ] } 0|| ] unit-test
+[ 11 ] [ 10 { [ odd? ] [ 100 > ] [ 1 + ] } 1|| ] unit-test
+[ 30 ] [ 10 20 { [ + odd? ] [ + 100 > ] [ + ] } 2|| ] unit-test
+[ f ] [ { [ 10 0 < ] [ f ] [ 0 1 = ] } 0|| ] unit-test
-[ 10 20 { [ + odd? ] [ + 100 > ] [ + ] } 2|| 30 = ] must-be-t
+: compiled-&& ( a -- ? ) { [ 0 > ] [ even? ] [ 2 + ] } 1&& ;
-[ { [ 10 0 < ] [ f ] [ 0 1 = ] } 0|| ] must-be-f
+[ f ] [ 3 compiled-&& ] unit-test
+[ 4 ] [ 2 compiled-&& ] unit-test
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+: compiled-|| ( a b -- ? ) { [ + odd? ] [ + 100 > ] [ + ] } 2|| ;
+[ 30 ] [ 10 20 compiled-|| ] unit-test
+[ 2 ] [ 1 1 compiled-|| ] unit-test
\ No newline at end of file
n '[ _ nnip ] suffix 1array
[ cond ] 3append ;
-MACRO: 0&& ( quots -- quot ) '[ _ 0 n&& ] ;
-MACRO: 1&& ( quots -- quot ) '[ _ 1 n&& ] ;
-MACRO: 2&& ( quots -- quot ) '[ _ 2 n&& ] ;
-MACRO: 3&& ( quots -- quot ) '[ _ 3 n&& ] ;
+<PRIVATE
+
+: unoptimized-&& ( quots quot -- ? )
+ [ [ call dup ] ] dip call [ nip ] prepose [ f ] 2dip all? swap and ; inline
+
+PRIVATE>
+
+: 0&& ( quots -- ? ) [ ] unoptimized-&& ;
+: 1&& ( obj quots -- ? ) [ with ] unoptimized-&& ;
+: 2&& ( obj1 obj2 quots -- ? ) [ with with ] unoptimized-&& ;
+: 3&& ( obj1 obj2 obj3 quots -- ? ) [ with with with ] unoptimized-&& ;
MACRO:: n|| ( quots n -- quot )
[ f ] quots [| q |
n '[ drop _ ndrop t ] [ f ] 2array suffix 1array
[ cond ] 3append ;
-MACRO: 0|| ( quots -- quot ) '[ _ 0 n|| ] ;
-MACRO: 1|| ( quots -- quot ) '[ _ 1 n|| ] ;
-MACRO: 2|| ( quots -- quot ) '[ _ 2 n|| ] ;
-MACRO: 3|| ( quots -- quot ) '[ _ 3 n|| ] ;
+<PRIVATE
+
+: unoptimized-|| ( quots quot -- ? )
+ [ [ call ] ] dip call map-find drop ; inline
+
+PRIVATE>
+
+: 0|| ( quots -- ? ) [ ] unoptimized-|| ;
+: 1|| ( obj quots -- ? ) [ with ] unoptimized-|| ;
+: 2|| ( obj1 obj2 quots -- ? ) [ with with ] unoptimized-|| ;
+: 3|| ( obj1 obj2 obj3 quots -- ? ) [ with with with ] unoptimized-|| ;
-
USING: kernel math tools.test combinators.short-circuit.smart ;
-
IN: combinators.short-circuit.smart.tests
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: must-be-t ( in -- ) [ t ] swap unit-test ;
-: must-be-f ( in -- ) [ f ] swap unit-test ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-[ { [ 1 ] [ 2 ] [ 3 ] } && 3 = ] must-be-t
-[ 3 { [ 0 > ] [ odd? ] [ 2 + ] } && 5 = ] must-be-t
-[ 10 20 { [ + 0 > ] [ - even? ] [ + ] } && 30 = ] must-be-t
-
-[ { [ 1 ] [ f ] [ 3 ] } && 3 = ] must-be-f
-[ 3 { [ 0 > ] [ even? ] [ 2 + ] } && ] must-be-f
-[ 10 20 { [ + 0 > ] [ - odd? ] [ + ] } && 30 = ] must-be-f
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-[ { [ 10 0 < ] [ f ] [ "factor" ] } || "factor" = ] must-be-t
+[ t ] [ { [ 1 ] [ 2 ] [ 3 ] } && 3 = ] unit-test
+[ t ] [ 3 { [ 0 > ] [ odd? ] [ 2 + ] } && 5 = ] unit-test
+[ t ] [ 10 20 { [ + 0 > ] [ - even? ] [ + ] } && 30 = ] unit-test
-[ 10 { [ odd? ] [ 100 > ] [ 1 + ] } || 11 = ] must-be-t
+[ f ] [ { [ 1 ] [ f ] [ 3 ] } && 3 = ] unit-test
+[ f ] [ 3 { [ 0 > ] [ even? ] [ 2 + ] } && ] unit-test
+[ f ] [ 10 20 { [ + 0 > ] [ - odd? ] [ + ] } && 30 = ] unit-test
-[ 10 20 { [ + odd? ] [ + 100 > ] [ + ] } || 30 = ] must-be-t
+[ t ] [ { [ 10 0 < ] [ f ] [ "factor" ] } || "factor" = ] unit-test
-[ { [ 10 0 < ] [ f ] [ 0 1 = ] } || ] must-be-f
+[ t ] [ 10 { [ odd? ] [ 100 > ] [ 1 + ] } || 11 = ] unit-test
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+[ t ] [ 10 20 { [ + odd? ] [ + 100 > ] [ + ] } || 30 = ] unit-test
+[ f ] [ { [ 10 0 < ] [ f ] [ 0 1 = ] } || ] unit-test
-USING: kernel sequences math stack-checker effects accessors macros
-fry combinators.short-circuit ;
+USING: kernel sequences math stack-checker effects accessors
+macros fry combinators.short-circuit ;
IN: combinators.short-circuit.smart
<PRIVATE
+ERROR: cannot-determine-arity ;
+
: arity ( quots -- n )
first infer
- dup terminated?>> [ "Cannot determine arity" throw ] when
- effect-height neg 1+ ;
+ dup terminated?>> [ cannot-determine-arity ] when
+ effect-height neg 1 + ;
PRIVATE>
{ $example
<" USING: combinators combinators.smart math prettyprint ;
9 [
- { [ 1- ] [ 1+ ] [ sq ] } cleave
+ { [ 1 - ] [ 1 + ] [ sq ] } cleave
] output>array .">
"{ 8 10 81 }"
}
{ $examples
{ $example
"USING: combinators.smart kernel math prettyprint ;"
- "10 [ [ 1- ] [ 1+ ] bi ] sum-outputs ."
+ "10 [ [ 1 - ] [ 1 + ] bi ] sum-outputs ."
"20"
}
} ;
{ append-outputs append-outputs-as } related-words
+HELP: drop-outputs
+{ $values { "quot" quotation } }
+{ $description "Calls a quotation and drops any values it leaves on the stack." } ;
+
+HELP: keep-inputs
+{ $values { "quot" quotation } }
+{ $description "Calls a quotation and preserves any values it takes off the stack." } ;
+
+{ drop-outputs keep-inputs } related-words
ARTICLE: "combinators.smart" "Smart combinators"
"A " { $emphasis "smart combinator" } " is a macro which reflects on the stack effect of an input quotation. The " { $vocab-link "combinators.smart" } " vocabulary implements a few simple smart combinators which look at the static stack effects of input quotations and generate code which produces or consumes the relevant number of stack values." $nl
-"Call a quotation and discard all output values:"
+"Call a quotation and discard all output values or preserve all input values:"
{ $subsection drop-outputs }
+{ $subsection keep-inputs }
"Take all input values from a sequence:"
{ $subsection input<sequence }
"Store all output values to a sequence:"
IN: combinators.smart.tests
: test-bi ( -- 9 11 )
- 10 [ 1- ] [ 1+ ] bi ;
+ 10 [ 1 - ] [ 1 + ] bi ;
[ [ test-bi ] output>array ] must-infer
[ { 9 11 } ] [ [ test-bi ] output>array ] unit-test
[ { { 1 2 } { 3 4 } } ] [ nested-smart-combo-test ] unit-test
-[ 14 ] [ [ 1 2 3 ] [ sq ] [ + ] map-reduce-outputs ] unit-test
\ No newline at end of file
+[ 14 ] [ [ 1 2 3 ] [ sq ] [ + ] map-reduce-outputs ] unit-test
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors fry generalizations kernel macros math.order
-stack-checker math ;
+stack-checker math sequences ;
IN: combinators.smart
MACRO: drop-outputs ( quot -- quot' )
dup infer out>> '[ @ _ ndrop ] ;
+MACRO: keep-inputs ( quot -- quot' )
+ dup infer in>> '[ _ _ nkeep ] ;
+
MACRO: output>sequence ( quot exemplar -- newquot )
[ dup infer out>> ] dip
'[ @ _ _ nsequence ] ;
MACRO: append-outputs ( quot -- seq )
'[ _ { } append-outputs-as ] ;
+
+MACRO: preserving ( quot -- )
+ [ infer in>> length ] keep '[ _ ndup @ ] ;
+
+MACRO: smart-if ( pred true false -- )
+ '[ _ preserving _ _ if ] ; inline
+++ /dev/null
-IN: compiler.cfg.alias-analysis.tests
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math namespaces assocs hashtables sequences arrays
-accessors vectors combinators sets classes compiler.cfg
+accessors vectors combinators sets classes cpu.architecture compiler.cfg
compiler.cfg.registers compiler.cfg.instructions
-compiler.cfg.copy-prop compiler.cfg.rpo
-compiler.cfg.liveness compiler.cfg.local ;
+compiler.cfg.copy-prop compiler.cfg.rpo compiler.cfg.liveness ;
IN: compiler.cfg.alias-analysis
! We try to eliminate redundant slot operations using some simple heuristics.
SYMBOL: ac-counter
: next-ac ( -- n )
- ac-counter [ dup 1+ ] change ;
+ ac-counter [ dup 1 + ] change ;
! Alias class for objects which are loaded from the data stack
! or other object slots. We pessimistically assume that they
M: ##set-slot-imm insn-object obj>> resolve ;
M: ##alien-global insn-object drop \ ##alien-global ;
-: init-alias-analysis ( live-in -- )
+: init-alias-analysis ( insns -- insns' )
H{ } clone histories set
H{ } clone vregs>acs set
H{ } clone acs>vregs set
0 ac-counter set
next-ac heap-ac set
- [ set-heap-ac ] each ;
+ dup local-live-in [ set-heap-ac ] each ;
GENERIC: analyze-aliases* ( insn -- insn' )
call-next-method
dup [ dst>> ] [ insn-slot# ] [ insn-object ] tri
2dup live-slot dup [
- 2nip \ ##copy new-insn analyze-aliases* nip
+ 2nip any-rep \ ##copy new-insn analyze-aliases* nip
] [
drop remember-slot
] if ;
[ insn# set eliminate-dead-stores* ] map-index sift ;
: alias-analysis-step ( insns -- insns' )
+ init-alias-analysis
analyze-aliases
compute-live-stores
eliminate-dead-stores ;
: alias-analysis ( cfg -- cfg' )
- [ init-alias-analysis ] [ alias-analysis-step ] local-optimization ;
\ No newline at end of file
+ [ alias-analysis-step ] local-optimization ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators.short-circuit kernel sequences math
+compiler.utilities compiler.cfg compiler.cfg.instructions compiler.cfg.rpo
+compiler.cfg.predecessors compiler.cfg.utilities ;
+IN: compiler.cfg.block-joining
+
+! Joining blocks that are not calls and are connected by a single CFG edge.
+! This pass does not update ##phi nodes and should therefore only run
+! before stack analysis.
+: join-block? ( bb -- ? )
+ {
+ [ kill-block? not ]
+ [ predecessors>> length 1 = ]
+ [ predecessor kill-block? not ]
+ [ predecessor successors>> length 1 = ]
+ [ [ predecessor ] keep back-edge? not ]
+ } 1&& ;
+
+: join-instructions ( bb pred -- )
+ [ instructions>> ] bi@ dup pop* push-all ;
+
+: update-successors ( bb pred -- )
+ [ successors>> ] dip (>>successors) ;
+
+: join-block ( bb pred -- )
+ [ join-instructions ] [ update-successors ] 2bi ;
+
+: join-blocks ( cfg -- cfg' )
+ needs-predecessors
+
+ dup post-order [
+ dup join-block?
+ [ dup predecessor join-block ] [ drop ] if
+ ] each
+
+ cfg-changed predecessors-changed ;
--- /dev/null
+Doug Coleman
\ No newline at end of file
--- /dev/null
+USING: accessors assocs compiler.cfg
+compiler.cfg.branch-splitting compiler.cfg.debugger
+compiler.cfg.predecessors compiler.cfg.rpo compiler.cfg.instructions fry kernel
+tools.test namespaces sequences vectors ;
+IN: compiler.cfg.branch-splitting.tests
+
+: get-predecessors ( cfg -- assoc )
+ H{ } clone [ '[ [ predecessors>> ] keep _ set-at ] each-basic-block ] keep ;
+
+: check-predecessors ( cfg -- )
+ [ get-predecessors ]
+ [ needs-predecessors drop ]
+ [ get-predecessors ] tri assert= ;
+
+: check-branch-splitting ( cfg -- )
+ needs-predecessors
+ split-branches
+ check-predecessors ;
+
+: test-branch-splitting ( -- )
+ cfg new 0 get >>entry check-branch-splitting ;
+
+V{ T{ ##branch } } 0 test-bb
+
+V{ T{ ##branch } } 1 test-bb
+
+V{ T{ ##branch } } 2 test-bb
+
+V{ T{ ##branch } } 3 test-bb
+
+V{ T{ ##branch } } 4 test-bb
+
+test-diamond
+
+[ ] [ test-branch-splitting ] unit-test
+
+V{ T{ ##branch } } 0 test-bb
+
+V{ T{ ##branch } } 1 test-bb
+
+V{ T{ ##branch } } 2 test-bb
+
+V{ T{ ##branch } } 3 test-bb
+
+V{ T{ ##branch } } 4 test-bb
+
+V{ T{ ##branch } } 5 test-bb
+
+0 { 1 2 } edges
+
+1 { 3 4 } edges
+
+2 { 3 4 } edges
+
+[ ] [ test-branch-splitting ] unit-test
+
+V{ T{ ##branch } } 0 test-bb
+
+V{ T{ ##branch } } 1 test-bb
+
+V{ T{ ##branch } } 2 test-bb
+
+V{ T{ ##branch } } 3 test-bb
+
+V{ T{ ##branch } } 4 test-bb
+
+0 { 1 2 } edges
+
+1 { 3 4 } edges
+
+2 4 edge
+
+[ ] [ test-branch-splitting ] unit-test
+
+V{ T{ ##branch } } 0 test-bb
+
+V{ T{ ##branch } } 1 test-bb
+
+V{ T{ ##branch } } 2 test-bb
+
+0 { 1 2 } edges
+
+1 2 edge
+
+[ ] [ test-branch-splitting ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Doug Coleman, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators.short-circuit kernel math math.order
+sequences assocs namespaces vectors fry arrays splitting
+compiler.cfg.def-use compiler.cfg compiler.cfg.rpo compiler.cfg.predecessors
+compiler.cfg.renaming compiler.cfg.instructions compiler.cfg.utilities ;
+IN: compiler.cfg.branch-splitting
+
+: clone-instructions ( insns -- insns' )
+ [ clone dup rename-insn-temps ] map ;
+
+: clone-basic-block ( bb -- bb' )
+ ! The new block temporarily gets the same RPO number as the old one,
+ ! until the next time RPO is computed. This is just to make
+ ! 'back-edge?' work.
+ <basic-block>
+ swap
+ [ instructions>> clone-instructions >>instructions ]
+ [ successors>> clone >>successors ]
+ [ number>> >>number ]
+ tri ;
+
+: new-blocks ( bb -- copies )
+ dup predecessors>> [
+ [ clone-basic-block ] dip
+ 1vector >>predecessors
+ ] with map ;
+
+: update-predecessor-successor ( pred copy old-bb -- )
+ '[
+ [ _ _ 3dup nip eq? [ drop nip ] [ 2drop ] if ] map
+ ] change-successors drop ;
+
+: update-predecessor-successors ( copies old-bb -- )
+ [ predecessors>> swap ] keep
+ '[ _ update-predecessor-successor ] 2each ;
+
+: update-successor-predecessor ( copies old-bb succ -- )
+ [
+ swap 1array split swap join V{ } like
+ ] change-predecessors drop ;
+
+: update-successor-predecessors ( copies old-bb -- )
+ dup successors>> [
+ update-successor-predecessor
+ ] with with each ;
+
+: split-branch ( bb -- )
+ [ new-blocks ] keep
+ [ update-predecessor-successors ]
+ [ update-successor-predecessors ]
+ 2bi ;
+
+UNION: irrelevant ##peek ##replace ##inc-d ##inc-r ;
+
+: split-instructions? ( insns -- ? ) [ irrelevant? not ] count 5 <= ;
+
+: short-tail-block? ( bb -- ? )
+ [ successors>> empty? ] [ instructions>> length 2 = ] bi and ;
+
+: short-block? ( bb -- ? )
+ ! If block is empty, always split
+ [ predecessors>> length ] [ instructions>> length 1 - ] bi * 10 <= ;
+
+: cond-cond-block? ( bb -- ? )
+ {
+ [ predecessors>> length 2 = ]
+ [ successors>> length 2 = ]
+ [ instructions>> length 20 <= ]
+ } 1&& ;
+
+: split-branch? ( bb -- ? )
+ dup loop-entry? [ drop f ] [
+ dup predecessors>> length 1 <= [ drop f ] [
+ {
+ [ short-block? ]
+ [ short-tail-block? ]
+ [ cond-cond-block? ]
+ } 1||
+ ] if
+ ] if ;
+
+: split-branches ( cfg -- cfg' )
+ needs-predecessors
+
+ dup [
+ dup split-branch? [ split-branch ] [ drop ] if
+ ] each-basic-block
+
+ cfg-changed ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces accessors math.order assocs kernel sequences
-combinators make classes words cpu.architecture
+combinators make classes words cpu.architecture layouts
compiler.cfg.instructions compiler.cfg.registers
compiler.cfg.stack-frame ;
IN: compiler.cfg.build-stack-frame
SYMBOL: frame-required?
-SYMBOL: spill-counts
-
GENERIC: compute-stack-frame* ( insn -- )
: request-stack-frame ( stack-frame -- )
+ frame-required? on
stack-frame [ max-stack-frame ] change ;
-M: ##stack-frame compute-stack-frame*
- frame-required? on
+M: ##alien-invoke compute-stack-frame*
+ stack-frame>> request-stack-frame ;
+
+M: ##alien-indirect compute-stack-frame*
+ stack-frame>> request-stack-frame ;
+
+M: ##alien-callback compute-stack-frame*
stack-frame>> request-stack-frame ;
M: ##call compute-stack-frame*
M: _gc compute-stack-frame*
frame-required? on
- stack-frame new swap gc-root-size>> >>gc-root-size
+ stack-frame new swap tagged-values>> length cells >>gc-root-size
request-stack-frame ;
-M: _spill-counts compute-stack-frame*
- counts>> stack-frame get (>>spill-counts) ;
+M: _spill-area-size compute-stack-frame*
+ n>> stack-frame get (>>spill-area-size) ;
M: insn compute-stack-frame*
class frame-required? word-prop [
] when ;
\ _spill t frame-required? set-word-prop
-\ ##fixnum-add t frame-required? set-word-prop
-\ ##fixnum-sub t frame-required? set-word-prop
-\ ##fixnum-mul t frame-required? set-word-prop
-\ ##fixnum-add-tail f frame-required? set-word-prop
-\ ##fixnum-sub-tail f frame-required? set-word-prop
-\ ##fixnum-mul-tail f frame-required? set-word-prop
: compute-stack-frame ( insns -- )
frame-required? off
- T{ stack-frame } clone stack-frame set
+ stack-frame new stack-frame set
[ compute-stack-frame* ] each
stack-frame get dup stack-frame-size >>total-size drop ;
GENERIC: insert-pro/epilogues* ( insn -- )
-M: ##stack-frame insert-pro/epilogues* drop ;
-
M: ##prologue insert-pro/epilogues*
drop frame-required? get [ stack-frame get _prologue ] when ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays fry kernel make math namespaces sequences
+compiler.cfg compiler.cfg.instructions compiler.cfg.stacks
+compiler.cfg.stacks.local ;
+IN: compiler.cfg.builder.blocks
+
+: set-basic-block ( basic-block -- )
+ [ basic-block set ] [ instructions>> building set ] bi
+ begin-local-analysis ;
+
+: initial-basic-block ( -- )
+ <basic-block> set-basic-block ;
+
+: end-basic-block ( -- )
+ basic-block get [ end-local-analysis ] when
+ building off
+ basic-block off ;
+
+: (begin-basic-block) ( -- )
+ <basic-block>
+ basic-block get [ dupd successors>> push ] when*
+ set-basic-block ;
+
+: begin-basic-block ( -- )
+ basic-block get [ end-local-analysis ] when
+ (begin-basic-block) ;
+
+: emit-trivial-block ( quot -- )
+ ##branch begin-basic-block
+ call
+ ##branch begin-basic-block ; inline
+
+: call-height ( #call -- n )
+ [ out-d>> length ] [ in-d>> length ] bi - ;
+
+: emit-primitive ( node -- )
+ [
+ [ word>> ##call ]
+ [ call-height adjust-d ] bi
+ ] emit-trivial-block ;
+
+: begin-branch ( -- ) clone-current-height (begin-basic-block) ;
+
+: end-branch ( -- pair/f )
+ ! pair is { final-bb final-height }
+ basic-block get dup [
+ ##branch
+ end-local-analysis
+ current-height get clone 2array
+ ] when ;
+
+: with-branch ( quot -- pair/f )
+ [ begin-branch call end-branch ] with-scope ; inline
+
+: set-successors ( branches -- )
+ ! Set the successor of each branch's final basic block to the
+ ! current block.
+ basic-block get dup [
+ '[ [ [ _ ] dip first successors>> push ] when* ] each
+ ] [ 2drop ] if ;
+
+: merge-heights ( branches -- )
+ ! If all elements are f, that means every branch ended with a backward
+ ! jump so the height is irrelevant since this block is unreachable.
+ [ ] find nip [ second current-height set ] [ end-basic-block ] if* ;
+
+: emit-conditional ( branches -- )
+ ! branchies is a sequence of pairs as above
+ end-basic-block
+ [ merge-heights begin-basic-block ]
+ [ set-successors ]
+ bi ;
+
+USING: tools.test kernel sequences words sequences.private fry
+prettyprint alien alien.accessors math.private compiler.tree.builder
+compiler.tree.optimizer compiler.cfg.builder compiler.cfg.debugger
+compiler.cfg.optimizer compiler.cfg.predecessors compiler.cfg.checker
+compiler.cfg arrays locals byte-arrays kernel.private math
+slots.private vectors sbufs strings math.partial-dispatch
+strings.private accessors compiler.cfg.instructions ;
IN: compiler.cfg.builder.tests
-USING: tools.test kernel sequences
-words sequences.private fry prettyprint alien alien.accessors
-math.private compiler.tree.builder compiler.tree.optimizer
-compiler.cfg.builder compiler.cfg.debugger arrays locals byte-arrays
-kernel.private math ;
! Just ensure that various CFGs build correctly.
-: unit-test-cfg ( quot -- ) '[ _ test-cfg drop ] [ ] swap unit-test ;
+: unit-test-cfg ( quot -- )
+ '[ _ test-cfg [ [ optimize-cfg check-cfg ] with-cfg ] each ] [ ] swap unit-test ;
+
+: blahblah ( nodes -- ? )
+ { fixnum } declare [
+ dup 3 bitand 1 = [ drop t ] [
+ dup 3 bitand 2 = [
+ blahblah
+ ] [ drop f ] if
+ ] if
+ ] any? ; inline recursive
+
+: more? ( x -- ? ) ;
+
+: test-case-1 ( -- ? ) f ;
+
+: test-case-2 ( -- )
+ test-case-1 [ test-case-2 ] [ ] if ; inline recursive
{
[ ]
[ 3 fixnum+fast ]
[ fixnum*fast ]
[ 3 fixnum*fast ]
+ [ 3 swap fixnum*fast ]
[ fixnum-shift-fast ]
[ 10 fixnum-shift-fast ]
[ -10 fixnum-shift-fast ]
[ 0 fixnum-shift-fast ]
+ [ 10 swap fixnum-shift-fast ]
+ [ -10 swap fixnum-shift-fast ]
+ [ 0 swap fixnum-shift-fast ]
[ fixnum-bitnot ]
[ eq? ]
[ "hi" eq? ]
[ "int" f "malloc" { "int" } alien-invoke ]
[ "int" { "int" } "cdecl" alien-indirect ]
[ "int" { "int" } "cdecl" [ ] alien-callback ]
+ [ swap - + * ]
+ [ swap slot ]
+ [ blahblah ]
+ [ 1000 [ dup [ reverse ] when ] times ]
+ [ 1array ]
+ [ 1 2 ? ]
+ [ { array } declare [ ] map ]
+ [ { array } declare dup 1 slot [ 1 slot ] when ]
+ [ [ dup more? ] [ dup ] produce ]
+ [ vector new over test-case-1 [ test-case-2 ] [ ] if ]
+ [ [ [ nth-unsafe ".." = 0 ] dip set-nth-unsafe ] 2curry (each-integer) ]
+ [
+ { fixnum sbuf } declare 2dup 3 slot fixnum> [
+ over 3 fixnum* over dup [ 2 slot resize-string ] dip 2 set-slot
+ ] [ ] if
+ ]
+ [ [ 2 fixnum* ] when 3 ]
+ [ [ 2 fixnum+ ] when 3 ]
+ [ [ 2 fixnum- ] when 3 ]
+ [ 10000 [ ] times ]
+ [
+ over integer? [
+ over dup 16 <-integer-fixnum
+ [ 0 >=-integer-fixnum ] [ drop f ] if [
+ nip dup
+ [ ] [ ] if
+ ] [ 2drop f ] if
+ ] [ 2drop f ] if
+ ]
+ [
+ pick 10 fixnum>= [ [ 123 fixnum-bitand ] 2dip ] [ ] if
+ set-string-nth-fast
+ ]
} [
unit-test-cfg
] each
{ pinned-c-ptr class } \ set-alien-cell '[ _ declare 10 _ execute ] unit-test-cfg
{ pinned-c-ptr class fixnum } \ set-alien-cell '[ _ declare _ execute ] unit-test-cfg
] each
+
+: contains-insn? ( quot insn-check -- ? )
+ [ test-mr [ instructions>> ] map ] dip
+ '[ _ any? ] any? ; inline
+
+[ t ] [ [ swap ] [ ##replace? ] contains-insn? ] unit-test
+
+[ f ] [ [ swap swap ] [ ##replace? ] contains-insn? ] unit-test
+
+[ t ] [
+ [ { fixnum byte-array fixnum } declare set-alien-unsigned-1 ]
+ [ ##set-alien-integer-1? ] contains-insn?
+] unit-test
+
+[ t ] [
+ [ { fixnum byte-array fixnum } declare [ dup * dup * ] 2dip set-alien-unsigned-1 ]
+ [ ##set-alien-integer-1? ] contains-insn?
+] unit-test
+
+[ f ] [
+ [ { byte-array fixnum } declare set-alien-unsigned-1 ]
+ [ ##set-alien-integer-1? ] contains-insn?
+] unit-test
+
+[ f ] [
+ [ 1000 [ ] times ]
+ [ [ ##peek? ] [ ##replace? ] bi or ] contains-insn?
+] unit-test
\ No newline at end of file
-! Copyright (C) 2004, 2008 Slava Pestov.
+! Copyright (C) 2004, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators hashtables kernel
math fry namespaces make sequences words byte-arrays
compiler.tree.propagation.info
compiler.cfg
compiler.cfg.hats
-compiler.cfg.stacks
-compiler.cfg.iterator
compiler.cfg.utilities
compiler.cfg.registers
compiler.cfg.intrinsics
+compiler.cfg.comparisons
compiler.cfg.stack-frame
compiler.cfg.instructions
+compiler.cfg.predecessors
+compiler.cfg.builder.blocks
+compiler.cfg.stacks
+compiler.cfg.stacks.local
compiler.alien ;
IN: compiler.cfg.builder
-! Convert tree SSA IR to CFG SSA IR.
+! Convert tree SSA IR to CFG IR. The result is not in SSA form; this is
+! constructed later by calling compiler.cfg.ssa.construction:construct-ssa.
SYMBOL: procedures
-SYMBOL: current-word
-SYMBOL: current-label
SYMBOL: loops
-SYMBOL: first-basic-block
-! Basic block after prologue, makes recursion faster
-SYMBOL: current-label-start
-
-: add-procedure ( -- )
- basic-block get current-word get current-label get
- <cfg> procedures get push ;
+: begin-cfg ( word label -- cfg )
+ initial-basic-block
+ H{ } clone loops set
+ [ basic-block get ] 2dip <cfg> dup cfg set ;
: begin-procedure ( word label -- )
- end-basic-block
- begin-basic-block
- H{ } clone loops set
- current-label set
- current-word set
- add-procedure ;
+ begin-cfg procedures get push ;
: with-cfg-builder ( nodes word label quot -- )
- '[ begin-procedure @ ] with-scope ; inline
-
-GENERIC: emit-node ( node -- next )
+ '[
+ begin-stack-analysis
+ begin-procedure
+ @
+ end-stack-analysis
+ ] with-scope ; inline
-: check-basic-block ( node -- node' )
- basic-block get [ drop f ] unless ; inline
+GENERIC: emit-node ( node -- )
: emit-nodes ( nodes -- )
- [ current-node emit-node check-basic-block ] iterate-nodes ;
+ [ basic-block get [ emit-node ] [ drop ] if ] each ;
: begin-word ( -- )
- #! We store the basic block after the prologue as a loop
- #! labeled by the current word, so that self-recursive
- #! calls can skip an epilogue/prologue.
##prologue
##branch
- begin-basic-block
- basic-block get first-basic-block set ;
+ begin-basic-block ;
: (build-cfg) ( nodes word label -- )
[
begin-word
- V{ } clone node-stack set
emit-nodes
] with-cfg-builder ;
] with-variable
] keep ;
-: local-recursive-call ( basic-block -- next )
+: emit-loop-call ( basic-block -- )
##branch
basic-block get successors>> push
- stop-iterating ;
+ end-basic-block ;
-: emit-call ( word height -- next )
- {
- { [ over loops get key? ] [ drop loops get at local-recursive-call ] }
- { [ terminate-call? ] [ ##call stop-iterating ] }
- { [ tail-call? not ] [ ##call ##branch begin-basic-block iterate-next ] }
- { [ dup current-label get eq? ] [ 2drop first-basic-block get local-recursive-call ] }
- [ drop ##epilogue ##jump stop-iterating ]
- } cond ;
+: emit-call ( word height -- )
+ over loops get key?
+ [ drop loops get at emit-loop-call ]
+ [ [ [ ##call ] [ adjust-d ] bi* ] emit-trivial-block ]
+ if ;
! #recursive
: recursive-height ( #recursive -- n )
[ label>> return>> in-d>> length ] [ in-d>> length ] bi - ;
-: emit-recursive ( #recursive -- next )
+: emit-recursive ( #recursive -- )
[ [ label>> id>> ] [ recursive-height ] bi emit-call ]
[ [ child>> ] [ label>> word>> ] [ label>> id>> ] tri (build-cfg) ] bi ;
: remember-loop ( label -- )
basic-block get swap loops get set-at ;
-: emit-loop ( node -- next )
- ##loop-entry
+: emit-loop ( node -- )
##branch
begin-basic-block
- [ label>> id>> remember-loop ] [ child>> emit-nodes ] bi
- iterate-next ;
+ [ label>> id>> remember-loop ] [ child>> emit-nodes ] bi ;
M: #recursive emit-node
dup label>> loop?>> [ emit-loop ] [ emit-recursive ] if ;
! #if
: emit-branch ( obj -- final-bb )
- [
- begin-basic-block
- emit-nodes
- basic-block get dup [ ##branch ] when
- ] with-scope ;
+ [ emit-nodes ] with-branch ;
: emit-if ( node -- )
- children>> [ emit-branch ] map
- end-basic-block
- begin-basic-block
- basic-block get '[ [ _ swap successors>> push ] when* ] each ;
-
-: ##branch-t ( vreg -- )
- \ f tag-number cc/= ##compare-imm-branch ;
+ children>> [ emit-branch ] map emit-conditional ;
: trivial-branch? ( nodes -- value ? )
dup length 1 = [
: emit-trivial-not-if ( -- )
ds-pop \ f tag-number cc= ^^compare-imm ds-push ;
+: emit-actual-if ( #if -- )
+ ! Inputs to the final instruction need to be copied because of
+ ! loc>vreg sync
+ ds-pop ^^copy \ f tag-number cc/= ##compare-imm-branch emit-if ;
+
M: #if emit-node
{
{ [ dup trivial-if? ] [ drop emit-trivial-if ] }
{ [ dup trivial-not-if? ] [ drop emit-trivial-not-if ] }
- [ ds-pop ##branch-t emit-if ]
- } cond iterate-next ;
+ [ emit-actual-if ]
+ } cond ;
! #dispatch
M: #dispatch emit-node
- ds-pop ^^offset>slot i ##dispatch emit-if iterate-next ;
+ ! Inputs to the final instruction need to be copied because of
+ ! loc>vreg sync. ^^offset>slot always returns a fresh vreg,
+ ! though.
+ ds-pop ^^offset>slot next-vreg ##dispatch emit-if ;
! #call
M: #call emit-node
! #push
M: #push emit-node
- literal>> ^^load-literal ds-push iterate-next ;
+ literal>> ^^load-literal ds-push ;
! #shuffle
+
+! Even though low level IR has its own dead code elimination pass,
+! we try not to introduce useless ##peeks here, since this reduces
+! the accuracy of global stack analysis.
+
+: make-input-map ( #shuffle -- assoc )
+ ! Assoc maps high-level IR values to stack locations.
+ [
+ [ in-d>> <reversed> [ <ds-loc> swap set ] each-index ]
+ [ in-r>> <reversed> [ <rs-loc> swap set ] each-index ] bi
+ ] H{ } make-assoc ;
+
+: make-output-seq ( values mapping input-map -- vregs )
+ '[ _ at _ at peek-loc ] map ;
+
+: load-shuffle ( #shuffle mapping input-map -- ds-vregs rs-vregs )
+ [ [ out-d>> ] 2dip make-output-seq ]
+ [ [ out-r>> ] 2dip make-output-seq ] 3bi ;
+
+: store-shuffle ( #shuffle ds-vregs rs-vregs -- )
+ [ [ in-d>> length neg inc-d ] dip ds-store ]
+ [ [ in-r>> length neg inc-r ] dip rs-store ]
+ bi-curry* bi ;
+
M: #shuffle emit-node
- dup
- H{ } clone
- [ [ in-d>> [ length ds-load ] keep ] dip '[ _ set-at ] 2each ]
- [ [ in-r>> [ length rs-load ] keep ] dip '[ _ set-at ] 2each ]
- [ nip ] 2tri
- [ [ [ out-d>> ] [ mapping>> ] bi ] dip '[ _ at _ at ] map ds-store ]
- [ [ [ out-r>> ] [ mapping>> ] bi ] dip '[ _ at _ at ] map rs-store ] 2bi
- iterate-next ;
+ dup dup [ mapping>> ] [ make-input-map ] bi load-shuffle store-shuffle ;
! #return
-M: #return emit-node
- drop ##epilogue ##return stop-iterating ;
+: emit-return ( -- )
+ ##branch begin-basic-block ##epilogue ##return ;
+
+M: #return emit-node drop emit-return ;
M: #return-recursive emit-node
- label>> id>> loops get key?
- [ iterate-next ] [ ##epilogue ##return stop-iterating ] if ;
+ label>> id>> loops get key? [ emit-return ] unless ;
! #terminate
-M: #terminate emit-node drop stop-iterating ;
+M: #terminate emit-node drop ##no-tco end-basic-block ;
! FFI
: return-size ( ctype -- n )
[ return>> return-size >>return ]
[ alien-parameters parameter-sizes drop >>params ] bi ;
-: alien-stack-frame ( params -- )
- <alien-stack-frame> ##stack-frame ;
+: alien-node-height ( params -- )
+ [ out-d>> length ] [ in-d>> length ] bi - adjust-d ;
-: emit-alien-node ( node quot -- next )
- [ params>> ] dip [ drop alien-stack-frame ] [ call ] 2bi
- ##branch begin-basic-block iterate-next ; inline
+: emit-alien-node ( node quot -- )
+ [
+ [ params>> dup dup <alien-stack-frame> ] dip call
+ alien-node-height
+ ] emit-trivial-block ; inline
M: #alien-invoke emit-node
[ ##alien-invoke ] emit-alien-node ;
dup params>> xt>> dup
[
##prologue
- dup [ ##alien-callback ] emit-alien-node drop
+ dup [ ##alien-callback ] emit-alien-node
##epilogue
params>> ##callback-return
- ] with-cfg-builder
- iterate-next ;
+ ] with-cfg-builder ;
! No-op nodes
-M: #introduce emit-node drop iterate-next ;
+M: #introduce emit-node drop ;
+
+M: #copy emit-node drop ;
-M: #copy emit-node drop iterate-next ;
+M: #enter-recursive emit-node drop ;
-M: #enter-recursive emit-node drop iterate-next ;
+M: #phi emit-node drop ;
-M: #phi emit-node drop iterate-next ;
+M: #declare emit-node drop ;
\ No newline at end of file
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel arrays vectors accessors
-namespaces make fry sequences ;
+USING: kernel math vectors arrays accessors namespaces ;
IN: compiler.cfg
TUPLE: basic-block < identity-tuple
-id
+{ id integer }
number
{ instructions vector }
{ successors vector }
V{ } clone >>predecessors
\ basic-block counter >>id ;
-: add-instructions ( bb quot -- )
- [ instructions>> building ] dip '[
- building get pop
- _ dip
- building get push
- ] with-variable ; inline
+TUPLE: cfg { entry basic-block } word label
+spill-area-size reps
+post-order linear-order
+predecessors-valid? dominance-valid? loops-valid? ;
-TUPLE: cfg { entry basic-block } word label spill-counts post-order ;
+: <cfg> ( entry word label -- cfg )
+ cfg new
+ swap >>label
+ swap >>word
+ swap >>entry ;
+
+: cfg-changed ( cfg -- cfg )
+ f >>post-order
+ f >>linear-order
+ f >>dominance-valid?
+ f >>loops-valid? ; inline
+
+: predecessors-changed ( cfg -- cfg )
+ f >>predecessors-valid? ;
-: <cfg> ( entry word label -- cfg ) f f cfg boa ;
+: with-cfg ( cfg quot: ( cfg -- ) -- )
+ [ dup cfg ] dip with-variable ; inline
TUPLE: mr { instructions array } word label ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel compiler.cfg.instructions compiler.cfg.rpo
-compiler.cfg.def-use compiler.cfg.linearization compiler.cfg.liveness
-combinators.short-circuit accessors math sequences sets assocs ;
+compiler.cfg.def-use compiler.cfg.linearization compiler.cfg.utilities
+compiler.cfg.mr combinators.short-circuit accessors math
+sequences sets assocs ;
IN: compiler.cfg.checker
-ERROR: last-insn-not-a-jump insn ;
+ERROR: bad-kill-block bb ;
+
+: check-kill-block ( bb -- )
+ dup instructions>> first2
+ swap ##epilogue? [
+ { [ ##return? ] [ ##callback-return? ] [ ##jump? ] } 1||
+ ] [ ##branch? ] if
+ [ drop ] [ bad-kill-block ] if ;
+
+ERROR: last-insn-not-a-jump bb ;
: check-last-instruction ( bb -- )
- last dup {
+ dup instructions>> last {
[ ##branch? ]
[ ##dispatch? ]
[ ##conditional-branch? ]
[ ##compare-imm-branch? ]
- [ ##return? ]
- [ ##callback-return? ]
- [ ##jump? ]
- [ ##call? ]
+ [ ##fixnum-add? ]
+ [ ##fixnum-sub? ]
+ [ ##fixnum-mul? ]
+ [ ##no-tco? ]
} 1|| [ drop ] [ last-insn-not-a-jump ] if ;
-ERROR: bad-loop-entry ;
+ERROR: bad-kill-insn bb ;
+
+: check-kill-instructions ( bb -- )
+ dup instructions>> [ kill-vreg-insn? ] any?
+ [ bad-kill-insn ] [ drop ] if ;
-: check-loop-entry ( bb -- )
- dup length 2 >= [
- 2 head* [ ##loop-entry? ] any?
- [ bad-loop-entry ] when
- ] [ drop ] if ;
+: check-normal-block ( bb -- )
+ [ check-last-instruction ]
+ [ check-kill-instructions ]
+ bi ;
ERROR: bad-successors ;
[ bad-successors ] unless ;
: check-basic-block ( bb -- )
- [ instructions>> check-last-instruction ]
- [ instructions>> check-loop-entry ]
+ [ dup kill-block? [ check-kill-block ] [ check-normal-block ] if ]
[ check-successors ]
- tri ;
+ bi ;
ERROR: bad-live-in ;
! Check that every used register has a definition
instructions>>
[ [ uses-vregs ] map concat ]
- [ [ [ defs-vregs ] [ temp-vregs ] bi append ] map concat ] bi
+ [ [ [ temp-vregs ] [ defs-vreg ] bi [ suffix ] when* ] map concat ] bi
2dup subset? [ 2drop ] [ undefined-values ] if ;
: check-cfg ( cfg -- )
- compute-liveness
- [ entry>> live-in assoc-empty? [ bad-live-in ] unless ]
[ [ check-basic-block ] each-basic-block ]
- [ flatten-cfg check-mr ]
- tri ;
+ [ build-mr check-mr ]
+ bi ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs math.order sequences ;
+IN: compiler.cfg.comparisons
+
+SYMBOLS: cc< cc<= cc= cc> cc>= cc/= ;
+
+: negate-cc ( cc -- cc' )
+ H{
+ { cc< cc>= }
+ { cc<= cc> }
+ { cc> cc<= }
+ { cc>= cc< }
+ { cc= cc/= }
+ { cc/= cc= }
+ } at ;
+
+: swap-cc ( cc -- cc' )
+ H{
+ { cc< cc> }
+ { cc<= cc>= }
+ { cc> cc< }
+ { cc>= cc<= }
+ { cc= cc= }
+ { cc/= cc/= }
+ } at ;
+
+: evaluate-cc ( result cc -- ? )
+ H{
+ { cc< { +lt+ } }
+ { cc<= { +lt+ +eq+ } }
+ { cc= { +eq+ } }
+ { cc>= { +eq+ +gt+ } }
+ { cc> { +gt+ } }
+ { cc/= { +lt+ +gt+ } }
+ } at memq? ;
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces assocs accessors ;
+USING: kernel namespaces assocs accessors sequences grouping
+combinators compiler.cfg.rpo compiler.cfg.renaming
+compiler.cfg.instructions compiler.cfg.predecessors ;
IN: compiler.cfg.copy-prop
+! The first three definitions are also used in compiler.cfg.alias-analysis.
SYMBOL: copies
+! Initialized per-basic-block; a mapping from inputs to dst for eliminating
+! redundant phi instructions
+SYMBOL: phis
+
: resolve ( vreg -- vreg )
- [ copies get at ] keep or ;
+ copies get ?at drop ;
+
+: (record-copy) ( dst src -- )
+ swap copies get set-at ; inline
+
+: record-copy ( ##copy -- )
+ [ dst>> ] [ src>> resolve ] bi (record-copy) ; inline
+
+<PRIVATE
+
+GENERIC: visit-insn ( insn -- )
+
+M: ##copy visit-insn record-copy ;
+
+: useless-phi ( dst inputs -- ) first (record-copy) ;
+
+: redundant-phi ( dst inputs -- ) phis get at (record-copy) ;
+
+: record-phi ( dst inputs -- ) phis get set-at ;
+
+M: ##phi visit-insn
+ [ dst>> ] [ inputs>> values [ resolve ] map ] bi
+ {
+ { [ dup all-equal? ] [ useless-phi ] }
+ { [ dup phis get key? ] [ redundant-phi ] }
+ [ record-phi ]
+ } cond ;
+
+M: insn visit-insn drop ;
+
+: collect-copies ( cfg -- )
+ H{ } clone copies set
+ [
+ H{ } clone phis set
+ instructions>> [ visit-insn ] each
+ ] each-basic-block ;
+
+GENERIC: update-insn ( insn -- keep? )
+
+M: ##copy update-insn drop f ;
+
+M: ##phi update-insn
+ dup dst>> copies get key? [ drop f ] [ call-next-method ] if ;
+
+M: insn update-insn rename-insn-uses t ;
+
+: rename-copies ( cfg -- )
+ copies get dup assoc-empty? [ 2drop ] [
+ renamings set
+ [
+ instructions>> [ update-insn ] filter-here
+ ] each-basic-block
+ ] if ;
+
+PRIVATE>
+
+: copy-propagation ( cfg -- cfg' )
+ needs-predecessors
-: record-copy ( insn -- )
- [ src>> resolve ] [ dst>> ] bi copies get set-at ; inline
+ [ collect-copies ]
+ [ rename-copies ]
+ [ ]
+ tri ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs deques dlists kernel locals sequences lexer
+namespaces functors compiler.cfg.rpo compiler.cfg.utilities
+compiler.cfg.predecessors compiler.cfg ;
+IN: compiler.cfg.dataflow-analysis
+
+GENERIC: join-sets ( sets bb dfa -- set )
+GENERIC: transfer-set ( in-set bb dfa -- out-set )
+GENERIC: block-order ( cfg dfa -- bbs )
+GENERIC: successors ( bb dfa -- seq )
+GENERIC: predecessors ( bb dfa -- seq )
+
+<PRIVATE
+
+MIXIN: dataflow-analysis
+
+: <dfa-worklist> ( cfg dfa -- queue )
+ block-order <hashed-dlist> [ push-all-front ] keep ;
+
+GENERIC# compute-in-set 2 ( bb out-sets dfa -- set )
+
+M: kill-block compute-in-set 3drop f ;
+
+M:: basic-block compute-in-set ( bb out-sets dfa -- set )
+ ! Only consider initialized sets.
+ bb dfa predecessors
+ [ out-sets key? ] filter
+ [ out-sets at ] map
+ bb dfa join-sets ;
+
+:: update-in-set ( bb in-sets out-sets dfa -- ? )
+ bb out-sets dfa compute-in-set
+ bb in-sets maybe-set-at ; inline
+
+GENERIC# compute-out-set 2 ( bb out-sets dfa -- set )
+
+M: kill-block compute-out-set 3drop f ;
+
+M:: basic-block compute-out-set ( bb in-sets dfa -- set )
+ bb in-sets at bb dfa transfer-set ;
+
+:: update-out-set ( bb in-sets out-sets dfa -- ? )
+ bb in-sets dfa compute-out-set
+ bb out-sets maybe-set-at ; inline
+
+:: dfa-step ( bb in-sets out-sets dfa work-list -- )
+ bb in-sets out-sets dfa update-in-set [
+ bb in-sets out-sets dfa update-out-set [
+ bb dfa successors work-list push-all-front
+ ] when
+ ] when ; inline
+
+:: run-dataflow-analysis ( cfg dfa -- in-sets out-sets )
+ cfg needs-predecessors drop
+ H{ } clone :> in-sets
+ H{ } clone :> out-sets
+ cfg dfa <dfa-worklist> :> work-list
+ work-list [ in-sets out-sets dfa work-list dfa-step ] slurp-deque
+ in-sets
+ out-sets ; inline
+
+M: dataflow-analysis join-sets 2drop assoc-refine ;
+
+FUNCTOR: define-analysis ( name -- )
+
+name-analysis DEFINES-CLASS ${name}-analysis
+name-ins DEFINES ${name}-ins
+name-outs DEFINES ${name}-outs
+name-in DEFINES ${name}-in
+name-out DEFINES ${name}-out
+
+WHERE
+
+SINGLETON: name-analysis
+
+SYMBOL: name-ins
+
+: name-in ( bb -- set ) name-ins get at ;
+
+SYMBOL: name-outs
+
+: name-out ( bb -- set ) name-outs get at ;
+
+;FUNCTOR
+
+! ! ! Forward dataflow analysis
+
+MIXIN: forward-analysis
+INSTANCE: forward-analysis dataflow-analysis
+
+M: forward-analysis block-order drop reverse-post-order ;
+M: forward-analysis successors drop successors>> ;
+M: forward-analysis predecessors drop predecessors>> ;
+
+FUNCTOR: define-forward-analysis ( name -- )
+
+name-analysis IS ${name}-analysis
+name-ins IS ${name}-ins
+name-outs IS ${name}-outs
+compute-name-sets DEFINES compute-${name}-sets
+
+WHERE
+
+INSTANCE: name-analysis forward-analysis
+
+: compute-name-sets ( cfg -- )
+ name-analysis run-dataflow-analysis
+ [ name-ins set ] [ name-outs set ] bi* ;
+
+;FUNCTOR
+
+! ! ! Backward dataflow analysis
+
+MIXIN: backward-analysis
+INSTANCE: backward-analysis dataflow-analysis
+
+M: backward-analysis block-order drop post-order ;
+M: backward-analysis successors drop predecessors>> ;
+M: backward-analysis predecessors drop successors>> ;
+
+FUNCTOR: define-backward-analysis ( name -- )
+
+name-analysis IS ${name}-analysis
+name-ins IS ${name}-ins
+name-outs IS ${name}-outs
+compute-name-sets DEFINES compute-${name}-sets
+
+WHERE
+
+INSTANCE: name-analysis backward-analysis
+
+: compute-name-sets ( cfg -- )
+ \ name-analysis run-dataflow-analysis
+ [ name-outs set ] [ name-ins set ] bi* ;
+
+;FUNCTOR
+
+PRIVATE>
+
+SYNTAX: FORWARD-ANALYSIS:
+ scan [ define-analysis ] [ define-forward-analysis ] bi ;
+
+SYNTAX: BACKWARD-ANALYSIS:
+ scan [ define-analysis ] [ define-backward-analysis ] bi ;
-Slava Pestov
\ No newline at end of file
+Slava Pestov
+Daniel Ehrenberg
--- /dev/null
+! Copyright (C) 2009 Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test compiler.cfg kernel accessors compiler.cfg.dce
+compiler.cfg.instructions compiler.cfg.registers cpu.architecture ;
+IN: compiler.cfg.dce.tests
+
+: test-dce ( insns -- insns' )
+ <basic-block> swap >>instructions
+ cfg new swap >>entry
+ eliminate-dead-code
+ entry>> instructions>> ;
+
+[ V{
+ T{ ##load-immediate { dst 1 } { val 8 } }
+ T{ ##load-immediate { dst 2 } { val 16 } }
+ T{ ##add { dst 3 } { src1 1 } { src2 2 } }
+ T{ ##replace { src 3 } { loc D 0 } }
+} ] [ V{
+ T{ ##load-immediate { dst 1 } { val 8 } }
+ T{ ##load-immediate { dst 2 } { val 16 } }
+ T{ ##add { dst 3 } { src1 1 } { src2 2 } }
+ T{ ##replace { src 3 } { loc D 0 } }
+} test-dce ] unit-test
+
+[ V{ } ] [ V{
+ T{ ##load-immediate { dst 1 } { val 8 } }
+ T{ ##load-immediate { dst 2 } { val 16 } }
+ T{ ##add { dst 3 } { src1 1 } { src2 2 } }
+} test-dce ] unit-test
+
+[ V{ } ] [ V{
+ T{ ##load-immediate { dst 3 } { val 8 } }
+ T{ ##allot { dst 1 } { temp 2 } }
+} test-dce ] unit-test
+
+[ V{ } ] [ V{
+ T{ ##load-immediate { dst 3 } { val 8 } }
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##set-slot-imm { obj 1 } { src 3 } }
+} test-dce ] unit-test
+
+[ V{
+ T{ ##load-immediate { dst 3 } { val 8 } }
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##set-slot-imm { obj 1 } { src 3 } }
+ T{ ##replace { src 1 } { loc D 0 } }
+} ] [ V{
+ T{ ##load-immediate { dst 3 } { val 8 } }
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##set-slot-imm { obj 1 } { src 3 } }
+ T{ ##replace { src 1 } { loc D 0 } }
+} test-dce ] unit-test
+
+[ V{
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##replace { src 1 } { loc D 0 } }
+} ] [ V{
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##replace { src 1 } { loc D 0 } }
+} test-dce ] unit-test
+
+[ V{
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##replace { src 1 } { loc D 0 } }
+ T{ ##load-immediate { dst 3 } { val 8 } }
+ T{ ##set-slot-imm { obj 1 } { src 3 } }
+} ] [ V{
+ T{ ##allot { dst 1 } { temp 2 } }
+ T{ ##replace { src 1 } { loc D 0 } }
+ T{ ##load-immediate { dst 3 } { val 8 } }
+ T{ ##set-slot-imm { obj 1 } { src 3 } }
+} test-dce ] unit-test
-! Copyright (C) 2008, 2009 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs sets kernel namespaces sequences
compiler.cfg.instructions compiler.cfg.def-use
-compiler.cfg.rpo ;
+compiler.cfg.rpo compiler.cfg.predecessors ;
IN: compiler.cfg.dce
! Maps vregs to sequences of vregs
! vregs which participate in side effects and thus are always live
SYMBOL: live-vregs
+: live-vreg? ( vreg -- ? )
+ live-vregs get key? ;
+
+! vregs which are the result of an allocation
+SYMBOL: allocations
+
+: allocation? ( vreg -- ? )
+ allocations get key? ;
+
: init-dead-code ( -- )
H{ } clone liveness-graph set
- H{ } clone live-vregs set ;
+ H{ } clone live-vregs set
+ H{ } clone allocations set ;
+
+GENERIC: build-liveness-graph ( insn -- )
+
+: add-edges ( insn register -- )
+ [ uses-vregs ] dip liveness-graph get [ union ] change-at ;
+
+: setter-liveness-graph ( insn vreg -- )
+ dup allocation? [ add-edges ] [ 2drop ] if ;
+
+M: ##set-slot build-liveness-graph
+ dup obj>> setter-liveness-graph ;
+
+M: ##set-slot-imm build-liveness-graph
+ dup obj>> setter-liveness-graph ;
+
+M: ##write-barrier build-liveness-graph
+ dup src>> setter-liveness-graph ;
+
+M: ##flushable build-liveness-graph
+ dup dst>> add-edges ;
+
+M: ##allot build-liveness-graph
+ [ dst>> allocations get conjoin ]
+ [ call-next-method ] bi ;
-GENERIC: update-liveness-graph ( insn -- )
+M: insn build-liveness-graph drop ;
-M: ##flushable update-liveness-graph
- [ uses-vregs ] [ dst>> ] bi liveness-graph get set-at ;
+GENERIC: compute-live-vregs ( insn -- )
-: record-live ( vregs -- )
+: (record-live) ( vregs -- )
[
dup live-vregs get key? [ drop ] [
[ live-vregs get conjoin ]
- [ liveness-graph get at record-live ]
+ [ liveness-graph get at (record-live) ]
bi
] if
] each ;
-M: insn update-liveness-graph uses-vregs record-live ;
+: record-live ( insn -- )
+ uses-vregs (record-live) ;
+
+: setter-live-vregs ( insn vreg -- )
+ allocation? [ drop ] [ record-live ] if ;
+
+M: ##set-slot compute-live-vregs
+ dup obj>> setter-live-vregs ;
+
+M: ##set-slot-imm compute-live-vregs
+ dup obj>> setter-live-vregs ;
+
+M: ##write-barrier compute-live-vregs
+ dup src>> setter-live-vregs ;
+
+M: ##flushable compute-live-vregs drop ;
+
+M: insn compute-live-vregs
+ record-live ;
GENERIC: live-insn? ( insn -- ? )
-M: ##flushable live-insn? dst>> live-vregs get key? ;
+M: ##flushable live-insn? dst>> live-vreg? ;
+
+M: ##set-slot live-insn? obj>> live-vreg? ;
+
+M: ##set-slot-imm live-insn? obj>> live-vreg? ;
+
+M: ##write-barrier live-insn? src>> live-vreg? ;
M: insn live-insn? drop t ;
: eliminate-dead-code ( cfg -- cfg' )
+ needs-predecessors
+
init-dead-code
- [ [ instructions>> [ update-liveness-graph ] each ] each-basic-block ]
- [ [ [ [ live-insn? ] filter ] change-instructions drop ] each-basic-block ]
- [ ]
- tri ;
\ No newline at end of file
+ dup
+ [ [ instructions>> [ build-liveness-graph ] each ] each-basic-block ]
+ [ [ instructions>> [ compute-live-vregs ] each ] each-basic-block ]
+ [ [ instructions>> [ live-insn? ] filter-here ] each-basic-block ]
+ tri ;
--- /dev/null
+Dead code elimination
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel words sequences quotations namespaces io
-classes.tuple accessors prettyprint prettyprint.config
-prettyprint.backend prettyprint.custom prettyprint.sections
-parser compiler.tree.builder compiler.tree.optimizer
-compiler.cfg.builder compiler.cfg.linearization
-compiler.cfg.registers compiler.cfg.stack-frame
-compiler.cfg.linear-scan compiler.cfg.two-operand
-compiler.cfg.liveness compiler.cfg.optimizer
-compiler.cfg.mr ;
+USING: kernel words sequences quotations namespaces io vectors
+arrays hashtables classes.tuple accessors prettyprint
+prettyprint.config assocs prettyprint.backend prettyprint.custom
+prettyprint.sections parser compiler.tree.builder
+compiler.tree.optimizer cpu.architecture compiler.cfg.builder
+compiler.cfg.linearization compiler.cfg.registers
+compiler.cfg.stack-frame compiler.cfg.linear-scan
+compiler.cfg.two-operand compiler.cfg.optimizer
+compiler.cfg.instructions compiler.cfg.utilities
+compiler.cfg.def-use compiler.cfg.rpo compiler.cfg.mr
+compiler.cfg.representations.preferred compiler.cfg ;
IN: compiler.cfg.debugger
GENERIC: test-cfg ( quot -- cfgs )
M: callable test-cfg
+ 0 vreg-counter set-global
build-tree optimize-tree gensym build-cfg ;
M: word test-cfg
+ 0 vreg-counter set-global
[ build-tree optimize-tree ] keep build-cfg ;
: test-mr ( quot -- mrs )
test-cfg [
- optimize-cfg
- build-mr
+ [
+ optimize-cfg
+ build-mr
+ ] with-cfg
] map ;
: insn. ( insn -- )
- tuple>array [ pprint bl ] each nl ;
+ tuple>array but-last [ pprint bl ] each nl ;
: mr. ( mrs -- )
[
] each ;
! Prettyprinting
-M: vreg pprint*
- <block
- \ V pprint-word [ reg-class>> pprint* ] [ n>> pprint* ] bi
- block> ;
-
: pprint-loc ( loc word -- ) <block pprint-word n>> pprint* block> ;
M: ds-loc pprint* \ D pprint-loc ;
M: rs-loc pprint* \ R pprint-loc ;
+
+: resolve-phis ( bb -- )
+ [
+ [ [ [ get ] dip ] assoc-map ] change-inputs drop
+ ] each-phi ;
+
+: test-bb ( insns n -- )
+ [ <basic-block> swap >>number swap >>instructions dup ] keep set
+ resolve-phis ;
+
+: edge ( from to -- )
+ [ get ] bi@ 1vector >>successors drop ;
+
+: edges ( from tos -- )
+ [ get ] [ [ get ] V{ } map-as ] bi* >>successors drop ;
+
+: test-diamond ( -- )
+ 0 1 edge
+ 1 { 2 3 } edges
+ 2 4 edge
+ 3 4 edge ;
+
+: fake-representations ( cfg -- )
+ post-order [
+ instructions>> [
+ [ [ temp-vregs ] [ temp-vreg-reps ] bi zip ]
+ [ [ defs-vreg ] [ defs-vreg-rep ] bi 2dup and [ 2array ] [ 2drop f ] if ]
+ bi [ suffix ] when*
+ ] map concat
+ ] map concat >hashtable representations set ;
\ No newline at end of file
--- /dev/null
+Slava Pestov
+Daniel Ehrenberg
--- /dev/null
+! Copyright (C) 2009 Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel tools.test accessors vectors sequences namespaces
+arrays
+cpu.architecture
+compiler.cfg.def-use
+compiler.cfg
+compiler.cfg.debugger
+compiler.cfg.instructions
+compiler.cfg.registers ;
+IN: compiler.cfg.def-use.tests
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 0 }
+ T{ ##peek f 2 D 0 }
+} 1 test-bb
+V{
+ T{ ##replace f 2 D 0 }
+} 2 test-bb
+1 2 edge
+V{
+ T{ ##replace f 0 D 0 }
+} 3 test-bb
+2 3 edge
+V{ } 4 test-bb
+V{ } 5 test-bb
+3 { 4 5 } edges
+V{
+ T{ ##phi f 2 H{ { 2 0 } { 3 1 } } }
+} 6 test-bb
+4 6 edge
+5 6 edge
+
+cfg new 1 get >>entry 0 set
+[ ] [ 0 get [ compute-defs ] [ compute-uses ] bi ] unit-test
-! Copyright (C) 2008, 2009 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays kernel compiler.cfg.instructions ;
+USING: accessors arrays kernel assocs sequences namespaces fry
+sets compiler.cfg.rpo compiler.cfg.instructions locals ;
IN: compiler.cfg.def-use
-GENERIC: defs-vregs ( insn -- seq )
+GENERIC: defs-vreg ( insn -- vreg/f )
GENERIC: temp-vregs ( insn -- seq )
GENERIC: uses-vregs ( insn -- seq )
-M: ##flushable defs-vregs dst>> 1array ;
-M: insn defs-vregs drop f ;
+M: ##flushable defs-vreg dst>> ;
+M: ##fixnum-overflow defs-vreg dst>> ;
+M: _fixnum-overflow defs-vreg dst>> ;
+M: insn defs-vreg drop f ;
M: ##write-barrier temp-vregs [ card#>> ] [ table>> ] bi 2array ;
M: ##unary/temp temp-vregs temp>> 1array ;
M: ##set-slot temp-vregs temp>> 1array ;
M: ##string-nth temp-vregs temp>> 1array ;
M: ##set-string-nth-fast temp-vregs temp>> 1array ;
+M: ##box-displaced-alien temp-vregs temp>> 1array ;
M: ##compare temp-vregs temp>> 1array ;
M: ##compare-imm temp-vregs temp>> 1array ;
M: ##compare-float temp-vregs temp>> 1array ;
-M: ##fixnum-mul temp-vregs [ temp1>> ] [ temp2>> ] bi 2array ;
-M: ##fixnum-mul-tail temp-vregs [ temp1>> ] [ temp2>> ] bi 2array ;
M: ##gc temp-vregs [ temp1>> ] [ temp2>> ] bi 2array ;
M: _dispatch temp-vregs temp>> 1array ;
M: insn temp-vregs drop f ;
M: ##alien-getter uses-vregs src>> 1array ;
M: ##alien-setter uses-vregs [ src>> ] [ value>> ] bi 2array ;
M: ##fixnum-overflow uses-vregs [ src1>> ] [ src2>> ] bi 2array ;
-M: ##phi uses-vregs inputs>> ;
+M: ##phi uses-vregs inputs>> values ;
M: _conditional-branch uses-vregs [ src1>> ] [ src2>> ] bi 2array ;
M: _compare-imm-branch uses-vregs src1>> 1array ;
M: _dispatch uses-vregs src>> 1array ;
M: insn uses-vregs drop f ;
-! Instructions that use vregs
-UNION: vreg-insn
-##flushable
-##write-barrier
-##dispatch
-##effect
-##fixnum-overflow
-##conditional-branch
-##compare-imm-branch
-##phi
-##gc
-_conditional-branch
-_compare-imm-branch
-_dispatch ;
+! Computing def-use chains.
+
+SYMBOLS: defs insns uses ;
+
+: def-of ( vreg -- node ) defs get at ;
+: uses-of ( vreg -- nodes ) uses get at ;
+: insn-of ( vreg -- insn ) insns get at ;
+
+: set-def-of ( obj insn assoc -- )
+ swap defs-vreg dup [ swap set-at ] [ 3drop ] if ;
+
+: compute-defs ( cfg -- )
+ H{ } clone [
+ '[
+ dup instructions>> [
+ _ set-def-of
+ ] with each
+ ] each-basic-block
+ ] keep
+ defs set ;
+
+: compute-insns ( cfg -- )
+ H{ } clone [
+ '[
+ instructions>> [
+ dup _ set-def-of
+ ] each
+ ] each-basic-block
+ ] keep insns set ;
+
+:: compute-uses ( cfg -- )
+ ! Here, a phi node uses its argument in the block that it comes from.
+ H{ } clone :> use
+ cfg [| block |
+ block instructions>> [
+ dup ##phi?
+ [ inputs>> [ use conjoin-at ] assoc-each ]
+ [ uses-vregs [ block swap use conjoin-at ] each ]
+ if
+ ] each
+ ] each-basic-block
+ use [ keys ] assoc-map uses set ;
--- /dev/null
+USING: tools.test sequences vectors namespaces kernel accessors assocs sets
+math.ranges arrays compiler.cfg compiler.cfg.dominance compiler.cfg.debugger
+compiler.cfg.predecessors ;
+IN: compiler.cfg.dominance.tests
+
+: test-dominance ( -- )
+ cfg new 0 get >>entry
+ needs-dominance drop ;
+
+! Example with no back edges
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{ } 4 test-bb
+V{ } 5 test-bb
+
+0 { 1 2 } edges
+1 3 edge
+2 4 edge
+3 4 edge
+4 5 edge
+
+[ ] [ test-dominance ] unit-test
+
+[ t ] [ 0 get dom-parent 0 get eq? ] unit-test
+[ t ] [ 1 get dom-parent 0 get eq? ] unit-test
+[ t ] [ 2 get dom-parent 0 get eq? ] unit-test
+[ t ] [ 4 get dom-parent 0 get eq? ] unit-test
+[ t ] [ 3 get dom-parent 1 get eq? ] unit-test
+[ t ] [ 5 get dom-parent 4 get eq? ] unit-test
+
+[ t ] [ 0 get dom-children 1 get 2 get 4 get 3array set= ] unit-test
+
+[ t ] [ 0 get 3 get dominates? ] unit-test
+[ f ] [ 3 get 4 get dominates? ] unit-test
+[ f ] [ 1 get 4 get dominates? ] unit-test
+[ t ] [ 4 get 5 get dominates? ] unit-test
+[ f ] [ 1 get 5 get dominates? ] unit-test
+
+! Example from the paper
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{ } 4 test-bb
+
+0 { 1 2 } edges
+1 3 edge
+2 4 edge
+3 4 edge
+4 3 edge
+
+[ ] [ test-dominance ] unit-test
+
+[ t ] [ 0 4 [a,b] [ get dom-parent 0 get eq? ] all? ] unit-test
+
+! The other example from the paper
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{ } 4 test-bb
+V{ } 5 test-bb
+
+0 { 1 2 } edges
+1 5 edge
+2 { 4 3 } edges
+5 4 edge
+4 { 5 3 } edges
+3 4 edge
+
+[ ] [ test-dominance ] unit-test
+
+[ t ] [ 0 5 [a,b] [ get dom-parent 0 get eq? ] all? ] unit-test
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs combinators compiler.cfg.rpo
-compiler.cfg.stack-analysis fry kernel math.order namespaces
-sequences ;
+USING: accessors assocs combinators sets math fry kernel math.order
+dlists deques vectors namespaces sequences sorting locals
+compiler.cfg.rpo compiler.cfg.predecessors ;
IN: compiler.cfg.dominance
! Reference:
! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
! http://www.cs.rice.edu/~keith/EMBED/dom.pdf
-SYMBOL: idoms
+! Also, a nice overview is given in these lecture notes:
+! http://llvm.cs.uiuc.edu/~vadve/CS526/public_html/Notes/4ssa.4up.pdf
-: idom ( bb -- bb' ) idoms get at ;
+<PRIVATE
+
+! Maps bb -> idom(bb)
+SYMBOL: dom-parents
+
+PRIVATE>
+
+: dom-parent ( bb -- bb' ) dom-parents get at ;
<PRIVATE
-: set-idom ( idom bb -- changed? ) idoms get maybe-set-at ;
+: set-idom ( idom bb -- changed? )
+ dom-parents get maybe-set-at ;
: intersect ( finger1 finger2 -- bb )
2dup [ number>> ] compare {
- { +lt+ [ [ idom ] dip intersect ] }
- { +gt+ [ idom intersect ] }
+ { +gt+ [ [ dom-parent ] dip intersect ] }
+ { +lt+ [ dom-parent intersect ] }
[ 2drop ]
} case ;
: compute-idom ( bb -- idom )
- predecessors>> [ idom ] map sift
+ predecessors>> [ dom-parent ] filter
[ ] [ intersect ] map-reduce ;
: iterate ( rpo -- changed? )
[ [ compute-idom ] keep set-idom ] map [ ] any? ;
+: compute-dom-parents ( cfg -- )
+ H{ } clone dom-parents set
+ reverse-post-order
+ unclip dup set-idom drop '[ _ iterate ] loop ;
+
+! Maps bb -> {bb' | idom(bb') = bb}
+SYMBOL: dom-childrens
+
PRIVATE>
-: compute-dominance ( cfg -- cfg )
- H{ } clone idoms set
- dup reverse-post-order
- unclip dup set-idom drop '[ _ iterate ] loop ;
\ No newline at end of file
+: dom-children ( bb -- seq ) dom-childrens get at ;
+
+<PRIVATE
+
+: compute-dom-children ( -- )
+ dom-parents get H{ } clone
+ [ '[ 2dup eq? [ 2drop ] [ _ push-at ] if ] assoc-each ] keep
+ dom-childrens set ;
+
+SYMBOLS: preorder maxpreorder ;
+
+PRIVATE>
+
+: pre-of ( bb -- n ) [ preorder get at ] [ -1/0. ] if* ;
+
+: maxpre-of ( bb -- n ) [ maxpreorder get at ] [ 1/0. ] if* ;
+
+<PRIVATE
+
+: (compute-dfs) ( n bb -- n )
+ [ 1 + ] dip
+ [ dupd preorder get set-at ]
+ [ dom-children [ (compute-dfs) ] each ]
+ [ dupd maxpreorder get set-at ]
+ tri ;
+
+: compute-dfs ( cfg -- )
+ H{ } clone preorder set
+ H{ } clone maxpreorder set
+ [ 0 ] dip entry>> (compute-dfs) drop ;
+
+: compute-dominance ( cfg -- cfg' )
+ [ compute-dom-parents compute-dom-children ] [ compute-dfs ] [ ] tri ;
+
+PRIVATE>
+
+: needs-dominance ( cfg -- cfg' )
+ needs-predecessors
+ dup dominance-valid?>> [ compute-dominance t >>dominance-valid? ] unless ;
+
+: dominates? ( bb1 bb2 -- ? )
+ swap [ pre-of ] [ [ pre-of ] [ maxpre-of ] bi ] bi* between? ;
+
+:: breadth-first-order ( cfg -- bfo )
+ <dlist> :> work-list
+ cfg post-order length <vector> :> accum
+ cfg entry>> work-list push-front
+ work-list [
+ [ accum push ]
+ [ dom-children work-list push-all-front ] bi
+ ] slurp-deque
+ accum ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008, 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors sequences namespaces combinators
+combinators.short-circuit classes vectors compiler.cfg
+compiler.cfg.instructions compiler.cfg.rpo ;
+IN: compiler.cfg.empty-blocks
+
+<PRIVATE
+
+: update-predecessor ( bb -- )
+ ! We have to replace occurrences of bb with bb's successor
+ ! in bb's predecessor's list of successors.
+ dup predecessors>> first [
+ [
+ 2dup eq? [ drop successors>> first ] [ nip ] if
+ ] with map
+ ] change-successors drop ;
+
+: update-successor ( bb -- )
+ ! We have to replace occurrences of bb with bb's predecessor
+ ! in bb's sucessor's list of predecessors.
+ dup successors>> first [
+ [
+ 2dup eq? [ drop predecessors>> first ] [ nip ] if
+ ] with map
+ ] change-predecessors drop ;
+
+SYMBOL: changed?
+
+: delete-basic-block ( bb -- )
+ [ update-predecessor ] [ update-successor ] bi
+ changed? on ;
+
+: delete-basic-block? ( bb -- ? )
+ {
+ [ instructions>> length 1 = ]
+ [ predecessors>> length 1 = ]
+ [ successors>> length 1 = ]
+ [ instructions>> first ##branch? ]
+ } 1&& ;
+
+PRIVATE>
+
+: delete-empty-blocks ( cfg -- cfg' )
+ changed? off
+ dup [ dup delete-basic-block? [ delete-basic-block ] [ drop ] if ] each-basic-block
+ changed? get [ cfg-changed ] when ;
\ No newline at end of file
--- /dev/null
+USING: compiler.cfg.gc-checks compiler.cfg.debugger
+compiler.cfg.registers compiler.cfg.instructions compiler.cfg
+compiler.cfg.predecessors cpu.architecture tools.test kernel vectors
+namespaces accessors sequences ;
+IN: compiler.cfg.gc-checks.tests
+
+: test-gc-checks ( -- )
+ H{ } clone representations set
+ cfg new 0 get >>entry
+ insert-gc-checks
+ drop ;
+
+V{
+ T{ ##inc-d f 3 }
+ T{ ##replace f 0 D 1 }
+} 0 test-bb
+
+V{
+ T{ ##box-float f 0 1 }
+} 1 test-bb
+
+0 1 edge
+
+[ ] [ test-gc-checks ] unit-test
+
+[ V{ D 0 D 2 } ] [ 1 get instructions>> first uninitialized-locs>> ] unit-test
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel sequences assocs
-cpu.architecture compiler.cfg.rpo
-compiler.cfg.liveness compiler.cfg.instructions
-compiler.cfg.hats ;
+USING: accessors kernel sequences assocs fry
+cpu.architecture
+compiler.cfg.rpo
+compiler.cfg.registers
+compiler.cfg.instructions
+compiler.cfg.stacks.uninitialized ;
IN: compiler.cfg.gc-checks
-: gc? ( bb -- ? )
+! Garbage collection check insertion. This pass runs after representation
+! selection, so it must keep track of representations.
+
+: insert-gc-check? ( bb -- ? )
instructions>> [ ##allocation? ] any? ;
-: object-pointer-regs ( basic-block -- vregs )
- live-in keys [ reg-class>> int-regs eq? ] filter ;
+: blocks-with-gc ( cfg -- bbs )
+ post-order [ insert-gc-check? ] filter ;
-: insert-gc-check ( basic-block -- )
- dup gc? [
- [ i i f f \ ##gc new-insn prefix ] change-instructions drop
- ] [ drop ] if ;
+: insert-gc-check ( bb -- )
+ dup '[
+ int-rep next-vreg-rep
+ int-rep next-vreg-rep
+ f f _ uninitialized-locs \ ##gc new-insn
+ prefix
+ ] change-instructions drop ;
: insert-gc-checks ( cfg -- cfg' )
- dup [ insert-gc-check ] each-basic-block ;
\ No newline at end of file
+ dup blocks-with-gc [
+ over compute-uninitialized-sets
+ [ insert-gc-check ] each
+ ] unless-empty ;
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays byte-arrays kernel layouts math namespaces
+USING: accessors arrays byte-arrays kernel layouts math namespaces
sequences classes.tuple cpu.architecture compiler.cfg.registers
compiler.cfg.instructions ;
IN: compiler.cfg.hats
-: i ( -- vreg ) int-regs next-vreg ; inline
-: ^^i ( -- vreg vreg ) i dup ; inline
-: ^^i1 ( obj -- vreg vreg obj ) [ ^^i ] dip ; inline
-: ^^i2 ( obj obj -- vreg vreg obj obj ) [ ^^i ] 2dip ; inline
-: ^^i3 ( obj obj obj -- vreg vreg obj obj obj ) [ ^^i ] 3dip ; inline
+: ^^r ( -- vreg vreg ) next-vreg dup ; inline
+: ^^r1 ( obj -- vreg vreg obj ) [ ^^r ] dip ; inline
+: ^^r2 ( obj obj -- vreg vreg obj obj ) [ ^^r ] 2dip ; inline
+: ^^r3 ( obj obj obj -- vreg vreg obj obj obj ) [ ^^r ] 3dip ; inline
-: d ( -- vreg ) double-float-regs next-vreg ; inline
-: ^^d ( -- vreg vreg ) d dup ; inline
-: ^^d1 ( obj -- vreg vreg obj ) [ ^^d ] dip ; inline
-: ^^d2 ( obj obj -- vreg vreg obj obj ) [ ^^d ] 2dip ; inline
-: ^^d3 ( obj obj obj -- vreg vreg obj obj obj ) [ ^^d ] 3dip ; inline
-
-: ^^load-literal ( obj -- dst ) ^^i1 ##load-literal ; inline
-: ^^peek ( loc -- dst ) ^^i1 ##peek ; inline
-: ^^slot ( obj slot tag -- dst ) ^^i3 i ##slot ; inline
-: ^^slot-imm ( obj slot tag -- dst ) ^^i3 ##slot-imm ; inline
-: ^^set-slot ( src obj slot tag -- ) i ##set-slot ; inline
-: ^^string-nth ( obj index -- dst ) ^^i2 i ##string-nth ; inline
-: ^^add ( src1 src2 -- dst ) ^^i2 ##add ; inline
-: ^^add-imm ( src1 src2 -- dst ) ^^i2 ##add-imm ; inline
-: ^^sub ( src1 src2 -- dst ) ^^i2 ##sub ; inline
-: ^^sub-imm ( src1 src2 -- dst ) ^^i2 ##sub-imm ; inline
-: ^^mul ( src1 src2 -- dst ) ^^i2 ##mul ; inline
-: ^^mul-imm ( src1 src2 -- dst ) ^^i2 ##mul-imm ; inline
-: ^^and ( input mask -- output ) ^^i2 ##and ; inline
-: ^^and-imm ( input mask -- output ) ^^i2 ##and-imm ; inline
-: ^^or ( src1 src2 -- dst ) ^^i2 ##or ; inline
-: ^^or-imm ( src1 src2 -- dst ) ^^i2 ##or-imm ; inline
-: ^^xor ( src1 src2 -- dst ) ^^i2 ##xor ; inline
-: ^^xor-imm ( src1 src2 -- dst ) ^^i2 ##xor-imm ; inline
-: ^^shl-imm ( src1 src2 -- dst ) ^^i2 ##shl-imm ; inline
-: ^^shr-imm ( src1 src2 -- dst ) ^^i2 ##shr-imm ; inline
-: ^^sar-imm ( src1 src2 -- dst ) ^^i2 ##sar-imm ; inline
-: ^^not ( src -- dst ) ^^i1 ##not ; inline
-: ^^log2 ( src -- dst ) ^^i1 ##log2 ; inline
-: ^^bignum>integer ( src -- dst ) ^^i1 i ##bignum>integer ; inline
-: ^^integer>bignum ( src -- dst ) ^^i1 i ##integer>bignum ; inline
-: ^^add-float ( src1 src2 -- dst ) ^^d2 ##add-float ; inline
-: ^^sub-float ( src1 src2 -- dst ) ^^d2 ##sub-float ; inline
-: ^^mul-float ( src1 src2 -- dst ) ^^d2 ##mul-float ; inline
-: ^^div-float ( src1 src2 -- dst ) ^^d2 ##div-float ; inline
-: ^^float>integer ( src -- dst ) ^^i1 ##float>integer ; inline
-: ^^integer>float ( src -- dst ) ^^d1 ##integer>float ; inline
-: ^^allot ( size class -- dst ) ^^i2 i ##allot ; inline
+: ^^load-literal ( obj -- dst ) ^^r1 ##load-literal ; inline
+: ^^copy ( src -- dst ) ^^r1 any-rep ##copy ; inline
+: ^^slot ( obj slot tag -- dst ) ^^r3 next-vreg ##slot ; inline
+: ^^slot-imm ( obj slot tag -- dst ) ^^r3 ##slot-imm ; inline
+: ^^set-slot ( src obj slot tag -- ) next-vreg ##set-slot ; inline
+: ^^string-nth ( obj index -- dst ) ^^r2 next-vreg ##string-nth ; inline
+: ^^add ( src1 src2 -- dst ) ^^r2 ##add ; inline
+: ^^add-imm ( src1 src2 -- dst ) ^^r2 ##add-imm ; inline
+: ^^sub ( src1 src2 -- dst ) ^^r2 ##sub ; inline
+: ^^sub-imm ( src1 src2 -- dst ) ^^r2 ##sub-imm ; inline
+: ^^neg ( src -- dst ) [ 0 ^^load-literal ] dip ^^sub ; inline
+: ^^mul ( src1 src2 -- dst ) ^^r2 ##mul ; inline
+: ^^mul-imm ( src1 src2 -- dst ) ^^r2 ##mul-imm ; inline
+: ^^and ( input mask -- output ) ^^r2 ##and ; inline
+: ^^and-imm ( input mask -- output ) ^^r2 ##and-imm ; inline
+: ^^or ( src1 src2 -- dst ) ^^r2 ##or ; inline
+: ^^or-imm ( src1 src2 -- dst ) ^^r2 ##or-imm ; inline
+: ^^xor ( src1 src2 -- dst ) ^^r2 ##xor ; inline
+: ^^xor-imm ( src1 src2 -- dst ) ^^r2 ##xor-imm ; inline
+: ^^shl ( src1 src2 -- dst ) ^^r2 ##shl ; inline
+: ^^shl-imm ( src1 src2 -- dst ) ^^r2 ##shl-imm ; inline
+: ^^shr ( src1 src2 -- dst ) ^^r2 ##shr ; inline
+: ^^shr-imm ( src1 src2 -- dst ) ^^r2 ##shr-imm ; inline
+: ^^sar ( src1 src2 -- dst ) ^^r2 ##sar ; inline
+: ^^sar-imm ( src1 src2 -- dst ) ^^r2 ##sar-imm ; inline
+: ^^not ( src -- dst ) ^^r1 ##not ; inline
+: ^^log2 ( src -- dst ) ^^r1 ##log2 ; inline
+: ^^bignum>integer ( src -- dst ) ^^r1 next-vreg ##bignum>integer ; inline
+: ^^integer>bignum ( src -- dst ) ^^r1 next-vreg ##integer>bignum ; inline
+: ^^add-float ( src1 src2 -- dst ) ^^r2 ##add-float ; inline
+: ^^sub-float ( src1 src2 -- dst ) ^^r2 ##sub-float ; inline
+: ^^mul-float ( src1 src2 -- dst ) ^^r2 ##mul-float ; inline
+: ^^div-float ( src1 src2 -- dst ) ^^r2 ##div-float ; inline
+: ^^sqrt ( src -- dst ) ^^r1 ##sqrt ; inline
+: ^^float>integer ( src -- dst ) ^^r1 ##float>integer ; inline
+: ^^integer>float ( src -- dst ) ^^r1 ##integer>float ; inline
+: ^^allot ( size class -- dst ) ^^r2 next-vreg ##allot ; inline
: ^^allot-tuple ( n -- dst ) 2 + cells tuple ^^allot ; inline
: ^^allot-array ( n -- dst ) 2 + cells array ^^allot ; inline
: ^^allot-byte-array ( n -- dst ) 2 cells + byte-array ^^allot ; inline
-: ^^box-float ( src -- dst ) ^^i1 i ##box-float ; inline
-: ^^unbox-float ( src -- dst ) ^^d1 ##unbox-float ; inline
-: ^^box-alien ( src -- dst ) ^^i1 i ##box-alien ; inline
-: ^^unbox-alien ( src -- dst ) ^^i1 ##unbox-alien ; inline
-: ^^unbox-c-ptr ( src class -- dst ) ^^i2 i ##unbox-c-ptr ;
-: ^^alien-unsigned-1 ( src -- dst ) ^^i1 ##alien-unsigned-1 ; inline
-: ^^alien-unsigned-2 ( src -- dst ) ^^i1 ##alien-unsigned-2 ; inline
-: ^^alien-unsigned-4 ( src -- dst ) ^^i1 ##alien-unsigned-4 ; inline
-: ^^alien-signed-1 ( src -- dst ) ^^i1 ##alien-signed-1 ; inline
-: ^^alien-signed-2 ( src -- dst ) ^^i1 ##alien-signed-2 ; inline
-: ^^alien-signed-4 ( src -- dst ) ^^i1 ##alien-signed-4 ; inline
-: ^^alien-cell ( src -- dst ) ^^i1 ##alien-cell ; inline
-: ^^alien-float ( src -- dst ) ^^d1 ##alien-float ; inline
-: ^^alien-double ( src -- dst ) ^^d1 ##alien-double ; inline
-: ^^alien-global ( symbol library -- dst ) ^^i2 ##alien-global ; inline
-: ^^compare ( src1 src2 cc -- dst ) ^^i3 i ##compare ; inline
-: ^^compare-imm ( src1 src2 cc -- dst ) ^^i3 i ##compare-imm ; inline
-: ^^compare-float ( src1 src2 cc -- dst ) ^^i3 i ##compare-float ; inline
-: ^^offset>slot ( vreg -- vreg' ) cell 4 = [ 1 ^^shr-imm ] when ; inline
-: ^^tag-fixnum ( src -- dst ) ^^i1 ##tag-fixnum ; inline
-: ^^untag-fixnum ( src -- dst ) ^^i1 ##untag-fixnum ; inline
-
-: ^^phi ( inputs -- dst ) ^^i1 ##phi ; inline
\ No newline at end of file
+: ^^box-alien ( src -- dst ) ^^r1 next-vreg ##box-alien ; inline
+: ^^box-displaced-alien ( base displacement -- dst ) ^^r2 next-vreg ##box-displaced-alien ; inline
+: ^^unbox-alien ( src -- dst ) ^^r1 ##unbox-alien ; inline
+: ^^unbox-c-ptr ( src class -- dst ) ^^r2 next-vreg ##unbox-c-ptr ;
+: ^^alien-unsigned-1 ( src -- dst ) ^^r1 ##alien-unsigned-1 ; inline
+: ^^alien-unsigned-2 ( src -- dst ) ^^r1 ##alien-unsigned-2 ; inline
+: ^^alien-unsigned-4 ( src -- dst ) ^^r1 ##alien-unsigned-4 ; inline
+: ^^alien-signed-1 ( src -- dst ) ^^r1 ##alien-signed-1 ; inline
+: ^^alien-signed-2 ( src -- dst ) ^^r1 ##alien-signed-2 ; inline
+: ^^alien-signed-4 ( src -- dst ) ^^r1 ##alien-signed-4 ; inline
+: ^^alien-cell ( src -- dst ) ^^r1 ##alien-cell ; inline
+: ^^alien-float ( src -- dst ) ^^r1 ##alien-float ; inline
+: ^^alien-double ( src -- dst ) ^^r1 ##alien-double ; inline
+: ^^alien-global ( symbol library -- dst ) ^^r2 ##alien-global ; inline
+: ^^compare ( src1 src2 cc -- dst ) ^^r3 next-vreg ##compare ; inline
+: ^^compare-imm ( src1 src2 cc -- dst ) ^^r3 next-vreg ##compare-imm ; inline
+: ^^compare-float ( src1 src2 cc -- dst ) ^^r3 next-vreg ##compare-float ; inline
+: ^^offset>slot ( vreg -- vreg' ) cell 4 = [ 1 ^^shr-imm ] [ ^^copy ] if ; inline
+: ^^tag-fixnum ( src -- dst ) ^^r1 ##tag-fixnum ; inline
+: ^^untag-fixnum ( src -- dst ) ^^r1 ##untag-fixnum ; inline
+: ^^fixnum-add ( src1 src2 -- dst ) ^^r2 ##fixnum-add ; inline
+: ^^fixnum-sub ( src1 src2 -- dst ) ^^r2 ##fixnum-sub ; inline
+: ^^fixnum-mul ( src1 src2 -- dst ) ^^r2 ##fixnum-mul ; inline
+: ^^phi ( inputs -- dst ) ^^r1 ##phi ; inline
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008, 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors math namespaces sequences kernel fry
-compiler.cfg compiler.cfg.registers compiler.cfg.instructions
-compiler.cfg.liveness compiler.cfg.local ;
-IN: compiler.cfg.height
-
-! Combine multiple stack height changes into one at the
-! start of the basic block.
-
-SYMBOL: ds-height
-SYMBOL: rs-height
-
-GENERIC: compute-heights ( insn -- )
-
-M: ##inc-d compute-heights n>> ds-height [ + ] change ;
-M: ##inc-r compute-heights n>> rs-height [ + ] change ;
-M: insn compute-heights drop ;
-
-GENERIC: normalize-height* ( insn -- insn' )
-
-: normalize-inc-d/r ( insn stack -- insn' )
- swap n>> '[ _ - ] change f ; inline
-
-M: ##inc-d normalize-height* ds-height normalize-inc-d/r ;
-M: ##inc-r normalize-height* rs-height normalize-inc-d/r ;
-
-GENERIC: loc-stack ( loc -- stack )
-
-M: ds-loc loc-stack drop ds-height ;
-M: rs-loc loc-stack drop rs-height ;
-
-GENERIC: <loc> ( n stack -- loc )
-
-M: ds-loc <loc> drop <ds-loc> ;
-M: rs-loc <loc> drop <rs-loc> ;
-
-: normalize-peek/replace ( insn -- insn' )
- [ [ [ n>> ] [ loc-stack get ] bi + ] keep <loc> ] change-loc ; inline
-
-M: ##peek normalize-height* normalize-peek/replace ;
-M: ##replace normalize-height* normalize-peek/replace ;
-
-M: insn normalize-height* ;
-
-: height-step ( insns -- insns' )
- 0 ds-height set
- 0 rs-height set
- [ [ compute-heights ] each ]
- [ [ [ normalize-height* ] map sift ] with-scope ] bi
- ds-height get dup 0 = [ drop ] [ \ ##inc-d new-insn prefix ] if
- rs-height get dup 0 = [ drop ] [ \ ##inc-r new-insn prefix ] if ;
-
-: normalize-height ( cfg -- cfg' )
- [ drop ] [ height-step ] local-optimization ;
+++ /dev/null
-Stack height normalization coalesces height changes at start of basic block
compiler.cfg.instructions.syntax ;
IN: compiler.cfg.instructions
-: new-insn ( ... class -- insn ) [ f f ] dip boa ; inline
+: new-insn ( ... class -- insn ) f swap boa ; inline
! Virtual CPU instructions, used by CFG and machine IRs
TUPLE: insn ;
! Instruction with no side effects; if 'out' is never read, we
! can eliminate it.
-TUPLE: ##flushable < insn { dst vreg } ;
+TUPLE: ##flushable < insn dst ;
! Instruction which is referentially transparent; we can replace
! repeated computation with a reference to a previous value
TUPLE: ##pure < ##flushable ;
-TUPLE: ##unary < ##pure { src vreg } ;
-TUPLE: ##unary/temp < ##unary { temp vreg } ;
-TUPLE: ##binary < ##pure { src1 vreg } { src2 vreg } ;
-TUPLE: ##binary-imm < ##pure { src1 vreg } { src2 integer } ;
+TUPLE: ##unary < ##pure src ;
+TUPLE: ##unary/temp < ##unary temp ;
+TUPLE: ##binary < ##pure src1 src2 ;
+TUPLE: ##binary-imm < ##pure src1 { src2 integer } ;
TUPLE: ##commutative < ##binary ;
TUPLE: ##commutative-imm < ##binary-imm ;
! Instruction only used for its side effect, produces no values
-TUPLE: ##effect < insn { src vreg } ;
+TUPLE: ##effect < insn src ;
! Read/write ops: candidates for alias analysis
TUPLE: ##read < ##flushable ;
TUPLE: ##write < ##effect ;
-TUPLE: ##alien-getter < ##flushable { src vreg } ;
-TUPLE: ##alien-setter < ##effect { value vreg } ;
+TUPLE: ##alien-getter < ##flushable src ;
+TUPLE: ##alien-setter < ##effect value ;
! Stack operations
INSN: ##load-immediate < ##pure { val integer } ;
INSN: ##inc-r { n integer } ;
! Subroutine calls
-INSN: ##stack-frame stack-frame ;
-INSN: ##call word { height integer } ;
+INSN: ##call word ;
INSN: ##jump word ;
INSN: ##return ;
+! Dummy instruction that simply inhibits TCO
+INSN: ##no-tco ;
+
! Jump tables
INSN: ##dispatch src temp ;
! Slot access
-INSN: ##slot < ##read { obj vreg } { slot vreg } { tag integer } { temp vreg } ;
-INSN: ##slot-imm < ##read { obj vreg } { slot integer } { tag integer } ;
-INSN: ##set-slot < ##write { obj vreg } { slot vreg } { tag integer } { temp vreg } ;
-INSN: ##set-slot-imm < ##write { obj vreg } { slot integer } { tag integer } ;
+INSN: ##slot < ##read obj slot { tag integer } temp ;
+INSN: ##slot-imm < ##read obj { slot integer } { tag integer } ;
+INSN: ##set-slot < ##write obj slot { tag integer } temp ;
+INSN: ##set-slot-imm < ##write obj { slot integer } { tag integer } ;
! String element access
-INSN: ##string-nth < ##flushable { obj vreg } { index vreg } { temp vreg } ;
-INSN: ##set-string-nth-fast < ##effect { obj vreg } { index vreg } { temp vreg } ;
+INSN: ##string-nth < ##flushable obj index temp ;
+INSN: ##set-string-nth-fast < ##effect obj index temp ;
! Integer arithmetic
INSN: ##add < ##commutative ;
INSN: ##or-imm < ##commutative-imm ;
INSN: ##xor < ##commutative ;
INSN: ##xor-imm < ##commutative-imm ;
+INSN: ##shl < ##binary ;
INSN: ##shl-imm < ##binary-imm ;
+INSN: ##shr < ##binary ;
INSN: ##shr-imm < ##binary-imm ;
+INSN: ##sar < ##binary ;
INSN: ##sar-imm < ##binary-imm ;
INSN: ##not < ##unary ;
INSN: ##log2 < ##unary ;
-! Overflowing arithmetic
-TUPLE: ##fixnum-overflow < insn src1 src2 ;
-INSN: ##fixnum-add < ##fixnum-overflow ;
-INSN: ##fixnum-add-tail < ##fixnum-overflow ;
-INSN: ##fixnum-sub < ##fixnum-overflow ;
-INSN: ##fixnum-sub-tail < ##fixnum-overflow ;
-INSN: ##fixnum-mul < ##fixnum-overflow temp1 temp2 ;
-INSN: ##fixnum-mul-tail < ##fixnum-overflow temp1 temp2 ;
-
: ##tag-fixnum ( dst src -- ) tag-bits get ##shl-imm ; inline
: ##untag-fixnum ( dst src -- ) tag-bits get ##sar-imm ; inline
INSN: ##sub-float < ##binary ;
INSN: ##mul-float < ##commutative ;
INSN: ##div-float < ##binary ;
+INSN: ##sqrt < ##unary ;
! Float/integer conversion
INSN: ##float>integer < ##unary ;
INSN: ##integer>float < ##unary ;
! Boxing and unboxing
-INSN: ##copy < ##unary ;
-INSN: ##copy-float < ##unary ;
+INSN: ##copy < ##unary rep ;
INSN: ##unbox-float < ##unary ;
INSN: ##unbox-any-c-ptr < ##unary/temp ;
INSN: ##box-float < ##unary/temp ;
INSN: ##box-alien < ##unary/temp ;
+INSN: ##box-displaced-alien < ##binary temp ;
: ##unbox-f ( dst src -- ) drop 0 ##load-immediate ;
: ##unbox-byte-array ( dst src -- ) byte-array-offset ##add-imm ;
INSN: ##set-alien-double < ##alien-setter ;
! Memory allocation
-INSN: ##allot < ##flushable size class { temp vreg } ;
+INSN: ##allot < ##flushable size class temp ;
UNION: ##allocation ##allot ##box-float ##box-alien ##integer>bignum ;
INSN: ##alien-global < ##flushable symbol library ;
! FFI
-INSN: ##alien-invoke params ;
-INSN: ##alien-indirect params ;
-INSN: ##alien-callback params ;
+INSN: ##alien-invoke params stack-frame ;
+INSN: ##alien-indirect params stack-frame ;
+INSN: ##alien-callback params stack-frame ;
INSN: ##callback-return params ;
! Instructions used by CFG IR only.
INSN: ##branch ;
-INSN: ##loop-entry ;
-
INSN: ##phi < ##pure inputs ;
-! Condition codes
-SYMBOL: cc<
-SYMBOL: cc<=
-SYMBOL: cc=
-SYMBOL: cc>
-SYMBOL: cc>=
-SYMBOL: cc/=
-
-: negate-cc ( cc -- cc' )
- H{
- { cc< cc>= }
- { cc<= cc> }
- { cc> cc<= }
- { cc>= cc< }
- { cc= cc/= }
- { cc/= cc= }
- } at ;
-
-: evaluate-cc ( result cc -- ? )
- H{
- { cc< { +lt+ } }
- { cc<= { +lt+ +eq+ } }
- { cc= { +eq+ } }
- { cc>= { +eq+ +gt+ } }
- { cc> { +gt+ } }
- { cc/= { +lt+ +gt+ } }
- } at memq? ;
-
-TUPLE: ##conditional-branch < insn { src1 vreg } { src2 vreg } cc ;
+! Conditionals
+TUPLE: ##conditional-branch < insn src1 src2 cc ;
INSN: ##compare-branch < ##conditional-branch ;
-INSN: ##compare-imm-branch { src1 vreg } { src2 integer } cc ;
+INSN: ##compare-imm-branch src1 { src2 integer } cc ;
INSN: ##compare < ##binary cc temp ;
INSN: ##compare-imm < ##binary-imm cc temp ;
INSN: ##compare-float-branch < ##conditional-branch ;
INSN: ##compare-float < ##binary cc temp ;
-INSN: ##gc { temp1 vreg } { temp2 vreg } live-registers live-spill-slots ;
+! Overflowing arithmetic
+TUPLE: ##fixnum-overflow < insn dst src1 src2 ;
+INSN: ##fixnum-add < ##fixnum-overflow ;
+INSN: ##fixnum-sub < ##fixnum-overflow ;
+INSN: ##fixnum-mul < ##fixnum-overflow ;
+
+INSN: ##gc temp1 temp2 data-values tagged-values uninitialized-locs ;
! Instructions used by machine IR only.
INSN: _prologue stack-frame ;
INSN: _label id ;
INSN: _branch label ;
+INSN: _loop-entry ;
INSN: _dispatch src temp ;
INSN: _dispatch-label label ;
-TUPLE: _conditional-branch < insn label { src1 vreg } { src2 vreg } cc ;
+TUPLE: _conditional-branch < insn label src1 src2 cc ;
INSN: _compare-branch < _conditional-branch ;
-INSN: _compare-imm-branch label { src1 vreg } { src2 integer } cc ;
+INSN: _compare-imm-branch label src1 { src2 integer } cc ;
INSN: _compare-float-branch < _conditional-branch ;
+! Overflowing arithmetic
+TUPLE: _fixnum-overflow < insn label dst src1 src2 ;
+INSN: _fixnum-add < _fixnum-overflow ;
+INSN: _fixnum-sub < _fixnum-overflow ;
+INSN: _fixnum-mul < _fixnum-overflow ;
+
TUPLE: spill-slot n ; C: <spill-slot> spill-slot
-INSN: _gc { temp1 vreg } { temp2 vreg } gc-roots gc-root-count gc-root-size ;
+INSN: _gc temp1 temp2 data-values tagged-values uninitialized-locs ;
! These instructions operate on machine registers and not
! virtual registers
-INSN: _spill src class n ;
-INSN: _reload dst class n ;
-INSN: _spill-counts counts ;
+INSN: _spill src rep n ;
+INSN: _reload dst rep n ;
+INSN: _spill-area-size n ;
+
+! Instructions that use vregs
+UNION: vreg-insn
+ ##flushable
+ ##write-barrier
+ ##dispatch
+ ##effect
+ ##fixnum-overflow
+ ##conditional-branch
+ ##compare-imm-branch
+ ##phi
+ ##gc
+ _conditional-branch
+ _compare-imm-branch
+ _dispatch ;
+
+! Instructions that kill all live vregs
+UNION: kill-vreg-insn
+ ##call
+ ##prologue
+ ##epilogue
+ ##alien-invoke
+ ##alien-indirect
+ ##alien-callback ;
+
+! Instructions that output floats
+UNION: output-float-insn
+ ##add-float
+ ##sub-float
+ ##mul-float
+ ##div-float
+ ##sqrt
+ ##integer>float
+ ##unbox-float
+ ##alien-float
+ ##alien-double ;
+
+! Instructions that take floats as inputs
+UNION: input-float-insn
+ ##add-float
+ ##sub-float
+ ##mul-float
+ ##div-float
+ ##sqrt
+ ##float>integer
+ ##box-float
+ ##set-alien-float
+ ##set-alien-double
+ ##compare-float
+ ##compare-float-branch ;
+
+! Smackdown
+INTERSECTION: ##unary-float ##unary input-float-insn ;
+INTERSECTION: ##binary-float ##binary input-float-insn ;
+
+! Instructions that have complex expansions and require that the
+! output registers are not equal to any of the input registers
+UNION: def-is-use-insn
+ ##integer>bignum
+ ##bignum>integer
+ ##unbox-any-c-ptr ;
\ No newline at end of file
"insn" "compiler.cfg.instructions" lookup ;
: insn-effect ( word -- effect )
- boa-effect in>> 2 head* f <effect> ;
+ boa-effect in>> but-last f <effect> ;
SYNTAX: INSN:
- parse-tuple-definition { "regs" "insn#" } append
+ parse-tuple-definition "insn#" suffix
[ dup tuple eq? [ drop insn-word ] when ] dip
[ define-tuple-class ]
[ 2drop save-location ]
- [ 2drop [ ] [ '[ f f _ boa , ] ] [ insn-effect ] tri define-inline ]
+ [ 2drop [ ] [ '[ f _ boa , ] ] [ insn-effect ] tri define-inline ]
3tri ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel sequences alien math classes.algebra
-fry locals combinators cpu.architecture
-compiler.tree.propagation.info
-compiler.cfg.hats compiler.cfg.stacks compiler.cfg.instructions
-compiler.cfg.utilities ;
+USING: accessors kernel sequences alien math classes.algebra fry
+locals combinators combinators.short-circuit cpu.architecture
+compiler.tree.propagation.info compiler.cfg.hats
+compiler.cfg.stacks compiler.cfg.instructions
+compiler.cfg.utilities compiler.cfg.builder.blocks ;
IN: compiler.cfg.intrinsics.alien
+: emit-<displaced-alien>? ( node -- ? )
+ node-input-infos {
+ [ first class>> fixnum class<= ]
+ [ second class>> c-ptr class<= ]
+ } 1&& ;
+
+: emit-<displaced-alien> ( node -- )
+ dup emit-<displaced-alien>?
+ [ drop 2inputs [ ^^untag-fixnum ] dip ^^box-displaced-alien ds-push ]
+ [ emit-primitive ]
+ if ;
+
: (prepare-alien-accessor-imm) ( class offset -- offset-vreg )
ds-drop [ ds-pop swap ^^unbox-c-ptr ] dip ^^add-imm ;
inline-alien ; inline
: inline-alien-float-setter ( node quot -- )
- '[ ds-pop ^^unbox-float @ ]
+ '[ ds-pop @ ]
[ float inline-alien-setter? ]
inline-alien ; inline
: emit-alien-cell-setter ( node -- )
[ ##set-alien-cell ] inline-alien-cell-setter ;
-: emit-alien-float-getter ( node reg-class -- )
+: emit-alien-float-getter ( node rep -- )
'[
_ {
- { single-float-regs [ ^^alien-float ] }
- { double-float-regs [ ^^alien-double ] }
- } case ^^box-float
+ { single-float-rep [ ^^alien-float ] }
+ { double-float-rep [ ^^alien-double ] }
+ } case
] inline-alien-getter ;
-: emit-alien-float-setter ( node reg-class -- )
+: emit-alien-float-setter ( node rep -- )
'[
_ {
- { single-float-regs [ ##set-alien-float ] }
- { double-float-regs [ ##set-alien-double ] }
+ { single-float-rep [ ##set-alien-float ] }
+ { double-float-rep [ ##set-alien-double ] }
} case
] inline-alien-float-setter ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math math.order sequences accessors arrays
byte-arrays layouts classes.tuple.private fry locals
compiler.tree.propagation.info compiler.cfg.hats
compiler.cfg.instructions compiler.cfg.stacks
-compiler.cfg.utilities ;
+compiler.cfg.utilities compiler.cfg.builder.blocks ;
IN: compiler.cfg.intrinsics.allot
: ##set-slots ( regs obj class -- )
- '[ _ swap 1+ _ tag-number ##set-slot-imm ] each-index ;
+ '[ _ swap 1 + _ tag-number ##set-slot-imm ] each-index ;
: emit-simple-allot ( node -- )
[ in-d>> length ] [ node-output-infos first class>> ] bi
- [ drop ds-load ] [ [ 1+ cells ] dip ^^allot ] [ nip ] 2tri
+ [ drop ds-load ] [ [ 1 + cells ] dip ^^allot ] [ nip ] 2tri
[ ##set-slots ] [ [ drop ] [ ds-push ] [ drop ] tri* ] 3bi ;
: tuple-slot-regs ( layout -- vregs )
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: sequences accessors layouts kernel math namespaces
-combinators fry locals
+USING: sequences accessors layouts kernel math math.intervals
+namespaces combinators fry arrays
compiler.tree.propagation.info
compiler.cfg.hats
compiler.cfg.stacks
-compiler.cfg.iterator
compiler.cfg.instructions
compiler.cfg.utilities
-compiler.cfg.registers ;
+compiler.cfg.builder.blocks
+compiler.cfg.registers
+compiler.cfg.comparisons ;
IN: compiler.cfg.intrinsics.fixnum
: emit-both-fixnums? ( -- )
0 cc= ^^compare-imm
ds-push ;
-: (emit-fixnum-imm-op) ( infos insn -- dst )
- ds-drop
- [ ds-pop ]
- [ second literal>> [ tag-fixnum ] [ \ f tag-number ] if* ]
- [ ]
- tri*
- call ; inline
-
-: (emit-fixnum-op) ( insn -- dst )
- [ 2inputs ] dip call ; inline
-
-:: emit-fixnum-op ( node insn imm-insn -- )
- [let | infos [ node node-input-infos ] |
- infos second value-info-small-tagged?
- [ infos imm-insn (emit-fixnum-imm-op) ]
- [ insn (emit-fixnum-op) ]
- if
- ds-push
- ] ; inline
+: tag-literal ( n -- tagged )
+ literal>> [ tag-fixnum ] [ \ f tag-number ] if* ;
-: emit-fixnum-shift-fast ( node -- )
- dup node-input-infos dup second value-info-small-fixnum? [
- nip
- [ ds-drop ds-pop ] dip
- second literal>> dup sgn {
- { -1 [ neg tag-bits get + ^^sar-imm ^^tag-fixnum ] }
- { 0 [ drop ] }
- { 1 [ ^^shl-imm ] }
- } case
- ds-push
- ] [ drop emit-primitive ] if ;
+: emit-fixnum-op ( insn -- )
+ [ 2inputs ] dip call ds-push ; inline
+
+: emit-fixnum-left-shift ( -- )
+ [ ^^untag-fixnum ^^shl ] emit-fixnum-op ;
+
+: emit-fixnum-right-shift ( -- )
+ [ ^^untag-fixnum ^^neg ^^sar dup tag-mask get ^^and-imm ^^xor ] emit-fixnum-op ;
+
+: emit-fixnum-shift-general ( -- )
+ ds-peek 0 cc> ##compare-imm-branch
+ [ emit-fixnum-left-shift ] with-branch
+ [ emit-fixnum-right-shift ] with-branch
+ 2array emit-conditional ;
+: emit-fixnum-shift-fast ( node -- )
+ node-input-infos second interval>> {
+ { [ dup 0 [a,inf] interval-subset? ] [ drop emit-fixnum-left-shift ] }
+ { [ dup 0 [-inf,a] interval-subset? ] [ drop emit-fixnum-right-shift ] }
+ [ drop emit-fixnum-shift-general ]
+ } cond ;
+
: emit-fixnum-bitnot ( -- )
ds-pop ^^not tag-mask get ^^xor-imm ds-push ;
: emit-fixnum-log2 ( -- )
ds-pop ^^log2 tag-bits get ^^sub-imm ^^tag-fixnum ds-push ;
-: (emit-fixnum*fast) ( -- dst )
- 2inputs ^^untag-fixnum ^^mul ;
-
-: (emit-fixnum*fast-imm) ( infos -- dst )
- ds-drop
- [ ds-pop ] [ second literal>> ] bi* ^^mul-imm ;
-
-: emit-fixnum*fast ( node -- )
- node-input-infos
- dup second value-info-small-fixnum?
- [ (emit-fixnum*fast-imm) ] [ drop (emit-fixnum*fast) ] if
- ds-push ;
+: emit-fixnum*fast ( -- )
+ 2inputs ^^untag-fixnum ^^mul ds-push ;
-: emit-fixnum-comparison ( node cc -- )
- [ ^^compare ] [ ^^compare-imm ] bi-curry
- emit-fixnum-op ;
+: emit-fixnum-comparison ( cc -- )
+ '[ _ ^^compare ] emit-fixnum-op ;
: emit-bignum>fixnum ( -- )
ds-pop ^^bignum>integer ^^tag-fixnum ds-push ;
: emit-fixnum>bignum ( -- )
ds-pop ^^untag-fixnum ^^integer>bignum ds-push ;
-: emit-fixnum-overflow-op ( quot quot-tail -- next )
- [ 2inputs 1 ##inc-d ] 2dip
- tail-call? [
- ##epilogue
- nip call
- stop-iterating
- ] [
- drop call
- ##branch
- begin-basic-block
- iterate-next
- ] if ; inline
+: emit-no-overflow-case ( dst -- final-bb )
+ [ ds-drop ds-drop ds-push ] with-branch ;
+
+: emit-overflow-case ( word -- final-bb )
+ [ ##call -1 adjust-d ] with-branch ;
+
+: emit-fixnum-overflow-op ( quot word -- )
+ ! Inputs to the final instruction need to be copied because
+ ! of loc>vreg sync
+ [ [ (2inputs) [ ^^copy ] bi@ ] dip call ] dip
+ [ emit-no-overflow-case ] [ emit-overflow-case ] bi* 2array
+ emit-conditional ; inline
+
+: fixnum+overflow ( x y -- z ) [ >bignum ] bi@ + ;
+
+: fixnum-overflow ( x y -- z ) [ >bignum ] bi@ - ;
+
+: fixnum*overflow ( x y -- z ) [ >bignum ] bi@ * ;
+
+: emit-fixnum+ ( -- )
+ [ ^^fixnum-add ] \ fixnum+overflow emit-fixnum-overflow-op ;
+
+: emit-fixnum- ( -- )
+ [ ^^fixnum-sub ] \ fixnum-overflow emit-fixnum-overflow-op ;
+
+: emit-fixnum* ( -- )
+ [ ^^untag-fixnum ^^fixnum-mul ] \ fixnum*overflow emit-fixnum-overflow-op ;
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel compiler.cfg.stacks compiler.cfg.hats
compiler.cfg.instructions compiler.cfg.utilities ;
IN: compiler.cfg.intrinsics.float
: emit-float-op ( insn -- )
- [ 2inputs [ ^^unbox-float ] bi@ ] dip call ^^box-float
- ds-push ; inline
+ [ 2inputs ] dip call ds-push ; inline
: emit-float-comparison ( cc -- )
- [ 2inputs [ ^^unbox-float ] bi@ ] dip ^^compare-float
- ds-push ; inline
+ [ 2inputs ] dip ^^compare-float ds-push ; inline
: emit-float>fixnum ( -- )
- ds-pop ^^unbox-float ^^float>integer ^^tag-fixnum ds-push ;
+ ds-pop ^^float>integer ^^tag-fixnum ds-push ;
: emit-fixnum>float ( -- )
- ds-pop ^^untag-fixnum ^^integer>float ^^box-float ds-push ;
+ ds-pop ^^untag-fixnum ^^integer>float ds-push ;
+
+: emit-fsqrt ( -- )
+ ds-pop ^^sqrt ds-push ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: words sequences kernel combinators cpu.architecture
compiler.cfg.hats
compiler.cfg.intrinsics.float
compiler.cfg.intrinsics.slots
compiler.cfg.intrinsics.misc
-compiler.cfg.iterator ;
+compiler.cfg.comparisons ;
+QUALIFIED: alien
+QUALIFIED: alien.accessors
QUALIFIED: kernel
QUALIFIED: arrays
QUALIFIED: byte-arrays
QUALIFIED: classes.tuple.private
QUALIFIED: math.private
QUALIFIED: math.integers.private
-QUALIFIED: alien.accessors
+QUALIFIED: math.libm
IN: compiler.cfg.intrinsics
{
math.private:fixnum<=
math.private:fixnum>=
math.private:fixnum>
- math.private:bignum>fixnum
- math.private:fixnum>bignum
+ ! math.private:bignum>fixnum
+ ! math.private:fixnum>bignum
kernel:eq?
slots.private:slot
slots.private:set-slot
byte-arrays:<byte-array>
byte-arrays:(byte-array)
kernel:<wrapper>
+ alien:<displaced-alien>
alien.accessors:alien-unsigned-1
alien.accessors:set-alien-unsigned-1
alien.accessors:alien-signed-1
alien.accessors:set-alien-double
} [ t "intrinsic" set-word-prop ] each ;
+: enable-fsqrt ( -- )
+ \ math.libm:fsqrt t "intrinsic" set-word-prop ;
+
: enable-fixnum-log2 ( -- )
\ math.integers.private:fixnum-log2 t "intrinsic" set-word-prop ;
-: emit-intrinsic ( node word -- node/f )
+: emit-intrinsic ( node word -- )
{
- { \ kernel.private:tag [ drop emit-tag iterate-next ] }
- { \ kernel.private:getenv [ emit-getenv iterate-next ] }
- { \ math.private:both-fixnums? [ drop emit-both-fixnums? iterate-next ] }
- { \ math.private:fixnum+ [ drop [ ##fixnum-add ] [ ##fixnum-add-tail ] emit-fixnum-overflow-op ] }
- { \ math.private:fixnum- [ drop [ ##fixnum-sub ] [ ##fixnum-sub-tail ] emit-fixnum-overflow-op ] }
- { \ math.private:fixnum* [ drop [ i i ##fixnum-mul ] [ i i ##fixnum-mul-tail ] emit-fixnum-overflow-op ] }
- { \ math.private:fixnum+fast [ [ ^^add ] [ ^^add-imm ] emit-fixnum-op iterate-next ] }
- { \ math.private:fixnum-fast [ [ ^^sub ] [ ^^sub-imm ] emit-fixnum-op iterate-next ] }
- { \ math.private:fixnum-bitand [ [ ^^and ] [ ^^and-imm ] emit-fixnum-op iterate-next ] }
- { \ math.private:fixnum-bitor [ [ ^^or ] [ ^^or-imm ] emit-fixnum-op iterate-next ] }
- { \ math.private:fixnum-bitxor [ [ ^^xor ] [ ^^xor-imm ] emit-fixnum-op iterate-next ] }
- { \ math.private:fixnum-shift-fast [ emit-fixnum-shift-fast iterate-next ] }
- { \ math.private:fixnum-bitnot [ drop emit-fixnum-bitnot iterate-next ] }
- { \ math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 iterate-next ] }
- { \ math.private:fixnum*fast [ emit-fixnum*fast iterate-next ] }
- { \ math.private:fixnum< [ cc< emit-fixnum-comparison iterate-next ] }
- { \ math.private:fixnum<= [ cc<= emit-fixnum-comparison iterate-next ] }
- { \ math.private:fixnum>= [ cc>= emit-fixnum-comparison iterate-next ] }
- { \ math.private:fixnum> [ cc> emit-fixnum-comparison iterate-next ] }
- { \ kernel:eq? [ cc= emit-fixnum-comparison iterate-next ] }
- { \ math.private:bignum>fixnum [ drop emit-bignum>fixnum iterate-next ] }
- { \ math.private:fixnum>bignum [ drop emit-fixnum>bignum iterate-next ] }
- { \ math.private:float+ [ drop [ ^^add-float ] emit-float-op iterate-next ] }
- { \ math.private:float- [ drop [ ^^sub-float ] emit-float-op iterate-next ] }
- { \ math.private:float* [ drop [ ^^mul-float ] emit-float-op iterate-next ] }
- { \ math.private:float/f [ drop [ ^^div-float ] emit-float-op iterate-next ] }
- { \ math.private:float< [ drop cc< emit-float-comparison iterate-next ] }
- { \ math.private:float<= [ drop cc<= emit-float-comparison iterate-next ] }
- { \ math.private:float>= [ drop cc>= emit-float-comparison iterate-next ] }
- { \ math.private:float> [ drop cc> emit-float-comparison iterate-next ] }
- { \ math.private:float= [ drop cc= emit-float-comparison iterate-next ] }
- { \ math.private:float>fixnum [ drop emit-float>fixnum iterate-next ] }
- { \ math.private:fixnum>float [ drop emit-fixnum>float iterate-next ] }
- { \ slots.private:slot [ emit-slot iterate-next ] }
- { \ slots.private:set-slot [ emit-set-slot iterate-next ] }
- { \ strings.private:string-nth [ drop emit-string-nth iterate-next ] }
- { \ strings.private:set-string-nth-fast [ drop emit-set-string-nth-fast iterate-next ] }
- { \ classes.tuple.private:<tuple-boa> [ emit-<tuple-boa> iterate-next ] }
- { \ arrays:<array> [ emit-<array> iterate-next ] }
- { \ byte-arrays:<byte-array> [ emit-<byte-array> iterate-next ] }
- { \ byte-arrays:(byte-array) [ emit-(byte-array) iterate-next ] }
- { \ kernel:<wrapper> [ emit-simple-allot iterate-next ] }
- { \ alien.accessors:alien-unsigned-1 [ 1 emit-alien-unsigned-getter iterate-next ] }
- { \ alien.accessors:set-alien-unsigned-1 [ 1 emit-alien-integer-setter iterate-next ] }
- { \ alien.accessors:alien-signed-1 [ 1 emit-alien-signed-getter iterate-next ] }
- { \ alien.accessors:set-alien-signed-1 [ 1 emit-alien-integer-setter iterate-next ] }
- { \ alien.accessors:alien-unsigned-2 [ 2 emit-alien-unsigned-getter iterate-next ] }
- { \ alien.accessors:set-alien-unsigned-2 [ 2 emit-alien-integer-setter iterate-next ] }
- { \ alien.accessors:alien-signed-2 [ 2 emit-alien-signed-getter iterate-next ] }
- { \ alien.accessors:set-alien-signed-2 [ 2 emit-alien-integer-setter iterate-next ] }
- { \ alien.accessors:alien-unsigned-4 [ 4 emit-alien-unsigned-getter iterate-next ] }
- { \ alien.accessors:set-alien-unsigned-4 [ 4 emit-alien-integer-setter iterate-next ] }
- { \ alien.accessors:alien-signed-4 [ 4 emit-alien-signed-getter iterate-next ] }
- { \ alien.accessors:set-alien-signed-4 [ 4 emit-alien-integer-setter iterate-next ] }
- { \ alien.accessors:alien-cell [ emit-alien-cell-getter iterate-next ] }
- { \ alien.accessors:set-alien-cell [ emit-alien-cell-setter iterate-next ] }
- { \ alien.accessors:alien-float [ single-float-regs emit-alien-float-getter iterate-next ] }
- { \ alien.accessors:set-alien-float [ single-float-regs emit-alien-float-setter iterate-next ] }
- { \ alien.accessors:alien-double [ double-float-regs emit-alien-float-getter iterate-next ] }
- { \ alien.accessors:set-alien-double [ double-float-regs emit-alien-float-setter iterate-next ] }
+ { \ kernel.private:tag [ drop emit-tag ] }
+ { \ kernel.private:getenv [ emit-getenv ] }
+ { \ math.private:both-fixnums? [ drop emit-both-fixnums? ] }
+ { \ math.private:fixnum+ [ drop emit-fixnum+ ] }
+ { \ math.private:fixnum- [ drop emit-fixnum- ] }
+ { \ math.private:fixnum* [ drop emit-fixnum* ] }
+ { \ math.private:fixnum+fast [ drop [ ^^add ] emit-fixnum-op ] }
+ { \ math.private:fixnum-fast [ drop [ ^^sub ] emit-fixnum-op ] }
+ { \ math.private:fixnum-bitand [ drop [ ^^and ] emit-fixnum-op ] }
+ { \ math.private:fixnum-bitor [ drop [ ^^or ] emit-fixnum-op ] }
+ { \ math.private:fixnum-bitxor [ drop [ ^^xor ] emit-fixnum-op ] }
+ { \ math.private:fixnum-shift-fast [ emit-fixnum-shift-fast ] }
+ { \ math.private:fixnum-bitnot [ drop emit-fixnum-bitnot ] }
+ { \ math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 ] }
+ { \ math.private:fixnum*fast [ drop emit-fixnum*fast ] }
+ { \ math.private:fixnum< [ drop cc< emit-fixnum-comparison ] }
+ { \ math.private:fixnum<= [ drop cc<= emit-fixnum-comparison ] }
+ { \ math.private:fixnum>= [ drop cc>= emit-fixnum-comparison ] }
+ { \ math.private:fixnum> [ drop cc> emit-fixnum-comparison ] }
+ { \ kernel:eq? [ drop cc= emit-fixnum-comparison ] }
+ { \ math.private:bignum>fixnum [ drop emit-bignum>fixnum ] }
+ { \ math.private:fixnum>bignum [ drop emit-fixnum>bignum ] }
+ { \ math.private:float+ [ drop [ ^^add-float ] emit-float-op ] }
+ { \ math.private:float- [ drop [ ^^sub-float ] emit-float-op ] }
+ { \ math.private:float* [ drop [ ^^mul-float ] emit-float-op ] }
+ { \ math.private:float/f [ drop [ ^^div-float ] emit-float-op ] }
+ { \ math.private:float< [ drop cc< emit-float-comparison ] }
+ { \ math.private:float<= [ drop cc<= emit-float-comparison ] }
+ { \ math.private:float>= [ drop cc>= emit-float-comparison ] }
+ { \ math.private:float> [ drop cc> emit-float-comparison ] }
+ { \ math.private:float= [ drop cc= emit-float-comparison ] }
+ { \ math.private:float>fixnum [ drop emit-float>fixnum ] }
+ { \ math.private:fixnum>float [ drop emit-fixnum>float ] }
+ { \ math.libm:fsqrt [ drop emit-fsqrt ] }
+ { \ slots.private:slot [ emit-slot ] }
+ { \ slots.private:set-slot [ emit-set-slot ] }
+ { \ strings.private:string-nth [ drop emit-string-nth ] }
+ { \ strings.private:set-string-nth-fast [ drop emit-set-string-nth-fast ] }
+ { \ classes.tuple.private:<tuple-boa> [ emit-<tuple-boa> ] }
+ { \ arrays:<array> [ emit-<array> ] }
+ { \ byte-arrays:<byte-array> [ emit-<byte-array> ] }
+ { \ byte-arrays:(byte-array) [ emit-(byte-array) ] }
+ { \ kernel:<wrapper> [ emit-simple-allot ] }
+ { \ alien:<displaced-alien> [ emit-<displaced-alien> ] }
+ { \ alien.accessors:alien-unsigned-1 [ 1 emit-alien-unsigned-getter ] }
+ { \ alien.accessors:set-alien-unsigned-1 [ 1 emit-alien-integer-setter ] }
+ { \ alien.accessors:alien-signed-1 [ 1 emit-alien-signed-getter ] }
+ { \ alien.accessors:set-alien-signed-1 [ 1 emit-alien-integer-setter ] }
+ { \ alien.accessors:alien-unsigned-2 [ 2 emit-alien-unsigned-getter ] }
+ { \ alien.accessors:set-alien-unsigned-2 [ 2 emit-alien-integer-setter ] }
+ { \ alien.accessors:alien-signed-2 [ 2 emit-alien-signed-getter ] }
+ { \ alien.accessors:set-alien-signed-2 [ 2 emit-alien-integer-setter ] }
+ { \ alien.accessors:alien-unsigned-4 [ 4 emit-alien-unsigned-getter ] }
+ { \ alien.accessors:set-alien-unsigned-4 [ 4 emit-alien-integer-setter ] }
+ { \ alien.accessors:alien-signed-4 [ 4 emit-alien-signed-getter ] }
+ { \ alien.accessors:set-alien-signed-4 [ 4 emit-alien-integer-setter ] }
+ { \ alien.accessors:alien-cell [ emit-alien-cell-getter ] }
+ { \ alien.accessors:set-alien-cell [ emit-alien-cell-setter ] }
+ { \ alien.accessors:alien-float [ single-float-rep emit-alien-float-getter ] }
+ { \ alien.accessors:set-alien-float [ single-float-rep emit-alien-float-setter ] }
+ { \ alien.accessors:alien-double [ double-float-rep emit-alien-float-getter ] }
+ { \ alien.accessors:set-alien-double [ double-float-rep emit-alien-float-setter ] }
} case ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: layouts namespaces kernel accessors sequences
-classes.algebra compiler.tree.propagation.info
-compiler.cfg.stacks compiler.cfg.hats compiler.cfg.instructions
-compiler.cfg.utilities ;
+USING: layouts namespaces kernel accessors sequences classes.algebra
+compiler.tree.propagation.info compiler.cfg.stacks compiler.cfg.hats
+compiler.cfg.registers compiler.cfg.instructions
+compiler.cfg.utilities compiler.cfg.builder.blocks ;
IN: compiler.cfg.intrinsics.slots
: value-tag ( info -- n ) class>> class-tag ; inline
dup third value-info-small-fixnum?
[ (emit-set-slot-imm) ] [ (emit-set-slot) ] if
] [ first class>> immediate class<= ] bi
- [ drop ] [ i i ##write-barrier ] if
+ [ drop ] [ next-vreg next-vreg ##write-barrier ] if
] [ drop emit-primitive ] if ;
: emit-string-nth ( -- )
: emit-set-string-nth-fast ( -- )
3inputs [ ^^untag-fixnum ] [ ^^untag-fixnum ] [ ] tri*
- swap i ##set-string-nth-fast ;
+ swap next-vreg ##set-string-nth-fast ;
+++ /dev/null
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces sequences kernel compiler.tree ;
-IN: compiler.cfg.iterator
-
-SYMBOL: node-stack
-
-: >node ( cursor -- ) node-stack get push ;
-: node> ( -- cursor ) node-stack get pop ;
-: node@ ( -- cursor ) node-stack get last ;
-: current-node ( -- node ) node@ first ;
-: iterate-next ( -- cursor ) node@ rest-slice ;
-: skip-next ( -- next ) node> rest-slice [ first ] [ >node ] bi ;
-
-: iterate-nodes ( cursor quot: ( -- ) -- )
- over empty? [
- 2drop
- ] [
- [ swap >node call node> drop ] keep iterate-nodes
- ] if ; inline recursive
-
-DEFER: (tail-call?)
-
-: tail-phi? ( cursor -- ? )
- [ first #phi? ] [ rest-slice (tail-call?) ] bi and ;
-
-: (tail-call?) ( cursor -- ? )
- [ t ] [
- [
- first
- [ #return? ]
- [ #return-recursive? ]
- [ #terminate? ] tri or or
- ] [ tail-phi? ] bi or
- ] if-empty ;
-
-: tail-call? ( -- ? )
- node-stack get [
- rest-slice
- [ t ] [ (tail-call?) ] if-empty
- ] all? ;
-
-: terminate-call? ( -- ? )
- node-stack get last
- rest-slice [ f ] [ first #terminate? ] if-empty ;
+++ /dev/null
-Utility for iterating for high-level IR
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces sequences math math.order kernel assocs
-accessors vectors fry heaps cpu.architecture sorting locals
-combinators compiler.cfg.registers
-compiler.cfg.linear-scan.live-intervals hints ;
+USING: accessors assocs heaps kernel namespaces sequences fry math
+math.order combinators arrays sorting compiler.utilities
+compiler.cfg.linear-scan.live-intervals
+compiler.cfg.linear-scan.allocation.spilling
+compiler.cfg.linear-scan.allocation.splitting
+compiler.cfg.linear-scan.allocation.state ;
IN: compiler.cfg.linear-scan.allocation
-! Mapping from register classes to sequences of machine registers
-SYMBOL: free-registers
+: active-positions ( new assoc -- )
+ [ vreg>> active-intervals-for ] dip
+ '[ [ 0 ] dip reg>> _ add-use-position ] each ;
-: free-registers-for ( vreg -- seq )
- reg-class>> free-registers get at ;
+: inactive-positions ( new assoc -- )
+ [ [ vreg>> inactive-intervals-for ] keep ] dip
+ '[
+ [ _ relevant-ranges intersect-live-ranges 1/0. or ] [ reg>> ] bi
+ _ add-use-position
+ ] each ;
-: deallocate-register ( live-interval -- )
- [ reg>> ] [ vreg>> ] bi free-registers-for push ;
+: register-status ( new -- free-pos )
+ dup free-positions
+ [ inactive-positions ] [ active-positions ] [ nip ] 2tri
+ >alist alist-max ;
-! Vector of active live intervals
-SYMBOL: active-intervals
-
-: active-intervals-for ( vreg -- seq )
- reg-class>> active-intervals get at ;
-
-: add-active ( live-interval -- )
- dup vreg>> active-intervals-for push ;
-
-: delete-active ( live-interval -- )
- dup vreg>> active-intervals-for delq ;
-
-! Vector of inactive live intervals
-SYMBOL: inactive-intervals
-
-: inactive-intervals-for ( vreg -- seq )
- reg-class>> inactive-intervals get at ;
-
-: add-inactive ( live-interval -- )
- dup vreg>> inactive-intervals-for push ;
-
-! Vector of handled live intervals
-SYMBOL: handled-intervals
-
-: add-handled ( live-interval -- )
- handled-intervals get push ;
-
-: finished? ( n live-interval -- ? ) end>> swap < ;
-
-: finish ( n live-interval -- keep? )
- nip [ deallocate-register ] [ add-handled ] bi f ;
-
-: activate ( n live-interval -- keep? )
- nip add-active f ;
-
-: deactivate ( n live-interval -- keep? )
- nip add-inactive f ;
-
-: don't-change ( n live-interval -- keep? ) 2drop t ;
-
-! Moving intervals between active and inactive sets
-: process-intervals ( n symbol quots -- )
- ! symbol stores an alist mapping register classes to vectors
- [ get values ] dip '[ [ _ cond ] with filter-here ] with each ; inline
-
-: covers? ( insn# live-interval -- ? )
- ranges>> [ [ from>> ] [ to>> ] bi between? ] with any? ;
-
-: deactivate-intervals ( n -- )
- ! Any active intervals which have ended are moved to handled
- ! Any active intervals which cover the current position
- ! are moved to inactive
- active-intervals {
- { [ 2dup finished? ] [ finish ] }
- { [ 2dup covers? not ] [ deactivate ] }
- [ don't-change ]
- } process-intervals ;
-
-: activate-intervals ( n -- )
- ! Any inactive intervals which have ended are moved to handled
- ! Any inactive intervals which do not cover the current position
- ! are moved to active
- inactive-intervals {
- { [ 2dup finished? ] [ finish ] }
- { [ 2dup covers? ] [ activate ] }
- [ don't-change ]
- } process-intervals ;
-
-! Minheap of live intervals which still need a register allocation
-SYMBOL: unhandled-intervals
-
-! Start index of current live interval. We ensure that all
-! live intervals added to the unhandled set have a start index
-! strictly greater than ths one. This ensures that we can catch
-! infinite loop situations.
-SYMBOL: progress
-
-: check-progress ( live-interval -- )
- start>> progress get <= [ "No progress" throw ] when ; inline
-
-: add-unhandled ( live-interval -- )
- [ check-progress ]
- [ dup start>> unhandled-intervals get heap-push ]
- bi ;
-
-: init-unhandled ( live-intervals -- )
- [ [ start>> ] keep ] { } map>assoc
- unhandled-intervals get heap-push-all ;
-
-! Coalescing
-: active-interval ( vreg -- live-interval )
- dup [ dup active-intervals-for [ vreg>> = ] with find nip ] when ;
-
-: coalesce? ( live-interval -- ? )
- [ start>> ] [ copy-from>> active-interval ] bi
- dup [ end>> = ] [ 2drop f ] if ;
-
-: coalesce ( live-interval -- )
- dup copy-from>> active-interval
- [ [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ]
- [ reg>> >>reg drop ]
- 2bi ;
-
-! Splitting
-: split-range ( live-range n -- before after )
- [ [ from>> ] dip <live-range> ]
- [ 1 + swap to>> <live-range> ]
- 2bi ;
-
-: split-last-range? ( last n -- ? )
- swap to>> <= ;
-
-: split-last-range ( before after last n -- before' after' )
- split-range [ [ but-last ] dip suffix ] [ prefix ] bi-curry* bi* ;
-
-: split-ranges ( live-ranges n -- before after )
- [ '[ from>> _ <= ] partition ]
- [
- pick empty? [ drop ] [
- [ over last ] dip 2dup split-last-range?
- [ split-last-range ] [ 2drop ] if
- ] if
- ] bi ;
-
-: split-uses ( uses n -- before after )
- '[ _ <= ] partition ;
-
-: record-split ( live-interval before after -- )
- [ >>split-before ] [ >>split-after ] bi* drop ; inline
-
-: check-split ( live-interval -- )
- [ end>> ] [ start>> ] bi - 0 =
- [ "BUG: splitting atomic interval" throw ] when ; inline
-
-: split-before ( before -- before' )
- [ [ ranges>> last ] [ uses>> last ] bi >>to drop ]
- [ compute-start/end ]
- [ ]
- tri ; inline
-
-: split-after ( after -- after' )
- [ [ ranges>> first ] [ uses>> first ] bi >>from drop ]
- [ compute-start/end ]
- [ ]
- tri ; inline
-
-:: split-interval ( live-interval n -- before after )
- live-interval check-split
- live-interval clone :> before
- live-interval clone f >>copy-from f >>reg :> after
- live-interval uses>> n split-uses before after [ (>>uses) ] bi-curry@ bi*
- live-interval ranges>> n split-ranges before after [ (>>ranges) ] bi-curry@ bi*
- live-interval before after record-split
- before split-before
- after split-after ;
-
-HINTS: split-interval live-interval object ;
-
-! Spilling
-SYMBOL: spill-counts
-
-: next-spill-location ( reg-class -- n )
- spill-counts get [ dup 1+ ] change-at ;
-
-: find-use ( live-interval n quot -- i elt )
- [ uses>> ] 2dip curry find ; inline
-
-: interval-to-spill ( active-intervals current -- live-interval )
- #! We spill the interval with the most distant use location.
- start>> '[ dup _ [ >= ] find-use nip ] { } map>assoc
- [ ] [ [ [ second ] bi@ > ] most ] map-reduce first ;
-
-: assign-spill ( before after -- before after )
- #! If it has been spilled already, reuse spill location.
- over reload-from>>
- [ over vreg>> reg-class>> next-spill-location ] unless*
- [ >>spill-to ] [ >>reload-from ] bi-curry bi* ;
-
-: split-and-spill ( new existing -- before after )
- swap start>> split-interval assign-spill ;
-
-: reuse-register ( new existing -- )
- reg>> >>reg add-active ;
-
-: spill-existing ( new existing -- )
- #! Our new interval will be used before the active interval
- #! with the most distant use location. Spill the existing
- #! interval, then process the new interval and the tail end
- #! of the existing interval again.
- [ reuse-register ]
- [ nip delete-active ]
- [ split-and-spill [ add-handled ] [ add-unhandled ] bi* ] 2tri ;
-
-: spill-new ( new existing -- )
- #! Our new interval will be used after the active interval
- #! with the most distant use location. Split the new
- #! interval, then process both parts of the new interval
- #! again.
- [ dup split-and-spill add-unhandled ] dip spill-existing ;
-
-: spill-existing? ( new existing -- ? )
- #! Test if 'new' will be used before 'existing'.
- over start>> '[ _ [ > ] find-use nip -1 or ] bi@ < ;
-
-: assign-blocked-register ( new -- )
- [ dup vreg>> active-intervals-for ] keep interval-to-spill
- 2dup spill-existing? [ spill-existing ] [ spill-new ] if ;
-
-: assign-free-register ( new registers -- )
- pop >>reg add-active ;
-
-: next-intersection ( new inactive -- n )
- 2drop 0 ;
-
-: intersecting-inactive ( new -- live-intervals )
- dup vreg>> inactive-intervals-for
- [ tuck next-intersection ] with { } map>assoc ;
-
-: fits-in-hole ( new pair -- )
- first reuse-register ;
-
-: split-before-use ( new pair -- before after )
- ! Find optimal split position
- second split-interval ;
-
-: assign-inactive-register ( new live-intervals -- )
- ! If there is an interval which is inactive for the entire lifetime
- ! if the new interval, reuse its vreg. Otherwise, split new so that
- ! the first half fits.
- sort-values last
- 2dup [ end>> ] [ second ] bi* < [
- fits-in-hole
- ] [
- [ split-before-use ] keep
- '[ _ fits-in-hole ] [ add-unhandled ] bi*
- ] if ;
+: no-free-registers? ( result -- ? )
+ second 0 = ; inline
: assign-register ( new -- )
- dup coalesce? [ coalesce ] [
- dup vreg>> free-registers-for [
- dup intersecting-inactive
- [ assign-blocked-register ]
- [ assign-inactive-register ]
- if-empty
- ] [ assign-free-register ]
- if-empty
- ] if ;
-
-! Main loop
-: reg-classes ( -- seq ) { int-regs double-float-regs } ; inline
-
-: reg-class-assoc ( quot -- assoc )
- [ reg-classes ] dip { } map>assoc ; inline
-
-: init-allocator ( registers -- )
- [ reverse >vector ] assoc-map free-registers set
- [ 0 ] reg-class-assoc spill-counts set
- <min-heap> unhandled-intervals set
- [ V{ } clone ] reg-class-assoc active-intervals set
- [ V{ } clone ] reg-class-assoc inactive-intervals set
- V{ } clone handled-intervals set
- -1 progress set ;
+ dup register-status {
+ { [ dup no-free-registers? ] [ drop assign-blocked-register ] }
+ { [ 2dup register-available? ] [ register-available ] }
+ [ drop assign-blocked-register ]
+ } cond ;
: handle-interval ( live-interval -- )
[
unhandled-intervals get [ handle-interval ] slurp-heap ;
: finish-allocation ( -- )
- ! Sanity check: all live intervals should've been processed
active-intervals inactive-intervals
[ get values [ handled-intervals get push-all ] each ] bi@ ;
: allocate-registers ( live-intervals machine-registers -- live-intervals )
- #! This modifies the input live-intervals.
init-allocator
init-unhandled
(allocate-registers)
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators fry hints kernel locals
+math sequences sets sorting splitting namespaces
+combinators.short-circuit compiler.utilities
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.allocation.splitting
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.allocation.spilling
+
+ERROR: bad-live-ranges interval ;
+
+: check-ranges ( live-interval -- )
+ check-allocation? get [
+ dup ranges>> [ [ from>> ] [ to>> ] bi <= ] all?
+ [ drop ] [ bad-live-ranges ] if
+ ] [ drop ] if ;
+
+: trim-before-ranges ( live-interval -- )
+ [ ranges>> ] [ uses>> last 1 + ] bi
+ [ '[ from>> _ <= ] filter-here ]
+ [ swap last (>>to) ]
+ 2bi ;
+
+: trim-after-ranges ( live-interval -- )
+ [ ranges>> ] [ uses>> first ] bi
+ [ '[ to>> _ >= ] filter-here ]
+ [ swap first (>>from) ]
+ 2bi ;
+
+: assign-spill ( live-interval -- )
+ dup vreg>> assign-spill-slot >>spill-to drop ;
+
+: spill-before ( before -- before/f )
+ ! If the interval does not have any usages before the spill location,
+ ! then it is the second child of an interval that was split. We reload
+ ! the value and let the resolve pass insert a split later.
+ dup uses>> empty? [ drop f ] [
+ {
+ [ ]
+ [ assign-spill ]
+ [ trim-before-ranges ]
+ [ compute-start/end ]
+ [ check-ranges ]
+ } cleave
+ ] if ;
+
+: assign-reload ( live-interval -- )
+ dup vreg>> assign-spill-slot >>reload-from drop ;
+
+: spill-after ( after -- after/f )
+ ! If the interval has no more usages after the spill location,
+ ! then it is the first child of an interval that was split. We
+ ! spill the value and let the resolve pass insert a reload later.
+ dup uses>> empty? [ drop f ] [
+ {
+ [ ]
+ [ assign-reload ]
+ [ trim-after-ranges ]
+ [ compute-start/end ]
+ [ check-ranges ]
+ } cleave
+ ] if ;
+
+: split-for-spill ( live-interval n -- before after )
+ split-interval [ spill-before ] [ spill-after ] bi* ;
+
+: find-use-position ( live-interval new -- n )
+ [ uses>> ] [ start>> '[ _ >= ] ] bi* find nip 1/0. or ;
+
+: find-use-positions ( live-intervals new assoc -- )
+ '[ [ _ find-use-position ] [ reg>> ] bi _ add-use-position ] each ;
+
+: active-positions ( new assoc -- )
+ [ [ vreg>> active-intervals-for ] keep ] dip
+ find-use-positions ;
+
+: inactive-positions ( new assoc -- )
+ [
+ [ vreg>> inactive-intervals-for ] keep
+ [ '[ _ intervals-intersect? ] filter ] keep
+ ] dip
+ find-use-positions ;
+
+: spill-status ( new -- use-pos )
+ H{ } clone
+ [ inactive-positions ] [ active-positions ] [ nip ] 2tri
+ >alist alist-max ;
+
+: spill-new? ( new pair -- ? )
+ [ uses>> first ] [ second ] bi* > ;
+
+: spill-new ( new pair -- )
+ drop spill-after add-unhandled ;
+
+: spill ( live-interval n -- )
+ split-for-spill
+ [ [ add-handled ] when* ]
+ [ [ add-unhandled ] when* ] bi* ;
+
+:: spill-intersecting-active ( new reg -- )
+ ! If there is an active interval using 'reg' (there should be at
+ ! most one) are split and spilled and removed from the inactive
+ ! set.
+ new vreg>> active-intervals-for [ [ reg>> reg = ] find swap dup ] keep
+ '[ _ delete-nth new start>> spill ] [ 2drop ] if ;
+
+:: spill-intersecting-inactive ( new reg -- )
+ ! Any inactive intervals using 'reg' are split and spilled
+ ! and removed from the inactive set.
+ new vreg>> inactive-intervals-for [
+ dup reg>> reg = [
+ dup new intervals-intersect? [
+ new start>> spill f
+ ] [ drop t ] if
+ ] [ drop t ] if
+ ] filter-here ;
+
+: spill-intersecting ( new reg -- )
+ ! Split and spill all active and inactive intervals
+ ! which intersect 'new' and use 'reg'.
+ [ spill-intersecting-active ]
+ [ spill-intersecting-inactive ]
+ 2bi ;
+
+: spill-available ( new pair -- )
+ ! A register would become fully available if all
+ ! active and inactive intervals using it were split
+ ! and spilled.
+ [ first spill-intersecting ] [ register-available ] 2bi ;
+
+: spill-partially-available ( new pair -- )
+ ! A register would be available for part of the new
+ ! interval's lifetime if all active and inactive intervals
+ ! using that register were split and spilled.
+ [ second 1 - split-for-spill [ add-unhandled ] when* ] keep
+ '[ _ spill-available ] when* ;
+
+: assign-blocked-register ( new -- )
+ dup spill-status {
+ { [ 2dup spill-new? ] [ spill-new ] }
+ { [ 2dup register-available? ] [ spill-available ] }
+ [ spill-partially-available ]
+ } cond ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators fry hints kernel locals
+math sequences sets sorting splitting namespaces
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.allocation.splitting
+
+: split-range ( live-range n -- before after )
+ [ [ from>> ] dip <live-range> ]
+ [ 1 + swap to>> <live-range> ]
+ 2bi ;
+
+: split-last-range? ( last n -- ? )
+ swap to>> <= ;
+
+: split-last-range ( before after last n -- before' after' )
+ split-range [ [ but-last ] dip suffix ] [ prefix ] bi-curry* bi* ;
+
+: split-ranges ( live-ranges n -- before after )
+ [ '[ from>> _ <= ] partition ]
+ [
+ [ over last ] dip 2dup split-last-range?
+ [ split-last-range ] [ 2drop ] if
+ ] bi ;
+
+: split-uses ( uses n -- before after )
+ '[ _ <= ] partition ;
+
+ERROR: splitting-too-early ;
+
+ERROR: splitting-too-late ;
+
+ERROR: splitting-atomic-interval ;
+
+: check-split ( live-interval n -- )
+ check-allocation? get [
+ [ [ start>> ] dip > [ splitting-too-early ] when ]
+ [ [ end>> ] dip <= [ splitting-too-late ] when ]
+ [ drop [ end>> ] [ start>> ] bi = [ splitting-atomic-interval ] when ]
+ 2tri
+ ] [ 2drop ] if ; inline
+
+: split-before ( before -- before' )
+ f >>spill-to ; inline
+
+: split-after ( after -- after' )
+ f >>reg f >>reload-from ; inline
+
+:: split-interval ( live-interval n -- before after )
+ live-interval n check-split
+ live-interval clone :> before
+ live-interval clone :> after
+ live-interval uses>> n split-uses before after [ (>>uses) ] bi-curry@ bi*
+ live-interval ranges>> n split-ranges before after [ (>>ranges) ] bi-curry@ bi*
+ before split-before
+ after split-after ;
+
+HINTS: split-interval live-interval object ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators cpu.architecture fry heaps
+kernel math math.order namespaces sequences vectors
+compiler.cfg compiler.cfg.registers
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.allocation.state
+
+! Start index of current live interval. We ensure that all
+! live intervals added to the unhandled set have a start index
+! strictly greater than this one. This ensures that we can catch
+! infinite loop situations. We also ensure that all live
+! intervals added to the handled set have an end index strictly
+! smaller than this one. This helps catch bugs.
+SYMBOL: progress
+
+: check-unhandled ( live-interval -- )
+ start>> progress get <= [ "check-unhandled" throw ] when ; inline
+
+: check-handled ( live-interval -- )
+ end>> progress get > [ "check-handled" throw ] when ; inline
+
+! Mapping from register classes to sequences of machine registers
+SYMBOL: registers
+
+! Vector of active live intervals
+SYMBOL: active-intervals
+
+: active-intervals-for ( vreg -- seq )
+ rep-of reg-class-of active-intervals get at ;
+
+: add-active ( live-interval -- )
+ dup vreg>> active-intervals-for push ;
+
+: delete-active ( live-interval -- )
+ dup vreg>> active-intervals-for delq ;
+
+: assign-free-register ( new registers -- )
+ pop >>reg add-active ;
+
+! Vector of inactive live intervals
+SYMBOL: inactive-intervals
+
+: inactive-intervals-for ( vreg -- seq )
+ rep-of reg-class-of inactive-intervals get at ;
+
+: add-inactive ( live-interval -- )
+ dup vreg>> inactive-intervals-for push ;
+
+: delete-inactive ( live-interval -- )
+ dup vreg>> inactive-intervals-for delq ;
+
+! Vector of handled live intervals
+SYMBOL: handled-intervals
+
+: add-handled ( live-interval -- )
+ [ check-handled ] [ handled-intervals get push ] bi ;
+
+: finished? ( n live-interval -- ? ) end>> swap < ;
+
+: finish ( n live-interval -- keep? )
+ nip add-handled f ;
+
+SYMBOL: check-allocation?
+
+ERROR: register-already-used live-interval ;
+
+: check-activate ( live-interval -- )
+ check-allocation? get [
+ dup [ reg>> ] [ vreg>> active-intervals-for [ reg>> ] map ] bi member?
+ [ register-already-used ] [ drop ] if
+ ] [ drop ] if ;
+
+: activate ( n live-interval -- keep? )
+ dup check-activate
+ nip add-active f ;
+
+: deactivate ( n live-interval -- keep? )
+ nip add-inactive f ;
+
+: don't-change ( n live-interval -- keep? ) 2drop t ;
+
+! Moving intervals between active and inactive sets
+: process-intervals ( n symbol quots -- )
+ ! symbol stores an alist mapping register classes to vectors
+ [ get values ] dip '[ [ _ cond ] with filter-here ] with each ; inline
+
+: deactivate-intervals ( n -- )
+ ! Any active intervals which have ended are moved to handled
+ ! Any active intervals which cover the current position
+ ! are moved to inactive
+ active-intervals {
+ { [ 2dup finished? ] [ finish ] }
+ { [ 2dup covers? not ] [ deactivate ] }
+ [ don't-change ]
+ } process-intervals ;
+
+: activate-intervals ( n -- )
+ ! Any inactive intervals which have ended are moved to handled
+ ! Any inactive intervals which do not cover the current position
+ ! are moved to active
+ inactive-intervals {
+ { [ 2dup finished? ] [ finish ] }
+ { [ 2dup covers? ] [ activate ] }
+ [ don't-change ]
+ } process-intervals ;
+
+! Minheap of live intervals which still need a register allocation
+SYMBOL: unhandled-intervals
+
+: add-unhandled ( live-interval -- )
+ [ check-unhandled ]
+ [ dup start>> unhandled-intervals get heap-push ]
+ bi ;
+
+: reg-class-assoc ( quot -- assoc )
+ [ reg-classes ] dip { } map>assoc ; inline
+
+: next-spill-slot ( rep -- n )
+ rep-size cfg get
+ [ swap [ align dup ] [ + ] bi ] change-spill-area-size drop ;
+
+! Mapping from vregs to spill slots
+SYMBOL: spill-slots
+
+: assign-spill-slot ( vreg -- n )
+ spill-slots get [ rep-of next-spill-slot ] cache ;
+
+: init-allocator ( registers -- )
+ registers set
+ <min-heap> unhandled-intervals set
+ [ V{ } clone ] reg-class-assoc active-intervals set
+ [ V{ } clone ] reg-class-assoc inactive-intervals set
+ V{ } clone handled-intervals set
+ cfg get 0 >>spill-area-size drop
+ H{ } clone spill-slots set
+ -1 progress set ;
+
+: init-unhandled ( live-intervals -- )
+ [ [ start>> ] keep ] { } map>assoc
+ unhandled-intervals get heap-push-all ;
+
+! A utility used by register-status and spill-status words
+: free-positions ( new -- assoc )
+ vreg>> rep-of reg-class-of registers get at [ 1/0. ] H{ } map>assoc ;
+
+: add-use-position ( n reg assoc -- ) [ [ min ] when* ] change-at ;
+
+: register-available? ( new result -- ? )
+ [ end>> ] [ second ] bi* < ; inline
+
+: register-available ( new result -- )
+ first >>reg add-active ;
+++ /dev/null
-USING: compiler.cfg.linear-scan.assignment tools.test ;
-IN: compiler.cfg.linear-scan.assignment.tests
-
-
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel math assocs namespaces sequences heaps
-fry make combinators
+fry make combinators sets locals arrays
cpu.architecture
+compiler.cfg
compiler.cfg.def-use
+compiler.cfg.liveness
compiler.cfg.registers
compiler.cfg.instructions
+compiler.cfg.renaming.functor
+compiler.cfg.linearization.order
+compiler.cfg.linear-scan.allocation
+compiler.cfg.linear-scan.allocation.state
compiler.cfg.linear-scan.live-intervals ;
IN: compiler.cfg.linear-scan.assignment
-! A vector of live intervals. There is linear searching involved
-! but since we never have too many machine registers (around 30
-! at most) and we probably won't have that many live at any one
-! time anyway, it is not a problem to check each element.
-TUPLE: active-intervals seq ;
+! This contains both active and inactive intervals; any interval
+! such that start <= insn# <= end is in this set.
+SYMBOL: pending-interval-heap
+SYMBOL: pending-interval-assoc
-: add-active ( live-interval -- )
- active-intervals get seq>> push ;
+: add-pending ( live-interval -- )
+ [ dup end>> pending-interval-heap get heap-push ]
+ [ [ reg>> ] [ vreg>> ] bi pending-interval-assoc get set-at ]
+ bi ;
-: lookup-register ( vreg -- reg )
- active-intervals get seq>> [ vreg>> = ] with find nip reg>> ;
+: remove-pending ( live-interval -- )
+ vreg>> pending-interval-assoc get delete-at ;
! Minheap of live intervals which still need a register allocation
SYMBOL: unhandled-intervals
: init-unhandled ( live-intervals -- )
[ add-unhandled ] each ;
+! Mapping from basic blocks to values which are live at the start
+SYMBOL: register-live-ins
+
+! Mapping from basic blocks to values which are live at the end
+SYMBOL: register-live-outs
+
+: init-assignment ( live-intervals -- )
+ <min-heap> pending-interval-heap set
+ H{ } clone pending-interval-assoc set
+ <min-heap> unhandled-intervals set
+ H{ } clone register-live-ins set
+ H{ } clone register-live-outs set
+ init-unhandled ;
+
: insert-spill ( live-interval -- )
- [ reg>> ] [ vreg>> reg-class>> ] [ spill-to>> ] tri
- dup [ _spill ] [ 3drop ] if ;
+ [ reg>> ] [ vreg>> rep-of ] [ spill-to>> ] tri _spill ;
+
+: handle-spill ( live-interval -- )
+ dup spill-to>> [ insert-spill ] [ drop ] if ;
+
+: expire-interval ( live-interval -- )
+ [ remove-pending ] [ handle-spill ] bi ;
+
+: (expire-old-intervals) ( n heap -- )
+ dup heap-empty? [ 2drop ] [
+ 2dup heap-peek nip <= [ 2drop ] [
+ dup heap-pop drop expire-interval
+ (expire-old-intervals)
+ ] if
+ ] if ;
: expire-old-intervals ( n -- )
- active-intervals get
- [ swap '[ end>> _ = ] partition ] change-seq drop
- [ insert-spill ] each ;
+ pending-interval-heap get (expire-old-intervals) ;
: insert-reload ( live-interval -- )
- [ reg>> ] [ vreg>> reg-class>> ] [ reload-from>> ] tri
- dup [ _reload ] [ 3drop ] if ;
+ [ reg>> ] [ vreg>> rep-of ] [ reload-from>> ] tri _reload ;
-: activate-new-intervals ( n -- )
- #! Any live intervals which start on the current instruction
- #! are added to the active set.
- unhandled-intervals get dup heap-empty? [ 2drop ] [
- 2dup heap-peek drop start>> = [
- heap-pop drop [ add-active ] [ insert-reload ] bi
- activate-new-intervals
+: handle-reload ( live-interval -- )
+ dup reload-from>> [ insert-reload ] [ drop ] if ;
+
+: activate-interval ( live-interval -- )
+ [ add-pending ] [ handle-reload ] bi ;
+
+: (activate-new-intervals) ( n heap -- )
+ dup heap-empty? [ 2drop ] [
+ 2dup heap-peek nip = [
+ dup heap-pop drop activate-interval
+ (activate-new-intervals)
] [ 2drop ] if
] if ;
-GENERIC: assign-before ( insn -- )
+: activate-new-intervals ( n -- )
+ unhandled-intervals get (activate-new-intervals) ;
+
+: prepare-insn ( n -- )
+ [ expire-old-intervals ] [ activate-new-intervals ] bi ;
-GENERIC: assign-after ( insn -- )
+GENERIC: assign-registers-in-insn ( insn -- )
-: all-vregs ( insn -- vregs )
- [ defs-vregs ] [ temp-vregs ] [ uses-vregs ] tri 3append ;
+: vreg>reg ( vreg -- reg ) pending-interval-assoc get at ;
-M: vreg-insn assign-before
- active-intervals get seq>> over all-vregs '[ vreg>> _ member? ] filter
- [ [ vreg>> ] [ reg>> ] bi ] { } map>assoc
- >>regs drop ;
+RENAMING: assign [ vreg>reg ] [ vreg>reg ] [ vreg>reg ]
-M: insn assign-before drop ;
+M: vreg-insn assign-registers-in-insn
+ [ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ;
-: compute-live-registers ( -- regs )
- active-intervals get seq>> [ [ vreg>> ] [ reg>> ] bi ] { } map>assoc ;
+! TODO: needs tagged-rep
-: compute-live-spill-slots ( -- spill-slots )
- unhandled-intervals get
- heap-values [ reload-from>> ] filter
- [ [ vreg>> ] [ reload-from>> ] bi ] { } map>assoc ;
+: trace-on-gc ( assoc -- assoc' )
+ ! When a GC occurs, virtual registers which contain tagged data
+ ! are traced by the GC. Outputs a sequence physical registers.
+ [ drop rep-of int-rep eq? ] { } assoc-filter-as values ;
-M: ##gc assign-after
- compute-live-registers >>live-registers
- compute-live-spill-slots >>live-spill-slots
+: spill-on-gc? ( vreg reg -- ? )
+ [ rep-of int-rep? not ] [ spill-slot? not ] bi* and ;
+
+: spill-on-gc ( assoc -- assoc' )
+ ! When a GC occurs, virtual registers which contain untagged data,
+ ! and are stored in physical registers, are saved to their spill
+ ! slots. Outputs sequence of triples:
+ ! - physical register
+ ! - spill slot
+ ! - representation
+ [
+ [
+ 2dup spill-on-gc?
+ [ swap [ assign-spill-slot ] [ rep-of ] bi 3array , ] [ 2drop ] if
+ ] assoc-each
+ ] { } make ;
+
+M: ##gc assign-registers-in-insn
+ ! Since ##gc is always the first instruction in a block, the set of
+ ! values live at the ##gc is just live-in.
+ dup call-next-method
+ basic-block get register-live-ins get at
+ [ trace-on-gc >>tagged-values ] [ spill-on-gc >>data-values ] bi
drop ;
-M: insn assign-after drop ;
+M: insn assign-registers-in-insn drop ;
-: <active-intervals> ( -- obj )
- V{ } clone active-intervals boa ;
+: compute-live-values ( vregs -- assoc )
+ ! If a live vreg is not in active or inactive, then it must have been
+ ! spilled.
+ dup assoc-empty? [
+ pending-interval-assoc get
+ '[ _ ?at [ ] [ spill-slots get at <spill-slot> ] if ] assoc-map
+ ] unless ;
-: init-assignment ( live-intervals -- )
- <active-intervals> active-intervals set
- <min-heap> unhandled-intervals set
- init-unhandled ;
+: begin-block ( bb -- )
+ dup basic-block set
+ dup block-from activate-new-intervals
+ [ live-in compute-live-values ] keep
+ register-live-ins get set-at ;
-: assign-registers-in-block ( bb -- )
- [
+: end-block ( bb -- )
+ [ live-out compute-live-values ] keep
+ register-live-outs get set-at ;
+
+ERROR: bad-vreg vreg ;
+
+: vreg-at-start ( vreg bb -- state )
+ register-live-ins get at ?at [ bad-vreg ] unless ;
+
+: vreg-at-end ( vreg bb -- state )
+ register-live-outs get at ?at [ bad-vreg ] unless ;
+
+:: assign-registers-in-block ( bb -- )
+ bb [
[
+ bb begin-block
[
{
- [ insn#>> activate-new-intervals ]
- [ assign-before ]
+ [ insn#>> 1 - prepare-insn ]
+ [ insn#>> prepare-insn ]
+ [ assign-registers-in-insn ]
[ , ]
- [ insn#>> expire-old-intervals ]
- [ assign-after ]
} cleave
] each
+ bb end-block
] V{ } make
] change-instructions drop ;
-: assign-registers ( rpo live-intervals -- )
- init-assignment
- [ assign-registers-in-block ] each ;
+: assign-registers ( live-intervals cfg -- )
+ [ init-assignment ] dip
+ linearization-order [ assign-registers-in-block ] each ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel sequences sets arrays math strings fry
-prettyprint compiler.cfg.linear-scan.live-intervals
-compiler.cfg.linear-scan.allocation ;
+namespaces prettyprint compiler.cfg.linear-scan.live-intervals
+compiler.cfg.linear-scan.allocation compiler.cfg assocs ;
IN: compiler.cfg.linear-scan.debugger
-: check-assigned ( live-intervals -- )
- [
- reg>>
- [ "Not all intervals have registers" throw ] unless
- ] each ;
-
-: split-children ( live-interval -- seq )
- dup split-before>> [
- [ split-before>> ] [ split-after>> ] bi
- [ split-children ] bi@
- append
- ] [ 1array ] if ;
-
: check-linear-scan ( live-intervals machine-registers -- )
- [ [ clone ] map ] dip allocate-registers
- [ split-children ] map concat check-assigned ;
+ [
+ [ clone ] map dup [ [ vreg>> ] keep ] H{ } map>assoc
+ live-intervals set
+ ] dip
+ allocate-registers drop ;
: picture ( uses -- str )
dup last 1 + CHAR: space <string>
: interval-picture ( interval -- str )
[ uses>> picture ]
- [ copy-from>> unparse ]
[ vreg>> unparse ]
- tri 3array ;
+ bi 2array ;
: live-intervals. ( seq -- )
[ interval-picture ] map simple-table. ;
IN: compiler.cfg.linear-scan.tests
USING: tools.test random sorting sequences sets hashtables assocs
-kernel fry arrays splitting namespaces math accessors vectors
-math.order grouping
+kernel fry arrays splitting namespaces math accessors vectors locals
+math.order grouping strings strings.private classes layouts
cpu.architecture
compiler.cfg
compiler.cfg.optimizer
compiler.cfg.instructions
compiler.cfg.registers
+compiler.cfg.predecessors
+compiler.cfg.rpo
+compiler.cfg.linearization
+compiler.cfg.debugger
+compiler.cfg.def-use
+compiler.cfg.comparisons
compiler.cfg.linear-scan
+compiler.cfg.linear-scan.numbering
compiler.cfg.linear-scan.live-intervals
compiler.cfg.linear-scan.allocation
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.allocation.splitting
+compiler.cfg.linear-scan.allocation.spilling
compiler.cfg.linear-scan.debugger ;
+check-allocation? on
+check-numbering? on
+
[
{ T{ live-range f 1 10 } T{ live-range f 15 15 } }
{ T{ live-range f 16 20 } }
] unit-test
[
- { }
- { T{ live-range f 1 10 } }
-] [
{ T{ live-range f 1 10 } } 0 split-ranges
-] unit-test
+] must-fail
[
{ T{ live-range f 0 0 } }
{ T{ live-range f 0 5 } } 0 split-ranges
] unit-test
-[ 7 ] [
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 2 } } }
- { start 0 }
- { end 10 }
- { uses V{ 0 1 3 7 10 } }
- }
- 4 [ >= ] find-use nip
-] unit-test
-
-[ 4 ] [
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 2 } } }
- { start 0 }
- { end 10 }
- { uses V{ 0 1 3 4 10 } }
- }
- 4 [ >= ] find-use nip
-] unit-test
+cfg new 0 >>spill-area-size cfg set
+H{ } spill-slots set
-[ f ] [
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 2 } } }
- { start 0 }
- { end 10 }
- { uses V{ 0 1 3 4 10 } }
- }
- 100 [ >= ] find-use nip
-] unit-test
+H{
+ { 1 single-float-rep }
+ { 2 single-float-rep }
+ { 3 single-float-rep }
+} representations set
[
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+ { vreg 1 }
{ start 0 }
- { end 1 }
+ { end 2 }
{ uses V{ 0 1 } }
- { ranges V{ T{ live-range f 0 1 } } }
+ { ranges V{ T{ live-range f 0 2 } } }
+ { spill-to 0 }
}
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+ { vreg 1 }
{ start 5 }
{ end 5 }
{ uses V{ 5 } }
{ ranges V{ T{ live-range f 5 5 } } }
+ { reload-from 0 }
}
] [
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+ { vreg 1 }
{ start 0 }
{ end 5 }
{ uses V{ 0 1 5 } }
{ ranges V{ T{ live-range f 0 5 } } }
- } 2 split-interval
+ } 2 split-for-spill
] unit-test
[
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 0 }
- { end 0 }
- { uses V{ 0 } }
- { ranges V{ T{ live-range f 0 0 } } }
+ { vreg 2 }
+ { start 0 }
+ { end 1 }
+ { uses V{ 0 } }
+ { ranges V{ T{ live-range f 0 1 } } }
+ { spill-to 4 }
}
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 1 }
- { end 5 }
- { uses V{ 1 5 } }
- { ranges V{ T{ live-range f 1 5 } } }
+ { vreg 2 }
+ { start 1 }
+ { end 5 }
+ { uses V{ 1 5 } }
+ { ranges V{ T{ live-range f 1 5 } } }
+ { reload-from 4 }
}
] [
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 0 }
- { end 5 }
- { uses V{ 0 1 5 } }
- { ranges V{ T{ live-range f 0 5 } } }
- } 0 split-interval
+ { vreg 2 }
+ { start 0 }
+ { end 5 }
+ { uses V{ 0 1 5 } }
+ { ranges V{ T{ live-range f 0 5 } } }
+ } 0 split-for-spill
] unit-test
[
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 3 }
- { end 10 }
- { uses V{ 3 10 } }
+ { vreg 3 }
+ { start 0 }
+ { end 1 }
+ { uses V{ 0 } }
+ { ranges V{ T{ live-range f 0 1 } } }
+ { spill-to 8 }
+ }
+ T{ live-interval
+ { vreg 3 }
+ { start 20 }
+ { end 30 }
+ { uses V{ 20 30 } }
+ { ranges V{ T{ live-range f 20 30 } } }
+ { reload-from 8 }
}
] [
+ T{ live-interval
+ { vreg 3 }
+ { start 0 }
+ { end 30 }
+ { uses V{ 0 20 30 } }
+ { ranges V{ T{ live-range f 0 8 } T{ live-range f 10 18 } T{ live-range f 20 30 } } }
+ } 10 split-for-spill
+] unit-test
+
+H{
+ { 1 int-rep }
+ { 2 int-rep }
+ { 3 int-rep }
+} representations set
+
+[
{
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 1 }
- { end 15 }
- { uses V{ 1 3 7 10 15 } }
- }
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 3 }
- { end 8 }
- { uses V{ 3 4 8 } }
- }
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 3 }
- { end 10 }
- { uses V{ 3 10 } }
- }
+ 3
+ 10
}
+] [
+ H{
+ { int-regs
+ V{
+ T{ live-interval
+ { vreg 1 }
+ { reg 1 }
+ { start 1 }
+ { end 15 }
+ { uses V{ 1 3 7 10 15 } }
+ }
+ T{ live-interval
+ { vreg 2 }
+ { reg 2 }
+ { start 3 }
+ { end 8 }
+ { uses V{ 3 4 8 } }
+ }
+ T{ live-interval
+ { vreg 3 }
+ { reg 3 }
+ { start 3 }
+ { end 10 }
+ { uses V{ 3 10 } }
+ }
+ }
+ }
+ } active-intervals set
+ H{ } inactive-intervals set
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+ { vreg 1 }
{ start 5 }
{ end 5 }
{ uses V{ 5 } }
}
- interval-to-spill
-] unit-test
-
-[ t ] [
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 5 }
- { end 15 }
- { uses V{ 5 10 15 } }
- }
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 1 }
- { end 20 }
- { uses V{ 1 20 } }
- }
- spill-existing?
+ spill-status
] unit-test
-[ f ] [
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 5 }
- { end 15 }
- { uses V{ 5 10 15 } }
- }
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 1 }
- { end 20 }
- { uses V{ 1 7 20 } }
+[
+ {
+ 1
+ 1/0.
}
- spill-existing?
-] unit-test
-
-[ t ] [
+] [
+ H{
+ { int-regs
+ V{
+ T{ live-interval
+ { vreg 1 }
+ { reg 1 }
+ { start 1 }
+ { end 15 }
+ { uses V{ 1 } }
+ }
+ T{ live-interval
+ { vreg 2 }
+ { reg 2 }
+ { start 3 }
+ { end 8 }
+ { uses V{ 3 8 } }
+ }
+ }
+ }
+ } active-intervals set
+ H{ } inactive-intervals set
T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
+ { vreg 3 }
{ start 5 }
{ end 5 }
{ uses V{ 5 } }
}
- T{ live-interval
- { vreg T{ vreg { reg-class int-regs } { n 1 } } }
- { start 1 }
- { end 20 }
- { uses V{ 1 7 20 } }
- }
- spill-existing?
+ spill-status
] unit-test
+H{ { 1 int-rep } { 2 int-rep } } representations set
+
[ ] [
{
T{ live-interval
- { vreg T{ vreg { n 1 } { reg-class int-regs } } }
+ { vreg 1 }
{ start 0 }
{ end 100 }
{ uses V{ 0 100 } }
[ ] [
{
T{ live-interval
- { vreg T{ vreg { n 1 } { reg-class int-regs } } }
+ { vreg 1 }
{ start 0 }
{ end 10 }
{ uses V{ 0 10 } }
{ ranges V{ T{ live-range f 0 10 } } }
}
T{ live-interval
- { vreg T{ vreg { n 2 } { reg-class int-regs } } }
+ { vreg 2 }
{ start 11 }
{ end 20 }
{ uses V{ 11 20 } }
[ ] [
{
T{ live-interval
- { vreg T{ vreg { n 1 } { reg-class int-regs } } }
+ { vreg 1 }
{ start 0 }
{ end 100 }
{ uses V{ 0 100 } }
{ ranges V{ T{ live-range f 0 100 } } }
}
T{ live-interval
- { vreg T{ vreg { n 2 } { reg-class int-regs } } }
+ { vreg 2 }
{ start 30 }
{ end 60 }
{ uses V{ 30 60 } }
[ ] [
{
T{ live-interval
- { vreg T{ vreg { n 1 } { reg-class int-regs } } }
+ { vreg 1 }
{ start 0 }
{ end 100 }
{ uses V{ 0 100 } }
{ ranges V{ T{ live-range f 0 100 } } }
}
T{ live-interval
- { vreg T{ vreg { n 2 } { reg-class int-regs } } }
+ { vreg 2 }
{ start 30 }
{ end 200 }
{ uses V{ 30 200 } }
[
{
T{ live-interval
- { vreg T{ vreg { n 1 } { reg-class int-regs } } }
+ { vreg 1 }
{ start 0 }
{ end 100 }
{ uses V{ 0 100 } }
{ ranges V{ T{ live-range f 0 100 } } }
}
T{ live-interval
- { vreg T{ vreg { n 2 } { reg-class int-regs } } }
+ { vreg 2 }
{ start 30 }
{ end 100 }
{ uses V{ 30 100 } }
check-linear-scan
] must-fail
-SYMBOL: available
-
-SYMBOL: taken
-
-SYMBOL: max-registers
-
-SYMBOL: max-insns
-
-SYMBOL: max-uses
-
-: not-taken ( -- n )
- available get keys dup empty? [ "Oops" throw ] when
- random
- dup taken get nth 1 + max-registers get = [
- dup available get delete-at
- ] [
- dup taken get [ 1 + ] change-nth
- ] if ;
-
-: random-live-intervals ( num-intervals max-uses max-registers max-insns -- seq )
- [
- max-insns set
- max-registers set
- max-uses set
- max-insns get [ 0 ] replicate taken set
- max-insns get [ dup ] H{ } map>assoc available set
- [
- \ live-interval new
- swap int-regs swap vreg boa >>vreg
- max-uses get random 2 max [ not-taken ] replicate natural-sort
- [ >>uses ] [ first >>start ] bi
- dup uses>> last >>end
- dup [ start>> ] [ end>> ] bi <live-range> 1vector >>ranges
- ] map
- ] with-scope ;
-
-: random-test ( num-intervals max-uses max-registers max-insns -- )
- over [ random-live-intervals ] dip int-regs associate check-linear-scan ;
-
-[ ] [ 30 2 1 60 random-test ] unit-test
-[ ] [ 60 2 2 60 random-test ] unit-test
-[ ] [ 80 2 3 200 random-test ] unit-test
-[ ] [ 70 2 5 30 random-test ] unit-test
-[ ] [ 60 2 6 30 random-test ] unit-test
-[ ] [ 1 2 10 10 random-test ] unit-test
+! Problem with spilling intervals with no more usages after the spill location
+H{
+ { 1 int-rep }
+ { 2 int-rep }
+ { 3 int-rep }
+ { 4 int-rep }
+ { 5 int-rep }
+} representations set
-[ ] [ 10 4 2 60 random-test ] unit-test
-[ ] [ 10 20 2 400 random-test ] unit-test
-[ ] [ 10 20 4 300 random-test ] unit-test
-
-USING: math.private compiler.cfg.debugger ;
-
-[ ] [
- [ float+ float>fixnum 3 fixnum*fast ]
- test-cfg first optimize-cfg linear-scan drop
-] unit-test
-
-: fake-live-ranges ( seq -- seq' )
- [
- clone dup [ start>> ] [ end>> ] bi <live-range> 1vector >>ranges
- ] map ;
-
-! Coalescing interacted badly with splitting
[ ] [
{
T{ live-interval
- { vreg V int-regs 70 }
- { start 14 }
- { end 17 }
- { uses V{ 14 15 16 17 } }
- { copy-from V int-regs 67 }
- }
- T{ live-interval
- { vreg V int-regs 67 }
- { start 13 }
- { end 14 }
- { uses V{ 13 14 } }
- }
- T{ live-interval
- { vreg V int-regs 30 }
- { start 4 }
- { end 18 }
- { uses V{ 4 12 16 17 18 } }
+ { vreg 1 }
+ { start 0 }
+ { end 20 }
+ { uses V{ 0 10 20 } }
+ { ranges V{ T{ live-range f 0 2 } T{ live-range f 10 20 } } }
}
T{ live-interval
- { vreg V int-regs 27 }
- { start 3 }
- { end 13 }
- { uses V{ 3 7 13 } }
+ { vreg 2 }
+ { start 0 }
+ { end 20 }
+ { uses V{ 0 10 20 } }
+ { ranges V{ T{ live-range f 0 2 } T{ live-range f 10 20 } } }
}
T{ live-interval
- { vreg V int-regs 59 }
- { start 10 }
- { end 18 }
- { uses V{ 10 11 12 18 } }
- { copy-from V int-regs 56 }
+ { vreg 3 }
+ { start 4 }
+ { end 8 }
+ { uses V{ 6 } }
+ { ranges V{ T{ live-range f 4 8 } } }
}
T{ live-interval
- { vreg V int-regs 60 }
- { start 12 }
- { end 17 }
- { uses V{ 12 17 } }
+ { vreg 4 }
+ { start 4 }
+ { end 8 }
+ { uses V{ 8 } }
+ { ranges V{ T{ live-range f 4 8 } } }
}
+
+ ! This guy will invoke the 'spill partially available' code path
T{ live-interval
- { vreg V int-regs 56 }
- { start 9 }
- { end 10 }
- { uses V{ 9 10 } }
+ { vreg 5 }
+ { start 4 }
+ { end 8 }
+ { uses V{ 8 } }
+ { ranges V{ T{ live-range f 4 8 } } }
}
- } fake-live-ranges
- { { int-regs { 0 1 2 3 } } }
- allocate-registers drop
+ }
+ H{ { int-regs { "A" "B" } } }
+ check-linear-scan
] unit-test
+! Test spill-new code path
+
[ ] [
{
T{ live-interval
- { vreg V int-regs 3687168 }
- { start 106 }
- { end 112 }
- { uses V{ 106 112 } }
- }
- T{ live-interval
- { vreg V int-regs 3687169 }
- { start 107 }
- { end 113 }
- { uses V{ 107 113 } }
- }
- T{ live-interval
- { vreg V int-regs 3687727 }
- { start 190 }
- { end 198 }
- { uses V{ 190 195 198 } }
- }
- T{ live-interval
- { vreg V int-regs 3686445 }
- { start 43 }
- { end 44 }
- { uses V{ 43 44 } }
- }
- T{ live-interval
- { vreg V int-regs 3686195 }
- { start 5 }
- { end 11 }
- { uses V{ 5 11 } }
- }
- T{ live-interval
- { vreg V int-regs 3686449 }
- { start 44 }
- { end 56 }
- { uses V{ 44 45 45 46 56 } }
- { copy-from V int-regs 3686445 }
- }
- T{ live-interval
- { vreg V int-regs 3686198 }
- { start 8 }
- { end 10 }
- { uses V{ 8 9 10 } }
- }
- T{ live-interval
- { vreg V int-regs 3686454 }
- { start 46 }
- { end 49 }
- { uses V{ 46 47 47 49 } }
- { copy-from V int-regs 3686449 }
- }
- T{ live-interval
- { vreg V int-regs 3686196 }
- { start 6 }
- { end 12 }
- { uses V{ 6 12 } }
- }
- T{ live-interval
- { vreg V int-regs 3686197 }
- { start 7 }
- { end 14 }
- { uses V{ 7 13 14 } }
- }
- T{ live-interval
- { vreg V int-regs 3686455 }
- { start 48 }
- { end 51 }
- { uses V{ 48 51 } }
- }
- T{ live-interval
- { vreg V int-regs 3686463 }
- { start 52 }
- { end 53 }
- { uses V{ 52 53 } }
- }
- T{ live-interval
- { vreg V int-regs 3686460 }
- { start 49 }
- { end 52 }
- { uses V{ 49 50 50 52 } }
- { copy-from V int-regs 3686454 }
- }
- T{ live-interval
- { vreg V int-regs 3686461 }
- { start 51 }
- { end 71 }
- { uses V{ 51 52 64 68 71 } }
- }
- T{ live-interval
- { vreg V int-regs 3686464 }
- { start 53 }
- { end 54 }
- { uses V{ 53 54 } }
- }
- T{ live-interval
- { vreg V int-regs 3686465 }
- { start 54 }
- { end 76 }
- { uses V{ 54 55 55 76 } }
- { copy-from V int-regs 3686464 }
- }
- T{ live-interval
- { vreg V int-regs 3686470 }
- { start 58 }
- { end 60 }
- { uses V{ 58 59 59 60 } }
- { copy-from V int-regs 3686469 }
- }
- T{ live-interval
- { vreg V int-regs 3686469 }
- { start 56 }
- { end 58 }
- { uses V{ 56 57 57 58 } }
- { copy-from V int-regs 3686449 }
- }
- T{ live-interval
- { vreg V int-regs 3686473 }
- { start 60 }
- { end 62 }
- { uses V{ 60 61 61 62 } }
- { copy-from V int-regs 3686470 }
- }
- T{ live-interval
- { vreg V int-regs 3686479 }
- { start 62 }
- { end 64 }
- { uses V{ 62 63 63 64 } }
- { copy-from V int-regs 3686473 }
- }
- T{ live-interval
- { vreg V int-regs 3686735 }
- { start 78 }
- { end 96 }
- { uses V{ 78 79 79 96 } }
- { copy-from V int-regs 3686372 }
- }
- T{ live-interval
- { vreg V int-regs 3686482 }
- { start 64 }
- { end 65 }
- { uses V{ 64 65 } }
- }
- T{ live-interval
- { vreg V int-regs 3686483 }
- { start 65 }
- { end 66 }
- { uses V{ 65 66 } }
- }
- T{ live-interval
- { vreg V int-regs 3687510 }
- { start 168 }
- { end 171 }
- { uses V{ 168 171 } }
- }
- T{ live-interval
- { vreg V int-regs 3687511 }
- { start 169 }
- { end 176 }
- { uses V{ 169 176 } }
- }
- T{ live-interval
- { vreg V int-regs 3686484 }
- { start 66 }
- { end 75 }
- { uses V{ 66 67 67 75 } }
- { copy-from V int-regs 3686483 }
- }
- T{ live-interval
- { vreg V int-regs 3687509 }
- { start 162 }
- { end 163 }
- { uses V{ 162 163 } }
- }
- T{ live-interval
- { vreg V int-regs 3686491 }
- { start 68 }
- { end 69 }
- { uses V{ 68 69 } }
- }
- T{ live-interval
- { vreg V int-regs 3687512 }
- { start 170 }
- { end 178 }
- { uses V{ 170 177 178 } }
- }
- T{ live-interval
- { vreg V int-regs 3687515 }
- { start 172 }
- { end 173 }
- { uses V{ 172 173 } }
- }
- T{ live-interval
- { vreg V int-regs 3686492 }
- { start 69 }
- { end 74 }
- { uses V{ 69 70 70 74 } }
- { copy-from V int-regs 3686491 }
- }
- T{ live-interval
- { vreg V int-regs 3687778 }
- { start 202 }
- { end 208 }
- { uses V{ 202 208 } }
- }
- T{ live-interval
- { vreg V int-regs 3686499 }
- { start 71 }
- { end 72 }
- { uses V{ 71 72 } }
- }
- T{ live-interval
- { vreg V int-regs 3687520 }
- { start 174 }
- { end 175 }
- { uses V{ 174 175 } }
- }
- T{ live-interval
- { vreg V int-regs 3687779 }
- { start 203 }
- { end 209 }
- { uses V{ 203 209 } }
- }
- T{ live-interval
- { vreg V int-regs 3687782 }
- { start 206 }
- { end 207 }
- { uses V{ 206 207 } }
- }
- T{ live-interval
- { vreg V int-regs 3686503 }
- { start 74 }
- { end 75 }
- { uses V{ 74 75 } }
- }
- T{ live-interval
- { vreg V int-regs 3686500 }
- { start 72 }
- { end 74 }
- { uses V{ 72 73 73 74 } }
- { copy-from V int-regs 3686499 }
- }
- T{ live-interval
- { vreg V int-regs 3687780 }
- { start 204 }
- { end 210 }
- { uses V{ 204 210 } }
- }
- T{ live-interval
- { vreg V int-regs 3686506 }
- { start 75 }
- { end 76 }
- { uses V{ 75 76 } }
- }
- T{ live-interval
- { vreg V int-regs 3687530 }
- { start 185 }
- { end 192 }
- { uses V{ 185 192 } }
- }
- T{ live-interval
- { vreg V int-regs 3687528 }
- { start 183 }
- { end 198 }
- { uses V{ 183 198 } }
- }
- T{ live-interval
- { vreg V int-regs 3687529 }
- { start 184 }
- { end 197 }
- { uses V{ 184 197 } }
- }
- T{ live-interval
- { vreg V int-regs 3687781 }
- { start 205 }
- { end 211 }
- { uses V{ 205 211 } }
- }
- T{ live-interval
- { vreg V int-regs 3687535 }
- { start 187 }
- { end 194 }
- { uses V{ 187 194 } }
- }
- T{ live-interval
- { vreg V int-regs 3686252 }
- { start 9 }
- { end 17 }
- { uses V{ 9 15 17 } }
- }
- T{ live-interval
- { vreg V int-regs 3686509 }
- { start 76 }
- { end 90 }
- { uses V{ 76 87 90 } }
- }
- T{ live-interval
- { vreg V int-regs 3687532 }
- { start 186 }
- { end 196 }
- { uses V{ 186 196 } }
- }
- T{ live-interval
- { vreg V int-regs 3687538 }
- { start 188 }
- { end 193 }
- { uses V{ 188 193 } }
- }
- T{ live-interval
- { vreg V int-regs 3687827 }
- { start 217 }
- { end 219 }
- { uses V{ 217 219 } }
- }
- T{ live-interval
- { vreg V int-regs 3687825 }
- { start 215 }
- { end 218 }
- { uses V{ 215 216 218 } }
- }
- T{ live-interval
- { vreg V int-regs 3687831 }
- { start 218 }
- { end 219 }
- { uses V{ 218 219 } }
- }
- T{ live-interval
- { vreg V int-regs 3686296 }
- { start 16 }
- { end 18 }
- { uses V{ 16 18 } }
- }
- T{ live-interval
- { vreg V int-regs 3686302 }
- { start 29 }
- { end 31 }
- { uses V{ 29 31 } }
- }
- T{ live-interval
- { vreg V int-regs 3687838 }
- { start 231 }
- { end 232 }
- { uses V{ 231 232 } }
- }
- T{ live-interval
- { vreg V int-regs 3686300 }
- { start 26 }
- { end 27 }
- { uses V{ 26 27 } }
- }
- T{ live-interval
- { vreg V int-regs 3686301 }
- { start 27 }
- { end 30 }
- { uses V{ 27 28 28 30 } }
- { copy-from V int-regs 3686300 }
- }
- T{ live-interval
- { vreg V int-regs 3686306 }
- { start 37 }
- { end 93 }
- { uses V{ 37 82 93 } }
- }
- T{ live-interval
- { vreg V int-regs 3686307 }
- { start 38 }
- { end 88 }
- { uses V{ 38 85 88 } }
- }
- T{ live-interval
- { vreg V int-regs 3687837 }
- { start 222 }
- { end 223 }
- { uses V{ 222 223 } }
- }
- T{ live-interval
- { vreg V int-regs 3686305 }
- { start 36 }
- { end 81 }
- { uses V{ 36 42 77 81 } }
- }
- T{ live-interval
- { vreg V int-regs 3686310 }
- { start 39 }
- { end 95 }
- { uses V{ 39 84 95 } }
- }
- T{ live-interval
- { vreg V int-regs 3687836 }
- { start 227 }
- { end 228 }
- { uses V{ 227 228 } }
- }
- T{ live-interval
- { vreg V int-regs 3687839 }
- { start 239 }
- { end 246 }
- { uses V{ 239 245 246 } }
- }
- T{ live-interval
- { vreg V int-regs 3687841 }
- { start 240 }
- { end 241 }
- { uses V{ 240 241 } }
- }
- T{ live-interval
- { vreg V int-regs 3687845 }
- { start 241 }
- { end 243 }
- { uses V{ 241 243 } }
- }
- T{ live-interval
- { vreg V int-regs 3686315 }
- { start 40 }
- { end 94 }
- { uses V{ 40 83 94 } }
- }
- T{ live-interval
- { vreg V int-regs 3687846 }
- { start 242 }
- { end 245 }
- { uses V{ 242 245 } }
- }
- T{ live-interval
- { vreg V int-regs 3687849 }
- { start 243 }
- { end 245 }
- { uses V{ 243 244 244 245 } }
- { copy-from V int-regs 3687845 }
- }
- T{ live-interval
- { vreg V int-regs 3687850 }
- { start 245 }
- { end 245 }
- { uses V{ 245 } }
- }
- T{ live-interval
- { vreg V int-regs 3687851 }
- { start 246 }
- { end 246 }
- { uses V{ 246 } }
- }
- T{ live-interval
- { vreg V int-regs 3687852 }
- { start 246 }
- { end 246 }
- { uses V{ 246 } }
- }
- T{ live-interval
- { vreg V int-regs 3687853 }
- { start 247 }
- { end 248 }
- { uses V{ 247 248 } }
- }
- T{ live-interval
- { vreg V int-regs 3687854 }
- { start 249 }
- { end 250 }
- { uses V{ 249 250 } }
- }
- T{ live-interval
- { vreg V int-regs 3687855 }
- { start 258 }
- { end 259 }
- { uses V{ 258 259 } }
- }
- T{ live-interval
- { vreg V int-regs 3687080 }
- { start 280 }
- { end 285 }
- { uses V{ 280 285 } }
- }
- T{ live-interval
- { vreg V int-regs 3687081 }
- { start 281 }
- { end 286 }
- { uses V{ 281 286 } }
+ { vreg 1 }
+ { start 0 }
+ { end 10 }
+ { uses V{ 0 6 10 } }
+ { ranges V{ T{ live-range f 0 10 } } }
}
+
+ ! This guy will invoke the 'spill new' code path
T{ live-interval
- { vreg V int-regs 3687082 }
- { start 282 }
- { end 287 }
- { uses V{ 282 287 } }
+ { vreg 5 }
+ { start 2 }
+ { end 8 }
+ { uses V{ 8 } }
+ { ranges V{ T{ live-range f 2 8 } } }
}
- T{ live-interval
- { vreg V int-regs 3687083 }
- { start 283 }
- { end 288 }
- { uses V{ 283 288 } }
- }
- T{ live-interval
- { vreg V int-regs 3687085 }
- { start 284 }
- { end 299 }
- { uses V{ 284 285 286 287 288 296 299 } }
- }
- T{ live-interval
- { vreg V int-regs 3687086 }
- { start 284 }
- { end 284 }
- { uses V{ 284 } }
- }
- T{ live-interval
- { vreg V int-regs 3687087 }
- { start 289 }
- { end 293 }
- { uses V{ 289 293 } }
- }
- T{ live-interval
- { vreg V int-regs 3687088 }
- { start 290 }
- { end 294 }
- { uses V{ 290 294 } }
- }
- T{ live-interval
- { vreg V int-regs 3687089 }
- { start 291 }
- { end 297 }
- { uses V{ 291 297 } }
- }
- T{ live-interval
- { vreg V int-regs 3687090 }
- { start 292 }
- { end 298 }
- { uses V{ 292 298 } }
- }
- T{ live-interval
- { vreg V int-regs 3687363 }
- { start 118 }
- { end 119 }
- { uses V{ 118 119 } }
- }
- T{ live-interval
- { vreg V int-regs 3686599 }
- { start 77 }
- { end 89 }
- { uses V{ 77 86 89 } }
- }
- T{ live-interval
- { vreg V int-regs 3687370 }
- { start 131 }
- { end 132 }
- { uses V{ 131 132 } }
- }
- T{ live-interval
- { vreg V int-regs 3687371 }
- { start 138 }
- { end 143 }
- { uses V{ 138 143 } }
- }
- T{ live-interval
- { vreg V int-regs 3687368 }
- { start 127 }
- { end 128 }
- { uses V{ 127 128 } }
- }
- T{ live-interval
- { vreg V int-regs 3687369 }
- { start 122 }
- { end 123 }
- { uses V{ 122 123 } }
- }
- T{ live-interval
- { vreg V int-regs 3687373 }
- { start 139 }
- { end 140 }
- { uses V{ 139 140 } }
- }
- T{ live-interval
- { vreg V int-regs 3686352 }
- { start 41 }
- { end 91 }
- { uses V{ 41 43 79 91 } }
- }
- T{ live-interval
- { vreg V int-regs 3687377 }
- { start 140 }
- { end 141 }
- { uses V{ 140 141 } }
- }
- T{ live-interval
- { vreg V int-regs 3687382 }
- { start 143 }
- { end 143 }
- { uses V{ 143 } }
- }
- T{ live-interval
- { vreg V int-regs 3687383 }
- { start 144 }
- { end 161 }
- { uses V{ 144 159 161 } }
- }
- T{ live-interval
- { vreg V int-regs 3687380 }
- { start 141 }
- { end 143 }
- { uses V{ 141 142 142 143 } }
- { copy-from V int-regs 3687377 }
- }
- T{ live-interval
- { vreg V int-regs 3687381 }
- { start 143 }
- { end 160 }
- { uses V{ 143 160 } }
- }
- T{ live-interval
- { vreg V int-regs 3687384 }
- { start 145 }
- { end 158 }
- { uses V{ 145 158 } }
- }
- T{ live-interval
- { vreg V int-regs 3687385 }
- { start 146 }
- { end 157 }
- { uses V{ 146 157 } }
- }
- T{ live-interval
- { vreg V int-regs 3687640 }
- { start 189 }
- { end 191 }
- { uses V{ 189 191 } }
- }
- T{ live-interval
- { vreg V int-regs 3687388 }
- { start 147 }
- { end 152 }
- { uses V{ 147 152 } }
- }
- T{ live-interval
- { vreg V int-regs 3687393 }
- { start 148 }
- { end 153 }
- { uses V{ 148 153 } }
- }
- T{ live-interval
- { vreg V int-regs 3687398 }
- { start 149 }
- { end 154 }
- { uses V{ 149 154 } }
- }
- T{ live-interval
- { vreg V int-regs 3686372 }
- { start 42 }
- { end 92 }
- { uses V{ 42 45 78 80 92 } }
- }
- T{ live-interval
- { vreg V int-regs 3687140 }
- { start 293 }
- { end 295 }
- { uses V{ 293 294 294 295 } }
- { copy-from V int-regs 3687087 }
- }
- T{ live-interval
- { vreg V int-regs 3687403 }
- { start 150 }
- { end 155 }
- { uses V{ 150 155 } }
- }
- T{ live-interval
- { vreg V int-regs 3687150 }
- { start 304 }
- { end 306 }
- { uses V{ 304 306 } }
- }
- T{ live-interval
- { vreg V int-regs 3687151 }
- { start 305 }
- { end 307 }
- { uses V{ 305 307 } }
- }
- T{ live-interval
- { vreg V int-regs 3687408 }
- { start 151 }
- { end 156 }
- { uses V{ 151 156 } }
- }
- T{ live-interval
- { vreg V int-regs 3687153 }
- { start 312 }
- { end 313 }
- { uses V{ 312 313 } }
- }
- T{ live-interval
- { vreg V int-regs 3686902 }
- { start 267 }
- { end 272 }
- { uses V{ 267 272 } }
- }
- T{ live-interval
- { vreg V int-regs 3686903 }
- { start 268 }
- { end 273 }
- { uses V{ 268 273 } }
- }
- T{ live-interval
- { vreg V int-regs 3686900 }
- { start 265 }
- { end 270 }
- { uses V{ 265 270 } }
- }
- T{ live-interval
- { vreg V int-regs 3686901 }
- { start 266 }
- { end 271 }
- { uses V{ 266 271 } }
- }
- T{ live-interval
- { vreg V int-regs 3687162 }
- { start 100 }
- { end 119 }
- { uses V{ 100 114 117 119 } }
- }
- T{ live-interval
- { vreg V int-regs 3687163 }
- { start 101 }
- { end 118 }
- { uses V{ 101 115 116 118 } }
- }
- T{ live-interval
- { vreg V int-regs 3686904 }
- { start 269 }
- { end 274 }
- { uses V{ 269 274 } }
- }
- T{ live-interval
- { vreg V int-regs 3687166 }
- { start 104 }
- { end 110 }
- { uses V{ 104 110 } }
- }
- T{ live-interval
- { vreg V int-regs 3687167 }
- { start 105 }
- { end 111 }
- { uses V{ 105 111 } }
- }
- T{ live-interval
- { vreg V int-regs 3687164 }
- { start 102 }
- { end 108 }
- { uses V{ 102 108 } }
- }
- T{ live-interval
- { vreg V int-regs 3687165 }
- { start 103 }
- { end 109 }
- { uses V{ 103 109 } }
- }
- } fake-live-ranges
- { { int-regs { 0 1 2 3 4 } } }
- allocate-registers drop
+ }
+ H{ { int-regs { "A" } } }
+ check-linear-scan
] unit-test
-! A reduction of the above
-[ ] [
+[ f ] [
+ T{ live-range f 0 10 }
+ T{ live-range f 20 30 }
+ intersect-live-range
+] unit-test
+
+[ 10 ] [
+ T{ live-range f 0 10 }
+ T{ live-range f 10 30 }
+ intersect-live-range
+] unit-test
+
+[ 5 ] [
+ T{ live-range f 0 10 }
+ T{ live-range f 5 30 }
+ intersect-live-range
+] unit-test
+
+[ 5 ] [
+ T{ live-range f 5 30 }
+ T{ live-range f 0 10 }
+ intersect-live-range
+] unit-test
+
+[ 5 ] [
+ T{ live-range f 5 10 }
+ T{ live-range f 0 15 }
+ intersect-live-range
+] unit-test
+
+[ 50 ] [
{
- T{ live-interval
- { vreg V int-regs 6449 }
- { start 44 }
- { end 56 }
- { uses V{ 44 45 46 56 } }
- }
- T{ live-interval
- { vreg V int-regs 6454 }
- { start 46 }
- { end 49 }
- { uses V{ 46 47 49 } }
- }
- T{ live-interval
- { vreg V int-regs 6455 }
- { start 48 }
- { end 51 }
- { uses V{ 48 51 } }
- }
- T{ live-interval
- { vreg V int-regs 6460 }
- { start 49 }
- { end 52 }
- { uses V{ 49 50 52 } }
- }
- T{ live-interval
- { vreg V int-regs 6461 }
- { start 51 }
- { end 71 }
- { uses V{ 51 52 64 68 71 } }
- }
- T{ live-interval
- { vreg V int-regs 6464 }
- { start 53 }
- { end 54 }
- { uses V{ 53 54 } }
- }
- T{ live-interval
- { vreg V int-regs 6470 }
- { start 58 }
- { end 60 }
- { uses V{ 58 59 60 } }
- }
- T{ live-interval
- { vreg V int-regs 6469 }
- { start 56 }
- { end 58 }
- { uses V{ 56 57 58 } }
- }
- T{ live-interval
- { vreg V int-regs 6473 }
- { start 60 }
- { end 62 }
- { uses V{ 60 61 62 } }
- }
- T{ live-interval
- { vreg V int-regs 6479 }
- { start 62 }
- { end 64 }
- { uses V{ 62 63 64 } }
- }
- T{ live-interval
- { vreg V int-regs 6735 }
- { start 78 }
- { end 96 }
- { uses V{ 78 79 96 } }
- { copy-from V int-regs 6372 }
- }
- T{ live-interval
- { vreg V int-regs 6483 }
- { start 65 }
- { end 66 }
- { uses V{ 65 66 } }
- }
- T{ live-interval
- { vreg V int-regs 7845 }
- { start 91 }
- { end 93 }
- { uses V{ 91 93 } }
- }
- T{ live-interval
- { vreg V int-regs 6372 }
- { start 42 }
- { end 92 }
- { uses V{ 42 45 78 80 92 } }
- }
- } fake-live-ranges
- { { int-regs { 0 1 2 3 } } }
- allocate-registers drop
+ T{ live-range f 0 10 }
+ T{ live-range f 20 30 }
+ T{ live-range f 40 50 }
+ }
+ {
+ T{ live-range f 11 15 }
+ T{ live-range f 31 35 }
+ T{ live-range f 50 55 }
+ }
+ intersect-live-ranges
+] unit-test
+
+[ f ] [
+ {
+ T{ live-range f 0 10 }
+ T{ live-range f 20 30 }
+ T{ live-range f 40 50 }
+ }
+ {
+ T{ live-range f 11 15 }
+ T{ live-range f 31 36 }
+ T{ live-range f 51 55 }
+ }
+ intersect-live-ranges
+] unit-test
+
+[ 5 ] [
+ T{ live-interval
+ { start 0 }
+ { end 10 }
+ { uses { 0 10 } }
+ { ranges V{ T{ live-range f 0 10 } } }
+ }
+ T{ live-interval
+ { start 5 }
+ { end 10 }
+ { uses { 5 10 } }
+ { ranges V{ T{ live-range f 5 10 } } }
+ }
+ relevant-ranges intersect-live-ranges
] unit-test
+
+! register-status had problems because it used map>assoc where the sequence
+! had multiple keys
+H{
+ { 1 int-rep }
+ { 2 int-rep }
+ { 3 int-rep }
+ { 4 int-rep }
+} representations set
+
+[ { 0 10 } ] [
+ H{ { int-regs { 0 1 } } } registers set
+ H{
+ { int-regs
+ {
+ T{ live-interval
+ { vreg 1 }
+ { start 0 }
+ { end 20 }
+ { reg 0 }
+ { ranges V{ T{ live-range f 0 2 } T{ live-range f 10 20 } } }
+ { uses V{ 0 2 10 20 } }
+ }
+
+ T{ live-interval
+ { vreg 2 }
+ { start 4 }
+ { end 40 }
+ { reg 0 }
+ { ranges V{ T{ live-range f 4 6 } T{ live-range f 30 40 } } }
+ { uses V{ 4 6 30 40 } }
+ }
+ }
+ }
+ } inactive-intervals set
+ H{
+ { int-regs
+ {
+ T{ live-interval
+ { vreg 3 }
+ { start 0 }
+ { end 40 }
+ { reg 1 }
+ { ranges V{ T{ live-range f 0 40 } } }
+ { uses V{ 0 40 } }
+ }
+ }
+ }
+ } active-intervals set
+
+ T{ live-interval
+ { vreg 4 }
+ { start 8 }
+ { end 10 }
+ { ranges V{ T{ live-range f 8 10 } } }
+ { uses V{ 8 10 } }
+ }
+ register-status
+] unit-test
+
+:: test-linear-scan-on-cfg ( regs -- )
+ [
+ cfg new 0 get >>entry
+ dup cfg set
+ dup fake-representations
+ dup { { int-regs regs } } (linear-scan)
+ flatten-cfg 1array mr.
+ ] with-scope ;
+
+! Bug in live spill slots calculation
+
+V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek
+ { dst 703128 }
+ { loc D 1 }
+ }
+ T{ ##peek
+ { dst 703129 }
+ { loc D 0 }
+ }
+ T{ ##copy
+ { dst 703134 }
+ { src 703128 }
+ }
+ T{ ##copy
+ { dst 703135 }
+ { src 703129 }
+ }
+ T{ ##compare-imm-branch
+ { src1 703128 }
+ { src2 5 }
+ { cc cc/= }
+ }
+} 1 test-bb
+
+V{
+ T{ ##copy
+ { dst 703134 }
+ { src 703129 }
+ }
+ T{ ##copy
+ { dst 703135 }
+ { src 703128 }
+ }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##replace
+ { src 703134 }
+ { loc D 0 }
+ }
+ T{ ##replace
+ { src 703135 }
+ { loc D 1 }
+ }
+ T{ ##epilogue }
+ T{ ##return }
+} 3 test-bb
+
+0 1 edge
+1 { 2 3 } edges
+2 3 edge
+
+! Bug in inactive interval handling
+! [ rot dup [ -rot ] when ]
+V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek
+ { dst 689473 }
+ { loc D 2 }
+ }
+ T{ ##peek
+ { dst 689474 }
+ { loc D 1 }
+ }
+ T{ ##peek
+ { dst 689475 }
+ { loc D 0 }
+ }
+ T{ ##compare-imm-branch
+ { src1 689473 }
+ { src2 5 }
+ { cc cc/= }
+ }
+} 1 test-bb
+
+V{
+ T{ ##copy
+ { dst 689481 }
+ { src 689475 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689482 }
+ { src 689474 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689483 }
+ { src 689473 }
+ { rep int-rep }
+ }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##copy
+ { dst 689481 }
+ { src 689473 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689482 }
+ { src 689475 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689483 }
+ { src 689474 }
+ { rep int-rep }
+ }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace
+ { src 689481 }
+ { loc D 0 }
+ }
+ T{ ##replace
+ { src 689482 }
+ { loc D 1 }
+ }
+ T{ ##replace
+ { src 689483 }
+ { loc D 2 }
+ }
+ T{ ##epilogue }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 3 4 } test-linear-scan-on-cfg ] unit-test
+
+! Similar to the above
+! [ swap dup [ rot ] when ]
+
+T{ basic-block
+ { id 201537 }
+ { number 0 }
+ { instructions V{ T{ ##prologue } T{ ##branch } } }
+} 0 set
+
+V{
+ T{ ##peek
+ { dst 689600 }
+ { loc D 1 }
+ }
+ T{ ##peek
+ { dst 689601 }
+ { loc D 0 }
+ }
+ T{ ##compare-imm-branch
+ { src1 689600 }
+ { src2 5 }
+ { cc cc/= }
+ }
+} 1 test-bb
+
+V{
+ T{ ##peek
+ { dst 689604 }
+ { loc D 2 }
+ }
+ T{ ##copy
+ { dst 689607 }
+ { src 689604 }
+ }
+ T{ ##copy
+ { dst 689608 }
+ { src 689600 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689610 }
+ { src 689601 }
+ { rep int-rep }
+ }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##peek
+ { dst 689609 }
+ { loc D 2 }
+ }
+ T{ ##copy
+ { dst 689607 }
+ { src 689600 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689608 }
+ { src 689601 }
+ { rep int-rep }
+ }
+ T{ ##copy
+ { dst 689610 }
+ { src 689609 }
+ { rep int-rep }
+ }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace
+ { src 689607 }
+ { loc D 0 }
+ }
+ T{ ##replace
+ { src 689608 }
+ { loc D 1 }
+ }
+ T{ ##replace
+ { src 689610 }
+ { loc D 2 }
+ }
+ T{ ##epilogue }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 3 4 } test-linear-scan-on-cfg ] unit-test
+
+! compute-live-registers was inaccurate since it didn't take
+! lifetime holes into account
+
+V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek
+ { dst 0 }
+ { loc D 0 }
+ }
+ T{ ##compare-imm-branch
+ { src1 0 }
+ { src2 5 }
+ { cc cc/= }
+ }
+} 1 test-bb
+
+V{
+ T{ ##peek
+ { dst 1 }
+ { loc D 1 }
+ }
+ T{ ##copy
+ { dst 2 }
+ { src 1 }
+ { rep int-rep }
+ }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##peek
+ { dst 3 }
+ { loc D 2 }
+ }
+ T{ ##copy
+ { dst 2 }
+ { src 3 }
+ { rep int-rep }
+ }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace
+ { src 2 }
+ { loc D 0 }
+ }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 3 4 } test-linear-scan-on-cfg ] unit-test
+
+! Inactive interval handling: splitting active interval
+! if it fits in lifetime hole only partially
+
+V{ T{ ##peek f 3 R 1 } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek f 2 R 0 }
+ T{ ##compare-imm-branch f 2 5 cc= }
+} 1 test-bb
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+} 2 test-bb
+
+
+V{
+ T{ ##peek f 1 D 1 }
+ T{ ##peek f 0 D 0 }
+ T{ ##replace f 1 D 2 }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace f 3 R 2 }
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+! Not until splitting is finished
+! [ _copy ] [ 3 get instructions>> second class ] unit-test
+
+! Resolve pass; make sure the spilling is done correctly
+V{ T{ ##peek f 3 R 1 } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek f 2 R 0 }
+ T{ ##compare-imm-branch f 2 5 cc= }
+} 1 test-bb
+
+V{
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##replace f 3 R 1 }
+ T{ ##peek f 1 D 1 }
+ T{ ##peek f 0 D 0 }
+ T{ ##replace f 1 D 2 }
+ T{ ##replace f 0 D 2 }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace f 3 R 2 }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+[ _spill ] [ 2 get successors>> first instructions>> first class ] unit-test
+
+[ _spill ] [ 3 get instructions>> second class ] unit-test
+
+[ f ] [ 3 get instructions>> [ _reload? ] any? ] unit-test
+
+[ _reload ] [ 4 get instructions>> first class ] unit-test
+
+! Resolve pass
+V{
+ T{ ##branch }
+} 0 test-bb
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-imm-branch f 0 5 cc= }
+} 1 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##peek f 1 D 0 }
+ T{ ##peek f 2 D 0 }
+ T{ ##replace f 1 D 0 }
+ T{ ##replace f 2 D 0 }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##peek f 1 D 0 }
+ T{ ##compare-imm-branch f 1 5 cc= }
+} 4 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 5 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 6 test-bb
+
+0 1 edge
+1 { 2 3 } edges
+2 4 edge
+3 4 edge
+4 { 5 6 } edges
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+[ t ] [ 2 get instructions>> [ _spill? ] any? ] unit-test
+
+[ t ] [ 3 get predecessors>> first instructions>> [ _spill? ] any? ] unit-test
+
+[ t ] [ 5 get instructions>> [ _reload? ] any? ] unit-test
+
+! A more complicated failure case with resolve that came up after the above
+! got fixed
+V{ T{ ##branch } } 0 test-bb
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##peek f 2 D 2 }
+ T{ ##peek f 3 D 3 }
+ T{ ##peek f 4 D 0 }
+ T{ ##branch }
+} 1 test-bb
+V{ T{ ##branch } } 2 test-bb
+V{ T{ ##branch } } 3 test-bb
+V{
+
+ T{ ##replace f 1 D 1 }
+ T{ ##replace f 2 D 2 }
+ T{ ##replace f 3 D 3 }
+ T{ ##replace f 4 D 4 }
+ T{ ##replace f 0 D 0 }
+ T{ ##branch }
+} 4 test-bb
+V{ T{ ##replace f 0 D 0 } T{ ##branch } } 5 test-bb
+V{ T{ ##return } } 6 test-bb
+V{ T{ ##branch } } 7 test-bb
+V{
+ T{ ##replace f 1 D 1 }
+ T{ ##replace f 2 D 2 }
+ T{ ##replace f 3 D 3 }
+ T{ ##peek f 5 D 1 }
+ T{ ##peek f 6 D 2 }
+ T{ ##peek f 7 D 3 }
+ T{ ##peek f 8 D 4 }
+ T{ ##replace f 5 D 1 }
+ T{ ##replace f 6 D 2 }
+ T{ ##replace f 7 D 3 }
+ T{ ##replace f 8 D 4 }
+ T{ ##branch }
+} 8 test-bb
+V{
+ T{ ##replace f 1 D 1 }
+ T{ ##replace f 2 D 2 }
+ T{ ##replace f 3 D 3 }
+ T{ ##return }
+} 9 test-bb
+
+0 1 edge
+1 { 2 7 } edges
+7 8 edge
+8 9 edge
+2 { 3 5 } edges
+3 4 edge
+4 9 edge
+5 6 edge
+
+[ ] [ { 1 2 3 4 } test-linear-scan-on-cfg ] unit-test
+
+[ _spill ] [ 1 get instructions>> second class ] unit-test
+[ _reload ] [ 4 get instructions>> 4 swap nth class ] unit-test
+[ V{ 3 2 1 } ] [ 8 get instructions>> [ _spill? ] filter [ n>> cell / ] map ] unit-test
+[ V{ 3 2 1 } ] [ 9 get instructions>> [ _reload? ] filter [ n>> cell / ] map ] unit-test
+
+! Resolve pass should insert this
+[ _reload ] [ 5 get predecessors>> first instructions>> first class ] unit-test
+
+! Some random bug
+V{
+ T{ ##peek f 1 D 1 }
+ T{ ##peek f 2 D 2 }
+ T{ ##replace f 1 D 1 }
+ T{ ##replace f 2 D 2 }
+ T{ ##peek f 3 D 0 }
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+} 0 test-bb
+
+V{ T{ ##branch } } 1 test-bb
+
+V{
+ T{ ##peek f 1 D 1 }
+ T{ ##peek f 2 D 2 }
+ T{ ##replace f 3 D 3 }
+ T{ ##replace f 1 D 1 }
+ T{ ##replace f 2 D 2 }
+ T{ ##replace f 0 D 3 }
+ T{ ##branch }
+} 2 test-bb
+
+V{ T{ ##branch } } 3 test-bb
+
+V{
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+! Spilling an interval immediately after its activated;
+! and the interval does not have a use at the activation point
+V{
+ T{ ##peek f 1 D 1 }
+ T{ ##peek f 2 D 2 }
+ T{ ##replace f 1 D 1 }
+ T{ ##replace f 2 D 2 }
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+} 0 test-bb
+
+V{ T{ ##branch } } 1 test-bb
+
+V{
+ T{ ##peek f 1 D 1 }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##replace f 1 D 1 }
+ T{ ##peek f 2 D 2 }
+ T{ ##replace f 2 D 2 }
+ T{ ##branch }
+} 3 test-bb
+
+V{ T{ ##branch } } 4 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 5 test-bb
+
+0 1 edge
+1 { 2 4 } edges
+4 5 edge
+2 3 edge
+3 5 edge
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+! Reduction of push-all regression, x86-32
+V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##load-immediate { dst 61 } }
+ T{ ##peek { dst 62 } { loc D 0 } }
+ T{ ##peek { dst 64 } { loc D 1 } }
+ T{ ##slot-imm
+ { dst 69 }
+ { obj 64 }
+ { slot 1 }
+ { tag 2 }
+ }
+ T{ ##copy { dst 79 } { src 69 } { rep int-rep } }
+ T{ ##slot-imm
+ { dst 85 }
+ { obj 62 }
+ { slot 2 }
+ { tag 7 }
+ }
+ T{ ##compare-branch
+ { src1 69 }
+ { src2 85 }
+ { cc cc> }
+ }
+} 1 test-bb
+
+V{
+ T{ ##slot-imm
+ { dst 97 }
+ { obj 62 }
+ { slot 2 }
+ { tag 7 }
+ }
+ T{ ##replace { src 79 } { loc D 3 } }
+ T{ ##replace { src 62 } { loc D 4 } }
+ T{ ##replace { src 79 } { loc D 1 } }
+ T{ ##replace { src 62 } { loc D 2 } }
+ T{ ##replace { src 61 } { loc D 5 } }
+ T{ ##replace { src 62 } { loc R 0 } }
+ T{ ##replace { src 69 } { loc R 1 } }
+ T{ ##replace { src 97 } { loc D 0 } }
+ T{ ##call { word resize-array } }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##peek { dst 98 } { loc R 0 } }
+ T{ ##peek { dst 100 } { loc D 0 } }
+ T{ ##set-slot-imm
+ { src 100 }
+ { obj 98 }
+ { slot 2 }
+ { tag 7 }
+ }
+ T{ ##peek { dst 108 } { loc D 2 } }
+ T{ ##peek { dst 110 } { loc D 3 } }
+ T{ ##peek { dst 112 } { loc D 0 } }
+ T{ ##peek { dst 114 } { loc D 1 } }
+ T{ ##peek { dst 116 } { loc D 4 } }
+ T{ ##peek { dst 119 } { loc R 0 } }
+ T{ ##copy { dst 109 } { src 108 } { rep int-rep } }
+ T{ ##copy { dst 111 } { src 110 } { rep int-rep } }
+ T{ ##copy { dst 113 } { src 112 } { rep int-rep } }
+ T{ ##copy { dst 115 } { src 114 } { rep int-rep } }
+ T{ ##copy { dst 117 } { src 116 } { rep int-rep } }
+ T{ ##copy { dst 120 } { src 119 } { rep int-rep } }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##copy { dst 109 } { src 62 } { rep int-rep } }
+ T{ ##copy { dst 111 } { src 61 } { rep int-rep } }
+ T{ ##copy { dst 113 } { src 62 } { rep int-rep } }
+ T{ ##copy { dst 115 } { src 79 } { rep int-rep } }
+ T{ ##copy { dst 117 } { src 64 } { rep int-rep } }
+ T{ ##copy { dst 120 } { src 69 } { rep int-rep } }
+ T{ ##branch }
+} 4 test-bb
+
+V{
+ T{ ##replace { src 120 } { loc D 0 } }
+ T{ ##replace { src 109 } { loc D 3 } }
+ T{ ##replace { src 111 } { loc D 4 } }
+ T{ ##replace { src 113 } { loc D 1 } }
+ T{ ##replace { src 115 } { loc D 2 } }
+ T{ ##replace { src 117 } { loc D 5 } }
+ T{ ##epilogue }
+ T{ ##return }
+} 5 test-bb
+
+0 1 edge
+1 { 2 4 } edges
+2 3 edge
+3 5 edge
+4 5 edge
+
+[ ] [ { 1 2 3 4 5 } test-linear-scan-on-cfg ] unit-test
+
+! Another reduction of push-all
+V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek { dst 85 } { loc D 0 } }
+ T{ ##slot-imm
+ { dst 89 }
+ { obj 85 }
+ { slot 3 }
+ { tag 7 }
+ }
+ T{ ##peek { dst 91 } { loc D 1 } }
+ T{ ##slot-imm
+ { dst 96 }
+ { obj 91 }
+ { slot 1 }
+ { tag 2 }
+ }
+ T{ ##add
+ { dst 109 }
+ { src1 89 }
+ { src2 96 }
+ }
+ T{ ##slot-imm
+ { dst 115 }
+ { obj 85 }
+ { slot 2 }
+ { tag 7 }
+ }
+ T{ ##slot-imm
+ { dst 118 }
+ { obj 115 }
+ { slot 1 }
+ { tag 2 }
+ }
+ T{ ##compare-branch
+ { src1 109 }
+ { src2 118 }
+ { cc cc> }
+ }
+} 1 test-bb
+
+V{
+ T{ ##add-imm
+ { dst 128 }
+ { src1 109 }
+ { src2 8 }
+ }
+ T{ ##load-immediate { dst 129 } { val 24 } }
+ T{ ##inc-d { n 4 } }
+ T{ ##inc-r { n 1 } }
+ T{ ##replace { src 109 } { loc D 2 } }
+ T{ ##replace { src 85 } { loc D 3 } }
+ T{ ##replace { src 128 } { loc D 0 } }
+ T{ ##replace { src 85 } { loc D 1 } }
+ T{ ##replace { src 89 } { loc D 4 } }
+ T{ ##replace { src 96 } { loc R 0 } }
+ T{ ##replace { src 129 } { loc R 0 } }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##peek { dst 134 } { loc D 1 } }
+ T{ ##slot-imm
+ { dst 140 }
+ { obj 134 }
+ { slot 2 }
+ { tag 7 }
+ }
+ T{ ##inc-d { n 1 } }
+ T{ ##inc-r { n 1 } }
+ T{ ##replace { src 140 } { loc D 0 } }
+ T{ ##replace { src 134 } { loc R 0 } }
+ T{ ##call { word resize-array } }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##peek { dst 141 } { loc R 0 } }
+ T{ ##peek { dst 143 } { loc D 0 } }
+ T{ ##set-slot-imm
+ { src 143 }
+ { obj 141 }
+ { slot 2 }
+ { tag 7 }
+ }
+ T{ ##write-barrier
+ { src 141 }
+ { card# 145 }
+ { table 146 }
+ }
+ T{ ##inc-d { n -1 } }
+ T{ ##inc-r { n -1 } }
+ T{ ##peek { dst 156 } { loc D 2 } }
+ T{ ##peek { dst 158 } { loc D 3 } }
+ T{ ##peek { dst 160 } { loc D 0 } }
+ T{ ##peek { dst 162 } { loc D 1 } }
+ T{ ##peek { dst 164 } { loc D 4 } }
+ T{ ##peek { dst 167 } { loc R 0 } }
+ T{ ##copy { dst 157 } { src 156 } { rep int-rep } }
+ T{ ##copy { dst 159 } { src 158 } { rep int-rep } }
+ T{ ##copy { dst 161 } { src 160 } { rep int-rep } }
+ T{ ##copy { dst 163 } { src 162 } { rep int-rep } }
+ T{ ##copy { dst 165 } { src 164 } { rep int-rep } }
+ T{ ##copy { dst 168 } { src 167 } { rep int-rep } }
+ T{ ##branch }
+} 4 test-bb
+
+V{
+ T{ ##inc-d { n 3 } }
+ T{ ##inc-r { n 1 } }
+ T{ ##copy { dst 157 } { src 85 } }
+ T{ ##copy { dst 159 } { src 89 } }
+ T{ ##copy { dst 161 } { src 85 } }
+ T{ ##copy { dst 163 } { src 109 } }
+ T{ ##copy { dst 165 } { src 91 } }
+ T{ ##copy { dst 168 } { src 96 } }
+ T{ ##branch }
+} 5 test-bb
+
+V{
+ T{ ##set-slot-imm
+ { src 163 }
+ { obj 161 }
+ { slot 3 }
+ { tag 7 }
+ }
+ T{ ##inc-d { n 1 } }
+ T{ ##inc-r { n -1 } }
+ T{ ##replace { src 168 } { loc D 0 } }
+ T{ ##replace { src 157 } { loc D 3 } }
+ T{ ##replace { src 159 } { loc D 4 } }
+ T{ ##replace { src 161 } { loc D 1 } }
+ T{ ##replace { src 163 } { loc D 2 } }
+ T{ ##replace { src 165 } { loc D 5 } }
+ T{ ##epilogue }
+ T{ ##return }
+} 6 test-bb
+
+0 1 edge
+1 { 2 5 } edges
+2 3 edge
+3 4 edge
+4 6 edge
+5 6 edge
+
+[ ] [ { 1 2 3 4 5 } test-linear-scan-on-cfg ] unit-test
+
+! Fencepost error in assignment pass
+V{ T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-imm-branch f 0 5 cc= }
+} 1 test-bb
+
+V{ T{ ##branch } } 2 test-bb
+
+V{
+ T{ ##peek f 1 D 0 }
+ T{ ##peek f 2 D 0 }
+ T{ ##replace f 1 D 0 }
+ T{ ##replace f 2 D 0 }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+[ 0 ] [ 1 get instructions>> [ _spill? ] count ] unit-test
+
+[ 1 ] [ 2 get instructions>> [ _spill? ] count ] unit-test
+
+[ 1 ] [ 3 get predecessors>> first instructions>> [ _spill? ] count ] unit-test
+
+[ 1 ] [ 4 get instructions>> [ _reload? ] count ] unit-test
+
+! Another test case for fencepost error in assignment pass
+V{ T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-imm-branch f 0 5 cc= }
+} 1 test-bb
+
+V{
+ T{ ##peek f 1 D 0 }
+ T{ ##peek f 2 D 0 }
+ T{ ##replace f 1 D 0 }
+ T{ ##replace f 2 D 0 }
+ T{ ##replace f 0 D 0 }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test
+
+[ 0 ] [ 1 get instructions>> [ _spill? ] count ] unit-test
+
+[ 1 ] [ 2 get instructions>> [ _spill? ] count ] unit-test
+
+[ 1 ] [ 2 get instructions>> [ _reload? ] count ] unit-test
+
+[ 0 ] [ 3 get instructions>> [ _spill? ] count ] unit-test
+
+[ 0 ] [ 4 get instructions>> [ _reload? ] count ] unit-test
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##replace f 1 D 1 }
+ T{ ##branch }
+} 0 test-bb
+
+V{
+ T{ ##gc f 2 3 }
+ T{ ##branch }
+} 1 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 2 test-bb
+
+0 1 edge
+1 2 edge
+
+[ ] [ { 1 2 3 } test-linear-scan-on-cfg ] unit-test
+
+[ { 3 } ] [ 1 get instructions>> first tagged-values>> ] unit-test
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##compare-imm-branch f 1 5 cc= }
+} 0 test-bb
+
+V{
+ T{ ##gc f 2 3 }
+ T{ ##replace f 0 D 0 }
+ T{ ##return }
+} 1 test-bb
+
+V{
+ T{ ##return }
+} 2 test-bb
+
+0 { 1 2 } edges
+
+[ ] [ { 1 2 3 } test-linear-scan-on-cfg ] unit-test
+
+[ { 3 } ] [ 1 get instructions>> first tagged-values>> ] unit-test
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors namespaces make
+USING: kernel accessors namespaces make locals
cpu.architecture
compiler.cfg
compiler.cfg.rpo
+compiler.cfg.liveness
+compiler.cfg.registers
compiler.cfg.instructions
compiler.cfg.linear-scan.numbering
compiler.cfg.linear-scan.live-intervals
compiler.cfg.linear-scan.allocation
-compiler.cfg.linear-scan.assignment ;
+compiler.cfg.linear-scan.allocation.state
+compiler.cfg.linear-scan.assignment
+compiler.cfg.linear-scan.resolve ;
IN: compiler.cfg.linear-scan
! References:
! by Omri Traub, Glenn Holloway, Michael D. Smith
! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.8435
-: (linear-scan) ( rpo -- )
- dup number-instructions
- dup compute-live-intervals
- machine-registers allocate-registers assign-registers ;
+:: (linear-scan) ( cfg machine-registers -- )
+ cfg compute-live-sets
+ cfg number-instructions
+ cfg compute-live-intervals machine-registers allocate-registers
+ cfg assign-registers
+ cfg resolve-data-flow
+ cfg check-numbering ;
: linear-scan ( cfg -- cfg' )
- [
- dup reverse-post-order (linear-scan)
- spill-counts get >>spill-counts
- ] with-scope ;
+ dup machine-registers (linear-scan) ;
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces kernel assocs accessors sequences math math.order fry
-binary-search compiler.cfg.instructions compiler.cfg.registers
-compiler.cfg.def-use compiler.cfg.liveness compiler.cfg ;
+combinators binary-search compiler.cfg.instructions compiler.cfg.registers
+compiler.cfg.def-use compiler.cfg.liveness compiler.cfg.linearization.order
+compiler.cfg ;
IN: compiler.cfg.linear-scan.live-intervals
TUPLE: live-range from to ;
TUPLE: live-interval
vreg
-reg spill-to reload-from split-before split-after
-start end ranges uses
-copy-from ;
+reg spill-to reload-from
+start end ranges uses ;
+GENERIC: covers? ( insn# obj -- ? )
+
+M: f covers? 2drop f ;
+
+M: live-range covers? [ from>> ] [ to>> ] bi between? ;
+
+M: live-interval covers? ( insn# live-interval -- ? )
+ ranges>>
+ dup length 4 <= [
+ [ covers? ] with any?
+ ] [
+ [ drop ] [ [ from>> <=> ] with search nip ] 2bi
+ covers?
+ ] if ;
+
ERROR: dead-value-error vreg ;
: shorten-range ( n live-interval -- )
V{ } clone >>ranges
swap >>vreg ;
-: block-from ( -- n )
- basic-block get instructions>> first insn#>> ;
+: block-from ( bb -- n ) instructions>> first insn#>> 1 - ;
-: block-to ( -- n )
- basic-block get instructions>> last insn#>> ;
+: block-to ( bb -- n ) instructions>> last insn#>> ;
M: live-interval hashcode*
nip [ start>> ] [ end>> 1000 * ] bi + ;
: handle-input ( n vreg live-intervals -- )
live-interval
- [ [ block-from ] 2dip add-range ] [ add-use ] 2bi ;
+ [ [ basic-block get block-from ] 2dip add-range ] [ add-use ] 2bi ;
: handle-temp ( n vreg live-intervals -- )
live-interval
M: vreg-insn compute-live-intervals*
dup insn#>>
live-intervals get
- [ [ defs-vregs ] 2dip '[ [ _ ] dip _ handle-output ] each ]
+ [ [ defs-vreg ] 2dip '[ [ _ ] dip _ handle-output ] when* ]
[ [ uses-vregs ] 2dip '[ [ _ ] dip _ handle-input ] each ]
[ [ temp-vregs ] 2dip '[ [ _ ] dip _ handle-temp ] each ]
3tri ;
-: record-copy ( insn -- )
- [ dst>> live-intervals get at ] [ src>> ] bi >>copy-from drop ;
-
-M: ##copy compute-live-intervals*
- [ call-next-method ] [ record-copy ] bi ;
-
-M: ##copy-float compute-live-intervals*
- [ call-next-method ] [ record-copy ] bi ;
-
: handle-live-out ( bb -- )
- live-out keys block-from block-to live-intervals get '[
+ live-out keys
+ basic-block get [ block-from ] [ block-to ] bi
+ live-intervals get '[
[ _ _ ] dip _ live-interval add-range
] each ;
: compute-start/end ( live-interval -- )
dup ranges>> [ first from>> ] [ last to>> ] bi
- 2dup > [ "BUG: start > end" throw ] when
[ >>start ] [ >>end ] bi* drop ;
+ERROR: bad-live-interval live-interval ;
+
+: check-start ( live-interval -- )
+ dup start>> -1 = [ bad-live-interval ] [ drop ] if ;
+
: finish-live-intervals ( live-intervals -- )
! Since live intervals are computed in a backward order, we have
! to reverse some sequences, and compute the start and end.
[
- [ ranges>> reverse-here ]
- [ uses>> reverse-here ]
- [ compute-start/end ]
- tri
+ {
+ [ ranges>> reverse-here ]
+ [ uses>> reverse-here ]
+ [ compute-start/end ]
+ [ check-start ]
+ } cleave
] each ;
-: compute-live-intervals ( rpo -- live-intervals )
+: compute-live-intervals ( cfg -- live-intervals )
H{ } clone [
live-intervals set
- <reversed> [ compute-live-intervals-step ] each
+ linearization-order <reversed>
+ [ compute-live-intervals-step ] each
] keep values dup finish-live-intervals ;
+
+: relevant-ranges ( interval1 interval2 -- ranges1 ranges2 )
+ [ [ ranges>> ] bi@ ] [ nip start>> ] 2bi '[ to>> _ >= ] filter ;
+
+: intersect-live-range ( range1 range2 -- n/f )
+ 2dup [ from>> ] bi@ > [ swap ] when
+ 2dup [ to>> ] [ from>> ] bi* >= [ nip from>> ] [ 2drop f ] if ;
+
+: intersect-live-ranges ( ranges1 ranges2 -- n )
+ {
+ { [ over empty? ] [ 2drop f ] }
+ { [ dup empty? ] [ 2drop f ] }
+ [
+ 2dup [ first ] bi@ intersect-live-range dup [ 2nip ] [
+ drop
+ 2dup [ first from>> ] bi@ <
+ [ [ rest-slice ] dip ] [ rest-slice ] if
+ intersect-live-ranges
+ ] if
+ ]
+ } cond ;
+
+: intervals-intersect? ( interval1 interval2 -- ? )
+ relevant-ranges intersect-live-ranges >boolean ; inline
\ No newline at end of file
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors math sequences ;
+USING: kernel accessors math sequences grouping namespaces
+compiler.cfg.linearization.order ;
IN: compiler.cfg.linear-scan.numbering
: number-instructions ( rpo -- )
- [ 0 ] dip [
+ linearization-order 0 [
instructions>> [
[ (>>insn#) ] [ drop 2 + ] 2bi
] each
- ] each drop ;
\ No newline at end of file
+ ] reduce drop ;
+
+SYMBOL: check-numbering?
+
+ERROR: bad-numbering bb ;
+
+: check-block-numbering ( bb -- )
+ dup instructions>> [ insn#>> ] map sift [ <= ] monotonic?
+ [ drop ] [ bad-numbering ] if ;
+
+: check-numbering ( cfg -- )
+ check-numbering? get
+ [ linearization-order [ check-block-numbering ] each ] [ drop ] if ;
\ No newline at end of file
--- /dev/null
+USING: compiler.cfg.linear-scan.resolve tools.test kernel namespaces
+accessors
+compiler.cfg
+compiler.cfg.instructions cpu.architecture make sequences
+compiler.cfg.linear-scan.allocation.state ;
+IN: compiler.cfg.linear-scan.resolve.tests
+
+[
+ {
+ { { T{ spill-slot f 0 } int-rep } { 1 int-rep } }
+ }
+] [
+ [
+ 0 <spill-slot> 1 int-rep add-mapping
+ ] { } make
+] unit-test
+
+[
+ {
+ T{ _reload { dst 1 } { rep int-rep } { n 0 } }
+ }
+] [
+ [
+ { T{ spill-slot f 0 } int-rep } { 1 int-rep } >insn
+ ] { } make
+] unit-test
+
+[
+ {
+ T{ _spill { src 1 } { rep int-rep } { n 0 } }
+ }
+] [
+ [
+ { 1 int-rep } { T{ spill-slot f 0 } int-rep } >insn
+ ] { } make
+] unit-test
+
+[
+ {
+ T{ ##copy { src 1 } { dst 2 } { rep int-rep } }
+ }
+] [
+ [
+ { 1 int-rep } { 2 int-rep } >insn
+ ] { } make
+] unit-test
+
+cfg new 8 >>spill-area-size cfg set
+H{ } clone spill-temps set
+
+[
+ t
+] [
+ { { { 0 int-rep } { 1 int-rep } } { { 1 int-rep } { 0 int-rep } } }
+ mapping-instructions {
+ {
+ T{ _spill { src 0 } { rep int-rep } { n 8 } }
+ T{ ##copy { dst 0 } { src 1 } { rep int-rep } }
+ T{ _reload { dst 1 } { rep int-rep } { n 8 } }
+ }
+ {
+ T{ _spill { src 1 } { rep int-rep } { n 8 } }
+ T{ ##copy { dst 1 } { src 0 } { rep int-rep } }
+ T{ _reload { dst 0 } { rep int-rep } { n 8 } }
+ }
+ } member?
+] unit-test
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators
+combinators.short-circuit fry kernel locals namespaces
+make math sequences hashtables
+compiler.cfg
+compiler.cfg.rpo
+compiler.cfg.liveness
+compiler.cfg.registers
+compiler.cfg.utilities
+compiler.cfg.instructions
+compiler.cfg.predecessors
+compiler.cfg.parallel-copy
+compiler.cfg.linear-scan.assignment
+compiler.cfg.linear-scan.allocation.state ;
+IN: compiler.cfg.linear-scan.resolve
+
+SYMBOL: spill-temps
+
+: spill-temp ( rep -- n )
+ spill-temps get [ next-spill-slot ] cache ;
+
+: add-mapping ( from to rep -- )
+ '[ _ 2array ] bi@ 2array , ;
+
+:: resolve-value-data-flow ( bb to vreg -- )
+ vreg bb vreg-at-end
+ vreg to vreg-at-start
+ 2dup = [ 2drop ] [ vreg rep-of add-mapping ] if ;
+
+: compute-mappings ( bb to -- mappings )
+ dup live-in dup assoc-empty? [ 3drop f ] [
+ [ keys [ resolve-value-data-flow ] with with each ] { } make
+ ] if ;
+
+: memory->register ( from to -- )
+ swap [ first2 ] [ first n>> ] bi* _reload ;
+
+: register->memory ( from to -- )
+ [ first2 ] [ first n>> ] bi* _spill ;
+
+: temp->register ( from to -- )
+ nip [ first ] [ second ] [ second spill-temp ] tri _reload ;
+
+: register->temp ( from to -- )
+ drop [ first2 ] [ second spill-temp ] bi _spill ;
+
+: register->register ( from to -- )
+ swap [ first ] [ first2 ] bi* ##copy ;
+
+SYMBOL: temp
+
+: >insn ( from to -- )
+ {
+ { [ over temp eq? ] [ temp->register ] }
+ { [ dup temp eq? ] [ register->temp ] }
+ { [ over first spill-slot? ] [ memory->register ] }
+ { [ dup first spill-slot? ] [ register->memory ] }
+ [ register->register ]
+ } cond ;
+
+: mapping-instructions ( alist -- insns )
+ [ swap ] H{ } assoc-map-as
+ [ temp [ swap >insn ] parallel-mapping ] { } make ;
+
+: perform-mappings ( bb to mappings -- )
+ dup empty? [ 3drop ] [
+ mapping-instructions insert-simple-basic-block
+ cfg get cfg-changed drop
+ ] if ;
+
+: resolve-edge-data-flow ( bb to -- )
+ 2dup compute-mappings perform-mappings ;
+
+: resolve-block-data-flow ( bb -- )
+ dup successors>> [ resolve-edge-data-flow ] with each ;
+
+: resolve-data-flow ( cfg -- )
+ needs-predecessors
+
+ H{ } clone spill-temps set
+ [ resolve-block-data-flow ] each-basic-block ;
+++ /dev/null
-IN: compiler.cfg.linearization.tests
-USING: compiler.cfg.linearization tools.test ;
-
-
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math accessors sequences namespaces make
-combinators assocs arrays locals cpu.architecture
+combinators assocs arrays locals layouts hashtables
+cpu.architecture
compiler.cfg
-compiler.cfg.rpo
-compiler.cfg.liveness
+compiler.cfg.comparisons
compiler.cfg.stack-frame
-compiler.cfg.instructions ;
+compiler.cfg.instructions
+compiler.cfg.utilities
+compiler.cfg.linearization.order ;
IN: compiler.cfg.linearization
+<PRIVATE
+
+SYMBOL: numbers
+
+: block-number ( bb -- n ) numbers get at ;
+
+: number-blocks ( bbs -- ) [ 2array ] map-index >hashtable numbers set ;
+
! Convert CFG IR to machine IR.
GENERIC: linearize-insn ( basic-block insn -- )
: linearize-basic-block ( bb -- )
- [ number>> _label ]
+ [ block-number _label ]
[ dup instructions>> [ linearize-insn ] with each ]
bi ;
M: insn linearize-insn , drop ;
: useless-branch? ( basic-block successor -- ? )
- #! If our successor immediately follows us in RPO, then we
- #! don't need to branch.
- [ number>> ] bi@ 1 - = ; inline
-
-: branch-to-branch? ( successor -- ? )
- #! A branch to a block containing just a jump return is cloned.
- instructions>> dup length 2 = [
- [ first ##epilogue? ]
- [ second [ ##return? ] [ ##jump? ] bi or ] bi and
- ] [ drop f ] if ;
-
-: emit-branch ( basic-block successor -- )
- {
- { [ 2dup useless-branch? ] [ 2drop ] }
- { [ dup branch-to-branch? ] [ nip linearize-basic-block ] }
- [ nip number>> _branch ]
- } cond ;
+ ! If our successor immediately follows us in linearization
+ ! order then we don't need to branch.
+ [ block-number ] bi@ 1 - = ; inline
+
+: emit-branch ( bb successor -- )
+ 2dup useless-branch? [ 2drop ] [ nip block-number _branch ] if ;
M: ##branch linearize-insn
drop dup successors>> first emit-branch ;
-: (binary-conditional) ( basic-block insn -- basic-block successor1 successor2 src1 src2 cc )
- [ dup successors>> first2 ]
+: successors ( bb -- first second ) successors>> first2 ; inline
+
+: (binary-conditional) ( bb insn -- bb successor1 successor2 src1 src2 cc )
+ [ dup successors ]
[ [ src1>> ] [ src2>> ] [ cc>> ] tri ] bi* ; inline
-: binary-conditional ( basic-block insn -- basic-block successor label2 src1 src2 cc )
+: binary-conditional ( bb insn -- bb successor label2 src1 src2 cc )
[ (binary-conditional) ]
[ drop dup successors>> second useless-branch? ] 2bi
- [ [ swap number>> ] 3dip ] [ [ number>> ] 3dip negate-cc ] if ;
-
-: with-regs ( insn quot -- )
- over regs>> [ call ] dip building get last (>>regs) ; inline
+ [ [ swap block-number ] 3dip ] [ [ block-number ] 3dip negate-cc ] if ;
M: ##compare-branch linearize-insn
- [ binary-conditional _compare-branch ] with-regs emit-branch ;
+ binary-conditional _compare-branch emit-branch ;
M: ##compare-imm-branch linearize-insn
- [ binary-conditional _compare-imm-branch ] with-regs emit-branch ;
+ binary-conditional _compare-imm-branch emit-branch ;
M: ##compare-float-branch linearize-insn
- [ binary-conditional _compare-float-branch ] with-regs emit-branch ;
+ binary-conditional _compare-float-branch emit-branch ;
-M: ##dispatch linearize-insn
- swap
- [ [ [ src>> ] [ temp>> ] bi _dispatch ] with-regs ]
- [ successors>> [ number>> _dispatch-label ] each ]
- bi* ;
+: overflow-conditional ( bb insn -- bb successor label2 dst src1 src2 )
+ [ dup successors block-number ]
+ [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] bi* ; inline
-: gc-root-registers ( n live-registers -- n )
- [
- [ second 2array , ]
- [ first reg-class>> reg-size + ]
- 2bi
- ] each ;
+M: ##fixnum-add linearize-insn
+ overflow-conditional _fixnum-add emit-branch ;
-: gc-root-spill-slots ( n live-spill-slots -- n )
- [
- dup first reg-class>> int-regs eq? [
- [ second <spill-slot> 2array , ]
- [ first reg-class>> reg-size + ]
- 2bi
- ] [ drop ] if
- ] each ;
-
-: oop-registers ( regs -- regs' )
- [ first reg-class>> int-regs eq? ] filter ;
+M: ##fixnum-sub linearize-insn
+ overflow-conditional _fixnum-sub emit-branch ;
-: data-registers ( regs -- regs' )
- [ first reg-class>> double-float-regs eq? ] filter ;
+M: ##fixnum-mul linearize-insn
+ overflow-conditional _fixnum-mul emit-branch ;
-:: compute-gc-roots ( live-registers live-spill-slots -- alist )
- [
- 0
- ! we put float registers last; the GC doesn't actually scan them
- live-registers oop-registers gc-root-registers
- live-spill-slots gc-root-spill-slots
- live-registers data-registers gc-root-registers
- drop
- ] { } make ;
+M: ##dispatch linearize-insn
+ swap
+ [ [ src>> ] [ temp>> ] bi _dispatch ]
+ [ successors>> [ block-number _dispatch-label ] each ]
+ bi* ;
-: count-gc-roots ( live-registers live-spill-slots -- n )
- ! Size of GC root area, minus the float registers
- [ oop-registers length ] bi@ + ;
+: gc-root-offsets ( registers -- alist )
+ ! Outputs a sequence of { offset register/spill-slot } pairs
+ [ length iota [ cell * ] map ] keep zip ;
M: ##gc linearize-insn
nip
- [
+ {
[ temp1>> ]
[ temp2>> ]
- [
- [ live-registers>> ] [ live-spill-slots>> ] bi
- [ compute-gc-roots ]
- [ count-gc-roots ]
- [ gc-roots-size ]
- 2tri
- ] tri
- _gc
- ] with-regs ;
+ [ data-values>> ]
+ [ tagged-values>> gc-root-offsets ]
+ [ uninitialized-locs>> ]
+ } cleave
+ _gc ;
: linearize-basic-blocks ( cfg -- insns )
[
- [ [ linearize-basic-block ] each-basic-block ]
- [ spill-counts>> _spill-counts ]
- bi
+ [
+ linearization-order
+ [ number-blocks ]
+ [ [ linearize-basic-block ] each ] bi
+ ] [ spill-area-size>> _spill-area-size ] bi
] { } make ;
+PRIVATE>
+
: flatten-cfg ( cfg -- mr )
[ linearize-basic-blocks ] [ word>> ] [ label>> ] tri
<mr> ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs deques dlists kernel make sorting
+namespaces sequences combinators combinators.short-circuit
+fry math sets compiler.cfg.rpo compiler.cfg.utilities
+compiler.cfg.loop-detection ;
+IN: compiler.cfg.linearization.order
+
+! This is RPO except loops are rotated. Based on SBCL's src/compiler/control.lisp
+
+<PRIVATE
+
+SYMBOLS: work-list loop-heads visited ;
+
+: visited? ( bb -- ? ) visited get key? ;
+
+: add-to-work-list ( bb -- )
+ dup visited get key? [ drop ] [
+ work-list get push-back
+ ] if ;
+
+: init-linearization-order ( cfg -- )
+ <dlist> work-list set
+ H{ } clone visited set
+ entry>> add-to-work-list ;
+
+: (find-alternate-loop-head) ( bb -- bb' )
+ dup {
+ [ predecessor visited? not ]
+ [ predecessors>> length 1 = ]
+ [ predecessor successors>> length 1 = ]
+ [ [ number>> ] [ predecessor number>> ] bi > ]
+ } 1&& [ predecessor (find-alternate-loop-head) ] when ;
+
+: find-back-edge ( bb -- pred )
+ [ predecessors>> ] keep '[ _ back-edge? ] find nip ;
+
+: find-alternate-loop-head ( bb -- bb' )
+ dup find-back-edge dup visited? [ drop ] [
+ nip (find-alternate-loop-head)
+ ] if ;
+
+: predecessors-ready? ( bb -- ? )
+ [ predecessors>> ] keep '[
+ _ 2dup back-edge?
+ [ 2drop t ] [ drop visited? ] if
+ ] all? ;
+
+: process-successor ( bb -- )
+ dup predecessors-ready? [
+ dup loop-entry? [ find-alternate-loop-head ] when
+ add-to-work-list
+ ] [ drop ] if ;
+
+: sorted-successors ( bb -- seq )
+ successors>> <reversed> [ loop-nesting-at ] sort-with ;
+
+: process-block ( bb -- )
+ [ , ]
+ [ visited get conjoin ]
+ [ sorted-successors [ process-successor ] each ]
+ tri ;
+
+: (linearization-order) ( cfg -- bbs )
+ init-linearization-order
+
+ [ work-list get [ process-block ] slurp-deque ] { } make ;
+
+PRIVATE>
+
+: linearization-order ( cfg -- bbs )
+ needs-post-order needs-loops
+
+ dup linear-order>> [ ] [
+ dup (linearization-order)
+ >>linear-order linear-order>>
+ ] ?if ;
\ No newline at end of file
+++ /dev/null
-Slava Pestov
\ No newline at end of file
--- /dev/null
+USING: compiler.cfg.liveness compiler.cfg.debugger
+compiler.cfg.instructions compiler.cfg.predecessors
+compiler.cfg.registers compiler.cfg cpu.architecture
+accessors namespaces sequences kernel tools.test vectors ;
+IN: compiler.cfg.liveness.tests
+
+: test-liveness ( -- )
+ cfg new 1 get >>entry
+ compute-live-sets ;
+
+! Sanity check...
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ T{ ##peek f 1 D 1 }
+ T{ ##branch }
+} 1 test-bb
+
+V{
+ T{ ##replace f 2 D 0 }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##replace f 3 D 0 }
+ T{ ##return }
+} 3 test-bb
+
+1 { 2 3 } edges
+
+test-liveness
+
+[
+ H{
+ { 1 1 }
+ { 2 2 }
+ { 3 3 }
+ }
+]
+[ 1 get live-in ]
+unit-test
+
+! Tricky case; defs must be killed before uses
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+} 1 test-bb
+
+V{
+ T{ ##add-imm f 0 0 10 }
+ T{ ##return }
+} 2 test-bb
+
+1 2 edge
+
+test-liveness
+
+[ H{ { 0 0 } } ] [ 2 get live-in ] unit-test
\ No newline at end of file
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces deques accessors sets sequences assocs fry
-dlists compiler.cfg.def-use compiler.cfg.instructions
-compiler.cfg.rpo ;
+USING: kernel accessors assocs sequences sets
+compiler.cfg.def-use compiler.cfg.dataflow-analysis
+compiler.cfg.instructions ;
IN: compiler.cfg.liveness
-! This is a backward dataflow analysis. See http://en.wikipedia.org/wiki/Liveness_analysis
+! See http://en.wikipedia.org/wiki/Liveness_analysis
+! Do not run after SSA construction
-! Assoc mapping basic blocks to sets of vregs
-SYMBOL: live-ins
+BACKWARD-ANALYSIS: live
-: live-in ( basic-block -- set ) live-ins get at ;
+GENERIC: insn-liveness ( live-set insn -- )
-! Assoc mapping basic blocks to sequences of sets of vregs; each sequence
-! is in conrrespondence with a predecessor
-SYMBOL: phi-live-ins
+: kill-defs ( live-set insn -- live-set )
+ defs-vreg [ over delete-at ] when* ;
-: phi-live-in ( predecessor basic-block -- set )
- [ predecessors>> index ] keep phi-live-ins get at
- dup [ nth ] [ 2drop f ] if ;
+: gen-uses ( live-set insn -- live-set )
+ dup ##phi? [ drop ] [ uses-vregs [ over conjoin ] each ] if ;
-! Assoc mapping basic blocks to sets of vregs
-SYMBOL: live-outs
+: transfer-liveness ( live-set instructions -- live-set' )
+ [ clone ] [ <reversed> ] bi* [ [ kill-defs ] [ gen-uses ] bi ] each ;
-: live-out ( basic-block -- set ) live-outs get at ;
+: local-live-in ( instructions -- live-set )
+ [ H{ } ] dip transfer-liveness keys ;
-SYMBOL: work-list
+M: live-analysis transfer-set
+ drop instructions>> transfer-liveness ;
-: add-to-work-list ( basic-blocks -- )
- work-list get '[ _ push-front ] each ;
-
-: map-unique ( seq quot -- assoc )
- map concat unique ; inline
-
-: gen-set ( instructions -- seq )
- [ ##phi? not ] filter [ uses-vregs ] map-unique ;
-
-: kill-set ( instructions -- seq )
- [ [ defs-vregs ] [ temp-vregs ] bi append ] map-unique ;
-
-: compute-live-in ( basic-block -- live-in )
- dup instructions>>
- [ [ live-out ] [ gen-set ] bi* assoc-union ]
- [ nip kill-set ]
- 2bi assoc-diff ;
-
-: compute-phi-live-in ( basic-block -- phi-live-in )
- instructions>> [ ##phi? ] filter
- [ f ] [ [ inputs>> ] map flip [ unique ] map ] if-empty ;
-
-: update-live-in ( basic-block -- changed? )
- [ [ compute-live-in ] keep live-ins get maybe-set-at ]
- [ [ compute-phi-live-in ] keep phi-live-ins get maybe-set-at ]
- bi and ;
-
-: compute-live-out ( basic-block -- live-out )
- [ successors>> [ live-in ] map ]
- [ dup successors>> [ phi-live-in ] with map ] bi
- append assoc-combine ;
-
-: update-live-out ( basic-block -- changed? )
- [ compute-live-out ] keep
- live-outs get maybe-set-at ;
-
-: liveness-step ( basic-block -- )
- dup update-live-out [
- dup update-live-in
- [ predecessors>> add-to-work-list ] [ drop ] if
- ] [ drop ] if ;
-
-: compute-liveness ( cfg -- cfg' )
- <hashed-dlist> work-list set
- H{ } clone live-ins set
- H{ } clone phi-live-ins set
- H{ } clone live-outs set
- dup post-order add-to-work-list
- work-list get [ liveness-step ] slurp-deque ;
+M: live-analysis join-sets
+ 2drop assoc-combine ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces deques accessors sets sequences assocs fry
+hashtables dlists compiler.cfg.def-use compiler.cfg.instructions
+compiler.cfg.rpo compiler.cfg.liveness compiler.cfg.utilities
+compiler.cfg.predecessors ;
+IN: compiler.cfg.liveness.ssa
+
+! TODO: merge with compiler.cfg.liveness
+
+! Assoc mapping basic blocks to sequences of sets of vregs; each sequence
+! is in correspondence with a predecessor
+SYMBOL: phi-live-ins
+
+: phi-live-in ( predecessor basic-block -- set ) phi-live-ins get at at ;
+
+SYMBOL: work-list
+
+: add-to-work-list ( basic-blocks -- )
+ work-list get '[ _ push-front ] each ;
+
+: compute-live-in ( basic-block -- live-in )
+ [ live-out ] keep instructions>> transfer-liveness ;
+
+: compute-phi-live-in ( basic-block -- phi-live-in )
+ H{ } clone [
+ '[ inputs>> [ swap _ conjoin-at ] assoc-each ] each-phi
+ ] keep ;
+
+: update-live-in ( basic-block -- changed? )
+ [ [ compute-live-in ] keep live-ins get maybe-set-at ]
+ [ [ compute-phi-live-in ] keep phi-live-ins get maybe-set-at ]
+ bi or ;
+
+: compute-live-out ( basic-block -- live-out )
+ [ successors>> [ live-in ] map ]
+ [ dup successors>> [ phi-live-in ] with map ] bi
+ append assoc-combine ;
+
+: update-live-out ( basic-block -- changed? )
+ [ compute-live-out ] keep
+ live-outs get maybe-set-at ;
+
+: liveness-step ( basic-block -- )
+ dup update-live-out [
+ dup update-live-in
+ [ predecessors>> add-to-work-list ] [ drop ] if
+ ] [ drop ] if ;
+
+: compute-ssa-live-sets ( cfg -- cfg' )
+ needs-predecessors
+
+ <hashed-dlist> work-list set
+ H{ } clone live-ins set
+ H{ } clone phi-live-ins set
+ H{ } clone live-outs set
+ dup post-order add-to-work-list
+ work-list get [ liveness-step ] slurp-deque ;
+
+: live-in? ( vreg bb -- ? ) live-in key? ;
+
+: live-out? ( vreg bb -- ? ) live-out key? ;
\ No newline at end of file
+++ /dev/null
-Slava Pestov
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: fry accessors kernel assocs compiler.cfg.liveness compiler.cfg.rpo ;
-IN: compiler.cfg.local
-
-: optimize-basic-block ( bb init-quot insn-quot -- )
- [ '[ live-in keys @ ] ] [ '[ _ change-instructions drop ] ] bi* bi ; inline
-
-: local-optimization ( cfg init-quot: ( live-in -- ) insn-quot: ( insns -- insns' ) -- cfg' )
- [ dup ] 2dip '[ _ _ optimize-basic-block ] each-basic-block ; inline
\ No newline at end of file
--- /dev/null
+USING: compiler.cfg compiler.cfg.loop-detection
+compiler.cfg.predecessors
+compiler.cfg.debugger
+tools.test kernel namespaces accessors ;
+IN: compiler.cfg.loop-detection.tests
+
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+
+0 { 1 2 } edges
+2 0 edge
+
+: test-loop-detection ( -- ) cfg new 0 get >>entry needs-loops drop ;
+
+[ ] [ test-loop-detection ] unit-test
+
+[ 1 ] [ 0 get loop-nesting-at ] unit-test
+[ 0 ] [ 1 get loop-nesting-at ] unit-test
+[ 1 ] [ 2 get loop-nesting-at ] unit-test
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators deques dlists fry kernel
+namespaces sequences sets compiler.cfg compiler.cfg.predecessors ;
+IN: compiler.cfg.loop-detection
+
+TUPLE: natural-loop header index ends blocks ;
+
+SYMBOL: loops
+
+<PRIVATE
+
+: <natural-loop> ( header index -- loop )
+ H{ } clone H{ } clone natural-loop boa ;
+
+: lookup-header ( header -- loop )
+ loops get [
+ loops get assoc-size <natural-loop>
+ ] cache ;
+
+SYMBOLS: visited active ;
+
+: record-back-edge ( from to -- )
+ lookup-header ends>> conjoin ;
+
+DEFER: find-loop-headers
+
+: visit-edge ( from to -- )
+ dup active get key?
+ [ record-back-edge ]
+ [ nip find-loop-headers ]
+ if ;
+
+: find-loop-headers ( bb -- )
+ dup visited get key? [ drop ] [
+ {
+ [ visited get conjoin ]
+ [ active get conjoin ]
+ [ dup successors>> [ visit-edge ] with each ]
+ [ active get delete-at ]
+ } cleave
+ ] if ;
+
+SYMBOL: work-list
+
+: process-loop-block ( bb loop -- )
+ 2dup blocks>> key? [ 2drop ] [
+ [ blocks>> conjoin ] [
+ 2dup header>> eq? [ 2drop ] [
+ drop predecessors>> work-list get push-all-front
+ ] if
+ ] 2bi
+ ] if ;
+
+: process-loop-ends ( loop -- )
+ [ ends>> keys <dlist> [ push-all-front ] [ work-list set ] [ ] tri ] keep
+ '[ _ process-loop-block ] slurp-deque ;
+
+: process-loop-headers ( -- )
+ loops get values [ process-loop-ends ] each ;
+
+SYMBOL: loop-nesting
+
+: compute-loop-nesting ( -- )
+ loops get H{ } clone [
+ [ values ] dip '[ blocks>> values [ _ inc-at ] each ] each
+ ] keep loop-nesting set ;
+
+: detect-loops ( cfg -- cfg' )
+ needs-predecessors
+ H{ } clone loops set
+ H{ } clone visited set
+ H{ } clone active set
+ H{ } clone loop-nesting set
+ dup entry>> find-loop-headers process-loop-headers compute-loop-nesting ;
+
+PRIVATE>
+
+: loop-nesting-at ( bb -- n ) loop-nesting get at 0 or ;
+
+: needs-loops ( cfg -- cfg' )
+ needs-predecessors
+ dup loops-valid?>> [ detect-loops t >>loops-valid? ] unless ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: compiler.cfg.linearization compiler.cfg.two-operand
-compiler.cfg.liveness compiler.cfg.gc-checks compiler.cfg.linear-scan
-compiler.cfg.build-stack-frame compiler.cfg.rpo ;
+USING: kernel namespaces accessors compiler.cfg
+compiler.cfg.linearization compiler.cfg.gc-checks
+compiler.cfg.linear-scan compiler.cfg.build-stack-frame ;
IN: compiler.cfg.mr
: build-mr ( cfg -- mr )
- convert-two-operand
- compute-liveness
insert-gc-checks
linear-scan
flatten-cfg
+++ /dev/null
-USING: arrays sequences tools.test compiler.cfg.checker compiler.cfg.debugger
-compiler.cfg.def-use sets kernel kernel.private fry slots.private vectors
-sequences.private math sbufs math.private slots.private strings ;
-IN: compiler.cfg.optimizer.tests
-
-! Miscellaneous tests
-
-: more? ( x -- ? ) ;
-
-: test-case-1 ( -- ? ) f ;
-
-: test-case-2 ( -- )
- test-case-1 [ test-case-2 ] [ ] if ; inline recursive
-
-{
- [ 1array ]
- [ 1 2 ? ]
- [ { array } declare [ ] map ]
- [ { array } declare dup 1 slot [ 1 slot ] when ]
- [ [ dup more? ] [ dup ] produce ]
- [ vector new over test-case-1 [ test-case-2 ] [ ] if ]
- [ [ [ nth-unsafe ".." = 0 ] dip set-nth-unsafe ] 2curry (each-integer) ]
- [
- { fixnum sbuf } declare 2dup 3 slot fixnum> [
- over 3 fixnum* over dup [ 2 slot resize-string ] dip 2 set-slot
- ] [ ] if
- ]
- [ [ 2 fixnum* ] when 3 ]
- [ [ 2 fixnum+ ] when 3 ]
- [ [ 2 fixnum- ] when 3 ]
- [ 10000 [ ] times ]
-} [
- [ [ ] ] dip '[ _ test-mr first check-mr ] unit-test
-] each
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences accessors combinators namespaces
-compiler.cfg.predecessors
-compiler.cfg.useless-blocks
-compiler.cfg.height
-compiler.cfg.stack-analysis
+compiler.cfg.tco
+compiler.cfg.useless-conditionals
+compiler.cfg.branch-splitting
+compiler.cfg.block-joining
+compiler.cfg.ssa.construction
compiler.cfg.alias-analysis
compiler.cfg.value-numbering
+compiler.cfg.copy-prop
compiler.cfg.dce
compiler.cfg.write-barrier
-compiler.cfg.liveness
-compiler.cfg.rpo
-compiler.cfg.phi-elimination ;
+compiler.cfg.representations
+compiler.cfg.two-operand
+compiler.cfg.ssa.destruction
+compiler.cfg.empty-blocks
+compiler.cfg.checker ;
IN: compiler.cfg.optimizer
+SYMBOL: check-optimizer?
+
+: ?check ( cfg -- cfg' )
+ check-optimizer? get [
+ dup check-cfg
+ ] when ;
+
: optimize-cfg ( cfg -- cfg' )
- [
- compute-predecessors
- delete-useless-blocks
- delete-useless-conditionals
- normalize-height
- stack-analysis
- compute-liveness
- alias-analysis
- value-numbering
- eliminate-dead-code
- eliminate-write-barriers
- eliminate-phis
- ] with-scope ;
+ optimize-tail-calls
+ delete-useless-conditionals
+ split-branches
+ join-blocks
+ construct-ssa
+ alias-analysis
+ value-numbering
+ copy-propagation
+ eliminate-dead-code
+ eliminate-write-barriers
+ select-representations
+ convert-two-operand
+ destruct-ssa
+ delete-empty-blocks
+ ?check ;
--- /dev/null
+USING: compiler.cfg.parallel-copy tools.test make arrays
+compiler.cfg.registers namespaces compiler.cfg.instructions
+cpu.architecture ;
+IN: compiler.cfg.parallel-copy.tests
+
+SYMBOL: temp
+
+: test-parallel-copy ( mapping -- seq )
+ 3 vreg-counter set-global
+ [ parallel-copy ] { } make ;
+
+[
+ {
+ T{ ##copy f 4 2 any-rep }
+ T{ ##copy f 2 1 any-rep }
+ T{ ##copy f 1 4 any-rep }
+ }
+] [
+ H{
+ { 1 2 }
+ { 2 1 }
+ } test-parallel-copy
+] unit-test
+
+[
+ {
+ T{ ##copy f 1 2 any-rep }
+ T{ ##copy f 3 4 any-rep }
+ }
+] [
+ H{
+ { 1 2 }
+ { 3 4 }
+ } test-parallel-copy
+] unit-test
+
+[
+ {
+ T{ ##copy f 1 3 any-rep }
+ T{ ##copy f 2 1 any-rep }
+ }
+] [
+ H{
+ { 1 3 }
+ { 2 3 }
+ } test-parallel-copy
+] unit-test
+
+[
+ {
+ T{ ##copy f 4 3 any-rep }
+ T{ ##copy f 3 2 any-rep }
+ T{ ##copy f 2 1 any-rep }
+ T{ ##copy f 1 4 any-rep }
+ }
+] [
+ {
+ { 2 1 }
+ { 3 2 }
+ { 1 3 }
+ { 4 3 }
+ } test-parallel-copy
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs cpu.architecture compiler.cfg.registers
+compiler.cfg.instructions deques dlists fry kernel locals namespaces
+sequences hashtables ;
+IN: compiler.cfg.parallel-copy
+
+! Revisiting Out-of-SSA Translation for Correctness, Code Quality, and Efficiency
+! http://hal.archives-ouvertes.fr/docs/00/34/99/25/PDF/OutSSA-RR.pdf,
+! Algorithm 1
+
+<PRIVATE
+
+SYMBOLS: temp locs preds to-do ready ;
+
+: init-to-do ( bs -- )
+ to-do get push-all-back ;
+
+: init-ready ( bs -- )
+ locs get '[ _ key? not ] filter ready get push-all-front ;
+
+: init ( mapping temp -- )
+ temp set
+ <dlist> to-do set
+ <dlist> ready set
+ [ preds set ]
+ [ [ nip dup ] H{ } assoc-map-as locs set ]
+ [ keys [ init-to-do ] [ init-ready ] bi ] tri ;
+
+:: process-ready ( b quot -- )
+ b preds get at :> a
+ a locs get at :> c
+ b c quot call
+ b a locs get set-at
+ a c = a preds get at and [ a ready get push-front ] when ; inline
+
+:: process-to-do ( b quot -- )
+ ! Note that we check if b = loc(b), not b = loc(pred(b)) as the
+ ! paper suggests. Confirmed by one of the authors at
+ ! http://www.reddit.com/comments/93253/some_lecture_notes_on_ssa_form/c0bco4f
+ b locs get at b = [
+ temp get b quot call
+ temp get b locs get set-at
+ b ready get push-front
+ ] when ; inline
+
+PRIVATE>
+
+:: parallel-mapping ( mapping temp quot -- )
+ [
+ mapping temp init
+ to-do get [
+ ready get [
+ quot process-ready
+ ] slurp-deque
+ quot process-to-do
+ ] slurp-deque
+ ] with-scope ; inline
+
+: parallel-copy ( mapping -- )
+ next-vreg [ any-rep ##copy ] parallel-mapping ;
\ No newline at end of file
+++ /dev/null
-Slava Pestov
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors compiler.cfg compiler.cfg.instructions
-compiler.cfg.rpo fry kernel sequences ;
-IN: compiler.cfg.phi-elimination
-
-: insert-copy ( predecessor input output -- )
- '[ _ _ swap ##copy ] add-instructions ;
-
-: eliminate-phi ( bb ##phi -- )
- [ predecessors>> ] [ [ inputs>> ] [ dst>> ] bi ] bi*
- '[ _ insert-copy ] 2each ;
-
-: eliminate-phi-step ( bb -- )
- dup [
- [ ##phi? ] partition
- [ [ eliminate-phi ] with each ] dip
- ] change-instructions drop ;
-
-: eliminate-phis ( cfg -- cfg' )
- dup [ eliminate-phi-step ] each-basic-block ;
\ No newline at end of file
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors sequences compiler.cfg.rpo ;
+USING: kernel accessors combinators fry sequences assocs compiler.cfg.rpo
+compiler.cfg.instructions compiler.cfg.utilities ;
IN: compiler.cfg.predecessors
-: predecessors-step ( bb -- )
+<PRIVATE
+
+: update-predecessors ( bb -- )
dup successors>> [ predecessors>> push ] with each ;
+: update-phi ( bb ##phi -- )
+ [
+ swap predecessors>>
+ '[ drop _ memq? ] assoc-filter
+ ] change-inputs drop ;
+
+: update-phis ( bb -- )
+ dup [ update-phi ] with each-phi ;
+
: compute-predecessors ( cfg -- cfg' )
- dup [ predecessors-step ] each-basic-block ;
+ {
+ [ [ V{ } clone >>predecessors drop ] each-basic-block ]
+ [ [ update-predecessors ] each-basic-block ]
+ [ [ update-phis ] each-basic-block ]
+ [ ]
+ } cleave ;
+
+PRIVATE>
+
+: needs-predecessors ( cfg -- cfg' )
+ dup predecessors-valid?>>
+ [ compute-predecessors t >>predecessors-valid? ] unless ;
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors namespaces kernel arrays parser ;
+USING: accessors namespaces kernel parser assocs ;
IN: compiler.cfg.registers
-! Virtual registers, used by CFG and machine IRs
-TUPLE: vreg { reg-class read-only } { n read-only } ;
+! Virtual registers, used by CFG and machine IRs, are just integers
SYMBOL: vreg-counter
-: next-vreg ( reg-class -- vreg ) \ vreg-counter counter vreg boa ;
-! Stack locations
+: next-vreg ( -- vreg )
+ ! This word cannot be called AFTER representation selection has run;
+ ! use next-vreg-rep in that case
+ \ vreg-counter counter ;
+
+SYMBOL: representations
+
+ERROR: bad-vreg vreg ;
+
+: rep-of ( vreg -- rep )
+ ! This word cannot be called BEFORE representation selection has run;
+ ! use any-rep for ##copy instructions and so on
+ representations get ?at [ bad-vreg ] unless ;
+
+: set-rep-of ( rep vreg -- )
+ representations get set-at ;
+
+: next-vreg-rep ( rep -- vreg )
+ ! This word cannot be called BEFORE representation selection has run;
+ ! use next-vreg in that case
+ next-vreg [ set-rep-of ] keep ;
+
+! Stack locations -- 'n' is an index starting from the top of the stack
+! going down. So 0 is the top of the stack, 1 is what would be the top
+! of the stack after a 'drop', and so on.
+
+! ##inc-d and ##inc-r affect locations as follows. Location D 0 before
+! an ##inc-d 1 becomes D 1 after ##inc-d 1.
TUPLE: loc { n read-only } ;
TUPLE: ds-loc < loc ;
TUPLE: rs-loc < loc ;
C: <rs-loc> rs-loc
-SYNTAX: V scan-word scan-word vreg boa parsed ;
SYNTAX: D scan-word <ds-loc> parsed ;
SYNTAX: R scan-word <rs-loc> parsed ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: functors assocs kernel accessors compiler.cfg.instructions
+lexer parser ;
+IN: compiler.cfg.renaming.functor
+
+FUNCTOR: define-renaming ( NAME DEF-QUOT USE-QUOT TEMP-QUOT -- )
+
+rename-insn-defs DEFINES ${NAME}-insn-defs
+rename-insn-uses DEFINES ${NAME}-insn-uses
+rename-insn-temps DEFINES ${NAME}-insn-temps
+
+WHERE
+
+GENERIC: rename-insn-defs ( insn -- )
+
+M: ##flushable rename-insn-defs
+ DEF-QUOT change-dst
+ drop ;
+
+M: ##fixnum-overflow rename-insn-defs
+ DEF-QUOT change-dst
+ drop ;
+
+M: _fixnum-overflow rename-insn-defs
+ DEF-QUOT change-dst
+ drop ;
+
+M: insn rename-insn-defs drop ;
+
+GENERIC: rename-insn-uses ( insn -- )
+
+M: ##effect rename-insn-uses
+ USE-QUOT change-src
+ drop ;
+
+M: ##unary rename-insn-uses
+ USE-QUOT change-src
+ drop ;
+
+M: ##binary rename-insn-uses
+ USE-QUOT change-src1
+ USE-QUOT change-src2
+ drop ;
+
+M: ##binary-imm rename-insn-uses
+ USE-QUOT change-src1
+ drop ;
+
+M: ##slot rename-insn-uses
+ USE-QUOT change-obj
+ USE-QUOT change-slot
+ drop ;
+
+M: ##slot-imm rename-insn-uses
+ USE-QUOT change-obj
+ drop ;
+
+M: ##set-slot rename-insn-uses
+ dup call-next-method
+ USE-QUOT change-obj
+ USE-QUOT change-slot
+ drop ;
+
+M: ##string-nth rename-insn-uses
+ USE-QUOT change-obj
+ USE-QUOT change-index
+ drop ;
+
+M: ##set-string-nth-fast rename-insn-uses
+ dup call-next-method
+ USE-QUOT change-obj
+ USE-QUOT change-index
+ drop ;
+
+M: ##set-slot-imm rename-insn-uses
+ dup call-next-method
+ USE-QUOT change-obj
+ drop ;
+
+M: ##alien-getter rename-insn-uses
+ dup call-next-method
+ USE-QUOT change-src
+ drop ;
+
+M: ##alien-setter rename-insn-uses
+ dup call-next-method
+ USE-QUOT change-value
+ drop ;
+
+M: ##conditional-branch rename-insn-uses
+ USE-QUOT change-src1
+ USE-QUOT change-src2
+ drop ;
+
+M: ##compare-imm-branch rename-insn-uses
+ USE-QUOT change-src1
+ drop ;
+
+M: ##dispatch rename-insn-uses
+ USE-QUOT change-src
+ drop ;
+
+M: ##fixnum-overflow rename-insn-uses
+ USE-QUOT change-src1
+ USE-QUOT change-src2
+ drop ;
+
+M: ##phi rename-insn-uses
+ [ USE-QUOT assoc-map ] change-inputs
+ drop ;
+
+M: insn rename-insn-uses drop ;
+
+GENERIC: rename-insn-temps ( insn -- )
+
+M: ##write-barrier rename-insn-temps
+ TEMP-QUOT change-card#
+ TEMP-QUOT change-table
+ drop ;
+
+M: ##unary/temp rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##allot rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##dispatch rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##slot rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##set-slot rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##string-nth rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##set-string-nth-fast rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##box-displaced-alien rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##compare rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##compare-imm rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##compare-float rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: ##gc rename-insn-temps
+ TEMP-QUOT change-temp1
+ TEMP-QUOT change-temp2
+ drop ;
+
+M: _dispatch rename-insn-temps
+ TEMP-QUOT change-temp drop ;
+
+M: insn rename-insn-temps drop ;
+
+;FUNCTOR
+
+SYNTAX: RENAMING: scan scan-object scan-object scan-object define-renaming ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel namespaces sequences
+compiler.cfg.instructions compiler.cfg.registers
+compiler.cfg.renaming.functor ;
+IN: compiler.cfg.renaming
+
+SYMBOL: renamings
+
+: rename-value ( vreg -- vreg' )
+ renamings get ?at drop ;
+
+RENAMING: rename [ rename-value ] [ rename-value ] [ drop next-vreg ]
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors sequences arrays fry namespaces
+cpu.architecture compiler.cfg.utilities compiler.cfg compiler.cfg.rpo
+compiler.cfg.instructions compiler.cfg.def-use ;
+IN: compiler.cfg.representations.preferred
+
+GENERIC: defs-vreg-rep ( insn -- rep/f )
+GENERIC: temp-vreg-reps ( insn -- reps )
+GENERIC: uses-vreg-reps ( insn -- reps )
+
+M: ##flushable defs-vreg-rep drop int-rep ;
+M: ##copy defs-vreg-rep rep>> ;
+M: output-float-insn defs-vreg-rep drop double-float-rep ;
+M: ##fixnum-overflow defs-vreg-rep drop int-rep ;
+M: _fixnum-overflow defs-vreg-rep drop int-rep ;
+M: ##phi defs-vreg-rep drop "##phi must be special-cased" throw ;
+M: insn defs-vreg-rep drop f ;
+
+M: ##write-barrier temp-vreg-reps drop { int-rep int-rep } ;
+M: ##unary/temp temp-vreg-reps drop { int-rep } ;
+M: ##allot temp-vreg-reps drop { int-rep } ;
+M: ##dispatch temp-vreg-reps drop { int-rep } ;
+M: ##slot temp-vreg-reps drop { int-rep } ;
+M: ##set-slot temp-vreg-reps drop { int-rep } ;
+M: ##string-nth temp-vreg-reps drop { int-rep } ;
+M: ##set-string-nth-fast temp-vreg-reps drop { int-rep } ;
+M: ##box-displaced-alien temp-vreg-reps drop { int-rep } ;
+M: ##compare temp-vreg-reps drop { int-rep } ;
+M: ##compare-imm temp-vreg-reps drop { int-rep } ;
+M: ##compare-float temp-vreg-reps drop { int-rep } ;
+M: ##gc temp-vreg-reps drop { int-rep int-rep } ;
+M: _dispatch temp-vreg-reps drop { int-rep } ;
+M: insn temp-vreg-reps drop f ;
+
+M: ##copy uses-vreg-reps rep>> 1array ;
+M: ##unary uses-vreg-reps drop { int-rep } ;
+M: ##unary-float uses-vreg-reps drop { double-float-rep } ;
+M: ##binary uses-vreg-reps drop { int-rep int-rep } ;
+M: ##binary-imm uses-vreg-reps drop { int-rep } ;
+M: ##binary-float uses-vreg-reps drop { double-float-rep double-float-rep } ;
+M: ##effect uses-vreg-reps drop { int-rep } ;
+M: ##slot uses-vreg-reps drop { int-rep int-rep } ;
+M: ##slot-imm uses-vreg-reps drop { int-rep } ;
+M: ##set-slot uses-vreg-reps drop { int-rep int-rep int-rep } ;
+M: ##set-slot-imm uses-vreg-reps drop { int-rep int-rep } ;
+M: ##string-nth uses-vreg-reps drop { int-rep int-rep } ;
+M: ##set-string-nth-fast uses-vreg-reps drop { int-rep int-rep int-rep } ;
+M: ##compare-branch uses-vreg-reps drop { int-rep int-rep } ;
+M: ##compare-imm-branch uses-vreg-reps drop { int-rep } ;
+M: ##compare-float-branch uses-vreg-reps drop { double-float-rep double-float-rep } ;
+M: ##dispatch uses-vreg-reps drop { int-rep } ;
+M: ##alien-getter uses-vreg-reps drop { int-rep } ;
+M: ##alien-setter uses-vreg-reps drop { int-rep int-rep } ;
+M: ##set-alien-float uses-vreg-reps drop { int-rep double-float-rep } ;
+M: ##set-alien-double uses-vreg-reps drop { int-rep double-float-rep } ;
+M: ##fixnum-overflow uses-vreg-reps drop { int-rep int-rep } ;
+M: _compare-imm-branch uses-vreg-reps drop { int-rep } ;
+M: _compare-branch uses-vreg-reps drop { int-rep int-rep } ;
+M: _compare-float-branch uses-vreg-reps drop { double-float-rep double-float-rep } ;
+M: _dispatch uses-vreg-reps drop { int-rep } ;
+M: ##phi uses-vreg-reps drop "##phi must be special-cased" throw ;
+M: insn uses-vreg-reps drop f ;
+
+: each-def-rep ( insn vreg-quot: ( vreg rep -- ) -- )
+ [ [ defs-vreg ] [ defs-vreg-rep ] bi ] dip with when* ; inline
+
+: each-use-rep ( insn vreg-quot: ( vreg rep -- ) -- )
+ [ [ uses-vregs ] [ uses-vreg-reps ] bi ] dip 2each ; inline
+
+: each-temp-rep ( insn vreg-quot: ( vreg rep -- ) -- )
+ [ [ temp-vregs ] [ temp-vreg-reps ] bi ] dip 2each ; inline
+
+: with-vreg-reps ( cfg vreg-quot: ( vreg rep -- ) -- )
+ '[
+ [ basic-block set ] [
+ [
+ _
+ [ each-def-rep ]
+ [ each-use-rep ]
+ [ each-temp-rep ] 2tri
+ ] each-non-phi
+ ] bi
+ ] each-basic-block ; inline
--- /dev/null
+USING: tools.test cpu.architecture
+compiler.cfg.registers compiler.cfg.instructions
+compiler.cfg.representations.preferred ;
+IN: compiler.cfg.representations
+
+[ { double-float-rep double-float-rep } ] [
+ T{ ##add-float
+ { dst 5 }
+ { src1 3 }
+ { src2 4 }
+ } uses-vreg-reps
+] unit-test
+
+[ double-float-rep ] [
+ T{ ##alien-double
+ { dst 5 }
+ { src 3 }
+ } defs-vreg-rep
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel fry accessors sequences assocs sets namespaces
+arrays combinators make locals deques dlists
+cpu.architecture compiler.utilities
+compiler.cfg
+compiler.cfg.rpo
+compiler.cfg.registers
+compiler.cfg.instructions
+compiler.cfg.def-use
+compiler.cfg.utilities
+compiler.cfg.loop-detection
+compiler.cfg.renaming.functor
+compiler.cfg.representations.preferred ;
+IN: compiler.cfg.representations
+
+! Virtual register representation selection.
+
+: emit-conversion ( dst src dst-rep src-rep -- )
+ 2array {
+ { { int-rep int-rep } [ int-rep ##copy ] }
+ { { double-float-rep double-float-rep } [ double-float-rep ##copy ] }
+ { { double-float-rep int-rep } [ ##unbox-float ] }
+ { { int-rep double-float-rep } [ int-rep next-vreg-rep ##box-float ] }
+ } case ;
+
+<PRIVATE
+
+! For every vreg, compute possible representations.
+SYMBOL: possibilities
+
+: possible ( vreg -- reps ) possibilities get at ;
+
+: compute-possibilities ( cfg -- )
+ H{ } clone [ '[ swap _ conjoin-at ] with-vreg-reps ] keep
+ [ keys ] assoc-map possibilities set ;
+
+! Compute vregs which must remain tagged for their lifetime.
+SYMBOL: always-boxed
+
+:: (compute-always-boxed) ( vreg rep assoc -- )
+ rep int-rep eq? [
+ int-rep vreg assoc set-at
+ ] when ;
+
+: compute-always-boxed ( cfg -- assoc )
+ H{ } clone [
+ '[
+ [
+ dup ##load-reference? [ drop ] [
+ [ _ (compute-always-boxed) ] each-def-rep
+ ] if
+ ] each-non-phi
+ ] each-basic-block
+ ] keep ;
+
+! For every vreg, compute the cost of keeping it in every possible
+! representation.
+
+! Cost map maps vreg to representation to cost.
+SYMBOL: costs
+
+: init-costs ( -- )
+ possibilities get [ [ 0 ] H{ } map>assoc ] assoc-map costs set ;
+
+: increase-cost ( rep vreg -- )
+ ! Increase cost of keeping vreg in rep, making a choice of rep less
+ ! likely.
+ [ basic-block get loop-nesting-at ] 2dip costs get at at+ ;
+
+: maybe-increase-cost ( possible vreg preferred -- )
+ pick eq? [ 2drop ] [ increase-cost ] if ;
+
+: representation-cost ( vreg preferred -- )
+ ! 'preferred' is a representation that the instruction can accept with no cost.
+ ! So, for each representation that's not preferred, increase the cost of keeping
+ ! the vreg in that representation.
+ [ drop possible ]
+ [ '[ _ _ maybe-increase-cost ] ]
+ 2bi each ;
+
+: compute-costs ( cfg -- costs )
+ init-costs [ representation-cost ] with-vreg-reps costs get ;
+
+! For every vreg, compute preferred representation, that minimizes costs.
+: minimize-costs ( costs -- representations )
+ [ >alist alist-min first ] assoc-map ;
+
+: compute-representations ( cfg -- )
+ [ compute-costs minimize-costs ]
+ [ compute-always-boxed ]
+ bi assoc-union
+ representations set ;
+
+! Insert conversions. This introduces new temporaries, so we need
+! to rename opearands too.
+
+:: emit-def-conversion ( dst preferred required -- new-dst' )
+ ! If an instruction defines a register with representation 'required',
+ ! but the register has preferred representation 'preferred', then
+ ! we rename the instruction's definition to a new register, which
+ ! becomes the input of a conversion instruction.
+ dst required next-vreg-rep [ preferred required emit-conversion ] keep ;
+
+:: emit-use-conversion ( src preferred required -- new-src' )
+ ! If an instruction uses a register with representation 'required',
+ ! but the register has preferred representation 'preferred', then
+ ! we rename the instruction's input to a new register, which
+ ! becomes the output of a conversion instruction.
+ required next-vreg-rep [ src required preferred emit-conversion ] keep ;
+
+SYMBOLS: renaming-set needs-renaming? ;
+
+: init-renaming-set ( -- )
+ needs-renaming? off
+ V{ } clone renaming-set set ;
+
+: no-renaming ( vreg -- )
+ dup 2array renaming-set get push ;
+
+: record-renaming ( from to -- )
+ 2array renaming-set get push needs-renaming? on ;
+
+:: (compute-renaming-set) ( vreg required quot: ( vreg preferred required -- ) -- )
+ vreg rep-of :> preferred
+ preferred required eq?
+ [ vreg no-renaming ]
+ [ vreg vreg preferred required quot call record-renaming ] if ; inline
+
+: compute-renaming-set ( insn -- )
+ ! temp vregs don't need conversions since they're always in their
+ ! preferred representation
+ init-renaming-set
+ [ [ [ emit-use-conversion ] (compute-renaming-set) ] each-use-rep ]
+ [ , ]
+ [ [ [ emit-def-conversion ] (compute-renaming-set) ] each-def-rep ]
+ tri ;
+
+: converted-value ( vreg -- vreg' )
+ renaming-set get pop first2 [ assert= ] dip ;
+
+RENAMING: convert [ converted-value ] [ converted-value ] [ ]
+
+: perform-renaming ( insn -- )
+ needs-renaming? get [
+ renaming-set get reverse-here
+ [ convert-insn-uses ] [ convert-insn-defs ] bi
+ renaming-set get length 0 assert=
+ ] [ drop ] if ;
+
+GENERIC: conversions-for-insn ( insn -- )
+
+SYMBOL: phi-mappings
+
+! compiler.cfg.cssa inserts conversions which convert phi inputs into
+! the representation of the output. However, we still have to do some
+! processing here, because if the only node that uses the output of
+! the phi instruction is another phi instruction then this phi node's
+! output won't have a representation assigned.
+M: ##phi conversions-for-insn
+ [ , ] [ [ inputs>> values ] [ dst>> ] bi phi-mappings get set-at ] bi ;
+
+M: vreg-insn conversions-for-insn
+ [ compute-renaming-set ] [ perform-renaming ] bi ;
+
+M: insn conversions-for-insn , ;
+
+: conversions-for-block ( bb -- )
+ dup kill-block? [ drop ] [
+ [
+ [
+ [ conversions-for-insn ] each
+ ] V{ } make
+ ] change-instructions drop
+ ] if ;
+
+! If the output of a phi instruction is only used as the input to another
+! phi instruction, then we want to use the same representation for both
+! if possible.
+SYMBOL: work-list
+
+: add-to-work-list ( vregs -- )
+ work-list get push-all-front ;
+
+: rep-assigned ( vregs -- vregs' )
+ representations get '[ _ key? ] filter ;
+
+: rep-not-assigned ( vregs -- vregs' )
+ representations get '[ _ key? not ] filter ;
+
+: add-ready-phis ( -- )
+ phi-mappings get keys rep-assigned add-to-work-list ;
+
+: process-phi-mapping ( dst -- )
+ ! If dst = phi(src1,src2,...) and dst's representation has been
+ ! determined, assign that representation to each one of src1,...
+ ! that does not have a representation yet, and process those, too.
+ dup phi-mappings get at* [
+ [ rep-of ] [ rep-not-assigned ] bi*
+ [ [ set-rep-of ] with each ] [ add-to-work-list ] bi
+ ] [ 2drop ] if ;
+
+: remaining-phi-mappings ( -- )
+ phi-mappings get keys rep-not-assigned
+ [ [ int-rep ] dip set-rep-of ] each ;
+
+: process-phi-mappings ( -- )
+ <hashed-dlist> work-list set
+ add-ready-phis
+ work-list get [ process-phi-mapping ] slurp-deque
+ remaining-phi-mappings ;
+
+: insert-conversions ( cfg -- )
+ H{ } clone phi-mappings set
+ [ conversions-for-block ] each-basic-block
+ process-phi-mappings ;
+
+PRIVATE>
+
+: select-representations ( cfg -- cfg' )
+ needs-loops
+
+ {
+ [ compute-possibilities ]
+ [ compute-representations ]
+ [ insert-conversions ]
+ [ ]
+ } cleave
+ representations get cfg get (>>reps) ;
\ No newline at end of file
: each-basic-block ( cfg quot -- )
[ reverse-post-order ] dip each ; inline
+
+: optimize-basic-block ( bb quot -- )
+ [ drop basic-block set ]
+ [ change-instructions drop ] 2bi ; inline
+
+: local-optimization ( cfg quot: ( insns -- insns' ) -- cfg' )
+ dupd '[ _ optimize-basic-block ] each-basic-block ; inline
+
+: needs-post-order ( cfg -- cfg' )
+ dup post-order drop ;
\ No newline at end of file
--- /dev/null
+USING: accessors compiler.cfg compiler.cfg.debugger
+compiler.cfg.dominance compiler.cfg.instructions
+compiler.cfg.predecessors compiler.cfg.ssa.construction assocs
+compiler.cfg.registers cpu.architecture kernel namespaces sequences
+tools.test vectors ;
+IN: compiler.cfg.ssa.construction.tests
+
+: reset-counters ( -- )
+ ! Reset counters so that results are deterministic w.r.t. hash order
+ 0 vreg-counter set-global
+ 0 basic-block set-global ;
+
+reset-counters
+
+V{
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 1 50 }
+ T{ ##add-imm f 2 2 10 }
+ T{ ##branch }
+} 0 test-bb
+
+V{
+ T{ ##load-immediate f 3 3 }
+ T{ ##branch }
+} 1 test-bb
+
+V{
+ T{ ##load-immediate f 3 4 }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##replace f 3 D 0 }
+ T{ ##return }
+} 3 test-bb
+
+0 { 1 2 } edges
+1 3 edge
+2 3 edge
+
+: test-ssa ( -- )
+ cfg new 0 get >>entry
+ dup cfg set
+ construct-ssa
+ drop ;
+
+[ ] [ test-ssa ] unit-test
+
+[
+ V{
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 1 50 }
+ T{ ##add-imm f 3 2 10 }
+ T{ ##branch }
+ }
+] [ 0 get instructions>> ] unit-test
+
+[
+ V{
+ T{ ##load-immediate f 4 3 }
+ T{ ##branch }
+ }
+] [ 1 get instructions>> ] unit-test
+
+[
+ V{
+ T{ ##load-immediate f 5 4 }
+ T{ ##branch }
+ }
+] [ 2 get instructions>> ] unit-test
+
+: clean-up-phis ( insns -- insns' )
+ [ dup ##phi? [ [ [ [ number>> ] dip ] assoc-map ] change-inputs ] when ] map ;
+
+[
+ V{
+ T{ ##phi f 6 H{ { 1 4 } { 2 5 } } }
+ T{ ##replace f 6 D 0 }
+ T{ ##return }
+ }
+] [
+ 3 get instructions>>
+ clean-up-phis
+] unit-test
+
+reset-counters
+
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ T{ ##peek f 0 D 0 } } 2 test-bb
+V{ T{ ##peek f 0 D 0 } } 3 test-bb
+V{ T{ ##replace f 0 D 0 } } 4 test-bb
+V{ } 5 test-bb
+V{ } 6 test-bb
+
+0 { 1 5 } edges
+1 { 2 3 } edges
+2 4 edge
+3 4 edge
+4 6 edge
+5 6 edge
+
+[ ] [ test-ssa ] unit-test
+
+[
+ V{
+ T{ ##phi f 3 H{ { 2 1 } { 3 2 } } }
+ T{ ##replace f 3 D 0 }
+ }
+] [
+ 4 get instructions>>
+ clean-up-phis
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces kernel accessors sequences fry assocs
+sets math combinators
+compiler.cfg
+compiler.cfg.rpo
+compiler.cfg.def-use
+compiler.cfg.liveness
+compiler.cfg.registers
+compiler.cfg.dominance
+compiler.cfg.instructions
+compiler.cfg.renaming
+compiler.cfg.renaming.functor
+compiler.cfg.ssa.construction.tdmsc ;
+IN: compiler.cfg.ssa.construction
+
+! The phi placement algorithm is implemented in
+! compiler.cfg.ssa.construction.tdmsc.
+
+! The renaming algorithm is based on "Practical Improvements to
+! the Construction and Destruction of Static Single Assignment Form",
+! however we construct pruned SSA, not semi-pruned SSA.
+
+! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.49.9683
+
+<PRIVATE
+
+! Maps vregs to sets of basic blocks
+SYMBOL: defs
+
+! Set of vregs defined in more than one basic block
+SYMBOL: defs-multi
+
+: compute-insn-defs ( bb insn -- )
+ defs-vreg dup [
+ defs get [ conjoin-at ] [ drop ] [ at assoc-size 1 > ] 2tri
+ [ defs-multi get conjoin ] [ drop ] if
+ ] [ 2drop ] if ;
+
+: compute-defs ( cfg -- )
+ H{ } clone defs set
+ H{ } clone defs-multi set
+ [
+ dup instructions>> [
+ compute-insn-defs
+ ] with each
+ ] each-basic-block ;
+
+! Maps basic blocks to sequences of vregs
+SYMBOL: inserting-phi-nodes
+
+: insert-phi-node-later ( vreg bb -- )
+ 2dup live-in key? [
+ [ predecessors>> over '[ _ ] H{ } map>assoc \ ##phi new-insn ] keep
+ inserting-phi-nodes get push-at
+ ] [ 2drop ] if ;
+
+: compute-phi-nodes-for ( vreg bbs -- )
+ keys [ insert-phi-node-later ] with merge-set-each ;
+
+: compute-phi-nodes ( -- )
+ H{ } clone inserting-phi-nodes set
+ defs-multi get defs get '[ _ at compute-phi-nodes-for ] assoc-each ;
+
+: insert-phi-nodes-in ( phis bb -- )
+ [ append ] change-instructions drop ;
+
+: insert-phi-nodes ( -- )
+ inserting-phi-nodes get [ swap insert-phi-nodes-in ] assoc-each ;
+
+SYMBOLS: stacks pushed ;
+
+: init-renaming ( -- )
+ H{ } clone stacks set ;
+
+: gen-name ( vreg -- vreg' )
+ [ next-vreg dup ] dip
+ dup pushed get 2dup key?
+ [ 2drop stacks get at set-last ]
+ [ conjoin stacks get push-at ]
+ if ;
+
+: top-name ( vreg -- vreg' )
+ stacks get at last ;
+
+RENAMING: ssa-rename [ gen-name ] [ top-name ] [ ]
+
+GENERIC: rename-insn ( insn -- )
+
+M: insn rename-insn
+ [ ssa-rename-insn-uses ]
+ [ ssa-rename-insn-defs ]
+ bi ;
+
+M: ##phi rename-insn
+ ssa-rename-insn-defs ;
+
+: rename-insns ( bb -- )
+ instructions>> [ rename-insn ] each ;
+
+: rename-successor-phi ( phi bb -- )
+ swap inputs>> [ top-name ] change-at ;
+
+: rename-successor-phis ( succ bb -- )
+ [ inserting-phi-nodes get at ] dip
+ '[ _ rename-successor-phi ] each ;
+
+: rename-successors-phis ( bb -- )
+ [ successors>> ] keep '[ _ rename-successor-phis ] each ;
+
+: pop-stacks ( -- )
+ pushed get stacks get '[ drop _ at pop* ] assoc-each ;
+
+: rename-in-block ( bb -- )
+ H{ } clone pushed set
+ [ rename-insns ]
+ [ rename-successors-phis ]
+ [
+ pushed get
+ [ dom-children [ rename-in-block ] each ] dip
+ pushed set
+ ] tri
+ pop-stacks ;
+
+: rename ( cfg -- )
+ init-renaming
+ entry>> rename-in-block ;
+
+PRIVATE>
+
+: construct-ssa ( cfg -- cfg' )
+ {
+ [ compute-live-sets ]
+ [ compute-merge-sets ]
+ [ compute-defs compute-phi-nodes insert-phi-nodes ]
+ [ rename ]
+ [ ]
+ } cleave ;
\ No newline at end of file
--- /dev/null
+USING: accessors arrays compiler.cfg compiler.cfg.debugger
+compiler.cfg.dominance compiler.cfg.predecessors
+compiler.cfg.ssa.construction.tdmsc kernel namespaces sequences
+tools.test vectors sets ;
+IN: compiler.cfg.ssa.construction.tdmsc.tests
+
+: test-tdmsc ( -- )
+ cfg new 0 get >>entry dup cfg set
+ compute-merge-sets ;
+
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{ } 4 test-bb
+V{ } 5 test-bb
+
+0 { 1 2 } edges
+1 3 edge
+2 4 edge
+3 4 edge
+4 5 edge
+
+[ ] [ test-tdmsc ] unit-test
+
+[ V{ 4 } ] [ 1 get 1array merge-set [ number>> ] map ] unit-test
+[ V{ 4 } ] [ 2 get 1array merge-set [ number>> ] map ] unit-test
+[ V{ } ] [ 0 get 1array merge-set ] unit-test
+[ V{ } ] [ 4 get 1array merge-set ] unit-test
+
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{ } 4 test-bb
+V{ } 5 test-bb
+V{ } 6 test-bb
+
+0 { 1 5 } edges
+1 { 2 3 } edges
+2 4 edge
+3 4 edge
+4 6 edge
+5 6 edge
+
+[ ] [ test-tdmsc ] unit-test
+
+[ t ] [
+ 2 get 3 get 2array merge-set
+ 4 get 6 get 2array set=
+] unit-test
+
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{ } 4 test-bb
+V{ } 5 test-bb
+V{ } 6 test-bb
+V{ } 7 test-bb
+
+0 1 edge
+1 2 edge
+2 { 3 6 } edges
+3 4 edge
+6 7 edge
+4 5 edge
+5 2 edge
+
+[ ] [ test-tdmsc ] unit-test
+
+[ V{ 2 } ] [ { 2 3 4 5 } [ get ] map merge-set [ number>> ] map ] unit-test
+[ V{ } ] [ { 0 1 6 7 } [ get ] map merge-set ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs bit-arrays bit-sets fry
+hashtables hints kernel locals math namespaces sequences sets
+compiler.cfg compiler.cfg.dominance compiler.cfg.rpo ;
+IN: compiler.cfg.ssa.construction.tdmsc
+
+! TDMSC-I algorithm from "A Practical and Fast Iterative Algorithm for
+! Phi-Function Computation Using DJ Graphs"
+
+! http://portal.acm.org/citation.cfm?id=1065887.1065890
+
+<PRIVATE
+
+SYMBOLS: visited merge-sets levels again? ;
+
+: init-merge-sets ( cfg -- )
+ post-order dup length '[ _ <bit-array> ] H{ } map>assoc merge-sets set ;
+
+: compute-levels ( cfg -- )
+ 0 over entry>> associate [
+ '[
+ _ [ [ dom-parent ] dip at 1 + ] 2keep set-at
+ ] each-basic-block
+ ] keep levels set ;
+
+: j-edge? ( from to -- ? )
+ 2dup eq? [ 2drop f ] [ dominates? not ] if ;
+
+: level ( bb -- n ) levels get at ; inline
+
+: set-bit ( bit-array n -- )
+ [ t ] 2dip swap set-nth ;
+
+: update-merge-set ( tmp to -- )
+ [ merge-sets get ] dip
+ '[
+ _
+ [ merge-sets get at bit-set-union ]
+ [ dupd number>> set-bit ]
+ bi
+ ] change-at ;
+
+:: walk ( tmp to lnode -- lnode )
+ tmp level to level >= [
+ tmp to update-merge-set
+ tmp dom-parent to tmp walk
+ ] [ lnode ] if ;
+
+: each-incoming-j-edge ( bb quot: ( from to -- ) -- )
+ [ [ predecessors>> ] keep ] dip
+ '[ _ 2dup j-edge? _ [ 2drop ] if ] each ; inline
+
+: visited? ( pair -- ? ) visited get key? ;
+
+: consistent? ( snode lnode -- ? )
+ [ merge-sets get at ] bi@ swap bit-set-subset? ;
+
+: (process-edge) ( from to -- )
+ f walk [
+ 2dup 2array visited? [
+ consistent? [ again? on ] unless
+ ] [ 2drop ] if
+ ] each-incoming-j-edge ;
+
+: process-edge ( from to -- )
+ 2dup 2array dup visited? [ 3drop ] [
+ visited get conjoin
+ (process-edge)
+ ] if ;
+
+: process-block ( bb -- )
+ [ process-edge ] each-incoming-j-edge ;
+
+: compute-merge-set-step ( bfo -- )
+ visited get clear-assoc
+ [ process-block ] each ;
+
+: compute-merge-set-loop ( cfg -- )
+ breadth-first-order
+ '[ again? off _ compute-merge-set-step again? get ]
+ loop ;
+
+: (merge-set) ( bbs -- flags rpo )
+ merge-sets get '[ _ at ] [ bit-set-union ] map-reduce
+ cfg get reverse-post-order ; inline
+
+: filter-by ( flags seq -- seq' )
+ [ drop ] pusher [ 2each ] dip ;
+
+HINTS: filter-by { bit-array object } ;
+
+PRIVATE>
+
+: compute-merge-sets ( cfg -- )
+ needs-dominance
+
+ H{ } clone visited set
+ [ compute-levels ]
+ [ init-merge-sets ]
+ [ compute-merge-set-loop ]
+ tri ;
+
+: merge-set-each ( bbs quot: ( bb -- ) -- )
+ [ (merge-set) ] dip '[
+ swap _ [ drop ] if
+ ] 2each ; inline
+
+: merge-set ( bbs -- bbs' )
+ (merge-set) filter-by ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel locals fry
+cpu.architecture
+compiler.cfg.rpo
+compiler.cfg.utilities
+compiler.cfg.registers
+compiler.cfg.instructions
+compiler.cfg.representations ;
+IN: compiler.cfg.ssa.cssa
+
+! Convert SSA to conventional SSA. This pass runs after representation
+! selection, so it must keep track of representations when introducing
+! new values.
+
+:: insert-copy ( bb src rep -- bb dst )
+ rep next-vreg-rep :> dst
+ bb [ dst src rep src rep-of emit-conversion ] add-instructions
+ bb dst ;
+
+: convert-phi ( ##phi -- )
+ dup dst>> rep-of '[ [ _ insert-copy ] assoc-map ] change-inputs drop ;
+
+: construct-cssa ( cfg -- )
+ [ [ convert-phi ] each-phi ] each-basic-block ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs fry kernel namespaces
+sequences sequences.deep
+sets vectors
+compiler.cfg.rpo
+compiler.cfg.def-use
+compiler.cfg.renaming
+compiler.cfg.dominance
+compiler.cfg.instructions
+compiler.cfg.liveness.ssa
+compiler.cfg.ssa.cssa
+compiler.cfg.ssa.interference
+compiler.cfg.ssa.interference.live-ranges
+compiler.cfg.utilities
+compiler.utilities ;
+IN: compiler.cfg.ssa.destruction
+
+! Maps vregs to leaders.
+SYMBOL: leader-map
+
+: leader ( vreg -- vreg' ) leader-map get compress-path ;
+
+! Maps leaders to equivalence class elements.
+SYMBOL: class-element-map
+
+: class-elements ( vreg -- elts ) class-element-map get at ;
+
+! Sequence of vreg pairs
+SYMBOL: copies
+
+: init-coalescing ( -- )
+ H{ } clone leader-map set
+ H{ } clone class-element-map set
+ V{ } clone copies set ;
+
+: classes-interfere? ( vreg1 vreg2 -- ? )
+ [ leader ] bi@ 2dup eq? [ 2drop f ] [
+ [ class-elements flatten ] bi@ sets-interfere?
+ ] if ;
+
+: update-leaders ( vreg1 vreg2 -- )
+ swap leader-map get set-at ;
+
+: merge-classes ( vreg1 vreg2 -- )
+ [ [ class-elements ] bi@ push ]
+ [ drop class-element-map get delete-at ] 2bi ;
+
+: eliminate-copy ( vreg1 vreg2 -- )
+ [ leader ] bi@
+ 2dup eq? [ 2drop ] [
+ [ update-leaders ]
+ [ merge-classes ]
+ 2bi
+ ] if ;
+
+: introduce-vreg ( vreg -- )
+ [ leader-map get conjoin ]
+ [ [ 1vector ] keep class-element-map get set-at ] bi ;
+
+GENERIC: prepare-insn ( insn -- )
+
+M: ##copy prepare-insn
+ [ dst>> ] [ src>> ] bi 2array copies get push ;
+
+M: ##phi prepare-insn
+ [ dst>> ] [ inputs>> values ] bi
+ [ eliminate-copy ] with each ;
+
+M: insn prepare-insn drop ;
+
+: prepare-block ( bb -- )
+ instructions>> [ prepare-insn ] each ;
+
+: prepare-coalescing ( cfg -- )
+ init-coalescing
+ defs get keys [ introduce-vreg ] each
+ [ prepare-block ] each-basic-block ;
+
+: process-copies ( -- )
+ copies get [
+ 2dup classes-interfere?
+ [ 2drop ] [ eliminate-copy ] if
+ ] assoc-each ;
+
+: useless-copy? ( ##copy -- ? )
+ dup ##copy? [ [ dst>> ] [ src>> ] bi eq? ] [ drop f ] if ;
+
+: perform-renaming ( cfg -- )
+ leader-map get keys [ dup leader ] H{ } map>assoc renamings set
+ [
+ instructions>> [
+ [ rename-insn-defs ]
+ [ rename-insn-uses ]
+ [ [ useless-copy? ] [ ##phi? ] bi or not ] tri
+ ] filter-here
+ ] each-basic-block ;
+
+: destruct-ssa ( cfg -- cfg' )
+ needs-dominance
+
+ dup construct-cssa
+ dup compute-defs
+ compute-ssa-live-sets
+ dup compute-live-ranges
+ dup prepare-coalescing
+ process-copies
+ dup perform-renaming ;
\ No newline at end of file
--- /dev/null
+USING: accessors compiler.cfg compiler.cfg.debugger
+compiler.cfg.def-use compiler.cfg.dominance
+compiler.cfg.instructions compiler.cfg.liveness.ssa
+compiler.cfg.registers compiler.cfg.predecessors
+compiler.cfg.ssa.interference
+compiler.cfg.ssa.interference.live-ranges cpu.architecture
+kernel namespaces tools.test ;
+IN: compiler.cfg.ssa.interference.tests
+
+: test-interference ( -- )
+ cfg new 0 get >>entry
+ compute-ssa-live-sets
+ dup compute-defs
+ compute-live-ranges ;
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 2 D 0 }
+ T{ ##copy f 1 0 }
+ T{ ##copy f 3 2 }
+ T{ ##branch }
+} 0 test-bb
+
+V{
+ T{ ##peek f 4 D 0 }
+ T{ ##peek f 5 D 0 }
+ T{ ##replace f 3 D 0 }
+ T{ ##peek f 6 D 0 }
+ T{ ##replace f 5 D 0 }
+ T{ ##return }
+} 1 test-bb
+
+0 1 edge
+
+[ ] [ test-interference ] unit-test
+
+[ f ] [ 0 1 vregs-interfere? ] unit-test
+[ f ] [ 1 0 vregs-interfere? ] unit-test
+[ f ] [ 2 3 vregs-interfere? ] unit-test
+[ f ] [ 3 2 vregs-interfere? ] unit-test
+[ t ] [ 0 2 vregs-interfere? ] unit-test
+[ t ] [ 2 0 vregs-interfere? ] unit-test
+[ f ] [ 1 3 vregs-interfere? ] unit-test
+[ f ] [ 3 1 vregs-interfere? ] unit-test
+[ t ] [ 3 4 vregs-interfere? ] unit-test
+[ t ] [ 4 3 vregs-interfere? ] unit-test
+[ t ] [ 3 5 vregs-interfere? ] unit-test
+[ t ] [ 5 3 vregs-interfere? ] unit-test
+[ f ] [ 3 6 vregs-interfere? ] unit-test
+[ f ] [ 6 3 vregs-interfere? ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators combinators.short-circuit fry
+kernel math math.order sorting namespaces sequences locals
+compiler.cfg.def-use compiler.cfg.dominance
+compiler.cfg.ssa.interference.live-ranges ;
+IN: compiler.cfg.ssa.interference
+
+! Interference testing using SSA properties. Actually the only SSA property
+! used here is that definitions dominate uses; because of this, the input
+! is allowed to have multiple definitions of each vreg as long as they're
+! all in the same basic block. This is needed because two-operand conversion
+! runs before coalescing, which uses SSA interference testing.
+<PRIVATE
+
+:: kill-after-def? ( vreg1 vreg2 bb -- ? )
+ ! If first register is used after second one is defined, they interfere.
+ ! If they are used in the same instruction, no interference. If the
+ ! instruction is a def-is-use-insn, then there will be a use at +1
+ ! (instructions are 2 apart) and so outputs will interfere with
+ ! inputs.
+ vreg1 bb kill-index
+ vreg2 bb def-index > ;
+
+:: interferes-same-block? ( vreg1 vreg2 bb1 bb2 -- ? )
+ ! If both are defined in the same basic block, they interfere if their
+ ! local live ranges intersect.
+ vreg1 bb1 def-index
+ vreg2 bb1 def-index <
+ [ vreg1 vreg2 ] [ vreg2 vreg1 ] if
+ bb1 kill-after-def? ;
+
+: interferes-first-dominates? ( vreg1 vreg2 bb1 bb2 -- ? )
+ ! If vreg1 dominates vreg2, then they interfere if vreg2's definition
+ ! occurs before vreg1 is killed.
+ nip
+ kill-after-def? ;
+
+: interferes-second-dominates? ( vreg1 vreg2 bb1 bb2 -- ? )
+ ! If vreg2 dominates vreg1, then they interfere if vreg1's definition
+ ! occurs before vreg2 is killed.
+ drop
+ swapd kill-after-def? ;
+
+PRIVATE>
+
+: vregs-interfere? ( vreg1 vreg2 -- ? )
+ 2dup [ def-of ] bi@ {
+ { [ 2dup eq? ] [ interferes-same-block? ] }
+ { [ 2dup dominates? ] [ interferes-first-dominates? ] }
+ { [ 2dup swap dominates? ] [ interferes-second-dominates? ] }
+ [ 2drop 2drop f ]
+ } cond ;
+
+<PRIVATE
+
+! Debug this stuff later
+
+: quadratic-test? ( seq1 seq2 -- ? ) [ length ] bi@ + 10 < ;
+
+: quadratic-test ( seq1 seq2 -- ? )
+ '[ _ [ vregs-interfere? ] with any? ] any? ;
+
+: sort-vregs-by-bb ( vregs -- alist )
+ defs get
+ '[ dup _ at ] { } map>assoc
+ [ second pre-of ] sort-with ;
+
+: ?last ( seq -- elt/f ) [ f ] [ last ] if-empty ; inline
+
+: find-parent ( dom current -- parent )
+ over empty? [ 2drop f ] [
+ over last over dominates? [ drop last ] [
+ over pop* find-parent
+ ] if
+ ] if ;
+
+:: linear-test ( seq1 seq2 -- ? )
+ ! Instead of sorting, SSA destruction should keep equivalence
+ ! classes sorted by merging them on append
+ V{ } clone :> dom
+ seq1 seq2 append sort-vregs-by-bb [| pair |
+ pair first :> current
+ dom current find-parent
+ dup [ current vregs-interfere? ] when
+ [ t ] [ current dom push f ] if
+ ] any? ;
+
+PRIVATE>
+
+: sets-interfere? ( seq1 seq2 -- ? )
+ quadratic-test ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs fry kernel namespaces sequences math
+arrays compiler.cfg.def-use compiler.cfg.instructions
+compiler.cfg.liveness.ssa compiler.cfg.rpo compiler.cfg.dominance ;
+IN: compiler.cfg.ssa.interference.live-ranges
+
+! Live ranges for interference testing
+
+<PRIVATE
+
+SYMBOLS: local-def-indices local-kill-indices ;
+
+: record-def ( n vreg -- )
+ ! We allow multiple defs of a vreg as long as they're
+ ! all in the same basic block
+ dup [
+ local-def-indices get 2dup key?
+ [ 3drop ] [ set-at ] if
+ ] [ 2drop ] if ;
+
+: record-uses ( n vregs -- )
+ local-kill-indices get '[ _ set-at ] with each ;
+
+: visit-insn ( insn n -- )
+ ! Instructions are numbered 2 apart. If the instruction requires
+ ! that outputs are in different registers than the inputs, then
+ ! a use will be registered for every output immediately after
+ ! this instruction and before the next one, ensuring that outputs
+ ! interfere with inputs.
+ 2 *
+ [ swap defs-vreg record-def ]
+ [ swap uses-vregs record-uses ]
+ [ over def-is-use-insn? [ 1 + swap defs-vreg 1array record-uses ] [ 2drop ] if ]
+ 2tri ;
+
+SYMBOLS: def-indices kill-indices ;
+
+: compute-local-live-ranges ( bb -- )
+ H{ } clone local-def-indices set
+ H{ } clone local-kill-indices set
+ [ instructions>> [ visit-insn ] each-index ]
+ [ [ local-def-indices get ] dip def-indices get set-at ]
+ [ [ local-kill-indices get ] dip kill-indices get set-at ]
+ tri ;
+
+PRIVATE>
+
+: compute-live-ranges ( cfg -- )
+ needs-dominance
+
+ H{ } clone def-indices set
+ H{ } clone kill-indices set
+ [ compute-local-live-ranges ] each-basic-block ;
+
+: def-index ( vreg bb -- n )
+ def-indices get at at ;
+
+ERROR: bad-kill-index vreg bb ;
+
+: kill-index ( vreg bb -- n )
+ 2dup live-out? [ 2drop 1/0. ] [
+ 2dup kill-indices get at at* [ 2nip ] [
+ drop 2dup live-in?
+ [ bad-kill-index ] [ 2drop -1/0. ] if
+ ] if
+ ] if ;
--- /dev/null
+! Copyright (C) 2009 Daniel Ehrenberg
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel tools.test namespaces sequences vectors accessors sets
+arrays math.ranges assocs
+cpu.architecture
+compiler.cfg
+compiler.cfg.ssa.liveness.private
+compiler.cfg.ssa.liveness
+compiler.cfg.debugger
+compiler.cfg.instructions
+compiler.cfg.predecessors
+compiler.cfg.registers
+compiler.cfg.dominance
+compiler.cfg.def-use ;
+IN: compiler.cfg.ssa.liveness
+
+[ t ] [ { 1 } 1 only? ] unit-test
+[ t ] [ { } 1 only? ] unit-test
+[ f ] [ { 2 1 } 1 only? ] unit-test
+[ f ] [ { 2 } 1 only? ] unit-test
+
+: test-liveness ( -- )
+ cfg new 0 get >>entry
+ dup compute-defs
+ dup compute-uses
+ needs-dominance
+ precompute-liveness ;
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+} 0 test-bb
+
+V{
+ T{ ##replace f 2 D 0 }
+} 1 test-bb
+
+V{
+ T{ ##replace f 3 D 0 }
+} 2 test-bb
+
+0 { 1 2 } edges
+
+[ ] [ test-liveness ] unit-test
+
+[ H{ } ] [ back-edge-targets get ] unit-test
+[ t ] [ 0 get R_q { 0 1 2 } [ get ] map unique = ] unit-test
+[ t ] [ 1 get R_q { 1 } [ get ] map unique = ] unit-test
+[ t ] [ 2 get R_q { 2 } [ get ] map unique = ] unit-test
+
+: self-T_q ( n -- ? )
+ get [ T_q ] [ 1array unique ] bi = ;
+
+[ t ] [ 0 self-T_q ] unit-test
+[ t ] [ 1 self-T_q ] unit-test
+[ t ] [ 2 self-T_q ] unit-test
+
+[ f ] [ 0 0 get live-in? ] unit-test
+[ t ] [ 1 0 get live-in? ] unit-test
+[ t ] [ 2 0 get live-in? ] unit-test
+[ t ] [ 3 0 get live-in? ] unit-test
+
+[ f ] [ 0 0 get live-out? ] unit-test
+[ f ] [ 1 0 get live-out? ] unit-test
+[ t ] [ 2 0 get live-out? ] unit-test
+[ t ] [ 3 0 get live-out? ] unit-test
+
+[ f ] [ 0 1 get live-in? ] unit-test
+[ f ] [ 1 1 get live-in? ] unit-test
+[ t ] [ 2 1 get live-in? ] unit-test
+[ f ] [ 3 1 get live-in? ] unit-test
+
+[ f ] [ 0 1 get live-out? ] unit-test
+[ f ] [ 1 1 get live-out? ] unit-test
+[ f ] [ 2 1 get live-out? ] unit-test
+[ f ] [ 3 1 get live-out? ] unit-test
+
+[ f ] [ 0 2 get live-in? ] unit-test
+[ f ] [ 1 2 get live-in? ] unit-test
+[ f ] [ 2 2 get live-in? ] unit-test
+[ t ] [ 3 2 get live-in? ] unit-test
+
+[ f ] [ 0 2 get live-out? ] unit-test
+[ f ] [ 1 2 get live-out? ] unit-test
+[ f ] [ 2 2 get live-out? ] unit-test
+[ f ] [ 3 2 get live-out? ] unit-test
+
+V{ } 0 test-bb
+V{ } 1 test-bb
+V{ } 2 test-bb
+V{ } 3 test-bb
+V{
+ T{ ##phi f 2 H{ { 2 0 } { 3 1 } } }
+} 4 test-bb
+test-diamond
+
+[ ] [ test-liveness ] unit-test
+
+[ t ] [ 0 1 get live-in? ] unit-test
+[ t ] [ 1 1 get live-in? ] unit-test
+[ f ] [ 2 1 get live-in? ] unit-test
+
+[ t ] [ 0 1 get live-out? ] unit-test
+[ t ] [ 1 1 get live-out? ] unit-test
+[ f ] [ 2 1 get live-out? ] unit-test
+
+[ t ] [ 0 2 get live-in? ] unit-test
+[ f ] [ 1 2 get live-in? ] unit-test
+[ f ] [ 2 2 get live-in? ] unit-test
+
+[ f ] [ 0 2 get live-out? ] unit-test
+[ f ] [ 1 2 get live-out? ] unit-test
+[ f ] [ 2 2 get live-out? ] unit-test
+
+[ f ] [ 0 3 get live-in? ] unit-test
+[ t ] [ 1 3 get live-in? ] unit-test
+[ f ] [ 2 3 get live-in? ] unit-test
+
+[ f ] [ 0 3 get live-out? ] unit-test
+[ f ] [ 1 3 get live-out? ] unit-test
+[ f ] [ 2 3 get live-out? ] unit-test
+
+[ f ] [ 0 4 get live-in? ] unit-test
+[ f ] [ 1 4 get live-in? ] unit-test
+[ f ] [ 2 4 get live-in? ] unit-test
+
+[ f ] [ 0 4 get live-out? ] unit-test
+[ f ] [ 1 4 get live-out? ] unit-test
+[ f ] [ 2 4 get live-out? ] unit-test
+
+! This is the CFG in Figure 3 from the paper
+V{ } 0 test-bb
+V{ } 1 test-bb
+0 1 edge
+V{ } 2 test-bb
+1 2 edge
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 0 }
+ T{ ##peek f 2 D 0 }
+} 3 test-bb
+V{ } 11 test-bb
+2 { 3 11 } edges
+V{
+ T{ ##replace f 0 D 0 }
+} 4 test-bb
+V{ } 8 test-bb
+3 { 8 4 } edges
+V{
+ T{ ##replace f 1 D 0 }
+} 9 test-bb
+8 9 edge
+V{
+ T{ ##replace f 2 D 0 }
+} 5 test-bb
+4 5 edge
+V{ } 10 test-bb
+V{ } 6 test-bb
+5 6 edge
+9 { 6 10 } edges
+V{ } 7 test-bb
+6 { 5 7 } edges
+10 8 edge
+7 2 edge
+
+[ ] [ test-liveness ] unit-test
+
+[ t ] [ 1 get R_q 1 11 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 2 get R_q 2 11 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 3 get R_q 3 10 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 4 get R_q 4 7 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 5 get R_q 5 7 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 6 get R_q 6 7 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 7 get R_q 7 7 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 8 get R_q 6 10 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 9 get R_q 8 6 10 [a,b] remove [ get ] map unique = ] unit-test
+[ t ] [ 10 get R_q 10 10 [a,b] [ get ] map unique = ] unit-test
+[ t ] [ 11 get R_q 11 11 [a,b] [ get ] map unique = ] unit-test
+
+[ t ] [ 1 get T_q 1 get 1array unique = ] unit-test
+[ t ] [ 2 get T_q 2 get 1array unique = ] unit-test
+[ t ] [ 3 get T_q 3 get 2 get 2array unique = ] unit-test
+[ t ] [ 4 get T_q 4 get 2 get 2array unique = ] unit-test
+[ t ] [ 5 get T_q 5 get 2 get 2array unique = ] unit-test
+[ t ] [ 6 get T_q { 6 2 5 } [ get ] map unique = ] unit-test
+[ t ] [ 7 get T_q { 7 2 } [ get ] map unique = ] unit-test
+[ t ] [ 8 get T_q { 8 2 5 } [ get ] map unique = ] unit-test
+[ t ] [ 9 get T_q { 2 5 8 9 } [ get ] map unique = ] unit-test
+[ t ] [ 10 get T_q { 2 5 8 10 } [ get ] map unique = ] unit-test
+[ t ] [ 11 get T_q 11 get 1array unique = ] unit-test
+
+[ f ] [ 1 get back-edge-target? ] unit-test
+[ t ] [ 2 get back-edge-target? ] unit-test
+[ f ] [ 3 get back-edge-target? ] unit-test
+[ f ] [ 4 get back-edge-target? ] unit-test
+[ t ] [ 5 get back-edge-target? ] unit-test
+[ f ] [ 6 get back-edge-target? ] unit-test
+[ f ] [ 7 get back-edge-target? ] unit-test
+[ t ] [ 8 get back-edge-target? ] unit-test
+[ f ] [ 9 get back-edge-target? ] unit-test
+[ f ] [ 10 get back-edge-target? ] unit-test
+[ f ] [ 11 get back-edge-target? ] unit-test
+
+[ f ] [ 0 1 get live-in? ] unit-test
+[ f ] [ 1 1 get live-in? ] unit-test
+[ f ] [ 2 1 get live-in? ] unit-test
+
+[ f ] [ 0 1 get live-out? ] unit-test
+[ f ] [ 1 1 get live-out? ] unit-test
+[ f ] [ 2 1 get live-out? ] unit-test
+
+[ f ] [ 0 2 get live-in? ] unit-test
+[ f ] [ 1 2 get live-in? ] unit-test
+[ f ] [ 2 2 get live-in? ] unit-test
+
+[ f ] [ 0 2 get live-out? ] unit-test
+[ f ] [ 1 2 get live-out? ] unit-test
+[ f ] [ 2 2 get live-out? ] unit-test
+
+[ f ] [ 0 3 get live-in? ] unit-test
+[ f ] [ 1 3 get live-in? ] unit-test
+[ f ] [ 2 3 get live-in? ] unit-test
+
+[ t ] [ 0 3 get live-out? ] unit-test
+[ t ] [ 1 3 get live-out? ] unit-test
+[ t ] [ 2 3 get live-out? ] unit-test
+
+[ t ] [ 0 4 get live-in? ] unit-test
+[ f ] [ 1 4 get live-in? ] unit-test
+[ t ] [ 2 4 get live-in? ] unit-test
+
+[ f ] [ 0 4 get live-out? ] unit-test
+[ f ] [ 1 4 get live-out? ] unit-test
+[ t ] [ 2 4 get live-out? ] unit-test
+
+[ f ] [ 0 5 get live-in? ] unit-test
+[ f ] [ 1 5 get live-in? ] unit-test
+[ t ] [ 2 5 get live-in? ] unit-test
+
+[ f ] [ 0 5 get live-out? ] unit-test
+[ f ] [ 1 5 get live-out? ] unit-test
+[ t ] [ 2 5 get live-out? ] unit-test
+
+[ f ] [ 0 6 get live-in? ] unit-test
+[ f ] [ 1 6 get live-in? ] unit-test
+[ t ] [ 2 6 get live-in? ] unit-test
+
+[ f ] [ 0 6 get live-out? ] unit-test
+[ f ] [ 1 6 get live-out? ] unit-test
+[ t ] [ 2 6 get live-out? ] unit-test
+
+[ f ] [ 0 7 get live-in? ] unit-test
+[ f ] [ 1 7 get live-in? ] unit-test
+[ f ] [ 2 7 get live-in? ] unit-test
+
+[ f ] [ 0 7 get live-out? ] unit-test
+[ f ] [ 1 7 get live-out? ] unit-test
+[ f ] [ 2 7 get live-out? ] unit-test
+
+[ f ] [ 0 8 get live-in? ] unit-test
+[ t ] [ 1 8 get live-in? ] unit-test
+[ t ] [ 2 8 get live-in? ] unit-test
+
+[ f ] [ 0 8 get live-out? ] unit-test
+[ t ] [ 1 8 get live-out? ] unit-test
+[ t ] [ 2 8 get live-out? ] unit-test
+
+[ f ] [ 0 9 get live-in? ] unit-test
+[ t ] [ 1 9 get live-in? ] unit-test
+[ t ] [ 2 9 get live-in? ] unit-test
+
+[ f ] [ 0 9 get live-out? ] unit-test
+[ t ] [ 1 9 get live-out? ] unit-test
+[ t ] [ 2 9 get live-out? ] unit-test
+
+[ f ] [ 0 10 get live-in? ] unit-test
+[ t ] [ 1 10 get live-in? ] unit-test
+[ t ] [ 2 10 get live-in? ] unit-test
+
+[ f ] [ 0 10 get live-out? ] unit-test
+[ t ] [ 1 10 get live-out? ] unit-test
+[ t ] [ 2 10 get live-out? ] unit-test
+
+[ f ] [ 0 11 get live-in? ] unit-test
+[ f ] [ 1 11 get live-in? ] unit-test
+[ f ] [ 2 11 get live-in? ] unit-test
+
+[ f ] [ 0 11 get live-out? ] unit-test
+[ f ] [ 1 11 get live-out? ] unit-test
+[ f ] [ 2 11 get live-out? ] unit-test
--- /dev/null
+! Copyright (C) 2009 Daniel Ehrenberg
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel sequences assocs accessors
+namespaces fry math sets combinators locals
+compiler.cfg.rpo
+compiler.cfg.dominance
+compiler.cfg.def-use
+compiler.cfg.instructions ;
+IN: compiler.cfg.ssa.liveness
+
+! Liveness checking on SSA IR, as described in
+! "Fast Liveness Checking for SSA-Form Programs", Sebastian Hack et al.
+! http://hal.archives-ouvertes.fr/docs/00/19/22/19/PDF/fast_liveness.pdf
+
+<PRIVATE
+
+! The sets T_q and R_q are described there
+SYMBOL: T_q-sets
+SYMBOL: R_q-sets
+
+! Targets of back edges
+SYMBOL: back-edge-targets
+
+: T_q ( q -- T_q )
+ T_q-sets get at ;
+
+: R_q ( q -- R_q )
+ R_q-sets get at ;
+
+: back-edge-target? ( block -- ? )
+ back-edge-targets get key? ;
+
+: next-R_q ( q -- R_q )
+ [ ] [ successors>> ] [ number>> ] tri
+ '[ number>> _ >= ] filter
+ [ R_q ] map assoc-combine
+ [ conjoin ] keep ;
+
+: set-R_q ( q -- )
+ [ next-R_q ] keep R_q-sets get set-at ;
+
+: set-back-edges ( q -- )
+ [ successors>> ] [ number>> ] bi '[
+ dup number>> _ <
+ [ back-edge-targets get conjoin ] [ drop ] if
+ ] each ;
+
+: init-R_q ( -- )
+ H{ } clone R_q-sets set
+ H{ } clone back-edge-targets set ;
+
+: compute-R_q ( cfg -- )
+ init-R_q
+ post-order [
+ [ set-R_q ] [ set-back-edges ] bi
+ ] each ;
+
+! This algorithm for computing T_q uses equation (1)
+! but not the faster algorithm described in the paper
+
+: back-edges-from ( q -- edges )
+ R_q keys [
+ [ successors>> ] [ number>> ] bi
+ '[ number>> _ < ] filter
+ ] gather ;
+
+: T^_q ( q -- T^_q )
+ [ back-edges-from ] [ R_q ] bi
+ '[ _ key? not ] filter ;
+
+: next-T_q ( q -- T_q )
+ dup dup T^_q [ next-T_q keys ] map
+ concat unique [ conjoin ] keep
+ [ swap T_q-sets get set-at ] keep ;
+
+: compute-T_q ( cfg -- )
+ H{ } T_q-sets set
+ [ next-T_q drop ] each-basic-block ;
+
+PRIVATE>
+
+: precompute-liveness ( cfg -- )
+ [ compute-R_q ] [ compute-T_q ] bi ;
+
+<PRIVATE
+
+! This doesn't take advantage of ordering T_q,a so you
+! only have to check one if the CFG is reducible.
+! It should be changed to be more efficient.
+
+: only? ( seq obj -- ? )
+ '[ _ eq? ] all? ;
+
+: strictly-dominates? ( bb1 bb2 -- ? )
+ [ dominates? ] [ eq? not ] 2bi and ;
+
+: T_q,a ( a q -- T_q,a )
+ ! This could take advantage of the structure of dominance,
+ ! but probably I'll replace it with the algorithm that works
+ ! on reducible CFGs anyway
+ T_q keys swap def-of
+ [ '[ _ swap strictly-dominates? ] filter ] when* ;
+
+: live? ( vreg node quot -- ? )
+ [ [ T_q,a ] [ drop uses-of ] 2bi ] dip
+ '[ [ R_q keys _ ] keep @ intersects? ] any? ; inline
+
+PRIVATE>
+
+: live-in? ( vreg node -- ? )
+ [ drop ] live? ;
+
+<PRIVATE
+
+: (live-out?) ( vreg node -- ? )
+ dup dup dup '[
+ _ = _ back-edge-target? not and
+ [ _ swap remove ] when
+ ] live? ;
+
+PRIVATE>
+
+:: live-out? ( vreg node -- ? )
+ [let | def [ vreg def-of ] |
+ {
+ { [ node def eq? ] [ vreg uses-of def only? not ] }
+ { [ def node strictly-dominates? ] [ vreg node (live-out?) ] }
+ [ f ]
+ } cond
+ ] ;
+++ /dev/null
-Slava Pestov
\ No newline at end of file
+++ /dev/null
-USING: prettyprint compiler.cfg.debugger compiler.cfg.linearization
-compiler.cfg.predecessors compiler.cfg.stack-analysis
-compiler.cfg.instructions sequences kernel tools.test accessors
-sequences.private alien math combinators.private compiler.cfg
-compiler.cfg.checker compiler.cfg.height compiler.cfg.rpo
-compiler.cfg.dce compiler.cfg.registers compiler.cfg.useless-blocks
-sets ;
-IN: compiler.cfg.stack-analysis.tests
-
-! Fundamental invariant: a basic block should not load or store a value more than once
-: check-for-redundant-ops ( cfg -- )
- [
- instructions>>
- [
- [ ##peek? ] filter [ loc>> ] map duplicates empty?
- [ "Redundant peeks" throw ] unless
- ] [
- [ ##replace? ] filter [ loc>> ] map duplicates empty?
- [ "Redundant replaces" throw ] unless
- ] bi
- ] each-basic-block ;
-
-: test-stack-analysis ( quot -- cfg )
- dup cfg? [ test-cfg first ] unless
- compute-predecessors
- delete-useless-blocks
- delete-useless-conditionals
- normalize-height
- stack-analysis
- dup check-cfg
- dup check-for-redundant-ops ;
-
-: linearize ( cfg -- mr )
- flatten-cfg instructions>> ;
-
-[ ] [ [ ] test-stack-analysis drop ] unit-test
-
-! Only peek once
-[ 1 ] [ [ dup drop dup ] test-stack-analysis linearize [ ##peek? ] count ] unit-test
-
-! Redundant replace is redundant
-[ f ] [ [ dup drop ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test
-[ f ] [ [ swap swap ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test
-
-! Replace required here
-[ t ] [ [ dup ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test
-[ t ] [ [ [ drop 1 ] when ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test
-
-! Only one replace, at the end
-[ 1 ] [ [ [ 1 ] [ 2 ] if ] test-stack-analysis linearize [ ##replace? ] count ] unit-test
-
-! Do we support the full language?
-[ ] [ [ { [ ] [ ] } dispatch ] test-stack-analysis drop ] unit-test
-[ ] [ [ { [ ] [ ] } dispatch dup ] test-stack-analysis drop ] unit-test
-[ ] [
- [ "int" { "int" "int" } "cdecl" [ + ] alien-callback ]
- test-cfg second test-stack-analysis drop
-] unit-test
-
-! Test loops
-[ ] [ [ [ t ] loop ] test-stack-analysis drop ] unit-test
-[ ] [ [ [ dup ] loop ] test-stack-analysis drop ] unit-test
-
-! Make sure that peeks are inserted in the right place
-[ ] [ [ [ drop 1 ] when ] test-stack-analysis drop ] unit-test
-
-! This should be a total no-op
-[ f ] [ [ [ ] dip ] test-stack-analysis linearize [ ##replace? ] any? ] unit-test
-
-! Don't insert inc-d/inc-r; that's wrong!
-[ 1 ] [ [ dup ] test-stack-analysis linearize [ ##inc-d? ] count ] unit-test
-
-! Bug in height tracking
-[ ] [ [ dup [ ] [ reverse ] if ] test-stack-analysis drop ] unit-test
-[ ] [ [ dup [ ] [ dup reverse drop ] if ] test-stack-analysis drop ] unit-test
-[ ] [ [ [ drop dup 4.0 > ] find-last-integer ] test-stack-analysis drop ] unit-test
-
-! Bugs with code that throws
-[ ] [ [ [ "Oops" throw ] unless ] test-stack-analysis drop ] unit-test
-[ ] [ [ [ ] (( -- * )) call-effect-unsafe ] test-stack-analysis drop ] unit-test
-[ ] [ [ dup [ "Oops" throw ] when dup ] test-stack-analysis drop ] unit-test
-[ ] [ [ B{ 1 2 3 4 } over [ "Oops" throw ] when swap ] test-stack-analysis drop ] unit-test
-
-! Make sure the replace stores a value with the right height
-[ ] [
- [ [ . ] [ 2drop 1 ] if ] test-stack-analysis eliminate-dead-code linearize
- [ ##replace? ] filter [ length 1 assert= ] [ first loc>> D 0 assert= ] bi
-] unit-test
-
-! translate-loc was the wrong way round
-[ ] [
- [ 1 2 rot ] test-stack-analysis eliminate-dead-code linearize
- [ [ ##load-immediate? ] count 2 assert= ]
- [ [ ##peek? ] count 1 assert= ]
- [ [ ##replace? ] count 3 assert= ]
- tri
-] unit-test
-
-[ ] [
- [ 1 2 ? ] test-stack-analysis eliminate-dead-code linearize
- [ [ ##load-immediate? ] count 2 assert= ]
- [ [ ##peek? ] count 1 assert= ]
- [ [ ##replace? ] count 1 assert= ]
- tri
-] unit-test
-
-! Sync before a back-edge, not after
-! ##peeks should be inserted before a ##loop-entry
-! Don't optimize out the constants
-[ 1 t ] [
- [ 1000 [ ] times ] test-stack-analysis eliminate-dead-code linearize
- [ [ ##add-imm? ] count ] [ [ ##load-immediate? ] any? ] bi
-] unit-test
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs kernel namespaces math sequences fry grouping
-sets make combinators compiler.cfg.copy-prop compiler.cfg.def-use
-compiler.cfg.instructions compiler.cfg.registers compiler.cfg.rpo
-compiler.cfg.hats compiler.cfg ;
-IN: compiler.cfg.stack-analysis
-
-! Convert stack operations to register operations
-
-! If 'poisoned' is set, disregard height information. This is set if we don't have
-! height change information for an instruction.
-TUPLE: state locs>vregs actual-locs>vregs changed-locs ds-height rs-height poisoned? ;
-
-: <state> ( -- state )
- state new
- H{ } clone >>locs>vregs
- H{ } clone >>actual-locs>vregs
- H{ } clone >>changed-locs
- 0 >>ds-height
- 0 >>rs-height ;
-
-M: state clone
- call-next-method
- [ clone ] change-locs>vregs
- [ clone ] change-actual-locs>vregs
- [ clone ] change-changed-locs ;
-
-: loc>vreg ( loc -- vreg ) state get locs>vregs>> at ;
-
-: record-peek ( dst loc -- )
- state get [ locs>vregs>> set-at ] [ actual-locs>vregs>> set-at ] 3bi ;
-
-: changed-loc ( loc -- )
- state get changed-locs>> conjoin ;
-
-: record-replace ( src loc -- )
- dup changed-loc state get locs>vregs>> set-at ;
-
-GENERIC: height-for ( loc -- n )
-
-M: ds-loc height-for drop state get ds-height>> ;
-M: rs-loc height-for drop state get rs-height>> ;
-
-: (translate-loc) ( loc -- n height ) [ n>> ] [ height-for ] bi ; inline
-
-GENERIC: translate-loc ( loc -- loc' )
-
-M: ds-loc translate-loc (translate-loc) - <ds-loc> ;
-M: rs-loc translate-loc (translate-loc) - <rs-loc> ;
-
-GENERIC: untranslate-loc ( loc -- loc' )
-
-M: ds-loc untranslate-loc (translate-loc) + <ds-loc> ;
-M: rs-loc untranslate-loc (translate-loc) + <rs-loc> ;
-
-: redundant-replace? ( vreg loc -- ? )
- dup untranslate-loc n>> 0 <
- [ 2drop t ] [ state get actual-locs>vregs>> at = ] if ;
-
-: save-changed-locs ( state -- )
- [ changed-locs>> ] [ locs>vregs>> ] bi '[
- _ at swap 2dup redundant-replace?
- [ 2drop ] [ untranslate-loc ##replace ] if
- ] assoc-each ;
-
-: clear-state ( state -- )
- [ locs>vregs>> clear-assoc ]
- [ actual-locs>vregs>> clear-assoc ]
- [ changed-locs>> clear-assoc ]
- tri ;
-
-ERROR: poisoned-state state ;
-
-: sync-state ( -- )
- state get {
- [ dup poisoned?>> [ poisoned-state ] [ drop ] if ]
- [ save-changed-locs ]
- [ clear-state ]
- } cleave ;
-
-: poison-state ( -- ) state get t >>poisoned? drop ;
-
-! Abstract interpretation
-GENERIC: visit ( insn -- )
-
-! Instructions which don't have any effect on the stack
-UNION: neutral-insn
- ##flushable
- ##effect ;
-
-M: neutral-insn visit , ;
-
-UNION: sync-if-back-edge
- ##branch
- ##conditional-branch
- ##compare-imm-branch
- ##dispatch
- ##loop-entry ;
-
-SYMBOL: local-only?
-
-t local-only? set-global
-
-: back-edge? ( from to -- ? )
- [ number>> ] bi@ > ;
-
-: sync-state? ( -- ? )
- basic-block get successors>>
- [ [ predecessors>> ] keep '[ _ back-edge? ] any? ] any?
- local-only? get or ;
-
-M: sync-if-back-edge visit
- sync-state? [ sync-state ] when , ;
-
-: adjust-d ( n -- ) state get [ + ] change-ds-height drop ;
-
-M: ##inc-d visit [ , ] [ n>> adjust-d ] bi ;
-
-: adjust-r ( n -- ) state get [ + ] change-rs-height drop ;
-
-M: ##inc-r visit [ , ] [ n>> adjust-r ] bi ;
-
-: eliminate-peek ( dst src -- )
- ! the requested stack location is already in 'src'
- [ ##copy ] [ swap copies get set-at ] 2bi ;
-
-M: ##peek visit
- dup
- [ dst>> ] [ loc>> translate-loc ] bi
- dup loc>vreg dup [ nip eliminate-peek drop ] [ drop record-peek , ] if ;
-
-M: ##replace visit
- [ src>> resolve ] [ loc>> translate-loc ] bi
- record-replace ;
-
-M: ##copy visit
- [ call-next-method ] [ record-copy ] bi ;
-
-M: ##call visit
- [ call-next-method ] [ height>> adjust-d ] bi ;
-
-! Instructions that poison the stack state
-UNION: poison-insn
- ##jump
- ##return
- ##callback-return
- ##fixnum-mul-tail
- ##fixnum-add-tail
- ##fixnum-sub-tail ;
-
-M: poison-insn visit call-next-method poison-state ;
-
-! Instructions that kill all live vregs
-UNION: kill-vreg-insn
- poison-insn
- ##stack-frame
- ##call
- ##prologue
- ##epilogue
- ##fixnum-mul
- ##fixnum-add
- ##fixnum-sub
- ##alien-invoke
- ##alien-indirect ;
-
-M: kill-vreg-insn visit sync-state , ;
-
-: visit-alien-node ( node -- )
- params>> [ out-d>> length ] [ in-d>> length ] bi - adjust-d ;
-
-M: ##alien-invoke visit
- [ call-next-method ] [ visit-alien-node ] bi ;
-
-M: ##alien-indirect visit
- [ call-next-method ] [ visit-alien-node ] bi ;
-
-M: ##alien-callback visit , ;
-
-! Maps basic-blocks to states
-SYMBOLS: state-in state-out ;
-
-: initial-state ( bb states -- state ) 2drop <state> ;
-
-: single-predecessor ( bb states -- state ) nip first clone ;
-
-ERROR: must-equal-failed seq ;
-
-: must-equal ( seq -- elt )
- dup all-equal? [ first ] [ must-equal-failed ] if ;
-
-: merge-heights ( state predecessors states -- state )
- nip
- [ [ ds-height>> ] map must-equal >>ds-height ]
- [ [ rs-height>> ] map must-equal >>rs-height ] bi ;
-
-: insert-peek ( predecessor loc -- vreg )
- ! XXX critical edges
- '[ _ ^^peek ] add-instructions ;
-
-: merge-loc ( predecessors locs>vregs loc -- vreg )
- ! Insert a ##phi in the current block where the input
- ! is the vreg storing loc from each predecessor block
- [ '[ [ _ ] dip at ] map ] keep
- '[ [ ] [ _ insert-peek ] ?if ] 2map
- dup all-equal? [ first ] [ ^^phi ] if ;
-
-: (merge-locs) ( predecessors assocs -- assoc )
- dup [ keys ] map concat prune
- [ [ 2nip ] [ merge-loc ] 3bi ] with with
- H{ } map>assoc ;
-
-: merge-locs ( state predecessors states -- state )
- [ locs>vregs>> ] map (merge-locs) >>locs>vregs ;
-
-: merge-loc' ( locs>vregs loc -- vreg )
- ! Insert a ##phi in the current block where the input
- ! is the vreg storing loc from each predecessor block
- '[ [ _ ] dip at ] map
- dup all-equal? [ first ] [ drop f ] if ;
-
-: merge-actual-locs ( state predecessors states -- state )
- nip
- [ actual-locs>vregs>> ] map
- dup [ keys ] map concat prune
- [ [ nip ] [ merge-loc' ] 2bi ] with
- H{ } map>assoc
- [ nip ] assoc-filter
- >>actual-locs>vregs ;
-
-: merge-changed-locs ( state predecessors states -- state )
- nip [ changed-locs>> ] map assoc-combine >>changed-locs ;
-
-ERROR: cannot-merge-poisoned states ;
-
-: multiple-predecessors ( bb states -- state )
- dup [ not ] any? [
- [ <state> ] 2dip
- sift merge-heights
- ] [
- dup [ poisoned?>> ] any? [
- cannot-merge-poisoned
- ] [
- [ state new ] 2dip
- [ predecessors>> ] dip
- {
- [ merge-locs ]
- [ merge-actual-locs ]
- [ merge-heights ]
- [ merge-changed-locs ]
- } 2cleave
- ] if
- ] if ;
-
-: merge-states ( bb states -- state )
- ! If any states are poisoned, save all registers
- ! to the stack in each branch
- dup length {
- { 0 [ initial-state ] }
- { 1 [ single-predecessor ] }
- [ drop multiple-predecessors ]
- } case ;
-
-: block-in-state ( bb -- states )
- dup predecessors>> state-out get '[ _ at ] map merge-states ;
-
-: set-block-in-state ( state bb -- )
- [ clone ] dip state-in get set-at ;
-
-: set-block-out-state ( state bb -- )
- [ clone ] dip state-out get set-at ;
-
-: visit-block ( bb -- )
- ! block-in-state may add phi nodes at the start of the basic block
- ! so we wrap the whole thing with a 'make'
- [
- dup basic-block set
- dup block-in-state
- [ swap set-block-in-state ] [
- state [
- [ instructions>> [ visit ] each ]
- [ [ state get ] dip set-block-out-state ]
- [ ]
- tri
- ] with-variable
- ] 2bi
- ] V{ } make >>instructions drop ;
-
-: stack-analysis ( cfg -- cfg' )
- [
- H{ } clone copies set
- H{ } clone state-in set
- H{ } clone state-out set
- dup [ visit-block ] each-basic-block
- ] with-scope ;
{ return integer }
{ total-size integer }
{ gc-root-size integer }
-spill-counts ;
+{ spill-area-size integer } ;
! Stack frame utilities
: param-base ( -- n )
stack-frame get [ params>> ] [ return>> ] bi + ;
-: spill-float-offset ( n -- offset )
- double-float-regs reg-size * ;
-
-: spill-integer-base ( -- n )
- stack-frame get spill-counts>> double-float-regs [ swap at ] keep reg-size *
+: spill-offset ( n -- offset )
param-base + ;
-: spill-integer-offset ( n -- offset )
- cells spill-integer-base + ;
-
-: spill-area-size ( stack-frame -- n )
- spill-counts>> [ swap reg-size * ] { } assoc>map sum ;
-
: gc-root-base ( -- n )
- stack-frame get spill-area-size
- param-base + ;
+ stack-frame get spill-area-size>> param-base + ;
: gc-root-offset ( n -- n' ) gc-root-base + ;
-: gc-roots-size ( live-registers live-spill-slots -- n )
- [ keys [ reg-class>> reg-size ] sigma ] bi@ + ;
-
: (stack-frame-size) ( stack-frame -- n )
[
{
- [ spill-area-size ]
- [ gc-root-size>> ]
[ params>> ]
[ return>> ]
+ [ gc-root-size>> ]
+ [ spill-area-size>> ]
} cleave
] sum-outputs ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces assocs kernel fry accessors sequences make math locals
+combinators compiler.cfg compiler.cfg.hats compiler.cfg.instructions
+compiler.cfg.utilities compiler.cfg.rpo compiler.cfg.stacks.local
+compiler.cfg.stacks.global compiler.cfg.stacks.height
+compiler.cfg.predecessors ;
+IN: compiler.cfg.stacks.finalize
+
+! This pass inserts peeks and replaces.
+
+:: inserting-peeks ( from to -- assoc )
+ ! A peek is inserted on an edge if the destination anticipates
+ ! the stack location, the source does not anticipate it and
+ ! it is not available from the source in a register.
+ to anticip-in
+ from anticip-out from avail-out assoc-union
+ assoc-diff ;
+
+:: inserting-replaces ( from to -- assoc )
+ ! A replace is inserted on an edge if two conditions hold:
+ ! - the location is not dead at the destination, OR
+ ! the location is live at the destination but not available
+ ! at the destination
+ ! - the location is pending in the source but not the destination
+ from pending-out to pending-in assoc-diff
+ to dead-in to live-in to anticip-in assoc-diff assoc-diff
+ assoc-diff ;
+
+: each-insertion ( assoc bb quot: ( vreg loc -- ) -- )
+ '[ drop [ loc>vreg ] [ _ untranslate-loc ] bi @ ] assoc-each ; inline
+
+ERROR: bad-peek dst loc ;
+
+: insert-peeks ( from to -- )
+ [ inserting-peeks ] keep
+ [ dup n>> 0 < [ bad-peek ] [ ##peek ] if ] each-insertion ;
+
+: insert-replaces ( from to -- )
+ [ inserting-replaces ] keep
+ [ dup n>> 0 < [ 2drop ] [ ##replace ] if ] each-insertion ;
+
+: visit-edge ( from to -- )
+ ! If both blocks are subroutine calls, don't bother
+ ! computing anything.
+ 2dup [ kill-block? ] both? [ 2drop ] [
+ 2dup [ [ insert-replaces ] [ insert-peeks ] 2bi ] V{ } make
+ [ 2drop ] [ insert-simple-basic-block ] if-empty
+ ] if ;
+
+: visit-block ( bb -- )
+ [ predecessors>> ] keep '[ _ visit-edge ] each ;
+
+: finalize-stack-shuffling ( cfg -- cfg' )
+ needs-predecessors
+
+ dup [ visit-block ] each-basic-block
+
+ cfg-changed ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs kernel combinators compiler.cfg.dataflow-analysis
+compiler.cfg.stacks.local ;
+IN: compiler.cfg.stacks.global
+
+: transfer-peeked-locs ( assoc bb -- assoc' )
+ [ replace-set assoc-diff ] [ peek-set assoc-union ] bi ;
+
+! A stack location is anticipated at a location if every path from
+! the location to an exit block will read the stack location
+! before writing it.
+BACKWARD-ANALYSIS: anticip
+
+M: anticip-analysis transfer-set drop transfer-peeked-locs ;
+
+! A stack location is live at a location if some path from
+! the location to an exit block will read the stack location
+! before writing it.
+BACKWARD-ANALYSIS: live
+
+M: live-analysis transfer-set drop transfer-peeked-locs ;
+
+M: live-analysis join-sets 2drop assoc-combine ;
+
+! A stack location is available at a location if all paths from
+! the entry block to the location load the location into a
+! register.
+FORWARD-ANALYSIS: avail
+
+M: avail-analysis transfer-set
+ drop [ peek-set assoc-union ] [ replace-set assoc-union ] bi ;
+
+! A stack location is pending at a location if all paths from
+! the entry block to the location write the location.
+FORWARD-ANALYSIS: pending
+
+M: pending-analysis transfer-set
+ drop replace-set assoc-union ;
+
+! A stack location is dead at a location if no paths from the
+! location to the exit block read the location before writing it.
+BACKWARD-ANALYSIS: dead
+
+M: dead-analysis transfer-set
+ drop
+ [ kill-set assoc-union ]
+ [ replace-set assoc-union ] bi ;
+
+! Main word
+: compute-global-sets ( cfg -- cfg' )
+ {
+ [ compute-anticip-sets ]
+ [ compute-live-sets ]
+ [ compute-pending-sets ]
+ [ compute-dead-sets ]
+ [ compute-avail-sets ]
+ [ ]
+ } cleave ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs fry kernel math
+namespaces compiler.cfg.registers ;
+IN: compiler.cfg.stacks.height
+
+! Global stack height tracking done while constructing CFG.
+SYMBOLS: ds-heights rs-heights ;
+
+: record-stack-heights ( ds-height rs-height bb -- )
+ [ ds-heights get set-at ] [ rs-heights get set-at ] bi-curry bi* ;
+
+GENERIC# translate-loc 1 ( loc bb -- loc' )
+
+M: ds-loc translate-loc [ n>> ] [ ds-heights get at ] bi* - <ds-loc> ;
+M: rs-loc translate-loc [ n>> ] [ rs-heights get at ] bi* - <rs-loc> ;
+
+: translate-locs ( assoc bb -- assoc' )
+ '[ [ _ translate-loc ] dip ] assoc-map ;
+
+GENERIC# untranslate-loc 1 ( loc bb -- loc' )
+
+M: ds-loc untranslate-loc [ n>> ] [ ds-heights get at ] bi* + <ds-loc> ;
+M: rs-loc untranslate-loc [ n>> ] [ rs-heights get at ] bi* + <rs-loc> ;
+
+: untranslate-locs ( assoc bb -- assoc' )
+ '[ [ _ untranslate-loc ] dip ] assoc-map ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel math math.order namespaces sets make
+sequences combinators fry
+compiler.cfg
+compiler.cfg.hats
+compiler.cfg.instructions
+compiler.cfg.registers
+compiler.cfg.stacks.height
+compiler.cfg.parallel-copy ;
+IN: compiler.cfg.stacks.local
+
+! Local stack analysis. We build three sets for every basic block
+! in the CFG:
+! - peek-set: all stack locations that the block reads before writing
+! - replace-set: all stack locations that the block writes
+! - kill-set: all stack locations which become unavailable after the
+! block ends because of the stack height being decremented
+! This is done while constructing the CFG.
+
+SYMBOLS: peek-sets replace-sets kill-sets ;
+
+SYMBOL: locs>vregs
+
+: loc>vreg ( loc -- vreg ) locs>vregs get [ drop next-vreg ] cache ;
+: vreg>loc ( vreg -- loc/f ) locs>vregs get value-at ;
+
+TUPLE: current-height
+{ d initial: 0 }
+{ r initial: 0 }
+{ emit-d initial: 0 }
+{ emit-r initial: 0 } ;
+
+SYMBOLS: local-peek-set local-replace-set replace-mapping ;
+
+GENERIC: translate-local-loc ( loc -- loc' )
+M: ds-loc translate-local-loc n>> current-height get d>> - <ds-loc> ;
+M: rs-loc translate-local-loc n>> current-height get r>> - <rs-loc> ;
+
+: emit-stack-changes ( -- )
+ replace-mapping get dup assoc-empty? [ drop ] [
+ [ [ loc>vreg ] dip ] assoc-map parallel-copy
+ ] if ;
+
+: emit-height-changes ( -- )
+ current-height get
+ [ emit-d>> dup 0 = [ drop ] [ ##inc-d ] if ]
+ [ emit-r>> dup 0 = [ drop ] [ ##inc-r ] if ] bi ;
+
+: emit-changes ( -- )
+ ! Insert height and stack changes prior to the last instruction
+ building get pop
+ emit-stack-changes
+ emit-height-changes
+ , ;
+
+! inc-d/inc-r: these emit ##inc-d/##inc-r to change the stack height later
+: inc-d ( n -- )
+ current-height get
+ [ [ + ] change-emit-d drop ]
+ [ [ + ] change-d drop ]
+ 2bi ;
+
+: inc-r ( n -- )
+ current-height get
+ [ [ + ] change-emit-r drop ]
+ [ [ + ] change-r drop ]
+ 2bi ;
+
+: peek-loc ( loc -- vreg )
+ translate-local-loc
+ dup replace-mapping get at
+ [ ] [ dup local-peek-set get conjoin loc>vreg ] ?if ;
+
+: replace-loc ( vreg loc -- )
+ translate-local-loc replace-mapping get set-at ;
+
+: compute-local-kill-set ( -- assoc )
+ basic-block get current-height get
+ [ [ ds-heights get at dup ] [ d>> ] bi* [-] iota [ swap - <ds-loc> ] with map ]
+ [ [ rs-heights get at dup ] [ r>> ] bi* [-] iota [ swap - <rs-loc> ] with map ] 2bi
+ append unique ;
+
+: begin-local-analysis ( -- )
+ H{ } clone local-peek-set set
+ H{ } clone replace-mapping set
+ current-height get
+ [ 0 >>emit-d 0 >>emit-r drop ]
+ [ [ d>> ] [ r>> ] bi basic-block get record-stack-heights ] bi ;
+
+: remove-redundant-replaces ( -- )
+ replace-mapping get [ [ loc>vreg ] dip = not ] assoc-filter
+ [ replace-mapping set ] [ keys unique local-replace-set set ] bi ;
+
+: end-local-analysis ( -- )
+ remove-redundant-replaces
+ emit-changes
+ basic-block get {
+ [ [ local-peek-set get ] dip peek-sets get set-at ]
+ [ [ local-replace-set get ] dip replace-sets get set-at ]
+ [ [ compute-local-kill-set ] dip kill-sets get set-at ]
+ } cleave ;
+
+: clone-current-height ( -- )
+ current-height [ clone ] change ;
+
+: peek-set ( bb -- assoc ) peek-sets get at ;
+: replace-set ( bb -- assoc ) replace-sets get at ;
+: kill-set ( bb -- assoc ) kill-sets get at ;
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: math sequences kernel cpu.architecture
-compiler.cfg.instructions compiler.cfg.registers
-compiler.cfg.hats ;
+USING: math sequences kernel namespaces accessors biassocs compiler.cfg
+compiler.cfg.instructions compiler.cfg.registers compiler.cfg.hats
+compiler.cfg.predecessors compiler.cfg.stacks.local
+compiler.cfg.stacks.height compiler.cfg.stacks.global
+compiler.cfg.stacks.finalize ;
IN: compiler.cfg.stacks
-: ds-drop ( -- )
- -1 ##inc-d ;
+: begin-stack-analysis ( -- )
+ <bihash> locs>vregs set
+ H{ } clone ds-heights set
+ H{ } clone rs-heights set
+ H{ } clone peek-sets set
+ H{ } clone replace-sets set
+ H{ } clone kill-sets set
+ current-height new current-height set ;
-: ds-pop ( -- vreg )
- D 0 ^^peek -1 ##inc-d ;
+: end-stack-analysis ( -- )
+ cfg get
+ compute-global-sets
+ finalize-stack-shuffling
+ drop ;
-: ds-push ( vreg -- )
- 1 ##inc-d D 0 ##replace ;
+: ds-drop ( -- ) -1 inc-d ;
+
+: ds-peek ( -- vreg ) D 0 peek-loc ;
+
+: ds-pop ( -- vreg ) ds-peek ds-drop ;
+
+: ds-push ( vreg -- ) 1 inc-d D 0 replace-loc ;
: ds-load ( n -- vregs )
dup 0 =
[ drop f ]
- [ [ <reversed> [ <ds-loc> ^^peek ] map ] [ neg ##inc-d ] bi ] if ;
+ [ [ <reversed> [ <ds-loc> peek-loc ] map ] [ neg inc-d ] bi ] if ;
: ds-store ( vregs -- )
[
<reversed>
- [ length ##inc-d ]
- [ [ <ds-loc> ##replace ] each-index ] bi
+ [ length inc-d ]
+ [ [ <ds-loc> replace-loc ] each-index ] bi
] unless-empty ;
+: rs-drop ( -- ) -1 inc-r ;
+
: rs-load ( n -- vregs )
dup 0 =
[ drop f ]
- [ [ <reversed> [ <rs-loc> ^^peek ] map ] [ neg ##inc-r ] bi ] if ;
+ [ [ <reversed> [ <rs-loc> peek-loc ] map ] [ neg inc-r ] bi ] if ;
: rs-store ( vregs -- )
[
<reversed>
- [ length ##inc-r ]
- [ [ <rs-loc> ##replace ] each-index ] bi
+ [ length inc-r ]
+ [ [ <rs-loc> replace-loc ] each-index ] bi
] unless-empty ;
+: (2inputs) ( -- vreg1 vreg2 )
+ D 1 peek-loc D 0 peek-loc ;
+
: 2inputs ( -- vreg1 vreg2 )
- D 1 ^^peek D 0 ^^peek -2 ##inc-d ;
+ (2inputs) -2 inc-d ;
+
+: (3inputs) ( -- vreg1 vreg2 vreg3 )
+ D 2 peek-loc D 1 peek-loc D 0 peek-loc ;
: 3inputs ( -- vreg1 vreg2 vreg3 )
- D 2 ^^peek D 1 ^^peek D 0 ^^peek -3 ##inc-d ;
+ (3inputs) -3 inc-d ;
+
+! adjust-d/adjust-r: these are called when other instructions which
+! internally adjust the stack height are emitted, such as ##call and
+! ##alien-invoke
+: adjust-d ( n -- ) current-height get [ + ] change-d drop ;
+: adjust-r ( n -- ) current-height get [ + ] change-r drop ;
+
--- /dev/null
+USING: compiler.cfg.stacks.uninitialized compiler.cfg.debugger
+compiler.cfg.registers compiler.cfg.instructions compiler.cfg
+compiler.cfg.predecessors cpu.architecture tools.test kernel vectors
+namespaces accessors sequences ;
+IN: compiler.cfg.stacks.uninitialized.tests
+
+: test-uninitialized ( -- )
+ cfg new 0 get >>entry
+ compute-uninitialized-sets ;
+
+V{
+ T{ ##inc-d f 3 }
+} 0 test-bb
+
+V{
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 0 D 1 }
+ T{ ##replace f 0 D 2 }
+ T{ ##inc-r f 1 }
+} 1 test-bb
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##inc-d f 1 }
+} 2 test-bb
+
+0 1 edge
+1 2 edge
+
+[ ] [ test-uninitialized ] unit-test
+
+[ V{ D 0 D 1 D 2 } ] [ 1 get uninitialized-locs ] unit-test
+[ V{ R 0 } ] [ 2 get uninitialized-locs ] unit-test
+
+! When merging, if a location is uninitialized in one branch and
+! initialized in another, we have to consider it uninitialized,
+! since it cannot be safely read from by a ##peek, or traced by GC.
+
+V{ } 0 test-bb
+
+V{
+ T{ ##inc-d f 1 }
+} 1 test-bb
+
+V{
+ T{ ##call f namestack }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##return }
+} 3 test-bb
+
+0 { 1 2 } edges
+1 3 edge
+2 3 edge
+
+[ ] [ test-uninitialized ] unit-test
+
+[ V{ D 0 } ] [ 3 get uninitialized-locs ] unit-test
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel sequences byte-arrays namespaces accessors classes math
+math.order fry arrays combinators compiler.cfg.registers
+compiler.cfg.instructions compiler.cfg.dataflow-analysis ;
+IN: compiler.cfg.stacks.uninitialized
+
+! Uninitialized stack location analysis.
+
+! Consider the following sequence of instructions:
+! ##inc-d 2
+! _gc
+! ##replace ... D 0
+! ##replace ... D 1
+! The GC check runs before stack locations 0 and 1 have been initialized,
+! and it needs to zero them out so that GC doesn't try to trace them.
+
+<PRIVATE
+
+GENERIC: visit-insn ( insn -- )
+
+: handle-inc ( n symbol -- )
+ [
+ swap {
+ { [ dup 0 < ] [ neg short tail ] }
+ { [ dup 0 > ] [ <byte-array> prepend ] }
+ } cond
+ ] change ;
+
+M: ##inc-d visit-insn n>> ds-loc handle-inc ;
+
+M: ##inc-r visit-insn n>> rs-loc handle-inc ;
+
+ERROR: uninitialized-peek insn ;
+
+M: ##peek visit-insn
+ dup loc>> [ n>> ] [ class get ] bi ?nth 0 =
+ [ uninitialized-peek ] [ drop ] if ;
+
+M: ##replace visit-insn
+ loc>> [ n>> ] [ class get ] bi
+ 2dup length < [ [ 1 ] 2dip set-nth ] [ 2drop ] if ;
+
+M: insn visit-insn drop ;
+
+: prepare ( pair -- )
+ [ first2 [ [ clone ] [ B{ } ] if* ] bi@ ] [ B{ } B{ } ] if*
+ [ ds-loc set ] [ rs-loc set ] bi* ;
+
+: visit-block ( bb -- ) instructions>> [ visit-insn ] each ;
+
+: finish ( -- pair ) ds-loc get rs-loc get 2array ;
+
+: (join-sets) ( seq1 seq2 -- seq )
+ 2dup [ length ] bi@ max '[ _ 1 pad-tail ] bi@ [ bitand ] 2map ;
+
+: (uninitialized-locs) ( seq quot -- seq' )
+ [ dup length [ drop 0 = ] pusher [ 2each ] dip ] dip map ; inline
+
+PRIVATE>
+
+FORWARD-ANALYSIS: uninitialized
+
+M: uninitialized-analysis transfer-set ( pair bb analysis -- pair' )
+ drop [ prepare ] dip visit-block finish ;
+
+M: uninitialized-analysis join-sets ( sets analysis -- pair )
+ 2drop sift [ f ] [ [ ] [ [ (join-sets) ] 2map ] map-reduce ] if-empty ;
+
+: uninitialized-locs ( bb -- locs )
+ uninitialized-in dup [
+ first2
+ [ [ <ds-loc> ] (uninitialized-locs) ]
+ [ [ <rs-loc> ] (uninitialized-locs) ]
+ bi* append
+ ] when ;
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators.short-circuit kernel math
+namespaces sequences fry combinators
+compiler.utilities
+compiler.cfg
+compiler.cfg.rpo
+compiler.cfg.hats
+compiler.cfg.instructions
+compiler.cfg.utilities ;
+IN: compiler.cfg.tco
+
+! Tail call optimization.
+
+: return? ( bb -- ? )
+ skip-empty-blocks
+ instructions>> {
+ [ length 2 = ]
+ [ first ##epilogue? ]
+ [ second ##return? ]
+ } 1&& ;
+
+: tail-call? ( bb -- ? )
+ {
+ [ instructions>> { [ length 2 >= ] [ last ##branch? ] } 1&& ]
+ [ successors>> first return? ]
+ } 1&& ;
+
+: word-tail-call? ( bb -- ? )
+ instructions>> penultimate ##call? ;
+
+: convert-tail-call ( bb quot: ( insn -- tail-insn ) -- )
+ '[
+ instructions>>
+ [ pop* ] [ pop ] [ ] tri
+ [ [ \ ##epilogue new-insn ] dip push ]
+ [ _ dip push ] bi
+ ]
+ [ successors>> delete-all ]
+ bi ; inline
+
+: convert-word-tail-call ( bb -- )
+ [ word>> \ ##jump new-insn ] convert-tail-call ;
+
+: loop-tail-call? ( bb -- ? )
+ instructions>> penultimate
+ { [ ##call? ] [ word>> cfg get label>> eq? ] } 1&& ;
+
+: convert-loop-tail-call ( bb -- )
+ ! If a word calls itself, this becomes a loop in the CFG.
+ [ instructions>> [ pop* ] [ pop* ] [ [ \ ##branch new-insn ] dip push ] tri ]
+ [ successors>> delete-all ]
+ [ [ cfg get entry>> successors>> first ] dip successors>> push ]
+ tri ;
+
+: optimize-tail-call ( bb -- )
+ dup tail-call? [
+ {
+ { [ dup loop-tail-call? ] [ convert-loop-tail-call ] }
+ { [ dup word-tail-call? ] [ convert-word-tail-call ] }
+ [ drop ]
+ } cond
+ ] [ drop ] if ;
+
+: optimize-tail-calls ( cfg -- cfg' )
+ dup [ optimize-tail-call ] each-basic-block
+
+ cfg-changed predecessors-changed ;
\ No newline at end of file
--- /dev/null
+USING: kernel compiler.cfg.two-operand compiler.cfg.instructions
+compiler.cfg.registers cpu.architecture namespaces tools.test ;
+IN: compiler.cfg.two-operand.tests
+
+3 vreg-counter set-global
+
+[
+ V{
+ T{ ##copy f 1 2 int-rep }
+ T{ ##sub f 1 1 3 }
+ }
+] [
+ H{
+ { 1 int-rep }
+ { 2 int-rep }
+ { 3 int-rep }
+ } clone representations set
+ {
+ T{ ##sub f 1 2 3 }
+ } (convert-two-operand)
+] unit-test
+
+[
+ V{
+ T{ ##copy f 1 2 double-float-rep }
+ T{ ##sub-float f 1 1 3 }
+ }
+] [
+ H{
+ { 1 double-float-rep }
+ { 2 double-float-rep }
+ { 3 double-float-rep }
+ } clone representations set
+ {
+ T{ ##sub-float f 1 2 3 }
+ } (convert-two-operand)
+] unit-test
+
+[
+ V{
+ T{ ##copy f 1 2 double-float-rep }
+ T{ ##mul-float f 1 1 1 }
+ }
+] [
+ H{
+ { 1 double-float-rep }
+ { 2 double-float-rep }
+ } clone representations set
+ {
+ T{ ##mul-float f 1 2 2 }
+ } (convert-two-operand)
+] unit-test
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays kernel sequences make compiler.cfg.instructions
+USING: accessors kernel sequences make combinators
+compiler.cfg.registers compiler.cfg.instructions
compiler.cfg.rpo cpu.architecture ;
IN: compiler.cfg.two-operand
-! On x86, instructions take the form x = x op y
-! Our SSA IR is x = y op z
+! This pass runs before SSA coalescing and normalizes instructions
+! to fit the x86 two-address scheme. Since the input is in SSA,
+! it suffices to convert
+!
+! x = y op z
+!
+! to
+!
+! x = y
+! x = x op z
+!
+! We don't bother with ##add, ##add-imm, ##sub-imm or ##mul-imm
+! since x86 has LEA and IMUL instructions which are effectively
+! three-operand addition and multiplication, respectively.
-! We don't bother with ##add, ##add-imm or ##sub-imm since x86
-! has a LEA instruction which is effectively a three-operand
-! addition
+UNION: two-operand-insn
+ ##sub
+ ##mul
+ ##and
+ ##and-imm
+ ##or
+ ##or-imm
+ ##xor
+ ##xor-imm
+ ##shl
+ ##shl-imm
+ ##shr
+ ##shr-imm
+ ##sar
+ ##sar-imm
+ ##fixnum-overflow
+ ##add-float
+ ##sub-float
+ ##mul-float
+ ##div-float ;
-: make-copy ( dst src -- insn ) \ ##copy new-insn ; inline
-
-: make-copy/float ( dst src -- insn ) \ ##copy-float new-insn ; inline
-
-: convert-two-operand/integer ( insn -- )
- [ [ dst>> ] [ src1>> ] bi ##copy ]
- [ dup dst>> >>src1 , ]
- bi ; inline
+GENERIC: convert-two-operand* ( insn -- )
-: convert-two-operand/float ( insn -- )
- [ [ dst>> ] [ src1>> ] bi ##copy-float ]
- [ dup dst>> >>src1 , ]
- bi ; inline
+: emit-copy ( dst src -- )
+ dup rep-of ##copy ; inline
-GENERIC: convert-two-operand* ( insn -- )
+M: two-operand-insn convert-two-operand*
+ [ [ dst>> ] [ src1>> ] bi emit-copy ]
+ [
+ dup [ src1>> ] [ src2>> ] bi = [ dup dst>> >>src2 ] when
+ dup dst>> >>src1 ,
+ ] bi ;
M: ##not convert-two-operand*
- [ [ dst>> ] [ src>> ] bi ##copy ]
+ [ [ dst>> ] [ src>> ] bi emit-copy ]
[ dup dst>> >>src , ]
bi ;
-M: ##sub convert-two-operand* convert-two-operand/integer ;
-M: ##mul convert-two-operand* convert-two-operand/integer ;
-M: ##mul-imm convert-two-operand* convert-two-operand/integer ;
-M: ##and convert-two-operand* convert-two-operand/integer ;
-M: ##and-imm convert-two-operand* convert-two-operand/integer ;
-M: ##or convert-two-operand* convert-two-operand/integer ;
-M: ##or-imm convert-two-operand* convert-two-operand/integer ;
-M: ##xor convert-two-operand* convert-two-operand/integer ;
-M: ##xor-imm convert-two-operand* convert-two-operand/integer ;
-M: ##shl-imm convert-two-operand* convert-two-operand/integer ;
-M: ##shr-imm convert-two-operand* convert-two-operand/integer ;
-M: ##sar-imm convert-two-operand* convert-two-operand/integer ;
-
-M: ##add-float convert-two-operand* convert-two-operand/float ;
-M: ##sub-float convert-two-operand* convert-two-operand/float ;
-M: ##mul-float convert-two-operand* convert-two-operand/float ;
-M: ##div-float convert-two-operand* convert-two-operand/float ;
-
M: insn convert-two-operand* , ;
+: (convert-two-operand) ( insns -- insns' )
+ dup first kill-vreg-insn? [
+ [ [ convert-two-operand* ] each ] V{ } make
+ ] unless ;
+
: convert-two-operand ( cfg -- cfg' )
- two-operand? [
- dup [
- [
- [ [ convert-two-operand* ] each ] V{ } make
- ] change-instructions drop
- ] each-basic-block
- ] when ;
+ two-operand? [ [ (convert-two-operand) ] local-optimization ] when ;
\ No newline at end of file
+++ /dev/null
-Eliminating unreachable basic blocks and unconditional jumps
+++ /dev/null
-IN: compiler.cfg.useless-blocks.tests
-USING: fry kernel sequences compiler.cfg.useless-blocks compiler.cfg.checker
-compiler.cfg.debugger compiler.cfg.predecessors tools.test ;
-
-{
- [ [ drop 1 ] when ]
- [ [ drop 1 ] unless ]
-} [
- [ [ ] ] dip
- '[ _ test-cfg first compute-predecessors delete-useless-blocks check-cfg ] unit-test
-] each
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008, 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors sequences combinators combinators.short-circuit
-classes vectors compiler.cfg compiler.cfg.instructions compiler.cfg.rpo ;
-IN: compiler.cfg.useless-blocks
-
-: update-predecessor-for-delete ( bb -- )
- ! We have to replace occurrences of bb with bb's successor
- ! in bb's predecessor's list of successors.
- dup predecessors>> first [
- [
- 2dup eq? [ drop successors>> first ] [ nip ] if
- ] with map
- ] change-successors drop ;
-
-: update-successor-for-delete ( bb -- )
- ! We have to replace occurrences of bb with bb's predecessor
- ! in bb's sucessor's list of predecessors.
- dup successors>> first [
- [
- 2dup eq? [ drop predecessors>> first ] [ nip ] if
- ] with map
- ] change-predecessors drop ;
-
-: delete-basic-block ( bb -- )
- [ update-predecessor-for-delete ]
- [ update-successor-for-delete ]
- bi ;
-
-: delete-basic-block? ( bb -- ? )
- {
- [ instructions>> length 1 = ]
- [ predecessors>> length 1 = ]
- [ successors>> length 1 = ]
- [ instructions>> first ##branch? ]
- } 1&& ;
-
-: delete-useless-blocks ( cfg -- cfg' )
- dup [
- dup delete-basic-block? [ delete-basic-block ] [ drop ] if
- ] each-basic-block
- f >>post-order ;
-
-: delete-conditional? ( bb -- ? )
- dup instructions>> [ drop f ] [
- last class {
- ##compare-branch
- ##compare-imm-branch
- ##compare-float-branch
- } memq? [ successors>> first2 eq? ] [ drop f ] if
- ] if-empty ;
-
-: delete-conditional ( bb -- )
- dup successors>> first 1vector >>successors
- [ but-last \ ##branch new-insn suffix ] change-instructions
- drop ;
-
-: delete-useless-conditionals ( cfg -- cfg' )
- dup [
- dup delete-conditional? [ delete-conditional ] [ drop ] if
- ] each-basic-block
- f >>post-order ;
--- /dev/null
+Eliminating unreachable basic blocks and unconditional jumps
--- /dev/null
+! Copyright (C) 2008, 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors sequences math combinators combinators.short-circuit
+classes vectors compiler.cfg compiler.cfg.instructions compiler.cfg.rpo
+compiler.cfg.utilities ;
+IN: compiler.cfg.useless-conditionals
+
+: delete-conditional? ( bb -- ? )
+ {
+ [ instructions>> last class { ##compare-branch ##compare-imm-branch ##compare-float-branch } memq? ]
+ [ successors>> first2 [ skip-empty-blocks ] bi@ eq? ]
+ } 1&& ;
+
+: delete-conditional ( bb -- )
+ [ first skip-empty-blocks 1vector ] change-successors
+ instructions>> [ pop* ] [ [ \ ##branch new-insn ] dip push ] bi ;
+
+: delete-useless-conditionals ( cfg -- cfg' )
+ dup [
+ dup delete-conditional? [ delete-conditional ] [ drop ] if
+ ] each-basic-block
+
+ cfg-changed predecessors-changed ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel math layouts make sequences combinators
-cpu.architecture namespaces compiler.cfg
-compiler.cfg.instructions ;
+USING: accessors assocs combinators combinators.short-circuit
+cpu.architecture kernel layouts locals make math namespaces sequences
+sets vectors fry compiler.cfg compiler.cfg.instructions
+compiler.cfg.rpo arrays ;
IN: compiler.cfg.utilities
-: value-info-small-fixnum? ( value-info -- ? )
- literal>> {
- { [ dup fixnum? ] [ tag-fixnum small-enough? ] }
- [ drop f ]
- } cond ;
-
-: value-info-small-tagged? ( value-info -- ? )
- dup literal?>> [
- literal>> {
- { [ dup fixnum? ] [ tag-fixnum small-enough? ] }
- { [ dup not ] [ drop t ] }
- [ drop f ]
- } cond
- ] [ drop f ] if ;
-
-: set-basic-block ( basic-block -- )
- [ basic-block set ] [ instructions>> building set ] bi ;
-
-: begin-basic-block ( -- )
- <basic-block> basic-block get [
- dupd successors>> push
- ] when*
- set-basic-block ;
-
-: end-basic-block ( -- )
- building off
- basic-block off ;
-
-: stop-iterating ( -- next ) end-basic-block f ;
-
-: call-height ( ##call -- n )
- [ out-d>> length ] [ in-d>> length ] bi - ;
-
-: emit-primitive ( node -- )
- [ word>> ] [ call-height ] bi ##call ##branch begin-basic-block ;
+PREDICATE: kill-block < basic-block
+ instructions>> {
+ [ length 2 = ]
+ [ first kill-vreg-insn? ]
+ } 1&& ;
+
+: back-edge? ( from to -- ? )
+ [ number>> ] bi@ >= ;
+
+: loop-entry? ( bb -- ? )
+ dup predecessors>> [ swap back-edge? ] with any? ;
+
+: empty-block? ( bb -- ? )
+ instructions>> {
+ [ length 1 = ]
+ [ first ##branch? ]
+ } 1&& ;
+
+SYMBOL: visited
+
+: (skip-empty-blocks) ( bb -- bb' )
+ dup visited get key? [
+ dup empty-block? [
+ dup visited get conjoin
+ successors>> first (skip-empty-blocks)
+ ] when
+ ] unless ;
+
+: skip-empty-blocks ( bb -- bb' )
+ H{ } clone visited [ (skip-empty-blocks) ] with-variable ;
+
+:: insert-basic-block ( froms to bb -- )
+ bb froms V{ } like >>predecessors drop
+ bb to 1vector >>successors drop
+ to predecessors>> [ dup froms memq? [ drop bb ] when ] change-each
+ froms [ successors>> [ dup to eq? [ drop bb ] when ] change-each ] each ;
+
+: add-instructions ( bb quot -- )
+ [ instructions>> building ] dip '[
+ building get pop
+ [ @ ] dip
+ ,
+ ] with-variable ; inline
+
+: <simple-block> ( insns -- bb )
+ <basic-block>
+ swap >vector
+ \ ##branch new-insn over push
+ >>instructions ;
+
+: insert-simple-basic-block ( from to insns -- )
+ [ 1vector ] 2dip <simple-block> insert-basic-block ;
+
+: has-phis? ( bb -- ? )
+ instructions>> first ##phi? ;
+
+: cfg-has-phis? ( cfg -- ? )
+ post-order [ has-phis? ] any? ;
+
+: if-has-phis ( bb quot: ( bb -- ) -- )
+ [ dup has-phis? ] dip [ drop ] if ; inline
+
+: each-phi ( bb quot: ( ##phi -- ) -- )
+ [ instructions>> ] dip
+ '[ dup ##phi? [ @ t ] [ drop f ] if ] all? drop ; inline
+
+: each-non-phi ( bb quot: ( insn -- ) -- )
+ [ instructions>> ] dip
+ '[ dup ##phi? [ drop ] _ if ] each ; inline
+
+: predecessor ( bb -- pred )
+ predecessors>> first ; inline
+
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors classes kernel math namespaces combinators
-compiler.cfg.instructions compiler.cfg.value-numbering.graph ;
+combinators.short-circuit compiler.cfg.instructions
+compiler.cfg.value-numbering.graph ;
IN: compiler.cfg.value-numbering.expressions
! Referentially-transparent expressions
-TUPLE: expr op ;
TUPLE: unary-expr < expr in ;
TUPLE: binary-expr < expr in1 in2 ;
TUPLE: commutative-expr < binary-expr ;
TUPLE: compare-expr < binary-expr cc ;
TUPLE: constant-expr < expr value ;
+TUPLE: reference-expr < expr value ;
: <constant> ( constant -- expr )
f swap constant-expr boa ; inline
M: constant-expr equal?
over constant-expr? [
- [ [ value>> ] bi@ = ]
- [ [ value>> class ] bi@ = ] 2bi
- and
+ {
+ [ [ value>> class ] bi@ = ]
+ [ [ value>> ] bi@ = ]
+ } 2&&
] [ 2drop f ] if ;
-! Expressions whose values are inputs to the basic block. We
-! can eliminate a second computation having the same 'n' as
-! the first one; we can also eliminate input-exprs whose
-! result is not used.
-TUPLE: input-expr < expr n ;
+: <reference> ( constant -- expr )
+ f swap reference-expr boa ; inline
-SYMBOL: input-expr-counter
-
-: next-input-expr ( class -- expr )
- input-expr-counter [ dup 1 + ] change input-expr boa ;
+M: reference-expr equal?
+ over reference-expr? [
+ [ value>> ] bi@ {
+ { [ 2dup eq? ] [ 2drop t ] }
+ { [ 2dup [ float? ] both? ] [ fp-bitwise= ] }
+ [ 2drop f ]
+ } cond
+ ] [ 2drop f ] if ;
: constant>vn ( constant -- vn ) <constant> expr>vn ; inline
M: ##load-immediate >expr val>> <constant> ;
+M: ##load-reference >expr obj>> <reference> ;
+
M: ##unary >expr
[ class ] [ src>> vreg>vn ] bi unary-expr boa ;
M: ##compare-float >expr compare>expr ;
-M: ##flushable >expr class next-input-expr ;
+M: ##flushable >expr drop next-input-expr ;
: init-expressions ( -- )
0 input-expr-counter set ;
! biassoc mapping expressions to value numbers
SYMBOL: exprs>vns
+TUPLE: expr op ;
+
: expr>vn ( expr -- vn ) exprs>vns get [ drop next-vn ] cache ;
: vn>expr ( vn -- expr ) exprs>vns get value-at ;
+! Expressions whose values are inputs to the basic block.
+TUPLE: input-expr < expr n ;
+
+SYMBOL: input-expr-counter
+
+: next-input-expr ( -- expr )
+ f input-expr-counter counter input-expr boa ;
+
SYMBOL: vregs>vns
-: vreg>vn ( vreg -- vn ) vregs>vns get at ;
+: vreg>vn ( vreg -- vn )
+ vregs>vns get [ drop next-input-expr expr>vn ] cache ;
: vn>vreg ( vn -- vreg ) vregs>vns get value-at ;
: vn>constant ( vn -- constant ) vn>expr value>> ; inline
+: vreg>constant ( vreg -- constant ) vreg>vn vn>constant ; inline
+
: init-value-graph ( -- )
0 vn-counter set
<bihash> exprs>vns set
+++ /dev/null
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces assocs sequences kernel accessors
-compiler.cfg.instructions compiler.cfg.value-numbering.graph ;
-IN: compiler.cfg.value-numbering.propagate
-
-! If two vregs compute the same value, replace references to
-! the latter with the former.
-
-: resolve ( vreg -- vreg' ) vreg>vn vn>vreg ; inline
-
-GENERIC: propagate ( insn -- insn )
-
-M: ##effect propagate
- [ resolve ] change-src ;
-
-M: ##unary propagate
- [ resolve ] change-src ;
-
-M: ##binary propagate
- [ resolve ] change-src1
- [ resolve ] change-src2 ;
-
-M: ##binary-imm propagate
- [ resolve ] change-src1 ;
-
-M: ##slot propagate
- [ resolve ] change-obj
- [ resolve ] change-slot ;
-
-M: ##slot-imm propagate
- [ resolve ] change-obj ;
-
-M: ##set-slot propagate
- call-next-method
- [ resolve ] change-obj
- [ resolve ] change-slot ;
-
-M: ##string-nth propagate
- [ resolve ] change-obj
- [ resolve ] change-index ;
-
-M: ##set-slot-imm propagate
- call-next-method
- [ resolve ] change-obj ;
-
-M: ##alien-getter propagate
- call-next-method
- [ resolve ] change-src ;
-
-M: ##alien-setter propagate
- call-next-method
- [ resolve ] change-value ;
-
-M: ##conditional-branch propagate
- [ resolve ] change-src1
- [ resolve ] change-src2 ;
-
-M: ##compare-imm-branch propagate
- [ resolve ] change-src1 ;
-
-M: ##dispatch propagate
- [ resolve ] change-src ;
-
-M: ##fixnum-overflow propagate
- [ resolve ] change-src1
- [ resolve ] change-src2 ;
-
-M: insn propagate ;
+++ /dev/null
-Propagation pass to update code after value numbering
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel sequences layouts accessors combinators namespaces
-math fry
-compiler.cfg.hats
+USING: accessors combinators combinators.short-circuit arrays
+fry kernel layouts math namespaces sequences cpu.architecture
+math.bitwise math.order classes vectors locals make
+compiler.cfg
+compiler.cfg.registers
+compiler.cfg.comparisons
compiler.cfg.instructions
+compiler.cfg.value-numbering.expressions
compiler.cfg.value-numbering.graph
-compiler.cfg.value-numbering.simplify
-compiler.cfg.value-numbering.expressions ;
+compiler.cfg.value-numbering.simplify ;
IN: compiler.cfg.value-numbering.rewrite
-GENERIC: rewrite ( insn -- insn' )
+: vreg-small-constant? ( vreg -- ? )
+ vreg>expr {
+ [ constant-expr? ]
+ [ value>> small-enough? ]
+ } 1&& ;
-M: ##mul-imm rewrite
- dup src2>> dup power-of-2? [
- [ [ dst>> ] [ src1>> ] bi ] [ log2 ] bi* \ ##shl-imm new-insn
- dup number-values
- ] [ drop ] if ;
+! Outputs f to mean no change
+
+GENERIC: rewrite ( insn -- insn/f )
+
+M: insn rewrite drop f ;
: ##branch-t? ( insn -- ? )
dup ##compare-imm-branch? [
- [ cc>> cc/= eq? ]
- [ src2>> \ f tag-number eq? ] bi and
+ {
+ [ cc>> cc/= eq? ]
+ [ src2>> \ f tag-number eq? ]
+ } 1&&
] [ drop f ] if ; inline
: rewrite-boolean-comparison? ( insn -- ? )
: rewrite-tagged-comparison? ( insn -- ? )
#! Are we comparing two tagged fixnums? Then untag them.
- [ src1>> vreg>expr tag-fixnum-expr? ]
- [ src2>> tag-mask get bitand 0 = ]
- bi and ; inline
+ {
+ [ src1>> vreg>expr tag-fixnum-expr? ]
+ [ src2>> tag-mask get bitand 0 = ]
+ } 1&& ; inline
+
+: tagged>constant ( n -- n' )
+ tag-bits get neg shift ; inline
: (rewrite-tagged-comparison) ( insn -- src1 src2 cc )
[ src1>> vreg>expr in1>> vn>vreg ]
- [ src2>> tag-bits get neg shift ]
+ [ src2>> tagged>constant ]
[ cc>> ]
tri ; inline
-GENERIC: rewrite-tagged-comparison ( insn -- insn' )
+GENERIC: rewrite-tagged-comparison ( insn -- insn/f )
M: ##compare-imm-branch rewrite-tagged-comparison
(rewrite-tagged-comparison) \ ##compare-imm-branch new-insn ;
M: ##compare-imm rewrite-tagged-comparison
[ dst>> ] [ (rewrite-tagged-comparison) ] bi
- i \ ##compare-imm new-insn ;
-
-M: ##compare-imm-branch rewrite
- dup rewrite-boolean-comparison? [ rewrite-boolean-comparison ] when
- dup ##compare-imm-branch? [
- dup rewrite-tagged-comparison? [ rewrite-tagged-comparison ] when
- ] when ;
-
-: flip-comparison? ( insn -- ? )
- dup cc>> cc= eq? [ src1>> vreg>expr constant-expr? ] [ drop f ] if ;
-
-: flip-comparison ( insn -- insn' )
- [ dst>> ]
- [ src2>> ]
- [ src1>> vreg>vn vn>constant ] tri
- cc= i \ ##compare-imm new-insn ;
-
-M: ##compare rewrite
- dup flip-comparison? [
- flip-comparison
- dup number-values
- rewrite
- ] when ;
+ next-vreg \ ##compare-imm new-insn ;
: rewrite-redundant-comparison? ( insn -- ? )
- [ src1>> vreg>expr compare-expr? ]
- [ src2>> \ f tag-number = ]
- [ cc>> { cc= cc/= } memq? ]
- tri and and ; inline
+ {
+ [ src1>> vreg>expr compare-expr? ]
+ [ src2>> \ f tag-number = ]
+ [ cc>> { cc= cc/= } memq? ]
+ } 1&& ; inline
: rewrite-redundant-comparison ( insn -- insn' )
[ cc>> ] [ dst>> ] [ src1>> vreg>expr dup op>> ] tri {
- { \ ##compare [ >compare-expr< i \ ##compare new-insn ] }
- { \ ##compare-imm [ >compare-imm-expr< i \ ##compare-imm new-insn ] }
- { \ ##compare-float [ >compare-expr< i \ ##compare-float new-insn ] }
+ { \ ##compare [ >compare-expr< next-vreg \ ##compare new-insn ] }
+ { \ ##compare-imm [ >compare-imm-expr< next-vreg \ ##compare-imm new-insn ] }
+ { \ ##compare-float [ >compare-expr< next-vreg \ ##compare-float new-insn ] }
} case
swap cc= eq? [ [ negate-cc ] change-cc ] when ;
+ERROR: bad-comparison ;
+
+: (fold-compare-imm) ( insn -- ? )
+ [ [ src1>> vreg>constant ] [ src2>> ] bi ] [ cc>> ] bi
+ pick integer?
+ [ [ <=> ] dip evaluate-cc ]
+ [
+ 2nip {
+ { cc= [ f ] }
+ { cc/= [ t ] }
+ [ bad-comparison ]
+ } case
+ ] if ;
+
+: fold-compare-imm? ( insn -- ? )
+ src1>> vreg>expr [ constant-expr? ] [ reference-expr? ] bi or ;
+
+: fold-branch ( ? -- insn )
+ 0 1 ?
+ basic-block get [ nth 1vector ] change-successors drop
+ \ ##branch new-insn ;
+
+: fold-compare-imm-branch ( insn -- insn/f )
+ (fold-compare-imm) fold-branch ;
+
+M: ##compare-imm-branch rewrite
+ {
+ { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] }
+ { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] }
+ { [ dup fold-compare-imm? ] [ fold-compare-imm-branch ] }
+ [ drop f ]
+ } cond ;
+
+: swap-compare ( src1 src2 cc swap? -- src1 src2 cc )
+ [ [ swap ] dip swap-cc ] when ; inline
+
+: >compare-imm-branch ( insn swap? -- insn' )
+ [
+ [ src1>> ]
+ [ src2>> ]
+ [ cc>> ]
+ tri
+ ] dip
+ swap-compare
+ [ vreg>constant ] dip
+ \ ##compare-imm-branch new-insn ; inline
+
+: self-compare? ( insn -- ? )
+ [ src1>> ] [ src2>> ] bi [ vreg>vn ] bi@ = ; inline
+
+: (rewrite-self-compare) ( insn -- ? )
+ cc>> { cc= cc<= cc>= } memq? ;
+
+: rewrite-self-compare-branch ( insn -- insn' )
+ (rewrite-self-compare) fold-branch ;
+
+M: ##compare-branch rewrite
+ {
+ { [ dup src1>> vreg-small-constant? ] [ t >compare-imm-branch ] }
+ { [ dup src2>> vreg-small-constant? ] [ f >compare-imm-branch ] }
+ { [ dup self-compare? ] [ rewrite-self-compare-branch ] }
+ [ drop f ]
+ } cond ;
+
+: >compare-imm ( insn swap? -- insn' )
+ [
+ {
+ [ dst>> ]
+ [ src1>> ]
+ [ src2>> ]
+ [ cc>> ]
+ } cleave
+ ] dip
+ swap-compare
+ [ vreg>constant ] dip
+ next-vreg \ ##compare-imm new-insn ; inline
+
+: >boolean-insn ( insn ? -- insn' )
+ [ dst>> ] dip
+ {
+ { t [ t \ ##load-reference new-insn ] }
+ { f [ \ f tag-number \ ##load-immediate new-insn ] }
+ } case ;
+
+: rewrite-self-compare ( insn -- insn' )
+ dup (rewrite-self-compare) >boolean-insn ;
+
+M: ##compare rewrite
+ {
+ { [ dup src1>> vreg-small-constant? ] [ t >compare-imm ] }
+ { [ dup src2>> vreg-small-constant? ] [ f >compare-imm ] }
+ { [ dup self-compare? ] [ rewrite-self-compare ] }
+ [ drop f ]
+ } cond ;
+
+: fold-compare-imm ( insn -- insn' )
+ dup (fold-compare-imm) >boolean-insn ;
+
M: ##compare-imm rewrite
- dup rewrite-redundant-comparison? [
- rewrite-redundant-comparison
- dup number-values rewrite
- ] when
- dup ##compare-imm? [
- dup rewrite-tagged-comparison? [
- rewrite-tagged-comparison
- dup number-values rewrite
- ] when
- ] when ;
-
-M: insn rewrite ;
+ {
+ { [ dup rewrite-redundant-comparison? ] [ rewrite-redundant-comparison ] }
+ { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] }
+ { [ dup fold-compare-imm? ] [ fold-compare-imm ] }
+ [ drop f ]
+ } cond ;
+
+: constant-fold? ( insn -- ? )
+ src1>> vreg>expr constant-expr? ; inline
+
+GENERIC: constant-fold* ( x y insn -- z )
+
+M: ##add-imm constant-fold* drop + ;
+M: ##sub-imm constant-fold* drop - ;
+M: ##mul-imm constant-fold* drop * ;
+M: ##and-imm constant-fold* drop bitand ;
+M: ##or-imm constant-fold* drop bitor ;
+M: ##xor-imm constant-fold* drop bitxor ;
+M: ##shr-imm constant-fold* drop [ cell-bits 2^ wrap ] dip neg shift ;
+M: ##sar-imm constant-fold* drop neg shift ;
+M: ##shl-imm constant-fold* drop shift ;
+
+: constant-fold ( insn -- insn' )
+ [ dst>> ]
+ [ [ src1>> vreg>constant ] [ src2>> ] [ ] tri constant-fold* ] bi
+ \ ##load-immediate new-insn ; inline
+
+: reassociate? ( insn -- ? )
+ [ src1>> vreg>expr op>> ] [ class ] bi = ; inline
+
+: reassociate ( insn op -- insn )
+ [
+ {
+ [ dst>> ]
+ [ src1>> vreg>expr [ in1>> vn>vreg ] [ in2>> vn>constant ] bi ]
+ [ src2>> ]
+ [ ]
+ } cleave constant-fold*
+ ] dip
+ over small-enough? [ new-insn ] [ 2drop 2drop f ] if ; inline
+
+M: ##add-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ { [ dup reassociate? ] [ \ ##add-imm reassociate ] }
+ [ drop f ]
+ } cond ;
+
+: sub-imm>add-imm ( insn -- insn' )
+ [ dst>> ] [ src1>> ] [ src2>> neg ] tri dup small-enough?
+ [ \ ##add-imm new-insn ] [ 3drop f ] if ;
+
+M: ##sub-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ [ sub-imm>add-imm ]
+ } cond ;
+
+: strength-reduce-mul ( insn -- insn' )
+ [ [ dst>> ] [ src1>> ] bi ] [ src2>> log2 ] bi \ ##shl-imm new-insn ;
+
+: strength-reduce-mul? ( insn -- ? )
+ src2>> power-of-2? ;
+
+M: ##mul-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ { [ dup strength-reduce-mul? ] [ strength-reduce-mul ] }
+ { [ dup reassociate? ] [ \ ##mul-imm reassociate ] }
+ [ drop f ]
+ } cond ;
+
+M: ##and-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ { [ dup reassociate? ] [ \ ##and-imm reassociate ] }
+ [ drop f ]
+ } cond ;
+
+M: ##or-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ { [ dup reassociate? ] [ \ ##or-imm reassociate ] }
+ [ drop f ]
+ } cond ;
+
+M: ##xor-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ { [ dup reassociate? ] [ \ ##xor-imm reassociate ] }
+ [ drop f ]
+ } cond ;
+
+M: ##shl-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ [ drop f ]
+ } cond ;
+
+M: ##shr-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ [ drop f ]
+ } cond ;
+
+M: ##sar-imm rewrite
+ {
+ { [ dup constant-fold? ] [ constant-fold ] }
+ [ drop f ]
+ } cond ;
+
+: insn>imm-insn ( insn op swap? -- )
+ swap [
+ [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] dip
+ [ swap ] when vreg>constant
+ ] dip new-insn ; inline
+
+: rewrite-arithmetic ( insn op -- ? )
+ {
+ { [ over src2>> vreg-small-constant? ] [ f insn>imm-insn ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: rewrite-arithmetic-commutative ( insn op -- ? )
+ {
+ { [ over src2>> vreg-small-constant? ] [ f insn>imm-insn ] }
+ { [ over src1>> vreg-small-constant? ] [ t insn>imm-insn ] }
+ [ 2drop f ]
+ } cond ; inline
+
+M: ##add rewrite \ ##add-imm rewrite-arithmetic-commutative ;
+
+: subtraction-identity? ( insn -- ? )
+ [ src1>> ] [ src2>> ] bi [ vreg>vn ] bi@ eq? ;
+
+: rewrite-subtraction-identity ( insn -- insn' )
+ dst>> 0 \ ##load-immediate new-insn ;
+
+M: ##sub rewrite
+ {
+ { [ dup subtraction-identity? ] [ rewrite-subtraction-identity ] }
+ [ \ ##sub-imm rewrite-arithmetic ]
+ } cond ;
+
+M: ##mul rewrite \ ##mul-imm rewrite-arithmetic-commutative ;
+
+M: ##and rewrite \ ##and-imm rewrite-arithmetic-commutative ;
+
+M: ##or rewrite \ ##or-imm rewrite-arithmetic-commutative ;
+
+M: ##xor rewrite \ ##xor-imm rewrite-arithmetic-commutative ;
+
+M: ##shl rewrite \ ##shl-imm rewrite-arithmetic ;
+
+M: ##shr rewrite \ ##shr-imm rewrite-arithmetic ;
+
+M: ##sar rewrite \ ##sar-imm rewrite-arithmetic ;
+
+: box-displaced-alien? ( expr -- ? )
+ op>> \ ##box-displaced-alien eq? ;
+
+! ##box-displaced-alien f 1 2 3
+! ##unbox-any-c-ptr 4 1
+! =>
+! ##box-displaced-alien f 1 2 3
+! ##unbox-any-c-ptr 5 3
+! ##add 4 5 2
+
+:: rewrite-unbox-displaced-alien ( insn expr -- insns )
+ [
+ next-vreg :> temp
+ temp expr in2>> vn>vreg insn temp>> ##unbox-any-c-ptr
+ insn dst>> temp expr in1>> vn>vreg ##add
+ ] { } make ;
+
+M: ##unbox-any-c-ptr rewrite
+ dup src>> vreg>expr dup box-displaced-alien?
+ [ rewrite-unbox-displaced-alien ] [ 2drop f ] if ;
USING: kernel accessors combinators classes math layouts
compiler.cfg.instructions
compiler.cfg.value-numbering.graph
-compiler.cfg.value-numbering.expressions ;
+compiler.cfg.value-numbering.expressions locals ;
IN: compiler.cfg.value-numbering.simplify
! Return value of f means we didn't simplify.
GENERIC: simplify* ( expr -- vn/expr/f )
-: simplify-unbox ( in boxer -- vn/expr/f )
- over op>> eq? [ in>> ] [ drop f ] if ; inline
-
-: simplify-unbox-float ( in -- vn/expr/f )
- \ ##box-float simplify-unbox ; inline
-
: simplify-unbox-alien ( in -- vn/expr/f )
- \ ##box-alien simplify-unbox ; inline
+ dup op>> \ ##box-alien eq? [ in>> ] [ drop f ] if ; inline
M: unary-expr simplify*
#! Note the copy propagation: a copy always simplifies to
#! its source VN.
[ in>> vn>expr ] [ op>> ] bi {
{ \ ##copy [ ] }
- { \ ##copy-float [ ] }
- { \ ##unbox-float [ simplify-unbox-float ] }
{ \ ##unbox-alien [ simplify-unbox-alien ] }
{ \ ##unbox-any-c-ptr [ simplify-unbox-alien ] }
[ 2drop f ]
: expr-zero? ( expr -- ? ) T{ constant-expr f f 0 } = ; inline
+: expr-one? ( expr -- ? ) T{ constant-expr f f 1 } = ; inline
+
: >binary-expr< ( expr -- in1 in2 )
[ in1>> vn>expr ] [ in2>> vn>expr ] bi ; inline
[ 2drop f ]
} cond ; inline
-: useless-shift? ( in1 in2 -- ? )
+: simplify-sub ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ dup expr-zero? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: simplify-mul ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ over expr-one? ] [ drop ] }
+ { [ dup expr-one? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: simplify-and ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ 2dup eq? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: simplify-or ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ 2dup eq? ] [ drop ] }
+ { [ over expr-zero? ] [ nip ] }
+ { [ dup expr-zero? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: simplify-xor ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ over expr-zero? ] [ nip ] }
+ { [ dup expr-zero? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: useless-shr? ( in1 in2 -- ? )
over op>> \ ##shl-imm eq?
[ [ in2>> ] [ expr>vn ] bi* = ] [ 2drop f ] if ; inline
-: simplify-shift ( expr -- vn/expr/f )
- >binary-expr<
- 2dup useless-shift? [ drop in1>> ] [ 2drop f ] if ; inline
+: simplify-shr ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ 2dup useless-shr? ] [ drop in1>> ] }
+ { [ dup expr-zero? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: simplify-shl ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ dup expr-zero? ] [ drop ] }
+ [ 2drop f ]
+ } cond ; inline
+
+: simplify-box-displaced-alien ( expr -- vn/expr/f )
+ >binary-expr< {
+ { [ over expr-zero? ] [ nip ] }
+ [ 2drop f ]
+ } cond ;
M: binary-expr simplify*
dup op>> {
{ \ ##add [ simplify-add ] }
{ \ ##add-imm [ simplify-add ] }
- { \ ##shr-imm [ simplify-shift ] }
- { \ ##sar-imm [ simplify-shift ] }
+ { \ ##sub [ simplify-sub ] }
+ { \ ##sub-imm [ simplify-sub ] }
+ { \ ##mul [ simplify-mul ] }
+ { \ ##mul-imm [ simplify-mul ] }
+ { \ ##and [ simplify-and ] }
+ { \ ##and-imm [ simplify-and ] }
+ { \ ##or [ simplify-or ] }
+ { \ ##or-imm [ simplify-or ] }
+ { \ ##xor [ simplify-xor ] }
+ { \ ##xor-imm [ simplify-xor ] }
+ { \ ##shr [ simplify-shr ] }
+ { \ ##shr-imm [ simplify-shr ] }
+ { \ ##sar [ simplify-shr ] }
+ { \ ##sar-imm [ simplify-shr ] }
+ { \ ##shl [ simplify-shl ] }
+ { \ ##shl-imm [ simplify-shl ] }
+ { \ ##box-displaced-alien [ simplify-box-displaced-alien ] }
[ 2drop f ]
} case ;
{ [ dup integer? ] [ nip ] }
} cond ;
-GENERIC: number-values ( insn -- )
-
-M: ##flushable number-values [ >expr simplify ] [ dst>> ] bi set-vn ;
-M: insn number-values drop ;
+: number-values ( insn -- )
+ [ >expr simplify ] [ dst>> ] bi set-vn ;
-IN: compiler.cfg.value-numbering.tests
USING: compiler.cfg.value-numbering compiler.cfg.instructions
-compiler.cfg.registers compiler.cfg.debugger cpu.architecture
-tools.test kernel math combinators.short-circuit accessors
-sequences compiler.cfg vectors arrays ;
+compiler.cfg.registers compiler.cfg.debugger compiler.cfg.comparisons
+cpu.architecture tools.test kernel math combinators.short-circuit
+accessors sequences compiler.cfg.predecessors locals compiler.cfg.dce
+compiler.cfg.ssa.destruction compiler.cfg.loop-detection
+compiler.cfg.representations compiler.cfg assocs vectors arrays
+layouts namespaces ;
+IN: compiler.cfg.value-numbering.tests
: trim-temps ( insns -- insns )
[
} 1|| [ f >>temp ] when
] map ;
-: test-value-numbering ( insns -- insns )
- { } init-value-numbering
- value-numbering-step ;
+! Folding constants together
+[
+ {
+ T{ ##load-reference f 0 0.0 }
+ T{ ##load-reference f 1 -0.0 }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ }
+] [
+ {
+ T{ ##load-reference f 0 0.0 }
+ T{ ##load-reference f 1 -0.0 }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##load-reference f 0 0.0 }
+ T{ ##copy f 1 0 any-rep }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ }
+] [
+ {
+ T{ ##load-reference f 0 0.0 }
+ T{ ##load-reference f 1 0.0 }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##load-reference f 0 t }
+ T{ ##copy f 1 0 any-rep }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ }
+] [
+ {
+ T{ ##load-reference f 0 t }
+ T{ ##load-reference f 1 t }
+ T{ ##replace f 0 D 0 }
+ T{ ##replace f 1 D 1 }
+ } value-numbering-step
+] unit-test
+
+! Compare propagation
+[
+ {
+ T{ ##load-reference f 1 + }
+ T{ ##peek f 2 D 0 }
+ T{ ##compare f 4 2 1 cc> }
+ T{ ##copy f 6 4 any-rep }
+ T{ ##replace f 6 D 0 }
+ }
+] [
+ {
+ T{ ##load-reference f 1 + }
+ T{ ##peek f 2 D 0 }
+ T{ ##compare f 4 2 1 cc> }
+ T{ ##compare-imm f 6 4 5 cc/= }
+ T{ ##replace f 6 D 0 }
+ } value-numbering-step trim-temps
+] unit-test
+
+[
+ {
+ T{ ##load-reference f 1 + }
+ T{ ##peek f 2 D 0 }
+ T{ ##compare f 4 2 1 cc<= }
+ T{ ##compare f 6 2 1 cc> }
+ T{ ##replace f 6 D 0 }
+ }
+] [
+ {
+ T{ ##load-reference f 1 + }
+ T{ ##peek f 2 D 0 }
+ T{ ##compare f 4 2 1 cc<= }
+ T{ ##compare-imm f 6 4 5 cc= }
+ T{ ##replace f 6 D 0 }
+ } value-numbering-step trim-temps
+] unit-test
+
+[
+ {
+ T{ ##peek f 8 D 0 }
+ T{ ##peek f 9 D -1 }
+ T{ ##unbox-float f 10 8 }
+ T{ ##unbox-float f 11 9 }
+ T{ ##compare-float f 12 10 11 cc< }
+ T{ ##compare-float f 14 10 11 cc>= }
+ T{ ##replace f 14 D 0 }
+ }
+] [
+ {
+ T{ ##peek f 8 D 0 }
+ T{ ##peek f 9 D -1 }
+ T{ ##unbox-float f 10 8 }
+ T{ ##unbox-float f 11 9 }
+ T{ ##compare-float f 12 10 11 cc< }
+ T{ ##compare-imm f 14 12 5 cc= }
+ T{ ##replace f 14 D 0 }
+ } value-numbering-step trim-temps
+] unit-test
+
+[
+ {
+ T{ ##peek f 29 D -1 }
+ T{ ##peek f 30 D -2 }
+ T{ ##compare f 33 29 30 cc<= }
+ T{ ##compare-branch f 29 30 cc<= }
+ }
+] [
+ {
+ T{ ##peek f 29 D -1 }
+ T{ ##peek f 30 D -2 }
+ T{ ##compare f 33 29 30 cc<= }
+ T{ ##compare-imm-branch f 33 5 cc/= }
+ } value-numbering-step trim-temps
+] unit-test
+
+! Immediate operand conversion
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add f 2 0 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add f 2 1 0 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 -100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##sub f 2 0 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 0 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##sub f 1 0 0 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul f 2 0 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul f 2 1 0 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 1 D 0 }
+ T{ ##shl-imm f 2 1 3 }
+ }
+] [
+ {
+ T{ ##peek f 1 D 0 }
+ T{ ##mul-imm f 2 1 8 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and f 2 0 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and f 2 1 0 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or f 2 0 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or f 2 1 0 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor f 2 0 1 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor-imm f 2 0 100 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor f 2 1 0 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare-imm f 2 0 100 cc<= }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare f 2 0 1 cc<= }
+ } value-numbering-step trim-temps
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare-imm f 2 0 100 cc>= }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare f 2 1 0 cc<= }
+ } value-numbering-step trim-temps
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare-imm-branch f 0 100 cc<= }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare-branch f 0 1 cc<= }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare-imm-branch f 0 100 cc>= }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##compare-branch f 1 0 cc<= }
+ } value-numbering-step trim-temps
+] unit-test
+
+! Reassociation
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##add-imm f 4 0 150 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##add f 4 2 3 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##add-imm f 4 0 150 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add f 2 1 0 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##add f 4 3 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##add-imm f 4 0 50 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##sub f 4 2 3 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##add-imm f 2 0 -100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##add-imm f 4 0 -150 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##sub f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##sub f 4 2 3 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##mul-imm f 4 0 5000 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##mul f 4 2 3 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##mul-imm f 4 0 5000 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##mul f 2 1 0 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##mul f 4 3 2 }
+ } value-numbering-step
+] unit-test
[
{
- T{ ##peek f V int-regs 45 D 1 }
- T{ ##copy f V int-regs 48 V int-regs 45 }
- T{ ##compare-imm-branch f V int-regs 45 7 cc/= }
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##and-imm f 4 0 32 }
}
] [
{
- T{ ##peek f V int-regs 45 D 1 }
- T{ ##copy f V int-regs 48 V int-regs 45 }
- T{ ##compare-imm-branch f V int-regs 48 7 cc/= }
- } test-value-numbering
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##and f 4 2 3 }
+ } value-numbering-step
] unit-test
[
{
- T{ ##load-immediate f V int-regs 2 8 }
- T{ ##peek f V int-regs 3 D 0 }
- T{ ##slot-imm f V int-regs 4 V int-regs 3 1 3 }
- T{ ##replace f V int-regs 4 D 0 }
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##and-imm f 4 0 32 }
}
] [
{
- T{ ##load-immediate f V int-regs 2 8 }
- T{ ##peek f V int-regs 3 D 0 }
- T{ ##slot-imm f V int-regs 4 V int-regs 3 1 3 }
- T{ ##replace f V int-regs 4 D 0 }
- } test-value-numbering
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##and f 2 1 0 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##and f 4 3 2 }
+ } value-numbering-step
] unit-test
-[ t ] [
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##or-imm f 4 0 118 }
+ }
+] [
{
- T{ ##peek f V int-regs 1 D 0 }
- T{ ##dispatch f V int-regs 1 V int-regs 2 }
- } dup test-value-numbering =
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##or f 4 2 3 }
+ } value-numbering-step
] unit-test
-[ t ] [
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##or-imm f 4 0 118 }
+ }
+] [
{
- T{ ##peek f V int-regs 16 D 0 }
- T{ ##peek f V int-regs 17 D -1 }
- T{ ##sar-imm f V int-regs 18 V int-regs 17 3 }
- T{ ##add-imm f V int-regs 19 V int-regs 16 13 }
- T{ ##add f V int-regs 21 V int-regs 18 V int-regs 19 }
- T{ ##alien-unsigned-1 f V int-regs 22 V int-regs 21 }
- T{ ##shl-imm f V int-regs 23 V int-regs 22 3 }
- T{ ##replace f V int-regs 23 D 0 }
- } dup test-value-numbering =
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##or f 2 1 0 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##or f 4 3 2 }
+ } value-numbering-step
] unit-test
[
{
- T{ ##peek f V int-regs 1 D 0 }
- T{ ##shl-imm f V int-regs 2 V int-regs 1 3 }
- T{ ##shr-imm f V int-regs 3 V int-regs 2 3 }
- T{ ##replace f V int-regs 1 D 0 }
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##xor-imm f 4 0 86 }
}
] [
{
- T{ ##peek f V int-regs 1 D 0 }
- T{ ##mul-imm f V int-regs 2 V int-regs 1 8 }
- T{ ##shr-imm f V int-regs 3 V int-regs 2 3 }
- T{ ##replace f V int-regs 3 D 0 }
- } test-value-numbering
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor f 2 0 1 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##xor f 4 2 3 }
+ } value-numbering-step
] unit-test
[
{
- T{ ##load-reference f V int-regs 1 + }
- T{ ##peek f V int-regs 2 D 0 }
- T{ ##compare f V int-regs 4 V int-regs 2 V int-regs 1 cc> }
- T{ ##compare f V int-regs 6 V int-regs 2 V int-regs 1 cc> }
- T{ ##replace f V int-regs 4 D 0 }
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor-imm f 2 0 100 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##xor-imm f 4 0 86 }
}
] [
{
- T{ ##load-reference f V int-regs 1 + }
- T{ ##peek f V int-regs 2 D 0 }
- T{ ##compare f V int-regs 4 V int-regs 2 V int-regs 1 cc> }
- T{ ##compare-imm f V int-regs 6 V int-regs 4 5 cc/= }
- T{ ##replace f V int-regs 6 D 0 }
- } test-value-numbering trim-temps
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 100 }
+ T{ ##xor f 2 1 0 }
+ T{ ##load-immediate f 3 50 }
+ T{ ##xor f 4 3 2 }
+ } value-numbering-step
] unit-test
+! Simplification
[
{
- T{ ##load-reference f V int-regs 1 + }
- T{ ##peek f V int-regs 2 D 0 }
- T{ ##compare f V int-regs 4 V int-regs 2 V int-regs 1 cc<= }
- T{ ##compare f V int-regs 6 V int-regs 2 V int-regs 1 cc> }
- T{ ##replace f V int-regs 6 D 0 }
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##load-immediate f 2 0 }
+ T{ ##copy f 3 0 any-rep }
+ T{ ##replace f 3 D 0 }
}
] [
{
- T{ ##load-reference f V int-regs 1 + }
- T{ ##peek f V int-regs 2 D 0 }
- T{ ##compare f V int-regs 4 V int-regs 2 V int-regs 1 cc<= }
- T{ ##compare-imm f V int-regs 6 V int-regs 4 5 cc= }
- T{ ##replace f V int-regs 6 D 0 }
- } test-value-numbering trim-temps
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##sub f 2 1 1 }
+ T{ ##add f 3 0 2 }
+ T{ ##replace f 3 D 0 }
+ } value-numbering-step
] unit-test
[
{
- T{ ##peek f V int-regs 8 D 0 }
- T{ ##peek f V int-regs 9 D -1 }
- T{ ##unbox-float f V double-float-regs 10 V int-regs 8 }
- T{ ##unbox-float f V double-float-regs 11 V int-regs 9 }
- T{ ##compare-float f V int-regs 12 V double-float-regs 10 V double-float-regs 11 cc< }
- T{ ##compare-float f V int-regs 14 V double-float-regs 10 V double-float-regs 11 cc>= }
- T{ ##replace f V int-regs 14 D 0 }
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##load-immediate f 2 0 }
+ T{ ##copy f 3 0 any-rep }
+ T{ ##replace f 3 D 0 }
}
] [
{
- T{ ##peek f V int-regs 8 D 0 }
- T{ ##peek f V int-regs 9 D -1 }
- T{ ##unbox-float f V double-float-regs 10 V int-regs 8 }
- T{ ##unbox-float f V double-float-regs 11 V int-regs 9 }
- T{ ##compare-float f V int-regs 12 V double-float-regs 10 V double-float-regs 11 cc< }
- T{ ##compare-imm f V int-regs 14 V int-regs 12 5 cc= }
- T{ ##replace f V int-regs 14 D 0 }
- } test-value-numbering trim-temps
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##sub f 2 1 1 }
+ T{ ##sub f 3 0 2 }
+ T{ ##replace f 3 D 0 }
+ } value-numbering-step
] unit-test
[
{
- T{ ##peek f V int-regs 29 D -1 }
- T{ ##peek f V int-regs 30 D -2 }
- T{ ##compare f V int-regs 33 V int-regs 29 V int-regs 30 cc<= }
- T{ ##compare-branch f V int-regs 29 V int-regs 30 cc<= }
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##load-immediate f 2 0 }
+ T{ ##copy f 3 0 any-rep }
+ T{ ##replace f 3 D 0 }
}
] [
{
- T{ ##peek f V int-regs 29 D -1 }
- T{ ##peek f V int-regs 30 D -2 }
- T{ ##compare f V int-regs 33 V int-regs 29 V int-regs 30 cc<= }
- T{ ##compare-imm-branch f V int-regs 33 5 cc/= }
- } test-value-numbering trim-temps
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##sub f 2 1 1 }
+ T{ ##or f 3 0 2 }
+ T{ ##replace f 3 D 0 }
+ } value-numbering-step
] unit-test
[
{
- T{ ##copy f V int-regs 48 V int-regs 45 }
- T{ ##compare-imm-branch f V int-regs 45 7 cc/= }
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##load-immediate f 2 0 }
+ T{ ##copy f 3 0 any-rep }
+ T{ ##replace f 3 D 0 }
}
] [
- { V int-regs 45 } init-value-numbering
{
- T{ ##copy f V int-regs 48 V int-regs 45 }
- T{ ##compare-imm-branch f V int-regs 48 7 cc/= }
+ T{ ##peek f 0 D 0 }
+ T{ ##peek f 1 D 1 }
+ T{ ##sub f 2 1 1 }
+ T{ ##xor f 3 0 2 }
+ T{ ##replace f 3 D 0 }
} value-numbering-step
] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##copy f 2 0 any-rep }
+ T{ ##replace f 2 D 0 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##mul f 2 0 1 }
+ T{ ##replace f 2 D 0 }
+ } value-numbering-step
+] unit-test
+
+! Constant folding
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##load-immediate f 3 4 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##add f 3 1 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##load-immediate f 3 -2 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##sub f 3 1 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##load-immediate f 3 6 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##mul f 3 1 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 1 }
+ T{ ##load-immediate f 3 0 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 1 }
+ T{ ##and f 3 1 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 1 }
+ T{ ##load-immediate f 3 3 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 1 }
+ T{ ##or f 3 1 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##load-immediate f 3 1 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 2 }
+ T{ ##load-immediate f 2 3 }
+ T{ ##xor f 3 1 2 }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 3 8 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 1 }
+ T{ ##shl-imm f 3 1 3 }
+ } value-numbering-step
+] unit-test
+
+cell 8 = [
+ [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 -1 }
+ T{ ##load-immediate f 3 HEX: ffffffffffff }
+ }
+ ] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 -1 }
+ T{ ##shr-imm f 3 1 16 }
+ } value-numbering-step
+ ] unit-test
+] when
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 -8 }
+ T{ ##load-immediate f 3 -4 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 -8 }
+ T{ ##sar-imm f 3 1 1 }
+ } value-numbering-step
+] unit-test
+
+cell 8 = [
+ [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 65536 }
+ T{ ##load-immediate f 2 140737488355328 }
+ T{ ##add f 3 0 2 }
+ }
+ ] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 65536 }
+ T{ ##shl-imm f 2 1 31 }
+ T{ ##add f 3 0 2 }
+ } value-numbering-step
+ ] unit-test
+
+ [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 140737488355328 }
+ T{ ##add f 3 0 2 }
+ }
+ ] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 140737488355328 }
+ T{ ##add f 3 0 2 }
+ } value-numbering-step
+ ] unit-test
+
+ [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 2147483647 }
+ T{ ##add-imm f 3 0 2147483647 }
+ T{ ##add-imm f 4 3 2147483647 }
+ }
+ ] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 2147483647 }
+ T{ ##add f 3 0 2 }
+ T{ ##add f 4 3 2 }
+ } value-numbering-step
+ ] unit-test
+] when
+
+! Displaced alien optimizations
+3 vreg-counter set-global
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 16 }
+ T{ ##box-displaced-alien f 1 2 0 }
+ T{ ##unbox-any-c-ptr f 4 0 }
+ T{ ##add-imm f 3 4 16 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 16 }
+ T{ ##box-displaced-alien f 1 2 0 }
+ T{ ##unbox-any-c-ptr f 3 1 }
+ } value-numbering-step
+] unit-test
+
+4 vreg-counter set-global
+
+[
+ {
+ T{ ##box-alien f 0 1 }
+ T{ ##load-immediate f 2 16 }
+ T{ ##box-displaced-alien f 3 2 0 }
+ T{ ##copy f 5 1 any-rep }
+ T{ ##add-imm f 4 5 16 }
+ }
+] [
+ {
+ T{ ##box-alien f 0 1 }
+ T{ ##load-immediate f 2 16 }
+ T{ ##box-displaced-alien f 3 2 0 }
+ T{ ##unbox-any-c-ptr f 4 3 }
+ } value-numbering-step
+] unit-test
+
+3 vreg-counter set-global
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 0 }
+ T{ ##copy f 3 0 any-rep }
+ T{ ##replace f 3 D 1 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 2 0 }
+ T{ ##box-displaced-alien f 3 2 0 }
+ T{ ##replace f 3 D 1 }
+ } value-numbering-step
+] unit-test
+
+! Branch folding
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##load-immediate f 3 5 }
+ }
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare f 3 1 2 cc= }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##load-reference f 3 t }
+ }
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare f 3 1 2 cc/= }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##load-reference f 3 t }
+ }
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare f 3 1 2 cc< }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##load-immediate f 3 5 }
+ }
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare f 3 2 1 cc< }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 5 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc< }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-reference f 1 t }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc<= }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 5 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc> }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-reference f 1 t }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc>= }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-immediate f 1 5 }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc/= }
+ } value-numbering-step
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-reference f 1 t }
+ }
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc= }
+ } value-numbering-step
+] unit-test
+
+: test-branch-folding ( insns -- insns' n )
+ <basic-block>
+ [ V{ 0 1 } clone >>successors basic-block set value-numbering-step ] keep
+ successors>> first ;
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##branch }
+ }
+ 1
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare-branch f 1 2 cc= }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##branch }
+ }
+ 0
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare-branch f 1 2 cc/= }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##branch }
+ }
+ 0
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare-branch f 1 2 cc< }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##branch }
+ }
+ 1
+] [
+ {
+ T{ ##load-immediate f 1 1 }
+ T{ ##load-immediate f 2 2 }
+ T{ ##compare-branch f 2 1 cc< }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+ }
+ 1
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc< }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+ }
+ 0
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc<= }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+ }
+ 1
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc> }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+ }
+ 0
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc>= }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+ }
+ 0
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc= }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+ }
+ 1
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc/= }
+ } test-branch-folding
+] unit-test
+
+[
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##load-reference f 1 t }
+ T{ ##branch }
+ }
+ 0
+] [
+ {
+ T{ ##peek f 0 D 0 }
+ T{ ##compare f 1 0 0 cc<= }
+ T{ ##compare-imm-branch f 1 5 cc/= }
+ } test-branch-folding
+] unit-test
+
+! More branch folding tests
+V{ T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##compare-branch f 0 0 cc< }
+} 1 test-bb
+
+V{
+ T{ ##load-immediate f 1 1 }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##load-immediate f 2 2 }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##phi f 3 H{ { 2 1 } { 3 2 } } }
+ T{ ##replace f 3 D 0 }
+ T{ ##return }
+} 4 test-bb
+
+test-diamond
+
+[ ] [
+ cfg new 0 get >>entry dup cfg set
+ value-numbering
+ select-representations
+ destruct-ssa drop
+] unit-test
+
+[ 1 ] [ 1 get successors>> length ] unit-test
+
+[ t ] [ 1 get successors>> first 3 get eq? ] unit-test
+
+[ 2 ] [ 4 get instructions>> length ] unit-test
+
+V{
+ T{ ##peek f 0 D 0 }
+ T{ ##branch }
+} 0 test-bb
+
+V{
+ T{ ##peek f 1 D 1 }
+ T{ ##compare-branch f 1 1 cc< }
+} 1 test-bb
+
+V{
+ T{ ##copy f 2 0 any-rep }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##phi f 3 V{ } }
+ T{ ##branch }
+} 3 test-bb
+
+V{
+ T{ ##replace f 3 D 0 }
+ T{ ##return }
+} 4 test-bb
+
+1 get 1 2array
+2 get 0 2array 2array 3 get instructions>> first (>>inputs)
+
+test-diamond
+
+[ ] [
+ cfg new 0 get >>entry
+ value-numbering
+ eliminate-dead-code
+ drop
+] unit-test
+
+[ t ] [ 1 get successors>> first 3 get eq? ] unit-test
+
+[ 1 ] [ 3 get instructions>> first inputs>> assoc-size ] unit-test
+
+V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+
+V{
+ T{ ##peek { dst 15 } { loc D 0 } }
+ T{ ##copy { dst 16 } { src 15 } { rep any-rep } }
+ T{ ##copy { dst 17 } { src 15 } { rep any-rep } }
+ T{ ##copy { dst 18 } { src 15 } { rep any-rep } }
+ T{ ##copy { dst 19 } { src 15 } { rep any-rep } }
+ T{ ##compare
+ { dst 20 }
+ { src1 18 }
+ { src2 19 }
+ { cc cc= }
+ { temp 22 }
+ }
+ T{ ##copy { dst 21 } { src 20 } { rep any-rep } }
+ T{ ##compare-imm-branch
+ { src1 21 }
+ { src2 5 }
+ { cc cc/= }
+ }
+} 1 test-bb
+
+V{
+ T{ ##copy { dst 23 } { src 15 } { rep any-rep } }
+ T{ ##copy { dst 24 } { src 15 } { rep any-rep } }
+ T{ ##load-reference { dst 25 } { obj t } }
+ T{ ##branch }
+} 2 test-bb
+
+V{
+ T{ ##replace { src 25 } { loc D 0 } }
+ T{ ##epilogue }
+ T{ ##return }
+} 3 test-bb
+
+V{
+ T{ ##copy { dst 26 } { src 15 } { rep any-rep } }
+ T{ ##copy { dst 27 } { src 15 } { rep any-rep } }
+ T{ ##add
+ { dst 28 }
+ { src1 26 }
+ { src2 27 }
+ }
+ T{ ##branch }
+} 4 test-bb
+
+V{
+ T{ ##replace { src 28 } { loc D 0 } }
+ T{ ##epilogue }
+ T{ ##return }
+} 5 test-bb
+
+0 1 edge
+1 { 2 4 } edges
+2 3 edge
+4 5 edge
+
+[ ] [
+ cfg new 0 get >>entry
+ value-numbering eliminate-dead-code drop
+] unit-test
+
+[ f ] [ 1 get instructions>> [ ##peek? ] any? ] unit-test
+
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces assocs biassocs classes kernel math accessors
-sorting sets sequences
-compiler.cfg.local
-compiler.cfg.liveness
+USING: namespaces assocs kernel accessors
+sorting sets sequences arrays
+cpu.architecture
+sequences.deep
+compiler.cfg
+compiler.cfg.rpo
+compiler.cfg.instructions
compiler.cfg.value-numbering.graph
compiler.cfg.value-numbering.expressions
-compiler.cfg.value-numbering.propagate
compiler.cfg.value-numbering.simplify
compiler.cfg.value-numbering.rewrite ;
IN: compiler.cfg.value-numbering
-: number-input-values ( live-in -- )
- [ [ f next-input-expr simplify ] dip set-vn ] each ;
+! Local value numbering.
-: init-value-numbering ( live-in -- )
- init-value-graph
- init-expressions
- number-input-values ;
+: >copy ( insn -- insn/##copy )
+ dup dst>> dup vreg>vn vn>vreg
+ 2dup eq? [ 2drop ] [ any-rep \ ##copy new-insn nip ] if ;
+
+: rewrite-loop ( insn -- insn' )
+ dup rewrite [ rewrite-loop ] [ ] ?if ;
+
+GENERIC: process-instruction ( insn -- insn' )
+
+M: ##flushable process-instruction
+ dup rewrite
+ [ process-instruction ]
+ [ dup number-values >copy ] ?if ;
+
+M: insn process-instruction
+ dup rewrite
+ [ process-instruction ] [ ] ?if ;
+
+M: array process-instruction
+ [ process-instruction ] map ;
: value-numbering-step ( insns -- insns' )
- [ [ number-values ] [ rewrite propagate ] bi ] map ;
+ init-value-graph
+ init-expressions
+ [ process-instruction ] map flatten ;
: value-numbering ( cfg -- cfg' )
- [ init-value-numbering ] [ value-numbering-step ] local-optimization ;
+ [ value-numbering-step ] local-optimization
+
+ cfg-changed predecessors-changed ;
--- /dev/null
+Slava Pestov
+Daniel Ehrenberg
-USING: compiler.cfg.write-barrier compiler.cfg.instructions
-compiler.cfg.registers compiler.cfg.debugger cpu.architecture
-arrays tools.test vectors compiler.cfg kernel accessors ;
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs compiler.cfg
+compiler.cfg.alias-analysis compiler.cfg.block-joining
+compiler.cfg.branch-splitting compiler.cfg.copy-prop
+compiler.cfg.dce compiler.cfg.debugger
+compiler.cfg.instructions compiler.cfg.loop-detection
+compiler.cfg.registers compiler.cfg.ssa.construction
+compiler.cfg.tco compiler.cfg.useless-conditionals
+compiler.cfg.utilities compiler.cfg.value-numbering
+compiler.cfg.write-barrier cpu.architecture kernel
+kernel.private math namespaces sequences sequences.private
+tools.test vectors ;
IN: compiler.cfg.write-barrier.tests
: test-write-barrier ( insns -- insns )
- write-barriers-step ;
+ <simple-block> dup write-barriers-step instructions>> ;
[
- {
- T{ ##peek f V int-regs 4 D 0 f }
- T{ ##copy f V int-regs 6 V int-regs 4 f }
- T{ ##allot f V int-regs 7 24 array V int-regs 8 f }
- T{ ##load-immediate f V int-regs 9 8 f }
- T{ ##set-slot-imm f V int-regs 9 V int-regs 7 1 3 f }
- T{ ##set-slot-imm f V int-regs 6 V int-regs 7 2 3 f }
- T{ ##replace f V int-regs 7 D 0 f }
+ V{
+ T{ ##peek f 4 D 0 f }
+ T{ ##allot f 7 24 array 8 f }
+ T{ ##load-immediate f 9 8 f }
+ T{ ##set-slot-imm f 9 7 1 3 f }
+ T{ ##set-slot-imm f 4 7 2 3 f }
+ T{ ##replace f 7 D 0 f }
+ T{ ##branch }
}
] [
{
- T{ ##peek f V int-regs 4 D 0 }
- T{ ##copy f V int-regs 6 V int-regs 4 }
- T{ ##allot f V int-regs 7 24 array V int-regs 8 }
- T{ ##load-immediate f V int-regs 9 8 }
- T{ ##set-slot-imm f V int-regs 9 V int-regs 7 1 3 }
- T{ ##write-barrier f V int-regs 7 V int-regs 10 V int-regs 11 }
- T{ ##set-slot-imm f V int-regs 6 V int-regs 7 2 3 }
- T{ ##write-barrier f V int-regs 7 V int-regs 12 V int-regs 13 }
- T{ ##replace f V int-regs 7 D 0 }
+ T{ ##peek f 4 D 0 }
+ T{ ##allot f 7 24 array 8 }
+ T{ ##load-immediate f 9 8 }
+ T{ ##set-slot-imm f 9 7 1 3 }
+ T{ ##write-barrier f 7 10 11 }
+ T{ ##set-slot-imm f 4 7 2 3 }
+ T{ ##write-barrier f 7 12 13 }
+ T{ ##replace f 7 D 0 }
} test-write-barrier
] unit-test
[
- {
- T{ ##load-immediate f V int-regs 4 24 }
- T{ ##peek f V int-regs 5 D -1 }
- T{ ##peek f V int-regs 6 D -2 }
- T{ ##set-slot-imm f V int-regs 5 V int-regs 6 3 2 }
- T{ ##write-barrier f V int-regs 6 V int-regs 7 V int-regs 8 }
+ V{
+ T{ ##load-immediate f 4 24 }
+ T{ ##peek f 5 D -1 }
+ T{ ##peek f 6 D -2 }
+ T{ ##set-slot-imm f 5 6 3 2 }
+ T{ ##write-barrier f 6 7 8 }
+ T{ ##branch }
}
] [
{
- T{ ##load-immediate f V int-regs 4 24 }
- T{ ##peek f V int-regs 5 D -1 }
- T{ ##peek f V int-regs 6 D -2 }
- T{ ##set-slot-imm f V int-regs 5 V int-regs 6 3 2 }
- T{ ##write-barrier f V int-regs 6 V int-regs 7 V int-regs 8 }
+ T{ ##load-immediate f 4 24 }
+ T{ ##peek f 5 D -1 }
+ T{ ##peek f 6 D -2 }
+ T{ ##set-slot-imm f 5 6 3 2 }
+ T{ ##write-barrier f 6 7 8 }
} test-write-barrier
] unit-test
[
- {
- T{ ##peek f V int-regs 19 D -3 }
- T{ ##peek f V int-regs 22 D -2 }
- T{ ##copy f V int-regs 23 V int-regs 19 }
- T{ ##set-slot-imm f V int-regs 22 V int-regs 23 3 2 }
- T{ ##write-barrier f V int-regs 23 V int-regs 24 V int-regs 25 }
- T{ ##copy f V int-regs 26 V int-regs 19 }
- T{ ##peek f V int-regs 28 D -1 }
- T{ ##copy f V int-regs 29 V int-regs 19 }
- T{ ##set-slot-imm f V int-regs 28 V int-regs 29 4 2 }
+ V{
+ T{ ##peek f 19 D -3 }
+ T{ ##peek f 22 D -2 }
+ T{ ##set-slot-imm f 22 19 3 2 }
+ T{ ##write-barrier f 19 24 25 }
+ T{ ##peek f 28 D -1 }
+ T{ ##set-slot-imm f 28 19 4 2 }
+ T{ ##branch }
}
] [
{
- T{ ##peek f V int-regs 19 D -3 }
- T{ ##peek f V int-regs 22 D -2 }
- T{ ##copy f V int-regs 23 V int-regs 19 }
- T{ ##set-slot-imm f V int-regs 22 V int-regs 23 3 2 }
- T{ ##write-barrier f V int-regs 23 V int-regs 24 V int-regs 25 }
- T{ ##copy f V int-regs 26 V int-regs 19 }
- T{ ##peek f V int-regs 28 D -1 }
- T{ ##copy f V int-regs 29 V int-regs 19 }
- T{ ##set-slot-imm f V int-regs 28 V int-regs 29 4 2 }
- T{ ##write-barrier f V int-regs 29 V int-regs 30 V int-regs 3 }
+ T{ ##peek f 19 D -3 }
+ T{ ##peek f 22 D -2 }
+ T{ ##set-slot-imm f 22 19 3 2 }
+ T{ ##write-barrier f 19 24 25 }
+ T{ ##peek f 28 D -1 }
+ T{ ##set-slot-imm f 28 19 4 2 }
+ T{ ##write-barrier f 19 30 3 }
} test-write-barrier
] unit-test
+
+V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 1 test-bb
+V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 2 test-bb
+1 get 2 get 1vector >>successors drop
+cfg new 1 get >>entry 0 set
+
+[ ] [ 0 [ eliminate-write-barriers ] change ] unit-test
+[ V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} ] [ 1 get instructions>> ] unit-test
+[ V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+} ] [ 2 get instructions>> ] unit-test
+
+V{
+ T{ ##allot f 1 }
+} 1 test-bb
+V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 2 test-bb
+1 get 2 get 1vector >>successors drop
+cfg new 1 get >>entry 0 set
+
+[ ] [ 0 [ eliminate-write-barriers ] change ] unit-test
+[ V{
+ T{ ##allot f 1 }
+} ] [ 1 get instructions>> ] unit-test
+[ V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+} ] [ 2 get instructions>> ] unit-test
+
+V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 1 test-bb
+V{
+ T{ ##allot }
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 2 test-bb
+1 get 2 get 1vector >>successors drop
+cfg new 1 get >>entry 0 set
+
+[ ] [ 0 [ eliminate-write-barriers ] change ] unit-test
+[ V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} ] [ 1 get instructions>> ] unit-test
+[ V{
+ T{ ##allot }
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} ] [ 2 get instructions>> ] unit-test
+
+V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 1 test-bb
+V{
+ T{ ##allot }
+} 2 test-bb
+1 get 2 get 1vector >>successors drop
+V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} 3 test-bb
+2 get 3 get 1vector >>successors drop
+cfg new 1 get >>entry 0 set
+[ ] [ 0 [ eliminate-write-barriers ] change ] unit-test
+[ V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} ] [ 1 get instructions>> ] unit-test
+[ V{ T{ ##allot } } ] [ 2 get instructions>> ] unit-test
+[ V{
+ T{ ##set-slot-imm f 2 1 3 4 }
+ T{ ##write-barrier f 1 2 3 }
+} ] [ 3 get instructions>> ] unit-test
+
+: reverse-here' ( seq -- )
+ { array } declare
+ [ length 2/ iota ] [ length ] [ ] tri
+ [ [ over - 1 - ] dip exchange-unsafe ] 2curry each ;
+
+: write-barrier-stats ( word -- cfg )
+ test-cfg first [
+ optimize-tail-calls
+ delete-useless-conditionals
+ split-branches
+ join-blocks
+ construct-ssa
+ alias-analysis
+ value-numbering
+ copy-propagation
+ eliminate-dead-code
+ eliminate-write-barriers
+ ] with-cfg
+ post-order>> write-barriers
+ [ [ loop-nesting-at ] [ length ] bi* ] assoc-map ;
+
+[ { { 0 1 } } ] [ \ reverse-here' write-barrier-stats ] unit-test
-! Copyright (C) 2008, 2009 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors namespaces assocs sets sequences locals
-compiler.cfg compiler.cfg.instructions compiler.cfg.copy-prop
-compiler.cfg.liveness compiler.cfg.local ;
+USING: kernel accessors namespaces assocs sets sequences
+fry combinators.short-circuit locals make arrays
+compiler.cfg
+compiler.cfg.dominance
+compiler.cfg.predecessors
+compiler.cfg.loop-detection
+compiler.cfg.rpo
+compiler.cfg.instructions
+compiler.cfg.registers
+compiler.cfg.dataflow-analysis
+compiler.cfg.utilities ;
IN: compiler.cfg.write-barrier
! Eliminate redundant write barrier hits.
! Objects which have been mutated
SYMBOL: mutated
-GENERIC: eliminate-write-barrier ( insn -- insn' )
+GENERIC: eliminate-write-barrier ( insn -- ? )
M: ##allot eliminate-write-barrier
- dup dst>> safe get conjoin ;
+ dst>> safe get conjoin t ;
M: ##write-barrier eliminate-write-barrier
- dup src>> resolve dup
- [ safe get key? not ]
- [ mutated get key? ] bi and
- [ safe get conjoin ] [ 2drop f ] if ;
+ src>> dup safe get key? not
+ [ safe get conjoin t ] [ drop f ] if ;
-M: ##copy eliminate-write-barrier
- dup record-copy ;
+M: insn eliminate-write-barrier drop t ;
-M: ##set-slot eliminate-write-barrier
- dup obj>> resolve mutated get conjoin ;
+! This doesn't actually benefit from being a dataflow analysis
+! might as well be dominator-based
+! Dealing with phi functions would help, though
+FORWARD-ANALYSIS: safe
-M: ##set-slot-imm eliminate-write-barrier
- dup obj>> resolve mutated get conjoin ;
+: has-allocation? ( bb -- ? )
+ instructions>> [ { [ ##allocation? ] [ ##call? ] } 1|| ] any? ;
-M: insn eliminate-write-barrier ;
+M: safe-analysis transfer-set
+ drop [ H{ } assoc-clone-like safe set ] dip
+ instructions>> [
+ eliminate-write-barrier drop
+ ] each safe get ;
-: write-barriers-step ( insns -- insns' )
- H{ } clone safe set
+M: safe-analysis join-sets
+ drop has-allocation? [ drop H{ } clone ] [ assoc-refine ] if ;
+
+: write-barriers-step ( bb -- )
+ dup safe-in H{ } assoc-clone-like safe set
+ instructions>> [ eliminate-write-barrier ] filter-here ;
+
+GENERIC: remove-dead-barrier ( insn -- ? )
+
+M: ##write-barrier remove-dead-barrier
+ src>> mutated get key? ;
+
+M: ##set-slot remove-dead-barrier
+ obj>> mutated get conjoin t ;
+
+M: ##set-slot-imm remove-dead-barrier
+ obj>> mutated get conjoin t ;
+
+M: insn remove-dead-barrier drop t ;
+
+: remove-dead-barriers ( bb -- )
H{ } clone mutated set
- H{ } clone copies set
- [ eliminate-write-barrier ] map sift ;
+ instructions>> [ remove-dead-barrier ] filter-here ;
+
+! Availability of slot
+! Anticipation of this and set-slot would help too, maybe later
+FORWARD-ANALYSIS: slot
+
+UNION: access ##read ##write ;
+
+M: slot-analysis transfer-set
+ drop [ H{ } assoc-clone-like ] dip
+ instructions>> over '[
+ dup access? [
+ obj>> _ conjoin
+ ] [ drop ] if
+ ] each ;
+
+: slot-available? ( vreg bb -- ? )
+ slot-in key? ;
+
+: make-barriers ( vregs -- bb )
+ [ [ next-vreg next-vreg ##write-barrier ] each ] V{ } make <simple-block> ;
+
+: emit-barriers ( vregs loop -- )
+ swap [
+ [ [ header>> predecessors>> ] [ ends>> keys ] bi diff ]
+ [ header>> ] bi
+ ] [ make-barriers ] bi*
+ insert-basic-block ;
+
+: write-barriers ( bbs -- bb=>barriers )
+ [
+ dup instructions>>
+ [ ##write-barrier? ] filter
+ [ src>> ] map
+ ] { } map>assoc
+ [ nip empty? not ] assoc-filter ;
+
+: filter-dominant ( bb=>barriers bbs -- barriers )
+ '[ drop _ [ dominates? ] with all? ] assoc-filter
+ values concat prune ;
+
+: dominant-write-barriers ( loop -- vregs )
+ [ blocks>> values write-barriers ] [ ends>> keys ] bi filter-dominant ;
+
+: safe-loops ( -- loops )
+ loops get values
+ [ blocks>> keys [ has-allocation? not ] all? ] filter ;
+
+:: insert-extra-barriers ( cfg -- )
+ safe-loops [| loop |
+ cfg needs-dominance needs-predecessors drop
+ loop dominant-write-barriers
+ loop header>> '[ _ slot-available? ] filter
+ [ loop emit-barriers cfg cfg-changed drop ] unless-empty
+ ] each ;
+
+: contains-write-barrier? ( cfg -- ? )
+ post-order [ instructions>> [ ##write-barrier? ] any? ] any? ;
: eliminate-write-barriers ( cfg -- cfg' )
- [ drop ] [ write-barriers-step ] local-optimization ;
+ dup contains-write-barrier? [
+ needs-loops
+ dup [ remove-dead-barriers ] each-basic-block
+ dup compute-slot-sets
+ dup insert-extra-barriers
+ dup compute-safe-sets
+ dup [ write-barriers-step ] each-basic-block
+ ] when ;
-IN: compiler.codegen.tests
USING: compiler.codegen.fixup tools.test cpu.architecture math kernel make
compiler.constants ;
+IN: compiler.codegen.tests
[ ] [ [ ] with-fixup drop ] unit-test
[ ] [ [ \ + %call ] with-fixup drop ] unit-test
kernel kernel.private layouts assocs words summary arrays
combinators classes.algebra alien alien.c-types alien.structs
alien.strings alien.arrays alien.complex alien.libraries sets libc
-continuations.private fry cpu.architecture
+continuations.private fry cpu.architecture classes locals
source-files.errors
compiler.errors
compiler.alien
+compiler.constants
compiler.cfg
compiler.cfg.instructions
compiler.cfg.stack-frame
compiler.utilities ;
IN: compiler.codegen
-GENERIC: generate-insn ( insn -- )
-
-SYMBOL: registers
+SYMBOL: insn-counts
-: register ( vreg -- operand )
- registers get at [ "Bad value" throw ] unless* ;
+H{ } clone insn-counts set-global
-: ?register ( obj -- operand )
- dup vreg? [ register ] when ;
+GENERIC: generate-insn ( insn -- )
TUPLE: asm label code calls ;
[ word>> init-generator ]
[
instructions>>
- [ [ regs>> registers set ] [ generate-insn ] bi ] each
+ [
+ [ class insn-counts get inc-at ]
+ [ generate-insn ]
+ bi
+ ] each
] bi
] with-fixup ;
: lookup-label ( id -- label )
labels get [ drop <label> ] cache ;
+M: ##no-tco generate-insn drop ;
+
M: ##load-immediate generate-insn
- [ dst>> register ] [ val>> ] bi %load-immediate ;
+ [ dst>> ] [ val>> ] bi %load-immediate ;
M: ##load-reference generate-insn
- [ dst>> register ] [ obj>> ] bi %load-reference ;
+ [ dst>> ] [ obj>> ] bi %load-reference ;
M: ##peek generate-insn
- [ dst>> register ] [ loc>> ] bi %peek ;
+ [ dst>> ] [ loc>> ] bi %peek ;
M: ##replace generate-insn
- [ src>> register ] [ loc>> ] bi %replace ;
+ [ src>> ] [ loc>> ] bi %replace ;
M: ##inc-d generate-insn n>> %inc-d ;
M: ##return generate-insn drop %return ;
M: _dispatch generate-insn
- [ src>> register ] [ temp>> register ] bi %dispatch ;
+ [ src>> ] [ temp>> ] bi %dispatch ;
M: _dispatch-label generate-insn
- label>> lookup-label %dispatch-label ;
+ label>> lookup-label
+ cell 0 <repetition> %
+ rc-absolute-cell label-fixup ;
: >slot< ( insn -- dst obj slot tag )
- {
- [ dst>> register ]
- [ obj>> register ]
- [ slot>> ?register ]
- [ tag>> ]
- } cleave ; inline
+ { [ dst>> ] [ obj>> ] [ slot>> ] [ tag>> ] } cleave ; inline
M: ##slot generate-insn
- [ >slot< ] [ temp>> register ] bi %slot ;
+ [ >slot< ] [ temp>> ] bi %slot ;
M: ##slot-imm generate-insn
>slot< %slot-imm ;
: >set-slot< ( insn -- src obj slot tag )
- {
- [ src>> register ]
- [ obj>> register ]
- [ slot>> ?register ]
- [ tag>> ]
- } cleave ; inline
+ { [ src>> ] [ obj>> ] [ slot>> ] [ tag>> ] } cleave ; inline
M: ##set-slot generate-insn
- [ >set-slot< ] [ temp>> register ] bi %set-slot ;
+ [ >set-slot< ] [ temp>> ] bi %set-slot ;
M: ##set-slot-imm generate-insn
>set-slot< %set-slot-imm ;
M: ##string-nth generate-insn
- {
- [ dst>> register ]
- [ obj>> register ]
- [ index>> register ]
- [ temp>> register ]
- } cleave %string-nth ;
+ { [ dst>> ] [ obj>> ] [ index>> ] [ temp>> ] } cleave %string-nth ;
M: ##set-string-nth-fast generate-insn
- {
- [ src>> register ]
- [ obj>> register ]
- [ index>> register ]
- [ temp>> register ]
- } cleave %set-string-nth-fast ;
+ { [ src>> ] [ obj>> ] [ index>> ] [ temp>> ] } cleave %set-string-nth-fast ;
: dst/src ( insn -- dst src )
- [ dst>> register ] [ src>> register ] bi ; inline
+ [ dst>> ] [ src>> ] bi ; inline
: dst/src1/src2 ( insn -- dst src1 src2 )
- [ dst>> register ]
- [ src1>> register ]
- [ src2>> ?register ] tri ; inline
+ [ dst>> ] [ src1>> ] [ src2>> ] tri ; inline
M: ##add generate-insn dst/src1/src2 %add ;
M: ##add-imm generate-insn dst/src1/src2 %add-imm ;
M: ##or-imm generate-insn dst/src1/src2 %or-imm ;
M: ##xor generate-insn dst/src1/src2 %xor ;
M: ##xor-imm generate-insn dst/src1/src2 %xor-imm ;
+M: ##shl generate-insn dst/src1/src2 %shl ;
M: ##shl-imm generate-insn dst/src1/src2 %shl-imm ;
+M: ##shr generate-insn dst/src1/src2 %shr ;
M: ##shr-imm generate-insn dst/src1/src2 %shr-imm ;
+M: ##sar generate-insn dst/src1/src2 %sar ;
M: ##sar-imm generate-insn dst/src1/src2 %sar-imm ;
M: ##not generate-insn dst/src %not ;
M: ##log2 generate-insn dst/src %log2 ;
-: src1/src2 ( insn -- src1 src2 )
- [ src1>> register ] [ src2>> register ] bi ; inline
+: label/dst/src1/src2 ( insn -- label dst src1 src2 )
+ [ label>> lookup-label ] [ dst/src1/src2 ] bi ; inline
-: src1/src2/temp1/temp2 ( insn -- src1 src2 temp1 temp2 )
- [ src1/src2 ] [ temp1>> register ] [ temp2>> register ] tri ; inline
-
-M: ##fixnum-add generate-insn src1/src2 %fixnum-add ;
-M: ##fixnum-add-tail generate-insn src1/src2 %fixnum-add-tail ;
-M: ##fixnum-sub generate-insn src1/src2 %fixnum-sub ;
-M: ##fixnum-sub-tail generate-insn src1/src2 %fixnum-sub-tail ;
-M: ##fixnum-mul generate-insn src1/src2/temp1/temp2 %fixnum-mul ;
-M: ##fixnum-mul-tail generate-insn src1/src2/temp1/temp2 %fixnum-mul-tail ;
+M: _fixnum-add generate-insn label/dst/src1/src2 %fixnum-add ;
+M: _fixnum-sub generate-insn label/dst/src1/src2 %fixnum-sub ;
+M: _fixnum-mul generate-insn label/dst/src1/src2 %fixnum-mul ;
: dst/src/temp ( insn -- dst src temp )
- [ dst/src ] [ temp>> register ] bi ; inline
+ [ dst/src ] [ temp>> ] bi ; inline
M: ##integer>bignum generate-insn dst/src/temp %integer>bignum ;
M: ##bignum>integer generate-insn dst/src/temp %bignum>integer ;
M: ##mul-float generate-insn dst/src1/src2 %mul-float ;
M: ##div-float generate-insn dst/src1/src2 %div-float ;
+M: ##sqrt generate-insn dst/src %sqrt ;
+
M: ##integer>float generate-insn dst/src %integer>float ;
M: ##float>integer generate-insn dst/src %float>integer ;
-M: ##copy generate-insn dst/src %copy ;
-M: ##copy-float generate-insn dst/src %copy-float ;
-M: ##unbox-float generate-insn dst/src %unbox-float ;
-M: ##unbox-any-c-ptr generate-insn dst/src/temp %unbox-any-c-ptr ;
-M: ##box-float generate-insn dst/src/temp %box-float ;
-M: ##box-alien generate-insn dst/src/temp %box-alien ;
+M: ##copy generate-insn [ dst/src ] [ rep>> ] bi %copy ;
+
+M: ##unbox-float generate-insn dst/src %unbox-float ;
+M: ##unbox-any-c-ptr generate-insn dst/src/temp %unbox-any-c-ptr ;
+M: ##box-float generate-insn dst/src/temp %box-float ;
+M: ##box-alien generate-insn dst/src/temp %box-alien ;
+
+M: ##box-displaced-alien generate-insn
+ [ dst/src1/src2 ] [ temp>> ] bi %box-displaced-alien ;
M: ##alien-unsigned-1 generate-insn dst/src %alien-unsigned-1 ;
M: ##alien-unsigned-2 generate-insn dst/src %alien-unsigned-2 ;
M: ##alien-double generate-insn dst/src %alien-double ;
: >alien-setter< ( insn -- src value )
- [ src>> register ] [ value>> register ] bi ; inline
+ [ src>> ] [ value>> ] bi ; inline
M: ##set-alien-integer-1 generate-insn >alien-setter< %set-alien-integer-1 ;
M: ##set-alien-integer-2 generate-insn >alien-setter< %set-alien-integer-2 ;
M: ##allot generate-insn
{
- [ dst>> register ]
+ [ dst>> ]
[ size>> ]
[ class>> ]
- [ temp>> register ]
+ [ temp>> ]
} cleave
%allot ;
M: ##write-barrier generate-insn
- [ src>> register ]
- [ card#>> register ]
- [ table>> register ]
+ [ src>> ]
+ [ card#>> ]
+ [ table>> ]
tri %write-barrier ;
+! GC checks
+: wipe-locs ( locs temp -- )
+ '[
+ _
+ [ 0 %load-immediate ]
+ [ swap [ %replace ] with each ] bi
+ ] unless-empty ;
+
+GENERIC# save-gc-root 1 ( gc-root operand temp -- )
+
+M:: spill-slot save-gc-root ( gc-root operand temp -- )
+ temp operand n>> int-rep %reload
+ gc-root temp %save-gc-root ;
+
+M: object save-gc-root drop %save-gc-root ;
+
+: save-gc-roots ( gc-roots temp -- ) '[ _ save-gc-root ] assoc-each ;
+
+: save-data-regs ( data-regs -- ) [ first3 %spill ] each ;
+
+GENERIC# load-gc-root 1 ( gc-root operand temp -- )
+
+M:: spill-slot load-gc-root ( gc-root operand temp -- )
+ gc-root temp %load-gc-root
+ temp operand n>> int-rep %spill ;
+
+M: object load-gc-root drop %load-gc-root ;
+
+: load-gc-roots ( gc-roots temp -- ) '[ _ load-gc-root ] assoc-each ;
+
+: load-data-regs ( data-regs -- ) [ first3 %reload ] each ;
+
M: _gc generate-insn
+ "no-gc" define-label
{
- [ temp1>> register ]
- [ temp2>> register ]
- [ gc-roots>> ]
- [ gc-root-count>> ]
- } cleave %gc ;
+ [ [ "no-gc" get ] dip [ temp1>> ] [ temp2>> ] bi %check-nursery ]
+ [ [ uninitialized-locs>> ] [ temp1>> ] bi wipe-locs ]
+ [ data-values>> save-data-regs ]
+ [ [ tagged-values>> ] [ temp1>> ] bi save-gc-roots ]
+ [ tagged-values>> length %call-gc ]
+ [ [ tagged-values>> ] [ temp1>> ] bi load-gc-roots ]
+ [ data-values>> load-data-regs ]
+ } cleave
+ "no-gc" resolve-label ;
-M: ##loop-entry generate-insn drop %loop-entry ;
+M: _loop-entry generate-insn drop %loop-entry ;
M: ##alien-global generate-insn
- [ dst>> register ] [ symbol>> ] [ library>> ] tri
+ [ dst>> ] [ symbol>> ] [ library>> ] tri
%alien-global ;
! ##alien-invoke
-GENERIC: reg-class-variable ( register-class -- symbol )
-
-M: reg-class reg-class-variable ;
-
-M: float-regs reg-class-variable drop float-regs ;
+GENERIC: next-fastcall-param ( rep -- )
-GENERIC: inc-reg-class ( register-class -- )
+: ?dummy-stack-params ( rep -- )
+ dummy-stack-params? [ rep-size cell align stack-params +@ ] [ drop ] if ;
-: ?dummy-stack-params ( reg-class -- )
- dummy-stack-params? [ reg-size cell align stack-params +@ ] [ drop ] if ;
+: ?dummy-int-params ( rep -- )
+ dummy-int-params? [ rep-size cell /i 1 max int-regs +@ ] [ drop ] if ;
-: ?dummy-int-params ( reg-class -- )
- dummy-int-params? [ reg-size cell /i 1 max int-regs +@ ] [ drop ] if ;
-
-: ?dummy-fp-params ( reg-class -- )
+: ?dummy-fp-params ( rep -- )
drop dummy-fp-params? [ float-regs inc ] when ;
-M: int-regs inc-reg-class
- [ reg-class-variable inc ]
- [ ?dummy-stack-params ]
- [ ?dummy-fp-params ]
- tri ;
+M: int-rep next-fastcall-param
+ int-regs inc [ ?dummy-stack-params ] [ ?dummy-fp-params ] bi ;
-M: float-regs inc-reg-class
- [ reg-class-variable inc ]
- [ ?dummy-stack-params ]
- [ ?dummy-int-params ]
- tri ;
+M: single-float-rep next-fastcall-param
+ float-regs inc [ ?dummy-stack-params ] [ ?dummy-int-params ] bi ;
+
+M: double-float-rep next-fastcall-param
+ float-regs inc [ ?dummy-stack-params ] [ ?dummy-int-params ] bi ;
-GENERIC: reg-class-full? ( class -- ? )
+GENERIC: reg-class-full? ( reg-class -- ? )
M: stack-params reg-class-full? drop t ;
-M: object reg-class-full?
- [ reg-class-variable get ] [ param-regs length ] bi >= ;
+M: reg-class reg-class-full?
+ [ get ] [ param-regs length ] bi >= ;
-: spill-param ( reg-class -- n reg-class )
+: alloc-stack-param ( rep -- n reg-class rep )
stack-params get
- [ reg-size cell align stack-params +@ ] dip
- stack-params ;
+ [ rep-size cell align stack-params +@ ] dip
+ stack-params dup ;
-: fastcall-param ( reg-class -- n reg-class )
- [ reg-class-variable get ] [ inc-reg-class ] [ ] tri ;
+: alloc-fastcall-param ( rep -- n reg-class rep )
+ [ [ reg-class-of get ] [ reg-class-of ] [ next-fastcall-param ] tri ] keep ;
-: alloc-parameter ( parameter -- reg reg-class )
- c-type-reg-class dup reg-class-full?
- [ spill-param ] [ fastcall-param ] if
- [ param-reg ] keep ;
+: alloc-parameter ( parameter -- reg rep )
+ c-type-rep dup reg-class-of reg-class-full?
+ [ alloc-stack-param ] [ alloc-fastcall-param ] if
+ [ param-reg ] dip ;
: (flatten-int-type) ( size -- seq )
cell /i "void*" c-type <repetition> ;
: reverse-each-parameter ( parameters quot -- )
[ [ parameter-sizes nip ] keep ] dip 2reverse-each ; inline
-: reset-freg-counts ( -- )
+: reset-fastcall-counts ( -- )
{ int-regs float-regs stack-params } [ 0 swap set ] each ;
: with-param-regs ( quot -- )
#! In quot you can call alloc-parameter
- [ reset-freg-counts call ] with-scope ; inline
+ [ reset-fastcall-counts call ] with-scope ; inline
: move-parameters ( node word -- )
#! Moves values from C stack to registers (if word is
: objects>registers ( params -- )
#! Generate code for unboxing a list of C types, then
- #! generate code for moving these parameters to register on
+ #! generate code for moving these parameters to registers on
#! architectures where parameters are passed in registers.
[
[ prepare-box-struct ] keep
alien-parameters [ box-parameter ] each-parameter ;
: registers>objects ( node -- )
+ ! Generate code for boxing input parameters in a callback.
[
dup \ %save-param-reg move-parameters
"nest_stacks" f %alien-invoke
: >compare< ( insn -- dst temp cc src1 src2 )
{
- [ dst>> register ]
- [ temp>> register ]
+ [ dst>> ]
+ [ temp>> ]
[ cc>> ]
- [ src1>> register ]
- [ src2>> ?register ]
+ [ src1>> ]
+ [ src2>> ]
} cleave ; inline
M: ##compare generate-insn >compare< %compare ;
{
[ label>> lookup-label ]
[ cc>> ]
- [ src1>> register ]
- [ src2>> ?register ]
+ [ src1>> ]
+ [ src2>> ]
} cleave ; inline
M: _compare-branch generate-insn
>binary-branch< %compare-float-branch ;
M: _spill generate-insn
- [ src>> ] [ n>> ] [ class>> ] tri {
- { int-regs [ %spill-integer ] }
- { double-float-regs [ %spill-float ] }
- } case ;
+ [ src>> ] [ n>> ] [ rep>> ] tri %spill ;
M: _reload generate-insn
- [ dst>> ] [ n>> ] [ class>> ] tri {
- { int-regs [ %reload-integer ] }
- { double-float-regs [ %reload-float ] }
- } case ;
+ [ dst>> ] [ n>> ] [ rep>> ] tri %reload ;
-M: _spill-counts generate-insn drop ;
+M: _spill-area-size generate-insn drop ;
compiler.tree.builder
compiler.tree.optimizer
+compiler.cfg
compiler.cfg.builder
compiler.cfg.optimizer
compiler.cfg.mr
} cond ;
: optimize? ( word -- ? )
- { [ predicate-engine-word? ] [ single-generic? ] } 1|| not ;
+ single-generic? not ;
: contains-breakpoints? ( -- ? )
dependencies get keys [ "break?" word-prop ] any? ;
: backend ( tree word -- )
build-cfg [
- optimize-cfg
- build-mr
+ [ optimize-cfg build-mr ] with-cfg
generate
save-asm
] each ;
] each
compile-queue get compile-loop
compiled get >alist
- ] with-scope ;
+ ] with-scope
+ "trace-compilation" get [ "--- compile done" print flush ] when ;
: with-optimizer ( quot -- )
[ optimizing-compiler compiler-impl ] dip with-variable ; inline
-USING: alien alien.c-types alien.syntax compiler kernel namespaces
-sequences stack-checker stack-checker.errors words arrays parser
-quotations continuations effects namespaces.private io
-io.streams.string memory system threads tools.test math accessors
-combinators specialized-arrays.float alien.libraries io.pathnames
-io.backend ;
+USING: accessors alien alien.c-types alien.libraries
+alien.syntax arrays classes.struct combinators
+compiler continuations effects io io.backend io.pathnames
+io.streams.string kernel math memory namespaces
+namespaces.private parser quotations sequences
+specialized-arrays.float stack-checker stack-checker.errors
+system threads tools.test words specialized-arrays.char ;
IN: compiler.tests.alien
<<
[ "a" 2 3 4 5 6 7 ffi_test_9 ] must-fail
[ 1 2 3 4 5 6 "a" ffi_test_9 ] must-fail
-C-STRUCT: foo
- { "int" "x" }
- { "int" "y" }
-;
+STRUCT: FOO { x int } { y int } ;
-: make-foo ( x y -- foo )
- "foo" <c-object> [ set-foo-y ] keep [ set-foo-x ] keep ;
+: make-FOO ( x y -- FOO )
+ FOO <struct> swap >>y swap >>x ;
-FUNCTION: int ffi_test_11 int a foo b int c ;
+FUNCTION: int ffi_test_11 int a FOO b int c ;
-[ 14 ] [ 1 2 3 make-foo 4 ffi_test_11 ] unit-test
+[ 14 ] [ 1 2 3 make-FOO 4 ffi_test_11 ] unit-test
FUNCTION: int ffi_test_13 int a int b int c int d int e int f int g int h int i int j int k ;
[ 66 ] [ 1 2 3 4 5 6 7 8 9 10 11 ffi_test_13 ] unit-test
-FUNCTION: foo ffi_test_14 int x int y ;
+FUNCTION: FOO ffi_test_14 int x int y ;
-[ 11 6 ] [ 11 6 ffi_test_14 dup foo-x swap foo-y ] unit-test
+[ 11 6 ] [ 11 6 ffi_test_14 [ x>> ] [ y>> ] bi ] unit-test
FUNCTION: char* ffi_test_15 char* x char* y ;
[ "bar" ] [ "xy" "xy" ffi_test_15 ] unit-test
[ 1 2 ffi_test_15 ] must-fail
-C-STRUCT: bar
- { "long" "x" }
- { "long" "y" }
- { "long" "z" }
-;
+STRUCT: BAR { x long } { y long } { z long } ;
-FUNCTION: bar ffi_test_16 long x long y long z ;
+FUNCTION: BAR ffi_test_16 long x long y long z ;
[ 11 6 -7 ] [
- 11 6 -7 ffi_test_16 dup bar-x over bar-y rot bar-z
+ 11 6 -7 ffi_test_16 [ x>> ] [ y>> ] [ z>> ] tri
] unit-test
-C-STRUCT: tiny
- { "int" "x" }
-;
+STRUCT: TINY { x int } ;
-FUNCTION: tiny ffi_test_17 int x ;
+FUNCTION: TINY ffi_test_17 int x ;
-[ 11 ] [ 11 ffi_test_17 tiny-x ] unit-test
+[ 11 ] [ 11 ffi_test_17 x>> ] unit-test
[ [ alien-indirect ] infer ] [ inference-error? ] must-fail-with
[ 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" }
+: ffi_test_19 ( x y z -- BAR )
+ "BAR" "f-stdcall" "ffi_test_19" { "long" "long" "long" }
alien-invoke gc ;
[ 11 6 -7 ] [
- 11 6 -7 ffi_test_19 dup bar-x over bar-y rot bar-z
+ 11 6 -7 ffi_test_19 [ x>> ] [ y>> ] [ z>> ] tri
] unit-test
FUNCTION: double ffi_test_6 float x float y ;
[ 1111 f 123456789 ffi_test_22 ] must-fail
-C-STRUCT: rect
- { "float" "x" }
- { "float" "y" }
- { "float" "w" }
- { "float" "h" }
-;
+STRUCT: RECT
+ { x float } { y float }
+ { w float } { h float } ;
-: <rect> ( x y w h -- rect )
- "rect" <c-object>
- [ set-rect-h ] keep
- [ set-rect-w ] keep
- [ set-rect-y ] keep
- [ set-rect-x ] keep ;
+: <RECT> ( x y w h -- rect )
+ RECT <struct>
+ swap >>h
+ swap >>w
+ swap >>y
+ swap >>x ;
-FUNCTION: int ffi_test_12 int a int b rect c int d int e int f ;
+FUNCTION: int ffi_test_12 int a int b RECT c int d int e int f ;
-[ 45 ] [ 1 2 3.0 4.0 5.0 6.0 <rect> 7 8 9 ffi_test_12 ] unit-test
+[ 45 ] [ 1 2 3.0 4.0 5.0 6.0 <RECT> 7 8 9 ffi_test_12 ] unit-test
[ 1 2 { 1 2 3 } 7 8 9 ffi_test_12 ] must-fail
] unit-test
! Test odd-size structs
-C-STRUCT: test-struct-1 { { "char" 1 } "x" } ;
+STRUCT: test-struct-1 { x char[1] } ;
FUNCTION: test-struct-1 ffi_test_24 ;
-[ B{ 1 } ] [ ffi_test_24 ] unit-test
+[ S{ test-struct-1 { x char-array{ 1 } } } ] [ ffi_test_24 ] unit-test
-C-STRUCT: test-struct-2 { { "char" 2 } "x" } ;
+STRUCT: test-struct-2 { x char[2] } ;
FUNCTION: test-struct-2 ffi_test_25 ;
-[ B{ 1 2 } ] [ ffi_test_25 ] unit-test
+[ S{ test-struct-2 { x char-array{ 1 2 } } } ] [ ffi_test_25 ] unit-test
-C-STRUCT: test-struct-3 { { "char" 3 } "x" } ;
+STRUCT: test-struct-3 { x char[3] } ;
FUNCTION: test-struct-3 ffi_test_26 ;
-[ B{ 1 2 3 } ] [ ffi_test_26 ] unit-test
+[ S{ test-struct-3 { x char-array{ 1 2 3 } } } ] [ ffi_test_26 ] unit-test
-C-STRUCT: test-struct-4 { { "char" 4 } "x" } ;
+STRUCT: test-struct-4 { x char[4] } ;
FUNCTION: test-struct-4 ffi_test_27 ;
-[ B{ 1 2 3 4 } ] [ ffi_test_27 ] unit-test
+[ S{ test-struct-4 { x char-array{ 1 2 3 4 } } } ] [ ffi_test_27 ] unit-test
-C-STRUCT: test-struct-5 { { "char" 5 } "x" } ;
+STRUCT: test-struct-5 { x char[5] } ;
FUNCTION: test-struct-5 ffi_test_28 ;
-[ B{ 1 2 3 4 5 } ] [ ffi_test_28 ] unit-test
+[ S{ test-struct-5 { x char-array{ 1 2 3 4 5 } } } ] [ ffi_test_28 ] unit-test
-C-STRUCT: test-struct-6 { { "char" 6 } "x" } ;
+STRUCT: test-struct-6 { x char[6] } ;
FUNCTION: test-struct-6 ffi_test_29 ;
-[ B{ 1 2 3 4 5 6 } ] [ ffi_test_29 ] unit-test
+[ S{ test-struct-6 { x char-array{ 1 2 3 4 5 6 } } } ] [ ffi_test_29 ] unit-test
-C-STRUCT: test-struct-7 { { "char" 7 } "x" } ;
+STRUCT: test-struct-7 { x char[7] } ;
FUNCTION: test-struct-7 ffi_test_30 ;
-[ B{ 1 2 3 4 5 6 7 } ] [ ffi_test_30 ] unit-test
+[ S{ test-struct-7 { x char-array{ 1 2 3 4 5 6 7 } } } ] [ ffi_test_30 ] unit-test
-C-STRUCT: test-struct-8 { "double" "x" } { "double" "y" } ;
+STRUCT: test-struct-8 { x double } { y double } ;
FUNCTION: double ffi_test_32 test-struct-8 x int y ;
[ 9.0 ] [
- "test-struct-8" <c-object>
- 1.0 over set-test-struct-8-x
- 2.0 over set-test-struct-8-y
+ test-struct-8 <struct>
+ 1.0 >>x
+ 2.0 >>y
3 ffi_test_32
] unit-test
-C-STRUCT: test-struct-9 { "float" "x" } { "float" "y" } ;
+STRUCT: test-struct-9 { x float } { y float } ;
FUNCTION: double ffi_test_33 test-struct-9 x int y ;
[ 9.0 ] [
- "test-struct-9" <c-object>
- 1.0 over set-test-struct-9-x
- 2.0 over set-test-struct-9-y
+ test-struct-9 <struct>
+ 1.0 >>x
+ 2.0 >>y
3 ffi_test_33
] unit-test
-C-STRUCT: test-struct-10 { "float" "x" } { "int" "y" } ;
+STRUCT: test-struct-10 { x float } { y int } ;
FUNCTION: double ffi_test_34 test-struct-10 x int y ;
[ 9.0 ] [
- "test-struct-10" <c-object>
- 1.0 over set-test-struct-10-x
- 2 over set-test-struct-10-y
+ test-struct-10 <struct>
+ 1.0 >>x
+ 2 >>y
3 ffi_test_34
] unit-test
-C-STRUCT: test-struct-11 { "int" "x" } { "int" "y" } ;
+STRUCT: test-struct-11 { x int } { y int } ;
FUNCTION: double ffi_test_35 test-struct-11 x int y ;
[ 9.0 ] [
- "test-struct-11" <c-object>
- 1 over set-test-struct-11-x
- 2 over set-test-struct-11-y
+ test-struct-11 <struct>
+ 1 >>x
+ 2 >>y
3 ffi_test_35
] unit-test
-C-STRUCT: test-struct-12 { "int" "a" } { "double" "x" } ;
+STRUCT: test-struct-12 { a int } { x double } ;
: make-struct-12 ( x -- alien )
- "test-struct-12" <c-object>
- [ set-test-struct-12-x ] keep ;
+ test-struct-12 <struct>
+ swap >>x ;
FUNCTION: double ffi_test_36 ( test-struct-12 x ) ;
: callback-9 ( -- callback )
"int" { "int" "int" "int" } "cdecl" [
- + + 1+
+ + + 1 +
] alien-callback ;
FUNCTION: void ffi_test_36_point_5 ( ) ;
[ 7 ] [ callback-9 ffi_test_37 ] unit-test
-C-STRUCT: test_struct_13
-{ "float" "x1" }
-{ "float" "x2" }
-{ "float" "x3" }
-{ "float" "x4" }
-{ "float" "x5" }
-{ "float" "x6" } ;
+STRUCT: test_struct_13
+{ x1 float }
+{ x2 float }
+{ x3 float }
+{ x4 float }
+{ x5 float }
+{ x6 float } ;
: make-test-struct-13 ( -- alien )
- "test_struct_13" <c-object>
- 1.0 over set-test_struct_13-x1
- 2.0 over set-test_struct_13-x2
- 3.0 over set-test_struct_13-x3
- 4.0 over set-test_struct_13-x4
- 5.0 over set-test_struct_13-x5
- 6.0 over set-test_struct_13-x6 ;
+ test_struct_13 <struct>
+ 1.0 >>x1
+ 2.0 >>x2
+ 3.0 >>x3
+ 4.0 >>x4
+ 5.0 >>x5
+ 6.0 >>x6 ;
FUNCTION: int ffi_test_39 ( long a, long b, test_struct_13 s ) ;
[ 21 ] [ 12347 12347 make-test-struct-13 ffi_test_39 ] unit-test
! Joe Groff found this problem
-C-STRUCT: double-rect
-{ "double" "a" }
-{ "double" "b" }
-{ "double" "c" }
-{ "double" "d" } ;
+STRUCT: double-rect
+{ a double }
+{ b double }
+{ c double }
+{ d double } ;
: <double-rect> ( a b c d -- foo )
- "double-rect" <c-object>
- {
- [ set-double-rect-d ]
- [ set-double-rect-c ]
- [ set-double-rect-b ]
- [ set-double-rect-a ]
- [ ]
- } cleave ;
+ double-rect <struct>
+ swap >>d
+ swap >>c
+ swap >>b
+ swap >>a ;
: >double-rect< ( foo -- a b c d )
{
- [ double-rect-a ]
- [ double-rect-b ]
- [ double-rect-c ]
- [ double-rect-d ]
+ [ a>> ]
+ [ b>> ]
+ [ c>> ]
+ [ d>> ]
} cleave ;
: double-rect-callback ( -- alien )
[ 1.0 2.0 3.0 4.0 ]
[ 1.0 2.0 3.0 4.0 <double-rect> double-rect-test >double-rect< ] unit-test
-C-STRUCT: test_struct_14
-{ "double" "x1" }
-{ "double" "x2" } ;
+STRUCT: test_struct_14
+ { x1 double }
+ { x2 double } ;
FUNCTION: test_struct_14 ffi_test_40 ( double x1, double x2 ) ;
[ 1.0 2.0 ] [
- 1.0 2.0 ffi_test_40
- [ test_struct_14-x1 ] [ test_struct_14-x2 ] bi
+ 1.0 2.0 ffi_test_40 [ x1>> ] [ x2>> ] bi
] unit-test
: callback-10 ( -- callback )
"test_struct_14" { "double" "double" } "cdecl"
[
- "test_struct_14" <c-object>
- [ set-test_struct_14-x2 ] keep
- [ set-test_struct_14-x1 ] keep
+ test_struct_14 <struct>
+ swap >>x2
+ swap >>x1
] alien-callback ;
: callback-10-test ( x1 x2 callback -- result )
[ 1.0 2.0 ] [
1.0 2.0 callback-10 callback-10-test
- [ test_struct_14-x1 ] [ test_struct_14-x2 ] bi
+ [ x1>> ] [ x2>> ] bi
] unit-test
FUNCTION: test-struct-12 ffi_test_41 ( int a, double x ) ;
[ 1 2.0 ] [
1 2.0 ffi_test_41
- [ test-struct-12-a ] [ test-struct-12-x ] bi
+ [ a>> ] [ x>> ] bi
] unit-test
: callback-11 ( -- callback )
"test-struct-12" { "int" "double" } "cdecl"
[
- "test-struct-12" <c-object>
- [ set-test-struct-12-x ] keep
- [ set-test-struct-12-a ] keep
+ test-struct-12 <struct>
+ swap >>x
+ swap >>a
] alien-callback ;
: callback-11-test ( x1 x2 callback -- result )
[ 1 2.0 ] [
1 2.0 callback-11 callback-11-test
- [ test-struct-12-a ] [ test-struct-12-x ] bi
+ [ a>> ] [ x>> ] bi
] unit-test
-C-STRUCT: test_struct_15
-{ "float" "x" }
-{ "float" "y" } ;
+STRUCT: test_struct_15
+ { x float }
+ { y float } ;
FUNCTION: test_struct_15 ffi_test_42 ( float x, float y ) ;
-[ 1.0 2.0 ] [ 1.0 2.0 ffi_test_42 [ test_struct_15-x ] [ test_struct_15-y ] bi ] unit-test
+[ 1.0 2.0 ] [ 1.0 2.0 ffi_test_42 [ x>> ] [ y>> ] bi ] unit-test
: callback-12 ( -- callback )
"test_struct_15" { "float" "float" } "cdecl"
[
- "test_struct_15" <c-object>
- [ set-test_struct_15-y ] keep
- [ set-test_struct_15-x ] keep
+ test_struct_15 <struct>
+ swap >>y
+ swap >>x
] alien-callback ;
: callback-12-test ( x1 x2 callback -- result )
"test_struct_15" { "float" "float" } "cdecl" alien-indirect ;
[ 1.0 2.0 ] [
- 1.0 2.0 callback-12 callback-12-test
- [ test_struct_15-x ] [ test_struct_15-y ] bi
+ 1.0 2.0 callback-12 callback-12-test [ x>> ] [ y>> ] bi
] unit-test
-C-STRUCT: test_struct_16
-{ "float" "x" }
-{ "int" "a" } ;
+STRUCT: test_struct_16
+ { x float }
+ { a int } ;
FUNCTION: test_struct_16 ffi_test_43 ( float x, int a ) ;
-[ 1.0 2 ] [ 1.0 2 ffi_test_43 [ test_struct_16-x ] [ test_struct_16-a ] bi ] unit-test
+[ 1.0 2 ] [ 1.0 2 ffi_test_43 [ x>> ] [ a>> ] bi ] unit-test
: callback-13 ( -- callback )
"test_struct_16" { "float" "int" } "cdecl"
[
- "test_struct_16" <c-object>
- [ set-test_struct_16-a ] keep
- [ set-test_struct_16-x ] keep
+ test_struct_16 <struct>
+ swap >>a
+ swap >>x
] alien-callback ;
: callback-13-test ( x1 x2 callback -- result )
[ 1.0 2 ] [
1.0 2 callback-13 callback-13-test
- [ test_struct_16-x ] [ test_struct_16-a ] bi
+ [ x>> ] [ a>> ] bi
] unit-test
FUNCTION: test_struct_14 ffi_test_44 ( ) ; inline
-[ 1.0 2.0 ] [ ffi_test_44 [ test_struct_14-x1 ] [ test_struct_14-x2 ] bi ] unit-test
+[ 1.0 2.0 ] [ ffi_test_44 [ x1>> ] [ x2>> ] bi ] unit-test
: stack-frame-bustage ( -- a b ) ffi_test_44 gc 3 ;
] unit-test
! Reported by jedahu
-C-STRUCT: bool-field-test
- { "char*" "name" }
- { "bool" "on" }
- { "short" "parents" } ;
+STRUCT: bool-field-test
+ { name char* }
+ { on bool }
+ { parents short } ;
FUNCTION: short ffi_test_48 ( bool-field-test x ) ;
[ 123 ] [
- "bool-field-test" <c-object> 123 over set-bool-field-test-parents
+ bool-field-test <struct>
+ 123 >>parents
ffi_test_48
-] unit-test
\ No newline at end of file
+] unit-test
-IN: compiler.tests.call-effect
USING: tools.test combinators generic.single sequences kernel ;
+IN: compiler.tests.call-effect
: execute-ic-test ( a b -- c ) execute( a -- c ) ;
[ ] [ [ ] call-test ] unit-test
[ ] [ f [ drop ] curry call-test ] unit-test
[ ] [ [ ] [ ] compose call-test ] unit-test
-[ [ 1 2 3 ] call-test ] [ wrong-values? ] must-fail-with
\ No newline at end of file
+[ [ 1 2 3 ] call-test ] [ wrong-values? ] must-fail-with
math hashtables.private math.private namespaces sequences tools.test
namespaces.private slots.private sequences.private byte-arrays alien
alien.accessors layouts words definitions compiler.units io
-combinators vectors grouping make alien.c-types ;
+combinators vectors grouping make alien.c-types combinators.short-circuit
+math.order ;
QUALIFIED: namespaces.private
IN: compiler.tests.codegen
[ 4294967295 B{ 255 255 255 255 } -1 ]
[
-1 <int> -1 <int>
- [ [ 0 alien-unsigned-cell swap ] [ 0 alien-signed-2 ] bi ]
+ [ [ 0 alien-unsigned-4 swap ] [ 0 alien-signed-2 ] bi ]
compile-call
-] unit-test
\ No newline at end of file
+] unit-test
+
+! Regression found while working on global register allocation
+
+: linear-scan-regression-1 ( a b c -- ) 3array , ;
+: linear-scan-regression-2 ( a b -- ) 2array , ;
+
+: linear-scan-regression ( a b c -- )
+ [ linear-scan-regression-2 ]
+ [ linear-scan-regression-1 ]
+ bi-curry bi-curry interleave ;
+
+[
+ {
+ { 1 "x" "y" }
+ { "x" "y" }
+ { 2 "x" "y" }
+ { "x" "y" }
+ { 3 "x" "y" }
+ }
+] [
+ [ { 1 2 3 } "x" "y" linear-scan-regression ] { } make
+] unit-test
+
+! Regression from Doug's value numbering changes
+[ t ] [ 2 [ 1 swap fixnum< ] compile-call ] unit-test
+[ 3 ] [ 2 [ 1 swap fixnum< [ 3 ] [ 4 ] if ] compile-call ] unit-test
+
+cell 4 = [
+ [ 0 ] [ 101 [ dup fixnum-fast 1 fixnum+fast 20 fixnum-shift-fast 20 fixnum-shift-fast ] compile-call ] unit-test
+] when
+
+! Regression from Slava's value numbering changes
+[ 1 ] [ 31337 [ dup fixnum<= [ 1 ] [ 2 ] if ] compile-call ] unit-test
+
+! Bug with ##return node construction
+: return-recursive-bug ( nodes -- ? )
+ { fixnum } declare [
+ dup 3 bitand 1 = [ drop t ] [
+ dup 3 bitand 2 = [
+ return-recursive-bug
+ ] [ drop f ] if
+ ] if
+ ] any? ; inline recursive
+
+[ t ] [ 3 [ return-recursive-bug ] compile-call ] unit-test
+
+! Coalescing reductions
+[ f ] [ V{ } 0 [ [ vector? ] both? ] compile-call ] unit-test
+[ f ] [ 0 V{ } [ [ vector? ] both? ] compile-call ] unit-test
+
+[ f ] [
+ f vector [
+ [ dup [ \ vector eq? ] [ drop f ] if ] dip
+ dup [ \ vector eq? ] [ drop f ] if
+ over rot [ drop ] [ nip ] if
+ ] compile-call
+] unit-test
+
+! Coalesing bug reduced from sequence-parser:take-sequence
+: coalescing-bug-1 ( a b c d -- a b c d )
+ 3dup {
+ [ 2drop 0 < ]
+ [ [ drop ] 2dip length > ]
+ [ drop > ]
+ } 3|| [ 3drop f ] [ slice boa ] if swap [ [ length ] bi@ ] 2keep ;
+
+[ 0 3 f { 1 2 3 } ] [ { 1 2 3 } -10 3 "hello" coalescing-bug-1 ] unit-test
+[ 0 3 f { 1 2 3 } ] [ { 1 2 3 } 0 7 "hello" coalescing-bug-1 ] unit-test
+[ 0 3 f { 1 2 3 } ] [ { 1 2 3 } 3 2 "hello" coalescing-bug-1 ] unit-test
+[ 2 3 T{ slice f 1 3 "hello" } { 1 2 3 } ] [ { 1 2 3 } 1 3 "hello" coalescing-bug-1 ] unit-test
+
+! Another one, found by Dan
+: coalescing-bug-2 ( a -- b )
+ dup dup 10 fixnum< [ 1 fixnum+fast ] when
+ fixnum+fast 2 fixnum*fast 2 fixnum-fast 2 fixnum*fast 2 fixnum+fast ;
+
+[ 10 ] [ 1 coalescing-bug-2 ] unit-test
+[ 86 ] [ 11 coalescing-bug-2 ] unit-test
+
+! Regression in suffix-arrays code
+: coalescing-bug-3 ( from/f to/f seq -- slice )
+ [
+ [ drop 0 or ] [ length or ] bi-curry bi*
+ [ min ] keep
+ ] keep <slice> ;
+
+[ T{ slice f 0 5 "hello" } ] [ f f "hello" coalescing-bug-3 ] unit-test
+[ T{ slice f 1 5 "hello" } ] [ 1 f "hello" coalescing-bug-3 ] unit-test
+[ T{ slice f 0 3 "hello" } ] [ f 3 "hello" coalescing-bug-3 ] unit-test
+[ T{ slice f 1 3 "hello" } ] [ 1 3 "hello" coalescing-bug-3 ] unit-test
+[ T{ slice f 3 3 "hello" } ] [ 4 3 "hello" coalescing-bug-3 ] unit-test
+[ T{ slice f 5 5 "hello" } ] [ 6 f "hello" coalescing-bug-3 ] unit-test
+
+! Reduction
+: coalescing-bug-4 ( a b c -- a b c )
+ [ [ min ] keep ] dip vector? [ 1 ] [ 2 ] if ;
+
+ [ 2 3 2 ] [ 2 3 "" coalescing-bug-4 ] unit-test
+ [ 3 3 2 ] [ 4 3 "" coalescing-bug-4 ] unit-test
+ [ 3 3 2 ] [ 4 3 "" coalescing-bug-4 ] unit-test
+ [ 2 3 1 ] [ 2 3 V{ } coalescing-bug-4 ] unit-test
+ [ 3 3 1 ] [ 4 3 V{ } coalescing-bug-4 ] unit-test
+ [ 3 3 1 ] [ 4 3 V{ } coalescing-bug-4 ] unit-test
+
+! Global stack analysis dataflow equations are wrong
+: some-word ( a -- b ) 2 + ;
+: global-dcn-bug-1 ( a b -- c d )
+ dup [ [ drop 1 ] dip ] [ [ some-word ] dip ] if
+ dup [ [ 1 fixnum+fast ] dip ] [ [ drop 1 ] dip ] if ;
+
+[ 2 t ] [ 0 t global-dcn-bug-1 ] unit-test
+[ 1 f ] [ 0 f global-dcn-bug-1 ] unit-test
\ No newline at end of file
-IN: compiler.tests.float
USING: compiler.units compiler kernel kernel.private memory math
math.private tools.test math.floats.private ;
+IN: compiler.tests.float
[ 5.0 ] [ [ 5.0 ] compile-call gc gc gc ] unit-test
[ 2.0 3.0 ] [ 3.0 [ 2.0 swap ] compile-call ] unit-test
-IN: compiler.tests.generic
USING: tools.test math kernel compiler.units definitions ;
+IN: compiler.tests.generic
GENERIC: bad ( -- )
M: integer bad ;
[ 0 bad ] must-fail
[ "" bad ] must-fail
-[ ] [ [ \ bad forget ] with-compilation-unit ] unit-test
\ No newline at end of file
+[ ] [ [ \ bad forget ] with-compilation-unit ] unit-test
[ -1 ] [ [ -123 -64 fixnum-shift ] compile-call ] unit-test
[ -1 ] [ -123 -64 [ fixnum-shift ] compile-call ] unit-test
-[ HEX: 10000000 ] [ HEX: 1000000 HEX: 10 [ fixnum* ] compile-call ] unit-test
-[ HEX: 10000000 ] [ HEX: -10000000 >fixnum [ 0 swap fixnum- ] compile-call ] unit-test
-[ HEX: 10000000 ] [ HEX: -fffffff >fixnum [ 1 swap fixnum- ] compile-call ] unit-test
+[ 4294967296 ] [ 1 32 [ fixnum-shift ] compile-call ] unit-test
+[ 4294967296 ] [ 1 [ 32 fixnum-shift ] compile-call ] unit-test
+[ 4294967296 ] [ 1 [ 16 fixnum-shift 16 fixnum-shift ] compile-call ] unit-test
+[ -4294967296 ] [ -1 32 [ fixnum-shift ] compile-call ] unit-test
+[ -4294967296 ] [ -1 [ 32 fixnum-shift ] compile-call ] unit-test
+[ -4294967296 ] [ -1 [ 16 fixnum-shift 16 fixnum-shift ] compile-call ] unit-test
-[ t ] [ 1 27 fixnum-shift dup [ fixnum+ ] compile-call 1 28 fixnum-shift = ] unit-test
-[ -268435457 ] [ 1 28 shift neg >fixnum [ -1 fixnum+ ] compile-call ] unit-test
+[ 8 ] [ 1 3 [ fixnum-shift-fast ] compile-call ] unit-test
+[ 8 ] [ 1 3 [ 15 bitand fixnum-shift-fast ] compile-call ] unit-test
+[ 8 ] [ 1 [ 3 fixnum-shift-fast ] compile-call ] unit-test
+[ 8 ] [ [ 1 3 fixnum-shift-fast ] compile-call ] unit-test
+[ -8 ] [ -1 3 [ fixnum-shift-fast ] compile-call ] unit-test
+[ -8 ] [ -1 3 [ 15 bitand fixnum-shift-fast ] compile-call ] unit-test
+[ -8 ] [ -1 [ 3 fixnum-shift-fast ] compile-call ] unit-test
+[ -8 ] [ [ -1 3 fixnum-shift-fast ] compile-call ] unit-test
+
+[ 2 ] [ 8 -2 [ fixnum-shift-fast ] compile-call ] unit-test
+[ 2 ] [ 8 2 [ 15 bitand neg fixnum-shift-fast ] compile-call ] unit-test
+[ 2 ] [ 8 [ -2 fixnum-shift-fast ] compile-call ] unit-test
[ 4294967296 ] [ 1 32 [ fixnum-shift ] compile-call ] unit-test
[ 4294967296 ] [ 1 [ 32 fixnum-shift ] compile-call ] unit-test
[ -4294967296 ] [ -1 [ 32 fixnum-shift ] compile-call ] unit-test
[ -4294967296 ] [ -1 [ 16 fixnum-shift 16 fixnum-shift ] compile-call ] unit-test
+[ HEX: 10000000 ] [ HEX: 1000000 HEX: 10 [ fixnum* ] compile-call ] unit-test
+[ HEX: 10000000 ] [ HEX: -10000000 >fixnum [ 0 swap fixnum- ] compile-call ] unit-test
+[ HEX: 10000000 ] [ HEX: -fffffff >fixnum [ 1 swap fixnum- ] compile-call ] unit-test
+
+[ t ] [ 1 27 fixnum-shift dup [ fixnum+ ] compile-call 1 28 fixnum-shift = ] unit-test
+[ -268435457 ] [ 1 28 shift neg >fixnum [ -1 fixnum+ ] compile-call ] unit-test
+
[ t ] [ 1 20 shift 1 20 shift [ fixnum* ] compile-call 1 40 shift = ] unit-test
[ t ] [ 1 20 shift neg 1 20 shift [ fixnum* ] compile-call 1 40 shift neg = ] unit-test
[ t ] [ 1 20 shift neg 1 20 shift neg [ fixnum* ] compile-call 1 40 shift = ] unit-test
[ t ] [ f [ f eq? ] compile-call ] unit-test
+cell 8 = [
+ [ HEX: 40400000 ] [
+ HEX: 4200 [ HEX: 7fff fixnum-bitand 13 fixnum-shift-fast 112 23 fixnum-shift-fast fixnum+fast ]
+ compile-call
+ ] unit-test
+] when
+
! regression
[ 3 ] [
100001 f <array> 3 100000 pick set-nth
] compile-call
] unit-test
+[ ALIEN: 123 ] [
+ 123 [ <alien> ] compile-call
+] unit-test
+
+[ ALIEN: 123 ] [
+ 123 [ { fixnum } declare <alien> ] compile-call
+] unit-test
+
+[ ALIEN: 123 ] [
+ [ 123 <alien> ] compile-call
+] unit-test
+
+[ f ] [
+ 0 [ <alien> ] compile-call
+] unit-test
+
+[ f ] [
+ 0 [ { fixnum } declare <alien> ] compile-call
+] unit-test
+
+[ f ] [
+ [ 0 <alien> ] compile-call
+] unit-test
+
+[ ALIEN: 321 ] [
+ 0 ALIEN: 321 [ <displaced-alien> ] compile-call
+] unit-test
+
+[ ALIEN: 321 ] [
+ 0 ALIEN: 321 [ { fixnum c-ptr } declare <displaced-alien> ] compile-call
+] unit-test
+
+[ ALIEN: 321 ] [
+ ALIEN: 321 [ 0 swap <displaced-alien> ] compile-call
+] unit-test
+
+[ B{ 0 1 2 3 4 } ] [
+ 2 B{ 0 1 2 3 4 } <displaced-alien>
+ [ 1 swap <displaced-alien> ] compile-call
+ underlying>>
+] unit-test
+
+[ B{ 0 1 2 3 4 } ] [
+ 2 B{ 0 1 2 3 4 } <displaced-alien>
+ [ 1 swap { c-ptr } declare <displaced-alien> ] compile-call
+ underlying>>
+] unit-test
+
[
B{ 0 0 0 0 } [ { byte-array } declare <void*> ] compile-call
] must-fail
--- /dev/null
+USING: accessors assocs compiler compiler.cfg
+compiler.cfg.debugger compiler.cfg.instructions compiler.cfg.mr
+compiler.cfg.registers compiler.codegen compiler.units
+cpu.architecture hashtables kernel namespaces sequences
+tools.test vectors words layouts literals math arrays
+alien.syntax math.private ;
+IN: compiler.tests.low-level-ir
+
+: compile-cfg ( cfg -- word )
+ gensym
+ [ build-mr generate code>> ] dip
+ [ associate >alist modify-code-heap ] keep ;
+
+: compile-test-cfg ( -- word )
+ cfg new 0 get >>entry
+ dup cfg set
+ dup fake-representations representations get >>reps
+ compile-cfg ;
+
+: compile-test-bb ( insns -- result )
+ V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+ V{
+ T{ ##inc-d f 1 }
+ T{ ##replace f 0 D 0 }
+ T{ ##branch }
+ } [ clone ] map append 1 test-bb
+ V{
+ T{ ##epilogue }
+ T{ ##return }
+ } [ clone ] map 2 test-bb
+ 0 1 edge
+ 1 2 edge
+ compile-test-cfg
+ execute( -- result ) ;
+
+! loading immediates
+[ f ] [
+ V{
+ T{ ##load-immediate f 0 5 }
+ } compile-test-bb
+] unit-test
+
+[ "hello" ] [
+ V{
+ T{ ##load-reference f 0 "hello" }
+ } compile-test-bb
+] unit-test
+
+! ##copy on floats. We can only run this test if float intrinsics
+! are enabled.
+\ float+ "intrinsic" word-prop [
+ [ 1.5 ] [
+ V{
+ T{ ##load-reference f 4 1.5 }
+ T{ ##unbox-float f 1 4 }
+ T{ ##copy f 2 1 double-float-rep }
+ T{ ##box-float f 3 2 }
+ T{ ##copy f 0 3 int-rep }
+ } compile-test-bb
+ ] unit-test
+] when
+
+! make sure slot access works when the destination is
+! one of the sources
+[ t ] [
+ V{
+ T{ ##load-immediate f 1 $[ 2 cell log2 shift ] }
+ T{ ##load-reference f 0 { t f t } }
+ T{ ##slot f 0 0 1 $[ array tag-number ] 2 }
+ } compile-test-bb
+] unit-test
+
+[ t ] [
+ V{
+ T{ ##load-reference f 0 { t f t } }
+ T{ ##slot-imm f 0 0 2 $[ array tag-number ] 2 }
+ } compile-test-bb
+] unit-test
+
+[ t ] [
+ V{
+ T{ ##load-immediate f 1 $[ 2 cell log2 shift ] }
+ T{ ##load-reference f 0 { t f t } }
+ T{ ##set-slot f 0 0 1 $[ array tag-number ] 2 }
+ } compile-test-bb
+ dup first eq?
+] unit-test
+
+[ t ] [
+ V{
+ T{ ##load-reference f 0 { t f t } }
+ T{ ##set-slot-imm f 0 0 2 $[ array tag-number ] }
+ } compile-test-bb
+ dup first eq?
+] unit-test
+
+[ 8 ] [
+ V{
+ T{ ##load-immediate f 0 4 }
+ T{ ##shl f 0 0 0 }
+ } compile-test-bb
+] unit-test
+
+[ 4 ] [
+ V{
+ T{ ##load-immediate f 0 4 }
+ T{ ##shl-imm f 0 0 3 }
+ } compile-test-bb
+] unit-test
+
+[ 31 ] [
+ V{
+ T{ ##load-reference f 1 B{ 31 67 52 } }
+ T{ ##unbox-any-c-ptr f 0 1 2 }
+ T{ ##alien-unsigned-1 f 0 0 }
+ T{ ##shl-imm f 0 0 3 }
+ } compile-test-bb
+] unit-test
+
+[ CHAR: l ] [
+ V{
+ T{ ##load-reference f 0 "hello world" }
+ T{ ##load-immediate f 1 3 }
+ T{ ##string-nth f 0 0 1 2 }
+ T{ ##shl-imm f 0 0 3 }
+ } compile-test-bb
+] unit-test
+
+[ 1 ] [
+ V{
+ T{ ##load-immediate f 0 16 }
+ T{ ##add-imm f 0 0 -8 }
+ } compile-test-bb
+] unit-test
+
+! These are def-is-use-insns
+USE: multiline
+
+/*
+
+[ 100 ] [
+ V{
+ T{ ##load-immediate f 0 100 }
+ T{ ##integer>bignum f 0 0 1 }
+ } compile-test-bb
+] unit-test
+
+[ 1 ] [
+ V{
+ T{ ##load-reference f 0 ALIEN: 8 }
+ T{ ##unbox-any-c-ptr f 0 0 1 }
+ } compile-test-bb
+] unit-test
+
+*/
quotations classes classes.algebra classes.tuple.private
continuations growable namespaces hints alien.accessors
compiler.tree.builder compiler.tree.optimizer sequences.deep
-compiler definitions ;
+compiler definitions generic.single ;
IN: compiler.tests.optimizer
GENERIC: xyz ( obj -- obj )
[ 3 ] [ t bad-kill-2 ] unit-test
! regression
-: (the-test) ( x -- y ) dup 0 > [ 1- (the-test) ] when ; inline recursive
+: (the-test) ( x -- y ) dup 0 > [ 1 - (the-test) ] when ; inline recursive
: the-test ( -- x y ) 2 dup (the-test) ;
[ 2 0 ] [ the-test ] unit-test
! regression
: branch-fold-regression-0 ( m -- n )
- t [ ] [ 1+ branch-fold-regression-0 ] if ; inline recursive
+ t [ ] [ 1 + branch-fold-regression-0 ] if ; inline recursive
: branch-fold-regression-1 ( -- m )
10 branch-fold-regression-0 ;
[ T{ some-tuple f [ 3 ] } ] [ 3 allot-regression ] unit-test
-[ 1 ] [ B{ 0 0 0 0 } [ 0 alien-signed-4 1+ ] compile-call ] unit-test
-[ 1 ] [ B{ 0 0 0 0 } [ 0 alien-unsigned-4 1+ ] compile-call ] unit-test
-[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-signed-8 1+ ] compile-call ] unit-test
-[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-unsigned-8 1+ ] compile-call ] unit-test
-[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-signed-cell 1+ ] compile-call ] unit-test
-[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-unsigned-cell 1+ ] compile-call ] unit-test
+[ 1 ] [ B{ 0 0 0 0 } [ 0 alien-signed-4 1 + ] compile-call ] unit-test
+[ 1 ] [ B{ 0 0 0 0 } [ 0 alien-unsigned-4 1 + ] compile-call ] unit-test
+[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-signed-8 1 + ] compile-call ] unit-test
+[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-unsigned-8 1 + ] compile-call ] unit-test
+[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-signed-cell 1 + ] compile-call ] unit-test
+[ 1 ] [ B{ 0 0 0 0 0 0 0 0 } [ 0 alien-unsigned-cell 1 + ] compile-call ] unit-test
: deep-find-test ( seq -- ? ) [ 5 = ] deep-find ;
! Type inference issue
[ 4 3 ] [
1 >bignum 2 >bignum
- [ { bignum integer } declare [ shift ] keep 1+ ] compile-call
+ [ { bignum integer } declare [ shift ] keep 1 + ] compile-call
] unit-test
: broken-declaration ( -- ) \ + declare ;
[ ] [ [ \ broken-declaration forget ] with-compilation-unit ] unit-test
+! Interval inference issue
+[ f ] [
+ 10 70
+ [
+ dup 70 >=
+ [ dup 700 <= [ swap 1024 rem rem ] [ 2drop 70 ] if ]
+ [ 2drop 70 ] if
+ 70 >=
+ ] compile-call
+] unit-test
+
! Modular arithmetic bug
: modular-arithmetic-bug ( a -- b ) >integer 256 mod ;
\ bad-dispatch-position-test forget
\ bad-dispatch-position-test* forget
] with-compilation-unit
-] unit-test
\ No newline at end of file
+] unit-test
+
+! Not sure if I want to fix this...
+! [ t [ [ f ] [ 3 ] if >fixnum ] compile-call ] [ no-method? ] must-fail-with
\ No newline at end of file
-IN: compiler.tests.peg-regression-2
USING: peg.ebnf strings tools.test ;
+IN: compiler.tests.peg-regression-2
GENERIC: <times> ( times -- term' )
M: string <times> ;
-IN: compiler.tests.pic-problem-1
USING: kernel sequences prettyprint memory tools.test ;
+IN: compiler.tests.pic-problem-1
TUPLE: x ;
CONSTANT: blah T{ x }
-[ T{ x } ] [ blah ] unit-test
\ No newline at end of file
+[ T{ x } ] [ blah ] unit-test
-IN: compiler.tests.redefine0
USING: tools.test eval compiler compiler.errors compiler.units definitions kernel math
namespaces macros assocs ;
+IN: compiler.tests.redefine0
! Test ripple-up behavior
: test-1 ( -- a ) 3 ;
: word-3 ( a -- b ) 1 + ;
-: word-4 ( a -- b c ) 0 swap word-3 swap 1+ ;
+: word-4 ( a -- b c ) 0 swap word-3 swap 1 + ;
[ 1 1 ] [ 0 word-4 ] unit-test
-IN: compiler.tests.redefine16
USING: eval tools.test definitions words compiler.units
quotations stack-checker ;
+IN: compiler.tests.redefine16
[ ] [ [ "blah" "compiler.tests.redefine16" lookup forget ] with-compilation-unit ] unit-test
-IN: compiler.tests.redefine17
USING: tools.test classes.mixin compiler.units arrays kernel.private
strings sequences vocabs definitions kernel ;
+IN: compiler.tests.redefine17
<< "compiler.tests.redefine17" words forget-all >>
-IN: compiler.tests.redefine2
USING: compiler compiler.units tools.test math parser kernel
sequences sequences.private classes.mixin generic definitions
arrays words assocs eval words.symbol ;
+IN: compiler.tests.redefine2
DEFER: redefine2-test
-IN: compiler.tests.redefine3
USING: accessors compiler compiler.units tools.test math parser
kernel sequences sequences.private classes.mixin generic
definitions arrays words assocs eval ;
+IN: compiler.tests.redefine3
GENERIC: sheeple ( obj -- x )
-M: object sheeple drop "sheeple" ;
+M: object sheeple drop "sheeple" ; inline
MIXIN: empty-mixin
-M: empty-mixin sheeple drop "wake up" ;
+M: empty-mixin sheeple drop "wake up" ; inline
: sheeple-test ( -- string ) { } sheeple ;
-IN: compiler.tests.redefine4
USING: io.streams.string kernel tools.test eval ;
+IN: compiler.tests.redefine4
: declaration-test-1 ( -- a ) 3 ; flushable
-IN: compiler.tests.reload
USE: vocabs.loader
+IN: compiler.tests.reload
! "parser" reload
! "sequences" reload
-IN: compiler.tests.stack-trace
USING: compiler tools.test namespaces sequences
kernel.private kernel math continuations continuations.private
words splitting grouping sorting accessors ;
+IN: compiler.tests.stack-trace
: symbolic-stack-trace ( -- newseq )
error-continuation get call>> callstack>array
[ baz ] [ 3 = ] must-fail-with
[ t ] [
symbolic-stack-trace
- [ word? ] filter
+ 2 head*
{ baz bar foo } tail?
] unit-test
[ t ] [
[ { 1 "hi" } bleh ] ignore-errors \ + stack-trace-any?
] unit-test
-
+
[ t f ] [
[ { "hi" } bleh ] ignore-errors
\ + stack-trace-any?
-IN: compiler.tests.tuples
USING: kernel tools.test compiler.units compiler ;
+IN: compiler.tests.tuples
TUPLE: color red green blue ;
{ $errors "Throws an " { $link inference-error } " if stack effect inference fails." } ;
HELP: build-sub-tree
-{ $values { "#call" #call } { "word/quot" { $or word quotation } } { "nodes/f" { $maybe "a sequence of nodes" } } }
+{ $values { "in-d" "a sequence of values" } { "out-d" "a sequence of values" } { "word/quot" { $or word quotation } } { "nodes/f" { $maybe "a sequence of nodes" } } }
{ $description "Attempts to construct tree SSA IR from a quotation, starting with an initial data stack of values from the call site. Outputs " { $link f } " if stack effect inference fails." } ;
-IN: compiler.tree.builder.tests
USING: compiler.tree.builder tools.test sequences kernel
compiler.tree stack-checker stack-checker.errors ;
+IN: compiler.tree.builder.tests
: inline-recursive ( -- ) inline-recursive ; inline recursive
: build-tree ( word/quot -- nodes )
[ f ] dip build-tree-with ;
-:: build-sub-tree ( #call word/quot -- nodes/f )
+:: build-sub-tree ( in-d out-d word/quot -- nodes/f )
#! We don't want methods on mixins to have a declaration for that mixin.
#! This slows down compiler.tree.propagation.inlining since then every
#! inlined usage of a method has an inline-dependency on the mixin, and
#! not the more specific type at the call site.
f specialize-method? [
[
- #call in-d>> word/quot build-tree-with unclip-last in-d>> :> in-d
+ in-d word/quot build-tree-with unclip-last in-d>> :> in-d'
{
{ [ dup not ] [ ] }
- { [ dup ends-with-terminate? ] [ #call out-d>> [ f swap #push ] map append ] }
- [ in-d #call out-d>> #copy suffix ]
+ { [ dup ends-with-terminate? ] [ out-d [ f swap #push ] map append ] }
+ [ in-d' out-d [ [ length ] bi@ assert= ] [ #copy suffix ] 2bi ]
} cond
] [ dup inference-error? [ drop f ] [ rethrow ] if ] recover
- ] with-variable ;
-
+ ] with-variable ;
\ No newline at end of file
+++ /dev/null
-IN: compiler.tree.checker.tests
-USING: compiler.tree.checker tools.test ;
-
-
grouping stack-checker.branches
compiler.tree
compiler.tree.def-use
+compiler.tree.recursive
compiler.tree.combinators ;
IN: compiler.tree.checker
-IN: compiler.tree.cleanup.tests
USING: tools.test kernel.private kernel arrays sequences
math.private math generic words quotations alien alien.c-types
strings sbufs sequences.private slots.private combinators
math.order math.functions accessors hashtables classes assocs
io.encodings.utf8 io.encodings.ascii io.encodings fry slots
sorting.private combinators.short-circuit grouping prettyprint
+generalizations
compiler.tree
compiler.tree.combinators
compiler.tree.cleanup
compiler.tree.propagation.info
compiler.tree.checker
compiler.tree.debugger ;
+IN: compiler.tree.cleanup.tests
[ t ] [ [ [ 1 ] [ 2 ] if ] cleaned-up-tree [ #if? ] contains-node? ] unit-test
GENERIC: mynot ( x -- y )
-M: f mynot drop t ;
+M: f mynot drop t ; inline
-M: object mynot drop f ;
+M: object mynot drop f ; inline
GENERIC: detect-f ( x -- y )
-M: f detect-f ;
+M: f detect-f ; inline
[ t ] [
[ dup [ mynot ] [ ] if detect-f ] \ detect-f inlined?
GENERIC: xyz ( n -- n )
-M: integer xyz ;
+M: integer xyz ; inline
-M: object xyz ;
+M: object xyz ; inline
[ t ] [
[ { integer } declare xyz ] \ xyz inlined?
2over dup xyz drop >= [
3drop
] [
- [ swap [ call 1+ ] dip ] keep (i-repeat)
+ [ swap [ call 1 + ] dip ] keep (i-repeat)
] if ; inline recursive
: i-repeat ( n quot -- ) [ { integer } declare ] dip 0 -rot (i-repeat) ; inline
[ { fixnum } declare [ ] times ] \ >= inlined?
] unit-test
-[ t ] [
- [ { fixnum } declare [ ] times ] \ 1+ inlined?
-] unit-test
-
[ t ] [
[ { fixnum } declare [ ] times ] \ + inlined?
] unit-test
[ { array-capacity } declare 1 fixnum- ] \ fixnum- inlined?
] unit-test
-[ t ] [
- [ 5000 [ 5000 [ ] times ] times ] \ 1+ inlined?
-] unit-test
-
-[ t ] [
- [ 5000 [ [ ] times ] each ] \ 1+ inlined?
-] unit-test
-
-[ t ] [
- [ 5000 0 [ dup 2 - swap [ 2drop ] curry each ] reduce ]
- \ 1+ inlined?
-] unit-test
-
GENERIC: annotate-entry-test-1 ( x -- )
M: fixnum annotate-entry-test-1 drop ;
2dup >= [
2drop
] [
- [ dup annotate-entry-test-1 1+ ] dip (annotate-entry-test-2)
+ [ dup annotate-entry-test-1 1 + ] dip (annotate-entry-test-2)
] if ; inline recursive
: annotate-entry-test-2 ( from to -- obj ) 0 -rot (annotate-entry-test-2) ; inline
{ fixnum-shift-fast } inlined?
] unit-test
+[ t ] [
+ [ 1 swap 7 bitand shift ]
+ { shift fixnum-shift } inlined?
+] unit-test
+
cell-bits 32 = [
[ t ] [
[ { fixnum fixnum } declare 1 swap 31 bitand shift ]
] \ + inlined?
] unit-test
-[ t ] [
- [ 1000 iota [ 1+ ] map ] { 1+ fixnum+ } inlined?
-] unit-test
-
: rec ( a -- b )
dup 0 > [ 1 - rec ] when ; inline recursive
: buffalo-wings ( i seq -- )
2dup < [
2dup chicken-fingers
- [ 1+ ] dip buffalo-wings
+ [ 1 + ] dip buffalo-wings
] [
2drop
] if ; inline recursive
: ribs ( i seq -- )
2dup < [
steak
- [ 1+ ] dip ribs
+ [ 1 + ] dip ribs
] [
2drop
] if ; inline recursive
[ { integer integer } declare + drop ]
{ + +-integer-integer } inlined?
] unit-test
+
+[ [ ] ] [
+ [
+ 20 f <array>
+ [ 0 swap nth ] keep
+ [ 1 swap nth ] keep
+ [ 2 swap nth ] keep
+ [ 3 swap nth ] keep
+ [ 4 swap nth ] keep
+ [ 5 swap nth ] keep
+ [ 6 swap nth ] keep
+ [ 7 swap nth ] keep
+ [ 8 swap nth ] keep
+ [ 9 swap nth ] keep
+ [ 10 swap nth ] keep
+ [ 11 swap nth ] keep
+ [ 12 swap nth ] keep
+ 14 ndrop
+ ] cleaned-up-tree nodes>quot
+] unit-test
GENERIC: delete-node ( node -- )
M: #call-recursive delete-node
- dup label>> [ [ eq? not ] with filter ] change-calls drop ;
+ dup label>> calls>> [ node>> eq? not ] with filter-here ;
M: #return-recursive delete-node
label>> f >>return drop ;
[ ]
} cond ;
-M: #declare cleanup* drop f ;
-
: delete-unreachable-branches ( #branch -- )
dup live-branches>> '[
_
-IN: compiler.tree.combinators.tests
USING: compiler.tree.combinators tools.test kernel ;
+IN: compiler.tree.combinators.tests
{ 1 0 } [ [ drop ] each-node ] must-infer-as
{ 1 1 } [ [ ] map-nodes ] must-infer-as
USING: sequences namespaces kernel accessors assocs sets fry
arrays combinators columns stack-checker.backend
stack-checker.branches compiler.tree compiler.tree.combinators
-compiler.tree.dead-code.liveness compiler.tree.dead-code.simple
-;
+compiler.tree.dead-code.liveness compiler.tree.dead-code.simple ;
IN: compiler.tree.dead-code.branches
M: #if mark-live-values* look-at-inputs ;
USING: accessors arrays assocs sequences kernel locals fry
combinators stack-checker.backend
compiler.tree
+compiler.tree.recursive
compiler.tree.dead-code.branches
compiler.tree.dead-code.liveness
compiler.tree.dead-code.simple ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors words assocs sequences arrays namespaces
-fry locals definitions classes.algebra
+fry locals definitions classes classes.algebra generic
stack-checker.state
stack-checker.backend
compiler.tree
compiler.tree.dead-code.liveness ;
IN: compiler.tree.dead-code.simple
-: flushable? ( word -- ? )
- [ "flushable" word-prop ] [ "predicating" word-prop ] bi or ;
+GENERIC: flushable? ( word -- ? )
+
+M: predicate flushable? drop t ;
+
+M: word flushable? "flushable" word-prop ;
+
+M: method-body flushable? "method-generic" word-prop flushable? ;
: flushable-call? ( #call -- ? )
dup word>> dup flushable? [
-IN: compiler.tree.debugger.tests
USING: compiler.tree.debugger tools.test sorting sequences io math.order ;
+IN: compiler.tree.debugger.tests
[ [ <=> ] sort ] optimized.
-[ <reversed> [ print ] each ] optimizer-report.
\ No newline at end of file
+[ <reversed> [ print ] each ] optimizer-report.
-! Copyright (C) 2006, 2008 Slava Pestov.
+! Copyright (C) 2006, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel assocs match fry accessors namespaces make effects
sequences sequences.private quotations generic macros arrays
compiler.tree.cleanup
compiler.tree.propagation
compiler.tree.propagation.info
+compiler.tree.escape-analysis
+compiler.tree.tuple-unboxing
compiler.tree.def-use
compiler.tree.builder
compiler.tree.optimizer
compiler.tree.combinators
-compiler.tree.checker ;
+compiler.tree.checker
+compiler.tree.identities
+compiler.tree.dead-code
+compiler.tree.modular-arithmetic ;
FROM: fry => _ ;
RENAME: _ match => __
IN: compiler.tree.debugger
H{ } clone intrinsics-called set
0 swap [
- [ 1+ ] dip
+ [ 1 + ] dip
dup #call? [
word>> {
{ [ dup "intrinsic" word-prop ] [ intrinsics-called ] }
: cleaned-up-tree ( quot -- nodes )
[
- check-optimizer? on
- build-tree optimize-tree
+ build-tree
+ analyze-recursive
+ normalize
+ propagate
+ cleanup
+ escape-analysis
+ unbox-tuples
+ apply-identities
+ compute-def-use
+ remove-dead-code
+ compute-def-use
+ optimize-modular-arithmetic
] with-scope ;
: inlined? ( quot seq/word -- ? )
ERROR: no-def-error value ;
: def-of ( value -- definition )
- dup def-use get at* [ nip ] [ no-def-error ] if ;
+ def-use get ?at [ no-def-error ] unless ;
ERROR: multiple-defs-error ;
M: #introduce node-uses-values drop f ;
M: #push node-uses-values drop f ;
M: #phi node-uses-values phi-in-d>> concat remove-bottom prune ;
-M: #declare node-uses-values declaration>> keys ;
+M: #declare node-uses-values drop f ;
M: #terminate node-uses-values [ in-d>> ] [ in-r>> ] bi append ;
M: #shuffle node-uses-values [ in-d>> ] [ in-r>> ] bi append ;
M: #alien-callback node-uses-values drop f ;
USING: kernel tools.test compiler.tree compiler.tree.builder
-compiler.tree.def-use compiler.tree.def-use.simplified accessors
-sequences sorting classes ;
+compiler.tree.recursive compiler.tree.def-use
+compiler.tree.def-use.simplified accessors sequences sorting classes ;
IN: compiler.tree.def-use.simplified
[ { #call #return } ] [
first out-d>> first actually-used-by
[ node>> class ] map natural-sort
] unit-test
+
+: word-1 ( a -- b ) dup [ word-1 ] when ; inline recursive
+
+[ { #introduce } ] [
+ [ word-1 ] build-tree analyze-recursive compute-def-use
+ last in-d>> first actually-defined-by
+ [ node>> class ] map natural-sort
+] unit-test
+
+[ { #if #return } ] [
+ [ word-1 ] build-tree analyze-recursive compute-def-use
+ first out-d>> first actually-used-by
+ [ node>> class ] map natural-sort
+] unit-test
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: sequences kernel fry vectors
-compiler.tree compiler.tree.def-use ;
+USING: sequences kernel fry vectors accessors namespaces assocs sets
+stack-checker.branches compiler.tree compiler.tree.def-use ;
IN: compiler.tree.def-use.simplified
! Simplified def-use follows chains of copies.
! A 'real' usage is a usage of a value that is not a #renaming.
TUPLE: real-usage value node ;
+<PRIVATE
+
+SYMBOLS: visited accum ;
+
+: if-not-visited ( value quot -- )
+ over visited get key?
+ [ 2drop ] [ over visited get conjoin call ] if ; inline
+
+: with-simplified-def-use ( quot -- real-usages )
+ [
+ H{ } clone visited set
+ H{ } clone accum set
+ call
+ accum get keys
+ ] with-scope ; inline
+
+PRIVATE>
+
! Def
-GENERIC: actually-defined-by* ( value node -- real-usage )
+GENERIC: actually-defined-by* ( value node -- )
-: actually-defined-by ( value -- real-usage )
- dup defined-by actually-defined-by* ;
+: (actually-defined-by) ( value -- )
+ [ dup defined-by actually-defined-by* ] if-not-visited ;
M: #renaming actually-defined-by*
- inputs/outputs swap [ index ] dip nth actually-defined-by ;
+ inputs/outputs swap [ index ] dip nth (actually-defined-by) ;
+
+M: #call-recursive actually-defined-by*
+ [ out-d>> index ] [ label>> return>> in-d>> nth ] bi
+ (actually-defined-by) ;
-M: #return-recursive actually-defined-by* real-usage boa ;
+M: #enter-recursive actually-defined-by*
+ [ out-d>> index ] keep
+ [ in-d>> nth (actually-defined-by) ]
+ [ label>> calls>> [ node>> in-d>> nth (actually-defined-by) ] with each ] 2bi ;
-M: node actually-defined-by* real-usage boa ;
+M: #phi actually-defined-by*
+ [ out-d>> index ] [ phi-in-d>> ] bi
+ [
+ nth dup +bottom+ eq?
+ [ drop ] [ (actually-defined-by) ] if
+ ] with each ;
+
+M: node actually-defined-by*
+ real-usage boa accum get conjoin ;
+
+: actually-defined-by ( value -- real-usages )
+ [ (actually-defined-by) ] with-simplified-def-use ;
! Use
-GENERIC# actually-used-by* 1 ( value node accum -- )
+GENERIC: actually-used-by* ( value node -- )
-: (actually-used-by) ( value accum -- )
- [ [ used-by ] keep ] dip '[ _ swap _ actually-used-by* ] each ;
+: (actually-used-by) ( value -- )
+ [ dup used-by [ actually-used-by* ] with each ] if-not-visited ;
M: #renaming actually-used-by*
- [ inputs/outputs [ indices ] dip nths ] dip
- '[ _ (actually-used-by) ] each ;
+ inputs/outputs [ indices ] dip nths
+ [ (actually-used-by) ] each ;
+
+M: #return-recursive actually-used-by*
+ [ in-d>> index ] keep
+ [ out-d>> nth (actually-used-by) ]
+ [ label>> calls>> [ node>> out-d>> nth (actually-used-by) ] with each ] 2bi ;
+
+M: #call-recursive actually-used-by*
+ [ in-d>> index ] [ label>> enter-out>> nth ] bi
+ (actually-used-by) ;
+
+M: #enter-recursive actually-used-by*
+ [ in-d>> index ] [ out-d>> nth ] bi (actually-used-by) ;
+
+M: #phi actually-used-by*
+ [ phi-in-d>> [ index ] with map-find drop ] [ out-d>> nth ] bi
+ (actually-used-by) ;
-M: #return-recursive actually-used-by* [ real-usage boa ] dip push ;
+M: #recursive actually-used-by* 2drop ;
-M: node actually-used-by* [ real-usage boa ] dip push ;
+M: node actually-used-by*
+ real-usage boa accum get conjoin ;
: actually-used-by ( value -- real-usages )
- 10 <vector> [ (actually-used-by) ] keep ;
+ [ (actually-used-by) ] with-simplified-def-use ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs namespaces sequences kernel math
combinators sets disjoint-sets fry stack-checker.values ;
IN: compiler.tree.escape-analysis.allocations
+! A map from values to classes. Only for #introduce outputs
+SYMBOL: value-classes
+
+: value-class ( value -- class ) value-classes get at ;
+
+: set-value-class ( class value -- ) value-classes get set-at ;
+
! A map from values to one of the following:
! - f -- initial status, assigned to values we have not seen yet;
! may potentially become an allocation later
--- /dev/null
+USING: compiler.tree.escape-analysis.check tools.test accessors kernel
+kernel.private math compiler.tree.builder compiler.tree.normalization
+compiler.tree.propagation compiler.tree.cleanup ;
+IN: compiler.tree.escape-analysis.check.tests
+
+: test-checker ( quot -- ? )
+ build-tree normalize propagate cleanup run-escape-analysis? ;
+
+[ t ] [
+ [ { complex } declare [ real>> ] [ imaginary>> ] bi ]
+ test-checker
+] unit-test
+
+[ t ] [
+ [ complex boa [ real>> ] [ imaginary>> ] bi ]
+ test-checker
+] unit-test
+
+[ t ] [
+ [ [ complex boa [ real>> ] [ imaginary>> ] bi ] when ]
+ test-checker
+] unit-test
+
+[ f ] [
+ [ swap 1 2 ? ]
+ test-checker
+] unit-test
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: classes classes.tuple math math.private accessors
-combinators kernel compiler.tree compiler.tree.combinators
-compiler.tree.propagation.info ;
+USING: classes classes.tuple math math.private accessors sequences
+combinators.short-circuit kernel compiler.tree
+compiler.tree.combinators compiler.tree.propagation.info ;
IN: compiler.tree.escape-analysis.check
GENERIC: run-escape-analysis* ( node -- ? )
+: unbox-inputs? ( nodes -- ? )
+ {
+ [ length 2 >= ]
+ [ first #introduce? ]
+ [ second #declare? ]
+ } 1&& ;
+
+: run-escape-analysis? ( nodes -- ? )
+ { [ unbox-inputs? ] [ [ run-escape-analysis* ] any? ] } 1|| ;
+
M: #push run-escape-analysis*
- literal>> [ class immutable-tuple-class? ] [ complex? ] bi or ;
+ literal>> class immutable-tuple-class? ;
M: #call run-escape-analysis*
- {
- { [ dup immutable-tuple-boa? ] [ t ] }
- [ f ]
- } cond nip ;
+ immutable-tuple-boa? ;
-M: node run-escape-analysis* drop f ;
+M: #recursive run-escape-analysis*
+ child>> run-escape-analysis? ;
-: run-escape-analysis? ( nodes -- ? )
- [ run-escape-analysis* ] contains-node? ;
+M: #branch run-escape-analysis*
+ children>> [ run-escape-analysis? ] any? ;
+
+M: node run-escape-analysis* drop f ;
-IN: compiler.tree.escape-analysis.tests
USING: compiler.tree.escape-analysis
compiler.tree.escape-analysis.allocations compiler.tree.builder
compiler.tree.recursive compiler.tree.normalization
classes.tuple namespaces
compiler.tree.propagation.info stack-checker.errors
compiler.tree.checker
-kernel.private ;
+kernel.private vectors ;
+IN: compiler.tree.escape-analysis.tests
GENERIC: count-unboxed-allocations* ( m node -- n )
: (count-unboxed-allocations) ( m node -- n )
- out-d>> first escaping-allocation? [ 1+ ] unless ;
+ out-d>> first escaping-allocation? [ 1 + ] unless ;
M: #call count-unboxed-allocations*
dup immutable-tuple-boa?
dup literal>> class immutable-tuple-class?
[ (count-unboxed-allocations) ] [ drop ] if ;
+M: #introduce count-unboxed-allocations*
+ out-d>> [ escaping-allocation? [ 1 + ] unless ] each ;
+
M: node count-unboxed-allocations* drop ;
: count-unboxed-allocations ( quot -- sizes )
dup i>> 1 <= [
drop 1 <ro-box>
] [
- i>> 1- <ro-box>
+ i>> 1 - <ro-box>
dup tuple-fib
swap
- i>> 1- <ro-box>
+ i>> 1 - <ro-box>
tuple-fib
swap i>> swap i>> + <ro-box>
] if ; inline recursive
[ 3 ] [ [ <ro-box> tuple-fib ] count-unboxed-allocations ] unit-test
: tuple-fib' ( m -- n )
- dup 1 <= [ 1- tuple-fib' i>> ] when <ro-box> ; inline recursive
+ dup 1 <= [ 1 - tuple-fib' i>> ] when <ro-box> ; inline recursive
[ 0 ] [ [ tuple-fib' ] count-unboxed-allocations ] unit-test
dup i>> 1 <= [
drop 1 <ro-box>
] [
- i>> 1- <ro-box>
+ i>> 1 - <ro-box>
dup bad-tuple-fib-1
swap
- i>> 1- <ro-box>
+ i>> 1 - <ro-box>
bad-tuple-fib-1 dup .
swap i>> swap i>> + <ro-box>
] if ; inline recursive
dup i>> 1 <= [
drop 1 <ro-box>
] [
- i>> 1- <ro-box>
+ i>> 1 - <ro-box>
dup bad-tuple-fib-2
swap
- i>> 1- <ro-box>
+ i>> 1 - <ro-box>
bad-tuple-fib-2
swap i>> swap i>> + <ro-box>
] if ; inline recursive
dup 1 <= [
drop 1 <ro-box>
] [
- 1- dup tuple-fib-2
+ 1 - dup tuple-fib-2
swap
- 1- tuple-fib-2
+ 1 - tuple-fib-2
swap i>> swap i>> + <ro-box>
] if ; inline recursive
dup 1 <= [
drop 1 <ro-box>
] [
- 1- dup tuple-fib-3
+ 1 - dup tuple-fib-3
swap
- 1- tuple-fib-3 dup .
+ 1 - tuple-fib-3 dup .
swap i>> swap i>> + <ro-box>
] if ; inline recursive
dup 1 <= [
drop 1 <ro-box>
] [
- 1- dup bad-tuple-fib-3
+ 1 - dup bad-tuple-fib-3
swap
- 1- bad-tuple-fib-3
+ 1 - bad-tuple-fib-3
2drop f
] if ; inline recursive
TUPLE: empty-tuple ;
-[ ] [ [ empty-tuple boa layout-of ] count-unboxed-allocations drop ] unit-test
\ No newline at end of file
+[ ] [ [ empty-tuple boa layout-of ] count-unboxed-allocations drop ] unit-test
+
+! New feature!
+
+[ 1 ] [ [ { complex } declare real>> ] count-unboxed-allocations ] unit-test
+
+[ 1 ] [
+ [ { complex } declare [ real>> ] [ imaginary>> ] bi ]
+ count-unboxed-allocations
+] unit-test
+
+[ 0 ] [
+ [ { vector } declare length>> ]
+ count-unboxed-allocations
+] unit-test
init-escaping-values
H{ } clone allocations set
H{ } clone slot-accesses set
+ H{ } clone value-classes set
dup (escape-analysis)
compute-escaping-allocations ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel sequences
+USING: kernel sequences fry math namespaces
compiler.tree
compiler.tree.def-use
compiler.tree.escape-analysis.allocations ;
GENERIC: escape-analysis* ( node -- )
+SYMBOL: next-node
+
+: each-with-next ( seq quot: ( elt -- ) -- )
+ dupd '[ 1 + _ ?nth next-node set @ ] each-index ; inline
+
: (escape-analysis) ( node -- )
[
[ node-defs-values introduce-values ]
[ escape-analysis* ]
bi
- ] each ;
+ ] each-with-next ;
-IN: compiler.tree.escape-analysis.recursive.tests
USING: kernel tools.test namespaces sequences
compiler.tree.escape-analysis.recursive
compiler.tree.escape-analysis.allocations ;
+IN: compiler.tree.escape-analysis.recursive.tests
H{ } clone allocations set
<escaping-values> escaping-values set
USING: kernel sequences math combinators accessors namespaces
fry disjoint-sets
compiler.tree
+compiler.tree.recursive
compiler.tree.combinators
compiler.tree.escape-analysis.nodes
compiler.tree.escape-analysis.branches
[ call-next-method ]
[
[ in-d>> ] [ label>> calls>> ] bi
- [ out-d>> escaping-values get '[ _ equate ] 2each ] with each
+ [ node>> out-d>> escaping-values get '[ _ equate ] 2each ] with each
] bi ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors sequences classes.tuple
classes.tuple.private arrays math math.private slots.private
combinators deques search-deques namespaces fry classes
-classes.algebra stack-checker.state
+classes.algebra assocs stack-checker.state
compiler.tree
compiler.tree.propagation.info
compiler.tree.escape-analysis.nodes
compiler.tree.escape-analysis.allocations ;
IN: compiler.tree.escape-analysis.simple
+M: #declare escape-analysis* drop ;
+
M: #terminate escape-analysis* drop ;
M: #renaming escape-analysis* inputs/outputs copy-values ;
-M: #introduce escape-analysis* out-d>> unknown-allocations ;
+: declared-class ( value -- class/f )
+ next-node get dup #declare? [ declaration>> at ] [ 2drop f ] if ;
+
+: record-param-allocation ( value class -- )
+ dup immutable-tuple-class? [
+ [ swap set-value-class ] [
+ all-slots [
+ [ <slot-value> dup ] [ class>> ] bi*
+ record-param-allocation
+ ] map swap record-allocation
+ ] 2bi
+ ] [ drop unknown-allocation ] if ;
+
+M: #introduce escape-analysis*
+ out-d>> [ dup declared-class record-param-allocation ] each ;
DEFER: record-literal-allocation
: object-slots ( object -- slots/f )
{
{ [ dup class immutable-tuple-class? ] [ tuple-slots ] }
- { [ dup complex? ] [ [ real-part ] [ imaginary-part ] bi 2array ] }
[ drop f ]
} cond ;
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors sequences words memoize combinators
-classes classes.builtin classes.tuple math.partial-dispatch
-fry assocs
+classes classes.builtin classes.tuple classes.singleton
+math.partial-dispatch fry assocs combinators.short-circuit
compiler.tree
compiler.tree.combinators
compiler.tree.propagation.info
M: #copy finalize* drop f ;
M: #shuffle finalize*
- dup
- [ [ in-d>> ] [ out-d>> ] [ mapping>> ] tri '[ _ at ] map sequence= ]
- [ [ in-r>> ] [ out-r>> ] [ mapping>> ] tri '[ _ at ] map sequence= ]
- bi and [ drop f ] when ;
+ dup {
+ [ [ in-d>> length ] [ out-d>> length ] bi = ]
+ [ [ in-r>> length ] [ out-r>> length ] bi = ]
+ [ [ in-d>> ] [ out-d>> ] [ mapping>> ] tri '[ _ at = ] 2all? ]
+ [ [ in-r>> ] [ out-r>> ] [ mapping>> ] tri '[ _ at = ] 2all? ]
+ } 1&& [ drop f ] when ;
MEMO: cached-expansion ( word -- nodes )
def>> splice-final ;
"predicating" word-prop {
{ [ dup builtin-class? ] [ drop word>> cached-expansion ] }
{ [ dup tuple-class? ] [ drop word>> def>> splice-final ] }
+ { [ dup singleton-class? ] [ drop word>> def>> splice-final ] }
[ drop ]
} cond ;
+M: math-partial finalize-word
+ dup primitive? [ drop ] [ nip cached-expansion ] if ;
+
M: word finalize-word drop ;
M: #call finalize*
--- /dev/null
+Slava Pestov
+Daniel Ehrenberg
-IN: compiler.tree.modular-arithmetic.tests
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
USING: kernel kernel.private tools.test math math.partial-dispatch
-math.private accessors slots.private sequences strings sbufs
-compiler.tree.builder
-compiler.tree.optimizer
-compiler.tree.debugger ;
+prettyprint math.private accessors slots.private sequences
+sequences.private strings sbufs compiler.tree.builder
+compiler.tree.normalization compiler.tree.debugger alien.accessors
+layouts combinators byte-arrays arrays ;
+IN: compiler.tree.modular-arithmetic.tests
: test-modular-arithmetic ( quot -- quot' )
- build-tree optimize-tree nodes>quot ;
+ cleaned-up-tree nodes>quot ;
[ [ >R >fixnum R> >fixnum fixnum+fast ] ]
[ [ { integer integer } declare + >fixnum ] test-modular-arithmetic ] unit-test
[ { string sbuf } declare ] \ push-all def>> append \ >fixnum inlined?
] unit-test
-
-
[ t ] [
[
{ integer } declare [ 256 mod ] map
] { mod fixnum-mod rem } inlined?
] unit-test
-[ [ >fixnum 255 fixnum-bitand ] ]
-[ [ >integer 256 rem ] test-modular-arithmetic ] unit-test
\ No newline at end of file
+[ [ >fixnum 255 >R R> fixnum-bitand ] ]
+[ [ >integer 256 rem ] test-modular-arithmetic ] unit-test
+
+[ t ] [
+ [ { fixnum fixnum } declare + [ 1 + >fixnum ] [ 2 + >fixnum ] bi ]
+ { >fixnum } inlined?
+] unit-test
+
+[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-unsigned-1 ] ]
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-1 ] test-modular-arithmetic ] unit-test
+
+[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-unsigned-2 ] ]
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-2 ] test-modular-arithmetic ] unit-test
+
+cell {
+ { 4 [ [ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-unsigned-4 ] ] ] }
+ { 8 [ [ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-unsigned-4 ] ] ] }
+} case
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-4 ] test-modular-arithmetic ] unit-test
+
+[ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-unsigned-8 ] ]
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-8 ] test-modular-arithmetic ] unit-test
+
+[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-signed-1 ] ]
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-1 ] test-modular-arithmetic ] unit-test
+
+[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-signed-2 ] ]
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-2 ] test-modular-arithmetic ] unit-test
+
+cell {
+ { 4 [ [ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-signed-4 ] ] ] }
+ { 8 [ [ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-signed-4 ] ] ] }
+} case
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-4 ] test-modular-arithmetic ] unit-test
+
+[ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-signed-8 ] ]
+[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-8 ] test-modular-arithmetic ] unit-test
+
+[ t ] [ [ { fixnum byte-array } declare [ + ] with map ] { + fixnum+ >fixnum } inlined? ] unit-test
+
+[ t ] [
+ [ 0 10 <byte-array> 10 [ 1 pick 0 + >fixnum pick set-nth-unsafe [ 1 + >fixnum ] dip ] times ]
+ { >fixnum } inlined?
+] unit-test
+
+[ f ] [ [ + >fixnum ] { >fixnum } inlined? ] unit-test
+
+[ t ] [
+ [ >integer [ >fixnum ] [ >fixnum ] bi ]
+ { >integer } inlined?
+] unit-test
+
+[ f ] [
+ [ >integer [ >fixnum ] [ >fixnum ] bi ]
+ { >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ >integer [ 2 + >fixnum ] [ 3 + >fixnum ] bi ]
+ { >integer } inlined?
+] unit-test
+
+[ f ] [
+ [ >integer [ 2 + >fixnum ] [ 3 + >fixnum ] bi ]
+ { >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ >integer [ >fixnum ] [ >fixnum ] bi ]
+ { >integer } inlined?
+] unit-test
+
+[ f ] [
+ [ >bignum [ >fixnum ] [ >fixnum ] bi ]
+ { >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ >bignum [ >fixnum ] [ >fixnum ] bi ]
+ { >bignum } inlined?
+] unit-test
+
+[ f ] [
+ [ [ { fixnum } declare 2 fixnum+ ] dip [ >fixnum 2 - ] [ ] if ]
+ { fixnum+ } inlined?
+] unit-test
+
+[ t ] [
+ [ { fixnum boolean } declare [ 1 + ] [ "HI" throw ] if >fixnum ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ { fixnum boolean } declare [ 1 + ] [ drop 5 ] if >fixnum ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ { fixnum boolean } declare [ 1 + ] [ 2 + ] if >fixnum ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ [ [ 1 ] [ 4 ] if ] ] [
+ [ [ 1.5 ] [ 4 ] if >fixnum ] test-modular-arithmetic
+] unit-test
+
+[ [ [ 1 ] [ 2 ] if ] ] [
+ [ [ 1.5 ] [ 2.3 ] if >fixnum ] test-modular-arithmetic
+] unit-test
+
+[ f ] [
+ [ { fixnum fixnum boolean } declare [ [ 3 * ] [ 1 + ] dip ] [ [ 4 - ] [ 2 + ] dip ] if >fixnum ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ 0 1000 [ 1 + dup >fixnum . ] times drop ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ { fixnum } declare 3 + [ 1000 ] dip [ >fixnum . ] curry times ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ 0 1000 [ 1 + ] times >fixnum ]
+ { fixnum+ >fixnum } inlined?
+] unit-test
+
+[ f ] [
+ [ f >fixnum ]
+ { >fixnum } inlined?
+] unit-test
+
+[ f ] [
+ [ [ >fixnum ] 2dip set-alien-unsigned-1 ]
+ { >fixnum } inlined?
+] unit-test
+
+[ t ] [
+ [ { fixnum } declare 123 >bignum bitand >fixnum ]
+ { >bignum fixnum>bignum bignum-bitand } inlined?
+] unit-test
+
+! Shifts
+[ t ] [
+ [
+ [ 0 ] 2dip { array } declare [
+ hashcode* >fixnum swap [
+ [ -2 shift ] [ 5 shift ] bi
+ + +
+ ] keep bitxor >fixnum
+ ] with each
+ ] { + bignum+ fixnum-shift bitxor bignum-bitxor } inlined?
+] unit-test
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
-USING: math math.partial-dispatch namespaces sequences sets
-accessors assocs words kernel memoize fry combinators
-combinators.short-circuit
+USING: math math.intervals math.private math.partial-dispatch
+namespaces sequences sets accessors assocs words kernel memoize fry
+combinators combinators.short-circuit layouts alien.accessors
compiler.tree
compiler.tree.combinators
+compiler.tree.propagation.info
compiler.tree.def-use
compiler.tree.def-use.simplified
compiler.tree.late-optimizations ;
! ==>
! [ >fixnum ] bi@ fixnum+fast
+! Words where the low-order bits of the output only depends on the
+! low-order bits of the input. If the output is only used for its
+! low-order bits, then the word can be converted into a form that is
+! cheaper to compute.
{ + - * bitand bitor bitxor } [
[
t "modular-arithmetic" set-word-prop
] each-integer-derived-op
] each
-{ bitand bitor bitxor bitnot }
+{ bitand bitor bitxor bitnot >integer >bignum fixnum>bignum }
[ t "modular-arithmetic" set-word-prop ] each
-SYMBOL: modularize-values
+! Words that only use the low-order bits of their input. If the input
+! is a modular arithmetic word, then the input can be converted into
+! a form that is cheaper to compute.
+{
+ >fixnum bignum>fixnum float>fixnum
+ set-alien-unsigned-1 set-alien-signed-1
+ set-alien-unsigned-2 set-alien-signed-2
+}
+cell 8 = [
+ { set-alien-unsigned-4 set-alien-signed-4 } append
+] when
+[ t "low-order" set-word-prop ] each
+
+! Values which only have their low-order bits used. This set starts out
+! big and is gradually refined.
+SYMBOL: modular-values
: modular-value? ( value -- ? )
- modularize-values get key? ;
+ modular-values get key? ;
-: modularize-value ( value -- ) modularize-values get conjoin ;
+: modular-value ( value -- )
+ modular-values get conjoin ;
-GENERIC: maybe-modularize* ( value node -- )
+! Values which are known to be fixnums.
+SYMBOL: fixnum-values
-: maybe-modularize ( value -- )
- actually-defined-by [ value>> ] [ node>> ] bi
- over actually-used-by length 1 = [
- maybe-modularize*
- ] [ 2drop ] if ;
+: fixnum-value? ( value -- ? )
+ fixnum-values get key? ;
-M: #call maybe-modularize*
- dup word>> "modular-arithmetic" word-prop [
- [ modularize-value ]
- [ in-d>> [ maybe-modularize ] each ] bi*
- ] [ 2drop ] if ;
+: fixnum-value ( value -- )
+ fixnum-values get conjoin ;
-M: node maybe-modularize* 2drop ;
+GENERIC: compute-modular-candidates* ( node -- )
-GENERIC: compute-modularized-values* ( node -- )
+M: #push compute-modular-candidates*
+ [ out-d>> first ] [ literal>> ] bi
+ real? [ [ modular-value ] [ fixnum-value ] bi ] [ drop ] if ;
-M: #call compute-modularized-values*
- dup word>> \ >fixnum eq?
- [ in-d>> first maybe-modularize ] [ drop ] if ;
+: small-shift? ( interval -- ? )
+ 0 cell-bits tag-bits get - 1 - [a,b] interval-subset? ;
-M: node compute-modularized-values* drop ;
+: modular-word? ( #call -- ? )
+ dup word>> { shift fixnum-shift bignum-shift } memq?
+ [ node-input-infos second interval>> small-shift? ]
+ [ word>> "modular-arithmetic" word-prop ]
+ if ;
-: compute-modularized-values ( nodes -- )
- [ compute-modularized-values* ] each-node ;
+: output-candidate ( #call -- )
+ out-d>> first [ modular-value ] [ fixnum-value ] bi ;
+
+: low-order-word? ( #call -- ? )
+ word>> "low-order" word-prop ;
+
+: input-candidiate ( #call -- )
+ in-d>> first modular-value ;
+
+M: #call compute-modular-candidates*
+ {
+ { [ dup modular-word? ] [ output-candidate ] }
+ { [ dup low-order-word? ] [ input-candidiate ] }
+ [ drop ]
+ } cond ;
+
+M: node compute-modular-candidates*
+ drop ;
+
+: compute-modular-candidates ( nodes -- )
+ H{ } clone modular-values set
+ H{ } clone fixnum-values set
+ [ compute-modular-candidates* ] each-node ;
+
+GENERIC: only-reads-low-order? ( node -- ? )
+
+: output-modular? ( #call -- ? )
+ out-d>> first modular-values get key? ;
+
+M: #call only-reads-low-order?
+ {
+ [ low-order-word? ]
+ [ { [ modular-word? ] [ output-modular? ] } 1&& ]
+ } 1|| ;
+
+M: node only-reads-low-order? drop f ;
+
+SYMBOL: changed?
+
+: only-used-as-low-order? ( value -- ? )
+ actually-used-by [ node>> only-reads-low-order? ] all? ;
+
+: (compute-modular-values) ( -- )
+ modular-values get keys [
+ dup only-used-as-low-order?
+ [ drop ] [ modular-values get delete-at changed? on ] if
+ ] each ;
+
+: compute-modular-values ( -- )
+ [ changed? off (compute-modular-values) changed? get ] loop ;
GENERIC: optimize-modular-arithmetic* ( node -- nodes )
+M: #push optimize-modular-arithmetic*
+ dup [ out-d>> first modular-value? ] [ literal>> real? ] bi and
+ [ [ >fixnum ] change-literal ] when ;
+
: redundant->fixnum? ( #call -- ? )
- in-d>> first actually-defined-by value>> modular-value? ;
+ in-d>> first actually-defined-by
+ [ value>> { [ modular-value? ] [ fixnum-value? ] } 1&& ] all? ;
: optimize->fixnum ( #call -- nodes )
dup redundant->fixnum? [ drop f ] when ;
+: should-be->fixnum? ( #call -- ? )
+ out-d>> first modular-value? ;
+
: optimize->integer ( #call -- nodes )
- dup out-d>> first actually-used-by dup length 1 = [
- first node>> { [ #call? ] [ word>> \ >fixnum eq? ] } 1&&
- [ drop { } ] when
- ] [ drop ] if ;
+ dup should-be->fixnum? [ \ >fixnum >>word ] when ;
MEMO: fixnum-coercion ( flags -- nodes )
+ ! flags indicate which input parameters are already known to be fixnums,
+ ! and don't need a coercion as a result.
[ [ ] [ >fixnum ] ? ] map '[ _ spread ] splice-quot ;
+: modular-value-info ( #call -- alist )
+ [ in-d>> ] [ out-d>> ] bi append
+ fixnum <class-info> '[ _ ] { } map>assoc ;
+
: optimize-modular-op ( #call -- nodes )
dup out-d>> first modular-value? [
[ in-d>> ] [ word>> integer-op-input-classes ] [ ] tri
[
[
- [ actually-defined-by value>> modular-value? ]
+ [ actually-defined-by [ value>> modular-value? ] all? ]
[ fixnum eq? ]
bi* or
] 2map fixnum-coercion
] [ [ modular-variant ] change-word ] bi* suffix
] when ;
+: optimize-low-order-op ( #call -- nodes )
+ dup in-d>> first actually-defined-by [ value>> fixnum-value? ] all? [
+ [ ] [ in-d>> first ] [ info>> ] tri
+ [ drop fixnum <class-info> ] change-at
+ ] when ;
+
+: like->fixnum? ( #call -- ? )
+ word>> { >fixnum bignum>fixnum float>fixnum } memq? ;
+
+: like->integer? ( #call -- ? )
+ word>> { >integer >bignum fixnum>bignum } memq? ;
+
M: #call optimize-modular-arithmetic*
- dup word>> {
- { [ dup \ >fixnum eq? ] [ drop optimize->fixnum ] }
- { [ dup \ >integer eq? ] [ drop optimize->integer ] }
- { [ dup "modular-arithmetic" word-prop ] [ drop optimize-modular-op ] }
- [ drop ]
+ {
+ { [ dup like->fixnum? ] [ optimize->fixnum ] }
+ { [ dup like->integer? ] [ optimize->integer ] }
+ { [ dup modular-word? ] [ optimize-modular-op ] }
+ { [ dup low-order-word? ] [ optimize-low-order-op ] }
+ [ ]
} cond ;
M: node optimize-modular-arithmetic* ;
: optimize-modular-arithmetic ( nodes -- nodes' )
- H{ } clone modularize-values set
- dup compute-modularized-values
- [ optimize-modular-arithmetic* ] map-nodes ;
+ dup compute-modular-candidates compute-modular-values
+ modular-values get assoc-empty? [
+ [ optimize-modular-arithmetic* ] map-nodes
+ ] unless ;
-IN: compiler.tree.normalization.tests
USING: compiler.tree.builder compiler.tree.recursive
compiler.tree.normalization
compiler.tree.normalization.introductions
compiler.tree.normalization.renaming
compiler.tree compiler.tree.checker
sequences accessors tools.test kernel math ;
+IN: compiler.tree.normalization.tests
[ 3 ] [ [ 3drop 1 2 3 ] build-tree count-introductions ] unit-test
+++ /dev/null
-USING: compiler.tree.optimizer tools.test ;
-IN: compiler.tree.optimizer.tests
-
-
: ?check ( nodes -- nodes' )
check-optimizer? get [
- compute-def-use
dup check-nodes
] when ;
--- /dev/null
+Slava Pestov
+Daniel Ehrenberg
--- /dev/null
+! Copyright (C) 2009 Slava Pestov, Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: compiler.tree.propagation.call-effect tools.test fry math effects kernel
+compiler.tree.builder compiler.tree.optimizer compiler.tree.debugger sequences ;
+IN: compiler.tree.propagation.call-effect.tests
+
+[ t ] [ \ + (( a b -- c )) execute-effect-unsafe? ] unit-test
+[ t ] [ \ + (( a b c -- d e )) execute-effect-unsafe? ] unit-test
+[ f ] [ \ + (( a b c -- d )) execute-effect-unsafe? ] unit-test
+[ f ] [ \ call (( x -- )) execute-effect-unsafe? ] unit-test
+
+[ t ] [ [ + ] cached-effect (( a b -- c )) effect= ] unit-test
+[ t ] [ 5 [ + ] curry cached-effect (( a -- c )) effect= ] unit-test
+[ t ] [ 5 [ ] curry cached-effect (( -- c )) effect= ] unit-test
+[ t ] [ [ dup ] [ drop ] compose cached-effect (( a -- b )) effect= ] unit-test
+[ t ] [ [ drop ] [ dup ] compose cached-effect (( a b -- c d )) effect= ] unit-test
+[ t ] [ [ 2drop ] [ dup ] compose cached-effect (( a b c -- d e )) effect= ] unit-test
+[ t ] [ [ 1 2 3 ] [ 2drop ] compose cached-effect (( -- a )) effect= ] unit-test
+[ t ] [ [ 1 2 ] [ 3drop ] compose cached-effect (( a -- )) effect= ] unit-test
+
+: optimized-quot ( quot -- quot' )
+ build-tree optimize-tree nodes>quot ;
+
+: compiled-call2 ( a quot: ( a -- b ) -- b )
+ call( a -- b ) ;
+
+: compiled-execute2 ( a b word: ( a b -- c ) -- c )
+ execute( a b -- c ) ;
+
+[ [ 3 ] ] [ [ 1 2 \ + execute( a b -- c ) ] optimized-quot ] unit-test
+[ [ 3 ] ] [ [ 1 2 [ + ] call( a b -- c ) ] optimized-quot ] unit-test
+[ [ 3 ] ] [ [ 1 2 '[ _ + ] call( a -- b ) ] optimized-quot ] unit-test
+[ [ 3 ] ] [ [ 1 2 '[ _ ] [ + ] compose call( a -- b ) ] optimized-quot ] unit-test
+
+[ 1 2 { [ + ] } first compiled-call2 ] must-fail
+[ 3 ] [ 1 2 { + } first compiled-execute2 ] unit-test
+[ 3 ] [ 1 2 '[ _ + ] compiled-call2 ] unit-test
+[ 3 ] [ 1 2 '[ _ ] [ + ] compose compiled-call2 ] unit-test
+[ 3 ] [ 1 2 \ + compiled-execute2 ] unit-test
+
+[ 3 ] [ 1 2 { [ + ] } first call( a b -- c ) ] unit-test
+[ 3 ] [ 1 2 { + } first execute( a b -- c ) ] unit-test
+[ 3 ] [ 1 2 '[ _ + ] call( a -- b ) ] unit-test
+[ 3 ] [ 1 2 '[ _ ] [ + ] compose call( a -- b ) ] unit-test
+
+[ t ] [ [ 2 '[ _ ] [ + ] compose ] final-info first infer-value (( object -- object )) effect= ] unit-test
+[ t ] [ [ 2 '[ _ ] 1 '[ _ + ] compose ] final-info first infer-value (( -- object )) effect= ] unit-test
+[ t ] [ [ 2 '[ _ + ] ] final-info first infer-value (( object -- object )) effect= ] unit-test
+[ f ] [ [ [ [ ] [ 1 ] if ] ] final-info first infer-value ] unit-test
+[ f ] [ [ [ 1 ] '[ @ ] ] final-info first infer-value ] unit-test
+[ f ] [ [ dup drop ] final-info first infer-value ] unit-test
+
+! This should not hang
+[ ] [ [ [ dup call( quot -- ) ] dup call( quot -- ) ] final-info drop ] unit-test
+[ ] [ [ [ dup curry call( quot -- ) ] dup curry call( quot -- ) ] final-info drop ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov, Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators combinators.private effects fry
+kernel kernel.private make sequences continuations quotations
+words math stack-checker stack-checker.transforms
+compiler.tree.propagation.info
+compiler.tree.propagation.inlining ;
+IN: compiler.tree.propagation.call-effect
+
+! call( and execute( have complex expansions.
+
+! call( uses the following strategy:
+! - Inline caching. If the quotation is the same as last time, just call it unsafely
+! - Effect inference. Infer quotation's effect, caching it in the cached-effect slot,
+! and compare it with declaration. If matches, call it unsafely.
+! - Fallback. If the above doesn't work, call it and compare the datastack before
+! and after to make sure it didn't mess anything up.
+
+! execute( uses a similar strategy.
+
+TUPLE: inline-cache value ;
+
+: cache-hit? ( word/quot ic -- ? )
+ [ value>> eq? ] [ value>> ] bi and ; inline
+
+SINGLETON: +unknown+
+
+GENERIC: cached-effect ( quot -- effect )
+
+M: object cached-effect drop +unknown+ ;
+
+GENERIC: curry-effect ( effect -- effect' )
+
+M: +unknown+ curry-effect ;
+
+M: effect curry-effect
+ [ in>> length ] [ out>> length ] [ terminated?>> ] tri
+ pick 0 = [ [ 1 + ] dip ] [ [ 1 - ] 2dip ] if
+ effect boa ;
+
+M: curry cached-effect
+ quot>> cached-effect curry-effect ;
+
+: compose-effects* ( effect1 effect2 -- effect' )
+ {
+ { [ 2dup [ effect? ] both? ] [ compose-effects ] }
+ { [ 2dup [ +unknown+ eq? ] either? ] [ 2drop +unknown+ ] }
+ } cond ;
+
+M: compose cached-effect
+ [ first>> ] [ second>> ] bi [ cached-effect ] bi@ compose-effects* ;
+
+M: quotation cached-effect
+ dup cached-effect>>
+ [ ] [
+ [ [ infer ] [ 2drop +unknown+ ] recover dup ] keep
+ (>>cached-effect)
+ ] ?if ;
+
+: call-effect-unsafe? ( quot effect -- ? )
+ [ cached-effect ] dip
+ over +unknown+ eq?
+ [ 2drop f ] [ effect<= ] if ; inline
+
+: (call-effect-slow>quot) ( in out effect -- quot )
+ [
+ [ [ datastack ] dip dip ] %
+ [ [ , ] bi@ \ check-datastack , ] dip
+ '[ _ wrong-values ] , \ unless ,
+ ] [ ] make ;
+
+: call-effect-slow>quot ( effect -- quot )
+ [ in>> length ] [ out>> length ] [ ] tri
+ [ (call-effect-slow>quot) ] keep add-effect-input
+ [ call-effect-unsafe ] 2curry ;
+
+: call-effect-slow ( quot effect -- ) drop call ;
+
+\ call-effect-slow [ call-effect-slow>quot ] 1 define-transform
+
+\ call-effect-slow t "no-compile" set-word-prop
+
+: call-effect-fast ( quot effect inline-cache -- )
+ 2over call-effect-unsafe?
+ [ [ nip (>>value) ] [ drop call-effect-unsafe ] 3bi ]
+ [ drop call-effect-slow ]
+ if ; inline
+
+: call-effect-ic ( quot effect inline-cache -- )
+ 3dup nip cache-hit?
+ [ drop call-effect-unsafe ]
+ [ call-effect-fast ]
+ if ; inline
+
+: call-effect>quot ( effect -- quot )
+ inline-cache new '[ drop _ _ call-effect-ic ] ;
+
+: execute-effect-slow ( word effect -- )
+ [ '[ _ execute ] ] dip call-effect-slow ; inline
+
+: execute-effect-unsafe? ( word effect -- ? )
+ over optimized? [ [ stack-effect ] dip effect<= ] [ 2drop f ] if ; inline
+
+: execute-effect-fast ( word effect inline-cache -- )
+ 2over execute-effect-unsafe?
+ [ [ nip (>>value) ] [ drop execute-effect-unsafe ] 3bi ]
+ [ drop execute-effect-slow ]
+ if ; inline
+
+: execute-effect-ic ( word effect inline-cache -- )
+ 3dup nip cache-hit?
+ [ drop execute-effect-unsafe ]
+ [ execute-effect-fast ]
+ if ; inline
+
+: execute-effect>quot ( effect -- quot )
+ inline-cache new '[ drop _ _ execute-effect-ic ] ;
+
+: last2 ( seq -- penultimate ultimate )
+ 2 tail* first2 ;
+
+: top-two ( #call -- effect value )
+ in-d>> last2 [ value-info ] bi@
+ literal>> swap ;
+
+ERROR: uninferable ;
+
+: remove-effect-input ( effect -- effect' )
+ (( -- object )) swap compose-effects ;
+
+: (infer-value) ( value-info -- effect )
+ dup class>> {
+ { \ quotation [
+ literal>> [ uninferable ] unless*
+ dup already-inlined? [ uninferable ] when
+ cached-effect dup +unknown+ = [ uninferable ] when
+ ] }
+ { \ curry [
+ slots>> third (infer-value)
+ remove-effect-input
+ ] }
+ { \ compose [
+ slots>> last2 [ (infer-value) ] bi@
+ compose-effects
+ ] }
+ [ uninferable ]
+ } case ;
+
+: infer-value ( value-info -- effect/f )
+ [ (infer-value) ]
+ [ dup uninferable? [ 2drop f ] [ rethrow ] if ]
+ recover ;
+
+: (value>quot) ( value-info -- quot )
+ dup class>> {
+ { \ quotation [ literal>> dup add-to-history '[ drop @ ] ] }
+ { \ curry [
+ slots>> third (value>quot)
+ '[ [ obj>> ] [ quot>> @ ] bi ]
+ ] }
+ { \ compose [
+ slots>> last2 [ (value>quot) ] bi@
+ '[ [ first>> @ ] [ second>> @ ] bi ]
+ ] }
+ } case ;
+
+: value>quot ( value-info -- quot: ( code effect -- ) )
+ (value>quot) '[ drop @ ] ;
+
+: call-inlining ( #call -- quot/f )
+ top-two dup infer-value [
+ pick effect<=
+ [ nip value>quot ]
+ [ drop call-effect>quot ] if
+ ] [ drop call-effect>quot ] if* ;
+
+\ call-effect [ call-inlining ] "custom-inlining" set-word-prop
+
+: execute-inlining ( #call -- quot/f )
+ top-two >literal< [
+ 2dup swap execute-effect-unsafe?
+ [ nip '[ 2drop _ execute ] ]
+ [ drop execute-effect>quot ] if
+ ] [ drop execute-effect>quot ] if ;
+
+\ execute-effect [ execute-inlining ] "custom-inlining" set-word-prop
-IN: compiler.tree.propagation.copy.tests
USING: compiler.tree.propagation.copy tools.test namespaces kernel
assocs ;
+IN: compiler.tree.propagation.copy.tests
H{ } clone copies set
stack-checker.branches
compiler.tree
compiler.tree.def-use
-compiler.tree.combinators ;
+compiler.tree.combinators
+compiler.utilities ;
IN: compiler.tree.propagation.copy
! Two values are copy-equivalent if they are always identical
! Mapping from values to their canonical leader
SYMBOL: copies
-:: compress-path ( source assoc -- destination )
- [let | destination [ source assoc at ] |
- source destination = [ source ] [
- [let | destination' [ destination assoc compress-path ] |
- destination' destination = [
- destination' source assoc set-at
- ] unless
- destination'
- ]
- ] if
- ] ;
-
: resolve-copy ( copy -- val ) copies get compress-path ;
: is-copy-of ( val copy -- ) copies get set-at ;
[ t ] [
null-info 3 <literal-info> value-info<=
] unit-test
+
+[ t t ] [
+ f <literal-info>
+ fixnum 0 40 [a,b] <class/interval-info>
+ value-info-union
+ \ f class-not <class-info>
+ value-info-intersect
+ [ class>> fixnum class= ]
+ [ interval>> 0 40 [a,b] = ] bi
+] unit-test
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs classes classes.algebra classes.tuple
-classes.tuple.private kernel accessors math math.intervals
-namespaces sequences words combinators
-arrays compiler.tree.propagation.copy ;
+classes.tuple.private kernel accessors math math.intervals namespaces
+sequences sequences.private words combinators memoize
+combinators.short-circuit byte-arrays strings arrays layouts
+cpu.architecture compiler.tree.propagation.copy ;
IN: compiler.tree.propagation.info
: false-class? ( class -- ? ) \ f class<= ;
CONSTANT: object-info T{ value-info f object full-interval }
-: class-interval ( class -- interval )
- dup real class<=
- [ "interval" word-prop [-inf,inf] or ] [ drop f ] if ;
-
: interval>literal ( class interval -- literal literal? )
#! If interval has zero length and the class is sufficiently
#! precise, we can turn it into a literal
[ read-only>> [ <literal-info> ] [ drop f ] if ] 2map
f prefix ;
+UNION: fixed-length array byte-array string ;
+
: init-literal-info ( info -- info )
+ empty-interval >>interval
dup literal>> class >>class
- dup literal>> dup real? [ [a,a] >>interval ] [
- [ [-inf,inf] >>interval ] dip
- dup tuple? [ tuple-slot-infos >>slots ] [ drop ] if
- ] if ; inline
+ dup literal>> {
+ { [ dup real? ] [ [a,a] >>interval ] }
+ { [ dup tuple? ] [ tuple-slot-infos >>slots ] }
+ { [ dup fixed-length? ] [ length <literal-info> >>length ] }
+ [ drop ]
+ } cond ; inline
+
+: empty-set? ( info -- ? )
+ {
+ [ class>> null-class? ]
+ [ [ interval>> empty-interval eq? ] [ class>> real class<= ] bi and ]
+ } 1|| ;
+
+: min-value ( class -- n )
+ {
+ { fixnum [ most-negative-fixnum ] }
+ { array-capacity [ 0 ] }
+ [ drop -1/0. ]
+ } case ;
+
+: max-value ( class -- n )
+ {
+ { fixnum [ most-positive-fixnum ] }
+ { array-capacity [ max-array-capacity ] }
+ [ drop 1/0. ]
+ } case ;
+
+: class-interval ( class -- i )
+ {
+ { fixnum [ fixnum-interval ] }
+ { array-capacity [ array-capacity-interval ] }
+ [ drop full-interval ]
+ } case ;
+
+: wrap-interval ( interval class -- interval' )
+ {
+ { [ over empty-interval eq? ] [ drop ] }
+ { [ over full-interval eq? ] [ nip class-interval ] }
+ { [ 2dup class-interval interval-subset? not ] [ nip class-interval ] }
+ [ drop ]
+ } cond ;
+
+: init-interval ( info -- info )
+ dup [ interval>> full-interval or ] [ class>> ] bi wrap-interval >>interval
+ dup class>> integer class<= [ [ integral-closure ] change-interval ] when ; inline
: init-value-info ( info -- info )
dup literal?>> [
init-literal-info
] [
- dup [ class>> null-class? ] [ interval>> empty-interval eq? ] bi or [
+ dup empty-set? [
null >>class
empty-interval >>interval
] [
- [ [-inf,inf] or ] change-interval
- dup class>> integer class<= [ [ integral-closure ] change-interval ] when
+ init-interval
dup [ class>> ] [ interval>> ] bi interval>literal
[ >>literal ] [ >>literal? ] bi*
] if
init-value-info ; foldable
: <class-info> ( class -- info )
- dup word? [ dup "interval" word-prop ] [ f ] if [-inf,inf] or
- <class/interval-info> ; foldable
+ f <class/interval-info> ; foldable
: <interval-info> ( interval -- info )
<value-info>
dup in-d>> last node-value-info
literal>> first immutable-tuple-class?
] [ drop f ] if ;
+
+: value-info-small-fixnum? ( value-info -- ? )
+ literal>> {
+ { [ dup fixnum? ] [ tag-fixnum small-enough? ] }
+ [ drop f ]
+ } cond ;
+
+: value-info-small-tagged? ( value-info -- ? )
+ dup literal?>> [
+ literal>> {
+ { [ dup fixnum? ] [ tag-fixnum small-enough? ] }
+ { [ dup not ] [ drop t ] }
+ [ drop f ]
+ } cond
+ ] [ drop f ] if ;
USING: accessors kernel arrays sequences math math.order
math.partial-dispatch generic generic.standard generic.single generic.math
classes.algebra classes.union sets quotations assocs combinators
-words namespaces continuations classes fry combinators.smart hints
-locals
+combinators.short-circuit words namespaces continuations classes
+fry hints locals
compiler.tree
compiler.tree.builder
compiler.tree.recursive
compiler.tree.propagation.nodes ;
IN: compiler.tree.propagation.inlining
-! We count nodes up-front; if there are relatively few nodes,
-! we are more eager to inline
-SYMBOL: node-count
-
-: count-nodes ( nodes -- n )
- 0 swap [ drop 1+ ] each-node ;
-
-: compute-node-count ( nodes -- ) count-nodes node-count set ;
-
-! We try not to inline the same word too many times, to avoid
-! combinatorial explosion
-SYMBOL: inlining-count
-
! Splicing nodes
: splicing-call ( #call word -- nodes )
[ [ in-d>> ] [ out-d>> ] bi ] dip #call 1array ;
+: open-code-#call ( #call word/quot -- nodes/f )
+ [ [ in-d>> ] [ out-d>> ] bi ] dip build-sub-tree ;
+
: splicing-body ( #call quot/word -- nodes/f )
- build-sub-tree dup [ analyze-recursive normalize ] when ;
+ open-code-#call dup [ analyze-recursive normalize ] when ;
! Dispatch elimination
: undo-inlining ( #call -- ? )
dupd inlining-math-partial eliminate-dispatch ;
! Method body inlining
-SYMBOL: recursive-calls
-DEFER: (flat-length)
-
-: word-flat-length ( word -- n )
- {
- ! special-case
- { [ dup { dip 2dip 3dip } memq? ] [ drop 1 ] }
- ! not inline
- { [ dup inline? not ] [ drop 1 ] }
- ! recursive and inline
- { [ dup recursive-calls get key? ] [ drop 10 ] }
- ! inline
- [ [ recursive-calls get conjoin ] [ def>> (flat-length) ] bi ]
- } cond ;
-
-: (flat-length) ( seq -- n )
- [
- {
- { [ dup quotation? ] [ (flat-length) 2 + ] }
- { [ dup array? ] [ (flat-length) ] }
- { [ dup word? ] [ word-flat-length ] }
- [ drop 0 ]
- } cond
- ] sigma ;
-
-: flat-length ( word -- n )
- H{ } clone recursive-calls [
- [ recursive-calls get conjoin ]
- [ def>> (flat-length) 5 /i ]
- bi
- ] with-variable ;
-
-: classes-known? ( #call -- ? )
- in-d>> [
- value-info class>>
- [ class-types length 1 = ]
- [ union-class? not ]
- bi and
- ] any? ;
-
-: node-count-bias ( -- n )
- 45 node-count get [-] 8 /i ;
-
-: body-length-bias ( word -- n )
- [ flat-length ] [ inlining-count get at 0 or ] bi
- over 2 <= [ drop ] [ 2/ 1+ * ] if 24 swap [-] 4 /i ;
-
-: inlining-rank ( #call word -- n )
- [
- [ classes-known? 2 0 ? ]
- [
- [ body-length-bias ]
- [ "specializer" word-prop 1 0 ? ]
- [ method-body? 1 0 ? ]
- tri
- node-count-bias
- loop-nesting get 0 or 2 *
- ] bi*
- ] sum-outputs ;
-
-: should-inline? ( #call word -- ? )
- dup inline? [ 2drop t ] [ inlining-rank 5 >= ] if ;
-
SYMBOL: history
-: remember-inlining ( word -- )
- [ inlining-count get inc-at ]
- [ history [ swap suffix ] change ]
- bi ;
+: already-inlined? ( obj -- ? ) history get memq? ;
+
+: add-to-history ( obj -- ) history [ swap suffix ] change ;
:: inline-word ( #call word -- ? )
- word history get memq? [ f ] [
+ word already-inlined? [ f ] [
#call word splicing-body [
[
- word remember-inlining
- [ ] [ count-nodes ] [ (propagate) ] tri
+ word add-to-history
+ dup (propagate)
] with-scope
- [ #call (>>body) ] [ node-count +@ ] bi* t
+ #call (>>body) t
] [ f ] if*
] if ;
-: inline-method-body ( #call word -- ? )
- 2dup should-inline? [ inline-word ] [ 2drop f ] if ;
-
: always-inline-word? ( word -- ? )
{ curry compose } memq? ;
: never-inline-word? ( word -- ? )
- [ deferred? ] [ "default" word-prop ] [ \ call eq? ] tri or or ;
+ { [ deferred? ] [ "default" word-prop ] [ \ call eq? ] } 1|| ;
: custom-inlining? ( word -- ? )
"custom-inlining" word-prop ;
{ [ dup always-inline-word? ] [ inline-word ] }
{ [ dup standard-generic? ] [ inline-standard-method ] }
{ [ dup math-generic? ] [ inline-math-method ] }
- { [ dup method-body? ] [ inline-method-body ] }
+ { [ dup inline? ] [ inline-word ] }
[ 2drop f ]
} cond ;
! See http://factorcode.org/license.txt for BSD license.
USING: kernel effects accessors math math.private
math.integers.private math.partial-dispatch math.intervals
-math.parser math.order layouts words sequences sequences.private
-arrays assocs classes classes.algebra combinators generic.math
-splitting fry locals classes.tuple alien.accessors
-classes.tuple.private slots.private definitions strings.private
-vectors hashtables generic
+math.parser math.order math.functions math.libm layouts words
+sequences sequences.private arrays assocs classes
+classes.algebra combinators generic.math splitting fry locals
+classes.tuple alien.accessors classes.tuple.private
+slots.private definitions strings.private vectors hashtables
+generic quotations
stack-checker.state
compiler.tree.comparisons
compiler.tree.propagation.info
compiler.tree.propagation.nodes
compiler.tree.propagation.slots
compiler.tree.propagation.simple
-compiler.tree.propagation.constraints ;
+compiler.tree.propagation.constraints
+compiler.tree.propagation.call-effect
+compiler.tree.propagation.transforms ;
IN: compiler.tree.propagation.known-words
-\ fixnum
-most-negative-fixnum most-positive-fixnum [a,b]
-"interval" set-word-prop
-
-\ array-capacity
-0 max-array-capacity [a,b]
-"interval" set-word-prop
-
{ + - * / }
[ { number number } "input-classes" set-word-prop ] each
\ bitnot { integer } "input-classes" set-word-prop
-: ?change-interval ( info quot -- quot' )
- over interval>> [ [ clone ] dip change-interval ] [ 2drop ] if ; inline
+: real-op ( info quot -- quot' )
+ [
+ dup class>> real classes-intersect?
+ [ clone ] [ drop real <class-info> ] if
+ ] dip
+ change-interval ; inline
{ bitnot fixnum-bitnot bignum-bitnot } [
- [ [ interval-bitnot ] ?change-interval ] "outputs" set-word-prop
+ [ [ interval-bitnot ] real-op ] "outputs" set-word-prop
] each
-\ abs [ [ interval-abs ] ?change-interval ] "outputs" set-word-prop
+\ abs [ [ interval-abs ] real-op ] "outputs" set-word-prop
+
+\ absq [ [ interval-absq ] real-op ] "outputs" set-word-prop
: math-closure ( class -- newclass )
{ fixnum bignum integer rational float real number object }
[ class<= ] with find nip ;
-: fits? ( interval class -- ? )
- "interval" word-prop interval-subset? ;
+: fits-in-fixnum? ( interval -- ? )
+ fixnum-interval interval-subset? ;
: binary-op-class ( info1 info2 -- newclass )
[ class>> ] bi@
[ [ interval>> ] bi@ ] dip call ; inline
: won't-overflow? ( class interval -- ? )
- [ fixnum class<= ] [ fixnum fits? ] bi* and ;
+ [ fixnum class<= ] [ fits-in-fixnum? ] bi* and ;
: may-overflow ( class interval -- class' interval' )
over null-class? [
[ object-info ] [ f <literal-info> ] if ;
: info-intervals-intersect? ( info1 info2 -- ? )
- [ interval>> ] bi@ intervals-intersect? ;
+ 2dup [ class>> real class<= ] both?
+ [ [ interval>> ] bi@ intervals-intersect? ] [ 2drop t ] if ;
{ number= bignum= float= } [
[
{ >integer integer }
} [
- '[
- _
- [ nip ] [
- [ interval>> ] [ class-interval ] bi*
- interval-intersect
- ] 2bi
- <class/interval-info>
- ] "outputs" set-word-prop
+ '[ _ swap interval>> <class/interval-info> ] "outputs" set-word-prop
] assoc-each
-: rem-custom-inlining ( #call -- quot/f )
- second value-info literal>> dup integer?
- [ power-of-2? [ 1- bitand ] f ? ] [ drop f ] if ;
-
-{
- mod-integer-integer
- mod-integer-fixnum
- mod-fixnum-integer
- fixnum-mod
-} [
- [
- in-d>> dup first value-info interval>> [0,inf] interval-subset?
- [ rem-custom-inlining ] [ drop f ] if
- ] "custom-inlining" set-word-prop
-] each
-
-\ rem [
- in-d>> rem-custom-inlining
-] "custom-inlining" set-word-prop
-
-{
- bitand-integer-integer
- bitand-integer-fixnum
- bitand-fixnum-integer
-} [
- [
- in-d>> second value-info >literal< [
- 0 most-positive-fixnum between?
- [ [ >fixnum ] bi@ fixnum-bitand ] f ?
- ] when
- ] "custom-inlining" set-word-prop
-] each
-
{ numerator denominator }
[ [ drop integer <class-info> ] "outputs" set-word-prop ] each
dup name>> {
{
[ "alien-signed-" ?head ]
- [ string>number 8 * 1- 2^ dup neg swap 1- [a,b] ]
+ [ string>number 8 * 1 - 2^ dup neg swap 1 - [a,b] ]
}
{
[ "alien-unsigned-" ?head ]
- [ string>number 8 * 2^ 1- 0 swap [a,b] ]
+ [ string>number 8 * 2^ 1 - 0 swap [a,b] ]
}
} cond
- [ fixnum fits? fixnum integer ? ] keep <class/interval-info>
+ [ fits-in-fixnum? fixnum integer ? ] keep <class/interval-info>
'[ 2drop _ ] "outputs" set-word-prop
] each
"outputs" set-word-prop
] each
-! Generate more efficient code for common idiom
-\ clone [
- in-d>> first value-info literal>> {
- { V{ } [ [ drop { } 0 vector boa ] ] }
- { H{ } [ [ drop 0 <hashtable> ] ] }
- [ drop f ]
- } case
-] "custom-inlining" set-word-prop
-
\ slot [
dup literal?>>
[ literal>> swap value-info-slot ] [ 2drop object-info ] if
] [ 2drop object-info ] if
] "outputs" set-word-prop
-\ instance? [
- in-d>> second value-info literal>> dup class?
- [ "predicate" word-prop '[ drop @ ] ] [ drop f ] if
-] "custom-inlining" set-word-prop
-
-\ equal? [
- ! If first input has a known type and second input is an
- ! object, we convert this to [ swap equal? ].
- in-d>> first2 value-info class>> object class= [
- value-info class>> \ equal? specific-method
- [ swap equal? ] f ?
- ] [ drop f ] if
-] "custom-inlining" set-word-prop
+{ facos fasin fatan fatan2 fcos fsin ftan fcosh fsinh ftanh fexp
+flog fpow fsqrt facosh fasinh fatanh } [
+ { float } "default-output-classes" set-word-prop
+] each
compiler.tree.debugger compiler.tree.checker
slots.private words hashtables classes assocs locals
specialized-arrays.double system sorting math.libm
-math.intervals quotations ;
+math.intervals quotations effects ;
IN: compiler.tree.propagation.tests
[ V{ } ] [ [ ] final-classes ] unit-test
[ bignum ] [ [ { bignum bignum } declare bitxor ] final-math-class ] unit-test
+[ bignum ] [ [ { integer } declare 123 >bignum bitand ] final-math-class ] unit-test
+
[ float ] [ [ { float float } declare mod ] final-math-class ] unit-test
-[ V{ integer } ] [ [ 255 bitand ] final-classes ] unit-test
+[ V{ fixnum } ] [ [ 255 bitand ] final-classes ] unit-test
-[ V{ integer } ] [
+[ V{ fixnum } ] [
[ [ 255 bitand ] [ 65535 bitand ] bi + ] final-classes
] unit-test
] final-literals
] unit-test
+[ V{ t } ] [ [ 40 mod 40 < ] final-literals ] unit-test
+
+[ V{ f } ] [ [ 40 mod 0 >= ] final-literals ] unit-test
+
+[ V{ t } ] [ [ 40 rem 0 >= ] final-literals ] unit-test
+
+[ V{ t } ] [ [ abs 40 mod 0 >= ] final-literals ] unit-test
+
+[ t ] [ [ abs ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ absq ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ { float } declare abs ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ { float } declare absq ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ { complex } declare abs ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ { complex } declare absq ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ [ - absq ] [ + ] 2map-reduce ] final-info first interval>> [0,inf] = ] unit-test
+
+[ t ] [ [ { double-array double-array } declare [ - absq ] [ + ] 2map-reduce ] final-info first interval>> [0,inf] = ] unit-test
+
[ V{ string } ] [
[ dup string? not [ "Oops" throw ] [ ] if ] final-classes
] unit-test
] unit-test
[ V{ fixnum } ] [
- [ >fixnum dup 100 < [ 1+ ] [ "Oops" throw ] if ] final-classes
+ [ >fixnum dup 100 < [ 1 + ] [ "Oops" throw ] if ] final-classes
] unit-test
[ V{ -1 } ] [
- [ 0 dup 100 < not [ 1+ ] [ 1- ] if ] final-literals
+ [ 0 dup 100 < not [ 1 + ] [ 1 - ] if ] final-literals
] unit-test
[ V{ 2 } ] [
[ { fixnum } declare dup 10 eq? [ "A" throw ] unless ] final-literals
] unit-test
+[ V{ 3 } ] [ [ [ { 1 2 3 } ] [ { 4 5 6 } ] if length ] final-literals ] unit-test
+
+[ V{ 3 } ] [ [ [ B{ 1 2 3 } ] [ B{ 4 5 6 } ] if length ] final-literals ] unit-test
+
+[ V{ 3 } ] [ [ [ "yay" ] [ "hah" ] if length ] final-literals ] unit-test
+
+[ V{ 3 } ] [ [ 3 <byte-array> length ] final-literals ] unit-test
+
+[ V{ 3 } ] [ [ 3 f <string> length ] final-literals ] unit-test
+
! Slot propagation
TUPLE: prop-test-tuple { x integer } ;
] final-classes
] unit-test
+[ V{ f { } } ] [
+ [
+ T{ mixed-mutable-immutable f 3 { } }
+ [ x>> ] [ y>> ] bi
+ ] final-literals
+] unit-test
+
! Recursive propagation
: recursive-test-1 ( a -- b ) recursive-test-1 ; inline recursive
] unit-test
: recursive-test-4 ( i n -- )
- 2dup < [ [ 1+ ] dip recursive-test-4 ] [ 2drop ] if ; inline recursive
+ 2dup < [ [ 1 + ] dip recursive-test-4 ] [ 2drop ] if ; inline recursive
[ ] [ [ recursive-test-4 ] final-info drop ] unit-test
[ V{ integer } ] [ [ { fixnum } declare recursive-test-6 ] final-classes ] unit-test
: recursive-test-7 ( a -- b )
- dup 10 < [ 1+ recursive-test-7 ] when ; inline recursive
+ dup 10 < [ 1 + recursive-test-7 ] when ; inline recursive
[ V{ fixnum } ] [ [ 0 recursive-test-7 ] final-classes ] unit-test
] unit-test
GENERIC: iterate ( obj -- next-obj ? )
-M: fixnum iterate f ;
-M: array iterate first t ;
+M: fixnum iterate f ; inline
+M: array iterate first t ; inline
: dead-loop ( obj -- final-obj )
iterate [ dead-loop ] when ; inline recursive
] unit-test
GENERIC: bad-generic ( a -- b )
-M: fixnum bad-generic 1 fixnum+fast ;
+M: fixnum bad-generic 1 fixnum+fast ; inline
: bad-behavior ( -- b ) 4 bad-generic ; inline recursive
[ V{ fixnum } ] [ [ bad-behavior ] final-classes ] unit-test
[ { integer } declare 127 bitand ] final-info first interval>>
] unit-test
+[ V{ t } ] [
+ [ [ 123 bitand ] [ drop f ] if dup [ 0 >= ] [ not ] if ] final-literals
+] unit-test
+
[ V{ bignum } ] [
- [ { bignum } declare dup 1- bitxor ] final-classes
+ [ { bignum } declare dup 1 - bitxor ] final-classes
] unit-test
[ V{ bignum integer } ] [
[ { bignum integer } declare [ shift ] keep ] final-classes
] unit-test
+[ V{ fixnum } ] [ [ >fixnum 15 bitand 1 swap shift ] final-classes ] unit-test
+
+[ V{ fixnum } ] [ [ 15 bitand 1 swap shift ] final-classes ] unit-test
+
[ V{ fixnum } ] [
[ { fixnum } declare log2 ] final-classes
] unit-test
TUPLE: littledan-1 { a read-only } ;
-: (littledan-1-test) ( a -- ) a>> 1+ littledan-1 boa (littledan-1-test) ; inline recursive
+: (littledan-1-test) ( a -- ) a>> 1 + littledan-1 boa (littledan-1-test) ; inline recursive
: littledan-1-test ( -- ) 0 littledan-1 boa (littledan-1-test) ; inline
[ ] [ [ littledan-2-test ] final-classes drop ] unit-test
: (littledan-3-test) ( x -- )
- length 1+ f <array> (littledan-3-test) ; inline recursive
+ length 1 + f <array> (littledan-3-test) ; inline recursive
: littledan-3-test ( -- )
0 f <array> (littledan-3-test) ; inline
[ V{ 0 } ] [ [ { } length ] final-literals ] unit-test
-[ V{ 1 } ] [ [ { } length 1+ f <array> length ] final-literals ] unit-test
+[ V{ 1 } ] [ [ { } length 1 + f <array> length ] final-literals ] unit-test
+
+! generalize-counter is not tight enough
+[ V{ fixnum } ] [ [ 0 10 [ 1 + >fixnum ] times ] final-classes ] unit-test
+
+[ V{ fixnum } ] [ [ 0 10 [ 1 + >fixnum ] times 0 + ] final-classes ] unit-test
+
+! Coercions need to update intervals
+[ V{ f } ] [ [ 1 2 ? 100 shift >fixnum 1 = ] final-literals ] unit-test
+
+[ V{ t } ] [ [ >fixnum 1 + >fixnum most-positive-fixnum <= ] final-literals ] unit-test
+
+[ V{ t } ] [ [ >fixnum 1 + >fixnum most-negative-fixnum >= ] final-literals ] unit-test
+
+[ V{ f } ] [ [ >fixnum 1 + >fixnum most-negative-fixnum > ] final-literals ] unit-test
! Mutable tuples with circularity should not cause problems
TUPLE: circle me ;
! Joe found an oversight
[ V{ integer } ] [ [ >integer ] final-classes ] unit-test
+
+TUPLE: foo bar ;
+
+[ t ] [ [ foo new ] { new } inlined? ] unit-test
+
+GENERIC: whatever ( x -- y )
+M: number whatever drop foo ; inline
+
+[ t ] [ [ 1 whatever new ] { new } inlined? ] unit-test
+
+: that-thing ( -- class ) foo ;
+
+[ f ] [ [ that-thing new ] { new } inlined? ] unit-test
+
+GENERIC: whatever2 ( x -- y )
+M: number whatever2 drop H{ { 1 1 } { 2 2 } { 3 3 } { 4 4 } { 5 6 } } ; inline
+M: f whatever2 ; inline
+
+[ t ] [ [ 1 whatever2 at ] { at* hashcode* } inlined? ] unit-test
+[ f ] [ [ whatever2 at ] { at* hashcode* } inlined? ] unit-test
+
+[ t ] [ [ { 1 2 3 } member? ] { member? } inlined? ] unit-test
+[ f ] [ [ { 1 2 3 } swap member? ] { member? } inlined? ] unit-test
+
+[ t ] [ [ { 1 2 3 } memq? ] { memq? } inlined? ] unit-test
+[ f ] [ [ { 1 2 3 } swap memq? ] { memq? } inlined? ] unit-test
+
+[ t ] [ [ V{ } clone ] { clone (clone) } inlined? ] unit-test
+[ f ] [ [ { } clone ] { clone (clone) } inlined? ] unit-test
+
+[ f ] [ [ instance? ] { instance? } inlined? ] unit-test
+[ f ] [ [ 5 instance? ] { instance? } inlined? ] unit-test
+[ t ] [ [ array instance? ] { instance? } inlined? ] unit-test
+
+[ t ] [ [ (( a b c -- c b a )) shuffle ] { shuffle } inlined? ] unit-test
+[ f ] [ [ { 1 2 3 } swap shuffle ] { shuffle } inlined? ] unit-test
H{ } clone copies set
H{ } clone 1array value-infos set
H{ } clone 1array constraints set
- H{ } clone inlining-count set
- dup compute-node-count
dup (propagate) ;
-IN: compiler.tree.propagation.recursive.tests
USING: tools.test compiler.tree.propagation.recursive
-math.intervals kernel ;
+math.intervals kernel math literals layouts ;
+IN: compiler.tree.propagation.recursive.tests
[ T{ interval f { 0 t } { 1/0. t } } ] [
T{ interval f { 1 t } { 1 t } }
- T{ interval f { 0 t } { 0 t } } generalize-counter-interval
+ T{ interval f { 0 t } { 0 t } }
+ integer generalize-counter-interval
+] unit-test
+
+[ T{ interval f { 0 t } { $[ most-positive-fixnum ] t } } ] [
+ T{ interval f { 1 t } { 1 t } }
+ T{ interval f { 0 t } { 0 t } }
+ fixnum generalize-counter-interval
] unit-test
[ T{ interval f { -1/0. t } { 10 t } } ] [
T{ interval f { -1 t } { -1 t } }
- T{ interval f { 10 t } { 10 t } } generalize-counter-interval
+ T{ interval f { 10 t } { 10 t } }
+ integer generalize-counter-interval
+] unit-test
+
+[ T{ interval f { $[ most-negative-fixnum ] t } { 10 t } } ] [
+ T{ interval f { -1 t } { -1 t } }
+ T{ interval f { 10 t } { 10 t } }
+ fixnum generalize-counter-interval
] unit-test
[ t ] [
T{ interval f { 1 t } { 268435455 t } }
T{ interval f { -268435456 t } { 268435455 t } } tuck
- generalize-counter-interval =
+ integer generalize-counter-interval =
+] unit-test
+
+[ t ] [
+ T{ interval f { 1 t } { 268435455 t } }
+ T{ interval f { -268435456 t } { 268435455 t } } tuck
+ fixnum generalize-counter-interval =
+] unit-test
+
+[ full-interval ] [
+ T{ interval f { -5 t } { 3 t } }
+ T{ interval f { 2 t } { 11 t } }
+ integer generalize-counter-interval
+] unit-test
+
+[ $[ fixnum-interval ] ] [
+ T{ interval f { -5 t } { 3 t } }
+ T{ interval f { 2 t } { 11 t } }
+ fixnum generalize-counter-interval
] unit-test
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel sequences accessors arrays fry math.intervals
-combinators namespaces
+USING: kernel sequences accessors arrays fry math math.intervals
+layouts combinators namespaces locals
stack-checker.inlining
compiler.tree
compiler.tree.combinators
in-d>> [ value-info ] map ;
: recursive-stacks ( #enter-recursive -- stacks initial )
- [ label>> calls>> [ node-input-infos ] map flip ]
+ [ label>> calls>> [ node>> node-input-infos ] map flip ]
[ latest-input-infos ] bi ;
-: generalize-counter-interval ( interval initial-interval -- interval' )
+:: generalize-counter-interval ( interval initial-interval class -- interval' )
{
- { [ 2dup interval-subset? ] [ empty-interval ] }
- { [ over empty-interval eq? ] [ empty-interval ] }
- { [ 2dup interval>= t eq? ] [ 1/0. [a,a] ] }
- { [ 2dup interval<= t eq? ] [ -1/0. [a,a] ] }
- [ [-inf,inf] ]
- } cond interval-union nip ;
+ { [ interval initial-interval interval-subset? ] [ initial-interval ] }
+ { [ interval empty-interval eq? ] [ initial-interval ] }
+ {
+ [ interval initial-interval interval>= t eq? ]
+ [ class max-value [a,a] initial-interval interval-union ]
+ }
+ {
+ [ interval initial-interval interval<= t eq? ]
+ [ class min-value [a,a] initial-interval interval-union ]
+ }
+ [ class class-interval ]
+ } cond ;
: generalize-counter ( info' initial -- info )
2dup [ not ] either? [ drop ] [
2dup [ class>> null-class? ] either? [ drop ] [
[ clone ] dip
- [ [ drop ] [ [ interval>> ] bi@ generalize-counter-interval ] 2bi >>interval ]
+ [ [ drop ] [ [ [ interval>> ] bi@ ] [ drop class>> ] 2bi generalize-counter-interval ] 2bi >>interval ]
[ [ drop ] [ [ slots>> ] bi@ [ generalize-counter ] 2map ] 2bi >>slots ]
[ [ drop ] [ [ length>> ] bi@ generalize-counter ] 2bi >>length ]
tri
M: #call propagate-before
dup word>> {
{ [ 2dup foldable-call? ] [ fold-call ] }
- { [ 2dup do-inlining ] [ 2drop ] }
+ { [ 2dup do-inlining ] [
+ [ output-value-infos ] [ drop out-d>> ] 2bi refine-value-infos
+ ] }
[
[ [ output-value-infos ] [ drop out-d>> ] 2bi set-value-infos ]
[ compute-constraints ]
{ [ over 0 = ] [ 2drop fixnum <class-info> ] }
{ [ 2dup length-accessor? ] [ nip length>> ] }
{ [ dup literal?>> ] [ literal>> literal-info-slot ] }
- [ [ 1- ] [ slots>> ] bi* ?nth ]
+ [ [ 1 - ] [ slots>> ] bi* ?nth ]
} cond [ object-info ] unless* ;
--- /dev/null
+Slava Pestov
+Daniel Ehrenberg
--- /dev/null
+! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel sequences words fry generic accessors classes.tuple
+classes classes.algebra definitions stack-checker.state quotations
+classes.tuple.private math math.partial-dispatch math.private
+math.intervals layouts math.order vectors hashtables
+combinators effects generalizations assocs sets
+combinators.short-circuit sequences.private locals
+stack-checker namespaces compiler.tree.propagation.info ;
+IN: compiler.tree.propagation.transforms
+
+\ equal? [
+ ! If first input has a known type and second input is an
+ ! object, we convert this to [ swap equal? ].
+ in-d>> first2 value-info class>> object class= [
+ value-info class>> \ equal? specific-method
+ [ swap equal? ] f ?
+ ] [ drop f ] if
+] "custom-inlining" set-word-prop
+
+: rem-custom-inlining ( #call -- quot/f )
+ second value-info literal>> dup integer?
+ [ power-of-2? [ 1 - bitand ] f ? ] [ drop f ] if ;
+
+{
+ mod-integer-integer
+ mod-integer-fixnum
+ mod-fixnum-integer
+ fixnum-mod
+} [
+ [
+ in-d>> dup first value-info interval>> [0,inf] interval-subset?
+ [ rem-custom-inlining ] [ drop f ] if
+ ] "custom-inlining" set-word-prop
+] each
+
+\ rem [
+ in-d>> rem-custom-inlining
+] "custom-inlining" set-word-prop
+
+: positive-fixnum? ( obj -- ? )
+ { [ fixnum? ] [ 0 >= ] } 1&& ;
+
+: simplify-bitand? ( value -- ? )
+ value-info literal>> positive-fixnum? ;
+
+{
+ bitand-integer-integer
+ bitand-integer-fixnum
+ bitand-fixnum-integer
+ bitand
+} [
+ [
+ {
+ {
+ [ dup in-d>> first simplify-bitand? ]
+ [ drop [ >fixnum fixnum-bitand ] ]
+ }
+ {
+ [ dup in-d>> second simplify-bitand? ]
+ [ drop [ [ >fixnum ] dip fixnum-bitand ] ]
+ }
+ [ drop f ]
+ } cond
+ ] "custom-inlining" set-word-prop
+] each
+
+! Speeds up 2^
+\ shift [
+ in-d>> first value-info literal>> 1 = [
+ cell-bits tag-bits get - 1 -
+ '[
+ >fixnum dup 0 < [ 2drop 0 ] [
+ dup _ < [ fixnum-shift ] [
+ fixnum-shift
+ ] if
+ ] if
+ ]
+ ] [ f ] if
+] "custom-inlining" set-word-prop
+
+! Generate more efficient code for common idiom
+\ clone [
+ in-d>> first value-info literal>> {
+ { V{ } [ [ drop { } 0 vector boa ] ] }
+ { H{ } [ [ drop 0 <hashtable> ] ] }
+ [ drop f ]
+ } case
+] "custom-inlining" set-word-prop
+
+ERROR: bad-partial-eval quot word ;
+
+: check-effect ( quot word -- )
+ 2dup [ infer ] [ stack-effect ] bi* effect<=
+ [ 2drop ] [ bad-partial-eval ] if ;
+
+:: define-partial-eval ( word quot n -- )
+ word [
+ in-d>> n tail*
+ [ value-info ] map
+ dup [ literal?>> ] all? [
+ [ literal>> ] map
+ n firstn
+ quot call dup [
+ [ n ndrop ] prepose
+ dup word check-effect
+ ] when
+ ] [ drop f ] if
+ ] "custom-inlining" set-word-prop ;
+
+: inline-new ( class -- quot/f )
+ dup tuple-class? [
+ dup inlined-dependency depends-on
+ [ all-slots [ initial>> literalize ] map ]
+ [ tuple-layout '[ _ <tuple-boa> ] ]
+ bi append >quotation
+ ] [ drop f ] if ;
+
+\ new [ inline-new ] 1 define-partial-eval
+
+\ instance? [
+ dup class?
+ [ "predicate" word-prop ] [ drop f ] if
+] 1 define-partial-eval
+
+! Shuffling
+: nths-quot ( indices -- quot )
+ [ [ '[ _ swap nth ] ] map ] [ length ] bi
+ '[ _ cleave _ narray ] ;
+
+\ shuffle [
+ shuffle-mapping nths-quot
+] 1 define-partial-eval
+
+! Index search
+\ index [
+ dup sequence? [
+ dup length 4 >= [
+ dup length zip >hashtable '[ _ at ]
+ ] [ drop f ] if
+ ] [ drop f ] if
+] 1 define-partial-eval
+
+: memq-quot ( seq -- newquot )
+ [ [ dupd eq? ] curry [ drop t ] ] { } map>assoc
+ [ drop f ] suffix [ cond ] curry ;
+
+\ memq? [
+ dup sequence? [ memq-quot ] [ drop f ] if
+] 1 define-partial-eval
+
+! Membership testing
+: member-quot ( seq -- newquot )
+ dup length 4 <= [
+ [ drop f ] swap
+ [ literalize [ t ] ] { } map>assoc linear-case-quot
+ ] [
+ unique [ key? ] curry
+ ] if ;
+
+\ member? [
+ dup sequence? [ member-quot ] [ drop f ] if
+] 1 define-partial-eval
+
+! Fast at for integer maps
+CONSTANT: lookup-table-at-max 256
+
+: lookup-table-at? ( assoc -- ? )
+ #! Can we use a fast byte array test here?
+ {
+ [ assoc-size 4 > ]
+ [ values [ ] all? ]
+ [ keys [ integer? ] all? ]
+ [ keys [ 0 lookup-table-at-max between? ] all? ]
+ } 1&& ;
+
+: lookup-table-seq ( assoc -- table )
+ [ keys supremum 1 + ] keep '[ _ at ] { } map-as ;
+
+: lookup-table-quot ( seq -- newquot )
+ lookup-table-seq
+ '[
+ _ over integer? [
+ 2dup bounds-check? [
+ nth-unsafe dup >boolean
+ ] [ 2drop f f ] if
+ ] [ 2drop f f ] if
+ ] ;
+
+: fast-lookup-table-at? ( assoc -- ? )
+ values {
+ [ [ integer? ] all? ]
+ [ [ 0 254 between? ] all? ]
+ } 1&& ;
+
+: fast-lookup-table-seq ( assoc -- table )
+ lookup-table-seq [ 255 or ] B{ } map-as ;
+
+: fast-lookup-table-quot ( seq -- newquot )
+ fast-lookup-table-seq
+ '[
+ _ over integer? [
+ 2dup bounds-check? [
+ nth-unsafe dup 255 eq? [ drop f f ] [ t ] if
+ ] [ 2drop f f ] if
+ ] [ 2drop f f ] if
+ ] ;
+
+: at-quot ( assoc -- quot )
+ dup lookup-table-at? [
+ dup fast-lookup-table-at? [
+ fast-lookup-table-quot
+ ] [
+ lookup-table-quot
+ ] if
+ ] [ drop f ] if ;
+
+\ at* [ at-quot ] 1 define-partial-eval
-IN: compiler.tree.recursive.tests
-USING: compiler.tree.recursive tools.test
-kernel combinators.short-circuit math sequences accessors
+USING: tools.test kernel combinators.short-circuit math sequences accessors
compiler.tree
compiler.tree.builder
-compiler.tree.combinators ;
+compiler.tree.combinators
+compiler.tree.recursive
+compiler.tree.recursive.private ;
+IN: compiler.tree.recursive.tests
[ { f f f f } ] [ f { f t f f } (tail-calls) ] unit-test
[ { f f f t } ] [ t { f t f f } (tail-calls) ] unit-test
] curry contains-node? ;
: loop-test-1 ( a -- )
- dup [ 1+ loop-test-1 ] [ drop ] if ; inline recursive
+ dup [ 1 + loop-test-1 ] [ drop ] if ; inline recursive
[ t ] [
[ loop-test-1 ] build-tree analyze-recursive
] unit-test
: loop-test-2 ( a b -- a' )
- dup [ 1+ loop-test-2 1- ] [ drop ] if ; inline recursive
+ dup [ 1 + loop-test-2 1 - ] [ drop ] if ; inline recursive
[ t ] [
[ loop-test-2 ] build-tree analyze-recursive
\ loop-test-3 label-is-not-loop?
] unit-test
-: loop-test-4 ( a -- )
- dup [
- loop-test-4
- ] [
- drop
- ] if ; inline recursive
-
[ f ] [
[ [ [ ] map ] map ] build-tree analyze-recursive
[
DEFER: a''
-: b'' ( -- )
+: b'' ( a -- b )
a'' ; inline recursive
-: a'' ( -- )
- b'' a'' ; inline recursive
+: a'' ( a -- b )
+ dup [ b'' a'' ] when ; inline recursive
[ t ] [
[ a'' ] build-tree analyze-recursive
\ a'' label-is-not-loop?
] unit-test
+[ t ] [
+ [ a'' ] build-tree analyze-recursive
+ \ b'' label-is-loop?
+] unit-test
+
+[ t ] [
+ [ b'' ] build-tree analyze-recursive
+ \ a'' label-is-loop?
+] unit-test
+
+[ t ] [
+ [ b'' ] build-tree analyze-recursive
+ \ b'' label-is-not-loop?
+] unit-test
+
: loop-in-non-loop ( x quot: ( i -- ) -- )
over 0 > [
[ [ 1 - ] dip loop-in-non-loop ] [ call ] 2bi
build-tree analyze-recursive
\ (each-integer) label-is-loop?
] unit-test
+
+DEFER: a'''
+
+: b''' ( -- )
+ blah [ b''' ] [ a''' b''' ] if ; inline recursive
+
+: a''' ( -- )
+ blah [ b''' ] [ a''' ] if ; inline recursive
+
+[ t ] [
+ [ b''' ] build-tree analyze-recursive
+ \ a''' label-is-loop?
+] unit-test
+
+DEFER: b4
+
+: a4 ( a -- b ) dup [ b4 ] when ; inline recursive
+
+: b4 ( a -- b ) dup [ a4 reverse ] when ; inline recursive
+
+[ t ] [ [ b4 ] build-tree analyze-recursive \ a4 label-is-loop? ] unit-test
+[ t ] [ [ b4 ] build-tree analyze-recursive \ b4 label-is-not-loop? ] unit-test
+[ t ] [ [ a4 ] build-tree analyze-recursive \ a4 label-is-not-loop? ] unit-test
+[ t ] [ [ a4 ] build-tree analyze-recursive \ b4 label-is-loop? ] unit-test
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel assocs arrays namespaces accessors sequences deques
-search-deques dlists compiler.tree compiler.tree.combinators ;
+USING: kernel assocs arrays namespaces accessors sequences deques fry
+search-deques dlists combinators.short-circuit make sets compiler.tree ;
IN: compiler.tree.recursive
-! Collect label info
-GENERIC: collect-label-info ( node -- )
+TUPLE: call-site tail? node label ;
-M: #return-recursive collect-label-info
- dup label>> (>>return) ;
+: recursive-phi-in ( #enter-recursive -- seq )
+ [ label>> calls>> [ node>> in-d>> ] map ] [ in-d>> ] bi suffix ;
-M: #call-recursive collect-label-info
- dup label>> calls>> push ;
+<PRIVATE
-M: #recursive collect-label-info
- label>> V{ } clone >>calls drop ;
+TUPLE: call-graph-node tail? label children calls ;
-M: node collect-label-info drop ;
-
-! A loop is a #recursive which only tail calls itself, and those
-! calls are nested inside other loops only. We optimistically
-! assume all #recursive nodes are loops, disqualifying them as
-! we see evidence to the contrary.
: (tail-calls) ( tail? seq -- seq' )
reverse [ swap [ and ] keep ] map nip reverse ;
: tail-calls ( tail? node -- seq )
[
- [ #phi? ]
- [ #return? ]
- [ #return-recursive? ]
- tri or or
+ {
+ [ #phi? ]
+ [ #return? ]
+ [ #return-recursive? ]
+ } 1||
] map (tail-calls) ;
-SYMBOL: loop-heights
-SYMBOL: loop-calls
-SYMBOL: loop-stack
-SYMBOL: work-list
+SYMBOLS: children calls ;
+
+GENERIC: node-call-graph ( tail? node -- )
-GENERIC: collect-loop-info* ( tail? node -- )
+: (build-call-graph) ( tail? nodes -- )
+ [ tail-calls ] keep
+ [ node-call-graph ] 2each ;
-: non-tail-label-info ( nodes -- )
- [ f swap collect-loop-info* ] each ;
+: build-call-graph ( nodes -- labels calls )
+ [
+ V{ } clone children set
+ V{ } clone calls set
+ [ t ] dip (build-call-graph)
+ children get
+ calls get
+ ] with-scope ;
-: (collect-loop-info) ( tail? nodes -- )
- [ tail-calls ] keep [ collect-loop-info* ] 2each ;
+M: #return-recursive node-call-graph
+ nip dup label>> (>>return) ;
-: remember-loop-info ( label -- )
- loop-stack get length swap loop-heights get set-at ;
+M: #call-recursive node-call-graph
+ [ dup label>> call-site boa ] keep
+ [ drop calls get push ]
+ [ label>> calls>> push ] 2bi ;
-M: #recursive collect-loop-info*
+M: #recursive node-call-graph
+ [ label>> V{ } clone >>calls drop ]
[
- [
- label>>
- [ swap 2array loop-stack [ swap suffix ] change ]
- [ remember-loop-info ]
- [ t >>loop? drop ]
- tri
- ]
- [ t swap child>> (collect-loop-info) ] bi
- ] with-scope ;
+ [ label>> ] [ child>> build-call-graph ] bi
+ call-graph-node boa children get push
+ ] bi ;
-: current-loop-nesting ( label -- alist )
- loop-stack get swap loop-heights get at tail ;
+M: #branch node-call-graph
+ children>> [ (build-call-graph) ] with each ;
-: disqualify-loop ( label -- )
- work-list get push-front ;
+M: node node-call-graph 2drop ;
-M: #call-recursive collect-loop-info*
- label>>
- swap [ dup disqualify-loop ] unless
- dup current-loop-nesting
- [ keys [ loop-calls get push-at ] with each ]
- [ [ nip not ] assoc-filter keys [ disqualify-loop ] each ]
- bi ;
+SYMBOLS: not-loops recursive-nesting ;
-M: #if collect-loop-info*
- children>> [ (collect-loop-info) ] with each ;
+: not-a-loop ( label -- ) not-loops get conjoin ;
-M: #dispatch collect-loop-info*
- children>> [ (collect-loop-info) ] with each ;
+: not-a-loop? ( label -- ? ) not-loops get key? ;
-M: node collect-loop-info* 2drop ;
+: non-tail-calls ( call-graph-node -- seq )
+ calls>> [ tail?>> not ] filter ;
+
+: visit-back-edges ( call-graph -- )
+ [
+ [ non-tail-calls [ label>> not-a-loop ] each ]
+ [ children>> visit-back-edges ]
+ bi
+ ] each ;
+
+SYMBOL: changed?
+
+: check-cross-frame-call ( call-site -- )
+ label>> dup not-a-loop? [ drop ] [
+ recursive-nesting get <reversed> [
+ 2dup label>> eq? [ 2drop f ] [
+ [ label>> not-a-loop? ] [ tail?>> not ] bi or
+ [ not-a-loop changed? on ] [ drop ] if t
+ ] if
+ ] with all? drop
+ ] if ;
+
+: detect-cross-frame-calls ( call-graph -- )
+ ! Suppose we have a nesting of recursives A --> B --> C
+ ! B tail-calls A, and C non-tail-calls B. Then A cannot be
+ ! a loop, it needs its own procedure, since the call from
+ ! C to A crosses a call-frame boundary.
+ [
+ [ recursive-nesting get push ]
+ [ calls>> [ check-cross-frame-call ] each ]
+ [ children>> detect-cross-frame-calls ] tri
+ recursive-nesting get pop*
+ ] each ;
+
+: while-changing ( quot: ( -- ) -- )
+ changed? off
+ [ call ] [ changed? get [ while-changing ] [ drop ] if ] bi ;
+ inline recursive
+
+: detect-loops ( call-graph -- )
+ H{ } clone not-loops set
+ V{ } clone recursive-nesting set
+ [ visit-back-edges ]
+ [ '[ _ detect-cross-frame-calls ] while-changing ]
+ bi ;
+
+: mark-loops ( call-graph -- )
+ [
+ [ label>> dup not-a-loop? [ t >>loop? ] unless drop ]
+ [ children>> mark-loops ]
+ bi
+ ] each ;
-: collect-loop-info ( node -- )
- { } loop-stack set
- H{ } clone loop-calls set
- H{ } clone loop-heights set
- <hashed-dlist> work-list set
- t swap (collect-loop-info) ;
+PRIVATE>
-: disqualify-loops ( -- )
- work-list get [
- dup loop?>> [
- [ f >>loop? drop ]
- [ loop-calls get at [ disqualify-loop ] each ]
- bi
- ] [ drop ] if
- ] slurp-deque ;
+SYMBOL: call-graph
: analyze-recursive ( nodes -- nodes )
- dup [ collect-label-info ] each-node
- dup collect-loop-info disqualify-loops ;
+ dup build-call-graph drop
+ [ call-graph set ]
+ [ detect-loops ]
+ [ mark-loops ]
+ tri ;
M: #copy inputs/outputs [ in-d>> ] [ out-d>> ] bi ;
M: #return-recursive inputs/outputs [ in-d>> ] [ out-d>> ] bi ;
-: recursive-phi-in ( #enter-recursive -- seq )
- [ label>> calls>> [ in-d>> ] map ] [ in-d>> ] bi suffix ;
-
: ends-with-terminate? ( nodes -- ? )
[ f ] [ last #terminate? ] if-empty ;
-IN: compiler.tree.tuple-unboxing.tests
USING: tools.test compiler.tree
compiler.tree.builder compiler.tree.recursive
compiler.tree.normalization compiler.tree.propagation
compiler.tree.def-use kernel accessors sequences math
math.private sorting math.order binary-search sequences.private
slots.private ;
+IN: compiler.tree.tuple-unboxing.tests
: test-unboxing ( quot -- )
build-tree
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces assocs accessors kernel combinators
+USING: namespaces assocs accessors kernel kernel.private combinators
classes.algebra sequences slots.private fry vectors
classes.tuple.private math math.private arrays
-stack-checker.branches
+stack-checker.branches stack-checker.values
compiler.utilities
compiler.tree
+compiler.tree.builder
+compiler.tree.cleanup
compiler.tree.combinators
+compiler.tree.propagation
compiler.tree.propagation.info
compiler.tree.escape-analysis.simple
compiler.tree.escape-analysis.allocations ;
} case ;
M: #declare unbox-tuples*
- #! We don't look at declarations after propagation anyway.
- f >>declaration ;
+ #! We don't look at declarations after escape analysis anyway.
+ drop f ;
M: #copy unbox-tuples*
[ flatten-values ] change-in-d
[ flatten-values ] change-in-d
[ flatten-values ] change-out-d ;
+: value-declaration ( value -- quot )
+ value-class [ 1array '[ _ declare ] ] [ [ ] ] if* ;
+
+: unbox-parameter-quot ( allocation -- quot )
+ dup unboxed-allocation {
+ { [ dup not ] [ 2drop [ ] ] }
+ { [ dup array? ] [
+ [ value-declaration ] [
+ [
+ [ unbox-parameter-quot ] [ 2 + '[ _ slot ] ] bi*
+ prepose
+ ] map-index
+ ] bi* '[ @ _ cleave ]
+ ] }
+ } cond ;
+
+: unbox-parameters-quot ( values -- quot )
+ [ unbox-parameter-quot ] map
+ dup [ [ ] = ] all? [ drop [ ] ] [ '[ _ spread ] ] if ;
+
+: unbox-parameters-nodes ( new-values old-values -- nodes )
+ [ flatten-values ] [ unbox-parameters-quot ] bi build-sub-tree ;
+
+: new-and-old-values ( values -- new-values old-values )
+ [ length [ <value> ] replicate ] keep ;
+
+: unbox-hairy-introduce ( #introduce -- nodes )
+ dup out-d>> new-and-old-values
+ [ drop >>out-d ] [ unbox-parameters-nodes ] 2bi
+ swap prefix propagate ;
+
+M: #introduce unbox-tuples*
+ ! For every output that is unboxed, insert slot accessors
+ ! to convert the stack value into its unboxed form
+ dup out-d>> [ unboxed-allocation ] any? [
+ unbox-hairy-introduce
+ ] when ;
+
! These nodes never participate in unboxing
: assert-not-unboxed ( values -- )
dup array?
M: #return unbox-tuples* dup in-d>> assert-not-unboxed ;
-M: #introduce unbox-tuples* dup out-d>> assert-not-unboxed ;
-
M: #alien-invoke unbox-tuples* dup in-d>> assert-not-unboxed ;
M: #alien-indirect unbox-tuples* dup in-d>> assert-not-unboxed ;
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences sequences.private arrays vectors fry
-math.order namespaces assocs ;
+math math.order namespaces assocs locals ;
IN: compiler.utilities
: flattener ( seq quot -- seq vector quot' )
dup
'[
@ [
- dup array?
+ dup [ array? ] [ vector? ] bi or
[ _ push-all ] [ _ push ] if
] when*
]
SYMBOL: yield-hook
yield-hook [ [ ] ] initialize
+
+: alist-most ( alist quot -- pair )
+ [ [ ] ] dip '[ [ [ second ] bi@ @ ] most ] map-reduce ; inline
+
+: alist-min ( alist -- pair ) [ before? ] alist-most ;
+
+: alist-max ( alist -- pair ) [ after? ] alist-most ;
+
+: penultimate ( seq -- elt ) [ length 2 - ] keep nth ;
+
+:: compress-path ( source assoc -- destination )
+ [let | destination [ source assoc at ] |
+ source destination = [ source ] [
+ [let | destination' [ destination assoc compress-path ] |
+ destination' destination = [
+ destination' source assoc set-at
+ ] unless
+ destination'
+ ]
+ ] if
+ ] ;
! Copyright (C) 2009 Marc Fauconneau.\r
! See http://factorcode.org/license.txt for BSD license.\r
-USING: accessors arrays assocs constructors fry\r
+USING: accessors arrays assocs fry\r
hashtables io kernel locals math math.order math.parser\r
math.ranges multiline sequences ;\r
IN: compression.huffman\r
{ code } ;\r
\r
: <huffman-code> ( -- code ) 0 0 0 huffman-code boa ;\r
-: next-size ( code -- ) [ 1+ ] change-size [ 2 * ] change-code drop ;\r
-: next-code ( code -- ) [ 1+ ] change-code drop ;\r
+: next-size ( code -- ) [ 1 + ] change-size [ 2 * ] change-code drop ;\r
+: next-code ( code -- ) [ 1 + ] change-code drop ;\r
\r
:: all-patterns ( huff n -- seq )\r
n log2 huff size>> - :> free-bits\r
{ rtable }\r
{ bits/level } ;\r
\r
-CONSTRUCTOR: huffman-decoder ( bs tdesc -- decoder )\r
+: <huffman-decoder> ( bs tdesc -- decoder )\r
+ huffman-decoder new\r
+ swap >>tdesc\r
+ swap >>bs\r
16 >>bits/level\r
[ ] [ tdesc>> ] [ bits/level>> 2^ ] tri reverse-table >>rtable ;\r
\r
! Copyright (C) 2009 Marc Fauconneau.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs byte-arrays
-byte-vectors combinators constructors fry grouping hashtables
+byte-vectors combinators fry grouping hashtables
compression.huffman images io.binary kernel locals
math math.bitwise math.order math.ranges multiline sequences
sorting ;
k swap - dup k! 0 >
]
[ ] produce swap suffix
- { } [ dup array? [ dup first 16 = ] [ f ] if [ [ unclip-last ] [ second 1+ swap <repetition> append ] bi* ] [ suffix ] if ] reduce
+ { } [ dup array? [ dup first 16 = ] [ f ] if [ [ unclip-last ] [ second 1 + swap <repetition> append ] bi* ] [ suffix ] if ] reduce
[ dup array? [ second 0 <repetition> ] [ 1array ] if ] map concat
nip swap cut 2array [ [ length>> [0,b) ] [ ] bi get-table ] map ;
}
: nth* ( n seq -- elt )
- [ length 1- swap - ] [ nth ] bi ;
+ [ length 1 - swap - ] [ nth ] bi ;
:: inflate-lz77 ( seq -- bytes )
1000 <byte-vector> :> bytes
seq
[
dup array?
- [ first2 '[ _ 1- bytes nth* bytes push ] times ]
+ [ first2 '[ _ 1 - bytes nth* bytes push ] times ]
[ bytes push ] if
] each
bytes ;
PRIVATE>
-! for debug -- shows residual values
-: reverse-png-filter' ( lines -- filtered )
+: reverse-png-filter' ( lines -- byte-array )
[ first ] [ 1 tail ] [ map ] bi-curry@ bi nip
- concat [ 128 + 256 wrap ] map ;
-
-: reverse-png-filter ( lines -- filtered )
+ concat [ 128 + ] B{ } map-as ;
+
+: reverse-png-filter ( lines -- byte-array )
dup first [ 0 ] replicate prefix
[ { 0 0 } prepend ] map
2 clump [
first2 dup [ third ] [ 0 2 rot set-nth ] bi png-unfilter-line
- ] map concat ;
+ ] map B{ } concat-as ;
: zlib-inflate ( bytes -- bytes )
bs:<lsb0-bit-reader>
+++ /dev/null
-! Copyright (C) 2009 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors tools.test compression.lzw ;
-IN: compression.lzw.tests
--- /dev/null
+Doug Coleman
\ No newline at end of file
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays grouping sequences ;
+USING: accessors arrays combinators grouping kernel locals math
+math.matrices math.order multiline sequence-parser sequences
+tools.continuations ;
IN: compression.run-length
: run-length-uncompress ( byte-array -- byte-array' )
- 2 group [ first2 <array> ] map concat ;
+ 2 group [ first2 <array> ] map B{ } concat-as ;
+
+: 8hi-lo ( byte -- hi lo )
+ [ HEX: f0 bitand -4 shift ] [ HEX: f bitand ] bi ; inline
+
+:: run-length-uncompress-bitmap4 ( byte-array m n -- byte-array' )
+ byte-array <sequence-parser> :> sp
+ m 1 + n zero-matrix :> matrix
+ n 4 mod n + :> stride
+ 0 :> i!
+ 0 :> j!
+ f :> done?!
+ [
+ ! i j [ number>string ] bi@ " " glue .
+ sp next dup 0 = [
+ sp next dup HEX: 03 HEX: ff between? [
+ nip [ sp ] dip dup odd?
+ [ 1 + take-n but-last ] [ take-n ] if
+ [ j matrix i swap nth copy ] [ length j + j! ] bi
+ ] [
+ nip {
+ { 0 [ i 1 + i! 0 j! ] }
+ { 1 [ t done?! ] }
+ { 2 [ sp next j + j! sp next i + i! ] }
+ } case
+ ] if
+ ] [
+ [ sp next 8hi-lo 2array <repetition> concat ] [ head ] bi
+ [ j matrix i swap nth copy ] [ length j + j! ] bi
+ ] if
+
+ ! j stride >= [ i 1 + i! 0 j! ] when
+ j stride >= [ 0 j! ] when
+ done? not
+ ] loop
+ matrix B{ } concat-as ;
+
+:: run-length-uncompress-bitmap8 ( byte-array m n -- byte-array' )
+ byte-array <sequence-parser> :> sp
+ m 1 + n zero-matrix :> matrix
+ n 4 mod n + :> stride
+ 0 :> i!
+ 0 :> j!
+ f :> done?!
+ [
+ ! i j [ number>string ] bi@ " " glue .
+ sp next dup 0 = [
+ sp next dup HEX: 03 HEX: ff between? [
+ nip [ sp ] dip dup odd?
+ [ 1 + take-n but-last ] [ take-n ] if
+ [ j matrix i swap nth copy ] [ length j + j! ] bi
+ ] [
+ nip {
+ { 0 [ i 1 + i! 0 j! ] }
+ { 1 [ t done?! ] }
+ { 2 [ sp next j + j! sp next i + i! ] }
+ } case
+ ] if
+ ] [
+ sp next <array> [ j matrix i swap nth copy ] [ length j + j! ] bi
+ ] if
+
+ ! j stride >= [ i 1 + i! 0 j! ] when
+ j stride >= [ 0 j! ] when
+ done? not
+ ] loop
+ matrix B{ } concat-as ;
-IN: concurrency.combinators.tests\r
USING: concurrency.combinators tools.test random kernel math \r
concurrency.mailboxes threads sequences accessors arrays\r
math.parser ;\r
+IN: concurrency.combinators.tests\r
\r
[ [ drop ] parallel-each ] must-infer\r
{ 2 0 } [ [ 2drop ] 2parallel-each ] must-infer-as\r
\r
[ "1a" "4b" "3c" ] [\r
2\r
- { [ 1- ] [ sq ] [ 1+ ] } parallel-cleave\r
+ { [ 1 - ] [ sq ] [ 1 + ] } parallel-cleave\r
[ number>string ] 3 parallel-napply\r
{ [ "a" append ] [ "b" append ] [ "c" append ] } parallel-spread\r
] unit-test\r
: count-down ( count-down -- )\r
dup n>> dup zero?\r
[ count-down-already-done ]\r
- [ 1- >>n count-down-check ] if ;\r
+ [ 1 - >>n count-down-check ] if ;\r
\r
: await-timeout ( count-down timeout -- )\r
[ promise>> ] dip ?promise-timeout ?linked t assert= ;\r
-IN: concurrency.distributed.tests
USING: tools.test concurrency.distributed kernel io.files
io.files.temp io.directories arrays io.sockets system
combinators threads math sequences concurrency.messaging
continuations accessors prettyprint ;
FROM: concurrency.messaging => receive send ;
+IN: concurrency.distributed.tests
: test-node ( -- addrspec )
{
-IN: concurrency.exchangers.tests\r
USING: tools.test concurrency.exchangers\r
concurrency.count-downs concurrency.promises locals kernel\r
threads ;\r
FROM: sequences => 3append ;\r
+IN: concurrency.exchangers.tests\r
\r
:: exchanger-test ( -- string )\r
[let |\r
-IN: concurrency.flags.tests\r
USING: tools.test concurrency.flags concurrency.combinators\r
kernel threads locals accessors calendar ;\r
+IN: concurrency.flags.tests\r
\r
:: flag-test-1 ( -- val )\r
[let | f [ <flag> ] |\r
-IN: concurrency.futures.tests\r
USING: concurrency.futures kernel tools.test threads ;\r
+IN: concurrency.futures.tests\r
\r
[ 50 ] [\r
[ 50 ] future ?future\r
-IN: concurrency.locks.tests\r
USING: tools.test concurrency.locks concurrency.count-downs\r
concurrency.messaging concurrency.mailboxes locals kernel\r
threads sequences calendar accessors ;\r
+IN: concurrency.locks.tests\r
\r
:: lock-test-0 ( -- v )\r
[let | v [ V{ } clone ]\r
<PRIVATE\r
\r
: add-reader ( lock -- )\r
- [ 1+ ] change-reader# drop ;\r
+ [ 1 + ] change-reader# drop ;\r
\r
: acquire-read-lock ( lock timeout -- )\r
over writer>>\r
writers>> notify-1 ;\r
\r
: remove-reader ( lock -- )\r
- [ 1- ] change-reader# drop ;\r
+ [ 1 - ] change-reader# drop ;\r
\r
: release-read-lock ( lock -- )\r
dup remove-reader\r
-IN: concurrency.mailboxes.tests\r
USING: concurrency.mailboxes concurrency.count-downs concurrency.conditions\r
vectors sequences threads tools.test math kernel strings namespaces\r
continuations calendar destructors ;\r
+IN: concurrency.mailboxes.tests\r
\r
{ 1 1 } [ [ integer? ] mailbox-get? ] must-infer-as\r
\r
[\r
<mailbox> 1 seconds mailbox-get-timeout\r
] [ wait-timeout? ] must-fail-with\r
-
\ No newline at end of file
+ \r
! Copyright (C) 2005, 2008 Chris Double, Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
-IN: concurrency.mailboxes\r
USING: dlists deques threads sequences continuations\r
destructors namespaces math quotations words kernel\r
arrays assocs init system concurrency.conditions accessors\r
debugger debugger.threads locals fry ;\r
+IN: concurrency.mailboxes\r
\r
-TUPLE: mailbox threads data disposed ;\r
+TUPLE: mailbox < disposable threads data ;\r
\r
M: mailbox dispose* threads>> notify-all ;\r
\r
: <mailbox> ( -- mailbox )\r
- <dlist> <dlist> f mailbox boa ;\r
+ mailbox new-disposable <dlist> >>threads <dlist> >>data ;\r
\r
: mailbox-empty? ( mailbox -- bool )\r
data>> deque-empty? ;\r
-IN: concurrency.promises.tests\r
USING: vectors concurrency.promises kernel threads sequences\r
tools.test ;\r
+IN: concurrency.promises.tests\r
\r
[ V{ 50 50 50 } ] [\r
0 <vector>\r
: acquire-timeout ( semaphore timeout -- )\r
over count>> zero?\r
[ dupd wait-to-acquire ] [ drop ] if\r
- [ 1- ] change-count drop ;\r
+ [ 1 - ] change-count drop ;\r
\r
: acquire ( semaphore -- )\r
f acquire-timeout ;\r
\r
: release ( semaphore -- )\r
- [ 1+ ] change-count\r
+ [ 1 + ] change-count\r
threads>> notify-1 ;\r
\r
:: with-semaphore-timeout ( semaphore timeout quot -- )\r
+++ /dev/null
-Slava Pestov
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test constructors calendar kernel accessors
-combinators.short-circuit initializers math ;
-IN: constructors.tests
-
-TUPLE: stock-spread stock spread timestamp ;
-
-CONSTRUCTOR: stock-spread ( stock spread -- stock-spread )
- now >>timestamp ;
-
-SYMBOL: AAPL
-
-[ t ] [
- AAPL 1234 <stock-spread>
- {
- [ stock>> AAPL eq? ]
- [ spread>> 1234 = ]
- [ timestamp>> timestamp? ]
- } 1&&
-] unit-test
-
-TUPLE: ct1 a ;
-TUPLE: ct2 < ct1 b ;
-TUPLE: ct3 < ct2 c ;
-TUPLE: ct4 < ct3 d ;
-
-CONSTRUCTOR: ct1 ( a -- obj )
- [ 1 + ] change-a ;
-
-CONSTRUCTOR: ct2 ( a b -- obj )
- initialize-ct1
- [ 1 + ] change-a ;
-
-CONSTRUCTOR: ct3 ( a b c -- obj )
- initialize-ct1
- [ 1 + ] change-a ;
-
-CONSTRUCTOR: ct4 ( a b c d -- obj )
- initialize-ct3
- [ 1 + ] change-a ;
-
-[ 1001 ] [ 1000 <ct1> a>> ] unit-test
-[ 2 ] [ 0 0 <ct2> a>> ] unit-test
-[ 2 ] [ 0 0 0 <ct3> a>> ] unit-test
-[ 3 ] [ 0 0 0 0 <ct4> a>> ] unit-test
-
-
-TUPLE: rofl a b c ;
-CONSTRUCTOR: rofl ( b c a -- obj ) ;
-
-[ T{ rofl { a 3 } { b 1 } { c 2 } } ] [ 1 2 3 <rofl> ] unit-test
-
-
-TUPLE: default { a integer initial: 0 } ;
-
-CONSTRUCTOR: default ( -- obj ) ;
-
-[ 0 ] [ <default> a>> ] unit-test
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov, Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs classes.tuple effects.parser fry
-generalizations generic.standard kernel lexer locals macros
-parser sequences slots vocabs words ;
-IN: constructors
-
-! An experiment
-
-: initializer-name ( class -- word )
- name>> "initialize-" prepend ;
-
-: lookup-initializer ( class -- word/f )
- initializer-name "initializers" lookup ;
-
-: initializer-word ( class -- word )
- initializer-name
- "initializers" create-vocab create
- [ t "initializer" set-word-prop ] [ ] bi ;
-
-: define-initializer-generic ( name -- )
- initializer-word (( object -- object )) define-simple-generic ;
-
-: define-initializer ( class def -- )
- [ drop define-initializer-generic ]
- [ [ dup lookup-initializer ] dip H{ } clone define-typecheck ] 2bi ;
-
-MACRO:: slots>constructor ( class slots -- quot )
- class all-slots [ [ name>> ] [ initial>> ] bi ] { } map>assoc :> params
- slots length
- params length
- '[
- _ narray slots swap zip
- params swap assoc-union
- values _ firstn class boa
- ] ;
-
-:: define-constructor ( constructor-word class effect def -- )
- constructor-word
- class def define-initializer
- class effect in>> '[ _ _ slots>constructor ]
- class lookup-initializer
- '[ @ _ execute( obj -- obj ) ] effect define-declared ;
-
-: scan-constructor ( -- class word )
- scan-word [ name>> "<" ">" surround create-in ] keep ;
-
-SYNTAX: CONSTRUCTOR:
- scan-constructor
- complete-effect
- parse-definition
- define-constructor ;
-
-"initializers" create-vocab drop
+++ /dev/null
-Utility to simplify tuple constructors
+++ /dev/null
-extensions
-IN: cords.tests
USING: cords strings tools.test kernel sequences ;
+IN: cords.tests
[ "hello world" ] [ "hello" " world" cord-append dup like ] unit-test
[ "hello world" ] [ { "he" "llo" " world" } cord-concat dup like ] unit-test
}
"cdecl" [ (master-event-source-callback) ] alien-callback ;
-TUPLE: event-stream info handle disposed ;
+TUPLE: event-stream < disposable info handle ;
: <event-stream> ( quot paths latency flags -- event-stream )
[
- add-event-source-callback dup
- [ master-event-source-callback ] dip
+ add-event-source-callback
+ [ master-event-source-callback ] keep
] 3dip <FSEventStream>
dup enable-event-stream
- f event-stream boa ;
+ event-stream new-disposable swap >>handle swap >>info ;
M: event-stream dispose*
{
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test core-foundation.numbers ;
-IN: core-foundation.numbers.tests
: (reset-timer) ( timer counter -- )
yield {
{ [ dup 0 = ] [ now ((reset-timer)) ] }
- { [ run-queue deque-empty? not ] [ 1- (reset-timer) ] }
+ { [ run-queue deque-empty? not ] [ 1 - (reset-timer) ] }
{ [ sleep-queue heap-empty? ] [ 5 minutes hence ((reset-timer)) ] }
[ sleep-queue heap-peek nip micros>timestamp ((reset-timer)) ]
} cond ;
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test core-foundation.utilities ;
-IN: core-foundation.utilities.tests
: make-bitmap-image ( dim quot -- image )
'[ <CGBitmapContext> &CGContextRelease @ ] make-memory-bitmap
- ARGB >>component-order ; inline
+ ARGB >>component-order
+ ubyte-components >>component-type ; inline
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test core-graphics.types ;
-IN: core-graphics.types.tests
! See http://factorcode.org/license.txt for BSD license.
USING: arrays alien alien.c-types alien.syntax kernel destructors
accessors fry words hashtables strings sequences memoize assocs math
-math.vectors math.rectangles math.functions locals init namespaces
-combinators fonts colors cache core-foundation core-foundation.strings
-core-foundation.attributed-strings core-foundation.utilities
-core-graphics core-graphics.types core-text.fonts core-text.utilities ;
+math.order math.vectors math.rectangles math.functions locals init
+namespaces combinators fonts colors cache core-foundation
+core-foundation.strings core-foundation.attributed-strings
+core-foundation.utilities core-graphics core-graphics.types
+core-text.fonts core-text.utilities ;
IN: core-text
TYPEDEF: void* CTLineRef
CTLineCreateWithAttributedString
] with-destructors ;
-TUPLE: line line metrics image loc dim disposed ;
+TUPLE: line < disposable line metrics image loc dim ;
: typographic-bounds ( line -- width ascent descent leading )
0 <CGFloat> 0 <CGFloat> 0 <CGFloat>
:: <line> ( font string -- line )
[
+ line new-disposable
+
[let* | open-font [ font cache-font ]
line [ string open-font font foreground>> <CTLine> |CFRelease ]
(ext) [ (loc) (dim) v+ ]
loc [ (loc) [ floor ] map ]
ext [ (loc) (dim) [ + ceiling ] 2map ]
- dim [ ext loc [ - >integer ] 2map ]
+ dim [ ext loc [ - >integer 1 max ] 2map ]
metrics [ open-font line compute-line-metrics ] |
- line metrics
+
+ line >>line
+
+ metrics >>metrics
+
dim [
{
[ font dim fill-background ]
[ loc set-text-position ]
[ [ line ] dip CTLineDraw ]
} cleave
- ] make-bitmap-image
- metrics loc dim line-loc
- metrics metrics>dim
+ ] make-bitmap-image >>image
+
+ metrics loc dim line-loc >>loc
+
+ metrics metrics>dim >>dim
]
- f line boa
] with-destructors ;
M: line dispose* line>> CFRelease ;
: cached-line ( font string -- line )
cached-lines get [ <line> ] 2cache ;
-[ <cache-assoc> cached-lines set-global ] "core-text" add-init-hook
\ No newline at end of file
+[ <cache-assoc> cached-lines set-global ] "core-text" add-init-hook
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test core-text.fonts ;
-IN: core-text.fonts.tests
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test core-text.utilities ;
-IN: core-text.utilities.tests
-! Copyright (C) 2006, 2008 Slava Pestov.
+! Copyright (C) 2006, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays generic kernel kernel.private math
memory namespaces make sequences layouts system hashtables
classes alien byte-arrays combinators words sets fry ;
IN: cpu.architecture
-! Register classes
-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 ;
-
-! A pseudo-register class for parameters spilled on the stack
-SINGLETON: stack-params
-
-GENERIC: reg-size ( register-class -- n )
+! Representations -- these are like low-level types
-M: int-regs reg-size drop cell ;
+! Unknown representation; this is used for ##copy instructions which
+! get eliminated later
+SINGLETON: any-rep
-M: single-float-regs reg-size drop 4 ;
+! Integer registers can contain data with one of these three representations
+! tagged-rep: tagged pointer or fixnum
+! int-rep: untagged fixnum, not a pointer
+SINGLETONS: tagged-rep int-rep ;
-M: double-float-regs reg-size drop 8 ;
+! Floating point registers can contain data with
+! one of these representations
+SINGLETONS: single-float-rep double-float-rep ;
-M: stack-params reg-size drop cell ;
+UNION: representation any-rep tagged-rep int-rep single-float-rep double-float-rep ;
-! Mapping from register class to machine registers
-HOOK: machine-registers cpu ( -- assoc )
+! Register classes
+SINGLETONS: int-regs float-regs ;
-! Return values of this class go here
-GENERIC: return-reg ( register-class -- reg )
+UNION: reg-class int-regs float-regs ;
+CONSTANT: reg-classes { int-regs float-regs }
-! Sequence of registers used for parameter passing in class
-GENERIC: param-regs ( register-class -- regs )
+! A pseudo-register class for parameters spilled on the stack
+SINGLETON: stack-params
-GENERIC: param-reg ( n register-class -- reg )
+: reg-class-of ( rep -- reg-class )
+ {
+ { tagged-rep [ int-regs ] }
+ { int-rep [ int-regs ] }
+ { single-float-rep [ float-regs ] }
+ { double-float-rep [ float-regs ] }
+ { stack-params [ stack-params ] }
+ } case ;
+
+: rep-size ( rep -- n )
+ {
+ { tagged-rep [ cell ] }
+ { int-rep [ cell ] }
+ { single-float-rep [ 4 ] }
+ { double-float-rep [ 8 ] }
+ { stack-params [ cell ] }
+ } case ;
-M: object param-reg param-regs nth ;
+! Mapping from register class to machine registers
+HOOK: machine-registers cpu ( -- assoc )
HOOK: two-operand? cpu ( -- ? )
HOOK: %return cpu ( -- )
HOOK: %dispatch cpu ( src temp -- )
-HOOK: %dispatch-label cpu ( label -- )
HOOK: %slot cpu ( dst obj slot tag temp -- )
HOOK: %slot-imm cpu ( dst obj slot tag -- )
HOOK: %or-imm cpu ( dst src1 src2 -- )
HOOK: %xor cpu ( dst src1 src2 -- )
HOOK: %xor-imm cpu ( dst src1 src2 -- )
+HOOK: %shl cpu ( dst src1 src2 -- )
HOOK: %shl-imm cpu ( dst src1 src2 -- )
+HOOK: %shr cpu ( dst src1 src2 -- )
HOOK: %shr-imm cpu ( dst src1 src2 -- )
+HOOK: %sar cpu ( dst src1 src2 -- )
HOOK: %sar-imm cpu ( dst src1 src2 -- )
HOOK: %not cpu ( dst src -- )
HOOK: %log2 cpu ( dst src -- )
-HOOK: %fixnum-add cpu ( src1 src2 -- )
-HOOK: %fixnum-add-tail cpu ( src1 src2 -- )
-HOOK: %fixnum-sub cpu ( src1 src2 -- )
-HOOK: %fixnum-sub-tail cpu ( src1 src2 -- )
-HOOK: %fixnum-mul cpu ( src1 src2 temp1 temp2 -- )
-HOOK: %fixnum-mul-tail cpu ( src1 src2 temp1 temp2 -- )
+HOOK: %fixnum-add cpu ( label dst src1 src2 -- )
+HOOK: %fixnum-sub cpu ( label dst src1 src2 -- )
+HOOK: %fixnum-mul cpu ( label dst src1 src2 -- )
HOOK: %integer>bignum cpu ( dst src temp -- )
HOOK: %bignum>integer cpu ( dst src temp -- )
HOOK: %sub-float cpu ( dst src1 src2 -- )
HOOK: %mul-float cpu ( dst src1 src2 -- )
HOOK: %div-float cpu ( dst src1 src2 -- )
+HOOK: %sqrt cpu ( dst src -- )
HOOK: %integer>float cpu ( dst src -- )
HOOK: %float>integer cpu ( dst src -- )
-HOOK: %copy cpu ( dst src -- )
-HOOK: %copy-float cpu ( dst src -- )
+HOOK: %copy cpu ( dst src rep -- )
HOOK: %unbox-float cpu ( dst src -- )
HOOK: %unbox-any-c-ptr cpu ( dst src temp -- )
HOOK: %box-float cpu ( dst src temp -- )
HOOK: %box-alien cpu ( dst src temp -- )
+HOOK: %box-displaced-alien cpu ( dst displacement base temp -- )
HOOK: %alien-unsigned-1 cpu ( dst src -- )
HOOK: %alien-unsigned-2 cpu ( dst src -- )
HOOK: %allot cpu ( dst size class temp -- )
HOOK: %write-barrier cpu ( src card# table -- )
-HOOK: %gc cpu ( temp1 temp2 live-registers live-spill-slots -- )
+
+! GC checks
+HOOK: %check-nursery cpu ( label temp1 temp2 -- )
+HOOK: %save-gc-root cpu ( gc-root register -- )
+HOOK: %load-gc-root cpu ( gc-root register -- )
+HOOK: %call-gc cpu ( gc-root-count -- )
HOOK: %prologue cpu ( n -- )
HOOK: %epilogue cpu ( n -- )
HOOK: %compare-imm-branch cpu ( label cc src1 src2 -- )
HOOK: %compare-float-branch cpu ( label cc src1 src2 -- )
-HOOK: %spill-integer cpu ( src n -- )
-HOOK: %spill-float cpu ( src n -- )
-HOOK: %reload-integer cpu ( dst n -- )
-HOOK: %reload-float cpu ( dst n -- )
+HOOK: %spill cpu ( src n rep -- )
+HOOK: %reload cpu ( dst n rep -- )
HOOK: %loop-entry cpu ( -- )
! FFI stuff
+! Return values of this class go here
+GENERIC: return-reg ( reg-class -- reg )
+
+! Sequence of registers used for parameter passing in class
+GENERIC: param-regs ( reg-class -- regs )
+
+M: stack-params param-regs drop f ;
+
+GENERIC: param-reg ( n reg-class -- reg )
+
+M: reg-class param-reg param-regs nth ;
+
+M: stack-params param-reg drop ;
+
! Is this integer small enough to appear in value template
! slots?
HOOK: small-enough? cpu ( n -- ? )
HOOK: %prepare-unbox cpu ( -- )
-HOOK: %unbox cpu ( n reg-class func -- )
+HOOK: %unbox cpu ( n rep func -- )
HOOK: %unbox-long-long cpu ( n func -- )
HOOK: %unbox-large-struct cpu ( n c-type -- )
-HOOK: %box cpu ( n reg-class func -- )
+HOOK: %box cpu ( n rep func -- )
HOOK: %box-long-long cpu ( n func -- )
HOOK: %box-large-struct cpu ( n c-type -- )
-GENERIC: %save-param-reg ( stack reg reg-class -- )
+HOOK: %save-param-reg cpu ( stack reg rep -- )
-GENERIC: %load-param-reg ( stack reg reg-class -- )
+HOOK: %load-param-reg cpu ( stack reg rep -- )
HOOK: %prepare-alien-invoke cpu ( -- )
HOOK: %callback-return cpu ( params -- )
M: object %callback-return drop %return ;
-
-M: stack-params param-reg drop ;
-
-M: stack-params param-regs drop f ;
-IN: cpu.ppc.assembler.tests
USING: cpu.ppc.assembler tools.test arrays kernel namespaces
-make vocabs sequences ;
+make vocabs sequences byte-arrays.hex ;
FROM: cpu.ppc.assembler => B ;
+IN: cpu.ppc.assembler.tests
: test-assembler ( expected quot -- )
[ 1array ] [ [ B{ } make ] curry ] bi* unit-test ;
-B{ HEX: 38 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 ADDI ] test-assembler
-B{ HEX: 3c HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 ADDIS ] test-assembler
-B{ HEX: 30 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 ADDIC ] test-assembler
-B{ HEX: 34 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 ADDIC. ] test-assembler
-B{ HEX: 38 HEX: 40 HEX: 00 HEX: 01 } [ 1 2 LI ] test-assembler
-B{ HEX: 3c HEX: 40 HEX: 00 HEX: 01 } [ 1 2 LIS ] test-assembler
-B{ HEX: 38 HEX: 22 HEX: ff HEX: fd } [ 1 2 3 SUBI ] test-assembler
-B{ HEX: 1c HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 MULI ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1a HEX: 14 } [ 1 2 3 ADD ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1a HEX: 15 } [ 1 2 3 ADD. ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1e HEX: 14 } [ 1 2 3 ADDO ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1e HEX: 15 } [ 1 2 3 ADDO. ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 18 HEX: 14 } [ 1 2 3 ADDC ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 18 HEX: 15 } [ 1 2 3 ADDC. ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1e HEX: 14 } [ 1 2 3 ADDO ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1c HEX: 15 } [ 1 2 3 ADDCO. ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 19 HEX: 14 } [ 1 2 3 ADDE ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: 38 } [ 1 2 3 AND ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: 39 } [ 1 2 3 AND. ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1b HEX: d6 } [ 1 2 3 DIVW ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 1b HEX: 96 } [ 1 2 3 DIVWU ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1a HEX: 38 } [ 1 2 3 EQV ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1b HEX: b8 } [ 1 2 3 NAND ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: f8 } [ 1 2 3 NOR ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 10 HEX: f8 } [ 1 2 NOT ] test-assembler
-B{ HEX: 60 HEX: 41 HEX: 00 HEX: 03 } [ 1 2 3 ORI ] test-assembler
-B{ HEX: 64 HEX: 41 HEX: 00 HEX: 03 } [ 1 2 3 ORIS ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1b HEX: 78 } [ 1 2 3 OR ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 13 HEX: 78 } [ 1 2 MR ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 18 HEX: 96 } [ 1 2 3 MULHW ] test-assembler
-B{ HEX: 1c HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 MULLI ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 18 HEX: 16 } [ 1 2 3 MULHWU ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 19 HEX: d6 } [ 1 2 3 MULLW ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: 30 } [ 1 2 3 SLW ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1e HEX: 30 } [ 1 2 3 SRAW ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1c HEX: 30 } [ 1 2 3 SRW ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1e HEX: 70 } [ 1 2 3 SRAWI ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 18 HEX: 50 } [ 1 2 3 SUBF ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 18 HEX: 10 } [ 1 2 3 SUBFC ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 19 HEX: 10 } [ 1 2 3 SUBFE ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 07 HEX: 74 } [ 1 2 EXTSB ] test-assembler
-B{ HEX: 68 HEX: 41 HEX: 00 HEX: 03 } [ 1 2 3 XORI ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1a HEX: 78 } [ 1 2 3 XOR ] test-assembler
-B{ HEX: 7c HEX: 22 HEX: 00 HEX: d0 } [ 1 2 NEG ] test-assembler
-B{ HEX: 2c HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 CMPI ] test-assembler
-B{ HEX: 28 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 CMPLI ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: 00 } [ 1 2 3 CMP ] test-assembler
-B{ HEX: 54 HEX: 22 HEX: 19 HEX: 0a } [ 1 2 3 4 5 RLWINM ] test-assembler
-B{ HEX: 54 HEX: 22 HEX: 18 HEX: 38 } [ 1 2 3 SLWI ] test-assembler
-B{ HEX: 54 HEX: 22 HEX: e8 HEX: fe } [ 1 2 3 SRWI ] test-assembler
-B{ HEX: 88 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LBZ ] test-assembler
-B{ HEX: 8c HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LBZU ] test-assembler
-B{ HEX: a8 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LHA ] test-assembler
-B{ HEX: ac HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LHAU ] test-assembler
-B{ HEX: a0 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LHZ ] test-assembler
-B{ HEX: a4 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LHZU ] test-assembler
-B{ HEX: 80 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LWZ ] test-assembler
-B{ HEX: 84 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LWZU ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: ae } [ 1 2 3 LBZX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: ee } [ 1 2 3 LBZUX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1a HEX: ae } [ 1 2 3 LHAX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1a HEX: ee } [ 1 2 3 LHAUX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1a HEX: 2e } [ 1 2 3 LHZX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 1a HEX: 6e } [ 1 2 3 LHZUX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: 2e } [ 1 2 3 LWZX ] test-assembler
-B{ HEX: 7c HEX: 41 HEX: 18 HEX: 6e } [ 1 2 3 LWZUX ] test-assembler
-B{ HEX: 48 HEX: 00 HEX: 00 HEX: 01 } [ 1 B ] test-assembler
-B{ HEX: 48 HEX: 00 HEX: 00 HEX: 01 } [ 1 BL ] test-assembler
-B{ HEX: 41 HEX: 80 HEX: 00 HEX: 04 } [ 1 BLT ] test-assembler
-B{ HEX: 41 HEX: 81 HEX: 00 HEX: 04 } [ 1 BGT ] test-assembler
-B{ HEX: 40 HEX: 81 HEX: 00 HEX: 04 } [ 1 BLE ] test-assembler
-B{ HEX: 40 HEX: 80 HEX: 00 HEX: 04 } [ 1 BGE ] test-assembler
-B{ HEX: 41 HEX: 80 HEX: 00 HEX: 04 } [ 1 BLT ] test-assembler
-B{ HEX: 40 HEX: 82 HEX: 00 HEX: 04 } [ 1 BNE ] test-assembler
-B{ HEX: 41 HEX: 82 HEX: 00 HEX: 04 } [ 1 BEQ ] test-assembler
-B{ HEX: 41 HEX: 83 HEX: 00 HEX: 04 } [ 1 BO ] test-assembler
-B{ HEX: 40 HEX: 83 HEX: 00 HEX: 04 } [ 1 BNO ] test-assembler
-B{ HEX: 4c HEX: 20 HEX: 00 HEX: 20 } [ 1 BCLR ] test-assembler
-B{ HEX: 4e HEX: 80 HEX: 00 HEX: 20 } [ BLR ] test-assembler
-B{ HEX: 4e HEX: 80 HEX: 00 HEX: 21 } [ BLRL ] test-assembler
-B{ HEX: 4c HEX: 20 HEX: 04 HEX: 20 } [ 1 BCCTR ] test-assembler
-B{ HEX: 4e HEX: 80 HEX: 04 HEX: 20 } [ BCTR ] test-assembler
-B{ HEX: 7c HEX: 61 HEX: 02 HEX: a6 } [ 3 MFXER ] test-assembler
-B{ HEX: 7c HEX: 68 HEX: 02 HEX: a6 } [ 3 MFLR ] test-assembler
-B{ HEX: 7c HEX: 69 HEX: 02 HEX: a6 } [ 3 MFCTR ] test-assembler
-B{ HEX: 7c HEX: 61 HEX: 03 HEX: a6 } [ 3 MTXER ] test-assembler
-B{ HEX: 7c HEX: 68 HEX: 03 HEX: a6 } [ 3 MTLR ] test-assembler
-B{ HEX: 7c HEX: 69 HEX: 03 HEX: a6 } [ 3 MTCTR ] test-assembler
-B{ HEX: 7c HEX: 61 HEX: 02 HEX: a6 } [ 3 MFXER ] test-assembler
-B{ HEX: 7c HEX: 68 HEX: 02 HEX: a6 } [ 3 MFLR ] test-assembler
-B{ HEX: c0 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LFS ] test-assembler
-B{ HEX: c4 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LFSU ] test-assembler
-B{ HEX: c8 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LFD ] test-assembler
-B{ HEX: cc HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 LFDU ] test-assembler
-B{ HEX: d0 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 STFS ] test-assembler
-B{ HEX: d4 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 STFSU ] test-assembler
-B{ HEX: d8 HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 STFD ] test-assembler
-B{ HEX: dc HEX: 22 HEX: 00 HEX: 03 } [ 1 2 3 STFDU ] test-assembler
-B{ HEX: fc HEX: 20 HEX: 10 HEX: 48 } [ 1 2 FMR ] test-assembler
-B{ HEX: fc HEX: 20 HEX: 10 HEX: 1e } [ 1 2 FCTIWZ ] test-assembler
-B{ HEX: fc HEX: 22 HEX: 18 HEX: 2a } [ 1 2 3 FADD ] test-assembler
-B{ HEX: fc HEX: 22 HEX: 18 HEX: 2b } [ 1 2 3 FADD. ] test-assembler
-B{ HEX: fc HEX: 22 HEX: 18 HEX: 28 } [ 1 2 3 FSUB ] test-assembler
-B{ HEX: fc HEX: 22 HEX: 00 HEX: f2 } [ 1 2 3 FMUL ] test-assembler
-B{ HEX: fc HEX: 22 HEX: 18 HEX: 24 } [ 1 2 3 FDIV ] test-assembler
-B{ HEX: fc HEX: 20 HEX: 10 HEX: 2c } [ 1 2 FSQRT ] test-assembler
-B{ HEX: fc HEX: 41 HEX: 18 HEX: 00 } [ 1 2 3 FCMPU ] test-assembler
-B{ HEX: fc HEX: 41 HEX: 18 HEX: 40 } [ 1 2 3 FCMPO ] test-assembler
-B{ HEX: 3c HEX: 60 HEX: 12 HEX: 34 HEX: 60 HEX: 63 HEX: 56 HEX: 78 } [ HEX: 12345678 3 LOAD ] test-assembler
+HEX{ 38 22 00 03 } [ 1 2 3 ADDI ] test-assembler
+HEX{ 3c 22 00 03 } [ 1 2 3 ADDIS ] test-assembler
+HEX{ 30 22 00 03 } [ 1 2 3 ADDIC ] test-assembler
+HEX{ 34 22 00 03 } [ 1 2 3 ADDIC. ] test-assembler
+HEX{ 38 40 00 01 } [ 1 2 LI ] test-assembler
+HEX{ 3c 40 00 01 } [ 1 2 LIS ] test-assembler
+HEX{ 38 22 ff fd } [ 1 2 3 SUBI ] test-assembler
+HEX{ 1c 22 00 03 } [ 1 2 3 MULI ] test-assembler
+HEX{ 7c 22 1a 14 } [ 1 2 3 ADD ] test-assembler
+HEX{ 7c 22 1a 15 } [ 1 2 3 ADD. ] test-assembler
+HEX{ 7c 22 1e 14 } [ 1 2 3 ADDO ] test-assembler
+HEX{ 7c 22 1e 15 } [ 1 2 3 ADDO. ] test-assembler
+HEX{ 7c 22 18 14 } [ 1 2 3 ADDC ] test-assembler
+HEX{ 7c 22 18 15 } [ 1 2 3 ADDC. ] test-assembler
+HEX{ 7c 22 1e 14 } [ 1 2 3 ADDO ] test-assembler
+HEX{ 7c 22 1c 15 } [ 1 2 3 ADDCO. ] test-assembler
+HEX{ 7c 22 19 14 } [ 1 2 3 ADDE ] test-assembler
+HEX{ 7c 41 18 38 } [ 1 2 3 AND ] test-assembler
+HEX{ 7c 41 18 39 } [ 1 2 3 AND. ] test-assembler
+HEX{ 7c 22 1b d6 } [ 1 2 3 DIVW ] test-assembler
+HEX{ 7c 22 1b 96 } [ 1 2 3 DIVWU ] test-assembler
+HEX{ 7c 41 1a 38 } [ 1 2 3 EQV ] test-assembler
+HEX{ 7c 41 1b b8 } [ 1 2 3 NAND ] test-assembler
+HEX{ 7c 41 18 f8 } [ 1 2 3 NOR ] test-assembler
+HEX{ 7c 41 10 f8 } [ 1 2 NOT ] test-assembler
+HEX{ 60 41 00 03 } [ 1 2 3 ORI ] test-assembler
+HEX{ 64 41 00 03 } [ 1 2 3 ORIS ] test-assembler
+HEX{ 7c 41 1b 78 } [ 1 2 3 OR ] test-assembler
+HEX{ 7c 41 13 78 } [ 1 2 MR ] test-assembler
+HEX{ 7c 22 18 96 } [ 1 2 3 MULHW ] test-assembler
+HEX{ 1c 22 00 03 } [ 1 2 3 MULLI ] test-assembler
+HEX{ 7c 22 18 16 } [ 1 2 3 MULHWU ] test-assembler
+HEX{ 7c 22 19 d6 } [ 1 2 3 MULLW ] test-assembler
+HEX{ 7c 41 18 30 } [ 1 2 3 SLW ] test-assembler
+HEX{ 7c 41 1e 30 } [ 1 2 3 SRAW ] test-assembler
+HEX{ 7c 41 1c 30 } [ 1 2 3 SRW ] test-assembler
+HEX{ 7c 41 1e 70 } [ 1 2 3 SRAWI ] test-assembler
+HEX{ 7c 22 18 50 } [ 1 2 3 SUBF ] test-assembler
+HEX{ 7c 22 18 10 } [ 1 2 3 SUBFC ] test-assembler
+HEX{ 7c 22 19 10 } [ 1 2 3 SUBFE ] test-assembler
+HEX{ 7c 41 07 74 } [ 1 2 EXTSB ] test-assembler
+HEX{ 68 41 00 03 } [ 1 2 3 XORI ] test-assembler
+HEX{ 7c 41 1a 78 } [ 1 2 3 XOR ] test-assembler
+HEX{ 7c 22 00 d0 } [ 1 2 NEG ] test-assembler
+HEX{ 2c 22 00 03 } [ 1 2 3 CMPI ] test-assembler
+HEX{ 28 22 00 03 } [ 1 2 3 CMPLI ] test-assembler
+HEX{ 7c 41 18 00 } [ 1 2 3 CMP ] test-assembler
+HEX{ 54 22 19 0a } [ 1 2 3 4 5 RLWINM ] test-assembler
+HEX{ 54 22 18 38 } [ 1 2 3 SLWI ] test-assembler
+HEX{ 54 22 e8 fe } [ 1 2 3 SRWI ] test-assembler
+HEX{ 88 22 00 03 } [ 1 2 3 LBZ ] test-assembler
+HEX{ 8c 22 00 03 } [ 1 2 3 LBZU ] test-assembler
+HEX{ a8 22 00 03 } [ 1 2 3 LHA ] test-assembler
+HEX{ ac 22 00 03 } [ 1 2 3 LHAU ] test-assembler
+HEX{ a0 22 00 03 } [ 1 2 3 LHZ ] test-assembler
+HEX{ a4 22 00 03 } [ 1 2 3 LHZU ] test-assembler
+HEX{ 80 22 00 03 } [ 1 2 3 LWZ ] test-assembler
+HEX{ 84 22 00 03 } [ 1 2 3 LWZU ] test-assembler
+HEX{ 7c 41 18 ae } [ 1 2 3 LBZX ] test-assembler
+HEX{ 7c 41 18 ee } [ 1 2 3 LBZUX ] test-assembler
+HEX{ 7c 41 1a ae } [ 1 2 3 LHAX ] test-assembler
+HEX{ 7c 41 1a ee } [ 1 2 3 LHAUX ] test-assembler
+HEX{ 7c 41 1a 2e } [ 1 2 3 LHZX ] test-assembler
+HEX{ 7c 41 1a 6e } [ 1 2 3 LHZUX ] test-assembler
+HEX{ 7c 41 18 2e } [ 1 2 3 LWZX ] test-assembler
+HEX{ 7c 41 18 6e } [ 1 2 3 LWZUX ] test-assembler
+HEX{ 48 00 00 01 } [ 1 B ] test-assembler
+HEX{ 48 00 00 01 } [ 1 BL ] test-assembler
+HEX{ 41 80 00 04 } [ 1 BLT ] test-assembler
+HEX{ 41 81 00 04 } [ 1 BGT ] test-assembler
+HEX{ 40 81 00 04 } [ 1 BLE ] test-assembler
+HEX{ 40 80 00 04 } [ 1 BGE ] test-assembler
+HEX{ 41 80 00 04 } [ 1 BLT ] test-assembler
+HEX{ 40 82 00 04 } [ 1 BNE ] test-assembler
+HEX{ 41 82 00 04 } [ 1 BEQ ] test-assembler
+HEX{ 41 83 00 04 } [ 1 BO ] test-assembler
+HEX{ 40 83 00 04 } [ 1 BNO ] test-assembler
+HEX{ 4c 20 00 20 } [ 1 BCLR ] test-assembler
+HEX{ 4e 80 00 20 } [ BLR ] test-assembler
+HEX{ 4e 80 00 21 } [ BLRL ] test-assembler
+HEX{ 4c 20 04 20 } [ 1 BCCTR ] test-assembler
+HEX{ 4e 80 04 20 } [ BCTR ] test-assembler
+HEX{ 7c 61 02 a6 } [ 3 MFXER ] test-assembler
+HEX{ 7c 68 02 a6 } [ 3 MFLR ] test-assembler
+HEX{ 7c 69 02 a6 } [ 3 MFCTR ] test-assembler
+HEX{ 7c 61 03 a6 } [ 3 MTXER ] test-assembler
+HEX{ 7c 68 03 a6 } [ 3 MTLR ] test-assembler
+HEX{ 7c 69 03 a6 } [ 3 MTCTR ] test-assembler
+HEX{ 7c 61 02 a6 } [ 3 MFXER ] test-assembler
+HEX{ 7c 68 02 a6 } [ 3 MFLR ] test-assembler
+HEX{ c0 22 00 03 } [ 1 2 3 LFS ] test-assembler
+HEX{ c4 22 00 03 } [ 1 2 3 LFSU ] test-assembler
+HEX{ c8 22 00 03 } [ 1 2 3 LFD ] test-assembler
+HEX{ cc 22 00 03 } [ 1 2 3 LFDU ] test-assembler
+HEX{ d0 22 00 03 } [ 1 2 3 STFS ] test-assembler
+HEX{ d4 22 00 03 } [ 1 2 3 STFSU ] test-assembler
+HEX{ d8 22 00 03 } [ 1 2 3 STFD ] test-assembler
+HEX{ dc 22 00 03 } [ 1 2 3 STFDU ] test-assembler
+HEX{ fc 20 10 90 } [ 1 2 FMR ] test-assembler
+HEX{ fc 40 08 90 } [ 2 1 FMR ] test-assembler
+HEX{ fc 20 10 91 } [ 1 2 FMR. ] test-assembler
+HEX{ fc 40 08 91 } [ 2 1 FMR. ] test-assembler
+HEX{ fc 20 10 1e } [ 1 2 FCTIWZ ] test-assembler
+HEX{ fc 22 18 2a } [ 1 2 3 FADD ] test-assembler
+HEX{ fc 22 18 2b } [ 1 2 3 FADD. ] test-assembler
+HEX{ fc 22 18 28 } [ 1 2 3 FSUB ] test-assembler
+HEX{ fc 22 00 f2 } [ 1 2 3 FMUL ] test-assembler
+HEX{ fc 22 18 24 } [ 1 2 3 FDIV ] test-assembler
+HEX{ fc 20 10 2c } [ 1 2 FSQRT ] test-assembler
+HEX{ fc 41 18 00 } [ 1 2 3 FCMPU ] test-assembler
+HEX{ fc 41 18 40 } [ 1 2 3 FCMPO ] test-assembler
+HEX{ 3c 60 12 34 60 63 56 78 } [ HEX: 12345678 3 LOAD ] test-assembler
-! Copyright (C) 2005, 2008 Slava Pestov.
+! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces words io.binary math math.order
+USING: kernel namespaces words math math.order locals
cpu.ppc.assembler.backend ;
IN: cpu.ppc.assembler
X: XOR. 1 316 31
X1: EXTSB 0 954 31
X1: EXTSB. 1 954 31
-: FMR ( a s -- ) [ 0 ] 2dip 72 0 63 x-insn ;
-: FMR. ( a s -- ) [ 0 ] 2dip 72 1 63 x-insn ;
+: FMR ( a s -- ) [ 0 ] 2dip 0 72 63 x-insn ;
+: FMR. ( a s -- ) [ 0 ] 2dip 1 72 63 x-insn ;
: FCTIWZ ( a s -- ) [ 0 ] 2dip 0 15 63 x-insn ;
: FCTIWZ. ( a s -- ) [ 0 ] 2dip 1 15 63 x-insn ;
MTSPR: CTR 9
! Pseudo-instructions
-: LI ( value dst -- ) 0 rot ADDI ; inline
+: LI ( value dst -- ) swap [ 0 ] dip ADDI ; inline
: SUBI ( dst src1 src2 -- ) neg ADDI ; inline
-: LIS ( value dst -- ) 0 rot ADDIS ; inline
+: LIS ( value dst -- ) swap [ 0 ] dip ADDIS ; inline
: SUBIC ( dst src1 src2 -- ) neg ADDIC ; inline
: SUBIC. ( dst src1 src2 -- ) neg ADDIC. ; inline
: NOT ( dst src -- ) dup NOR ; inline
: (SRWI) ( d a b -- d a b x y ) 32 over - swap 31 ; inline
: SRWI ( d a b -- ) (SRWI) RLWINM ;
: SRWI. ( d a b -- ) (SRWI) RLWINM. ;
-: LOAD32 ( n r -- ) [ w>h/h ] dip tuck LIS dup rot ORI ;
+:: LOAD32 ( n r -- )
+ n -16 shift HEX: ffff bitand r LIS
+ r r n HEX: ffff bitand ORI ;
: immediate? ( n -- ? ) HEX: -8000 HEX: 7fff between? ;
: LOAD ( n r -- ) over immediate? [ LI ] [ LOAD32 ] if ;
! key = class\r
5 4 MR\r
! key &= cache.length - 1\r
- 5 5 mega-cache-size get 1- bootstrap-cell * ANDI\r
+ 5 5 mega-cache-size get 1 - bootstrap-cell * ANDI\r
! cache += array-start-offset\r
3 3 array-start-offset ADDI\r
! cache += key\r
USING: accessors assocs sequences kernel combinators make math
math.order math.ranges system namespaces locals layouts words
alien alien.accessors alien.c-types literals cpu.architecture
-cpu.ppc.assembler cpu.ppc.assembler.backend literals compiler.cfg.registers
-compiler.cfg.instructions compiler.constants compiler.codegen
+cpu.ppc.assembler cpu.ppc.assembler.backend compiler.cfg.registers
+compiler.cfg.instructions compiler.cfg.comparisons
compiler.codegen.fixup compiler.cfg.intrinsics
-compiler.cfg.stack-frame compiler.units ;
+compiler.cfg.stack-frame compiler.cfg.build-stack-frame
+compiler.units compiler.constants compiler.codegen ;
FROM: cpu.ppc.assembler => B ;
IN: cpu.ppc
M: ppc machine-registers
{
{ int-regs $[ 2 12 [a,b] 15 29 [a,b] append ] }
- { double-float-regs $[ 0 29 [a,b] ] }
+ { float-regs $[ 0 29 [a,b] ] }
} ;
CONSTANT: scratch-reg 30
M: ppc %peek loc>operand LWZ ;
M: ppc %replace loc>operand STW ;
-: (%inc) ( n reg -- ) dup rot cells ADDI ; inline
+:: (%inc) ( n reg -- ) reg reg n cells ADDI ; inline
M: ppc %inc-d ( n -- ) ds-reg (%inc) ;
M: ppc %inc-r ( n -- ) rs-reg (%inc) ;
: xt-save ( n -- i ) 2 cells - ;
! Next, we have the spill area as well as the FFI parameter area.
-! They overlap, since basic blocks with FFI calls will never
-! spill.
+! It is safe for them to overlap, since basic blocks with FFI calls
+! will never spill -- indeed, basic blocks with FFI calls do not
+! use vregs at all, and the FFI call is a stack analysis sync point.
+! In the future this will change and the stack frame logic will
+! need to be untangled somewhat.
+
: param@ ( n -- x ) reserved-area-size + ; inline
: param-save-size ( -- n ) 8 cells ; foldable
: local@ ( n -- x )
reserved-area-size param-save-size + + ; inline
-: spill-integer-base ( -- n )
- stack-frame get spill-counts>> double-float-regs swap at
- double-float-regs reg-size * ;
-
-: spill-integer@ ( n -- offset )
- cells spill-integer-base + param@ ;
-
-: spill-float@ ( n -- offset )
- double-float-regs reg-size * param@ ;
+: spill@ ( n -- offset )
+ spill-offset local@ ;
! Some FP intrinsics need a temporary scratch area in the stack
-! frame, 8 bytes in size
+! frame, 8 bytes in size. This is in the param-save area so it
+! does not overlap with spill slots.
: scratch@ ( n -- offset )
- stack-frame get total-size>>
- factor-area-size -
- param-save-size -
- + ;
+ factor-area-size + ;
+
+! GC root area
+: gc-root@ ( n -- offset )
+ gc-root-offset local@ ;
! Finally we have the linkage area
HOOK: lr-save os ( -- n )
M: ppc stack-frame-size ( stack-frame -- i )
- [ spill-counts>> [ swap reg-size * ] { } assoc>map sum ]
- [ params>> ]
- [ return>> ]
- tri + +
+ (stack-frame-size)
param-save-size +
reserved-area-size +
factor-area-size +
M: ppc %or-imm ORI ;
M: ppc %xor XOR ;
M: ppc %xor-imm XORI ;
+M: ppc %shl SLW ;
M: ppc %shl-imm swapd SLWI ;
+M: ppc %shr SRW ;
M: ppc %shr-imm swapd SRWI ;
+M: ppc %sar SRAW ;
M: ppc %sar-imm SRAWI ;
M: ppc %not NOT ;
-: %alien-invoke-tail ( func dll -- )
- [ scratch-reg ] 2dip %alien-global scratch-reg MTCTR BCTR ;
-
-:: exchange-regs ( r1 r2 -- )
- scratch-reg r1 MR
- r1 r2 MR
- r2 scratch-reg MR ;
-
-: ?MR ( r1 r2 -- ) 2dup = [ 2drop ] [ MR ] if ;
-
-:: move>args ( src1 src2 -- )
- {
- { [ src1 4 = ] [ 3 src2 ?MR 3 4 exchange-regs ] }
- { [ src1 3 = ] [ 4 src2 ?MR ] }
- { [ src2 3 = ] [ 4 src1 ?MR 3 4 exchange-regs ] }
- { [ src2 4 = ] [ 3 src1 ?MR ] }
- [ 3 src1 MR 4 src2 MR ]
- } cond ;
-
-: clear-xer ( -- )
+:: overflow-template ( label dst src1 src2 insn -- )
0 0 LI
- 0 MTXER ; inline
-
-:: overflow-template ( src1 src2 insn func -- )
- "no-overflow" define-label
- clear-xer
- scratch-reg src2 src1 insn call
- scratch-reg ds-reg 0 STW
- "no-overflow" get BNO
- src1 src2 move>args
- %prepare-alien-invoke
- func f %alien-invoke
- "no-overflow" resolve-label ; inline
-
-:: overflow-template-tail ( src1 src2 insn func -- )
- "overflow" define-label
- clear-xer
- scratch-reg src2 src1 insn call
- "overflow" get BO
- scratch-reg ds-reg 0 STW
- BLR
- "overflow" resolve-label
- src1 src2 move>args
- %prepare-alien-invoke
- func f %alien-invoke-tail ; inline
-
-M: ppc %fixnum-add ( src1 src2 -- )
- [ ADDO. ] "overflow_fixnum_add" overflow-template ;
+ 0 MTXER
+ dst src2 src1 insn call
+ label BO ; inline
-M: ppc %fixnum-add-tail ( src1 src2 -- )
- [ ADDO. ] "overflow_fixnum_add" overflow-template-tail ;
+M: ppc %fixnum-add ( label dst src1 src2 -- )
+ [ ADDO. ] overflow-template ;
-M: ppc %fixnum-sub ( src1 src2 -- )
- [ SUBFO. ] "overflow_fixnum_subtract" overflow-template ;
+M: ppc %fixnum-sub ( label dst src1 src2 -- )
+ [ SUBFO. ] overflow-template ;
-M: ppc %fixnum-sub-tail ( src1 src2 -- )
- [ SUBFO. ] "overflow_fixnum_subtract" overflow-template-tail ;
-
-M:: ppc %fixnum-mul ( src1 src2 temp1 temp2 -- )
- "no-overflow" define-label
- clear-xer
- temp1 src1 tag-bits get SRAWI
- temp2 temp1 src2 MULLWO.
- temp2 ds-reg 0 STW
- "no-overflow" get BNO
- src2 src2 tag-bits get SRAWI
- temp1 src2 move>args
- %prepare-alien-invoke
- "overflow_fixnum_multiply" f %alien-invoke
- "no-overflow" resolve-label ;
-
-M:: ppc %fixnum-mul-tail ( src1 src2 temp1 temp2 -- )
- "overflow" define-label
- clear-xer
- temp1 src1 tag-bits get SRAWI
- temp2 temp1 src2 MULLWO.
- "overflow" get BO
- temp2 ds-reg 0 STW
- BLR
- "overflow" resolve-label
- src2 src2 tag-bits get SRAWI
- temp1 src2 move>args
- %prepare-alien-invoke
- "overflow_fixnum_multiply" f %alien-invoke-tail ;
+M: ppc %fixnum-mul ( label dst src1 src2 -- )
+ [ MULLWO. ] overflow-template ;
: bignum@ ( n -- offset ) cells bignum tag-number - ; inline
temp dst 1 bignum@ STW
! Compute sign
temp src MR
- temp temp cell-bits 1- SRAWI
+ temp temp cell-bits 1 - SRAWI
temp temp 1 ANDI
! Store sign
temp dst 2 bignum@ STW
fp-scratch-reg 1 0 scratch@ STFD
dst 1 4 scratch@ LWZ ;
-M: ppc %copy ( dst src -- ) MR ;
-
-M: ppc %copy-float ( dst src -- ) FMR ;
+M: ppc %copy ( dst src rep -- )
+ {
+ { int-rep [ MR ] }
+ { double-float-rep [ FMR ] }
+ } case ;
M: ppc %unbox-float ( dst src -- ) float-offset LFD ;
: alien@ ( n -- n' ) cells object tag-number - ;
+:: %allot-alien ( dst base displacement temp -- )
+ dst 4 cells alien temp %allot
+ temp \ f tag-number %load-immediate
+ ! Store expired slot
+ temp dst 1 alien@ STW
+ ! Store underlying-alien slot
+ base dst 2 alien@ STW
+ ! Store offset
+ displacement dst 3 alien@ STW ;
+
M:: ppc %box-alien ( dst src temp -- )
[
"f" define-label
dst \ f tag-number %load-immediate
0 src 0 CMPI
"f" get BEQ
- dst 4 cells alien temp %allot
- ! Store offset
- src dst 3 alien@ STW
- ! Store expired slot
- temp \ f tag-number %load-immediate
- temp dst 1 alien@ STW
- ! Store underlying-alien slot
- temp dst 2 alien@ STW
+ dst temp src temp %allot-alien
"f" resolve-label
] with-scope ;
+M:: ppc %box-displaced-alien ( dst displacement base temp -- )
+ [
+ "end" define-label
+ "ok" define-label
+ ! If displacement is zero, return the base
+ dst base MR
+ 0 displacement 0 CMPI
+ "end" get BEQ
+ ! If base is already a displaced alien, unpack it
+ 0 base \ f tag-number CMPI
+ "ok" get BEQ
+ temp base header-offset LWZ
+ 0 temp alien type-number tag-fixnum CMPI
+ "ok" get BEQ
+ ! displacement += base.displacement
+ temp base 3 alien@ LWZ
+ displacement displacement temp ADD
+ ! base = base.base
+ base base 1 alien@ LWZ
+ "ok" resolve-label
+ dst base displacement temp %allot-alien
+ "end" resolve-label
+ ] with-scope ;
+
M: ppc %alien-unsigned-1 0 LBZ ;
M: ppc %alien-unsigned-2 0 LHZ ;
src card# deck-bits SRWI
table scratch-reg card# STBX ;
-M: ppc %gc
- "end" define-label
- 12 load-zone-ptr
- 11 12 cell LWZ ! nursery.here -> r11
- 12 12 3 cells LWZ ! nursery.end -> r12
- 11 11 1024 ADDI ! add ALLOT_BUFFER_ZONE to here
- 11 0 12 CMP ! is here >= end?
- "end" get BLE
+M:: ppc %check-nursery ( label temp1 temp2 -- )
+ temp2 load-zone-ptr
+ temp1 temp2 cell LWZ
+ temp2 temp2 3 cells LWZ
+ ! add ALLOT_BUFFER_ZONE to here
+ temp1 temp1 1024 ADDI
+ ! is here >= end?
+ temp1 0 temp2 CMP
+ label BLE ;
+
+M:: ppc %save-gc-root ( gc-root register -- )
+ register 1 gc-root gc-root@ STW ;
+
+M:: ppc %load-gc-root ( gc-root register -- )
+ register 1 gc-root gc-root@ LWZ ;
+
+M:: ppc %call-gc ( gc-root-count -- )
%prepare-alien-invoke
- "minor_gc" f %alien-invoke
- "end" resolve-label ;
+ 3 1 gc-root-base local@ ADDI
+ gc-root-count 4 LI
+ "inline_gc" f %alien-invoke ;
M: ppc %prologue ( n -- )
0 11 LOAD32 rc-absolute-ppc-2/2 rel-this
M: ppc %compare-imm-branch (%compare-imm) %branch ;
M: ppc %compare-float-branch (%compare-float) %branch ;
-M: ppc %spill-integer ( src n -- ) spill-integer@ 1 swap STW ;
-M: ppc %reload-integer ( dst n -- ) spill-integer@ 1 swap LWZ ;
+: load-from-frame ( dst n rep -- )
+ {
+ { int-rep [ [ 1 ] dip LWZ ] }
+ { single-float-rep [ [ 1 ] dip LFS ] }
+ { double-float-rep [ [ 1 ] dip LFD ] }
+ { stack-params [ [ 0 1 ] dip LWZ [ 0 1 ] dip param@ STW ] }
+ } case ;
+
+: next-param@ ( n -- x ) param@ stack-frame get total-size>> + ;
+
+: store-to-frame ( src n rep -- )
+ {
+ { int-rep [ [ 1 ] dip STW ] }
+ { single-float-rep [ [ 1 ] dip STFS ] }
+ { double-float-rep [ [ 1 ] dip STFD ] }
+ { stack-params [ [ [ 0 1 ] dip next-param@ LWZ 0 1 ] dip STW ] }
+ } case ;
+
+M: ppc %spill ( src n rep -- )
+ [ spill@ ] dip store-to-frame ;
-M: ppc %spill-float ( src n -- ) spill-float@ 1 swap STFD ;
-M: ppc %reload-float ( dst n -- ) spill-float@ 1 swap LFD ;
+M: ppc %reload ( dst n rep -- )
+ [ spill@ ] dip load-from-frame ;
M: ppc %loop-entry ;
M: int-regs param-regs drop { 3 4 5 6 7 8 9 10 } ;
M: float-regs return-reg drop 1 ;
-M: int-regs %save-param-reg drop 1 rot local@ STW ;
-M: int-regs %load-param-reg drop 1 rot local@ LWZ ;
-
-GENERIC: STF ( src dst off reg-class -- )
-
-M: single-float-regs STF drop STFS ;
-M: double-float-regs STF drop STFD ;
-
-M: float-regs %save-param-reg [ 1 rot local@ ] dip STF ;
-
-GENERIC: LF ( dst src off reg-class -- )
-
-M: single-float-regs LF drop LFS ;
-M: double-float-regs LF drop LFD ;
-
-M: float-regs %load-param-reg [ 1 rot local@ ] dip LF ;
-
-M: stack-params %load-param-reg ( stack reg reg-class -- )
- drop [ 0 1 rot local@ LWZ 0 1 ] dip param@ STW ;
-
-: next-param@ ( n -- x ) param@ stack-frame get total-size>> + ;
+M:: ppc %save-param-reg ( stack reg rep -- )
+ reg stack local@ rep store-to-frame ;
-M: stack-params %save-param-reg ( stack reg reg-class -- )
- #! Funky. Read the parameter from the caller's stack frame.
- #! This word is used in callbacks
- drop
- [ 0 1 ] dip next-param@ LWZ
- [ 0 1 ] dip local@ STW ;
+M:: ppc %load-param-reg ( stack reg rep -- )
+ reg stack local@ rep load-from-frame ;
M: ppc %prepare-unbox ( -- )
! First parameter is top of stack
3 ds-reg 0 LWZ
ds-reg dup cell SUBI ;
-M: ppc %unbox ( n reg-class func -- )
+M: ppc %unbox ( n rep func -- )
! Value must be in r3
! Call the unboxer
f %alien-invoke
! Store the return value on the C stack
- over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
+ over [ [ reg-class-of return-reg ] keep %save-param-reg ] [ 2drop ] if ;
M: ppc %unbox-long-long ( n func -- )
! Value must be in r3:r4
! Call the function
"to_value_struct" f %alien-invoke ;
-M: ppc %box ( n reg-class func -- )
+M: ppc %box ( n rep func -- )
! If the source is a stack location, load it into freg #0.
! If the source is f, then we assume the value is already in
! freg #0.
- [ over [ 0 over param-reg swap %load-param-reg ] [ 2drop ] if ] dip
+ [ over [ 0 over reg-class-of param-reg swap %load-param-reg ] [ 2drop ] if ] dip
f %alien-invoke ;
M: ppc %box-long-long ( n func -- )
-! Copyright (C) 2005, 2008 Slava Pestov.
+! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: locals alien.c-types alien.syntax arrays kernel
-math namespaces sequences system layouts io vocabs.loader
-accessors init combinators command-line cpu.x86.assembler
-cpu.x86 cpu.architecture make compiler compiler.units
+USING: locals alien.c-types alien.syntax arrays kernel fry math
+namespaces sequences system layouts io vocabs.loader accessors init
+combinators command-line make compiler compiler.units
compiler.constants compiler.alien compiler.codegen
-compiler.codegen.fixup compiler.cfg.instructions
-compiler.cfg.builder compiler.cfg.intrinsics
-compiler.cfg.stack-frame ;
+compiler.codegen.fixup compiler.cfg.instructions compiler.cfg.builder
+compiler.cfg.intrinsics compiler.cfg.stack-frame cpu.x86.assembler
+cpu.x86.assembler.operands cpu.x86 cpu.architecture ;
IN: cpu.x86.32
! We implement the FFI for Linux, OS X and Windows all at once.
-! OS X requires that the stack be 16-byte aligned, and we do
-! this on all platforms, sacrificing some stack space for
-! code simplicity.
+! OS X requires that the stack be 16-byte aligned.
M: x86.32 machine-registers
{
{ int-regs { EAX ECX EDX EBP EBX } }
- { double-float-regs { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } }
+ { float-regs { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } }
} ;
M: x86.32 ds-reg ESI ;
M: x86.32 rs-reg EDI ;
M: x86.32 stack-reg ESP ;
-M: x86.32 temp-reg-1 ECX ;
-M: x86.32 temp-reg-2 EDX ;
+M: x86.32 temp-reg ECX ;
M:: x86.32 %dispatch ( src temp -- )
! Load jump table base.
- src HEX: ffffffff ADD
+ temp src HEX: ffffffff [+] LEA
+ building get length cell - :> start
0 rc-absolute-cell rel-here
! Go
- src HEX: 7f [+] JMP
+ temp HEX: 7f [+] JMP
+ building get length :> end
! Fix up the displacement above
cell code-alignment
- [ 7 + building get dup pop* push ]
+ [ end start - + building get dup pop* push ]
[ align-code ]
bi ;
M: x86.32 %alien-invoke 0 CALL rc-relative rel-dlsym ;
-M: x86.32 %alien-invoke-tail 0 JMP rc-relative rel-dlsym ;
-
M: x86.32 return-struct-in-registers? ( c-type -- ? )
c-type
[ return-in-registers?>> ]
! On x86, parameters are never passed in registers.
M: int-regs return-reg drop EAX ;
M: int-regs param-regs drop { } ;
-M: int-regs push-return-reg return-reg PUSH ;
-
-M: int-regs load-return-reg
- return-reg swap next-stack@ MOV ;
-
-M: int-regs store-return-reg
- [ stack@ ] [ return-reg ] bi* MOV ;
-
M: float-regs param-regs drop { } ;
-: FSTP ( operand size -- ) 4 = [ FSTPS ] [ FSTPL ] if ;
+GENERIC: push-return-reg ( rep -- )
+GENERIC: load-return-reg ( n rep -- )
+GENERIC: store-return-reg ( n rep -- )
-M: float-regs push-return-reg
- stack-reg swap reg-size
- [ SUB ] [ [ [] ] dip FSTP ] 2bi ;
+M: int-rep push-return-reg drop EAX PUSH ;
+M: int-rep load-return-reg drop EAX swap next-stack@ MOV ;
+M: int-rep store-return-reg drop stack@ EAX MOV ;
-: FLD ( operand size -- ) 4 = [ FLDS ] [ FLDL ] if ;
+M: single-float-rep push-return-reg drop ESP 4 SUB ESP [] FSTPS ;
+M: single-float-rep load-return-reg drop next-stack@ FLDS ;
+M: single-float-rep store-return-reg drop stack@ FSTPS ;
-M: float-regs load-return-reg
- [ next-stack@ ] [ reg-size ] bi* FLD ;
-
-M: float-regs store-return-reg
- [ stack@ ] [ reg-size ] bi* FSTP ;
+M: double-float-rep push-return-reg drop ESP 8 SUB ESP [] FSTPL ;
+M: double-float-rep load-return-reg drop next-stack@ FLDL ;
+M: double-float-rep store-return-reg drop stack@ FSTPL ;
: align-sub ( n -- )
[ align-stack ] keep - decr-stack-reg ;
align-stack incr-stack-reg ;
: with-aligned-stack ( n quot -- )
- [ [ align-sub ] [ call ] bi* ]
- [ [ align-add ] [ drop ] bi* ] 2bi ; inline
+ '[ align-sub @ ] [ align-add ] bi ; inline
M: x86.32 %prologue ( n -- )
dup PUSH
0 PUSH rc-absolute-cell rel-this
- stack-reg swap 3 cells - SUB ;
+ 3 cells - decr-stack-reg ;
-M: object %load-param-reg 3drop ;
+M: x86.32 %load-param-reg 3drop ;
-M: object %save-param-reg 3drop ;
+M: x86.32 %save-param-reg 3drop ;
-: (%box) ( n reg-class -- )
+: (%box) ( n rep -- )
#! If n is f, push the return register onto the stack; we
#! are boxing a return value of a C function. If n is an
#! integer, push [ESP+n] on the stack; we are boxing a
#! parameter being passed to a callback from C.
over [ load-return-reg ] [ 2drop ] if ;
-M:: x86.32 %box ( n reg-class func -- )
- n reg-class (%box)
- reg-class reg-size [
- reg-class push-return-reg
+M:: x86.32 %box ( n rep func -- )
+ n rep (%box)
+ rep rep-size [
+ rep push-return-reg
func f %alien-invoke
] with-aligned-stack ;
EAX ESI [] MOV
ESI 4 SUB ;
-: (%unbox) ( func -- )
+: call-unbox-func ( func -- )
4 [
! Push parameter
EAX PUSH
f %alien-invoke
] with-aligned-stack ;
-M: x86.32 %unbox ( n reg-class func -- )
+M: x86.32 %unbox ( n rep func -- )
#! The value being unboxed must already be in EAX.
#! If n is f, we're unboxing a return value about to be
#! returned by the callback. Otherwise, we're unboxing
#! a parameter to a C function about to be called.
- (%unbox)
+ call-unbox-func
! Store the return value on the C stack
over [ store-return-reg ] [ 2drop ] if ;
M: x86.32 %unbox-long-long ( n func -- )
- (%unbox)
+ call-unbox-func
! Store the return value on the C stack
[
dup stack@ EAX MOV
{ 2 [ %unbox-struct-2 ] }
} case ;
-M: x86.32 %unbox-large-struct ( n c-type -- )
+M:: x86.32 %unbox-large-struct ( n c-type -- )
! Alien must be in EAX.
! Compute destination address
- ECX rot stack@ LEA
+ ECX n stack@ LEA
12 [
! Push struct size
- heap-size PUSH
+ c-type heap-size PUSH
! Push destination address
ECX PUSH
! Push source address
sse2? [
" - yes" print
enable-float-intrinsics
+ enable-fsqrt
[
sse2? [
"This image was built to use SSE2, which your CPU does not support." print
! Copyright (C) 2007, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel namespaces system
-cpu.x86.assembler layouts vocabs parser compiler.constants ;
+cpu.x86.assembler cpu.x86.assembler.operands layouts
+vocabs parser compiler.constants ;
IN: bootstrap.x86
4 \ cell set
! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays kernel math namespaces make sequences
-system layouts alien alien.c-types alien.accessors alien.structs
-slots splitting assocs combinators locals cpu.x86.assembler
-cpu.x86 cpu.architecture compiler.constants
-compiler.codegen compiler.codegen.fixup
-compiler.cfg.instructions compiler.cfg.builder
-compiler.cfg.intrinsics compiler.cfg.stack-frame ;
+USING: accessors arrays kernel math namespaces make sequences system
+layouts alien alien.c-types alien.accessors alien.structs slots
+splitting assocs combinators locals compiler.constants
+compiler.codegen compiler.codegen.fixup compiler.cfg.instructions
+compiler.cfg.builder compiler.cfg.intrinsics compiler.cfg.stack-frame
+cpu.x86.assembler cpu.x86.assembler.operands cpu.x86 cpu.architecture ;
IN: cpu.x86.64
M: x86.64 machine-registers
{
{ int-regs { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 R13 } }
- { double-float-regs {
+ { float-regs {
XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15
} }
M: x86.64 stack-reg RSP ;
M:: x86.64 %dispatch ( src temp -- )
+ building get length :> start
! Load jump table base.
temp HEX: ffffffff MOV
0 rc-absolute-cell rel-here
! Add jump table base
- src temp ADD
- src HEX: 7f [+] JMP
+ temp src ADD
+ temp HEX: 7f [+] JMP
+ building get length :> end
! Fix up the displacement above
cell code-alignment
- [ 15 + building get dup pop* push ]
+ [ end start - 2 - + building get dup pop* push ]
[ align-code ]
bi ;
M: float-regs return-reg drop XMM0 ;
M: x86.64 %prologue ( n -- )
- temp-reg-1 0 MOV rc-absolute-cell rel-this
+ temp-reg 0 MOV rc-absolute-cell rel-this
dup PUSH
- temp-reg-1 PUSH
+ temp-reg PUSH
stack-reg swap 3 cells - SUB ;
-M: stack-params %load-param-reg
+M: stack-params copy-register*
drop
- [ R11 swap param@ MOV ] dip
- param@ R11 MOV ;
+ {
+ { [ dup integer? ] [ R11 swap next-stack@ MOV R11 MOV ] }
+ { [ over integer? ] [ R11 swap MOV param@ R11 MOV ] }
+ } cond ;
-M: stack-params %save-param-reg
- drop
- R11 swap next-stack@ MOV
- param@ R11 MOV ;
+M: x86 %save-param-reg [ param@ ] 2dip copy-register ;
+
+M: x86 %load-param-reg [ swap param@ ] dip copy-register ;
: with-return-regs ( quot -- )
[
param-reg-1 R14 [] MOV
R14 cell SUB ;
-M: x86.64 %unbox ( n reg-class func -- )
+M:: x86.64 %unbox ( n rep func -- )
! Call the unboxer
- f %alien-invoke
- ! Store the return value on the C stack
- over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
+ func f %alien-invoke
+ ! Store the return value on the C stack if this is an
+ ! alien-invoke, otherwise leave it the return register if
+ ! this is the end of alien-callback
+ n [ n rep reg-class-of return-reg rep %save-param-reg ] when ;
M: x86.64 %unbox-long-long ( n func -- )
- int-regs swap %unbox ;
+ [ int-rep ] dip %unbox ;
: %unbox-struct-field ( c-type i -- )
! Alien must be in param-reg-1.
- R11 swap cells [+] swap reg-class>> {
+ R11 swap cells [+] swap rep>> reg-class-of {
{ int-regs [ int-regs get pop swap MOV ] }
- { double-float-regs [ float-regs get pop swap MOVSD ] }
+ { float-regs [ float-regs get pop swap MOVSD ] }
} case ;
M: x86.64 %unbox-small-struct ( c-type -- )
flatten-value-type [ %unbox-struct-field ] each-index
] with-return-regs ;
-M: x86.64 %unbox-large-struct ( n c-type -- )
+M:: x86.64 %unbox-large-struct ( n c-type -- )
! Source is in param-reg-1
- heap-size
- ! Load destination address
- param-reg-2 rot param@ LEA
- ! Load structure size
- param-reg-3 swap MOV
+ ! Load destination address into param-reg-2
+ param-reg-2 n param@ LEA
+ ! Load structure size into param-reg-3
+ param-reg-3 c-type heap-size MOV
! Copy the struct to the C stack
"to_value_struct" f %alien-invoke ;
-: load-return-value ( reg-class -- )
- 0 over param-reg swap return-reg
- 2dup eq? [ 2drop ] [ MOV ] if ;
-
-M: x86.64 %box ( n reg-class func -- )
- rot [
- rot [ 0 swap param-reg ] keep %load-param-reg
+: load-return-value ( rep -- )
+ [ [ 0 ] dip reg-class-of param-reg ]
+ [ reg-class-of return-reg ]
+ [ ]
+ tri copy-register ;
+
+M:: x86.64 %box ( n rep func -- )
+ n [
+ n
+ 0 rep reg-class-of param-reg
+ rep %load-param-reg
] [
- swap load-return-value
- ] if*
- f %alien-invoke ;
+ rep load-return-value
+ ] if
+ func f %alien-invoke ;
M: x86.64 %box-long-long ( n func -- )
- int-regs swap %box ;
+ [ int-rep ] dip %box ;
-: box-struct-field@ ( i -- operand ) 1+ cells param@ ;
+: box-struct-field@ ( i -- operand ) 1 + cells param@ ;
: %box-struct-field ( c-type i -- )
- box-struct-field@ swap reg-class>> {
+ box-struct-field@ swap c-type-rep reg-class-of {
{ int-regs [ int-regs get pop MOV ] }
- { double-float-regs [ float-regs get pop MOVSD ] }
+ { float-regs [ float-regs get pop MOVSD ] }
} case ;
M: x86.64 %box-small-struct ( c-type -- )
rc-absolute-cell rel-dlsym
R11 CALL ;
-M: x86.64 %alien-invoke-tail
- R11 0 MOV
- rc-absolute-cell rel-dlsym
- R11 JMP ;
-
M: x86.64 %prepare-alien-indirect ( -- )
"unbox_alien" f %alien-invoke
RBP RAX MOV ;
! SSE2 is always available on x86-64.
enable-float-intrinsics
+enable-fsqrt
USE: vocabs.loader
! Copyright (C) 2007, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel namespaces system
-cpu.x86.assembler layouts vocabs parser compiler.constants math ;
+layouts vocabs parser compiler.constants math
+cpu.x86.assembler cpu.x86.assembler.operands ;
IN: bootstrap.x86
8 \ cell set
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel namespaces system
-cpu.x86.assembler layouts vocabs parser ;
+cpu.x86.assembler cpu.x86.assembler.operands layouts vocabs parser ;
IN: bootstrap.x86
: stack-frame-size ( -- n ) 4 bootstrap-cells ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays sequences math splitting make assocs
-kernel layouts system alien.c-types alien.structs
-cpu.architecture cpu.x86.assembler cpu.x86
-compiler.codegen compiler.cfg.registers ;
+USING: accessors arrays sequences math splitting make assocs kernel
+layouts system alien.c-types alien.structs cpu.architecture
+cpu.x86.assembler cpu.x86.assembler.operands cpu.x86 compiler.codegen
+compiler.cfg.registers ;
IN: cpu.x86.64.unix
-M: int-regs param-regs drop { RDI RSI RDX RCX R8 R9 } ;
+M: int-regs param-regs
+ drop { RDI RSI RDX RCX R8 R9 } ;
M: float-regs param-regs
drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
! The ABI for passing structs by value is pretty messed up
<< "void*" c-type clone "__stack_value" define-primitive-type
-stack-params "__stack_value" c-type (>>reg-class) >>
+stack-params "__stack_value" c-type (>>rep) >>
: struct-types&offset ( struct-type -- pairs )
fields>> [
: flatten-small-struct ( c-type -- seq )
struct-types&offset split-struct [
- [ c-type c-type-reg-class ] map
+ [ c-type c-type-rep reg-class-of ] map
int-regs swap member? "void*" "double" ? c-type
] map ;
M: x86.64 dummy-fp-params? f ;
-M: x86.64 temp-reg-1 R8 ;
-
-M: x86.64 temp-reg-2 R9 ;
+M: x86.64 temp-reg R8 ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel namespaces system
-cpu.x86.assembler layouts vocabs parser ;
+layouts vocabs parser cpu.x86.assembler
+cpu.x86.assembler.operands ;
IN: bootstrap.x86
: stack-frame-size ( -- n ) 8 bootstrap-cells ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel layouts system math alien.c-types sequences
-compiler.cfg.registers cpu.architecture cpu.x86.assembler cpu.x86 ;
+compiler.cfg.registers cpu.architecture cpu.x86.assembler cpu.x86
+cpu.x86.assembler.operands ;
IN: cpu.x86.64.winnt
M: int-regs param-regs drop { RCX RDX R8 R9 } ;
M: x86.64 dummy-fp-params? t ;
-M: x86.64 temp-reg-1 RAX ;
-
-M: x86.64 temp-reg-2 RCX ;
+M: x86.64 temp-reg RAX ;
<<
"longlong" "ptrdiff_t" typedef
-USING: cpu.x86.assembler kernel tools.test namespaces make ;
+USING: cpu.x86.assembler cpu.x86.assembler.operands
+kernel tools.test namespaces make ;
IN: cpu.x86.assembler.tests
+[ { HEX: 40 HEX: 8a HEX: 2a } ] [ [ BPL RDX [] MOV ] { } make ] unit-test
+
[ { HEX: 49 HEX: 89 HEX: 04 HEX: 24 } ] [ [ R12 [] RAX MOV ] { } make ] unit-test
[ { HEX: 49 HEX: 8b HEX: 06 } ] [ [ RAX R14 [] MOV ] { } make ] unit-test
[ { HEX: 4c HEX: 89 HEX: e2 } ] [ [ RDX R12 MOV ] { } make ] unit-test
[ { HEX: 49 HEX: 89 HEX: d4 } ] [ [ R12 RDX MOV ] { } make ] unit-test
+! r-rm / m-r sse instruction
+[ { HEX: 0f HEX: 10 HEX: c1 } ] [ [ XMM0 XMM1 MOVUPS ] { } make ] unit-test
+[ { HEX: 0f HEX: 10 HEX: 01 } ] [ [ XMM0 ECX [] MOVUPS ] { } make ] unit-test
+[ { HEX: 0f HEX: 11 HEX: 08 } ] [ [ EAX [] XMM1 MOVUPS ] { } make ] unit-test
+
+[ { HEX: f3 HEX: 0f HEX: 10 HEX: c1 } ] [ [ XMM0 XMM1 MOVSS ] { } make ] unit-test
+[ { HEX: f3 HEX: 0f HEX: 10 HEX: 01 } ] [ [ XMM0 ECX [] MOVSS ] { } make ] unit-test
+[ { HEX: f3 HEX: 0f HEX: 11 HEX: 08 } ] [ [ EAX [] XMM1 MOVSS ] { } make ] unit-test
+
+[ { HEX: 66 HEX: 0f HEX: 6f HEX: c1 } ] [ [ XMM0 XMM1 MOVDQA ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 6f HEX: 01 } ] [ [ XMM0 ECX [] MOVDQA ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 7f HEX: 08 } ] [ [ EAX [] XMM1 MOVDQA ] { } make ] unit-test
+
+! r-rm only sse instruction
+[ { HEX: 66 HEX: 0f HEX: 2e HEX: c1 } ] [ [ XMM0 XMM1 UCOMISD ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 2e HEX: 01 } ] [ [ XMM0 ECX [] UCOMISD ] { } make ] unit-test
+[ [ EAX [] XMM1 UCOMISD ] { } make ] must-fail
+[ { HEX: 66 HEX: 0f HEX: 38 HEX: 2a HEX: 01 } ] [ [ XMM0 ECX [] MOVNTDQA ] { } make ] unit-test
+
+! rm-r only sse instructions
+[ { HEX: 0f HEX: 2b HEX: 08 } ] [ [ EAX [] XMM1 MOVNTPS ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: e7 HEX: 08 } ] [ [ EAX [] XMM1 MOVNTDQ ] { } make ] unit-test
+
+! three-byte-opcode ssse3 instruction
+[ { HEX: 66 HEX: 0f HEX: 38 HEX: 02 HEX: c1 } ] [ [ XMM0 XMM1 PHADDD ] { } make ] unit-test
+
+! int/sse conversion instruction
[ { HEX: f2 HEX: 0f HEX: 2c HEX: c0 } ] [ [ EAX XMM0 CVTTSD2SI ] { } make ] unit-test
[ { HEX: f2 HEX: 48 HEX: 0f HEX: 2c HEX: c0 } ] [ [ RAX XMM0 CVTTSD2SI ] { } make ] unit-test
[ { HEX: f2 HEX: 4c HEX: 0f HEX: 2c HEX: e0 } ] [ [ R12 XMM0 CVTTSD2SI ] { } make ] unit-test
! [ { HEX: f2 HEX: 0f HEX: 11 HEX: 00 } ] [ [ RAX [] XMM0 MOVSD ] { } make ] unit-test
! [ { HEX: f2 HEX: 41 HEX: 0f HEX: 11 HEX: 04 HEX: 24 } ] [ [ R12 [] XMM0 MOVSD ] { } make ] unit-test
+! 3-operand r-rm-imm sse instructions
+[ { HEX: 66 HEX: 0f HEX: 70 HEX: c1 HEX: 02 } ] [ [ XMM0 XMM1 2 PSHUFD ] { } make ] unit-test
+[ { HEX: 0f HEX: c6 HEX: c1 HEX: 02 } ] [ [ XMM0 XMM1 2 SHUFPS ] { } make ] unit-test
+
+! scalar register insert/extract sse instructions
+[ { HEX: 66 HEX: 0f HEX: c4 HEX: c1 HEX: 02 } ] [ [ XMM0 ECX 2 PINSRW ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: c4 HEX: 04 HEX: 11 HEX: 03 } ] [ [ XMM0 ECX EDX [+] 3 PINSRW ] { } make ] unit-test
+
+[ { HEX: 66 HEX: 0f HEX: c5 HEX: c1 HEX: 02 } ] [ [ EAX XMM1 2 PEXTRW ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 3a HEX: 15 HEX: 08 HEX: 02 } ] [ [ EAX [] XMM1 2 PEXTRW ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 3a HEX: 15 HEX: 14 HEX: 08 HEX: 03 } ] [ [ EAX ECX [+] XMM2 3 PEXTRW ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 3a HEX: 14 HEX: c8 HEX: 02 } ] [ [ EAX XMM1 2 PEXTRB ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 3a HEX: 14 HEX: 08 HEX: 02 } ] [ [ EAX [] XMM1 2 PEXTRB ] { } make ] unit-test
+
+! sse shift instructions
+[ { HEX: 66 HEX: 0f HEX: 71 HEX: d0 HEX: 05 } ] [ [ XMM0 5 PSRLW ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: d1 HEX: c1 } ] [ [ XMM0 XMM1 PSRLW ] { } make ] unit-test
+
+! sse comparison instructions
+[ { HEX: 66 HEX: 0f HEX: c2 HEX: c1 HEX: 02 } ] [ [ XMM0 XMM1 CMPLEPD ] { } make ] unit-test
+
+! unique sse instructions
+[ { HEX: 0f HEX: 18 HEX: 00 } ] [ [ EAX [] PREFETCHNTA ] { } make ] unit-test
+[ { HEX: 0f HEX: 18 HEX: 08 } ] [ [ EAX [] PREFETCHT0 ] { } make ] unit-test
+[ { HEX: 0f HEX: 18 HEX: 10 } ] [ [ EAX [] PREFETCHT1 ] { } make ] unit-test
+[ { HEX: 0f HEX: 18 HEX: 18 } ] [ [ EAX [] PREFETCHT2 ] { } make ] unit-test
+[ { HEX: 0f HEX: ae HEX: 10 } ] [ [ EAX [] LDMXCSR ] { } make ] unit-test
+[ { HEX: 0f HEX: ae HEX: 18 } ] [ [ EAX [] STMXCSR ] { } make ] unit-test
+
+[ { HEX: 0f HEX: c3 HEX: 08 } ] [ [ EAX [] ECX MOVNTI ] { } make ] unit-test
+
+[ { HEX: 0f HEX: 50 HEX: c1 } ] [ [ EAX XMM1 MOVMSKPS ] { } make ] unit-test
+[ { HEX: 66 HEX: 0f HEX: 50 HEX: c1 } ] [ [ EAX XMM1 MOVMSKPD ] { } make ] unit-test
+
+[ { HEX: f3 HEX: 0f HEX: b8 HEX: c1 } ] [ [ EAX ECX POPCNT ] { } make ] unit-test
+[ { HEX: f3 HEX: 48 HEX: 0f HEX: b8 HEX: c1 } ] [ [ RAX RCX POPCNT ] { } make ] unit-test
+[ { HEX: f3 HEX: 0f HEX: b8 HEX: 01 } ] [ [ EAX ECX [] POPCNT ] { } make ] unit-test
+[ { HEX: f3 HEX: 0f HEX: b8 HEX: 04 HEX: 11 } ] [ [ EAX ECX EDX [+] POPCNT ] { } make ] unit-test
+
+[ { HEX: f2 HEX: 0f HEX: 38 HEX: f0 HEX: c1 } ] [ [ EAX CL CRC32B ] { } make ] unit-test
+[ { HEX: f2 HEX: 0f HEX: 38 HEX: f0 HEX: 01 } ] [ [ EAX ECX [] CRC32B ] { } make ] unit-test
+[ { HEX: f2 HEX: 0f HEX: 38 HEX: f1 HEX: c1 } ] [ [ EAX ECX CRC32 ] { } make ] unit-test
+[ { HEX: f2 HEX: 0f HEX: 38 HEX: f1 HEX: 01 } ] [ [ EAX ECX [] CRC32 ] { } make ] unit-test
+
+! memory address modes
[ { HEX: 8a HEX: 18 } ] [ [ BL RAX [] MOV ] { } make ] unit-test
[ { HEX: 66 HEX: 8b HEX: 18 } ] [ [ BX RAX [] MOV ] { } make ] unit-test
[ { HEX: 8b HEX: 18 } ] [ [ EBX RAX [] MOV ] { } make ] unit-test
[ { HEX: 48 HEX: d3 HEX: e9 } ] [ [ RCX CL SHR ] { } make ] unit-test
[ { HEX: f7 HEX: c1 HEX: d2 HEX: 04 HEX: 00 HEX: 00 } ] [ [ ECX 1234 TEST ] { } make ] unit-test
+
+[ { HEX: 4d HEX: 6b HEX: c0 HEX: 03 } ] [ [ R8 R8 3 IMUL3 ] { } make ] unit-test
+[ { HEX: 49 HEX: 6b HEX: c0 HEX: 03 } ] [ [ RAX R8 3 IMUL3 ] { } make ] unit-test
+[ { HEX: 4c HEX: 6b HEX: c0 HEX: 03 } ] [ [ R8 RAX 3 IMUL3 ] { } make ] unit-test
+[ { HEX: 48 HEX: 6b HEX: c1 HEX: 03 } ] [ [ RAX RCX 3 IMUL3 ] { } make ] unit-test
+[ { HEX: 48 HEX: 69 HEX: c1 HEX: 44 HEX: 03 HEX: 00 HEX: 00 } ] [ [ RAX RCX HEX: 344 IMUL3 ] { } make ] unit-test
+
+[ { 15 183 195 } ] [ [ EAX BX MOVZX ] { } make ] unit-test
+
-! Copyright (C) 2005, 2009 Slava Pestov.
+! Copyright (C) 2005, 2009 Slava Pestov, Joe Groff.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays io.binary kernel combinators
-kernel.private math namespaces make sequences words system layouts
-math.order accessors cpu.x86.assembler.syntax ;
+USING: arrays io.binary kernel combinators kernel.private math locals
+namespaces make sequences words system layouts math.order accessors
+cpu.x86.assembler.operands cpu.x86.assembler.operands.private ;
+QUALIFIED: sequences
IN: cpu.x86.assembler
! A postfix assembler for x86-32 and x86-64.
-! In 32-bit mode, { 1234 } is absolute indirect addressing.
-! In 64-bit mode, { 1234 } is RIP-relative.
-! Beware!
-
-! Register operands -- eg, ECX
-REGISTERS: 8 AL CL DL BL ;
-
-REGISTERS: 16 AX CX DX BX SP BP SI DI ;
-
-REGISTERS: 32 EAX ECX EDX EBX ESP EBP ESI EDI ;
-
-REGISTERS: 64
-RAX RCX RDX RBX RSP RBP RSI RDI R8 R9 R10 R11 R12 R13 R14 R15 ;
-
-REGISTERS: 128
-XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
-XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15 ;
-
-TUPLE: byte value ;
-
-C: <byte> byte
-
<PRIVATE
-#! Extended AMD64 registers (R8-R15) return true.
-GENERIC: extended? ( op -- ? )
-
-M: object extended? drop f ;
-
-PREDICATE: register < word
- "register" word-prop ;
-
-PREDICATE: register-8 < register
- "register-size" word-prop 8 = ;
-
-PREDICATE: register-16 < register
- "register-size" word-prop 16 = ;
-
-PREDICATE: register-32 < register
- "register-size" word-prop 32 = ;
-
-PREDICATE: register-64 < register
- "register-size" word-prop 64 = ;
-
-PREDICATE: register-128 < register
- "register-size" word-prop 128 = ;
-
-M: register extended? "register" word-prop 7 > ;
-
-! Addressing modes
-TUPLE: indirect base index scale displacement ;
-
-M: indirect extended? base>> extended? ;
-
-: canonicalize-EBP ( indirect -- indirect )
- #! { EBP } ==> { EBP 0 }
- dup [ base>> { EBP RBP R13 } member? ] [ displacement>> not ] bi and
- [ 0 >>displacement ] when ;
-
-ERROR: bad-index indirect ;
-
-: check-ESP ( indirect -- indirect )
- dup index>> { ESP RSP } memq? [ bad-index ] when ;
-
-: canonicalize ( indirect -- indirect )
- #! Modify the indirect to work around certain addressing mode
- #! quirks.
- canonicalize-EBP check-ESP ;
-
-: <indirect> ( base index scale displacement -- indirect )
- indirect boa canonicalize ;
-
: reg-code ( reg -- n ) "register" word-prop 7 bitand ;
: indirect-base* ( op -- n ) base>> EBP or reg-code ;
dup displacement>> dup [
swap base>>
[ dup fits-in-byte? [ , ] [ 4, ] if ] [ 4, ] if
- ] [
- 2drop
- ] if ;
+ ] [ 2drop ] if ;
M: register displacement, drop ;
: addressing ( reg# indirect -- )
[ mod-r/m, ] [ sib, ] [ displacement, ] tri ;
-! Utilities
-UNION: operand register indirect ;
-
-GENERIC: operand-64? ( operand -- ? )
-
-M: indirect operand-64?
- [ base>> ] [ index>> ] bi [ operand-64? ] either? ;
-
-M: register-64 operand-64? drop t ;
-
-M: object operand-64? drop f ;
-
: rex.w? ( rex.w reg r/m -- ? )
{
{ [ dup register-128? ] [ drop operand-64? ] }
: rex.b ( m op -- n )
[ extended? [ BIN: 00000001 bitor ] when ] keep
- dup indirect? [
- index>> extended? [ BIN: 00000010 bitor ] when
- ] [
- drop
- ] if ;
+ dup indirect? [ index>> extended? [ BIN: 00000010 bitor ] when ] [ drop ] if ;
+
+: no-prefix? ( prefix reg r/m -- ? )
+ [ BIN: 01000000 = ]
+ [ extended-8-bit-register? not ]
+ [ extended-8-bit-register? not ] tri*
+ and and ;
-: rex-prefix ( reg r/m rex.w -- )
+:: rex-prefix ( reg r/m rex.w -- )
#! Compile an AMD64 REX prefix.
- 2over rex.w? BIN: 01001000 BIN: 01000000 ?
- swap rex.r swap rex.b
- dup BIN: 01000000 = [ drop ] [ , ] if ;
+ rex.w reg r/m rex.w? BIN: 01001000 BIN: 01000000 ?
+ r/m rex.r
+ reg rex.b
+ dup reg r/m no-prefix? [ drop ] [ , ] if ;
: 16-prefix ( reg r/m -- )
[ register-16? ] either? [ HEX: 66 , ] when ;
-: prefix ( reg r/m rex.w -- ) 2over 16-prefix rex-prefix ;
+: prefix ( reg r/m rex.w -- ) [ drop 16-prefix ] [ rex-prefix ] 3bi ;
: prefix-1 ( reg rex.w -- ) f swap prefix ;
: opcode, ( opcode -- ) dup array? [ % ] [ , ] if ;
-: extended-opcode ( opcode -- opcode' ) OCT: 17 swap 2array ;
+: extended-opcode ( opcode -- opcode' )
+ dup array? [ OCT: 17 sequences:prefix ] [ OCT: 17 swap 2array ] if ;
: extended-opcode, ( opcode -- ) extended-opcode opcode, ;
: 2-operand ( dst src op -- )
#! Sets the opcode's direction bit. It is set if the
#! destination is a direct register operand.
- 2over 16-prefix
- direction-bit
- operand-size-bit
- (2-operand) ;
+ [ drop 16-prefix ] [ direction-bit operand-size-bit (2-operand) ] 3bi ;
PRIVATE>
-: [] ( reg/displacement -- indirect )
- dup integer? [ [ f f f ] dip ] [ f f f ] if <indirect> ;
-
-: [+] ( reg displacement -- indirect )
- dup integer?
- [ dup zero? [ drop f ] when [ f f ] dip ]
- [ f f ] if
- <indirect> ;
-
! Moving stuff
GENERIC: PUSH ( op -- )
M: register PUSH f HEX: 50 short-operand ;
: SHR ( dst n -- ) BIN: 101 (SHIFT) ;
: SAR ( dst n -- ) BIN: 111 (SHIFT) ;
-GENERIC: IMUL2 ( dst src -- )
-M: immediate IMUL2 swap dup reg-code t HEX: 68 3array immediate-1/4 ;
-M: operand IMUL2 OCT: 257 extended-opcode (2-operand) ;
+: IMUL2 ( dst src -- )
+ OCT: 257 extended-opcode (2-operand) ;
+
+: IMUL3 ( dst src imm -- )
+ dup fits-in-byte? [
+ [ swap HEX: 6a 2-operand ] dip 1,
+ ] [
+ [ swap HEX: 68 2-operand ] dip 4,
+ ] if ;
: MOVSX ( dst src -- )
- dup register-32? OCT: 143 OCT: 276 extended-opcode ?
- over register-16? [ BIN: 1 opcode-or ] when
- swapd
+ swap
+ over register-32? OCT: 143 OCT: 276 extended-opcode ?
+ pick register-16? [ BIN: 1 opcode-or ] when
(2-operand) ;
: MOVZX ( dst src -- )
+ swap
OCT: 266 extended-opcode
- over register-16? [ BIN: 1 opcode-or ] when
- swapd
+ pick register-16? [ BIN: 1 opcode-or ] when
(2-operand) ;
! Conditional move
! Misc
: NOP ( -- ) HEX: 90 , ;
+: PAUSE ( -- ) HEX: f3 , HEX: 90 , ;
+
+: RDPMC ( -- ) HEX: 0f , HEX: 33 , ;
! x87 Floating Point Unit
pick register-128? [ swapd ] [ BIN: 1 bitor ] if ;
: 2-operand-sse ( dst src op1 op2 -- )
- , direction-bit-sse extended-opcode (2-operand) ;
+ [ , ] when* direction-bit-sse extended-opcode (2-operand) ;
+
+: direction-op-sse ( dst src op1s -- dst' src' op1' )
+ pick register-128? [ swapd first ] [ second ] if ;
+
+: 2-operand-rm-mr-sse ( dst src op1{rm,mr} op2 -- )
+ [ , ] when* direction-op-sse extended-opcode (2-operand) ;
+
+: 2-operand-rm-sse ( dst src op1 op2 -- )
+ [ , ] when* swapd extended-opcode (2-operand) ;
+
+: 2-operand-mr-sse ( dst src op1 op2 -- )
+ [ , ] when* extended-opcode (2-operand) ;
: 2-operand-int/sse ( dst src op1 op2 -- )
- , swapd extended-opcode (2-operand) ;
+ [ , ] when* swapd extended-opcode (2-operand) ;
+
+: 3-operand-rm-sse ( dst src imm op1 op2 -- )
+ rot [ 2-operand-rm-sse ] dip , ;
+: 3-operand-mr-sse ( dst src imm op1 op2 -- )
+ rot [ 2-operand-mr-sse ] dip , ;
+
+: 3-operand-rm-mr-sse ( dst src imm op1 op2 -- )
+ rot [ 2-operand-rm-mr-sse ] dip , ;
+
+: 2-operand-sse-cmp ( dst src cmp op1 op2 -- )
+ 3-operand-rm-sse ; inline
+
+: 2-operand-sse-shift ( dst imm reg op1 op2 -- )
+ [ , ] when*
+ [ f HEX: 0f ] dip 2array 3array
+ swapd 1-operand , ;
+
+PRIVATE>
+
+: MOVUPS ( dest src -- ) HEX: 10 f 2-operand-sse ;
+: MOVUPD ( dest src -- ) HEX: 10 HEX: 66 2-operand-sse ;
+: MOVSD ( dest src -- ) HEX: 10 HEX: f2 2-operand-sse ;
+: MOVSS ( dest src -- ) HEX: 10 HEX: f3 2-operand-sse ;
+: MOVLPS ( dest src -- ) HEX: 12 f 2-operand-sse ;
+: MOVLPD ( dest src -- ) HEX: 12 HEX: 66 2-operand-sse ;
+: MOVDDUP ( dest src -- ) HEX: 12 HEX: f2 2-operand-rm-sse ;
+: MOVSLDUP ( dest src -- ) HEX: 12 HEX: f3 2-operand-rm-sse ;
+: UNPCKLPS ( dest src -- ) HEX: 14 f 2-operand-rm-sse ;
+: UNPCKLPD ( dest src -- ) HEX: 14 HEX: 66 2-operand-rm-sse ;
+: UNPCKHPS ( dest src -- ) HEX: 15 f 2-operand-rm-sse ;
+: UNPCKHPD ( dest src -- ) HEX: 15 HEX: 66 2-operand-rm-sse ;
+: MOVHPS ( dest src -- ) HEX: 16 f 2-operand-sse ;
+: MOVHPD ( dest src -- ) HEX: 16 HEX: 66 2-operand-sse ;
+: MOVSHDUP ( dest src -- ) HEX: 16 HEX: f3 2-operand-rm-sse ;
+
+: PREFETCHNTA ( mem -- ) { BIN: 000 f { HEX: 0f HEX: 18 } } 1-operand ;
+: PREFETCHT0 ( mem -- ) { BIN: 001 f { HEX: 0f HEX: 18 } } 1-operand ;
+: PREFETCHT1 ( mem -- ) { BIN: 010 f { HEX: 0f HEX: 18 } } 1-operand ;
+: PREFETCHT2 ( mem -- ) { BIN: 011 f { HEX: 0f HEX: 18 } } 1-operand ;
+
+: MOVAPS ( dest src -- ) HEX: 28 f 2-operand-sse ;
+: MOVAPD ( dest src -- ) HEX: 28 HEX: 66 2-operand-sse ;
+: CVTSI2SD ( dest src -- ) HEX: 2a HEX: f2 2-operand-int/sse ;
+: CVTSI2SS ( dest src -- ) HEX: 2a HEX: f3 2-operand-int/sse ;
+: MOVNTPS ( dest src -- ) HEX: 2b f 2-operand-mr-sse ;
+: MOVNTPD ( dest src -- ) HEX: 2b HEX: 66 2-operand-mr-sse ;
+: CVTTSD2SI ( dest src -- ) HEX: 2c HEX: f2 2-operand-int/sse ;
+: CVTTSS2SI ( dest src -- ) HEX: 2c HEX: f3 2-operand-int/sse ;
+: CVTSD2SI ( dest src -- ) HEX: 2d HEX: f2 2-operand-int/sse ;
+: CVTSS2SI ( dest src -- ) HEX: 2d HEX: f3 2-operand-int/sse ;
+: UCOMISS ( dest src -- ) HEX: 2e f 2-operand-rm-sse ;
+: UCOMISD ( dest src -- ) HEX: 2e HEX: 66 2-operand-rm-sse ;
+: COMISS ( dest src -- ) HEX: 2f f 2-operand-rm-sse ;
+: COMISD ( dest src -- ) HEX: 2f HEX: 66 2-operand-rm-sse ;
+
+: PSHUFB ( dest src -- ) { HEX: 38 HEX: 00 } HEX: 66 2-operand-rm-sse ;
+: PHADDW ( dest src -- ) { HEX: 38 HEX: 01 } HEX: 66 2-operand-rm-sse ;
+: PHADDD ( dest src -- ) { HEX: 38 HEX: 02 } HEX: 66 2-operand-rm-sse ;
+: PHADDSW ( dest src -- ) { HEX: 38 HEX: 03 } HEX: 66 2-operand-rm-sse ;
+: PMADDUBSW ( dest src -- ) { HEX: 38 HEX: 04 } HEX: 66 2-operand-rm-sse ;
+: PHSUBW ( dest src -- ) { HEX: 38 HEX: 05 } HEX: 66 2-operand-rm-sse ;
+: PHSUBD ( dest src -- ) { HEX: 38 HEX: 06 } HEX: 66 2-operand-rm-sse ;
+: PHSUBSW ( dest src -- ) { HEX: 38 HEX: 07 } HEX: 66 2-operand-rm-sse ;
+: PSIGNB ( dest src -- ) { HEX: 38 HEX: 08 } HEX: 66 2-operand-rm-sse ;
+: PSIGNW ( dest src -- ) { HEX: 38 HEX: 09 } HEX: 66 2-operand-rm-sse ;
+: PSIGND ( dest src -- ) { HEX: 38 HEX: 0a } HEX: 66 2-operand-rm-sse ;
+: PMULHRSW ( dest src -- ) { HEX: 38 HEX: 0b } HEX: 66 2-operand-rm-sse ;
+: PBLENDVB ( dest src -- ) { HEX: 38 HEX: 10 } HEX: 66 2-operand-rm-sse ;
+: BLENDVPS ( dest src -- ) { HEX: 38 HEX: 14 } HEX: 66 2-operand-rm-sse ;
+: BLENDVPD ( dest src -- ) { HEX: 38 HEX: 15 } HEX: 66 2-operand-rm-sse ;
+: PTEST ( dest src -- ) { HEX: 38 HEX: 17 } HEX: 66 2-operand-rm-sse ;
+: PABSB ( dest src -- ) { HEX: 38 HEX: 1c } HEX: 66 2-operand-rm-sse ;
+: PABSW ( dest src -- ) { HEX: 38 HEX: 1d } HEX: 66 2-operand-rm-sse ;
+: PABSD ( dest src -- ) { HEX: 38 HEX: 1e } HEX: 66 2-operand-rm-sse ;
+: PMOVSXBW ( dest src -- ) { HEX: 38 HEX: 20 } HEX: 66 2-operand-rm-sse ;
+: PMOVSXBD ( dest src -- ) { HEX: 38 HEX: 21 } HEX: 66 2-operand-rm-sse ;
+: PMOVSXBQ ( dest src -- ) { HEX: 38 HEX: 22 } HEX: 66 2-operand-rm-sse ;
+: PMOVSXWD ( dest src -- ) { HEX: 38 HEX: 23 } HEX: 66 2-operand-rm-sse ;
+: PMOVSXWQ ( dest src -- ) { HEX: 38 HEX: 24 } HEX: 66 2-operand-rm-sse ;
+: PMOVSXDQ ( dest src -- ) { HEX: 38 HEX: 25 } HEX: 66 2-operand-rm-sse ;
+: PMULDQ ( dest src -- ) { HEX: 38 HEX: 28 } HEX: 66 2-operand-rm-sse ;
+: PCMPEQQ ( dest src -- ) { HEX: 38 HEX: 29 } HEX: 66 2-operand-rm-sse ;
+: MOVNTDQA ( dest src -- ) { HEX: 38 HEX: 2a } HEX: 66 2-operand-rm-sse ;
+: PACKUSDW ( dest src -- ) { HEX: 38 HEX: 2b } HEX: 66 2-operand-rm-sse ;
+: PMOVZXBW ( dest src -- ) { HEX: 38 HEX: 30 } HEX: 66 2-operand-rm-sse ;
+: PMOVZXBD ( dest src -- ) { HEX: 38 HEX: 31 } HEX: 66 2-operand-rm-sse ;
+: PMOVZXBQ ( dest src -- ) { HEX: 38 HEX: 32 } HEX: 66 2-operand-rm-sse ;
+: PMOVZXWD ( dest src -- ) { HEX: 38 HEX: 33 } HEX: 66 2-operand-rm-sse ;
+: PMOVZXWQ ( dest src -- ) { HEX: 38 HEX: 34 } HEX: 66 2-operand-rm-sse ;
+: PMOVZXDQ ( dest src -- ) { HEX: 38 HEX: 35 } HEX: 66 2-operand-rm-sse ;
+: PCMPGTQ ( dest src -- ) { HEX: 38 HEX: 37 } HEX: 66 2-operand-rm-sse ;
+: PMINSB ( dest src -- ) { HEX: 38 HEX: 38 } HEX: 66 2-operand-rm-sse ;
+: PMINSD ( dest src -- ) { HEX: 38 HEX: 39 } HEX: 66 2-operand-rm-sse ;
+: PMINUW ( dest src -- ) { HEX: 38 HEX: 3a } HEX: 66 2-operand-rm-sse ;
+: PMINUD ( dest src -- ) { HEX: 38 HEX: 3b } HEX: 66 2-operand-rm-sse ;
+: PMAXSB ( dest src -- ) { HEX: 38 HEX: 3c } HEX: 66 2-operand-rm-sse ;
+: PMAXSD ( dest src -- ) { HEX: 38 HEX: 3d } HEX: 66 2-operand-rm-sse ;
+: PMAXUW ( dest src -- ) { HEX: 38 HEX: 3e } HEX: 66 2-operand-rm-sse ;
+: PMAXUD ( dest src -- ) { HEX: 38 HEX: 3f } HEX: 66 2-operand-rm-sse ;
+: PMULLD ( dest src -- ) { HEX: 38 HEX: 40 } HEX: 66 2-operand-rm-sse ;
+: PHMINPOSUW ( dest src -- ) { HEX: 38 HEX: 41 } HEX: 66 2-operand-rm-sse ;
+: CRC32B ( dest src -- ) { HEX: 38 HEX: f0 } HEX: f2 2-operand-rm-sse ;
+: CRC32 ( dest src -- ) { HEX: 38 HEX: f1 } HEX: f2 2-operand-rm-sse ;
+
+: ROUNDPS ( dest src imm -- ) { HEX: 3a HEX: 08 } HEX: 66 3-operand-rm-sse ;
+: ROUNDPD ( dest src imm -- ) { HEX: 3a HEX: 09 } HEX: 66 3-operand-rm-sse ;
+: ROUNDSS ( dest src imm -- ) { HEX: 3a HEX: 0a } HEX: 66 3-operand-rm-sse ;
+: ROUNDSD ( dest src imm -- ) { HEX: 3a HEX: 0b } HEX: 66 3-operand-rm-sse ;
+: BLENDPS ( dest src imm -- ) { HEX: 3a HEX: 0c } HEX: 66 3-operand-rm-sse ;
+: BLENDPD ( dest src imm -- ) { HEX: 3a HEX: 0d } HEX: 66 3-operand-rm-sse ;
+: PBLENDW ( dest src imm -- ) { HEX: 3a HEX: 0e } HEX: 66 3-operand-rm-sse ;
+: PALIGNR ( dest src imm -- ) { HEX: 3a HEX: 0f } HEX: 66 3-operand-rm-sse ;
+
+: PEXTRB ( dest src imm -- ) { HEX: 3a HEX: 14 } HEX: 66 3-operand-mr-sse ;
+
+<PRIVATE
+: (PEXTRW-sse1) ( dest src imm -- ) HEX: c5 HEX: 66 3-operand-rm-sse ;
+: (PEXTRW-sse4) ( dest src imm -- ) { HEX: 3a HEX: 15 } HEX: 66 3-operand-mr-sse ;
PRIVATE>
-: MOVSS ( dest src -- ) HEX: 10 HEX: f3 2-operand-sse ;
-: MOVSD ( dest src -- ) HEX: 10 HEX: f2 2-operand-sse ;
-: ADDSD ( dest src -- ) HEX: 58 HEX: f2 2-operand-sse ;
-: MULSD ( dest src -- ) HEX: 59 HEX: f2 2-operand-sse ;
-: SUBSD ( dest src -- ) HEX: 5c HEX: f2 2-operand-sse ;
-: DIVSD ( dest src -- ) HEX: 5e HEX: f2 2-operand-sse ;
-: SQRTSD ( dest src -- ) HEX: 51 HEX: f2 2-operand-sse ;
-: UCOMISD ( dest src -- ) HEX: 2e HEX: 66 2-operand-sse ;
-: COMISD ( dest src -- ) HEX: 2f HEX: 66 2-operand-sse ;
-
-: CVTSS2SD ( dest src -- ) HEX: 5a HEX: f3 2-operand-sse ;
-: CVTSD2SS ( dest src -- ) HEX: 5a HEX: f2 2-operand-sse ;
-
-: CVTSI2SD ( dest src -- ) HEX: 2a HEX: f2 2-operand-int/sse ;
-: CVTSD2SI ( dest src -- ) HEX: 2d HEX: f2 2-operand-int/sse ;
-: CVTTSD2SI ( dest src -- ) HEX: 2c HEX: f2 2-operand-int/sse ;
+: PEXTRW ( dest src imm -- ) pick indirect? [ (PEXTRW-sse4) ] [ (PEXTRW-sse1) ] if ;
+: PEXTRD ( dest src imm -- ) { HEX: 3a HEX: 16 } HEX: 66 3-operand-mr-sse ;
+ALIAS: PEXTRQ PEXTRD
+: EXTRACTPS ( dest src imm -- ) { HEX: 3a HEX: 17 } HEX: 66 3-operand-mr-sse ;
+
+: PINSRB ( dest src imm -- ) { HEX: 3a HEX: 20 } HEX: 66 3-operand-rm-sse ;
+: INSERTPS ( dest src imm -- ) { HEX: 3a HEX: 21 } HEX: 66 3-operand-rm-sse ;
+: PINSRD ( dest src imm -- ) { HEX: 3a HEX: 22 } HEX: 66 3-operand-rm-sse ;
+ALIAS: PINSRQ PINSRD
+: DPPS ( dest src imm -- ) { HEX: 3a HEX: 40 } HEX: 66 3-operand-rm-sse ;
+: DPPD ( dest src imm -- ) { HEX: 3a HEX: 41 } HEX: 66 3-operand-rm-sse ;
+: MPSADBW ( dest src imm -- ) { HEX: 3a HEX: 42 } HEX: 66 3-operand-rm-sse ;
+: PCMPESTRM ( dest src imm -- ) { HEX: 3a HEX: 60 } HEX: 66 3-operand-rm-sse ;
+: PCMPESTRI ( dest src imm -- ) { HEX: 3a HEX: 61 } HEX: 66 3-operand-rm-sse ;
+: PCMPISTRM ( dest src imm -- ) { HEX: 3a HEX: 62 } HEX: 66 3-operand-rm-sse ;
+: PCMPISTRI ( dest src imm -- ) { HEX: 3a HEX: 63 } HEX: 66 3-operand-rm-sse ;
+
+: MOVMSKPS ( dest src -- ) HEX: 50 f 2-operand-int/sse ;
+: MOVMSKPD ( dest src -- ) HEX: 50 HEX: 66 2-operand-int/sse ;
+: SQRTPS ( dest src -- ) HEX: 51 f 2-operand-rm-sse ;
+: SQRTPD ( dest src -- ) HEX: 51 HEX: 66 2-operand-rm-sse ;
+: SQRTSD ( dest src -- ) HEX: 51 HEX: f2 2-operand-rm-sse ;
+: SQRTSS ( dest src -- ) HEX: 51 HEX: f3 2-operand-rm-sse ;
+: RSQRTPS ( dest src -- ) HEX: 52 f 2-operand-rm-sse ;
+: RSQRTSS ( dest src -- ) HEX: 52 HEX: f3 2-operand-rm-sse ;
+: RCPPS ( dest src -- ) HEX: 53 f 2-operand-rm-sse ;
+: RCPSS ( dest src -- ) HEX: 53 HEX: f3 2-operand-rm-sse ;
+: ANDPS ( dest src -- ) HEX: 54 f 2-operand-rm-sse ;
+: ANDPD ( dest src -- ) HEX: 54 HEX: 66 2-operand-rm-sse ;
+: ANDNPS ( dest src -- ) HEX: 55 f 2-operand-rm-sse ;
+: ANDNPD ( dest src -- ) HEX: 55 HEX: 66 2-operand-rm-sse ;
+: ORPS ( dest src -- ) HEX: 56 f 2-operand-rm-sse ;
+: ORPD ( dest src -- ) HEX: 56 HEX: 66 2-operand-rm-sse ;
+: XORPS ( dest src -- ) HEX: 57 f 2-operand-rm-sse ;
+: XORPD ( dest src -- ) HEX: 57 HEX: 66 2-operand-rm-sse ;
+: ADDPS ( dest src -- ) HEX: 58 f 2-operand-rm-sse ;
+: ADDPD ( dest src -- ) HEX: 58 HEX: 66 2-operand-rm-sse ;
+: ADDSD ( dest src -- ) HEX: 58 HEX: f2 2-operand-rm-sse ;
+: ADDSS ( dest src -- ) HEX: 58 HEX: f3 2-operand-rm-sse ;
+: MULPS ( dest src -- ) HEX: 59 f 2-operand-rm-sse ;
+: MULPD ( dest src -- ) HEX: 59 HEX: 66 2-operand-rm-sse ;
+: MULSD ( dest src -- ) HEX: 59 HEX: f2 2-operand-rm-sse ;
+: MULSS ( dest src -- ) HEX: 59 HEX: f3 2-operand-rm-sse ;
+: CVTPS2PD ( dest src -- ) HEX: 5a f 2-operand-rm-sse ;
+: CVTPD2PS ( dest src -- ) HEX: 5a HEX: 66 2-operand-rm-sse ;
+: CVTSD2SS ( dest src -- ) HEX: 5a HEX: f2 2-operand-rm-sse ;
+: CVTSS2SD ( dest src -- ) HEX: 5a HEX: f3 2-operand-rm-sse ;
+: CVTDQ2PS ( dest src -- ) HEX: 5b f 2-operand-rm-sse ;
+: CVTPS2DQ ( dest src -- ) HEX: 5b HEX: 66 2-operand-rm-sse ;
+: CVTTPS2DQ ( dest src -- ) HEX: 5b HEX: f3 2-operand-rm-sse ;
+: SUBPS ( dest src -- ) HEX: 5c f 2-operand-rm-sse ;
+: SUBPD ( dest src -- ) HEX: 5c HEX: 66 2-operand-rm-sse ;
+: SUBSD ( dest src -- ) HEX: 5c HEX: f2 2-operand-rm-sse ;
+: SUBSS ( dest src -- ) HEX: 5c HEX: f3 2-operand-rm-sse ;
+: MINPS ( dest src -- ) HEX: 5d f 2-operand-rm-sse ;
+: MINPD ( dest src -- ) HEX: 5d HEX: 66 2-operand-rm-sse ;
+: MINSD ( dest src -- ) HEX: 5d HEX: f2 2-operand-rm-sse ;
+: MINSS ( dest src -- ) HEX: 5d HEX: f3 2-operand-rm-sse ;
+: DIVPS ( dest src -- ) HEX: 5e f 2-operand-rm-sse ;
+: DIVPD ( dest src -- ) HEX: 5e HEX: 66 2-operand-rm-sse ;
+: DIVSD ( dest src -- ) HEX: 5e HEX: f2 2-operand-rm-sse ;
+: DIVSS ( dest src -- ) HEX: 5e HEX: f3 2-operand-rm-sse ;
+: MAXPS ( dest src -- ) HEX: 5f f 2-operand-rm-sse ;
+: MAXPD ( dest src -- ) HEX: 5f HEX: 66 2-operand-rm-sse ;
+: MAXSD ( dest src -- ) HEX: 5f HEX: f2 2-operand-rm-sse ;
+: MAXSS ( dest src -- ) HEX: 5f HEX: f3 2-operand-rm-sse ;
+: PUNPCKLBW ( dest src -- ) HEX: 60 HEX: 66 2-operand-rm-sse ;
+: PUNPCKLWD ( dest src -- ) HEX: 61 HEX: 66 2-operand-rm-sse ;
+: PUNPCKLDQ ( dest src -- ) HEX: 62 HEX: 66 2-operand-rm-sse ;
+: PACKSSWB ( dest src -- ) HEX: 63 HEX: 66 2-operand-rm-sse ;
+: PCMPGTB ( dest src -- ) HEX: 64 HEX: 66 2-operand-rm-sse ;
+: PCMPGTW ( dest src -- ) HEX: 65 HEX: 66 2-operand-rm-sse ;
+: PCMPGTD ( dest src -- ) HEX: 66 HEX: 66 2-operand-rm-sse ;
+: PACKUSWB ( dest src -- ) HEX: 67 HEX: 66 2-operand-rm-sse ;
+: PUNPCKHBW ( dest src -- ) HEX: 68 HEX: 66 2-operand-rm-sse ;
+: PUNPCKHWD ( dest src -- ) HEX: 69 HEX: 66 2-operand-rm-sse ;
+: PUNPCKHDQ ( dest src -- ) HEX: 6a HEX: 66 2-operand-rm-sse ;
+: PACKSSDW ( dest src -- ) HEX: 6b HEX: 66 2-operand-rm-sse ;
+: PUNPCKLQDQ ( dest src -- ) HEX: 6c HEX: 66 2-operand-rm-sse ;
+: PUNPCKHQDQ ( dest src -- ) HEX: 6d HEX: 66 2-operand-rm-sse ;
+
+: MOVD ( dest src -- ) { HEX: 6e HEX: 7e } HEX: 66 2-operand-rm-mr-sse ;
+: MOVDQA ( dest src -- ) { HEX: 6f HEX: 7f } HEX: 66 2-operand-rm-mr-sse ;
+: MOVDQU ( dest src -- ) { HEX: 6f HEX: 7f } HEX: f3 2-operand-rm-mr-sse ;
+
+: PSHUFD ( dest src imm -- ) HEX: 70 HEX: 66 3-operand-rm-sse ;
+: PSHUFLW ( dest src imm -- ) HEX: 70 HEX: f2 3-operand-rm-sse ;
+: PSHUFHW ( dest src imm -- ) HEX: 70 HEX: f3 3-operand-rm-sse ;
+
+<PRIVATE
+
+: (PSRLW-imm) ( dest imm -- ) BIN: 010 HEX: 71 HEX: 66 2-operand-sse-shift ;
+: (PSRAW-imm) ( dest imm -- ) BIN: 100 HEX: 71 HEX: 66 2-operand-sse-shift ;
+: (PSLLW-imm) ( dest imm -- ) BIN: 110 HEX: 71 HEX: 66 2-operand-sse-shift ;
+: (PSRLD-imm) ( dest imm -- ) BIN: 010 HEX: 72 HEX: 66 2-operand-sse-shift ;
+: (PSRAD-imm) ( dest imm -- ) BIN: 100 HEX: 72 HEX: 66 2-operand-sse-shift ;
+: (PSLLD-imm) ( dest imm -- ) BIN: 110 HEX: 72 HEX: 66 2-operand-sse-shift ;
+: (PSRLQ-imm) ( dest imm -- ) BIN: 010 HEX: 73 HEX: 66 2-operand-sse-shift ;
+: (PSLLQ-imm) ( dest imm -- ) BIN: 110 HEX: 73 HEX: 66 2-operand-sse-shift ;
+
+: (PSRLW-reg) ( dest src -- ) HEX: d1 HEX: 66 2-operand-rm-sse ;
+: (PSRLD-reg) ( dest src -- ) HEX: d2 HEX: 66 2-operand-rm-sse ;
+: (PSRLQ-reg) ( dest src -- ) HEX: d3 HEX: 66 2-operand-rm-sse ;
+: (PSRAW-reg) ( dest src -- ) HEX: e1 HEX: 66 2-operand-rm-sse ;
+: (PSRAD-reg) ( dest src -- ) HEX: e2 HEX: 66 2-operand-rm-sse ;
+: (PSLLW-reg) ( dest src -- ) HEX: f1 HEX: 66 2-operand-rm-sse ;
+: (PSLLD-reg) ( dest src -- ) HEX: f2 HEX: 66 2-operand-rm-sse ;
+: (PSLLQ-reg) ( dest src -- ) HEX: f3 HEX: 66 2-operand-rm-sse ;
+
+PRIVATE>
+
+: PSRLW ( dest src -- ) dup integer? [ (PSRLW-imm) ] [ (PSRLW-reg) ] if ;
+: PSRAW ( dest src -- ) dup integer? [ (PSRAW-imm) ] [ (PSRAW-reg) ] if ;
+: PSLLW ( dest src -- ) dup integer? [ (PSLLW-imm) ] [ (PSLLW-reg) ] if ;
+: PSRLD ( dest src -- ) dup integer? [ (PSRLD-imm) ] [ (PSRLD-reg) ] if ;
+: PSRAD ( dest src -- ) dup integer? [ (PSRAD-imm) ] [ (PSRAD-reg) ] if ;
+: PSLLD ( dest src -- ) dup integer? [ (PSLLD-imm) ] [ (PSLLD-reg) ] if ;
+: PSRLQ ( dest src -- ) dup integer? [ (PSRLQ-imm) ] [ (PSRLQ-reg) ] if ;
+: PSLLQ ( dest src -- ) dup integer? [ (PSLLQ-imm) ] [ (PSLLQ-reg) ] if ;
+
+: PSRLDQ ( dest imm -- ) BIN: 011 HEX: 73 HEX: 66 2-operand-sse-shift ;
+: PSLLDQ ( dest imm -- ) BIN: 111 HEX: 73 HEX: 66 2-operand-sse-shift ;
+
+: PCMPEQB ( dest src -- ) HEX: 74 HEX: 66 2-operand-rm-sse ;
+: PCMPEQW ( dest src -- ) HEX: 75 HEX: 66 2-operand-rm-sse ;
+: PCMPEQD ( dest src -- ) HEX: 76 HEX: 66 2-operand-rm-sse ;
+: HADDPD ( dest src -- ) HEX: 7c HEX: 66 2-operand-rm-sse ;
+: HADDPS ( dest src -- ) HEX: 7c HEX: f2 2-operand-rm-sse ;
+: HSUBPD ( dest src -- ) HEX: 7d HEX: 66 2-operand-rm-sse ;
+: HSUBPS ( dest src -- ) HEX: 7d HEX: f2 2-operand-rm-sse ;
+
+: FXSAVE ( dest -- ) { BIN: 000 f { HEX: 0f HEX: ae } } 1-operand ;
+: FXRSTOR ( src -- ) { BIN: 001 f { HEX: 0f HEX: ae } } 1-operand ;
+: LDMXCSR ( src -- ) { BIN: 010 f { HEX: 0f HEX: ae } } 1-operand ;
+: STMXCSR ( dest -- ) { BIN: 011 f { HEX: 0f HEX: ae } } 1-operand ;
+: LFENCE ( -- ) HEX: 0f , HEX: ae , OCT: 350 , ;
+: MFENCE ( -- ) HEX: 0f , HEX: ae , OCT: 360 , ;
+: SFENCE ( -- ) HEX: 0f , HEX: ae , OCT: 370 , ;
+: CLFLUSH ( dest -- ) { BIN: 111 f { HEX: 0f HEX: ae } } 1-operand ;
+
+: POPCNT ( dest src -- ) HEX: b8 HEX: f3 2-operand-rm-sse ;
+
+: CMPEQPS ( dest src -- ) 0 HEX: c2 f 2-operand-sse-cmp ;
+: CMPLTPS ( dest src -- ) 1 HEX: c2 f 2-operand-sse-cmp ;
+: CMPLEPS ( dest src -- ) 2 HEX: c2 f 2-operand-sse-cmp ;
+: CMPUNORDPS ( dest src -- ) 3 HEX: c2 f 2-operand-sse-cmp ;
+: CMPNEQPS ( dest src -- ) 4 HEX: c2 f 2-operand-sse-cmp ;
+: CMPNLTPS ( dest src -- ) 5 HEX: c2 f 2-operand-sse-cmp ;
+: CMPNLEPS ( dest src -- ) 6 HEX: c2 f 2-operand-sse-cmp ;
+: CMPORDPS ( dest src -- ) 7 HEX: c2 f 2-operand-sse-cmp ;
+
+: CMPEQPD ( dest src -- ) 0 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPLTPD ( dest src -- ) 1 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPLEPD ( dest src -- ) 2 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPUNORDPD ( dest src -- ) 3 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPNEQPD ( dest src -- ) 4 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPNLTPD ( dest src -- ) 5 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPNLEPD ( dest src -- ) 6 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+: CMPORDPD ( dest src -- ) 7 HEX: c2 HEX: 66 2-operand-sse-cmp ;
+
+: CMPEQSD ( dest src -- ) 0 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPLTSD ( dest src -- ) 1 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPLESD ( dest src -- ) 2 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPUNORDSD ( dest src -- ) 3 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPNEQSD ( dest src -- ) 4 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPNLTSD ( dest src -- ) 5 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPNLESD ( dest src -- ) 6 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+: CMPORDSD ( dest src -- ) 7 HEX: c2 HEX: f2 2-operand-sse-cmp ;
+
+: CMPEQSS ( dest src -- ) 0 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPLTSS ( dest src -- ) 1 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPLESS ( dest src -- ) 2 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPUNORDSS ( dest src -- ) 3 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPNEQSS ( dest src -- ) 4 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPNLTSS ( dest src -- ) 5 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPNLESS ( dest src -- ) 6 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+: CMPORDSS ( dest src -- ) 7 HEX: c2 HEX: f3 2-operand-sse-cmp ;
+
+: MOVNTI ( dest src -- ) { HEX: 0f HEX: c3 } (2-operand) ;
+
+: PINSRW ( dest src imm -- ) HEX: c4 HEX: 66 3-operand-rm-sse ;
+: SHUFPS ( dest src imm -- ) HEX: c6 f 3-operand-rm-sse ;
+: SHUFPD ( dest src imm -- ) HEX: c6 HEX: 66 3-operand-rm-sse ;
+
+: ADDSUBPD ( dest src -- ) HEX: d0 HEX: 66 2-operand-rm-sse ;
+: ADDSUBPS ( dest src -- ) HEX: d0 HEX: f2 2-operand-rm-sse ;
+: PADDQ ( dest src -- ) HEX: d4 HEX: 66 2-operand-rm-sse ;
+: PMULLW ( dest src -- ) HEX: d5 HEX: 66 2-operand-rm-sse ;
+: PMOVMSKB ( dest src -- ) HEX: d7 HEX: 66 2-operand-rm-sse ;
+: PSUBUSB ( dest src -- ) HEX: d8 HEX: 66 2-operand-rm-sse ;
+: PSUBUSW ( dest src -- ) HEX: d9 HEX: 66 2-operand-rm-sse ;
+: PMINUB ( dest src -- ) HEX: da HEX: 66 2-operand-rm-sse ;
+: PAND ( dest src -- ) HEX: db HEX: 66 2-operand-rm-sse ;
+: PADDUSB ( dest src -- ) HEX: dc HEX: 66 2-operand-rm-sse ;
+: PADDUSW ( dest src -- ) HEX: dd HEX: 66 2-operand-rm-sse ;
+: PMAXUB ( dest src -- ) HEX: de HEX: 66 2-operand-rm-sse ;
+: PANDN ( dest src -- ) HEX: df HEX: 66 2-operand-rm-sse ;
+: PAVGB ( dest src -- ) HEX: e0 HEX: 66 2-operand-rm-sse ;
+: PAVGW ( dest src -- ) HEX: e3 HEX: 66 2-operand-rm-sse ;
+: PMULHUW ( dest src -- ) HEX: e4 HEX: 66 2-operand-rm-sse ;
+: PMULHW ( dest src -- ) HEX: e5 HEX: 66 2-operand-rm-sse ;
+: CVTTPD2DQ ( dest src -- ) HEX: e6 HEX: 66 2-operand-rm-sse ;
+: CVTPD2DQ ( dest src -- ) HEX: e6 HEX: f2 2-operand-rm-sse ;
+: CVTDQ2PD ( dest src -- ) HEX: e6 HEX: f3 2-operand-rm-sse ;
+
+: MOVNTDQ ( dest src -- ) HEX: e7 HEX: 66 2-operand-mr-sse ;
+
+: PSUBSB ( dest src -- ) HEX: e8 HEX: 66 2-operand-rm-sse ;
+: PSUBSW ( dest src -- ) HEX: e9 HEX: 66 2-operand-rm-sse ;
+: PMINSW ( dest src -- ) HEX: ea HEX: 66 2-operand-rm-sse ;
+: POR ( dest src -- ) HEX: eb HEX: 66 2-operand-rm-sse ;
+: PADDSB ( dest src -- ) HEX: ec HEX: 66 2-operand-rm-sse ;
+: PADDSW ( dest src -- ) HEX: ed HEX: 66 2-operand-rm-sse ;
+: PMAXSW ( dest src -- ) HEX: ee HEX: 66 2-operand-rm-sse ;
+: PXOR ( dest src -- ) HEX: ef HEX: 66 2-operand-rm-sse ;
+: LDDQU ( dest src -- ) HEX: f0 HEX: f2 2-operand-rm-sse ;
+: PMULUDQ ( dest src -- ) HEX: f4 HEX: 66 2-operand-rm-sse ;
+: PMADDWD ( dest src -- ) HEX: f5 HEX: 66 2-operand-rm-sse ;
+: PSADBW ( dest src -- ) HEX: f6 HEX: 66 2-operand-rm-sse ;
+: MASKMOVDQU ( dest src -- ) HEX: f7 HEX: 66 2-operand-rm-sse ;
+: PSUBB ( dest src -- ) HEX: f8 HEX: 66 2-operand-rm-sse ;
+: PSUBW ( dest src -- ) HEX: f9 HEX: 66 2-operand-rm-sse ;
+: PSUBD ( dest src -- ) HEX: fa HEX: 66 2-operand-rm-sse ;
+: PSUBQ ( dest src -- ) HEX: fb HEX: 66 2-operand-rm-sse ;
+: PADDB ( dest src -- ) HEX: fc HEX: 66 2-operand-rm-sse ;
+: PADDW ( dest src -- ) HEX: fd HEX: 66 2-operand-rm-sse ;
+: PADDD ( dest src -- ) HEX: fe HEX: 66 2-operand-rm-sse ;
+
+! x86-64 branch prediction hints
+
+: HWNT ( -- ) HEX: 2e , ; ! Hint branch Weakly Not Taken
+: HST ( -- ) HEX: 3e , ; ! Hint branch Strongly Taken
+
--- /dev/null
+! Copyright (C) 2008, 2009 Slava Pestov, Joe Groff.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel words math accessors sequences namespaces
+assocs layouts cpu.x86.assembler.syntax ;
+IN: cpu.x86.assembler.operands
+
+! In 32-bit mode, { 1234 } is absolute indirect addressing.
+! In 64-bit mode, { 1234 } is RIP-relative.
+! Beware!
+
+REGISTERS: 8 AL CL DL BL SPL BPL SIL DIL R8B R9B R10B R11B R12B R13B R14B R15B ;
+
+ALIAS: AH SPL
+ALIAS: CH BPL
+ALIAS: DH SIL
+ALIAS: BH DIL
+
+REGISTERS: 16 AX CX DX BX SP BP SI DI R8W R9W R10W R11W R12W R13W R14W R15W ;
+
+REGISTERS: 32 EAX ECX EDX EBX ESP EBP ESI EDI R8D R9D R10D R11D R12D R13D R14D R15D ;
+
+REGISTERS: 64
+RAX RCX RDX RBX RSP RBP RSI RDI R8 R9 R10 R11 R12 R13 R14 R15 ;
+
+REGISTERS: 128
+XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
+XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15 ;
+
+PREDICATE: register < word
+ "register" word-prop ;
+
+<PRIVATE
+
+PREDICATE: register-8 < register
+ "register-size" word-prop 8 = ;
+
+PREDICATE: register-16 < register
+ "register-size" word-prop 16 = ;
+
+PREDICATE: register-32 < register
+ "register-size" word-prop 32 = ;
+
+PREDICATE: register-64 < register
+ "register-size" word-prop 64 = ;
+
+PREDICATE: register-128 < register
+ "register-size" word-prop 128 = ;
+
+GENERIC: extended? ( op -- ? )
+
+M: object extended? drop f ;
+
+M: register extended? "register" word-prop 7 > ;
+
+! Addressing modes
+TUPLE: indirect base index scale displacement ;
+
+M: indirect extended? base>> extended? ;
+
+: canonicalize-EBP ( indirect -- indirect )
+ #! { EBP } ==> { EBP 0 }
+ dup [ base>> { EBP RBP R13 } member? ] [ displacement>> not ] bi and
+ [ 0 >>displacement ] when ;
+
+ERROR: bad-index indirect ;
+
+: check-ESP ( indirect -- indirect )
+ dup index>> { ESP RSP } memq? [ bad-index ] when ;
+
+: canonicalize ( indirect -- indirect )
+ #! Modify the indirect to work around certain addressing mode
+ #! quirks.
+ canonicalize-EBP check-ESP ;
+
+: <indirect> ( base index scale displacement -- indirect )
+ indirect boa canonicalize ;
+
+! Utilities
+UNION: operand register indirect ;
+
+GENERIC: operand-64? ( operand -- ? )
+
+M: indirect operand-64?
+ [ base>> ] [ index>> ] bi [ operand-64? ] either? ;
+
+M: register-64 operand-64? drop t ;
+
+M: object operand-64? drop f ;
+
+PRIVATE>
+
+: [] ( reg/displacement -- indirect )
+ dup integer? [ [ f f f ] dip ] [ f f f ] if <indirect> ;
+
+: [+] ( reg displacement -- indirect )
+ dup integer?
+ [ dup zero? [ drop f ] when [ f f ] dip ]
+ [ f f ] if
+ <indirect> ;
+
+TUPLE: byte value ;
+
+C: <byte> byte
+
+: extended-8-bit-register? ( register -- ? )
+ { SPL BPL SIL DIL } memq? ;
+
+: n-bit-version-of ( register n -- register' )
+ ! Certain 8-bit registers don't exist in 32-bit mode...
+ [ "register" word-prop ] dip registers get at nth
+ dup extended-8-bit-register? cell 4 = and
+ [ drop f ] when ;
+
+: 8-bit-version-of ( register -- register' ) 8 n-bit-version-of ;
+: 16-bit-version-of ( register -- register' ) 16 n-bit-version-of ;
+: 32-bit-version-of ( register -- register' ) 32 n-bit-version-of ;
+: 64-bit-version-of ( register -- register' ) 64 n-bit-version-of ;
+: native-version-of ( register -- register' ) cell-bits n-bit-version-of ;
\ No newline at end of file
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel words words.symbol sequences lexer parser fry ;
+USING: kernel words words.symbol sequences lexer parser fry
+namespaces combinators assocs ;
IN: cpu.x86.assembler.syntax
-: define-register ( name num size -- )
- [ "cpu.x86.assembler" create dup define-symbol ] 2dip
- [ dupd "register" set-word-prop ] dip
- "register-size" set-word-prop ;
+SYMBOL: registers
-: define-registers ( names size -- )
- '[ _ define-register ] each-index ;
+registers [ H{ } clone ] initialize
-SYNTAX: REGISTERS: scan-word ";" parse-tokens swap define-registers ;
+: define-register ( name num size -- word )
+ [ "cpu.x86.assembler.operands" create ] 2dip {
+ [ 2drop ]
+ [ 2drop define-symbol ]
+ [ drop "register" set-word-prop ]
+ [ nip "register-size" set-word-prop ]
+ } 3cleave ;
+
+: define-registers ( size names -- )
+ [ swap '[ _ define-register ] map-index ] [ drop ] 2bi
+ registers get set-at ;
+
+SYNTAX: REGISTERS: scan-word ";" parse-tokens define-registers ;
! Copyright (C) 2007, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: bootstrap.image.private kernel kernel.private namespaces
-system cpu.x86.assembler layouts compiler.units math
-math.private compiler.constants vocabs slots.private words
-locals.backend make sequences combinators arrays ;
+USING: bootstrap.image.private kernel kernel.private namespaces system
+layouts compiler.units math math.private compiler.constants vocabs
+slots.private words locals.backend make sequences combinators arrays
+ cpu.x86.assembler cpu.x86.assembler.operands ;
IN: bootstrap.x86
big-endian off
temp2 temp1 MOV
bootstrap-cell 8 = [ temp2 1 SHL ] when
! key &= cache.length - 1
- temp2 mega-cache-size get 1- bootstrap-cell * AND
+ temp2 mega-cache-size get 1 - bootstrap-cell * AND
! cache += array-start-offset
temp0 array-start-offset ADD
! cache += key
! make a copy
mod-arg div-arg MOV
! sign-extend
- mod-arg bootstrap-cell-bits 1- SAR
+ mod-arg bootstrap-cell-bits 1 - SAR
! divide
temp3 IDIV ;
-IN: cpu.x86.features.tests
USING: cpu.x86.features tools.test kernel sequences math system ;
+IN: cpu.x86.features.tests
cpu x86? [
[ t ] [ sse2? { t f } member? ] unit-test
[ t ] [ [ 10000 [ ] times ] count-instructions integer? ] unit-test
-] when
\ No newline at end of file
+] when
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs alien alien.c-types arrays strings
-cpu.x86.assembler cpu.x86.assembler.private cpu.architecture
-kernel kernel.private math memory namespaces make sequences
-words system layouts combinators math.order fry locals
-compiler.constants compiler.cfg.registers
-compiler.cfg.instructions compiler.cfg.intrinsics
-compiler.cfg.stack-frame compiler.codegen compiler.codegen.fixup ;
+cpu.x86.assembler cpu.x86.assembler.private cpu.x86.assembler.operands
+cpu.architecture kernel kernel.private math memory namespaces make
+sequences words system layouts combinators math.order fry locals
+compiler.constants
+compiler.cfg.registers
+compiler.cfg.instructions
+compiler.cfg.intrinsics
+compiler.cfg.comparisons
+compiler.cfg.stack-frame
+compiler.codegen
+compiler.codegen.fixup ;
IN: cpu.x86
<< enable-fixnum-log2 >>
: param@ ( n -- op ) reserved-area-size + stack@ ;
-: spill-integer@ ( n -- op ) spill-integer-offset param@ ;
-
-: spill-float@ ( n -- op ) spill-float-offset param@ ;
+: spill@ ( n -- op ) spill-offset param@ ;
: gc-root@ ( n -- op ) gc-root-offset param@ ;
M: x86 stack-frame-size ( stack-frame -- i )
(stack-frame-size) 3 cells reserved-area-size + + align-stack ;
-HOOK: temp-reg-1 cpu ( -- reg )
-HOOK: temp-reg-2 cpu ( -- reg )
+! Must be a volatile register not used for parameter passing, for safe
+! use in calls in and out of C
+HOOK: temp-reg cpu ( -- reg )
+! Fastcall calling convention
HOOK: param-reg-1 cpu ( -- reg )
HOOK: param-reg-2 cpu ( -- reg )
HOOK: pic-tail-reg cpu ( -- reg )
-M: x86 %load-immediate MOV ;
+M: x86 %load-immediate dup 0 = [ drop dup XOR ] [ MOV ] if ;
M: x86 %load-reference swap 0 MOV rc-absolute-cell rel-immediate ;
: align-code ( n -- )
0 <repetition> % ;
-M: x86 %dispatch-label ( label -- )
- 0 cell, rc-absolute-cell label-fixup ;
-
:: (%slot) ( obj slot tag temp -- op )
temp slot obj [+] LEA
temp tag neg [+] ; inline
M: x86 %set-slot ( src obj slot tag temp -- ) (%slot) swap MOV ;
M: x86 %set-slot-imm ( src obj slot tag -- ) (%slot-imm) swap MOV ;
-M: x86 %add [+] LEA ;
-M: x86 %add-imm [+] LEA ;
+M: x86 %add 2over eq? [ nip ADD ] [ [+] LEA ] if ;
+M: x86 %add-imm 2over eq? [ nip ADD ] [ [+] LEA ] if ;
M: x86 %sub nip SUB ;
-M: x86 %sub-imm neg [+] LEA ;
+M: x86 %sub-imm 2over eq? [ nip SUB ] [ neg [+] LEA ] if ;
M: x86 %mul nip swap IMUL2 ;
-M: x86 %mul-imm nip IMUL2 ;
+M: x86 %mul-imm IMUL3 ;
M: x86 %and nip AND ;
M: x86 %and-imm nip AND ;
M: x86 %or nip OR ;
M: x86 %not drop NOT ;
M: x86 %log2 BSR ;
-: ?MOV ( dst src -- )
- 2dup = [ 2drop ] [ MOV ] if ; inline
-
-:: move>args ( src1 src2 -- )
- {
- { [ src1 param-reg-2 = ] [ param-reg-1 src2 ?MOV param-reg-1 param-reg-2 XCHG ] }
- { [ src1 param-reg-1 = ] [ param-reg-2 src2 ?MOV ] }
- { [ src2 param-reg-1 = ] [ param-reg-2 src1 ?MOV param-reg-1 param-reg-2 XCHG ] }
- { [ src2 param-reg-2 = ] [ param-reg-1 src1 ?MOV ] }
- [
- param-reg-1 src1 MOV
- param-reg-2 src2 MOV
- ]
- } cond ;
-
-HOOK: %alien-invoke-tail cpu ( func dll -- )
-
-:: overflow-template ( src1 src2 insn inverse func -- )
- <label> "no-overflow" set
+:: overflow-template ( label dst src1 src2 insn -- )
src1 src2 insn call
- ds-reg [] src1 MOV
- "no-overflow" get JNO
- src1 src2 inverse call
- src1 src2 move>args
- %prepare-alien-invoke
- func f %alien-invoke
- "no-overflow" resolve-label ; inline
+ label JO ; inline
-:: overflow-template-tail ( src1 src2 insn inverse func -- )
- <label> "no-overflow" set
- src1 src2 insn call
- "no-overflow" get JNO
- src1 src2 inverse call
- src1 src2 move>args
- %prepare-alien-invoke
- func f %alien-invoke-tail
- "no-overflow" resolve-label
- ds-reg [] src1 MOV
- 0 RET ; inline
-
-M: x86 %fixnum-add ( src1 src2 -- )
- [ ADD ] [ SUB ] "overflow_fixnum_add" overflow-template ;
-
-M: x86 %fixnum-add-tail ( src1 src2 -- )
- [ ADD ] [ SUB ] "overflow_fixnum_add" overflow-template-tail ;
-
-M: x86 %fixnum-sub ( src1 src2 -- )
- [ SUB ] [ ADD ] "overflow_fixnum_subtract" overflow-template ;
-
-M: x86 %fixnum-sub-tail ( src1 src2 -- )
- [ SUB ] [ ADD ] "overflow_fixnum_subtract" overflow-template-tail ;
-
-M:: x86 %fixnum-mul ( src1 src2 temp1 temp2 -- )
- "no-overflow" define-label
- temp1 src1 MOV
- temp1 tag-bits get SAR
- src2 temp1 IMUL2
- ds-reg [] temp1 MOV
- "no-overflow" get JNO
- src1 src2 move>args
- param-reg-1 tag-bits get SAR
- param-reg-2 tag-bits get SAR
- %prepare-alien-invoke
- "overflow_fixnum_multiply" f %alien-invoke
- "no-overflow" resolve-label ;
-
-M:: x86 %fixnum-mul-tail ( src1 src2 temp1 temp2 -- )
- "overflow" define-label
- temp1 src1 MOV
- temp1 tag-bits get SAR
- src2 temp1 IMUL2
- "overflow" get JO
- ds-reg [] temp1 MOV
- 0 RET
- "overflow" resolve-label
- src1 src2 move>args
- param-reg-1 tag-bits get SAR
- param-reg-2 tag-bits get SAR
- %prepare-alien-invoke
- "overflow_fixnum_multiply" f %alien-invoke-tail ;
+M: x86 %fixnum-add ( label dst src1 src2 -- )
+ [ ADD ] overflow-template ;
+
+M: x86 %fixnum-sub ( label dst src1 src2 -- )
+ [ SUB ] overflow-template ;
+
+M: x86 %fixnum-mul ( label dst src1 src2 -- )
+ [ swap IMUL2 ] overflow-template ;
: bignum@ ( reg n -- op )
cells bignum tag-number - [+] ; inline
dst 3 bignum@ src MOV
! Compute sign
temp src MOV
- temp cell-bits 1- SAR
+ temp cell-bits 1 - SAR
temp 1 AND
! Store sign
dst 2 bignum@ temp MOV
M: x86 %sub-float nip SUBSD ;
M: x86 %mul-float nip MULSD ;
M: x86 %div-float nip DIVSD ;
+M: x86 %sqrt SQRTSD ;
M: x86 %integer>float CVTSI2SD ;
M: x86 %float>integer CVTTSD2SI ;
-M: x86 %copy ( dst src -- ) ?MOV ;
+GENERIC: copy-register* ( dst src rep -- )
+
+M: int-rep copy-register* drop MOV ;
+M: tagged-rep copy-register* drop MOV ;
+M: single-float-rep copy-register* drop MOVSS ;
+M: double-float-rep copy-register* drop MOVSD ;
+
+: copy-register ( dst src rep -- )
+ 2over eq? [ 3drop ] [ copy-register* ] if ;
-M: x86 %copy-float ( dst src -- )
- 2dup = [ 2drop ] [ MOVSD ] if ;
+M: x86 %copy ( dst src rep -- ) copy-register ;
M: x86 %unbox-float ( dst src -- )
float-offset [+] MOVSD ;
: alien@ ( reg n -- op ) cells alien tag-number - [+] ;
+:: %allot-alien ( dst base displacement temp -- )
+ dst 4 cells alien temp %allot
+ dst 1 alien@ base MOV ! alien
+ dst 2 alien@ \ f tag-number MOV ! expired
+ dst 3 alien@ displacement MOV ! displacement
+ ;
+
M:: x86 %box-alien ( dst src temp -- )
[
"end" define-label
dst \ f tag-number MOV
src 0 CMP
"end" get JE
- dst 4 cells alien temp %allot
- dst 1 alien@ \ f tag-number MOV
- dst 2 alien@ \ f tag-number MOV
- ! Store src in alien-offset slot
- dst 3 alien@ src MOV
+ dst \ f tag-number src temp %allot-alien
"end" resolve-label
] with-scope ;
-: small-reg-8 ( reg -- reg' )
- H{
- { EAX RAX }
- { ECX RCX }
- { EDX RDX }
- { EBX RBX }
- { ESP RSP }
- { EBP RBP }
- { ESI RSP }
- { EDI RDI }
-
- { RAX RAX }
- { RCX RCX }
- { RDX RDX }
- { RBX RBX }
- { RSP RSP }
- { RBP RBP }
- { RSI RSP }
- { RDI RDI }
- } at ; inline
-
-: small-reg-4 ( reg -- reg' )
- small-reg-8 H{
- { RAX EAX }
- { RCX ECX }
- { RDX EDX }
- { RBX EBX }
- { RSP ESP }
- { RBP EBP }
- { RSI ESP }
- { RDI EDI }
- } at ; inline
-
-: small-reg-2 ( reg -- reg' )
- small-reg-4 H{
- { EAX AX }
- { ECX CX }
- { EDX DX }
- { EBX BX }
- { ESP SP }
- { EBP BP }
- { ESI SI }
- { EDI DI }
- } at ; inline
-
-: small-reg-1 ( reg -- reg' )
- small-reg-4 {
- { EAX AL }
- { ECX CL }
- { EDX DL }
- { EBX BL }
- } at ; inline
-
-: small-reg ( reg size -- reg' )
- {
- { 1 [ small-reg-1 ] }
- { 2 [ small-reg-2 ] }
- { 4 [ small-reg-4 ] }
- { 8 [ small-reg-8 ] }
- } case ;
+M:: x86 %box-displaced-alien ( dst displacement base temp -- )
+ [
+ "end" define-label
+ "ok" define-label
+ ! If displacement is zero, return the base
+ dst base MOV
+ displacement 0 CMP
+ "end" get JE
+ ! If base is already a displaced alien, unpack it
+ base \ f tag-number CMP
+ "ok" get JE
+ base header-offset [+] alien type-number tag-fixnum CMP
+ "ok" get JNE
+ ! displacement += base.displacement
+ displacement base 3 alien@ ADD
+ ! base = base.base
+ base base 1 alien@ MOV
+ "ok" resolve-label
+ dst base displacement temp %allot-alien
+ "end" resolve-label
+ ] with-scope ;
-HOOK: small-regs cpu ( -- regs )
+! The 'small-reg' mess is pretty crappy, but its only used on x86-32.
+! On x86-64, all registers have 8-bit versions. However, a similar
+! problem arises for shifts, where the shift count must be in CL, and
+! so one day I will fix this properly by adding precoloring to the
+! register allocator.
-M: x86.32 small-regs { EAX ECX EDX EBX } ;
-M: x86.64 small-regs { RAX RCX RDX RBX } ;
+HOOK: has-small-reg? cpu ( reg size -- ? )
-HOOK: small-reg-native cpu ( reg -- reg' )
+CONSTANT: have-byte-regs { EAX ECX EDX EBX }
-M: x86.32 small-reg-native small-reg-4 ;
-M: x86.64 small-reg-native small-reg-8 ;
+M: x86.32 has-small-reg?
+ {
+ { 8 [ have-byte-regs memq? ] }
+ { 16 [ drop t ] }
+ { 32 [ drop t ] }
+ } case ;
+
+M: x86.64 has-small-reg? 2drop t ;
: small-reg-that-isn't ( exclude -- reg' )
- small-regs swap [ small-reg-native ] map '[ _ memq? not ] find nip ;
+ [ have-byte-regs ] dip
+ [ native-version-of ] map
+ '[ _ memq? not ] find nip ;
: with-save/restore ( reg quot -- )
[ drop PUSH ] [ call ] [ drop POP ] 2tri ; inline
-:: with-small-register ( dst exclude quot: ( new-dst -- ) -- )
- #! If the destination register overlaps a small register, we
- #! call the quot with that. Otherwise, we find a small
- #! register that is not in exclude, and call quot, saving
- #! and restoring the small register.
- dst small-reg-native small-regs memq? [ dst quot call ] [
+:: with-small-register ( dst exclude size quot: ( new-dst -- ) -- )
+ ! If the destination register overlaps a small register with
+ ! 'size' bits, we call the quot with that. Otherwise, we find a
+ ! small register that is not in exclude, and call quot, saving and
+ ! restoring the small register.
+ dst size has-small-reg? [ dst quot call ] [
exclude small-reg-that-isn't
[ quot call ] with-save/restore
] if ; inline
+: ?MOV ( dst src -- )
+ 2dup = [ 2drop ] [ MOV ] if ; inline
+
M:: x86 %string-nth ( dst src index temp -- )
+ ! We request a small-reg of size 8 since those of size 16 are
+ ! a superset.
"end" define-label
- dst { src index temp } [| new-dst |
+ dst { src index temp } 8 [| new-dst |
! Load the least significant 7 bits into new-dst.
! 8th bit indicates whether we have to load from
! the aux vector or not.
temp src index [+] LEA
- new-dst 1 small-reg temp string-offset [+] MOV
- new-dst new-dst 1 small-reg MOVZX
+ new-dst 8-bit-version-of temp string-offset [+] MOV
+ new-dst new-dst 8-bit-version-of MOVZX
! Do we have to look at the aux vector?
new-dst HEX: 80 CMP
"end" get JL
new-dst index ADD
new-dst index ADD
! Load high 16 bits
- new-dst 2 small-reg new-dst byte-array-offset [+] MOV
- new-dst new-dst 2 small-reg MOVZX
+ new-dst 16-bit-version-of new-dst byte-array-offset [+] MOV
+ new-dst new-dst 16-bit-version-of MOVZX
new-dst 7 SHL
! Compute code point
new-dst temp XOR
] with-small-register ;
M:: x86 %set-string-nth-fast ( ch str index temp -- )
- ch { index str temp } [| new-ch |
+ ch { index str temp } 8 [| new-ch |
new-ch ch ?MOV
temp str index [+] LEA
- temp string-offset [+] new-ch 1 small-reg MOV
+ temp string-offset [+] new-ch 8-bit-version-of MOV
] with-small-register ;
:: %alien-integer-getter ( dst src size quot -- )
- dst { src } [| new-dst |
- new-dst dup size small-reg dup src [] MOV
+ dst { src } size [| new-dst |
+ new-dst dup size n-bit-version-of dup src [] MOV
quot call
dst new-dst ?MOV
] with-small-register ; inline
: %alien-unsigned-getter ( dst src size -- )
[ MOVZX ] %alien-integer-getter ; inline
-M: x86 %alien-unsigned-1 1 %alien-unsigned-getter ;
-M: x86 %alien-unsigned-2 2 %alien-unsigned-getter ;
+M: x86 %alien-unsigned-1 8 %alien-unsigned-getter ;
+M: x86 %alien-unsigned-2 16 %alien-unsigned-getter ;
+M: x86 %alien-unsigned-4 32 [ 2drop ] %alien-integer-getter ;
: %alien-signed-getter ( dst src size -- )
[ MOVSX ] %alien-integer-getter ; inline
-M: x86 %alien-signed-1 1 %alien-signed-getter ;
-M: x86 %alien-signed-2 2 %alien-signed-getter ;
-M: x86 %alien-signed-4 4 %alien-signed-getter ;
-
-M: x86 %alien-unsigned-4 4 [ 2drop ] %alien-integer-getter ;
+M: x86 %alien-signed-1 8 %alien-signed-getter ;
+M: x86 %alien-signed-2 16 %alien-signed-getter ;
+M: x86 %alien-signed-4 32 %alien-signed-getter ;
M: x86 %alien-cell [] MOV ;
M: x86 %alien-float dupd [] MOVSS dup CVTSS2SD ;
M: x86 %alien-double [] MOVSD ;
:: %alien-integer-setter ( ptr value size -- )
- value { ptr } [| new-value |
+ value { ptr } size [| new-value |
new-value value ?MOV
- ptr [] new-value size small-reg MOV
+ ptr [] new-value size n-bit-version-of MOV
] with-small-register ; inline
-M: x86 %set-alien-integer-1 1 %alien-integer-setter ;
-M: x86 %set-alien-integer-2 2 %alien-integer-setter ;
-M: x86 %set-alien-integer-4 4 %alien-integer-setter ;
+M: x86 %set-alien-integer-1 8 %alien-integer-setter ;
+M: x86 %set-alien-integer-2 16 %alien-integer-setter ;
+M: x86 %set-alien-integer-4 32 %alien-integer-setter ;
M: x86 %set-alien-cell [ [] ] dip MOV ;
M: x86 %set-alien-float dup dup CVTSD2SS [ [] ] dip MOVSS ;
M: x86 %set-alien-double [ [] ] dip MOVSD ;
+: shift-count? ( reg -- ? ) { ECX RCX } memq? ;
+
+:: emit-shift ( dst src1 src2 quot -- )
+ src2 shift-count? [
+ dst CL quot call
+ ] [
+ dst shift-count? [
+ dst src2 XCHG
+ src2 CL quot call
+ dst src2 XCHG
+ ] [
+ ECX native-version-of [
+ CL src2 MOV
+ drop dst CL quot call
+ ] with-save/restore
+ ] if
+ ] if ; inline
+
+M: x86 %shl [ SHL ] emit-shift ;
+M: x86 %shr [ SHR ] emit-shift ;
+M: x86 %sar [ SAR ] emit-shift ;
+
: load-zone-ptr ( reg -- )
#! Load pointer to start of zone array
0 MOV "nursery" f rc-absolute-cell rel-dlsym ;
table table [] MOV
table card# [+] card-mark <byte> MOV ;
-:: check-nursery ( temp1 temp2 -- )
+M:: x86 %check-nursery ( label temp1 temp2 -- )
temp1 load-zone-ptr
temp2 temp1 cell [+] MOV
temp2 1024 ADD
temp1 temp1 3 cells [+] MOV
- temp2 temp1 CMP ;
-
-GENERIC# save-gc-root 1 ( gc-root operand temp -- )
-
-M:: spill-slot save-gc-root ( gc-root spill-slot temp -- )
- temp spill-slot n>> spill-integer@ MOV
- gc-root gc-root@ temp MOV ;
-
-M:: word save-gc-root ( gc-root register temp -- )
- gc-root gc-root@ register MOV ;
+ temp2 temp1 CMP
+ label JLE ;
-: save-gc-roots ( gc-roots temp -- )
- '[ _ save-gc-root ] assoc-each ;
+M: x86 %save-gc-root ( gc-root register -- ) [ gc-root@ ] dip MOV ;
-GENERIC# load-gc-root 1 ( gc-root operand temp -- )
+M: x86 %load-gc-root ( gc-root register -- ) swap gc-root@ MOV ;
-M:: spill-slot load-gc-root ( gc-root spill-slot temp -- )
- temp gc-root gc-root@ MOV
- spill-slot n>> spill-integer@ temp MOV ;
-
-M:: word load-gc-root ( gc-root register temp -- )
- register gc-root gc-root@ MOV ;
-
-: load-gc-roots ( gc-roots temp -- )
- '[ _ load-gc-root ] assoc-each ;
-
-:: call-gc ( gc-root-count -- )
+M:: x86 %call-gc ( gc-root-count -- )
! Pass pointer to start of GC roots as first parameter
param-reg-1 gc-root-base param@ LEA
! Pass number of roots as second parameter
%prepare-alien-invoke
"inline_gc" f %alien-invoke ;
-M:: x86 %gc ( temp1 temp2 gc-roots gc-root-count -- )
- "end" define-label
- temp1 temp2 check-nursery
- "end" get JLE
- gc-roots temp1 save-gc-roots
- gc-root-count call-gc
- gc-roots temp1 load-gc-roots
- "end" resolve-label ;
-
M: x86 %alien-global
[ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;
{ cc/= [ JNE ] }
} case ;
-M: x86 %spill-integer ( src n -- ) spill-integer@ swap MOV ;
-M: x86 %reload-integer ( dst n -- ) spill-integer@ MOV ;
-
-M: x86 %spill-float ( src n -- ) spill-float@ swap MOVSD ;
-M: x86 %reload-float ( dst n -- ) spill-float@ MOVSD ;
+M: x86 %spill ( src n rep -- ) [ spill@ swap ] dip copy-register ;
+M: x86 %reload ( dst n rep -- ) [ spill@ ] dip copy-register ;
M: x86 %loop-entry 16 code-alignment [ NOP ] times ;
-M: int-regs %save-param-reg drop [ param@ ] dip MOV ;
-M: int-regs %load-param-reg drop swap param@ MOV ;
-
-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 [ param@ ] 2dip MOVSS/D ;
-M: float-regs %load-param-reg [ swap param@ ] dip MOVSS/D ;
-
-GENERIC: push-return-reg ( reg-class -- )
-GENERIC: load-return-reg ( n reg-class -- )
-GENERIC: store-return-reg ( n reg-class -- )
-
M: x86 %prepare-alien-invoke
#! Save Factor stack pointers in case the C code calls a
#! callback which does a GC, which must reliably trace
#! all roots.
- temp-reg-1 "stack_chain" f %alien-global
- temp-reg-1 temp-reg-1 [] MOV
- temp-reg-1 [] stack-reg MOV
- temp-reg-1 [] cell SUB
- temp-reg-1 2 cells [+] ds-reg MOV
- temp-reg-1 3 cells [+] rs-reg MOV ;
+ temp-reg "stack_chain" f %alien-global
+ temp-reg temp-reg [] MOV
+ temp-reg [] stack-reg MOV
+ temp-reg [] cell SUB
+ temp-reg 2 cells [+] ds-reg MOV
+ temp-reg 3 cells [+] rs-reg MOV ;
M: x86 value-struct? drop t ;
dup init-result-set ;
M: postgresql-result-set advance-row ( result-set -- )
- [ 1+ ] change-n drop ;
+ [ 1 + ] change-n drop ;
M: postgresql-result-set more-rows? ( result-set -- ? )
[ n>> ] [ max>> ] bi < ;
M: random-id-generator eval-generator ( singleton -- obj )
drop
system-random-generator get [
- 63 [ random-bits ] keep 1- set-bit
+ 63 [ random-bits ] keep 1 - set-bit
] with-random ;
: interval-comparison ( ? str -- str )
} define-persistent
[ bignum-test drop-table ] ignore-errors
[ ] [ bignum-test ensure-table ] unit-test
- [ ] [ 63 2^ 1- dup dup <bignum-test> insert-tuple ] unit-test ;
+ [ ] [ 63 2^ 1 - dup dup <bignum-test> insert-tuple ] unit-test ;
! sqlite only
! [ T{ bignum-test f 1
-IN: debugger.tests\r
USING: debugger kernel continuations tools.test ;\r
+IN: debugger.tests\r
\r
[ ] [ [ drop ] [ error. ] recover ] unit-test\r
\r
[ f ] [ { } vm-error? ] unit-test\r
-[ f ] [ { "A" "B" } vm-error? ] unit-test
\ No newline at end of file
+[ f ] [ { "A" "B" } vm-error? ] unit-test\r
error-continuation get name>> assoc-stack ;
: :res ( n -- * )
- 1- restarts get-global nth f restarts set-global restart ;
+ 1 - restarts get-global nth f restarts set-global restart ;
: :1 ( -- * ) 1 :res ;
: :2 ( -- * ) 2 :res ;
: restart. ( restart n -- )
[
- 1+ dup 3 <= [ ":" % # " " % ] [ # " :res " % ] if
+ 1 + dup 3 <= [ ":" % # " " % ] [ # " :res " % ] if
name>> %
] "" make print ;
: array-size-error. ( obj -- )
"Invalid array size: " write dup third .
- "Maximum: " write fourth 1- . ;
+ "Maximum: " write fourth 1 - . ;
: c-string-error. ( obj -- )
"Cannot convert to C string: " write third . ;
"Cannot do next-object outside begin/end-scan" print drop ;
: undefined-symbol-error. ( obj -- )
- "The image refers to a library or symbol that was not found"
- " at load time" append print drop ;
+ "The image refers to a library or symbol that was not found at load time"
+ print drop ;
: stack-underflow. ( obj name -- )
write " stack underflow" print drop ;
drop "Not in a vocabulary; IN: form required" ;
M: no-word-error summary
- name>> "No word named ``" "'' found in current vocabulary search path" surround ;
+ name>>
+ "No word named ``"
+ "'' found in current vocabulary search path" surround ;
M: no-word-error error. summary print ;
+M: no-word-in-vocab summary
+ [ vocab>> ] [ word>> ] bi
+ [ "No word named ``" % % "'' found in ``" % % "'' vocabulary" % ] "" make ;
+
+M: no-word-in-vocab error. summary print ;
+
M: ambiguous-use-error summary
- words>> first name>> "More than one vocabulary defines a word named ``" "''" surround ;
+ words>> first name>>
+ "More than one vocabulary defines a word named ``" "''" surround ;
M: ambiguous-use-error error. summary print ;
{
{ [ os windows? ] [ "debugger.windows" require ] }
{ [ os unix? ] [ "debugger.unix" require ] }
-} cond
\ No newline at end of file
+} cond
"SIGUSR1" "SIGUSR2"
}
-: signal-name ( n -- str/f ) 1- signal-names ?nth ;
+: signal-name ( n -- str/f ) 1 - signal-names ?nth ;
: signal-name. ( n -- )
signal-name [ " (" ")" surround write ] when* ;
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test definitions.icons ;
-IN: definitions.icons.tests
TUPLE: hey value ;
C: <hey> hey
-CONSULT: alpha hey value>> 1+ ;
-CONSULT: beta hey value>> 1- ;
+CONSULT: alpha hey value>> 1 + ;
+CONSULT: beta hey value>> 1 - ;
[ 2 ] [ 1 <hey> one ] unit-test
[ 2 ] [ 1 <hey> two ] unit-test
--- /dev/null
+USING: tools.test disjoint-sets namespaces slots.private ;
+IN: disjoint-sets.testes
+
+SYMBOL: +blah+
+-405534154 +blah+ 1 set-slot
+
+SYMBOL: uf
+
+[ ] [
+ <disjoint-set> uf set
+ +blah+ uf get add-atom
+ 19026 uf get add-atom
+ 19026 +blah+ uf get equate
+] unit-test
+
+[ 2 ] [ 19026 uf get equiv-set-size ] unit-test
ranks>> at ; inline
: inc-rank ( a disjoint-set -- )
- ranks>> [ 1+ ] change-at ; inline
+ ranks>> [ 1 + ] change-at ; inline
: representative? ( a disjoint-set -- ? )
dupd parent = ; inline
+PRIVATE>
+
GENERIC: representative ( a disjoint-set -- p )
M: disjoint-set representative
[ [ parent ] keep representative dup ] 2keep set-parent
] if ;
+<PRIVATE
+
: representatives ( a b disjoint-set -- r r )
[ representative ] curry bi@ ; inline
-IN: documents.tests
USING: documents documents.private accessors sequences
namespaces tools.test make arrays kernel fry ;
+IN: documents.tests
! Tests
[ drop ] [ doc-line length ] 2bi 2array ;
: doc-lines ( from to document -- slice )
- [ 1+ ] [ value>> ] bi* <slice> ;
+ [ 1 + ] [ value>> ] bi* <slice> ;
: start-on-line ( from line# document -- n1 )
drop over first =
[ start-on-line ] [ end-on-line ] bi-curry bi-curry bi* ;
: last-line# ( document -- line )
- value>> length 1- ;
+ value>> length 1 - ;
CONSTANT: doc-start { 0 0 }
over length 1 = [
nip first2
] [
- first swap length 1- + 0
+ first swap length 1 - + 0
] if
] dip last length + 2array ;
0 swap [ append ] change-nth ;
: append-last ( str seq -- )
- [ length 1- ] keep [ prepend ] change-nth ;
+ [ length 1 - ] keep [ prepend ] change-nth ;
: loc-col/str ( loc document -- str col )
[ first2 swap ] dip nth swap ;
: (set-doc-range) ( doc-lines from to lines -- changed-lines )
[ prepare-insert ] 3keep
- [ [ first ] bi@ 1+ ] dip
+ [ [ first ] bi@ 1 + ] dip
replace-slice ;
: entire-doc ( document -- start end document )
: prev ( loc document quot: ( loc document -- loc ) -- loc )
{
{ [ pick { 0 0 } = ] [ 2drop ] }
- { [ pick second zero? ] [ drop [ first 1- ] dip line-end ] }
+ { [ pick second zero? ] [ drop [ first 1 - ] dip line-end ] }
[ call ]
} cond ; inline
: next ( loc document quot: ( loc document -- loc ) -- loc )
{
{ [ 2over doc-end = ] [ 2drop ] }
- { [ 2over line-end? ] [ 2drop first 1+ 0 2array ] }
+ { [ 2over line-end? ] [ 2drop first 1 + 0 2array ] }
[ call ]
} cond ; inline
M: one-word-elt prev-elt
drop
- [ [ 1- ] dip f prev-word ] modify-col ;
+ [ [ 1 - ] dip f prev-word ] modify-col ;
M: one-word-elt next-elt
drop
M: word-elt prev-elt
drop
- [ [ [ 1- ] dip blank-at? prev-word ] modify-col ]
+ [ [ [ 1 - ] dip blank-at? prev-word ] modify-col ]
prev ;
M: word-elt next-elt
ARTICLE: "editor" "Editor integration"
"Factor development is best done with one of the supported editors; this allows you to quickly jump to definitions from the Factor environment."
{ $subsection edit }
-"Depending on the editor you are using, you must load one of the child vocabularies of the " { $vocab-link "editors" } " vocabulary, for example " { $vocab-link "editors.emacs" } ", for example:"
+"Depending on the editor you are using, you must load one of the child vocabularies of the " { $vocab-link "editors" } " vocabulary, for example " { $vocab-link "editors.emacs" } ":"
{ $code "USE: editors.emacs" }
+"If you intend to always use the same editor, it helps to have it load during stage 2 bootstrap. Place the code to load and possibly configure it in the " { $link "factor-boot-rc" } "."
+$nl
"Editor integration vocabularies store a quotation in a global variable when loaded:"
{ $subsection edit-hook }
"If a syntax error was thrown while loading a source file, you can jump to the location of the error in your editor:"
USING: parser lexer kernel namespaces sequences definitions
io.files io.backend io.pathnames io summary continuations
tools.crossref vocabs.hierarchy prettyprint source-files
-source-files.errors assocs vocabs vocabs.loader splitting
+source-files.errors assocs vocabs.loader splitting
accessors debugger help.topics ;
+FROM: vocabs => vocab-name >vocab-link ;
IN: editors
TUPLE: no-edit-hook ;
SYMBOL: edit-hook
: available-editors ( -- seq )
- "editors" all-child-vocabs-seq [ vocab-name ] map ;
+ "editors" child-vocabs no-roots no-prefixes [ vocab-name ] map ;
: editor-restarts ( -- alist )
available-editors
: edit-vocab ( name -- )
>vocab-link edit ;
-GENERIC: error-file ( error -- file )
-
-GENERIC: error-line ( error -- line )
-
-M: lexer-error error-file
- error>> error-file ;
-
-M: lexer-error error-line
- [ error>> error-line ] [ line>> ] bi or ;
-
-M: source-file-error error-file
- [ error>> error-file ] [ file>> ] bi or ;
-
-M: source-file-error error-line
- error>> error-line ;
-
-M: condition error-file
- error>> error-file ;
-
-M: condition error-line
- error>> error-line ;
-
-M: object error-file
- drop f ;
-
-M: object error-line
- drop f ;
-
-: (:edit) ( error -- )
+: edit-error ( error -- )
[ error-file ] [ error-line ] bi
2dup and [ edit-location ] [ 2drop ] if ;
: :edit ( -- )
- error get (:edit) ;
-
-: edit-error ( error -- )
- [ file>> ] [ line#>> ] bi 2dup and [ edit-location ] [ 2drop ] if ;
+ error get edit-error ;
: edit-each ( seq -- )
[
--- /dev/null
+USING: help.syntax ;
+IN: editors.gvim
+ABOUT: { "vim" "vim" }
USING: definitions io.launcher kernel math math.parser parser
namespaces prettyprint editors make ;
-
IN: editors.macvim
: macvim ( file line -- )
[ "mate" , "-a" , "-l" , number>string , , ] { } make
run-detached drop ;
-[ textmate ] edit-hook set-global
+[ textmate ] edit-hook set-global
\ No newline at end of file
-USING: definitions editors help help.markup help.syntax io io.files
- io.pathnames words ;
+USING: definitions editors help help.markup help.syntax
+io io.files io.pathnames words ;
IN: editors.vim
+ABOUT: { "vim" "vim" }
+
ARTICLE: { "vim" "vim" } "Vim support"
-"This module makes the " { $link edit } " word work with Vim by setting the " { $link edit-hook } " global variable to call " { $link vim } ". The " { $link vim-path } " variable contains the name of the vim executable. The default " { $link vim-path } " is " { $snippet "\"gvim\"" } "."
+"This module makes the " { $link edit } " word work with Vim by setting the " { $link edit-hook } " global variable to call " { $link vim } "."
$nl
-"If you intend to use this module regularly, it helps to have it load during stage 2 bootstrap. On Windows, place the following example " { $snippet ".factor-boot-rc" } " in the directory returned by " { $link home } ":"
-{ $code
-"USING: modules namespaces ;"
-"REQUIRES: libs/vim ;"
-"USE: vim"
-"\"c:\\\\program files\\\\vim\\\\vim70\\\\gvim\" vim-path set-global"
+"The " { $link vim-path } " variable contains the name of the vim executable. The default " { $link vim-path } " is " { $snippet "\"vim\"" } ". Which is not very useful, as it starts vim in the same terminal where you started factor."
+{ $list
+ { "If you want to use gvim instead or are on a Windows platform use " { $vocab-link "editors.gvim" } "." }
+ { "If you want to start vim in an extra terminal, use something like this:" { $code "{ \"urxvt\" \"-e\" \"vim\" } vim-path set-global" } "Replace " { $snippet "urxvt" } " by your terminal of choice." }
}
-"On Unix, you may omit the last line if " { $snippet "\"vim\"" } " is in your " { $snippet "$PATH" } "."
$nl
-"You may also wish to install Vim support files to enable syntax hilighting and other features. These are in the " { $link resource-path } " in " { $snippet "misc/vim" } "." ;
+"You may also wish to install Vim support files to enable syntax hilighting and other features. These are in the " { $link resource-path } " in " { $snippet "misc/vim" } "."
+{ $see-also "editor" }
+;
USING: definitions io io.launcher kernel math math.parser
namespaces parser prettyprint sequences editors accessors
-make ;
+make strings ;
IN: editors.vim
SYMBOL: vim-path
M: vim vim-command
[
- vim-path get ,
+ vim-path get dup string? [ , ] [ % ] if
[ , ] [ number>string "+" prepend , ] bi*
] { } make ;
-IN: eval.tests
USING: eval tools.test ;
+IN: eval.tests
[ 4 ] [ "USE: math 2 2 +" eval( -- result ) ] unit-test
[ "USE: math 2 2 +" eval( -- ) ] must-fail
[ "<p><a href=\"a\">a</a> <a href=\"b\">c</a></p>" ] [ "[[a]] [[b|c]]" convert-farkup ] unit-test
-[ "<p><a href=\"C%2b%2b\">C++</a></p>" ] [ "[[C++]]" convert-farkup ] unit-test
+[ "<p><a href=\"C%2B%2B\">C++</a></p>" ] [ "[[C++]]" convert-farkup ] unit-test
[ "<p><foo></p>" ] [ "<foo>" convert-farkup ] unit-test
parse-paragraph paragraph boa ;
: cut-half-slice ( string i -- before after-slice )
- [ head ] [ 1+ short tail-slice ] 2bi ;
+ [ head ] [ 1 + short tail-slice ] 2bi ;
: find-cut ( string quot -- before after delimiter )
dupd find
! Copyright (C) 2008 John Benediktsson
! See http://factorcode.org/license.txt for BSD license
-
USING: calendar kernel formatting tools.test ;
-
IN: formatting.tests
[ "%s" printf ] must-infer
[ t ] [ "[####monkey]" "monkey" "[%'#10s]" sprintf = ] unit-test
[ t ] [ "[many monke]" "many monkeys" "[%10.10s]" sprintf = ] unit-test
+[ t ] [ "{ 1, 2, 3 }" { 1 2 3 } "%[%s, %]" sprintf = ] unit-test
+[ t ] [ "{ 1:2, 3:4 }" H{ { 1 2 } { 3 4 } } "%[%s: %s %]" sprintf = ] unit-test
+
[ "%H:%M:%S" strftime ] must-infer
[ t ] [ "Thu Oct 09 12:03:15 2008" testtime "%c" strftime = ] unit-test
[ t ] [ "PM" testtime "%p" strftime = ] unit-test
+
! Copyright (C) 2008 John Benediktsson
! See http://factorcode.org/license.txt for BSD license
-
USING: accessors arrays assocs calendar combinators fry kernel
generalizations io io.streams.string macros math math.functions
math.parser peg.ebnf quotations sequences splitting strings
unicode.categories unicode.case vectors combinators.smart ;
-
IN: formatting
<PRIVATE
: fix-sign ( string -- string )
dup CHAR: 0 swap index 0 =
[ dup 0 swap [ [ CHAR: 0 = not ] keep digit? and ] find-from
- [ dup 1- rot dup [ nth ] dip swap
+ [ dup 1 - rot dup [ nth ] dip swap
{
- { CHAR: - [ [ 1- ] dip remove-nth "-" prepend ] }
- { CHAR: + [ [ 1- ] dip remove-nth "+" prepend ] }
+ { CHAR: - [ [ 1 - ] dip remove-nth "-" prepend ] }
+ { CHAR: + [ [ 1 - ] dip remove-nth "+" prepend ] }
[ drop swap drop ]
} case
] [ drop ] if
[ "." split1 ] dip [ CHAR: 0 pad-tail ] [ head-slice ] bi "." glue ;
: max-digits ( n digits -- n' )
- 10 swap ^ [ * round ] keep / ; inline
+ 10^ [ * round ] keep / ; inline
: >exp ( x -- exp base )
[
abs 0 swap
[ dup [ 10.0 >= ] [ 1.0 < ] bi or ]
[ dup 10.0 >=
- [ 10.0 / [ 1+ ] dip ]
- [ 10.0 * [ 1- ] dip ] if
+ [ 10.0 / [ 1 + ] dip ]
+ [ 10.0 * [ 1 - ] dip ] if
] while
] keep 0 < [ neg ] when ;
: (week-of-year) ( timestamp day -- n )
[ dup clone 1 >>month 1 >>day day-of-week dup ] dip > [ 7 swap - ] when
- [ day-of-year ] dip 2dup < [ 0 2nip ] [ - 7 / 1+ >fixnum ] if ;
+ [ day-of-year ] dip 2dup < [ 0 2nip ] [ - 7 / 1 + >fixnum ] if ;
: week-of-year-sunday ( timestamp -- n ) 0 (week-of-year) ; inline
-IN: fry.tests
USING: fry tools.test math prettyprint kernel io arrays
sequences eval accessors ;
+IN: fry.tests
[ [ 3 + ] ] [ 3 '[ _ + ] ] unit-test
: check-fry ( quot -- quot )
dup { load-local load-locals get-local drop-locals } intersect
- empty? [ >r/r>-in-fry-error ] unless ;
+ [ >r/r>-in-fry-error ] unless-empty ;
PREDICATE: fry-specifier < word { _ @ } memq? ;
check-fry
[ [ deep-fry ] each ] [ ] make
[ dup \ @ = [ drop [ _ call ] ] [ 1array ] if ] map concat
- { _ } split [ spread>quot ] [ length 1- ] bi ;
+ { _ } split [ spread>quot ] [ length 1 - ] bi ;
PRIVATE>
-IN: functors.tests
USING: functors tools.test math words kernel multiline parser
io.streams.string generic ;
+IN: functors.tests
<<
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays classes.mixin classes.parser
-classes.tuple classes.tuple.parser combinators effects
-effects.parser fry generic generic.parser generic.standard
-interpolate io.streams.string kernel lexer locals.parser
-locals.rewrite.closures locals.types make namespaces parser
+classes.singleton classes.tuple classes.tuple.parser
+combinators effects.parser fry generic generic.parser
+generic.standard interpolate io.streams.string kernel lexer
+locals.parser locals.types macros make namespaces parser
quotations sequences vocabs.parser words words.symbol ;
IN: functors
[ parse-definition* ] dip
parsed ;
-: DEFINE* ( accum -- accum ) \ define-declared* parsed ;
-
SYNTAX: `TUPLE:
scan-param parsed
scan {
} case
\ define-tuple-class parsed ;
+SYNTAX: `SINGLETON:
+ scan-param parsed
+ \ define-singleton-class parsed ;
+
+SYNTAX: `MIXIN:
+ scan-param parsed
+ \ define-mixin-class parsed ;
+
SYNTAX: `M:
scan-param parsed
scan-param parsed
complete-effect parsed
\ define-simple-generic* parsed ;
+SYNTAX: `MACRO:
+ scan-param parsed
+ parse-declared*
+ \ define-macro parsed ;
+
SYNTAX: `inline [ word make-inline ] over push-all ;
SYNTAX: `call-next-method T{ fake-call-next-method } parsed ;
SYNTAX: IS [ dup search [ ] [ no-word ] ?if ] (INTERPOLATE) ;
+SYNTAX: DEFERS [ current-vocab create ] (INTERPOLATE) ;
+
SYNTAX: DEFINES [ create-in ] (INTERPOLATE) ;
SYNTAX: DEFINES-CLASS [ create-class-in ] (INTERPOLATE) ;
: functor-words ( -- assoc )
H{
{ "TUPLE:" POSTPONE: `TUPLE: }
+ { "SINGLETON:" POSTPONE: `SINGLETON: }
+ { "MIXIN:" POSTPONE: `MIXIN: }
{ "M:" POSTPONE: `M: }
{ "C:" POSTPONE: `C: }
{ ":" POSTPONE: `: }
{ "SYNTAX:" POSTPONE: `SYNTAX: }
{ "SYMBOL:" POSTPONE: `SYMBOL: }
{ "inline" POSTPONE: `inline }
+ { "MACRO:" POSTPONE: `MACRO: }
{ "call-next-method" POSTPONE: `call-next-method }
} ;
HELP: page-action
{ $class-description "The class of Chloe page actions. These are actions whose " { $slot "display" } " slot is pre-set to serve the Chloe template stored in the " { $slot "page" } " slot." } ;
-HELP: param
-{ $values
- { "name" string }
- { "value" string }
-}
-{ $description "Outputs the value of a query parameter (if the current request is a GET or HEAD request) or a POST parameter (if the current request is a POST request)." }
-{ $notes "Instead of using this word, it is better to use " { $link validate-params } " and then access parameters via " { $link "html.forms.values" } " words." } ;
-
-HELP: params
-{ $var-description "A variable holding an assoc of query parameters (if the current request is a GET or HEAD request) or POST parameters (if the current request is a POST request)." }
-{ $notes "Instead of using this word, it is better to use " { $link validate-params } " and then access parameters via " { $link "html.forms.values" } " words." } ;
-
HELP: validate-integer-id
{ $description "A utility word which validates an integer parameter named " { $snippet "id" } "." }
{ $examples
ARTICLE: "furnace.actions.config" "Furnace action configuration"
"Actions have the following slots:"
{ $table
- { { $slot "rest" } { "A parameter name to map the rest of the URL, after the action name, to. If this is not set, then navigating to a URL where the action is not the last path component will return to the client with an error." } }
+ { { $slot "rest" } { "A parameter name to map the rest of the URL, after the action name, to. If this is not set, then navigating to a URL where the action is not the last path component will return to the client with an error. A more general facility can be found in the " { $vocab-link "http.server.rewrite" } " vocabulary." } }
{ { $slot "init" } { "A quotation called at the beginning of a GET or HEAD request. Typically this quotation configures " { $link "html.forms" } " and parses query parameters." } }
{ { $slot "authorize" } { "A quotation called at the beginning of a GET, HEAD or POST request. In GET requests, it is called after the " { $slot "init" } " quotation; in POST requests, it is called after the " { $slot "validate" } " quotation. By convention, this quotation performs custom authorization checks which depend on query parameters or POST parameters." } }
{ { $slot "display" } { "A quotation called after the " { $slot "init" } " quotation in a GET request. This quotation must return an HTTP " { $link response } "." } }
"Any one of the above steps can perform validation; if " { $link validation-failed } " is called during a POST request, the client is sent back to the page containing the form submission, with current form values and validation errors passed in a " { $link "furnace.conversations" } "." ;
ARTICLE: "furnace.actions.impl" "Furnace actions implementation"
-"The following words are used by the action implementation and there is rarely any reason to call them directly:"
-{ $subsection new-action }
-{ $subsection param }
-{ $subsection params } ;
+"The following parametrized constructor should be called from constructors for subclasses of " { $link action } ":"
+{ $subsection new-action } ;
ARTICLE: "furnace.actions" "Furnace actions"
"The " { $vocab-link "furnace.actions" } " vocabulary implements a type of responder, called an " { $emphasis "action" } ", which handles the form validation lifecycle."
html.templates.chloe.compiler ;\r
IN: furnace.actions\r
\r
-SYMBOL: params\r
-\r
SYMBOL: rest\r
\r
TUPLE: action rest init authorize display validate submit ;\r
] [ drop <400> ] if\r
] with-exit-continuation ;\r
\r
-: param ( name -- value )\r
- params get at ;\r
-\r
CONSTANT: revalidate-url-key "__u"\r
\r
: revalidate-url ( -- url/f )\r
] [ drop <400> ] if\r
] with-exit-continuation ;\r
\r
-: handle-rest ( path action -- assoc )\r
- rest>> dup [ [ "/" join ] dip associate ] [ 2drop f ] if ;\r
+: handle-rest ( path action -- )\r
+ rest>> dup [ [ "/" join ] dip set-param ] [ 2drop ] if ;\r
\r
: init-action ( path action -- )\r
begin-form\r
- handle-rest\r
- request get request-params assoc-union params set ;\r
+ handle-rest ;\r
\r
M: action call-responder* ( path action -- response )\r
[ init-action ] keep\r
+++ /dev/null
-USING: furnace.auth tools.test ;
-IN: furnace.auth.tests
-
+++ /dev/null
-IN: furnace.auth.features.edit-profile.tests
-USING: tools.test furnace.auth.features.edit-profile ;
-
-
+++ /dev/null
-IN: furnace.auth.features.recover-password
-USING: tools.test furnace.auth.features.recover-password ;
-
-
+++ /dev/null
-IN: furnace.auth.features.registration.tests
-USING: tools.test furnace.auth.features.registration ;
-
-
+++ /dev/null
-IN: furnace.auth.login.tests\r
-USING: tools.test furnace.auth.login ;\r
-\r
-\r
USING: accessors namespaces kernel combinators.short-circuit
db.tuples db.types furnace.auth furnace.sessions furnace.cache ;
-
IN: furnace.auth.login.permits
TUPLE: permit < server-state session uid ;
-IN: furnace.auth.providers.assoc.tests\r
USING: furnace.actions furnace.auth furnace.auth.providers \r
furnace.auth.providers.assoc furnace.auth.login\r
tools.test namespaces accessors kernel ;\r
+IN: furnace.auth.providers.assoc.tests\r
\r
<action> "Test" <login-realm>\r
<users-in-memory> >>users\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
-IN: furnace.auth.providers.assoc\r
USING: accessors assocs kernel furnace.auth.providers ;\r
+IN: furnace.auth.providers.assoc\r
\r
TUPLE: users-in-memory assoc ;\r
\r
-IN: furnace.auth.providers.db.tests\r
USING: furnace.actions\r
furnace.auth\r
furnace.auth.login\r
furnace.auth.providers.db tools.test\r
namespaces db db.sqlite db.tuples continuations\r
io.files io.files.temp io.directories accessors kernel ;\r
+IN: furnace.auth.providers.db.tests\r
\r
<action> "test" <login-realm> realm set\r
\r
+++ /dev/null
-IN: furnace.db.tests
-USING: tools.test furnace.db ;
-
-
-IN: furnace.tests
USING: http http.server.dispatchers http.server.responses
http.server furnace furnace.utilities tools.test kernel
namespaces accessors io.streams.string urls xml.writer ;
+IN: furnace.tests
+
TUPLE: funny-dispatcher < dispatcher ;
: <funny-dispatcher> ( -- dispatcher ) funny-dispatcher new-dispatcher ;
-IN: furnace.sessions.tests\r
USING: tools.test http furnace.sessions furnace.actions\r
http.server http.server.responses math namespaces make kernel\r
accessors io.sockets io.servers.connection prettyprint\r
io.streams.string io.files io.files.temp io.directories\r
splitting destructors sequences db db.tuples db.sqlite\r
continuations urls math.parser furnace furnace.utilities ;\r
+IN: furnace.sessions.tests\r
\r
: with-session ( session quot -- )\r
[\r
\r
M: foo call-responder*\r
2drop\r
- "x" [ 1+ ] schange\r
+ "x" [ 1 + ] schange\r
"x" sget number>string "text/html" <content> ;\r
\r
: url-responder-mock-test ( -- string )\r
\r
"auth-test.db" temp-file <sqlite-db> [\r
\r
- <request> init-request\r
+ <request> "GET" >>method init-request\r
session ensure-table\r
\r
"127.0.0.1" 1234 <inet4> remote-address set\r
\r
[ 9 ] [ "x" sget sq ] unit-test\r
\r
- [ ] [ "x" [ 1- ] schange ] unit-test\r
+ [ ] [ "x" [ 1 - ] schange ] unit-test\r
\r
[ 4 ] [ "x" sget sq ] unit-test\r
\r
{ $values { "referrer/f" { $maybe string } } }
{ $description "Outputs the current request's referrer URL." } ;
-HELP: request-params
-{ $values { "request" request } { "assoc" assoc } }
-{ $description "Outputs the query parameters (if the current request is a GET or HEAD request) or the POST parameters (if the current request is a POST request)." } ;
-
HELP: resolve-base-path
{ $values { "string" string } { "string'" string } }
{ $description "Resolves a responder-relative URL." } ;
{ $subsection exit-with }
"Other useful words:"
{ $subsection hidden-form-field }
-{ $subsection request-params }
{ $subsection client-state }
{ $subsection user-agent } ;
CONSTANT: nested-forms-key "__n"
-: request-params ( request -- assoc )
- dup method>> {
- { "GET" [ url>> query>> ] }
- { "HEAD" [ url>> query>> ] }
- { "POST" [ post-data>> params>> ] }
- } case ;
-
: referrer ( -- referrer/f )
#! Typo is intentional, it's in the HTTP spec!
"referer" request get header>> at
-USING: windows.dinput windows.dinput.constants parser
-alien.c-types windows.ole32 namespaces assocs kernel arrays
-vectors windows.kernel32 windows.com windows.dinput shuffle
-windows.user32 windows.messages sequences combinators locals
-math.rectangles accessors math alien alien.strings
-io.encodings.utf16 io.encodings.utf16n continuations
-byte-arrays game-input.dinput.keys-array game-input
-ui.backend.windows windows.errors struct-arrays
-math.bitwise ;
+USING: accessors alien alien.c-types alien.strings arrays
+assocs byte-arrays combinators continuations game-input
+game-input.dinput.keys-array io.encodings.utf16
+io.encodings.utf16n kernel locals math math.bitwise
+math.rectangles namespaces parser sequences shuffle
+struct-arrays ui.backend.windows vectors windows.com
+windows.dinput windows.dinput.constants windows.errors
+windows.kernel32 windows.messages windows.ole32
+windows.user32 ;
IN: game-input.dinput
-
CONSTANT: MOUSE-BUFFER-SIZE 16
SINGLETON: dinput-game-input-backend
DBT_DEVTYP_DEVICEINTERFACE over set-DEV_BROADCAST_DEVICEW-dbcc_devicetype ;
: create-device-change-window ( -- )
- <zero-window-rect> create-window
+ <zero-window-rect> WS_OVERLAPPEDWINDOW 0 create-window
[
(device-notification-filter)
DEVICE_NOTIFY_WINDOW_HANDLE DEVICE_NOTIFY_ALL_INTERFACE_CLASSES bitor
+USING: ui game-input tools.test kernel system threads calendar
+combinators.short-circuit ;
IN: game-input.tests
-USING: ui game-input tools.test kernel system threads calendar ;
-os windows? os macosx? or [
+os { [ windows? ] [ macosx? ] } 1|| [
[ ] [ open-game-input ] unit-test
[ ] [ 1 seconds sleep ] unit-test
[ ] [ close-game-input ] unit-test
-] when
\ No newline at end of file
+] when
game-input-opened? [
(open-game-input)
] unless
- game-input-opened [ 1+ ] change-global
+ game-input-opened [ 1 + ] change-global
reset-mouse ;
: close-game-input ( -- )
game-input-opened [
dup zero? [ game-input-not-open ] when
- 1-
+ 1 -
] change-global
game-input-opened? [
(close-game-input)
IOHIDValueGetIntegerValue pov-values ?nth [ pov-neutral ] unless* ;
: record-button ( state hid-value element -- )
- [ buttons>> ] [ button-value ] [ IOHIDElementGetUsage 1- ] tri* rot set-nth ;
+ [ buttons>> ] [ button-value ] [ IOHIDElementGetUsage 1 - ] tri* rot set-nth ;
: record-controller ( controller-state value -- )
dup IOHIDValueGetElement {
{ 3 5 } [ 2 nweave ] must-infer-as\r
\r
[ { 0 1 2 } { 3 5 4 } { 7 8 6 } ]\r
-[ 9 [ ] each { [ 3array ] [ swap 3array ] [ rot 3array ] } 3 nspread ] unit-test
\ No newline at end of file
+[ 9 [ ] each { [ 3array ] [ swap 3array ] [ rot 3array ] } 3 nspread ] unit-test\r
+\r
+[ 1 2 3 4 1 2 3 ] [ 1 2 3 4 3 nover ] unit-test\r
+\r
+[ [ 1 2 3 ] [ 1 2 3 ] ]\r
+[ 1 2 3 [ ] [ ] 3 nbi-curry ] unit-test\r
+\r
+[ 15 3 ] [ 1 2 3 4 5 [ + + + + ] [ - - - - ] 5 nbi ] unit-test\r
+\r
+: nover-test ( -- a b c d e f g )\r
+ 1 2 3 4 3 nover ;\r
+\r
+[ 1 2 3 4 1 2 3 ] [ nover-test ] unit-test\r
MACRO: nsequence ( n seq -- )
[
- [ drop <reversed> ] [ '[ _ _ new-sequence ] ] 2bi
+ [ drop iota <reversed> ] [ '[ _ _ new-sequence ] ] 2bi
[ '[ @ [ _ swap set-nth-unsafe ] keep ] ] reduce
] keep
'[ @ _ like ] ;
'[ _ { } nsequence ] ;
MACRO: nsum ( n -- )
- 1- [ + ] n*quot ;
+ 1 - [ + ] n*quot ;
MACRO: firstn-unsafe ( n -- )
- [ '[ [ _ ] dip nth-unsafe ] ] map '[ _ cleave ] ;
+ iota [ '[ [ _ ] dip nth-unsafe ] ] map '[ _ cleave ] ;
MACRO: firstn ( n -- )
dup zero? [ drop [ drop ] ] [
- [ 1- swap bounds-check 2drop ]
+ [ 1 - swap bounds-check 2drop ]
[ firstn-unsafe ]
bi-curry '[ _ _ bi ]
] if ;
MACRO: npick ( n -- )
- 1- [ dup ] [ '[ _ dip swap ] ] repeat ;
+ 1 - [ dup ] [ '[ _ dip swap ] ] repeat ;
+
+MACRO: nover ( n -- )
+ dup 1 + '[ _ npick ] n*quot ;
MACRO: ndup ( n -- )
dup '[ _ npick ] n*quot ;
MACRO: nrot ( n -- )
- 1- [ ] [ '[ _ dip swap ] ] repeat ;
+ 1 - [ ] [ '[ _ dip swap ] ] repeat ;
MACRO: -nrot ( n -- )
- 1- [ ] [ '[ swap _ dip ] ] repeat ;
+ 1 - [ ] [ '[ swap _ dip ] ] repeat ;
MACRO: ndrop ( n -- )
[ drop ] n*quot ;
MACRO: nwith ( n -- )
[ with ] n*quot ;
+MACRO: nbi ( n -- )
+ '[ [ _ nkeep ] dip call ] ;
+
MACRO: ncleave ( quots n -- )
[ '[ _ '[ _ _ nkeep ] ] map [ ] join ] [ '[ _ ndrop ] ] bi
compose ;
swap <repetition> spread>quot ;
MACRO: mnswap ( m n -- )
- 1+ '[ _ -nrot ] swap '[ _ _ napply ] ;
+ 1 + '[ _ -nrot ] swap '[ _ _ napply ] ;
MACRO: nweave ( n -- )
- [ dup <reversed> [ '[ _ _ mnswap ] ] with map ] keep
+ [ dup iota <reversed> [ '[ _ _ mnswap ] ] with map ] keep
'[ _ _ ncleave ] ;
+MACRO: nbi-curry ( n -- )
+ [ bi-curry ] n*quot ;
+
: nappend-as ( n exemplar -- seq )
[ narray concat ] dip like ; inline
-IN: globs.tests
USING: tools.test globs ;
+IN: globs.tests
[ f ] [ "abd" "fdf" glob-matches? ] unit-test
[ f ] [ "fdsafas" "?" glob-matches? ] unit-test
"The difference can be summarized as the following:"
{ $list
{ "With groups, the subsequences form the original sequence when concatenated:"
- { $unchecked-example "dup n groups concat sequence= ." "t" }
+ { $unchecked-example
+ "USING: grouping ;"
+ "{ 1 2 3 4 } dup" "2 <groups> concat sequence= ." "t"
+ }
}
{ "With clumps, collecting the first element of each subsequence but the last one, together with the last subseqence, yields the original sequence:"
- { $unchecked-example "dup n clumps unclip-last [ [ first ] map ] dip append sequence= ." "t" }
+ { $unchecked-example
+ "USING: grouping ;"
+ "{ 1 2 3 4 } dup" "2 <clumps> unclip-last [ [ first ] map ] dip append sequence= ." "t"
+ }
}
}
"A combinator built using clumps:"
M: chunking-seq set-nth group@ <slice> 0 swap copy ;
-M: chunking-seq like drop { } like ;
+M: chunking-seq like drop { } like ; inline
INSTANCE: chunking-seq sequence
MIXIN: subseq-chunking
-M: subseq-chunking nth group@ subseq ;
+M: subseq-chunking nth group@ subseq ; inline
MIXIN: slice-chunking
-M: slice-chunking nth group@ <slice> ;
+M: slice-chunking nth group@ <slice> ; inline
-M: slice-chunking nth-unsafe group@ slice boa ;
+M: slice-chunking nth-unsafe group@ slice boa ; inline
TUPLE: abstract-groups < chunking-seq ;
M: abstract-groups length
- [ seq>> length ] [ n>> ] bi [ + 1- ] keep /i ;
+ [ seq>> length ] [ n>> ] bi [ + 1 - ] keep /i ; inline
M: abstract-groups set-length
- [ n>> * ] [ seq>> ] bi set-length ;
+ [ n>> * ] [ seq>> ] bi set-length ; inline
M: abstract-groups group@
- [ n>> [ * dup ] keep + ] [ seq>> ] bi [ length min ] keep ;
+ [ n>> [ * dup ] keep + ] [ seq>> ] bi [ length min ] keep ; inline
TUPLE: abstract-clumps < chunking-seq ;
M: abstract-clumps length
- [ seq>> length ] [ n>> ] bi - 1+ ;
+ [ seq>> length ] [ n>> ] bi - 1 + ; inline
M: abstract-clumps set-length
- [ n>> + 1- ] [ seq>> ] bi set-length ;
+ [ n>> + 1 - ] [ seq>> ] bi set-length ; inline
M: abstract-clumps group@
- [ n>> over + ] [ seq>> ] bi ;
+ [ n>> over + ] [ seq>> ] bi ; inline
PRIVATE>
: all-equal? ( seq -- ? ) [ = ] monotonic? ;
-: all-eq? ( seq -- ? ) [ eq? ] monotonic? ;
\ No newline at end of file
+: all-eq? ( seq -- ? ) [ eq? ] monotonic? ;
] each
: sort-entries ( entries -- entries' )
- [ [ key>> ] compare ] sort ;
+ [ key>> ] sort-with ;
: delete-test ( n -- obj1 obj2 )
[
! Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math sequences arrays assocs sequences.private
-growable accessors math.order summary ;
+growable accessors math.order summary vectors ;
IN: heaps
GENERIC: heap-push* ( value key heap -- entry )
<PRIVATE
-TUPLE: heap data ;
+TUPLE: heap { data vector } ;
: <heap> ( class -- heap )
[ V{ } clone ] dip boa ; inline
TUPLE: entry value key heap index ;
-: <entry> ( value key heap -- entry ) f entry boa ;
+: <entry> ( value key heap -- entry ) f entry boa ; inline
PRIVATE>
: right ( n -- m ) 1 shift 2 + ; inline
-: up ( n -- m ) 1- 2/ ; inline
+: up ( n -- m ) 1 - 2/ ; inline
: data-nth ( n heap -- entry )
data>> nth-unsafe ; inline
-: up-value ( n heap -- entry )
- [ up ] dip data-nth ; inline
-
: left-value ( n heap -- entry )
[ left ] dip data-nth ; inline
: data-pop* ( heap -- )
data>> pop* ; inline
-: data-peek ( heap -- entry )
- data>> last ; inline
-
: data-first ( heap -- entry )
data>> first ; inline
[ data-exchange ] 2keep up-heap
] [
3drop
- ] if ;
+ ] if ; inline recursive
: up-heap ( n heap -- )
- over 0 > [ (up-heap) ] [ 2drop ] if ;
+ over 0 > [ (up-heap) ] [ 2drop ] if ; inline recursive
: (child) ( m heap -- n )
2dup right-value
2dup right-bounds-check?
[ drop left ] [ (child) ] if ;
-: swap-down ( m heap -- )
- [ child ] 2keep data-exchange ;
-
DEFER: down-heap
: (down-heap) ( m heap -- )
3drop
] [
[ data-exchange ] 2keep down-heap
- ] if ;
+ ] if ; inline recursive
: down-heap ( m heap -- )
- 2dup left-bounds-check? [ 2drop ] [ (down-heap) ] if ;
+ 2dup left-bounds-check? [ 2drop ] [ (down-heap) ] if ; inline recursive
PRIVATE>
[ swapd heap-push ] curry assoc-each ;
: >entry< ( entry -- key value )
- [ value>> ] [ key>> ] bi ;
+ [ value>> ] [ key>> ] bi ; inline
M: heap heap-peek ( heap -- value key )
data-first >entry< ;
M: heap heap-delete ( entry heap -- )
[ entry>index ] keep
- 2dup heap-size 1- = [
+ 2dup heap-size 1 - = [
nip data-pop*
] [
[ nip data-pop ] 2keep
-IN: help.apropos.tests
USING: help.apropos tools.test ;
+IN: help.apropos.tests
[ ] [ "swp" apropos ] unit-test
[ dup name>> >lower ] { } map>assoc ;
: vocab-candidates ( -- candidates )
- all-vocabs-seq [ dup vocab-name >lower ] { } map>assoc ;
+ all-vocabs-recursive no-roots no-prefixes
+ [ dup vocab-name >lower ] { } map>assoc ;
: help-candidates ( seq -- candidates )
[ [ >link ] [ article-title >lower ] bi ] { } map>assoc
{ $code ": sq ( x -- y ) dup * ;" }
"(You could have looked this up yourself by clicking on the " { $link sq } " word itself.)"
$nl
-"Note the key elements in a word definition: The colon " { $link POSTPONE: : } " denotes the start of a word definition. The name of the new word must immediately follow. The word definition then continues on until the " { $link POSTPONE: ; } " token signifies the end of the definition. This type of word definition is called a " { $emphasis "compound definition." }
+"Note the key elements in a word definition: The colon " { $link POSTPONE: : } " denotes the start of a word definition. The name of the new word and a stack effect declaration must immediately follow. The word definition then continues on until the " { $link POSTPONE: ; } " token signifies the end of the definition. This type of word definition is called a " { $emphasis "compound definition." }
$nl
"Factor is all about code reuse through short and logical colon definitions. Breaking up a problem into small pieces which are easy to test is called " { $emphasis "factoring." }
$nl
}
"Note that words must be defined before being referenced. The following is generally invalid:"
{ $code
- ": frob accelerate particles ;"
- ": accelerate accelerator on ;"
- ": particles [ (particles) ] each ;"
+ ": frob ( what -- ) accelerate particles ;"
+ ": accelerate ( -- ) accelerator on ;"
+ ": particles ( what -- ) [ (particles) ] each ;"
}
-"You would have to place the first definition after the two others for the parser to accept the file."
+"You would have to place the first definition after the two others for the parser to accept the file. If you have a set of mutually recursive words, you can use " { $link POSTPONE: DEFER: } "."
{ $references
{ }
"word-search"
"Don't worry about efficiency unless your program is too slow. Don't prefer complex code to simple code just because you feel it will be more efficient. The Factor compiler is designed to make idiomatic code run fast."
{ "None of the above are hard-and-fast rules: there are exceptions to all of them. But one rule unconditionally holds: " { $emphasis "there is always a simpler way" } "." }
}
-"Factor tries to implement as much of itself as possible, because this improves simplicity and performance. One consequence is that Factor exposes its internals for extension and study. You even have the option of using low-level features not usually found in high-level languages, such manual memory management, pointer arithmetic, and inline assembly code."
+"Factor tries to implement as much of itself as possible, because this improves simplicity and performance. One consequence is that Factor exposes its internals for extension and study. You even have the option of using low-level features not usually found in high-level languages, such as manual memory management, pointer arithmetic, and inline assembly code."
$nl
"Unsafe features are tucked away so that you will not invoke them by accident, or have to use them to solve conventional programming problems. However when the need arises, unsafe features are invaluable, for example you might have to do some pointer arithmetic when interfacing directly with C libraries." ;
"Factor only makes use of one native thread, and Factor threads are scheduled co-operatively. C library calls block the entire VM."
"Factor does not hide anything from the programmer, all internals are exposed. It is your responsibility to avoid writing fragile code which depends too much on implementation detail."
{ "If a literal object appears in a word definition, the object itself is pushed on the stack when the word executes, not a copy. If you intend to mutate this object, you must " { $link clone } " it first. See " { $link "syntax-literals" } "." }
+ { "Also, " { $link dup } " and related shuffle words don't copy entire objects or arrays; they only duplicate the reference to them. If you want to guard an object against mutation, use " { $link clone } "." }
{ "For a discussion of potential issues surrounding the " { $link f } " object, see " { $link "booleans" } "." }
{ "Factor's object system is quite flexible. Careless usage of union, mixin and predicate classes can lead to similar problems to those caused by “multiple inheritance” in other languages. In particular, it is possible to have two classes such that they have a non-empty intersection and yet neither is a subclass of the other. If a generic word defines methods on two such classes, various disambiguation rules are applied to ensure method dispatch remains deterministic, however they may not be what you expect. See " { $link "method-order" } " for details." }
{ "Be careful when calling words which access variables from a " { $link make-assoc } " which constructs an assoc with arbitrary keys, since those keys might shadow variables." }
-IN: help.crossref.tests
USING: help.crossref help.topics help.markup tools.test words
definitions assocs sequences kernel namespaces parser arrays
io.streams.string continuations debugger compiler.units eval ;
+IN: help.crossref.tests
[ ] [
"IN: help.crossref.tests USING: help.syntax help.markup ; : foo ( -- ) ; HELP: foo \"foo is great\" ; ARTICLE: \"foo\" \"Foo\" { $subsection foo } ;" eval( -- )
-IN: help.handbook.tests
USING: help tools.test ;
+IN: help.handbook.tests
[ ] [ "article-index" print-topic ] unit-test
[ ] [ "primitive-index" print-topic ] unit-test
{ $heading "Debugging" }
{ $subsection "prettyprint" }
{ $subsection "inspector" }
-{ $subsection "tools.annotations" }
{ $subsection "tools.inference" }
+{ $subsection "tools.annotations" }
+{ $subsection "tools.deprecation" }
{ $heading "Browsing" }
{ $subsection "see" }
{ $subsection "tools.crossref" }
{ $subsection "profiling" }
{ $subsection "tools.memory" }
{ $subsection "tools.threads" }
+{ $subsection "tools.destructors" }
{ $subsection "tools.disassembler" }
{ $heading "Deployment" }
{ $subsection "tools.deploy" } ;
-IN: help.tests
USING: tools.test help kernel ;
+IN: help.tests
[ 3 throw ] must-fail
[ ] [ :help ] unit-test
-[ ] [ f print-topic ] unit-test
\ No newline at end of file
+[ ] [ f print-topic ] unit-test
-IN: help.html.tests
USING: help.html tools.test help.topics kernel ;
+IN: help.html.tests
[ ] [ "xml" >link help>html drop ] unit-test
-[ "article-foobar.html" ] [ "foobar" >link topic>filename ] unit-test
\ No newline at end of file
+[ "article-foobar.html" ] [ "foobar" >link topic>filename ] unit-test
assocs sequences make words accessors arrays help.topics vocabs
vocabs.hierarchy help.vocabs namespaces prettyprint io
vocabs.loader serialize fry memoize unicode.case math.order
-sorting debugger html xml.syntax xml.writer math.parser ;
+sorting debugger html xml.syntax xml.writer math.parser
+sets hashtables ;
FROM: io.encodings.ascii => ascii ;
FROM: ascii => ascii? ;
IN: help.html
{ CHAR: / "__slash__" }
{ CHAR: , "__comma__" }
{ CHAR: @ "__at__" }
+ { CHAR: # "__hash__" }
} at [ % ] [ , ] ?if
] [ number>string "__" "__" surround % ] if ;
dup topic>filename utf8 [ help>html write-xml ] with-file-writer ;
: all-vocabs-really ( -- seq )
- #! Hack.
- all-vocabs values concat
- vocabs [ find-vocab-root not ] filter [ vocab ] map append ;
+ all-vocabs-recursive >hashtable f over delete-at no-roots remove-redundant-prefixes ;
: all-topics ( -- topics )
[
load-index swap >lower
'[ [ drop _ ] dip >lower subseq? ] assoc-filter
[ swap result boa ] { } assoc>map
- [ [ title>> ] compare ] sort ;
+ [ title>> ] sort-with ;
: article-apropos ( string -- results )
"articles.idx" offline-apropos ;
swap '[
_ elements [
rest { { } { "" } } member?
- [ "Empty description" throw ] when
+ [ "Empty $description" simple-lint-error ] when
] each
] each ;
USING: assocs continuations fry help help.lint.checks
help.topics io kernel namespaces parser sequences
source-files.errors vocabs.hierarchy vocabs words classes
-locals tools.errors ;
+locals tools.errors listener ;
FROM: help.lint.checks => all-vocabs ;
+FROM: vocabs => child-vocabs ;
IN: help.lint
SYMBOL: lint-failures
] check-something
] [ drop ] if ;
-: check-words ( words -- ) [ check-word ] each ;
-
: check-article ( article -- )
[ with-interactive-vocabs ] vocabs-quot set
>link dup '[
: help-lint ( prefix -- )
[
- all-vocabs-seq [ vocab-name ] map all-vocabs set
+ auto-use? off
+ all-vocab-names all-vocabs set
group-articles vocab-articles set
child-vocabs
[ check-vocab ] each
] with-nesting
] ($heading) ;
+: $deprecated ( element -- )
+ [
+ deprecated-style get [
+ last-element off
+ "This word is deprecated" $heading print-element
+ ] with-nesting
+ ] ($heading) ;
+
! Images
: $image ( element -- )
[ first write-image ] ($span) ;
{ wrap-margin 500 }
} warning-style set-global
+SYMBOL: deprecated-style
+H{
+ { page-color COLOR: gray90 }
+ { border-color COLOR: red }
+ { border-width 5 }
+ { wrap-margin 500 }
+} deprecated-style set-global
+
SYMBOL: table-content-style
H{
{ wrap-margin 350 }
{ $code "USE: tools.scaffold" }
"Then, ask the scaffold tool to create a new vocabulary named " { $snippet "palindrome" } ":"
{ $code "\"resource:work\" \"palindrome\" scaffold-vocab" }
-"If you look at the output, you will see that a few files were created in your “work” directory. The following phrase will print the full path of your work directory:"
+"If you look at the output, you will see that a few files were created in your “work” directory, and that the new source file was loaded."
+$nl
+"The following phrase will print the full path of your work directory:"
{ $code "\"work\" resource-path ." }
"The work directory is one of several " { $link "vocabs.roots" } " where Factor searches for vocabularies. It is possible to define new vocabulary roots; see " { $link "add-vocab-roots" } ". To keep things simple in this tutorial, we'll just use the work directory, though."
$nl
-"Open the work directory in your file manager, and open the subdirectory named " { $snippet "palindrome" } ". Inside this subdirectory you will see a file named " { $snippet "palindrome.factor" } ". We will be editing this file."
-$nl
-"Notice that the file ends with an " { $link POSTPONE: IN: } " form telling Factor that all definitions in this source file should go into the " { $snippet "palindrome" } " vocabulary using the " { $link POSTPONE: IN: } " word:"
-{ $code "IN: palindrome" }
-"We will add new definitions after the " { $link POSTPONE: IN: } " form."
+"Open the work directory in your file manager, and open the subdirectory named " { $snippet "palindrome" } ". Inside this subdirectory you will see a file named " { $snippet "palindrome.factor" } ". Open this file in your text editor."
$nl
"You are now ready to go on to the next section: " { $link "first-program-logic" } "." ;
ARTICLE: "first-program-logic" "Writing some logic in your first program"
"Your " { $snippet "palindrome.factor" } " file should look like the following after the previous section:"
{ $code
- "! Copyright (C) 2008 <your name here>"
+ "! Copyright (C) 2009 <your name here>"
"! See http://factorcode.org/license.txt for BSD license."
+ "USING: ;"
"IN: palindrome"
}
+"Notice that the file ends with an " { $link POSTPONE: IN: } " form telling Factor that all definitions in this source file should go into the " { $snippet "palindrome" } " vocabulary using the " { $link POSTPONE: IN: } " word. We will add new definitions after the " { $link POSTPONE: IN: } " form."
+$nl
+"In order to be able to call the words defined in the " { $snippet "palindrome" } " vocabulary, you need to issue the following command in the listener:"
+{ $code "USE: palindrome" }
+"Now, we will be making some additions to the file. Since the file was loaded by the scaffold tool in the previous step, you need to tell Factor to reload it if it changes. Factor has a handy feature for this; pressing " { $command tool "common" refresh-all } " in the listener window will reload any changed source files. You can also force a single vocabulary to reload:"
+{ $code "\"palindrome\" reload" }
"We will now write our first word using " { $link POSTPONE: : } ". This word will test if a string is a palindrome; it will take a string as input, and give back a boolean as output. We will call this word " { $snippet "palindrome?" } ", following a naming convention that words returning booleans have names ending with " { $snippet "?" } "."
$nl
"Recall that a string is a palindrome if it is spelled the same forwards or backwards; that is, if the string is equal to its reverse. We can express this in Factor as follows:"
$nl
"To add the word to the search path, first convince yourself that this word is in the " { $vocab-link "kernel" } " vocabulary. Enter " { $snippet "dup" } " in the listener's input area, and press " { $operation com-browse } ". This will open the documentation browser tool, viewing the help for the " { $link dup } " word. One of the subheadings in the help article will mention the word's vocabulary."
$nl
-"So now, add the following at the start of the source file:"
+"Go back to the third line in your source file and change it to:"
{ $code "USING: kernel ;" }
"Next, find out what vocabulary " { $link reverse } " lives in; type the word name " { $snippet "reverse" } " in the listener's input area, and press " { $operation com-browse } "."
$nl
ARTICLE: "first-program-test" "Testing your first program"
"Your " { $snippet "palindrome.factor" } " file should look like the following after the previous section:"
{ $code
- "! Copyright (C) 2008 <your name here>"
+ "! Copyright (C) 2009 <your name here>"
"! See http://factorcode.org/license.txt for BSD license."
- "IN: palindrome"
"USING: kernel sequences ;"
+ "IN: palindrome"
""
": palindrome? ( str -- ? ) dup reverse = ;"
}
-"We will now test our new word in the listener. First we have add the palindrome vocabulary to the listener's vocabulary search path:"
-{ $code "USE: palindrome"}
+"We will now test our new word in the listener. If you haven't done so already, add the palindrome vocabulary to the listener's vocabulary search path:"
+{ $code "USE: palindrome" }
"Next, push a string on the stack:"
{ $code "\"hello\"" }
"Note that the stack display in the listener now shows this string. Having supplied the input, we call our word:"
$nl
"We will add some unit tests, which are similar to the interactive tests we did above. Unit tests are defined with the " { $link POSTPONE: unit-test } " word, which takes a sequence of expected outputs, and a piece of code. It runs the code, and asserts that it outputs the expected values."
$nl
-"Add the following three lines to " { $snippet "palindrome-tests.factor" } ":"
+"Add the following two lines to " { $snippet "palindrome-tests.factor" } ":"
{ $code
- "USING: palindrome tools.test ;"
"[ f ] [ \"hello\" palindrome? ] unit-test"
"[ t ] [ \"racecar\" palindrome? ] unit-test"
}
{ $code "\"palindrome\" test" }
"The next step is to, of course, fix our code so that the unit test can pass."
$nl
-"We begin by writing a word called " { $snippet "normalize" } " which removes blanks and non-alphabetical characters from a string, and then converts the string to lower case. We call this word " { $snippet "normalize" } ". To figure out how to write this word, we begin with some interactive experimentation in the listener."
+"We begin by writing a word which removes blanks and non-alphabetical characters from a string, and then converts the string to lower case. We call this word " { $snippet "normalize" } ". To figure out how to write this word, we begin with some interactive experimentation in the listener."
$nl
"Start by pushing a character on the stack; notice that characters are really just integers:"
{ $code "CHAR: a" }
{ $code "[ Letter? ] filter >lower" }
"This code starts with a string on the stack, removes non-alphabetical characters, and converts the result to lower case, leaving a new string on the stack. We put this code in a new word, and add the new word to " { $snippet "palindrome.factor" } ":"
{ $code ": normalize ( str -- newstr ) [ Letter? ] filter >lower ;" }
-"You will need to add " { $vocab-link "unicode.case" } " and " { $vocab-link "unicode.categories" } " to the vocabulary search path, so that " { $link Letter? } " can be used in the source file."
+"You will need to add " { $vocab-link "unicode.case" } " and " { $vocab-link "unicode.categories" } " to the vocabulary search path, so that " { $link >lower } " and " { $link Letter? } " can be used in the source file."
$nl
"We modify " { $snippet "palindrome?" } " to first apply " { $snippet "normalize" } " to its input:"
{ $code ": palindrome? ( str -- ? ) normalize dup reverse = ;" }
-IN: help.vocabs.tests
USING: help.vocabs tools.test help.markup help vocabs ;
+IN: help.vocabs.tests
[ ] [ { $vocab "scratchpad" } print-content ] unit-test
-[ ] [ "classes" vocab print-topic ] unit-test
\ No newline at end of file
+[ ] [ "classes" vocab print-topic ] unit-test
make namespaces prettyprint sequences sets sorting summary
vocabs vocabs.files vocabs.hierarchy vocabs.loader
vocabs.metadata words words.symbol definitions.icons ;
+FROM: vocabs.hierarchy => child-vocabs ;
IN: help.vocabs
: about ( vocab -- )
$heading ;
: $vocabs ( seq -- )
- [ vocab-row ] map vocab-headings prefix $table ;
+ convert-prefixes [ vocab-row ] map vocab-headings prefix $table ;
: $vocab-roots ( assoc -- )
[
] unless-empty ;
: describe-children ( vocab -- )
- vocab-name all-child-vocabs $vocab-roots ;
+ vocab-name child-vocabs
+ $vocab-roots ;
: files. ( seq -- )
snippet-style get [
} cleave ;
: keyed-vocabs ( str quot -- seq )
- [ all-vocabs ] 2dip '[ [ _ swap @ member? ] filter ] assoc-map ; inline
+ [ all-vocabs-recursive ] 2dip
+ '[ [ _ swap @ member? ] filter no-prefixes ] assoc-map ; inline
: tagged ( tag -- assoc )
[ vocab-tags ] keyed-vocabs ;
dup [ array? ] all? [ first ] when length ;
SYNTAX: HINTS:
- scan-object
+ scan-object dup wrapper? [ wrapped>> ] when
[ changed-definition ]
- [ parse-definition { } like "specializer" set-word-prop ] bi ;
+ [ subwords [ changed-definition ] each ]
+ [ parse-definition { } like "specializer" set-word-prop ] tri ;
! Default specializers
{ first first2 first3 first4 }
\ push { { vector } { sbuf } } "specializer" set-word-prop
+\ last { { vector } } "specializer" set-word-prop
+
+\ set-last { { object vector } } "specializer" set-word-prop
+
\ push-all
{ { string sbuf } { array vector } { byte-array byte-vector } }
"specializer" set-word-prop
-IN: html.components.tests
USING: tools.test kernel io.streams.string
io.streams.null accessors inspector html.streams
html.components html.forms namespaces
xml.writer ;
FROM: html.components => inspector ;
+IN: html.components.tests
[ ] [ begin-form ] unit-test
-IN: html.forms.tests
USING: kernel sequences tools.test assocs html.forms validators accessors
namespaces ;
FROM: html.forms => values ;
+IN: html.forms.tests
: with-validation ( quot -- messages )
[
[ value ] dip '[
[
form [ clone ] change
- 1+ "index" set-value
+ 1 + "index" set-value
"value" set-value
@
] with-scope
[ value ] dip '[
[
begin-form
- 1+ "index" set-value
+ 1 + "index" set-value
from-object
@
] with-scope
M: template-lexer skip-word
[
{
- { [ 2dup nth CHAR: " = ] [ drop 1+ ] }
+ { [ 2dup nth CHAR: " = ] [ drop 1 + ] }
{ [ 2dup swap tail-slice "%>" head? ] [ drop 2 + ] }
[ f skip ]
} cond
USING: http.client http.client.private http tools.test
namespaces urls ;
+IN: http.client.tests
[ "localhost" f ] [ "localhost" parse-host ] unit-test
[ "localhost" 8888 ] [ "localhost:8888" parse-host ] unit-test
{ version "1.1" }
{ cookies V{ } }
{ header H{ { "connection" "close" } { "user-agent" "Factor http.client" } } }
+ { redirects 10 }
}
] [
"http://www.apple.com/index.html"
{ version "1.1" }
{ cookies V{ } }
{ header H{ { "connection" "close" } { "user-agent" "Factor http.client" } } }
+ { redirects 10 }
}
] [
"https://www.amazon.com/index.html"
ERROR: too-many-redirects ;
-CONSTANT: max-redirects 10
-
<PRIVATE
: write-request-line ( request -- request )
:: do-redirect ( quot: ( chunk -- ) response -- response )
redirects inc
- redirects get max-redirects < [
+ redirects get request get redirects>> < [
request get clone
response "location" header redirect-url
response code>> 307 = [ "GET" >>method ] unless
with-output-stream*
] [
in>> [
- read-response dup redirect? [ t ] [
+ read-response dup redirect?
+ request get redirects>> 0 > and [ t ] [
[ nip response set ]
[ read-response-body ]
[ ]
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel summary debugger io make math.parser
-prettyprint http.client accessors ;
+prettyprint http http.client accessors ;
IN: http.client.debugger
M: too-many-redirects summary
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test http.client.post-data ;
-IN: http.client.post-data.tests
{ { $slot "header" } { "An assoc of HTTP header values. See " { $link "http.headers" } } }
{ { $slot "post-data" } { "See " { $link "http.post-data" } } }
{ { $slot "cookies" } { "A sequence of HTTP cookies. See " { $link "http.cookies" } } }
+ { { $slot "redirects" } { "Number of redirects to attempt before throwing an error. Default is " { $snippet "max-redirects" } " ." } }
} } ;
HELP: <response>
{ header H{ { "some-header" "1; 2" } { "content-length" "4" } { "content-type" "application/octet-stream" } } }
{ post-data T{ post-data { data "blah" } { content-type "application/octet-stream" } } }
{ cookies V{ } }
+ { redirects 10 }
}
] [
read-request-test-1 lf>crlf [
{ version "1.1" }
{ header H{ { "host" "www.sex.com" } } }
{ cookies V{ } }
+ { redirects 10 }
}
] [
read-request-test-2 lf>crlf [
base64 ;
IN: http
+CONSTANT: max-redirects 10
+
: (read-header) ( -- alist )
[ read-crlf dup f like ] [ parse-header-line ] produce nip ;
version
header
post-data
-cookies ;
+cookies
+redirects ;
: set-header ( request/response value key -- request/response )
pick header>> set-at ;
H{ } clone >>header
V{ } clone >>cookies
"close" "connection" set-header
- "Factor http.client" "user-agent" set-header ;
+ "Factor http.client" "user-agent" set-header
+ max-redirects >>redirects ;
: header ( request/response key -- value )
swap header>> at ;
-IN: http.parsers.tests
USING: http http.parsers tools.test ;
+IN: http.parsers.tests
[ { } ] [ "" parse-cookie ] unit-test
[ { } ] [ "" parse-set-cookie ] unit-test
[ { T{ cookie { name "__s" } { value "12345567" } } } ]
[ "__s=12345567;" parse-cookie ]
-unit-test
\ No newline at end of file
+unit-test
-IN: http.server.redirection.tests
USING: http http.server.redirection urls accessors
namespaces tools.test present kernel ;
+IN: http.server.redirection.tests
[
<request>
--- /dev/null
+IN: http.server.rewrite
+USING: help.syntax help.markup http.server ;
+
+HELP: rewrite
+{ $class-description "The class of directory rewrite responders. The slots are as follows:"
+{ $list
+ { { $slot "default" } " - the responder to call if no file name is provided." }
+ { { $slot "child" } " - the responder to call if a file name is provided." }
+ { { $slot "param" } " - the name of a request parameter which will store the first path component of the file name passed to the responder." }
+} } ;
+
+HELP: <rewrite>
+{ $values { "rewrite" rewrite } }
+{ $description "Creates a new " { $link rewrite } " responder." }
+{ $examples
+ { $code
+ "<rewrite>"
+ " <display-post-action> >>default"
+ " <display-comment-action> >>child"
+ " \"comment_id\" >>param"
+ }
+} ;
+
+HELP: vhost-rewrite
+{ $class-description "The class of virtual host rewrite responders. The slots are as follows:"
+{ $list
+ { { $slot "default" } " - the responder to call if no host name prefix is provided." }
+ { { $slot "child" } " - the responder to call if a host name prefix is provided." }
+ { { $slot "param" } " - the name of a request parameter which will store the first host name component of the host name passed to the responder." }
+ { { $slot "suffix" } " - the domain name suffix which will be chopped off the end of the request's host name in order to produce the parameter." }
+} } ;
+
+HELP: <vhost-rewrite>
+{ $values { "vhost-rewrite" vhost-rewrite } }
+{ $description "Creates a new " { $link vhost-rewrite } " responder." }
+{ $examples
+ { $code
+ "<vhost-rewrite>"
+ " <show-blogs-action> >>default"
+ " <display-blog-action> >>child"
+ " \"blog_id\" >>param"
+ " \"blogs.vegan.net\" >>suffix"
+ }
+} ;
+
+ARTICLE: "http.server.rewrite.overview" "Rewrite responder overview"
+"Rewrite responders take the file name and turn it into a request parameter named by the " { $slot "param" } " slot before delegating to a child responder. If a file name is provided, it calls the responder in the " { $slot "child" } " slot. If no file name is provided, they call the default responder in the " { $slot "default" } " slot."
+$nl
+"For example, suppose you want to have the following website schema:"
+{ $list
+{ { $snippet "/posts/" } " - show a list of posts" }
+{ { $snippet "/posts/factor_language" } " - show thread with ID " { $snippet "factor_language" } }
+{ { $snippet "/posts/factor_language/1" } " - show first comment in the thread with ID " { $snippet "factor_language" } }
+{ { $snippet "/animals" } ", ... - a bunch of other actions" } }
+"One way to achieve this would be to have a nesting of responders as follows:"
+{ $list
+{ "A dispatcher at the top level" }
+ { "A " { $link rewrite } " as a child of the dispatcher under the name " { $snippet "posts" } ". The rewrite has the " { $slot "param" } " slot set to, say, " { $snippet "post_id" } ". The " { $slot "default" } " slot is set to a Furnace action which displays a list of posts." }
+ { "The child slot is set to a second " { $link rewrite } " instance, with " { $snippet "param" } " set to " { $snippet "comment_id" } ", the " { $slot "default" } " slot set to an action which displays a post identified by the " { $snippet "post_id" } " parameter, and the " { $snippet "child" } " slot set to an action which displays the comment identified by the " { $snippet "comment_id" } " parameter." } }
+"Note that parameters can be extracted from the request using the " { $link param } " word, but most of the time you want to use " { $vocab-link "furnace.actions" } " instead." ;
+
+ARTICLE: "http.server.rewrite" "URL rewrite responders"
+"The " { $vocab-link "http.server.rewrite" } " vocabulary defines two responder types which can help make website URLs more human-friendly."
+{ $subsection "http.server.rewrite.overview" }
+"Directory rewrite responders:"
+{ $subsection rewrite }
+{ $subsection <rewrite> }
+"Virtual host rewrite responders -- these chop off the value in the " { $snippet "suffix" } " slot from the tail of the host name, and use the rest as the parameter value:"
+{ $subsection vhost-rewrite }
+{ $subsection <vhost-rewrite> } ;
+
+ABOUT: "http.server.rewrite"
\ No newline at end of file
--- /dev/null
+USING: accessors arrays http.server http.server.rewrite kernel
+namespaces tools.test urls ;
+IN: http.server.rewrite.tests
+
+TUPLE: rewrite-test-default ;
+
+M: rewrite-test-default call-responder*
+ drop "DEFAULT!" 2array ;
+
+TUPLE: rewrite-test-child ;
+
+M: rewrite-test-child call-responder*
+ drop "rewritten-param" param 2array ;
+
+V{ } clone responder-nesting set
+H{ } clone params set
+
+<rewrite>
+ rewrite-test-child new >>child
+ rewrite-test-default new >>default
+ "rewritten-param" >>param
+"rewrite" set
+
+[ { { } "DEFAULT!" } ] [ { } "rewrite" get call-responder ] unit-test
+[ { { } "xxx" } ] [ { "xxx" } "rewrite" get call-responder ] unit-test
+[ { { "blah" } "xxx" } ] [ { "xxx" "blah" } "rewrite" get call-responder ] unit-test
+
+<vhost-rewrite>
+ rewrite-test-child new >>child
+ rewrite-test-default new >>default
+ "rewritten-param" >>param
+ "blogs.vegan.net" >>suffix
+"rewrite" set
+
+[ { { } "DEFAULT!" } ] [
+ URL" http://blogs.vegan.net" url set
+ { } "rewrite" get call-responder
+] unit-test
+
+[ { { } "DEFAULT!" } ] [
+ URL" http://www.blogs.vegan.net" url set
+ { } "rewrite" get call-responder
+] unit-test
+
+[ { { } "erg" } ] [
+ URL" http://erg.blogs.vegan.net" url set
+ { } "rewrite" get call-responder
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors http.server http.server.dispatchers kernel
+namespaces sequences splitting urls ;
+IN: http.server.rewrite
+
+TUPLE: rewrite param child default ;
+
+: <rewrite> ( -- rewrite )
+ rewrite new ;
+
+M: rewrite call-responder*
+ over empty? [ default>> ] [
+ [ [ first ] [ param>> ] bi* set-param ]
+ [ [ rest ] [ child>> ] bi* ]
+ 2bi
+ ] if
+ call-responder* ;
+
+TUPLE: vhost-rewrite suffix param child default ;
+
+: <vhost-rewrite> ( -- vhost-rewrite )
+ vhost-rewrite new ;
+
+: sub-domain? ( vhost-rewrite url -- subdomain ? )
+ swap suffix>> dup [
+ [ host>> canonical-host ] [ "." prepend ] bi* ?tail
+ ] [ 2drop f f ] if ;
+
+M: vhost-rewrite call-responder*
+ dup url get sub-domain?
+ [ over param>> set-param child>> ] [ drop default>> ] if
+ call-responder ;
-USING: help.markup help.syntax io.streams.string quotations strings urls http vocabs.refresh math io.servers.connection ;
+USING: help.markup help.syntax io.streams.string quotations strings urls
+http vocabs.refresh math io.servers.connection assocs ;
IN: http.server
HELP: trivial-responder
HELP: http-insomniac
{ $description "Starts a thread which rotates the logs and e-mails a summary of HTTP requests every 24 hours. See " { $link "logging.insomniac" } "." } ;
+HELP: request-params
+{ $values { "request" request } { "assoc" assoc } }
+{ $description "Outputs the query parameters (if the current request is a GET or HEAD request) or the POST parameters (if the current request is a POST request)." } ;
+
+HELP: param
+{ $values
+ { "name" string }
+ { "value" string }
+}
+{ $description "Outputs the value of a query parameter (if the current request is a GET or HEAD request) or a POST parameter (if the current request is a POST request)." }
+{ $notes "Instead of using this word, it is better to use " { $vocab-link "furnace.actions" } " and the associated validation machinery, which allows you to access values using " { $link "html.forms.values" } " words." } ;
+
+HELP: params
+{ $var-description "A variable holding an assoc of query parameters (if the current request is a GET or HEAD request) or POST parameters (if the current request is a POST request)." }
+{ $notes "Instead of using this word, it is better to use " { $vocab-link "furnace.actions" } " and the associated validation machinery, which allows you to access values using " { $link "html.forms.values" } " words." } ;
+
ARTICLE: "http.server.requests" "HTTP request variables"
"The following variables are set by the HTTP server at the beginning of a request."
{ $subsection request }
{ $subsection url }
{ $subsection post-request? }
{ $subsection responder-nesting }
+{ $subsection params }
+"Utility words:"
+{ $subsection param }
+{ $subsection set-param }
+{ $subsection request-params }
"Additional vocabularies may be set by vocabularies such as " { $vocab-link "html.forms" } " and " { $vocab-link "furnace.sessions" } "." ;
ARTICLE: "http.server.responders" "HTTP server responders"
USING: kernel accessors sequences arrays namespaces splitting
vocabs.loader destructors assocs debugger continuations
combinators vocabs.refresh tools.time math math.parser present
-io vectors
+vectors hashtables
+io
io.sockets
io.sockets.secure
io.encodings
: split-path ( string -- path )
"/" split harvest ;
+: request-params ( request -- assoc )
+ dup method>> {
+ { "GET" [ url>> query>> ] }
+ { "HEAD" [ url>> query>> ] }
+ { "POST" [ post-data>> params>> ] }
+ } case ;
+
+SYMBOL: params
+
+: param ( name -- value )
+ params get at ;
+
+: set-param ( value name -- )
+ params get set-at ;
+
: init-request ( request -- )
- [ request set ] [ url>> url set ] bi
+ [ request set ]
+ [ url>> url set ]
+ [ request-params >hashtable params set ] tri
V{ } clone responder-nesting set ;
: dispatch-request ( request -- response )
-IN: http.server.static.tests
USING: http.server.static tools.test xml.writer ;
+IN: http.server.static.tests
-[ ] [ "resource:basis" directory>html write-xml ] unit-test
\ No newline at end of file
+[ ] [ "resource:basis" directory>html write-xml ] unit-test
USING: images.bitmap images.viewer io.encodings.binary
io.files io.files.unique kernel tools.test images.loader
-literals sequences checksums.md5 checksums
-images.normalization ;
+literals sequences checksums.md5 checksums ;
IN: images.bitmap.tests
CONSTANT: test-bitmap24 "vocab:images/test-images/thiswayup24.bmp"
: test-bitmap-save ( path -- ? )
[ md5 checksum-file ]
- [ load-image normalize-image ] bi
- "bitmap-save-test" unique-file
+ [ load-image ] bi
+ "bitmap-save-test" ".bmp" make-unique-file
[ save-bitmap ]
[ md5 checksum-file ] bi = ;
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.c-types arrays byte-arrays columns
combinators compression.run-length endian fry grouping images
-images.loader io io.binary io.encodings.binary io.files
+images.bitmap.loading images.loader io io.binary
+io.encodings.binary io.encodings.string io.files
io.streams.limited kernel locals macros math math.bitwise
math.functions namespaces sequences specialized-arrays.uint
-specialized-arrays.ushort strings summary io.encodings.8-bit
-io.encodings.string ;
-QUALIFIED-WITH: bitstreams b
+specialized-arrays.ushort strings summary ;
IN: images.bitmap
-: read2 ( -- n ) 2 read le> ;
-: read4 ( -- n ) 4 read le> ;
: write2 ( n -- ) 2 >le write ;
: write4 ( n -- ) 4 >le write ;
-SINGLETON: bitmap-image
-"bmp" bitmap-image register-image-class
-
-TUPLE: loading-bitmap
-magic size reserved1 reserved2 offset header-length width
-height planes bit-count compression size-image
-x-pels y-pels color-used color-important
-red-mask green-mask blue-mask alpha-mask
-cs-type end-points
-gamma-red gamma-green gamma-blue
-intent profile-data profile-size reserved3
-color-palette color-index bitfields ;
-
-! endpoints-triple is ciexyzX/Y/Z, 3x fixed-point-2.30 aka 3x uint
-
-<PRIVATE
-
-: os2-color-lookup ( loading-bitmap -- seq )
- [ color-index>> >array ]
- [ color-palette>> 3 <sliced-groups> ] bi
- '[ _ nth ] map concat ;
-
-: os2v2-color-lookup ( loading-bitmap -- seq )
- [ color-index>> >array ]
- [ color-palette>> 3 <sliced-groups> ] bi
- '[ _ nth ] map concat ;
-
-: v3-color-lookup ( loading-bitmap -- seq )
- [ color-index>> >array ]
- [ color-palette>> 4 <sliced-groups> [ 3 head-slice ] map ] bi
- '[ _ nth ] map concat ;
-
-: color-lookup ( loading-bitmap -- seq )
- dup header-length>> {
- { 12 [ os2-color-lookup ] }
- { 64 [ os2v2-color-lookup ] }
- { 40 [ v3-color-lookup ] }
- ! { 108 [ v4-color-lookup ] }
- ! { 124 [ v5-color-lookup ] }
- } case ;
-
-ERROR: bmp-not-supported n ;
-
-: uncompress-bitfield ( seq masks -- bytes' )
- '[
- _ [
- [ bitand ] [ bit-count ] [ log2 ] tri - shift
- ] with map
- ] { } map-as B{ } concat-as ;
-
-: bitmap>bytes ( loading-bitmap -- byte-array )
- dup bit-count>>
- {
- { 32 [ color-index>> ] }
- { 24 [ color-index>> ] }
- { 16 [
- [
- ! byte-array>ushort-array
- 2 group [ le> ] map
- ! 5 6 5
- ! { HEX: f800 HEX: 7e0 HEX: 1f } uncompress-bitfield
- ! 5 5 5
- { HEX: 7c00 HEX: 3e0 HEX: 1f } uncompress-bitfield
- ] change-color-index
- color-index>>
- ] }
- { 8 [ color-lookup ] }
- { 4 [ [ 4 b:byte-array-n>seq ] change-color-index color-lookup ] }
- { 1 [ [ 1 b:byte-array-n>seq ] change-color-index color-lookup ] }
- [ bmp-not-supported ]
- } case >byte-array ;
-
-: set-bitfield-widths ( loading-bitmap -- loading-bitmap' )
- dup bit-count>> {
- { 16 [ dup color-palette>> 4 group [ le> ] map ] }
- { 32 [ { HEX: ff0000 HEX: ff00 HEX: ff } ] }
- } case reverse >>bitfields ;
-
-ERROR: unsupported-bitfield-widths n ;
-
-M: unsupported-bitfield-widths summary
- drop "Bitmaps only support bitfield compression in 16/32bit images" ;
-
-: uncompress-bitfield-widths ( loading-bitmap -- loading-bitmap' )
- set-bitfield-widths
- dup bit-count>> {
- { 16 [
- dup bitfields>> '[
- byte-array>ushort-array _ uncompress-bitfield
- ] change-color-index
- ] }
- { 32 [
- dup bitfields>> '[
- byte-array>uint-array _ uncompress-bitfield
- ] change-color-index
- ] }
- [ unsupported-bitfield-widths ]
- } case ;
-
-ERROR: unsupported-bitmap-compression compression ;
-
-: uncompress-bitmap ( loading-bitmap -- loading-bitmap' )
- dup compression>> {
- { f [ ] }
- { 0 [ ] }
- { 1 [ [ run-length-uncompress ] change-color-index ] }
- { 2 [ [ 4 b:byte-array-n>seq run-length-uncompress >byte-array ] change-color-index ] }
- { 3 [ uncompress-bitfield-widths ] }
- { 4 [ "jpeg" unsupported-bitmap-compression ] }
- { 5 [ "png" unsupported-bitmap-compression ] }
- } case ;
-
-: bitmap-padding ( width -- n )
- 3 * 4 mod 4 swap - 4 mod ; inline
-
-: loading-bitmap>bytes ( loading-bitmap -- byte-array )
- uncompress-bitmap
- bitmap>bytes ;
-
-: parse-file-header ( loading-bitmap -- loading-bitmap )
- 2 read latin1 decode >>magic
- read4 >>size
- read2 >>reserved1
- read2 >>reserved2
- read4 >>offset ;
-
-: read-v3-header ( loading-bitmap -- loading-bitmap )
- read4 >>width
- read4 32 >signed >>height
- read2 >>planes
- read2 >>bit-count
- read4 >>compression
- read4 >>size-image
- read4 >>x-pels
- read4 >>y-pels
- read4 >>color-used
- read4 >>color-important ;
-
-: read-v4-header ( loading-bitmap -- loading-bitmap )
- read-v3-header
- read4 >>red-mask
- read4 >>green-mask
- read4 >>blue-mask
- read4 >>alpha-mask
- read4 >>cs-type
- read4 read4 read4 3array >>end-points
- read4 >>gamma-red
- read4 >>gamma-green
- read4 >>gamma-blue ;
-
-: read-v5-header ( loading-bitmap -- loading-bitmap )
- read-v4-header
- read4 >>intent
- read4 >>profile-data
- read4 >>profile-size
- read4 >>reserved3 ;
-
-: read-os2-header ( loading-bitmap -- loading-bitmap )
- read2 >>width
- read2 16 >signed >>height
- read2 >>planes
- read2 >>bit-count ;
-
-: read-os2v2-header ( loading-bitmap -- loading-bitmap )
- read4 >>width
- read4 32 >signed >>height
- read2 >>planes
- read2 >>bit-count ;
-
-ERROR: unknown-bitmap-header n ;
-
-: parse-bitmap-header ( loading-bitmap -- loading-bitmap )
- read4 [ >>header-length ] keep
- {
- { 12 [ read-os2-header ] }
- { 64 [ read-os2v2-header ] }
- { 40 [ read-v3-header ] }
- { 108 [ read-v4-header ] }
- { 124 [ read-v5-header ] }
- [ unknown-bitmap-header ]
- } case ;
-
-: color-palette-length ( loading-bitmap -- n )
- [ offset>> 14 - ] [ header-length>> ] bi - ;
-
-: color-index-length ( loading-bitmap -- n )
- {
- [ width>> ]
- [ planes>> * ]
- [ bit-count>> * 31 + 32 /i 4 * ]
- [ height>> abs * ]
- } cleave ;
-
-: image-size ( loading-bitmap -- n )
- [ [ width>> ] [ height>> ] bi * ] [ bit-count>> 8 /i ] bi * abs ;
-
-: parse-bitmap ( loading-bitmap -- loading-bitmap )
- dup color-palette-length read >>color-palette
- dup size-image>> dup 0 > [
- read >>color-index
- ] [
- drop dup color-index-length read >>color-index
- ] if ;
-
-ERROR: unsupported-bitmap-file magic ;
-
-: load-bitmap ( path -- loading-bitmap )
- binary stream-throws <limited-file-reader> [
- loading-bitmap new
- parse-file-header dup magic>> {
- { "BM" [ parse-bitmap-header parse-bitmap ] }
- ! { "BA" [ parse-os2-bitmap-array ] }
- ! { "CI" [ parse-os2-color-icon ] }
- ! { "CP" [ parse-os2-color-pointer ] }
- ! { "IC" [ parse-os2-icon ] }
- ! { "PT" [ parse-os2-pointer ] }
- [ unsupported-bitmap-file ]
- } case
- ] with-input-stream ;
-
-ERROR: unknown-component-order bitmap ;
-
-: bitmap>component-order ( loading-bitmap -- object )
- bit-count>> {
- { 32 [ BGR ] }
- { 24 [ BGR ] }
- { 16 [ BGR ] }
- { 8 [ BGR ] }
- { 4 [ BGR ] }
- { 1 [ BGR ] }
- [ unknown-component-order ]
- } case ;
-
-M: bitmap-image load-image* ( path bitmap-image -- bitmap )
- drop load-bitmap
- [ image new ] dip
- {
- [ loading-bitmap>bytes >>bitmap ]
- [ [ width>> ] [ height>> abs ] bi 2array >>dim ]
- [ height>> 0 < not >>upside-down? ]
- [ compression>> 3 = [ t >>upside-down? ] when ]
- [ bitmap>component-order >>component-order ]
- } cleave ;
-
-PRIVATE>
-
-: bitmap>color-index ( bitmap -- byte-array )
- [
- bitmap>>
- 4 <sliced-groups>
- [ 3 head-slice <reversed> ] map
- B{ } join
- ] [
- dim>> first dup bitmap-padding dup 0 > [
- [ 3 * group ] dip '[ _ <byte-array> append ] map
- B{ } join
- ] [
- 2drop
- ] if
- ] bi ;
-
-: reverse-lines ( byte-array width -- byte-array )
- <sliced-groups> <reversed> concat ; inline
-
: save-bitmap ( image path -- )
binary [
B{ CHAR: B CHAR: M } write
[
- bitmap>color-index length 14 + 40 + write4
+ bitmap>> length 14 + 40 + write4
0 write4
54 write4
40 write4
! compression
[ drop 0 write4 ]
- ! size-image
- [ bitmap>color-index length write4 ]
+ ! image-size
+ [ bitmap>> length write4 ]
! x-pels
[ drop 0 write4 ]
[ drop 0 write4 ]
! color-palette
- [
- [ bitmap>color-index ]
- [ dim>> first 3 * ]
- [ dim>> first bitmap-padding + ] tri
- reverse-lines write
- ]
+ [ bitmap>> write ]
} cleave
] bi
] with-file-writer ;
--- /dev/null
+Doug Coleman
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays byte-arrays combinators
+compression.run-length fry grouping images images.loader io
+io.binary io.encodings.8-bit io.encodings.binary
+io.encodings.string io.streams.limited kernel math math.bitwise
+sequences specialized-arrays.ushort summary ;
+QUALIFIED-WITH: bitstreams b
+IN: images.bitmap.loading
+
+SINGLETON: bitmap-image
+"bmp" bitmap-image register-image-class
+
+! http://www.fileformat.info/format/bmp/egff.htm
+! http://www.digicamsoft.com/bmp/bmp.html
+
+ERROR: unknown-component-order bitmap ;
+ERROR: unknown-bitmap-header n ;
+
+: read2 ( -- n ) 2 read le> ;
+: read4 ( -- n ) 4 read le> ;
+
+TUPLE: loading-bitmap
+ file-header header
+ color-palette color-index bitfields ;
+
+TUPLE: file-header
+ { magic initial: "BM" }
+ { size }
+ { reserved1 initial: 0 }
+ { reserved2 initial: 0 }
+ { offset }
+ { header-length } ;
+
+TUPLE: v3-header
+ { width initial: 0 }
+ { height initial: 0 }
+ { planes initial: 0 }
+ { bit-count initial: 0 }
+ { compression initial: 0 }
+ { image-size initial: 0 }
+ { x-resolution initial: 0 }
+ { y-resolution initial: 0 }
+ { colors-used initial: 0 }
+ { colors-important initial: 0 } ;
+
+TUPLE: v4-header < v3-header
+ { red-mask initial: 0 }
+ { green-mask initial: 0 }
+ { blue-mask initial: 0 }
+ { alpha-mask initial: 0 }
+ { cs-type initial: 0 }
+ { end-points initial: 0 }
+ { gamma-red initial: 0 }
+ { gamma-green initial: 0 }
+ { gamma-blue initial: 0 } ;
+
+TUPLE: v5-header < v4-header
+ { intent initial: 0 }
+ { profile-data initial: 0 }
+ { profile-size initial: 0 }
+ { reserved3 initial: 0 } ;
+
+TUPLE: os2v1-header
+ { width initial: 0 }
+ { height initial: 0 }
+ { planes initial: 0 }
+ { bit-count initial: 0 } ;
+
+TUPLE: os2v2-header < os2v1-header
+ { compression initial: 0 }
+ { image-size initial: 0 }
+ { x-resolution initial: 0 }
+ { y-resolution initial: 0 }
+ { colors-used initial: 0 }
+ { colors-important initial: 0 }
+ { units initial: 0 }
+ { reserved initial: 0 }
+ { recording initial: 0 }
+ { rendering initial: 0 }
+ { size1 initial: 0 }
+ { size2 initial: 0 }
+ { color-encoding initial: 0 }
+ { identifier initial: 0 } ;
+
+UNION: v-header v3-header v4-header v5-header ;
+UNION: os2-header os2v1-header os2v2-header ;
+
+: parse-file-header ( -- file-header )
+ \ file-header new
+ 2 read latin1 decode >>magic
+ read4 >>size
+ read2 >>reserved1
+ read2 >>reserved2
+ read4 >>offset
+ read4 >>header-length ;
+
+: read-v3-header-data ( header -- header )
+ read4 >>width
+ read4 32 >signed >>height
+ read2 >>planes
+ read2 >>bit-count
+ read4 >>compression
+ read4 >>image-size
+ read4 >>x-resolution
+ read4 >>y-resolution
+ read4 >>colors-used
+ read4 >>colors-important ;
+
+: read-v3-header ( -- header )
+ \ v3-header new
+ read-v3-header-data ;
+
+: read-v4-header-data ( header -- header )
+ read4 >>red-mask
+ read4 >>green-mask
+ read4 >>blue-mask
+ read4 >>alpha-mask
+ read4 >>cs-type
+ read4 read4 read4 3array >>end-points
+ read4 >>gamma-red
+ read4 >>gamma-green
+ read4 >>gamma-blue ;
+
+: read-v4-header ( -- v4-header )
+ \ v4-header new
+ read-v3-header-data
+ read-v4-header-data ;
+
+: read-v5-header-data ( v5-header -- v5-header )
+ read4 >>intent
+ read4 >>profile-data
+ read4 >>profile-size
+ read4 >>reserved3 ;
+
+: read-v5-header ( -- loading-bitmap )
+ \ v5-header new
+ read-v3-header-data
+ read-v4-header-data
+ read-v5-header-data ;
+
+: read-os2v1-header ( -- os2v1-header )
+ \ os2v1-header new
+ read2 >>width
+ read2 16 >signed >>height
+ read2 >>planes
+ read2 >>bit-count ;
+
+: read-os2v2-header-data ( os2v2-header -- os2v2-header )
+ read4 >>width
+ read4 32 >signed >>height
+ read2 >>planes
+ read2 >>bit-count
+ read4 >>compression
+ read4 >>image-size
+ read4 >>x-resolution
+ read4 >>y-resolution
+ read4 >>colors-used
+ read4 >>colors-important
+ read2 >>units
+ read2 >>reserved
+ read2 >>recording
+ read2 >>rendering
+ read4 >>size1
+ read4 >>size2
+ read4 >>color-encoding
+ read4 >>identifier ;
+
+: read-os2v2-header ( -- os2v2-header )
+ \ os2v2-header new
+ read-os2v2-header-data ;
+
+: parse-header ( n -- header )
+ {
+ { 12 [ read-os2v1-header ] }
+ { 64 [ read-os2v2-header ] }
+ { 40 [ read-v3-header ] }
+ { 108 [ read-v4-header ] }
+ { 124 [ read-v5-header ] }
+ [ unknown-bitmap-header ]
+ } case ;
+
+: color-index-length ( header -- n )
+ {
+ [ width>> ]
+ [ planes>> * ]
+ [ bit-count>> * 31 + 32 /i 4 * ]
+ [ height>> abs * ]
+ } cleave ;
+
+: color-palette-length ( loading-bitmap -- n )
+ file-header>>
+ [ offset>> 14 - ] [ header-length>> ] bi - ;
+
+: parse-color-palette ( loading-bitmap -- loading-bitmap )
+ dup color-palette-length read >>color-palette ;
+
+GENERIC: parse-color-data* ( loading-bitmap header -- loading-bitmap )
+
+: parse-color-data ( loading-bitmap -- loading-bitmap )
+ dup header>> parse-color-data* ;
+
+M: os2v1-header parse-color-data* ( loading-bitmap header -- loading-bitmap )
+ color-index-length read >>color-index ;
+
+M: object parse-color-data* ( loading-bitmap header -- loading-bitmap )
+ dup image-size>> [ 0 ] unless* dup 0 >
+ [ nip ] [ drop color-index-length ] if read >>color-index ;
+
+: alpha-used? ( loading-bitmap -- ? )
+ color-index>> 4 <sliced-groups> [ fourth 0 = ] all? not ;
+
+GENERIC: bitmap>component-order* ( loading-bitmap header -- object )
+
+: bitmap>component-order ( loading-bitmap -- object )
+ dup header>> bitmap>component-order* ;
+
+: simple-bitmap>component-order ( loading-bitamp -- object )
+ header>> bit-count>> {
+ { 32 [ BGRX ] }
+ { 24 [ BGR ] }
+ { 16 [ BGR ] }
+ { 8 [ BGR ] }
+ { 4 [ BGR ] }
+ { 1 [ BGR ] }
+ [ unknown-component-order ]
+ } case ;
+
+: advanced-bitmap>component-order ( loading-bitmap -- object )
+ [ ] [ header>> bit-count>> ] [ alpha-used? ] tri 2array {
+ { { 32 t } [ drop BGRA ] }
+ { { 32 f } [ drop BGRX ] }
+ [ drop simple-bitmap>component-order ]
+ } case ;
+
+: color-lookup3 ( loading-bitmap -- seq )
+ [ color-index>> >array ]
+ [ color-palette>> 3 <sliced-groups> ] bi
+ '[ _ nth ] map concat ;
+
+: color-lookup4 ( loading-bitmap -- seq )
+ [ color-index>> >array ]
+ [ color-palette>> 4 <sliced-groups> [ 3 head-slice ] map ] bi
+ '[ _ nth ] map concat ;
+
+! os2v1 is 3bytes each, all others are 3 + 1 unused
+: color-lookup ( loading-bitmap -- seq )
+ dup file-header>> header-length>> {
+ { 12 [ color-lookup3 ] }
+ { 64 [ color-lookup4 ] }
+ { 40 [ color-lookup4 ] }
+ { 108 [ color-lookup4 ] }
+ { 124 [ color-lookup4 ] }
+ } case ;
+
+M: os2v1-header bitmap>component-order* drop simple-bitmap>component-order ;
+M: os2v2-header bitmap>component-order* drop simple-bitmap>component-order ;
+M: v3-header bitmap>component-order* drop simple-bitmap>component-order ;
+M: v4-header bitmap>component-order* drop advanced-bitmap>component-order ;
+M: v5-header bitmap>component-order* drop advanced-bitmap>component-order ;
+
+: uncompress-bitfield ( seq masks -- bytes' )
+ '[
+ _ [
+ [ bitand ] [ bit-count ] [ log2 ] tri - shift
+ ] with map
+ ] { } map-as B{ } concat-as ;
+
+ERROR: bmp-not-supported n ;
+
+: bitmap>bytes ( loading-bitmap -- byte-array )
+ dup header>> bit-count>>
+ {
+ { 32 [ color-index>> ] }
+ { 24 [ color-index>> ] }
+ { 16 [
+ [
+ ! byte-array>ushort-array
+ 2 group [ le> ] map
+ ! 5 6 5
+ ! { HEX: f800 HEX: 7e0 HEX: 1f } uncompress-bitfield
+ ! 5 5 5
+ { HEX: 7c00 HEX: 3e0 HEX: 1f } uncompress-bitfield
+ ] change-color-index
+ color-index>>
+ ] }
+ { 8 [ color-lookup ] }
+ { 4 [ [ 4 b:byte-array-n>seq ] change-color-index color-lookup ] }
+ { 1 [ [ 1 b:byte-array-n>seq ] change-color-index color-lookup ] }
+ [ bmp-not-supported ]
+ } case >byte-array ;
+
+: set-bitfield-widths ( loading-bitmap -- loading-bitmap' )
+ dup header>> bit-count>> {
+ { 16 [ dup color-palette>> 4 group [ le> ] map ] }
+ { 32 [ { HEX: ff0000 HEX: ff00 HEX: ff } ] }
+ } case reverse >>bitfields ;
+
+ERROR: unsupported-bitfield-widths n ;
+
+M: unsupported-bitfield-widths summary
+ drop "Bitmaps only support bitfield compression in 16/32bit images" ;
+
+: uncompress-bitfield-widths ( loading-bitmap -- loading-bitmap' )
+ set-bitfield-widths
+ dup header>> bit-count>> {
+ { 16 [
+ dup bitfields>> '[
+ byte-array>ushort-array _ uncompress-bitfield
+ ] change-color-index
+ ] }
+ { 32 [ ] }
+ [ unsupported-bitfield-widths ]
+ } case ;
+
+ERROR: unsupported-bitmap-compression compression ;
+
+GENERIC: uncompress-bitmap* ( loading-bitmap header -- loading-bitmap )
+
+: uncompress-bitmap ( loading-bitmap -- loading-bitmap )
+ dup header>> uncompress-bitmap* ;
+
+M: os2-header uncompress-bitmap* ( loading-bitmap header -- loading-bitmap' )
+ drop ;
+
+: do-run-length-uncompress ( loading-bitmap word -- loading-bitmap )
+ dupd '[
+ _ header>> [ width>> ] [ height>> ] bi
+ _ execute
+ ] change-color-index ; inline
+
+M: v-header uncompress-bitmap* ( loading-bitmap header -- loading-bitmap' )
+ compression>> {
+ { f [ ] }
+ { 0 [ ] }
+ { 1 [ \ run-length-uncompress-bitmap8 do-run-length-uncompress ] }
+ { 2 [ \ run-length-uncompress-bitmap4 do-run-length-uncompress ] }
+ { 3 [ uncompress-bitfield-widths ] }
+ { 4 [ "jpeg" unsupported-bitmap-compression ] }
+ { 5 [ "png" unsupported-bitmap-compression ] }
+ } case ;
+
+ERROR: unsupported-bitmap-file magic ;
+
+: load-bitmap ( stream -- loading-bitmap )
+ [
+ \ loading-bitmap new
+ parse-file-header [ >>file-header ] [ ] bi magic>> {
+ { "BM" [
+ dup file-header>> header-length>> parse-header >>header
+ parse-color-palette
+ parse-color-data
+ ] }
+ ! { "BA" [ parse-os2-bitmap-array ] }
+ ! { "CI" [ parse-os2-color-icon ] }
+ ! { "CP" [ parse-os2-color-pointer ] }
+ ! { "IC" [ parse-os2-icon ] }
+ ! { "PT" [ parse-os2-pointer ] }
+ [ unsupported-bitmap-file ]
+ } case
+ ] with-input-stream ;
+
+: loading-bitmap>bytes ( loading-bitmap -- byte-array )
+ uncompress-bitmap bitmap>bytes ;
+
+M: bitmap-image stream>image ( stream bitmap-image -- bitmap )
+ drop load-bitmap
+ [ image new ] dip
+ {
+ [ loading-bitmap>bytes >>bitmap ]
+ [ header>> [ width>> ] [ height>> abs ] bi 2array >>dim ]
+ [ header>> height>> 0 < not >>upside-down? ]
+ [ bitmap>component-order >>component-order ubyte-components >>component-type ]
+ } cleave ;
--- /dev/null
+Doug Coleman
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: http.client images.loader images.loader.private kernel ;
+IN: images.http
+
+: load-http-image ( path -- image )
+ [ http-get nip ] [ image-class new ] bi load-image* ;
USING: images tools.test kernel accessors ;
IN: images.tests
-[ B{ 57 57 57 255 } ] [ 1 1 T{ image f { 2 3 } RGBA f B{
+[ B{ 57 57 57 255 } ] [ 1 1 T{ image f { 2 3 } RGBA ubyte-components f B{
0 0 0 0
0 0 0 0
0 0 0 0
57 57 57 255
0 0 0 0
0 0 0 0
-} ] [ B{ 57 57 57 255 } 1 1 T{ image f { 2 3 } RGBA f B{
+} ] [ B{ 57 57 57 255 } 1 1 T{ image f { 2 3 } RGBA ubyte-components f B{
0 0 0 0
0 0 0 0
0 0 0 0
USING: combinators kernel accessors sequences math arrays ;
IN: images
-SINGLETONS: L LA BGR RGB BGRA RGBA ABGR ARGB RGBX XRGB BGRX XBGR
-R16G16B16 R32G32B32 R16G16B16A16 R32G32B32A32 ;
+SINGLETONS:
+ A L LA BGR RGB BGRA RGBA ABGR ARGB RGBX XRGB BGRX XBGR
+ INTENSITY DEPTH DEPTH-STENCIL R RG
+ ubyte-components ushort-components uint-components
+ half-components float-components
+ byte-integer-components ubyte-integer-components
+ short-integer-components ushort-integer-components
+ int-integer-components uint-integer-components
+ u-5-5-5-1-components u-5-6-5-components
+ u-10-10-10-2-components
+ u-24-components u-24-8-components
+ float-32-u-8-components
+ u-9-9-9-e5-components
+ float-11-11-10-components ;
-UNION: alpha-channel BGRA RGBA ABGR ARGB R16G16B16A16 R32G32B32A32 ;
+UNION: component-order
+ A L LA BGR RGB BGRA RGBA ABGR ARGB RGBX XRGB BGRX XBGR
+ INTENSITY DEPTH DEPTH-STENCIL R RG ;
-: bytes-per-pixel ( component-order -- n )
+UNION: component-type
+ ubyte-components ushort-components uint-components
+ half-components float-components
+ byte-integer-components ubyte-integer-components
+ short-integer-components ushort-integer-components
+ int-integer-components uint-integer-components
+ u-5-5-5-1-components u-5-6-5-components
+ u-10-10-10-2-components
+ u-24-components u-24-8-components
+ float-32-u-8-components
+ u-9-9-9-e5-components
+ float-11-11-10-components ;
+
+UNION: unnormalized-integer-components
+ byte-integer-components ubyte-integer-components
+ short-integer-components ushort-integer-components
+ int-integer-components uint-integer-components ;
+
+UNION: signed-unnormalized-integer-components
+ byte-integer-components
+ short-integer-components
+ int-integer-components ;
+
+UNION: unsigned-unnormalized-integer-components
+ ubyte-integer-components
+ ushort-integer-components
+ uint-integer-components ;
+
+UNION: packed-components
+ u-5-5-5-1-components u-5-6-5-components
+ u-10-10-10-2-components
+ u-24-components u-24-8-components
+ float-32-u-8-components
+ u-9-9-9-e5-components
+ float-11-11-10-components ;
+
+UNION: alpha-channel BGRA RGBA ABGR ARGB LA A INTENSITY ;
+
+UNION: alpha-channel-precedes-colors ABGR ARGB XBGR XRGB ;
+
+TUPLE: image dim component-order component-type upside-down? bitmap ;
+
+: <image> ( -- image ) image new ; inline
+
+: has-alpha? ( image -- ? ) component-order>> alpha-channel? ;
+
+: bytes-per-component ( component-type -- n )
+ {
+ { ubyte-components [ 1 ] }
+ { ushort-components [ 2 ] }
+ { uint-components [ 4 ] }
+ { half-components [ 2 ] }
+ { float-components [ 4 ] }
+ { byte-integer-components [ 1 ] }
+ { ubyte-integer-components [ 1 ] }
+ { short-integer-components [ 2 ] }
+ { ushort-integer-components [ 2 ] }
+ { int-integer-components [ 4 ] }
+ { uint-integer-components [ 4 ] }
+ } case ;
+
+: bytes-per-packed-pixel ( component-type -- n )
{
+ { u-5-5-5-1-components [ 2 ] }
+ { u-5-6-5-components [ 2 ] }
+ { u-10-10-10-2-components [ 4 ] }
+ { u-24-components [ 4 ] }
+ { u-24-8-components [ 4 ] }
+ { u-9-9-9-e5-components [ 4 ] }
+ { float-11-11-10-components [ 4 ] }
+ { float-32-u-8-components [ 8 ] }
+ } case ;
+
+: component-count ( component-order -- n )
+ {
+ { A [ 1 ] }
{ L [ 1 ] }
{ LA [ 2 ] }
{ BGR [ 3 ] }
{ XRGB [ 4 ] }
{ BGRX [ 4 ] }
{ XBGR [ 4 ] }
- { R16G16B16 [ 6 ] }
- { R32G32B32 [ 12 ] }
- { R16G16B16A16 [ 8 ] }
- { R32G32B32A32 [ 16 ] }
+ { INTENSITY [ 1 ] }
+ { DEPTH [ 1 ] }
+ { DEPTH-STENCIL [ 1 ] }
+ { R [ 1 ] }
+ { RG [ 2 ] }
} case ;
-TUPLE: image dim component-order upside-down? bitmap ;
-
-: <image> ( -- image ) image new ; inline
-
-: has-alpha? ( image -- ? ) component-order>> alpha-channel? ;
+: (bytes-per-pixel) ( component-order component-type -- n )
+ dup packed-components?
+ [ nip bytes-per-packed-pixel ] [
+ [ component-count ] [ bytes-per-component ] bi* *
+ ] if ;
-GENERIC: load-image* ( path class -- image )
+: bytes-per-pixel ( image -- n )
+ [ component-order>> ] [ component-type>> ] bi (bytes-per-pixel) ;
<PRIVATE
: pixel@ ( x y image -- start end bitmap )
[ dim>> first * + ]
- [ component-order>> bytes-per-pixel [ * dup ] keep + ]
+ [ bytes-per-pixel [ * dup ] keep + ]
[ bitmap>> ] tri ;
: set-subseq ( new-value from to victim -- )
! Copyright (C) 2009 Marc Fauconneau.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays byte-arrays combinators
-constructors grouping compression.huffman images
+grouping compression.huffman images
images.processing io io.binary io.encodings.binary io.files
io.streams.byte-array kernel locals math math.bitwise
math.constants math.functions math.matrices math.order
math.ranges math.vectors memoize multiline namespaces
-sequences sequences.deep ;
+sequences sequences.deep images.loader ;
IN: images.jpeg
QUALIFIED-WITH: bitstreams bs
{ huff-tables initial: { f f f f } }
{ components } ;
+"jpg" jpeg-image register-image-class
+"jpeg" jpeg-image register-image-class
+
<PRIVATE
-CONSTRUCTOR: jpeg-image ( headers bitstream -- image ) ;
+: <jpeg-image> ( headers bitstream -- image )
+ jpeg-image new swap >>bitstream swap >>headers ;
SINGLETONS: SOF DHT DAC RST SOI EOI SOS DQT DNL DRI DHP EXP
APP JPG COM TEM RES ;
TUPLE: jpeg-chunk length type data ;
-CONSTRUCTOR: jpeg-chunk ( type length data -- jpeg-chunk ) ;
+: <jpeg-chunk> ( type length data -- jpeg-chunk )
+ jpeg-chunk new
+ swap >>data
+ swap >>length
+ swap >>type ;
TUPLE: jpeg-color-info
h v quant-table dc-huff-table ac-huff-table { diff initial: 0 } id ;
-CONSTRUCTOR: jpeg-color-info ( h v quant-table -- jpeg-color-info ) ;
+: <jpeg-color-info> ( h v quant-table -- jpeg-color-info )
+ jpeg-color-info new
+ swap >>quant-table
+ swap >>v
+ swap >>h ;
: jpeg> ( -- jpeg-image ) jpeg-image get ;
] with each^2 ;
: sign-extend ( bits v -- v' )
- swap [ ] [ 1- 2^ < ] 2bi
- [ -1 swap shift 1+ + ] [ drop ] if ;
+ swap [ ] [ 1 - 2^ < ] 2bi
+ [ -1 swap shift 1 + + ] [ drop ] if ;
: read1-jpeg-dc ( decoder -- dc )
[ read1-huff dup ] [ bs>> bs:read ] bi sign-extend ;
0 :> k!
[
color ac-huff-table>> read1-jpeg-ac
- [ first 1+ k + k! ] [ second k coefs set-nth ] [ ] tri
+ [ first 1 + k + k! ] [ second k coefs set-nth ] [ ] tri
{ 0 0 } = not
k 63 < and
] loop
: setup-bitmap ( image -- )
dup dim>> 16 v/n [ ceiling ] map 16 v*n >>dim
BGR >>component-order
+ ubyte-components >>component-type
f >>upside-down?
dup dim>> first2 * 3 * 0 <array> >>bitmap
drop ;
PRIVATE>
-: load-jpeg ( path -- image )
- binary [
+M: jpeg-image stream>image ( stream jpeg-image -- bitmap )
+ drop [
parse-marker { SOI } = [ not-a-jpeg-image ] unless
parse-headers
contents <jpeg-image>
- ] with-file-reader
+ ] with-input-stream
dup jpeg-image [
baseline-parse
baseline-decompress
] with-variable ;
-
-M: jpeg-image load-image* ( path jpeg-image -- bitmap )
- drop load-jpeg ;
-
! Copyright (C) 2009 Doug Coleman, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
-USING: constructors kernel splitting unicode.case combinators
-accessors images io.pathnames namespaces assocs ;
+USING: accessors assocs byte-arrays combinators images
+io.encodings.binary io.pathnames io.streams.byte-array
+io.streams.limited kernel namespaces splitting strings
+unicode.case ;
IN: images.loader
ERROR: unknown-image-extension extension ;
file-extension >lower types get ?at
[ unknown-image-extension ] unless ;
+: open-image-file ( path -- stream )
+ binary stream-throws <limited-file-reader> ;
+
PRIVATE>
+GENERIC# load-image* 1 ( obj class -- image )
+
+GENERIC: stream>image ( stream class -- image )
+
: register-image-class ( extension class -- )
swap types get set-at ;
: load-image ( path -- image )
- dup image-class load-image* ;
+ [ open-image-file ] [ image-class ] bi load-image* ;
+
+M: byte-array load-image*
+ [ binary <byte-reader> ] dip stream>image ;
+
+M: limited-stream load-image* stream>image ;
+
+M: string load-image* [ open-image-file ] dip stream>image ;
+
+M: pathname load-image* [ open-image-file ] dip stream>image ;
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors constructors images io io.binary io.encodings.ascii
+USING: accessors images io io.binary io.encodings.ascii
io.encodings.binary io.encodings.string io.files io.files.info kernel
-sequences io.streams.limited fry combinators arrays math
-checksums checksums.crc32 compression.inflate grouping byte-arrays
-images.loader ;
+sequences io.streams.limited fry combinators arrays math checksums
+checksums.crc32 compression.inflate grouping byte-arrays images.loader ;
IN: images.png
SINGLETON: png-image
"png" png-image register-image-class
-TUPLE: loading-png < image chunks
-width height bit-depth color-type compression-method
-filter-method interlace-method uncompressed ;
+TUPLE: loading-png
+ chunks
+ width height bit-depth color-type compression-method
+ filter-method interlace-method uncompressed ;
-CONSTRUCTOR: loading-png ( -- image )
+: <loading-png> ( -- image )
+ loading-png new
V{ } clone >>chunks ;
TUPLE: png-chunk length type data ;
-CONSTRUCTOR: png-chunk ( -- png-chunk ) ;
+: <png-chunk> ( -- png-chunk )
+ png-chunk new ; inline
CONSTANT: png-header
B{ HEX: 89 HEX: 50 HEX: 4e HEX: 47 HEX: 0d HEX: 0a HEX: 1a HEX: 0a }
ERROR: bad-checksum ;
-: read-png-chunks ( image -- image )
+: read-png-chunks ( loading-png -- loading-png )
<png-chunk>
4 read be> [ >>length ] [ 4 + ] bi
read dup crc32 checksum-bytes
4 read = [ bad-checksum ] unless
4 cut-slice
- [ ascii decode >>type ]
- [ B{ } like >>data ] bi*
+ [ ascii decode >>type ] [ B{ } like >>data ] bi*
[ over chunks>> push ]
[ type>> ] bi "IEND" =
[ read-png-chunks ] unless ;
-: find-chunk ( image string -- chunk )
+: find-chunk ( loading-png string -- chunk )
[ chunks>> ] dip '[ type>> _ = ] find nip ;
-: parse-ihdr-chunk ( image -- image )
+: parse-ihdr-chunk ( loading-png -- loading-png )
dup "IHDR" find-chunk data>> {
[ [ 0 4 ] dip subseq be> >>width ]
[ [ 4 8 ] dip subseq be> >>height ]
[ [ 12 ] dip nth >>interlace-method ]
} cleave ;
-: find-compressed-bytes ( image -- bytes )
+: find-compressed-bytes ( loading-png -- bytes )
chunks>> [ type>> "IDAT" = ] filter
[ data>> ] map concat ;
-: fill-image-data ( image -- image )
- dup [ width>> ] [ height>> ] bi 2array >>dim ;
-: zlib-data ( png-image -- bytes )
+: zlib-data ( loading-png -- bytes )
chunks>> [ type>> "IDAT" = ] find nip data>> ;
ERROR: unknown-color-type n ;
ERROR: unimplemented-color-type image ;
-: inflate-data ( image -- bytes )
+: inflate-data ( loading-png -- bytes )
zlib-data zlib-inflate ;
-: decode-greyscale ( image -- image )
+: decode-greyscale ( loading-png -- loading-png )
unimplemented-color-type ;
-: decode-truecolor ( image -- image )
- {
- [ inflate-data ]
- [ dim>> first 3 * 1 + group reverse-png-filter ]
- [ swap >byte-array >>bitmap drop ]
- [ RGB >>component-order drop ]
- [ ]
+: png-image-bytes ( loading-png -- byte-array )
+ [ inflate-data ] [ width>> 3 * 1 + ] bi group
+ reverse-png-filter ;
+
+: decode-truecolor ( loading-png -- loading-png )
+ [ <image> ] dip {
+ [ png-image-bytes >>bitmap ]
+ [ [ width>> ] [ height>> ] bi 2array >>dim ]
+ [ drop RGB >>component-order ubyte-components >>component-type ]
} cleave ;
-: decode-indexed-color ( image -- image )
+: decode-indexed-color ( loading-png -- loading-png )
unimplemented-color-type ;
-: decode-greyscale-alpha ( image -- image )
+: decode-greyscale-alpha ( loading-png -- loading-png )
unimplemented-color-type ;
-: decode-truecolor-alpha ( image -- image )
- unimplemented-color-type ;
+: decode-truecolor-alpha ( loading-png -- loading-png )
+ [ <image> ] dip {
+ [ png-image-bytes >>bitmap ]
+ [ [ width>> ] [ height>> ] bi 2array >>dim ]
+ [ drop RGBA >>component-order ubyte-components >>component-type ]
+ } cleave ;
-: decode-png ( image -- image )
+: decode-png ( loading-png -- loading-png )
dup color-type>> {
{ 0 [ decode-greyscale ] }
{ 2 [ decode-truecolor ] }
[ unknown-color-type ]
} case ;
-: load-png ( path -- image )
- binary stream-throws <limited-file-reader> [
+M: png-image stream>image
+ drop [
<loading-png>
read-png-header
read-png-chunks
parse-ihdr-chunk
- fill-image-data
decode-png
] with-input-stream ;
-
-M: png-image load-image*
- drop load-png ;
<image> over matrix-dim >>dim\r
swap flip flatten\r
[ 128 * 128 + 0 max 255 min >fixnum ] map\r
- >byte-array >>bitmap L >>component-order ;\r
+ >byte-array >>bitmap L >>component-order ubyte-components >>component-type ;\r
\r
:: matrix-zoom ( m f -- m' )\r
m matrix-dim f v*n coord-matrix\r
[
{
{
- T{ image f { 2 2 } L f B{ 1 2 5 6 } }
- T{ image f { 2 2 } L f B{ 3 4 7 8 } }
+ T{ image f { 2 2 } L ubyte-components f B{ 1 2 5 6 } }
+ T{ image f { 2 2 } L ubyte-components f B{ 3 4 7 8 } }
}
{
- T{ image f { 2 2 } L f B{ 9 10 13 14 } }
- T{ image f { 2 2 } L f B{ 11 12 15 16 } }
+ T{ image f { 2 2 } L ubyte-components f B{ 9 10 13 14 } }
+ T{ image f { 2 2 } L ubyte-components f B{ 11 12 15 16 } }
}
}
] [
1 16 [a,b] >byte-array >>bitmap
{ 4 4 } >>dim
L >>component-order
+ ubyte-components >>component-type
{ 2 2 } tesselate
] unit-test
[
{
{
- T{ image f { 2 2 } L f B{ 1 2 4 5 } }
- T{ image f { 1 2 } L f B{ 3 6 } }
+ T{ image f { 2 2 } L ubyte-components f B{ 1 2 4 5 } }
+ T{ image f { 1 2 } L ubyte-components f B{ 3 6 } }
}
{
- T{ image f { 2 1 } L f B{ 7 8 } }
- T{ image f { 1 1 } L f B{ 9 } }
+ T{ image f { 2 1 } L ubyte-components f B{ 7 8 } }
+ T{ image f { 1 1 } L ubyte-components f B{ 9 } }
}
}
] [
1 9 [a,b] >byte-array >>bitmap
{ 3 3 } >>dim
L >>component-order
+ ubyte-components >>component-type
{ 2 2 } tesselate
-] unit-test
\ No newline at end of file
+] unit-test
'[ _ tesselate-columns ] map ;
: tile-width ( tile-bitmap original-image -- width )
- [ first length ] [ component-order>> bytes-per-pixel ] bi* /i ;
+ [ first length ] [ bytes-per-pixel ] bi* /i ;
: <tile-image> ( tile-bitmap original-image -- tile-image )
clone
[ [ over tile-width ] [ length ] bi 2array >>dim ] bi ;
:: tesselate ( image tess-dim -- image-grid )
- image component-order>> bytes-per-pixel :> bpp
+ image bytes-per-pixel :> bpp
image dim>> { bpp 1 } v* :> image-dim'
tess-dim { bpp 1 } v* :> tess-dim'
image bitmap>> image-dim' tess-dim' tesselate-bitmap
- [ [ image <tile-image> ] map ] map ;
\ No newline at end of file
+ [ [ image <tile-image> ] map ] map ;
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs byte-arrays classes combinators
-compression.lzw constructors endian fry grouping images io
+compression.lzw endian fry grouping images io
io.binary io.encodings.ascii io.encodings.binary
io.encodings.string io.encodings.utf8 io.files kernel math
math.bitwise math.order math.parser pack prettyprint sequences
SINGLETON: tiff-image
TUPLE: loading-tiff endianness the-answer ifd-offset ifds ;
-CONSTRUCTOR: loading-tiff ( -- tiff ) V{ } clone >>ifds ;
+
+: <loading-tiff> ( -- tiff )
+ loading-tiff new V{ } clone >>ifds ;
TUPLE: ifd count ifd-entries next
processed-tags strips bitmap ;
-CONSTRUCTOR: ifd ( count ifd-entries next -- ifd ) ;
+
+: <ifd> ( count ifd-entries next -- ifd )
+ ifd new
+ swap >>next
+ swap >>ifd-entries
+ swap >>count ;
TUPLE: ifd-entry tag type count offset/value ;
-CONSTRUCTOR: ifd-entry ( tag type count offset/value -- ifd-entry ) ;
+
+: <ifd-entry> ( tag type count offset/value -- ifd-entry )
+ ifd-entry new
+ swap >>offset/value
+ swap >>count
+ swap >>type
+ swap >>tag ;
SINGLETONS: photometric-interpretation
photometric-interpretation-white-is-zero
'[
_ group
[ _ group unclip [ v+ ] accumulate swap suffix concat ] map
- concat >byte-array
+ B{ } concat-as
] change-bitmap ;
: strips-predictor ( ifd -- ifd )
[ unknown-component-order ]
} case >>bitmap ;
-: ifd-component-order ( ifd -- byte-order )
+: ifd-component-order ( ifd -- component-order component-type )
bits-per-sample find-tag {
- { { 32 32 32 32 } [ R32G32B32A32 ] }
- { { 32 32 32 } [ R32G32B32 ] }
- { { 16 16 16 16 } [ R16G16B16A16 ] }
- { { 16 16 16 } [ R16G16B16 ] }
- { { 8 8 8 8 } [ RGBA ] }
- { { 8 8 8 } [ RGB ] }
- { 8 [ LA ] }
+ { { 32 32 32 32 } [ RGBA float-components ] }
+ { { 32 32 32 } [ RGB float-components ] }
+ { { 16 16 16 16 } [ RGBA ushort-components ] }
+ { { 16 16 16 } [ RGB ushort-components ] }
+ { { 8 8 8 8 } [ RGBA ubyte-components ] }
+ { { 8 8 8 } [ RGB ubyte-components ] }
+ { 8 [ LA ubyte-components ] }
[ unknown-component-order ]
} case ;
} case ;
: ifd>image ( ifd -- image )
- {
- [ [ image-width find-tag ] [ image-length find-tag ] bi 2array ]
- [ ifd-component-order f ]
- [ bitmap>> ]
- } cleave image boa ;
+ [ <image> ] dip {
+ [ [ image-width find-tag ] [ image-length find-tag ] bi 2array >>dim ]
+ [ ifd-component-order [ >>component-order ] [ >>component-type ] bi* ]
+ [ bitmap>> >>bitmap ]
+ } cleave ;
: tiff>image ( image -- image )
ifds>> [ ifd>image ] map first ;
: with-tiff-endianness ( loading-tiff quot -- )
[ dup endianness>> ] dip with-endianness ; inline
-: load-tiff-ifds ( path -- loading-tiff )
- binary [
+: load-tiff-ifds ( stream -- loading-tiff )
+ [
<loading-tiff>
read-header [
dup ifd-offset>> read-ifds
process-ifds
] with-tiff-endianness
- ] with-file-reader ;
+ ] with-input-stream* ;
: process-chunky-ifd ( ifd -- )
read-strips
ifds>> [ process-ifd ] each ;
: load-tiff ( path -- loading-tiff )
- [ load-tiff-ifds dup ] keep
- binary [
- [ process-tif-ifds ] with-tiff-endianness
- ] with-file-reader ;
+ [ load-tiff-ifds dup ]
+ [
+ [ [ 0 seek-absolute ] dip stream-seek ]
+ [
+ [
+ [ process-tif-ifds ] with-tiff-endianness
+ ] with-input-stream
+ ] bi
+ ] bi ;
! tiff files can store several images -- we just take the first for now
-M: tiff-image load-image* ( path tiff-image -- image )
+M: tiff-image stream>image ( stream tiff-image -- image )
drop load-tiff tiff>image ;
{ "tif" "tiff" } [ tiff-image register-image-class ] each
array>> [ value ] map ;\r
\r
: <interval-map> ( specification -- map )\r
- all-intervals [ [ first second ] compare ] sort\r
+ all-intervals [ first second ] sort-with\r
>intervals ensure-disjoint interval-map boa ;\r
\r
: <interval-set> ( specification -- map )\r
[\r
alist sort-keys unclip swap [ [ first dup ] [ second ] bi ] dip\r
[| oldkey oldval key val | ! Underneath is start\r
- oldkey 1+ key =\r
+ oldkey 1 + key =\r
oldval val = and\r
[ oldkey 2array oldval 2array , key ] unless\r
key val\r
: something ( array -- num )
{
- { [ dup 1+ 2array ] [ 3 * ] }
+ { [ dup 1 + 2array ] [ 3 * ] }
{ [ 3array ] [ + + ] }
} switch ;
[ ] [ [ <funny-tuple> ] [undo] drop ] unit-test
-[ 0 ] [ { 1 2 } [ [ 1+ 2 ] { } output>sequence ] undo ] unit-test
-[ { 0 1 } ] [ 1 2 [ [ [ 1+ ] bi@ ] input<sequence ] undo ] unit-test
+[ 0 ] [ { 1 2 } [ [ 1 + 2 ] { } output>sequence ] undo ] unit-test
+[ { 0 1 } ] [ 1 2 [ [ [ 1 + ] bi@ ] input<sequence ] undo ] unit-test
! Copyright (C) 2007, 2009 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel words summary slots quotations
+USING: accessors kernel locals words summary slots quotations
sequences assocs math arrays stack-checker effects
continuations debugger classes.tuple namespaces make vectors
bit-arrays byte-arrays strings sbufs math.functions macros
\ output>sequence 2 [ [undo] '[ dup _ assure-same-class _ input<sequence ] ] define-pop-inverse
\ input<sequence 1 [ [undo] '[ _ { } output>sequence ] ] define-pop-inverse
+! conditionals
+
+:: undo-if-empty ( result a b -- seq )
+ a call( -- b ) result = [ { } ] [ result b [undo] call( a -- b ) ] if ;
+
+:: undo-if* ( result a b -- boolean )
+ b call( -- b ) result = [ f ] [ result a [undo] call( a -- b ) ] if ;
+
+\ if-empty 2 [ swap [ undo-if-empty ] 2curry ] define-pop-inverse
+
+\ if* 2 [ swap [ undo-if* ] 2curry ] define-pop-inverse
+
! Constructor inverse
: deconstruct-pred ( class -- quot )
"predicate" word-prop [ dupd call assure ] curry ;
max-events epoll_create dup io-error >>fd
max-events "epoll-event" <struct-array> >>events ;
-M: epoll-mx dispose fd>> close-file ;
+M: epoll-mx dispose* fd>> close-file ;
: make-event ( fd events -- event )
"epoll-event" <c-object>
kqueue dup io-error >>fd
max-events "kevent" <struct-array> >>events ;
-M: kqueue-mx dispose fd>> close-file ;
+M: kqueue-mx dispose* fd>> close-file ;
: make-kevent ( fd filter flags -- event )
"kevent" <c-object>
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors assocs sequences threads ;
+USING: kernel accessors assocs sequences threads destructors ;
IN: io.backend.unix.multiplexers
-TUPLE: mx fd reads writes ;
+TUPLE: mx < disposable fd reads writes ;
: new-mx ( class -- obj )
- new
+ new-disposable
H{ } clone >>reads
H{ } clone >>writes ; inline
dup assoc-empty? [ drop 0 ] [ keys supremum ] if ;
: num-fds ( mx -- n )
- [ reads>> max-fd ] [ writes>> max-fd ] bi max 1+ ;
+ [ reads>> max-fd ] [ writes>> max-fd ] bi max 1 + ;
: init-fdsets ( mx -- nfds read write except )
[ num-fds ]
kernel.private math io.ports sequences strings sbufs threads
unix vectors io.buffers io.backend io.encodings math.parser
continuations system libc namespaces make io.timeouts
-io.encodings.utf8 destructors accessors summary combinators
-locals unix.time fry io.backend.unix.multiplexers ;
+io.encodings.utf8 destructors destructors.private accessors
+summary combinators locals unix.time fry
+io.backend.unix.multiplexers ;
QUALIFIED: io
IN: io.backend.unix
GENERIC: handle-fd ( handle -- fd )
-TUPLE: fd fd disposed ;
+TUPLE: fd < disposable fd ;
: init-fd ( fd -- fd )
[
#! since on OS X 10.3, this operation fails from init-io
#! when running the Factor.app (presumably because fd 0 and
#! 1 are closed).
- f fd boa ;
+ fd new-disposable swap >>fd ;
M: fd dispose
dup disposed>> [ drop ] [
- [ cancel-operation ]
- [ t >>disposed drop ]
- [ fd>> close-file ]
- tri
+ {
+ [ cancel-operation ]
+ [ t >>disposed drop ]
+ [ unregister-disposable ]
+ [ fd>> close-file ]
+ } cleave
] if ;
M: fd handle-fd dup check-disposed fd>> ;
! pipe to non-blocking, and read from it instead of the real
! stdin. Very crufty, but it will suffice until we get native
! threading support at the language level.
-TUPLE: stdin control size data disposed ;
+TUPLE: stdin < disposable control size data ;
M: stdin dispose*
[
: data-read-fd ( -- fd ) &: stdin_read *uint ;
: <stdin> ( -- stdin )
- stdin new
+ stdin new-disposable
control-write-fd <fd> <output-port> >>control
size-read-fd <fd> init-fd <input-port> >>size
data-read-fd <fd> >>data ;
-IN: io.backend.windows.privileges.tests\r
USING: io.backend.windows.privileges tools.test ;\r
+IN: io.backend.windows.privileges.tests\r
\r
[ [ ] with-privileges ] must-infer\r
io.buffers io.files io.ports io.binary io.timeouts system
strings kernel math namespaces sequences windows.errors
windows.kernel32 windows.shell32 windows.types windows.winsock
-splitting continuations math.bitwise accessors ;
+splitting continuations math.bitwise accessors init sets assocs ;
IN: io.backend.windows
+TUPLE: win32-handle < disposable handle ;
+
: set-inherit ( handle ? -- )
- [ HANDLE_FLAG_INHERIT ] dip
+ [ handle>> HANDLE_FLAG_INHERIT ] dip
>BOOLEAN SetHandleInformation win32-error=0/f ;
-TUPLE: win32-handle handle disposed ;
-
: new-win32-handle ( handle class -- win32-handle )
- new swap [ >>handle ] [ f set-inherit ] bi ;
+ new-disposable swap >>handle
+ dup f set-inherit ;
: <win32-handle> ( handle -- win32-handle )
win32-handle new-win32-handle ;
M: win32-handle dispose* ( handle -- )
- handle>> CloseHandle drop ;
+ handle>> CloseHandle win32-error=0/f ;
TUPLE: win32-file < win32-handle ptr ;
<win32-file> |dispose
dup add-completion ;
-: share-mode ( -- fixnum )
+: share-mode ( -- n )
{
FILE_SHARE_READ
FILE_SHARE_WRITE
M: unix >directory-entry ( byte-array -- directory-entry )
{
- [ dirent-d_name utf8 alien>string ]
+ [ dirent-d_name underlying>> utf8 alien>string ]
[ dirent-d_type dirent-type>file-type ]
} cleave directory-entry boa ;
<PRIVATE
: encode-if< ( char stream encoding max -- )
- nip 1- pick < [ encode-error ] [ stream-write1 ] if ; inline
+ nip 1 - pick < [ encode-error ] [ stream-write1 ] if ; inline
: decode-if< ( stream encoding max -- character )
nip swap stream-read1 dup
SINGLETON: ascii
M: ascii encode-char
- 128 encode-if< ;
+ 128 encode-if< ; inline
M: ascii decode-char
- 128 decode-if< ;
\ No newline at end of file
+ 128 decode-if< ; inline
IN: io.files.info.windows
:: round-up-to ( n multiple -- n' )
- n multiple rem dup 0 = [
- drop n
+ n multiple rem [
+ n
] [
multiple swap - n +
- ] if ;
+ ] if-zero ;
TUPLE: windows-file-info < file-info attributes ;
file-info ;
: volume-information ( normalized-path -- volume-name volume-serial max-component flags type )
- MAX_PATH 1+ [ <byte-array> ] keep
+ MAX_PATH 1 + [ <byte-array> ] keep
"DWORD" <c-object>
"DWORD" <c-object>
"DWORD" <c-object>
- MAX_PATH 1+ [ <byte-array> ] keep
+ MAX_PATH 1 + [ <byte-array> ] keep
[ GetVolumeInformation win32-error=0/f ] 7 nkeep
drop 5 nrot drop
[ utf16n alien>string ] 4 ndip
] if ;
: find-first-volume ( -- string handle )
- MAX_PATH 1+ [ <byte-array> ] keep
+ MAX_PATH 1 + [ <byte-array> ] keep
dupd
FindFirstVolume dup win32-error=0/f
[ utf16n alien>string ] dip ;
: find-next-volume ( handle -- string/f )
- MAX_PATH 1+ [ <byte-array> tuck ] keep
+ MAX_PATH 1 + [ <byte-array> tuck ] keep
FindNextVolume 0 = [
GetLastError ERROR_NO_MORE_FILES =
[ drop f ] [ win32-error-string throw ] if
: (follow-links) ( n path -- path' )
over 0 = [ symlink-depth get too-many-symlinks ] when
dup link-info type>> +symbolic-link+ =
- [ [ 1- ] [ follow-link ] bi* (follow-links) ]
+ [ [ 1 - ] [ follow-link ] bi* (follow-links) ]
[ nip ] if ; inline recursive
PRIVATE>
IN: io.files.links.unix.tests
: make-test-links ( n path -- )
- [ '[ [ 1+ ] keep [ number>string _ prepend ] bi@ make-link ] each ]
+ [ '[ [ 1 + ] keep [ number>string _ prepend ] bi@ make-link ] each ]
[ [ number>string ] dip prepend touch-file ] 2bi ; inline
[ t ] [
GetLastError ERROR_ALREADY_EXISTS = not ;
: set-file-pointer ( handle length method -- )
- [ dupd d>w/w <uint> ] dip SetFilePointer
- INVALID_SET_FILE_POINTER = [
- CloseHandle "SetFilePointer failed" throw
- ] when drop ;
+ [ [ handle>> ] dip d>w/w <uint> ] dip SetFilePointer
+ INVALID_SET_FILE_POINTER = [ "SetFilePointer failed" throw ] when ;
HOOK: open-append os ( path -- win32-file )
{ [ os winnt? ] [ "io.launcher.windows.nt" require ] }
[ ]
} cond
-
-: run-desc ( desc -- result ) ascii <process-reader> f swap stream-read-until drop ;
"append-test" temp-file ascii file-contents
] unit-test
+[ "( scratchpad ) " ] [
+ console-vm "-run=listener" 2array
+ ascii [ "USE: system 0 exit" print flush readln ] with-process-stream
+] unit-test
+
+[ ] [
+ console-vm "-run=listener" 2array
+ ascii [ "USE: system 0 exit" print ] with-process-writer
+] unit-test
+[ ] [
+ <process>
+ console-vm "-run=listener" 2array >>command
+ "vocab:io/launcher/windows/nt/test/input.txt" >>stdin
+ try-process
+] unit-test
: duplicate-handle ( handle -- handle' )
GetCurrentProcess ! source process
- swap ! handle
+ swap handle>> ! handle
GetCurrentProcess ! target process
f <void*> [ ! target handle
DUPLICATE_SAME_ACCESS ! desired access
TRUE ! inherit handle
- DUPLICATE_CLOSE_SOURCE ! options
+ 0 ! options
DuplicateHandle win32-error=0/f
- ] keep *void* ;
+ ] keep *void* <win32-handle> &dispose ;
! /dev/null simulation
: null-input ( -- pipe )
- (pipe) [ in>> handle>> ] [ out>> dispose ] bi ;
+ (pipe) [ in>> &dispose ] [ out>> dispose ] bi ;
: null-output ( -- pipe )
- (pipe) [ in>> dispose ] [ out>> handle>> ] bi ;
+ (pipe) [ in>> dispose ] [ out>> &dispose ] bi ;
: null-pipe ( mode -- pipe )
{
create-mode
FILE_ATTRIBUTE_NORMAL ! flags and attributes
f ! template file
- CreateFile dup invalid-handle? <win32-file> &dispose handle>> ;
+ CreateFile dup invalid-handle? <win32-file> &dispose ;
: redirect-append ( path access-mode create-mode -- handle )
[ path>> ] 2dip
dup 0 FILE_END set-file-pointer ;
: redirect-handle ( handle access-mode create-mode -- handle )
- 2drop handle>> duplicate-handle ;
+ 2drop ;
: redirect-stream ( stream access-mode create-mode -- handle )
- [ underlying-handle handle>> ] 2dip redirect-handle ;
+ [ underlying-handle ] 2dip redirect-handle ;
: redirect ( obj access-mode create-mode -- handle )
{
{ [ pick win32-file? ] [ redirect-handle ] }
[ redirect-stream ]
} cond
- dup [ dup t set-inherit ] when ;
+ dup [ dup t set-inherit handle>> ] when ;
: redirect-stdout ( process args -- handle )
drop
--- /dev/null
+USE: system 0 exit\r
: count-trailing-backslashes ( str n -- str n )
[ "\\" ?tail ] dip swap [
- 1+ count-trailing-backslashes
+ 1 + count-trailing-backslashes
] when ;
: fix-trailing-backslashes ( str -- str' )
math ;
IN: io.mmap
-TUPLE: mapped-file address handle length disposed ;
+TUPLE: mapped-file < disposable address handle length ;
HOOK: (mapped-file-reader) os ( path length -- address handle )
HOOK: (mapped-file-r/w) os ( path length -- address handle )
-ERROR: bad-mmap-size path size ;
+ERROR: bad-mmap-size n ;
<PRIVATE
-: prepare-mapped-file ( path -- path' n )
- [ normalize-path ] [ file-info size>> ] bi
- dup 0 <= [ bad-mmap-size ] when ;
+: prepare-mapped-file ( path quot -- mapped-file path' length )
+ [
+ [ normalize-path ] [ file-info size>> ] bi
+ [ dup 0 <= [ bad-mmap-size ] [ 2drop ] if ]
+ [ nip mapped-file new-disposable swap >>length ]
+ ] dip 2tri [ >>address ] [ >>handle ] bi* ; inline
PRIVATE>
: <mapped-file-reader> ( path -- mmap )
- prepare-mapped-file
- [ (mapped-file-reader) ] keep
- f mapped-file boa ;
+ [ (mapped-file-reader) ] prepare-mapped-file ;
: <mapped-file> ( path -- mmap )
- prepare-mapped-file
- [ (mapped-file-r/w) ] keep
- f mapped-file boa ;
+ [ (mapped-file-r/w) ] prepare-mapped-file ;
HOOK: close-mapped-file io-backend ( mmap -- )
SYMBOL: inotify
-TUPLE: linux-monitor < monitor wd inotify watches disposed ;
+TUPLE: linux-monitor < monitor wd inotify watches ;
: <linux-monitor> ( wd path mailbox -- monitor )
linux-monitor new-monitor
path 1array 0 0 <event-stream> >>handle
] ;
-M: macosx-monitor dispose
- handle>> dispose ;
+M: macosx-monitor dispose* handle>> dispose ;
macosx set-io-backend
[ dispose-monitors ] [ ] cleanup
] with-scope ; inline
-TUPLE: monitor < identity-tuple path queue timeout ;
-
-M: monitor hashcode* path>> hashcode* ;
+TUPLE: monitor < disposable path queue timeout ;
M: monitor timeout timeout>> ;
M: monitor set-timeout (>>timeout) ;
: new-monitor ( path mailbox class -- monitor )
- new
+ new-disposable
swap >>queue
swap >>path ; inline
TUPLE: dummy-monitor < monitor ;
M: dummy-monitor dispose
- drop dummy-monitor-disposed get [ 1+ ] change-i drop ;
+ drop dummy-monitor-disposed get [ 1 + ] change-i drop ;
M: mock-io-backend (monitor)
nip
over exists? [
dummy-monitor new-monitor
- dummy-monitor-created get [ 1+ ] change-i drop
+ dummy-monitor-created get [ 1 + ] change-i drop
] [
"Does not exist" throw
] if ;
! Simulate recursive monitors on platforms that don't have them
-TUPLE: recursive-monitor < monitor children thread ready disposed ;
+TUPLE: recursive-monitor < monitor children thread ready ;
: notify? ( -- ? ) monitor tget ready>> promise-fulfilled? ;
PRIVATE>
: run-pipeline ( seq -- results )
- [ length dup zero? [ drop { } ] [ 1- <pipes> ] if ] keep
+ [ length dup zero? [ drop { } ] [ 1 - <pipes> ] if ] keep
[
[ [ first in>> ] [ second out>> ] bi ] dip
run-pipeline-element
SYMBOL: default-buffer-size
64 1024 * default-buffer-size set-global
-TUPLE: port handle timeout disposed ;
+TUPLE: port < disposable handle timeout ;
M: port timeout timeout>> ;
M: port set-timeout (>>timeout) ;
: <port> ( handle class -- port )
- new swap >>handle ; inline
+ new-disposable swap >>handle ; inline
TUPLE: buffered-port < port { buffer buffer } ;
TUPLE: threaded-server
name
log-level
-secure insecure
+secure
+insecure
secure-config
sockets
max-connections
: new-threaded-server ( encoding class -- threaded-server )
new
- swap >>encoding
"server" >>name
DEBUG >>log-level
- 1 minutes >>timeout
- V{ } clone >>sockets
<secure-config> >>secure-config
+ V{ } clone >>sockets
+ 1 minutes >>timeout
[ "No handler quotation" throw ] >>handler
- <flag> >>ready ; inline
+ <flag> >>ready
+ swap >>encoding ;
: <threaded-server> ( encoding -- threaded-server )
threaded-server new-threaded-server ;
password [ B{ 0 } password! ] unless
[let | len [ password strlen ] |
- buf password len 1+ size min memcpy
+ buf password len 1 + size min memcpy
len
]
] alien-callback ;
SSL_CTX_set_verify_depth
] [ drop ] if ;
-TUPLE: bio handle disposed ;
+TUPLE: bio < disposable handle ;
-: <bio> ( handle -- bio ) f bio boa ;
+: <bio> ( handle -- bio ) bio new-disposable swap >>handle ;
M: bio dispose* handle>> BIO_free ssl-error ;
SSL_CTX_set_tmp_dh ssl-error
] [ drop ] if ;
-TUPLE: rsa handle disposed ;
+TUPLE: rsa < disposable handle ;
-: <rsa> ( handle -- rsa ) f rsa boa ;
+: <rsa> ( handle -- rsa ) rsa new-disposable swap >>handle ;
M: rsa dispose* handle>> RSA_free ;
SSL_CTX_set_tmp_rsa ssl-error ;
: <openssl-context> ( config ctx -- context )
- openssl-context new
+ openssl-context new-disposable
swap >>handle
swap >>config
V{ } clone >>aliens
[ handle>> SSL_CTX_free ]
tri ;
-TUPLE: ssl-handle file handle connected disposed ;
+TUPLE: ssl-handle < disposable file handle connected ;
SYMBOL: default-secure-context
] unless* ;
: <ssl-handle> ( fd -- ssl )
- current-secure-context handle>> SSL_new dup ssl-error
- f f ssl-handle boa ;
+ ssl-handle new-disposable
+ current-secure-context handle>> SSL_new
+ dup ssl-error >>handle
+ swap >>file ;
M: ssl-handle dispose*
[ handle>> SSL_free ] [ file>> dispose ] bi ;
"vocab:openssl/cacert.pem" >>ca-file
t >>verify ;
-TUPLE: secure-context config handle disposed ;
+TUPLE: secure-context < disposable config handle ;
HOOK: <secure-context> secure-socket-backend ( config -- context )
! See what happens if other end is closed
[ ] [ <promise> "port" set ] unit-test
+[ ] [ "datagram3" get dispose ] unit-test
+
[ ] [
[
"127.0.0.1" 0 <inet4> utf8 <server>
[ "hello" f ] [
"port" get ?promise utf8 [
+ 1 seconds input-stream get set-timeout
+ 1 seconds output-stream get set-timeout
"hi\n" write flush readln readln
] with-client
] unit-test
<byte-array> glue ;
: inet6-bytes ( seq -- bytes )
- [ 2 >be ] { } map-as concat >byte-array ;
+ [ 2 >be ] { } map-as B{ } concat-as ;
PRIVATE>
[ handle-fd ] 2dip 1 <int> "int" heap-size setsockopt io-error ;
M: unix addrinfo-error ( n -- )
- dup zero? [ drop ] [ gai_strerror throw ] if ;
+ [ gai_strerror throw ] unless-zero ;
! Client sockets - TCP and Unix domain
M: object (get-local-address) ( handle remote -- sockaddr )
! Test duplex stream close behavior
TUPLE: closing-stream < disposable ;
-: <closing-stream> ( -- stream ) closing-stream new ;
+: <closing-stream> ( -- stream ) closing-stream new-disposable ;
M: closing-stream dispose* drop ;
M: limited-stream stream-read-until
swap BV{ } clone (read-until) [ 2nip B{ } like ] dip ;
+M: limited-stream stream-seek
+ stream>> stream-seek ;
+
M: limited-stream dispose
stream>> dispose ;
USING: alien.syntax alien.c-types core-foundation
core-foundation.bundles core-foundation.dictionaries system
-combinators kernel sequences debugger io accessors ;
+combinators kernel sequences io accessors ;
IN: iokit
<<
FUNCTION: char* mach_error_string ( IOReturn error ) ;
-TUPLE: mach-error error-code ;
-C: <mach-error> mach-error
-
-M: mach-error error.
- "IOKit call failed: " print error-code>> mach_error_string print ;
+TUPLE: mach-error error-code error-string ;
+: <mach-error> ( code -- error )
+ dup mach_error_string \ mach-error boa ;
: mach-error ( return -- )
dup KERN_SUCCESS = [ drop ] [ <mach-error> throw ] if ;
Chris Double
+Peter Burns
+Philipp Winkler
{ 10.25 } [ "1025e-2" json> ] unit-test
{ 0.125 } [ "0.125" json> ] unit-test
{ -0.125 } [ "-0.125" json> ] unit-test
+{ -0.00125 } [ "-0.125e-2" json> ] unit-test
+{ -012.5 } [ "-0.125e+2" json> ] unit-test
! not widely supported by javascript, but allowed in the grammar, and a nice
! feature to get
{ 8 9 10 12 13 34 47 92 } >string 1array [ <" "\b\t\n\f\r\"\/\\" "> json> ] unit-test
{ HEX: abcd } >string 1array [ <" "\uaBCd" "> json> ] unit-test
+{ H{ { "a" { } } { "b" 123 } } } [ "{\"a\":[],\"b\":123}" json> ] unit-test
{ { } } [ "[]" json> ] unit-test
{ { 1 "two" 3.0 } } [ <" [1, "two", 3.0] "> json> ] unit-test
{ H{ } } [ "{}" json> ] unit-test
-! Copyright (C) 2008 Peter Burns.
+! Copyright (C) 2008 Peter Burns, 2009 Philipp Winkler
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel peg peg.ebnf math.parser math.parser.private strings math
-math.functions sequences arrays vectors hashtables assocs
-prettyprint json ;
+USING: arrays assocs combinators io io.streams.string json
+kernel math math.parser math.parser.private prettyprint
+sequences strings vectors ;
IN: json.reader
<PRIVATE
+: value ( char -- num char )
+ 1string " \t\r\n,:}]" read-until
+ [
+ append
+ [ string>float ]
+ [ [ "eE." index ] any? [ >integer ] unless ] bi
+ ] dip ;
-: grammar-list>vector ( seq -- vec ) first2 values swap prefix ;
+DEFER: j-string
+
+: convert-string ( str -- str )
+ read1
+ {
+ { CHAR: b [ 8 ] }
+ { CHAR: f [ 12 ] }
+ { CHAR: n [ CHAR: \n ] }
+ { CHAR: r [ CHAR: \r ] }
+ { CHAR: t [ CHAR: \t ] }
+ { CHAR: u [ 4 read hex> ] }
+ [ ]
+ } case
+ dup
+ [ 1string append j-string append ]
+ [ drop ] if ;
+
+: j-string ( -- str )
+ "\\\"" read-until CHAR: \" =
+ [ convert-string ] unless ;
+
+: second-last ( seq -- second-last )
+ [ length 2 - ] keep nth ; inline
-! Grammar for JSON from RFC 4627
-EBNF: (json>)
+: third-last ( seq -- third-last )
+ [ length 3 - ] keep nth ; inline
+
+: last2 ( seq -- second-last last )
+ [ second-last ] [ last ] bi ; inline
-ws = (" " | "\r" | "\t" | "\n")*
+: last3 ( seq -- third-last second-last last )
+ [ third-last ] [ last2 ] bi ; inline
-true = "true" => [[ t ]]
-false = "false" => [[ f ]]
-null = "null" => [[ json-null ]]
+: v-over-push ( vec -- vec' )
+ dup length 2 >=
+ [
+ dup
+ [ pop ]
+ [ last ] bi push
+ ] when ;
-hex = [0-9a-fA-F]
-char = '\\"' [[ CHAR: " ]]
- | "\\\\" [[ CHAR: \ ]]
- | "\\/" [[ CHAR: / ]]
- | "\\b" [[ 8 ]]
- | "\\f" [[ 12 ]]
- | "\\n" [[ CHAR: \n ]]
- | "\\r" [[ CHAR: \r ]]
- | "\\t" [[ CHAR: \t ]]
- | "\\u" (hex hex hex hex) [[ hex> ]] => [[ second ]]
- | [^"\]
-string = '"' char*:cs '"' => [[ cs >string ]]
+: v-pick-push ( vec -- vec' )
+ dup length 3 >=
+ [
+ dup
+ [ pop ]
+ [ second-last ] bi push
+ ] when ;
-sign = ("-" | "+")? => [[ "-" = "-" "" ? ]]
-digits = [0-9]+ => [[ >string ]]
-decimal = "." digits => [[ concat ]]
-exp = ("e" | "E") sign digits => [[ concat ]]
-number = sign digits decimal? exp? => [[ dup concat swap fourth [ string>float ] [ string>number ] if ]]
+: (close-array) ( accum -- accum' )
+ dup last vector? [ v-over-push ] unless
+ dup pop >array over push ;
-elements = value ("," value)* => [[ grammar-list>vector ]]
-array = "[" elements?:arr "]" => [[ arr >array ]]
-
-pair = ws string:key ws ":" value:val => [[ { key val } ]]
-members = pair ("," pair)* => [[ grammar-list>vector ]]
-object = "{" members?:hash "}" => [[ hash >hashtable ]]
-
-val = true
- | false
- | null
- | string
- | number
- | array
- | object
-
-value = ws val:v ws => [[ v ]]
-
-;EBNF
+: (close-hash) ( accum -- accum' )
+ dup length 3 >= [ v-over-push ] when
+ dup dup [ pop ] dip pop swap
+ zip H{ } assoc-clone-like over push ;
+
+: scan ( accum char -- accum )
+ ! 2dup . . ! Great for debug...
+ [
+ {
+ { CHAR: \" [ j-string over push ] }
+ { CHAR: [ [ V{ } clone over push ] }
+ { CHAR: , [ v-over-push ] }
+ { CHAR: ] [ (close-array) ] }
+ { CHAR: { [ 2 [ V{ } clone over push ] times ] }
+ { CHAR: : [ v-pick-push ] }
+ { CHAR: } [ (close-hash) ] }
+ { CHAR: \u000020 [ ] }
+ { CHAR: \t [ ] }
+ { CHAR: \r [ ] }
+ { CHAR: \n [ ] }
+ { CHAR: t [ 3 read drop t over push ] }
+ { CHAR: f [ 4 read drop f over push ] }
+ { CHAR: n [ 3 read drop json-null over push ] }
+ [ value [ over push ] dip [ scan ] when* ]
+ } case
+ ] when* ;
+: (json-parser>) ( string -- object )
+ [ V{ } clone [ read1 dup ] [ scan ] while drop first ] with-string-reader ;
+
PRIVATE>
-
-: json> ( string -- object ) (json>) ;
\ No newline at end of file
+
+: json> ( string -- object )
+ (json-parser>) ;
\ No newline at end of file
\r
<PRIVATE\r
: levenshtein-step ( insert delete change same? -- next )\r
- 0 1 ? + [ [ 1+ ] bi@ ] dip min min ;\r
+ 0 1 ? + [ [ 1 + ] bi@ ] dip min min ;\r
\r
: lcs-step ( insert delete change same? -- next )\r
1 -1/0. ? + max max ; ! -1/0. is -inf (float)\r
\r
:: loop-step ( i j matrix old new step -- )\r
- i j 1+ matrix nth nth ! insertion\r
- i 1+ j matrix nth nth ! deletion\r
+ i j 1 + matrix nth nth ! insertion\r
+ i 1 + j matrix nth nth ! deletion\r
i j matrix nth nth ! replace/retain\r
i old nth j new nth = ! same?\r
step call\r
- i 1+ j 1+ matrix nth set-nth ; inline\r
+ i 1 + j 1 + matrix nth set-nth ; inline\r
\r
: lcs-initialize ( |str1| |str2| -- matrix )\r
[ drop 0 <array> ] with map ;\r
[ [ + ] curry map ] with map ;\r
\r
:: run-lcs ( old new init step -- matrix )\r
- [let | matrix [ old length 1+ new length 1+ init call ] |\r
+ [let | matrix [ old length 1 + new length 1 + init call ] |\r
old length [| i |\r
new length\r
[| j | i j matrix old new step loop-step ] each\r
TUPLE: trace-state old new table i j ;\r
\r
: old-nth ( state -- elt )\r
- [ i>> 1- ] [ old>> ] bi nth ;\r
+ [ i>> 1 - ] [ old>> ] bi nth ;\r
\r
: new-nth ( state -- elt )\r
- [ j>> 1- ] [ new>> ] bi nth ;\r
+ [ j>> 1 - ] [ new>> ] bi nth ;\r
\r
: top-beats-side? ( state -- ? )\r
- [ [ i>> ] [ j>> 1- ] [ table>> ] tri nth nth ]\r
- [ [ i>> 1- ] [ j>> ] [ table>> ] tri nth nth ] bi > ;\r
+ [ [ i>> ] [ j>> 1 - ] [ table>> ] tri nth nth ]\r
+ [ [ i>> 1 - ] [ j>> ] [ table>> ] tri nth nth ] bi > ;\r
\r
: retained? ( state -- ? )\r
{\r
\r
: do-retain ( state -- state )\r
dup old-nth retain boa ,\r
- [ 1- ] change-i [ 1- ] change-j ;\r
+ [ 1 - ] change-i [ 1 - ] change-j ;\r
\r
: inserted? ( state -- ? )\r
{\r
} 1&& ;\r
\r
: do-insert ( state -- state )\r
- dup new-nth insert boa , [ 1- ] change-j ;\r
+ dup new-nth insert boa , [ 1 - ] change-j ;\r
\r
: deleted? ( state -- ? )\r
{\r
} 1&& ;\r
\r
: do-delete ( state -- state )\r
- dup old-nth delete boa , [ 1- ] change-i ;\r
+ dup old-nth delete boa , [ 1 - ] change-i ;\r
\r
: (trace-diff) ( state -- )\r
{\r
} cond ;\r
\r
: trace-diff ( old new table -- diff )\r
- [ ] [ first length 1- ] [ length 1- ] tri trace-state boa\r
+ [ ] [ first length 1 - ] [ length 1 - ] tri trace-state boa\r
[ (trace-diff) ] { } make reverse ;\r
PRIVATE>\r
\r
\r
100 malloc "block" set\r
\r
-[ t ] [ "block" get mallocs key? ] unit-test\r
+[ t ] [ "block" get malloc-exists? ] unit-test\r
\r
[ ] [ [ "block" get &free drop ] with-destructors ] unit-test\r
\r
-[ f ] [ "block" get mallocs key? ] unit-test\r
+[ f ] [ "block" get malloc-exists? ] unit-test\r
! Copyright (C) 2007, 2008 Doug Coleman
! See http://factorcode.org/license.txt for BSD license.
USING: alien assocs continuations alien.destructors kernel
-namespaces accessors sets summary ;
+namespaces accessors sets summary destructors destructors.private ;
IN: libc
: errno ( -- int )
: (realloc) ( alien size -- newalien )
"void*" "libc" "realloc" { "void*" "ulong" } alien-invoke ;
-: mallocs ( -- assoc )
- \ mallocs [ H{ } clone ] initialize-alien ;
+! We stick malloc-ptr instances in the global disposables set
+TUPLE: malloc-ptr value continuation ;
+
+M: malloc-ptr hashcode* value>> hashcode* ;
+
+M: malloc-ptr equal?
+ over malloc-ptr? [ [ value>> ] bi@ = ] [ 2drop f ] if ;
+
+: <malloc-ptr> ( value -- malloc-ptr )
+ malloc-ptr new swap >>value ;
PRIVATE>
: check-ptr ( c-ptr -- c-ptr )
[ bad-ptr ] unless* ;
-ERROR: double-free ;
-
-M: double-free summary
- drop "Free failed since memory is not allocated" ;
-
ERROR: realloc-error ptr size ;
M: realloc-error summary
<PRIVATE
: add-malloc ( alien -- alien )
- dup mallocs conjoin ;
+ dup <malloc-ptr> register-disposable ;
: delete-malloc ( alien -- )
- [
- mallocs delete-at*
- [ drop ] [ double-free ] if
- ] when* ;
+ [ <malloc-ptr> unregister-disposable ] when* ;
: malloc-exists? ( alien -- ? )
- mallocs key? ;
+ <malloc-ptr> disposables get key? ;
PRIVATE>
: memcpy ( dst src size -- )
"void" "libc" "memcpy" { "void*" "void*" "ulong" } alien-invoke ;
+: memcmp ( a b size -- cmp )
+ "int" "libc" "memcmp" { "void*" "void*" "ulong" } alien-invoke ;
+
+: memory= ( a b size -- ? )
+ memcmp 0 = ;
+
: strlen ( alien -- len )
"size_t" "libc" "strlen" { "char*" } alien-invoke ;
{ 9 } [
<linked-hash>
- { [ 3 * ] [ 1- ] } "first" pick set-at
- { [ [ 1- ] bi@ ] [ 2 / ] } "second" pick set-at
+ { [ 3 * ] [ 1 - ] } "first" pick set-at
+ { [ [ 1 - ] bi@ ] [ 2 / ] } "second" pick set-at
4 6 pick values [ first call ] each
+ swap values <reversed> [ second call ] each
] unit-test
2 "by" pick set-at
3 "cx" pick set-at
>alist
-] unit-test
\ No newline at end of file
+] unit-test
"Hiding all visible variables:"
{ $subsection hide-all-vars } ;
+HELP: only-use-vocabs
+{ $values { "vocabs" "a sequence of vocabulary specifiers" } }
+{ $description "Replaces the current manifest's vocabulary search path with the given set of vocabularies." } ;
+
HELP: show-var
{ $values { "var" "a variable name" } }
{ $description "Adds a variable to the watch list; its value will be printed by the listener after every expression." } ;
namespaces parser lexer sequences strings io.styles
vectors words generic system combinators continuations debugger
definitions compiler.units accessors colors prettyprint fry
-sets vocabs.parser source-files.errors locals ;
+sets vocabs.parser source-files.errors locals vocabs vocabs.loader ;
IN: listener
GENERIC: stream-read-quot ( stream -- quot/f )
PRIVATE>
+SYMBOL: interactive-vocabs
+
+{
+ "accessors"
+ "arrays"
+ "assocs"
+ "combinators"
+ "compiler"
+ "compiler.errors"
+ "compiler.units"
+ "continuations"
+ "debugger"
+ "definitions"
+ "editors"
+ "help"
+ "help.apropos"
+ "help.lint"
+ "help.vocabs"
+ "inspector"
+ "io"
+ "io.files"
+ "io.pathnames"
+ "kernel"
+ "listener"
+ "math"
+ "math.order"
+ "memory"
+ "namespaces"
+ "parser"
+ "prettyprint"
+ "see"
+ "sequences"
+ "slicing"
+ "sorting"
+ "stack-checker"
+ "strings"
+ "syntax"
+ "tools.annotations"
+ "tools.crossref"
+ "tools.destructors"
+ "tools.disassembler"
+ "tools.errors"
+ "tools.memory"
+ "tools.profiler"
+ "tools.test"
+ "tools.threads"
+ "tools.time"
+ "vocabs"
+ "vocabs.loader"
+ "vocabs.refresh"
+ "vocabs.hierarchy"
+ "words"
+ "scratchpad"
+} interactive-vocabs set-global
+
+: only-use-vocabs ( vocabs -- )
+ clear-manifest
+ [ vocab ] filter
+ [
+ vocab
+ [ find-vocab-root not ]
+ [ source-loaded?>> +done+ eq? ] bi or
+ ] filter
+ [ use-vocab ] each ;
+
+: with-interactive-vocabs ( quot -- )
+ [
+ <manifest> manifest set
+ "scratchpad" set-current-vocab
+ interactive-vocabs get only-use-vocabs
+ call
+ ] with-scope ; inline
+
: listener ( -- )
[ [ { } (listener) ] with-interactive-vocabs ] with-return ;
cons>> car ;
M: lazy-take cdr ( lazy-take -- cdr )
- [ n>> 1- ] keep
+ [ n>> 1 - ] keep
cons>> cdr ltake ;
M: lazy-take nil? ( lazy-take -- ? )
C: lfrom-by lazy-from-by
: lfrom ( n -- list )
- [ 1+ ] lfrom-by ;
+ [ 1 + ] lfrom-by ;
M: lazy-from-by car ( lazy-from-by -- car )
n>> ;
[ index>> ] [ seq>> nth ] bi ;
M: sequence-cons cdr ( sequence-cons -- cdr )
- [ index>> 1+ ] [ seq>> sequence-tail>list ] bi ;
+ [ index>> 1 + ] [ seq>> sequence-tail>list ] bi ;
M: sequence-cons nil? ( sequence-cons -- ? )
drop f ;
] unit-test
{ T{ cons f 2 T{ cons f 3 T{ cons f 4 T{ cons f 5 +nil+ } } } } } [
- { 1 2 3 4 } sequence>list [ 1+ ] lmap
+ { 1 2 3 4 } sequence>list [ 1 + ] lmap
] unit-test
{ 15 } [
] if ; inline recursive
: llength ( list -- n )
- 0 [ drop 1+ ] foldl ;
+ 0 [ drop 1 + ] foldl ;
: lreverse ( list -- newlist )
nil [ swap cons ] foldl ;
IN: scratchpad
<< CONSTANT: five 5 >>
-{ $[ five dup 1+ dup 2 + ] } .
+{ $[ five dup 1 + dup 2 + ] } .
"> "{ 5 6 8 }" }
} ;
IN: scratchpad
CONSTANT: five 5
-{ $ five $[ five dup 1+ dup 2 + ] } .
+{ $ five $[ five dup 1 + dup 2 + ] } .
"> "{ 5 5 6 8 }" }
{ $subsection POSTPONE: $ }
{ $subsection POSTPONE: $[ }
SYNTAX: $ scan-word expand-literal >vector ;
SYNTAX: $[ parse-quotation with-datastack >vector ;
SYNTAX: ${ \ } [ expand-literals ] parse-literal ;
+
+SYNTAX: $$
+ scan-word execute( accum -- accum ) dup pop [ >quotation ] keep
+ [ output>sequence ] 2curry call( -- object ) parsed ;
{ $code
":: counter ( -- )"
" [let | value! [ 0 ] |"
- " [ value 1+ dup value! ]"
- " [ value 1- dup value! ] ] ;"
+ " [ value 1 + dup value! ]"
+ " [ value 1 - dup value! ] ] ;"
}
"Mutable bindings are implemented in a manner similar to the ML language; each mutable binding is actually an immutable binding of a mutable cell (in Factor's case, a 1-element array); reading the binding automatically dereferences the array, and writing to the binding stores into the array."
$nl
[ 5 ] [ 10 xyzzy ] unit-test
:: let*-test-1 ( a -- b )
- [let* | b [ a 1+ ]
- c [ b 1+ ] |
+ [let* | b [ a 1 + ]
+ c [ b 1 + ] |
a b c 3array ] ;
[ { 1 2 3 } ] [ 1 let*-test-1 ] unit-test
:: let*-test-2 ( a -- b )
- [let* | b [ a 1+ ]
- c! [ b 1+ ] |
+ [let* | b [ a 1 + ]
+ c! [ b 1 + ] |
a b c 3array ] ;
[ { 1 2 3 } ] [ 1 let*-test-2 ] unit-test
:: let*-test-3 ( a -- b )
- [let* | b [ a 1+ ]
- c! [ b 1+ ] |
- c 1+ c! a b c 3array ] ;
+ [let* | b [ a 1 + ]
+ c! [ b 1 + ] |
+ c 1 + c! a b c 3array ] ;
[ { 1 2 4 } ] [ 1 let*-test-3 ] unit-test
[ 3 ] [ 3 [| | :> a! a ] call ] unit-test
-[ 3 ] [ 2 [| | :> a! a 1+ a! a ] call ] unit-test
+[ 3 ] [ 2 [| | :> a! a 1 + a! a ] call ] unit-test
:: wlet-&&-test ( a -- ? )
[wlet | is-integer? [ a integer? ]
over exists? [ move-file ] [ 2drop ] if ;\r
\r
: advance-log ( path n -- )\r
- [ 1- log# ] 2keep log# ?move-file ;\r
+ [ 1 - log# ] 2keep log# ?move-file ;\r
\r
: rotate-log ( service -- )\r
dup close-log\r
C: <bits> bits
: make-bits ( number -- bits )
- dup zero? [ drop T{ bits f 0 0 } ] [ dup abs log2 1 + <bits> ] if ; inline
+ [ T{ bits f 0 0 } ] [ dup abs log2 1 + <bits> ] if-zero ; inline
-M: bits length length>> ;
+M: bits length length>> ; inline
-M: bits nth-unsafe number>> swap bit? ;
+M: bits nth-unsafe number>> swap bit? ; inline
INSTANCE: bits immutable-sequence
: unbits ( seq -- number )
- <reversed> 0 [ [ 1 shift ] dip [ 1+ ] when ] reduce ;
+ <reversed> 0 [ [ 1 shift ] dip [ 1 + ] when ] reduce ;
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: help.markup help.syntax math sequences ;
+USING: assocs help.markup help.syntax math sequences ;
IN: math.bitwise
HELP: bitfield
}
} ;
+HELP: symbols>flags
+{ $values { "symbols" sequence } { "assoc" assoc } { "flag-bits" integer } }
+{ $description "Constructs an integer value by mapping the values in the " { $snippet "symbols" } " sequence to integer values using " { $snippet "assoc" } " and " { $link bitor } "ing the values together." }
+{ $examples
+ { $example "USING: math.bitwise prettyprint ui.gadgets.worlds ;"
+ "IN: scratchpad"
+ "CONSTANT: window-controls>flags H{"
+ " { close-button 1 }"
+ " { minimize-button 2 }"
+ " { maximize-button 4 }"
+ " { resize-handles 8 }"
+ " { small-title-bar 16 }"
+ " { normal-title-bar 32 }"
+ "}"
+ "{ resize-handles close-button small-title-bar } window-controls>flags symbols>flags ."
+ "25"
+ }
+} ;
+
HELP: mask
{ $values
{ "x" integer } { "n" integer }
[ 256 ] [ 1 { 8 } bitfield ] unit-test
[ 268 ] [ 3 1 { 8 2 } bitfield ] unit-test
[ 268 ] [ 1 { 8 { 3 2 } } bitfield ] unit-test
-[ 512 ] [ 1 { { 1+ 8 } } bitfield ] unit-test
+: test-1+ ( x -- y ) 1 + ;
+[ 512 ] [ 1 { { test-1+ 8 } } bitfield ] unit-test
CONSTANT: a 1
CONSTANT: b 2
! Copyright (C) 2007, 2008 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays kernel math sequences accessors math.bits
-sequences.private words namespaces macros hints
-combinators fry io.binary combinators.smart ;
+USING: arrays assocs combinators combinators.smart fry kernel
+macros math math.bits sequences sequences.private words ;
IN: math.bitwise
! utilities
MACRO: flags ( values -- )
[ 0 ] [ [ ?execute bitor ] curry compose ] reduce ;
+: symbols>flags ( symbols assoc -- flag-bits )
+ [ at ] curry map
+ 0 [ bitor ] reduce ;
+
! bitfield
<PRIVATE
: bit-count ( x -- n )
dup 0 < [ bitnot ] when (bit-count) ; inline
-! Signed byte array to integer conversion
-: signed-le> ( bytes -- x )
- [ le> ] [ length 8 * 1 - on-bits ] bi
- 2dup > [ bitnot bitor ] [ drop ] if ;
-
-: signed-be> ( bytes -- x )
- <reversed> signed-le> ;
-
: >signed ( x n -- y )
2dup neg 1 + shift 1 = [ 2^ - ] [ drop ] if ;
HELP: permutation
{ $values { "n" "a non-negative integer" } { "seq" sequence } { "seq" sequence } }
{ $description "Outputs the " { $snippet "nth" } " lexicographical permutation of " { $snippet "seq" } "." }
-{ $notes "Permutations are 0-based and a bounds error will be thrown if " { $snippet "n" } " is larger than " { $snippet "seq length factorial 1-" } "." }
+{ $notes "Permutations are 0-based and a bounds error will be thrown if " { $snippet "n" } " is larger than " { $snippet "seq length factorial 1 -" } "." }
{ $examples
{ $example "USING: math.combinatorics prettyprint ;"
"1 3 permutation ." "{ 0 2 1 }" }
parser ;
IN: math.complex.private
-M: real real-part ;
-M: real imaginary-part drop 0 ;
-M: complex real-part real>> ;
-M: complex imaginary-part imaginary>> ;
-M: complex absq >rect [ sq ] bi@ + ;
-M: complex hashcode* nip >rect [ hashcode ] bi@ bitxor ;
+M: real real-part ; inline
+M: real imaginary-part drop 0 ; inline
+M: complex real-part real>> ; inline
+M: complex imaginary-part imaginary>> ; inline
+M: complex absq >rect [ sq ] bi@ + ; inline
+M: complex hashcode* nip >rect [ hashcode ] bi@ bitxor ; inline
: componentwise ( x y quot -- a b ) [ [ >rect ] bi@ ] dip bi-curry@ bi* ; inline
: complex= ( x y quot -- ? ) componentwise and ; inline
-M: complex equal? over complex? [ [ = ] complex= ] [ 2drop f ] if ;
-M: complex number= [ number= ] complex= ;
+M: complex equal? over complex? [ [ = ] complex= ] [ 2drop f ] if ; inline
+M: complex number= [ number= ] complex= ; inline
: complex-op ( x y quot -- z ) componentwise rect> ; inline
-M: complex + [ + ] complex-op ;
-M: complex - [ - ] complex-op ;
+M: complex + [ + ] complex-op ; inline
+M: complex - [ - ] complex-op ; inline
: *re ( x y -- xr*yr xi*yi ) [ >rect ] bi@ [ * ] bi-curry@ bi* ; inline
: *im ( x y -- xi*yr xr*yi ) swap [ >rect ] bi@ swap [ * ] bi-curry@ bi* ; inline
-M: complex * [ *re - ] [ *im + ] 2bi rect> ;
+M: complex * [ *re - ] [ *im + ] 2bi rect> ; inline
: (complex/) ( x y -- r i m ) [ [ *re + ] [ *im - ] 2bi ] keep absq ; inline
: complex/ ( x y quot -- z ) [ (complex/) ] dip curry bi@ rect> ; inline
-M: complex / [ / ] complex/ ;
-M: complex /f [ /f ] complex/ ;
-M: complex /i [ /i ] complex/ ;
-M: complex abs absq >float fsqrt ;
-M: complex sqrt >polar [ fsqrt ] [ 2.0 / ] bi* polar> ;
+M: complex / [ / ] complex/ ; inline
+M: complex /f [ /f ] complex/ ; inline
+M: complex /i [ /i ] complex/ ; inline
+M: complex abs absq >float fsqrt ; inline
+M: complex sqrt >polar [ fsqrt ] [ 2.0 / ] bi* polar> ; inline
IN: syntax
"Computing additive and multiplicative inverses:"
{ $subsection neg }
{ $subsection recip }
-"Incrementing, decrementing:"
-{ $subsection 1+ }
-{ $subsection 1- }
"Minimum, maximum, clamping:"
{ $subsection min }
{ $subsection max }
"Tests:"
{ $subsection zero? }
{ $subsection between? }
+"Control flow:"
+{ $subsection if-zero }
+{ $subsection when-zero }
+{ $subsection unless-zero }
"Sign:"
{ $subsection sgn }
"Rounding:"
{ $subsection exp }
{ $subsection cis }
{ $subsection log }
+{ $subsection log10 }
"Raising a number to a power:"
{ $subsection ^ }
+{ $subsection 10^ }
"Converting between rectangular and polar form:"
{ $subsection abs }
{ $subsection absq }
{ $values { "x" number } { "y" number } }
{ $description "Natural logarithm function. Outputs negative infinity if " { $snippet "x" } " is 0." } ;
+HELP: log10
+{ $values { "x" number } { "y" number } }
+{ $description "Logarithm function base 10. Outputs negative infinity if " { $snippet "x" } " is 0." } ;
+
HELP: sqrt
{ $values { "x" number } { "y" number } }
{ $description "Square root function." } ;
{ $description "Raises " { $snippet "x" } " to the power of " { $snippet "y" } ". If " { $snippet "y" } " is an integer the answer is computed exactly, otherwise a floating point approximation is used." }
{ $errors "Throws an error if " { $snippet "x" } " and " { $snippet "y" } " are both integer 0." } ;
+HELP: 10^
+{ $values { "x" number } { "y" number } }
+{ $description "Raises " { $snippet "x" } " to the power of 10. If " { $snippet "x" } " is an integer the answer is computed exactly, otherwise a floating point approximation is used." } ;
+
HELP: gcd
{ $values { "x" integer } { "y" integer } { "a" integer } { "d" integer } }
{ $description "Computes the positive greatest common divisor " { $snippet "d" } " of " { $snippet "x" } " and " { $snippet "y" } ", and another value " { $snippet "a" } " satisfying:" { $code "a*y = d mod x" } }
[ t ] [ e pi i* ^ imaginary-part -0.00001 0.00001 between? ] unit-test
[ t ] [ 0 0 ^ fp-nan? ] unit-test
+[ 0.0 ] [ 0.0 1.0 ^ ] unit-test
[ 1/0. ] [ 0 -2 ^ ] unit-test
[ t ] [ 0 0.0 ^ fp-nan? ] unit-test
[ 1/0. ] [ 0 -2.0 ^ ] unit-test
[ 2.5 ] [ 1.0 2.5 1.0 lerp ] unit-test
[ 1.75 ] [ 1.0 2.5 0.5 lerp ] unit-test
-[ C{ 1 2 } ] [ C{ 1 2 } 1 ^ ] unit-test
\ No newline at end of file
+[ C{ 1 2 } ] [ C{ 1 2 } 1 ^ ] unit-test
GENERIC: sqrt ( x -- y ) foldable
M: real sqrt
- >float dup 0.0 < [ neg fsqrt 0.0 swap rect> ] [ fsqrt ] if ;
+ >float dup 0.0 < [ neg fsqrt 0.0 swap rect> ] [ fsqrt ] if ; inline
: factor-2s ( n -- r s )
#! factor an integer into 2^r * s
2dup [ real? ] both? [ drop 0 >= ] [ 2drop f ] if ; inline
: 0^ ( x -- z )
- dup zero? [ drop 0/0. ] [ 0 < 1/0. 0 ? ] if ; inline
+ [ 0/0. ] [ 0 < 1/0. 0 ? ] if-zero ; inline
: (^mod) ( n x y -- z )
make-bits 1 [
: ^ ( x y -- z )
{
- { [ over zero? ] [ nip 0^ ] }
+ { [ over 0 = ] [ nip 0^ ] }
{ [ dup integer? ] [ integer^ ] }
{ [ 2dup real^? ] [ fpow ] }
[ ^complex ]
: divisor? ( m n -- ? )
mod 0 = ;
+ERROR: non-trivial-divisor n ;
+
: mod-inv ( x n -- y )
[ nip ] [ gcd 1 = ] 2bi
[ dup 0 < [ + ] [ nip ] if ]
- [ "Non-trivial divisor found" throw ] if ; foldable
+ [ non-trivial-divisor ] if ; foldable
: ^mod ( x y n -- z )
over 0 < [
GENERIC: absq ( x -- y ) foldable
-M: real absq sq ;
+M: real absq sq ; inline
: ~abs ( x y epsilon -- ? )
[ - abs ] dip < ;
GENERIC: exp ( x -- y )
-M: real exp fexp ;
+M: real exp fexp ; inline
M: complex exp >rect swap fexp swap polar> ;
GENERIC: log ( x -- y )
-M: real log dup 0.0 >= [ flog ] [ 0.0 rect> log ] if ;
+M: real log dup 0.0 >= [ flog ] [ 0.0 rect> log ] if ; inline
M: complex log >polar swap flog swap rect> ;
+: 10^ ( x -- y ) 10 swap ^ ; inline
+
+: log10 ( x -- y ) log 10 log / ; inline
+
GENERIC: cos ( x -- y ) foldable
M: complex cos
[ [ fcos ] [ fcosh ] bi* * ]
[ [ fsin neg ] [ fsinh ] bi* * ] 2bi rect> ;
-M: real cos fcos ;
+M: real cos fcos ; inline
: sec ( x -- y ) cos recip ; inline
[ [ fcosh ] [ fcos ] bi* * ]
[ [ fsinh ] [ fsin ] bi* * ] 2bi rect> ;
-M: real cosh fcosh ;
+M: real cosh fcosh ; inline
: sech ( x -- y ) cosh recip ; inline
[ [ fsin ] [ fcosh ] bi* * ]
[ [ fcos ] [ fsinh ] bi* * ] 2bi rect> ;
-M: real sin fsin ;
+M: real sin fsin ; inline
: cosec ( x -- y ) sin recip ; inline
[ [ fsinh ] [ fcos ] bi* * ]
[ [ fcosh ] [ fsin ] bi* * ] 2bi rect> ;
-M: real sinh fsinh ;
+M: real sinh fsinh ; inline
: cosech ( x -- y ) sinh recip ; inline
M: complex tan [ sin ] [ cos ] bi / ;
-M: real tan ftan ;
+M: real tan ftan ; inline
GENERIC: tanh ( x -- y ) foldable
M: complex tanh [ sinh ] [ cosh ] bi / ;
-M: real tanh ftanh ;
+M: real tanh ftanh ; inline
: cot ( x -- y ) tan recip ; inline
M: complex atan i* atanh i* ;
-M: real atan fatan ;
+M: real atan fatan ; inline
: asec ( x -- y ) recip acos ; inline
: round ( x -- y ) dup sgn 2 / + truncate ; inline
: floor ( x -- y )
- dup 1 mod dup zero?
- [ drop ] [ dup 0 < [ - 1 - ] [ - ] if ] if ; foldable
+ dup 1 mod
+ [ ] [ dup 0 < [ - 1 - ] [ - ] if ] if-zero ; foldable
: ceiling ( x -- y ) neg floor neg ; foldable
+: floor-to ( x step -- y )
+ [ [ / floor ] [ * ] bi ] unless-zero ;
+
: lerp ( a b t -- a_t ) [ over - ] dip * + ; inline
{ $description "Computes the bitwise complement of the interval." } ;
HELP: points>interval
-{ $values { "seq" "a sequence of " { $snippet "{ point included? }" } " pairs" } { "interval" interval } }
+{ $values { "seq" "a sequence of " { $snippet "{ point included? }" } " pairs" } { "interval" interval } { "nan?" "true if the computation produced NaNs" } }
{ $description "Outputs the smallest interval containing all of the endpoints." }
;
USING: math.intervals kernel sequences words math math.order
arrays prettyprint tools.test random vocabs combinators
-accessors math.constants ;
+accessors math.constants fry ;
IN: math.intervals.tests
[ empty-interval ] [ 2 2 (a,b) ] unit-test
+[ empty-interval ] [ 2 2.0 (a,b) ] unit-test
+
[ empty-interval ] [ 2 2 [a,b) ] unit-test
[ empty-interval ] [ 2 2 (a,b] ] unit-test
[ T{ interval f { 1 t } { 1 t } } ] [ 1 [a,a] ] unit-test
+! Not sure how to handle NaNs yet...
+! [ 1 0/0. [a,b] ] must-fail
+! [ 0/0. 1 [a,b] ] must-fail
+
[ t ] [ { 3 t } { 3 f } endpoint< ] unit-test
[ t ] [ { 2 f } { 3 f } endpoint< ] unit-test
[ f ] [ { 3 f } { 3 t } endpoint< ] unit-test
0 1 (a,b) 0 1 [a,b] interval-subset?
] unit-test
+[ t ] [
+ full-interval -1/0. 1/0. [a,b] interval-subset?
+] unit-test
+
+[ t ] [
+ -1/0. 1/0. [a,b] full-interval interval-subset?
+] unit-test
+
+[ f ] [
+ full-interval 0 1/0. [a,b] interval-subset?
+] unit-test
+
+[ t ] [
+ 0 1/0. [a,b] full-interval interval-subset?
+] unit-test
+
[ f ] [
0 0 1 (a,b) interval-contains?
] unit-test
[ f ] [ 0 10 [a,b] 0 [a,a] interval< ] unit-test
+[ f ] [ 0 10 [a,b] 0.0 [a,a] interval< ] unit-test
+
+[ f ] [ 0.0 10 [a,b] 0 [a,a] interval< ] unit-test
+
[ f ] [ 0 10 [a,b] 10 [a,a] interval> ] unit-test
[ incomparable ] [ 0 [a,a] 0 10 [a,b] interval< ] unit-test
[ t ] [ 1 100 [a,b] -1 1 [a,b] interval/i [-inf,inf] = ] unit-test
+! Accuracy of interval-mod
+[ t ] [ full-interval 40 40 [a,b] interval-mod -40 40 (a,b) interval-subset?
+] unit-test
+
! Interval random tester
: random-element ( interval -- n )
dup full-interval eq? [
} case
] if ;
-: random-unary-op ( -- pair )
+: unary-ops ( -- alist )
{
{ bitnot interval-bitnot }
{ abs interval-abs }
{ 2/ interval-2/ }
- { 1+ interval-1+ }
- { 1- interval-1- }
{ neg interval-neg }
}
"math.ratios.private" vocab [
{ recip interval-recip } suffix
- ] when
- random ;
+ ] when ;
-: unary-test ( -- ? )
- random-interval random-unary-op ! 2dup . .
+: unary-test ( op -- ? )
+ [ random-interval ] dip
0 pick interval-contains? over first \ recip eq? and [
2drop t
] [
second execute( a -- b ) interval-contains?
] if ;
-[ t ] [ 80000 iota [ drop unary-test ] all? ] unit-test
+unary-ops [
+ [ [ t ] ] dip '[ 8000 iota [ drop _ unary-test ] all? ] unit-test
+] each
-: random-binary-op ( -- pair )
+: binary-ops ( -- alist )
{
{ + interval+ }
{ - interval- }
{ bitand interval-bitand }
{ bitor interval-bitor }
{ bitxor interval-bitxor }
- ! { shift interval-shift }
{ min interval-min }
{ max interval-max }
}
"math.ratios.private" vocab [
{ / interval/ } suffix
- ] when
- random ;
+ ] when ;
-: binary-test ( -- ? )
- random-interval random-interval random-binary-op ! 3dup . . .
+: binary-test ( op -- ? )
+ [ random-interval random-interval ] dip
0 pick interval-contains? over first { / /i mod rem } member? and [
3drop t
] [
second execute( a b -- c ) interval-contains?
] if ;
-[ t ] [ 80000 iota [ drop binary-test ] all? ] unit-test
+binary-ops [
+ [ [ t ] ] dip '[ 8000 iota [ drop _ binary-test ] all? ] unit-test
+] each
-: random-comparison ( -- pair )
+: comparison-ops ( -- alist )
{
{ < interval< }
{ <= interval<= }
{ > interval> }
{ >= interval>= }
- } random ;
+ } ;
-: comparison-test ( -- ? )
- random-interval random-interval random-comparison
+: comparison-test ( op -- ? )
+ [ random-interval random-interval ] dip
[ [ [ random-element ] bi@ ] dip first execute( a b -- ? ) ] 3keep
second execute( a b -- ? ) dup incomparable eq? [ 2drop t ] [ = ] if ;
-[ t ] [ 40000 iota [ drop comparison-test ] all? ] unit-test
+comparison-ops [
+ [ [ t ] ] dip '[ 8000 iota [ drop _ comparison-test ] all? ] unit-test
+] each
[ t ] [ -10 10 [a,b] 0 100 [a,b] assume> 0 10 (a,b] = ] unit-test
[ t ] [ -10 10 [a,b] interval-abs 0 10 [a,b] = ] unit-test
+[ t ] [ full-interval interval-abs [0,inf] = ] unit-test
+
+[ t ] [ [0,inf] interval-abs [0,inf] = ] unit-test
+
+[ t ] [ empty-interval interval-abs empty-interval = ] unit-test
+
+[ t ] [ [0,inf] interval-sq [0,inf] = ] unit-test
+
! Test that commutative interval ops really are
: random-interval-or-empty ( -- obj )
10 random 0 = [ empty-interval ] [ random-interval ] if ;
-: random-commutative-op ( -- op )
+: commutative-ops ( -- seq )
{
interval+ interval*
interval-bitor interval-bitand interval-bitxor
interval-max interval-min
- } random ;
-
-[ t ] [
- 80000 iota [
- drop
- random-interval-or-empty random-interval-or-empty
- random-commutative-op
- [ execute ] [ swapd execute ] 3bi =
- ] all?
-] unit-test
+ } ;
+
+commutative-ops [
+ [ [ t ] ] dip '[
+ 8000 iota [
+ drop
+ random-interval-or-empty random-interval-or-empty _
+ [ execute ] [ swapd execute ] 3bi =
+ ] all?
+ ] unit-test
+] each
-! Copyright (C) 2007, 2008 Slava Pestov, Doug Coleman.
+! Copyright (C) 2007, 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
! Based on Slate's src/unfinished/interval.slate by Brian Rice.
USING: accessors kernel sequences arrays math math.order
-combinators generic layouts ;
+combinators generic layouts memoize ;
IN: math.intervals
SYMBOL: empty-interval
TUPLE: interval { from read-only } { to read-only } ;
+: closed-point? ( from to -- ? )
+ 2dup [ first ] bi@ number=
+ [ [ second ] both? ] [ 2drop f ] if ;
+
: <interval> ( from to -- interval )
- 2dup [ first ] bi@ {
- { [ 2dup > ] [ 2drop 2drop empty-interval ] }
- { [ 2dup = ] [
- 2drop 2dup [ second ] both?
+ {
+ { [ 2dup [ first ] bi@ > ] [ 2drop empty-interval ] }
+ { [ 2dup [ first ] bi@ number= ] [
+ 2dup [ second ] both?
[ interval boa ] [ 2drop empty-interval ] if
] }
- [ 2drop interval boa ]
+ { [ 2dup [ { -1/0. t } = ] [ { 1/0. t } = ] bi* and ] [
+ 2drop full-interval
+ ] }
+ [ interval boa ]
} cond ;
: open-point ( n -- endpoint ) f 2array ;
: (a,inf] ( a -- interval ) 1/0. (a,b] ; inline
-: [0,inf] ( -- interval ) 0 [a,inf] ; foldable
+MEMO: [0,inf] ( -- interval ) 0 [a,inf] ; foldable
+
+MEMO: fixnum-interval ( -- interval )
+ most-negative-fixnum most-positive-fixnum [a,b] ; inline
+
+MEMO: array-capacity-interval ( -- interval )
+ 0 max-array-capacity [a,b] ; inline
: [-inf,inf] ( -- interval ) full-interval ; inline
[ 2dup [ first ] bi@ ] dip call [
2drop t
] [
- 2dup [ first ] bi@ = [
+ 2dup [ first ] bi@ number= [
[ second ] bi@ not or
] [
2drop f
] if
] if ; inline
+: endpoint= ( p1 p2 -- ? )
+ [ [ first ] bi@ number= ] [ [ second ] bi@ eq? ] 2bi and ;
+
: endpoint< ( p1 p2 -- ? ) [ < ] compare-endpoints ;
-: endpoint<= ( p1 p2 -- ? ) [ endpoint< ] 2keep = or ;
+: endpoint<= ( p1 p2 -- ? ) [ endpoint< ] [ endpoint= ] 2bi or ;
: endpoint> ( p1 p2 -- ? ) [ > ] compare-endpoints ;
-: endpoint>= ( p1 p2 -- ? ) [ endpoint> ] 2keep = or ;
+: endpoint>= ( p1 p2 -- ? ) [ endpoint> ] [ endpoint= ] 2bi or ;
: endpoint-min ( p1 p2 -- p3 ) [ endpoint< ] most ;
: interval>points ( int -- from to )
[ from>> ] [ to>> ] bi ;
-: points>interval ( seq -- interval )
- dup [ first fp-nan? ] any?
- [ drop [-inf,inf] ] [
- dup first
- [ [ endpoint-min ] reduce ]
- [ [ endpoint-max ] reduce ]
- 2bi <interval>
- ] if ;
+: points>interval ( seq -- interval nan? )
+ [ first fp-nan? not ] partition
+ [
+ [ [ ] [ endpoint-min ] map-reduce ]
+ [ [ ] [ endpoint-max ] map-reduce ] bi
+ <interval>
+ ]
+ [ empty? not ]
+ bi* ;
+
+: nan-ok ( interval nan? -- interval ) drop ; inline
+: nan-not-ok ( interval nan? -- interval ) [ drop full-interval ] when ; inline
: (interval-op) ( p1 p2 quot -- p3 )
[ [ first ] [ first ] [ call ] tri* ]
[ drop [ second ] both? ]
3bi 2array ; inline
-: interval-op ( i1 i2 quot -- i3 )
+: interval-op ( i1 i2 quot -- i3 nan? )
{
[ [ from>> ] [ from>> ] [ ] tri* (interval-op) ]
[ [ to>> ] [ from>> ] [ ] tri* (interval-op) ]
} cond ; inline
: interval+ ( i1 i2 -- i3 )
- [ [ + ] interval-op ] do-empty-interval ;
+ [ [ + ] interval-op nan-ok ] do-empty-interval ;
: interval- ( i1 i2 -- i3 )
- [ [ - ] interval-op ] do-empty-interval ;
+ [ [ - ] interval-op nan-ok ] do-empty-interval ;
: interval-intersect ( i1 i2 -- i3 )
{
{ [ dup empty-interval eq? ] [ drop ] }
{ [ over full-interval eq? ] [ drop ] }
{ [ dup full-interval eq? ] [ nip ] }
- [ [ interval>points 2array ] bi@ append points>interval ]
+ [ [ interval>points 2array ] bi@ append points>interval nan-not-ok ]
} cond ;
: interval-subset? ( i1 i2 -- ? )
0 swap interval-contains? ;
: interval* ( i1 i2 -- i3 )
- [ [ [ * ] interval-op ] do-empty-interval ]
+ [ [ [ * ] interval-op nan-ok ] do-empty-interval ]
[ [ interval-zero? ] either? ]
2bi [ 0 [a,a] interval-union ] when ;
] [
interval>points
2dup [ second ] both?
- [ [ first ] bi@ = ]
+ [ [ first ] bi@ number= ]
[ 2drop f ] if
] if ;
[
[
[ interval-closure ] bi@
- [ shift ] interval-op
+ [ shift ] interval-op nan-not-ok
] interval-integer-op
] do-empty-interval ;
: interval-max ( i1 i2 -- i3 )
#! Inaccurate; could be tighter
- [ [ interval-closure ] bi@ [ max ] interval-op ] do-empty-interval ;
+ [ [ interval-closure ] bi@ [ max ] interval-op nan-not-ok ] do-empty-interval ;
: interval-min ( i1 i2 -- i3 )
#! Inaccurate; could be tighter
- [ [ interval-closure ] bi@ [ min ] interval-op ] do-empty-interval ;
+ [ [ interval-closure ] bi@ [ min ] interval-op nan-not-ok ] do-empty-interval ;
: interval-interior ( i1 -- i2 )
dup special-interval? [
} cond ; inline
: interval/ ( i1 i2 -- i3 )
- [ [ [ / ] interval-op ] interval-division-op ] do-empty-interval ;
+ [ [ [ / ] interval-op nan-not-ok ] interval-division-op ] do-empty-interval ;
: interval/-safe ( i1 i2 -- i3 )
#! Just a hack to make the compiler work if bootstrap.math
[
[
[ interval-closure ] bi@
- [ /i ] interval-op
+ [ /i ] interval-op nan-not-ok
] interval-integer-op
] interval-division-op
] do-empty-interval ;
: interval/f ( i1 i2 -- i3 )
- [ [ [ /f ] interval-op ] interval-division-op ] do-empty-interval ;
+ [ [ [ /f ] interval-op nan-not-ok ] interval-division-op ] do-empty-interval ;
: (interval-abs) ( i1 -- i2 )
interval>points [ first2 [ abs ] dip 2array ] bi@ 2array ;
{
{ [ dup empty-interval eq? ] [ ] }
{ [ dup full-interval eq? ] [ drop [0,inf] ] }
- { [ 0 over interval-contains? ] [ (interval-abs) { 0 t } suffix points>interval ] }
- [ (interval-abs) points>interval ]
+ { [ 0 over interval-contains? ] [ (interval-abs) { 0 t } suffix points>interval nan-not-ok ] }
+ [ (interval-abs) points>interval nan-not-ok ]
} cond ;
-: interval-mod ( i1 i2 -- i3 )
- #! Inaccurate.
- [
- [
- nip interval-abs to>> first [ neg ] keep (a,b)
- ] interval-division-op
- ] do-empty-interval ;
-
-: interval-rem ( i1 i2 -- i3 )
- #! Inaccurate.
- [
- [
- nip interval-abs to>> first 0 swap [a,b)
- ] interval-division-op
- ] do-empty-interval ;
+: interval-absq ( i1 -- i2 )
+ interval-abs interval-sq ;
: interval-recip ( i1 -- i2 ) 1 [a,a] swap interval/ ;
: left-endpoint-< ( i1 i2 -- ? )
[ swap interval-subset? ]
[ nip interval-singleton? ]
- [ [ from>> ] bi@ = ]
+ [ [ from>> ] bi@ endpoint= ]
2tri and and ;
: right-endpoint-< ( i1 i2 -- ? )
[ interval-subset? ]
[ drop interval-singleton? ]
- [ [ to>> ] bi@ = ]
+ [ [ to>> ] bi@ endpoint= ]
2tri and and ;
: (interval<) ( i1 i2 -- i1 i2 ? )
} cond 2nip ;
: left-endpoint-<= ( i1 i2 -- ? )
- [ from>> ] dip to>> = ;
+ [ from>> ] [ to>> ] bi* endpoint= ;
: right-endpoint-<= ( i1 i2 -- ? )
- [ to>> ] dip from>> = ;
+ [ to>> ] [ from>> ] bi* endpoint= ;
: interval<= ( i1 i2 -- ? )
{
: interval>= ( i1 i2 -- ? )
swap interval<= ;
+: interval-mod ( i1 i2 -- i3 )
+ {
+ { [ over empty-interval eq? ] [ swap ] }
+ { [ dup empty-interval eq? ] [ ] }
+ { [ dup full-interval eq? ] [ ] }
+ [ interval-abs to>> first [ neg ] keep (a,b) ]
+ } cond
+ swap 0 [a,a] interval>= t eq? [ [0,inf] interval-intersect ] when ;
+
+: (rem-range) ( i -- i' ) interval-abs to>> first 0 swap [a,b) ;
+
+: interval-rem ( i1 i2 -- i3 )
+ {
+ { [ over empty-interval eq? ] [ drop ] }
+ { [ dup empty-interval eq? ] [ nip ] }
+ { [ dup full-interval eq? ] [ 2drop [0,inf] ] }
+ [ nip (rem-range) ]
+ } cond ;
+
: interval-bitand-pos ( i1 i2 -- ? )
[ to>> first ] bi@ min 0 swap [a,b] ;
: facos ( x -- y )
"double" "libm" "acos" { "double" } alien-invoke ;
- inline
: fasin ( x -- y )
"double" "libm" "asin" { "double" } alien-invoke ;
- inline
: fatan ( x -- y )
"double" "libm" "atan" { "double" } alien-invoke ;
- inline
: fatan2 ( x y -- z )
"double" "libm" "atan2" { "double" "double" } alien-invoke ;
- inline
: fcos ( x -- y )
"double" "libm" "cos" { "double" } alien-invoke ;
- inline
: fsin ( x -- y )
"double" "libm" "sin" { "double" } alien-invoke ;
- inline
: ftan ( x -- y )
"double" "libm" "tan" { "double" } alien-invoke ;
- inline
: fcosh ( x -- y )
"double" "libm" "cosh" { "double" } alien-invoke ;
- inline
: fsinh ( x -- y )
"double" "libm" "sinh" { "double" } alien-invoke ;
- inline
: ftanh ( x -- y )
"double" "libm" "tanh" { "double" } alien-invoke ;
- inline
: fexp ( x -- y )
"double" "libm" "exp" { "double" } alien-invoke ;
- inline
: flog ( x -- y )
"double" "libm" "log" { "double" } alien-invoke ;
- inline
: fpow ( x y -- z )
"double" "libm" "pow" { "double" "double" } alien-invoke ;
- inline
: fsqrt ( x -- y )
"double" "libm" "sqrt" { "double" } alien-invoke ;
- inline
! Windows doesn't have these...
: facosh ( x -- y )
"double" "libm" "acosh" { "double" } alien-invoke ;
- inline
: fasinh ( x -- y )
"double" "libm" "asinh" { "double" } alien-invoke ;
- inline
: fatanh ( x -- y )
"double" "libm" "atanh" { "double" } alien-invoke ;
- inline
: do-row ( exchange-with row# -- )
[ exchange-rows ] keep
[ first-col ] keep
- dup 1+ rows-from clear-col ;
+ dup 1 + rows-from clear-col ;
: find-row ( row# quot -- i elt )
[ rows-from ] dip find ; inline
: (echelon) ( col# row# -- )
over cols < over rows < and [
- 2dup pivot-row [ over do-row 1+ ] when*
- [ 1+ ] dip (echelon)
+ 2dup pivot-row [ over do-row 1 + ] when*
+ [ 1 + ] dip (echelon)
] [
2drop
] if ;
! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays columns kernel math math.bits
-math.order math.vectors sequences sequences.private ;
+USING: accessors arrays columns kernel locals math math.bits
+math.functions math.order math.vectors sequences
+sequences.private fry ;
IN: math.matrices
! Matrices
: zero-matrix ( m n -- matrix )
- [ nip 0 <array> ] curry map ;
+ '[ _ 0 <array> ] replicate ;
: identity-matrix ( n -- matrix )
#! Make a nxn identity matrix.
dup [ [ = 1 0 ? ] with map ] curry map ;
+:: rotation-matrix3 ( axis theta -- matrix )
+ theta cos :> c
+ theta sin :> s
+ axis first3 :> z :> y :> x
+ x sq 1.0 x sq - c * + x y * 1.0 c - * z s * - x z * 1.0 c - * y s * + 3array
+ x y * 1.0 c - * z s * + y sq 1.0 y sq - c * + y z * 1.0 c - * x s * - 3array
+ x z * 1.0 c - * y s * - y z * 1.0 c - * x s * + z sq 1.0 z sq - c * + 3array
+ 3array ;
+
+:: rotation-matrix4 ( axis theta -- matrix )
+ theta cos :> c
+ theta sin :> s
+ axis first3 :> z :> y :> x
+ x sq 1.0 x sq - c * + x y * 1.0 c - * z s * - x z * 1.0 c - * y s * + 0 4array
+ x y * 1.0 c - * z s * + y sq 1.0 y sq - c * + y z * 1.0 c - * x s * - 0 4array
+ x z * 1.0 c - * y s * - y z * 1.0 c - * x s * + z sq 1.0 z sq - c * + 0 4array
+ { 0.0 0.0 0.0 1.0 } 4array ;
+
+:: translation-matrix4 ( offset -- matrix )
+ offset first3 :> z :> y :> x
+ {
+ { 1.0 0.0 0.0 x }
+ { 0.0 1.0 0.0 y }
+ { 0.0 0.0 1.0 z }
+ { 0.0 0.0 0.0 1.0 }
+ } ;
+
+: >scale-factors ( number/sequence -- x y z )
+ dup number? [ dup dup ] [ first3 ] if ;
+
+:: scale-matrix3 ( factors -- matrix )
+ factors >scale-factors :> z :> y :> x
+ {
+ { x 0.0 0.0 }
+ { 0.0 y 0.0 }
+ { 0.0 0.0 z }
+ } ;
+
+:: scale-matrix4 ( factors -- matrix )
+ factors >scale-factors :> z :> y :> x
+ {
+ { x 0.0 0.0 0.0 }
+ { 0.0 y 0.0 0.0 }
+ { 0.0 0.0 z 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } ;
+
+: ortho-matrix4 ( dim -- matrix )
+ [ recip ] map scale-matrix4 ;
+
+:: frustum-matrix4 ( xy-dim near far -- matrix )
+ xy-dim first2 :> y :> x
+ near x /f :> xf
+ near y /f :> yf
+ near far + near far - /f :> zf
+ 2 near far * * near far - /f :> wf
+
+ {
+ { xf 0.0 0.0 0.0 }
+ { 0.0 yf 0.0 0.0 }
+ { 0.0 0.0 zf wf }
+ { 0.0 0.0 -1.0 0.0 }
+ } ;
+
+:: skew-matrix4 ( theta -- matrix )
+ theta tan :> zf
+
+ {
+ { 1.0 0.0 0.0 0.0 }
+ { 0.0 1.0 0.0 0.0 }
+ { 0.0 zf 1.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } ;
+
! Matrix operations
: mneg ( m -- m ) [ vneg ] map ;
PRIVATE>
-: cross ( vec1 vec2 -- vec3 ) [ i ] [ j ] [ k ] 2tri 3array ;
+: cross ( vec1 vec2 -- vec3 ) [ [ i ] [ j ] [ k ] 2tri ] keep 3sequence ;
: proj ( v u -- w )
[ [ v. ] [ norm-sq ] bi / ] keep n*v ;
: cross-zip ( seq1 seq2 -- seq1xseq2 )
[ [ 2array ] with map ] curry map ;
-
-<PRIVATE
-: m^n ( m n -- m )
+: m^n ( m n -- n )
make-bits over first length identity-matrix
- [ [ dupd m. ] when [ dup m. ] dip ] reduce nip ;
-
-PRIVATE>
\ No newline at end of file
+ [ [ dupd m. ] when [ dup m. ] dip ] reduce nip ;
\ No newline at end of file
HELP: sieve
{ $values { "n" "the greatest odd number to consider" } { "arr" "a bit array" } }
-{ $description "Return a bit array containing a primality bit for every odd number between 3 and " { $snippet "n" } " (inclusive). " { $snippet ">index" } " can be used to retrieve the index of an odd number to be tested." } ;
+{ $description "Apply Eratostene sieve up to " { $snippet "n" } ". Primality can then be tested using " { $link sieve } "." } ;
-HELP: >index
-{ $values { "n" "an odd number" } { "i" "the corresponding index" } }
-{ $description "Retrieve the index corresponding to the odd number on the stack." } ;
-
-{ sieve >index } related-words
+HELP: marked-prime?
+{ $values { "n" "an integer" } { "arr" "a byte array returned by " { $link sieve } } { "?" "a boolean" } }
+{ $description "Check whether a number between 3 and the limit given to " { $link sieve } " has been marked as a prime number."} ;
-USING: bit-arrays math.primes.erato tools.test ;
+USING: byte-arrays math math.bitwise math.primes.erato sequences tools.test ;
-[ ?{ t t t f t t f t t f t f f t } ] [ 29 sieve ] unit-test
+[ B{ 255 251 247 126 } ] [ 100 sieve ] unit-test
+[ 1 100 sieve marked-prime? ] [ bounds-error? ] must-fail-with
+[ 120 100 sieve marked-prime? ] [ bounds-error? ] must-fail-with
+[ f ] [ 119 100 sieve marked-prime? ] unit-test
+[ t ] [ 113 100 sieve marked-prime? ] unit-test
+
+! There are 25997 primes below 300000. 1 must be removed and 3 5 7 added.
+[ 25997 ] [ 299999 sieve [ bit-count ] sigma 2 + ] unit-test
\ No newline at end of file
! Copyright (C) 2009 Samuel Tardieu.
! See http://factorcode.org/license.txt for BSD license.
-USING: bit-arrays kernel math math.functions math.ranges sequences ;
+USING: arrays byte-arrays kernel math math.bitwise math.functions math.order
+math.ranges sequences sequences.private ;
IN: math.primes.erato
-: >index ( n -- i )
- 3 - 2 /i ; inline
+<PRIVATE
-: index> ( i -- n )
- 2 * 3 + ; inline
+CONSTANT: masks B{ 0 128 0 0 0 0 0 64 0 0 0 32 0 16 0 0 0 8 0 4 0 0 0 2 0 0 0 0 0 1 }
-: mark-multiples ( i arr -- )
- [ index> [ sq >index ] keep ] dip
- [ length 1 - swap <range> f swap ] keep
- [ set-nth ] curry with each ;
+: bit-pos ( n -- byte/f mask/f )
+ 30 /mod masks nth-unsafe [ drop f f ] when-zero ;
-: maybe-mark-multiples ( i arr -- )
- 2dup nth [ mark-multiples ] [ 2drop ] if ;
+: marked-unsafe? ( n arr -- ? )
+ [ bit-pos ] dip swap [ [ nth-unsafe ] [ bitand zero? not ] bi* ] [ 2drop f ] if* ;
-: init-sieve ( n -- arr )
- >index 1 + <bit-array> dup set-bits ;
+: unmark ( n arr -- )
+ [ bit-pos swap ] dip
+ over [ [ swap unmask ] change-nth-unsafe ] [ 3drop ] if ;
+
+: upper-bound ( arr -- n ) length 30 * 1 - ;
+
+: unmark-multiples ( i arr -- )
+ 2dup marked-unsafe? [
+ [ [ dup sq ] [ upper-bound ] bi* rot <range> ] keep
+ [ unmark ] curry each
+ ] [
+ 2drop
+ ] if ;
+
+: init-sieve ( n -- arr ) 29 + 30 /i 255 <array> >byte-array ;
+
+PRIVATE>
: sieve ( n -- arr )
- [ init-sieve ] [ sqrt >index [0,b] ] bi
- over [ maybe-mark-multiples ] curry each ; foldable
+ init-sieve [ 2 swap upper-bound sqrt [a,b] ] keep
+ [ [ unmark-multiples ] curry each ] keep ;
+
+: marked-prime? ( n arr -- ? )
+ 2dup upper-bound 2 swap between? [ bounds-error ] unless
+ over { 2 3 5 } member? [ 2drop t ] [ marked-unsafe? ] if ;
USING: help.markup help.syntax math sequences ;
IN: math.primes.factors
-{ factors group-factors unique-factors } related-words
+{ divisors factors group-factors unique-factors } related-words
HELP: factors
{ $values { "n" "a positive integer" } { "seq" sequence } }
HELP: totient
{ $values { "n" "a positive integer" } { "t" integer } }
{ $description { "Return the number of integers between 1 and " { $snippet "n-1" } " that are relatively prime to " { $snippet "n" } "." } } ;
+
+HELP: divisors
+{ $values { "n" "a positive integer" } { "seq" sequence } }
+{ $description { "Return the ordered list of divisors of " { $snippet "n" } ", including 1 and " { $snippet "n" } "." } } ;
-USING: math.primes.factors tools.test ;
+USING: math.primes.factors sequences tools.test ;
{ { 999983 999983 1000003 } } [ 999969000187000867 factors ] unit-test
{ { } } [ -5 factors ] unit-test
{ 0 } [ 1 totient ] unit-test
{ { 425612003 } } [ 425612003 factors ] unit-test
{ { 13 4253 15823 32472893749823741 } } [ 28408516453955558205925627 factors ] unit-test
+{ { 1 2 3 4 6 8 12 24 } } [ 24 divisors ] unit-test
+{ 24 } [ 360 divisors length ] unit-test
! Copyright (C) 2007-2009 Samuel Tardieu.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays combinators kernel make math math.functions
-math.primes sequences ;
+math.primes math.ranges sequences sequences.product sorting ;
IN: math.primes.factors
<PRIVATE
: count-factor ( n d -- n' c )
[ 1 ] 2dip [ /i ] keep
- [ dupd /mod zero? ] curry [ nip [ 1+ ] dip ] while drop
+ [ dupd /mod zero? ] curry [ nip [ 1 + ] dip ] while drop
swap ;
: write-factor ( n d -- n' d' )
: totient ( n -- t )
{
{ [ dup 2 < ] [ drop 0 ] }
- [ dup unique-factors [ 1 [ 1- * ] reduce ] [ product ] bi / * ]
+ [ dup unique-factors [ 1 [ 1 - * ] reduce ] [ product ] bi / * ]
} cond ; foldable
+
+: divisors ( n -- seq )
+ group-factors [ first2 [0,b] [ ^ ] with map ] map
+ [ product ] product-map natural-sort ;
-USING: arrays math math.primes math.primes.miller-rabin
-tools.test ;
+USING: arrays kernel math math.primes math.primes.miller-rabin
+sequences tools.test ;
IN: math.primes.tests
{ 1237 } [ 1234 next-prime ] unit-test
{ { 4999963 4999999 5000011 5000077 5000081 } }
[ 4999962 5000082 primes-between >array ] unit-test
+{ { 8999981 8999993 9000011 9000041 } }
+[ 8999980 9000045 primes-between >array ] unit-test
+
[ 2 ] [ 1 next-prime ] unit-test
[ 3 ] [ 2 next-prime ] unit-test
[ 5 ] [ 3 next-prime ] unit-test
[ 100000000000031 ] [ 100000000000000 next-prime ] unit-test
[ 49 ] [ 50 random-prime log2 ] unit-test
+
+[ t ] [ 5000077 dup find-relative-prime coprime? ] unit-test
+
+[ 5 t { 14 14 14 14 14 } ]
+[ 5 15 unique-primes [ length ] [ [ prime? ] all? ] [ [ log2 ] map ] tri ] unit-test
! Copyright (C) 2007-2009 Samuel Tardieu.
! See http://factorcode.org/license.txt for BSD license.
-USING: combinators kernel math math.bitwise math.functions
-math.order math.primes.erato math.primes.miller-rabin
-math.ranges random sequences sets fry ;
+USING: combinators combinators.short-circuit fry kernel math
+math.bitwise math.functions math.order math.primes.erato
+math.primes.erato.private math.primes.miller-rabin math.ranges
+literals random sequences sets vectors ;
IN: math.primes
<PRIVATE
-: look-in-bitmap ( n -- ? ) >index 4999999 sieve nth ;
+: look-in-bitmap ( n -- ? ) $[ 8999999 sieve ] marked-unsafe? ; inline
-: really-prime? ( n -- ? )
- dup 5000000 < [ look-in-bitmap ] [ miller-rabin ] if ; foldable
+: (prime?) ( n -- ? )
+ dup 8999999 <= [ look-in-bitmap ] [ miller-rabin ] if ;
+
+! In order not to reallocate large vectors, we compute the upper bound
+! of the number of primes in a given interval. We use a double inequality given
+! by Pierre Dusart in http://www.ams.org/mathscinet-getitem?mr=99d:11133
+! for x > 598. Under this limit, we know that there are at most 108 primes.
+: upper-pi ( x -- y )
+ dup log [ / ] [ 1.2762 swap / 1 + ] bi * ceiling ;
+
+: lower-pi ( x -- y )
+ dup log [ / ] [ 0.992 swap / 1 + ] bi * floor ;
+
+: <primes-vector> ( low high -- vector )
+ swap [ [ upper-pi ] [ lower-pi ] bi* - >integer
+ 108 max 10000 min <vector> ] keep
+ 3 < [ [ 2 swap push ] keep ] when ;
+
+: simple? ( n -- ? ) { [ even? ] [ 3 mod 0 = ] [ 5 mod 0 = ] } 1|| ;
PRIVATE>
: prime? ( n -- ? )
{
- { [ dup 2 < ] [ drop f ] }
- { [ dup even? ] [ 2 = ] }
- [ really-prime? ]
+ { [ dup 7 < ] [ { 2 3 5 } member? ] }
+ { [ dup simple? ] [ drop f ] }
+ [ (prime?) ]
} cond ; foldable
: next-prime ( n -- p )
dup 2 < [
drop 2
] [
- next-odd [ dup really-prime? ] [ 2 + ] until
+ next-odd [ dup prime? ] [ 2 + ] until
] if ; foldable
: primes-between ( low high -- seq )
- [ dup 3 max dup even? [ 1 + ] when ] dip
- 2 <range> [ prime? ] filter
- swap 3 < [ 2 prefix ] when ;
+ [ [ 3 max dup even? [ 1 + ] when ] dip 2 <range> ]
+ [ <primes-vector> ] 2bi
+ [ '[ [ prime? ] _ push-if ] each ] keep clone ;
: primes-upto ( n -- seq ) 2 swap primes-between ;
: unique-primes ( n numbits -- seq )
2dup 2^ estimated-primes > [ too-few-primes ] when
- 2dup '[ _ random-prime ] replicate
+ 2dup [ random-prime ] curry replicate
dup all-unique? [ 2nip ] [ drop unique-primes ] if ;
: <range> ( a b step -- range )
[ over - ] dip [ /i 1 + 0 max ] keep range boa ; inline
-M: range length ( seq -- n )
- length>> ;
+M: range length ( seq -- n ) length>> ; inline
-M: range nth-unsafe ( n range -- obj )
- [ step>> * ] keep from>> + ;
+M: range nth-unsafe ( n range -- obj ) [ step>> * ] keep from>> + ; inline
! For ranges with many elements, the default element-wise methods
! sequences define are unsuitable because they're O(n)
[ 3 ] [ 10/3 truncate ] unit-test
[ -3 ] [ -10/3 truncate ] unit-test
-[ -1/2 ] [ 1/2 1- ] unit-test
-[ 3/2 ] [ 1/2 1+ ] unit-test
+[ -1/2 ] [ 1/2 1 - ] unit-test
+[ 3/2 ] [ 1/2 1 + ] unit-test
[ 1.0 ] [ 0.5 1/2 + ] unit-test
[ 1.0 ] [ 1/2 0.5 + ] unit-test
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel kernel.private math math.functions math.private ;
+USING: accessors kernel kernel.private math math.functions
+math.private sequences summary ;
IN: math.ratios
: 2>fraction ( a/b c/d -- a c b d )
PRIVATE>
+ERROR: division-by-zero x ;
+
+M: division-by-zero summary
+ drop "Division by zero" ;
+
M: integer /
- dup zero? [
- "Division by zero" throw
+ [
+ division-by-zero
] [
dup 0 < [ [ neg ] bi@ ] when
2dup gcd nip [ /i ] curry bi@ fraction>
- ] if ;
+ ] if-zero ;
M: ratio hashcode*
nip >fraction [ hashcode ] bi@ bitxor ;
M: ratio >bignum >fraction /i >bignum ;
M: ratio >float >fraction /f ;
-M: ratio numerator numerator>> ;
-M: ratio denominator denominator>> ;
+M: ratio numerator numerator>> ; inline
+M: ratio denominator denominator>> ; inline
M: ratio < scale < ;
M: ratio <= scale <= ;
--- /dev/null
+IN: math.vectors.specialization.tests
+USING: compiler.tree.debugger math.vectors tools.test kernel
+kernel.private math specialized-arrays.double
+specialized-arrays.complex-float
+specialized-arrays.float ;
+
+[ V{ t } ] [
+ [ { double-array double-array } declare distance 0.0 < not ] final-literals
+] unit-test
+
+[ V{ float } ] [
+ [ { float-array float } declare v*n norm ] final-classes
+] unit-test
+
+[ V{ number } ] [
+ [ { complex-float-array complex-float-array } declare v. ] final-classes
+] unit-test
+
+[ V{ real } ] [
+ [ { complex-float-array complex } declare v*n norm ] final-classes
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: words kernel make sequences effects kernel.private accessors
+combinators math math.intervals math.vectors namespaces assocs fry
+splitting classes.algebra generalizations
+compiler.tree.propagation.info ;
+IN: math.vectors.specialization
+
+SYMBOLS: -> +vector+ +scalar+ +nonnegative+ ;
+
+: signature-for-schema ( array-type elt-type schema -- signature )
+ [
+ {
+ { +vector+ [ drop ] }
+ { +scalar+ [ nip ] }
+ { +nonnegative+ [ nip ] }
+ } case
+ ] with with map ;
+
+: (specialize-vector-word) ( word array-type elt-type schema -- word' )
+ signature-for-schema
+ [ [ name>> ] [ [ name>> ] map "," join ] bi* "=>" glue f <word> ]
+ [ [ , \ declare , def>> % ] [ ] make ]
+ [ drop stack-effect ]
+ 2tri
+ [ define-declared ] [ 2drop ] 3bi ;
+
+: output-infos ( array-type elt-type schema -- value-infos )
+ [
+ {
+ { +vector+ [ drop <class-info> ] }
+ { +scalar+ [ nip <class-info> ] }
+ { +nonnegative+ [ nip real class-and [0,inf] <class/interval-info> ] }
+ } case
+ ] with with map ;
+
+: record-output-signature ( word array-type elt-type schema -- word )
+ output-infos
+ [ drop ]
+ [ drop ]
+ [ [ stack-effect in>> length '[ _ ndrop ] ] dip append ] 2tri
+ "outputs" set-word-prop ;
+
+CONSTANT: vector-words
+H{
+ { [v-] { +vector+ +vector+ -> +vector+ } }
+ { distance { +vector+ +vector+ -> +nonnegative+ } }
+ { n*v { +scalar+ +vector+ -> +vector+ } }
+ { n+v { +scalar+ +vector+ -> +vector+ } }
+ { n-v { +scalar+ +vector+ -> +vector+ } }
+ { n/v { +scalar+ +vector+ -> +vector+ } }
+ { norm { +vector+ -> +nonnegative+ } }
+ { norm-sq { +vector+ -> +nonnegative+ } }
+ { normalize { +vector+ -> +vector+ } }
+ { v* { +vector+ +vector+ -> +vector+ } }
+ { v*n { +vector+ +scalar+ -> +vector+ } }
+ { v+ { +vector+ +vector+ -> +vector+ } }
+ { v+n { +vector+ +scalar+ -> +vector+ } }
+ { v- { +vector+ +vector+ -> +vector+ } }
+ { v-n { +vector+ +scalar+ -> +vector+ } }
+ { v. { +vector+ +vector+ -> +scalar+ } }
+ { v/ { +vector+ +vector+ -> +vector+ } }
+ { v/n { +vector+ +scalar+ -> +vector+ } }
+ { vceiling { +vector+ -> +vector+ } }
+ { vfloor { +vector+ -> +vector+ } }
+ { vmax { +vector+ +vector+ -> +vector+ } }
+ { vmin { +vector+ +vector+ -> +vector+ } }
+ { vneg { +vector+ -> +vector+ } }
+ { vtruncate { +vector+ -> +vector+ } }
+}
+
+SYMBOL: specializations
+
+specializations [ vector-words keys [ V{ } clone ] H{ } map>assoc ] initialize
+
+: add-specialization ( new-word signature word -- )
+ specializations get at set-at ;
+
+: word-schema ( word -- schema ) vector-words at ;
+
+: inputs ( schema -- seq ) { -> } split first ;
+
+: outputs ( schema -- seq ) { -> } split second ;
+
+: specialize-vector-word ( word array-type elt-type -- word' )
+ pick word-schema
+ [ inputs (specialize-vector-word) ]
+ [ outputs record-output-signature ] 3bi ;
+
+: input-signature ( word -- signature ) def>> first ;
+
+: specialize-vector-words ( array-type elt-type -- )
+ [ vector-words keys ] 2dip
+ '[
+ [ _ _ specialize-vector-word ] keep
+ [ dup input-signature ] dip
+ add-specialization
+ ] each ;
+
+: find-specialization ( classes word -- word/f )
+ specializations get at
+ [ first [ class<= ] 2all? ] with find
+ swap [ second ] when ;
+
+: vector-word-custom-inlining ( #call -- word/f )
+ [ in-d>> [ value-info class>> ] map ] [ word>> ] bi
+ find-specialization ;
+
+vector-words keys [
+ [ vector-word-custom-inlining ]
+ "custom-inlining" set-word-prop
+] each
\ No newline at end of file
[ { 1.75 2.125 } ] [ { 1.0 2.5 } { 2.5 1.0 } { 0.5 0.25 } vlerp ] unit-test
[ 1.125 ] [ 0.0 1.0 2.0 4.0 { 0.5 0.25 } bilerp ] unit-test
+
+[ 17 ] [ 0 1 2 3 4 5 6 7 { 1 2 3 } trilerp ] unit-test
\ No newline at end of file
: set-axis ( u v axis -- w )
[ [ zero? 2over ? ] dip swap nth ] map-index 2nip ;
+<PRIVATE
+
: 2tetra@ ( p q r s t u v w quot -- )
dup [ [ 2bi@ ] curry 4dip ] dip 2bi@ ; inline
+PRIVATE>
+
: trilerp ( aaa baa aba bba aab bab abb bbb {t,u,v} -- a_tuv )
[ first lerp ] [ second lerp ] [ third lerp ] tri-curry
[ 2tetra@ ] [ 2bi@ ] [ call ] tri* ;
[ 89 ] [ 10 fib ] unit-test
-[ "USING: kernel math memoize generalizations ; IN: memoize.tests MEMO: x ( a b c d e -- f g h i j ) [ 1+ ] 4 ndip ;" eval( -- ) ] must-fail
+[ "USING: kernel math memoize generalizations ; IN: memoize.tests MEMO: x ( a b c d e -- f g h i j ) [ 1 + ] 4 ndip ;" eval( -- ) ] must-fail
MEMO: see-test ( a -- b ) reverse ;
dup bytes>> length 256 < [ fill-bytes ] when ;
: split-bytes ( bytes separator -- leftover-bytes safe-to-dump )
- dupd [ length ] bi@ 1- - short cut-slice swap ;
+ dupd [ length ] bi@ 1 - - short cut-slice swap ;
: dump-until-separator ( multipart -- multipart )
dup
\r
3 <model> "x" set\r
"x" get [ 2 * ] <arrow> dup "z" set\r
-[ 1+ ] <arrow> "y" set\r
+[ 1 + ] <arrow> "y" set\r
[ ] [ "y" get activate-model ] unit-test\r
[ t ] [ "z" get "x" get connections>> memq? ] unit-test\r
[ 7 ] [ "y" get value>> ] unit-test\r
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+USING: accessors models models.arrow inverse kernel ;
+IN: models.illusion
+
+TUPLE: illusion < arrow ;
+
+: <illusion> ( model quot -- illusion )
+ illusion new V{ } clone >>connections V{ } clone >>dependencies 0 >>ref
+ swap >>quot over >>model [ add-dependency ] keep ;
+
+: <activated-illusion> ( model quot -- illusion ) <illusion> dup activate-model ;
+
+: backtalk ( value object -- )
+ [ quot>> [undo] call( a -- b ) ] [ model>> ] bi set-model ;
+
+M: illusion update-model ( model -- ) [ [ value>> ] keep backtalk ] with-locked-model ;
\ No newline at end of file
--- /dev/null
+Two Way Arrows
\ No newline at end of file
M: model model-activated drop ;
: ref-model ( model -- n )
- [ 1+ ] change-ref ref>> ;
+ [ 1 + ] change-ref ref>> ;
: unref-model ( model -- n )
- [ 1- ] change-ref ref>> ;
+ [ 1 - ] change-ref ref>> ;
: activate-model ( model -- )
dup ref-model 1 = [
\r
TUPLE: an-observer { i integer } ;\r
\r
-M: an-observer model-changed nip [ 1+ ] change-i drop ;\r
+M: an-observer model-changed nip [ 1 + ] change-i drop ;\r
\r
[ 1 0 ] [\r
[let* | m1 [ 1 <model> ]\r
o1 i>>\r
o2 i>>\r
]\r
-] unit-test
\ No newline at end of file
+] unit-test\r
{ $notes { $link "ui.gadgets.sliders" } " use range models." } ;\r
\r
HELP: <range>\r
-{ $values { "value" real } { "page" real } { "min" real } { "max" real } { "range" range } }\r
+{ $values { "value" real } { "page" real } { "min" real } { "max" real } { "step" real } { "range" range } }\r
{ $description "Creates a new " { $link range } " model." } ;\r
\r
HELP: range-model\r
tools.test models.range ;\r
\r
! Test <range> \r
-: setup-range ( -- range ) 0 0 0 255 <range> ;\r
+: setup-range ( -- range ) 0 0 0 255 1 <range> ;\r
+: setup-stepped-range ( -- range ) 0 0 0 255 2 <range> ;\r
\r
! clamp-value should not go past range ends\r
[ 0 ] [ -10 setup-range clamp-value ] unit-test\r
[ 255 ] [ 2000 setup-range clamp-value ] unit-test\r
[ 14 ] [ 14 setup-range clamp-value ] unit-test\r
\r
+! step-value\r
+[ 14 ] [ 15 setup-stepped-range step-value ] unit-test\r
+\r
! range min/max/page values should be correct\r
[ 0 ] [ setup-range range-page-value ] unit-test\r
[ 0 ] [ setup-range range-min-value ] unit-test\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: accessors kernel models arrays sequences math math.order\r
-models.product ;\r
+models.product generalizations math.functions ;\r
FROM: models.product => product ;\r
IN: models.range\r
\r
TUPLE: range < product ;\r
\r
-: <range> ( value page min max -- range )\r
- 4array [ <model> ] map range new-product ;\r
+: <range> ( value page min max step -- range )\r
+ 5 narray [ <model> ] map range new-product ;\r
\r
: range-model ( range -- model ) dependencies>> first ;\r
: range-page ( range -- model ) dependencies>> second ;\r
: range-min ( range -- model ) dependencies>> third ;\r
: range-max ( range -- model ) dependencies>> fourth ;\r
+: range-step ( range -- model ) dependencies>> 4 swap nth ;\r
+\r
+: step-value ( value range -- value' )\r
+ range-step value>> floor-to ;\r
\r
M: range range-value\r
- [ range-model value>> ] keep clamp-value ;\r
+ [ range-model value>> ] [ clamp-value ] [ step-value ] tri ;\r
\r
M: range range-page-value range-page value>> ;\r
\r
-USING: help.markup help.syntax ;
+USING: help.markup help.syntax strings ;
IN: multiline
HELP: STRING:
""
} ;
+HELP: HEREDOC:
+{ $syntax "HEREDOC: marker\n...text...\nmarker" }
+{ $values { "marker" "a word (token)" } { "text" "arbitrary text" } { "value" string } }
+{ $description "Returns a string delimited by an arbitrary user-defined token. This delimiter must be exactly the text beginning at the first non-blank character after " { $link POSTPONE: HEREDOC: } " until the end of the line containing " { $link POSTPONE: HEREDOC: } ". Text is captured until a line is found conatining exactly this delimter string." }
+{ $warning "Whitespace is significant." }
+{ $examples
+ { $example "USING: multiline prettyprint ;"
+ "HEREDOC: END\nx\nEND\n."
+ "\"x\\n\""
+ }
+ { $example "USING: multiline prettyprint sequences ;"
+ "2 5 HEREDOC: zap\nfoo\nbar\nzap\nsubseq ."
+ "\"o\\nb\""
+ }
+} ;
+
+HELP: DELIMITED:
+{ $syntax "DELIMITED: marker\n...text...\nmarker" }
+{ $values { "marker" "a word (token)" } { "text" "arbitrary text" } { "value" string } }
+{ $description "Returns a string delimited by an arbitrary user-defined token. This delimiter must be exactly the text beginning at the first non-blank character after " { $link POSTPONE: DELIMITED: } " until the end of the line containing " { $link POSTPONE: DELIMITED: } ". Text is captured until the exact delimiter string is found, regardless of where." }
+{ $warning "Whitespace is significant on the " { $link POSTPONE: DELIMITED: } " line." }
+{ $examples
+ { $example "USING: multiline prettyprint ;"
+ "DELIMITED: factor blows my mind"
+"whoafactor blows my mind ."
+ "\"whoa\""
+ }
+} ;
+
{ POSTPONE: <" POSTPONE: STRING: } related-words
HELP: parse-multiline-string
"Multiline strings:"
{ $subsection POSTPONE: STRING: }
{ $subsection POSTPONE: <" }
+{ $subsection POSTPONE: HEREDOC: }
+{ $subsection POSTPONE: DELIMITED: }
"Multiline comments:"
{ $subsection POSTPONE: /* }
"Writing new multiline parsing words:"
-USING: multiline tools.test ;
+USING: accessors eval multiline tools.test ;
IN: multiline.tests
STRING: test-it
[ "\nhi" ] [ <"
hi"> ] unit-test
+
+
+! HEREDOC:
+
+[ "foo\nbar\n" ] [ HEREDOC: END
+foo
+bar
+END
+] unit-test
+
+[ "" ] [ HEREDOC: END
+END
+] unit-test
+
+[ " END\n" ] [ HEREDOC: END
+ END
+END
+] unit-test
+
+[ "\n" ] [ HEREDOC: END
+
+END
+] unit-test
+
+[ "x\n" ] [ HEREDOC: END
+x
+END
+] unit-test
+
+[ "x\n" ] [ HEREDOC: END
+x
+END
+] unit-test
+
+[ "xyz \n" ] [ HEREDOC: END
+xyz
+END
+] unit-test
+
+[ "} ! * # \" «\n" ] [ HEREDOC: END
+} ! * # " «
+END
+] unit-test
+
+[ 21 "foo\nbar\n" " HEREDOC: FOO\n FOO\n" 22 ] [ 21 HEREDOC: X
+foo
+bar
+X
+HEREDOC: END
+ HEREDOC: FOO
+ FOO
+END
+22 ] unit-test
+
+[ "lol\n xyz\n" ]
+[
+HEREDOC: xyz
+lol
+ xyz
+xyz
+] unit-test
+
+
+[ "lol" ]
+[ DELIMITED: aol
+lolaol ] unit-test
+
+[ "whoa" ]
+[ DELIMITED: factor blows my mind
+whoafactor blows my mind ] unit-test
quotations math accessors locals ;
IN: multiline
+ERROR: bad-heredoc identifier ;
+
<PRIVATE
: next-line-text ( -- str )
lexer get dup next-line line-text>> ;
<PRIVATE
-:: (parse-multiline-string) ( i end -- j )
+:: (scan-multiline-string) ( i end -- j )
lexer get line-text>> :> text
text [
end text i start* [| j |
] [
text i short tail % CHAR: \n ,
lexer get next-line
- 0 end (parse-multiline-string)
+ 0 end (scan-multiline-string)
] if*
] [ end unexpected-eof ] if ;
-PRIVATE>
-
-: parse-multiline-string ( end-text -- str )
+:: (parse-multiline-string) ( end-text skip-n-chars -- str )
[
lexer get
- [ 1+ swap (parse-multiline-string) ]
+ [ skip-n-chars + end-text (scan-multiline-string) ]
change-column drop
] "" make ;
+: rest-of-line ( -- seq )
+ lexer get [ line-text>> ] [ column>> ] bi tail ;
+
+:: advance-same-line ( text -- )
+ lexer get [ text length + ] change-column drop ;
+
+:: (parse-til-line-begins) ( begin-text -- )
+ lexer get still-parsing? [
+ lexer get line-text>> begin-text sequence= [
+ begin-text advance-same-line
+ ] [
+ lexer get line-text>> % "\n" %
+ lexer get next-line
+ begin-text (parse-til-line-begins)
+ ] if
+ ] [
+ begin-text bad-heredoc
+ ] if ;
+
+: parse-til-line-begins ( begin-text -- seq )
+ [ (parse-til-line-begins) ] "" make ;
+
+PRIVATE>
+
+: parse-multiline-string ( end-text -- str )
+ 1 (parse-multiline-string) ;
+
SYNTAX: <"
"\">" parse-multiline-string parsed ;
"\"}" parse-multiline-string parsed ;
SYNTAX: /* "*/" parse-multiline-string drop ;
+
+SYNTAX: HEREDOC:
+ lexer get skip-blank
+ rest-of-line
+ lexer get next-line
+ parse-til-line-begins parsed ;
+
+SYNTAX: DELIMITED:
+ lexer get skip-blank
+ rest-of-line
+ lexer get next-line
+ 0 (parse-multiline-string) parsed ;
--- /dev/null
+USING: alien help.markup help.syntax io kernel math quotations
+opengl.gl assocs vocabs.loader sequences accessors colors words
+opengl ;
+IN: opengl.annotations
+
+HELP: log-gl-error
+{ $values { "function" word } }
+{ $description "If the most recent OpenGL call resulted in an error, append it to the " { $link gl-error-log } "." }
+{ $notes "Don't call this function directly. Call " { $link log-gl-errors } " to annotate every OpenGL function to automatically log errors." } ;
+
+HELP: gl-error-log
+{ $var-description "A vector of OpenGL errors logged by " { $link log-gl-errors } ". Each log entry has the following tuple slots:" }
+{ $list
+ { { $snippet "function" } " is the OpenGL function that raised the error." }
+ { { $snippet "error" } " is the OpenGL error code." }
+ { { $snippet "timestamp" } " is the time the error was logged." }
+}
+{ "The error log is emptied using the " { $link clear-gl-error-log } " word." } ;
+
+HELP: clear-gl-error-log
+{ $description "Empties the OpenGL error log populated by " { $link log-gl-errors } "." } ;
+
+HELP: throw-gl-errors
+{ $description "Annotate every OpenGL function to throw a " { $link gl-error } " if the function results in an error. Use " { $link reset-gl-functions } " to reverse this operation." } ;
+
+HELP: log-gl-errors
+{ $description "Annotate every OpenGL function to log using " { $link log-gl-error } " if the function results in an error. Use " { $link reset-gl-functions } " to reverse this operation." } ;
+
+HELP: reset-gl-functions
+{ $description "Removes any annotations from all OpenGL functions, such as those applied by " { $link throw-gl-errors } " or " { $link log-gl-errors } "." } ;
+
+{ throw-gl-errors gl-error log-gl-errors log-gl-error clear-gl-error-log reset-gl-functions } related-words
+
+ARTICLE: "opengl.annotations" "OpenGL error reporting"
+"The " { $vocab-link "opengl.annotations" } " vocabulary provides some tools for tracking down GL errors:"
+{ $subsection throw-gl-errors }
+{ $subsection log-gl-errors }
+{ $subsection clear-gl-error-log }
+{ $subsection reset-gl-functions } ;
+
+ABOUT: "opengl.annotations"
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Joe Groff.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces combinators.short-circuit vocabs sequences
+compiler.units tools.annotations tools.annotations.private fry words
+opengl calendar accessors ascii ;
+IN: opengl.annotations
+
+TUPLE: gl-error-log
+ { function word initial: t }
+ { error gl-error }
+ { timestamp timestamp } ;
+
+gl-error-log [ V{ } clone ] initialize
+
+: <gl-error-log> ( function code -- gl-error-log )
+ [ dup ] dip <gl-error> now gl-error-log boa ;
+
+: log-gl-error ( function -- )
+ gl-error-code [ <gl-error-log> gl-error-log get push ] [ drop ] if* ;
+
+: clear-gl-error-log ( -- )
+ V{ } clone gl-error-log set ;
+
+: gl-function? ( word -- ? )
+ name>> { [ "glGetError" = not ] [ "gl" head? ] [ third LETTER? ] } 1&& ;
+
+: gl-functions ( -- words )
+ "opengl.gl" vocab words [ gl-function? ] filter ;
+
+: annotate-gl-functions ( quot -- )
+ [
+ [ gl-functions ] dip [ [ dup ] dip curry (annotate) ] curry each
+ ] with-compilation-unit ;
+
+: reset-gl-functions ( -- )
+ [ gl-functions [ (reset) ] each ] with-compilation-unit ;
+
+: throw-gl-errors ( -- )
+ [ '[ @ _ (gl-error) ] ] annotate-gl-functions ;
+
+: log-gl-errors ( -- )
+ [ '[ @ _ log-gl-error ] ] annotate-gl-functions ;
HELP: has-gl-extensions?
{ $values { "extensions" "A sequence of extension name strings" } { "?" "A boolean value" } }
-{ $description "Returns true if the set of " { $snippet "extensions" } " is a subset of the implementation-supported extensions returned by " { $link gl-extensions } "." } ;
+{ $description "Returns true if the set of " { $snippet "extensions" } " is a subset of the implementation-supported extensions returned by " { $link gl-extensions } ". Elements of " { $snippet "extensions" } " can be sequences, in which case true will be returned if any one of the extensions in the subsequence are available." }
+{ $examples "Testing for framebuffer object and pixel buffer support:"
+ { $code <" {
+ { "GL_EXT_framebuffer_object" "GL_ARB_framebuffer_object" }
+ "GL_ARB_pixel_buffer_object"
+} has-gl-extensions? "> }
+} ;
HELP: has-gl-version-or-extensions?
{ $values { "version" "A version string" } { "extensions" "A sequence of extension name strings" } { "?" "a boolean" } }
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: opengl.capabilities tools.test ;
+IN: opengl.capabilities.tests
+
+CONSTANT: test-extensions
+ {
+ "GL_ARB_vent_core_frogblast"
+ "GL_EXT_resonance_cascade"
+ "GL_EXT_slipgate"
+ }
+
+[ t ]
+[ "GL_ARB_vent_core_frogblast" test-extensions (has-extension?) ] unit-test
+
+[ f ]
+[ "GL_ARB_wallhack" test-extensions (has-extension?) ] unit-test
+
+[ t ] [
+ { "GL_EXT_dimensional_portal" "GL_EXT_slipgate" }
+ test-extensions (has-extension?)
+] unit-test
! Copyright (C) 2008 Joe Groff.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces make sequences splitting opengl.gl
-continuations math.parser math arrays sets math.order fry ;
+continuations math.parser math arrays sets strings math.order fry ;
IN: opengl.capabilities
: (require-gl) ( thing require-quot make-error-quot -- )
[ dupd call [ drop ] ] dip '[ _ " " make throw ] if ; inline
+: (has-extension?) ( query-extension(s) available-extensions -- ? )
+ over string? [ member? ] [ [ member? ] curry any? ] if ;
+
: gl-extensions ( -- seq )
GL_EXTENSIONS glGetString " " split ;
: has-gl-extensions? ( extensions -- ? )
- gl-extensions swap [ over member? ] all? nip ;
+ gl-extensions [ (has-extension?) ] curry all? ;
: (make-gl-extensions-error) ( required-extensions -- )
gl-extensions diff
"Required OpenGL extensions not supported:\n" %
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: help.markup help.syntax multiline tools.continuations ;
+IN: opengl.debug
+
+HELP: G
+{ $description "Makes the OpenGL context associated with " { $link G-world } " active for subsequent OpenGL calls. This is intended to be used from the listener, where interactively entered OpenGL calls can be directed to any window. Note that the Factor UI resets the OpenGL context every time a window is updated, so every code snippet entered in the listener must be prefixed with " { $snippet "G" } " in this use case." }
+{ $examples { $code <" USING: opengl.debug ui ;
+
+[ drop t ] find-window G-world set
+G 0.0 0.0 1.0 1.0 glClearColor
+G GL_COLOR_BUFFER_BIT glClear
+"> } } ;
+
+HELP: F
+{ $description "Flushes the OpenGL context associated with " { $link G-world } ", thereby committing any outstanding drawing operations." } ;
+
+HELP: G-world
+{ $var-description "The world whose OpenGL context is made active by " { $link G } "." } ;
+
+HELP: GB
+{ $description "A shorthand for " { $link gl-break } "." } ;
+
+HELP: gl-break
+{ $description "Suspends the current thread and activates the walker like " { $link break } ", but also preserves the current OpenGL context, saves it to " { $link G-world } " for interactive use through " { $link G } ", and restores the current context when the suspended thread is continued. The shorthand word " { $link POSTPONE: GB } " can also be used." } ;
+
+{ G F G-world POSTPONE: GB gl-break } related-words
+
+ARTICLE: "opengl.debug" "Interactive debugging of OpenGL applications"
+"The " { $vocab-link "opengl.debug" } " vocabulary provides words to assist with interactive debugging of OpenGL applications in the Factor UI."
+{ $subsection G-world }
+{ $subsection G }
+{ $subsection F }
+{ $subsection GB }
+{ $subsection gl-break } ;
+
+ABOUT: "opengl.debug"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors kernel namespaces parser tools.continuations
+ui.backend ui.gadgets.worlds words ;
+IN: opengl.debug
+
+SYMBOL: G-world
+
+: G ( -- )
+ G-world get set-gl-context ;
+
+: F ( -- )
+ G-world get handle>> flush-gl-context ;
+
+: gl-break ( -- )
+ world get dup G-world set-global
+ [ break ] dip
+ set-gl-context ;
+
+<< \ gl-break t "break?" set-word-prop >>
+
+SYNTAX: GB
+ \ gl-break parsed ;
+
--- /dev/null
+Helper words for breaking and interactively manipulating OpenGL applications
HELP: gen-framebuffer
{ $values { "id" integer } }
-{ $description "Wrapper for " { $link glGenFramebuffersEXT } " to handle the common case of generating a single framebuffer ID." } ;
+{ $description "Wrapper for " { $link glGenFramebuffers } " to handle the common case of generating a single framebuffer ID." } ;
HELP: gen-renderbuffer
{ $values { "id" integer } }
-{ $description "Wrapper for " { $link glGenRenderbuffersEXT } " to handle the common case of generating a single render buffer ID." } ;
+{ $description "Wrapper for " { $link glGenRenderbuffers } " to handle the common case of generating a single render buffer ID." } ;
HELP: delete-framebuffer
{ $values { "id" integer } }
-{ $description "Wrapper for " { $link glDeleteFramebuffersEXT } " to handle the common case of deleting a single framebuffer ID." } ;
+{ $description "Wrapper for " { $link glDeleteFramebuffers } " to handle the common case of deleting a single framebuffer ID." } ;
HELP: delete-renderbuffer
{ $values { "id" integer } }
-{ $description "Wrapper for " { $link glDeleteRenderbuffersEXT } " to handle the common case of deleting a single render buffer ID." } ;
+{ $description "Wrapper for " { $link glDeleteRenderbuffers } " to handle the common case of deleting a single render buffer ID." } ;
{ gen-framebuffer delete-framebuffer } related-words
{ gen-renderbuffer delete-renderbuffer } related-words
HELP: framebuffer-incomplete?
{ $values { "status/f" "The framebuffer error code, or " { $snippet "f" } " if the framebuffer is render-complete." } }
-{ $description "Checks the framebuffer currently bound by " { $link glBindFramebufferEXT } " or " { $link with-framebuffer } " to see if it is incomplete, i.e., it is not ready to be rendered to." } ;
+{ $description "Checks the framebuffer currently bound by " { $link glBindFramebuffer } " or " { $link with-framebuffer } " to see if it is incomplete, i.e., it is not ready to be rendered to." } ;
HELP: check-framebuffer
-{ $description "Checks the framebuffer currently bound by " { $link glBindFramebufferEXT } " or " { $link with-framebuffer } " with " { $link framebuffer-incomplete? } ", and throws a descriptive error if the framebuffer is incomplete." } ;
+{ $description "Checks the framebuffer currently bound by " { $link glBindFramebuffer } " or " { $link with-framebuffer } " with " { $link framebuffer-incomplete? } ", and throws a descriptive error if the framebuffer is incomplete." } ;
HELP: with-framebuffer
{ $values { "id" "The id of a framebuffer object." } { "quot" "a quotation" } }
-{ $description "Binds framebuffer " { $snippet "id" } " in the dynamic extent of " { $snippet "quot" } ", restoring the window framebuffer when finished." } ;
+{ $description "Binds framebuffer " { $snippet "id" } " for drawing in the dynamic extent of " { $snippet "quot" } ", restoring the window framebuffer when finished." } ;
-ABOUT: "gl-utilities"
\ No newline at end of file
+ABOUT: "gl-utilities"
IN: opengl.framebuffers
: gen-framebuffer ( -- id )
- [ glGenFramebuffersEXT ] (gen-gl-object) ;
+ [ glGenFramebuffers ] (gen-gl-object) ;
: gen-renderbuffer ( -- id )
- [ glGenRenderbuffersEXT ] (gen-gl-object) ;
+ [ glGenRenderbuffers ] (gen-gl-object) ;
: delete-framebuffer ( id -- )
- [ glDeleteFramebuffersEXT ] (delete-gl-object) ;
+ [ glDeleteFramebuffers ] (delete-gl-object) ;
: delete-renderbuffer ( id -- )
- [ glDeleteRenderbuffersEXT ] (delete-gl-object) ;
+ [ glDeleteRenderbuffers ] (delete-gl-object) ;
: framebuffer-incomplete? ( -- status/f )
- GL_FRAMEBUFFER_EXT glCheckFramebufferStatusEXT
- dup GL_FRAMEBUFFER_COMPLETE_EXT = f rot ? ;
+ GL_DRAW_FRAMEBUFFER glCheckFramebufferStatus
+ dup GL_FRAMEBUFFER_COMPLETE = f rot ? ;
: framebuffer-error ( status -- * )
{
- { GL_FRAMEBUFFER_COMPLETE_EXT [ "framebuffer complete" ] }
- { GL_FRAMEBUFFER_UNSUPPORTED_EXT [ "framebuffer configuration unsupported" ] }
- { GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT [ "framebuffer incomplete (incomplete attachment)" ] }
- { GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT [ "framebuffer incomplete (missing attachment)" ] }
+ { GL_FRAMEBUFFER_COMPLETE [ "framebuffer complete" ] }
+ { GL_FRAMEBUFFER_UNSUPPORTED [ "framebuffer configuration unsupported" ] }
+ { GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT [ "framebuffer incomplete (incomplete attachment)" ] }
+ { GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT [ "framebuffer incomplete (missing attachment)" ] }
{ GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT [ "framebuffer incomplete (dimension mismatch)" ] }
{ GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT [ "framebuffer incomplete (format mismatch)" ] }
- { GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT [ "framebuffer incomplete (draw buffer(s) have no attachment)" ] }
- { GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT [ "framebuffer incomplete (read buffer has no attachment)" ] }
- { GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT [ "framebuffer incomplete (multisample counts don't match)" ] }
+ { GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER [ "framebuffer incomplete (draw buffer(s) have no attachment)" ] }
+ { GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER [ "framebuffer incomplete (read buffer has no attachment)" ] }
+ { GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE [ "framebuffer incomplete (multisample counts don't match)" ] }
[ drop gl-error "unknown framebuffer error" ]
} case throw ;
framebuffer-incomplete? [ framebuffer-error ] when* ;
: with-framebuffer ( id quot -- )
- [ GL_FRAMEBUFFER_EXT swap glBindFramebufferEXT ] dip
- [ GL_FRAMEBUFFER_EXT 0 glBindFramebufferEXT ] [ ] cleanup ; inline
+ [ GL_DRAW_FRAMEBUFFER swap glBindFramebuffer ] dip
+ [ GL_DRAW_FRAMEBUFFER 0 glBindFramebuffer ] [ ] cleanup ; inline
: with-draw-read-framebuffers ( draw-id read-id quot -- )
[
- [ GL_DRAW_FRAMEBUFFER_EXT swap glBindFramebufferEXT ]
- [ GL_READ_FRAMEBUFFER_EXT swap glBindFramebufferEXT ] bi*
+ [ GL_DRAW_FRAMEBUFFER swap glBindFramebuffer ]
+ [ GL_READ_FRAMEBUFFER swap glBindFramebuffer ] bi*
] dip
[
- GL_DRAW_FRAMEBUFFER_EXT 0 glBindFramebufferEXT
- GL_READ_FRAMEBUFFER_EXT 0 glBindFramebufferEXT
+ GL_DRAW_FRAMEBUFFER 0 glBindFramebuffer
+ GL_READ_FRAMEBUFFER 0 glBindFramebuffer
] [ ] cleanup ; inline
: framebuffer-attachment ( attachment -- id )
- GL_FRAMEBUFFER_EXT swap GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
- 0 <uint> [ glGetFramebufferAttachmentParameterivEXT ] keep *uint ;
+ GL_FRAMEBUFFER swap GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
+ 0 <uint> [ glGetFramebufferAttachmentParameteriv ] keep *uint ;
: gl-function-number ( -- n )
+gl-function-number-counter+ get-global
- dup 1+ +gl-function-number-counter+ set-global ;
+ dup 1 + +gl-function-number-counter+ set-global ;
: gl-function-pointer ( names n -- funptr )
gl-function-context 2array dup +gl-function-pointers+ get-global at
CONSTANT: GL_NONE HEX: 0
CONSTANT: GL_LEFT HEX: 0406
CONSTANT: GL_RIGHT HEX: 0407
-
+CONSTANT: GL_FRONT_LEFT HEX: 0400
CONSTANT: GL_FRONT_RIGHT HEX: 0401
CONSTANT: GL_BACK_LEFT HEX: 0402
CONSTANT: GL_BACK_RIGHT HEX: 0403
CONSTANT: GL_RGB HEX: 1907
CONSTANT: GL_RGBA HEX: 1908
-! GL_BGRA_ext: http://www.opengl.org/registry/specs/EXT/bgra.txt
-CONSTANT: GL_BGR_EXT HEX: 80E0
-CONSTANT: GL_BGRA_EXT HEX: 80E1
-
! Implementation limits
CONSTANT: GL_MAX_LIST_NESTING HEX: 0B31
CONSTANT: GL_MAX_ATTRIB_STACK_DEPTH HEX: 0D35
GL-FUNCTION: void glTexSubImage3D { glTexSubImage3DEXT } ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid* pixels ) ;
+! GL_ARB_imaging
+
+
+CONSTANT: GL_CONSTANT_COLOR HEX: 8001
+CONSTANT: GL_ONE_MINUS_CONSTANT_COLOR HEX: 8002
+CONSTANT: GL_CONSTANT_ALPHA HEX: 8003
+CONSTANT: GL_ONE_MINUS_CONSTANT_ALPHA HEX: 8004
+CONSTANT: GL_BLEND_COLOR HEX: 8005
+CONSTANT: GL_FUNC_ADD HEX: 8006
+CONSTANT: GL_MIN HEX: 8007
+CONSTANT: GL_MAX HEX: 8008
+CONSTANT: GL_BLEND_EQUATION HEX: 8009
+CONSTANT: GL_FUNC_SUBTRACT HEX: 800A
+CONSTANT: GL_FUNC_REVERSE_SUBTRACT HEX: 800B
+
+
! OpenGL 1.3
GL-FUNCTION: void glMultiDrawElements { glMultiDrawElementsEXT } ( GLenum mode, GLsizei* count, GLenum type, GLvoid** indices, GLsizei primcount ) ;
GL-FUNCTION: void glPointParameterf { glPointParameterfARB } ( GLenum pname, GLfloat param ) ;
GL-FUNCTION: void glPointParameterfv { glPointParameterfvARB } ( GLenum pname, GLfloat* params ) ;
+GL-FUNCTION: void glPointParameteri { glPointParameteriARB } ( GLenum pname, GLint param ) ;
+GL-FUNCTION: void glPointParameteriv { glPointParameterivARB } ( GLenum pname, GLint* params ) ;
GL-FUNCTION: void glSecondaryColor3b { glSecondaryColor3bEXT } ( GLbyte red, GLbyte green, GLbyte blue ) ;
GL-FUNCTION: void glSecondaryColor3bv { glSecondaryColor3bvEXT } ( GLbyte* v ) ;
GL-FUNCTION: void glSecondaryColor3d { glSecondaryColor3dEXT } ( GLdouble red, GLdouble green, GLdouble blue ) ;
CONSTANT: GL_STENCIL_BACK_REF HEX: 8CA3
CONSTANT: GL_STENCIL_BACK_VALUE_MASK HEX: 8CA4
CONSTANT: GL_STENCIL_BACK_WRITEMASK HEX: 8CA5
-CONSTANT: GL_BLEND_EQUATION HEX: 8009
ALIAS: GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION
TYPEDEF: char GLchar
CONSTANT: GL_COMPRESSED_SRGB_ALPHA HEX: 8C49
CONSTANT: GL_COMPRESSED_SLUMINANCE HEX: 8C4A
CONSTANT: GL_COMPRESSED_SLUMINANCE_ALPHA HEX: 8C4B
+CONSTANT: GL_FLOAT_MAT2x3 HEX: 8B65
+CONSTANT: GL_FLOAT_MAT2x4 HEX: 8B66
+CONSTANT: GL_FLOAT_MAT3x2 HEX: 8B67
+CONSTANT: GL_FLOAT_MAT3x4 HEX: 8B68
+CONSTANT: GL_FLOAT_MAT4x2 HEX: 8B69
+CONSTANT: GL_FLOAT_MAT4x3 HEX: 8B6A
GL-FUNCTION: void glUniformMatrix2x3fv { } ( GLint location, GLsizei count, GLboolean transpose, GLfloat* value ) ;
GL-FUNCTION: void glUniformMatrix2x4fv { } ( GLint location, GLsizei count, GLboolean transpose, GLfloat* value ) ;
GL-FUNCTION: void glUniformMatrix4x3fv { } ( GLint location, GLsizei count, GLboolean transpose, GLfloat* value ) ;
-! GL_EXT_framebuffer_object
-
-
-CONSTANT: GL_INVALID_FRAMEBUFFER_OPERATION_EXT HEX: 0506
-CONSTANT: GL_MAX_RENDERBUFFER_SIZE_EXT HEX: 84E8
-CONSTANT: GL_FRAMEBUFFER_BINDING_EXT HEX: 8CA6
-CONSTANT: GL_RENDERBUFFER_BINDING_EXT HEX: 8CA7
-CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT HEX: 8CD0
-CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT HEX: 8CD1
-CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT HEX: 8CD2
-CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT HEX: 8CD3
-CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT HEX: 8CD4
-CONSTANT: GL_FRAMEBUFFER_COMPLETE_EXT HEX: 8CD5
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT HEX: 8CD6
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT HEX: 8CD7
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT HEX: 8CD9
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT HEX: 8CDA
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT HEX: 8CDB
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT HEX: 8CDC
-CONSTANT: GL_FRAMEBUFFER_UNSUPPORTED_EXT HEX: 8CDD
-CONSTANT: GL_MAX_COLOR_ATTACHMENTS_EXT HEX: 8CDF
-CONSTANT: GL_COLOR_ATTACHMENT0_EXT HEX: 8CE0
-CONSTANT: GL_COLOR_ATTACHMENT1_EXT HEX: 8CE1
-CONSTANT: GL_COLOR_ATTACHMENT2_EXT HEX: 8CE2
-CONSTANT: GL_COLOR_ATTACHMENT3_EXT HEX: 8CE3
-CONSTANT: GL_COLOR_ATTACHMENT4_EXT HEX: 8CE4
-CONSTANT: GL_COLOR_ATTACHMENT5_EXT HEX: 8CE5
-CONSTANT: GL_COLOR_ATTACHMENT6_EXT HEX: 8CE6
-CONSTANT: GL_COLOR_ATTACHMENT7_EXT HEX: 8CE7
-CONSTANT: GL_COLOR_ATTACHMENT8_EXT HEX: 8CE8
-CONSTANT: GL_COLOR_ATTACHMENT9_EXT HEX: 8CE9
-CONSTANT: GL_COLOR_ATTACHMENT10_EXT HEX: 8CEA
-CONSTANT: GL_COLOR_ATTACHMENT11_EXT HEX: 8CEB
-CONSTANT: GL_COLOR_ATTACHMENT12_EXT HEX: 8CEC
-CONSTANT: GL_COLOR_ATTACHMENT13_EXT HEX: 8CED
-CONSTANT: GL_COLOR_ATTACHMENT14_EXT HEX: 8CEE
-CONSTANT: GL_COLOR_ATTACHMENT15_EXT HEX: 8CEF
-CONSTANT: GL_DEPTH_ATTACHMENT_EXT HEX: 8D00
-CONSTANT: GL_STENCIL_ATTACHMENT_EXT HEX: 8D20
-CONSTANT: GL_FRAMEBUFFER_EXT HEX: 8D40
-CONSTANT: GL_RENDERBUFFER_EXT HEX: 8D41
-CONSTANT: GL_RENDERBUFFER_WIDTH_EXT HEX: 8D42
-CONSTANT: GL_RENDERBUFFER_HEIGHT_EXT HEX: 8D43
-CONSTANT: GL_RENDERBUFFER_INTERNAL_FORMAT_EXT HEX: 8D44
-CONSTANT: GL_STENCIL_INDEX1_EXT HEX: 8D46
-CONSTANT: GL_STENCIL_INDEX4_EXT HEX: 8D47
-CONSTANT: GL_STENCIL_INDEX8_EXT HEX: 8D48
-CONSTANT: GL_STENCIL_INDEX16_EXT HEX: 8D49
-CONSTANT: GL_RENDERBUFFER_RED_SIZE_EXT HEX: 8D50
-CONSTANT: GL_RENDERBUFFER_GREEN_SIZE_EXT HEX: 8D51
-CONSTANT: GL_RENDERBUFFER_BLUE_SIZE_EXT HEX: 8D52
-CONSTANT: GL_RENDERBUFFER_ALPHA_SIZE_EXT HEX: 8D53
-CONSTANT: GL_RENDERBUFFER_DEPTH_SIZE_EXT HEX: 8D54
-CONSTANT: GL_RENDERBUFFER_STENCIL_SIZE_EXT HEX: 8D55
-
-GL-FUNCTION: void glBindFramebufferEXT { } ( GLenum target, GLuint framebuffer ) ;
-GL-FUNCTION: void glBindRenderbufferEXT { } ( GLenum target, GLuint renderbuffer ) ;
-GL-FUNCTION: GLenum glCheckFramebufferStatusEXT { } ( GLenum target ) ;
-GL-FUNCTION: void glDeleteFramebuffersEXT { } ( GLsizei n, GLuint* framebuffers ) ;
-GL-FUNCTION: void glDeleteRenderbuffersEXT { } ( GLsizei n, GLuint* renderbuffers ) ;
-GL-FUNCTION: void glFramebufferRenderbufferEXT { } ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) ;
-GL-FUNCTION: void glFramebufferTexture1DEXT { } ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) ;
-GL-FUNCTION: void glFramebufferTexture2DEXT { } ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) ;
-GL-FUNCTION: void glFramebufferTexture3DEXT { } ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset ) ;
-GL-FUNCTION: void glGenFramebuffersEXT { } ( GLsizei n, GLuint* framebuffers ) ;
-GL-FUNCTION: void glGenRenderbuffersEXT { } ( GLsizei n, GLuint* renderbuffers ) ;
-GL-FUNCTION: void glGenerateMipmapEXT { } ( GLenum target ) ;
-GL-FUNCTION: void glGetFramebufferAttachmentParameterivEXT { } ( GLenum target, GLenum attachment, GLenum pname, GLint* params ) ;
-GL-FUNCTION: void glGetRenderbufferParameterivEXT { } ( GLenum target, GLenum pname, GLint* params ) ;
-GL-FUNCTION: GLboolean glIsFramebufferEXT { } ( GLuint framebuffer ) ;
-GL-FUNCTION: GLboolean glIsRenderbufferEXT { } ( GLuint renderbuffer ) ;
-GL-FUNCTION: void glRenderbufferStorageEXT { } ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) ;
-
-
-! GL_EXT_framebuffer_blit
-
-
-GL-FUNCTION: void glBlitFramebufferEXT { } ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+! OpenGL 3.0
+
+
+TYPEDEF: ushort GLhalf
+
+CONSTANT: GL_VERTEX_ATTRIB_ARRAY_INTEGER HEX: 88FD
+CONSTANT: GL_SAMPLER_CUBE_SHADOW HEX: 8DC5
+CONSTANT: GL_UNSIGNED_INT_VEC2 HEX: 8DC6
+CONSTANT: GL_UNSIGNED_INT_VEC3 HEX: 8DC7
+CONSTANT: GL_UNSIGNED_INT_VEC4 HEX: 8DC8
+CONSTANT: GL_INT_SAMPLER_1D HEX: 8DC9
+CONSTANT: GL_INT_SAMPLER_2D HEX: 8DCA
+CONSTANT: GL_INT_SAMPLER_3D HEX: 8DCB
+CONSTANT: GL_INT_SAMPLER_CUBE HEX: 8DCC
+CONSTANT: GL_INT_SAMPLER_2D_RECT HEX: 8DCD
+CONSTANT: GL_INT_SAMPLER_1D_ARRAY HEX: 8DCE
+CONSTANT: GL_INT_SAMPLER_2D_ARRAY HEX: 8DCF
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_1D HEX: 8DD1
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_2D HEX: 8DD2
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_3D HEX: 8DD3
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_CUBE HEX: 8DD4
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_2D_RECT HEX: 8DD5
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_1D_ARRAY HEX: 8DD6
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_2D_ARRAY HEX: 8DD7
+CONSTANT: GL_MIN_PROGRAM_TEXEL_OFFSET HEX: 8904
+CONSTANT: GL_MAX_PROGRAM_TEXEL_OFFSET HEX: 8905
+
+CONSTANT: GL_RGBA32F HEX: 8814
+CONSTANT: GL_RGB32F HEX: 8815
+CONSTANT: GL_RGBA16F HEX: 881A
+CONSTANT: GL_RGB16F HEX: 881B
+CONSTANT: GL_TEXTURE_RED_TYPE HEX: 8C10
+CONSTANT: GL_TEXTURE_GREEN_TYPE HEX: 8C11
+CONSTANT: GL_TEXTURE_BLUE_TYPE HEX: 8C12
+CONSTANT: GL_TEXTURE_ALPHA_TYPE HEX: 8C13
+CONSTANT: GL_TEXTURE_DEPTH_TYPE HEX: 8C16
+CONSTANT: GL_UNSIGNED_NORMALIZED HEX: 8C17
+
+CONSTANT: GL_QUERY_WAIT HEX: 8E13
+CONSTANT: GL_QUERY_NO_WAIT HEX: 8E14
+CONSTANT: GL_QUERY_BY_REGION_WAIT HEX: 8E15
+CONSTANT: GL_QUERY_BY_REGION_NO_WAIT HEX: 8E16
+
+CONSTANT: GL_HALF_FLOAT HEX: 140B
+
+CONSTANT: GL_MAP_READ_BIT HEX: 0001
+CONSTANT: GL_MAP_WRITE_BIT HEX: 0002
+CONSTANT: GL_MAP_INVALIDATE_RANGE_BIT HEX: 0004
+CONSTANT: GL_MAP_INVALIDATE_BUFFER_BIT HEX: 0008
+CONSTANT: GL_MAP_FLUSH_EXPLICIT_BIT HEX: 0010
+CONSTANT: GL_MAP_UNSYNCHRONIZED_BIT HEX: 0020
+
+CONSTANT: GL_R8 HEX: 8229
+CONSTANT: GL_R16 HEX: 822A
+CONSTANT: GL_RG8 HEX: 822B
+CONSTANT: GL_RG16 HEX: 822C
+CONSTANT: GL_R16F HEX: 822D
+CONSTANT: GL_R32F HEX: 822E
+CONSTANT: GL_RG16F HEX: 822F
+CONSTANT: GL_RG32F HEX: 8230
+CONSTANT: GL_R8I HEX: 8231
+CONSTANT: GL_R8UI HEX: 8232
+CONSTANT: GL_R16I HEX: 8233
+CONSTANT: GL_R16UI HEX: 8234
+CONSTANT: GL_R32I HEX: 8235
+CONSTANT: GL_R32UI HEX: 8236
+CONSTANT: GL_RG8I HEX: 8237
+CONSTANT: GL_RG8UI HEX: 8238
+CONSTANT: GL_RG16I HEX: 8239
+CONSTANT: GL_RG16UI HEX: 823A
+CONSTANT: GL_RG32I HEX: 823B
+CONSTANT: GL_RG32UI HEX: 823C
+CONSTANT: GL_RG HEX: 8227
+CONSTANT: GL_COMPRESSED_RED HEX: 8225
+CONSTANT: GL_COMPRESSED_RG HEX: 8226
+CONSTANT: GL_RG_INTEGER HEX: 8228
+
+CONSTANT: GL_VERTEX_ARRAY_BINDING HEX: 85B5
+
+CONSTANT: GL_CLAMP_READ_COLOR HEX: 891C
+CONSTANT: GL_FIXED_ONLY HEX: 891D
+
+CONSTANT: GL_DEPTH_COMPONENT32F HEX: 8CAC
+CONSTANT: GL_DEPTH32F_STENCIL8 HEX: 8CAD
+
+CONSTANT: GL_RGB9_E5 HEX: 8C3D
+CONSTANT: GL_UNSIGNED_INT_5_9_9_9_REV HEX: 8C3E
+CONSTANT: GL_TEXTURE_SHARED_SIZE HEX: 8C3F
+
+CONSTANT: GL_R11F_G11F_B10F HEX: 8C3A
+CONSTANT: GL_UNSIGNED_INT_10F_11F_11F_REV HEX: 8C3B
+
+CONSTANT: GL_INVALID_FRAMEBUFFER_OPERATION HEX: 0506
+CONSTANT: GL_MAX_RENDERBUFFER_SIZE HEX: 84E8
+CONSTANT: GL_FRAMEBUFFER_BINDING HEX: 8CA6
+CONSTANT: GL_RENDERBUFFER_BINDING HEX: 8CA7
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE HEX: 8CD0
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME HEX: 8CD1
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL HEX: 8CD2
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE HEX: 8CD3
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING HEX: 8210
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE HEX: 8211
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE HEX: 8212
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE HEX: 8213
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE HEX: 8214
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE HEX: 8215
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE HEX: 8216
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE HEX: 8217
+CONSTANT: GL_FRAMEBUFFER_DEFAULT HEX: 8218
+CONSTANT: GL_FRAMEBUFFER_UNDEFINED HEX: 8219
+CONSTANT: GL_DEPTH_STENCIL_ATTACHMENT HEX: 821A
+CONSTANT: GL_FRAMEBUFFER_COMPLETE HEX: 8CD5
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT HEX: 8CD6
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT HEX: 8CD7
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER HEX: 8CDB
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER HEX: 8CDC
+CONSTANT: GL_FRAMEBUFFER_UNSUPPORTED HEX: 8CDD
+CONSTANT: GL_MAX_COLOR_ATTACHMENTS HEX: 8CDF
+CONSTANT: GL_COLOR_ATTACHMENT0 HEX: 8CE0
+CONSTANT: GL_COLOR_ATTACHMENT1 HEX: 8CE1
+CONSTANT: GL_COLOR_ATTACHMENT2 HEX: 8CE2
+CONSTANT: GL_COLOR_ATTACHMENT3 HEX: 8CE3
+CONSTANT: GL_COLOR_ATTACHMENT4 HEX: 8CE4
+CONSTANT: GL_COLOR_ATTACHMENT5 HEX: 8CE5
+CONSTANT: GL_COLOR_ATTACHMENT6 HEX: 8CE6
+CONSTANT: GL_COLOR_ATTACHMENT7 HEX: 8CE7
+CONSTANT: GL_COLOR_ATTACHMENT8 HEX: 8CE8
+CONSTANT: GL_COLOR_ATTACHMENT9 HEX: 8CE9
+CONSTANT: GL_COLOR_ATTACHMENT10 HEX: 8CEA
+CONSTANT: GL_COLOR_ATTACHMENT11 HEX: 8CEB
+CONSTANT: GL_COLOR_ATTACHMENT12 HEX: 8CEC
+CONSTANT: GL_COLOR_ATTACHMENT13 HEX: 8CED
+CONSTANT: GL_COLOR_ATTACHMENT14 HEX: 8CEE
+CONSTANT: GL_COLOR_ATTACHMENT15 HEX: 8CEF
+CONSTANT: GL_DEPTH_ATTACHMENT HEX: 8D00
+CONSTANT: GL_STENCIL_ATTACHMENT HEX: 8D20
+CONSTANT: GL_FRAMEBUFFER HEX: 8D40
+CONSTANT: GL_RENDERBUFFER HEX: 8D41
+CONSTANT: GL_RENDERBUFFER_WIDTH HEX: 8D42
+CONSTANT: GL_RENDERBUFFER_HEIGHT HEX: 8D43
+CONSTANT: GL_RENDERBUFFER_INTERNAL_FORMAT HEX: 8D44
+CONSTANT: GL_STENCIL_INDEX1 HEX: 8D46
+CONSTANT: GL_STENCIL_INDEX4 HEX: 8D47
+CONSTANT: GL_STENCIL_INDEX8 HEX: 8D48
+CONSTANT: GL_STENCIL_INDEX16 HEX: 8D49
+CONSTANT: GL_RENDERBUFFER_RED_SIZE HEX: 8D50
+CONSTANT: GL_RENDERBUFFER_GREEN_SIZE HEX: 8D51
+CONSTANT: GL_RENDERBUFFER_BLUE_SIZE HEX: 8D52
+CONSTANT: GL_RENDERBUFFER_ALPHA_SIZE HEX: 8D53
+CONSTANT: GL_RENDERBUFFER_DEPTH_SIZE HEX: 8D54
+CONSTANT: GL_RENDERBUFFER_STENCIL_SIZE HEX: 8D55
+
+CONSTANT: GL_READ_FRAMEBUFFER HEX: 8CA8
+CONSTANT: GL_DRAW_FRAMEBUFFER HEX: 8CA9
+
+ALIAS: GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING
+CONSTANT: GL_READ_FRAMEBUFFER_BINDING HEX: 8CAA
+
+CONSTANT: GL_RENDERBUFFER_SAMPLES HEX: 8CAB
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE HEX: 8D56
+CONSTANT: GL_MAX_SAMPLES HEX: 8D57
+
+CONSTANT: GL_DEPTH_STENCIL HEX: 84F9
+CONSTANT: GL_UNSIGNED_INT_24_8 HEX: 84FA
+CONSTANT: GL_DEPTH24_STENCIL8 HEX: 88F0
+CONSTANT: GL_TEXTURE_STENCIL_SIZE HEX: 88F1
+
+CONSTANT: GL_RGBA32UI HEX: 8D70
+CONSTANT: GL_RGB32UI HEX: 8D71
+
+CONSTANT: GL_RGBA16UI HEX: 8D76
+CONSTANT: GL_RGB16UI HEX: 8D77
+
+CONSTANT: GL_RGBA8UI HEX: 8D7C
+CONSTANT: GL_RGB8UI HEX: 8D7D
+
+CONSTANT: GL_RGBA32I HEX: 8D82
+CONSTANT: GL_RGB32I HEX: 8D83
+
+CONSTANT: GL_RGBA16I HEX: 8D88
+CONSTANT: GL_RGB16I HEX: 8D89
+
+CONSTANT: GL_RGBA8I HEX: 8D8E
+CONSTANT: GL_RGB8I HEX: 8D8F
+
+CONSTANT: GL_RED_INTEGER HEX: 8D94
+CONSTANT: GL_GREEN_INTEGER HEX: 8D95
+CONSTANT: GL_BLUE_INTEGER HEX: 8D96
+CONSTANT: GL_RGB_INTEGER HEX: 8D98
+CONSTANT: GL_RGBA_INTEGER HEX: 8D99
+CONSTANT: GL_BGR_INTEGER HEX: 8D9A
+CONSTANT: GL_BGRA_INTEGER HEX: 8D9B
+
+CONSTANT: GL_FLOAT_32_UNSIGNED_INT_24_8_REV HEX: 8DAD
+
+CONSTANT: GL_TEXTURE_1D_ARRAY HEX: 8C18
+CONSTANT: GL_TEXTURE_2D_ARRAY HEX: 8C1A
+
+CONSTANT: GL_PROXY_TEXTURE_2D_ARRAY HEX: 8C1B
+
+CONSTANT: GL_PROXY_TEXTURE_1D_ARRAY HEX: 8C19
+
+CONSTANT: GL_TEXTURE_BINDING_1D_ARRAY HEX: 8C1C
+CONSTANT: GL_TEXTURE_BINDING_2D_ARRAY HEX: 8C1D
+CONSTANT: GL_MAX_ARRAY_TEXTURE_LAYERS HEX: 88FF
+
+CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER HEX: 8CD4
+
+CONSTANT: GL_SAMPLER_1D_ARRAY HEX: 8DC0
+CONSTANT: GL_SAMPLER_2D_ARRAY HEX: 8DC1
+CONSTANT: GL_SAMPLER_1D_ARRAY_SHADOW HEX: 8DC3
+CONSTANT: GL_SAMPLER_2D_ARRAY_SHADOW HEX: 8DC4
+
+CONSTANT: GL_COMPRESSED_RED_RGTC1 HEX: 8DBB
+CONSTANT: GL_COMPRESSED_SIGNED_RED_RGTC1 HEX: 8DBC
+CONSTANT: GL_COMPRESSED_RG_RGTC2 HEX: 8DBD
+CONSTANT: GL_COMPRESSED_SIGNED_RG_RGTC2 HEX: 8DBE
+
+CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER HEX: 8C8E
+CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_START HEX: 8C84
+CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_SIZE HEX: 8C85
+CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_BINDING HEX: 8C8F
+CONSTANT: GL_INTERLEAVED_ATTRIBS HEX: 8C8C
+CONSTANT: GL_SEPARATE_ATTRIBS HEX: 8C8D
+CONSTANT: GL_PRIMITIVES_GENERATED HEX: 8C87
+CONSTANT: GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN HEX: 8C88
+CONSTANT: GL_RASTERIZER_DISCARD HEX: 8C89
+CONSTANT: GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS HEX: 8C8A
+CONSTANT: GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS HEX: 8C8B
+CONSTANT: GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS HEX: 8C80
+CONSTANT: GL_TRANSFORM_FEEDBACK_VARYINGS HEX: 8C83
+CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_MODE HEX: 8C7F
+CONSTANT: GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH HEX: 8C76
+
+CONSTANT: GL_FRAMEBUFFER_SRGB HEX: 8DB9
+
+CONSTANT: GL_MAJOR_VERSION HEX: 821B
+CONSTANT: GL_MINOR_VERSION HEX: 821C
+CONSTANT: GL_NUM_EXTENSIONS HEX: 821D
+CONSTANT: GL_CONTEXT_FLAGS HEX: 821E
+CONSTANT: GL_INDEX HEX: 8222
+CONSTANT: GL_DEPTH_BUFFER HEX: 8223
+CONSTANT: GL_STENCIL_BUFFER HEX: 8224
+CONSTANT: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT HEX: 0001
+
+ALIAS: GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_R_TO_TEXTURE
+ALIAS: GL_MAX_VARYING_COMPONENTS GL_MAX_VARYING_FLOATS
+ALIAS: GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES
+ALIAS: GL_CLIP_DISTANCE0 GL_CLIP_PLANE0
+ALIAS: GL_CLIP_DISTANCE1 GL_CLIP_PLANE1
+ALIAS: GL_CLIP_DISTANCE2 GL_CLIP_PLANE2
+ALIAS: GL_CLIP_DISTANCE3 GL_CLIP_PLANE3
+ALIAS: GL_CLIP_DISTANCE4 GL_CLIP_PLANE4
+ALIAS: GL_CLIP_DISTANCE5 GL_CLIP_PLANE5
+
+GL-FUNCTION: void glVertexAttribIPointer { glVertexAttribIPointerEXT } ( GLuint index, GLint size, GLenum type, GLsizei stride, void* pointer ) ;
+
+GL-FUNCTION: void glGetVertexAttribIiv { glGetVertexAttribIivEXT } ( GLuint index, GLenum pname, GLint* params ) ;
+GL-FUNCTION: void glGetVertexAttribIuiv { glGetVertexAttribIuivEXT } ( GLuint index, GLenum pname, GLuint* params ) ;
+
+GL-FUNCTION: void glUniform1ui { glUniform1uiEXT } ( GLint location, GLuint v0 ) ;
+GL-FUNCTION: void glUniform2ui { glUniform2uiEXT } ( GLint location, GLuint v0, GLuint v1 ) ;
+GL-FUNCTION: void glUniform3ui { glUniform3uiEXT } ( GLint location, GLuint v0, GLuint v1, GLuint v2 ) ;
+GL-FUNCTION: void glUniform4ui { glUniform4uiEXT } ( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) ;
+
+GL-FUNCTION: void glUniform1uiv { glUniform1uivEXT } ( GLint location, GLsizei count, GLuint* value ) ;
+GL-FUNCTION: void glUniform2uiv { glUniform2uivEXT } ( GLint location, GLsizei count, GLuint* value ) ;
+GL-FUNCTION: void glUniform3uiv { glUniform3uivEXT } ( GLint location, GLsizei count, GLuint* value ) ;
+GL-FUNCTION: void glUniform4uiv { glUniform4uivEXT } ( GLint location, GLsizei count, GLuint* value ) ;
+
+GL-FUNCTION: void glGetUniformuiv { glGetUniformuivEXT } ( GLuint program, GLint location, GLuint* params ) ;
+
+GL-FUNCTION: void glBindFragDataLocation { glBindFragDataLocationEXT } ( GLuint program, GLuint colorNumber, GLchar* name ) ;
+GL-FUNCTION: GLint glGetFragDataLocation { glGetFragDataLocationEXT } ( GLuint program, GLchar* name ) ;
+
+GL-FUNCTION: void glBeginConditionalRender { glBeginConditionalRenderNV } ( GLuint id, GLenum mode ) ;
+GL-FUNCTION: void glEndConditionalRender { glEndConditionalRenderNV } ( ) ;
+
+GL-FUNCTION: void glBindVertexArray { glBindVertexArrayAPPLE } ( GLuint array ) ;
+GL-FUNCTION: void glDeleteVertexArrays { glDeleteVertexArraysAPPLE } ( GLsizei n, GLuint* arrays ) ;
+GL-FUNCTION: void glGenVertexArrays { glGenVertexArraysAPPLE } ( GLsizei n, GLuint* arrays ) ;
+GL-FUNCTION: GLboolean glIsVertexArray { glIsVertexArrayAPPLE } ( GLuint array ) ;
+
+GL-FUNCTION: void glClampColor { glClampColorARB } ( GLenum target, GLenum clamp ) ;
+
+GL-FUNCTION: void glBindFramebuffer { glBindFramebufferEXT } ( GLenum target, GLuint framebuffer ) ;
+GL-FUNCTION: void glBindRenderbuffer { glBindRenderbufferEXT } ( GLenum target, GLuint renderbuffer ) ;
+GL-FUNCTION: GLenum glCheckFramebufferStatus { glCheckFramebufferStatusEXT } ( GLenum target ) ;
+GL-FUNCTION: void glDeleteFramebuffers { glDeleteFramebuffersEXT } ( GLsizei n, GLuint* framebuffers ) ;
+GL-FUNCTION: void glDeleteRenderbuffers { glDeleteRenderbuffersEXT } ( GLsizei n, GLuint* renderbuffers ) ;
+GL-FUNCTION: void glFramebufferRenderbuffer { glFramebufferRenderbufferEXT } ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ) ;
+GL-FUNCTION: void glFramebufferTexture1D { glFramebufferTexture1DEXT } ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) ;
+GL-FUNCTION: void glFramebufferTexture2D { glFramebufferTexture2DEXT } ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) ;
+GL-FUNCTION: void glFramebufferTexture3D { glFramebufferTexture3DEXT } ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset ) ;
+GL-FUNCTION: void glFramebufferTextureLayer { glFramebufferTextureLayerEXT }
+ ( GLenum target, GLenum attachment,
+ GLuint texture, GLint level, GLint layer ) ;
+GL-FUNCTION: void glGenFramebuffers { glGenFramebuffersEXT } ( GLsizei n, GLuint* framebuffers ) ;
+GL-FUNCTION: void glGenRenderbuffers { glGenRenderbuffersEXT } ( GLsizei n, GLuint* renderbuffers ) ;
+GL-FUNCTION: void glGenerateMipmap { glGenerateMipmapEXT } ( GLenum target ) ;
+GL-FUNCTION: void glGetFramebufferAttachmentParameteriv { glGetFramebufferAttachmentParameterivEXT } ( GLenum target, GLenum attachment, GLenum pname, GLint* params ) ;
+GL-FUNCTION: void glGetRenderbufferParameteriv { glGetRenderbufferParameterivEXT } ( GLenum target, GLenum pname, GLint* params ) ;
+GL-FUNCTION: GLboolean glIsFramebuffer { glIsFramebufferEXT } ( GLuint framebuffer ) ;
+GL-FUNCTION: GLboolean glIsRenderbuffer { glIsRenderbufferEXT } ( GLuint renderbuffer ) ;
+GL-FUNCTION: void glRenderbufferStorage { glRenderbufferStorageEXT } ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ) ;
+
+GL-FUNCTION: void glBlitFramebuffer { glBlitFramebufferEXT }
+ ( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter ) ;
-CONSTANT: GL_READ_FRAMEBUFFER_EXT HEX: 8CA8
-CONSTANT: GL_DRAW_FRAMEBUFFER_EXT HEX: 8CA9
+GL-FUNCTION: void glRenderbufferStorageMultisample { glRenderbufferStorageMultisampleEXT } (
+ GLenum target, GLsizei samples,
+ GLenum internalformat,
+ GLsizei width, GLsizei height ) ;
-ALIAS: GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT
-CONSTANT: GL_READ_FRAMEBUFFER_BINDING_EXT HEX: 8CAA
+GL-FUNCTION: void glTexParameterIiv { glTexParameterIivEXT } ( GLenum target, GLenum pname, GLint* params ) ;
+GL-FUNCTION: void glTexParameterIuiv { glTexParameterIuivEXT } ( GLenum target, GLenum pname, GLuint* params ) ;
+GL-FUNCTION: void glGetTexParameterIiv { glGetTexParameterIivEXT } ( GLenum target, GLenum pname, GLint* params ) ;
+GL-FUNCTION: void glGetTexParameterIuiv { glGetTexParameterIuivEXT } ( GLenum target, GLenum pname, GLuint* params ) ;
+GL-FUNCTION: void glColorMaski { glColorMaskIndexedEXT }
+ ( GLuint buf, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) ;
-! GL_EXT_framebuffer_multisample
+GL-FUNCTION: void glGetBooleani_v { glGetBooleanIndexedvEXT } ( GLenum value, GLuint index, GLboolean* data ) ;
+GL-FUNCTION: void glGetIntegeri_v { glGetIntegerIndexedvEXT } ( GLenum value, GLuint index, GLint* data ) ;
-GL-FUNCTION: void glRenderbufferStorageMultisampleEXT { } (
- GLenum target, GLsizei samples,
- GLenum internalformat,
- GLsizei width, GLsizei height ) ;
+GL-FUNCTION: void glEnablei { glEnableIndexedEXT } ( GLenum target, GLuint index ) ;
-CONSTANT: GL_RENDERBUFFER_SAMPLES_EXT HEX: 8CAB
-CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT HEX: 8D56
-CONSTANT: GL_MAX_SAMPLES_EXT HEX: 8D57
+GL-FUNCTION: void glDisablei { glDisableIndexedEXT } ( GLenum target, GLuint index ) ;
+GL-FUNCTION: GLboolean glIsEnabledi { glIsEnabledIndexedEXT } ( GLenum target, GLuint index ) ;
-! GL_ARB_texture_float
+GL-FUNCTION: void glBindBufferRange { glBindBufferRangeEXT } ( GLenum target, GLuint index, GLuint buffer,
+ GLintptr offset, GLsizeiptr size ) ;
+GL-FUNCTION: void glBindBufferBase { glBindBufferBaseEXT } ( GLenum target, GLuint index, GLuint buffer ) ;
+GL-FUNCTION: void glBeginTransformFeedback { glBeginTransformFeedbackEXT } ( GLenum primitiveMode ) ;
+GL-FUNCTION: void glEndTransformFeedback { glEndTransformFeedbackEXT } ( ) ;
-CONSTANT: GL_RGBA32F_ARB HEX: 8814
-CONSTANT: GL_RGB32F_ARB HEX: 8815
-CONSTANT: GL_ALPHA32F_ARB HEX: 8816
-CONSTANT: GL_INTENSITY32F_ARB HEX: 8817
-CONSTANT: GL_LUMINANCE32F_ARB HEX: 8818
-CONSTANT: GL_LUMINANCE_ALPHA32F_ARB HEX: 8819
-CONSTANT: GL_RGBA16F_ARB HEX: 881A
-CONSTANT: GL_RGB16F_ARB HEX: 881B
-CONSTANT: GL_ALPHA16F_ARB HEX: 881C
-CONSTANT: GL_INTENSITY16F_ARB HEX: 881D
-CONSTANT: GL_LUMINANCE16F_ARB HEX: 881E
-CONSTANT: GL_LUMINANCE_ALPHA16F_ARB HEX: 881F
-CONSTANT: GL_TEXTURE_RED_TYPE_ARB HEX: 8C10
-CONSTANT: GL_TEXTURE_GREEN_TYPE_ARB HEX: 8C11
-CONSTANT: GL_TEXTURE_BLUE_TYPE_ARB HEX: 8C12
-CONSTANT: GL_TEXTURE_ALPHA_TYPE_ARB HEX: 8C13
-CONSTANT: GL_TEXTURE_LUMINANCE_TYPE_ARB HEX: 8C14
-CONSTANT: GL_TEXTURE_INTENSITY_TYPE_ARB HEX: 8C15
-CONSTANT: GL_TEXTURE_DEPTH_TYPE_ARB HEX: 8C16
-CONSTANT: GL_UNSIGNED_NORMALIZED_ARB HEX: 8C17
-
-
-! GL_EXT_gpu_shader4
-
-
-GL-FUNCTION: void glVertexAttribI1iEXT { } ( GLuint index, GLint x ) ;
-GL-FUNCTION: void glVertexAttribI2iEXT { } ( GLuint index, GLint x, GLint y ) ;
-GL-FUNCTION: void glVertexAttribI3iEXT { } ( GLuint index, GLint x, GLint y, GLint z ) ;
-GL-FUNCTION: void glVertexAttribI4iEXT { } ( GLuint index, GLint x, GLint y, GLint z, GLint w ) ;
-
-GL-FUNCTION: void glVertexAttribI1uiEXT { } ( GLuint index, GLuint x ) ;
-GL-FUNCTION: void glVertexAttribI2uiEXT { } ( GLuint index, GLuint x, GLuint y ) ;
-GL-FUNCTION: void glVertexAttribI3uiEXT { } ( GLuint index, GLuint x, GLuint y, GLuint z ) ;
-GL-FUNCTION: void glVertexAttribI4uiEXT { } ( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ) ;
-
-GL-FUNCTION: void glVertexAttribI1ivEXT { } ( GLuint index, GLint* v ) ;
-GL-FUNCTION: void glVertexAttribI2ivEXT { } ( GLuint index, GLint* v ) ;
-GL-FUNCTION: void glVertexAttribI3ivEXT { } ( GLuint index, GLint* v ) ;
-GL-FUNCTION: void glVertexAttribI4ivEXT { } ( GLuint index, GLint* v ) ;
-
-GL-FUNCTION: void glVertexAttribI1uivEXT { } ( GLuint index, GLuint* v ) ;
-GL-FUNCTION: void glVertexAttribI2uivEXT { } ( GLuint index, GLuint* v ) ;
-GL-FUNCTION: void glVertexAttribI3uivEXT { } ( GLuint index, GLuint* v ) ;
-GL-FUNCTION: void glVertexAttribI4uivEXT { } ( GLuint index, GLuint* v ) ;
-
-GL-FUNCTION: void glVertexAttribI4bvEXT { } ( GLuint index, GLbyte* v ) ;
-GL-FUNCTION: void glVertexAttribI4svEXT { } ( GLuint index, GLshort* v ) ;
-GL-FUNCTION: void glVertexAttribI4ubvEXT { } ( GLuint index, GLubyte* v ) ;
-GL-FUNCTION: void glVertexAttribI4usvEXT { } ( GLuint index, GLushort* v ) ;
-
-GL-FUNCTION: void glVertexAttribIPointerEXT { } ( GLuint index, GLint size, GLenum type, GLsizei stride, void* pointer ) ;
-
-GL-FUNCTION: void glGetVertexAttribIivEXT { } ( GLuint index, GLenum pname, GLint* params ) ;
-GL-FUNCTION: void glGetVertexAttribIuivEXT { } ( GLuint index, GLenum pname, GLuint* params ) ;
-
-GL-FUNCTION: void glUniform1uiEXT { } ( GLint location, GLuint v0 ) ;
-GL-FUNCTION: void glUniform2uiEXT { } ( GLint location, GLuint v0, GLuint v1 ) ;
-GL-FUNCTION: void glUniform3uiEXT { } ( GLint location, GLuint v0, GLuint v1, GLuint v2 ) ;
-GL-FUNCTION: void glUniform4uiEXT { } ( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) ;
-
-GL-FUNCTION: void glUniform1uivEXT { } ( GLint location, GLsizei count, GLuint* value ) ;
-GL-FUNCTION: void glUniform2uivEXT { } ( GLint location, GLsizei count, GLuint* value ) ;
-GL-FUNCTION: void glUniform3uivEXT { } ( GLint location, GLsizei count, GLuint* value ) ;
-GL-FUNCTION: void glUniform4uivEXT { } ( GLint location, GLsizei count, GLuint* value ) ;
-
-GL-FUNCTION: void glGetUniformuivEXT { } ( GLuint program, GLint location, GLuint* params ) ;
-
-GL-FUNCTION: void glBindFragDataLocationEXT { } ( GLuint program, GLuint colorNumber, GLchar* name ) ;
-GL-FUNCTION: GLint glGetFragDataLocationEXT { } ( GLuint program, GLchar* name ) ;
-
-CONSTANT: GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT HEX: 88FD
-CONSTANT: GL_SAMPLER_1D_ARRAY_EXT HEX: 8DC0
-CONSTANT: GL_SAMPLER_2D_ARRAY_EXT HEX: 8DC1
-CONSTANT: GL_SAMPLER_BUFFER_EXT HEX: 8DC2
-CONSTANT: GL_SAMPLER_1D_ARRAY_SHADOW_EXT HEX: 8DC3
-CONSTANT: GL_SAMPLER_2D_ARRAY_SHADOW_EXT HEX: 8DC4
-CONSTANT: GL_SAMPLER_CUBE_SHADOW_EXT HEX: 8DC5
-CONSTANT: GL_UNSIGNED_INT_VEC2_EXT HEX: 8DC6
-CONSTANT: GL_UNSIGNED_INT_VEC3_EXT HEX: 8DC7
-CONSTANT: GL_UNSIGNED_INT_VEC4_EXT HEX: 8DC8
-CONSTANT: GL_INT_SAMPLER_1D_EXT HEX: 8DC9
-CONSTANT: GL_INT_SAMPLER_2D_EXT HEX: 8DCA
-CONSTANT: GL_INT_SAMPLER_3D_EXT HEX: 8DCB
-CONSTANT: GL_INT_SAMPLER_CUBE_EXT HEX: 8DCC
-CONSTANT: GL_INT_SAMPLER_2D_RECT_EXT HEX: 8DCD
-CONSTANT: GL_INT_SAMPLER_1D_ARRAY_EXT HEX: 8DCE
-CONSTANT: GL_INT_SAMPLER_2D_ARRAY_EXT HEX: 8DCF
-CONSTANT: GL_INT_SAMPLER_BUFFER_EXT HEX: 8DD0
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_1D_EXT HEX: 8DD1
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_2D_EXT HEX: 8DD2
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_3D_EXT HEX: 8DD3
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_CUBE_EXT HEX: 8DD4
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT HEX: 8DD5
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT HEX: 8DD6
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT HEX: 8DD7
-CONSTANT: GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT HEX: 8DD8
-CONSTANT: GL_MIN_PROGRAM_TEXEL_OFFSET_EXT HEX: 8904
-CONSTANT: GL_MAX_PROGRAM_TEXEL_OFFSET_EXT HEX: 8905
+GL-FUNCTION: void glTransformFeedbackVaryings { glTransformFeedbackVaryingsEXT } ( GLuint program, GLsizei count,
+ GLchar** varyings, GLenum bufferMode ) ;
+GL-FUNCTION: void glGetTransformFeedbackVarying { glGetTransformFeedbackVaryingEXT } ( GLuint program, GLuint index,
+ GLsizei bufSize, GLsizei* length,
+ GLsizei* size, GLenum* type, GLchar* name ) ;
+
+GL-FUNCTION: void glClearBufferiv { } ( GLenum buffer, GLint drawbuffer, GLint* value ) ;
+GL-FUNCTION: void glClearBufferuiv { } ( GLenum buffer, GLint drawbuffer, GLuint* value ) ;
+GL-FUNCTION: void glClearBufferfv { } ( GLenum buffer, GLint drawbuffer, GLfloat* value ) ;
+GL-FUNCTION: void glClearBufferfi { } ( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) ;
+
+GL-FUNCTION: GLubyte* glGetStringi { } ( GLenum value, GLuint index ) ;
+
+GL-FUNCTION: GLvoid* glMapBufferRange { } ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) ;
+GL-FUNCTION: void glFlushMappedBufferRange { glFlushMappedBufferRangeAPPLE } ( GLenum target, GLintptr offset, GLsizeiptr size ) ;
+
+
+! OpenGL 3.1
+
+CONSTANT: GL_RED_SNORM HEX: 8F90
+CONSTANT: GL_RG_SNORM HEX: 8F91
+CONSTANT: GL_RGB_SNORM HEX: 8F92
+CONSTANT: GL_RGBA_SNORM HEX: 8F93
+CONSTANT: GL_R8_SNORM HEX: 8F94
+CONSTANT: GL_RG8_SNORM HEX: 8F95
+CONSTANT: GL_RGB8_SNORM HEX: 8F96
+CONSTANT: GL_RGBA8_SNORM HEX: 8F97
+CONSTANT: GL_R16_SNORM HEX: 8F98
+CONSTANT: GL_RG16_SNORM HEX: 8F99
+CONSTANT: GL_RGB16_SNORM HEX: 8F9A
+CONSTANT: GL_RGBA16_SNORM HEX: 8F9B
+CONSTANT: GL_SIGNED_NORMALIZED HEX: 8F9C
+
+CONSTANT: GL_PRIMITIVE_RESTART HEX: 8F9D
+CONSTANT: GL_PRIMITIVE_RESTART_INDEX HEX: 8F9E
+
+CONSTANT: GL_COPY_READ_BUFFER HEX: 8F36
+CONSTANT: GL_COPY_WRITE_BUFFER HEX: 8F37
+
+CONSTANT: GL_UNIFORM_BUFFER HEX: 8A11
+CONSTANT: GL_UNIFORM_BUFFER_BINDING HEX: 8A28
+CONSTANT: GL_UNIFORM_BUFFER_START HEX: 8A29
+CONSTANT: GL_UNIFORM_BUFFER_SIZE HEX: 8A2A
+CONSTANT: GL_MAX_VERTEX_UNIFORM_BLOCKS HEX: 8A2B
+CONSTANT: GL_MAX_GEOMETRY_UNIFORM_BLOCKS HEX: 8A2C
+CONSTANT: GL_MAX_FRAGMENT_UNIFORM_BLOCKS HEX: 8A2D
+CONSTANT: GL_MAX_COMBINED_UNIFORM_BLOCKS HEX: 8A2E
+CONSTANT: GL_MAX_UNIFORM_BUFFER_BINDINGS HEX: 8A2F
+CONSTANT: GL_MAX_UNIFORM_BLOCK_SIZE HEX: 8A30
+CONSTANT: GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS HEX: 8A31
+CONSTANT: GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS HEX: 8A32
+CONSTANT: GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS HEX: 8A33
+CONSTANT: GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT HEX: 8A34
+CONSTANT: GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH HEX: 8A35
+CONSTANT: GL_ACTIVE_UNIFORM_BLOCKS HEX: 8A36
+CONSTANT: GL_UNIFORM_TYPE HEX: 8A37
+CONSTANT: GL_UNIFORM_SIZE HEX: 8A38
+CONSTANT: GL_UNIFORM_NAME_LENGTH HEX: 8A39
+CONSTANT: GL_UNIFORM_BLOCK_INDEX HEX: 8A3A
+CONSTANT: GL_UNIFORM_OFFSET HEX: 8A3B
+CONSTANT: GL_UNIFORM_ARRAY_STRIDE HEX: 8A3C
+CONSTANT: GL_UNIFORM_MATRIX_STRIDE HEX: 8A3D
+CONSTANT: GL_UNIFORM_IS_ROW_MAJOR HEX: 8A3E
+CONSTANT: GL_UNIFORM_BLOCK_BINDING HEX: 8A3F
+CONSTANT: GL_UNIFORM_BLOCK_DATA_SIZE HEX: 8A40
+CONSTANT: GL_UNIFORM_BLOCK_NAME_LENGTH HEX: 8A41
+CONSTANT: GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS HEX: 8A42
+CONSTANT: GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES HEX: 8A43
+CONSTANT: GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER HEX: 8A44
+CONSTANT: GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER HEX: 8A45
+CONSTANT: GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER HEX: 8A46
+CONSTANT: GL_INVALID_INDEX HEX: FFFFFFFF
+
+CONSTANT: GL_TEXTURE_RECTANGLE HEX: 84F5
+CONSTANT: GL_TEXTURE_BINDING_RECTANGLE HEX: 84F6
+CONSTANT: GL_PROXY_TEXTURE_RECTANGLE HEX: 84F7
+CONSTANT: GL_MAX_RECTANGLE_TEXTURE_SIZE HEX: 84F8
+CONSTANT: GL_SAMPLER_2D_RECT HEX: 8B63
+CONSTANT: GL_SAMPLER_2D_RECT_SHADOW HEX: 8B64
+
+CONSTANT: GL_SAMPLER_BUFFER HEX: 8DC2
+CONSTANT: GL_INT_SAMPLER_BUFFER HEX: 8DD0
+CONSTANT: GL_UNSIGNED_INT_SAMPLER_BUFFER HEX: 8DD8
+
+CONSTANT: GL_TEXTURE_BUFFER HEX: 8C2A
+
+CONSTANT: GL_MAX_TEXTURE_BUFFER_SIZE HEX: 8C2B
+CONSTANT: GL_TEXTURE_BINDING_BUFFER HEX: 8C2C
+CONSTANT: GL_TEXTURE_BUFFER_DATA_STORE_BINDING HEX: 8C2D
+CONSTANT: GL_TEXTURE_BUFFER_FORMAT HEX: 8C2E
+
+GL-FUNCTION: void glDrawArraysInstanced { glDrawArraysInstancedARB } ( GLenum mode, GLint first, GLsizei count, GLsizei primcount ) ;
+GL-FUNCTION: void glDrawElementsInstanced { glDrawElementsInstancedARB } ( GLenum mode, GLsizei count, GLenum type, GLvoid* indices, GLsizei primcount ) ;
+GL-FUNCTION: void glTexBuffer { glTexBufferEXT } ( GLenum target, GLenum internalformat, GLuint buffer ) ;
+GL-FUNCTION: void glPrimitiveRestartIndex { } ( GLuint index ) ;
+
+GL-FUNCTION: void glGetUniformIndices { } ( GLuint program, GLsizei uniformCount, GLchar** uniformNames, GLuint* uniformIndices ) ;
+GL-FUNCTION: void glGetActiveUniformsiv { } ( GLuint program, GLsizei uniformCount, GLuint* uniformIndices, GLenum pname, GLint* params ) ;
+GL-FUNCTION: void glGetActiveUniformName { } ( GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName ) ;
+GL-FUNCTION: GLuint glGetUniformBlockIndex { } ( GLuint program, GLchar* uniformBlockName ) ;
+GL-FUNCTION: void glGetActiveUniformBlockiv { } ( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params ) ;
+GL-FUNCTION: void glGetActiveUniformBlockName { } ( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName ) ;
+GL-FUNCTION: void glUniformBlockBinding { } ( GLuint buffer, GLuint uniformBlockIndex, GLuint uniformBlockBinding ) ;
+
+GL-FUNCTION: void glCopyBufferSubData { glCopyBufferSubDataEXT } ( GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size ) ;
! GL_EXT_geometry_shader4
GL-FUNCTION: void glProgramParameteriEXT { } ( GLuint program, GLenum pname, GLint value ) ;
GL-FUNCTION: void glFramebufferTextureEXT { } ( GLenum target, GLenum attachment,
GLuint texture, GLint level ) ;
-GL-FUNCTION: void glFramebufferTextureLayerEXT { } ( GLenum target, GLenum attachment,
- GLuint texture, GLint level, GLint layer ) ;
-GL-FUNCTION: void glFramebufferTextureFaceEXT { } ( GLenum target, GLenum attachment,
- GLuint texture, GLint level, GLenum face ) ;
CONSTANT: GL_GEOMETRY_SHADER_EXT HEX: 8DD9
CONSTANT: GL_GEOMETRY_VERTICES_OUT_EXT HEX: 8DDA
CONSTANT: GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT HEX: 8C29
CONSTANT: GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT HEX: 8DDD
CONSTANT: GL_MAX_VERTEX_VARYING_COMPONENTS_EXT HEX: 8DDE
-CONSTANT: GL_MAX_VARYING_COMPONENTS_EXT HEX: 8B4B
CONSTANT: GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT HEX: 8DDF
CONSTANT: GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT HEX: 8DE0
CONSTANT: GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT HEX: 8DE1
CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT HEX: 8DA8
CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT HEX: 8DA9
CONSTANT: GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT HEX: 8DA7
-ALIAS: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT
CONSTANT: GL_PROGRAM_POINT_SIZE_EXT HEX: 8642
-! GL_EXT_texture_integer
+! GL_EXT_framebuffer_object
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT HEX: 8CD9
+CONSTANT: GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT HEX: 8CDA
-GL-FUNCTION: void glClearColorIiEXT { } ( GLint r, GLint g, GLint b, GLint a ) ;
-GL-FUNCTION: void glClearColorIuiEXT { } ( GLuint r, GLuint g, GLuint b, GLuint a ) ;
-GL-FUNCTION: void glTexParameterIivEXT { } ( GLenum target, GLenum pname, GLint* params ) ;
-GL-FUNCTION: void glTexParameterIuivEXT { } ( GLenum target, GLenum pname, GLuint* params ) ;
-GL-FUNCTION: void glGetTexParameterIivEXT { } ( GLenum target, GLenum pname, GLint* params ) ;
-GL-FUNCTION: void glGetTexParameterIuivEXT { } ( GLenum target, GLenum pname, GLuint* params ) ;
+! GL_ARB_texture_float
+
+CONSTANT: GL_ALPHA32F_ARB HEX: 8816
+CONSTANT: GL_INTENSITY32F_ARB HEX: 8817
+CONSTANT: GL_LUMINANCE32F_ARB HEX: 8818
+CONSTANT: GL_LUMINANCE_ALPHA32F_ARB HEX: 8819
+CONSTANT: GL_ALPHA16F_ARB HEX: 881C
+CONSTANT: GL_INTENSITY16F_ARB HEX: 881D
+CONSTANT: GL_LUMINANCE16F_ARB HEX: 881E
+CONSTANT: GL_LUMINANCE_ALPHA16F_ARB HEX: 881F
+CONSTANT: GL_TEXTURE_LUMINANCE_TYPE_ARB HEX: 8C14
+CONSTANT: GL_TEXTURE_INTENSITY_TYPE_ARB HEX: 8C15
-CONSTANT: GL_RGBA_INTEGER_MODE_EXT HEX: 8D9E
+! GL_EXT_texture_integer
-CONSTANT: GL_RGBA32UI_EXT HEX: 8D70
-CONSTANT: GL_RGB32UI_EXT HEX: 8D71
CONSTANT: GL_ALPHA32UI_EXT HEX: 8D72
CONSTANT: GL_INTENSITY32UI_EXT HEX: 8D73
CONSTANT: GL_LUMINANCE32UI_EXT HEX: 8D74
CONSTANT: GL_LUMINANCE_ALPHA32UI_EXT HEX: 8D75
-CONSTANT: GL_RGBA16UI_EXT HEX: 8D76
-CONSTANT: GL_RGB16UI_EXT HEX: 8D77
CONSTANT: GL_ALPHA16UI_EXT HEX: 8D78
CONSTANT: GL_INTENSITY16UI_EXT HEX: 8D79
CONSTANT: GL_LUMINANCE16UI_EXT HEX: 8D7A
CONSTANT: GL_LUMINANCE_ALPHA16UI_EXT HEX: 8D7B
-CONSTANT: GL_RGBA8UI_EXT HEX: 8D7C
-CONSTANT: GL_RGB8UI_EXT HEX: 8D7D
CONSTANT: GL_ALPHA8UI_EXT HEX: 8D7E
CONSTANT: GL_INTENSITY8UI_EXT HEX: 8D7F
CONSTANT: GL_LUMINANCE8UI_EXT HEX: 8D80
CONSTANT: GL_LUMINANCE_ALPHA8UI_EXT HEX: 8D81
-CONSTANT: GL_RGBA32I_EXT HEX: 8D82
-CONSTANT: GL_RGB32I_EXT HEX: 8D83
CONSTANT: GL_ALPHA32I_EXT HEX: 8D84
CONSTANT: GL_INTENSITY32I_EXT HEX: 8D85
CONSTANT: GL_LUMINANCE32I_EXT HEX: 8D86
CONSTANT: GL_LUMINANCE_ALPHA32I_EXT HEX: 8D87
-CONSTANT: GL_RGBA16I_EXT HEX: 8D88
-CONSTANT: GL_RGB16I_EXT HEX: 8D89
CONSTANT: GL_ALPHA16I_EXT HEX: 8D8A
CONSTANT: GL_INTENSITY16I_EXT HEX: 8D8B
CONSTANT: GL_LUMINANCE16I_EXT HEX: 8D8C
CONSTANT: GL_LUMINANCE_ALPHA16I_EXT HEX: 8D8D
-CONSTANT: GL_RGBA8I_EXT HEX: 8D8E
-CONSTANT: GL_RGB8I_EXT HEX: 8D8F
CONSTANT: GL_ALPHA8I_EXT HEX: 8D90
CONSTANT: GL_INTENSITY8I_EXT HEX: 8D91
CONSTANT: GL_LUMINANCE8I_EXT HEX: 8D92
CONSTANT: GL_LUMINANCE_ALPHA8I_EXT HEX: 8D93
-CONSTANT: GL_RED_INTEGER_EXT HEX: 8D94
-CONSTANT: GL_GREEN_INTEGER_EXT HEX: 8D95
-CONSTANT: GL_BLUE_INTEGER_EXT HEX: 8D96
CONSTANT: GL_ALPHA_INTEGER_EXT HEX: 8D97
-CONSTANT: GL_RGB_INTEGER_EXT HEX: 8D98
-CONSTANT: GL_RGBA_INTEGER_EXT HEX: 8D99
-CONSTANT: GL_BGR_INTEGER_EXT HEX: 8D9A
-CONSTANT: GL_BGRA_INTEGER_EXT HEX: 8D9B
-CONSTANT: GL_LUMINANCE_INTEGER_EXT HEX: 8D9C
-CONSTANT: GL_LUMINANCE_ALPHA_INTEGER_EXT HEX: 8D9D
-
-
-! GL_EXT_transform_feedback
-
-
-GL-FUNCTION: void glBindBufferRangeEXT { } ( GLenum target, GLuint index, GLuint buffer,
- GLintptr offset, GLsizeiptr size ) ;
-GL-FUNCTION: void glBindBufferOffsetEXT { } ( GLenum target, GLuint index, GLuint buffer,
- GLintptr offset ) ;
-GL-FUNCTION: void glBindBufferBaseEXT { } ( GLenum target, GLuint index, GLuint buffer ) ;
-
-GL-FUNCTION: void glBeginTransformFeedbackEXT { } ( GLenum primitiveMode ) ;
-GL-FUNCTION: void glEndTransformFeedbackEXT { } ( ) ;
-
-GL-FUNCTION: void glTransformFeedbackVaryingsEXT { } ( GLuint program, GLsizei count,
- GLchar** varyings, GLenum bufferMode ) ;
-GL-FUNCTION: void glGetTransformFeedbackVaryingEXT { } ( GLuint program, GLuint index,
- GLsizei bufSize, GLsizei* length,
- GLsizei* size, GLenum* type, GLchar* name ) ;
+CONSTANT: GL_LUMINANCE_INTEGER_EXT HEX: 8D9C
+CONSTANT: GL_LUMINANCE_ALPHA_INTEGER_EXT HEX: 8D9D
-GL-FUNCTION: void glGetIntegerIndexedvEXT { } ( GLenum param, GLuint index, GLint* values ) ;
-GL-FUNCTION: void glGetBooleanIndexedvEXT { } ( GLenum param, GLuint index, GLboolean* values ) ;
-
-CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_EXT HEX: 8C8E
-CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT HEX: 8C84
-CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT HEX: 8C85
-CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT HEX: 8C8F
-CONSTANT: GL_INTERLEAVED_ATTRIBS_EXT HEX: 8C8C
-CONSTANT: GL_SEPARATE_ATTRIBS_EXT HEX: 8C8D
-CONSTANT: GL_PRIMITIVES_GENERATED_EXT HEX: 8C87
-CONSTANT: GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT HEX: 8C88
-CONSTANT: GL_RASTERIZER_DISCARD_EXT HEX: 8C89
-CONSTANT: GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT HEX: 8C8A
-CONSTANT: GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT HEX: 8C8B
-CONSTANT: GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT HEX: 8C80
-CONSTANT: GL_TRANSFORM_FEEDBACK_VARYINGS_EXT HEX: 8C83
-CONSTANT: GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT HEX: 8C7F
-CONSTANT: GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT HEX: 8C76
+GL-FUNCTION: void glClearColorIiEXT { } ( GLint r, GLint g, GLint b, GLint a ) ;
+GL-FUNCTION: void glClearColorIuiEXT { } ( GLuint r, GLuint g, GLuint b, GLuint a ) ;
--- /dev/null
+! (c)2009 Joe Groff bsd license
+! This vocab only exports forward-compatible OpenGL 3.x symbols.
+! For legacy OpenGL and extensions, use opengl.gl
+
+QUALIFIED-WITH: opengl.gl gl
+IN: opengl.gl3
+
+ALIAS: GL_DEPTH_BUFFER_BIT gl:GL_DEPTH_BUFFER_BIT
+ALIAS: GL_STENCIL_BUFFER_BIT gl:GL_STENCIL_BUFFER_BIT
+ALIAS: GL_COLOR_BUFFER_BIT gl:GL_COLOR_BUFFER_BIT
+ALIAS: GL_FALSE gl:GL_FALSE
+ALIAS: GL_TRUE gl:GL_TRUE
+ALIAS: GL_POINTS gl:GL_POINTS
+ALIAS: GL_LINES gl:GL_LINES
+ALIAS: GL_LINE_LOOP gl:GL_LINE_LOOP
+ALIAS: GL_LINE_STRIP gl:GL_LINE_STRIP
+ALIAS: GL_TRIANGLES gl:GL_TRIANGLES
+ALIAS: GL_TRIANGLE_STRIP gl:GL_TRIANGLE_STRIP
+ALIAS: GL_TRIANGLE_FAN gl:GL_TRIANGLE_FAN
+ALIAS: GL_NEVER gl:GL_NEVER
+ALIAS: GL_LESS gl:GL_LESS
+ALIAS: GL_EQUAL gl:GL_EQUAL
+ALIAS: GL_LEQUAL gl:GL_LEQUAL
+ALIAS: GL_GREATER gl:GL_GREATER
+ALIAS: GL_NOTEQUAL gl:GL_NOTEQUAL
+ALIAS: GL_GEQUAL gl:GL_GEQUAL
+ALIAS: GL_ALWAYS gl:GL_ALWAYS
+ALIAS: GL_ZERO gl:GL_ZERO
+ALIAS: GL_ONE gl:GL_ONE
+ALIAS: GL_SRC_COLOR gl:GL_SRC_COLOR
+ALIAS: GL_ONE_MINUS_SRC_COLOR gl:GL_ONE_MINUS_SRC_COLOR
+ALIAS: GL_SRC_ALPHA gl:GL_SRC_ALPHA
+ALIAS: GL_ONE_MINUS_SRC_ALPHA gl:GL_ONE_MINUS_SRC_ALPHA
+ALIAS: GL_DST_ALPHA gl:GL_DST_ALPHA
+ALIAS: GL_ONE_MINUS_DST_ALPHA gl:GL_ONE_MINUS_DST_ALPHA
+ALIAS: GL_DST_COLOR gl:GL_DST_COLOR
+ALIAS: GL_ONE_MINUS_DST_COLOR gl:GL_ONE_MINUS_DST_COLOR
+ALIAS: GL_SRC_ALPHA_SATURATE gl:GL_SRC_ALPHA_SATURATE
+ALIAS: GL_NONE gl:GL_NONE
+ALIAS: GL_FRONT_LEFT gl:GL_FRONT_LEFT
+ALIAS: GL_FRONT_RIGHT gl:GL_FRONT_RIGHT
+ALIAS: GL_BACK_LEFT gl:GL_BACK_LEFT
+ALIAS: GL_BACK_RIGHT gl:GL_BACK_RIGHT
+ALIAS: GL_FRONT gl:GL_FRONT
+ALIAS: GL_BACK gl:GL_BACK
+ALIAS: GL_LEFT gl:GL_LEFT
+ALIAS: GL_RIGHT gl:GL_RIGHT
+ALIAS: GL_FRONT_AND_BACK gl:GL_FRONT_AND_BACK
+ALIAS: GL_NO_ERROR gl:GL_NO_ERROR
+ALIAS: GL_INVALID_ENUM gl:GL_INVALID_ENUM
+ALIAS: GL_INVALID_VALUE gl:GL_INVALID_VALUE
+ALIAS: GL_INVALID_OPERATION gl:GL_INVALID_OPERATION
+ALIAS: GL_OUT_OF_MEMORY gl:GL_OUT_OF_MEMORY
+ALIAS: GL_CW gl:GL_CW
+ALIAS: GL_CCW gl:GL_CCW
+ALIAS: GL_POINT_SIZE gl:GL_POINT_SIZE
+ALIAS: GL_POINT_SIZE_RANGE gl:GL_POINT_SIZE_RANGE
+ALIAS: GL_POINT_SIZE_GRANULARITY gl:GL_POINT_SIZE_GRANULARITY
+ALIAS: GL_LINE_SMOOTH gl:GL_LINE_SMOOTH
+ALIAS: GL_LINE_WIDTH gl:GL_LINE_WIDTH
+ALIAS: GL_LINE_WIDTH_RANGE gl:GL_LINE_WIDTH_RANGE
+ALIAS: GL_LINE_WIDTH_GRANULARITY gl:GL_LINE_WIDTH_GRANULARITY
+ALIAS: GL_POLYGON_SMOOTH gl:GL_POLYGON_SMOOTH
+ALIAS: GL_CULL_FACE gl:GL_CULL_FACE
+ALIAS: GL_CULL_FACE_MODE gl:GL_CULL_FACE_MODE
+ALIAS: GL_FRONT_FACE gl:GL_FRONT_FACE
+ALIAS: GL_DEPTH_RANGE gl:GL_DEPTH_RANGE
+ALIAS: GL_DEPTH_TEST gl:GL_DEPTH_TEST
+ALIAS: GL_DEPTH_WRITEMASK gl:GL_DEPTH_WRITEMASK
+ALIAS: GL_DEPTH_CLEAR_VALUE gl:GL_DEPTH_CLEAR_VALUE
+ALIAS: GL_DEPTH_FUNC gl:GL_DEPTH_FUNC
+ALIAS: GL_STENCIL_TEST gl:GL_STENCIL_TEST
+ALIAS: GL_STENCIL_CLEAR_VALUE gl:GL_STENCIL_CLEAR_VALUE
+ALIAS: GL_STENCIL_FUNC gl:GL_STENCIL_FUNC
+ALIAS: GL_STENCIL_VALUE_MASK gl:GL_STENCIL_VALUE_MASK
+ALIAS: GL_STENCIL_FAIL gl:GL_STENCIL_FAIL
+ALIAS: GL_STENCIL_PASS_DEPTH_FAIL gl:GL_STENCIL_PASS_DEPTH_FAIL
+ALIAS: GL_STENCIL_PASS_DEPTH_PASS gl:GL_STENCIL_PASS_DEPTH_PASS
+ALIAS: GL_STENCIL_REF gl:GL_STENCIL_REF
+ALIAS: GL_STENCIL_WRITEMASK gl:GL_STENCIL_WRITEMASK
+ALIAS: GL_VIEWPORT gl:GL_VIEWPORT
+ALIAS: GL_DITHER gl:GL_DITHER
+ALIAS: GL_BLEND_DST gl:GL_BLEND_DST
+ALIAS: GL_BLEND_SRC gl:GL_BLEND_SRC
+ALIAS: GL_BLEND gl:GL_BLEND
+ALIAS: GL_LOGIC_OP_MODE gl:GL_LOGIC_OP_MODE
+ALIAS: GL_COLOR_LOGIC_OP gl:GL_COLOR_LOGIC_OP
+ALIAS: GL_DRAW_BUFFER gl:GL_DRAW_BUFFER
+ALIAS: GL_READ_BUFFER gl:GL_READ_BUFFER
+ALIAS: GL_SCISSOR_BOX gl:GL_SCISSOR_BOX
+ALIAS: GL_SCISSOR_TEST gl:GL_SCISSOR_TEST
+ALIAS: GL_COLOR_CLEAR_VALUE gl:GL_COLOR_CLEAR_VALUE
+ALIAS: GL_COLOR_WRITEMASK gl:GL_COLOR_WRITEMASK
+ALIAS: GL_DOUBLEBUFFER gl:GL_DOUBLEBUFFER
+ALIAS: GL_STEREO gl:GL_STEREO
+ALIAS: GL_LINE_SMOOTH_HINT gl:GL_LINE_SMOOTH_HINT
+ALIAS: GL_POLYGON_SMOOTH_HINT gl:GL_POLYGON_SMOOTH_HINT
+ALIAS: GL_UNPACK_SWAP_BYTES gl:GL_UNPACK_SWAP_BYTES
+ALIAS: GL_UNPACK_LSB_FIRST gl:GL_UNPACK_LSB_FIRST
+ALIAS: GL_UNPACK_ROW_LENGTH gl:GL_UNPACK_ROW_LENGTH
+ALIAS: GL_UNPACK_SKIP_ROWS gl:GL_UNPACK_SKIP_ROWS
+ALIAS: GL_UNPACK_SKIP_PIXELS gl:GL_UNPACK_SKIP_PIXELS
+ALIAS: GL_UNPACK_ALIGNMENT gl:GL_UNPACK_ALIGNMENT
+ALIAS: GL_PACK_SWAP_BYTES gl:GL_PACK_SWAP_BYTES
+ALIAS: GL_PACK_LSB_FIRST gl:GL_PACK_LSB_FIRST
+ALIAS: GL_PACK_ROW_LENGTH gl:GL_PACK_ROW_LENGTH
+ALIAS: GL_PACK_SKIP_ROWS gl:GL_PACK_SKIP_ROWS
+ALIAS: GL_PACK_SKIP_PIXELS gl:GL_PACK_SKIP_PIXELS
+ALIAS: GL_PACK_ALIGNMENT gl:GL_PACK_ALIGNMENT
+ALIAS: GL_MAX_TEXTURE_SIZE gl:GL_MAX_TEXTURE_SIZE
+ALIAS: GL_MAX_VIEWPORT_DIMS gl:GL_MAX_VIEWPORT_DIMS
+ALIAS: GL_SUBPIXEL_BITS gl:GL_SUBPIXEL_BITS
+ALIAS: GL_TEXTURE_1D gl:GL_TEXTURE_1D
+ALIAS: GL_TEXTURE_2D gl:GL_TEXTURE_2D
+ALIAS: GL_POLYGON_OFFSET_UNITS gl:GL_POLYGON_OFFSET_UNITS
+ALIAS: GL_POLYGON_OFFSET_POINT gl:GL_POLYGON_OFFSET_POINT
+ALIAS: GL_POLYGON_OFFSET_LINE gl:GL_POLYGON_OFFSET_LINE
+ALIAS: GL_POLYGON_OFFSET_FILL gl:GL_POLYGON_OFFSET_FILL
+ALIAS: GL_POLYGON_OFFSET_FACTOR gl:GL_POLYGON_OFFSET_FACTOR
+ALIAS: GL_TEXTURE_BINDING_1D gl:GL_TEXTURE_BINDING_1D
+ALIAS: GL_TEXTURE_BINDING_2D gl:GL_TEXTURE_BINDING_2D
+ALIAS: GL_TEXTURE_WIDTH gl:GL_TEXTURE_WIDTH
+ALIAS: GL_TEXTURE_HEIGHT gl:GL_TEXTURE_HEIGHT
+ALIAS: GL_TEXTURE_INTERNAL_FORMAT gl:GL_TEXTURE_INTERNAL_FORMAT
+ALIAS: GL_TEXTURE_BORDER_COLOR gl:GL_TEXTURE_BORDER_COLOR
+ALIAS: GL_TEXTURE_BORDER gl:GL_TEXTURE_BORDER
+ALIAS: GL_TEXTURE_RED_SIZE gl:GL_TEXTURE_RED_SIZE
+ALIAS: GL_TEXTURE_GREEN_SIZE gl:GL_TEXTURE_GREEN_SIZE
+ALIAS: GL_TEXTURE_BLUE_SIZE gl:GL_TEXTURE_BLUE_SIZE
+ALIAS: GL_TEXTURE_ALPHA_SIZE gl:GL_TEXTURE_ALPHA_SIZE
+ALIAS: GL_DONT_CARE gl:GL_DONT_CARE
+ALIAS: GL_FASTEST gl:GL_FASTEST
+ALIAS: GL_NICEST gl:GL_NICEST
+ALIAS: GL_BYTE gl:GL_BYTE
+ALIAS: GL_UNSIGNED_BYTE gl:GL_UNSIGNED_BYTE
+ALIAS: GL_SHORT gl:GL_SHORT
+ALIAS: GL_UNSIGNED_SHORT gl:GL_UNSIGNED_SHORT
+ALIAS: GL_INT gl:GL_INT
+ALIAS: GL_UNSIGNED_INT gl:GL_UNSIGNED_INT
+ALIAS: GL_FLOAT gl:GL_FLOAT
+ALIAS: GL_DOUBLE gl:GL_DOUBLE
+ALIAS: GL_CLEAR gl:GL_CLEAR
+ALIAS: GL_AND gl:GL_AND
+ALIAS: GL_AND_REVERSE gl:GL_AND_REVERSE
+ALIAS: GL_COPY gl:GL_COPY
+ALIAS: GL_AND_INVERTED gl:GL_AND_INVERTED
+ALIAS: GL_NOOP gl:GL_NOOP
+ALIAS: GL_XOR gl:GL_XOR
+ALIAS: GL_OR gl:GL_OR
+ALIAS: GL_NOR gl:GL_NOR
+ALIAS: GL_EQUIV gl:GL_EQUIV
+ALIAS: GL_INVERT gl:GL_INVERT
+ALIAS: GL_OR_REVERSE gl:GL_OR_REVERSE
+ALIAS: GL_COPY_INVERTED gl:GL_COPY_INVERTED
+ALIAS: GL_OR_INVERTED gl:GL_OR_INVERTED
+ALIAS: GL_NAND gl:GL_NAND
+ALIAS: GL_SET gl:GL_SET
+ALIAS: GL_TEXTURE gl:GL_TEXTURE
+ALIAS: GL_COLOR gl:GL_COLOR
+ALIAS: GL_DEPTH gl:GL_DEPTH
+ALIAS: GL_STENCIL gl:GL_STENCIL
+ALIAS: GL_STENCIL_INDEX gl:GL_STENCIL_INDEX
+ALIAS: GL_DEPTH_COMPONENT gl:GL_DEPTH_COMPONENT
+ALIAS: GL_RED gl:GL_RED
+ALIAS: GL_GREEN gl:GL_GREEN
+ALIAS: GL_BLUE gl:GL_BLUE
+ALIAS: GL_ALPHA gl:GL_ALPHA
+ALIAS: GL_RGB gl:GL_RGB
+ALIAS: GL_RGBA gl:GL_RGBA
+ALIAS: GL_POINT gl:GL_POINT
+ALIAS: GL_LINE gl:GL_LINE
+ALIAS: GL_FILL gl:GL_FILL
+ALIAS: GL_KEEP gl:GL_KEEP
+ALIAS: GL_REPLACE gl:GL_REPLACE
+ALIAS: GL_INCR gl:GL_INCR
+ALIAS: GL_DECR gl:GL_DECR
+ALIAS: GL_VENDOR gl:GL_VENDOR
+ALIAS: GL_RENDERER gl:GL_RENDERER
+ALIAS: GL_VERSION gl:GL_VERSION
+ALIAS: GL_EXTENSIONS gl:GL_EXTENSIONS
+ALIAS: GL_NEAREST gl:GL_NEAREST
+ALIAS: GL_LINEAR gl:GL_LINEAR
+ALIAS: GL_NEAREST_MIPMAP_NEAREST gl:GL_NEAREST_MIPMAP_NEAREST
+ALIAS: GL_LINEAR_MIPMAP_NEAREST gl:GL_LINEAR_MIPMAP_NEAREST
+ALIAS: GL_NEAREST_MIPMAP_LINEAR gl:GL_NEAREST_MIPMAP_LINEAR
+ALIAS: GL_LINEAR_MIPMAP_LINEAR gl:GL_LINEAR_MIPMAP_LINEAR
+ALIAS: GL_TEXTURE_MAG_FILTER gl:GL_TEXTURE_MAG_FILTER
+ALIAS: GL_TEXTURE_MIN_FILTER gl:GL_TEXTURE_MIN_FILTER
+ALIAS: GL_TEXTURE_WRAP_S gl:GL_TEXTURE_WRAP_S
+ALIAS: GL_TEXTURE_WRAP_T gl:GL_TEXTURE_WRAP_T
+ALIAS: GL_PROXY_TEXTURE_1D gl:GL_PROXY_TEXTURE_1D
+ALIAS: GL_PROXY_TEXTURE_2D gl:GL_PROXY_TEXTURE_2D
+ALIAS: GL_REPEAT gl:GL_REPEAT
+ALIAS: GL_R3_G3_B2 gl:GL_R3_G3_B2
+ALIAS: GL_RGB4 gl:GL_RGB4
+ALIAS: GL_RGB5 gl:GL_RGB5
+ALIAS: GL_RGB8 gl:GL_RGB8
+ALIAS: GL_RGB10 gl:GL_RGB10
+ALIAS: GL_RGB12 gl:GL_RGB12
+ALIAS: GL_RGB16 gl:GL_RGB16
+ALIAS: GL_RGBA2 gl:GL_RGBA2
+ALIAS: GL_RGBA4 gl:GL_RGBA4
+ALIAS: GL_RGB5_A1 gl:GL_RGB5_A1
+ALIAS: GL_RGBA8 gl:GL_RGBA8
+ALIAS: GL_RGB10_A2 gl:GL_RGB10_A2
+ALIAS: GL_RGBA12 gl:GL_RGBA12
+ALIAS: GL_RGBA16 gl:GL_RGBA16
+ALIAS: GL_UNSIGNED_BYTE_3_3_2 gl:GL_UNSIGNED_BYTE_3_3_2
+ALIAS: GL_UNSIGNED_SHORT_4_4_4_4 gl:GL_UNSIGNED_SHORT_4_4_4_4
+ALIAS: GL_UNSIGNED_SHORT_5_5_5_1 gl:GL_UNSIGNED_SHORT_5_5_5_1
+ALIAS: GL_UNSIGNED_INT_8_8_8_8 gl:GL_UNSIGNED_INT_8_8_8_8
+ALIAS: GL_UNSIGNED_INT_10_10_10_2 gl:GL_UNSIGNED_INT_10_10_10_2
+ALIAS: GL_TEXTURE_BINDING_3D gl:GL_TEXTURE_BINDING_3D
+ALIAS: GL_PACK_SKIP_IMAGES gl:GL_PACK_SKIP_IMAGES
+ALIAS: GL_PACK_IMAGE_HEIGHT gl:GL_PACK_IMAGE_HEIGHT
+ALIAS: GL_UNPACK_SKIP_IMAGES gl:GL_UNPACK_SKIP_IMAGES
+ALIAS: GL_UNPACK_IMAGE_HEIGHT gl:GL_UNPACK_IMAGE_HEIGHT
+ALIAS: GL_TEXTURE_3D gl:GL_TEXTURE_3D
+ALIAS: GL_PROXY_TEXTURE_3D gl:GL_PROXY_TEXTURE_3D
+ALIAS: GL_TEXTURE_DEPTH gl:GL_TEXTURE_DEPTH
+ALIAS: GL_TEXTURE_WRAP_R gl:GL_TEXTURE_WRAP_R
+ALIAS: GL_MAX_3D_TEXTURE_SIZE gl:GL_MAX_3D_TEXTURE_SIZE
+ALIAS: GL_UNSIGNED_BYTE_2_3_3_REV gl:GL_UNSIGNED_BYTE_2_3_3_REV
+ALIAS: GL_UNSIGNED_SHORT_5_6_5 gl:GL_UNSIGNED_SHORT_5_6_5
+ALIAS: GL_UNSIGNED_SHORT_5_6_5_REV gl:GL_UNSIGNED_SHORT_5_6_5_REV
+ALIAS: GL_UNSIGNED_SHORT_4_4_4_4_REV gl:GL_UNSIGNED_SHORT_4_4_4_4_REV
+ALIAS: GL_UNSIGNED_SHORT_1_5_5_5_REV gl:GL_UNSIGNED_SHORT_1_5_5_5_REV
+ALIAS: GL_UNSIGNED_INT_8_8_8_8_REV gl:GL_UNSIGNED_INT_8_8_8_8_REV
+ALIAS: GL_UNSIGNED_INT_2_10_10_10_REV gl:GL_UNSIGNED_INT_2_10_10_10_REV
+ALIAS: GL_BGR gl:GL_BGR
+ALIAS: GL_BGRA gl:GL_BGRA
+ALIAS: GL_MAX_ELEMENTS_VERTICES gl:GL_MAX_ELEMENTS_VERTICES
+ALIAS: GL_MAX_ELEMENTS_INDICES gl:GL_MAX_ELEMENTS_INDICES
+ALIAS: GL_CLAMP_TO_EDGE gl:GL_CLAMP_TO_EDGE
+ALIAS: GL_TEXTURE_MIN_LOD gl:GL_TEXTURE_MIN_LOD
+ALIAS: GL_TEXTURE_MAX_LOD gl:GL_TEXTURE_MAX_LOD
+ALIAS: GL_TEXTURE_BASE_LEVEL gl:GL_TEXTURE_BASE_LEVEL
+ALIAS: GL_TEXTURE_MAX_LEVEL gl:GL_TEXTURE_MAX_LEVEL
+ALIAS: GL_SMOOTH_POINT_SIZE_RANGE gl:GL_SMOOTH_POINT_SIZE_RANGE
+ALIAS: GL_SMOOTH_POINT_SIZE_GRANULARITY gl:GL_SMOOTH_POINT_SIZE_GRANULARITY
+ALIAS: GL_SMOOTH_LINE_WIDTH_RANGE gl:GL_SMOOTH_LINE_WIDTH_RANGE
+ALIAS: GL_SMOOTH_LINE_WIDTH_GRANULARITY gl:GL_SMOOTH_LINE_WIDTH_GRANULARITY
+ALIAS: GL_ALIASED_LINE_WIDTH_RANGE gl:GL_ALIASED_LINE_WIDTH_RANGE
+ALIAS: GL_CONSTANT_COLOR gl:GL_CONSTANT_COLOR
+ALIAS: GL_ONE_MINUS_CONSTANT_COLOR gl:GL_ONE_MINUS_CONSTANT_COLOR
+ALIAS: GL_CONSTANT_ALPHA gl:GL_CONSTANT_ALPHA
+ALIAS: GL_ONE_MINUS_CONSTANT_ALPHA gl:GL_ONE_MINUS_CONSTANT_ALPHA
+ALIAS: GL_BLEND_COLOR gl:GL_BLEND_COLOR
+ALIAS: GL_FUNC_ADD gl:GL_FUNC_ADD
+ALIAS: GL_MIN gl:GL_MIN
+ALIAS: GL_MAX gl:GL_MAX
+ALIAS: GL_BLEND_EQUATION gl:GL_BLEND_EQUATION
+ALIAS: GL_FUNC_SUBTRACT gl:GL_FUNC_SUBTRACT
+ALIAS: GL_FUNC_REVERSE_SUBTRACT gl:GL_FUNC_REVERSE_SUBTRACT
+ALIAS: GL_TEXTURE0 gl:GL_TEXTURE0
+ALIAS: GL_TEXTURE1 gl:GL_TEXTURE1
+ALIAS: GL_TEXTURE2 gl:GL_TEXTURE2
+ALIAS: GL_TEXTURE3 gl:GL_TEXTURE3
+ALIAS: GL_TEXTURE4 gl:GL_TEXTURE4
+ALIAS: GL_TEXTURE5 gl:GL_TEXTURE5
+ALIAS: GL_TEXTURE6 gl:GL_TEXTURE6
+ALIAS: GL_TEXTURE7 gl:GL_TEXTURE7
+ALIAS: GL_TEXTURE8 gl:GL_TEXTURE8
+ALIAS: GL_TEXTURE9 gl:GL_TEXTURE9
+ALIAS: GL_TEXTURE10 gl:GL_TEXTURE10
+ALIAS: GL_TEXTURE11 gl:GL_TEXTURE11
+ALIAS: GL_TEXTURE12 gl:GL_TEXTURE12
+ALIAS: GL_TEXTURE13 gl:GL_TEXTURE13
+ALIAS: GL_TEXTURE14 gl:GL_TEXTURE14
+ALIAS: GL_TEXTURE15 gl:GL_TEXTURE15
+ALIAS: GL_TEXTURE16 gl:GL_TEXTURE16
+ALIAS: GL_TEXTURE17 gl:GL_TEXTURE17
+ALIAS: GL_TEXTURE18 gl:GL_TEXTURE18
+ALIAS: GL_TEXTURE19 gl:GL_TEXTURE19
+ALIAS: GL_TEXTURE20 gl:GL_TEXTURE20
+ALIAS: GL_TEXTURE21 gl:GL_TEXTURE21
+ALIAS: GL_TEXTURE22 gl:GL_TEXTURE22
+ALIAS: GL_TEXTURE23 gl:GL_TEXTURE23
+ALIAS: GL_TEXTURE24 gl:GL_TEXTURE24
+ALIAS: GL_TEXTURE25 gl:GL_TEXTURE25
+ALIAS: GL_TEXTURE26 gl:GL_TEXTURE26
+ALIAS: GL_TEXTURE27 gl:GL_TEXTURE27
+ALIAS: GL_TEXTURE28 gl:GL_TEXTURE28
+ALIAS: GL_TEXTURE29 gl:GL_TEXTURE29
+ALIAS: GL_TEXTURE30 gl:GL_TEXTURE30
+ALIAS: GL_TEXTURE31 gl:GL_TEXTURE31
+ALIAS: GL_ACTIVE_TEXTURE gl:GL_ACTIVE_TEXTURE
+ALIAS: GL_MULTISAMPLE gl:GL_MULTISAMPLE
+ALIAS: GL_SAMPLE_ALPHA_TO_COVERAGE gl:GL_SAMPLE_ALPHA_TO_COVERAGE
+ALIAS: GL_SAMPLE_ALPHA_TO_ONE gl:GL_SAMPLE_ALPHA_TO_ONE
+ALIAS: GL_SAMPLE_COVERAGE gl:GL_SAMPLE_COVERAGE
+ALIAS: GL_SAMPLE_BUFFERS gl:GL_SAMPLE_BUFFERS
+ALIAS: GL_SAMPLES gl:GL_SAMPLES
+ALIAS: GL_SAMPLE_COVERAGE_VALUE gl:GL_SAMPLE_COVERAGE_VALUE
+ALIAS: GL_SAMPLE_COVERAGE_INVERT gl:GL_SAMPLE_COVERAGE_INVERT
+ALIAS: GL_TEXTURE_CUBE_MAP gl:GL_TEXTURE_CUBE_MAP
+ALIAS: GL_TEXTURE_BINDING_CUBE_MAP gl:GL_TEXTURE_BINDING_CUBE_MAP
+ALIAS: GL_TEXTURE_CUBE_MAP_POSITIVE_X gl:GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ALIAS: GL_TEXTURE_CUBE_MAP_NEGATIVE_X gl:GL_TEXTURE_CUBE_MAP_NEGATIVE_X
+ALIAS: GL_TEXTURE_CUBE_MAP_POSITIVE_Y gl:GL_TEXTURE_CUBE_MAP_POSITIVE_Y
+ALIAS: GL_TEXTURE_CUBE_MAP_NEGATIVE_Y gl:GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
+ALIAS: GL_TEXTURE_CUBE_MAP_POSITIVE_Z gl:GL_TEXTURE_CUBE_MAP_POSITIVE_Z
+ALIAS: GL_TEXTURE_CUBE_MAP_NEGATIVE_Z gl:GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+ALIAS: GL_PROXY_TEXTURE_CUBE_MAP gl:GL_PROXY_TEXTURE_CUBE_MAP
+ALIAS: GL_MAX_CUBE_MAP_TEXTURE_SIZE gl:GL_MAX_CUBE_MAP_TEXTURE_SIZE
+ALIAS: GL_COMPRESSED_RGB gl:GL_COMPRESSED_RGB
+ALIAS: GL_COMPRESSED_RGBA gl:GL_COMPRESSED_RGBA
+ALIAS: GL_TEXTURE_COMPRESSION_HINT gl:GL_TEXTURE_COMPRESSION_HINT
+ALIAS: GL_TEXTURE_COMPRESSED_IMAGE_SIZE gl:GL_TEXTURE_COMPRESSED_IMAGE_SIZE
+ALIAS: GL_TEXTURE_COMPRESSED gl:GL_TEXTURE_COMPRESSED
+ALIAS: GL_NUM_COMPRESSED_TEXTURE_FORMATS gl:GL_NUM_COMPRESSED_TEXTURE_FORMATS
+ALIAS: GL_COMPRESSED_TEXTURE_FORMATS gl:GL_COMPRESSED_TEXTURE_FORMATS
+ALIAS: GL_CLAMP_TO_BORDER gl:GL_CLAMP_TO_BORDER
+ALIAS: GL_BLEND_DST_RGB gl:GL_BLEND_DST_RGB
+ALIAS: GL_BLEND_SRC_RGB gl:GL_BLEND_SRC_RGB
+ALIAS: GL_BLEND_DST_ALPHA gl:GL_BLEND_DST_ALPHA
+ALIAS: GL_BLEND_SRC_ALPHA gl:GL_BLEND_SRC_ALPHA
+ALIAS: GL_POINT_FADE_THRESHOLD_SIZE gl:GL_POINT_FADE_THRESHOLD_SIZE
+ALIAS: GL_DEPTH_COMPONENT16 gl:GL_DEPTH_COMPONENT16
+ALIAS: GL_DEPTH_COMPONENT24 gl:GL_DEPTH_COMPONENT24
+ALIAS: GL_DEPTH_COMPONENT32 gl:GL_DEPTH_COMPONENT32
+ALIAS: GL_MIRRORED_REPEAT gl:GL_MIRRORED_REPEAT
+ALIAS: GL_MAX_TEXTURE_LOD_BIAS gl:GL_MAX_TEXTURE_LOD_BIAS
+ALIAS: GL_TEXTURE_LOD_BIAS gl:GL_TEXTURE_LOD_BIAS
+ALIAS: GL_INCR_WRAP gl:GL_INCR_WRAP
+ALIAS: GL_DECR_WRAP gl:GL_DECR_WRAP
+ALIAS: GL_TEXTURE_DEPTH_SIZE gl:GL_TEXTURE_DEPTH_SIZE
+ALIAS: GL_TEXTURE_COMPARE_MODE gl:GL_TEXTURE_COMPARE_MODE
+ALIAS: GL_TEXTURE_COMPARE_FUNC gl:GL_TEXTURE_COMPARE_FUNC
+ALIAS: GL_BUFFER_SIZE gl:GL_BUFFER_SIZE
+ALIAS: GL_BUFFER_USAGE gl:GL_BUFFER_USAGE
+ALIAS: GL_QUERY_COUNTER_BITS gl:GL_QUERY_COUNTER_BITS
+ALIAS: GL_CURRENT_QUERY gl:GL_CURRENT_QUERY
+ALIAS: GL_QUERY_RESULT gl:GL_QUERY_RESULT
+ALIAS: GL_QUERY_RESULT_AVAILABLE gl:GL_QUERY_RESULT_AVAILABLE
+ALIAS: GL_ARRAY_BUFFER gl:GL_ARRAY_BUFFER
+ALIAS: GL_ELEMENT_ARRAY_BUFFER gl:GL_ELEMENT_ARRAY_BUFFER
+ALIAS: GL_ARRAY_BUFFER_BINDING gl:GL_ARRAY_BUFFER_BINDING
+ALIAS: GL_ELEMENT_ARRAY_BUFFER_BINDING gl:GL_ELEMENT_ARRAY_BUFFER_BINDING
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING gl:GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
+ALIAS: GL_READ_ONLY gl:GL_READ_ONLY
+ALIAS: GL_WRITE_ONLY gl:GL_WRITE_ONLY
+ALIAS: GL_READ_WRITE gl:GL_READ_WRITE
+ALIAS: GL_BUFFER_ACCESS gl:GL_BUFFER_ACCESS
+ALIAS: GL_BUFFER_MAPPED gl:GL_BUFFER_MAPPED
+ALIAS: GL_BUFFER_MAP_POINTER gl:GL_BUFFER_MAP_POINTER
+ALIAS: GL_STREAM_DRAW gl:GL_STREAM_DRAW
+ALIAS: GL_STREAM_READ gl:GL_STREAM_READ
+ALIAS: GL_STREAM_COPY gl:GL_STREAM_COPY
+ALIAS: GL_STATIC_DRAW gl:GL_STATIC_DRAW
+ALIAS: GL_STATIC_READ gl:GL_STATIC_READ
+ALIAS: GL_STATIC_COPY gl:GL_STATIC_COPY
+ALIAS: GL_DYNAMIC_DRAW gl:GL_DYNAMIC_DRAW
+ALIAS: GL_DYNAMIC_READ gl:GL_DYNAMIC_READ
+ALIAS: GL_DYNAMIC_COPY gl:GL_DYNAMIC_COPY
+ALIAS: GL_SAMPLES_PASSED gl:GL_SAMPLES_PASSED
+ALIAS: GL_BLEND_EQUATION_RGB gl:GL_BLEND_EQUATION_RGB
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_ENABLED gl:GL_VERTEX_ATTRIB_ARRAY_ENABLED
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_SIZE gl:GL_VERTEX_ATTRIB_ARRAY_SIZE
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_STRIDE gl:GL_VERTEX_ATTRIB_ARRAY_STRIDE
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_TYPE gl:GL_VERTEX_ATTRIB_ARRAY_TYPE
+ALIAS: GL_CURRENT_VERTEX_ATTRIB gl:GL_CURRENT_VERTEX_ATTRIB
+ALIAS: GL_VERTEX_PROGRAM_POINT_SIZE gl:GL_VERTEX_PROGRAM_POINT_SIZE
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_POINTER gl:GL_VERTEX_ATTRIB_ARRAY_POINTER
+ALIAS: GL_STENCIL_BACK_FUNC gl:GL_STENCIL_BACK_FUNC
+ALIAS: GL_STENCIL_BACK_FAIL gl:GL_STENCIL_BACK_FAIL
+ALIAS: GL_STENCIL_BACK_PASS_DEPTH_FAIL gl:GL_STENCIL_BACK_PASS_DEPTH_FAIL
+ALIAS: GL_STENCIL_BACK_PASS_DEPTH_PASS gl:GL_STENCIL_BACK_PASS_DEPTH_PASS
+ALIAS: GL_MAX_DRAW_BUFFERS gl:GL_MAX_DRAW_BUFFERS
+ALIAS: GL_DRAW_BUFFER0 gl:GL_DRAW_BUFFER0
+ALIAS: GL_DRAW_BUFFER1 gl:GL_DRAW_BUFFER1
+ALIAS: GL_DRAW_BUFFER2 gl:GL_DRAW_BUFFER2
+ALIAS: GL_DRAW_BUFFER3 gl:GL_DRAW_BUFFER3
+ALIAS: GL_DRAW_BUFFER4 gl:GL_DRAW_BUFFER4
+ALIAS: GL_DRAW_BUFFER5 gl:GL_DRAW_BUFFER5
+ALIAS: GL_DRAW_BUFFER6 gl:GL_DRAW_BUFFER6
+ALIAS: GL_DRAW_BUFFER7 gl:GL_DRAW_BUFFER7
+ALIAS: GL_DRAW_BUFFER8 gl:GL_DRAW_BUFFER8
+ALIAS: GL_DRAW_BUFFER9 gl:GL_DRAW_BUFFER9
+ALIAS: GL_DRAW_BUFFER10 gl:GL_DRAW_BUFFER10
+ALIAS: GL_DRAW_BUFFER11 gl:GL_DRAW_BUFFER11
+ALIAS: GL_DRAW_BUFFER12 gl:GL_DRAW_BUFFER12
+ALIAS: GL_DRAW_BUFFER13 gl:GL_DRAW_BUFFER13
+ALIAS: GL_DRAW_BUFFER14 gl:GL_DRAW_BUFFER14
+ALIAS: GL_DRAW_BUFFER15 gl:GL_DRAW_BUFFER15
+ALIAS: GL_BLEND_EQUATION_ALPHA gl:GL_BLEND_EQUATION_ALPHA
+ALIAS: GL_MAX_VERTEX_ATTRIBS gl:GL_MAX_VERTEX_ATTRIBS
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_NORMALIZED gl:GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
+ALIAS: GL_MAX_TEXTURE_IMAGE_UNITS gl:GL_MAX_TEXTURE_IMAGE_UNITS
+ALIAS: GL_FRAGMENT_SHADER gl:GL_FRAGMENT_SHADER
+ALIAS: GL_VERTEX_SHADER gl:GL_VERTEX_SHADER
+ALIAS: GL_MAX_FRAGMENT_UNIFORM_COMPONENTS gl:GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
+ALIAS: GL_MAX_VERTEX_UNIFORM_COMPONENTS gl:GL_MAX_VERTEX_UNIFORM_COMPONENTS
+ALIAS: GL_MAX_VARYING_FLOATS gl:GL_MAX_VARYING_FLOATS
+ALIAS: GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS gl:GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
+ALIAS: GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS gl:GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
+ALIAS: GL_SHADER_TYPE gl:GL_SHADER_TYPE
+ALIAS: GL_FLOAT_VEC2 gl:GL_FLOAT_VEC2
+ALIAS: GL_FLOAT_VEC3 gl:GL_FLOAT_VEC3
+ALIAS: GL_FLOAT_VEC4 gl:GL_FLOAT_VEC4
+ALIAS: GL_INT_VEC2 gl:GL_INT_VEC2
+ALIAS: GL_INT_VEC3 gl:GL_INT_VEC3
+ALIAS: GL_INT_VEC4 gl:GL_INT_VEC4
+ALIAS: GL_BOOL gl:GL_BOOL
+ALIAS: GL_BOOL_VEC2 gl:GL_BOOL_VEC2
+ALIAS: GL_BOOL_VEC3 gl:GL_BOOL_VEC3
+ALIAS: GL_BOOL_VEC4 gl:GL_BOOL_VEC4
+ALIAS: GL_FLOAT_MAT2 gl:GL_FLOAT_MAT2
+ALIAS: GL_FLOAT_MAT3 gl:GL_FLOAT_MAT3
+ALIAS: GL_FLOAT_MAT4 gl:GL_FLOAT_MAT4
+ALIAS: GL_SAMPLER_1D gl:GL_SAMPLER_1D
+ALIAS: GL_SAMPLER_2D gl:GL_SAMPLER_2D
+ALIAS: GL_SAMPLER_3D gl:GL_SAMPLER_3D
+ALIAS: GL_SAMPLER_CUBE gl:GL_SAMPLER_CUBE
+ALIAS: GL_SAMPLER_1D_SHADOW gl:GL_SAMPLER_1D_SHADOW
+ALIAS: GL_SAMPLER_2D_SHADOW gl:GL_SAMPLER_2D_SHADOW
+ALIAS: GL_DELETE_STATUS gl:GL_DELETE_STATUS
+ALIAS: GL_COMPILE_STATUS gl:GL_COMPILE_STATUS
+ALIAS: GL_LINK_STATUS gl:GL_LINK_STATUS
+ALIAS: GL_VALIDATE_STATUS gl:GL_VALIDATE_STATUS
+ALIAS: GL_INFO_LOG_LENGTH gl:GL_INFO_LOG_LENGTH
+ALIAS: GL_ATTACHED_SHADERS gl:GL_ATTACHED_SHADERS
+ALIAS: GL_ACTIVE_UNIFORMS gl:GL_ACTIVE_UNIFORMS
+ALIAS: GL_ACTIVE_UNIFORM_MAX_LENGTH gl:GL_ACTIVE_UNIFORM_MAX_LENGTH
+ALIAS: GL_SHADER_SOURCE_LENGTH gl:GL_SHADER_SOURCE_LENGTH
+ALIAS: GL_ACTIVE_ATTRIBUTES gl:GL_ACTIVE_ATTRIBUTES
+ALIAS: GL_ACTIVE_ATTRIBUTE_MAX_LENGTH gl:GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
+ALIAS: GL_FRAGMENT_SHADER_DERIVATIVE_HINT gl:GL_FRAGMENT_SHADER_DERIVATIVE_HINT
+ALIAS: GL_SHADING_LANGUAGE_VERSION gl:GL_SHADING_LANGUAGE_VERSION
+ALIAS: GL_CURRENT_PROGRAM gl:GL_CURRENT_PROGRAM
+ALIAS: GL_POINT_SPRITE_COORD_ORIGIN gl:GL_POINT_SPRITE_COORD_ORIGIN
+ALIAS: GL_LOWER_LEFT gl:GL_LOWER_LEFT
+ALIAS: GL_UPPER_LEFT gl:GL_UPPER_LEFT
+ALIAS: GL_STENCIL_BACK_REF gl:GL_STENCIL_BACK_REF
+ALIAS: GL_STENCIL_BACK_VALUE_MASK gl:GL_STENCIL_BACK_VALUE_MASK
+ALIAS: GL_STENCIL_BACK_WRITEMASK gl:GL_STENCIL_BACK_WRITEMASK
+ALIAS: GL_PIXEL_PACK_BUFFER gl:GL_PIXEL_PACK_BUFFER
+ALIAS: GL_PIXEL_UNPACK_BUFFER gl:GL_PIXEL_UNPACK_BUFFER
+ALIAS: GL_PIXEL_PACK_BUFFER_BINDING gl:GL_PIXEL_PACK_BUFFER_BINDING
+ALIAS: GL_PIXEL_UNPACK_BUFFER_BINDING gl:GL_PIXEL_UNPACK_BUFFER_BINDING
+ALIAS: GL_FLOAT_MAT2x3 gl:GL_FLOAT_MAT2x3
+ALIAS: GL_FLOAT_MAT2x4 gl:GL_FLOAT_MAT2x4
+ALIAS: GL_FLOAT_MAT3x2 gl:GL_FLOAT_MAT3x2
+ALIAS: GL_FLOAT_MAT3x4 gl:GL_FLOAT_MAT3x4
+ALIAS: GL_FLOAT_MAT4x2 gl:GL_FLOAT_MAT4x2
+ALIAS: GL_FLOAT_MAT4x3 gl:GL_FLOAT_MAT4x3
+ALIAS: GL_SRGB gl:GL_SRGB
+ALIAS: GL_SRGB8 gl:GL_SRGB8
+ALIAS: GL_SRGB_ALPHA gl:GL_SRGB_ALPHA
+ALIAS: GL_SRGB8_ALPHA8 gl:GL_SRGB8_ALPHA8
+ALIAS: GL_COMPRESSED_SRGB gl:GL_COMPRESSED_SRGB
+ALIAS: GL_COMPRESSED_SRGB_ALPHA gl:GL_COMPRESSED_SRGB_ALPHA
+ALIAS: GL_COMPARE_REF_TO_TEXTURE gl:GL_COMPARE_REF_TO_TEXTURE
+ALIAS: GL_CLIP_DISTANCE0 gl:GL_CLIP_DISTANCE0
+ALIAS: GL_CLIP_DISTANCE1 gl:GL_CLIP_DISTANCE1
+ALIAS: GL_CLIP_DISTANCE2 gl:GL_CLIP_DISTANCE2
+ALIAS: GL_CLIP_DISTANCE3 gl:GL_CLIP_DISTANCE3
+ALIAS: GL_CLIP_DISTANCE4 gl:GL_CLIP_DISTANCE4
+ALIAS: GL_CLIP_DISTANCE5 gl:GL_CLIP_DISTANCE5
+ALIAS: GL_MAX_CLIP_DISTANCES gl:GL_MAX_CLIP_DISTANCES
+ALIAS: GL_MAJOR_VERSION gl:GL_MAJOR_VERSION
+ALIAS: GL_MINOR_VERSION gl:GL_MINOR_VERSION
+ALIAS: GL_NUM_EXTENSIONS gl:GL_NUM_EXTENSIONS
+ALIAS: GL_CONTEXT_FLAGS gl:GL_CONTEXT_FLAGS
+ALIAS: GL_DEPTH_BUFFER gl:GL_DEPTH_BUFFER
+ALIAS: GL_STENCIL_BUFFER gl:GL_STENCIL_BUFFER
+ALIAS: GL_COMPRESSED_RED gl:GL_COMPRESSED_RED
+ALIAS: GL_COMPRESSED_RG gl:GL_COMPRESSED_RG
+ALIAS: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT gl:GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
+ALIAS: GL_RGBA32F gl:GL_RGBA32F
+ALIAS: GL_RGB32F gl:GL_RGB32F
+ALIAS: GL_RGBA16F gl:GL_RGBA16F
+ALIAS: GL_RGB16F gl:GL_RGB16F
+ALIAS: GL_VERTEX_ATTRIB_ARRAY_INTEGER gl:GL_VERTEX_ATTRIB_ARRAY_INTEGER
+ALIAS: GL_MAX_ARRAY_TEXTURE_LAYERS gl:GL_MAX_ARRAY_TEXTURE_LAYERS
+ALIAS: GL_MIN_PROGRAM_TEXEL_OFFSET gl:GL_MIN_PROGRAM_TEXEL_OFFSET
+ALIAS: GL_MAX_PROGRAM_TEXEL_OFFSET gl:GL_MAX_PROGRAM_TEXEL_OFFSET
+ALIAS: GL_CLAMP_READ_COLOR gl:GL_CLAMP_READ_COLOR
+ALIAS: GL_FIXED_ONLY gl:GL_FIXED_ONLY
+ALIAS: GL_MAX_VARYING_COMPONENTS gl:GL_MAX_VARYING_COMPONENTS
+ALIAS: GL_TEXTURE_1D_ARRAY gl:GL_TEXTURE_1D_ARRAY
+ALIAS: GL_PROXY_TEXTURE_1D_ARRAY gl:GL_PROXY_TEXTURE_1D_ARRAY
+ALIAS: GL_TEXTURE_2D_ARRAY gl:GL_TEXTURE_2D_ARRAY
+ALIAS: GL_PROXY_TEXTURE_2D_ARRAY gl:GL_PROXY_TEXTURE_2D_ARRAY
+ALIAS: GL_TEXTURE_BINDING_1D_ARRAY gl:GL_TEXTURE_BINDING_1D_ARRAY
+ALIAS: GL_TEXTURE_BINDING_2D_ARRAY gl:GL_TEXTURE_BINDING_2D_ARRAY
+ALIAS: GL_R11F_G11F_B10F gl:GL_R11F_G11F_B10F
+ALIAS: GL_UNSIGNED_INT_10F_11F_11F_REV gl:GL_UNSIGNED_INT_10F_11F_11F_REV
+ALIAS: GL_RGB9_E5 gl:GL_RGB9_E5
+ALIAS: GL_UNSIGNED_INT_5_9_9_9_REV gl:GL_UNSIGNED_INT_5_9_9_9_REV
+ALIAS: GL_TEXTURE_SHARED_SIZE gl:GL_TEXTURE_SHARED_SIZE
+ALIAS: GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH gl:GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH
+ALIAS: GL_TRANSFORM_FEEDBACK_BUFFER_MODE gl:GL_TRANSFORM_FEEDBACK_BUFFER_MODE
+ALIAS: GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS gl:GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS
+ALIAS: GL_TRANSFORM_FEEDBACK_VARYINGS gl:GL_TRANSFORM_FEEDBACK_VARYINGS
+ALIAS: GL_TRANSFORM_FEEDBACK_BUFFER_START gl:GL_TRANSFORM_FEEDBACK_BUFFER_START
+ALIAS: GL_TRANSFORM_FEEDBACK_BUFFER_SIZE gl:GL_TRANSFORM_FEEDBACK_BUFFER_SIZE
+ALIAS: GL_PRIMITIVES_GENERATED gl:GL_PRIMITIVES_GENERATED
+ALIAS: GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN gl:GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
+ALIAS: GL_RASTERIZER_DISCARD gl:GL_RASTERIZER_DISCARD
+ALIAS: GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS gl:GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS
+ALIAS: GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS gl:GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS
+ALIAS: GL_INTERLEAVED_ATTRIBS gl:GL_INTERLEAVED_ATTRIBS
+ALIAS: GL_SEPARATE_ATTRIBS gl:GL_SEPARATE_ATTRIBS
+ALIAS: GL_TRANSFORM_FEEDBACK_BUFFER gl:GL_TRANSFORM_FEEDBACK_BUFFER
+ALIAS: GL_TRANSFORM_FEEDBACK_BUFFER_BINDING gl:GL_TRANSFORM_FEEDBACK_BUFFER_BINDING
+ALIAS: GL_RGBA32UI gl:GL_RGBA32UI
+ALIAS: GL_RGB32UI gl:GL_RGB32UI
+ALIAS: GL_RGBA16UI gl:GL_RGBA16UI
+ALIAS: GL_RGB16UI gl:GL_RGB16UI
+ALIAS: GL_RGBA8UI gl:GL_RGBA8UI
+ALIAS: GL_RGB8UI gl:GL_RGB8UI
+ALIAS: GL_RGBA32I gl:GL_RGBA32I
+ALIAS: GL_RGB32I gl:GL_RGB32I
+ALIAS: GL_RGBA16I gl:GL_RGBA16I
+ALIAS: GL_RGB16I gl:GL_RGB16I
+ALIAS: GL_RGBA8I gl:GL_RGBA8I
+ALIAS: GL_RGB8I gl:GL_RGB8I
+ALIAS: GL_RED_INTEGER gl:GL_RED_INTEGER
+ALIAS: GL_GREEN_INTEGER gl:GL_GREEN_INTEGER
+ALIAS: GL_BLUE_INTEGER gl:GL_BLUE_INTEGER
+ALIAS: GL_RGB_INTEGER gl:GL_RGB_INTEGER
+ALIAS: GL_RGBA_INTEGER gl:GL_RGBA_INTEGER
+ALIAS: GL_BGR_INTEGER gl:GL_BGR_INTEGER
+ALIAS: GL_BGRA_INTEGER gl:GL_BGRA_INTEGER
+ALIAS: GL_SAMPLER_1D_ARRAY gl:GL_SAMPLER_1D_ARRAY
+ALIAS: GL_SAMPLER_2D_ARRAY gl:GL_SAMPLER_2D_ARRAY
+ALIAS: GL_SAMPLER_1D_ARRAY_SHADOW gl:GL_SAMPLER_1D_ARRAY_SHADOW
+ALIAS: GL_SAMPLER_2D_ARRAY_SHADOW gl:GL_SAMPLER_2D_ARRAY_SHADOW
+ALIAS: GL_SAMPLER_CUBE_SHADOW gl:GL_SAMPLER_CUBE_SHADOW
+ALIAS: GL_UNSIGNED_INT_VEC2 gl:GL_UNSIGNED_INT_VEC2
+ALIAS: GL_UNSIGNED_INT_VEC3 gl:GL_UNSIGNED_INT_VEC3
+ALIAS: GL_UNSIGNED_INT_VEC4 gl:GL_UNSIGNED_INT_VEC4
+ALIAS: GL_INT_SAMPLER_1D gl:GL_INT_SAMPLER_1D
+ALIAS: GL_INT_SAMPLER_2D gl:GL_INT_SAMPLER_2D
+ALIAS: GL_INT_SAMPLER_3D gl:GL_INT_SAMPLER_3D
+ALIAS: GL_INT_SAMPLER_CUBE gl:GL_INT_SAMPLER_CUBE
+ALIAS: GL_INT_SAMPLER_1D_ARRAY gl:GL_INT_SAMPLER_1D_ARRAY
+ALIAS: GL_INT_SAMPLER_2D_ARRAY gl:GL_INT_SAMPLER_2D_ARRAY
+ALIAS: GL_UNSIGNED_INT_SAMPLER_1D gl:GL_UNSIGNED_INT_SAMPLER_1D
+ALIAS: GL_UNSIGNED_INT_SAMPLER_2D gl:GL_UNSIGNED_INT_SAMPLER_2D
+ALIAS: GL_UNSIGNED_INT_SAMPLER_3D gl:GL_UNSIGNED_INT_SAMPLER_3D
+ALIAS: GL_UNSIGNED_INT_SAMPLER_CUBE gl:GL_UNSIGNED_INT_SAMPLER_CUBE
+ALIAS: GL_UNSIGNED_INT_SAMPLER_1D_ARRAY gl:GL_UNSIGNED_INT_SAMPLER_1D_ARRAY
+ALIAS: GL_UNSIGNED_INT_SAMPLER_2D_ARRAY gl:GL_UNSIGNED_INT_SAMPLER_2D_ARRAY
+ALIAS: GL_QUERY_WAIT gl:GL_QUERY_WAIT
+ALIAS: GL_QUERY_NO_WAIT gl:GL_QUERY_NO_WAIT
+ALIAS: GL_QUERY_BY_REGION_WAIT gl:GL_QUERY_BY_REGION_WAIT
+ALIAS: GL_QUERY_BY_REGION_NO_WAIT gl:GL_QUERY_BY_REGION_NO_WAIT
+ALIAS: GL_DEPTH_COMPONENT32F gl:GL_DEPTH_COMPONENT32F
+ALIAS: GL_DEPTH32F_STENCIL8 gl:GL_DEPTH32F_STENCIL8
+ALIAS: GL_FLOAT_32_UNSIGNED_INT_24_8_REV gl:GL_FLOAT_32_UNSIGNED_INT_24_8_REV
+ALIAS: GL_INVALID_FRAMEBUFFER_OPERATION gl:GL_INVALID_FRAMEBUFFER_OPERATION
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING gl:GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE gl:GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE gl:GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE gl:GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE gl:GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE gl:GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE gl:GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE gl:GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
+ALIAS: GL_FRAMEBUFFER_DEFAULT gl:GL_FRAMEBUFFER_DEFAULT
+ALIAS: GL_FRAMEBUFFER_UNDEFINED gl:GL_FRAMEBUFFER_UNDEFINED
+ALIAS: GL_DEPTH_STENCIL_ATTACHMENT gl:GL_DEPTH_STENCIL_ATTACHMENT
+ALIAS: GL_INDEX gl:GL_INDEX
+ALIAS: GL_MAX_RENDERBUFFER_SIZE gl:GL_MAX_RENDERBUFFER_SIZE
+ALIAS: GL_DEPTH_STENCIL gl:GL_DEPTH_STENCIL
+ALIAS: GL_UNSIGNED_INT_24_8 gl:GL_UNSIGNED_INT_24_8
+ALIAS: GL_DEPTH24_STENCIL8 gl:GL_DEPTH24_STENCIL8
+ALIAS: GL_TEXTURE_STENCIL_SIZE gl:GL_TEXTURE_STENCIL_SIZE
+ALIAS: GL_TEXTURE_RED_TYPE gl:GL_TEXTURE_RED_TYPE
+ALIAS: GL_TEXTURE_GREEN_TYPE gl:GL_TEXTURE_GREEN_TYPE
+ALIAS: GL_TEXTURE_BLUE_TYPE gl:GL_TEXTURE_BLUE_TYPE
+ALIAS: GL_TEXTURE_ALPHA_TYPE gl:GL_TEXTURE_ALPHA_TYPE
+ALIAS: GL_TEXTURE_DEPTH_TYPE gl:GL_TEXTURE_DEPTH_TYPE
+ALIAS: GL_UNSIGNED_NORMALIZED gl:GL_UNSIGNED_NORMALIZED
+ALIAS: GL_FRAMEBUFFER_BINDING gl:GL_FRAMEBUFFER_BINDING
+ALIAS: GL_DRAW_FRAMEBUFFER_BINDING gl:GL_DRAW_FRAMEBUFFER_BINDING
+ALIAS: GL_RENDERBUFFER_BINDING gl:GL_RENDERBUFFER_BINDING
+ALIAS: GL_READ_FRAMEBUFFER gl:GL_READ_FRAMEBUFFER
+ALIAS: GL_DRAW_FRAMEBUFFER gl:GL_DRAW_FRAMEBUFFER
+ALIAS: GL_READ_FRAMEBUFFER_BINDING gl:GL_READ_FRAMEBUFFER_BINDING
+ALIAS: GL_RENDERBUFFER_SAMPLES gl:GL_RENDERBUFFER_SAMPLES
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE gl:GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME gl:GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL gl:GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE gl:GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
+ALIAS: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER gl:GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER
+ALIAS: GL_FRAMEBUFFER_COMPLETE gl:GL_FRAMEBUFFER_COMPLETE
+ALIAS: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT gl:GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+ALIAS: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT gl:GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
+ALIAS: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER gl:GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
+ALIAS: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER gl:GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
+ALIAS: GL_FRAMEBUFFER_UNSUPPORTED gl:GL_FRAMEBUFFER_UNSUPPORTED
+ALIAS: GL_MAX_COLOR_ATTACHMENTS gl:GL_MAX_COLOR_ATTACHMENTS
+ALIAS: GL_COLOR_ATTACHMENT0 gl:GL_COLOR_ATTACHMENT0
+ALIAS: GL_COLOR_ATTACHMENT1 gl:GL_COLOR_ATTACHMENT1
+ALIAS: GL_COLOR_ATTACHMENT2 gl:GL_COLOR_ATTACHMENT2
+ALIAS: GL_COLOR_ATTACHMENT3 gl:GL_COLOR_ATTACHMENT3
+ALIAS: GL_COLOR_ATTACHMENT4 gl:GL_COLOR_ATTACHMENT4
+ALIAS: GL_COLOR_ATTACHMENT5 gl:GL_COLOR_ATTACHMENT5
+ALIAS: GL_COLOR_ATTACHMENT6 gl:GL_COLOR_ATTACHMENT6
+ALIAS: GL_COLOR_ATTACHMENT7 gl:GL_COLOR_ATTACHMENT7
+ALIAS: GL_COLOR_ATTACHMENT8 gl:GL_COLOR_ATTACHMENT8
+ALIAS: GL_COLOR_ATTACHMENT9 gl:GL_COLOR_ATTACHMENT9
+ALIAS: GL_COLOR_ATTACHMENT10 gl:GL_COLOR_ATTACHMENT10
+ALIAS: GL_COLOR_ATTACHMENT11 gl:GL_COLOR_ATTACHMENT11
+ALIAS: GL_COLOR_ATTACHMENT12 gl:GL_COLOR_ATTACHMENT12
+ALIAS: GL_COLOR_ATTACHMENT13 gl:GL_COLOR_ATTACHMENT13
+ALIAS: GL_COLOR_ATTACHMENT14 gl:GL_COLOR_ATTACHMENT14
+ALIAS: GL_COLOR_ATTACHMENT15 gl:GL_COLOR_ATTACHMENT15
+ALIAS: GL_DEPTH_ATTACHMENT gl:GL_DEPTH_ATTACHMENT
+ALIAS: GL_STENCIL_ATTACHMENT gl:GL_STENCIL_ATTACHMENT
+ALIAS: GL_FRAMEBUFFER gl:GL_FRAMEBUFFER
+ALIAS: GL_RENDERBUFFER gl:GL_RENDERBUFFER
+ALIAS: GL_RENDERBUFFER_WIDTH gl:GL_RENDERBUFFER_WIDTH
+ALIAS: GL_RENDERBUFFER_HEIGHT gl:GL_RENDERBUFFER_HEIGHT
+ALIAS: GL_RENDERBUFFER_INTERNAL_FORMAT gl:GL_RENDERBUFFER_INTERNAL_FORMAT
+ALIAS: GL_STENCIL_INDEX1 gl:GL_STENCIL_INDEX1
+ALIAS: GL_STENCIL_INDEX4 gl:GL_STENCIL_INDEX4
+ALIAS: GL_STENCIL_INDEX8 gl:GL_STENCIL_INDEX8
+ALIAS: GL_STENCIL_INDEX16 gl:GL_STENCIL_INDEX16
+ALIAS: GL_RENDERBUFFER_RED_SIZE gl:GL_RENDERBUFFER_RED_SIZE
+ALIAS: GL_RENDERBUFFER_GREEN_SIZE gl:GL_RENDERBUFFER_GREEN_SIZE
+ALIAS: GL_RENDERBUFFER_BLUE_SIZE gl:GL_RENDERBUFFER_BLUE_SIZE
+ALIAS: GL_RENDERBUFFER_ALPHA_SIZE gl:GL_RENDERBUFFER_ALPHA_SIZE
+ALIAS: GL_RENDERBUFFER_DEPTH_SIZE gl:GL_RENDERBUFFER_DEPTH_SIZE
+ALIAS: GL_RENDERBUFFER_STENCIL_SIZE gl:GL_RENDERBUFFER_STENCIL_SIZE
+ALIAS: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE gl:GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
+ALIAS: GL_MAX_SAMPLES gl:GL_MAX_SAMPLES
+ALIAS: GL_FRAMEBUFFER_SRGB gl:GL_FRAMEBUFFER_SRGB
+ALIAS: GL_HALF_FLOAT gl:GL_HALF_FLOAT
+ALIAS: GL_MAP_READ_BIT gl:GL_MAP_READ_BIT
+ALIAS: GL_MAP_WRITE_BIT gl:GL_MAP_WRITE_BIT
+ALIAS: GL_MAP_INVALIDATE_RANGE_BIT gl:GL_MAP_INVALIDATE_RANGE_BIT
+ALIAS: GL_MAP_INVALIDATE_BUFFER_BIT gl:GL_MAP_INVALIDATE_BUFFER_BIT
+ALIAS: GL_MAP_FLUSH_EXPLICIT_BIT gl:GL_MAP_FLUSH_EXPLICIT_BIT
+ALIAS: GL_MAP_UNSYNCHRONIZED_BIT gl:GL_MAP_UNSYNCHRONIZED_BIT
+ALIAS: GL_COMPRESSED_RED_RGTC1 gl:GL_COMPRESSED_RED_RGTC1
+ALIAS: GL_COMPRESSED_SIGNED_RED_RGTC1 gl:GL_COMPRESSED_SIGNED_RED_RGTC1
+ALIAS: GL_COMPRESSED_RG_RGTC2 gl:GL_COMPRESSED_RG_RGTC2
+ALIAS: GL_COMPRESSED_SIGNED_RG_RGTC2 gl:GL_COMPRESSED_SIGNED_RG_RGTC2
+ALIAS: GL_RG gl:GL_RG
+ALIAS: GL_RG_INTEGER gl:GL_RG_INTEGER
+ALIAS: GL_R8 gl:GL_R8
+ALIAS: GL_R16 gl:GL_R16
+ALIAS: GL_RG8 gl:GL_RG8
+ALIAS: GL_RG16 gl:GL_RG16
+ALIAS: GL_R16F gl:GL_R16F
+ALIAS: GL_R32F gl:GL_R32F
+ALIAS: GL_RG16F gl:GL_RG16F
+ALIAS: GL_RG32F gl:GL_RG32F
+ALIAS: GL_R8I gl:GL_R8I
+ALIAS: GL_R8UI gl:GL_R8UI
+ALIAS: GL_R16I gl:GL_R16I
+ALIAS: GL_R16UI gl:GL_R16UI
+ALIAS: GL_R32I gl:GL_R32I
+ALIAS: GL_R32UI gl:GL_R32UI
+ALIAS: GL_RG8I gl:GL_RG8I
+ALIAS: GL_RG8UI gl:GL_RG8UI
+ALIAS: GL_RG16I gl:GL_RG16I
+ALIAS: GL_RG16UI gl:GL_RG16UI
+ALIAS: GL_RG32I gl:GL_RG32I
+ALIAS: GL_RG32UI gl:GL_RG32UI
+ALIAS: GL_VERTEX_ARRAY_BINDING gl:GL_VERTEX_ARRAY_BINDING
+ALIAS: GL_SAMPLER_2D_RECT gl:GL_SAMPLER_2D_RECT
+ALIAS: GL_SAMPLER_2D_RECT_SHADOW gl:GL_SAMPLER_2D_RECT_SHADOW
+ALIAS: GL_SAMPLER_BUFFER gl:GL_SAMPLER_BUFFER
+ALIAS: GL_INT_SAMPLER_2D_RECT gl:GL_INT_SAMPLER_2D_RECT
+ALIAS: GL_INT_SAMPLER_BUFFER gl:GL_INT_SAMPLER_BUFFER
+ALIAS: GL_UNSIGNED_INT_SAMPLER_2D_RECT gl:GL_UNSIGNED_INT_SAMPLER_2D_RECT
+ALIAS: GL_UNSIGNED_INT_SAMPLER_BUFFER gl:GL_UNSIGNED_INT_SAMPLER_BUFFER
+ALIAS: GL_TEXTURE_BUFFER gl:GL_TEXTURE_BUFFER
+ALIAS: GL_MAX_TEXTURE_BUFFER_SIZE gl:GL_MAX_TEXTURE_BUFFER_SIZE
+ALIAS: GL_TEXTURE_BINDING_BUFFER gl:GL_TEXTURE_BINDING_BUFFER
+ALIAS: GL_TEXTURE_BUFFER_DATA_STORE_BINDING gl:GL_TEXTURE_BUFFER_DATA_STORE_BINDING
+ALIAS: GL_TEXTURE_BUFFER_FORMAT gl:GL_TEXTURE_BUFFER_FORMAT
+ALIAS: GL_TEXTURE_RECTANGLE gl:GL_TEXTURE_RECTANGLE
+ALIAS: GL_TEXTURE_BINDING_RECTANGLE gl:GL_TEXTURE_BINDING_RECTANGLE
+ALIAS: GL_PROXY_TEXTURE_RECTANGLE gl:GL_PROXY_TEXTURE_RECTANGLE
+ALIAS: GL_MAX_RECTANGLE_TEXTURE_SIZE gl:GL_MAX_RECTANGLE_TEXTURE_SIZE
+ALIAS: GL_RED_SNORM gl:GL_RED_SNORM
+ALIAS: GL_RG_SNORM gl:GL_RG_SNORM
+ALIAS: GL_RGB_SNORM gl:GL_RGB_SNORM
+ALIAS: GL_RGBA_SNORM gl:GL_RGBA_SNORM
+ALIAS: GL_R8_SNORM gl:GL_R8_SNORM
+ALIAS: GL_RG8_SNORM gl:GL_RG8_SNORM
+ALIAS: GL_RGB8_SNORM gl:GL_RGB8_SNORM
+ALIAS: GL_RGBA8_SNORM gl:GL_RGBA8_SNORM
+ALIAS: GL_R16_SNORM gl:GL_R16_SNORM
+ALIAS: GL_RG16_SNORM gl:GL_RG16_SNORM
+ALIAS: GL_RGB16_SNORM gl:GL_RGB16_SNORM
+ALIAS: GL_RGBA16_SNORM gl:GL_RGBA16_SNORM
+ALIAS: GL_SIGNED_NORMALIZED gl:GL_SIGNED_NORMALIZED
+ALIAS: GL_PRIMITIVE_RESTART gl:GL_PRIMITIVE_RESTART
+ALIAS: GL_PRIMITIVE_RESTART_INDEX gl:GL_PRIMITIVE_RESTART_INDEX
+ALIAS: GL_COPY_READ_BUFFER gl:GL_COPY_READ_BUFFER
+ALIAS: GL_COPY_WRITE_BUFFER gl:GL_COPY_WRITE_BUFFER
+ALIAS: GL_UNIFORM_BUFFER gl:GL_UNIFORM_BUFFER
+ALIAS: GL_UNIFORM_BUFFER_BINDING gl:GL_UNIFORM_BUFFER_BINDING
+ALIAS: GL_UNIFORM_BUFFER_START gl:GL_UNIFORM_BUFFER_START
+ALIAS: GL_UNIFORM_BUFFER_SIZE gl:GL_UNIFORM_BUFFER_SIZE
+ALIAS: GL_MAX_VERTEX_UNIFORM_BLOCKS gl:GL_MAX_VERTEX_UNIFORM_BLOCKS
+ALIAS: GL_MAX_FRAGMENT_UNIFORM_BLOCKS gl:GL_MAX_FRAGMENT_UNIFORM_BLOCKS
+ALIAS: GL_MAX_COMBINED_UNIFORM_BLOCKS gl:GL_MAX_COMBINED_UNIFORM_BLOCKS
+ALIAS: GL_MAX_UNIFORM_BUFFER_BINDINGS gl:GL_MAX_UNIFORM_BUFFER_BINDINGS
+ALIAS: GL_MAX_UNIFORM_BLOCK_SIZE gl:GL_MAX_UNIFORM_BLOCK_SIZE
+ALIAS: GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS gl:GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS
+ALIAS: GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS gl:GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS
+ALIAS: GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT gl:GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
+ALIAS: GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH gl:GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
+ALIAS: GL_ACTIVE_UNIFORM_BLOCKS gl:GL_ACTIVE_UNIFORM_BLOCKS
+ALIAS: GL_UNIFORM_TYPE gl:GL_UNIFORM_TYPE
+ALIAS: GL_UNIFORM_SIZE gl:GL_UNIFORM_SIZE
+ALIAS: GL_UNIFORM_NAME_LENGTH gl:GL_UNIFORM_NAME_LENGTH
+ALIAS: GL_UNIFORM_BLOCK_INDEX gl:GL_UNIFORM_BLOCK_INDEX
+ALIAS: GL_UNIFORM_OFFSET gl:GL_UNIFORM_OFFSET
+ALIAS: GL_UNIFORM_ARRAY_STRIDE gl:GL_UNIFORM_ARRAY_STRIDE
+ALIAS: GL_UNIFORM_MATRIX_STRIDE gl:GL_UNIFORM_MATRIX_STRIDE
+ALIAS: GL_UNIFORM_IS_ROW_MAJOR gl:GL_UNIFORM_IS_ROW_MAJOR
+ALIAS: GL_UNIFORM_BLOCK_BINDING gl:GL_UNIFORM_BLOCK_BINDING
+ALIAS: GL_UNIFORM_BLOCK_DATA_SIZE gl:GL_UNIFORM_BLOCK_DATA_SIZE
+ALIAS: GL_UNIFORM_BLOCK_NAME_LENGTH gl:GL_UNIFORM_BLOCK_NAME_LENGTH
+ALIAS: GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS gl:GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
+ALIAS: GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES gl:GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
+ALIAS: GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER gl:GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
+ALIAS: GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER gl:GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
+ALIAS: GL_INVALID_INDEX gl:GL_INVALID_INDEX
+
+ALIAS: glCullFace gl:glCullFace
+ALIAS: glFrontFace gl:glFrontFace
+ALIAS: glHint gl:glHint
+ALIAS: glLineWidth gl:glLineWidth
+ALIAS: glPointSize gl:glPointSize
+ALIAS: glPolygonMode gl:glPolygonMode
+ALIAS: glScissor gl:glScissor
+ALIAS: glTexParameterf gl:glTexParameterf
+ALIAS: glTexParameterfv gl:glTexParameterfv
+ALIAS: glTexParameteri gl:glTexParameteri
+ALIAS: glTexParameteriv gl:glTexParameteriv
+ALIAS: glTexImage1D gl:glTexImage1D
+ALIAS: glTexImage2D gl:glTexImage2D
+ALIAS: glDrawBuffer gl:glDrawBuffer
+ALIAS: glClear gl:glClear
+ALIAS: glClearColor gl:glClearColor
+ALIAS: glClearStencil gl:glClearStencil
+ALIAS: glClearDepth gl:glClearDepth
+ALIAS: glStencilMask gl:glStencilMask
+ALIAS: glColorMask gl:glColorMask
+ALIAS: glDepthMask gl:glDepthMask
+ALIAS: glDisable gl:glDisable
+ALIAS: glEnable gl:glEnable
+ALIAS: glFinish gl:glFinish
+ALIAS: glFlush gl:glFlush
+ALIAS: glBlendFunc gl:glBlendFunc
+ALIAS: glLogicOp gl:glLogicOp
+ALIAS: glStencilFunc gl:glStencilFunc
+ALIAS: glStencilOp gl:glStencilOp
+ALIAS: glDepthFunc gl:glDepthFunc
+ALIAS: glPixelStoref gl:glPixelStoref
+ALIAS: glPixelStorei gl:glPixelStorei
+ALIAS: glReadBuffer gl:glReadBuffer
+ALIAS: glReadPixels gl:glReadPixels
+ALIAS: glGetBooleanv gl:glGetBooleanv
+ALIAS: glGetDoublev gl:glGetDoublev
+ALIAS: glGetError gl:glGetError
+ALIAS: glGetFloatv gl:glGetFloatv
+ALIAS: glGetIntegerv gl:glGetIntegerv
+ALIAS: glGetString gl:glGetString
+ALIAS: glGetTexImage gl:glGetTexImage
+ALIAS: glGetTexParameterfv gl:glGetTexParameterfv
+ALIAS: glGetTexParameteriv gl:glGetTexParameteriv
+ALIAS: glGetTexLevelParameterfv gl:glGetTexLevelParameterfv
+ALIAS: glGetTexLevelParameteriv gl:glGetTexLevelParameteriv
+ALIAS: glIsEnabled gl:glIsEnabled
+ALIAS: glDepthRange gl:glDepthRange
+ALIAS: glViewport gl:glViewport
+ALIAS: glDrawArrays gl:glDrawArrays
+ALIAS: glDrawElements gl:glDrawElements
+ALIAS: glGetPointerv gl:glGetPointerv
+ALIAS: glPolygonOffset gl:glPolygonOffset
+ALIAS: glCopyTexImage1D gl:glCopyTexImage1D
+ALIAS: glCopyTexImage2D gl:glCopyTexImage2D
+ALIAS: glCopyTexSubImage1D gl:glCopyTexSubImage1D
+ALIAS: glCopyTexSubImage2D gl:glCopyTexSubImage2D
+ALIAS: glTexSubImage1D gl:glTexSubImage1D
+ALIAS: glTexSubImage2D gl:glTexSubImage2D
+ALIAS: glBindTexture gl:glBindTexture
+ALIAS: glDeleteTextures gl:glDeleteTextures
+ALIAS: glGenTextures gl:glGenTextures
+ALIAS: glIsTexture gl:glIsTexture
+ALIAS: glBlendColor gl:glBlendColor
+ALIAS: glBlendEquation gl:glBlendEquation
+ALIAS: glDrawRangeElements gl:glDrawRangeElements
+ALIAS: glTexImage3D gl:glTexImage3D
+ALIAS: glTexSubImage3D gl:glTexSubImage3D
+ALIAS: glCopyTexSubImage3D gl:glCopyTexSubImage3D
+ALIAS: glActiveTexture gl:glActiveTexture
+ALIAS: glSampleCoverage gl:glSampleCoverage
+ALIAS: glCompressedTexImage3D gl:glCompressedTexImage3D
+ALIAS: glCompressedTexImage2D gl:glCompressedTexImage2D
+ALIAS: glCompressedTexImage1D gl:glCompressedTexImage1D
+ALIAS: glCompressedTexSubImage3D gl:glCompressedTexSubImage3D
+ALIAS: glCompressedTexSubImage2D gl:glCompressedTexSubImage2D
+ALIAS: glCompressedTexSubImage1D gl:glCompressedTexSubImage1D
+ALIAS: glGetCompressedTexImage gl:glGetCompressedTexImage
+ALIAS: glBlendFuncSeparate gl:glBlendFuncSeparate
+ALIAS: glMultiDrawArrays gl:glMultiDrawArrays
+ALIAS: glMultiDrawElements gl:glMultiDrawElements
+ALIAS: glPointParameterf gl:glPointParameterf
+ALIAS: glPointParameterfv gl:glPointParameterfv
+ALIAS: glPointParameteri gl:glPointParameteri
+ALIAS: glPointParameteriv gl:glPointParameteriv
+ALIAS: glGenQueries gl:glGenQueries
+ALIAS: glDeleteQueries gl:glDeleteQueries
+ALIAS: glIsQuery gl:glIsQuery
+ALIAS: glBeginQuery gl:glBeginQuery
+ALIAS: glEndQuery gl:glEndQuery
+ALIAS: glGetQueryiv gl:glGetQueryiv
+ALIAS: glGetQueryObjectiv gl:glGetQueryObjectiv
+ALIAS: glGetQueryObjectuiv gl:glGetQueryObjectuiv
+ALIAS: glBindBuffer gl:glBindBuffer
+ALIAS: glDeleteBuffers gl:glDeleteBuffers
+ALIAS: glGenBuffers gl:glGenBuffers
+ALIAS: glIsBuffer gl:glIsBuffer
+ALIAS: glBufferData gl:glBufferData
+ALIAS: glBufferSubData gl:glBufferSubData
+ALIAS: glGetBufferSubData gl:glGetBufferSubData
+ALIAS: glMapBuffer gl:glMapBuffer
+ALIAS: glUnmapBuffer gl:glUnmapBuffer
+ALIAS: glGetBufferParameteriv gl:glGetBufferParameteriv
+ALIAS: glGetBufferPointerv gl:glGetBufferPointerv
+ALIAS: glBlendEquationSeparate gl:glBlendEquationSeparate
+ALIAS: glDrawBuffers gl:glDrawBuffers
+ALIAS: glStencilOpSeparate gl:glStencilOpSeparate
+ALIAS: glStencilFuncSeparate gl:glStencilFuncSeparate
+ALIAS: glStencilMaskSeparate gl:glStencilMaskSeparate
+ALIAS: glAttachShader gl:glAttachShader
+ALIAS: glBindAttribLocation gl:glBindAttribLocation
+ALIAS: glCompileShader gl:glCompileShader
+ALIAS: glCreateProgram gl:glCreateProgram
+ALIAS: glCreateShader gl:glCreateShader
+ALIAS: glDeleteProgram gl:glDeleteProgram
+ALIAS: glDeleteShader gl:glDeleteShader
+ALIAS: glDetachShader gl:glDetachShader
+ALIAS: glDisableVertexAttribArray gl:glDisableVertexAttribArray
+ALIAS: glEnableVertexAttribArray gl:glEnableVertexAttribArray
+ALIAS: glGetActiveAttrib gl:glGetActiveAttrib
+ALIAS: glGetActiveUniform gl:glGetActiveUniform
+ALIAS: glGetAttachedShaders gl:glGetAttachedShaders
+ALIAS: glGetAttribLocation gl:glGetAttribLocation
+ALIAS: glGetProgramiv gl:glGetProgramiv
+ALIAS: glGetProgramInfoLog gl:glGetProgramInfoLog
+ALIAS: glGetShaderiv gl:glGetShaderiv
+ALIAS: glGetShaderInfoLog gl:glGetShaderInfoLog
+ALIAS: glGetShaderSource gl:glGetShaderSource
+ALIAS: glGetUniformLocation gl:glGetUniformLocation
+ALIAS: glGetUniformfv gl:glGetUniformfv
+ALIAS: glGetUniformiv gl:glGetUniformiv
+ALIAS: glGetVertexAttribdv gl:glGetVertexAttribdv
+ALIAS: glGetVertexAttribfv gl:glGetVertexAttribfv
+ALIAS: glGetVertexAttribiv gl:glGetVertexAttribiv
+ALIAS: glGetVertexAttribPointerv gl:glGetVertexAttribPointerv
+ALIAS: glIsProgram gl:glIsProgram
+ALIAS: glIsShader gl:glIsShader
+ALIAS: glLinkProgram gl:glLinkProgram
+ALIAS: glShaderSource gl:glShaderSource
+ALIAS: glUseProgram gl:glUseProgram
+ALIAS: glUniform1f gl:glUniform1f
+ALIAS: glUniform2f gl:glUniform2f
+ALIAS: glUniform3f gl:glUniform3f
+ALIAS: glUniform4f gl:glUniform4f
+ALIAS: glUniform1i gl:glUniform1i
+ALIAS: glUniform2i gl:glUniform2i
+ALIAS: glUniform3i gl:glUniform3i
+ALIAS: glUniform4i gl:glUniform4i
+ALIAS: glUniform1fv gl:glUniform1fv
+ALIAS: glUniform2fv gl:glUniform2fv
+ALIAS: glUniform3fv gl:glUniform3fv
+ALIAS: glUniform4fv gl:glUniform4fv
+ALIAS: glUniform1iv gl:glUniform1iv
+ALIAS: glUniform2iv gl:glUniform2iv
+ALIAS: glUniform3iv gl:glUniform3iv
+ALIAS: glUniform4iv gl:glUniform4iv
+ALIAS: glUniformMatrix2fv gl:glUniformMatrix2fv
+ALIAS: glUniformMatrix3fv gl:glUniformMatrix3fv
+ALIAS: glUniformMatrix4fv gl:glUniformMatrix4fv
+ALIAS: glValidateProgram gl:glValidateProgram
+ALIAS: glVertexAttrib1d gl:glVertexAttrib1d
+ALIAS: glVertexAttrib1dv gl:glVertexAttrib1dv
+ALIAS: glVertexAttrib1f gl:glVertexAttrib1f
+ALIAS: glVertexAttrib1fv gl:glVertexAttrib1fv
+ALIAS: glVertexAttrib1s gl:glVertexAttrib1s
+ALIAS: glVertexAttrib1sv gl:glVertexAttrib1sv
+ALIAS: glVertexAttrib2d gl:glVertexAttrib2d
+ALIAS: glVertexAttrib2dv gl:glVertexAttrib2dv
+ALIAS: glVertexAttrib2f gl:glVertexAttrib2f
+ALIAS: glVertexAttrib2fv gl:glVertexAttrib2fv
+ALIAS: glVertexAttrib2s gl:glVertexAttrib2s
+ALIAS: glVertexAttrib2sv gl:glVertexAttrib2sv
+ALIAS: glVertexAttrib3d gl:glVertexAttrib3d
+ALIAS: glVertexAttrib3dv gl:glVertexAttrib3dv
+ALIAS: glVertexAttrib3f gl:glVertexAttrib3f
+ALIAS: glVertexAttrib3fv gl:glVertexAttrib3fv
+ALIAS: glVertexAttrib3s gl:glVertexAttrib3s
+ALIAS: glVertexAttrib3sv gl:glVertexAttrib3sv
+ALIAS: glVertexAttrib4Nbv gl:glVertexAttrib4Nbv
+ALIAS: glVertexAttrib4Niv gl:glVertexAttrib4Niv
+ALIAS: glVertexAttrib4Nsv gl:glVertexAttrib4Nsv
+ALIAS: glVertexAttrib4Nub gl:glVertexAttrib4Nub
+ALIAS: glVertexAttrib4Nubv gl:glVertexAttrib4Nubv
+ALIAS: glVertexAttrib4Nuiv gl:glVertexAttrib4Nuiv
+ALIAS: glVertexAttrib4Nusv gl:glVertexAttrib4Nusv
+ALIAS: glVertexAttrib4bv gl:glVertexAttrib4bv
+ALIAS: glVertexAttrib4d gl:glVertexAttrib4d
+ALIAS: glVertexAttrib4dv gl:glVertexAttrib4dv
+ALIAS: glVertexAttrib4f gl:glVertexAttrib4f
+ALIAS: glVertexAttrib4fv gl:glVertexAttrib4fv
+ALIAS: glVertexAttrib4iv gl:glVertexAttrib4iv
+ALIAS: glVertexAttrib4s gl:glVertexAttrib4s
+ALIAS: glVertexAttrib4sv gl:glVertexAttrib4sv
+ALIAS: glVertexAttrib4ubv gl:glVertexAttrib4ubv
+ALIAS: glVertexAttrib4uiv gl:glVertexAttrib4uiv
+ALIAS: glVertexAttrib4usv gl:glVertexAttrib4usv
+ALIAS: glVertexAttribPointer gl:glVertexAttribPointer
+ALIAS: glUniformMatrix2x3fv gl:glUniformMatrix2x3fv
+ALIAS: glUniformMatrix3x2fv gl:glUniformMatrix3x2fv
+ALIAS: glUniformMatrix2x4fv gl:glUniformMatrix2x4fv
+ALIAS: glUniformMatrix4x2fv gl:glUniformMatrix4x2fv
+ALIAS: glUniformMatrix3x4fv gl:glUniformMatrix3x4fv
+ALIAS: glUniformMatrix4x3fv gl:glUniformMatrix4x3fv
+ALIAS: glColorMaski gl:glColorMaski
+ALIAS: glGetBooleani_v gl:glGetBooleani_v
+ALIAS: glGetIntegeri_v gl:glGetIntegeri_v
+ALIAS: glEnablei gl:glEnablei
+ALIAS: glDisablei gl:glDisablei
+ALIAS: glIsEnabledi gl:glIsEnabledi
+ALIAS: glBeginTransformFeedback gl:glBeginTransformFeedback
+ALIAS: glEndTransformFeedback gl:glEndTransformFeedback
+ALIAS: glBindBufferRange gl:glBindBufferRange
+ALIAS: glBindBufferBase gl:glBindBufferBase
+ALIAS: glTransformFeedbackVaryings gl:glTransformFeedbackVaryings
+ALIAS: glGetTransformFeedbackVarying gl:glGetTransformFeedbackVarying
+ALIAS: glClampColor gl:glClampColor
+ALIAS: glBeginConditionalRender gl:glBeginConditionalRender
+ALIAS: glEndConditionalRender gl:glEndConditionalRender
+ALIAS: glVertexAttribIPointer gl:glVertexAttribIPointer
+ALIAS: glGetVertexAttribIiv gl:glGetVertexAttribIiv
+ALIAS: glGetVertexAttribIuiv gl:glGetVertexAttribIuiv
+ALIAS: glGetUniformuiv gl:glGetUniformuiv
+ALIAS: glBindFragDataLocation gl:glBindFragDataLocation
+ALIAS: glGetFragDataLocation gl:glGetFragDataLocation
+ALIAS: glUniform1ui gl:glUniform1ui
+ALIAS: glUniform2ui gl:glUniform2ui
+ALIAS: glUniform3ui gl:glUniform3ui
+ALIAS: glUniform4ui gl:glUniform4ui
+ALIAS: glUniform1uiv gl:glUniform1uiv
+ALIAS: glUniform2uiv gl:glUniform2uiv
+ALIAS: glUniform3uiv gl:glUniform3uiv
+ALIAS: glUniform4uiv gl:glUniform4uiv
+ALIAS: glTexParameterIiv gl:glTexParameterIiv
+ALIAS: glTexParameterIuiv gl:glTexParameterIuiv
+ALIAS: glGetTexParameterIiv gl:glGetTexParameterIiv
+ALIAS: glGetTexParameterIuiv gl:glGetTexParameterIuiv
+ALIAS: glClearBufferiv gl:glClearBufferiv
+ALIAS: glClearBufferuiv gl:glClearBufferuiv
+ALIAS: glClearBufferfv gl:glClearBufferfv
+ALIAS: glClearBufferfi gl:glClearBufferfi
+ALIAS: glGetStringi gl:glGetStringi
+ALIAS: glDrawArraysInstanced gl:glDrawArraysInstanced
+ALIAS: glDrawElementsInstanced gl:glDrawElementsInstanced
+ALIAS: glTexBuffer gl:glTexBuffer
+ALIAS: glPrimitiveRestartIndex gl:glPrimitiveRestartIndex
+ALIAS: glIsRenderbuffer gl:glIsRenderbuffer
+ALIAS: glBindRenderbuffer gl:glBindRenderbuffer
+ALIAS: glDeleteRenderbuffers gl:glDeleteRenderbuffers
+ALIAS: glGenRenderbuffers gl:glGenRenderbuffers
+ALIAS: glRenderbufferStorage gl:glRenderbufferStorage
+ALIAS: glGetRenderbufferParameteriv gl:glGetRenderbufferParameteriv
+ALIAS: glIsFramebuffer gl:glIsFramebuffer
+ALIAS: glBindFramebuffer gl:glBindFramebuffer
+ALIAS: glDeleteFramebuffers gl:glDeleteFramebuffers
+ALIAS: glGenFramebuffers gl:glGenFramebuffers
+ALIAS: glCheckFramebufferStatus gl:glCheckFramebufferStatus
+ALIAS: glFramebufferTexture1D gl:glFramebufferTexture1D
+ALIAS: glFramebufferTexture2D gl:glFramebufferTexture2D
+ALIAS: glFramebufferTexture3D gl:glFramebufferTexture3D
+ALIAS: glFramebufferRenderbuffer gl:glFramebufferRenderbuffer
+ALIAS: glGetFramebufferAttachmentParameteriv gl:glGetFramebufferAttachmentParameteriv
+ALIAS: glGenerateMipmap gl:glGenerateMipmap
+ALIAS: glBlitFramebuffer gl:glBlitFramebuffer
+ALIAS: glRenderbufferStorageMultisample gl:glRenderbufferStorageMultisample
+ALIAS: glFramebufferTextureLayer gl:glFramebufferTextureLayer
+ALIAS: glMapBufferRange gl:glMapBufferRange
+ALIAS: glFlushMappedBufferRange gl:glFlushMappedBufferRange
+ALIAS: glBindVertexArray gl:glBindVertexArray
+ALIAS: glDeleteVertexArrays gl:glDeleteVertexArrays
+ALIAS: glGenVertexArrays gl:glGenVertexArrays
+ALIAS: glIsVertexArray gl:glIsVertexArray
+ALIAS: glGetUniformIndices gl:glGetUniformIndices
+ALIAS: glGetActiveUniformsiv gl:glGetActiveUniformsiv
+ALIAS: glGetActiveUniformName gl:glGetActiveUniformName
+ALIAS: glGetUniformBlockIndex gl:glGetUniformBlockIndex
+ALIAS: glGetActiveUniformBlockiv gl:glGetActiveUniformBlockiv
+ALIAS: glGetActiveUniformBlockName gl:glGetActiveUniformBlockName
+ALIAS: glUniformBlockBinding gl:glUniformBlockBinding
+ALIAS: glCopyBufferSubData gl:glCopyBufferSubData
--- /dev/null
+Forward-compatible subset of OpenGL 3.1
USING: alien help.markup help.syntax io kernel math quotations
-opengl.gl assocs vocabs.loader sequences accessors colors ;
+opengl.gl assocs vocabs.loader sequences accessors colors words ;
IN: opengl
HELP: gl-color
{ $notes "See " { $link "colors" } "." } ;
HELP: gl-error
-{ $description "If the most recent OpenGL call resulted in an error, print the error to " { $link output-stream } "." } ;
+{ $description "If the most recent OpenGL call resulted in an error, throw a " { $snippet "gl-error" } " instance reporting the error." } ;
HELP: do-enabled
{ $values { "what" integer } { "quot" quotation } }
{ $description "Binds texture " { $snippet "id" } " to texture target " { $snippet "target" } " of texture unit " { $snippet "unit" } ". Equivalent to " { $snippet "unit glActiveTexture target id glBindTexture" } "." } ;
HELP: set-draw-buffers
-{ $values { "buffers" "A sequence of buffer words (e.g. " { $snippet "GL_BACK" } ", " { $snippet "GL_COLOR_ATTACHMENT0_EXT" } ")"} }
+{ $values { "buffers" "A sequence of buffer words (e.g. " { $snippet "GL_BACK" } ", " { $snippet "GL_COLOR_ATTACHMENT0" } ")"} }
{ $description "Wrapper for " { $link glDrawBuffers } ". Sets up the buffers named in the sequence for simultaneous drawing." } ;
HELP: do-attribs
$nl
"The " { $vocab-link "opengl.gl" } " and " { $vocab-link "opengl.glu" } " vocabularies have the actual OpenGL bindings."
{ $subsection "opengl-low-level" }
+"Error reporting:"
+{ $subsection gl-error }
"Wrappers:"
{ $subsection gl-color }
{ $subsection gl-translate }
! Portions copyright (C) 2007 Eduardo Cavazos.
! Portions copyright (C) 2008 Joe Groff.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.c-types continuations kernel libc math macros
-namespaces math.vectors math.parser opengl.gl combinators
-combinators.smart arrays sequences splitting words byte-arrays assocs
+USING: alien alien.c-types ascii calendar combinators.short-circuit
+continuations kernel libc math macros namespaces math.vectors
+math.parser opengl.gl combinators combinators.smart arrays
+sequences splitting words byte-arrays assocs vocabs
colors colors.constants accessors generalizations locals fry
specialized-arrays.float specialized-arrays.uint ;
IN: opengl
{ HEX: 0503 "Stack overflow" }
{ HEX: 0504 "Stack underflow" }
{ HEX: 0505 "Out of memory" }
+ { HEX: 0506 "Invalid framebuffer operation" }
} at "Unknown error" or ;
-TUPLE: gl-error code string ;
+TUPLE: gl-error function code string ;
+
+: <gl-error> ( function code -- gl-error )
+ dup error>string \ gl-error boa ; inline
+
+: gl-error-code ( -- code/f )
+ glGetError dup 0 = [ drop f ] when ; inline
+
+: (gl-error) ( function -- )
+ gl-error-code [ <gl-error> throw ] [ drop ] if* ;
: gl-error ( -- )
- glGetError dup 0 = [ drop ] [
- dup error>string \ gl-error boa throw
- ] if ;
+ f (gl-error) ; inline
: do-enabled ( what quot -- )
over glEnable dip glDisable ; inline
: (gen-gl-object) ( quot -- id )
[ 1 0 <uint> ] dip keep *uint ; inline
-: gen-gl-buffer ( -- id )
- [ glGenBuffers ] (gen-gl-object) ;
-
: (delete-gl-object) ( id quot -- )
[ 1 swap <uint> ] dip call ; inline
+: gen-gl-buffer ( -- id )
+ [ glGenBuffers ] (gen-gl-object) ;
+
: delete-gl-buffer ( id -- )
[ glDeleteBuffers ] (delete-gl-object) ;
GL_ARRAY_BUFFER swap _ with-gl-buffer
] with-gl-buffer ; inline
+: gen-vertex-array ( -- id )
+ [ glGenVertexArrays ] (gen-gl-object) ;
+
+: delete-vertex-array ( id -- )
+ [ glDeleteVertexArrays ] (delete-gl-object) ;
+
+:: with-vertex-array ( id quot -- )
+ id glBindVertexArray
+ quot [ 0 glBindVertexArray ] [ ] cleanup ; inline
+
: <gl-buffer> ( target data hint -- id )
pick gen-gl-buffer [
[
GL_PROJECTION glMatrixMode
glLoadIdentity
GL_MODELVIEW glMatrixMode
- glLoadIdentity ;
\ No newline at end of file
+ glLoadIdentity ;
! Programs
+: (gl-program) ( shaders quot: ( gl-program -- ) -- program )
+ glCreateProgram
+ [
+ [ swap [ glAttachShader ] with each ]
+ [ swap call ] bi-curry bi*
+ ] [ glLinkProgram ] [ ] tri gl-error ; inline
+
+: <mrt-gl-program> ( shaders frag-data-locations -- program )
+ [ [ first2 swap glBindFragDataLocation ] with each ] curry (gl-program) ;
+
: <gl-program> ( shaders -- program )
- glCreateProgram swap
- [ dupd glAttachShader ] each
- [ glLinkProgram ] keep
- gl-error ;
+ [ drop ] (gl-program) ;
: (gl-program?) ( object -- ? )
dup integer? [ glIsProgram c-bool> ] [ drop f ] if ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test opengl.textures opengl.textures.private
-images kernel namespaces accessors sequences ;
+USING: tools.test opengl.gl opengl.textures opengl.textures.private
+images kernel namespaces accessors sequences literals ;
IN: opengl.textures.tests
[
{ { 10 30 } { 30 300 } }
}
[ [ image new swap >>dim ] map ] map image-locs
-] unit-test
\ No newline at end of file
+] unit-test
+
+${ GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE }
+[ RGBA ubyte-components (image-format) ] unit-test
+
+${ GL_RGBA8 GL_BGRA GL_UNSIGNED_BYTE }
+[ BGRA ubyte-components (image-format) ] unit-test
+
+${ GL_RGBA8 GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV }
+[ ARGB ubyte-components (image-format) ] unit-test
+
+${ GL_RGBA32F GL_RGBA GL_FLOAT }
+[ RGBA float-components (image-format) ] unit-test
+
+${ GL_RGBA32UI GL_BGRA_INTEGER GL_UNSIGNED_INT }
+[ BGRA uint-integer-components (image-format) ] unit-test
+
+${ GL_RGB9_E5 GL_RGB GL_UNSIGNED_INT_5_9_9_9_REV }
+[ BGR u-9-9-9-e5-components (image-format) ] unit-test
+
+${ GL_R11F_G11F_B10F GL_RGB GL_UNSIGNED_INT_10F_11F_11F_REV }
+[ BGR float-11-11-10-components (image-format) ] unit-test
opengl opengl.gl opengl.capabilities combinators images
images.tesselation grouping specialized-arrays.float sequences math
math.vectors math.matrices generalizations fry arrays namespaces
-system ;
+system locals literals ;
IN: opengl.textures
SYMBOL: non-power-of-2-textures?
: delete-texture ( id -- ) [ glDeleteTextures ] (delete-gl-object) ;
-GENERIC: component-order>format ( component-order -- format type )
+ERROR: unsupported-component-order component-order component-type ;
+
+CONSTANT: image-internal-formats H{
+ { { A ubyte-components } $ GL_ALPHA8 }
+ { { A ushort-components } $ GL_ALPHA16 }
+ { { A half-components } $ GL_ALPHA16F_ARB }
+ { { A float-components } $ GL_ALPHA32F_ARB }
+ { { A byte-integer-components } $ GL_ALPHA8I_EXT }
+ { { A ubyte-integer-components } $ GL_ALPHA8UI_EXT }
+ { { A short-integer-components } $ GL_ALPHA16I_EXT }
+ { { A ushort-integer-components } $ GL_ALPHA16UI_EXT }
+ { { A int-integer-components } $ GL_ALPHA32I_EXT }
+ { { A uint-integer-components } $ GL_ALPHA32UI_EXT }
+
+ { { L ubyte-components } $ GL_LUMINANCE8 }
+ { { L ushort-components } $ GL_LUMINANCE16 }
+ { { L half-components } $ GL_LUMINANCE16F_ARB }
+ { { L float-components } $ GL_LUMINANCE32F_ARB }
+ { { L byte-integer-components } $ GL_LUMINANCE8I_EXT }
+ { { L ubyte-integer-components } $ GL_LUMINANCE8UI_EXT }
+ { { L short-integer-components } $ GL_LUMINANCE16I_EXT }
+ { { L ushort-integer-components } $ GL_LUMINANCE16UI_EXT }
+ { { L int-integer-components } $ GL_LUMINANCE32I_EXT }
+ { { L uint-integer-components } $ GL_LUMINANCE32UI_EXT }
+
+ { { R ubyte-components } $ GL_R8 }
+ { { R ushort-components } $ GL_R16 }
+ { { R half-components } $ GL_R16F }
+ { { R float-components } $ GL_R32F }
+ { { R byte-integer-components } $ GL_R8I }
+ { { R ubyte-integer-components } $ GL_R8UI }
+ { { R short-integer-components } $ GL_R16I }
+ { { R ushort-integer-components } $ GL_R16UI }
+ { { R int-integer-components } $ GL_R32I }
+ { { R uint-integer-components } $ GL_R32UI }
+
+ { { INTENSITY ubyte-components } $ GL_INTENSITY8 }
+ { { INTENSITY ushort-components } $ GL_INTENSITY16 }
+ { { INTENSITY half-components } $ GL_INTENSITY16F_ARB }
+ { { INTENSITY float-components } $ GL_INTENSITY32F_ARB }
+ { { INTENSITY byte-integer-components } $ GL_INTENSITY8I_EXT }
+ { { INTENSITY ubyte-integer-components } $ GL_INTENSITY8UI_EXT }
+ { { INTENSITY short-integer-components } $ GL_INTENSITY16I_EXT }
+ { { INTENSITY ushort-integer-components } $ GL_INTENSITY16UI_EXT }
+ { { INTENSITY int-integer-components } $ GL_INTENSITY32I_EXT }
+ { { INTENSITY uint-integer-components } $ GL_INTENSITY32UI_EXT }
+
+ { { DEPTH ushort-components } $ GL_DEPTH_COMPONENT16 }
+ { { DEPTH u-24-components } $ GL_DEPTH_COMPONENT24 }
+ { { DEPTH uint-components } $ GL_DEPTH_COMPONENT32 }
+ { { DEPTH float-components } $ GL_DEPTH_COMPONENT32F }
+
+ { { LA ubyte-components } $ GL_LUMINANCE8_ALPHA8 }
+ { { LA ushort-components } $ GL_LUMINANCE16_ALPHA16 }
+ { { LA half-components } $ GL_LUMINANCE_ALPHA16F_ARB }
+ { { LA float-components } $ GL_LUMINANCE_ALPHA32F_ARB }
+ { { LA byte-integer-components } $ GL_LUMINANCE_ALPHA8I_EXT }
+ { { LA ubyte-integer-components } $ GL_LUMINANCE_ALPHA8UI_EXT }
+ { { LA short-integer-components } $ GL_LUMINANCE_ALPHA16I_EXT }
+ { { LA ushort-integer-components } $ GL_LUMINANCE_ALPHA16UI_EXT }
+ { { LA int-integer-components } $ GL_LUMINANCE_ALPHA32I_EXT }
+ { { LA uint-integer-components } $ GL_LUMINANCE_ALPHA32UI_EXT }
+
+ { { RG ubyte-components } $ GL_RG8 }
+ { { RG ushort-components } $ GL_RG16 }
+ { { RG half-components } $ GL_RG16F }
+ { { RG float-components } $ GL_RG32F }
+ { { RG byte-integer-components } $ GL_RG8I }
+ { { RG ubyte-integer-components } $ GL_RG8UI }
+ { { RG short-integer-components } $ GL_RG16I }
+ { { RG ushort-integer-components } $ GL_RG16UI }
+ { { RG int-integer-components } $ GL_RG32I }
+ { { RG uint-integer-components } $ GL_RG32UI }
+
+ { { DEPTH-STENCIL u-24-8-components } $ GL_DEPTH24_STENCIL8 }
+ { { DEPTH-STENCIL float-32-u-8-components } $ GL_DEPTH32F_STENCIL8 }
+
+ { { RGB ubyte-components } $ GL_RGB8 }
+ { { RGB ushort-components } $ GL_RGB16 }
+ { { RGB half-components } $ GL_RGB16F }
+ { { RGB float-components } $ GL_RGB32F }
+ { { RGB byte-integer-components } $ GL_RGB8I }
+ { { RGB ubyte-integer-components } $ GL_RGB8UI }
+ { { RGB byte-integer-components } $ GL_RGB8I }
+ { { RGB ubyte-integer-components } $ GL_RGB8UI }
+ { { RGB short-integer-components } $ GL_RGB16I }
+ { { RGB ushort-integer-components } $ GL_RGB16UI }
+ { { RGB int-integer-components } $ GL_RGB32I }
+ { { RGB uint-integer-components } $ GL_RGB32UI }
+ { { RGB u-5-6-5-components } $ GL_RGB5 }
+ { { RGB u-9-9-9-e5-components } $ GL_RGB9_E5 }
+ { { RGB float-11-11-10-components } $ GL_R11F_G11F_B10F }
+
+ { { RGBA ubyte-components } $ GL_RGBA8 }
+ { { RGBA ushort-components } $ GL_RGBA16 }
+ { { RGBA half-components } $ GL_RGBA16F }
+ { { RGBA float-components } $ GL_RGBA32F }
+ { { RGBA byte-integer-components } $ GL_RGBA8I }
+ { { RGBA ubyte-integer-components } $ GL_RGBA8UI }
+ { { RGBA byte-integer-components } $ GL_RGBA8I }
+ { { RGBA ubyte-integer-components } $ GL_RGBA8UI }
+ { { RGBA short-integer-components } $ GL_RGBA16I }
+ { { RGBA ushort-integer-components } $ GL_RGBA16UI }
+ { { RGBA int-integer-components } $ GL_RGBA32I }
+ { { RGBA uint-integer-components } $ GL_RGBA32UI }
+ { { RGBA u-5-5-5-1-components } $ GL_RGB5_A1 }
+ { { RGBA u-10-10-10-2-components } $ GL_RGB10_A2 }
+}
+
+GENERIC: fix-internal-component-order ( order -- order' )
+
+M: object fix-internal-component-order ;
+M: BGR fix-internal-component-order drop RGB ;
+M: BGRA fix-internal-component-order drop RGBA ;
+M: ARGB fix-internal-component-order drop RGBA ;
+M: ABGR fix-internal-component-order drop RGBA ;
+M: RGBX fix-internal-component-order drop RGBA ;
+M: BGRX fix-internal-component-order drop RGBA ;
+M: XRGB fix-internal-component-order drop RGBA ;
+M: XBGR fix-internal-component-order drop RGBA ;
+
+: image-internal-format ( component-order component-type -- internal-format )
+ 2dup
+ [ fix-internal-component-order ] dip 2array image-internal-formats at
+ [ 2nip ] [ unsupported-component-order ] if* ;
+
+: reversed-type? ( component-type -- ? )
+ { u-9-9-9-e5-components float-11-11-10-components } member? ;
+
+: (component-order>format) ( component-order component-type -- gl-format )
+ dup unnormalized-integer-components? [
+ swap {
+ { A [ drop GL_ALPHA_INTEGER_EXT ] }
+ { L [ drop GL_LUMINANCE_INTEGER_EXT ] }
+ { R [ drop GL_RED_INTEGER ] }
+ { LA [ drop GL_LUMINANCE_ALPHA_INTEGER_EXT ] }
+ { RG [ drop GL_RG_INTEGER ] }
+ { BGR [ drop GL_BGR_INTEGER ] }
+ { RGB [ drop GL_RGB_INTEGER ] }
+ { BGRA [ drop GL_BGRA_INTEGER ] }
+ { RGBA [ drop GL_RGBA_INTEGER ] }
+ { BGRX [ drop GL_BGRA_INTEGER ] }
+ { RGBX [ drop GL_RGBA_INTEGER ] }
+ [ swap unsupported-component-order ]
+ } case
+ ] [
+ swap {
+ { A [ drop GL_ALPHA ] }
+ { L [ drop GL_LUMINANCE ] }
+ { R [ drop GL_RED ] }
+ { LA [ drop GL_LUMINANCE_ALPHA ] }
+ { RG [ drop GL_RG ] }
+ { BGR [ reversed-type? GL_RGB GL_BGR ? ] }
+ { RGB [ reversed-type? GL_BGR GL_RGB ? ] }
+ { BGRA [ drop GL_BGRA ] }
+ { RGBA [ drop GL_RGBA ] }
+ { ARGB [ drop GL_BGRA ] }
+ { ABGR [ drop GL_RGBA ] }
+ { BGRX [ drop GL_BGRA ] }
+ { RGBX [ drop GL_RGBA ] }
+ { XRGB [ drop GL_BGRA ] }
+ { XBGR [ drop GL_RGBA ] }
+ { INTENSITY [ drop GL_INTENSITY ] }
+ { DEPTH [ drop GL_DEPTH_COMPONENT ] }
+ { DEPTH-STENCIL [ drop GL_DEPTH_STENCIL ] }
+ [ swap unsupported-component-order ]
+ } case
+ ] if ;
+
+GENERIC: (component-type>type) ( component-order component-type -- gl-type )
+
+M: object (component-type>type) unsupported-component-order ;
+
+: four-channel-alpha-first? ( component-order component-type -- ? )
+ over component-count 4 =
+ [ drop alpha-channel-precedes-colors? ]
+ [ unsupported-component-order ] if ;
+
+: not-alpha-first ( component-order component-type -- )
+ over alpha-channel-precedes-colors?
+ [ unsupported-component-order ]
+ [ 2drop ] if ;
+
+M: ubyte-components (component-type>type)
+ drop alpha-channel-precedes-colors?
+ [ GL_UNSIGNED_INT_8_8_8_8_REV ]
+ [ GL_UNSIGNED_BYTE ] if ;
+
+M: ushort-components (component-type>type) not-alpha-first GL_UNSIGNED_SHORT ;
+M: uint-components (component-type>type) not-alpha-first GL_UNSIGNED_INT ;
+M: half-components (component-type>type) not-alpha-first GL_HALF_FLOAT ;
+M: float-components (component-type>type) not-alpha-first GL_FLOAT ;
+M: byte-integer-components (component-type>type) not-alpha-first GL_BYTE ;
+M: ubyte-integer-components (component-type>type) not-alpha-first GL_UNSIGNED_BYTE ;
+M: short-integer-components (component-type>type) not-alpha-first GL_SHORT ;
+M: ushort-integer-components (component-type>type) not-alpha-first GL_UNSIGNED_SHORT ;
+M: int-integer-components (component-type>type) not-alpha-first GL_INT ;
+M: uint-integer-components (component-type>type) not-alpha-first GL_UNSIGNED_INT ;
+
+M: u-5-5-5-1-components (component-type>type)
+ four-channel-alpha-first?
+ [ GL_UNSIGNED_SHORT_1_5_5_5_REV ]
+ [ GL_UNSIGNED_SHORT_5_5_5_1 ] if ;
+
+M: u-5-6-5-components (component-type>type) 2drop GL_UNSIGNED_SHORT_5_6_5 ;
+
+M: u-10-10-10-2-components (component-type>type)
+ four-channel-alpha-first?
+ [ GL_UNSIGNED_INT_2_10_10_10_REV ]
+ [ GL_UNSIGNED_INT_10_10_10_2 ] if ;
-M: RGB component-order>format drop GL_RGB GL_UNSIGNED_BYTE ;
-M: BGR component-order>format drop GL_BGR GL_UNSIGNED_BYTE ;
-M: RGBA component-order>format drop GL_RGBA GL_UNSIGNED_BYTE ;
-M: ARGB component-order>format drop GL_BGRA_EXT GL_UNSIGNED_INT_8_8_8_8_REV ;
-M: BGRA component-order>format drop GL_BGRA_EXT GL_UNSIGNED_BYTE ;
-M: BGRX component-order>format drop GL_BGRA_EXT GL_UNSIGNED_BYTE ;
-M: LA component-order>format drop GL_LUMINANCE_ALPHA GL_UNSIGNED_BYTE ;
-M: L component-order>format drop GL_LUMINANCE GL_UNSIGNED_BYTE ;
+M: u-24-components (component-type>type)
+ over DEPTH =
+ [ 2drop GL_UNSIGNED_INT ] [ unsupported-component-order ] if ;
+
+M: u-24-8-components (component-type>type)
+ over DEPTH-STENCIL =
+ [ 2drop GL_UNSIGNED_INT_24_8 ] [ unsupported-component-order ] if ;
+
+M: u-9-9-9-e5-components (component-type>type)
+ over BGR =
+ [ 2drop GL_UNSIGNED_INT_5_9_9_9_REV ] [ unsupported-component-order ] if ;
+
+M: float-11-11-10-components (component-type>type)
+ over BGR =
+ [ 2drop GL_UNSIGNED_INT_10F_11F_11F_REV ] [ unsupported-component-order ] if ;
+
+: image-data-format ( component-order component-type -- gl-format gl-type )
+ [ (component-order>format) ] [ (component-type>type) ] 2bi ;
SLOT: display-list
DEFER: make-texture
+: (image-format) ( component-order component-type -- internal-format format type )
+ [ image-internal-format ] [ image-data-format ] 2bi ;
+
+: image-format ( image -- internal-format format type )
+ [ component-order>> ] [ component-type>> ] bi (image-format) ;
+
<PRIVATE
-TUPLE: single-texture image dim loc texture-coords texture display-list disposed ;
+TUPLE: single-texture < disposable image dim loc texture-coords texture display-list ;
: adjust-texture-dim ( dim -- dim' )
non-power-of-2-textures? get [
[ dup 1 = [ next-power-of-2 ] unless ] map
] unless ;
-: (tex-image) ( image bitmap -- )
- [
- [ GL_TEXTURE_2D 0 GL_RGBA ] dip
- [ dim>> adjust-texture-dim first2 0 ]
- [ component-order>> component-order>format ] bi
- ] dip
- glTexImage2D ;
+:: tex-image ( image bitmap -- )
+ image image-format :> type :> format :> internal-format
+ GL_TEXTURE_2D 0 internal-format
+ image dim>> adjust-texture-dim first2 0
+ format type bitmap glTexImage2D ;
-: (tex-sub-image) ( image -- )
+: tex-sub-image ( image -- )
[ GL_TEXTURE_2D 0 0 0 ] dip
- [ dim>> first2 ] [ component-order>> component-order>format ] [ bitmap>> ] tri
+ [ dim>> first2 ]
+ [ image-format [ drop ] 2dip ]
+ [ bitmap>> ] tri
glTexSubImage2D ;
: init-texture ( -- )
GL_COMPILE [ [ dim>> ] keep draw-textured-rect ] make-dlist ;
: <single-texture> ( image loc -- texture )
- single-texture new swap >>loc swap [ >>image ] [ dim>> >>dim ] bi
+ single-texture new-disposable swap >>loc swap [ >>image ] [ dim>> >>dim ] bi
dup image>> dim>> product 0 = [
dup texture-coords >>texture-coords
dup image>> make-texture >>texture
dup texture>> [ draw-textured-rect ] [ 2drop ] if
] if ;
-TUPLE: multi-texture grid display-list loc disposed ;
+TUPLE: multi-texture < disposable grid display-list loc ;
: image-locs ( image-grid -- loc-grid )
[ first [ dim>> first ] map ] [ [ first dim>> second ] map ] bi
[ dup image-locs ] dip
'[ [ _ v+ <single-texture> |dispose ] 2map ] 2map ;
-: draw-textured-grid ( grid -- )
- [ [ [ dim>> ] keep (draw-textured-rect) ] each ] each ;
-
: grid-has-alpha? ( grid -- ? )
first first image>> has-alpha? ;
: <multi-texture> ( image-grid loc -- multi-texture )
[
- [
- <texture-grid> dup
- make-textured-grid-display-list
- ] keep
- f multi-texture boa
+ [ multi-texture new-disposable ] 2dip
+ [ nip >>loc ] [ <texture-grid> >>grid ] 2bi
+ dup grid>> make-textured-grid-display-list >>display-list
] with-destructors ;
M: multi-texture draw-scaled-texture nip draw-texture ;
GL_TEXTURE_BIT [
GL_TEXTURE_2D swap glBindTexture
non-power-of-2-textures? get
- [ dup bitmap>> (tex-image) ]
- [ [ f (tex-image) ] [ (tex-sub-image) ] bi ] if
+ [ dup bitmap>> tex-image ]
+ [ [ f tex-image ] [ tex-sub-image ] bi ] if
] do-attribs
] keep ;
DESTRUCTOR: pango_layout_iter_free
-TUPLE: layout font string selection layout metrics ink-rect logical-rect image disposed ;
+TUPLE: layout < disposable font string selection layout metrics ink-rect logical-rect image ;
SYMBOL: dpi
: <layout> ( font string -- line )
[
- layout new
+ layout new-disposable
swap unpack-selection
swap >>font
dup [ string>> ] [ font>> ] bi <PangoLayout> >>layout
dup zero? [
2drop epsilon
] [
- [ exactly-n ] [ 1- at-most-n ] 2bi 2choice
+ [ exactly-n ] [ 1 - at-most-n ] 2bi 2choice
] if ;
: at-least-n ( parser n -- parser' )
: next-id ( -- n )
#! Return the next unique id for a parser
id get-global [
- dup 1+ id set-global
+ dup 1 + id set-global
] [
1 id set-global 0
] if* ;
IN: persistent.hashtables.config
: radix-bits ( -- n ) << cell 4 = 4 5 ? parsed >> ; foldable
-: radix-mask ( -- n ) radix-bits 2^ 1- ; foldable
-: full-bitmap-mask ( -- n ) radix-bits 2^ 2^ 1- ; inline
+: radix-mask ( -- n ) radix-bits 2^ 1 - ; foldable
+: full-bitmap-mask ( -- n ) radix-bits 2^ 2^ 1 - ; inline
{
{ [ 2dup root>> eq? ] [ nip ] }
{ [ over not ] [ 2drop T{ persistent-hash } ] }
- [ count>> 1- persistent-hash boa ]
+ [ count>> 1 - persistent-hash boa ]
} cond ;
M: persistent-hash >alist [ root>> >alist% ] { } make ;
persistent.hashtables.nodes ;
IN: persistent.hashtables.nodes.bitmap
-: index ( bit bitmap -- n ) [ 1- ] dip bitand bit-count ; inline
+: index ( bit bitmap -- n ) [ 1 - ] dip bitand bit-count ; inline
M:: bitmap-node (entry-at) ( key hashcode bitmap-node -- entry )
[let* | shift [ bitmap-node shift>> ]
IN: persistent.vectors
HELP: PV{
-{ $syntax "elements... }" }
+{ $syntax "PV{ elements... }" }
{ $description "Parses a literal " { $link persistent-vector } "." } ;
HELP: >persistent-vector
[ 1array ] dip node boa ;
: 2node ( first second -- node )
- [ 2array ] [ drop level>> 1+ ] 2bi node boa ;
+ [ 2array ] [ drop level>> 1 + ] 2bi node boa ;
: new-child ( new-child node -- node' expansion/f )
dup full? [ tuck level>> 1node ] [ node-add f ] if ;
: new-last ( val seq -- seq' )
- [ length 1- ] keep new-nth ;
+ [ length 1 - ] keep new-nth ;
: node-set-last ( child node -- node' )
clone [ new-last ] change-children ;
clone
dup tail>> full?
[ ppush-new-tail ] [ ppush-tail ] if
- [ 1+ ] change-count ;
+ [ 1 + ] change-count ;
: node-set-nth ( val i node -- node' )
clone [ new-nth ] change-children ;
clone
dup tail>> children>> length 1 >
[ ppop-tail ] [ ppop-new-tail ] if
- ] dip 1- >>count
+ ] dip 1 - >>count
]
} case ;
+USING: combinators kernel math parser sequences splitting ;
IN: porter-stemmer
-USING: kernel math parser sequences combinators splitting ;
: consonant? ( i str -- ? )
2dup nth dup "aeiou" member? [
] [
CHAR: y = [
over zero?
- [ 2drop t ] [ [ 1- ] dip consonant? not ] if
+ [ 2drop t ] [ [ 1 - ] dip consonant? not ] if
] [
2drop t
] if
: skip-vowels ( i str -- i str )
2dup bounds-check? [
- 2dup consonant? [ [ 1+ ] dip skip-vowels ] unless
+ 2dup consonant? [ [ 1 + ] dip skip-vowels ] unless
] when ;
: skip-consonants ( i str -- i str )
2dup bounds-check? [
- 2dup consonant? [ [ 1+ ] dip skip-consonants ] when
+ 2dup consonant? [ [ 1 + ] dip skip-consonants ] when
] when ;
: (consonant-seq) ( n i str -- n )
skip-vowels
2dup bounds-check? [
- [ 1+ ] [ 1+ ] [ ] tri* skip-consonants [ 1+ ] dip
+ [ 1 + ] [ 1 + ] [ ] tri* skip-consonants [ 1 + ] dip
(consonant-seq)
] [
2drop
over 1 < [
2drop f
] [
- 2dup nth [ over 1- over nth ] dip = [
+ 2dup nth [ over 1 - over nth ] dip = [
consonant?
] [
2drop f
{ [ "bl" ?tail ] [ "ble" append ] }
{ [ "iz" ?tail ] [ "ize" append ] }
{
- [ dup length 1- over double-consonant? ]
+ [ dup length 1 - over double-consonant? ]
[ dup "lsz" last-is? [ but-last-slice ] unless ]
}
{
: ll->l ( str -- newstr )
{
{ [ dup last CHAR: l = not ] [ ] }
- { [ dup length 1- over double-consonant? not ] [ ] }
+ { [ dup length 1 - over double-consonant? not ] [ ] }
{ [ dup consonant-seq 1 > ] [ but-last-slice ] }
[ ]
} cond ;
[ "Hi" ] [ "Hi" present ] unit-test
[ "+" ] [ \ + present ] unit-test
[ "kernel" ] [ "kernel" vocab present ] unit-test
-[ ] [ all-vocabs-seq [ present ] map drop ] unit-test
\ No newline at end of file
+[ ] [ all-vocabs-recursive no-roots no-prefixes [ present ] map drop ] unit-test
\ No newline at end of file
] if
] if ; inline
-: tuple>assoc ( tuple -- assoc )
- [ class all-slots ] [ tuple-slots ] bi zip
+: filter-tuple-assoc ( slot,value -- name,value )
[ [ initial>> ] dip = not ] assoc-filter
[ [ name>> ] dip ] assoc-map ;
+: tuple>assoc ( tuple -- assoc )
+ [ class all-slots ] [ tuple-slots ] bi zip filter-tuple-assoc ;
+
: pprint-slot-value ( name value -- )
<flow \ { pprint-word
[ text ] [ f <inset pprint* block> ] bi*
\ } pprint-word block> ;
+: (pprint-tuple) ( opener class slots closer -- )
+ <flow {
+ [ pprint-word ]
+ [ pprint-word ]
+ [ t <inset [ pprint-slot-value ] assoc-each block> ]
+ [ pprint-word ]
+ } spread block> ;
+
+: ?pprint-tuple ( tuple quot -- )
+ [ boa-tuples? get [ pprint-object ] ] dip [ check-recursion ] curry if ; inline
+
: pprint-tuple ( tuple -- )
- boa-tuples? get [ pprint-object ] [
- [
- <flow
- \ T{ pprint-word
- dup class pprint-word
- t <inset
- tuple>assoc [ pprint-slot-value ] assoc-each
- block>
- \ } pprint-word
- block>
- ] check-recursion
- ] if ;
+ [ [ \ T{ ] dip [ class ] [ tuple>assoc ] bi \ } (pprint-tuple) ] ?pprint-tuple ;
M: tuple pprint*
pprint-tuple ;
M: object >pprint-sequence ;
M: vector >pprint-sequence ;
M: byte-vector >pprint-sequence ;
-M: curry >pprint-sequence ;
-M: compose >pprint-sequence ;
+M: callable >pprint-sequence ;
M: hashtable >pprint-sequence >alist ;
M: wrapper >pprint-sequence wrapped>> 1array ;
M: callstack >pprint-sequence callstack>array ;
-M: tuple >pprint-sequence
- [ class ] [ tuple-slots ] bi
+: class-slot-sequence ( class slots -- sequence )
[ 1array ] [ [ f 2array ] dip append ] if-empty ;
+M: tuple >pprint-sequence
+ [ class ] [ tuple-slots ] bi class-slot-sequence ;
+
M: object pprint-narrow? drop f ;
M: byte-vector pprint-narrow? drop f ;
M: array pprint-narrow? drop t ;
prettyprint.sections sequences tools.test vectors words
effects splitting generic.standard prettyprint.private
continuations generic compiler.units tools.continuations
-tools.continuations.private eval accessors make vocabs.parser see ;
+tools.continuations.private eval accessors make vocabs.parser see
+listener ;
IN: prettyprint.tests
[ "4" ] [ 4 unparse ] unit-test
[ "USING: prettyprint.tests ;\nM: started-out-hustlin' ended-up-ballin' ; inline\n" ] [
[ M\ started-out-hustlin' ended-up-ballin' see ] with-string-writer
] unit-test
+
+TUPLE: tuple-with-declared-slot { x integer } ;
+
+[
+ {
+ "USING: math ;"
+ "IN: prettyprint.tests"
+ "TUPLE: tuple-with-declared-slot { x integer initial: 0 } ;"
+ ""
+ }
+] [
+ [ \ tuple-with-declared-slot see ] with-string-writer "\n" split
+] unit-test
+
+TUPLE: tuple-with-read-only-slot { x read-only } ;
+
+[
+ {
+ "IN: prettyprint.tests"
+ "TUPLE: tuple-with-read-only-slot { x read-only } ;"
+ ""
+ }
+] [
+ [ \ tuple-with-read-only-slot see ] with-string-writer "\n" split
+] unit-test
+
+TUPLE: tuple-with-initial-slot { x initial: 123 } ;
+
+[
+ {
+ "IN: prettyprint.tests"
+ "TUPLE: tuple-with-initial-slot { x initial: 123 } ;"
+ ""
+ }
+] [
+ [ \ tuple-with-initial-slot see ] with-string-writer "\n" split
+] unit-test
+
+TUPLE: tuple-with-initial-declared-slot { x integer initial: 123 } ;
+
+[
+ {
+ "USING: math ;"
+ "IN: prettyprint.tests"
+ "TUPLE: tuple-with-initial-declared-slot"
+ " { x integer initial: 123 } ;"
+ ""
+ }
+] [
+ [ \ tuple-with-initial-declared-slot see ] with-string-writer "\n" split
+] unit-test
: remove-breakpoints ( quot pos -- quot' )
over quotation? [
- 1+ cut [ (remove-breakpoints) ] bi@
+ 1 + cut [ (remove-breakpoints) ] bi@
[ -> ] glue
] [
drop
] each
] with-row
] each
- ] tabular-output nl ;
\ No newline at end of file
+ ] tabular-output nl ;
line-limit? [
"..." write pprinter get return
] when
- pprinter get [ 1+ ] change-line-count drop
+ pprinter get [ 1 + ] change-line-count drop
nl do-indent
] if ;
TUPLE: text < section string ;
: <text> ( string style -- text )
- over length 1+ \ text new-section
+ over length 1 + \ text new-section
swap >>style
swap >>string ;
: group-flow ( seq -- newseq )
[
dup length [
- 2dup 1- swap ?nth prev set
- 2dup 1+ swap ?nth next set
+ 2dup 1 - swap ?nth prev set
+ 2dup 1 + swap ?nth next set
swap nth dup split-before dup , split-after
] with each
] { } make { t } split harvest ;
: take-some ( seqs -- seqs seq )
0 over [ length + dup 76 >= ] find drop nip
- [ 1- cut-slice swap ] [ f swap ] if* concat ;
+ [ 1 - cut-slice swap ] [ f swap ] if* concat ;
: divide-lines ( strings -- strings )
[ dup ] [ take-some ] produce nip ;
(>>i) ;
M: random-dummy random-32* ( obj -- r )
- [ dup 1+ ] change-i drop ;
+ [ dup 1 + ] change-i drop ;
: y ( n seq -- y )
[ nth-unsafe 31 mask-bit ]
- [ [ 1+ ] [ nth-unsafe ] bi* 31 bits ] 2bi bitor ; inline
+ [ [ 1 + ] [ nth-unsafe ] bi* 31 bits ] 2bi bitor ; inline
: mt[k] ( offset n seq -- )
[
[
seq>>
[ [ n m - ] dip '[ [ m ] dip _ mt[k] ] each ]
- [ [ m 1- ] dip '[ [ m n - ] [ n m - + ] bi* _ mt[k] ] each ]
+ [ [ m 1 - ] dip '[ [ m n - ] [ n m - + ] bi* _ mt[k] ] each ]
bi
] [ 0 >>i drop ] bi ; inline
: init-mt-formula ( i seq -- f(seq[i]) )
- dupd nth dup -30 shift bitxor 1812433253 * + 1+ 32 bits ; inline
+ dupd nth dup -30 shift bitxor 1812433253 * + 1 + 32 bits ; inline
: init-mt-rest ( seq -- )
- n 1- swap '[
- _ [ init-mt-formula ] [ [ 1+ ] dip set-nth ] 2bi
+ n 1 - swap '[
+ _ [ init-mt-formula ] [ [ 1 + ] dip set-nth ] 2bi
] each ; inline
: init-mt-seq ( seed -- seq )
M: mersenne-twister random-32* ( mt -- r )
[ next-index ]
[ seq>> nth-unsafe mt-temper ]
- [ [ 1+ ] change-i drop ] tri ;
+ [ [ 1 + ] change-i drop ] tri ;
[
[ 32 random-bits ] with-system-random
<PRIVATE
: random-integer ( n -- n' )
- dup log2 7 + 8 /i 1+
+ dup log2 7 + 8 /i 1 +
[ random-bytes >byte-array byte-array>bignum ]
[ 3 shift 2^ ] bi / * >integer ;
: randomize ( seq -- seq )
dup length [ dup 1 > ]
- [ [ iota random ] [ 1- ] bi [ pick exchange ] keep ]
+ [ [ iota random ] [ 1 - ] bi [ pick exchange ] keep ]
while drop ;
: delete-random ( seq -- elt )
: to-times ( term n -- ast )
dup zero?
[ 2drop epsilon ]
- [ dupd 1- to-times 2array <concatenation> <maybe> ]
+ [ dupd 1 - to-times 2array <concatenation> <maybe> ]
if ;
M: from-to <times>
drop [ { [ length = ] [ ?nth "\r\n" member? ] } 2|| ] ;
M: ^ question>quot
- drop [ { [ drop zero? ] [ [ 1- ] dip ?nth "\r\n" member? ] } 2|| ] ;
+ drop [ { [ drop zero? ] [ [ 1 - ] dip ?nth "\r\n" member? ] } 2|| ] ;
M: $unix question>quot
drop [ { [ length = ] [ ?nth CHAR: \n = ] } 2|| ] ;
M: ^unix question>quot
- drop [ { [ drop zero? ] [ [ 1- ] dip ?nth CHAR: \n = ] } 2|| ] ;
+ drop [ { [ drop zero? ] [ [ 1 - ] dip ?nth CHAR: \n = ] } 2|| ] ;
M: word-break question>quot
drop [ word-break-at? ] ;
M: lookbehind question>quot ! Returns ( index string -- ? )
term>> <reversed-option>
ast>dfa dfa>reverse-shortest-word
- '[ [ 1- ] dip f _ execute ] ;
+ '[ [ 1 - ] dip f _ execute ] ;
: check-string ( string -- string )
! Make this configurable
GENERIC: end/start ( string regexp -- end start )
M: regexp end/start drop length 0 ;
-M: reverse-regexp end/start drop length 1- -1 swap ;
+M: reverse-regexp end/start drop length 1 - -1 swap ;
PRIVATE>
:: (next-match) ( i string regexp quot: ( i string regexp -- j ) reverse? -- i start end ? )
i string regexp quot call dup [| j |
j i j
- reverse? [ swap [ 1+ ] bi@ ] when
+ reverse? [ swap [ 1 + ] bi@ ] when
string
] [ drop f f f f ] if ; inline
: search-range ( i string reverse? -- seq )
- [ drop dup 1+ -1 ] [ length 1 ] if range boa ; inline
+ [ drop dup 1 + -1 ] [ length 1 ] if range boa ; inline
:: next-match ( i string regexp quot: ( i string regexp -- j ) reverse? -- i start end ? )
f f f f
[ subseq ] map-matches ;
: count-matches ( string regexp -- n )
- [ 0 ] 2dip [ 3drop 1+ ] each-match ;
+ [ 0 ] 2dip [ 3drop 1 + ] each-match ;
<PRIVATE
dup skip-blank [
[ index-from ] 2keep
[ swapd subseq ]
- [ 2drop 1+ ] 3bi
+ [ 2drop 1 + ] 3bi
] change-lexer-column ;
: parse-noblank-token ( lexer -- str/f )
"prettyprint" vocab [
"regexp.prettyprint" require
-] when
\ No newline at end of file
+] when
! Copyright (C) 2007 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs fry generalizations grouping
-kernel lexer macros make math math.order math.vectors
+USING: accessors arrays assocs effects fry generalizations
+grouping kernel lexer macros math math.order math.vectors
namespaces parser quotations sequences sequences.private
-splitting.monotonic stack-checker strings unicode.case
-words effects ;
+splitting.monotonic stack-checker strings unicode.case words ;
IN: roman
<PRIVATE
ERROR: roman-range-error n ;
-: roman-range-check ( n -- )
- dup 1 3999 between? [ drop ] [ roman-range-error ] if ;
+: roman-range-check ( n -- n )
+ dup 1 3999 between? [ roman-range-error ] unless ;
: roman-digit-index ( ch -- n )
1string roman-digits index ; inline
-: roman<= ( ch1 ch2 -- ? )
+: roman>= ( ch1 ch2 -- ? )
[ roman-digit-index ] bi@ >= ;
: roman>n ( ch -- n )
roman-digit-index roman-values nth ;
-: (>roman) ( n -- )
- roman-values roman-digits [
- [ /mod swap ] dip <repetition> concat %
- ] 2each drop ;
-
: (roman>) ( seq -- n )
[ [ roman>n ] map ] [ all-eq? ] bi
[ sum ] [ first2 swap - ] if ;
PRIVATE>
: >roman ( n -- str )
- dup roman-range-check [ (>roman) ] "" make ;
+ roman-range-check
+ roman-values roman-digits [
+ [ /mod swap ] dip <repetition> concat
+ ] 2map "" concat-as nip ;
: >ROMAN ( n -- str ) >roman >upper ;
: roman> ( str -- n )
- >lower [ roman<= ] monotonic-split [ (roman>) ] sigma ;
+ >lower [ roman>= ] monotonic-split [ (roman>) ] sigma ;
<PRIVATE
PRIVATE>
<<
+
SYNTAX: ROMAN-OP:
scan-word [ name>> "roman" prepend create-in ] keep
1quotation '[ _ binary-roman-op ]
dup infer [ in>> ] [ out>> ] bi
[ "string" <repetition> ] bi@ <effect> define-declared ;
+
>>
ROMAN-OP: +
M: word declarations.
{
POSTPONE: delimiter
+ POSTPONE: deprecated
POSTPONE: inline
POSTPONE: recursive
POSTPONE: foldable
dup name>> ,
dup class>> object eq? [
dup class>> ,
- initial: ,
- dup initial>> ,
] unless
dup read-only>> [
read-only ,
] when
+ dup [ class>> object eq? not ] [ initial>> ] bi or [
+ initial: ,
+ dup initial>> ,
+ ] when
drop
] { } make ;
] { } make prune ;
: see-methods ( word -- )
- methods see-all nl ;
\ No newline at end of file
+ methods see-all nl ;
M: complex-sequence length
seq>> length -1 shift ;
M: complex-sequence nth-unsafe
- complex@ [ nth-unsafe ] [ [ 1+ ] dip nth-unsafe ] 2bi rect> ;
+ complex@ [ nth-unsafe ] [ [ 1 + ] dip nth-unsafe ] 2bi rect> ;
M: complex-sequence set-nth-unsafe
complex@
[ [ real-part ] [ ] [ ] tri* set-nth-unsafe ]
- [ [ imaginary-part ] [ 1+ ] [ ] tri* set-nth-unsafe ] 3bi ;
+ [ [ imaginary-part ] [ 1 + ] [ ] tri* set-nth-unsafe ] 3bi ;
help.markup splitting io.streams.byte-array io.encodings.string
io.encodings.utf8 io.encodings.binary combinators accessors
locals prettyprint compiler.units sequences.private
-classes.tuple.private ;
+classes.tuple.private vocabs.loader ;
IN: serialize
GENERIC: (serialize) ( obj -- )
! The last case is needed because a very large number would
! otherwise be confused with a small number.
: serialize-cell ( n -- )
- dup zero? [ drop 0 write1 ] [
+ [ 0 write1 ] [
dup HEX: 7e <= [
HEX: 80 bitor write1
] [
- dup log2 8 /i 1+
+ dup log2 8 /i 1 +
dup HEX: 7f >= [
HEX: ff write1
dup serialize-cell
] if
>be write
] if
- ] if ;
+ ] if-zero ;
: deserialize-cell ( -- n )
read1 {
drop CHAR: n write1 ;
M: integer (serialize) ( obj -- )
- dup zero? [
- drop CHAR: z write1
+ [
+ CHAR: z write1
] [
dup 0 < [ neg CHAR: m ] [ CHAR: p ] if write1
serialize-cell
- ] if ;
+ ] if-zero ;
M: float (serialize) ( obj -- )
CHAR: F write1
(deserialize-string) dup intern-object ;
: deserialize-word ( -- word )
- (deserialize) (deserialize) 2dup lookup
+ (deserialize) (deserialize) 2dup [ require ] keep lookup
dup [ 2nip ] [
drop
2array unparse "Unknown word: " prepend throw
binary [ deserialize ] with-byte-reader ;
: object>bytes ( obj -- bytes )
- binary [ serialize ] with-byte-writer ;
\ No newline at end of file
+ binary [ serialize ] with-byte-writer ;
WHERE
-: NAME<=> ( obj1 obj2 -- <=> ) QUOT bi@ <=> ;
+: NAME<=> ( obj1 obj2 -- <=> ) QUOT compare ;
: NAME>=< ( obj1 obj2 -- >=< ) NAME<=> invert-comparison ;
;FUNCTOR
<PRIVATE
:: insert ( seq quot: ( elt -- elt' ) n -- )
n zero? [
- n n 1- [ seq nth quot call ] bi@ >= [
- n n 1- seq exchange
- seq quot n 1- insert
+ n n 1 - [ seq nth quot call ] bi@ >= [
+ n n 1 - seq exchange
+ seq quot n 1 - insert
] unless
] unless ; inline recursive
PRIVATE>
! See http://factorcode.org/license.txt for BSD license.
USING: functors sequences sequences.private kernel words classes
math alien alien.c-types byte-arrays accessors
-specialized-arrays ;
+specialized-arrays prettyprint.custom ;
IN: specialized-arrays.direct.functor
FUNCTOR: define-direct-array ( T -- )
A' IS ${T}-array
+S IS ${T}-sequence
>A' IS >${T}-array
<A'> IS <${A'}>
+A'{ IS ${A'}{
A DEFINES-CLASS direct-${T}-array
<A> DEFINES <${A}>
{ length fixnum read-only } ;
: <A> ( alien len -- direct-array ) A boa ; inline
-M: A length length>> ;
-M: A nth-unsafe underlying>> NTH call ;
-M: A set-nth-unsafe underlying>> SET-NTH call ;
-M: A like drop dup A instance? [ >A' ] unless ;
-M: A new-sequence drop <A'> ;
+M: A length length>> ; inline
+M: A nth-unsafe underlying>> NTH call ; inline
+M: A set-nth-unsafe underlying>> SET-NTH call ; inline
+M: A like drop dup A instance? [ >A' ] unless ; inline
+M: A new-sequence drop <A'> ; inline
+
+M: A byte-length length>> T heap-size * ; inline
+
+M: A pprint-delims drop \ A'{ \ } ;
+
+M: A >pprint-sequence ;
+
+M: A pprint* pprint-object ;
INSTANCE: A sequence
+INSTANCE: A S
+
+T c-type
+ \ A >>direct-array-class
+ \ <A> >>direct-array-constructor
+ drop
;FUNCTOR
HINTS: (double-array) { 2 } { 3 } ;
-HINTS: vneg { array } { double-array } ;
-HINTS: v*n { array object } { double-array float } ;
-HINTS: n*v { array object } { float double-array } ;
-HINTS: v/n { array object } { double-array float } ;
-HINTS: n/v { object array } { float double-array } ;
-HINTS: v+ { array array } { double-array double-array } ;
-HINTS: v- { array array } { double-array double-array } ;
-HINTS: v* { array array } { double-array double-array } ;
-HINTS: v/ { array array } { double-array double-array } ;
-HINTS: vmax { array array } { double-array double-array } ;
-HINTS: vmin { array array } { double-array double-array } ;
-HINTS: v. { array array } { double-array double-array } ;
-HINTS: norm-sq { array } { double-array } ;
-HINTS: norm { array } { double-array } ;
-HINTS: normalize { array } { double-array } ;
-HINTS: distance { array array } { double-array double-array } ;
-
! Type functions
USING: words classes.algebra compiler.tree.propagation.info
math.intervals ;
-{ v+ v- v* v/ vmax vmin } [
- [
- [ class>> double-array class<= ] both?
- double-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-{ n*v n/v } [
- [
- nip class>> double-array class<= double-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-{ v*n v/n } [
- [
- drop class>> double-array class<= double-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-{ vneg normalize } [
- [
- class>> double-array class<= double-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
\ norm-sq [
class>> double-array class<= [ float 0. 1/0. [a,b] <class/interval-info> ] [ object-info ] if
] "outputs" set-word-prop
-\ v. [
- [ class>> double-array class<= ] both?
- float object ? <class-info>
-] "outputs" set-word-prop
-
\ distance [
[ class>> double-array class<= ] both?
[ float 0. 1/0. [a,b] <class/interval-info> ] [ object-info ] if
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: functors sequences sequences.private prettyprint.custom
-kernel words classes math parser alien.c-types byte-arrays
-accessors summary ;
+kernel words classes math math.vectors.specialization parser
+alien.c-types byte-arrays accessors summary ;
IN: specialized-arrays.functor
ERROR: bad-byte-array-length byte-array type ;
FUNCTOR: define-array ( T -- )
A DEFINES-CLASS ${T}-array
+S DEFINES-CLASS ${T}-sequence
<A> DEFINES <${A}>
(A) DEFINES (${A})
>A DEFINES >${A}
WHERE
+MIXIN: S
+
TUPLE: A
{ length array-capacity read-only }
{ underlying byte-array read-only } ;
dup length T heap-size /mod 0 = [ drop T bad-byte-array-length ] unless
swap A boa ; inline
-M: A clone [ length>> ] [ underlying>> clone ] bi A boa ;
+M: A clone [ length>> ] [ underlying>> clone ] bi A boa ; inline
-M: A length length>> ;
+M: A length length>> ; inline
-M: A nth-unsafe underlying>> NTH call ;
+M: A nth-unsafe underlying>> NTH call ; inline
-M: A set-nth-unsafe underlying>> SET-NTH call ;
+M: A set-nth-unsafe underlying>> SET-NTH call ; inline
-: >A ( seq -- specialized-array ) A new clone-like ; inline
+: >A ( seq -- specialized-array ) A new clone-like ;
-M: A like drop dup A instance? [ >A ] unless ;
+M: A like drop dup A instance? [ >A ] unless ; inline
-M: A new-sequence drop (A) ;
+M: A new-sequence drop (A) ; inline
M: A equal? over A instance? [ sequence= ] [ 2drop f ] if ;
[ T heap-size * ] [ underlying>> ] bi*
resize-byte-array
] 2bi
- A boa ;
+ A boa ; inline
-M: A byte-length underlying>> length ;
+M: A byte-length underlying>> length ; inline
M: A pprint-delims drop \ A{ \ } ;
SYNTAX: A{ \ } [ >A ] parse-literal ;
INSTANCE: A sequence
+INSTANCE: A S
+
+A T c-type-boxed-class specialize-vector-words
+
+T c-type
+ \ A >>array-class
+ \ <A> >>array-constructor
+ \ S >>sequence-mixin-class
+ drop
;FUNCTOR
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.alien
+
+<< "ptrdiff_t" define-array >>
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: functors sequences sequences.private growable
+USING: accessors alien.c-types functors sequences sequences.private growable
prettyprint.custom kernel words classes math parser ;
+QUALIFIED: vectors.functor
IN: specialized-vectors.functor
FUNCTOR: define-vector ( T -- )
+V DEFINES-CLASS ${T}-vector
+
A IS ${T}-array
+S IS ${T}-sequence
<A> IS <${A}>
-V DEFINES-CLASS ${T}-vector
-<V> DEFINES <${V}>
->V DEFINES >${V}
+>V DEFERS >${V}
V{ DEFINES ${V}{
WHERE
-TUPLE: V { underlying A } { length array-capacity } ;
-
-: <V> ( capacity -- vector ) <A> 0 V boa ; inline
-
-M: V like
- drop dup V instance? [
- dup A instance? [ dup length V boa ] [ >V ] if
- ] unless ;
-
-M: V new-sequence drop [ <A> ] [ >fixnum ] bi V boa ;
-
-M: A new-resizable drop <V> ;
+V A <A> vectors.functor:define-vector
-M: V equal? over V instance? [ sequence= ] [ 2drop f ] if ;
+M: V contract 2drop ;
-: >V ( seq -- vector ) V new clone-like ; inline
+M: V byte-length underlying>> byte-length ;
M: V pprint-delims drop \ V{ \ } ;
SYNTAX: V{ \ } [ >V ] parse-literal ;
INSTANCE: V growable
+INSTANCE: V S
;FUNCTOR
[ length ] [ ] [ <circular> 1 over change-circular-start ] tri
[ @ not [ , ] [ drop ] if ] 3each
] { } make
- dup empty? [ over length 1- prefix ] when -1 prefix 2 clump
+ dup empty? [ over length 1 - prefix ] when -1 prefix 2 clump
swap
] dip
- '[ first2 [ 1+ ] bi@ _ _ boa ] map ; inline
+ '[ first2 [ 1 + ] bi@ _ _ boa ] map ; inline
PRIVATE>
drop
[ downward-slices ]
[ stable-slices ]
- [ upward-slices ] tri 3append [ [ from>> ] compare ] sort
+ [ upward-slices ] tri 3append [ from>> ] sort-with
]
} case ;
continuations assocs combinators compiler.errors accessors math.order
definitions sets hints macros stack-checker.state
stack-checker.visitor stack-checker.errors stack-checker.values
-stack-checker.recursive-state ;
+stack-checker.recursive-state summary ;
IN: stack-checker.backend
: push-d ( obj -- ) meta-d push ;
: time-bomb ( error -- )
'[ _ throw ] infer-quot-here ;
-: bad-call ( -- )
- "call must be given a callable" time-bomb ;
+ERROR: bad-call obj ;
+
+M: bad-call summary
+ drop "call must be given a callable" ;
: infer-literal-quot ( literal -- )
dup recursive-quotation? [
[ [ recursion>> ] keep add-local-quotation ]
bi infer-quot
] [
- drop bad-call
+ value>> \ bad-call boa time-bomb
] if
] if ;
+++ /dev/null
-Slava Pestov
\ No newline at end of file
+++ /dev/null
-USING: stack-checker.call-effect tools.test kernel math effects ;
-IN: stack-checker.call-effect.tests
-
-[ t ] [ \ + (( a b -- c )) execute-effect-unsafe? ] unit-test
-[ t ] [ \ + (( a b c -- d e )) execute-effect-unsafe? ] unit-test
-[ f ] [ \ + (( a b c -- d )) execute-effect-unsafe? ] unit-test
-[ f ] [ \ call (( x -- )) execute-effect-unsafe? ] unit-test
-
-[ t ] [ [ + ] cached-effect (( a b -- c )) effect= ] unit-test
-[ t ] [ 5 [ + ] curry cached-effect (( a -- c )) effect= ] unit-test
-[ t ] [ 5 [ ] curry cached-effect (( -- c )) effect= ] unit-test
-[ t ] [ [ dup ] [ drop ] compose cached-effect (( a -- b )) effect= ] unit-test
-[ t ] [ [ drop ] [ dup ] compose cached-effect (( a b -- c d )) effect= ] unit-test
-[ t ] [ [ 2drop ] [ dup ] compose cached-effect (( a b c -- d e )) effect= ] unit-test
-[ t ] [ [ 1 2 3 ] [ 2drop ] compose cached-effect (( -- a )) effect= ] unit-test
-[ t ] [ [ 1 2 ] [ 3drop ] compose cached-effect (( a -- )) effect= ] unit-test
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators combinators.private effects fry
-kernel kernel.private make sequences continuations quotations
-stack-checker stack-checker.transforms words math ;
-IN: stack-checker.call-effect
-
-! call( and execute( have complex expansions.
-
-! call( uses the following strategy:
-! - Inline caching. If the quotation is the same as last time, just call it unsafely
-! - Effect inference. Infer quotation's effect, caching it in the cached-effect slot,
-! and compare it with declaration. If matches, call it unsafely.
-! - Fallback. If the above doesn't work, call it and compare the datastack before
-! and after to make sure it didn't mess anything up.
-
-! execute( uses a similar strategy.
-
-TUPLE: inline-cache value ;
-
-: cache-hit? ( word/quot ic -- ? )
- [ value>> eq? ] [ value>> ] bi and ; inline
-
-SINGLETON: +unknown+
-
-GENERIC: cached-effect ( quot -- effect )
-
-M: object cached-effect drop +unknown+ ;
-
-GENERIC: curry-effect ( effect -- effect' )
-
-M: +unknown+ curry-effect ;
-
-M: effect curry-effect
- [ in>> length ] [ out>> length ] [ terminated?>> ] tri
- pick 0 = [ [ 1+ ] dip ] [ [ 1- ] 2dip ] if
- effect boa ;
-
-M: curry cached-effect
- quot>> cached-effect curry-effect ;
-
-: compose-effects* ( effect1 effect2 -- effect' )
- {
- { [ 2dup [ effect? ] both? ] [ compose-effects ] }
- { [ 2dup [ +unknown+ eq? ] either? ] [ 2drop +unknown+ ] }
- } cond ;
-
-M: compose cached-effect
- [ first>> ] [ second>> ] bi [ cached-effect ] bi@ compose-effects* ;
-
-M: quotation cached-effect
- dup cached-effect>>
- [ ] [
- [ [ infer ] [ 2drop +unknown+ ] recover dup ] keep
- (>>cached-effect)
- ] ?if ;
-
-: call-effect-unsafe? ( quot effect -- ? )
- [ cached-effect ] dip
- over +unknown+ eq?
- [ 2drop f ] [ effect<= ] if ; inline
-
-: (call-effect-slow>quot) ( in out effect -- quot )
- [
- [ [ datastack ] dip dip ] %
- [ [ , ] bi@ \ check-datastack , ] dip
- '[ _ wrong-values ] , \ unless ,
- ] [ ] make ;
-
-: call-effect-slow>quot ( effect -- quot )
- [ in>> length ] [ out>> length ] [ ] tri
- [ (call-effect-slow>quot) ] keep add-effect-input
- [ call-effect-unsafe ] 2curry ;
-
-: call-effect-slow ( quot effect -- ) drop call ;
-
-\ call-effect-slow [ call-effect-slow>quot ] 1 define-transform
-
-\ call-effect-slow t "no-compile" set-word-prop
-
-: call-effect-fast ( quot effect inline-cache -- )
- 2over call-effect-unsafe?
- [ [ nip (>>value) ] [ drop call-effect-unsafe ] 3bi ]
- [ drop call-effect-slow ]
- if ; inline
-
-\ call-effect [
- inline-cache new '[
- _
- 3dup nip cache-hit? [
- drop call-effect-unsafe
- ] [
- call-effect-fast
- ] if
- ]
-] 0 define-transform
-
-\ call-effect t "no-compile" set-word-prop
-
-: execute-effect-slow ( word effect -- )
- [ '[ _ execute ] ] dip call-effect-slow ; inline
-
-: execute-effect-unsafe? ( word effect -- ? )
- over optimized? [ [ stack-effect ] dip effect<= ] [ 2drop f ] if ; inline
-
-: execute-effect-fast ( word effect inline-cache -- )
- 2over execute-effect-unsafe?
- [ [ nip (>>value) ] [ drop execute-effect-unsafe ] 3bi ]
- [ drop execute-effect-slow ]
- if ; inline
-
-: execute-effect-ic ( word effect inline-cache -- )
- 3dup nip cache-hit?
- [ drop execute-effect-unsafe ]
- [ execute-effect-fast ]
- if ; inline
-
-: execute-effect>quot ( effect -- quot )
- inline-cache new '[ _ _ execute-effect-ic ] ;
-
-\ execute-effect [ execute-effect>quot ] 1 define-transform
-
-\ execute-effect t "no-compile" set-word-prop
\ No newline at end of file
Slava Pestov
+Daniel Ehrenberg
-! Copyright (C) 2004, 2009 Slava Pestov.
+! Copyright (C) 2004, 2009 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: fry accessors alien alien.accessors arrays byte-arrays classes
continuations.private effects generic hashtables
[ length ensure-d ] keep zip
#declare, ;
+\ declare [ infer-declare ] "special" set-word-prop
+
GENERIC: infer-call* ( value known -- )
: (infer-call) ( value -- ) dup known infer-call* ;
: infer-call ( -- ) pop-d (infer-call) ;
+\ call [ infer-call ] "special" set-word-prop
+
+\ (call) [ infer-call ] "special" set-word-prop
+
M: literal infer-call*
[ 1array #drop, ] [ infer-literal-quot ] bi* ;
: infer-dip ( -- ) \ dip 1 infer-ndip ;
+\ dip [ infer-dip ] "special" set-word-prop
+
: infer-2dip ( -- ) \ 2dip 2 infer-ndip ;
+\ 2dip [ infer-2dip ] "special" set-word-prop
+
: infer-3dip ( -- ) \ 3dip 3 infer-ndip ;
+\ 3dip [ infer-3dip ] "special" set-word-prop
+
: infer-builder ( quot word -- )
[
[ 2 consume-d ] dip
: infer-curry ( -- ) [ <curried> ] \ curry infer-builder ;
+\ curry [ infer-curry ] "special" set-word-prop
+
: infer-compose ( -- ) [ <composed> ] \ compose infer-builder ;
+\ compose [ infer-compose ] "special" set-word-prop
+
+ERROR: bad-executable obj ;
+
+M: bad-executable summary
+ drop "execute must be given a word" ;
+
: infer-execute ( -- )
pop-literal nip
dup word? [
apply-object
] [
- drop
- "execute must be given a word" time-bomb
+ \ bad-executable boa time-bomb
] if ;
+\ execute [ infer-execute ] "special" set-word-prop
+
+\ (execute) [ infer-execute ] "special" set-word-prop
+
: infer-<tuple-boa> ( -- )
\ <tuple-boa>
- peek-d literal value>> second 1+ { tuple } <effect>
+ peek-d literal value>> second 1 + { tuple } <effect>
apply-word/effect ;
+\ <tuple-boa> [ infer-<tuple-boa> ] "special" set-word-prop
+
+\ <tuple-boa> t "flushable" set-word-prop
+
: infer-effect-unsafe ( word -- )
pop-literal nip
add-effect-input
: infer-execute-effect-unsafe ( -- )
\ (execute) infer-effect-unsafe ;
+\ execute-effect-unsafe [ infer-execute-effect-unsafe ] "special" set-word-prop
+
: infer-call-effect-unsafe ( -- )
\ call infer-effect-unsafe ;
+\ call-effect-unsafe [ infer-call-effect-unsafe ] "special" set-word-prop
+
: infer-exit ( -- )
\ exit (( n -- * )) apply-word/effect ;
+\ exit [ infer-exit ] "special" set-word-prop
+
: infer-load-locals ( -- )
pop-literal nip
consume-d dup copy-values dup output-r
[ [ f f ] dip ] [ swap zip ] 2bi #shuffle, ;
+\ load-locals [ infer-load-locals ] "special" set-word-prop
+
+: infer-load-local ( -- )
+ 1 infer->r ;
+
+\ load-local [ infer-load-local ] "special" set-word-prop
+
: infer-get-local ( -- )
[let* | n [ pop-literal nip 1 swap - ]
in-r [ n consume-r ]
#shuffle,
] ;
+\ get-local [ infer-get-local ] "special" set-word-prop
+
: infer-drop-locals ( -- )
f f pop-literal nip consume-r f f #shuffle, ;
+\ drop-locals [ infer-drop-locals ] "special" set-word-prop
+
+: infer-call-effect ( word -- )
+ 1 ensure-d first literal value>>
+ add-effect-input add-effect-input
+ apply-word/effect ;
+
+{ call-effect execute-effect } [
+ dup t "no-compile" set-word-prop
+ dup '[ _ infer-call-effect ] "special" set-word-prop
+] each
+
+\ do-primitive [ unknown-primitive-error ] "special" set-word-prop
+
+\ if [ infer-if ] "special" set-word-prop
+\ dispatch [ infer-dispatch ] "special" set-word-prop
+
+\ alien-invoke [ infer-alien-invoke ] "special" set-word-prop
+\ alien-indirect [ infer-alien-indirect ] "special" set-word-prop
+\ alien-callback [ infer-alien-callback ] "special" set-word-prop
+
: infer-special ( word -- )
- {
- { \ declare [ infer-declare ] }
- { \ call [ infer-call ] }
- { \ (call) [ infer-call ] }
- { \ dip [ infer-dip ] }
- { \ 2dip [ infer-2dip ] }
- { \ 3dip [ infer-3dip ] }
- { \ curry [ infer-curry ] }
- { \ compose [ infer-compose ] }
- { \ execute [ infer-execute ] }
- { \ (execute) [ infer-execute ] }
- { \ execute-effect-unsafe [ infer-execute-effect-unsafe ] }
- { \ call-effect-unsafe [ infer-call-effect-unsafe ] }
- { \ if [ infer-if ] }
- { \ dispatch [ infer-dispatch ] }
- { \ <tuple-boa> [ infer-<tuple-boa> ] }
- { \ exit [ infer-exit ] }
- { \ load-local [ 1 infer->r ] }
- { \ load-locals [ infer-load-locals ] }
- { \ get-local [ infer-get-local ] }
- { \ drop-locals [ infer-drop-locals ] }
- { \ do-primitive [ unknown-primitive-error ] }
- { \ alien-invoke [ infer-alien-invoke ] }
- { \ alien-indirect [ infer-alien-indirect ] }
- { \ alien-callback [ infer-alien-callback ] }
- } case ;
+ "special" word-prop call( -- ) ;
: infer-local-reader ( word -- )
(( -- value )) apply-word/effect ;
dispatch <tuple-boa> exit load-local load-locals get-local
drop-locals do-primitive alien-invoke alien-indirect
alien-callback
-} [
- [ t "special" set-word-prop ]
- [ t "no-compile" set-word-prop ] bi
-] each
+} [ t "no-compile" set-word-prop ] each
! Exceptions to the above
\ curry f "no-compile" set-word-prop
\ reset-inline-cache-stats { } { } define-primitive
\ inline-cache-stats { } { array } define-primitive
-\ optimized? { word } { object } define-primitive
\ No newline at end of file
+\ optimized? { word } { object } define-primitive
"Combinators which are recursive require additional care. In addition to being declared " { $link POSTPONE: inline } ", they must be declared " { $link POSTPONE: recursive } ". There are three restrictions that only apply to combinators with this declaration:"
{ $heading "Input quotation declaration" }
"Input parameters which are quotations must be annotated as much in the stack effect. For example, the following will not infer:"
-{ $example ": bad ( quot -- ) [ call ] keep foo ; inline recursive" "[ [ ] bad ] infer." "Got a computed value where a literal quotation was expected\n\nType :help for debugging help." }
+{ $example ": bad ( quot -- ) [ call ] keep bad ; inline recursive" "[ [ ] bad ] infer." "Got a computed value where a literal quotation was expected\n\nType :help for debugging help." }
"The following is correct:"
{ $example ": good ( quot: ( -- ) -- ) [ call ] keep good ; inline recursive" "[ [ ] good ] infer." "( -- )" }
"The effect of the nested quotation itself is only present for documentation purposes; the mere presence of a nested effect is sufficient to mark that value as a quotation parameter."
! Found during code review
[ [ [ drop [ ] ] when call ] infer ] must-fail
-[ swap [ [ drop [ ] ] when call ] infer ] must-fail
\ No newline at end of file
+[ swap [ [ drop [ ] ] when call ] infer ] must-fail
+
+{ 3 1 } [ call( a b -- c ) ] must-infer-as
+{ 3 1 } [ execute( a b -- c ) ] must-infer-as
+
+[ [ call-effect ] infer ] must-fail
+[ [ execute-effect ] infer ] must-fail
: infer. ( quot -- )
#! Safe to call from inference transforms.
infer effect>string print ;
-
-"stack-checker.call-effect" require
\ No newline at end of file
\ spread t "no-compile" set-word-prop
+\ 0&& [ '[ _ 0 n&& ] ] 1 define-transform
+
+\ 0&& t "no-compile" set-word-prop
+
+\ 1&& [ '[ _ 1 n&& ] ] 1 define-transform
+
+\ 1&& t "no-compile" set-word-prop
+
+\ 2&& [ '[ _ 2 n&& ] ] 1 define-transform
+
+\ 2&& t "no-compile" set-word-prop
+
+\ 3&& [ '[ _ 3 n&& ] ] 1 define-transform
+
+\ 3&& t "no-compile" set-word-prop
+
+\ 0|| [ '[ _ 0 n|| ] ] 1 define-transform
+
+\ 0|| t "no-compile" set-word-prop
+
+\ 1|| [ '[ _ 1 n|| ] ] 1 define-transform
+
+\ 1|| t "no-compile" set-word-prop
+
+\ 2|| [ '[ _ 2 n|| ] ] 1 define-transform
+
+\ 2|| t "no-compile" set-word-prop
+
+\ 3|| [ '[ _ 3 n|| ] ] 1 define-transform
+
+\ 3|| t "no-compile" set-word-prop
+
\ (call-next-method) [
[
[ "method-class" word-prop ]
] 1 define-transform
\ boa t "no-compile" set-word-prop
-
-\ new [
- dup tuple-class? [
- dup inlined-dependency depends-on
- [ all-slots [ initial>> literalize ] map ]
- [ tuple-layout '[ _ <tuple-boa> ] ]
- bi append
- ] [ drop f ] if
-] 1 define-transform
-
-! Fast at for integer maps
-CONSTANT: lookup-table-at-max 256
-
-: lookup-table-at? ( assoc -- ? )
- #! Can we use a fast byte array test here?
- {
- [ assoc-size 4 > ]
- [ values [ ] all? ]
- [ keys [ integer? ] all? ]
- [ keys [ 0 lookup-table-at-max between? ] all? ]
- } 1&& ;
-
-: lookup-table-seq ( assoc -- table )
- [ keys supremum 1+ ] keep '[ _ at ] { } map-as ;
-
-: lookup-table-quot ( seq -- newquot )
- lookup-table-seq
- '[
- _ over integer? [
- 2dup bounds-check? [
- nth-unsafe dup >boolean
- ] [ 2drop f f ] if
- ] [ 2drop f f ] if
- ] ;
-
-: fast-lookup-table-at? ( assoc -- ? )
- values {
- [ [ integer? ] all? ]
- [ [ 0 254 between? ] all? ]
- } 1&& ;
-
-: fast-lookup-table-seq ( assoc -- table )
- lookup-table-seq [ 255 or ] B{ } map-as ;
-
-: fast-lookup-table-quot ( seq -- newquot )
- fast-lookup-table-seq
- '[
- _ over integer? [
- 2dup bounds-check? [
- nth-unsafe dup 255 eq? [ drop f f ] [ t ] if
- ] [ 2drop f f ] if
- ] [ 2drop f f ] if
- ] ;
-
-: at-quot ( assoc -- quot )
- dup lookup-table-at? [
- dup fast-lookup-table-at? [
- fast-lookup-table-quot
- ] [
- lookup-table-quot
- ] if
- ] [ drop f ] if ;
-
-\ at* [ at-quot ] 1 define-transform
-
-! Membership testing
-: member-quot ( seq -- newquot )
- dup length 4 <= [
- [ drop f ] swap
- [ literalize [ t ] ] { } map>assoc linear-case-quot
- ] [
- unique [ key? ] curry
- ] if ;
-
-\ member? [
- dup sequence? [ member-quot ] [ drop f ] if
-] 1 define-transform
-
-: memq-quot ( seq -- newquot )
- [ [ dupd eq? ] curry [ drop t ] ] { } map>assoc
- [ drop f ] suffix [ cond ] curry ;
-
-\ memq? [
- dup sequence? [ memq-quot ] [ drop f ] if
-] 1 define-transform
-
-! Index search
-\ index [
- dup sequence? [
- dup length 4 >= [
- dup length zip >hashtable '[ _ at ]
- ] [ drop f ] if
- ] [ drop f ] if
-] 1 define-transform
-
-! Shuffling
-: nths-quot ( indices -- quot )
- [ [ '[ _ swap nth ] ] map ] [ length ] bi
- '[ _ cleave _ narray ] ;
-
-\ shuffle [
- shuffle-mapping nths-quot
-] 1 define-transform
--- /dev/null
+! (c)Joe Groff bsd license
+USING: accessors arrays kernel prettyprint.backend
+prettyprint.custom sequences struct-arrays ;
+IN: struct-arrays.prettyprint
+
+M: struct-array pprint-delims
+ drop \ struct-array{ \ } ;
+
+M: struct-array >pprint-sequence
+ [ >array ] [ class>> ] bi prefix ;
+
+M: struct-array pprint* pprint-object ;
+
IN: struct-arrays.tests
-USING: struct-arrays tools.test kernel math sequences
-alien.syntax alien.c-types destructors libc accessors ;
+USING: classes.struct struct-arrays tools.test kernel math sequences
+alien.syntax alien.c-types destructors libc accessors sequences.private ;
-C-STRUCT: test-struct
-{ "int" "x" }
-{ "int" "y" } ;
+STRUCT: test-struct-array
+ { x int }
+ { y int } ;
: make-point ( x y -- struct )
- "test-struct" <c-object>
- [ set-test-struct-y ] keep
- [ set-test-struct-x ] keep ;
+ test-struct-array <struct-boa> ;
[ 5/4 ] [
- 2 "test-struct" <struct-array>
+ 2 test-struct-array <struct-array>
1 2 make-point over set-first
3 4 make-point over set-second
- 0 [ [ test-struct-x ] [ test-struct-y ] bi / + ] reduce
+ 0 [ [ x>> ] [ y>> ] bi / + ] reduce
] unit-test
[ 5/4 ] [
[
- 2 "test-struct" malloc-struct-array
+ 2 test-struct-array malloc-struct-array
dup &free drop
1 2 make-point over set-first
3 4 make-point over set-second
- 0 [ [ test-struct-x ] [ test-struct-y ] bi / + ] reduce
+ 0 [ [ x>> ] [ y>> ] bi / + ] reduce
] with-destructors
] unit-test
-[ ] [ ALIEN: 123 10 "test-struct" <direct-struct-array> drop ] unit-test
+[ ] [ ALIEN: 123 10 test-struct-array <direct-struct-array> drop ] unit-test
[ ] [
[
- 10 "test-struct" malloc-struct-array
+ 10 test-struct-array malloc-struct-array
&free drop
] with-destructors
-] unit-test
\ No newline at end of file
+] unit-test
+
+[ 15 ] [ 15 10 test-struct-array <struct-array> resize length ] unit-test
+
+[ S{ test-struct-array f 12 20 } ] [
+ struct-array{ test-struct-array
+ S{ test-struct-array f 4 20 }
+ S{ test-struct-array f 12 20 }
+ S{ test-struct-array f 20 20 }
+ } second
+] unit-test
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien alien.c-types byte-arrays kernel libc
-math sequences sequences.private ;
+USING: accessors alien alien.c-types alien.structs byte-arrays
+classes.struct kernel libc math parser sequences sequences.private ;
IN: struct-arrays
+: c-type-struct-class ( c-type -- class )
+ c-type boxed-class>> ; foldable
+
TUPLE: struct-array
{ underlying c-ptr read-only }
{ length array-capacity read-only }
-{ element-size array-capacity read-only } ;
+{ element-size array-capacity read-only }
+{ class read-only } ;
+
+M: struct-array length length>> ; inline
+M: struct-array byte-length [ length>> ] [ element-size>> ] bi * ; inline
-M: struct-array length length>> ;
+: (nth-ptr) ( i struct-array -- alien )
+ [ element-size>> * ] [ underlying>> ] bi <displaced-alien> ; inline
M: struct-array nth-unsafe
- [ element-size>> * ] [ underlying>> ] bi <displaced-alien> ;
+ [ (nth-ptr) ] [ class>> dup struct-class? ] bi [ memory>struct ] [ drop ] if ; inline
M: struct-array set-nth-unsafe
- [ nth-unsafe swap ] [ element-size>> ] bi memcpy ;
+ [ (nth-ptr) swap ] [ element-size>> ] bi memcpy ; inline
M: struct-array new-sequence
- element-size>> [ * <byte-array> ] 2keep struct-array boa ; inline
+ [ element-size>> [ * <byte-array> ] 2keep ]
+ [ class>> ] bi struct-array boa ; inline
+
+M: struct-array resize ( n seq -- newseq )
+ [ [ element-size>> * ] [ underlying>> ] bi resize ]
+ [ [ element-size>> ] [ class>> ] bi ] 2bi
+ struct-array boa ;
: <struct-array> ( length c-type -- struct-array )
- heap-size [ * <byte-array> ] 2keep struct-array boa ; inline
+ [ heap-size [ * <byte-array> ] 2keep ]
+ [ c-type-struct-class ] bi struct-array boa ; inline
ERROR: bad-byte-array-length byte-array ;
: byte-array>struct-array ( byte-array c-type -- struct-array )
- heap-size [
+ [ heap-size [
[ dup length ] dip /mod 0 =
[ drop bad-byte-array-length ] unless
- ] keep struct-array boa ; inline
+ ] keep ] [ c-type-struct-class ] bi struct-array boa ; inline
: <direct-struct-array> ( alien length c-type -- struct-array )
- heap-size struct-array boa ; inline
+ [ heap-size ] [ c-type-struct-class ] bi struct-array boa ; inline
: malloc-struct-array ( length c-type -- struct-array )
[ heap-size calloc ] 2keep <direct-struct-array> ; inline
INSTANCE: struct-array sequence
+
+M: struct-type <c-type-array> ( len c-type -- array )
+ dup c-type-array-constructor
+ [ execute( len -- array ) ]
+ [ <struct-array> ] ?if ; inline
+
+M: struct-type <c-type-direct-array> ( alien len c-type -- array )
+ dup c-type-direct-array-constructor
+ [ execute( alien len -- array ) ]
+ [ <direct-struct-array> ] ?if ; inline
+
+: >struct-array ( sequence class -- struct-array )
+ [ dup length ] dip <struct-array>
+ [ 0 swap copy ] keep ; inline
+
+SYNTAX: struct-array{
+ \ } scan-word [ >struct-array ] curry parse-literal ;
+
+USING: vocabs vocabs.loader ;
+
+"prettyprint" vocab [ "struct-arrays.prettyprint" require ] when
--- /dev/null
+IN: struct-vectors
+USING: help.markup help.syntax alien strings math ;
+
+HELP: struct-vector
+{ $class-description "The class of growable C struct and union arrays." } ;
+
+HELP: <struct-vector>
+{ $values { "capacity" integer } { "c-type" string } { "struct-vector" struct-vector } }
+{ $description "Creates a new vector with the given initial capacity." } ;
+
+ARTICLE: "struct-vectors" "C struct and union vectors"
+"The " { $vocab-link "struct-vectors" } " vocabulary implements vectors specialized for holding C struct and union values. These are growable versions of " { $vocab-link "struct-arrays" } "."
+{ $subsection struct-vector }
+{ $subsection <struct-vector> } ;
+
+ABOUT: "struct-vectors"
--- /dev/null
+IN: struct-vectors.tests
+USING: struct-vectors tools.test alien.c-types alien.syntax
+namespaces kernel sequences ;
+
+C-STRUCT: point
+ { "float" "x" }
+ { "float" "y" } ;
+
+: make-point ( x y -- point )
+ "point" <c-object>
+ [ set-point-y ] keep
+ [ set-point-x ] keep ;
+
+[ ] [ 1 "point" <struct-vector> "v" set ] unit-test
+
+[ 1.5 6.0 ] [
+ 1.0 2.0 make-point "v" get push
+ 3.0 4.5 make-point "v" get push
+ 1.5 6.0 make-point "v" get push
+ "v" get pop [ point-x ] [ point-y ] bi
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types byte-arrays growable kernel math sequences
+sequences.private struct-arrays ;
+IN: struct-vectors
+
+TUPLE: struct-vector
+{ underlying struct-array }
+{ length array-capacity }
+{ c-type read-only } ;
+
+: <struct-vector> ( capacity c-type -- struct-vector )
+ [ <struct-array> 0 ] keep struct-vector boa ; inline
+
+M: struct-vector byte-length underlying>> byte-length ;
+M: struct-vector new-sequence
+ [ c-type>> <struct-array> ] [ [ >fixnum ] [ c-type>> ] bi* ] 2bi
+ struct-vector boa ;
+
+M: struct-vector contract 2drop ;
+
+M: struct-array new-resizable c-type>> <struct-vector> ;
+
+INSTANCE: struct-vector growable
: from-to ( index begin suffix-array -- from/f to/f )
swap '[ _ head? not ]
- [ find-last-from drop dup [ 1+ ] when ]
+ [ find-last-from drop dup [ 1 + ] when ]
[ find-from drop ] 3bi ;
: <funky-slice> ( from/f to/f seq -- slice )
: thread-registered? ( thread -- ? )
id>> threads key? ;
+ERROR: already-stopped thread ;
+
: check-unregistered ( thread -- thread )
- dup thread-registered?
- [ "Thread already stopped" throw ] when ;
+ dup thread-registered? [ already-stopped ] when ;
+
+ERROR: not-running thread ;
: check-registered ( thread -- thread )
- dup thread-registered?
- [ "Thread is not running" throw ] unless ;
+ dup thread-registered? [ not-running ] unless ;
<PRIVATE
ABOUT: "tools.annotations"
HELP: annotate
-{ $values { "word" "a word" } { "quot" { $quotation "( word def -- def )" } } }
+{ $values { "word" "a word" } { "quot" { $quotation "( old-def -- new-def )" } } }
{ $description "Changes a word definition to the result of applying a quotation to the old definition." }
{ $notes "This word is used to implement " { $link watch } "." } ;
HELP: word-timing.
{ $description "Prints the word timing table." } ;
+
+HELP: cannot-annotate-twice
+{ $error-description "Thrown when attempting to annotate a word that's already been annotated. If a word already has an annotation such as a watch or a breakpoint, you must first " { $link reset } " the word before adding another annotation." } ;
\ No newline at end of file
! erg's bug
GENERIC: some-generic ( a -- b )
-M: integer some-generic 1+ ;
+M: integer some-generic 1 + ;
[ 4 ] [ 3 some-generic ] unit-test
[ 4 ] [ 3 some-generic ] unit-test
-[ ] [ "IN: tools.annotations.tests USE: math M: integer some-generic 1- ;" eval( -- ) ] unit-test
+[ ] [ "IN: tools.annotations.tests USE: math M: integer some-generic 1 - ;" eval( -- ) ] unit-test
[ 2 ] [ 3 some-generic ] unit-test
[ ] [ M\ string blah-generic watch ] unit-test
[ "hi" ] [ "hi" blah-generic ] unit-test
+
+! See how well watch interacts with optimizations.
+GENERIC: my-generic ( a -- b )
+M: object my-generic ;
+
+\ my-generic watch
+
+: some-code ( -- )
+ f my-generic drop ;
+
+[ ] [ some-code ] unit-test
USING: accessors kernel math sorting words parser io summary
quotations sequences prettyprint continuations effects
definitions compiler.units namespaces assocs tools.walker
-tools.time generic inspector fry tools.continuations ;
+tools.time generic inspector fry tools.continuations
+locals generalizations macros ;
IN: tools.annotations
-GENERIC: reset ( word -- )
+<PRIVATE
+
+GENERIC: (reset) ( word -- )
-M: generic reset
- subwords [ reset ] each ;
+M: generic (reset)
+ subwords [ (reset) ] each ;
-M: word reset
+M: word (reset)
dup "unannotated-def" word-prop [
- [
- dup dup "unannotated-def" word-prop define
- ] with-compilation-unit
+ dup dup "unannotated-def" word-prop define
f "unannotated-def" set-word-prop
] [ drop ] if ;
+PRIVATE>
+
+: reset ( word -- )
+ [ (reset) ] with-compilation-unit ;
+
ERROR: cannot-annotate-twice word ;
M: cannot-annotate-twice summary drop "Cannot annotate a word twice" ;
cannot-annotate-twice
] when ;
-PRIVATE>
-
-GENERIC# annotate 1 ( word quot -- )
+GENERIC# (annotate) 1 ( word quot -- )
-M: generic annotate
- [ "methods" word-prop values ] dip '[ _ annotate ] each ;
+M: generic (annotate)
+ [ "methods" word-prop values ] dip '[ _ (annotate) ] each ;
-M: word annotate
+M: word (annotate)
[ check-annotate-twice ] dip
- [
- [ dup def>> 2dup "unannotated-def" set-word-prop ] dip
- call( old -- new ) define
- ] with-compilation-unit ;
+ [ dup def>> 2dup "unannotated-def" set-word-prop ] dip
+ call( old -- new ) define ;
-<PRIVATE
+PRIVATE>
-: stack-values ( names -- alist )
- [ datastack ] dip [ nip ] [ length tail* ] 2bi zip ;
+: annotate ( word quot -- )
+ [ (annotate) ] with-compilation-unit ;
-: trace-message ( word quot str -- )
- "--- " write write bl over .
- [ stack-effect ] dip '[ @ stack-values ] [ f ] if*
- [ simple-table. ] unless-empty flush ; inline
+<PRIVATE
+
+:: trace-quot ( word effect quot str -- quot' )
+ effect quot call :> values
+ values length :> n
+ [
+ "--- " write str write bl word .
+ n ndup n narray values swap zip simple-table.
+ flush
+ ] ; inline
-: entering ( str -- ) [ in>> ] "Entering" trace-message ;
+MACRO: entering ( word -- quot )
+ dup stack-effect [ in>> ] "Entering" trace-quot ;
-: leaving ( str -- ) [ out>> ] "Leaving" trace-message ;
+MACRO: leaving ( word -- quot )
+ dup stack-effect [ out>> ] "Leaving" trace-quot ;
: (watch) ( word def -- def )
over '[ _ entering @ _ leaving ] ;
:: (fuzzy) ( accum i full ch -- accum i full ? )
ch i full index-from [
:> i i accum push
- accum i 1+ full t
+ accum i 1 + full t
] [
f -1 full f
] if* ;
[
2dup number=
[ drop ] [ nip V{ } clone pick push ] if
- 1+
+ 1 +
] keep pick last push
] each ;
: score-1 ( i full -- n )
{
{ [ over zero? ] [ 2drop 10 ] }
- { [ 2dup length 1- number= ] [ 2drop 4 ] }
- { [ 2dup [ 1- ] dip nth Letter? not ] [ 2drop 10 ] }
- { [ 2dup [ 1+ ] dip nth Letter? not ] [ 2drop 4 ] }
+ { [ 2dup length 1 - number= ] [ 2drop 4 ] }
+ { [ 2dup [ 1 - ] dip nth Letter? not ] [ 2drop 10 ] }
+ { [ 2dup [ 1 + ] dip nth Letter? not ] [ 2drop 4 ] }
[ 2drop 1 ]
} cond ;
all-words name-completions ;
: vocabs-matching ( str -- seq )
- all-vocabs-seq name-completions ;
+ all-vocabs-recursive no-roots no-prefixes name-completions ;
: chars-matching ( str -- seq )
name-map keys dup zip completions ;
--- /dev/null
+IN: tools.continuations
+USING: help.markup help.syntax ;
+
+HELP: break
+{ $description "A breakpoint. When this word is executed, the walker tool opens with execution suspended at the breakpoint's location." }
+{ $see-also "ui-walker" } ;
\ No newline at end of file
-USING: words ;
+USING: kernel words ;
IN: generic
-: next-method-quot ( method -- quot ) "next-method-quot" word-prop ;
+: (call-next-method) ( method -- )
+ dup "next-method" word-prop execute ;
continuations io vocabs.loader system strings sets vectors quotations
byte-arrays sorting compiler.units definitions generic
generic.standard generic.single tools.deploy.config combinators
-classes slots.private ;
+classes classes.builtin slots.private grouping ;
QUALIFIED: bootstrap.stage2
QUALIFIED: command-line
QUALIFIED: compiler.errors
: strip-init-hooks ( -- )
"Stripping startup hooks" show
{
+ "alien.strings"
"command-line"
"cpu.x86"
+ "destructors"
"environment"
"libc"
- "alien.strings"
}
[ init-hooks get delete-at ] each
deploy-threads? get [
run-file
] when ;
+: strip-destructors ( -- )
+ "libc" vocab [
+ "Stripping destructor debug code" show
+ "vocab:tools/deploy/shaker/strip-destructors.factor"
+ run-file
+ ] when ;
+
: strip-call ( -- )
"Stripping stack effect checking from call( and execute(" show
"vocab:tools/deploy/shaker/strip-call.factor" run-file ;
strip-word-names? [ dup strip-word-names ] when
2drop ;
+: compiler-classes ( -- seq )
+ { "compiler" "stack-checker" }
+ [ child-vocabs [ words ] map concat [ class? ] filter ]
+ map concat unique ;
+
+: prune-decision-tree ( tree classes -- )
+ [ tuple class>type ] 2dip '[
+ dup array? [
+ [
+ dup array? [
+ [
+ 2 group
+ [ drop _ key? not ] assoc-filter
+ concat
+ ] map
+ ] when
+ ] map
+ ] when
+ ] change-nth ;
+
: strip-compiler-classes ( -- )
strip-dictionary? [
"Stripping compiler classes" show
- { "compiler" "stack-checker" }
- [ child-vocabs [ words ] map concat [ class? ] filter ] map concat
- [ dup implementors [ "methods" word-prop delete-at ] with each ] each
+ [ single-generic? ] instances
+ compiler-classes '[ "decision-tree" word-prop _ prune-decision-tree ] each
] when ;
+: recursive-subst ( seq old new -- )
+ '[
+ _ _
+ {
+ ! old becomes new
+ { [ 3dup drop eq? ] [ 2nip ] }
+ ! recurse into arrays
+ { [ pick array? ] [ [ dup ] 2dip recursive-subst ] }
+ ! otherwise do nothing
+ [ 2drop ]
+ } cond
+ ] change-each ;
+
+: strip-default-method ( generic new-default -- )
+ [
+ [ "decision-tree" word-prop ]
+ [ "default-method" word-prop ] bi
+ ] dip
+ recursive-subst ;
+
+: new-default-method ( -- gensym )
+ [ [ "No method" throw ] (( -- * )) define-temp ] with-compilation-unit ;
+
: strip-default-methods ( -- )
+ ! In a development image, each generic has its own default method.
+ ! This gives better error messages for runtime type errors, but
+ ! takes up space. For deployment we merge them all together.
strip-debugger? [
"Stripping default methods" show
- [
- [ generic? ] instances
- [ "No method" throw ] (( -- * )) define-temp
- dup t "default" set-word-prop
- '[
- [ _ "default-method" set-word-prop ] [ make-generic ] bi
- ] each
- ] with-compilation-unit
+ [ single-generic? ] instances
+ new-default-method '[ _ strip-default-method ] each
] when ;
: strip-vocab-globals ( except names -- words )
"io-thread" "io.thread" lookup ,
- "mallocs" "libc.private" lookup ,
+ "disposables" "destructors" lookup ,
deploy-threads? [
"initial-thread" "threads" lookup ,
compiled-generic-crossref
compiler-impl
compiler.errors:compiler-errors
- ! definition-observers
- interactive-vocabs
lexer-factory
print-use-hook
root-cache
{ } { "math.partial-dispatch" } strip-vocab-globals %
+ { } { "math.vectors.specialization" } strip-vocab-globals %
+
{ } { "peg" } strip-vocab-globals %
] when
[ compress-object? ] [ ] "objects" compress ;
: remain-compiled ( old new -- old new )
- #! Quotations which were formerly compiled must remain
- #! compiled.
+ ! Quotations which were formerly compiled must remain
+ ! compiled.
2dup [
2dup [ quot-compiled? ] [ quot-compiled? not ] bi* and
[ nip jit-compile ] [ 2drop ] if
[ boot ] %
init-hooks get values concat %
strip-debugger? [ , ] [
- ! Don't reference try directly
+ ! Don't reference 'try' directly since we don't want
+ ! to pull in the debugger and prettyprinter into every
+ ! deployed app
[:c]
[print-error]
'[
t "quiet" set-global
f output-stream set-global ;
-: unsafe-next-method-quot ( method -- quot )
+: next-method* ( method -- quot )
[ "method-class" word-prop ]
[ "method-generic" word-prop ] bi
- next-method 1quotation ;
+ next-method ;
: compute-next-methods ( -- )
[ standard-generic? ] instances [
"methods" word-prop [
- nip dup
- unsafe-next-method-quot
- "next-method-quot" set-word-prop
+ nip dup next-method* "next-method" set-word-prop
] assoc-each
] each
"vocab:tools/deploy/shaker/next-methods.factor" run-file ;
: (clear-megamorphic-cache) ( i array -- )
+ ! Can't do any dispatch while clearing caches since that
+ ! might leave them in an inconsistent state.
2dup 1 slot < [
2dup [ f ] 2dip set-array-nth
[ 1 + ] dip (clear-megamorphic-cache)
: strip ( -- )
init-stripper
strip-libc
+ strip-destructors
strip-call
strip-cocoa
strip-debugger
compute-next-methods
strip-init-hooks
strip-c-io
- strip-compiler-classes
strip-default-methods
+ strip-compiler-classes
f 5 setenv ! we can't use the Factor debugger or Factor I/O anymore
deploy-vocab get vocab-main deploy-boot-quot
find-megamorphic-caches
"threads" vocab [
[
"error-in-thread" "threads" lookup
- [ die 2drop ]
- define
+ [ [ die 2drop ] define ] [ f "combination" set-word-prop ] bi
] with-compilation-unit
] when
--- /dev/null
+USE: kernel
+IN: destructors.private
+
+: register-disposable ( obj -- ) drop ; inline
+
+: unregister-disposable ( obj -- ) drop ; inline
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: help.markup help.syntax kernel words ;
+IN: tools.deprecation
+
+HELP: :deprecations
+{ $description "Prints all deprecation notes." } ;
+
+ARTICLE: "tools.deprecation" "Deprecation tracking"
+"Factor's core syntax defines a " { $link POSTPONE: deprecated } " word that can be applied to words to mark them as deprecated. When the " { $vocab-link "tools.deprecation" } " vocabulary is loaded, notes will be collected and reported by the " { $link "tools.errors" } " mechanism when deprecated words are used to define other words."
+{ $subsection POSTPONE: deprecated }
+{ $subsection :deprecations } ;
+
+ABOUT: "tools.deprecation"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors arrays assocs compiler.units
+debugger init io kernel namespaces prettyprint sequences
+source-files.errors summary tools.crossref
+tools.crossref.private tools.errors words ;
+IN: tools.deprecation
+
+SYMBOL: +deprecation-note+
+SYMBOL: deprecation-notes
+
+deprecation-notes [ H{ } clone ] initialize
+
+TUPLE: deprecation-note < source-file-error ;
+
+M: deprecation-note error-type drop +deprecation-note+ ;
+
+TUPLE: deprecated-usages asset usages ;
+
+: :deprecations ( -- )
+ deprecation-notes get-global values errors. ;
+
+T{ error-type
+ { type +deprecation-note+ }
+ { word ":deprecations" }
+ { plural "deprecated word usages" }
+ { icon "vocab:ui/tools/error-list/icons/deprecation-note.tiff" }
+ { quot [ deprecation-notes get values ] }
+ { forget-quot [ deprecation-notes get delete-at ] }
+} define-error-type
+
+: <deprecation-note> ( error word -- deprecation-note )
+ \ deprecation-note <definition-error> ;
+
+: deprecation-note ( word usages -- )
+ [ deprecated-usages boa ]
+ [ drop <deprecation-note> ]
+ [ drop deprecation-notes get-global set-at ] 2tri ;
+
+: clear-deprecation-note ( word -- )
+ deprecation-notes get-global delete-at ;
+
+: check-deprecations ( word -- )
+ dup "forgotten" word-prop
+ [ clear-deprecation-note ] [
+ dup def>> uses [ deprecated? ] filter
+ [ clear-deprecation-note ] [ >array deprecation-note ] if-empty
+ ] if ;
+
+M: deprecated-usages summary
+ drop "Deprecated words used" ;
+
+M: deprecated-usages error.
+ "The definition of " write
+ dup asset>> pprint
+ " uses these deprecated words:" write nl
+ usages>> [ " " write pprint nl ] each ;
+
+SINGLETON: deprecation-observer
+
+: initialize-deprecation-notes ( -- )
+ get-crossref [ drop deprecated? ] assoc-filter
+ values [ keys [ check-deprecations ] each ] each ;
+
+M: deprecation-observer definitions-changed
+ drop keys [ word? ] filter
+ dup [ deprecated? ] filter empty?
+ [ [ check-deprecations ] each ]
+ [ drop initialize-deprecation-notes ] if ;
+
+[ \ deprecation-observer add-definition-observer ]
+"tools.deprecation" add-init-hook
+
+initialize-deprecation-notes
--- /dev/null
+Tracking usage of deprecated words
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax help.tips quotations destructors ;
+IN: tools.destructors
+
+HELP: disposables.
+{ $description "Print the number of disposable objects of each class." } ;
+
+HELP: leaks
+{ $values
+ { "quot" quotation }
+}
+{ $description "Runs a quotation, printing any increases in the number of disposable objects after the quotation returns. The " { $link debug-leaks? } " variable is also switched on while the quotation runs, recording the current continuation in every newly-created disposable object." } ;
+
+TIP: "Use the " { $link leaks } " combinator to track down resource leaks." ;
+
+ARTICLE: "tools.destructors" "Destructor tools"
+"The " { $vocab-link "tools.destructors" } " vocabulary provides words for tracking down resource leaks."
+{ $subsection debug-leaks? }
+{ $subsection disposables. }
+{ $subsection leaks }
+{ $see-also "destructors" } ;
+
+ABOUT: "tools.destructors"
--- /dev/null
+USING: kernel tools.destructors tools.test destructors namespaces ;
+IN: tools.destructors.tests
+
+f debug-leaks? set-global
+
+[ [ 3 throw ] leaks ] must-fail
+
+[ f ] [ debug-leaks? get-global ] unit-test
+
+[ ] [ [ ] leaks ] unit-test
+
+[ f ] [ debug-leaks? get-global ] unit-test
+
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs classes destructors fry kernel math namespaces
+prettyprint sequences sets sorting continuations accessors arrays
+io io.styles combinators.smart ;
+IN: tools.destructors
+
+<PRIVATE
+
+: class-tally ( assoc -- assoc' )
+ H{ } clone [ [ keys ] dip '[ dup class _ push-at ] each ] keep ;
+
+: (disposables.) ( assoc -- )
+ class-tally >alist [ first2 [ length ] keep 3array ] map [ second ] sort-with
+ standard-table-style [
+ [
+ [ "Disposable class" write ] with-cell
+ [ "Instances" write ] with-cell
+ [ ] with-cell
+ ] with-row
+ [
+ [
+ [
+ [ pprint-cell ]
+ [ pprint-cell ]
+ [ [ "[ List instances ]" swap write-object ] with-cell ]
+ tri*
+ ] input<sequence
+ ] with-row
+ ] each
+ ] tabular-output nl ;
+
+: sort-disposables ( seq -- seq' )
+ [ disposable? ] partition [ [ id>> ] sort-with ] dip append ;
+
+PRIVATE>
+
+: disposables. ( -- )
+ disposables get (disposables.) ;
+
+: disposables-of-class. ( class -- )
+ [ disposables get values sort-disposables ] dip
+ '[ _ instance? ] filter stack. ;
+
+: leaks ( quot -- )
+ disposables get clone
+ t debug-leaks? set-global
+ [
+ [ call disposables get clone ] dip
+ ] [ f debug-leaks? set-global ] [ ] cleanup
+ assoc-diff (disposables.) ; inline
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: tr arrays sequences io words generic system combinators
-vocabs.loader kernel ;
+USING: alien alien.c-types arrays byte-arrays combinators
+destructors generic io kernel libc math sequences system tr
+vocabs.loader words ;
IN: tools.disassembler
GENERIC: disassemble ( obj -- )
TR: tabs>spaces "\t" "\s" ;
+M: byte-array disassemble
+ [
+ [ malloc-byte-array &free alien-address dup ]
+ [ length + ] bi
+ 2array disassemble
+ ] with-destructors ;
+
M: pair disassemble first2 disassemble* [ tabs>spaces print ] each ;
M: word disassemble word-xt 2array disassemble ;
CONSTANT: +listener-input+ "<Listener input>"
-M: source-file-error summary
+: error-location ( error -- string )
[
- [ file>> [ % ": " % ] [ +listener-input+ % ] if* ]
- [ line#>> [ # ] when* ] bi
+ [ file>> [ % ] [ +listener-input+ % ] if* ]
+ [ line#>> [ ": " % # ] when* ] bi
] "" make ;
+M: source-file-error summary error>> summary ;
+
M: source-file-error error.
- [ summary print nl ]
+ [ error-location print nl ]
[ asset>> [ "Asset: " write short. nl ] when* ]
[ error>> error. ]
tri ;
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays io io.streams.string kernel math math.parser
-namespaces sequences splitting grouping strings ascii
-byte-arrays byte-vectors ;
+USING: arrays ascii byte-arrays byte-vectors grouping io
+io.encodings.binary io.files io.streams.string kernel math
+math.parser namespaces sequences splitting strings ;
IN: tools.hexdump
<PRIVATE
: hexdump ( byte-array -- str )
[ hexdump. ] with-string-writer ;
+
+: hexdump-file ( path -- )
+ binary file-contents hexdump. ;
{ "str" string }
{ "hash" hashtable }
{ "hashtable" hashtable }
- { "?" "a boolean" }
+ { "?" boolean }
{ "ch" "a character" }
{ "word" word }
{ "array" array }
[ nip require ]
} 2cleave ;
+: scaffold-core ( string -- ) "resource:core" swap scaffold-vocab ;
+
+: scaffold-basis ( string -- ) "resource:basis" swap scaffold-vocab ;
+
+: scaffold-extra ( string -- ) "resource:extra" swap scaffold-vocab ;
+
+: scaffold-work ( string -- ) "resource:work" swap scaffold-vocab ;
+
<PRIVATE
: tests-file-string ( vocab -- string )
'[ _ ndup _ narray _ prefix ] ;
: experiment. ( seq -- )
- [ first write ": " write ] [ rest . ] bi ;
+ [ first write ": " write ] [ rest . flush ] bi ;
:: experiment ( word: ( -- error ? ) line# -- )
word <experiment> :> e
M: test-failure error. ( error -- )
{
- [ summary print nl ]
+ [ error-location print nl ]
[ asset>> [ experiment. nl ] when* ]
[ error>> error. ]
[ traceback-button. ]
--- /dev/null
+IN: tools.walker
+USING: help.syntax help.markup tools.continuations ;
+
+HELP: B
+{ $description "An alias for " { $link break } ", defined in the " { $vocab-link "syntax" } " vocabulary so that it is always available." } ;
\ No newline at end of file
[ \ CLASS [ tuple-prototype <repetition> concat ] [ tuple-arity ] bi ] keep
\ CLASS-array boa ; inline
-M: CLASS-array length length>> ;
+M: CLASS-array length length>> ; inline
-M: CLASS-array nth-unsafe tuple-slice \ CLASS read-tuple ;
+M: CLASS-array nth-unsafe tuple-slice \ CLASS read-tuple ; inline
-M: CLASS-array set-nth-unsafe tuple-slice \ CLASS write-tuple ;
+M: CLASS-array set-nth-unsafe tuple-slice \ CLASS write-tuple ; inline
-M: CLASS-array new-sequence drop <CLASS-array> ;
+M: CLASS-array new-sequence drop <CLASS-array> ; inline
: >CLASS-array ( seq -- tuple-array ) 0 <CLASS-array> clone-like ;
-M: CLASS-array like drop dup CLASS-array? [ >CLASS-array ] unless ;
+M: CLASS-array like drop dup CLASS-array? [ >CLASS-array ] unless ; inline
INSTANCE: CLASS-array sequence
HOOK: offscreen-pixels ui-backend ( world -- alien w h )
-: with-gl-context ( handle quot -- )
- '[ select-gl-context @ ]
- [ flush-gl-context gl-error ] bi ; inline
-
HOOK: (with-ui) ui-backend ( quot -- )
HOOK: (grab-input) ui-backend ( handle -- )
cocoa.views cocoa.windows combinators command-line
core-foundation core-foundation.run-loop core-graphics
core-graphics.types destructors fry generalizations io.thread
-kernel libc literals locals math math.rectangles memory
-namespaces sequences specialized-arrays.int threads ui
+kernel libc literals locals math math.bitwise math.rectangles memory
+namespaces sequences threads ui
ui.backend ui.backend.cocoa.views ui.clipboards ui.gadgets
ui.gadgets.worlds ui.pixel-formats ui.pixel-formats.private
ui.private words.symbol ;
M: cocoa-ui-backend (fullscreen?) ( world -- ? )
handle>> view>> -> isInFullScreenMode zero? not ;
+CONSTANT: window-control>styleMask
+ H{
+ { close-button $ NSClosableWindowMask }
+ { minimize-button $ NSMiniaturizableWindowMask }
+ { maximize-button 0 }
+ { resize-handles $ NSResizableWindowMask }
+ { small-title-bar $[ NSTitledWindowMask NSUtilityWindowMask bitor ] }
+ { normal-title-bar $ NSTitledWindowMask }
+ }
+
+: world>styleMask ( world -- n )
+ window-controls>> window-control>styleMask symbols>flags ;
+
M:: cocoa-ui-backend (open-window) ( world -- )
world [ [ dim>> ] dip <FactorView> ]
with-world-pixel-format :> view
- view world world>NSRect <ViewWindow> :> window
+ view world [ world>NSRect ] [ world>styleMask ] bi <ViewWindow> :> window
view -> release
world view register-window
window world window-loc>> auto-position
M: cocoa-ui-backend close-window ( gadget -- )
find-world [
handle>> [
- window>> f -> performClose:
+ window>> -> close
] when*
] when* ;
! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien alien.c-types arrays assocs cocoa kernel math
-cocoa.messages cocoa.subclassing cocoa.classes cocoa.views
-cocoa.application cocoa.pasteboard cocoa.types cocoa.windows sequences
-ui ui.private ui.gadgets ui.gadgets.private ui.gadgets.worlds
-ui.gestures core-foundation.strings core-graphics core-graphics.types
-threads combinators math.rectangles ;
+USING: accessors alien alien.c-types alien.strings arrays assocs
+cocoa kernel math cocoa.messages cocoa.subclassing cocoa.classes
+cocoa.views cocoa.application cocoa.pasteboard cocoa.types
+cocoa.windows sequences io.encodings.utf8 ui ui.private ui.gadgets
+ui.gadgets.private ui.gadgets.worlds ui.gestures
+core-foundation.strings core-graphics core-graphics.types threads
+combinators math.rectangles ;
IN: ui.backend.cocoa.views
: send-mouse-moved ( view event -- )
[ drop dim>> first2 ]
2bi <CGRect> ;
+CONSTANT: selector>action H{
+ { "undo:" undo-action }
+ { "redo:" redo-action }
+ { "cut:" cut-action }
+ { "copy:" copy-action }
+ { "paste:" paste-action }
+ { "delete:" delete-action }
+ { "selectAll:" select-all-action }
+ { "newDocument:" new-action }
+ { "openDocument:" open-action }
+ { "saveDocument:" save-action }
+ { "saveDocumentAs:" save-as-action }
+ { "revertDocumentToSaved:" revert-action }
+}
+
+: validate-action ( world selector -- ? validated? )
+ selector>action at
+ [ swap world-focus parents-handle-gesture? t ] [ drop f f ] if* ;
+
CLASS: {
{ +superclass+ "NSOpenGLView" }
{ +name+ "FactorView" }
[ nip send-key-up-event ]
}
+{ "validateUserInterfaceItem:" "char" { "id" "SEL" "id" }
+ [
+ nip -> action
+ 2dup [ window ] [ utf8 alien>string ] bi* validate-action
+ [ [ 2drop ] dip >c-bool ] [ SUPER-> validateUserInterfaceItem: ] if
+ ]
+}
+
{ "undo:" "id" { "id" "SEL" "id" }
[ nip undo-action send-action$ ]
}
[ nip select-all-action send-action$ ]
}
+{ "newDocument:" "id" { "id" "SEL" "id" }
+ [ nip new-action send-action$ ]
+}
+
+{ "openDocument:" "id" { "id" "SEL" "id" }
+ [ nip open-action send-action$ ]
+}
+
+{ "saveDocument:" "id" { "id" "SEL" "id" }
+ [ nip save-action send-action$ ]
+}
+
+{ "saveDocumentAs:" "id" { "id" "SEL" "id" }
+ [ nip save-as-action send-action$ ]
+}
+
+{ "revertDocumentToSaved:" "id" { "id" "SEL" "id" }
+ [ nip revert-action send-action$ ]
+}
+
! Multi-touch gestures: this is undocumented.
! http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
{ "magnifyWithEvent:" "void" { "id" "SEL" "id" }
windows.messages windows.types windows.offscreen windows.nt
threads libc combinators fry combinators.short-circuit continuations
command-line shuffle opengl ui.render math.bitwise locals
-accessors math.rectangles math.order calendar ascii
+accessors math.rectangles math.order calendar ascii sets
io.encodings.utf16n windows.errors literals ui.pixel-formats
ui.pixel-formats.private memoize classes struct-arrays ;
IN: ui.backend.windows
lf>crlf [
utf16n string>alien
EmptyClipboard win32-error=0/f
- GMEM_MOVEABLE over length 1+ GlobalAlloc
+ GMEM_MOVEABLE over length 1 + GlobalAlloc
dup win32-error=0/f
dup GlobalLock dup win32-error=0/f
SYMBOLS: msg-obj class-name-ptr mouse-captured ;
-: style ( -- n ) WS_OVERLAPPEDWINDOW ; inline
-: ex-style ( -- n ) WS_EX_APPWINDOW WS_EX_WINDOWEDGE bitor ; inline
+CONSTANT: window-control>style
+ H{
+ { close-button 0 }
+ { minimize-button $ WS_MINIMIZEBOX }
+ { maximize-button $ WS_MAXIMIZEBOX }
+ { resize-handles $ WS_THICKFRAME }
+ { small-title-bar $ WS_CAPTION }
+ { normal-title-bar $ WS_CAPTION }
+ }
+
+CONSTANT: window-control>ex-style
+ H{
+ { close-button 0 }
+ { minimize-button 0 }
+ { maximize-button 0 }
+ { resize-handles $ WS_EX_WINDOWEDGE }
+ { small-title-bar $ WS_EX_TOOLWINDOW }
+ { normal-title-bar $ WS_EX_APPWINDOW }
+ }
+
+: needs-sysmenu? ( controls -- ? )
+ { close-button minimize-button maximize-button } intersects? ;
+
+: has-titlebar? ( controls -- ? )
+ { small-title-bar normal-title-bar } intersects? ;
+
+: world>style ( world -- n )
+ window-controls>>
+ [ window-control>style symbols>flags ]
+ [ needs-sysmenu? [ WS_SYSMENU bitor ] when ]
+ [ has-titlebar? [ WS_POPUP bitor ] unless ] tri ;
+
+: world>ex-style ( world -- n )
+ window-controls>> window-control>ex-style symbols>flags ;
: get-RECT-top-left ( RECT -- x y )
[ RECT-left ] keep RECT-top ;
: handle-wm-size ( hWnd uMsg wParam lParam -- )
2nip
[ lo-word ] keep hi-word 2array
- dup { 0 0 } = [ 2drop ] [ swap window (>>dim) ] if ;
+ dup { 0 0 } = [ 2drop ] [ swap window [ (>>dim) ] [ drop ] if* ] if ;
: handle-wm-move ( hWnd uMsg wParam lParam -- )
2nip
[ lo-word ] keep hi-word 2array
- swap window (>>window-loc) ;
+ swap window [ (>>window-loc) ] [ drop ] if* ;
CONSTANT: wm-keydown-codes
H{
RegisterClassEx win32-error=0/f
] [ drop ] if ;
-: adjust-RECT ( RECT -- )
- style 0 ex-style AdjustWindowRectEx win32-error=0/f ;
+: adjust-RECT ( RECT style ex-style -- )
+ [ 0 ] dip AdjustWindowRectEx win32-error=0/f ;
: make-RECT ( world -- RECT )
[ window-loc>> ] [ dim>> ] bi <RECT> ;
CW_USEDEFAULT over set-RECT-left
CW_USEDEFAULT swap set-RECT-top ;
-: make-adjusted-RECT ( rect -- RECT )
- make-RECT
- dup get-RECT-top-left [ zero? ] both? swap
- dup adjust-RECT
+: make-adjusted-RECT ( rect style ex-style -- RECT )
+ [
+ make-RECT
+ dup get-RECT-top-left [ zero? ] both? swap
+ dup
+ ] 2dip adjust-RECT
swap [ dup default-position-RECT ] when ;
: get-window-class ( -- class-name )
dup
] change-global ;
-: create-window ( rect -- hwnd )
- make-adjusted-RECT
+:: create-window ( rect style ex-style -- hwnd )
+ rect style ex-style make-adjusted-RECT
[ get-window-class f ] dip
[
[ ex-style ] 2dip
- { WS_CLIPSIBLINGS WS_CLIPCHILDREN style } flags
+ WS_CLIPSIBLINGS WS_CLIPCHILDREN bitor style bitor
] dip get-RECT-dimensions
f f f GetModuleHandle f CreateWindowEx dup win32-error=0/f ;
[ swap [ handle>> hDC>> set-pixel-format ] [ get-rc ] bi ]
with-world-pixel-format ;
+: disable-close-button ( hwnd -- )
+ 0 GetSystemMenu
+ SC_CLOSE MF_BYCOMMAND MF_GRAYED bitor EnableMenuItem drop ;
+
+: ?disable-close-button ( world hwnd -- )
+ swap window-controls>> close-button swap member? not
+ [ disable-close-button ] [ drop ] if ;
+
M: windows-ui-backend (open-window) ( world -- )
- [ dup create-window [ f f ] dip f f <win> >>handle setup-gl ]
+ [
+ dup
+ [ ] [ world>style ] [ world>ex-style ] tri create-window
+ [ ?disable-close-button ]
+ [ [ f f ] dip f f <win> >>handle setup-gl ] 2bi
+ ]
[ dup handle>> hWnd>> register-window ]
[ handle>> hWnd>> show-window ] tri ;
} cleave ;
: exit-fullscreen ( world -- )
- handle>> hWnd>>
+ dup handle>> hWnd>>
{
- [
- GWL_STYLE GetWindowLong
- fullscreen-flags bitor
- ]
- [ GWL_STYLE rot SetWindowLong win32-error=0/f ]
+ [ GWL_STYLE rot world>style SetWindowLong win32-error=0/f ]
[
f
over hwnd>RECT get-RECT-dimensions
: max-descent ( seq -- n )
[ descent>> ] map ?supremum ;
-: max-text-height ( seq -- y )
- [ ascent>> ] filter [ height>> ] map ?supremum ;
-
: max-graphics-height ( seq -- y )
[ ascent>> not ] filter [ height>> ] map ?supremum 0 or ;
<PRIVATE
-: page-elt ( editor -- editor element ) dup visible-lines 1- <page-elt> ;
+: page-elt ( editor -- editor element ) dup visible-lines 1 - <page-elt> ;
PRIVATE>
: this-line-and-next ( document line -- start end )
[ nip 0 swap 2array ]
- [ [ nip 1+ ] [ 1+ swap doc-line length ] 2bi 2array ]
+ [ [ nip 1 + ] [ 1 + swap doc-line length ] 2bi 2array ]
2bi ;
: last-line? ( document line -- ? )
[ '[ [ dim>> ] [ gap>> ] [ filled-cell>> ] tri _ tri@ ] dip ] dip call ; inline
: available-space ( pref-dim gap dims -- avail )
- length 1+ * [-] ; inline
+ length 1 + * [-] ; inline
: -center) ( pref-dim gap filled-cell dims -- )
[ nip available-space ] 2keep [ remove-nth sum [-] ] 2keep set-nth ; inline
[ <frame-grid> ] dip new-grid ; inline
: <frame> ( cols rows -- frame )
- frame new-frame ;
\ No newline at end of file
+ frame new-frame ;
mock-gadget new 0 >>graft-called 0 >>ungraft-called ;
M: mock-gadget graft*
- [ 1+ ] change-graft-called drop ;
+ [ 1 + ] change-graft-called drop ;
M: mock-gadget ungraft*
- [ 1+ ] change-ungraft-called drop ;
+ [ 1 + ] change-ungraft-called drop ;
! We can't print to output-stream here because that might be a pane
! stream, and our graft-queue rebinding here would be captured
3 [
<mock-gadget> over <model> >>model
"g" get over add-gadget drop
- swap 1+ number>string set
+ swap 1 + number>string set
] each ;
: status-flags ( -- seq )
orientation>> vertical = "\n" "" ? ;
: gadget-seq-text ( seq gadget -- )
- gadget-text-separator swap
- [ dup % ] [ gadget-text* ] interleave drop ;
+ gadget-text-separator '[ _ % ] [ gadget-text* ] interleave ;
M: gadget gadget-text*
[ children>> ] keep gadget-seq-text ;
USING: vocabs vocabs.loader ;
-"prettyprint" vocab [ "ui.gadgets.prettyprint" require ] when
\ No newline at end of file
+"prettyprint" vocab [ "ui.gadgets.prettyprint" require ] when
: line>y ( n gadget -- y ) line-height * >integer ;
: validate-line ( m gadget -- n )
- control-value [ drop f ] [ length 1- min 0 max ] if-empty ;
+ control-value [ drop f ] [ length 1 - min 0 max ] if-empty ;
: valid-line? ( n gadget -- ? )
- control-value length 1- 0 swap between? ;
+ control-value length 1 - 0 swap between? ;
: visible-line ( gadget quot -- n )
'[
[ loc>> ] visible-line ;
: last-visible-line ( gadget -- n )
- [ [ loc>> ] [ dim>> ] bi v+ ] visible-line 1+ ;
+ [ [ loc>> ] [ dim>> ] bi v+ ] visible-line 1 + ;
: each-slice-index ( from to seq quot -- )
[ [ <slice> ] [ drop [a,b) ] 3bi ] dip 2each ; inline
2bi 2array ;
: visible-lines ( gadget -- n )
- [ visible-dim second ] [ line-height ] bi /i ;
\ No newline at end of file
+ [ visible-dim second ] [ line-height ] bi /i ;
: <operations-menu> ( target hook -- menu )
over object-operations
[ primary-operation? ] partition
- [ reverse ] [ [ [ command-name ] compare ] sort ] bi*
+ [ reverse ] [ [ command-name ] sort-with ] bi*
{ ---- } glue <commands-menu> ;
: show-operations-menu ( gadget target hook -- )
add-incremental
] [ next-line ] bi ;
-: ?pane-nl ( pane -- )
- [ dup current>> children>> empty? [ pane-nl ] [ drop ] if ]
- [ pane-nl ] bi ;
-
: smash-pane ( pane -- gadget ) [ pane-nl ] [ output>> smash-line ] bi ;
: pane-write ( seq pane -- )
] [ drop ] if ;
: end-selection ( pane -- )
- f >>selecting?
- hand-moved?
+ dup selecting?>> hand-moved? or
+ [ f >>selecting? ] dip
[ [ com-copy-selection ] [ request-focus ] bi ]
[ [ relayout-1 ] [ focus-input ] bi ]
if ;
[ ] [
<gadget> dup "g" set
- 10 1 0 100 <range> 20 1 0 100 <range> 2array <product>
+ 10 1 0 100 1 <range> 20 1 0 100 1 <range> 2array <product>
<viewport> "v" set
] unit-test
} set-gestures
: <scroller-model> ( -- model )
- 0 0 0 0 <range> 0 0 0 0 <range> 2array <product> ;
+ 0 0 0 0 1 <range> 0 0 0 0 1 <range> 2array <product> ;
M: viewport pref-dim* gadget-child pref-viewport-dim ;
column-line-color
selection-required?
single-click?
-selected-value
+selection
min-rows
min-cols
max-rows
HELP: elevator
{ $class-description "An elevator is the part of a " { $link slider } " between the up/down arrow buttons, where a " { $link thumb } " may be moved up and down." } ;
-HELP: find-elevator
-{ $values { "gadget" gadget } { "elevator/f" { $maybe elevator } } }
-{ $description "Finds the first parent of " { $snippet "gadget" } " which is an " { $link elevator } ". Outputs " { $link f } " if the gadget is not contained in an " { $link elevator } "." } ;
-
HELP: slider
{ $class-description "A slider is a control for graphically manipulating a " { $link "models-range" } "."
$nl
TUPLE: slider < track elevator thumb saved line ;
-: slider-value ( gadget -- n ) model>> range-value >fixnum ;
+: slider-value ( gadget -- n ) model>> range-value ;
: slider-page ( gadget -- n ) model>> range-page-value ;
+: slider-min ( gadget -- n ) model>> range-min-value ;
: slider-max ( gadget -- n ) model>> range-max-value ;
: slider-max* ( gadget -- n ) model>> range-max-value* ;
+: slider-length ( gadget -- n ) [ slider-max ] [ slider-min ] bi - ;
+: slider-length* ( gadget -- n ) [ slider-max* ] [ slider-min ] bi - ;
+
: slide-by ( amount slider -- ) model>> move-by ;
: slide-by-page ( amount slider -- ) model>> move-by-page ;
TUPLE: elevator < gadget direction ;
-: find-elevator ( gadget -- elevator/f ) [ elevator? ] find-parent ;
-
: find-slider ( gadget -- slider/f ) [ slider? ] find-parent ;
CONSTANT: elevator-padding 4
CONSTANT: min-thumb-dim 30
: visible-portion ( slider -- n )
- [ slider-page ] [ slider-max 1 max ] bi / 1 min ;
+ [ slider-page ]
+ [ slider-length 1 max ]
+ bi / 1 min ;
: thumb-dim ( slider -- h )
[
#! x*n is the screen position of the thumb, and conversely
#! for x/n. The '1 max' calls avoid division by zero.
[ [ elevator-length ] [ thumb-dim ] bi - 1 max ]
- [ slider-max* 1 max ]
+ [ slider-length* 1 max ]
bi / ;
: slider>screen ( m slider -- n ) slider-scale * ;
swap >>orientation ;
: thumb-loc ( slider -- loc )
- [ slider-value ] keep slider>screen elevator-padding + ;
+ [ slider-value ]
+ [ slider-min - ]
+ [ slider>screen elevator-padding + ] tri ;
: layout-thumb-loc ( thumb slider -- )
[ thumb-loc ] [ orientation>> ] bi n*v
[ <up-button> f track-add ]
[ <down-button> f track-add ]
[ drop <gadget> { 1 1 } >>dim f track-add ]
- } cleave ;
\ No newline at end of file
+ } cleave ;
+
{ $subsection column-titles } ;
ARTICLE: "ui.gadgets.tables.selection" "Table row selection"
-"At any given time, a single row in the table may be selected."
-$nl
"A few slots in the table gadget concern row selection:"
{ $table
- { { $slot "selected-value" } { " - if set to a model, the currently selected row's value, as determined by a " { $link row-value } " call to the renderer, is stored in this model. See " { $link "models" } "." } }
- { { $slot "selected-index" } " - the index of the currently selected row." }
+ { { $slot "selection" } { " - if set to a model, the values of the currently selected row or rows, as determined by a " { $link row-value } " call to the renderer, is stored in this model. See " { $link "models" } "." } }
+ { { $slot "selection-index" } { " - if set to a model, the indices of the currently selected rows." } }
{ { $slot "selection-required?" } { " - if set to a true value, the table ensures that some row is always selected, if the model is non-empty. If set to " { $link f } ", a state where nothing is selected is permitted to occur. The default is " { $link f } "." } }
+ { { $slot "multiple-selection?" } { " - if set to a true value, users are allowed to select more than one value." } }
}
"Some words for row selection:"
-{ $subsection selected-row }
-{ $subsection (selected-row) } ;
+{ $subsection selected-rows }
+{ $subsection (selected-rows) }
+{ $subsection selected } ;
ARTICLE: "ui.gadgets.tables.actions" "Table row actions"
"When the user double-clicks on a row, or presses " { $command table "row" row-action } " while a row is selected, optional action and hook quotations are invoked. The action receives the row value and the hook receives the table gadget itself. These quotations are stored in the " { $slot "action" } " and " { $snippet "hook" } " slots of a table, respectively."
IN: ui.gadgets.tables.tests
USING: ui.gadgets.tables ui.gadgets.scrollers ui.gadgets.debug accessors
-models namespaces tools.test kernel combinators ;
+models namespaces tools.test kernel combinators prettyprint arrays ;
SINGLETON: test-renderer
[ selected-row drop ]
} cleave
] with-grafted-gadget
-] unit-test
\ No newline at end of file
+] unit-test
+
+SINGLETON: silly-renderer
+
+M: silly-renderer row-columns drop unparse 1array ;
+
+M: silly-renderer column-titles drop { "Foo" } ;
+
+: test-table-2 ( -- table )
+ { 1 2 f } <model> silly-renderer <table> ;
+
+[ f f ] [
+ test-table dup [
+ selected-row
+ ] with-grafted-gadget
+] unit-test
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays colors colors.constants fry kernel math
-math.functions math.rectangles math.order math.vectors namespaces
-opengl sequences ui.gadgets ui.gadgets.scrollers ui.gadgets.status-bar
-ui.gadgets.worlds ui.gestures ui.render ui.pens.solid ui.text
-ui.commands ui.images ui.gadgets.menus ui.gadgets.line-support
-models math.ranges combinators
-combinators.short-circuit fonts locals strings ;
+USING: accessors assocs hashtables arrays colors colors.constants fry
+kernel math math.functions math.ranges math.rectangles math.order
+math.vectors namespaces opengl sequences ui.gadgets
+ui.gadgets.scrollers ui.gadgets.status-bar ui.gadgets.worlds
+ui.gestures ui.render ui.pens.solid ui.text ui.commands ui.images
+ui.gadgets.menus ui.gadgets.line-support models combinators
+combinators.short-circuit fonts locals strings sets sorting ;
IN: ui.gadgets.tables
! Row rendererer protocol
{ mouse-color initial: COLOR: black }
column-line-color
selection-required?
-selected-index selected-value
+selection
+selection-index
+selected-indices
mouse-index
{ takes-focus? initial: t }
-focused? ;
+focused?
+multiple-selection? ;
+
+<PRIVATE
+
+: add-selected-index ( table n -- table )
+ over selected-indices>> conjoin ;
+
+: multiple>single ( values -- value/f ? )
+ dup assoc-empty? [ drop f f ] [ values first t ] if ;
+
+: selected-index ( table -- n )
+ selected-indices>> multiple>single drop ;
+
+: set-selected-index ( table n -- table )
+ dup associate >>selected-indices ;
+
+PRIVATE>
+
+: selected ( table -- index/indices )
+ [ selected-indices>> ] [ multiple-selection?>> ] bi
+ [ multiple>single drop ] unless ;
: new-table ( rows renderer class -- table )
new-line-gadget
swap >>renderer
swap >>model
- f <model> >>selected-value
sans-serif-font >>font
focus-border-color >>focus-border-color
- transparent >>column-line-color ; inline
+ transparent >>column-line-color
+ f <model> >>selection-index
+ f <model> >>selection
+ H{ } clone >>selected-indices ;
: <table> ( rows renderer -- table ) table new-table ;
: row-bounds ( table row -- loc dim )
row-rect rect-bounds ; inline
-: draw-selected-row ( table -- )
+: draw-selected-rows ( table -- )
{
- { [ dup selected-index>> not ] [ drop ] }
+ { [ dup selected-indices>> assoc-empty? ] [ drop ] }
[
- [ ] [ selected-index>> ] [ selection-color>> gl-color ] tri
- row-bounds gl-fill-rect
+ [ selected-indices>> keys ] [ selection-color>> gl-color ] [ ] tri
+ [ swap row-bounds gl-fill-rect ] curry each
]
} cond ;
: draw-focused-row ( table -- )
{
{ [ dup focused?>> not ] [ drop ] }
- { [ dup selected-index>> not ] [ drop ] }
+ { [ dup selected-index not ] [ drop ] }
[
- [ ] [ selected-index>> ] [ focus-border-color>> gl-color ] tri
+ [ ] [ selected-index ] [ focus-border-color>> gl-color ] tri
row-bounds gl-rect
]
} cond ;
dup renderer>> column-alignment
[ ] [ column-widths>> length 0 <repetition> ] ?if ;
-:: row-font ( row index table -- font )
+:: row-font ( row ind table -- font )
table font>> clone
row table renderer>> row-color [ >>foreground ] when*
- index table selected-index>> = [ table selection-color>> >>background ] when ;
+ ind table selected-indices>> key?
+ [ table selection-color>> >>background ] when ;
: draw-columns ( columns widths alignment font gap -- )
'[ [ _ ] 3dip _ draw-column ] 3each ;
dup control-value empty? [ drop ] [
dup line-height \ line-height [
{
- [ draw-selected-row ]
+ [ draw-selected-rows ]
[ draw-lines ]
[ draw-column-lines ]
[ draw-focused-row ]
PRIVATE>
-: (selected-row) ( table -- value/f ? )
- [ selected-index>> ] keep nth-row ;
+: (selected-rows) ( table -- assoc )
+ [ selected-indices>> ] keep
+ '[ _ nth-row drop ] assoc-map ;
+
+: selected-rows ( table -- assoc )
+ [ selected-indices>> ] [ ] [ renderer>> ] tri
+ '[ _ nth-row drop _ row-value ] assoc-map ;
+
+: (selected-row) ( table -- value/f ? ) (selected-rows) multiple>single ;
-: selected-row ( table -- value/f ? )
- [ (selected-row) ] keep
- swap [ renderer>> row-value t ] [ 2drop f f ] if ;
+: selected-row ( table -- value/f ? ) selected-rows multiple>single ;
<PRIVATE
-: update-selected-value ( table -- )
- [ selected-row drop ] [ selected-value>> ] bi set-model ;
+: set-table-model ( model value multiple? -- )
+ [ values ] [ multiple>single drop ] if swap set-model ;
+
+: update-selected ( table -- )
+ [
+ [ selection>> ]
+ [ selected-rows ]
+ [ multiple-selection?>> ] tri
+ set-table-model
+ ]
+ [
+ [ selection-index>> ]
+ [ selected-indices>> ]
+ [ multiple-selection?>> ] tri
+ set-table-model
+ ] bi ;
: show-row-summary ( table n -- )
over nth-row
f >>mouse-index [ hide-status ] [ relayout-1 ] bi ;
: find-row-index ( value table -- n/f )
- [ model>> value>> ] [ renderer>> '[ _ row-value ] map index ] bi ;
+ [ model>> value>> ] [ renderer>> ] bi
+ '[ _ row-value eq? ] with find drop ;
-: initial-selected-index ( table -- n/f )
+: (update-selected-indices) ( table -- set )
+ [ selection>> value>> dup [ array? not ] [ ] bi and [ 1array ] when ] keep
+ '[ _ find-row-index ] map sift unique f assoc-like ;
+
+: initial-selected-indices ( table -- set )
{
[ model>> value>> empty? not ]
[ selection-required?>> ]
- [ drop 0 ]
+ [ drop { 0 } unique ]
} 1&& ;
-: (update-selected-index) ( table -- n/f )
- [ selected-value>> value>> ] keep over
- [ find-row-index ] [ 2drop f ] if ;
-
-: update-selected-index ( table -- n/f )
+: update-selected-indices ( table -- set )
{
- [ (update-selected-index) ]
- [ initial-selected-index ]
+ [ (update-selected-indices) ]
+ [ initial-selected-indices ]
} 1|| ;
M: table model-changed
- nip dup update-selected-index {
- [ >>selected-index f >>mouse-index drop ]
- [ show-row-summary ]
- [ drop update-selected-value ]
+ nip dup update-selected-indices {
+ [ >>selected-indices f >>mouse-index drop ]
+ [ multiple>single drop show-row-summary ]
+ [ drop update-selected ]
[ drop relayout ]
} 2cleave ;
: thin-row-rect ( table row -- rect )
row-rect [ { 0 1 } v* ] change-dim ;
+: scroll-to-row ( table n -- )
+ dup [ [ thin-row-rect ] [ drop ] 2bi scroll>rect ] [ 2drop ] if ;
+
+: add-selected-row ( table n -- )
+ [ scroll-to-row ]
+ [ add-selected-index relayout-1 ] 2bi ;
+
: (select-row) ( table n -- )
- [ dup [ [ thin-row-rect ] [ drop ] 2bi scroll>rect ] [ 2drop ] if ]
- [ >>selected-index relayout-1 ]
+ [ scroll-to-row ]
+ [ set-selected-index relayout-1 ]
2bi ;
: mouse-row ( table -- n )
[ hand-rel second ] keep y>line ;
-: if-mouse-row ( table true: ( table mouse-index -- ) false: ( table -- ) -- )
+: if-mouse-row ( table true: ( mouse-index table -- ) false: ( table -- ) -- )
[ [ mouse-row ] keep 2dup valid-line? ]
[ ] [ '[ nip @ ] ] tri* if ; inline
+: (table-button-down) ( quot table -- )
+ dup takes-focus?>> [ dup request-focus ] when swap
+ '[ swap [ >>mouse-index ] _ bi ] [ drop ] if-mouse-row ; inline
+
: table-button-down ( table -- )
- dup takes-focus?>> [ dup request-focus ] when
- [ swap [ >>mouse-index ] [ (select-row) ] bi ] [ drop ] if-mouse-row ;
+ [ (select-row) ] swap (table-button-down) ;
+
+: continued-button-down ( table -- )
+ dup multiple-selection?>>
+ [ [ add-selected-row ] swap (table-button-down) ] [ table-button-down ] if ;
+
+: thru-button-down ( table -- )
+ dup multiple-selection?>> [
+ [ 2dup over selected-index (a,b) swap
+ [ swap add-selected-index drop ] curry each add-selected-row ]
+ swap (table-button-down)
+ ] [ table-button-down ] if ;
PRIVATE>
if ;
: row-action? ( table -- ? )
- [ [ mouse-row ] keep valid-line? ]
- [ single-click?>> hand-click# get 2 = or ] bi and ;
+ single-click?>> hand-click# get 2 = or ;
<PRIVATE
: table-button-up ( table -- )
- dup row-action? [ row-action ] [ update-selected-value ] if ;
+ dup [ mouse-row ] keep valid-line? [
+ dup row-action? [ row-action ] [ update-selected ] if
+ ] [ drop ] if ;
PRIVATE>
: select-row ( table n -- )
over validate-line
[ (select-row) ]
- [ drop update-selected-value ]
+ [ drop update-selected ]
[ show-row-summary ]
2tri ;
<PRIVATE
: prev/next-row ( table n -- )
- [ dup selected-index>> ] dip '[ _ + ] [ 0 ] if* select-row ;
+ [ dup selected-index ] dip '[ _ + ] [ 0 ] if* select-row ;
: previous-row ( table -- )
-1 prev/next-row ;
0 select-row ;
: last-row ( table -- )
- dup control-value length 1- select-row ;
+ dup control-value length 1 - select-row ;
: prev/next-page ( table n -- )
- over visible-lines 1- * prev/next-row ;
+ over visible-lines 1 - * prev/next-row ;
: previous-page ( table -- )
-1 prev/next-page ;
{ mouse-enter show-mouse-help }
{ mouse-leave hide-mouse-help }
{ motion show-mouse-help }
- { T{ button-down } table-button-down }
+ { T{ button-down f { S+ } 1 } thru-button-down }
+ { T{ button-down f { A+ } 1 } continued-button-down }
{ T{ button-up } table-button-up }
+ { T{ button-up f { S+ } } table-button-up }
+ { T{ button-down } table-button-down }
{ gain-focus focus-table }
{ lose-focus unfocus-table }
{ T{ drag } table-button-down }
dup renderer>> column-titles
[ <column-headers> ] [ drop f ] if ;
-PRIVATE>
\ No newline at end of file
+PRIVATE>
USING: ui.gadgets ui.render ui.text ui.text.private
ui.gestures ui.backend help.markup help.syntax
-models opengl sequences strings ;
+models opengl sequences strings destructors ;
IN: ui.gadgets.worlds
HELP: user-input
{ $description "Sets the title bar of the native window containing the world." }
{ $notes "This word should not be called directly by user code. Instead, change the " { $snippet "title" } " slot model; see " { $link "models" } "." } ;
-HELP: select-gl-context
-{ $values { "handle" "a backend-specific handle" } }
+HELP: set-gl-context
+{ $values { "world" world } }
{ $description "Selects an OpenGL context to be the implicit destination for subsequent GL rendering calls. This word is called automatically by the UI before drawing a " { $link world } "." } ;
+HELP: window-resource
+{ $values { "resource" disposable } { "resource" disposable } }
+{ $description "Marks " { $snippet "resource" } " to be destroyed with " { $link dispose } " when the window with the currently active OpenGL context (set by " { $link set-gl-context } ") is closed. " { $snippet "resource" } " is left unmodified at the top of the stack." } ;
+
HELP: flush-gl-context
{ $values { "handle" "a backend-specific handle" } }
{ $description "Ensures all GL rendering calls made to an OpenGL context finish rendering to the screen. This word is called automatically by the UI after drawing a " { $link world } "." } ;
{ { $snippet "grab-input?" } " - if set to " { $link t } ", the world will hide the mouse cursor and disable normal mouse input while focused. Use " { $link grab-input } " and " { $link ungrab-input } " to change this setting." }
{ { $snippet "handle" } " - a backend-specific native handle representing the native window containing the world, or " { $link f } " if the world is not grafted." }
{ { $snippet "window-loc" } " - the on-screen location of the native window containing the world. The co-ordinate system here is backend-specific." }
+ { { $snippet "window-controls" } " - the set of " { $link "ui.gadgets.worlds-window-controls" } " with which the world window was created." }
}
} ;
{ $subsection "ui.gadgets.worlds-subclassing" }
{ $subsection "gl-utilities" }
{ $subsection "text-rendering" } ;
+
ui.pixel-formats destructors literals strings ;
IN: ui.gadgets.worlds
+SYMBOLS:
+ close-button
+ minimize-button
+ maximize-button
+ resize-handles
+ small-title-bar
+ normal-title-bar ;
+
CONSTANT: default-world-pixel-format-attributes
{ windowed double-buffered T{ depth-bits { value 16 } } }
+CONSTANT: default-world-window-controls
+ {
+ normal-title-bar
+ close-button
+ minimize-button
+ maximize-button
+ resize-handles
+ }
+
TUPLE: world < track
active? focused? grab-input?
layers
title status status-owner
text-handle handle images
window-loc
- pixel-format-attributes ;
+ pixel-format-attributes
+ window-controls
+ window-resources ;
TUPLE: world-attributes
{ world-class initial: world }
{ title string initial: "Factor Window" }
status
gadgets
- { pixel-format-attributes initial: $ default-world-pixel-format-attributes } ;
+ { pixel-format-attributes initial: $ default-world-pixel-format-attributes }
+ { window-controls initial: $ default-world-window-controls } ;
: <world-attributes> ( -- world-attributes )
world-attributes new ; inline
'[ f _ [ (>>status-owner) ] [ status>> set-model ] 2bi ] when
] [ 2drop ] if ;
+: window-resource ( resource -- resource )
+ dup world get-global window-resources>> push ;
+
+: set-gl-context ( world -- )
+ [ world set-global ]
+ [ handle>> select-gl-context ] bi ;
+
+: with-gl-context ( world quot -- )
+ '[ set-gl-context @ ]
+ [ handle>> flush-gl-context gl-error ] bi ; inline
+
ERROR: no-world-found ;
: find-gl-context ( gadget -- )
find-world dup
- [ handle>> select-gl-context ] [ no-world-found ] if ;
+ [ set-gl-context ] [ no-world-found ] if ;
: (request-focus) ( child world ? -- )
pick parent>> pick eq? [
t >>root?
f >>active?
{ 0 0 } >>window-loc
- f >>grab-input? ;
+ f >>grab-input?
+ V{ } clone >>window-resources ;
: apply-world-attributes ( world attributes -- world )
{
[ title>> >>title ]
[ status>> >>status ]
[ pixel-format-attributes>> >>pixel-format-attributes ]
+ [ window-controls>> >>window-controls ]
[ grab-input?>> >>grab-input? ]
[ gadgets>> [ 1 track-add ] each ]
} cleave ;
M: world (>>dim)
[ call-next-method ]
[
- dup handle>>
- [ select-gl-context resize-world ]
- [ drop ] if*
+ dup active?>> [
+ dup handle>>
+ [ [ set-gl-context ] [ resize-world ] bi ]
+ [ drop ] if
+ ] [ drop ] if
] bi ;
GENERIC: draw-world* ( world -- )
dup draw-world? [
dup world [
[
- dup handle>> [ draw-world* ] with-gl-context
+ dup [ draw-world* ] with-gl-context
flush-layout-cache-hook get call( -- )
] [
over <world-error> ui-error
"Outputs " { $link f } " if the gesture was handled, and " { $link t } " if the gesture should be passed on to the gadget's parent."
$nl
"The default implementation looks at the " { $snippet "\"gestures\"" } " word property of each superclass of the gadget's class." }
-{ $notes "Methods should be defined on this word if you desire to handle an arbitrary set of gestures. To define handlers for a fixed set, it is easier to use " { $link set-gestures } "." } ;
+{ $notes "Methods should be defined on this word if you desire to handle an arbitrary set of gestures. To define handlers for a fixed set, it is easier to use " { $link set-gestures } ". If you define a method on " { $snippet "handle-gesture" } ", you should also override " { $link handles-gesture? } "." } ;
-{ propagate-gesture handle-gesture set-gestures } related-words
+HELP: handles-gesture?
+{ $values { "gesture" "a gesture" } { "gadget" "the receiver of the gesture" } { "?" "a boolean" } }
+{ $contract "Returns a true value if " { $snippet "gadget" } " would handle " { $snippet "gesture" } " in its " { $link handle-gesture } " method."
+$nl
+"The default implementation looks at the " { $snippet "\"gestures\"" } " word property of each superclass of the gadget's class and returns true if a handler is present for " { $snippet "gesture" } "." }
+{ $notes "This word is used in Factor's MacOS X UI to validate menu items." } ;
+
+HELP: parents-handle-gesture?
+{ $values { "gesture" "a gesture" } { "gadget" "the receiver of the gesture" } { "?" "a boolean" } }
+{ $contract "Returns a true value if " { $snippet "gadget" } " or any of its ancestors would handle " { $snippet "gesture" } " in its " { $link handle-gesture } " method." } ;
+
+{ propagate-gesture handle-gesture handles-gesture? set-gestures } related-words
HELP: propagate-gesture
{ $values { "gesture" "a gesture" } { "gadget" gadget } }
{ $class-description "Gesture sent when the " { $emphasis "select all" } " standard window system action is invoked." }
{ $examples { $code "select-all-action" } } ;
+HELP: new-action
+{ $class-description "Gesture sent when the " { $emphasis "new" } " standard window system action is invoked." }
+{ $examples { $code "new-action" } } ;
+
+HELP: open-action
+{ $class-description "Gesture sent when the " { $emphasis "open" } " standard window system action is invoked." }
+{ $examples { $code "open-action" } } ;
+
+HELP: save-action
+{ $class-description "Gesture sent when the " { $emphasis "save" } " standard window system action is invoked." }
+{ $examples { $code "save-action" } } ;
+
+HELP: save-as-action
+{ $class-description "Gesture sent when the " { $emphasis "save as" } " standard window system action is invoked." }
+{ $examples { $code "save-as-action" } } ;
+
+HELP: revert-action
+{ $class-description "Gesture sent when the " { $emphasis "revert" } " standard window system action is invoked." }
+{ $examples { $code "revert-action" } } ;
+
+HELP: close-action
+{ $class-description "Gesture sent when the " { $emphasis "close" } " standard window system action is invoked." }
+{ $examples { $code "close-action" } } ;
+
HELP: C+
{ $description "Control key modifier." } ;
{ $subsection zoom-out-action } ;
ARTICLE: "action-gestures" "Action gestures"
-"Action gestures exist to keep keyboard shortcuts for common clipboard operations consistent."
+"Action gestures exist to keep keyboard shortcuts for common application operations consistent."
+{ $subsection undo-action }
+{ $subsection redo-action }
{ $subsection cut-action }
{ $subsection copy-action }
{ $subsection paste-action }
{ $subsection delete-action }
{ $subsection select-all-action }
+{ $subsection new-action }
+{ $subsection open-action }
+{ $subsection save-action }
+{ $subsection save-as-action }
+{ $subsection revert-action }
+{ $subsection close-action }
"The following keyboard gestures, if not handled directly, send action gestures:"
{ $table
{ { $strong "Keyboard gesture" } { $strong "Action gesture" } }
{ { $snippet "T{ key-down f { C+ } \"z\" }" } { $snippet "undo-action" } }
- { { $snippet "T{ key-down f { C+ } \"Z\" }" } { $snippet "redo-action" } }
+ { { $snippet "T{ key-down f { C+ } \"y\" }" } { $snippet "redo-action" } }
{ { $snippet "T{ key-down f { C+ } \"x\" }" } { $snippet "cut-action" } }
{ { $snippet "T{ key-down f { C+ } \"c\" }" } { $snippet "copy-action" } }
{ { $snippet "T{ key-down f { C+ } \"v\" }" } { $snippet "paste-action" } }
{ { $snippet "T{ key-down f { C+ } \"a\" }" } { $snippet "select-all-action" } }
+ { { $snippet "T{ key-down f { C+ } \"n\" }" } { $snippet "new-action" } }
+ { { $snippet "T{ key-down f { C+ } \"o\" }" } { $snippet "open-action" } }
+ { { $snippet "T{ key-down f { C+ } \"s\" }" } { $snippet "save-action" } }
+ { { $snippet "T{ key-down f { C+ } \"S\" }" } { $snippet "save-as-action" } }
+ { { $snippet "T{ key-down f { C+ } \"w\" }" } { $snippet "close-action" } }
}
"Action gestures should be used in place of the above keyboard gestures if possible. For example, on Mac OS X, the standard " { $strong "Edit" } " menu items send action gestures." ;
combinators.short-circuit ;
IN: ui.gestures
+: get-gesture-handler ( gesture gadget -- quot )
+ class superclasses [ "gestures" word-prop ] map assoc-stack ;
+
GENERIC: handle-gesture ( gesture gadget -- ? )
M: object handle-gesture
[ nip ]
- [ class superclasses [ "gestures" word-prop ] map assoc-stack ] 2bi
+ [ get-gesture-handler ] 2bi
dup [ call( gadget -- ) f ] [ 2drop t ] if ;
+GENERIC: handles-gesture? ( gesture gadget -- ? )
+
+M: object handles-gesture? ( gesture gadget -- ? )
+ get-gesture-handler >boolean ;
+
+: parents-handle-gesture? ( gesture gadget -- ? )
+ [ handles-gesture? not ] with each-parent not ;
+
: set-gestures ( class hash -- ) "gestures" set-word-prop ;
: gesture-queue ( -- deque ) \ gesture-queue get ;
cut-action copy-action paste-action
delete-action select-all-action
left-action right-action up-action down-action
-zoom-in-action zoom-out-action ;
+zoom-in-action zoom-out-action
+new-action open-action save-action save-as-action
+revert-action close-action ;
UNION: action
undo-action redo-action
cut-action copy-action paste-action
delete-action select-all-action
left-action right-action up-action down-action
-zoom-in-action zoom-out-action ;
+zoom-in-action zoom-out-action
+new-action open-action save-action save-as-action
+revert-action close-action ;
CONSTANT: action-gestures
{
{ "z" undo-action }
- { "Z" redo-action }
+ { "y" redo-action }
{ "x" cut-action }
{ "c" copy-action }
{ "v" paste-action }
{ "a" select-all-action }
+ { "n" new-action }
+ { "o" open-action }
+ { "s" save-action }
+ { "S" save-as-action }
+ { "w" close-action }
}
! Modifiers
:: gradient-vertices ( direction dim colors -- seq )
direction dim v* dim over v- swap
- colors length dup 1- v/n [ v*n ] with map
+ colors length dup 1 - v/n [ v*n ] with map
swap [ over v+ 2array ] curry map
concat concat >float-array ;
[ colors>> draw-gradient ]
} cleave ;
-M: gradient pen-background 2drop transparent ;
\ No newline at end of file
+M: gradient pen-background 2drop transparent ;
ERROR: invalid-pixel-format-attributes world attributes ;
-TUPLE: pixel-format world handle ;
+TUPLE: pixel-format < disposable world handle ;
: <pixel-format> ( world attributes -- pixel-format )
2dup (make-pixel-format)
- [ nip pixel-format boa ] [ invalid-pixel-format-attributes ] if* ;
+ [ pixel-format new-disposable swap >>handle swap >>world ]
+ [ invalid-pixel-format-attributes ]
+ ?if ;
-M: pixel-format dispose
+M: pixel-format dispose*
[ (free-pixel-format) ] [ f >>handle drop ] bi ;
: pixel-format-attribute ( pixel-format attribute-name -- value )
\r
M: uniscribe-renderer x>offset ( x font string -- n )\r
[ 2drop 0 ] [\r
- cached-script-string x>line-offset 0 = [ 1+ ] unless\r
+ cached-script-string x>line-offset 0 = [ 1 + ] unless\r
] if-empty ;\r
\r
M: uniscribe-renderer offset>x ( n font string -- x )\r
: com-help ( debugger -- ) error>> error-help-window ;
-: com-edit ( debugger -- ) error>> (:edit) ;
+: com-edit ( debugger -- ) error>> edit-error ;
\ com-edit H{ { +listener+ t } } define-command
! { { $image "vocab:ui/tools/error-list/icons/syntax-error.tiff" } "Syntax error" { $link "syntax" } }
{ { $image "vocab:ui/tools/error-list/icons/compiler-error.tiff" } "Compiler error" { $link "compiler-errors" } }
{ { $image "vocab:ui/tools/error-list/icons/linkage-error.tiff" } "Linkage error" { $link "loading-libs" } }
- { { $image "vocab:ui/tools/error-list/icons/unit-test-error.tiff" } "Unit test failure" { $link "tools.test" } }
{ { $image "vocab:ui/tools/error-list/icons/help-lint-error.tiff" } "Help lint failure" { $link "help.lint" } }
+ { { $image "vocab:ui/tools/error-list/icons/unit-test-error.tiff" } "Unit test failure" { $link "tools.test" } }
+ { { $image "vocab:ui/tools/error-list/icons/deprecation-note.tiff" } "Deprecated words used" { $link "tools.deprecation" } }
} ;
ABOUT: "ui.tools.error-list"
60 >>min-cols
60 >>max-cols
t >>selection-required?
- error-list source-file>> >>selected-value ;
+ error-list source-file>> >>selection ;
SINGLETON: error-renderer
60 >>min-cols
60 >>max-cols
t >>selection-required?
- error-list error>> >>selected-value ;
+ error-list error>> >>selection ;
TUPLE: error-display < track ;
{ 5 5 } >>gap
error-list <error-list-toolbar> f track-add
error-list source-file-table>> <scroller> "Source files" <labeled-gadget> 1/4 track-add
- error-list error-table>> <scroller> "Errors" <labeled-gadget> 1/2 track-add
- error-list error-display>> "Details" <labeled-gadget> 1/4 track-add
+ error-list error-table>> <scroller> "Errors" <labeled-gadget> 1/4 track-add
+ error-list error-display>> "Details" <labeled-gadget> 1/2 track-add
{ 5 5 } <filled-border> 1 track-add ;
M: error-list-gadget focusable-child*
make-mirror [ <slot-description> ] { } assoc>map ;
M: hashtable make-slot-descriptions
- call-next-method [ [ key-string>> ] compare ] sort ;
+ call-next-method [ key-string>> ] sort-with ;
: <inspector-table> ( model -- table )
[ make-slot-descriptions ] <arrow> inspector-renderer <table>
M: word-completion row-color
[ vocabulary>> ] [ manifest>> ] bi* {
+ { [ dup not ] [ COLOR: black ] }
{ [ 2dup search-vocabs>> memq? ] [ COLOR: black ] }
{ [ over ".private" tail? ] [ COLOR: dark-red ] }
[ COLOR: dark-gray ]
[ ] [ "h" get history-recall-previous ] unit-test
[ "22" ] [ "d" get doc-string ] unit-test
+
+[ ] [ <document> "d" set ] unit-test
+[ ] [ "d" get <history> "h" set ] unit-test
+
+[ ] [ "aaa" "d" get set-doc-string ] unit-test
+[ T{ input f "aaa" } ] [ "h" get history-add ] unit-test
+
+[ ] [ "" "d" get set-doc-string ] unit-test
+[ T{ input f "" } ] [ "h" get history-add ] unit-test
+[ T{ input f "" } ] [ "h" get history-add ] unit-test
+[ ] [ " " "d" get set-doc-string ] unit-test
+[ ] [ "h" get history-recall-previous ] unit-test
+
V{ } clone 0 history boa ;
: history-add ( history -- input )
- dup elements>> length 1+ >>index
+ dup elements>> length 1 + >>index
[ document>> doc-string [ <input> ] [ empty? ] bi ] keep
'[ [ _ elements>> push ] keep ] unless ;
<PRIVATE
+: (save-history) ( input index elements -- )
+ 2dup length > [
+ [ [ T{ input f "" } ] dip push ] keep
+ (save-history)
+ ] [ set-nth ] if ;
+
: save-history ( history -- )
[ document>> doc-string ] keep
- '[ <input> _ [ index>> ] [ elements>> ] bi set-nth ]
+ '[ <input> _ [ index>> ] [ elements>> ] bi (save-history) ]
unless-empty ;
: update-document ( history -- )
[ set-doc-string ] [ clear-undo drop ] 2bi ;
: change-history-index ( history i -- )
- over elements>> length 1-
+ over elements>> length 1 -
'[ _ + _ min 0 max ] change-index drop ;
: history-recall ( history i -- )
M: interactor dispose drop ;
: go-to-error ( interactor error -- )
- [ line>> 1- ] [ column>> ] bi 2array
+ [ line>> 1 - ] [ column>> ] bi 2array
over set-caret
mark>caret ;
: use-if-necessary ( word manifest -- )
2dup [ vocabulary>> ] dip and [
manifest [
- vocabulary>> use-vocab
+ [ vocabulary>> use-vocab ]
+ [ dup name>> associate use-words ] bi
] with-variable
] [ 2drop ] if ;
[ call-next-method ] [ restart-listener ] bi ;
M: listener-gadget ungraft*
- [ com-end ] [ call-next-method ] bi ;
\ No newline at end of file
+ [ com-end ] [ call-next-method ] bi ;
! Copyright (C) 2006, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: continuations definitions generic help.topics threads
-stack-checker summary io.pathnames io.styles kernel namespaces parser
-prettyprint quotations tools.crossref tools.annotations editors
-tools.profiler tools.test tools.time tools.walker vocabs vocabs.loader
-words sequences classes compiler.errors compiler.units
-accessors vocabs.parser macros.expander ui ui.tools.browser
-ui.tools.listener ui.tools.listener.completion ui.tools.profiler
-ui.tools.inspector ui.tools.traceback ui.commands ui.gadgets.editors
-ui.gestures ui.operations ui.tools.deploy models help.tips
-source-files.errors ;
+stack-checker summary io.pathnames io.styles kernel namespaces
+parser prettyprint quotations tools.crossref tools.annotations
+editors tools.profiler tools.test tools.time tools.walker vocabs
+vocabs.loader words sequences classes compiler.errors
+compiler.units accessors vocabs.parser macros.expander ui
+ui.tools.browser ui.tools.listener ui.tools.listener.completion
+ui.tools.profiler ui.tools.inspector ui.tools.traceback
+ui.commands ui.gadgets.editors ui.gestures ui.operations
+ui.tools.deploy models help.tips source-files.errors destructors
+libc libc.private ;
IN: ui.tools.operations
! Objects
{ +listener+ t }
} define-operation
+! Disposables
+[ disposable? ] \ dispose H{ } define-operation
+
+! Disposables with a continuation
+PREDICATE: tracked-disposable < disposable
+ continuation>> >boolean ;
+
+PREDICATE: tracked-malloc-ptr < malloc-ptr
+ continuation>> >boolean ;
+
+: com-creation-traceback ( disposable -- )
+ continuation>> traceback-window ;
+
+[ tracked-disposable? ] \ com-creation-traceback H{ { +primary+ t } } define-operation
+[ tracked-malloc-ptr? ] \ com-creation-traceback H{ { +primary+ t } } define-operation
+
! Operations -> commands
interactor
"quotation"
horizontal <track>
{ 3 3 } >>gap
profiler vocabs>> vocab-renderer <profiler-table>
- profiler vocab>> >>selected-value
+ profiler vocab>> >>selection
10 >>min-rows
10 >>max-rows
"Vocabularies" <labeled-gadget>
horizontal <track>
{ 3 3 } >>gap
profiler <generic-model> word-renderer <profiler-table>
- profiler generic>> >>selected-value
+ profiler generic>> >>selection
"Generic words" <labeled-gadget>
1/2 track-add
profiler <class-model> word-renderer <profiler-table>
- profiler class>> >>selected-value
+ profiler class>> >>selection
"Classes" <labeled-gadget>
1/2 track-add
1/2 track-add
} define-command-map
tool "common" f {
- { T{ key-down f { A+ } "s" } save }
{ T{ key-down f { A+ } "w" } close-window }
{ T{ key-down f { A+ } "q" } com-exit }
{ T{ key-down f f "F2" } refresh-all }
$nl\r
"Breakpoints can be inserted directly into code:"\r
{ $subsection break }\r
+{ $subsection POSTPONE: B }\r
"Note that because the walker calls various core library and UI words while rendering its own user interface, setting a breakpoint on a word such as " { $link append } " or " { $link draw-gadget } " will hang the UI." ;\r
\r
ARTICLE: "ui-walker" "UI walker"\r
] [
[
[ traverse-step traverse-from-path ]
- [ tuck children>> swap first 1+ tail-slice % ] 2bi
+ [ tuck children>> swap first 1 + tail-slice % ] 2bi
] make-node
] if
] if ;
traverse-step traverse-from-path ;
: (traverse-middle) ( frompath topath gadget -- )
- [ first 1+ ] [ first ] [ children>> ] tri* <slice> % ;
+ [ first 1 + ] [ first ] [ children>> ] tri* <slice> % ;
: traverse-post ( topath gadget -- )
traverse-step traverse-to-path ;
M: gadget leaves* conjoin ;
-: leaves ( tree -- assoc ) H{ } clone [ leaves* ] keep ;
\ No newline at end of file
+: leaves ( tree -- assoc ) H{ } clone [ leaves* ] keep ;
{ $values { "gadget" gadget } { "title/attributes" { "a " { $link string } " or a " { $link world-attributes } " tuple" } } }
{ $description "Opens a native window containing " { $snippet "gadget" } " with the specified attributes. If a string is provided, it is used as the window title; otherwise, the window attributes are specified in a " { $link world-attributes } " tuple." } ;
+HELP: close-window
+{ $values { "gadget" gadget } }
+{ $description "Close the native window containing " { $snippet "gadget" } "." } ;
+
HELP: world-attributes
{ $values { "world-class" class } { "title" string } { "status" gadget } { "gadgets" sequence } { "pixel-format-attributes" sequence } }
{ $class-description "Tuples of this class can be passed to " { $link open-window } " to control attributes of the window opened. The following attributes can be set:" }
{ { $snippet "status" } ", if specified, is a gadget that will be used as the window's status bar." }
{ { $snippet "gadgets" } " is a sequence of gadgets that will be placed inside the window." }
{ { $snippet "pixel-format-attributes" } " is a sequence of " { $link "ui.pixel-formats-attributes" } " that the window will request for its OpenGL pixel format." }
+ { { $snippet "window-controls" } " is a sequence of " { $link "ui.gadgets.worlds-window-controls" } " that will be placed in the window." }
} ;
HELP: set-fullscreen
HELP: beep
{ $description "Plays the system beep sound." } ;
+HELP: topmost-window
+{ $values { "world" world } }
+{ $description "Returns the " { $link world } " representing the currently focused window." } ;
+
ARTICLE: "ui-glossary" "UI glossary"
{ $table
{ "color" { "an instance of " { $link color } } }
{ $subsection "ui-backend" } ;
ABOUT: "ui"
+
+HELP: close-button
+{ $description "Asks for a close button to be available for a window. Without a close button, a window cannot be closed by the user and must be closed by the program using " { $link close-window } "." } ;
+
+HELP: minimize-button
+{ $description "Asks for a minimize button to be available for a window." } ;
+
+HELP: maximize-button
+{ $description "Asks for a maximize button to be available for a window." } ;
+
+HELP: resize-handles
+{ $description "Asks for resize controls to be available for a window. Without resize controls, the window size will not be changeable by the user." } ;
+
+HELP: small-title-bar
+{ $description "Asks for a window to have a small title bar. Without a title bar, the " { $link close-button } ", " { $link minimize-button } ", and " { $link maximize-button } " controls will not be available. A small title bar may have other side effects in the window system, such as causing the window to not show up in the system task switcher and to float over other Factor windows." } ;
+
+HELP: normal-title-bar
+{ $description "Asks for a window to have a title bar. Without a title bar, the " { $link close-button } ", " { $link minimize-button } ", and " { $link maximize-button } " controls will not be available." } ;
+
+ARTICLE: "ui.gadgets.worlds-window-controls" "Window controls"
+"The following window controls can be placed in a " { $link world } " window:"
+{ $subsection close-button }
+{ $subsection minimize-button }
+{ $subsection maximize-button }
+{ $subsection resize-handles }
+{ $subsection small-title-bar }
+{ $subsection normal-title-bar }
+"Provide a sequence of these values in the " { $snippet "window-controls" } " slot of the " { $link world-attributes } " tuple you pass to " { $link open-window } "." ;
#! etc.
swap 2array windows get-global push
windows get-global dup length 1 >
- [ [ length 1- dup 1- ] keep exchange ] [ drop ] if ;
+ [ [ length 1 - dup 1 - ] keep exchange ] [ drop ] if ;
: unregister-window ( handle -- )
windows [ [ first = not ] with filter ] change-global ;
: set-up-window ( world -- )
{
- [ handle>> select-gl-context ]
+ [ set-gl-context ]
[ [ title>> ] keep set-title ]
[ begin-world ]
[ resize-world ]
: (ungraft-world) ( world -- )
{
- [ handle>> select-gl-context ]
+ [ set-gl-context ]
[ text-handle>> [ dispose ] when* ]
[ images>> [ dispose ] when* ]
[ hand-clicked close-global ]
[ hand-gadget close-global ]
[ end-world ]
+ [ [ <reversed> [ [ dispose ] when* ] each V{ } clone ] change-window-resources drop ]
} cleave ;
M: world ungraft*
windows get empty? not ;
: ?attributes ( gadget title/attributes -- attributes )
- dup string? [ world-attributes new swap >>title ] when
+ dup string? [ world-attributes new swap >>title ] [ clone ] if
swap [ [ [ 1array ] [ f ] if* ] curry unless* ] curry change-gadgets ;
PRIVATE>
: raise-window ( gadget -- )
find-world raise-window* ;
+: topmost-window ( -- world )
+ windows get last second ;
+
HOOK: close-window ui-backend ( gadget -- )
M: object close-window
"The " { $vocab-link "unicode.breaks" "unicode.breaks" } " vocabulary partially implements Unicode Standard Annex #29. This provides for segmentation of a string along grapheme and word boundaries. In Unicode, a grapheme, or a basic unit of display in text, may be more than one code point. For example, in the string \"e\\u000301\" (where U+0301 is a combining acute accent), there is only one grapheme, as the acute accent goes above the e, forming a single grapheme. Word breaks, in general, are more complicated than simply splitting by whitespace, and the Unicode algorithm provides for that."
$nl "Operations for graphemes:"
{ $subsection first-grapheme }
+{ $subsection first-grapheme-from }
{ $subsection last-grapheme }
+{ $subsection last-grapheme-from }
{ $subsection >graphemes }
{ $subsection string-reverse }
"Operations on words:"
{ $subsection first-word }
+{ $subsection first-word-from }
+{ $subsection last-word }
+{ $subsection last-word-from }
{ $subsection >words } ;
HELP: first-grapheme
{ $values { "str" string } { "i" "an index" } }
{ $description "Finds the index of the start of the last grapheme of the string. This can be used to traverse the graphemes of a string backwards." } ;
+HELP: first-grapheme-from
+{ $values { "start" "an index" } { "str" string } { "i" "an index" } }
+{ $description "Finds the length of the first grapheme of the string, starting from the given index. This can be used repeatedly to efficiently traverse the graphemes of the string, using slices." } ;
+
+HELP: last-grapheme-from
+{ $values { "end" "an index" } { "str" string } { "i" "an index" } }
+{ $description "Finds the index of the start of the last grapheme of the string, starting from the given index. This can be used to traverse the graphemes of a string backwards." } ;
+
HELP: >graphemes
{ $values { "str" string } { "graphemes" "an array of strings" } }
{ $description "Divides a string into a sequence of individual graphemes." } ;
HELP: first-word
{ $values { "str" string } { "i" "index" } }
-{ $description "Finds the length of the first word in the string." } ;
+{ $description "Finds the index of the end of the first word in the string." } ;
+
+HELP: last-word
+{ $values { "str" string } { "i" "index" } }
+{ $description "Finds the index of the beginning of the last word in the string." } ;
+
+HELP: first-word-from
+{ $values { "start" "index" } { "str" string } { "i" "index" } }
+{ $description "Finds the index of the end of the first word in the string, starting from the given index." } ;
+
+HELP: last-word-from
+{ $values { "end" "index" } { "str" string } { "i" "index" } }
+{ $description "Finds the index of the start of the word that the index is contained in." } ;
HELP: >words
{ $values { "str" string } { "words" "an array of strings" } }
[ 3 ] [ 2 "hello" first-grapheme-from ] unit-test
[ 1 ] [ 2 "hello" last-grapheme-from ] unit-test
+[ 4 ] [ 2 "what am I saying" first-word-from ] unit-test
+[ 0 ] [ 2 "what am I saying" last-word-from ] unit-test
+[ 16 ] [ 11 "what am I saying" first-word-from ] unit-test
+[ 10 ] [ 11 "what am I saying" last-word-from ] unit-test
+
: grapheme-break-test ( -- filename )
"vocab:unicode/breaks/GraphemeBreakTest.txt" ;
: connect ( class1 class2 -- ) 1 set-table ;
: disconnect ( class1 class2 -- ) 0 set-table ;
-: break-around ( classes1 classes2 -- )
- [ disconnect ] [ swap disconnect ] 2bi ;
-
: make-grapheme-table ( -- )
{ CR } { LF } connect
{ Control CR LF } graphemes disconnect
: grapheme-break? ( class1 class2 -- ? )
grapheme-table nth nth not ;
-: chars ( i str n -- str[i] str[i+n] )
- swap [ dupd + ] dip [ ?nth ] curry bi@ ;
-
PRIVATE>
: first-grapheme ( str -- i )
unclip-slice grapheme-class over
[ grapheme-class [ nip ] [ grapheme-break? ] 2bi ] find drop
- nip swap length or 1+ ;
+ nip swap length or 1 + ;
: first-grapheme-from ( start str -- i )
over tail-slice first-grapheme + ;
swap [ format/extended? not ] find-from drop ;
: walk-up ( str i -- j )
- dupd 1+ (walk-up) [ 1+ (walk-up) ] [ drop f ] if* ;
+ dupd 1 + (walk-up) [ 1 + (walk-up) ] [ drop f ] if* ;
: (walk-down) ( str i -- j )
swap [ format/extended? not ] find-last-from drop ;
: walk-down ( str i -- j )
- dupd (walk-down) [ 1- (walk-down) ] [ drop f ] if* ;
+ dupd (walk-down) [ 1 - (walk-down) ] [ drop f ] if* ;
: word-break? ( str i table-entry -- ? )
{
: first-word ( str -- i )
[ unclip-slice word-break-prop over <enum> ] keep
'[ swap _ word-break-next ] assoc-find 2drop
- nip swap length or 1+ ;
+ nip swap length or 1 + ;
: >words ( str -- words )
[ first-word ] >pieces ;
<PRIVATE
: nth-next ( i str -- str[i-1] str[i] )
- [ [ 1- ] keep ] dip '[ _ nth ] bi@ ;
+ [ [ 1 - ] keep ] dip '[ _ nth ] bi@ ;
PRIVATE>
word-break-next nip
]
} 2|| ;
+
+: first-word-from ( start str -- i )
+ over tail-slice first-word + ;
+
+: last-word ( str -- i )
+ [ length ] keep '[ _ word-break-at? ] find-last drop 0 or ;
+
+: last-word-from ( end str -- i )
+ swap head-slice last-word ;
:: assert= ( test spec quot -- )
spec [
[
- [ 1- test nth ] bi@
+ [ 1 - test nth ] bi@
[ 1quotation ] [ quot curry ] bi* unit-test
] with each
] assoc-each ;
! Normalization -- Composition
: initial-medial? ( str i -- ? )
- { [ swap nth initial? ] [ 1+ swap ?nth medial? ] } 2&& ;
+ { [ swap nth initial? ] [ 1 + swap ?nth medial? ] } 2&& ;
: --final? ( str i -- ? )
2 + swap ?nth final? ;
: compose-jamo ( str i -- str i )
2dup initial-medial? [
2dup --final? [ imf, ] [ im, ] if
- ] [ 2dup swap nth , 1+ ] if ;
+ ] [ 2dup swap nth , 1 + ] if ;
: pass-combining ( str -- str i )
dup [ non-starter? not ] find drop
: get-str ( state i -- ch )
swap [ i>> + ] [ str>> ] bi ?nth ; inline
: current ( state -- ch ) 0 get-str ; inline
-: to ( state -- state ) [ 1+ ] change-i ; inline
+: to ( state -- state ) [ 1 + ] change-i ; inline
: push-after ( ch state -- state ) [ ?push ] change-after ; inline
:: try-compose ( state new-char current-class -- state )
:: (compose) ( str i -- )
i str ?nth [
dup jamo? [ drop str i compose-jamo ] [
- i 1+ str ?nth combining-class
- [ str i 1+ compose-combining ] [ , str i 1+ ] if
+ i 1 + str ?nth combining-class
+ [ str i 1 + compose-combining ] [ , str i 1 + ] if
] if (compose)
] when* ; inline recursive
#! first group is -1337, legacy unix code
-1337 NGROUPS_MAX [ 4 * <byte-array> ] keep
<int> [ getgrouplist io-error ] 2keep
- [ 4 tail-slice ] [ *int 1- ] bi* >groups ;
+ [ 4 tail-slice ] [ *int 1 - ] bi* >groups ;
PRIVATE>
HEX: ff00 bitand -8 shift ; inline
: WIFSIGNALED ( status -- ? )
- HEX: 7f bitand 1+ -1 shift 0 > ; inline
+ HEX: 7f bitand 1 + -1 shift 0 > ; inline
: WCOREFLAG ( -- value )
HEX: 80 ; inline
-USING: alien.syntax ;
+USING: alien.syntax alien.c-types ;
IN: unix.types
TYPEDEF: long ssize_t
TYPEDEF: int pid_t
TYPEDEF: int time_t
+
+ALIAS: <time_t> <int>
-USING: alien.syntax ;
+USING: alien.syntax alien.c-types ;
IN: unix.types
TYPEDEF: ulonglong __uquad_type
TYPEDEF: ulonglong __fsfilcnt64_t
TYPEDEF: ulonglong ino64_t
TYPEDEF: ulonglong off64_t
+
+ALIAS: <time_t> <long>
\ No newline at end of file
-USING: alien.syntax ;
+USING: alien.syntax alien.c-types ;
IN: unix.types
! Darwin 9.1.0
TYPEDEF: long ssize_t
TYPEDEF: __int32_t pid_t
TYPEDEF: long time_t
+
+ALIAS: <time_t> <long>
\ No newline at end of file
-USING: alien.syntax combinators layouts vocabs.loader ;
+USING: alien.syntax alien.c-types combinators layouts vocabs.loader ;
IN: unix.types
! NetBSD 4.0
TYPEDEF: int pid_t
TYPEDEF: int time_t
+ALIAS: <time_t> <int>
+
cell-bits {
{ 32 [ "unix.types.netbsd.32" require ] }
{ 64 [ "unix.types.netbsd.64" require ] }
-USING: alien.syntax ;
+USING: alien.syntax alien.c-types ;
IN: unix.types
! OpenBSD 4.2
TYPEDEF: long ssize_t
TYPEDEF: int pid_t
TYPEDEF: int time_t
+
+ALIAS: <time_t> <int>
\ No newline at end of file
: <front-node> ( elt front -- node )
[
unroll-factor 0 <array>
- [ unroll-factor 1- swap set-nth ] keep f
+ [ unroll-factor 1 - swap set-nth ] keep f
] dip [ node boa dup ] keep
dup [ (>>prev) ] [ 2drop ] if ; inline
] [ dup front>> >>back ] if* drop ; inline
: push-front/new ( elt list -- )
- unroll-factor 1- >>front-pos
+ unroll-factor 1 - >>front-pos
[ <front-node> ] change-front
normalize-back ; inline
: push-front/existing ( elt list front -- )
- [ [ 1- ] change-front-pos ] dip
+ [ [ 1 - ] change-front-pos ] dip
[ front-pos>> ] [ data>> ] bi* set-nth-unsafe ; inline
M: unrolled-list push-front*
: pop-front/existing ( list front -- )
[ dup front-pos>> ] [ data>> ] bi* [ 0 ] 2dip set-nth-unsafe
- [ 1+ ] change-front-pos
+ [ 1 + ] change-front-pos
drop ; inline
M: unrolled-list pop-front*
dup front>> [ empty-unrolled-list ] unless*
- over front-pos>> unroll-factor 1- eq?
+ over front-pos>> unroll-factor 1 - eq?
[ pop-front/new ] [ pop-front/existing ] if ;
: <back-node> ( elt back -- node )
normalize-front ; inline
: push-back/existing ( elt list back -- )
- [ [ 1+ ] change-back-pos ] dip
- [ back-pos>> 1- ] [ data>> ] bi* set-nth-unsafe ; inline
+ [ [ 1 + ] change-back-pos ] dip
+ [ back-pos>> 1 - ] [ data>> ] bi* set-nth-unsafe ; inline
M: unrolled-list push-back*
dup [ back>> ] [ back-pos>> unroll-factor eq? not ] bi
M: unrolled-list peek-back
dup back>>
- [ [ back-pos>> 1- ] dip data>> nth-unsafe ]
+ [ [ back-pos>> 1 - ] dip data>> nth-unsafe ]
[ empty-unrolled-list ]
if* ;
dup back>> [ normalize-front ] [ f >>front drop ] if ; inline
: pop-back/existing ( list back -- )
- [ [ 1- ] change-back-pos ] dip
+ [ [ 1 - ] change-back-pos ] dip
[ dup back-pos>> ] [ data>> ] bi* [ 0 ] 2dip set-nth-unsafe
drop ; inline
"USING: io urls.encoding ;"
"{ { \"from\" \"Lead\" } { \"to\" \"Gold, please\" } }"
"assoc>query print"
- "from=Lead&to=Gold%2c%20please"
+ "from=Lead&to=Gold%2C%20please"
}
} ;
: push-utf8 ( ch -- )
1string utf8 encode
- [ CHAR: % , >hex 2 CHAR: 0 pad-head % ] each ;
+ [ CHAR: % , >hex >upper 2 CHAR: 0 pad-head % ] each ;
PRIVATE>
2dup length 2 - >= [
2drop
] [
- [ 1+ dup 2 + ] dip subseq hex> [ , ] when*
+ [ 1 + dup 2 + ] dip subseq hex> [ , ] when*
] if ;
: url-decode-% ( index str -- index str )
2dup nth dup CHAR: % = [
drop url-decode-% [ 3 + ] dip
] [
- , [ 1+ ] dip
+ , [ 1 + ] dip
] if url-decode-iter
] if ;
[ f ] [ foo ] unit-test\r
[ ] [ 3 to: foo ] unit-test\r
[ 3 ] [ foo ] unit-test\r
-[ ] [ \ foo [ 1+ ] change-value ] unit-test\r
+[ ] [ \ foo [ 1 + ] change-value ] unit-test\r
[ 4 ] [ foo ] unit-test\r
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: functors sequences sequences.private growable
+kernel words classes math parser ;
+IN: vectors.functor
+
+FUNCTOR: define-vector ( V A <A> -- )
+
+<V> DEFINES <${V}>
+>V DEFINES >${V}
+
+WHERE
+
+TUPLE: V { underlying A } { length array-capacity } ;
+
+: <V> ( capacity -- vector ) <A> 0 V boa ; inline
+
+M: V like
+ drop dup V instance? [
+ dup A instance? [ dup length V boa ] [ >V ] if
+ ] unless ; inline
+
+M: V new-sequence drop [ <A> ] [ >fixnum ] bi V boa ; inline
+
+M: A new-resizable drop <V> ; inline
+
+M: V equal? over V instance? [ sequence= ] [ 2drop f ] if ;
+
+: >V ( seq -- vector ) V new clone-like ; inline
+
+INSTANCE: V growable
+
+;FUNCTOR
M: vlist ppush
>vlist<
2dup length = [ unshare ] unless
- [ [ 1+ swap ] dip push ] keep vlist boa ;
+ [ [ 1 + swap ] dip push ] keep vlist boa ;
ERROR: empty-vlist-error ;
M: vlist ppop
[ empty-vlist-error ]
- [ [ length>> 1- ] [ vector>> ] bi vlist boa ] if-empty ;
+ [ [ length>> 1 - ] [ vector>> ] bi vlist boa ] if-empty ;
M: vlist clone
[ length>> ] [ vector>> >vector ] bi vlist boa ;
: valist-at ( key i array -- value ? )
over 0 >= [
3dup nth-unsafe = [
- [ 1+ ] dip nth-unsafe nip t
+ [ 1 + ] dip nth-unsafe nip t
] [
[ 2 - ] dip valist-at
] if
: reset-cache ( -- )
root-cache get-global clear-assoc
\ vocab-file-contents reset-memoized
- \ all-vocabs-seq reset-memoized
+ \ all-vocabs-recursive reset-memoized
\ all-authors reset-memoized
\ all-tags reset-memoized ;
"Loading vocabulary hierarchies:"\r
{ $subsection load }\r
{ $subsection load-all }\r
-"Getting all vocabularies on disk:"\r
+"Getting all vocabularies from disk:"\r
{ $subsection all-vocabs }\r
-{ $subsection all-vocabs-seq }\r
-"Getting " { $link "vocabs.metadata" } " for all vocabularies on disk:"\r
+{ $subsection all-vocabs-recursive }\r
+"Getting all vocabularies from disk whose names which match a string prefix:"\r
+{ $subsection child-vocabs }\r
+{ $subsection child-vocabs-recursive }\r
+"Words for modifying output:"\r
+{ $subsection no-roots }\r
+{ $subsection no-prefixes }\r
+"Getting " { $link "vocabs.metadata" } " for all vocabularies from disk:"\r
{ $subsection all-tags }\r
{ $subsection all-authors } ;\r
\r
ABOUT: "vocabs.hierarchy"\r
\r
-HELP: all-vocabs\r
-{ $values { "assoc" "an association list mapping vocabulary roots to sequences of vocabulary specifiers" } }\r
-{ $description "Outputs an association list of all vocabularies which have been loaded or are available for loading." } ;\r
-\r
HELP: load\r
{ $values { "prefix" string } }\r
{ $description "Load all vocabularies that match the provided prefix." }\r
HELP: load-all\r
{ $description "Load all vocabularies in the source tree." } ;\r
\r
-HELP: all-vocabs-under\r
-{ $values { "prefix" string } { "vocabs" "a sequence of vocabularies" } }\r
-{ $description "Return a sequence of vocab or vocab-links for each vocab matching the provided prefix. Unlike " { $link all-child-vocabs } " this word will return both loaded and unloaded vocabularies." } ;\r
! Copyright (C) 2007, 2009 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
-USING: arrays assocs combinators.short-circuit fry\r
+USING: accessors arrays assocs combinators.short-circuit fry\r
io.directories io.files io.files.info io.pathnames kernel make\r
memoize namespaces sequences sorting splitting vocabs sets\r
vocabs.loader vocabs.metadata vocabs.errors ;\r
+RENAME: child-vocabs vocabs => vocabs:child-vocabs\r
IN: vocabs.hierarchy\r
\r
+TUPLE: vocab-prefix name ;\r
+\r
+C: <vocab-prefix> vocab-prefix\r
+\r
+M: vocab-prefix vocab-name name>> ;\r
+\r
<PRIVATE\r
\r
: vocab-subdirs ( dir -- dirs )\r
] filter\r
] with-directory-files natural-sort ;\r
\r
-: (all-child-vocabs) ( root name -- vocabs )\r
- [\r
- vocab-dir append-path dup exists?\r
- [ vocab-subdirs ] [ drop { } ] if\r
- ] keep\r
- [ '[ [ _ "." ] dip 3append ] map ] unless-empty ;\r
-\r
: vocab-dir? ( root name -- ? )\r
over\r
[ ".factor" vocab-dir+ append-path exists? ]\r
[ 2drop f ]\r
if ;\r
\r
-: vocabs-in-dir ( root name -- )\r
- dupd (all-child-vocabs) [\r
- 2dup vocab-dir? [ dup >vocab-link , ] when\r
- vocabs-in-dir\r
- ] with each ;\r
+: (child-vocabs) ( root prefix -- vocabs )\r
+ [ vocab-dir append-path dup exists? [ vocab-subdirs ] [ drop { } ] if ]\r
+ [ nip [ '[ [ _ "." ] dip 3append ] map ] unless-empty ]\r
+ [ drop '[ _ over vocab-dir? [ >vocab-link ] [ <vocab-prefix> ] if ] map ]\r
+ 2tri ;\r
\r
-PRIVATE>\r
+: ((child-vocabs-recursive)) ( root name -- )\r
+ dupd vocab-name (child-vocabs)\r
+ [ dup , ((child-vocabs-recursive)) ] with each ;\r
\r
-: all-vocabs ( -- assoc )\r
- vocab-roots get [\r
- dup [ "" vocabs-in-dir ] { } make\r
- ] { } map>assoc ;\r
-\r
-: all-vocabs-under ( prefix -- vocabs )\r
- [\r
- [ vocab-roots get ] dip '[ _ vocabs-in-dir ] each\r
- ] { } make ;\r
+: (child-vocabs-recursive) ( root name -- seq )\r
+ [ ((child-vocabs-recursive)) ] { } make ;\r
\r
-MEMO: all-vocabs-seq ( -- seq )\r
- "" all-vocabs-under ;\r
+: no-rooted ( seq -- seq' ) [ find-vocab-root not ] filter ;\r
\r
-<PRIVATE\r
+: one-level-only? ( name prefix -- ? )\r
+ ?head [ "." split1 nip not ] dip and ;\r
\r
: unrooted-child-vocabs ( prefix -- seq )\r
+ [ vocabs no-rooted ] dip\r
dup empty? [ CHAR: . suffix ] unless\r
- vocabs\r
- [ find-vocab-root not ] filter\r
- [\r
- vocab-name swap ?head CHAR: . rot member? not and\r
- ] with filter\r
- [ vocab ] map ;\r
+ '[ vocab-name _ one-level-only? ] filter ;\r
+\r
+: unrooted-child-vocabs-recursive ( prefix -- seq )\r
+ vocabs:child-vocabs no-rooted ;\r
\r
PRIVATE>\r
\r
-: all-child-vocabs ( prefix -- assoc )\r
- vocab-roots get [\r
- dup pick (all-child-vocabs) [ >vocab-link ] map\r
- ] { } map>assoc\r
- swap unrooted-child-vocabs f swap 2array suffix ;\r
+: no-prefixes ( seq -- seq' ) [ vocab-prefix? not ] filter ;\r
\r
-: all-child-vocabs-seq ( prefix -- assoc )\r
- vocab-roots get swap '[\r
- dup _ (all-child-vocabs)\r
- [ vocab-dir? ] with filter\r
- ] map concat ;\r
+: convert-prefixes ( seq -- seq' )\r
+ [ dup vocab-prefix? [ name>> vocab-link boa ] when ] map ;\r
+\r
+: remove-redundant-prefixes ( seq -- seq' )\r
+ #! Hack.\r
+ [ vocab-prefix? ] partition\r
+ [\r
+ [ vocab-name ] map unique\r
+ '[ name>> _ key? not ] filter\r
+ convert-prefixes\r
+ ] keep\r
+ append ;\r
+\r
+: no-roots ( assoc -- seq ) values concat ;\r
+\r
+: child-vocabs ( prefix -- assoc )\r
+ [ [ vocab-roots get ] dip '[ dup _ (child-vocabs) ] { } map>assoc ]\r
+ [ unrooted-child-vocabs [ vocab ] map f swap 2array ]\r
+ bi suffix ;\r
+\r
+: all-vocabs ( -- assoc )\r
+ "" child-vocabs ;\r
+\r
+: child-vocabs-recursive ( prefix -- assoc )\r
+ [ [ vocab-roots get ] dip '[ dup _ (child-vocabs-recursive) ] { } map>assoc ]\r
+ [ unrooted-child-vocabs-recursive [ vocab ] map f swap 2array ]\r
+ bi suffix ;\r
+\r
+MEMO: all-vocabs-recursive ( -- assoc )\r
+ "" child-vocabs-recursive ;\r
+\r
+: all-vocab-names ( -- seq )\r
+ all-vocabs-recursive no-roots no-prefixes [ vocab-name ] map ;\r
+\r
+: child-vocab-names ( prefix -- seq )\r
+ child-vocabs no-roots no-prefixes [ vocab-name ] map ;\r
\r
<PRIVATE\r
\r
: filter-unportable ( seq -- seq' )\r
[ vocab-name unportable? not ] filter ;\r
\r
+: collect-vocabs ( quot -- seq )\r
+ [ all-vocabs-recursive no-roots no-prefixes ] dip\r
+ gather natural-sort ; inline\r
+\r
PRIVATE>\r
\r
: (load) ( prefix -- failures )\r
- all-vocabs-under\r
+ [ child-vocabs-recursive no-roots no-prefixes ]\r
+ [ dup find-vocab-root [ >vocab-link prefix ] [ drop ] if ] bi\r
filter-unportable\r
require-all ;\r
\r
: load-all ( -- )\r
"" load ;\r
\r
-MEMO: all-tags ( -- seq )\r
- all-vocabs-seq [ vocab-tags ] gather natural-sort ;\r
+MEMO: all-tags ( -- seq ) [ vocab-tags ] collect-vocabs ;\r
\r
-MEMO: all-authors ( -- seq )\r
- all-vocabs-seq [ vocab-authors ] gather natural-sort ;
\ No newline at end of file
+MEMO: all-authors ( -- seq ) [ vocab-authors ] collect-vocabs ;\r
<PRIVATE
: sort-vocabs ( seq -- seq' )
- [ [ vocab-name ] compare ] sort ;
+ [ vocab-name ] sort-with ;
: pprint-using ( seq -- )
[ "syntax" vocab = not ] filter
specialized-arrays.alien specialized-arrays.direct.alien ;
IN: windows.com.wrapper
-TUPLE: com-wrapper callbacks vtbls disposed ;
+TUPLE: com-wrapper < disposable callbacks vtbls ;
<PRIVATE
"windows.com.wrapper.callbacks" create-vocab drop
: (next-vtbl-counter) ( -- n )
- +vtbl-counter+ [ 1+ dup ] change ;
+ +vtbl-counter+ [ 1 + dup ] change ;
: com-unwrap ( wrapped -- object )
+wrapped-objects+ get-global at*
: (make-add-ref) ( interfaces -- quot )
length "void*" heap-size * '[
_
- [ alien-unsigned-4 1+ dup ]
+ [ alien-unsigned-4 1 + dup ]
[ set-alien-unsigned-4 ]
2bi
] ;
length "void*" heap-size * '[
_
[ drop ]
- [ alien-unsigned-4 1- dup ]
+ [ alien-unsigned-4 1 - dup ]
[ set-alien-unsigned-4 ]
2tri
dup 0 = [ swap (free-wrapped-object) ] [ nip ] if
"windows.com.wrapper.callbacks" create ;
: (finish-thunk) ( param-count thunk quot -- thunked-quot )
- [ [ drop [ ] ] [ swap 1- '[ _ _ ndip ] ] if-empty ]
+ [ [ drop [ ] ] [ swap 1 - '[ _ _ ndip ] ] if-empty ]
dip compose ;
: (make-interface-callbacks) ( interface-name quots iunknown-methods n -- words )
[ +live-wrappers+ get adjoin ] bi ;
: <com-wrapper> ( implementations -- wrapper )
- (make-callbacks) f f com-wrapper boa
+ com-wrapper new-disposable swap (make-callbacks) >>callbacks
dup allocate-wrapper ;
M: com-wrapper dispose*
: filenames-from-hdrop ( hdrop -- filenames )\r
dup HEX: FFFFFFFF f 0 DragQueryFile ! get count of files\r
[\r
- 2dup f 0 DragQueryFile 1+ ! get size of filename buffer\r
+ 2dup f 0 DragQueryFile 1 + ! get size of filename buffer\r
dup "WCHAR" <c-array>\r
[ swap DragQueryFile drop ] keep\r
alien>u16-string\r
GetLastError n>win32-error-string ;
: (win32-error) ( n -- )
- dup zero? [
- drop
- ] [
- win32-error-string throw
- ] if ;
+ [ win32-error-string throw ] unless-zero ;
: win32-error ( -- )
GetLastError (win32-error) ;
swap >>dim
swap >>bitmap
BGRX >>component-order
+ ubyte-components >>component-type
t >>upside-down? ;
: with-memory-dc ( quot: ( hDC -- ) -- )
:: make-bitmap-image ( dim dc quot -- image )
dim dc make-bitmap [ &DeleteObject drop ] dip
quot dip
- dim bitmap>image ; inline
\ No newline at end of file
+ dim bitmap>image ; inline
USING: alien alien.syntax alien.c-types alien.strings math
-kernel sequences windows.errors windows.types debugger io
+kernel sequences windows.errors windows.types io
accessors math.order namespaces make math.parser windows.kernel32
combinators locals specialized-arrays.direct.uchar ;
IN: windows.ole32
: succeeded? ( hresult -- ? )
0 HEX: 7FFFFFFF between? ;
-TUPLE: ole32-error error-code ;
-C: <ole32-error> ole32-error
+TUPLE: ole32-error code message ;
-M: ole32-error error.
- "COM method failed: " print error-code>> n>win32-error-string print ;
+: <ole32-error> ( code -- error )
+ dup n>win32-error-string \ ole32-error boa ;
: ole32-error ( hresult -- )
dup succeeded? [ drop ] [ <ole32-error> throw ] if ;
[ ]
} 2cleave
- GUID-Data4 8 <direct-uchar-array> {
+ GUID-Data4 {
[ 20 22 0 (guid-byte>guid) ]
[ 22 24 1 (guid-byte>guid) ]
[ [ GUID-Data3 ] 4 (guid-section%) "-" % ]
[ ]
} cleave
- GUID-Data4 8 <direct-uchar-array> {
+ GUID-Data4 {
[ 0 (guid-byte%) ]
[ 1 (guid-byte%) "-" % ]
[ 2 (guid-byte%) ]
windows.fonts opengl.textures locals windows.errors ;
IN: windows.uniscribe
-TUPLE: script-string font string metrics ssa size image disposed ;
+TUPLE: script-string < disposable font string metrics ssa size image ;
: line-offset>x ( n script-string -- x )
2dup string>> length = [
ssa>> ! ssa
- swap 1- ! icp
+ swap 1 - ! icp
TRUE ! fTrailing
] [
ssa>>
TEXTMETRIC>metrics ;
: <script-string> ( font string -- script-string )
- [ script-string new ] 2dip
+ [ script-string new-disposable ] 2dip
[ >>font ] [ >>string ] bi*
[
{
CONSTANT: SWP_DEFERERASE 8192
CONSTANT: SWP_ASYNCWINDOWPOS 16384
+CONSTANT: MF_ENABLED HEX: 0000
+CONSTANT: MF_GRAYED HEX: 0001
+CONSTANT: MF_DISABLED HEX: 0002
+CONSTANT: MF_STRING HEX: 0000
+CONSTANT: MF_BITMAP HEX: 0004
+CONSTANT: MF_UNCHECKED HEX: 0000
+CONSTANT: MF_CHECKED HEX: 0008
+CONSTANT: MF_POPUP HEX: 0010
+CONSTANT: MF_MENUBARBREAK HEX: 0020
+CONSTANT: MF_MENUBREAK HEX: 0040
+CONSTANT: MF_UNHILITE HEX: 0000
+CONSTANT: MF_HILITE HEX: 0080
+CONSTANT: MF_OWNERDRAW HEX: 0100
+CONSTANT: MF_USECHECKBITMAPS HEX: 0200
+CONSTANT: MF_BYCOMMAND HEX: 0000
+CONSTANT: MF_BYPOSITION HEX: 0400
+CONSTANT: MF_SEPARATOR HEX: 0800
+CONSTANT: MF_DEFAULT HEX: 1000
+CONSTANT: MF_SYSMENU HEX: 2000
+CONSTANT: MF_HELP HEX: 4000
+CONSTANT: MF_RIGHTJUSTIFY HEX: 4000
+CONSTANT: MF_MOUSESELECT HEX: 8000
LIBRARY: user32
! FUNCTION: DrawTextW
! FUNCTION: EditWndProc
FUNCTION: BOOL EmptyClipboard ( ) ;
-! FUNCTION: EnableMenuItem
+FUNCTION: BOOL EnableMenuItem ( HMENU hMenu, UINT uIDEnableItem, UINT uEnable ) ;
! FUNCTION: EnableScrollBar
! FUNCTION: EnableWindow
! FUNCTION: EndDeferWindowPos
! FUNCTION: GetSubMenu
! FUNCTION: GetSysColor
FUNCTION: HBRUSH GetSysColorBrush ( int nIndex ) ;
-! FUNCTION: GetSystemMenu
+FUNCTION: HMENU GetSystemMenu ( HWND hWnd, BOOL bRevert ) ;
! FUNCTION: GetSystemMetrics
! FUNCTION: GetTabbedTextExtentA
! FUNCTION: GetTabbedTextExtentW
[ "aaa bb\nccccccc\nddddddd" ] [ "aaa bb ccccccc ddddddd" 6 wrap-string ] unit-test
[ "a b c d e f\ng h" ] [ "a b c d e f g h" 11 wrap-string ] unit-test
+
+[ "" ] [ "" 10 wrap-string ] unit-test
+[ "Hello" ] [ "\nHello\n" 10 wrap-string ] unit-test
--- /dev/null
+! Copyright (C) 2009 Daniel Ehrenberg
+! See http://factorcode.org/license.txt for BSD license.
+USING: wrap tools.test ;
+
+[ { } ] [ { } 10 10 wrap ] unit-test
[
line-ideal set
line-max set
- initialize
- [ wrap-step ] reduce
- min-cost
- post-process
+ [ { } ] [
+ initialize
+ [ wrap-step ] reduce
+ min-cost
+ post-process
+ ] if-empty
] with-scope ;
{ "XImage-funcs" "f" } ;
X-FUNCTION: XImage* XGetImage ( Display* display, Drawable d, int x, int y, uint width, uint height, ulong plane_mask, int format ) ;
-X-FUNCTION: int XDestroyImage ( XImage *ximage ) ;
+X-FUNCTION: int XDestroyImage ( XImage* ximage ) ;
: XImage-size ( ximage -- size )
[ XImage-height ] [ XImage-bytes_per_line ] bi * ;
: number<-> ( doc -- dup )
0 over [
dup var>> [
- over >>var [ 1+ ] dip
+ over >>var [ 1 + ] dip
] unless drop
] each-interpolated drop ;
[ T{ xml-chunk f V{ "hello" } } ] [ "hello" string>xml-chunk ] unit-test
[ "1.1" ] [ "<?xml version='1.1'?><x/>" string>xml prolog>> version>> ] unit-test
[ "ß" ] [ "<x>ß</x>" <string-reader> read-xml children>string ] unit-test
+
+! <pull-xml> tests
+! this tests just checks that pull-event doesn't raise an exception
+[ ] [ "vocab:xml/tests/test.xml" binary [ <pull-xml> pull-event drop ] with-file-reader ] unit-test
\ No newline at end of file
swap
[ version-1.0?>> over text? not ]
[ check>> ] bi and [
- spot get [ 1+ ] change-column drop
+ spot get [ 1 + ] change-column drop
disallowed-char
] [ drop ] if
] [ drop ] if* ;
: record ( spot char -- spot )
over char>> [
CHAR: \n =
- [ [ 1+ ] change-line -1 ] [ dup column>> 1+ ] if
+ [ [ 1 + ] change-line -1 ] [ dup column>> 1 + ] if
>>column
] [ drop ] if ;
: take-string ( match -- string )
dup length <circular-string>
spot get '[ 2dup _ string-matches? ] take-until nip
- dup length rot length 1- - head
+ dup length rot length 1 - - head
get-char [ missing-close ] unless next ;
: expect ( string -- )
TUPLE: pull-xml scope ;
: <pull-xml> ( -- pull-xml )
[
+ init-parser
input-stream [ ] change ! bring var in this scope
init-xml text-now? on
] H{ } make-assoc
drop
seen-whitespace-end? get [
- position get 1+ whitespace-end set
+ position get 1 + whitespace-end set
] unless
(check-word-break)
: next-token, ( len id -- )
[ position get 2dup + ] dip token,
- position get + dup 1- position set last-offset set ;
+ position get + dup 1 - position set last-offset set ;
: push-context ( rules -- )
context [ <line-context> ] change ;
}
refresh_image() {
- ./$FACTOR_BINARY -script -e="USE: vocabs.loader USE: system refresh-all USE: memory save 0 exit"
+ ./$FACTOR_BINARY -script -e="USING: vocabs.loader system memory ; refresh-all USE: memory save 0 exit"
check_ret factor
}
make_boot_image() {
- ./$FACTOR_BINARY -script -e="\"$MAKE_IMAGE_TARGET\" USE: system USE: bootstrap.image make-image save 0 exit"
+ ./$FACTOR_BINARY -script -e="\"$MAKE_IMAGE_TARGET\" USING: system bootstrap.image memory ; make-image save 0 exit"
check_ret factor
}
[ "( displaced alien )" ] [ 0 B{ 1 2 3 } <displaced-alien> unparse ] unit-test
-[ f ] [ DLL" fadfasdfsada" dll-valid? ] unit-test
-
-[ f ] [ "does not exist" DLL" fadsfasfdsaf" dlsym ] unit-test
-
SYMBOL: initialize-test
f initialize-test set-global
GENERIC: >c-ptr ( obj -- c-ptr )
-M: c-ptr >c-ptr ;
+M: c-ptr >c-ptr ; inline
SLOT: underlying
-M: object >c-ptr underlying>> ;
+M: object >c-ptr underlying>> ; inline
GENERIC: expired? ( c-ptr -- ? ) flushable
[ <memory-stream> ] [ <decoder> ] bi*
"\0" swap stream-read-until drop ;
+M: object alien>string
+ [ underlying>> ] dip alien>string ;
+
M: f alien>string
drop ;
sequences sequences.private ;
IN: arrays
-M: array clone (clone) ;
-M: array length length>> ;
-M: array nth-unsafe [ >fixnum ] dip array-nth ;
-M: array set-nth-unsafe [ >fixnum ] dip set-array-nth ;
-M: array resize resize-array ;
+M: array clone (clone) ; inline
+M: array length length>> ; inline
+M: array nth-unsafe [ >fixnum ] dip array-nth ; inline
+M: array set-nth-unsafe [ >fixnum ] dip set-array-nth ; inline
+M: array resize resize-array ; inline
: >array ( seq -- array ) { } clone-like ;
-M: object new-sequence drop 0 <array> ;
+M: object new-sequence drop 0 <array> ; inline
-M: f new-sequence drop dup zero? [ drop f ] [ 0 <array> ] if ;
+M: f new-sequence drop [ f ] [ 0 <array> ] if-zero ; inline
M: array equal?
over array? [ sequence= ] [ 2drop f ] if ;
-IN: assocs.tests
USING: kernel math namespaces make tools.test vectors sequences
sequences.private hashtables io prettyprint assocs
continuations specialized-arrays.double ;
+IN: assocs.tests
[ t ] [ H{ } dup assoc-subset? ] unit-test
[ f ] [ H{ { 1 3 } } H{ } assoc-subset? ] unit-test
[ f ] [ 1 2 H{ { 2 1 } } maybe-set-at ] unit-test
[ t ] [ 1 3 H{ { 2 1 } } clone maybe-set-at ] unit-test
[ t ] [ 3 2 H{ { 2 1 } } clone maybe-set-at ] unit-test
+
+[ H{ { 1 2 } { 2 3 } } ] [
+ {
+ H{ { 1 3 } }
+ H{ { 2 3 } }
+ H{ { 1 2 } }
+ } assoc-combine
+] unit-test
+
+[ H{ { 1 7 } } ] [
+ {
+ H{ { 1 2 } { 2 4 } { 5 6 } }
+ H{ { 1 3 } { 2 5 } }
+ H{ { 1 7 } { 5 6 } }
+ } assoc-refine
+] unit-test
GENERIC: assoc-clone-like ( assoc exemplar -- newassoc )
GENERIC: >alist ( assoc -- newassoc )
-M: assoc assoc-like drop ;
+M: assoc assoc-like drop ; inline
: ?at ( key assoc -- value/key ? )
2dup at* [ 2nip t ] [ 2drop f ] if ; inline
M: assoc assoc-clone-like ( assoc exemplar -- newassoc )
[ dup assoc-size ] dip new-assoc
- [ [ set-at ] with-assoc assoc-each ] keep ;
+ [ [ set-at ] with-assoc assoc-each ] keep ; inline
: keys ( assoc -- keys )
[ drop ] { } assoc>map ;
: assoc-combine ( seq -- union )
H{ } clone [ dupd update ] reduce ;
+: assoc-refine ( seq -- assoc )
+ [ f ] [ [ ] [ assoc-intersect ] map-reduce ] if-empty ;
+
: assoc-diff ( assoc1 assoc2 -- diff )
[ nip key? not ] curry assoc-filter ;
[ 2nip set-second ]
[ drop [ swap 2array ] dip push ] if ;
-M: sequence new-assoc drop <vector> ;
+M: sequence new-assoc drop <vector> ; inline
-M: sequence clear-assoc delete-all ;
+M: sequence clear-assoc delete-all ; inline
M: sequence delete-at
[ nip ] [ search-alist nip ] 2bi
[ swap delete-nth ] [ drop ] if* ;
-M: sequence assoc-size length ;
+M: sequence assoc-size length ; inline
M: sequence assoc-clone-like
- [ >alist ] dip clone-like ;
+ [ >alist ] dip clone-like ; inline
M: sequence assoc-like
- [ >alist ] dip like ;
+ [ >alist ] dip like ; inline
-M: sequence >alist ;
+M: sequence >alist ; inline
! Override sequence => assoc instance for f
-M: f clear-assoc drop ;
+M: f clear-assoc drop ; inline
-M: f assoc-like drop dup assoc-empty? [ drop f ] when ;
+M: f assoc-like drop dup assoc-empty? [ drop f ] when ; inline
INSTANCE: sequence assoc
-TUPLE: enum seq ;
+TUPLE: enum { seq read-only } ;
C: <enum> enum
M: enum at*
seq>> 2dup bounds-check?
- [ nth t ] [ 2drop f f ] if ;
+ [ nth t ] [ 2drop f f ] if ; inline
-M: enum set-at seq>> set-nth ;
+M: enum set-at seq>> set-nth ; inline
-M: enum delete-at seq>> delete-nth ;
+M: enum delete-at seq>> delete-nth ; inline
M: enum >alist ( enum -- alist )
- seq>> [ length ] keep zip ;
+ seq>> [ length ] keep zip ; inline
-M: enum assoc-size seq>> length ;
+M: enum assoc-size seq>> length ; inline
-M: enum clear-assoc seq>> delete-all ;
+M: enum clear-assoc seq>> delete-all ; inline
INSTANCE: enum assoc
{ "set-retainstack" "kernel" (( rs -- )) }
{ "set-callstack" "kernel" (( cs -- )) }
{ "exit" "system" (( n -- )) }
- { "data-room" "memory" (( -- cards generations )) }
- { "code-room" "memory" (( -- code-free code-total )) }
+ { "data-room" "memory" (( -- cards decks generations )) }
+ { "code-room" "memory" (( -- code-total code-used code-free largest-free-block )) }
{ "micros" "system" (( -- us )) }
{ "modify-code-heap" "compiler.units" (( alist -- )) }
{ "(dlopen)" "alien.libraries" (( path -- dll )) }
"M\\"
"]"
"delimiter"
+ "deprecated"
"f"
"flushable"
"foldable"
+USING: tools.test byte-arrays sequences kernel math ;\r
IN: byte-arrays.tests\r
-USING: tools.test byte-arrays sequences kernel ;\r
\r
[ 6 B{ 1 2 3 } ] [\r
6 B{ 1 2 3 } resize-byte-array\r
\r
[ -10 B{ } resize-byte-array ] must-fail\r
\r
-[ B{ 123 } ] [ 123 1byte-array ] unit-test
\ No newline at end of file
+[ B{ 123 } ] [ 123 1byte-array ] unit-test\r
+\r
+[ B{ 123 } ] [ 123 0 B{ 0 } [ set-nth ] keep ] unit-test\r
+\r
+[ B{ 123 } ] [ 123 >bignum 0 B{ 0 } [ set-nth ] keep ] unit-test
\ No newline at end of file
sequences.private math ;
IN: byte-arrays
-M: byte-array clone (clone) ;
-M: byte-array length length>> ;
-M: byte-array nth-unsafe swap >fixnum alien-unsigned-1 ;
-M: byte-array set-nth-unsafe swap >fixnum set-alien-unsigned-1 ;
+M: byte-array clone (clone) ; inline
+M: byte-array length length>> ; inline
+M: byte-array nth-unsafe swap >fixnum alien-unsigned-1 ; inline
+M: byte-array set-nth-unsafe swap >fixnum set-alien-unsigned-1 ; inline
: >byte-array ( seq -- byte-array ) B{ } clone-like ; inline
-M: byte-array new-sequence drop (byte-array) ;
+M: byte-array new-sequence drop (byte-array) ; inline
M: byte-array equal?
over byte-array? [ sequence= ] [ 2drop f ] if ;
M: byte-array resize
- resize-byte-array ;
+ resize-byte-array ; inline
INSTANCE: byte-array sequence
-IN: byte-vectors.tests\r
USING: tools.test byte-vectors vectors sequences kernel\r
prettyprint ;\r
+IN: byte-vectors.tests\r
\r
[ 0 ] [ 123 <byte-vector> length ] unit-test\r
\r
drop dup byte-vector? [\r
dup byte-array?\r
[ dup length byte-vector boa ] [ >byte-vector ] if\r
- ] unless ;\r
+ ] unless ; inline\r
\r
M: byte-vector new-sequence\r
- drop [ (byte-array) ] [ >fixnum ] bi byte-vector boa ;\r
+ drop [ (byte-array) ] [ >fixnum ] bi byte-vector boa ; inline\r
\r
M: byte-vector equal?\r
over byte-vector? [ sequence= ] [ 2drop f ] if ;\r
\r
+M: byte-vector contract 2drop ; inline\r
+\r
M: byte-array like\r
#! If we have an byte-array, we're done.\r
#! If we have a byte-vector, and it's at full capacity,\r
2dup length eq?\r
[ nip ] [ resize-byte-array ] if\r
] [ >byte-array ] if\r
- ] unless ;\r
+ ] unless ; inline\r
\r
-M: byte-array new-resizable drop <byte-vector> ;\r
+M: byte-array new-resizable drop <byte-vector> ; inline\r
\r
INSTANCE: byte-vector growable\r
+++ /dev/null
-IN: checksums.tests
-USING: checksums tools.test ;
-
[ B{ CHAR: \n } join ] dip checksum-bytes ;
: checksum-file ( path checksum -- value )
- #! normalize-path (file-reader) is equivalen to
+ #! normalize-path (file-reader) is equivalent to
#! binary <file-reader>. We use the lower-level form
#! so that we can move io.encodings.binary to basis/.
[ normalize-path (file-reader) ] dip checksum-stream ;
{ $subsection classes-intersect? }\r
{ $subsection min-class }\r
"Low-level implementation detail:"\r
-{ $subsection class-types }\r
{ $subsection flatten-class }\r
{ $subsection flatten-builtin-class }\r
{ $subsection class-types }\r
\r
PREDICATE: empty-intersection < anonymous-intersection participants>> empty? ;\r
\r
-: (class<=) ( first second -- -1/0/1 )\r
+: (class<=) ( first second -- ? )\r
2dup eq? [ 2drop t ] [\r
2dup superclass<= [ 2drop t ] [\r
[ normalize-class ] bi@ {\r
: class= ( first second -- ? )\r
[ class<= ] [ swap class<= ] 2bi and ;\r
\r
+ERROR: topological-sort-failed ;\r
+\r
: largest-class ( seq -- n elt )\r
dup [ [ class< ] with any? not ] curry find-last\r
- [ "Topological sort failed" throw ] unless* ;\r
+ [ topological-sort-failed ] unless* ;\r
\r
: sort-classes ( seq -- newseq )\r
- [ [ name>> ] compare ] sort >vector\r
+ [ name>> ] sort-with >vector\r
[ dup empty? not ]\r
[ dup largest-class [ over delete-nth ] dip ]\r
produce nip ;\r
-IN: classes.builtin.tests
USING: tools.test words sequences kernel memory accessors ;
+IN: classes.builtin.tests
[ f ] [
[ word? ] instances
: bootstrap-type>class ( n -- class ) builtins get nth ;
-M: hi-tag class hi-tag type>class ;
+M: hi-tag class hi-tag type>class ; inline
-M: object class tag type>class ;
+M: object class tag type>class ; inline
M: builtin-class rank-class drop 0 ;
[ swap classes-intersect? ]
} cond ;
-M: anonymous-intersection (flatten-class)
- participants>> [ flatten-builtin-class ] map
- [
- builtins get sift [ (flatten-class) ] each
- ] [
- [ ] [ assoc-intersect ] map-reduce [ swap set ] assoc-each
- ] if-empty ;
+: full-cover ( -- ) builtins get sift [ (flatten-class) ] each ;
-M: anonymous-complement (flatten-class)
- drop builtins get sift [ (flatten-class) ] each ;
+M: anonymous-complement (flatten-class) drop full-cover ;
"You can ask a class for its superclass:"
{ $subsection superclass }
{ $subsection superclasses }
+{ $subsection subclass-of? }
"Class predicates can be used to test instances directly:"
{ $subsection "class-predicates" }
"There is a universal class which all objects are an instance of, and an empty class with no instances:"
}
} ;
-{ superclass superclasses } related-words
+HELP: subclass-of?
+{ $values
+ { "class" class }
+ { "superclass" class }
+ { "?" boolean }
+}
+{ $description "Outputs a boolean value indicating whether " { $snippet "class" } " is at any level a subclass of " { $snippet "superclass" } "." }
+{ $examples
+ { $example "USING: classes classes.tuple prettyprint words ;"
+ "tuple-class \\ class subclass-of? ."
+ "t"
+ }
+} ;
+
+{ superclass superclasses subclass-of? } related-words
HELP: members
{ $values { "class" class } { "seq" "a sequence of union members, or " { $link f } } }
"class-intersect-no-method-c" parse-stream drop
] unit-test
+! Forget the above crap
+[
+ { "classes.test.a" "classes.test.b" "classes.test.c" "classes.test.d" }
+ [ forget-vocab ] each
+] with-compilation-unit
+
TUPLE: forgotten-predicate-test ;
[ ] [ [ \ forgotten-predicate-test forget ] with-compilation-unit ] unit-test
: superclasses ( class -- supers )
[ superclass ] follow reverse ;
+: subclass-of? ( class superclass -- ? )
+ swap superclasses member? ;
+
: members ( class -- seq )
#! Output f for non-classes to work with algebra code
dup class? [ "members" word-prop ] [ drop f ] if ;
--- /dev/null
+USING: kernel tools.test generic generic.standard ;
+IN: classes.intersection.tests
+
+TUPLE: a ;
+TUPLE: a1 < a ; TUPLE: a2 < a ; TUPLE: a3 < a2 ;
+MIXIN: b
+INSTANCE: a3 b
+INSTANCE: a1 b
+INTERSECTION: c a2 b ;
+
+GENERIC: x ( a -- b )
+
+M: c x drop c ;
+M: a x drop a ;
+
+[ a ] [ T{ a } x ] unit-test
+[ a ] [ T{ a1 } x ] unit-test
+[ a ] [ T{ a2 } x ] unit-test
+
+[ t ] [ T{ a3 } c? ] unit-test
+[ t ] [ T{ a3 } \ x effective-method M\ c x eq? nip ] unit-test
+[ c ] [ T{ a3 } x ] unit-test
+
+! More complex case
+TUPLE: t1 ;
+TUPLE: t2 < t1 ; TUPLE: t3 < t1 ;
+TUPLE: t4 < t2 ; TUPLE: t5 < t2 ;
+
+UNION: m t4 t5 t3 ;
+INTERSECTION: i t2 m ;
+
+GENERIC: g ( a -- b )
+
+M: i g drop i ;
+M: t4 g drop t4 ;
+
+[ t4 ] [ T{ t4 } g ] unit-test
+[ i ] [ T{ t5 } g ] unit-test
\ No newline at end of file
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: words sequences kernel assocs combinators classes
+USING: words accessors sequences kernel assocs combinators classes
classes.algebra classes.builtin namespaces arrays math quotations ;
IN: classes.intersection
M: intersection-class (flatten-class)
participants <anonymous-intersection> (flatten-class) ;
+
+! Horribly inefficient and inaccurate
+: intersect-flattened-classes ( seq1 seq2 -- seq3 )
+ ! Only keep those in seq1 that intersect something in seq2.
+ [ [ classes-intersect? ] with any? ] curry filter ;
+
+M: anonymous-intersection (flatten-class)
+ participants>> [ full-cover ] [
+ [ flatten-class keys ]
+ [ intersect-flattened-classes ] map-reduce
+ [ dup set ] each
+ ] if-empty ;
PREDICATE: tuple-c < tuple-b slot>> ;
-GENERIC: ptest ( tuple -- )
-M: tuple-a ptest drop ;
-M: tuple-c ptest drop ;
+GENERIC: ptest ( tuple -- x )
+M: tuple-a ptest drop tuple-a ;
+M: tuple-c ptest drop tuple-c ;
-[ ] [ tuple-b new ptest ] unit-test
+[ tuple-a ] [ tuple-b new ptest ] unit-test
+[ tuple-c ] [ tuple-b new t >>slot ptest ] unit-test
+
+PREDICATE: tuple-d < tuple-a slot>> ;
+
+GENERIC: ptest' ( tuple -- x )
+M: tuple-a ptest' drop tuple-a ;
+M: tuple-d ptest' drop tuple-d ;
+
+[ tuple-a ] [ tuple-b new ptest' ] unit-test
+[ tuple-d ] [ tuple-b new t >>slot ptest' ] unit-test
PREDICATE: predicate-class < class
"metaclass" word-prop predicate-class eq? ;
-: predicate-quot ( class -- quot )
+GENERIC: predicate-quot ( class -- quot )
+
+M: predicate-class predicate-quot
[
\ dup ,
[ superclass "predicate" word-prop % ]
-! Copyright (C) 2008 Doug Coleman.
+! Copyright (C) 2008, 2009 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: classes classes.algebra classes.predicate kernel
sequences words ;
IN: classes.singleton
+: singleton-predicate-quot ( class -- quot ) [ eq? ] curry ;
+
PREDICATE: singleton-class < predicate-class
[ "predicate-definition" word-prop ]
- [ [ eq? ] curry ] bi sequence= ;
+ [ singleton-predicate-quot ]
+ bi sequence= ;
: define-singleton-class ( word -- )
- \ word over [ eq? ] curry define-predicate-class ;
+ \ word over singleton-predicate-quot define-predicate-class ;
M: singleton-class instance? eq? ;
M: singleton-class (classes-intersect?)
over singleton-class? [ eq? ] [ call-next-method ] if ;
+
+M: singleton-class predicate-quot
+ singleton-predicate-quot ;
\ No newline at end of file
-IN: classes.tuple.parser.tests
USING: accessors classes.tuple.parser lexer words classes
sequences math kernel slots tools.test parser compiler.units
-arrays classes.tuple eval ;
+arrays classes.tuple eval multiline ;
+IN: classes.tuple.parser.tests
TUPLE: test-1 ;
: parse-long-slot-name ( -- spec )
[ scan , \ } parse-until % ] { } make ;
-: parse-slot-name ( string/f -- ? )
+: parse-slot-name-delim ( end-delim string/f -- ? )
#! This isn't meant to enforce any kind of policy, just
#! to check for mistakes of this form:
#!
{
{ [ dup not ] [ unexpected-eof ] }
{ [ dup { ":" "(" "<" "\"" "!" } member? ] [ invalid-slot-name ] }
- { [ dup ";" = ] [ drop f ] }
+ { [ 2dup = ] [ drop f ] }
[ dup "{" = [ drop parse-long-slot-name ] when , t ]
- } cond ;
+ } cond nip ;
+
+: parse-tuple-slots-delim ( end-delim -- )
+ dup scan parse-slot-name-delim [ parse-tuple-slots-delim ] [ drop ] if ;
+
+: parse-slot-name ( string/f -- ? )
+ ";" swap parse-slot-name-delim ;
: parse-tuple-slots ( -- )
- scan parse-slot-name [ parse-tuple-slots ] when ;
+ ";" parse-tuple-slots-delim ;
: parse-tuple-definition ( -- class superclass slots )
CREATE-CLASS
: parse-slot-values ( -- values )
[ (parse-slot-values) ] { } make ;
-: boa>tuple ( class slots -- tuple )
+GENERIC# boa>object 1 ( class slots -- tuple )
+
+M: tuple-class boa>object
swap prefix >tuple ;
-: assoc>tuple ( class slots -- tuple )
- [ [ ] [ initial-values ] [ all-slots ] tri ] dip
- swap [ [ slot-named offset>> 2 - ] curry dip ] curry assoc-map
- [ dup <enum> ] dip update boa>tuple ;
+: assoc>object ( class slots values -- tuple )
+ [ [ [ initial>> ] map ] keep ] dip
+ swap [ [ slot-named* drop ] curry dip ] curry assoc-map
+ [ dup <enum> ] dip update boa>object ;
-: parse-tuple-literal-slots ( class -- tuple )
+: parse-tuple-literal-slots ( class slots -- tuple )
scan {
{ f [ unexpected-eof ] }
- { "f" [ \ } parse-until boa>tuple ] }
- { "{" [ parse-slot-values assoc>tuple ] }
- { "}" [ new ] }
+ { "f" [ drop \ } parse-until boa>object ] }
+ { "{" [ parse-slot-values assoc>object ] }
+ { "}" [ drop new ] }
[ bad-literal-tuple ]
} case ;
: parse-tuple-literal ( -- tuple )
- scan-word parse-tuple-literal-slots ;
+ scan-word dup all-slots parse-tuple-literal-slots ;
{ $subsection POSTPONE: SLOT: }
"Protocol slots are used where the implementation of a superclass needs to assume that each subclass defines certain slots, however the slots of each subclass are potentially declared with different class specializers, thus preventing the slots from being defined in the superclass."
$nl
-"For example, the " { $link growable } " mixin provides an implementation of the sequence protocol which wraps an underlying sequence, resizing it as necessary when elements are added beyond the length of the sequence. It assumes that the concrete mixin instances define two slots, " { $snippet "length" } " and " { $snippet "underlying" } ". These slots are defined as protocol slots:"
-{ $snippet "SLOT: length" "SLOT: underlying" }
+"For example, the " { $link growable } " mixin provides an implementation of the sequence protocol which wraps an underlying sequence, resizing it as necessary when elements are added beyond the length of the sequence. It assumes that the concrete mixin instances define two slots, " { $snippet "length" } " and " { $snippet "underlying" } ". These slots are defined as protocol slots: " { $snippet "SLOT: length" } " and " { $snippet "SLOT: underlying" } ". "
"An alternate approach would be to define " { $link growable } " as a tuple class with these two slots, and have other classes subclass it as required. However, this rules out subclasses defining these slots with custom type declarations."
$nl
"For example, compare the definitions of the " { $link sbuf } " class,"
{ $list
{ { $snippet "\"predicate\"" } " - a quotation which tests if the top of the stack is an instance of this tuple class" }
{ { $snippet "\"slots\"" } " - a sequence of " { $link slot-spec } " instances" }
- { { $snippet "\"tuple-layout\"" } " - an array with the tuple size and superclasses encoded in a format amneable to fast method dispatch" }
+ { { $snippet "\"layout\"" } " - an array with the tuple size and superclasses encoded in a format amneable to fast method dispatch" }
} } ;
HELP: define-tuple-predicate
-USING: definitions generic kernel kernel.private math math.constants
-parser sequences tools.test words assocs namespaces quotations
-sequences.private classes continuations generic.single
-generic.standard effects classes.tuple classes.tuple.private arrays
-vectors strings compiler.units accessors classes.algebra calendar
-prettyprint io.streams.string splitting summary columns math.order
-classes.private slots slots.private eval see words.symbol
-compiler.errors parser.notes ;
+USING: accessors arrays assocs calendar classes classes.algebra
+classes.private classes.tuple classes.tuple.private columns
+compiler.errors compiler.units continuations definitions
+effects eval generic generic.single generic.standard grouping
+io.streams.string kernel kernel.private math math.constants
+math.order namespaces parser parser.notes prettyprint
+quotations random see sequences sequences.private slots
+slots.private splitting strings summary threads tools.test
+vectors vocabs words words.symbol ;
IN: classes.tuple.tests
TUPLE: rect x y w h ;
[ t ] [ 3 redefinition-problem'? ] unit-test
! Hardcore unit tests
-USE: threads
\ thread "slots" word-prop "slots" set
] with-compilation-unit
] unit-test
-USE: vocabs
-
\ vocab "slots" word-prop "slots" set
[ ] [
: layout-of ( tuple -- layout )
1 slot { array } declare ; inline
-M: tuple class layout-of 2 slot { word } declare ;
+M: tuple class layout-of 2 slot { word } declare ; inline
: tuple-size ( tuple -- size )
- layout-of second ; inline
+ layout-of 3 slot { fixnum } declare ; inline
: prepare-tuple>array ( tuple -- n tuple layout )
- check-tuple [ tuple-size ] [ ] [ layout-of ] tri ;
+ check-tuple [ tuple-size iota ] [ ] [ layout-of ] tri ;
: copy-tuple-slots ( n tuple -- array )
[ array-nth ] curry map ;
GENERIC: slots>tuple ( seq class -- tuple )
-M: tuple-class slots>tuple
+M: tuple-class slots>tuple ( seq class -- tuple )
check-slots pad-slots
tuple-layout <tuple> [
- [ tuple-size ]
+ [ tuple-size iota ]
[ [ set-array-nth ] curry ]
bi 2each
] keep ;
dup boa-check-quot "boa-check" set-word-prop ;
: tuple-prototype ( class -- prototype )
- [ initial-values ] keep
- over [ ] any? [ slots>tuple ] [ 2drop f ] if ;
+ [ initial-values ] keep over [ ] any?
+ [ slots>tuple ] [ 2drop f ] if ;
: define-tuple-prototype ( class -- )
dup tuple-prototype "prototype" set-word-prop ;
[ swap classes-intersect? ]
} cond ;
-M: tuple clone (clone) ;
+M: tuple clone (clone) ; inline
M: tuple equal? over tuple? [ tuple= ] [ 2drop f ] if ;
M: tuple hashcode* tuple-hashcode ;
M: tuple-class new
- dup "prototype" word-prop
- [ (clone) ] [ tuple-layout <tuple> ] ?if ;
+ dup "prototype" word-prop [ (clone) ] [ tuple-layout <tuple> ] ?if ;
M: tuple-class boa
[ "boa-check" word-prop [ call ] when* ]
{ bi* tri* spread } related-words
+HELP: to-fixed-point
+{ $values { "object" object } { "quot" { $quotation "( object(n) -- object(n+1) )" } } { "object(n)" object } }
+{ $description "Applies the quotation repeatedly with " { $snippet "object" } " as the initial input until the output of the quotation equals the input." }
+{ $examples
+ { $example
+ "USING: combinators kernel math prettyprint sequences ;"
+ "IN: scratchpad"
+ ": flatten ( sequence -- sequence' )"
+ " \"flatten\" over index"
+ " [ [ 1 + swap nth ] [ nip dup 2 + ] [ drop ] 2tri replace-slice ] when* ;"
+ ""
+ "{ \"flatten\" { 1 { 2 3 } \"flatten\" { 4 5 } { 6 } } } [ flatten ] to-fixed-point ."
+ "{ 1 { 2 3 } 4 5 { 6 } }"
+ }
+} ;
+
HELP: alist>quot
{ $values { "default" "a quotation" } { "assoc" "a sequence of quotation pairs" } { "quot" "a new quotation" } }
{ $description "Constructs a quotation which calls the first quotation in each pair of " { $snippet "assoc" } " until one of them outputs a true value, and then calls the second quotation in the corresponding pair. Quotations are called in reverse order, and if no quotation outputs a true value then " { $snippet "default" } " is called." }
{ $values { "assoc" "a sequence of pairs of quotations" } { "quot" quotation } }
{ $description "Creates a quotation that when called, has the same effect as applying " { $link cond } " to " { $snippet "assoc" } "."
$nl
-"the generated quotation is more efficient than the naive implementation of " { $link cond } ", though, since it expands into a series of conditionals, and no iteration through " { $snippet "assoc" } " has to be performed." }
+"The generated quotation is more efficient than the naive implementation of " { $link cond } ", though, since it expands into a series of conditionals, and no iteration through " { $snippet "assoc" } " has to be performed." }
{ $notes "This word is used behind the scenes to compile " { $link cond } " forms efficiently; it can also be called directly, which is useful for meta-programming." } ;
HELP: case>quot
] if ;
: <buckets> ( initial length -- array )
- next-power-of-2 swap [ nip clone ] curry map ;
+ next-power-of-2 iota swap [ nip clone ] curry map ;
: distribute-buckets ( alist initial quot -- buckets )
swapd [ [ dup first ] dip call 2array ] curry map
dup assoc-size 1 eq?
[ assoc-hashcode ] [ nip assoc-size ] if
] recursive-hashcode ;
+
+: to-fixed-point ( object quot: ( object(n) -- object(n+1) ) -- object(n) )
+ [ keep over = ] keep [ to-fixed-point ] curry unless ; inline recursive
USING: help.markup help.syntax libc kernel continuations io
-sequences ;
+sequences classes ;
IN: destructors
+HELP: debug-leaks?
+{ $var-description "When this variable is on, " { $link new-disposable } " stores the current continuation in the " { $link disposable } "'s " { $slot "continuation" } " slot." }
+{ $see-also "tools.destructors" } ;
+
+HELP: disposable
+{ $class-description "Parent class for disposable resources. This class has three slots:"
+ { $list
+ { { $slot "disposed" } " - boolean. Set to true by " { $link dispose } ". Assert that it is false with " { $link check-disposed } "." }
+ { { $slot "id" } " - unique identifier. Set by " { $link new-disposable } "." }
+ { { $slot "continuation" } " - current continuation at construction time, for debugging. Set by " { $link new-disposable } " if " { $link debug-leaks? } " is on." }
+ }
+"New instances must be constructed with " { $link new-disposable } " and subclasses must implement " { $link dispose* } "." } ;
+
+HELP: new-disposable
+{ $values { "class" class } { "disposable" disposable } }
+{ $description "Constructs a new instance of a subclass of " { $link disposable } ". This sets the " { $slot "id" } " slot, registers the new object with the global " { $link disposables } " set, and if " { $link debug-leaks? } " is on, stores the current continuation in the " { $slot "continuation" } " slot." } ;
+
HELP: dispose
{ $values { "disposable" "a disposable object" } }
{ $contract "Releases operating system resources associated with a disposable object. Disposable objects include streams, memory mapped files, and so on."
$nl
"No further operations can be performed on a disposable object after this call."
$nl
-"Disposing an object which has already been disposed should have no effect, and in particular it should not fail with an error. To help implement this pattern, add a " { $snippet "disposed" } " slot to your object and implement the " { $link dispose* } " method instead." }
-{ $notes "You must close disposable objects after you are finished working with them, to avoid leaking operating system resources. A convenient way to automate this is by using the " { $link with-disposal } " word."
+"Disposing an object which has already been disposed should have no effect, and in particular it should not fail with an error. To help implement this pattern, inherit from the " { $link disposable } " class and implement the " { $link dispose* } " method instead." }
+{ $notes "You must dispose of disposable objects after you are finished working with them, to avoid leaking operating system resources. A convenient way to automate this is by using the " { $link with-disposal } " word."
$nl
-"The default implementation assumes the object has a " { $snippet "disposable" } " slot. If the slot is set to " { $link f } ", it calls " { $link dispose* } " and sets the slot to " { $link f } "." } ;
+"The default implementation assumes the object has a " { $snippet "disposed" } " slot. If the slot is set to " { $link f } ", it calls " { $link dispose* } " and sets the slot to " { $link t } "." } ;
HELP: dispose*
{ $values { "disposable" "a disposable object" } }
{ $contract "Releases operating system resources associated with a disposable object. Disposable objects include streams, memory mapped files, and so on." }
{ $notes
- "This word should not be called directly. It can be implemented on objects with a " { $snippet "disposable" } " slot to ensure that the object is only disposed once."
+ "This word should not be called directly. It can be implemented on objects with a " { $slot "disposed" } " slot to ensure that the object is only disposed once."
} ;
HELP: with-disposal
HELP: with-destructors
{ $values { "quot" "a quotation" } }
-{ $description "Calls a quotation within a new dynamic scope. This quotation may register destructors using " { $link &dispose } " or " { $link |dispose } ". The former registers a destructor that will always run whether or not the quotation threw an error, and the latter registers a destructor that only runs if the quotation throws an error only. Destructors are run in reverse order from the order in which they were registered." }
+{ $description "Calls a quotation within a new dynamic scope. This quotation may register destructors using " { $link &dispose } " or " { $link |dispose } ". The former registers a destructor that will always run whether or not the quotation threw an error, and the latter registers a destructor that only runs if the quotation throws an error. Destructors are run in reverse order from the order in which they were registered." }
{ $notes
"Destructors generalize " { $link with-disposal } ". The following two lines are equivalent, except that the second line establishes a new dynamic scope:"
{ $code
{ "seq" sequence } }
{ $description "Attempts to dispose of each element of a sequence and collects all of the errors into a sequence. If any errors are thrown during disposal, the last error is rethrown after all objects have been disposed." } ;
+HELP: disposables
+{ $var-description "Global variable holding all disposable objects which have not been disposed of yet. The " { $link new-disposable } " word adds objects here, and the " { $link dispose } " method on disposables removes them. The " { $link "tools.destructors" } " vocabulary provides some words for working with this data." }
+{ $see-also "tools.destructors" } ;
+
ARTICLE: "destructors-anti-patterns" "Resource disposal anti-patterns"
"Words which create objects corresponding to external resources should always be used with " { $link with-disposal } ". The following code is wrong:"
{ $code
}
"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-input-stream } " and " { $link with-output-stream } "; see " { $link "stdio" } " for details." ;
-ARTICLE: "destructors" "Deterministic resource disposal"
-"Operating system resources such as streams, memory mapped files, and so on are not managed by Factor's garbage collector and must be released when you are done with them. Failing to release a resource can lead to reduced performance and instability."
-$nl
-"Disposable object protocol:"
+ARTICLE: "destructors-using" "Using destructors"
+"Disposing of an object:"
{ $subsection dispose }
-{ $subsection dispose* }
"Utility word for scoped disposal:"
{ $subsection with-disposal }
"Utility word for disposing multiple objects:"
"Utility words for more complex disposal patterns:"
{ $subsection with-destructors }
{ $subsection &dispose }
-{ $subsection |dispose }
-{ $subsection "destructors-anti-patterns" } ;
+{ $subsection |dispose } ;
+
+ARTICLE: "destructors-extending" "Writing new destructors"
+"Superclass for disposable objects:"
+{ $subsection disposable }
+"Parametrized constructor for disposable objects:"
+{ $subsection new-disposable }
+"Generic disposal word:"
+{ $subsection dispose* }
+"Global set of disposable objects:"
+{ $subsection disposables } ;
+
+ARTICLE: "destructors" "Deterministic resource disposal"
+"Operating system resources such as streams, memory mapped files, and so on are not managed by Factor's garbage collector and must be released when you are done with them. Failing to release a resource can lead to reduced performance and instability."
+{ $subsection "destructors-using" }
+{ $subsection "destructors-extending" }
+{ $subsection "destructors-anti-patterns" }
+{ $see-also "tools.destructors" } ;
ABOUT: "destructors"
USING: destructors kernel tools.test continuations accessors
-namespaces sequences ;
+namespaces sequences destructors.private ;
IN: destructors.tests
TUPLE: dispose-error ;
] ignore-errors destroyed?>>
] unit-test
+TUPLE: silly-disposable < disposable ;
+
+M: silly-disposable dispose* drop ;
+
+silly-disposable new-disposable "s" set
+"s" get dispose
+[ "s" get unregister-disposable ]
+[ disposable>> silly-disposable? ]
+must-fail-with
-! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov.
+! Copyright (C) 2007, 2009 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors continuations kernel namespaces make
-sequences vectors ;
+sequences vectors sets assocs init math ;
IN: destructors
-TUPLE: disposable disposed ;
+SYMBOL: disposables
+
+[ H{ } clone disposables set-global ] "destructors" add-init-hook
+
+ERROR: already-unregistered disposable ;
+
+SYMBOL: debug-leaks?
+
+<PRIVATE
+
+SLOT: continuation
+
+: register-disposable ( obj -- )
+ debug-leaks? get-global [ continuation >>continuation ] when
+ disposables get conjoin ;
+
+: unregister-disposable ( obj -- )
+ disposables get 2dup key? [ delete-at ] [ drop already-unregistered ] if ;
+
+PRIVATE>
+
+TUPLE: disposable < identity-tuple
+{ id integer }
+{ disposed boolean }
+continuation ;
+
+M: disposable hashcode* nip id>> ;
+
+: new-disposable ( class -- disposable )
+ new \ disposable counter >>id
+ dup register-disposable ; inline
GENERIC: dispose* ( disposable -- )
M: object dispose
dup disposed>> [ drop ] [ t >>disposed dispose* ] if ;
+M: disposable dispose
+ dup disposed>> [ drop ] [
+ [ unregister-disposable ]
+ [ call-next-method ]
+ bi
+ ] if ;
+
: dispose-each ( seq -- )
[
[ [ dispose ] curry [ , ] recover ] each
-IN: effects.tests
USING: effects tools.test prettyprint accessors sequences ;
+IN: effects.tests
[ t ] [ 1 1 <effect> 2 2 <effect> effect<= ] unit-test
[ f ] [ 1 0 <effect> 2 2 <effect> effect<= ] unit-test
[ t ] [ (( -- )) (( -- )) compose-effects (( -- )) effect= ] unit-test
[ t ] [ (( -- * )) (( -- )) compose-effects (( -- * )) effect= ] unit-test
-[ t ] [ (( -- )) (( -- * )) compose-effects (( -- * )) effect= ] unit-test
\ No newline at end of file
+[ t ] [ (( -- )) (( -- * )) compose-effects (( -- * )) effect= ] unit-test
TUPLE: effect { in read-only } { out read-only } { terminated? read-only } ;
+GENERIC: effect-length ( obj -- n )
+M: sequence effect-length length ;
+M: integer effect-length ;
+
: <effect> ( in out -- effect )
dup { "*" } sequence= [ drop { } t ] [ f ] if
effect boa ;
: effect-height ( effect -- n )
- [ out>> length ] [ in>> length ] bi - ; inline
+ [ out>> effect-length ] [ in>> effect-length ] bi - ; inline
: effect<= ( effect1 effect2 -- ? )
{
{ [ over terminated?>> ] [ t ] }
{ [ dup terminated?>> ] [ f ] }
- { [ 2dup [ in>> length ] bi@ > ] [ f ] }
+ { [ 2dup [ in>> effect-length ] bi@ > ] [ f ] }
{ [ 2dup [ effect-height ] bi@ = not ] [ f ] }
[ t ]
} cond 2nip ; inline
: effect= ( effect1 effect2 -- ? )
- [ [ in>> length ] bi@ = ]
- [ [ out>> length ] bi@ = ]
+ [ [ in>> effect-length ] bi@ = ]
+ [ [ out>> effect-length ] bi@ = ]
[ [ terminated?>> ] bi@ = ]
2tri and and ;
stack-effect effect-height ;
: split-shuffle ( stack shuffle -- stack1 stack2 )
- in>> length cut* ;
+ in>> effect-length cut* ;
: shuffle-mapping ( effect -- mapping )
[ out>> ] [ in>> ] bi [ index ] curry map ;
over terminated?>> [
drop
] [
- [ [ [ in>> length ] [ out>> length ] bi ] [ in>> length ] bi* swap [-] + ]
- [ [ out>> length ] [ [ in>> length ] [ out>> length ] bi ] bi* [ [-] ] dip + ]
+ [ [ [ in>> effect-length ] [ out>> effect-length ] bi ] [ in>> effect-length ] bi* swap [-] + ]
+ [ [ out>> effect-length ] [ [ in>> effect-length ] [ out>> effect-length ] bi ] bi* [ [-] ] dip + ]
[ nip terminated?>> ] 2tri
+ [ [ [ "obj" ] replicate ] bi@ ] dip
effect boa
] if ; inline
: parse-effect-tokens ( end -- tokens )
[ parse-effect-token dup ] curry [ ] produce nip ;
+ERROR: stack-effect-omits-dashes effect ;
+
: parse-effect ( end -- effect )
parse-effect-tokens { "--" } split1 dup
- [ <effect> ] [ "Stack effect declaration must contain --" throw ] if ;
+ [ <effect> ] [ drop stack-effect-omits-dashes ] if ;
: complete-effect ( -- effect )
"(" expect ")" parse-effect ;
$nl
"Here is an example:"
{ $code
- "GENERIC: explain"
+ "GENERIC: explain ( object -- )"
"M: object explain drop \"an object\" print ;"
"M: number explain drop \"a number\" print ;"
"M: sequence explain drop \"a sequence\" print ;"
"The linear order is the following, from least-specific to most-specific:"
{ $code "{ object sequence number }" }
"Neither " { $link number } " nor " { $link sequence } " are subclasses of each other, yet their intersection is the non-empty " { $link integer } " class. Calling " { $snippet "explain" } " with an integer on the stack will print " { $snippet "a number" } " because " { $link number } " precedes " { $link sequence } " in the class linearization order. If this was not the desired outcome, define a method on the intersection:"
-{ $code "M: integer explain drop \"a sequence\" print ;" }
+{ $code "M: integer explain drop \"an integer\" print ;" }
"Now, the linear order is the following, from least-specific to most-specific:"
{ $code "{ object sequence number integer }" }
"The " { $link order } " word can be useful to clarify method dispatch order:"
HELP: math-generic
{ $class-description "The class of generic words using " { $link math-combination } "." } ;
-HELP: last/first
-{ $values { "seq" sequence } { "pair" "a two-element array" } }
-{ $description "Creates an array holding the first and last element of the sequence." } ;
+
-IN: generic.math.tests
USING: generic.math math tools.test kernel ;
+IN: generic.math.tests
! Test math-combination
[ [ [ >float ] dip ] ] [ \ real \ float math-upgrade ] unit-test
<PRIVATE
-: last/first ( seq -- pair ) [ last ] [ first ] bi 2array ;
-
: bootstrap-words ( classes -- classes' )
[ bootstrap-word ] map ;
-IN: generic.single.tests
USING: tools.test math math.functions math.constants generic.standard
generic.single strings sequences arrays kernel accessors words
specialized-arrays.double byte-arrays bit-arrays parser namespaces
make quotations stack-checker vectors growable hashtables sbufs
prettyprint byte-vectors bit-vectors specialized-vectors.double
definitions generic sets graphs assocs grouping see eval ;
+IN: generic.single.tests
GENERIC: lo-tag-test ( obj -- obj' )
! Corner case
[ "IN: generic.single.tests GENERIC# broken-generic# -1 ( a -- b )" eval( -- ) ]
[ error>> bad-dispatch-position? ]
-must-fail-with
\ No newline at end of file
+must-fail-with
default get <array> [ <enum> swap update ] keep ;
: lo-tag-number ( class -- n )
- "type" word-prop dup num-tags get member?
+ "type" word-prop dup num-tags get iota member?
[ drop object tag-number ] unless ;
M: tag-dispatch-engine compile-engine
: keep-going? ( assoc -- ? )
assumed get swap second first class<= ;
+ERROR: unreachable ;
+
: prune-redundant-predicates ( assoc -- default assoc' )
{
- { [ dup empty? ] [ drop [ "Unreachable" throw ] { } ] }
+ { [ dup empty? ] [ drop [ unreachable ] { } ] }
{ [ dup length 1 = ] [ first second { } ] }
{ [ dup keep-going? ] [ rest-slice prune-redundant-predicates ] }
[ [ first second ] [ rest-slice ] bi ]
-! Copyright (C) 2005, 2008 Slava Pestov.
+! Copyright (C) 2005, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel kernel.private math math.private
sequences sequences.private ;
SLOT: length
SLOT: underlying
-M: growable length length>> ;
-M: growable nth-unsafe underlying>> nth-unsafe ;
-M: growable set-nth-unsafe underlying>> set-nth-unsafe ;
+M: growable length length>> ; inline
+M: growable nth-unsafe underlying>> nth-unsafe ; inline
+M: growable set-nth-unsafe underlying>> set-nth-unsafe ; inline
: capacity ( seq -- n ) underlying>> length ; inline
: expand ( len seq -- )
[ resize ] change-underlying drop ; inline
-: contract ( len seq -- )
+GENERIC: contract ( len seq -- )
+
+M: growable contract ( len seq -- )
[ length ] keep
[ [ 0 ] 2dip set-nth-unsafe ] curry
- (each-integer) ; inline
+ (each-integer) ;
: growable-check ( n seq -- n seq )
over 0 < [ bounds-error ] when ; inline
[ >fixnum ] dip
] if ; inline
-M: growable set-nth ensure set-nth-unsafe ;
+M: growable set-nth ensure set-nth-unsafe ; inline
-M: growable clone (clone) [ clone ] change-underlying ;
+M: growable clone (clone) [ clone ] change-underlying ; inline
M: growable lengthen ( n seq -- )
2dup length > [
2dup capacity > [ over new-size over expand ] when
2dup (>>length)
- ] when 2drop ;
+ ] when 2drop ; inline
M: growable shorten ( n seq -- )
growable-check
2dup length < [
2dup contract
2dup (>>length)
- ] when 2drop ;
+ ] when 2drop ; inline
INSTANCE: growable sequence
-IN: hashtables.tests
USING: kernel math namespaces make tools.test vectors sequences
sequences.private hashtables io prettyprint assocs
continuations ;
+IN: hashtables.tests
[ f ] [ "hi" V{ 1 2 3 } at ] unit-test
[ 1 ] [ "h" get assoc-size ] unit-test
[ 1 ] [ 2 "h" get at ] unit-test
+
+! Random test case
+[ "A" ] [ 100 [ dup ] H{ } map>assoc 32 over delete-at "A" 32 pick set-at 32 swap at ] unit-test
] if ;
M: hashtable assoc-size ( hash -- n )
- [ count>> ] [ deleted>> ] bi - ;
+ [ count>> ] [ deleted>> ] bi - ; inline
: rehash ( hash -- )
dup >alist [
] keep { } like ;
M: hashtable clone
- (clone) [ clone ] change-array ;
+ (clone) [ clone ] change-array ; inline
M: hashtable equal?
over hashtable? [
] [ 2drop f ] if ;
! Default method
-M: assoc new-assoc drop <hashtable> ;
+M: assoc new-assoc drop <hashtable> ; inline
-M: f new-assoc drop <hashtable> ;
+M: f new-assoc drop <hashtable> ; inline
: >hashtable ( assoc -- hashtable )
H{ } assoc-clone-like ;
M: hashtable assoc-like
- drop dup hashtable? [ >hashtable ] unless ;
+ drop dup hashtable? [ >hashtable ] unless ; inline
: ?set-at ( value key assoc/f -- assoc )
[ [ set-at ] keep ] [ associate ] if* ;
-IN: io.backend.tests
USING: tools.test io.backend kernel ;
+IN: io.backend.tests
[ ] [ "a" normalize-path drop ] unit-test
: nth-byte ( x n -- b ) -8 * shift mask-byte ; inline
-: >le ( x n -- byte-array ) [ nth-byte ] with B{ } map-as ;
+: >le ( x n -- byte-array ) iota [ nth-byte ] with B{ } map-as ;
: >be ( x n -- byte-array ) >le dup reverse-here ;
: d>w/w ( d -- w1 w2 )
: h>b/b ( h -- b1 b2 )
[ mask-byte ]
[ -8 shift mask-byte ] bi ;
+
+: signed-le> ( bytes -- x )
+ [ le> ] [ length 8 * 1 - 2^ 1 - ] bi
+ 2dup > [ bitnot bitor ] [ drop ] if ;
+
+: signed-be> ( bytes -- x )
+ <reversed> signed-le> ;
dup stream-read1 dup [ begin-utf8 ] when nip ; inline
M: utf8 decode-char
- drop decode-utf8 ;
+ drop decode-utf8 ; inline
! Encoding UTF-8
PRIVATE>
: code-point-length ( n -- x )
- dup zero? [ drop 1 ] [
+ [ 1 ] [
log2 {
{ [ dup 0 6 between? ] [ 1 ] }
{ [ dup 7 10 between? ] [ 2 ] }
{ [ dup 11 15 between? ] [ 3 ] }
{ [ dup 16 20 between? ] [ 4 ] }
} cond nip
- ] if ;
+ ] if-zero ;
: code-point-offsets ( string -- indices )
0 [ code-point-length + ] accumulate swap suffix ;
"non-byte-array-error" unique-file binary [
"" write
] with-file-writer
-] [ no-method? ] must-fail-with
\ No newline at end of file
+] [ no-method? ] must-fail-with
+
+! What happens if we close a file twice?
+[ ] [
+ "closing-twice" unique-file ascii <file-writer>
+ [ dispose ] [ dispose ] bi
+] unit-test
\ No newline at end of file
" 16 group"
"] with-disposal"
}
-"This code is robust however it is more complex than it needs to be since. This is where the default stream words come in; using them, the above can be rewritten as follows:"
+"This code is robust, however it is more complex than it needs to be. This is where the default stream words come in; using them, the above can be rewritten as follows:"
{ $code
"USING: continuations kernel io io.files math.parser splitting ;"
"\"data.txt\" utf8 <file-reader> ["
{ $subsection write1 }
{ $subsection write }
"If the default output stream is a character stream (" { $link stream-element-type } " outputs " { $link +character+ } "), lines of text can be written:"
-{ $subsection readln }
{ $subsection print }
{ $subsection nl }
{ $subsection bl }
{ $example "USING: io.pathnames prettyprint ;" "\"/usr/libexec/awk/\" file-name ." "\"awk\"" }
} ;
+HELP: file-extension
+{ $values { "path" "a pathname string" } { "extension" string } }
+{ $description "Outputs the extension of " { $snippet "path" } ", or " { $link f } " if the filename has no extension." }
+{ $examples
+ { $example "USING: io.pathnames prettyprint ;" "\"/usr/bin/gcc\" file-extension ." "f" }
+ { $example "USING: io.pathnames prettyprint ;" "\"/home/csi/gui.vbs\" file-extension ." "\"vbs\"" }
+} ;
+
+HELP: file-stem
+{ $values { "path" "a pathname string" } { "stem" string } }
+{ $description "Outputs the " { $link file-name } " of " { $snippet "filename" } " with the file extension removed, if any." }
+{ $examples
+ { $example "USING: io.pathnames prettyprint ;" "\"/usr/bin/gcc\" file-stem ." "\"gcc\"" }
+ { $example "USING: io.pathnames prettyprint ;" "\"/home/csi/gui.vbs\" file-stem ." "\"gui\"" }
+} ;
+
+{ file-name file-stem file-extension } related-words
+
HELP: path-components
{ $values { "path" "a pathnames string" } { "seq" sequence } }
{ $description "Splits a pathname on the " { $link path-separator } " into its its component strings." } ;
"Pathname manipulation:"
{ $subsection parent-directory }
{ $subsection file-name }
+{ $subsection file-stem }
+{ $subsection file-extension }
{ $subsection last-path-separator }
{ $subsection path-components }
{ $subsection prepend-path }
] if
] unless ;
-: file-extension ( filename -- extension )
+: file-stem ( path -- stem )
+ file-name "." split1-last drop ;
+
+: file-extension ( path -- extension )
file-name "." split1-last nip ;
: path-components ( path -- seq )
USING: tools.test io.streams.byte-array io.encodings.binary
-io.encodings.utf8 io kernel arrays strings namespaces ;
+io.encodings.utf8 io kernel arrays strings namespaces math ;
[ B{ } ] [ B{ } binary [ contents ] with-byte-reader ] unit-test
[ B{ 1 2 3 } ] [ binary [ B{ 1 2 3 } write ] with-byte-writer ] unit-test
read1
] with-byte-reader
] unit-test
+
+! Overly aggressive compiler optimizations
+[ B{ 123 } ] [
+ binary [ 123 >bignum write1 ] with-byte-writer
+] unit-test
\ No newline at end of file
accessors combinators ;
IN: io.streams.c
-TUPLE: c-stream handle disposed ;
+TUPLE: c-stream < disposable handle ;
+
+: new-c-stream ( handle class -- c-stream )
+ new-disposable swap >>handle ; inline
M: c-stream dispose* handle>> fclose ;
TUPLE: c-writer < c-stream ;
-: <c-writer> ( handle -- stream ) f c-writer boa ;
+: <c-writer> ( handle -- stream ) c-writer new-c-stream ;
M: c-writer stream-element-type drop +byte+ ;
TUPLE: c-reader < c-stream ;
-: <c-reader> ( handle -- stream ) f c-reader boa ;
+: <c-reader> ( handle -- stream ) c-reader new-c-stream ;
M: c-reader stream-element-type drop +byte+ ;
M: memory-stream stream-read1
[ [ alien>> ] [ index>> ] bi alien-unsigned-1 ]
- [ [ 1+ ] change-index drop ] bi ;
+ [ [ 1 + ] change-index drop ] bi ;
{ $subsection until }
"To execute one iteration of a loop, use the following word:"
{ $subsection do }
-"This word is intended as a modifier. The normal " { $link while } " loop never executes the body if the predicate returns first on the first iteration. To ensure the body executes at least once, use " { $link do } ":"
+"This word is intended as a modifier. The normal " { $link while } " loop never executes the body if the predicate returns false on the first iteration. To ensure the body executes at least once, use " { $link do } ":"
{ $code
"[ P ] [ Q ] do while"
}
! Object protocol
GENERIC: hashcode* ( depth obj -- code )
-M: object hashcode* 2drop 0 ;
+M: object hashcode* 2drop 0 ; inline
-M: f hashcode* 2drop 31337 ;
+M: f hashcode* 2drop 31337 ; inline
: hashcode ( obj -- code ) 3 swap hashcode* ; inline
GENERIC: equal? ( obj1 obj2 -- ? )
-M: object equal? 2drop f ;
+M: object equal? 2drop f ; inline
TUPLE: identity-tuple ;
-M: identity-tuple equal? 2drop f ;
+M: identity-tuple equal? 2drop f ; inline
: = ( obj1 obj2 -- ? )
2dup eq? [ 2drop t ] [
GENERIC: clone ( obj -- cloned )
-M: object clone ;
+M: object clone ; inline
-M: callstack clone (clone) ;
+M: callstack clone (clone) ; inline
! Tuple construction
GENERIC: new ( class -- tuple )
-IN: system.tests\r
USING: layouts math tools.test ;\r
+IN: system.tests\r
\r
[ t ] [ cell integer? ] unit-test\r
[ t ] [ bootstrap-cell integer? ] unit-test\r
M: real >integer
dup most-negative-fixnum most-positive-fixnum between?
- [ >fixnum ] [ >bignum ] if ;
+ [ >fixnum ] [ >bignum ] if ; inline
UNION: immediate fixnum POSTPONE: f ;
HELP: skip
{ $values { "i" "a starting index" } { "seq" sequence } { "?" "a boolean" } { "n" integer } }
-{ $description "Skips to the first space character (if " { $snippet "boolean" } " is " { $link f } ") or the first non-space character (otherwise)." } ;
+{ $description "Skips to the first space character (if " { $snippet "boolean" } " is " { $link f } ") or the first non-space character (otherwise). Tabulations used as separators instead of spaces will be flagged as an error." } ;
HELP: change-lexer-column
{ $values { "lexer" lexer } { "quot" { $quotation "( col line -- newcol )" } } }
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences accessors namespaces math words strings
-io vectors arrays math.parser combinators continuations ;
+io vectors arrays math.parser combinators continuations
+source-files.errors ;
IN: lexer
TUPLE: lexer text line line-text line-length column ;
: <lexer> ( text -- lexer )
lexer new-lexer ;
+ERROR: unexpected want got ;
+
+: forbid-tab ( c -- c )
+ [ CHAR: \t eq? [ "[space]" "[tab]" unexpected ] when ] keep ; inline
+
: skip ( i seq ? -- n )
over length
- [ [ swap CHAR: \s eq? xor ] curry find-from drop ] dip or ;
+ [ [ swap forbid-tab CHAR: \s eq? xor ] curry find-from drop ] dip or ;
: change-lexer-column ( lexer quot -- )
[ [ column>> ] [ line-text>> ] bi ] prepose keep
] change-lexer-column ;
: still-parsing? ( lexer -- ? )
- [ line>> ] [ text>> ] bi length <= ;
+ [ line>> ] [ text>> length ] bi <= ;
: still-parsing-line? ( lexer -- ? )
[ column>> ] [ line-length>> ] bi < ;
: scan ( -- str/f ) lexer get parse-token ;
-ERROR: unexpected want got ;
-
PREDICATE: unexpected-eof < unexpected
got>> not ;
TUPLE: lexer-error line column line-text error ;
+M: lexer-error error-file error>> error-file ;
+M: lexer-error error-line [ error>> error-line ] [ line>> ] bi or ;
+
: <lexer-error> ( msg -- error )
\ lexer-error new
lexer get
$nl
"On the other hand, using " { $link make } " instead of a single call to " { $link surround } " is overkill. The below headings summarize the most important cases where other idioms are more appropriate than " { $link make } "."
{ $heading "Make versus combinators" }
-"Sometimes, usages of " { $link make } " are better expressed with " { $link "sequences-combinators" } ". For example, instead of calling a combinator with a quotation which executes " { $link , } " exactly once on each iteration, oftena combinator encapsulating that specific idiom exists and can be used."
+"Sometimes, usages of " { $link make } " are better expressed with " { $link "sequences-combinators" } ". For example, instead of calling a combinator with a quotation which executes " { $link , } " exactly once on each iteration, often a combinator encapsulating that specific idiom exists and can be used."
$nl
"For example,"
{ $code "[ [ 42 * , ] each ] { } make" }
: make ( quot exemplar -- seq )
[
[
- 1024 swap new-resizable [
+ 100 swap new-resizable [
building set call
] keep
] keep like
USING: help.markup help.syntax math math.private ;
IN: math.floats
-ARTICLE: "floats" "Floats"
-{ $subsection float }
-"Rational numbers represent " { $emphasis "exact" } " quantities. On the other hand, a floating point number is an " { $emphasis "approximation" } ". While rationals can grow to any required precision, floating point numbers are fixed-width, and manipulating them is usually faster than manipulating ratios or bignums (but slower than manipulating fixnums). Floating point numbers are often used to represent irrational numbers, which have no exact representation as a ratio of two integers."
-$nl
-"Introducing a floating point number in a computation forces the result to be expressed in floating point."
-{ $example "5/4 1/2 + ." "1+3/4" }
-{ $example "5/4 0.5 + ." "1.75" }
-"Integers and rationals can be converted to floats:"
-{ $subsection >float }
-"Two real numbers can be divided yielding a float result:"
-{ $subsection /f }
-"Floating point numbers are represented internally in IEEE 754 double-precision format. This internal representation can be accessed for advanced operations and input/output purposes."
-{ $subsection float>bits }
-{ $subsection double>bits }
-{ $subsection bits>float }
-{ $subsection bits>double }
-{ $see-also "syntax-floats" } ;
-
-ABOUT: "floats"
-
HELP: float
{ $class-description "The class of double-precision floating point numbers." } ;
{ $description "Converts a real to a float. This is the identity on floats, and performs a floating point division on rationals." } ;
HELP: bits>double ( n -- x )
-{ $values { "n" "a 64-bit integer representing an 754 double-precision float" } { "x" float } }
-{ $description "Creates a " { $link float } " object from a binary representation. This word is usually used to reconstruct floats read from streams." } ;
+{ $values { "n" "a 64-bit integer representing an IEEE 754 double-precision float" } { "x" float } }
+{ $description "Creates a " { $link float } " object from a 64-bit binary representation. This word is usually used to reconstruct floats read from streams." } ;
{ bits>double bits>float double>bits float>bits } related-words
HELP: bits>float ( n -- x )
-{ $values { "n" "a 32-bit integer representing an 754 single-precision float" } { "x" float } }
-{ $description "Creates a " { $link float } " object from a binary representation. This word is usually used to reconstruct floats read from streams." } ;
+{ $values { "n" "a 32-bit integer representing an IEEE 754 single-precision float" } { "x" float } }
+{ $description "Creates a " { $link float } " object from a 32-bit binary representation. This word is usually used to reconstruct floats read from streams." } ;
HELP: double>bits ( x -- n )
-{ $values { "x" float } { "n" "a 64-bit integer representing an 754 double-precision float" } }
-{ $description "Creates a " { $link float } " object from a binary representation. This word is usually used to reconstruct floats read from streams." } ;
+{ $values { "x" float } { "n" "a 64-bit integer representing an IEEE 754 double-precision float" } }
+{ $description "Creates a 64-bit binary representation of a " { $link float } " object. This can be used in the process of writing a float to a stream." } ;
HELP: float>bits ( x -- n )
-{ $values { "x" float } { "n" "a 32-bit integer representing an 754 single-precision float" } }
-{ $description "Creates a " { $link float } " object from a binary representation. This word is usually used to reconstruct floats read from streams." } ;
+{ $values { "x" float } { "n" "a 32-bit integer representing an IEEE 754 single-precision float" } }
+{ $description "Creates a 32-bit binary representation of a " { $link float } " object. This can be used in the process of writing a float to a stream." } ;
! Unsafe primitives
HELP: float+ ( x y -- z )
{ $values { "x" float } { "y" float } { "?" "a boolean" } }
{ $description "Primitive version of " { $link >= } "." }
{ $warning "This word does not perform type checking, and passing objects of the wrong type can crash the runtime. User code should call the generic word " { $link >= } " instead." } ;
+
+ARTICLE: "floats" "Floats"
+{ $subsection float }
+"Rational numbers represent " { $emphasis "exact" } " quantities. On the other hand, a floating point number is an " { $emphasis "approximate" } " value. While rationals can grow to any required precision, floating point numbers have limited precision, and manipulating them is usually faster than manipulating ratios or bignums."
+$nl
+"Introducing a floating point number in a computation forces the result to be expressed in floating point."
+{ $example "5/4 1/2 + ." "1+3/4" }
+{ $example "5/4 0.5 + ." "1.75" }
+"Integers and rationals can be converted to floats:"
+{ $subsection >float }
+"Two real numbers can be divided yielding a float result:"
+{ $subsection /f }
+"Floating point numbers are represented internally in IEEE 754 double-precision format. This internal representation can be accessed for advanced operations and input/output purposes."
+{ $subsection float>bits }
+{ $subsection double>bits }
+{ $subsection bits>float }
+{ $subsection bits>double }
+"Constructing floating point NaNs:"
+{ $subsection <fp-nan> }
+"Floating point numbers are discrete:"
+{ $subsection prev-float }
+{ $subsection next-float }
+"Introspection on floating point numbers:"
+{ $subsection fp-special? }
+{ $subsection fp-nan? }
+{ $subsection fp-qnan? }
+{ $subsection fp-snan? }
+{ $subsection fp-infinity? }
+{ $subsection fp-nan-payload }
+"Comparing two floating point numbers:"
+{ $subsection fp-bitwise= }
+{ $see-also "syntax-floats" } ;
+
+ABOUT: "floats"
-! Copyright (C) 2004, 2006 Slava Pestov.
+! Copyright (C) 2004, 2009 Slava Pestov, Joe Groff.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math math.private ;
IN: math.floats.private
-M: fixnum >float fixnum>float ;
-M: bignum >float bignum>float ;
+M: fixnum >float fixnum>float ; inline
+M: bignum >float bignum>float ; inline
-M: float >fixnum float>fixnum ;
-M: float >bignum float>bignum ;
-M: float >float ;
+M: float >fixnum float>fixnum ; inline
+M: float >bignum float>bignum ; inline
+M: float >float ; inline
-M: float hashcode* nip float>bits ;
-M: float equal? over float? [ float= ] [ 2drop f ] if ;
-M: float number= float= ;
+M: float hashcode* nip float>bits ; inline
+M: float equal? over float? [ float= ] [ 2drop f ] if ; inline
+M: float number= float= ; inline
-M: float < float< ;
-M: float <= float<= ;
-M: float > float> ;
-M: float >= float>= ;
+M: float < float< ; inline
+M: float <= float<= ; inline
+M: float > float> ; inline
+M: float >= float>= ; inline
-M: float + float+ ;
-M: float - float- ;
-M: float * float* ;
-M: float / float/f ;
-M: float /f float/f ;
-M: float /i float/f >integer ;
-M: float mod float-mod ;
+M: float + float+ ; inline
+M: float - float- ; inline
+M: float * float* ; inline
+M: float / float/f ; inline
+M: float /f float/f ; inline
+M: float /i float/f >integer ; inline
+M: float mod float-mod ; inline
-M: real abs dup 0 < [ neg ] when ;
+M: real abs dup 0 < [ neg ] when ; inline
+
+M: float fp-special?
+ double>bits -52 shift HEX: 7ff [ bitand ] keep = ; inline
+
+M: float fp-nan-payload
+ double>bits 52 2^ 1 - bitand ; inline
+
+M: float fp-nan?
+ dup fp-special? [ fp-nan-payload zero? not ] [ drop f ] if ; inline
+
+M: float fp-qnan?
+ dup fp-nan? [ fp-nan-payload 51 2^ bitand zero? not ] [ drop f ] if ; inline
+
+M: float fp-snan?
+ dup fp-nan? [ fp-nan-payload 51 2^ bitand zero? ] [ drop f ] if ; inline
+
+M: float fp-infinity?
+ dup fp-special? [ fp-nan-payload zero? ] [ drop f ] if ; inline
+
+M: float next-float ( m -- n )
+ double>bits
+ dup -0.0 double>bits > [ 1 - bits>double ] [ ! negative non-zero
+ dup -0.0 double>bits = [ drop 0.0 ] [ ! negative zero
+ 1 + bits>double ! positive
+ ] if
+ ] if ; inline
+
+M: float prev-float ( m -- n )
+ double>bits
+ dup -0.0 double>bits >= [ 1 + bits>double ] [ ! negative
+ dup 0.0 double>bits = [ drop -0.0 ] [ ! positive zero
+ 1 - bits>double ! positive non-zero
+ ] if
+ ] if ; inline
sequences.private math math.private combinators ;
IN: math.integers.private
-M: integer numerator ;
-M: integer denominator drop 1 ;
+M: integer numerator ; inline
+M: integer denominator drop 1 ; inline
-M: fixnum >fixnum ;
-M: fixnum >bignum fixnum>bignum ;
-M: fixnum >integer ;
+M: fixnum >fixnum ; inline
+M: fixnum >bignum fixnum>bignum ; inline
+M: fixnum >integer ; inline
-M: fixnum hashcode* nip ;
-M: fixnum equal? over bignum? [ >bignum bignum= ] [ 2drop f ] if ;
-M: fixnum number= eq? ;
+M: fixnum hashcode* nip ; inline
+M: fixnum equal? over bignum? [ >bignum bignum= ] [ 2drop f ] if ; inline
+M: fixnum number= eq? ; inline
-M: fixnum < fixnum< ;
-M: fixnum <= fixnum<= ;
-M: fixnum > fixnum> ;
-M: fixnum >= fixnum>= ;
+M: fixnum < fixnum< ; inline
+M: fixnum <= fixnum<= ; inline
+M: fixnum > fixnum> ; inline
+M: fixnum >= fixnum>= ; inline
-M: fixnum + fixnum+ ;
-M: fixnum - fixnum- ;
-M: fixnum * fixnum* ;
-M: fixnum /i fixnum/i ;
-M: fixnum /f [ >float ] dip >float float/f ;
+M: fixnum + fixnum+ ; inline
+M: fixnum - fixnum- ; inline
+M: fixnum * fixnum* ; inline
+M: fixnum /i fixnum/i ; inline
+M: fixnum /f [ >float ] dip >float float/f ; inline
-M: fixnum mod fixnum-mod ;
+M: fixnum mod fixnum-mod ; inline
-M: fixnum /mod fixnum/mod ;
+M: fixnum /mod fixnum/mod ; inline
-M: fixnum bitand fixnum-bitand ;
-M: fixnum bitor fixnum-bitor ;
-M: fixnum bitxor fixnum-bitxor ;
-M: fixnum shift >fixnum fixnum-shift ;
+M: fixnum bitand fixnum-bitand ; inline
+M: fixnum bitor fixnum-bitor ; inline
+M: fixnum bitxor fixnum-bitxor ; inline
+M: fixnum shift >fixnum fixnum-shift ; inline
-M: fixnum bitnot fixnum-bitnot ;
+M: fixnum bitnot fixnum-bitnot ; inline
-M: fixnum bit? neg shift 1 bitand 0 > ;
+M: fixnum bit? neg shift 1 bitand 0 > ; inline
: fixnum-log2 ( x -- n )
0 swap [ dup 1 eq? ] [ [ 1 + ] [ 2/ ] bi* ] until drop ;
-M: fixnum (log2) fixnum-log2 ;
+M: fixnum (log2) fixnum-log2 ; inline
-M: bignum >fixnum bignum>fixnum ;
-M: bignum >bignum ;
+M: bignum >fixnum bignum>fixnum ; inline
+M: bignum >bignum ; inline
M: bignum hashcode* nip >fixnum ;
M: bignum equal?
over bignum? [ bignum= ] [
swap dup fixnum? [ >bignum bignum= ] [ 2drop f ] if
- ] if ;
+ ] if ; inline
-M: bignum number= bignum= ;
+M: bignum number= bignum= ; inline
-M: bignum < bignum< ;
-M: bignum <= bignum<= ;
-M: bignum > bignum> ;
-M: bignum >= bignum>= ;
+M: bignum < bignum< ; inline
+M: bignum <= bignum<= ; inline
+M: bignum > bignum> ; inline
+M: bignum >= bignum>= ; inline
-M: bignum + bignum+ ;
-M: bignum - bignum- ;
-M: bignum * bignum* ;
-M: bignum /i bignum/i ;
-M: bignum mod bignum-mod ;
+M: bignum + bignum+ ; inline
+M: bignum - bignum- ; inline
+M: bignum * bignum* ; inline
+M: bignum /i bignum/i ; inline
+M: bignum mod bignum-mod ; inline
-M: bignum /mod bignum/mod ;
+M: bignum /mod bignum/mod ; inline
-M: bignum bitand bignum-bitand ;
-M: bignum bitor bignum-bitor ;
-M: bignum bitxor bignum-bitxor ;
-M: bignum shift >fixnum bignum-shift ;
+M: bignum bitand bignum-bitand ; inline
+M: bignum bitor bignum-bitor ; inline
+M: bignum bitxor bignum-bitxor ; inline
+M: bignum shift >fixnum bignum-shift ; inline
-M: bignum bitnot bignum-bitnot ;
-M: bignum bit? bignum-bit? ;
-M: bignum (log2) bignum-log2 ;
+M: bignum bitnot bignum-bitnot ; inline
+M: bignum bit? bignum-bit? ; inline
+M: bignum (log2) bignum-log2 ; inline
! Converting ratios to floats. Based on FLOAT-RATIO from
! sbcl/src/code/float.lisp, which has the following license:
over zero? [
2drop 0.0
] [
- dup zero? [
- 2drop 1/0.
+ [
+ drop 1/0.
] [
pre-scale
/f-loop over odd?
[ zero? [ 1 + ] unless ] [ drop ] if
post-scale
- ] if
+ ] if-zero
] if ; inline
M: bignum /f ( m n -- f )
} ;
HELP: <
-{ $values { "x" real } { "y" real } { "?" "a boolean" } }
+{ $values { "x" real } { "y" real } { "?" boolean } }
{ $description "Tests if " { $snippet "x" } " is less than " { $snippet "y" } "." } ;
HELP: <=
-{ $values { "x" real } { "y" real } { "?" "a boolean" } }
+{ $values { "x" real } { "y" real } { "?" boolean } }
{ $description "Tests if " { $snippet "x" } " is less than or equal to " { $snippet "y" } "." } ;
HELP: >
-{ $values { "x" real } { "y" real } { "?" "a boolean" } }
+{ $values { "x" real } { "y" real } { "?" boolean } }
{ $description "Tests if " { $snippet "x" } " is greater than " { $snippet "y" } "." } ;
HELP: >=
-{ $values { "x" real } { "y" real } { "?" "a boolean" } }
+{ $values { "x" real } { "y" real } { "?" boolean } }
{ $description "Tests if " { $snippet "x" } " is greater than or equal to " { $snippet "y" } "." } ;
{ $description "Computes the bitwise complement of the input; that is, each bit in the input number is flipped." }
{ $notes "This word implements bitwise not, so applying it to booleans will throw an error. Boolean not is the " { $link not } " word."
$nl
-"Due to the two's complement representation of signed integers, the following two lines are equivalent:" { $code "bitnot" "neg 1-" } } ;
+"Due to the two's complement representation of signed integers, the following two lines are equivalent:" { $code "bitnot" "neg 1 -" } } ;
HELP: bit?
{ $values { "x" integer } { "n" integer } { "?" "a boolean" } }
{ $description "Outputs the largest integer " { $snippet "n" } " such that " { $snippet "2^n" } " is less than or equal to " { $snippet "x" } "." }
{ $errors "Throws an error if " { $snippet "x" } " is zero or negative." } ;
-HELP: 1+
-{ $values { "x" number } { "y" number } }
-{ $description
- "Increments a number by 1. The following two lines are equivalent:"
- { $code "1+" "1 +" }
- "There is no difference in behavior or efficiency."
-} ;
-
-HELP: 1-
-{ $values { "x" number } { "y" number } }
-{ $description
- "Decrements a number by 1. The following two lines are equivalent:"
- { $code "1-" "1 -" }
- "There is no difference in behavior or efficiency."
-} ;
-
HELP: ?1+
{ $values { "x" { $maybe number } } { "y" number } }
{ $description "If the input is not " { $link f } ", adds one. Otherwise, outputs a " { $snippet "0" } "." } ;
{ $description
"Outputs one of the following:"
{ $list
- "-1 if " { $snippet "x" } " is negative"
- "0 if " { $snippet "x" } " is equal to 0"
- "1 if " { $snippet "x" } " is positive"
+ { "-1 if " { $snippet "x" } " is negative" }
+ { "0 if " { $snippet "x" } " is equal to 0" }
+ { "1 if " { $snippet "x" } " is positive" }
}
} ;
{ $values { "x" number } { "?" "a boolean" } }
{ $description "Tests if the number is equal to zero." } ;
+HELP: if-zero
+{ $values { "n" number } { "quot1" quotation } { "quot2" quotation } }
+{ $description "Makes an implicit check if the number is zero. A zero is dropped and " { $snippet "quot1" } " is called. Otherwise, if the number is not zero, " { $snippet "quot2" } " is called on it." }
+{ $example
+ "USING: kernel math prettyprint sequences ;"
+ "3 [ \"zero\" ] [ sq ] if-zero ."
+ "9"
+} ;
+
+HELP: when-zero
+{ $values
+ { "n" number } { "quot" "the first quotation of an " { $link if-zero } } }
+{ $description "Makes an implicit check if the sequence is empty. A zero is dropped and the " { $snippet "quot" } " is called." }
+{ $examples "This word is equivalent to " { $link if-zero } " with an empty second quotation:"
+ { $example
+ "USING: math prettyprint ;"
+ "0 [ 4 ] [ ] if-zero ."
+ "4"
+ }
+ { $example
+ "USING: math prettyprint ;"
+ "0 [ 4 ] when-zero ."
+ "4"
+ }
+} ;
+
+HELP: unless-zero
+{ $values
+ { "n" number } { "quot" "the second quotation of an " { $link if-empty } } }
+{ $description "Makes an implicit check if the number is zero. A zero is dropped. Otherwise, the " { $snippet "quot" } " is called on the number." }
+{ $examples "This word is equivalent to " { $link if-zero } " with an empty first quotation:"
+ { $example
+ "USING: sequences math prettyprint ;"
+ "3 [ ] [ sq ] if-empty ."
+ "9"
+ }
+ { $example
+ "USING: sequences math prettyprint ;"
+ "3 [ sq ] unless-zero ."
+ "9"
+ }
+} ;
+
HELP: times
{ $values { "n" integer } { "quot" quotation } }
{ $description "Calls the quotation " { $snippet "n" } " times." }
{ $example "USING: io math ;" "3 [ \"Hi\" print ] times" "Hi\nHi\nHi" }
} ;
+HELP: fp-bitwise=
+{ $values
+ { "x" float } { "y" float }
+ { "?" boolean }
+}
+{ $description "Compares two floating point numbers for bit equality." } ;
+
HELP: fp-special?
{ $values { "x" real } { "?" "a boolean" } }
{ $description "Tests if " { $snippet "x" } " is an IEEE special value (Not-a-Number or Infinity). While " { $snippet "x" } " can be any real number, this word will only ever yield true if " { $snippet "x" } " is a " { $link float } "." } ;
HELP: next-float
{ $values { "m" float } { "n" float } }
-{ $description "Returns the least representable " { $link float } " value greater than " { $snippet "m" } "." } ;
+{ $description "Returns the least representable " { $link float } " value greater than " { $snippet "m" } ", or in the case of " { $snippet "-0.0" } ", returns " { $snippet "+0.0" } "." } ;
HELP: prev-float
{ $values { "m" float } { "n" float } }
-{ $description "Returns the greatest representable " { $link float } " value less than " { $snippet "m" } "." } ;
+{ $description "Returns the greatest representable " { $link float } " value less than " { $snippet "m" } ", or in the case of " { $snippet "+0.0" } ", returns " { $snippet "-0.0" } "." } ;
{ next-float prev-float } related-words
HELP: all-integers?
{ $values { "n" integer } { "quot" { $quotation "( i -- ? )" } } { "?" "a boolean" } }
-{ $description "Applies the quotation to each integer from 0 up to " { $snippet "n" } ", excluding " { $snippet "n" } ". Iterationi stops when the quotation outputs " { $link f } " or the end is reached. If the quotation yields a false value for some integer, this word outputs " { $link f } ". Otherwise, this word outputs " { $link t } "." }
+{ $description "Applies the quotation to each integer from 0 up to " { $snippet "n" } ", excluding " { $snippet "n" } ". Iteration stops when the quotation outputs " { $link f } " or the end is reached. If the quotation yields a false value for some integer, this word outputs " { $link f } ". Otherwise, this word outputs " { $link t } "." }
{ $notes "This word is used to implement " { $link all? } "." } ;
HELP: find-integer
PRIVATE>
+ERROR: log2-expects-positive x ;
+
: log2 ( x -- n )
dup 0 <= [
- "log2 expects positive inputs" throw
+ log2-expects-positive
] [
(log2)
] if ; inline
: zero? ( x -- ? ) 0 number= ; inline
-: 1+ ( x -- y ) 1 + ; inline
-: 1- ( x -- y ) 1 - ; inline
: 2/ ( x -- y ) -1 shift ; inline
: sq ( x -- y ) dup * ; inline
: neg ( x -- -x ) -1 * ; inline
: even? ( n -- ? ) 1 bitand zero? ;
: odd? ( n -- ? ) 1 bitand 1 number= ;
+: if-zero ( n quot1 quot2 -- )
+ [ dup zero? ] [ [ drop ] prepose ] [ ] tri* if ; inline
+
+: when-zero ( n quot -- ) [ ] if-zero ; inline
+
+: unless-zero ( n quot -- ) [ ] swap if-zero ; inline
+
UNION: integer fixnum bignum ;
TUPLE: ratio { numerator integer read-only } { denominator integer read-only } ;
GENERIC: fp-infinity? ( x -- ? )
GENERIC: fp-nan-payload ( x -- bits )
-M: object fp-special?
- drop f ;
-M: object fp-nan?
- drop f ;
-M: object fp-qnan?
- drop f ;
-M: object fp-snan?
- drop f ;
-M: object fp-infinity?
- drop f ;
-M: object fp-nan-payload
- drop f ;
-
-M: float fp-special?
- double>bits -52 shift HEX: 7ff [ bitand ] keep = ;
-
-M: float fp-nan-payload
- double>bits HEX: fffffffffffff bitand ; foldable flushable
-
-M: float fp-nan?
- dup fp-special? [ fp-nan-payload zero? not ] [ drop f ] if ;
-
-M: float fp-qnan?
- dup fp-nan? [ fp-nan-payload HEX: 8000000000000 bitand zero? not ] [ drop f ] if ;
-
-M: float fp-snan?
- dup fp-nan? [ fp-nan-payload HEX: 8000000000000 bitand zero? ] [ drop f ] if ;
-
-M: float fp-infinity?
- dup fp-special? [ fp-nan-payload zero? ] [ drop f ] if ;
+M: object fp-special? drop f ; inline
+M: object fp-nan? drop f ; inline
+M: object fp-qnan? drop f ; inline
+M: object fp-snan? drop f ; inline
+M: object fp-infinity? drop f ; inline
+M: object fp-nan-payload drop f ; inline
: <fp-nan> ( payload -- nan )
- HEX: 7ff0000000000000 bitor bits>double ; foldable flushable
+ HEX: 7ff0000000000000 bitor bits>double ; inline
-: next-float ( m -- n )
- double>bits
- dup -0.0 double>bits > [ 1 - bits>double ] [ ! negative non-zero
- dup -0.0 double>bits = [ drop 0.0 ] [ ! negative zero
- 1 + bits>double ! positive
- ] if
- ] if ; foldable flushable
-
-: prev-float ( m -- n )
- double>bits
- dup -0.0 double>bits >= [ 1 + bits>double ] [ ! negative
- dup 0.0 double>bits = [ drop -0.0 ] [ ! positive zero
- 1 - bits>double ! positive non-zero
- ] if
- ] if ; foldable flushable
+GENERIC: next-float ( m -- n )
+GENERIC: prev-float ( m -- n )
: next-power-of-2 ( m -- n )
dup 2 <= [ drop 2 ] [ 1 - log2 1 + 2^ ] if ; inline
{ $subsection "order-specifiers" }
"Utilities for comparing objects:"
{ $subsection after? }
-{ $subsection after? }
{ $subsection before? }
{ $subsection after=? }
{ $subsection before=? }
: >=< ( obj1 obj2 -- >=< ) <=> invert-comparison ; inline
-M: real <=> 2dup < [ 2drop +lt+ ] [ number= +eq+ +gt+ ? ] if ;
+M: real <=> 2dup < [ 2drop +lt+ ] [ number= +eq+ +gt+ ? ] if ; inline
GENERIC: before? ( obj1 obj2 -- ? )
GENERIC: after? ( obj1 obj2 -- ? )
GENERIC: before=? ( obj1 obj2 -- ? )
GENERIC: after=? ( obj1 obj2 -- ? )
-M: object before? ( obj1 obj2 -- ? ) <=> +lt+ eq? ;
-M: object after? ( obj1 obj2 -- ? ) <=> +gt+ eq? ;
-M: object before=? ( obj1 obj2 -- ? ) <=> +gt+ eq? not ;
-M: object after=? ( obj1 obj2 -- ? ) <=> +lt+ eq? not ;
+M: object before? ( obj1 obj2 -- ? ) <=> +lt+ eq? ; inline
+M: object after? ( obj1 obj2 -- ? ) <=> +gt+ eq? ; inline
+M: object before=? ( obj1 obj2 -- ? ) <=> +gt+ eq? not ; inline
+M: object after=? ( obj1 obj2 -- ? ) <=> +lt+ eq? not ; inline
-M: real before? ( obj1 obj2 -- ? ) < ;
-M: real after? ( obj1 obj2 -- ? ) > ;
-M: real before=? ( obj1 obj2 -- ? ) <= ;
-M: real after=? ( obj1 obj2 -- ? ) >= ;
+M: real before? ( obj1 obj2 -- ? ) < ; inline
+M: real after? ( obj1 obj2 -- ? ) > ; inline
+M: real before=? ( obj1 obj2 -- ? ) <= ; inline
+M: real after=? ( obj1 obj2 -- ? ) >= ; inline
-: min ( x y -- z ) [ before? ] most ; inline
+: min ( x y -- z ) [ before? ] most ; inline
: max ( x y -- z ) [ after? ] most ; inline
: clamp ( x min max -- y ) [ max ] dip min ; inline
[ "e" string>number ]
unit-test
+[ 100000 ]
+[ "100,000" string>number ]
+unit-test
+
+[ 100000.0 ]
+[ "100,000.0" string>number ]
+unit-test
+
[ "100.0" ]
[ "1.0e2" string>number number>string ]
unit-test
{ CHAR: d 13 }
{ CHAR: e 14 }
{ CHAR: f 15 }
- } at 255 or ; inline
+ { CHAR: , f }
+ } at* [ drop 255 ] unless ; inline
: string>digits ( str -- digits )
[ digit> ] B{ } map-as ; inline
: (digits>integer) ( valid? accum digit radix -- valid? accum )
- 2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if ; inline
+ over [
+ 2dup < [ swapd * + ] [ 2drop 2drop f 0 ] if
+ ] [ 2drop ] if ; inline
: each-digit ( seq radix quot -- n/f )
[ t 0 ] 3dip curry each swap [ drop f ] unless ; inline
] if ; inline
: string>float ( str -- n/f )
+ [ CHAR: , eq? not ] filter
>byte-array 0 suffix (string>float) ;
PRIVATE>
[
dup 0 < negative? set
abs 1 /mod
- [ dup zero? [ drop "" ] [ (>base) sign append ] if ]
+ [ [ "" ] [ (>base) sign append ] if-zero ]
[
[ numerator (>base) ]
[ denominator (>base) ] bi
HELP: gc ( -- )
{ $description "Performs a full garbage collection." } ;
-HELP: data-room ( -- cards generations )
-{ $values { "cards" "number of bytes reserved for card marking" } { "generations" "array of free/total bytes pairs" } }
+HELP: data-room ( -- cards decks generations )
+{ $values { "cards" "number of kilobytes reserved for card marking" } { "decks" "number of kilobytes reserved for decks of cards" } { "generations" "array of free/total kilobytes pairs" } }
{ $description "Queries the runtime for memory usage information." } ;
-HELP: code-room ( -- code-free code-total )
-{ $values { "code-free" "bytes free in the code heap" } { "code-total" "total bytes in the code heap" } }
+HELP: code-room ( -- code-total code-used code-free largest-free-block )
+{ $values { "code-total" "total kilobytes in the code heap" } { "code-used" "kilobytes used in the code heap" } { "code-free" "kilobytes free in the code heap" } { "largest-free-block" "size of largest free block" } }
{ $description "Queries the runtime for memory usage information." } ;
HELP: size ( obj -- n )
ARTICLE: "parsing-words" "Parsing words"
"The Factor parser follows a simple recursive-descent design. The parser reads successive tokens from the input; if the token identifies a number or an ordinary word, it is added to an accumulator vector. Otherwise if the token identifies a parsing word, the parsing word is executed immediately."
$nl
-"Parsing words are defined using the a defining word:"
+"Parsing words are defined using the defining word:"
{ $subsection POSTPONE: SYNTAX: }
"Parsing words have uppercase names by convention. Here is the simplest possible parsing word; it prints a greeting at parse time:"
{ $code "SYNTAX: HELLO \"Hello world\" print ;" }
[ 3 ] [ x ] unit-test
[ 4 ] [ y ] unit-test
-[ "IN: qualified.tests FROM: qualified.tests => doesnotexist ;" eval( -- ) ]
-[ error>> no-word-error? ] must-fail-with
-
-[ "IN: qualified.tests RENAME: doesnotexist qualified.tests => blahx" eval( -- ) ]
-[ error>> no-word-error? ] must-fail-with
-
! Two similar bugs
! Replace : def with something in << >>
call
] with-scope ; inline
-SYMBOL: interactive-vocabs
-
-{
- "accessors"
- "arrays"
- "assocs"
- "combinators"
- "compiler"
- "compiler.errors"
- "compiler.units"
- "continuations"
- "debugger"
- "definitions"
- "editors"
- "help"
- "help.apropos"
- "help.lint"
- "help.vocabs"
- "inspector"
- "io"
- "io.files"
- "io.pathnames"
- "kernel"
- "listener"
- "math"
- "math.order"
- "memory"
- "namespaces"
- "parser"
- "prettyprint"
- "see"
- "sequences"
- "slicing"
- "sorting"
- "stack-checker"
- "strings"
- "syntax"
- "tools.annotations"
- "tools.crossref"
- "tools.disassembler"
- "tools.errors"
- "tools.memory"
- "tools.profiler"
- "tools.test"
- "tools.threads"
- "tools.time"
- "vocabs"
- "vocabs.loader"
- "vocabs.refresh"
- "vocabs.hierarchy"
- "words"
- "scratchpad"
-} interactive-vocabs set-global
-
-: with-interactive-vocabs ( quot -- )
- [
- <manifest> manifest set
- "scratchpad" set-current-vocab
- interactive-vocabs get only-use-vocabs
- call
- ] with-scope ; inline
-
SYMBOL: print-use-hook
print-use-hook [ [ ] ] initialize
: <sbuf> ( n -- sbuf ) 0 <string> 0 sbuf boa ; inline
M: sbuf set-nth-unsafe
- [ >fixnum ] [ >fixnum ] [ underlying>> ] tri* set-string-nth ;
+ [ >fixnum ] [ >fixnum ] [ underlying>> ] tri* set-string-nth ; inline
M: sbuf new-sequence
- drop [ 0 <string> ] [ >fixnum ] bi sbuf boa ;
+ drop [ 0 <string> ] [ >fixnum ] bi sbuf boa ; inline
: >sbuf ( seq -- sbuf ) SBUF" " clone-like ; inline
M: sbuf like
drop dup sbuf? [
dup string? [ dup length sbuf boa ] [ >sbuf ] if
- ] unless ;
+ ] unless ; inline
-M: sbuf new-resizable drop <sbuf> ;
+M: sbuf new-resizable drop <sbuf> ; inline
M: sbuf equal?
over sbuf? [ sequence= ] [ 2drop f ] if ;
-M: string new-resizable drop <sbuf> ;
+M: string new-resizable drop <sbuf> ; inline
M: string like
#! If we have a string, we're done.
2dup length eq?
[ nip dup reset-string-hashcode ] [ resize-string ] if
] [ >string ] if
- ] unless ;
+ ] unless ; inline
INSTANCE: sbuf growable
}
} ;
-{ if-empty when-empty unless-empty } related-words
-
HELP: delete-all
{ $values { "seq" "a resizable sequence" } }
{ $description "Resizes the sequence to zero length, removing all elements. Not all sequences are resizable." }
} ;
HELP: slice
-{ $class-description "A virtual sequence which presents a subrange of the elements of an underlying sequence. New instances can be created by calling " { $link <slice> } "."
+{ $class-description "A virtual sequence which presents a subrange of the elements of an underlying sequence. New instances can be created by calling " { $link <slice> } ". Convenience words are also provided for creating slices where one endpoint is the start or end of the sequence; see " { $link "sequences-slices" } " for a list."
$nl
"Slices are mutable if the underlying sequence is mutable, and mutating a slice changes the underlying sequence. However, slices cannot be resized after creation." } ;
{ "newseq" sequence } }
{ $description "Calls the quotation for every element of the sequence in order. However, the element is not passed to the quotation -- it is dropped, and the quotation produces an element of its own that is collected into a sequence of the same class as the input sequence." }
{ $examples
- { $unchecked-example "USING: prettyprint kernel sequences ;"
+ { $unchecked-example "USING: kernel prettyprint random sequences ;"
"5 [ 100 random ] replicate ."
"{ 52 10 45 81 30 }"
}
{ $examples "Get random numbers until zero is reached:"
{ $unchecked-example
"USING: random sequences prettyprint math ;"
- "100 [ random dup zero? [ drop f ] when ] follow ."
+ "100 [ random [ f ] when-zero ] follow ."
"{ 100 86 34 32 24 11 7 2 }"
} } ;
}
} ;
+HELP: assert-sequence=
+{ $values
+ { "a" sequence } { "b" sequence }
+}
+{ $description "Throws an error if all the elements of two sequences, taken pairwise, are not equal." }
+{ $notes "The sequences need not be of the same type." }
+{ $examples
+ { $example
+ "USING: prettyprint sequences ;"
+ "{ 1 2 3 } V{ 1 2 3 } assert-sequence="
+ ""
+ }
+} ;
+
ARTICLE: "sequences-unsafe" "Unsafe sequence operations"
"The " { $link nth-unsafe } " and " { $link set-nth-unsafe } " sequence protocol bypasses bounds checks for increased performance."
$nl
{ $subsection virtual@ } ;
ARTICLE: "virtual-sequences" "Virtual sequences"
-"Virtual sequences allow different ways of accessing a sequence without having to create a new sequence or a new data structure altogether. To do this, they translate the virtual index into a normal index into an underlying sequence using the " { $link "virtual-sequences-protocol" } "."
+"A virtual sequence is an implementation of the " { $link "sequence-protocol" } " which does not store its own elements, and instead computes them, either from scratch or by retrieving them from another sequence."
+$nl
+"Implementations include the following:"
+{ $list
+ { $link reversed }
+ { $link slice }
+ { $link iota }
+}
+"Virtual sequences can be implemented with the " { $link "virtual-sequences-protocol" } ", by translating an index in the virtual sequence into an index in another sequence:"
{ $subsection "virtual-sequences-protocol" } ;
ARTICLE: "sequences-integers" "Counted loops"
$nl
"More elaborate counted loops can be performed with " { $link "math.ranges" } "." ;
+ARTICLE: "sequences-if" "Control flow with sequences"
+"To reduce the boilerplate of checking if a sequence is empty, several combinators are provided."
+$nl
+"Checking if a sequence is empty:"
+{ $subsection if-empty }
+{ $subsection when-empty }
+{ $subsection unless-empty } ;
+
ARTICLE: "sequences-access" "Accessing sequence elements"
{ $subsection ?nth }
"Concise way of extracting one of the first four elements:"
{ $subsection pad-tail } ;
ARTICLE: "sequences-slices" "Subsequences and slices"
+"There are two ways to extract a subrange of elements from a sequence. The first approach creates a new sequence of the same type as the input, which does not share storage with the underlying sequence. This takes time proportional to the number of elements being extracted. The second approach creates a " { $emphasis "slice" } ", which is a virtual sequence (see " { $link "virtual-sequences" } ") sharing storage with the original sequence. Slices are constructed in constant time."
+$nl
+"Some general guidelines for choosing between the two approaches:"
+{ $list
+ "If you are using mutable state, the choice has to be made one way or another because of semantics; mutating a slice will change the underlying sequence."
+ { "Using a slice can improve algorithmic complexity. For example, if each iteration of a loop decomposes a sequence using " { $link first } " and " { $link rest } ", then the loop will run in quadratic time, relative to the length of the sequence. Using " { $link rest-slice } " changes the loop to run in linear time, since " { $link rest-slice } " does not copy any elements. Taking a slice of a slice will “collapse” the slice so to avoid the double indirection, so it is safe to use slices in recursive code." }
+ "Accessing elements from a concrete sequence (such as a string or an array) is often faster than accessing elements from a slice, because slice access entails additional indirection. However, in some cases, if the slice is immediately consumed by an iteration combinator, the compiler can eliminate the slice allocation and indirect altogether."
+ "If the slice outlives the original sequence, the original sequence will still remain in memory, since the slice will reference it. This can increase memory consumption unnecessarily."
+}
+{ $heading "Subsequence operations" }
"Extracting a subsequence:"
{ $subsection subseq }
{ $subsection head }
{ $subsection unclip-last }
{ $subsection cut }
{ $subsection cut* }
-"A " { $emphasis "slice" } " is a virtual sequence which presents as view of a subsequence of an underlying sequence:"
+{ $heading "Slice operations" }
+"The slice data type:"
{ $subsection slice }
{ $subsection slice? }
"Extracting a slice:"
{ $subsection sequence= }
{ $subsection mismatch }
{ $subsection drop-prefix }
+{ $subsection assert-sequence= }
"The " { $link <=> } " generic word performs lexicographic comparison when applied to sequences." ;
ARTICLE: "sequences-f" "The f object as a sequence"
"Using sequences for looping:"
{ $subsection "sequences-integers" }
{ $subsection "math.ranges" }
+"Using sequences for control flow:"
+{ $subsection "sequences-if" }
"For inner loops:"
{ $subsection "sequences-unsafe" } ;
[ f f ] [
{ 1 2 3 4 5 6 7 8 } [ H{ { 11 "hi" } } at ] map-find
] unit-test
+
+USE: make
+
+[ { "a" 1 "b" 1 "c" } ]
+[ 1 { "a" "b" "c" } [ [ dup , ] [ , ] interleave drop ] { } make ] unit-test
+
+[ t ] [ 0 array-capacity? ] unit-test
+[ f ] [ -1 array-capacity? ] unit-test
: new-like ( len exemplar quot -- seq )
over [ [ new-sequence ] dip call ] dip like ; inline
-M: sequence like drop ;
+M: sequence like drop ; inline
GENERIC: lengthen ( n seq -- )
GENERIC: shorten ( n seq -- )
-M: sequence lengthen 2dup length > [ set-length ] [ 2drop ] if ;
+M: sequence lengthen 2dup length > [ set-length ] [ 2drop ] if ; inline
-M: sequence shorten 2dup length < [ set-length ] [ 2drop ] if ;
+M: sequence shorten 2dup length < [ set-length ] [ 2drop ] if ; inline
: empty? ( seq -- ? ) length 0 = ; inline
GENERIC: nth-unsafe ( n seq -- elt ) flushable
GENERIC: set-nth-unsafe ( elt n seq -- )
-M: sequence nth bounds-check nth-unsafe ;
-M: sequence set-nth bounds-check set-nth-unsafe ;
+M: sequence nth bounds-check nth-unsafe ; inline
+M: sequence set-nth bounds-check set-nth-unsafe ; inline
-M: sequence nth-unsafe nth ;
-M: sequence set-nth-unsafe set-nth ;
+M: sequence nth-unsafe nth ; inline
+M: sequence set-nth-unsafe set-nth ; inline
: change-nth-unsafe ( i seq quot -- )
[ [ nth-unsafe ] dip call ] 3keep drop set-nth-unsafe ; inline
! The f object supports the sequence protocol trivially
-M: f length drop 0 ;
-M: f nth-unsafe nip ;
-M: f like drop [ f ] when-empty ;
+M: f length drop 0 ; inline
+M: f nth-unsafe nip ; inline
+M: f like drop [ f ] when-empty ; inline
INSTANCE: f immutable-sequence
! Integers support the sequence protocol
-M: integer length ;
-M: integer nth-unsafe drop ;
+M: integer length ; inline
+M: integer nth-unsafe drop ; inline
INSTANCE: integer immutable-sequence
<PRIVATE
-M: iota length n>> ;
-M: iota nth-unsafe drop ;
+M: iota length n>> ; inline
+M: iota nth-unsafe drop ; inline
INSTANCE: iota immutable-sequence
GENERIC: virtual-seq ( seq -- seq' )
GENERIC: virtual@ ( n seq -- n' seq' )
-M: virtual-sequence nth virtual@ nth ;
-M: virtual-sequence set-nth virtual@ set-nth ;
-M: virtual-sequence nth-unsafe virtual@ nth-unsafe ;
-M: virtual-sequence set-nth-unsafe virtual@ set-nth-unsafe ;
-M: virtual-sequence like virtual-seq like ;
-M: virtual-sequence new-sequence virtual-seq new-sequence ;
+M: virtual-sequence nth virtual@ nth ; inline
+M: virtual-sequence set-nth virtual@ set-nth ; inline
+M: virtual-sequence nth-unsafe virtual@ nth-unsafe ; inline
+M: virtual-sequence set-nth-unsafe virtual@ set-nth-unsafe ; inline
+M: virtual-sequence like virtual-seq like ; inline
+M: virtual-sequence new-sequence virtual-seq new-sequence ; inline
INSTANCE: virtual-sequence sequence
C: <reversed> reversed
-M: reversed virtual-seq seq>> ;
-
-M: reversed virtual@ seq>> [ length swap - 1 - ] keep ;
-
-M: reversed length seq>> length ;
+M: reversed virtual-seq seq>> ; inline
+M: reversed virtual@ seq>> [ length swap - 1 - ] keep ; inline
+M: reversed length seq>> length ; inline
INSTANCE: reversed virtual-sequence
check-slice
slice boa ; inline
-M: slice virtual-seq seq>> ;
+M: slice virtual-seq seq>> ; inline
-M: slice virtual@ [ from>> + ] [ seq>> ] bi ;
+M: slice virtual@ [ from>> + ] [ seq>> ] bi ; inline
-M: slice length [ to>> ] [ from>> ] bi - ;
+M: slice length [ to>> ] [ from>> ] bi - ; inline
: short ( seq n -- seq n' ) over length min ; inline
C: <repetition> repetition
-M: repetition length len>> ;
-M: repetition nth-unsafe nip elt>> ;
+M: repetition length len>> ; inline
+M: repetition nth-unsafe nip elt>> ; inline
INSTANCE: repetition immutable-sequence
<PRIVATE
+ERROR: integer-length-expected obj ;
+
: check-length ( n -- n )
#! Ricing.
- dup integer? [ "length not an integer" throw ] unless ; inline
+ dup integer? [ integer-length-expected ] unless ; inline
: ((copy)) ( dst i src j n -- dst i src j n )
dup -roll [
(copy) drop ; inline
M: sequence clone-like
- [ dup length ] dip new-sequence [ 0 swap copy ] keep ;
+ [ dup length ] dip new-sequence [ 0 swap copy ] keep ; inline
-M: immutable-sequence clone-like like ;
+M: immutable-sequence clone-like like ; inline
: push-all ( src dest -- ) [ length ] [ copy ] bi ;
<PRIVATE
+: ((each)) ( seq -- n quot )
+ [ length ] keep [ nth-unsafe ] curry ; inline
+
: (each) ( seq quot -- n quot' )
- [ [ length ] keep [ nth-unsafe ] curry ] dip compose ; inline
+ [ ((each)) ] dip compose ; inline
+
+: (each-index) ( seq quot -- n quot' )
+ [ ((each)) [ keep ] curry ] dip compose ; inline
: (collect) ( quot into -- quot' )
[ [ keep ] dip set-nth-unsafe ] 2curry ; inline
: reduce ( seq identity quot -- result )
swapd each ; inline
+: map-integers ( len quot exemplar -- newseq )
+ [ over ] dip [ [ collect ] keep ] new-like ; inline
+
: map-as ( seq quot exemplar -- newseq )
- [ over length ] dip [ [ map-into ] keep ] new-like ; inline
+ [ (each) ] dip map-integers ; inline
: map ( seq quot -- newseq )
over map-as ; inline
[ -rot ] dip 2each ; inline
: 2map-as ( seq1 seq2 quot exemplar -- newseq )
- [ (2each) ] dip map-as ; inline
+ [ (2each) ] dip map-integers ; inline
: 2map ( seq1 seq2 quot -- newseq )
pick 2map-as ; inline
(3each) each ; inline
: 3map-as ( seq1 seq2 seq3 quot exemplar -- newseq )
- [ (3each) ] dip map-as ; inline
+ [ (3each) ] dip map-integers ; inline
: 3map ( seq1 seq2 seq3 quot -- newseq )
[ pick ] dip swap 3map-as ; inline
: follow ( obj quot -- seq )
[ dup ] swap [ keep ] curry produce nip ; inline
-: prepare-index ( seq quot -- seq n quot )
- [ dup length ] dip ; inline
-
: each-index ( seq quot -- )
- prepare-index 2each ; inline
+ (each-index) each-integer ; inline
: interleave ( seq between quot -- )
- swap [ drop ] [ [ 2dip call ] 2curry ] 2bi
- [ [ 0 = ] 2dip if ] 2curry
- each-index ; inline
+ pick empty? [ 3drop ] [
+ [ [ drop first-unsafe ] dip call ]
+ [ [ rest-slice ] 2dip [ bi* ] 2curry each ]
+ 3bi
+ ] if ; inline
: map-index ( seq quot -- newseq )
- prepare-index 2map ; inline
+ [ dup length iota ] dip 2map ; inline
: reduce-index ( seq identity quot -- )
swapd each-index ; inline
: last ( seq -- elt ) [ length 1 - ] [ nth ] bi ;
+: set-last ( elt seq -- ) [ length 1 - ] keep set-nth ;
+
: pop* ( seq -- ) [ length 1 - ] [ shorten ] bi ;
<PRIVATE
3tri ;
: reverse-here ( seq -- )
- [ length 2/ ] [ length ] [ ] tri
+ [ length 2/ iota ] [ length ] [ ] tri
[ [ over - 1 - ] dip exchange-unsafe ] 2curry each ;
: reverse ( seq -- newseq )
<PRIVATE
: (start) ( subseq seq n -- subseq seq ? )
- pick length [
+ pick length iota [
[ 3dup ] dip [ + swap nth-unsafe ] keep rot nth-unsafe =
] all? nip ; inline
PRIVATE>
: start* ( subseq seq n -- i )
- pick length pick length swap - 1 +
+ pick length pick length swap - 1 + iota
[ (start) ] find-from
swap [ 3drop ] dip ;
<PRIVATE
: generic-flip ( matrix -- newmatrix )
- [ dup first length [ length min ] reduce ] keep
+ [ dup first length [ length min ] reduce iota ] keep
[ [ nth-unsafe ] with { } map-as ] curry { } map-as ; inline
USE: arrays
: array-flip ( matrix -- newmatrix )
{ array } declare
- [ dup first array-length [ array-length min ] reduce ] keep
- [ [ array-nth ] with { } map-as ] curry { } map-as ;
+ [ dup first array-length [ array-length min ] reduce iota ] keep
+ [ [ { array } declare array-nth ] with { } map-as ] curry { } map-as ;
PRIVATE>
-USING: kernel help.markup help.syntax sequences quotations assocs ;
+USING: assocs hashtables help.markup help.syntax kernel
+quotations sequences ;
IN: sets
ARTICLE: "sets" "Set-theoretic operations on sequences"
"Adding elements to sets:"
{ $subsection adjoin }
{ $subsection conjoin }
+{ $subsection conjoin-at }
{ $see-also member? memq? any? all? "assocs-sets" } ;
ABOUT: "sets"
}
{ $side-effects "assoc" } ;
+HELP: conjoin-at
+{ $values { "value" object } { "key" object } { "assoc" assoc } }
+{ $description "Adds " { $snippet "value" } " to the set stored at " { $snippet "key" } " of " { $snippet "assoc" } "." } ;
+
HELP: unique
{ $values { "seq" "a sequence" } { "assoc" assoc } }
{ $description "Outputs a new assoc where the keys and values are equal." }
{ "seq" sequence } { "quot" quotation }
{ "newseq" sequence } }
{ $description "Maps a quotation onto a sequence, concatenates the results of the mapping, and removes duplicates." } ;
+
[ f ] [ { } { 1 } intersects? ] unit-test
[ f ] [ { 1 } { } intersects? ] unit-test
+
: conjoin ( elt assoc -- ) dupd set-at ;
+: conjoin-at ( value key assoc -- )
+ [ dupd ?set-at ] change-at ;
+
: (prune) ( elt hash vec -- )
3dup drop key? [ 3drop ] [
[ drop conjoin ] [ nip push ] 3bi
-IN: slots.tests
USING: math accessors slots strings generic.single kernel
tools.test generic words parser eval math.functions ;
+IN: slots.tests
TUPLE: r/w-test foo ;
[ "xyz" 4 >>length ] [ no-method? ] must-fail-with
-[ t ] [ r/o-test \ foo>> method "foldable" word-prop ] unit-test
-[ t ] [ r/o-test \ foo>> method "flushable" word-prop ] unit-test
-
-[ f ] [ r/w-test \ foo>> method "foldable" word-prop ] unit-test
-[ t ] [ r/w-test \ foo>> method "flushable" word-prop ] unit-test
-
-! See if declarations are cleared on redefinition
-[ ] [ "IN: slots.tests TUPLE: r/w-test { foo read-only } ;" eval( -- ) ] unit-test
-
-[ t ] [ r/w-test \ foo>> method "foldable" word-prop ] unit-test
-[ t ] [ r/w-test \ foo>> method "flushable" word-prop ] unit-test
-
-[ ] [ "IN: slots.tests TUPLE: r/w-test foo ;" eval( -- ) ] unit-test
-
-[ f ] [ r/w-test \ foo>> method "foldable" word-prop ] unit-test
-[ t ] [ r/w-test \ foo>> method "flushable" word-prop ] unit-test
-
! Test protocol slots
SLOT: my-protocol-slot-test
T{ protocol-slot-test-tuple { x 3 } } clone
[ 7 + ] change-my-protocol-slot-test x>>
] unit-test
+
+UNION: comme-ci integer float ;
+UNION: comme-ca integer float ;
+comme-ca 25.5 "initial-value" set-word-prop
+
+[ 0 ] [ comme-ci initial-value ] unit-test
+[ 25.5 ] [ comme-ca initial-value ] unit-test
[ create-method ] 2dip
[ [ props>> ] [ drop ] [ ] tri* update ]
[ drop define ]
- 3bi ;
+ [ 2drop make-inline ]
+ 3tri ;
-: reader-quot ( slot-spec -- quot )
- [
+GENERIC# reader-quot 1 ( class slot-spec -- quot )
+
+M: object reader-quot
+ nip [
dup offset>> ,
\ slot ,
dup class>> object bootstrap-word eq?
dup t "reader" set-word-prop ;
: reader-props ( slot-spec -- assoc )
- [
- [ "reading" set ]
- [ read-only>> [ t "foldable" set ] when ] bi
- t "flushable" set
- ] H{ } make-assoc ;
+ "reading" associate ;
: define-reader-generic ( name -- )
reader-word (( object -- value )) define-simple-generic ;
: define-reader ( class slot-spec -- )
[ nip name>> define-reader-generic ]
[
- [ name>> reader-word ] [ reader-quot ] [ reader-props ] tri
- define-typecheck
+ {
+ [ drop ]
+ [ nip name>> reader-word ]
+ [ reader-quot ]
+ [ nip reader-props ]
+ } 2cleave define-typecheck
] 2bi ;
: writer-word ( name -- word )
: writer-quot/fixnum ( slot-spec -- )
[ [ >fixnum ] dip ] % writer-quot/check ;
-: writer-quot ( slot-spec -- quot )
- [
+GENERIC# writer-quot 1 ( class slot-spec -- quot )
+
+M: object writer-quot
+ nip [
{
{ [ dup class>> object bootstrap-word eq? ] [ writer-quot/object ] }
{ [ dup class>> "coercer" word-prop ] [ writer-quot/coerce ] }
: define-writer ( class slot-spec -- )
[ nip name>> define-writer-generic ] [
- [ name>> writer-word ] [ writer-quot ] [ writer-props ] tri
- define-typecheck
+ {
+ [ drop ]
+ [ nip name>> writer-word ]
+ [ writer-quot ]
+ [ nip writer-props ]
+ } 2cleave define-typecheck
] 2bi ;
: setter-word ( name -- word )
: initial-value ( class -- object )
{
+ { [ dup "initial-value" word-prop ] [ dup "initial-value" word-prop ] }
{ [ \ f bootstrap-word over class<= ] [ f ] }
{ [ \ array-capacity bootstrap-word over class<= ] [ 0 ] }
{ [ float bootstrap-word over class<= ] [ 0.0 ] }
: finalize-slots ( specs base -- specs )
over length iota [ + ] with map [ >>offset ] 2map ;
+: slot-named* ( name specs -- offset spec/f )
+ [ name>> = ] with find ;
+
: slot-named ( name specs -- spec/f )
- [ name>> = ] with find nip ;
+ slot-named* nip ;
"Sorting a sequence with a custom comparator:"
{ $subsection sort }
"Sorting a sequence with common comparators:"
+{ $subsection sort-with }
+{ $subsection inv-sort-with }
{ $subsection natural-sort }
{ $subsection sort-keys }
{ $subsection sort-values } ;
HELP: sort
{ $values { "seq" "a sequence" } { "quot" { $quotation "( obj1 obj2 -- <=> )" } } { "sortedseq" "a new sorted sequence" } }
-{ $description "Sorts the elements into a new array using a stable sort." }
+{ $description "Sorts the elements of " { $snippet "seq" } " into a new array using a stable sort." }
{ $notes "The algorithm used is the merge sort." } ;
+HELP: sort-with
+{ $values { "seq" "a sequence" } { "quot" { $quotation "( object -- key )" } } { "sortedseq" "a new sorted sequence" } }
+{ $description "Sorts the elements of " { $snippet "seq" } " by applying " { $link compare } " with " { $snippet "quot" } " to each pair of elements in the sequence." } ;
+
+HELP: inv-sort-with
+{ $values { "seq" "a sequence" } { "quot" { $quotation "( object -- key )" } } { "sortedseq" "a new sorted sequence" } }
+{ $description "Sorts the elements of " { $snippet "seq" } " by applying " { $link compare } " with " { $snippet "quot" } " to each pair of elements in the sequence and inverting the results." } ;
+
HELP: sort-keys
{ $values { "seq" "an alist" } { "sortedseq" "a new sorted sequence" } }
-{ $description "Sorts the elements comparing first elements of pairs using the " { $link <=> } " word." } ;
+{ $description "Sorts the elements of " { $snippet "seq" } " comparing first elements of pairs using the " { $link <=> } " word." } ;
HELP: sort-values
{ $values { "seq" "an alist" } { "sortedseq" "a new sorted sequence" } }
-{ $description "Sorts the elements comparing second elements of pairs using the " { $link <=> } " word." } ;
+{ $description "Sorts the elements of " { $snippet "seq" } " comparing second elements of pairs using the " { $link <=> } " word." } ;
HELP: natural-sort
{ $values { "seq" "a sequence of real numbers" } { "sortedseq" "a new sorted sequence" } }
{ $values { "seq" "a sequence" } { "n" integer } }
{ $description "Outputs the index of the midpoint of " { $snippet "seq" } "." } ;
-{ <=> compare natural-sort sort-keys sort-values } related-words
+{ <=> compare natural-sort sort-with inv-sort-with sort-keys sort-values } related-words
: natural-sort ( seq -- sortedseq ) [ <=> ] sort ;
-: sort-keys ( seq -- sortedseq ) [ [ first ] compare ] sort ;
+: sort-with ( seq quot -- sortedseq )
+ [ compare ] curry sort ; inline
+: inv-sort-with ( seq quot -- sortedseq )
+ [ compare invert-comparison ] curry sort ; inline
-: sort-values ( seq -- sortedseq ) [ [ second ] compare ] sort ;
+: sort-keys ( seq -- sortedseq ) [ first ] sort-with ;
+
+: sort-values ( seq -- sortedseq ) [ second ] sort-with ;
: sort-pair ( a b -- c d ) 2dup after? [ swap ] when ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs kernel math.order sorting sequences definitions
-namespaces arrays splitting io math.parser math init ;
+namespaces arrays splitting io math.parser math init continuations ;
IN: source-files.errors
+GENERIC: error-file ( error -- file )
+GENERIC: error-line ( error -- line )
+
+M: object error-file drop f ;
+M: object error-line drop f ;
+
+M: condition error-file error>> error-file ;
+M: condition error-line error>> error-line ;
+
TUPLE: source-file-error error asset file line# ;
+M: source-file-error error-file [ error>> error-file ] [ file>> ] bi or ;
+M: source-file-error error-line [ error>> error-line ] [ line#>> ] bi or ;
+
: sort-errors ( errors -- alist )
- [ [ [ line#>> ] compare ] sort ] { } assoc-map-as sort-keys ;
+ [ [ line#>> ] sort-with ] { } assoc-map-as sort-keys ;
: group-by-source-file ( errors -- assoc )
H{ } clone [ [ push-at ] curry [ dup file>> ] prepose each ] keep ;
: (split) ( separators n seq -- )
3dup rot [ member? ] curry find-from drop
[ [ swap subseq , ] 2keep 1 + swap (split) ]
- [ swap dup zero? [ drop ] [ tail ] if , drop ] if* ; inline recursive
+ [ swap [ tail ] unless-zero , drop ] if* ; inline recursive
: split, ( seq separators -- ) 0 rot (split) ;
[ ] [ dup rehash-string string-hashcode ] ?if ;
M: string length
- length>> ;
+ length>> ; inline
M: string nth-unsafe
- [ >fixnum ] dip string-nth ;
+ [ >fixnum ] dip string-nth ; inline
M: string set-nth-unsafe
dup reset-string-hashcode
- [ >fixnum ] [ >fixnum ] [ ] tri* set-string-nth ;
+ [ >fixnum ] [ >fixnum ] [ ] tri* set-string-nth ; inline
M: string clone
- (clone) [ clone ] change-aux ;
+ (clone) [ clone ] change-aux ; inline
-M: string resize resize-string ;
+M: string resize resize-string ; inline
: 1string ( ch -- str ) 1 swap <string> ;
: >string ( seq -- str ) "" clone-like ;
-M: string new-sequence drop 0 <string> ;
+M: string new-sequence drop 0 <string> ; inline
INSTANCE: string sequence
{ $syntax ": foo ... ; delimiter" }
{ $description "Declares the most recently defined word as a delimiter. Delimiters are words which are only ever valid as the end of a nested block to be read by " { $link parse-until } ". An unpaired occurrence of a delimiter is a parse error." } ;
+HELP: deprecated
+{ $syntax ": foo ... ; deprecated" }
+{ $description "Declares the most recently defined word as deprecated. If the " { $vocab-link "tools.deprecation" } " vocabulary is loaded, usages of deprecated words will be noted by the " { $link "tools.errors" } " system." }
+{ $notes "Code that uses deprecated words continues to function normally; the errors are purely informational. However, code that uses deprecated words should be updated, for the deprecated words are intended to be removed soon." } ;
+
HELP: SYNTAX:
{ $syntax "SYNTAX: foo ... ;" }
{ $description "Defines a parsing word." }
HELP: QUALIFIED:
{ $syntax "QUALIFIED: vocab" }
{ $description "Adds the vocabulary's words, prefixed with the vocabulary name, to the search path." }
-{ $notes "If adding the vocabulary introduces ambiguity, the vocabulary will take precedence when resolving any ambiguous names. This is a rare case; for example, suppose a vocabulary " { $snippet "fish" } " defines a word named " { $snippet "go:fishing" } ", and a vocabulary named " { $snippet "go" } " defines a word named " { $snippet "finishing" } ". Then, the following will call the latter word:"
+{ $notes "If adding the vocabulary introduces ambiguity, the vocabulary will take precedence when resolving any ambiguous names. This is a rare case; for example, suppose a vocabulary " { $snippet "fish" } " defines a word named " { $snippet "go:fishing" } ", and a vocabulary named " { $snippet "go" } " defines a word named " { $snippet "fishing" } ". Then, the following will call the latter word:"
{ $code
"USE: fish"
"QUALIFIED: go"
"foldable" [ word make-foldable ] define-core-syntax
"flushable" [ word make-flushable ] define-core-syntax
"delimiter" [ word t "delimiter" set-word-prop ] define-core-syntax
+ "deprecated" [ word make-deprecated ] define-core-syntax
"SYNTAX:" [
CREATE-WORD parse-definition define-syntax
] define-core-syntax
"initial:" "syntax" lookup define-symbol
-
+
"read-only" "syntax" lookup define-symbol
"call(" [ \ call-effect parse-call( ] define-core-syntax
M: vector like
drop dup vector? [
dup array? [ dup length vector boa ] [ >vector ] if
- ] unless ;
+ ] unless ; inline
M: vector new-sequence
- drop [ f <array> ] [ >fixnum ] bi vector boa ;
+ drop [ f <array> ] [ >fixnum ] bi vector boa ; inline
M: vector equal?
over vector? [ sequence= ] [ 2drop f ] if ;
2dup length eq?
[ nip ] [ resize-array ] if
] [ >array ] if
- ] unless ;
+ ] unless ; inline
-M: sequence new-resizable drop <vector> ;
+M: sequence new-resizable drop <vector> ; inline
INSTANCE: vector growable
"Words for working with the current manifest:"
{ $subsection use-vocab }
{ $subsection unuse-vocab }
-{ $subsection only-use-vocabs }
{ $subsection add-qualified }
{ $subsection add-words-from }
{ $subsection add-words-excluding }
{ $description "Removes a vocabulary from the current manifest." }
{ $notes "This word is used to implement " { $link POSTPONE: UNUSE: } "." } ;
-HELP: only-use-vocabs
-{ $values { "vocabs" "a sequence of vocabulary specifiers" } }
-{ $description "Replaces the current manifest's vocabulary search path with the given set of vocabularies." } ;
-
HELP: add-qualified
{ $values { "vocab" "a vocabulary specifier" } { "prefix" string } }
{ $description "Adds the vocabulary's words, prefixed with the given string, to the current manifest." }
--- /dev/null
+IN: vocabs.parser.tests
+USING: vocabs.parser tools.test eval kernel accessors ;
+
+[ "FROM: kernel => doesnotexist ;" eval( -- ) ]
+[ error>> T{ no-word-in-vocab { word "doesnotexist" } { vocab "kernel" } } = ]
+must-fail-with
+
+[ "RENAME: doesnotexist kernel => newname" eval( -- ) ]
+[ error>> T{ no-word-in-vocab { word "doesnotexist" } { vocab "kernel" } } = ]
+must-fail-with
\ No newline at end of file
C: <extra-words> extra-words
-<PRIVATE
-
: clear-manifest ( -- )
manifest get
[ search-vocab-names>> clear-assoc ]
[ qualified-vocabs>> delete-all ]
tri ;
+ERROR: no-word-in-vocab word vocab ;
+
+<PRIVATE
+
: (add-qualified) ( qualified -- )
manifest get qualified-vocabs>> push ;
-: (from) ( vocab words -- vocab words words' assoc )
- 2dup swap load-vocab words>> ;
+: (from) ( vocab words -- vocab words words' vocab )
+ 2dup swap load-vocab ;
-: extract-words ( seq assoc -- assoc' )
- extract-keys dup [ [ drop ] [ no-word-error ] if ] assoc-each ;
+: extract-words ( seq vocab -- assoc' )
+ [ words>> extract-keys dup ] [ name>> ] bi
+ [ swap [ 2drop ] [ no-word-in-vocab ] if ] curry assoc-each ;
: (lookup) ( name assoc -- word/f )
at dup forward-reference? [ drop f ] when ;
2bi
] [ drop ] if ;
-: only-use-vocabs ( vocabs -- )
- clear-manifest [ vocab ] filter [ use-vocab ] each ;
-
TUPLE: qualified vocab prefix words ;
: <qualified> ( vocab prefix -- qualified )
TUPLE: exclude vocab names words ;
: <exclude> ( vocab words -- from )
- (from) [ nip ] [ extract-words ] 2bi assoc-diff exclude boa ;
+ (from) [ nip words>> ] [ extract-words ] 2bi assoc-diff exclude boa ;
: add-words-excluding ( vocab words -- )
<exclude> (add-qualified) ;
TUPLE: rename word vocab words ;
: <rename> ( word vocab new-name -- rename )
- [ 2dup load-vocab words>> dupd at [ ] [ no-word-error ] ?if ] dip
+ [ 2dup load-vocab words>> dupd at [ ] [ swap no-word-in-vocab ] ?if ] dip
associate rename boa ;
: add-renamed-word ( word vocab new-name -- )
HELP: define-declared
{ $values { "word" word } { "def" quotation } { "effect" effect } }
{ $description "Defines a word and declares its stack effect." }
+{ $notes "This word must be called from inside " { $link with-compilation-unit } "." }
{ $side-effects "word" } ;
HELP: define-temp
{ $description "Tests if an object is a delimiter word declared by " { $link POSTPONE: delimiter } "." }
{ $notes "Outputs " { $link f } " if the object is not a word." } ;
+HELP: deprecated?
+{ $values { "obj" object } { "?" "a boolean" } }
+{ $description "Tests if an object is " { $link POSTPONE: deprecated } "." }
+{ $notes "Outputs " { $link f } " if the object is not a word." } ;
+
+HELP: make-deprecated
+{ $values { "word" word } }
+{ $description "Declares a word as " { $link POSTPONE: deprecated } "." }
+{ $side-effects "word" } ;
+
HELP: make-flushable
{ $values { "word" word } }
{ $description "Declares a word as " { $link POSTPONE: flushable } "." }
HELP: define-inline
{ $values { "word" word } { "def" quotation } { "effect" effect } }
{ $description "Defines a word and makes it " { $link POSTPONE: inline } "." }
+{ $notes "This word must be called from inside " { $link with-compilation-unit } "." }
{ $side-effects "word" } ;
[
all-words [
"compiled-uses" word-prop
- keys [ "forgotten" word-prop ] any?
- ] filter
+ keys [ "forgotten" word-prop ] filter
+ ] map harvest
] unit-test
M: word execute (execute) ;
-M: word ?execute execute( -- value ) ;
+M: word ?execute execute( -- value ) ; inline
M: word <=>
[ [ name>> ] [ vocabulary>> ] bi 2array ] compare ;
: define-declared ( word def effect -- )
[ nip swap set-stack-effect ] [ drop define ] 3bi ;
+: make-deprecated ( word -- )
+ t "deprecated" set-word-prop ;
+
: make-inline ( word -- )
dup inline? [ drop ] [
[ t "inline" set-word-prop ]
{
"unannotated-def" "parsing" "inline" "recursive"
"foldable" "flushable" "reading" "writing" "reader"
- "writer" "delimiter"
+ "writer" "delimiter" "deprecated"
} reset-props ;
: reset-generic ( word -- )
: delimiter? ( obj -- ? )
dup word? [ "delimiter" word-prop ] [ drop f ] if ;
+: deprecated? ( obj -- ? )
+ dup word? [ "deprecated" word-prop ] [ drop f ] if ;
+
! Definition protocol
M: word where "loc" word-prop ;
] if ;
M: word hashcode*
- nip 1 slot { fixnum } declare ; foldable
+ nip 1 slot { fixnum } declare ; inline foldable
M: word literalize <wrapper> ;
-INSTANCE: word definition
\ No newline at end of file
+INSTANCE: word definition
\r
: with-pv ( i quot -- ) [ swap >pv call ] with-scope ; inline\r
\r
-: dimension ( array -- x ) length 1- ; inline \r
+: dimension ( array -- x ) length 1 - ; inline \r
: change-last ( seq quot -- ) \r
[ [ dimension ] keep ] dip change-nth ; inline\r
\r
: point-inside-or-on-halfspace? ( halfspace v -- ? ) \r
position-point VERY-SMALL-NUM neg > ;\r
: project-vector ( seq -- seq ) \r
- pv> [ head ] [ 1+ tail ] 2bi append ; \r
+ pv> [ head ] [ 1 + tail ] 2bi append ; \r
: get-intersection ( matrice -- seq ) \r
[ 1 tail* ] map flip first ;\r
\r
: compute-adjacencies ( solid -- solid )\r
dup dimension>> [ >= ] curry \r
[ keep swap ] curry MAX-FACE-PER-CORNER swap\r
- [ [ test-faces-combinaisons ] 2keep 1- ] while drop ;\r
+ [ [ test-faces-combinaisons ] 2keep 1 - ] while drop ;\r
\r
: find-adjacencies ( solid -- solid ) \r
erase-old-adjacencies \r
[ [ non-empty-solid? ] filter ] change-solids ;\r
\r
: projected-space ( space solids -- space ) \r
- swap dimension>> 1- <space> \r
+ swap dimension>> 1 - <space> \r
swap >>dimension swap >>solids ;\r
\r
: get-silhouette ( solid -- silhouette ) \r
! { [ dup 0 = ] [ 2drop { { } } ] }\r
! { [ over empty? ] [ 2drop { } ] }\r
! { [ t ] [ \r
-! [ [ 1- (combinations) ] [ drop first ] 2bi prefix-each ]\r
+! [ [ 1 - (combinations) ] [ drop first ] 2bi prefix-each ]\r
! [ (combinations) ] 2bi append\r
! ] }\r
! } cond ;\r
{ [ over 1 = ] [ 3drop columnize ] }\r
{ [ over 0 = ] [ 2drop 2drop { } ] }\r
{ [ 2dup < ] [ 2drop [ 1 cut ] dip \r
- [ 1- among [ append ] with map ] \r
+ [ 1 - among [ append ] with map ] \r
[ among append ] 2bi\r
] }\r
{ [ 2dup = ] [ 3drop 1array ] }\r
: do-row ( exchange-with row# -- )\r
[ exchange-rows ] keep\r
[ first-col ] keep\r
- dup 1+ rows-from clear-col ;\r
+ dup 1 + rows-from clear-col ;\r
\r
: find-row ( row# quot -- i elt )\r
[ rows-from ] dip find ; inline\r
\r
: (echelon) ( col# row# -- )\r
over cols < over rows < and [\r
- 2dup pivot-row [ over do-row 1+ ] when*\r
- [ 1+ ] dip (echelon)\r
+ 2dup pivot-row [ over do-row 1 + ] when*\r
+ [ 1 + ] dip (echelon)\r
] [\r
2drop\r
] if ;\r
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.cxx.parser alien.marshall
+alien.inline.types classes.mixin classes.tuple kernel namespaces
+assocs sequences parser classes.parser alien.marshall.syntax
+interpolate locals effects io strings make vocabs.parser words
+generic fry quotations ;
+IN: alien.cxx
+
+<PRIVATE
+: class-mixin ( str -- word )
+ create-class-in [ define-mixin-class ] keep ;
+
+: class-tuple-word ( word -- word' )
+ "#" append create-in ;
+
+: define-class-tuple ( word mixin -- )
+ [ drop class-wrapper { } define-tuple-class ]
+ [ add-mixin-instance ] 2bi ;
+PRIVATE>
+
+: define-c++-class ( name superclass-mixin -- )
+ [ [ class-tuple-word ] [ class-mixin ] bi dup ] dip
+ add-mixin-instance define-class-tuple ;
+
+:: define-c++-method ( class-name generic name types effect virtual -- )
+ [ name % "_" % class-name { { CHAR: : CHAR: _ } } substitute % ] "" make :> name'
+ effect [ in>> "self" suffix ] [ out>> ] bi <effect> :> effect'
+ types class-name "*" append suffix :> types'
+ effect in>> "," join :> args
+ class-name virtual [ "#" append ] unless current-vocab lookup :> class
+ SBUF" " clone dup [ I[ return self->${name}(${args});]I ] with-output-stream >string :> body
+ name' types' effect' body define-c-marshalled
+ class generic create-method name' current-vocab lookup 1quotation define ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: parser lexer alien.inline ;
+IN: alien.cxx.parser
+
+: parse-c++-class-definition ( -- class superclass-mixin )
+ scan scan-word ;
+
+: parse-c++-method-definition ( -- class-name generic name types effect )
+ scan scan-word function-types-effect ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test alien.cxx.syntax alien.inline.syntax
+alien.marshall.syntax alien.marshall accessors kernel ;
+IN: alien.cxx.syntax.tests
+
+DELETE-C-LIBRARY: test
+C-LIBRARY: test
+
+COMPILE-AS-C++
+
+C-INCLUDE: <string>
+
+C-TYPEDEF: std::string string
+
+C++-CLASS: std::string c++-root
+
+GENERIC: to-string ( obj -- str )
+
+C++-METHOD: std::string to-string const-char* c_str ( )
+
+CM-FUNCTION: std::string* new_string ( const-char* s )
+ return new std::string(s);
+;
+
+;C-LIBRARY
+
+ALIAS: <std::string> new_string
+
+{ 1 1 } [ new_string ] must-infer-as
+{ 1 1 } [ c_str_std__string ] must-infer-as
+[ t ] [ "abc" <std::string> std::string? ] unit-test
+[ "abc" ] [ "abc" <std::string> to-string ] unit-test
+
+
+DELETE-C-LIBRARY: inheritance
+C-LIBRARY: inheritance
+
+COMPILE-AS-C++
+
+C-INCLUDE: <cstring>
+
+<RAW-C
+class alpha {
+ public:
+ alpha(const char* s) {
+ str = s;
+ };
+ const char* render() {
+ return str;
+ };
+ virtual const char* chop() {
+ return str;
+ };
+ virtual int length() {
+ return strlen(str);
+ };
+ const char* str;
+};
+
+class beta : alpha {
+ public:
+ beta(const char* s) : alpha(s + 1) { };
+ const char* render() {
+ return str + 1;
+ };
+ virtual const char* chop() {
+ return str + 2;
+ };
+};
+RAW-C>
+
+C++-CLASS: alpha c++-root
+C++-CLASS: beta alpha
+
+CM-FUNCTION: alpha* new_alpha ( const-char* s )
+ return new alpha(s);
+;
+
+CM-FUNCTION: beta* new_beta ( const-char* s )
+ return new beta(s);
+;
+
+ALIAS: <alpha> new_alpha
+ALIAS: <beta> new_beta
+
+GENERIC: render ( obj -- obj )
+GENERIC: chop ( obj -- obj )
+GENERIC: length ( obj -- n )
+
+C++-METHOD: alpha render const-char* render ( )
+C++-METHOD: beta render const-char* render ( )
+C++-VIRTUAL: alpha chop const-char* chop ( )
+C++-VIRTUAL: beta chop const-char* chop ( )
+C++-VIRTUAL: alpha length int length ( )
+
+;C-LIBRARY
+
+{ 1 1 } [ render_alpha ] must-infer-as
+{ 1 1 } [ chop_beta ] must-infer-as
+{ 1 1 } [ length_alpha ] must-infer-as
+[ t ] [ "x" <alpha> alpha#? ] unit-test
+[ t ] [ "x" <alpha> alpha? ] unit-test
+[ t ] [ "x" <beta> alpha? ] unit-test
+[ f ] [ "x" <beta> alpha#? ] unit-test
+[ 5 ] [ "hello" <alpha> length ] unit-test
+[ 4 ] [ "hello" <beta> length ] unit-test
+[ "hello" ] [ "hello" <alpha> render ] unit-test
+[ "llo" ] [ "hello" <beta> render ] unit-test
+[ "ello" ] [ "hello" <beta> underlying>> \ alpha# new swap >>underlying render ] unit-test
+[ "hello" ] [ "hello" <alpha> chop ] unit-test
+[ "lo" ] [ "hello" <beta> chop ] unit-test
+[ "lo" ] [ "hello" <beta> underlying>> \ alpha# new swap >>underlying chop ] unit-test
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.cxx alien.cxx.parser ;
+IN: alien.cxx.syntax
+
+SYNTAX: C++-CLASS:
+ parse-c++-class-definition define-c++-class ;
+
+SYNTAX: C++-METHOD:
+ parse-c++-method-definition f define-c++-method ;
+
+SYNTAX: C++-VIRTUAL:
+ parse-c++-method-definition t define-c++-method ;
--- /dev/null
+Jeremy Hughes
--- /dev/null
+Jeremy Hughes
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel strings words.symbol sequences ;
+IN: alien.inline.compiler
+
+HELP: C
+{ $var-description "A symbol representing C source." } ;
+
+HELP: C++
+{ $var-description "A symbol representing C++ source." } ;
+
+HELP: compile-to-library
+{ $values
+ { "lang" symbol } { "args" sequence } { "contents" string } { "name" string }
+}
+{ $description "Compiles and links " { $snippet "contents" } " into a shared library called " { $snippet "libname.suffix" }
+ "in " { $snippet "resource:alien-inline-libs" } ". " { $snippet "suffix" } " is OS specific. "
+ { $snippet "args" } " is a sequence of arguments for the linking stage." }
+{ $notes
+ { $list
+ "C and C++ are the only supported languages."
+ { "Source and object files are placed in " { $snippet "resource:temp" } "." } }
+} ;
+
+HELP: compiler
+{ $values
+ { "lang" symbol }
+ { "str" string }
+}
+{ $description "Returns a compiler name based on OS and source language." }
+{ $see-also compiler-descr } ;
+
+HELP: compiler-descr
+{ $values
+ { "lang" symbol }
+ { "descr" "a process description" }
+}
+{ $description "Returns a compiler process description based on OS and source language." }
+{ $see-also compiler } ;
+
+HELP: inline-library-file
+{ $values
+ { "name" string }
+ { "path" "a pathname string" }
+}
+{ $description "Appends " { $snippet "name" } " to the " { $link inline-libs-directory } "." } ;
+
+HELP: inline-libs-directory
+{ $values
+ { "path" "a pathname string" }
+}
+{ $description "The directory where libraries created using " { $snippet "alien.inline" } " are stored." } ;
+
+HELP: library-path
+{ $values
+ { "str" string }
+ { "path" "a pathname string" }
+}
+{ $description "Converts " { $snippet "name" } " into a full path to the corresponding inline library." } ;
+
+HELP: library-suffix
+{ $values
+ { "str" string }
+}
+{ $description "The appropriate shared library suffix for the current OS." } ;
+
+HELP: link-descr
+{ $values
+ { "lang" "a language" }
+ { "descr" sequence }
+}
+{ $description "Returns part of a process description. OS dependent." } ;
+
+ARTICLE: "alien.inline.compiler" "Inline C compiler"
+{ $vocab-link "alien.inline.compiler" }
+;
+
+ABOUT: "alien.inline.compiler"
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays combinators fry generalizations
+io.encodings.ascii io.files io.files.temp io.launcher kernel
+locals make sequences system vocabs.parser words io.directories
+io.pathnames ;
+IN: alien.inline.compiler
+
+SYMBOL: C
+SYMBOL: C++
+
+: inline-libs-directory ( -- path )
+ "alien-inline-libs" resource-path dup make-directories ;
+
+: inline-library-file ( name -- path )
+ inline-libs-directory prepend-path ;
+
+: library-suffix ( -- str )
+ os {
+ { [ dup macosx? ] [ drop ".dylib" ] }
+ { [ dup unix? ] [ drop ".so" ] }
+ { [ dup windows? ] [ drop ".dll" ] }
+ } cond ;
+
+: library-path ( str -- path )
+ '[ "lib" % _ % library-suffix % ] "" make inline-library-file ;
+
+HOOK: compiler os ( lang -- str )
+
+M: word compiler
+ {
+ { C [ "gcc" ] }
+ { C++ [ "g++" ] }
+ } case ;
+
+M: openbsd compiler
+ {
+ { C [ "gcc" ] }
+ { C++ [ "eg++" ] }
+ } case ;
+
+M: windows compiler
+ {
+ { C [ "gcc" ] }
+ { C++ [ "g++" ] }
+ } case ;
+
+HOOK: compiler-descr os ( lang -- descr )
+
+M: word compiler-descr compiler 1array ;
+M: macosx compiler-descr
+ call-next-method cpu x86.64?
+ [ { "-arch" "x86_64" } append ] when ;
+
+HOOK: link-descr os ( lang -- descr )
+
+M: word link-descr drop { "-shared" "-o" } ;
+M: macosx link-descr
+ drop { "-g" "-prebind" "-dynamiclib" "-o" }
+ cpu x86.64? [ { "-arch" "x86_64" } prepend ] when ;
+M: windows link-descr
+ {
+ { C [ { "-mno-cygwin" "-shared" "-o" } ] }
+ { C++ [ { "-lstdc++" "-mno-cygwin" "-shared" "-o" } ] }
+ } case ;
+
+<PRIVATE
+: src-suffix ( lang -- str )
+ {
+ { C [ ".c" ] }
+ { C++ [ ".cpp" ] }
+ } case ;
+
+: link-command ( args in out lang -- descr )
+ [ 2array ] dip [ compiler 1array ] [ link-descr ] bi
+ append prepend prepend ;
+
+:: compile-to-object ( lang contents name -- )
+ name ".o" append temp-file
+ contents name lang src-suffix append temp-file
+ [ ascii set-file-contents ] keep 2array
+ lang compiler-descr { "-fPIC" "-c" "-o" } append prepend
+ try-process ;
+
+:: link-object ( lang args name -- )
+ args name [ library-path ]
+ [ ".o" append temp-file ] bi
+ lang link-command try-process ;
+PRIVATE>
+
+:: compile-to-library ( lang args contents name -- )
+ lang contents name compile-to-object
+ lang args name link-object ;
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel strings effects quotations ;
+IN: alien.inline
+
+<PRIVATE
+: $binding-note ( x -- )
+ drop
+ { "This word requires that certain variables are correctly bound. "
+ "Call " { $link POSTPONE: define-c-library } " to set them up." } print-element ;
+PRIVATE>
+
+HELP: compile-c-library
+{ $description "Writes, compiles, and links code generated since last invocation of " { $link POSTPONE: define-c-library } ". "
+ "Also calls " { $snippet "add-library" } ". "
+ "This word does nothing if the shared library is younger than the factor source file." }
+{ $notes $binding-note } ;
+
+HELP: c-use-framework
+{ $values
+ { "str" string }
+}
+{ $description "OS X only. Adds " { $snippet "-framework name" } " to linker command." }
+{ $notes $binding-note }
+{ $see-also c-link-to c-link-to/use-framework } ;
+
+HELP: define-c-function
+{ $values
+ { "function" "function name" } { "types" "a sequence of C types" } { "effect" effect } { "body" string }
+}
+{ $description "Defines a C function and a factor word which calls it." }
+{ $notes
+ { $list
+ { "The number of " { $snippet "types" } " must match the " { $snippet "in" } " count of the " { $snippet "effect" } "." }
+ { "There must be only one " { $snippet "out" } " element. It must be a legal C return type with dashes (-) instead of spaces." }
+ $binding-note
+ }
+}
+{ $see-also POSTPONE: define-c-function' } ;
+
+HELP: define-c-function'
+{ $values
+ { "function" "function name" } { "effect" effect } { "body" string }
+}
+{ $description "Defines a C function and a factor word which calls it. See " { $link define-c-function } " for more information." }
+{ $notes
+ { $list
+ { "Each effect element must be a legal C type with dashes (-) instead of spaces. "
+ "C argument names will be generated alphabetically, starting with " { $snippet "a" } "." }
+ $binding-note
+ }
+}
+{ $see-also define-c-function } ;
+
+HELP: c-include
+{ $values
+ { "str" string }
+}
+{ $description "Appends an include line to the C library in scope." }
+{ $notes $binding-note } ;
+
+HELP: define-c-library
+{ $values
+ { "name" string }
+}
+{ $description "Starts a new C library scope. Other " { $snippet "alien.inline" } " words can be used after this one." } ;
+
+HELP: c-link-to
+{ $values
+ { "str" string }
+}
+{ $description "Adds " { $snippet "-lname" } " to linker command." }
+{ $notes $binding-note }
+{ $see-also c-use-framework c-link-to/use-framework } ;
+
+HELP: c-link-to/use-framework
+{ $values
+ { "str" string }
+}
+{ $description "Equivalent to " { $link c-use-framework } " on OS X and " { $link c-link-to } " everywhere else." }
+{ $notes $binding-note }
+{ $see-also c-link-to c-use-framework } ;
+
+HELP: define-c-struct
+{ $values
+ { "name" string } { "fields" "type/name pairs" }
+}
+{ $description "Defines a C struct and factor words which operate on it." }
+{ $notes $binding-note } ;
+
+HELP: define-c-typedef
+{ $values
+ { "old" "C type" } { "new" "C type" }
+}
+{ $description "Define C and factor typedefs." }
+{ $notes $binding-note } ;
+
+HELP: delete-inline-library
+{ $values
+ { "name" string }
+}
+{ $description "Delete the shared library file corresponding to " { $snippet "name" } "." }
+{ $notes "Must be executed in the vocabulary where " { $snippet "name" } " is defined. " } ;
+
+HELP: with-c-library
+{ $values
+ { "name" string } { "quot" quotation }
+}
+{ $description "Calls " { $link define-c-library } ", then the quotation, then " { $link compile-c-library } ", then sets all variables bound by " { $snippet "define-c-library" } " to " { $snippet "f" } "." } ;
+
+HELP: raw-c
+{ $values { "str" string } }
+{ $description "Insert a string into the generated source file. Useful for macros and other details not implemented in " { $snippet "alien.inline" } "." } ;
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.inline.compiler alien.inline.types
+alien.libraries alien.parser arrays assocs effects fry
+generalizations grouping io.directories io.files
+io.files.info io.files.temp kernel lexer math math.order
+math.ranges multiline namespaces sequences source-files
+splitting strings system vocabs.loader vocabs.parser words
+alien.c-types alien.structs make parser continuations ;
+IN: alien.inline
+
+SYMBOL: c-library
+SYMBOL: library-is-c++
+SYMBOL: linker-args
+SYMBOL: c-strings
+
+<PRIVATE
+: cleanup-variables ( -- )
+ { c-library library-is-c++ linker-args c-strings }
+ [ off ] each ;
+
+: arg-list ( types -- params )
+ CHAR: a swap length CHAR: a + [a,b]
+ [ 1string ] map ;
+
+: compile-library? ( -- ? )
+ c-library get library-path dup exists? [
+ file get [
+ path>>
+ [ file-info modified>> ] bi@ <=> +lt+ =
+ ] [ drop t ] if*
+ ] [ drop t ] if ;
+
+: compile-library ( -- )
+ library-is-c++ get [ C++ ] [ C ] if
+ linker-args get
+ c-strings get "\n" join
+ c-library get compile-to-library ;
+
+: c-library-name ( name -- name' )
+ [ current-vocab name>> % "_" % % ] "" make ;
+PRIVATE>
+
+: append-function-body ( prototype-str body -- str )
+ [ swap % " {\n" % % "\n}\n" % ] "" make ;
+
+: function-types-effect ( -- function types effect )
+ scan scan swap ")" parse-tokens
+ [ "(" subseq? not ] filter swap parse-arglist ;
+
+: prototype-string ( function types effect -- str )
+ [ [ cify-type ] map ] dip
+ types-effect>params-return cify-type -rot
+ [ " " join ] map ", " join
+ "(" prepend ")" append 3array " " join
+ library-is-c++ get [ "extern \"C\" " prepend ] when ;
+
+: prototype-string' ( function types return -- str )
+ [ dup arg-list ] <effect> prototype-string ;
+
+: factor-function ( function types effect -- word quot effect )
+ annotate-effect [ c-library get ] 3dip
+ [ [ factorize-type ] map ] dip
+ types-effect>params-return factorize-type -roll
+ concat make-function ;
+
+: define-c-library ( name -- )
+ c-library-name [ c-library set ] [ "c-library" set ] bi
+ V{ } clone c-strings set
+ V{ } clone linker-args set ;
+
+: compile-c-library ( -- )
+ compile-library? [ compile-library ] when
+ c-library get dup library-path "cdecl" add-library ;
+
+: define-c-function ( function types effect body -- )
+ [
+ [ factor-function define-declared ]
+ [ prototype-string ] 3bi
+ ] dip append-function-body c-strings get push ;
+
+: define-c-function' ( function effect body -- )
+ [
+ [ in>> ] keep
+ [ factor-function define-declared ]
+ [ out>> prototype-string' ] 3bi
+ ] dip append-function-body c-strings get push ;
+
+: c-link-to ( str -- )
+ "-l" prepend linker-args get push ;
+
+: c-use-framework ( str -- )
+ "-framework" swap linker-args get '[ _ push ] bi@ ;
+
+: c-link-to/use-framework ( str -- )
+ os macosx? [ c-use-framework ] [ c-link-to ] if ;
+
+: c-include ( str -- )
+ "#include " prepend c-strings get push ;
+
+: define-c-typedef ( old new -- )
+ [ typedef ] [
+ [ swap "typedef " % % " " % % ";" % ]
+ "" make c-strings get push
+ ] 2bi ;
+
+: define-c-struct ( name fields -- )
+ [ current-vocab swap define-struct ] [
+ over
+ [
+ "typedef struct " % "_" % % " {\n" %
+ [ first2 swap % " " % % ";\n" % ] each
+ "} " % % ";\n" %
+ ] "" make c-strings get push
+ ] 2bi ;
+
+: delete-inline-library ( name -- )
+ c-library-name [ remove-library ]
+ [ library-path dup exists? [ delete-file ] [ drop ] if ] bi ;
+
+: with-c-library ( name quot -- )
+ [ [ define-c-library ] dip call compile-c-library ]
+ [ cleanup-variables ] [ ] cleanup ; inline
+
+: raw-c ( str -- )
+ [ "\n" % % "\n" % ] "" make c-strings get push ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax alien.inline ;
+IN: alien.inline.syntax
+
+HELP: ;C-LIBRARY
+{ $syntax ";C-LIBRARY" }
+{ $description "Writes, compiles, and links code generated since previous invocation of " { $link POSTPONE: C-LIBRARY: } "." }
+{ $see-also POSTPONE: compile-c-library } ;
+
+HELP: C-FRAMEWORK:
+{ $syntax "C-FRAMEWORK: name" }
+{ $description "OS X only. Link to named framework. Takes effect when " { $link POSTPONE: ;C-LIBRARY } " is called." }
+{ $see-also POSTPONE: c-use-framework } ;
+
+HELP: C-FUNCTION:
+{ $syntax "C-FUNCTION: return name ( args ... )\nbody\n;" }
+{ $description "Appends a function to the C library in scope and defines an FFI word that calls it." }
+{ $examples
+ { $example
+ "USING: alien.inline.syntax prettyprint ;"
+ "IN: cmath.ffi"
+ ""
+ "C-LIBRARY: cmathlib"
+ ""
+ "C-FUNCTION: int add ( int a, int b )"
+ " return a + b;"
+ ";"
+ ""
+ ";C-LIBRARY"
+ ""
+ "1 2 add ."
+ "3" }
+}
+{ $see-also POSTPONE: define-c-function } ;
+
+HELP: C-INCLUDE:
+{ $syntax "C-INCLUDE: name" }
+{ $description "Appends an include line to the C library in scope." }
+{ $see-also POSTPONE: c-include } ;
+
+HELP: C-LIBRARY:
+{ $syntax "C-LIBRARY: name" }
+{ $description "Starts a new C library scope. Other " { $snippet "alien.inline" } " syntax can be used after this word." }
+{ $examples
+ { $example
+ "USING: alien.inline.syntax ;"
+ "IN: rectangle.ffi"
+ ""
+ "C-LIBRARY: rectlib"
+ ""
+ "C-STRUCTURE: rectangle { \"int\" \"width\" } { \"int\" \"height\" } ;"
+ ""
+ "C-FUNCTION: int area ( rectangle c )"
+ " return c.width * c.height;"
+ ";"
+ ""
+ ";C-LIBRARY"
+ "" }
+}
+{ $see-also POSTPONE: define-c-library } ;
+
+HELP: C-LINK/FRAMEWORK:
+{ $syntax "C-LINK/FRAMEWORK: name" }
+{ $description "Equivalent to " { $link POSTPONE: C-FRAMEWORK: } " on OS X and " { $link POSTPONE: C-LINK: } " everywhere else." }
+{ $see-also POSTPONE: c-link-to/use-framework } ;
+
+HELP: C-LINK:
+{ $syntax "C-LINK: name" }
+{ $description "Link to named library. Takes effect when " { $link POSTPONE: ;C-LIBRARY } " is called." }
+{ $see-also POSTPONE: c-link-to } ;
+
+HELP: C-STRUCTURE:
+{ $syntax "C-STRUCTURE: name pairs ... ;" }
+{ $description "Like " { $snippet "C-STRUCT:" } " but also generates equivalent C code."}
+{ $see-also POSTPONE: define-c-struct } ;
+
+HELP: C-TYPEDEF:
+{ $syntax "C-TYPEDEF: old new" }
+{ $description "Like " { $snippet "TYPEDEF:" } " but generates a C typedef statement too." }
+{ $see-also POSTPONE: define-c-typedef } ;
+
+HELP: COMPILE-AS-C++
+{ $syntax "COMPILE-AS-C++" }
+{ $description "Insert this word anywhere between " { $link POSTPONE: C-LIBRARY: } " and " { $link POSTPONE: ;C-LIBRARY } " and the generated code will be treated as C++ with " { $snippet "extern \"C\"" } " prepended to each function prototype." } ;
+
+HELP: DELETE-C-LIBRARY:
+{ $syntax "DELETE-C-LIBRARY: name" }
+{ $description "Deletes the shared library file corresponding to " { $snippet "name" } " . " }
+{ $notes
+ { $list
+ { "Must be executed in the vocabulary where " { $snippet "name" } " is defined. " }
+ "This word is mainly useful for unit tests."
+ }
+}
+{ $see-also POSTPONE: delete-inline-library } ;
+
+HELP: <RAW-C
+{ $syntax "<RAW-C code RAW-C>" }
+{ $description "Insert a (multiline) string into the generated source file. Useful for macros and other details not implemented in " { $snippet "alien.inline" } "." } ;
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.inline alien.inline.syntax io.directories io.files
+kernel namespaces tools.test alien.c-types alien.structs ;
+IN: alien.inline.syntax.tests
+
+DELETE-C-LIBRARY: test
+C-LIBRARY: test
+
+C-FUNCTION: const-int add ( int a, int b )
+ return a + b;
+;
+
+C-TYPEDEF: double bigfloat
+
+C-FUNCTION: bigfloat smaller ( bigfloat a )
+ return a / 10;
+;
+
+C-STRUCTURE: rectangle
+ { "int" "width" }
+ { "int" "height" } ;
+
+C-FUNCTION: int area ( rectangle c )
+ return c.width * c.height;
+;
+
+;C-LIBRARY
+
+{ 2 1 } [ add ] must-infer-as
+[ 5 ] [ 2 3 add ] unit-test
+
+[ t ] [ "double" "bigfloat" [ resolve-typedef ] bi@ = ] unit-test
+{ 1 1 } [ smaller ] must-infer-as
+[ 1.0 ] [ 10 smaller ] unit-test
+
+[ t ] [ "rectangle" resolve-typedef struct-type? ] unit-test
+{ 1 1 } [ area ] must-infer-as
+[ 20 ] [
+ "rectangle" <c-object>
+ 4 over set-rectangle-width
+ 5 over set-rectangle-height
+ area
+] unit-test
+
+
+DELETE-C-LIBRARY: cpplib
+C-LIBRARY: cpplib
+
+COMPILE-AS-C++
+
+C-INCLUDE: <string>
+
+C-FUNCTION: const-char* hello ( )
+ std::string s("hello world");
+ return s.c_str();
+;
+
+;C-LIBRARY
+
+{ 0 1 } [ hello ] must-infer-as
+[ "hello world" ] [ hello ] unit-test
+
+
+DELETE-C-LIBRARY: compile-error
+C-LIBRARY: compile-error
+
+C-FUNCTION: char* breakme ( )
+ return not a string;
+;
+
+<< [ compile-c-library ] must-fail >>
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.inline lexer multiline namespaces parser ;
+IN: alien.inline.syntax
+
+
+SYNTAX: C-LIBRARY: scan define-c-library ;
+
+SYNTAX: COMPILE-AS-C++ t library-is-c++ set ;
+
+SYNTAX: C-LINK: scan c-link-to ;
+
+SYNTAX: C-FRAMEWORK: scan c-use-framework ;
+
+SYNTAX: C-LINK/FRAMEWORK: scan c-link-to/use-framework ;
+
+SYNTAX: C-INCLUDE: scan c-include ;
+
+SYNTAX: C-FUNCTION:
+ function-types-effect parse-here define-c-function ;
+
+SYNTAX: C-TYPEDEF: scan scan define-c-typedef ;
+
+SYNTAX: C-STRUCTURE:
+ scan parse-definition define-c-struct ;
+
+SYNTAX: ;C-LIBRARY compile-c-library ;
+
+SYNTAX: DELETE-C-LIBRARY: scan delete-inline-library ;
+
+SYNTAX: <RAW-C "RAW-C>" parse-multiline-string raw-c ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types assocs combinators.short-circuit
+continuations effects fry kernel math memoize sequences
+splitting strings peg.ebnf make ;
+IN: alien.inline.types
+
+: cify-type ( str -- str' )
+ { { CHAR: - CHAR: space } } substitute ;
+
+: factorize-type ( str -- str' )
+ cify-type
+ "const " ?head drop
+ "unsigned " ?head [ "u" prepend ] when
+ "long " ?head [ "long" prepend ] when
+ " const" ?tail drop ;
+
+: const-pointer? ( str -- ? )
+ cify-type { [ " const" tail? ] [ "&" tail? ] } 1|| ;
+
+: pointer-to-const? ( str -- ? )
+ cify-type "const " head? ;
+
+: template-class? ( str -- ? )
+ [ CHAR: < = ] any? ;
+
+MEMO: resolved-primitives ( -- seq )
+ primitive-types [ resolve-typedef ] map ;
+
+: primitive-type? ( type -- ? )
+ [
+ factorize-type resolve-typedef [ resolved-primitives ] dip
+ '[ _ = ] any?
+ ] [ 2drop f ] recover ;
+
+: pointer? ( type -- ? )
+ factorize-type [ "*" tail? ] [ "&" tail? ] bi or ;
+
+: type-sans-pointer ( type -- type' )
+ factorize-type [ '[ _ = ] "*&" swap any? ] trim-tail ;
+
+: pointer-to-primitive? ( type -- ? )
+ factorize-type
+ { [ pointer? ] [ type-sans-pointer primitive-type? ] } 1&& ;
+
+: pointer-to-non-const-primitive? ( str -- ? )
+ {
+ [ pointer-to-const? not ]
+ [ factorize-type pointer-to-primitive? ]
+ } 1&& ;
+
+: types-effect>params-return ( types effect -- params return )
+ [ in>> zip ]
+ [ nip out>> dup length 0 > [ first ] [ drop "void" ] if ]
+ 2bi ;
+
+: annotate-effect ( types effect -- types effect' )
+ [ in>> ] [ out>> ] bi [
+ zip
+ [ over pointer-to-primitive? [ ">" prepend ] when ]
+ assoc-map unzip
+ ] dip <effect> ;
+
+TUPLE: c++-type name params ptr ;
+C: <c++-type> c++-type
+
+EBNF: (parse-c++-type)
+dig = [0-9]
+alpha = [a-zA-Z]
+alphanum = [1-9a-zA-Z]
+name = [_a-zA-Z] [_a-zA-Z1-9:]* => [[ first2 swap prefix >string ]]
+ptr = [*&] => [[ empty? not ]]
+
+param = "," " "* type " "* => [[ third ]]
+
+params = "<" " "* type " "* param* ">" => [[ [ 4 swap nth ] [ third ] bi prefix ]]
+
+type = name " "* params? " "* ptr? => [[ { 0 2 4 } [ swap nth ] with map first3 <c++-type> ]]
+;EBNF
+
+: parse-c++-type ( str -- c++-type )
+ factorize-type (parse-c++-type) ;
+
+DEFER: c++-type>string
+
+: params>string ( params -- str )
+ [ "<" % [ c++-type>string ] map "," join % ">" % ] "" make ;
+
+: c++-type>string ( c++-type -- str )
+ [
+ [ name>> % ]
+ [ params>> [ params>string % ] when* ]
+ [ ptr>> [ "*" % ] when ]
+ tri
+ ] "" make ;
+
+GENERIC: c++-type ( obj -- c++-type/f )
+
+M: object c++-type drop f ;
+
+M: c++-type c-type ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel quotations sequences
+strings alien alien.c-types math byte-arrays ;
+IN: alien.marshall
+
+<PRIVATE
+: $memory-note ( arg -- )
+ drop "This word returns a pointer to unmanaged memory."
+ print-element ;
+
+: $c-ptr-note ( arg -- )
+ drop "Does nothing if its argument is a non false c-ptr."
+ print-element ;
+
+: $see-article ( arg -- )
+ drop { "See " { $vocab-link "alien.inline" } "." }
+ print-element ;
+PRIVATE>
+
+HELP: ?malloc-byte-array
+{ $values
+ { "c-type" c-type }
+ { "alien" alien }
+}
+{ $description "Does nothing if input is an alien, otherwise assumes it is a byte array and calls "
+ { $snippet "malloc-byte-array" } "."
+}
+{ $notes $memory-note } ;
+
+HELP: alien-wrapper
+{ $var-description "For wrapping C pointers in a structure factor can dispatch on." } ;
+
+HELP: unmarshall-cast
+{ $values
+ { "alien-wrapper" alien-wrapper }
+ { "alien-wrapper'" alien-wrapper }
+}
+{ $description "Called immediately after unmarshalling. Useful for automatically casting to subtypes." } ;
+
+HELP: marshall-bool
+{ $values
+ { "?" "a generalized boolean" }
+ { "n" "0 or 1" }
+}
+{ $description "Marshalls objects to bool." }
+{ $notes "Will treat " { $snippet "0" } " as " { $snippet "t" } "." } ;
+
+HELP: marshall-bool*
+{ $values
+ { "?/seq" "t/f or sequence" }
+ { "alien" alien }
+}
+{ $description "When the argument is a sequence, returns a pointer to an array of bool, "
+ "otherwise returns a pointer to a single bool value."
+}
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-bool**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description "Takes a one or two dimensional array of generalized booleans "
+ "and returns a pointer to the equivalent C structure."
+}
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-primitive
+{ $values
+ { "n" number }
+ { "n" number }
+}
+{ $description "Marshall numbers to C primitives."
+ $nl
+ "Factor marshalls numbers to primitives for FFI calls, so all "
+ "this word does is convert " { $snippet "t" } " to " { $snippet "1" }
+ ", " { $snippet "f" } " to " { $snippet "0" } ", and lets anything else "
+ "pass through untouched."
+} ;
+
+HELP: marshall-char*
+{ $values
+ { "n/seq" "number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-char**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-char**-or-strings
+{ $values
+ { "seq" "a sequence of strings" }
+ { "alien" alien }
+}
+{ $description "Marshalls an array of strings or characters to an array of C strings." }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-char*-or-string
+{ $values
+ { "n/string" "a number or string" }
+ { "alien" alien }
+}
+{ $description "Marshalls a string to a C string or a number to a pointer to " { $snippet "char" } "." }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-double*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-double**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-float*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-float**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-int*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-int**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-long*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-long**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-longlong*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-longlong**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-non-pointer
+{ $values
+ { "alien-wrapper/byte-array" "an alien-wrapper or byte-array" }
+ { "byte-array" byte-array }
+}
+{ $description "Converts argument to a byte array." }
+{ $notes "Not meant to be called directly. Use the output of " { $link marshaller } " instead." } ;
+
+HELP: marshall-pointer
+{ $values
+ { "obj" object }
+ { "alien" alien }
+}
+{ $description "Converts argument to a C pointer." }
+{ $notes "Can marshall the following types: " { $snippet "alien, f, byte-array, alien-wrapper, struct-array" } "." } ;
+
+HELP: marshall-short*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-short**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-uchar*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-uchar**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-uint*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-uint**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-ulong*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-ulong**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-ulonglong*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-ulonglong**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-ushort*
+{ $values
+ { "n/seq" "a number or sequence" }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-ushort**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description $see-article }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshall-void**
+{ $values
+ { "seq" sequence }
+ { "alien" alien }
+}
+{ $description "Marshalls a sequence of objects to an array of pointers to void." }
+{ $notes { $list $c-ptr-note $memory-note } } ;
+
+HELP: marshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot" quotation }
+}
+{ $description "Given a C type, returns a quotation that will marshall its argument to that type." } ;
+
+HELP: out-arg-unmarshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot" quotation }
+}
+{ $description "Like " { $link unmarshaller } " but returns an empty quotation "
+ "for all types except pointers to non-const primitives."
+} ;
+
+HELP: class-unmarshaller
+{ $values
+ { "type" " a C type string" }
+ { "quot/f" quotation }
+}
+{ $description "If in the vocab in which this word is called, there is a subclass of " { $link alien-wrapper }
+ " named after the type argument, " { $snippet "pointer-unmarshaller" } " will return a quotation which "
+ "wraps its argument in an instance of that subclass. In any other case it returns an empty quotation."
+}
+{ $notes "Not meant to be called directly. Use the output of " { $link marshaller } " instead." } ;
+
+HELP: primitive-marshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot/f" "a quotation or f" }
+}
+{ $description "Returns a quotation to marshall objects to the argument type." }
+{ $notes "Not meant to be called directly. Use the output of " { $link marshaller } " instead." } ;
+
+HELP: primitive-unmarshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot/f" "a quotation or f" }
+}
+{ $description "Returns a quotation to unmarshall objects from the argument type." }
+{ $notes "Not meant to be called directly. Use the output of " { $link unmarshaller } " instead." } ;
+
+HELP: struct-field-unmarshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot" quotation }
+}
+{ $description "Like " { $link unmarshaller } " but returns a quotation that "
+ "does not call " { $snippet "free" } " on its argument."
+}
+{ $notes "Not meant to be called directly. Use the output of " { $link unmarshaller } " instead." } ;
+
+HELP: struct-primitive-unmarshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot/f" "a quotation or f" }
+}
+{ $description "Like " { $link primitive-unmarshaller } " but returns a quotation that "
+ "does not call " { $snippet "free" } " on its argument." }
+{ $notes "Not meant to be called directly. Use the output of " { $link unmarshaller } " instead." } ;
+
+HELP: struct-unmarshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot/f" quotation }
+}
+{ $description "Returns a quotation which wraps its argument in the subclass of "
+ { $link struct-wrapper } " which matches the " { $snippet "type" } " arg."
+}
+{ $notes "Not meant to be called directly. Use the output of " { $link unmarshaller } " instead." } ;
+
+HELP: struct-wrapper
+{ $var-description "For wrapping C structs in a structure factor can dispatch on." } ;
+
+HELP: unmarshall-bool
+{ $values
+ { "n" number }
+ { "?" "a boolean" }
+}
+{ $description "Unmarshalls a number to a boolean." } ;
+
+HELP: unmarshall-bool*
+{ $values
+ { "alien" alien }
+ { "?" "a boolean" }
+}
+{ $description "Unmarshalls a C pointer to a boolean." } ;
+
+HELP: unmarshall-bool*-free
+{ $values
+ { "alien" alien }
+ { "?" "a boolean" }
+}
+{ $description "Unmarshalls a C pointer to a boolean and frees the pointer." } ;
+
+HELP: unmarshall-char*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-char*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-char*-to-string
+{ $values
+ { "alien" alien }
+ { "string" string }
+}
+{ $description "Unmarshalls a " { $snippet "char" } " pointer to a factor string." } ;
+
+HELP: unmarshall-char*-to-string-free
+{ $values
+ { "alien" alien }
+ { "string" string }
+}
+{ $description "Unmarshalls a " { $snippet "char" } " pointer to a factor string and frees the pointer." } ;
+
+HELP: unmarshall-double*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-double*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-float*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-float*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-int*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-int*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-long*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-long*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-longlong*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-longlong*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-short*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-short*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-uchar*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-uchar*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-uint*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-uint*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-ulong*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-ulong*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-ulonglong*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-ulonglong*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-ushort*
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshall-ushort*-free
+{ $values
+ { "alien" alien }
+ { "n" number }
+}
+{ $description $see-article } ;
+
+HELP: unmarshaller
+{ $values
+ { "type" "a C type string" }
+ { "quot" quotation }
+}
+{ $description "Given a C type, returns a quotation that will unmarshall values of that type." } ;
+
+ARTICLE: "alien.marshall" "C marshalling"
+{ $vocab-link "alien.marshall" } " provides alien wrappers and marshalling words for the "
+"automatic marshalling and unmarshalling of C function arguments, return values, and output parameters."
+
+{ $subheading "Important words" }
+"Wrap an alien:" { $subsection alien-wrapper }
+"Wrap a struct:" { $subsection struct-wrapper }
+"Get the marshaller for a C type:" { $subsection marshaller }
+"Get the unmarshaller for a C type:" { $subsection unmarshaller }
+"Get the unmarshaller for an output parameter:" { $subsection out-arg-unmarshaller }
+"Get the unmarshaller for a struct field:" { $subsection struct-field-unmarshaller }
+$nl
+"Other marshalling and unmarshalling words in this vocabulary are not intended to be "
+"invoked directly."
+$nl
+"Most marshalling words allow non false c-ptrs to pass through unchanged."
+
+{ $subheading "Primitive marshallers" }
+{ $subsection marshall-primitive } "for marshalling primitive values."
+{ $subsection marshall-int* }
+ "marshalls a number or sequence of numbers. If argument is a sequence, returns a pointer "
+ "to a C array, otherwise returns a pointer to a single value."
+{ $subsection marshall-int** }
+"marshalls a 1D or 2D array of numbers. Returns an array of pointers to arrays."
+
+{ $subheading "Primitive unmarshallers" }
+{ $snippet "unmarshall-<prim>*" } " and " { $snippet "unmarshall-<prim>*-free" }
+" for all values of " { $snippet "<prim>" } " in " { $link primitive-types } "."
+{ $subsection unmarshall-int* }
+"unmarshalls a pointer to primitive. Returns a number. "
+"Assumes the pointer is not an array (if it is, only the first value is returned). "
+"C functions that return arrays are not handled correctly by " { $snippet "alien.marshall" }
+" and must be unmarshalled by hand."
+{ $subsection unmarshall-int*-free }
+"unmarshalls a pointer to primitive, and then frees the pointer."
+$nl
+"Primitive values require no unmarshalling. The factor FFI already does this."
+;
+
+ABOUT: "alien.marshall"
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien alien.c-types alien.inline.types
+alien.marshall.private alien.strings byte-arrays classes
+combinators combinators.short-circuit destructors fry
+io.encodings.utf8 kernel libc sequences
+specialized-arrays.alien specialized-arrays.bool
+specialized-arrays.char specialized-arrays.double
+specialized-arrays.float specialized-arrays.int
+specialized-arrays.long specialized-arrays.longlong
+specialized-arrays.short specialized-arrays.uchar
+specialized-arrays.uint specialized-arrays.ulong
+specialized-arrays.ulonglong specialized-arrays.ushort strings
+unix.utilities vocabs.parser words libc.private struct-arrays
+locals generalizations math ;
+IN: alien.marshall
+
+<< primitive-types [ [ "void*" = ] [ "bool" = ] bi or not ]
+filter [ define-primitive-marshallers ] each >>
+
+TUPLE: alien-wrapper { underlying alien } ;
+TUPLE: struct-wrapper < alien-wrapper disposed ;
+TUPLE: class-wrapper < alien-wrapper disposed ;
+
+MIXIN: c++-root
+
+GENERIC: unmarshall-cast ( alien-wrapper -- alien-wrapper' )
+
+M: alien-wrapper unmarshall-cast ;
+M: struct-wrapper unmarshall-cast ;
+
+M: struct-wrapper dispose* underlying>> free ;
+
+M: class-wrapper c++-type class name>> parse-c++-type ;
+
+: marshall-pointer ( obj -- alien )
+ {
+ { [ dup alien? ] [ ] }
+ { [ dup not ] [ ] }
+ { [ dup byte-array? ] [ malloc-byte-array ] }
+ { [ dup alien-wrapper? ] [ underlying>> ] }
+ { [ dup struct-array? ] [ underlying>> ] }
+ } cond ;
+
+: marshall-primitive ( n -- n )
+ [ bool>arg ] ptr-pass-through ;
+
+ALIAS: marshall-void* marshall-pointer
+
+: marshall-void** ( seq -- alien )
+ [ marshall-void* ] void*-array{ } map-as malloc-underlying ;
+
+: (marshall-char*-or-string) ( n/string -- alien )
+ dup string?
+ [ utf8 string>alien malloc-byte-array ]
+ [ (marshall-char*) ] if ;
+
+: marshall-char*-or-string ( n/string -- alien )
+ [ (marshall-char*-or-string) ] ptr-pass-through ;
+
+: (marshall-char**-or-strings) ( seq -- alien )
+ [ marshall-char*-or-string ] void*-array{ } map-as
+ malloc-underlying ;
+
+: marshall-char**-or-strings ( seq -- alien )
+ [ (marshall-char**-or-strings) ] ptr-pass-through ;
+
+: marshall-bool ( ? -- n )
+ >boolean [ 1 ] [ 0 ] if ;
+
+: (marshall-bool*) ( ?/seq -- alien )
+ [ marshall-bool <bool> malloc-byte-array ]
+ [ >bool-array malloc-underlying ]
+ marshall-x* ;
+
+: marshall-bool* ( ?/seq -- alien )
+ [ (marshall-bool*) ] ptr-pass-through ;
+
+: (marshall-bool**) ( seq -- alien )
+ [ marshall-bool* ] map >void*-array malloc-underlying ;
+
+: marshall-bool** ( seq -- alien )
+ [ (marshall-bool**) ] ptr-pass-through ;
+
+: unmarshall-bool ( n -- ? )
+ 0 = not ;
+
+: unmarshall-bool* ( alien -- ? )
+ *bool unmarshall-bool ;
+
+: unmarshall-bool*-free ( alien -- ? )
+ [ *bool unmarshall-bool ] keep add-malloc free ;
+
+: primitive-marshaller ( type -- quot/f )
+ {
+ { "bool" [ [ ] ] }
+ { "boolean" [ [ marshall-bool ] ] }
+ { "char" [ [ marshall-primitive ] ] }
+ { "uchar" [ [ marshall-primitive ] ] }
+ { "short" [ [ marshall-primitive ] ] }
+ { "ushort" [ [ marshall-primitive ] ] }
+ { "int" [ [ marshall-primitive ] ] }
+ { "uint" [ [ marshall-primitive ] ] }
+ { "long" [ [ marshall-primitive ] ] }
+ { "ulong" [ [ marshall-primitive ] ] }
+ { "long" [ [ marshall-primitive ] ] }
+ { "ulong" [ [ marshall-primitive ] ] }
+ { "float" [ [ marshall-primitive ] ] }
+ { "double" [ [ marshall-primitive ] ] }
+ { "bool*" [ [ marshall-bool* ] ] }
+ { "boolean*" [ [ marshall-bool* ] ] }
+ { "char*" [ [ marshall-char*-or-string ] ] }
+ { "uchar*" [ [ marshall-uchar* ] ] }
+ { "short*" [ [ marshall-short* ] ] }
+ { "ushort*" [ [ marshall-ushort* ] ] }
+ { "int*" [ [ marshall-int* ] ] }
+ { "uint*" [ [ marshall-uint* ] ] }
+ { "long*" [ [ marshall-long* ] ] }
+ { "ulong*" [ [ marshall-ulong* ] ] }
+ { "longlong*" [ [ marshall-longlong* ] ] }
+ { "ulonglong*" [ [ marshall-ulonglong* ] ] }
+ { "float*" [ [ marshall-float* ] ] }
+ { "double*" [ [ marshall-double* ] ] }
+ { "bool&" [ [ marshall-bool* ] ] }
+ { "boolean&" [ [ marshall-bool* ] ] }
+ { "char&" [ [ marshall-char* ] ] }
+ { "uchar&" [ [ marshall-uchar* ] ] }
+ { "short&" [ [ marshall-short* ] ] }
+ { "ushort&" [ [ marshall-ushort* ] ] }
+ { "int&" [ [ marshall-int* ] ] }
+ { "uint&" [ [ marshall-uint* ] ] }
+ { "long&" [ [ marshall-long* ] ] }
+ { "ulong&" [ [ marshall-ulong* ] ] }
+ { "longlong&" [ [ marshall-longlong* ] ] }
+ { "ulonglong&" [ [ marshall-ulonglong* ] ] }
+ { "float&" [ [ marshall-float* ] ] }
+ { "double&" [ [ marshall-double* ] ] }
+ { "void*" [ [ marshall-void* ] ] }
+ { "bool**" [ [ marshall-bool** ] ] }
+ { "boolean**" [ [ marshall-bool** ] ] }
+ { "char**" [ [ marshall-char**-or-strings ] ] }
+ { "uchar**" [ [ marshall-uchar** ] ] }
+ { "short**" [ [ marshall-short** ] ] }
+ { "ushort**" [ [ marshall-ushort** ] ] }
+ { "int**" [ [ marshall-int** ] ] }
+ { "uint**" [ [ marshall-uint** ] ] }
+ { "long**" [ [ marshall-long** ] ] }
+ { "ulong**" [ [ marshall-ulong** ] ] }
+ { "longlong**" [ [ marshall-longlong** ] ] }
+ { "ulonglong**" [ [ marshall-ulonglong** ] ] }
+ { "float**" [ [ marshall-float** ] ] }
+ { "double**" [ [ marshall-double** ] ] }
+ { "void**" [ [ marshall-void** ] ] }
+ [ drop f ]
+ } case ;
+
+: marshall-non-pointer ( alien-wrapper/byte-array -- byte-array )
+ {
+ { [ dup byte-array? ] [ ] }
+ { [ dup alien-wrapper? ]
+ [ [ underlying>> ] [ class name>> heap-size ] bi
+ memory>byte-array ] }
+ } cond ;
+
+
+: marshaller ( type -- quot )
+ factorize-type dup primitive-marshaller [ nip ] [
+ pointer?
+ [ [ marshall-pointer ] ]
+ [ [ marshall-non-pointer ] ] if
+ ] if* ;
+
+
+: unmarshall-char*-to-string ( alien -- string )
+ utf8 alien>string ;
+
+: unmarshall-char*-to-string-free ( alien -- string )
+ [ unmarshall-char*-to-string ] keep add-malloc free ;
+
+: primitive-unmarshaller ( type -- quot/f )
+ {
+ { "bool" [ [ ] ] }
+ { "boolean" [ [ unmarshall-bool ] ] }
+ { "char" [ [ ] ] }
+ { "uchar" [ [ ] ] }
+ { "short" [ [ ] ] }
+ { "ushort" [ [ ] ] }
+ { "int" [ [ ] ] }
+ { "uint" [ [ ] ] }
+ { "long" [ [ ] ] }
+ { "ulong" [ [ ] ] }
+ { "longlong" [ [ ] ] }
+ { "ulonglong" [ [ ] ] }
+ { "float" [ [ ] ] }
+ { "double" [ [ ] ] }
+ { "bool*" [ [ unmarshall-bool*-free ] ] }
+ { "boolean*" [ [ unmarshall-bool*-free ] ] }
+ { "char*" [ [ ] ] }
+ { "uchar*" [ [ unmarshall-uchar*-free ] ] }
+ { "short*" [ [ unmarshall-short*-free ] ] }
+ { "ushort*" [ [ unmarshall-ushort*-free ] ] }
+ { "int*" [ [ unmarshall-int*-free ] ] }
+ { "uint*" [ [ unmarshall-uint*-free ] ] }
+ { "long*" [ [ unmarshall-long*-free ] ] }
+ { "ulong*" [ [ unmarshall-ulong*-free ] ] }
+ { "longlong*" [ [ unmarshall-long*-free ] ] }
+ { "ulonglong*" [ [ unmarshall-ulong*-free ] ] }
+ { "float*" [ [ unmarshall-float*-free ] ] }
+ { "double*" [ [ unmarshall-double*-free ] ] }
+ { "bool&" [ [ unmarshall-bool*-free ] ] }
+ { "boolean&" [ [ unmarshall-bool*-free ] ] }
+ { "char&" [ [ ] ] }
+ { "uchar&" [ [ unmarshall-uchar*-free ] ] }
+ { "short&" [ [ unmarshall-short*-free ] ] }
+ { "ushort&" [ [ unmarshall-ushort*-free ] ] }
+ { "int&" [ [ unmarshall-int*-free ] ] }
+ { "uint&" [ [ unmarshall-uint*-free ] ] }
+ { "long&" [ [ unmarshall-long*-free ] ] }
+ { "ulong&" [ [ unmarshall-ulong*-free ] ] }
+ { "longlong&" [ [ unmarshall-longlong*-free ] ] }
+ { "ulonglong&" [ [ unmarshall-ulonglong*-free ] ] }
+ { "float&" [ [ unmarshall-float*-free ] ] }
+ { "double&" [ [ unmarshall-double*-free ] ] }
+ [ drop f ]
+ } case ;
+
+: struct-primitive-unmarshaller ( type -- quot/f )
+ {
+ { "bool" [ [ unmarshall-bool ] ] }
+ { "boolean" [ [ unmarshall-bool ] ] }
+ { "char" [ [ ] ] }
+ { "uchar" [ [ ] ] }
+ { "short" [ [ ] ] }
+ { "ushort" [ [ ] ] }
+ { "int" [ [ ] ] }
+ { "uint" [ [ ] ] }
+ { "long" [ [ ] ] }
+ { "ulong" [ [ ] ] }
+ { "longlong" [ [ ] ] }
+ { "ulonglong" [ [ ] ] }
+ { "float" [ [ ] ] }
+ { "double" [ [ ] ] }
+ { "bool*" [ [ unmarshall-bool* ] ] }
+ { "boolean*" [ [ unmarshall-bool* ] ] }
+ { "char*" [ [ ] ] }
+ { "uchar*" [ [ unmarshall-uchar* ] ] }
+ { "short*" [ [ unmarshall-short* ] ] }
+ { "ushort*" [ [ unmarshall-ushort* ] ] }
+ { "int*" [ [ unmarshall-int* ] ] }
+ { "uint*" [ [ unmarshall-uint* ] ] }
+ { "long*" [ [ unmarshall-long* ] ] }
+ { "ulong*" [ [ unmarshall-ulong* ] ] }
+ { "longlong*" [ [ unmarshall-long* ] ] }
+ { "ulonglong*" [ [ unmarshall-ulong* ] ] }
+ { "float*" [ [ unmarshall-float* ] ] }
+ { "double*" [ [ unmarshall-double* ] ] }
+ { "bool&" [ [ unmarshall-bool* ] ] }
+ { "boolean&" [ [ unmarshall-bool* ] ] }
+ { "char&" [ [ unmarshall-char* ] ] }
+ { "uchar&" [ [ unmarshall-uchar* ] ] }
+ { "short&" [ [ unmarshall-short* ] ] }
+ { "ushort&" [ [ unmarshall-ushort* ] ] }
+ { "int&" [ [ unmarshall-int* ] ] }
+ { "uint&" [ [ unmarshall-uint* ] ] }
+ { "long&" [ [ unmarshall-long* ] ] }
+ { "ulong&" [ [ unmarshall-ulong* ] ] }
+ { "longlong&" [ [ unmarshall-longlong* ] ] }
+ { "ulonglong&" [ [ unmarshall-ulonglong* ] ] }
+ { "float&" [ [ unmarshall-float* ] ] }
+ { "double&" [ [ unmarshall-double* ] ] }
+ [ drop f ]
+ } case ;
+
+
+: ?malloc-byte-array ( c-type -- alien )
+ dup alien? [ malloc-byte-array ] unless ;
+
+:: x-unmarshaller ( type type-quot superclass def clean -- quot/f )
+ type type-quot call current-vocab lookup [
+ dup superclasses superclass swap member?
+ [ def call ] [ drop clean call f ] if
+ ] [ clean call f ] if* ; inline
+
+: struct-unmarshaller ( type -- quot/f )
+ [ ] \ struct-wrapper
+ [ '[ ?malloc-byte-array _ new swap >>underlying ] ]
+ [ ]
+ x-unmarshaller ;
+
+: class-unmarshaller ( type -- quot/f )
+ [ type-sans-pointer "#" append ] \ class-wrapper
+ [ '[ _ new swap >>underlying ] ]
+ [ ]
+ x-unmarshaller ;
+
+: non-primitive-unmarshaller ( type -- quot/f )
+ {
+ { [ dup pointer? ] [ class-unmarshaller ] }
+ [ struct-unmarshaller ]
+ } cond ;
+
+: unmarshaller ( type -- quot )
+ factorize-type {
+ [ primitive-unmarshaller ]
+ [ non-primitive-unmarshaller ]
+ [ drop [ ] ]
+ } 1|| ;
+
+: struct-field-unmarshaller ( type -- quot )
+ factorize-type {
+ [ struct-primitive-unmarshaller ]
+ [ non-primitive-unmarshaller ]
+ [ drop [ ] ]
+ } 1|| ;
+
+: out-arg-unmarshaller ( type -- quot )
+ dup pointer-to-non-const-primitive?
+ [ factorize-type primitive-unmarshaller ]
+ [ drop [ drop ] ] if ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien alien.c-types alien.inline arrays
+combinators fry functors kernel lexer libc macros math
+sequences specialized-arrays.alien libc.private
+combinators.short-circuit ;
+IN: alien.marshall.private
+
+: bool>arg ( ? -- 1/0/obj )
+ {
+ { t [ 1 ] }
+ { f [ 0 ] }
+ [ ]
+ } case ;
+
+MACRO: marshall-x* ( num-quot seq-quot -- alien )
+ '[ bool>arg dup number? _ _ if ] ;
+
+: ptr-pass-through ( obj quot -- alien )
+ over { [ c-ptr? ] [ ] } 1&& [ drop ] [ call ] if ; inline
+
+: malloc-underlying ( obj -- alien )
+ underlying>> malloc-byte-array ;
+
+FUNCTOR: define-primitive-marshallers ( TYPE -- )
+<TYPE> IS <${TYPE}>
+*TYPE IS *${TYPE}
+>TYPE-array IS >${TYPE}-array
+marshall-TYPE DEFINES marshall-${TYPE}
+(marshall-TYPE*) DEFINES (marshall-${TYPE}*)
+(marshall-TYPE**) DEFINES (marshall-${TYPE}**)
+marshall-TYPE* DEFINES marshall-${TYPE}*
+marshall-TYPE** DEFINES marshall-${TYPE}**
+marshall-TYPE*-free DEFINES marshall-${TYPE}*-free
+marshall-TYPE**-free DEFINES marshall-${TYPE}**-free
+unmarshall-TYPE* DEFINES unmarshall-${TYPE}*
+unmarshall-TYPE*-free DEFINES unmarshall-${TYPE}*-free
+WHERE
+<PRIVATE
+: (marshall-TYPE*) ( n/seq -- alien )
+ [ <TYPE> malloc-byte-array ]
+ [ >TYPE-array malloc-underlying ]
+ marshall-x* ;
+PRIVATE>
+: marshall-TYPE* ( n/seq -- alien )
+ [ (marshall-TYPE*) ] ptr-pass-through ;
+<PRIVATE
+: (marshall-TYPE**) ( seq -- alien )
+ [ marshall-TYPE* ] void*-array{ } map-as malloc-underlying ;
+PRIVATE>
+: marshall-TYPE** ( seq -- alien )
+ [ (marshall-TYPE**) ] ptr-pass-through ;
+: unmarshall-TYPE* ( alien -- n )
+ *TYPE ; inline
+: unmarshall-TYPE*-free ( alien -- n )
+ [ unmarshall-TYPE* ] keep add-malloc free ;
+;FUNCTOR
+
+SYNTAX: PRIMITIVE-MARSHALLERS:
+";" parse-tokens [ define-primitive-marshallers ] each ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: classes help.markup help.syntax kernel quotations words
+alien.marshall.structs strings alien.structs alien.marshall ;
+IN: alien.marshall.structs
+
+HELP: define-marshalled-struct
+{ $values
+ { "name" string } { "vocab" "a vocabulary specifier" } { "fields" "an alist" }
+}
+{ $description "Calls " { $link define-struct } " and " { $link define-struct-tuple } "." } ;
+
+HELP: define-struct-tuple
+{ $values
+ { "name" string }
+}
+{ $description "Defines a subclass of " { $link struct-wrapper } ", a constructor, "
+ "and accessor words."
+} ;
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.marshall arrays assocs
+classes.tuple combinators destructors generalizations generic
+kernel libc locals parser quotations sequences slots words
+alien.structs lexer vocabs.parser fry effects ;
+IN: alien.marshall.structs
+
+<PRIVATE
+: define-struct-accessor ( class name quot -- )
+ [ "accessors" create create-method dup make-inline ] dip define ;
+
+: define-struct-getter ( class name word type -- )
+ [ ">>" append \ underlying>> ] 2dip
+ struct-field-unmarshaller \ call 4array >quotation
+ define-struct-accessor ;
+
+: define-struct-setter ( class name word type -- )
+ [ "(>>" prepend ")" append ] 2dip
+ marshaller [ underlying>> ] \ bi* roll 4array >quotation
+ define-struct-accessor ;
+
+: define-struct-accessors ( class name type reader writer -- )
+ [ dup define-protocol-slot ] 3dip
+ [ drop swap define-struct-getter ]
+ [ nip swap define-struct-setter ] 5 nbi ;
+
+: define-struct-constructor ( class -- )
+ {
+ [ name>> "<" prepend ">" append create-in ]
+ [ '[ _ new ] ]
+ [ name>> '[ _ malloc-object >>underlying ] append ]
+ [ name>> 1array ]
+ } cleave { } swap <effect> define-declared ;
+PRIVATE>
+
+:: define-struct-tuple ( name -- )
+ name create-in :> class
+ class struct-wrapper { } define-tuple-class
+ class define-struct-constructor
+ name c-type fields>> [
+ class swap
+ {
+ [ name>> { { CHAR: space CHAR: - } } substitute ]
+ [ type>> ] [ reader>> ] [ writer>> ]
+ } cleave define-struct-accessors
+ ] each ;
+
+: define-marshalled-struct ( name vocab fields -- )
+ [ define-struct ] [ 2drop define-struct-tuple ] 3bi ;
--- /dev/null
+Jeremy Hughes
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel quotations words
+alien.inline alien.syntax effects alien.marshall
+alien.marshall.structs strings sequences alien.inline.syntax ;
+IN: alien.marshall.syntax
+
+HELP: CM-FUNCTION:
+{ $syntax "CM-FUNCTION: return name args\n body\n;" }
+{ $description "Like " { $link POSTPONE: C-FUNCTION: } " but with marshalling "
+ "of arguments and return values."
+}
+{ $examples
+ { $example
+ "USING: alien.inline.syntax alien.marshall.syntax prettyprint ;"
+ "IN: example"
+ ""
+ "C-LIBRARY: exlib"
+ ""
+ "C-INCLUDE: <stdio.h>"
+ "C-INCLUDE: <stdlib.h>"
+ "CM-FUNCTION: char* sum_diff ( const-int a, const-int b, int* x, int* y )"
+ " *x = a + b;"
+ " *y = a - b;"
+ " char* s = (char*) malloc(sizeof(char) * 64);"
+ " sprintf(s, \"sum %i, diff %i\", *x, *y);"
+ " return s;"
+ ";"
+ ""
+ ";C-LIBRARY"
+ ""
+ "8 5 0 0 sum_diff . . ."
+ "3\n13\n\"sum 13, diff 3\""
+ }
+}
+{ $see-also define-c-marshalled POSTPONE: C-FUNCTION: POSTPONE: M-FUNCTION: } ;
+
+HELP: CM-STRUCTURE:
+{ $syntax "CM-STRUCTURE: name fields ... ;" }
+{ $description "Like " { $link POSTPONE: C-STRUCTURE: } " but with marshalling of fields. "
+ "Defines a subclass of " { $link struct-wrapper } " a constructor, and slot-like accessor words."
+}
+{ $see-also POSTPONE: C-STRUCTURE: POSTPONE: M-STRUCTURE: } ;
+
+HELP: M-FUNCTION:
+{ $syntax "M-FUNCTION: return name args ;" }
+{ $description "Like " { $link POSTPONE: FUNCTION: } " but with marshalling "
+ "of arguments and return values."
+}
+{ $see-also marshalled-function POSTPONE: C-FUNCTION: POSTPONE: CM-FUNCTION: } ;
+
+HELP: M-STRUCTURE:
+{ $syntax "M-STRUCTURE: name fields ... ;" }
+{ $description "Like " { $link POSTPONE: C-STRUCT: } " but with marshalling of fields. "
+ "Defines a subclass of " { $link struct-wrapper } " a constructor, and slot-like accessor words."
+}
+{ $see-also define-marshalled-struct POSTPONE: C-STRUCTURE: POSTPONE: CM-STRUCTURE: } ;
+
+HELP: define-c-marshalled
+{ $values
+ { "name" string } { "types" sequence } { "effect" effect } { "body" string }
+}
+{ $description "Defines a C function and a factor word which calls it with marshalling of "
+ "args and return values."
+}
+{ $see-also define-c-marshalled' } ;
+
+HELP: define-c-marshalled'
+{ $values
+ { "name" string } { "effect" effect } { "body" string }
+}
+{ $description "Like " { $link define-c-marshalled } ". "
+ "The effect elements must be C type strings."
+} ;
+
+HELP: marshalled-function
+{ $values
+ { "name" string } { "types" sequence } { "effect" effect }
+ { "word" word } { "quot" quotation } { "effect" effect }
+}
+{ $description "Defines a word which calls the named C function. Arguments, "
+ "return value, and output parameters are marshalled and unmarshalled."
+} ;
+
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.inline.syntax alien.marshall.syntax destructors
+tools.test accessors kernel ;
+IN: alien.marshall.syntax.tests
+
+DELETE-C-LIBRARY: test
+C-LIBRARY: test
+
+C-INCLUDE: <stdlib.h>
+C-INCLUDE: <string.h>
+C-INCLUDE: <stdbool.h>
+
+CM-FUNCTION: void outarg1 ( int* a )
+ *a += 2;
+;
+
+CM-FUNCTION: unsigned-long* outarg2 ( unsigned-long a, unsigned-long* b )
+ unsigned long* x = malloc(sizeof(unsigned long*));
+ *b = 10 + *b;
+ *x = a + *b;
+ return x;
+;
+
+CM-STRUCTURE: wedge
+ { "double" "degrees" } ;
+
+CM-STRUCTURE: sundial
+ { "double" "radius" }
+ { "wedge" "wedge" } ;
+
+CM-FUNCTION: double hours ( sundial* d )
+ return d->wedge.degrees / 30;
+;
+
+CM-FUNCTION: void change_time ( double hours, sundial* d )
+ d->wedge.degrees = hours * 30;
+;
+
+CM-FUNCTION: bool c_not ( bool p )
+ return !p;
+;
+
+CM-FUNCTION: char* upcase ( const-char* s )
+ int len = strlen(s);
+ char* t = malloc(sizeof(char) * len);
+ int i;
+ for (i = 0; i < len; i++)
+ t[i] = toupper(s[i]);
+ t[i] = '\0';
+ return t;
+;
+
+;C-LIBRARY
+
+{ 1 1 } [ outarg1 ] must-infer-as
+[ 3 ] [ 1 outarg1 ] unit-test
+[ 3 ] [ t outarg1 ] unit-test
+[ 2 ] [ f outarg1 ] unit-test
+
+{ 2 2 } [ outarg2 ] must-infer-as
+[ 18 15 ] [ 3 5 outarg2 ] unit-test
+
+{ 1 1 } [ hours ] must-infer-as
+[ 5.0 ] [ <sundial> <wedge> 150 >>degrees >>wedge hours ] unit-test
+
+{ 2 0 } [ change_time ] must-infer-as
+[ 150.0 ] [ 5 <sundial> <wedge> 11 >>degrees >>wedge [ change_time ] keep wedge>> degrees>> ] unit-test
+
+{ 1 1 } [ c_not ] must-infer-as
+[ f ] [ "x" c_not ] unit-test
+[ f ] [ 0 c_not ] unit-test
+
+{ 1 1 } [ upcase ] must-infer-as
+[ "ABC" ] [ "abc" upcase ] unit-test
--- /dev/null
+! Copyright (C) 2009 Jeremy Hughes.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.inline alien.inline.types alien.marshall
+combinators effects generalizations kernel locals make namespaces
+quotations sequences words alien.marshall.structs lexer parser
+vocabs.parser multiline ;
+IN: alien.marshall.syntax
+
+:: marshalled-function ( name types effect -- word quot effect )
+ name types effect factor-function
+ [ in>> ]
+ [ out>> types [ pointer-to-non-const-primitive? ] filter append ]
+ bi <effect>
+ [
+ [
+ types [ marshaller ] map , \ spread , ,
+ types length , \ nkeep ,
+ types [ out-arg-unmarshaller ] map
+ effect out>> dup empty?
+ [ drop ] [ first unmarshaller prefix ] if
+ , \ spread ,
+ ] [ ] make
+ ] dip ;
+
+: define-c-marshalled ( name types effect body -- )
+ [
+ [ marshalled-function define-declared ]
+ [ prototype-string ] 3bi
+ ] dip append-function-body c-strings get push ;
+
+: define-c-marshalled' ( name effect body -- )
+ [
+ [ in>> ] keep
+ [ marshalled-function define-declared ]
+ [ out>> prototype-string' ] 3bi
+ ] dip append-function-body c-strings get push ;
+
+SYNTAX: CM-FUNCTION:
+ function-types-effect parse-here define-c-marshalled ;
+
+SYNTAX: M-FUNCTION:
+ function-types-effect marshalled-function define-declared ;
+
+SYNTAX: M-STRUCTURE:
+ scan current-vocab parse-definition
+ define-marshalled-struct ;
+
+SYNTAX: CM-STRUCTURE:
+ scan current-vocab parse-definition
+ [ define-marshalled-struct ] [ nip define-c-struct ] 3bi ;
: four ( -- x )
!BROKEN this code is broken
- 2 2 + 1+ ;
+ 2 2 + 1 + ;
: five ( -- x )
!TODO return 5
! See http://factorcode.org/license.txt for BSD license.
USING: kernel vocabs vocabs.loader tools.time vocabs.hierarchy
arrays assocs io.styles io help.markup prettyprint sequences
-continuations debugger math namespaces memory ;
+continuations debugger math namespaces memory fry ;
IN: benchmark
<PRIVATE
PRIVATE>
+: (run-benchmark) ( vocab -- time )
+ [ 5 ] dip '[ gc [ _ run ] benchmark ] replicate infimum ;
+
: run-benchmark ( vocab -- )
- [ "=== " write vocab-name print flush ] [
- [ [ require ] [ gc [ run ] benchmark ] [ ] tri timings ]
+ [ "=== " write print flush ] [
+ [ [ require ] [ (run-benchmark) ] [ ] tri timings ]
[ swap errors ]
recover get set-at
] bi ;
[
V{ } clone timings set
V{ } clone errors set
- "benchmark" all-child-vocabs-seq
+ "benchmark" child-vocab-names
+ [ find-vocab-root ] filter
[ run-benchmark ] each
timings get
errors get
! http://crazybob.org/BeustSequence.java.html
:: (count-numbers) ( remaining first value used max listener: ( -- ) -- ? )
- 10 first - [| i |
+ 10 first - iota [| i |
[let* | digit [ i first + ]
mask [ digit 2^ ]
value' [ i value + ] |
remaining 1 <= [
listener call f
] [
- remaining 1-
+ remaining 1 -
0
value' 10 *
used mask bitor
] any? ; inline recursive
:: count-numbers ( max listener -- )
- 10 [ 1+ 1 1 0 max listener (count-numbers) ] any? drop ;
+ 10 iota [ 1 + 1 1 0 max listener (count-numbers) ] any? drop ;
inline
:: beust ( -- )
[let | i! [ 0 ] |
- 5000000000 [ i 1+ i! ] count-numbers
+ 5000000000 [ i 1 + i! ] count-numbers
i number>string " unique numbers." append print
] ;
--- /dev/null
+Doug Coleman
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators
+concurrency.mailboxes fry io kernel make math math.parser
+math.text.english sequences threads ;
+IN: benchmark.chameneos-redux
+
+SYMBOLS: red yellow blue ;
+
+ERROR: bad-color-pair pair ;
+
+TUPLE: creature n color count self-count mailbox ;
+
+TUPLE: meeting-place count mailbox ;
+
+: <meeting-place> ( count -- meeting-place )
+ meeting-place new
+ swap >>count
+ <mailbox> >>mailbox ;
+
+: <creature> ( n color -- creature )
+ creature new
+ swap >>color
+ swap >>n
+ 0 >>count
+ 0 >>self-count
+ <mailbox> >>mailbox ;
+
+: make-creatures ( colors -- seq )
+ [ length iota ] [ ] bi [ <creature> ] 2map ;
+
+: complement-color ( color1 color2 -- color3 )
+ 2dup = [ drop ] [
+ 2array {
+ { { red yellow } [ blue ] }
+ { { red blue } [ yellow ] }
+ { { yellow red } [ blue ] }
+ { { yellow blue } [ red ] }
+ { { blue red } [ yellow ] }
+ { { blue yellow } [ red ] }
+ [ bad-color-pair ]
+ } case
+ ] if ;
+
+: color-string ( color1 color2 -- string )
+ [
+ [ [ name>> ] bi@ " + " glue % " -> " % ]
+ [ complement-color name>> % ] 2bi
+ ] "" make ;
+
+: print-color-table ( -- )
+ { blue red yellow } dup
+ '[ _ '[ color-string print ] with each ] each ;
+
+: try-meet ( meeting-place creature -- )
+ over count>> 0 < [
+ 2drop
+ ] [
+ [ swap mailbox>> mailbox-put ]
+ [ nip mailbox>> mailbox-get drop ]
+ [ try-meet ] 2tri
+ ] if ;
+
+: creature-meeting ( seq -- )
+ first2 {
+ [ [ [ 1 + ] change-count ] bi@ 2drop ]
+ [ 2dup = [ [ 1 + ] change-self-count ] when 2drop ]
+ [ [ [ color>> ] bi@ complement-color ] [ [ (>>color) ] bi-curry@ bi ] 2bi ]
+ [ [ mailbox>> f swap mailbox-put ] bi@ ]
+ } 2cleave ;
+
+: run-meeting-place ( meeting-place -- )
+ [ 1 - ] change-count
+ dup count>> 0 < [
+ mailbox>> mailbox-get-all
+ [ f swap mailbox>> mailbox-put ] each
+ ] [
+ [ mailbox>> 2 swap '[ _ mailbox-get ] replicate creature-meeting ]
+ [ run-meeting-place ] bi
+ ] if ;
+
+: number>chameneos-string ( n -- string )
+ number>string string>digits [ number>text ] { } map-as " " join ;
+
+: chameneos-redux ( n colors -- )
+ [ <meeting-place> ] [ make-creatures ] bi*
+ {
+ [ nip nl bl [ bl ] [ color>> name>> write ] interleave nl ]
+ [ [ '[ _ _ try-meet ] in-thread ] with each ]
+ [ drop run-meeting-place ]
+
+ [ nip [ [ count>> number>string write bl ] [ self-count>> number>text write nl ] bi ] each ]
+ [ nip 0 [ count>> + ] reduce bl number>chameneos-string print ]
+ } 2cleave ;
+
+! 6000000 for shootout, too slow right now
+
+: chameneos-redux-main ( -- )
+ print-color-table
+ 60000 [
+ { blue red yellow } chameneos-redux
+ ] [
+ { blue red yellow red yellow blue red yellow red blue } chameneos-redux
+ ] bi ;
+
+MAIN: chameneos-redux-main
: count ( quot: ( -- ? ) -- n )
#! Call quot until it returns false, return number of times
#! it was true
- [ 0 ] dip '[ _ dip swap [ [ 1+ ] when ] keep ] loop ; inline
+ [ 0 ] dip '[ _ dip swap [ [ 1 + ] when ] keep ] loop ; inline
: count-flips ( perm -- flip# )
'[
[ CHAR: 0 + write1 ] each nl ; inline
: fannkuch-step ( counter max-flips perm -- counter max-flips )
- pick 30 < [ [ 1+ ] [ ] [ dup write-permutation ] tri* ] when
+ pick 30 < [ [ 1 + ] [ ] [ dup write-permutation ] tri* ] when
count-flips max ; inline
: fannkuch ( n -- )
[
- [ 0 0 ] dip [ 1+ ] B{ } map-as
+ [ 0 0 ] dip [ 1 + ] B{ } map-as
[ fannkuch-step ] each-permutation nip
] keep
"Pfannkuchen(" write pprint ") = " write . ;
:: split-lines ( n quot -- )
n line-length /mod
[ [ line-length quot call ] times ] dip
- dup zero? [ drop ] quot if ; inline
+ quot unless-zero ; inline
: write-random-fasta ( seed n chars floats desc id -- seed )
write-description
dup i>> 1 <= [
drop 1 <box>
] [
- i>> 1- <box>
+ i>> 1 - <box>
dup tuple-fib
swap
- i>> 1- <box>
+ i>> 1 - <box>
tuple-fib
swap i>> swap i>> + <box>
] if ; inline recursive
-IN: benchmark.fib6\r
USING: math kernel alien ;\r
+IN: benchmark.fib6\r
\r
: fib ( x -- y )\r
"int" { "int" } "cdecl" [\r
dup 1 <= [ drop 1 ] [\r
- 1- dup fib swap 1- fib +\r
+ 1 - dup fib swap 1 - fib +\r
] if\r
] alien-callback\r
"int" { "int" } "cdecl" alien-indirect ;\r
USING: math sequences kernel ;
IN: benchmark.gc1
-: gc1 ( -- ) 6000000 [ >bignum 1+ ] map drop ;
+: gc1 ( -- ) 6000000 [ >bignum 1 + ] map drop ;
-MAIN: gc1
\ No newline at end of file
+MAIN: gc1
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators kernel locals math
+math.ranges memoize sequences strings hashtables
+math.parser grouping ;
+IN: benchmark.hashtables
+
+MEMO: strings ( -- str )
+ 1 100 [a,b] 1 [ + ] accumulate nip [ number>string ] map ;
+
+:: add-delete-mix ( hash keys -- )
+ keys [| k |
+ 0 k hash set-at
+ k hash delete-at
+ ] each
+
+ keys [
+ 0 swap hash set-at
+ ] each
+
+ keys [
+ hash delete-at
+ ] each ;
+
+:: store-lookup-mix ( hash keys -- )
+ keys [
+ 0 swap hash set-at
+ ] each
+
+ keys [
+ hash at
+ ] map drop
+
+ keys [
+ hash [ 1 + ] change-at
+ ] each ;
+
+: string-mix ( hash -- )
+ strings
+ [ add-delete-mix ]
+ [ store-lookup-mix ]
+ 2bi ;
+
+TUPLE: collision value ;
+
+M: collision hashcode* value>> hashcode* 15 bitand ;
+
+: collision-mix ( hash -- )
+ strings 30 head [ collision boa ] map
+ [ add-delete-mix ]
+ [ store-lookup-mix ]
+ 2bi ;
+
+: small-mix ( hash -- )
+ strings 10 group [
+ [ add-delete-mix ]
+ [ store-lookup-mix ]
+ 2bi
+ ] with each ;
+
+: hashtable-benchmark ( -- )
+ H{ } clone
+ 10000 [
+ dup {
+ [ small-mix ]
+ [ clear-assoc ]
+ [ string-mix ]
+ [ clear-assoc ]
+ [ collision-mix ]
+ [ clear-assoc ]
+ } cleave
+ ] times
+ drop ;
+
+MAIN: hashtable-benchmark
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: heaps math sequences kernel ;
+IN: benchmark.heaps
+
+: data ( -- seq )
+ 1 6000 [ 13 + 79 * 13591 mod dup ] replicate nip ;
+
+: heap-test ( -- )
+ <min-heap>
+ data
+ [ [ dup pick heap-push ] each ]
+ [ length [ dup heap-pop* ] times ] bi
+ drop ;
+
+: heap-benchmark ( -- )
+ 100 [ heap-test ] times ;
+
+MAIN: heap-benchmark
\ No newline at end of file
: tally ( x exemplar -- b )
clone tuck
[
- [ [ 1+ ] [ 1 ] if* ] change-at
+ [ [ 1 + ] [ 1 ] if* ] change-at
] curry each ;
: small-groups ( x n -- b )
swap
- [ length swap - 1+ ] 2keep
+ [ length swap - 1 + ] 2keep
[ [ over + ] dip subseq ] 2curry map ;
: handle-table ( inputs n -- )
: <color-map> ( nb-cols -- map )
dup [
- 360 * swap 1+ / sat val
+ 360 * swap 1 + / sat val
1 <hsva> >rgba scale-rgb
] with map ;
:: each-pair ( bodies pair-quot: ( other-body body -- ) each-quot: ( body -- ) -- )
bodies [| body i |
body each-quot call
- bodies i 1+ tail-slice [
+ bodies i 1 + tail-slice [
body pair-quot call
] each
] each-index ; inline
-IN: benchmark.nsieve-bits
USING: math math.parser sequences sequences.private kernel
bit-arrays make io ;
+IN: benchmark.nsieve-bits
: clear-flags ( step i seq -- )
2dup length >= [
2dup length < [
2dup nth-unsafe [
over dup 2 * pick clear-flags
- rot 1+ -rot ! increment count
- ] when [ 1+ ] dip (nsieve-bits)
+ rot 1 + -rot ! increment count
+ ] when [ 1 + ] dip (nsieve-bits)
] [
2drop
] if ; inline recursive
: nsieve-bits ( m -- count )
- 0 2 rot 1+ <bit-array> dup set-bits (nsieve-bits) ;
+ 0 2 rot 1 + <bit-array> dup set-bits (nsieve-bits) ;
: nsieve-bits. ( m -- )
[ "Primes up to " % dup # " " % nsieve-bits # ] "" make
: nsieve-bits-main ( n -- )
dup 2^ 10000 * nsieve-bits.
- dup 1- 2^ 10000 * nsieve-bits.
+ dup 1 - 2^ 10000 * nsieve-bits.
2 - 2^ 10000 * nsieve-bits. ;
: nsieve-bits-main* ( -- ) 11 nsieve-bits-main ;
2dup length < [
2dup nth-unsafe 0 > [
over dup 2 * pick clear-flags
- rot 1+ -rot ! increment count
- ] when [ 1+ ] dip (nsieve)
+ rot 1 + -rot ! increment count
+ ] when [ 1 + ] dip (nsieve)
] [
2drop
] if ; inline recursive
: nsieve ( m -- count )
- 0 2 rot 1+ <byte-array> dup [ drop 1 ] change-each (nsieve) ;
+ 0 2 rot 1 + <byte-array> dup [ drop 1 ] change-each (nsieve) ;
: nsieve. ( m -- )
[ "Primes up to " % dup # " " % nsieve # ] "" make print ;
-IN: benchmark.nsieve
USING: math math.parser sequences sequences.private kernel
arrays make io ;
+IN: benchmark.nsieve
: clear-flags ( step i seq -- )
2dup length >= [
2dup length < [
2dup nth-unsafe [
over dup 2 * pick clear-flags
- rot 1+ -rot ! increment count
- ] when [ 1+ ] dip (nsieve)
+ rot 1 + -rot ! increment count
+ ] when [ 1 + ] dip (nsieve)
] [
2drop
] if ; inline recursive
: nsieve ( m -- count )
- 0 2 rot 1+ t <array> (nsieve) ;
+ 0 2 rot 1 + t <array> (nsieve) ;
: nsieve. ( m -- )
[ "Primes up to " % dup # " " % nsieve # ] "" make print ;
IN: benchmark.partial-sums
! Helper words
-: summing-integers ( n quot -- y ) [ 0.0 ] 2dip '[ 1+ @ + ] each ; inline
+: summing-integers ( n quot -- y ) [ 0.0 ] 2dip '[ 1 + @ + ] each ; inline
: summing-floats ( n quot -- y ) '[ >float @ ] summing-integers ; inline
: cube ( x -- y ) dup dup * * ; inline
-: -1^ ( n -- -1/1 ) 2 mod 2 * 1- ; inline
+: -1^ ( n -- -1/1 ) 2 mod 2 * 1 - ; inline
! The functions
-: 2/3^k ( n -- y ) [ 2.0 3.0 / swap 1- ^ ] summing-floats ; inline
+: 2/3^k ( n -- y ) [ 2.0 3.0 / swap 1 - ^ ] summing-floats ; inline
: k^-0.5 ( n -- y ) [ -0.5 ^ ] summing-floats ; inline
-: 1/k(k+1) ( n -- y ) [ dup 1+ * recip ] summing-floats ; inline
+: 1/k(k+1) ( n -- y ) [ dup 1 + * recip ] summing-floats ; inline
: flint-hills ( n -- y ) [ [ cube ] [ sin sq ] bi * recip ] summing-floats ; inline
: cookson-hills ( n -- y ) [ [ cube ] [ cos sq ] bi * recip ] summing-floats ; inline
: harmonic ( n -- y ) [ recip ] summing-floats ; inline
: riemann-zeta ( n -- y ) [ sq recip ] summing-floats ; inline
: alternating-harmonic ( n -- y ) [ [ -1^ ] keep /f ] summing-integers ; inline
-: gregory ( n -- y ) [ [ -1^ ] [ 2.0 * 1- ] bi / ] summing-integers ; inline
+: gregory ( n -- y ) [ [ -1^ ] [ 2.0 * 1 - ] bi / ] summing-integers ; inline
: partial-sums ( n -- results )
[
[ 1 { { 1 0 } { 0 1 } } ] dip 0 0 (pidigits) ;
: pidigits-main ( -- )
- 10000 pidigits ;
+ 2000 pidigits ;
MAIN: pidigits-main
M: sphere intersect-scene ( hit ray sphere -- hit )
[ [ sphere-n normalize ] keep <hit> nip ] if-ray-sphere ;
+HINTS: M\ sphere intersect-scene { hit ray sphere } ;
+
TUPLE: group < sphere { objs array read-only } ;
: <group> ( objs bound -- group )
M: group intersect-scene ( hit ray group -- hit )
[ drop objs>> [ intersect-scene ] with each ] if-ray-sphere ;
+HINTS: M\ group intersect-scene { hit ray group } ;
+
CONSTANT: initial-hit T{ hit f double-array{ 0.0 0.0 0.0 } 1/0. }
: initial-intersect ( ray scene -- hit )
] with map ;
: ray-pixel ( scene point -- n )
- ss-grid ray-grid 0.0 -rot
+ ss-grid ray-grid [ 0.0 ] 2dip
[ [ swap cast-ray + ] with each ] with each ;
: pixel-grid ( -- grid )
: ack ( m n -- x )
{
- { [ over zero? ] [ nip 1+ ] }
- { [ dup zero? ] [ drop 1- 1 ack ] }
- [ [ drop 1- ] [ 1- ack ] 2bi ack ]
+ { [ over zero? ] [ nip 1 + ] }
+ { [ dup zero? ] [ drop 1 - 1 ack ] }
+ [ [ drop 1 - ] [ 1 - ack ] 2bi ack ]
} cond ; inline recursive
: tak ( x y z -- t )
2over <= [
2nip
] [
- [ rot 1- -rot tak ]
- [ -rot 1- -rot tak ]
- [ 1- -rot tak ]
+ [ rot 1 - -rot tak ]
+ [ -rot 1 - -rot tak ]
+ [ 1 - -rot tak ]
3tri
tak
] if ; inline recursive
: recursive ( n -- )
[ 3 swap ack . flush ]
[ 27.0 + fib . flush ]
- [ 1- [ 3 * ] [ 2 * ] [ ] tri tak . flush ] tri
+ [ 1 - [ 3 * ] [ 2 * ] [ ] tri tak . flush ] tri
3 fib . flush
3.0 2.0 1.0 tak . flush ;
: tuple-array-benchmark ( -- )
100 [
drop 5000 <point-array> [
- [ 1+ ] change-x
- [ 1- ] change-y
- [ 1+ 2 / ] change-z
+ [ 1 + ] change-x
+ [ 1 - ] change-y
+ [ 1 + 2 / ] change-z
] map [ z>> ] sigma
] sigma . ;
-MAIN: tuple-array-benchmark
\ No newline at end of file
+MAIN: tuple-array-benchmark
--- /dev/null
+! Copyright (C) Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.accessors alien.c-types alien.syntax byte-arrays
+destructors generalizations hints kernel libc locals math math.order
+sequences sequences.private ;
+IN: benchmark.yuv-to-rgb
+
+C-STRUCT: yuv_buffer
+ { "int" "y_width" }
+ { "int" "y_height" }
+ { "int" "y_stride" }
+ { "int" "uv_width" }
+ { "int" "uv_height" }
+ { "int" "uv_stride" }
+ { "void*" "y" }
+ { "void*" "u" }
+ { "void*" "v" } ;
+
+:: fake-data ( -- rgb yuv )
+ [let* | w [ 1600 ]
+ h [ 1200 ]
+ buffer [ "yuv_buffer" <c-object> ]
+ rgb [ w h * 3 * <byte-array> ] |
+ w buffer set-yuv_buffer-y_width
+ h buffer set-yuv_buffer-y_height
+ h buffer set-yuv_buffer-uv_height
+ w buffer set-yuv_buffer-y_stride
+ w buffer set-yuv_buffer-uv_stride
+ w h * [ dup * ] B{ } map-as malloc-byte-array &free buffer set-yuv_buffer-y
+ w h * 2/ [ dup dup * * ] B{ } map-as malloc-byte-array &free buffer set-yuv_buffer-u
+ w h * 2/ [ dup * dup * ] B{ } map-as malloc-byte-array &free buffer set-yuv_buffer-v
+ rgb buffer
+ ] ;
+
+: clamp ( n -- n )
+ 255 min 0 max ; inline
+
+: stride ( line yuv -- uvy yy )
+ [ yuv_buffer-uv_stride swap 2/ * ] [ yuv_buffer-y_stride * ] 2bi ; inline
+
+: compute-y ( yuv uvy yy x -- y )
+ + >fixnum nip swap yuv_buffer-y swap alien-unsigned-1 16 - ; inline
+
+: compute-v ( yuv uvy yy x -- v )
+ nip 2/ + >fixnum swap yuv_buffer-u swap alien-unsigned-1 128 - ; inline
+
+: compute-u ( yuv uvy yy x -- v )
+ nip 2/ + >fixnum swap yuv_buffer-v swap alien-unsigned-1 128 - ; inline
+
+:: compute-yuv ( yuv uvy yy x -- y u v )
+ yuv uvy yy x compute-y
+ yuv uvy yy x compute-u
+ yuv uvy yy x compute-v ; inline
+
+: compute-blue ( y u v -- b )
+ drop 516 * 128 + swap 298 * + -8 shift clamp ; inline
+
+: compute-green ( y u v -- g )
+ [ [ 298 * ] dip 100 * - ] dip 208 * - 128 + -8 shift clamp ;
+ inline
+
+: compute-red ( y u v -- g )
+ nip 409 * swap 298 * + 128 + -8 shift clamp ; inline
+
+: compute-rgb ( y u v -- b g r )
+ [ compute-blue ] [ compute-green ] [ compute-red ] 3tri ;
+ inline
+
+: store-rgb ( index rgb b g r -- index )
+ [ pick 0 + pick set-nth-unsafe ]
+ [ pick 1 + pick set-nth-unsafe ]
+ [ pick 2 + pick set-nth-unsafe ] tri*
+ drop ; inline
+
+: yuv>rgb-pixel ( index rgb yuv uvy yy x -- index )
+ compute-yuv compute-rgb store-rgb 3 + ; inline
+
+: yuv>rgb-row ( index rgb yuv y -- index )
+ over stride
+ pick yuv_buffer-y_width
+ [ yuv>rgb-pixel ] with with with with each ; inline
+
+: yuv>rgb ( rgb yuv -- )
+ [ 0 ] 2dip
+ dup yuv_buffer-y_height
+ [ yuv>rgb-row ] with with each
+ drop ;
+
+HINTS: yuv>rgb byte-array byte-array ;
+
+: yuv>rgb-benchmark ( -- )
+ [ fake-data yuv>rgb ] with-destructors ;
+
+MAIN: yuv>rgb-benchmark
--- /dev/null
+John Benediktsson
--- /dev/null
+! Copyright (C) 2009 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: help.syntax help.markup brainfuck strings ;
+
+IN: brainfuck
+
+HELP: run-brainfuck
+{ $values { "code" string } }
+{ $description
+ "A brainfuck program is a sequence of eight commands that are "
+ "executed sequentially. An instruction pointer begins at the first "
+ "command, and each command is executed until the program terminates "
+ "when the instruction pointer moves beyond the last command.\n"
+ "\n"
+ "The eight language commands, each consisting of a single character, "
+ "are the following:\n"
+ { $table
+ { "Character" "Meaning" }
+ { ">" "increment the data pointer (to point to the next cell to the right)." }
+ { "<" "decrement the data pointer (to point to the next cell to the left)." }
+ { "+" "increment (increase by one) the byte at the data pointer." }
+ { "-" "decrement (decrease by one) the byte at the data pointer." }
+ { "." "output the value of the byte at the data pointer." }
+ { "," "accept one byte of input, storing its value in the byte at the data pointer." }
+ { "[" "if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command*." }
+ { "]" "if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command*." }
+ }
+ "\n"
+ "Brainfuck programs can be translated into C using the following "
+ "substitutions, assuming ptr is of type unsigned char* and has been "
+ "initialized to point to an array of zeroed bytes:\n"
+ { $table
+ { "Character" "C equivalent" }
+ { ">" "++ptr;" }
+ { "<" "--ptr;" }
+ { "+" "++*ptr;" }
+ { "-" "--*ptr;" }
+ { "." "putchar(*ptr);" }
+ { "," "*ptr=getchar();" }
+ { "[" "while (*ptr) {" }
+ { "]" "}" }
+ }
+} ;
+
+HELP: get-brainfuck
+{ $values { "code" string } { "result" string } }
+{ $description "Returns the output from a brainfuck program as a result string." }
+{ $see-also run-brainfuck } ;
--- /dev/null
+! Copyright (C) 2009 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: brainfuck kernel io.streams.string math math.parser math.ranges
+multiline quotations sequences tools.test ;
+
+
+[ "+" run-brainfuck ] must-infer
+[ "+" get-brainfuck ] must-infer
+
+! Hello World!
+
+[ "Hello World!\n" ] [ <" ++++++++++[>+++++++>++++++++++>+++>+<<<<-]
+ >++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
+ ------.--------.>+.>. "> get-brainfuck ] unit-test
+
+! Addition (single-digit)
+
+[ "8" ] [ "35" [ ",>++++++[<-------->-],[<+>-]<."
+ get-brainfuck ] with-string-reader ] unit-test
+
+! Multiplication (single-digit)
+
+[ "8\0" ] [ "24" [ <" ,>,>++++++++[<------<------>>-]
+ <<[>[>+>+<<-]>>[<<+>>-]<<<-]
+ >>>++++++[<++++++++>-],<.>. ">
+ get-brainfuck ] with-string-reader ] unit-test
+
+! Division (single-digit, integer)
+
+[ "3" ] [ "62" [ <" ,>,>++++++[-<--------<-------->>]
+ <<[
+ >[->+>+<<]
+ >[-<<-
+ [>]>>>[<[>>>-<<<[-]]>>]<<]
+ >>>+
+ <<[-<<+>>]
+ <<<]
+ >[-]>>>>[-<<<<<+>>>>>]
+ <<<<++++++[-<++++++++>]<. ">
+ get-brainfuck ] with-string-reader ] unit-test
+
+! Uppercase
+
+[ "A" ] [ "a\n" [ ",----------[----------------------.,----------]"
+ get-brainfuck ] with-string-reader ] unit-test
+
+! cat
+
+[ "ABC" ] [ "ABC\0" [ ",[.,]" get-brainfuck ] with-string-reader ] unit-test
+
+! Squares of numbers from 0 to 100
+
+100 [0,b] [ dup * number>string ] map "\n" join "\n" append 1quotation
+[ <" ++++[>+++++<-]>[<+++++>-]+<+[
+ >[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
+ >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
+ <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>
+ [-[<->-]+[<<<]]<[>+<-]>]<<-]<<-] ">
+ get-brainfuck ] unit-test
+
+
--- /dev/null
+! Copyright (C) 2009 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: accessors assocs fry io io.streams.string kernel macros math
+peg.ebnf prettyprint quotations sequences strings ;
+
+IN: brainfuck
+
+<PRIVATE
+
+TUPLE: brainfuck pointer memory ;
+
+: <brainfuck> ( -- brainfuck )
+ 0 H{ } clone brainfuck boa ;
+
+: get-memory ( brainfuck -- brainfuck value )
+ dup [ pointer>> ] [ memory>> ] bi at 0 or ;
+
+: set-memory ( brainfuck value -- brainfuck )
+ over [ pointer>> ] [ memory>> ] bi set-at ;
+
+: (+) ( brainfuck n -- brainfuck )
+ [ get-memory ] dip + 255 bitand set-memory ;
+
+: (-) ( brainfuck n -- brainfuck )
+ [ get-memory ] dip - 255 bitand set-memory ;
+
+: (?) ( brainfuck -- brainfuck t/f )
+ get-memory 0 = not ;
+
+: (.) ( brainfuck -- brainfuck )
+ get-memory 1string write ;
+
+: (,) ( brainfuck -- brainfuck )
+ read1 set-memory ;
+
+: (>) ( brainfuck n -- brainfuck )
+ [ dup pointer>> ] dip + >>pointer ;
+
+: (<) ( brainfuck n -- brainfuck )
+ [ dup pointer>> ] dip - >>pointer ;
+
+: (#) ( brainfuck -- brainfuck )
+ dup
+ [ "ptr=" write pointer>> pprint ]
+ [ ",mem=" write memory>> pprint nl ] bi ;
+
+: compose-all ( seq -- quot )
+ [ ] [ compose ] reduce ;
+
+EBNF: parse-brainfuck
+
+inc-ptr = (">")+ => [[ length 1quotation [ (>) ] append ]]
+dec-ptr = ("<")+ => [[ length 1quotation [ (<) ] append ]]
+inc-mem = ("+")+ => [[ length 1quotation [ (+) ] append ]]
+dec-mem = ("-")+ => [[ length 1quotation [ (-) ] append ]]
+output = "." => [[ [ (.) ] ]]
+input = "," => [[ [ (,) ] ]]
+debug = "#" => [[ [ (#) ] ]]
+space = (" "|"\t"|"\r\n"|"\n")+ => [[ [ ] ]]
+unknown = (.) => [[ "Invalid input" throw ]]
+
+ops = inc-ptr|dec-ptr|inc-mem|dec-mem|output|input|debug|space
+loop = "[" {loop|ops}+ "]" => [[ second compose-all 1quotation [ [ (?) ] ] prepend [ while ] append ]]
+
+code = (loop|ops|unknown)* => [[ compose-all ]]
+
+;EBNF
+
+PRIVATE>
+
+MACRO: run-brainfuck ( code -- )
+ [ <brainfuck> ] swap parse-brainfuck [ drop flush ] 3append ;
+
+: get-brainfuck ( code -- result )
+ [ run-brainfuck ] with-string-writer ; inline
+
--- /dev/null
+Brainfuck programming language.
--- /dev/null
+USING: bson.reader bson.writer byte-arrays io.encodings.binary
+io.streams.byte-array tools.test literals calendar kernel math ;
+
+IN: bson.tests
+
+: turnaround ( value -- value )
+ assoc>bv >byte-array binary [ H{ } stream>assoc ] with-byte-reader ;
+
+[ H{ { "a" "a string" } } ] [ H{ { "a" "a string" } } turnaround ] unit-test
+
+[ H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } ]
+[ H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } turnaround ] unit-test
+
+[ H{ { "a list" { 1 2.234 "hello world" } } } ]
+[ H{ { "a list" { 1 2.234 "hello world" } } } turnaround ] unit-test
+
+[ H{ { "a quotation" [ 1 2 + ] } } ]
+[ H{ { "a quotation" [ 1 2 + ] } } turnaround ] unit-test
+
+[ H{ { "a date" T{ timestamp { year 2009 }
+ { month 7 }
+ { day 11 }
+ { hour 9 }
+ { minute 8 }
+ { second 40+77/1000 } } } }
+]
+[ H{ { "a date" T{ timestamp { year 2009 }
+ { month 7 }
+ { day 11 }
+ { hour 11 }
+ { minute 8 }
+ { second 40+15437/200000 }
+ { gmt-offset T{ duration { hour 2 } } } } } } turnaround
+] unit-test
+
+[ H{ { "nested" H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } }
+ { "array" H{ { "a list" { 1 2.234 "hello world" } } } }
+ { "quot" [ 1 2 + ] } }
+]
+[ H{ { "nested" H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } }
+ { "array" H{ { "a list" { 1 2.234 "hello world" } } } }
+ { "quot" [ 1 2 + ] } } turnaround ] unit-test
+
+
-USING: accessors assocs bson.constants byte-arrays byte-vectors fry io
-io.binary io.encodings.string io.encodings.utf8 kernel math namespaces
-sequences serialize arrays calendar io.encodings ;
+USING: accessors assocs bson.constants calendar fry io io.binary
+io.encodings io.encodings.utf8 kernel math math.bitwise namespaces
+sequences serialize ;
+
+FROM: kernel.private => declare ;
+FROM: io.encodings.private => (read-until) ;
IN: bson.reader
TUPLE: element { type integer } name ;
TUPLE: state
- { size initial: -1 } { read initial: 0 } exemplar
+ { size initial: -1 } exemplar
result scope element ;
: <state> ( exemplar -- state )
clone [ >>result ] [ V{ } clone [ push ] keep >>scope ] bi
V{ } clone [ T_Object "" element boa swap push ] keep >>element ;
-PREDICATE: bson-eoo < integer T_EOO = ;
PREDICATE: bson-not-eoo < integer T_EOO > ;
+PREDICATE: bson-eoo < integer T_EOO = ;
-PREDICATE: bson-double < integer T_Double = ;
-PREDICATE: bson-integer < integer T_Integer = ;
PREDICATE: bson-string < integer T_String = ;
PREDICATE: bson-object < integer T_Object = ;
+PREDICATE: bson-oid < integer T_OID = ;
PREDICATE: bson-array < integer T_Array = ;
+PREDICATE: bson-integer < integer T_Integer = ;
+PREDICATE: bson-double < integer T_Double = ;
+PREDICATE: bson-date < integer T_Date = ;
PREDICATE: bson-binary < integer T_Binary = ;
+PREDICATE: bson-boolean < integer T_Boolean = ;
PREDICATE: bson-regexp < integer T_Regexp = ;
+PREDICATE: bson-null < integer T_NULL = ;
+PREDICATE: bson-ref < integer T_DBRef = ;
PREDICATE: bson-binary-bytes < integer T_Binary_Bytes = ;
PREDICATE: bson-binary-function < integer T_Binary_Function = ;
PREDICATE: bson-binary-uuid < integer T_Binary_UUID = ;
PREDICATE: bson-binary-custom < integer T_Binary_Custom = ;
-PREDICATE: bson-oid < integer T_OID = ;
-PREDICATE: bson-boolean < integer T_Boolean = ;
-PREDICATE: bson-date < integer T_Date = ;
-PREDICATE: bson-null < integer T_NULL = ;
-PREDICATE: bson-ref < integer T_DBRef = ;
GENERIC: element-read ( type -- cont? )
GENERIC: element-data-read ( type -- object )
GENERIC: element-binary-read ( length type -- object )
-: byte-array>number ( seq -- number )
- byte-array>bignum >integer ; inline
-
: get-state ( -- state )
state get ; inline
-: count-bytes ( count -- )
- [ get-state ] dip '[ _ + ] change-read drop ; inline
-
: read-int32 ( -- int32 )
- 4 [ read byte-array>number ] [ count-bytes ] bi ; inline
+ 4 read signed-le> ; inline
: read-longlong ( -- longlong )
- 8 [ read byte-array>number ] [ count-bytes ] bi ; inline
+ 8 read signed-le> ; inline
: read-double ( -- double )
- 8 [ read byte-array>number bits>double ] [ count-bytes ] bi ; inline
+ 8 read le> bits>double ; inline
: read-byte-raw ( -- byte-raw )
- 1 [ read ] [ count-bytes ] bi ; inline
+ 1 read ; inline
: read-byte ( -- byte )
read-byte-raw first ; inline
+: utf8-read-until ( seps stream encoding -- string/f sep/f )
+ [ { utf8 } declare decode-char dup [ dup rot member? ] [ 2drop f t ] if ]
+ 3curry (read-until) ;
+
: read-cstring ( -- string )
- input-stream get utf8 <decoder>
- "\0" swap stream-read-until drop ; inline
+ "\0" input-stream get utf8 utf8-read-until drop ; inline
: read-sized-string ( length -- string )
drop read-cstring ; inline
M: bson-object element-data-read ( type -- object )
(object-data-read) ;
-M: bson-array element-data-read ( type -- object )
- (object-data-read) ;
-
M: bson-string element-data-read ( type -- object )
drop
read-int32 read-sized-string ;
+M: bson-array element-data-read ( type -- object )
+ (object-data-read) ;
+
M: bson-integer element-data-read ( type -- object )
drop
read-int32 ;
USE: tools.continuations
-: stream>assoc ( exemplar -- assoc bytes-read )
+: stream>assoc ( exemplar -- assoc )
<state> dup state
[ read-int32 >>size read-elements ] with-variable
- [ result>> ] [ read>> ] bi ;
+ result>> ;
namespaces quotations sequences sequences.private serialize strings
words combinators.short-circuit literals ;
+FROM: io.encodings.utf8.private => char>utf8 ;
+FROM: kernel.private => declare ;
+
IN: bson.writer
<PRIVATE
SYMBOL: shared-buffer
+CONSTANT: CHAR-SIZE 1
CONSTANT: INT32-SIZE 4
-CONSTANT: CHAR-SIZE 1
CONSTANT: INT64-SIZE 8
: (buffer) ( -- buffer )
shared-buffer get
- [ 8192 <byte-vector> [ shared-buffer set ] keep ] unless* ; inline
-
-: >le-stream ( x n -- )
- swap
- '[ _ swap nth-byte 0 B{ 0 }
- [ set-nth-unsafe ] keep write ] each ; inline
-
+ [ BV{ } clone [ shared-buffer set ] keep ] unless*
+ { byte-vector } declare ; inline
+
PRIVATE>
: reset-buffer ( buffer -- )
: ensure-buffer ( -- )
(buffer) drop ; inline
-: with-buffer ( quot -- byte-vector )
+: with-buffer ( quot: ( -- ) -- byte-vector )
[ (buffer) [ reset-buffer ] keep dup ] dip
- with-output-stream* dup encoder? [ stream>> ] when ; inline
+ with-output-stream* ; inline
: with-length ( quot: ( -- ) -- bytes-written start-index )
- [ (buffer) [ length ] keep ] dip call
- length swap [ - ] keep ; inline
+ [ (buffer) [ length ] keep ] dip
+ call length swap [ - ] keep ; inline
-: with-length-prefix ( quot: ( -- ) -- )
- [ B{ 0 0 0 0 } write ] prepose with-length
- [ INT32-SIZE >le ] dip (buffer)
- '[ _ over [ nth-unsafe ] dip _ + _ set-nth-unsafe ]
- [ INT32-SIZE ] dip each-integer ; inline
+: (with-length-prefix) ( quot: ( -- ) length-quot: ( bytes-written -- length ) -- )
+ [ [ B{ 0 0 0 0 } write ] prepose with-length ] dip swap
+ [ call ] dip (buffer) copy ; inline
+: with-length-prefix ( quot: ( -- ) -- )
+ [ INT32-SIZE >le ] (with-length-prefix) ; inline
+
: with-length-prefix-excl ( quot: ( -- ) -- )
- [ B{ 0 0 0 0 } write ] prepose with-length
- [ INT32-SIZE - INT32-SIZE >le ] dip (buffer)
- '[ _ over [ nth-unsafe ] dip _ + _ set-nth-unsafe ]
- [ INT32-SIZE ] dip each-integer ; inline
+ [ INT32-SIZE [ - ] keep >le ] (with-length-prefix) ; inline
<PRIVATE
-GENERIC: bson-type? ( obj -- type ) foldable flushable
-GENERIC: bson-write ( obj -- )
+GENERIC: bson-type? ( obj -- type )
+GENERIC: bson-write ( obj -- )
M: t bson-type? ( boolean -- type ) drop T_Boolean ;
M: f bson-type? ( boolean -- type ) drop T_Boolean ;
-M: real bson-type? ( real -- type ) drop T_Double ;
-M: tuple bson-type? ( tuple -- type ) drop T_Object ;
-M: sequence bson-type? ( seq -- type ) drop T_Array ;
M: string bson-type? ( string -- type ) drop T_String ;
M: integer bson-type? ( integer -- type ) drop T_Integer ;
M: assoc bson-type? ( assoc -- type ) drop T_Object ;
+M: real bson-type? ( real -- type ) drop T_Double ;
+M: tuple bson-type? ( tuple -- type ) drop T_Object ;
+M: sequence bson-type? ( seq -- type ) drop T_Array ;
M: timestamp bson-type? ( timestamp -- type ) drop T_Date ;
M: mdbregexp bson-type? ( regexp -- type ) drop T_Regexp ;
M: quotation bson-type? ( quotation -- type ) drop T_Binary ;
M: byte-array bson-type? ( byte-array -- type ) drop T_Binary ;
-: write-utf8-string ( string -- )
- output-stream get utf8 <encoder> stream-write ; inline
+: write-utf8-string ( string -- ) output-stream get '[ _ swap char>utf8 ] each ; inline
-: write-byte ( byte -- ) CHAR-SIZE >le-stream ; inline
-: write-int32 ( int -- ) INT32-SIZE >le-stream ; inline
-: write-double ( real -- ) double>bits INT64-SIZE >le-stream ; inline
-: write-cstring ( string -- ) write-utf8-string 0 write-byte ; inline
-: write-longlong ( object -- ) INT64-SIZE >le-stream ; inline
+: write-int32 ( int -- ) INT32-SIZE >le write ; inline
+: write-double ( real -- ) double>bits INT64-SIZE >le write ; inline
+: write-cstring ( string -- ) write-utf8-string 0 write1 ; inline
+: write-longlong ( object -- ) INT64-SIZE >le write ; inline
-: write-eoo ( -- ) T_EOO write-byte ; inline
-: write-type ( obj -- obj ) [ bson-type? write-byte ] keep ; inline
+: write-eoo ( -- ) T_EOO write1 ; inline
+: write-type ( obj -- obj ) [ bson-type? write1 ] keep ; inline
: write-pair ( name object -- ) write-type [ write-cstring ] dip bson-write ; inline
+M: string bson-write ( obj -- )
+ '[ _ write-cstring ] with-length-prefix-excl ;
+
M: f bson-write ( f -- )
- drop 0 write-byte ;
+ drop 0 write1 ;
M: t bson-write ( t -- )
- drop 1 write-byte ;
-
-M: string bson-write ( obj -- )
- '[ _ write-cstring ] with-length-prefix-excl ;
+ drop 1 write1 ;
M: integer bson-write ( num -- )
write-int32 ;
M: byte-array bson-write ( binary -- )
[ length write-int32 ] keep
- T_Binary_Bytes write-byte
+ T_Binary_Bytes write1
write ;
M: oid bson-write ( oid -- )
: (serialize-code) ( code -- )
object>bytes [ length write-int32 ] keep
- T_Binary_Custom write-byte
+ T_Binary_Custom write1
write ;
M: quotation bson-write ( quotation -- )
[ '[ _ bson-write ] with-buffer ] with-scope ; inline
: assoc>stream ( assoc -- )
- bson-write ; inline
+ { assoc } declare bson-write ; inline
: mdb-special-value? ( value -- ? )
{ [ timestamp? ] [ quotation? ] [ mdbregexp? ]
- [ oid? ] [ byte-array? ] } 1|| ;
\ No newline at end of file
+ [ oid? ] [ byte-array? ] } 1|| ; inline
\ No newline at end of file
: next-draw ( gadget -- )
dup [ draw-seq>> ] [ draw-n>> ] bi
- 1+ swap length mod
+ 1 + swap length mod
>>draw-n relayout-1 ;
: make-draws ( gadget -- draw-seq )
framebuffer framebuffer-dim ;
: outlining-supported? ( -- ? )
- "2.0" {
+ "3.0" {
"GL_ARB_shader_objects"
"GL_ARB_draw_buffers"
"GL_ARB_multitexture"
- } has-gl-version-or-extensions? {
"GL_EXT_framebuffer_object"
"GL_ARB_texture_float"
- } has-gl-extensions? and ;
+ } has-gl-version-or-extensions? ;
: pass1-program ( -- program )
vertex-shader-source <vertex-shader> check-gl-shader
GL_TEXTURE_2D 0 iformat dim first2 0 xformat GL_UNSIGNED_BYTE f glTexImage2D ;
:: (attach-framebuffer-texture) ( texture attachment -- )
- GL_FRAMEBUFFER_EXT attachment GL_TEXTURE_2D texture 0 glFramebufferTexture2DEXT
+ GL_DRAW_FRAMEBUFFER attachment GL_TEXTURE_2D texture 0 glFramebufferTexture2D
gl-error ;
: (make-framebuffer) ( color-texture normal-texture depth-texture -- framebuffer )
3array gen-framebuffer dup [
- swap GL_COLOR_ATTACHMENT0_EXT
- GL_COLOR_ATTACHMENT1_EXT
- GL_DEPTH_ATTACHMENT_EXT 3array [ (attach-framebuffer-texture) ] 2each
+ swap GL_COLOR_ATTACHMENT0
+ GL_COLOR_ATTACHMENT1
+ GL_DEPTH_ATTACHMENT 3array [ (attach-framebuffer-texture) ] 2each
check-framebuffer
] with-framebuffer ;
: (make-framebuffer-textures) ( draw dim -- draw color normal depth )
{
[ drop ]
- [ GL_RGBA16F_ARB GL_RGBA [ >>color-texture ] (framebuffer-texture>>draw) ]
- [ GL_RGBA16F_ARB GL_RGBA [ >>normal-texture ] (framebuffer-texture>>draw) ]
+ [ GL_RGBA16F GL_RGBA [ >>color-texture ] (framebuffer-texture>>draw) ]
+ [ GL_RGBA16F GL_RGBA [ >>normal-texture ] (framebuffer-texture>>draw) ]
[
GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT
[ >>depth-texture ] (framebuffer-texture>>draw)
[ drop ] [ remake-framebuffer ] if ;
: clear-framebuffer ( -- )
- GL_COLOR_ATTACHMENT0_EXT glDrawBuffer
+ GL_COLOR_ATTACHMENT0 glDrawBuffer
0.15 0.15 0.15 1.0 glClearColor
GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
- GL_COLOR_ATTACHMENT1_EXT glDrawBuffer
+ GL_COLOR_ATTACHMENT1 glDrawBuffer
0.0 0.0 0.0 0.0 glClearColor
GL_COLOR_BUFFER_BIT glClear ;
: (pass1) ( geom draw -- )
dup framebuffer>> [
clear-framebuffer
- { GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT1_EXT } set-draw-buffers
+ { GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT1 } set-draw-buffers
pass1-program>> (draw-cel-shaded-bunny)
] with-framebuffer ;
--- /dev/null
+Doug Coleman
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors c.lexer kernel sequence-parser tools.test ;
+IN: c.lexer.tests
+
+[ 36 ]
+[
+ " //jofiejoe\n //eoieow\n/*asdf*/\n "
+ <sequence-parser> skip-whitespace/comments n>>
+] unit-test
+
+[ f "33asdf" ]
+[ "33asdf" <sequence-parser> [ take-c-identifier ] [ take-rest ] bi ] unit-test
+
+[ "asdf" ]
+[ "asdf" <sequence-parser> take-c-identifier ] unit-test
+
+[ "_asdf" ]
+[ "_asdf" <sequence-parser> take-c-identifier ] unit-test
+
+[ "_asdf400" ]
+[ "_asdf400" <sequence-parser> take-c-identifier ] unit-test
+
+[ "asdfasdf" ] [
+ "/*asdfasdf*/" <sequence-parser> take-c-comment
+] unit-test
+
+[ "k" ] [
+ "/*asdfasdf*/k" <sequence-parser> [ take-c-comment drop ] [ take-rest ] bi
+] unit-test
+
+[ "omg" ] [
+ "//asdfasdf\nomg" <sequence-parser>
+ [ take-c++-comment drop ] [ take-rest ] bi
+] unit-test
+
+[ "omg" ] [
+ "omg" <sequence-parser>
+ [ take-c++-comment drop ] [ take-rest ] bi
+] unit-test
+
+[ "/*asdfasdf" ] [
+ "/*asdfasdf" <sequence-parser> [ take-c-comment drop ] [ take-rest ] bi
+] unit-test
+
+[ "asdf" "eoieoei" ] [
+ "//asdf\neoieoei" <sequence-parser>
+ [ take-c++-comment ] [ take-rest ] bi
+] unit-test
+
+[ f ]
+[
+ "\"abc\" asdf" <sequence-parser>
+ [ CHAR: \ CHAR: " take-quoted-string drop ] [ "asdf" take-sequence ] bi
+] unit-test
+
+[ "abc\\\"def" ]
+[
+ "\"abc\\\"def\" asdf" <sequence-parser>
+ CHAR: \ CHAR: " take-quoted-string
+] unit-test
+
+[ "asdf" ]
+[
+ "\"abc\" asdf" <sequence-parser>
+ [ CHAR: \ CHAR: " take-quoted-string drop ]
+ [ skip-whitespace "asdf" take-sequence ] bi
+] unit-test
+
+[ f ]
+[
+ "\"abc asdf" <sequence-parser>
+ CHAR: \ CHAR: " take-quoted-string
+] unit-test
+
+[ "\"abc" ]
+[
+ "\"abc asdf" <sequence-parser>
+ [ CHAR: \ CHAR: " take-quoted-string drop ]
+ [ "\"abc" take-sequence ] bi
+] unit-test
+
+[ "c" ]
+[ "c" <sequence-parser> take-token ] unit-test
+
+[ f ]
+[ "" <sequence-parser> take-token ] unit-test
+
+[ "abcd e \\\"f g" ]
+[ "\"abcd e \\\"f g\"" <sequence-parser> CHAR: \ CHAR: " take-token* ] unit-test
+
+[ "123" ]
+[ "123jjj" <sequence-parser> take-c-integer ] unit-test
+
+[ "123uLL" ]
+[ "123uLL" <sequence-parser> take-c-integer ] unit-test
+
+[ "123ull" ]
+[ "123ull" <sequence-parser> take-c-integer ] unit-test
+
+[ "123u" ]
+[ "123u" <sequence-parser> take-c-integer ] unit-test
+
--- /dev/null
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators combinators.short-circuit
+generalizations kernel locals math.order math.ranges
+sequence-parser sequences sorting.functor sorting.slots
+unicode.categories ;
+IN: c.lexer
+
+: take-c-comment ( sequence-parser -- seq/f )
+ [
+ dup "/*" take-sequence [
+ "*/" take-until-sequence*
+ ] [
+ drop f
+ ] if
+ ] with-sequence-parser ;
+
+: take-c++-comment ( sequence-parser -- seq/f )
+ [
+ dup "//" take-sequence [
+ [
+ [
+ { [ current CHAR: \n = ] [ sequence-parse-end? ] } 1||
+ ] take-until
+ ] [
+ advance drop
+ ] bi
+ ] [
+ drop f
+ ] if
+ ] with-sequence-parser ;
+
+: skip-whitespace/comments ( sequence-parser -- sequence-parser )
+ skip-whitespace-eol
+ {
+ { [ dup take-c-comment ] [ skip-whitespace/comments ] }
+ { [ dup take-c++-comment ] [ skip-whitespace/comments ] }
+ [ ]
+ } cond ;
+
+: take-define-identifier ( sequence-parser -- string )
+ skip-whitespace/comments
+ [ current { [ blank? ] [ CHAR: ( = ] } 1|| ] take-until ;
+
+:: take-quoted-string ( sequence-parser escape-char quote-char -- string )
+ sequence-parser n>> :> start-n
+ sequence-parser advance
+ [
+ {
+ [ { [ previous escape-char = ] [ current quote-char = ] } 1&& ]
+ [ current quote-char = not ]
+ } 1||
+ ] take-while :> string
+ sequence-parser current quote-char = [
+ sequence-parser advance* string
+ ] [
+ start-n sequence-parser (>>n) f
+ ] if ;
+
+: (take-token) ( sequence-parser -- string )
+ skip-whitespace [ current { [ blank? ] [ f = ] } 1|| ] take-until ;
+
+:: take-token* ( sequence-parser escape-char quote-char -- string/f )
+ sequence-parser skip-whitespace
+ dup current {
+ { quote-char [ escape-char quote-char take-quoted-string ] }
+ { f [ drop f ] }
+ [ drop (take-token) ]
+ } case ;
+
+: take-token ( sequence-parser -- string/f )
+ CHAR: \ CHAR: " take-token* ;
+
+: c-identifier-begin? ( ch -- ? )
+ CHAR: a CHAR: z [a,b]
+ CHAR: A CHAR: Z [a,b]
+ { CHAR: _ } 3append member? ;
+
+: c-identifier-ch? ( ch -- ? )
+ CHAR: a CHAR: z [a,b]
+ CHAR: A CHAR: Z [a,b]
+ CHAR: 0 CHAR: 9 [a,b]
+ { CHAR: _ } 4 nappend member? ;
+
+: (take-c-identifier) ( sequence-parser -- string/f )
+ dup current c-identifier-begin? [
+ [ current c-identifier-ch? ] take-while
+ ] [
+ drop f
+ ] if ;
+
+: take-c-identifier ( sequence-parser -- string/f )
+ [ (take-c-identifier) ] with-sequence-parser ;
+
+<< "length" [ length ] define-sorting >>
+
+: sort-tokens ( seq -- seq' )
+ { length>=< <=> } sort-by ;
+
+: take-c-integer ( sequence-parser -- string/f )
+ [
+ dup take-integer [
+ swap
+ { "ull" "uLL" "Ull" "ULL" "ll" "LL" "l" "L" "u" "U" }
+ take-longest [ append ] when*
+ ] [
+ drop f
+ ] if*
+ ] with-sequence-parser ;
+
+CONSTANT: c-punctuators
+ {
+ "[" "]" "(" ")" "{" "}" "." "->"
+ "++" "--" "&" "*" "+" "-" "~" "!"
+ "/" "%" "<<" ">>" "<" ">" "<=" ">=" "==" "!=" "^" "|" "&&" "||"
+ "?" ":" ";" "..."
+ "=" "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" "&=" "^=" "|="
+ "," "#" "##"
+ "<:" ":>" "<%" "%>" "%:" "%:%:"
+ }
+
+: take-c-punctuator ( sequence-parser -- string/f )
+ c-punctuators take-longest ;
io.streams.string kernel combinators accessors io.pathnames
fry sequences arrays locals namespaces io.directories
assocs math splitting make unicode.categories
-combinators.short-circuit ;
+combinators.short-circuit c.lexer ;
IN: c.preprocessor
: initial-library-paths ( -- seq )
--- /dev/null
+Matthew Willis
--- /dev/null
+USING: central destructors help.markup help.syntax ;
+
+HELP: CENTRAL:
+{ $description
+ "This parsing word defines a pair of words useful for "
+ "implementing the \"central\" pattern: " { $snippet "symbol" } " and "
+ { $snippet "with-symbol" } ". This is a middle ground between excessive "
+ "stack manipulation and full-out locals, meant to solve the case where "
+ "one object is operated on by several related words."
+} ;
+
+HELP: DISPOSABLE-CENTRAL:
+{ $description
+ "Like " { $link POSTPONE: CENTRAL: } ", but generates " { $snippet "with-" }
+ " words that are wrapped in a " { $link with-disposal } "."
+} ;
\ No newline at end of file
--- /dev/null
+USING: accessors central destructors kernel math tools.test ;
+
+IN: scratchpad
+
+CENTRAL: test-central
+
+[ 3 ] [ 3 [ test-central ] with-test-central ] unit-test
+
+TUPLE: test-disp-cent value disposed ;
+
+! A phony destructor that adds 1 to the value so we can make sure it got called.
+M: test-disp-cent dispose* dup value>> 1 + >>value drop ;
+
+DISPOSABLE-CENTRAL: t-d-c
+
+: test-t-d-c ( -- n )
+ test-disp-cent new 3 >>value [ t-d-c ] with-t-d-c value>> ;
+
+[ 4 ] [ test-t-d-c ] unit-test
--- /dev/null
+USING: destructors kernel lexer namespaces parser sequences words ;
+
+IN: central
+
+: define-central-getter ( word -- )
+ dup [ get ] curry (( -- obj )) define-declared ;
+
+: define-centrals ( str -- getter setter )
+ [ create-in dup define-central-getter ]
+ [ "with-" prepend create-in dup make-inline ] bi ;
+
+: central-setter-def ( word with-word -- with-word quot )
+ [ with-variable ] with ;
+
+: disposable-setter-def ( word with-word -- with-word quot )
+ [ pick [ drop with-variable ] with-disposal ] with ;
+
+: declare-central ( with-word quot -- ) (( object quot -- )) define-declared ;
+
+: define-central ( word-name -- )
+ define-centrals central-setter-def declare-central ;
+
+: define-disposable-central ( word-name -- )
+ define-centrals disposable-setter-def declare-central ;
+
+SYNTAX: CENTRAL: ( -- ) scan define-central ;
+
+SYNTAX: DISPOSABLE-CENTRAL: ( -- ) scan define-disposable-central ;
\ No newline at end of file
--- /dev/null
+extensions
--- /dev/null
+USING: classes.tuple.change-tracking tools.test strings accessors kernel continuations ;
+IN: classes.tuple.change-tracking.tests
+
+TUPLE: resource < change-tracking-tuple
+ { pathname string } ;
+
+: <resource> ( pathname -- resource ) f swap resource boa ;
+
+[ t ] [ "foo" <resource> "bar" >>pathname changed?>> ] unit-test
+[ f ] [ "foo" <resource> [ 123 >>pathname ] [ drop ] recover changed?>> ] unit-test
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors classes classes.tuple fry kernel sequences slots ;
+IN: classes.tuple.change-tracking
+
+TUPLE: change-tracking-tuple
+ { changed? boolean } ;
+
+PREDICATE: change-tracking-tuple-class < tuple-class
+ change-tracking-tuple subclass-of? ;
+
+: changed? ( tuple -- changed? ) changed?>> ; inline
+: clear-changed ( tuple -- tuple ) f >>changed? ; inline
+
+: filter-changed ( sequence -- sequence' ) [ changed? ] filter ; inline
+
+<PRIVATE
+
+M: change-tracking-tuple-class writer-quot ( class slot-spec -- )
+ [ call-next-method ]
+ [ name>> "changed?" = [ '[ _ [ t >>changed? drop ] bi ] ] unless ] bi ;
+
+PRIVATE>
+
--- /dev/null
+Tuple classes that keep track of when they've been modified
--- /dev/null
+USING: assocs io.pathnames fry namespaces namespaces.private kernel sequences parser hashtables ;
+IN: closures
+SYMBOL: |
+
+! Selective Binding
+: delayed-bind-with ( vars quot -- quot' ) '[ _ dup [ get ] map zip >hashtable [ _ bind ] curry ] ;
+SYNTAX: C[ | parse-until parse-quotation delayed-bind-with over push-all ;
+! Common ones
+SYNTAX: DIR[ parse-quotation { current-directory } swap delayed-bind-with over push-all ;
+
+! Namespace Binding
+: bind-to-namespace ( quot -- quot' ) '[ namespace [ _ bind ] curry ] ;
+SYNTAX: NS[ parse-quotation bind-to-namespace over push-all ;
\ No newline at end of file
horizontal <slider> 1 >>line ;
: <color-sliders> ( -- gadget model )
- 3 [ 0 0 0 255 <range> ] replicate
+ 3 [ 0 0 0 255 1 <range> ] replicate
[ <filled-pile> { 5 5 } >>gap [ <color-slider> add-gadget ] reduce ]
[ [ range-model ] map <product> ]
bi ;
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: assocs classes help.markup help.syntax kernel math
+quotations strings ;
+IN: combinators.tuple
+
+HELP: 2make-tuple
+{ $values
+ { "x" object } { "y" object } { "class" class } { "assoc" assoc }
+ { "tuple" tuple }
+}
+{ $description "Constructs a " { $link tuple } " of " { $snippet "class" } " by calling the quotations making up the values of " { $snippet "assoc" } " on " { $snippet "x" } " and " { $snippet "y" } ", assigning the result of each call to the slot named by the corresponding key. The quotations must have the effect " { $snippet "( x y -- slot-value )" } ". The order in which the quotations is called is undefined." } ;
+
+HELP: 3make-tuple
+{ $values
+ { "x" object } { "y" object } { "z" object } { "class" class } { "assoc" "a list of " { $link string } "/" { $link quotation } " pairs" }
+ { "tuple" tuple }
+}
+{ $description "Constructs a " { $link tuple } " of " { $snippet "class" } " by calling the quotations making up the values of " { $snippet "assoc" } " on " { $snippet "x" } ", " { $snippet "y" } ", and " { $snippet "z" } ", assigning the result of each call to the slot named by the corresponding key. The quotations must have the effect " { $snippet "( x y z -- slot-value )" } ". The order in which the quotations is called is undefined." } ;
+
+HELP: make-tuple
+{ $values
+ { "x" object } { "class" class } { "assoc" "a list of " { $link string } "/" { $link quotation } " pairs" }
+ { "tuple" tuple }
+}
+{ $description "Constructs a " { $link tuple } " of " { $snippet "class" } " by calling the quotations making up the values of " { $snippet "assoc" } " on " { $snippet "x" } ", assigning the result of each call to the slot named by the corresponding key. The quotations must have the effect " { $snippet "( x -- slot-value )" } ". The order in which the quotations is called is undefined." } ;
+
+HELP: nmake-tuple
+{ $values
+ { "class" class } { "assoc" "a list of " { $link string } "/" { $link quotation } " pairs" } { "n" integer }
+}
+{ $description "Constructs a " { $link tuple } " of " { $snippet "class" } " by calling the quotations making up the values of " { $snippet "assoc" } " on the top " { $snippet "n" } " values on the datastack below " { $snippet "class" } ", assigning the result of each call to the slot named by the corresponding key. The order in which the quotations is called is undefined." } ;
+
+{ make-tuple 2make-tuple 3make-tuple nmake-tuple } related-words
+
+ARTICLE: "combinators.tuple" "Tuple-constructing combinators"
+"The " { $vocab-link "combinators.tuple" } " vocabulary provides dataflow combinators that construct " { $link tuple } " objects."
+{ $subsection make-tuple }
+{ $subsection 2make-tuple }
+{ $subsection 3make-tuple }
+{ $subsection nmake-tuple }
+;
+
+ABOUT: "combinators.tuple"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors assocs classes.tuple generalizations kernel
+locals quotations sequences ;
+IN: combinators.tuple
+
+<PRIVATE
+
+:: (tuple-slot-quot) ( slot assoc n -- quot )
+ slot name>> assoc at [
+ slot initial>> :> initial
+ { n ndrop initial } >quotation
+ ] unless* ;
+
+PRIVATE>
+
+MACRO:: nmake-tuple ( class assoc n -- )
+ class all-slots [ assoc n (tuple-slot-quot) ] map :> quots
+ class <wrapper> :> \class
+ { quots n ncleave \class boa } >quotation ;
+
+: make-tuple ( x class assoc -- tuple )
+ 1 nmake-tuple ; inline
+
+: 2make-tuple ( x y class assoc -- tuple )
+ 2 nmake-tuple ; inline
+
+: 3make-tuple ( x y z class assoc -- tuple )
+ 3 nmake-tuple ; inline
+
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license
+USING: accessors compiler.tree.builder compiler.cfg compiler.cfg.rpo
+compiler.cfg.dominance compiler.cfg.dominance.private
+compiler.cfg.predecessors compiler.cfg.debugger compiler.cfg.optimizer
+compiler.cfg.utilities compiler.tree.recursive images.viewer
+images.png io io.encodings.ascii io.files io.files.unique io.launcher
+kernel math.parser sequences assocs arrays make math namespaces
+quotations combinators locals words ;
+IN: compiler.graphviz
+
+: quotes ( str -- str' ) "\"" "\"" surround ;
+
+: graph, ( quot title -- )
+ [
+ quotes "digraph " " {" surround ,
+ call
+ "}" ,
+ ] { } make , ; inline
+
+: render-graph ( quot -- )
+ { } make
+ "cfg" ".dot" make-unique-file
+ dup "Wrote " prepend print
+ [ [ concat ] dip ascii set-file-lines ]
+ [ { "dot" "-Tpng" "-O" } swap suffix try-process ]
+ [ ".png" append "open" swap 2array try-process ]
+ tri ; inline
+
+: attrs>string ( seq -- str )
+ [ "" ] [ "," join "[" "]" surround ] if-empty ;
+
+: edge,* ( from to attrs -- )
+ [
+ [ quotes % " -> " % ] [ quotes % " " % ] [ attrs>string % ] tri*
+ ";" %
+ ] "" make , ;
+
+: edge, ( from to -- )
+ { } edge,* ;
+
+: bb-edge, ( from to -- )
+ [ number>> number>string ] bi@ edge, ;
+
+: node-style, ( str attrs -- )
+ [ [ quotes % " " % ] [ attrs>string % ";" % ] bi* ] "" make , ;
+
+: cfg-title ( cfg/mr -- string )
+ [
+ "=== word: " %
+ [ word>> name>> % ", label: " % ]
+ [ label>> name>> % ]
+ bi
+ ] "" make ;
+
+: cfg-vertex, ( bb -- )
+ [ number>> number>string ]
+ [ kill-block? { "color=grey" "style=filled" } { } ? ]
+ bi node-style, ;
+
+: cfgs ( cfgs -- )
+ [
+ [
+ [ [ cfg-vertex, ] each-basic-block ]
+ [
+ [
+ dup successors>> [
+ bb-edge,
+ ] with each
+ ] each-basic-block
+ ] bi
+ ] over cfg-title graph,
+ ] each ;
+
+: optimized-cfg ( quot -- cfgs )
+ {
+ { [ dup cfg? ] [ 1array ] }
+ { [ dup quotation? ] [ test-cfg [ optimize-cfg ] map ] }
+ { [ dup word? ] [ test-cfg [ optimize-cfg ] map ] }
+ [ ]
+ } cond ;
+
+: render-cfg ( cfg -- )
+ optimized-cfg [ cfgs ] render-graph ;
+
+: dom-trees ( cfgs -- )
+ [
+ [
+ needs-dominance drop
+ dom-childrens get [
+ [
+ bb-edge,
+ ] with each
+ ] assoc-each
+ ] over cfg-title graph,
+ ] each ;
+
+: render-dom ( cfg -- )
+ optimized-cfg [ dom-trees ] render-graph ;
+
+SYMBOL: word-counts
+SYMBOL: vertex-names
+
+: vertex-name ( call-graph-node -- string )
+ label>> vertex-names get [
+ word>> name>>
+ dup word-counts get [ 0 or 1 + dup ] change-at number>string " #" glue
+ ] cache ;
+
+: vertex-attrs ( obj -- string )
+ tail?>> { "style=bold,label=\"tail\"" } { } ? ;
+
+: call-graph-edge, ( from to attrs -- )
+ [ [ vertex-name ] [ vertex-attrs ] bi ] dip append edge,* ;
+
+: (call-graph-back-edges) ( string calls -- )
+ [ { "color=red" } call-graph-edge, ] with each ;
+
+: (call-graph-edges) ( string children -- )
+ [
+ {
+ [ { } call-graph-edge, ]
+ [ [ vertex-name ] [ label>> loop?>> { "shape=box" } { } ? ] bi node-style, ]
+ [ [ vertex-name ] [ calls>> ] bi (call-graph-back-edges) ]
+ [ [ vertex-name ] [ children>> ] bi (call-graph-edges) ]
+ } cleave
+ ] with each ;
+
+: call-graph-edges ( call-graph-node -- )
+ H{ } clone word-counts set
+ H{ } clone vertex-names set
+ [ "ROOT" ] dip (call-graph-edges) ;
+
+: render-call-graph ( tree -- )
+ dup quotation? [ build-tree ] when
+ analyze-recursive drop
+ [ [ call-graph get call-graph-edges ] "Call graph" graph, ]
+ render-graph ;
\ No newline at end of file
--- /dev/null
+Slava Pestov
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test constructors calendar kernel accessors
+combinators.short-circuit initializers math ;
+IN: constructors.tests
+
+TUPLE: stock-spread stock spread timestamp ;
+
+CONSTRUCTOR: stock-spread ( stock spread -- stock-spread )
+ now >>timestamp ;
+
+SYMBOL: AAPL
+
+[ t ] [
+ AAPL 1234 <stock-spread>
+ {
+ [ stock>> AAPL eq? ]
+ [ spread>> 1234 = ]
+ [ timestamp>> timestamp? ]
+ } 1&&
+] unit-test
+
+TUPLE: ct1 a ;
+TUPLE: ct2 < ct1 b ;
+TUPLE: ct3 < ct2 c ;
+TUPLE: ct4 < ct3 d ;
+
+CONSTRUCTOR: ct1 ( a -- obj )
+ [ 1 + ] change-a ;
+
+CONSTRUCTOR: ct2 ( a b -- obj )
+ [ 1 + ] change-a ;
+
+CONSTRUCTOR: ct3 ( a b c -- obj )
+ [ 1 + ] change-a ;
+
+CONSTRUCTOR: ct4 ( a b c d -- obj )
+ [ 1 + ] change-a ;
+
+[ 1001 ] [ 1000 <ct1> a>> ] unit-test
+[ 2 ] [ 0 0 <ct2> a>> ] unit-test
+[ 3 ] [ 0 0 0 <ct3> a>> ] unit-test
+[ 4 ] [ 0 0 0 0 <ct4> a>> ] unit-test
--- /dev/null
+! Copyright (C) 2009 Slava Pestov, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs classes classes.tuple effects.parser
+fry generalizations generic.standard kernel lexer locals macros
+parser sequences slots vocabs words arrays ;
+IN: constructors
+
+! An experiment
+
+: initializer-name ( class -- word )
+ name>> "initialize-" prepend ;
+
+: lookup-initializer ( class -- word/f )
+ initializer-name "initializers" lookup ;
+
+: initializer-word ( class -- word )
+ initializer-name
+ "initializers" create-vocab create
+ [ t "initializer" set-word-prop ] [ ] bi ;
+
+: define-initializer-generic ( name -- )
+ initializer-word (( object -- object )) define-simple-generic ;
+
+: define-initializer ( class def -- )
+ [ drop define-initializer-generic ]
+ [ [ dup lookup-initializer ] dip H{ } clone define-typecheck ] 2bi ;
+
+: all-slots-assoc ( class -- slots )
+ superclasses [ [ "slots" word-prop ] keep '[ _ ] { } map>assoc ] map concat ;
+
+MACRO:: slots>constructor ( class slots -- quot )
+ class all-slots-assoc slots [ '[ first name>> _ = ] find-last nip ] with map :> slot-assoc
+ class all-slots-assoc [ [ ] [ first initial>> ] bi ] { } map>assoc :> default-params
+ slots length
+ default-params length
+ '[
+ _ narray slot-assoc swap zip
+ default-params swap assoc-union values _ firstn class boa
+ ] ;
+
+:: (define-constructor) ( constructor-word class effect def -- word quot )
+ constructor-word
+ class def define-initializer
+ class effect in>> '[ _ _ slots>constructor ] ;
+
+:: define-constructor ( constructor-word class effect def reverse? -- )
+ constructor-word class effect def (define-constructor)
+ class superclasses [ lookup-initializer ] map sift
+ reverse? [ reverse ] when
+ '[ @ _ [ execute( obj -- obj ) ] each ] effect define-declared ;
+
+: scan-constructor ( -- class word )
+ scan-word [ name>> "<" ">" surround create-in ] keep ;
+
+: parse-constructor ( -- class word effect def )
+ scan-constructor complete-effect parse-definition ;
+
+SYNTAX: CONSTRUCTOR: parse-constructor f define-constructor ;
+
+"initializers" create-vocab drop
--- /dev/null
+Utility to simplify tuple constructors
--- /dev/null
+extensions
: changelog ( -- authors )
image parent-directory [
- "git log --pretty=format:%an" ascii <process-reader> stream-lines
+ "git log --no-merges --pretty=format:%an" ascii <process-reader> stream-lines
] with-directory ;
: patch-counts ( authors -- assoc )
[ drop 1 coyield* 2 coyield* 3 coterminate ] cocreate ;
: test2 ( -- co )
- [ 1+ coyield* ] cocreate ;
+ [ 1 + coyield* ] cocreate ;
test1 dup *coresume . dup *coresume . dup *coresume . dup *coresume 2drop
[ test2 42 over coresume . dup *coresume . drop ] must-fail
{ "c" "b" "a" } [ test3 { "a" "b" "c" } over coresume [ dup *coresume [ *coresume ] dip ] dip ] unit-test
-{ 4+2/3 } [ [ 1+ coyield 2 * coyield 3 / coreset ] cocreate 1 5 [ over coresume ] times nip ] unit-test
\ No newline at end of file
+{ 4+2/3 } [ [ 1 + coyield 2 * coyield 3 / coreset ] cocreate 1 5 [ over coresume ] times nip ] unit-test
: barrett-mu ( n size -- mu )
#! Calculates Barrett's reduction parameter mu
#! size = word size in bits (8, 16, 32, 64, ...)
- [ [ log2 1+ ] [ / 2 * ] bi* ]
+ [ [ log2 1 + ] [ / 2 * ] bi* ]
[ 2^ rot ^ swap /i ] 2bi ;
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" nth ; inline
: to64 ( v n -- string )
- [ [ -6 shift ] [ 6 2^ 1- bitand lookup-table ] bi ]
+ [ [ -6 shift ] [ 6 2^ 1 - bitand lookup-table ] bi ]
replicate nip ; inline
PRIVATE>
: modulus-phi ( numbits -- n phi )
#! Loop until phi is not divisible by the public key.
dup rsa-primes [ * ] 2keep
- [ 1- ] bi@ *
+ [ 1 - ] bi@ *
dup public-key gcd nip 1 = [
rot drop
] [
H{ } clone swap [ swap [ etag-add ] keep ] each ;
: lines>bytes ( seq n -- bytes )
- head 0 [ length 1+ + ] reduce ;
+ head 0 [ length 1 + + ] reduce ;
: file>lines ( path -- lines )
ascii file-lines ;
1 HEX: 7f <string> %
second dup number>string %
1 CHAR: , <string> %
- 1- lines>bytes number>string %
+ 1 - lines>bytes number>string %
] "" make ;
: etag-length ( vector -- n )
[ etag-strings ] dip ascii set-file-lines ;
: etags ( path -- )
- [ (ctags) sort-values etag-hash >alist ] dip etags-write ;
\ No newline at end of file
+ [ (ctags) sort-values etag-hash >alist ] dip etags-write ;
[ f ] [ { 2 4 6 } [ odd? ] any? ] unit-test
[ { 1 3 5 } ] [ { 1 2 3 4 5 6 } [ odd? ] filter ] unit-test
+
+[ { } ]
+[ { 1 2 } { } [ + ] 2map ] unit-test
+
+[ { 11 } ]
+[ { 1 2 } { 10 } [ + ] 2map ] unit-test
+
+[ { 11 22 } ]
+[ { 1 2 } { 10 20 } [ + ] 2map ] unit-test
+
+[ { } ]
+[ { 1 2 } { } { } [ + + ] 3map ] unit-test
+
+[ { 111 } ]
+[ { 1 2 } { 10 } { 100 200 } [ + + ] 3map ] unit-test
+
+[ { 111 222 } ]
+[ { 1 2 } { 10 20 } { 100 200 } [ + + ] 3map ] unit-test
+
+: test-3map ( -- seq )
+ { 1 2 } { 10 20 } { 100 200 } [ + + ] 3map ;
+
+[ { 111 222 } ] [ test-3map ] unit-test
! Copyright (C) 2009 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel math sequences sequences.private ;
+USING: accessors arrays generalizations kernel math sequences
+sequences.private fry ;
IN: cursors
GENERIC: cursor-done? ( cursor -- ? )
[ [ call ] dip cursor-write ] 2curry ; inline
: cursor-map ( from to quot -- )
- swap cursor-map-quot cursor-each ; inline
+ swap cursor-map-quot cursor-each ; inline
: cursor-write-if ( obj quot to -- )
[ over [ call ] dip ] dip
>from-sequence< nth-unsafe ;
M: from-sequence cursor-advance
- [ 1+ ] change-n drop ;
+ [ 1 + ] change-n drop ;
: >input ( seq -- cursor )
0 from-sequence boa ; inline
: map ( seq quot -- ) [ cursor-map ] transform ; inline
: filter ( seq quot -- newseq ) [ cursor-filter ] transform ; inline
+
+: find-done2? ( cursor cursor quot -- ? )
+ 2over [ cursor-done? ] either?
+ [ 3drop t ] [ [ [ cursor-get-unsafe ] bi@ ] dip call ] if ; inline
+
+: cursor-until2 ( cursor cursor quot -- )
+ [ find-done2? not ]
+ [ drop [ cursor-advance ] bi@ ] bi-curry bi-curry bi-curry while ; inline
+
+: cursor-each2 ( cursor cursor quot -- )
+ [ f ] compose cursor-until2 ; inline
+
+: cursor-map2 ( from to quot -- )
+ swap cursor-map-quot cursor-each2 ; inline
+
+: iterate2 ( seq1 seq2 quot iterator -- )
+ [ [ >input ] bi@ ] 2dip call ; inline
+
+: transform2 ( seq1 seq2 quot transformer -- newseq )
+ [ over >output [ [ >input ] [ >input ] bi* ] dip ] 2dip
+ [ call ]
+ [ 2drop nip freeze ] 4 nbi ; inline
+
+: 2each ( seq1 seq2 quot -- ) [ cursor-each2 ] iterate2 ; inline
+: 2map ( seq1 seq2 quot -- ) [ cursor-map2 ] transform2 ; inline
+
+: find-done3? ( cursor1 cursor2 cursor3 quot -- ? )
+ [ 3 ndrop t ] swap '[ [ cursor-get-unsafe ] tri@ @ ]
+ [ 3 ndup 3 narray [ cursor-done? ] any? ] 2dip if ; inline
+
+: cursor-until3 ( cursor cursor quot -- )
+ [ find-done3? not ]
+ [ drop [ cursor-advance ] tri@ ]
+ bi-curry bi-curry bi-curry bi-curry while ; inline
+
+: cursor-each3 ( cursor cursor quot -- )
+ [ f ] compose cursor-until3 ; inline
+
+: cursor-map3 ( from to quot -- )
+ swap cursor-map-quot cursor-each3 ; inline
+
+: iterate3 ( seq1 seq2 seq3 quot iterator -- )
+ [ [ >input ] tri@ ] 2dip call ; inline
+
+: transform3 ( seq1 seq2 seq3 quot transformer -- newseq )
+ [ pick >output [ [ >input ] [ >input ] [ >input ] tri* ] dip ] 2dip
+ [ call ]
+ [ 2drop 2nip freeze ] 5 nbi ; inline
+
+: 3each ( seq1 seq2 seq3 quot -- ) [ cursor-each3 ] iterate3 ; inline
+: 3map ( seq1 seq2 seq3 quot -- ) [ cursor-map3 ] transform3 ; inline
--- /dev/null
+USING: accessors sequences generalizations io.encodings.utf8 db.postgresql parser combinators vocabs.parser db.sqlite
+io.files ;
+IN: db.info
+! having sensative (and likely to change) information directly in source code seems a bad idea
+: get-info ( -- lines ) current-vocab name>> "vocab:" "/dbinfo.txt" surround utf8 file-lines ;
+SYNTAX: get-psql-info <postgresql-db> get-info 5 firstn
+ {
+ [ >>host ]
+ [ >>port ]
+ [ >>username ]
+ [ [ f ] [ ] if-empty >>password ]
+ [ >>database ]
+ } spread parsed ;
+
+SYNTAX: get-sqlite-info get-info first <sqlite-db> parsed ;
\ No newline at end of file
-USING: descriptive kernel math tools.test continuations prettyprint io.streams.string see ;\r
+USING: descriptive kernel math tools.test continuations prettyprint io.streams.string see\r
+math.ratios ;\r
IN: descriptive.tests\r
\r
DESCRIPTIVE: divide ( num denom -- fraction ) / ;\r
\r
[ 3 ] [ 9 3 divide ] unit-test\r
-[ T{ descriptive-error f { { "num" 3 } { "denom" 0 } } "Division by zero" divide } ] [ [ 3 0 divide ] [ ] recover ] unit-test\r
\r
-[ "USING: descriptive math ;\nIN: descriptive.tests\nDESCRIPTIVE: divide ( num denom -- fraction ) / ;\n" ] [ \ divide [ see ] with-string-writer ] unit-test\r
+[\r
+ T{ descriptive-error f\r
+ { { "num" 3 } { "denom" 0 } }\r
+ T{ division-by-zero f 3 }\r
+ divide\r
+ }\r
+] [\r
+ [ 3 0 divide ] [ ] recover\r
+] unit-test\r
+\r
+[ "USING: descriptive math ;\nIN: descriptive.tests\nDESCRIPTIVE: divide ( num denom -- fraction ) / ;\n" ]\r
+[ \ divide [ see ] with-string-writer ] unit-test\r
\r
DESCRIPTIVE:: divide* ( num denom -- fraction ) num denom / ;\r
\r
[ 3 ] [ 9 3 divide* ] unit-test\r
-[ T{ descriptive-error f { { "num" 3 } { "denom" 0 } } "Division by zero" divide* } ] [ [ 3 0 divide* ] [ ] recover ] unit-test\r
+\r
+[\r
+ T{ descriptive-error f\r
+ { { "num" 3 } { "denom" 0 } }\r
+ T{ division-by-zero f 3 }\r
+ divide*\r
+ }\r
+] [ [ 3 0 divide* ] [ ] recover ] unit-test\r
\r
[ "USING: descriptive math ;\nIN: descriptive.tests\nDESCRIPTIVE:: divide* ( num denom -- fraction ) num denom / ;\n" ] [ \ divide* [ see ] with-string-writer ] unit-test\r
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: cdr-name ( name -- name ) dup CHAR: . index 1+ tail ;
+: cdr-name ( name -- name ) dup CHAR: . index 1 + tail ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! have-delegates?
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: cdr-name ( name -- name ) dup CHAR: . index 1+ tail ;
+: cdr-name ( name -- name ) dup CHAR: . index 1 + tail ;
: is-soa? ( name -- ? ) SOA IN query boa matching-rrs empty? not ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: sort-largest-first ( seq -- seq ) [ [ length ] compare ] sort reverse ;
+: sort-largest-first ( seq -- seq ) [ length ] sort-with reverse ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
USING: tools.deploy.config ;
H{
- { deploy-unicode? f }
+ { deploy-name "drills" }
+ { deploy-c-types? t }
+ { "stop-after-last-window?" t }
+ { deploy-unicode? t }
{ deploy-threads? t }
+ { deploy-reflection 6 }
+ { deploy-word-defs? t }
{ deploy-math? t }
- { deploy-name "drills" }
{ deploy-ui? t }
- { "stop-after-last-window?" t }
- { deploy-word-props? f }
- { deploy-c-types? f }
- { deploy-io 2 }
- { deploy-word-defs? f }
- { deploy-reflection 1 }
+ { deploy-word-props? t }
+ { deploy-io 3 }
}
-USING: accessors arrays cocoa.dialogs combinators continuations
+USING: arrays cocoa.dialogs combinators continuations
fry grouping io.encodings.utf8 io.files io.styles kernel math
math.parser models models.arrow models.history namespaces random
sequences splitting ui ui.gadgets.alerts ui.gadgets.book-extras
ui.gadgets.books ui.gadgets.buttons ui.gadgets.frames
ui.gadgets.grids ui.gadgets.labels ui.gadgets.tracks fonts
wrap.strings system ;
-
+EXCLUDE: accessors => change-model ;
IN: drills.deployed
SYMBOLS: it startLength ;
: big ( gadget -- gadget ) T{ font { name "sans-serif" } { size 30 } } >>font ;
-USING: accessors arrays cocoa.dialogs combinators continuations
+USING: arrays cocoa.dialogs combinators continuations
fry grouping io.encodings.utf8 io.files io.styles kernel math
math.parser models models.arrow models.history namespaces random
sequences splitting ui ui.gadgets.alerts ui.gadgets.book-extras
ui.gadgets.books ui.gadgets.buttons ui.gadgets.frames
ui.gadgets.grids ui.gadgets.labels ui.gadgets.tracks fonts
wrap.strings ;
+EXCLUDE: accessors => change-model ;
IN: drills
SYMBOLS: it startLength ;
: big ( gadget -- gadget ) T{ font { name "sans-serif" } { size 30 } } >>font ;
: card ( model quot -- button ) <arrow> <label-control> big [ next ] <book-btn> ;
-: op ( quot str -- gadget ) <label> big swap <book-bevel-btn> ;
+: op ( quot str -- gadget ) <label> big swap <book-border-btn> ;
: show ( model -- gadget ) dup it set-global [ random ] <arrow>
{ [ [ first ] card ]
KEY EC_KEY_get0_public_key dup
[| PUB |
KEY EC_KEY_get0_group :> GROUP
- GROUP EC_GROUP_get_degree bits>bytes 1+ :> LEN
+ GROUP EC_GROUP_get_degree bits>bytes 1 + :> LEN
LEN <byte-array> :> BIN
GROUP PUB POINT_CONVERSION_COMPRESSED BIN LEN f
EC_POINT_point2oct ssl-error
LEN *uint SIG resize ;
: ecdsa-verify ( dgst sig -- ? )
- ec-key-handle [ 0 -rot [ dup length ] bi@ ] dip ECDSA_verify 0 > ;
\ No newline at end of file
+ ec-key-handle [ 0 -rot [ dup length ] bi@ ] dip ECDSA_verify 0 > ;
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel parser vocabs.parser words ;
+IN: enter
+! main words are usually only used for entry, doing initialization, etc
+! it makes sense, then to define it all at once, rather than factoring it out into a seperate word
+! and then declaring it main
+SYNTAX: ENTER: gensym [ parse-definition (( -- )) define-declared ] keep current-vocab (>>main) ;
\ No newline at end of file
+++ /dev/null
-USING: kernel file-trees ;
-IN: file-trees.tests
-{ "/sample/1" "/sample/2" "/killer/1" "/killer/2/3"
-"/killer/2/4" "/killer/2/4/6" "/megakiller" } create-tree drop
\ No newline at end of file
+++ /dev/null
-USING: accessors arrays delegate delegate.protocols
-io.pathnames kernel locals namespaces prettyprint sequences
-ui.frp vectors ;
-IN: file-trees
-
-TUPLE: tree node children ;
-CONSULT: sequence-protocol tree children>> ;
-
-: <tree> ( start -- tree ) V{ } clone
- [ tree boa dup children>> ] [ ".." swap tree boa ] bi swap push ;
-
-DEFER: (tree-insert)
-
-: tree-insert ( path tree -- ) [ unclip <tree> ] [ children>> ] bi* (tree-insert) ;
-:: (tree-insert) ( path-rest path-head tree-children -- )
- tree-children [ node>> path-head node>> = ] find nip
- [ path-rest swap tree-insert ]
- [
- path-head tree-children push
- path-rest [ path-head tree-insert ] unless-empty
- ] if* ;
-: create-tree ( file-list -- tree ) [ path-components ] map
- t <tree> [ [ tree-insert ] curry each ] keep ;
-
-: <dir-table> ( tree-model -- table )
- <frp-list*> [ node>> 1array ] >>quot
- [ selected-value>> <switch> ]
- [ swap >>model ] bi ;
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+Syntax for modifying gadget fonts
\ No newline at end of file
--- /dev/null
+USING: help.syntax help.markup ;
+IN: fonts.syntax
+
+HELP: FONT:
+{ $syntax "\"testing\" <label> FONT: 18 serif bold ... ;" }
+{ $description "Used after a gadget to change font settings. Attributes can be in any order: the first number is set as the size, the style attributes like bold and italic will set the bold? and italic? slots, and font-names like serif or monospace will set the name slot." } ;
\ No newline at end of file
--- /dev/null
+USING: accessors arrays variants combinators io.styles
+kernel math parser sequences fry ;
+IN: fonts.syntax
+
+VARIANT: fontname serif monospace ;
+
+: install ( object quot -- quot/? ) over [ curry ] [ 2drop [ ] ] if ;
+
+: >>name* ( object fontname -- object ) name>> >>name ;
+
+SYNTAX: FONT: \ ; parse-until {
+ [ [ number? ] find nip [ >>size ] install ]
+ [ [ italic = ] find nip [ >>italic? ] install ]
+ [ [ bold = ] find nip [ >>bold? ] install ]
+ [ [ fontname? ] find nip [ >>name* ] install ]
+} cleave 4array concat '[ dup font>> @ drop ] over push-all ;
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+USING: arrays vectors combinators effects kernel math sequences splitting
+strings.parser parser fry sequences.extras ;
+IN: fries
+: str-fry ( str on -- quot ) split
+ [ unclip-last [ [ spin glue ] reduce-r ] 2curry ]
+ [ length 1 - 1 <effect> [ call-effect ] 2curry ] bi ;
+: gen-fry ( str on -- quot ) split
+ [ unclip-last [ [ spin 1array glue ] reduce-r ] 2curry ]
+ [ length 1 - 1 <effect> [ call-effect ] 2curry ] bi ;
+
+SYNTAX: i" parse-string rest "_" str-fry over push-all ;
+SYNTAX: i{ \ } parse-until >array { _ } gen-fry over push-all ;
+SYNTAX: iV{ \ } parse-until >vector V{ _ } gen-fry over push-all ;
--- /dev/null
+Generalized Frying
\ No newline at end of file
USING: accessors arrays assocs combinators help help.crossref
help.markup help.topics io io.streams.string kernel make namespaces
parser prettyprint sequences summary help.vocabs
-vocabs vocabs.loader vocabs.hierarchy vocabs.metadata words see ;
-
+vocabs vocabs.loader vocabs.hierarchy vocabs.metadata words see
+listener ;
+FROM: vocabs.hierarchy => child-vocabs ;
IN: fuel.help
<PRIVATE
[ fuel-vocab-help-table ] bi*
[ 2array ] [ drop f ] if*
] if-empty
- ] { } assoc>map [ ] filter ;
+ ] { } assoc>map sift ;
: fuel-vocab-children-help ( name -- element )
- all-child-vocabs fuel-vocab-list ; inline
+ child-vocabs fuel-vocab-list ; inline
: fuel-vocab-describe-words ( name -- element )
[ words. ] with-string-writer \ describe-words swap 2array ; inline
dup dup >vocab-link where normalize-loc 4array ;
: sort-xrefs ( seq -- seq' )
- [ [ first ] dip first <=> ] sort ;
+ [ first ] sort-with ;
: format-xrefs ( seq -- seq' )
[ word? ] filter [ word>xref ] map ;
: current-words ( -- seq )
manifest get
- [ search-vocabs>> ] [ qualified-vocabs>> ] bi [ words>> ] bi@
- assoc-union keys ;
+ [ search-vocabs>> ] [ qualified-vocabs>> ] bi [ [ words>> ] map ] bi@
+ append H{ } [ assoc-union ] reduce keys ;
: vocabs-words ( names -- seq )
prune [ (vocab-words) ] map concat ;
: article-location ( name -- loc ) article loc>> get-loc ;
-: get-vocabs ( -- seq ) all-vocabs-seq [ vocab-name ] map ;
+: get-vocabs ( -- seq ) all-vocab-names ;
: get-vocabs/prefix ( prefix -- seq ) get-vocabs swap filter-prefix ;
USING: accessors calendar continuations destructors kernel math
-math.order namespaces system threads ui ui.gadgets.worlds ;
+math.order namespaces system threads ui ui.gadgets.worlds
+sequences ;
IN: game-loop
TUPLE: game-loop
<PRIVATE
: redraw ( loop -- )
- [ 1+ ] change-frame-number
+ [ 1 + ] change-frame-number
[ tick-slice ] [ delegate>> ] bi draw* ;
: tick ( loop -- )
delegate>> tick* ;
: increment-tick ( loop -- )
- [ 1+ ] change-tick-number
+ [ 1 + ] change-tick-number
dup tick-length>> [ + ] curry change-last-tick
drop ;
: ?tick ( loop count -- )
- dup zero? [ drop millis >>last-tick drop ] [
+ [ millis >>last-tick drop ] [
over [ since-last-tick ] [ tick-length>> ] bi >=
- [ [ drop increment-tick ] [ drop tick ] [ 1- ?tick ] 2tri ]
+ [ [ drop increment-tick ] [ drop tick ] [ 1 - ?tick ] 2tri ]
[ 2drop ] if
- ] if ;
+ ] if-zero ;
: (run-loop) ( loop -- )
dup running?>>
USING: accessors game-input game-loop kernel math ui.gadgets
-ui.gadgets.worlds ui.gestures ;
+ui.gadgets.worlds ui.gestures threads ;
IN: game-worlds
TUPLE: game-world < world
GENERIC: tick-length ( world -- millis )
M: game-world draw*
- swap >>tick-slice draw-world ;
+ swap >>tick-slice relayout-1 yield ;
M: game-world begin-world
open-game-input
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: alien byte-arrays destructors help.markup help.syntax kernel math
+quotations ;
+IN: gpu.buffers
+
+HELP: <buffer-ptr>
+{ $values
+ { "buffer" buffer } { "offset" integer }
+ { "buffer-ptr" buffer-ptr }
+}
+{ $description "Constructs a " { $link buffer-ptr } " tuple." } ;
+
+HELP: <buffer-range>
+{ $values
+ { "buffer" buffer } { "offset" integer } { "size" integer }
+ { "buffer-range" buffer-range }
+}
+{ $description "Constructs a " { $link buffer-range } " tuple." } ;
+
+HELP: <buffer>
+{ $values
+ { "upload" buffer-upload-pattern }
+ { "usage" buffer-usage-pattern }
+ { "kind" buffer-kind }
+ { "size" integer }
+ { "initial-data" { $maybe c-ptr } }
+ { "buffer" buffer }
+}
+{ $description "Allocates a new " { $link buffer } " object of " { $snippet "size" } " bytes. If " { $snippet "initial-data" } " is not " { $link f } ", " { $snippet "size" } " bytes are copied from " { $snippet "initial-data" } " into the buffer to initialize it; otherwise, the buffer content is left uninitialized. " { $snippet "upload" } ", " { $snippet "usage" } ", and " { $snippet "kind" } " provide hints to the implementation about the expected usage pattern of the buffer as documented in the " { $link buffer } " class documentation." } ;
+
+HELP: allocate-buffer
+{ $values
+ { "buffer" buffer } { "size" integer } { "initial-data" { $maybe c-ptr } }
+}
+{ $description "Discards any memory currently held by " { $snippet "buffer" } " and reallocates a new memory block of " { $snippet "size" } " bytes for it. If " { $snippet "initial-data" } " is not " { $link f } ", " { $snippet "size" } " bytes are copied from " { $snippet "initial-data" } " into the buffer to initialize it; otherwise, the buffer content is left uninitialized." } ;
+
+HELP: buffer
+{ $class-description "Objects of this class represent GPU-accessible memory buffers. Buffer objects can be used to store vertex data and to update or read pixel data from textures and framebuffers without CPU involvement. The data inside buffer objects may be resident in main memory or different parts of GPU memory; the graphics driver will choose a location for a buffer based on usage hints specified when the buffer object is constructed with " { $link <buffer> } " or " { $link byte-array>buffer } ":"
+{ $list
+{ { $snippet "upload-pattern" } " is one of the " { $link buffer-upload-pattern } " values and indicates how frequently the data in the buffer will be updated with new data from CPU memory." }
+{ { $snippet "usage-pattern" } " is one of the " { $link buffer-usage-pattern } " values and indicates how frequently the data in the buffer will be updated with new data from CPU memory." }
+{ { $snippet "kind" } " is one of the " { $link buffer-kind } " values and indicates the primary purpose of the buffer." }
+}
+"These settings are only performance hints and do not restrict the usage of the buffer in any way. For example, a buffer constructed as a " { $link vertex-buffer } " with " { $link static-upload } " can still receive pixel data as though it were a " { $link pixel-pack-buffer } ", and can still be updated with " { $link copy-buffer } " or " { $link update-buffer } ". However, performance may be worse when actual usage conflicts with declared usage."
+} ;
+
+HELP: buffer-access-mode
+{ $class-description "A " { $snippet "buffer-access-mode" } " value is passed to " { $link with-mapped-buffer } " to control access to the mapped address space." }
+{ $list
+{ { $link read-access } " permits the mapped address space only to be read from." }
+{ { $link write-access } " permits the mapped address space only to be written to." }
+{ { $link read-write-access } " permits full access to the mapped address space." }
+} ;
+
+HELP: buffer-kind
+{ $class-description { $snippet "buffer-kind" } " values tell the graphics driver what the primary application of a " { $link buffer } " object will be. Note that any buffer can be used for any purpose; however, performance may be improved if a buffer object is constructed as the same kind as its primary use case."
+{ $list
+{ "A " { $link vertex-buffer } " is used to store vertex attribute data to be rendered as part of a vertex array." }
+{ "An " { $link index-buffer } " is used to store indexes into a vertex array." }
+{ "A " { $link pixel-unpack-buffer } " is used as a source for updating texture image data." }
+{ "A " { $link pixel-pack-buffer } " is used as a destination for reading texture or framebuffer image data." }
+{ "A " { $link transform-feedback-buffer } " is used as a destination for transform feedback output from a vertex shader." }
+} }
+{ $notes "The " { $snippet "pixel-unpack-buffer" } " and " { $snippet "pixel-pack-buffer" } " kinds require OpenGL 2.1 or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+HELP: buffer-ptr
+{ $class-description "A " { $snippet "buffer-ptr" } " references a memory location inside a " { $link buffer } " object. " { $snippet "buffer-ptr" } "s are tuples with the following slots:"
+{ $list
+{ { $snippet "buffer" } " is the " { $link buffer } " object being referenced." }
+{ { $snippet "offset" } " is an integer offset from the beginning of the buffer." }
+} } ;
+
+HELP: buffer-ptr>range
+{ $values
+ { "buffer-ptr" buffer-ptr }
+ { "buffer-range" buffer-range }
+}
+{ $description "Converts a " { $link buffer-ptr } " into a " { $link buffer-range } " spanning from the " { $snippet "offset" } " referenced by the " { $snippet "buffer-ptr" } " to the end of the underlying " { $link buffer } "." } ;
+
+HELP: buffer-range
+{ $class-description "A " { $snippet "buffer-range" } " references a subset of a " { $link buffer } " object's memory. " { $snippet "buffer-range" } "s are tuples with the following slots:"
+{ $list
+{ { $snippet "buffer" } " is the " { $link buffer } " object being referenced." }
+{ { $snippet "offset" } " is an integer offset from the beginning of the buffer to the beginning of the referenced range." }
+{ { $snippet "size" } " is the integer length from the beginning offset to the end of the referenced range." }
+} } ;
+
+{ buffer-ptr buffer-range } related-words
+
+HELP: buffer-size
+{ $values
+ { "buffer" buffer }
+ { "size" integer }
+}
+{ $description "Returns the size in bytes of the memory currently allocated for a " { $link buffer } " object." } ;
+
+HELP: buffer-upload-pattern
+{ $class-description { $snippet "buffer-upload-pattern" } " values aid the graphics driver in optimizing access to " { $link buffer } " objects by declaring the frequency with which the buffer will be supplied new data."
+{ $list
+{ { $link stream-upload } " declares that the buffer data will only be used a few times before being deallocated by " { $link dispose } " or replaced by " { $link allocate-buffer } "." }
+{ { $link static-upload } " declares that the buffer data will be provided once and accessed frequently without modification." }
+{ { $link dynamic-upload } " declares that the buffer data will be frequently modified." }
+}
+"A " { $snippet "buffer-upload-pattern" } " is only a declaration and does not actually control access to the underlying buffer data." } ;
+
+HELP: buffer-usage-pattern
+{ $class-description { $snippet "buffer-usage-pattern" } " values aid the graphics driver in optimizing access to " { $link buffer } " objects by declaring the primary provider and consumer of data for the buffer."
+{ $list
+{ { $link draw-usage } " declares that the buffer will be supplied with data from CPU memory and read from by the GPU for vertex or texture image data." }
+{ { $link read-usage } " declares that the buffer will be supplied with data from other GPU resources and read from primarily by the CPU." }
+{ { $link copy-usage } " declares that the buffer will both receive and supply data primarily for other GPU resources." }
+}
+"A " { $snippet "buffer-usage-pattern" } " is only a declaration and does not actually control access to the underlying buffer data." } ;
+
+{ buffer-kind buffer-upload-pattern buffer-usage-pattern } related-words
+
+HELP: byte-array>buffer
+{ $values
+ { "byte-array" byte-array }
+ { "upload" buffer-upload-pattern }
+ { "usage" buffer-usage-pattern }
+ { "kind" buffer-kind }
+ { "buffer" buffer }
+}
+{ $description "Allocates a new " { $link buffer } " object with the size and contents of " { $snippet "byte-array" } ". " { $snippet "upload" } ", " { $snippet "usage" } ", and " { $snippet "kind" } " provide hints to the implementation about the expected usage pattern of the buffer as documented in the " { $link buffer } " class documentation." } ;
+
+HELP: copy-buffer
+{ $values
+ { "to-buffer-ptr" buffer-ptr } { "from-buffer-ptr" buffer-ptr } { "size" integer }
+}
+{ $description "Instructs the GPU to asynchronously copy " { $snippet "size" } " bytes from " { $snippet "from-buffer-ptr" } " into " { $snippet "to-buffer-ptr" } "." }
+{ $notes "This word requires that the graphics context support OpenGL 3.1 or the " { $snippet "GL_ARB_copy_buffer" } " extension." } ;
+
+HELP: copy-usage
+{ $class-description "This " { $link buffer-usage-pattern } " declares that a " { $link buffer } " object will be primarily read from and written to by other GPU resources." } ;
+
+HELP: draw-usage
+{ $class-description "This " { $link buffer-usage-pattern } " declares that a " { $link buffer } " object will be primarily read from by the GPU and written to by the CPU." } ;
+
+HELP: dynamic-upload
+{ $class-description "This " { $link buffer-upload-pattern } " declares that a " { $link buffer } " object's data store will be updated frequently during its lifetime." } ;
+
+HELP: gpu-data-ptr
+{ $class-description "This class is a union of the " { $link c-ptr } " and " { $link buffer-ptr } " classes. It represents a value that can be supplied either from CPU or GPU memory." } ;
+
+HELP: index-buffer
+{ $class-description "This " { $link buffer-kind } " declares that a " { $link buffer } "'s primary use will be to index vertex arrays." } ;
+
+HELP: pixel-pack-buffer
+{ $class-description "This " { $link buffer-kind } " declares that a " { $link buffer } "'s primary use will be as a destination for receiving image data from textures or framebuffers." }
+{ $notes "This word requires OpenGL 2.1 or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+HELP: pixel-unpack-buffer
+{ $class-description "This " { $link buffer-kind } " declares that a " { $link buffer } "'s primary use will be as a source for supplying image data to textures." }
+{ $notes "This word requires OpenGL 2.1 or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+HELP: read-access
+{ $class-description "This " { $link buffer-access-mode } " value requests read-only access when mapping a " { $link buffer } " object through " { $link with-mapped-buffer } "." } ;
+
+HELP: read-buffer
+{ $values
+ { "buffer-ptr" buffer-ptr } { "size" integer }
+ { "data" byte-array }
+}
+{ $description "Reads " { $snippet "size" } " bytes from " { $snippet "buffer" } " into a new " { $link byte-array } "." } ;
+
+HELP: read-usage
+{ $class-description "This " { $link buffer-usage-pattern } " declares that a " { $link buffer } " object will be primarily read from by the CPU and written to by the GPU." } ;
+
+{ copy-usage draw-usage read-usage } related-words
+
+HELP: read-write-access
+{ $class-description "This " { $link buffer-access-mode } " value requests full access when mapping a buffer object through " { $link with-mapped-buffer } "." } ;
+
+HELP: static-upload
+{ $class-description "This " { $link buffer-upload-pattern } " declares that a " { $link buffer } " object's data store will be read from frequently and modified infrequently." } ;
+
+HELP: stream-upload
+{ $var-description "This " { $link buffer-upload-pattern } " declares that a " { $link buffer } " object's data store will be used only a handful of times before being deallocated or replaced." } ;
+
+{ dynamic-upload static-upload stream-upload } related-words
+
+HELP: transform-feedback-buffer
+{ $class-description "This " { $link buffer-kind } " declares that a " { $link buffer } "'s primary use will be to receive transform feedback output from a render job." }
+{ $notes "Transform feedback requires OpenGL 3.0 or one of the " { $snippet "GL_EXT_transform_feedback" } " or " { $snippet "GL_ARB_transform_feedback" } " extensions." } ;
+
+HELP: update-buffer
+{ $values
+ { "buffer-ptr" buffer-ptr } { "size" integer } { "data" { $maybe c-ptr } }
+}
+{ $description "Replaces " { $snippet "size" } " bytes of data in the " { $link buffer } " referenced by " { $snippet "buffer-ptr" } " with data from " { $snippet "data" } "." } ;
+
+HELP: vertex-buffer
+{ $class-description "This " { $link buffer-kind } " declares that a " { $link buffer } "'s primary use will be to provide vertex attribute information to a vertex array." } ;
+
+{ index-buffer pixel-pack-buffer pixel-unpack-buffer vertex-buffer transform-feedback-buffer } related-words
+
+HELP: with-mapped-buffer
+{ $values
+ { "buffer" buffer } { "access" buffer-access-mode } { "quot" { $quotation "( alien -- )" } }
+}
+{ $description "Maps " { $snippet "buffer" } " into CPU address space with " { $snippet "access" } " for the dynamic extent of " { $snippet "quot" } ". " { $snippet "quot" } " is called with a pointer to the mapped memory on top of the stack." } ;
+
+{ allocate-buffer buffer-size update-buffer read-buffer copy-buffer with-mapped-buffer } related-words
+
+HELP: write-access
+{ $class-description "This " { $link buffer-access-mode } " value requests write-only access when mapping a buffer object through " { $link with-mapped-buffer } "." } ;
+
+{ read-access read-write-access write-access } related-words
+
+ARTICLE: "gpu.buffers" "Buffer objects"
+"The " { $vocab-link "gpu.buffers" } " vocabulary provides words for creating, allocating, updating, and reading GPU data buffers."
+{ $subsection buffer }
+{ $subsection <buffer> }
+{ $subsection byte-array>buffer }
+"Declaring buffer usage:"
+{ $subsection buffer-kind }
+{ $subsection buffer-upload-pattern }
+{ $subsection buffer-usage-pattern }
+"Referencing buffer data:"
+{ $subsection buffer-ptr }
+{ $subsection buffer-range }
+"Manipulating buffer data:"
+{ $subsection allocate-buffer }
+{ $subsection update-buffer }
+{ $subsection read-buffer }
+{ $subsection copy-buffer }
+{ $subsection with-mapped-buffer }
+;
+
+ABOUT: "gpu.buffers"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien alien.c-types arrays byte-arrays
+combinators destructors gpu kernel locals math opengl opengl.gl
+ui.gadgets.worlds variants ;
+IN: gpu.buffers
+
+VARIANT: buffer-upload-pattern
+ stream-upload static-upload dynamic-upload ;
+
+VARIANT: buffer-usage-pattern
+ draw-usage read-usage copy-usage ;
+
+VARIANT: buffer-access-mode
+ read-access write-access read-write-access ;
+
+VARIANT: buffer-kind
+ vertex-buffer index-buffer
+ pixel-unpack-buffer pixel-pack-buffer
+ transform-feedback-buffer ;
+
+TUPLE: buffer < gpu-object
+ { upload-pattern buffer-upload-pattern }
+ { usage-pattern buffer-usage-pattern }
+ { kind buffer-kind } ;
+
+<PRIVATE
+
+: gl-buffer-usage ( buffer -- usage )
+ [ upload-pattern>> ] [ usage-pattern>> ] bi 2array {
+ { { stream-upload draw-usage } [ GL_STREAM_DRAW ] }
+ { { stream-upload read-usage } [ GL_STREAM_READ ] }
+ { { stream-upload copy-usage } [ GL_STREAM_COPY ] }
+
+ { { static-upload draw-usage } [ GL_STATIC_DRAW ] }
+ { { static-upload read-usage } [ GL_STATIC_READ ] }
+ { { static-upload copy-usage } [ GL_STATIC_COPY ] }
+
+ { { dynamic-upload draw-usage } [ GL_DYNAMIC_DRAW ] }
+ { { dynamic-upload read-usage } [ GL_DYNAMIC_READ ] }
+ { { dynamic-upload copy-usage } [ GL_DYNAMIC_COPY ] }
+ } case ; inline
+
+: gl-access ( access -- gl-access )
+ {
+ { read-access [ GL_READ_ONLY ] }
+ { write-access [ GL_WRITE_ONLY ] }
+ { read-write-access [ GL_READ_WRITE ] }
+ } case ; inline
+
+: gl-target ( kind -- target )
+ {
+ { vertex-buffer [ GL_ARRAY_BUFFER ] }
+ { index-buffer [ GL_ELEMENT_ARRAY_BUFFER ] }
+ { pixel-unpack-buffer [ GL_PIXEL_UNPACK_BUFFER ] }
+ { pixel-pack-buffer [ GL_PIXEL_PACK_BUFFER ] }
+ { transform-feedback-buffer [ GL_TRANSFORM_FEEDBACK_BUFFER ] }
+ } case ; inline
+
+: get-buffer-int ( target enum -- value )
+ 0 <int> [ glGetBufferParameteriv ] keep *int ;
+
+: bind-buffer ( buffer -- target )
+ [ kind>> gl-target dup ] [ handle>> glBindBuffer ] bi ;
+
+PRIVATE>
+
+M: buffer dispose
+ [ [ delete-gl-buffer ] when* f ] change-handle drop ;
+
+TUPLE: buffer-ptr
+ { buffer buffer read-only }
+ { offset integer read-only } ;
+C: <buffer-ptr> buffer-ptr
+
+TUPLE: buffer-range < buffer-ptr
+ { size integer read-only } ;
+C: <buffer-range> buffer-range
+
+UNION: gpu-data-ptr buffer-ptr c-ptr ;
+
+: buffer-size ( buffer -- size )
+ bind-buffer GL_BUFFER_SIZE get-buffer-int ;
+
+: buffer-ptr>range ( buffer-ptr -- buffer-range )
+ [ buffer>> ] [ offset>> ] bi
+ 2dup [ buffer-size ] dip -
+ buffer-range boa ; inline
+
+:: allocate-buffer ( buffer size initial-data -- )
+ buffer bind-buffer :> target
+ target size initial-data buffer gl-buffer-usage glBufferData ;
+
+: <buffer> ( upload usage kind size initial-data -- buffer )
+ [ [ gen-gl-buffer ] 3dip buffer boa dup ] 2dip allocate-buffer
+ window-resource ;
+
+: byte-array>buffer ( byte-array upload usage kind -- buffer )
+ [ ] 3curry dip
+ [ byte-length ] [ ] bi <buffer> ;
+
+:: update-buffer ( buffer-ptr size data -- )
+ buffer-ptr buffer>> :> buffer
+ buffer bind-buffer :> target
+ target buffer-ptr offset>> size data glBufferSubData ;
+
+:: read-buffer ( buffer-ptr size -- data )
+ buffer-ptr buffer>> :> buffer
+ buffer bind-buffer :> target
+ size <byte-array> :> data
+ target buffer-ptr offset>> size data glGetBufferSubData
+ data ;
+
+:: copy-buffer ( to-buffer-ptr from-buffer-ptr size -- )
+ GL_COPY_WRITE_BUFFER to-buffer-ptr buffer>> glBindBuffer
+ GL_COPY_READ_BUFFER from-buffer-ptr buffer>> glBindBuffer
+
+ GL_COPY_READ_BUFFER GL_COPY_WRITE_BUFFER
+ from-buffer-ptr offset>> to-buffer-ptr offset>>
+ size glCopyBufferSubData ;
+
+:: with-mapped-buffer ( buffer access quot: ( alien -- ) -- )
+ buffer bind-buffer :> target
+ target access gl-access glMapBuffer
+
+ quot call
+
+ target glUnmapBuffer ; inline
+
+:: with-bound-buffer ( buffer target quot: ( -- ) -- )
+ target gl-target buffer glBindBuffer
+ quot call ; inline
+
+: with-buffer-ptr ( buffer-ptr target quot: ( c-ptr -- ) -- )
+ [ [ offset>> <alien> ] [ buffer>> handle>> ] bi ] 2dip
+ with-bound-buffer ; inline
+
+: with-gpu-data-ptr ( gpu-data-ptr target quot: ( c-ptr -- ) -- )
+ pick buffer-ptr?
+ [ with-buffer-ptr ]
+ [ [ gl-target 0 glBindBuffer ] dip call ] if ; inline
+
--- /dev/null
+Buffers in GPU memory
--- /dev/null
+Joe Groff
+Slava Pestov
--- /dev/null
+#version 110
+
+uniform mat4 mv_matrix, p_matrix;
+uniform vec4 color, ambient, diffuse;
+uniform float shininess;
+
+varying vec3 frag_normal;
+varying vec3 frag_light_direction;
+varying vec3 frag_eye_direction;
+
+float
+cel(float d)
+{
+ return smoothstep(0.25, 0.255, d) * 0.4 + smoothstep(0.695, 0.70, d) * 0.5;
+}
+
+vec4
+cel_light()
+{
+ vec3 normal = normalize(frag_normal),
+ light = normalize(frag_light_direction),
+ eye = normalize(frag_eye_direction),
+ reflection = reflect(light, normal);
+
+ float d = dot(light, normal) * 0.5 + 0.5;
+ float s = pow(max(dot(reflection, -eye), 0.0), shininess);
+
+ vec4 amb_diff = ambient + diffuse * vec4(vec3(cel(d)), 1.0);
+ vec4 spec = vec4(vec3(cel(s)), 0.0);
+
+ return amb_diff * color + spec;
+}
+
+void
+main()
+{
+ gl_FragData[0] = cel_light();
+ gl_FragData[1] = vec4(frag_normal, 0.0);
+}
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien.c-types arrays combinators combinators.short-circuit
+game-worlds gpu gpu.buffers gpu.util.wasd gpu.framebuffers gpu.render
+gpu.shaders gpu.state gpu.textures gpu.util grouping http.client images
+images.loader io io.encodings.ascii io.files io.files.temp
+kernel math math.matrices math.parser math.vectors
+method-chains sequences specialized-arrays.float specialized-vectors.uint splitting
+struct-vectors threads ui ui.gadgets ui.gadgets.worlds
+ui.pixel-formats ;
+IN: gpu.demos.bunny
+
+GLSL-SHADER-FILE: bunny-vertex-shader vertex-shader "bunny.v.glsl"
+GLSL-SHADER-FILE: bunny-fragment-shader fragment-shader "bunny.f.glsl"
+GLSL-PROGRAM: bunny-program
+ bunny-vertex-shader bunny-fragment-shader ;
+
+GLSL-SHADER-FILE: window-vertex-shader vertex-shader "window.v.glsl"
+
+GLSL-SHADER-FILE: sobel-fragment-shader fragment-shader "sobel.f.glsl"
+GLSL-PROGRAM: sobel-program
+ window-vertex-shader sobel-fragment-shader ;
+
+GLSL-SHADER-FILE: loading-fragment-shader fragment-shader "loading.f.glsl"
+GLSL-PROGRAM: loading-program
+ window-vertex-shader loading-fragment-shader ;
+
+TUPLE: bunny-state
+ vertexes
+ indexes
+ vertex-array
+ index-elements ;
+
+TUPLE: sobel-state
+ vertex-array
+ color-texture
+ normal-texture
+ depth-texture
+ framebuffer ;
+
+TUPLE: loading-state
+ vertex-array
+ texture ;
+
+TUPLE: bunny-world < wasd-world
+ bunny sobel loading ;
+
+VERTEX-FORMAT: bunny-vertex
+ { "vertex" float-components 3 f }
+ { f float-components 1 f }
+ { "normal" float-components 3 f }
+ { f float-components 1 f } ;
+VERTEX-STRUCT: bunny-vertex-struct bunny-vertex
+
+UNIFORM-TUPLE: bunny-uniforms < mvp-uniforms
+ { "light-position" vec3-uniform f }
+ { "color" vec4-uniform f }
+ { "ambient" vec4-uniform f }
+ { "diffuse" vec4-uniform f }
+ { "shininess" float-uniform f } ;
+
+UNIFORM-TUPLE: sobel-uniforms
+ { "texcoord-scale" vec2-uniform f }
+ { "color-texture" texture-uniform f }
+ { "normal-texture" texture-uniform f }
+ { "depth-texture" texture-uniform f }
+ { "line-color" vec4-uniform f } ;
+
+UNIFORM-TUPLE: loading-uniforms
+ { "texcoord-scale" vec2-uniform f }
+ { "loading-texture" texture-uniform f } ;
+
+: numbers ( str -- seq )
+ " " split [ string>number ] map sift ;
+
+: <bunny-vertex> ( vertex -- struct )
+ >float-array
+ "bunny-vertex-struct" <c-object>
+ [ set-bunny-vertex-struct-vertex ] keep ;
+
+: (parse-bunny-model) ( vs is -- vs is )
+ readln [
+ numbers {
+ { [ dup length 5 = ] [ 3 head <bunny-vertex> pick push ] }
+ { [ dup first 3 = ] [ rest over push-all ] }
+ [ drop ]
+ } cond (parse-bunny-model)
+ ] when* ;
+
+: parse-bunny-model ( -- vertexes indexes )
+ 100000 "bunny-vertex-struct" <struct-vector>
+ 100000 <uint-vector>
+ (parse-bunny-model) ;
+
+: normal ( vertexes -- normal )
+ [ [ second ] [ first ] bi v- ]
+ [ [ third ] [ first ] bi v- ] bi cross
+ vneg normalize ; inline
+
+: calc-bunny-normal ( vertexes indexes -- )
+ swap
+ [ [ nth bunny-vertex-struct-vertex ] curry { } map-as normal ]
+ [
+ [
+ nth [ bunny-vertex-struct-normal v+ ] keep
+ set-bunny-vertex-struct-normal
+ ] curry with each
+ ] 2bi ;
+
+: calc-bunny-normals ( vertexes indexes -- )
+ 3 <groups>
+ [ calc-bunny-normal ] with each ;
+
+: normalize-bunny-normals ( vertexes -- )
+ [
+ [ bunny-vertex-struct-normal normalize ] keep
+ set-bunny-vertex-struct-normal
+ ] each ;
+
+: bunny-data ( filename -- vertexes indexes )
+ ascii [ parse-bunny-model ] with-file-reader
+ [ calc-bunny-normals ]
+ [ drop normalize-bunny-normals ]
+ [ ] 2tri ;
+
+: <bunny-buffers> ( vertexes indexes -- vertex-buffer index-buffer index-count )
+ [ underlying>> static-upload draw-usage vertex-buffer byte-array>buffer ]
+ [
+ [ underlying>> static-upload draw-usage index-buffer byte-array>buffer ]
+ [ length ] bi
+ ] bi* ;
+
+: bunny-model-path ( -- path ) "bun_zipper.ply" temp-file ;
+
+CONSTANT: bunny-model-url "http://factorcode.org/bun_zipper.ply"
+
+: download-bunny ( -- path )
+ bunny-model-path dup exists? [
+ bunny-model-url dup print flush
+ over download-to
+ ] unless ;
+
+: get-bunny-data ( bunny-state -- )
+ download-bunny bunny-data
+ [ >>vertexes ] [ >>indexes ] bi* drop ;
+
+: fill-bunny-state ( bunny-state -- )
+ dup [ vertexes>> ] [ indexes>> ] bi <bunny-buffers>
+ [ bunny-program <program-instance> bunny-vertex buffer>vertex-array >>vertex-array ]
+ [ 0 <buffer-ptr> ]
+ [ uint-indexes <index-elements> >>index-elements ] tri*
+ drop ;
+
+: <bunny-state> ( -- bunny-state )
+ bunny-state new
+ dup [ get-bunny-data ] curry "Downloading bunny model" spawn drop ;
+
+: bunny-loaded? ( bunny-state -- ? )
+ { [ vertexes>> ] [ indexes>> ] } 1&& ;
+
+: bunny-state-filled? ( bunny-state -- ? )
+ { [ vertex-array>> ] [ index-elements>> ] } 1&& ;
+
+: <sobel-state> ( window-vertex-buffer -- sobel-state )
+ sobel-state new
+ swap sobel-program <program-instance> window-vertex buffer>vertex-array >>vertex-array
+
+ RGBA half-components T{ texture-parameters
+ { wrap clamp-texcoord-to-edge }
+ { min-filter filter-linear }
+ { min-mipmap-filter f }
+ } <texture-2d> >>color-texture
+ RGBA half-components T{ texture-parameters
+ { wrap clamp-texcoord-to-edge }
+ { min-filter filter-linear }
+ { min-mipmap-filter f }
+ } <texture-2d> >>normal-texture
+ DEPTH u-24-components T{ texture-parameters
+ { wrap clamp-texcoord-to-edge }
+ { min-filter filter-linear }
+ { min-mipmap-filter f }
+ } <texture-2d> >>depth-texture
+
+ dup
+ [
+ [ color-texture>> 0 <texture-2d-attachment> ]
+ [ normal-texture>> 0 <texture-2d-attachment> ] bi 2array
+ ] [ depth-texture>> 0 <texture-2d-attachment> ] bi f { 1024 768 } <framebuffer> >>framebuffer ;
+
+: <loading-state> ( window-vertex-buffer -- loading-state )
+ loading-state new
+ swap
+ loading-program <program-instance> window-vertex buffer>vertex-array >>vertex-array
+
+ RGBA ubyte-components T{ texture-parameters
+ { wrap clamp-texcoord-to-edge }
+ { min-filter filter-linear }
+ { min-mipmap-filter f }
+ } <texture-2d>
+ dup 0 "vocab:gpu/demos/bunny/loading.tiff" load-image allocate-texture-image
+ >>texture ;
+
+BEFORE: bunny-world begin-world
+ init-gpu
+
+ { -0.2 0.13 0.1 } 1.1 0.2 set-wasd-view
+
+ <bunny-state> >>bunny
+ <window-vertex-buffer>
+ [ <sobel-state> >>sobel ]
+ [ <loading-state> >>loading ] bi
+ drop ;
+
+: <bunny-uniforms> ( world -- uniforms )
+ [ wasd-mv-matrix ] [ wasd-p-matrix ] bi
+ { -10000.0 10000.0 10000.0 } ! light position
+ { 0.6 0.5 0.5 1.0 } ! color
+ { 0.2 0.2 0.2 0.2 } ! ambient
+ { 0.8 0.8 0.8 0.8 } ! diffuse
+ 100.0 ! shininess
+ bunny-uniforms boa ;
+
+: draw-bunny ( world -- )
+ T{ depth-state { comparison cmp-less } } set-gpu-state
+
+ [
+ sobel>> framebuffer>> {
+ { T{ color-attachment f 0 } { 0.15 0.15 0.15 1.0 } }
+ { T{ color-attachment f 1 } { 0.0 0.0 0.0 0.0 } }
+ { depth-attachment 1.0 }
+ } clear-framebuffer
+ ] [
+ {
+ { "primitive-mode" [ drop triangles-mode ] }
+ { "output-attachments" [ drop { T{ color-attachment f 0 } T{ color-attachment f 1 } } ] }
+ { "uniforms" [ <bunny-uniforms> ] }
+ { "vertex-array" [ bunny>> vertex-array>> ] }
+ { "indexes" [ bunny>> index-elements>> ] }
+ { "framebuffer" [ sobel>> framebuffer>> ] }
+ } <render-set> render
+ ] bi ;
+
+: <sobel-uniforms> ( sobel -- uniforms )
+ { 1.0 1.0 } swap
+ [ color-texture>> ] [ normal-texture>> ] [ depth-texture>> ] tri
+ { 0.1 0.0 0.1 1.0 } ! line_color
+ sobel-uniforms boa ;
+
+: draw-sobel ( world -- )
+ T{ depth-state { comparison f } } set-gpu-state
+
+ sobel>> {
+ { "primitive-mode" [ drop triangle-strip-mode ] }
+ { "indexes" [ drop T{ index-range f 0 4 } ] }
+ { "uniforms" [ <sobel-uniforms> ] }
+ { "vertex-array" [ vertex-array>> ] }
+ } <render-set> render ;
+
+: draw-sobeled-bunny ( world -- )
+ [ draw-bunny ] [ draw-sobel ] bi ;
+
+: draw-loading ( world -- )
+ T{ depth-state { comparison f } } set-gpu-state
+
+ loading>> {
+ { "primitive-mode" [ drop triangle-strip-mode ] }
+ { "indexes" [ drop T{ index-range f 0 4 } ] }
+ { "uniforms" [ { 1.0 -1.0 } swap texture>> loading-uniforms boa ] }
+ { "vertex-array" [ vertex-array>> ] }
+ } <render-set> render ;
+
+M: bunny-world draw-world*
+ dup bunny>>
+ dup bunny-loaded? [
+ dup bunny-state-filled? [ drop ] [ fill-bunny-state ] if
+ draw-sobeled-bunny
+ ] [ drop draw-loading ] if ;
+
+AFTER: bunny-world resize-world
+ [ sobel>> framebuffer>> ] [ dim>> ] bi resize-framebuffer ;
+
+M: bunny-world pref-dim* drop { 1024 768 } ;
+M: bunny-world tick-length drop 1000 30 /i ;
+M: bunny-world wasd-movement-speed drop 1/160. ;
+M: bunny-world wasd-near-plane drop 1/32. ;
+M: bunny-world wasd-far-plane drop 256.0 ;
+
+: bunny-window ( -- )
+ [
+ f T{ world-attributes
+ { world-class bunny-world }
+ { title "Bunny" }
+ { pixel-format-attributes {
+ windowed
+ double-buffered
+ T{ depth-bits { value 24 } }
+ } }
+ { grab-input? t }
+ } open-window
+ ] with-ui ;
+
+MAIN: bunny-window
--- /dev/null
+#version 110
+
+uniform mat4 mv_matrix, p_matrix;
+uniform vec3 light_position;
+
+attribute vec3 vertex, normal;
+
+varying vec3 frag_normal;
+varying vec3 frag_light_direction;
+varying vec3 frag_eye_direction;
+
+void
+main()
+{
+ vec4 position = mv_matrix * vec4(vertex, 1.0);
+
+ gl_Position = p_matrix * position;
+ frag_normal = (mv_matrix * vec4(normal, 0.0)).xyz;
+ frag_light_direction = (mv_matrix * vec4(light_position, 1.0)).xyz - position.xyz;
+ frag_eye_direction = position.xyz;
+
+}
--- /dev/null
+#version 110
+
+uniform sampler2D loading_texture;
+
+varying vec2 texcoord;
+
+void
+main()
+{
+ gl_FragColor = texture2D(loading_texture, texcoord);
+}
--- /dev/null
+#version 110
+
+uniform sampler2D color_texture, normal_texture, depth_texture;
+uniform vec4 line_color;
+
+varying vec2 texcoord;
+
+const float sample_step = 1.0/512.0;
+const float depth_weight = 8.0;
+
+float
+border_factor(vec2 texcoord)
+{
+ float depth_samples[8];
+
+ depth_samples[0] = texture2D(depth_texture, texcoord + vec2(-sample_step, -sample_step)).x;
+ depth_samples[1] = texture2D(depth_texture, texcoord + vec2( 0, -sample_step)).x;
+ depth_samples[2] = texture2D(depth_texture, texcoord + vec2( sample_step, -sample_step)).x;
+
+ depth_samples[3] = texture2D(depth_texture, texcoord + vec2(-sample_step, 0 )).x;
+
+ depth_samples[4] = texture2D(depth_texture, texcoord + vec2( sample_step, 0 )).x;
+
+ depth_samples[5] = texture2D(depth_texture, texcoord + vec2(-sample_step, sample_step)).x;
+ depth_samples[6] = texture2D(depth_texture, texcoord + vec2( 0, sample_step)).x;
+ depth_samples[7] = texture2D(depth_texture, texcoord + vec2( sample_step, sample_step)).x;
+
+ float horizontal = 1.0 * depth_samples[0] + 2.0 * depth_samples[3] + 1.0 * depth_samples[5]
+ - 1.0 * depth_samples[2] - 2.0 * depth_samples[4] - 1.0 * depth_samples[7];
+
+ float vertical = 1.0 * depth_samples[0] + 2.0 * depth_samples[1] + 1.0 * depth_samples[2]
+ - 1.0 * depth_samples[5] - 2.0 * depth_samples[6] - 1.0 * depth_samples[7];
+
+ return depth_weight * sqrt(horizontal*horizontal + vertical*vertical);
+}
+
+void
+main()
+{
+ gl_FragColor = mix(
+ texture2D(color_texture, texcoord),
+ line_color,
+ border_factor(texcoord)
+ );
+}
--- /dev/null
+Stanford Bunny with shader effects
--- /dev/null
+#version 110
+
+uniform vec2 texcoord_scale;
+
+attribute vec2 vertex;
+
+varying vec2 texcoord;
+
+void
+main()
+{
+ texcoord = (vertex * texcoord_scale) * vec2(0.5) + vec2(0.5);
+ gl_Position = vec4(vertex, 0.0, 1.0);
+}
--- /dev/null
+#version 110
+
+struct sphere
+{
+ vec3 center;
+ float radius;
+ vec4 color;
+};
+
+uniform sphere spheres[4];
+uniform float floor_height;
+uniform vec4 floor_color[2];
+uniform vec4 background_color;
+uniform vec3 light_direction;
+
+varying vec3 ray_origin, ray_direction;
+
+const float FAR_AWAY = 1.0e20;
+const vec4 reflection_color = vec4(1.0, 0.0, 1.0, 0.0);
+
+float sphere_intersect(sphere s, vec3 ro, vec3 rd)
+{
+ vec3 dist = (ro - s.center);
+
+ float b = dot(dist, normalize(rd));
+ float c = dot(dist, dist) - s.radius*s.radius;
+ float d = b * b - c;
+
+ return d > 0.0 ? -b - sqrt(d) : FAR_AWAY;
+}
+
+float floor_intersect(float height, vec3 ro, vec3 rd)
+{
+ return (height - ro.y) / rd.y;
+}
+
+void
+cast_ray(vec3 ro, vec3 rd, out sphere intersect_sphere, out bool intersect_floor, out float intersect_distance)
+{
+ intersect_floor = false;
+ intersect_distance = FAR_AWAY;
+
+ for (int i = 0; i < 4; ++i) {
+ float d = sphere_intersect(spheres[i], ro, rd);
+
+ if (d > 0.0 && d < intersect_distance) {
+ intersect_distance = d;
+ intersect_sphere = spheres[i];
+ }
+ }
+
+ if (intersect_distance >= FAR_AWAY) {
+ intersect_distance = floor_intersect(floor_height, ro, rd);
+ if (intersect_distance < 0.0)
+ intersect_distance = FAR_AWAY;
+ intersect_floor = intersect_distance < FAR_AWAY;
+ }
+}
+
+vec4 render_floor(vec3 at, float distance, bool shadowed)
+{
+ vec3 at2 = 0.125 * at;
+
+ float dropoff = exp(-0.005 * abs(distance)) * 0.8 + 0.2;
+ float fade = 0.5 * dropoff + 0.5;
+
+ vec4 color = fract((floor(at2.x) + floor(at2.z)) * 0.5) == 0.0
+ ? mix(floor_color[1], floor_color[0], fade)
+ : mix(floor_color[0], floor_color[1], fade);
+
+ float light = shadowed ? 0.2 : dropoff;
+
+ return color * light * dot(vec3(0.0, 1.0, 0.0), -light_direction);
+}
+
+vec4 sphere_color(vec4 color, vec3 normal, vec3 eye_ray, bool shadowed)
+{
+ float light = shadowed
+ ? 0.2
+ : max(dot(normal, -light_direction), 0.0) * 0.8 + 0.2;
+
+ float spec = shadowed
+ ? 0.0
+ : 0.3 * pow(max(dot(reflect(-light_direction, normal), eye_ray), 0.0), 100.0);
+
+ return color * light + vec4(spec);
+}
+
+bool reflection_p(vec4 color)
+{
+ vec4 difference = color - reflection_color;
+ return dot(difference, difference) == 0.0;
+}
+
+vec4 render_sphere(sphere s, vec3 at, vec3 eye_ray, bool shadowed)
+{
+ vec3 normal = normalize(at - s.center);
+
+ vec4 color;
+
+ if (reflection_p(s.color)) {
+ sphere reflect_sphere;
+ bool reflect_floor;
+ float reflect_distance;
+ vec3 reflect_direction = reflect(eye_ray, normal);
+
+ cast_ray(at, reflect_direction, reflect_sphere, reflect_floor, reflect_distance);
+
+ vec3 reflect_at = at + reflect_direction * reflect_distance;
+ if (reflect_floor)
+ color = render_floor(reflect_at, reflect_distance, false);
+ else if (reflect_distance < FAR_AWAY) {
+ vec3 reflect_normal = normalize(reflect_at - reflect_sphere.center);
+
+ color = sphere_color(reflect_sphere.color, reflect_normal, reflect_direction, false);
+ } else {
+ color = background_color;
+ }
+ } else
+ color = s.color;
+
+ return sphere_color(color, normal, eye_ray, shadowed);
+}
+
+void
+main()
+{
+ vec3 ray_direction_normalized = normalize(ray_direction);
+
+ sphere intersect_sphere;
+ bool intersect_floor;
+ float intersect_distance;
+
+ cast_ray(ray_origin, ray_direction_normalized, intersect_sphere, intersect_floor, intersect_distance);
+
+ vec3 at = ray_origin + ray_direction_normalized * intersect_distance;
+
+ sphere shadow_sphere;
+ bool shadow_floor;
+ float shadow_distance;
+
+ cast_ray(at - 0.0001 * light_direction, -light_direction, shadow_sphere, shadow_floor, shadow_distance);
+
+ bool shadowed = shadow_distance < FAR_AWAY;
+
+ if (intersect_floor)
+ gl_FragColor = render_floor(at, intersect_distance, shadowed);
+ else if (intersect_distance < FAR_AWAY)
+ gl_FragColor = render_sphere(intersect_sphere, at, ray_direction_normalized, shadowed);
+ else
+ gl_FragColor = background_color;
+}
+
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors arrays combinators.tuple game-loop game-worlds
+generalizations gpu gpu.render gpu.shaders gpu.util gpu.util.wasd
+kernel literals math math.matrices math.order math.vectors
+method-chains sequences ui ui.gadgets ui.gadgets.worlds
+ui.pixel-formats ;
+IN: gpu.demos.raytrace
+
+GLSL-SHADER-FILE: raytrace-vertex-shader vertex-shader "raytrace.v.glsl"
+GLSL-SHADER-FILE: raytrace-fragment-shader fragment-shader "raytrace.f.glsl"
+GLSL-PROGRAM: raytrace-program
+ raytrace-vertex-shader raytrace-fragment-shader ;
+
+UNIFORM-TUPLE: sphere-uniforms
+ { "center" vec3-uniform f }
+ { "radius" float-uniform f }
+ { "color" vec4-uniform f } ;
+
+UNIFORM-TUPLE: raytrace-uniforms
+ { "mv-inv-matrix" mat4-uniform f }
+ { "fov" vec2-uniform f }
+
+ { "spheres" sphere-uniforms 4 }
+
+ { "floor-height" float-uniform f }
+ { "floor-color" vec4-uniform 2 }
+ { "background-color" vec4-uniform f }
+ { "light-direction" vec3-uniform f } ;
+
+CONSTANT: reflection-color { 1.0 0.0 1.0 0.0 }
+
+TUPLE: sphere
+ { axis array }
+ { home array }
+ { dtheta float }
+ { radius float }
+ { color array }
+ { theta float initial: 0.0 } ;
+
+TUPLE: raytrace-world < wasd-world
+ fov
+ spheres
+ vertex-array ;
+
+: tick-sphere ( sphere -- )
+ dup dtheta>> [ + ] curry change-theta drop ;
+
+: sphere-center ( sphere -- center )
+ [ [ axis>> ] [ theta>> ] bi rotation-matrix4 ]
+ [ home>> ] bi m.v ;
+
+: <sphere-uniforms> ( world -- uniforms )
+ [ wasd-mv-inv-matrix ]
+ [ fov>> ]
+ [
+ spheres>>
+ [ [ sphere-center ] [ radius>> ] [ color>> ] tri sphere-uniforms boa ] map
+ ] tri
+ -30.0 ! floor_height
+ { { 1.0 0.0 0.0 1.0 } { 1.0 1.0 1.0 1.0 } } ! floor_color
+ { 0.15 0.15 1.0 1.0 } ! background_color
+ { 0.0 -1.0 -0.1 } ! light_direction
+ raytrace-uniforms boa ;
+
+CONSTANT: initial-spheres {
+ T{ sphere f { 0.0 1.0 0.0 } { 0.0 0.0 0.0 } 0.0 4.0 $ reflection-color }
+ T{ sphere f { 0.0 1.0 0.0 } { 7.0 0.0 0.0 } 0.02 1.0 { 1.0 0.0 0.0 1.0 } }
+ T{ sphere f { 0.0 0.0 -1.0 } { -9.0 0.0 0.0 } 0.03 1.0 { 0.0 1.0 0.0 1.0 } }
+ T{ sphere f { 1.0 0.0 0.0 } { 0.0 5.0 0.0 } 0.025 1.0 { 1.0 1.0 0.0 1.0 } }
+}
+
+BEFORE: raytrace-world begin-world
+ init-gpu
+ { -2.0 6.25 10.0 } 0.19 0.55 set-wasd-view
+ initial-spheres [ clone ] map >>spheres
+ raytrace-program <program-instance> <window-vertex-array> >>vertex-array
+ drop ;
+
+CONSTANT: fov 0.7
+
+AFTER: raytrace-world resize-world
+ dup dim>> dup first2 min >float v/n fov v*n >>fov drop ;
+
+AFTER: raytrace-world tick*
+ spheres>> [ tick-sphere ] each ;
+
+M: raytrace-world draw-world*
+ {
+ { "primitive-mode" [ drop triangle-strip-mode ] }
+ { "indexes" [ drop T{ index-range f 0 4 } ] }
+ { "uniforms" [ <sphere-uniforms> ] }
+ { "vertex-array" [ vertex-array>> ] }
+ } <render-set> render ;
+
+M: raytrace-world pref-dim* drop { 1024 768 } ;
+M: raytrace-world tick-length drop 1000 30 /i ;
+M: raytrace-world wasd-movement-speed drop 1/4. ;
+
+: raytrace-window ( -- )
+ [
+ f T{ world-attributes
+ { world-class raytrace-world }
+ { title "Raytracing" }
+ { pixel-format-attributes {
+ windowed
+ double-buffered
+ } }
+ { grab-input? t }
+ } open-window
+ ] with-ui ;
+
+MAIN: raytrace-window
--- /dev/null
+#version 110
+
+uniform mat4 mv_inv_matrix;
+uniform vec2 fov;
+
+attribute vec2 vertex;
+
+varying vec3 ray_origin, ray_direction;
+
+void
+main()
+{
+ gl_Position = vec4(vertex, 0.0, 1.0);
+ ray_direction = (mv_inv_matrix * vec4(fov * vertex, -1.0, 0.0)).xyz;
+ ray_origin = (mv_inv_matrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
+}
+
--- /dev/null
+Real-time GPU-accelerated raytracing of reflective spheres
--- /dev/null
+Runnable demonstrations of the gpu library
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: alien byte-arrays gpu.buffers gpu.textures help.markup
+help.syntax images kernel math math.rectangles sequences ;
+IN: gpu.framebuffers
+
+HELP: <color-attachment>
+{ $values
+ { "index" integer }
+ { "color-attachment" color-attachment }
+}
+{ $description "Constructs an " { $link attachment-ref } " referencing the " { $snippet "index" } "th " { $snippet "color-attachment" } " of a framebuffer." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: <framebuffer-rect>
+{ $values
+ { "framebuffer" any-framebuffer } { "attachment" attachment-ref } { "rect" rect }
+ { "framebuffer-rect" framebuffer-rect }
+}
+{ $description "Constructs a " { $link framebuffer-rect } " tuple that references a rectangular region of " { $snippet "attachment" } " in " { $snippet "framebuffer" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+{ framebuffer-rect <framebuffer-rect> <full-framebuffer-rect> } related-words
+
+HELP: <framebuffer>
+{ $values
+ { "color-attachments" sequence } { "depth-attachment" framebuffer-attachment } { "stencil-attachment" framebuffer-attachment } { "dim" { $maybe sequence } }
+ { "framebuffer" framebuffer }
+}
+{ $description "Creates a new " { $link framebuffer } " object comprising the given set of " { $snippet "color-attachments" } ", " { $snippet "depth-attachment" } ", and " { $snippet "stencil-attachment" } ". If " { $snippet "dim" } " is not null, all of the attachments will be resized using " { $link resize-framebuffer } "; otherwise, each texture or renderbuffer being attached must have image memory allocated for the framebuffer creation to succeed." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. If only the " { $snippet "GL_EXT_framebuffer_object" } " is available, all framebuffer attachments must have the same size, and all color attachments must have the same " { $link component-order } " and " { $link component-type } "." } ;
+
+HELP: <full-framebuffer-rect>
+{ $values
+ { "framebuffer" any-framebuffer } { "attachment" attachment-ref }
+ { "framebuffer-rect" framebuffer-rect }
+}
+{ $description "Constructs a " { $link framebuffer-rect } " tuple that spans the entire size of " { $snippet "attachment" } " in " { $snippet "framebuffer" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: <renderbuffer>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "samples" { $maybe integer } } { "dim" { $maybe sequence } }
+ { "renderbuffer" renderbuffer }
+}
+{ $description "Creates a new " { $link renderbuffer } " object. If " { $snippet "samples" } " is not " { $link f } ", it specifies the multisampling level to use. If " { $snippet "dim" } " is not " { $link f } ", image memory of the given dimensions will be allocated for the renderbuffer; otherwise, memory will have to be allocated separately with " { $link allocate-renderbuffer } "." }
+{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Multisampled renderbuffers require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_multisample" } " extensions." } ;
+
+HELP: <system-attachment>
+{ $values
+ { "side" { $maybe framebuffer-attachment-side } } { "face" { $maybe framebuffer-attachment-face } }
+ { "system-attachment" system-attachment }
+}
+{ $description "Constructs an " { $link attachment-ref } " referencing a " { $link system-framebuffer } " color attachment." } ;
+
+HELP: <texture-1d-attachment>
+{ $values
+ { "texture" texture-data-target } { "level" integer }
+ { "texture-1d-attachment" texture-1d-attachment }
+}
+{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "level" } "th level of detail of one-dimensional texture " { $snippet "texture" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: <texture-2d-attachment>
+{ $values
+ { "texture" texture-data-target } { "level" integer }
+ { "texture-2d-attachment" texture-2d-attachment }
+}
+{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "level" } "th level of detail of two-dimensional texture " { $snippet "texture" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: <texture-3d-attachment>
+{ $values
+ { "texture" texture-data-target } { "z-offset" integer } { "level" integer }
+ { "texture-3d-attachment" texture-3d-attachment }
+}
+{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "z-offset" } "th plane of the " { $snippet "level" } "th level of detail of three-dimensional texture " { $snippet "texture" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: <texture-layer-attachment>
+{ $values
+ { "texture" texture-data-target } { "layer" integer } { "level" integer }
+ { "texture-layer-attachment" texture-layer-attachment }
+}
+{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "layer" } "th layer of the " { $snippet "level" } "th level of detail of three-dimensional texture or array texture " { $snippet "texture" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ;
+
+HELP: allocate-renderbuffer
+{ $values
+ { "renderbuffer" renderbuffer } { "dim" sequence }
+}
+{ $description "Allocates image memory for " { $snippet "renderbuffer" } " with dimension " { $snippet "dim" } "." }
+{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: any-framebuffer
+{ $class-description "This class is a union of the " { $link framebuffer } " class, which represents user-created framebuffer objects, and the " { $link system-framebuffer } ". Words which accept " { $snippet "any-framebuffer" } " can operate on either the system framebuffer or user framebuffers." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: attachment-ref
+{ $class-description "An " { $snippet "attachment-ref" } " value references a particular color, depth, or stencil attachment to a " { $link framebuffer } " object."
+{ $list
+{ { $link system-attachment } " references one or more of the color attachments to the " { $link system-framebuffer } "." }
+{ { $link color-attachment } " references one of the indexed color attachments to a user-created " { $link framebuffer } "." }
+{ { $link default-attachment } " references the back buffer of the " { $snippet "system-framebuffer" } " or the first color attachment of a user " { $snippet "framebuffer" } "." }
+{ { $link depth-attachment } " references the depth buffer attachment to any framebuffer." }
+{ { $link stencil-attachment } " references the stencil buffer attachment to any framebuffer." }
+} }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: back-face
+{ $class-description "Use this value in the " { $snippet "face" } " slot of a " { $link system-attachment } " reference to select the back face of a double-buffered " { $link system-framebuffer } "." } ;
+
+HELP: clear-framebuffer
+{ $values
+ { "framebuffer" any-framebuffer } { "alist" "a list of " { $link attachment-ref } "/value pairs" }
+}
+{ $description "Clears the active viewport area of the specified attachments to " { $snippet "framebuffer" } " to the associated values." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: clear-framebuffer-attachment
+{ $values
+ { "framebuffer" any-framebuffer } { "attachment-ref" attachment-ref } { "value" object }
+}
+{ $description "Clears the active viewport area of the given attachment to " { $snippet "framebuffer" } " to " { $snippet "value" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+{ clear-framebuffer clear-framebuffer-attachment } related-words
+
+HELP: color-attachment
+{ $class-description "This " { $link attachment-ref } " type references a color attachment to a user-created " { $link framebuffer } " object. The " { $snippet "index" } " slot of the tuple indicates the color attachment referenced. Color attachments to the " { $link system-framebuffer } " are referenced by the " { $link system-attachment } " type." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+{
+ color-attachment system-attachment default-attachment depth-attachment stencil-attachment
+ attachment-ref color-attachment-ref
+} related-words
+
+HELP: color-attachment-ref
+{ $class-description "A " { $snippet "color-attachment-ref" } " value references a particular color attachment to a " { $link framebuffer } " object."
+{ $list
+{ { $link system-attachment } " references one or more of the color attachments to the " { $link system-framebuffer } "." }
+{ { $link color-attachment } " references one of the indexed color attachments to a user-created " { $link framebuffer } "." }
+{ { $link default-attachment } " references the back buffer of the " { $snippet "system-framebuffer" } " or the first color attachment of a user " { $snippet "framebuffer" } "." }
+} }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: copy-framebuffer
+{ $values
+ { "to-fb-rect" framebuffer-rect } { "from-fb-rect" framebuffer-rect } { "depth?" boolean } { "stencil?" boolean } { "filter" texture-filter }
+}
+{ $description "Copies the rectangular region " { $snippet "from-fb-rect" } " to " { $snippet "to-fb-rect" } ". If " { $snippet "depth?" } " is true, depth values are also copied, and if " { $snippet "stencil?" } " is true, so are stencil values. If the rectangle sizes do not match, the region is scaled using nearest-neighbor or linear filtering based on " { $snippet "filter" } "." }
+{ $notes "This word requires OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_blit" } " extensions." } ;
+
+HELP: default-attachment
+{ $class-description "This " { $link attachment-ref } " references the back buffer of the " { $link system-framebuffer } " or the first color attachment of a user-created " { $link framebuffer } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: depth-attachment
+{ $class-description "This " { $link attachment-ref } " references the depth buffer attachment of a user-created " { $link framebuffer } " or the " { $link system-framebuffer } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: framebuffer
+{ $class-description "Objects of this class represent user-created framebuffer objects. These framebuffer objects provide an offscreen target for rendering operations and can send rendering output either to textures or to dedicated " { $link renderbuffer } "s. A framebuffer consists of a set of one or more color " { $link framebuffer-attachment } "s, an optional depth buffer " { $snippet "framebuffer-attachment" } ", and an optional stencil buffer " { $snippet "framebuffer-attachment" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: framebuffer-attachment
+{ $class-description "This class is a union of the " { $link renderbuffer } " and " { $link texture-attachment } " classes, either of which can function as an attachment to a user-created " { $link framebuffer } " object." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: framebuffer-attachment-at
+{ $values
+ { "framebuffer" framebuffer } { "attachment-ref" attachment-ref }
+ { "attachment" framebuffer-attachment }
+}
+{ $description "Returns the " { $link texture-attachment } " or " { $link renderbuffer } " referenced by " { $snippet "attachment-ref" } " in " { $snippet "framebuffer" } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: framebuffer-attachment-face
+{ $class-description "The values " { $link front-face } " and " { $link back-face } " select a face of a double-buffered " { $link system-framebuffer } " when stored in the " { $snippet "face" } " slot of a " { $link system-attachment } " reference." } ;
+
+HELP: framebuffer-attachment-side
+{ $class-description "The values " { $link left-side } " and " { $link right-side } " select a face of a stereoscopic " { $link system-framebuffer } " when stored in the " { $snippet "side" } " slot of a " { $link system-attachment } " reference." } ;
+
+HELP: framebuffer-rect
+{ $class-description "This tuple class references a rectangular subregion of a color attachment of a " { $link framebuffer } " object."
+{ $list
+{ { $snippet "framebuffer" } " references either a user-created " { $link framebuffer } " or the " { $link system-framebuffer } "." }
+{ { $snippet "attachment" } " is a " { $link color-attachment-ref } " referencing the color attachment of interest in the framebuffer." }
+{ { $snippet "rect" } " is a " { $link rect } " referencing the rectangular region of interest of the attachment." }
+} }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: front-face
+{ $class-description "Use this value in the " { $snippet "face" } " slot of a " { $link system-attachment } " reference to select the front face of a double-buffered " { $link system-framebuffer } "." } ;
+
+{ front-face back-face } related-words
+
+HELP: left-side
+{ $class-description "Use this value in the " { $snippet "side" } " slot of a " { $link system-attachment } " reference to select the left side of a stereoscopic " { $link system-framebuffer } "." } ;
+
+{ left-side right-side } related-words
+
+HELP: read-framebuffer
+{ $values
+ { "framebuffer-rect" framebuffer-rect }
+ { "byte-array" byte-array }
+}
+{ $description "Reads the rectangular region " { $snippet "framebuffer-rect" } " into a new " { $snippet "byte-array" } ". The format of the byte array is determined by the " { $link component-order } " and " { $link component-type } " of the associated " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: read-framebuffer-image
+{ $values
+ { "framebuffer-rect" framebuffer-rect }
+ { "image" image }
+}
+{ $description "Reads the rectangular region " { $snippet "framebuffer-rect" } " into a new " { $snippet "image" } ". The format of the image is determined by the " { $link component-order } " and " { $link component-type } " of the associated " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: read-framebuffer-to
+{ $values
+ { "framebuffer-rect" framebuffer-rect } { "gpu-data-ptr" gpu-data-ptr }
+}
+{ $description "Reads the rectangular region " { $snippet "framebuffer-rect" } " into " { $snippet "gpu-data-ptr" } ", which can reference either CPU memory (a " { $link byte-array } " or " { $link alien } ") or a GPU " { $link buffer-ptr } ". The format of the written data is determined by the " { $link component-order } " and " { $link component-type } " of the associated " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Reading into a " { $snippet "buffer-ptr" } " requires OpenGL 2.1 or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+{ read-framebuffer read-framebuffer-image read-framebuffer-to } related-words
+
+HELP: renderbuffer
+{ $class-description "Objects of this type represent renderbuffer objects, two-dimensional image buffers that can serve as " { $link framebuffer-attachment } "s to user-created " { $link framebuffer } " objects." }
+{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+{ renderbuffer renderbuffer-dim allocate-renderbuffer <renderbuffer> } related-words
+{ framebuffer <framebuffer> resize-framebuffer } related-words
+
+HELP: renderbuffer-dim
+{ $values
+ { "renderbuffer" renderbuffer }
+ { "dim" sequence }
+}
+{ $description "Returns the dimensions of the allocated image memory for " { $snippet "renderbuffer" } "." }
+{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: resize-framebuffer
+{ $values
+ { "framebuffer" framebuffer } { "dim" sequence }
+}
+{ $description "Reallocates the image memory for all of the textures and renderbuffers bound to " { $snippet "framebuffer" } " to be of the given dimensions." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: right-side
+{ $class-description "Use this value in the " { $snippet "side" } " slot of a " { $link system-attachment } " reference to select the right side of a stereoscopic " { $link system-framebuffer } "." } ;
+
+HELP: stencil-attachment
+{ $class-description "This " { $link attachment-ref } " references the stencil buffer attachment of a user-created " { $link framebuffer } " or the " { $link system-framebuffer } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: system-attachment
+{ $class-description "This " { $link attachment-ref } " references one or more of the color attachments to the " { $link system-framebuffer } ". Depending on the window system pixel format for the window, up to four attachments may be available:"
+{ $list
+{ "If double buffering is available, there is a " { $link back-face } ", which holds the screen image as it is drawn, and a " { $link front-face } ", which holds the current contents of the screen. The two buffers get swapped when a scene is completely drawn." }
+{ "If stereoscopic rendering is available, there is a " { $link left-side } " and " { $link right-side } ", representing the left and right eye viewpoints of a 3D viewing apparatus." }
+}
+"To select a subset of these attachments, the " { $snippet "system-attachment" } " tuple type has two slots:"
+{ $list
+{ { $snippet "side" } " selects either the " { $snippet "left-side" } " or " { $snippet "right-side" } ", or both if set to " { $link f } "." }
+{ { $snippet "face" } " selects either the " { $snippet "back-face" } " or " { $snippet "front-face" } ", or both if set to " { $link f } "." }
+}
+"If stereo or double buffering are not available, then both sides or faces respectively will be equivalent. All attachments can be selected by setting both slots to " { $link f } ", both attachments of a side or face can be selected by setting a single slot, and a single attachment can be targeted by setting both slots." } ;
+
+HELP: system-framebuffer
+{ $class-description "This symbol represents the framebuffer supplied by the window system to store the contents of the window on screen. Since this framebuffer is managed by the window system, it cannot have its attachments modified or resized; however, it is still a valid target for rendering, copying via " { $link copy-framebuffer } ", clearing via " { $link clear-framebuffer } ", and reading via " { $link read-framebuffer } "." } ;
+
+HELP: texture-1d-attachment
+{ $class-description "This class references a single level of detail of a one-dimensional texture for use as a " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: texture-2d-attachment
+{ $class-description "This class references a single level of detail of a two-dimensional texture for use as a " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: texture-3d-attachment
+{ $class-description "This class references a single plane and level of detail of a three-dimensional texture for use as a " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: texture-attachment
+{ $class-description "This class is a union of the " { $link texture-1d-attachment } ", " { $link texture-2d-attachment } ", " { $link texture-3d-attachment } ", and " { $link texture-layer-attachment } " classes, which select layers and levels of detail of " { $link texture } " objects to serve as " { $link framebuffer } " attachments." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ;
+
+HELP: texture-layer-attachment
+{ $class-description "This class references a single layer and level of detail of a three-dimensional texture or array texture for use as a " { $link framebuffer-attachment } "." }
+{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ;
+
+{ texture-1d-attachment <texture-1d-attachment> } related-words
+{ texture-2d-attachment <texture-2d-attachment> } related-words
+{ texture-3d-attachment <texture-3d-attachment> } related-words
+{ texture-layer-attachment <texture-layer-attachment> } related-words
+
+ARTICLE: "gpu.framebuffers" "Framebuffer objects"
+"The " { $vocab-link "gpu.framebuffers" } " vocabulary provides words for creating, allocating, and reading from framebuffer objects. Framebuffer objects are used as rendering targets; the " { $link system-framebuffer } " is supplied by the window system and contains the contents of the window on screen. User-created " { $link framebuffer } " objects can also be created to direct rendering output to offscreen " { $link texture } "s or " { $link renderbuffer } "s."
+{ $subsection system-framebuffer }
+{ $subsection framebuffer }
+{ $subsection renderbuffer }
+"The contents of a framebuffer can be cleared to known values before rendering a scene:"
+{ $subsection clear-framebuffer }
+{ $subsection clear-framebuffer-attachment }
+"The image memory for a renderbuffer can be resized, or the full set of textures and renderbuffers attached to a framebuffer can be resized to the same dimensions together:"
+{ $subsection allocate-renderbuffer }
+{ $subsection resize-framebuffer }
+"Rectangular regions of framebuffers can be read into memory, read into GPU " { $link buffer } "s, and copied between framebuffers:"
+{ $subsection framebuffer-rect }
+{ $subsection attachment-ref }
+{ $subsection read-framebuffer }
+{ $subsection read-framebuffer-to }
+{ $subsection read-framebuffer-image }
+{ $subsection copy-framebuffer } ;
+
+ABOUT: "gpu.framebuffers"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien.c-types arrays byte-arrays combinators
+destructors gpu gpu.buffers gpu.private gpu.textures
+gpu.textures.private images kernel locals math math.rectangles opengl
+opengl.framebuffers opengl.gl opengl.textures sequences
+specialized-arrays.int specialized-arrays.uint
+ui.gadgets.worlds variants ;
+IN: gpu.framebuffers
+
+SINGLETON: system-framebuffer
+
+TUPLE: renderbuffer < gpu-object
+ { component-order component-order initial: RGBA }
+ { component-type component-type initial: ubyte-components }
+ { samples integer initial: 0 } ;
+
+<PRIVATE
+
+: get-framebuffer-int ( enum -- value )
+ GL_RENDERBUFFER swap 0 <int> [ glGetRenderbufferParameteriv ] keep *int ;
+
+PRIVATE>
+
+:: allocate-renderbuffer ( renderbuffer dim -- )
+ GL_RENDERBUFFER renderbuffer handle>> glBindRenderbuffer
+ GL_RENDERBUFFER
+ renderbuffer samples>> dup zero?
+ [ drop renderbuffer texture-gl-internal-format dim first2 glRenderbufferStorage ]
+ [ renderbuffer texture-gl-internal-format dim first2 glRenderbufferStorageMultisample ]
+ if ;
+
+:: renderbuffer-dim ( renderbuffer -- dim )
+ GL_RENDERBUFFER renderbuffer handle>> glBindRenderbuffer
+ GL_RENDERBUFFER_WIDTH get-framebuffer-int
+ GL_RENDERBUFFER_HEIGHT get-framebuffer-int 2array ;
+
+: <renderbuffer> ( component-order component-type samples dim -- renderbuffer )
+ [ [ gen-renderbuffer ] 3dip renderbuffer boa dup ] dip
+ [ allocate-renderbuffer ] [ drop ] if*
+ window-resource ;
+
+M: renderbuffer dispose
+ [ [ delete-renderbuffer ] when* f ] change-handle drop ;
+
+TUPLE: texture-1d-attachment
+ { texture texture-1d-data-target read-only initial: T{ texture-1d } }
+ { level integer read-only } ;
+
+C: <texture-1d-attachment> texture-1d-attachment
+
+TUPLE: texture-2d-attachment
+ { texture texture-2d-data-target read-only initial: T{ texture-2d } }
+ { level integer read-only } ;
+
+C: <texture-2d-attachment> texture-2d-attachment
+
+TUPLE: texture-3d-attachment
+ { texture texture-3d read-only initial: T{ texture-3d } }
+ { z-offset integer read-only }
+ { level integer read-only } ;
+
+C: <texture-3d-attachment> texture-3d-attachment
+
+TUPLE: texture-layer-attachment
+ { texture texture-3d-data-target read-only initial: T{ texture-3d } }
+ { layer integer read-only }
+ { level integer read-only } ;
+
+C: <texture-layer-attachment> texture-layer-attachment
+
+UNION: texture-attachment
+ texture-1d-attachment texture-2d-attachment texture-3d-attachment texture-layer-attachment ;
+
+M: texture-attachment dispose texture>> dispose ;
+
+UNION: framebuffer-attachment renderbuffer texture-attachment ;
+UNION: ?framebuffer-attachment framebuffer-attachment POSTPONE: f ;
+
+GENERIC: attachment-object ( attachment -- object )
+M: renderbuffer attachment-object ;
+M: texture-attachment attachment-object texture>> texture-object ;
+
+TUPLE: framebuffer < gpu-object
+ { color-attachments array read-only }
+ { depth-attachment ?framebuffer-attachment read-only initial: f }
+ { stencil-attachment ?framebuffer-attachment read-only initial: f } ;
+
+UNION: any-framebuffer system-framebuffer framebuffer ;
+
+VARIANT: framebuffer-attachment-side
+ left-side right-side ;
+
+VARIANT: framebuffer-attachment-face
+ back-face front-face ;
+
+UNION: ?framebuffer-attachment-side framebuffer-attachment-side POSTPONE: f ;
+UNION: ?framebuffer-attachment-face framebuffer-attachment-face POSTPONE: f ;
+
+VARIANT: color-attachment-ref
+ default-attachment
+ system-attachment: {
+ { side ?framebuffer-attachment-side initial: f }
+ { face ?framebuffer-attachment-face initial: back-face }
+ }
+ color-attachment: { { index integer } } ;
+
+VARIANT: non-color-attachment-ref
+ depth-attachment
+ stencil-attachment ;
+
+UNION: attachment-ref
+ color-attachment-ref
+ non-color-attachment-ref
+ POSTPONE: f ;
+
+TUPLE: framebuffer-rect
+ { framebuffer any-framebuffer read-only initial: system-framebuffer }
+ { attachment color-attachment-ref read-only initial: default-attachment }
+ { rect rect read-only } ;
+
+C: <framebuffer-rect> framebuffer-rect
+
+: framebuffer-attachment-at ( framebuffer attachment-ref -- attachment )
+ {
+ { default-attachment [ color-attachments>> first ] }
+ { color-attachment [ swap color-attachments>> nth ] }
+ { depth-attachment [ depth-attachment>> ] }
+ { stencil-attachment [ stencil-attachment>> ] }
+ } match ;
+
+<PRIVATE
+
+GENERIC: framebuffer-handle ( framebuffer -- handle )
+
+M: system-framebuffer framebuffer-handle drop 0 ;
+M: framebuffer framebuffer-handle handle>> ;
+
+GENERIC# allocate-framebuffer-attachment 1 ( framebuffer-attachment dim -- )
+
+M: texture-attachment allocate-framebuffer-attachment
+ [ [ texture>> ] [ level>> ] bi ] dip f allocate-texture ;
+M: renderbuffer allocate-framebuffer-attachment
+ allocate-renderbuffer ;
+
+GENERIC: framebuffer-attachment-dim ( framebuffer-attachment -- dim )
+
+M: texture-attachment framebuffer-attachment-dim
+ [ texture>> ] [ level>> ] bi texture-dim
+ dup number? [ 1 2array ] [ 2 head ] if ;
+
+M: renderbuffer framebuffer-attachment-dim
+ renderbuffer-dim ;
+
+: each-attachment ( framebuffer quot: ( attachment -- ) -- )
+ [ [ color-attachments>> ] dip each ]
+ [ swap depth-attachment>> [ swap call ] [ drop ] if* ]
+ [ swap stencil-attachment>> [ swap call ] [ drop ] if* ] 2tri ; inline
+
+: each-attachment-target ( framebuffer quot: ( attachment-target attachment -- ) -- )
+ [ [ color-attachments>> ] dip [ GL_COLOR_ATTACHMENT0 + swap ] prepose each-index ]
+ [ swap depth-attachment>> [ GL_DEPTH_ATTACHMENT spin call ] [ drop ] if* ]
+ [ swap stencil-attachment>> [ GL_STENCIL_ATTACHMENT spin call ] [ drop ] if* ] 2tri ; inline
+
+GENERIC: bind-framebuffer-attachment ( attachment-target attachment -- )
+
+M:: renderbuffer bind-framebuffer-attachment ( attachment-target renderbuffer -- )
+ GL_DRAW_FRAMEBUFFER attachment-target
+ GL_RENDERBUFFER renderbuffer handle>>
+ glFramebufferRenderbuffer ;
+
+M:: texture-1d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
+ GL_DRAW_FRAMEBUFFER attachment-target
+ texture-attachment [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] [ level>> ] bi
+ glFramebufferTexture1D ;
+
+M:: texture-2d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
+ GL_DRAW_FRAMEBUFFER attachment-target
+ texture-attachment [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] [ level>> ] bi
+ glFramebufferTexture2D ;
+
+M:: texture-3d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
+ GL_DRAW_FRAMEBUFFER attachment-target
+ texture-attachment
+ [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ]
+ [ level>> ] [ z-offset>> ] tri
+ glFramebufferTexture3D ;
+
+M:: texture-layer-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
+ GL_DRAW_FRAMEBUFFER attachment-target
+ texture-attachment
+ [ texture>> texture-object handle>> ]
+ [ level>> ] [ layer>> ] tri
+ glFramebufferTextureLayer ;
+
+GENERIC: (default-gl-attachment) ( framebuffer -- gl-attachment )
+GENERIC: (default-attachment-type) ( framebuffer -- type )
+GENERIC: (default-attachment-image-type) ( framebuffer -- order type )
+
+M: system-framebuffer (default-gl-attachment)
+ drop GL_BACK ;
+M: framebuffer (default-gl-attachment)
+ drop GL_COLOR_ATTACHMENT0 ;
+
+SYMBOLS: float-type int-type uint-type ;
+
+: (color-attachment-type) ( framebuffer index -- type )
+ swap color-attachments>> nth attachment-object component-type>> {
+ { [ dup signed-unnormalized-integer-components? ] [ drop int-type ] }
+ { [ dup unsigned-unnormalized-integer-components? ] [ drop uint-type ] }
+ [ drop float-type ]
+ } cond ;
+
+M: system-framebuffer (default-attachment-type)
+ drop float-type ;
+M: framebuffer (default-attachment-type)
+ 0 (color-attachment-type) ;
+
+M: system-framebuffer (default-attachment-image-type) ( framebuffer -- order type )
+ drop RGBA ubyte-components ;
+M: framebuffer (default-attachment-image-type) ( framebuffer -- order type )
+ color-attachments>> first attachment-object
+ [ component-order>> ] [ component-type>> ] bi ;
+
+: gl-system-attachment ( side face -- attachment )
+ 2array {
+ { { f f } [ GL_FRONT_AND_BACK ] }
+ { { f front-face } [ GL_FRONT ] }
+ { { f back-face } [ GL_BACK ] }
+ { { left-side f } [ GL_LEFT ] }
+ { { left-side front-face } [ GL_FRONT_LEFT ] }
+ { { left-side back-face } [ GL_BACK_LEFT ] }
+ { { right-side f } [ GL_RIGHT ] }
+ { { right-side front-face } [ GL_FRONT_RIGHT ] }
+ { { right-side back-face } [ GL_BACK_RIGHT ] }
+ } case ;
+
+: gl-attachment ( framebuffer attachment-ref -- gl-attachment )
+ [ {
+ { depth-attachment [ GL_DEPTH_ATTACHMENT ] }
+ { stencil-attachment [ GL_STENCIL_ATTACHMENT ] }
+ { color-attachment [ GL_COLOR_ATTACHMENT0 + ] }
+ { system-attachment [ gl-system-attachment ] }
+ { default-attachment [ dup (default-gl-attachment) ] }
+ } match ] [ GL_NONE ] if* nip ;
+
+: color-attachment-image-type ( framebuffer attachment-ref -- order type )
+ {
+ { color-attachment [
+ swap color-attachments>> nth
+ attachment-object [ component-order>> ] [ component-type>> ] bi
+ ] }
+ { system-attachment [ 3drop RGBA ubyte-components ] }
+ { default-attachment [ (default-attachment-image-type) ] }
+ } match ;
+
+: framebuffer-rect-image-type ( framebuffer-rect -- order type )
+ [ framebuffer>> ] [ attachment>> ] bi color-attachment-image-type ;
+
+HOOK: (clear-integer-color-attachment) gpu-api ( type value -- )
+
+M: opengl-2 (clear-integer-color-attachment)
+ 4 0 pad-tail first4
+ swap {
+ { int-type [ glClearColorIiEXT ] }
+ { uint-type [ glClearColorIuiEXT ] }
+ } case GL_COLOR_BUFFER_BIT glClear ;
+
+M: opengl-3 (clear-integer-color-attachment)
+ [ GL_COLOR 0 ] dip 4 0 pad-tail
+ swap {
+ { int-type [ >int-array glClearBufferiv ] }
+ { uint-type [ >uint-array glClearBufferuiv ] }
+ } case ;
+
+:: (clear-color-attachment) ( type attachment value -- )
+ attachment glDrawBuffer
+ type float-type =
+ [ value 4 value last pad-tail first4 glClearColor GL_COLOR_BUFFER_BIT glClear ]
+ [ type value (clear-integer-color-attachment) ] if ;
+
+: framebuffer-rect-size ( framebuffer-rect -- size )
+ [ rect>> dim>> product ]
+ [ framebuffer-rect-image-type (bytes-per-pixel) ] bi * ;
+
+PRIVATE>
+
+: <full-framebuffer-rect> ( framebuffer attachment -- framebuffer-rect )
+ 2dup framebuffer-attachment-at
+ { 0 0 } swap framebuffer-attachment-dim <rect>
+ <framebuffer-rect> ;
+
+: resize-framebuffer ( framebuffer dim -- )
+ [ allocate-framebuffer-attachment ] curry each-attachment ;
+
+:: attach-framebuffer-attachments ( framebuffer -- )
+ GL_DRAW_FRAMEBUFFER framebuffer handle>> glBindFramebuffer
+ framebuffer [ bind-framebuffer-attachment ] each-attachment-target ;
+
+M: framebuffer dispose
+ [ [ delete-framebuffer ] when* f ] change-handle drop ;
+
+: dispose-framebuffer-attachments ( framebuffer -- )
+ [ [ dispose ] when* ] each-attachment ;
+
+: <framebuffer> ( color-attachments depth-attachment stencil-attachment dim -- framebuffer )
+ [ [ 0 ] 3dip framebuffer boa dup ] dip
+ [ resize-framebuffer ] [ drop ] if*
+ gen-framebuffer >>handle
+ dup attach-framebuffer-attachments
+ window-resource ;
+
+:: clear-framebuffer-attachment ( framebuffer attachment-ref value -- )
+ GL_DRAW_FRAMEBUFFER framebuffer framebuffer-handle glBindFramebuffer
+ attachment-ref {
+ { system-attachment [| side face |
+ float-type
+ side face gl-system-attachment
+ value (clear-color-attachment)
+ ] }
+ { color-attachment [| i |
+ framebuffer i (color-attachment-type)
+ GL_COLOR_ATTACHMENT0 i +
+ value (clear-color-attachment)
+ ] }
+ { default-attachment [
+ framebuffer [ (default-attachment-type) ] [ (default-gl-attachment) ] bi
+ value (clear-color-attachment)
+ ] }
+ { depth-attachment [ value glClearDepth GL_DEPTH_BUFFER_BIT glClear ] }
+ { stencil-attachment [ value glClearStencil GL_STENCIL_BUFFER_BIT glClear ] }
+ } match ;
+
+: clear-framebuffer ( framebuffer alist -- )
+ [ first2 clear-framebuffer-attachment ] with each ;
+
+:: read-framebuffer-to ( framebuffer-rect gpu-data-ptr -- )
+ GL_READ_FRAMEBUFFER framebuffer-rect framebuffer>> framebuffer-handle glBindFramebuffer
+ framebuffer-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glReadBuffer
+ framebuffer-rect rect>> [ loc>> first2 ] [ dim>> first2 ] bi
+ framebuffer-rect framebuffer-rect-image-type image-data-format
+ gpu-data-ptr pixel-pack-buffer [ glReadPixels ] with-gpu-data-ptr ;
+
+: read-framebuffer ( framebuffer-rect -- byte-array )
+ dup framebuffer-rect-size <byte-array> [ read-framebuffer-to ] keep ;
+
+: read-framebuffer-image ( framebuffer-rect -- image )
+ [ <image> ] dip {
+ [ rect>> dim>> >>dim ]
+ [
+ framebuffer-rect-image-type
+ [ >>component-order ] [ >>component-type ] bi*
+ ]
+ [ read-framebuffer >>bitmap ]
+ } cleave ;
+
+:: copy-framebuffer ( to-fb-rect from-fb-rect depth? stencil? filter -- )
+ GL_DRAW_FRAMEBUFFER to-fb-rect framebuffer>> framebuffer-handle glBindFramebuffer
+ to-fb-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glDrawBuffer
+ GL_READ_FRAMEBUFFER from-fb-rect framebuffer>> framebuffer-handle glBindFramebuffer
+ from-fb-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glReadBuffer
+ to-fb-rect attachment>> [ GL_COLOR_BUFFER_BIT ] [ 0 ] if
+ depth? [ GL_DEPTH_BUFFER_BIT ] [ 0 ] if bitor
+ stencil? [ GL_STENCIL_BUFFER_BIT ] [ 0 ] if bitor :> mask
+
+ from-fb-rect rect>> rect-extent [ first2 ] bi@
+ to-fb-rect rect>> rect-extent [ first2 ] bi@
+ mask filter gl-mag-filter glBlitFramebuffer ;
+
--- /dev/null
+Render targets for GPU operations
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: help.markup help.syntax ui.gadgets.worlds ;
+IN: gpu
+
+HELP: finish-gpu
+{ $description "Waits for all outstanding GPU commands in the current graphics context to complete." } ;
+
+HELP: flush-gpu
+{ $description "Forces the execution of all outstanding GPU commands in the current graphics context." }
+{ $notes { $snippet "flush-gpu" } " does not wait for execution to finish. For that, use " { $link finish-gpu } "." } ;
+
+{ finish-gpu flush-gpu } related-words
+
+HELP: gpu-object
+{ $class-description "Parent class of all GPU resources." } ;
+
+HELP: init-gpu
+{ $description "Initializes the current graphics context for use with the " { $snippet "gpu" } " library. This should be the first thing called in a world's " { $link begin-world } " method." } ;
+
+HELP: reset-gpu
+{ $description "Clears all framebuffer, GPU buffer, shader, and vertex array bindings. Call this before directly calling OpenGL functions after using " { $snippet "gpu" } " functions." } ;
+
+ARTICLE: "gpu" "Graphics context management"
+"Preparing the GPU library:"
+{ $subsection init-gpu }
+"Forcing execution of queued commands:"
+{ $subsection flush-gpu }
+{ $subsection finish-gpu }
+"Resetting OpenGL state:"
+{ $subsection reset-gpu } ;
+
+ARTICLE: "gpu-summary" "GPU-accelerated rendering"
+"The " { $vocab-link "gpu" } " library is a set of vocabularies that work together to provide a convenient interface to creating, managing, and using GPU resources."
+{ $subsection "gpu" }
+{ $subsection "gpu.state" }
+{ $subsection "gpu.buffers" }
+{ $subsection "gpu.textures" }
+{ $subsection "gpu.framebuffers" }
+{ $subsection "gpu.shaders" }
+{ $subsection "gpu.render" }
+"The library is built on top of the OpenGL API, but it aims to be complete enough that raw OpenGL calls are never needed. OpenGL 2.0 with the vertex array object extension (" { $snippet "GL_APPLE_vertex_array_object" } " or " { $snippet "GL_ARB_vertex_array_object" } ") is required. Some features require later OpenGL versions or additional extensions; these requirements are documented alongside individual words. To make full use of the library, an OpenGL 3.1 or later implementation is recommended." ;
+
+ABOUT: "gpu-summary"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: kernel namespaces opengl.capabilities opengl.gl variants ;
+IN: gpu
+
+TUPLE: gpu-object < identity-tuple handle ;
+
+<PRIVATE
+
+VARIANT: gpu-api
+ opengl-2 opengl-3 ;
+
+: set-gpu-api ( -- )
+ "2.0" require-gl-version
+ "3.0" has-gl-version? opengl-3 opengl-2 ? gpu-api set-global ;
+
+HOOK: init-gpu-api gpu-api ( -- )
+
+M: opengl-2 init-gpu-api
+ GL_POINT_SPRITE glEnable ;
+M: opengl-3 init-gpu-api
+ ;
+
+PRIVATE>
+
+: init-gpu ( -- )
+ set-gpu-api
+ init-gpu-api ;
+
+: reset-gpu ( -- )
+ "3.0" { { "GL_APPLE_vertex_array_object" "GL_ARB_vertex_array_object" } }
+ has-gl-version-or-extensions?
+ [ 0 glBindVertexArray ] when
+
+ "3.0" { { "GL_EXT_framebuffer_object" "GL_ARB_framebuffer_object" } }
+ has-gl-version-or-extensions? [
+ GL_DRAW_FRAMEBUFFER 0 glBindFramebuffer
+ GL_READ_FRAMEBUFFER 0 glBindFramebuffer
+ GL_RENDERBUFFER 0 glBindRenderbuffer
+ ] when
+
+ "1.5" { "GL_ARB_vertex_buffer_object" }
+ has-gl-version-or-extensions? [
+ GL_ARRAY_BUFFER 0 glBindBuffer
+ GL_ELEMENT_ARRAY_BUFFER 0 glBindBuffer
+ ] when
+
+ "2.1" { "GL_ARB_pixel_buffer_object" }
+ has-gl-version-or-extensions? [
+ GL_PIXEL_PACK_BUFFER 0 glBindBuffer
+ GL_PIXEL_UNPACK_BUFFER 0 glBindBuffer
+ ] when
+
+ "2.0" { "GL_ARB_shader_objects" }
+ has-gl-version-or-extensions?
+ [ 0 glUseProgram ] when ;
+
+: flush-gpu ( -- )
+ glFlush ;
+
+: finish-gpu ( -- )
+ glFinish ;
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: alien alien.syntax byte-arrays classes gpu.buffers
+gpu.framebuffers gpu.shaders gpu.textures help.markup
+help.syntax images kernel math multiline sequences
+specialized-arrays.alien specialized-arrays.uint
+specialized-arrays.ulong strings ;
+IN: gpu.render
+
+HELP: <index-elements>
+{ $values
+ { "ptr" gpu-data-ptr } { "count" integer } { "index-type" index-type }
+ { "index-elements" index-elements }
+}
+{ $description "Constructs an " { $link index-elements } " tuple." } ;
+
+HELP: <index-range>
+{ $values
+ { "start" integer } { "count" integer }
+ { "index-range" index-range }
+}
+{ $description "Constructs an " { $link index-range } " tuple." } ;
+
+HELP: <multi-index-elements>
+{ $values
+ { "buffer" { $maybe buffer } } { "ptrs" "an " { $link uint-array } " or " { $link void*-array } } { "counts" uint-array } { "index-type" index-type }
+ { "multi-index-elements" multi-index-elements }
+}
+{ $description "Constructs a " { $link multi-index-elements } " tuple." } ;
+
+HELP: <multi-index-range>
+{ $values
+ { "starts" uint-array } { "counts" uint-array }
+ { "multi-index-range" multi-index-range }
+}
+{ $description "Constructs a " { $link multi-index-range } " tuple." } ;
+
+HELP: UNIFORM-TUPLE:
+{ $syntax <" UNIFORM-TUPLE: class-name
+ { "slot" uniform-type dimension }
+ { "slot" uniform-type dimension }
+ ...
+ { "slot" uniform-type dimension } ; "> }
+{ $description "Defines a new " { $link uniform-tuple } " class. Tuples of the new class can be used as the " { $snippet "uniforms" } " slot of a " { $link render-set } " in order to set the uniform parameters of the active shader program. The " { $link uniform-type } " of each slot defines the component type, and the " { $snippet "dimension" } " specifies an array length if not " { $link f } "."
+$nl
+"Uniform parameters are passed from Factor to the shader program through the uniform tuple as follows:"
+{ $list
+{ { $link int-uniform } "s and " { $link uint-uniform } "s take their values from Factor " { $link integer } "s." }
+{ { $link float-uniform } "s take their values from Factor " { $link float } "s." }
+{ { $link bool-uniform } "s take their values from Factor " { $link boolean } "s." }
+{ { $link texture-uniform } "s take their values from " { $link texture } " objects." }
+{ "Vector uniforms take their values from Factor " { $link sequence } "s of the corresponding component type."
+ { $list
+ { "Float vector types: " { $link vec2-uniform } ", " { $link vec3-uniform } ", " { $link vec4-uniform } }
+ { "Integer vector types: " { $link ivec2-uniform } ", " { $link ivec3-uniform } ", " { $link ivec4-uniform } }
+ { "Unsigned integer vector types: " { $link uvec2-uniform } ", " { $link uvec3-uniform } ", " { $link uvec4-uniform } }
+ { "Boolean vector types: " { $link bvec2-uniform } ", " { $link bvec3-uniform } ", " { $link bvec4-uniform } }
+ }
+}
+{ "Matrix uniforms take their values from row-major Factor " { $link sequence } "s of sequences of floats. Matrix types are:"
+ { $list
+ { { $link mat2-uniform } ", " { $link mat2x3-uniform } ", " { $link mat2x4-uniform } }
+ { { $link mat3x2-uniform } ", " { $link mat3-uniform } ", " { $link mat3x4-uniform } }
+ { { $link mat4x2-uniform } ", " { $link mat4x3-uniform } ", " { $link mat4-uniform } }
+ }
+"Rectangular matrix type names are column x row."
+}
+{ "Uniform slots can also be defined as other " { $snippet "uniform-tuple" } " types to bind uniform structures. The uniform structure will take its value from the slots of a tuple of the given type." }
+{ "Array uniforms are passed as Factor sequences of the corresponding value type above." }
+}
+$nl
+"A value of a uniform tuple type is a standard Factor tuple. Uniform tuples are constructed with " { $link new } " or " { $link boa } ", and values are placed inside them using standard slot accessors."
+} ;
+
+HELP: bool-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a boolean uniform parameter." } ;
+
+HELP: bvec2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a two-component boolean vector uniform parameter." } ;
+
+HELP: bvec3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a three-component boolean vector uniform parameter." } ;
+
+HELP: bvec4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a four-component boolean vector uniform parameter." } ;
+
+HELP: define-uniform-tuple
+{ $values
+ { "class" class } { "superclass" class } { "uniforms" sequence }
+}
+{ $description "Defines a new " { $link uniform-tuple } " as a subclass of " { $snippet "superclass" } " with the slots specified by the " { $link uniform } " tuple values in " { $snippet "uniforms" } ". The runtime equivalent of " { $link POSTPONE: UNIFORM-TUPLE: } ". This word must be called inside a compilation unit." } ;
+
+HELP: float-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a float uniform parameter." } ;
+
+{ index-elements index-range multi-index-elements multi-index-range } related-words
+
+HELP: index-elements
+{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a " { $link render-set } " to instruct " { $link render } " to assemble primitives from the active " { $link vertex-array } " by using an array of indexes in CPU or GPU memory."
+{ $list
+{ "The " { $snippet "ptr" } " slot contains a " { $link byte-array } ", " { $link alien } ", or " { $link buffer-ptr } " value referencing the beginning of the index array." }
+{ "The " { $snippet "count" } " slot contains an " { $link integer } " value specifying the number of indexes to supply from the array." }
+{ "The " { $snippet "index-type" } " slot contains an " { $link index-type } " value specifying whether the array consists of " { $link ubyte-indexes } ", " { $link ushort-indexes } ", or " { $link uint-indexes } "." }
+} } ;
+
+HELP: index-range
+{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a " { $link render-set } " to instruct " { $link render } " to assemble primitives sequentially from a slice of the active " { $link vertex-array } "."
+{ $list
+{ "The " { $snippet "start" } " slot contains an " { $link integer } " value indicating the first element of the array to draw." }
+{ "The " { $snippet "count" } " slot contains an " { $link integer } " value indicating the number of elements to draw." }
+} } ;
+
+HELP: index-type
+{ $class-description "The " { $snippet "index-type" } " slot of an " { $link index-elements } " or " { $link multi-index-elements } " tuple indicates the type of the index array's elements: one-byte " { $link ubyte-indexes } ", two-byte " { $link ushort-indexes } ", or four-byte " { $link uint-indexes } "." } ;
+
+{ index-type ubyte-indexes ushort-indexes uint-indexes } related-words
+
+HELP: int-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a signed integer uniform parameter." } ;
+
+HELP: invalid-uniform-type
+{ $values
+ { "uniform" uniform }
+}
+{ $description "Throws an error indicating that a slot of a " { $link uniform-tuple } " has been declared to have an invalid type." } ;
+
+HELP: ivec2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a two-component integer vector uniform parameter." } ;
+
+HELP: ivec3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a three-component integer vector uniform parameter." } ;
+
+HELP: ivec4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a four-component integer vector uniform parameter." } ;
+
+HELP: lines-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to assemble a line from each pair of indexed vertex array elements." } ;
+
+HELP: line-loop-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to assemble a connected loop of lines from each consecutive pair of indexed vertex array elements, adding another line to close the last and first elements." } ;
+
+HELP: line-strip-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to assemble a connected strip of lines from each consecutive pair of indexed vertex array elements." } ;
+
+HELP: mat2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 2x2 square float matrix uniform parameter." } ;
+
+HELP: mat2x3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 2-column, 3-row float matrix uniform parameter." } ;
+
+HELP: mat2x4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 2-column, 4-row float matrix uniform parameter." } ;
+
+HELP: mat3x2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 3-column, 2-row float matrix uniform parameter." } ;
+
+HELP: mat3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 3x3 square float matrix uniform parameter." } ;
+
+HELP: mat3x4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 3-column, 4-row float matrix uniform parameter." } ;
+
+HELP: mat4x2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 4-column, 2-row float matrix uniform parameter." } ;
+
+HELP: mat4x3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 4-column, 3-row float matrix uniform parameter." } ;
+
+HELP: mat4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a 4x4 square float matrix uniform parameter." } ;
+
+HELP: multi-index-elements
+{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a non-instanced " { $link render-set } " to instruct " { $link render } " to assemble primitives from the active " { $link vertex-array } " by using multiple arrays of indexes in CPU or GPU memory."
+{ $list
+{ "The " { $snippet "buffer" } " slot contains either a " { $link buffer } " object to read indexes from, or " { $link f } " to read from CPU memory." }
+{ "The " { $snippet "ptrs" } " slot contains either a " { $link void*-array } " of pointers to the starts of index data, or a pointer-sized " { $link ulong-array } " of offsets into " { $snippet "buffer" } "." }
+{ "The " { $snippet "counts" } " slot contains a " { $link uint-array } " containing the number of indexes to read from each pointer or offset in " { $snippet "ptrs" } "." }
+{ "The " { $snippet "index-type" } " slot contains an " { $link index-type } " value specifying whether the arrays consist of " { $link ubyte-indexes } ", " { $link ushort-indexes } ", or " { $link uint-indexes } "." }
+} } ;
+
+HELP: multi-index-range
+{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a non-instanced " { $link render-set } " to instruct " { $link render } " to assemble primitives from the active " { $link vertex-array } " by using multiple consecutive slices of its elements."
+{ $list
+{ "The " { $snippet "starts" } " slot contains a " { $link uint-array } " of indexes into the array from which to start generating primitives." }
+{ "The " { $snippet "counts" } " slot contains a " { $link uint-array } " of corresponding counts of indexes to read from each specified " { $snippet "start" } " index." }
+} } ;
+
+HELP: points-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a point for each indexed vertex array element." } ;
+
+HELP: primitive-mode
+{ $class-description "The " { $snippet "primitive-mode" } " slot of a " { $link render-set } " tells " { $link render } " what kind of primitives to generate and how to assemble them from the selected elements of the active " { $link vertex-array } "." }
+{ $list
+{ { $link points-mode } " causes each element to generate a point." }
+{ { $link lines-mode } " causes each pair of elements to generate a disconnected line." }
+{ { $link line-strip-mode } " causes each consecutive pair of elements to generate a connected strip of lines." }
+{ { $link line-loop-mode } " causes each consecutive pair of elements to generate a connected loop of lines, with an extra line connecting the last and first elements." }
+{ { $link triangles-mode } " causes every 3 elements to generate an independent triangle." }
+{ { $link triangle-strip-mode } " causes every consecutive group of 3 elements to generate a connected strip of triangles." }
+{ { $link triangle-fan-mode } " causes a triangle to be generated from the first element and every subsequent consecutive pair of elements in a fan pattern." } } ;
+
+{ primitive-mode points-mode lines-mode line-strip-mode line-loop-mode triangles-mode triangle-strip-mode triangle-fan-mode } related-words
+
+HELP: render
+{ $values
+ { "render-set" render-set }
+}
+{ $description "Submits a rendering job to the GPU. The values in the " { $link render-set } " tuple describe the job." } ;
+
+HELP: render-set
+{ $class-description "A " { $snippet "render-set" } " tuple describes a GPU rendering job."
+{ $list
+{ "The " { $link primitive-mode } " slot determines what kind of primitives should be rendered, and how they should be assembled." }
+{ "The " { $link vertex-array } " slot supplies the shader program and vertex data to be rendered." }
+{ "The " { $snippet "uniforms" } " slot contains a " { $link uniform-tuple } " with values for the shader program's uniform parameters." }
+{ "The " { $snippet "indexes" } " slot contains one of the " { $link vertex-indexes } " types and selects elements from the vertex array to be rendered." }
+{ "The " { $snippet "instances" } " slot, if not " { $link f } ", instructs the GPU to render several instances of the same set of vertexes. Instancing requires OpenGL 3.1 or one of the " { $snippet "GL_EXT_draw_instanced" } " or " { $snippet "GL_ARB_draw_instanced" } " extensions." }
+{ "The " { $snippet "framebuffer" } " slot determines the target for the rendering output. Either the " { $link system-framebuffer } " or a user-created " { $link framebuffer } " object can be specified. " { $link f } " can also be specified to disable rasterization and only run the vertex transformation rendering stage." }
+{ "The " { $snippet "output-attachments" } " slot specifies which of the framebuffer's " { $link color-attachment-ref } "s to write the fragment shader's color output to. If the shader uses " { $snippet "gl_FragColor" } " or " { $snippet "gl_FragData[n]" } " to write its output, then " { $snippet "output-attachments" } " should be an array of " { $link color-attachment-ref } "s, and the output to color attachment binding is determined positionally. If the shader uses named output values, then " { $snippet "output-attachments" } " should be a list of string/" { $link color-attachment-ref } " pairs, mapping output names to color attachments." }
+{ "The " { $snippet "transform-feedback-output" } " slot specifies a target for transform feedback output from the vertex shader: either an entire " { $link buffer } ", a " { $link buffer-range } " subset, or a " { $link buffer-ptr } " offset into the buffer. If " { $link f } ", no transform feedback output is collected. The shader program associated with " { $snippet "vertex-array" } " must have a transform feedback output format specified." }
+} }
+{ $notes "User-created framebuffers require OpenGL 3.0 or one of the " { $snippet "GL_EXT_framebuffer_object" } " or " { $snippet "GL_ARB_framebuffer_object" } " extensions. Disabling rasterization requires OpenGL 3.0 or the " { $snippet "GL_EXT_transform_feedback" } " extension. Named output-attachment values are available in GLSL 1.30 or later, and GLSL 1.20 and earlier using the " { $snippet "GL_EXT_gpu_shader4" } " extension. Transform feedback requires OpenGL 3.0 or one of the " { $snippet "GL_EXT_transform_feedback" } " or " { $snippet "GL_ARB_transform_feedback" } " extensions." } ;
+
+{ render render-set } related-words
+
+HELP: texture-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a texture uniform parameter." } ;
+
+HELP: triangle-fan-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a fan of triangles using the first indexed vertex array element and every subsequent consecutive pair of elements." } ;
+
+HELP: triangle-strip-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a strip of triangles using every consecutive group of 3 indexed vertex array elements." } ;
+
+HELP: triangles-mode
+{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a triangle for each group of 3 indexed vertex array elements." } ;
+
+HELP: ubyte-indexes
+{ $class-description "This " { $link index-type } " indicates that an " { $link index-elements } " or " { $link multi-index-elements } " buffer consists of unsigned byte indexes." } ;
+
+HELP: uint-indexes
+{ $class-description "This " { $link index-type } " indicates that an " { $link index-elements } " or " { $link multi-index-elements } " buffer consists of four-byte unsigned int indexes." } ;
+
+HELP: uint-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to an unsigned integer uniform parameter." } ;
+
+HELP: uniform
+{ $class-description "Values of this tuple type are passed to " { $link define-uniform-tuple } " to define a new " { $link uniform-tuple } " type." } ;
+
+HELP: uniform-tuple
+{ $class-description "The base class for tuple types defined with " { $link POSTPONE: UNIFORM-TUPLE: } ". A uniform tuple is used as part of a " { $link render-set } " to supply values for a shader program's uniform parameters. See the " { $link POSTPONE: UNIFORM-TUPLE: } " documentation for details on how uniform tuples are defined and used." } ;
+
+HELP: uniform-type
+{ $class-description { $snippet "uniform-type" } " values are used as part of a " { $link POSTPONE: UNIFORM-TUPLE: } " definition to define the types of uniform slots." } ;
+
+HELP: ushort-indexes
+{ $class-description "This " { $link index-type } " indicates that an " { $link index-elements } " or " { $link multi-index-elements } " buffer consists of two-byte unsigned short indexes." } ;
+
+{ index-type ubyte-indexes ushort-indexes uint-indexes } related-words
+
+HELP: uvec2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a two-component unsigned integer vector uniform parameter." } ;
+
+HELP: uvec3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a three-component unsigned integer vector uniform parameter." } ;
+
+HELP: uvec4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a four-component unsigned integer vector uniform parameter." } ;
+
+HELP: vec2-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a two-component float vector uniform parameter." } ;
+
+HELP: vec3-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a three-component float vector uniform parameter." } ;
+
+HELP: vec4-uniform
+{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " corresponds to a four-component float vector uniform parameter." } ;
+
+HELP: vertex-indexes
+{ $class-description "This class is a union of the following tuple types, any of which can be used as the " { $snippet "indexes" } " slot of a " { $link render-set } " to select elements from a " { $link vertex-array } " for rendering."
+{ $list
+{ "An " { $link index-range } " value submits a sequential slice of a vertex array for rendering." }
+{ "An " { $link index-elements } " value submits vertex array elements in an order specified by an array of indexes." }
+{ "A " { $link multi-index-range } " value submits multiple sequential slices of a vertex array." }
+{ "A " { $link multi-index-elements } " value submits multiple separate lists of indexed vertex array elements." }
+} } ;
+
+ARTICLE: "gpu.render" "Rendering"
+"The " { $vocab-link "gpu.render" } " vocabulary contains words for organizing and submitting data to the GPU for rendering."
+{ $subsection render }
+{ $subsection render-set }
+{ $link uniform-tuple } "s provide Factor types for containing and submitting shader uniform parameters:"
+{ $subsection POSTPONE: UNIFORM-TUPLE: }
+;
+
+ABOUT: "gpu.render"
--- /dev/null
+USING: accessors combinators gpu.render gpu.render.private kernel sequences tools.test ;
+IN: gpu.render.tests
+
+UNIFORM-TUPLE: two-textures
+ { "argyle" texture-uniform f }
+ { "thread-count" float-uniform f }
+ { "tweed" texture-uniform f } ;
+
+UNIFORM-TUPLE: inherited-textures < two-textures
+ { "paisley" texture-uniform f } ;
+
+UNIFORM-TUPLE: array-of-textures < two-textures
+ { "plaids" texture-uniform 4 } ;
+
+UNIFORM-TUPLE: struct-containing-texture
+ { "threads" two-textures f } ;
+
+UNIFORM-TUPLE: array-of-struct-containing-texture
+ { "threads" inherited-textures 3 } ;
+
+UNIFORM-TUPLE: array-of-struct-containing-array-of-texture
+ { "threads" array-of-textures 2 } ;
+
+[ 1 ] [ texture-uniform uniform-type-texture-units ] unit-test
+[ 0 ] [ float-uniform uniform-type-texture-units ] unit-test
+[ 2 ] [ two-textures uniform-type-texture-units ] unit-test
+[ 3 ] [ inherited-textures uniform-type-texture-units ] unit-test
+[ 6 ] [ array-of-textures uniform-type-texture-units ] unit-test
+[ 2 ] [ struct-containing-texture uniform-type-texture-units ] unit-test
+[ 9 ] [ array-of-struct-containing-texture uniform-type-texture-units ] unit-test
+[ 12 ] [ array-of-struct-containing-array-of-texture uniform-type-texture-units ] unit-test
+
+[ { [ ] } ] [ texture-uniform f uniform-texture-accessors ] unit-test
+
+[ { } ] [ float-uniform f uniform-texture-accessors ] unit-test
+
+[ { [ argyle>> ] [ tweed>> ] } ] [ two-textures f uniform-texture-accessors ] unit-test
+
+[ { [ argyle>> ] [ tweed>> ] [ paisley>> ] } ]
+[ inherited-textures f uniform-texture-accessors ] unit-test
+
+[ {
+ [ argyle>> ]
+ [ tweed>> ]
+ [ plaids>> {
+ [ 0 swap nth ]
+ [ 1 swap nth ]
+ [ 2 swap nth ]
+ [ 3 swap nth ]
+ } ]
+} ] [ array-of-textures f uniform-texture-accessors ] unit-test
+
+[ {
+ [ threads>> {
+ [ argyle>> ]
+ [ tweed>> ]
+ } ]
+} ] [ struct-containing-texture f uniform-texture-accessors ] unit-test
+
+[ {
+ [ threads>> {
+ [ 0 swap nth {
+ [ argyle>> ]
+ [ tweed>> ]
+ [ paisley>> ]
+ } ]
+ [ 1 swap nth {
+ [ argyle>> ]
+ [ tweed>> ]
+ [ paisley>> ]
+ } ]
+ [ 2 swap nth {
+ [ argyle>> ]
+ [ tweed>> ]
+ [ paisley>> ]
+ } ]
+ } ]
+} ] [ array-of-struct-containing-texture f uniform-texture-accessors ] unit-test
+
+[ {
+ [ threads>> {
+ [ 0 swap nth {
+ [ argyle>> ]
+ [ tweed>> ]
+ [ plaids>> {
+ [ 0 swap nth ]
+ [ 1 swap nth ]
+ [ 2 swap nth ]
+ [ 3 swap nth ]
+ } ]
+ } ]
+ [ 1 swap nth {
+ [ argyle>> ]
+ [ tweed>> ]
+ [ plaids>> {
+ [ 0 swap nth ]
+ [ 1 swap nth ]
+ [ 2 swap nth ]
+ [ 3 swap nth ]
+ } ]
+ } ]
+ } ]
+} ] [ array-of-struct-containing-array-of-texture f uniform-texture-accessors ] unit-test
+
+[ [
+ nip {
+ [ argyle>> 0 (bind-texture-unit) ]
+ [ tweed>> 1 (bind-texture-unit) ]
+ [ plaids>> {
+ [ 0 swap nth 2 (bind-texture-unit) ]
+ [ 1 swap nth 3 (bind-texture-unit) ]
+ [ 2 swap nth 4 (bind-texture-unit) ]
+ [ 3 swap nth 5 (bind-texture-unit) ]
+ } cleave ]
+ } cleave
+] ] [ array-of-textures [bind-uniform-textures] ] unit-test
+
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien alien.c-types alien.structs arrays
+assocs classes classes.mixin classes.parser classes.singleton
+classes.tuple classes.tuple.private combinators combinators.tuple destructors fry
+generic generic.parser gpu gpu.buffers gpu.framebuffers
+gpu.framebuffers.private gpu.shaders gpu.shaders.private gpu.state
+gpu.textures gpu.textures.private half-floats images kernel
+lexer locals math math.order math.parser namespaces opengl
+opengl.gl parser quotations sequences slots sorting
+specialized-arrays.alien specialized-arrays.float specialized-arrays.int
+specialized-arrays.uint strings ui.gadgets.worlds variants
+vocabs.parser words ;
+IN: gpu.render
+
+UNION: ?integer integer POSTPONE: f ;
+
+VARIANT: uniform-type
+ bool-uniform
+ bvec2-uniform
+ bvec3-uniform
+ bvec4-uniform
+ uint-uniform
+ uvec2-uniform
+ uvec3-uniform
+ uvec4-uniform
+ int-uniform
+ ivec2-uniform
+ ivec3-uniform
+ ivec4-uniform
+ float-uniform
+ vec2-uniform
+ vec3-uniform
+ vec4-uniform
+
+ mat2-uniform
+ mat2x3-uniform
+ mat2x4-uniform
+
+ mat3x2-uniform
+ mat3-uniform
+ mat3x4-uniform
+
+ mat4x2-uniform
+ mat4x3-uniform
+ mat4-uniform
+
+ texture-uniform ;
+
+ALIAS: mat2x2-uniform mat2-uniform
+ALIAS: mat3x3-uniform mat3-uniform
+ALIAS: mat4x4-uniform mat4-uniform
+
+TUPLE: uniform
+ { name string read-only initial: "" }
+ { uniform-type class read-only initial: float-uniform }
+ { dim ?integer read-only initial: f } ;
+
+VARIANT: index-type
+ ubyte-indexes
+ ushort-indexes
+ uint-indexes ;
+
+TUPLE: index-range
+ { start integer read-only }
+ { count integer read-only } ;
+
+C: <index-range> index-range
+
+TUPLE: multi-index-range
+ { starts uint-array read-only }
+ { counts uint-array read-only } ;
+
+C: <multi-index-range> multi-index-range
+
+TUPLE: index-elements
+ { ptr read-only }
+ { count integer read-only }
+ { index-type index-type read-only } ;
+
+C: <index-elements> index-elements
+
+UNION: ?buffer buffer POSTPONE: f ;
+
+TUPLE: multi-index-elements
+ { buffer ?buffer read-only }
+ { ptrs read-only }
+ { counts uint-array read-only }
+ { index-type index-type read-only } ;
+
+C: <multi-index-elements> multi-index-elements
+
+UNION: vertex-indexes
+ index-range
+ multi-index-range
+ index-elements
+ multi-index-elements ;
+
+VARIANT: primitive-mode
+ points-mode
+ lines-mode
+ line-strip-mode
+ line-loop-mode
+ triangles-mode
+ triangle-strip-mode
+ triangle-fan-mode ;
+
+TUPLE: uniform-tuple ;
+
+ERROR: invalid-uniform-type uniform ;
+
+<PRIVATE
+
+: gl-index-type ( index-type -- gl-index-type )
+ {
+ { ubyte-indexes [ GL_UNSIGNED_BYTE ] }
+ { ushort-indexes [ GL_UNSIGNED_SHORT ] }
+ { uint-indexes [ GL_UNSIGNED_INT ] }
+ } case ;
+
+: gl-primitive-mode ( primitive-mode -- gl-primitive-mode )
+ {
+ { points-mode [ GL_POINTS ] }
+ { lines-mode [ GL_LINES ] }
+ { line-strip-mode [ GL_LINE_STRIP ] }
+ { line-loop-mode [ GL_LINE_LOOP ] }
+ { triangles-mode [ GL_TRIANGLES ] }
+ { triangle-strip-mode [ GL_TRIANGLE_STRIP ] }
+ { triangle-fan-mode [ GL_TRIANGLE_FAN ] }
+ } case ;
+
+GENERIC: render-vertex-indexes ( primitive-mode vertex-indexes -- )
+
+GENERIC# render-vertex-indexes-instanced 1 ( primitive-mode vertex-indexes instances -- )
+
+M: index-range render-vertex-indexes
+ [ gl-primitive-mode ] [ [ start>> ] [ count>> ] bi ] bi* glDrawArrays ;
+
+M: index-range render-vertex-indexes-instanced
+ [ gl-primitive-mode ] [ [ start>> ] [ count>> ] bi ] [ ] tri*
+ glDrawArraysInstanced ;
+
+M: multi-index-range render-vertex-indexes
+ [ gl-primitive-mode ] [ [ starts>> ] [ counts>> dup length ] bi ] bi*
+ glMultiDrawArrays ;
+
+M: index-elements render-vertex-indexes
+ [ gl-primitive-mode ]
+ [ [ count>> ] [ index-type>> gl-index-type ] [ ptr>> ] tri ] bi*
+ index-buffer [ glDrawElements ] with-gpu-data-ptr ;
+
+M: index-elements render-vertex-indexes-instanced
+ [ gl-primitive-mode ]
+ [ [ count>> ] [ index-type>> gl-index-type ] [ ptr>> ] tri ]
+ [ ] tri*
+ swap index-buffer [ swap glDrawElementsInstanced ] with-gpu-data-ptr ;
+
+M: multi-index-elements render-vertex-indexes
+ [ gl-primitive-mode ]
+ [ { [ counts>> ] [ index-type>> gl-index-type ] [ ptrs>> dup length ] [ buffer>> ] } cleave ]
+ bi*
+ GL_ELEMENT_ARRAY_BUFFER swap [ handle>> ] [ 0 ] if* glBindBuffer glMultiDrawElements ;
+
+: (bind-texture-unit) ( texture texture-unit -- )
+ swap [ GL_TEXTURE0 + glActiveTexture ] [ bind-texture drop ] bi* ; inline
+
+GENERIC: bind-uniform-textures ( program-instance uniform-tuple -- )
+GENERIC: bind-uniforms ( program-instance uniform-tuple -- )
+
+M: uniform-tuple bind-uniform-textures
+ 2drop ;
+M: uniform-tuple bind-uniforms
+ 2drop ;
+
+: uniform-slot-type ( uniform -- type )
+ dup dim>> [ drop sequence ] [
+ uniform-type>> {
+ { bool-uniform [ boolean ] }
+ { uint-uniform [ integer ] }
+ { int-uniform [ integer ] }
+ { float-uniform [ float ] }
+ { texture-uniform [ texture ] }
+ [ drop sequence ]
+ } case
+ ] if ;
+
+: uniform>slot ( uniform -- slot )
+ [ name>> ] [ uniform-slot-type ] bi 2array ;
+
+: uniform-type-texture-units ( uniform-type -- units )
+ dup texture-uniform = [ drop 1 ] [ "uniform-tuple-texture-units" word-prop 0 or ] if ;
+
+: all-uniform-tuple-slots ( class -- slots )
+ dup "uniform-tuple-slots" word-prop
+ [ swap superclass all-uniform-tuple-slots prepend ] [ drop { } ] if* ;
+
+DEFER: uniform-texture-accessors
+
+: uniform-type-texture-accessors ( uniform-type -- accessors )
+ texture-uniform = [ { [ ] } ] [ { } ] if ;
+
+: uniform-slot-texture-accessor ( uniform -- accessor )
+ [ name>> reader-word ] [ [ uniform-type>> ] [ dim>> ] bi uniform-texture-accessors ] bi
+ dup length 1 = [ first swap prefix ] [ [ ] 2sequence ] if ;
+
+: uniform-tuple-texture-accessors ( uniform-type -- accessors )
+ all-uniform-tuple-slots [ uniform-type>> uniform-type-texture-units zero? not ] filter
+ [ uniform-slot-texture-accessor ] map ;
+
+: uniform-texture-accessors ( uniform-type dim -- accessors )
+ [
+ dup uniform-type?
+ [ uniform-type-texture-accessors ]
+ [ uniform-tuple-texture-accessors ] if
+ ] [
+ 2dup swap empty? not and [
+ iota [
+ [ swap nth ] swap prefix
+ over length 1 = [ swap first append ] [ swap suffix ] if
+ ] with map
+ ] [ drop ] if
+ ] bi* ;
+
+: texture-accessor>cleave ( unit accessors -- unit' cleaves )
+ dup last sequence?
+ [ [ last [ texture-accessor>cleave ] map ] [ but-last ] bi swap suffix \ cleave suffix ]
+ [ over suffix \ (bind-texture-unit) suffix [ 1 + ] dip ] if ;
+
+: [bind-uniform-textures] ( class -- quot )
+ f uniform-texture-accessors
+ 0 swap [ texture-accessor>cleave ] map nip
+ \ nip swap \ cleave [ ] 3sequence ;
+
+DEFER: [bind-uniform-tuple]
+
+:: [bind-uniform-array] ( value>>-quot type texture-unit name dim -- texture-unit' quot )
+ { name uniform-index } >quotation :> index-quot
+ { index-quot value>>-quot bi* } >quotation :> pre-quot
+
+ type H{
+ { bool-uniform { dim swap [ >c-bool ] int-array{ } map-as glUniform1iv } }
+ { int-uniform { dim swap >int-array glUniform1iv } }
+ { uint-uniform { dim swap >uint-array glUniform1uiv } }
+ { float-uniform { dim swap >float-array glUniform1fv } }
+
+ { bvec2-uniform { dim swap [ [ >c-bool ] map ] map int-array{ } concat-as glUniform2iv } }
+ { ivec2-uniform { dim swap int-array{ } concat-as glUniform2i } }
+ { uvec2-uniform { dim swap uint-array{ } concat-as glUniform2ui } }
+ { vec2-uniform { dim swap float-array{ } concat-as glUniform2f } }
+
+ { bvec3-uniform { dim swap [ [ >c-bool ] map ] map int-array{ } concat-as glUniform3iv } }
+ { ivec3-uniform { dim swap int-array{ } concat-as glUniform3i } }
+ { uvec3-uniform { dim swap uint-array{ } concat-as glUniform3ui } }
+ { vec3-uniform { dim swap float-array{ } concat-as glUniform3f } }
+
+ { bvec4-uniform { dim swap [ [ >c-bool ] map ] map int-array{ } concat-as glUniform4iv } }
+ { ivec4-uniform { dim swap int-array{ } concat-as glUniform4iv } }
+ { uvec4-uniform { dim swap uint-array{ } concat-as glUniform4uiv } }
+ { vec4-uniform { dim swap float-array{ } concat-as glUniform4fv } }
+
+ { mat2-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix2fv } }
+ { mat2x3-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix2x3fv } }
+ { mat2x4-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix2x4fv } }
+
+ { mat3x2-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix3x2fv } }
+ { mat3-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix3fv } }
+ { mat3x4-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix3x4fv } }
+
+ { mat4x2-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix4x2fv } }
+ { mat4x3-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix4x3fv } }
+ { mat4-uniform { [ dim 1 ] dip float-array{ } concat-as concat glUniformMatrix4fv } }
+
+ { texture-uniform { drop dim dup iota [ texture-unit + ] int-array{ } map-as glUniform1iv } }
+ } at [ uniform invalid-uniform-type ] unless* >quotation :> value-quot
+
+ type uniform-type-texture-units dim * texture-unit +
+ pre-quot value-quot append ;
+
+:: [bind-uniform-value] ( value>>-quot type texture-unit name -- texture-unit' quot )
+ { name uniform-index } >quotation :> index-quot
+ { index-quot value>>-quot bi* } >quotation :> pre-quot
+
+ type H{
+ { bool-uniform [ >c-bool glUniform1i ] }
+ { int-uniform [ glUniform1i ] }
+ { uint-uniform [ glUniform1ui ] }
+ { float-uniform [ glUniform1f ] }
+
+ { bvec2-uniform [ [ >c-bool ] map first2 glUniform2i ] }
+ { ivec2-uniform [ first2 glUniform2i ] }
+ { uvec2-uniform [ first2 glUniform2ui ] }
+ { vec2-uniform [ first2 glUniform2f ] }
+
+ { bvec3-uniform [ [ >c-bool ] map first3 glUniform3i ] }
+ { ivec3-uniform [ first3 glUniform3i ] }
+ { uvec3-uniform [ first3 glUniform3ui ] }
+ { vec3-uniform [ first3 glUniform3f ] }
+
+ { bvec4-uniform [ [ >c-bool ] map first4 glUniform4i ] }
+ { ivec4-uniform [ first4 glUniform4i ] }
+ { uvec4-uniform [ first4 glUniform4ui ] }
+ { vec4-uniform [ first4 glUniform4f ] }
+
+ { mat2-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix2fv ] }
+ { mat2x3-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix2x3fv ] }
+ { mat2x4-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix2x4fv ] }
+
+ { mat3x2-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix3x2fv ] }
+ { mat3-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix3fv ] }
+ { mat3x4-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix3x4fv ] }
+
+ { mat4x2-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix4x2fv ] }
+ { mat4x3-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix4x3fv ] }
+ { mat4-uniform [ [ 1 1 ] dip float-array{ } concat-as glUniformMatrix4fv ] }
+
+ { texture-uniform { drop texture-unit glUniform1i } }
+ } at [ uniform invalid-uniform-type ] unless* >quotation :> value-quot
+
+ type uniform-type-texture-units texture-unit +
+ pre-quot value-quot append ;
+
+:: [bind-uniform-struct] ( value>>-quot type texture-unit name dim -- texture-unit' quot )
+ dim
+ [
+ iota
+ [ [ [ swap nth ] swap prefix ] map ]
+ [ [ number>string name "[" append "]." surround ] map ] bi
+ ] [
+ { [ ] }
+ name "." append 1array
+ ] if* :> name-prefixes :> quot-prefixes
+ type all-uniform-tuple-slots :> uniforms
+
+ texture-unit quot-prefixes name-prefixes [| quot-prefix name-prefix |
+ uniforms name-prefix [bind-uniform-tuple]
+ quot-prefix prepend
+ ] 2map :> value-cleave :> texture-unit'
+
+ texture-unit'
+ value>>-quot { value-cleave 2cleave } append ;
+
+:: [bind-uniform] ( texture-unit uniform prefix -- texture-unit' quot )
+ prefix uniform name>> append hyphens>underscores :> name
+ uniform uniform-type>> :> type
+ uniform dim>> :> dim
+ uniform name>> reader-word 1quotation :> value>>-quot
+
+ value>>-quot type texture-unit name {
+ { [ type uniform-type? dim and ] [ dim [bind-uniform-array] ] }
+ { [ type uniform-type? dim not and ] [ [bind-uniform-value] ] }
+ [ dim [bind-uniform-struct] ]
+ } cond ;
+
+:: [bind-uniform-tuple] ( texture-unit uniforms prefix -- texture-unit' quot )
+ texture-unit uniforms [ prefix [bind-uniform] ] map :> uniforms-cleave :> texture-unit'
+
+ texture-unit'
+ { uniforms-cleave 2cleave } >quotation ;
+
+:: [bind-uniforms] ( superclass uniforms -- quot )
+ superclass "uniform-tuple-texture-units" word-prop 0 or :> first-texture-unit
+ superclass \ bind-uniforms method :> next-method
+ first-texture-unit uniforms "" [bind-uniform-tuple] nip :> bind-quot
+
+ { 2dup next-method } bind-quot [ ] append-as ;
+
+: define-uniform-tuple-methods ( class superclass uniforms -- )
+ [
+ 2drop
+ [ \ bind-uniform-textures create-method-in ]
+ [ [bind-uniform-textures] ] bi define
+ ] [
+ [ \ bind-uniforms create-method-in ] 2dip
+ [bind-uniforms] define
+ ] 3bi ;
+
+: parse-uniform-tuple-definition ( -- class superclass uniforms )
+ CREATE-CLASS scan {
+ { ";" [ uniform-tuple f ] }
+ { "<" [ scan-word parse-definition [ first3 uniform boa ] map ] }
+ { "{" [
+ uniform-tuple
+ \ } parse-until parse-definition swap prefix
+ [ first3 uniform boa ] map
+ ] }
+ } case ;
+
+: (define-uniform-tuple) ( class superclass uniforms -- )
+ {
+ [ [ uniform>slot ] map define-tuple-class ]
+ [
+ [ uniform-type-texture-units ]
+ [
+ [ [ uniform-type>> uniform-type-texture-units ] [ dim>> 1 or ] bi * ]
+ [ + ] map-reduce
+ ] bi* +
+ "uniform-tuple-texture-units" set-word-prop
+ ]
+ [ nip "uniform-tuple-slots" set-word-prop ]
+ [ define-uniform-tuple-methods ]
+ } 3cleave ;
+
+: true-subclasses ( class -- seq )
+ [ subclasses ] keep [ = not ] curry filter ;
+
+PRIVATE>
+
+: define-uniform-tuple ( class superclass uniforms -- )
+ (define-uniform-tuple) ; inline
+
+SYNTAX: UNIFORM-TUPLE:
+ parse-uniform-tuple-definition define-uniform-tuple ;
+
+<PRIVATE
+
+: bind-vertex-array ( vertex-array -- )
+ handle>> glBindVertexArray ;
+
+: bind-unnamed-output-attachments ( framebuffer attachments -- )
+ [ gl-attachment ] with map
+ dup length 1 =
+ [ first glDrawBuffer ]
+ [ [ length ] [ >int-array ] bi glDrawBuffers ] if ;
+
+: bind-named-output-attachments ( program-instance framebuffer attachments -- )
+ rot '[ first _ swap output-index ] sort-with [ second ] map
+ bind-unnamed-output-attachments ;
+
+: bind-output-attachments ( program-instance framebuffer attachments -- )
+ dup first sequence?
+ [ bind-named-output-attachments ] [ [ drop ] 2dip bind-unnamed-output-attachments ] if ;
+
+GENERIC: bind-transform-feedback-output ( output -- )
+
+M: buffer bind-transform-feedback-output
+ [ GL_TRANSFORM_FEEDBACK_BUFFER 0 ] dip handle>> glBindBufferBase ; inline
+
+M: buffer-range bind-transform-feedback-output
+ [ GL_TRANSFORM_FEEDBACK_BUFFER 0 ] dip
+ [ handle>> ] [ offset>> ] [ size>> ] tri glBindBufferRange ; inline
+
+M: buffer-ptr bind-transform-feedback-output
+ buffer-ptr>range bind-transform-feedback-output ; inline
+
+: gl-feedback-primitive-mode ( primitive-mode -- gl-mode )
+ {
+ { points-mode [ GL_POINTS ] }
+ { lines-mode [ GL_LINES ] }
+ { line-strip-mode [ GL_LINES ] }
+ { line-loop-mode [ GL_LINES ] }
+ { triangles-mode [ GL_TRIANGLES ] }
+ { triangle-strip-mode [ GL_TRIANGLES ] }
+ { triangle-fan-mode [ GL_TRIANGLES ] }
+ } case ;
+
+PRIVATE>
+
+UNION: ?any-framebuffer any-framebuffer POSTPONE: f ;
+UNION: transform-feedback-output buffer buffer-range POSTPONE: f ;
+
+TUPLE: render-set
+ { primitive-mode primitive-mode read-only }
+ { vertex-array vertex-array read-only }
+ { uniforms uniform-tuple read-only }
+ { indexes vertex-indexes initial: T{ index-range } read-only }
+ { instances ?integer initial: f read-only }
+ { framebuffer ?any-framebuffer initial: system-framebuffer read-only }
+ { output-attachments sequence initial: { default-attachment } read-only }
+ { transform-feedback-output transform-feedback-output initial: f read-only } ;
+
+: <render-set> ( x quot-assoc -- render-set )
+ render-set swap make-tuple ; inline
+
+: 2<render-set> ( x y quot-assoc -- render-set )
+ render-set swap 2make-tuple ; inline
+
+: 3<render-set> ( x y z quot-assoc -- render-set )
+ render-set swap 3make-tuple ; inline
+
+: render ( render-set -- )
+ {
+ [ vertex-array>> program-instance>> handle>> glUseProgram ]
+ [
+ [ vertex-array>> program-instance>> ] [ uniforms>> ] bi
+ [ bind-uniform-textures ] [ bind-uniforms ] 2bi
+ ]
+ [
+ framebuffer>>
+ [ GL_DRAW_FRAMEBUFFER swap framebuffer-handle glBindFramebuffer ]
+ [ GL_DRAW_FRAMEBUFFER 0 glBindFramebuffer GL_RASTERIZER_DISCARD glEnable ] if*
+ ]
+ [
+ [ vertex-array>> program-instance>> ]
+ [ framebuffer>> ]
+ [ output-attachments>> ] tri
+ bind-output-attachments
+ ]
+ [ vertex-array>> bind-vertex-array ]
+ [
+ dup transform-feedback-output>> [
+ [ primitive-mode>> gl-feedback-primitive-mode glBeginTransformFeedback ]
+ [ bind-transform-feedback-output ] bi*
+ ] [ drop ] if*
+ ]
+
+ [
+ [ primitive-mode>> ] [ indexes>> ] [ instances>> ] tri
+ [ render-vertex-indexes-instanced ]
+ [ render-vertex-indexes ] if*
+ ]
+
+ [ transform-feedback-output>> [ glEndTransformFeedback ] when ]
+ [ framebuffer>> [ GL_RASTERIZER_DISCARD glDisable ] unless ]
+ } cleave ; inline
+
--- /dev/null
+Execution of GPU jobs
--- /dev/null
+USING: accessors debugger gpu.shaders io kernel prettyprint ;
+IN: gpu.shaders.prettyprint
+
+M: compile-shader-error error.
+ "The GLSL shader " write
+ [ shader>> name>> pprint-short " failed to compile." print ]
+ [ log>> print ] bi ;
+
+M: link-program-error error.
+ "The GLSL program " write
+ [ shader>> name>> pprint-short " failed to link." print ]
+ [ log>> print ] bi ;
+
+M: too-many-feedback-formats-error error.
+ drop
+ "Only one transform feedback format can be specified for a program." print ;
+
+M: invalid-link-feedback-format-error error.
+ drop
+ "Vertex formats used for transform feedback can't contain padding fields." print ;
+
+M: inaccurate-feedback-attribute-error error.
+ drop
+ "The types of the transform feedback attributes don't match those specified by the program's vertex format." print ;
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: alien.syntax classes gpu.buffers help.markup help.syntax
+images kernel math multiline quotations sequences strings ;
+IN: gpu.shaders
+
+HELP: <program-instance>
+{ $values
+ { "program" program }
+ { "instance" program-instance }
+}
+{ $description "Compiles and links an instance of " { $snippet "program" } " for the current graphics context. If an instance already exists for " { $snippet "program" } " in the current context, it is reused." } ;
+
+HELP: <shader-instance>
+{ $values
+ { "shader" shader }
+ { "instance" shader-instance }
+}
+{ $description "Compiles an instance of " { $snippet "shader" } " for the current graphics context. If an instance already exists for " { $snippet "shader" } " in the current context, it is reused." } ;
+
+HELP: <vertex-array>
+{ $values
+ { "program-instance" program-instance } { "vertex-formats" "a list of " { $link buffer-ptr } "/" { $link vertex-format } " pairs" }
+ { "vertex-array" vertex-array }
+}
+{ $description "Creates a new " { $link vertex-array } " to feed data to " { $snippet "program-instance" } " from the set of " { $link buffer } "s specified in " { $snippet "vertex-formats" } "." } ;
+
+HELP: GLSL-PROGRAM:
+{ $syntax "GLSL-PROGRAM: program-name shader shader ... shader [vertex-format] ;" }
+{ $description "Defines a new " { $link program } " named " { $snippet "program-name" } ". When the program is instantiated with " { $link <program-instance> } ", it will link together instances of all of the specified " { $link shader } "s to create the program instance. A single " { $link vertex-array } " may optionally be specified; if the program is used to collect transform feedback, this format will be used for the output." }
+{ $notes "Transform feedback requires OpenGL 3.0 or one of the " { $snippet "GL_EXT_transform_feedback" } " or " { $snippet "GL_ARB_transform_feedback" } " extensions." } ;
+
+HELP: GLSL-SHADER-FILE:
+{ $syntax "GLSL-SHADER-FILE: shader-name shader-kind \"filename\"" }
+{ $description "Defines a new " { $link shader } " of kind " { $link shader-kind } " named " { $snippet "shader-name" } ". The shader will read its source code from " { $snippet "filename" } " in the current Factor source file's directory." } ;
+
+HELP: GLSL-SHADER:
+{ $syntax <" GLSL-SHADER-FILE: shader-name shader-kind
+
+shader source
+
+; "> }
+{ $description "Defines a new " { $link shader } " of kind " { $link shader-kind } " named " { $snippet "shader-name" } ". The shader will read its source code from the current Factor source file between the " { $snippet "GLSL-SHADER:" } " line and the first subsequent line with a single semicolon on it." } ;
+
+HELP: VERTEX-FORMAT:
+{ $syntax <" VERTEX-FORMAT: format-name
+ { "attribute"/f component-type dimension normalize? }
+ { "attribute"/f component-type dimension normalize? }
+ ...
+ { "attribute"/f component-type dimension normalize? } ; "> }
+{ $description "Defines a new binary " { $link vertex-format } " for structuring vertex data stored in " { $link buffer } "s. Each " { $snippet "attribute" } " name either corresponds to an input parameter of a vertex shader, or is " { $link f } " to include padding in the vertex format. The " { $link component-type } " determines the format of the components, and the " { $snippet "dimension" } " determines the number of components. If the " { $snippet "component-type" } " is an integer type and " { $snippet "normalize?" } " is true, the component values will be scaled to the range 0.0 to 1.0 when fed to the vertex shader; otherwise, they will be cast to floats retaining their integral values." } ;
+
+HELP: VERTEX-STRUCT:
+{ $syntax <" VERTEX-STRUCT: struct-name format-name "> }
+{ $description "Defines a struct C type (like " { $link POSTPONE: C-STRUCT: } ") with the same binary format and component types as the given " { $link vertex-format } "." } ;
+
+{ POSTPONE: GLSL-PROGRAM: POSTPONE: GLSL-SHADER-FILE: POSTPONE: GLSL-SHADER: } related-words
+
+HELP: attribute-index
+{ $values
+ { "program-instance" program-instance } { "attribute-name" string }
+ { "index" integer }
+}
+{ $description "Returns the numeric index of the vertex attribute named " { $snippet "attribute-name" } " in " { $snippet "program-instance" } "." } ;
+
+HELP: buffer>vertex-array
+{ $values
+ { "vertex-buffer" buffer } { "program-instance" program-instance } { "format" vertex-format }
+ { "vertex-array" vertex-array }
+}
+{ $description "Creates a new " { $link vertex-array } " from the entire contents of a single " { $link buffer } " in a single " { $link vertex-format } " for use with " { $snippet "program-instance" } "." } ;
+
+{ vertex-array <vertex-array> buffer>vertex-array } related-words
+
+HELP: compile-shader-error
+{ $class-description "An error compiling the source for a " { $link shader } "."
+{ $list
+{ "The " { $snippet "shader" } " slot indicates the shader that failed to compile." }
+{ "The " { $snippet "log" } " slot contains the error string from the GLSL compiler." }
+} } ;
+
+HELP: define-vertex-format
+{ $values
+ { "class" class } { "vertex-attributes" sequence }
+}
+{ $description "Defines a new " { $link vertex-format } " with the binary format specified by the " { $link vertex-attribute } " tuple values in " { $snippet "vertex-attributes" } ". The runtime equivalent of " { $link POSTPONE: VERTEX-FORMAT: } ". This word must be called inside a compilation unit." } ;
+
+HELP: define-vertex-struct
+{ $values
+ { "struct-name" string } { "vertex-format" vertex-format }
+}
+{ $description "Defines a new struct C type from a " { $link vertex-format } ". The runtime equivalent of " { $link POSTPONE: VERTEX-STRUCT: } ". This word must be called inside a compilation unit." } ;
+
+HELP: fragment-shader
+{ $class-description "This " { $link shader-kind } " indicates that a " { $link shader } " is a fragment shader." } ;
+
+HELP: link-program-error
+{ $class-description "An error linking the constituent shaders of a " { $link program } "."
+{ $list
+{ "The " { $snippet "program" } " slot indicates the program that failed to link." }
+{ "The " { $snippet "log" } " slot contains the error string from the GLSL linker." }
+} } ;
+
+{ compile-shader-error link-program-error } related-words
+
+HELP: output-index
+{ $values
+ { "program-instance" program-instance } { "output-name" string }
+ { "index" integer }
+}
+{ $description "Returns the numeric index of the fragment shader output named " { $snippet "output-name" } " in " { $snippet "program-instance" } "." }
+{ $notes "Named fragment shader outputs require OpenGL 3.0 or later and GLSL 1.30 or later, or OpenGL 2.0 or later and GLSL 1.20 or earlier with the " { $snippet "GL_EXT_gpu_shader4" } " extension." } ;
+
+HELP: program
+{ $class-description "A " { $snippet "program" } " provides a specification for linking a " { $link program-instance } " in a graphics context. Programs are defined with " { $link POSTPONE: GLSL-PROGRAM: } " and instantiated for a context with " { $link <program-instance> } "." } ;
+
+HELP: program-instance
+{ $class-description "A " { $snippet "program-instance" } " is a shader " { $link program } " that has been compiled and linked for a graphics context using " { $link <program-instance> } "." } ;
+
+HELP: refresh-program
+{ $values
+ { "program" program }
+}
+{ $description "Rereads the source code for every " { $link shader } " in " { $link program } " and attempts to refresh all the existing " { $link shader-instance } "s and " { $link program-instance } "s for those shaders. If any of the new source code fails to compile or link, the existing valid shader and program instances will remain untouched. However, subsequent attempts to compile new shader or program instances will still attempt to use the new source code. If the compilation and linking succeed, the existing shader and program instances will be updated on the fly to reference the newly compiled code." } ;
+
+HELP: shader
+{ $class-description "A " { $snippet "shader" } " provides a block of GLSL source code that can be compiled into a " { $link shader-instance } " in a graphics context. Shaders are defined with " { $link POSTPONE: GLSL-SHADER: } " or " { $link POSTPONE: GLSL-SHADER-FILE: } " and instantiated for a context with " { $link <shader-instance> } "." } ;
+
+HELP: shader-instance
+{ $class-description "A " { $snippet "shader-instance" } " is a " { $link shader } " that has been compiled for a graphics context using " { $link <shader-instance> } "." } ;
+
+HELP: shader-kind
+{ $class-description "A " { $snippet "shader-kind" } " value is passed as part of a " { $link POSTPONE: GLSL-SHADER: } " or " { $link POSTPONE: GLSL-SHADER-FILE: } " definition to indicate the kind of " { $link shader } " being defined."
+{ $list
+{ { $link vertex-shader } "s run during primitive assembly and map input vertex data to positions in screen space for rasterization." }
+{ { $link fragment-shader } "s run as part of rasterization and decide the final rendered output of a primitive as the outputs of the vertex shader are interpolated across its surface." }
+} } ;
+
+HELP: too-many-feedback-formats-error
+{ $class-description "This error is thrown when a " { $link POSTPONE: GLSL-PROGRAM: } " definition attempts to include more than one " { $link vertex-format } " for transform feedback formatting." } ;
+
+HELP: invalid-link-feedback-format-error
+{ $class-description "This error is thrown when the " { $link vertex-format } " specified as the transform feedback output format of a " { $link program } " is not suitable for the purpose. Transform feedback formats do not support padding (fields with a name of " { $link f } ")." } ;
+
+HELP: inaccurate-feedback-attribute-error
+{ $class-description "This error is thrown when the " { $link vertex-format } " specified as the transform feedback output format of a " { $link program } " does not match the format of the output attributes linked into a " { $link program-instance } "." } ;
+
+HELP: uniform-index
+{ $values
+ { "program-instance" program-instance } { "uniform-name" string }
+ { "index" integer }
+}
+{ $description "Returns the numeric index of the uniform parameter named " { $snippet "output-name" } " in " { $snippet "program-instance" } "." } ;
+
+HELP: vertex-shader
+{ $class-description "This " { $link shader-kind } " indicates that a " { $link shader } " is a vertex shader." } ;
+
+HELP: vertex-array
+{ $class-description "A " { $snippet "vertex-array" } " object associates a shader " { $link program-instance } " with vertex attribute data from one or more " { $link buffer } "s. The format of the binary data inside these buffers is described using " { $link vertex-format } "s. " { $snippet "vertex-array" } "s are constructed using the " { $link <vertex-array> } " or " { $link buffer>vertex-array } " words." } ;
+
+HELP: vertex-array-buffer
+{ $values
+ { "vertex-array" vertex-array }
+ { "vertex-buffer" buffer }
+}
+{ $description "Returns the first " { $link buffer } " object comprised in " { $snippet "vertex-array" } "." } ;
+
+HELP: vertex-attribute
+{ $class-description "This tuple type is passed to " { $link define-vertex-format } " to define a new " { $link vertex-format } " type." } ;
+
+HELP: vertex-format
+{ $class-description "This class encompasses all vertex formats defined by " { $link POSTPONE: VERTEX-FORMAT: } ". A vertex format defines the binary layout of vertex attribute data in a " { $link buffer } " for use as part of a " { $link vertex-array } ". See the " { $link POSTPONE: VERTEX-FORMAT: } " documentation for details on how vertex formats are defined." } ;
+
+HELP: vertex-format-size
+{ $values
+ { "format" vertex-format }
+ { "size" integer }
+}
+{ $description "Returns the size in bytes of a set of vertex attributes in " { $snippet "format" } "." } ;
+
+ARTICLE: "gpu.shaders" "Shader objects"
+"The " { $vocab-link "gpu.shaders" } " vocabulary supports defining, compiling, and linking " { $link shader } "s into " { $link program } "s that run on the GPU and control rendering."
+{ $subsection POSTPONE: GLSL-PROGRAM: }
+{ $subsection POSTPONE: GLSL-SHADER: }
+{ $subsection POSTPONE: GLSL-SHADER-FILE: }
+"A program must be instantiated for each graphics context it is used in:"
+{ $subsection <program-instance> }
+"Program instances can be updated on the fly, allowing for interactive development of shaders:"
+{ $subsection refresh-program }
+"Render data inside GPU " { $link buffer } "s is organized into " { $link vertex-array } "s for consumption by shader code:"
+{ $subsection vertex-array }
+{ $subsection <vertex-array> }
+{ $subsection buffer>vertex-array }
+{ $subsection POSTPONE: VERTEX-FORMAT: } ;
+
+ABOUT: "gpu.shaders"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: multiline gpu.shaders gpu.shaders.private tools.test ;
+IN: gpu.shaders.tests
+
+[ <" ERROR: foo.factor:20: Bad command or filename
+INFO: foo.factor:30: The operation completed successfully
+NOT:A:LOG:LINE "> ]
+[ T{ shader { filename "foo.factor" } { line 19 } }
+<" ERROR: 0:1: Bad command or filename
+INFO: 0:11: The operation completed successfully
+NOT:A:LOG:LINE "> replace-log-line-numbers ] unit-test
+
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien alien.c-types alien.strings
+alien.structs arrays assocs byte-arrays classes.mixin
+classes.parser classes.singleton combinators
+combinators.short-circuit definitions destructors
+generic.parser gpu gpu.buffers hashtables images
+io.encodings.ascii io.files io.pathnames kernel lexer literals
+locals math math.parser memoize multiline namespaces opengl
+opengl.gl opengl.shaders parser quotations sequences
+specialized-arrays.alien specialized-arrays.int splitting
+strings tr ui.gadgets.worlds variants vectors vocabs vocabs.loader
+vocabs.parser words words.constant ;
+IN: gpu.shaders
+
+VARIANT: shader-kind
+ vertex-shader fragment-shader ;
+
+UNION: ?string string POSTPONE: f ;
+
+ERROR: too-many-feedback-formats-error formats ;
+ERROR: invalid-link-feedback-format-error format ;
+ERROR: inaccurate-feedback-attribute-error attribute ;
+
+TUPLE: vertex-attribute
+ { name ?string read-only initial: f }
+ { component-type component-type read-only initial: float-components }
+ { dim integer read-only initial: 4 }
+ { normalize? boolean read-only initial: f } ;
+
+MIXIN: vertex-format
+UNION: ?vertex-format vertex-format POSTPONE: f ;
+
+TUPLE: shader
+ { name word read-only initial: t }
+ { kind shader-kind read-only }
+ { filename read-only }
+ { line integer read-only }
+ { source string }
+ { instances hashtable read-only } ;
+
+TUPLE: program
+ { name word read-only initial: t }
+ { filename read-only }
+ { line integer read-only }
+ { shaders array read-only }
+ { feedback-format ?vertex-format read-only }
+ { instances hashtable read-only } ;
+
+TUPLE: shader-instance < gpu-object
+ { shader shader }
+ { world world } ;
+
+TUPLE: program-instance < gpu-object
+ { program program }
+ { world world } ;
+
+GENERIC: vertex-format-size ( format -- size )
+
+MEMO: uniform-index ( program-instance uniform-name -- index )
+ [ handle>> ] dip glGetUniformLocation ;
+MEMO: attribute-index ( program-instance attribute-name -- index )
+ [ handle>> ] dip glGetAttribLocation ;
+MEMO: output-index ( program-instance output-name -- index )
+ [ handle>> ] dip glGetFragDataLocation ;
+
+<PRIVATE
+
+TR: hyphens>underscores "-" "_" ;
+
+: gl-vertex-type ( component-type -- gl-type )
+ {
+ { ubyte-components [ GL_UNSIGNED_BYTE ] }
+ { ushort-components [ GL_UNSIGNED_SHORT ] }
+ { uint-components [ GL_UNSIGNED_INT ] }
+ { half-components [ GL_HALF_FLOAT ] }
+ { float-components [ GL_FLOAT ] }
+ { byte-integer-components [ GL_BYTE ] }
+ { short-integer-components [ GL_SHORT ] }
+ { int-integer-components [ GL_INT ] }
+ { ubyte-integer-components [ GL_UNSIGNED_BYTE ] }
+ { ushort-integer-components [ GL_UNSIGNED_SHORT ] }
+ { uint-integer-components [ GL_UNSIGNED_INT ] }
+ } case ;
+
+: vertex-type-size ( component-type -- size )
+ {
+ { ubyte-components [ 1 ] }
+ { ushort-components [ 2 ] }
+ { uint-components [ 4 ] }
+ { half-components [ 2 ] }
+ { float-components [ 4 ] }
+ { byte-integer-components [ 1 ] }
+ { short-integer-components [ 2 ] }
+ { int-integer-components [ 4 ] }
+ { ubyte-integer-components [ 1 ] }
+ { ushort-integer-components [ 2 ] }
+ { uint-integer-components [ 4 ] }
+ } case ;
+
+: vertex-attribute-size ( vertex-attribute -- size )
+ [ component-type>> vertex-type-size ] [ dim>> ] bi * ;
+
+: vertex-attributes-size ( vertex-attributes -- size )
+ [ vertex-attribute-size ] [ + ] map-reduce ;
+
+: feedback-type= ( component-type dim gl-type -- ? )
+ [ 2array ] dip {
+ { $ GL_FLOAT [ { float-components 1 } ] }
+ { $ GL_FLOAT_VEC2 [ { float-components 2 } ] }
+ { $ GL_FLOAT_VEC3 [ { float-components 3 } ] }
+ { $ GL_FLOAT_VEC4 [ { float-components 4 } ] }
+ { $ GL_INT [ { int-integer-components 1 } ] }
+ { $ GL_INT_VEC2 [ { int-integer-components 2 } ] }
+ { $ GL_INT_VEC3 [ { int-integer-components 3 } ] }
+ { $ GL_INT_VEC4 [ { int-integer-components 4 } ] }
+ { $ GL_UNSIGNED_INT [ { uint-integer-components 1 } ] }
+ { $ GL_UNSIGNED_INT_VEC2 [ { uint-integer-components 2 } ] }
+ { $ GL_UNSIGNED_INT_VEC3 [ { uint-integer-components 3 } ] }
+ { $ GL_UNSIGNED_INT_VEC4 [ { uint-integer-components 4 } ] }
+ } case = ;
+
+:: assert-feedback-attribute ( size gl-type name vertex-attribute -- )
+ {
+ [ vertex-attribute name>> name = ]
+ [ size 1 = ]
+ [ gl-type vertex-attribute [ component-type>> ] [ dim>> ] bi feedback-type= ]
+ } 0&& [ vertex-attribute inaccurate-feedback-attribute-error ] unless ;
+
+:: [bind-vertex-attribute] ( stride offset vertex-attribute -- stride offset' quot )
+ vertex-attribute name>> hyphens>underscores :> name
+ vertex-attribute component-type>> :> type
+ type gl-vertex-type :> gl-type
+ vertex-attribute dim>> :> dim
+ vertex-attribute normalize?>> >c-bool :> normalize?
+ vertex-attribute vertex-attribute-size :> size
+
+ stride offset size +
+ {
+ { [ name not ] [ [ 2drop ] ] }
+ {
+ [ type unnormalized-integer-components? ]
+ [
+ {
+ name attribute-index [ glEnableVertexAttribArray ] keep
+ dim gl-type stride offset
+ } >quotation :> dip-block
+
+ { dip-block dip <displaced-alien> glVertexAttribIPointer } >quotation
+ ]
+ }
+ [
+ {
+ name attribute-index [ glEnableVertexAttribArray ] keep
+ dim gl-type normalize? stride offset
+ } >quotation :> dip-block
+
+ { dip-block dip <displaced-alien> glVertexAttribPointer } >quotation
+ ]
+ } cond ;
+
+:: [bind-vertex-format] ( vertex-attributes -- quot )
+ vertex-attributes vertex-attributes-size :> stride
+ stride 0 vertex-attributes [ [bind-vertex-attribute] ] { } map-as 2nip :> attributes-cleave
+ { attributes-cleave 2cleave } >quotation :> with-block
+
+ { drop vertex-buffer with-block with-buffer-ptr } >quotation ;
+
+:: [link-feedback-format] ( vertex-attributes -- quot )
+ vertex-attributes [ name>> not ] any?
+ [ [ nip invalid-link-feedback-format-error ] ] [
+ vertex-attributes
+ [ name>> ascii malloc-string ]
+ void*-array{ } map-as :> varying-names
+ vertex-attributes length :> varying-count
+ { drop varying-count varying-names GL_INTERLEAVED_ATTRIBS glTransformFeedbackVaryings }
+ >quotation
+ ] if ;
+
+:: [verify-feedback-attribute] ( vertex-attribute index -- quot )
+ vertex-attribute name>> :> name
+ name length 1 + :> name-buffer-length
+ {
+ index name-buffer-length dup
+ [ f 0 <int> 0 <int> ] dip <byte-array>
+ [ glGetTransformFeedbackVarying ] 3keep
+ ascii alien>string
+ vertex-attribute assert-feedback-attribute
+ } >quotation ;
+
+:: [verify-feedback-format] ( vertex-attributes -- quot )
+ vertex-attributes [ [verify-feedback-attribute] ] map-index :> verify-cleave
+ { drop verify-cleave cleave } >quotation ;
+
+GENERIC: bind-vertex-format ( program-instance buffer-ptr format -- )
+
+GENERIC: link-feedback-format ( program-handle format -- )
+
+M: f link-feedback-format
+ 2drop ;
+
+GENERIC: (verify-feedback-format) ( program-instance format -- )
+
+M: f (verify-feedback-format)
+ 2drop ;
+
+: verify-feedback-format ( program-instance -- )
+ dup program>> feedback-format>> (verify-feedback-format) ;
+
+: define-vertex-format-methods ( class vertex-attributes -- )
+ {
+ [
+ [ \ bind-vertex-format create-method-in ] dip
+ [bind-vertex-format] define
+ ] [
+ [ \ link-feedback-format create-method-in ] dip
+ [link-feedback-format] define
+ ] [
+ [ \ (verify-feedback-format) create-method-in ] dip
+ [verify-feedback-format] define
+ ] [
+ [ \ vertex-format-size create-method-in ] dip
+ [ \ drop ] dip vertex-attributes-size [ ] 2sequence define
+ ]
+ } 2cleave ;
+
+: component-type>c-type ( component-type -- c-type )
+ {
+ { ubyte-components [ "uchar" ] }
+ { ushort-components [ "ushort" ] }
+ { uint-components [ "uint" ] }
+ { half-components [ "half" ] }
+ { float-components [ "float" ] }
+ { byte-integer-components [ "char" ] }
+ { ubyte-integer-components [ "uchar" ] }
+ { short-integer-components [ "short" ] }
+ { ushort-integer-components [ "ushort" ] }
+ { int-integer-components [ "int" ] }
+ { uint-integer-components [ "uint" ] }
+ } case ;
+
+: c-array-dim ( dim -- string )
+ dup 1 = [ drop "" ] [ number>string "[" "]" surround ] if ;
+
+SYMBOL: padding-no
+padding-no [ 0 ] initialize
+
+: padding-name ( -- name )
+ "padding-"
+ padding-no get number>string append
+ "(" ")" surround
+ padding-no inc ;
+
+: vertex-attribute>c-type ( vertex-attribute -- {type,name} )
+ [
+ [ component-type>> component-type>c-type ]
+ [ dim>> c-array-dim ] bi append
+ ] [ name>> [ padding-name ] unless* ] bi 2array ;
+
+: shader-filename ( shader/program -- filename )
+ dup filename>> [ nip ] [ name>> where first ] if* file-name ;
+
+: numbered-log-line? ( log-line-components -- ? )
+ {
+ [ length 4 >= ]
+ [ third string>number ]
+ } 1&& ;
+
+: replace-log-line-number ( object log-line -- log-line' )
+ ":" split dup numbered-log-line? [
+ {
+ [ nip first ]
+ [ drop shader-filename " " prepend ]
+ [ [ line>> ] [ third string>number ] bi* + number>string ]
+ [ nip 3 tail ]
+ } 2cleave [ 3array ] dip append
+ ] [ nip ] if ":" join ;
+
+: replace-log-line-numbers ( object log -- log' )
+ "\n" split [ empty? not ] filter
+ [ replace-log-line-number ] with map
+ "\n" join ;
+
+: gl-shader-kind ( shader-kind -- shader-kind )
+ {
+ { vertex-shader [ GL_VERTEX_SHADER ] }
+ { fragment-shader [ GL_FRAGMENT_SHADER ] }
+ } case ;
+
+PRIVATE>
+
+: define-vertex-format ( class vertex-attributes -- )
+ [
+ [
+ [ define-singleton-class ]
+ [ vertex-format add-mixin-instance ]
+ [ ] tri
+ ] [ define-vertex-format-methods ] bi*
+ ]
+ [ "vertex-format-attributes" set-word-prop ] 2bi ;
+
+SYNTAX: VERTEX-FORMAT:
+ CREATE-CLASS parse-definition
+ [ first4 vertex-attribute boa ] map
+ define-vertex-format ;
+
+: define-vertex-struct ( struct-name vertex-format -- )
+ [ current-vocab ] dip
+ "vertex-format-attributes" word-prop [ vertex-attribute>c-type ] map
+ define-struct ;
+
+SYNTAX: VERTEX-STRUCT:
+ scan scan-word define-vertex-struct ;
+
+TUPLE: vertex-array < gpu-object
+ { program-instance program-instance read-only }
+ { vertex-buffers sequence read-only } ;
+
+M: vertex-array dispose
+ [ [ delete-vertex-array ] when* f ] change-handle drop ;
+
+: <vertex-array> ( program-instance vertex-formats -- vertex-array )
+ gen-vertex-array
+ [ glBindVertexArray [ first2 bind-vertex-format ] with each ]
+ [ -rot [ first buffer>> ] map vertex-array boa ] 3bi
+ window-resource ;
+
+: buffer>vertex-array ( vertex-buffer program-instance format -- vertex-array )
+ [ swap ] dip
+ [ 0 <buffer-ptr> ] dip 2array 1array <vertex-array> ; inline
+
+: vertex-array-buffer ( vertex-array -- vertex-buffer )
+ vertex-buffers>> first ;
+
+TUPLE: compile-shader-error shader log ;
+TUPLE: link-program-error program log ;
+
+: compile-shader-error ( shader instance -- * )
+ [ dup ] dip [ gl-shader-info-log ] [ delete-gl-shader ] bi replace-log-line-numbers
+ \ compile-shader-error boa throw ;
+
+: link-program-error ( program instance -- * )
+ [ dup ] dip [ gl-program-info-log ] [ delete-gl-program ] bi replace-log-line-numbers
+ \ link-program-error boa throw ;
+
+DEFER: <shader-instance>
+
+<PRIVATE
+
+: valid-handle? ( handle -- ? )
+ { [ ] [ zero? not ] } 1&& ;
+
+: compile-shader ( shader -- instance )
+ [ ] [ source>> ] [ kind>> gl-shader-kind ] tri <gl-shader>
+ dup gl-shader-ok?
+ [ swap world get \ shader-instance boa window-resource ]
+ [ compile-shader-error ] if ;
+
+: (link-program) ( program shader-instances -- program-instance )
+ [ [ handle>> ] map ] curry
+ [ feedback-format>> [ link-feedback-format ] curry ] bi (gl-program)
+ dup gl-program-ok? [
+ [ swap world get \ program-instance boa |dispose dup verify-feedback-format ]
+ with-destructors window-resource
+ ] [ link-program-error ] if ;
+
+: link-program ( program -- program-instance )
+ dup shaders>> [ <shader-instance> ] map (link-program) ;
+
+: in-word's-path ( word kind filename -- word kind filename' )
+ [ over ] dip [ where first parent-directory ] dip append-path ;
+
+: become-shader-instance ( shader-instance new-shader-instance -- )
+ handle>> [ swap delete-gl-shader ] curry change-handle drop ;
+
+: refresh-shader-source ( shader -- )
+ dup filename>>
+ [ ascii file-contents >>source drop ]
+ [ drop ] if* ;
+
+: become-program-instance ( program-instance new-program-instance -- )
+ handle>> [ swap delete-gl-program-only ] curry change-handle drop ;
+
+: reset-memos ( -- )
+ \ uniform-index reset-memoized
+ \ attribute-index reset-memoized
+ \ output-index reset-memoized ;
+
+: ?delete-at ( key assoc value -- )
+ 2over at = [ delete-at ] [ 2drop ] if ;
+
+: find-shader-instance ( shader -- instance )
+ world get over instances>> at*
+ [ nip ] [ drop compile-shader ] if ;
+
+: find-program-instance ( program -- instance )
+ world get over instances>> at*
+ [ nip ] [ drop link-program ] if ;
+
+: shaders-and-feedback-format ( words -- shaders feedback-format )
+ [ vertex-format? ] partition swap
+ [ [ def>> first ] map ] [
+ dup length 1 <=
+ [ [ f ] [ first ] if-empty ]
+ [ too-many-feedback-formats-error ] if
+ ] bi* ;
+
+PRIVATE>
+
+:: refresh-program ( program -- )
+ program shaders>> [ refresh-shader-source ] each
+ program instances>> [| world old-instance |
+ old-instance valid-handle? [
+ world [
+ [
+ program shaders>> [ compile-shader |dispose ] map :> new-shader-instances
+ program new-shader-instances (link-program) |dispose :> new-program-instance
+
+ old-instance new-program-instance become-program-instance
+ new-shader-instances [| new-shader-instance |
+ world new-shader-instance shader>> instances>> at
+ new-shader-instance become-shader-instance
+ ] each
+ ] with-destructors
+ ] with-gl-context
+ ] when
+ ] assoc-each
+ reset-memos ;
+
+: <shader-instance> ( shader -- instance )
+ [ find-shader-instance dup world get ] keep instances>> set-at ;
+
+: <program-instance> ( program -- instance )
+ [ find-program-instance dup world get ] keep instances>> set-at ;
+
+SYNTAX: GLSL-SHADER:
+ CREATE-WORD dup
+ scan-word
+ f
+ lexer get line>>
+ parse-here
+ H{ } clone
+ shader boa
+ define-constant ;
+
+SYNTAX: GLSL-SHADER-FILE:
+ CREATE-WORD dup
+ scan-word execute( -- kind )
+ scan-object in-word's-path
+ 0
+ over ascii file-contents
+ H{ } clone
+ shader boa
+ define-constant ;
+
+SYNTAX: GLSL-PROGRAM:
+ CREATE-WORD dup
+ f
+ lexer get line>>
+ \ ; parse-until >array shaders-and-feedback-format
+ H{ } clone
+ program boa
+ define-constant ;
+
+M: shader-instance dispose
+ [ dup valid-handle? [ delete-gl-shader ] [ drop ] if f ] change-handle
+ [ world>> ] [ shader>> instances>> ] [ ] tri ?delete-at ;
+
+M: program-instance dispose
+ [ dup valid-handle? [ delete-gl-program-only ] [ drop ] if f ] change-handle
+ [ world>> ] [ program>> instances>> ] [ ] tri ?delete-at
+ reset-memos ;
+
+"prettyprint" vocab [ "gpu.shaders.prettyprint" require ] when
--- /dev/null
+GPU programs that control vertex transformation and shading
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: help.markup help.syntax kernel math math.rectangles multiline sequences ;
+IN: gpu.state
+
+HELP: <blend-mode>
+{ $values
+ { "equation" blend-equation } { "source-function" blend-function } { "dest-function" blend-function }
+ { "blend-mode" blend-mode }
+}
+{ $description "Constructs a " { $link blend-mode } " tuple." } ;
+
+{ blend-mode <blend-mode> } related-words
+
+HELP: <blend-state>
+{ $values
+ { "constant-color" sequence } { "rgb-mode" { $maybe blend-mode } } { "alpha-mode" { $maybe blend-mode } }
+ { "blend-state" blend-state }
+}
+{ $description "Constructs a " { $link blend-state } " tuple." } ;
+
+{ blend-state <blend-state> get-blend-state } related-words
+
+HELP: <depth-range-state>
+{ $values
+ { "near" float } { "far" float }
+ { "depth-range-state" depth-range-state }
+}
+{ $description "Constructs a " { $link depth-range-state } " tuple." } ;
+
+{ depth-range-state <depth-range-state> get-depth-range-state } related-words
+
+HELP: <depth-state>
+{ $values
+ { "comparison" comparison }
+ { "depth-state" depth-state }
+}
+{ $description "Constructs a " { $link depth-state } " tuple." } ;
+
+{ depth-state <depth-state> get-depth-state } related-words
+
+HELP: <line-state>
+{ $values
+ { "width" float } { "antialias?" boolean }
+ { "line-state" line-state }
+}
+{ $description "Constructs a " { $link line-state } " tuple." } ;
+
+{ line-state <line-state> get-line-state } related-words
+
+HELP: <mask-state>
+{ $values
+ { "color" sequence } { "depth" boolean } { "stencil-front" boolean } { "stencil-back" boolean }
+ { "mask-state" mask-state }
+}
+{ $description "Constructs a " { $link mask-state } " tuple." } ;
+
+{ mask-state <mask-state> get-mask-state } related-words
+
+HELP: <multisample-state>
+{ $values
+ { "multisample?" boolean } { "sample-alpha-to-coverage?" boolean } { "sample-alpha-to-one?" boolean } { "sample-coverage" { $maybe float } } { "invert-sample-coverage?" boolean }
+ { "multisample-state" multisample-state }
+}
+{ $description "Constructs a " { $link multisample-state } " tuple." } ;
+
+{ multisample-state <multisample-state> get-multisample-state } related-words
+
+HELP: <point-state>
+{ $values
+ { "size" { $maybe float } } { "sprite-origin" point-sprite-origin } { "fade-threshold" float }
+ { "point-state" point-state }
+}
+{ $description "Constructs a " { $link point-state } " tuple." } ;
+
+{ point-state <point-state> get-point-state } related-words
+
+HELP: <scissor-state>
+{ $values
+ { "rect" { $maybe rect } }
+ { "scissor-state" scissor-state }
+}
+{ $description "Constructs a " { $link scissor-state } " tuple." } ;
+
+{ scissor-state <scissor-state> get-scissor-state } related-words
+
+HELP: <stencil-mode>
+{ $values
+ { "value" integer } { "mask" integer } { "comparison" comparison } { "stencil-fail-op" stencil-op } { "depth-fail-op" stencil-op } { "depth-pass-op" stencil-op }
+ { "stencil-mode" stencil-mode }
+}
+{ $description "Constructs a " { $link stencil-mode } " tuple." } ;
+
+{ stencil-mode <stencil-mode> } related-words
+
+HELP: <stencil-state>
+{ $values
+ { "front-mode" { $maybe stencil-mode } } { "back-mode" { $maybe stencil-mode } }
+ { "stencil-state" stencil-state }
+}
+{ $description "Constructs a " { $link stencil-state } " tuple." } ;
+
+{ stencil-state <stencil-state> get-stencil-state } related-words
+
+HELP: <triangle-cull-state>
+{ $values
+ { "front-face" triangle-face } { "cull" { $maybe triangle-cull } }
+ { "triangle-cull-state" triangle-cull-state }
+}
+{ $description "Constructs a " { $link triangle-cull-state } " tuple." } ;
+
+{ triangle-cull-state <triangle-cull-state> get-triangle-cull-state } related-words
+
+HELP: <triangle-state>
+{ $values
+ { "front-mode" triangle-mode } { "back-mode" triangle-mode } { "antialias?" boolean }
+ { "triangle-state" triangle-state }
+}
+{ $description "Constructs a " { $link triangle-state } " tuple." } ;
+
+{ triangle-state <triangle-state> get-triangle-state } related-words
+
+HELP: <viewport-state>
+{ $values
+ { "rect" rect }
+ { "viewport-state" viewport-state }
+}
+{ $description "Constructs a " { $link viewport-state } " tuple." } ;
+
+{ viewport-state <viewport-state> get-viewport-state } related-words
+
+HELP: blend-equation
+{ $class-description "The " { $snippet "blend-equation" } " of a " { $link blend-mode } " determines how the source and destination color values are combined after they have been multiplied by the result of their respective " { $link blend-function } "s."
+{ $list
+{ { $link eq-add } " indicates that the source and destination results are added." }
+{ { $link eq-subtract } " indicates that the destination result is subtracted from the source." }
+{ { $link eq-reverse-subtract } " indicates that the source result is subtracted from the destination." }
+{ { $link eq-min } " indicates that the componentwise minimum of the source and destination results is taken." }
+{ { $link eq-max } " indicates that the componentwise maximum of the source and destination results is taken." }
+} } ;
+
+HELP: blend-function
+{ $class-description "The " { $snippet "blend-function" } "s of a " { $link blend-mode } " multiply the source and destination colors being blended by a function of their values before they are combined by the " { $link blend-equation } "."
+{ $list
+ { { $link func-zero } " returns a constant factor of zero." }
+ { { $link func-one } " returns a constant factor of one." }
+ { { $link func-source } " returns the corresponding source color component for every result component." }
+ { { $link func-one-minus-source } " returns one minus the corresponding source color component for every result component." }
+ { { $link func-dest } " returns the corresponding destination color component for every result component." }
+ { { $link func-one-minus-dest } " returns one minus the corresponding destination color component for every result component." }
+ { { $link func-constant } " returns the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+ { { $link func-one-minus-constant } " returns one minus the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+ { { $link func-source-alpha } " returns the source alpha component for every result component." }
+ { { $link func-one-minus-source-alpha } " returns one minus the source alpha component for every result component." }
+ { { $link func-dest-alpha } " returns the destination alpha component for every result component." }
+ { { $link func-one-minus-dest-alpha } " returns one minus the destination alpha component for every result component." }
+ { { $link func-constant-alpha } " returns the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+ { { $link func-one-minus-constant-alpha } " returns one minus the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+} } ;
+
+HELP: blend-mode
+{ $class-description "A " { $link blend-mode } " is specified as part of the " { $link blend-state } " to determine the blending equation used between the source (incoming fragment) and destination (existing framebuffer value) colors of blended pixels."
+{ $list
+{ "The " { $snippet "equation" } " slot determines how the source and destination colors are combined after the " { $snippet "source-function" } " and " { $snippet "dest-function" } " have been applied."
+ { $list
+ { { $link eq-add } " indicates that the source and destination results are added." }
+ { { $link eq-subtract } " indicates that the destination result is subtracted from the source." }
+ { { $link eq-reverse-subtract } " indicates that the source result is subtracted from the destination." }
+ { { $link eq-min } " indicates that the componentwise minimum of the source and destination results is taken." }
+ { { $link eq-max } " indicates that the componentwise maximum of the source and destination results is taken." }
+ }
+}
+{ "The " { $snippet "source-function" } " and " { $snippet "dest-function" } " slots each specify a function to apply to the source, destination, or constant color values to generate a blending factor that is multiplied respectively against the source or destination value before feeding the results to the " { $snippet "equation" } "."
+}
+ { $list
+ { { $link func-zero } " returns a constant factor of zero." }
+ { { $link func-one } " returns a constant factor of one." }
+ { { $link func-source } " returns the corresponding source color component for every result component." }
+ { { $link func-one-minus-source } " returns one minus the corresponding source color component for every result component." }
+ { { $link func-dest } " returns the corresponding destination color component for every result component." }
+ { { $link func-one-minus-dest } " returns one minus the corresponding destination color component for every result component." }
+ { { $link func-constant } " returns the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+ { { $link func-one-minus-constant } " returns one minus the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+ { { $link func-source-alpha } " returns the source alpha component for every result component." }
+ { { $link func-one-minus-source-alpha } " returns one minus the source alpha component for every result component." }
+ { { $link func-dest-alpha } " returns the destination alpha component for every result component." }
+ { { $link func-one-minus-dest-alpha } " returns one minus the destination alpha component for every result component." }
+ { { $link func-constant-alpha } " returns the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+ { { $link func-one-minus-constant-alpha } " returns one minus the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." }
+}
+"A typical transparency effect will use the values:"
+{ $code <" T{ blend-mode
+ { equation eq-add }
+ { source-function func-source-alpha }
+ { dest-function func-one-minus-source-alpha }
+} "> }
+} } ;
+
+HELP: blend-state
+{ $class-description "The " { $snippet "blend-state" } " controls how alpha blending between the current framebuffer contents and newly drawn pixels."
+{ $list
+{ "The " { $snippet "constant-color" } " slot contains an optional four-" { $link float } " sequence that specifies a constant parameter to the " { $snippet "func-*constant*" } " " { $link blend-function } "s. If constant blend functions are not used, the slot can be " { $link f } "." }
+{ "The " { $snippet "rgb-mode" } " and " { $snippet "alpha-mode" } " slots both contain " { $link blend-mode } " values that determine the blending equation used between RGB and alpha channel values, respectively. If both slots are " { $link f } ", blending is disabled." }
+} } ;
+
+HELP: cmp-always
+{ $class-description "This " { $link comparison } " test always succeeds." } ;
+
+HELP: cmp-equal
+{ $class-description "This " { $link comparison } " test succeeds if the compared values are equal." } ;
+
+HELP: cmp-greater
+{ $class-description "This " { $link comparison } " test succeeds if the incoming value is greater than the buffer value." } ;
+
+HELP: cmp-greater-equal
+{ $class-description "This " { $link comparison } " test succeeds if the incoming value is greater than or equal to the buffer value." } ;
+
+HELP: cmp-less
+{ $class-description "This " { $link comparison } " test succeeds if the incoming value is less than the buffer value." } ;
+
+HELP: cmp-less-equal
+{ $class-description "This " { $link comparison } " test succeeds if the incoming value is less than or equal to the buffer value." } ;
+
+HELP: cmp-never
+{ $class-description "This " { $link comparison } " test always fails." } ;
+
+HELP: cmp-not-equal
+{ $class-description "This " { $link comparison } " test succeeds if the compared values are not equal." } ;
+
+HELP: comparison
+{ $class-description { $snippet "comparison" } " values are used in the " { $link stencil-state } " and " { $link depth-state } " and control how the fragment stencil and depth tests are performed. For the stencil test, a reference value (the " { $snippet "value" } " slot of the active " { $link stencil-mode } ") is compared to the stencil buffer value using the comparison operator. For the depth test, the incoming fragment depth is compared to the depth buffer value."
+{ $list
+{ { $link cmp-always } " always succeeds." }
+{ { $link cmp-never } " always fails." }
+{ { $link cmp-equal } " succeeds if the compared values are equal." }
+{ { $link cmp-not-equal } " succeeds if the compared values are not equal." }
+{ { $link cmp-less } " succeeds if the incoming value is less than the buffer value." }
+{ { $link cmp-less-equal } " succeeds if the incoming value is less than or equal to the buffer value." }
+{ { $link cmp-greater } " succeeds if the incoming value is greater than the buffer value." }
+{ { $link cmp-greater-equal } " succeeds if the incoming value is greater than or equal to the buffer value." }
+} } ;
+
+HELP: cull-all
+{ $class-description "This " { $link triangle-cull } " value culls all triangles." } ;
+
+HELP: cull-back
+{ $class-description "This " { $link triangle-cull } " value culls back-facing triangles." } ;
+
+HELP: cull-front
+{ $class-description "This " { $link triangle-cull } " value culls front-facing triangles." } ;
+
+HELP: depth-range-state
+{ $class-description "The " { $snippet "depth-range-state" } " controls the range of depth values that are generated for fragments and used for depth testing and writing to the depth buffer."
+{ $list
+{ "The " { $snippet "near" } " slot contains a " { $link float } " value that will be assigned to fragments on the near plane. The default value is " { $snippet "0.0" } "." }
+{ "The " { $snippet "far" } " slot contains a " { $link float } " value that will be assigned to fragments on the far plane. The default value is " { $snippet "1.0" } "." }
+} } ;
+
+HELP: depth-state
+{ $class-description "The " { $snippet "depth-state" } " controls how incoming fragments' depth values are tested against the depth buffer. The " { $link comparison } " slot, if not " { $link f } ", determines the condition that must be true between the incoming fragment depth and depth buffer depth to pass a fragment. If the " { $snippet "comparison" } " is " { $link f } ", depth testing is disabled and all fragments pass. " { $link cmp-less } " is typically used for depth culling." } ;
+
+HELP: eq-add
+{ $var-description "This " { $link blend-equation } " adds the source and destination colors together." } ;
+
+HELP: eq-max
+{ $var-description "This " { $link blend-equation } " takes the componentwise maximum of the source and destination colors." } ;
+
+HELP: eq-min
+{ $var-description "This " { $link blend-equation } " takes the componentwise minimum of the source and destination colors." } ;
+
+HELP: eq-reverse-subtract
+{ $var-description "This " { $link blend-equation } " subtracts the source color from the destination color." } ;
+
+HELP: eq-subtract
+{ $var-description "This " { $link blend-equation } " subtracts the destination color from the source color." } ;
+
+HELP: face-ccw
+{ $class-description "This " { $link triangle-face } " value refers to the face with counterclockwise-wound vertices." } ;
+
+HELP: face-cw
+{ $class-description "This " { $link triangle-face } " value refers to the face with clockwise-wound vertices." } ;
+
+HELP: func-constant
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ;
+
+HELP: func-constant-alpha
+{ $class-description "This " { $link blend-function } " multiplies the input color by the alpha component of the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ;
+
+HELP: func-dest
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the destination color value." } ;
+
+HELP: func-dest-alpha
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the alpha component of the destination color value." } ;
+
+HELP: func-one
+{ $class-description "This " { $link blend-function } " multiplies the input color by one; that is, the input color is unchanged." } ;
+
+HELP: func-one-minus-constant
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by one minus the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ;
+
+HELP: func-one-minus-constant-alpha
+{ $class-description "This " { $link blend-function } " multiplies the input color by one minus the alpha component of the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ;
+
+HELP: func-one-minus-dest
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by one minus the destination color value." } ;
+
+HELP: func-one-minus-dest-alpha
+{ $class-description "This " { $link blend-function } " multiplies the input color by one minus the alpha component of the destination color value." } ;
+
+HELP: func-one-minus-source
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by one minus the source color value." } ;
+
+HELP: func-one-minus-source-alpha
+{ $class-description "This " { $link blend-function } " multiplies the input color by one minus the alpha component source color value." } ;
+
+HELP: func-source
+{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the source color value." } ;
+
+HELP: func-source-alpha
+{ $class-description "This " { $link blend-function } " multiplies the input color by the alpha component of the source color value." } ;
+
+HELP: func-source-alpha-saturate
+{ $class-description "This " { $link blend-function } " multiplies the input color by the minimum of the alpha component of the source color value and one minus the alpha component of the destination color value. It is only valid as the " { $snippet "source-function" } " of a " { $link blend-mode } "." } ;
+
+HELP: func-zero
+{ $class-description "This " { $link blend-function } " multiplies the input color by zero." } ;
+
+HELP: get-blend-state
+{ $values
+
+ { "blend-state" blend-state }
+}
+{ $description "Retrieves the current GPU " { $link blend-state } "." } ;
+
+HELP: get-depth-range-state
+{ $values
+
+ { "depth-range-state" depth-range-state }
+}
+{ $description "Retrieves the current GPU " { $link depth-range-state } "." } ;
+
+HELP: get-depth-state
+{ $values
+
+ { "depth-state" depth-state }
+}
+{ $description "Retrieves the current GPU " { $link depth-state } "." } ;
+
+HELP: get-line-state
+{ $values
+
+ { "line-state" line-state }
+}
+{ $description "Retrieves the current GPU " { $link line-state } "." } ;
+
+HELP: get-mask-state
+{ $values
+
+ { "mask-state" mask-state }
+}
+{ $description "Retrieves the current GPU " { $link mask-state } "." } ;
+
+HELP: get-multisample-state
+{ $values
+
+ { "multisample-state" multisample-state }
+}
+{ $description "Retrieves the current GPU " { $link multisample-state } "." } ;
+
+HELP: get-point-state
+{ $values
+
+ { "point-state" point-state }
+}
+{ $description "Retrieves the current GPU " { $link point-state } "." } ;
+
+HELP: get-scissor-state
+{ $values
+
+ { "scissor-state" scissor-state }
+}
+{ $description "Retrieves the current GPU " { $link scissor-state } "." } ;
+
+HELP: get-stencil-state
+{ $values
+
+ { "stencil-state" stencil-state }
+}
+{ $description "Retrieves the current GPU " { $link stencil-state } "." } ;
+
+HELP: get-triangle-cull-state
+{ $values
+
+ { "triangle-cull-state" triangle-cull-state }
+}
+{ $description "Retrieves the current GPU " { $link triangle-cull-state } "." } ;
+
+HELP: get-triangle-state
+{ $values
+
+ { "triangle-state" triangle-state }
+}
+{ $description "Retrieves the current GPU " { $link triangle-state } "." } ;
+
+HELP: get-viewport-state
+{ $values
+
+ { "viewport-state" viewport-state }
+}
+{ $description "Retrieves the current GPU " { $link viewport-state } "." } ;
+
+HELP: gpu-state
+{ $class-description "This class is a union of all the GPU state tuple classes that can be passed to " { $link set-gpu-state } ":"
+{ $list
+{ { $link viewport-state } }
+{ { $link scissor-state } }
+{ { $link multisample-state } }
+{ { $link stencil-state } }
+{ { $link depth-range-state } }
+{ { $link depth-state } }
+{ { $link blend-state } }
+{ { $link mask-state } }
+{ { $link triangle-cull-state } }
+{ { $link triangle-state } }
+{ { $link point-state } }
+{ { $link line-state } }
+} } ;
+
+HELP: line-state
+{ $class-description "The " { $snippet "line-state" } " controls how lines are rendered."
+{ $list
+{ "The " { $snippet "width" } " slot is a " { $link float } " value specifying the line width in pixels." }
+{ "The " { $snippet "antialias?" } " slot is a " { $link boolean } " value specifying whether line edges should be smoothed." }
+}
+} ;
+
+HELP: mask-state
+{ $class-description "The " { $snippet "mask-state" } " controls what parts of the framebuffer are written to."
+{ $list
+{ "The " { $snippet "color" } " slot is a sequence of four " { $link boolean } " values specifying whether the red, green, blue, and alpha channels of the color buffer will be written to." }
+{ "The " { $snippet "depth" } " slot is a " { $link boolean } " value specifying whether the depth buffer will be written to." }
+{ "The " { $snippet "stencil-front" } " and " { $snippet "stencil-back" } " slots are " { $link integer } " values that indicate which bits of the stencil buffer will be written to for front- and back-facing triangles, respectively." }
+} } ;
+
+HELP: multisample-state
+{ $class-description "The " { $snippet "multisample-state" } " controls whether and how multisampling occurs."
+{ $list
+{ "The " { $snippet "multisample?" } " slot is a " { $link boolean } " value that determines whether multisampling is enabled." }
+{ "The " { $snippet "sample-alpha-to-coverage?" } " slot is a " { $link boolean } " value that determines whether sample coverage values are determined from their alpha components." }
+{ "The " { $snippet "sample-alpha-to-one?" } " slot is a " { $link boolean } " value that determines whether a sample's alpha value is replaced with one after its alpha-based coverage is calculated." }
+{ "The " { $snippet "sample-coverage" } " slot is an optional " { $link float } " value that is used to calculate another coverage value that is then combined with the alpha-based coverage. If " { $link f } ", the alpha-based coverage is untouched." }
+{ "The " { $snippet "invert-sample-coverage?" } " slot is a " { $link boolean } " value that, if true, indicates that the coverage value derived from " { $snippet "sample-coverage" } " should be inverted before being combined." }
+} } ;
+
+HELP: op-dec-sat
+{ $class-description "This " { $link stencil-op } " subtracts one from the stencil buffer value, leaving it unchanged if it is already zero." } ;
+
+HELP: op-dec-wrap
+{ $class-description "This " { $link stencil-op } " subtracts one from the stencil buffer value, wrapping the value to the maximum storable value if it was zero." } ;
+
+HELP: op-inc-sat
+{ $class-description "This " { $link stencil-op } " adds one to the stencil buffer value, leaving it unchanged if it is already the maximum storable value." } ;
+
+HELP: op-inc-wrap
+{ $class-description "This " { $link stencil-op } " adds one to the stencil buffer value, wrapping the value to zero if it was the maximum storable value." } ;
+
+HELP: op-invert
+{ $class-description "This " { $link stencil-op } " bitwise NOTs the stencil buffer value." } ;
+
+HELP: op-keep
+{ $class-description "This " { $link stencil-op } " leaves the stencil buffer value unchanged." } ;
+
+HELP: op-replace
+{ $class-description "This " { $link stencil-op } " sets the stencil buffer value to the reference " { $snippet "value" } "." } ;
+
+HELP: op-zero
+{ $class-description "This " { $link stencil-op } " sets the stencil buffer value to zero." } ;
+
+HELP: origin-lower-left
+{ "This " { $link point-sprite-origin } " value sets the point sprite coordinate origin to the lower left corner of the point and increases the Y coordinate upward." } ;
+
+HELP: origin-upper-left
+{ "This " { $link point-sprite-origin } " value sets the point sprite coordinate origin to the upper left corner of the point and increases the Y coordinate downward." } ;
+
+HELP: point-sprite-origin
+{ $class-description "The " { $snippet "point-sprite-origin" } " is set as part of the " { $link point-state } " and determines how point sprite coordinates are generated over the rendered area of a point."
+{ $list
+{ { $link origin-lower-left } " sets the coordinate origin to the lower left corner of the point and increases the Y coordinate upward." }
+{ { $link origin-upper-left } " sets the coordinate origin to the upper left corner of the point and increases the Y coordinate downward." }
+} } ;
+
+HELP: point-state
+{ $class-description "The " { $snippet "point-state" } " controls how points are drawn."
+{ $list
+{ "The " { $snippet "size" } " slot contains either a " { $link float } " value specifying a constant pixel radius for all points drawn, or " { $link f } ", in which case the vertex shader determines the size of each point independently." }
+{ "The " { $snippet "sprite-origin" } " slot contains either " { $link origin-lower-left } " or " { $link origin-upper-left } ", and determines whether the vertical point sprite coordinates fed to the fragment shader start at zero in the bottom corner and increase upward or start at zero in the upper corner and increase downward." }
+{ "If multisampling is enabled in the " { $link multisample-state } ", the " { $snippet "fade-threshold" } " slot specifies a pixel width at which the multisampling implementation may fade the alpha component of point fragments." }
+} } ;
+
+HELP: scissor-state
+{ $class-description "The " { $snippet "scissor-state" } " allows rendering output to be clipped to a rectangular region of the framebuffer. If the " { $snippet "rect" } " slot is set to a " { $link rect } " value, fragments outside that rectangle will be discarded. If it is " { $link f } ", fragments are allowed anywhere on the framebuffer." } ;
+
+HELP: set-gpu-state
+{ $values
+ { "states" "a " { $link sequence } " or " { $link gpu-state } }
+}
+{ $description "Changes the GPU state using the values passed in " { $snippet "states" } "." } ;
+
+HELP: set-gpu-state*
+{ $values
+ { "state" gpu-state }
+}
+{ $description "Changes the GPU state using a single " { $link gpu-state } " value." } ;
+
+HELP: stencil-mode
+{ $class-description "A " { $snippet "stencil-mode" } " is specified as part of the " { $link stencil-state } " to define the interaction between an incoming fragment and the stencil buffer."
+{ $list
+{ "The " { $snippet "value" } " slot contains an " { $link integer } " value that is used as the reference value for the " { $snippet "comparison" } " of the stencil test." }
+{ "The " { $snippet "mask" } " slot contains an " { $link integer } " mask value that indicates which bits are relevant to the stencil test." }
+{ "The " { $snippet "comparison" } " slot contains a " { $link comparison } " value that indicates the comparison taken between the masked reference value and stored stencil buffer value to determine whether the fragment is allowed to pass." }
+{ "The " { $snippet "stencil-fail-op" } ", " { $snippet "depth-fail-op" } ", and " { $snippet "depth-pass-op" } " slots all contain " { $link stencil-op } " values that determine how the value in the stencil buffer is affected when the stencil test fails, the stencil test succeeds but depth test fails, and both stencil and depth tests succeed, respectively."
+ { $list
+ { { $link op-keep } " leaves the stencil buffer value unchanged." }
+ { { $link op-zero } " sets the stencil buffer value to zero." }
+ { { $link op-replace } " sets the stencil buffer value to the reference " { $snippet "value" } "." }
+ { { $link op-invert } " bitwise NOTs the stencil buffer value." }
+ { { $link op-inc-sat } " adds one to the stencil buffer value, leaving it unchanged if it is already the maximum storable value." }
+ { { $link op-dec-sat } " subtracts one from the stencil buffer value, leaving it unchanged if it is already zero." }
+ { { $link op-inc-wrap } " adds one to the stencil buffer value, wrapping the value to zero if it was the maximum storable value." }
+ { { $link op-dec-wrap } " subtracts one from the stencil buffer value, wrapping the value to the maximum storable value if it was zero." }
+ }
+}
+} } ;
+
+HELP: stencil-op
+{ $class-description { $snippet "stencil-op" } "s are set as part of a " { $link stencil-mode } " and determine how the stencil buffer is modified by incoming fragments."
+{ $list
+{ { $link op-keep } " leaves the stencil buffer value unchanged." }
+{ { $link op-zero } " sets the stencil buffer value to zero." }
+{ { $link op-replace } " sets the stencil buffer value to the reference " { $snippet "value" } "." }
+{ { $link op-invert } " bitwise NOTs the stencil buffer value." }
+{ { $link op-inc-sat } " adds one to the stencil buffer value, leaving it unchanged if it is already the maximum storable value." }
+{ { $link op-dec-sat } " subtracts one from the stencil buffer value, leaving it unchanged if it is already zero." }
+{ { $link op-inc-wrap } " adds one to the stencil buffer value, wrapping the value to zero if it was the maximum storable value." }
+{ { $link op-dec-wrap } " subtracts one from the stencil buffer value, wrapping the value to the maximum storable value if it was zero." }
+} } ;
+
+HELP: stencil-state
+{ $class-description "The " { $snippet "stencil-state" } " controls how incoming fragments interact with the stencil buffer. The " { $snippet "front-mode" } " and " { $snippet "back-mode" } " slots are both " { $link stencil-mode } " tuples that define the stencil buffer interaction for front- and back-facing triangle fragments, respectively. If both slots are " { $link f } ", stencil testing is disabled." } ;
+
+HELP: triangle-cull
+{ $class-description "The " { $snippet "cull" } " slot of the " { $link triangle-cull-state } " determines which triangle faces are culled, if any."
+{ $list
+{ { $link cull-all } " culls all triangles." }
+{ { $link cull-front } " culls front-facing triangles." }
+{ { $link cull-back } " culls back-facing triangles." }
+} } ;
+
+HELP: triangle-cull-state
+{ $class-description "The " { $snippet "triangle-cull-state" } " controls what faces of triangles are rasterized."
+{ $list
+{ "The " { $snippet "front-face" } " slot determines which vertex winding order is considered the front face of a triangle: " { $link face-ccw } " or " { $link face-cw } "." }
+{ "The " { $snippet "cull" } " slot determines which triangle faces are discarded: " { $link cull-front } ", " { $link cull-back } ", " { $link cull-all } ", or " { $link f } " to disable triangle culling." }
+} } ;
+
+HELP: triangle-face
+{ $class-description "A " { $snippet "triangle-face" } " value names a vertex winding order for triangles."
+{ $list
+{ { $link face-ccw } " indicates counterclockwise winding." }
+{ { $link face-cw } " indicates clockwise winding." }
+} } ;
+
+HELP: triangle-fill
+{ $class-description "This " { $link triangle-mode } " fills the entire surface of triangles." } ;
+
+HELP: triangle-lines
+{ $class-description "This " { $link triangle-mode } " renders lines across the edges of triangles." } ;
+
+HELP: triangle-mode
+{ $class-description "The " { $snippet "triangle-mode" } " is set as part of the " { $link triangle-state } " to determine how triangles are rendered."
+{ $list
+{ { $link triangle-points } " renders the vertices of triangles as if they were points." }
+{ { $link triangle-lines } " renders lines across the edges of triangles." }
+{ { $link triangle-fill } ", the default, fills the entire surface of triangles." }
+} } ;
+
+HELP: triangle-points
+{ $class-description "This " { $link triangle-mode } " renders the vertices of triangles as if they were points." } ;
+
+HELP: triangle-state
+{ $class-description "The " { $snippet "triangle-state" } " controls how triangles are rasterized."
+{ $list
+{ "The " { $snippet "front-mode" } " and " { $snippet "back-mode" } " slots determine how a front- or back-facing triangle is rendered."
+ { $list
+ { { $link triangle-points } " renders the vertices of triangles as if they were points." }
+ { { $link triangle-lines } " renders lines across the edges of triangles." }
+ { { $link triangle-fill } ", the default, fills the entire surface of triangles." }
+ }
+}
+{ "The " { $snippet "antialias?" } " slot contains a " { $link boolean } " value that decides whether the edges of triangles should be smoothed." }
+} } ;
+
+HELP: viewport-state
+{ $class-description "The " { $snippet "viewport-state" } " controls the rectangular region of the framebuffer to which window-space coordinates are mapped. Window-space vertices are mapped from the rectangle <-1.0, -1.0><1.0, 1.0> to the rectangular region specified by the " { $snippet "rect" } " slot." } ;
+
+ARTICLE: "gpu.state" "GPU state"
+"The " { $vocab-link "gpu.state" } " vocabulary provides words for querying and setting GPU state."
+{ $subsection set-gpu-state }
+"The following state tuples are available:"
+{ $subsection viewport-state }
+{ $subsection scissor-state }
+{ $subsection multisample-state }
+{ $subsection stencil-state }
+{ $subsection depth-range-state }
+{ $subsection depth-state }
+{ $subsection blend-state }
+{ $subsection mask-state }
+{ $subsection triangle-cull-state }
+{ $subsection triangle-state }
+{ $subsection point-state }
+{ $subsection line-state } ;
+
+ABOUT: "gpu.state"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien.c-types arrays byte-arrays combinators gpu
+kernel literals math math.rectangles opengl opengl.gl sequences
+variants specialized-arrays.int specialized-arrays.float ;
+IN: gpu.state
+
+UNION: ?rect rect POSTPONE: f ;
+UNION: ?float float POSTPONE: f ;
+
+TUPLE: viewport-state
+ { rect rect read-only } ;
+C: <viewport-state> viewport-state
+
+TUPLE: scissor-state
+ { rect ?rect read-only } ;
+C: <scissor-state> scissor-state
+
+TUPLE: multisample-state
+ { multisample? boolean read-only }
+ { sample-alpha-to-coverage? boolean read-only }
+ { sample-alpha-to-one? boolean read-only }
+ { sample-coverage ?float read-only }
+ { invert-sample-coverage? boolean read-only } ;
+C: <multisample-state> multisample-state
+
+VARIANT: comparison
+ cmp-never cmp-always
+ cmp-less cmp-less-equal cmp-equal
+ cmp-greater-equal cmp-greater cmp-not-equal ;
+VARIANT: stencil-op
+ op-keep op-zero
+ op-replace op-invert
+ op-inc-sat op-dec-sat
+ op-inc-wrap op-dec-wrap ;
+
+UNION: ?comparison comparison POSTPONE: f ;
+
+TUPLE: stencil-mode
+ { value integer initial: 0 read-only }
+ { mask integer initial: HEX: FFFFFFFF read-only }
+ { comparison comparison initial: cmp-always read-only }
+ { stencil-fail-op stencil-op initial: op-keep read-only }
+ { depth-fail-op stencil-op initial: op-keep read-only }
+ { depth-pass-op stencil-op initial: op-keep read-only } ;
+C: <stencil-mode> stencil-mode
+
+UNION: ?stencil-mode stencil-mode POSTPONE: f ;
+
+TUPLE: stencil-state
+ { front-mode ?stencil-mode initial: f read-only }
+ { back-mode ?stencil-mode initial: f read-only } ;
+C: <stencil-state> stencil-state
+
+TUPLE: depth-range-state
+ { near float initial: 0.0 read-only }
+ { far float initial: 1.0 read-only } ;
+C: <depth-range-state> depth-range-state
+
+TUPLE: depth-state
+ { comparison ?comparison initial: f read-only } ;
+C: <depth-state> depth-state
+
+VARIANT: blend-equation
+ eq-add eq-subtract eq-reverse-subtract eq-min eq-max ;
+VARIANT: blend-function
+ func-zero func-one
+ func-source func-one-minus-source
+ func-dest func-one-minus-dest
+ func-constant func-one-minus-constant
+ func-source-alpha func-one-minus-source-alpha
+ func-dest-alpha func-one-minus-dest-alpha
+ func-constant-alpha func-one-minus-constant-alpha ;
+
+VARIANT: source-only-blend-function
+ func-source-alpha-saturate ;
+
+UNION: source-blend-function blend-function source-only-blend-function ;
+
+TUPLE: blend-mode
+ { equation blend-equation initial: eq-add read-only }
+ { source-function source-blend-function initial: func-source-alpha read-only }
+ { dest-function blend-function initial: func-one-minus-source-alpha read-only } ;
+C: <blend-mode> blend-mode
+
+UNION: ?blend-mode blend-mode POSTPONE: f ;
+
+TUPLE: blend-state
+ { constant-color sequence initial: f read-only }
+ { rgb-mode ?blend-mode read-only }
+ { alpha-mode ?blend-mode read-only } ;
+C: <blend-state> blend-state
+
+TUPLE: mask-state
+ { color sequence initial: { t t t t } read-only }
+ { depth boolean initial: t read-only }
+ { stencil-front integer initial: HEX: FFFFFFFF read-only }
+ { stencil-back integer initial: HEX: FFFFFFFF read-only } ;
+C: <mask-state> mask-state
+
+VARIANT: triangle-face
+ face-ccw face-cw ;
+VARIANT: triangle-cull
+ cull-front cull-back cull-all ;
+VARIANT: triangle-mode
+ triangle-points triangle-lines triangle-fill ;
+
+UNION: ?triangle-cull triangle-cull POSTPONE: f ;
+
+TUPLE: triangle-cull-state
+ { front-face triangle-face initial: face-ccw read-only }
+ { cull ?triangle-cull initial: f read-only } ;
+C: <triangle-cull-state> triangle-cull-state
+
+TUPLE: triangle-state
+ { front-mode triangle-mode initial: triangle-fill read-only }
+ { back-mode triangle-mode initial: triangle-fill read-only }
+ { antialias? boolean initial: f read-only } ;
+C: <triangle-state> triangle-state
+
+VARIANT: point-sprite-origin
+ origin-upper-left origin-lower-left ;
+
+TUPLE: point-state
+ { size ?float initial: 1.0 read-only }
+ { sprite-origin point-sprite-origin initial: origin-upper-left read-only }
+ { fade-threshold float initial: 1.0 read-only } ;
+C: <point-state> point-state
+
+TUPLE: line-state
+ { width float initial: 1.0 read-only }
+ { antialias? boolean initial: f read-only } ;
+C: <line-state> line-state
+
+UNION: gpu-state
+ viewport-state
+ triangle-cull-state
+ triangle-state
+ point-state
+ line-state
+ scissor-state
+ multisample-state
+ stencil-state
+ depth-range-state
+ depth-state
+ blend-state
+ mask-state ;
+
+<PRIVATE
+
+: gl-triangle-face ( triangle-face -- face )
+ {
+ { face-ccw [ GL_CCW ] }
+ { face-cw [ GL_CW ] }
+ } case ;
+
+: gl-triangle-face> ( triangle-face -- face )
+ {
+ { $ GL_CCW [ face-ccw ] }
+ { $ GL_CW [ face-cw ] }
+ } case ;
+
+: gl-triangle-cull ( triangle-cull -- cull )
+ {
+ { cull-front [ GL_FRONT ] }
+ { cull-back [ GL_BACK ] }
+ { cull-all [ GL_FRONT_AND_BACK ] }
+ } case ;
+
+: gl-triangle-cull> ( triangle-cull -- cull )
+ {
+ { $ GL_FRONT [ cull-front ] }
+ { $ GL_BACK [ cull-back ] }
+ { $ GL_FRONT_AND_BACK [ cull-all ] }
+ } case ;
+
+: gl-triangle-mode ( triangle-mode -- mode )
+ {
+ { triangle-points [ GL_POINT ] }
+ { triangle-lines [ GL_LINE ] }
+ { triangle-fill [ GL_FILL ] }
+ } case ;
+
+: gl-triangle-mode> ( triangle-mode -- mode )
+ {
+ { $ GL_POINT [ triangle-points ] }
+ { $ GL_LINE [ triangle-lines ] }
+ { $ GL_FILL [ triangle-fill ] }
+ } case ;
+
+: gl-point-sprite-origin ( point-sprite-origin -- sprite-origin )
+ {
+ { origin-upper-left [ GL_UPPER_LEFT ] }
+ { origin-lower-left [ GL_LOWER_LEFT ] }
+ } case ;
+
+: gl-point-sprite-origin> ( point-sprite-origin -- sprite-origin )
+ {
+ { $ GL_UPPER_LEFT [ origin-upper-left ] }
+ { $ GL_LOWER_LEFT [ origin-lower-left ] }
+ } case ;
+
+: gl-comparison ( comparison -- comparison )
+ {
+ { cmp-never [ GL_NEVER ] }
+ { cmp-always [ GL_ALWAYS ] }
+ { cmp-less [ GL_LESS ] }
+ { cmp-less-equal [ GL_LEQUAL ] }
+ { cmp-equal [ GL_EQUAL ] }
+ { cmp-greater-equal [ GL_GEQUAL ] }
+ { cmp-greater [ GL_GREATER ] }
+ { cmp-not-equal [ GL_NOTEQUAL ] }
+ } case ;
+
+: gl-comparison> ( comparison -- comparison )
+ {
+ { $ GL_NEVER [ cmp-never ] }
+ { $ GL_ALWAYS [ cmp-always ] }
+ { $ GL_LESS [ cmp-less ] }
+ { $ GL_LEQUAL [ cmp-less-equal ] }
+ { $ GL_EQUAL [ cmp-equal ] }
+ { $ GL_GEQUAL [ cmp-greater-equal ] }
+ { $ GL_GREATER [ cmp-greater ] }
+ { $ GL_NOTEQUAL [ cmp-not-equal ] }
+ } case ;
+
+: gl-stencil-op ( stencil-op -- op )
+ {
+ { op-keep [ GL_KEEP ] }
+ { op-zero [ GL_ZERO ] }
+ { op-replace [ GL_REPLACE ] }
+ { op-invert [ GL_INVERT ] }
+ { op-inc-sat [ GL_INCR ] }
+ { op-dec-sat [ GL_DECR ] }
+ { op-inc-wrap [ GL_INCR_WRAP ] }
+ { op-dec-wrap [ GL_DECR_WRAP ] }
+ } case ;
+
+: gl-stencil-op> ( op -- op )
+ {
+ { $ GL_KEEP [ op-keep ] }
+ { $ GL_ZERO [ op-zero ] }
+ { $ GL_REPLACE [ op-replace ] }
+ { $ GL_INVERT [ op-invert ] }
+ { $ GL_INCR [ op-inc-sat ] }
+ { $ GL_DECR [ op-dec-sat ] }
+ { $ GL_INCR_WRAP [ op-inc-wrap ] }
+ { $ GL_DECR_WRAP [ op-dec-wrap ] }
+ } case ;
+
+: (set-stencil-mode) ( gl-face stencil-mode -- )
+ {
+ [ [ comparison>> gl-comparison ] [ value>> ] [ mask>> ] tri glStencilFuncSeparate ]
+ [
+ [ stencil-fail-op>> ] [ depth-fail-op>> ] [ depth-pass-op>> ] tri
+ [ gl-stencil-op ] tri@ glStencilOpSeparate
+ ]
+ } 2cleave ;
+
+: gl-blend-equation ( blend-equation -- blend-equation )
+ {
+ { eq-add [ GL_FUNC_ADD ] }
+ { eq-subtract [ GL_FUNC_SUBTRACT ] }
+ { eq-reverse-subtract [ GL_FUNC_REVERSE_SUBTRACT ] }
+ { eq-min [ GL_MIN ] }
+ { eq-max [ GL_MAX ] }
+ } case ;
+
+: gl-blend-equation> ( blend-equation -- blend-equation )
+ {
+ { $ GL_FUNC_ADD [ eq-add ] }
+ { $ GL_FUNC_SUBTRACT [ eq-subtract ] }
+ { $ GL_FUNC_REVERSE_SUBTRACT [ eq-reverse-subtract ] }
+ { $ GL_MIN [ eq-min ] }
+ { $ GL_MAX [ eq-max ] }
+ } case ;
+
+: gl-blend-function ( blend-function -- blend-function )
+ {
+ { func-zero [ GL_ZERO ] }
+ { func-one [ GL_ONE ] }
+ { func-source [ GL_SRC_COLOR ] }
+ { func-one-minus-source [ GL_ONE_MINUS_SRC_COLOR ] }
+ { func-dest [ GL_DST_COLOR ] }
+ { func-one-minus-dest [ GL_ONE_MINUS_DST_COLOR ] }
+ { func-constant [ GL_CONSTANT_COLOR ] }
+ { func-one-minus-constant [ GL_ONE_MINUS_CONSTANT_COLOR ] }
+ { func-source-alpha [ GL_SRC_ALPHA ] }
+ { func-one-minus-source-alpha [ GL_ONE_MINUS_SRC_ALPHA ] }
+ { func-dest-alpha [ GL_DST_ALPHA ] }
+ { func-one-minus-dest-alpha [ GL_ONE_MINUS_DST_ALPHA ] }
+ { func-constant-alpha [ GL_CONSTANT_ALPHA ] }
+ { func-one-minus-constant-alpha [ GL_ONE_MINUS_CONSTANT_ALPHA ] }
+ { func-source-alpha-saturate [ GL_SRC_ALPHA_SATURATE ] }
+ } case ;
+
+: gl-blend-function> ( blend-function -- blend-function )
+ {
+ { $ GL_ZERO [ func-zero ] }
+ { $ GL_ONE [ func-one ] }
+ { $ GL_SRC_COLOR [ func-source ] }
+ { $ GL_ONE_MINUS_SRC_COLOR [ func-one-minus-source ] }
+ { $ GL_DST_COLOR [ func-dest ] }
+ { $ GL_ONE_MINUS_DST_COLOR [ func-one-minus-dest ] }
+ { $ GL_CONSTANT_COLOR [ func-constant ] }
+ { $ GL_ONE_MINUS_CONSTANT_COLOR [ func-one-minus-constant ] }
+ { $ GL_SRC_ALPHA [ func-source-alpha ] }
+ { $ GL_ONE_MINUS_SRC_ALPHA [ func-one-minus-source-alpha ] }
+ { $ GL_DST_ALPHA [ func-dest-alpha ] }
+ { $ GL_ONE_MINUS_DST_ALPHA [ func-one-minus-dest-alpha ] }
+ { $ GL_CONSTANT_ALPHA [ func-constant-alpha ] }
+ { $ GL_ONE_MINUS_CONSTANT_ALPHA [ func-one-minus-constant-alpha ] }
+ { $ GL_SRC_ALPHA_SATURATE [ func-source-alpha-saturate ] }
+ } case ;
+
+PRIVATE>
+
+GENERIC: set-gpu-state* ( state -- )
+
+M: viewport-state set-gpu-state*
+ rect>> [ loc>> first2 ] [ dim>> first2 ] bi glViewport ;
+
+M: triangle-cull-state set-gpu-state*
+ {
+ [ front-face>> gl-triangle-face glFrontFace ]
+ [ GL_CULL_FACE swap cull>> [ gl-triangle-cull glCullFace glEnable ] [ glDisable ] if* ]
+ } cleave ;
+
+M: triangle-state set-gpu-state*
+ {
+ [ GL_FRONT swap front-mode>> gl-triangle-mode glPolygonMode ]
+ [ GL_BACK swap back-mode>> gl-triangle-mode glPolygonMode ]
+ [ GL_POLYGON_SMOOTH swap antialias?>> [ glEnable ] [ glDisable ] if ]
+ } cleave ;
+
+M: point-state set-gpu-state*
+ {
+ [ GL_VERTEX_PROGRAM_POINT_SIZE swap size>> [ glPointSize glDisable ] [ glEnable ] if* ]
+ [ GL_POINT_SPRITE_COORD_ORIGIN swap sprite-origin>> gl-point-sprite-origin glPointParameteri ]
+ [ GL_POINT_FADE_THRESHOLD_SIZE swap fade-threshold>> glPointParameterf ]
+ } cleave ;
+
+M: line-state set-gpu-state*
+ {
+ [ width>> glLineWidth ]
+ [ GL_LINE_SMOOTH swap antialias?>> [ glEnable ] [ glDisable ] if ]
+ } cleave ;
+
+M: scissor-state set-gpu-state*
+ GL_SCISSOR_TEST swap rect>>
+ [ [ loc>> first2 ] [ dim>> first2 ] bi glViewport glEnable ]
+ [ glDisable ] if* ;
+
+M: multisample-state set-gpu-state*
+ dup multisample?>> [
+ GL_MULTISAMPLE glEnable
+ {
+ [ GL_SAMPLE_ALPHA_TO_COVERAGE swap sample-alpha-to-coverage?>>
+ [ glEnable ] [ glDisable ] if
+ ]
+ [ GL_SAMPLE_ALPHA_TO_ONE swap sample-alpha-to-one?>>
+ [ glEnable ] [ glDisable ] if
+ ]
+ [ GL_SAMPLE_COVERAGE swap [ invert-sample-coverage?>> >c-bool ] [ sample-coverage>> ] bi
+ [ swap glSampleCoverage glEnable ] [ drop glDisable ] if*
+ ]
+ } cleave
+ ] [ drop GL_MULTISAMPLE glDisable ] if ;
+
+M: stencil-state set-gpu-state*
+ [ ] [ front-mode>> ] [ back-mode>> ] tri or
+ [
+ GL_STENCIL_TEST glEnable
+ [ front-mode>> GL_FRONT swap (set-stencil-mode) ]
+ [ back-mode>> GL_BACK swap (set-stencil-mode) ] bi
+ ] [ drop GL_STENCIL_TEST glDisable ] if ;
+
+M: depth-range-state set-gpu-state*
+ [ near>> ] [ far>> ] bi glDepthRange ;
+
+M: depth-state set-gpu-state*
+ GL_DEPTH_TEST swap comparison>> [ gl-comparison glDepthFunc glEnable ] [ glDisable ] if* ;
+
+M: blend-state set-gpu-state*
+ [ ] [ rgb-mode>> ] [ alpha-mode>> ] tri or
+ [
+ GL_BLEND glEnable
+ [ constant-color>> [ first4 glBlendColor ] when* ]
+ [
+ [ rgb-mode>> ] [ alpha-mode>> ] bi {
+ [ [ equation>> gl-blend-equation ] bi@ glBlendEquationSeparate ]
+ [
+ [
+ [ source-function>> gl-blend-function ]
+ [ dest-function>> gl-blend-function ] bi
+ ] bi@ glBlendFuncSeparate
+ ]
+ } 2cleave
+ ] bi
+ ] [ drop GL_BLEND glDisable ] if ;
+
+M: mask-state set-gpu-state*
+ {
+ [ color>> [ >c-bool ] map first4 glColorMask ]
+ [ depth>> >c-bool glDepthMask ]
+ [ GL_FRONT swap stencil-front>> glStencilMaskSeparate ]
+ [ GL_BACK swap stencil-back>> glStencilMaskSeparate ]
+ } cleave ;
+
+: set-gpu-state ( states -- )
+ dup sequence?
+ [ [ set-gpu-state* ] each ]
+ [ set-gpu-state* ] if ; inline
+
+<PRIVATE
+
+: get-gl-bool ( enum -- value )
+ 0 <uchar> [ glGetBooleanv ] keep *uchar c-bool> ;
+: get-gl-int ( enum -- value )
+ 0 <int> [ glGetIntegerv ] keep *int ;
+: get-gl-float ( enum -- value )
+ 0 <float> [ glGetFloatv ] keep *float ;
+
+: get-gl-bools ( enum count -- value )
+ <byte-array> [ glGetBooleanv ] keep [ c-bool> ] { } map-as ;
+: get-gl-ints ( enum count -- value )
+ <int-array> [ glGetIntegerv ] keep ;
+: get-gl-floats ( enum count -- value )
+ <float-array> [ glGetFloatv ] keep ;
+
+: get-gl-rect ( enum -- value )
+ 4 get-gl-ints first4 [ 2array ] 2bi@ <rect> ;
+
+: gl-enabled? ( enum -- ? )
+ glIsEnabled c-bool> ;
+
+PRIVATE>
+
+: get-viewport-state ( -- viewport-state )
+ GL_VIEWPORT get-gl-rect <viewport-state> ;
+
+: get-scissor-state ( -- scissor-state )
+ GL_SCISSOR_TEST get-gl-bool
+ [ GL_SCISSOR_BOX get-gl-rect ] [ f ] if
+ <scissor-state> ;
+
+: get-multisample-state ( -- multisample-state )
+ GL_MULTISAMPLE gl-enabled?
+ GL_SAMPLE_ALPHA_TO_COVERAGE gl-enabled?
+ GL_SAMPLE_ALPHA_TO_ONE gl-enabled?
+ GL_SAMPLE_COVERAGE gl-enabled? [
+ GL_SAMPLE_COVERAGE_VALUE get-gl-float
+ GL_SAMPLE_COVERAGE_INVERT get-gl-bool
+ ] [ f f ] if
+ <multisample-state> ;
+
+: get-stencil-state ( -- stencil-state )
+ GL_STENCIL_TEST gl-enabled? [
+ GL_STENCIL_REF get-gl-int
+ GL_STENCIL_VALUE_MASK get-gl-int
+ GL_STENCIL_FUNC get-gl-int gl-comparison>
+ GL_STENCIL_FAIL get-gl-int gl-stencil-op>
+ GL_STENCIL_PASS_DEPTH_FAIL get-gl-int gl-stencil-op>
+ GL_STENCIL_PASS_DEPTH_PASS get-gl-int gl-stencil-op>
+ <stencil-mode>
+
+ GL_STENCIL_BACK_REF get-gl-int
+ GL_STENCIL_BACK_VALUE_MASK get-gl-int
+ GL_STENCIL_BACK_FUNC get-gl-int gl-comparison>
+ GL_STENCIL_BACK_FAIL get-gl-int gl-stencil-op>
+ GL_STENCIL_BACK_PASS_DEPTH_FAIL get-gl-int gl-stencil-op>
+ GL_STENCIL_BACK_PASS_DEPTH_PASS get-gl-int gl-stencil-op>
+ <stencil-mode>
+ ] [ f f ] if
+ <stencil-state> ;
+
+: get-depth-range-state ( -- depth-range-state )
+ GL_DEPTH_RANGE 2 get-gl-floats first2 <depth-range-state> ;
+
+: get-depth-state ( -- depth-state )
+ GL_DEPTH_TEST gl-enabled?
+ [ GL_DEPTH_FUNC get-gl-int gl-comparison> ] [ f ] if
+ <depth-state> ;
+
+: get-blend-state ( -- blend-state )
+ GL_BLEND gl-enabled? [
+ GL_BLEND_COLOR 4 get-gl-floats
+
+ GL_BLEND_EQUATION_RGB get-gl-int gl-blend-equation>
+ GL_BLEND_SRC_RGB get-gl-int gl-blend-function>
+ GL_BLEND_DST_RGB get-gl-int gl-blend-function>
+ <blend-mode>
+
+ GL_BLEND_EQUATION_ALPHA get-gl-int gl-blend-equation>
+ GL_BLEND_SRC_ALPHA get-gl-int gl-blend-function>
+ GL_BLEND_DST_ALPHA get-gl-int gl-blend-function>
+ <blend-mode>
+ ] [ f f f ] if
+ <blend-state> ;
+
+: get-mask-state ( -- mask-state )
+ GL_COLOR_WRITEMASK 4 get-gl-bools
+ GL_DEPTH_WRITEMASK get-gl-bool
+ GL_STENCIL_WRITEMASK get-gl-int
+ GL_STENCIL_BACK_WRITEMASK get-gl-int
+ <mask-state> ;
+
+: get-triangle-cull-state ( -- triangle-cull-state )
+ GL_FRONT_FACE get-gl-int gl-triangle-face>
+ GL_CULL_FACE gl-enabled?
+ [ GL_CULL_FACE_MODE get-gl-int gl-triangle-cull> ]
+ [ f ] if
+ <triangle-cull-state> ;
+
+: get-triangle-state ( -- triangle-state )
+ GL_POLYGON_MODE 2 get-gl-ints
+ first2 [ gl-triangle-mode> ] bi@
+ GL_POLYGON_SMOOTH gl-enabled?
+ <triangle-state> ;
+
+: get-point-state ( -- point-state )
+ GL_VERTEX_PROGRAM_POINT_SIZE gl-enabled?
+ [ f ] [ GL_POINT_SIZE get-gl-float ] if
+ GL_POINT_SPRITE_COORD_ORIGIN get-gl-int gl-point-sprite-origin>
+ GL_POINT_FADE_THRESHOLD_SIZE get-gl-float
+ <point-state> ;
+
+: get-line-state ( -- line-state )
+ GL_LINE_WIDTH get-gl-float
+ GL_LINE_SMOOTH gl-enabled?
+ <line-state> ;
--- /dev/null
+GPU state manipulation
--- /dev/null
+High-level OpenGL-based GPU resource management and rendering library
--- /dev/null
+Multidimensional image data in GPU memory
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: alien byte-arrays classes gpu.buffers help.markup help.syntax
+images kernel math ;
+IN: gpu.textures
+
+HELP: +X
+{ $class-description "This " { $link cube-map-axis } " references the positive X face of a " { $link texture-cube-map } "." } ;
+
+HELP: +Y
+{ $class-description "This " { $link cube-map-axis } " references the positive Y face of a " { $link texture-cube-map } "." } ;
+
+HELP: +Z
+{ $class-description "This " { $link cube-map-axis } " references the positive Z face of a " { $link texture-cube-map } "." } ;
+
+HELP: -X
+{ $class-description "This " { $link cube-map-axis } " references the negative X face of a " { $link texture-cube-map } "." } ;
+
+HELP: -Y
+{ $class-description "This " { $link cube-map-axis } " references the negative Y face of a " { $link texture-cube-map } "." } ;
+
+HELP: -Z
+{ $class-description "This " { $link cube-map-axis } " references the negative Z face of a " { $link texture-cube-map } "." } ;
+
+HELP: <cube-map-face>
+{ $values
+ { "texture" texture-cube-map } { "axis" cube-map-axis }
+ { "cube-map-face" cube-map-face }
+}
+{ $description "Constructs a new " { $link cube-map-face } " reference." } ;
+
+HELP: <texture-1d-array>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-1d-array }
+}
+{ $description "Creates a new one-dimensional array texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." }
+{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ;
+
+HELP: <texture-1d>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-1d }
+}
+{ $description "Creates a new one-dimensional texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } ;
+
+HELP: <texture-2d-array>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-2d-array }
+}
+{ $description "Creates a new two-dimensional array texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." }
+{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ;
+
+HELP: <texture-2d>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-2d }
+}
+{ $description "Creates a new two-dimensional texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } ;
+
+HELP: <texture-3d>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-3d }
+}
+{ $description "Creates a new three-dimensional texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } ;
+
+HELP: <texture-cube-map>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-cube-map }
+}
+{ $description "Creates a new cube map texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of each " { $link cube-map-face } " of the new texture." } ;
+
+HELP: <texture-data>
+{ $values
+ { "ptr" gpu-data-ptr } { "component-order" component-order } { "component-type" component-type }
+ { "texture-data" texture-data }
+}
+{ $description "Constructs a new " { $link texture-data } " tuple." }
+{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+HELP: <texture-rectangle>
+{ $values
+ { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters }
+ { "texture" texture-rectangle }
+}
+{ $description "Creates a new rectangle texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the texture." }
+{ $notes "Rectangle textures require OpenGL 3.1 or the " { $snippet "GL_ARB_texture_rectangle" } " extension." } ;
+
+HELP: allocate-texture
+{ $values
+ { "tdt" texture-data-target } { "level" integer } { "dim" "an " { $link integer } " or sequence of " { $link integer } "s" } { "data" { $maybe texture-data } }
+}
+{ $description "Allocates a new block of GPU memory for the " { $snippet "level" } "th level of detail of a " { $link texture-data-target } ". If " { $snippet "data" } " is not " { $link f } ", the new data is initialized from the given " { $link texture-data } " object; otherwise, the new image is left uninitialized." }
+{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+HELP: allocate-texture-image
+{ $values
+ { "tdt" texture-data-target } { "level" integer } { "image" image }
+}
+{ $description "Allocates a new block of GPU memory for the " { $snippet "level" } "th level of detail of a " { $link texture-data-target } " and initializes it with the contents of an " { $link image } "." } ;
+
+{ allocate-texture allocate-texture-image } related-words
+
+HELP: clamp-texcoord-to-border
+{ $class-description "This " { $link texture-wrap } " value clamps texture coordinates to a texture's border." } ;
+
+HELP: clamp-texcoord-to-edge
+{ $class-description "This " { $link texture-wrap } " value clamps texture coordinates to a texture image's edge." } ;
+
+HELP: cube-map-axis
+{ $class-description "Objects of this class are stored in the " { $snippet "axis" } " slot of a " { $link cube-map-face } " to choose the referenced face: " { $link +X } ", " { $link +Y } ", " { $link +Z } ", " { $link -X } ", " { $link -Y } ", or " { $link -Z } "."
+} ;
+
+HELP: cube-map-face
+{ $class-description "A " { $snippet "cube-map-face" } " tuple references a single face of a " { $link texture-cube-map } " object for use with " { $link allocate-texture } ", " { $link update-texture } ", or " { $link read-texture } "."
+{ $list
+{ "The " { $snippet "texture" } " slot indicates the cube map texture being referenced." }
+{ "The " { $snippet "axis" } " slot indicates which face to reference: " { $link +X } ", " { $link +Y } ", " { $link +Z } ", " { $link -X } ", " { $link -Y } ", or " { $link -Z } "." }
+} } ;
+
+HELP: filter-linear
+{ $class-description "This " { $link texture-filter } " value selects linear filtering between pixel samples." } ;
+
+HELP: filter-nearest
+{ $class-description "This " { $link texture-filter } " value selects nearest-neighbor sampling." } ;
+
+HELP: generate-mipmaps
+{ $values
+ { "texture" texture }
+}
+{ $description "Replaces the image data for all levels of detail of " { $snippet "texture" } " below the highest level with images automatically generated from the highest level of detail image." }
+{ $notes "This word requires OpenGL 3.0 or one of the " { $snippet "GL_EXT_framebuffer_object" } " or " { $snippet "GL_ARB_framebuffer_object" } " extensions." } ;
+
+HELP: image>texture-data
+{ $values
+ { "image" image }
+ { "dim" "a sequence of " { $link integer } "s" } { "texture-data" texture-data }
+}
+{ $description "Constructs a " { $link texture-data } " tuple referencing the pixel data from an " { $link image } "." } ;
+
+HELP: read-texture
+{ $values
+ { "tdt" texture-data-target } { "level" integer }
+ { "byte-array" byte-array }
+}
+{ $description "Reads the entire image for the " { $snippet "level" } "th level of detail of a texture into a new " { $link byte-array } ". The format of the data in the byte array is determined by the " { $link component-order } " and " { $link component-type } " of the texture." } ;
+
+HELP: read-texture-image
+{ $values
+ { "tdt" texture-data-target } { "level" integer }
+ { "image" image }
+}
+{ $description "Reads the entire image for the " { $snippet "level" } "th level of detail of a texture into a new " { $link image } ". The format of the image is determined by the " { $link component-order } " and " { $link component-type } " of the texture." } ;
+
+HELP: read-texture-to
+{ $values
+ { "tdt" texture-data-target } { "level" integer } { "gpu-data-ptr" gpu-data-ptr }
+}
+{ $description "Reads the entire image for the " { $snippet "level" } "th level of detail of a texture into the CPU or GPU memory referenced by " { $link gpu-data-ptr } ". The format of the data in the byte array is determined by the " { $link component-order } " and " { $link component-type } " of the texture." }
+{ $notes "Reading texture data into a GPU " { $snippet "buffer-ptr" } " requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+{ read-texture read-texture-image read-texture-to } related-words
+
+HELP: repeat-texcoord
+{ $class-description "This " { $link texture-wrap } " value causes the texture image to be repeated through texture coordinate space." } ;
+
+HELP: repeat-texcoord-mirrored
+{ $class-description "This " { $link texture-wrap } " value causes the texture image to be repeated through texture coordinate space, mirroring the image on every repetition." } ;
+
+HELP: set-texture-parameters
+{ $values
+ { "texture" texture } { "parameters" texture-parameters }
+}
+{ $description "Changes the " { $link texture-parameters } " of a " { $link texture } "." } ;
+
+HELP: texture
+{ $class-description "Textures are typed, multidimensional arrays of GPU memory used for storing image data, lookup tables, and other kinds of multidimensional data for use with shader programs. They come in different types depending on dimensionality and intended usage:"
+{ $subsection texture-1d }
+{ $subsection texture-2d }
+{ $subsection texture-3d }
+{ $subsection texture-cube-map }
+{ $subsection texture-rectangle }
+{ $subsection texture-1d-array }
+{ $subsection texture-2d-array }
+"Textures are constructed using the corresponding " { $snippet "<constructor word>" } " for their type. The constructor sets the texture's " { $link component-order } ", " { $link component-type } ", and " { $link texture-parameters } ". Once created, memory for a texture can be allocated with " { $link allocate-texture } ", updated with " { $link update-texture } ", or retrieved with " { $link read-texture } "." } ;
+
+HELP: texture-1d
+{ $class-description "A one-dimensional " { $link texture } " object. Textures of this type are dimensioned by single integers in calls to " { $link allocate-texture } " and " { $link update-texture } "." } ;
+
+{ texture-1d <texture-1d> } related-words
+
+HELP: texture-1d-array
+{ $class-description "A one-dimensional array " { $link texture } " object. Textures of this type are dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". A 1D array texture is distinct from a 2D texture (" { $link texture-2d } ") in that each row of the texture is independent; texture values are not filtered between rows, and lower levels of detail retain the same height, only losing detail in the width direction." }
+{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ;
+
+{ texture-1d-array <texture-1d-array> } related-words
+
+HELP: texture-2d
+{ $class-description "A two-dimensional " { $link texture } " object. Textures of this type are dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } "." } ;
+
+{ texture-2d <texture-2d> } related-words
+
+HELP: texture-2d-array
+{ $class-description "A two-dimensional array " { $link texture } " object. Textures of this type are dimensioned by sequences of three integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". A 2D array texture is distinct from a 3D texture (" { $link texture-3d } ") in that each plane of the texture is independent; texture values are not filtered between planes, and lower levels of detail retain the same depth, only losing detail in the width and height directions." }
+{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ;
+
+{ texture-2d-array <texture-2d-array> } related-words
+
+HELP: texture-3d
+{ $class-description "A three-dimensional " { $link texture } " object. Textures of this type are dimensioned by sequences of three integers in calls to " { $link allocate-texture } " and " { $link update-texture } "." } ;
+
+{ texture-3d <texture-3d> } related-words
+
+HELP: texture-wrap
+{ $class-description "Values of this class are used in the " { $snippet "wrap" } " slot of a set of " { $link texture-parameters } " to specify how texture coordinates outside the 0.0 to 1.0 range should be mapped onto the texture image."
+{ $list
+{ { $link clamp-texcoord-to-edge } " clamps coordinates to the edge of the texture image." }
+{ { $link clamp-texcoord-to-border } " clamps coordinates to the border of the texture image." }
+{ { $link repeat-texcoord } " repeats the texture image." }
+{ { $link repeat-texcoord-mirrored } " repeats the texture image, mirroring it with each repetition." }
+} } ;
+
+HELP: texture-cube-map
+{ $class-description "A cube map " { $link texture } " object. Textures of this type comprise six two-dimensional image sets, which are independently referenced by " { $link cube-map-face } " objects and dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". When a cube map is sampled in shader code, the three-dimensional texture coordinates are projected onto the unit cube, and the cube face that is hit by the vector is used to select a face of the cube map texture." } ;
+
+{ texture-cube-map <texture-cube-map> } related-words
+
+HELP: texture-data
+{ $class-description { $snippet "texture-data" } " tuples are used to feed image data to " { $link allocate-texture } " and " { $link update-texture } "."
+{ $list
+{ "The " { $snippet "ptr" } " slot references either CPU memory (as a " { $link byte-array } " or " { $link alien } ") or a GPU " { $link buffer-ptr } " that contains the image data." }
+{ "The " { $snippet "component-order" } " and " { $snippet "component-type" } " slots determine the " { $link component-order } " and " { $link component-type } " of the referenced data." }
+} }
+{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+{ texture-data <texture-data> } related-words
+
+HELP: texture-data-size
+{ $values
+ { "tdt" texture-data-target } { "level" integer }
+ { "size" integer }
+}
+{ $description "Returns the size in bytes of the image data allocated for the " { $snippet "level" } "th level of detail of a " { $link texture-data-target } "." } ;
+
+HELP: texture-data-target
+{ $class-description "Most " { $link texture } " types can have image data assigned to themselves directly by " { $link allocate-texture } " and " { $link update-texture } "; however, " { $link texture-cube-map } " objects comprise six independent image sets, each of which must be referenced separately with a " { $link cube-map-face } " tuple when allocating or updating images. The " { $snippet "texture-data-target" } " class is a union of all " { $link texture } " classes (except " { $snippet "texture-cube-map" } ") and the " { $snippet "cube-map-face" } " class." } ;
+
+HELP: texture-dim
+{ $values
+ { "tdt" texture-data-target } { "level" integer }
+ { "dim" "an " { $link integer } " or sequence of integers" }
+}
+{ $description "Returns the dimensions of the memory allocated for the " { $snippet "level" } "th level of detail of the given " { $link texture-data-target } "." } ;
+
+HELP: texture-filter
+{ $class-description { $snippet "texture-filter" } " values are used in a " { $link texture-parameters } " tuple to determine how a texture should be sampled between pixels or between levels of detail. " { $link filter-linear } " selects linear filtering, while " { $link filter-nearest } " selects nearest-neighbor sampling." } ;
+
+HELP: texture-parameters
+{ $class-description "A " { $snippet "texture-parameters" } " tuple is supplied when constructing a " { $link texture } " to control the wrapping, filtering, and level-of-detail handling of the texture. These tuples have the following slots:"
+{ $list
+{ "The " { $snippet "wrap" } " slot determines how texture coordinates outside the 0.0 to 1.0 range are mapped to the texture image. The slot either contains a single " { $link texture-wrap } " value, which will apply to all three axes, or a sequence of up to three values, which will apply to the S, T, and R axes, respectively." }
+{ "The " { $snippet "min-filter" } " and " { $snippet "min-mipmap-filter" } " determine how the texture image is filtered when sampled below its highest level of detail, the former filtering between pixels within a level of detail and the latter filtering between levels of detail. A setting of " { $link filter-linear } " uses linear, bilinear, or trilinear filtering among the sampled pixels, while a setting of " { $link filter-nearest } " uses nearest-neighbor sampling. The " { $snippet "min-mipmap-filter" } " slot may additionally be set to " { $link f } " to disable mipmapping and only sample the highest level of detail." }
+{ "The " { $snippet "mag-filter" } " analogously determines how the texture image is filtered when sampled above its highest level of detail." }
+{ "The " { $snippet "min-lod" } " and " { $snippet "max-lod" } " slots contain integer values that will clamp the range of levels of detail that will be sampled from the texture." }
+{ "The " { $snippet "lod-bias" } " slot contains an integer value that will offset the levels of detail that would normally be sampled from the texture." }
+{ "The " { $snippet "base-level" } " slot contains an integer value that identifies the highest level of detail for the image, typically zero." }
+{ "The " { $snippet "max-level" } " slot contains an integer value that identifies the lowest level of detail for the image. This value will automatically be clamped to the maximum of the base-2 logarithms of the dimensions of the highest level of detail image." }
+} } ;
+
+{ texture-parameters set-texture-parameters } related-words
+
+HELP: texture-rectangle
+{ $class-description "A two-dimensional rectangle " { $link texture } " object. Textures of this type are dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". Rectangle textures differ from normal 2D textures (" { $link texture-2d } ") in that texture coordinates map directly to pixel coordinates when they are sampled from shader code, rather than being normalized into the 0.0 to 1.0 range as with other texture types. Also, rectangle textures do not support mipmapping or texture wrapping." }
+{ $notes "Rectangle textures require OpenGL 3.1 or the " { $snippet "GL_ARB_texture_rectangle" } " extension." } ;
+
+HELP: update-texture
+{ $values
+ { "tdt" texture-data-target } { "level" integer } { "loc" "an " { $link integer } " or sequence of integers" } { "dim" "an " { $link integer } " or sequence of integers" } { "data" texture-data }
+}
+{ $description "Updates the linear, rectangular, or cubic subregion of a " { $link texture-data-target } " bounded by " { $snippet "loc" } " and " { $snippet "dim" } " with new image data from a " { $link texture-data } " tuple." }
+{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ;
+
+HELP: update-texture-image
+{ $values
+ { "tdt" texture-data-target } { "level" integer } { "loc" "an " { $link integer } " or sequence of integers" } { "image" image }
+}
+{ $description "Updates the linear, rectangular, or cubic subregion of a " { $link texture-data-target } " bounded by " { $snippet "loc" } " and " { $snippet "dim" } " with new image data from an " { $link image } " object." } ;
+
+{ update-texture update-texture-image } related-words
+
+ARTICLE: "gpu.textures" "Texture objects"
+"The " { $vocab-link "gpu.textures" } " vocabulary provides words for creating, allocating, updating, and reading GPU texture objects."
+{ $subsection texture }
+{ $subsection allocate-texture }
+{ $subsection update-texture }
+{ $subsection read-texture }
+"Words are also provided to interface textures with the " { $vocab-link "images" } " library:"
+{ $subsection allocate-texture-image }
+{ $subsection update-texture-image }
+{ $subsection read-texture-image }
+;
+
+ABOUT: "gpu.textures"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien.c-types arrays byte-arrays combinators
+destructors fry gpu gpu.buffers images kernel locals math
+opengl opengl.gl opengl.textures sequences
+specialized-arrays.float ui.gadgets.worlds variants ;
+IN: gpu.textures
+
+TUPLE: texture < gpu-object
+ { component-order component-order read-only initial: RGBA }
+ { component-type component-type read-only initial: ubyte-components } ;
+
+TUPLE: texture-1d < texture ;
+TUPLE: texture-2d < texture ;
+TUPLE: texture-rectangle < texture ;
+TUPLE: texture-3d < texture ;
+TUPLE: texture-cube-map < texture ;
+
+TUPLE: texture-1d-array < texture ;
+TUPLE: texture-2d-array < texture ;
+
+VARIANT: cube-map-axis
+ -X -Y -Z +X +Y +Z ;
+
+TUPLE: cube-map-face
+ { texture texture-cube-map read-only }
+ { axis cube-map-axis read-only } ;
+C: <cube-map-face> cube-map-face
+
+UNION: texture-1d-data-target
+ texture-1d ;
+UNION: texture-2d-data-target
+ texture-2d texture-rectangle texture-1d-array cube-map-face ;
+UNION: texture-3d-data-target
+ texture-3d texture-2d-array ;
+UNION: texture-data-target
+ texture-1d-data-target texture-2d-data-target texture-3d-data-target ;
+
+M: texture dispose
+ [ [ delete-texture ] when* f ] change-handle drop ;
+
+TUPLE: texture-data
+ { ptr read-only }
+ { component-order component-order read-only initial: RGBA }
+ { component-type component-type read-only initial: ubyte-components } ;
+
+C: <texture-data> texture-data
+UNION: ?texture-data texture-data POSTPONE: f ;
+UNION: ?float-array float-array POSTPONE: f ;
+
+VARIANT: texture-wrap
+ clamp-texcoord-to-edge clamp-texcoord-to-border repeat-texcoord repeat-texcoord-mirrored ;
+VARIANT: texture-filter
+ filter-nearest filter-linear ;
+
+UNION: wrap-set texture-wrap sequence ;
+UNION: ?texture-filter texture-filter POSTPONE: f ;
+
+TUPLE: texture-parameters
+ { wrap wrap-set initial: { repeat-texcoord repeat-texcoord repeat-texcoord } }
+ { min-filter texture-filter initial: filter-nearest }
+ { min-mipmap-filter ?texture-filter initial: filter-linear }
+ { mag-filter texture-filter initial: filter-linear }
+ { min-lod integer initial: -1000 }
+ { max-lod integer initial: 1000 }
+ { lod-bias integer initial: 0 }
+ { base-level integer initial: 0 }
+ { max-level integer initial: 1000 } ;
+
+<PRIVATE
+
+GENERIC: texture-object ( texture-data-target -- texture )
+M: cube-map-face texture-object
+ texture>> ;
+M: texture texture-object
+ ;
+
+: gl-wrap ( wrap -- gl-wrap )
+ {
+ { clamp-texcoord-to-edge [ GL_CLAMP_TO_EDGE ] }
+ { clamp-texcoord-to-border [ GL_CLAMP_TO_BORDER ] }
+ { repeat-texcoord [ GL_REPEAT ] }
+ { repeat-texcoord-mirrored [ GL_MIRRORED_REPEAT ] }
+ } case ;
+
+: set-texture-gl-wrap ( target wraps -- )
+ dup sequence? [ 1array ] unless 3 over last pad-tail {
+ [ [ GL_TEXTURE_WRAP_S ] dip first gl-wrap glTexParameteri ]
+ [ [ GL_TEXTURE_WRAP_T ] dip second gl-wrap glTexParameteri ]
+ [ [ GL_TEXTURE_WRAP_R ] dip third gl-wrap glTexParameteri ]
+ } 2cleave ;
+
+: gl-mag-filter ( filter -- gl-filter )
+ {
+ { filter-nearest [ GL_NEAREST ] }
+ { filter-linear [ GL_LINEAR ] }
+ } case ;
+
+: gl-min-filter ( filter mipmap-filter -- gl-filter )
+ 2array {
+ { { filter-nearest f } [ GL_NEAREST ] }
+ { { filter-linear f } [ GL_LINEAR ] }
+ { { filter-nearest filter-nearest } [ GL_NEAREST_MIPMAP_NEAREST ] }
+ { { filter-linear filter-nearest } [ GL_LINEAR_MIPMAP_NEAREST ] }
+ { { filter-linear filter-linear } [ GL_LINEAR_MIPMAP_LINEAR ] }
+ { { filter-nearest filter-linear } [ GL_NEAREST_MIPMAP_LINEAR ] }
+ } case ;
+
+GENERIC: texture-gl-target ( texture -- target )
+GENERIC: texture-data-gl-target ( texture -- target )
+
+M: texture-1d texture-gl-target drop GL_TEXTURE_1D ;
+M: texture-2d texture-gl-target drop GL_TEXTURE_2D ;
+M: texture-rectangle texture-gl-target drop GL_TEXTURE_RECTANGLE ;
+M: texture-3d texture-gl-target drop GL_TEXTURE_3D ;
+M: texture-cube-map texture-gl-target drop GL_TEXTURE_CUBE_MAP ;
+M: texture-1d-array texture-gl-target drop GL_TEXTURE_1D_ARRAY ;
+M: texture-2d-array texture-gl-target drop GL_TEXTURE_2D_ARRAY ;
+
+M: texture-1d texture-data-gl-target drop GL_TEXTURE_1D ;
+M: texture-2d texture-data-gl-target drop GL_TEXTURE_2D ;
+M: texture-rectangle texture-data-gl-target drop GL_TEXTURE_RECTANGLE ;
+M: texture-3d texture-data-gl-target drop GL_TEXTURE_3D ;
+M: texture-1d-array texture-data-gl-target drop GL_TEXTURE_1D_ARRAY ;
+M: texture-2d-array texture-data-gl-target drop GL_TEXTURE_2D_ARRAY ;
+M: cube-map-face texture-data-gl-target
+ axis>> {
+ { -X [ GL_TEXTURE_CUBE_MAP_NEGATIVE_X ] }
+ { -Y [ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ] }
+ { -Z [ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ] }
+ { +X [ GL_TEXTURE_CUBE_MAP_POSITIVE_X ] }
+ { +Y [ GL_TEXTURE_CUBE_MAP_POSITIVE_Y ] }
+ { +Z [ GL_TEXTURE_CUBE_MAP_POSITIVE_Z ] }
+ } case ;
+
+: texture-gl-internal-format ( texture -- internal-format )
+ [ component-order>> ] [ component-type>> ] bi image-internal-format ; inline
+
+: texture-data-gl-args ( texture data -- format type ptr )
+ [
+ nip
+ [ [ component-order>> ] [ component-type>> ] bi image-data-format ]
+ [ ptr>> ] bi
+ ] [
+ [ component-order>> ] [ component-type>> ] bi image-data-format f
+ ] if* ;
+
+:: bind-tdt ( tdt -- texture )
+ tdt texture-object :> texture
+ texture [ texture-gl-target ] [ handle>> ] bi glBindTexture
+ texture ;
+
+: get-texture-float ( target level enum -- value )
+ 0 <float> [ glGetTexLevelParameterfv ] keep *float ;
+: get-texture-int ( target level enum -- value )
+ 0 <int> [ glGetTexLevelParameteriv ] keep *int ;
+
+: ?product ( x -- y )
+ dup number? [ product ] unless ;
+
+PRIVATE>
+
+GENERIC# allocate-texture 3 ( tdt level dim data -- )
+
+M:: texture-1d-data-target allocate-texture ( tdt level dim data -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level texture texture-gl-internal-format
+ dim 0 texture data texture-data-gl-args
+ pixel-unpack-buffer [ glTexImage1D ] with-gpu-data-ptr ;
+
+M:: texture-2d-data-target allocate-texture ( tdt level dim data -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level texture texture-gl-internal-format
+ dim first2 0 texture data texture-data-gl-args
+ pixel-unpack-buffer [ glTexImage2D ] with-gpu-data-ptr ;
+
+M:: texture-3d-data-target allocate-texture ( tdt level dim data -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level texture texture-gl-internal-format
+ dim first3 0 texture data texture-data-gl-args
+ pixel-unpack-buffer [ glTexImage3D ] with-gpu-data-ptr ;
+
+GENERIC# update-texture 4 ( tdt level loc dim data -- )
+
+M:: texture-1d-data-target update-texture ( tdt level loc dim data -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level
+ loc dim texture data texture-data-gl-args
+ pixel-unpack-buffer [ glTexSubImage1D ] with-gpu-data-ptr ;
+
+M:: texture-2d-data-target update-texture ( tdt level loc dim data -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level
+ loc dim [ first2 ] bi@
+ texture data texture-data-gl-args
+ pixel-unpack-buffer [ glTexSubImage2D ] with-gpu-data-ptr ;
+
+M:: texture-3d-data-target update-texture ( tdt level loc dim data -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level
+ loc dim [ first3 ] bi@
+ texture data texture-data-gl-args
+ pixel-unpack-buffer [ glTexSubImage3D ] with-gpu-data-ptr ;
+
+: image>texture-data ( image -- dim texture-data )
+ { [ dim>> ] [ bitmap>> ] [ component-order>> ] [ component-type>> ] } cleave
+ <texture-data> ; inline
+
+GENERIC# texture-dim 1 ( tdt level -- dim )
+
+M:: texture-1d-data-target texture-dim ( tdt level -- dim )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level GL_TEXTURE_WIDTH get-texture-int ;
+
+M:: texture-2d-data-target texture-dim ( tdt level -- dim )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level
+ [ GL_TEXTURE_WIDTH get-texture-int ] [ GL_TEXTURE_HEIGHT get-texture-int ] 2bi
+ 2array ;
+
+M:: texture-3d-data-target texture-dim ( tdt level -- dim )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level
+ [ GL_TEXTURE_WIDTH get-texture-int ]
+ [ GL_TEXTURE_HEIGHT get-texture-int ]
+ [ GL_TEXTURE_DEPTH get-texture-int ] 2tri
+ 3array ;
+
+: texture-data-size ( tdt level -- size )
+ [ texture-dim ?product ] [ drop texture-object bytes-per-pixel ] 2bi * ;
+
+:: read-texture-to ( tdt level gpu-data-ptr -- )
+ tdt bind-tdt :> texture
+ tdt texture-data-gl-target level
+ texture [ component-order>> ] [ component-type>> ] bi image-data-format
+ gpu-data-ptr pixel-pack-buffer [ glGetTexImage ] with-gpu-data-ptr ;
+
+: read-texture ( tdt level -- byte-array )
+ 2dup texture-data-size <byte-array>
+ [ read-texture-to ] keep ;
+
+: allocate-texture-image ( tdt level image -- )
+ image>texture-data allocate-texture ;
+
+: update-texture-image ( tdt level loc image -- )
+ image>texture-data update-texture ;
+
+: read-texture-image ( tdt level -- image )
+ [ texture-dim ]
+ [ drop texture-object [ component-order>> ] [ component-type>> ] bi f ]
+ [ read-texture ] 2tri
+ image boa ;
+
+<PRIVATE
+: bind-texture ( texture -- gl-target )
+ [ texture-gl-target dup ] [ handle>> ] bi glBindTexture ;
+PRIVATE>
+
+: generate-mipmaps ( texture -- )
+ bind-texture glGenerateMipmap ;
+
+: set-texture-parameters ( texture parameters -- )
+ [ bind-texture ] dip {
+ [ wrap>> set-texture-gl-wrap ]
+ [
+ [ GL_TEXTURE_MIN_FILTER ] dip
+ [ min-filter>> ] [ min-mipmap-filter>> ] bi gl-min-filter glTexParameteri
+ ] [
+ [ GL_TEXTURE_MAG_FILTER ] dip
+ mag-filter>> gl-mag-filter glTexParameteri
+ ]
+ [ [ GL_TEXTURE_MIN_LOD ] dip min-lod>> glTexParameteri ]
+ [ [ GL_TEXTURE_MAX_LOD ] dip max-lod>> glTexParameteri ]
+ [ [ GL_TEXTURE_LOD_BIAS ] dip lod-bias>> glTexParameteri ]
+ [ [ GL_TEXTURE_BASE_LEVEL ] dip base-level>> glTexParameteri ]
+ [ [ GL_TEXTURE_MAX_LEVEL ] dip max-level>> glTexParameteri ]
+ } 2cleave ;
+
+<PRIVATE
+
+: <texture> ( component-order component-type parameters class -- texture )
+ '[ [ gen-texture ] 2dip _ boa dup window-resource ] dip
+ [ T{ texture-parameters } clone ] unless* set-texture-parameters ; inline
+
+PRIVATE>
+
+: <texture-1d> ( component-order component-type parameters -- texture )
+ texture-1d <texture> ;
+: <texture-2d> ( component-order component-type parameters -- texture )
+ texture-2d <texture> ;
+: <texture-3d> ( component-order component-type parameters -- texture )
+ texture-3d <texture> ;
+: <texture-cube-map> ( component-order component-type parameters -- texture )
+ texture-cube-map <texture> ;
+: <texture-rectangle> ( component-order component-type parameters -- texture )
+ texture-rectangle <texture> ;
+: <texture-1d-array> ( component-order component-type parameters -- texture )
+ texture-1d-array <texture> ;
+: <texture-2d-array> ( component-order component-type parameters -- texture )
+ texture-2d-array <texture> ;
+
--- /dev/null
+Miscellaneous functions useful for GPU library apps
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: gpu.buffers gpu.render gpu.shaders gpu.textures images kernel
+specialized-arrays.float ;
+IN: gpu.util
+
+CONSTANT: environment-cube-map-mv-matrices
+ H{
+ { +X {
+ { 0.0 0.0 -1.0 0.0 }
+ { 0.0 -1.0 0.0 0.0 }
+ { -1.0 0.0 0.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } }
+ { +Y {
+ { 1.0 0.0 0.0 0.0 }
+ { 0.0 0.0 1.0 0.0 }
+ { 0.0 -1.0 0.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } }
+ { +Z {
+ { 1.0 0.0 0.0 0.0 }
+ { 0.0 -1.0 0.0 0.0 }
+ { 0.0 0.0 -1.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } }
+ { -X {
+ { 0.0 0.0 1.0 0.0 }
+ { 0.0 -1.0 0.0 0.0 }
+ { 1.0 0.0 0.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } }
+ { -Y {
+ { 1.0 0.0 0.0 0.0 }
+ { 0.0 0.0 -1.0 0.0 }
+ { 0.0 1.0 0.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } }
+ { -Z {
+ { -1.0 0.0 0.0 0.0 }
+ { 0.0 -1.0 0.0 0.0 }
+ { 0.0 0.0 1.0 0.0 }
+ { 0.0 0.0 0.0 1.0 }
+ } }
+ }
+
+VERTEX-FORMAT: window-vertex
+ { "vertex" float-components 2 f } ;
+
+CONSTANT: window-vertexes
+ float-array{
+ -1.0 -1.0
+ -1.0 1.0
+ 1.0 -1.0
+ 1.0 1.0
+ }
+
+: <window-vertex-buffer> ( -- buffer )
+ window-vertexes
+ static-upload draw-usage vertex-buffer
+ byte-array>buffer ;
+
+: <window-vertex-array> ( program-instance -- vertex-array )
+ [ <window-vertex-buffer> ] dip window-vertex buffer>vertex-array ;
--- /dev/null
+Scaffolding for demo scenes that can be explored using FPS-style controls
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors arrays combinators.smart game-input
+game-input.scancodes game-loop game-worlds
+gpu.render gpu.state kernel literals
+locals math math.constants math.functions math.matrices
+math.order math.vectors opengl.gl sequences
+specialized-arrays.float ui ui.gadgets.worlds ;
+IN: gpu.util.wasd
+
+UNIFORM-TUPLE: mvp-uniforms
+ { "mv_matrix" mat4-uniform f }
+ { "p_matrix" mat4-uniform f } ;
+
+CONSTANT: -pi/2 $[ pi -2.0 / ]
+CONSTANT: pi/2 $[ pi 2.0 / ]
+
+TUPLE: wasd-world < game-world location yaw pitch p-matrix ;
+
+GENERIC: wasd-near-plane ( world -- near-plane )
+M: wasd-world wasd-near-plane drop 0.25 ;
+
+GENERIC: wasd-far-plane ( world -- far-plane )
+M: wasd-world wasd-far-plane drop 1024.0 ;
+
+GENERIC: wasd-movement-speed ( world -- speed )
+M: wasd-world wasd-movement-speed drop 1/16. ;
+
+GENERIC: wasd-mouse-scale ( world -- scale )
+M: wasd-world wasd-mouse-scale drop 1/600. ;
+
+GENERIC: wasd-pitch-range ( world -- min max )
+M: wasd-world wasd-pitch-range drop -pi/2 pi/2 ;
+
+GENERIC: wasd-fly-vertically? ( world -- ? )
+M: wasd-world wasd-fly-vertically? drop t ;
+
+: wasd-mv-matrix ( world -- matrix )
+ [ { 1.0 0.0 0.0 } swap pitch>> rotation-matrix4 ]
+ [ { 0.0 1.0 0.0 } swap yaw>> rotation-matrix4 ]
+ [ location>> vneg translation-matrix4 ] tri m. m. ;
+
+: wasd-mv-inv-matrix ( world -- matrix )
+ [ location>> translation-matrix4 ]
+ [ { 0.0 -1.0 0.0 } swap yaw>> rotation-matrix4 ]
+ [ { -1.0 0.0 0.0 } swap pitch>> rotation-matrix4 ] tri m. m. ;
+
+: wasd-p-matrix ( world -- matrix )
+ p-matrix>> ;
+
+CONSTANT: fov 0.7
+
+:: generate-p-matrix ( world -- matrix )
+ world wasd-near-plane :> near-plane
+ world wasd-far-plane :> far-plane
+
+ world dim>> dup first2 min >float v/n fov v*n near-plane v*n
+ near-plane far-plane frustum-matrix4 ;
+
+: set-wasd-view ( world location yaw pitch -- world )
+ [ >>location ] [ >>yaw ] [ >>pitch ] tri* ;
+
+:: eye-rotate ( yaw pitch v -- v' )
+ yaw neg :> y
+ pitch neg :> p
+ y cos :> cosy
+ y sin :> siny
+ p cos :> cosp
+ p sin :> sinp
+
+ cosy 0.0 siny neg 3array
+ siny sinp * cosp cosy sinp * 3array
+ siny cosp * sinp neg cosy cosp * 3array 3array
+ v swap v.m ;
+
+: ?pitch ( world -- pitch )
+ dup wasd-fly-vertically? [ pitch>> ] [ drop 0.0 ] if ;
+
+: forward-vector ( world -- v )
+ [ yaw>> ] [ ?pitch ] [ wasd-movement-speed ] tri
+ { 0.0 0.0 -1.0 } n*v eye-rotate ;
+: rightward-vector ( world -- v )
+ [ yaw>> ] [ ?pitch ] [ wasd-movement-speed ] tri
+ { 1.0 0.0 0.0 } n*v eye-rotate ;
+
+: walk-forward ( world -- )
+ dup forward-vector [ v+ ] curry change-location drop ;
+: walk-backward ( world -- )
+ dup forward-vector [ v- ] curry change-location drop ;
+: walk-leftward ( world -- )
+ dup rightward-vector [ v- ] curry change-location drop ;
+: walk-rightward ( world -- )
+ dup rightward-vector [ v+ ] curry change-location drop ;
+: walk-upward ( world -- )
+ dup wasd-movement-speed { 0.0 1.0 0.0 } n*v [ v+ ] curry change-location drop ;
+: walk-downward ( world -- )
+ dup wasd-movement-speed { 0.0 1.0 0.0 } n*v [ v- ] curry change-location drop ;
+
+: clamp-pitch ( world -- world )
+ dup [ wasd-pitch-range clamp ] curry change-pitch ;
+
+: rotate-with-mouse ( world mouse -- )
+ [ [ dup wasd-mouse-scale ] [ dx>> ] bi* * [ + ] curry change-yaw ]
+ [ [ dup wasd-mouse-scale ] [ dy>> ] bi* * [ + ] curry change-pitch clamp-pitch ] bi
+ drop ;
+
+:: wasd-keyboard-input ( world -- )
+ read-keyboard keys>> :> keys
+ key-w keys nth key-, keys nth or [ world walk-forward ] when
+ key-s keys nth key-o keys nth or [ world walk-backward ] when
+ key-a keys nth [ world walk-leftward ] when
+ key-d keys nth key-e keys nth or [ world walk-rightward ] when
+ key-space keys nth [ world walk-upward ] when
+ key-c keys nth key-j keys nth or [ world walk-downward ] when
+ key-escape keys nth [ world close-window ] when ;
+
+: wasd-mouse-input ( world -- )
+ read-mouse rotate-with-mouse ;
+
+M: wasd-world tick*
+ dup focused?>> [
+ [ wasd-keyboard-input ] [ wasd-mouse-input ] bi
+ reset-mouse
+ ] [ drop ] if ;
+
+M: wasd-world resize-world
+ [ <viewport-state> set-gpu-state* ]
+ [ dup generate-p-matrix >>p-matrix drop ] bi ;
+
--- /dev/null
+USING: alien.c-types alien.syntax half-floats kernel math tools.test ;
+IN: half-floats.tests
+
+[ HEX: 0000 ] [ 0.0 half>bits ] unit-test
+[ HEX: 8000 ] [ -0.0 half>bits ] unit-test
+[ HEX: 3e00 ] [ 1.5 half>bits ] unit-test
+[ HEX: be00 ] [ -1.5 half>bits ] unit-test
+[ HEX: 7c00 ] [ 1/0. half>bits ] unit-test
+[ HEX: fc00 ] [ -1/0. half>bits ] unit-test
+[ HEX: 7eaa ] [ HEX: aaaaaaaaaaaaa <fp-nan> half>bits ] unit-test
+
+! too-big floats overflow to infinity
+[ HEX: 7c00 ] [ 65536.0 half>bits ] unit-test
+[ HEX: fc00 ] [ -65536.0 half>bits ] unit-test
+[ HEX: 7c00 ] [ 131072.0 half>bits ] unit-test
+[ HEX: fc00 ] [ -131072.0 half>bits ] unit-test
+
+! too-small floats flush to zero
+[ HEX: 0000 ] [ 1.0e-9 half>bits ] unit-test
+[ HEX: 8000 ] [ -1.0e-9 half>bits ] unit-test
+
+[ 0.0 ] [ HEX: 0000 bits>half ] unit-test
+[ -0.0 ] [ HEX: 8000 bits>half ] unit-test
+[ 1.5 ] [ HEX: 3e00 bits>half ] unit-test
+[ -1.5 ] [ HEX: be00 bits>half ] unit-test
+[ 1/0. ] [ HEX: 7c00 bits>half ] unit-test
+[ -1/0. ] [ HEX: fc00 bits>half ] unit-test
+[ 3.0 ] [ HEX: 4200 bits>half ] unit-test
+[ t ] [ HEX: 7e00 bits>half fp-nan? ] unit-test
+
+C-STRUCT: halves
+ { "half" "tom" }
+ { "half" "dick" }
+ { "half" "harry" }
+ { "half" "harry-jr" } ;
+
+[ 8 ] [ "halves" heap-size ] unit-test
+
+[ 3.0 ] [
+ "halves" <c-object>
+ 3.0 over set-halves-dick
+ halves-dick
+] unit-test
+
+[ half-array{ 1.0 2.0 3.0 1/0. -1/0. } ]
+[ { 1.0 2.0 3.0 1/0. -1/0. } >half-array ] unit-test
+
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien.c-types alien.syntax kernel math math.order
+specialized-arrays.direct.functor specialized-arrays.functor ;
+IN: half-floats
+
+: half>bits ( float -- bits )
+ float>bits
+ [ -31 shift 15 shift ] [
+ HEX: 7fffffff bitand
+ dup zero? [
+ dup HEX: 7f800000 >= [ -13 shift HEX: 7fff bitand ] [
+ -13 shift
+ 112 10 shift -
+ 0 HEX: 7c00 clamp
+ ] if
+ ] unless
+ ] bi bitor ;
+
+: bits>half ( bits -- float )
+ [ -15 shift 31 shift ] [
+ HEX: 7fff bitand
+ dup zero? [
+ dup HEX: 7c00 >= [ 13 shift HEX: 7f800000 bitor ] [
+ 13 shift
+ 112 23 shift +
+ ] if
+ ] unless
+ ] bi bitor bits>float ;
+
+C-STRUCT: half { "ushort" "(bits)" } ;
+
+<<
+
+"half" c-type
+ [ half>bits <ushort> ] >>unboxer-quot
+ [ *ushort bits>half ] >>boxer-quot
+ drop
+
+"half" define-array
+"half" define-direct-array
+
+>>
--- /dev/null
+Half-precision float support for FFI
: (mint) ( tuple counter -- tuple )
2dup set-suffix checksummed-bits pick
- valid-guess? [ drop ] [ 1+ (mint) ] if ;
+ valid-guess? [ drop ] [ 1 + (mint) ] if ;
PRIVATE>
--- /dev/null
+IN: histogram\r
+USING: help.markup help.syntax sequences hashtables quotations assocs ;\r
+\r
+HELP: histogram\r
+{ $values\r
+ { "seq" sequence }\r
+ { "hashtable" hashtable }\r
+}\r
+{ $examples \r
+ { $example "! Count the number of times an element appears in a sequence."\r
+ "USING: prettyprint histogram ;"\r
+ "\"aaabc\" histogram ."\r
+ "H{ { 97 3 } { 98 1 } { 99 1 } }"\r
+ }\r
+}\r
+{ $description "Returns a hashtable where the keys are the elements of the sequence and the values are the number of times they appeared in that sequence." } ;\r
+\r
+HELP: histogram*\r
+{ $values\r
+ { "hashtable" hashtable } { "seq" sequence }\r
+ { "hashtable" hashtable }\r
+}\r
+{ $examples \r
+ { $example "! Count the number of times the elements of two sequences appear."\r
+ "USING: prettyprint histogram ;"\r
+ "\"aaabc\" histogram \"aaaaaabc\" histogram* ."\r
+ "H{ { 97 9 } { 98 2 } { 99 2 } }"\r
+ }\r
+}\r
+{ $description "Takes an existing hashtable and uses " { $link histogram } " to continue counting the number of occurences of each element." } ;\r
+\r
+HELP: sequence>assoc\r
+{ $values\r
+ { "seq" sequence } { "quot" quotation } { "exemplar" "an exemplar assoc" }\r
+ { "assoc" assoc }\r
+}\r
+{ $examples \r
+ { $example "! Iterate over a sequence and increment the count at each element"\r
+ "USING: assocs prettyprint histogram ;"\r
+ "\"aaabc\" [ inc-at ] H{ } sequence>assoc ."\r
+ "H{ { 97 3 } { 98 1 } { 99 1 } }"\r
+ }\r
+}\r
+{ $description "Iterates over a sequence, allowing elements of the sequence to be added to a newly created " { $snippet "assoc" } " according to the passed quotation." } ;\r
+\r
+HELP: sequence>assoc*\r
+{ $values\r
+ { "assoc" assoc } { "seq" sequence } { "quot" quotation }\r
+ { "assoc" assoc }\r
+}\r
+{ $examples \r
+ { $example "! Iterate over a sequence and add the counts to an existing assoc"\r
+ "USING: assocs prettyprint histogram kernel ;"\r
+ "H{ { 97 2 } { 98 1 } } clone \"aaabc\" [ inc-at ] sequence>assoc* ."\r
+ "H{ { 97 5 } { 98 2 } { 99 1 } }"\r
+ }\r
+}\r
+{ $description "Iterates over a sequence, allowing elements of the sequence to be added to an existing " { $snippet "assoc" } " according to the passed quotation." } ;\r
+\r
+HELP: sequence>hashtable\r
+{ $values\r
+ { "seq" sequence } { "quot" quotation }\r
+ { "hashtable" hashtable }\r
+}\r
+{ $examples \r
+ { $example "! Count the number of times an element occurs in a sequence"\r
+ "USING: assocs prettyprint histogram ;"\r
+ "\"aaabc\" [ inc-at ] sequence>hashtable ."\r
+ "H{ { 97 3 } { 98 1 } { 99 1 } }"\r
+ }\r
+}\r
+{ $description "Iterates over a sequence, allowing elements of the sequence to be added to a hashtable according to the passed quotation." } ;\r
+\r
+ARTICLE: "histogram" "Computing histograms"\r
+"Counting elements in a sequence:"\r
+{ $subsection histogram }\r
+{ $subsection histogram* }\r
+"Combinators for implementing histogram:"\r
+{ $subsection sequence>assoc }\r
+{ $subsection sequence>assoc* }\r
+{ $subsection sequence>hashtable } ;\r
+\r
+ABOUT: "histogram"\r
--- /dev/null
+IN: histogram.tests\r
+USING: help.markup help.syntax tools.test histogram ;\r
+\r
+[\r
+ H{\r
+ { 97 2 }\r
+ { 98 2 }\r
+ { 99 2 }\r
+ }\r
+] [\r
+ "aabbcc" histogram\r
+] unit-test\r
--- /dev/null
+! Copyright (C) 2009 Doug Coleman.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+USING: kernel sequences assocs fry ;\r
+IN: histogram\r
+\r
+<PRIVATE\r
+\r
+: (sequence>assoc) ( seq quot assoc -- assoc )\r
+ [ swap curry each ] keep ; inline\r
+\r
+PRIVATE>\r
+\r
+: sequence>assoc* ( assoc seq quot: ( obj assoc -- ) -- assoc )\r
+ rot (sequence>assoc) ; inline\r
+\r
+: sequence>assoc ( seq quot: ( obj assoc -- ) exemplar -- assoc )\r
+ clone (sequence>assoc) ; inline\r
+\r
+: sequence>hashtable ( seq quot: ( obj hashtable -- ) -- hashtable )\r
+ H{ } sequence>assoc ; inline\r
+\r
+: histogram* ( hashtable seq -- hashtable )\r
+ [ inc-at ] sequence>assoc* ;\r
+\r
+: histogram ( seq -- hashtable )\r
+ [ inc-at ] sequence>hashtable ;\r
+\r
+: collect-values ( seq quot: ( obj hashtable -- ) -- hash )\r
+ '[ [ dup @ ] dip push-at ] sequence>hashtable ; inline\r
[
"h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" "h9"
"ol" "li" "form" "a" "p" "html" "head" "body" "title"
- "b" "i" "ul" "table" "tbody" "tr" "td" "th" "pre" "textarea"
+ "b" "i" "ul" "table" "thead" "tfoot" "tbody" "tr" "td" "th" "pre" "textarea"
"script" "div" "span" "select" "option" "style" "input"
"strong"
] [ define-closed-html-word ] each
USING: assocs html.parser kernel math sequences strings ascii
arrays generalizations shuffle namespaces make
splitting http accessors io combinators http.client urls
-urls.encoding fry prettyprint sets ;
+urls.encoding fry prettyprint sets combinators.short-circuit ;
IN: html.parser.analyzer
TUPLE: link attributes clickable ;
: find-nth ( seq quot n -- i elt )
[ <enum> >alist ] 2dip -rot
- '[ _ [ second @ ] find-from rot drop swap 1+ ]
+ '[ _ [ second @ ] find-from rot drop swap 1 + ]
[ f 0 ] 2dip times drop first2 ; inline
: find-first-name ( vector string -- i/f tag/f )
: find-between* ( vector i/f tag/f -- vector )
over integer? [
[ tail-slice ] [ name>> ] bi*
- dupd find-matching-close drop dup [ 1+ ] when
+ dupd find-matching-close drop dup [ 1 + ] when
[ head ] [ first ] if*
] [
3drop V{ } clone
[ [ name>> "a" = ] [ attributes>> "href" swap at ] bi and ]
find-between-all ;
+: find-images ( vector -- vector' )
+ [
+ {
+ [ name>> "img" = ]
+ [ attributes>> "src" swap at ]
+ } 1&&
+ ] find-all
+ values [ attributes>> "src" swap at ] map ;
+
: <link> ( vector -- link )
[ first attributes>> ]
[ [ name>> { text "img" } member? ] filter ] bi
0 [ [ 7 shift ] dip bitor ] reduce ;
: synchsafe>seq ( n -- seq )
- dup 1+ log2 1+ 7 / ceiling
+ dup 1 + log2 1 + 7 / ceiling
[ [ -7 shift ] keep HEX: 7f bitand ] replicate nip reverse ;
: filter-text-data ( data -- filtered )
USING: kernel accessors grouping sequences combinators
math specialized-arrays.direct.uint byte-arrays fry
specialized-arrays.direct.ushort specialized-arrays.uint
-specialized-arrays.ushort specialized-arrays.float images ;
+specialized-arrays.ushort specialized-arrays.float images
+half-floats ;
IN: images.normalization
<PRIVATE
: add-dummy-alpha ( seq -- seq' )
3 <groups> [ 255 suffix ] map concat ;
-: normalize-floats ( byte-array -- byte-array )
- byte-array>float-array [ 255.0 * >integer ] B{ } map-as ;
+: normalize-floats ( float-array -- byte-array )
+ [ 255.0 * >integer ] B{ } map-as ;
+GENERIC: normalize-component-type* ( image component-type -- image )
GENERIC: normalize-component-order* ( image component-order -- image )
: normalize-component-order ( image -- image )
+ dup component-type>> '[ _ normalize-component-type* ] change-bitmap
dup component-order>> '[ _ normalize-component-order* ] change-bitmap ;
-M: RGBA normalize-component-order* drop ;
-
-M: R32G32B32A32 normalize-component-order*
- drop normalize-floats ;
-
-M: R32G32B32 normalize-component-order*
- drop normalize-floats add-dummy-alpha ;
+M: float-components normalize-component-type*
+ drop byte-array>float-array normalize-floats ;
+M: half-components normalize-component-type*
+ drop byte-array>half-array normalize-floats ;
-: RGB16>8 ( bitmap -- bitmap' )
+: ushorts>ubytes ( bitmap -- bitmap' )
byte-array>ushort-array [ -8 shift ] B{ } map-as ; inline
-M: R16G16B16A16 normalize-component-order*
- drop RGB16>8 ;
+M: ushort-components normalize-component-type*
+ drop ushorts>ubytes ;
-M: R16G16B16 normalize-component-order*
- drop RGB16>8 add-dummy-alpha ;
+M: ubyte-components normalize-component-type*
+ drop ;
+
+M: RGBA normalize-component-order* drop ;
: BGR>RGB ( bitmap -- pixels )
3 <sliced-groups> [ <reversed> ] map B{ } join ; inline
+++ /dev/null
-Kobi Lurie
-Doug Coleman
+++ /dev/null
-! Copyright (C) 2009 Kobi Lurie, Doug Coleman.\r
-! See http://factorcode.org/license.txt for BSD license.\r
-USING: accessors fry images.loader\r
-images.processing.rotation kernel literals math sequences\r
-tools.test images.processing.rotation.private ;\r
-IN: images.processing.rotation.tests\r
-\r
-: first-row ( seq^2 -- seq ) first ;\r
-: first-col ( seq^2 -- item ) harvest [ first ] map ;\r
-: last-row ( seq^2 -- item ) last ;\r
-: last-col ( seq^2 -- item ) harvest [ last ] map ;\r
-: end-of-first-row ( seq^2 -- item ) first-row last ;\r
-: first-of-first-row ( seq^2 -- item ) first-row first ;\r
-: end-of-last-row ( seq^2 -- item ) last-row last ;\r
-: first-of-last-row ( seq^2 -- item ) last-row first ;\r
-\r
-<<\r
-\r
-: clone-image ( image -- new-image )\r
- clone [ clone ] change-bitmap ;\r
-\r
->>\r
-\r
-CONSTANT: pasted-image\r
- $[\r
- "vocab:images/processing/rotation/test-bitmaps/PastedImage.bmp"\r
- load-image clone-image\r
- ]\r
-\r
-CONSTANT: pasted-image90\r
- $[\r
- "vocab:images/processing/rotation/test-bitmaps/PastedImage90.bmp"\r
- load-image clone-image\r
- ]\r
-\r
-CONSTANT: lake-image\r
- $[\r
- "vocab:images/processing/rotation/test-bitmaps/lake.bmp"\r
- load-image preprocess\r
- ]\r
-\r
-[ t ] [ pasted-image dup clone-image 4 [ 90 rotate ] times = ] unit-test\r
-[ t ] [ pasted-image dup clone-image 2 [ 180 rotate ] times = ] unit-test\r
-[ t ] [ pasted-image dup clone-image 270 rotate 90 rotate = ] unit-test\r
-[ t ] [\r
- pasted-image dup clone-image dup { 90 180 90 } [ rotate drop ] with each =\r
-] unit-test\r
-\r
-[ t ] [\r
- pasted-image 90 rotate\r
- pasted-image90 = \r
-] unit-test\r
-\r
-[ t ] [\r
- "vocab:images/processing/rotation/test-bitmaps/small.bmp"\r
- load-image 90 rotate \r
- "vocab:images/processing/rotation/test-bitmaps/small-rotated.bmp"\r
- load-image =\r
-] unit-test\r
- \r
-[ t ] [\r
- lake-image\r
- [ first-of-first-row ]\r
- [ 90 (rotate) end-of-first-row ] bi =\r
-] unit-test\r
-\r
-[ t ]\r
-[ lake-image [ first-row ] [ 90 (rotate) last-col ] bi = ] unit-test\r
-\r
-[ t ]\r
-[ lake-image [ last-col ] [ 90 (rotate) last-row reverse ] bi = ] unit-test\r
-\r
-[ t ]\r
-[ lake-image [ last-row ] [ 90 (rotate) first-col ] bi = ] unit-test\r
-\r
-[ t ]\r
-[ lake-image [ first-col ] [ 90 (rotate) first-row reverse ] bi = ] unit-test\r
+++ /dev/null
-! Copyright (C) 2009 Kobi Lurie.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays colors combinators
-combinators.short-circuit fry grouping images images.bitmap
-images.loader images.normalization kernel locals math sequences ;
-IN: images.processing.rotation
-
-ERROR: unsupported-rotation degrees ;
-
-<PRIVATE
-
-: rotate-90 ( seq^3 -- seq^3 ) flip [ reverse ] map ;
-: rotate-180 ( seq^3 -- seq^3 ) reverse [ reverse ] map ;
-: rotate-270 ( seq^3 -- seq^3 ) flip reverse ;
-
-: (rotate) ( seq n -- seq' )
- {
- { 0 [ ] }
- { 90 [ rotate-90 ] }
- { 180 [ rotate-180 ] }
- { 270 [ rotate-270 ] }
- [ unsupported-rotation ]
- } case ;
-
-: rows-remove-pad ( byte-rows -- pixels' )
- [ dup length 4 mod head* ] map ;
-
-: row-length ( image -- n )
- [ bitmap>> length ] [ dim>> second ] bi /i ;
-
-: image>byte-rows ( image -- byte-rows )
- [ bitmap>> ] [ row-length ] bi group rows-remove-pad ;
-
-: (seperate-to-pixels) ( byte-rows image -- pixel-rows )
- component-order>> bytes-per-pixel '[ _ group ] map ;
-
-: image>pixel-rows ( image -- pixel-rows )
- [ image>byte-rows ] keep (seperate-to-pixels) ;
-
-: flatten-table ( seq^3 -- seq )
- [ concat ] map concat ;
-
-: preprocess ( image -- pixelrows )
- normalize-image image>pixel-rows ;
-
-: ?reverse-dimensions ( image n -- )
- { 270 90 } member? [ [ reverse ] change-dim ] when drop ;
-
-: normalize-degree ( n -- n' ) 360 rem ;
-
-: processing-effect ( image quot -- image' )
- '[ preprocess @ flatten-table ] [ (>>bitmap) ] [ ] tri ; inline
-
-:: rotate' ( image n -- image )
- n normalize-degree :> n'
- image preprocess :> pixel-table
- image n' ?reverse-dimensions
- pixel-table n' (rotate) :> table-rotated
- image table-rotated flatten-table >>bitmap ;
-
-PRIVATE>
-
-: rotate ( image n -- image' )
- normalize-degree
- [ '[ _ (rotate) ] processing-effect ] [ ?reverse-dimensions ] 2bi ;
-
-: reflect-y-axis ( image -- image )
- [ [ reverse ] map ] processing-effect ;
-
-: reflect-x-axis ( image -- image )
- [ reverse ] processing-effect ;
CONSTANT: IEXTEN OCT: 0100000
M: linux lookup-baud ( n -- n )
- dup H{
- { 0 OCT: 0000000 }
- { 50 OCT: 0000001 }
- { 75 OCT: 0000002 }
- { 110 OCT: 0000003 }
- { 134 OCT: 0000004 }
- { 150 OCT: 0000005 }
- { 200 OCT: 0000006 }
- { 300 OCT: 0000007 }
- { 600 OCT: 0000010 }
- { 1200 OCT: 0000011 }
- { 1800 OCT: 0000012 }
- { 2400 OCT: 0000013 }
- { 4800 OCT: 0000014 }
- { 9600 OCT: 0000015 }
- { 19200 OCT: 0000016 }
- { 38400 OCT: 0000017 }
+ H{
+ { 0 OCT: 0000000 }
+ { 50 OCT: 0000001 }
+ { 75 OCT: 0000002 }
+ { 110 OCT: 0000003 }
+ { 134 OCT: 0000004 }
+ { 150 OCT: 0000005 }
+ { 200 OCT: 0000006 }
+ { 300 OCT: 0000007 }
+ { 600 OCT: 0000010 }
+ { 1200 OCT: 0000011 }
+ { 1800 OCT: 0000012 }
+ { 2400 OCT: 0000013 }
+ { 4800 OCT: 0000014 }
+ { 9600 OCT: 0000015 }
+ { 19200 OCT: 0000016 }
+ { 38400 OCT: 0000017 }
{ 57600 OCT: 0010001 }
{ 115200 OCT: 0010002 }
{ 230400 OCT: 0010003 }
: do-connect ( server port quot: ( host port -- stream ) attempts -- stream/f )
dup 0 > [
[ drop call( host port -- stream ) ]
- [ drop 15 sleep 1- do-connect ]
+ [ drop 15 sleep 1 - do-connect ]
recover
] [ 2drop 2drop f ] if ;
GENERIC: process-message ( irc-message -- )
M: object process-message drop ;
M: ping process-message trailing>> /PONG ;
-M: join process-message [ sender>> ] [ chat> ] bi join-participant ;
-M: part process-message [ sender>> ] [ chat> ] bi part-participant ;
+! FIXME: it shouldn't be checking for the presence of chat here...
+M: join process-message [ sender>> ] [ chat> ] bi [ join-participant ] [ drop ] if* ;
+M: part process-message [ sender>> ] [ chat> ] bi [ part-participant ] [ drop ] if* ;
M: quit process-message sender>> quit-participant ;
M: nick process-message [ trailing>> ] [ sender>> ] bi rename-participant* ;
M: rpl-nickname-in-use process-message name>> "_" append /NICK ;
: timestamp-path ( timestamp -- path )
timestamp>ymd ".log" append log-directory prepend-path ;
+: update-current-stream ( timestamp -- )
+ current-stream get [ dispose ] when*
+ [ day-of-year current-day set ]
+ [ timestamp-path latin1 <file-appender> ] bi
+ current-stream set ;
+
+: same-day? ( timestamp -- ? ) day-of-year current-day get = ;
+
: timestamp>stream ( timestamp -- stream )
- dup day-of-year current-day get = [
- drop
- ] [
- current-stream get [ dispose ] when*
- [ day-of-year current-day set ]
- [ timestamp-path latin1 <file-appender> ] bi
- current-stream set
- ] if current-stream get ;
+ dup same-day? [ drop ] [ update-current-stream ] if
+ current-stream get ;
: log-message ( string timestamp -- )
[ add-timestamp ] [ timestamp>stream ] bi
C: <segment> segment
: segment-number++ ( segment -- )
- [ number>> 1+ ] keep (>>number) ;
+ [ number>> 1 + ] keep (>>number) ;
: clamp-length ( n seq -- n' )
0 swap length clamp ;
: (random-segments) ( segments n -- segments )
dup 0 > [
- [ dup last random-segment over push ] dip 1- (random-segments)
+ [ dup last random-segment over push ] dip 1 - (random-segments)
] [ drop ] if ;
CONSTANT: default-segment-radius 1
rot dup length swap <slice> find-nearest-segment ;
: nearest-segment-backward ( segments oint start -- segment )
- swapd 1+ 0 spin <slice> <reversed> find-nearest-segment ;
+ swapd 1 + 0 spin <slice> <reversed> find-nearest-segment ;
: nearest-segment ( segments oint start-segment -- segment )
#! find the segment nearest to 'oint', and return it.
over clamp-length swap nth ;
: next-segment ( segments current-segment -- segment )
- number>> 1+ get-segment ;
+ number>> 1 + get-segment ;
: previous-segment ( segments current-segment -- segment )
- number>> 1- get-segment ;
+ number>> 1 - get-segment ;
: heading-segment ( segments current-segment heading -- segment )
#! the next segment on the given heading
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel ui.gadgets.borders ui.gestures ;
+IN: key-handlers
+
+TUPLE: key-handler < border handlers ;
+: <keys> ( gadget -- key-handler ) key-handler new-border { 0 0 } >>size ;
+
+M: key-handler handle-gesture
+ tuck handlers>> at [ call( gadget -- ) f ] [ drop t ] if* ;
\ No newline at end of file
: inversions ( seq -- n )
0 swap [ length ] keep [
- [ nth ] 2keep swap 1+ tail-slice (inversions) +
+ [ nth ] 2keep swap 1 + tail-slice (inversions) +
] curry each ;
: duplicates? ( seq -- ? )
! Computing a basis
: graded ( seq -- seq )
- dup 0 [ length max ] reduce 1+ [ V{ } clone ] replicate
+ dup 0 [ length max ] reduce 1 + [ V{ } clone ] replicate
[ dup length pick nth push ] reduce ;
: nth-basis-elt ( generators n -- elt )
! Graded by degree
: (graded-ker/im-d) ( n seq -- null/rank )
#! d: C(n) ---> C(n+1)
- [ ?nth ] [ [ 1+ ] dip ?nth ] 2bi
+ [ ?nth ] [ [ 1 + ] dip ?nth ] 2bi
dim-im/ker-d ;
: graded-ker/im-d ( graded-basis -- seq )
] if ;
: graded-triple ( seq n -- triple )
- 3 [ 1- + ] with map swap [ ?nth ] curry map ;
+ 3 [ 1 - + ] with map swap [ ?nth ] curry map ;
: graded-triples ( seq -- triples )
dup length [ graded-triple ] with map ;
--- /dev/null
+Matthew Willis
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.libraries alien.syntax system sequences combinators kernel ;
+
+IN: llvm.core
+
+<<
+
+: add-llvm-library ( name -- )
+ dup
+ {
+ { [ os macosx? ] [ "/usr/local/lib/lib" ".dylib" surround ] }
+ { [ os windows? ] [ ".dll" append ] }
+ { [ os unix? ] [ "lib" ".so" surround ] }
+ } cond "cdecl" add-library ;
+
+"LLVMSystem" add-llvm-library
+"LLVMSupport" add-llvm-library
+"LLVMCore" add-llvm-library
+"LLVMBitReader" add-llvm-library
+
+>>
+
+! llvm-c/Core.h
+
+LIBRARY: LLVMCore
+
+TYPEDEF: uint unsigned
+TYPEDEF: unsigned enum
+
+CONSTANT: LLVMZExtAttribute BIN: 1
+CONSTANT: LLVMSExtAttribute BIN: 10
+CONSTANT: LLVMNoReturnAttribute BIN: 100
+CONSTANT: LLVMInRegAttribute BIN: 1000
+CONSTANT: LLVMStructRetAttribute BIN: 10000
+CONSTANT: LLVMNoUnwindAttribute BIN: 100000
+CONSTANT: LLVMNoAliasAttribute BIN: 1000000
+CONSTANT: LLVMByValAttribute BIN: 10000000
+CONSTANT: LLVMNestAttribute BIN: 100000000
+CONSTANT: LLVMReadNoneAttribute BIN: 1000000000
+CONSTANT: LLVMReadOnlyAttribute BIN: 10000000000
+TYPEDEF: enum LLVMAttribute;
+
+C-ENUM:
+ LLVMVoidTypeKind
+ LLVMFloatTypeKind
+ LLVMDoubleTypeKind
+ LLVMX86_FP80TypeKind
+ LLVMFP128TypeKind
+ LLVMPPC_FP128TypeKind
+ LLVMLabelTypeKind
+ LLVMMetadataTypeKind
+ LLVMIntegerTypeKind
+ LLVMFunctionTypeKind
+ LLVMStructTypeKind
+ LLVMArrayTypeKind
+ LLVMPointerTypeKind
+ LLVMOpaqueTypeKind
+ LLVMVectorTypeKind ;
+TYPEDEF: enum LLVMTypeKind
+
+C-ENUM:
+ LLVMExternalLinkage
+ LLVMLinkOnceLinkage
+ LLVMWeakLinkage
+ LLVMAppendingLinkage
+ LLVMInternalLinkage
+ LLVMDLLImportLinkage
+ LLVMDLLExportLinkage
+ LLVMExternalWeakLinkage
+ LLVMGhostLinkage ;
+TYPEDEF: enum LLVMLinkage
+
+C-ENUM:
+ LLVMDefaultVisibility
+ LLVMHiddenVisibility
+ LLVMProtectedVisibility ;
+TYPEDEF: enum LLVMVisibility
+
+CONSTANT: LLVMCCallConv 0
+CONSTANT: LLVMFastCallConv 8
+CONSTANT: LLVMColdCallConv 9
+CONSTANT: LLVMX86StdcallCallConv 64
+CONSTANT: LLVMX86FastcallCallConv 65
+TYPEDEF: enum LLVMCallConv
+
+CONSTANT: LLVMIntEQ 32
+CONSTANT: LLVMIntNE 33
+CONSTANT: LLVMIntUGT 34
+CONSTANT: LLVMIntUGE 35
+CONSTANT: LLVMIntULT 36
+CONSTANT: LLVMIntULE 37
+CONSTANT: LLVMIntSGT 38
+CONSTANT: LLVMIntSGE 39
+CONSTANT: LLVMIntSLT 40
+CONSTANT: LLVMIntSLE 41
+TYPEDEF: enum LLVMIntPredicate
+
+C-ENUM:
+ LLVMRealPredicateFalse
+ LLVMRealOEQ
+ LLVMRealOGT
+ LLVMRealOGE
+ LLVMRealOLT
+ LLVMRealOLE
+ LLVMRealONE
+ LLVMRealORD
+ LLVMRealUNO
+ LLVMRealUEQ
+ LLVMRealUGT
+ LLVMRealUGE
+ LLVMRealULT
+ LLVMRealULE
+ LLVMRealUNE
+ LLVMRealPredicateTrue ;
+TYPEDEF: enum LLVMRealPredicate
+
+! Opaque Types
+
+TYPEDEF: void* LLVMModuleRef
+
+TYPEDEF: void* LLVMPassManagerRef
+
+TYPEDEF: void* LLVMModuleProviderRef
+
+TYPEDEF: void* LLVMTypeRef
+
+TYPEDEF: void* LLVMTypeHandleRef
+
+TYPEDEF: void* LLVMValueRef
+
+TYPEDEF: void* LLVMBasicBlockRef
+
+TYPEDEF: void* LLVMBuilderRef
+
+TYPEDEF: void* LLVMMemoryBufferRef
+
+! Functions
+
+FUNCTION: void LLVMDisposeMessage ( char* Message ) ;
+
+FUNCTION: LLVMModuleRef LLVMModuleCreateWithName ( char* ModuleID ) ;
+
+FUNCTION: int LLVMAddTypeName ( LLVMModuleRef M, char* Name, LLVMTypeRef Ty ) ;
+
+FUNCTION: void LLVMDisposeModule ( LLVMModuleRef M ) ;
+
+FUNCTION: void LLVMDumpModule ( LLVMModuleRef M ) ;
+
+FUNCTION: LLVMModuleProviderRef
+LLVMCreateModuleProviderForExistingModule ( LLVMModuleRef M ) ;
+
+FUNCTION: void LLVMDisposeModuleProvider ( LLVMModuleProviderRef MP ) ;
+
+! Types
+
+! LLVM types conform to the following hierarchy:
+!
+! types:
+! integer type
+! real type
+! function type
+! sequence types:
+! array type
+! pointer type
+! vector type
+! void type
+! label type
+! opaque type
+
+! See llvm::LLVMTypeKind::getTypeID.
+FUNCTION: LLVMTypeKind LLVMGetTypeKind ( LLVMTypeRef Ty ) ;
+
+! Operations on integer types
+FUNCTION: LLVMTypeRef LLVMInt1Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMInt8Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMInt16Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMInt32Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMInt64Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMIntType ( unsigned NumBits ) ;
+FUNCTION: unsigned LLVMGetIntTypeWidth ( LLVMTypeRef IntegerTy ) ;
+
+! Operations on real types
+FUNCTION: LLVMTypeRef LLVMFloatType ( ) ;
+FUNCTION: LLVMTypeRef LLVMDoubleType ( ) ;
+FUNCTION: LLVMTypeRef LLVMX86FP80Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMFP128Type ( ) ;
+FUNCTION: LLVMTypeRef LLVMPPCFP128Type ( ) ;
+
+! Operations on function types
+FUNCTION: LLVMTypeRef
+LLVMFunctionType ( LLVMTypeRef ReturnType, LLVMTypeRef* ParamTypes, unsigned ParamCount, int IsVarArg ) ;
+FUNCTION: int LLVMIsFunctionVarArg ( LLVMTypeRef FunctionTy ) ;
+FUNCTION: LLVMTypeRef LLVMGetReturnType ( LLVMTypeRef FunctionTy ) ;
+FUNCTION: unsigned LLVMCountParamTypes ( LLVMTypeRef FunctionTy ) ;
+FUNCTION: void LLVMGetParamTypes ( LLVMTypeRef FunctionTy, LLVMTypeRef* Dest ) ;
+
+! Operations on struct types
+FUNCTION: LLVMTypeRef
+LLVMStructType ( LLVMTypeRef* ElementTypes, unsigned ElementCount, int Packed ) ;
+FUNCTION: unsigned LLVMCountStructElementTypes ( LLVMTypeRef StructTy ) ;
+FUNCTION: void LLVMGetStructElementTypes ( LLVMTypeRef StructTy, LLVMTypeRef* Dest ) ;
+FUNCTION: int LLVMIsPackedStruct ( LLVMTypeRef StructTy ) ;
+
+! Operations on array, pointer, and vector types (sequence types)
+FUNCTION: LLVMTypeRef LLVMArrayType ( LLVMTypeRef ElementType, unsigned ElementCount ) ;
+FUNCTION: LLVMTypeRef LLVMPointerType ( LLVMTypeRef ElementType, unsigned AddressSpace ) ;
+FUNCTION: LLVMTypeRef LLVMVectorType ( LLVMTypeRef ElementType, unsigned ElementCount ) ;
+
+FUNCTION: LLVMTypeRef LLVMGetElementType ( LLVMTypeRef Ty ) ;
+FUNCTION: unsigned LLVMGetArrayLength ( LLVMTypeRef ArrayTy ) ;
+FUNCTION: unsigned LLVMGetPointerAddressSpace ( LLVMTypeRef PointerTy ) ;
+FUNCTION: unsigned LLVMGetVectorSize ( LLVMTypeRef VectorTy ) ;
+
+! Operations on other types
+FUNCTION: LLVMTypeRef LLVMVoidType ( ) ;
+FUNCTION: LLVMTypeRef LLVMLabelType ( ) ;
+FUNCTION: LLVMTypeRef LLVMOpaqueType ( ) ;
+
+! Operations on type handles
+FUNCTION: LLVMTypeHandleRef LLVMCreateTypeHandle ( LLVMTypeRef PotentiallyAbstractTy ) ;
+FUNCTION: void LLVMRefineType ( LLVMTypeRef AbstractTy, LLVMTypeRef ConcreteTy ) ;
+FUNCTION: LLVMTypeRef LLVMResolveTypeHandle ( LLVMTypeHandleRef TypeHandle ) ;
+FUNCTION: void LLVMDisposeTypeHandle ( LLVMTypeHandleRef TypeHandle ) ;
+
+! Types end
+
+FUNCTION: unsigned LLVMCountParams ( LLVMValueRef Fn ) ;
+
+FUNCTION: void LLVMGetParams ( LLVMValueRef Fn, LLVMValueRef* Params ) ;
+
+FUNCTION: LLVMValueRef
+LLVMAddFunction ( LLVMModuleRef M, char* Name, LLVMTypeRef FunctionTy ) ;
+
+FUNCTION: LLVMValueRef LLVMGetFirstFunction ( LLVMModuleRef M ) ;
+
+FUNCTION: LLVMValueRef LLVMGetNextFunction ( LLVMValueRef Fn ) ;
+
+FUNCTION: unsigned LLVMGetFunctionCallConv ( LLVMValueRef Fn ) ;
+
+FUNCTION: void LLVMSetFunctionCallConv ( LLVMValueRef Fn, unsigned CC ) ;
+
+FUNCTION: LLVMBasicBlockRef
+LLVMAppendBasicBlock ( LLVMValueRef Fn, char* Name ) ;
+
+FUNCTION: LLVMValueRef LLVMGetBasicBlockParent ( LLVMBasicBlockRef BB ) ;
+
+! Values
+
+FUNCTION: LLVMTypeRef LLVMTypeOf ( LLVMValueRef Val ) ;
+FUNCTION: char* LLVMGetValueName ( LLVMValueRef Val ) ;
+FUNCTION: void LLVMSetValueName ( LLVMValueRef Val, char* Name ) ;
+FUNCTION: void LLVMDumpValue ( LLVMValueRef Val ) ;
+
+! Instruction Builders
+
+FUNCTION: LLVMBuilderRef LLVMCreateBuilder ( ) ;
+FUNCTION: void LLVMPositionBuilder
+( LLVMBuilderRef Builder, LLVMBasicBlockRef Block, LLVMValueRef Instr ) ;
+FUNCTION: void LLVMPositionBuilderBefore
+( LLVMBuilderRef Builder, LLVMValueRef Instr ) ;
+FUNCTION: void LLVMPositionBuilderAtEnd
+( LLVMBuilderRef Builder, LLVMBasicBlockRef Block ) ;
+FUNCTION: LLVMBasicBlockRef LLVMGetInsertBlock
+( LLVMBuilderRef Builder ) ;
+FUNCTION: void LLVMClearInsertionPosition
+( LLVMBuilderRef Builder ) ;
+FUNCTION: void LLVMInsertIntoBuilder
+( LLVMBuilderRef Builder, LLVMValueRef Instr ) ;
+FUNCTION: void LLVMDisposeBuilder
+( LLVMBuilderRef Builder ) ;
+
+! IB Terminators
+
+FUNCTION: LLVMValueRef LLVMBuildRetVoid
+( LLVMBuilderRef Builder ) ;
+FUNCTION: LLVMValueRef LLVMBuildRet
+( LLVMBuilderRef Builder, LLVMValueRef V ) ;
+FUNCTION: LLVMValueRef LLVMBuildBr
+( LLVMBuilderRef Builder, LLVMBasicBlockRef Dest ) ;
+FUNCTION: LLVMValueRef LLVMBuildCondBr
+( LLVMBuilderRef Builder, LLVMValueRef If, LLVMBasicBlockRef Then, LLVMBasicBlockRef Else ) ;
+FUNCTION: LLVMValueRef LLVMBuildSwitch
+( LLVMBuilderRef Builder, LLVMValueRef V, LLVMBasicBlockRef Else, unsigned NumCases ) ;
+FUNCTION: LLVMValueRef LLVMBuildInvoke
+( LLVMBuilderRef Builder, LLVMValueRef Fn, LLVMValueRef* Args, unsigned NumArgs,
+ LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildUnwind
+( LLVMBuilderRef Builder ) ;
+FUNCTION: LLVMValueRef LLVMBuildUnreachable
+( LLVMBuilderRef Builder ) ;
+
+! IB Add Case to Switch
+
+FUNCTION: void LLVMAddCase
+( LLVMValueRef Switch, LLVMValueRef OnVal, LLVMBasicBlockRef Dest ) ;
+
+! IB Arithmetic
+
+FUNCTION: LLVMValueRef LLVMBuildAdd
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildSub
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildMul
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildUDiv
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildSDiv
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFDiv
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildURem
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildSRem
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFRem
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildShl
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildLShr
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildAShr
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildAnd
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildOr
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildXor
+( LLVMBuilderRef Builder, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildNeg
+( LLVMBuilderRef Builder, LLVMValueRef V, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildNot
+( LLVMBuilderRef Builder, LLVMValueRef V, char* Name ) ;
+
+! IB Memory
+
+FUNCTION: LLVMValueRef LLVMBuildMalloc
+( LLVMBuilderRef Builder, LLVMTypeRef Ty, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildArrayMalloc
+( LLVMBuilderRef Builder, LLVMTypeRef Ty, LLVMValueRef Val, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildAlloca
+( LLVMBuilderRef Builder, LLVMTypeRef Ty, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildArrayAlloca
+( LLVMBuilderRef Builder, LLVMTypeRef Ty, LLVMValueRef Val, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFree
+( LLVMBuilderRef Builder, LLVMValueRef PointerVal ) ;
+FUNCTION: LLVMValueRef LLVMBuildLoad
+( LLVMBuilderRef Builder, LLVMValueRef PointerVal, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildStore
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMValueRef Ptr ) ;
+FUNCTION: LLVMValueRef LLVMBuildGEP
+( LLVMBuilderRef B, LLVMValueRef Pointer, LLVMValueRef* Indices,
+ unsigned NumIndices, char* Name ) ;
+
+! IB Casts
+
+FUNCTION: LLVMValueRef LLVMBuildTrunc
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildZExt
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildSExt
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFPToUI
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFPToSI
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildUIToFP
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildSIToFP
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFPTrunc
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFPExt
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildPtrToInt
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildIntToPtr
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildBitCast
+( LLVMBuilderRef Builder, LLVMValueRef Val, LLVMTypeRef DestTy, char* Name ) ;
+
+! IB Comparisons
+
+FUNCTION: LLVMValueRef LLVMBuildICmp
+( LLVMBuilderRef Builder, LLVMIntPredicate Op, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildFCmp
+( LLVMBuilderRef Builder, LLVMRealPredicate Op, LLVMValueRef LHS, LLVMValueRef RHS, char* Name ) ;
+
+! IB Misc Instructions
+
+FUNCTION: LLVMValueRef LLVMBuildPhi
+( LLVMBuilderRef Builder, LLVMTypeRef Ty, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildCall
+( LLVMBuilderRef Builder, LLVMValueRef Fn, LLVMValueRef* Args, unsigned NumArgs, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildSelect
+( LLVMBuilderRef Builder, LLVMValueRef If, LLVMValueRef Then, LLVMValueRef Else, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildVAArg
+( LLVMBuilderRef Builder, LLVMValueRef List, LLVMTypeRef Ty, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildExtractElement
+( LLVMBuilderRef Builder, LLVMValueRef VecVal, LLVMValueRef Index, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildInsertElement
+( LLVMBuilderRef Builder, LLVMValueRef VecVal, LLVMValueRef EltVal, LLVMValueRef Index, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildShuffleVector
+( LLVMBuilderRef Builder, LLVMValueRef V1, LLVMValueRef V2, LLVMValueRef Mask, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildExtractValue
+( LLVMBuilderRef Builder, LLVMValueRef AggVal, unsigned Index, char* Name ) ;
+FUNCTION: LLVMValueRef LLVMBuildInsertValue
+( LLVMBuilderRef Builder, LLVMValueRef AggVal, LLVMValueRef EltVal, unsigned Index, char* Name ) ;
+
+! Memory Buffers/Bit Reader
+
+FUNCTION: int LLVMCreateMemoryBufferWithContentsOfFile
+( char* Path, LLVMMemoryBufferRef* OutMemBuf, char** OutMessage ) ;
+
+FUNCTION: void LLVMDisposeMemoryBuffer ( LLVMMemoryBufferRef MemBuf ) ;
+
+LIBRARY: LLVMBitReader
+
+FUNCTION: int LLVMParseBitcode
+( LLVMMemoryBufferRef MemBuf, LLVMModuleRef* OutModule, char** OutMessage ) ;
+
+FUNCTION: int LLVMGetBitcodeModuleProvider
+( LLVMMemoryBufferRef MemBuf, LLVMModuleProviderRef* OutMP, char** OutMessage ) ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.libraries alien.syntax llvm.core ;
+IN: llvm.engine
+
+<<
+
+"LLVMExecutionEngine" add-llvm-library
+"LLVMTarget" add-llvm-library
+"LLVMAnalysis" add-llvm-library
+"LLVMipa" add-llvm-library
+"LLVMTransformUtils" add-llvm-library
+"LLVMScalarOpts" add-llvm-library
+"LLVMCodeGen" add-llvm-library
+"LLVMAsmPrinter" add-llvm-library
+"LLVMSelectionDAG" add-llvm-library
+"LLVMX86CodeGen" add-llvm-library
+"LLVMJIT" add-llvm-library
+"LLVMInterpreter" add-llvm-library
+
+>>
+
+! llvm-c/ExecutionEngine.h
+
+LIBRARY: LLVMExecutionEngine
+
+TYPEDEF: void* LLVMGenericValueRef
+TYPEDEF: void* LLVMExecutionEngineRef
+
+FUNCTION: LLVMGenericValueRef LLVMCreateGenericValueOfInt
+( LLVMTypeRef Ty, ulonglong N, int IsSigned ) ;
+
+FUNCTION: ulonglong LLVMGenericValueToInt
+( LLVMGenericValueRef GenVal, int IsSigned ) ;
+
+FUNCTION: int LLVMCreateExecutionEngine
+( LLVMExecutionEngineRef *OutEE, LLVMModuleProviderRef MP, char** OutError ) ;
+
+FUNCTION: int LLVMCreateJITCompiler
+( LLVMExecutionEngineRef* OutJIT, LLVMModuleProviderRef MP, unsigned OptLevel, char** OutError ) ;
+
+FUNCTION: void LLVMDisposeExecutionEngine ( LLVMExecutionEngineRef EE ) ;
+
+FUNCTION: void LLVMFreeMachineCodeForFunction ( LLVMExecutionEngineRef EE, LLVMValueRef F ) ;
+
+FUNCTION: void LLVMAddModuleProvider ( LLVMExecutionEngineRef EE, LLVMModuleProviderRef MP ) ;
+
+FUNCTION: int LLVMRemoveModuleProvider
+( LLVMExecutionEngineRef EE, LLVMModuleProviderRef MP, LLVMModuleRef* OutMod, char** OutError ) ;
+
+FUNCTION: int LLVMFindFunction
+( LLVMExecutionEngineRef EE, char* Name, LLVMValueRef* OutFn ) ;
+
+FUNCTION: void* LLVMGetPointerToGlobal ( LLVMExecutionEngineRef EE, LLVMValueRef Global ) ;
+
+FUNCTION: LLVMGenericValueRef LLVMRunFunction
+( LLVMExecutionEngineRef EE, LLVMValueRef F, unsigned NumArgs, LLVMGenericValueRef* Args ) ;
\ No newline at end of file
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.llvm io.pathnames llvm.invoker llvm.reader tools.test ;
+
+[ 3 ] [
+ << "resource:extra/llvm/reader/add.bc" install-bc >> 1 2 add
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien arrays assocs compiler.units effects
+io.backend io.pathnames kernel llvm.core llvm.jit llvm.reader
+llvm.types make namespaces sequences specialized-arrays.alien
+vocabs words ;
+
+IN: llvm.invoker
+
+! get function name, ret type, param types and names
+
+! load module
+! iterate through functions in a module
+
+TUPLE: function name alien return params ;
+
+: params ( llvm-function -- param-list )
+ dup LLVMCountParams <void*-array>
+ [ LLVMGetParams ] keep >array
+ [ [ LLVMGetValueName ] [ LLVMTypeOf tref> ] bi 2array ] map ;
+
+: <function> ( LLVMValueRef -- function )
+ function new
+ over LLVMGetValueName >>name
+ over LLVMTypeOf tref> type>> return>> >>return
+ swap params >>params ;
+
+: (functions) ( llvm-function -- )
+ [ dup , LLVMGetNextFunction (functions) ] when* ;
+
+: functions ( llvm-module -- functions )
+ LLVMGetFirstFunction [ (functions) ] { } make [ <function> ] map ;
+
+: function-effect ( function -- effect )
+ [ params>> [ first ] map ] [ return>> void? 0 1 ? ] bi <effect> ;
+
+: install-function ( function -- )
+ dup name>> "alien.llvm" create-vocab drop
+ "alien.llvm" create swap
+ [
+ dup name>> function-pointer ,
+ dup return>> c-type ,
+ dup params>> [ second c-type ] map ,
+ "cdecl" , \ alien-indirect ,
+ ] [ ] make swap function-effect [ define-declared ] with-compilation-unit ;
+
+: install-module ( name -- )
+ thejit get mps>> at [
+ module>> functions [ install-function ] each
+ ] [ "no such module" throw ] if* ;
+
+: install-bc ( path -- )
+ [ normalize-path ] [ file-name ] bi
+ [ load-into-jit ] keep install-module ;
+
+<< "alien.llvm" create-vocab drop >>
\ No newline at end of file
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: destructors llvm.jit llvm.wrappers tools.test ;
+
+[ ] [ "test" <module> "test" add-module "test" remove-module ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.syntax assocs destructors
+kernel llvm.core llvm.engine llvm.wrappers namespaces ;
+
+IN: llvm.jit
+
+SYMBOL: thejit
+
+TUPLE: jit ee mps ;
+
+: empty-engine ( -- engine )
+ "initial-module" <module> <provider> <engine> ;
+
+: <jit> ( -- jit )
+ jit new empty-engine >>ee H{ } clone >>mps ;
+
+: (remove-functions) ( function -- )
+ thejit get ee>> value>> over LLVMFreeMachineCodeForFunction
+ LLVMGetNextFunction dup ALIEN: 0 = [ drop ] [ (remove-functions) ] if ;
+
+: remove-functions ( module -- )
+ ! free machine code for each function in module
+ LLVMGetFirstFunction dup ALIEN: 0 = [ drop ] [ (remove-functions) ] if ;
+
+: remove-provider ( provider -- )
+ thejit get ee>> value>> swap value>> f <void*> f <void*>
+ [ LLVMRemoveModuleProvider drop ] 2keep *void* [ llvm-throw ] when*
+ *void* module new swap >>value
+ [ value>> remove-functions ] with-disposal ;
+
+: remove-module ( name -- )
+ dup thejit get mps>> at [
+ remove-provider
+ thejit get mps>> delete-at
+ ] [ drop ] if* ;
+
+: add-module ( module name -- )
+ [ <provider> ] dip [ remove-module ] keep
+ thejit get ee>> value>> pick
+ [ [ value>> LLVMAddModuleProvider ] [ t >>disposed drop ] bi ] with-disposal
+ thejit get mps>> set-at ;
+
+: function-pointer ( name -- alien )
+ thejit get ee>> value>> dup
+ rot f <void*> [ LLVMFindFunction drop ] keep
+ *void* LLVMGetPointerToGlobal ;
+
+thejit [ <jit> ] initialize
\ No newline at end of file
--- /dev/null
+unportable
--- /dev/null
+define i32 @add(i32 %x, i32 %y) {
+entry:
+ %sum = add i32 %x, %y
+ ret i32 %sum
+}
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.syntax destructors kernel
+llvm.core llvm.engine llvm.jit llvm.wrappers ;
+
+IN: llvm.reader
+
+: buffer>module ( buffer -- module )
+ [
+ value>> f <void*> f <void*>
+ [ LLVMParseBitcode drop ] 2keep
+ *void* [ llvm-throw ] when* *void*
+ module new swap >>value
+ ] with-disposal ;
+
+: load-module ( path -- module )
+ <buffer> buffer>module ;
+
+: load-into-jit ( path name -- )
+ [ load-module ] dip add-module ;
\ No newline at end of file
--- /dev/null
+unportable
--- /dev/null
+bindings
+unportable
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel llvm.types sequences tools.test ;
+
+[ T{ integer f 32 } ] [ " i32 " parse-type ] unit-test
+[ float ] [ " float " parse-type ] unit-test
+[ T{ pointer f f x86_fp80 } ] [ " x86_fp80 * " parse-type ] unit-test
+[ T{ vector f f 4 T{ integer f 32 } } ] [ " < 4 x i32 > " parse-type ] unit-test
+[ T{ struct f f { float double } f } ] [ TYPE: { float , double } ; ] unit-test
+[ T{ array f f 0 float } ] [ TYPE: [ 0 x float ] ; ] unit-test
+
+[ label void metadata ]
+[ [ " label " " void " " metadata " ] [ parse-type ] each ] unit-test
+
+[ T{ function f f float { float float } t } ]
+[ TYPE: float ( float , float , ... ) ; ] unit-test
+
+[ T{ struct f f { float TYPE: i32 (i32)* ; } t } ]
+[ TYPE: < { float, i32 (i32)* } > ; ] unit-test
+
+[ t ] [ TYPE: i32 ; TYPE: i32 ; [ >tref ] bi@ = ] unit-test
+[ t ] [ TYPE: i32 * ; TYPE: i32 * ; [ >tref ] bi@ = ] unit-test
+
+[ TYPE: i32 ; ] [ TYPE: i32 ; >tref tref> ] unit-test
+[ TYPE: float ; ] [ TYPE: float ; >tref tref> ] unit-test
+[ TYPE: double ; ] [ TYPE: double ; >tref tref> ] unit-test
+[ TYPE: x86_fp80 ; ] [ TYPE: x86_fp80 ; >tref tref> ] unit-test
+[ TYPE: fp128 ; ] [ TYPE: fp128 ; >tref tref> ] unit-test
+[ TYPE: ppc_fp128 ; ] [ TYPE: ppc_fp128 ; >tref tref> ] unit-test
+[ TYPE: opaque ; ] [ TYPE: opaque ; >tref tref> ] unit-test
+[ TYPE: label ; ] [ TYPE: label ; >tref tref> ] unit-test
+[ TYPE: void ; ] [ TYPE: void ; >tref tref> ] unit-test
+[ TYPE: i32* ; ] [ TYPE: i32* ; >tref tref> ] unit-test
+[ TYPE: < 2 x i32 > ; ] [ TYPE: < 2 x i32 > ; >tref tref> ] unit-test
+[ TYPE: [ 0 x i32 ] ; ] [ TYPE: [ 0 x i32 ] ; >tref tref> ] unit-test
+[ TYPE: { i32, i32 } ; ] [ TYPE: { i32, i32 } ; >tref tref> ] unit-test
+[ TYPE: < { i32, i32 } > ; ] [ TYPE: < { i32, i32 } > ; >tref tref> ] unit-test
+[ TYPE: i32 ( i32 ) ; ] [ TYPE: i32 ( i32 ) ; >tref tref> ] unit-test
+[ TYPE: \1* ; ] [ TYPE: \1* ; >tref tref> ] unit-test
+[ TYPE: { i32, \2* } ; ] [ TYPE: { i32, \2* } ; >tref tref> ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays combinators kernel llvm.core
+locals math.parser math multiline
+namespaces parser peg.ebnf sequences
+sequences.deep specialized-arrays.alien strings vocabs words ;
+
+IN: llvm.types
+
+! Type resolution strategy:
+! pass 1:
+! create the type with uprefs mapped to opaque types
+! cache typerefs in enclosing types for pass 2
+! if our type is concrete, then we are done
+!
+! pass 2:
+! wrap our abstract type in a type handle
+! create a second type, using the cached enclosing type info
+! resolve the first type to the second
+!
+GENERIC: (>tref) ( type -- LLVMTypeRef )
+GENERIC: ((tref>)) ( LLVMTypeRef type -- type )
+GENERIC: c-type ( type -- str )
+
+! default implementation for simple types
+M: object ((tref>)) nip ;
+: unsupported-type ( -- )
+ "cannot generate c-type: unsupported llvm type" throw ;
+M: object c-type unsupported-type ;
+
+TUPLE: integer size ;
+C: <integer> integer
+
+M: integer (>tref) size>> LLVMIntType ;
+M: integer ((tref>)) swap LLVMGetIntTypeWidth >>size ;
+M: integer c-type size>> {
+ { 64 [ "longlong" ] }
+ { 32 [ "int" ] }
+ { 16 [ "short" ] }
+ { 8 [ "char" ] }
+ [ unsupported-type ]
+} case ;
+
+SINGLETONS: float double x86_fp80 fp128 ppc_fp128 ;
+
+M: float (>tref) drop LLVMFloatType ;
+M: double (>tref) drop LLVMDoubleType ;
+M: double c-type drop "double" ;
+M: x86_fp80 (>tref) drop LLVMX86FP80Type ;
+M: fp128 (>tref) drop LLVMFP128Type ;
+M: ppc_fp128 (>tref) drop LLVMPPCFP128Type ;
+
+SINGLETONS: opaque label void metadata ;
+
+M: opaque (>tref) drop LLVMOpaqueType ;
+M: label (>tref) drop LLVMLabelType ;
+M: void (>tref) drop LLVMVoidType ;
+M: void c-type drop "void" ;
+M: metadata (>tref) drop
+ "metadata types unsupported by llvm c bindings" throw ;
+
+! enclosing types cache their llvm refs during
+! the first pass, used in the second pass to
+! resolve uprefs
+TUPLE: enclosing cached ;
+
+GENERIC: clean ( type -- )
+GENERIC: clean* ( type -- )
+M: object clean drop ;
+M: enclosing clean f >>cached clean* ;
+
+! builds the stack of types that uprefs need to refer to
+SYMBOL: types
+:: push-type ( type quot: ( type -- LLVMTypeRef ) -- LLVMTypeRef )
+ type types get push
+ type quot call( type -- LLVMTypeRef )
+ types get pop over >>cached drop ;
+
+DEFER: <up-ref>
+:: push-ref ( ref quot: ( LLVMTypeRef -- type ) -- type )
+ ref types get index
+ [ types get length swap - <up-ref> ] [
+ ref types get push
+ ref quot call( LLVMTypeRef -- type )
+ types get pop drop
+ ] if* ;
+
+GENERIC: (>tref)* ( type -- LLVMTypeRef )
+M: enclosing (>tref) [ (>tref)* ] push-type ;
+
+DEFER: type-kind
+GENERIC: (tref>)* ( LLVMTypeRef type -- type )
+M: enclosing ((tref>)) [ (tref>)* ] curry push-ref ;
+
+: (tref>) ( LLVMTypeRef -- type ) dup type-kind ((tref>)) ;
+
+TUPLE: pointer < enclosing type ;
+: <pointer> ( t -- o ) pointer new swap >>type ;
+
+M: pointer (>tref)* type>> (>tref) 0 LLVMPointerType ;
+M: pointer clean* type>> clean ;
+M: pointer (tref>)* swap LLVMGetElementType (tref>) >>type ;
+M: pointer c-type type>> 8 <integer> = "char*" "void*" ? ;
+
+TUPLE: vector < enclosing size type ;
+: <vector> ( s t -- o )
+ vector new
+ swap >>type swap >>size ;
+
+M: vector (>tref)* [ type>> (>tref) ] [ size>> ] bi LLVMVectorType ;
+M: vector clean* type>> clean ;
+M: vector (tref>)*
+ over LLVMGetElementType (tref>) >>type
+ swap LLVMGetVectorSize >>size ;
+
+TUPLE: struct < enclosing types packed? ;
+: <struct> ( ts p? -- o )
+ struct new
+ swap >>packed? swap >>types ;
+
+M: struct (>tref)*
+ [ types>> [ (>tref) ] map >void*-array ]
+ [ types>> length ]
+ [ packed?>> 1 0 ? ] tri LLVMStructType ;
+M: struct clean* types>> [ clean ] each ;
+M: struct (tref>)*
+ over LLVMIsPackedStruct 0 = not >>packed?
+ swap dup LLVMCountStructElementTypes <void*-array>
+ [ LLVMGetStructElementTypes ] keep >array
+ [ (tref>) ] map >>types ;
+
+TUPLE: array < enclosing size type ;
+: <array> ( s t -- o )
+ array new
+ swap >>type swap >>size ;
+
+M: array (>tref)* [ type>> (>tref) ] [ size>> ] bi LLVMArrayType ;
+M: array clean* type>> clean ;
+M: array (tref>)*
+ over LLVMGetElementType (tref>) >>type
+ swap LLVMGetArrayLength >>size ;
+
+SYMBOL: ...
+TUPLE: function < enclosing return params vararg? ;
+: <function> ( ret params var? -- o )
+ function new
+ swap >>vararg? swap >>params swap >>return ;
+
+M: function (>tref)* {
+ [ return>> (>tref) ]
+ [ params>> [ (>tref) ] map >void*-array ]
+ [ params>> length ]
+ [ vararg?>> 1 0 ? ]
+} cleave LLVMFunctionType ;
+M: function clean* [ return>> clean ] [ params>> [ clean ] each ] bi ;
+M: function (tref>)*
+ over LLVMIsFunctionVarArg 0 = not >>vararg?
+ over LLVMGetReturnType (tref>) >>return
+ swap dup LLVMCountParamTypes <void*-array>
+ [ LLVMGetParamTypes ] keep >array
+ [ (tref>) ] map >>params ;
+
+: type-kind ( LLVMTypeRef -- class )
+ LLVMGetTypeKind {
+ { LLVMVoidTypeKind [ void ] }
+ { LLVMFloatTypeKind [ float ] }
+ { LLVMDoubleTypeKind [ double ] }
+ { LLVMX86_FP80TypeKind [ x86_fp80 ] }
+ { LLVMFP128TypeKind [ fp128 ] }
+ { LLVMPPC_FP128TypeKind [ ppc_fp128 ] }
+ { LLVMLabelTypeKind [ label ] }
+ { LLVMIntegerTypeKind [ integer new ] }
+ { LLVMFunctionTypeKind [ function new ] }
+ { LLVMStructTypeKind [ struct new ] }
+ { LLVMArrayTypeKind [ array new ] }
+ { LLVMPointerTypeKind [ pointer new ] }
+ { LLVMOpaqueTypeKind [ opaque ] }
+ { LLVMVectorTypeKind [ vector new ] }
+ } case ;
+
+TUPLE: up-ref height ;
+C: <up-ref> up-ref
+
+M: up-ref (>tref)
+ types get length swap height>> - types get nth
+ cached>> [ LLVMOpaqueType ] unless* ;
+
+: resolve-types ( typeref typeref -- typeref )
+ over LLVMCreateTypeHandle [ LLVMRefineType ] dip
+ [ LLVMResolveTypeHandle ] keep LLVMDisposeTypeHandle ;
+
+: >tref-caching ( type -- LLVMTypeRef )
+ V{ } clone types [ (>tref) ] with-variable ;
+
+: >tref ( type -- LLVMTypeRef )
+ [ >tref-caching ] [ >tref-caching ] [ clean ] tri
+ 2dup = [ drop ] [ resolve-types ] if ;
+
+: tref> ( LLVMTypeRef -- type )
+ V{ } clone types [ (tref>) ] with-variable ;
+
+: t. ( type -- )
+ >tref
+ "type-info" LLVMModuleCreateWithName
+ [ "t" rot LLVMAddTypeName drop ]
+ [ LLVMDumpModule ]
+ [ LLVMDisposeModule ] tri ;
+
+EBNF: parse-type
+
+WhiteSpace = " "*
+
+Zero = "0" => [[ drop 0 ]]
+LeadingDigit = [1-9]
+DecimalDigit = [0-9]
+Number = LeadingDigit:d (DecimalDigit)*:ds => [[ ds d prefix string>number ]]
+WhiteNumberSpace = WhiteSpace Number:n WhiteSpace => [[ n ]]
+WhiteZeroSpace = WhiteSpace (Zero | Number):n WhiteSpace => [[ n ]]
+
+Integer = "i" Number:n => [[ n <integer> ]]
+FloatingPoint = ( "float" | "double" | "x86_fp80" | "fp128" | "ppc_fp128" ) => [[ "llvm.types" vocab lookup ]]
+LabelVoidMetadata = ( "label" | "void" | "metadata" | "opaque" ) => [[ "llvm.types" vocab lookup ]]
+Primitive = LabelVoidMetadata | FloatingPoint
+Pointer = T:t WhiteSpace "*" => [[ t <pointer> ]]
+Vector = "<" WhiteNumberSpace:n "x" Type:t ">" => [[ n t <vector> ]]
+StructureTypesList = "," Type:t => [[ t ]]
+Structure = "{" Type:t (StructureTypesList)*:ts "}" => [[ ts t prefix >array f <struct> ]]
+Array = "[" WhiteZeroSpace:n "x" Type:t "]" => [[ n t <array> ]]
+NoFunctionParams = "(" WhiteSpace ")" => [[ drop { } ]]
+VarArgs = WhiteSpace "..." WhiteSpace => [[ drop ... ]]
+ParamListContinued = "," (Type | VarArgs):t => [[ t ]]
+ParamList = "(" Type:t (ParamListContinued*):ts ")" => [[ ts t prefix ]]
+Function = T:t WhiteSpace ( ParamList | NoFunctionParams ):ts => [[ ... ts member? dup [ ... ts delete ] when t ts >array rot <function> ]]
+PackedStructure = "<" WhiteSpace "{" Type:ty (StructureTypesList)*:ts "}" WhiteSpace ">" => [[ ts ty prefix >array t <struct> ]]
+UpReference = "\\" Number:n => [[ n <up-ref> ]]
+Name = '%' ([a-zA-Z][a-zA-Z0-9]*):id => [[ id flatten >string ]]
+
+T = Pointer | Function | Primitive | Integer | Vector | Structure | PackedStructure | Array | UpReference | Name
+
+Type = WhiteSpace T:t WhiteSpace => [[ t ]]
+
+Program = Type
+
+;EBNF
+
+SYNTAX: TYPE: ";" parse-multiline-string parse-type parsed ;
\ No newline at end of file
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: destructors kernel llvm.wrappers sequences tools.test vocabs ;
+
+[ ] [ "test" <module> dispose ] unit-test
+[ ] [ "test" <module> <provider> dispose ] unit-test
+[ ] [ "llvm.jit" vocabs member? [ "test" <module> <provider> <engine> dispose ] unless ] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Matthew Willis.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.strings
+io.encodings.utf8 destructors kernel
+llvm.core llvm.engine ;
+
+IN: llvm.wrappers
+
+: llvm-throw ( char* -- )
+ [ utf8 alien>string ] [ LLVMDisposeMessage ] bi throw ;
+
+: <dispose> ( alien class -- disposable ) new swap >>value ;
+
+TUPLE: module value disposed ;
+M: module dispose* value>> LLVMDisposeModule ;
+
+: <module> ( name -- module )
+ LLVMModuleCreateWithName module <dispose> ;
+
+TUPLE: provider value module disposed ;
+M: provider dispose* value>> LLVMDisposeModuleProvider ;
+
+: (provider) ( module -- provider )
+ [ value>> LLVMCreateModuleProviderForExistingModule provider <dispose> ]
+ [ t >>disposed value>> ] bi
+ >>module ;
+
+: <provider> ( module -- provider )
+ [ (provider) ] with-disposal ;
+
+TUPLE: engine value disposed ;
+M: engine dispose* value>> LLVMDisposeExecutionEngine ;
+
+: (engine) ( provider -- engine )
+ [
+ value>> f <void*> f <void*>
+ [ swapd 0 swap LLVMCreateJITCompiler drop ] 2keep
+ *void* [ llvm-throw ] when* *void*
+ ]
+ [ t >>disposed drop ] bi
+ engine <dispose> ;
+
+: <engine> ( provider -- engine )
+ [ (engine) ] with-disposal ;
+
+: (add-block) ( name -- basic-block )
+ "function" swap LLVMAppendBasicBlock ;
+
+TUPLE: builder value disposed ;
+M: builder dispose* value>> LLVMDisposeBuilder ;
+
+: <builder> ( name -- builder )
+ (add-block) LLVMCreateBuilder [ swap LLVMPositionBuilderAtEnd ] keep
+ builder <dispose> ;
+
+TUPLE: buffer value disposed ;
+M: buffer dispose* value>> LLVMDisposeMemoryBuffer ;
+
+: <buffer> ( path -- module )
+ f <void*> f <void*>
+ [ LLVMCreateMemoryBufferWithContentsOfFile drop ] 2keep
+ *void* [ llvm-throw ] when* *void* buffer <dispose> ;
\ No newline at end of file
! Copyright (C) 2008 Doug Coleman, Slava Pestov, Aaron Schaefer.
! See http://factorcode.org/license.txt for BSD license.
-USING: combinators.short-circuit kernel math math.constants math.functions
- math.vectors sequences ;
+USING: combinators.short-circuit kernel math math.constants
+math.functions math.vectors sequences ;
IN: math.analysis
<PRIVATE
: stirling-fact ( n -- fact )
[ pi 2 * * sqrt ]
[ [ e / ] keep ^ ]
- [ 12 * recip 1+ ] tri * * ;
+ [ 12 * recip 1 + ] tri * * ;
MACRO: chain-rule ( word -- e )
[ input-length '[ _ duals>nweave ] ]
[ "derivative" word-prop ]
- [ input-length 1+ '[ _ nspread ] ]
+ [ input-length 1 + '[ _ nspread ] ]
tri
'[ [ @ _ @ ] sum-outputs ] ;
! Specialize math functions to operate on dual numbers.
[ all-words [ "derivative" word-prop ] filter
- [ define-dual ] each ] with-compilation-unit
\ No newline at end of file
+ [ define-dual ] each ] with-compilation-unit
<PRIVATE
: weighted ( x y a -- z )
- tuck [ * ] [ 1- neg * ] 2bi* + ;
+ tuck [ * ] [ 1 - neg * ] 2bi* + ;
: a ( n -- a )
- 1+ 2 swap / ;
+ 1 + 2 swap / ;
PRIVATE>
: lprimes ( -- list ) 2 [ next-prime ] lfrom-by ;
: lprimes-from ( n -- list )
- dup 3 < [ drop lprimes ] [ 1- next-prime [ next-prime ] lfrom-by ] if ;
+ dup 3 < [ drop lprimes ] [ 1 - next-prime [ next-prime ] lfrom-by ] if ;
HELP: number>text
{ $values { "n" integer } { "str" string } }
{ $description "Converts an integer to a text string representation in English, including appropriate punctuation and conjunctions." }
-{ $examples { $example "USING: math.text.english prettyprint ;" "12345 number>text ." "\"Twelve Thousand, Three Hundred and Forty-Five\"" } } ;
+{ $examples { $example "USING: math.text.english prettyprint ;" "12345 number>text ." "\"twelve thousand, three hundred and forty-five\"" } } ;
USING: math.functions math.text.english tools.test ;
IN: math.text.english.tests
-[ "Zero" ] [ 0 number>text ] unit-test
-[ "Twenty-One" ] [ 21 number>text ] unit-test
-[ "One Hundred" ] [ 100 number>text ] unit-test
-[ "One Hundred and One" ] [ 101 number>text ] unit-test
-[ "One Thousand and One" ] [ 1001 number>text ] unit-test
-[ "One Thousand, One Hundred and One" ] [ 1101 number>text ] unit-test
-[ "One Million, One Thousand and One" ] [ 1001001 number>text ] unit-test
-[ "One Million, One Thousand, One Hundred and One" ] [ 1001101 number>text ] unit-test
-[ "One Million, One Hundred and Eleven Thousand, One Hundred and Eleven" ] [ 1111111 number>text ] unit-test
-[ "One Duotrigintillion" ] [ 10 99 ^ number>text ] unit-test
+[ "zero" ] [ 0 number>text ] unit-test
+[ "twenty-one" ] [ 21 number>text ] unit-test
+[ "one hundred" ] [ 100 number>text ] unit-test
+[ "one hundred and one" ] [ 101 number>text ] unit-test
+[ "one thousand and one" ] [ 1001 number>text ] unit-test
+[ "one thousand, one hundred and one" ] [ 1101 number>text ] unit-test
+[ "one million, one thousand and one" ] [ 1001001 number>text ] unit-test
+[ "one million, one thousand, one hundred and one" ] [ 1001101 number>text ] unit-test
+[ "one million, one hundred and eleven thousand, one hundred and eleven" ] [ 1111111 number>text ] unit-test
+[ "one duotrigintillion" ] [ 10 99 ^ number>text ] unit-test
-[ "Negative One Hundred and Twenty-Three" ] [ -123 number>text ] unit-test
+[ "negative one hundred and twenty-three" ] [ -123 number>text ] unit-test
<PRIVATE
: small-numbers ( n -- str )
- { "Zero" "One" "Two" "Three" "Four" "Five" "Six" "Seven" "Eight" "Nine"
- "Ten" "Eleven" "Twelve" "Thirteen" "Fourteen" "Fifteen" "Sixteen"
- "Seventeen" "Eighteen" "Nineteen" } nth ;
+ {
+ "zero" "one" "two" "three" "four" "five" "six"
+ "seven" "eight" "nine" "ten" "eleven" "twelve"
+ "thirteen" "fourteen" "fifteen" "sixteen" "seventeen"
+ "eighteen" "nineteen"
+ } nth ;
: tens ( n -- str )
- { f f "Twenty" "Thirty" "Forty" "Fifty" "Sixty" "Seventy" "Eighty" "Ninety" } nth ;
-
+ {
+ f f "twenty" "thirty" "forty" "fifty" "sixty"
+ "seventy" "eighty" "ninety"
+ } nth ;
+
: scale-numbers ( n -- str ) ! up to 10^99
- { f "Thousand" "Million" "Billion" "Trillion" "Quadrillion" "Quintillion"
- "Sextillion" "Septillion" "Octillion" "Nonillion" "Decillion" "Undecillion"
- "Duodecillion" "Tredecillion" "Quattuordecillion" "Quindecillion"
- "Sexdecillion" "Septendecillion" "Octodecillion" "Novemdecillion"
- "Vigintillion" "Unvigintillion" "Duovigintillion" "Trevigintillion"
- "Quattuorvigintillion" "Quinvigintillion" "Sexvigintillion"
- "Septvigintillion" "Octovigintillion" "Novemvigintillion" "Trigintillion"
- "Untrigintillion" "Duotrigintillion" } nth ;
+ {
+ f "thousand" "million" "billion" "trillion" "quadrillion"
+ "quintillion" "sextillion" "septillion" "octillion"
+ "nonillion" "decillion" "undecillion" "duodecillion"
+ "tredecillion" "quattuordecillion" "quindecillion"
+ "sexdecillion" "septendecillion" "octodecillion" "novemdecillion"
+ "vigintillion" "unvigintillion" "duovigintillion" "trevigintillion"
+ "quattuorvigintillion" "quinvigintillion" "sexvigintillion"
+ "septvigintillion" "octovigintillion" "novemvigintillion"
+ "trigintillion" "untrigintillion" "duotrigintillion"
+ } nth ;
SYMBOL: and-needed?
: set-conjunction ( seq -- )
first { [ 100 < ] [ 0 > ] } 1&& and-needed? set ;
: negative-text ( n -- str )
- 0 < "Negative " "" ? ;
+ 0 < "negative " "" ? ;
: hundreds-place ( n -- str )
100 /mod over 0 = [
2drop ""
] [
- [ small-numbers " Hundred" append ] dip
+ [ small-numbers " hundred" append ] dip
0 = [ " and " append ] unless
] if ;
] if ;
: (number>text) ( n -- str )
- [ negative-text ] [ abs 3digit-groups recombine ] bi append ;
+ [ negative-text ] [ abs 3 digit-groups recombine ] bi append ;
PRIVATE>
} cond ;
: over-1000000 ( n -- str )
- 3digit-groups [ 1+ units nth n-units ] map-index sift
+ 3 digit-groups [ 1 + units nth n-units ] map-index sift
reverse " " join ;
: decompose ( n -- str ) 1000000 /mod [ over-1000000 ] dip complete ;
USING: help.markup help.syntax ;
IN: math.text.utils
-HELP: 3digit-groups
-{ $values { "n" "a positive integer" } { "seq" "a sequence" } }
-{ $description "Decompose a number into 3 digits groups and return them in a sequence, starting with the units, then the tenths, etc." } ;
+HELP: digit-groups
+{ $values { "n" "a positive integer" } { "k" "a positive integer" } { "seq" "a sequence" } }
+{ $description "Decompose a number into groups of " { $snippet "k" } " digits and return them in a sequence starting with the least significant grouped digits first." } ;
USING: math.text.utils tools.test ;
-[ { 1 999 2 } ] [ 2999001 3digit-groups ] unit-test
+[ { 1 999 2 } ] [ 2999001 3 digit-groups ] unit-test
! Copyright (c) 2007, 2008 Aaron Schaefer.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math sequences ;
+USING: kernel fry math.functions math sequences ;
IN: math.text.utils
-: 3digit-groups ( n -- seq )
- [ dup 0 > ] [ 1000 /mod ] produce nip ;
+: digit-groups ( n k -- seq )
+ [ dup 0 > ] swap '[ _ 10^ /mod ] produce nip ;
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: alien destructors help.markup help.syntax kernel math ;
+IN: memory.piles
+
+HELP: <pile>
+{ $values
+ { "size" integer }
+ { "pile" pile }
+}
+{ $description "Allocates " { $snippet "size" } " bytes of raw memory for a new " { $link pile } ". The pile should be " { $link dispose } "d when it is no longer needed." } ;
+
+HELP: not-enough-pile-space
+{ $values
+ { "pile" pile }
+}
+{ $description "This error is thrown by " { $link pile-alloc } " when the " { $link pile } " does not have enough remaining space for the requested allocation." } ;
+
+HELP: pile
+{ $class-description "A " { $snippet "pile" } " is a block of raw memory that can be apportioned out in constant time. A pile is allocated using the " { $link <pile> } " word. Blocks of memory can be requested from the pile using " { $link pile-alloc } ", and all the pile's memory can be reclaimed with " { $link pile-empty } "." } ;
+
+HELP: pile-align
+{ $values
+ { "pile" pile } { "align" "a power of two" }
+ { "pile" pile }
+}
+{ $description "Adjusts a " { $link pile } "'s internal state so that the next call to " { $link pile-alloc } " will return a pointer aligned to " { $snippet "align" } " bytes relative to the pile's initial offset." } ;
+
+HELP: pile-alloc
+{ $values
+ { "pile" pile } { "size" integer }
+ { "alien" alien }
+}
+{ $description "Requests " { $snippet "size" } " bytes from a " { $link pile } ". If the pile does not have enough space to satisfy the request, a " { $link not-enough-pile-space } " error is thrown." } ;
+
+HELP: <pile-c-array>
+{ $values
+ { "pile" pile } { "n" integer } { "c-type" "a C type" }
+ { "alien" alien }
+}
+{ $description "Requests enough space from a " { $link pile } " to hold " { $snippet "n" } " values of " { $snippet "c-type" } ". If the pile does not have enough space to satisfy the request, a " { $link not-enough-pile-space } " error is thrown." } ;
+
+HELP: <pile-c-object>
+{ $values
+ { "pile" pile } { "c-type" "a C type" }
+ { "alien" alien }
+}
+{ $description "Requests enough space from a " { $link pile } " to hold a value of " { $snippet "c-type" } ". If the pile does not have enough space to satisfy the request, a " { $link not-enough-pile-space } " error is thrown." } ;
+
+HELP: pile-empty
+{ $values
+ { "pile" pile }
+}
+{ $description "Reclaims all the memory allocated out of a " { $link pile } ". Allocations will resume from the beginning of the pile." } ;
+
+ARTICLE: "memory.piles" "Piles"
+"A " { $link pile } " is a block of raw memory. Portions of its memory can be allocated from the beginning of the pile in constant time, and the pile can be emptied and its pointer reset to the beginning."
+{ $subsection <pile> }
+{ $subsection pile-alloc }
+{ $subsection <pile-c-array> }
+{ $subsection <pile-c-object> }
+{ $subsection pile-align }
+{ $subsection pile-empty }
+"An example of the utility of piles is in video games. For example, the game Abuse was scripted with a Lisp dialect. In order to avoid stalls from traditional GC or heap-based allocators, the Abuse Lisp VM would allocate values from a preallocated pile over the course of a frame, and release the entire pile at the end of the frame." ;
+
+ABOUT: "memory.piles"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien destructors kernel math
+memory.piles tools.test ;
+IN: memory.piles.tests
+
+[ 25 ] [
+ [
+ 100 <pile> &dispose
+ [ 25 pile-alloc ] [ 50 pile-alloc ] bi
+ swap [ alien-address ] bi@ -
+ ] with-destructors
+] unit-test
+
+[ 32 ] [
+ [
+ 100 <pile> &dispose
+ [ 25 pile-alloc ] [ 8 pile-align 50 pile-alloc ] bi
+ swap [ alien-address ] bi@ -
+ ] with-destructors
+] unit-test
+
+[ 75 ] [
+ [
+ 100 <pile> &dispose
+ dup 25 pile-alloc drop
+ dup 50 pile-alloc drop
+ offset>>
+ ] with-destructors
+] unit-test
+
+[ 100 ] [
+ [
+ 100 <pile> &dispose
+ dup 25 pile-alloc drop
+ dup 75 pile-alloc drop
+ offset>>
+ ] with-destructors
+] unit-test
+
+[
+ [
+ 100 <pile> &dispose
+ dup 25 pile-alloc drop
+ dup 76 pile-alloc drop
+ ] with-destructors
+] [ not-enough-pile-space? ] must-fail-with
+
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors alien alien.c-types destructors kernel libc math ;
+IN: memory.piles
+
+TUPLE: pile
+ { underlying c-ptr }
+ { size integer }
+ { offset integer } ;
+
+ERROR: not-enough-pile-space pile ;
+
+M: pile dispose
+ [ [ free ] when* f ] change-underlying drop ;
+
+: <pile> ( size -- pile )
+ [ malloc ] keep 0 pile boa ;
+
+: pile-empty ( pile -- )
+ 0 >>offset drop ;
+
+: pile-alloc ( pile size -- alien )
+ [
+ [ [ ] [ size>> ] [ offset>> ] tri ] dip +
+ < [ not-enough-pile-space ] [ drop ] if
+ ] [
+ drop [ offset>> ] [ underlying>> ] bi <displaced-alien>
+ ] [
+ [ + ] curry change-offset drop
+ ] 2tri ;
+
+: <pile-c-object> ( pile c-type -- alien )
+ heap-size pile-alloc ; inline
+
+: <pile-c-array> ( pile n c-type -- alien )
+ heap-size * pile-alloc ; inline
+
+: pile-align ( pile align -- pile )
+ [ align ] curry change-offset ;
+
--- /dev/null
+Preallocated raw memory blocks
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: classes help.markup help.syntax kernel math ;
+IN: memory.pools
+
+HELP: <pool>
+{ $values
+ { "size" integer } { "class" class }
+ { "pool" pool }
+}
+{ $description "Creates a " { $link pool } " of " { $snippet "size" } " objects of " { $snippet "class" } "." } ;
+
+HELP: POOL:
+{ $syntax "POOL: class size" }
+{ $description "Creates a " { $link pool } " of " { $snippet "size" } " objects of " { $snippet "class" } ", and associates it with the class using " { $link set-class-pool } "." } ;
+
+HELP: class-pool
+{ $values
+ { "class" class }
+ { "pool" pool }
+}
+{ $description "Returns the " { $link pool } " associated with " { $snippet "class" } ", or " { $link f } " if no pool is associated." } ;
+
+HELP: free-to-pool
+{ $values
+ { "object" object }
+}
+{ $description "Frees an object from the " { $link pool } " it was allocated from. The object must have been allocated by " { $link new-from-pool } "." } ;
+
+HELP: new-from-pool
+{ $values
+ { "class" class }
+ { "object" object }
+}
+{ $description "Allocates an object from the " { $link pool } " associated with " { $snippet "class" } ". If the pool is exhausted, " { $link f } " is returned." } ;
+
+{ POSTPONE: POOL: class-pool set-class-pool new-from-pool free-to-pool } related-words
+
+HELP: pool
+{ $class-description "A " { $snippet "pool" } " contains a fixed-size set of preallocated tuple objects. Once the pool has been allocated, its objects can be allocated with " { $link pool-new } " and freed with " { $link pool-free } " in constant time. A pool can also be associated with its class with the " { $link POSTPONE: POOL: } " syntax or the " { $link set-class-pool } " word, after which the words " { $link new-from-pool } " and " { $link free-to-pool } " can be used with the class name to allocate and free objects." } ;
+
+HELP: pool-free
+{ $values
+ { "object" object } { "pool" pool }
+}
+{ $description "Frees an object back into " { $link pool } "." } ;
+
+HELP: pool-size
+{ $values
+ { "pool" pool }
+ { "size" integer }
+}
+{ $description "Returns the number of unallocated objects inside a " { $link pool } "." } ;
+
+HELP: pool-new
+{ $values
+ { "pool" pool }
+ { "object" object }
+}
+{ $description "Returns an unallocated object out of a " { $link pool } ". If the pool is exhausted, " { $link f } " is returned." } ;
+
+{ pool <pool> pool-new pool-free pool-size } related-words
+
+HELP: set-class-pool
+{ $values
+ { "class" class } { "pool" pool }
+}
+{ $description "Associates a " { $link pool } " with " { $snippet "class" } "." } ;
+
+ARTICLE: "memory.pools" "Pools"
+"The " { $vocab-link "memory.pools" } " vocabulary provides " { $link pool } " objects which manage preallocated collections of objects."
+{ $subsection pool }
+{ $subsection POSTPONE: POOL: }
+{ $subsection new-from-pool }
+{ $subsection free-to-pool } ;
+
+ABOUT: "memory.pools"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: kernel memory.pools tools.test ;
+IN: memory.pools.tests
+
+TUPLE: foo x ;
+
+[ 1 ] [
+ foo 2 foo <pool> set-class-pool
+
+ foo new-from-pool drop
+ foo class-pool pool-size
+] unit-test
+
+[ T{ foo } T{ foo } f ] [
+ foo 2 foo <pool> set-class-pool
+
+ foo new-from-pool
+ foo new-from-pool
+ foo new-from-pool
+] unit-test
+
+[ f ] [
+ foo 2 foo <pool> set-class-pool
+
+ foo new-from-pool
+ foo new-from-pool
+ eq?
+] unit-test
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors arrays bit-arrays classes
+classes.tuple.private fry kernel locals parser
+sequences sequences.private vectors words ;
+IN: memory.pools
+
+TUPLE: pool
+ prototype
+ { objects vector } ;
+
+: <pool> ( size class -- pool )
+ [ nip new ]
+ [ [ iota ] dip '[ _ new ] V{ } replicate-as ] 2bi
+ pool boa ;
+
+: pool-size ( pool -- size )
+ objects>> length ;
+
+<PRIVATE
+
+:: copy-tuple ( from to -- to )
+ from tuple-size :> size
+ size [| n | n from array-nth n to set-array-nth ] each
+ to ; inline
+
+: (pool-new) ( pool -- object )
+ objects>> [ f ] [ pop ] if-empty ;
+
+: (pool-init) ( pool object -- object )
+ [ prototype>> ] dip copy-tuple ; inline
+
+PRIVATE>
+
+: pool-new ( pool -- object )
+ dup (pool-new) [ (pool-init) ] [ drop f ] if* ; inline
+
+: pool-free ( object pool -- )
+ objects>> push ;
+
+: class-pool ( class -- pool )
+ "pool" word-prop ;
+
+: set-class-pool ( class pool -- )
+ "pool" set-word-prop ;
+
+: new-from-pool ( class -- object )
+ class-pool pool-new ;
+
+: free-to-pool ( object -- )
+ dup class class-pool pool-free ;
+
+SYNTAX: POOL:
+ scan-word scan-word '[ _ swap <pool> ] [ swap set-class-pool ] bi ;
+
--- /dev/null
+Preallocated pools of tuple objects
USING: tools.deploy.config ;
H{
- { deploy-math? t }
- { deploy-io 2 }
- { deploy-unicode? t }
+ { deploy-name "Merger" }
{ deploy-c-types? f }
{ "stop-after-last-window?" t }
- { deploy-ui? t }
- { deploy-reflection 1 }
- { deploy-name "Merger" }
- { deploy-word-props? f }
+ { deploy-unicode? f }
{ deploy-threads? t }
+ { deploy-reflection 1 }
{ deploy-word-defs? f }
+ { deploy-math? t }
+ { deploy-ui? t }
+ { deploy-word-props? f }
+ { deploy-io 2 }
}
-USING: accessors arrays fry io.directories kernel models sequences sets ui
+USING: accessors arrays fry io.directories kernel
+models sequences sets ui
ui.gadgets ui.gadgets.buttons ui.gadgets.labeled
ui.gadgets.tracks ui.gadgets.labels ui.gadgets.glass
math.rectangles cocoa.dialogs ;
--- /dev/null
+Sam Anklesaria
--- /dev/null
+USING: help.markup help.syntax models models.arrow sequences monads ;
+IN: models.combinators
+
+HELP: merge
+{ $values { "models" "a list of models" } { "model" basic-model } }
+{ $description "Creates a model that merges the updates of others" } ;
+
+HELP: filter-model
+{ $values { "model" model } { "quot" "quotation with stack effect ( a b -- c )" } { "filter-model" filter-model } }
+{ $description "Creates a model that uses the updates of another model only when they satisfy a given predicate" } ;
+
+HELP: fold
+{ $values { "oldval" "starting value" } { "quot" "applied to update and previous values" } { "model" model } { "model" model } }
+{ $description "Similar to " { $link reduce } " but works on models, applying a quotation to the previous and new values at each update" } ;
+
+HELP: switch-models
+{ $values { "model1" model } { "model2" model } { "model'" model } }
+{ $description "Creates a model that starts with the behavior of model2 and switches to the behavior of model1 on its update" } ;
+
+HELP: <mapped>
+{ $values { "model" model } { "quot" "applied to model's value on updates" } { "model" model } }
+{ $description "An expanded version of " { $link <arrow> } ". Use " { $link fmap } " instead." } ;
+
+HELP: when-model
+{ $values { "model" model } { "quot" "called on the model if the quot yields true" } { "cond" "a quotation called on the model's value, yielding a boolean value" } }
+{ $description "Calls quot when model updates if its value meets the condition set in cond" } ;
+
+HELP: with-self
+{ $values { "quot" "quotation that recieves its own return value" } { "model" model } }
+{ $description "Fixed points for models: the quot reacts to the same model to gives" } ;
+
+HELP: #1
+{ $values { "model" model } { "model'" model } }
+{ $description "Moves a model to the top of its dependencies' connections, thus being notified before the others" } ;
+
+ARTICLE: "models.combinators" "Extending models"
+"The " { $vocab-link "models.combinators" } " library expands models to have discrete start and end times. "
+"Also, it provides methods of manipulating and combining models, expecially useful when programming user interfaces: "
+"The output models of some gadgets (see " { $vocab-link "ui.gadgets.controls" } " ) can be manipulated and used as the input models of others. " ;
+
+ABOUT: "models.combinators"
\ No newline at end of file
--- /dev/null
+USING: accessors arrays kernel models models.product monads
+sequences sequences.extras ;
+FROM: syntax => >> ;
+IN: models.combinators
+
+TUPLE: multi-model < model important? ;
+GENERIC: (model-changed) ( model observer -- )
+: <multi-model> ( models kind -- model ) f swap new-model [ [ add-dependency ] curry each ] keep ;
+M: multi-model model-changed over value>> [ (model-changed) ] [ 2drop ] if ;
+M: multi-model model-activated dup dependencies>> [ value>> ] find nip
+ [ swap model-changed ] [ drop ] if* ;
+
+: #1 ( model -- model' ) t >>important? ;
+
+IN: models
+: notify-connections ( model -- )
+ dup connections>> dup [ dup multi-model? [ important?>> ] [ drop f ] if ] find-all
+ [ second tuck [ remove ] dip prefix ] each
+ [ model-changed ] with each ;
+IN: models.combinators
+
+TUPLE: basic-model < multi-model ;
+M: basic-model (model-changed) [ value>> ] dip set-model ;
+: merge ( models -- model ) basic-model <multi-model> ;
+: 2merge ( model1 model2 -- model ) 2array merge ;
+: <basic> ( value -- model ) basic-model new-model ;
+
+TUPLE: filter-model < multi-model quot ;
+M: filter-model (model-changed) [ value>> ] dip 2dup quot>> call( a -- ? )
+ [ set-model ] [ 2drop ] if ;
+: filter-model ( model quot -- filter-model ) [ 1array \ filter-model <multi-model> ] dip >>quot ;
+
+TUPLE: fold-model < multi-model quot base values ;
+M: fold-model (model-changed) 2dup base>> =
+ [ [ [ value>> ] [ [ values>> ] [ quot>> ] bi ] bi* swapd reduce* ] keep set-model ]
+ [ [ [ value>> ] [ values>> ] bi* push ]
+ [ [ [ value>> ] [ [ value>> ] [ quot>> ] bi ] bi* call( val oldval -- newval ) ] keep set-model ] 2bi
+ ] if ;
+M: fold-model model-activated drop ;
+: new-fold-model ( deps -- model ) fold-model <multi-model> V{ } clone >>values ;
+: fold ( model oldval quot -- model ) rot 1array new-fold-model swap >>quot
+ swap >>value ;
+: fold* ( model oldmodel quot -- model ) over [ [ 2array new-fold-model ] dip >>quot ]
+ dip [ >>base ] [ value>> >>value ] bi ;
+
+TUPLE: updater-model < multi-model values updates ;
+M: updater-model (model-changed) [ tuck updates>> =
+ [ [ values>> value>> ] keep set-model ]
+ [ drop ] if ] keep f swap (>>value) ;
+: updates ( values updates -- model ) [ 2array updater-model <multi-model> ] 2keep
+ [ >>values ] [ >>updates ] bi* ;
+
+SYMBOL: switch
+TUPLE: switch-model < multi-model original switcher on ;
+M: switch-model (model-changed) 2dup switcher>> =
+ [ [ value>> ] dip over switch = [ nip [ original>> ] keep f >>on model-changed ] [ t >>on set-model ] if ]
+ [ dup on>> [ 2drop ] [ [ value>> ] dip over [ set-model ] [ 2drop ] if ] if ] if ;
+: switch-models ( model1 model2 -- model' ) swap [ 2array switch-model <multi-model> ] 2keep
+ [ [ value>> >>value ] [ >>original ] bi ] [ >>switcher ] bi* ;
+M: switch-model model-activated [ original>> ] keep model-changed ;
+: >behavior ( event -- behavior ) t >>value ;
+
+TUPLE: mapped-model < multi-model model quot ;
+: new-mapped-model ( model quot class -- mapped-model ) [ over 1array ] dip
+ <multi-model> swap >>quot swap >>model ;
+: <mapped> ( model quot -- model ) mapped-model new-mapped-model ;
+M: mapped-model (model-changed)
+ [ [ value>> ] [ quot>> ] bi* call( old -- new ) ] [ nip ] 2bi
+ set-model ;
+
+TUPLE: side-effect-model < mapped-model ;
+M: side-effect-model (model-changed) [ value>> ] dip [ quot>> call( old -- ) ] 2keep set-model ;
+
+TUPLE: quot-model < mapped-model ;
+M: quot-model (model-changed) nip [ quot>> call( -- b ) ] keep set-model ;
+
+TUPLE: action-value < basic-model parent ;
+: <action-value> ( parent value -- model ) action-value new-model swap >>parent ;
+M: action-value model-activated dup parent>> dup activate-model model-changed ; ! a fake dependency of sorts
+
+TUPLE: action < multi-model quot ;
+M: action (model-changed) [ [ value>> ] [ quot>> ] bi* call( a -- b ) ] keep value>>
+ [ swap add-connection ] 2keep model-changed ;
+: <action> ( model quot -- action-model ) [ 1array action <multi-model> ] dip >>quot dup f <action-value> >>value value>> ;
+
+TUPLE: collection < multi-model ;
+: <collection> ( models -- product ) collection <multi-model> ;
+M: collection (model-changed)
+ nip
+ dup dependencies>> [ value>> ] all?
+ [ dup [ value>> ] product-value swap set-model ]
+ [ drop ] if ;
+M: collection model-activated dup (model-changed) ;
+
+! for side effects
+TUPLE: (when-model) < multi-model quot cond ;
+: when-model ( model quot cond -- model ) rot 1array (when-model) <multi-model> swap >>cond swap >>quot ;
+M: (when-model) (model-changed) [ quot>> ] 2keep
+ [ value>> ] [ cond>> ] bi* call( a -- ? ) [ call( model -- ) ] [ 2drop ] if ;
+
+! only used in construction
+: with-self ( quot: ( model -- model ) -- model ) [ f <basic> dup ] dip call swap [ add-dependency ] keep ; inline
+
+USE: models.combinators.templates
+<< { "$>" "<$" "fmap" } [ fmaps ] each >>
\ No newline at end of file
--- /dev/null
+Model combination and manipulation
\ No newline at end of file
--- /dev/null
+USING: kernel sequences functors fry macros generalizations ;
+IN: models.combinators.templates
+FROM: models.combinators => <collection> #1 ;
+FUNCTOR: fmaps ( W -- )
+W IS ${W}
+w-n DEFINES ${W}-n
+w-2 DEFINES 2${W}
+w-3 DEFINES 3${W}
+w-4 DEFINES 4${W}
+w-n* DEFINES ${W}-n*
+w-2* DEFINES 2${W}*
+w-3* DEFINES 3${W}*
+w-4* DEFINES 4${W}*
+WHERE
+MACRO: w-n ( int -- quot ) dup '[ [ _ narray <collection> ] dip [ _ firstn ] prepend W ] ;
+: w-2 ( a b quot -- mapped ) 2 w-n ; inline
+: w-3 ( a b c quot -- mapped ) 3 w-n ; inline
+: w-4 ( a b c d quot -- mapped ) 4 w-n ; inline
+MACRO: w-n* ( int -- quot ) dup '[ [ _ narray <collection> #1 ] dip [ _ firstn ] prepend W ] ;
+: w-2* ( a b quot -- mapped ) 2 w-n* ; inline
+: w-3* ( a b c quot -- mapped ) 3 w-n* ; inline
+: w-4* ( a b c d quot -- mapped ) 4 w-n* ; inline
+;FUNCTOR
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays accessors kernel models threads calendar ;
+IN: models.conditional
+
+TUPLE: conditional < model condition thread ;
+
+M: conditional model-changed
+ [
+ [ dup
+ [ condition>> call( -- ? ) ]
+ [ thread>> self = not ] bi or
+ [ [ value>> ] dip set-model f ]
+ [ 2drop t ] if 100 milliseconds sleep
+ ] 2curry "models.conditional" spawn-server
+ ] keep (>>thread) ;
+
+: <conditional> ( condition -- model )
+ f conditional new-model swap >>condition ;
+
+M: conditional model-activated [ model>> ] keep model-changed ;
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
--- /dev/null
+USING: help.syntax help.markup modules.rpc-server modules.using ;
+IN: modules.rpc-server
+HELP: service
+{ $syntax "IN: my-vocab service" }
+{ $description "Allows words defined in the vocabulary to be used as remote procedure calls by " { $link POSTPONE: USING*: } } ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators continuations effects
+io.encodings.binary io.servers.connection kernel namespaces
+sequences serialize sets threads vocabs vocabs.parser init io ;
+IN: modules.rpc-server
+
+<PRIVATE
+TUPLE: rpc-request args vocabspec wordname ;
+SYMBOL: serving-vocabs serving-vocabs [ V{ } clone ] initialize
+
+: getter ( -- ) deserialize dup serving-vocabs get-global index
+ [ vocab-words [ stack-effect ] { } assoc-map-as ]
+ [ \ no-vocab boa ] if serialize flush ;
+
+: doer ( -- ) deserialize dup vocabspec>> serving-vocabs get-global index
+ [ [ args>> ] [ wordname>> ] [ vocabspec>> vocab-words ] tri at [ execute ] curry with-datastack ]
+ [ vocabspec>> \ no-vocab boa ] if serialize flush ;
+
+PRIVATE>
+SYNTAX: service current-vocab name>> serving-vocabs get-global adjoin ;
+
+: start-rpc-server ( -- )
+ binary <threaded-server>
+ "rpcs" >>name 9012 >>insecure
+ [ deserialize {
+ { "getter" [ getter ] }
+ { "doer" [ doer ] }
+ { "loader" [ deserialize vocab serialize flush ] }
+ } case ] >>handler
+ start-server ;
--- /dev/null
+Serve factor words as rpcs
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
--- /dev/null
+USING: help.syntax help.markup ;
+IN: modules.rpc
+ARTICLE: { "modules" "protocol" } "RPC Protocol"
+{ $list
+ "Send vocab as string"
+ "Send arglist"
+ "Send word as string"
+ "Receive result list"
+} ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs fry generalizations io.encodings.binary
+io.sockets kernel locals namespaces parser sequences serialize
+vocabs vocabs.parser words io ;
+IN: modules.rpc
+
+TUPLE: rpc-request args vocabspec wordname ;
+
+: send-with-check ( message -- reply/* )
+ serialize flush deserialize dup no-vocab? [ throw ] when ;
+
+:: define-remote ( str effect addrspec vocabspec -- )
+ str create-in effect [ in>> length ] [ out>> length ] bi
+ '[ _ narray vocabspec str rpc-request boa addrspec 9012 <inet> binary
+ [ "doer" serialize send-with-check ] with-client _ firstn ]
+ effect define-declared ;
+
+:: remote-vocab ( addrspec vocabspec -- vocab )
+ vocabspec "-remote" append dup vocab [ dup set-current-vocab
+ vocabspec addrspec 9012 <inet> binary [ "getter" serialize send-with-check ] with-client
+ [ first2 addrspec vocabspec define-remote ] each
+ ] unless ;
+
+: remote-load ( addr vocabspec -- voabspec ) [ swap
+ 9012 <inet> binary [ "loader" serialize serialize flush deserialize ] with-client ] keep
+ [ dictionary get-global set-at ] keep ;
\ No newline at end of file
--- /dev/null
+remote procedure call client
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
--- /dev/null
+Improved module import syntax with network transparency
\ No newline at end of file
--- /dev/null
+USING: help.syntax help.markup strings modules.using ;
+IN: modules.using
+ARTICLE: { "modules.using" "use" } "Using the modules.using vocab"
+"This vocabulary defines " { $link POSTPONE: USING*: } " as an alternative to " { $link POSTPONE: USING: } " which makes qualified imports easier. "
+"Secondly, it allows loading vocabularies from remote servers, as long as the remote vocabulary can be accessed at compile time. "
+"Finally, the word can treat words in remote vocabularies as remote procedure calls. Any inputs are passed to the imported words as normal, and the result will appear on the stack- the only difference is that the word isn't called locally." ;
+ABOUT: { "modules.using" "use" }
+
+HELP: USING*:
+{ $syntax "USING: rpc-server::module fetch-sever:module { module qualified-name } { module => word ... } { qualified-module } { module EXCEPT word ... } { module word => importname } ;" }
+{ $description "Adds vocabularies to the search path. Vocabularies can be loaded off a server or called as an rpc if preceded by a valid hostname. Bracketed pairs facilitate all types of qualified imports on both remote and local modules." } ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel modules.rpc peg peg-lexer peg.ebnf sequences
+strings vocabs.parser ;
+IN: modules.using
+
+EBNF: modulize
+tokenpart = (!(':').)+ => [[ >string ]]
+s = ':' => [[ drop ignore ]]
+rpc = tokenpart s s tokenpart => [[ first2 remote-vocab ]]
+remote = tokenpart s tokenpart => [[ first2 remote-load ]]
+module = rpc | remote | tokenpart
+;EBNF
+
+ON-BNF: USING*:
+tokenizer = <foreign factor>
+sym = !(";"|"}"|"=>"|"EXCEPT").
+modspec = sym => [[ modulize ]]
+qualified-with = modspec sym => [[ first2 add-qualified ignore ]]
+qualified = modspec => [[ dup add-qualified ignore ]]
+from = modspec "=>" sym+ => [[ first3 nip add-words-from ignore ]]
+exclude = modspec "EXCEPT" sym+ => [[ first3 nip add-words-excluding ignore ]]
+rename = modspec sym "=>" sym => [[ first4 nip swapd add-renamed-word ignore ]]
+long = "{" ( from | exclude | rename | qualified-with | qualified ) "}" => [[ drop ignore ]]
+short = modspec => [[ use-vocab ignore ]]
+wordSpec = long | short
+using = wordSpec+ ";" => [[ drop ignore ]]
+;ON-BNF
\ No newline at end of file
] unit-test
LAZY: nats-from ( n -- list )
- dup 1+ nats-from cons ;
+ dup 1 + nats-from cons ;
: nats ( -- list ) 0 nats-from ;
! Functors
GENERIC# fmap 1 ( functor quot -- functor' )
+GENERIC# <$ 1 ( functor quot -- functor' )
+GENERIC# $> 1 ( functor quot -- functor' )
! Monads
M: monad fail monad-of fail ;
: bind ( mvalue quot -- mvalue' ) swap >>= call( quot -- mvalue ) ;
+: bind* ( mvalue quot -- mvalue' ) '[ drop @ ] bind ;
: >> ( mvalue k -- mvalue' ) '[ drop _ ] bind ;
:: lift-m2 ( m1 m2 f monad -- m3 )
[
[ dup string>number [ nip ] [ not-an-integer ] if* ] bi@
] keep length
- 10 swap ^ / + swap [ neg ] when ;
+ 10^ / + swap [ neg ] when ;
SYNTAX: DECIMAL: scan parse-decimal parsed ;
sequences formatting combinators namespaces io tools.time prettyprint io.encodings.binary
accessors words mongodb.driver strings math.parser bson.writer ;
FROM: mongodb.driver => find ;
+FROM: memory => gc ;
IN: mongodb.benchmark
[ create-collection ] keep ;
: prepare-index ( collection -- )
- "_x_idx" [ "x" asc ] key-spec <index-spec> unique-index ensure-index ;
+ "_x_idx" [ "x" asc ] key-spec <index-spec> t >>unique? ensure-index ;
: insert ( doc-quot: ( i -- doc ) -- quot: ( -- ) )
prepare-collection
: deserialize ( doc-quot: ( i -- doc ) -- quot: ( -- ) )
[ 0 ] dip call( i -- doc ) assoc>bv
- '[ trial-size [ _ binary [ H{ } stream>assoc 2drop ] with-byte-reader ] times ] ;
+ '[ trial-size [ _ binary [ H{ } stream>assoc drop ] with-byte-reader ] times ] ;
: check-for-key ( assoc key -- )
CHECK-KEY [ swap key? [ "ups... where's the key" throw ] unless ] [ 2drop ] if ;
: [bench-quot] ( feat-seq op-word -- quot: ( doc-word -- ) )
'[ _ swap _
'[ [ [ _ execute( -- quot ) ] dip
- [ execute( -- ) ] each _ execute( quot -- quot ) benchmark ] with-result ] each
+ [ execute( -- ) ] each _ execute( quot -- quot ) gc benchmark ] with-result ] each
print-separator ] ;
: run-serialization-bench ( doc-word-seq feat-seq -- )
USING: accessors assocs fry io.encodings.binary io.sockets kernel math
math.parser mongodb.msg mongodb.operations namespaces destructors
-constructors sequences splitting checksums checksums.md5 formatting
+constructors sequences splitting checksums checksums.md5
io.streams.duplex io.encodings.utf8 io.encodings.string combinators.smart
arrays hashtables sequences.deep vectors locals ;
mdb-connection get instance>> ; inline
: index-collection ( -- ns )
- mdb-instance name>> "%s.system.indexes" sprintf ; inline
+ mdb-instance name>> "system.indexes" "." glue ; inline
: namespaces-collection ( -- ns )
- mdb-instance name>> "%s.system.namespaces" sprintf ; inline
+ mdb-instance name>> "system.namespaces" "." glue ; inline
: cmd-collection ( -- ns )
- mdb-instance name>> "%s.$cmd" sprintf ; inline
+ mdb-instance name>> "$cmd" "." glue ; inline
: index-ns ( colname -- index-ns )
- [ mdb-instance name>> ] dip "%s.%s" sprintf ; inline
+ [ mdb-instance name>> ] dip "." glue ; inline
: send-message ( message -- )
[ mdb-connection get handle>> ] dip '[ _ write-message ] with-stream* ;
HELP: create-collection
{ $values
- { "name" "collection name" }
+ { "name/collection" "collection name" }
}
{ $description "Creates a new collection with the given name." } ;
"\"db\" \"127.0.0.1\" 27017 <mdb>"
"[ \"mycollection\" nameIdx [ \"name\" asc ] keyspec <index-spec> ensure-index ] with-db" "" }
{ $unchecked-example "USING: mongodb.driver ;"
- "\"db\" \"127.0.0.1\" 27017 <mdb>" "[ \"mycollection\" nameIdx [ \"name\" asc ] keyspec <index-spec> unique-index ensure-index ] with-db" "" } } ;
+ "\"db\" \"127.0.0.1\" 27017 <mdb>" "[ \"mycollection\" nameIdx [ \"name\" asc ] keyspec <index-spec> t >>unique? ensure-index ] with-db" "" } } ;
HELP: explain.
{ $values
-USING: accessors assocs bson.constants bson.writer combinators combinators.smart
-constructors continuations destructors formatting fry io io.pools
-io.encodings.binary io.sockets io.streams.duplex kernel linked-assocs hashtables
-namespaces parser prettyprint sequences sets splitting strings uuid arrays
-math math.parser memoize mongodb.connection mongodb.msg mongodb.operations ;
+USING: accessors arrays assocs bson.constants combinators
+combinators.smart constructors destructors formatting fry hashtables
+io io.pools io.sockets kernel linked-assocs math mongodb.connection
+mongodb.msg parser prettyprint sequences sets splitting strings
+tools.continuations uuid memoize locals ;
IN: mongodb.driver
CONSTRUCTOR: index-spec ( ns name key -- index-spec ) ;
-: unique-index ( index-spec -- index-spec )
- t >>unique? ;
-
M: mdb-pool make-connection
mdb>> mdb-open ;
[ make-cursor ] 2tri
swap objects>> ;
+: make-collection-assoc ( collection assoc -- )
+ [ [ name>> "create" ] dip set-at ]
+ [ [ [ capped>> ] keep ] dip
+ '[ _ _
+ [ [ drop t "capped" ] dip set-at ]
+ [ [ size>> "size" ] dip set-at ]
+ [ [ max>> "max" ] dip set-at ] 2tri ] when
+ ] 2bi ;
+
PRIVATE>
SYNTAX: r/ ( token -- mdbregexp )
H{ } clone [ set-at ] keep <mdb-db>
[ verify-nodes ] keep ;
-GENERIC: create-collection ( name -- )
+GENERIC: create-collection ( name/collection -- )
M: string create-collection
<mdb-collection> create-collection ;
M: mdb-collection create-collection
- [ cmd-collection ] dip
- <linked-hash> [
- [ [ name>> "create" ] dip set-at ]
- [ [ [ capped>> ] keep ] dip
- '[ _ _
- [ [ drop t "capped" ] dip set-at ]
- [ [ size>> "size" ] dip set-at ]
- [ [ max>> "max" ] dip set-at ] 2tri ] when
- ] 2bi
- ] keep <mdb-query-msg> 1 >>return# send-query-plain drop ;
-
+ [ [ cmd-collection ] dip
+ <linked-hash> [ make-collection-assoc ] keep
+ <mdb-query-msg> 1 >>return# send-query-plain drop ] keep
+ [ ] [ name>> ] bi mdb-instance collections>> set-at ;
+
: load-collection-list ( -- collection-list )
namespaces-collection
H{ } clone <mdb-query-msg> send-query-plain objects>> ;
: ensure-valid-collection-name ( collection -- )
[ ";$." intersect length 0 > ] keep
- '[ _ "%s contains invalid characters ( . $ ; )" sprintf throw ] when ; inline
-
-: (ensure-collection) ( collection -- )
- mdb-instance collections>> dup keys length 0 =
- [ load-collection-list
- [ [ "options" ] dip key? ] filter
- [ [ "name" ] dip at "." split second <mdb-collection> ] map
- over '[ [ ] [ name>> ] bi _ set-at ] each ] [ ] if
- [ dup ] dip key? [ drop ]
- [ [ ensure-valid-collection-name ] keep create-collection ] if ;
-
+ '[ _ "contains invalid characters ( . $ ; )" "." glue throw ] when ; inline
+
+: build-collection-map ( -- assoc )
+ H{ } clone load-collection-list
+ [ [ "name" ] dip at "." split second <mdb-collection> ] map
+ over '[ [ ] [ name>> ] bi _ set-at ] each ;
+
+: ensure-collection-map ( mdb-instance -- assoc )
+ dup collections>> dup keys length 0 =
+ [ drop build-collection-map [ >>collections drop ] keep ]
+ [ nip ] if ;
+
+: (ensure-collection) ( collection mdb-instance -- collection )
+ ensure-collection-map [ dup ] dip key?
+ [ ] [ [ ensure-valid-collection-name ]
+ [ create-collection ]
+ [ ] tri ] if ;
+
: reserved-namespace? ( name -- ? )
[ "$cmd" = ] [ "system" head? ] bi or ;
: check-collection ( collection -- fq-collection )
- dup mdb-collection? [ name>> ] when
- "." split1 over mdb-instance name>> =
- [ nip ] [ drop ] if
- [ ] [ reserved-namespace? ] bi
- [ [ (ensure-collection) ] keep ] unless
- [ mdb-instance name>> ] dip "%s.%s" sprintf ;
+ [let* | instance [ mdb-instance ]
+ instance-name [ instance name>> ] |
+ dup mdb-collection? [ name>> ] when
+ "." split1 over instance-name =
+ [ nip ] [ drop ] if
+ [ ] [ reserved-namespace? ] bi
+ [ instance (ensure-collection) ] unless
+ [ instance-name ] dip "." glue ] ;
: fix-query-collection ( mdb-query -- mdb-query )
[ check-collection ] change-collection ; inline
+++ /dev/null
-Sascha Matzke
+++ /dev/null
-USING: accessors fry io io.encodings.binary io.servers.connection
-io.sockets io.streams.byte-array kernel math mongodb.msg classes formatting
-namespaces prettyprint tools.walker calendar calendar.format bson.writer.private
-json.writer mongodb.operations.private mongodb.operations ;
-
-IN: mongodb.mmm
-
-SYMBOLS: mmm-port mmm-server-ip mmm-server-port mmm-server mmm-dump-output mmm-t-srv ;
-
-GENERIC: dump-message ( message -- )
-
-: check-options ( -- )
- mmm-port get [ 27040 mmm-port set ] unless
- mmm-server-ip get [ "127.0.0.1" mmm-server-ip set ] unless
- mmm-server-port get [ 27017 mmm-server-port set ] unless
- mmm-server-ip get mmm-server-port get <inet> mmm-server set ;
-
-: read-msg-binary ( -- )
- read-int32
- [ write-int32 ] keep
- 4 - read write ;
-
-: read-request-header ( -- msg-stub )
- mdb-msg new
- read-int32 MSG-HEADER-SIZE - >>length
- read-int32 >>req-id
- read-int32 >>resp-id
- read-int32 >>opcode ;
-
-: read-request ( -- msg-stub binary )
- binary [ read-msg-binary ] with-byte-writer
- [ binary [ read-request-header ] with-byte-reader ] keep ; ! msg-stub binary
-
-: dump-request ( msg-stub binary -- )
- [ mmm-dump-output get ] 2dip
- '[ _ drop _ binary [ read-message dump-message ] with-byte-reader ] with-output-stream ;
-
-: read-reply ( -- binary )
- binary [ read-msg-binary ] with-byte-writer ;
-
-: forward-request-read-reply ( msg-stub binary -- binary )
- [ mmm-server get binary ] 2dip
- '[ _ opcode>> _ write flush
- OP_Query =
- [ read-reply ]
- [ f ] if ] with-client ;
-
-: dump-reply ( binary -- )
- [ mmm-dump-output get ] dip
- '[ _ binary [ read-message dump-message ] with-byte-reader ] with-output-stream ;
-
-: message-prefix ( message -- prefix message )
- [ now timestamp>http-string ] dip
- [ class name>> ] keep
- [ "%s: %s" sprintf ] dip ; inline
-
-M: mdb-query-msg dump-message ( message -- )
- message-prefix
- [ collection>> ] keep
- query>> >json
- "%s -> %s: %s \n" printf ;
-
-M: mdb-insert-msg dump-message ( message -- )
- message-prefix
- [ collection>> ] keep
- objects>> >json
- "%s -> %s : %s \n" printf ;
-
-M: mdb-reply-msg dump-message ( message -- )
- message-prefix
- [ cursor>> ] keep
- [ start#>> ] keep
- [ returned#>> ] keep
- objects>> >json
- "%s -> cursor: %d, start: %d, returned#: %d, -> %s \n" printf ;
-
-M: mdb-msg dump-message ( message -- )
- message-prefix drop "%s \n" printf ;
-
-: forward-reply ( binary -- )
- write flush ;
-
-: handle-mmm-connection ( -- )
- read-request
- [ dump-request ] 2keep
- forward-request-read-reply
- [ dump-reply ] keep
- forward-reply ;
-
-: start-mmm-server ( -- )
- output-stream get mmm-dump-output set
- binary <threaded-server> [ mmm-t-srv set ] keep
- "127.0.0.1" mmm-port get <inet4> >>insecure
- [ handle-mmm-connection ] >>handler
- start-server* ;
-
-: run-mmm ( -- )
- check-options
- start-mmm-server ;
-
-MAIN: run-mmm
+++ /dev/null
-mongo-message-monitor - a small proxy to introspect messages send to MongoDB
[ opcode>> ] keep [ >>opcode ] dip
flags>> >>flags ;
-M: mdb-query-op (read-message) ( msg-stub opcode -- message )
- drop
- [ mdb-query-msg new ] dip copy-header
- read-cstring >>collection
- read-int32 >>skip#
- read-int32 >>return#
- H{ } stream>assoc change-bytes-read >>query
- dup length>> bytes-read> >
- [ H{ } stream>assoc change-bytes-read >>returnfields ] when ;
-
-M: mdb-insert-op (read-message) ( msg-stub opcode -- message )
- drop
- [ mdb-insert-msg new ] dip copy-header
- read-cstring >>collection
- V{ } clone >>objects
- [ '[ _ length>> bytes-read> > ] ] keep tuck
- '[ H{ } stream>assoc change-bytes-read _ objects>> push ]
- while ;
-
-M: mdb-delete-op (read-message) ( msg-stub opcode -- message )
- drop
- [ mdb-delete-msg new ] dip copy-header
- read-cstring >>collection
- H{ } stream>assoc change-bytes-read >>selector ;
-
-M: mdb-getmore-op (read-message) ( msg-stub opcode -- message )
- drop
- [ mdb-getmore-msg new ] dip copy-header
- read-cstring >>collection
- read-int32 >>return#
- read-longlong >>cursor ;
-
-M: mdb-killcursors-op (read-message) ( msg-stub opcode -- message )
- drop
- [ mdb-killcursors-msg new ] dip copy-header
- read-int32 >>cursors#
- V{ } clone >>cursors
- [ [ cursors#>> ] keep
- '[ read-longlong _ cursors>> push ] times ] keep ;
-
-M: mdb-update-op (read-message) ( msg-stub opcode -- message )
- drop
- [ mdb-update-msg new ] dip copy-header
- read-cstring >>collection
- read-int32 >>upsert?
- H{ } stream>assoc change-bytes-read >>selector
- H{ } stream>assoc change-bytes-read >>object ;
-
M: mdb-reply-op (read-message) ( msg-stub opcode -- message )
drop
[ <mdb-reply-msg> ] dip copy-header
read-longlong >>cursor
read-int32 >>start#
read-int32 [ >>returned# ] keep
- [ H{ } stream>assoc drop ] accumulator [ times ] dip >>objects ;
+ [ H{ } stream>assoc ] accumulator [ times ] dip >>objects ;
: read-header ( message -- message )
read-int32 >>length
: user-defined-key-index ( class -- assoc )
mdb-slot-map user-defined-key
[ drop [ "user-defined-key-index" 1 ] dip
- H{ } clone [ set-at ] keep <tuple-index> unique-index
+ H{ } clone [ set-at ] keep <tuple-index> t >>unique?
[ ] [ name>> ] bi H{ } clone [ set-at ] keep
] [ 2drop H{ } clone ] if ;
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2008, 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math sequences vectors classes classes.algebra
+combinators arrays words assocs parser namespaces make
+definitions prettyprint prettyprint.backend prettyprint.custom
+quotations generalizations debugger io compiler.units
+kernel.private effects accessors hashtables sorting shuffle
+math.order sets see effects.parser ;
+IN: multi-methods
+
+! PART I: Converting hook specializers
+: canonicalize-specializer-0 ( specializer -- specializer' )
+ [ \ f or ] map ;
+
+SYMBOL: args
+
+SYMBOL: hooks
+
+SYMBOL: total
+
+: canonicalize-specializer-1 ( specializer -- specializer' )
+ [
+ [ class? ] filter
+ [ length <reversed> [ 1 + neg ] map ] keep zip
+ [ length args [ max ] change ] keep
+ ]
+ [
+ [ pair? ] filter
+ [ keys [ hooks get adjoin ] each ] keep
+ ] bi append ;
+
+: canonicalize-specializer-2 ( specializer -- specializer' )
+ [
+ [
+ {
+ { [ dup integer? ] [ ] }
+ { [ dup word? ] [ hooks get index ] }
+ } cond args get +
+ ] dip
+ ] assoc-map ;
+
+: canonicalize-specializer-3 ( specializer -- specializer' )
+ [ total get object <array> dup <enum> ] dip update ;
+
+: canonicalize-specializers ( methods -- methods' hooks )
+ [
+ [ [ canonicalize-specializer-0 ] dip ] assoc-map
+
+ 0 args set
+ V{ } clone hooks set
+
+ [ [ canonicalize-specializer-1 ] dip ] assoc-map
+
+ hooks [ natural-sort ] change
+
+ [ [ canonicalize-specializer-2 ] dip ] assoc-map
+
+ args get hooks get length + total set
+
+ [ [ canonicalize-specializer-3 ] dip ] assoc-map
+
+ hooks get
+ ] with-scope ;
+
+: drop-n-quot ( n -- quot ) \ drop <repetition> >quotation ;
+
+: prepare-method ( method n -- quot )
+ [ 1quotation ] [ drop-n-quot ] bi* prepend ;
+
+: prepare-methods ( methods -- methods' prologue )
+ canonicalize-specializers
+ [ length [ prepare-method ] curry assoc-map ] keep
+ [ [ get ] curry ] map concat [ ] like ;
+
+! Part II: Topologically sorting specializers
+: maximal-element ( seq quot -- n elt )
+ dupd [
+ swapd [ call +lt+ = ] 2curry filter empty?
+ ] 2curry find [ "Topological sort failed" throw ] unless* ;
+ inline
+
+: topological-sort ( seq quot -- newseq )
+ [ >vector [ dup empty? not ] ] dip
+ [ dupd maximal-element [ over delete-nth ] dip ] curry
+ produce nip ; inline
+
+: classes< ( seq1 seq2 -- lt/eq/gt )
+ [
+ {
+ { [ 2dup eq? ] [ +eq+ ] }
+ { [ 2dup [ class<= ] [ swap class<= ] 2bi and ] [ +eq+ ] }
+ { [ 2dup class<= ] [ +lt+ ] }
+ { [ 2dup swap class<= ] [ +gt+ ] }
+ [ +eq+ ]
+ } cond 2nip
+ ] 2map [ +eq+ eq? not ] find nip +eq+ or ;
+
+: sort-methods ( alist -- alist' )
+ [ [ first ] bi@ classes< ] topological-sort ;
+
+! PART III: Creating dispatch quotation
+: picker ( n -- quot )
+ {
+ { 0 [ [ dup ] ] }
+ { 1 [ [ over ] ] }
+ { 2 [ [ pick ] ] }
+ [ 1 - picker [ dip swap ] curry ]
+ } case ;
+
+: (multi-predicate) ( class picker -- quot )
+ swap "predicate" word-prop append ;
+
+: multi-predicate ( classes -- quot )
+ dup length <reversed>
+ [ picker 2array ] 2map
+ [ drop object eq? not ] assoc-filter
+ [ [ t ] ] [
+ [ (multi-predicate) ] { } assoc>map
+ unclip [ swap [ f ] \ if 3array append [ ] like ] reduce
+ ] if-empty ;
+
+: argument-count ( methods -- n )
+ keys 0 [ length max ] reduce ;
+
+ERROR: no-method arguments generic ;
+
+: make-default-method ( methods generic -- quot )
+ [ argument-count ] dip [ [ narray ] dip no-method ] 2curry ;
+
+: multi-dispatch-quot ( methods generic -- quot )
+ [ make-default-method ]
+ [ drop [ [ multi-predicate ] dip ] assoc-map reverse ]
+ 2bi alist>quot ;
+
+! Generic words
+PREDICATE: generic < word
+ "multi-methods" word-prop >boolean ;
+
+: methods ( word -- alist )
+ "multi-methods" word-prop >alist ;
+
+: make-generic ( generic -- quot )
+ [
+ [ methods prepare-methods % sort-methods ] keep
+ multi-dispatch-quot %
+ ] [ ] make ;
+
+: update-generic ( word -- )
+ dup make-generic define ;
+
+! Methods
+PREDICATE: method-body < word
+ "multi-method-generic" word-prop >boolean ;
+
+M: method-body stack-effect
+ "multi-method-generic" word-prop stack-effect ;
+
+M: method-body crossref?
+ "forgotten" word-prop not ;
+
+: method-word-name ( specializer generic -- string )
+ [ name>> % "-" % unparse % ] "" make ;
+
+: method-word-props ( specializer generic -- assoc )
+ [
+ "multi-method-generic" set
+ "multi-method-specializer" set
+ ] H{ } make-assoc ;
+
+: <method> ( specializer generic -- word )
+ [ method-word-props ] 2keep
+ method-word-name f <word>
+ swap >>props ;
+
+: with-methods ( word quot -- )
+ over [
+ [ "multi-methods" word-prop ] dip call
+ ] dip update-generic ; inline
+
+: reveal-method ( method classes generic -- )
+ [ set-at ] with-methods ;
+
+: method ( classes word -- method )
+ "multi-methods" word-prop at ;
+
+: create-method ( classes generic -- method )
+ 2dup method dup [
+ 2nip
+ ] [
+ drop [ <method> dup ] 2keep reveal-method
+ ] if ;
+
+: niceify-method ( seq -- seq )
+ [ dup \ f eq? [ drop f ] when ] map ;
+
+M: no-method error.
+ "Type check error" print
+ nl
+ "Generic word " write dup generic>> pprint
+ " does not have a method applicable to inputs:" print
+ dup arguments>> short.
+ nl
+ "Inputs have signature:" print
+ dup arguments>> [ class ] map niceify-method .
+ nl
+ "Available methods: " print
+ generic>> methods canonicalize-specializers drop sort-methods
+ keys [ niceify-method ] map stack. ;
+
+: forget-method ( specializer generic -- )
+ [ delete-at ] with-methods ;
+
+: method>spec ( method -- spec )
+ [ "multi-method-specializer" word-prop ]
+ [ "multi-method-generic" word-prop ] bi prefix ;
+
+: define-generic ( word effect -- )
+ over set-stack-effect
+ dup "multi-methods" word-prop [ drop ] [
+ [ H{ } clone "multi-methods" set-word-prop ]
+ [ update-generic ]
+ bi
+ ] if ;
+
+! Syntax
+SYNTAX: GENERIC: CREATE-WORD complete-effect define-generic ;
+
+: parse-method ( -- quot classes generic )
+ parse-definition [ 2 tail ] [ second ] [ first ] tri ;
+
+: create-method-in ( specializer generic -- method )
+ create-method dup save-location f set-word ;
+
+: CREATE-METHOD ( -- method )
+ scan-word scan-object swap create-method-in ;
+
+: (METHOD:) ( -- method def ) CREATE-METHOD parse-definition ;
+
+SYNTAX: METHOD: (METHOD:) define ;
+
+! For compatibility
+SYNTAX: M:
+ scan-word 1array scan-word create-method-in
+ parse-definition
+ define ;
+
+! Definition protocol. We qualify core generics here
+QUALIFIED: syntax
+
+syntax:M: generic definer drop \ GENERIC: f ;
+
+syntax:M: generic definition drop f ;
+
+PREDICATE: method-spec < array
+ unclip generic? [ [ class? ] all? ] dip and ;
+
+syntax:M: method-spec where
+ dup unclip method [ ] [ first ] ?if where ;
+
+syntax:M: method-spec set-where
+ unclip method set-where ;
+
+syntax:M: method-spec definer
+ unclip method definer ;
+
+syntax:M: method-spec definition
+ unclip method definition ;
+
+syntax:M: method-spec synopsis*
+ unclip method synopsis* ;
+
+syntax:M: method-spec forget*
+ unclip method forget* ;
+
+syntax:M: method-body definer
+ drop \ METHOD: \ ; ;
+
+syntax:M: method-body synopsis*
+ dup definer.
+ [ "multi-method-generic" word-prop pprint-word ]
+ [ "multi-method-specializer" word-prop pprint* ] bi ;
--- /dev/null
+Experimental multiple dispatch implementation
--- /dev/null
+extensions
--- /dev/null
+USING: multi-methods tools.test math sequences namespaces system
+kernel strings ;
+IN: multi-methods.tests
+
+[ { POSTPONE: f integer } ] [ { f integer } canonicalize-specializer-0 ] unit-test
+
+: setup-canon-test ( -- )
+ 0 args set
+ V{ } clone hooks set ;
+
+: canon-test-1 ( -- seq )
+ { integer { cpu x86 } sequence } canonicalize-specializer-1 ;
+
+[ { { -2 integer } { -1 sequence } { cpu x86 } } ] [
+ [
+ setup-canon-test
+ canon-test-1
+ ] with-scope
+] unit-test
+
+[ { { 0 integer } { 1 sequence } { 2 x86 } } ] [
+ [
+ setup-canon-test
+ canon-test-1
+ canonicalize-specializer-2
+ ] with-scope
+] unit-test
+
+[ { integer sequence x86 } ] [
+ [
+ setup-canon-test
+ canon-test-1
+ canonicalize-specializer-2
+ args get hooks get length + total set
+ canonicalize-specializer-3
+ ] with-scope
+] unit-test
+
+CONSTANT: example-1
+ {
+ { { { cpu x86 } { os linux } } "a" }
+ { { { cpu ppc } } "b" }
+ { { string { os windows } } "c" }
+ }
+
+[
+ {
+ { { object x86 linux } "a" }
+ { { object ppc object } "b" }
+ { { string object windows } "c" }
+ }
+ { cpu os }
+] [
+ example-1 canonicalize-specializers
+] unit-test
+
+[
+ {
+ { { object x86 linux } [ drop drop "a" ] }
+ { { object ppc object } [ drop drop "b" ] }
+ { { string object windows } [ drop drop "c" ] }
+ }
+ [ \ cpu get \ os get ]
+] [
+ example-1 prepare-methods
+] unit-test
--- /dev/null
+USING: multi-methods tools.test math sequences namespaces system
+kernel strings words compiler.units quotations ;
+IN: multi-methods.tests
+
+DEFER: fake
+\ fake H{ } clone "multi-methods" set-word-prop
+<< (( -- )) \ fake set-stack-effect >>
+
+[ "fake-{ }" ] [ { } \ fake method-word-name ] unit-test
+
+[ H{ { "multi-method-generic" fake } { "multi-method-specializer" { } } } ]
+[ { } \ fake method-word-props ] unit-test
+
+[ t ] [ { } \ fake <method> method-body? ] unit-test
+
+[
+ [ { } [ ] ] [ \ fake methods prepare-methods [ sort-methods ] dip ] unit-test
+
+ [ t ] [ { } \ fake multi-dispatch-quot callable? ] unit-test
+
+ [ t ] [ \ fake make-generic quotation? ] unit-test
+
+ [ ] [ \ fake update-generic ] unit-test
+
+ DEFER: testing
+
+ [ ] [ \ testing (( -- )) define-generic ] unit-test
+
+ [ t ] [ \ testing generic? ] unit-test
+] with-compilation-unit
--- /dev/null
+USING: math strings sequences tools.test ;
+IN: multi-methods.tests
+
+GENERIC: legacy-test ( a -- b )
+
+M: integer legacy-test sq ;
+M: string legacy-test " hey" append ;
+
+[ 25 ] [ 5 legacy-test ] unit-test
+[ "hello hey" ] [ "hello" legacy-test ] unit-test
--- /dev/null
+USING: multi-methods tools.test math sequences namespaces system
+kernel strings definitions prettyprint debugger arrays
+hashtables continuations classes assocs accessors see ;
+RENAME: GENERIC: multi-methods => multi-methods:GENERIC:
+IN: multi-methods.tests
+
+multi-methods:GENERIC: first-test ( -- )
+
+[ t ] [ \ first-test generic? ] unit-test
+
+MIXIN: thing
+
+SINGLETON: paper INSTANCE: paper thing
+SINGLETON: scissors INSTANCE: scissors thing
+SINGLETON: rock INSTANCE: rock thing
+
+multi-methods:GENERIC: beats? ( obj1 obj2 -- ? )
+
+METHOD: beats? { paper scissors } 2drop t ;
+METHOD: beats? { scissors rock } 2drop t ;
+METHOD: beats? { rock paper } 2drop t ;
+METHOD: beats? { thing thing } 2drop f ;
+
+: play ( obj1 obj2 -- ? ) beats? ;
+
+[ { } 3 play ] must-fail
+[ t ] [ error get no-method? ] unit-test
+[ ] [ error get error. ] unit-test
+[ { { } 3 } ] [ error get arguments>> ] unit-test
+[ t ] [ paper scissors play ] unit-test
+[ f ] [ scissors paper play ] unit-test
+
+[ t ] [ { beats? paper scissors } method-spec? ] unit-test
+[ ] [ { beats? paper scissors } see ] unit-test
+
+SYMBOL: some-var
+
+multi-methods:GENERIC: hook-test ( obj -- obj )
+
+METHOD: hook-test { array { some-var array } } reverse ;
+METHOD: hook-test { { some-var array } } class ;
+METHOD: hook-test { hashtable { some-var number } } assoc-size ;
+
+{ 1 2 3 } some-var set
+[ { f t t } ] [ { t t f } hook-test ] unit-test
+[ fixnum ] [ 3 hook-test ] unit-test
+5.0 some-var set
+[ 0 ] [ H{ } hook-test ] unit-test
+
+"error" some-var set
+[ H{ } hook-test ] must-fail
+[ t ] [ error get no-method? ] unit-test
+[ { H{ } "error" } ] [ error get arguments>> ] unit-test
+
+MIXIN: busted
+
+TUPLE: busted-1 ;
+TUPLE: busted-2 ; INSTANCE: busted-2 busted
+TUPLE: busted-3 ;
+
+multi-methods:GENERIC: busted-sort ( obj1 obj2 -- obj1 obj2 )
+
+METHOD: busted-sort { busted-1 busted-2 } ;
+METHOD: busted-sort { busted-2 busted-3 } ;
+METHOD: busted-sort { busted busted } ;
--- /dev/null
+USING: kernel multi-methods tools.test math arrays sequences
+math.order ;
+IN: multi-methods.tests
+
+[ { 1 2 3 4 5 6 } ] [
+ { 6 4 5 1 3 2 } [ <=> ] topological-sort
+] unit-test
+
+[ +lt+ ] [
+ { fixnum array } { number sequence } classes<
+] unit-test
+
+[ +eq+ ] [
+ { number sequence } { number sequence } classes<
+] unit-test
+
+[ +gt+ ] [
+ { object object } { number sequence } classes<
+] unit-test
-USING: byte-arrays combinators fry images kernel locals math
+USING: accessors arrays byte-arrays combinators
+combinators.short-circuit fry hints images kernel locals math
math.affine-transforms math.functions math.order
-math.polynomials math.vectors random random.mersenne-twister
-sequences sequences.product hints arrays sequences.private
-combinators.short-circuit math.private ;
+math.polynomials math.private math.vectors random
+random.mersenne-twister sequences sequences.private
+sequences.product ;
IN: noise
: <perlin-noise-table> ( -- table )
[ 255.0 * >fixnum ] B{ } map-as ;
: >image ( bytes dim -- image )
- swap [ L f ] dip image boa ;
+ image new
+ swap >>dim
+ swap >>bitmap
+ L >>component-order
+ ubyte-components >>component-type ;
:: perlin-noise-unsafe ( table point -- value )
point unit-cube :> cube
ui.gadgets.worlds ui.render accessors combinators literals ;
IN: opengl.demo-support
-CONSTANT: FOV $[ 2.0 sqrt 1+ ]
+CONSTANT: FOV $[ 2.0 sqrt 1 + ]
CONSTANT: MOUSE-MOTION-SCALE 0.5
CONSTANT: KEY-ROTATE-STEP 10.0
: sorted-pair-methods ( word -- alist )
"pair-generic-methods" word-prop >alist
- [ [ first method-sort-key ] bi@ >=< ] sort ;
+ [ first method-sort-key ] inv-sort-with ;
: pair-generic-definition ( word -- def )
[ sorted-pair-methods [ first2 pair-method-cond ] map ]
2drop epsilon
] [
2dup exactly-n
- -rot 1- at-most-n <|>
+ -rot 1 - at-most-n <|>
] if ;
: at-least-n ( parser n -- parser' )
:: prepare-pos ( v i -- c l )
[let | n [ i v head-slice ] |
- v CHAR: \n n last-index -1 or 1+ -
- n [ CHAR: \n = ] count 1+
+ v CHAR: \n n last-index -1 or 1 + -
+ n [ CHAR: \n = ] count 1 +
] ;
: store-pos ( v a -- )
[ swap hash>> set-at ]
} case ;
-:: at-pos ( t l c -- p ) t l head-slice [ length ] map sum l 1- + c + ;
+:: at-pos ( t l c -- p ) t l head-slice [ length ] map sum l 1 - + c + ;
M: lex-hash at*
swap {
{ input [ drop lexer get text>> "\n" join t ] }
- { pos [ drop lexer get [ text>> ] [ line>> 1- ] [ column>> 1+ ] tri at-pos t ] }
+ { pos [ drop lexer get [ text>> ] [ line>> 1 - ] [ column>> 1 + ] tri at-pos t ] }
[ swap hash>> at* ]
} case ;
spaces = space* => [[ drop ignore ]]
chunk = (!(space) .)+ => [[ >string ]]
expr = spaces chunk
-;EBNF
\ No newline at end of file
+;EBNF
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+USING: accessors arrays byte-arrays calendar classes
+classes.tuple classes.tuple.parser combinators db db.queries
+db.tuples db.types kernel math nmake parser sequences strings
+strings.parser unicode.case urls words ;
+IN: persistency
+
+TUPLE: persistent id ;
+
+: add-types ( table -- table' ) [ dup array? [ [ first dup >upper ] [ second ] bi 3array ]
+ [ dup >upper FACTOR-BLOB 3array ] if
+ ] map { "id" "ID" +db-assigned-id+ } prefix ;
+
+: remove-types ( table -- table' ) [ dup array? [ first ] when ] map ;
+
+SYNTAX: STORED-TUPLE: parse-tuple-definition [ drop persistent ] dip [ remove-types define-tuple-class ]
+ [ nip [ dup name>> >upper ] [ add-types ] bi* define-persistent ] 3bi ;
+
+: define-db ( database class -- ) swap [ [ ensure-table ] with-db ] [ "database" set-word-prop ] 2bi ;
+
+: query>tuple ( tuple/query -- tuple ) dup query? [ tuple>> ] when ;
+: w/db ( query quot -- ) [ dup query>tuple class "database" word-prop ] dip with-db ; inline
+: get-tuples ( query -- tuples ) [ select-tuples ] w/db ;
+: get-tuple ( query -- tuple ) [ select-tuple ] w/db ;
+: store-tuple ( tuple -- ) [ insert-tuple ] w/db ;
+: modify-tuple ( tuple -- ) [ update-tuple ] w/db ;
+: remove-tuples ( tuple -- ) [ delete-tuples ] w/db ;
+
+TUPLE: pattern value ; C: <pattern> pattern
+SYNTAX: %" parse-string <pattern> parsed ;
+M: pattern where value>> over column-name>> 0% " LIKE " 0% bind# ;
--- /dev/null
+USING: help help.markup help.syntax kernel quotations ;
+IN: prettyprint.callables
+
+HELP: simplify-callable
+{ $values { "quot" callable } { "quot'" callable } }
+{ $description "Converts " { $snippet "quot" } " into an equivalent quotation by simplifying usages of " { $link dip } ", " { $link call } ", " { $link curry } ", and " { $link compose } " with literal parameters. This word is used when callable objects are prettyprinted." } ;
--- /dev/null
+! (c) 2009 Joe Groff bsd license
+USING: kernel math prettyprint prettyprint.callables
+tools.test ;
+IN: prettyprint.callables.tests
+
+[ [ dip ] ] [ [ dip ] simplify-callable ] unit-test
+[ [ [ + ] dip ] ] [ [ [ + ] dip ] simplify-callable ] unit-test
+[ [ + 5 ] ] [ [ 5 [ + ] dip ] simplify-callable ] unit-test
+[ [ + ] ] [ [ [ + ] call ] simplify-callable ] unit-test
+[ [ call ] ] [ [ call ] simplify-callable ] unit-test
+[ [ 5 + ] ] [ [ 5 [ + ] curry call ] simplify-callable ] unit-test
+[ [ 4 5 + ] ] [ [ 4 5 [ + ] 2curry call ] simplify-callable ] unit-test
+[ [ 4 5 6 + ] ] [ [ 4 5 6 [ + ] 3curry call ] simplify-callable ] unit-test
+[ [ + . ] ] [ [ [ + ] [ . ] compose call ] simplify-callable ] unit-test
+[ [ . + ] ] [ [ [ + ] [ . ] prepose call ] simplify-callable ] unit-test
--- /dev/null
+! (c) 2009 Joe Groff bsd license
+USING: combinators combinators.short-circuit generalizations
+kernel macros math math.ranges prettyprint.custom quotations
+sequences words ;
+IN: prettyprint.callables
+
+<PRIVATE
+
+CONSTANT: simple-combinators { dip call curry 2curry 3curry compose prepose }
+
+: literal? ( obj -- ? ) word? not ;
+
+MACRO: slice-match? ( quots -- quot: ( seq end -- ? ) )
+ dup length
+ [ 0 [a,b) [ [ - swap nth ] swap prefix prepend ] 2map ]
+ [ nip \ nip swap \ >= [ ] 3sequence ] 2bi
+ prefix \ 2&& [ ] 2sequence ;
+
+: end-len>from-to ( seq end len -- from to seq )
+ [ - ] [ drop 1 + ] 2bi rot ;
+
+: slice-change ( seq end len quot -- seq' )
+ [ end-len>from-to ] dip
+ [ [ subseq ] dip call ] curry
+ [ replace-slice ] 3bi ; inline
+
+: when-slice-match ( seq i criteria quot -- seq' )
+ [ [ 2dup ] dip slice-match? ] dip [ drop ] if ; inline
+
+: simplify-dip ( quot i -- quot' )
+ { [ literal? ] [ callable? ] }
+ [ 2 [ first2 swap suffix ] slice-change ] when-slice-match ;
+
+: simplify-call ( quot i -- quot' )
+ { [ callable? ] }
+ [ 1 [ first ] slice-change ] when-slice-match ;
+
+: simplify-curry ( quot i -- quot' )
+ { [ literal? ] [ callable? ] }
+ [ 2 [ first2 swap prefix 1quotation ] slice-change ] when-slice-match ;
+
+: simplify-2curry ( quot i -- quot' )
+ { [ literal? ] [ literal? ] [ callable? ] }
+ [ 3 [ [ 2 head ] [ third ] bi append 1quotation ] slice-change ] when-slice-match ;
+
+: simplify-3curry ( quot i -- quot' )
+ { [ literal? ] [ literal? ] [ literal? ] [ callable? ] }
+ [ 4 [ [ 3 head ] [ fourth ] bi append 1quotation ] slice-change ] when-slice-match ;
+
+: simplify-compose ( quot i -- quot' )
+ { [ callable? ] [ callable? ] }
+ [ 2 [ first2 append 1quotation ] slice-change ] when-slice-match ;
+
+: simplify-prepose ( quot i -- quot' )
+ { [ callable? ] [ callable? ] }
+ [ 2 [ first2 swap append 1quotation ] slice-change ] when-slice-match ;
+
+: (simplify-callable) ( quot -- quot' )
+ dup [ simple-combinators member? ] find {
+ { \ dip [ simplify-dip ] }
+ { \ call [ simplify-call ] }
+ { \ curry [ simplify-curry ] }
+ { \ 2curry [ simplify-2curry ] }
+ { \ 3curry [ simplify-3curry ] }
+ { \ compose [ simplify-compose ] }
+ { \ prepose [ simplify-prepose ] }
+ [ 2drop ]
+ } case ;
+
+PRIVATE>
+
+: simplify-callable ( quot -- quot' )
+ [ (simplify-callable) ] to-fixed-point ;
+
+M: callable >pprint-sequence simplify-callable ;
--- /dev/null
+Quotation simplification for prettyprinting automatically-constructed callable objects
<PRIVATE
: sum-divisible-by ( target n -- m )
- [ /i dup 1+ * ] keep * 2 /i ;
+ [ /i dup 1 + * ] keep * 2 /i ;
PRIVATE>
! --------
: euler012 ( -- answer )
- 8 [ dup nth-triangle tau* 500 < ] [ 1+ ] while nth-triangle ;
+ 8 [ dup nth-triangle tau* 500 < ] [ 1 + ] while nth-triangle ;
! [ euler012 ] 10 ave-time
! 6573 ms ave run time - 346.27 SD (10 trials)
<PRIVATE
: next-collatz ( n -- n )
- dup even? [ 2 / ] [ 3 * 1+ ] if ;
+ dup even? [ 2 / ] [ 3 * 1 + ] if ;
: longest ( seq seq -- seq )
2dup [ length ] bi@ > [ drop ] [ nip ] if ;
<PRIVATE
: worth-calculating? ( n -- ? )
- 1- 3 { [ divisor? ] [ / even? ] } 2&& ;
+ 1 - 3 { [ divisor? ] [ / even? ] } 2&& ;
PRIVATE>
ascii file-contents [ quotable? ] filter "," split ;
: name-scores ( seq -- seq )
- [ 1+ swap alpha-value * ] map-index ;
+ [ 1 + swap alpha-value * ] map-index ;
PRIVATE>
<PRIVATE
: (digit-fib) ( n term -- term )
- 2dup fib number>string length > [ 1+ (digit-fib) ] [ nip ] if ;
+ 2dup fib number>string length > [ 1 + (digit-fib) ] [ nip ] if ;
: digit-fib ( n -- term )
1 (digit-fib) ;
<PRIVATE
: digit-fib* ( n -- term )
- 1- 5 log10 2 / + phi log10 / ceiling >integer ;
+ 1 - 5 log10 2 / + phi log10 / ceiling >integer ;
PRIVATE>
1 1000 (a,b) [ prime? ] filter [ 1 swap / ] map ;
: (mult-order) ( n a m -- k )
- 3dup ^ swap mod 1 = [ 2nip ] [ 1+ (mult-order) ] if ;
+ 3dup ^ swap mod 1 = [ 2nip ] [ 1 + (mult-order) ] if ;
PRIVATE>
dup sq -rot * + + ;
: (consecutive-primes) ( b a n -- m )
- 3dup quadratic prime? [ 1+ (consecutive-primes) ] [ 2nip ] if ;
+ 3dup quadratic prime? [ 1 + (consecutive-primes) ] [ 2nip ] if ;
: consecutive-primes ( a b -- m )
swap 0 (consecutive-primes) ;
PRIVATE>
: euler030 ( -- answer )
- 325537 [0,b) [ dup sum-fifth-powers = ] filter sum 1- ;
+ 325537 [0,b) [ dup sum-fifth-powers = ] filter sum 1 - ;
! [ euler030 ] 100 ave-time
! 1700 ms ave run time - 64.84 SD (100 trials)
: (circular?) ( seq n -- ? )
dup 0 > [
2dup rotate 10 digits>integer
- prime? [ 1- (circular?) ] [ 2drop f ] if
+ prime? [ 1 - (circular?) ] [ 2drop f ] if
] [
2drop t
] if ;
: circular? ( seq -- ? )
- dup length 1- (circular?) ;
+ dup length 1 - (circular?) ;
PRIVATE>
pick length 8 > [
2drop 10 digits>integer
] [
- [ * number>digits over push-all ] 2keep 1+ (concat-product)
+ [ * number>digits over push-all ] 2keep 1 + (concat-product)
] if ;
: concat-product ( n -- m )
p-count get length ;
: adjust-p-count ( n -- )
- max-p 1- over <range> p-count get
- [ [ 1+ ] change-nth ] curry each ;
+ max-p 1 - over <range> p-count get
+ [ [ 1 + ] change-nth ] curry each ;
: (count-perimeters) ( seq -- )
dup sum max-p < [
: (concat-upto) ( n limit str -- str )
2dup length > [
- pick number>string over push-all rot 1+ -rot (concat-upto)
+ pick number>string over push-all rot 1 + -rot (concat-upto)
] [
2nip
] if ;
SBUF" " clone 1 -rot (concat-upto) ;
: nth-integer ( n str -- m )
- [ 1- ] dip nth 1string string>number ;
+ [ 1 - ] dip nth 1string string>number ;
PRIVATE>
: (triangle-upto) ( limit n -- )
2dup nth-triangle > [
- dup nth-triangle , 1+ (triangle-upto)
+ dup nth-triangle , 1 + (triangle-upto)
] [
2drop
] if ;
<PRIVATE
: triangle? ( n -- ? )
- 8 * 1+ sqrt 1- 2 / 1 mod zero? ;
+ 8 * 1 + sqrt 1 - 2 / 1 mod zero? ;
PRIVATE>
<PRIVATE
: subseq-divisible? ( n index seq -- ? )
- [ 1- dup 3 + ] dip subseq 10 digits>integer swap divisor? ;
+ [ 1 - dup 3 + ] dip subseq 10 digits>integer swap divisor? ;
: interesting? ( seq -- ? )
{
<PRIVATE
: nth-pentagonal ( n -- seq )
- dup 3 * 1- * 2 / ;
+ dup 3 * 1 - * 2 / ;
: sum-and-diff? ( m n -- ? )
[ + ] [ - ] 2bi [ pentagonal? ] bi@ and ;
<PRIVATE
: nth-hexagonal ( n -- m )
- dup 2 * 1- * ;
+ dup 2 * 1 - * ;
DEFER: next-solution
dup pentagonal? [ nip ] [ drop next-solution ] if ;
: next-solution ( n -- m )
- 1+ dup nth-hexagonal (next-solution) ;
+ 1 + dup nth-hexagonal (next-solution) ;
PRIVATE>
dup perfect-squares [ 2 * - ] with map [ prime? ] any? ;
: next-odd-composite ( n -- m )
- dup odd? [ 2 + ] [ 1+ ] if dup prime? [ next-odd-composite ] when ;
+ dup odd? [ 2 + ] [ 1 + ] if dup prime? [ next-odd-composite ] when ;
: disprove-conjecture ( n -- m )
dup fits-conjecture? [ next-odd-composite disprove-conjecture ] when ;
swap - nip
] [
dup prime? [ [ drop 0 ] 2dip ] [
- 2dup unique-factors length = [ [ 1+ ] 2dip ] [ [ drop 0 ] 2dip ] if
- ] if 1+ (consecutive)
+ 2dup unique-factors length = [ [ 1 + ] 2dip ] [ [ drop 0 ] 2dip ] if
+ ] if 1 + (consecutive)
] if ;
: consecutive ( goal test -- n )
sieve get nth 0 = ;
: multiples ( n -- seq )
- sieve get length 1- over <range> ;
+ sieve get length 1 - over <range> ;
: increment-counts ( n -- )
- multiples [ sieve get [ 1+ ] change-nth ] each ;
+ multiples [ sieve get [ 1 + ] change-nth ] each ;
: prime-tau-upto ( limit -- seq )
dup initialize-sieve 2 swap [a,b) [
! Copyright (c) 2008 Aaron Schaefer.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math math.functions math.ranges project-euler.common sequences ;
+USING: kernel math math.functions math.ranges
+project-euler.common sequences ;
IN: project-euler.048
! http://projecteuler.net/index.php?section=problems&id=48
! --------
: euler048 ( -- answer )
- 1000 [1,b] [ dup ^ ] sigma 10 10 ^ mod ;
+ 1000 [1,b] [ dup ^ ] sigma 10 10^ mod ;
! [ euler048 ] 100 ave-time
! 276 ms run / 1 ms GC ave time - 100 trials
: count-digits ( n -- byte-array )
10 <byte-array> [
- '[ 10 /mod _ [ 1+ ] change-nth dup 0 > ] loop drop
+ '[ 10 /mod _ [ 1 + ] change-nth dup 0 > ] loop drop
] keep ;
HINTS: count-digits fixnum ;
2dup [ first ] bi@ > [ drop ] [ nip ] if ;
: continue? ( pair seq -- ? )
- [ first ] [ length 1- ] bi* < ;
+ [ first ] [ length 1 - ] bi* < ;
: (find-longest) ( best seq limit -- best )
[ longest-prime longest ] 2keep 2over continue? [
<PRIVATE
: map-nx ( n x -- seq )
- [ 1+ * ] with map ; inline
+ [ 1 + * ] with map ; inline
: all-same-digits? ( seq -- ? )
[ number>digits natural-sort ] map all-equal? ;
: next-all-same ( x n -- n )
dup candidate? [
2dup swap map-nx all-same-digits?
- [ nip ] [ 1+ next-all-same ] if
+ [ nip ] [ 1 + next-all-same ] if
] [
- 1+ next-all-same
+ 1 + next-all-same
] if ;
PRIVATE>
: (lychrel?) ( n iteration -- ? )
dup 50 < [
[ add-reverse ] dip over palindrome?
- [ 2drop f ] [ 1+ (lychrel?) ] if
+ [ 2drop f ] [ 1 + (lychrel?) ] if
] [
2drop t
] if ;
! (n-2)² + 4(n-1) = odd squares, no need to calculate
: prime-corners ( n -- m )
- 3 [1,b] swap '[ _ [ 1- * ] keep 2 - sq + prime? ] count ;
+ 3 [1,b] swap '[ _ [ 1 - * ] keep 2 - sq + prime? ] count ;
: total-corners ( n -- m )
- 1- 2 * ; foldable
+ 1 - 2 * ; foldable
: ratio-below? ( count length -- ? )
- total-corners 1+ / PERCENT_PRIME < ;
+ total-corners 1 + / PERCENT_PRIME < ;
: next-layer ( count length -- count' length' )
2 + [ prime-corners + ] keep ;
} cond product ;
: primorial-upto ( limit -- m )
- 1 swap '[ dup primorial _ <= ] [ 1+ dup primorial ] produce
+ 1 swap '[ dup primorial _ <= ] [ 1 + dup primorial ] produce
nip penultimate ;
PRIVATE>
p-count get length ;
: adjust-p-count ( n -- )
- max-p 1- over <range> p-count get
- [ [ 1+ ] change-nth ] curry each ;
+ max-p 1 - over <range> p-count get
+ [ [ 1 + ] change-nth ] curry each ;
: (count-perimeters) ( seq -- )
dup sum max-p < [
over zero? [
3drop
] [
- [ [ 1- 2array ] dip at ]
+ [ [ 1 - 2array ] dip at ]
[ [ use 2array ] dip at + ]
[ [ 2array ] dip set-at ] 3tri
] if ;
: (euler076) ( n -- m )
dup init
[ [ ways ] curry each-subproblem ]
- [ [ dup 2array ] dip at 1- ] 2bi ;
+ [ [ dup 2array ] dip at 1 - ] 2bi ;
PRIVATE>
567 [1,b] [ chain-ending ] map ;
: fast-chain-ending ( seq n -- m )
- dup 567 > [ next-link ] when 1- swap nth ;
+ dup 567 > [ next-link ] when 1 - swap nth ;
PRIVATE>
! --------
: euler097 ( -- answer )
- 2 7830457 10 10 ^ ^mod 28433 * 10 10 ^ mod 1+ ;
+ 2 7830457 10 10 ^ ^mod 28433 * 10 10 ^ mod 1 + ;
! [ euler097 ] 100 ave-time
! 0 ms ave run timen - 0.22 SD (100 trials)
flip first2 swap [ log ] map v* ;
: solve ( seq -- index )
- simplify [ supremum ] keep index 1+ ;
+ simplify [ supremum ] keep index 1 + ;
PRIVATE>
: euler100 ( -- answer )
1 1
- [ dup dup 1- * 2 * 10 24 ^ <= ]
+ [ dup dup 1 - * 2 * 10 24 ^ <= ]
[ tuck 6 * swap - 2 - ] while nip ;
! TODO: solution needs generalization
<PRIVATE
: nth* ( n seq -- elt/0 )
- [ length swap - 1- ] keep ?nth 0 or ;
+ [ length swap - 1 - ] keep ?nth 0 or ;
: next ( colortile seq -- )
[ nth* ] [ last + ] [ push ] tri ;
: ways ( length colortile -- permutations )
- V{ 1 } clone [ [ next ] 2curry times ] keep last 1- ;
+ V{ 1 } clone [ [ next ] 2curry times ] keep last 1 - ;
: (euler116) ( length -- permutations )
3 [1,b] [ ways ] with sigma ;
<PRIVATE
: sum-1toN ( n -- sum )
- dup 1+ * 2/ ; inline
+ dup 1 + * 2/ ; inline
: >base7 ( x -- y )
[ dup 0 > ] [ 7 /mod ] produce nip ;
: (use-digit) ( prev x index -- next )
- [ [ 1+ * ] [ sum-1toN 7 sum-1toN ] bi ] dip ^ * + ;
+ [ [ 1 + * ] [ sum-1toN 7 sum-1toN ] bi ] dip ^ * + ;
: (euler148) ( x -- y )
>base7 0 [ (use-digit) ] reduce-index ;
:: (euler150) ( m -- n )
[let | table [ sums-triangle ] |
m [| x |
- x 1+ [| y |
+ x 1 + [| y |
m x - [0,b) [| z |
x z + table nth-unsafe
- [ y z + 1+ swap nth-unsafe ]
+ [ y z + 1 + swap nth-unsafe ]
[ y swap nth-unsafe ] bi -
] map partial-sum-infimum
] map-infimum
--- /dev/null
+USING: project-euler.151 tools.test ;
+IN: project-euler.151.tests
+
+[ 12138569781349/26138246400000 ] [ euler151 ] unit-test
: (pick-sheet) ( seq i -- newseq )
[
- <=> sgn
+ <=>
{
- { -1 [ ] }
- { 0 [ 1- ] }
- { 1 [ 1+ ] }
+ { +lt+ [ ] }
+ { +eq+ [ 1 - ] }
+ { +gt+ [ 1 + ] }
} case
] curry map-index ;
: (euler151) ( x -- y )
table get [ {
{ { 0 0 0 1 } [ 0 ] }
- { { 0 0 1 0 } [ { 0 0 0 1 } (euler151) 1+ ] }
- { { 0 1 0 0 } [ { 0 0 1 1 } (euler151) 1+ ] }
- { { 1 0 0 0 } [ { 0 1 1 1 } (euler151) 1+ ] }
+ { { 0 0 1 0 } [ { 0 0 0 1 } (euler151) 1 + ] }
+ { { 0 1 0 0 } [ { 0 0 1 1 } (euler151) 1 + ] }
+ { { 1 0 0 0 } [ { 0 1 1 1 } (euler151) 1 + ] }
[ [ dup length [ pick-sheet ] with map sum ] [ sum ] bi / ]
} case ] cache ;
{ 1 1 1 1 } (euler151)
] with-scope ;
-! TODO: doesn't work currently, problem in area of 'with map' in (euler151)
-
! [ euler151 ] 100 ave-time
! ? ms run time - 100 trials
{
{ [ dup 2 < ] [ drop 1 ] }
{ [ dup odd? ] [ 2/ fn ] }
- [ 2/ [ fn ] [ 1- fn ] bi + ]
+ [ 2/ [ fn ] [ 1 - fn ] bi + ]
} cond ;
: euler169 ( -- result )
: compute ( vec ratio -- )
{
- { [ dup integer? ] [ 1- 0 add-bits ] }
+ { [ dup integer? ] [ 1 - 0 add-bits ] }
{ [ dup 1 < ] [ 1 over - / dupd compute 1 1 add-bits ] }
[ [ 1 mod compute ] 2keep >integer 0 add-bits ]
} cond ;
pick [ next ] [ next ] bi
[ = ] [
pick equate
- [ 1+ ] dip
+ [ 1 + ] dip
] 2unless? (p186)
] [
drop nip
PRIVATE>
:: P_m ( m -- P_m )
- m [1,b] [| i | 2 i * m 1+ / i ^ ] PI ;
+ m [1,b] [| i | 2 i * m 1 + / i ^ ] PI ;
: euler190 ( -- answer )
2 15 [a,b] [ P_m truncate ] sigma ;
[ 0 prefix ] [ 0 suffix ] bi [ + ] 2map ;
: generate ( n -- seq )
- 1- { 1 } [ (generate) ] iterate concat prune ;
+ 1 - { 1 } [ (generate) ] iterate concat prune ;
: squarefree ( n -- ? )
factors all-unique? ;
: first-row ( n -- t )
[ <failure> <success> <failure> ] dip
- 1- [| a b c | b c <block> a b ] times 2drop ;
+ 1 - [| a b c | b c <block> a b ] times 2drop ;
GENERIC: total ( t -- n )
M: block total [ total ] dup choice + ;
M: end total ways>> ;
: solve ( width height -- ways )
- [ first-row ] dip 1- [ next-row ] times total ;
+ [ first-row ] dip 1 - [ next-row ] times total ;
PRIVATE>
! Copyright (c) 2007, 2008 Aaron Schaefer.
! See http://factorcode.org/license.txt for BSD license.
-USING: continuations fry io kernel make math math.functions math.parser
- math.statistics memory tools.time ;
+USING: continuations fry io kernel make math math.functions
+math.parser math.statistics memory tools.time ;
IN: project-euler.ave-time
: nth-place ( x n -- y )
- 10 swap ^ [ * round >integer ] keep /f ;
+ 10^ [ * round >integer ] keep /f ;
: collect-benchmarks ( quot n -- seq )
[
'[ _ gc benchmark 1000 / , ] tuck
'[ _ _ with-datastack drop ]
]
- [ 1- ] tri* swap times call
+ [ 1 - ] tri* swap times call
] { } make ; inline
: ave-time ( quot n -- )
<PRIVATE
: max-children ( seq -- seq )
- [ dup length 1- [ nth-pair max , ] with each ] { } make ;
+ [ dup length 1 - [ nth-pair max , ] with each ] { } make ;
! Propagate one row into the upper one
: propagate ( bottom top -- newtop )
PRIVATE>
: alpha-value ( str -- n )
- >lower [ CHAR: a - 1+ ] sigma ;
+ >lower [ CHAR: a - 1 + ] sigma ;
: cartesian-product ( seq1 seq2 -- seq1xseq2 )
[ [ 2array ] with map ] curry map concat ;
-: log10 ( m -- n )
- log 10 log / ;
-
: mediant ( a/c b/d -- (a+b)/(c+d) )
2>fraction [ + ] 2bi@ / ;
[ dup 0 = not ] [ 10 /mod ] produce reverse nip ;
: number-length ( n -- m )
- log10 floor 1+ >integer ;
+ log10 floor 1 + >integer ;
: nth-prime ( n -- n )
- 1- lprimes lnth ;
+ 1 - lprimes lnth ;
: nth-triangle ( n -- n )
- dup 1+ * 2 / ;
+ dup 1 + * 2 / ;
: palindrome? ( n -- ? )
number>string dup reverse = ;
number>string natural-sort >string "123456789" = ;
: pentagonal? ( n -- ? )
- dup 0 > [ 24 * 1+ sqrt 1+ 6 / 1 mod zero? ] [ drop f ] if ;
+ dup 0 > [ 24 * 1 + sqrt 1 + 6 / 1 mod zero? ] [ drop f ] if ;
: penultimate ( seq -- elt )
dup length 2 - swap nth ;
! The divisor function, counts the number of divisors
: tau ( m -- n )
- group-factors flip second 1 [ 1+ * ] reduce ;
+ group-factors flip second 1 [ 1 + * ] reduce ;
! Optimized brute-force, is often faster than prime factorization
: tau* ( m -- n )
- factor-2s dup [ 1+ ]
+ factor-2s dup [ 1 + ]
[ perfect-square? -1 0 ? ]
[ dup sqrt >fixnum [1,b] ] tri* [
dupd divisor? [ [ 2 + ] dip ] when
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+USING: accessors arrays colors.constants combinators
+db.sqlite db.tuples db.types kernel locals math
+monads persistency sequences sequences.extras ui ui.gadgets.controls
+ui.gadgets.layout models.combinators ui.gadgets.labels
+ui.gadgets.scrollers ui.pens.solid io.files.temp ;
+FROM: sets => prune ;
+IN: recipes
+
+STORED-TUPLE: recipe { title { VARCHAR 100 } } { votes INTEGER } { txt TEXT } { genre { VARCHAR 100 } } ;
+: <recipe> ( title genre text -- recipe ) recipe new swap >>txt swap >>genre swap >>title 0 >>votes ;
+"recipes.db" temp-file <sqlite-db> recipe define-db
+: top-recipes ( offset search -- recipes ) <query> T{ recipe } rot >>title >>tuple
+ "votes" >>order 30 >>limit swap >>offset get-tuples ;
+: top-genres ( -- genres ) f f top-recipes [ genre>> ] map prune 4 short head-slice ;
+
+: interface ( -- book ) [
+ [
+ [ $ TOOLBAR $ ] <hbox> COLOR: AliceBlue <solid> >>interior ,
+ [ "Genres:" <label> , <spacer> $ ALL $ $ GENRES $ ] <hbox>
+ { 5 0 } >>gap COLOR: gray <solid> >>interior ,
+ $ RECIPES $
+ ] <vbox> ,
+ [
+ [ "Title:" <label> , $ TITLE $ "Genre:" <label> , $ GENRE $ ] <hbox> ,
+ $ BODY $
+ $ BUTTON $
+ ] <vbox> ,
+ ] <book*> { 350 245 } >>pref-dim ;
+
+:: recipe-browser ( -- ) [ [
+ interface
+ <table*> :> tbl
+ "okay" <model-border-btn> BUTTON -> :> ok
+ IMG-MODEL-BTN: submit [ store-tuple ] >>value TOOLBAR -> :> submit
+ IMG-MODEL-BTN: love 1 >>value TOOLBAR ->
+ IMG-MODEL-BTN: hate -1 >>value -> 2array merge :> votes
+ IMG-MODEL-BTN: back -> [ -30 ] <$
+ IMG-MODEL-BTN: more -> [ 30 ] <$ 2array merge :> viewed
+ <spacer> <model-field*> ->% 1 :> search
+ submit ok [ [ drop ] ] <$ 2array merge [ drop ] >>value :> quot
+ viewed 0 [ + ] fold search ok t <basic> "all" <model-btn> ALL ->
+ tbl selection>> votes [ [ + ] curry change-votes modify-tuple ] 2$>
+ 4array merge
+ [ drop [ f ] [ "%" dup surround <pattern> ] if-empty top-recipes ] 3fmap :> ups
+ ups [ top-genres [ <model-btn> GENRES -> ] map merge ] bind*
+ [ text>> T{ recipe } swap >>genre get-tuples ] fmap
+ tbl swap ups 2merge >>model
+ [ [ title>> ] [ genre>> ] bi 2array ] >>quot
+ { "Title" "Genre" } >>column-titles dup <scroller> RECIPES ,% 1 actions>>
+ submit [ "" dup dup <recipe> ] <$ 2array merge
+ { [ [ title>> ] fmap <model-field> TITLE ->% .5 ]
+ [ [ genre>> ] fmap <model-field> GENRE ->% .5 ]
+ [ [ txt>> ] fmap <model-editor> BODY ->% 1 ]
+ } cleave
+ [ <recipe> ] 3fmap
+ [ [ 1 ] <$ ]
+ [ quot ok updates #1 [ call( recipe -- ) 0 ] 2fmap ] bi
+ 2merge 0 <basic> switch-models >>model
+ ] with-interface "recipes" open-window ] with-ui ;
+
+MAIN: recipe-browser
\ No newline at end of file
--- /dev/null
+Database backed recipe sharing
\ No newline at end of file
! Copyright (C) 2009 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors http.client kernel unicode.categories
-sequences urls splitting combinators splitting.monotonic
-combinators.short-circuit assocs unicode.case arrays
-math.parser calendar.format make fry present globs
-multiline regexp.combinators regexp ;
+USING: accessors arrays assocs calendar.format combinators
+combinators.short-circuit fry globs http.client kernel make
+math.parser multiline namespaces present regexp
+regexp.combinators sequences sets splitting splitting.monotonic
+unicode.case unicode.categories urls ;
IN: robots
! visit-time is GMT, request-rate is pages/second
! crawl-rate is seconds
+SYMBOL: robot-identities
+robot-identities [ { "FactorSpider" } ] initialize
+
TUPLE: robots site sitemap rules rules-quot ;
: <robots> ( site sitemap rules -- robots )
derive-urls [ <glob> ] map <and> <not>
] bi 2array <or> '[ _ matches? ] ;
+: relevant-rules ( robots -- rules )
+ [
+ user-agents>> [
+ robot-identities get [ swap glob-matches? ] with any?
+ ] any?
+ ] filter ;
+
PRIVATE>
: parse-robots.txt ( string -- sitemaps rules-seq )
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2009 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators io kernel lists math math.parser
+sequences splitting ;
+IN: rpn
+
+SINGLETONS: add-insn sub-insn mul-insn div-insn ;
+TUPLE: push-insn value ;
+
+GENERIC: eval-insn ( stack insn -- stack )
+
+: binary-op ( stack quot: ( x y -- z ) -- stack )
+ [ uncons uncons ] dip dip cons ; inline
+
+M: add-insn eval-insn drop [ + ] binary-op ;
+M: sub-insn eval-insn drop [ - ] binary-op ;
+M: mul-insn eval-insn drop [ * ] binary-op ;
+M: div-insn eval-insn drop [ / ] binary-op ;
+M: push-insn eval-insn value>> swons ;
+
+: rpn-tokenize ( string -- string' )
+ " " split harvest sequence>list ;
+
+: rpn-parse ( string -- tokens )
+ rpn-tokenize [
+ {
+ { "+" [ add-insn ] }
+ { "-" [ sub-insn ] }
+ { "*" [ mul-insn ] }
+ { "/" [ div-insn ] }
+ [ string>number push-insn boa ]
+ } case
+ ] lmap ;
+
+: print-stack ( list -- )
+ [ number>string print ] leach ;
+
+: rpn-eval ( tokens -- )
+ nil [ eval-insn ] foldl print-stack ;
+
+: rpn ( -- )
+ "RPN> " write flush
+ readln [ rpn-parse rpn-eval rpn ] when* ;
+
+MAIN: rpn
--- /dev/null
+Simple RPN calculator
--- /dev/null
+USING: io io.encodings.utf8 io.launcher kernel sequences ;
+IN: run-desc
+: run-desc ( desc -- result ) utf8 [ contents [ but-last ] [ f ] if* ] with-process-reader ;
[ "abcd" <sequence-parser> [ "ab" take-sequence drop ] [ "cd" take-sequence ] bi ] unit-test
[ f ]
-[
- "\"abc\" asdf" <sequence-parser>
- [ CHAR: \ CHAR: " take-quoted-string drop ] [ "asdf" take-sequence ] bi
-] unit-test
-
-[ "abc\\\"def" ]
-[
- "\"abc\\\"def\" asdf" <sequence-parser>
- CHAR: \ CHAR: " take-quoted-string
-] unit-test
-
-[ "asdf" ]
-[
- "\"abc\" asdf" <sequence-parser>
- [ CHAR: \ CHAR: " take-quoted-string drop ]
- [ skip-whitespace "asdf" take-sequence ] bi
-] unit-test
-
-[ f ]
-[
- "\"abc asdf" <sequence-parser>
- CHAR: \ CHAR: " take-quoted-string
-] unit-test
-
-[ "\"abc" ]
-[
- "\"abc asdf" <sequence-parser>
- [ CHAR: \ CHAR: " take-quoted-string drop ]
- [ "\"abc" take-sequence ] bi
-] unit-test
-
-[ "c" ]
-[ "c" <sequence-parser> take-token ] unit-test
-
-[ f ]
-[ "" <sequence-parser> take-token ] unit-test
-
-[ "abcd e \\\"f g" ]
-[ "\"abcd e \\\"f g\"" <sequence-parser> CHAR: \ CHAR: " take-token* ] unit-test
-
-[ "" ]
[ "" <sequence-parser> take-rest ] unit-test
-[ "" ]
+[ f ]
[ "abc" <sequence-parser> dup "abc" take-sequence drop take-rest ] unit-test
[ f ]
[ "abcd" ] [ "abcd" <sequence-parser> 4 take-n ] unit-test
[ "abcd" "efg" ] [ "abcdefg" <sequence-parser> [ 4 take-n ] [ take-rest ] bi ] unit-test
-[ "asdfasdf" ] [
- "/*asdfasdf*/" <sequence-parser> take-c-comment
-] unit-test
-
-[ "k" ] [
- "/*asdfasdf*/k" <sequence-parser> [ take-c-comment drop ] [ take-rest ] bi
-] unit-test
-
-[ "omg" ] [
- "//asdfasdf\nomg" <sequence-parser>
- [ take-c++-comment drop ] [ take-rest ] bi
-] unit-test
-
-[ "omg" ] [
- "omg" <sequence-parser>
- [ take-c++-comment drop ] [ take-rest ] bi
-] unit-test
-
-[ "/*asdfasdf" ] [
- "/*asdfasdf" <sequence-parser> [ take-c-comment drop ] [ take-rest ] bi
-] unit-test
-
-[ "asdf" "eoieoei" ] [
- "//asdf\neoieoei" <sequence-parser>
- [ take-c++-comment ] [ take-rest ] bi
-] unit-test
-
-[ f "33asdf" ]
-[ "33asdf" <sequence-parser> [ take-c-identifier ] [ take-rest ] bi ] unit-test
-
-[ "asdf" ]
-[ "asdf" <sequence-parser> take-c-identifier ] unit-test
-
-[ "_asdf" ]
-[ "_asdf" <sequence-parser> take-c-identifier ] unit-test
-
-[ "_asdf400" ]
-[ "_asdf400" <sequence-parser> take-c-identifier ] unit-test
-
-[ "123" ]
-[ "123jjj" <sequence-parser> take-c-integer ] unit-test
-
-[ "123uLL" ]
-[ "123uLL" <sequence-parser> take-c-integer ] unit-test
-
-[ "123ull" ]
-[ "123ull" <sequence-parser> take-c-integer ] unit-test
-
-[ "123u" ]
-[ "123u" <sequence-parser> take-c-integer ] unit-test
-
-[ 36 ]
-[
- " //jofiejoe\n //eoieow\n/*asdf*/\n "
- <sequence-parser> skip-whitespace/comments n>>
-] unit-test
-
[ f ]
[ "\n" <sequence-parser> take-integer ] unit-test
! Copyright (C) 2005, 2009 Daniel Ehrenberg, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces math kernel sequences accessors fry circular
-unicode.case unicode.categories locals combinators.short-circuit
-make combinators io splitting math.parser math.ranges
-generalizations sorting.functor math.order sorting.slots ;
+USING: accessors circular combinators.short-circuit fry io
+kernel locals math math.order sequences sorting.functor
+sorting.slots unicode.categories ;
IN: sequence-parser
TUPLE: sequence-parser sequence n ;
: advance* ( sequence-parser -- )
advance drop ; inline
+: next ( sequence-parser -- obj ) [ current ] [ advance* ] bi ;
+
: get+increment ( sequence-parser -- char/f )
[ current ] [ advance drop ] bi ; inline
] take-until :> found
growing sequence sequence= [
found dup length
- growing length 1- - head
+ growing length 1 - - head
sequence-parser [ growing length - 1 + ] change-n drop
! sequence-parser advance drop
] [
: skip-whitespace-eol ( sequence-parser -- sequence-parser )
[ [ current " \t\r" member? not ] take-until drop ] keep ;
-: take-c-comment ( sequence-parser -- seq/f )
- [
- dup "/*" take-sequence [
- "*/" take-until-sequence*
- ] [
- drop f
- ] if
- ] with-sequence-parser ;
-
-: take-c++-comment ( sequence-parser -- seq/f )
- [
- dup "//" take-sequence [
- [
- [
- { [ current CHAR: \n = ] [ sequence-parse-end? ] } 1||
- ] take-until
- ] [
- advance drop
- ] bi
- ] [
- drop f
- ] if
- ] with-sequence-parser ;
-
-: skip-whitespace/comments ( sequence-parser -- sequence-parser )
- skip-whitespace-eol
- {
- { [ dup take-c-comment ] [ skip-whitespace/comments ] }
- { [ dup take-c++-comment ] [ skip-whitespace/comments ] }
- [ ]
- } cond ;
-
-: take-define-identifier ( sequence-parser -- string )
- skip-whitespace/comments
- [ current { [ blank? ] [ CHAR: ( = ] } 1|| ] take-until ;
-
: take-rest-slice ( sequence-parser -- sequence/f )
[ sequence>> ] [ n>> ] bi
2dup [ length ] dip < [ 2drop f ] [ tail-slice ] if ; inline
: take-rest ( sequence-parser -- sequence )
- [ take-rest-slice ] [ sequence>> like ] bi ;
+ [ take-rest-slice ] [ sequence>> like ] bi f like ;
: take-until-object ( sequence-parser obj -- sequence )
'[ current _ = ] take-until ;
: parse-sequence ( sequence quot -- )
[ <sequence-parser> ] dip call ; inline
-:: take-quoted-string ( sequence-parser escape-char quote-char -- string )
- sequence-parser n>> :> start-n
- sequence-parser advance
- [
- {
- [ { [ previous escape-char = ] [ current quote-char = ] } 1&& ]
- [ current quote-char = not ]
- } 1||
- ] take-while :> string
- sequence-parser current quote-char = [
- sequence-parser advance* string
- ] [
- start-n sequence-parser (>>n) f
- ] if ;
-
-: (take-token) ( sequence-parser -- string )
- skip-whitespace [ current { [ blank? ] [ f = ] } 1|| ] take-until ;
-
-:: take-token* ( sequence-parser escape-char quote-char -- string/f )
- sequence-parser skip-whitespace
- dup current {
- { quote-char [ escape-char quote-char take-quoted-string ] }
- { f [ drop f ] }
- [ drop (take-token) ]
- } case ;
-
-: take-token ( sequence-parser -- string/f )
- CHAR: \ CHAR: " take-token* ;
-
: take-integer ( sequence-parser -- n/f )
[ current digit? ] take-while ;
:: take-n ( sequence-parser n -- seq/f )
n sequence-parser [ n>> + ] [ sequence>> length ] bi > [
- f
+ sequence-parser take-rest
] [
sequence-parser n>> dup n + sequence-parser sequence>> subseq
sequence-parser [ n + ] change-n drop
] if ;
-: c-identifier-begin? ( ch -- ? )
- CHAR: a CHAR: z [a,b]
- CHAR: A CHAR: Z [a,b]
- { CHAR: _ } 3append member? ;
-
-: c-identifier-ch? ( ch -- ? )
- CHAR: a CHAR: z [a,b]
- CHAR: A CHAR: Z [a,b]
- CHAR: 0 CHAR: 9 [a,b]
- { CHAR: _ } 4 nappend member? ;
-
-: (take-c-identifier) ( sequence-parser -- string/f )
- dup current c-identifier-begin? [
- [ current c-identifier-ch? ] take-while
- ] [
- drop f
- ] if ;
-
-: take-c-identifier ( sequence-parser -- string/f )
- [ (take-c-identifier) ] with-sequence-parser ;
-
<< "length" [ length ] define-sorting >>
: sort-tokens ( seq -- seq' )
swap
'[ _ [ swap take-sequence ] with-sequence-parser ] find nip ;
-
: take-longest ( sequence-parser seq -- seq )
sort-tokens take-first-matching ;
-: take-c-integer ( sequence-parser -- string/f )
- [
- dup take-integer [
- swap
- { "ull" "uLL" "Ull" "ULL" "ll" "LL" "l" "L" "u" "U" }
- take-longest [ append ] when*
- ] [
- drop f
- ] if*
- ] with-sequence-parser ;
-
-CONSTANT: c-punctuators
- {
- "[" "]" "(" ")" "{" "}" "." "->"
- "++" "--" "&" "*" "+" "-" "~" "!"
- "/" "%" "<<" ">>" "<" ">" "<=" ">=" "==" "!=" "^" "|" "&&" "||"
- "?" ":" ";" "..."
- "=" "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" "&=" "^=" "|="
- "," "#" "##"
- "<:" ":>" "<%" "%>" "%:" "%:%:"
- }
-
-: take-c-punctuator ( sequence-parser -- string/f )
- c-punctuators take-longest ;
-
: write-full ( sequence-parser -- ) sequence>> write ;
: write-rest ( sequence-parser -- ) take-rest write ;
--- /dev/null
+! Copyright (C) 2009 Maximilian Lupke.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs help.markup help.syntax sequences ;
+IN: sequences.abbrev
+
+HELP: abbrev
+{ $values
+ { "seqs" sequence }
+ { "assoc" assoc }
+}
+{ $description "Calculates an assoc of { prefix sequence } pairs with prefix being an prefix of each element of sequence for each element in " { $snippet "seqs" } "." } ;
+
+HELP: unique-abbrev
+{ $values
+ { "seqs" sequence }
+ { "assoc" assoc }
+}
+{ $description "Calculates an assoc of { prefix { sequence } } pairs with prefix being an unambiguous prefix of sequence in seqs." } ;
+
+ARTICLE: "sequences.abbrev" "Examples of abbrev usage"
+"It is probably easiest to just run examples to understand abbrev."
+{ $code
+ "{ \"hello\" \"help\" } abbrev"
+ "{ \"hello\" \"help\" } unique-abbrev"
+}
+;
+
+ABOUT: "sequences.abbrev"
--- /dev/null
+USING: assocs sequences.abbrev tools.test ;
+IN: sequences.abbrev.tests
+
+[ { "hello" "help" } ] [
+ "he" { "apple" "hello" "help" } abbrev at
+] unit-test
+
+[ f ] [
+ "he" { "apple" "hello" "help" } unique-abbrev at
+] unit-test
+
+[ { "apple" } ] [
+ "a" { "apple" "hello" "help" } abbrev at
+] unit-test
+
+[ { "apple" } ] [
+ "a" { "apple" "hello" "help" } unique-abbrev at
+] unit-test
+
+[ f ] [
+ "a" { "hello" "help" } abbrev at
+] unit-test
+
+[ f ] [
+ "a" { "hello" "help" } unique-abbrev at
+] unit-test
--- /dev/null
+! Copyright (C) 2009 Maximilian Lupke.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays assocs fry kernel math.ranges sequences ;
+IN: sequences.abbrev
+
+<PRIVATE
+
+: prefixes ( seq -- prefixes )
+ dup length [1,b] [ head ] with map ;
+
+: (abbrev) ( seq -- assoc )
+ [ prefixes ] keep 1array '[ _ ] H{ } map>assoc ;
+
+: assoc-merge ( assoc1 assoc2 -- assoc3 )
+ tuck '[ over _ at dup [ append ] [ drop ] if ] assoc-map assoc-union ;
+
+PRIVATE>
+
+: abbrev ( seqs -- assoc )
+ [ (abbrev) ] map H{ } [ assoc-merge ] reduce ;
+
+: unique-abbrev ( seqs -- assoc )
+ abbrev [ nip length 1 = ] assoc-filter ;
--- /dev/null
+Maximilian Lupke
--- /dev/null
+USING: arrays kernel locals math sequences ;
+IN: sequences.extras
+: reduce1 ( seq quot -- result ) [ unclip ] dip reduce ; inline
+
+:: reduce-r
+ ( list identity quot: ( obj1 obj2 -- obj ) -- result )
+ list empty?
+ [ identity ]
+ [ list rest identity quot reduce-r list first quot call ] if ;
+ inline recursive
+
+! Quot must have static stack effect, unlike "reduce"
+:: reduce* ( seq id quot -- result ) seq
+ [ id ]
+ [ unclip id swap quot call( prev elt -- next ) quot reduce* ] if-empty ; inline recursive
+
+:: combos ( list1 list2 -- result ) list2 [ [ 2array ] curry list1 swap map ] map concat ;
+: find-all ( seq quot -- elts ) [ [ length iota ] keep ] dip
+ [ dupd call( a -- ? ) [ 2array ] [ 2drop f ] if ] curry 2map [ ] filter ; inline
+
+: insert-sorted ( elt seq -- seq ) 2dup [ < ] with find drop over length or swap insert-nth ;
\ No newline at end of file
[ lengths>> ns ] [ nip sequences>> ] 2bi ;
:: (carry-n) ( ns lengths i -- )
- ns length i 1+ = [
+ ns length i 1 + = [
i ns nth i lengths nth = [
0 i ns set-nth
- i 1+ ns [ 1+ ] change-nth
- ns lengths i 1+ (carry-n)
+ i 1 + ns [ 1 + ] change-nth
+ ns lengths i 1 + (carry-n)
] when
] unless ;
0 (carry-n) ;
: product-iter ( ns lengths -- )
- [ 0 over [ 1+ ] change-nth ] dip carry-ns ;
+ [ 0 over [ 1 + ] change-nth ] dip carry-ns ;
: start-product-iter ( sequence-product -- ns lengths )
[ [ drop 0 ] map ] [ [ length ] map ] bi ;
0 :> i!
sequences [ length ] [ * ] map-reduce sequences
[| result |
- sequences [ quot call i result set-nth i 1+ i! ] product-each
+ sequences [ quot call i result set-nth i 1 + i! ] product-each
result
] new-like ; inline
--- /dev/null
+USING: accessors assocs fry generalizations kernel math
+namespaces parser sequences words ;
+IN: set-n
+: get* ( var n -- val ) namestack dup length rot - head assoc-stack ;
+
+: set* ( val var n -- ) 1 + namestack [ length swap - ] keep nth set-at ;
+
+! dynamic lambda
+SYNTAX: :| (:) dup in>> dup length [ spin '[ _ narray _ swap zip _ bind ] ] 2curry dip define-declared ;
\ No newline at end of file
[ first3 ] dip head 3array ;
: strip-tease ( data -- seq )
- dup third length 1- [
+ dup third length 1 - [
2 + (strip-tease)
] with map ;
[ lexenv self>> suffix ] dip <lambda> ;
: compile-method-body ( lexenv block -- quot )
- [ [ (compile-method-body) ] [ arguments>> length 1+ ] bi ] 2keep
+ [ [ (compile-method-body) ] [ arguments>> length 1 + ] bi ] 2keep
make-return ;
: compile-method ( lexenv ast-method -- )
: compile-smalltalk ( statement -- quot )
[ empty-lexenv ] dip [ compile-sequence nip 0 ]
- 2keep make-return ;
\ No newline at end of file
+ 2keep make-return ;
: (make-reflection-depthbuffer) ( -- depthbuffer )
gen-renderbuffer [
- GL_RENDERBUFFER_EXT swap glBindRenderbufferEXT
- GL_RENDERBUFFER_EXT GL_DEPTH_COMPONENT32 (reflection-dim) glRenderbufferStorageEXT
+ GL_RENDERBUFFER swap glBindRenderbuffer
+ GL_RENDERBUFFER GL_DEPTH_COMPONENT32 (reflection-dim) glRenderbufferStorage
] keep ;
: (make-reflection-framebuffer) ( depthbuffer -- framebuffer )
gen-framebuffer dup [
- swap [ GL_FRAMEBUFFER_EXT GL_DEPTH_ATTACHMENT_EXT GL_RENDERBUFFER_EXT ] dip
- glFramebufferRenderbufferEXT
+ swap [ GL_DRAW_FRAMEBUFFER GL_DEPTH_ATTACHMENT GL_RENDERBUFFER ] dip
+ glFramebufferRenderbuffer
] with-framebuffer ;
: (plane-program) ( -- program )
: (reflection-face) ( gadget face -- )
swap reflection-texture>> [
- GL_FRAMEBUFFER_EXT
- GL_COLOR_ATTACHMENT0_EXT
- ] 2dip 0 glFramebufferTexture2DEXT
+ GL_DRAW_FRAMEBUFFER
+ GL_COLOR_ATTACHMENT0
+ ] 2dip 0 glFramebufferTexture2D
check-framebuffer ;
: (draw-reflection-texture) ( gadget -- )
[ host>> = ] with partition ;
: add-spidered ( spider spider-result -- )
- [ [ 1+ ] change-count ] dip
+ [ [ 1 + ] change-count ] dip
2dup [ spidered>> ] [ dup url>> ] bi* rot set-at
[ filter-base-links ] 2keep
- depth>> 1+ swap
+ depth>> 1 + swap
[ add-nonmatching ]
[ tuck [ apply-filters ] 2dip add-todo ] 2bi ;
+++ /dev/null
-Sam Anklesaria
\ No newline at end of file
+++ /dev/null
-USING: combinators effects kernel math sequences splitting
-strings.parser ;
-IN: str-fry
-: str-fry ( str -- quot ) "_" split
- [ unclip [ [ rot glue ] reduce ] 2curry ]
- [ length 1 - 1 <effect> [ call-effect ] 2curry ] bi ;
-SYNTAX: I" parse-string rest str-fry over push-all ;
\ No newline at end of file
+++ /dev/null
-String Frying
\ No newline at end of file
DEFER: search
: assume ( n x y -- )
- [ >board ] 2keep [ [ 1+ ] dip search ] 2keep f>board ;
+ [ >board ] 2keep [ [ 1 + ] dip search ] 2keep f>board ;
: attempt ( n x y -- )
{
[ assume ]
} cond ;
-: solve ( x y -- ) 9 [ 1+ 2over attempt ] each 2drop ;
+: solve ( x y -- ) 9 [ 1 + 2over attempt ] each 2drop ;
: board. ( board -- )
standard-table-style [
: search ( x y -- )
{
- { [ over 9 = ] [ [ drop 0 ] dip 1+ search ] }
+ { [ over 9 = ] [ [ drop 0 ] dip 1 + search ] }
{ [ over 0 = over 9 = and ] [ 2drop solution. ] }
- { [ 2dup board> ] [ [ 1+ ] dip search ] }
+ { [ 2dup board> ] [ [ 1 + ] dip search ] }
[ solve ]
} cond ;
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+USING: accessors arrays combinators.short-circuit grouping kernel lists
+lists.lazy locals math math.functions math.parser math.ranges
+models.product monads random sequences sets ui ui.gadgets.controls
+ui.gadgets.layout models.combinators ui.gadgets.alerts vectors fry
+ui.gadgets.labels ;
+IN: sudokus
+
+: row ( index -- row ) 1 + 9 / ceiling ;
+: col ( index -- col ) 9 mod 1 + ;
+: sq ( index -- square ) [ row ] [ col ] bi [ 3 / ceiling ] bi@ 2array ;
+: near ( a pos -- ? ) { [ [ row ] bi@ = ] [ [ col ] bi@ = ] [ [ sq ] bi@ = ] } 2|| ;
+: nth-or-lower ( n seq -- elt ) [ length 1 - 2dup > [ nip ] [ drop ] if ] keep nth ;
+
+:: solutions ( puzzle random? -- solutions )
+ f puzzle random? [ indices [ f ] [ random? swap nth-or-lower ] if-empty ] [ index ] if
+ [ :> pos
+ 1 9 [a,b] 80 iota [ pos near ] filter [ puzzle nth ] map prune diff
+ [ 1array puzzle pos cut-slice rest surround ] map >list [ random? solutions ] bind
+ ] [ puzzle list-monad return ] if* ;
+
+: solution ( puzzle random? -- solution ) dupd solutions dup +nil+ = [ drop "Unsolvable" alert* ] [ nip car ] if ;
+: hint ( puzzle -- puzzle' ) [ [ f swap indices random dup ] [ f solution ] bi nth ] keep swapd >vector [ set-nth ] keep ;
+: create ( difficulty -- puzzle ) 81 [ f ] replicate
+ 40 random solution [ [ dup length random f spin set-nth ] curry times ] keep ;
+
+: do-sudoku ( -- ) [ [
+ [
+ 81 [ "" ] replicate <basic> switch-models [ [ <basic> ] map 9 group [ 3 group ] map 3 group
+ [ [ [ <spacer> [ [ <model-field> ->% 2 [ string>number ] fmap ]
+ map <spacer> ] map concat ] <hbox> , ] map concat <spacer> ] map concat <product>
+ [ "Difficulty:" <label> , "1" <basic> <model-field> -> [ string>number 1 or 1 + 10 * ] fmap
+ "Generate" <model-border-btn> -> updates [ create ] fmap <spacer>
+ "Hint" <model-border-btn> -> "Solve" <model-border-btn> -> ] <hbox> ,
+ roll [ swap updates ] curry bi@
+ [ [ hint ] fmap ] [ [ f solution ] fmap ] bi* 3array merge [ [ [ number>string ] [ "" ] if* ] map ] fmap
+ ] bind
+ ] with-self , ] <vbox> { 280 220 } >>pref-dim
+ "Sudoku Sleuth" open-window ] with-ui ;
+
+MAIN: do-sudoku
\ No newline at end of file
--- /dev/null
+graphical sudoku solver
\ No newline at end of file
: svg-string>number ( string -- number )
{ { CHAR: E CHAR: e } } substitute "e" split1
- [ string>number ] [ [ string>number 10 swap ^ ] [ 1 ] if* ] bi* *
+ [ string>number ] [ [ string>number 10^ ] [ 1 ] if* ] bi* *
>float ;
: degrees ( deg -- rad ) pi * 180.0 / ;
memory-status MEMORYSTATUSEX-ullAvailVirtual ;
: computer-name ( -- string )
- MAX_COMPUTERNAME_LENGTH 1+
+ MAX_COMPUTERNAME_LENGTH 1 +
[ <byte-array> dup ] keep <uint>
GetComputerName win32-error=0/f alien>native-string ;
-USING: accessors arrays byte-arrays combinators fry grouping
-images kernel math math.affine-transforms math.order
-math.vectors noise random sequences ;
+USING: accessors arrays byte-arrays combinators
+combinators.smart fry grouping images kernel math
+math.affine-transforms math.order math.vectors noise random
+sequences ;
IN: terrain.generation
CONSTANT: terrain-segment-size { 512 512 }
TUPLE: segment image ;
+: <terrain-image> ( bytes -- image )
+ <image>
+ swap >>bitmap
+ RGBA >>component-order
+ ubyte-components >>component-type
+ terrain-segment-size >>dim ;
+
: terrain-segment ( terrain at -- image )
- {
- [ big-noise-segment ]
- [ small-noise-segment ]
- [ tiny-noise-segment ]
- [ padding ]
- } 2cleave
- 4array flip concat >byte-array
- [ terrain-segment-size RGBA f ] dip image boa ;
+ [
+ {
+ [ big-noise-segment ]
+ [ small-noise-segment ]
+ [ tiny-noise-segment ]
+ [ padding ]
+ } 2cleave
+ ] output>array flip B{ } concat-as <terrain-image> ;
: 4max ( a b c d -- max )
max max max ; inline
destructors grid-meshes ;
IN: terrain
-CONSTANT: FOV $[ 2.0 sqrt 1+ ]
+CONSTANT: FOV $[ 2.0 sqrt 1 + ]
CONSTANT: NEAR-PLANE $[ 1.0 1024.0 / ]
CONSTANT: FAR-PLANE 2.0
CONSTANT: PLAYER-START-LOCATION { 0.5 0.51 0.5 }
[ not ] change-paused? drop ;
: level>> ( tetris -- level )
- rows>> 1+ 10 / ceiling ;
+ rows>> 1 + 10 / ceiling ;
: update-interval ( tetris -- interval )
- level>> 1- 60 * 1000 swap - ;
+ level>> 1 - 60 * 1000 swap - ;
: add-block ( tetris block -- )
over board>> spin current-piece tetromino>> colour>> set-block ;
{ 2 [ 100 ] }
{ 3 [ 300 ] }
{ 4 [ 1200 ] }
- } case swap 1+ * ;
+ } case swap 1 + * ;
: add-score ( tetris n-rows -- tetris )
over level>> swap rows-score swap [ + ] change-score ;
tetrominoes get random ;
: blocks-max ( blocks quot -- max )
- map [ 1+ ] [ max ] map-reduce ; inline
+ map [ 1 + ] [ max ] map-reduce ; inline
: blocks-width ( blocks -- width )
[ first ] blocks-max ;
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel tokyo.alien.tcadb tokyo.assoc-functor ;
+IN: tokyo.abstractdb
+
+<< "tcadb" "abstractdb" define-tokyo-assoc-api >>
+
+: <tokyo-abstractdb> ( name -- tokyo-abstractdb )
+ tcadbnew [ swap tcadbopen drop ] keep
+ tokyo-abstractdb new [ (>>handle) ] keep ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Higher level API for Tokyo Cabinet's Abstract database API. Implements the associative protocol.
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Cabinet's Abstract database API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel tokyo.alien.tchdb tokyo.alien.tcutil
+tokyo.alien.tcbdb tokyo.alien.tcfdb tokyo.alien.tctdb ;
+IN: tokyo.alien.tcadb
+
+LIBRARY: tokyocabinet
+
+TYPEDEF: void* TCADB
+
+C-ENUM:
+ ADBOVOID
+ ADBOMDB
+ ADBONDB
+ ADBOHDB
+ ADBOBDB
+ ADBOFDB
+ ADBOTDB
+ ADBOSKEL ;
+
+FUNCTION: TCADB* tcadbnew ( ) ;
+FUNCTION: void tcadbdel ( TCADB* adb ) ;
+FUNCTION: bool tcadbopen ( TCADB* adb, char* name ) ;
+FUNCTION: bool tcadbclose ( TCADB* adb ) ;
+FUNCTION: bool tcadbput ( TCADB* adb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcadbput2 ( TCADB* adb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcadbputkeep ( TCADB* adb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcadbputkeep2 ( TCADB* adb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcadbputcat ( TCADB* adb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcadbputcat2 ( TCADB* adb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcadbout ( TCADB* adb, void* kbuf, int ksiz ) ;
+FUNCTION: bool tcadbout2 ( TCADB* adb, char* kstr ) ;
+FUNCTION: void* tcadbget ( TCADB* adb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: char* tcadbget2 ( TCADB* adb, char* kstr ) ;
+FUNCTION: int tcadbvsiz ( TCADB* adb, void* kbuf, int ksiz ) ;
+FUNCTION: int tcadbvsiz2 ( TCADB* adb, char* kstr ) ;
+FUNCTION: bool tcadbiterinit ( TCADB* adb ) ;
+FUNCTION: void* tcadbiternext ( TCADB* adb, int* sp ) ;
+FUNCTION: char* tcadbiternext2 ( TCADB* adb ) ;
+FUNCTION: TCLIST* tcadbfwmkeys ( TCADB* adb, void* pbuf, int psiz, int max ) ;
+FUNCTION: TCLIST* tcadbfwmkeys2 ( TCADB* adb, char* pstr, int max ) ;
+FUNCTION: int tcadbaddint ( TCADB* adb, void* kbuf, int ksiz, int num ) ;
+FUNCTION: double tcadbadddouble ( TCADB* adb, void* kbuf, int ksiz, double num ) ;
+FUNCTION: bool tcadbsync ( TCADB* adb ) ;
+FUNCTION: bool tcadboptimize ( TCADB* adb, char* params ) ;
+FUNCTION: bool tcadbvanish ( TCADB* adb ) ;
+FUNCTION: bool tcadbcopy ( TCADB* adb, char* path ) ;
+FUNCTION: bool tcadbtranbegin ( TCADB* adb ) ;
+FUNCTION: bool tcadbtrancommit ( TCADB* adb ) ;
+FUNCTION: bool tcadbtranabort ( TCADB* adb ) ;
+FUNCTION: char* tcadbpath ( TCADB* adb ) ;
+FUNCTION: ulonglong tcadbrnum ( TCADB* adb ) ;
+FUNCTION: ulonglong tcadbsize ( TCADB* adb ) ;
+FUNCTION: TCLIST* tcadbmisc ( TCADB* adb, char* name, TCLIST* args ) ;
+
+! -----
+
+TYPEDEF: void* ADBSKEL
+
+TYPEDEF: void* ADBMAPPROC
+
+FUNCTION: bool tcadbsetskel ( TCADB* adb, ADBSKEL* skel ) ;
+FUNCTION: int tcadbomode ( TCADB* adb ) ;
+FUNCTION: void* tcadbreveal ( TCADB* adb ) ;
+FUNCTION: bool tcadbputproc ( TCADB* adb, void* kbuf, int ksiz, void* vbuf, int vsiz, TCPDPROC proc, void* op ) ;
+FUNCTION: bool tcadbforeach ( TCADB* adb, TCITER iter, void* op ) ;
+FUNCTION: bool tcadbmapbdb ( TCADB* adb, TCLIST* keys, TCBDB* bdb, ADBMAPPROC proc, void* op, longlong csiz ) ;
+FUNCTION: bool tcadbmapbdbemit ( void* map, char* kbuf, int ksiz, char* vbuf, int vsiz ) ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Cabinet's B+ Tree database API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel tokyo.alien.tchdb tokyo.alien.tcutil ;
+IN: tokyo.alien.tcbdb
+
+LIBRARY: tokyocabinet
+
+TYPEDEF: void* TCBDB
+
+CONSTANT: BDBFOPEN HDBFOPEN
+CONSTANT: BDBFFATAL HDBFFATAL
+
+CONSTANT: BDBTLARGE 1
+CONSTANT: BDBTDEFLATE 2
+CONSTANT: BDBTBZIP 4
+CONSTANT: BDBTTCBS 8
+CONSTANT: BDBTEXCODEC 16
+
+CONSTANT: BDBOREADER 1
+CONSTANT: BDBOWRITER 2
+CONSTANT: BDBOCREAT 4
+CONSTANT: BDBOTRUNC 8
+CONSTANT: BDBONOLCK 16
+CONSTANT: BDBOLCKNB 32
+CONSTANT: BDBOTSYNC 64
+
+TYPEDEF: void* BDBCUR
+
+C-ENUM:
+ BDBCPCURRENT
+ BDBCPBEFORE
+ BDBCPAFTER ;
+
+FUNCTION: char* tcbdberrmsg ( int ecode ) ;
+FUNCTION: TCBDB* tcbdbnew ( ) ;
+FUNCTION: void tcbdbdel ( TCBDB* bdb ) ;
+FUNCTION: int tcbdbecode ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbsetmutex ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbsetcmpfunc ( TCBDB* bdb, TCCMP cmp, void* cmpop ) ;
+FUNCTION: bool tcbdbtune ( TCBDB* bdb, int lmemb, int nmemb, longlong bnum, char apow, char fpow, uchar opts ) ;
+FUNCTION: bool tcbdbsetcache ( TCBDB* bdb, int lcnum, int ncnum ) ;
+FUNCTION: bool tcbdbsetxmsiz ( TCBDB* bdb, longlong xmsiz ) ;
+FUNCTION: bool tcbdbopen ( TCBDB* bdb, char* path, int omode ) ;
+FUNCTION: bool tcbdbclose ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbput ( TCBDB* bdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcbdbput2 ( TCBDB* bdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcbdbputkeep ( TCBDB* bdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcbdbputkeep2 ( TCBDB* bdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcbdbputcat ( TCBDB* bdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcbdbputcat2 ( TCBDB* bdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcbdbputdup ( TCBDB* bdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcbdbputdup2 ( TCBDB* bdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcbdbputdup3 ( TCBDB* bdb, void* kbuf, int ksiz, TCLIST* vals ) ;
+FUNCTION: bool tcbdbout ( TCBDB* bdb, void* kbuf, int ksiz ) ;
+FUNCTION: bool tcbdbout2 ( TCBDB* bdb, char* kstr ) ;
+FUNCTION: bool tcbdbout3 ( TCBDB* bdb, void* kbuf, int ksiz ) ;
+FUNCTION: void* tcbdbget ( TCBDB* bdb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: char* tcbdbget2 ( TCBDB* bdb, char* kstr ) ;
+FUNCTION: void* tcbdbget3 ( TCBDB* bdb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: TCLIST* tcbdbget4 ( TCBDB* bdb, void* kbuf, int ksiz ) ;
+FUNCTION: int tcbdbvnum ( TCBDB* bdb, void* kbuf, int ksiz ) ;
+FUNCTION: int tcbdbvnum2 ( TCBDB* bdb, char* kstr ) ;
+FUNCTION: int tcbdbvsiz ( TCBDB* bdb, void* kbuf, int ksiz ) ;
+FUNCTION: int tcbdbvsiz2 ( TCBDB* bdb, char* kstr ) ;
+FUNCTION: TCLIST* tcbdbrange ( TCBDB* bdb, void* bkbuf, int bksiz, bool binc, void* ekbuf, int eksiz, bool einc, int max ) ;
+FUNCTION: TCLIST* tcbdbrange2 ( TCBDB* bdb, char* bkstr, bool binc, char* ekstr, bool einc, int max ) ;
+FUNCTION: TCLIST* tcbdbfwmkeys ( TCBDB* bdb, void* pbuf, int psiz, int max ) ;
+FUNCTION: TCLIST* tcbdbfwmkeys2 ( TCBDB* bdb, char* pstr, int max ) ;
+FUNCTION: int tcbdbaddint ( TCBDB* bdb, void* kbuf, int ksiz, int num ) ;
+FUNCTION: double tcbdbadddouble ( TCBDB* bdb, void* kbuf, int ksiz, double num ) ;
+FUNCTION: bool tcbdbsync ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdboptimize ( TCBDB* bdb, int lmemb, int nmemb, longlong bnum, char apow, char fpow, uchar opts ) ;
+FUNCTION: bool tcbdbvanish ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbcopy ( TCBDB* bdb, char* path ) ;
+FUNCTION: bool tcbdbtranbegin ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbtrancommit ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbtranabort ( TCBDB* bdb ) ;
+FUNCTION: char* tcbdbpath ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdbrnum ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdbfsiz ( TCBDB* bdb ) ;
+FUNCTION: BDBCUR* tcbdbcurnew ( TCBDB* bdb ) ;
+FUNCTION: void tcbdbcurdel ( BDBCUR* cur ) ;
+FUNCTION: bool tcbdbcurfirst ( BDBCUR* cur ) ;
+FUNCTION: bool tcbdbcurlast ( BDBCUR* cur ) ;
+FUNCTION: bool tcbdbcurjump ( BDBCUR* cur, void* kbuf, int ksiz ) ;
+FUNCTION: bool tcbdbcurjump2 ( BDBCUR* cur, char* kstr ) ;
+FUNCTION: bool tcbdbcurprev ( BDBCUR* cur ) ;
+FUNCTION: bool tcbdbcurnext ( BDBCUR* cur ) ;
+FUNCTION: bool tcbdbcurput ( BDBCUR* cur, void* vbuf, int vsiz, int cpmode ) ;
+FUNCTION: bool tcbdbcurput2 ( BDBCUR* cur, char* vstr, int cpmode ) ;
+FUNCTION: bool tcbdbcurout ( BDBCUR* cur ) ;
+FUNCTION: void* tcbdbcurkey ( BDBCUR* cur, int* sp ) ;
+FUNCTION: char* tcbdbcurkey2 ( BDBCUR* cur ) ;
+FUNCTION: void* tcbdbcurkey3 ( BDBCUR* cur, int* sp ) ;
+FUNCTION: void* tcbdbcurval ( BDBCUR* cur, int* sp ) ;
+FUNCTION: char* tcbdbcurval2 ( BDBCUR* cur ) ;
+FUNCTION: void* tcbdbcurval3 ( BDBCUR* cur, int* sp ) ;
+FUNCTION: bool tcbdbcurrec ( BDBCUR* cur, TCXSTR* kxstr, TCXSTR* vxstr ) ;
+
+! -----------
+
+FUNCTION: void tcbdbsetecode ( TCBDB* bdb, int ecode, char* filename, int line, char* func ) ;
+FUNCTION: void tcbdbsetdbgfd ( TCBDB* bdb, int fd ) ;
+FUNCTION: int tcbdbdbgfd ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbhasmutex ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbmemsync ( TCBDB* bdb, bool phys ) ;
+FUNCTION: bool tcbdbcacheclear ( TCBDB* bdb ) ;
+FUNCTION: TCCMP tcbdbcmpfunc ( TCBDB* bdb ) ;
+FUNCTION: void* tcbdbcmpop ( TCBDB* bdb ) ;
+FUNCTION: uint tcbdblmemb ( TCBDB* bdb ) ;
+FUNCTION: uint tcbdbnmemb ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdblnum ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdbnnum ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdbbnum ( TCBDB* bdb ) ;
+FUNCTION: uint tcbdbalign ( TCBDB* bdb ) ;
+FUNCTION: uint tcbdbfbpmax ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdbinode ( TCBDB* bdb ) ;
+FUNCTION: tokyo_time_t tcbdbmtime ( TCBDB* bdb ) ;
+FUNCTION: uchar tcbdbflags ( TCBDB* bdb ) ;
+FUNCTION: uchar tcbdbopts ( TCBDB* bdb ) ;
+FUNCTION: char* tcbdbopaque ( TCBDB* bdb ) ;
+FUNCTION: ulonglong tcbdbbnumused ( TCBDB* bdb ) ;
+FUNCTION: bool tcbdbsetlsmax ( TCBDB* bdb, uint lsmax ) ;
+FUNCTION: bool tcbdbsetcapnum ( TCBDB* bdb, ulonglong capnum ) ;
+FUNCTION: bool tcbdbsetcodecfunc ( TCBDB* bdb, TCCODEC enc, void* encop, TCCODEC dec, void* decop ) ;
+FUNCTION: bool tcbdbputdupback ( TCBDB* bdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcbdbputdupback2 ( TCBDB* bdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcbdbputproc ( TCBDB* bdb, void* kbuf, int ksiz, void* vbuf, int vsiz, TCPDPROC proc, void* op ) ;
+FUNCTION: bool tcbdbcurjumpback ( BDBCUR* cur, void* kbuf, int ksiz ) ;
+FUNCTION: bool tcbdbcurjumpback2 ( BDBCUR* cur, char* kstr ) ;
+FUNCTION: bool tcbdbforeach ( TCBDB* bdb, TCITER iter, void* op ) ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Cabinet's Fixed Length database API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel tokyo.alien.tcutil ;
+IN: tokyo.alien.tcfdb
+
+TYPEDEF: void* TCFDB
+
+CONSTANT: FDBFOPEN 1
+CONSTANT: FDBFFATAL 2
+
+CONSTANT: FDBOREADER 1
+CONSTANT: FDBOWRITER 2
+CONSTANT: FDBOCREAT 4
+CONSTANT: FDBOTRUNC 8
+CONSTANT: FDBONOLCK 16
+CONSTANT: FDBOLCKNB 32
+CONSTANT: FDBOTSYNC 64
+
+CONSTANT: FDBIDMIN -1
+CONSTANT: FDBIDPREV -2
+CONSTANT: FDBIDMAX -3
+CONSTANT: FDBIDNEXT -4
+
+FUNCTION: char* tcfdberrmsg ( int ecode ) ;
+FUNCTION: TCFDB* tcfdbnew ( ) ;
+FUNCTION: void tcfdbdel ( TCFDB* fdb ) ;
+FUNCTION: int tcfdbecode ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbsetmutex ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbtune ( TCFDB* fdb, int width, longlong limsiz ) ;
+FUNCTION: bool tcfdbopen ( TCFDB* fdb, char* path, int omode ) ;
+FUNCTION: bool tcfdbclose ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbput ( TCFDB* fdb, longlong id, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcfdbput2 ( TCFDB* fdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcfdbput3 ( TCFDB* fdb, char* kstr, void* vstr ) ;
+FUNCTION: bool tcfdbputkeep ( TCFDB* fdb, longlong id, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcfdbputkeep2 ( TCFDB* fdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcfdbputkeep3 ( TCFDB* fdb, char* kstr, void* vstr ) ;
+FUNCTION: bool tcfdbputcat ( TCFDB* fdb, longlong id, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcfdbputcat2 ( TCFDB* fdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcfdbputcat3 ( TCFDB* fdb, char* kstr, void* vstr ) ;
+FUNCTION: bool tcfdbout ( TCFDB* fdb, longlong id ) ;
+FUNCTION: bool tcfdbout2 ( TCFDB* fdb, void* kbuf, int ksiz ) ;
+FUNCTION: bool tcfdbout3 ( TCFDB* fdb, char* kstr ) ;
+FUNCTION: void* tcfdbget ( TCFDB* fdb, longlong id, int* sp ) ;
+FUNCTION: void* tcfdbget2 ( TCFDB* fdb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: char* tcfdbget3 ( TCFDB* fdb, char* kstr ) ;
+FUNCTION: int tcfdbget4 ( TCFDB* fdb, longlong id, void* vbuf, int max ) ;
+FUNCTION: int tcfdbvsiz ( TCFDB* fdb, longlong id ) ;
+FUNCTION: int tcfdbvsiz2 ( TCFDB* fdb, void* kbuf, int ksiz ) ;
+FUNCTION: int tcfdbvsiz3 ( TCFDB* fdb, char* kstr ) ;
+FUNCTION: bool tcfdbiterinit ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdbiternext ( TCFDB* fdb ) ;
+FUNCTION: void* tcfdbiternext2 ( TCFDB* fdb, int* sp ) ;
+FUNCTION: char* tcfdbiternext3 ( TCFDB* fdb ) ;
+FUNCTION: ulonglong* tcfdbrange ( TCFDB* fdb, longlong lower, longlong upper, int max, int* np ) ;
+FUNCTION: TCLIST* tcfdbrange2 ( TCFDB* fdb, void* lbuf, int lsiz, void* ubuf, int usiz, int max ) ;
+FUNCTION: TCLIST* tcfdbrange3 ( TCFDB* fdb, char* lstr, char* ustr, int max ) ;
+FUNCTION: TCLIST* tcfdbrange4 ( TCFDB* fdb, void* ibuf, int isiz, int max ) ;
+FUNCTION: TCLIST* tcfdbrange5 ( TCFDB* fdb, void* istr, int max ) ;
+FUNCTION: int tcfdbaddint ( TCFDB* fdb, longlong id, int num ) ;
+FUNCTION: double tcfdbadddouble ( TCFDB* fdb, longlong id, double num ) ;
+FUNCTION: bool tcfdbsync ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdboptimize ( TCFDB* fdb, int width, longlong limsiz ) ;
+FUNCTION: bool tcfdbvanish ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbcopy ( TCFDB* fdb, char* path ) ;
+FUNCTION: bool tcfdbtranbegin ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbtrancommit ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbtranabort ( TCFDB* fdb ) ;
+FUNCTION: char* tcfdbpath ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdbrnum ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdbfsiz ( TCFDB* fdb ) ;
+
+! --------
+
+FUNCTION: void tcfdbsetecode ( TCFDB* fdb, int ecode, char* filename, int line, char* func ) ;
+FUNCTION: void tcfdbsetdbgfd ( TCFDB* fdb, int fd ) ;
+FUNCTION: int tcfdbdbgfd ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbhasmutex ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbmemsync ( TCFDB* fdb, bool phys ) ;
+FUNCTION: ulonglong tcfdbmin ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdbmax ( TCFDB* fdb ) ;
+FUNCTION: uint tcfdbwidth ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdblimsiz ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdblimid ( TCFDB* fdb ) ;
+FUNCTION: ulonglong tcfdbinode ( TCFDB* fdb ) ;
+FUNCTION: tokyo_time_t tcfdbmtime ( TCFDB* fdb ) ;
+FUNCTION: int tcfdbomode ( TCFDB* fdb ) ;
+FUNCTION: uchar tcfdbtype ( TCFDB* fdb ) ;
+FUNCTION: uchar tcfdbflags ( TCFDB* fdb ) ;
+FUNCTION: char* tcfdbopaque ( TCFDB* fdb ) ;
+FUNCTION: bool tcfdbputproc ( TCFDB* fdb, longlong id, void* vbuf, int vsiz, TCPDPROC proc, void* op ) ;
+FUNCTION: bool tcfdbforeach ( TCFDB* fdb, TCITER iter, void* op ) ;
+FUNCTION: longlong tcfdbkeytoid ( char* kbuf, int ksiz ) ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Cabinet's Hash database API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel tokyo.alien.tcutil ;
+IN: tokyo.alien.tchdb
+
+LIBRARY: tokyocabinet
+
+TYPEDEF: void* TCHDB*
+
+CONSTANT: HDBFOPEN 1
+CONSTANT: HDBFFATAL 2
+
+CONSTANT: HDBTLARGE 1
+CONSTANT: HDBTDEFLATE 2
+CONSTANT: HDBTBZIP 4
+CONSTANT: HDBTTCBS 8
+CONSTANT: HDBTEXCODEC 16
+
+CONSTANT: HDBOREADER 1
+CONSTANT: HDBOWRITER 2
+CONSTANT: HDBOCREAT 4
+CONSTANT: HDBOTRUNC 8
+CONSTANT: HDBONOLCK 16
+CONSTANT: HDBOLCKNB 32
+CONSTANT: HDBOTSYNC 64
+
+FUNCTION: char* tchdberrmsg ( int ecode ) ;
+FUNCTION: TCHDB* tchdbnew ( ) ;
+FUNCTION: void tchdbdel ( TCHDB* hdb ) ;
+FUNCTION: int tchdbecode ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbsetmutex ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbtune ( TCHDB* hdb, longlong bnum, char apow, char fpow, uchar opts ) ;
+FUNCTION: bool tchdbsetcache ( TCHDB* hdb, int rcnum ) ;
+FUNCTION: bool tchdbsetxmsiz ( TCHDB* hdb, longlong xmsiz ) ;
+FUNCTION: bool tchdbopen ( TCHDB* hdb, char* path, int omode ) ;
+FUNCTION: bool tchdbclose ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbput ( TCHDB* hdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tchdbput2 ( TCHDB* hdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tchdbputkeep ( TCHDB* hdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tchdbputkeep2 ( TCHDB* hdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tchdbputcat ( TCHDB* hdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tchdbputcat2 ( TCHDB* hdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tchdbputasync ( TCHDB* hdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tchdbputasync2 ( TCHDB* hdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tchdbout ( TCHDB* hdb, void* kbuf, int ksiz ) ;
+FUNCTION: bool tchdbout2 ( TCHDB* hdb, char* kstr ) ;
+FUNCTION: void* tchdbget ( TCHDB* hdb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: char* tchdbget2 ( TCHDB* hdb, char* kstr ) ;
+FUNCTION: int tchdbget3 ( TCHDB* hdb, void* kbuf, int ksiz, void* vbuf, int max ) ;
+FUNCTION: int tchdbvsiz ( TCHDB* hdb, void* kbuf, int ksiz ) ;
+FUNCTION: int tchdbvsiz2 ( TCHDB* hdb, char* kstr ) ;
+FUNCTION: bool tchdbiterinit ( TCHDB* hdb ) ;
+FUNCTION: void* tchdbiternext ( TCHDB* hdb, int* sp ) ;
+FUNCTION: char* tchdbiternext2 ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbiternext3 ( TCHDB* hdb, TCXSTR* kxstr, TCXSTR* vxstr ) ;
+FUNCTION: TCLIST* tchdbfwmkeys ( TCHDB* hdb, void* pbuf, int psiz, int max ) ;
+FUNCTION: TCLIST* tchdbfwmkeys2 ( TCHDB* hdb, char* pstr, int max ) ;
+FUNCTION: int tchdbaddint ( TCHDB* hdb, void* kbuf, int ksiz, int num ) ;
+FUNCTION: double tchdbadddouble ( TCHDB* hdb, void* kbuf, int ksiz, double num ) ;
+FUNCTION: bool tchdbsync ( TCHDB* hdb ) ;
+FUNCTION: bool tchdboptimize ( TCHDB* hdb, longlong bnum, char apow, char fpow, uchar opts ) ;
+FUNCTION: bool tchdbvanish ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbcopy ( TCHDB* hdb, char* path ) ;
+FUNCTION: bool tchdbtranbegin ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbtrancommit ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbtranabort ( TCHDB* hdb ) ;
+FUNCTION: char* tchdbpath ( TCHDB* hdb ) ;
+FUNCTION: ulonglong tchdbrnum ( TCHDB* hdb ) ;
+FUNCTION: ulonglong tchdbfsiz ( TCHDB* hdb ) ;
+
+! --------
+
+FUNCTION: void tchdbsetecode ( TCHDB* hdb, int ecode, char* filename, int line, char* func ) ;
+FUNCTION: void tchdbsettype ( TCHDB* hdb, uchar type ) ;
+FUNCTION: void tchdbsetdbgfd ( TCHDB* hdb, int fd ) ;
+FUNCTION: int tchdbdbgfd ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbhasmutex ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbmemsync ( TCHDB* hdb, bool phys ) ;
+FUNCTION: bool tchdbcacheclear ( TCHDB* hdb ) ;
+FUNCTION: ulonglong tchdbbnum ( TCHDB* hdb ) ;
+FUNCTION: uint tchdbalign ( TCHDB* hdb ) ;
+FUNCTION: uint tchdbfbpmax ( TCHDB* hdb ) ;
+FUNCTION: ulonglong tchdbxmsiz ( TCHDB* hdb ) ;
+FUNCTION: ulonglong tchdbinode ( TCHDB* hdb ) ;
+FUNCTION: tokyo_time_t tchdbmtime ( TCHDB* hdb ) ;
+FUNCTION: int tchdbomode ( TCHDB* hdb ) ;
+FUNCTION: uchar tchdbtype ( TCHDB* hdb ) ;
+FUNCTION: uchar tchdbflags ( TCHDB* hdb ) ;
+FUNCTION: uchar tchdbopts ( TCHDB* hdb ) ;
+FUNCTION: char* tchdbopaque ( TCHDB* hdb ) ;
+FUNCTION: ulonglong tchdbbnumused ( TCHDB* hdb ) ;
+FUNCTION: bool tchdbsetcodecfunc ( TCHDB* hdb, TCCODEC enc, void* encop, TCCODEC dec, void* decop ) ;
+FUNCTION: void tchdbcodecfunc ( TCHDB* hdb, TCCODEC* ep, void* *eop, TCCODEC* dp, void* *dop ) ;
+FUNCTION: bool tchdbputproc ( TCHDB* hdb, void* kbuf, int ksiz, void* vbuf, int vsiz, TCPDPROC proc, void* op ) ;
+FUNCTION: void* tchdbgetnext ( TCHDB* hdb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: char* tchdbgetnext2 ( TCHDB* hdb, char* kstr ) ;
+FUNCTION: char* tchdbgetnext3 ( TCHDB* hdb, char* kbuf, int ksiz, int* sp, char* *vbp, int* vsp ) ;
+FUNCTION: bool tchdbforeach ( TCHDB* hdb, TCITER iter, void* op ) ;
+FUNCTION: bool tchdbtranvoid ( TCHDB* hdb ) ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Tyrant's Remote database API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel system tokyo.alien.tchdb tokyo.alien.tcutil
+tokyo.alien.tctdb ;
+IN: tokyo.alien.tcrdb
+
+<< "tokyotyrant" {
+ { [ os macosx? ] [ "/opt/local/lib/libtokyotyrant.dylib" ] }
+ { [ os unix? ] [ "libtokyotyrant.so" ] }
+ { [ os windows? ] [ "tokyotyrant.dll" ] }
+} cond "cdecl" add-library >>
+
+LIBRARY: tokyotyrant
+
+TYPEDEF: void* TCRDB*
+! C-STRUCT: TCRDB
+! { "pthread_mutex_t" mmtx }
+! { "pthread_key_t" eckey }
+! { "char*" host }
+! { "int" port }
+! { "char*" expr }
+! { "int" fd }
+! { "TTSOCK*" sock }
+! { "double" timeout }
+! { "int" opts } ;
+
+C-ENUM:
+ TTESUCCESS
+ TTEINVALID
+ TTENOHOST
+ TTEREFUSED
+ TTESEND
+ TTERECV
+ TTEKEEP
+ TTENOREC ;
+CONSTANT: TTEMISC 9999
+
+CONSTANT: RDBTRECON 1
+CONSTANT: RDBXOLCKREC 1
+CONSTANT: RDBXOLCKGLB 2
+CONSTANT: RDBROCHKCON 1
+CONSTANT: RDBMONOULOG 1
+
+FUNCTION: char* tcrdberrmsg ( int ecode ) ;
+FUNCTION: TCRDB* tcrdbnew ( ) ;
+FUNCTION: void tcrdbdel ( TCRDB* rdb ) ;
+FUNCTION: int tcrdbecode ( TCRDB* rdb ) ;
+FUNCTION: bool tcrdbtune ( TCRDB* rdb, double timeout, int opts ) ;
+FUNCTION: bool tcrdbopen ( TCRDB* rdb, char* host, int port ) ;
+FUNCTION: bool tcrdbopen2 ( TCRDB* rdb, char* expr ) ;
+FUNCTION: bool tcrdbclose ( TCRDB* rdb ) ;
+FUNCTION: bool tcrdbput ( TCRDB* rdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcrdbput2 ( TCRDB* rdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcrdbputkeep ( TCRDB* rdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcrdbputkeep2 ( TCRDB* rdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcrdbputcat ( TCRDB* rdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcrdbputcat2 ( TCRDB* rdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcrdbputshl ( TCRDB* rdb, void* kbuf, int ksiz, void* vbuf, int vsiz, int width ) ;
+FUNCTION: bool tcrdbputshl2 ( TCRDB* rdb, char* kstr, char* vstr, int width ) ;
+FUNCTION: bool tcrdbputnr ( TCRDB* rdb, void* kbuf, int ksiz, void* vbuf, int vsiz ) ;
+FUNCTION: bool tcrdbputnr2 ( TCRDB* rdb, char* kstr, char* vstr ) ;
+FUNCTION: bool tcrdbout ( TCRDB* rdb, void* kbuf, int ksiz ) ;
+FUNCTION: bool tcrdbout2 ( TCRDB* rdb, char* kstr ) ;
+FUNCTION: void* tcrdbget ( TCRDB* rdb, void* kbuf, int ksiz, int* sp ) ;
+FUNCTION: char* tcrdbget2 ( TCRDB* rdb, char* kstr ) ;
+FUNCTION: bool tcrdbget3 ( TCRDB* rdb, TCMAP* recs ) ;
+FUNCTION: int tcrdbvsiz ( TCRDB* rdb, void* kbuf, int ksiz ) ;
+FUNCTION: int tcrdbvsiz2 ( TCRDB* rdb, char* kstr ) ;
+FUNCTION: bool tcrdbiterinit ( TCRDB* rdb ) ;
+FUNCTION: void* tcrdbiternext ( TCRDB* rdb, int* sp ) ;
+FUNCTION: char* tcrdbiternext2 ( TCRDB* rdb ) ;
+FUNCTION: TCLIST* tcrdbfwmkeys ( TCRDB* rdb, void* pbuf, int psiz, int max ) ;
+FUNCTION: TCLIST* tcrdbfwmkeys2 ( TCRDB* rdb, char* pstr, int max ) ;
+FUNCTION: int tcrdbaddint ( TCRDB* rdb, void* kbuf, int ksiz, int num ) ;
+FUNCTION: double tcrdbadddouble ( TCRDB* rdb, void* kbuf, int ksiz, double num ) ;
+FUNCTION: void* tcrdbext ( TCRDB* rdb, char* name, int opts, void* kbuf, int ksiz, void* vbuf, int vsiz, int* sp ) ;
+FUNCTION: char* tcrdbext2 ( TCRDB* rdb, char* name, int opts, char* kstr, char* vstr ) ;
+FUNCTION: bool tcrdbsync ( TCRDB* rdb ) ;
+FUNCTION: bool tcrdboptimize ( TCRDB* rdb, char* params ) ;
+FUNCTION: bool tcrdbvanish ( TCRDB* rdb ) ;
+FUNCTION: bool tcrdbcopy ( TCRDB* rdb, char* path ) ;
+FUNCTION: bool tcrdbrestore ( TCRDB* rdb, char* path, ulonglong ts, int opts ) ;
+FUNCTION: bool tcrdbsetmst ( TCRDB* rdb, char* host, int port, int opts ) ;
+FUNCTION: bool tcrdbsetmst2 ( TCRDB* rdb, char* expr, int opts ) ;
+FUNCTION: char* tcrdbexpr ( TCRDB* rdb ) ;
+FUNCTION: ulonglong tcrdbrnum ( TCRDB* rdb ) ;
+FUNCTION: ulonglong tcrdbsize ( TCRDB* rdb ) ;
+FUNCTION: char* tcrdbstat ( TCRDB* rdb ) ;
+FUNCTION: TCLIST* tcrdbmisc ( TCRDB* rdb, char* name, int opts, TCLIST* args ) ;
+
+CONSTANT: RDBITLEXICAL TDBITLEXICAL
+CONSTANT: RDBITDECIMAL TDBITDECIMAL
+CONSTANT: RDBITOPT TDBITOPT
+CONSTANT: RDBITVOID TDBITVOID
+CONSTANT: RDBITKEEP TDBITKEEP
+
+TYPEDEF: void* RDBQRY*
+! C-STRUCT: RDBQRY
+! { "TCRDB*" rdb }
+! { "TCLIST*" args } ;
+
+CONSTANT: RDBQCSTREQ TDBQCSTREQ
+CONSTANT: RDBQCSTRINC TDBQCSTRINC
+CONSTANT: RDBQCSTRBW TDBQCSTRBW
+CONSTANT: RDBQCSTREW TDBQCSTREW
+CONSTANT: RDBQCSTRAND TDBQCSTRAND
+CONSTANT: RDBQCSTROR TDBQCSTROR
+CONSTANT: RDBQCSTROREQ TDBQCSTROREQ
+CONSTANT: RDBQCSTRRX TDBQCSTRRX
+CONSTANT: RDBQCNUMEQ TDBQCNUMEQ
+CONSTANT: RDBQCNUMGT TDBQCNUMGT
+CONSTANT: RDBQCNUMGE TDBQCNUMGE
+CONSTANT: RDBQCNUMLT TDBQCNUMLT
+CONSTANT: RDBQCNUMLE TDBQCNUMLE
+CONSTANT: RDBQCNUMBT TDBQCNUMBT
+CONSTANT: RDBQCNUMOREQ TDBQCNUMOREQ
+CONSTANT: RDBQCNEGATE TDBQCNEGATE
+CONSTANT: RDBQCNOIDX TDBQCNOIDX
+
+CONSTANT: RDBQOSTRASC TDBQOSTRASC
+CONSTANT: RDBQOSTRDESC TDBQOSTRDESC
+CONSTANT: RDBQONUMASC TDBQONUMASC
+CONSTANT: RDBQONUMDESC TDBQONUMDESC
+
+FUNCTION: bool tcrdbtblput ( TCRDB* rdb, void* pkbuf, int pksiz, TCMAP* cols ) ;
+FUNCTION: bool tcrdbtblputkeep ( TCRDB* rdb, void* pkbuf, int pksiz, TCMAP* cols ) ;
+FUNCTION: bool tcrdbtblputcat ( TCRDB* rdb, void* pkbuf, int pksiz, TCMAP* cols ) ;
+FUNCTION: bool tcrdbtblout ( TCRDB* rdb, void* pkbuf, int pksiz ) ;
+FUNCTION: TCMAP* tcrdbtblget ( TCRDB* rdb, void* pkbuf, int pksiz ) ;
+FUNCTION: bool tcrdbtblsetindex ( TCRDB* rdb, char* name, int type ) ;
+FUNCTION: longlong tcrdbtblgenuid ( TCRDB* rdb ) ;
+FUNCTION: RDBQRY* tcrdbqrynew ( TCRDB* rdb ) ;
+FUNCTION: void tcrdbqrydel ( RDBQRY* qry ) ;
+FUNCTION: void tcrdbqryaddcond ( RDBQRY* qry, char* name, int op, char* expr ) ;
+FUNCTION: void tcrdbqrysetorder ( RDBQRY* qry, char* name, int type ) ;
+FUNCTION: void tcrdbqrysetlimit ( RDBQRY* qry, int max, int skip ) ;
+FUNCTION: TCLIST* tcrdbqrysearch ( RDBQRY* qry ) ;
+FUNCTION: bool tcrdbqrysearchout ( RDBQRY* qry ) ;
+FUNCTION: TCLIST* tcrdbqrysearchget ( RDBQRY* qry ) ;
+FUNCTION: TCMAP* tcrdbqryrescols ( TCLIST* res, int index ) ;
+FUNCTION: int tcrdbqrysearchcount ( RDBQRY* qry ) ;
+
+FUNCTION: void tcrdbsetecode ( TCRDB* rdb, int ecode ) ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Cabinet's Table database API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel tokyo.alien.tchdb tokyo.alien.tcutil ;
+IN: tokyo.alien.tctdb
+
+LIBRARY: tokyocabinet
+
+TYPEDEF: void* TDBIDX*
+TYPEDEF: void* TCTDB*
+
+CONSTANT: TDBFOPEN HDBFOPEN
+CONSTANT: TDBFFATAL HDBFFATAL
+
+CONSTANT: TDBTLARGE 1
+CONSTANT: TDBTDEFLATE 2
+CONSTANT: TDBTBZIP 4
+CONSTANT: TDBTTCBS 8
+CONSTANT: TDBTEXCODEC 16
+
+CONSTANT: TDBOREADER 1
+CONSTANT: TDBOWRITER 2
+CONSTANT: TDBOCREAT 4
+CONSTANT: TDBOTRUNC 8
+CONSTANT: TDBONOLCK 16
+CONSTANT: TDBOLCKNB 32
+CONSTANT: TDBOTSYNC 64
+
+C-ENUM:
+ TDBITLEXICAL
+ TDBITDECIMAL ;
+
+CONSTANT: TDBITOPT 9998
+CONSTANT: TDBITVOID 9999
+CONSTANT: TDBITKEEP 16777216
+
+TYPEDEF: void* TDBCOND*
+TYPEDEF: void* TDBQRY*
+
+C-ENUM:
+ TDBQCSTREQ
+ TDBQCSTRINC
+ TDBQCSTRBW
+ TDBQCSTREW
+ TDBQCSTRAND
+ TDBQCSTROR
+ TDBQCSTROREQ
+ TDBQCSTRRX
+ TDBQCNUMEQ
+ TDBQCNUMGT
+ TDBQCNUMGE
+ TDBQCNUMLT
+ TDBQCNUMLE
+ TDBQCNUMBT
+ TDBQCNUMOREQ ;
+
+CONSTANT: TDBQCNEGATE 16777216
+CONSTANT: TDBQCNOIDX 33554432
+
+C-ENUM:
+ TDBQOSTRASC
+ TDBQOSTRDESC
+ TDBQONUMASC
+ TDBQONUMDESC ;
+
+CONSTANT: TDBQPPUT 1
+CONSTANT: TDBQPOUT 2
+CONSTANT: TDBQPSTOP 16777216
+
+! int (*)(const void *pkbuf, int pksiz, TCMAP *cols, void *op);
+TYPEDEF: void* TDBQRYPROC
+
+FUNCTION: char* tctdberrmsg ( int ecode ) ;
+FUNCTION: TCTDB* tctdbnew ( ) ;
+FUNCTION: void tctdbdel ( TCTDB* tdb ) ;
+FUNCTION: int tctdbecode ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbsetmutex ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbtune ( TCTDB* tdb, longlong bnum, char apow, char fpow, uchar opts ) ;
+FUNCTION: bool tctdbsetcache ( TCTDB* tdb, int rcnum, int lcnum, int ncnum ) ;
+FUNCTION: bool tctdbsetxmsiz ( TCTDB* tdb, longlong xmsiz ) ;
+FUNCTION: bool tctdbopen ( TCTDB* tdb, char* path, int omode ) ;
+FUNCTION: bool tctdbclose ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbput ( TCTDB* tdb, void* pkbuf, int pksiz, TCMAP* cols ) ;
+FUNCTION: bool tctdbput2 ( TCTDB* tdb, void* pkbuf, int pksiz, void* cbuf, int csiz ) ;
+FUNCTION: bool tctdbput3 ( TCTDB* tdb, char* pkstr, char* cstr ) ;
+FUNCTION: bool tctdbputkeep ( TCTDB* tdb, void* pkbuf, int pksiz, TCMAP* cols ) ;
+FUNCTION: bool tctdbputkeep2 ( TCTDB* tdb, void* pkbuf, int pksiz, void* cbuf, int csiz ) ;
+FUNCTION: bool tctdbputkeep3 ( TCTDB* tdb, char* pkstr, char* cstr ) ;
+FUNCTION: bool tctdbputcat ( TCTDB* tdb, void* pkbuf, int pksiz, TCMAP* cols ) ;
+FUNCTION: bool tctdbputcat2 ( TCTDB* tdb, void* pkbuf, int pksiz, void* cbuf, int csiz ) ;
+FUNCTION: bool tctdbputcat3 ( TCTDB* tdb, char* pkstr, char* cstr ) ;
+FUNCTION: bool tctdbout ( TCTDB* tdb, void* pkbuf, int pksiz ) ;
+FUNCTION: bool tctdbout2 ( TCTDB* tdb, char* pkstr ) ;
+FUNCTION: TCMAP* tctdbget ( TCTDB* tdb, void* pkbuf, int pksiz ) ;
+FUNCTION: char* tctdbget2 ( TCTDB* tdb, void* pkbuf, int pksiz, int* sp ) ;
+FUNCTION: char* tctdbget3 ( TCTDB* tdb, char* pkstr ) ;
+FUNCTION: int tctdbvsiz ( TCTDB* tdb, void* pkbuf, int pksiz ) ;
+FUNCTION: int tctdbvsiz2 ( TCTDB* tdb, char* pkstr ) ;
+FUNCTION: bool tctdbiterinit ( TCTDB* tdb ) ;
+FUNCTION: void* tctdbiternext ( TCTDB* tdb, int* sp ) ;
+FUNCTION: char* tctdbiternext2 ( TCTDB* tdb ) ;
+FUNCTION: TCLIST* tctdbfwmkeys ( TCTDB* tdb, void* pbuf, int psiz, int max ) ;
+FUNCTION: TCLIST* tctdbfwmkeys2 ( TCTDB* tdb, char* pstr, int max ) ;
+FUNCTION: int tctdbaddint ( TCTDB* tdb, void* pkbuf, int pksiz, int num ) ;
+FUNCTION: double tctdbadddouble ( TCTDB* tdb, void* pkbuf, int pksiz, double num ) ;
+FUNCTION: bool tctdbsync ( TCTDB* tdb ) ;
+FUNCTION: bool tctdboptimize ( TCTDB* tdb, longlong bnum, char apow, char fpow, uchar opts ) ;
+FUNCTION: bool tctdbvanish ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbcopy ( TCTDB* tdb, char* path ) ;
+FUNCTION: bool tctdbtranbegin ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbtrancommit ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbtranabort ( TCTDB* tdb ) ;
+FUNCTION: char* tctdbpath ( TCTDB* tdb ) ;
+FUNCTION: ulonglong tctdbrnum ( TCTDB* tdb ) ;
+FUNCTION: ulonglong tctdbfsiz ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbsetindex ( TCTDB* tdb, char* name, int type ) ;
+FUNCTION: longlong tctdbgenuid ( TCTDB* tdb ) ;
+FUNCTION: TDBQRY* tctdbqrynew ( TCTDB* tdb ) ;
+FUNCTION: void tctdbqrydel ( TDBQRY* qry ) ;
+FUNCTION: void tctdbqryaddcond ( TDBQRY* qry, char* name, int op, char* expr ) ;
+FUNCTION: void tctdbqrysetorder ( TDBQRY* qry, char* name, int type ) ;
+FUNCTION: void tctdbqrysetlimit ( TDBQRY* qry, int max, int skip ) ;
+FUNCTION: TCLIST* tctdbqrysearch ( TDBQRY* qry ) ;
+FUNCTION: bool tctdbqrysearchout ( TDBQRY* qry ) ;
+FUNCTION: bool tctdbqryproc ( TDBQRY* qry, TDBQRYPROC proc, void* op ) ;
+FUNCTION: char* tctdbqryhint ( TDBQRY* qry ) ;
+
+! =======
+
+FUNCTION: void tctdbsetecode ( TCTDB* tdb, int ecode, char* filename, int line, char* func ) ;
+FUNCTION: void tctdbsetdbgfd ( TCTDB* tdb, int fd ) ;
+FUNCTION: int tctdbdbgfd ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbhasmutex ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbmemsync ( TCTDB* tdb, bool phys ) ;
+FUNCTION: ulonglong tctdbbnum ( TCTDB* tdb ) ;
+FUNCTION: uint tctdbalign ( TCTDB* tdb ) ;
+FUNCTION: uint tctdbfbpmax ( TCTDB* tdb ) ;
+FUNCTION: ulonglong tctdbinode ( TCTDB* tdb ) ;
+FUNCTION: tokyo_time_t tctdbmtime ( TCTDB* tdb ) ;
+FUNCTION: uchar tctdbflags ( TCTDB* tdb ) ;
+FUNCTION: uchar tctdbopts ( TCTDB* tdb ) ;
+FUNCTION: char* tctdbopaque ( TCTDB* tdb ) ;
+FUNCTION: ulonglong tctdbbnumused ( TCTDB* tdb ) ;
+FUNCTION: int tctdbinum ( TCTDB* tdb ) ;
+FUNCTION: longlong tctdbuidseed ( TCTDB* tdb ) ;
+FUNCTION: bool tctdbsetuidseed ( TCTDB* tdb, longlong seed ) ;
+FUNCTION: bool tctdbsetcodecfunc ( TCTDB* tdb, TCCODEC enc, void* encop, TCCODEC dec, void* decop ) ;
+FUNCTION: bool tctdbputproc ( TCTDB* tdb, void* pkbuf, int pksiz, void* cbuf, int csiz, TCPDPROC proc, void* op ) ;
+FUNCTION: bool tctdbforeach ( TCTDB* tdb, TCITER iter, void* op ) ;
+FUNCTION: bool tctdbqryproc2 ( TDBQRY* qry, TDBQRYPROC proc, void* op ) ;
+FUNCTION: bool tctdbqrysearchout2 ( TDBQRY* qry ) ;
+FUNCTION: int tctdbstrtoindextype ( char* str ) ;
+FUNCTION: int tctdbqrycount ( TDBQRY* qry ) ;
+FUNCTION: int tctdbqrystrtocondop ( char* str ) ;
+FUNCTION: int tctdbqrystrtoordertype ( char* str ) ;
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Bindings for Tokyo Cabinet's Utils API
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.libraries alien.syntax
+combinators kernel system ;
+IN: tokyo.alien.tcutil
+
+<< "tokyocabinet" {
+ { [ os macosx? ] [ "/opt/local/lib/libtokyocabinet.dylib" ] }
+ { [ os unix? ] [ "libtokyocabinet.so" ] }
+ { [ os windows? ] [ "tokyocabinet.dll" ] }
+} cond "cdecl" add-library >>
+
+LIBRARY: tokyocabinet
+
+C-ENUM:
+ TCDBTHASH
+ TCDBTBTREE
+ TCDBTFIXED
+ TCDBTTABLE ;
+
+! FIXME: on windows 64bits this isn't correct, because long is 32bits there, and time_t is int64
+TYPEDEF: long tokyo_time_t
+
+TYPEDEF: void* TCLIST*
+
+FUNCTION: TCLIST* tclistnew ( ) ;
+FUNCTION: TCLIST* tclistnew2 ( int anum ) ;
+FUNCTION: void tclistdel ( TCLIST* list ) ;
+FUNCTION: int tclistnum ( TCLIST* list ) ;
+FUNCTION: void* tclistval ( TCLIST* list, int index, int* sp ) ;
+FUNCTION: char* tclistval2 ( TCLIST* list, int index ) ;
+FUNCTION: void tclistpush ( TCLIST* list, void* ptr, int size ) ;
+FUNCTION: void tclistpush2 ( TCLIST* list, char* str ) ;
+FUNCTION: void tcfree ( void* ptr ) ;
+
+TYPEDEF: void* TCCMP
+TYPEDEF: void* TCCODEC
+TYPEDEF: void* TCPDPROC
+TYPEDEF: void* TCITER
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types arrays assocs destructors fry functors
+kernel locals sequences serialize tokyo.alien.tcutil tokyo.utils vectors ;
+IN: tokyo.assoc-functor
+
+FUNCTOR: define-tokyo-assoc-api ( T N -- )
+
+DBGET IS ${T}get
+DBPUT IS ${T}put
+DBOUT IS ${T}out
+DBDEL IS ${T}del
+DBRNUM IS ${T}rnum
+DBITERINIT IS ${T}iterinit
+DBITERNEXT IS ${T}iternext
+DBVANISH IS ${T}vanish
+
+DBKEYS DEFINES tokyo-${N}-keys
+
+TYPE DEFINES-CLASS tokyo-${N}
+
+WHERE
+
+TUPLE: TYPE handle disposed ;
+
+INSTANCE: TYPE assoc
+
+M: TYPE dispose* [ DBDEL f ] change-handle drop ;
+
+M: TYPE at* ( key db -- value/f ? )
+ handle>> swap object>bytes dup length 0 <int>
+ DBGET [ [ memory>object ] [ tcfree ] bi t ] [ f f ] if* ;
+
+M: TYPE assoc-size ( db -- size ) handle>> DBRNUM ;
+
+: DBKEYS ( db -- keys )
+ [ assoc-size <vector> ] [ handle>> ] bi
+ dup DBITERINIT drop 0 <int>
+ [ 2dup DBITERNEXT dup ] [
+ [ memory>object ] [ tcfree ] bi
+ [ pick ] dip swap push
+ ] while 3drop ;
+
+M: TYPE >alist ( db -- alist )
+ [ DBKEYS dup ] keep '[ dup _ at 2array ] change-each ;
+
+M: TYPE set-at ( value key db -- )
+ handle>> spin [ object>bytes dup length ] bi@ DBPUT drop ;
+
+M: TYPE delete-at ( key db -- )
+ handle>> swap object>bytes dup length DBOUT drop ;
+
+M: TYPE clear-assoc ( db -- ) handle>> DBVANISH drop ;
+
+M: TYPE equal? assoc= ;
+
+M: TYPE hashcode* assoc-hashcode ;
+
+;FUNCTOR
\ No newline at end of file
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Functor used to implement the assoc protocol on the different db apis in Tokyo
--- /dev/null
+Bruno Deferrari
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel tokyo.alien.tcrdb tokyo.assoc-functor ;
+IN: tokyo.remotedb
+
+<< "tcrdb" "remotedb" define-tokyo-assoc-api >>
+
+: <tokyo-remotedb> ( host port -- tokyo-remotedb )
+ [ tcrdbnew dup ] 2dip tcrdbopen drop
+ tokyo-remotedb new [ (>>handle) ] keep ;
--- /dev/null
+Higher level API for Tokyo Tyrant's Remote database API. Implements the associative protocol.
--- /dev/null
+Bruno Deferrari
--- /dev/null
+Some utility words used by the tokyo vocabs
--- /dev/null
+! Copyright (C) 2009 Bruno Deferrari
+! See http://factorcode.org/license.txt for BSD license.
+USING: io io.streams.memory serialize kernel ;
+IN: tokyo.utils
+
+: with-memory-reader ( memory quot -- )
+ [ <memory-stream> ] dip with-input-stream* ; inline
+
+: memory>object ( memory -- object )
+ [ deserialize ] with-memory-reader ;
: go-left? ( -- ? ) current-side get left eq? ;
-: inc-count ( tree -- ) [ 1+ ] change-count drop ;
+: inc-count ( tree -- ) [ 1 + ] change-count drop ;
-: dec-count ( tree -- ) [ 1- ] change-count drop ;
+: dec-count ( tree -- ) [ 1 - ] change-count drop ;
: node-link@ ( node ? -- node )
go-left? xor [ left>> ] [ right>> ] if ;
+++ /dev/null
-Sam Anklesaria
+++ /dev/null
-USING: help.markup help.syntax models monads sequences
-ui.gadgets.buttons ui.gadgets.tracks ;
-IN: ui.frp
-
-! Layout utilities
-
-HELP: ,
-{ $values { "uiitem" "a gadget or model" } }
-{ $description "Used in a series of gadgets created by a box, accumulating the gadget" } ;
-HELP: ->
-{ $values { "uiitem" "a gadget or model" } { "model" model } }
-{ $description "Like " { $link , } "but passes its model on for further use." } ;
-HELP: <hbox>
-{ $values { "gadgets" "a list of gadgets" } { "track" track } }
-{ $syntax "[ gadget , gadget , ... ] <hbox>" }
-{ $description "Creates an horizontal track containing the gadgets listed in the quotation" } ;
-HELP: <vbox>
-{ $values { "gadgets" "a list of gadgets" } { "track" track } }
-{ $syntax "[ gadget , gadget , ... ] <hbox>" }
-{ $description "Creates an vertical track containing the gadgets listed in the quotation" } ;
-
-! Gadgets
-HELP: <frp-button>
-{ $values { "text" "the button's label" } { "button" button } }
-{ $description "Creates an button whose model updates on clicks" } ;
-
-HELP: <merge>
-{ $values { "models" "a list of models" } { "model" merge-model } }
-{ $description "Creates a model that merges the updates of others" } ;
-
-HELP: <filter>
-{ $values { "model" model } { "quot" "quotation with stack effect ( a b -- c )" } { "filter-model" filter-model } }
-{ $description "Creates a model that uses the updates of another model when they satisfy a given predicate" } ;
-
-HELP: <fold>
-{ $values { "oldval" "starting value" } { "quot" "applied to update and previous values" } { "model" model } { "model'" model } }
-{ $description "Similar to " { $link reduce } " but works on models, applying a quotation to the previous and new values at each update" } ;
-
-HELP: <switch>
-{ $values { "signal1" model } { "signal2" model } { "signal'" model } }
-{ $description "Creates a model that starts with the behavior of model1 and switches to the behavior of model2 on its update" } ;
-
-ARTICLE: { "frp" "instances" } "FRP Instances"
-"Models are all functors, as " { $link fmap } " corresponds directly to the " { $link "models.arrow" } " vocabulary. "
-"Also, a gadget is a monad. Binding recieves a model and creates a new gadget." ;
-
+++ /dev/null
-USING: accessors arrays colors fonts kernel models
-models.product monads sequences ui.gadgets ui.gadgets.buttons
-ui.gadgets.editors ui.gadgets.line-support ui.gadgets.tables
-ui.gadgets.tracks ui.render ui.gadgets.scrollers ;
-QUALIFIED: make
-IN: ui.frp
-
-! Gadgets
-: <frp-button> ( text -- button ) [ t swap set-control-value ] <border-button> f <model> >>model ;
-TUPLE: frp-table < table quot val-quot color-quot column-titles column-alignment ;
-M: frp-table column-titles column-titles>> ;
-M: frp-table column-alignment column-alignment>> ;
-M: frp-table row-columns quot>> [ call( a -- b ) ] [ drop f ] if* ;
-M: frp-table row-value val-quot>> [ call( a -- b ) ] [ drop f ] if* ;
-M: frp-table row-color color-quot>> [ call( a -- b ) ] [ drop f ] if* ;
-
-: <frp-table> ( model -- table )
- frp-table new-line-gadget dup >>renderer [ ] >>quot swap >>model
- f <model> >>selected-value sans-serif-font >>font
- focus-border-color >>focus-border-color
- transparent >>column-line-color [ ] >>val-quot ;
-: <frp-table*> ( -- table ) f <model> <frp-table> ;
-: <frp-list> ( model -- table ) <frp-table> [ 1array ] >>quot ;
-: <frp-list*> ( -- table ) f <model> <frp-list> ;
-
-: <frp-field> ( -- field ) f <model> <model-field> ;
-
-! Layout utilities
-
-GENERIC: output-model ( gadget -- model )
-M: gadget output-model model>> ;
-M: frp-table output-model selected-value>> ;
-M: model-field output-model field-model>> ;
-M: scroller output-model children>> first model>> ;
-
-GENERIC: , ( uiitem -- )
-M: gadget , make:, ;
-M: model , activate-model ;
-
-GENERIC: -> ( uiitem -- model )
-M: gadget -> dup make:, output-model ;
-M: model -> dup , ;
-M: table -> dup , selected-value>> ;
-
-: <box> ( gadgets type -- track )
- [ { } make:make ] dip <track> swap [ f track-add ] each ; inline
-: <box*> ( gadgets type -- track ) [ <box> ] [ [ model>> ] map <product> ] bi >>model ; inline
-: <hbox> ( gadgets -- track ) horizontal <box> ; inline
-: <hbox*> ( gadgets -- track ) horizontal <box*> ; inline
-: <vbox> ( gadgets -- track ) vertical <box> ; inline
-: <vbox*> ( gadgets -- track ) vertical <box*> ; inline
-
-! !!! Model utilities
-TUPLE: multi-model < model ;
-: <multi-model> ( models kind -- model ) f swap new-model [ [ add-dependency ] curry each ] keep ;
-
-! Events- discrete model utilities
-
-TUPLE: merge-model < multi-model ;
-M: merge-model model-changed [ value>> ] dip set-model ;
-: <merge> ( models -- model ) merge-model <multi-model> ;
-
-TUPLE: filter-model < multi-model quot ;
-M: filter-model model-changed [ value>> ] dip [ quot>> call( val -- bool ) ] 2keep
- [ set-model ] [ 2drop ] if ;
-: <filter> ( model quot -- filter-model ) [ 1array filter-model <multi-model> ] dip >>quot ;
-
-! Behaviors - continuous model utilities
-
-TUPLE: fold-model < multi-model oldval quot ;
-M: fold-model model-changed [ [ value>> ] [ [ oldval>> ] [ quot>> ] bi ] bi*
- call( val oldval -- newval ) ] keep set-model ;
-: <fold> ( oldval quot model -- model' ) 1array fold-model <multi-model> swap >>quot
- swap [ >>oldval ] [ >>value ] bi ;
-
-TUPLE: switch-model < multi-model original switcher on ;
-M: switch-model model-changed 2dup switcher>> =
- [ over value>> [ [ value>> ] [ t >>on ] bi* set-model ] [ 2drop ] if ]
- [ dup on>> [ 2drop ] [ [ value>> ] dip set-model ] if ] if ;
-M: switch-model model-activated [ original>> ] keep model-changed ;
-: <switch> ( signal1 signal2 -- signal' ) [ 2array switch-model <multi-model> ] 2keep
- [ >>original ] [ >>switcher ] bi* ;
-
-TUPLE: mapped < model model quot ;
-
-: <mapped> ( model quot -- arrow )
- f mapped new-model
- swap >>quot
- over >>model
- [ add-dependency ] keep ;
-
-M: mapped model-changed
- [ [ value>> ] [ quot>> ] bi* call( old -- new ) ] [ nip ] 2bi
- set-model ;
-
-! Instances
-M: model fmap <mapped> ;
-
-SINGLETON: gadget-monad
-INSTANCE: gadget-monad monad
-INSTANCE: gadget monad
-M: gadget monad-of drop gadget-monad ;
-M: gadget-monad return drop <gadget> swap >>model ;
-M: gadget >>= output-model [ swap call( x -- y ) ] curry ;
\ No newline at end of file
+++ /dev/null
-Utilities for functional reactive programming in user interfaces
-USING: accessors ui ui.gadgets ui.gadgets.labels ui.gadgets.buttons ui.gadgets.packs locals sequences fonts io.styles ;
+USING: accessors models monads macros generalizations kernel
+ui ui.gadgets.controls models.combinators ui.gadgets.layout ui.gadgets
+ui.gadgets.labels ui.gadgets.editors ui.gadgets.buttons
+ui.gadgets.packs locals sequences fonts io.styles
+wrap.strings ;
+
IN: ui.gadgets.alerts
-:: alert ( quot string -- ) <pile> { 10 10 } >>gap 1 >>align string <label> T{ font { name "sans-serif" } { size 18 } } >>font { 200 100 } >>pref-dim add-gadget
- "okay" [ close-window ] quot append <border-button> add-gadget "" open-window ;
\ No newline at end of file
+:: alert ( quot string -- ) <pile> { 10 10 } >>gap 1 >>align
+ string 22 wrap-lines <label> T{ font { name "sans-serif" } { size 18 } } >>font { 200 100 } >>pref-dim add-gadget
+ "okay" [ close-window ] quot append <border-button> add-gadget "" open-window ;
+
+: alert* ( str -- ) [ ] swap alert ;
+
+:: ask-user ( string -- model' )
+ [ [let | lbl [ string <label> T{ font { name "sans-serif" } { size 14 } } >>font dup , ]
+ fldm [ <model-field*> ->% 1 ]
+ btn [ "okay" <model-border-btn> ] |
+ btn -> [ fldm swap updates ]
+ [ [ drop lbl close-window ] $> , ] bi
+ ] ] <vbox> { 161 86 } >>pref-dim "" open-window ;
+
+MACRO: ask-buttons ( buttons -- quot ) dup length [
+ [ swap
+ [ 22 wrap-lines <label> T{ font { name "sans-serif" } { size 18 } } >>font ,
+ [ [ <model-border-btn> [ close-window ] >>hook -> ] map ] <hbox> , ] <vbox>
+ "" open-window
+ ] dip firstn
+ ] 2curry ;
\ No newline at end of file
: |<< ( book -- ) 0 swap set-control-value ;
: next ( book -- ) model>> [ 1 + ] change-model ;
: prev ( book -- ) model>> [ 1 - ] change-model ;
-: (book-t) ( quot -- quot ) '[ : owner ( gadget -- book ) parent>> dup book? [ owner ] unless ; owner @ ] ;
+: owner ( gadget -- book ) parent>> dup book? [ owner ] unless ;
+: (book-t) ( quot -- quot ) '[ owner @ ] ;
: <book-btn> ( label quot -- button ) (book-t) <button> ;
-: <book-bevel-btn> ( label quot -- button ) (book-t) <border-button> ;
-: >>> ( label -- button ) [ next ] <book-btn> ;
-: <<< ( label -- button ) [ prev ] <book-btn> ;
\ No newline at end of file
+: <book-border-btn> ( label quot -- button ) (book-t) <border-button> ;
+: >>> ( gadget -- ) owner next ;
+: <<< ( gadget -- ) owner prev ;
+: go-to ( gadget number -- ) swap owner model>> set-model ;
+
+: <forward-btn> ( label -- button ) [ >>> ] <button> ;
+: <backward-btn> ( label -- button ) [ <<< ] <button> ;
-USING: accessors arrays kernel math.rectangles models sequences
-ui.frp ui.gadgets ui.gadgets.glass ui.gadgets.labels
-ui.gadgets.tables ui.gestures ;
+USING: accessors arrays kernel math.rectangles sequences
+ui.gadgets.controls models.combinators ui.gadgets ui.gadgets.glass
+ui.gadgets.labels ui.gestures ;
+QUALIFIED-WITH: ui.gadgets.tables tbl
IN: ui.gadgets.comboboxes
TUPLE: combo-table < table spawner ;
-M: combo-table handle-gesture [ call-next-method ] 2keep swap
+M: combo-table handle-gesture [ call-next-method drop ] 2keep swap
T{ button-up } = [
[ spawner>> ]
- [ selected-value>> value>> [ swap set-control-value ] [ drop ] if* ]
- [ hide-glass ] tri drop t
- ] [ drop ] if ;
+ [ tbl:selected-row [ swap set-control-value ] [ 2drop ] if ]
+ [ hide-glass ] tri
+ ] [ drop ] if t ;
TUPLE: combobox < label-control table ;
combobox H{
{ T{ button-down } [ dup table>> over >>spawner <zero-rect> show-glass ] }
} set-gestures
-: <combobox> ( options -- combobox ) [ first [ combobox new-label ] keep <model> >>model ] keep
- [ 1array ] map <model> trivial-renderer combo-table new-table
- >>table ;
\ No newline at end of file
+: <combobox> ( options -- combobox ) [ first [ combobox new-label ] keep <basic> >>model ] keep
+ <basic> combo-table new-table [ 1array ] >>quot >>table ;
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
--- /dev/null
+USING: accessors help.markup help.syntax ui.gadgets.buttons
+ui.gadgets.editors models ui.gadgets ;
+IN: ui.gadgets.controls
+
+HELP: <model-btn>
+{ $values { "gadget" "the button's label" } { "button" button } }
+{ $description "Creates an button whose signal updates on clicks. " } ;
+
+HELP: <model-border-btn>
+{ $values { "text" "the button's label" } { "button" button } }
+{ $description "Creates an button whose signal updates on clicks. " } ;
+
+HELP: <table>
+{ $values { "model" "values the table is to display" } { "table" table } }
+{ $description "Creates an " { $link table } } ;
+
+HELP: <table*>
+{ $values { "table" table } }
+{ $description "Creates an " { $link table } " with no initial values to display" } ;
+
+HELP: <list>
+{ $values { "column-model" "values the table is to display" } { "table" table } }
+{ $description "Creates an " { $link table } " with a val-quot that renders each element as its own row" } ;
+
+HELP: <list*>
+{ $values { "table" table } }
+{ $description "Creates an model-list with no initial values to display" } ;
+
+HELP: indexed
+{ $values { "table" table } }
+{ $description "Sets the output model of an table to the selected-index, rather than the selected-value" } ;
+
+HELP: <model-field>
+{ $values { "model" model } { "gadget" model-field } }
+{ $description "Creates a field with an initial value" } ;
+
+HELP: <model-field*>
+{ $values { "field" model-field } }
+{ $description "Creates a field with an empty initial value" } ;
+
+HELP: <empty-field>
+{ $values { "model" model } { "field" model-field } }
+{ $description "Creates a field with an empty initial value that switches to another signal on its update" } ;
+
+HELP: <model-editor>
+{ $values { "model" model } { "gadget" model-field } }
+{ $description "Creates an editor with an initial value" } ;
+
+HELP: <model-editor*>
+{ $values { "editor" "an editor" } }
+{ $description "Creates a editor with an empty initial value" } ;
+
+HELP: <empty-editor>
+{ $values { "model" model } { "editor" "an editor" } }
+{ $description "Creates a field with an empty initial value that switches to another signal on its update" } ;
+
+HELP: <model-action-field>
+{ $values { "field" action-field } }
+{ $description "Field that updates its model with its contents when the user hits the return key" } ;
+
+HELP: IMG-MODEL-BTN:
+{ $syntax "IMAGE-MODEL-BTN: filename" }
+{ $description "Creates a button using a tiff image named as specified found in the icons subdirectory of the vocabulary path" } ;
+
+HELP: IMG-BTN:
+{ $syntax "[ do-something ] IMAGE-BTN: filename" }
+{ $description "Creates a button using a tiff image named as specified found in the icons subdirectory of the vocabulary path, calling the specified quotation on click" } ;
+
+HELP: output-model
+{ $values { "gadget" gadget } { "model" model } }
+{ $description "Returns the model a gadget uses for output. Often the same as " { $link model>> } } ;
\ No newline at end of file
--- /dev/null
+USING: accessors assocs arrays kernel models monads sequences
+models.combinators ui.gadgets ui.gadgets.borders ui.gadgets.buttons
+ui.gadgets.buttons.private ui.gadgets.editors words images.loader
+ui.gadgets.scrollers ui.images vocabs.parser lexer
+models.range ui.gadgets.sliders ;
+QUALIFIED-WITH: ui.gadgets.sliders slider
+QUALIFIED-WITH: ui.gadgets.tables tbl
+EXCLUDE: ui.gadgets.editors => model-field ;
+IN: ui.gadgets.controls
+
+TUPLE: model-btn < button hook value ;
+: <model-btn> ( gadget -- button ) [
+ [ dup hook>> [ call( button -- ) ] [ drop ] if* ]
+ [ [ [ value>> ] [ ] bi or ] keep set-control-value ]
+ [ model>> f swap (>>value) ] tri
+ ] model-btn new-button f <basic> >>model ;
+: <model-border-btn> ( text -- button ) <model-btn> border-button-theme ;
+
+TUPLE: table < tbl:table { quot initial: [ ] } { val-quot initial: [ ] } color-quot column-titles column-alignment actions ;
+M: table tbl:column-titles column-titles>> ;
+M: table tbl:column-alignment column-alignment>> ;
+M: table tbl:row-columns quot>> [ call( a -- b ) ] [ drop f ] if* ;
+M: table tbl:row-value val-quot>> [ call( a -- b ) ] [ drop f ] if* ;
+M: table tbl:row-color color-quot>> [ call( a -- b ) ] [ drop f ] if* ;
+
+: new-table ( model class -- table ) f swap tbl:new-table dup >>renderer
+ f <basic> >>actions dup actions>> [ set-model ] curry >>action ;
+: <table> ( model -- table ) table new-table ;
+: <table*> ( -- table ) V{ } clone <model> <table> ;
+: <list> ( column-model -- table ) <table> [ 1array ] >>quot ;
+: <list*> ( -- table ) V{ } clone <model> <list> ;
+: indexed ( table -- table ) f >>val-quot ;
+
+TUPLE: model-field < field model* ;
+: init-field ( model -- model' ) [ [ ] [ "" ] if* ] change-value ;
+: <model-field> ( model -- gadget ) model-field new-field swap init-field >>model* ;
+M: model-field graft*
+ [ [ model*>> value>> ] [ editor>> ] bi set-editor-string ]
+ [ dup editor>> model>> add-connection ]
+ [ dup model*>> add-connection ] tri ;
+M: model-field ungraft*
+ [ dup editor>> model>> remove-connection ]
+ [ dup model*>> remove-connection ] bi ;
+M: model-field model-changed 2dup model*>> =
+ [ [ value>> ] [ editor>> ] bi* set-editor-string ]
+ [ nip [ editor>> editor-string ] [ model*>> ] bi set-model ] if ;
+
+: (new-field) ( editor field -- gadget ) [ new-editor ] dip new-border dup gadget-child >>editor
+ field-theme { 1 0 } >>align ; inline
+: <model-field*> ( -- field ) "" <model> <model-field> ;
+: <empty-field> ( model -- field ) "" <model> switch-models <model-field> ;
+: <model-editor> ( model -- gadget ) multiline-editor model-field (new-field) swap init-field >>model* ;
+: <model-editor*> ( -- editor ) "" <model> <model-editor> ;
+: <empty-editor> ( model -- editor ) "" <model> switch-models <model-editor> ;
+
+: <model-action-field> ( -- field ) f <action-field> dup [ set-control-value ] curry >>quot
+ f <model> >>model ;
+
+: <slider> ( init page min max step -- slider ) <range> horizontal slider:<slider> ;
+
+: image-prep ( -- image ) scan current-vocab name>> "vocab:" "/icons/" surround ".tiff" surround <image-name> dup cached-image drop ;
+SYNTAX: IMG-MODEL-BTN: image-prep [ <model-btn> ] curry over push-all ;
+
+SYNTAX: IMG-BTN: image-prep [ swap <button> ] curry over push-all ;
+
+GENERIC: output-model ( gadget -- model )
+M: gadget output-model model>> ;
+M: table output-model dup val-quot>> [ selection>> ] [ selection-index>> ] if ;
+M: model-field output-model model*>> ;
+M: scroller output-model viewport>> children>> first output-model ;
+M: slider output-model model>> range-model ;
+
+IN: accessors
+M: model-btn text>> children>> first text>> ;
+
+IN: ui.gadgets.controls
+
+SINGLETON: gadget-monad
+INSTANCE: gadget-monad monad
+INSTANCE: gadget monad
+M: gadget monad-of drop gadget-monad ;
+M: gadget-monad return drop <gadget> swap >>model ;
+M: gadget >>= output-model [ swap call( x -- y ) ] curry ;
\ No newline at end of file
--- /dev/null
+Gadgets with expanded model usage
\ No newline at end of file
--- /dev/null
+Sam Anklesaria
--- /dev/null
+USING: help.markup help.syntax models ui.gadgets.tracks ;
+IN: ui.gadgets.layout
+
+HELP: ,
+{ $values { "item" "a gadget or model" } }
+{ $description "Used in a series of gadgets created by a box, accumulating the gadget" } ;
+
+HELP: ,%
+{ $syntax "gadget ,% width" }
+{ $description "Like ',' but stretches the gadget to always fill a percent of the parent" } ;
+
+HELP: ->
+{ $values { "uiitem" "a gadget or model" } { "model" model } }
+{ $description "Like ',' but passes its model on for further use." } ;
+
+HELP: ->%
+{ $syntax "gadget ,% width" }
+{ $description "Like '->' but stretches the gadget to always fill a percent of the parent" } ;
+
+HELP: <spacer>
+{ $description "Grows to fill any empty space in a box" } ;
+
+HELP: <hbox>
+{ $values { "gadgets" "a list of gadgets" } { "track" track } }
+{ $syntax "[ gadget , gadget , ... ] <hbox>" }
+{ $description "Creates an horizontal track containing the gadgets listed in the quotation" } ;
+
+HELP: <vbox>
+{ $values { "gadgets" "a list of gadgets" } { "track" track } }
+{ $syntax "[ gadget , gadget , ... ] <hbox>" }
+{ $description "Creates an vertical track containing the gadgets listed in the quotation" } ;
+
+HELP: $
+{ $syntax "$ PLACEHOLDER-NAME $" }
+{ $description "Defines an insertion point in a template named PLACEHOLDER-NAME which can be used by calling its name" } ;
+
+HELP: with-interface
+{ $values { "quot" "quotation that builds a template and inserts into it" } }
+{ $description "Create templates, used with " { $link POSTPONE: $ } } ;
+
+ARTICLE: "ui.gadgets.layout" "GUI Layout"
+"Laying out GUIs works the same way as building lists with " { $vocab-link "make" }
+". Gadgets are layed out using " { $vocab-link "ui.gadgets.tracks" } " through " { $link <hbox> } " and " { $link <vbox> } ", which allow both fixed and percentage widths. "
+{ $link , } " and " { $link -> } " add a model or gadget to the gadget you're building. "
+"Also, books can be made with " { $link <book> } ". "
+{ $link <spacer> } "s add flexable space between items. " $nl
+"Using " { $link with-interface } ", one can pre-build templates to add items to later: "
+"Like in the StringTemplate framework for java, placeholders are defined using $ PLACERHOLDER-NAME $ "
+"Using PLACEHOLDER-NAME again sets it as the current insertion point. "
+"For examples using normal layout, see the " { $vocab-link "sudokus" } " demo. "
+"For examples of templating, see the " { $vocab-link "recipes" } " demo. " ;
+
+ABOUT: "ui.gadgets.layout"
\ No newline at end of file
--- /dev/null
+USING: accessors assocs arrays fry kernel lexer make math.parser
+models monads namespaces parser sequences
+sequences.extras models.combinators ui.gadgets
+ui.gadgets.tracks words ui.gadgets.controls ;
+QUALIFIED: make
+QUALIFIED-WITH: ui.gadgets.books book
+IN: ui.gadgets.layout
+
+SYMBOL: templates
+TUPLE: layout gadget size ; C: <layout> layout
+TUPLE: placeholder < gadget members ;
+: <placeholder> ( -- placeholder ) placeholder new V{ } clone >>members ;
+
+: (remove-members) ( placeholder members -- ) [ [ model? ] filter swap parent>> model>> [ remove-connection ] curry each ]
+ [ nip [ gadget? ] filter [ unparent ] each ] 2bi ;
+
+: remove-members ( placeholder -- ) dup members>> [ drop ] [ [ (remove-members) ] keep delete-all ] if-empty ;
+: add-member ( obj placeholder -- ) over layout? [ [ gadget>> ] dip ] when members>> push ;
+
+: , ( item -- ) make:, ;
+: make* ( quot -- list ) { } make ; inline
+
+! Just take the previous mentioned placeholder and use it
+! If there is no previously mentioned placeholder, we're probably making a box, and will create the placeholder ourselves
+DEFER: with-interface
+: insertion-quot ( quot -- quot' ) make:building get [ [ placeholder? ] find-last nip [ <placeholder> dup , ] unless*
+ templates get spin '[ [ _ templates set _ , @ ] with-interface ] ] when* ;
+
+SYNTAX: ,% scan string>number [ <layout> , ] curry over push-all ;
+SYNTAX: ->% scan string>number '[ [ _ <layout> , ] [ output-model ] bi ] over push-all ;
+
+GENERIC: -> ( uiitem -- model )
+M: gadget -> dup , output-model ;
+M: model -> dup , ;
+
+: <spacer> ( -- ) <gadget> 1 <layout> , ;
+
+: add-layout ( track layout -- track ) [ gadget>> ] [ size>> ] bi track-add ;
+: layouts ( sized? gadgets -- layouts ) [ [ gadget? ] [ layout? ] bi or ] filter swap
+ [ [ dup layout? [ f <layout> ] unless ] map ]
+ [ [ dup gadget? [ gadget>> ] unless ] map ] if ;
+: make-layout ( building sized? -- models layouts ) [ swap layouts ] curry
+ [ make* [ [ model? ] filter ] ] dip bi ; inline
+: <box> ( gadgets type -- track )
+ [ t make-layout ] dip <track>
+ swap [ add-layout ] each
+ swap [ <collection> >>model ] unless-empty ; inline
+: <hbox> ( gadgets -- track ) horizontal <box> ; inline
+: <vbox> ( gadgets -- track ) vertical <box> ; inline
+
+: make-book ( models gadgets model -- book ) book:<book> swap [ "No models in books" throw ] unless-empty ;
+: <book> ( quot: ( -- model ) -- book ) f make-layout rot 0 >>value make-book ; inline
+: <book*> ( quot -- book ) f make-layout f make-book ; inline
+
+ERROR: not-in-template word ;
+SYNTAX: $ CREATE-WORD dup
+ [ [ dup templates get at [ nip , ] [ not-in-template ] if* ] curry (( -- )) define-declared "$" expect ]
+ [ [ <placeholder> [ swap templates get set-at ] keep , ] curry ] bi over push-all ;
+
+: insert-gadget ( number parent gadget -- ) -rot [ but-last insert-nth ] change-children drop ;
+: insert-size ( number parent size -- ) -rot [ but-last insert-nth ] change-sizes drop ;
+: insertion-point ( placeholder -- number parent ) dup parent>> [ children>> index ] keep ;
+
+GENERIC: >layout ( gadget -- layout )
+M: gadget >layout f <layout> ;
+M: layout >layout ;
+
+GENERIC# (add-gadget-at) 2 ( parent item n -- )
+M: gadget (add-gadget-at) -rot [ add-gadget ] keep insert-gadget ;
+M: track (add-gadget-at) -rot >layout [ add-layout ] keep [ gadget>> insert-gadget ] [ size>> insert-size ] 3bi ;
+
+GENERIC# add-gadget-at 1 ( item location -- )
+M: object add-gadget-at insertion-point -rot (add-gadget-at) ;
+M: model add-gadget-at parent>> dup book:book? [ "No models in books" throw ]
+ [ dup model>> dup collection? [ nip swap add-connection ] [ drop [ 1array <collection> ] dip (>>model) ] if ] if ;
+: track-add-at ( item location size -- ) swap [ <layout> ] dip add-gadget-at ;
+: (track-add-at) ( parent item n size -- ) swap [ <layout> ] dip (add-gadget-at) ;
+
+: insert-item ( item location -- ) [ dup get [ drop ] [ remove-members ] if ] [ on ] [ ] tri
+ [ add-member ] 2keep add-gadget-at ;
+
+: insert-items ( makelist -- ) t swap [ dup placeholder? [ nip ] [ over insert-item ] if ] each drop ;
+
+: with-interface ( quot -- ) [ make* ] curry H{ } clone templates rot with-variable [ insert-items ] with-scope ; inline
+
+M: model >>= [ swap insertion-quot <action> ] curry ;
+M: model fmap insertion-quot <mapped> ;
+M: model $> insertion-quot side-effect-model new-mapped-model ;
+M: model <$ insertion-quot quot-model new-mapped-model ;
\ No newline at end of file
--- /dev/null
+Syntax for easily building GUIs and using templates
\ No newline at end of file
list-theme ;
: calc-bounded-index ( n list -- m )
- control-value length 1- min 0 max ;
+ control-value length 1 - min 0 max ;
: bound-index ( list -- )
dup index>> over calc-bounded-index >>index drop ;
] if ;
: select-previous ( list -- )
- [ index>> 1- ] keep select-index ;
+ [ index>> 1 - ] keep select-index ;
: select-next ( list -- )
- [ index>> 1+ ] keep select-index ;
+ [ index>> 1 + ] keep select-index ;
: invoke-value-action ( list -- )
dup list-empty? [
--- /dev/null
+Sam Anklesaria
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2009 Sam Anklesaria
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays accessors combinators kernel math
+models models.combinators namespaces sequences
+ui.gadgets ui.gadgets.controls ui.gadgets.layout
+ui.gadgets.tracks ui.gestures ui.gadgets.line-support ;
+EXCLUDE: ui.gadgets.editors => model-field ;
+IN: ui.gadgets.poppers
+
+TUPLE: popped < model-field { fatal? initial: t } ;
+TUPLE: popped-editor < multiline-editor ;
+: <popped> ( text -- gadget ) <basic> init-field popped-editor popped (new-field) swap >>model* ;
+
+: set-expansion ( popped size -- ) over dup parent>> [ children>> index ] [ sizes>> ] bi set-nth relayout ;
+: new-popped ( popped -- ) insertion-point "" <popped>
+ [ rot 1 + f (track-add-at) ] keep [ relayout ] [ request-focus ] bi ;
+: focus-prev ( popped -- ) dup parent>> children>> length 1 =
+ [ drop ] [
+ insertion-point [ 1 - dup -1 = [ drop 1 ] when ] [ children>> ] bi* nth
+ [ request-focus ] [ editor>> end-of-document ] bi
+ ] if ;
+: initial-popped ( popper -- ) "" <popped> [ f track-add drop ] keep request-focus ;
+
+TUPLE: popper < track { unfocus-hook initial: [ drop ] } ;
+! list of strings is model (make shown objects implement sequence protocol)
+: <popper> ( model -- popper ) vertical popper new-track swap >>model ;
+
+M: popped handle-gesture swap {
+ { gain-focus [ 1 set-expansion f ] }
+ { lose-focus [ dup parent>>
+ [ [ unfocus-hook>> call( a -- ) ] curry [ f set-expansion ] bi ]
+ [ drop ] if* f
+ ] }
+ { T{ key-up f f "RET" } [ dup editor>> delete-previous-character new-popped f ] }
+ { T{ key-up f f "BACKSPACE" } [ dup editor>> editor-string "" =
+ [ dup fatal?>> [ [ focus-prev ] [ unparent ] bi ] [ t >>fatal? drop ] if ]
+ [ f >>fatal? drop ] if f
+ ] }
+ [ swap call-next-method ]
+} case ;
+
+M: popper handle-gesture swap T{ button-down f f 1 } =
+ [ hand-click# get 2 = [ initial-popped ] [ drop ] if ] [ drop ] if f ;
+
+M: popper model-changed
+ [ children>> [ unparent ] each ]
+ [ [ value>> [ <popped> ] map ] dip [ f track-add ] reduce request-focus ] bi ;
+
+M: popped pref-dim* editor>> [ pref-dim* first ] [ line-height ] bi 2array ;
+M: popper focusable-child* children>> [ t ] [ first ] if-empty ;
\ No newline at end of file
f swap open-window* ;
: into-window ( world quot -- world )
- [ dup handle>> ] dip with-gl-context ; inline
+ [ dup ] dip with-gl-context ; inline
--- /dev/null
+Syntax and combinators for manipulating algebraic data types
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: arrays classes classes.singleton classes.tuple help.markup
+help.syntax kernel multiline slots quotations ;
+IN: variants
+
+HELP: VARIANT:
+{ $syntax <"
+VARIANT: class-name
+ singleton
+ singleton
+ tuple: { slot slot slot ... }
+ .
+ .
+ .
+ ; "> }
+{ $description "Defines " { $snippet "class-name" } " as a union of the following " { $link singleton-class } " and " { $link tuple-class } " definitions. Each " { $snippet "singleton" } " word is defined as a " { $snippet "singleton-class" } ", and each " { $snippet "tuple" } " word is defined aas a " { $snippet "tuple-class" } " with the given set of " { $snippet "slot" } "s, using the same syntax for slot specifiers as " { $link POSTPONE: TUPLE: } ". Typed tuple slots can recursively reference the variant " { $snippet "class-name" } " being defined. For " { $snippet "tuple" } " types, a " { $link boa } " constructor word " { $snippet "<tuple>" } " is defined as well." }
+{ $examples { $code <"
+USING: kernel variants ;
+IN: scratchpad
+
+VARIANT: list
+ nil
+ cons: { { first object } { rest list } }
+ ;
+"> } } ;
+
+HELP: match
+{ $values { "branches" array } }
+{ $description "Dispatches on the type of the value on the top of the stack. If the type is a " { $link singleton-class } ", the corresponding quotation is called with the underlying stack unchanged. If the type is a " { $link tuple-class } ", the tuple slots are pushed onto the stack by order of arguments." }
+{ $examples { $example <"
+USING: kernel math prettyprint variants ;
+IN: scratchpad
+
+VARIANT: list
+ nil
+ cons: { { first object } { rest list } }
+ ;
+
+: list-length ( list -- length )
+ {
+ { nil [ 0 ] }
+ { cons [ nip list-length 1 + ] }
+ } match ;
+
+1 2 3 4 nil <cons> <cons> <cons> <cons> list-length .
+"> "4" } } ;
+
+HELP: unboa
+{ $values { "class" class } }
+{ $description "Decomposes a tuple of type " { $snippet "class" } " into its component slot values by order of arguments. The inverse of " { $link boa } "." } ;
+
+HELP: variant-class
+{ $class-description "This class comprises class names that have been defined with " { $link POSTPONE: VARIANT: } ". When a " { $snippet "variant-class" } " is used as the type of a specialized " { $link tuple } " slot, the variant's first member type is used as the default " { $link initial-value } "." } ;
+
+{ POSTPONE: VARIANT: variant-class match } related-words
+
+ARTICLE: "variants" "Algebraic data types"
+"The " { $vocab-link "variants" } " vocabulary provides syntax and combinators for defining and manipulating algebraic data types."
+{ $subsection POSTPONE: VARIANT: }
+{ $subsection variant-class }
+{ $subsection match } ;
+
+ABOUT: "variants"
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: kernel math tools.test variants ;
+IN: variants.tests
+
+VARIANT: list
+ nil
+ cons: { { first object } { rest list } }
+ ;
+
+[ t ] [ nil list? ] unit-test
+[ t ] [ 1 nil <cons> list? ] unit-test
+[ f ] [ 1 list? ] unit-test
+
+: list-length ( list -- length )
+ {
+ { nil [ 0 ] }
+ { cons [ nip list-length 1 + ] }
+ } match ;
+
+[ 4 ]
+[ 5 6 7 8 nil <cons> <cons> <cons> <cons> list-length ] unit-test
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors arrays classes classes.mixin classes.parser
+classes.singleton classes.tuple classes.tuple.parser
+classes.union combinators inverse kernel lexer macros make
+parser quotations sequences slots splitting words ;
+IN: variants
+
+PREDICATE: variant-class < mixin-class "variant" word-prop ;
+
+M: variant-class initial-value*
+ dup members [ no-initial-value ]
+ [ nip first dup word? [ initial-value* ] unless ] if-empty ;
+
+: define-tuple-class-and-boa-word ( class superclass slots -- )
+ pick [ define-tuple-class ] dip
+ dup name>> "<" ">" surround create-in swap define-boa-word ;
+
+: define-variant-member ( member -- class )
+ dup array? [ first3 pick [ define-tuple-class-and-boa-word ] dip ] [ dup define-singleton-class ] if ;
+
+: define-variant-class ( class members -- )
+ [ [ define-mixin-class ] [ t "variant" set-word-prop ] [ ] tri ] dip
+ [ define-variant-member swap add-mixin-instance ] with each ;
+
+: parse-variant-tuple-member ( name -- member )
+ create-class-in tuple
+ "{" expect
+ [ "}" parse-tuple-slots-delim ] { } make
+ 3array ;
+
+: parse-variant-member ( name -- member )
+ ":" ?tail [ parse-variant-tuple-member ] [ create-class-in ] if ;
+
+: parse-variant-members ( -- members )
+ [ scan dup ";" = not ]
+ [ parse-variant-member ] produce nip ;
+
+SYNTAX: VARIANT:
+ CREATE-CLASS
+ parse-variant-members
+ define-variant-class ;
+
+MACRO: unboa ( class -- )
+ <wrapper> \ boa [ ] 2sequence [undo] ;
+
+GENERIC# (match-branch) 1 ( class quot -- class quot' )
+
+M: singleton-class (match-branch)
+ \ drop prefix ;
+M: object (match-branch)
+ over \ unboa [ ] 2sequence prepend ;
+
+: ?class ( object -- class )
+ dup word? [ class ] unless ;
+
+MACRO: match ( branches -- )
+ [ dup callable? [ first2 (match-branch) 2array ] unless ] map
+ [ \ dup \ ?class ] dip \ case [ ] 4sequence ;
+
>>comments ;
: reverse-chronological-order ( seq -- sorted )
- [ [ date>> ] compare invert-comparison ] sort ;
+ [ date>> ] inv-sort-with ;
: validate-author ( -- )
{ { "author" [ v-username ] } } validate-params ;
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel furnace.actions html.forms
-http.server.dispatchers db db.tuples db.types urls
-furnace.redirection multiline http namespaces ;
+USING: accessors furnace.actions furnace.redirection
+html.forms http http.server http.server.dispatchers
+io.directories io.encodings.utf8 io.files io.pathnames
+kernel math.parser multiline namespaces sequences urls ;
IN: webapps.imagebin
-TUPLE: imagebin < dispatcher ;
-
-TUPLE: image id path ;
-
-image "IMAGE" {
- { "id" "ID" INTEGER +db-assigned-id+ }
- { "path" "PATH" { VARCHAR 256 } +not-null+ }
-} define-persistent
+TUPLE: imagebin < dispatcher path n ;
: <uploaded-image-action> ( -- action )
<page-action>
{ imagebin "uploaded-image" } >>template ;
-SYMBOL: my-post-data
+: next-image-path ( -- path )
+ imagebin get
+ [ path>> ] [ n>> number>string ] bi append-path ;
+
+M: imagebin call-responder*
+ [ imagebin set ] [ call-next-method ] bi ;
+
+: move-image ( mime-file -- )
+ next-image-path
+ [ [ temporary-path>> ] dip move-file ]
+ [ [ filename>> ] dip ".txt" append utf8 set-file-contents ] 2bi ;
+
: <upload-image-action> ( -- action )
<page-action>
{ imagebin "upload-image" } >>template
[
-
- ! request get post-data>> my-post-data set-global
- ! image new
- ! "file" value
- ! insert-tuple
+ "file1" param [ move-image ] when*
+ "file2" param [ move-image ] when*
+ "file3" param [ move-image ] when*
"uploaded-image" <redirect>
] >>submit ;
-: <imagebin> ( -- responder )
+: <imagebin> ( image-directory -- responder )
imagebin new-dispatcher
+ swap [ make-directories ] [ >>path ] bi
+ 0 >>n
<upload-image-action> "" add-responder
<upload-image-action> "upload-image" add-responder
<uploaded-image-action> "uploaded-image" add-responder ;
+"resource:images" <imagebin> main-responder set-global
<html>
<head><title>Uploaded</title></head>
<body>
-hi from uploaded-image
+You uploaded something!
</body>
</html>
: pastes ( -- pastes )
f <paste> select-tuples
- [ [ date>> ] compare ] sort
+ [ date>> ] sort-with
reverse ;
TUPLE: annotation < entity parent ;
: blogroll ( -- seq )
f <blog> select-tuples
- [ [ name>> ] compare ] sort ;
+ [ name>> ] sort-with ;
: postings ( -- seq )
posting new select-tuples
- [ [ date>> ] compare invert-comparison ] sort ;
+ [ date>> ] inv-sort-with ;
: <edit-blogroll-action> ( -- action )
<page-action>
[ '[ _ <posting> ] map ] 2map concat ;
: sort-entries ( entries -- entries' )
- [ [ date>> ] compare invert-comparison ] sort ;
+ [ date>> ] inv-sort-with ;
: update-cached-postings ( -- )
blogroll fetch-blogroll sort-entries 8 short head [
M: revision feed-entry-url id>> revision-url ;
: reverse-chronological-order ( seq -- sorted )
- [ [ date>> ] compare invert-comparison ] sort ;
+ [ date>> ] inv-sort-with ;
: <revision> ( id -- revision )
revision new swap >>id ;
[
f <article> select-tuples
- [ [ title>> ] compare ] sort
+ [ title>> ] sort-with
"articles" set-value
] >>init
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel
-cocoa
-cocoa.application
-cocoa.types
-cocoa.classes
-cocoa.windows
-core-graphics.types ;
+USING: cocoa cocoa.application cocoa.types cocoa.classes cocoa.windows
+core-graphics.types kernel math.bitwise ;
IN: webkit-demo
FRAMEWORK: /System/Library/Frameworks/WebKit.framework
WebView -> alloc
rect f f -> initWithFrame:frameName:groupName: ;
+: window-style ( -- n )
+ {
+ NSClosableWindowMask
+ NSMiniaturizableWindowMask
+ NSResizableWindowMask
+ NSTitledWindowMask
+ } flags ;
+
: <WebWindow> ( -- id )
- <WebView> rect <ViewWindow> ;
+ <WebView> rect window-style <ViewWindow> ;
: load-url ( window url -- )
[ -> contentView ] [ <NSString> ] bi* -> setMainFrameURL: ;
--- /dev/null
+Open windows with different control sets
--- /dev/null
+! (c)2009 Joe Groff bsd license
+USING: accessors assocs kernel locals sequences ui
+ui.gadgets ui.gadgets.worlds ;
+IN: window-controls-demo
+
+CONSTANT: window-control-sets-to-test
+ H{
+ { "No controls" { } }
+ { "Normal title bar" { normal-title-bar } }
+ { "Small title bar" { small-title-bar close-button } }
+ { "Close button" { normal-title-bar close-button } }
+ { "Close and minimize buttons" { normal-title-bar close-button minimize-button } }
+ { "Minimize button" { normal-title-bar minimize-button } }
+ { "Close, minimize, and maximize buttons" { normal-title-bar close-button minimize-button maximize-button } }
+ { "Resizable" { normal-title-bar close-button minimize-button maximize-button resize-handles } }
+ }
+
+TUPLE: window-controls-demo-world < world
+ windows ;
+
+M: window-controls-demo-world end-world
+ windows>> [ close-window ] each ;
+
+M: window-controls-demo-world pref-dim*
+ drop { 400 400 } ;
+
+: attributes-template ( -- x )
+ T{ world-attributes
+ { world-class window-controls-demo-world }
+ } clone ;
+
+: window-controls-demo ( -- )
+ attributes-template V{ } clone window-control-sets-to-test
+ [| title attributes windows controls |
+ f attributes
+ title >>title
+ controls >>window-controls
+ open-window*
+ windows >>windows
+ windows push
+ ] with with assoc-each ;
+
+MAIN: window-controls-demo
*wordtimes* get-global [ drop { 0 0 } ] cache first2 ;
: update-times ( utime current-utime current-numinvokes -- utime' invokes' )
- rot [ + ] curry [ 1+ ] bi* ;
+ rot [ + ] curry [ 1 + ] bi* ;
: register-time ( utime word -- )
name>>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+x = ENV["TM_FILEPATH"][/\/([^\/]+\.factor)/,1]
+y = x.sub("-tests","").sub("docs", "tests")
+if x == y then
+ z = x.sub(".factor","")
+ factor_eval(%Q(USING: tools.scaffold #{z} ;\n"#{z}" scaffold-help))
+ y = x.sub(".factor", "-docs.factor")
+end
+exec "mate #{ENV["TM_FILEPATH"][/(.*\/)[^\/]+\.factor/,1] << y}"</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>none</string>
+ <key>keyEquivalent</key>
+ <string>^@`</string>
+ <key>name</key>
+ <string>Cycle Vocabs/Docs/Tests</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>D348BE40-6F51-4471-B300-DDDA70ED8C8C</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: editors\n "#{word}" edit-vocab))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>@V</string>
+ <key>name</key>
+ <string>Edit Vocab</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>0034EC1C-DAD1-498F-82FD-BEF7015F84EE</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USING: help.topics editors ;\n \\ #{word} >link edit))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>@D</string>
+ <key>name</key>
+ <string>Edit Word Docs</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>D95A617C-E1C6-44DA-9126-04171CB21299</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: editors\n \\ #{word} edit))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>@E</string>
+ <key>name</key>
+ <string>Edit Word</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>C573487C-DD7D-497F-A728-52D7962D95E2</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: ui.tools.operations\n [ #{ENV["TM_SELECTED_TEXT"} ] com-expand-macros))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>name</key>
+ <string>Expand Selection</string>
+ <key>output</key>
+ <string>showAsTooltip</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>8465B33D-7CA0-4337-945C-4078346D64BC</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_run(%Q(#{doc_using_statements(doc)} USE: editors\n \\ #{word} fix))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>@F</string>
+ <key>name</key>
+ <string>Fix Word</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>D02D9D74-E073-48AE-A78E-B40FFFA519D5</string>
+</dict>
+</plist>
doc = STDIN.read
word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
-factor_run(%Q(#{doc_using_statements(doc)} USE: ui.tools.workspace\n \\ #{word} help-window))</string>
+factor_run(%Q(#{doc_using_statements(doc)} USE: help\n \\ #{word} help))</string>
<key>fallbackInput</key>
<string>word</string>
<key>input</key>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>beforeRunningCommand</key>
- <string>nop</string>
- <key>command</key>
- <string>#!/usr/bin/env ruby
-
-require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
-
-doc = STDIN.read
-puts factor_eval(%Q(#{doc_using_statements(doc)} USE: inference\n [ #{ENV["TM_SELECTED_TEXT"]} ] infer.))</string>
- <key>fallbackInput</key>
- <string>word</string>
- <key>input</key>
- <string>document</string>
- <key>name</key>
- <string>Infer Effect of Selection</string>
- <key>output</key>
- <string>showAsTooltip</string>
- <key>scope</key>
- <string>source.factor</string>
- <key>uuid</key>
- <string>B619FCC0-2DF2-4657-82A8-0E5676A10254</string>
-</dict>
-</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: stack-checker\n [ #{ENV["TM_SELECTED_TEXT"]} ] infer.))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^i</string>
+ <key>name</key>
+ <string>Infer Selection</string>
+ <key>output</key>
+ <string>showAsTooltip</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>B619FCC0-2DF2-4657-82A8-0E5676A10254</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: stack-checker\n [ #{ENV["TM_SELECTED_TEXT"]} ] infer.))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>name</key>
+ <string>Insert Inferrence</string>
+ <key>output</key>
+ <string>afterSelectedText</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>DBC0A0CA-5368-43A7-864B-7B9C4034AD08</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_run(%Q(#{doc_using_statements(doc)} USE: tools.profiler\n [ #{word} ] profile))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^p</string>
+ <key>name</key>
+ <string>Profile</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>7FF52332-CA5B-4D46-99EF-DAE0659DB478</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+doc = STDIN.read
+factor_run(%Q(USE: vocabs.loader\n "#{doc[/\bIN:\s(\S+)/, 1]}" reload))</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^r</string>
+ <key>name</key>
+ <string>Reload in Listener</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>8088D204-FFD7-4384-8FDD-A01536FFD0E7</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: tools.annotations\n \\ #{word} reset))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^~r</string>
+ <key>name</key>
+ <string>Reset Word</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>71F08D9B-3D24-4E78-84C9-82CA736554D1</string>
+</dict>
+</plist>
doc = STDIN.read
word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
-puts factor_eval(%Q(#{doc_using_statements(doc)} USE: prettyprint\n \\ #{word} see))</string>
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: see\n \\ #{word} see))</string>
<key>fallbackInput</key>
<string>word</string>
<key>input</key>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: tools.annotations\n \\ #{word} breakpoint))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^b</string>
+ <key>name</key>
+ <string>Set Breakpoint</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>E4614756-DF2E-433A-8935-197159C67AB8</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+factor_run(%Q(USING: namespaces parser ;
+auto-use? t set "#{ENV["TM_FILEPATH"]}" run-file auto-use? f set))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>none</string>
+ <key>keyEquivalent</key>
+ <string>^u</string>
+ <key>name</key>
+ <string>Show Using</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>93AF1721-C14D-428A-B5A0-34CEFAA3B3C5</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: tools.crossref\n \\ #{word} usage.))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>name</key>
+ <string>Usage</string>
+ <key>output</key>
+ <string>showAsTooltip</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>3043A033-A113-4283-BCBB-3DE2CCC8F63E</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(USE: tools.crossref\n "#{word}" vocab-usage.))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>none</string>
+ <key>name</key>
+ <string>Vocab Usage</string>
+ <key>output</key>
+ <string>showAsTooltip</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>B1F81321-B760-474F-875D-78FB52752E1B</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(USE: tools.crossref\n "#{word}" vocab-uses.))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>none</string>
+ <key>name</key>
+ <string>Vocab Uses</string>
+ <key>output</key>
+ <string>showAsTooltip</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>BC3E2E39-3B79-460C-B05E-BD00BAACB90E</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+puts factor_run(%Q(#{doc_using_statements(doc)} USE: tools.walker\n [ #{ENV["TM_SELECTED_TEXT"]} ] walk))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^w</string>
+ <key>name</key>
+ <string>Walk Selection</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>57C2BAAC-0474-404F-AA91-DFD02EC2A3ED</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>bundleUUID</key>
+ <string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+word = line_current_word(ENV["TM_CURRENT_LINE"], ENV["TM_LINE_INDEX"].to_i)
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: tools.annotations\n \\ #{word} watch))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>keyEquivalent</key>
+ <string>^~w</string>
+ <key>name</key>
+ <string>Watch Word</string>
+ <key>output</key>
+ <string>discard</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>1C86869F-1030-4F74-B242-6357A080E127</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>commands</key>
+ <array>
+ <dict>
+ <key>command</key>
+ <string>cut:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>m</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>y</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>-</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>w</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>o</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>r</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>d</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <dict>
+ <key>action</key>
+ <string>findPrevious</string>
+ <key>findInProjectIgnoreCase</key>
+ <true/>
+ <key>findString</key>
+ <string>: </string>
+ <key>ignoreCase</key>
+ <true/>
+ <key>replaceAllScope</key>
+ <string>document</string>
+ <key>replaceString</key>
+ <string>table</string>
+ <key>wrapAround</key>
+ <true/>
+ </dict>
+ <key>command</key>
+ <string>findWithOptions:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>moveToBeginningOfLine:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>paste:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>moveToBeginningOfLineAndModifySelection:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <dict>
+ <key>beforeRunningCommand</key>
+ <string>nop</string>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+
+doc = STDIN.read
+puts factor_eval(%Q(#{doc_using_statements(doc)} USE: stack-checker\n [ #{ENV["TM_SELECTED_TEXT"]} ] infer.))</string>
+ <key>fallbackInput</key>
+ <string>word</string>
+ <key>input</key>
+ <string>document</string>
+ <key>name</key>
+ <string>Insert Inferrence</string>
+ <key>output</key>
+ <string>afterSelectedText</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>DBC0A0CA-5368-43A7-864B-7B9C4034AD08</string>
+ </dict>
+ <key>command</key>
+ <string>executeCommandWithOptions:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>insertNewline:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <dict>
+ <key>action</key>
+ <string>findPrevious</string>
+ <key>findInProjectIgnoreCase</key>
+ <true/>
+ <key>findString</key>
+ <string>(</string>
+ <key>ignoreCase</key>
+ <true/>
+ <key>replaceAllScope</key>
+ <string>document</string>
+ <key>replaceString</key>
+ <string>table</string>
+ <key>wrapAround</key>
+ <true/>
+ </dict>
+ <key>command</key>
+ <string>findWithOptions:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>moveToEndOfLineAndModifySelection:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>cut:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string> </string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>;</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>moveToBeginningOfLine:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>:</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string> </string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>m</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>y</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>-</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>w</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>o</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>r</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string>d</string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string> </string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ <dict>
+ <key>command</key>
+ <string>paste:</string>
+ </dict>
+ <dict>
+ <key>argument</key>
+ <string> </string>
+ <key>command</key>
+ <string>insertText:</string>
+ </dict>
+ </array>
+ <key>keyEquivalent</key>
+ <string>@W</string>
+ <key>name</key>
+ <string>Extract as New Word</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>82E740D1-8D20-48AF-8470-C85C251D4870</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>name</key>
+ <string>Miscellaneous</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>settings</key>
+ <dict>
+ <key>increaseIndentPattern</key>
+ <string>^:</string>
+ <key>shellVariables</key>
+ <array>
+ <dict>
+ <key>name</key>
+ <string>TM_COMMENT_START</string>
+ <key>value</key>
+ <string>! </string>
+ </dict>
+ </array>
+ </dict>
+ <key>uuid</key>
+ <string>D60675B0-9BF4-4CCF-9066-CA14FE836981</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>[
+ $TM_SELECTED_TEXT$0
+]</string>
+ <key>keyEquivalent</key>
+ <string>~[</string>
+ <key>name</key>
+ <string>[ expanded</string>
+ <key>scope</key>
+ <string>source.factor
+</string>
+ <key>tabTrigger</key>
+ <string>“</string>
+ <key>uuid</key>
+ <string>F771F82B-6B2B-4DAE-9A2A-E1042D3B08AD</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>[ $TM_SELECTED_TEXT$0 ]</string>
+ <key>keyEquivalent</key>
+ <string>[</string>
+ <key>name</key>
+ <string>[</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>[</string>
+ <key>uuid</key>
+ <string>3F17AF0F-4DE0-4A86-A649-CB65907F0DA5</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>
+ [ $1 ]
+ [ $2 ] bi</string>
+ <key>name</key>
+ <string>bi</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>bi</string>
+ <key>uuid</key>
+ <string>8D69F968-D322-4008-A540-209B32A97F5D</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>{
+ [ $1 ]
+ [ $2 ]
+ [ $3 ]
+ [ $4 ]
+} cleave</string>
+ <key>name</key>
+ <string>cleave</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>cleave</string>
+ <key>uuid</key>
+ <string>E51383D9-1C82-4ACE-AE45-633E6CE35245</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>{
+ { [ $1 ] [ $2 ] }
+ { [ $3 ] [ $4 ] }
+$5} cond </string>
+ <key>name</key>
+ <string>cond</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>cond</string>
+ <key>uuid</key>
+ <string>C8E068DE-A117-43AE-9916-99AF2C21BD24</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>
+FUNCTOR: $1 ( $2 -- $3 )
+$4
+WHERE
+$0
+;FUNCTOR
+</string>
+ <key>name</key>
+ <string>functor</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>functor</string>
+ <key>uuid</key>
+ <string>B9DA0999-D710-4693-8056-9E4B8BDAC7E9</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>
+ [ $1 ]
+ [ $2 ] if</string>
+ <key>name</key>
+ <string>if</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>if</string>
+ <key>uuid</key>
+ <string>AD9D0A71-2371-4756-86D7-A084B4A3FE2F</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>:: $1 ( $2 -- $3 ) $0 ;</string>
+ <key>name</key>
+ <string>::</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>::</string>
+ <key>uuid</key>
+ <string>9A96D386-F7B9-47DC-9CAE-E4BAD1F81748</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>
+ [let | $1 [ $2 ] $3|
+ $0
+ ]</string>
+ <key>name</key>
+ <string>let</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>let</string>
+ <key>uuid</key>
+ <string>1B3CF04D-B23D-4D9A-A648-7191315CDF96</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>{
+ [ $1 ]
+ [ $2 ]
+ [ $3 ]
+ [ $4 ]
+} spread</string>
+ <key>name</key>
+ <string>spread</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>spread</string>
+ <key>uuid</key>
+ <string>3DE1C097-6F69-4562-9C49-C897FF5AB909</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>
+ [ $1 ]
+ [ $2 ]
+ [ $3 ] tri</string>
+ <key>name</key>
+ <string>tri</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>tri</string>
+ <key>uuid</key>
+ <string>B8B7B5ED-C75C-4BD1-906A-220C9956F91F</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>: $1 ( $2 -- $3 ) $0 ;</string>
+ <key>name</key>
+ <string>:</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>:</string>
+ <key>uuid</key>
+ <string>7903894E-CB75-43ED-8635-C0E65F94DEBB</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>{
+ $TM_SELECTED_TEXT$0
+}</string>
+ <key>keyEquivalent</key>
+ <string>~{</string>
+ <key>name</key>
+ <string>{ expanded</string>
+ <key>scope</key>
+ <string>source.factor
+</string>
+ <key>uuid</key>
+ <string>275EA395-6026-481A-81C5-1F71D8026972</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>content</key>
+ <string>{ $TM_SELECTED_TEXT$0 }</string>
+ <key>keyEquivalent</key>
+ <string>{</string>
+ <key>name</key>
+ <string>{</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>tabTrigger</key>
+ <string>[</string>
+ <key>uuid</key>
+ <string>B4448FB0-B7F9-4FFD-AB4B-EAD31A5920CB</string>
+</dict>
+</plist>
document.scan(/\b(USING:\s[^;]*\s;|USE:\s+\S+|IN:\s\S+)/).join("\n") << "\n"
end
+def doc_vocab(document)
+ document.sub(/\bIN:\s(\S+)/, %Q("\\1"))
+end
+
def line_current_word(line, point)
left = line.rindex(/\s/, point - 1) || 0; right = line.index(/\s/, point) || line.length
line[left..right]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>command</key>
+ <string>#!/usr/bin/env ruby
+require "#{ENV["TM_BUNDLE_SUPPORT"]}/lib/tm_factor"
+require ENV['TM_SUPPORT_PATH'] + '/lib/ui'
+
+a = TextMate::UI.request_string(:title => "Scaffold Setup", :prompt =>
+"Vocab Name:")
+b = ENV["TM_FILEPATH"]
+if b then c = b[/\/factor\/([^\/]+)\//,1]
+else c = "work"
+end
+factor_eval(%Q(USING: kernel editors tools.scaffold ; "#{a}" dup #{"scaffold-" << c} edit-vocab))</string>
+ <key>extension</key>
+ <string>factor</string>
+ <key>keyEquivalent</key>
+ <string>@N</string>
+ <key>name</key>
+ <string>Vocabulary</string>
+ <key>scope</key>
+ <string>source.factor</string>
+ <key>uuid</key>
+ <string>B6D1D91E-3EF3-4112-97DF-BFCABEBAA1C9</string>
+</dict>
+</plist>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>deleted</key>
+ <array/>
+ <key>mainMenu</key>
+ <dict>
+ <key>excludedItems</key>
+ <array>
+ <string>DBC0A0CA-5368-43A7-864B-7B9C4034AD08</string>
+ <string>1B3CF04D-B23D-4D9A-A648-7191315CDF96</string>
+ <string>3F17AF0F-4DE0-4A86-A649-CB65907F0DA5</string>
+ <string>B4448FB0-B7F9-4FFD-AB4B-EAD31A5920CB</string>
+ <string>C8E068DE-A117-43AE-9916-99AF2C21BD24</string>
+ <string>AD9D0A71-2371-4756-86D7-A084B4A3FE2F</string>
+ <string>8D69F968-D322-4008-A540-209B32A97F5D</string>
+ <string>B8B7B5ED-C75C-4BD1-906A-220C9956F91F</string>
+ <string>E51383D9-1C82-4ACE-AE45-633E6CE35245</string>
+ <string>3DE1C097-6F69-4562-9C49-C897FF5AB909</string>
+ <string>B9DA0999-D710-4693-8056-9E4B8BDAC7E9</string>
+ <string>7903894E-CB75-43ED-8635-C0E65F94DEBB</string>
+ <string>9A96D386-F7B9-47DC-9CAE-E4BAD1F81748</string>
+ <string>F771F82B-6B2B-4DAE-9A2A-E1042D3B08AD</string>
+ <string>275EA395-6026-481A-81C5-1F71D8026972</string>
+ </array>
+ <key>items</key>
+ <array>
+ <string>8088D204-FFD7-4384-8FDD-A01536FFD0E7</string>
+ <string>CAD3BB10-C480-4C0E-9518-94D61F7A0C0B</string>
+ <string>82E740D1-8D20-48AF-8470-C85C251D4870</string>
+ <string>D348BE40-6F51-4471-B300-DDDA70ED8C8C</string>
+ <string>9D99C141-EC9D-4C9E-9C08-0CA4EAEA2F3E</string>
+ <string>1C72489C-15A1-4B44-BCDF-438962D4F3EB</string>
+ <string>9E5EC5B6-AABD-4657-A663-D3C558051216</string>
+ <string>219C4AB2-742E-48FE-92E1-CB2EC19C8A24</string>
+ <string>D25BF2AE-0595-44AE-B97A-9F20D4E28173</string>
+ <string>93AF1721-C14D-428A-B5A0-34CEFAA3B3C5</string>
+ </array>
+ <key>submenus</key>
+ <dict>
+ <key>1C72489C-15A1-4B44-BCDF-438962D4F3EB</key>
+ <dict>
+ <key>items</key>
+ <array>
+ <string>3043A033-A113-4283-BCBB-3DE2CCC8F63E</string>
+ <string>B1F81321-B760-474F-875D-78FB52752E1B</string>
+ <string>BC3E2E39-3B79-460C-B05E-BD00BAACB90E</string>
+ </array>
+ <key>name</key>
+ <string>Cross Ref</string>
+ </dict>
+ <key>219C4AB2-742E-48FE-92E1-CB2EC19C8A24</key>
+ <dict>
+ <key>items</key>
+ <array>
+ <string>57C2BAAC-0474-404F-AA91-DFD02EC2A3ED</string>
+ <string>E4614756-DF2E-433A-8935-197159C67AB8</string>
+ <string>1C86869F-1030-4F74-B242-6357A080E127</string>
+ <string>71F08D9B-3D24-4E78-84C9-82CA736554D1</string>
+ </array>
+ <key>name</key>
+ <string>Debugging</string>
+ </dict>
+ <key>9D99C141-EC9D-4C9E-9C08-0CA4EAEA2F3E</key>
+ <dict>
+ <key>items</key>
+ <array>
+ <string>D02D9D74-E073-48AE-A78E-B40FFFA519D5</string>
+ <string>C573487C-DD7D-497F-A728-52D7962D95E2</string>
+ <string>D95A617C-E1C6-44DA-9126-04171CB21299</string>
+ <string>0034EC1C-DAD1-498F-82FD-BEF7015F84EE</string>
+ </array>
+ <key>name</key>
+ <string>Edit</string>
+ </dict>
+ <key>9E5EC5B6-AABD-4657-A663-D3C558051216</key>
+ <dict>
+ <key>items</key>
+ <array>
+ <string>7FF52332-CA5B-4D46-99EF-DAE0659DB478</string>
+ <string>15A984BD-BC65-43E8-878A-267788C8DA70</string>
+ <string>8E01DDAF-959B-4237-ADB9-C133A4ACCE90</string>
+ <string>B619FCC0-2DF2-4657-82A8-0E5676A10254</string>
+ <string>8465B33D-7CA0-4337-945C-4078346D64BC</string>
+ </array>
+ <key>name</key>
+ <string>Tools</string>
+ </dict>
+ <key>D25BF2AE-0595-44AE-B97A-9F20D4E28173</key>
+ <dict>
+ <key>items</key>
+ <array>
+ <string>35484754-DBF9-4381-BB25-00CAB64DF4A1</string>
+ <string>BC5BE120-734B-40DF-8B6B-5D3243614B27</string>
+ </array>
+ <key>name</key>
+ <string>Help</string>
+ </dict>
+ </dict>
+ </dict>
<key>name</key>
<string>Factor</string>
<key>ordering</key>
<array>
<string>3C9C9C2A-314A-475B-A4E4-A68BAAF3F36E</string>
+ <string>D60675B0-9BF4-4CCF-9066-CA14FE836981</string>
<string>141517D7-73E0-4475-A481-71102575A175</string>
+ <string>B6D1D91E-3EF3-4112-97DF-BFCABEBAA1C9</string>
<string>CAD3BB10-C480-4C0E-9518-94D61F7A0C0B</string>
+ <string>8088D204-FFD7-4384-8FDD-A01536FFD0E7</string>
<string>15A984BD-BC65-43E8-878A-267788C8DA70</string>
<string>8E01DDAF-959B-4237-ADB9-C133A4ACCE90</string>
<string>35484754-DBF9-4381-BB25-00CAB64DF4A1</string>
<string>BC5BE120-734B-40DF-8B6B-5D3243614B27</string>
<string>B619FCC0-2DF2-4657-82A8-0E5676A10254</string>
+ <string>DBC0A0CA-5368-43A7-864B-7B9C4034AD08</string>
+ <string>93AF1721-C14D-428A-B5A0-34CEFAA3B3C5</string>
+ <string>3043A033-A113-4283-BCBB-3DE2CCC8F63E</string>
+ <string>B1F81321-B760-474F-875D-78FB52752E1B</string>
+ <string>BC3E2E39-3B79-460C-B05E-BD00BAACB90E</string>
+ <string>8465B33D-7CA0-4337-945C-4078346D64BC</string>
+ <string>57C2BAAC-0474-404F-AA91-DFD02EC2A3ED</string>
+ <string>1C86869F-1030-4F74-B242-6357A080E127</string>
+ <string>E4614756-DF2E-433A-8935-197159C67AB8</string>
+ <string>D02D9D74-E073-48AE-A78E-B40FFFA519D5</string>
+ <string>C573487C-DD7D-497F-A728-52D7962D95E2</string>
+ <string>0034EC1C-DAD1-498F-82FD-BEF7015F84EE</string>
+ <string>D95A617C-E1C6-44DA-9126-04171CB21299</string>
+ <string>71F08D9B-3D24-4E78-84C9-82CA736554D1</string>
+ <string>7FF52332-CA5B-4D46-99EF-DAE0659DB478</string>
+ <string>D348BE40-6F51-4471-B300-DDDA70ED8C8C</string>
+ <string>1B3CF04D-B23D-4D9A-A648-7191315CDF96</string>
+ <string>3F17AF0F-4DE0-4A86-A649-CB65907F0DA5</string>
+ <string>F771F82B-6B2B-4DAE-9A2A-E1042D3B08AD</string>
+ <string>B4448FB0-B7F9-4FFD-AB4B-EAD31A5920CB</string>
+ <string>275EA395-6026-481A-81C5-1F71D8026972</string>
+ <string>C8E068DE-A117-43AE-9916-99AF2C21BD24</string>
+ <string>AD9D0A71-2371-4756-86D7-A084B4A3FE2F</string>
+ <string>8D69F968-D322-4008-A540-209B32A97F5D</string>
+ <string>B8B7B5ED-C75C-4BD1-906A-220C9956F91F</string>
+ <string>E51383D9-1C82-4ACE-AE45-633E6CE35245</string>
+ <string>3DE1C097-6F69-4562-9C49-C897FF5AB909</string>
+ <string>B9DA0999-D710-4693-8056-9E4B8BDAC7E9</string>
+ <string>7903894E-CB75-43ED-8635-C0E65F94DEBB</string>
+ <string>9A96D386-F7B9-47DC-9CAE-E4BAD1F81748</string>
+ <string>82E740D1-8D20-48AF-8470-C85C251D4870</string>
</array>
<key>uuid</key>
<string>8061D2F3-B603-411D-AFFE-61784A07906D</string>
--- /dev/null
+#!/bin/bash
+
+# change directories to a factor module
+function cdfactor {
+ code=$(printf "USING: io io.pathnames vocabs vocabs.loader ; "
+ printf "\"%s\" <vocab> vocab-source-path (normalize-path) print" $1)
+ echo $code > $HOME/.cdfactor
+ fn=$(factor $HOME/.cdfactor)
+ dn=$(dirname $fn)
+ echo $dn
+ if [ -z "$dn" ]; then
+ echo "Warning: directory '$1' not found" 1>&2
+ else
+ cd $dn
+ fi
+}
+
+
syn match factorComment /\<#! .*/ contains=factorTodo
syn match factorComment /\<! .*/ contains=factorTodo
-syn cluster factorDefnContents contains=@factorCluster,factorStackEffect,factorArray0,factorQuotation0
+syn cluster factorDefnContents contains=@factorCluster,factorStackEffect,factorLiteralStackEffect,factorArray0,factorQuotation0
-syn region factorDefn matchgroup=factorDefnDelims start=/\<\(MACRO\|MEMO\|:\)\?:\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
-syn region factorMethod matchgroup=factorMethodDelims start=/\<M:\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
+syn region factorDefn matchgroup=factorDefnDelims start=/\<\(SYNTAX\|\(MACRO\|MEMO\)\?:\?\):\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
+syn region factorMethod matchgroup=factorMethodDelims start=/\<M::\?\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
syn region factorGeneric matchgroup=factorGenericDelims start=/\<GENERIC:\s\+\S\+\>/ end=/$/ contains=factorStackEffect
syn region factorGenericN matchgroup=factorGenericNDelims start=/\<GENERIC#\s\+\S\+\s\+\d\+\>/ end=/$/ contains=factorStackEffect
-syn region factorPrivateDefn matchgroup=factorPrivateDefnDelims start=/\<\(MACRO\|MEMO\|:\)\?:\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
-syn region factorPrivateMethod matchgroup=factorPrivateMethodDelims start=/\<M:\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
+syn region factorPrivateDefn matchgroup=factorPrivateDefnDelims start=/\<\(SYNTAX\|\(MACRO\|MEMO\)\?:\?\):\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
+syn region factorPrivateMethod matchgroup=factorPrivateMethodDelims start=/\<M::\?\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
syn region factorPGeneric matchgroup=factorPGenericDelims start=/\<GENERIC:\s\+\S\+\>/ end=/$/ contains=factorStackEffect contained
syn region factorPGenericN matchgroup=factorPGenericNDelims start=/\<GENERIC#\s\+\S\+\s\+\d\+\>/ end=/$/ contains=factorStackEffect
syn keyword factorBoolean boolean f general-t t
-syn keyword factorCompileDirective inline foldable parsing
+syn keyword factorCompileDirective inline foldable recursive
<%
"syn match factorStackEffectErr /\<)\>/
"syn region factorStackEffectErr start=/\<(\>/ end=/\<)\>/
-syn region factorStackEffect start=/\<(\>/ end=/\<)\>/ contained
+"syn region factorStackEffect start=/\<(\>/ end=/\<)\>/ contained
+syn match factorStackEffect /\<( .*--.* )\>/ contained
+syn match factorLiteralStackEffect /\<(( .*--.* ))\>/
"adapted from lisp.vim
if exists("g:factor_norainbow")
- syn region factorQuotation matchgroup=factorDelimiter start=/\<\[\>/ matchgroup=factorDelimiter end=/\<\]\>/ contains=ALL
+ syn region factorQuotation matchgroup=factorDelimiter start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ matchgroup=factorDelimiter end=/\<\]\>/ contains=ALL
else
- syn region factorQuotation0 matchgroup=hlLevel0 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation1,factorArray1
- syn region factorQuotation1 contained matchgroup=hlLevel1 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation2,factorArray2
- syn region factorQuotation2 contained matchgroup=hlLevel2 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation3,factorArray3
- syn region factorQuotation3 contained matchgroup=hlLevel3 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation4,factorArray4
- syn region factorQuotation4 contained matchgroup=hlLevel4 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation5,factorArray5
- syn region factorQuotation5 contained matchgroup=hlLevel5 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation6,factorArray6
- syn region factorQuotation6 contained matchgroup=hlLevel6 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation7,factorArray7
- syn region factorQuotation7 contained matchgroup=hlLevel7 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation8,factorArray8
- syn region factorQuotation8 contained matchgroup=hlLevel8 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation9,factorArray9
- syn region factorQuotation9 contained matchgroup=hlLevel9 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation0,factorArray0
+ syn region factorQuotation0 matchgroup=hlLevel0 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation1,factorArray1
+ syn region factorQuotation1 contained matchgroup=hlLevel1 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation2,factorArray2
+ syn region factorQuotation2 contained matchgroup=hlLevel2 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation3,factorArray3
+ syn region factorQuotation3 contained matchgroup=hlLevel3 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation4,factorArray4
+ syn region factorQuotation4 contained matchgroup=hlLevel4 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation5,factorArray5
+ syn region factorQuotation5 contained matchgroup=hlLevel5 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation6,factorArray6
+ syn region factorQuotation6 contained matchgroup=hlLevel6 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation7,factorArray7
+ syn region factorQuotation7 contained matchgroup=hlLevel7 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation8,factorArray8
+ syn region factorQuotation8 contained matchgroup=hlLevel8 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation9,factorArray9
+ syn region factorQuotation9 contained matchgroup=hlLevel9 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation0,factorArray0
endif
if exists("g:factor_norainbow")
- syn region factorArray matchgroup=factorDelimiter start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ matchgroup=factorDelimiter end=/\<}\>/ contains=ALL
+ syn region factorArray matchgroup=factorDelimiter start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ matchgroup=factorDelimiter end=/\<}\>/ contains=ALL
else
- syn region factorArray0 matchgroup=hlLevel0 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray1,factorQuotation1
- syn region factorArray1 contained matchgroup=hlLevel1 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray2,factorQuotation2
- syn region factorArray2 contained matchgroup=hlLevel2 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray3,factorQuotation3
- syn region factorArray3 contained matchgroup=hlLevel3 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray4,factorQuotation4
- syn region factorArray4 contained matchgroup=hlLevel4 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray5,factorQuotation5
- syn region factorArray5 contained matchgroup=hlLevel5 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray6,factorQuotation6
- syn region factorArray6 contained matchgroup=hlLevel6 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray7,factorQuotation7
- syn region factorArray7 contained matchgroup=hlLevel7 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray8,factorQuotation8
- syn region factorArray8 contained matchgroup=hlLevel8 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray9,factorQuotation9
- syn region factorArray9 contained matchgroup=hlLevel9 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray0,factorQuotation0
+ syn region factorArray0 matchgroup=hlLevel0 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray1,factorQuotation1
+ syn region factorArray1 contained matchgroup=hlLevel1 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray2,factorQuotation2
+ syn region factorArray2 contained matchgroup=hlLevel2 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray3,factorQuotation3
+ syn region factorArray3 contained matchgroup=hlLevel3 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray4,factorQuotation4
+ syn region factorArray4 contained matchgroup=hlLevel4 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray5,factorQuotation5
+ syn region factorArray5 contained matchgroup=hlLevel5 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray6,factorQuotation6
+ syn region factorArray6 contained matchgroup=hlLevel6 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray7,factorQuotation7
+ syn region factorArray7 contained matchgroup=hlLevel7 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray8,factorQuotation8
+ syn region factorArray8 contained matchgroup=hlLevel8 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray9,factorQuotation9
+ syn region factorArray9 contained matchgroup=hlLevel9 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray0,factorQuotation0
endif
syn match factorBracketErr /\<\]\>/
HiLink factorComment Comment
HiLink factorStackEffect Typedef
+ HiLink factorLiteralStackEffect Typedef
HiLink factorTodo Todo
HiLink factorInclude Include
HiLink factorRepeat Repeat
let b:current_syntax = "factor"
set sw=4
-set ts=4
+set sts=4
set expandtab
set autoindent " annoying?
(beginning-of-line)
(when (fuel-syntax--at-begin-of-def) 0)))
+(defsubst factor-mode--previous-non-empty ()
+ (forward-line -1)
+ (while (and (not (bobp))
+ (fuel-syntax--looking-at-emptiness))
+ (forward-line -1)))
+
(defun factor-mode--indent-setter-line ()
(when (fuel-syntax--at-setter-line)
- (save-excursion
- (let ((indent (and (fuel-syntax--at-constructor-line) (current-indentation))))
- (while (not (or indent
- (bobp)
- (fuel-syntax--at-begin-of-def)
- (fuel-syntax--at-end-of-def)))
- (if (fuel-syntax--at-constructor-line)
- (setq indent (fuel-syntax--increased-indentation))
- (forward-line -1)))
- indent))))
+ (or (save-excursion
+ (let ((indent (and (fuel-syntax--at-constructor-line)
+ (current-indentation))))
+ (while (not (or indent
+ (bobp)
+ (fuel-syntax--at-begin-of-def)
+ (fuel-syntax--at-end-of-def)))
+ (if (fuel-syntax--at-constructor-line)
+ (setq indent (fuel-syntax--increased-indentation))
+ (forward-line -1)))
+ indent))
+ (save-excursion
+ (factor-mode--previous-non-empty)
+ (current-indentation)))))
(defun factor-mode--indent-continuation ()
(save-excursion
- (forward-line -1)
- (while (and (not (bobp))
- (fuel-syntax--looking-at-emptiness))
- (forward-line -1))
+ (factor-mode--previous-non-empty)
(cond ((or (fuel-syntax--at-end-of-def)
(fuel-syntax--at-setter-line))
(fuel-syntax--decreased-indentation))
(defsubst factor-mode--cycling-setup ()
(setq factor-mode--cycling-no-ask nil))
+(defun factor-mode--code-file (kind &optional file)
+ (let* ((file (or file (buffer-file-name)))
+ (bn (file-name-nondirectory file)))
+ (and (string-match (format "\\(.+\\)-%s\\.factor$" kind) bn)
+ (expand-file-name (concat (match-string 1 bn) ".factor")
+ (file-name-directory file)))))
+
+(defsubst factor-mode--in-docs (&optional file)
+ (factor-mode--code-file "docs"))
+
+(defsubst factor-mode--in-tests (&optional file)
+ (factor-mode--code-file "tests"))
+
(defun factor-mode-visit-other-file (&optional skip)
"Cycle between code, tests and docs factor files.
With prefix, non-existing files will be skipped."
;;; fuel-log.el -- logging utilities
-;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; Copyright (C) 2008, 2009 Jose Antonio Ortega Ruiz
;; See http://factorcode.org/license.txt for BSD license.
;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
(defvar fuel-log--inhibit-p nil
"Set this to t to inhibit all log messages")
+(defvar fuel-log--debug-p nil
+ "If t, all messages are logged no matter what")
+
(define-derived-mode factor-messages-mode fundamental-mode "FUEL Messages"
"Simple mode to log interactions with the factor listener"
(kill-all-local-variables)
(current-buffer))))
(defun fuel-log--msg (type &rest args)
- (unless fuel-log--inhibit-p
+ (when (or fuel-log--debug-p (not fuel-log--inhibit-p))
(with-current-buffer (fuel-log--buffer)
(let ((inhibit-read-only t))
(insert
(when (looking-at "Word *\\(Stack effect\\|Syntax\\)$")
(push (list "Word" (match-string-no-properties 1)) rows)
(forward-line))
- (while (looking-at "\\(.+?\\)\\( +\\(.+\\)\\)?$")
+ (while (looking-at " ?\\(.+?\\)\\( +\\(.+\\)\\)?$")
(let ((word `($link ,(match-string-no-properties 1)
,(match-string-no-properties 1)
word))
(when fuel-mode-autodoc-p (fuel-autodoc-mode fuel-mode))
(setq fuel-stack-mode-string "/S")
- (when fuel-mode-stack-p (fuel-stack-mode fuel-mode)))
+ (when fuel-mode-stack-p (fuel-stack-mode fuel-mode))
+
+ (when (and fuel-mode (not (file-exists-p (buffer-file-name))))
+ (fuel-scaffold--maybe-insert)))
\f
;;; Keys:
(let ((cmd '(:fuel* (vocab-roots get :get) "fuel")))
(fuel-eval--retort-result (fuel-eval--send/wait cmd))))
+(defun fuel-scaffold--dev-name ()
+ (or fuel-scaffold-developer-name
+ (let ((cmd '(:fuel* (developer-name get :get) "fuel")))
+ (fuel-eval--retort-result (fuel-eval--send/wait cmd)))
+ "Your name"))
+
+(defun fuel-scaffold--first-vocab ()
+ (goto-char (point-min))
+ (re-search-forward fuel-syntax--current-vocab-regex nil t))
+
+(defsubst fuel-scaffold--vocab (file)
+ (save-excursion
+ (set-buffer (find-file-noselect file))
+ (fuel-scaffold--first-vocab)
+ (fuel-syntax--current-vocab)))
+
+(defconst fuel-scaffold--tests-header-format
+ "! Copyright (C) %s %s
+! See http://factorcode.org/license.txt for BSD license.
+USING: %s tools.test ;
+IN: %s
+")
+
+(defsubst fuel-scaffold--check-auto (var)
+ (and var (or (eq var 'always) (y-or-n-p "Insert template? "))))
+
+(defun fuel-scaffold--tests (parent)
+ (when (and parent (fuel-scaffold--check-auto fuel-scaffold-test-autoinsert-p))
+ (let ((year (format-time-string "%Y"))
+ (name (fuel-scaffold--dev-name))
+ (vocab (fuel-scaffold--vocab parent)))
+ (insert (format fuel-scaffold--tests-header-format
+ year name vocab vocab))
+ t)))
+
+(defsubst fuel-scaffold--create-docs (vocab)
+ (let ((cmd `(:fuel* (,vocab ,fuel-scaffold-developer-name fuel-scaffold-help)
+ "fuel")))
+ (fuel-eval--send/wait cmd)))
+
+(defun fuel-scaffold--help (parent)
+ (when (and parent (fuel-scaffold--check-auto fuel-scaffold-help-autoinsert-p))
+ (let* ((ret (fuel-scaffold--create-docs (fuel-scaffold--vocab parent)))
+ (file (fuel-eval--retort-result ret)))
+ (when file
+ (revert-buffer t t t)
+ (when (and fuel-scaffold-help-header-only-p
+ (fuel-scaffold--first-vocab))
+ (delete-region (1+ (point)) (point-max))
+ (save-buffer))
+ (message "Inserting template ... done."))
+ (goto-char (point-min)))))
+
+(defun fuel-scaffold--maybe-insert ()
+ (ignore-errors
+ (or (fuel-scaffold--tests (factor-mode--in-tests))
+ (fuel-scaffold--help (factor-mode--in-docs)))))
+
\f
;;; User interface:
(interactive "P")
(let* ((vocab (or (and (not arg) (fuel-syntax--current-vocab))
(fuel-completion--read-vocab nil)))
- (cmd `(:fuel* (,vocab ,fuel-scaffold-developer-name fuel-scaffold-help)
- "fuel"))
- (ret (fuel-eval--send/wait cmd))
+ (ret (fuel-scaffold--create-docs vocab))
(file (fuel-eval--retort-result ret)))
(unless file
(error "Error creating help file" (car (fuel-eval--retort-error ret))))
"HELP:" "HEX:" "HOOK:"
"IN:" "initial:" "INSTANCE:" "INTERSECTION:"
"LIBRARY:"
- "M:" "MACRO:" "MACRO::" "MAIN:" "MATH:" "MEMO:" "MEMO:" "METHOD:" "MIXIN:"
+ "M:" "M::" "MACRO:" "MACRO::" "MAIN:" "MATH:"
+ "MEMO:" "MEMO:" "METHOD:" "MIXIN:"
"OCT:"
"POSTPONE:" "PREDICATE:" "PRIMITIVE:" "PRIVATE>" "PROVIDE:"
"QUALIFIED-WITH:" "QUALIFIED:"
(format "%s +\\([^ \r\n]+\\)" (regexp-opt prefixes t)))
(defconst fuel-syntax--method-definition-regex
- "^M: +\\([^ ]+\\) +\\([^ ]+\\)")
+ "^M::? +\\([^ ]+\\) +\\([^ ]+\\)")
(defconst fuel-syntax--integer-regex
"\\_<-?[0-9]+\\_>")
"C-ENUM" "C-STRUCT" "C-UNION"
"FROM" "FUNCTION:"
"INTERSECTION:"
- "M" "MACRO" "MACRO:"
+ "M" "M:" "MACRO" "MACRO:"
"MEMO" "MEMO:" "METHOD"
"SYNTAX"
"PREDICATE" "PRIMITIVE"
(format ":[^ ]* \\([^ ]+\\)\\(%s\\)*" fuel-syntax--stack-effect-regex))
(defconst fuel-syntax--defun-signature-regex
- (format "\\(%s\\|%s\\)" fuel-syntax--word-signature-regex "M[^:]*: [^ ]+ [^ ]+"))
+ (format "\\(%s\\|%s\\)"
+ fuel-syntax--word-signature-regex
+ "M[^:]*: [^ ]+ [^ ]+"))
(defconst fuel-syntax--constructor-decl-regex
"\\_<C: +\\(\\w+\\) +\\(\\w+\\)\\( .*\\)?$")
("\\_<\\(}\\)\\_>" (1 "){"))
;; Parenthesis:
("\\_<\\((\\)\\_>" (1 "()"))
- ("\\_<call\\((\\)\\_>" (1 "()"))
+ ("\\_<\\w*\\((\\)\\_>" (1 "()"))
("\\_<\\()\\)\\_>" (1 ")("))
("\\_<(\\((\\)\\_>" (1 "()"))
("\\_<\\()\\))\\_>" (1 ")("))
(push (fuel-table--pad-row (reverse frow)) frows)))
(reverse frows)))
+(defvar fuel-table-corner-lt "┌")
+(defvar fuel-table-corner-lb "└")
+(defvar fuel-table-corner-rt "┐")
+(defvar fuel-table-corner-rb "┘")
+(defvar fuel-table-line "─")
+(defvar fuel-table-tee-t "┬")
+(defvar fuel-table-tee-b "┴")
+(defvar fuel-table-tee-l "├")
+(defvar fuel-table-tee-r "┤")
+(defvar fuel-table-crux "┼")
+(defvar fuel-table-sep "│")
+
+(defun fuel-table--insert-line (widths first last sep)
+ (insert first fuel-table-line)
+ (dolist (w widths)
+ (while (> w 0)
+ (insert fuel-table-line)
+ (setq w (1- w)))
+ (insert fuel-table-line sep fuel-table-line))
+ (delete-char -2)
+ (insert fuel-table-line last)
+ (newline))
+
+(defun fuel-table--insert-first-line (widths)
+ (fuel-table--insert-line widths
+ fuel-table-corner-lt
+ fuel-table-corner-rt
+ fuel-table-tee-t))
+
+(defun fuel-table--insert-middle-line (widths)
+ (fuel-table--insert-line widths
+ fuel-table-tee-l
+ fuel-table-tee-r
+ fuel-table-crux))
+
+(defun fuel-table--insert-last-line (widths)
+ (fuel-table--insert-line widths
+ fuel-table-corner-lb
+ fuel-table-corner-rb
+ fuel-table-tee-b))
+
+(defun fuel-table--insert-row (r)
+ (let ((ln (length (car r)))
+ (l 0))
+ (while (< l ln)
+ (insert (concat fuel-table-sep " "
+ (mapconcat 'identity
+ (mapcar `(lambda (x) (nth ,l x)) r)
+ (concat " " fuel-table-sep " "))
+ " " fuel-table-sep "\n"))
+ (setq l (1+ l)))))
+
(defun fuel-table--insert (rows)
(let* ((widths (fuel-table--col-widths rows))
- (rows (fuel-table--format-rows rows widths))
- (ls (concat "+" (mapconcat (lambda (n) (make-string n ?-)) widths "-+") "-+")))
- (insert ls "\n")
+ (rows (fuel-table--format-rows rows widths)))
+ (fuel-table--insert-first-line widths)
(dolist (r rows)
- (let ((ln (length (car r)))
- (l 0))
- (while (< l ln)
- (insert (concat "|" (mapconcat 'identity
- (mapcar `(lambda (x) (nth ,l x)) r)
- " |")
- " |\n"))
- (setq l (1+ l))))
- (insert ls "\n"))))
+ (fuel-table--insert-row r)
+ (fuel-table--insert-middle-line widths))
+ (kill-line -1)
+ (fuel-table--insert-last-line widths)))
\f
(provide 'fuel-table)
names of all the vocabularies Factor knows about. To regenerate it manually,
run the following code in the listener:
- USE: editors.vim.generate-syntax
-
- generate-vim-syntax
+ "editors.vim.generate-syntax" run
...or run it from the command-line:
+
" Vim syntax file
" Language: factor
" Maintainer: Alex Chapman <chapman.alex@gmail.com>
syn match factorComment /\<#! .*/ contains=factorTodo
syn match factorComment /\<! .*/ contains=factorTodo
-syn cluster factorDefnContents contains=@factorCluster,factorStackEffect,factorArray0,factorQuotation0
+syn cluster factorDefnContents contains=@factorCluster,factorStackEffect,factorLiteralStackEffect,factorArray0,factorQuotation0
-syn region factorDefn matchgroup=factorDefnDelims start=/\<\(MACRO\|MEMO\|:\)\?:\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
-syn region factorMethod matchgroup=factorMethodDelims start=/\<M:\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
+syn region factorDefn matchgroup=factorDefnDelims start=/\<\(SYNTAX\|\(MACRO\|MEMO\)\?:\?\):\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
+syn region factorMethod matchgroup=factorMethodDelims start=/\<M::\?\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents
syn region factorGeneric matchgroup=factorGenericDelims start=/\<GENERIC:\s\+\S\+\>/ end=/$/ contains=factorStackEffect
syn region factorGenericN matchgroup=factorGenericNDelims start=/\<GENERIC#\s\+\S\+\s\+\d\+\>/ end=/$/ contains=factorStackEffect
-syn region factorPrivateDefn matchgroup=factorPrivateDefnDelims start=/\<\(MACRO\|MEMO\|:\)\?:\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
-syn region factorPrivateMethod matchgroup=factorPrivateMethodDelims start=/\<M:\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
+syn region factorPrivateDefn matchgroup=factorPrivateDefnDelims start=/\<\(SYNTAX\|\(MACRO\|MEMO\)\?:\?\):\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
+syn region factorPrivateMethod matchgroup=factorPrivateMethodDelims start=/\<M::\?\s\+\S\+\s\+\S\+\>/ end=/\<;\>/ contains=@factorDefnContents contained
syn region factorPGeneric matchgroup=factorPGenericDelims start=/\<GENERIC:\s\+\S\+\>/ end=/$/ contains=factorStackEffect contained
syn region factorPGenericN matchgroup=factorPGenericNDelims start=/\<GENERIC#\s\+\S\+\s\+\d\+\>/ end=/$/ contains=factorStackEffect
syn keyword factorBoolean boolean f general-t t
-syn keyword factorCompileDirective inline foldable parsing
+syn keyword factorCompileDirective inline foldable recursive
syn keyword factorKeyword or tuck 2bi 2tri while wrapper nip 4dip wrapper? bi* callstack>array both? hashcode die dupd callstack callstack? 3dup tri@ pick curry build ?execute 3bi prepose >boolean ?if clone eq? tri* ? = swapd call-clear 2over 2keep 3keep clear 2dup when not tuple? dup 2bi* 2tri* call tri-curry object bi@ do unless* if* loop bi-curry* drop when* assert= retainstack assert? -rot execute 2bi@ 2tri@ boa with either? 3drop bi curry? datastack until 3dip over 3curry roll tri-curry* swap tri-curry@ 2nip and throw set-retainstack bi-curry (clone) hashcode* compose spin 2dip if 3tri unless compose? tuple keep 2curry equal? set-datastack assert tri 2drop most <wrapper> boolean? identity-tuple? null new set-callstack dip bi-curry@ rot -roll xor identity-tuple boolean
-syn keyword factorKeyword ?at assoc? assoc-clone-like assoc= delete-at* assoc-partition extract-keys new-assoc value? assoc-size map>assoc push-at assoc-like key? assoc-intersect update assoc-union assoc-combine at* assoc-empty? at+ set-at assoc-all? assoc-subset? assoc-hashcode change-at assoc-each assoc-diff zip values value-at rename-at inc-at enum? at cache assoc>map <enum> assoc assoc-map enum value-at* remove-all assoc-map-as >alist assoc-filter-as substitute-here clear-assoc assoc-stack substitute assoc-filter 2cache delete-at assoc-find keys assoc-any? unzip
-syn keyword factorKeyword case execute-effect dispatch-case-quot <buckets> no-cond no-case? 3cleave>quot contiguous-range? 2cleave cond>quot wrong-values? no-cond? cleave>quot no-case hash-dispatch-quot case>quot 3cleave wrong-values alist>quot hash-case-table hash-case-quot case-find (distribute-buckets) cond cleave distribute-buckets call-effect 2cleave>quot recursive-hashcode linear-case-quot spread spread>quot
-syn keyword factorKeyword byte-array>bignum sgn >bignum next-float number= each-integer next-power-of-2 ?1+ fp-special? imaginary-part mod recip float>bits rational >float number? 2^ bignum? integer fixnum? neg fixnum sq bignum fp-snan? fp-infinity? denominator (all-integers?) times find-last-integer (each-integer) bit? * + fp-bitwise= - fp-qnan? / power-of-2? >= bitand find-integer complex <fp-nan> < log2 > integer? real number bits>double double>bits bitor 2/ zero? rem fp-nan-payload all-integers? (find-integer) real-part prev-float align bits>float float? shift float 1+ 1- fp-nan? abs bitxor ratio? even? <= /mod odd? >integer ratio rational? bitnot real? >fixnum complex? /i numerator /f
-syn keyword factorKeyword append assert-sequence= find-last-from trim-head-slice clone-like 3sequence assert-sequence? map-as filter-here last-index-from prepare-index reversed index-from cut* pad-tail (indices) concat-as remq but-last snip trim-tail nths nth 2pusher sequence slice? <slice> partition remove-nth tail-slice empty? tail* if-empty find-from virtual-sequence? member? set-length delq drop-prefix unclip iota unclip-last-slice bounds-error? sequence-hashcode-step map start midpoint@ rest-slice prepend fourth sift delete sigma new-sequence follow like delete-nth first4 1sequence reverse slice unless-empty padding virtual@ repetition? index 4sequence max-length set-second immutable-sequence first2 first3 replicate-as reduce-index unclip-slice supremum insert-nth trim-tail-slice tail 3append short count suffix concat flip filter sum immutable? 2sequence delete-all start* indices snip-slice check-slice sequence? head map-find reduce append-as reverse-here sequence= halves collapse-slice interleave 2map binary-reduce virtual-seq slice-error? product bounds-check? bounds-check harvest immutable find produce remove pad-head replicate set-fourth peek shorten reversed? map-find-last 3map-as 2unclip-slice shorter? 3map find-last head-slice pop* 2map-as tail-slice* but-last-slice 2map-reduce iota? accumulate each pusher cut-slice new-resizable each-index head-slice* 2reverse-each sequence-hashcode memq? pop set-nth ?nth <flat-slice> second change-each join when-empty accumulator immutable-sequence? <reversed> all? 3append-as virtual-sequence subseq? push-either new-like length last-index push-if 2all? lengthen assert-sequence copy map-reduce move third first 3each tail? set-first prefix bounds-error any? <repetition> trim-slice exchange surround 2reduce cut change-nth min-length set-third produce-as push-all head? delete-slice rest sum-lengths 2each head* infimum glue slice-error subseq replace-slice push repetition map-index trim-head unclip-last mismatch trim
+syn keyword factorKeyword ?at assoc? assoc-clone-like assoc= delete-at* assoc-partition extract-keys new-assoc value? assoc-size map>assoc push-at assoc-like key? assoc-intersect assoc-refine update assoc-union assoc-combine at* assoc-empty? at+ set-at assoc-all? assoc-subset? assoc-hashcode change-at assoc-each assoc-diff zip values value-at rename-at inc-at enum? at cache assoc>map <enum> assoc assoc-map enum value-at* remove-all assoc-map-as >alist assoc-filter-as substitute-here clear-assoc assoc-stack maybe-set-at substitute assoc-filter 2cache delete-at assoc-find keys assoc-any? unzip
+syn keyword factorKeyword case execute-effect no-cond no-case? 3cleave>quot 2cleave cond>quot wrong-values? no-cond? cleave>quot no-case case>quot 3cleave wrong-values to-fixed-point alist>quot case-find cond cleave call-effect 2cleave>quot recursive-hashcode linear-case-quot spread spread>quot
+syn keyword factorKeyword byte-array>bignum sgn >bignum next-float number= each-integer next-power-of-2 ?1+ fp-special? imaginary-part mod recip float>bits rational >float number? 2^ bignum? integer fixnum? neg fixnum sq bignum fp-snan? fp-infinity? denominator (all-integers?) times find-last-integer (each-integer) bit? * + fp-bitwise= - fp-qnan? / power-of-2? >= bitand find-integer complex <fp-nan> < log2 > integer? real number bits>double double>bits bitor 2/ zero? rem fp-nan-payload all-integers? (find-integer) real-part prev-float align bits>float float? shift float fp-nan? abs bitxor ratio? even? <= /mod odd? >integer ratio rational? bitnot real? >fixnum complex? /i numerator /f
+syn keyword factorKeyword append assert-sequence= find-last-from trim-head-slice clone-like 3sequence assert-sequence? map-as filter-here last-index-from reversed index-from cut* pad-tail (indices) concat-as remq but-last snip trim-tail nths nth 2pusher sequence slice? <slice> partition remove-nth tail-slice empty? tail* if-empty find-from virtual-sequence? member? set-length delq drop-prefix unclip iota unclip-last-slice bounds-error? sequence-hashcode-step map start midpoint@ rest-slice prepend fourth sift delete sigma new-sequence follow like delete-nth first4 1sequence reverse slice unless-empty padding virtual@ repetition? set-last index 4sequence max-length set-second immutable-sequence first2 first3 replicate-as reduce-index unclip-slice supremum insert-nth trim-tail-slice tail 3append short count suffix concat flip filter sum immutable? 2sequence map-integers delete-all start* indices snip-slice check-slice sequence? head map-find reduce append-as reverse-here sequence= halves collapse-slice interleave 2map binary-reduce virtual-seq slice-error? product bounds-check? bounds-check harvest immutable find produce remove pad-head last replicate set-fourth shorten reversed? map-find-last 3map-as 2unclip-slice shorter? 3map find-last head-slice pop* 2map-as tail-slice* but-last-slice 2map-reduce iota? accumulate each pusher cut-slice new-resizable each-index head-slice* 2reverse-each sequence-hashcode memq? pop set-nth ?nth <flat-slice> second change-each join when-empty accumulator immutable-sequence? <reversed> all? 3append-as virtual-sequence subseq? push-either new-like length last-index push-if 2all? lengthen assert-sequence copy map-reduce move third first 3each tail? set-first prefix bounds-error any? <repetition> trim-slice exchange surround 2reduce cut change-nth min-length set-third produce-as push-all head? delete-slice rest sum-lengths 2each head* infimum glue slice-error subseq replace-slice push repetition map-index trim-head unclip-last mismatch trim
syn keyword factorKeyword global +@ change set-namestack change-global init-namespaces on off set-global namespace set with-scope bind with-variable inc dec counter initialize namestack get get-global make-assoc
syn keyword factorKeyword <array> 2array 3array pair >array 1array 4array pair? array resize-array array?
syn keyword factorKeyword +character+ bad-seek-type? readln stream-seek read print with-output-stream contents write1 stream-write1 stream-copy stream-element-type with-input-stream stream-print stream-read stream-contents bl seek-output bad-seek-type nl stream-nl write flush stream-lines +byte+ stream-flush read1 seek-absolute? stream-read1 lines stream-readln stream-read-until each-line seek-end with-output-stream* seek-absolute with-streams seek-input seek-relative? input-stream stream-write read-partial seek-end? seek-relative error-stream read-until with-input-stream* with-streams* each-block output-stream stream-read-partial
"syn match factorStackEffectErr /\<)\>/
"syn region factorStackEffectErr start=/\<(\>/ end=/\<)\>/
-syn region factorStackEffect start=/\<(\>/ end=/\<)\>/ contained
+"syn region factorStackEffect start=/\<(\>/ end=/\<)\>/ contained
+syn match factorStackEffect /\<( .*--.* )\>/ contained
+syn match factorLiteralStackEffect /\<(( .*--.* ))\>/
"adapted from lisp.vim
if exists("g:factor_norainbow")
- syn region factorQuotation matchgroup=factorDelimiter start=/\<\[\>/ matchgroup=factorDelimiter end=/\<\]\>/ contains=ALL
+ syn region factorQuotation matchgroup=factorDelimiter start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ matchgroup=factorDelimiter end=/\<\]\>/ contains=ALL
else
- syn region factorQuotation0 matchgroup=hlLevel0 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation1,factorArray1
- syn region factorQuotation1 contained matchgroup=hlLevel1 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation2,factorArray2
- syn region factorQuotation2 contained matchgroup=hlLevel2 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation3,factorArray3
- syn region factorQuotation3 contained matchgroup=hlLevel3 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation4,factorArray4
- syn region factorQuotation4 contained matchgroup=hlLevel4 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation5,factorArray5
- syn region factorQuotation5 contained matchgroup=hlLevel5 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation6,factorArray6
- syn region factorQuotation6 contained matchgroup=hlLevel6 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation7,factorArray7
- syn region factorQuotation7 contained matchgroup=hlLevel7 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation8,factorArray8
- syn region factorQuotation8 contained matchgroup=hlLevel8 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation9,factorArray9
- syn region factorQuotation9 contained matchgroup=hlLevel9 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation0,factorArray0
+ syn region factorQuotation0 matchgroup=hlLevel0 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation1,factorArray1
+ syn region factorQuotation1 contained matchgroup=hlLevel1 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation2,factorArray2
+ syn region factorQuotation2 contained matchgroup=hlLevel2 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation3,factorArray3
+ syn region factorQuotation3 contained matchgroup=hlLevel3 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation4,factorArray4
+ syn region factorQuotation4 contained matchgroup=hlLevel4 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation5,factorArray5
+ syn region factorQuotation5 contained matchgroup=hlLevel5 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation6,factorArray6
+ syn region factorQuotation6 contained matchgroup=hlLevel6 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation7,factorArray7
+ syn region factorQuotation7 contained matchgroup=hlLevel7 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation8,factorArray8
+ syn region factorQuotation8 contained matchgroup=hlLevel8 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation9,factorArray9
+ syn region factorQuotation9 contained matchgroup=hlLevel9 start=/\<\(\('\|\$\|\)\[\)\|\[\(let\||\)\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation0,factorArray0
endif
if exists("g:factor_norainbow")
- syn region factorArray matchgroup=factorDelimiter start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ matchgroup=factorDelimiter end=/\<}\>/ contains=ALL
+ syn region factorArray matchgroup=factorDelimiter start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ matchgroup=factorDelimiter end=/\<}\>/ contains=ALL
else
- syn region factorArray0 matchgroup=hlLevel0 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray1,factorQuotation1
- syn region factorArray1 contained matchgroup=hlLevel1 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray2,factorQuotation2
- syn region factorArray2 contained matchgroup=hlLevel2 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray3,factorQuotation3
- syn region factorArray3 contained matchgroup=hlLevel3 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray4,factorQuotation4
- syn region factorArray4 contained matchgroup=hlLevel4 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray5,factorQuotation5
- syn region factorArray5 contained matchgroup=hlLevel5 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray6,factorQuotation6
- syn region factorArray6 contained matchgroup=hlLevel6 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray7,factorQuotation7
- syn region factorArray7 contained matchgroup=hlLevel7 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray8,factorQuotation8
- syn region factorArray8 contained matchgroup=hlLevel8 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray9,factorQuotation9
- syn region factorArray9 contained matchgroup=hlLevel9 start=/\<\(V\|H\|T\|W\|F\|B\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray0,factorQuotation0
+ syn region factorArray0 matchgroup=hlLevel0 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray1,factorQuotation1
+ syn region factorArray1 contained matchgroup=hlLevel1 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray2,factorQuotation2
+ syn region factorArray2 contained matchgroup=hlLevel2 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray3,factorQuotation3
+ syn region factorArray3 contained matchgroup=hlLevel3 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray4,factorQuotation4
+ syn region factorArray4 contained matchgroup=hlLevel4 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray5,factorQuotation5
+ syn region factorArray5 contained matchgroup=hlLevel5 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray6,factorQuotation6
+ syn region factorArray6 contained matchgroup=hlLevel6 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray7,factorQuotation7
+ syn region factorArray7 contained matchgroup=hlLevel7 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray8,factorQuotation8
+ syn region factorArray8 contained matchgroup=hlLevel8 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray9,factorQuotation9
+ syn region factorArray9 contained matchgroup=hlLevel9 start=/\<\(V\|H\|T\|W\|F\|B\|\$\)\?{\>/ end=/\<}\>/ contains=@factorCluster,factorArray0,factorQuotation0
endif
syn match factorBracketErr /\<\]\>/
HiLink factorComment Comment
HiLink factorStackEffect Typedef
+ HiLink factorLiteralStackEffect Typedef
HiLink factorTodo Todo
HiLink factorInclude Include
HiLink factorRepeat Repeat
let b:current_syntax = "factor"
set sw=4
-set ts=4
+set sts=4
set expandtab
set autoindent " annoying?
" vim: syntax=vim
+
--- /dev/null
+Kobi Lurie
+Doug Coleman
--- /dev/null
+! Copyright (C) 2009 Kobi Lurie, Doug Coleman.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+USING: accessors fry images.loader\r
+images.processing.rotation kernel literals math sequences\r
+tools.test images.processing.rotation.private ;\r
+IN: images.processing.rotation.tests\r
+\r
+: first-row ( seq^2 -- seq ) first ;\r
+: first-col ( seq^2 -- item ) harvest [ first ] map ;\r
+: last-row ( seq^2 -- item ) last ;\r
+: last-col ( seq^2 -- item ) harvest [ last ] map ;\r
+: end-of-first-row ( seq^2 -- item ) first-row last ;\r
+: first-of-first-row ( seq^2 -- item ) first-row first ;\r
+: end-of-last-row ( seq^2 -- item ) last-row last ;\r
+: first-of-last-row ( seq^2 -- item ) last-row first ;\r
+\r
+<<\r
+\r
+: clone-image ( image -- new-image )\r
+ clone [ clone ] change-bitmap ;\r
+\r
+>>\r
+\r
+: pasted-image ( -- image )\r
+ "vocab:images/processing/rotation/test-bitmaps/PastedImage.bmp"\r
+ load-image clone-image ;\r
+\r
+: pasted-image90 ( -- image )\r
+ "vocab:images/processing/rotation/test-bitmaps/PastedImage90.bmp"\r
+ load-image clone-image ;\r
+\r
+: lake-image ( -- image )\r
+ "vocab:images/processing/rotation/test-bitmaps/lake.bmp"\r
+ load-image clone-image image>pixel-rows ;\r
+\r
+[ t ] [ pasted-image dup clone-image 4 [ 90 rotate ] times = ] unit-test\r
+[ t ] [ pasted-image dup clone-image 2 [ 180 rotate ] times = ] unit-test\r
+[ t ] [ pasted-image dup clone-image 270 rotate 90 rotate = ] unit-test\r
+[ t ] [\r
+ pasted-image dup clone-image dup { 90 180 90 } [ rotate drop ] with each =\r
+] unit-test\r
+\r
+[ t ] [\r
+ pasted-image 90 rotate\r
+ pasted-image90 = \r
+] unit-test\r
+\r
+[ t ] [\r
+ "vocab:images/processing/rotation/test-bitmaps/small.bmp"\r
+ load-image 90 rotate \r
+ "vocab:images/processing/rotation/test-bitmaps/small-rotated.bmp"\r
+ load-image =\r
+] unit-test\r
+ \r
+[ t ] [\r
+ lake-image\r
+ [ first-of-first-row ]\r
+ [ 90 (rotate) end-of-first-row ] bi =\r
+] unit-test\r
+\r
+[ t ]\r
+[ lake-image [ first-row ] [ 90 (rotate) last-col ] bi = ] unit-test\r
+\r
+[ t ]\r
+[ lake-image [ last-col ] [ 90 (rotate) last-row reverse ] bi = ] unit-test\r
+\r
+[ t ]\r
+[ lake-image [ last-row ] [ 90 (rotate) first-col ] bi = ] unit-test\r
+\r
+[ t ]\r
+[ lake-image [ first-col ] [ 90 (rotate) first-row reverse ] bi = ] unit-test\r
--- /dev/null
+! Copyright (C) 2009 Kobi Lurie.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays colors combinators
+combinators.short-circuit fry grouping images images.bitmap
+images.loader images.normalization kernel locals math sequences ;
+IN: images.processing.rotation
+
+ERROR: unsupported-rotation degrees ;
+
+<PRIVATE
+
+: rotate-90 ( seq^3 -- seq^3 ) flip [ reverse ] map ;
+: rotate-180 ( seq^3 -- seq^3 ) reverse [ reverse ] map ;
+: rotate-270 ( seq^3 -- seq^3 ) flip reverse ;
+
+: (rotate) ( seq n -- seq' )
+ {
+ { 0 [ ] }
+ { 90 [ rotate-90 ] }
+ { 180 [ rotate-180 ] }
+ { 270 [ rotate-270 ] }
+ [ unsupported-rotation ]
+ } case ;
+
+: rows-remove-pad ( byte-rows -- pixels' )
+ [ dup length 4 mod head* ] map ;
+
+: row-length ( image -- n )
+ [ bitmap>> length ] [ dim>> second ] bi /i ;
+
+: image>byte-rows ( image -- byte-rows )
+ [ bitmap>> ] [ row-length ] bi group rows-remove-pad ;
+
+: (seperate-to-pixels) ( byte-rows image -- pixel-rows )
+ component-order>> bytes-per-pixel '[ _ group ] map ;
+
+: image>pixel-rows ( image -- pixel-rows )
+ [ image>byte-rows ] keep (seperate-to-pixels) ;
+
+: flatten-table ( seq^3 -- seq )
+ [ concat ] map concat ;
+
+: ?reverse-dimensions ( image n -- )
+ { 270 90 } member? [ [ reverse ] change-dim ] when drop ;
+
+: normalize-degree ( n -- n' ) 360 rem ;
+
+: processing-effect ( image quot -- image' )
+ '[ image>pixel-rows @ flatten-table ] [ (>>bitmap) ] [ ] tri ; inline
+
+:: rotate' ( image n -- image )
+ n normalize-degree :> n'
+ image image>pixel-rows :> pixel-table
+ image n' ?reverse-dimensions
+ pixel-table n' (rotate) :> table-rotated
+ image table-rotated flatten-table >>bitmap ;
+
+PRIVATE>
+
+: rotate ( image n -- image' )
+ normalize-degree
+ [ '[ _ (rotate) ] processing-effect ] [ ?reverse-dimensions ] 2bi ;
+
+: reflect-y-axis ( image -- image )
+ [ [ reverse ] map ] processing-effect ;
+
+: reflect-x-axis ( image -- image )
+ [ reverse ] processing-effect ;
+++ /dev/null
-Sam Anklesaria
+++ /dev/null
-USING: modules.rpc-server vocabs ;
-IN: modules.remote-loading mem-service
-
-: get-vocab ( vocabstr -- vocab ) vocab ;
\ No newline at end of file
+++ /dev/null
-required for listeners allowing remote loading of modules
\ No newline at end of file
+++ /dev/null
-Sam Anklesaria
+++ /dev/null
-USING: accessors assocs continuations effects io
-io.encodings.binary io.servers.connection kernel
-memoize namespaces parser sets sequences serialize
-threads vocabs vocabs.parser words ;
-IN: modules.rpc-server
-
-SYMBOL: serving-vocabs V{ } clone serving-vocabs set-global
-
-: do-rpc ( args word -- bytes )
- [ execute ] curry with-datastack object>bytes ; inline
-
-MEMO: mem-do-rpc ( args word -- bytes ) do-rpc ; inline
-
-: process ( vocabspec -- )
- vocab-words [ deserialize ] dip deserialize
- swap at "executer" get execute( args word -- bytes ) write flush ;
-
-: (serve) ( -- )
- deserialize dup serving-vocabs get-global index
- [ process ] [ drop ] if ;
-
-: start-serving-vocabs ( -- )
- [
- binary <threaded-server>
- 5000 >>insecure
- [ (serve) ] >>handler
- start-server
- ] in-thread ;
-
-: (service) ( -- )
- serving-vocabs get-global empty? [ start-serving-vocabs ] when
- current-vocab serving-vocabs get-global adjoin
- "get-words" create-in
- in get [ vocab vocab-words [ stack-effect ] { } assoc-map-as ] curry
- (( -- words )) define-inline ;
-
-SYNTAX: service \ do-rpc "executer" set (service) ;
-SYNTAX: mem-service \ mem-do-rpc "executer" set (service) ;
-
-load-vocab-hook [
- [
- dup words>> values
- \ mem-do-rpc "memoize" word-prop [ delete-at ] curry each
- ] append
-] change-global
+++ /dev/null
-remote procedure call server
\ No newline at end of file
+++ /dev/null
-Sam Anklesaria
+++ /dev/null
-USING: help.syntax help.markup ;
-IN: modules.rpc
-ARTICLE: { "modules" "protocol" } "RPC Protocol"
-{ $list
- "Send vocab as string"
- "Send arglist"
- "Send word as string"
- "Receive result list"
-} ;
\ No newline at end of file
+++ /dev/null
-USING: accessors compiler.units combinators fry generalizations io
-io.encodings.binary io.sockets kernel namespaces
-parser sequences serialize vocabs vocabs.parser words ;
-IN: modules.rpc
-
-DEFER: get-words
-
-: remote-quot ( addrspec vocabspec effect str -- quot )
- '[ _ 5000 <inet> binary
- [
- _ serialize _ in>> length narray serialize _ serialize flush deserialize dup length firstn
- ] with-client
- ] ;
-
-: define-remote ( addrspec vocabspec effect str -- ) [
- [ remote-quot ] 2keep create-in -rot define-declared word make-inline
- ] with-compilation-unit ;
-
-: with-in ( vocab quot -- vocab ) over
- [ '[ _ set-in @ ] in get swap dip set-in ] dip vocab ; inline
-
-: remote-vocab ( addrspec vocabspec -- vocab )
- dup "-remote" append [
- [ (( -- words )) [ "get-words" remote-quot ] keep call-effect ] 2keep
- [ rot first2 swap define-remote ] 2curry each
- ] with-in ;
\ No newline at end of file
+++ /dev/null
-remote procedure call client
\ No newline at end of file
+++ /dev/null
-Sam Anklesaria
+++ /dev/null
-module pushing in remote-loading listeners
\ No newline at end of file
+++ /dev/null
-USING: assocs modules.rpc-server vocabs
-modules.remote-loading words ;
-IN: modules.uploads service
-
-: upload-vocab ( word binary -- ) \ get-vocab "memoize" word-prop set-at ;
\ No newline at end of file
+++ /dev/null
-Sam Anklesaria
+++ /dev/null
-improved module import syntax
\ No newline at end of file
+++ /dev/null
-unportable
+++ /dev/null
-USING: modules.rpc-server io.servers.connection ;
-IN: modules.test-server service
-: rpc-hello ( -- str ) "hello world" stop-this-server ;
\ No newline at end of file
+++ /dev/null
-USING: modules.using ;
-IN: modules.using.tests
-USING: tools.test localhost::modules.test-server ;
-[ "hello world" ] [ rpc-hello ] unit-test
\ No newline at end of file
+++ /dev/null
-USING: modules.using modules.rpc-server help.syntax help.markup strings ;
-IN: modules
-
-HELP: service
-{ $syntax "IN: module service" }
-{ $description "Starts a server for requests for remote procedure calls." } ;
-
-ARTICLE: { "modules" "remote-loading" } "Using the remote-loading vocabulary"
-"If loaded, starts serving vocabularies, accessable through a " { $link POSTPONE: USING: } " form" ;
-
-HELP: USING:
-{ $syntax "USING: rpc-server::module fetch-sever::module { module qualified-name } { module => word ... } ... ;" }
-{ $description "Adds vocabularies to the front of the search path. Vocabularies can be fetched remotely, if preceded by a valid hostname. Name pairs facilitate imports like in the "
-{ $link POSTPONE: QUALIFIED: } " or " { $link POSTPONE: FROM: } " forms." } ;
\ No newline at end of file
+++ /dev/null
-USING: assocs kernel modules.remote-loading modules.rpc
-namespaces peg peg.ebnf peg-lexer sequences vocabs vocabs.parser
-strings ;
-IN: modules.using
-
-: >qualified ( vocab prefix -- assoc )
- [ vocab-words ] [ 58 suffix ] bi* [ swap [ prepend ] dip ] curry assoc-map ;
-
-: >partial-vocab ( words assoc -- assoc )
- [ dupd at [ no-word-error ] unless* ] curry { } map>assoc ;
-
-: remote-load ( addr vocabspec -- voab ) [ "modules.remote-loading" remote-vocab (use+) ] dip get-vocab ;
-
-: load'em ( vocab words/? -- ) [ swap >partial-vocab ] when* use get push ;
-
-EBNF: modulize
-tokenpart = (!(':').)+ => [[ >string ]]
-s = ':' => [[ drop ignore ]]
-rpc = tokenpart s s tokenpart => [[ first2 remote-vocab ]]
-remote = tokenpart s tokenpart => [[ first2 remote-load ]]
-plain = tokenpart => [[ load-vocab ]]
-module = rpc | remote | plain
-;EBNF
-
-ON-BNF: USING:
-tokenizer = <foreign factor>
-sym = !(";"|"}"|"=>").
-modspec = sym => [[ modulize ]]
-qualified = modspec sym => [[ first2 >qualified ]]
-unqualified = modspec => [[ vocab-words ]]
-words = ("=>" sym+ )? => [[ [ f ] [ second ] if-empty ]]
-long = "{" ( qualified | unqualified ) words "}" => [[ rest first2 load'em ignore ]]
-short = modspec => [[ use+ ignore ]]
-wordSpec = long | short
-using = wordSpec+ ";" => [[ drop ignore ]]
-;ON-BNF
\ No newline at end of file
+++ /dev/null
-Slava Pestov
+++ /dev/null
-! Copyright (C) 2008, 2009 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math sequences vectors classes classes.algebra
-combinators arrays words assocs parser namespaces make
-definitions prettyprint prettyprint.backend prettyprint.custom
-quotations generalizations debugger io compiler.units
-kernel.private effects accessors hashtables sorting shuffle
-math.order sets see effects.parser ;
-IN: multi-methods
-
-! PART I: Converting hook specializers
-: canonicalize-specializer-0 ( specializer -- specializer' )
- [ \ f or ] map ;
-
-SYMBOL: args
-
-SYMBOL: hooks
-
-SYMBOL: total
-
-: canonicalize-specializer-1 ( specializer -- specializer' )
- [
- [ class? ] filter
- [ length <reversed> [ 1+ neg ] map ] keep zip
- [ length args [ max ] change ] keep
- ]
- [
- [ pair? ] filter
- [ keys [ hooks get adjoin ] each ] keep
- ] bi append ;
-
-: canonicalize-specializer-2 ( specializer -- specializer' )
- [
- [
- {
- { [ dup integer? ] [ ] }
- { [ dup word? ] [ hooks get index ] }
- } cond args get +
- ] dip
- ] assoc-map ;
-
-: canonicalize-specializer-3 ( specializer -- specializer' )
- [ total get object <array> dup <enum> ] dip update ;
-
-: canonicalize-specializers ( methods -- methods' hooks )
- [
- [ [ canonicalize-specializer-0 ] dip ] assoc-map
-
- 0 args set
- V{ } clone hooks set
-
- [ [ canonicalize-specializer-1 ] dip ] assoc-map
-
- hooks [ natural-sort ] change
-
- [ [ canonicalize-specializer-2 ] dip ] assoc-map
-
- args get hooks get length + total set
-
- [ [ canonicalize-specializer-3 ] dip ] assoc-map
-
- hooks get
- ] with-scope ;
-
-: drop-n-quot ( n -- quot ) \ drop <repetition> >quotation ;
-
-: prepare-method ( method n -- quot )
- [ 1quotation ] [ drop-n-quot ] bi* prepend ;
-
-: prepare-methods ( methods -- methods' prologue )
- canonicalize-specializers
- [ length [ prepare-method ] curry assoc-map ] keep
- [ [ get ] curry ] map concat [ ] like ;
-
-! Part II: Topologically sorting specializers
-: maximal-element ( seq quot -- n elt )
- dupd [
- swapd [ call +lt+ = ] 2curry filter empty?
- ] 2curry find [ "Topological sort failed" throw ] unless* ;
- inline
-
-: topological-sort ( seq quot -- newseq )
- [ >vector [ dup empty? not ] ] dip
- [ dupd maximal-element [ over delete-nth ] dip ] curry
- produce nip ; inline
-
-: classes< ( seq1 seq2 -- lt/eq/gt )
- [
- {
- { [ 2dup eq? ] [ +eq+ ] }
- { [ 2dup [ class<= ] [ swap class<= ] 2bi and ] [ +eq+ ] }
- { [ 2dup class<= ] [ +lt+ ] }
- { [ 2dup swap class<= ] [ +gt+ ] }
- [ +eq+ ]
- } cond 2nip
- ] 2map [ +eq+ eq? not ] find nip +eq+ or ;
-
-: sort-methods ( alist -- alist' )
- [ [ first ] bi@ classes< ] topological-sort ;
-
-! PART III: Creating dispatch quotation
-: picker ( n -- quot )
- {
- { 0 [ [ dup ] ] }
- { 1 [ [ over ] ] }
- { 2 [ [ pick ] ] }
- [ 1- picker [ dip swap ] curry ]
- } case ;
-
-: (multi-predicate) ( class picker -- quot )
- swap "predicate" word-prop append ;
-
-: multi-predicate ( classes -- quot )
- dup length <reversed>
- [ picker 2array ] 2map
- [ drop object eq? not ] assoc-filter
- [ [ t ] ] [
- [ (multi-predicate) ] { } assoc>map
- unclip [ swap [ f ] \ if 3array append [ ] like ] reduce
- ] if-empty ;
-
-: argument-count ( methods -- n )
- keys 0 [ length max ] reduce ;
-
-ERROR: no-method arguments generic ;
-
-: make-default-method ( methods generic -- quot )
- [ argument-count ] dip [ [ narray ] dip no-method ] 2curry ;
-
-: multi-dispatch-quot ( methods generic -- quot )
- [ make-default-method ]
- [ drop [ [ multi-predicate ] dip ] assoc-map reverse ]
- 2bi alist>quot ;
-
-! Generic words
-PREDICATE: generic < word
- "multi-methods" word-prop >boolean ;
-
-: methods ( word -- alist )
- "multi-methods" word-prop >alist ;
-
-: make-generic ( generic -- quot )
- [
- [ methods prepare-methods % sort-methods ] keep
- multi-dispatch-quot %
- ] [ ] make ;
-
-: update-generic ( word -- )
- dup make-generic define ;
-
-! Methods
-PREDICATE: method-body < word
- "multi-method-generic" word-prop >boolean ;
-
-M: method-body stack-effect
- "multi-method-generic" word-prop stack-effect ;
-
-M: method-body crossref?
- "forgotten" word-prop not ;
-
-: method-word-name ( specializer generic -- string )
- [ name>> % "-" % unparse % ] "" make ;
-
-: method-word-props ( specializer generic -- assoc )
- [
- "multi-method-generic" set
- "multi-method-specializer" set
- ] H{ } make-assoc ;
-
-: <method> ( specializer generic -- word )
- [ method-word-props ] 2keep
- method-word-name f <word>
- swap >>props ;
-
-: with-methods ( word quot -- )
- over [
- [ "multi-methods" word-prop ] dip call
- ] dip update-generic ; inline
-
-: reveal-method ( method classes generic -- )
- [ set-at ] with-methods ;
-
-: method ( classes word -- method )
- "multi-methods" word-prop at ;
-
-: create-method ( classes generic -- method )
- 2dup method dup [
- 2nip
- ] [
- drop [ <method> dup ] 2keep reveal-method
- ] if ;
-
-: niceify-method ( seq -- seq )
- [ dup \ f eq? [ drop f ] when ] map ;
-
-M: no-method error.
- "Type check error" print
- nl
- "Generic word " write dup generic>> pprint
- " does not have a method applicable to inputs:" print
- dup arguments>> short.
- nl
- "Inputs have signature:" print
- dup arguments>> [ class ] map niceify-method .
- nl
- "Available methods: " print
- generic>> methods canonicalize-specializers drop sort-methods
- keys [ niceify-method ] map stack. ;
-
-: forget-method ( specializer generic -- )
- [ delete-at ] with-methods ;
-
-: method>spec ( method -- spec )
- [ "multi-method-specializer" word-prop ]
- [ "multi-method-generic" word-prop ] bi prefix ;
-
-: define-generic ( word effect -- )
- over set-stack-effect
- dup "multi-methods" word-prop [ drop ] [
- [ H{ } clone "multi-methods" set-word-prop ]
- [ update-generic ]
- bi
- ] if ;
-
-! Syntax
-SYNTAX: GENERIC: CREATE-WORD complete-effect define-generic ;
-
-: parse-method ( -- quot classes generic )
- parse-definition [ 2 tail ] [ second ] [ first ] tri ;
-
-: create-method-in ( specializer generic -- method )
- create-method dup save-location f set-word ;
-
-: CREATE-METHOD ( -- method )
- scan-word scan-object swap create-method-in ;
-
-: (METHOD:) ( -- method def ) CREATE-METHOD parse-definition ;
-
-SYNTAX: METHOD: (METHOD:) define ;
-
-! For compatibility
-SYNTAX: M:
- scan-word 1array scan-word create-method-in
- parse-definition
- define ;
-
-! Definition protocol. We qualify core generics here
-QUALIFIED: syntax
-
-syntax:M: generic definer drop \ GENERIC: f ;
-
-syntax:M: generic definition drop f ;
-
-PREDICATE: method-spec < array
- unclip generic? [ [ class? ] all? ] dip and ;
-
-syntax:M: method-spec where
- dup unclip method [ ] [ first ] ?if where ;
-
-syntax:M: method-spec set-where
- unclip method set-where ;
-
-syntax:M: method-spec definer
- unclip method definer ;
-
-syntax:M: method-spec definition
- unclip method definition ;
-
-syntax:M: method-spec synopsis*
- unclip method synopsis* ;
-
-syntax:M: method-spec forget*
- unclip method forget* ;
-
-syntax:M: method-body definer
- drop \ METHOD: \ ; ;
-
-syntax:M: method-body synopsis*
- dup definer.
- [ "multi-method-generic" word-prop pprint-word ]
- [ "multi-method-specializer" word-prop pprint* ] bi ;
+++ /dev/null
-Experimental multiple dispatch implementation
+++ /dev/null
-extensions
+++ /dev/null
-IN: multi-methods.tests
-USING: multi-methods tools.test math sequences namespaces system
-kernel strings ;
-
-[ { POSTPONE: f integer } ] [ { f integer } canonicalize-specializer-0 ] unit-test
-
-: setup-canon-test ( -- )
- 0 args set
- V{ } clone hooks set ;
-
-: canon-test-1 ( -- seq )
- { integer { cpu x86 } sequence } canonicalize-specializer-1 ;
-
-[ { { -2 integer } { -1 sequence } { cpu x86 } } ] [
- [
- setup-canon-test
- canon-test-1
- ] with-scope
-] unit-test
-
-[ { { 0 integer } { 1 sequence } { 2 x86 } } ] [
- [
- setup-canon-test
- canon-test-1
- canonicalize-specializer-2
- ] with-scope
-] unit-test
-
-[ { integer sequence x86 } ] [
- [
- setup-canon-test
- canon-test-1
- canonicalize-specializer-2
- args get hooks get length + total set
- canonicalize-specializer-3
- ] with-scope
-] unit-test
-
-CONSTANT: example-1
- {
- { { { cpu x86 } { os linux } } "a" }
- { { { cpu ppc } } "b" }
- { { string { os windows } } "c" }
- }
-
-[
- {
- { { object x86 linux } "a" }
- { { object ppc object } "b" }
- { { string object windows } "c" }
- }
- { cpu os }
-] [
- example-1 canonicalize-specializers
-] unit-test
-
-[
- {
- { { object x86 linux } [ drop drop "a" ] }
- { { object ppc object } [ drop drop "b" ] }
- { { string object windows } [ drop drop "c" ] }
- }
- [ \ cpu get \ os get ]
-] [
- example-1 prepare-methods
-] unit-test
+++ /dev/null
-IN: multi-methods.tests
-USING: multi-methods tools.test math sequences namespaces system
-kernel strings words compiler.units quotations ;
-
-DEFER: fake
-\ fake H{ } clone "multi-methods" set-word-prop
-
-[ "fake-{ }" ] [ { } \ fake method-word-name ] unit-test
-
-[ H{ { "multi-method-generic" fake } { "multi-method-specializer" { } } } ]
-[ { } \ fake method-word-props ] unit-test
-
-[ t ] [ { } \ fake <method> method-body? ] unit-test
-
-[
- [ { } [ ] ] [ \ fake methods prepare-methods [ sort-methods ] dip ] unit-test
-
- [ t ] [ { } \ fake multi-dispatch-quot callable? ] unit-test
-
- [ t ] [ \ fake make-generic quotation? ] unit-test
-
- [ ] [ \ fake update-generic ] unit-test
-
- DEFER: testing
-
- [ ] [ \ testing (( -- )) define-generic ] unit-test
-
- [ t ] [ \ testing generic? ] unit-test
-] with-compilation-unit
+++ /dev/null
-IN: multi-methods.tests
-USING: math strings sequences tools.test ;
-
-GENERIC: legacy-test ( a -- b )
-
-M: integer legacy-test sq ;
-M: string legacy-test " hey" append ;
-
-[ 25 ] [ 5 legacy-test ] unit-test
-[ "hello hey" ] [ "hello" legacy-test ] unit-test
+++ /dev/null
-IN: multi-methods.tests
-USING: multi-methods tools.test math sequences namespaces system
-kernel strings definitions prettyprint debugger arrays
-hashtables continuations classes assocs accessors see ;
-
-GENERIC: first-test ( -- )
-
-[ t ] [ \ first-test generic? ] unit-test
-
-MIXIN: thing
-
-SINGLETON: paper INSTANCE: paper thing
-SINGLETON: scissors INSTANCE: scissors thing
-SINGLETON: rock INSTANCE: rock thing
-
-GENERIC: beats? ( obj1 obj2 -- ? )
-
-METHOD: beats? { paper scissors } t ;
-METHOD: beats? { scissors rock } t ;
-METHOD: beats? { rock paper } t ;
-METHOD: beats? { thing thing } f ;
-
-: play ( obj1 obj2 -- ? ) beats? 2nip ;
-
-[ { } 3 play ] must-fail
-[ t ] [ error get no-method? ] unit-test
-[ ] [ error get error. ] unit-test
-[ { { } 3 } ] [ error get arguments>> ] unit-test
-[ t ] [ paper scissors play ] unit-test
-[ f ] [ scissors paper play ] unit-test
-
-[ t ] [ { beats? paper scissors } method-spec? ] unit-test
-[ ] [ { beats? paper scissors } see ] unit-test
-
-SYMBOL: some-var
-
-GENERIC: hook-test ( -- obj )
-
-METHOD: hook-test { array { some-var array } } reverse ;
-METHOD: hook-test { { some-var array } } class ;
-METHOD: hook-test { hashtable { some-var number } } assoc-size ;
-
-{ 1 2 3 } some-var set
-[ { f t t } ] [ { t t f } hook-test ] unit-test
-[ fixnum ] [ 3 hook-test ] unit-test
-5.0 some-var set
-[ 0 ] [ H{ } hook-test ] unit-test
-
-"error" some-var set
-[ H{ } hook-test ] must-fail
-[ t ] [ error get no-method? ] unit-test
-[ { H{ } "error" } ] [ error get arguments>> ] unit-test
-
-MIXIN: busted
-
-TUPLE: busted-1 ;
-TUPLE: busted-2 ; INSTANCE: busted-2 busted
-TUPLE: busted-3 ;
-
-GENERIC: busted-sort ( obj1 obj2 -- obj1 obj2 )
-
-METHOD: busted-sort { busted-1 busted-2 } ;
-METHOD: busted-sort { busted-2 busted-3 } ;
-METHOD: busted-sort { busted busted } ;
+++ /dev/null
-USING: kernel multi-methods tools.test math arrays sequences
-math.order ;
-IN: multi-methods.tests
-
-[ { 1 2 3 4 5 6 } ] [
- { 6 4 5 1 3 2 } [ <=> ] topological-sort
-] unit-test
-
-[ +lt+ ] [
- { fixnum array } { number sequence } classes<
-] unit-test
-
-[ +eq+ ] [
- { number sequence } { number sequence } classes<
-] unit-test
-
-[ +gt+ ] [
- { object object } { number sequence } classes<
-] unit-test
include vm/Config.macosx
include vm/Config.x86.32
+CFLAGS += -m32
box_alien(ffi_dlsym(NULL,sym));
else
{
- tagged<dll> d = library.as<dll>();
- d.untag_check();
+ dll *d = untag_check<dll>(library.value());
if(d->dll == NULL)
dpush(F);
else
- box_alien(ffi_dlsym(d.untagged(),sym));
+ box_alien(ffi_dlsym(d,sym));
}
}
/* close a native library handle */
PRIMITIVE(dlclose)
{
- ffi_dlclose(untag_check<dll>(dpop()));
+ dll *d = untag_check<dll>(dpop());
+ if(d->dll != NULL)
+ ffi_dlclose(d);
}
PRIMITIVE(dll_validp)
if(library == F)
dpush(T);
else
- dpush(tagged<dll>(library)->dll == NULL ? F : T);
+ dpush(untag_check<dll>(library)->dll == NULL ? F : T);
}
/* gets the address of an object representing a C pointer */
bool performing_compaction;
cell collecting_gen;
-/* if true, we collecting aging space for the second time, so if it is still
+/* if true, we are collecting aging space for the second time, so if it is still
full, we go on to collect tenured */
bool collecting_aging_again;
print_string("\n");
print_obj(frame_scan(frame));
print_string("\n");
+ print_string("word/quot addr: ");
print_cell_hex((cell)frame_executing(frame));
- print_string(" ");
+ print_string("\n");
+ print_string("word/quot xt: ");
print_cell_hex((cell)frame->xt);
print_string("\n");
+ print_string("return address: ");
+ print_cell_hex((cell)FRAME_RETURN_ADDRESS(frame));
+ print_string("\n");
}
void print_callstack()
static void load_code_heap(FILE *file, image_header *h, vm_parameters *p)
{
- cell good_size = h->code_size + (1 << 19);
-
- if(good_size > p->code_size)
- p->code_size = good_size;
+ if(h->code_size > p->code_size)
+ fatal_error("Code heap too small to fit image",h->code_size);
init_code_heap(p->code_size);
PRIMITIVE(fixnum_shift)
{
- fixnum y = untag_fixnum(dpop()); \
+ fixnum y = untag_fixnum(dpop());
fixnum x = untag_fixnum(dpeek());
if(x == 0)
-#include <ucontext.h>
+#include <sys/ucontext.h>
namespace factor
{
-#include <ucontext.h>
+#include <sys/ucontext.h>
namespace factor
{
-#include <ucontext.h>
+#include <sys/ucontext.h>
namespace factor
{