diff --git a/.cvskeywords b/.cvskeywords index 90736f2241..318ccc5823 100644 --- a/.cvskeywords +++ b/.cvskeywords @@ -1,10 +1,10 @@ -./library/win32/win32-io-internals.factor:! $Id: win32-io-internals.factor,v 1.8 2005/07/23 09:30:17 eiz Exp $ +./library/win32/win32-io-internals.factor:! $Id: win32-io-internals.factor,v 1.11 2005/09/03 18:48:25 spestov Exp $ ./library/win32/win32-io.factor:! $Id: win32-io.factor,v 1.4 2005/07/23 06:11:07 eiz Exp $ -./library/win32/win32-stream.factor:! $Id: win32-stream.factor,v 1.8 2005/07/23 06:11:07 eiz Exp $ -./library/win32/win32-errors.factor:! $Id: win32-errors.factor,v 1.7 2005/06/09 02:32:45 eiz Exp $ -./library/win32/win32-server.factor:! $Id: win32-server.factor,v 1.7 2005/07/23 06:11:07 eiz Exp $ -./library/win32/winsock.factor:! $Id: winsock.factor,v 1.5 2005/06/13 21:04:58 spestov Exp $ -./library/bootstrap/win32-io.factor:! $Id: win32-io.factor,v 1.8 2005/06/19 21:50:33 spestov Exp $ +./library/win32/win32-stream.factor:! $Id: win32-stream.factor,v 1.10 2005/09/03 18:48:25 spestov Exp $ +./library/win32/win32-errors.factor:! $Id: win32-errors.factor,v 1.8 2005/09/03 18:48:25 spestov Exp $ +./library/win32/win32-server.factor:! $Id: win32-server.factor,v 1.11 2005/09/03 18:48:25 spestov Exp $ +./library/win32/winsock.factor:! $Id: winsock.factor,v 1.6 2005/08/31 22:42:52 eiz Exp $ +./library/bootstrap/win32-io.factor:! $Id: win32-io.factor,v 1.9 2005/08/31 05:39:36 eiz Exp $ ./factor/ExternalFactor.java: * $Id: ExternalFactor.java,v 1.27 2005/07/17 20:29:04 spestov Exp $ ./factor/ConstructorArtifact.java: * $Id: ConstructorArtifact.java,v 1.1 2005/03/01 23:55:59 spestov Exp $ ./factor/math/Complex.java: * $Id: Complex.java,v 1.1.1.1 2004/07/16 06:26:13 spestov Exp $ diff --git a/CHANGES.html b/CHANGES.html index ff7f199285..5ab313438f 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -1,9 +1,99 @@ + + Factor change log +

Factor 0.77:

+ + +

Factor 0.76:

- + + + diff --git a/Makefile b/Makefile index 148077d847..85a583e94b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,16 @@ else STRIP = strip endif -DEFAULT_LIBS = -lm +ifdef STATIC + DEFAULT_LIBS = -lm -Wl,-static -Wl,-whole-archive \ + -Wl,-export-dynamic \ + -lSDL -lSDL_gfx -lSDL_ttf \ + -Wl,-no-whole-archive \ + -lfreetype -lz -L/usr/X11R6/lib -lX11 -lXext \ + -Wl,-Bdynamic +else + DEFAULT_LIBS = -lm +endif UNIX_OBJS = native/unix/file.o \ native/unix/signal.o \ @@ -28,7 +37,7 @@ else PLAF_OBJS = $(UNIX_OBJS) endif -OBJS = $(PLAF_OBJS) native/arithmetic.o native/array.o native/bignum.o \ +OBJS = $(PLAF_OBJS) native/array.o native/bignum.o \ native/s48_bignum.o \ native/complex.o native/cons.o native/error.o \ native/factor.o native/fixnum.o \ @@ -45,7 +54,8 @@ OBJS = $(PLAF_OBJS) native/arithmetic.o native/array.o native/bignum.o \ native/debug.o \ native/hashtable.o \ native/icache.o \ - native/io.o + native/io.o \ + native/wrapper.o default: @echo "Run 'make' with one of the following parameters:" @@ -76,13 +86,13 @@ macosx: linux: $(MAKE) f \ CFLAGS="$(DEFAULT_CFLAGS) -export-dynamic" \ - LIBS="$(DEFAULT_LIBS) -ldl" + LIBS="-ldl $(DEFAULT_LIBS)" $(STRIP) f linux-ppc: $(MAKE) f \ CFLAGS="$(DEFAULT_CFLAGS) -export-dynamic -mregnames" \ - LIBS="$(DEFAULT_LIBS) -ldl" + LIBS="-ldl $(DEFAULT_LIBS)" $(STRIP) f windows: diff --git a/README.txt b/README.txt index 250a439fc9..cbe8d632ce 100644 --- a/README.txt +++ b/README.txt @@ -69,8 +69,8 @@ The Factor source distribution ships with four boot image files: boot.image.le32 - for x86 boot.image.be32 - for PowerPC, SPARC - boot.image.le64 - for x86-64 - boot.image.be64 - for Alpha, PowerPC/64, UltraSparc + boot.image.le64 - for x86-64, Alpha + boot.image.be64 - for PowerPC/64, UltraSparc Once you have compiled the Factor runtime, you must bootstrap the Factor system using the image that corresponds to your CPU architecture. @@ -136,7 +136,6 @@ as, and issue a command similar to the following to bootstrap Factor: generic/ - generic words, for object oriented programming style help/ - online help system httpd/ - HTTP client, server, and web application framework - icons/ - images used by web framework and UI inference/ - stack effect inference, used by compiler, as well as a useful development tool of its own io/ - input and output streams diff --git a/TODO.FACTOR.txt b/TODO.FACTOR.txt index 0f483351c9..8b7b2844fe 100644 --- a/TODO.FACTOR.txt +++ b/TODO.FACTOR.txt @@ -1,27 +1,17 @@ + ui: -- fix listener prompt display after presentation commands invoked -- theme abstraction in ui -- menu dragging - fix up the min thumb size hack -- gaps in pack layout -- find out why so many small bignums get consed +- long lines of text fail in draw-surface +- only redraw dirty gadgets - faster mouse tracking -- binary search to locate visible children of packs -- rewrite frame layout for new style -- an interior paint that is only painted on rollover and mouse press; - use it for menu items. give menus a gradient background -- scroll bar: more intuitive behavior when clicking inside the elevator -- timers -- nicer scrollbars with up/down buttons -- icons +- off-by-one error in pick-up? +- closing ui does not stop timers +- adding/removing timers automatically for animated gadgets +- theme abstraction in ui +- find out why so many small bignums get consed - use incremental strategy for all pack layouts where possible - multiline editing in listener -- sort out clipping off-by-one flaw when filling rectangles -- better menu positioning -- only redraw dirty gadgets - get stuff in examples dir running in the ui -- opengl rendering - text selection - clipboard support @@ -42,10 +32,11 @@ - http keep alive, and range get - code walker & exceptions -- sleep word + ffi: +- C structs, enums, unions: use new-style string mode parsing +- alien/c-types.factor is ugly - smarter out parameter handling - clarify powerpc passing of value struct parameters - ffi unicode strings: null char security hole @@ -53,63 +44,63 @@ - value type structs - bitfields in C structs - setting struct members that are not * +- callbacks + compiler: -- inference needs to be more robust with heavily recursive code -- powerpc: float ffi parameters +- removing unneeded #label +- flushing optimization +- compile-byte/cell: instantiating aliens - fix fixnum<< and /i overflow on PowerPC - simplifier: - kill replace after a peek - merge inc-d's across VOPs that don't touch the stack - intrinsic char-slot set-char-slot integer-slot set-integer-slot - [ [ dup call ] dup call ] infer hangs -- more accurate types for various words - declarations -- type inference fails with some assembler words; - displaced, register and other predicates need to inherit from list - not cons, and need stronger branch partial eval -- optimize away arithmetic dispatch - the invalid recursion form case needs to be fixed, for inlines too - #jump-f #jump-f-label - re-introduce #target-label => #target optimization - -+ sequences - -- dipping 2nmap, 2each -- array sort -- nappend: instead of using push, enlarge the sequence with set-length - then add set the elements with set-nth -- specialized arrays +- recursion is iffy; if the stack at the recursive call doesn't match + up, throw an error + kernel: +- reader syntax for arrays, byte arrays, displaced aliens +- out of memory error when printing global namespace +- first time hash/vector is grown, set size to something big +- merge timers with sleeping tasks +- what about tasks and timers between image restarts +- split: return vectors +- specialized arrays - there is a problem with hashcodes of words and bootstrapping - delegating generic words with a non-standard picker - powerpc has weird callstack residue - instances: do not use make-list -- unions containing tuples do not work properly -- method doc strings -- clean up metaclasses - vectors: ensure its ok with bignum indices - code gc -- doc comments of generics -- M: object should not inhibit delegation +- set-path: iterative +- parse-command-line: no unswons of cli args +- >c/c>: vector stack +- tag: move from kernel-internals to kernel +- word: when bootstrapping, 'word' var is not cleared +- search: slow +- investigate if rehashing on startup is really necessary +- vectorize >n, n>, (get) +- mutable strings simplifying string operarations +- 2each, find*, subset are ugly +- map and 2map duplicate logic + i/o: +- buffer: instantiating aliens - faster stream-copy - reading and writing byte arrays -- unix io: handle \n\r and \n\0 - stream server can hang because of exception handler limitations - better i/o scheduler -- unify unparse and prettyprint - utf16, utf8 encoding - fix i/o on generic x86/ppc unix - if two tasks write to a unix stream, the buffer can overflow -- rename prettyprint* to pprint, prettyprint to pp -- reader syntax for arrays, byte arrays, displaced aliens -- print parsing words in bold + nice to have libraries: diff --git a/actions.xml b/actions.xml index be5949b468..7272b7acd4 100644 --- a/actions.xml +++ b/actions.xml @@ -64,7 +64,7 @@ FactorPlugin.evalInListener(view, "\"" + FactorReader.charsToEscapes(word) - + "\" apropos."); + + "\" apropos"); } diff --git a/boot.image.be32 b/boot.image.be32 index 11a85a7e63..a5f1fd37b0 100644 Binary files a/boot.image.be32 and b/boot.image.be32 differ diff --git a/boot.image.be64 b/boot.image.be64 index 89344caf3d..d3ef5199ad 100644 Binary files a/boot.image.be64 and b/boot.image.be64 differ diff --git a/boot.image.le32 b/boot.image.le32 index 9cf34b1939..3a70171459 100644 Binary files a/boot.image.le32 and b/boot.image.le32 differ diff --git a/boot.image.le64 b/boot.image.le64 index d1fc132b81..9412b76a39 100644 Binary files a/boot.image.le64 and b/boot.image.le64 differ diff --git a/contrib/algebra/README.TXT b/contrib/algebra/README.TXT index 4f428bafca..8997f0b784 100644 --- a/contrib/algebra/README.TXT +++ b/contrib/algebra/README.TXT @@ -1,5 +1,6 @@ -This is the infix minilanguage created by Daniel Ehrenberg, allowing you to do infix math in Factor. The syntax is simple: all operators are right-associative, and square brackets ('[' and ']') are used for paretheses. The syntax for creating an infix expression is ([ infix code goes here ]). That will leave the expression in the internal s-expression format which is easier to process by the evaluator and the CAS. The CAS subsystem of the infix minilanguage does algebra. Currently, it doesn't do very much, only modular arithmetic, though there may be more by the time you read this. There is also constant folding. The way to evaluate an infix expression is to make a seperate word to evaluate it in. The syntax for this is :| name | args |: body ; . Args are one or more variables that you use in the expression. Their values come from the stack. Variables are effectively substituted in to the expression. To make a new variable, use the syntax VARIABLE: variablename in top level code. The variables included by default are x, y, z, a, b, and c. To make a new operator, just set its arith-1 and/or arith-2 word properties, which should link to a word that is the unary or binary arithmetic version, respectively. To make a new constant, like pi, just set the constant? word property of a word that pushes it to t. When opening the files in this package, open first infix.factor, then algebra.factor, then repl.factor. To close, here's an implementation of the quadratic formula using infix math. This is included in the module. -:| quadratic-formula a b c |: - [ [ - b ] / 2 * a ] +- [ sqrt [ sq b ] - 4 * a * c ] / 2 * a ; +This is the infix minilanguage created by Daniel Ehrenberg, allowing you to do infix math in Factor. The syntax is simple: all infix are right-associative and parentheses may be used. There are also unary operators and operators which take arguments in square brackets seperated by semicolons. Infix operators are the ones that are made of non-alphabetic characters. To make a word that uses infix, the syntax is MATH: functionname[firstarg;secondarg;etc]=value ; Args are one or more variables that you use in the expression. Their values come from the stack. Variables are effectively substituted in to the expression. Any alphabetic string may be used as a variable. To make a new operator, just update the functions hashtable in the infix vocabulary. For more information, see the code or contact the author of this program. To close, here's an implementation of the quadratic formula using infix math. This is included in the module. + +MATH: quadratic[a;b;c] = + plusmin[(-b)/2*a;(sqrt(b^2)-4*a*c)/2*a] ; If you find any bugs in this or have any questions, please contact me at microdan @ gmail . com, ask LittleDan@irc.freenode.net, or ask irc.freenode.net/#concatenative diff --git a/contrib/algebra/algebra.factor b/contrib/algebra/algebra.factor deleted file mode 100644 index a9159d778b..0000000000 --- a/contrib/algebra/algebra.factor +++ /dev/null @@ -1,55 +0,0 @@ -IN: algebra USING: lists math kernel words namespaces ; - -GENERIC: (fold-consts) ( infix -- infix ? ) - -M: number (fold-consts) - f ; -M: var (fold-consts) - t ; -M: list2 (fold-consts) - 2unlist (fold-consts) [ - 2list t - ] [ - swap arith-1 word-prop unit call f - ] ifte ; -M: list3 (fold-consts) - 3unlist >r (fold-consts) r> swapd (fold-consts) >r rot r> or [ - 3list t - ] [ - rot arith-2 word-prop unit call f - ] ifte ; - -: fold-consts ( infix -- infix ) - #! Given a mathematical s-expression, perform constant folding, - #! which is doing all the calculations it can do without any - #! variables added. - (fold-consts) drop ; - - -VARIABLE: modularity - #! This is the variable that stores what mod we're in - - -GENERIC: (install-mod) ( infix -- infix-with-mod ) - -: put-mod ( object -- [ mod object modularity ] ) - [ \ mod , , modularity , ] make-list ; - -M: num/vc (install-mod) - put-mod ; - -M: list2 (install-mod) - 2unlist (install-mod) 2list put-mod ; - -M: list3 (install-mod) - 3unlist (install-mod) swap (install-mod) swap 3list put-mod ; - -: install-mod ( arglist infix -- new-arglist infix-with-mod) - #! Given an argument list and an infix expression, produce - #! a new arglist and a new infix expression that will evaluate - #! the given one using modular arithmetic. - >r modularity swons r> (install-mod) ; - -:| quadratic-formula a b c |: - [ [ - b ] / 2 * a ] +- [ sqrt [ sq b ] - 4 * a * c ] / 2 * a ; - diff --git a/contrib/algebra/infix.factor b/contrib/algebra/infix.factor deleted file mode 100644 index 15dcfbcbf7..0000000000 --- a/contrib/algebra/infix.factor +++ /dev/null @@ -1,193 +0,0 @@ -IN: algebra -USING: kernel lists math namespaces test io words parser - generic errors prettyprint vectors kernel-internals ; - -SYMBOL: variable? - #! For word props: will this be a var in an infix expression? -PREDICATE: word var - #! Class of variables - variable? word-prop ; -SYMBOL: constant? - #! Word prop for things like pi and e -PREDICATE: word con - constant? word-prop ; - -PREDICATE: cons single - #! Single-element list - cdr not ; -UNION: num/vc number var con ; -PREDICATE: cons list-word - #! List where first element is a word but not a variable - unswons tuck word? and [ var? not ] [ drop f ] ifte ; -PREDICATE: cons list-nvl - #! List where first element is a number, variable, or list - unswons dup num/vc? swap cons? or and ; -UNION: num/con number con ; - -GENERIC: infix ( list -- list ) - #! Parse an infix expression. This is right associative - #! and everything has equal precendence. The output is - #! an s-expression. Operators can be unary or binary. -M: num/vc infix ; -M: single infix car infix ; -M: list-word infix - uncons infix 2list ; -M: list-nvl infix - unswons infix swap uncons infix swapd 3list ; - - -: ([ - #! Begin a literal infix expression - [ ] ; parsing -: ]) - #! End a literal infix expression. - reverse infix swons ; parsing - -: VARIABLE: - #! Make a variable, which acts like a symbol - CREATE dup define-symbol t variable? set-word-prop ; parsing -VARIABLE: x -VARIABLE: y -VARIABLE: z -VARIABLE: a -VARIABLE: b -VARIABLE: c -VARIABLE: d - -SYMBOL: arith-1 - #! Word prop for unary mathematical function -SYMBOL: arith-2 - #! Word prop for binary mathematical function - -PREDICATE: cons list2 - #! List of 2 elements - length 2 = ; -PREDICATE: cons list3 - #! List of 3 elements - length 3 = ; - - -GENERIC: (eval-infix) ( varstuff infix -- quote ) - -M: num/con (eval-infix) - nip unit \ drop swons ; - -: (find) ( counter item list -- index ) - dup [ - 2dup car = [ 2drop ] [ >r >r 1 + r> r> cdr (find) ] ifte - ] [ - "Undefined variable in infix expression" throw - ] ifte ; -: find ( list item -- index ) - 0 -rot swap (find) ; -M: var (eval-infix) - find [ swap array-nth ] cons ; - -: swap-in-infix ( var fix1 fix2 -- [ fix1solved swap fix2solved ] ) - >r dupd (eval-infix) swap r> (eval-infix) \ swap swons append ; -M: list3 (eval-infix) - unswons arith-2 word-prop unit -rot 2unlist - swap-in-infix \ dup swons swap append ; - -M: list2 (eval-infix) - 2unlist swapd (eval-infix) swap arith-1 word-prop add ; - -: build-prefix ( num-of-vars -- quote ) - #! What needs to be placed in front of the eval-infix quote - [ dup , \ , dup [ - 2dup - 1 - [ swap set-array-nth ] cons , \ keep , - ] repeat drop ] make-list ; - -: eval-infix ( vars infix -- quote ) - #! Given a list of variables and an infix expression in s-expression - #! form, build a quotation which takes as many arguments from the - #! datastack as there are elements in the varnames list, builds - #! it into a vector, and calculates the values of the expression with - #! the values filled in. - over length build-prefix -rot (eval-infix) append ; - -DEFER: fold-consts -: (| f ; parsing ! delete -: | reverse f ; parsing ! delete -: end-infix ( vars reverse-infix -- code ) - infix fold-consts eval-infix ; -: |) reverse end-infix swons \ call swons ; parsing ! delete - -: 3keep - #! like keep or 2keep but with 3 - -rot >r >r swap r> r> 3dup - >r >r >r >r rot r> swap call r> r> r> ; - -: :| - #! :| sq x |: x * x ; - CREATE [ - "in-defintion" off - 3dup nip "infix-code" set-word-prop - end-infix define-compound - ] f "in-definition" on ; parsing -: |: - #! :| sq x |: x * x ; - reverse 3dup nip "infix-args" set-word-prop - swap f ; parsing - -: .w/o-line ( obj -- ) - [ one-line on 4 swap prettyprint* drop ] with-scope ; - -PREDICATE: compound infix-word "infix-code" word-prop ; - -M: infix-word see - dup prettyprint-IN: - ":| " write dup prettyprint-word " " write - dup "infix-args" word-prop [ prettyprint-word " " write ] each - "|:\n " write - "infix-code" word-prop .w/o-line - " ;" print ; - - -: (fac) dup 0 = [ drop ] [ dup 1 - >r * r> (fac) ] ifte ; -: fac - #! Factorial - 1 swap (fac) ; - -: infix-relation - #! Wraps operators like = and > so that if they're given - #! f as either argument, they return f, and they return f if - #! the operation yields f, but if it yields t, it returns the - #! left argument. This way, these types of operations can be - #! composed. - >r 2dup and not [ - r> 3drop f - ] [ - dupd r> call [ - drop f - ] unless - ] ifte ; -! Wrapped operations -: new= [ = ] infix-relation ; -: new> [ > ] infix-relation ; -: new< [ < ] infix-relation ; -: new>= [ >= ] infix-relation ; -: new<= [ <= ] infix-relation ; - -: +- ( a b -- a+b a-b ) - [ + ] 2keep - ; - -: || ; - -! Install arithmetic operators into words -[ + - / * ^ and or xor mod +- min gcd max bitand polar> align shift /mod /i /f rect> bitor - bitxor rem || ] [ - dup arith-2 set-word-prop -] each -[ [[ = new= ]] [[ > new> ]] [[ < new< ]] [[ >= new>= ]] [[ <= new<= ]] ] [ - uncons arith-2 set-word-prop -] each -[ sqrt abs fac sq asin denominator rational? rad>deg exp recip sgn >rect acoth arg fixnum - bitnot sinh acosec acosh acosech complex? ratio? number? >polar number= cis deg>rad >fixnum - cot cos sec cosec tan imaginary coth asech atanh absq >float numerator acot acos atan asec - cosh log bignum? conjugate asinh sin float? real? >bignum tanh sech ] [ - dup arith-1 set-word-prop -] each -[ [[ - neg ]] ] [ uncons arith-1 set-word-prop ] each -[ pi i e -i inf -inf pi/2 ] [ t constant? set-word-prop ] each - diff --git a/contrib/algebra/parse-k.factor b/contrib/algebra/parse-k.factor new file mode 100644 index 0000000000..ea3d3d168d --- /dev/null +++ b/contrib/algebra/parse-k.factor @@ -0,0 +1,362 @@ +IN: infix +USING: sequences kernel io math strings combinators namespaces prettyprint + errors parser generic lists kernel-internals hashtables words vectors ; + +! Tokenizer + +TUPLE: tok char ; + +TUPLE: brackets seq ender ; + +SYMBOL: apostrophe + +SYMBOL: code #! Source code +SYMBOL: spot #! Current index of string + +: take-until ( quot -- parsed-stuff | quot: char -- ? ) + #! Take the substring of a string starting at spot + #! from code until the quotation given is true and + #! advance spot to after the substring. + >r spot get code get 2dup r> + skip [ swap subseq ] keep + spot set ; + +: parse-blank ( -- ) + #! Advance code past any whitespace, including newlines + spot get code get [ blank? not ] skip spot set ; + +: not-done? ( -- ? ) + #! Return t if spot is not at the end of code + code get length spot get = not ; + +: incr-spot ( -- ) + #! Increment spot. + spot [ 1 + ] change ; + +: parse-var ( -- variable-name ) + #! Take a series of letters from code, advancing + #! spot and returning the letters. + [ letter? not ] take-until ; + +: parse-num ( -- number ) + #! Take a number from code, advancing spot and + #! returning the number. + [ "0123456789." member? not ] take-until string>number ; + +: get-token ( -- char ) + spot get code get nth ; + +DEFER: token + +: next-token ( list -- list ) + #! Take one token from code and return it + parse-blank not-done? [ + get-token token + ] when ; + +: token + { + { [ dup letter? ] [ drop parse-var swons ] } + { [ dup "0123456789." member? ] [ drop parse-num swons ] } + { [ dup ";!@#$%^&*?/|\\=+_-~" member? ] [ swons incr-spot ] } + { [ dup "([{" member? ] [ drop f incr-spot ] } + { [ dup ")]}" member? ] [ swons incr-spot ] } + { [ dup CHAR: ' = ] [ drop apostrophe swons incr-spot ] } + { [ t ] [ "Bad character " swap ch>string append throw ] } + } cond next-token ; + +: tokenize ( string -- tokens ) + #! Tokenize a string, returning a list of tokens + [ + code set 0 spot set + f next-token reverse + ] with-scope ; + + +! Parser + +TUPLE: apply func args ; + #! Function application +C: apply + >r [ ] subset r> + [ set-apply-args ] keep + [ set-apply-func ] keep ; + +UNION: value number string ; + +: semicolon ( -- semicolon ) + #! The semicolon token + << tok f CHAR: ; >> ; + +: nest-apply ( [ ast ] -- apply ) + unswons unit swap [ + swap unit + ] each car ; + +GENERIC: parse-token ( ast tokens token -- ast tokens ) + #! Take one or more tokens + +DEFER: parse-tokens + +: semicolon-split ( list -- [ ast ] ) + reverse semicolon unit split [ parse-tokens ] map ; + +M: value parse-token + swapd swons swap ; + +M: brackets parse-token + swapd dup brackets-seq swap brackets-ender { + { [ dup CHAR: ] = ] [ drop semicolon-split >r unswons r> swons ] } + { [ dup CHAR: } = ] [ drop semicolon-split >vector swons ] } + { [ CHAR: ) = ] [ reverse parse-tokens swons ] } + } cond swap ; + +M: object tok-char drop -1 ; ! Hack! + +GENERIC: tok>string ( token/string -- string ) +M: tok tok>string + tok-char ch>string ; +M: string tok>string ; + +: binary-op ( ast tokens token -- ast ) + >r >r unswons r> parse-tokens 2list r> + tok>string swap swons ; + +: unary-op ( ast tokens token -- ast ) + tok>string -rot nip + parse-tokens unit unit ; + +: null-op ( ast tokens token -- ast ) + nip tok-char ch>string swons ; + +M: tok parse-token + over [ + pick [ + binary-op + ] [ + unary-op + ] ifte + ] [ + null-op + ] ifte f ; + +( ast tokens token -- ast tokens ) + +M: symbol parse-token ! apostrophe + drop unswons >r parse-tokens >r unswons r> 2list r> + unit parse-tokens swap swons f ; + +: (parse-tokens) ( ast tokens -- ast ) + dup [ + unswons parse-token (parse-tokens) + ] [ + drop + ] ifte ; + +: parse-tokens ( tokens -- ast ) + #! Convert a list of tokens into an AST + f swap (parse-tokens) nest-apply ; + +: parse-full ( string -- ast ) + #! Convert a string into an AST + tokenize parse-tokens ; + + +! Compiler + +GENERIC: compile-ast ( vars ast -- quot ) + +M: string compile-ast ! variables + swap index dup -1 = [ + "Variable not found" throw + ] [ + [ swap array-nth ] cons + ] ifte ; + +: replace-with ( data -- [ drop data ] ) + \ drop swap 2list ; + +UNION: comp-literal number general-list ; + +M: comp-literal compile-ast ! literal numbers + replace-with nip ; + +: accumulator ( vars { asts } quot -- quot ) + -rot [ + [ + \ dup , + compile-ast % + dup % + ] each-with + ] [ ] make nip ; + +M: vector compile-ast ! literal vectors + dup [ number? ] all? [ + replace-with nip + ] [ + [ , ] accumulator [ { } make nip ] cons + ] ifte ; + +: infix-relation + #! Wraps operators like = and > so that if they're given + #! f as either argument, they return f, and they return f if + #! the operation yields f, but if it yields t, it returns the + #! left argument. This way, these types of operations can be + #! composed. + >r 2dup and not [ + r> 3drop f + ] [ + dupd r> call [ + drop f + ] unless + ] ifte ; + +: functions + #! Regular functions + #! Gives quotation applicable to stack + {{ + [ [[ "+" 2 ]] + ] + [ [[ "-" 2 ]] - ] + [ [[ ">" 2 ]] [ > ] infix-relation ] + [ [[ "<" 2 ]] [ < ] infix-relation ] + [ [[ "=" 2 ]] [ = ] infix-relation ] + [ [[ "-" 1 ]] neg ] + [ [[ "~" 1 ]] not ] + [ [[ "&" 2 ]] and ] + [ [[ "|" 2 ]] or ] + [ [[ "&" 1 ]] t [ and ] reduce ] + [ [[ "|" 1 ]] f [ or ] reduce ] + [ [[ "*" 2 ]] * ] + [ [[ "ln" 1 ]] log ] + [ [[ "plusmin" 2 ]] [ + ] 2keep - ] + [ [[ "@" 2 ]] swap nth ] + [ [[ "sqrt" 1 ]] sqrt ] + [ [[ "/" 2 ]] / ] + [ [[ "^" 2 ]] ^ ] + [ [[ "#" 1 ]] length ] + [ [[ "eq" 2 ]] eq? ] + [ [[ "*" 1 ]] first ] + [ [[ "+" 1 ]] flip ] + [ [[ "\\" 1 ]] ] + [ [[ "sin" 1 ]] sin ] + [ [[ "cos" 1 ]] cos ] + [ [[ "tan" 1 ]] tan ] + [ [[ "max" 2 ]] max ] + [ [[ "min" 2 ]] min ] + [ [[ "," 2 ]] append ] + [ [[ "," 1 ]] concat ] + [ [[ "sn" 3 ]] -rot set-nth ] + [ [[ "prod" 1 ]] product ] + [ [[ "vec" 1 ]] >vector ] + }} ; + +: drc ( list -- list ) + #! all of list except last element (backwards cdr) + dup cdr [ + uncons drc cons + ] [ + drop f + ] ifte ; + +: map-with-left ( seq object quot -- seq ) + [ swapd call ] cons swapd map-with ; inline + +: high-functions + #! Higher-order functions + #! Gives quotation applicable to quotation and rest of stack + {{ + [ [[ "!" 2 ]] 2map ] + [ [[ "!" 1 ]] map ] + [ [[ ">" 2 ]] map-with ] + [ [[ "<" 2 ]] map-with-left ] + [ [[ "^" 1 ]] all? ] + [ [[ "~" 1 ]] call not ] + [ [[ "~" 2 ]] call not ] + [ [[ "/" 2 ]] swapd reduce ] + [ [[ "\\" 2 ]] swapd accumulate ] + }} ; + +: get-hash ( key table -- value ) + #! like hash but throws exception if f + dupd hash [ nip ] [ + [ "Key not found " write . ] string-out throw + ] ifte* ; + +: >apply< ( apply -- func args ) + dup apply-func swap apply-args ; + +: make-apply ( arity apply/string -- quot ) + dup string? [ + swons functions get-hash + ] [ + >apply< car >r over r> make-apply + -rot swons high-functions get-hash cons + ] ifte ; + +: get-function ( apply -- quot ) + >apply< length swap make-apply ; + +M: apply compile-ast ! function application + [ apply-args [ swap ] accumulator [ drop ] append ] keep + get-function append ; + +: push-list ( list item -- list ) + unit append ; + +: parse-comp ( args string -- quot ) + #! Compile a string into a quotation w/o prologue + parse-full compile-ast ; + +: prologue ( args -- quot ) + #! Build the prolog for a function + [ + length dup , \ , + [ 1 - ] keep [ + 2dup - [ swap set-array-nth ] cons , \ keep , + ] repeat drop + ] [ ] make ; + +: ast>quot ( args ast -- quot ) + over prologue -rot compile-ast append ; + +: define-math ( seq -- ) + " " join + dup parse-full apply-args uncons car swap + >apply< >r create-in r> + [ "math-args" set-word-prop ] 2keep + >r tuck >r >r swap "code" set-word-prop r> r> r> + rot ast>quot define-compound ; + +: MATH: + #! MATH: sq[x]=x*x ; + "in-definition" on + string-mode on + [ + string-mode off define-math + ] f ; parsing + +: TEST-MATH: + #! Executes and prints the result of a math + #! expression at parsetime + string-mode on [ + " " join string-mode off parse-full + f swap ast>quot call . + ] f ; parsing + +! PREDICATE: compound infix-word "code" word-prop ; +! M: infix-word definer +! drop POSTPONE: MATH: ; +! M: infix-word class. +! "code" word-prop write " ;" print ; +! +! Redefine compound to not include infix words so see works +! IN: words +! USING: kernel words parse-k ; +! +! PREDICATE: word compound +! dup word-primitive 1 = swap infix-word? not and ; + + + +MATH: quadratic[a;b;c] = + plusmin[(-b)/2*a;(sqrt(b^2)-4*a*c)/2*a] ; diff --git a/contrib/algebra/repl.factor b/contrib/algebra/repl.factor deleted file mode 100644 index 12b44e8afc..0000000000 --- a/contrib/algebra/repl.factor +++ /dev/null @@ -1,9 +0,0 @@ -IN: algebra USING: prettyprint io kernel parser ; - -: algebra-repl ( -- ) - "ok " write flush - read-line dup "exit" = [ - terpri "bye" print - ] [ - parse infix f swap eval-infix call . algebra-repl - ] ifte ; diff --git a/contrib/concurrency/concurrency-examples.factor b/contrib/concurrency/concurrency-examples.factor new file mode 100644 index 0000000000..279141ddc0 --- /dev/null +++ b/contrib/concurrency/concurrency-examples.factor @@ -0,0 +1,187 @@ +! Copyright (C) 2005 Chris Double. All Rights Reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, +! this list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +! +! Examples of using the concurrency library. +IN: concurrency-examples +USING: concurrency kernel io lists threads math sequences namespaces unparser prettyprint errors dlists ; + +: (logger) ( mailbox -- ) + #! Using the given mailbox, start a thread which + #! logs messages put into the box. + dup mailbox-get print (logger) ; + +: logger ( -- mailbox ) + #! Start a logging thread, which will log messages to the + #! console that are put in the returned mailbox. + make-mailbox dup [ (logger) ] cons in-thread ; + +: (pong-server0) ( -- ) + receive uncons "ping" = [ + "pong" swap send (pong-server0) + ] [ + "Pong server shutting down" swap send + ] ifte ; + +: pong-server0 ( -- process) + [ (pong-server0) ] spawn ; + +TUPLE: ping-message from ; +TUPLE: shutdown-message from ; + +GENERIC: handle-message + +M: ping-message handle-message ( message -- bool ) + ping-message-from "pong" swap send t ; + +M: shutdown-message handle-message ( message -- bool ) + shutdown-message-from "Pong server shutdown commenced" swap send f ; + +: (pong-server1) ( -- ) + "pong-server1 waiting for message..." print + receive handle-message [ (pong-server1) ] when ; + +: pong-server1 ( -- process ) + [ + (pong-server1) + "pong-server1 exiting..." print + ] spawn ; + +TUPLE: echo-message from text ; + +M: echo-message handle-message ( message -- bool ) + dup echo-message-text swap echo-message-from send t ; + +GENERIC: handle-message2 +PREDICATE: tagged-message ping-message2 ( obj -- ? ) tagged-message-data "ping" = ; +PREDICATE: tagged-message shutdown-message2 ( obj -- ? ) tagged-message-data "shutdown" = ; + +M: ping-message2 handle-message2 ( message -- bool ) + "pong" reply t ; + +M: shutdown-message2 handle-message2 ( message -- bool ) + "Pong server shutdown commenced" reply f ; + +: (pong-server2) ( -- ) + "pong-server2 waiting for message..." print + receive handle-message2 [ (pong-server2) ] when ; + +: pong-server2 ( -- process ) + [ + (pong-server2) + "pong-server2 exiting..." print + ] spawn ; + +: pong-server3 ( -- process ) + [ handle-message2 ] spawn-server ; + +GENERIC: handle-rpc-message +GENERIC: run-rpc-command + +TUPLE: rpc-command op args ; +PREDICATE: rpc-command add-command ( msg -- bool ) + rpc-command-op "add" = ; +PREDICATE: rpc-command product-command ( msg -- bool ) + rpc-command-op "product" = ; +PREDICATE: rpc-command shutdown-command ( msg -- bool ) + rpc-command-op "shutdown" = ; +PREDICATE: rpc-command crash-command ( msg -- bool ) + rpc-command-op "crash" = ; + +M: tagged-message handle-rpc-message ( message -- bool ) + dup tagged-message-data run-rpc-command -rot reply not ; + +M: add-command run-rpc-command ( command -- shutdown? result ) + rpc-command-args sum f ; + +M: product-command run-rpc-command ( command -- shutdown? result ) + rpc-command-args product f ; + +M: shutdown-command run-rpc-command ( command -- shutdown? result ) + drop t t ; + +M: crash-command run-rpc-command ( command -- shutdown? result ) + drop 1 0 / f ; + +: fragile-rpc-server ( -- process ) + [ handle-rpc-message ] spawn-server ; + +: (robust-rpc-server) ( worker -- ) + [ + receive over send + ] [ + [ + "Worker died, Starting a new worker" print + drop [ handle-rpc-message ] spawn-linked-server + ] when + ] catch + (robust-rpc-server) ; + +: robust-rpc-server ( -- process ) + [ + [ handle-rpc-message ] spawn-linked-server + (robust-rpc-server) + ] spawn ; + +: test-add ( process -- ) + [ + "add" [ 1 2 3 ] swap send-synchronous . + ] cons spawn drop ; + +: test-crash ( process -- ) + [ + "crash" f swap send-synchronous . + ] cons spawn drop ; + +! ****************************** +! Experimental code below +! ****************************** +USE: gadgets +USE: gadgets-labels +USE: gadgets-presentations +USE: generic + +TUPLE: promised-label promise ; + +C: promised-label ( promise -- promised-label ) + over set-delegate [ set-promised-label-promise ] keep + [ [ dup promised-label-promise ?promise drop relayout ] cons spawn drop ] keep ; + +: promised-label-text ( promised-label -- text ) + promised-label-promise dup promise-fulfilled? [ + ?promise + ] [ + drop "Unfulfilled Promise" + ] ifte ; + +M: promised-label pref-dim ( promised-label - dim ) + dup promised-label-text label-size ; + +M: promised-label draw-gadget* ( promised-label -- ) + dup delegate draw-gadget* + dup promised-label-text draw-string ; + +: fib ( n -- n ) + yield dup 2 < [ drop 1 ] [ dup 1 - fib swap 2 - fib + ] ifte ; + +: test-promise-ui ( -- ) + dup gadget. [ 12 fib unparse swap fulfill ] cons spawn drop ; diff --git a/contrib/concurrency/concurrency-tests.factor b/contrib/concurrency/concurrency-tests.factor new file mode 100644 index 0000000000..6734571716 --- /dev/null +++ b/contrib/concurrency/concurrency-tests.factor @@ -0,0 +1,182 @@ +! Copyright (C) 2005 Chris Double. All Rights Reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, +! this list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +! +IN: concurrency +USING: kernel concurrency concurrency-examples threads vectors + sequences lists namespaces test errors dlists strings + math words ; + +[ "junk" ] [ + + 5 over dlist-push-end + "junk" over dlist-push-end + 20 over dlist-push-end + [ string? ] swap dlist-pop? +] unit-test + +[ 5 20 ] [ + + 5 over dlist-push-end + "junk" over dlist-push-end + 20 over dlist-push-end + [ string? ] over dlist-pop? drop + [ ] dlist-each +] unit-test + +[ "junk" ] [ + + 5 over dlist-push-end + "junk" over dlist-push-end + 20 over dlist-push-end + [ integer? ] over dlist-pop? drop + [ integer? ] over dlist-pop? drop + [ ] dlist-each +] unit-test + +[ t ] [ + + 5 over dlist-push-end + "junk" over dlist-push-end + 20 over dlist-push-end + [ string? ] swap dlist-pred? +] unit-test + +[ t ] [ + + 5 over dlist-push-end + "junk" over dlist-push-end + 20 over dlist-push-end + [ integer? ] swap dlist-pred? +] unit-test + +[ f ] [ + + 5 over dlist-push-end + "junk" over dlist-push-end + 20 over dlist-push-end + [ string? ] over dlist-pop? drop + [ string? ] swap dlist-pred? +] unit-test + +[ { 1 2 3 } ] [ + 0 + make-mailbox + 2dup [ mailbox-get swap push ] cons cons in-thread + 2dup [ mailbox-get swap push ] cons cons in-thread + 2dup [ mailbox-get swap push ] cons cons in-thread + 1 over mailbox-put + 2 over mailbox-put + 3 swap mailbox-put +] unit-test + +[ { 1 2 3 } ] [ + 0 + make-mailbox + 2dup [ [ integer? ] swap mailbox-get? swap push ] cons cons in-thread + 2dup [ [ integer? ] swap mailbox-get? swap push ] cons cons in-thread + 2dup [ [ integer? ] swap mailbox-get? swap push ] cons cons in-thread + 1 over mailbox-put + 2 over mailbox-put + 3 swap mailbox-put +] unit-test + +[ { 1 "junk" 3 "junk2" } [ 456 ] ] [ + 0 + make-mailbox + 2dup [ [ integer? ] swap mailbox-get? swap push ] cons cons in-thread + 2dup [ [ integer? ] swap mailbox-get? swap push ] cons cons in-thread + 2dup [ [ string? ] swap mailbox-get? swap push ] cons cons in-thread + 2dup [ [ string? ] swap mailbox-get? swap push ] cons cons in-thread + 1 over mailbox-put + "junk" over mailbox-put + [ 456 ] over mailbox-put + 3 over mailbox-put + "junk2" over mailbox-put + mailbox-get +] unit-test + +[ f ] [ 1 2 gensym gensym tag-match? ] unit-test +[ f ] [ "junk" gensym tag-match? ] unit-test +[ t ] [ 1 2 gensym dup tagged-message-tag tag-match? ] unit-test + +[ "test" ] [ + [ self ] "test" with-process +] unit-test + + +[ "received" ] [ + [ + receive dup tagged-message? [ + "received" reply + ] [ + drop f + ] ifte + ] spawn + "sent" swap send-synchronous +] unit-test + +[ 1 3 2 ] [ + 1 self send + 2 self send + 3 self send + receive + [ 2 mod 0 = not ] receive-if + receive +] unit-test + +[ "pong" "Pong server shutdown commenced" ] [ + pong-server3 "ping" over send-synchronous + swap "shutdown" swap send-synchronous +] unit-test + +[ t 60 120 ] [ + fragile-rpc-server + << rpc-command f "product" [ 4 5 6 ] >> over send-synchronous >r + << rpc-command f "add" [ 10 20 30 ] >> over send-synchronous >r + << rpc-command f "shutdown" [ ] >> swap send-synchronous + r> r> +] unit-test + +[ "crash" ] [ + [ + [ + "crash" throw + ] spawn-link drop + receive + ] + [ + ] catch +] unit-test + +[ 50 ] [ + [ 50 ] future ?future +] unit-test + +[ { 50 50 50 } ] [ + 0 + + 2dup [ ?promise swap push ] cons cons spawn drop + 2dup [ ?promise swap push ] cons cons spawn drop + 2dup [ ?promise swap push ] cons cons spawn drop + 50 swap fulfill +] unit-test diff --git a/contrib/concurrency/concurrency.factor b/contrib/concurrency/concurrency.factor new file mode 100644 index 0000000000..f64dd22277 --- /dev/null +++ b/contrib/concurrency/concurrency.factor @@ -0,0 +1,436 @@ +! Copyright (C) 2005 Chris Double. All Rights Reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, +! this list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +! +! Concurrency library for Factor based on Erlang/Termite style +! concurrency. +USING: kernel lists generic threads io namespaces errors words + math sequences hashtables unparser strings vectors dlists ; +IN: concurrency + +#! Debug +USE: prettyprint + +: (dlist-pop?) ( dlist pred dnode -- obj | f ) + [ + [ dlist-node-data swap call ] 2keep rot [ + swapd [ (dlist-unlink) ] keep dlist-node-data nip + ] [ + dlist-node-next (dlist-pop?) + ] ifte + ] [ + 2drop f + ] ifte* ; + +: dlist-pop? ( pred dlist -- obj | f ) + #! Return first item in the dlist that when passed to the + #! predicate quotation, true is left on the stack. The + #! item is removed from the dlist. The 'pred' quotation + #! must have stack effect ( obj -- bool ). + #! TODO: needs a better name and should be moved to dlists. + dup dlist-first swapd (dlist-pop?) ; + +: (dlist-pred?) ( pred dnode -- bool ) + [ + [ dlist-node-data swap call ] 2keep rot [ + 2drop t + ] [ + dlist-node-next (dlist-pred?) + ] ifte + ] [ + drop f + ] ifte* ; + +: dlist-pred? ( pred dlist -- obj | f ) + #! Return true if any item in the dlist that when passed to the + #! predicate quotation, true is left on the stack. + #! The 'pred' quotation must have stack effect ( obj -- bool ). + #! TODO: needs a better name and should be moved to dlists. + dlist-first (dlist-pred?) ; + +TUPLE: mailbox threads data ; + +: make-mailbox ( -- mailbox ) + #! A mailbox is an object that can be used for safe thread + #! communication. Items can be put in the mailbox and retrieved in a + #! FIFO order. If the mailbox is empty when a get operation is + #! performed then the thread will block until another thread places + #! something in the mailbox. If multiple threads are waiting on the + #! same mailbox, only one of the waiting threads will be unblocked + #! to process the get operation. + 0 ; + +: mailbox-empty? ( mailbox -- bool ) + #! Return true if the mailbox is empty + mailbox-data dlist-empty? ; + +: mailbox-put ( obj mailbox -- ) + #! Put the object into the mailbox. Any threads that have + #! a blocking get on the mailbox are resumed. + [ mailbox-data dlist-push-end ] keep + [ mailbox-threads ] keep 0 swap set-mailbox-threads + [ schedule-thread ] each yield ; + +: (mailbox-block-unless-pred) ( pred mailbox -- pred mailbox ) + #! Block the thread if there are not items in the mailbox + #! that return true when the predicate is called with the item + #! on the stack. The predicate must have stack effect ( X -- bool ). + dup mailbox-data pick swap dlist-pred? [ + [ + swap mailbox-threads push stop + ] callcc0 + (mailbox-block-unless-pred) + ] unless ; + +: (mailbox-block-if-empty) ( mailbox -- mailbox ) + #! Block the thread if the mailbox is empty + dup mailbox-empty? [ + [ + swap mailbox-threads push stop + ] callcc0 + (mailbox-block-if-empty) + ] when ; + +: mailbox-get ( mailbox -- obj ) + #! Get the first item put into the mailbox. If it is + #! empty the thread blocks until an item is put into it. + #! The thread then resumes, leaving the item on the stack. + (mailbox-block-if-empty) + mailbox-data dlist-pop-front ; + +: mailbox-get? ( pred mailbox -- obj ) + #! Get the first item in the mailbox which satisfies the predicate. + #! 'pred' will be called with each item on the stack. When pred returns + #! true that item will be returned. If nothing in the mailbox + #! satisfies the predicate then the thread will block until something does. + (mailbox-block-unless-pred) + mailbox-data dlist-pop? ; + +#! Processes run on nodes identified by a hostname and port. +TUPLE: node hostname port ; + +: localnode ( -- node ) + #! Return the default node on the localhost + "localhost" 9000 ; + +#! Processes run in nodes. Each process has a mailbox that is +#! used for receiving messages sent to that process. +TUPLE: process node links pid mailbox ; + +: make-process ( -- process ) + #! Return a process set to run on the local node. A process is + #! similar to a thread but can send and receive messages to and + #! from other processes. It may also be linked to other processes so + #! that it receives a message if that process terminates. + localnode [ ] gensym unparse make-mailbox ; + +: make-linked-process ( process -- process ) + #! Return a process set to run on the local node. That process is + #! linked to the process on the stack. It will receive a message if + #! that process terminates. + localnode swap unit gensym unparse make-mailbox ; + +#! The 'self-process' variable holds the currently executing process. +SYMBOL: self-process + +: self ( -- process ) + #! Returns the contents of the 'self-process' variables which + #! is the process object for the current process. + self-process get ; + +: init-main-process ( -- ) + #! Setup the main process. + make-process self-process set ; + +init-main-process + +: with-process ( quot process -- ) + #! Calls the quotation with 'self' set + #! to the given process. + [ + self-process set + ] make-hash + swap bind ; + +: spawn ( quot -- process ) + #! Start a process which runs the given quotation. + [ in-thread ] make-process [ with-process ] over slip ; + +TUPLE: linked-exception error ; + +: send ( message process -- ) + #! Send the message to the process by placing it in the + #! processes mailbox. + process-mailbox mailbox-put ; + +: receive ( -- message ) + #! Return a message from the current processes mailbox. + #! If the box is empty, suspend the process until something + #! is placed in the box. + self process-mailbox mailbox-get dup linked-exception? [ + linked-exception-error throw + ] when ; + +: receive-if ( pred -- message ) + #! Return the first message frmo the current processes mailbox + #! that satisfies the predicate. To satisfy the predicate, 'pred' + #! is called with the item on the stack and the predicate should leave + #! a boolean indicating whether it was satisfied or not. The predicate + #! must have stack effect ( X -- bool ). If nothing in the mailbox + #! satisfies the predicate then the process will block until something does. + self process-mailbox mailbox-get? dup linked-exception? [ + linked-exception-error throw + ] when ; + +: rethrow-linked ( error -- ) + #! Rethrow the error to the linked process + self process-links [ over swap send ] each drop ; + +: spawn-link ( quot -- process ) + #! Same as spawn but if the quotation throws an error that + #! is uncaught, that error gets propogated to the process + #! performing the spawn-link. + [ [ [ rethrow-linked ] when* ] catch ] cons + [ in-thread ] self make-linked-process [ with-process ] over slip ; + +#! A common operation is to send a message to a process containing +#! the sending process so the receiver can send a reply back. A 'tag' +#! is also sent so that the sender can match the reply with the +#! original request. The 'tagged-message' tuple ecapsulates this. +TUPLE: tagged-message data from tag ; + +: >tagged-message< ( tagged-message -- data from tag ) + #! Explode a message tuple. + dup tagged-message-data swap + dup tagged-message-from swap + tagged-message-tag ; + +: (recv) ( msg form -- ) + #! Process a form with the following format: + #! [ pred match-quot ] + #! 'pred' is a word that has stack effect ( msg -- bool ). It is + #! executed with the message on the stack. It should return a + #! boolean if it is a message this form should process. + #! 'match-quot' is a quotation with stack effect ( msg -- ). It + #! will be called with the message on the top of the stack if + #! the 'pred' word returned true. + uncons >r dupd execute [ + r> car call + ] [ + r> 2drop + ] ifte ; + +: recv ( forms -- ) + #! Get a message from the processes mailbox. Compare it against the + #! forms to run a quotation if it matches the given message. 'forms' + #! is a list of quotations in the following format: + #! [ pred match-quot ] + #! 'pred' is a word that has stack effect ( msg -- bool ). It is + #! executed with the message on the stack. It should return a + #! boolean if it is a message this form should process. + #! 'match-quot' is a quotation with stack effect ( msg -- ). It + #! will be called with the message on the top of the stack if + #! the 'pred' word returned true. + #! Each form in the list will be matched against the message, + #! even if a prior match succeeded. This means multiple quotations + #! may be run against the message. + receive swap [ dupd (recv) ] each drop ; + +: tag-message ( message -- tagged-message ) + #! Given a message, wrap it with a tagged message. + self gensym ; + +: tag-match? ( message tag -- bool ) + #! Return true if the message is a tagged message and + #! its tag matches the given tag. + swap dup tagged-message? [ + tagged-message-tag = + ] [ + 2drop f + ] ifte ; + +: send-synchronous ( message process -- reply ) + #! Sends a message to the process using the 'message' + #! protocol and waits for a reply to that message. The reply + #! is matched up with the request by generating a message tag + #! which should be sent back with the reply. + >r tag-message [ tagged-message-tag ] keep r> send + unit [ car tag-match? ] cons receive-if tagged-message-data ; + +: reply ( tagged-message message -- ) + #! Replies to the tagged-message which should have been a result of a + #! 'send-synchronous' call. It will send 'message' back to the process + #! that originally sent the tagged message, and will have the same tag + #! as that in 'tagged-message'. + swap >tagged-message< rot drop ( message from tag ) + swap >r >r self r> r> send ; + +: forever ( quot -- ) + #! Loops forever executing the quotation. + dup >r call r> forever ; + +SYMBOL: quit-cc + +: (spawn-server) ( quot -- ) + #! Receive a message, and run 'quot' on it. If 'quot' + #! returns true, start again, otherwise exit loop. + #! The quotation should have stack effect ( message -- bool ). + "Waiting for message in server: " write self process-pid print + receive over call [ (spawn-server) ] when ; + +: spawn-server ( quot -- process ) + #! Spawn a server that receives messages, calling the + #! quotation on the message. If the quotation returns false + #! the spawned process exits. If it returns true, the process + #! starts from the beginning again. The quotation should have + #! stack effect ( message -- bool ). + [ + (spawn-server) + "Exiting process: " write self process-pid print + ] cons spawn ; + +: spawn-linked-server ( quot -- process ) + #! Similar to 'spawn-server' but the parent process will be linked + #! to the child. + [ + (spawn-server) + "Exiting process: " write self process-pid print + ] cons spawn-link ; + +: send-reply ( message pred quot -- ) + #! The intent of this word is to provde an easy way to + #! check the data contained in a message, process it, and + #! return a result to the original sender. + #! Given a message tuple, call 'pred' given the + #! message data from that tuple on the top of the stack. + #! 'pred' should have stack effect ( data -- boolean ). + #! If 'pred' returns true, call 'quot' with the message + #! data from the message tuple on the stack. 'quot' has + #! stack effect ( data -- result ). + #! The result of that call will be sent back to the + #! messages original caller with the same tag as the + #! original message. + >r >r >tagged-message< rot ( from tag data r: quot pred ) + dup r> call [ ( from tag data r: quot ) + r> call ( from tag result ) + self ( from tag result self ) + rot ( from self tag result ) + swap send + ] [ + r> drop 3drop + ] ifte ; + +: maybe-send-reply ( message pred quot -- ) + #! Same as !result but if false is returned from + #! quot then nothing is sent back to the caller. + >r >r >tagged-message< rot ( from tag data r: quot pred ) + dup r> call [ ( from tag data r: quot ) + r> call ( from tag result ) + [ + self ( from tag result self ) + rot ( from self tag result ) + swap send + ] [ + 2drop + ] ifte* + ] [ + r> drop 3drop + ] ifte ; + +: server-cc ( -- cc | process) + #! Captures the current continuation and returns the value. + #! If that CC is called with a process on the stack it will + #! set 'self' for the current process to it. Otherwise it will + #! return the value. This allows capturing a continuation in a server, + #! and jumping back into it from a spawn and keeping the 'self' + #! variable correct. It's a workaround until I can find out how to + #! stop 'self' from being clobbered back to its old value. + [ ] callcc1 dup process? [ self-process set f ] when ; + +: call-server-cc ( server-cc -- ) + #! Calls the server continuation passing the current 'self' + #! so the server continuation gets its new self updated. + self swap call ; + +: future ( quot -- future ) + #! Spawn a process to call the quotation and immediately return + #! a 'future' on the stack. The future can later be queried with + #! ?future. If the quotation has completed the result will be returned. + #! If not, the process will block until the quotation completes. + #! 'quot' must have stack effect ( -- X ). + [ call self send ] cons spawn ; + +: ?future ( future -- result ) + #! Block the process until the future has completed and then place the + #! result on the stack. Return the result immediately if the future has completed. + process-mailbox mailbox-get ; + +TUPLE: promise fulfilled? value processes ; + +C: promise ( -- ) + [ 0 swap set-promise-processes ] keep ; + +: fulfill ( value promise -- ) + #! Set the future of the promise to the given value. Threads + #! blocking on the promise will then be released. + dup promise-fulfilled? [ + [ set-promise-value ] keep + [ t swap set-promise-fulfilled? ] keep + [ promise-processes ] keep 0 swap set-promise-processes + [ schedule-thread ] each yield + ] unless ; + + : (maybe-block-promise) ( promise -- promise ) + #! Block the process if the promise is unfulfilled. This is different from + #! (mailbox-block-if-empty) in that when a promise is fulfilled, all threads + #! need to be resumed, rather than just one. + dup promise-fulfilled? [ + [ + swap promise-processes push stop + ] callcc0 + ] unless ; + +: ?promise ( promise -- result ) + (maybe-block-promise) promise-value ; + +! ****************************** +! Experimental code below +! ****************************** +SYMBOL: lazy-quot + +: lazy ( quot -- lazy ) + #! Spawn a process that immediately blocks and return it. + #! When '?lazy' is called on the returned process, call the quotation + #! and return the result. The quotation must have stack effect ( -- X ). + [ + [ + lazy-quot set + [ + [ tagged-message? [ [ drop t ] [ get call ] send-reply ] ] + ] recv + ] with-scope + ] cons spawn ; + +: ?lazy ( lazy -- result ) + #! Given a process spawned using 'lazy', evaluate it and return the result. + lazy-quot swap send-synchronous ; + diff --git a/contrib/concurrency/concurrency.html b/contrib/concurrency/concurrency.html new file mode 100644 index 0000000000..baa97bd1f8 --- /dev/null +++ b/contrib/concurrency/concurrency.html @@ -0,0 +1,549 @@ + + + Factor Concurrency Library + + + +

Factor Concurrency Library

+

The concurrency library here is based upon the style + of concurrency used in systems like Erlang and Termite. It is + currently at a very early stage and only supports concurrent + processes within a single Factor image. The interface is very likely to + change so it is quite experimental at this stage. The ability to + have distributed processes is planned.

+

Overview

+

A concurrency oriented program is one in which multiple processes +run simultaneously in a single Factor image. The processes can +communicate with each other by asynchronous message sends. Although +processes can share data via Factor's mutable data structures it is +not recommended as the use of shared state concurrency is often a +cause of problems.

+

Loading

+

The quickest way to get up and running with this library is to +change to the 'concurrency' directory and run Factor. Then execute the +following commands:

+
+"load.factor" run-file
+USE: concurrency
+USE: concurrency-examples
+
+

Processes

+

A process is basically a thread with a message queue. Other +processes can place items on this queue by sending the process a +message. A process can check its queue for messages, blocking if none +are pending, and process them as they are queued.

+

Factor processes are very lightweight. Each process can take as +little as 900 bytes of memory. This library has been tested running +hundreds of thousands of simple processes.

+

The messages that are sent from process to process are any Factor +value. Factor tuples are ideal for this sort of thing as you can send +a tuple to a process and the predicate dispatch mechanism can be used +to perform actions depending on what the type of the tuple is.

+

Processes are usually created using the 'spawn' word:

+
+IN: concurrency
+spawn ( quot -- process )
+
+

This word takes a quotation on the stack and starts a process that +will execute that quotation asynchronously. When the quotation +completes the process will die. 'spawn' leaves on the stack the +process object that was started. This object can be used to send +messages to the process using the 'send' word:

+
+IN: concurrency
+send ( message process -- )
+
+

'send' will return immediately after placing the message in the +target processes message queue. A process can get a message from its +queue using the 'receive' word:

+
+IN: concurrency
+receive ( -- message )
+
+

This will get the most recent message +and leave it on the stack. If there are no messages in the queue the +process will 'block' until a message is available. When a process is +blocked it takes no CPU time at all.

+
+[ receive print ] spawn 
+"Hello Process!" swap send
+
+

This example spawns a process that first blocks, waiting to receive +a message. When a message is received, the 'receive' call returns +leaving it on the stack. It then prints the message and exits. 'spawn' +left the process on the stack so it's available to send the 'Hello +Process!' message to it. Immediately after the 'send' you should see +'Hello Process!' printed on the console.

+

It is also possible to selectively retrieve messages from the +message queue. The 'receive-if' word takes a predicate quotation on the stack +and returns the first message in the queue that satisfies the +predicate. If no items satisfy the predicate then the process is +blocked until a message is received that does. +

+
+: odd? ( n -- ? )
+  2 mod 1 = ;
+
+1 self send
+2 self send
+3 self send
+
+receive .
+ => 1
+[ odd? ] receive-if .
+ => 3
+receive .
+ => 2
+
+

Self

+

A process can get access to its own process object using the 'self' +word so it can pass it to other processes. This allows the other processes to send +messages back. A simple example of using this gets the current +processes 'self' and spawns a process which sends a message to it. We +then receive the message from the original process

+
+  self .s
+    => << process ... >>
+  [ "Hello!" swap send ] cons spawn drop  receive .
+    => "Hello"
+
+

Servers

+

A common idiom is to create 'server' processes that act on messages +that are sent to it. These follow a basic pattern of blocking until a +message is received, processing that message then looping back to +blocking for a message.

+

The following example shows a very simple server that expects a +cons cell as its message. The 'car' of the cons should be the senders +process object. If the 'cdr' is 'ping' then the server sends 'pong' +back to the caller. If the 'cdr' is anything else then the server +exits:

+
+: (pong-server0) ( -- )
+  receive uncons "ping" = [
+    "pong" swap send (pong-server0)
+  ] [
+    "Pong server shutting down" swap send
+  ] ifte ;
+  
+: pong-server0 ( -- process)
+  [ (pong-server0) ] spawn ;
+
+  pong-server0
+  self "ping" cons over send receive .
+    => "pong"
+  self "ping" cons over send receive .
+    => "pong"
+  self "shutdown" cons over send receive .
+    => "Pong server shutting down"
+
+

Handling the deconstructing of messages and dispatching based on +the message can be a bit of a chore. Especially in servers that take a +number of different messages. One approach to factor this code out, +and reduce the amount of stack juggling required, is to use tuples as +messages. This allows using the generic dispatch mechanism. The +following example implements the pong server but using tuples as +messages:

+
+TUPLE: ping-message from ;
+TUPLE: shutdown-message from ;
+
+GENERIC: handle-message
+
+M: ping-message handle-message ( message -- bool )
+  ping-message-from "pong" swap send t ;
+
+M: shutdown-message handle-message ( message -- bool )
+  shutdown-message-from "Pong server shutdown commenced" swap send f ;
+
+: (pong-server1) ( -- )
+  "pong-server1 waiting for message..." print
+  receive handle-message [ (pong-server1) ] when ;
+
+: pong-server1 ( -- process )
+  [ 
+    (pong-server1) 
+    "pong-server1 exiting..." print
+  ] spawn ;
+
+

Two tuples are created for a 'ping' and 'shutdown' message. Each +has a 'from' slot which holds the process of the sender. The server +loop, in '(pong-server1)', calls a generic method called +'handle-message'. This has signature ( message -- bool ). These +methods return a boolean. +True means continue the server +loop. False means exit and shut down the server.

+

Two methods are added to the generic word. One for 'ping' and the +other for 'pong'. Here's a sample run:

+
  clear
+  pong-server1
+=> pong-server1 waiting for message...
+    self <ping-message> over send receive .
+=> "pong"
+pong-server1 waiting for message...
+    self <ping-message> over send receive .
+=> "pong"
+pong-server1 waiting for message...
+    self <shutdown-message> over send receive .
+=> "Pong server shutdown commenced"
+   pong-server1 exiting...
+
+

The advantage of this approach is it is easy to extend the server +without shutting it down. Adding a new message is as simple as +defining the tuple and adding a method to 'handle-message' specialised +on that tuple. Here's an example of adding an 'echo' message, without +shutting the server down:

+
+  pong-server1
+=> pong-server1 waiting for message...
+  self <ping-message> over send receive .
+=> "pong"
+
+TUPLE: echo-message from text ;
+
+M: echo-message handle-message ( message -- bool )
+  dup echo-message-text swap echo-message-from send  t ;
+
+  self "Hello World" <echo-message> over send receive .
+=>"Hello World"
+
+
+

Synchronous Sends

+

The 'send' word sends a message asynchronously, and the sending +process continues immediately. The 'pong server' examples shown +previously all sent messages to the server and waited for a reply back +from the server. This pattern of synchronous sending is made easier +with the 'send-synchronous' word:

+
+IN: concurrency
+send-synchronous ( message process -- reply )
+
+

This word will send a message to the given process and immediately +block until a reply is received for this particular message send. It +leaves the reply on the stack. Note that it doesn't wait for just any +reply, it waits for a reply specifically to this send.

+

To do this it wraps the requested message inside a 'tagged-message' +tuple. This tuple is defined as:

+
+TUPLE: tagged-message data from tag ;
+
+

When 'send-synchronous' is called it will created a +'tagged-message', storing the current process in the 'from' slot. This +is what the receiving server will use to send the reply to. It also +generates a random 'tag' which is stored in the 'tag' slot. The +receiving server will include this value in its reply. After the send +the current process will block waiting for a reply that has the exact +same tag. In this way you can be sure that the reply you got was for +the specific message sent.

+

Here is the 'pong server' recoded to use 'send-synchronous' and the +tagged-message type:

+
+GENERIC: handle-message2
+PREDICATE: tagged-message ping-message2 ( obj -- ? ) 
+  tagged-message-data "ping" = ;
+PREDICATE: tagged-message shutdown-message2 ( obj -- ? ) 
+  tagged-message-data "shutdown" = ;
+
+M: ping-message2 handle-message2 ( message -- bool ) 
+  "pong" reply t ;
+
+M: shutdown-message2 handle-message2 ( message -- bool )  
+  "Pong server shutdown commenced" reply f ;
+
+: (pong-server2) ( -- )
+  "pong-server2 waiting for message..." print
+  receive handle-message2 [ (pong-server2) ] when ;
+
+: pong-server2 ( -- process )
+  [ 
+    (pong-server2) 
+    "pong-server2 exiting..." print
+  ] spawn ;
+
+ pong-server2
+=> pong-server2 waiting for message...
+ "ping" over send-synchronous .
+=> "pong"
+   pong-server2 waiting for message...
+ "ping" over send-synchronous .
+=> "pong"
+   pong-server2 waiting for message...
+  "shutdown" over send-synchronous .
+=> "Pong server shutdown commenced"
+   pong-server2 exiting...
+
+

The main difference in this example is that the 'handle-message2' +methods are dispatched over predicate types. Two predicate types are +set up both based on the 'tagged-message' tuple mentioned earlier. The +first is for 'ping-message2' which is a tagged message where the +message data is the string "ping". The second is also a tagged message +but the message data is the string "shutdown".

+

The implementation of the methods uses the 'reply' word. 'reply' +takes a received tagged-message and a new message on the stack and replies to +it. This means that it sends a reply back to the calling process using +the same 'tag' +as the original message. It is a convenience word so you don't have to +manually unpack the tagged-message tuple to get at the originating +process and tag. Its signature is:

+
+IN: concurrency
+reply ( tagged-message message -- )
+
+

Generic Server

+

You'll probably have noticed that the general pattern of the pong +server examples are the same. In a loop they receive a message, +process it using a generic function, and either exit or go back to the +beginning of the loop. This is abstracted in the 'spawn-server' +word:

+
+IN: quotation
+spawn-server ( quot -- process )
+
+

This takes a quotation that has stack effect ( message -- bool ). +'spawn-server' will spawn a server loop that waits for a message. When +it is received the quotation is called on it. If the quotation returns +false then the server process exits, otherwise it loops from the +beginning again. Using this word you can write the previous +'pong-server2' example as:

+
+GENERIC: handle-message2
+PREDICATE: tagged-message ping-message2 ( obj -- ? ) tagged-message-data "ping" = ;
+PREDICATE: tagged-message shutdown-message2 ( obj -- ? ) tagged-message-data "shutdown" = ;
+
+M: ping-message2 handle-message2 ( message -- bool ) 
+  "pong" reply t ;
+
+M: shutdown-message2 handle-message2 ( message -- bool )  
+  "Pong server shutdown commenced" reply f ;
+
+: pong-server3 ( -- process )
+  [ handle-message2 ] spawn-server ;
+
+

The main change is that you no longer need the helper +(pong-server2) word.

+

Exceptions

+

A process can handle exceptions using the standard Factor exception +handling mechanism. If an exception is uncaught the process will +terminate. For example:

+
+[
+  1 0 / 
+  "This will not print" print
+] spawn
+ =>
+Division by zero
+:s :r show stacks at time of error.
+:get ( var -- value ) inspects the error namestack.
+
+

Processes can be linked so that a parent process can receive the +exception that caused the child process to terminate. In this way +'supervisor' processes can be created that are notified when child +processes terminate and possibly restart them.

+

The easiest way to form this link is using the 'spawn-link' +word. This will create a unidirectional link, such that if an +uncaught exception causes the child to terminate, the parent process +can catch it:

+
+[
+  [ 
+    1 0 /  
+    "This will not print" print
+  ] spawn-link drop
+  receive
+] [ 
+  [ "Exception caught." print ] when
+] catch
+  => "Exception caught."
+
+

Exceptions are only raised in the parent when the parent does a +'receive' or 'receive-if'. This is because the exception is sent from +the child to the parent as a message.

+

To demonstrate how a 'supervisor' process could be created we'll +use the following example 'rpc-server'. It processes 'add', 'product' +and 'crash' messages. 'crash' causes a deliberate divide by zero error +to terminate the process:

+
+GENERIC: handle-rpc-message
+GENERIC: run-rpc-command 
+
+TUPLE: rpc-command op args ;
+PREDICATE: rpc-command add-command ( msg -- bool )
+  rpc-command-op "add" = ;
+PREDICATE: rpc-command product-command ( msg -- bool )
+  rpc-command-op "product" = ;
+PREDICATE: rpc-command shutdown-command ( msg -- bool )
+  rpc-command-op "shutdown" = ;
+PREDICATE: rpc-command crash-command ( msg -- bool )
+  rpc-command-op "crash" = ;
+
+M: tagged-message handle-rpc-message ( message -- bool )
+  dup tagged-message-data run-rpc-command -rot reply not ;
+
+M: add-command run-rpc-command ( command -- shutdown? result )
+  rpc-command-args sum f ;
+
+M: product-command run-rpc-command ( command -- shutdown? result )
+  rpc-command-args product f ;
+
+M: shutdown-command run-rpc-command ( command -- shutdown? result )
+  drop t t ;
+
+M: crash-command run-rpc-command ( command -- shutdown? result )
+  drop 1 0 / f ;
+
+: fragile-rpc-server ( -- process )
+  [ handle-rpc-message ] spawn-server ;
+
+: test-add ( process -- )
+  [ 
+    "add" [ 1 2 3 ] <rpc-command> swap send-synchronous .
+  ] cons spawn drop ;
+
+: test-crash ( process -- )
+  [ 
+    "crash" f <rpc-command> swap send-synchronous .
+  ] cons spawn drop ;
+
+

An example of use:

+
+  fragile-rpc-server
+=> Waiting for message in server: G:13037
+  dup test-add
+=> 6
+   Waiting for message in server: G:13037
+  dup test-crash
+=> Division by zero
+   :s :r show stacks at time of error.
+   :get ( var -- value ) inspects the error namestack. 
+  dup test-add
+
+

After the crash, all other messages are ignored by the server as it +is no longer running. The following is a way to re-use this code by +running a 'supervisor' process that links with the 'worker' rpc-server. When +the worker crashes the supervisor process restarts it. All +messages sent to the supervisor are immediately forwarded to the +worker:

+
+: (robust-rpc-server) ( worker -- )
+  [
+    #! Forward all messages to worker
+    receive over send
+  ] [
+    [  
+      "Worker died, Starting a new worker" print
+      drop [ handle-rpc-message ] spawn-linked-server
+    ] when
+  ] catch 
+  (robust-rpc-server) ;
+  
+: robust-rpc-server ( -- process )
+  [
+    [ handle-rpc-message ] spawn-linked-server
+    (robust-rpc-server)
+  ] spawn ;
+
+

This time when the 'robust-rpc-server' is run you'll notice that +messages after the crash are still processed:

+
+  robust-rpc-server
+=> Waiting for message in server: G:13045
+  dup test-add
+=> 6
+   Waiting for message in server: G:13045
+  dup test-crash
+=> Worker died, Starting a new worker
+   Waiting for message in server: G:13050  
+  dup test-add
+=> 6
+   Waiting for message in server: G:13050
+
+ +

Futures

+

A future is a placeholder for the result of a computation that is +being calculated in a process. When the process has completed the +computation the future can be queried to find out the result. If the +computation has not completed when the future is queried them the +process will block until the result is completed.

+

A future is created using the 'future' word:

+
+IN: concurrency
+future ( quot -- future )
+
+

The quotation will be run in a spawned process, and a future object +is immediately returned. This future object can be resolved using the +word '?future':

+
+IN: concurrency
+?future ( future -- result )
+
+

Futures are useful for starting calculations that take a long time +to run but aren't needed to later in the process. When the process +needs the value it can use '?future' to get the result or block until +the result is available. For example:

+
+  [ 30 fib ] future
+  ...do stuff...
+  ?future 
+
+

Promises

+

A promise is similar to a future but it is not produced by +calcuating something in the background. It represents a promise to +provide a value sometime later. A process can request the value of a +promise and will block if the promise is not fulfilled. Later, another +process can fulfill the promise, providing a value. All threads +waiting on the promise will then resume with that value on the +stack.

+

The words that operate on promises are:

+
+IN: concurrency
+<promise> ( -- promise )
+fulfill ( value promise  -- )
+?promise ( promise -- result ) 
+
+

A simple example of use is:

+
+  <promise>
+  [ ?promise "Promise fulfilled: " write print ] spawn drop
+  [ ?promise "Promise fulfilled: " write print ] spawn drop
+  [ ?promise "Promise fulfilled: " write print ] spawn drop
+  "hello" swap fulfill
+    => Promise fulfilled: hello
+       Promise fulfilled: hello
+       Promise fulfilled: hello
+
+

In this example a promise is created and three processes spawned, +waiting for that promise to be fulfilled. The main process then +fulfills that promise with the value "hello" and all the blocking +processes resume, printing the value.

+

GUI

+

In the Alice programming system it's possible to display futures +and promises in the inspector and the values will automatically change +then the future is ready, or the promise fulfilled. It's possible to +do similar things with the Factor GUI but there is nothing currently +built-in. A simple example of how this might work is included in the +concurrency-examples vocabulary, with the 'test-promise-ui' word.

+
+: test-promise-ui ( -- )
+  <promise> dup <promised-label> gadget. 
+  [ 12 fib unparse swap fulfill ] cons spawn drop ;
+
+

This creates a 'promised-label' gadget. This is a gadget, also +implemented in the examples, that has an attached promise. The gadget will display the text 'Unfulfilled +Promise' while the promise is unfulfilled. When it is fulfilled the +gadget will immediately redisplay the value of the promise (which will +need to be a printable value for this example).

+

The example above displays the gadget using 'gadget.' and then +spawns a thread to compute the 12th fibonacci number and fulfill the +promise with it converted to a string. As soon as the fulfill occurs +the gadget redisplays with the new value.

+

So running 'test-promise-ui' will displays 'Unfulfilled Promise' +and a short time later change to the new computed value. You will need +to have the Factor GUI listener for this to work:

+
+USE: shells
+[ ui ] in-thread
+
+ + + diff --git a/contrib/concurrency/load.factor b/contrib/concurrency/load.factor new file mode 100644 index 0000000000..1ba87047a2 --- /dev/null +++ b/contrib/concurrency/load.factor @@ -0,0 +1,17 @@ +USE: kernel +USE: httpd +USE: threads +USE: prettyprint +USE: errors +USE: io + +USE: parser + +: a "../dlists.factor" run-file + "concurrency.factor" run-file ; +: b "concurrency-examples.factor" run-file ; +: c "concurrency-tests.factor" run-file ; +a +b +USE: concurrency +USE: concurreny-examples \ No newline at end of file diff --git a/contrib/concurrency/style.css b/contrib/concurrency/style.css new file mode 100644 index 0000000000..207afdceb7 --- /dev/null +++ b/contrib/concurrency/style.css @@ -0,0 +1,28 @@ + body { background: white; color: black; } + p { margin-left: 10%; margin-right: 10%; + font: normal 100% Verdana, Arial, Helvetica; } + td { margin-left: 10%; margin-right: 10%; + font: normal 100% Verdana, Arial, Helvetica; } + table { margin-left: 10%; margin-right: 10%; } + ul { margin-left: 10%; margin-right: 10%; + font: normal 100% Verdana, Arial, Helvetica; } + ol { margin-left: 10%; margin-right: 10%; + font: normal 100% Verdana, Arial, Helvetica; } + h1 { text-align: center; margin-bottom: 0; margin-top: 1em; } + h2 { margin: 0 5% 0 7.5%; font-size: 120%; font-style: italic; } + h3 { border: 2px solid blue; border-width: 2px 0.5em 2px 0.5em; + padding: 0.2em 0.2em 0.2em 0.5em; background: #fafafa; + margin-left: 10%; margin-right: 10%; margin-top: 2em; + font-size: 100%; } + .note { border: 2px solid blue; border-width: 2px 2px 2px 2em; + padding: 0.5em 0.5em 0.5em 1em; background: #ffe; } + .code { border: 1px solid black; border-width: 1px; + padding: 0.5em; background: #ffe; + margin-left: 10%; margin-right: 10%; } + blockquote { margin-left: 25%; margin-right: 25%; + font-style: italic; } + .highlite { color: red; } + .footer { margin-top: 2.5em; border-top: 1px solid gray; color: + #AAA; font-size: 85%; padding-top: 0.33em; } + #copyright { text-align: center; color: #AAA; + font-size: 65%; } \ No newline at end of file diff --git a/contrib/cont-responder/cont-numbers-game.factor b/contrib/cont-responder/cont-numbers-game.factor index ddde1ec541..62e2474d25 100644 --- a/contrib/cont-responder/cont-numbers-game.factor +++ b/contrib/cont-responder/cont-numbers-game.factor @@ -69,7 +69,7 @@ USE: namespaces - ] show [ "num" get ] bind parse-number ; + ] show [ "num" get ] bind string>number ; : guess-banner "I'm thinking of a number between 0 and 100." web-print ; diff --git a/contrib/cont-responder/cont-testing.factor b/contrib/cont-responder/cont-testing.factor index 5316f87589..7e78e27cfa 100644 --- a/contrib/cont-responder/cont-testing.factor +++ b/contrib/cont-responder/cont-testing.factor @@ -94,10 +94,10 @@ USE: io #! Create a namespace holding data required #! for testing continuation based responder functions #! at the interpreter console. - [ + [ reset-continuation-table init-session-namespace - ] extend ; + ] make-hash ; : test-cont-function ( quot -- ) #! Call a continuation responder function with required diff --git a/contrib/cont-responder/eval-responder.factor b/contrib/cont-responder/eval-responder.factor index d0bfa814cb..b50e244a6b 100644 --- a/contrib/cont-responder/eval-responder.factor +++ b/contrib/cont-responder/eval-responder.factor @@ -46,11 +46,11 @@ USE: sequences #! Create an 'evaluator' object that holds #! the current stack, output and history for #! do-eval. - [ + [ "history" set "output" set "stack" set - ] extend ; + ] make-hash ; : display-eval-form ( url -- ) #! Display the components for allowing entry of @@ -73,13 +73,13 @@ USE: sequences #! Replace occurrences of single quotes with #! backslash quote. [ - [ dup [ [[ CHAR: ' "\\'" ]] [[ CHAR: " "\\\"" ]] ] assoc [ , ] [ , ] ?ifte ] each - ] make-string ; + [ dup [ [[ CHAR: ' "\\'" ]] [[ CHAR: " "\\\"" ]] ] assoc [ % ] [ % ] ?ifte ] each + ] "" make ; : make-eval-javascript ( string -- string ) #! Give a string return some javascript that when #! executed will set the eval textarea to that string. - [ "document.forms.main.eval.value=\"" , escape-quotes , "\"" , ] make-string ; + [ "document.forms.main.eval.value=\"" % escape-quotes % "\"" % ] "" make ; : write-eval-link ( string -- ) #! Given text to evaluate, create an A HREF link which when #! clicked sets the eval textarea to that value. @@ -115,13 +115,13 @@ USE: sequences #! Return an html fragment dispaying the source #! of the given word. dup dup - [ + {{ }} clone [ "browser" "responder" set - +
"Source" write
[ [ parse ] [ [ "No such word" write ] [ car see ] ifte ] catch ] with-simple-html-output
"Apropos" write "Usages" write
[ apropos. ] with-simple-html-output
[ apropos ] with-simple-html-output [ [ parse ] [ [ "No such word" write ] [ car usages. ] ifte ] catch ] with-simple-html-output
diff --git a/contrib/cont-responder/live-updater-responder.factor b/contrib/cont-responder/live-updater-responder.factor index db498ac73c..23800ba7d5 100644 --- a/contrib/cont-responder/live-updater-responder.factor +++ b/contrib/cont-responder/live-updater-responder.factor @@ -37,14 +37,14 @@ USE: prettyprint : live-search-apropos-word ( string -- ) #! Given a string that is a factor word, show the #! aporpos of that word. - [ + [ "browser" "responder" set
 
         stdio get  [   
-          apropos.
+          apropos
         ] with-stream              
     
- ] bind ; + ] with-scope ; : live-updater-responder ( -- ) [ @@ -57,7 +57,7 @@ USE: prettyprint [ [ - "millis" [ millis prettyprint ] "Display Server millis" live-anchor + "millis" [ millis pprint ] "Display Server millis" live-anchor
"The millisecond time from the server will appear here" write
diff --git a/contrib/cont-responder/live-updater.factor b/contrib/cont-responder/live-updater.factor index 1e4ca45178..950a695f24 100644 --- a/contrib/cont-responder/live-updater.factor +++ b/contrib/cont-responder/live-updater.factor @@ -34,11 +34,11 @@ USE: lists : get-live-updater-js* ( stream -- string ) #! Read all lines from the stream, creating a string of the result. - dup stream-readln dup [ , "\n" , get-live-updater-js* ] [ drop stream-close ] ifte ; + dup stream-readln dup [ % "\n" % get-live-updater-js* ] [ drop stream-close ] ifte ; : get-live-updater-js ( filename -- string ) #! Return the liveUpdater javascript code as a string. - [ get-live-updater-js* ] make-string ; + [ get-live-updater-js* ] "" make ; : live-updater-url ( -- url ) #! Generate an URL to the liveUpdater.js code. @@ -71,10 +71,10 @@ USE: lists #! fragment which is the output generated by calling #! 'quot'. That HTML fragment will be wrapped in a #! 'div' with the given id. - [ + [ "div-quot" set "div-id" set - ] extend [ + ] make-hash [ [ t "disable-initial-redirect?" set [ @@ -123,10 +123,10 @@ USE: lists #! 'div' with the given id. The 'quot' is called with #! a string on top of the stack. This is the input string #! entered in the live search input box. - [ + [ "div-quot" set "div-id" set - ] extend [ + ] make-hash [ [ t "disable-initial-redirect?" set #! Retrieve the search query value from the POST parameters. diff --git a/contrib/cont-responder/todo-example.factor b/contrib/cont-responder/todo-example.factor index 287e22b5ac..adcb400e8f 100644 --- a/contrib/cont-responder/todo-example.factor +++ b/contrib/cont-responder/todo-example.factor @@ -44,65 +44,65 @@ USE: sequences : todo-stylesheet ( -- string ) #! Return the stylesheet for the todo list - [ - "table.list {" , - " text-align:center;" , - " font-family: Verdana;" , - " font-weight: normal;" , - " font-size: 11px;" , - " color: #404040;" , - " background-color: #fafafa;" , - " border: 1px #6699cc solid;" , - " border-collapse: collapse;" , - " boder-spacing: 0px;" , - "}" , - "tr.heading {" , - " border-bottom: 2px solid #6699cc;" , - " border-left: 1px solix #6699cc;" , - " background-color: #BEC8D1;" , - " text-align: left;" , - " text-indent: 0px;" , - " font-family: verdana;" , - " font-weight: bold;" , - " color: #404040;" , - "}" , - "tr.item {" , - " border-bottom: 1px solid #9cf;" , - " border-top: 0px;" , - " border-left: 1px solid #9cf;" , - " border-right: 0px;" , - " text-align: left;" , - " text-indent: 2px;" , - " font-family: verdana, sans-serif, arial;" , - " font-weight: normal;" , - " color: #404040;" , - " background-color: #fafafa;" , - "}" , - "tr.complete {" , - " border-bottom: 1px solid #9cf;" , - " border-top: 0px;" , - " border-left: 1px solid #9cf;" , - " border-right: 0px;" , - " text-align: left;" , - " text-indent: 2px;" , - " font-family: verdana, sans-serif, arial;" , - " font-weight: normal;" , - " color: #404040;" , - " background-color: #ccc;" , - "}" , - "td.lbl {" , - " font-weight: bold; text-align: right;" , - "}" , - "tr.required {" , - " background: #FCC;" , - "}" , - "input:focus {" , - " background: yellow;" , - "}" , - "textarea:focus {" , - " background: yellow;" , - "}" , - ] make-string ; + { + "table.list {" + " text-align:center;" + " font-family: Verdana;" + " font-weight: normal;" + " font-size: 11px;" + " color: #404040;" + " background-color: #fafafa;" + " border: 1px #6699cc solid;" + " border-collapse: collapse;" + " boder-spacing: 0px;" + "}" + "tr.heading {" + " border-bottom: 2px solid #6699cc;" + " border-left: 1px solix #6699cc;" + " background-color: #BEC8D1;" + " text-align: left;" + " text-indent: 0px;" + " font-family: verdana;" + " font-weight: bold;" + " color: #404040;" + "}" + "tr.item {" + " border-bottom: 1px solid #9cf;" + " border-top: 0px;" + " border-left: 1px solid #9cf;" + " border-right: 0px;" + " text-align: left;" + " text-indent: 2px;" + " font-family: verdana, sans-serif, arial;" + " font-weight: normal;" + " color: #404040;" + " background-color: #fafafa;" + "}" + "tr.complete {" + " border-bottom: 1px solid #9cf;" + " border-top: 0px;" + " border-left: 1px solid #9cf;" + " border-right: 0px;" + " text-align: left;" + " text-indent: 2px;" + " font-family: verdana, sans-serif, arial;" + " font-weight: normal;" + " color: #404040;" + " background-color: #ccc;" + "}" + "td.lbl {" + " font-weight: bold; text-align: right;" + "}" + "tr.required {" + " background: #FCC;" + "}" + "input:focus {" + " background: yellow;" + "}" + "textarea:focus {" + " background: yellow;" + "}" + } concat ; : todo-stylesheet-url ( -- url ) #! Generate an URL for the stylesheet. @@ -234,7 +234,7 @@ USE: sequences : get-todo-filename ( database-path -- filename ) #! Get the filename containing the todo list details. - [ swap , todo-username , ".todo" , ] make-string ; + [ swap % todo-username % ".todo" % ] "" make ; : add-default-todo-item ( -- ) #! Add a default todo item. This is a workaround for the @@ -452,7 +452,7 @@ USE: sequences #! Write the table of items for the todo list. "heading" [ - [ "Priority" write ] [ "Complete?" write ] [ "Description" write ] [ "Action" write ] [ bl ] + [ "Priority" write ] [ "Complete?" write ] [ "Description" write ] [ "Action" write ] [ " " write ] ] styled-row todo-items [ write-item-row ] each
; @@ -473,7 +473,7 @@ USE: sequences : show-todo-list ( -- ) #! Show the current todo list. [ - [ "todo" get todo-username , "'s To Do list" , ] make-string + [ "todo" get todo-username % "'s To Do list" % ] "" make [ include-todo-stylesheet ] [ "todo" get write-item-table diff --git a/contrib/cont-responder/todo.factor b/contrib/cont-responder/todo.factor index 44507cec33..7b08bb2ea4 100644 --- a/contrib/cont-responder/todo.factor +++ b/contrib/cont-responder/todo.factor @@ -36,22 +36,23 @@ USE: prettyprint USE: hashtables USE: sequences USE: http +USE: unparser : ( user password -- ) #! Create an empty todo list - [ + [ "password" set "user" set f "items" set - ] extend ; + ] make-hash ; : ( priority description -- ) #! Create a todo item - [ + [ "description" set "priority" set f "complete?" set - ] extend ; + ] make-hash ; : add-todo-item ( -- ) #! Add the item to the todo list @@ -93,14 +94,14 @@ USE: http : read-todo ( -- ) #! Read a todo list from the current input stream. - read-line url-decode read-line url-decode - read-line str>number [ + readln url-decode readln url-decode + readln string>number [ dup - [ - read-line url-decode "yes" = "complete?" set - read-line url-decode "priority" set - read-line url-decode "description" set - ] extend add-todo-item + [ + readln url-decode "yes" = "complete?" set + readln url-decode "priority" set + readln url-decode "description" set + ] make-hash add-todo-item ] times ; : load-todo ( filename -- ) @@ -147,9 +148,10 @@ USE: http #! return the description for the todo list item. "description" swap hash ; -: priority-comparator ( item1 item2 -- bool ) - #! Return true if item1 is a higher priority than item2 - >r item-priority r> item-priority string> ; +: priority-comparator ( item1 item2 -- number ) + #! Return 0 if item equals item2, -1 if item1 < item2 and + #! 1 if item1 > item2. + >r item-priority r> item-priority lexi ; : todo-items ( -- alist ) #! Return a list of items for the given todo list. diff --git a/contrib/crypto/common.factor b/contrib/crypto/common.factor new file mode 100644 index 0000000000..0181b3f766 --- /dev/null +++ b/contrib/crypto/common.factor @@ -0,0 +1,68 @@ +IN: crypto +USING: kernel io strings sequences namespaces math prettyprint +unparser test parser lists ; + +: (shift-mod) ( n s w -- n ) + >r shift r> 1 swap shift mod ; + +: bitroll ( n s w -- n ) + #! Roll n by s bits to the left, wrapping around after + #! w bits. + [ mod ] keep + over 0 < [ [ + ] keep ] when + [ + (shift-mod) + ] 3keep + [ - ] keep (shift-mod) bitor ; + + +: w+ ( int -- int ) + + HEX: ffffffff bitand ; + +: nth-int ( string n -- int ) + 4 * dup 4 + rot subseq le> ; + +: nth-int-be ( string n -- int ) + 4 * dup 4 + rot subseq be> ; + +: float-sin ( int -- int ) + sin abs 4294967296 * >bignum ; + +: update ( num var -- ) + [ w+ ] change ; + +: update-old-new ( old new -- ) + [ get >r get r> ] 2keep >r >r w+ dup r> set r> set ; + +! calculate pad length. leave 8 bytes for length after padding +: zero-pad-length ( length -- pad-length ) + dup 64 mod 56 < 55 119 ? swap - ; ! one less for first byte of padding 0x80 + +! pad 0x80 then 00 til 8 bytes left, then 64bit length in bits +: pad-string-md5 ( string -- padded-string ) + [ + dup % "\u0080" % + dup length 64 mod zero-pad-length 0 fill % + dup length 8 * 8 >le % + ] "" make nip ; + +: pad-string-sha1 ( string -- padded-string ) + [ + dup % "\u0080" % + dup length 64 mod zero-pad-length 0 fill % + dup length 8 * 8 >be % + ] "" make nip ; + +: num-blocks ( length -- num ) + 64 /i ; + +: get-block ( string num -- string ) + 64 * dup 64 + rot subseq ; + +: hex-string ( str -- str ) + [ + [ + >hex 2 48 pad-left % + ] each + ] "" make ; + diff --git a/contrib/crypto/load.factor b/contrib/crypto/load.factor new file mode 100644 index 0000000000..2f76a42724 --- /dev/null +++ b/contrib/crypto/load.factor @@ -0,0 +1,7 @@ +IN: crypto +USING: parser sequences ; +[ + "contrib/crypto/common.factor" + "contrib/crypto/md5.factor" + "contrib/crypto/sha1.factor" +] [ run-file ] each diff --git a/contrib/crypto/md5.factor b/contrib/crypto/md5.factor index 469931d993..489345dfac 100644 --- a/contrib/crypto/md5.factor +++ b/contrib/crypto/md5.factor @@ -11,27 +11,12 @@ SYMBOL: old-b SYMBOL: old-c SYMBOL: old-d -: w+ ( int -- int ) - + HEX: ffffffff bitand ; - -: nth-int ( string n -- int ) - 4 * dup 4 + rot subseq le> ; - -: initialize ( -- ) +: initialize-md5 ( -- ) HEX: 67452301 dup a set old-a set HEX: efcdab89 dup b set old-b set HEX: 98badcfe dup c set old-c set HEX: 10325476 dup d set old-d set ; -: float-sin ( int -- int ) - sin abs 4294967296 * >bignum ; - -: update ( num var -- ) - [ w+ ] change ; - -: update-old-new ( old new -- ) - [ get >r get r> ] 2keep >r >r w+ dup r> set r> set ; - : update-md ( -- ) old-a a update-old-new old-b b update-old-new @@ -88,7 +73,7 @@ SYMBOL: old-d : S43 15 ; : S44 21 ; -: process-block ( block -- ) +: process-md5-block ( block -- ) S11 1 pick 0 nth-int [ F ] ABCD S12 2 pick 1 nth-int [ F ] DABC S13 3 pick 2 nth-int [ F ] CDAB @@ -160,34 +145,26 @@ SYMBOL: old-d drop ; -! calculate pad length. leave 8 bytes for length after padding -: md5-zero-pad-length ( length -- pad-length ) - dup 64 mod 56 < 55 119 ? swap - ; ! one less for first byte of padding 0x80 - -! pad 0x80 then 00 til 8 bytes left, then 64bit length in bits -: pad-string ( string -- padded-string ) - [ - dup % "\u0080" % - dup length 64 mod md5-zero-pad-length 0 fill % - dup length 8 * 8 >le % - ] make-string ; - -: num-blocks ( length -- num ) - 64 /i ; - -: get-block ( string num -- string ) - 64 * dup 64 + rot subseq ; - : get-md5 ( -- str ) [ [ a b c d ] [ get 4 >le % ] each - ] make-string hex-string ; + ] "" make hex-string ; : string>md5 ( string -- md5 ) [ - initialize pad-string - dup length num-blocks [ 2dup get-block process-block ] repeat - 2drop get-md5 + initialize-md5 pad-string-md5 + dup length num-blocks [ 2dup get-block process-md5-block ] repeat + drop get-md5 + ] with-scope ; + +: stream>md5 ( stream -- md5 ) + [ + contents string>md5 + ] with-scope ; + +: file>md5 ( file -- md5 ) + [ + stream>md5 ] with-scope ; : test-md5 ( -- ) diff --git a/contrib/crypto/sha1.factor b/contrib/crypto/sha1.factor new file mode 100644 index 0000000000..5de365454a --- /dev/null +++ b/contrib/crypto/sha1.factor @@ -0,0 +1,157 @@ +IN: crypto +USING: kernel io strings sequences namespaces math prettyprint +unparser test parser lists vectors hashtables kernel-internals ; + +! Implemented according to RFC 3174. + +SYMBOL: h0 +SYMBOL: h1 +SYMBOL: h2 +SYMBOL: h3 +SYMBOL: h4 +SYMBOL: A +SYMBOL: B +SYMBOL: C +SYMBOL: D +SYMBOL: E +SYMBOL: w +SYMBOL: K +SYMBOL: f-table + +: reset-w ( -- ) + 80 w set ; + +: initialize-sha1 ( -- ) + HEX: 67452301 dup h0 set A set + HEX: efcdab89 dup h1 set B set + HEX: 98badcfe dup h2 set C set + HEX: 10325476 dup h3 set D set + HEX: c3d2e1f0 dup h4 set E set + reset-w + [ + 20 [ HEX: 5a827999 , ] times + 20 [ HEX: 6ed9eba1 , ] times + 20 [ HEX: 8f1bbcdc , ] times + 20 [ HEX: ca62c1d6 , ] times + ] { } make K set ; + +: get-wth ( n -- wth ) + w get nth ; + +: shift-wth ( n -- ) + get-wth 1 32 bitroll ; + +! W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16)) +: sha1-W ( t -- W_t ) + dup 3 - get-wth + over 8 - get-wth bitxor + over 14 - get-wth bitxor + swap 16 - get-wth bitxor 1 32 bitroll ; + +! f(t;B,C,D) = (B AND C) OR ((NOT B) AND D) ( 0 <= t <= 19) +! f(t;B,C,D) = B XOR C XOR D (20 <= t <= 39) +! f(t;B,C,D) = (B AND C) OR (B AND D) OR (C AND D) (40 <= t <= 59) +! f(t;B,C,D) = B XOR C XOR D (60 <= t <= 79) + +! JUMP-TABLE: f 4 ( maximum ) +! {{ + ! [[ 0 [ >r over bitnot r> bitand >r bitand r> bitor ] ]] + ! [[ 1 [ bitxor bitxor ] ]] + ! [[ 2 [ 2dup bitand >r pick bitand >r bitand r> r> bitor bitor ] ]] + ! [[ 3 [ bitxor bitxor ] ]] +! }} f-table set + +! J: 0 f >r over bitnot r> bitand >r bitand r> bitor ; +! J: 1 f bitxor bitxor ; +! J: 2 f 2dup bitand >r pick bitand >r bitand r> r> bitor bitor ; +! J: 3 f bitxor bitxor ; + +! todo: make inlined +{ + { [ dup 0 = ] [ drop >r over bitnot r> bitand >r bitand r> bitor ] } + { [ dup 1 = ] [ drop bitxor bitxor ] } + { [ dup 2 = ] [ drop 2dup bitand >r pick bitand >r bitand r> r> bitor bitor ] } + { [ dup 3 = ] [ drop bitxor bitxor ] } +} f-table set + +: sha1-f ( B C D t -- f_tbcd ) + 20 /i f-table get cond ; + +: make-w ( -- ) + ! compute w, steps a-b of RFC 3174, section 6.1 + 80 [ dup 16 < [ + [ nth-int-be w get push ] 2keep + ] [ + dup sha1-W w get push + ] ifte + ] repeat ; + +: init-letters ( -- ) + ! step c of RFC 3174, section 6.1 + h0 get A set + h1 get B set + h2 get C set + h3 get D set + h4 get E set ; + +: calculate-letters ( -- ) + ! step d of RFC 3174, section 6.1 + 80 [ + ! TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t); + [ + [ B get C get D get ] keep sha1-f , + dup get-wth , + dup K get nth , + A get 5 32 bitroll , + E get , + ] { } make sum 4294967296 mod + + ! E = D; D = C; C = S^30(B); B = A; A = TEMP; + >r + D get E set + C get D set + B get 30 32 bitroll C set + A get B set + r> A set + ] repeat ; + +: update-hs ( -- ) + ! step e of RFC 3174, section 6.1 + A h0 update-old-new + B h1 update-old-new + C h2 update-old-new + D h3 update-old-new + E h4 update-old-new ; + +: process-sha1-block ( block -- ) + make-w init-letters calculate-letters update-hs drop ; + +: get-sha1 ( -- str ) + [ + [ h0 h1 h2 h3 h4 ] [ get 4 >be % ] each + ] "" make hex-string ; + +: string>sha1 ( string -- sha1 ) + [ + initialize-sha1 pad-string-sha1 + dup length num-blocks [ reset-w 2dup get-block process-sha1-block ] repeat + drop get-sha1 + ] with-scope ; + +: stream>sha1 ( stream -- sha1 ) + [ + contents string>sha1 + ] with-scope ; + +: file>sha1 ( file -- sha1 ) + [ + stream>sha1 + ] with-scope ; + +! unit test from the RFC +: test-sha1 ( -- ) + [ "a9993e364706816aba3e25717850c26c9cd0d89d" ] [ "abc" string>sha1 ] unit-test + [ "84983e441c3bd26ebaae4aa1f95129e5e54670f1" ] [ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" string>sha1 ] unit-test + ! [ "34aa973cd4c4daa4f61eeb2bdbad27316534016f" ] [ 1000000 CHAR: a fill string>sha1 ] unit-test ! takes a long time... + [ "dea356a2cddd90c7a7ecedc5ebb563934f460452" ] [ "0123456701234567012345670123456701234567012345670123456701234567" [ 10 [ dup % ] times ] "" make nip string>sha1 ] unit-test ; + diff --git a/contrib/gl/gl.factor b/contrib/gl/gl.factor index 31dc28ab56..a1f1b047ff 100644 --- a/contrib/gl/gl.factor +++ b/contrib/gl/gl.factor @@ -701,10 +701,10 @@ FUNCTION: void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) ; FUNCTION: void glPushMatrix ( ) ; FUNCTION: void glPopMatrix ( ) ; FUNCTION: void glLoadIdentity ( ) ; -FUNCTION: void glLoadMatrixd ( GLdouble *m ) ; -FUNCTION: void glLoadMatrixf ( GLfloat *m ) ; -FUNCTION: void glMultMatrixd ( GLdouble *m ) ; -FUNCTION: void glMultMatrixf ( GLfloat *m ) ; +FUNCTION: void glLoadMatrixd ( GLdouble* m ) ; +FUNCTION: void glLoadMatrixf ( GLfloat* m ) ; +FUNCTION: void glMultMatrixd ( GLdouble* m ) ; +FUNCTION: void glMultMatrixf ( GLfloat* m ) ; FUNCTION: void glRotated ( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ) ; FUNCTION: void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) ; FUNCTION: void glScaled ( GLdouble x, GLdouble y, GLdouble z ) ; @@ -892,10 +892,10 @@ FUNCTION: void glRectf ( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) ; FUNCTION: void glRecti ( GLint x1, GLint y1, GLint x2, GLint y2 ) ; FUNCTION: void glRects ( GLshort x1, GLshort y1, GLshort x2, GLshort y2 ) ; -FUNCTION: void glRectdv ( GLdouble *v1, GLdouble *v2 ) ; -FUNCTION: void glRectfv ( GLfloat *v1, GLfloat *v2 ) ; -FUNCTION: void glRectiv ( GLint *v1, GLint *v2 ) ; -FUNCTION: void glRectsv ( GLshort *v1, GLshort *v2 ) ; +FUNCTION: void glRectdv ( GLdouble* v1, GLdouble* v2 ) ; +FUNCTION: void glRectfv ( GLfloat* v1, GLfloat* v2 ) ; +FUNCTION: void glRectiv ( GLint* v1, GLint* v2 ) ; +FUNCTION: void glRectsv ( GLshort* v1, GLshort* v2 ) ; ! Vertex Arrays (1.1) diff --git a/contrib/parser-combinators/lazy-examples.factor b/contrib/parser-combinators/lazy-examples.factor index 94db1f3346..19f31446d3 100644 --- a/contrib/parser-combinators/lazy-examples.factor +++ b/contrib/parser-combinators/lazy-examples.factor @@ -42,7 +42,7 @@ USE: namespaces #! each successive value being the result of applying quot to #! n. swap dup unit delay -rot - [ , dup , \ call , , \ lfrom-by , ] make-list delay lcons ; + [ , dup , \ call , , \ lfrom-by , ] [ ] make delay lcons ; : lnaturals 0 lfrom ; : lpositves 1 lfrom ; diff --git a/contrib/parser-combinators/lazy.factor b/contrib/parser-combinators/lazy.factor index 62ee083370..0e0e435e2b 100644 --- a/contrib/parser-combinators/lazy.factor +++ b/contrib/parser-combinators/lazy.factor @@ -80,7 +80,7 @@ DEFER: lnil : lcons ( lcar lcdr -- promise ) #! Given a car and cdr, both lazy values, return a lazy cons. - swap [ , , \ , ] make-list delay ; + swap [ , , \ , ] [ ] make delay ; : lunit ( lvalue -- llist ) #! Given a lazy value (a quotation that when called produces @@ -102,8 +102,8 @@ DEFER: lnil drop ] [ swap 2dup - [ , \ lcdr , , \ lmap , ] make-list delay >r - [ , \ lcar , , \ call , ] make-list delay r> + [ , \ lcdr , , \ lmap , ] [ ] make delay >r + [ , \ lcar , , \ call , ] [ ] make delay r> lcons ] ifte ; @@ -117,8 +117,8 @@ DEFER: lnil nip ] [ swap dupd ( llist llist n -- ) - [ [ 1 - ] cons , \ call , , \ lcdr , \ ltake , ] make-list delay >r - [ , \ lcar , ] make-list delay r> + [ [ 1 - ] cons , \ call , , \ lcdr , \ ltake , ] [ ] make delay >r + [ , \ lcar , ] [ ] make delay r> lcons ] ifte ] ifte ; @@ -283,7 +283,7 @@ DEFER: list>llist [ 1 2 3 ] list>llist [ 4 5 6 ] list>llist [ 7 8 9 ] list>llist - 3list + 2list cons list>llist lappend* ; diff --git a/contrib/parser-combinators/parser-combinators.factor b/contrib/parser-combinators/parser-combinators.factor index 621491c63b..2db044dba8 100644 --- a/contrib/parser-combinators/parser-combinators.factor +++ b/contrib/parser-combinators/parser-combinators.factor @@ -27,6 +27,7 @@ USE: sequences USE: strings USE: lists USE: math +USE: io GENERIC: phead @@ -398,94 +399,3 @@ DEFER: <*> #! Return a parser that optionally uses the parser #! if that parser would be successfull. [ () call ] cons ; - -USE: prettyprint -USE: parser -USE: unparser -USE: io - -! Testing <&> -: test1 "abcd" "a" token "b" token <&> call [ . ] leach ; -: test1a "abcd" "a" token "b" token <&> "c" token <&> call [ . ] leach ; -: test1b "abcd" "a" token "b" token "c" token <&> <&> call [ . ] leach ; -: test2 "decd" "a" token "b" token <&> call [ . ] leach ; -: test3 "dbcd" "a" token "b" token <&> call [ . ] leach ; -: test4 "adcd" "a" token "b" token <&> call [ . ] leach ; - -! Testing <|> -: test5 "abcd" "a" token "b" token <|> call [ . ] leach ; -: test6 "bbcd" "a" token "b" token <|> call [ . ] leach ; -: test7 "cbcd" "a" token "b" token <|> call [ . ] leach ; - -! Testing sp -: test8 " abcd" "a" token call [ . ] leach ; -: test9 " abcd" "a" token sp call [ . ] leach ; - -! Testing just -: test10 "abcd" "abcd" token "abc" token <|> call [ . ] leach ; -: test11 "abcd" "abcd" token "abc" token <|> just call [ . ] leach ; - -! Testing <@ -: test12 "01234" [ digit? ] satisfy call [ . ] leach ; -: test13 "01234" [ digit? ] satisfy [ digit> ] <@ call [ . ] leach ; - -! Testing some -: test14 "begin1" "begin" token call [ . ] leach ; -: test15 "This should fail with an error" print - "begin1" "begin" token some call . ; -: test16 "begin" "begin" token some call . ; - -! parens test function -: parens ( -- parser ) - #! Return a parser that parses nested parentheses. - [ "(" token parens <&> ")" token <&> parens <&> epsilon <|> call ] ; - -: test17 "" parens call [ . ] leach ; -: test18 "()" parens call [ . ] leach ; -: test19 "((()))" parens call [ . ] leach ; - -! <& parser and &> parser -: test20 "abcd" "a" token "b" token <&> call [ . ] leach ; -: test21 "abcd" "a" token "b" token <& call [ . ] leach ; -: test22 "abcd" "a" token "b" token &> call [ . ] leach ; - -! nesting example -: parens-open "(" token ; -: parens-close ")" token ; -: nesting - [ parens-open - nesting &> - parens-close <& - nesting <&> - [ unswons 1 + max ] <@ - 0 succeed <|> - call ] ; - -: test23 "" nesting just call [ . ] leach ; -: test24 "()" nesting just call [ . ] leach ; -: test25 "(())" nesting just call [ . ] leach ; -: test26 "()(()(()()))()" nesting just call [ . ] leach ; - -! Testing <*> and <:&> -: test27 "1234" "1" token <*> call [ . ] leach ; -: test28 "1111234" "1" token <*> call [ . ] leach ; -: test28a "1111234" "1" token <*> [ car concat unit ] <@ call [ . ] leach ; -: test29 "234" "1" token <*> call [ . ] leach ; -: pdigit [ digit? ] satisfy [ digit> ] <@ ; -: pnatural pdigit <*> ; -: pnatural2 pnatural [ car [ >digit ] map >string dup pempty? [ drop 0 ] [ str>number ] ifte unit ] <@ ; -: test30 "12345" pnatural2 call [ . ] leach ; - -! Testing <+> -: test31 "1234" "1" token <+> call [ . ] leach ; -: test32 "1111234" "1" token <+> call [ . ] leach ; -: test33 "234" "1" token <+> call [ . ] leach ; - -! Testing -: test34 "ab" "a" token pdigit <&> "b" token <&> call [ . ] leach ; -: test35 "ac" "a" token pdigit <&> "b" token <&> call [ . ] leach ; -: test36 "a5b" "a" token pdigit <&> "b" token <&> call [ . ] leach ; -: pinteger "-" token pnatural2 <&> [ uncons swap [ car -1 * ] when ] <@ ; -: test37 "123" pinteger call [ . ] leach ; -: test38 "-123" pinteger call [ . ] leach ; - diff --git a/contrib/parser-combinators/parser-combinators.html b/contrib/parser-combinators/parser-combinators.html index 1e14501207..33aeaba902 100644 --- a/contrib/parser-combinators/parser-combinators.html +++ b/contrib/parser-combinators/parser-combinators.html @@ -7,7 +7,9 @@

Parsers

The parser combinator library described here is based on a library written for the Clean pure functional programming language and - described in chapter 5 of the 'Clean Book'. Based on the description + described in chapter 5 of the 'Clean Book' (PDF + available here). Based on the description in that chapter I developed a version for Factor, a concatenative language.

A parser is a word or quotation that, when called, processes diff --git a/contrib/parser-combinators/tests.factor b/contrib/parser-combinators/tests.factor new file mode 100644 index 0000000000..1bfe3d5c46 --- /dev/null +++ b/contrib/parser-combinators/tests.factor @@ -0,0 +1,260 @@ +! Copyright (C) 2005 Chris Double. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, +! this list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +IN: scratchpad +USING: kernel lazy parser-combinators test errors strings parser lists math sequences unparser ; + +! Testing <&> +[ [ [[ "cd" [[ "a" "b" ]] ]] ] ] [ + "abcd" "a" token "b" token <&> call llist>list +] unit-test + +[ [ [[ "d" [[ [[ "a" "b" ]] "c" ]] ]] ] ] [ + "abcd" "a" token "b" token <&> "c" token <&> call llist>list +] unit-test + +[ [ [[ "d" [[ "a" [[ "b" "c" ]] ]] ]] ] ] [ + "abcd" "a" token "b" token "c" token <&> <&> call llist>list +] unit-test + +[ f ] [ + "decd" "a" token "b" token <&> call llist>list +] unit-test + +[ f ] [ + "dbcd" "a" token "b" token <&> call llist>list +] unit-test + +[ f ] [ + "adcd" "a" token "b" token <&> call llist>list +] unit-test + +! Testing <|> +[ [ [[ "bcd" "a" ]] ] ] [ + "abcd" "a" token "b" token <|> call llist>list +] unit-test + +[ [ [[ "bcd" "b" ]] ] ] [ + "bbcd" "a" token "b" token <|> call llist>list +] unit-test + +[ f ] [ + "cbcd" "a" token "b" token <|> call llist>list +] unit-test + +! Testing sp +[ f ] [ + " abcd" "a" token call llist>list +] unit-test + +[ [ [[ "bcd" "a" ]] ] ] [ + " abcd" "a" token sp call llist>list +] unit-test + +! Testing just +[ [ [[ "" "abcd" ]] [[ "d" "abc" ]] ] ] [ + "abcd" "abcd" token "abc" token <|> call llist>list +] unit-test + +[ [ [[ "" "abcd" ]] ] ] [ + "abcd" "abcd" token "abc" token <|> just call llist>list +] unit-test + +! Testing <@ +[ [ [[ "1234" 48 ]] ] ] [ + "01234" [ digit? ] satisfy call llist>list +] unit-test + +[ [ [[ "1234" 0 ]] ] ] [ + "01234" [ digit? ] satisfy [ digit> ] <@ call llist>list +] unit-test + +! Testing some +[ [ [[ "1" "begin" ]] ] ] [ + "begin1" "begin" token call llist>list +] unit-test + +[ + "begin1" "begin" token some call +] unit-test-fails + +[ "begin" ] [ + "begin" "begin" token some call +] unit-test + +! parens test function +: parens ( -- parser ) + #! Return a parser that parses nested parentheses. + [ "(" token parens <&> ")" token <&> parens <&> epsilon <|> call ] ; + +[ [ [[ "" "" ]] ] ] [ + "" parens call llist>list +] unit-test + +[ + [[ "" [[ [[ [[ "(" "" ]] ")" ]] "" ]] ]] + [[ "()" "" ]] +] [ + "()" parens call [ ] leach +] unit-test + +[ [[ "((()))" "" ]] ] [ + "((()))" parens call lcdr lcar +] unit-test + +! <& parser and &> parser +[ [ [[ "cd" [[ "a" "b" ]] ]] ] ] [ + "abcd" "a" token "b" token <&> call llist>list +] unit-test + +[ [ [[ "cd" "a" ]] ] ] [ + "abcd" "a" token "b" token <& call llist>list +] unit-test + +[ [ [[ "cd" "b" ]] ] ] [ + "abcd" "a" token "b" token &> call llist>list +] unit-test + +! nesting example +: parens-open "(" token ; +: parens-close ")" token ; +: nesting + [ parens-open + nesting &> + parens-close <& + nesting <&> + [ unswons 1 + max ] <@ + 0 succeed <|> + call ] ; + +[ [ [[ "" 0 ]] ] ] [ + "" nesting just call llist>list +] unit-test + +[ [ [[ "" 1 ]] ] ] [ + "()" nesting just call llist>list +] unit-test + +[ [ [[ "" 2 ]] ] ] [ + "(())" nesting just call llist>list +] unit-test + +[ [ [[ "" 3 ]] ] ] [ + "()(()(()()))()" nesting just call llist>list +] unit-test + +! Testing <*> and <:&> +[ [ [ "234" [ "1" ] ] [ "1234" ] ] ] [ + "1234" "1" token <*> call llist>list +] unit-test + +[ + [ "234" [ "1" "1" "1" "1" ] ] + [ "1234" [ "1" "1" "1" ] ] + [ "11234" [ "1" "1" ] ] + [ "111234" [ "1" ] ] + [ "1111234" ] +] [ + "1111234" "1" token <*> call [ ] leach +] unit-test + +[ + [ "234" "1111" ] + [ "1234" "111" ] + [ "11234" "11" ] + [ "111234" "1" ] + [ "1111234" f ] +] [ + "1111234" "1" token <*> [ car concat unit ] <@ call [ ] leach +] unit-test + +[ [ "234" ] ] [ + "234" "1" token <*> call [ ] leach +] unit-test + +: pdigit [ digit? ] satisfy [ digit> ] <@ ; +: pnatural pdigit <*> ; +: pnatural2 pnatural [ car [ >digit ] map >string dup pempty? [ drop 0 ] [ string>number ] ifte unit ] <@ ; + +[ + [ "" 12345 ] + [ "5" 1234 ] + [ "45" 123 ] + [ "345" 12 ] + [ "2345" 1 ] + [ "12345" 0 ] +] [ + "12345" pnatural2 call [ ] leach +] unit-test + +! Testing <+> +[ [ "234" [ "1" ] ] ] [ + "1234" "1" token <+> call [ ] leach +] unit-test + +[ + [ "234" [ "1" "1" "1" "1" ] ] + [ "1234" [ "1" "1" "1" ] ] + [ "11234" [ "1" "1" ] ] + [ "111234" [ "1" ] ] +] [ + "1111234" "1" token <+> call [ ] leach +] unit-test + +[ ] [ + "234" "1" token <+> call [ ] leach +] unit-test + +! Testing +[ [[ "" [[ [ "a" ] "b" ]] ]] ] [ + "ab" "a" token pdigit <&> "b" token <&> call [ ] leach +] unit-test + +[ ] [ + "ac" "a" token pdigit <&> "b" token <&> call [ ] leach +] unit-test + +[ [[ "" [[ [ "a" 5 ] "b" ]] ]] ] [ + "a5b" "a" token pdigit <&> "b" token <&> call [ ] leach +] unit-test + +: pinteger "-" token pnatural2 <&> [ uncons swap [ car -1 * ] when ] <@ ; + +[ + [ "" 123 ] + [ "3" 12 ] + [ "23" 1 ] + [ "123" 0 ] +] [ + "123" pinteger call [ ] leach +] unit-test + +[ + [[ "" -123 ]] + [[ "3" -12 ]] + [[ "23" -1 ]] + [[ "123" 0 ]] + [ "-123" 0 ] +] [ + "-123" pinteger call [ ] leach +] unit-test + diff --git a/doc/bootstrap.txt b/doc/bootstrap.txt deleted file mode 100644 index b828542359..0000000000 --- a/doc/bootstrap.txt +++ /dev/null @@ -1,212 +0,0 @@ -THE BOOTSTRAP PROCESS - -* Why bother? - -Factor cannot be built entirely from source. That is, certain parts -- -such as the parser itself -- are written in entirely in Factor, thus to -build a new Factor system, one needs to be running an existing Factor -system. - -The Factor runtime, coded in C, knows nothing of the syntax of Factor -source files, or even the organization of words into vocabularies. Most -conventional languages fall into two implementation styles: - -- A single monolithic executable is shipped, with most of the language -written in low level code. This includes Python, Perl, and so on. This -approach has the disadvantage that the language is less flexible, due to -the large native substrate. - -- A smaller interpreter/compiler is shipped, that reads bytecode or -source files from disk, and constructs the standard library on startup. -This has the disadvantage of slow startup time. This includes Java. - -* How does it work? - -Factor takes a superior approach, used by Lisp and Smalltalk -implementations, where initialization consists of loading a memory -image. Execution then begins immediately. New images can be generated in -one of two ways: - -- Saving the current memory heap to disk as a new image file. - -This is easily done and easily implemented: - - "foo.image" save-image - -Since this simply saves a copy of the entire heap to a file, no more -will be said about it here. - -- Generating a new image from sources. - -If the former was the only way to save code changes to an image, things -would be out of hand. For example, if the runtime's object format has to -change, one would have to write a tool to read an image, convert each -object, and write it out again. Or if new primitives were added, or the -major parts of the library needed a reorganization... things would get -messy. - -Generating a new image from source is called 'bootstrapping'. -Bootstrapping is the topic of the remainder of this document. - -Some terminology: the current running Factor image, the one generating -the bootstrap image, is a 'host' image; the bootstrap image being -generated is a 'target' image. - -* General overview of the bootstrap process - -While Factor cannot be built entirely from source, bootstrapping allows -one to use an existing Factor implementation, that is up to date with -respect to the sources one is bootstrapping from, to build a new image -in a reasonably clean and controlled manner. - -Bootstrapping proceeds in two stages: - -- In first stage, the make-image word is used to generate a stage 1 -image. The make-image word is defined in /library/bootstrap, and is -called like so: - - "foo.image" make-image - -Unlike save-image, make-image actually writes out each object -'manually', without dumping memory; this allows the object format to be -changed, by modifying /library/bootstrap/image.factor. - -- In the second stage, one runs the Factor interpreter, passing the -stage 1 image on the command line. The stage 1 image then proceeds to -load remaining source files from disk, finally producing a completed -image, that can in turn make new images, etc. - -Now, lets look at each stage in detail. - -* Stage 1 bootstrap - -The first stage is by far the most interesting. - -Take a careful look at the words for searching vocabularies in -/library/vocabularies.factor. - -They all access the vocabulary hash by accessing the 'vocabulary' -variable in the current namespace; so if one calls these words in a -dynamic scope where this variable is set to something other than the -global vocabulary hash, interesting things can happen. - -(Note there is little risk of accidental capture here; you can name a -variable 'vocabularies', and it won't clash unless you actually define -it as a symbol in the 'words' vocabulary, which you won't do.) - -** Setting up the target environment - -After initializing some internal objects, make-image runs the file -/library/bootstrap/boot.factor. Bootstrapping is performed in new -dynamic scope, so that vocabularies can be overriden. - -The first file run by bootstrapping is -/library/bootstrap/primitives.factor. - -This file sets up an initially empty target image vocabulary hash; then, -it copies 'syntax' and 'generic' vocabularies from the host vocabulary -hash to the target vocabulary hash. Then, it adds new words, one for -each primitive, to the target vocabulary hash. - -Files are run after being fully parsed; since the host vocabulary hash -is in scope when primitives.factor is parsed, primitives.factor can -still make use of host words. However, after primitives.factor is run, -the bootstrap vocabulary is very bare; containing syntax parsing and -primitives only. - -** Bootstrapping the core library - -Bootstrapping then continues, and loads various source files into the -target vocabulary hash. Each file loaded must only refer to primitive -words, and words loaded from previous files. So by reading through each -file referenced by boot.factor, you can see the entire construction of -the core of Factor, from the bottom up! - -After most files being loaded, there is still a problem; the 'syntax' -and 'generic' vocabularies in the target image were copied from the host -image, and not loaded from source. The generic vocabulary is overwritten -near the end of bootstrap, by loading in the relevant source files. - -(The reason 'generic' words have to be copied first, and not loaded in -order, is that the parsing words in this vocabulary are used to define -dispatch classes. This will be documented separately.) - -** Bootstrapping syntax parsing words - -So much for 'generic'. Bootstrapping the syntax words is a slightly -tougher problem. Since the syntax vocabulary parses source files itself, -a delicate trick must be performed. - -Take a look at the start of /library/syntax/parse-syntax.factor: - -IN: !syntax -USE: syntax - -This file defines parsing words such as [ ] : ; and so on. As you can -see, the file itself is parsed using the host image 'syntax' vocabulary, -but the new parsing words are defined in a '!syntax' vocabulary. - -After loading parse-syntax.factor, boot.factor then flips the two -vocabularies, and renames each word in '!syntax': - -vocabularies get [ - "!syntax" get "syntax" set - - "syntax" get [ - cdr dup word? [ - "syntax" "vocabulary" set-word-property - ] [ - drop - ] ifte - ] hash-each -] bind - -"!syntax" vocabularies get remove-hash - -The reason parse-syntax.factor can't do IN: syntax is that because about -half way through parsing it, its own words would start executing. But we -can *never* execute target image words in the host image -- for example, -the target image might have a different set of primitives, different -runtime layout, and so on. - -* Saving the stage 1 image - -Once /library/bootstrap/boot.factor completes executing, make-image -resumes, and it now has a nice, shiny new vocabularies hash ready to -save to a target image. It then outputs this hash to a file, along with -various auxilliary objects, using the precise object format required by -the runtime. - -It also outputs a 'boot quotation'. The boot quotation is executed by -the interpreter as soon as the target image is loaded, and leads us to -stage 2; but first, a little hack. - -** The transfer hack - -Some parsing words generate code in the target image vocabulary. -However, since the host image parsing words are actually executing -during bootstrap, the generated code refers to host image words. The -bootstrapping code performs a 'transfer' where each host image word that -is referred to in the target image is replaced with the -identically-named target image word. - -* On to stage 2 - -The boot quotation left behind from stage 1 simply runs the -/library/bootstrap/boot-stage2.factor file. - -This file begins by reloading each source file loaded in stage 1. This -is for convinience; after changing some core library files, it is faster -for the developer to just redo stage 2, and get an up to date image, -instead of doing the whole stage 1 process again. - -After stage 1 has been redone, stage 2 proceeds to load more library -files. Basically, stage 1 only has barely enough to begin parsing source -files from disk; stage 2 loads everything else, like development tools, -the compiler, HTTP server. etc. - -Stage 2 finishes by running /library/bootstrap/init-stage2.factor, which -infers stack effects and performs various cleanup tasks. Then, it uses -the 'save-image' word to save a memory dump, which becomes a shiny new -'factor.image', ready for hacking, and ready for bootstrapping more new -images! diff --git a/doc/comparison.tex b/doc/comparison.tex index 27fa2b6802..0c4e7999e0 100644 --- a/doc/comparison.tex +++ b/doc/comparison.tex @@ -119,7 +119,7 @@ DEFER: second-word-to-be-defined \end{verbatim} before the definition of the first word. -Factor supports named variables. This doesn't destroy concatenativity, though, because +Factor supports named variables. This doesn't destroy concatenativity, though, because words and quotations are not boundaries for it at all; dynamic scope is used. \section{Common Lisp and Scheme} diff --git a/doc/handbook.tex b/doc/handbook.tex index a1cfe92da5..6601294243 100644 --- a/doc/handbook.tex +++ b/doc/handbook.tex @@ -10,6 +10,7 @@ \usepackage{epsfig} \usepackage{amssymb} \usepackage{epstopdf} +%\usepackage{fancyref} \pagestyle{headings} @@ -75,7 +76,7 @@ \chapter*{Foreword} -This handbook documents release 0.76 of the Factor programming language. +This handbook documents release 0.77 of the Factor programming language. Note that this handbook is not a tutorial or introductory guide, nor does it cover some background material that you are expected to understand, such as object-oriented programming, higher-order functions, continuations, or general algorithm and program design. @@ -173,7 +174,6 @@ The following naming conventions are used in the Factor library. \item[\texttt{foo-with}] a form of the \texttt{foo} combinator that takes an extra object, and passes this object on each iteration of the quotation; for example, \texttt{each-with} and \texttt{map-with} \item[\texttt{from>}] converts an instance of the \texttt{from} class into some canonical form \item[\texttt{from>to}] convert an instance of the \texttt{from} class to the \texttt{to} class -\item[\texttt{make-foo}] executes a quotation in a namespace where a sequence of type \texttt{foo} is being constructed; for example, \texttt{make-string} \item[\texttt{>s}] move top of data stack to the \texttt{s} stack, where \texttt{s} is either \texttt{r} (call stack), \texttt{n} (name stack), or \texttt{c} (catch stack). Sometimes, libraries will define their own words following this naming convention, to implement user-defined stacks, typically stored in variables \item[\texttt{s>}] move top of \texttt{s} stack to the data stack, where \texttt{s} is as above \item[\texttt{style}] an association list holding text formatting information, possible keys are described in \ref{styles} @@ -189,8 +189,8 @@ This guide uses the standard mathematical notation to denote intervals. Notation&Meaning\\ \hline $(a,b)$&All numbers from $a$ to $b$, excluding $a$ and $b$\\ -$[a,b)$&All numbers from $a$ to $b$, including $a$ and excluding and $b$\\ -$(a,b]$&All numbers from $a$ to $b$, excluding $a$ and including and $b$\\ +$[a,b)$&All numbers from $a$ to $b$, including $a$ and excluding $b$\\ +$(a,b]$&All numbers from $a$ to $b$, excluding $a$ and including $b$\\ $[a,b]$&All numbers from $a$ to $b$, including $a$ and $b$ \end{tabular} @@ -233,7 +233,7 @@ parsing words. Tokens are appended to the parse tree, the top level of which is returned by the original parser invocation. Nested levels of the parse tree are created by parsing words. -Here is the parser algorithm in more detail -- some of the concepts therein will be defined shortly: +The parser iterates through the input text, checking each character in turn. Here is the parser algorithm in more detail -- some of the concepts therein will be defined shortly: \begin{itemize} \item If the current character is a double-quote (\texttt{"}), the \texttt{"} parsing word is executed, causing a string to be read. @@ -280,7 +280,9 @@ description={a collection of words, uniquely identified by name. The hashtable o A \emph{word} is a code definition identified by a name. Words are sorted into \emph{vocabularies}. Words are discussed in depth in \ref{words}. When the parser reads a token, it attempts to look up a word named by that token. The -lookup is performed in the parser's current vocabulary set. +lookup is performed by searching each vocabulary in the search path, in order. + +Due to the way the parser works, words cannot be referenced before they are defined; that is, source files must order definitions in a strictly bottom-up fashion. For a way around this, see \ref{deferred}. For a source file the vocabulary search path starts off with two vocabularies: \begin{verbatim} @@ -291,7 +293,7 @@ The \texttt{syntax} vocabulary consists of a set of parsing words for reading Fa and defining new words. The \texttt{scratchpad} vocabulary is the default vocabulary for new word definitions. -At the interactive listener, the default search path contains many more vocabularies. The default search path depends on how the parser was invoked (\ref{parsing-quotations}). +At the interactive listener, the default search path contains many more vocabularies. Details on the default search path and parser invocation are found in \ref{parser-chapter}. \wordtable{ \vocabulary{syntax} \parsingword{USE:}{USE: \emph{vocabulary}} @@ -301,7 +303,7 @@ name=search path, description={the list of vocabularies that the parser looks up tokens in. You can add to this list with the \texttt{USE:} and \texttt{USING:} parsing words}}} \useglos -The \texttt{USE:} parsing word adds a new vocabulary at the front of the search path. Subsequent word lookups by the parser will search this vocabulary first. +Adds a new vocabulary at the front of the search path. Subsequent word lookups by the parser will search this vocabulary first. \begin{alltt} USE: lists \end{alltt} @@ -314,7 +316,41 @@ Consecutive \texttt{USE:} declarations can be merged into a single \texttt{USING USING: lists strings vectors ; \end{alltt} -Due to the way the parser works, words cannot be referenced before they are defined; that is, source files must order definitions in a strictly bottom-up fashion. For a way around this, see \ref{deferred}. +\wordtable{ +\vocabulary{syntax} +\parsingword{IN:}{IN:~\emph{vocabulary}} +} +Sets the current vocabulary for new word definitions, and adds the vocabulary at the front of the search path (\ref{vocabsearch}). + +Here is an example demonstrating the vocabulary search path. If you can understand this example, then you have grasped vocabularies. +\begin{verbatim} +IN: foe +USE: sequences + +: append + #! Prints a message, then calls sequences::append. + "foe::append calls sequences::append" print append ; + +IN: fee + +: append + #! Loops, calling fee::append. + "fee::append calls fee::append" print append ; + +USE: foe + +: append + #! Redefining fee::append to call foe::append. + "fee::append calls foe::append" print append ; + +"1234" "5678" append print +\end{verbatim} +When placed in a source file and run, the above code produces the following output: +\begin{verbatim} +fee::append calls foe::append +foe::append calls sequences::append +12345678 +\end{verbatim} \section{Numbers} @@ -486,7 +522,7 @@ Escape code&Character\\ \texttt{\bs{}s}&Space\\ \texttt{\bs{}t}&Tab\\ \texttt{\bs{}n}&Newline\\ -\texttt{\bs{}t}&Carriage return\\ +\texttt{\bs{}r}&Carriage return\\ \texttt{\bs{}0}&Null byte (ASCII 0)\\ \texttt{\bs{}e}&Escape (ASCII 27)\\ \texttt{\bs{}"}&Double quote (\texttt{"})\\ @@ -568,16 +604,20 @@ Lists are documented in \ref{lists}. \subsection{Words} -While words parse as themselves, a word occurring inside a quotation is executed when the quotation is called. Sometimes it is desirable to have a word be pushed on the data stack during the execution of a quotation, usually for reflective access to the word's slots. +\newcommand{\wrapglos}{ +\glossary{ +name=wrapper, +description={an instance of the \texttt{wrapper} class, holding a reference to a single object. When the evaluator encounters a wrapper, it pushes the wrapped object on the data stack. Wrappers are used to push words literally on the data stack}}} +\wrapglos +While words parse as themselves, a word occurring inside a quotation is executed when the quotation is called. Sometimes it is desirable to have a word be pushed on the data stack during the execution of a quotation. The canonical use-case for this is passing the word to the \verb|execute| word (\ref{quotations}), or alternatively, reflectively accessing word properties (\ref{word-props}). \wordtable{ \vocabulary{syntax} \parsingword{\bs}{\bs~\emph{word}} } -Reads the next word from the input string and appends some \emph{code} to the parse tree that pushes the word on the stack when the code is called. The following two lines are equivalent: -\begin{verbatim} -\ length -[ length ] car -\end{verbatim} +Reads the next word from the input string and appends a \emph{wrapper} holding the word to the parse tree. When the evaluator encounters a wrapper, it pushes the wrapped object literally on the data stack. + +Wrappers and the implementation of the \verb|\| word are discussed in detail in \ref{reading-ahead}. + \wordtable{ \vocabulary{syntax} \parsingword{POSTPONE:}{POSTPONE: \emph{word}} @@ -626,7 +666,7 @@ Reads from the input string until the next occurrence of \texttt{"}, converts the string to a string buffer, and appends it to the parse tree. As with strings, the escape codes described in \ref{syntax:char} are permitted. \begin{alltt} - SBUF" Hello world" sbuf>string print + SBUF" Hello world" >string print \textbf{Hello world} \end{alltt} @@ -680,35 +720,13 @@ description={an instance of a user-defined class whose metaclass is the \texttt{ \parsingword{<<}{<<} \parsingword{>>}{>>} } -Parses a tuple. The tuple's class must follow \texttt{<<}. The element after that is always the tuple's delegate. Further elements until \texttt{>>} are specified according to the tuple's slot definition, and an error is raised if an incorrect number of elements is given. +Parses a tuple. The tuple's class must follow \texttt{<<}. The element after that is always the tuple's delegate. Further elements until \texttt{>>} are specified according to the tuple's slot definition. If an insufficient number of elements is given, the remaining slots of the tuple are set to \verb|f|. Listing too many elements raises a parse error. \begin{verbatim} << color f 255 0 0 >> \end{verbatim} Tuples are documented in \ref{tuples}. -\subsection{Matrices}\label{syntax:matrices} -\newcommand{\matrixglos}{\glossary{ -name=matrix, -description={an instance of the \texttt{matrix} class, representing a mathematical matrix of numbers}}} -\matrixglos -\wordtable{ -\vocabulary{syntax} -\parsingword{M[}{M[} -\parsingword{]M}{]M} -} -Parses a matrix. A matrix is specified as a set of rows, and each row is written like a list and must have the same length. The following is an example: -\begin{verbatim} -M[ [ 3 -5 1 ] - [ -2 7 1/2 ] ]M -\end{verbatim} -It corresponds to the following mathematical matrix: -$$\left( \begin{array}{c c c} -3 & -5 & 1 \\ --2 & 7 & \frac{1}{2} -\end{array} \right)$$ -Matrices are documented in \ref{matrices}. - \section{Comments}\label{comments} \wordtable{ @@ -808,13 +826,18 @@ name=call frame, description=the currently executing quotation}} \cfglos \glossary{ +name=evaluator, +description={a process by which code is evaluated, taking quotations as input. Two possibilities are the interpreter, which evaluates a quotation directly, and the compiler, which transforms quotations into machine code which evaluates the quotation when invoked}} +\glossary{ name=interpreter, description=executes quotations by iterating them and recursing into nested definitions. see compiler} \glossary{ name=quotation, description=a list containing Factor code to be executed} -The Factor interpreter executes quotations. Quotations are lists, and since lists can contain any Factor object, they can contain words. It is words that give quotations their operational behavior, as you can see in the following description of the interpreter algorithm. +A Factor evaluator executes quotations. Quotations are lists, and since lists can contain any Factor object, they can contain words. It is words that give quotations their operational behavior, as you can see in the following description of the evaluator algorithm. + +The Factor interpreter performs the below steps literally. The compiler generates machine code which perform the steps in a more efficient manner than the interpreter (\ref{compiler}). \begin{itemize} \item If the call frame is \texttt{f}, the call stack is popped and becomes the new call frame. @@ -825,12 +848,13 @@ The Factor interpreter executes quotations. Quotations are lists, and since list \item If the word is compiled or primitive, the interpreter jumps to a machine code definition. See \ref{primitives}. \item If the word is undefined, an error is raised. See \ref{deferred}. \end{itemize} +\item If the car of the call frame is a wrapper, the wrapped object is pushed on the data stack. \item Otherwise, the car of the call frame is pushed on the data stack. \item The call frame is set to the cdr, and the loop continues. \end{itemize} \begin{figure} -\caption{Interpreter algorithm} +\caption{Evaluator semantics} \begin{center} \scalebox{0.45}{ %BEGIN IMAGE @@ -842,12 +866,7 @@ The Factor interpreter executes quotations. Quotations are lists, and since list \end{figure} \glossary{name=combinator, description=a word taking quotations or other words as input} -The following pair of words invokes the interpreter reflectively. They are used to implement \emph{combinators}, which are words that take code from the stack. Combinator definitions must be followed by the \texttt{inline} word to mark them as inline in order to compile; for example: -\begin{verbatim} -: keep ( x quot -- x | quot: x -- ) - over >r call r> ; inline -\end{verbatim} -Word inlining is documented in \ref{declarations}. +The following pair of words invokes the interpreter reflectively. \wordtable{ \vocabulary{kernel} @@ -871,6 +890,13 @@ Execute a word definition, taking action based on the word definition, as above. \textbf{Hello world} \end{alltt} +These words are used to implement \emph{combinators}, which are words that take code from the stack. Combinator definitions must be followed by the \texttt{inline} word to mark them as inline in order to compile; for example: +\begin{verbatim} +: keep ( x quot -- x | quot: x -- ) + over >r call r> ; inline +\end{verbatim} +Word inlining is documented in \ref{declarations}. + \subsection{Tail call optimization} \newcommand{\tailglos}{\glossary{ @@ -885,7 +911,7 @@ purpose in pushing the empty call frame on the call stack. Therefore the last ca \subsection{Call stack manipulation} -Because of the way the interpreter is described in \ref{quotations}, the top of the call stack is not accessed during the execution of a quotation; it is only popped when the interpreter reaches the end of the quotation. In effect, the call stack can be used as a temporary storage area, as long as pushes and pops are balanced out within a single quotation. +The definition of evaluator semantics in \ref{quotations} stipulates that the top of the call stack is not accessed during the execution of a quotation; the call stack is only popped when the end of the quotation is reached. In effect, the call stack can be used as a temporary storage area, as long as pushes and pops are balanced out within a single quotation. \wordtable{ \vocabulary{kernel} \ordinaryword{>r}{>r ( x -- r:x )} @@ -997,6 +1023,17 @@ X dup [ Y ] [ drop Z ] ifte } These are variations of \texttt{ifte*} where one of the quotations is \texttt{[ ]}. +The following two lines are equivalent: +\begin{verbatim} +X [ Y ] when* +X dup [ Y ] [ drop ] ifte +\end{verbatim} +The following two lines are equivalent: +\begin{verbatim} +X [ Y ] unless* +X dup [ ] [ drop Y ] ifte +\end{verbatim} + There is one final conditional form that is used to implement the ``default value'' idiom. \wordtable{ \vocabulary{kernel} @@ -1006,8 +1043,8 @@ There is one final conditional form that is used to implement the ``default valu } If the condition is \texttt{f}, the \texttt{false} quotation is called with the \texttt{default} value on the stack. Otherwise, the \texttt{true} quotation is called with the condition on the stack. The following two lines are equivalent: \begin{verbatim} -X [ Y ] [ Z ] ?ifte -X dup [ nip Y ] [ drop Z ] ifte +D X [ Y ] [ Z ] ?ifte +D X dup [ nip Y ] [ drop Z ] ifte \end{verbatim} \subsection{Boolean logic} @@ -1146,9 +1183,14 @@ I/O or an explicit call to \texttt{yield}. This is implemented by adding the cur \wordtable{ \vocabulary{threads} \ordinaryword{yield}{yield ( -- )} - } Add the current continuation to the end of the run queue, and call the continuation at the front of the run queue. +\wordtable{ +\vocabulary{threads} +\ordinaryword{sleep}{sleep ( ms -- )} +} +Pauses the current thread for \verb|ms| milliseconds. Other threads and I/O operations may execute in the meantime. The multitasker guarantees that the thread will not be woken up before \verb|ms| milliseconds passes, however it does not guarantee that the tread will not be woken up late; indeed, since multitasking is co-operative, a non-yielding thread can delay other sleeping threads indefinately. + \wordtable{ \vocabulary{threads} \ordinaryword{stop}{stop ( -- )} @@ -1204,10 +1246,12 @@ description=the collection of vocabularies making up the code in the Factor imag \vocabulary{words} \classword{word} } -Words are the fundamental unit of code in Factor, analogous to functions or procedures in other languages. Words are also objects, and this concept forms the basis for Factor's meta-programming facilities. Words hold two distinct pieces of information: +Words are the fundamental unit of code in Factor, analogous to functions or procedures in other languages. Words are also objects, and this concept forms the basis for Factor's meta-programming facilities. A word consists of several parts: \begin{itemize} -\item A definition, specifying the behavior of the word when executed, -\item A set of word properties, including the name of the word, its vocabulary, any documentation strings, and other meta-data. +\item a word name, +\item a vocabulary name, +\item a definition, specifying the behavior of the word when executed, +\item a set of word properties, including documentation strings and other meta-data. \end{itemize} \wordtable{ \vocabulary{words} @@ -1215,29 +1259,47 @@ Words are the fundamental unit of code in Factor, analogous to functions or proc } Tests if the \texttt{object} is a word. -\section{Vocabularies} +\wordtable{ +\vocabulary{words} +\ordinaryword{word-name}{word-name ( word -- string )} +\ordinaryword{word-vocabulary}{word-vocabulary ( word -- string )} +} +A pair of words for obtaining a word's name and vocabulary. + +\wordtable{ +\vocabulary{words} +\ordinaryword{word-sort}{word-sort ( list -- list )} + +} +Sort a list of words by name. + +\section{Vocabularies}\label{vocabularies} \wordtable{ \vocabulary{words} \symbolword{vocabularies} } -Words are organized into named vocabularies, stored in the global \texttt{vocabularies} variable (\ref{namespaces}). -\wordtable{ -\vocabulary{syntax} -\parsingword{IN:}{IN:~\emph{vocabulary}} -} -Sets the current vocabulary for new word definitions, and adds the vocabulary to the search path (\ref{vocabsearch}). +\glossary{name=interned word, +description={a word that is a member of the vocabulary named by its vocabulary slot. Interned words are created by calls to \verb|create|}} -Parsing words add definitions to the current vocabulary. When a source file is being parsed, the current vocabulary is initially set to \texttt{scratchpad}. +Words are organized into named vocabularies, stored in the global \texttt{vocabularies} variable (\ref{namespaces}). A word is said to be \emph{interned} if it is a member of the vocabulary named by its vocabulary slot. Otherwise, the word is \emph{uninterned}. + +Parsing words add definitions to the current vocabulary. When a source file is being parsed, the current vocabulary is initially set to \texttt{scratchpad}. The current vocabulary may be changed with the \verb|IN:| parsing word (\ref{vocabsearch}). \subsection{Searching for words} Words whose names are known at parse time -- that is, most words making up your program -- can be referenced by stating their name. However, the parser itself, and sometimes code you write, will need to look up words dynamically. \wordtable{ \vocabulary{words} -\ordinaryword{search}{search ( name vocabs -- word )} +\ordinaryword{lookup}{lookup ( name vocabulary -- word/f )} } -The \texttt{vocabs} parameter is a list of vocabulary names. If a word with the given name is found, it is pushed on the stack, otherwise, \texttt{f} is pushed. +Searches for a word named \verb|name| in the vocabulary named \verb|vocab|. If no such word exists, pushes \texttt{f}. +\wordtable{ +\vocabulary{words} +\ordinaryword{search}{search ( name vocabs -- word/f )} + +} +The \texttt{vocabs} parameter is a sequence of vocabulary names. If a word with the given name is found, it is pushed on the stack, otherwise, \texttt{f} is pushed. \subsection{Creating words}\label{creating-words} @@ -1252,10 +1314,39 @@ Creates a new word \texttt{name} in \texttt{vocabulary}. If the vocabulary alrea \ordinaryword{create-in}{create-in ( name -- word )} } -Creates a new word \texttt{name} in the current vocabulary. This word is intended to be called from parsing words (\ref{parsing-words}), and in fact is defined as follows: -\begin{verbatim} -: create-in ( name -- word ) "in" get create dup save-location ; -\end{verbatim} +Creates a new word \texttt{name} in the current vocabulary. This word is intended to be called from parsing words (\ref{parsing-words}). + +\newcommand{\uninternedglos}{ +\glossary{name=uninterned word, +description={a word whose vocabulary slot is either set to \texttt{f}, or that does not belong to the vocabulary named by its vocabulary slot. Uninterned words are created by calls to \texttt{gensym} and \texttt{}, and interned words can be come uninterned via calls to \texttt{forget}}}} +\uninternedglos + +\wordtable{ +\vocabulary{words} +\ordinaryword{gensym}{gensym ( -- word )} +} +Creates an uninterned word that is not equal to any other word in the system, either stored in a vocabulary, or resulting from prior or future calls to \verb|gensym|. Gensyms have an automatically-generated name based on a prefix and an incrementing counter, for debugging: +\begin{alltt} + gensym . +\textbf{G:260561} + gensym . +\textbf{G:260562} +\end{alltt} +Gensyms are often used as placeholders and representitives that must be unique. For example, the compiler uses gensyms internally to label sections of assembly code. + +\wordtable{ +\vocabulary{words} +\ordinaryword{}{ ( name vocabulary -- word )} +} +Creates an uninterned word whose name and vocabulary slots have the given values, however the word is not actually entered into this vocabulary. This word is used to implement \verb|create| and \verb|gensym|, and it is not usually used directly, since it can give confusing results: +\begin{alltt} + "reverse" "sequences" dup . +\textbf{reverse} + "reverse" "sequences" lookup dup . +\textbf{reverse} + eq? +\textbf{f} +\end{alltt} \section{Word definition} @@ -1391,28 +1482,74 @@ The class that all undefined words are an instance of. \parsingword{FORGET:}{FORGET:~\emph{name}} } Removes the word \texttt{name} from its vocabulary. Existing definitions that reference the word will continue to work, but newly-parsed occurrences of the word will not locate the forgotten definition. No exception is thrown if no such word exists. +\uninternedglos \wordtable{ \vocabulary{words} \ordinaryword{forget}{forget ( word -- )} - } -Removes the word from its vocabulary. The parsing word \texttt{FORGET:} is implemented using this word. +Removes the word from its vocabulary. The word becomes uninterned. The parsing word \texttt{FORGET:} is implemented using this word. +\wordtable{ +\vocabulary{words} +\ordinaryword{interned?}{interned?~( word -- ?~)} +} +Test if the word is interned. If the word's vocabulary slot is \verb|f|, immediately outputs \verb|f|, otherwise, tests if the word with the same name in that vocabulary is actually the given word. +\begin{alltt} + "interning" "scratchpad" create + dup interned? +\textbf{t} + dup forget + interned? +\textbf{f} +\end{alltt} \subsection{Declarations}\label{declarations} -A compound or generic word (\ref{generic}) can be given special behavior with one of the below parsing words. - -\wordtable{ -\vocabulary{syntax} -\parsingword{inline}{inline} -} -Marks the most recently defined word as an inline word. The compiler copies the definitions of inline words directly into the word being compiled. Combinators must be inlined in order to compile. For any other word, inlining is merely an optimization; see \ref{compiler}. Inlining does not affect the execution of the word in the interpreter, nor is inlining visible when you \texttt{see} the word (\ref{exploring-vocabs}). +A compound or generic word (\ref{generic}) can be given special behavior with one of the below parsing words. They all act on the most recently-defined word by setting to \verb|t| a word property keyed by the string naming the declaration word. +The first declaration specifies the time when a word runs. It affects both interpreted and compiled definitions. \wordtable{ \vocabulary{syntax} \parsingword{parsing}{parsing} } -Marks the most recently defined word as a parsing word. Parsing words run at parse time. Se \ref{parsing-words}. +Parsing words run at parse time. See \ref{parsing-words}. + +The remaining declarations only affect compiled definitions. They do not change evaluation semantics of a word, but instead declare that the word follows a certain contract, and thus may be compiled differently. +If a generic word is defined as \verb|flushable| or \verb|foldable|, all methods must satisfy the contract, otherwise unpredicable behavior will occur. + +\glossary{name=inline word, +description={calls to inline words are replaced with the inline word's body by the compiler. Inline words are declared via the \verb|inline| parsing word}} +\wordtable{ +\vocabulary{syntax} +\parsingword{inline}{inline} +} +The compiler copies the definitions of inline words directly into the word being compiled. Combinators must be inlined in order to compile. For any other word, inlining is merely an optimization; see \ref{compiler}. Inlining does not affect the execution of the word in the interpreter. + +\glossary{name=flushable word, +description={calls to flushable words may be removed from compiled code if their outputs are subsequently discarded by calls to \verb|drop|. Flushable words are declared via the \verb|flushable| parsing word}} +\wordtable{ +\vocabulary{syntax} +\parsingword{flushable}{flushable} +} +Calls to flushable words may be removed from compiled code if their outputs are subsequently discarded by calls to \verb|drop|. Flushable words must be side-effect-free; that is, their outputs must solely depend on inputs, and they must not modify their inputs, or any other object visible outside the dynamic extent of the flushable word. Note that if a word with no outputs is declared flushable, calls to it are \emph{never} compiled in. + +\glossary{name=foldable word, +description={calls to foldable words may be evaluated at compile time if all inputs are literal. Foldable words are declared via the \verb|foldable| parsing word}} +\wordtable{ +\vocabulary{syntax} +\parsingword{foldable}{foldable} +} +Foldable words may be evaluated at compile time if all inputs are literal. Foldable words must satisfy a very strong contract: +\begin{itemize} +\item foldable words must satisfy the contract of flushable words, +\item foldable words must halt\footnote{of course, this cannot be guaranteed in the general case, but for example, a word computing a series until it coverges should not be foldable, since compilation will not halt in the event the series does not converge.} +\item inputs and outputs of foldable words must be immutable objects. +\end{itemize} +The last restriction ensures that words like \verb|clone| do not satisfy the foldable word contract. Indeed, \verb|clone| is flushable, however it may output a mutable object if its input is mutable, and so it is undesirable to evaluate it at compile-time, since the following two definitions have differing semantics: +\begin{verbatim} +: foe { } ; +: foe { } clone ; +\end{verbatim} +Most mathematical opeartions are foldable. For example, \verb|2 2 +| is compiled to a literal \verb|4|, because \verb|+| is foldable. \section{Word properties}\label{word-props} @@ -1434,35 +1571,14 @@ Retrieve and store word properties. Note that the stack effect is designed so th The following properties are commonly-set: \begin{description} -\item[\texttt{"name"}] The name of the word -\item[\texttt{"vocabulary"}] The vocabulary containing the word -\item[\texttt{"parsing"}] A boolean specifying if this is a parsing word (\ref{parsing-words}) -\item[\texttt{"inline"}] A boolean specifying if this word is compiled inline (\ref{declarations}) -\item[\texttt{"methods"}] Only defined on generic words; a hashtable mapping classes to quotations (\ref{generic}) +\item[\texttt{"parsing"}, \texttt{"inline"}, \texttt{"flushable"}, \texttt{"foldable"}] declarations (see \ref{declarations}) +\item[\texttt{"methods"}] only defined on generic words; a hashtable mapping classes to quotations (see \ref{generic}) +\item[\texttt{"combination"}] only defined on generic words; see \ref{combinations} \item[\texttt{"file"}] The source file storing the word definition \item[\texttt{"line"}] The line number in the source file storing the word definition \item[\texttt{"col"}] The column number in the source file storing the word definition \end{description} -\wordtable{ -\vocabulary{words} -\ordinaryword{word-name}{word-prop ( word -- name )} -\ordinaryword{word-vocabulary}{word-vocabulary ( word -- vocabulary )} - -} -Retreive the name of a word, and the name of the vocabulary it is stored in. The definitions are trivial: -\begin{verbatim} -: word-name "name" word-prop ; -: word-vocabulary "vocabulary" word-prop ; -\end{verbatim} - -\wordtable{ -\vocabulary{words} -\ordinaryword{word-sort}{word-sort ( list -- list )} - -} -Sort a list of words by name. - \wordtable{ \vocabulary{words} \ordinaryword{word-props}{word-props ( word -- hashtable )} @@ -1493,7 +1609,7 @@ The words outlined in this section should not be used in ordinary code. \ordinaryword{set-word-primitive}{set-word-primitive ( word -- n )} } -Retreives and stores a word's primitive number. +Retreives and stores a word's primitive number. Note that changing the primitive number does not update the execution token, and the word will still call the old definition until a subsequent call to \verb|update-xt|. \wordtable{ \vocabulary{words} @@ -1518,7 +1634,7 @@ This is an even lower-level facility for working with the address containing nat \ordinaryword{update-xt}{update-xt ( word -- )} } -Updates a word's execution token according to its primitive number. When called with a compiled word, has the effect of decompiling the word. The execution token is automatically updated after a call to \texttt{set-word-primitive}. +Updates a word's execution token according to its primitive number. When called with a compiled word, has the effect of decompiling the word. \wordtable{ \vocabulary{words} @@ -1539,7 +1655,13 @@ Everything in Factor is an object, where an object is a collection of slots. Eac \glossary{name=equal, description={two objects are equal if they have the same class and if their slots are equal, or alternatively, if both are numbers that denote the same value}} -There are two distinct notions of ``sameness'' when it comes to objects. You can test if two references point to the same object, or you can test if two objects are equal in some sense, usually by having the same type and equal slot values. +There are two distinct notions of ``sameness'' when it comes to objects. You can test if two references point to the same object, or you can test if two objects are equal in some sense, usually by being instances of the same class, and having equal slot values. Both notions of equality are equality relations in the mathematical sense; that is, they obey the following axioms: +\begin{itemize} +\item They are reflexive: $x\sim x$ +\item They are symmetric: $x\sim y$ if and only if $y\sim x$ +\item They are transitive: if $x\sim y$ and $y\sim z$, then $x\sim z$ +\end{itemize} + \wordtable{ \vocabulary{kernel} \ordinaryword{eq?}{eq?~( object object -- ?~)} @@ -1552,18 +1674,22 @@ Output \texttt{t} if two references point to the same object, and \texttt{f} oth Output \texttt{t} if two objects are equal, and \texttt{f} otherwise. The precise meaning of equality depends on the object's class, however usually two objects are equal if their slot values are equal. If two objects are equal, they have the same printed representation, although the converse is not always true. In particular: \begin{itemize} \item If no more specific method is defined, \texttt{=} calls \texttt{eq?}. -\item Two numbers are equal if they have the same numerical value. -\item Two sequences are equal if they are both instances of the same class, and if they have the same length, and elements. +\item Two numbers are equal if they have the same numerical value after being upgraded to the highest type of the two (\ref{number-protocol}). +\item Two lists, vectors, strings, string buffers or arrays are equal if they have the same length, and elements. \item Two hashtables are equal if they hold the same set of key/value pairs. \item Two tuples are equal if they are of the same class and their slots are equal. \item Two words are equal if they are the same object. \end{itemize} +This generic word is flushable, so user-defined methods must satisfy the flushable contract (see \ref{declarations}). + \wordtable{ \vocabulary{kernel} \genericword{clone}{clone ( object -- object )} } Make a fresh object that is equal to the given object. This is not guaranteed to actually copy the object; it does nothing with immutable objects, and does not copy words either. However, sequences and tuples can be cloned to obtain a new shallow copy of the original. +This generic word is flushable, so user-defined methods must satisfy the flushable contract (see \ref{declarations}). + \section{Generic words and methods}\label{generic} \glossary{name=generic word, @@ -1662,6 +1788,7 @@ bignum byte-array complex cons +displaced-alien dll f fixnum @@ -1673,6 +1800,7 @@ t tuple vector word +wrapper \end{verbatim} \wordtable{ \vocabulary{kernel} @@ -1754,18 +1882,31 @@ PREDICATE: integer printable CHAR: \s CHAR: ~ between? ; \end{verbatim} \subsection{Operations on classes} +\wordtable{ +\vocabulary{kernel} +\ordinaryword{class<}{class< ( class1 class2 -- ?~)} +} +Tests if all instances of \verb|class1| are also instances of \verb|class2|. This is a partial order with top and bottom in the mathematical sense; that is, it obeys the following axioms: +\begin{itemize} +\item It is reflexive: $X\subset X$ +\item It is transitive: if $X\subset Y$ and $Y\subset Z$, then $X\subset Z$ +\item There is a bottom element: for all classes $X$, $\texttt{null}\subset X$ +\item There is a top element: for all classes $X$, $X\subset\texttt{object}$ +\end{itemize} + +This ordering determines the method ordering of a generic word (\ref{method-order}). + \wordtable{ \vocabulary{kernel} \ordinaryword{class-and}{class-and ( class class -- class )} \ordinaryword{class-or}{class-or ( class class -- class )} } -Intersection and union of classes. Note that the returned class might not be the exact desired class; for example, \texttt{object} is output if no suitable class definition could be found at all. -\wordtable{ -\vocabulary{kernel} -\ordinaryword{class<}{class< ( class class -- class )} -} -Classes are partially ordered. This ordering determines the method ordering of a generic word (\ref{method-order}). +Intersection and union of classes. Note that the returned class might not be the exact desired class; for example, \texttt{object} is output if no suitable class definition could be found at all. However, the following axioms are satisfied: +\begin{itemize} +\item If $X\subset Y$, then $X\cup Y=Y$ +\item If $X\subset Y$, then $X\cap Y=X$ +\end{itemize} \section{Tuples}\label{tuples} \tupleglos @@ -1796,7 +1937,7 @@ The word \texttt{} takes the slot values from the stack and produces a new \texttt{point}: \begin{alltt} 1 2 3 . -\textbf{<< point 1 2 3 >>} +\textbf{<< point f 1 2 3 >>} \end{alltt} \subsection{Constructors} @@ -1831,11 +1972,10 @@ method call receives the delegate on the stack, not the original object. \ordinaryword{delegate}{delegate ( object -- object )} } -Returns an object's delegate, or \texttt{f} if no delegate is set. Note that in this case, undefined methods will be passed to \texttt{f}; rather an error is raised immediately. +Returns an object's delegate, or \texttt{f} if no delegate is set. A direct consequence of this behavior is that an object may not have a delegate of \texttt{f}. \wordtable{ \vocabulary{generic} \ordinaryword{set-delegate}{set-delegate ( object tuple -- )} - } Sets a tuple's delegate. @@ -1849,6 +1989,99 @@ Class membership test pridicates only test if an object is a direct instance of Tests if the quotation outputs a true value when applied to the object or some object that it delegates to. +Note that the \verb|standard-combination| method combination does not respect delegation unless the picker quotation is given as \verb|[ dup ]|. The \verb|math-combination| does not respect delegation at all (see \ref{combinations}). + +\subsection{Method combination}\label{combinations} + +Method combination adds a degree of flexibility to the generic word system, where a particular form of higher-order programming can be used to customize two aspects of generic word behavior: +\begin{itemize} +\item which stack item(s) the generic word dispatches upon, +\item which methods out of the set of applicable methods are called +\end{itemize} +The \verb|GENERIC:| parsing word creates a generic word using the \emph{standard method combination}. The \verb|G:| parsing word allows a custom method combination to be specified. +\wordtable{ +\vocabulary{syntax} +\parsingword{G:}{G: \emph{generic} \emph{combination ...} ;} +} +Defines a generic word using the long-form. +A method combination is a quotation that is given the generic word on the stack, and outputs a quotation \emph{that becomes the definition of the word}. This is a very profound and abstract concept, and the examples in the remainder of the section will make it easier to grasp. The method combination quotation is called each time the generic word has to be updated (for example, when a method is added), and must not have any side effects. + +\subsubsection{Standard method combination} + +The following two lines are equivalent: +\begin{verbatim} +GENERIC: foo +G: foo simple-combination ; +\end{verbatim} +\wordtable{ +\vocabulary{generic} +\ordinaryword{simple-combination}{simple-combination~( word -- quot )} +} +Perform simple method combination: +\begin{itemize} +\item the word dispatches on the top stack item, +\item only the method with most specific class is invoked, +\item if no suitable method is found, the generic word is called on the object's delegate +\end{itemize} + +The next level of generality is the standard combination, which also invokes only the most specific method, but dispatches on an arbitrary stack element. +\wordtable{ +\vocabulary{generic} +\ordinaryword{standard-combination}{standard-combination~( word picker -- quot )} +} +The \verb|picker| quotation must produce exactly one value on the stack. The picker is spliced into the returned quotation at appropriate points, making the generic word dispatch on the stack item produced by the picker. The simple combination is defined in terms of the standard combination as follows: +\begin{verbatim} +: simple-combination [ dup ] standard-combination ; +\end{verbatim} +Here is an example of a generic word a non-simple picker. +\begin{verbatim} +G: sbuf-append [ over ] standard-combination ; +M: string sbuf-append swap nappend ; +M: integer sbuf-append push ; +\end{verbatim} +Now it may be used as thus: +\begin{alltt} + SBUF" " clone "my-sbuf" set + "hello" "my-sbuf" get sbuf-append + CHAR: \bs{}s "my-sbuf" get sbuf-append + "world" "my-sbuf" get sbuf-append + "my-sbuf" get . +\textbf{SBUF" hello world"} +\end{alltt} + +\subsubsection{Math method combination} +\newcommand{\numupgradeglos}{ +\glossary{ +name=numerical upgrading, +description={the stipulation that if one of the inputs to an arithmetic word is a \texttt{bignum} and the other is a \texttt{fixnum}, the latter is first coerced to a \texttt{bignum}, and if one of the inputs is a \texttt{float}, the other is coerced to a \texttt{float}}}} +\numupgradeglos + +\wordtable{ +\vocabulary{generic} +\ordinaryword{math-combination}{math-combination~( word -- quot )} +} +The math method combination is used for binary operators such as \verb|+|, \verb|*|, and so on. +A method can only be added to a generic word using the math combination if the method specializes on one of the below classes, or a union defined over one or more of the below classes: +\begin{verbatim} +fixnum +bignum +ratio +float +complex +object +\end{verbatim} +The math combination performs numerical upgrading as described in \ref{number-protocol}. + +\subsubsection{Custom method combinations} + +Development of custom method combination requires a good understanding of higher-order programming (code that writes code) and Factor internals. Custom method combination has not been fully explored at this stage of Factor development, and this section can only give a brief sketch of what is involved. + +\wordtable{ +\vocabulary{generic} +\ordinaryword{methods}{methods~( word -- alist )} +} +Outputs an association list mapping classes to method definition quotations. The association list is sorted with the least-specific method first. The task of the method combination is to transform this association list into an executable quotation. + \part{Library reference} \chapter{Sequences} @@ -1869,7 +2102,7 @@ Class&Mutable&Growable&Lookup&at start&at end&Primary purpose\\ \texttt{string}&&&$O(1)$&&&Immutable text strings \end{tabular} -A handful of ``virtual'' sequences are provided by the library. These sequences are not backed by actual storage, but instead either compute their values, or take them from an underlying sequence. Virtual sequences are documented in \ref{virtual-seq} and include: +A handful of ``virtual'' sequences are provided by the library. These sequences are not backed by actual storage, but instead either compute their values, or take them from an underlying sequence. Virtual sequences include: \begin{verbatim} repeated range @@ -1878,6 +2111,11 @@ slice \end{verbatim} User-defined classes can also implement the sequence protocol and gain the ability to reuse many of the words in this section. +Finally, integers implement the sequence protocol, allowing counted loops to fall out as a trivial case of sequence iteration (\ref{counted-loops}). + +\glossary{name=virtual sequence, +description={a sequence that is not backed by actual storage, but instead either computes its values, or take them from an underlying sequence}} + \section{Sequence protocol} The following set of generic words constitutes the sequence protocol. The mutating words are not supported by all sequences; in particular, lists and strings are immutable. @@ -1893,6 +2131,8 @@ An object that is an instance of a class implementing these generic words can be \genericword{length}{length ( seq -- n )} } Outputs the length of the sequence. All sequences support this operation. + +This generic word is flushable, so user-defined methods must satisfy the flushable contract (see \ref{declarations}). \wordtable{ \vocabulary{sequences} \genericword{set-length}{set-length ( n seq -- )} @@ -1905,12 +2145,30 @@ Resizes the sequence. Not all sequences can be resized. } Outputs the $n$th element of the sequence. Elements are numbered starting from 0, so the last element has an index one less than the length of the sequence. An exception should be thrown if an out-of-bounds index is accessed. All sequences support this operation, however with lists it has non-constant running time. +This generic word is flushable, so user-defined methods must satisfy the flushable contract (see \ref{declarations}). + \wordtable{ \vocabulary{sequences} \genericword{set-nth}{set-nth ( elt n seq -- )} } Sets the $n$th element of the sequence. Storing beyond the end of a resizable sequence such as a vector or string buffer grows the sequence. Storing to a negative index is always an error. +\wordtable{ +\vocabulary{sequences} +\genericword{like}{like ( seq template -- seq )} +} +Outputs a sequence with the same elements as the input sequence, but ``like'' the template sequence, meaning it either has the same class as the template sequence, or if the template sequence is a virtual sequence, the same class as the template sequence's underlying sequence. The default implementation does nothing. + +This generic word is flushable, so user-defined methods must satisfy the flushable contract (see \ref{declarations}). + +\wordtable{ +\vocabulary{sequences} +\genericword{thaw}{thaw ( seq -- seq )} +} +Outputs a sequence with the same elements as the input sequence, but mutable. The default implementation converts the sequence into a vector. + +This generic word is flushable, so user-defined methods must satisfy the flushable contract (see \ref{declarations}). + \section{Sequence operations} \subsection{Comparison} @@ -1932,20 +2190,6 @@ Compares two sequences of integers lexicographically (dictionary order). The out \item[Zero] indicating that \texttt{s1} is equal to \texttt{s2} \item[Negative] indicating that \texttt{s1} precedes \texttt{s2} \end{description} -\wordtable{ -\vocabulary{sequences} -\ordinaryword{lexi>}{lexi> ( s1 s2 -- ?~)} - -} -Tests if \texttt{s1} follows \texttt{s2}. Implemented as follows: -\begin{verbatim} -: lexi> ( s1 s1 -- ? ) lexi 0 > ; -\end{verbatim} -This is usually used to sort lists of strings: -\begin{alltt} - [ "Curry" "Apple" "Veal" "Turkey" ] [ string> ] sort . -[ "Apple" "Curry" "Turkey" "Veal" ] -\end{alltt} \subsection{Iteration}\label{iteration} @@ -1979,8 +2223,8 @@ So indeed, it is an expression of an idiom rather than an algorithm. Various wor } Like \verb|reduce|, but instead outputs a sequence of intermediate values. The first element of the resulting sequence is always \verb|ident|. For example, \begin{alltt} - { 2 2 2 2 2 } 0 [ + ] accumulate . -{ 0 2 4 6 8 } + \tto 2 2 2 2 2 \ttc 0 [ + ] accumulate . +\tto 0 2 4 6 8 \ttc \end{alltt} \wordtable{ \vocabulary{sequences} @@ -2000,25 +2244,42 @@ Applies the quotation to each element yielding a new element. The new elements a \texttt{quot:~element -- element}\\ } Applies the quotation to each element yielding a new element, storing the new elements back in the original sequence. This modifies \texttt{seq} and so throws an exception if it is immutable. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{2each}{2each ( s1 s2 quot -- )} +\texttt{quot:~e1 e2 --}\\ +} +Applies the quotation to pairs of elements from \texttt{s1} and \texttt{s2}, which must have the same length. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{2reduce}{2reduce ( seq1 seq2 ident quot -- result )} +\texttt{quot:~previous elt1 elt2 -- next}\\ +} +Combines successive pairs of elements from the two sequences using a ternary operation. The first input value at each iteration except the first one is the result of the previous iteration. The first input value at the first iteration is \verb|ident|. For example, the \verb|v.| word computing the dot product of two vectors is implemented using \verb|2reduce|: +\begin{verbatim} +: v. ( v v -- n ) 0 [ * + ] 2reduce ; +\end{verbatim} +See \ref{inner-product} for details. + +The \verb|2reduce| word has a trivial implementation: +\begin{verbatim} +: 2reduce >r -rot r> 2each ; inline +\end{verbatim} + \wordtable{ \vocabulary{sequences} \ordinaryword{2map}{2map ( s1 s2 quot -- seq )} \texttt{quot:~e1 e2 -- element}\\ } -Applies the quotation to pairs of elements from \texttt{s1} and \texttt{s2}, yielding a new element. The new elements are collected into a sequence of the same class as \texttt{s1}. Here is an example computing the pair-wise product of the elements of two vectors: +Applies the quotation to pairs of elements from \texttt{s1} and \texttt{s2}, yielding a new element. The two input sequences must have the same length. The new elements are collected into a sequence of the same class as \texttt{s1}. Here is an example computing the pair-wise product of the elements of two vectors: \begin{alltt} \tto 5 3 -2 \ttc \tto 8 16 3 \ttc [ * ] 2map . \textbf{\tto 40 48 -6 \ttc} \end{alltt} -In fact the \verb|v*| word in the \verb|matrices| vocabulary is defined to call \verb|[ * ] 2map|; see \ref{pairwise} for documentation on this and similar words. +In fact the \verb|v*| word in the \verb|math| vocabulary is defined to call \verb|[ * ] 2map|; see \ref{pairwise} for documentation on this and similar words. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{2nmap}{2nmap ( s1 s2 quot -- )} -\texttt{quot:~e1 e2 -- element}\\ -} -Applies the quotation to pairs of elements from \texttt{s1} and \texttt{s2}, yielding a new element. The new element is stored back in \texttt{s1}. This modifies \texttt{s1} and so throws an exception if it is immutable. \wordtable{ \vocabulary{sequences} \genericword{find}{find ( seq quot -- i elt )} @@ -2049,16 +2310,379 @@ member? ( elt seq -- ? ) } Curried forms of the above combinators. They pass an additional object to each invocation of the quotation. -\subsection{Stack operations}\label{stack-seq} +\subsection{Counted loops}\label{counted-loops} -The following words allow any mutable, growable sequence to be used as a LIFO (last in, first out) stack. +Integers support the sequence protocol in a trivial fashion; a non-negative integer presents its non-negative predecessors as elements. For example, the integer 3, when viewed as a sequence, contains the elements 0, 1, 2. This is very useful for performing counted loops. +For example, the \verb|each| combinator, given an integer, simply calls the quotation that number of times, pushing a counter on each iteration that ranges from 0 up to that integer: +\begin{alltt} + 3 [ . ] each +0 +1 +2 +\end{alltt} +A common idiom is to iterate over a sequence, while maintaining a loop counter. This can be done using \verb|2each|: +\begin{alltt} + \tto "a" "b" "c" \ttc dup length [ + "Index: " write . "Element: " write . + ] 2each +\textbf{Index: 0 +Element: "a" +Index: 1 +Element: "b" +Index: 2 +Element: "c"} +\end{alltt} +Combinators that produce new sequences, such as \verb|map|, will output a vector if the input is an integer. + +If you wish to perform an iteration over a range of integers that does not begin from zero, or an iteration that starts at a specific index and decreases towards zero, use a \verb|| sequence. + +\glossary{name=range sequence, +description={an instance of the \texttt{range} class, which is a virtual sequence of integers}} +\wordtable{ +\vocabulary{sequences} +\ordinaryword{}{ ( a b -- seq )} +} +Creates an immutable sequence consisting of all integers in the interval $[a,b)$ (if $ab$). If $a=b$, the resulting sequence is empty. This is just a tuple implementing the sequence protocol. +\begin{alltt} + CHAR: a CHAR: z 1 + . +<< range [ ] 97 123 1 >> + CHAR: a CHAR: z 1 + >string . +"abcdefghijklmnopqrstuvwxyz" + CHAR: z CHAR: a 1 - >string . +"zyxwvutsrqponmlkjihgfedcba" +\end{alltt} + +\subsection{Aggregation and grouping}\label{aggregation} + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{append}{append ( s1 s2 -- seq )} +} +Outputs a new sequence consisting of the elements of \texttt{s1} followed by the elements of \texttt{s2}. The new sequence is of the same class as \texttt{s1}. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{add}{add ( seq elt -- seq )} +} +Outputs a new sequence consisting of the elements of \texttt{seq} followed by \verb|elt|. +The new sequence is of the same type as \texttt{seq}. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{append3}{append3 ( s1 s2 s3 -- seq )} +} +Appends the three sequences \texttt{s1}, \texttt{s2} and \texttt{s3} into a new sequence of the same class as \texttt{s1}. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{nappend}{nappend ( s1 s2 -- )} +} +Appends \texttt{s2} to \texttt{s1}. Nothing is output, and \texttt{s1} is modified. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{copy-into}{copy-into ( start to from -- )} +} +Copies all elements of \verb|from| into \verb|to|, with destination indices starting from \verb|start|. The \verb|to| sequence must be large enough, or an exception is thrown. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{concat}{concat ( sequence -- sequence )} +} +The input is a sequence of sequences. If the input is empty, the output is the empty list (\texttt{f}). Otherwise, the elements of the input sequence are concatenated together, and a new sequence of the same type as the first element is output. +\begin{alltt} + \tto "a" [ CHAR: b ] \tto CHAR: c \ttc \ttc concat . +\textbf{"abc"} +\end{alltt} +\wordtable{ +\vocabulary{sequences} +\ordinaryword{join}{join ( sequence glue -- sequence )} +} +Like \verb|concat|, but \verb|glue| is placed between each pair of sequences, and the resulting sequence has the same type as \verb|glue|. +\begin{alltt} + \tto "alpha" "beta" "gamma" \ttc ", " join . +\textbf{"alpha, beta, gamma"} +\end{alltt} +\wordtable{ +\vocabulary{sequences} +\ordinaryword{split1}{split1~( seq split -- before after )} +} +If \texttt{seq} does not contain \texttt{split} as a subsequence, then \texttt{before} is equal to the \texttt{seq}, and \texttt{after} is \texttt{f}. Otherwise, \texttt{before} and \texttt{after} are both sequences, and yield the input excluding \texttt{split} when appended. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{split}{split~( seq split -- list )} +} +Outputs a list of subsequences taken between occurrences of \texttt{split} in \texttt{seq}. If \texttt{split} does not occur in \texttt{seq}, outputs a singleton list containing \texttt{seq} only. +\begin{alltt} + "/usr/local/bin" "/" split . +\textbf{[ "" "usr" "local" "bin" ]} +\end{alltt} +\wordtable{ +\vocabulary{sequences} +\ordinaryword{group}{group~( str n -- list )} +} +Splits the sequence into groups of $n$ elements and collects each group in a list. If the sequence length is not a multiple of $n$, the final subsequence in the list will be shorter than $n$. + +\subsection{Searching and sorting}\label{seq-searching} + +A set of words dealing with sequence element indices, and for sorting sequences. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{index}{index ( obj seq -- n )} +\ordinaryword{index*}{index* ( obj i seq -- n )} +} +Outputs the index of the first element in the sequence equal to \texttt{obj}. If no element is found, outputs $-1$. The \verb|index*| form allows a start index to be specified. A related word is \verb|member?| (\ref{set-theoretic}). +\wordtable{ +\vocabulary{sequences} +\ordinaryword{start}{start ( subseq seq -- n )} +\ordinaryword{start*}{start* ( subseq i seq -- n )} +} +Outputs the start index of a subsequence, or $-1$ if the subsequence does not occur in the sequence. The \verb|start*| form allows a start index to be specified. A related word is \verb|subseq?|. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{subseq?}{subseq?~( s1 s2 -- ?~)} +} +Tests if \texttt{s2} contains \texttt{s1} as a subsequence. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{sort}{sort~( seq quot -- seq )} +\texttt{quot:~e1 e2 -- -1/0/1}\\ +} +Sorts the sequence by comparing each pair of elements with the quotation. The quotation should output one of the following values: +\begin{description} +\item[Positive] indicating that \texttt{e1} follows \texttt{e2} +\item[Zero] indicating that \texttt{e1} is equal to \texttt{e2} +\item[Negative] indicating that \texttt{e1} precedes \texttt{e2} +\end{description} +A new sorted sequence is output, and the given sequence is not modified. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{nsort}{nsort~( seq quot -- )} +\texttt{quot:~e1 e2 -- -1/0/1}\\ +} +Like \verb|sort|, except the sequence is sorted in-place. Giving an immutable sequence to this word will raise an exception. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{number-sort}{number-sort~( seq -- seq )} +} +Sorts a sequence of real numbers. Defined as follows: +\begin{verbatim} +: number-sort [ - ] sort ; +\end{verbatim} + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{string-sort}{string-sort~( seq -- seq )} +} +Sorts a sequence of strings. Defined as follows: +\begin{verbatim} +: string-sort [ lexi ] sort ; +\end{verbatim} + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{binsearch}{binsearch~( elt seq quot -- i )} +} +Perform a binary search for \verb|elt| on a sorted sequence. The quotation follows the same protocol as the comaprator quotation given to \verb|sort|, and the sequence must already be sorted under this quotation. The index of the greatest element that is equal to or less than \verb|elt| is output. If the sequence is empty, outputs $-1$. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{binsearch*}{binsearch*~( elt seq quot -- elt )} +} +Like \verb|binsearch|, but outputs the element at that index, rather than the index itself. If the sequence is empty, outputs \verb|f|. + +\subsection{Slicing and reshaping}\label{reshaping} +\glossary{name=slice, +description={an instance of the \texttt{slice} class, which is a virtual sequence sharing structure with a subrange of some underlying sequence}} + +The first set of words are concerned with taking subsequences of a sequence. Each of the below words comes in dual pairs; the first of the pair outputs a new copied sequence, the second outputs a virtual sequence sharing structure with the underlying sequence. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{head}{head~( n seq -- seq )} +\ordinaryword{head-slice}{head-slice ( n seq -- slice )} +} +Outputs a new sequence consisting of the first $n$ elements of the input sequence. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{tail}{tail~( n seq -- seq )} +\ordinaryword{tail-slice}{tail-slice ( n seq -- slice )} +} +Outputs a new sequence consisting of all elements of the sequence, starting at the $n$th index. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{head*}{head~( n seq -- seq )} +\ordinaryword{head-slice*}{head-slice*~( n seq -- slice )} +} +Outputs a new sequence consisting of all elements of the sequence, until the $n$th element from the end. In other words, it outputs a sequence of the first $l-n$ elements of the input sequence, where $l$ is its length. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{tail*}{tail*~( n seq -- seq )} +\ordinaryword{tail-slice*}{tail-slice*~( n seq -- slice )} +} +Outputs a new sequence consisting of the last $n$ elements of the input sequence. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{subseq}{subseq~( from to seq -- seq )} +\ordinaryword{}{ ( from to seq -- slice )} +} +Outputs a new sequence consisting of all elements in the interval $[from,to)$. +\wordtable{ +\vocabulary{sequences} +\genericword{reverse}{reverse ( seq -- seq )} +\genericword{reverse}{reverse-slice ( seq -- seq )} +} +Outputs a new sequence with the reverse element order. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{head?}{head?~( s1 s2 -- ?~)} +\ordinaryword{tail?}{tail?~( s1 s2 -- ?~)} +} +Tests if \texttt{s1} starts or ends with \texttt{s1}. If \texttt{s1} is longer than \texttt{s2}, outputs \texttt{f}. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{?head}{?head~( s1 s2 -- seq ?~)} +\ordinaryword{?tail}{?tail~( s1 s2 -- seq ?~)} +} +Tests if \texttt{s1} starts or ends with \texttt{s1} as a subsequence. If there is a match, outputs the subrange of \texttt{s1} excluding \texttt{s1} followed by \texttt{t}. If there is no match, outputs \texttt{s1} followed by \texttt{f}. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{flip}{flip ( seq -- seq )} +} +Outputs the two-dimensional transpose of the sequence of sequences, all of which must have equal length. An example: +\begin{alltt} + \tto \tto 1 2 3 \ttc \tto 4 5 6 \ttc \ttc flip +\textbf{\tto \tto 1 2 \ttc \tto 3 4 \ttc \tto 5 6 \ttc \ttc} +\end{alltt} + +\subsection{Set-theoretic operations}\label{set-theoretic} + +A set of words for testing membership, and aggregating sequences without regard for element order. + +\wordtable{ +\vocabulary{sequences} +\ordinaryword{member?}{member?~( elt seq -- ?~)} +} +Tests if \texttt{seq} contains an element equal to \texttt{elt}. A related word is \verb|index| (\ref{seq-searching}).. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{memq?}{memq?~( elt seq -- ?~)} +} +Tests if the sequence contains the actual object given. Elements are compared by identity. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{contained?}{contained?~( s1 s2 -- ?~)} +} +Tests if every element of \texttt{s1} is equal to some element of \texttt{s2}. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{remove}{remove ( object seq -- seq )} +} +Outputs a new sequence containing all elements of the input sequence except those equal to the \texttt{object}. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{prune}{prune ( seq -- seq )} +} +Outputs a new sequence with each element of \verb|seq| appearing only once. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{seq-union}{seq-union ( seq seq -- seq )} +} +Outputs a sequence of elements present in at least one of the sequences, filtering duplicates by comparing elements for equality. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{seq-intersect}{seq-intersect ( seq seq -- seq )} +} +Outputs a sequence of elements present in both sequences, comparing elements for equality. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{seq-diff}{seq-diff ( s1 s2 -- seq )} +} +Outputs a sequence of elements present in \texttt{sl2} but not \texttt{s1}, comparing elements for equality. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{subset}{subset ( seq quot -- seq )} +\texttt{quot:~element -- ?}\\ +} +Applies the quotation to each element, and outputs a new sequence containing the elements of the original sequence for which the quotation output a true value. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{contains?}{contains?~( seq quot -- ?~)} +\texttt{quot:~element -- ?}\\ +} +Applies the quotation to each element of the sequence. If an element is found for which the quotation outputs a true value, a true value is output. Otherwise if the end of the sequence is reached, \verb|f| is output. Given an empty sequence, vacuously outputs \texttt{f}. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{all?}{all?~( seq quot -- ?~)} +\texttt{quot:~element -- ?}\\ +} +Outputs \texttt{t} if the quotation yields true when applied to each element, otherwise outputs \texttt{f}. Given an empty sequence, vacuously outputs \texttt{t}. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{monotonic?}{monotonic?~( seq quot -- ?~)} +\texttt{quot:~element element -- ?}\\ +} +Tests if all elements of the sequence are equivalent under the relation. The quotation should be an equality relation (see \ref{equality}), otherwise the result will not be useful. This is implemented by vacuously outputting \verb|t| if the sequence is empty, or otherwise, by applying the quotation to each element together with the first element in turn, and testing if it always yields a true value. Usually, this word is used to test if all elements of a sequence are equal, or the same element: +\begin{verbatim} +[ = ] every? +[ eq? ] every? +\end{verbatim} + +A pair of utility words test of every element in a sequence is true, or if the sequence contains at least one true element. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{conjunction}{conjunction~( seq -- ?~)} +\ordinaryword{disjunction}{disjunction~( seq -- ?~)} +} +The implementations are trivial: +\begin{verbatim} +: conjunction ( v -- ? ) [ ] all? ; +: disjunction ( v -- ? ) [ ] contains? ; +\end{verbatim} + +\wordtable{ +\ordinaryword{subset-with}{subset-with ( object seq quot -- seq )} +\texttt{quot:~object element -- ?}\\ +\ordinaryword{some-with?}{some-with?~( object seq quot -- ?~)} +\texttt{quot:~object element -- ?}\\ +\ordinaryword{all-with?}{all-with?~( object seq quot -- ?~)} +\texttt{quot:~object element -- ?}\\ +} +Curried forms of the above combinators. They pass an additional object to each invocation of the quotation. + +\section{Oddball operations}\label{oddball-seq} + +These operations do not fit into any clearly-defined functional category, but are nonetheless useful. \wordtable{ \vocabulary{sequences} \genericword{empty?}{empty?~( seq -- ?~)} } Tests if the sequence contains any elements. The default implementation of this word tests if the length is zero; user-defined sequences can provide a custom implementation that is more efficient. +A few convenience words are defined for accessing the first few elements. +\wordtable{ +\vocabulary{sequences} +\ordinaryword{first}{first ( seq -- elt )} +\ordinaryword{second}{second ( seq -- elt )} +\ordinaryword{third}{third ( seq -- elt )} +\ordinaryword{fourth}{fourth ( seq -- elt )} +} +Note the naming convention here; the \verb|first| word actually gets the 0th element: +\begin{verbatim} +: first 0 swap nth ; inline +\end{verbatim} +\wordtable{ +\vocabulary{sequences} +\ordinaryword{first2}{first2 ( seq -- first second )} +\ordinaryword{first3}{first3 ( seq -- first second third )} +} +Outputs the first two, or the first three elements of the sequence, respectively. + \wordtable{ \vocabulary{sequences} \ordinaryword{peek}{peek ( sequence -- element )} @@ -2082,43 +2706,12 @@ Adds and removes an element at the end of the sequence. The sequence's length is dup peek >r dup length 1 - swap set-length r> ; \end{verbatim} -\subsection{Aggregation}\label{aggregation} +\wordtable{ +\vocabulary{sequences} +\ordinaryword{push-new}{push-new ( element sequence -- )} +} -A set of words for combining sequences into new sequences. - -\wordtable{ -\vocabulary{sequences} -\ordinaryword{append}{append ( s1 s2 -- seq )} -} -Output a new sequence consisting of the elements of \texttt{s1} followed by the elements of \texttt{s2}. The new sequence is of the same class as \texttt{s1}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{append3}{append3 ( s1 s2 s3 -- seq )} -} -Append the three sequences \texttt{s1}, \texttt{s2} and \texttt{s3} into a new sequence of the same class as \texttt{s1}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{concat}{concat ( sequence -- sequence )} -} -The input is a sequence of sequences. If the input is empty, the output is the empty list (\texttt{f}). Otherwise, the elements of the input sequence are concatenated together, and a new sequence of the same type as the first element is output. -\begin{alltt} - [ "a" [ CHAR: b ] \tto CHAR: c \ttc ] concat . -\textbf{"abc"} -\end{alltt} -\wordtable{ -\vocabulary{sequences} -\ordinaryword{nappend}{nappend ( s1 s2 -- )} -} -Append \texttt{s2} to \texttt{s1}. Nothing is output, and \texttt{s1} is modified. -\wordtable{ -\vocabulary{sequences} -\genericword{reverse}{reverse ( seq -- seq )} -} -Outputs a new sequence of the same class, with the reverse element order. A related word is \verb|reverse-slice|; see \ref{virtual-seq}. - -\subsection{Indexing} - -A set of words dealing with sequence element indices. +Adds the element to the sequence if the sequence does not already contain an equal element. \wordtable{ \vocabulary{sequences} @@ -2128,185 +2721,18 @@ A set of words dealing with sequence element indices. Applies the quotation to the $n$th element of the sequence, and store the output back in the $n$th slot of the sequence. This modifies \texttt{seq} and so throws an exception if it is immutable. \wordtable{ \vocabulary{sequences} -\ordinaryword{index}{index ( obj seq -- n )} -\ordinaryword{index*}{index* ( obj i seq -- n )} +\ordinaryword{}{ ( n object -- seq )} } -Outputs the index of the first element in the sequence equal to \texttt{obj}. If no element is found, outputs $-1$. The \verb|index*| form allows a start index to be specified. A related word is \verb|member?|. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{start}{start ( subseq seq -- n )} -\ordinaryword{start*}{start* ( subseq i seq -- n )} -} -Outputs the start index of a subsequence, or $-1$ if the subsequence does not occur in the sequence. The \verb|start*| form allows a start index to be specified. A related word is \verb|subseq?|. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{cut}{cut ( seq n -- s1 s2 )} -} -Outputs a pair of sequences that equal the original sequence when appended. The first sequence has length $n$, the second has length $l-n$ where $l$ is the length of the input. +Creates an immutable sequence consisting of \verb|object| repeated $n$ times. No storage allocation of $n$ elements is made; rather a repeated sequence is just a tuple where the \verb|nth| word is implemented to return the same value on each invocation. \begin{alltt} - "Hello world" 5 cut .s -\textbf{" world" -"Hello"} -\end{alltt} -\wordtable{ -\vocabulary{sequences} -\ordinaryword{cut*}{cut* ( seq n -- s1 s2 )} -} -Outputs a pair of sequences that equal the original sequence excluding the $n$th element, when appended. The first sequence has length $n$, the second has length $l-n$ where $l$ is the length of the input. -\begin{alltt} - "Hello world" 5 cut* .s -\textbf{"world" -"Hello"} + 5 "hey" . +<< repeated [ ] 5 "hey" >> + 5 "hey" >list . +[ "hey" "hey" "hey" "hey" "hey" ] \end{alltt} -\subsection{Subsequences}\label{subseq} - -A set of words for extracting subsequences of contiguous elements, and performing operations on them. - -\wordtable{ -\vocabulary{sequences} -\ordinaryword{subseq?}{subseq?~( s1 s2 -- ?~)} -} -Tests if \texttt{s2} contains \texttt{s1} as a subsequence. A related word is \verb|start|. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{head?}{head?~( s1 s2 -- ?~)} -\ordinaryword{tail?}{tail?~( s1 s2 -- ?~)} -} -Tests if \texttt{s1} starts or ends with \texttt{s1}. If \texttt{s1} is longer than \texttt{s2}, outputs \texttt{f}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{head}{head~( n seq -- seq )} -} -Outputs a new sequence consisting of the first $n$ elements of the input sequence. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{tail}{tail~( n seq -- seq )} -} -Outputs a new sequence consisting of all elements of the sequence, starting at the $n$th index. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{tail*}{tail*~( n seq -- seq )} -} -Outputs a new sequence consisting of the last $n$ elements of the input sequence. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{?head}{?head~( s1 s2 -- seq ?~)} -\ordinaryword{?tail}{?tail~( s1 s2 -- seq ?~)} -} -Tests if \texttt{s1} starts or ends with \texttt{s1} as a subsequence. If there is a match, outputs the subrange of \texttt{s1} excluding \texttt{s1} followed by \texttt{t}. If there is no match, outputs \texttt{s1} followed by \texttt{f}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{split1}{split1~( seq split -- before after )} -} -If \texttt{seq} does not contain \texttt{split} as a subsequence, then \texttt{before} is equal to the \texttt{seq}, and \texttt{after} is \texttt{f}. Otherwise, \texttt{before} and \texttt{after} are both sequences, and yield the input excluding \texttt{split} when appended. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{split}{split~( seq split -- list )} -} -Outputs a list of subsequences taken between occurrences of \texttt{split} in \texttt{seq}. If \texttt{split} does not occur in \texttt{seq}, outputs a singleton list containing \texttt{seq} only. -\begin{alltt} - "/usr/local/bin" "/" split . -\textbf{[ "" "usr" "local" "bin" ]} -\end{alltt} -\wordtable{ -\vocabulary{sequences} -\ordinaryword{group}{group~( str n -- list )} -} -Splits the sequence into groups of $n$ elements and collects each group in a list. If the sequence length is not a multiple of $n$, the final subsequence in the list will be shorter than $n$. - -\subsection{Set-theoretic operations} - -A set of words for testing membership, and aggregating sequences without regard for element order. - -\wordtable{ -\vocabulary{sequences} -\ordinaryword{member?}{member?~( elt seq -- ?~)} -} -Tests if \texttt{seq} contains an element equal to \texttt{elt}. A related word is \verb|index|. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{memq?}{memq?~( elt seq -- ?~)} -} -Tests if the sequence contains the actual object given. Elements are compared by identity. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{contained?}{contained?~( s1 s2 -- ?~)} -} -Tests if every element of \texttt{s1} is equal to some element of \texttt{s2}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{remove}{remove ( object seq -- seq )} -} -Outputs a new sequence containing all elements of the input sequence except those equal to the \texttt{object}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{remq}{remq ( object seq -- seq )} -} -Outputs a new sequence containing all elements of the \texttt{list} except \texttt{object}. Elements are compared by identity. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{prune}{prune ( seq -- seq )} -} -Outputs a new sequence with each element of \verb|seq| appearing only once. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{seq-union}{seq-union ( seq seq -- seq )} -} -Outputs a sequence of elements present in one or both sequences, filtering duplicates by comparing elements for equality. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{seq-intersect}{seq-intersect ( seq seq -- seq )} -} -Outputs a sequence of elements present in both sequences, comparing elements for equality. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{seq-diff}{seq-diff ( s1 s2 -- seq )} -} -Outputs a sequence of elements present in \texttt{sl2} but not \texttt{s1}, comparing elements for equality. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{seq-diffq}{seq-diffq ( s1 s2 -- seq )} -} -Outputs a sequence of elements present in \texttt{sl2} but not \texttt{s1}, comparing elements for identity. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{subset}{subset ( seq quot -- seq )} -\texttt{quot:~element -- ?}\\ -} -Applies the quotation to each element, and outputs a new sequence containing the elements of the original sequence for which the quotation output a true value. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{contains?}{contains?~( seq quot -- ?~)} -\texttt{quot:~element -- ?}\\ -} -Applies the quotation to each element of the sequence. If an element is found for which the quotation outputs a true value, a true value is output. Otherwise if the end of the sequence is reached, \verb|f| is output. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{all?}{all?~( seq quot -- ?~)} -\texttt{quot:~element -- ?}\\ -} -Outputs \texttt{t} if the quotation yields true when applied to each element, otherwise outputs \texttt{f}. Given an empty sequence, vacuously outputs \texttt{t}. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{fiber?}{fiber?~( seq quot -- ?~)} -\texttt{quot:~element element -- ?}\\ -} -Tests if all elements of the sequence are equivalent under the relation. The quotation should be an equality relation, otherwise the result will not be useful. This is implemented by vacuously outputting \verb|t| if the sequence is empty, or otherwise, by applying the quotation to each element together with the first element in turn, and testing if it always yields a true value. Usually, this word is used to test if all elements of a sequence are equal, or the same element: -\begin{verbatim} -[ = ] fiber? -[ eq? ] fiber? -\end{verbatim} - -\wordtable{ -\ordinaryword{subset-with}{subset-with ( object seq quot -- seq )} -\texttt{quot:~object element -- ?}\\ -\ordinaryword{some-with?}{some-with?~( object seq quot -- ?~)} -\texttt{quot:~object element -- ?}\\ -\ordinaryword{all-with?}{all-with?~( object seq quot -- ?~)} -\texttt{quot:~object element -- ?}\\ -} -Curried forms of the above combinators. They pass an additional object to each invocation of the quotation. +\glossary{name=repeated sequence, +description={an instance of the \texttt{repeated} class, which is a virtual, immutable sequence consisting of a fixed element repeated a certain number of times}} \section{Vectors}\label{vectors} @@ -2356,6 +2782,7 @@ Creates a new vector of the requested length, where all elements are initially \ } A \emph{cons cell} is an ordered pair of values. The first value is called the \emph{car}, the second is called the \emph{cdr}. The literal syntax of cons cells is documented in \ref{listsyntax}. +Cons cells, and by extension lists, are immutable. \wordtable{ \vocabulary{lists} @@ -2399,7 +2826,13 @@ Here is an example: \textbf{"gravy" "potatoes"} \end{alltt} -Cons cells, and by extension lists, are immutable. + +\wordtable{ +\vocabulary{lists} +\ordinaryword{2car}{2car ( c1 c2 -- car1 car2 )} +\ordinaryword{2cdr}{2cdr ( c1 c2 -- cdr1 cdr2 )} +} +Deconstructs paired lists. Compare the stack effects with those of \verb|car|, \verb|cdr| and \verb|uncons| \subsection{Lists}\label{lists} @@ -2465,65 +2898,9 @@ Makes a list of one element. Makes a list of two elements. \wordtable{ \vocabulary{lists} -\ordinaryword{2unlist}{2unlist ( [ o1 o2 ] -- o1 o2 )} -} -Pushes the first two elements of a list. -\wordtable{ -\vocabulary{lists} -\ordinaryword{3list}{3list ( o1 o2 o3 -- [ o1 o2 o3 ] )} -} -Makes a list of three elements. -\wordtable{ -\vocabulary{lists} -\ordinaryword{3unlist}{3unlist ( [ o1 o2 o3 ] -- o1 o2 o3 )} -} -Pushes the first three elements of a list. -\wordtable{ -\vocabulary{lists} \ordinaryword{unique}{unique ( obj list -- list )} } If the list already contains an element equal to the object, do nothing, otherwise cons the object into the list. -\wordtable{ -\vocabulary{lists} -\ordinaryword{count}{count~( n -- list )} -} -Return a new list containing all integers from 0 up to $n-1$, inclusive. - -\wordtable{ -\vocabulary{lists} -\ordinaryword{sort}{sort~( list quot -- list )} -\texttt{quot:~e1 e2 -- ?}\\ -} -Sorts the list by comparing each pair of elements with the quotation. The quotation should output \texttt{t} if \texttt{e2} is to come before \texttt{e1} in the list. For example, to sort a list of numbers in ascending order, you can do the following: -\begin{alltt} - [ 8 6 9 1 10 3 ] [ > ] sort . -[ 1 3 6 8 9 10 ] -\end{alltt} - -\subsection{Queues} - -The following set of words manages LIFO (last-in-first-out) queues. Queues are built up from cons cells, and hence are immutable; queue operations always return a new queue. - -\wordtable{ -\vocabulary{lists} -\ordinaryword{}{ ( -- queue )} -} -Makes a new queue with no elements. -\wordtable{ -\vocabulary{lists} -\ordinaryword{queue-empty?}{queue-empty?~( queue -- ?~)} -} -Outputs \texttt{t} if the given queue does not contain any elements, \texttt{f} otherwise. -\wordtable{ -\vocabulary{lists} -\ordinaryword{deque}{deque ( queue -- element queue )} -} -Dequeues an element and outputs a new queue without that element. -\wordtable{ -\vocabulary{lists} -\ordinaryword{enque}{deque ( element queue -- queue )} -} -Enqueues an element and outputs a new queue. \section{Strings}\label{strings} @@ -2597,91 +2974,10 @@ Tests if the object at the top of the stack is a string buffer. \vocabulary{strings} \ordinaryword{>sbuf}{>sbuf~( sequence -- sbuf )} } -Turns any type of sequence into a string buffer. Given a string buffer, this makes a fresh copy. +Turns a sequence of integers into a string buffer. Given a string buffer, this makes a fresh copy. String buffers support the stream input and output protocol (\ref{string-streams}). -\section{Virtual sequences}\label{virtual-seq} - -\glossary{name=virtual sequence, -description={a sequence that is not backed by actual storage, but instead either computes its values, or take them from an underlying sequence}} -\glossary{name=repeated sequence, -description={an instance of the \texttt{repeated} class, which is a virtual, immutable sequence consisting of a fixed element repeated a certain number of times}} - -Virtual sequences are not backed by actual storage, but instead either compute their values, or take them from an underlying sequence. - -\glossary{name=range sequence, -description={an instance of the \texttt{range} class, which is a virtual sequence of integers}} -\wordtable{ -\vocabulary{sequences} -\ordinaryword{}{ ( a b -- seq )} -} -Creates an immutable sequence consisting of all integers in the interval $[a,b)$ (if $ab$). If $a=b$, the resulting sequence is empty. As with repeated sequences, this is just a tuple implementing the sequence protocol. -\begin{alltt} - CHAR: a CHAR: z 1 + . -<< range [ ] 97 123 1 >> - CHAR: a CHAR: z 1 + >string . -"abcdefghijklmnopqrstuvwxyz" - CHAR: z CHAR: a 1 - >string . -"zyxwvutsrqponmlkjihgfedcba" -\end{alltt} -\glossary{name=slice, -description={an instance of the \texttt{slice} class, which is a virtual sequence sharing structure with a subrange of some underlying sequence}} - -\wordtable{ -\vocabulary{sequences} -\ordinaryword{}{ ( n object -- seq )} -} -Creates an immutable sequence consisting of \verb|object| repeated $n$ times. No storage allocation of $n$ elements is made; rather a repeated sequence is just a tuple where the \verb|nth| word is implemented to return the same value on each invocation. -\begin{alltt} - 5 "hey" . -<< repeated [ ] 5 "hey" >> - 5 "hey" >list . -[ "hey" "hey" "hey" "hey" "hey" ] -\end{alltt} - -\wordtable{ -\vocabulary{sequences} -\genericword{reverse-slice}{reverse-slice ( seq -- seq )} -} -Outputs a sequence with the same length as the input sequence, that presents the elements of the input sequence in reverse order. The new sequence shares storage with the given sequence. -A related word is \verb|reverse|, see \ref{aggregation}. - -\wordtable{ -\vocabulary{sequences} -\ordinaryword{}{ ( a b seq -- slice )} -} -Creates a mutable sequence that is a view of a subrange of elements of an underlying sequence. Changes to the underlying sequence are reflected in the slice, and vice versa. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{head-slice}{head-slice ( n seq -- slice )} -} -Creates a slice viewing the first $n$ elements of the input sequence. -\wordtable{ -\vocabulary{sequences} -\ordinaryword{tail-slice}{tail-slice ( n seq -- slice )} -} -Creates a slice viewing all elements of the sequence, starting at the $n$th index. - -\wordtable{ -\vocabulary{sequences} -\ordinaryword{tail-slice*}{tail-slice* ( n seq -- slice )} -} -Creates a slice viewing the last $n$ elements of the input sequence. - -There is a correspondence between the four slicing words above, and the subsequence words from \ref{subseq}: - -\begin{tabular}[t]{l|l} -Subsequence&Slice\\ -\hline -\verb|subseq|&\verb||\\ -\verb|head|&\verb|head-slice|\\ -\verb|tail|&\verb|tail-slice|\\ -\verb|tail*|&\verb|tail-slice*| -\end{tabular} - -The slice words output a new virtual sequence that shares structure with the original sequence, whereas the subsequence words output a fresh copied sequence. - \section{Constructing sequences}\label{make-seq} The library supports an idiom where sequences can be constructed without passing the partial sequence being built on the stack. This reduces stack noise, and thus simplifies code and makes it easier to understand. @@ -2692,48 +2988,68 @@ description={a variable binding policy where bindings established in a scope are \dynamicscopeglos \wordtable{ \vocabulary{namespaces} -\ordinaryword{make-list}{make-list ( quot -- list )} -\ordinaryword{make-string}{make-string ( quot -- string )} -\ordinaryword{make-sbuf}{make-sbuf ( quot -- string )} -\ordinaryword{make-vector}{make-vector ( quot -- vector )} +\ordinaryword{make}{make-list ( quot exemplar -- seq )} } -Calls the quotation in a new \emph{dynamic scope}. The quotation and any words it calls can execute the \texttt{,} and \texttt{\%} words to add elements at the end of the sequence being constructed. +Calls the quotation in a new \emph{dynamic scope}. The quotation and any words it calls can execute the \texttt{,} and \texttt{\%} words to accumulate elements. When the quotation returns, all accumulated elements are collected into a sequence with the same type as \verb|exemplar|. \wordtable{ \vocabulary{namespaces} \ordinaryword{,}{,~( element -- )} } -Adds the element to the end of the sequence being constructed by the innermost call to one of the above combinators. -\wordtable{ -\vocabulary{namespaces} -\ordinaryword{unique,}{unique,~( element -- )} -} -Adds the element to the end of the sequence being constructed as long as the sequence does not already have an equal element. -\wordtable{ -\vocabulary{namespaces} -\ordinaryword{literal,}{literal,~( element -- )} -} -Adds the element wrapped inside a one-element list, then adds the \texttt{car} word. This is used to construct quotations with \texttt{make-list} that must push a word on the stack. +Adds the element to the end of the sequence being constructed. \wordtable{ \vocabulary{namespaces} \ordinaryword{\%}{\% ( sequence -- )} } -Appends the subsequence to the end of the sequence being constructed. +Appends the given sequence to the end of the sequence being constructed. Here is an example of sequence construction: \begin{alltt} - : silly [ [ dup , ] repeat ] make-vector , ; - [ 4 [ dup silly ] repeat ] make-list . + : silly [ [ dup , ] repeat ] \tto \ttc make , ; + [ 4 [ silly ] each ] [ ] make . \textbf{[ \tto \ttc \tto 0 \ttc \tto 0 1 \ttc \tto 0 1 2 \ttc ]} \end{alltt} -Note that the sequence construction combinators will capture any variables set inside the quotation, due to the dynamic scoping behavior. These combinators are actually implemented using variables. See \ref{namespaces}. +Note that \verb|make| will capture any variables set inside the quotation, due to dynamic scoping. See \ref{namespaces}. -\chapter{Mappings} +\chapter{Collections} \glossary{name=mapping, description={an unordered collection of elements, accessed by key. Examples include association lists and hashtables}} -Mappings associate keys with values. The two classes of mappings in the Factor library are association lists and hashtables. +Apart from sequences, there are two types of collections in Factor: +\begin{itemize} +\item queues, which implement first-in-first-out semantics, +\item mappings, which associate keys with values. +\end{itemize} + +\section{Queues} + +The following set of words manages LIFO (last-in-first-out) queues. + +\wordtable{ +\vocabulary{lists} +\ordinaryword{}{ ( -- queue )} +} +Makes a new queue with no elements. +\wordtable{ +\vocabulary{lists} +\ordinaryword{queue-empty?}{queue-empty?~( queue -- ?~)} +} +Outputs \texttt{t} if the given queue does not contain any elements, \texttt{f} otherwise. +\wordtable{ +\vocabulary{lists} +\ordinaryword{deque}{deque ( queue -- element )} +} +Dequeues an element. An exception is thrown if the queue is empty. +\wordtable{ +\vocabulary{lists} +\ordinaryword{enque}{deque ( element queue -- )} +} +Enqueues an element. + +\section{Mappings} + +The two classes of mappings in the Factor library are association lists and hashtables. \begin{tabular}[t]{l|c|c|c|l} Class&Mutable&Ordered&Lookup&Primary purpose\\ @@ -2744,7 +3060,7 @@ Class&Mutable&Ordered&Lookup&Primary purpose\\ It might be tempting to just always use hashtables, however for very small mappings, association lists are just as efficient, and are easier to work with since the entire set of list words can be used with them. -\section{Association lists} +\subsection{Association lists} \glossary{name=association list, description={a list of pairs, where the car of each pair is a key and the cdr is the value associated with that key}} @@ -2765,12 +3081,6 @@ Tests if the object at the top of the stack is a proper list whose every element These words look up a key in an association list, comparing keys in the list with the given key by equality with \texttt{=}. The list is searched starting from the beginning. The two words differ in that the latter returns the key/value pair located, whereas the former only returns the value. The \texttt{assoc*} word allows a distinction to be made between a missing value. \wordtable{ \vocabulary{lists} -\ordinaryword{assq}{assq ( k alist -- v )} -\ordinaryword{assq*}{assq* ( k alist -- [[ k v ]] )} -} -These words compare keys by identity with \texttt{eq?}~and are dual to \texttt{assoc} and \texttt{assoc*}. -\wordtable{ -\vocabulary{lists} \ordinaryword{acons}{acons ( v k alist -- alist )} \ordinaryword{set-assoc}{set-assoc ( v k alist -- alist )} } @@ -2803,37 +3113,7 @@ Outputs a new association list which does not have any key/value pairs with the \end{center} \end{figure} -\subsection{Dual representation} - -Sometimes it is convenient to decompose an association list into two lists of equal length, containing the keys and values, respectively, in the same order as the association list. This dual representation can be manipulated with a handful of helper words. - -\wordtable{ -\vocabulary{lists} -\ordinaryword{zip}{zip ( keys values -- alist )} -\ordinaryword{unzip}{unzip ( alist -- keys values )} -} -These words convert between pairs of lists and lists of pairs. -\begin{alltt} - [ 1 2 3 ] [ 4 5 6 ] zip . -[ [[ 1 4 ]] [[ 2 5 ]] [[ 3 6 ]] ] - [ [[ 1 2 ]] [[ 3 4 ]] [[ 5 6 ]] ] unzip .s -[ 2 4 6 ] -[ 1 3 5 ] -\end{alltt} -\wordtable{ -\vocabulary{lists} -\ordinaryword{2cons}{2cons ( car1 car2 cdr1 cdr2 -- c1 c2 )} -} -Cons a pair of elements onto a pair of lists. -\wordtable{ -\vocabulary{lists} -\ordinaryword{2car}{2car ( c1 c2 -- car1 car2 )} -\ordinaryword{2cdr}{2cdr ( c1 c2 -- cdr1 cdr2 )} -\ordinaryword{2uncons}{2uncons ( c1 c2 -- car1 car2 cdr1 cdr2 )} -} -Deconstructs paired lists. Compare the stack effects with those of \verb|car|, \verb|cdr| and \verb|uncons| in \ref{cons-cells}. - -\section{Hashtables}\label{hashtables} +\subsection{Hashtables}\label{hashtables} \hashglos \glossary{name=bucket, @@ -2851,10 +3131,11 @@ A hashtable sorts key/value pairs into buckets using a hashing function. The num } Outputs the hashcode of the object. The contract of this generic word is as follows: \begin{itemize} -\item The hashcode must be a fixnum (\ref{integers})\footnote{Strictly speaking, returning a bignum will not fail, however it will result in lower overall performance since the compiler will no longer make type assumptions when compiling callers of \texttt{hashcode}.} -\item If two objects are equal under \texttt{=}, they must have the same hashcode. +\item the hashcode must be a fixnum (\ref{integers})\footnote{Strictly speaking, returning a bignum will not fail, however it will result in lower overall performance since the compiler will no longer make type assumptions when compiling callers of \texttt{hashcode}.}, +\item if two objects are equal under \texttt{=}, they must have the same hashcode, +\item the word must not have any side effects \end{itemize} -If mutable objects are used as hashtable keys, they must not be mutated. Doing so will violate bucket sorting invariants and result in undefined behavior. +If mutable objects are used as hashtable keys, they must not be mutated in such a way that their hashcode changes. Doing so will violate bucket sorting invariants and result in undefined behavior. \wordtable{ \vocabulary{hashtables} @@ -2919,6 +3200,29 @@ Applies the quotation to each key/value pair, collecting the key/value pairs for } If the key is present in the hashtable, return the associated value, otherwise apply the quotation to the key, yielding a new value that is then stored in the hashtable. +There is a pair of words for working with lazily-instantiated hashtables. + +\wordtable{ +\vocabulary{hashtables} +\ordinaryword{?hash}{?hash ( key hash/f -- value )} +} +Outputs the value of the key, or \texttt{f} if the hashtable is \texttt{f}. The standard \verb|hash| word would raise an exception in the latter case. + +\wordtable{ +\vocabulary{hashtables} +\ordinaryword{?set-hash}{?set-hash ( value key hash/f -- hash )} +} +If the given hashtable is not \verb|f|, store the key/value pair and output the same hashtable instance. Otherwise if the given hashtable if \verb|f|, create a new hashtable holding the key/value pair. + +The following pair of words from the UI framework (see \ref{ui}) demonstrate the lazily-insantiated hashtable idiom: +\begin{verbatim} +: paint-prop* ( gadget key -- value ) + swap gadget-paint ?hash ; + +: set-paint-prop ( gadget value key -- ) + pick gadget-paint ?set-hash swap set-gadget-paint ; +\end{verbatim} + \subsection{Converting between mappings} \wordtable{ @@ -2939,28 +3243,11 @@ Creates an association list with the same key/valie pairs as the hashtable. Builds lists of keys and values stored in the hashtable. \wordtable{ \vocabulary{hashtables} -\ordinaryword{buckets>list}{buckets>list ( hash -- list )} +\ordinaryword{buckets>vector}{buckets>vector ( hash -- vector )} } -Outputs a list of association lists, where each association list contains the key/value pairs in a certain bucket. Useful for debugging hashcode distribution. +Outputs a vector of association lists, where each association list contains the key/value pairs in a certain bucket. Useful for debugging hashcode distribution. -\subsection{Hashtable construction} - -A facility analogous to sequence construction (\ref{make-seq}) exists for hashtables. - -\wordtable{ -\vocabulary{hashtables} -\ordinaryword{make-hash}{make-hash ( quot -- hash )} -} -Calls the quotation in a new dynamic scope. The quotation and any words it calls can execute the \texttt{hash,} word to add key/value pairs to the hashtable being constructed. -\wordtable{ -\vocabulary{hashtables} -\ordinaryword{hash,}{hash,~( value key -- )} -} -Adds a key/value pair to the hashtable currently being constructed. - -As with sequence construction, care must be taken to mind the effects of dynamic scoping on variable assignment performed by the quotation. Details are in \ref{namespaces}. - -\section{Variables and namespaces}\label{namespaces} +\subsection{Variables and namespaces}\label{namespaces} A variable is an entry in a hashtable of bindings, with the hashtable being implicit rather than passed on the stack. These hashtables are termed \emph{namespaces}. Nesting of scopes is implemented with a search order on namespaces, defined by a \emph{name stack}. Since namespaces are just hashtables, any object can be used as a variable, however by convention, variables are keyed by symbols (\ref{symbols}). @@ -3031,18 +3318,22 @@ outer \vocabulary{namespaces} \ordinaryword{with-scope}{with-scope ( quot -- )} } -Calls the quotation in a new dynamic scope. Any variables set by the quotation are discarded when it returns. +Calls the quotation in a new namespace. Any variables set by the quotation are discarded when it returns. \wordtable{ \vocabulary{namespaces} -\ordinaryword{}{ ( -- ns )} +\ordinaryword{make-hash}{make-hash ( quot -- hash )} } -Creates a hashtable with a certain default size. +Calls the quotation in a new namespace, and outputs this namespace when the quotation returns. Useful for quickly building hashtables; for example: +\begin{alltt} + [ 1 "one" set 2 "two" set ] make-hash . +\textbf{\tto\tto [[ "one" 1 ]] [[ "two" 2 ]] \ttc\ttc} +\end{alltt} + \wordtable{ \vocabulary{namespaces} \ordinaryword{bind}{bind ( ns quot -- )} -\ordinaryword{extend}{extend ( ns quot -- namespace )} } -Calls the quotation in the dynamic scope of \texttt{ns}. When variables are looked up by the quotation, \texttt{ns} is checked first, and setting variables in the quotation stores them in \texttt{ns}. The \texttt{extend} word places the namespace back on the data stack when the quotation returns. +Calls the quotation in the dynamic scope of \texttt{ns}. When variables are looked up by the quotation, \texttt{ns} is checked first, and setting variables in the quotation stores them in \texttt{ns}. \wordtable{ \vocabulary{namespaces} \ordinaryword{namespace}{namespace ( -- ns )} @@ -3082,10 +3373,22 @@ If the variable is set in the current namespace, outputs its value. Otherwise se Factor attempts to preserve natural mathematical semantics for numbers. Multiplying two large integers never results in overflow, and dividing two integers yields an exact fraction rather than a floating point approximation. Floating point numbers are also supported, along with complex numbers. -\section{Number protocol} +\section{Number protocol}\label{number-protocol} + +\numupgradeglos The following usual operations are supported by all numbers. +These words obey the rules of numerical upgrading. If one of the inputs is a \texttt{bignum} and the other is a \texttt{fixnum}, the latter is first coerced to a \texttt{bignum}; if one of the inputs is a \texttt{float}, the other is coerced to a \texttt{float}. + +Two examples where you should note the types of the inputs and outputs: +\begin{alltt} + 3 >fixnum 6 >bignum * class . +\textbf{bignum} + 1/2 2.0 + . +\textbf{4.5} +\end{alltt} + \wordtable{ \vocabulary{math} \ordinaryword{+}{+ ( n n -- n )} @@ -3095,19 +3398,6 @@ The following usual operations are supported by all numbers. } The non-commutative operations \texttt{-} and \texttt{/} take operands from the stack in the natural order; \texttt{6 2 /} divides 6 by 2. -\wordtable{ -\vocabulary{math} -\ordinaryword{/i}{/i ( n n -- integer )} -\ordinaryword{/f}{/f ( n n -- float )} -} -The \texttt{/} word gives an exact answer where possible. These two words output the answer in other forms. The \texttt{/i} word truncates the result towards zero, and \texttt{/f} converts it to a floating point approximation. -\wordtable{ -\vocabulary{math} -\ordinaryword{\hhat}{\^{} ( x y -- z )} - -} -Raises \texttt{x} to the power of \texttt{y}. If \texttt{y} is an integer the answer is computed exactly, otherwise a floating point approximation is used. - The following ordering operations are supported on real numbers only. \wordtable{ @@ -3118,6 +3408,15 @@ The following ordering operations are supported on real numbers only. \ordinaryword{>=}{>= ( n n -- ?~)} } +The following pair of division operations are supported on integers only. + +\wordtable{ +\vocabulary{math} +\ordinaryword{/i}{/i ( n n -- integer )} +\ordinaryword{/f}{/f ( n n -- float )} +} +The \texttt{/} word gives an exact answer where possible. These two words output the answer in other forms. The \texttt{/i} word truncates the result towards zero, and \texttt{/f} converts it to a floating point approximation. + \section{Integers}\label{integers} \integerglos @@ -3164,30 +3463,6 @@ The word \texttt{.} prints numbers in decimal, regardless of how they were input } Prints an integer in hexadecimal, octal or binary. -\subsection{Counted loops} - -A pair of combinators calls a quotation a fixed number of times. - -\wordtable{ -\vocabulary{math} -\ordinaryword{times}{times ( n quot -- )} -\texttt{quot:~-- }\\ -} -Calls the quotation $n$ times. If $n<0$, the quotation is not called at all. - -\wordtable{ -\vocabulary{math} -\ordinaryword{repeat}{repeat ( n quot -- )} -\texttt{quot:~i -- i }\\ -} -Calls \texttt{quot} $n$ times, with the parameter \texttt{i} ranging from 0 to $n-1$. The quotation must output $i$ unmodified; or indeed, if it modifies it, the loop continues from that index. That is, the value $i$ on the stack is the actual loop counter, not a copy. - -If you wish to perform an iteration over a range of integers that does not begin from zero, or an iteration that starts at a specific index and decreases towards zero, use the \verb|each| combinator (\ref{iteration}) in conjunction with a \verb|| sequence (\ref{virtual-seq}), for example like so: -\begin{verbatim} -! Print all integers from 9 down to 4, inclusive -9 3 [ . ] each -\end{verbatim} - \subsection{Modular arithmetic} \wordtable{ @@ -3221,14 +3496,14 @@ Computes both the quotient and remainder. That is, \texttt{/mod} could be define \end{verbatim} \wordtable{ \vocabulary{math} -\ordinaryword{gcd}{gcd ( x y -- a c )} +\ordinaryword{gcd}{gcd ( x y -- a d )} } Applies the Euclidian algorithm to \texttt{x} and \texttt{y}. The output values satisfy the following property for some integer $b$: -$$ax+by=c$$ -Furthermore, $c$ is the greatest integer having this property; that is, it is the greatest common divisor of $a$ and $b$. +$$ax+by=d$$ +Furthermore, $d$ is the greatest integer having this property; that is, it is the greatest common divisor of $a$ and $b$. \wordtable{ \vocabulary{math} -\ordinaryword{mod-inv}{gcd ( x n -- y )} +\ordinaryword{mod-inv}{mod-inv ( x n -- y )} } Computes a value \texttt{y} that satisfies the following property: $$xy \equiv 1 \bmod{n}$$ An exception is thrown if no such \texttt{y} exists. @@ -3295,7 +3570,7 @@ Computes a new integer consisting of the bits of the first integer, shifted to t \vocabulary{math} \ordinaryword{log2}{log2 ( n -{}- b )} } -Computes the largest integer less than or equal to $log_2 n$. The input must be positive and the result is always an integer. In most cases, the \verb|log| word (\ref{algebraic}) should be used instead, since it allows any complex number as input, and the result is not truncated to an integer. +Computes the largest integer less than or equal to $\log_2 n$. The input must be positive and the result is always an integer. In most cases, the \verb|log| word (\ref{algebraic}) should be used instead, since it allows any complex number as input, and the result is not truncated to an integer. \wordtable{ \vocabulary{math} @@ -3432,6 +3707,12 @@ Complex numbers arise as solutions to quadratic equations whose graph does not i } Tests if the top of the stack is a complex number. Note that unlike math, where all real numbers are also complex numbers, Factor only considers a number to be a complex number if its imaginary part is non-zero. +\wordtable{ +\vocabulary{math} +\ordinaryword{conjugate}{conjugate ( n -- n )} +} +Outputs the complex conjugate of a complex number. The complex conjugate of $a+bi$ is denoted $\overline{a+bi}$ and equals $a-bi$. + \wordtable{ \vocabulary{math} \ordinaryword{real}{real ( n -- n )} @@ -3533,9 +3814,14 @@ The next set of words computes powers and logarithms. \vocabulary{math} \ordinaryword{sq}{sq ( x -- y )} \ordinaryword{sqrt}{sqrt ( x -- y )} -\ordinaryword{recip}{recip ( x -- y )} } -Computes the square (raised to power 2), square root (raised to power $1/2$), and reciprocal (raised to power $-1$). +Computes the square (raised to power 2) and square root (raised to power $1/2$). +\wordtable{ +\vocabulary{math} +\ordinaryword{\hhat}{\^{} ( x y -- z )} + +} +Raises \texttt{x} to the power of \texttt{y}. If \texttt{y} is an integer the answer is computed exactly, otherwise a floating point approximation is used. \wordtable{ \vocabulary{math} \ordinaryword{exp}{exp ( n -- n )} @@ -3559,6 +3845,31 @@ Computes the natural (base $e$) logarithm. This is the inverse of the \texttt{ex \end{alltt} The \texttt{math} vocabulary provides the full set of trigonometric and hyperbolic functions, along with inverses and reciprocals. Complex number arguments are supported. +\index{\texttt{sin}} +\index{\texttt{cos}} +\index{\texttt{tan}} +\index{\texttt{cosec}} +\index{\texttt{sec}} +\index{\texttt{cot}} +\index{\texttt{asin}} +\index{\texttt{acos}} +\index{\texttt{atan}} +\index{\texttt{acosec}} +\index{\texttt{asec}} +\index{\texttt{acot}} +\index{\texttt{sinh}} +\index{\texttt{cosh}} +\index{\texttt{tanh}} +\index{\texttt{cosech}} +\index{\texttt{sech}} +\index{\texttt{coth}} +\index{\texttt{asinh}} +\index{\texttt{acosh}} +\index{\texttt{atanh}} +\index{\texttt{acosech}} +\index{\texttt{asech}} +\index{\texttt{acoth}} + \begin{tabular}{l|l|l|l|l} Function&Trigonometric&Hyperbolic&Trig. inverse&Hyp. inverse\\ \hline @@ -3575,6 +3886,13 @@ Cotangent&\texttt{cot}&\texttt{coth}&\texttt{acot}&\texttt{acoth} The following words in the \texttt{math} vocabulary push constant values on the stack. +\index{\texttt{i}} +\index{\texttt{-i}} +\index{\texttt{inf}} +\index{\texttt{-inf}} +\index{\texttt{e}} +\index{\texttt{pi}} + \begin{tabular}{l|l} Word&Value\\ \hline @@ -3584,13 +3902,10 @@ Word&Value\\ \texttt{-inf}&Negative floating point infinity\\ \texttt{e}&Base of natural logarithm ($e\approx 2.7182818284590452354$)\\ \texttt{pi}&Ratio of circumference to diameter ($\pi\approx 3.14159265358979323846$)\\ -\texttt{pi/2}&$\frac{\pi}{2}\approx 1.5707963267948966$ \end{tabular} \section{Linear algebra} -The \verb|matrices| vocabulary provides a set of words for simple algebraic operations on mathematical vectors and matrices. - \subsection{Vectors} Any Factor sequence can be used to represent a mathematical vector, not just instances of the \verb|vector| class. Anywhere a vector is mentioned in this section, keep in mind it is a mathematical term, not a Factor data type. @@ -3600,18 +3915,18 @@ The usual mathematical operations on vectors are supported. \subsubsection{Scaling operations} \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{vneg}{vneg ( vec -- vec )} } Negates each element of a vector. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{v*n}{v*n ( vec n -- vec )} \ordinaryword{n*v}{n*v ( n vec -- vec )} } Multiplies each element of the vector by a scalar. The two words only differ in argument order. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{v/n}{v/n ( vec n -- vec )} \ordinaryword{n/v}{n/v ( n vec -- vec )} } @@ -3622,7 +3937,7 @@ Divides each element of the vector by a scalar, or alternatively, divides the sc These words all expect a pair of vectors of equal length. They apply a binary operation to each pair of elements, producing a new vector. They are all implemented using the \verb|2map| combinator (\ref{iteration}). \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{v+}{v+ ( vec vec -- vec )} \ordinaryword{v-}{v-~( vec vec -- vec )} \ordinaryword{v*}{v*~( vec vec -- vec )} @@ -3649,54 +3964,39 @@ Note that \verb|v*| is not the inner product. The inner product is the \verb|v.| These words take a vector as input and produce a single number (or boolean). \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{sum}{sum~( vec -- n )} \ordinaryword{product}{product~( vec -- n )} } -Adds or multiplies all numbers in the vector. These are implemented as follows: +Adds or multiplies all numbers in the vector. These are implemented using the \verb|reduce| combinator (\ref{iteration}): \begin{verbatim} : sum ( v -- n ) 0 [ + ] reduce ; : product 1 [ * ] reduce ; \end{verbatim} -using the \verb|reduce| combinator (\ref{iteration}). - -\wordtable{ -\vocabulary{matrices} -\ordinaryword{conj}{conj~( vec -- ?~)} -} -Tests if all elements in the vector are true values. This is implemented as follows: -\begin{verbatim} -: conj [ ] all? ; -\end{verbatim} -\wordtable{ -\vocabulary{matrices} -\ordinaryword{disj}{disj~( vec -- ?~)} -} -Tests if at least one element in the vector is a true value. This is implemented as follows: -\begin{verbatim} -: conj [ ] contains? ; -\end{verbatim} - \subsubsection{Inner and cross products}\label{inner-product} \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{v.}{v.~( vec vec -- n )} } -Computes the inner product of two vectors. They must be of equal length. - -Mathematically speaking, this is a map $<,>: {\mathbb{C}}^n \times {\mathbb{C}}^n \rightarrow \mathbb{C}$. It is the complex inner product; that is, $ =\overline{}$, where $\overline{z}$ is the complex conjugate. +Computes the real inner product of two vectors. They must be of equal length. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} +\ordinaryword{c.}{c.~( vec vec -- n )} +} +Computes the complex inner product of two vectors. The complex inner product is skew-symmetric; that is, $=\overline{}$, where $\overline{z}$ is the complex conjugate of $z$. + +\wordtable{ +\vocabulary{math} \ordinaryword{norm}{norm~( vec -- n )} } Computes the norm (``length'') of a vector. The norm of a vector $v$ is defined as $\sqrt{}$. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{normalize}{normalize~( vec -- vec )} } Outputs a vector with the same direction, but length 1. Defined as follows: @@ -3705,7 +4005,7 @@ Outputs a vector with the same direction, but length 1. Defined as follows: \end{verbatim} \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{cross}{cross~( v1 v2 -- vec )} } Computes the cross product $v_1\times v_2$. The following example illustrates the fact that a cross product of two vectors is always orthogonal to either vector. @@ -3720,124 +4020,86 @@ Computes the cross product $v_1\times v_2$. The following example illustrates th \subsection{Matrices}\label{matrices} -Matrix literal syntax is documented in \ref{syntax:matrices}. In addition to the literal syntax, new matrices may be created from scratch in one of several ways. +Matrices are represented as sequences of sequences of equal length. For example, consider +the following object: +\begin{verbatim} +{ { 1 0 -1 } + { 2 1/3 6 } + { 4 -2 0 } + { 0 0 8 } } +\end{verbatim} +It corresponds to the following mathematical matrix: +$$\left( \begin{array}{c c c} +1 & 0 & -1 \\ +2 & 1/3 & 6 \\ +4 & -2 & 0 \\ +0 & 0 & 8 \end{array} +\right)$$ +The transpose of a matrix may be computed with the \verb|flip| word (\ref{reshaping}). \wordtable{ -\vocabulary{matrices} -\ordinaryword{}{ ( rows cols seq -- matrix )} -} -Creates a new matrix with the given dimensions and underlying sequence. The underlying sequence stores elements in row-major order. - -\wordtable{ -\vocabulary{matrices} -\ordinaryword{matrix-sequence}{matrix-sequence ( matrix -- seq )} -} -Outputs the underlying sequence of a matrix. - -\begin{alltt} - M[ [ 1 2 3 ] [ 4 5 6 ] ]M matrix-sequence . -\textbf{\tto 1 2 3 4 5 6 \ttc} -\end{alltt} - -\wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{}{ ( rows cols -- matrix )} } Creates a new matrix with the given dimensions and all elements set to zero. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{}{ ( n -- matrix )} } Creates a new $n\times n$ matrix where all elements on the main diagonal are 1, and all other elements are zero; for example: \begin{alltt} - 3 prettyprint -\textbf{M[ [ 1 0 0 ] - [ 0 1 0 ] - [ 0 0 1 ] ]M} + 3 . +\textbf{\tto \tto 1 0 0 \ttc \tto 0 1 0 \ttc \tto 0 0 1 \ttc \ttc} \end{alltt} The following are the usual algebraic operations on matrices. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{n*m}{n*m ( n matrix -- matrix )} } Multiplies each element of a matrix by a scalar. \begin{alltt} 5 2 n*m prettyprint -\textbf{M[ [ 5 0 ] - [ 0 5 ] ]M} +\textbf{\tto \tto 5 0 \ttc + \tto 0 5 \ttc \ttc} \end{alltt} \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{m+}{m+~( matrix matrix -- matrix )} } Adds two matrices. They must have the same dimensions. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{m-}{m-~( matrix matrix -- matrix )} } Subtracts two matrices. They must have the same dimensions. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{m*}{m*~( matrix matrix -- matrix )} } Multiplies two matrices element-wise. They must have the same dimensions. This is \emph{not} matrix multiplication in the usual mathematical sense. \wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{m.}{m.~( matrix matrix -- matrix )} } Composes two matrices as linear operators. This is the usual mathematical matrix multiplication, and the first matrix must have the same number of columns as the second matrix has rows. \wordtable{ -\vocabulary{matrices} -\ordinaryword{transpose}{transpose~( matrix -- matrix )} -} -Outputs a matrix where each row is a column of the original matrix, and each column is a row of the original matrix. -\begin{alltt} - M[ [ 1 2 ] [ 3 4 ] [ 5 6 ] ]M transpose . -\textbf{M[ [ 1 3 5 ] [ 2 4 6 ] ]M} -\end{alltt} - -\subsection{Column and row matrices} - -There is a natural isomorphism between the vector space $\mathbb{C}^m$, the $m\times 1$ matrices, and the $1 \times m$ matrices. Additionally, a $m\times n$ matrix acts as a linear operator from the vector space $\mathbb{C}^n$ to $\mathbb{C}^m$ in the same way as multiplying the $m\times n$ matrix by a $n \times 1$ matrix. In Factor, these ideas are embodied by a set of words for converting vectors to matrices, and vice-versa. - -\wordtable{ -\vocabulary{matrices} -\ordinaryword{}{~( vector -- matrix )} -} -Given a vector with $n$ elements, outputs a $1 \times n$ matrix. -\begin{alltt} - \tto 1.0 4.43 7.6 0.2 \ttc . -\textbf{M[ [ 1.0 4.43 7.6 0.2 ] ]M} -\end{alltt} - -\wordtable{ -\vocabulary{matrices} -\ordinaryword{}{~( vector -- matrix )} -} -Given a vector with $n$ elements, outputs a $n \times 1$ matrix. -\begin{alltt} - \tto 1.0 4.43 7.6 0.2 \ttc . -\textbf{M[ [ 1.0 ] [ 4.43 ] [ 7.6 ] [ 0.2 ] ]M} -\end{alltt} - -\wordtable{ -\vocabulary{matrices} +\vocabulary{math} \ordinaryword{m.v}{m.v~( matrix vector -- vector )} } Applies a matrix to a vector on the right, as a linear transformation. The vector is treated as a matrix with one column. \begin{alltt} - \tto 5 -3 \ttc M[ [ 0 1 ] [ 1 0 ] ]M v.m . + \tto 5 -3 \ttc \tto \tto 0 1 \ttc \tto 1 0 \ttc \ttc v.m . \textbf{\tto -3 5 \ttc} \end{alltt} @@ -3848,6 +4110,55 @@ treated as a matrix with one column. Applies a matrix to a vector on the left, as a linear transformation. The vector is treated as a matrix with one row. +\section{Converting between numbers and strings}\label{parsing-numbers} + +Two sets of words convert between numbers and strings. + +\wordtable{ +\vocabulary{math} +\ordinaryword{string>number}{string>number~( string -- number )} +} +Attempts to parse the string as a number. An exception is thrown if the string does not represent a number in one of the following forms: +\begin{itemize} +\item An integer; see \ref{integer-literals} +\item A ratio; see \ref{ratio-literals} +\item A float; see \ref{float-literals} +\end{itemize} +In particular, complex numbers are parsed by the \verb|#{| and \verb|}#| parsing words, not by the number parser. To parse complex number literals, use the \texttt{parse} word (\ref{parser-chapter}). +\wordtable{ +\vocabulary{math} +\genericword{base>}{base>~( string base -- integer )} +} +Converts a string representation of an integer in the given base into an integer. Throws an exception if the string is not a valid representation of an integer. +\wordtable{ +\vocabulary{math} +\ordinaryword{bin>}{bin>~( string -- integer )} +\ordinaryword{oct>}{oct>~( string -- integer )} +\ordinaryword{dec>}{dec>~( string -- integer )} +\ordinaryword{hex>}{hex>~( string -- integer )} +} +Convenience words defined in terms of \texttt{base>} for parsing integers in base 2, 8, 10 and 16, respectively. + +\wordtable{ +\vocabulary{math} +\genericword{number>string}{number>string~( number -- string~)} +} +Outputs a string representation of a number. As with \verb|string>number|, only real numbers are supported. Printing complex numbers requires the more general prettyprinter facility (see \ref{prettyprint}). +A set of words are provided for converting integers into strings with various bases. +\wordtable{ +\vocabulary{unparser} +\ordinaryword{>base}{>base~( integer base -- string~)} +} +Converts the integer into a string representation in the given base. The base must be between 2 and 36, inclusive. +\wordtable{ +\vocabulary{unparser} +\ordinaryword{>bin}{>bin~( integer -- string~)} +\ordinaryword{>oct}{>oct~( integer -- string~)} +\ordinaryword{>dec}{>dec~( integer -- string~)} +\ordinaryword{>hex}{>hex~( integer -- string~)} +} +Convenience words defined in terms of \texttt{>base} for converting integers into string representations in base 2, 8, 10 and 16, respectively. + \chapter{Streams} \glossary{name=stream, description={a source or sink of characters supporting some subset of the stream protocol, used as an end-point for input/output operations}} @@ -3887,12 +4198,12 @@ Releases any external resources associated with the stream, such as file handles You must close streams after you are finished working with them. A convenient way to automate this is by using the \texttt{with-stream} word in \ref{stdio}. -The following two words are optional, and should be implemented on input streams. +The following three words are optional, and should be implemented on input streams. \wordtable{ \vocabulary{io} \genericword{stream-readln}{stream-readln ( s -- str/f )} } -Reads a line of text and outputs it on the stack. If the end of the stream has been reached, outputs \texttt{f}. The precise meaning of a ``line'' depends on the stream. Streams that do not support this generic word can be wrapped in a line stream that reads lines terminated by \verb|\n|, \verb|\r| or \verb|\r\n| (\ref{special-stream}). File and network streams are automatically wrapped in line streams. +Reads a line of text and outputs it on the stack. If the end of the stream has been reached, outputs \texttt{f}. The precise meaning of a ``line'' depends on the stream. Streams that do not support this generic word can be wrapped in a line stream that reads lines terminated by \verb|\n|, \verb|\r| or \verb|\r\n| (\ref{special-streams}). File and network streams are automatically wrapped in line streams. \wordtable{ \vocabulary{io} \genericword{stream-read1}{stream-read1 ( s -- char/f )} @@ -3970,7 +4281,7 @@ Outputs a string to the stream, then calls \verb|stream-terpri| to force a newli description={the value of the \texttt{stdio} variable, used by various words as an implicit stream parameter}} \glossary{name=stdio, description={see default stream}} -Various words take an implicit stream parameter from the \texttt{stdio} variable to reduce stack shuffling. +Various words take an implicit stream parameter from the \texttt{stdio} variable to reduce stack shuffling. Unless rebound in a child namespace, this variable will be set to a console stream for interacting with the user. \wordtable{ \vocabulary{io} \ordinaryword{close}{close ( -- )} @@ -4076,12 +4387,11 @@ Key&Description\\ \ttindex{foreground}&The foreground color, as a list with red, green, blue components\\ \ttindex{background}&The background color, as a list with red, green, blue components\\ \ttindex{font}&A font family name\\ -\ttindex{font-style}&One of \ttindex{plain}, \ttindex{bold}, \ttindex{italic}, or \ttindex|bold-italic|\\ +\ttindex{font-style}&One of \ttindex{plain}, \ttindex{bold}, \ttindex{italic}, or \ttindex{|bold-italic}\\ \ttindex{font-size}&An integer\\ \ttindex{underline}&A boolean\\ \ttindex{presented}&If set, a presentation for this object is output\\ \ttindex{file}&If set, a hyperlink to that file is output\\ -\ttindex{icon}&If set, the icon named by this resource path is output\\ \end{tabular} All keys are symbols in the \verb|styles| vocabulary. @@ -4099,7 +4409,7 @@ String buffers support both the stream input and output protocol directly, with \vocabulary{io} \ordinaryword{}{ ( string -- stream )} } -Creates a new stream for reading characters from a string. First, a string buffer is created holding the reversed string, since characters are read in reverse by repeated calls to \verb|pop| (\ref{stack-seq}). The result is wrapped in a line stream providing a \verb|stream-readln| implementation (\ref{special-streams}): +Creates a new stream for reading characters from a string. First, a string buffer is created holding the reversed string, since characters are read in reverse by repeated calls to \verb|pop| (\ref{oddball-seq}). The result is wrapped in a line stream providing a \verb|stream-readln| implementation (\ref{special-streams}): \begin{verbatim} : ( string -- stream ) >sbuf ; @@ -4126,9 +4436,9 @@ M: sbuf stream-format rot nappend drop ; \section{Reading and writing binary data} \glossary{name=big endian, -description={a representation of an integer as a sequence of bytes, ordered from most significant to least significant. This is the native byte ordering for PowerPC, SPARC, Alpha and ARM processors}} +description={a representation of an integer as a sequence of bytes, ordered from most significant to least significant. This is the native byte ordering for PowerPC, SPARC, and ARM processors}} \glossary{name=little endian, -description={a representation of an integer as a sequence of bytes, ordered from least significant to most significant. This is the native byte ordering for x86 and x86-64 processors}} +description={a representation of an integer as a sequence of bytes, ordered from least significant to most significant. This is the native byte ordering for x86, x86-64 and Alpha processors}} The core stream words read and write strings. Packed binary integers can be read and written by converting to and from sequences of bytes. Floating point numbers can be read and written by converting them into a their bitwise integer representation (\ref{float-bits}). There are two ways to order the bytes making up an integer; \emph{little endian} byte order outputs the least significant byte first, and the most significant byte last, whereas \emph{big endian} is the other way around. @@ -4321,57 +4631,16 @@ M: tex-stream stream-format ( string attrs stream -- ) ] with-wrapper ; \end{verbatim} -\section{Printing objects} +\section{Printing objects}\label{prettyprint} \glossary{name=prettyprinter, description={a set of words for printing objects in readable form}} One of Factor's key features is the ability to print almost any object in a readable form. This greatly aids debugging and provides the building blocks for light-weight object serialization facilities. -\subsection{The unparser} - -The unparser provides a basic facility for turning certain types of objects into strings. A more general facility supporting more types is the prettyprinter (\ref{prettyprint}). -\glossary{ -name=unreadable string, -description={a string which raises a parse error when parsed}} -\glossary{ -name=readable form, -description={a readable form of an object is a string that parses to that object}} - -\wordtable{ -\vocabulary{unparser} -\genericword{unparse}{unparse~( object -- string~)} -} -Outputs a string representation of \texttt{object}. Only the following classes of objects are supported; for anything else, an unreadable string is output: -\begin{verbatim} -boolean -dll -number -sbuf -string -word -\end{verbatim} -A set of words are provided for converting integers into strings with various bases. -\wordtable{ -\vocabulary{unparser} -\ordinaryword{>base}{>base~( n base -- string~)} -} -Converts \texttt{n} into a string representation in the given base. The base must be between 2 and 36, inclusive. -\wordtable{ -\vocabulary{unparser} -\ordinaryword{>bin}{>bin~( n -- string~)} -\ordinaryword{>oct}{>oct~( n -- string~)} -\ordinaryword{>dec}{>dec~( n -- string~)} -\ordinaryword{>hex}{>hex~( n -- string~)} -} -Convenience words defined in terms of \texttt{>base} for converting integers into string representations in base 2, 8, 10 and 16, respectively. - -\subsection{The prettyprinter}\label{prettyprint} - \wordtable{ \vocabulary{prettyprint} -\ordinaryword{prettyprint}{prettyprint~( object --~)} - +\ordinaryword{.}{.~( object --~)} } Prints the object using literal syntax that can be parsed back again. Even though the prettyprinter supports more classes of objects than \texttt{unparse}, it is still not a general serialization mechanism. The following restrictions apply: @@ -4382,21 +4651,30 @@ array byte-array displaced-alien \end{verbatim} -\item Circular structure is not printed in a readable way. Circular references are printed as ``\texttt{...}''. +\item Shared structure is not reflected in the printed output; if the output is parsed back in, fresh objects are created for all literal denotations. +\item Circular structure is not printed in a readable way. Circular references are printed as ``\texttt{\#}''. \item Floating point numbers might not equal themselves after being printed and read, since a decimal representation of a float is inexact. \end{itemize} \wordtable{ \vocabulary{prettyprint} -\ordinaryword{.}{.~( object --~)} - +\ordinaryword{unparse}{unparse~( object --~string )} } -Prettyprint the object, except all output is on a single line without indentation, and deeply-nested structure is not printed fully. This word is intended for interactive use at the listener. +Prints the object to a string. \wordtable{ \vocabulary{prettyprint} -\ordinaryword{[.]}{[.]~( sequence --~)} - +\ordinaryword{short.}{short.~( object --~)} } -Prettyprint each element of the sequence on its own line using the \texttt{.} word. +Prettyprint the object, with nesting and length limits. +\wordtable{ +\vocabulary{prettyprint} +\ordinaryword{unparse-short}{unparse-short~( object --~string )} +} +Prints the object to a string with nesting and length limits. +\wordtable{ +\vocabulary{prettyprint} +\ordinaryword{sequence.}{sequence.~( sequence --~)} +} +Prettyprint each element of the sequence on its own line using the \verb|short.| word. \subsection{Variables controlling the prettyprinter} @@ -4406,100 +4684,42 @@ The following variables affect the prettyprinter if set in the dynamic scope fro \vocabulary{prettyprint} \symbolword{tab-size} } -Specifies the indentation for recursive objects such as lists, vectors, hashtables and tuples. The default tab size is 4. +Specifies the indentation for recursive objects such as lists, vectors, hashtables and tuples. The default is 4. \wordtable{ \vocabulary{prettyprint} -\symbolword{prettyprint-limit} +\symbolword{margin} } -Controls the maximum nesting depth. Printing structures that nest further than this will simply print ``\texttt{...}''. If this is set to \texttt{f}, the nesting depth is unlimited. The default is \texttt{f}. Inside calls to \texttt{.}, set to 16, which translates to four levels of nesting with the default tab size. +Specifies the maximum line length, in characters. Lines longer than the margin are wrapped. The default is 64. \wordtable{ \vocabulary{prettyprint} -\symbolword{one-line} +\symbolword{nesting-limit} } -If set to true, the prettyprinter does not emit newlines. The default is \texttt{f}. Inside calls to \texttt{.}, set to \texttt{t}. - -\subsection{Extending the prettyprinter} - -If define your own data type and wish to add new syntax for it, you must implement two facilities: -\begin{itemize} -\item Parsing word(s) for reading your data type, -\item A prettyprinter method for printing your data type. -\end{itemize} -Parsing words are documented in \ref{parsing-words}. +Specifies the maximum nesting level. Structures that nest further than this will simply print ``\texttt{\#}''. The default is \texttt{f}, which denotes unlimited nesting depth. \wordtable{ \vocabulary{prettyprint} -\genericword{prettyprint*}{prettyprint* ( indent object -- indent )} +\symbolword{length-limit} } -Prettyprints the given object. Unlike \texttt{prettyprint}, this word does not emit a trailing newline, and the current indent level is given. This word is also generic, so you can add methods to have it print your own data types in a nice way. +Specifies the maximum sequence length. Sequences longer than this are truncated, and \verb|...| is output in place of remaining elements. The default is \texttt{f}, which denotes unlimited sequence length. -The remaining words in this section are useful in the implementation of prettyprinter methods. \wordtable{ \vocabulary{prettyprint} -\genericword{unparse.}{unparse.~( object -- )} +\symbolword{line-limit} } -Prints the textual representation of an object as returned by \verb|unparse|. Generally \texttt{prettyprint*} is used instead; one important distinction with \verb|unparse.| is that if the given object is a parsing word, the output is not prefixed with \texttt{POSTPONE:}. -\wordtable{ -\vocabulary{prettyprint} -\genericword{prettyprint-newline}{prettyprint-newline ( indent -- )} -} -Emits a newline followed by the given amount of indentation. -\wordtable{ -\vocabulary{prettyprint} -\genericword{?prettyprint-newline}{?prettyprint-newline ( indent -- )} -} -If \texttt{one-line} is on, emits a space, otherwise, emits a newline followed by the given amount of indentation. -\wordtable{ -\vocabulary{prettyprint} -\genericword{}{prettyprint>~( indent -- indent )} -} -Decreases the indent level and emits a newline if \texttt{one-line} is off. +Specifies the maximum lines of output. If more than this number of lines are printed, remaining output is truncated, and \verb|...| is output in place of remaining lines. The default is \texttt{f}, which denotes unlimited lines of output. -\chapter{The parser} +\wordtable{ +\vocabulary{prettyprint} +\symbolword{string-limit} +} +If set to \verb|t|, strings longer than the margin are truncated. Otherwise, strings are printed fully, regardless of length. The default is \verb|f|. + +\chapter{The parser}\label{parser-chapter} This section concerns itself with reflective access and extension of the parser. The parser algorithm and standard syntax is described in \ref{syntax}. Before the parser proper is documented, we draw attention to a set of words for parsing numbers. They are called by the parser, and are useful in their own right. -\section{Parsing numbers}\label{parsing-numbers} - -\wordtable{ -\vocabulary{parser} -\ordinaryword{str>number}{str>number~( string -- number )} -} -Attempts to parse the string as a number. An exception is thrown if the string does not represent a number in one of the following forms: -\begin{itemize} -\item An integer; see \ref{integer-literals} -\item A ratio; see \ref{ratio-literals} -\item A float; see \ref{float-literals} -\end{itemize} -In particular, complex numbers are parsed by the \verb|#{| and \verb|}#| parsing words, not by the number parser. To parse complex number literals, use the \texttt{parse} word (\ref{parsing-quotations}). -\wordtable{ -\vocabulary{parser} -\ordinaryword{parse-number}{parse-number~( string -- number/f )} -} -Like \texttt{str>number}, except instead of raising an error, outputs \texttt{f} if the string is not a valid literal number. -\wordtable{ -\vocabulary{parser} -\genericword{base>}{base>~( string base -- integer )} -} -Converts a string representation of an integer in the given base into an integer. Throws an exception if the string is not a valid representation of an integer. -\wordtable{ -\vocabulary{parser} -\ordinaryword{bin>}{bin>~( string -- integer )} -\ordinaryword{oct>}{oct>~( string -- integer )} -\ordinaryword{dec>}{dec>~( string -- integer )} -\ordinaryword{hex>}{hex>~( string -- integer )} -} -Convenience words defined in terms of \texttt{base>} for parsing integers in base 2, 8, 10 and 16, respectively. - -\section{Parsing quotations}\label{parsing-quotations} - As documented in \ref{vocabsearch}, the parser looks up words in the vocabulary search path. New word definitions are added to the current vocabulary. These two parameters are stored in a pair of variables (\ref{namespaces}): \begin{description} \item[\texttt{"use"}] the vocabulary search path; a list of strings @@ -4532,7 +4752,7 @@ The \texttt{eval} word is defined as follows: \section{Parsing from streams} -There are two sets of words for parsing input from streams. The first set uses the following initial values for the \texttt{"use"} and \texttt{"in"} variables: +Words for parsing input from streams use the following initial values for the \texttt{"use"} and \texttt{"in"} variables: \begin{description} \item[\texttt{"use"}] \texttt{[ "scratchpad" "syntax" ]} @@ -4562,16 +4782,6 @@ Parses the contents of a file and calls the resulting quotation. Defined as foll : run-file parse-file call ; \end{verbatim} -The next set of stream parsing words takes the vocabulary search path and current vocabulary from the current scope. These words are used to load the \texttt{.factor-rc} file on startup, so that any \texttt{USE:}~and \texttt{USING:}~declarations set in that file take effect in the listener (\ref{listener}). - -\wordtable{ -\vocabulary{parser} -\genericword{(parse-stream)}{(parse-stream)~( name stream -- list )} -\genericword{(parse-file)}{(parse-file)~( path -- list )} -\genericword{(run-file)}{(run-file)~( path -- )} -} -Like the first set of stream parsing words, except the \texttt{"use"} and \texttt{"in"} variables are taken from the current scope. - \section{Parsing words}\label{parsing-words} \parsingwordglos @@ -4649,7 +4859,19 @@ Indeed, any type of object can be added to the parse tree in this fashion. \glossary{name=reading ahead, description=a parsing word reads ahead of it scans following tokens from the input string} -The next idiom to look at is parsing words that read ahead. The first example is the \verb|HEX:| word, documented in \ref{integer-literals}. This word is defined so that the following two lines are equivalent: +The next idiom to look at is parsing words that read ahead. +\wordtable{ +\vocabulary{parser} +\ordinaryword{scan}{scan ( -- string )} +} +Outputs the next token as a string, or \texttt{f} if the end of the input has been reached. Advances the parser state to after this token. +\wordtable{ +\vocabulary{parser} +\ordinaryword{scan-word}{scan-word ( -- word )} +} +Reads the next token from the input and looks up a word with this name. If the lookup fails, attempts to parse the word as a number by calling \verb|str>number|. Outputs \verb|f| if the end of input has been reached. There is no confusion with the \verb|f| literal here, since the latter is raad as the \verb|f| parsing word. + +The first example is the \verb|HEX:| word, documented in \ref{integer-literals}. This word is defined so that the following two lines are equivalent: \begin{verbatim} HEX: deadbeef 3735928559 @@ -4660,27 +4882,49 @@ It is defined in terms of a lower-level \texttt{(BASE)} word that takes the nume : HEX: 16 (BASE) ; parsing \end{verbatim} The key word here is \texttt{scan}. -\wordtable{ -\vocabulary{parser} -\ordinaryword{scan}{scan ( -- string )} -} -Outputs the next token as a string, or \texttt{f} if the end of the input has been reached. Advances the parser state to after this token. -The next example of a parsing word we will look at is the \verb|\| word. It reads the next token from the input, and appends code to push that word literally on the stack. That is, the following two phrases both have the effect of pushing the word \verb|+| on the stack, rather than executing it: +The next example of a parsing word we will look at is the \verb|\| word. It is used to insert a word literally in a quotation, that is, push it on the stack during evaluation, so that the following two lines are equivalent: \begin{verbatim} -\ + -[ + ] car +\ execute + \end{verbatim} -We can look at how \verb|\| is implemented: +The implementation of the \verb|\| parsing word reads the next token from the input stream using \verb|scan-word|. +It then uses the \verb|literalize| word to turn the word into an object that pushes the word +on the stack, and then appends this to the parse tree: \begin{verbatim} -: \ scan-word unit swons \ car swons ; parsing +: \ scan-word literalize swons ; parsing \end{verbatim} -The key word here is \verb|scan-word|. It combines \texttt{scan} word with vocabulary search. + \wordtable{ -\vocabulary{parser} -\ordinaryword{scan-word}{scan-word ( -- word )} +\vocabulary{words} +\ordinaryword{literalize}{literalize ( object -- object )} } -Reads the next token from the input and looks up a word with this name. If the lookup fails, attempts to parse the word as a number by calling \verb|str>number|. +Turns non-self-evaluating objects (words and wrappers) into wrappers that push those objects, and is a no-op on everything else. This word is generic (\ref{generic}), with three trivial methods: +\begin{verbatim} +GENERIC: literalize ( object -- object ) +M: object literalize ; +M: wrapper literalize ; +M: word literalize ; +\end{verbatim} + +\wrapglos + +Instances of the \verb|wrapper| class hold a reference to a single object. When the evaluator encounters a wrapper, it pushes the wrapped object on the data stack. + +\wordtable{ +\vocabulary{kernel} +\ordinaryword{wrapped}{wrapped ( wrapper -- object )} +} +Outputs the object wrapped by the wrapper. This word is used in the implementation of the \verb|wrapper| method of the \verb|prettyprint*| generic word: +\begin{verbatim} +M: wrapper prettyprint* + dup wrapped word? [ + \ \ unparse. bl wrapped unparse. + ] [ + \ W[ unparse. bl wrapped prettyprint* \ ]W unparse. + ] ifte ; +\end{verbatim} +The somewhat more verbose \verb|W[ ... ]W| syntax is only part of the language for completeness, to handle the corner case where a wrapper wrapping another wrapper is printed out and read back in by the parser. \subsection{Defining words} @@ -4790,7 +5034,7 @@ This word is used to implement end-of-line comments: : ! until-eol drop ; parsing \end{verbatim} -\chapter{UI framework} +\chapter{UI framework}\label{ui} \begin{itemize} @@ -5133,10 +5377,8 @@ Static content may be served by setting the \verb|"doc-root"| variable to a dire "/var/www/" "doc-root" set \end{verbatim} -If a directory holds an \verb|index.html| file, the file is served when the directory is requested, otherwise a directory listing is produced. The directory listing references icons sent via the resource responder. The icons are located in the Factor source tree, and the \verb|"resource-path"| variable may be set to the root of the source tree in order for the icons to be located: -\begin{verbatim} -"/home/slava/work/Factor/" "resource-path" set -\end{verbatim} +If a directory holds an \verb|index.html| file, the file is served when the directory is requested, otherwise a directory listing is produced. + A facility for ad-hoc server-side scripting exists. If a file with the \verb|.factsp| filename extension is requested, the file is run with \verb|run-file| and any output it sends to the default stream is sent to the client (\ref{stdio}). These ``Factor server pages'' are slower and less powerful than responders, so it is recommended that responders be used instead. A different static site can be associated with each virtual host by setting the \verb|"doc-root"| variable in each virtual host (\ref{vhosts}). @@ -5264,13 +5506,564 @@ Character&Entity\\ \verb|"| &\verb|"| \end{tabular} +\part{The implementation} + +\chapter{Development tools} + +This chapter covers various features and library words that are not used directly by user code, but are usually invoked interactively at the listener for development and testing. + +\section{Command line usage} + +A few command line parameters are supported by the Factor runtime: +\begin{description} +\item[\texttt{+D\emph{n}}] Datastack size, kilobytes +\item[\texttt{+C\emph{n}}] Callstack size, kilobytes +\item[\texttt{+G\emph{n}}] Number of generations, must be $>= 2$ +\item[\texttt{+Y\emph{n}}] Size of $n-1$ youngest generations, megabytes +\item[\texttt{+A\emph{n}}] Size of tenured and semi-spaces, megabytes +\item[\texttt{+X\emph{n}}] Code heap size, megabytes +\item[\texttt{+L\emph{n}}] Literal table size, kilobytes +\end{description} + +All other command line parameters are handled by the library: +\begin{description} +\item[\texttt{-\emph{foo}}] Sets the object path \verb|"foo"| to \verb|t| +\item[\texttt{-no-\emph{foo}}] Sets the object path \verb|"foo"| to \verb|f| +\item[\texttt{\emph{foo}=\emph{bar}}] Sets the global variable \verb|"foo"| to \verb|"bar"| +\end{description} + +An object path is a colon-delimited set of strings, where each string is a namespace nested in the one before it, and the first one resides in the global namespace. The following command line switches are supported by the library; others can be handled by user code: +\begin{description} +\item[\texttt{-libraries:\emph{foo}:name=\emph{bar}}] +\item[\texttt{-libraries:\emph{foo}:abi=\emph{bar}}] See \ref{native-libs} +\item[\texttt{-shell=\emph{foo}}] \verb|foo| is one of the following: +\begin{description} +\item[\texttt{tty}] Starts the standard terminal-based listener. Not supported on Windows; the default on Unix. +\item[\texttt{ui}] Starts the graphical user interface (see \ref{ui}). Default on Windows. +\item[\texttt{telnet}] Starts the telnet server.. +\end{description} +\item[\texttt{-telnetd-port}] Port number for \verb|telnet| shell; default is 9999 +\item[\texttt{-no-user-init}] Inhibit loading \verb|.factor-rc| + +\end{description} + +On startup, Factor reads the \texttt{.factor-rc} file from your home directory. You can put +any quick definitions you want available at the listener there. Another way to have a set of definitions available at all times is to save a custom image (see \ref{images}). + +\section{The listener}\label{listener} + +The listener reads Factor code from the terminal and executes it. The listener is a piece of Factor code, like any other; however, it helps to think of it as the primary interface to the Factor system. You can try the classical first program: +\begin{alltt} + "Hello, world." print +\textbf{Hello, world.} +\end{alltt} +Multi-line phrases are supported: +\begin{alltt} + [ 1 2 3 ] [ +. +] each +\textbf{1 +2 +3} +\end{alltt} +The listener knows when to expect more input by looking at the height of the +stack. Parsing words such as \texttt{[} and \texttt{:} leave elements on the parser +stack; these elements are popped by \texttt{]} and \texttt{;}. + +Often it is useful to look at the state of the stacks in the listener. + +\wordtable{ +\vocabulary{prettyprint} +\ordinaryword{.s}{.s ( -- )} +\ordinaryword{.r}{.r ( -- )} +} +To see the contents of the data or return stack, use the \texttt{.s} and \texttt{.r} words. +Each stack is printed with each element on its own line; the top of the stack is the first element printed. + +\wordtable{ +\vocabulary{words} +\ordinaryword{watch}{watch ( word -- )} +} +To print the stack automatically when a word is entered and exited, use \verb|watch|. It modifies the word definition to act accordingly: +\begin{alltt} + : squared dup * ; + \bs squared watch + 5 squared +\textbf{===> Entering: squared +5 +===> Leaving: squared +25} +\end{alltt} +This modifies the word definition (as you can verify using \verb|see|); to restore the original definition, reload the word from its source file. + +\wordtable{ +\vocabulary{words} +\ordinaryword{reload}{reload ( word -- )} +} +Reload the source file the word was originally loaded from. If the word was automatically-generated, or defined in the listener, an exception is thrown. + +\section{Looking at word definitions} + +\wordtable{ +\vocabulary{words} +\ordinaryword{vocabs}{vocabs ( -- list )} +} +Entering \texttt{vocabs .}~in the listener produces a list of all existing vocabularies: + +\begin{alltt} + vocabs . +\textbf{[ "alien" "ansi" "assembler" "browser-responder" +"command-line" "compiler" "cont-responder" "errors" +"file-responder" "files" "gadgets" "generic" +"hashtables" "html" "httpd" "httpd-responder" "image" +"inference" "interpreter" "io-internals" "jedit" +"kernel" "kernel-internals" "line-editor" "listener" +"lists" "logging" "math" "math-internals" "memory" +"namespaces" "parser" "prettyprint" "profiler" +"quit-responder" "random" "resource-responder" +"scratchpad" "sdl" "shells" "stdio" "streams" +"strings" "syntax" "telnetd" "test" "test-responder" +"threads" "unparser" "url-encoding" "vectors" "words" ]} +\end{alltt} + +\wordtable{ +\vocabulary{words} +\ordinaryword{words}{words ( vocabulary -- list )} +} +You can use \texttt{words .}~to list the words inside a given vocabulary: + +\begin{alltt} + "namespaces" words . +\textbf{[ (get) , >n append, bind change cons@ +dec extend get global inc init-namespaces list-buffer +literal, make-list make-rlist make-rstring make-string +make-vector n> namespace namestack nest off on put set +set-global set-namestack unique, unique@ with-scope ]} +\end{alltt} + +\wordtable{ +\vocabulary{generic} +\ordinaryword{classes}{classes ( -- list )} +} +You can use \texttt{classes .}~to output a list of classes in the system: + +\begin{alltt} + classes . +\textbf{[ alien alien-error byte-array displaced-alien +dll ansi-stream disp-only displaced indirect operand +register absolute absolute-16/16 relative relative-bitfld +item kernel-error no-method border checkbox dialog editor +ellipse etched-rect frame gadget hand hollow-ellipse +hollow-rect label line menu pane pile plain-ellipse +plain-rect rectangle roll-rect scroller shelf slider +stack tile viewport world 2generic arrayed builtin +complement generic null object predicate tuple +tuple-class union hashtable html-stream class-tie +computed inference-error inference-warning literal +literal-tie value buffer port jedit-stream boolean +general-t array cons general-list list bignum complex +fixnum float integer number ratio rational real +parse-error potential-float potential-ratio +button-down-event button-up-event joy-axis-event +joy-ball-event joy-button-down-event joy-button-up-event +joy-hat-event key-down-event key-up-event motion-event +quit-event resize-event user-event sequence stdio-stream +client-stream fd-stream null-stream server string-output +wrapper-stream LETTER blank digit letter printable sbuf +string text POSTPONE: f POSTPONE: t vector compound +primitive symbol undefined word ]} +\end{alltt} + +\wordtable{ +\vocabulary{prettyprint} +\ordinaryword{see}{see ( word -- )} +} +You can look at the definition of any word, including library words, using \texttt{see}. Keep in mind you might have to \texttt{USE:} the vocabulary first. + +\begin{alltt} + USE: httpd + \bs httpd-connection see +\textbf{IN: httpd +: httpd-connection ( socket -- ) + "http-server" get accept [ + httpd-client + ] in-thread drop ;} +\end{alltt} + +If you \texttt{see} a generic word, all methods defined on the generic word are shown. If you see a class word, all methods specializing on the class are shown: +\begin{alltt} + \bs list see +\textbf{PREDICATE: general-list list + dup [ + last* cdr + ] when not ; +IN: gadgets +M: list custom-sheet + [ + length count + ] keep zip alist>sheet "Elements:" ; +IN: prettyprint +M: list prettyprint* + [ + [ + POSTPONE: [ + ] car swap [ + POSTPONE: ] + ] car prettyprint-sequence + ] check-recursion ;} +\end{alltt} + +The \texttt{see} word shows a reconstruction of the source code, not the original source code. So in particular, formatting and some comments are lost. + +\wordtable{ +\vocabulary{prettyprint} +\ordinaryword{apropos}{apropos ( string -- )} +} +The \texttt{apropos} word is handy when searching for related words. It lists all words +whose names contain a given string. The \texttt{apropos} word is also useful when you know the exact name of a word, but are unsure what vocabulary it is in. For example, if you're looking for ways to iterate over various collections, you can do an apropos search for \texttt{each}: + +\begin{alltt} + "each" apropos +\textbf{IN: gadgets each-gesture +IN: gadgets each-parent +IN: hashtables hash-each +IN: hashtables hash-each-with +IN: inference each-node +IN: inference each-node-with +IN: kernel-internals each-bucket +IN: math each-bit +IN: memory (each-object) +IN: memory each-object +IN: memory each-slot +IN: sequences 2each +IN: sequences each +IN: sequences each-with +IN: sequences tree-each +IN: sequences tree-each-with +IN: words each-word} +\end{alltt} + +\wordtable{ +\vocabulary{words} +\ordinaryword{usage}{usage ( word -- seq )} +} +The \texttt{usage} word finds all words that refer to a given word. +This word is helpful in two situations; the first is for learning -- a good way to learn a word is to see it used in context. The second is during refactoring -- if you change a word's stack effect, you must also update all words that call it. Usually you print the +return value of \texttt{usage} using \texttt{.}: +\begin{alltt} + \bs each-parent usage . +\textbf{[ handle-gesture user-input ]} +\end{alltt} + +\section{The inspector} + +The inspector allows objects to be browsed and inspected in a convenient fashion. +\wordtable{ +\vocabulary{inspector} +\ordinaryword{inspect}{inspect ( object -- )} +} +Starts the inspector if it is not already running, and prints a short blurb followed by all slot values of the object. +\begin{alltt} + \tto "a" "b" "c" \ttc inspect +\textbf{Object inspector. +inspecting ( -- obj ) push current object +go ( n -- ) inspect nth slot +up -- return to previous object +refs -- inspect references to current object +bye -- exit inspector + +You are looking at an instance of the vector class: + \tto "a" "b" "c" \ttc +It takes up 16 bytes of memory. +0 | "a" +1 | "b" +2 | "c" +inspector} +\end{alltt} + +The inspector changes the listener prompt to \verb|inspector| to remind you that several additional features are now operational. +\wordtable{ +\vocabulary{inspector} +\ordinaryword{inspecting}{inspecting ( -- object )} +} +Pushes the currently inspected object on the data stack. +\wordtable{ +\vocabulary{inspector} +\ordinaryword{go}{go ( n -- )} +} +Inspects the $n$th slot value of the currently inspected object. +\wordtable{ +\vocabulary{inspector} +\ordinaryword{up}{up ( -- )} +} +Returns to the previous object. +\wordtable{ +\vocabulary{inspector} +\ordinaryword{refs}{refs ( -- )} +} +Inspects a list of objects that refer to the current object. This uses the heap reflection facility (see \ref{heap-reflection}). + +To exit the inspector, issue the \verb|bye| word. + +\section{The walker} + +The walker lets you step through the execution of a qotation. When a compound definition is reached, you can either keep walking inside the definition, or execute it in one step. The stacks can be inspected at each stage. + +There are two ways to use the walker. First of all, you can call the \texttt{walk} word explicitly, giving it a quotation: + +\begin{alltt} + [ [ 10 [ dup , ] repeat ] [ ] make ] walk +\textbf{\&s \&r show stepper stacks. +\&get ( var -- value ) inspects the stepper namestack. +step -- single step over +into -- single step into +continue -- continue execution +bye -- exit single-stepper +[ [ 10 [ dup , ] repeat ] make-list ] +walk} +\end{alltt} + +As you can see, the walker prints a brief help message, then the currently executing quotation. It changes the listener prompt to \texttt{walk}, to remind you that there is a suspended continuation. + +The first element of the quotation shown is the next object to be evaluated. If it is a literal, both \texttt{step} and \texttt{into} have the effect of pushing it on the walker data stack. If it is a compound definition, then \texttt{into} will recurse the walker into the compound definition; otherwise, the word executes in one step. + +The \texttt{\&r} word shows the walker return stack, which is laid out just like the primary interpreter's return stack. In fact, a good way to understand how Factor's return stack works is to play with the walker. + +Note that the walker does not automatically stop when the quotation originally given finishes executing; it just keeps on walking up the return stack, and even lets you step through the listener's code. You can invoke \texttt{continue} or \texttt{bye} to terminate the walker. + +While the walker can be invoked explicitly using the \texttt{walk} word, sometimes it is more convenient to \emph{annotate} a word such that the walker is invoked automatically when the word is called. This can be done using the \texttt{break} word: + +\begin{alltt} + \bs layout* break +\end{alltt} + +Now, when some piece of code calls \texttt{layout*}, the walker will open, and you will be able to step through execution and see exactly what's going on. An important point to keep in mind is that when the walker is invoked in this manner, \texttt{bye} will not have the desired effect; execution will continue, but the data stack will be inconsistent, and an error will most likely be raised a short time later. Always use \texttt{continue} to resume execution after a break. + +You can undo the effect of \texttt{break} by reloading the original source file containing the word definition in question. + +\section{Unit testing} + +Unit tests are very easy to write, and are a great debugging aid in any dynamic language. +It is highly recommended that you write tests before or during development of any piece of Factor code. This section will not describe unit testing methodology; it only introduces Factor's unit test framework. +\wordtable{ +\vocabulary{test} +\ordinaryword{unit-test}{unit-test ( expect quot -- )} +} +Asserts that executing the quotation with an empty stack produces the expected stack. If the assertion fails, an exception is thrown. Here is an example unit test: + +\begin{verbatim} +[ "Hello, crazy world" ] +[ "Hello, " "crazy " "world" append3 ] unit-test +\end{verbatim} + +\wordtable{ +\vocabulary{test} +\ordinaryword{unit-test-fails}{unit-test-fails ( quot -- )} +} +Asserts that executing the quotation throws an exception. If the quotation returns normally, an exception is thrown. For example, the following test should pass, since calling \verb|nth| with a negative index should fail: + +\begin{verbatim} +[ -3 { } nth ] unit-test-fails +\end{verbatim} + +\section{Timing code} + +Factor provides two facilities for timing code; a way to time the execution of a particular quotation, and a rudimentary profiler. +\wordtable{ +\vocabulary{test} +\ordinaryword{time}{time ( quot -- )} +} +Calls the quotation, and reports the time taken. For example: + +\begin{alltt} + [ 1000000 [ f f cons drop ] repeat ] time +\textbf{515 ms run / 11 ms GC time} +\end{alltt} + +\wordtable{ +\vocabulary{words} +\ordinaryword{profile}{profile ( word -- )} +} +Marks the word for profiling. This modifies the word definition so that when the word executes, the execution time of the word is added to a global variable with the word's name. For example: +\begin{alltt} + : foo 100 sleep ; + \bs foo profile + 10 [ drop foo ] each + \bs foo get . +\textbf{1000} +\end{alltt} + +\section{Exploring memory usage}\label{heap-reflection} + +Factor supports heap introspection. You can find all objects in the heap that match a certain predicate using the \texttt{instances} word. For example, if you suspect a resource leak, you can find all I/O ports as follows: + +\begin{alltt} + USE: io-internals + [ port? ] instances . +\textbf{[ \# \# ]} +\end{alltt} + +The \texttt{references} word finds all objects that refer to a given object: + +\begin{alltt} + [ float? ] instances car references . +\textbf{[ \# [ -1.0 0.0 / ] ]} +\end{alltt} + +You can print a memory usage summary with \texttt{room.}: + +\begin{alltt} + room. +\textbf{Data space: 16384 KB total 2530 KB used 13853 KB free +Code space: 16384 KB total 490 KB used 15893 KB free} +\end{alltt} + +And finally, a detailed memory allocation breakdown by type with \texttt{heap-stats.}: + +\begin{alltt} + heap-stats. +\textbf{bignum: 312 bytes, 17 instances +cons: 850376 bytes, 106297 instances +float: 112 bytes, 7 instances +t: 8 bytes, 1 instances +array: 202064 bytes, 3756 instances +hashtable: 54912 bytes, 3432 instances +vector: 5184 bytes, 324 instances +string: 391024 bytes, 7056 instances +sbuf: 64 bytes, 4 instances +port: 112 bytes, 2 instances +word: 96960 bytes, 3030 instances +tuple: 688 bytes, 22 instances} +\end{alltt} + +\chapter{Images}\label{images} + +\glossary{name=image, +description={the complete persistent state of a Factor system, dumped to a file}} + +An image is basically a dump of all objects in the heap. When Factor is started, an image name must be specified on the command line: +\begin{alltt} +\textbf{\$} ./f factor.image +\textbf{Loading factor.image... relocating... done +Factor 0.77 :: http://factor.sourceforge.net :: linux/x86 +(C) 2003, 2005 Slava Pestov, Chris Double, +Mackenzie Straight} +\end{alltt} +The most-recently loaded image is stored in the \verb|"image"| global variable. +The current image can be saved back to disk using one of two words. + +\wordtable{ +\vocabulary{memory} +\ordinaryword{save}{save ( -- )} +} +Save the current image to disk. Defined as: +\begin{verbatim} +: save "image" get save-image ; +\end{verbatim} +\wordtable{ +\vocabulary{memory} +\ordinaryword{save-image}{save-image ( name -- )} +} +Save the current image to a file with the specified name. +\begin{alltt} + "work.image" save-image +\textbf{Saving work.image...} +\end{alltt} + +When you save an image before exiting Factor, then start Factor again, everything will be almost as you left it. Try the following: + +\begin{alltt} +\textbf{\$} ./f factor.image + "Learn Factor" "reminder" set + "factor.image" save-image +\textbf{Saving factor.image...} + bye +\textbf{\$} ./f factor.image + "reminder" get . +\textbf{"Learn Factor"} +\end{alltt} + +This is what is meant by the image being an \emph{infinite session}. When you shut down and restart Factor, what happends is much closer to a Laptop's ``suspend'' mode, than a desktop computer being fully shut down. + +\section{The bootstrap process} + +The Factor library source code cannot produce a new image from scratch, because +of inherent circularity; critical components such as the parser and the generic +word system are written in Factor itself. +The Factor runtime, coded in C, knows nothing of the syntax of Factor +source files, or even the organization of words into vocabularies. + +However, if \verb|save-image| was the only way one could save a new image, things +could get out of hand; since \verb|save-image| performs a memory dump, there would be +no way to change object formats, or perform major re-organizations of the system, and +so on. + +The bootstrap process builds a new image, from source, from inside another Factor +image, in a reasonably clean and controlled manner. Bootstrap proceeds in two stages: + +\begin{itemize} +\item In the first stage, the currently-running Factor image (the \emph{host image}) runs the image generator to produce a bootstrap image (the \emph{target image}). +\item In the second stage, the target image is run, and any final loading and initialization is performed. +\end{itemize} + +The first stage is performed by the following word. + +\wordtable{ +\vocabulary{image} +\ordinaryword{make-image}{make-image ( name -- )} +} +Generates a new bootstrap image, and writes it to the file named \verb|name|. + +The output format is determined by a pair of variables: + +\wordtable{ +\vocabulary{image} +\symbolword{big-endian} +\symbolword{64-bits} +} +The combination of the four flags allows you to switch between the four image formats supported by Factor: +\begin{itemize} +\item Little endian, 32 bit (x86) +\item Little endian, 64 bit (x86-64, Alpha) +\item Big endian, 32 bit (PowerPC, ARM, Sparc) +\item Big endian, 64 bit (PowerPC-64, UltraSparc) +\end{itemize} + +Now we will look at the bootstrap process in more detail. + +First note that the \verb|vocabularies| variable can be shadowed in a new dynamic scope, forcing words like \verb|search| and \verb|create| to operate on the new set of vocabularies (see \ref{vocabularies}). Bootstrapping uses this to build the vocabularies for the target image. + +After initializing some internal objects, \verb|make-image| runs the file +\verb|boot-stage1.factor|. This file then runs \verb|primitives.factor|, which sets up the initial target image vocabularies, consisting of a copy of the \verb|syntax| vocabulary from the host image, along with all primitive words defined in the runtime. The \verb|syntax| vocabulary is copied so that further source files can be parsed in. + +Note that apart from words in the copied \verb|syntax| vocabulary, no words in the target image may be executed in the host image; doing so can lead to all kinds of problems, since the target image may be linked with a different set of primitives and an incompatible runtime structure than the host image. + +Bootstrapping proceeds to load various source files into the +target vocabulary hash. Each file loaded must only refer to primitive +words, and words loaded from previous files. So by reading through each +file referenced by \verb|boot-stage1.factor|, you can see the entire construction of the Factor system from the bottom up. + +After the library has been loaded into the target image, there is still a problem; the \verb|syntax| vocabulary in the target image was copied from the host +image, and not loaded from source. Loading the \verb|syntax| vocabulary for the target image is the very last task performed during bootstrap, since after this point, no more code may be loaded in (since it would invoke parsing words intended for the target image in the host image). + +Take a look at the start of any source file in \verb|library/syntax/|: + +\begin{verbatim} +IN: !syntax +USE: syntax +\end{verbatim} + +The source files defining parsing words are themselves parsed using the \verb|syntax| vocabulary, \emph{but add new definitions} to the \verb|!syntax| vocabulary. This allows bootstrap to replace the \verb|syntax| vocabulary with \verb|!syntax| as the very last step. + +Once all source files have been loaded into the target image, the target image is written to disk. This is done by tracing all objects and outputting them manually, without a dependency on their actual memory layout in the host image; this allows object formats to be changed easily. + \chapter{Alien interface} Factor's alien inteface provides a means of directly calling native libraries written in C and other languages. There are no wrappers to write, other than having to specify the return type and parameter types for the functions you wish to call. -\section{Loading native libraries} +\section{Loading native libraries}\label{native-libs} A native library must be made available to Factor under a logical name before use. This is done via command line parameters, or the \verb|add-library| word. @@ -5650,484 +6443,6 @@ Resize a block previously allocated with \verb|malloc|. } Deallocate a block previously allocated with \verb|malloc|. -\part{Development tools} - -Factor supports interactive development in a live environment. Instead of working with -static executable files and restarting your application after each change, you can -incrementally make changes to your application and test them immediately. If you -notice an undesirable behavior, Factor's powerful reflection features will aid in -pinpointing the error. - -If you are used to a statically typed language, you might find Factor's tendency to only fail at runtime hard to work with at first. However, the interactive development tools outlined in this part allow a much quicker turn-around time for testing changes. Also, write unit tests -- unit testing is a great way to ensure that old bugs do not re-appear once they've been fixed. - -\chapter{System organization} - -\section{The listener}\label{listener} - -Factor is an \emph{image-based environment}. When you compiled Factor, you also generated a file named \texttt{factor.image}. I will have more to say about images later, but for now it suffices to understand that to start Factor, you must pass the image file name on the command line: -\begin{alltt} -./f factor.image -\textbf{Loading factor.image... relocating... done -Factor 0.73 :: http://factor.sourceforge.net :: unix/x86 -(C) 2003, 2005 Slava Pestov, Chris Double, -Mackenzie Straight -ok} -\end{alltt} -An \texttt{\textbf{ok}} prompt is printed after the initial banner, indicating the listener is ready to execute Factor phrases. The listener is a piece of Factor code, like any other; however, it helps to think of it as the primary interface to the Factor system. The listener reads Factor code and executes it. You can try the classical first program: - -\begin{alltt} - "Hello, world." print -\textbf{Hello, world.} -\end{alltt} - - -Multi-line phrases are supported; if there are unclosed brackets, the listener outputs \texttt{...} instead of the \texttt{ok} prompt, and the entire phrase is executed once all brackets are closed: - -\begin{alltt} - [ 1 2 3 ] [ -\textbf{...} . -\textbf{...} ] each -\textbf{1 -2 -3} -\end{alltt} - -The listener knows when to print a continuation prompt by looking at the height of the -stack. Parsing words such as \texttt{[} and \texttt{:} leave elements on the parser -stack; these elements are popped by \texttt{]} and \texttt{;}. - -On startup, Factor reads the \texttt{.factor-rc} file from your home directory. You can put -any quick definitions you want available at the listener there. To avoid loading this -file, pass the \texttt{-no-user-init} command line switch. Another way to have a set of definitions available at all times is to save a custom image, as described in the next section. - -\section{Source files} - -While it is possible to do all development in the listener and save your work in images, it is far more convenient to work with source files, at least until an in-image structure editor is developed. - -By convention, Factor source files are saved with the \texttt{.factor} filename extension. They can be loaded into the image as follows: - -\begin{alltt} - "examples/numbers-game.factor" run-file -\end{alltt} - -In Factor, loading a source file replaces any existing definitions\footnote{But see \ref{compiler} for this is not true of compiled code.}. Each word definition remembers what source file it was loaded from (if any). To reload the source file associated with a definition, use the \texttt{reload} word: - -\begin{alltt} - \bs draw reload -\end{alltt} - -Word definitions also retain the line number where they are located in their original source file. This allows you to open a word definition in jEdit\footnote{\texttt{http://www.jedit.org}} for editing using the -\texttt{jedit} word: - -\begin{alltt} - \bs compile jedit -\end{alltt} - -This word requires that a jEdit instance is already running. - -The \texttt{jedit} word will open word definitions from the Factor library once the full path of the Factor source tree is entered into the \texttt{"resource-path"} variable. One way to do this is to add a phrase like the following to your \texttt{.factor-rc}: - -\begin{verbatim} -"/home/slava/Factor/" "resource-path" set -\end{verbatim} - -\section{Images} - -The \texttt{factor.image} file is basically a dump of all objects in the heap. A new image can be saved as follows: - -\begin{alltt} - "work.image" save-image -\textbf{Saving work.image...} -\end{alltt} - -When you save an image before exiting Factor, then start Factor again, everything will be almost as you left it. Try the following: - -\begin{alltt} -./f factor.image - "Learn Factor" "reminder" set - "factor.image" save-image bye -\textbf{Saving factor.image...} -\end{alltt} - -Factor will save the image and exit. Now start it again and see that the reminder is still there: - -\begin{alltt} -./f factor.image - "reminder" get . -\textbf{"Learn Factor"} -\end{alltt} - -This is what is meant by the image being an \emph{infinite session}. When you shut down and restart Factor, what happends is much closer to a Laptop's ``suspend'' mode, than a desktop computer being fully shut down. - -\section{Looking at objects} - -Probably the most important debugging tool of them all is the \texttt{.} word. It prints the object at the top of the stack in a form that can be parsed by the Factor parser. A related word is \texttt{prettyprint}. It is identical to \texttt{.} except the output is more verbose; lists, vectors and hashtables are broken up into multiple lines and indented. - -\begin{alltt} - [ [ \tto 1 \ttc \tto 2 \ttc ] dup car swap cdr ] . -[ [ \tto 1 \ttc \tto 2 \ttc ] dup car swap cdr ] -\end{alltt} - -Most objects print in a parsable form, but not all. One exceptions to this rule is objects with external state, such as I/O ports or aliens (pointers to native structures). Also, objects with circular or very deeply nested structure will not print in a fully parsable form, since the prettyprinter has a limit on maximum nesting. Here is an example -- a vector is created, that holds a list whose first element is the vector itself: - -\begin{alltt} - \tto \ttc [ unit 0 ] keep [ set-vector-nth ] keep . -\tto [ ... ] \ttc -\end{alltt} - -The prettyprinted form of a vector or list with many elements is not always readable. The \texttt{[.]} and \texttt{\tto.\ttc} words output a list or a vector, respectively, with each element on its own line. In fact, the stack printing words are defined in terms of \texttt{[.]} and \texttt{\tto.\ttc}: - -\begin{verbatim} -: .s datastack {.} ; -: .r callstack {.} ; -: .n namestack [.] ; -: .c catchstack [.] ; -\end{verbatim} - -Before we move on, one final set of output words comes is used to output integers in -different numeric bases. The \texttt{.b} word prints an integer in binary, \texttt{.o} in octal, and \texttt{.h} in hexadecimal. - -\begin{alltt} - 31337 .b -\textbf{111101001101001} - 31337 .o -\textbf{75151} - 31337 .h -\textbf{7a69} -\end{alltt} - -\chapter{Word tools} - -\section{Exploring vocabularies}\label{exploring-vocabs} - -Factor organizes code in a two-tier structure of vocabularies and words. A word is the smallest unit of code; it corresponds to a function or method in other languages. Vocabularies group related words together for easy browsing and tracking of source dependencies. - -Entering \texttt{vocabs .}~in the listener produces a list of all existing vocabularies: - -\begin{alltt} - vocabs . -\textbf{[ "alien" "ansi" "assembler" "browser-responder" -"command-line" "compiler" "cont-responder" "errors" -"file-responder" "files" "gadgets" "generic" -"hashtables" "html" "httpd" "httpd-responder" "image" -"inference" "interpreter" "io-internals" "jedit" -"kernel" "kernel-internals" "line-editor" "listener" -"lists" "logging" "math" "math-internals" "memory" -"namespaces" "parser" "prettyprint" "profiler" -"quit-responder" "random" "resource-responder" -"scratchpad" "sdl" "shells" "stdio" "streams" -"strings" "syntax" "telnetd" "test" "test-responder" -"threads" "unparser" "url-encoding" "vectors" "words" ]} -\end{alltt} - -As you can see, there are a lot of vocabularies! Now, you can use \texttt{words .}~to list the words inside a given vocabulary: - -\begin{alltt} - "namespaces" words . -\textbf{[ (get) , >n append, bind change cons@ -dec extend get global inc init-namespaces list-buffer -literal, make-list make-rlist make-rstring make-string -make-vector n> namespace namestack nest off on put set -set-global set-namestack unique, unique@ with-scope ]} -\end{alltt} - -You can look at the definition of any word, including library words, using \texttt{see}. Keep in mind you might have to \texttt{USE:} the vocabulary first. - -\begin{alltt} - USE: httpd - \bs httpd-connection see -\textbf{IN: httpd : httpd-connection ( socket -- ) - "http-server" get accept [ - httpd-client - ] in-thread drop ;} -\end{alltt} - -The \texttt{see} word shows a reconstruction of the source code, not the original source code. So in particular, formatting and some comments are lost. - -\section{Cross-referencing words} - -The \texttt{apropos.} word is handy when searching for related words. It lists all words -whose names contain a given string. The \texttt{apropos.} word is also useful when you know the exact name of a word, but are unsure what vocabulary it is in. For example, if you're looking for ways to iterate over various collections, you can do an apropos search for \texttt{map}: - -\begin{alltt} - "map" apropos. -\textbf{IN: inference -type-value-map -IN: lists -map -map-with -IN: sdl -set-surface-map -surface-map -IN: strings -string-map -IN: vectors -vector-map} -\end{alltt} - -From the above output, you can see that \texttt{map} is for lists, \texttt{string-map} is for strings, and \texttt{vector-map} is for vectors. - -The \texttt{usage} word finds all words that refer to a given word and pushes a list on the stack. This word is helpful in two situations; the first is for learning -- a good way to learn a word is to see it used in context. The second is during refactoring -- if you change a word's stack effect, you must also update all words that call it. Usually you print the -return value of \texttt{usage} using \texttt{.}: - -\begin{alltt} - \bs string-map usage . -\textbf{schars>entities -filter-null -url-encode} -\end{alltt} - -Another useful word is \texttt{usages}. Unlike \texttt{usage}, it finds all usages, even -indirect ones -- so if a word refers to another word that refers to the given word, -both words will be in the output list. - -\section{Exploring classes} - -Factor supports object-oriented programming via generic words. Generic words are called -like ordinary words, however they can have multiple definitions, one per class, and -these definitions do not have to appear in the same source file. Such a definition is -termed a \emph{method}, and the method is said to \emph{specialize} on a certain -class. A class in the most -general sense is just a set of objects. You can output a list of classes in the system -with \texttt{classes .}: - -\begin{alltt} - classes. -\textbf{[ alien alien-error byte-array displaced-alien -dll ansi-stream disp-only displaced indirect operand -register absolute absolute-16/16 relative relative-bitfld -item kernel-error no-method border checkbox dialog editor -ellipse etched-rect frame gadget hand hollow-ellipse -hollow-rect label line menu pane pile plain-ellipse -plain-rect rectangle roll-rect scroller shelf slider -stack tile viewport world 2generic arrayed builtin -complement generic null object predicate tuple -tuple-class union hashtable html-stream class-tie -computed inference-error inference-warning literal -literal-tie value buffer port jedit-stream boolean -general-t array cons general-list list bignum complex -fixnum float integer number ratio rational real -parse-error potential-float potential-ratio -button-down-event button-up-event joy-axis-event -joy-ball-event joy-button-down-event joy-button-up-event -joy-hat-event key-down-event key-up-event motion-event -quit-event resize-event user-event sequence stdio-stream -client-stream fd-stream null-stream server string-output -wrapper-stream LETTER blank digit letter printable sbuf -string text POSTPONE: f POSTPONE: t vector compound -primitive symbol undefined word ]} -\end{alltt} - -If you \texttt{see} a generic word, all methods defined on the generic word are shown. -Alternatively, you can use \texttt{methods.} to print all methods specializing on a -given class: - -\begin{alltt} - \bs list methods. -\textbf{PREDICATE: general-list list - dup [ - last* cdr - ] when not ; -IN: gadgets -M: list custom-sheet - [ - length count - ] keep zip alist>sheet "Elements:" ; -IN: prettyprint -M: list prettyprint* - [ - [ - POSTPONE: [ - ] car swap [ - POSTPONE: ] - ] car prettyprint-sequence - ] check-recursion ;} -\end{alltt} - -\chapter{Debugging and optimizing} - -\section{Looking at stacks} - -To see the contents of the data stack, use the \texttt{.s} word. Similarly, the other stacks can be shown with \texttt{.r} (return stack), \texttt{.n} (name stack), and \texttt{.c} (catch stack). Each stack is printed with each element on its own line; the top of the stack is the first element printed. - -\section{The debugger} - -If the execution of a phrase in the listener causes an error to be thrown, the error -is printed and the stacks at the time of the error are saved. If you're spent any -time with Factor at all, you are probably familiar with this type of message: - -\begin{alltt} - [ 1 2 3 ] 4 append reverse -\textbf{The generic word car does not have a suitable method for 4 -:s :r :n :c show stacks at time of error. -:get ( var -- value ) inspects the error namestack.} -\end{alltt} - -The words \texttt{:s}, \texttt{:r}, \texttt{:n} and \texttt{:s} behave like their counterparts that are prefixed with \texttt{.}, except they show the stacks as they were when the error was thrown. - -The return stack warrants some special attention. To successfully develop Factor, you will need to learn to understand how it works. Lets look at the first few lines of the return stack at the time of the above error: - -\begin{verbatim} -[ swap cdr ] -uncons -[ r> tuck 2slip ] -(each) -[ swons ] -[ each ] -each -\end{verbatim} - -You can see the sequence of calls leading up to the error was \texttt{each} calling \texttt{(each)} calling \texttt{uncons}. The error tells us that the \texttt{car} word is the one that failed. Now, you can stare at the stack dump, at notice that if the call to \texttt{car} was successful and execution returned to \texttt{(each)}, the quotation \texttt{[ r> tuck 2slip ]} would resume executing. The first word there, \texttt{r>}, would take the quotation \texttt{[ swons ]} and put it back on the data stack. After \texttt{(each)} returned, it would then continue executing the quotation \texttt{[ each ]}. So what is going on here is a recursive loop, \texttt{[ swons ] each}. If you look at the definition of \texttt{reverse}, you will see that this is exactly what is being done: - -\begin{verbatim} -: reverse ( list -- list ) [ ] swap [ swons ] each ; -\end{verbatim} - -So a list is being reversed, but at some stage, the \texttt{car} is taken of something that is not a number. Now, you can look at the data stack with \texttt{:s}: - -\begin{verbatim} -<< no-method [ ] 4 car >> -car -4 -4 -[ 3 2 1 ] -\end{verbatim} - -So now, the mystery has been solved: as \texttt{reverse} iterates down the input value, it hits a cons cells whose \texttt{cdr} is not a list. Indeed, if you look at the value we are passing to \texttt{reverse}, you will see why: - -\begin{alltt} - [ 1 2 3 ] 4 append . -[[ 1 [[ 2 [[ 3 4 ]] ]] ]] -\end{alltt} - -In the future, the debugger will be linked with the walker, documented below. Right now, the walker is a separate tool. Another caveat is that in compiled code, the return stack is not reconstructed if there is an error. Until this is fixed, you should only compile code once it is debugged. For more potential compiler pitfalls, see \ref{compiler}. - -\section{The walker} - -The walker lets you step through the execution of a qotation. When a compound definition is reached, you can either keep walking inside the definition, or execute it in one step. The stacks can be inspected at each stage. - -There are two ways to use the walker. First of all, you can call the \texttt{walk} word explicitly, giving it a quotation: - -\begin{alltt} - [ [ 10 [ dup , ] repeat ] make-list ] walk -\textbf{\&s \&r \&n \&c show stepper stacks. -\&get ( var -- value ) inspects the stepper namestack. -step -- single step over -into -- single step into -continue -- continue execution -bye -- exit single-stepper -[ [ 10 [ dup , ] repeat ] make-list ] -walk} -\end{alltt} - -As you can see, the walker prints a brief help message, then the currently executing quotation. It changes the listener prompt from \texttt{ok} to \texttt{walk}, to remind you that there is a suspended continuation. - -The first element of the quotation shown is the next object to be evaluated. If it is a literal, both \texttt{step} and \texttt{into} have the effect of pushing it on the walker data stack. If it is a compound definition, then \texttt{into} will recurse the walker into the compound definition; otherwise, the word executes in one step. - -The \texttt{\&r} word shows the walker return stack, which is laid out just like the primary interpreter's return stack. In fact, a good way to understand how Factor's return stack works is to play with the walker. - -Note that the walker does not automatically stop when the quotation originally given finishes executing; it just keeps on walking up the return stack, and even lets you step through the listener's code. You can invoke \texttt{continue} or \texttt{exit} to terminate the walker. - -While the walker can be invoked explicitly using the \texttt{walk} word, sometimes it is more convenient to \emph{annotate} a word such that the walker is invoked automatically when the word is called. This can be done using the \texttt{break} word: - -\begin{alltt} - \bs layout* break -\end{alltt} - -Now, when some piece of code calls \texttt{layout*}, the walker will open, and you will be able to step through execution and see exactly what's going on. An important point to keep in mind is that when the walker is invoked in this manner, \texttt{exit} will not have the desired effect; execution will continue, but the data stack will be inconsistent, and an error will most likely be raised a short time later. Always use \texttt{continue} to resume execution after a break. - -The walker is very handy, but sometimes you just want to see if a word is being called at all and when, and you don't care to single-step it. In that case, you can use the \texttt{watch} word: - -\begin{alltt} - \bs draw-shape break -\end{alltt} - -Now when \texttt{draw-shape} is called, a message will be printed to that effect. - -You can undo the effect of \texttt{break} or \texttt{watch} by reloading the original source file containing the word definition in question: - -\begin{alltt} - \bs layout* reload - \bs draw-shape reload -\end{alltt} - -\section{Dealing with hangs} - -If you accidentally start an infinite loop, you can send the Factor runtime a \texttt{QUIT} signal. On Unix, this is done by pressing \texttt{Control-\bs} in the controlling terminal. This will cause the runtime to dump the data and return stacks in a semi-readable form. Note that this will help you find the root cause of the hang, but it will not let you interrupt the infinite loop. - -\section{Unit testing} - -Unit tests are very easy to write. They are usually placed in source files. A unit test can be executed with the \texttt{unit-test} word in the \texttt{test} vocabulary. This word takes a list and a quotation; the quotation is executed, and the resulting data stack is compared against the list. If they do not equal, the unit test has failed. Here is an example of a unit test: - -\begin{verbatim} -[ "Hello, crazy world" ] [ - "editor" get [ 0 caret set ] bind - ", crazy" 5 "editor" get [ line-insert ] bind - "editor" get [ line-text get ] bind -] unit-test -\end{verbatim} - -To have a unit test assert that a piece of code does not execute successfully, but rather throws an exception, use the \texttt{unit-test-fails} word. It takes only one quotation; if the quotation does \emph{not} throw an exception, the unit test has failed. - -\begin{verbatim} -[ -3 { } vector-nth ] unit-test-fails -\end{verbatim} - -Unit testing is a good habit to get into. Sometimes, writing tests first, before any code, can speed the development process too; by running your unit test script, you can gauge progress. - -\section{Timing code} - -The \texttt{time} word reports the time taken to execute a quotation, in milliseconds. The portion of time spent in garbage collection is also shown: - -\begin{alltt} - [ 1000000 [ f f cons drop ] repeat ] time -\textbf{515 milliseconds run time -11 milliseconds GC time} -\end{alltt} - -\section{Exploring memory usage} - -Factor supports heap introspection. You can find all objects in the heap that match a certain predicate using the \texttt{instances} word. For example, if you suspect a resource leak, you can find all I/O ports as follows: - -\begin{alltt} - USE: io-internals - [ port? ] instances . -\textbf{[ \# \# ]} -\end{alltt} - -The \texttt{references} word finds all objects that refer to a given object: - -\begin{alltt} - [ float? ] instances car references . -\textbf{[ \# [ -1.0 0.0 / ] ]} -\end{alltt} - -You can print a memory usage summary with \texttt{room.}: - -\begin{alltt} - room. -\textbf{Data space: 16384 KB total 2530 KB used 13853 KB free -Code space: 16384 KB total 490 KB used 15893 KB free} -\end{alltt} - -And finally, a detailed memory allocation breakdown by type with \texttt{heap-stats.}: - -\begin{alltt} - heap-stats. -\textbf{bignum: 312 bytes, 17 instances -cons: 850376 bytes, 106297 instances -float: 112 bytes, 7 instances -t: 8 bytes, 1 instances -array: 202064 bytes, 3756 instances -hashtable: 54912 bytes, 3432 instances -vector: 5184 bytes, 324 instances -string: 391024 bytes, 7056 instances -sbuf: 64 bytes, 4 instances -port: 112 bytes, 2 instances -word: 96960 bytes, 3030 instances -tuple: 688 bytes, 22 instances} -\end{alltt} - \chapter{Stack effect inference} The stack effect inference tool checks correctness of code before it is run. @@ -6145,21 +6460,9 @@ The main entry point of the stack checker is a single word. Takes a quotation and attempts to infer its stack effect. An exception is thrown if the stack effect cannot be inferred. -You can combine unit testing with stack effect inference by writing unit tests that check stack effects of words. In fact, this can be automated with the \texttt{infer>test.} word; it takes a quotation on the stack, and prints a code snippet that tests the stack effect of the quotation: - -\begin{alltt} - [ draw-shape ] infer>test. -\textbf{[ [ [ object ] [ ] ] ] -[ [ draw-shape ] infer ] -unit-test} -\end{alltt} - -You can then copy and paste this snippet into a test script, and run the test script after -making changes to the word to ensure its stack effect signature has not changed. - \section{The algorithm} -The stack effect inference algorithm mirrors the interpreter algorithm. A ``meta data stack'' holds two types of entries; computed values, whose type is known but literal value will only be known at runtime, and literals, whose value is known statically. When a literal value is encountered, it is simply placed on the meta data stack. When a word is encountered, one of several actions are taken, depending on the type of the word: +The stack effect inference algorithm mirrors the evaluator algorithm (\ref{quotations}). A ``meta data stack'' holds two types of entries; computed values, whose type is known but literal value will only be known at runtime, and literals, whose value is known statically. When a literal value is encountered, it is simply placed on the meta data stack. When a word is encountered, one of several actions are taken, depending on the type of the word: \begin{itemize} \item If the word has special stack effect inference behavior, this behavior is invoked. Shuffle words and various primitives fall into this category. @@ -6271,6 +6574,150 @@ The compiler has two limitations you must be aware of. First, if an exception is The compiler consists of multiple stages -- first, a dataflow graph is inferred, then various optimizations are done on this graph, then it is transformed into a linear representation, further optimizations are done, and finally, machine code is generated from the linear representation. +\section{Dataflow intermediate representation} + +The dataflow IR represents nested control structure, and annotates all calls with stack input and output annotations. Such annotations consists of lists of values, where a value abstracts over a possibly unknown computation result. It has a tree shape, where each node is a tuple delegating to an instance of the \verb|node| tuple class. + +The \verb|node| tuple has the following slots: + +\begin{description} +\item[\texttt{param}] The meaning is determined by the tuple wrapping the node instance. For example with \verb|#call| nodes, this is the word being called. +\item[\texttt{in-d}] A list of input values popped the data stack. +\item[\texttt{in-r}] A list of input values popped the return stack. Only used by \verb|#call >r| nodes. +\item[\texttt{out-d}] A list of output values pushed on the data stack. +\item[\texttt{out-r}] A list of output values pushed on the return stack. Only used by \verb|#call r>| nodes. +\item[\texttt{node-classes}] A hashtable mapping values to classes. +\item[\texttt{node-literals}] A hashtable mapping values to literals. +\item[\texttt{node-successor}] The direct successor of the node. +\item[\texttt{node-children}] A list of the node's children, for example if this is a branch or label node. The number of children depends on the type of node. +\end{description} + +Note that nodes are linked by the \verb|node-successor| slot. Nested structure is realized by a list value in the \verb|node-children| slot. + +The stack effect inferencer transforms quotations into dataflow IR. + +The \verb|node-classes| and \verb|node-literals| slots are filled in by a separate class inference stage (\ref{class-inference}). + +\wordtable{ +\vocabulary{inference} +\ordinaryword{dataflow}{dataflow ( quot -- node )} +} + +Produces the dataflow IR of a quotation. + +\wordtable{ +\vocabulary{inference} +\ordinaryword{dataflow.}{dataflow.~( quot ? -- )} +} + +Prints dataflow IR in human-readable form. The boolean indicates if stack effect annotations should be output. + +\subsection{Values} + +Values are an abstraction over possibly known computation inputs and outputs. There are three types of values: + +\begin{description} +\item[Literal values] represent a known constant +\item[Computed values] represent inputs and outputs whose specific value is not known +\item[Joined values] represent a unification of possible values of a stack slot where branched control flow meets +\end{description} + +The \verb|value| tuple has one slot, \verb|value-recursion|. This is a list of nested lexical scopes, used to resolve recursive stack effects + +\subsection{Straight-line code} + +\begin{description} + +\item[\texttt{\#push}] Pushes literal values on the data stack. + +\begin{description} +\item[\texttt{node-out-d}] A list of literals. +\end{description} + +\item[\texttt{\#drop}] Pops literal values from the data stack. + +\begin{description} +\item[\texttt{node-in-d}] A list of literals. +\end{description} + +\item[\texttt{\#call}] Invokes the word identified by \verb|node-param|. + +\begin{description} +\item[\texttt{node-param}]A word.\\ +\item[\texttt{node-in-d}]Input values.\\ +\item[\texttt{node-out-d}]Output values. +\end{description} + +\item[\texttt{\#call-label}] Like \verb|#call| but \verb|node-param| refers to a parent \verb|#label| node. + +\end{description} + +\subsection{Branching and recursion} + +\begin{description} + +\item[\texttt{\#ifte}] A conditional expression. + +\begin{description} +\item[\texttt{node-in-d}]A singleton list holding the condition being tested.\\ +\item[\texttt{node-children}]A list of two nodes, the true and false branches. +\end{description} + +\item[\texttt{\#dispatch}] A jump table. + +\begin{description} +\item[\texttt{node-in-d}]A singleton list holding the jump table index.\\ +\item[\texttt{node-children}]A list of nodes, in consecutive jump table order. +\end{description} + +\item[\texttt{\#values}] Found at the end of each branch in an \verb|#ifte| or \verb|#dispatch| node. + +\begin{description} +\item[\texttt{node-out-d}]A list of values present on the data stack at the end of the branch.\\ +\end{description} + +\item[\texttt{\#meet}] Must be the successor if an \verb|#ifte| or \verb|#dispatch| node. + +\begin{description} +\item[\texttt{node-in-d}]A list of \verb|meet| values unified from the \verb|#values| node at the end of each branch.\\ +\end{description} + +\item[\texttt{\#label}] A named block of code. Child \verb|#call-label| nodes can recurse on this label. + +\begin{description} +\item[\texttt{node-param}]A gensym identifying the label.\\ +\item[\texttt{node-children}]A singleton list whose sole element is the labelled node. +\end{description} + +\item[\texttt{\#entry}] Must be the first node of a \verb|#label|. These nodes are created by the stack effect inferencer, however are only properly filled out by the recursive value inference stage (\ref{recursive-inference}). +\begin{description} +\item[\texttt{node-in-d}]A list of \verb|meet| values unified from all entry points into the block scoped by the \verb|#label| node.\\ +\end{description} + +\item[\texttt{\#return}] Found at the end of a word's dataflow IR. + +\begin{description} +\item[\texttt{node-out-d}]Values present on the stack when the word returns. +\end{description} + +\end{description} + +\section{Dataflow optimizer} + +The dataflow optimizer consists of a set of loosely-related words and passes over dataflow IR that apply various transformations with the intent of improving the efficiency of the generated code. + +\subsection{Killing unused literals} + +\subsection{Class inference}\label{class-inference} + +\subsection{Recursive value inference}\label{recursive-inference} + +\subsection{Method inlining and type check elimination} + +\subsection{Branch folding} + +\subsection{Partial evaluation} + \section{Linear intermediate representation} The linear IR is the second of the two intermediate @@ -6278,17 +6725,6 @@ representations used by Factor. It is basically a high-level assembly language. Linear IR operations are called VOPs. The last stage of the compiler generates machine code instructions corresponding to each \emph{virtual operation} in the linear IR. To perform everything except for the machine code generation, use the \texttt{precompile} word. This will dump the optimized linear IR instead of generating code, which can be useful sometimes. - -\begin{alltt} - \bs append precompile -\textbf{<< \%prologue << vop [ ] [ ] [ ] [ ] >> >> -<< \%peek-d << vop [ ] [ 1 ] [ << vreg ... 0 >> ] [ ] >> >> -<< \%peek-d << vop [ ] [ 0 ] [ << vreg ... 1 >> ] [ ] >> >> -<< \%replace-d << vop [ ] [ 0 << vreg ... 0 >> ] [ ] [ ] >> >> -<< \%replace-d << vop [ ] [ 1 << vreg ... 1 >> ] [ ] [ ] >> >> -<< \%inc-d << vop [ ] [ -1 ] [ ] [ ] >> >> -<< \%return << vop [ ] [ ] [ ] [ ] >> >>} -\end{alltt} \subsection{Control flow} diff --git a/doc/interpreter.dia b/doc/interpreter.dia index cc2b84a83d..fa93e3bc05 100644 Binary files a/doc/interpreter.dia and b/doc/interpreter.dia differ diff --git a/doc/interpreter.eps b/doc/interpreter.eps index 2fbe308608..dd146bd485 100644 --- a/doc/interpreter.eps +++ b/doc/interpreter.eps @@ -1,11 +1,11 @@ %!PS-Adobe-2.0 EPSF-2.0 %%Title: interpreter.dia %%Creator: Dia v0.94 -%%CreationDate: Wed Apr 27 23:34:54 2005 +%%CreationDate: Wed Aug 10 01:38:18 2005 %%For: slava %%Orientation: Portrait %%Magnification: 1.0000 -%%BoundingBox: 0 0 578 592 +%%BoundingBox: 0 0 652 742 %%BeginSetup %%EndSetup %%EndComments @@ -99,249 +99,26 @@ dup 4 2 roll putinterval } bind def -/Times-Roman-latin1 - /Times-Roman findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Times-Italic-latin1 - /Times-Italic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Times-Bold-latin1 - /Times-Bold findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Times-BoldItalic-latin1 - /Times-BoldItalic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/AvantGarde-Book-latin1 - /AvantGarde-Book findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/AvantGarde-BookOblique-latin1 - /AvantGarde-BookOblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/AvantGarde-Demi-latin1 - /AvantGarde-Demi findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/AvantGarde-DemiOblique-latin1 - /AvantGarde-DemiOblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Bookman-Light-latin1 - /Bookman-Light findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Bookman-LightItalic-latin1 - /Bookman-LightItalic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Bookman-Demi-latin1 - /Bookman-Demi findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Bookman-DemiItalic-latin1 - /Bookman-DemiItalic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Courier-latin1 - /Courier findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Courier-Oblique-latin1 - /Courier-Oblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Courier-Bold-latin1 - /Courier-Bold findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Courier-BoldOblique-latin1 - /Courier-BoldOblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-latin1 - /Helvetica findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-Oblique-latin1 - /Helvetica-Oblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-Bold-latin1 - /Helvetica-Bold findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-BoldOblique-latin1 - /Helvetica-BoldOblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-Narrow-latin1 - /Helvetica-Narrow findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-Narrow-Oblique-latin1 - /Helvetica-Narrow-Oblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-Narrow-Bold-latin1 - /Helvetica-Narrow-Bold findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Helvetica-Narrow-BoldOblique-latin1 - /Helvetica-Narrow-BoldOblique findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/NewCenturySchoolbook-Roman-latin1 - /NewCenturySchoolbook-Roman findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/NewCenturySchoolbook-Italic-latin1 - /NewCenturySchoolbook-Italic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/NewCenturySchoolbook-Bold-latin1 - /NewCenturySchoolbook-Bold findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/NewCenturySchoolbook-BoldItalic-latin1 - /NewCenturySchoolbook-BoldItalic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Palatino-Roman-latin1 - /Palatino-Roman findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Palatino-Italic-latin1 - /Palatino-Italic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Palatino-Bold-latin1 - /Palatino-Bold findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Palatino-BoldItalic-latin1 - /Palatino-BoldItalic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/Symbol-latin1 - /Symbol findfont -definefont pop -/ZapfChancery-MediumItalic-latin1 - /ZapfChancery-MediumItalic findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop -/ZapfDingbats-latin1 - /ZapfDingbats findfont - dup length dict begin - {1 index /FID ne {def} {pop pop} ifelse} forall - /Encoding isolatin1encoding def - currentdict end -definefont pop +/dpi_x 300 def +/dpi_y 300 def +/conicto { + /to_y exch def + /to_x exch def + /conic_cntrl_y exch def + /conic_cntrl_x exch def + currentpoint + /p0_y exch def + /p0_x exch def + /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def + /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def + /p2_x p1_x to_x p0_x sub 1 3 div mul add def + /p2_y p1_y to_y p0_y sub 1 3 div mul add def + p1_x p1_y p2_x p2_y to_x to_y curveto +} bind def +/start_ol { gsave 1.1 dpi_x div dup scale} bind def +/end_ol { closepath fill grestore } bind def 28.346000 -28.346000 scale -1.050000 -22.149700 translate +3.650000 -25.769040 translate %%EndProlog @@ -353,8 +130,538 @@ n 7.417767 1.333300 m 15.185534 3.275242 l 7.417767 5.217183 l -0.350000 3.27524 0 slj 0.000000 0.000000 0.000000 srgb n 7.417767 1.333300 m 15.185534 3.275242 l 7.417767 5.217183 l -0.350000 3.275242 l cp s -/Helvetica-latin1 ff 0.560000 scf sf -(Is the callframe equal to f?) dup sw 2 div 7.417767 ex sub 3.475242 m gs 1 -1 sc sh gr +gsave 3.358000 3.475242 translate 0.035278 -0.035278 scale +start_ol +448 3328 moveto +896 3328 lineto +896 0 lineto +448 0 lineto +448 3328 lineto +end_ol grestore +gsave 3.535800 3.475242 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 3.857534 3.475242 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 4.052267 3.475242 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 4.289334 3.475242 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 4.678800 3.475242 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 5.051334 3.475242 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 5.246067 3.475242 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 5.584734 3.475242 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 5.957267 3.475242 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 6.126600 3.475242 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 6.295934 3.475242 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 6.507600 3.475242 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 6.761600 3.475242 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 7.134134 3.475242 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave 7.726800 3.475242 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 8.099334 3.475242 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 8.294067 3.475242 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 8.666600 3.475242 translate 0.035278 -0.035278 scale +start_ol +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +2112 384 moveto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +2112 2496 lineto +2496 2496 lineto +2496 -960 lineto +2112 -960 lineto +2112 384 lineto +end_ol grestore +gsave 9.056067 3.475242 translate 0.035278 -0.035278 scale +start_ol +448 986 moveto +448 2496 lineto +832 2496 lineto +832 1001 lineto +832 629 978 442 conicto +1124 256 1417 256 conicto +1768 256 1972 477 conicto +2176 699 2176 1081 conicto +2176 2496 lineto +2560 2496 lineto +2560 0 lineto +2176 0 lineto +2176 384 lineto +2022 157 1819 46 conicto +1617 -64 1349 -64 conicto +906 -64 677 203 conicto +448 471 448 986 conicto +end_ol grestore +gsave 9.445534 3.475242 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 9.818067 3.475242 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 9.987400 3.475242 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 10.182134 3.475242 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 10.419200 3.475242 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 10.791734 3.475242 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 10.986467 3.475242 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 11.198134 3.475242 translate 0.035278 -0.035278 scale +start_ol +896 576 moveto +1344 576 lineto +1344 0 lineto +896 0 lineto +896 576 lineto +1344 896 moveto +896 896 lineto +896 1234 lineto +896 1455 961 1597 conicto +1027 1740 1239 1928 conicto +1428 2122 lineto +1553 2242 1608 2347 conicto +1664 2452 1664 2562 conicto +1664 2762 1516 2885 conicto +1368 3008 1124 3008 conicto +945 3008 742 2926 conicto +539 2845 320 2688 conicto +320 3136 lineto +531 3265 748 3328 conicto +966 3392 1197 3392 conicto +1610 3392 1861 3173 conicto +2112 2954 2112 2595 conicto +2112 2423 2032 2268 conicto +1953 2114 1755 1919 conicto +1562 1731 lineto +1465 1628 1425 1570 conicto +1385 1512 1369 1457 conicto +1357 1411 1350 1345 conicto +1344 1280 1344 1166 conicto +1344 896 lineto +end_ol grestore 1.000000 1.000000 1.000000 srgb n 13.204300 6.315370 m 13.204300 9.015370 l 18.654300 9.015370 l 18.654300 6.315370 l f 0.100000 slw @@ -363,116 +670,3627 @@ n 13.204300 6.315370 m 13.204300 9.015370 l 18.654300 9.015370 l 18.654300 6.315 0 slj 0.000000 0.000000 0.000000 srgb n 13.204300 6.315370 m 13.204300 9.015370 l 18.654300 9.015370 l 18.654300 6.315370 l cp s -/Helvetica-latin1 ff 0.560000 scf sf -(Pop call stack) dup sw 2 div 15.929300 ex sub 7.465370 m gs 1 -1 sc sh gr -(into callframe) dup sw 2 div 15.929300 ex sub 8.265370 m gs 1 -1 sc sh gr +gsave 13.846500 7.465370 translate 0.035278 -0.035278 scale +start_ol +896 2944 moveto +896 1728 lineto +1488 1728 lineto +1817 1728 1996 1886 conicto +2176 2044 2176 2337 conicto +2176 2627 1996 2785 conicto +1817 2944 1488 2944 conicto +896 2944 lineto +448 3328 moveto +1488 3328 lineto +2050 3328 2337 3076 conicto +2624 2824 2624 2337 conicto +2624 1847 2337 1595 conicto +2050 1344 1488 1344 conicto +896 1344 lineto +896 0 lineto +448 0 lineto +448 3328 lineto +end_ol grestore +gsave 14.185167 7.465370 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 14.557700 7.465370 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave 14.947167 7.465370 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 15.141900 7.465370 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 15.480567 7.465370 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 15.853100 7.465370 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 16.022433 7.465370 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 16.191767 7.465370 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 16.386500 7.465370 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 16.708233 7.465370 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 16.945300 7.465370 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 17.317833 7.465370 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 17.656500 7.465370 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 1419 lineto +2087 2496 lineto +2624 2496 lineto +1266 1328 lineto +2688 0 lineto +2137 0 lineto +832 1219 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 13.833800 8.265370 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 14.003133 8.265370 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 14.392600 8.265370 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 14.629667 8.265370 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 15.002200 8.265370 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 15.196933 8.265370 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 15.535600 8.265370 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 15.908133 8.265370 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 16.077467 8.265370 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 16.246800 8.265370 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 16.458467 8.265370 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 16.712467 8.265370 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 17.085000 8.265370 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave 17.677667 8.265370 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore 1.000000 1.000000 1.000000 srgb -n 7.430363 7.787500 m 14.488729 9.949211 l 7.430363 12.110922 l 0.371996 9.949211 l ef +n 7.430363 7.398875 m 15.757659 9.949211 l 7.430363 12.499548 l -0.896934 9.949211 l ef 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb -n 7.430363 7.787500 m 14.488729 9.949211 l 7.430363 12.110922 l 0.371996 9.949211 l cp s -/Helvetica-latin1 ff 0.560000 scf sf -(Is the car of the) dup sw 2 div 7.430363 ex sub 9.749211 m gs 1 -1 sc sh gr -(callframe a word?) dup sw 2 div 7.430363 ex sub 10.549211 m gs 1 -1 sc sh gr +n 7.430363 7.398875 m 15.757659 9.949211 l 7.430363 12.499548 l -0.896934 9.949211 l cp s +gsave 3.937863 9.749211 translate 0.035278 -0.035278 scale +start_ol +128 3328 moveto +584 3328 lineto +1286 515 lineto +1985 3328 lineto +2493 3328 lineto +3194 515 lineto +3893 3328 lineto +4352 3328 lineto +3514 0 lineto +2946 0 lineto +2242 2889 lineto +1531 0 lineto +964 0 lineto +128 3328 lineto +end_ol grestore +gsave 4.538996 9.749211 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 4.928463 9.749211 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 5.300996 9.749211 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 5.538063 9.749211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 5.732796 9.749211 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 5.902129 9.749211 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 6.223863 9.749211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 6.418596 9.749211 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 6.655663 9.749211 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 7.045129 9.749211 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 7.417663 9.749211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 7.612396 9.749211 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 7.849463 9.749211 translate 0.035278 -0.035278 scale +start_ol +1477 -262 moveto +1305 -695 1142 -827 conicto +980 -960 707 -960 conicto +384 -960 lineto +384 -640 lineto +622 -640 lineto +789 -640 881 -555 conicto +974 -471 1085 -156 conicto +1159 33 lineto +128 2496 lineto +590 2496 lineto +1361 544 lineto +2131 2496 lineto +2560 2496 lineto +1477 -262 lineto +end_ol grestore +gsave 8.213529 9.749211 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave 8.602996 9.749211 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 8.975529 9.749211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 9.170263 9.749211 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 9.542796 9.749211 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 9.754463 9.749211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 9.949196 9.749211 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 10.186263 9.749211 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 10.575729 9.749211 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 4.200329 10.549211 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 4.538996 10.549211 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 4.911529 10.549211 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 5.165529 10.549211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 5.360263 10.549211 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 5.732796 10.549211 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 5.944463 10.549211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 6.139196 10.549211 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 6.376263 10.549211 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 6.765729 10.549211 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 7.138263 10.549211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 7.332996 10.549211 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 7.671663 10.549211 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 8.044196 10.549211 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 8.213529 10.549211 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 8.382863 10.549211 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 8.577596 10.549211 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 8.789263 10.549211 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 9.043263 10.549211 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 9.415796 10.549211 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave 10.008463 10.549211 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 10.380996 10.549211 translate 0.035278 -0.035278 scale +start_ol +896 576 moveto +1344 576 lineto +1344 0 lineto +896 0 lineto +896 576 lineto +1344 896 moveto +896 896 lineto +896 1234 lineto +896 1455 961 1597 conicto +1027 1740 1239 1928 conicto +1428 2122 lineto +1553 2242 1608 2347 conicto +1664 2452 1664 2562 conicto +1664 2762 1516 2885 conicto +1368 3008 1124 3008 conicto +945 3008 742 2926 conicto +539 2845 320 2688 conicto +320 3136 lineto +531 3265 748 3328 conicto +966 3392 1197 3392 conicto +1610 3392 1861 3173 conicto +2112 2954 2112 2595 conicto +2112 2423 2032 2268 conicto +1953 2114 1755 1919 conicto +1562 1731 lineto +1465 1628 1425 1570 conicto +1385 1512 1369 1457 conicto +1357 1411 1350 1345 conicto +1344 1280 1344 1166 conicto +1344 896 lineto +end_ol grestore 1.000000 1.000000 1.000000 srgb -n 1.481360 13.637600 m 1.481360 16.337600 l 6.331360 16.337600 l 6.331360 13.637600 l f +n -3.318640 14.137600 m -3.318640 18.437600 l 3.431360 18.437600 l 3.431360 14.137600 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb -n 1.481360 13.637600 m 1.481360 16.337600 l 6.331360 16.337600 l 6.331360 13.637600 l cp s -/Helvetica-latin1 ff 0.560000 scf sf -(Push car on) dup sw 2 div 3.906360 ex sub 14.787600 m gs 1 -1 sc sh gr -(data stack) dup sw 2 div 3.906360 ex sub 15.587600 m gs 1 -1 sc sh gr +n -3.318640 14.137600 m -3.318640 18.437600 l 3.431360 18.437600 l 3.431360 14.137600 l cp s +gsave -2.678373 15.287600 translate 0.035278 -0.035278 scale +start_ol +448 3328 moveto +2560 3328 lineto +2560 2944 lineto +896 2944 lineto +896 1984 lineto +2496 1984 lineto +2496 1600 lineto +896 1600 lineto +896 384 lineto +2624 384 lineto +2624 0 lineto +448 0 lineto +448 3328 lineto +end_ol grestore +gsave -2.288907 15.287600 translate 0.035278 -0.035278 scale +start_ol +2496 2496 moveto +1589 1282 lineto +2560 0 lineto +2067 0 lineto +1327 981 lineto +607 0 lineto +128 0 lineto +1085 1306 lineto +192 2496 lineto +678 2496 lineto +1344 1607 lineto +2010 2496 lineto +2496 2496 lineto +end_ol grestore +gsave -1.941773 15.287600 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave -1.569240 15.287600 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave -1.230573 15.287600 translate 0.035278 -0.035278 scale +start_ol +448 986 moveto +448 2496 lineto +832 2496 lineto +832 1001 lineto +832 629 978 442 conicto +1124 256 1417 256 conicto +1768 256 1972 477 conicto +2176 699 2176 1081 conicto +2176 2496 lineto +2560 2496 lineto +2560 0 lineto +2176 0 lineto +2176 384 lineto +2022 157 1819 46 conicto +1617 -64 1349 -64 conicto +906 -64 677 203 conicto +448 471 448 986 conicto +end_ol grestore +gsave -0.841107 15.287600 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave -0.604040 15.287600 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave -0.231507 15.287600 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave -0.036773 15.287600 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 0.200293 15.287600 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 0.589760 15.287600 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 0.962293 15.287600 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 1.157027 15.287600 translate 0.035278 -0.035278 scale +start_ol +192 2496 moveto +607 2496 lineto +1126 549 lineto +1643 2496 lineto +2133 2496 lineto +2652 549 lineto +3169 2496 lineto +3584 2496 lineto +2923 0 lineto +2433 0 lineto +1890 2046 lineto +1343 0 lineto +853 0 lineto +192 2496 lineto +end_ol grestore +gsave 1.656560 15.287600 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 2.029093 15.287600 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 2.274627 15.287600 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +gsave 2.664093 15.287600 translate 0.035278 -0.035278 scale +start_ol +512 576 moveto +960 576 lineto +960 0 lineto +512 0 lineto +512 576 lineto +512 2368 moveto +960 2368 lineto +960 1792 lineto +512 1792 lineto +512 2368 lineto +end_ol grestore +gsave -2.288907 16.087600 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave -1.950240 16.087600 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave -1.577707 16.087600 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave -0.985040 16.087600 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave -0.595573 16.087600 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave -0.223040 16.087600 translate 0.035278 -0.035278 scale +start_ol +448 986 moveto +448 2496 lineto +832 2496 lineto +832 1001 lineto +832 629 978 442 conicto +1124 256 1417 256 conicto +1768 256 1972 477 conicto +2176 699 2176 1081 conicto +2176 2496 lineto +2560 2496 lineto +2560 0 lineto +2176 0 lineto +2176 384 lineto +2022 157 1819 46 conicto +1617 -64 1349 -64 conicto +906 -64 677 203 conicto +448 471 448 986 conicto +end_ol grestore +gsave 0.166427 16.087600 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 0.555893 16.087600 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +gsave 0.945360 16.087600 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 1.140093 16.087600 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +gsave 1.529560 16.087600 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 1.902093 16.087600 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 2.113760 16.087600 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave -1.192473 16.887600 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave -0.870740 16.887600 translate 0.035278 -0.035278 scale +start_ol +1477 -262 moveto +1305 -695 1142 -827 conicto +980 -960 707 -960 conicto +384 -960 lineto +384 -640 lineto +622 -640 lineto +789 -640 881 -555 conicto +974 -471 1085 -156 conicto +1159 33 lineto +128 2496 lineto +590 2496 lineto +1361 544 lineto +2131 2496 lineto +2560 2496 lineto +1477 -262 lineto +end_ol grestore +gsave -0.506673 16.887600 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave 0.085993 16.887600 translate 0.035278 -0.035278 scale +start_ol +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +832 2112 moveto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +end_ol grestore +gsave 0.475460 16.887600 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 0.847993 16.887600 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 1.017327 16.887600 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave -1.446473 17.687600 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave -1.057007 17.687600 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave -0.803007 17.687600 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave -0.633673 17.687600 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave -0.041007 17.687600 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 0.128327 17.687600 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 0.365393 17.687600 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 0.534727 17.687600 translate 0.035278 -0.035278 scale +start_ol +128 2496 moveto +563 2496 lineto +1344 401 lineto +2125 2496 lineto +2560 2496 lineto +1623 0 lineto +1065 0 lineto +128 2496 lineto +end_ol grestore +gsave 0.898793 17.687600 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 1.271327 17.687600 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore 1.000000 1.000000 1.000000 srgb -n 8.004240 12.950000 m 8.004240 17.250000 l 13.954240 17.250000 l 13.954240 12.950000 l f +n 11.604240 14.750000 m 11.604240 17.450000 l 17.200000 17.450000 l 17.200000 14.750000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb -n 8.004240 12.950000 m 8.004240 17.250000 l 13.954240 17.250000 l 13.954240 12.950000 l cp s -/Helvetica-latin1 ff 0.560000 scf sf -(Execute car:) dup sw 2 div 10.979240 ex sub 14.100000 m gs 1 -1 sc sh gr -(compound defs) dup sw 2 div 10.979240 ex sub 14.900000 m gs 1 -1 sc sh gr -(symbols) dup sw 2 div 10.979240 ex sub 15.700000 m gs 1 -1 sc sh gr -(primitives) dup sw 2 div 10.979240 ex sub 16.500000 m gs 1 -1 sc sh gr +n 11.604240 14.750000 m 11.604240 17.450000 l 17.200000 17.450000 l 17.200000 14.750000 l cp s +gsave 12.734187 15.900000 translate 0.035278 -0.035278 scale +start_ol +896 2944 moveto +896 1728 lineto +1488 1728 lineto +1817 1728 1996 1886 conicto +2176 2044 2176 2337 conicto +2176 2627 1996 2785 conicto +1817 2944 1488 2944 conicto +896 2944 lineto +448 3328 moveto +1488 3328 lineto +2050 3328 2337 3076 conicto +2624 2824 2624 2337 conicto +2624 1847 2337 1595 conicto +2050 1344 1488 1344 conicto +896 1344 lineto +896 0 lineto +448 0 lineto +448 3328 lineto +end_ol grestore +gsave 13.089787 15.900000 translate 0.035278 -0.035278 scale +start_ol +448 986 moveto +448 2496 lineto +832 2496 lineto +832 1001 lineto +832 629 978 442 conicto +1124 256 1417 256 conicto +1768 256 1972 477 conicto +2176 699 2176 1081 conicto +2176 2496 lineto +2560 2496 lineto +2560 0 lineto +2176 0 lineto +2176 384 lineto +2022 157 1819 46 conicto +1617 -64 1349 -64 conicto +906 -64 677 203 conicto +448 471 448 986 conicto +end_ol grestore +gsave 13.479253 15.900000 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 13.800987 15.900000 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 14.190453 15.900000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 14.385187 15.900000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 14.554520 15.900000 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 14.723853 15.900000 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 14.960920 15.900000 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 15.333453 15.900000 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 15.587453 15.900000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 15.959987 15.900000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 12.327787 16.700000 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 12.700320 16.700000 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 13.089787 16.700000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 13.284520 16.700000 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +gsave 13.673987 16.700000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 14.046520 16.700000 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 14.283587 16.700000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 14.656120 16.700000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 14.850853 16.700000 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 15.172587 16.700000 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 15.409653 16.700000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 15.782187 16.700000 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 16.120853 16.700000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 1419 lineto +2087 2496 lineto +2624 2496 lineto +1266 1328 lineto +2688 0 lineto +2137 0 lineto +832 1219 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore 1.000000 1.000000 1.000000 srgb -n 4.025000 18.750000 m 4.025000 21.450000 l 10.275000 21.450000 l 10.275000 18.750000 l f +n 4.375000 21.200000 m 4.375000 23.900000 l 10.625000 23.900000 l 10.625000 21.200000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb -n 4.025000 18.750000 m 4.025000 21.450000 l 10.275000 21.450000 l 10.275000 18.750000 l cp s -/Helvetica-latin1 ff 0.560000 scf sf -(Set call frame to) dup sw 2 div 7.150000 ex sub 19.900000 m gs 1 -1 sc sh gr -(call frame's cdr) dup sw 2 div 7.150000 ex sub 20.700000 m gs 1 -1 sc sh gr +n 4.375000 21.200000 m 4.375000 23.900000 l 10.625000 23.900000 l 10.625000 21.200000 l cp s +gsave 4.993867 22.350000 translate 0.035278 -0.035278 scale +start_ol +2496 3200 moveto +2496 2752 lineto +2234 2882 2001 2945 conicto +1768 3008 1552 3008 conicto +1175 3008 971 2863 conicto +768 2718 768 2452 conicto +768 2228 905 2113 conicto +1042 1999 1426 1929 conicto +1708 1873 lineto +2210 1778 2449 1540 conicto +2688 1303 2688 903 conicto +2688 427 2358 181 conicto +2029 -64 1392 -64 conicto +1152 -64 881 -15 conicto +610 33 320 128 conicto +320 576 lineto +603 448 875 384 conicto +1147 320 1409 320 conicto +1807 320 2023 465 conicto +2240 610 2240 878 conicto +2240 1113 2084 1245 conicto +1928 1378 1572 1444 conicto +1288 1497 lineto +776 1599 548 1817 conicto +320 2035 320 2424 conicto +320 2874 636 3133 conicto +952 3392 1507 3392 conicto +1744 3392 1991 3344 conicto +2238 3297 2496 3200 conicto +end_ol grestore +gsave 5.383333 22.350000 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 5.755867 22.350000 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 5.992933 22.350000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 6.187667 22.350000 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 6.526333 22.350000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 6.898867 22.350000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 7.068200 22.350000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 7.237533 22.350000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 7.432267 22.350000 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 7.643933 22.350000 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 7.897933 22.350000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 8.270467 22.350000 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave 8.863133 22.350000 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 9.235667 22.350000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 9.430400 22.350000 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 9.667467 22.350000 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 5.142033 23.150000 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 5.480700 23.150000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 5.853233 23.150000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 6.022567 23.150000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 6.191900 23.150000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 6.386633 23.150000 translate 0.035278 -0.035278 scale +start_ol +1664 3520 moveto +1664 3200 lineto +1305 3200 lineto +1075 3200 985 3100 conicto +896 3001 896 2742 conicto +896 2496 lineto +1600 2496 lineto +1600 2176 lineto +896 2176 lineto +896 0 lineto +512 0 lineto +512 2176 lineto +128 2176 lineto +128 2496 lineto +512 2496 lineto +512 2691 lineto +512 3124 703 3322 conicto +894 3520 1310 3520 conicto +1664 3520 lineto +end_ol grestore +gsave 6.598300 23.150000 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 6.852300 23.150000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 7.224833 23.150000 translate 0.035278 -0.035278 scale +start_ol +2431 2020 moveto +2590 2296 2809 2428 conicto +3029 2560 3325 2560 conicto +3726 2560 3943 2287 conicto +4160 2014 4160 1509 conicto +4160 0 lineto +3776 0 lineto +3776 1496 lineto +3776 1874 3641 2057 conicto +3506 2240 3228 2240 conicto +2890 2240 2693 2018 conicto +2496 1796 2496 1413 conicto +2496 0 lineto +2112 0 lineto +2112 1496 lineto +2112 1876 1976 2058 conicto +1841 2240 1560 2240 conicto +1225 2240 1028 2017 conicto +832 1794 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +977 2341 1180 2450 conicto +1383 2560 1662 2560 conicto +1942 2560 2139 2422 conicto +2337 2284 2431 2020 conicto +end_ol grestore +gsave 7.817500 23.150000 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 8.190033 23.150000 translate 0.035278 -0.035278 scale +start_ol +832 3328 moveto +832 2048 lineto +448 2048 lineto +448 3328 lineto +832 3328 lineto +end_ol grestore +gsave 8.359367 23.150000 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 8.681100 23.150000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 8.875833 23.150000 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 9.214500 23.150000 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +gsave 9.603967 23.150000 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore 0.100000 slw [] 0 sd [] 0 sd 0 slc -n 7.417770 5.217190 m 7.429265 7.563896 l s +n 7.417770 5.217190 m 7.429072 7.175272 l s 0.100000 slw [] 0 sd 0 slj 0 slc -n 7.177366 7.176928 m 7.429812 7.675698 l 7.677360 7.174479 l s +n 7.176836 6.788525 m 7.429717 7.287073 l 7.676827 6.785639 l s 0.100000 slw [] 0 sd [] 0 sd 0 slc -n 10.959500 11.030100 m 10.976941 12.726405 l s +n 11.594011 11.224379 m 14.262809 14.575093 l s 0.100000 slw [] 0 sd 0 slj 0 slc -n 10.722963 12.340799 m 10.978091 12.838203 l 11.222937 12.335659 l s +n 13.825404 14.427197 m 14.332464 14.662547 l 14.216508 14.115688 l s 0.100000 slw [] 0 sd [] 0 sd 0 slc -n 3.901180 11.030100 m 3.905916 13.413994 l s +n 3.266714 11.224379 m 0.221951 13.987335 l s 0.100000 slw [] 0 sd 0 slj 0 slc -n 3.655145 13.026294 m 3.906138 13.525797 l 4.155144 13.025301 l s +n 0.341427 13.541328 m 0.139156 14.062468 l 0.677430 13.911602 l s 0.100000 slw [] 0 sd [] 0 sd 0 slc -n 10.979240 17.250000 m 8.898975 18.626602 l s +n 14.402120 17.450000 m 9.245488 21.071488 l s 0.100000 slw [] 0 sd 0 slj 0 slc -n 9.084744 18.203888 m 8.805737 18.688301 l 9.360671 18.620859 l s +n 9.419487 20.643795 m 9.153994 21.135744 l 9.706849 21.052969 l s 0.100000 slw [] 0 sd [] 0 sd 0 slc -n 3.906360 16.337600 m 5.459655 18.566545 l s +n 0.056360 18.437600 m 5.735108 21.104935 l s 0.100000 slw [] 0 sd 0 slj 0 slc -n 5.032599 18.390990 m 5.523578 18.658273 l 5.442816 18.105120 l s +n 5.277455 21.166178 m 5.836304 21.152468 l 5.490026 20.713615 l s 0.100000 slw [] 0 sd [] 0 sd 0 slj 0 slc -n 7.150000 21.450000 m 7.150000 22.099700 l -1.000000 22.099700 l -1.000000 1.319040 l 3.533880 1.319040 l 3.533880 2.080663 l s +n 7.500000 23.900000 m 7.500000 25.719040 l -3.600000 25.719040 l -3.600000 -0.330960 l 7.417767 -0.330960 l 7.417767 1.109693 l s 0.100000 slw [] 0 sd 0 slj 0 slc -n 3.283880 1.692467 m 3.533880 2.192467 l 3.783880 1.692467 l s +n 7.167767 0.721497 m 7.417767 1.221497 l 7.667767 0.721497 l s 0.100000 slw [] 0 sd [] 0 sd @@ -494,12 +4312,1149 @@ n 15.929300 9.015370 m 15.929300 9.639660 l 19.267400 9.639660 l 19.267400 1.319 0 slj 0 slc n 11.051700 1.692467 m 11.301700 2.192467 l 11.551700 1.692467 l s -/Helvetica-latin1 ff 0.560000 scf sf -(No) 6.450000 6.519040 m gs 1 -1 sc sh gr -/Helvetica-latin1 ff 0.560000 scf sf -(Yes) 13.350000 5.119040 m gs 1 -1 sc sh gr -/Helvetica-latin1 ff 0.560000 scf sf -(Yes) 11.300000 12.019040 m gs 1 -1 sc sh gr -/Helvetica-latin1 ff 0.560000 scf sf -(No) 2.750000 12.069040 m gs 1 -1 sc sh gr +gsave 6.450000 6.519040 translate 0.035278 -0.035278 scale +start_ol +448 3328 moveto +1067 3328 lineto +2560 544 lineto +2560 3328 lineto +3008 3328 lineto +3008 0 lineto +2389 0 lineto +896 2784 lineto +896 0 lineto +448 0 lineto +448 3328 lineto +end_ol grestore +gsave 6.907200 6.519040 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 13.350000 5.119040 translate 0.035278 -0.035278 scale +start_ol +-64 3328 moveto +432 3328 lineto +1379 1960 lineto +2320 3328 lineto +2816 3328 lineto +1600 1585 lineto +1600 0 lineto +1152 0 lineto +1152 1585 lineto +-64 3328 lineto +end_ol grestore +gsave 13.637867 5.119040 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 14.010400 5.119040 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 13.600000 13.019000 translate 0.035278 -0.035278 scale +start_ol +1600 2882 moveto +985 1216 lineto +2218 1216 lineto +1600 2882 lineto +1344 3328 moveto +1858 3328 lineto +3136 0 lineto +2665 0 lineto +2360 832 lineto +847 832 lineto +542 0 lineto +64 0 lineto +1344 3328 lineto +end_ol grestore +gsave 14.014867 13.019000 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 14.209600 13.019000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave 14.378933 13.019000 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 14.548267 13.019000 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 14.785333 13.019000 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 15.157867 13.019000 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 15.411867 13.019000 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 15.784400 13.019000 translate 0.035278 -0.035278 scale +start_ol +448 3520 moveto +832 3520 lineto +832 0 lineto +448 0 lineto +448 3520 lineto +end_ol grestore +gsave -1.100000 13.019040 translate 0.035278 -0.035278 scale +start_ol +1600 2882 moveto +985 1216 lineto +2218 1216 lineto +1600 2882 lineto +1344 3328 moveto +1858 3328 lineto +3136 0 lineto +2665 0 lineto +2360 832 lineto +847 832 lineto +542 0 lineto +64 0 lineto +1344 3328 lineto +end_ol grestore +gsave -0.685133 13.019040 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave -0.490400 13.019040 translate 0.035278 -0.035278 scale +start_ol +192 2496 moveto +607 2496 lineto +1126 549 lineto +1643 2496 lineto +2133 2496 lineto +2652 549 lineto +3169 2496 lineto +3584 2496 lineto +2923 0 lineto +2433 0 lineto +1890 2046 lineto +1343 0 lineto +853 0 lineto +192 2496 lineto +end_ol grestore +gsave 0.009133 13.019040 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 0.381667 13.019040 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 0.627200 13.019040 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +1.000000 1.000000 1.000000 srgb +n 4.075000 14.769040 m 4.075000 17.569040 l 10.875000 17.569040 l 10.875000 14.769040 l f +0.100000 slw +[] 0 sd +[] 0 sd +0 slj +0.000000 0.000000 0.000000 srgb +n 4.075000 14.769040 m 4.075000 17.569040 l 10.875000 17.569040 l 10.875000 14.769040 l cp s +gsave 5.121267 15.969040 translate 0.035278 -0.035278 scale +start_ol +896 2944 moveto +896 1728 lineto +1488 1728 lineto +1817 1728 1996 1886 conicto +2176 2044 2176 2337 conicto +2176 2627 1996 2785 conicto +1817 2944 1488 2944 conicto +896 2944 lineto +448 3328 moveto +1488 3328 lineto +2050 3328 2337 3076 conicto +2624 2824 2624 2337 conicto +2624 1847 2337 1595 conicto +2050 1344 1488 1344 conicto +896 1344 lineto +896 0 lineto +448 0 lineto +448 3328 lineto +end_ol grestore +gsave 5.476867 15.969040 translate 0.035278 -0.035278 scale +start_ol +448 986 moveto +448 2496 lineto +832 2496 lineto +832 1001 lineto +832 629 978 442 conicto +1124 256 1417 256 conicto +1768 256 1972 477 conicto +2176 699 2176 1081 conicto +2176 2496 lineto +2560 2496 lineto +2560 0 lineto +2176 0 lineto +2176 384 lineto +2022 157 1819 46 conicto +1617 -64 1349 -64 conicto +906 -64 677 203 conicto +448 471 448 986 conicto +end_ol grestore +gsave 5.866333 15.969040 translate 0.035278 -0.035278 scale +start_ol +2048 2432 moveto +2048 2048 lineto +1868 2144 1674 2192 conicto +1480 2240 1273 2240 conicto +957 2240 798 2144 conicto +640 2048 640 1856 conicto +640 1709 757 1625 conicto +875 1542 1229 1467 conicto +1380 1435 lineto +1812 1341 1994 1170 conicto +2176 999 2176 692 conicto +2176 343 1899 139 conicto +1622 -64 1137 -64 conicto +936 -64 717 -32 conicto +498 0 256 64 conicto +256 512 lineto +490 385 718 320 conicto +947 256 1170 256 conicto +1470 256 1631 358 conicto +1792 461 1792 647 conicto +1792 820 1670 912 conicto +1549 1004 1141 1089 conicto +988 1123 lineto +600 1203 428 1369 conicto +256 1535 256 1824 conicto +256 2177 510 2368 conicto +765 2560 1233 2560 conicto +1466 2560 1670 2528 conicto +1875 2496 2048 2432 conicto +end_ol grestore +gsave 6.188067 15.969040 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 6.577533 15.969040 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 6.772267 15.969040 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 7.009333 15.969040 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 7.398800 15.969040 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 7.771333 15.969040 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 7.966067 15.969040 translate 0.035278 -0.035278 scale +start_ol +1409 2240 moveto +1083 2240 893 1974 conicto +704 1709 704 1248 conicto +704 787 892 521 conicto +1081 256 1409 256 conicto +1733 256 1922 522 conicto +2112 789 2112 1248 conicto +2112 1705 1922 1972 conicto +1733 2240 1409 2240 conicto +1408 2560 moveto +1946 2560 2253 2212 conicto +2560 1864 2560 1248 conicto +2560 634 2253 285 conicto +1946 -64 1408 -64 conicto +869 -64 562 285 conicto +256 634 256 1248 conicto +256 1864 562 2212 conicto +869 2560 1408 2560 conicto +end_ol grestore +gsave 8.338600 15.969040 translate 0.035278 -0.035278 scale +start_ol +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +832 2112 moveto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +end_ol grestore +gsave 8.728067 15.969040 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 -76 lineto +832 -542 657 -751 conicto +482 -960 91 -960 conicto +-64 -960 lineto +-64 -640 lineto +28 -640 lineto +272 -640 360 -530 conicto +448 -421 448 -76 conicto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 8.897400 15.969040 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 9.269933 15.969040 translate 0.035278 -0.035278 scale +start_ol +2240 2432 moveto +2240 2048 lineto +2066 2144 1892 2192 conicto +1718 2240 1541 2240 conicto +1143 2240 923 1979 conicto +704 1718 704 1248 conicto +704 778 923 517 conicto +1143 256 1541 256 conicto +1718 256 1892 304 conicto +2066 352 2240 448 conicto +2240 64 lineto +2068 0 1883 -32 conicto +1698 -64 1490 -64 conicto +924 -64 590 290 conicto +256 645 256 1248 conicto +256 1859 593 2209 conicto +931 2560 1517 2560 conicto +1707 2560 1888 2528 conicto +2070 2496 2240 2432 conicto +end_ol grestore +gsave 9.608600 15.969040 translate 0.035278 -0.035278 scale +start_ol +832 3200 moveto +832 2496 lineto +1664 2496 lineto +1664 2176 lineto +832 2176 lineto +832 804 lineto +832 495 914 407 conicto +997 320 1248 320 conicto +1664 320 lineto +1664 0 lineto +1248 0 lineto +793 0 620 173 conicto +448 347 448 804 conicto +448 2176 lineto +128 2176 lineto +128 2496 lineto +448 2496 lineto +448 3200 lineto +832 3200 lineto +end_ol grestore +gsave 5.218633 16.769040 translate 0.035278 -0.035278 scale +start_ol +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +832 2112 moveto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +832 0 lineto +448 0 lineto +448 3520 lineto +832 3520 lineto +832 2112 lineto +end_ol grestore +gsave 5.608100 16.769040 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 5.980633 16.769040 translate 0.035278 -0.035278 scale +start_ol +448 2496 moveto +832 2496 lineto +832 0 lineto +448 0 lineto +448 2496 lineto +448 3520 moveto +832 3520 lineto +832 3008 lineto +448 3008 lineto +448 3520 lineto +end_ol grestore +gsave 6.149967 16.769040 translate 0.035278 -0.035278 scale +start_ol +2560 1509 moveto +2560 0 lineto +2176 0 lineto +2176 1496 lineto +2176 1869 2029 2054 conicto +1883 2240 1590 2240 conicto +1238 2240 1035 2018 conicto +832 1796 832 1413 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +983 2337 1188 2448 conicto +1394 2560 1662 2560 conicto +2106 2560 2333 2293 conicto +2560 2027 2560 1509 conicto +end_ol grestore +gsave 6.539433 16.769040 translate 0.035278 -0.035278 scale +start_ol +2112 1278 moveto +2112 1736 1926 1988 conicto +1741 2240 1407 2240 conicto +1074 2240 889 1988 conicto +704 1736 704 1278 conicto +704 824 889 572 conicto +1074 320 1407 320 conicto +1741 320 1926 572 conicto +2112 824 2112 1278 conicto +2496 289 moveto +2496 -343 2214 -651 conicto +1933 -960 1352 -960 conicto +1137 -960 946 -928 conicto +755 -896 576 -832 conicto +576 -448 lineto +758 -546 936 -593 conicto +1114 -640 1298 -640 conicto +1707 -640 1909 -426 conicto +2112 -212 2112 220 conicto +2112 448 lineto +1982 223 1780 111 conicto +1578 0 1297 0 conicto +828 0 542 350 conicto +256 701 256 1279 conicto +256 1859 542 2209 conicto +828 2560 1297 2560 conicto +1578 2560 1780 2448 conicto +1982 2337 2112 2112 conicto +2112 2496 lineto +2496 2496 lineto +2496 289 lineto +end_ol grestore +gsave 6.928900 16.769040 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 7.123633 16.769040 translate 0.035278 -0.035278 scale +start_ol +192 2496 moveto +607 2496 lineto +1126 549 lineto +1643 2496 lineto +2133 2496 lineto +2652 549 lineto +3169 2496 lineto +3584 2496 lineto +2923 0 lineto +2433 0 lineto +1890 2046 lineto +1343 0 lineto +853 0 lineto +192 2496 lineto +end_ol grestore +gsave 7.623167 16.769040 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 7.877167 16.769040 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 8.249700 16.769040 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave 8.639167 16.769040 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave 9.028633 16.769040 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 9.401167 16.769040 translate 0.035278 -0.035278 scale +start_ol +2112 2112 moveto +2112 3520 lineto +2496 3520 lineto +2496 0 lineto +2112 0 lineto +2112 384 lineto +1980 156 1779 46 conicto +1578 -64 1297 -64 conicto +835 -64 545 297 conicto +256 659 256 1248 conicto +256 1837 545 2198 conicto +835 2560 1297 2560 conicto +1578 2560 1779 2450 conicto +1980 2340 2112 2112 conicto +704 1249 moveto +704 784 891 520 conicto +1079 256 1407 256 conicto +1735 256 1923 520 conicto +2112 784 2112 1249 conicto +2112 1713 1923 1976 conicto +1735 2240 1407 2240 conicto +1079 2240 891 1976 conicto +704 1713 704 1249 conicto +end_ol grestore +0.100000 slw +[] 0 sd +[] 0 sd +0 slc +n 7.430363 12.499548 m 7.470603 14.545476 l s +0.100000 slw +[] 0 sd +0 slj +0 slc +n 7.213017 14.162271 m 7.472801 14.657258 l 7.712921 14.152439 l s +gsave 7.700000 13.969040 translate 0.035278 -0.035278 scale +start_ol +1600 2882 moveto +985 1216 lineto +2218 1216 lineto +1600 2882 lineto +1344 3328 moveto +1858 3328 lineto +3136 0 lineto +2665 0 lineto +2360 832 lineto +847 832 lineto +542 0 lineto +64 0 lineto +1344 3328 lineto +end_ol grestore +gsave 8.114867 13.969040 translate 0.035278 -0.035278 scale +start_ol +end_ol grestore +gsave 8.309600 13.969040 translate 0.035278 -0.035278 scale +start_ol +192 2496 moveto +607 2496 lineto +1126 549 lineto +1643 2496 lineto +2133 2496 lineto +2652 549 lineto +3169 2496 lineto +3584 2496 lineto +2923 0 lineto +2433 0 lineto +1890 2046 lineto +1343 0 lineto +853 0 lineto +192 2496 lineto +end_ol grestore +gsave 8.809133 13.969040 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore +gsave 9.063133 13.969040 translate 0.035278 -0.035278 scale +start_ol +1559 1280 moveto +1040 1280 840 1160 conicto +640 1041 640 754 conicto +640 525 790 390 conicto +940 256 1198 256 conicto +1554 256 1769 510 conicto +1984 765 1984 1187 conicto +1984 1280 lineto +1559 1280 lineto +2368 1449 moveto +2368 0 lineto +1984 0 lineto +1984 384 lineto +1842 154 1628 45 conicto +1415 -64 1107 -64 conicto +717 -64 486 154 conicto +256 372 256 739 conicto +256 1166 539 1383 conicto +822 1600 1384 1600 conicto +1984 1600 lineto +1984 1641 lineto +1984 1927 1796 2083 conicto +1608 2240 1266 2240 conicto +1049 2240 843 2192 conicto +638 2144 448 2048 conicto +448 2432 lineto +673 2496 884 2528 conicto +1095 2560 1295 2560 conicto +1835 2560 2101 2284 conicto +2368 2009 2368 1449 conicto +end_ol grestore +gsave 9.435667 13.969040 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave 9.825133 13.969040 translate 0.035278 -0.035278 scale +start_ol +832 384 moveto +832 -960 lineto +448 -960 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +963 2340 1164 2450 conicto +1366 2560 1645 2560 conicto +2108 2560 2398 2198 conicto +2688 1837 2688 1248 conicto +2688 659 2398 297 conicto +2108 -64 1645 -64 conicto +1366 -64 1164 46 conicto +963 156 832 384 conicto +2240 1249 moveto +2240 1713 2052 1976 conicto +1865 2240 1536 2240 conicto +1208 2240 1020 1976 conicto +832 1713 832 1249 conicto +832 784 1020 520 conicto +1208 256 1536 256 conicto +1865 256 2052 520 conicto +2240 784 2240 1249 conicto +end_ol grestore +gsave 10.214600 13.969040 translate 0.035278 -0.035278 scale +start_ol +2624 1352 moveto +2624 1152 lineto +704 1152 lineto +731 715 960 485 conicto +1189 256 1597 256 conicto +1834 256 2056 320 conicto +2278 384 2496 512 conicto +2496 128 lineto +2273 34 2039 -15 conicto +1805 -64 1565 -64 conicto +961 -64 608 284 conicto +256 632 256 1225 conicto +256 1839 595 2199 conicto +934 2560 1509 2560 conicto +2024 2560 2324 2235 conicto +2624 1910 2624 1352 conicto +2240 1472 moveto +2235 1822 2043 2031 conicto +1852 2240 1537 2240 conicto +1180 2240 965 2038 conicto +750 1836 718 1470 conicto +2240 1472 lineto +end_ol grestore +gsave 10.587133 13.969040 translate 0.035278 -0.035278 scale +start_ol +1920 2112 moveto +1848 2178 1764 2209 conicto +1680 2240 1578 2240 conicto +1218 2240 1025 2001 conicto +832 1763 832 1317 conicto +832 0 lineto +448 0 lineto +448 2496 lineto +832 2496 lineto +832 2112 lineto +965 2339 1180 2449 conicto +1396 2560 1702 2560 conicto +1747 2560 1799 2560 conicto +1852 2560 1917 2560 conicto +1920 2112 lineto +end_ol grestore showpage diff --git a/doc/theory.tex b/doc/theory.tex index 7709980259..ebefcdfa58 100644 --- a/doc/theory.tex +++ b/doc/theory.tex @@ -88,7 +88,7 @@ The set of program quotations, $QUOT \subset OBJ$, is the smallest set satisfyin \begin{enumerate} -\item The empty list $\mbox{\texttt{f}} \in QUOT$. +\item The empty list $\bot \in QUOT$. \item If $a \in OBJ$, $b \in QUOT$, $(a::b) \in QUOT$. \end{enumerate} @@ -105,7 +105,7 @@ The set of stacks, $STACK \subset QUOT$, is the smallest set satisfying: \begin{enumerate} -\item The empty list $\mbox{\texttt{f}} \in STACK$. +\item The empty list $\bot \in STACK$. \item If $a \in QUOT$, $b \in STACK$, $(a::b) \in STACK$. \end{enumerate} diff --git a/examples/factorbot.factor b/examples/factorbot.factor index b699c036f3..da4febb162 100644 --- a/examples/factorbot.factor +++ b/examples/factorbot.factor @@ -1,8 +1,8 @@ ! Simple IRC bot written in Factor. +USING: errors generic hashtables http io kernel math namespaces +parser prettyprint sequences strings unparser words ; IN: factorbot -USING: hashtables http io kernel math namespaces prettyprint -sequences strings words ; SYMBOL: irc-stream SYMBOL: nickname @@ -30,15 +30,15 @@ SYMBOL: receiver "JOIN " irc-write irc-print ; GENERIC: handle-irc -PREDICATE: string privmsg "PRIVMSG" swap subseq? ; +PREDICATE: string privmsg " " split1 nip "PRIVMSG" head? ; +PREDICATE: string ping "PING" head? ; -M: string handle-irc ( line -- ) +M: object handle-irc ( line -- ) drop ; : parse-privmsg ( line -- text ) - ":" ?head drop - "!" split1 swap speaker set - "PRIVMSG " split1 nip + " " split1 nip + "PRIVMSG " ?head drop " " split1 swap receiver set ":" ?head drop ; @@ -48,6 +48,12 @@ M: privmsg handle-irc ( line -- ) [ "factorbot-commands" ] search dup [ execute ] [ 2drop ] ifte ; +M: ping handle-irc ( line -- ) + "PING " ?head drop "PONG " swap append irc-print ; + +: parse-irc ( line -- ) + ":" ?head [ "!" split1 swap speaker set ] when handle-irc ; + : say ( line nick -- ) "PRIVMSG " irc-write irc-write " :" irc-write irc-print ; @@ -72,7 +78,7 @@ M: privmsg handle-irc ( line -- ) : irc-loop ( -- ) irc-stream get stream-readln - [ dup print flush handle-irc irc-loop ] when* ; + [ dup print flush parse-irc irc-loop ] when* ; : factorbot "irc.freenode.net" connect diff --git a/examples/mandel.factor b/examples/mandel.factor index 065ae40939..27f4330448 100644 --- a/examples/mandel.factor +++ b/examples/mandel.factor @@ -87,12 +87,10 @@ USE: test : val 0.85 ; : ( nb-cols -- map ) - [ - dup [ - dup 360 * pick 1 + / 360 / sat val - hsv>rgb 1.0 scale-rgb , - ] repeat - ] make-vector nip ; + dup [ + 360 * swap 1 + / 360 / sat val + hsv>rgb 1.0 scale-rgb + ] map-with ; : iter ( c z nb-iter -- x ) over absq 4 >= over 0 = or [ diff --git a/examples/numbers-game.factor b/examples/numbers-game.factor index 00e45e2368..18ee288ce0 100644 --- a/examples/numbers-game.factor +++ b/examples/numbers-game.factor @@ -1,7 +1,7 @@ IN: numbers-game USING: kernel math parser random io ; -: read-number ( -- n ) readln parse-number ; +: read-number ( -- n ) readln str>number ; : guess-banner "I'm thinking of a number between 0 and 100." print ; diff --git a/examples/plot3d.factor b/examples/plot3d.factor index 76f50b5904..9551803951 100644 --- a/examples/plot3d.factor +++ b/examples/plot3d.factor @@ -15,28 +15,35 @@ ! "examples/plot3d.factor" run-file IN: plot3d -USING: alien compiler errors gl kernel lists math matrices -namespaces prettyprint sdl sequences ; +USING: alien compiler errors gl kernel lists math namespaces +prettyprint sdl sequences vectors ; : display-list 1 ; +: matrix-get ( i j matrix -- ) swapd nth nth ; + : plot-vertex ( matrix i j -- ) - rot matrix-get 3unlist glVertex3f ; + rot matrix-get 3unseq glVertex3f ; : plot-face ( matrix i j -- face ) GL_QUADS glBegin [ rot matrix-get ] 3keep [ 1 + rot matrix-get v- ] 3keep [ rot matrix-get ] 3keep - [ >r 1 + r> rot matrix-get v- cross normalize >list 3unlist glNormal3f ] 3keep + [ >r 1 + r> rot matrix-get v- cross normalize 3unseq glNormal3f ] 3keep [ plot-vertex ] 3keep [ 1 + plot-vertex ] 3keep [ >r 1 + r> 1 + plot-vertex ] 3keep >r 1 + r> plot-vertex glEnd ; +: 2repeat ( i j quot -- | quot: i j -- i j ) + rot [ + rot [ [ rot dup slip -rot ] repeat ] keep -rot + ] repeat 2drop ; inline + : plot-faces ( points -- ) - dup matrix-rows 1 - over matrix-cols 1 - [ + dup length 1 - over first length 1 - [ 3dup plot-face ] 2repeat drop ; @@ -65,23 +72,27 @@ SYMBOL: theta swap 15 - 30 / swap 15 - 30 / ; : max-z ( seq -- z ) - 0.1 swap [ 2 swap nth max ] each ; + 0.1 [ third max ] reduce ; : min-z ( seq -- z ) - -0.1 swap [ 2 swap nth min ] each ; + -0.1 [ third min ] reduce ; : normalize-points ( seq -- ) - dup min-z over [ over >r 3unlist r> - 3list ] nmap drop - dup max-z swap [ over >r 3unlist r> / 3list ] nmap drop ; + dup min-z over [ over >r 3unseq r> - 3vector ] nmap drop + dup max-z swap [ over >r 3unseq r> / 3vector ] nmap drop ; : valuate-points ( quot -- matrix ) - >r 30 30 r> - [ i/j>x/y ] swap unit [ 2keep rot 3list ] append3 - make-matrix ; + 30 [ + ( quot i ) + 30 [ + ( quot i j ) + [ 3dup i/j>x/y rot call ] 2keep i/j>x/y rot 3vector nip + ] map 2nip + ] map-with ; inline : make-plot - [ rect> sq exp real ] valuate-points - dup matrix-sequence normalize-points + [ rect> real ] valuate-points + dup [ normalize-points ] each display-list GL_COMPILE glNewList plot-faces plot-axes diff --git a/factor/jedit/FactorPlugin.props b/factor/jedit/FactorPlugin.props index a815a43ff3..65d4ed2c81 100644 --- a/factor/jedit/FactorPlugin.props +++ b/factor/jedit/FactorPlugin.props @@ -2,7 +2,7 @@ plugin.factor.jedit.FactorPlugin.activate=startup plugin.factor.jedit.FactorPlugin.name=Factor -plugin.factor.jedit.FactorPlugin.version=0.76 +plugin.factor.jedit.FactorPlugin.version=0.77 plugin.factor.jedit.FactorPlugin.author=Slava Pestov plugin.factor.jedit.FactorPlugin.docs=/doc/jedit/index.html diff --git a/library/alien/aliens.factor b/library/alien/aliens.factor index 5808e7f3b7..21f63dccdc 100644 --- a/library/alien/aliens.factor +++ b/library/alien/aliens.factor @@ -4,21 +4,8 @@ IN: alien USING: hashtables io kernel kernel-internals lists math namespaces parser ; -DEFER: dll? -BUILTIN: dll 15 dll? [ 1 "dll-path" f ] ; - -DEFER: alien? -BUILTIN: alien 16 alien? ; - -DEFER: displaced-alien? -BUILTIN: displaced-alien 20 displaced-alien? ; - UNION: c-ptr byte-array alien displaced-alien ; -: NULL ( -- null ) - #! C null value. - 0 ; - M: alien hashcode ( obj -- n ) alien-address >fixnum ; @@ -44,13 +31,12 @@ M: alien = ( obj obj -- ? ) : add-library ( library name abi -- ) "libraries" get [ - [ - "abi" set - "name" set - ] extend swap set + [ "abi" set "name" set ] make-hash swap set ] bind ; : library-abi ( library -- abi ) - library [ [ "abi" get ] bind ] [ "cdecl" ] ifte* ; + library "abi" swap ?hash [ "cdecl" ] unless* ; + +: DLL" skip-blank parse-string dlopen swons ; parsing : ALIEN: scan-word swons ; parsing diff --git a/library/alien/c-types.factor b/library/alien/c-types.factor index 9c7a5316c0..4e67313de4 100644 --- a/library/alien/c-types.factor +++ b/library/alien/c-types.factor @@ -6,14 +6,14 @@ hashtables kernel kernel-internals lists math namespaces parser sequences strings words ; : ( -- type ) - [ - [ "No setter" throw ] "setter" set - [ "No getter" throw ] "getter" set - "no boxer" "boxer" set - "no unboxer" "unboxer" set - << int-regs f >> "reg-class" set - 0 "width" set - ] extend ; + {{ + [[ "setter" [ "No setter" throw ] ]] + [[ "getter" [ "No getter" throw ] ]] + [[ "boxer" "no boxer" ]] + [[ "unboxer" "no unboxer" ]] + [[ "reg-class" << int-regs f >> ]] + [[ "width" 0 ]] + }} clone ; SYMBOL: c-types @@ -26,13 +26,12 @@ SYMBOL: c-types c-type [ "width" get ] bind ; : define-c-type ( quot name -- ) - >r swap extend r> c-types get set-hash ; inline + >r [ swap bind ] keep r> c-types get set-hash ; + inline -: ( size -- byte-array ) - cell / ceiling ; +: ( size -- c-ptr ) cell / ceiling ; -: ( n size -- byte-array ) - * cell / ceiling ; +: ( n size -- c-ptr ) * ; : define-pointer ( type -- ) "void*" c-type swap "*" append c-types get set-hash ; @@ -74,7 +73,7 @@ SYMBOL: c-types [ "width" get , \ , \ tuck , 0 , "setter" get % - ] make-list + ] [ ] make ] bind define-compound ; : init-c-type ( name vocab -- ) diff --git a/library/alien/compiler.factor b/library/alien/compiler.factor index 0a4afea1db..6be67f90a5 100644 --- a/library/alien/compiler.factor +++ b/library/alien/compiler.factor @@ -2,8 +2,8 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: alien USING: assembler compiler compiler-backend compiler-frontend -errors generic hashtables inference kernel lists math namespaces -sequences io strings unparser words ; +errors generic hashtables inference io kernel lists math +namespaces prettyprint sequences strings words parser ; ! ! ! WARNING ! ! ! ! Reloading this file into a running Factor instance on Win32 @@ -26,21 +26,14 @@ sequences io strings unparser words ; ! FFI code does not run in the interpreter. -TUPLE: alien-error symbol library ; - -C: alien-error ( lib sym -- ) - [ set-alien-error-symbol ] keep - [ set-alien-error-library ] keep ; +TUPLE: alien-error library symbol ; M: alien-error error. ( error -- ) - [ - "C library interface words cannot be interpreted. " % - "Either the compiler is disabled, " % - "or the " % dup alien-error-library unparse % - " library does not define the " % - alien-error-symbol unparse % - " symbol." % - ] make-string print ; + "C library interface words cannot be interpreted. " write + "Either the compiler is disabled, " write + "or the " write dup alien-error-library pprint + " library does not define the " write + alien-error-symbol pprint " symbol." print ; : alien-invoke ( ... return library function parameters -- ... ) #! Call a C library function. @@ -93,7 +86,7 @@ C: alien-node make-node ; : incr-param ( reg-class -- ) #! OS X is so ugly. - dup class [ 1 + ] change dup float-regs? [ + dup class inc dup float-regs? [ os "macosx" = [ int-regs [ swap float-regs-size 4 / + ] change ] [ @@ -137,6 +130,23 @@ M: alien-node linearize-node* ( node -- ) [ dup parameters stack-space %cleanup , ] unless linearize-return ; +: unpair ( seq -- odds evens ) + 2 swap group flip dup empty? + [ drop { } { } ] [ first2 ] ifte ; + +: parse-arglist ( lst -- types stack effect ) + unpair [ + " " % [ "," ?tail drop % " " % ] each "-- " % + ] "" make ; + +: (define-c-word) ( type lib func types stack-effect -- ) + >r over create-in >r + [ alien-invoke ] cons cons cons cons r> swap define-compound + word r> "stack-effect" set-word-prop ; + +: define-c-word ( type lib func function-args -- ) + [ "()" subseq? not ] subset parse-arglist (define-c-word) ; + \ alien-invoke [ [ string object string general-list ] [ ] ] "infer-effect" set-word-prop @@ -149,5 +159,13 @@ M: alien-node linearize-node* ( node -- ) ] "infer" set-word-prop global [ - "libraries" get [ "libraries" set ] unless + "libraries" get [ {{ }} clone "libraries" set ] unless ] bind + +M: compound (uncrossref) + dup word-def \ alien-invoke swap member? [ + drop + ] [ + dup { "infer-effect" "base-case" "no-effect" } + reset-props update-xt + ] ifte ; diff --git a/library/alien/enums.factor b/library/alien/enums.factor deleted file mode 100644 index dff5314cbe..0000000000 --- a/library/alien/enums.factor +++ /dev/null @@ -1,23 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: alien -USING: kernel lists math parser words ; - -: BEGIN-ENUM: - #! C-style enumerations. Their use is not encouraged unless - #! it is for C library interfaces. Used like this: - #! - #! BEGIN-ENUM 0 - #! ENUM: x - #! ENUM: y - #! ENUM: z - #! END-ENUM - #! - #! This is the same as : x 0 ; : y 1 ; : z 2 ;. - scan str>number ; parsing - -: ENUM: - dup CREATE swap unit define-compound 1 + ; parsing - -: END-ENUM - drop ; parsing diff --git a/library/alien/structs.factor b/library/alien/structs.factor index 35311dd35c..42c8d29088 100644 --- a/library/alien/structs.factor +++ b/library/alien/structs.factor @@ -38,21 +38,3 @@ math namespaces parser sequences strings words ; ] "struct-name" get define-c-type "struct-name" get "in" get init-c-type ; - -: BEGIN-STRUCT: ( -- offset ) - scan "struct-name" set 0 ; parsing - -: FIELD: ( offset -- offset ) - scan scan define-field ; parsing - -: END-STRUCT ( length -- ) - define-struct-type ; parsing - -: BEGIN-UNION: ( -- max ) - scan "struct-name" set 0 ; parsing - -: MEMBER: ( max -- max ) - scan define-member ; parsing - -: END-UNION ( max -- ) - define-struct-type ; parsing diff --git a/library/alien/syntax.factor b/library/alien/syntax.factor index 9283db2f91..610b808b5e 100644 --- a/library/alien/syntax.factor +++ b/library/alien/syntax.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2005 Alex Chapman. ! See http://factor.sf.net/license.txt for BSD license. IN: alien -USING: compiler kernel lists namespaces parser sequences words ; +USING: compiler kernel lists math namespaces parser +sequences words ; ! usage of 'LIBRARY:' and 'FUNCTION:' : ! @@ -22,19 +23,6 @@ USING: compiler kernel lists namespaces parser sequences words ; : LIBRARY: scan "c-library" set ; parsing -: parse-arglist ( lst -- types stack effect ) - unpair [ - " " % [ "," ?tail drop % " " % ] each "-- " % - ] make-string ; - -: (define-c-word) ( type lib func types stack-effect -- ) - >r over create-in >r - [ alien-invoke ] cons cons cons cons r> swap define-compound - word r> "stack-effect" set-word-prop ; - -: define-c-word ( type lib func function-args -- ) - [ "()" subseq? not ] subset parse-arglist (define-c-word) ; - : FUNCTION: scan "c-library" get scan string-mode on [ string-mode off define-c-word ] [ ] ; parsing @@ -43,4 +31,39 @@ USING: compiler kernel lists namespaces parser sequences words ; #! TYPEDEF: old new scan scan typedef ; parsing -: DLL" skip-blank parse-string dlopen swons ; parsing +: BEGIN-STRUCT: ( -- offset ) + scan "struct-name" set 0 ; parsing + +: FIELD: ( offset -- offset ) + scan scan define-field ; parsing + +: END-STRUCT ( length -- ) + define-struct-type ; parsing + +: BEGIN-UNION: ( -- max ) + scan "struct-name" set 0 ; parsing + +: MEMBER: ( max -- max ) + scan define-member ; parsing + +: END-UNION ( max -- ) + define-struct-type ; parsing + +: BEGIN-ENUM: + #! C-style enumerations. Their use is not encouraged unless + #! it is for C library interfaces. Used like this: + #! + #! BEGIN-ENUM 0 + #! ENUM: x + #! ENUM: y + #! ENUM: z + #! END-ENUM + #! + #! This is the same as : x 0 ; : y 1 ; : z 2 ;. + scan string>number ; parsing + +: ENUM: + dup CREATE swap unit define-compound 1 + ; parsing + +: END-ENUM + drop ; parsing diff --git a/library/bootstrap/boot-stage1.factor b/library/bootstrap/boot-stage1.factor index 8d16275738..c82cdb2034 100644 --- a/library/bootstrap/boot-stage1.factor +++ b/library/bootstrap/boot-stage1.factor @@ -1,51 +1,60 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: image -USING: generic hashtables kernel lists math memory namespaces -parser prettyprint sequences io vectors words ; +USING: generic hashtables kernel kernel-internals +lists math memory namespaces parser prettyprint +sequences io vectors words ; "Bootstrap stage 1..." print "/library/bootstrap/primitives.factor" run-resource -: pull-in ( list -- ) [ dup print parse-resource % ] each ; - -! The make-list form creates a boot quotation +! The [ ] make form creates a boot quotation [ [ + [ hashtable? ] instances + [ dup hash-size 1 max swap set-bucket-count ] each + + boot + ] % + + { "/version.factor" - "/library/stack.factor" - "/library/combinators.factor" + "/library/generic/early-generic.factor" + + "/library/kernel.factor" "/library/collections/sequences.factor" "/library/collections/arrays.factor" - "/library/kernel.factor" - "/library/math/math.factor" "/library/math/integer.factor" "/library/math/ratio.factor" "/library/math/float.factor" "/library/math/complex.factor" + "/library/math/random.factor" "/library/collections/growable.factor" "/library/collections/cons.factor" - "/library/collections/vectors.factor" + "/library/collections/virtual-sequences.factor" "/library/collections/sequences-epilogue.factor" "/library/collections/strings.factor" "/library/collections/sbuf.factor" "/library/collections/assoc.factor" "/library/collections/lists.factor" + "/library/collections/vectors.factor" "/library/collections/hashtables.factor" "/library/collections/namespaces.factor" - "/library/collections/vectors-epilogue.factor" "/library/collections/sequence-eq.factor" "/library/collections/slicing.factor" + "/library/collections/sequence-sort.factor" "/library/collections/strings-epilogue.factor" "/library/collections/tree-each.factor" + "/library/collections/queues.factor" "/library/math/matrices.factor" + "/library/math/parse-numbers.factor" "/library/words.factor" "/library/vocabularies.factor" @@ -60,41 +69,67 @@ parser prettyprint sequences io vectors words ; "/library/io/string-streams.factor" "/library/io/c-streams.factor" "/library/io/files.factor" + "/library/io/binary.factor" - "/library/threads.factor" - - "/library/syntax/parse-numbers.factor" "/library/syntax/parse-words.factor" "/library/syntax/parse-errors.factor" "/library/syntax/parser.factor" "/library/syntax/parse-stream.factor" + + "/library/generic/generic.factor" + "/library/generic/standard-combination.factor" + "/library/generic/slots.factor" + "/library/generic/math-combination.factor" + "/library/generic/predicate.factor" + "/library/generic/union.factor" + "/library/generic/complement.factor" + "/library/generic/tuple.factor" + "/library/syntax/generic.factor" - "/library/syntax/math.factor" "/library/syntax/parse-syntax.factor" "/library/alien/aliens.factor" - "/library/syntax/unparser.factor" "/library/syntax/prettyprint.factor" - "/library/tools/gensym.factor" + "/library/io/logging.factor" + "/library/tools/interpreter.factor" "/library/tools/debugger.factor" "/library/tools/memory.factor" + "/library/tools/listener.factor" + "/library/tools/walker.factor" + "/library/tools/jedit.factor" + "/library/tools/annotations.factor" + "/library/tools/inspector.factor" + + "/library/test/test.factor" + + "/library/syntax/see.factor" + + "/library/threads.factor" + + "/library/tools/telnetd.factor" + + "/library/bootstrap/image.factor" - "/library/inference/conditions.factor" "/library/inference/dataflow.factor" - "/library/inference/values.factor" "/library/inference/inference.factor" "/library/inference/branches.factor" "/library/inference/words.factor" - "/library/inference/stack.factor" - "/library/inference/partial-eval.factor" + "/library/inference/recursive-values.factor" + "/library/inference/class-infer.factor" + "/library/inference/kill-literals.factor" + "/library/inference/split-nodes.factor" + "/library/inference/optimizer.factor" + "/library/inference/inline-methods.factor" + "/library/inference/known-words.factor" + "/library/inference/call-optimizers.factor" + "/library/inference/print-dataflow.factor" "/library/compiler/assembler.factor" "/library/compiler/relocate.factor" "/library/compiler/xt.factor" - "/library/compiler/optimizer.factor" "/library/compiler/vops.factor" "/library/compiler/linearizer.factor" "/library/compiler/intrinsics.factor" @@ -103,82 +138,23 @@ parser prettyprint sequences io vectors words ; "/library/compiler/compiler.factor" "/library/alien/c-types.factor" - "/library/alien/enums.factor" "/library/alien/structs.factor" "/library/alien/compiler.factor" "/library/alien/syntax.factor" "/library/cli.factor" - "/library/tools/memory.factor" - ] pull-in -] make-list - -"object" [ "generic" ] search -"typemap" [ "generic" ] search -"builtins" [ "generic" ] search - -vocabularies get [ "generic" off ] bind - -reveal -reveal -reveal - -[ - [ - boot - - "Rehashing hash tables..." print - - [ hashtable? ] instances - [ dup hash-size 1 max swap set-bucket-count ] each - - "Building cross-reference database..." print - - recrossref - ] % - - [ - "/library/generic/generic.factor" - "/library/generic/slots.factor" - "/library/generic/object.factor" - "/library/generic/null.factor" - "/library/generic/builtin.factor" - "/library/generic/predicate.factor" - "/library/generic/union.factor" - "/library/generic/complement.factor" - "/library/generic/tuple.factor" - "/library/bootstrap/init.factor" - ] pull-in - - [ - "Building generics..." print + } [ dup print parse-resource % ] each - all-words [ generic? ] subset [ make-generic ] each - ] % -] make-list - -swap - -[ - "/library/bootstrap/boot-stage2.factor" run-resource -] - -append3 + [ "/library/bootstrap/boot-stage2.factor" run-resource ] % +] [ ] make vocabularies get [ "!syntax" get "syntax" set - "syntax" get [ - cdr dup word? [ - "syntax" "vocabulary" set-word-prop - ] [ - drop - ] ifte - ] hash-each + "syntax" get hash-values [ word? ] subset + [ "syntax" swap set-word-vocabulary ] each ] bind "!syntax" vocabularies get remove-hash - -FORGET: pull-in diff --git a/library/bootstrap/boot-stage2.factor b/library/bootstrap/boot-stage2.factor index e2fca26979..2e7e4ad1ce 100644 --- a/library/bootstrap/boot-stage2.factor +++ b/library/bootstrap/boot-stage2.factor @@ -1,11 +1,10 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. -USING: alien assembler command-line compiler generic hashtables -kernel lists memory namespaces parser sequences io unparser +USING: alien assembler command-line compiler compiler-backend +errors generic hashtables io io-internals kernel +kernel-internals lists math memory namespaces parser sequences words ; -\ fiber? t "inline" set-word-prop - : pull-in ( ? list -- ) swap [ [ @@ -35,4 +34,123 @@ cpu "ppc" = [ "/library/compiler/ppc/alien.factor" ] pull-in -"/library/bootstrap/boot-stage3.factor" run-resource +"statically-linked" get [ + unix? [ + "sdl" "libSDL.so" "cdecl" add-library + "sdl-gfx" "libSDL_gfx.so" "cdecl" add-library + "sdl-ttf" "libSDL_ttf.so" "cdecl" add-library + ] when + + win32? [ + "kernel32" "kernel32.dll" "stdcall" add-library + "user32" "user32.dll" "stdcall" add-library + "gdi32" "gdi32.dll" "stdcall" add-library + "winsock" "ws2_32.dll" "stdcall" add-library + "mswsock" "mswsock.dll" "stdcall" add-library + "libc" "msvcrt.dll" "cdecl" add-library + "sdl" "SDL.dll" "cdecl" add-library + "sdl-gfx" "SDL_gfx.dll" "cdecl" add-library + "sdl-ttf" "SDL_ttf.dll" "cdecl" add-library + ] when +] unless + +"Loading more library code..." print + +t [ + "/library/alien/malloc.factor" + "/library/io/buffer.factor" + + "/library/math/constants.factor" + "/library/math/pow.factor" + "/library/math/trig-hyp.factor" + "/library/math/arc-trig-hyp.factor" + + "/library/httpd/load.factor" + "/library/sdl/load.factor" + "/library/ui/load.factor" + "/library/help/tutorial.factor" +] pull-in + +: compile? "compile" get supported-cpu? and ; + +compile? [ + "Compiling base..." print + + [ car * = string>number number>string scan (generate) ] + [ compile ] + each +] when + +compile? [ + unix? [ + "/library/unix/types.factor" + ] pull-in + + os "freebsd" = [ + "/library/unix/syscalls-freebsd.factor" + ] pull-in + + os "linux" = [ + "/library/unix/syscalls-linux.factor" + ] pull-in + + os "macosx" = [ + "/library/unix/syscalls-macosx.factor" + ] pull-in + + unix? [ + "/library/unix/syscalls.factor" + "/library/unix/io.factor" + "/library/unix/sockets.factor" + "/library/unix/files.factor" + ] pull-in + + os "win32" = [ + "/library/win32/win32-io.factor" + "/library/win32/win32-errors.factor" + "/library/win32/winsock.factor" + "/library/win32/win32-io-internals.factor" + "/library/win32/win32-stream.factor" + "/library/win32/win32-server.factor" + "/library/bootstrap/win32-io.factor" + ] pull-in +] when + +"Building cross-reference database..." print +recrossref + +compile? [ + "Compiling system..." print + compile-all + terpri + "Unless you're working on the compiler, ignore the errors above." print + "Not every word compiles, by design." print + terpri + "Initializing native I/O..." print + init-io +] when + +[ + boot + run-user-init + "shell" get [ "shells" ] search execute + 0 exit +] set-boot + +0 [ compiled? [ 1 + ] when ] each-word +number>string write " words compiled" print + +0 [ drop 1 + ] each-word +number>string write " words total" print + +"Total bootstrap GC time: " write gc-time +number>string write " ms" print + +"Bootstrapping is complete." print +"Now, you can run ./f factor.image" print + +"factor.image" save-image +0 exit + +FORGET: pull-in +FORGET: compile? diff --git a/library/bootstrap/boot-stage3.factor b/library/bootstrap/boot-stage3.factor deleted file mode 100644 index ddf07d26c4..0000000000 --- a/library/bootstrap/boot-stage3.factor +++ /dev/null @@ -1,131 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -USING: alien assembler command-line compiler compiler-backend -compiler-frontend io-internals kernel lists math namespaces -parser sequences io unparser words ; - -"Compiling base..." print - -unix? [ - "sdl" "libSDL.so" "cdecl" add-library - "sdl-gfx" "libSDL_gfx.so" "cdecl" add-library - "sdl-ttf" "libSDL_ttf.so" "cdecl" add-library -] when - -win32? [ - "kernel32" "kernel32.dll" "stdcall" add-library - "user32" "user32.dll" "stdcall" add-library - "gdi32" "gdi32.dll" "stdcall" add-library - "winsock" "ws2_32.dll" "stdcall" add-library - "mswsock" "mswsock.dll" "stdcall" add-library - "libc" "msvcrt.dll" "cdecl" add-library - "sdl" "SDL.dll" "cdecl" add-library - "sdl-gfx" "SDL_gfx.dll" "cdecl" add-library - "sdl-ttf" "SDL_ttf.dll" "cdecl" add-library -] when - -default-cli-args -parse-command-line -init-assembler - -: compile? "compile" get supported-cpu? and ; - -"library/inference/branches.factor" run-file - -compile? [ - \ car compile - \ * compile - \ length compile - \ = compile - \ unparse compile - \ scan compile - \ optimize compile - \ (generate) compile -] when - -"Loading more library code..." print - -t [ - "/library/alien/malloc.factor" - "/library/io/buffer.factor" - - "/library/math/constants.factor" - "/library/math/pow.factor" - "/library/math/more-matrices.factor" - "/library/math/trig-hyp.factor" - "/library/math/arc-trig-hyp.factor" - "/library/math/random.factor" - - "/library/in-thread.factor" - - "/library/io/directories.factor" - "/library/io/binary.factor" - - "/library/eval-catch.factor" - "/library/tools/listener.factor" - "/library/tools/word-tools.factor" - "/library/syntax/see.factor" - "/library/test/test.factor" - "/library/inference/test.factor" - "/library/tools/walker.factor" - "/library/tools/annotations.factor" - "/library/tools/inspector.factor" - "/library/bootstrap/image.factor" - - "/library/io/logging.factor" - - "/library/tools/telnetd.factor" - "/library/tools/jedit.factor" - - "/library/httpd/load.factor" - "/library/sdl/load.factor" - "/library/ui/load.factor" - "/library/help/tutorial.factor" -] pull-in - -compile? [ - unix? [ - "/library/unix/types.factor" - ] pull-in - - os "freebsd" = [ - "/library/unix/syscalls-freebsd.factor" - ] pull-in - - os "linux" = [ - "/library/unix/syscalls-linux.factor" - ] pull-in - - os "macosx" = [ - "/library/unix/syscalls-macosx.factor" - ] pull-in - - unix? [ - "/library/unix/syscalls.factor" - "/library/unix/io.factor" - "/library/unix/sockets.factor" - "/library/unix/files.factor" - ] pull-in - - os "win32" = [ - "/library/win32/win32-io.factor" - "/library/win32/win32-errors.factor" - "/library/win32/winsock.factor" - "/library/win32/win32-io-internals.factor" - "/library/win32/win32-stream.factor" - "/library/win32/win32-server.factor" - "/library/bootstrap/win32-io.factor" - ] pull-in -] when - -compile? [ - "Compiling system..." print - compile-all - "Initializing native I/O..." print - init-io -] when - -FORGET: pull-in -FORGET: compile? - -"/library/bootstrap/boot-stage4.factor" dup print run-resource diff --git a/library/bootstrap/boot-stage4.factor b/library/bootstrap/boot-stage4.factor deleted file mode 100644 index 96809a3b1a..0000000000 --- a/library/bootstrap/boot-stage4.factor +++ /dev/null @@ -1,54 +0,0 @@ -! Copyright (C) 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: kernel -USING: alien assembler command-line compiler console errors -generic inference kernel-internals listener lists math memory -namespaces parser presentation prettyprint random io -unparser words ; - -"Bootstrap stage 4..." print - -: warm-boot ( -- ) - #! A fully bootstrapped image has this as the boot - #! quotation. - init-assembler - init-error-handler - default-cli-args - parse-command-line - "null-stdio" get [ << null-stream f >> stdio set ] when ; - -: shell ( str -- ) - #! This handles the -shell: cli argument. - [ "shells" ] search execute ; - -[ - boot - warm-boot - run-user-init - "shell" get shell - 0 exit -] set-boot - -warm-boot - -terpri -"Unless you're working on the compiler, ignore the errors above." print -"Not every word compiles, by design." print -terpri - -0 [ compiled? [ 1 + ] when ] each-word -unparse write " words compiled" print - -0 [ drop 1 + ] each-word -unparse write " words total" print - -"Total bootstrap GC time: " write gc-time unparse write " ms" print - -"Bootstrapping is complete." print -"Now, you can run ./f factor.image" print - -! Save a bit of space -global [ stdio off ] bind - -"factor.image" save-image -0 exit diff --git a/library/bootstrap/image.factor b/library/bootstrap/image.factor index e50e211561..a01bd70bf8 100644 --- a/library/bootstrap/image.factor +++ b/library/bootstrap/image.factor @@ -8,25 +8,31 @@ ! generate the minimal image, and writing the cons cells, words, ! strings etc to the image file in the CFactor object memory ! format. -! -! What is a bootstrap image? It basically contains enough code -! to parse a source file. See platform/native/boot.factor -- -! It initializes the core interpreter services, and proceeds to -! run platform/native/boot-stage2.factor. IN: image USING: errors generic hashtables kernel lists math namespaces parser prettyprint sequences sequences io strings vectors words ; +! If true in current namespace, we are bootstrapping. +SYMBOL: bootstrapping? + ! The image being constructed; a vector of word-size integers SYMBOL: image -! Boot quotation, set by boot.factor -SYMBOL: boot-quot +! Object cache +SYMBOL: objects + +! Image output format +SYMBOL: big-endian +SYMBOL: 64-bits + +SYMBOL: t-object : emit ( cell -- ) image get push ; +: emit-seq ( seq -- ) image get swap nappend ; + : fixup ( value offset -- ) image get set-nth ; ( Object memory ) @@ -34,8 +40,8 @@ SYMBOL: boot-quot : image-magic HEX: 0f0e0d0c ; : image-version 0 ; -: cell "64-bits" get 8 4 ? ; -: char "64-bits" get 4 2 ? ; +: cell 64-bits get 8 4 ? ; +: char 64-bits get 4 2 ? ; : untag ( cell tag -- ) tag-mask bitnot bitand ; : tag ( cell -- tag ) tag-mask bitand ; @@ -45,6 +51,7 @@ SYMBOL: boot-quot : hashtable-type 10 ; inline : vector-type 11 ; inline : string-type 12 ; inline +: wrapper-type 14 ; inline : word-type 17 ; inline : tuple-type 18 ; inline @@ -53,12 +60,7 @@ SYMBOL: boot-quot ( Image header ) -: base - #! We relocate the image to after the header, and leaving - #! some empty cells. This lets us differentiate an F pointer - #! (0/tag 3) from a pointer to the first object in the - #! image. - 64 cell * ; +: base 1024 ; : header ( -- ) image-magic emit @@ -95,14 +97,6 @@ GENERIC: ' ( obj -- ptr ) : align-here ( -- ) here 8 mod 4 = [ 0 emit ] when ; -( Remember what objects we've compiled ) - -: pooled-object ( object -- pointer ) - "objects" get hash ; - -: pool-object ( object pointer -- ) - swap "objects" get set-hash ; - ( Fixnums ) : emit-fixnum ( n -- ) fixnum-tag immediate emit ; @@ -115,11 +109,11 @@ M: bignum ' ( bignum -- tagged ) #! This can only emit 0, -1 and 1. bignum-tag here-as >r bignum-tag >header emit - [ + {{ [[ 0 [ 1 0 ] ]] [[ -1 [ 2 1 1 ] ]] [[ 1 [ 2 0 1 ] ]] - ] assoc unswons emit-fixnum [ emit ] each align-here r> ; + }} hash unswons emit-fixnum emit-seq align-here r> ; ( Special objects ) @@ -127,11 +121,11 @@ M: bignum ' ( bignum -- tagged ) : t, object-tag here-as - dup t-offset fixup "t" set + dup t-offset fixup t-object set t-type >header emit 0 ' emit ; -M: t ' ( obj -- ptr ) drop "t" get ; +M: t ' ( obj -- ptr ) drop t-object get ; M: f ' ( obj -- ptr ) #! f is #define F RETAG(0,OBJECT_TYPE) drop object-tag ; @@ -148,37 +142,49 @@ M: f ' ( obj -- ptr ) ( Words ) -: word, ( word -- ) - [ - word-type >header , - dup hashcode fixnum-tag immediate , - 0 , - dup word-primitive , - dup word-def ' , - dup word-props ' , - ] make-list - swap object-tag here-as pool-object - [ emit ] each ; +: emit-word ( word -- ) + dup word-props ' >r + dup word-def ' >r + dup word-primitive ' >r + dup word-vocabulary ' >r + dup word-name ' >r + object-tag here-as over objects get set-hash + word-type >header emit + hashcode emit-fixnum + r> emit + r> emit + r> emit + r> emit + r> emit + 0 emit ; : word-error ( word msg -- ) - [ % dup word-vocabulary % " " % word-name % ] make-string - throw ; + [ % dup word-vocabulary % " " % word-name % ] "" make + throw ; inline : transfer-word ( word -- word ) #! This is a hack. See doc/bootstrap.txt. - dup dup word-name swap word-vocabulary unit search + dup dup word-name swap word-vocabulary lookup [ ] [ dup "Missing DEFER: " word-error ] ?ifte ; +: pooled-object ( object -- ptr ) objects get hash ; + : fixup-word ( word -- offset ) - dup pooled-object [ ] [ "Not in image: " word-error ] ?ifte ; + transfer-word dup pooled-object dup + [ nip ] [ "Not in image: " word-error ] ifte ; : fixup-words ( -- ) - image get [ - dup word? [ fixup-word ] when - ] map image set ; + image get [ dup word? [ fixup-word ] when ] nmap ; -M: word ' ( word -- pointer ) - transfer-word dup pooled-object dup [ nip ] [ drop ] ifte ; +M: word ' ( word -- pointer ) ; + +( Wrappers ) + +M: wrapper ' ( wrapper -- pointer ) + wrapped ' + object-tag here-as >r + wrapper-type >header emit + emit r> ; ( Conses ) @@ -189,37 +195,25 @@ M: cons ' ( c -- tagged ) ( Strings ) -: align-string ( n str -- ) - tuck length - CHAR: \0 fill append ; +: emit-chars ( seq -- ) + big-endian get [ [ reverse ] map ] unless + [ 0 [ swap 16 shift + ] reduce emit ] each ; -: emit-chars ( str -- ) - "big-endian" get [ reverse ] unless - 0 swap [ swap 16 shift + ] each emit ; +: pack-string ( string -- seq ) + dup length 1 + char align CHAR: \0 pad-right char swap group ; -: (pack-string) ( n list -- ) - #! Emit bytes for a string, with n characters per word. - [ - 2dup length > [ dupd align-string ] when - emit-chars - ] each drop ; - -: pack-string ( string -- ) - char tuck swap group (pack-string) ; - -: emit-string ( string -- ) +: emit-string ( string -- ptr ) object-tag here-as swap string-type >header emit dup length emit-fixnum dup hashcode emit-fixnum - "\0" append pack-string + pack-string emit-chars align-here ; M: string ' ( string -- pointer ) #! We pool strings so that each string is only written once #! to the image - dup pooled-object [ ] [ - dup emit-string dup >r pool-object r> - ] ?ifte ; + objects get [ emit-string ] cache ; ( Arrays and vectors ) @@ -228,13 +222,13 @@ M: string ' ( string -- pointer ) object-tag here-as >r >header emit dup length emit-fixnum - ( elements -- ) [ emit ] each + ( elements -- ) emit-seq align-here r> ; M: tuple ' ( tuple -- pointer ) tuple-type emit-array ; -: emit-vector ( vector -- pointer ) +M: vector ' ( vector -- pointer ) dup array-type emit-array swap length object-tag here-as >r vector-type >header emit @@ -242,94 +236,83 @@ M: tuple ' ( tuple -- pointer ) emit ( array ptr ) align-here r> ; -M: vector ' ( vector -- pointer ) - emit-vector ; +( Hashes ) -: emit-hashtable ( hash -- pointer ) - dup buckets>list array-type emit-array - swap hash>alist length +M: hashtable ' ( hashtable -- pointer ) + dup buckets>vector array-type emit-array + swap hash-size object-tag here-as >r hashtable-type >header emit emit-fixnum ( length ) emit ( array ptr ) align-here r> ; -M: hashtable ' ( hashtable -- pointer ) - #! Only hashtables are pooled, not vectors! - dup pooled-object [ ] [ - dup emit-hashtable [ pool-object ] keep - ] ?ifte ; - ( End of the image ) -: vocabulary, ( hash -- ) - dup hashtable? [ - [ cdr dup word? [ word, ] [ drop ] ifte ] hash-each - ] [ - drop - ] ifte ; - -: vocabularies, ( vocabularies -- ) - [ cdr vocabulary, ] hash-each ; +: words, ( -- ) + all-words [ emit-word ] each ; : global, ( -- ) - vocabularies get - dup vocabularies, - [ - vocabularies set - typemap [ ] change - builtins [ ] change - crossref [ ] change - ] extend ' + [ + { vocabularies typemap builtins } [ [ ] change ] each + ] make-hash ' global-offset fixup ; -: boot, ( quot -- ) - boot-quot get swap append ' boot-quot-offset fixup ; +: boot, ( quot -- ) ' boot-quot-offset fixup ; + +: heap-size image get length header-size - cell * ; : end ( quot -- ) + "Generating words..." print + words, + "Generating global namespace..." print global, + "Generating boot quotation..." print boot, + "Performing some word fixups..." print fixup-words - here base - heap-size-offset fixup ; + heap-size heap-size-offset fixup ; ( Image output ) : (write-image) ( image -- ) - "64-bits" get 8 4 ? swap "big-endian" get [ + 64-bits get 8 4 ? swap big-endian get [ [ swap >be write ] each-with ] [ [ swap >le write ] each-with ] ifte ; : write-image ( image file -- ) + "Writing image to " write dup write "..." print [ (write-image) ] with-stream ; -: with-minimal-image ( quot -- image ) +: with-image ( quot -- image ) [ - 300000 image set - "objects" set + bootstrapping? on + 800000 image set + 20000 objects set call + "Image length: " write image get length . + "Object cache size: " write objects get hash-size . image get ] with-scope ; -: with-image ( quot -- image ) - #! The quotation leaves a boot quotation on the stack. - [ begin call end ] with-minimal-image ; - : make-image ( name -- ) - #! Make an image for the C interpreter. + #! Make a bootstrap image. [ - boot-quot off + begin "/library/bootstrap/boot-stage1.factor" run-resource + namespace global [ "foobar" set ] bind + end ] with-image swap write-image ; : make-images ( -- ) - "64-bits" off - "big-endian" off "boot.image.le32" make-image - "big-endian" on "boot.image.be32" make-image - "64-bits" on - "big-endian" off "boot.image.le64" make-image - "big-endian" on "boot.image.be64" make-image - "64-bits" off ; + 64-bits off + big-endian off "boot.image.le32" make-image + big-endian on "boot.image.be32" make-image + 64-bits on + big-endian off "boot.image.le64" make-image + big-endian on "boot.image.be64" make-image + 64-bits off ; diff --git a/library/bootstrap/init.factor b/library/bootstrap/init.factor index ad568c73c7..61b5fdee4d 100644 --- a/library/bootstrap/init.factor +++ b/library/bootstrap/init.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. -IN: kernel -USING: io-internals namespaces parser io threads words ; +IN: kernel-internals +USING: assembler command-line errors io io-internals kernel +namespaces parser threads words ; : boot ( -- ) #! Initialize an interpreter with the basic services. @@ -9,4 +10,9 @@ USING: io-internals namespaces parser io threads words ; init-threads init-io "HOME" os-env [ "." ] unless* "~" set - init-search-path ; + init-search-path + init-assembler + init-error-handler + default-cli-args + parse-command-line + "null-stdio" get [ << null-stream f >> stdio set ] when ; diff --git a/library/bootstrap/primitives.factor b/library/bootstrap/primitives.factor index a73264b410..fa089c8af3 100644 --- a/library/bootstrap/primitives.factor +++ b/library/bootstrap/primitives.factor @@ -1,228 +1,332 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: image -USING: kernel lists math memory namespaces parser words vectors -hashtables generic alien assembler compiler errors files generic -io-internals kernel kernel-internals lists math math-internals -parser profiler strings unparser vectors words hashtables -sequences ; +USING: alien generic hashtables io kernel kernel-internals lists +math namespaces sequences strings vectors words ; -! This symbol needs the same hashcode in the target as in the +! Some very tricky code creating a bootstrap embryo in the +! host image. + +"Creating primitives and basic runtime structures..." print + +! These symbols need the same hashcode in the target as in the ! host. -vocabularies +{ vocabularies object null typemap builtins } ! Bring up a bare cross-compiling vocabulary. -"syntax" vocab clone -"generic" vocab clone +"syntax" vocab - vocabularies set - typemap set -num-types builtins set - crossref set +{{ }} clone vocabularies set +f crossref set -vocabularies get [ - "generic" set - "syntax" set - reveal -] bind +vocabularies get [ "syntax" set [ reveal ] each ] bind -: set-stack-effect ( [ vocab word effect ] -- ) - 3unlist >r unit search r> dup string? [ - "stack-effect" set-word-prop - ] [ - "infer-effect" set-word-prop - ] ifte ; +: make-primitive ( { vocab word } n -- ) + >r first2 create r> f define ; -: make-primitive ( n [ vocab word effect ] -- n ) - [ 2unlist create >r 1 + r> over f define ] keep - set-stack-effect ; +{ + { "execute" "words" } + { "call" "kernel" } + { "ifte" "kernel" } + { "dispatch" "kernel-internals" } + { "cons" "lists" } + { "" "vectors" } + { "rehash-string" "strings" } + { "" "strings" } + { "sbuf>string" "strings" } + { ">fixnum" "math" } + { ">bignum" "math" } + { ">float" "math" } + { "(fraction>)" "math-internals" } + { "string>float" "math-internals" } + { "float>string" "math-internals" } + { "float>bits" "math" } + { "double>bits" "math" } + { "bits>float" "math" } + { "bits>double" "math" } + { "" "math-internals" } + { "fixnum+" "math-internals" } + { "fixnum-" "math-internals" } + { "fixnum*" "math-internals" } + { "fixnum/i" "math-internals" } + { "fixnum/f" "math-internals" } + { "fixnum-mod" "math-internals" } + { "fixnum/mod" "math-internals" } + { "fixnum-bitand" "math-internals" } + { "fixnum-bitor" "math-internals" } + { "fixnum-bitxor" "math-internals" } + { "fixnum-bitnot" "math-internals" } + { "fixnum-shift" "math-internals" } + { "fixnum<" "math-internals" } + { "fixnum<=" "math-internals" } + { "fixnum>" "math-internals" } + { "fixnum>=" "math-internals" } + { "bignum=" "math-internals" } + { "bignum+" "math-internals" } + { "bignum-" "math-internals" } + { "bignum*" "math-internals" } + { "bignum/i" "math-internals" } + { "bignum/f" "math-internals" } + { "bignum-mod" "math-internals" } + { "bignum/mod" "math-internals" } + { "bignum-bitand" "math-internals" } + { "bignum-bitor" "math-internals" } + { "bignum-bitxor" "math-internals" } + { "bignum-bitnot" "math-internals" } + { "bignum-shift" "math-internals" } + { "bignum<" "math-internals" } + { "bignum<=" "math-internals" } + { "bignum>" "math-internals" } + { "bignum>=" "math-internals" } + { "float=" "math-internals" } + { "float+" "math-internals" } + { "float-" "math-internals" } + { "float*" "math-internals" } + { "float/f" "math-internals" } + { "float<" "math-internals" } + { "float<=" "math-internals" } + { "float>" "math-internals" } + { "float>=" "math-internals" } + { "facos" "math-internals" } + { "fasin" "math-internals" } + { "fatan" "math-internals" } + { "fatan2" "math-internals" } + { "fcos" "math-internals" } + { "fexp" "math-internals" } + { "fcosh" "math-internals" } + { "flog" "math-internals" } + { "fpow" "math-internals" } + { "fsin" "math-internals" } + { "fsinh" "math-internals" } + { "fsqrt" "math-internals" } + { "" "words" } + { "update-xt" "words" } + { "compiled?" "words" } + { "drop" "kernel" } + { "dup" "kernel" } + { "swap" "kernel" } + { "over" "kernel" } + { "pick" "kernel" } + { ">r" "kernel" } + { "r>" "kernel" } + { "eq?" "kernel" } + { "getenv" "kernel-internals" } + { "setenv" "kernel-internals" } + { "stat" "io" } + { "(directory)" "io" } + { "gc" "memory" } + { "gc-time" "memory" } + { "save-image" "memory" } + { "datastack" "kernel" } + { "callstack" "kernel" } + { "set-datastack" "kernel" } + { "set-callstack" "kernel" } + { "exit" "kernel" } + { "room" "memory" } + { "os-env" "kernel" } + { "millis" "kernel" } + { "(random-int)" "math" } + { "type" "kernel" } + { "tag" "kernel-internals" } + { "cwd" "io" } + { "cd" "io" } + { "compiled-offset" "assembler" } + { "set-compiled-offset" "assembler" } + { "literal-top" "assembler" } + { "set-literal-top" "assembler" } + { "address" "memory" } + { "dlopen" "alien" } + { "dlsym" "alien" } + { "dlclose" "alien" } + { "" "alien" } + { "" "kernel-internals" } + { "" "alien" } + { "alien-signed-cell" "alien" } + { "set-alien-signed-cell" "alien" } + { "alien-unsigned-cell" "alien" } + { "set-alien-unsigned-cell" "alien" } + { "alien-signed-8" "alien" } + { "set-alien-signed-8" "alien" } + { "alien-unsigned-8" "alien" } + { "set-alien-unsigned-8" "alien" } + { "alien-signed-4" "alien" } + { "set-alien-signed-4" "alien" } + { "alien-unsigned-4" "alien" } + { "set-alien-unsigned-4" "alien" } + { "alien-signed-2" "alien" } + { "set-alien-signed-2" "alien" } + { "alien-unsigned-2" "alien" } + { "set-alien-unsigned-2" "alien" } + { "alien-signed-1" "alien" } + { "set-alien-signed-1" "alien" } + { "alien-unsigned-1" "alien" } + { "set-alien-unsigned-1" "alien" } + { "alien-float" "alien" } + { "set-alien-float" "alien" } + { "alien-double" "alien" } + { "set-alien-double" "alien" } + { "alien-c-string" "alien" } + { "set-alien-c-string" "alien" } + { "throw" "errors" } + { "string>memory" "kernel-internals" } + { "memory>string" "kernel-internals" } + { "alien-address" "alien" } + { "slot" "kernel-internals" } + { "set-slot" "kernel-internals" } + { "integer-slot" "kernel-internals" } + { "set-integer-slot" "kernel-internals" } + { "char-slot" "kernel-internals" } + { "set-char-slot" "kernel-internals" } + { "resize-array" "kernel-internals" } + { "resize-string" "strings" } + { "" "hashtables" } + { "" "kernel-internals" } + { "" "kernel-internals" } + { "begin-scan" "memory" } + { "next-object" "memory" } + { "end-scan" "memory" } + { "size" "memory" } + { "die" "kernel" } + { "flush-icache" "assembler" } + { "fopen" "io-internals" } + { "fgetc" "io-internals" } + { "fwrite" "io-internals" } + { "fflush" "io-internals" } + { "fclose" "io-internals" } + { "expired?" "alien" } + { "" "kernel" } +} dup length 3 swap [ + ] map-with [ make-primitive ] 2each -2 [ - [ "execute" "words" [ [ word ] [ ] ] ] - [ "call" "kernel" [ [ general-list ] [ ] ] ] - [ "ifte" "kernel" [ [ object general-list general-list ] [ ] ] ] - [ "dispatch" "kernel-internals" [ [ fixnum vector ] [ ] ] ] - [ "cons" "lists" [ [ object object ] [ cons ] ] ] - [ "" "vectors" [ [ integer ] [ vector ] ] ] - [ "rehash-string" "strings" [ [ string ] [ ] ] ] - [ "" "strings" [ [ integer ] [ sbuf ] ] ] - [ "sbuf>string" "strings" [ [ sbuf ] [ string ] ] ] - [ "arithmetic-type" "math-internals" [ [ object object ] [ object object fixnum ] ] ] - [ ">fixnum" "math" [ [ number ] [ fixnum ] ] ] - [ ">bignum" "math" [ [ number ] [ bignum ] ] ] - [ ">float" "math" [ [ number ] [ float ] ] ] - [ "(fraction>)" "math-internals" [ [ integer integer ] [ rational ] ] ] - [ "str>float" "parser" [ [ string ] [ float ] ] ] - [ "(unparse-float)" "unparser" [ [ float ] [ string ] ] ] - [ "float>bits" "math" [ [ real ] [ integer ] ] ] - [ "double>bits" "math" [ [ real ] [ integer ] ] ] - [ "bits>float" "math" [ [ integer ] [ float ] ] ] - [ "bits>double" "math" [ [ integer ] [ float ] ] ] - [ "" "math-internals" [ [ real real ] [ number ] ] ] - [ "fixnum+" "math-internals" [ [ fixnum fixnum ] [ integer ] ] ] - [ "fixnum-" "math-internals" [ [ fixnum fixnum ] [ integer ] ] ] - [ "fixnum*" "math-internals" [ [ fixnum fixnum ] [ integer ] ] ] - [ "fixnum/i" "math-internals" [ [ fixnum fixnum ] [ integer ] ] ] - [ "fixnum/f" "math-internals" [ [ fixnum fixnum ] [ integer ] ] ] - [ "fixnum-mod" "math-internals" [ [ fixnum fixnum ] [ fixnum ] ] ] - [ "fixnum/mod" "math-internals" [ [ fixnum fixnum ] [ integer fixnum ] ] ] - [ "fixnum-bitand" "math-internals" [ [ fixnum fixnum ] [ fixnum ] ] ] - [ "fixnum-bitor" "math-internals" [ [ fixnum fixnum ] [ fixnum ] ] ] - [ "fixnum-bitxor" "math-internals" [ [ fixnum fixnum ] [ fixnum ] ] ] - [ "fixnum-bitnot" "math-internals" [ [ fixnum ] [ fixnum ] ] ] - [ "fixnum-shift" "math-internals" [ [ fixnum fixnum ] [ fixnum ] ] ] - [ "fixnum<" "math-internals" [ [ fixnum fixnum ] [ boolean ] ] ] - [ "fixnum<=" "math-internals" [ [ fixnum fixnum ] [ boolean ] ] ] - [ "fixnum>" "math-internals" [ [ fixnum fixnum ] [ boolean ] ] ] - [ "fixnum>=" "math-internals" [ [ fixnum fixnum ] [ boolean ] ] ] - [ "bignum=" "math-internals" [ [ bignum bignum ] [ boolean ] ] ] - [ "bignum+" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum-" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum*" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum/i" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum/f" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum-mod" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum/mod" "math-internals" [ [ bignum bignum ] [ bignum bignum ] ] ] - [ "bignum-bitand" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum-bitor" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum-bitxor" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum-bitnot" "math-internals" [ [ bignum ] [ bignum ] ] ] - [ "bignum-shift" "math-internals" [ [ bignum bignum ] [ bignum ] ] ] - [ "bignum<" "math-internals" [ [ bignum bignum ] [ boolean ] ] ] - [ "bignum<=" "math-internals" [ [ bignum bignum ] [ boolean ] ] ] - [ "bignum>" "math-internals" [ [ bignum bignum ] [ boolean ] ] ] - [ "bignum>=" "math-internals" [ [ bignum bignum ] [ boolean ] ] ] - [ "float=" "math-internals" [ [ bignum bignum ] [ boolean ] ] ] - [ "float+" "math-internals" [ [ float float ] [ float ] ] ] - [ "float-" "math-internals" [ [ float float ] [ float ] ] ] - [ "float*" "math-internals" [ [ float float ] [ float ] ] ] - [ "float/f" "math-internals" [ [ float float ] [ float ] ] ] - [ "float<" "math-internals" [ [ float float ] [ boolean ] ] ] - [ "float<=" "math-internals" [ [ float float ] [ boolean ] ] ] - [ "float>" "math-internals" [ [ float float ] [ boolean ] ] ] - [ "float>=" "math-internals" [ [ float float ] [ boolean ] ] ] - [ "facos" "math-internals" [ [ real ] [ float ] ] ] - [ "fasin" "math-internals" [ [ real ] [ float ] ] ] - [ "fatan" "math-internals" [ [ real ] [ float ] ] ] - [ "fatan2" "math-internals" [ [ real real ] [ float ] ] ] - [ "fcos" "math-internals" [ [ real ] [ float ] ] ] - [ "fexp" "math-internals" [ [ real ] [ float ] ] ] - [ "fcosh" "math-internals" [ [ real ] [ float ] ] ] - [ "flog" "math-internals" [ [ real ] [ float ] ] ] - [ "fpow" "math-internals" [ [ real real ] [ float ] ] ] - [ "fsin" "math-internals" [ [ real ] [ float ] ] ] - [ "fsinh" "math-internals" [ [ real ] [ float ] ] ] - [ "fsqrt" "math-internals" [ [ real ] [ float ] ] ] - [ "" "words" [ [ ] [ word ] ] ] - [ "update-xt" "words" [ [ word ] [ ] ] ] - [ "compiled?" "words" [ [ word ] [ boolean ] ] ] - [ "drop" "kernel" [ [ object ] [ ] ] ] - [ "dup" "kernel" [ [ object ] [ object object ] ] ] - [ "swap" "kernel" [ [ object object ] [ object object ] ] ] - [ "over" "kernel" [ [ object object ] [ object object object ] ] ] - [ "pick" "kernel" [ [ object object object ] [ object object object object ] ] ] - [ ">r" "kernel" [ [ object ] [ ] ] ] - [ "r>" "kernel" [ [ ] [ object ] ] ] - [ "eq?" "kernel" [ [ object object ] [ boolean ] ] ] - [ "getenv" "kernel-internals" [ [ fixnum ] [ object ] ] ] - [ "setenv" "kernel-internals" [ [ object fixnum ] [ ] ] ] - [ "stat" "io" [ [ string ] [ general-list ] ] ] - [ "(directory)" "io" [ [ string ] [ general-list ] ] ] - [ "gc" "memory" [ [ fixnum ] [ ] ] ] - [ "gc-time" "memory" [ [ string ] [ ] ] ] - [ "save-image" "memory" [ [ string ] [ ] ] ] - [ "datastack" "kernel" " -- ds " ] - [ "callstack" "kernel" " -- cs " ] - [ "set-datastack" "kernel" " ds -- " ] - [ "set-callstack" "kernel" " cs -- " ] - [ "exit" "kernel" [ [ integer ] [ ] ] ] - [ "room" "memory" [ [ ] [ integer integer integer integer general-list ] ] ] - [ "os-env" "kernel" [ [ string ] [ object ] ] ] - [ "millis" "kernel" [ [ ] [ integer ] ] ] - [ "(random-int)" "math" [ [ ] [ integer ] ] ] - [ "type" "kernel" [ [ object ] [ fixnum ] ] ] - [ "cwd" "io" [ [ ] [ string ] ] ] - [ "cd" "io" [ [ string ] [ ] ] ] - [ "compiled-offset" "assembler" [ [ ] [ integer ] ] ] - [ "set-compiled-offset" "assembler" [ [ integer ] [ ] ] ] - [ "literal-top" "assembler" [ [ ] [ integer ] ] ] - [ "set-literal-top" "assembler" [ [ integer ] [ ] ] ] - [ "address" "memory" [ [ object ] [ integer ] ] ] - [ "dlopen" "alien" [ [ string ] [ dll ] ] ] - [ "dlsym" "alien" [ [ string object ] [ integer ] ] ] - [ "dlclose" "alien" [ [ dll ] [ ] ] ] - [ "" "alien" [ [ integer ] [ alien ] ] ] - [ "" "kernel-internals" [ [ integer ] [ byte-array ] ] ] - [ "" "alien" [ [ integer c-ptr ] [ displaced-alien ] ] ] - [ "alien-signed-cell" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-signed-cell" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-unsigned-cell" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-unsigned-cell" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-signed-8" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-signed-8" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-unsigned-8" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-unsigned-8" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-signed-4" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-signed-4" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-unsigned-4" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-unsigned-4" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-signed-2" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-signed-2" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-unsigned-2" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-unsigned-2" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-signed-1" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-signed-1" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-unsigned-1" "alien" [ [ c-ptr integer ] [ integer ] ] ] - [ "set-alien-unsigned-1" "alien" [ [ integer c-ptr integer ] [ ] ] ] - [ "alien-float" "alien" [ [ c-ptr integer ] [ float ] ] ] - [ "set-alien-float" "alien" [ [ float c-ptr integer ] [ ] ] ] - [ "alien-double" "alien" [ [ c-ptr integer ] [ float ] ] ] - [ "set-alien-double" "alien" [ [ float c-ptr integer ] [ ] ] ] - [ "alien-c-string" "alien" [ [ c-ptr integer ] [ string ] ] ] - [ "set-alien-c-string" "alien" [ [ string c-ptr integer ] [ ] ] ] - [ "throw" "errors" [ [ object ] [ ] ] ] - [ "string>memory" "kernel-internals" [ [ string integer ] [ ] ] ] - [ "memory>string" "kernel-internals" [ [ integer integer ] [ string ] ] ] - [ "alien-address" "alien" [ [ alien ] [ integer ] ] ] - [ "slot" "kernel-internals" [ [ object fixnum ] [ object ] ] ] - [ "set-slot" "kernel-internals" [ [ object object fixnum ] [ ] ] ] - [ "integer-slot" "kernel-internals" [ [ object fixnum ] [ integer ] ] ] - [ "set-integer-slot" "kernel-internals" [ [ integer object fixnum ] [ ] ] ] - [ "char-slot" "kernel-internals" [ [ object fixnum ] [ fixnum ] ] ] - [ "set-char-slot" "kernel-internals" [ [ integer object fixnum ] [ ] ] ] - [ "resize-array" "kernel-internals" [ [ integer array ] [ array ] ] ] - [ "resize-string" "strings" [ [ integer string ] [ string ] ] ] - [ "" "hashtables" [ [ number ] [ hashtable ] ] ] - [ "" "kernel-internals" [ [ number ] [ array ] ] ] - [ "" "kernel-internals" [ [ number ] [ tuple ] ] ] - [ "begin-scan" "memory" [ [ ] [ ] ] ] - [ "next-object" "memory" [ [ ] [ object ] ] ] - [ "end-scan" "memory" [ [ ] [ ] ] ] - [ "size" "memory" [ [ object ] [ fixnum ] ] ] - [ "die" "kernel" [ [ ] [ ] ] ] - [ "flush-icache" "assembler" f ] - [ "fopen" "io-internals" [ [ string string ] [ alien ] ] ] - [ "fgetc" "io-internals" [ [ alien ] [ object ] ] ] - [ "fwrite" "io-internals" [ [ string alien ] [ ] ] ] - [ "fflush" "io-internals" [ [ alien ] [ ] ] ] - [ "fclose" "io-internals" [ [ alien ] [ ] ] ] - [ "expired?" "alien" [ [ object ] [ boolean ] ] ] -] [ - make-primitive -] each drop +: set-stack-effect ( { vocab word effect } -- ) + first3 >r lookup r> "stack-effect" set-word-prop ; -! These need a more descriptive comment. -[ - [ "drop" "kernel" " x -- " ] - [ "dup" "kernel" " x -- x x " ] - [ "swap" "kernel" " x y -- y x " ] - [ "over" "kernel" " x y -- x y x " ] - [ "pick" "kernel" " x y z -- x y z x " ] - [ ">r" "kernel" " x -- r: x " ] - [ "r>" "kernel" " r: x -- x " ] -] [ +{ + { "drop" "kernel" " x -- " } + { "dup" "kernel" " x -- x x " } + { "swap" "kernel" " x y -- y x " } + { "over" "kernel" " x y -- x y x " } + { "pick" "kernel" " x y z -- x y z x " } + { ">r" "kernel" " x -- r: x " } + { "r>" "kernel" " r: x -- x " } + { "datastack" "kernel" " -- ds " } + { "callstack" "kernel" " -- cs " } + { "set-datastack" "kernel" " ds -- " } + { "set-callstack" "kernel" " cs -- " } + { "flush-icache" "assembler" " -- " } +} [ set-stack-effect ] each FORGET: make-primitive FORGET: set-stack-effect + +! Okay, now we have primitives fleshed out. Bring up the generic +! word system. +: builtin-predicate ( class predicate -- ) + [ \ type , over types first , \ eq? , ] [ ] make + define-predicate ; + +: register-builtin ( class -- ) + dup types first builtins get set-nth ; + +: define-builtin ( symbol type# predicate slotspec -- ) + >r >r >r + dup intern-symbol + dup r> 1vector "types" set-word-prop + dup builtin define-class + dup r> builtin-predicate + dup r> intern-slots 2dup "slots" set-word-prop + define-slots + register-builtin ; + +{{ }} clone typemap set +num-types empty-vector builtins set + +! Catch-all metaclass for providing a default method. +object num-types >vector "types" set-word-prop +object [ drop t ] "predicate" set-word-prop +object object define-class + +! Null metaclass with no instances. +null { } "types" set-word-prop +null [ drop f ] "predicate" set-word-prop +null null define-class + +"fixnum" "math" create 0 "fixnum?" "math" create { } define-builtin +"fixnum" "math" create 0 "math-priority" set-word-prop +"fixnum" "math" create ">fixnum" [ "math" ] search unit "coercer" set-word-prop + +"bignum" "math" create 1 "bignum?" "math" create { } define-builtin +"bignum" "math" create 1 "math-priority" set-word-prop +"bignum" "math" create ">bignum" [ "math" ] search unit "coercer" set-word-prop + +"cons" "lists" create 2 "cons?" "lists" create +{ { 0 { "car" "lists" } f } { 1 { "cdr" "lists" } f } } define-builtin + +"ratio" "math" create 4 "ratio?" "math" create +{ { 0 { "numerator" "math" } f } { 1 { "denominator" "math" } f } } define-builtin +"ratio" "math" create 2 "math-priority" set-word-prop + +"float" "math" create 5 "float?" "math" create { } define-builtin +"float" "math" create 3 "math-priority" set-word-prop +"float" "math" create ">float" [ "math" ] search unit "coercer" set-word-prop + +"complex" "math" create 6 "complex?" "math" create +{ { 0 { "real" "math" } f } { 1 { "imaginary" "math" } f } } define-builtin +"complex" "math" create 4 "math-priority" set-word-prop + +"t" "!syntax" create 7 "t?" "kernel" create +{ } define-builtin + +"array" "kernel-internals" create 8 "array?" "kernel-internals" create +{ } define-builtin + +"f" "!syntax" create 9 "not" "kernel" create +{ } define-builtin + +"hashtable" "hashtables" create 10 "hashtable?" "hashtables" create { + { 1 { "hash-size" "hashtables" } { "set-hash-size" "kernel-internals" } } + { 2 { "hash-array" "kernel-internals" } { "set-hash-array" "kernel-internals" } } +} define-builtin + +"vector" "vectors" create 11 "vector?" "vectors" create { + { 1 { "length" "sequences" } { "set-capacity" "kernel-internals" } } + { 2 { "underlying" "kernel-internals" } { "set-underlying" "kernel-internals" } } +} define-builtin + +"string" "strings" create 12 "string?" "strings" create { + { 1 { "length" "sequences" } f } + { 2 { "hashcode" "kernel" } f } +} define-builtin + +"sbuf" "strings" create 13 "sbuf?" "strings" create { + { 1 { "length" "sequences" } { "set-capacity" "kernel-internals" } } + { 2 { "underlying" "kernel-internals" } { "set-underlying" "kernel-internals" } } +} define-builtin + +"wrapper" "kernel" create 14 "wrapper?" "kernel" create +{ { 1 { "wrapped" "kernel" } f } } define-builtin + +"dll" "alien" create 15 "dll?" "alien" create +{ { 1 { "dll-path" "alien" } f } } define-builtin + +"alien" "alien" create 16 "alien?" "alien" create { } define-builtin + +"word" "words" create 17 "word?" "words" create { + { 1 { "hashcode" "kernel" } f } + { 2 { "word-name" "words" } f } + { 3 { "word-vocabulary" "words" } { "set-word-vocabulary" "words" } } + { 4 { "word-primitive" "words" } { "set-word-primitive" "words" } } + { 5 { "word-def" "words" } { "set-word-def" "words" } } + { 6 { "word-props" "words" } { "set-word-props" "words" } } +} define-builtin + +"tuple" "kernel" create 18 "tuple?" "kernel" create { } define-builtin + +"byte-array" "kernel-internals" create 19 "byte-array?" "kernel-internals" create { } define-builtin + +"displaced-alien" "alien" create 20 "displaced-alien?" "alien" create { } define-builtin + +FORGET: builtin-predicate +FORGET: register-builtin +FORGET: define-builtin diff --git a/library/bootstrap/win32-io.factor b/library/bootstrap/win32-io.factor index c51094e12c..3b8fe648ee 100644 --- a/library/bootstrap/win32-io.factor +++ b/library/bootstrap/win32-io.factor @@ -39,9 +39,9 @@ USE: win32-api IN: io-internals -: io-multiplex ( timeout -- task ) +: io-multiplex ( timeout -- ) #! FIXME: needs to work given a timeout - -1 = [ win32-next-io-task ] when ; + dup -1 = [ drop INFINITE ] when cancel-timedout wait-for-io swap call ; : init-io ( -- ) win32-init-stdio ; diff --git a/library/cli.factor b/library/cli.factor index ceeb97dccd..64fd4f8d0a 100644 --- a/library/cli.factor +++ b/library/cli.factor @@ -8,7 +8,7 @@ sequences strings ; ! on all other words already being defined. : ?run-file ( file -- ) - dup exists? [ (run-file) ] [ drop ] ifte ; + dup exists? [ run-file ] [ drop ] ifte ; : run-user-init ( -- ) #! Run user init file if it exists diff --git a/library/collections/arrays.factor b/library/collections/arrays.factor index cb7649cc98..586dd24568 100644 --- a/library/collections/arrays.factor +++ b/library/collections/arrays.factor @@ -17,9 +17,6 @@ DEFER: repeat IN: kernel-internals USING: kernel math-internals sequences ; -DEFER: array? -BUILTIN: array 8 array? ; - : array-capacity ( a -- n ) 1 slot ; inline : array-nth ( n a -- obj ) swap 2 fixnum+ slot ; inline : set-array-nth ( obj n a -- ) swap 2 fixnum+ set-slot ; inline @@ -34,8 +31,12 @@ M: array resize resize-array ; 3dup swap array-nth pick rot set-array-nth ] repeat 2drop ; -DEFER: byte-array? -BUILTIN: byte-array 19 byte-array? ; - M: byte-array length array-capacity ; M: byte-array resize resize-array ; + +: make-tuple ( class size -- tuple ) + #! Internal allocation function. Do not call it directly, + #! since you can fool the runtime and corrupt memory by + #! specifying an incorrect size. Note that this word is also + #! handled specially by the compiler's type inferencer. + [ 2 set-slot ] keep ; flushable diff --git a/library/collections/assoc.factor b/library/collections/assoc.factor index fa44e5f7e8..56fd83ce9c 100644 --- a/library/collections/assoc.factor +++ b/library/collections/assoc.factor @@ -2,24 +2,12 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: lists USING: kernel sequences ; -: assoc? ( list -- ? ) - #! Push if the list appears to be an alist. An association - #! list is a list of conses where the car of each cons is a - #! key, and the cdr is a value. - dup list? [ [ cons? ] all? ] [ drop f ] ifte ; - : assoc* ( key alist -- [[ key value ]] ) #! Look up a key/value pair. [ car = ] find-with nip ; : assoc ( key alist -- value ) assoc* cdr ; -: assq* ( key alist -- [[ key value ]] ) - #! Looks up a key/value pair using identity comparison. - [ car eq? ] find-with nip ; - -: assq ( key alist -- value ) assq* cdr ; - : remove-assoc ( key alist -- alist ) #! Remove all key/value pairs with this key. [ car = not ] subset-with ; diff --git a/library/collections/cons.factor b/library/collections/cons.factor index 03bbf6dd11..65b9806e95 100644 --- a/library/collections/cons.factor +++ b/library/collections/cons.factor @@ -6,69 +6,34 @@ IN: lists USING: generic kernel sequences ; ! else depends on, and is loaded early in bootstrap. ! lists.factor has everything else. -DEFER: cons? -BUILTIN: cons 2 cons? [ 0 "car" f ] [ 1 "cdr" f ] ; - ! We borrow an idiom from Common Lisp. The car/cdr of an empty ! list is the empty list. M: f car ; M: f cdr ; -UNION: general-list f cons ; +UNION: general-list POSTPONE: f cons ; GENERIC: >list ( seq -- list ) M: general-list >list ( list -- list ) ; : last ( list -- last ) #! Last cons of a list. - dup cdr cons? [ cdr last ] when ; + dup cdr cons? [ cdr last ] when ; foldable PREDICATE: general-list list ( list -- ? ) #! Proper list test. A proper list is either f, or a cons #! cell whose cdr is a proper list. dup [ last cdr ] when not ; -: uncons ( [[ car cdr ]] -- car cdr ) dup car swap cdr ; -: unswons ( [[ car cdr ]] -- cdr car ) dup cdr swap car ; +: uncons ( [[ car cdr ]] -- car cdr ) dup car swap cdr ; inline +: unswons ( [[ car cdr ]] -- cdr car ) dup cdr swap car ; inline -: swons ( cdr car -- [[ car cdr ]] ) swap cons ; -: unit ( a -- [ a ] ) f cons ; -: 2list ( a b -- [ a b ] ) unit cons ; -: 3list ( a b c -- [ a b c ] ) 2list cons ; -: 2unlist ( [ a b ] -- a b ) uncons car ; -: 3unlist ( [ a b c ] -- a b c ) uncons uncons car ; +: swons ( cdr car -- [[ car cdr ]] ) swap cons ; inline +: unit ( a -- [ a ] ) f cons ; inline +: 2list ( a b -- [ a b ] ) unit cons ; inline -: 2car ( cons cons -- car car ) swap car swap car ; -: 2cdr ( cons cons -- car car ) swap cdr swap cdr ; -: 2cons ( ca1 ca2 cd1 cd2 -- c1 c2 ) rot swons >r cons r> ; -: 2uncons ( c1 c2 -- ca1 ca2 cd1 cd2 ) [ 2car ] 2keep 2cdr ; - -: zip ( list list -- list ) - #! Make a new list containing pairs of corresponding - #! elements from the two given lists. - 2dup and [ 2uncons zip >r cons r> cons ] [ 2drop [ ] ] ifte ; - -: unzip ( assoc -- keys values ) - #! Split an association list into two lists of keys and - #! values. - [ uncons >r uncons r> unzip 2cons ] [ [ ] [ ] ] ifte* ; - -: unpair ( list -- list1 list2 ) - [ uncons uncons unpair rot swons >r cons r> ] [ f f ] ifte* ; - -: ( -- queue ) - #! Make a new functional queue. - [[ [ ] [ ] ]] ; - -: queue-empty? ( queue -- ? ) - uncons or not ; - -: enque ( obj queue -- queue ) - uncons >r cons r> cons ; - -: deque ( queue -- obj queue ) - uncons - [ uncons swapd cons ] [ reverse uncons f swons ] ifte* ; +: 2car ( cons cons -- car car ) swap car swap car ; inline +: 2cdr ( cons cons -- car car ) swap cdr swap cdr ; inline M: cons = ( obj cons -- ? ) 2dup eq? [ diff --git a/library/collections/growable.factor b/library/collections/growable.factor index 07ebffa0d3..5ea11fc2b9 100644 --- a/library/collections/growable.factor +++ b/library/collections/growable.factor @@ -5,21 +5,6 @@ IN: kernel-internals USING: errors kernel math math-internals sequences ; -: assert-positive ( fx -- ) - 0 fixnum< - [ "Sequence index must be positive" throw ] when ; inline - -: assert-bounds ( fx seq -- ) - over assert-positive - length fixnum>= - [ "Sequence index out of bounds" throw ] when ; inline - -: bounds-check ( n seq -- fixnum seq ) - >r >fixnum r> 2dup assert-bounds ; inline - -: growable-check ( n seq -- fixnum seq ) - >r >fixnum dup assert-positive r> ; inline - GENERIC: underlying GENERIC: set-underlying GENERIC: set-capacity diff --git a/library/collections/hashtables.factor b/library/collections/hashtables.factor index d8b74c6ede..88b34ea49d 100644 --- a/library/collections/hashtables.factor +++ b/library/collections/hashtables.factor @@ -1,20 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. -IN: kernel-internals - -DEFER: hash-array -DEFER: set-hash-array -DEFER: set-hash-size - IN: hashtables -USING: generic kernel lists math sequences vectors ; - -! We put hash-size in the hashtables vocabulary, and -! the other words in kernel-internals. -DEFER: hashtable? -BUILTIN: hashtable 10 hashtable? - [ 1 "hash-size" set-hash-size ] - [ 2 hash-array set-hash-array ] ; +USING: generic kernel lists math sequences vectors +kernel-internals ; ! A hashtable is implemented as an array of buckets. The ! array index is determined using a hash function, and the @@ -62,9 +50,9 @@ IN: hashtables : hash* ( key table -- [[ key value ]] ) #! Look up a value in the hashtable. - 2dup (hashcode) swap hash-bucket assoc* ; + 2dup (hashcode) swap hash-bucket assoc* ; flushable -: hash ( key table -- value ) hash* cdr ; +: hash ( key table -- value ) hash* cdr ; flushable : set-hash* ( key hash quot -- ) #! Apply the quotation to yield a new association list. @@ -83,6 +71,7 @@ IN: hashtables : hash>alist ( hash -- alist ) #! Push a list of key/value pairs in a hashtable. [ ] swap [ hash-bucket [ swons ] each ] each-bucket ; + flushable : (set-hash) ( value key hash -- ) dup hash-size+ [ set-assoc ] set-hash* ; @@ -113,25 +102,41 @@ IN: hashtables : hash-clear ( hash -- ) 0 over set-hash-size [ f -rot set-hash-bucket ] each-bucket ; -: buckets>list ( hash -- list ) - hash-array >list ; +: buckets>vector ( hash -- vector ) + hash-array >vector ; : alist>hash ( alist -- hash ) dup length 1 max swap - [ unswons pick set-hash ] each ; + [ unswons pick set-hash ] each ; foldable : hash-keys ( hash -- list ) - hash>alist [ car ] map ; + hash>alist [ car ] map ; flushable : hash-values ( hash -- alist ) - hash>alist [ cdr ] map ; + hash>alist [ cdr ] map ; flushable -: hash-each ( hash quot -- ) +: hash-each ( hash quot -- | quot: [[ k v ]] -- ) swap hash-array [ swap each ] each-with ; inline -: hash-each-with ( obj hash quot -- | quot: obj elt -- ) +: hash-each-with ( obj hash quot -- | quot: obj [[ k v ]] -- ) swap [ with ] hash-each 2drop ; inline +: hash-all? ( hash quot -- | quot: [[ k v ]] -- ? ) + swap hash-array [ swap all? ] all-with? ; inline + +: hash-all-with? ( obj hash quot -- ? | quot: [[ k v ]] -- ? ) + swap [ with rot ] hash-all? 2nip ; inline + +: hash-contained? ( h1 h2 -- ? ) + #! Test if h2 contains all the key/value pairs of h1. + swap [ + uncons >r swap hash* dup [ + cdr r> = + ] [ + r> 2drop f + ] ifte + ] hash-all-with? ; flushable + : hash-subset ( hash quot -- hash | quot: [[ k v ]] -- ? ) >r hash>alist r> subset alist>hash ; inline @@ -145,8 +150,7 @@ M: hashtable = ( obj hash -- ? ) 2drop t ] [ over hashtable? [ - swap hash>alist swap hash>alist 2dup - contained? >r swap contained? r> and + 2dup hash-contained? >r swap hash-contained? r> and ] [ 2drop f ] ifte @@ -166,8 +170,12 @@ M: hashtable hashcode ( hash -- n ) pick rot >r >r call dup r> r> set-hash ] ifte* ; inline +: map>hash ( seq quot -- hash | quot: elt -- value ) + over >r map r> dup length -rot + [ pick set-hash ] 2each ; inline + : ?hash ( key hash/f -- value/f ) - dup [ hash ] [ 2drop f ] ifte ; + dup [ hash ] [ 2drop f ] ifte ; flushable : ?set-hash ( value key hash/f -- hash ) [ 1 ] unless* [ set-hash ] keep ; diff --git a/library/collections/lists.factor b/library/collections/lists.factor index 610e9cfaa0..e5c99fc5a6 100644 --- a/library/collections/lists.factor +++ b/library/collections/lists.factor @@ -13,12 +13,10 @@ M: cons peek ( list -- last ) #! Last element of a list. last car ; -: (each) ( list quot -- list quot ) - [ >r car r> call ] 2keep >r cdr r> ; inline - M: f each ( list quot -- ) 2drop ; -M: cons each ( list quot -- | quot: elt -- ) (each) each ; +M: cons each ( list quot -- | quot: elt -- ) + [ >r car r> call ] 2keep >r cdr r> each ; : (list-find) ( list quot i -- i elt ) pick [ @@ -34,38 +32,6 @@ M: cons each ( list quot -- | quot: elt -- ) (each) each ; M: general-list find ( list quot -- i elt ) 0 (list-find) ; -M: general-list find* ( start list quot -- i elt ) - >r tail r> find ; - -: partition-add ( obj ? ret1 ret2 -- ret1 ret2 ) - rot [ swapd cons ] [ >r cons r> ] ifte ; - -: partition-step ( ref list combinator -- ref cdr combinator car ? ) - pick pick car pick call >r >r unswons r> swap r> ; inline - -: (partition) ( ref list combinator ret1 ret2 -- ret1 ret2 ) - >r >r over [ - partition-step r> r> partition-add (partition) - ] [ - 3drop r> r> - ] ifte ; inline - -: partition ( ref list combinator -- list1 list2 ) - #! The combinator must have stack effect: - #! ( ref element -- ? ) - [ ] [ ] (partition) ; inline - -: sort ( list comparator -- sorted ) - #! To sort in ascending order, comparator must have stack - #! effect ( x y -- x>y ). - over [ - ( Partition ) [ >r uncons dupd r> partition ] keep - ( Recurse ) [ sort swap ] keep sort - ( Combine ) swapd cons append - ] [ - drop - ] ifte ; inline - : unique ( elem list -- list ) #! Prepend an element to a list if it does not occur in the #! list. @@ -76,25 +42,6 @@ M: general-list reverse-slice ( list -- list ) M: general-list reverse reverse-slice ; -IN: sequences -DEFER: - -IN: lists - -: count ( n -- [ 0 ... n-1 ] ) - 0 swap >list ; - -: project ( n quot -- list ) - >r count r> map ; inline - -: project-with ( elt n quot -- list ) - swap [ with rot ] project 2nip ; inline - -: seq-transpose ( seq -- list ) - #! An example illustrates this word best: - #! [ [ 1 2 3 ] [ 4 5 6 ] ] ==> [ [ 1 2 ] [ 3 4 ] [ 5 6 ] ] - dup first length [ swap [ nth ] map-with ] project-with ; - M: general-list head ( n list -- list ) #! Return the first n elements of the list. over 0 > [ diff --git a/library/collections/namespaces.factor b/library/collections/namespaces.factor index 9c8ef4888b..78a875244a 100644 --- a/library/collections/namespaces.factor +++ b/library/collections/namespaces.factor @@ -1,8 +1,5 @@ ! Copyright (C) 2003, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. -IN: words -DEFER: literalize - IN: namespaces USING: hashtables kernel kernel-internals lists math sequences strings vectors words ; @@ -33,7 +30,7 @@ strings vectors words ; : namespace ( -- namespace ) #! Push the current namespace. - namestack car ; + namestack car ; inline : >n ( namespace -- n:namespace ) #! Push a namespace on the name stack. @@ -45,10 +42,6 @@ strings vectors words ; : global ( -- g ) 4 getenv ; -: ( -- n ) - #! Create a new namespace. - 23 ; - : (get) ( var ns -- value ) #! Internal word for searching the namestack. dup [ @@ -59,23 +52,19 @@ strings vectors words ; ] ?ifte ] [ 2drop f - ] ifte ; + ] ifte ; flushable : get ( variable -- value ) #! Push the value of a variable by searching the namestack #! from the top down. - namestack (get) ; + namestack (get) ; flushable : set ( value variable -- ) namespace set-hash ; -: on ( var -- ) t swap set ; - -: off ( var -- ) f swap set ; - : nest ( variable -- hash ) #! If the variable is set in the current namespace, return #! its value, otherwise set its value to a new namespace. - dup namespace hash [ ] [ >r dup r> set ] ?ifte ; + dup namespace hash [ ] [ >r {{ }} clone dup r> set ] ?ifte ; : change ( var quot -- ) #! Execute the quotation with the variable value on the @@ -83,88 +72,62 @@ strings vectors words ; #! quotation. >r dup get r> rot slip set ; inline +: on ( var -- ) t swap set ; inline + +: off ( var -- ) f swap set ; inline + +: inc ( var -- ) [ 1 + ] change ; inline + +: dec ( var -- ) [ 1 - ] change ; inline + : bind ( namespace quot -- ) #! Execute a quotation with a namespace on the namestack. swap >n call n> drop ; inline -: with-scope ( quot -- ) - #! Execute a quotation with a new namespace on the - #! namestack. - >n call n> drop ; inline +: make-hash ( quot -- hash ) {{ }} clone >n call n> ; inline -: extend ( namespace code -- namespace ) - #! Used in code like this: - #! : - #! [ - #! .... - #! ] extend ; - over >r bind r> ; inline +: with-scope ( quot -- ) make-hash drop ; inline ! Building sequences SYMBOL: building -: make-seq ( quot sequence -- sequence ) - #! Call , and % from the quotation to append to a sequence. - [ building set call building get ] with-scope ; inline +: make ( quot proto -- ) + #! Call , and % from "quot" to append to a sequence + #! that has the same type as "proto". + [ + dup thaw building set >r call building get r> like + ] with-scope ; inline : , ( obj -- ) #! Add to the sequence being built with make-seq. building get push ; -: unique, ( obj -- ) - #! Add the object to the sequence being built with make-seq - #! unless an equal object has already been added. - building get 2dup member? [ 2drop ] [ push ] ifte ; - : % ( seq -- ) #! Append to the sequence being built with make-seq. building get swap nappend ; -: literal, ( word -- ) - #! Append some code that pushes the word on the stack. Used - #! when building quotations. - literalize % ; - -: make-vector ( quot -- vector ) - 100 make-seq ; inline - -: make-list ( quot -- list ) - make-vector >list ; inline - -: make-sbuf ( quot -- sbuf ) - 100 make-seq ; inline - -: make-string ( quot -- string ) - make-sbuf >string ; inline - -: make-rstring ( quot -- string ) - make-sbuf >string ; inline +: # ( n -- ) + #! Only useful with "" make. + number>string % ; ! Building hashtables, and computing a transitive closure. SYMBOL: hash-buffer -: make-hash ( quot -- hash ) - [ - hash-buffer set - call - hash-buffer get - ] with-scope ; inline - -: hash, ( value key -- ? ) +: closure, ( value key -- old ) hash-buffer get [ hash swap ] 2keep set-hash ; : (closure) ( key hash -- ) tuck hash dup [ hash-keys [ - dup dup hash, [ - 2drop - ] [ - swap (closure) - ] ifte + dup dup closure, [ 2drop ] [ swap (closure) ] ifte ] each-with ] [ 2drop ] ifte ; : closure ( key hash -- list ) - [ (closure) ] make-hash hash-keys ; + [ + {{ }} clone hash-buffer set + (closure) + hash-buffer get hash-keys + ] with-scope ; diff --git a/library/collections/queues.factor b/library/collections/queues.factor new file mode 100644 index 0000000000..7e3ed95a00 --- /dev/null +++ b/library/collections/queues.factor @@ -0,0 +1,24 @@ +IN: queues +USING: errors kernel lists math sequences vectors ; + +TUPLE: queue in out ; + +C: queue ( -- queue ) ; + +: queue-empty? ( queue -- ? ) + dup queue-in swap queue-out or not ; + +: enque ( obj queue -- ) + [ queue-in cons ] keep set-queue-in ; + +: deque ( queue -- obj ) + dup queue-out [ + uncons rot set-queue-out + ] [ + dup queue-in [ + reverse uncons pick set-queue-out + f rot set-queue-in + ] [ + "Empty queue" throw + ] ifte* + ] ifte* ; diff --git a/library/collections/sbuf.factor b/library/collections/sbuf.factor index 29025ba397..e315abde76 100644 --- a/library/collections/sbuf.factor +++ b/library/collections/sbuf.factor @@ -10,11 +10,6 @@ USING: generic sequences ; M: string resize resize-string ; -DEFER: sbuf? -BUILTIN: sbuf 13 sbuf? - [ 1 length set-capacity ] - [ 2 underlying set-underlying ] ; - M: sbuf set-length ( n sbuf -- ) grow-length ; M: sbuf nth ( n sbuf -- ch ) bounds-check underlying char-slot ; diff --git a/library/collections/sequence-eq.factor b/library/collections/sequence-eq.factor index 049c2e6cdc..9a6f08067f 100644 --- a/library/collections/sequence-eq.factor +++ b/library/collections/sequence-eq.factor @@ -9,21 +9,14 @@ UNION: sequence array string sbuf vector ; : length= ( seq seq -- ? ) length swap length number= ; -: (sequence=) ( seq seq i -- ? ) - over length over number= [ - 3drop t - ] [ - 3dup 2nth = [ 1 + (sequence=) ] [ 3drop f ] ifte - ] ifte ; - : sequence= ( seq seq -- ? ) #! Check if two sequences have the same length and elements, #! but not necessarily the same class. - over general-list? over general-list? or [ - swap >list swap >list = + 2dup length= [ + dup length [ >r 2dup r> 2nth = ] all? 2nip ] [ - 2dup length= [ 0 (sequence=) ] [ 2drop f ] ifte - ] ifte ; + 2drop f + ] ifte ; flushable M: sequence = ( obj seq -- ? ) 2dup eq? [ diff --git a/library/collections/sequence-sort.factor b/library/collections/sequence-sort.factor new file mode 100644 index 0000000000..d71c97e75e --- /dev/null +++ b/library/collections/sequence-sort.factor @@ -0,0 +1,92 @@ +IN: sorting-internals +USING: kernel math sequences vectors ; + +TUPLE: sorter seq start end mid ; + +C: sorter ( seq start end -- sorter ) + [ >r 1 + rot r> set-sorter-seq ] keep + dup sorter-seq midpoint over set-sorter-mid + dup sorter-seq length 1 - over set-sorter-end + 0 over set-sorter-start ; inline + +: s*/e* dup sorter-start swap sorter-end ; inline +: s*/e dup sorter-start swap sorter-seq length 1 - ; inline +: s/e* 0 swap sorter-end ; inline +: sorter-exchange dup s*/e* rot sorter-seq exchange ; inline +: compare over sorter-seq nth swap sorter-mid rot call ; inline +: >start> dup sorter-start 1 + swap set-sorter-start ; inline +: start> sort-up ] when + ] when ; inline + +: sort-down ( quot sorter -- quot sorter ) + dup s/e* <= [ + [ dup sorter-end compare 0 > ] 2keep rot + [ dup start> dup sort-step + [ dup sorter-seq swap s/e* (nsort) ] 2keep + [ dup sorter-seq swap s*/e (nsort) ] 2keep + ] [ + 2drop + ] ifte 2drop ; inline + +: partition ( -1/1 seq -- seq ) + dup midpoint@ swap rot 1 < + [ head-slice ] [ tail-slice ] ifte ; inline + +: (binsearch) ( elt quot seq -- i ) + dup length 1 <= [ + 2nip slice-from + ] [ + 3dup >r >r >r midpoint swap call dup 0 = [ + r> r> 3drop r> dup slice-from swap slice-to + 2 /i + ] [ + r> swap r> swap r> partition (binsearch) + ] ifte + ] ifte ; inline + +: flatten-slice ( seq -- slice ) + #! Binsearch returns an index relative to the sequence + #! being sliced, so if we are given a slice as input, + #! unexpected behavior will result. + dup slice? [ >vector ] when 0 over length rot ; + inline + +IN: sequences + +: nsort ( seq quot -- | quot: elt elt -- -1/0/1 ) + swap dup length 1 <= + [ 2drop ] [ 0 over length 1 - (nsort) ] ifte ; inline + +: sort ( seq quot -- seq | quot: elt elt -- -1/0/1 ) + swap [ swap nsort ] immutable ; inline + +: number-sort ( seq -- seq ) [ - ] sort ; + +: string-sort ( seq -- seq ) [ lexi ] sort ; + +: binsearch ( elt seq quot -- i | quot: elt elt -- -1/0/1 ) + swap dup empty? + [ 3drop -1 ] [ flatten-slice (binsearch) ] ifte ; + inline + +: binsearch* ( elt seq quot -- elt | quot: elt elt -- -1/0/1 ) + over >r binsearch dup -1 = [ r> 2drop f ] [ r> nth ] ifte ; + inline diff --git a/library/collections/sequences-epilogue.factor b/library/collections/sequences-epilogue.factor index f2aa932e3d..5f917f1ce5 100644 --- a/library/collections/sequences-epilogue.factor +++ b/library/collections/sequences-epilogue.factor @@ -1,21 +1,8 @@ ! Copyright (C) 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: sequences -USING: generic kernel kernel-internals lists math strings -vectors ; - -! A reversal of an underlying sequence. -TUPLE: reversed ; -C: reversed [ set-delegate ] keep ; -: reversed@ delegate [ length swap - 1 - ] keep ; -M: reversed nth ( n seq -- elt ) reversed@ nth ; -M: reversed set-nth ( elt n seq -- ) reversed@ set-nth ; -M: reversed thaw ( seq -- seq ) delegate reverse ; - -! A repeated sequence is the same element n times. -TUPLE: repeated length object ; -M: repeated length repeated-length ; -M: repeated nth nip repeated-object ; +USING: errors generic kernel kernel-internals lists math strings +vectors words ; ! Combinators M: object each ( seq quot -- ) @@ -23,23 +10,11 @@ M: object each ( seq quot -- ) [ swap nth swap call ] 3keep ] repeat 2drop ; -: change-nth ( seq i quot -- ) - pick pick >r >r >r swap nth r> call r> r> swap set-nth ; - inline - -: (nmap) ( seq i quot -- ) - pick length pick <= [ - 3drop - ] [ - [ change-nth ] 3keep >r 1 + r> (nmap) - ] ifte ; inline - -: nmap ( seq quot -- | quot: elt -- elt ) - #! Destructive on seq. - 0 swap (nmap) ; inline - : map ( seq quot -- seq | quot: elt -- elt ) - swap [ swap nmap ] immutable ; inline + over [ + length rot + [ -rot [ slip push ] 2keep ] each nip + ] keep like ; inline : map-with ( obj list quot -- list | quot: obj elt -- elt ) swap [ with rot ] map 2nip ; inline @@ -47,19 +22,28 @@ M: object each ( seq quot -- ) : accumulate ( list identity quot -- values | quot: x y -- z ) rot [ pick >r swap call r> ] map-with nip ; inline -: (2nmap) ( seq1 seq2 i quot -- elt3 ) - pick pick >r >r >r 2nth r> call r> r> swap set-nth ; inline +: change-nth ( seq i quot -- ) + pick pick >r >r >r swap nth r> call r> r> swap set-nth ; + inline -: 2nmap ( seq1 seq2 quot -- | quot: elt1 elt2 -- elt3 ) - #! Destructive on seq2. - over length [ - [ >r 3dup r> swap (2nmap) ] keep - ] repeat 3drop ; inline +: nmap ( seq quot -- seq | quot: elt -- elt ) + over length [ [ swap change-nth ] 3keep ] repeat 2drop ; inline -M: object 2map ( seq1 seq2 quot -- seq | quot: elt1 elt2 -- elt3 ) - swap [ swap 2nmap ] immutable ; +: 2each ( seq seq quot -- | quot: elt -- ) + over length >r >r cons r> r> + [ [ swap >r >r uncons r> 2nth r> call ] 3keep ] repeat + 2drop ; inline -M: object find* ( i seq quot -- i elt ) +: 2reduce ( seq seq identity quot -- value | quot: e x y -- z ) + >r -rot r> 2each ; inline + +: 2map ( seq seq quot -- seq | quot: elt elt -- elt ) + over [ + length 2swap + [ 2swap [ slip push ] 2keep ] 2each nip + ] keep like ; inline + +: find* ( i seq quot -- i elt ) pick pick length >= [ 3drop -1 f ] [ @@ -68,7 +52,10 @@ M: object find* ( i seq quot -- i elt ) ] [ r> 1 + r> r> find* ] ifte - ] ifte ; + ] ifte ; inline + +: find-with* ( obj i seq quot -- i elt | quot: elt -- ? ) + -rot [ with rot ] find* 2swap 2drop ; inline M: object find ( seq quot -- i elt ) 0 -rot find* ; @@ -102,14 +89,17 @@ M: object find ( seq quot -- i elt ) : subset-with ( obj seq quot -- seq | quot: obj elt -- ? ) swap [ with rot ] subset 2nip ; inline -: fiber? ( seq quot -- ? | quot: elt elt -- ? ) - #! Tests if all elements are equivalent under the relation. - over empty? - [ 2drop t ] [ >r [ first ] keep r> all-with? ] ifte ; inline +: (monotonic) ( quot seq i -- ? ) + 2dup 1 + swap nth >r swap nth r> rot call ; inline + +: monotonic? ( seq quot -- ? | quot: elt elt -- ? ) + #! Eg, { 1 2 3 4 } [ < ] monotonic? ==> t + #! { 1 3 2 4 } [ < ] monotonic? ==> f + swap dup length 1 - [ + pick pick >r >r (monotonic) r> r> rot + ] all? 2nip ; inline ! Operations -M: object thaw clone ; - M: object like drop ; M: object empty? ( seq -- ? ) length 0 = ; @@ -123,46 +113,31 @@ M: object empty? ( seq -- ? ) length 0 = ; M: object >list ( seq -- list ) dup length 0 rot (>list) ; -: index* ( obj i seq -- n ) - #! The index of the object in the sequence, starting from i. - [ = ] find-with* drop ; +: index ( obj seq -- n ) [ = ] find-with drop ; flushable +: index* ( obj i seq -- n ) [ = ] find-with* drop ; flushable +: member? ( obj seq -- ? ) [ = ] contains-with? ; flushable +: memq? ( obj seq -- ? ) [ eq? ] contains-with? ; flushable +: remove ( obj list -- list ) [ = not ] subset-with ; flushable -: index ( obj seq -- n ) - #! The index of the object in the sequence. - [ = ] find-with drop ; +: copy-into ( start to from -- ) + dup length [ >r pick r> + pick set-nth ] 2each 2drop ; -: member? ( obj seq -- ? ) - #! Tests for membership using =. - [ = ] contains-with? ; - -: memq? ( obj seq -- ? ) - #! Tests for membership using eq? - [ eq? ] contains-with? ; - -: remove ( obj list -- list ) - #! Remove all occurrences of objects equal to this one from - #! the list. - [ = not ] subset-with ; - -: remq ( obj list -- list ) - #! Remove all occurrences of the object from the list. - [ eq? not ] subset-with ; - -: nappend ( s1 s2 -- ) - #! Destructively append s2 to s1. - [ over push ] each drop ; +: nappend ( to from -- ) + >r dup length swap r> + over length over length + pick set-length + copy-into ; : append ( s1 s2 -- s1+s2 ) #! Outputs a new sequence of the same type as s1. - swap [ swap nappend ] immutable ; + swap [ swap nappend ] immutable ; flushable : add ( seq elt -- seq ) #! Outputs a new sequence of the same type as seq. - unit append ; + swap [ push ] immutable ; flushable : append3 ( s1 s2 s3 -- s1+s2+s3 ) #! Return a new sequence of the same type as s1. - rot [ [ rot nappend ] keep swap nappend ] immutable ; + rot [ [ rot nappend ] keep swap nappend ] immutable ; flushable : concat ( seq -- seq ) #! Append a sequence of sequences together. The new sequence @@ -170,7 +145,7 @@ M: object >list ( seq -- list ) dup length 0 rot (>list) ; dup empty? [ [ 1024 swap [ dupd nappend ] each ] keep first like - ] unless ; + ] unless ; flushable M: object peek ( sequence -- element ) #! Get value at end of sequence. @@ -186,30 +161,37 @@ M: object peek ( sequence -- element ) : prune ( seq -- seq ) [ dup length swap [ over push-new ] each - ] keep like ; + ] keep like ; flushable : >pop> ( stack -- stack ) dup pop drop ; +: join ( seq glue -- seq ) + #! The new sequence is of the same type as glue. + swap dup empty? [ + swap like + ] [ + dup length swap + [ over push 2dup push ] each nip >pop> + concat + ] ifte ; flushable + M: object reverse-slice ( seq -- seq ) ; M: object reverse ( seq -- seq ) [ ] keep like ; ! Set theoretic operations : seq-intersect ( seq1 seq2 -- seq1/\seq2 ) - [ swap member? ] subset-with ; + [ swap member? ] subset-with ; flushable : seq-diff ( seq1 seq2 -- seq2-seq1 ) - [ swap member? not ] subset-with ; - -: seq-diffq ( seq1 seq2 -- seq2-seq1 ) - [ swap memq? not ] subset-with ; + [ swap member? not ] subset-with ; flushable : seq-union ( seq1 seq2 -- seq1\/seq2 ) - append prune ; + append prune ; flushable : contained? ( seq1 seq2 -- ? ) #! Is every element of seq1 in seq2 - swap [ swap member? ] all-with? ; + swap [ swap member? ] all-with? ; flushable ! Lexicographic comparison : (lexi) ( seq seq i limit -- n ) @@ -221,21 +203,49 @@ M: object reverse ( seq -- seq ) [ ] keep like ; ] [ r> drop - >r 3drop r> ] ifte - ] ifte ; + ] ifte ; flushable : lexi ( s1 s2 -- n ) #! Lexicographically compare two sequences of numbers #! (usually strings). Negative if s1s2. - 0 pick length pick length min (lexi) ; + 0 pick length pick length min (lexi) ; flushable -: lexi> ( seq seq -- ? ) - #! Test if the first sequence follows the second - #! lexicographically. - lexi 0 > ; +: flip ( seq -- seq ) + #! An example illustrates this word best: + #! { { 1 2 3 } { 4 5 6 } } ==> { { 1 4 } { 2 5 } { 3 6 } } + dup empty? [ + dup first length [ swap [ nth ] map-with ] map-with + ] unless ; flushable + +: max-length ( seq -- n ) + #! Longest sequence length in a sequence of sequences. + 0 [ length max ] reduce ; flushable + +: exchange ( n n seq -- ) + [ tuck nth >r nth r> ] 3keep tuck + >r >r set-nth r> r> set-nth ; + +: midpoint@ length 2 /i ; inline + +: midpoint [ midpoint@ ] keep nth ; inline IN: kernel : depth ( -- n ) #! Push the number of elements on the datastack. datastack length ; + +: no-cond "cond fall-through" throw ; inline + +: cond ( conditions -- ) + #! Conditions is a sequence of quotation pairs. + #! { { [ X ] [ Y ] } { [ Z ] [ T ] } } + #! => X [ Y ] [ Z [ T ] [ ] ifte ] ifte + #! The last condition should be a catch-all 't'. + [ first call ] find nip dup + [ second call ] [ no-cond ] ifte ; + +: with-datastack ( stack word -- stack ) + datastack >r >r set-datastack r> execute + datastack r> [ push ] keep set-datastack 2nip ; diff --git a/library/collections/sequences.factor b/library/collections/sequences.factor index eae919d0ea..81bc1165d8 100644 --- a/library/collections/sequences.factor +++ b/library/collections/sequences.factor @@ -11,26 +11,25 @@ USING: errors generic kernel math math-internals strings vectors ; ! kernel-internals vocabulary, so don't use them unless you have ! a good reason. -GENERIC: empty? ( sequence -- ? ) -GENERIC: length ( sequence -- n ) +GENERIC: empty? ( sequence -- ? ) flushable +GENERIC: length ( sequence -- n ) flushable GENERIC: set-length ( n sequence -- ) -GENERIC: nth ( n sequence -- obj ) +GENERIC: nth ( n sequence -- obj ) flushable GENERIC: set-nth ( value n sequence -- obj ) -GENERIC: thaw ( seq -- mutable-seq ) -GENERIC: like ( seq seq -- seq ) -GENERIC: reverse ( seq -- seq ) -GENERIC: reverse-slice ( seq -- seq ) -GENERIC: peek ( seq -- elt ) -GENERIC: head ( n seq -- seq ) -GENERIC: tail ( n seq -- seq ) -GENERIC: concat ( seq -- seq ) +GENERIC: thaw ( seq -- mutable-seq ) flushable +GENERIC: like ( seq seq -- seq ) flushable +GENERIC: reverse ( seq -- seq ) flushable +GENERIC: reverse-slice ( seq -- seq ) flushable +GENERIC: peek ( seq -- elt ) flushable +GENERIC: head ( n seq -- seq ) flushable +GENERIC: tail ( n seq -- seq ) flushable GENERIC: resize ( n seq -- seq ) : immutable ( seq quot -- seq | quot: seq -- ) swap [ thaw ] keep >r dup >r swap call r> r> like ; inline G: each ( seq quot -- | quot: elt -- ) - [ over ] [ type ] ; inline + [ over ] standard-combination ; inline : each-with ( obj seq quot -- | quot: obj elt -- ) swap [ with ] each 2drop ; inline @@ -38,21 +37,12 @@ G: each ( seq quot -- | quot: elt -- ) : reduce ( seq identity quot -- value | quot: x y -- z ) swapd each ; inline -G: 2map ( seq seq quot -- seq | quot: elt elt -- elt ) - [ over ] [ type ] ; inline - G: find ( seq quot -- i elt | quot: elt -- ? ) - [ over ] [ type ] ; inline + [ over ] standard-combination ; inline : find-with ( obj seq quot -- i elt | quot: elt -- ? ) swap [ with rot ] find 2swap 2drop ; inline -G: find* ( i seq quot -- i elt | quot: elt -- ? ) - [ over ] [ type ] ; inline - -: find-with* ( obj i seq quot -- i elt | quot: elt -- ? ) - -rot [ with rot ] find* 2swap 2drop ; inline - : first 0 swap nth ; inline : second 1 swap nth ; inline : third 2 swap nth ; inline @@ -60,12 +50,24 @@ G: find* ( i seq quot -- i elt | quot: elt -- ? ) : push ( element sequence -- ) #! Push a value on the end of a sequence. - dup length swap set-nth ; + dup length swap set-nth ; inline -: 2nth ( s s n -- x x ) tuck swap nth >r swap nth r> ; +: 2nth ( s s n -- x x ) tuck swap nth >r swap nth r> ; inline -: 2unseq ( { x y } -- x y ) - dup first swap second ; +: first2 ( { x y } -- x y ) + dup first swap second ; inline -: 3unseq ( { x y z } -- x y z ) - dup first over second rot third ; +: first3 ( { x y z } -- x y z ) + dup first over second rot third ; inline + +TUPLE: bounds-error index seq ; + +: bounds-error throw ; inline + +: growable-check ( n seq -- fx seq ) + >r >fixnum dup 0 fixnum< + [ r> 2dup bounds-error ] [ r> ] ifte ; inline + +: bounds-check ( n seq -- fx seq ) + growable-check 2dup length fixnum>= + [ 2dup bounds-error ] when ; inline diff --git a/library/collections/slicing.factor b/library/collections/slicing.factor index 52130e46e8..40fdc337af 100644 --- a/library/collections/slicing.factor +++ b/library/collections/slicing.factor @@ -4,129 +4,56 @@ IN: sequences USING: generic kernel kernel-internals lists math namespaces strings vectors ; -! A range of integers. -TUPLE: range from to step ; +: head-slice ( n seq -- slice ) 0 -rot ; flushable -C: range ( from to -- range ) - >r 2dup > -1 1 ? r> - [ set-range-step ] keep - [ set-range-to ] keep - [ set-range-from ] keep ; +: tail-slice ( n seq -- slice ) [ length ] keep ; flushable -M: range length ( range -- n ) - dup range-to swap range-from - abs ; +: (slice*) [ length swap - ] keep ; -M: range nth ( n range -- n ) - [ range-step * ] keep range-from + ; +: head-slice* ( n seq -- slice ) (slice*) head-slice ; flushable -M: range like ( seq range -- range ) - drop >vector ; +: tail-slice* ( n seq -- slice ) (slice*) tail-slice ; flushable -M: range thaw ( range -- seq ) - >vector ; +: subseq ( from to seq -- seq ) [ ] keep like ; flushable -! A slice of another sequence. -TUPLE: slice seq ; +M: object head ( index seq -- seq ) [ head-slice ] keep like ; -C: slice ( from to seq -- ) - [ set-slice-seq ] keep - [ >r r> set-delegate ] keep ; +: head* ( n seq -- seq ) [ head-slice* ] keep like ; flushable -M: slice nth ( n slice -- obj ) - [ delegate nth ] keep slice-seq nth ; +M: object tail ( index seq -- seq ) [ tail-slice ] keep like ; -M: slice set-nth ( obj n slice -- ) - [ delegate nth ] keep slice-seq set-nth ; +: tail* ( n seq -- seq ) [ tail-slice* ] keep like ; flushable -M: slice like ( seq slice -- seq ) - slice-seq like ; - -M: slice thaw ( slice -- seq ) - >vector ; - -: head-slice ( n seq -- slice ) - 0 -rot ; - -: tail-slice ( n seq -- slice ) - [ length ] keep ; - -: tail-slice* ( n seq -- slice ) - [ length swap - ] keep tail-slice ; - -: subseq ( from to seq -- seq ) - #! Makes a new sequence with the same contents and type as - #! the slice of another sequence. - [ ] keep like ; - -M: object head ( index seq -- seq ) - 0 -rot subseq ; - -M: object tail ( index seq -- seq ) - #! Returns a new string, from the given index until the end - #! of the string. - [ length ] keep subseq ; - -: tail* ( n seq -- seq ) - #! Unlike tail, n is an index from the end of the - #! sequence. For example, if n=1, this returns a sequence of - #! one element. - [ length swap - ] keep tail ; - -: length< ( seq seq -- ? ) - swap length swap length < ; +: length< ( seq seq -- ? ) swap length swap length < ; flushable : head? ( seq begin -- ? ) 2dup length< [ 2drop f ] [ dup length rot head-slice sequence= - ] ifte ; + ] ifte ; flushable : ?head ( seq begin -- str ? ) - 2dup head? [ - length swap tail t - ] [ - drop f - ] ifte ; + 2dup head? [ length swap tail t ] [ drop f ] ifte ; flushable : tail? ( seq end -- ? ) 2dup length< [ 2drop f ] [ - dup length pick length swap - rot tail-slice sequence= - ] ifte ; + dup length rot tail-slice* sequence= + ] ifte ; flushable : ?tail ( seq end -- seq ? ) - 2dup tail? [ - length swap [ length swap - ] keep head t + 2dup tail? [ length swap head* t ] [ drop f ] ifte ; flushable + +: (group) ( n seq -- ) + 2dup length >= [ + dup like , drop ] [ - drop f + 2dup head , dupd tail-slice (group) ] ifte ; -: cut ( index seq -- seq seq ) - #! Returns 2 sequences, that when concatenated yield the - #! original sequence. - [ head ] 2keep tail ; - -: cut* ( index seq -- seq seq ) - #! Returns 2 sequences, that when concatenated yield the - #! original sequences, without the element at the given - #! index. - [ head ] 2keep >r 1 + r> tail ; - -: group-advance subseq , >r tuck + swap r> ; -: group-finish nip dup length swap subseq , ; - -: (group) ( start n seq -- ) - 3dup >r dupd + r> 2dup length < [ - group-advance (group) - ] [ - group-finish 3drop - ] ifte ; - -: group ( n seq -- list ) - #! Split a sequence into element chunks. - [ 0 -rot (group) ] make-list ; +: group ( n seq -- seq ) [ (group) ] { } make ; flushable : start-step ( subseq seq n -- subseq slice ) pick length dupd + rot ; @@ -140,36 +67,29 @@ M: object tail ( index seq -- seq ) ] [ r> r> 1 + start* ] ifte - ] ifte ; + ] ifte ; flushable : start ( subseq seq -- n ) #! The index of a subsequence in a sequence. - 0 start* ; + 0 start* ; flushable -: subseq? ( subseq seq -- ? ) start -1 > ; +: subseq? ( subseq seq -- ? ) start -1 > ; flushable + +: (split1) ( seq subseq -- before after ) + #! After is a slice. + dup pick start dup -1 = [ + 2drop dup like f + ] [ + [ swap length + over tail-slice ] keep rot head swap + ] ifte ; flushable : split1 ( seq subseq -- before after ) - dup pick start dup -1 = [ - 2drop f - ] [ - [ swap length + over tail ] keep rot head swap - ] ifte ; + #! After is of the same type as seq. + (split1) dup like ; flushable -: split-next ( index seq subseq -- next ) - pick >r dup pick r> start* dup -1 = [ - >r drop tail , r> ( end of sequence ) - ] [ - swap length dupd + >r swap subseq , r> - ] ifte ; +: (split) ( seq subseq -- ) + tuck (split1) >r , r> dup [ swap (split) ] [ 2drop ] ifte ; -: (split) ( index seq subseq -- ) - 2dup >r >r split-next dup -1 = [ - r> r> 3drop - ] [ - r> r> (split) - ] ifte ; +: split ( seq subseq -- seq ) [ (split) ] [ ] make ; flushable -: split ( seq subseq -- list ) - #! Split the sequence at each occurrence of subseq, and push - #! a list of the pieces. - [ 0 -rot (split) ] make-list ; +: cut ( n seq -- ) [ head ] 2keep tail ; flushable diff --git a/library/collections/strings-epilogue.factor b/library/collections/strings-epilogue.factor index 35d0ee0f5a..dd5ebc4df4 100644 --- a/library/collections/strings-epilogue.factor +++ b/library/collections/strings-epilogue.factor @@ -4,22 +4,27 @@ IN: strings USING: generic kernel kernel-internals lists math namespaces sequences strings ; -: empty-sbuf ( len -- sbuf ) dup [ set-length ] keep ; +: empty-sbuf ( len -- sbuf ) + dup [ set-length ] keep ; inline -: fill ( count char -- string ) >string ; +: fill ( count char -- string ) + >string ; inline : padding ( string count char -- string ) >r swap length - dup 0 <= [ r> 2drop "" ] [ r> fill ] ifte ; + flushable : pad-left ( string count char -- string ) - pick >r padding r> append ; + pick >r padding r> append ; flushable : pad-right ( string count char -- string ) - pick >r padding r> swap append ; + pick >r padding r> swap append ; flushable -: ch>string ( ch -- str ) 1 [ push ] keep (sbuf>string) ; +: ch>string ( ch -- str ) + 1 [ push ] keep (sbuf>string) ; flushable -: >sbuf ( seq -- sbuf ) dup length [ swap nappend ] keep ; +: >sbuf ( seq -- sbuf ) + dup length [ swap nappend ] keep ; inline M: object >string >sbuf (sbuf>string) ; diff --git a/library/collections/strings.factor b/library/collections/strings.factor index 871f2e6fe8..400f0aeb56 100644 --- a/library/collections/strings.factor +++ b/library/collections/strings.factor @@ -3,13 +3,9 @@ IN: strings USING: generic kernel kernel-internals lists math sequences ; -! Strings -DEFER: string? -BUILTIN: string 12 string? [ 1 length f ] [ 2 hashcode f ] ; - M: string nth ( n str -- ch ) bounds-check char-slot ; -GENERIC: >string ( seq -- string ) +GENERIC: >string ( seq -- string ) flushable M: string >string ; @@ -23,7 +19,7 @@ PREDICATE: integer printable CHAR: \s CHAR: ~ between? ; : quotable? ( ch -- ? ) #! In a string literal, can this character be used without #! escaping? - dup printable? swap "\"\\" member? not and ; + dup printable? swap "\"\\" member? not and ; foldable : url-quotable? ( ch -- ? ) #! In a URL, can this character be used without @@ -31,4 +27,4 @@ PREDICATE: integer printable CHAR: \s CHAR: ~ between? ; dup letter? over LETTER? or over digit? or - swap "/_?." member? or ; + swap "/_?." member? or ; foldable diff --git a/library/collections/tree-each.factor b/library/collections/tree-each.factor index 11c8d57ba3..5cf4099aef 100644 --- a/library/collections/tree-each.factor +++ b/library/collections/tree-each.factor @@ -1,10 +1,10 @@ ! Copyright (C) 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: sequences -USING: generic kernel lists ; +USING: generic kernel lists strings ; G: tree-each ( obj quot -- | quot: elt -- ) - [ over ] [ type ] ; inline + [ over ] standard-combination ; inline : tree-each-with ( obj vector quot -- ) swap [ with ] tree-each 2drop ; inline @@ -13,5 +13,7 @@ M: object tree-each call ; M: sequence tree-each swap [ swap tree-each ] each-with ; +M: string tree-each call ; + M: cons tree-each ( cons quot -- ) >r uncons r> tuck >r >r tree-each r> r> tree-each ; diff --git a/library/collections/vectors-epilogue.factor b/library/collections/vectors-epilogue.factor deleted file mode 100644 index 9fdcd677e4..0000000000 --- a/library/collections/vectors-epilogue.factor +++ /dev/null @@ -1,31 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -USING: errors generic kernel kernel-internals lists math -math-internals sequences ; - -IN: vectors - -: empty-vector ( len -- vec ) dup [ set-length ] keep ; - -: >vector ( list -- vector ) - dup length [ swap nappend ] keep ; - -M: repeated thaw >vector ; - -M: vector clone ( vector -- vector ) >vector ; - -: zero-vector ( n -- vector ) 0 >vector ; - -M: general-list thaw >vector ; - -M: general-list like drop >list ; - -M: vector like drop >vector ; - -: (1vector) [ push ] keep ; inline -: (2vector) [ swapd push ] keep (1vector) ; inline -: (3vector) [ >r rot r> push ] keep (2vector) ; inline - -: 1vector ( x -- { x } ) 1 (1vector) ; -: 2vector ( x y -- { x y } ) 2 (2vector) ; -: 3vector ( x y z -- { x y z } ) 3 (3vector) ; diff --git a/library/collections/vectors.factor b/library/collections/vectors.factor index 6b1498b0e5..e25c91ab57 100644 --- a/library/collections/vectors.factor +++ b/library/collections/vectors.factor @@ -4,11 +4,6 @@ IN: vectors USING: errors generic kernel kernel-internals lists math math-internals sequences ; -DEFER: vector? -BUILTIN: vector 11 vector? - [ 1 length set-capacity ] - [ 2 underlying set-underlying ] ; - M: vector set-length ( len vec -- ) grow-length ; M: vector nth ( n vec -- obj ) bounds-check underlying array-nth ; @@ -18,3 +13,25 @@ M: vector set-nth ( obj n vec -- ) M: vector hashcode ( vec -- n ) dup length 0 number= [ drop 0 ] [ first hashcode ] ifte ; + +: empty-vector ( len -- vec ) + dup [ set-length ] keep ; inline + +: >vector ( list -- vector ) + dup length [ swap nappend ] keep ; inline + +M: object thaw >vector ; + +M: vector clone ( vector -- vector ) >vector ; + +M: general-list like drop >list ; + +M: vector like drop >vector ; + +: (1vector) [ push ] keep ; inline +: (2vector) [ swapd push ] keep (1vector) ; inline +: (3vector) [ >r rot r> push ] keep (2vector) ; inline + +: 1vector ( x -- { x } ) 1 (1vector) ; flushable +: 2vector ( x y -- { x y } ) 2 (2vector) ; flushable +: 3vector ( x y z -- { x y z } ) 3 (3vector) ; flushable diff --git a/library/collections/virtual-sequences.factor b/library/collections/virtual-sequences.factor new file mode 100644 index 0000000000..76aab05cc9 --- /dev/null +++ b/library/collections/virtual-sequences.factor @@ -0,0 +1,53 @@ +! Copyright (C) 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: sequences +USING: generic kernel math vectors ; + +! A repeated sequence is the same element n times. +TUPLE: repeated length object ; + +M: repeated length repeated-length ; + +M: repeated nth nip repeated-object ; + +! A reversal of an underlying sequence. +TUPLE: reversed ; + +C: reversed [ set-delegate ] keep ; + +: reversed@ delegate [ length swap - 1 - ] keep ; + +M: reversed nth ( n seq -- elt ) reversed@ nth ; + +M: reversed set-nth ( elt n seq -- ) reversed@ set-nth ; + +M: reversed thaw ( seq -- seq ) delegate reverse ; + +! A slice of another sequence. +TUPLE: slice seq from to step ; + +: collapse-slice ( from to slice -- from to seq ) + dup slice-from swap slice-seq >r tuck + >r + r> r> ; + +C: slice ( from to seq -- seq ) + #! A slice of a slice collapses. + >r dup slice? [ collapse-slice ] when r> + [ set-slice-seq ] keep + >r 2dup > -1 1 ? r> + [ set-slice-step ] keep + [ set-slice-to ] keep + [ set-slice-from ] keep ; + +: ( from to -- seq ) 0 ; + +M: slice length ( range -- n ) + dup slice-to swap slice-from - abs ; + +: slice@ ( n slice -- n seq ) + [ [ slice-step * ] keep slice-from + ] keep slice-seq ; + +M: slice nth ( n slice -- obj ) slice@ nth ; + +M: slice set-nth ( obj n slice -- ) slice@ set-nth ; + +M: slice like ( seq slice -- seq ) slice-seq like ; diff --git a/library/combinators.factor b/library/combinators.factor deleted file mode 100644 index a030dee844..0000000000 --- a/library/combinators.factor +++ /dev/null @@ -1,64 +0,0 @@ -! Copyright (C) 2003, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: kernel - -: slip ( quot x -- x | quot: -- ) - >r call r> ; inline - -: 2slip ( quot x y -- x y | quot: -- ) - >r >r call r> r> ; inline - -: keep ( x quot -- x | quot: x -- ) - over >r call r> ; inline - -: 2keep ( x y quot -- x y | quot: x y -- ) - over >r pick >r call r> r> ; inline - -: 3keep ( x y z quot -- x y z | quot: x y z -- ) - >r 3dup r> swap >r swap >r swap >r call r> r> r> ; inline - -: while ( quot generator -- ) - #! Keep applying the quotation to the value produced by - #! calling the generator until the generator returns f. - 2dup >r >r swap >r call dup [ - r> call r> r> while - ] [ - r> 2drop r> r> 2drop - ] ifte ; inline - -: ifte* ( cond true false -- | true: cond -- | false: -- ) - #! [ X ] [ Y ] ifte* ==> dup [ X ] [ drop Y ] ifte - pick [ drop call ] [ 2nip call ] ifte ; inline - -: ?ifte ( default cond true false -- ) - #! [ X ] [ Y ] ?ifte ==> dup [ nip X ] [ drop Y ] ifte - >r >r dup [ - nip r> r> drop call - ] [ - drop r> drop r> call - ] ifte ; inline - -: unless ( cond quot -- | quot: -- ) - #! Execute a quotation only when the condition is f. The - #! condition is popped off the stack. - [ ] swap ifte ; inline - -: unless* ( cond quot -- | quot: -- ) - #! If cond is f, pop it off the stack and evaluate the - #! quotation. Otherwise, leave cond on the stack. - over [ drop ] [ nip call ] ifte ; inline - -: when ( cond quot -- | quot: -- ) - #! Execute a quotation only when the condition is not f. The - #! condition is popped off the stack. - [ ] ifte ; inline - -: when* ( cond quot -- | quot: cond -- ) - #! If the condition is true, it is left on the stack, and - #! the quotation is evaluated. Otherwise, the condition is - #! popped off the stack. - dupd [ drop ] ifte ; inline - -: with ( obj quot elt -- obj quot ) - #! Utility word for each-with, map-with. - pick pick >r >r swap call r> r> ; inline diff --git a/library/compiler/assembler.factor b/library/compiler/assembler.factor index 9c35d82ca9..31dfc34c34 100644 --- a/library/compiler/assembler.factor +++ b/library/compiler/assembler.factor @@ -20,15 +20,13 @@ SYMBOL: interned-literals : compile-aligned ( n -- ) compiled-offset cell 2 * align set-compiled-offset ; inline +: add-literal ( obj -- lit# ) + address + literal-top set-compiled-cell + literal-top dup cell + set-literal-top ; + : intern-literal ( obj -- lit# ) - dup interned-literals get hash [ ] [ - [ - address - literal-top set-compiled-cell - literal-top dup cell + set-literal-top - dup - ] keep interned-literals get set-hash - ] ?ifte ; + interned-literals get [ add-literal ] cache ; : compile-byte ( n -- ) compiled-offset set-compiled-byte @@ -44,6 +42,6 @@ SYMBOL: interned-literals compiled-offset 0 compile-cell ; : init-assembler ( -- ) - global [ interned-literals set ] bind ; + {{ }} clone interned-literals global set-hash ; : w>h/h dup -16 shift HEX: ffff bitand >r HEX: ffff bitand r> ; diff --git a/library/compiler/compiler.factor b/library/compiler/compiler.factor index 70c6a8ddd4..989a5e6788 100644 --- a/library/compiler/compiler.factor +++ b/library/compiler/compiler.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2004, 2005 Slava Pestov. IN: compiler -USING: compiler-backend compiler-frontend errors inference -kernel lists math namespaces prettyprint io words ; +USING: compiler-backend compiler-frontend errors inference io +kernel lists math namespaces prettyprint sequences words ; : supported-cpu? ( -- ? ) cpu "unknown" = not ; @@ -12,9 +12,7 @@ kernel lists math namespaces prettyprint io words ; ] unless ; : compiling ( word -- word parameter ) - check-architecture - "Compiling " write dup unparse. terpri flush - dup word-def ; + check-architecture "Compiling " write dup . dup word-def ; GENERIC: (compile) ( word -- ) @@ -27,7 +25,7 @@ M: compound (compile) ( word -- ) : precompile ( word -- ) #! Print linear IR of word. [ - word-def dataflow optimize linearize simplify [.] + word-def dataflow optimize linearize simplify [ . ] each ] with-scope ; : compile-postponed ( -- ) @@ -43,26 +41,29 @@ M: compound (compile) ( word -- ) "compile" get [ word compile ] when ; parsing : cannot-compile ( word error -- ) - "Cannot compile " write swap unparse. terpri print-error ; + "Cannot compile " write swap . print-error ; : try-compile ( word -- ) [ compile ] [ [ cannot-compile ] when* ] catch ; : compile-all ( -- ) [ try-compile ] each-word ; -: decompile ( word -- ) - dup compiled? [ - "Decompiling " write dup unparse. terpri flush - [ word-primitive ] keep set-word-primitive - ] [ - drop - ] ifte ; - -M: compound (uncrossref) - dup f "infer-effect" set-word-prop - dup f "base-case" set-word-prop - dup f "no-effect" set-word-prop - decompile ; - : recompile ( word -- ) - dup decompile compile ; + dup update-xt compile ; + +: compile-1 ( quot -- word ) + #! Compute a quotation into an uninterned word, for testing + #! purposes. + gensym [ swap define-compound ] keep dup compile execute ; + +\ dataflow profile +\ optimize profile +\ linearize profile +\ simplify profile +\ generate profile +\ kill-node profile +\ partial-eval profile +\ inline-method profile +\ apply-identities profile +\ subst-values profile +\ split-branch profile diff --git a/library/compiler/generator.factor b/library/compiler/generator.factor index 2ad15605a9..f4a1ebb035 100644 --- a/library/compiler/generator.factor +++ b/library/compiler/generator.factor @@ -2,7 +2,7 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: compiler-backend USING: assembler compiler errors inference kernel lists math -namespaces sequences strings vectors words ; +memory namespaces sequences strings vectors words ; ! Compile a VOP. GENERIC: generate-node ( vop -- ) @@ -59,6 +59,10 @@ M: %target generate-node GENERIC: v>operand +M: integer v>operand tag-bits shift ; + +M: f v>operand address ; + : dest/src ( vop -- dest src ) dup vop-out-1 v>operand swap vop-in-1 v>operand ; diff --git a/library/compiler/intrinsics.factor b/library/compiler/intrinsics.factor index f864fd5715..cfeb6f8f92 100644 --- a/library/compiler/intrinsics.factor +++ b/library/compiler/intrinsics.factor @@ -3,7 +3,7 @@ IN: compiler-frontend USING: assembler compiler-backend generic hashtables inference kernel kernel-internals lists math math-internals namespaces -sequences words ; +sequences vectors words ; ! Architecture description : fixnum-imm? @@ -54,26 +54,32 @@ sequences words ; out-1 ] "intrinsic" set-word-prop -: node-peek ( node -- obj ) node-in-d peek ; +: node-peek ( node -- value ) node-in-d peek ; -: peek-2 dup length 2 - swap nth ; -: node-peek-2 ( node -- obj ) node-in-d peek-2 ; +: type-tag ( type -- tag ) + #! Given a type number, return the tag number. + dup 6 > [ drop 3 ] when ; -: typed? ( value -- ? ) value-types length 1 = ; +: value-tag ( value node -- n/f ) + #! If the tag is known, output it, otherwise f. + node-classes hash dup [ + types [ type-tag ] map dup [ = ] monotonic? + [ first ] [ drop f ] ifte + ] [ + drop f + ] ifte ; -: slot@ ( node -- n ) +: slot@ ( node -- n/f ) #! Compute slot offset. - node-in-d - dup peek literal-value cell * - swap peek-2 value-types car type-tag - ; - -: typed-literal? ( node -- ? ) - #! Output if the node's first input is well-typed, and the - #! second is a literal. - dup node-peek safe-literal? swap node-peek-2 typed? and ; + dup node-in-d reverse dup first dup literal? [ + literal-value cell * swap second + rot value-tag dup [ - ] [ 2drop f ] ifte + ] [ + 3drop f + ] ifte ; \ slot [ - dup typed-literal? [ + dup slot@ [ 1 %dec-d , in-1 0 swap slot@ %fast-slot , @@ -87,36 +93,34 @@ sequences words ; ] "intrinsic" set-word-prop \ set-slot [ - dup typed-literal? [ + dup slot@ [ 1 %dec-d , in-2 2 %dec-d , slot@ >r 0 1 r> %fast-set-slot , - 0 %write-barrier , ] [ drop in-3 3 %dec-d , 1 %untag , 0 1 2 %set-slot , - 1 %write-barrier , ] ifte + 1 %write-barrier , ] "intrinsic" set-word-prop \ type [ drop in-1 0 %type , - 0 %tag-fixnum , + 0 %retag-fixnum , out-1 ] "intrinsic" set-word-prop -\ arithmetic-type [ +\ tag [ drop in-1 - 0 %arithmetic-type , - 0 %tag-fixnum , - 1 %inc-d , + 0 %tag , + 0 %retag-fixnum , out-1 ] "intrinsic" set-word-prop @@ -136,23 +140,23 @@ sequences words ; : value/vreg-list ( in -- list ) [ 0 swap length 1 - ] keep - [ >r 2dup r> 3list >r 1 - >r 1 + r> r> ] map 2nip ; + [ >r 2dup r> 3vector >r 1 - >r 1 + r> r> ] map 2nip ; : values>vregs ( in -- in ) value/vreg-list - dup [ 3unlist load-value ] each - [ car ] map ; + dup [ first3 load-value ] each + [ first ] map ; : load-inputs ( node -- in ) dup node-in-d values>vregs [ length swap node-out-d length - %dec-d , ] keep ; : binary-op-reg ( node op -- ) - >r load-inputs 2unlist swap dup r> execute , + >r load-inputs first2 swap dup r> execute , 0 0 %replace-d , ; inline -: literal-fixnum? ( value -- ? ) - dup safe-literal? [ literal-value fixnum? ] [ drop f ] ifte ; +: literal-immediate? ( value -- ? ) + dup literal? [ literal-value immediate? ] [ drop f ] ifte ; : binary-op-imm ( imm op -- ) 1 %dec-d , in-1 @@ -162,7 +166,7 @@ sequences words ; : binary-op ( node op -- ) #! out is a vreg where the vop stores the result. fixnum-imm? [ - >r dup node-peek dup literal-fixnum? [ + >r dup node-peek dup literal-immediate? [ literal-value r> binary-op-imm drop ] [ drop r> binary-op-reg @@ -183,7 +187,7 @@ sequences words ; [[ fixnum> %fixnum> ]] [[ eq? %eq? ]] ] [ - uncons [ literal, \ binary-op , ] make-list + uncons [ literalize , \ binary-op , ] [ ] make "intrinsic" set-word-prop ] each @@ -197,7 +201,7 @@ sequences words ; \ fixnum* [ ! Turn multiplication by a power of two into a left shift. - dup node-peek dup literal-fixnum? [ + dup node-peek dup literal-immediate? [ literal-value dup power-of-2? [ nip fast-fixnum* ] [ diff --git a/library/compiler/linearizer.factor b/library/compiler/linearizer.factor index d9f16b89c2..23ca7b2304 100644 --- a/library/compiler/linearizer.factor +++ b/library/compiler/linearizer.factor @@ -1,13 +1,16 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: compiler-frontend -USING: compiler-backend errors generic inference kernel -kernel-internals lists math namespaces prettyprint sequences +USING: compiler-backend errors generic lists inference kernel +math namespaces prettyprint sequences strings words ; GENERIC: linearize-node* ( node -- ) + M: f linearize-node* ( f -- ) drop ; +M: node linearize-node* ( node -- ) drop ; + : linearize-node ( node -- ) [ dup linearize-node* node-successor linearize-node @@ -17,22 +20,17 @@ M: f linearize-node* ( f -- ) drop ; #! Transform dataflow IR into linear IR. This strips out #! stack flow information, and flattens conditionals into #! jumps and labels. - [ %prologue , linearize-node ] make-list ; + [ %prologue , linearize-node ] [ ] make ; M: #label linearize-node* ( node -- )

browser-body
- - ] show drop drop ; + + ] show-final ; -: eval-string ( vocab to-eval -- ) - #! Evaluate the 'to-eval' within the given vocabulary. - build-eval-string [ - parse call - ] [ - [ - show-parse-error - drop - ] when* - ] catch ; - -: browser-url ( vocab word -- url ) - #! Given a vocabulary and word as strings, return a browser - #! URL which, when requested, will display the source to that - #! word. - [ - ".?word=" % url-encode % - "&vocab=" % url-encode % - ] make-string ; - -: browse ( -- ) - #! Display a Smalltalk like browser for exploring/modifying words. - [ - [ - - - - "Factor Browser - " write - "current-vocab" get write - " - " write - "current-word" get write - - - - -
- write-browser-body -
- - - ] show [ - "allow-edit?" get [ - "eval" get [ - "eval" off - "Editing has been disabled." show-message-page - ] when - ] unless - "allow-edit?" get "allow-edit?" set - ] extend - ] bind [ - "allow-edit?" get - "vocabs" get - "words" get - "eval" get dup [ "vocabs" get swap eval-string ] [ drop ] ifte - [ - "vocabs" get dup [ ] [ drop "unknown" ] ifte "words" get dup [ ] [ drop "unknown" ] ifte browser-url - forward-to-url - ] show-final - ] bind ; - -: browser-responder ( allow-edit? -- ) +: browser-responder ( -- ) #! Start the Smalltalk-like browser. - "query" get dup [ - dup >r "vocab" swap assoc r> "word" swap assoc + "query" get [ + [ "vocab" swap assoc ] keep + "word" swap assoc ] [ - drop "browser-responder" "" - ] ifte browse ; - -! "browser-edit" [ t browser-responder ] install-cont-responder + "browser-responder" "browse" + ] ifte* browse ; diff --git a/library/httpd/cont-responder.factor b/library/httpd/cont-responder.factor index c4f2f12145..160a0c1f78 100644 --- a/library/httpd/cont-responder.factor +++ b/library/httpd/cont-responder.factor @@ -22,7 +22,7 @@ ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IN: cont-responder USING: http httpd math random namespaces io - lists strings kernel html unparser hashtables + lists strings kernel html hashtables parser generic sequences ; #! Used inside the session state of responders to indicate whether the @@ -40,7 +40,8 @@ SYMBOL: post-refresh-get? : get-random-id ( -- id ) #! Generate a random id to use for continuation URL's - [ 32 [ 0 9 random-int unparse % ] times ] make-string str>number 36 >base ; + [ 32 [ 0 9 random-int CHAR: 0 + , ] times ] "" make + string>number 36 >base ; #! Name of variable holding the table of continuations. SYMBOL: table @@ -51,7 +52,7 @@ SYMBOL: table : reset-continuation-table ( -- ) #! Create the initial global table - table set ; + {{ }} clone table set ; #! Tuple for holding data related to a continuation. TUPLE: item expire? quot id time-added ; @@ -201,7 +202,7 @@ SYMBOL: callback-cc [ "HTTP/1.1 302 Document Moved\nLocation: " % % "\nContent-Length: 0\nContent-Type: text/plain\n\n" % - ] make-string call-exit-continuation ; + ] "" make call-exit-continuation ; : redirect-to-here ( -- ) #! Force a redirect to the client browser so that the browser @@ -274,7 +275,7 @@ SYMBOL: root-continuation #! Convert the given quotation so it works as a callback #! by returning a quotation that will pass the original #! quotation to the callback continuation. - [ , callback-cc get , \ call , ] make-list ; + [ , callback-cc get , \ call , ] [ ] make ; : quot-href ( text quot -- ) #! Write to standard output an HTML HREF where the href, @@ -299,15 +300,14 @@ SYMBOL: root-continuation #! #! Convert the quotation so it is run within a session namespace #! and that namespace is initialized first. - \ init-session-namespace swons [ , \ with-scope , ] make-list - [ + \ init-session-namespace swons [ , \ with-scope , ] [ ] make + [ [ cont-get/post-responder ] "get" set [ cont-get/post-responder ] "post" set - over "responder-name" set - over "responder" set + swap "responder" set reset-continuation-table permanent register-continuation root-continuation set - ] extend swap responders get set-hash ; + ] make-responder ; : responder-items ( name -- items ) #! Return the table of continuation items for a given responder. diff --git a/library/httpd/default-responders.factor b/library/httpd/default-responders.factor index 1f579679a9..56ba5f4e23 100644 --- a/library/httpd/default-responders.factor +++ b/library/httpd/default-responders.factor @@ -8,43 +8,30 @@ test-responder ; #! Remove all existing responders, and create a blank #! responder table. global [ - responders set + {{ }} clone responders set - ! Runs all unit tests and dumps result to the client. This uses - ! a lot of server resources, so disable it on a busy server. - [ - "test" "responder" set - [ test-responder ] "get" set - ] extend add-responder - ! 404 error message pages are served by this guy - [ + [ "404" "responder" set [ drop no-such-responder ] "get" set - ] extend add-responder + ] make-responder + + ! Servers Factor word definitions from the image. + "browser" [ browser-responder ] install-cont-responder ! Serves files from a directory stored in the "doc-root" ! variable. You can set the variable in the global namespace, ! or inside the responder. - [ + [ ! "/var/www/" "doc-root" set "file" "responder" set [ file-responder ] "get" set [ file-responder ] "post" set [ file-responder ] "head" set - ] extend add-responder - - ! Serves Factor source code - [ - "resource" "responder" set - [ resource-responder ] "get" set - ] extend add-responder - - ! Servers Factor word definitions from the image. - "browser" [ f browser-responder ] install-cont-responder + ] make-responder ! The root directory is served by... "file" set-default-responder - vhosts nest [ "default" set ] bind + vhosts nest [ {{ }} clone "default" set ] bind ] bind diff --git a/library/httpd/file-responder.factor b/library/httpd/file-responder.factor index b0c171e006..51dd0f8bfc 100644 --- a/library/httpd/file-responder.factor +++ b/library/httpd/file-responder.factor @@ -1,17 +1,17 @@ ! Copyright (C) 2004,2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: file-responder -USING: html httpd kernel lists namespaces parser sequences -io strings unparser ; +USING: html httpd kernel lists math namespaces parser sequences +io strings ; : serving-path ( filename -- filename ) [ "" ] unless* "doc-root" get swap append ; : file-response ( mime-type length -- ) [ - unparse "Content-Length" swons , + number>string "Content-Length" swons , "Content-Type" swons , - ] make-list "200 OK" response terpri ; + ] [ ] make "200 OK" response terpri ; : serve-static ( filename mime-type -- ) over file-length file-response "method" get "head" = [ @@ -27,6 +27,18 @@ io strings unparser ; serve-static ] ifte ; +: file-link. ( text path -- ) + file swons unit format ; + +: file-type. ( path -- ) + directory? "[DIR ] " "[FILE] " ? write ; + +: file. ( dir name -- ) + tuck path+ [ file-type. ] keep file-link. ; + +: directory. ( dir -- ) + dup directory [ file. terpri ] each-with ; + : list-directory ( directory -- ) serving-html "method" get "head" = [ diff --git a/library/httpd/html-tags.factor b/library/httpd/html-tags.factor index a8c263bd7c..1e697d1acd 100644 --- a/library/httpd/html-tags.factor +++ b/library/httpd/html-tags.factor @@ -24,6 +24,7 @@ ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IN: html +USING: prettyprint ; USE: strings USE: lists USE: kernel @@ -67,7 +68,7 @@ USE: sequences ! "click" write ! ! (url -- ) -! "click" write +! "click" write ! ! Tags that have no 'closing' equivalent have a trailing tag/> form: ! @@ -76,15 +77,13 @@ USE: sequences : attrs>string ( alist -- string ) #! Convert the attrs alist to a string #! suitable for embedding in an html tag. - reverse [ - [ dup car % "='" % cdr % "'" % ] each - ] make-string ; + [ [ " " % dup car % "='" % cdr % "'" % ] each ] "" make ; : write-attributes ( n: namespace -- ) #! With the attribute namespace on the stack, get the attributes #! and write them to standard output. If no attributes exist, write #! nothing. - "attrs" get [ bl attrs>string write ] when* ; + "attrs" get attrs>string write ; : store-prev-attribute ( n: tag value -- ) #! Assumes an attribute namespace is on the stack. @@ -92,114 +91,80 @@ USE: sequences #! and sets it's value to the current value on the stack. #! If there is no previous attribute, no value is expected #! on the stack. - "current-attribute" get [ swons "attrs" [ cons ] change ] when* ; + "current-attribute" get [ swons "attrs" get push ] when* ; -! HTML tag words -! -! Each closable HTML tag has four words defined. The example below is for -!

: -! -! :

( -- ) -! #! Writes the opening tag to standard output. -! "

" write ; - -! :

) -! #! Used for setting inline attributes. Prints out -! #! an unclosed opening tag. -! " >n ; -! -! : p> ( n: -- ) -! #! Used to close off inline attribute version of word. -! #! Prints out attributes and closes opening tag. -! store-prev-attribute write-attributes n> drop ">" write ; -! -! :

( -- ) -! #! Write out the closing tag. -! "" write ; -! -! Each open only HTML tag has only three words: -! -! : ( -- ) -! #! Used for printing the tag with no attributes. -! "" write ; -! -! : ) -! #! Used for setting inline attributes. -! " >n ; -! -! : input/> ( n: -- ) -! #! Used to close off inline attribute version of word -! #! and print the tag/ -! store-prev-attribute write-attributes n> drop ">" write ; -! -! Each attribute word has the form xxxx= where 'xxxx' is the attribute -! name. The example below is for href: -! -! : href= ( n: optional-value -- ) -! store-prev-attribute "href" "current-attribute" set ; - -: create-word ( vocab name def -- ) +: html-word ( name def -- ) #! Define 'word creating' word to allow #! dynamically creating words. - >r swap create r> define-compound ; + >r "html" create dup r> define-compound ; -: def-for-html-word- ( name -- name quot ) +: "<" swap ">" append3 ; + +: do- write ; + +: def-for-html-word- ( name -- ) #! Return the name and code for the patterned #! word. - "<" swap ">" append3 dup [ write ] cons ; + dup swap [ do- ] cons html-word define-open ; -: def-for-html-word-n { } clone "attrs" set ; + +: def-for-html-word- >n ] cons ; + ( name -- name quot ) +: foo> ">" append ; + +: do-foo> store-prev-attribute write-attributes n> drop ">" write ; + +: def-for-html-word-foo> ( name -- ) #! Return the name and code for the foo> patterned #! word. - ">" append [ - store-prev-attribute write-attributes n> drop ">" write - ] ; + foo> [ do-foo> ] html-word define-open ; -: def-for-html-word- ( name -- name quot ) +: [ "" % ] "" make ; + +: def-for-html-word- ( name -- ) #! Return the name and code for the patterned #! word. - [ "" % ] make-string dup [ write ] cons ; + dup [ write ] cons html-word define-close ; -: def-for-html-word- ( name -- name quot ) +: [ "<" % % "/>" % ] "" make ; + +: def-for-html-word- ( name -- ) #! Return the name and code for the patterned #! word. - [ "<" % dup % "/>" % ] make-string swap - [ "<" % % ">" % ] make-string - [ write ] cons ; + dup swap [ do- ] cons html-word drop ; -: def-for-html-word-foo/> ( name -- name quot ) +: foo/> "/>" append ; + +: def-for-html-word-foo/> ( name -- ) #! Return the name and code for the foo/> patterned #! word. - "/>" append [ - store-prev-attribute write-attributes n> drop ">" write - ] ; + foo/> [ do-foo> ] html-word define-close ; : define-closed-html-word ( name -- ) #! Given an HTML tag name, define the words for #! that closable HTML tag. - "html" swap - 2dup def-for-html-word- create-word - 2dup def-for-html-word- create-word - def-for-html-word- create-word ; + dup def-for-html-word- + dup def-for-html-word- + def-for-html-word- ; : define-open-html-word ( name -- ) #! Given an HTML tag name, define the words for #! that open HTML tag. - "html" swap - 2dup def-for-html-word- create-word - 2dup def-for-html-word- create-word ; + dup def-for-html-word- + dup def-for-html-word- ; : define-attribute-word ( name -- ) - "html" swap dup "=" append swap - [ store-prev-attribute ] cons reverse - [ "current-attribute" set ] append create-word ; + dup "=" append swap [ + \ store-prev-attribute , , [ "current-attribute" set ] % + ] [ ] make html-word drop ; ! Define some closed HTML tags [ diff --git a/library/httpd/html.factor b/library/httpd/html.factor index 389adbe63f..dceb67bbac 100644 --- a/library/httpd/html.factor +++ b/library/httpd/html.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: html -USING: generic http io kernel lists namespaces presentation -sequences strings styles unparser words ; +USING: generic http io kernel lists math namespaces parser +presentation sequences strings styles words ; : html-entities ( -- alist ) [ @@ -13,14 +13,11 @@ sequences strings styles unparser words ; [[ CHAR: " """ ]] ] ; -: char>entity ( ch -- str ) - dup >r html-entities assoc dup r> ? ; - : chars>entities ( str -- str ) #! Convert <, >, &, ' and " to HTML entities. [ [ dup html-entities assoc [ % ] [ , ] ?ifte ] each - ] make-string ; + ] "" make ; : hex-color, ( triplet -- ) [ >hex 2 CHAR: 0 pad-left % ] each ; @@ -38,7 +35,7 @@ sequences strings styles unparser words ; [ "text-decoration: underline; " % ] when ; : size-css, ( size -- ) - "font-size: " % unparse % "; " % ; + "font-size: " % # "; " % ; : font-css, ( font -- ) "font-family: " % % "; " % ; @@ -52,7 +49,7 @@ sequences strings styles unparser words ; [ font-size size-css, ] [ underline underline-css, ] ] assoc-apply - ] make-string ; + ] "" make ; : span-tag ( style quot -- ) over css-style dup "" = [ @@ -69,7 +66,7 @@ sequences strings styles unparser words ; ] when* "/" ?tail drop ; : file-link-href ( path -- href ) - [ "/" % resolve-file-link url-encode % ] make-string ; + [ "/" % resolve-file-link url-encode % ] "" make ; : file-link-tag ( style quot -- ) over file swap assoc [ @@ -80,7 +77,12 @@ sequences strings styles unparser words ; : browser-link-href ( word -- href ) dup word-name swap word-vocabulary - [ "/responder/browser/?vocab=" % % "&word=" % % ] make-string ; + [ + "/responder/browser/?vocab=" % + url-encode % + "&word=" % + url-encode % + ] "" make ; : browser-link-tag ( style quot -- style ) over presented swap assoc dup word? [ @@ -89,16 +91,6 @@ sequences strings styles unparser words ; drop call ] ifte ; -: icon-tag ( string style quot -- ) - over icon swap assoc dup [ - - #! Ignore the quotation, since no further style - #! can be applied - 3drop - ] [ - drop call - ] ifte ; - TUPLE: html-stream ; M: html-stream stream-write1 ( char stream -- ) @@ -110,10 +102,8 @@ M: html-stream stream-format ( str style stream -- ) [ [ [ - [ - [ drop chars>entities write ] span-tag - ] file-link-tag - ] icon-tag + [ drop chars>entities write ] span-tag + ] file-link-tag ] browser-link-tag ] with-wrapper ; @@ -129,7 +119,6 @@ C: html-stream ( stream -- stream ) #! font-style #! font-size #! underline - #! icon #! file #! word #! vocab diff --git a/library/httpd/http-client.factor b/library/httpd/http-client.factor index 8265010e9a..de92da80ce 100644 --- a/library/httpd/http-client.factor +++ b/library/httpd/http-client.factor @@ -1,12 +1,12 @@ ! Copyright (C) 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: http-client -USING: errors http kernel lists namespaces parser sequences -io strings unparser ; +USING: errors http kernel lists math namespaces parser sequences +io strings ; : parse-host ( url -- host port ) #! Extract the host name and port number from an HTTP URL. - ":" split1 [ parse-number ] [ 80 ] ifte* ; + ":" split1 [ string>number ] [ 80 ] ifte* ; : parse-url ( url -- host resource ) "http://" ?head [ @@ -16,15 +16,17 @@ io strings unparser ; : parse-response ( line -- code ) "HTTP/" ?head [ " " split1 nip ] when - " " split1 drop parse-number ; + " " split1 drop string>number ; : read-response ( -- code header ) #! After sending a GET oR POST we read a response line and #! header. flush readln parse-response read-header ; +: crlf "\r\n" write ; + : http-request ( host resource method -- ) - write CHAR: \s write write " HTTP/1.0" write crlf + write " " write write " HTTP/1.0" write crlf "Host: " write write crlf ; : get-request ( host resource -- ) @@ -50,10 +52,11 @@ DEFER: http-get >r http-get 2nip r> stream-copy ; : post-request ( content-type content host resource -- ) + #! Note: It is up to the caller to url encode the content if + #! it is required according to the content-type. "POST" http-request [ - url-encode - "Content-Length: " write length unparse write crlf - "Content-Type: " write write crlf + "Content-Length: " write length number>string write crlf + "Content-Type: " write url-encode write crlf crlf ] keep write ; diff --git a/library/httpd/http-common.factor b/library/httpd/http-common.factor index bc95e66df2..0a93003e61 100644 --- a/library/httpd/http-common.factor +++ b/library/httpd/http-common.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2003, 2005 Slava Pestov IN: http USING: errors kernel lists math namespaces parser sequences -io strings unparser ; +io strings ; : header-line ( alist line -- alist ) ": " split1 dup [ cons swons ] [ 2drop ] ifte ; @@ -22,7 +22,7 @@ io strings unparser ; CHAR: % , >hex 2 CHAR: 0 pad-left % ] ifte ] each - ] make-string ; + ] "" make ; : catch-hex> ( str -- n ) #! Push f if string is not a valid hex literal. @@ -53,4 +53,4 @@ io strings unparser ; ] ifte ; : url-decode ( str -- str ) - [ 0 swap url-decode-iter ] make-string ; + [ 0 swap url-decode-iter ] "" make ; diff --git a/library/httpd/httpd.factor b/library/httpd/httpd.factor index 1a9ceb1c86..1e3a35f404 100644 --- a/library/httpd/httpd.factor +++ b/library/httpd/httpd.factor @@ -38,7 +38,7 @@ sequences ; [ (handle-request) serve-responder ] with-scope ; : parse-request ( request -- ) - dup log + dup log-message " " split1 dup [ " HTTP" split1 drop url>path secure-path dup [ swap handle-request diff --git a/library/httpd/load.factor b/library/httpd/load.factor index 3d78266fc9..8cf325f27d 100644 --- a/library/httpd/load.factor +++ b/library/httpd/load.factor @@ -7,8 +7,6 @@ USING: kernel parser sequences io ; "/library/httpd/responder.factor" "/library/httpd/httpd.factor" "/library/httpd/file-responder.factor" - "/library/httpd/test-responder.factor" - "/library/httpd/resource-responder.factor" "/library/httpd/cont-responder.factor" "/library/httpd/browser-responder.factor" "/library/httpd/default-responders.factor" diff --git a/library/httpd/resource-responder.factor b/library/httpd/resource-responder.factor deleted file mode 100644 index fa5f94150a..0000000000 --- a/library/httpd/resource-responder.factor +++ /dev/null @@ -1,21 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: resource-responder -USING: httpd kernel lists namespaces io ; - -: resource-response ( mime-type -- ) - "Content-Type" swons unit "200 OK" response terpri ; - -: serve-resource ( filename mime-type -- ) - dup mime-type resource-response "method" get "head" = [ - drop - ] [ - stdio get stream-copy - ] ifte ; - -: resource-responder ( filename -- ) - "resource-path" get [ - serve-resource - ] [ - drop "404 resource-path not set" httpd-error - ] ifte ; diff --git a/library/httpd/responder.factor b/library/httpd/responder.factor index 1fac90f1e0..3873b1e26e 100644 --- a/library/httpd/responder.factor +++ b/library/httpd/responder.factor @@ -1,8 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: httpd -USING: hashtables http kernel lists namespaces parser sequences -io strings ; +USING: hashtables http kernel lists math namespaces parser +sequences io strings ; ! Variables SYMBOL: vhosts @@ -49,10 +49,7 @@ SYMBOL: responders [ "request" get % CHAR: / , "raw-query" get [ CHAR: ? , % ] when* - ] make-string redirect ; - -: content-length ( alist -- length ) - "Content-Length" swap assoc parse-number ; + ] "" make redirect ; : query>alist ( query -- alist ) dup [ @@ -64,11 +61,12 @@ SYMBOL: responders ] when ; : read-post-request ( header -- alist ) - content-length dup [ read query>alist ] when ; + "Content-Length" swap assoc dup + [ string>number read query>alist ] when ; : log-user-agent ( alist -- ) "User-Agent" swap assoc* [ - unswons [ % ": " % % ] make-string log + unswons [ % ": " % % ] "" make log-message ] when* ; : prepare-url ( url -- url ) @@ -95,8 +93,12 @@ SYMBOL: responders ! - header -- an alist of headers from the user's client ! - response -- an alist of the POST request response -: ( -- responder ) - [ +: add-responder ( responder -- ) + #! Add a responder object to the list. + "responder" over hash responders get set-hash ; + +: make-responder ( quot -- responder ) + [ ( url -- ) [ drop "GET method not implemented" httpd-error @@ -113,7 +115,9 @@ SYMBOL: responders [ drop bad-request ] "bad" set - ] extend ; + + call + ] make-hash add-responder ; : vhost ( name -- responder ) vhosts get hash [ "default" vhost ] unless* ; @@ -134,7 +138,7 @@ SYMBOL: responders "default" responder call-responder ; : log-responder ( path -- ) - "Calling responder " swap append log ; + "Calling responder " swap append log-message ; : trim-/ ( url -- url ) #! Trim a leading /, if there is one. @@ -162,7 +166,3 @@ SYMBOL: responders : no-such-responder ( -- ) "404 No such responder" httpd-error ; - -: add-responder ( responder -- ) - #! Add a responder object to the list. - "responder" over hash responders get set-hash ; diff --git a/library/httpd/test-responder.factor b/library/httpd/test-responder.factor deleted file mode 100644 index fef5856c33..0000000000 --- a/library/httpd/test-responder.factor +++ /dev/null @@ -1,9 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: test-responder -USING: html httpd kernel test ; - -: test-responder ( argument -- ) - drop - serving-html - "Factor Test Suite" [ all-tests ] simple-html-document ; diff --git a/library/icons/File.png b/library/icons/File.png deleted file mode 100644 index dd1124b58e..0000000000 Binary files a/library/icons/File.png and /dev/null differ diff --git a/library/icons/Folder.png b/library/icons/Folder.png deleted file mode 100644 index 2de866acb8..0000000000 Binary files a/library/icons/Folder.png and /dev/null differ diff --git a/library/in-thread.factor b/library/in-thread.factor deleted file mode 100644 index 140123b7e9..0000000000 --- a/library/in-thread.factor +++ /dev/null @@ -1,19 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: threads -USING: errors kernel lists namespaces sequences ; - -: in-thread ( quot -- ) - #! Execute a quotation in a co-operative thread. The - #! quotation begins executing immediately, and execution - #! after the 'in-thread' call in the original thread - #! resumes when the quotation yields, either due to blocking - #! I/O or an explicit call to 'yield'. - [ - schedule-thread - ! Clear stacks since we never go up from this point - [ ] set-catchstack - { } set-callstack - try - stop - ] callcc0 drop ; diff --git a/library/inference/branches.factor b/library/inference/branches.factor index e607ced654..2543350a00 100644 --- a/library/inference/branches.factor +++ b/library/inference/branches.factor @@ -1,84 +1,71 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: inference -USING: errors generic interpreter kernel lists math namespaces -sequences strings vectors words hashtables prettyprint ; +USING: errors generic hashtables interpreter kernel lists math +namespaces parser prettyprint sequences strings vectors words ; -: longest ( list -- length ) - [ length ] map 0 [ max ] reduce ; - -: computed-value-vector ( n -- vector ) - empty-vector [ drop object ] map ; - -: add-inputs ( count stack -- stack ) - #! Add this many inputs to the given stack. - [ length - computed-value-vector ] keep append ; - -: unify-lengths ( list -- list ) +: unify-lengths ( seq -- seq ) #! Pad all vectors to the same length. If one vector is #! shorter, pad it with unknown results at the bottom. - dup longest swap [ add-inputs ] map-with ; + dup max-length swap + [ [ required-inputs ] keep append ] map-with ; -: unify-results ( list -- value ) +: unify-length ( seq seq -- seq ) + 2vector unify-lengths first2 ; + +: unify-values ( seq -- value ) #! If all values in list are equal, return the value. - #! Otherwise, unify types. - dup [ eq? ] fiber? [ - car - ] [ - [ value-class ] map class-or-list - ] ifte ; + #! Otherwise, unify. + dup [ eq? ] monotonic? [ first ] [ ] ifte ; -: unify-stacks ( list -- stack ) +: unify-stacks ( seq -- stack ) #! Replace differing literals in stacks with unknown #! results. - unify-lengths seq-transpose [ unify-results ] map >vector ; + unify-lengths flip [ unify-values ] map ; -: balanced? ( list -- ? ) - #! Check if a list of [[ instack outstack ]] pairs is - #! balanced. - [ uncons length swap length - ] map [ = ] fiber? ; +: balanced? ( in out -- ? ) + [ swap length swap length - ] 2map [ = ] monotonic? ; -: unify-effect ( list -- in out ) - #! Unify a list of [[ instack outstack ]] pairs. - dup balanced? [ - unzip unify-stacks >r unify-stacks r> - ] [ - "Unbalanced branches" inference-error +: unify-effect ( in out -- in out ) + 2dup balanced? + [ unify-stacks >r unify-stacks r> ] + [ + { "Unbalanced branches:" } -rot [ + swap length number>string + " " rot length number>string append3 + ] 2map append "\n" join inference-error ] ifte ; -: datastack-effect ( list -- ) - [ [ effect ] bind ] map +: datastack-effect ( seq -- ) + dup [ d-in swap hash ] map + swap [ meta-d swap hash ] map unify-effect meta-d set d-in set ; -: callstack-effect ( list -- ) - [ [ { } meta-r get ] bind cons ] map +: callstack-effect ( seq -- ) + dup length { } + swap [ meta-r swap hash ] map unify-effect meta-r set drop ; -: filter-terminators ( list -- list ) +: filter-terminators ( seq -- seq ) #! Remove branches that unconditionally throw errors. [ [ active? ] bind ] subset ; -: unify-effects ( list -- ) - filter-terminators [ - dup datastack-effect callstack-effect - ] [ - terminate - ] ifte* ; +: unify-effects ( seq -- ) + filter-terminators dup empty? + [ drop terminate ] + [ dup datastack-effect callstack-effect ] ifte ; : unify-dataflow ( effects -- nodes ) [ [ dataflow-graph get ] bind ] map ; -: clone-values ( seq -- seq ) [ clone-value ] map ; - : copy-inference ( -- ) #! We avoid cloning the same object more than once in order #! to preserve identity structure. - cloned off - meta-r [ clone-values ] change - meta-d [ clone-values ] change - d-in [ clone-values ] change + meta-r [ clone ] change + meta-d [ clone ] change + d-in [ clone ] change dataflow-graph off current-node off ; @@ -86,38 +73,24 @@ sequences strings vectors words hashtables prettyprint ; #! Return a namespace with inferencer variables: #! meta-d, meta-r, d-in. They are set to f if #! terminate was called. - [ - copy-inference - dup value-recursion recursive-state set - literal-value dup infer-quot - active? [ - #values node, - handle-terminator - ] [ - drop - ] ifte - ] extend ; + [ + [ + base-case-continuation set + copy-inference + dup value-recursion recursive-state set + dup literal-value infer-quot + active? [ #values node, ] when + f + ] callcc1 [ terminate ] when drop + ] make-hash ; : (infer-branches) ( branchlist -- list ) - [ infer-branch ] map dup unify-effects unify-dataflow ; + [ infer-branch ] map dup unify-effects + unify-dataflow ; : infer-branches ( branches node -- ) #! Recursive stack effect inference is done here. If one of #! the branches has an undecidable stack effect, we set the #! base case to this stack effect and try again. - [ >r (infer-branches) r> set-node-children ] keep node, ; - -\ ifte [ - 2 #drop node, pop-d pop-d swap 2list - #ifte pop-d drop infer-branches -] "infer" set-word-prop - -: vtable>list ( rstate vtable -- list ) - [ swap ] map-with >list ; - -USE: kernel-internals - -\ dispatch [ - pop-literal vtable>list - #dispatch pop-d drop infer-branches -] "infer" set-word-prop + [ >r (infer-branches) r> set-node-children ] keep + node, #merge node, ; diff --git a/library/inference/call-optimizers.factor b/library/inference/call-optimizers.factor new file mode 100644 index 0000000000..66db22caad --- /dev/null +++ b/library/inference/call-optimizers.factor @@ -0,0 +1,178 @@ +! Copyright (C) 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: inference +USING: errors generic hashtables kernel math math-internals +sequences vectors words ; + +! A system for associating dataflow optimizers with words. + +: optimizer-hooks ( node -- conditions ) + node-param "optimizer-hooks" word-prop ; + +: optimize-hooks ( node -- node/t ) + dup optimizer-hooks cond ; + +: define-optimizers ( word optimizers -- ) + { [ t ] [ drop t ] } add "optimizer-hooks" set-word-prop ; + +: partial-eval? ( #call -- ? ) + dup node-param "foldable" word-prop [ + dup node-in-d [ + dup literal? + [ 2drop t ] [ swap node-literals hash* ] ifte + ] all-with? + ] [ + drop f + ] ifte ; + +: literal-in-d ( #call -- inputs ) + dup node-in-d [ + dup literal? + [ nip literal-value ] [ swap node-literals hash ] ifte + ] map-with ; + +: partial-eval ( #call -- node ) + dup literal-in-d over node-param + [ with-datastack ] [ + [ 3drop t ] [ inline-literals ] ifte + ] catch ; + +: flip-branches ( #ifte -- ) + dup node-children first2 swap 2vector swap set-node-children ; + +\ not { + { [ dup node-successor #ifte? ] [ node-successor dup flip-branches ] } +} define-optimizers + +: disjoint-eq? ( node -- ? ) + dup node-classes swap node-in-d + [ swap hash ] map-with + first2 2dup and [ classes-intersect? not ] [ 2drop f ] ifte ; + +\ eq? { + { [ dup disjoint-eq? ] [ [ f ] inline-literals ] } +} define-optimizers + +! Arithmetic identities +SYMBOL: @ + +: define-identities ( words identities -- ) + swap [ swap "identities" set-word-prop ] each-with ; + +: literals-match? ( values template -- ? ) + [ + over literal? [ >r literal-value r> ] [ nip @ ] ifte = + ] 2map [ ] all? ; + +: values-match? ( values template -- ? ) + [ @ = [ drop f ] unless ] 2map [ ] subset [ eq? ] monotonic? ; + +: apply-identity? ( values identity -- ? ) + first 2dup literals-match? >r values-match? r> and ; + +: find-identity ( node -- values identity ) + dup node-in-d swap node-param "identities" word-prop + [ dupd apply-identity? ] find nip ; + +: apply-identities ( node -- node/f ) + dup find-identity dup [ + second swap dataflow-with [ subst-node ] keep + ] [ + 3drop f + ] ifte ; + +[ + fixnum+ bignum+ float+ ] { + { { @ 0 } [ drop ] } + { { 0 @ } [ nip ] } +} define-identities + +[ - fixnum- bignum- float- ] { + { { @ 0 } [ drop ] } + { { @ @ } [ 2drop 0 ] } +} define-identities + +[ * fixnum* bignum* float* ] { + { { @ 1 } [ drop ] } + { { 1 @ } [ nip ] } + { { @ 0 } [ nip ] } + { { 0 @ } [ drop ] } + { { @ -1 } [ drop 0 swap - ] } + { { -1 @ } [ nip 0 swap - ] } +} define-identities + +[ / /i /f fixnum/i fixnum/f bignum/i bignum/f float/f ] { + { { @ 1 } [ drop ] } + { { @ -1 } [ drop 0 swap - ] } +} define-identities + +[ rem mod fixnum-mod bignum-mod ] { + { { @ 1 } [ 2drop 0 ] } +} define-identities + +! [ ^ ] { +! { { 1 @ } [ 2drop 1 ] } +! { { @ 1 } [ drop ] } +! { { @ 2 } [ drop dup * ] } +! { { @ -1 } [ drop 1 swap / ] } +! { { @ -2 } [ drop dup * 1 swap / ] } +! } define-identities + +[ bitand fixnum-bitand bignum-bitand ] { + { { @ -1 } [ drop ] } + { { -1 @ } [ nip ] } + { { @ @ } [ drop ] } + { { @ 0 } [ nip ] } + { { 0 @ } [ drop ] } +} define-identities + +[ bitor fixnum-bitor bignum-bitor ] { + { { @ 0 } [ drop ] } + { { 0 @ } [ nip ] } + { { @ @ } [ drop ] } + { { @ -1 } [ nip ] } + { { -1 @ } [ drop ] } +} define-identities + +[ bitxor fixnum-bitxor bignum-bitxor ] { + { { @ 0 } [ drop ] } + { { 0 @ } [ nip ] } + { { @ -1 } [ drop bitnot ] } + { { -1 @ } [ nip bitnot ] } + { { @ @ } [ 2drop 0 ] } +} define-identities + +[ shift fixnum-shift bignum-shift ] { + { { 0 @ } [ drop ] } + { { @ 0 } [ drop ] } +} define-identities + +[ < fixnum< bignum< float< ] { + { { @ @ } [ 2drop f ] } +} define-identities + +[ <= fixnum<= bignum<= float<= ] { + { { @ @ } [ 2drop t ] } +} define-identities + +[ > fixnum> bignum> float>= ] { + { { @ @ } [ 2drop f ] } +} define-identities + +[ >= fixnum>= bignum>= float>= ] { + { { @ @ } [ 2drop t ] } +} define-identities + +[ eq? number= = ] { + { { @ @ } [ 2drop t ] } +} define-identities + +M: #call optimize-node* ( node -- node/t ) + { + { [ dup node-param not ] [ node-successor ] } + { [ dup partial-eval? ] [ partial-eval ] } + { [ dup find-identity nip ] [ apply-identities ] } + { [ dup optimizer-hooks ] [ optimize-hooks ] } + { [ dup inlining-class ] [ inline-method ] } + { [ dup optimize-predicate? ] [ optimize-predicate ] } + { [ t ] [ drop t ] } + } cond ; diff --git a/library/inference/class-infer.factor b/library/inference/class-infer.factor new file mode 100644 index 0000000000..7acf08930c --- /dev/null +++ b/library/inference/class-infer.factor @@ -0,0 +1,157 @@ +! Copyright (C) 2004, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: inference +USING: generic hashtables kernel kernel-internals namespaces +sequences vectors words ; + +! Infer possible classes of values in a dataflow IR. + +! Variables used by the class inferencer + +! Current value --> class mapping +SYMBOL: value-classes + +! Current value --> literal mapping +SYMBOL: value-literals + +! Maps ties to ties +SYMBOL: ties + +GENERIC: apply-tie ( tie -- ) + +M: f apply-tie ( f -- ) drop ; + +TUPLE: class-tie value class ; + +: set-value-class ( class value -- ) + 2dup swap ties get hash [ apply-tie ] when* + value-classes get set-hash ; + +M: class-tie apply-tie ( tie -- ) + dup class-tie-class swap class-tie-value + set-value-class ; + +TUPLE: literal-tie value literal ; + +: set-value-literal ( literal value -- ) + over class over set-value-class + 2dup swap ties get hash [ apply-tie ] when* + value-literals get set-hash ; + +M: literal-tie apply-tie ( tie -- ) + dup literal-tie-literal swap literal-tie-value + set-value-literal ; + +GENERIC: infer-classes* ( node -- ) + +M: node infer-classes* ( node -- ) drop ; + +! For conditionals, a map of child node # --> possibility +GENERIC: child-ties ( node -- seq ) + +M: node child-ties ( node -- seq ) + node-children length f ; + +: value-class ( value -- class ) + value-classes get hash [ object ] unless* ; + +: value-literal ( value -- class ) + value-literals get hash ; + +: annotate-node ( node -- ) + #! Annotate the node with the currently-inferred set of + #! value classes. + dup node-values ( 2dup ) + [ value-class ] map>hash swap set-node-classes + ( [ value-literal ] map>hash swap set-node-literals ) ; + +: assume-classes ( classes values -- ) + [ set-value-class ] 2each ; + +: assume-literals ( literals values -- ) + [ set-value-literal ] 2each ; + +: intersect-classes ( classes values -- ) + [ [ value-class class-and ] 2map ] keep assume-classes ; + +: type/tag-ties ( node n -- ) + over node-out-d first over [ ] map-with + >r swap node-in-d first swap [ type>class ] map-with r> + [ ties get set-hash ] 2each ; + +\ type [ num-types type/tag-ties ] "create-ties" set-word-prop + +\ tag [ num-tags type/tag-ties ] "create-ties" set-word-prop + +: create-ties ( #call -- ) + #! If the node is calling a class test predicate, create a + #! tie. + dup node-param "create-ties" word-prop dup [ + call + ] [ + drop dup node-param "predicating" word-prop dup [ + >r dup node-in-d first r> + swap node-out-d first general-t + ties get set-hash + ] [ + 2drop + ] ifte + ] ifte ; + +\ make-tuple [ + dup node-in-d first literal-value 1vector +] "output-classes" set-word-prop + +: output-classes ( node -- seq ) + dup node-param "output-classes" word-prop [ + call + ] [ + node-param "infer-effect" word-prop second + ] ?ifte ; + +M: #call infer-classes* ( node -- ) + dup node-param [ + dup create-ties + dup output-classes swap node-out-d intersect-classes + ] [ + drop + ] ifte ; + +M: #push infer-classes* ( node -- ) + node-out-d dup [ literal-value ] map swap assume-literals ; + +M: #ifte child-ties ( node -- seq ) + node-in-d first dup general-t + swap f 2vector ; + +M: #dispatch child-ties ( node -- seq ) + dup node-in-d first + swap node-children length [ ] map-with ; + +DEFER: (infer-classes) + +: infer-children ( node -- ) + dup node-children swap child-ties [ + [ + value-classes [ clone ] change + ties [ clone ] change + apply-tie + (infer-classes) + ] with-scope + ] 2each ; + +: (infer-classes) ( node -- ) + [ + dup infer-classes* + dup annotate-node + dup infer-children + node-successor (infer-classes) + ] when* ; + +: infer-classes ( node -- ) + [ + {{ }} clone value-classes set + {{ }} clone value-literals set + {{ }} clone ties set + (infer-classes) + ] with-scope ; diff --git a/library/inference/conditions.factor b/library/inference/conditions.factor deleted file mode 100644 index dad8880c33..0000000000 --- a/library/inference/conditions.factor +++ /dev/null @@ -1,38 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: inference -USING: errors interpreter kernel lists namespaces prettyprint -sequences io ; - -DEFER: recursive-state - -: inference-condition ( msg symbol -- ) - [ - , , recursive-state get , meta-d get , meta-r get , - ] make-list ; - -: inference-condition. ( cond msg -- ) - "! " write write - cdr unswons error. - "! Recursive state:" print - car [ "! " write . ] each ; - -: inference-error ( msg -- ) - #! Signalled if your code is malformed in some - #! statically-provable way. - \ inference-error inference-condition throw ; - -PREDICATE: cons inference-error car \ inference-error = ; -M: inference-error error. ( error -- ) - "Inference error: " inference-condition. ; - -: inference-warning ( msg -- ) - "inference-warnings" get [ - \ inference-warning inference-condition error. - ] [ - drop - ] ifte ; - -PREDICATE: cons inference-warning car \ inference-warning = ; -M: inference-warning error. ( error -- ) - "Inference warning: " inference-condition. ; diff --git a/library/inference/dataflow.factor b/library/inference/dataflow.factor index 72b295c1eb..da77a27337 100644 --- a/library/inference/dataflow.factor +++ b/library/inference/dataflow.factor @@ -4,28 +4,74 @@ IN: inference USING: generic interpreter kernel lists namespaces parser sequences vectors words ; +! Recursive state. An alist, mapping words to labels. +SYMBOL: recursive-state + +TUPLE: value recursion uid ; + +C: value ( -- value ) + gensym over set-value-uid + recursive-state get over set-value-recursion ; + +M: value = eq? ; + +TUPLE: computed ; + +C: computed ( -- value ) over set-delegate ; + +TUPLE: literal value ; + +C: literal ( obj -- value ) + over set-delegate + [ set-literal-value ] keep ; + +TUPLE: meet values ; + +C: meet ( values -- value ) + over set-delegate [ set-meet-values ] keep ; + +: value-refers? ( referee referrer -- ? ) + 2dup eq? [ + 2drop t + ] [ + dup meet? [ + meet-values [ value-refers? ] contains-with? + ] [ + 2drop f + ] ifte + ] ifte ; + ! The dataflow IR is the first of the two intermediate ! representations used by Factor. It annotates concatenative ! code with stack flow information and types. -TUPLE: node effect param in-d out-d in-r out-r +TUPLE: node param in-d out-d in-r out-r + classes literals history successor children ; -: make-node ( effect param in-d out-d in-r out-r node -- node ) - [ >r f r> set-delegate ] keep ; +M: node = eq? ; -: empty-node f f f f f f f f f ; -: param-node ( label) f swap f f f f f ; -: in-d-node ( inputs) >r f f r> f f f f ; -: out-d-node ( outputs) >r f f f r> f f f ; +: make-node ( param in-d out-d in-r out-r node -- node ) + [ + >r {{ }} clone {{ }} clone { } clone f f r> + set-delegate + ] keep ; -: d-tail ( n -- list ) meta-d get tail* >list ; -: r-tail ( n -- list ) meta-r get tail* >list ; +: param-node ( label) { } { } { } { } ; +: in-d-node ( inputs) >r f r> { } { } { } ; +: out-d-node ( outputs) >r f { } r> { } { } ; + +: d-tail ( n -- list ) meta-d get tail* >vector ; +: r-tail ( n -- list ) meta-r get tail* >vector ; TUPLE: #label ; C: #label make-node ; : #label ( label -- node ) param-node <#label> ; +TUPLE: #entry ; +C: #entry make-node ; +: #entry ( -- node ) meta-d get clone in-d-node <#entry> ; + TUPLE: #call ; C: #call make-node ; : #call ( word -- node ) param-node <#call> ; @@ -44,11 +90,11 @@ C: #drop make-node ; TUPLE: #values ; C: #values make-node ; -: #values ( -- node ) meta-d get >list in-d-node <#values> ; +: #values ( -- node ) meta-d get clone in-d-node <#values> ; TUPLE: #return ; C: #return make-node ; -: #return ( -- node ) meta-d get >list in-d-node <#return> ; +: #return ( -- node ) meta-d get clone in-d-node <#return> ; TUPLE: #ifte ; C: #ifte make-node ; @@ -58,6 +104,10 @@ TUPLE: #dispatch ; C: #dispatch make-node ; : #dispatch ( in -- node ) 1 d-tail in-d-node <#dispatch> ; +TUPLE: #merge ; +C: #merge make-node ; +: #merge ( -- node ) meta-d get clone out-d-node <#merge> ; + : node-inputs ( d-count r-count node -- ) tuck >r r-tail r> set-node-in-r @@ -86,7 +136,7 @@ SYMBOL: current-node current-node get current-node off ; : unnest-node ( new-node dataflow current -- new-node ) - >r >r dataflow-graph get unit over set-node-children + >r >r dataflow-graph get 1vector over set-node-children r> dataflow-graph set r> current-node set ; @@ -102,16 +152,129 @@ SYMBOL: current-node : node-effect ( node -- [[ d-in meta-d ]] ) dup node-in-d swap node-out-d cons ; -: consumes-literal? ( literal node -- ? ) - #! Does the dataflow node consume the literal? - 2dup node-in-d memq? >r node-in-r memq? r> or ; +: node-values ( node -- values ) + [ + dup node-in-d % dup node-out-d % + dup node-in-r % node-out-r % + ] { } make ; -: produces-literal? ( literal node -- ? ) - #! Does the dataflow node produce the literal? - 2dup node-out-d memq? >r node-out-r memq? r> or ; +: uses-value? ( value node -- ? ) + node-values [ value-refers? ] contains-with? ; : last-node ( node -- last ) dup node-successor [ last-node ] [ ] ?ifte ; -! Recursive state. An alist, mapping words to labels. -SYMBOL: recursive-state +: penultimate-node ( node -- penultimate ) + dup node-successor dup [ + dup node-successor + [ nip penultimate-node ] [ drop ] ifte + ] [ + 2drop f + ] ifte ; + +: drop-inputs ( node -- #drop ) + node-in-d clone in-d-node <#drop> ; + +: each-node ( node quot -- | quot: node -- ) + over [ + [ call ] 2keep swap + [ node-children [ swap each-node ] each-with ] 2keep + node-successor swap each-node + ] [ + 2drop + ] ifte ; inline + +: each-node-with ( obj node quot -- | quot: obj node -- ) + swap [ with ] each-node 2drop ; inline + +: all-nodes? ( node quot -- ? | quot: node -- ? ) + over [ + [ call ] 2keep rot [ + [ + swap node-children [ swap all-nodes? ] all-with? + ] 2keep rot [ + >r node-successor r> all-nodes? + ] [ + 2drop f + ] ifte + ] [ + 2drop f + ] ifte + ] [ + 2drop t + ] ifte ; inline + +: all-nodes-with? ( obj node quot -- ? | quot: obj node -- ? ) + swap [ with rot ] all-nodes? 2nip ; inline + +SYMBOL: substituted + +DEFER: subst-value + +: subst-meet ( new old meet -- ) + #! We avoid mutating the same meet more than once, since + #! doing so can introduce cycles. + dup substituted get memq? [ + 3drop + ] [ + dup substituted get push meet-values subst-value + ] ifte ; + +: (subst-value) ( new old value -- value ) + 2dup eq? [ + 2drop + ] [ + dup meet? [ + pick over swap value-refers? [ + 2nip ! don't substitute a meet into itself + ] [ + [ subst-meet ] keep + ] ifte + ] [ + 2nip + ] ifte + ] ifte ; + +: subst-value ( new old seq -- ) + pick pick eq? over empty? or [ + 3drop + ] [ + [ >r 2dup r> (subst-value) ] nmap 2drop + ] ifte ; + +: (subst-values) ( newseq oldseq seq -- ) + #! Mutates seq. + -rot [ pick subst-value ] 2each drop ; + +: subst-values ( new old node -- ) + #! Mutates the node. + [ + { } clone substituted set [ + 3dup node-in-d (subst-values) + 3dup node-in-r (subst-values) + 3dup node-out-d (subst-values) + 3dup node-out-r (subst-values) + drop + ] each-node 2drop + ] with-scope ; + +: remember-node ( word node -- ) + #! Annotate each node with the fact it was inlined from + #! 'word'. + [ + dup #call? [ node-history push ] [ 2drop ] ifte + ] each-node-with ; + +: (clone-node) ( node -- node ) + clone + dup node-in-d clone over set-node-in-d + dup node-in-r clone over set-node-in-r + dup node-out-d clone over set-node-out-d + dup node-out-r clone over set-node-out-r ; + +: clone-node ( node -- node ) + dup [ + (clone-node) + dup node-children [ clone-node ] map over set-node-children + dup node-successor clone-node over set-node-successor + ] when ; diff --git a/library/inference/inference.factor b/library/inference/inference.factor index 66e2c8df47..f5d7740481 100644 --- a/library/inference/inference.factor +++ b/library/inference/inference.factor @@ -1,12 +1,36 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: inference -USING: errors generic interpreter kernel lists math namespaces -prettyprint sequences strings unparser vectors words ; +USING: errors generic interpreter io kernel lists math +namespaces parser prettyprint sequences strings vectors words ; ! This variable takes a boolean value. SYMBOL: inferring-base-case +! Called when a recursive call during base case inference is +! found. Either tries to infer another branch, or gives up. +SYMBOL: base-case-continuation + +TUPLE: inference-error message rstate data-stack call-stack ; + +: inference-error ( msg -- ) + recursive-state get meta-d get meta-r get + throw ; inline + +M: inference-error error. ( error -- ) + "! Inference error:" print + dup inference-error-message print + "! Recursive state:" print + inference-error-rstate sequence. ; + +M: value literal-value ( value -- ) + { + "A literal value was expected where a computed value was found.\n" + "This means the word you are inferring applies 'call' or 'execute'\n" + "to a value that is not known at compile time.\n" + "See the handbook for details." + } concat inference-error ; + ! Word properties that affect inference: ! - infer-effect -- must be set. controls number of inputs ! expected, and number of outputs produced. @@ -18,33 +42,16 @@ SYMBOL: inferring-base-case SYMBOL: d-in : pop-literal ( -- rstate obj ) - 1 #drop node, pop-d >literal< ; + 1 #drop node, pop-d dup value-recursion swap literal-value ; -: (ensure-types) ( typelist n stack -- ) - pick [ - 3dup >r >r car r> r> nth value-class-and - >r >r cdr r> 1 + r> (ensure-types) - ] [ - 3drop - ] ifte ; +: computed-value-vector ( n -- vector ) + empty-vector dup [ drop ] nmap ; -: ensure-types ( typelist stack -- ) - dup length pick length - dup 0 < [ - swap >r neg swap tail 0 r> - ] [ - swap - ] ifte (ensure-types) ; - -: required-inputs ( typelist stack -- values ) - >r dup length r> length - dup 0 > [ - swap head [ ] map - ] [ - 2drop f - ] ifte ; +: required-inputs ( n stack -- values ) + length - 0 max computed-value-vector ; : ensure-d ( typelist -- ) - dup meta-d get ensure-types - meta-d get required-inputs >vector dup + length meta-d get required-inputs dup meta-d [ append ] change d-in [ append ] change ; @@ -54,20 +61,21 @@ SYMBOL: d-in 2slip second length 0 rot node-outputs ; inline -: (present-effect) ( vector -- list ) - >list [ value-class ] map ; - -: present-effect ( [[ d-in meta-d ]] -- [ in-types out-types ] ) +: effect ( -- [[ in# out# ]] ) #! After inference is finished, collect information. - uncons >r (present-effect) r> (present-effect) 2list ; + d-in get length object >list + meta-d get length object >list 2list ; -: simple-effect ( [[ d-in meta-d ]] -- [[ in# out# ]] ) - #! After inference is finished, collect information. - uncons length >r length r> cons ; +: no-base-case ( word -- ) + { + "The base case of a recursive word could not be inferred.\n" + "This means the word calls itself in every control flow path.\n" + "See the handbook for details." + } concat inference-error ; : init-inference ( recursive-state -- ) init-interpreter - 0 d-in set + { } clone d-in set recursive-state set dataflow-graph off current-node off ; @@ -77,67 +85,57 @@ GENERIC: apply-object : apply-literal ( obj -- ) #! Literals are annotated with the current recursive #! state. - recursive-state get push-d 1 #push node, ; + push-d 1 #push node, ; M: object apply-object apply-literal ; +M: wrapper apply-object wrapped apply-literal ; + : active? ( -- ? ) #! Is this branch not terminated? d-in get meta-d get and ; -: effect ( -- [[ d-in meta-d ]] ) - d-in get meta-d get cons ; - : terminate ( -- ) #! Ignore this branch's stack effect. meta-d off meta-r off d-in off ; -: terminator? ( obj -- ? ) - #! Does it throw an error? - dup word? [ "terminator" word-prop ] [ drop f ] ifte ; - -: handle-terminator ( quot -- ) - #! If the quotation throws an error, do not count its stack - #! effect. - [ terminator? ] find drop -1 > [ terminate ] when ; - : infer-quot ( quot -- ) #! Recursive calls to this word are made for nested #! quotations. - active? [ - [ unswons apply-object infer-quot ] when* - ] [ - drop - ] ifte ; + [ active? [ apply-object t ] [ drop f ] ifte ] all? drop ; : infer-quot-value ( rstate quot -- ) - recursive-state get >r - swap recursive-state set - dup infer-quot handle-terminator - r> recursive-state set ; - -: check-active ( -- ) - active? [ "Provable runtime error" inference-error ] unless ; + recursive-state get >r swap recursive-state set + infer-quot r> recursive-state set ; : check-return ( -- ) #! Raise an error if word leaves values on return stack. meta-r get empty? [ - "Word leaves elements on return stack" inference-error + "Word leaves " meta-r get length number>string + " element(s) on return stack. Check >r/r> usage." append3 + inference-error ] unless ; : with-infer ( quot -- ) [ inferring-base-case off + [ no-base-case ] base-case-continuation set f init-inference call - check-active check-return ] with-scope ; : infer ( quot -- effect ) #! Stack effect of a quotation. - [ infer-quot effect present-effect ] with-infer ; + [ infer-quot effect ] with-infer ; + +: (dataflow) ( quot -- dataflow ) + infer-quot #return node, dataflow-graph get ; : dataflow ( quot -- dataflow ) #! Data flow of a quotation. - [ infer-quot #return node, dataflow-graph get ] with-infer ; + [ (dataflow) ] with-infer ; + +: dataflow-with ( quot stack -- effect ) + #! Infer starting from a stack of values. + [ meta-d set (dataflow) ] with-infer ; diff --git a/library/inference/inline-methods.factor b/library/inference/inline-methods.factor new file mode 100644 index 0000000000..81486d7778 --- /dev/null +++ b/library/inference/inline-methods.factor @@ -0,0 +1,74 @@ +! Copyright (C) 2004, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: inference +USING: generic hashtables kernel lists math namespaces sequences +vectors words ; + +! Method inlining optimization + +GENERIC: dispatching-values ( node word -- seq ) + +M: object dispatching-values 2drop { } ; + +M: simple-generic dispatching-values drop node-in-d peek 1vector ; + +M: 2generic dispatching-values drop node-in-d 2 swap tail* ; + +: node-classes* ( node seq -- seq ) + >r node-classes r> + [ swap hash [ object ] unless* ] map-with ; + +: dispatching-classes ( node -- seq ) + dup dup node-param dispatching-values node-classes* ; + +: already-inlined? ( node -- ? ) + #! Was this node inlined from definition of 'word'? + dup node-param swap node-history memq? ; + +: inlining-class ( #call -- class ) + #! If the generic dispatch can be eliminated, return the + #! class of the method that will always be invoked here. + dup already-inlined? [ + drop f + ] [ + dup dispatching-classes dup empty? [ + 2drop f + ] [ + dup [ = ] monotonic? [ + first swap node-param order min-class + ] [ + 2drop f + ] ifte + ] ifte + ] ifte ; + +: will-inline ( node -- quot ) + dup inlining-class swap node-param "methods" word-prop hash ; + +: method-dataflow ( node -- dataflow ) + dup will-inline swap node-in-d dataflow-with + dup solve-recursion ; + +: inline-method ( node -- node ) + #! We set the #call node's param to f so that it gets killed + #! later. + dup method-dataflow + [ >r node-param r> remember-node ] 2keep + [ subst-node ] keep ; + +: related? ( actual testing -- ? ) + #! If actual is a subset of testing or if the two classes + #! are disjoint, return t. + 2dup class< >r classes-intersect? not r> or ; + +: optimize-predicate? ( #call -- ? ) + dup node-param "predicating" word-prop dup [ + >r dup node-in-d node-classes* first r> related? + ] [ + 2drop f + ] ifte ; + +: optimize-predicate ( #call -- node ) + dup node-param "predicating" word-prop >r + dup dup node-in-d node-classes* first r> class< + 1vector inline-literals ; diff --git a/library/inference/kill-literals.factor b/library/inference/kill-literals.factor new file mode 100644 index 0000000000..4a5e08bb13 --- /dev/null +++ b/library/inference/kill-literals.factor @@ -0,0 +1,103 @@ +! Copyright (C) 2004, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: inference +USING: generic hashtables inference kernel lists +matrices namespaces sequences vectors ; + +GENERIC: literals* ( node -- ) + +: literals ( node -- seq ) + [ [ literals* ] each-node ] { } make ; + +GENERIC: can-kill? ( literal node -- ? ) + +: kill-set ( node -- list ) + #! Push a list of literals that may be killed in the IR. + dup literals [ + swap [ can-kill? ] all-nodes-with? + ] subset-with ; + +: remove-values ( values node -- ) + 2dup [ node-in-d seq-diff ] keep set-node-in-d + 2dup [ node-out-d seq-diff ] keep set-node-out-d + 2dup [ node-in-r seq-diff ] keep set-node-in-r + [ node-out-r seq-diff ] keep set-node-out-r ; + +GENERIC: kill-node* ( literals node -- ) + +M: node kill-node* ( literals node -- ) 2drop ; + +: kill-node ( literals node -- ) + [ 2dup kill-node* remove-values ] each-node-with ; + +! Generic nodes +M: node literals* ( node -- ) drop ; + +M: node can-kill? ( literal node -- ? ) uses-value? not ; + +! #push +M: #push literals* ( node -- ) + node-out-d % ; + +M: #push can-kill? ( literal node -- ? ) 2drop t ; + +M: #push kill-node* ( literals node -- ) + [ node-out-d seq-diff ] keep set-node-out-d ; + +! #drop +M: #drop can-kill? ( literal node -- ? ) 2drop t ; + +! #call +: (kill-shuffle) ( word -- map ) + {{ + [[ dup {{ }} ]] + [[ drop {{ }} ]] + [[ swap {{ }} ]] + [[ over + {{ + [[ { f t } dup ]] + }} + ]] + [[ pick + {{ + [[ { f f t } over ]] + [[ { f t f } over ]] + [[ { f t t } dup ]] + }} + ]] + [[ >r {{ }} ]] + [[ r> {{ }} ]] + }} hash ; + +M: #call can-kill? ( literal node -- ? ) + dup node-param (kill-shuffle) >r delegate can-kill? r> or ; + +: kill-mask ( killing node -- mask ) + dup node-param \ r> = [ node-in-r ] [ node-in-d ] ifte + [ swap memq? ] map-with ; + +: lookup-mask ( mask word -- word ) + over [ ] contains? [ (kill-shuffle) hash ] [ nip ] ifte ; + +: kill-shuffle ( literals node -- ) + #! If certain values passing through a stack op are being + #! killed, the stack op can be reduced, in extreme cases + #! to a no-op. + [ [ kill-mask ] keep node-param lookup-mask ] keep + set-node-param ; + +M: #call kill-node* ( literals node -- ) + dup node-param (kill-shuffle) + [ kill-shuffle ] [ 2drop ] ifte ; + +! #call-label +M: #call-label can-kill? ( literal node -- ? ) 2drop t ; + +! #values +M: #values can-kill? ( literal node -- ? ) 2drop t ; + +! #merge +M: #merge can-kill? ( literal node -- ? ) 2drop t ; + +! #entry +M: #entry can-kill? ( literal node -- ? ) 2drop t ; diff --git a/library/inference/known-words.factor b/library/inference/known-words.factor new file mode 100644 index 0000000000..cbddc25e02 --- /dev/null +++ b/library/inference/known-words.factor @@ -0,0 +1,519 @@ +IN: inference +USING: alien assembler errors generic hashtables interpreter io +io-internals kernel kernel-internals lists math math-internals +memory parser sequences strings vectors words prettyprint ; + +! Primitive combinators +\ call [ [ general-list ] [ ] ] "infer-effect" set-word-prop + +\ call [ + pop-literal infer-quot-value +] "infer" set-word-prop + +\ execute [ [ word ] [ ] ] "infer-effect" set-word-prop + +\ execute [ + pop-literal unit infer-quot-value +] "infer" set-word-prop + +\ ifte [ [ object general-list general-list ] [ ] ] "infer-effect" set-word-prop + +\ ifte [ + 2 #drop node, pop-d pop-d swap 2vector + #ifte pop-d drop infer-branches +] "infer" set-word-prop + +\ cond [ [ object ] [ ] ] "infer-effect" set-word-prop + +\ cond [ + pop-literal [ first2 cons ] map reverse-slice + [ no-cond ] swap alist>quot infer-quot-value +] "infer" set-word-prop + +\ dispatch [ [ fixnum vector ] [ ] ] "infer-effect" set-word-prop + +\ dispatch [ + pop-literal nip [ ] map + #dispatch pop-d drop infer-branches +] "infer" set-word-prop + +! Stack manipulation +\ >r [ [ object ] [ ] ] "infer-effect" set-word-prop + +\ >r [ + \ >r #call + 1 0 pick node-inputs + pop-d push-r + 0 1 pick node-outputs + node, +] "infer" set-word-prop + +\ r> [ [ ] [ object ] ] "infer-effect" set-word-prop + +\ r> [ + \ r> #call + 0 1 pick node-inputs + pop-r push-d + 1 0 pick node-outputs + node, +] "infer" set-word-prop + +\ drop [ 1 #drop node, pop-d drop ] "infer" set-word-prop +\ drop [ [ object ] [ ] ] "infer-effect" set-word-prop + +\ dup [ \ dup infer-shuffle ] "infer" set-word-prop +\ dup [ [ object ] [ object object ] ] "infer-effect" set-word-prop + +\ swap [ \ swap infer-shuffle ] "infer" set-word-prop +\ swap [ [ object object ] [ object object ] ] "infer-effect" set-word-prop + +\ over [ \ over infer-shuffle ] "infer" set-word-prop +\ over [ [ object object ] [ object object object ] ] "infer-effect" set-word-prop + +\ pick [ \ pick infer-shuffle ] "infer" set-word-prop +\ pick [ [ object object object ] [ object object object object ] ] "infer-effect" set-word-prop + +! Non-standard control flow +\ throw [ [ object ] [ ] ] "infer-effect" set-word-prop + +\ throw [ + \ throw dup "infer-effect" word-prop consume/produce + terminate +] "infer" set-word-prop + +! Stack effects for all primitives +\ cons [ [ object object ] [ cons ] ] "infer-effect" set-word-prop +\ cons t "foldable" set-word-prop +\ cons t "flushable" set-word-prop + +\ [ [ integer ] [ vector ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ rehash-string [ [ string ] [ ] ] "infer-effect" set-word-prop + +\ [ [ integer ] [ sbuf ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ sbuf>string [ [ sbuf ] [ string ] ] "infer-effect" set-word-prop +\ sbuf>string t "flushable" set-word-prop + +\ >fixnum [ [ number ] [ fixnum ] ] "infer-effect" set-word-prop +\ >fixnum t "flushable" set-word-prop +\ >fixnum t "foldable" set-word-prop + +\ >bignum [ [ number ] [ bignum ] ] "infer-effect" set-word-prop +\ >bignum t "flushable" set-word-prop +\ >bignum t "foldable" set-word-prop + +\ >float [ [ number ] [ float ] ] "infer-effect" set-word-prop +\ >float t "flushable" set-word-prop +\ >float t "foldable" set-word-prop + +\ (fraction>) [ [ integer integer ] [ rational ] ] "infer-effect" set-word-prop +\ (fraction>) t "flushable" set-word-prop +\ (fraction>) t "foldable" set-word-prop + +\ string>float [ [ string ] [ float ] ] "infer-effect" set-word-prop +\ string>float t "flushable" set-word-prop +\ string>float t "foldable" set-word-prop + +\ float>string [ [ float ] [ string ] ] "infer-effect" set-word-prop +\ float>string t "flushable" set-word-prop +\ float>string t "foldable" set-word-prop + +\ float>bits [ [ real ] [ integer ] ] "infer-effect" set-word-prop +\ float>bits t "flushable" set-word-prop +\ float>bits t "foldable" set-word-prop + +\ double>bits [ [ real ] [ integer ] ] "infer-effect" set-word-prop +\ double>bits t "flushable" set-word-prop +\ double>bits t "foldable" set-word-prop + +\ bits>float [ [ integer ] [ float ] ] "infer-effect" set-word-prop +\ bits>float t "flushable" set-word-prop +\ bits>float t "foldable" set-word-prop + +\ bits>double [ [ integer ] [ float ] ] "infer-effect" set-word-prop +\ bits>double t "flushable" set-word-prop +\ bits>double t "foldable" set-word-prop + +\ [ [ real real ] [ number ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop +\ t "foldable" set-word-prop + +\ fixnum+ [ [ fixnum fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ fixnum+ t "flushable" set-word-prop +\ fixnum+ t "foldable" set-word-prop + +\ fixnum- [ [ fixnum fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ fixnum- t "flushable" set-word-prop +\ fixnum- t "foldable" set-word-prop + +\ fixnum* [ [ fixnum fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ fixnum* t "flushable" set-word-prop +\ fixnum* t "foldable" set-word-prop + +\ fixnum/i [ [ fixnum fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ fixnum/i t "flushable" set-word-prop +\ fixnum/i t "foldable" set-word-prop + +\ fixnum/f [ [ fixnum fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ fixnum/f t "flushable" set-word-prop +\ fixnum/f t "foldable" set-word-prop + +\ fixnum-mod [ [ fixnum fixnum ] [ fixnum ] ] "infer-effect" set-word-prop +\ fixnum-mod t "flushable" set-word-prop +\ fixnum-mod t "foldable" set-word-prop + +\ fixnum/mod [ [ fixnum fixnum ] [ integer fixnum ] ] "infer-effect" set-word-prop +\ fixnum/mod t "flushable" set-word-prop +\ fixnum/mod t "foldable" set-word-prop + +\ fixnum-bitand [ [ fixnum fixnum ] [ fixnum ] ] "infer-effect" set-word-prop +\ fixnum-bitand t "flushable" set-word-prop +\ fixnum-bitand t "foldable" set-word-prop + +\ fixnum-bitor [ [ fixnum fixnum ] [ fixnum ] ] "infer-effect" set-word-prop +\ fixnum-bitor t "flushable" set-word-prop +\ fixnum-bitor t "foldable" set-word-prop + +\ fixnum-bitxor [ [ fixnum fixnum ] [ fixnum ] ] "infer-effect" set-word-prop +\ fixnum-bitxor t "flushable" set-word-prop +\ fixnum-bitxor t "foldable" set-word-prop + +\ fixnum-bitnot [ [ fixnum ] [ fixnum ] ] "infer-effect" set-word-prop +\ fixnum-bitnot t "flushable" set-word-prop +\ fixnum-bitnot t "foldable" set-word-prop + +\ fixnum-shift [ [ fixnum fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ fixnum-shift t "flushable" set-word-prop +\ fixnum-shift t "foldable" set-word-prop + +\ fixnum< [ [ fixnum fixnum ] [ boolean ] ] "infer-effect" set-word-prop +\ fixnum< t "flushable" set-word-prop +\ fixnum< t "foldable" set-word-prop + +\ fixnum<= [ [ fixnum fixnum ] [ boolean ] ] "infer-effect" set-word-prop +\ fixnum<= t "flushable" set-word-prop +\ fixnum<= t "foldable" set-word-prop + +\ fixnum> [ [ fixnum fixnum ] [ boolean ] ] "infer-effect" set-word-prop +\ fixnum> t "flushable" set-word-prop +\ fixnum> t "foldable" set-word-prop + +\ fixnum>= [ [ fixnum fixnum ] [ boolean ] ] "infer-effect" set-word-prop +\ fixnum>= t "flushable" set-word-prop +\ fixnum>= t "foldable" set-word-prop + +\ bignum= [ [ bignum bignum ] [ boolean ] ] "infer-effect" set-word-prop +\ bignum= t "flushable" set-word-prop +\ bignum= t "foldable" set-word-prop + +\ bignum+ [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum+ t "flushable" set-word-prop +\ bignum+ t "foldable" set-word-prop + +\ bignum- [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum- t "flushable" set-word-prop +\ bignum- t "foldable" set-word-prop + +\ bignum* [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum* t "flushable" set-word-prop +\ bignum* t "foldable" set-word-prop + +\ bignum/i [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum/i t "flushable" set-word-prop +\ bignum/i t "foldable" set-word-prop + +\ bignum/f [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum/f t "flushable" set-word-prop +\ bignum/f t "foldable" set-word-prop + +\ bignum-mod [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum-mod t "flushable" set-word-prop +\ bignum-mod t "foldable" set-word-prop + +\ bignum/mod [ [ bignum bignum ] [ bignum bignum ] ] "infer-effect" set-word-prop +\ bignum/mod t "flushable" set-word-prop +\ bignum/mod t "foldable" set-word-prop + +\ bignum-bitand [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum-bitand t "flushable" set-word-prop +\ bignum-bitand t "foldable" set-word-prop + +\ bignum-bitor [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum-bitor t "flushable" set-word-prop +\ bignum-bitor t "foldable" set-word-prop + +\ bignum-bitxor [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum-bitxor t "flushable" set-word-prop +\ bignum-bitxor t "foldable" set-word-prop + +\ bignum-bitnot [ [ bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum-bitnot t "flushable" set-word-prop +\ bignum-bitnot t "foldable" set-word-prop + +\ bignum-shift [ [ bignum bignum ] [ bignum ] ] "infer-effect" set-word-prop +\ bignum-shift t "flushable" set-word-prop +\ bignum-shift t "foldable" set-word-prop + +\ bignum< [ [ bignum bignum ] [ boolean ] ] "infer-effect" set-word-prop +\ bignum< t "flushable" set-word-prop +\ bignum< t "foldable" set-word-prop + +\ bignum<= [ [ bignum bignum ] [ boolean ] ] "infer-effect" set-word-prop +\ bignum<= t "flushable" set-word-prop +\ bignum<= t "foldable" set-word-prop + +\ bignum> [ [ bignum bignum ] [ boolean ] ] "infer-effect" set-word-prop +\ bignum> t "flushable" set-word-prop +\ bignum> t "foldable" set-word-prop + +\ bignum>= [ [ bignum bignum ] [ boolean ] ] "infer-effect" set-word-prop +\ bignum>= t "flushable" set-word-prop +\ bignum>= t "foldable" set-word-prop + +\ float= [ [ bignum bignum ] [ boolean ] ] "infer-effect" set-word-prop +\ float= t "flushable" set-word-prop +\ float= t "foldable" set-word-prop + +\ float+ [ [ float float ] [ float ] ] "infer-effect" set-word-prop +\ float+ t "flushable" set-word-prop +\ float+ t "foldable" set-word-prop + +\ float- [ [ float float ] [ float ] ] "infer-effect" set-word-prop +\ float- t "flushable" set-word-prop +\ float- t "foldable" set-word-prop + +\ float* [ [ float float ] [ float ] ] "infer-effect" set-word-prop +\ float* t "flushable" set-word-prop +\ float* t "foldable" set-word-prop + +\ float/f [ [ float float ] [ float ] ] "infer-effect" set-word-prop +\ float/f t "flushable" set-word-prop +\ float/f t "foldable" set-word-prop + +\ float< [ [ float float ] [ boolean ] ] "infer-effect" set-word-prop +\ float< t "flushable" set-word-prop +\ float< t "foldable" set-word-prop + +\ float<= [ [ float float ] [ boolean ] ] "infer-effect" set-word-prop +\ float<= t "flushable" set-word-prop +\ float<= t "foldable" set-word-prop + +\ float> [ [ float float ] [ boolean ] ] "infer-effect" set-word-prop +\ float> t "flushable" set-word-prop +\ float> t "foldable" set-word-prop + +\ float>= [ [ float float ] [ boolean ] ] "infer-effect" set-word-prop +\ float>= t "flushable" set-word-prop +\ float>= t "foldable" set-word-prop + +\ facos [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ facos t "flushable" set-word-prop +\ facos t "foldable" set-word-prop + +\ fasin [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fasin t "flushable" set-word-prop +\ fasin t "foldable" set-word-prop + +\ fatan [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fatan t "flushable" set-word-prop +\ fatan t "foldable" set-word-prop + +\ fatan2 [ [ real real ] [ float ] ] "infer-effect" set-word-prop +\ fatan2 t "flushable" set-word-prop +\ fatan2 t "foldable" set-word-prop + +\ fcos [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fcos t "flushable" set-word-prop +\ fcos t "foldable" set-word-prop + +\ fexp [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fexp t "flushable" set-word-prop +\ fexp t "foldable" set-word-prop + +\ fcosh [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fcosh t "flushable" set-word-prop +\ fcosh t "foldable" set-word-prop + +\ flog [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ flog t "flushable" set-word-prop +\ flog t "foldable" set-word-prop + +\ fpow [ [ real real ] [ float ] ] "infer-effect" set-word-prop +\ fpow t "flushable" set-word-prop +\ fpow t "foldable" set-word-prop + +\ fsin [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fsin t "flushable" set-word-prop +\ fsin t "foldable" set-word-prop + +\ fsinh [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fsinh t "flushable" set-word-prop +\ fsinh t "foldable" set-word-prop + +\ fsqrt [ [ real ] [ float ] ] "infer-effect" set-word-prop +\ fsqrt t "flushable" set-word-prop +\ fsqrt t "foldable" set-word-prop + +\ [ [ object object ] [ word ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ update-xt [ [ word ] [ ] ] "infer-effect" set-word-prop +\ compiled? [ [ word ] [ boolean ] ] "infer-effect" set-word-prop + +\ eq? [ [ object object ] [ boolean ] ] "infer-effect" set-word-prop +\ eq? t "flushable" set-word-prop +\ eq? t "foldable" set-word-prop + +\ getenv [ [ fixnum ] [ object ] ] "infer-effect" set-word-prop +\ setenv [ [ object fixnum ] [ ] ] "infer-effect" set-word-prop +\ stat [ [ string ] [ general-list ] ] "infer-effect" set-word-prop +\ (directory) [ [ string ] [ general-list ] ] "infer-effect" set-word-prop +\ gc [ [ fixnum ] [ ] ] "infer-effect" set-word-prop +\ gc-time [ [ string ] [ ] ] "infer-effect" set-word-prop +\ save-image [ [ string ] [ ] ] "infer-effect" set-word-prop +\ exit [ [ integer ] [ ] ] "infer-effect" set-word-prop +\ room [ [ ] [ integer integer integer integer general-list ] ] "infer-effect" set-word-prop +\ os-env [ [ string ] [ object ] ] "infer-effect" set-word-prop +\ millis [ [ ] [ integer ] ] "infer-effect" set-word-prop +\ (random-int) [ [ ] [ integer ] ] "infer-effect" set-word-prop + +\ type [ [ object ] [ fixnum ] ] "infer-effect" set-word-prop +\ type t "flushable" set-word-prop +\ type t "foldable" set-word-prop + +\ tag [ [ object ] [ fixnum ] ] "infer-effect" set-word-prop +\ tag t "flushable" set-word-prop +\ tag t "foldable" set-word-prop + +\ cwd [ [ ] [ string ] ] "infer-effect" set-word-prop +\ cd [ [ string ] [ ] ] "infer-effect" set-word-prop + +\ compiled-offset [ [ ] [ integer ] ] "infer-effect" set-word-prop +\ compiled-offset t "flushable" set-word-prop + +\ set-compiled-offset [ [ integer ] [ ] ] "infer-effect" set-word-prop + +\ literal-top [ [ ] [ integer ] ] "infer-effect" set-word-prop +\ literal-top t "flushable" set-word-prop + +\ set-literal-top [ [ integer ] [ ] ] "infer-effect" set-word-prop + +\ address [ [ object ] [ integer ] ] "infer-effect" set-word-prop +\ address t "flushable" set-word-prop + +\ dlopen [ [ string ] [ dll ] ] "infer-effect" set-word-prop +\ dlsym [ [ string object ] [ integer ] ] "infer-effect" set-word-prop +\ dlclose [ [ dll ] [ ] ] "infer-effect" set-word-prop + +\ [ [ integer ] [ alien ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ [ [ integer ] [ byte-array ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ [ [ integer c-ptr ] [ displaced-alien ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ alien-signed-cell [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-signed-cell t "flushable" set-word-prop + +\ set-alien-signed-cell [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-unsigned-cell [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-unsigned-cell t "flushable" set-word-prop + +\ set-alien-unsigned-cell [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-signed-8 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-signed-8 t "flushable" set-word-prop + +\ set-alien-signed-8 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-unsigned-8 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-unsigned-8 t "flushable" set-word-prop + +\ set-alien-unsigned-8 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-signed-4 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-signed-4 t "flushable" set-word-prop + +\ set-alien-signed-4 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-unsigned-4 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-unsigned-4 t "flushable" set-word-prop + +\ set-alien-unsigned-4 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-signed-2 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-signed-2 t "flushable" set-word-prop + +\ set-alien-signed-2 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-unsigned-2 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-unsigned-2 t "flushable" set-word-prop + +\ set-alien-unsigned-2 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-signed-1 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-signed-1 t "flushable" set-word-prop + +\ set-alien-signed-1 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-unsigned-1 [ [ c-ptr integer ] [ integer ] ] "infer-effect" set-word-prop +\ alien-unsigned-1 t "flushable" set-word-prop + +\ set-alien-unsigned-1 [ [ integer c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-float [ [ c-ptr integer ] [ float ] ] "infer-effect" set-word-prop +\ alien-float t "flushable" set-word-prop + +\ set-alien-float [ [ float c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-double [ [ c-ptr integer ] [ float ] ] "infer-effect" set-word-prop +\ alien-double t "flushable" set-word-prop + +\ set-alien-double [ [ float c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ alien-c-string [ [ c-ptr integer ] [ string ] ] "infer-effect" set-word-prop +\ alien-c-string t "flushable" set-word-prop + +\ set-alien-c-string [ [ string c-ptr integer ] [ ] ] "infer-effect" set-word-prop +\ string>memory [ [ string integer ] [ ] ] "infer-effect" set-word-prop +\ memory>string [ [ integer integer ] [ string ] ] "infer-effect" set-word-prop +\ alien-address [ [ alien ] [ integer ] ] "infer-effect" set-word-prop + +\ slot [ [ object fixnum ] [ object ] ] "infer-effect" set-word-prop +\ slot t "flushable" set-word-prop + +\ set-slot [ [ object object fixnum ] [ ] ] "infer-effect" set-word-prop + +\ integer-slot [ [ object fixnum ] [ integer ] ] "infer-effect" set-word-prop +\ integer-slot t "flushable" set-word-prop + +\ set-integer-slot [ [ integer object fixnum ] [ ] ] "infer-effect" set-word-prop + +\ char-slot [ [ object fixnum ] [ fixnum ] ] "infer-effect" set-word-prop +\ char-slot t "flushable" set-word-prop + +\ set-char-slot [ [ integer object fixnum ] [ ] ] "infer-effect" set-word-prop +\ resize-array [ [ integer array ] [ array ] ] "infer-effect" set-word-prop +\ resize-string [ [ integer string ] [ string ] ] "infer-effect" set-word-prop + +\ [ [ number ] [ hashtable ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ [ [ number ] [ array ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ [ [ number ] [ tuple ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop + +\ begin-scan [ [ ] [ ] ] "infer-effect" set-word-prop +\ next-object [ [ ] [ object ] ] "infer-effect" set-word-prop +\ end-scan [ [ ] [ ] ] "infer-effect" set-word-prop + +\ size [ [ object ] [ fixnum ] ] "infer-effect" set-word-prop +\ size t "flushable" set-word-prop + +\ die [ [ ] [ ] ] "infer-effect" set-word-prop +\ fopen [ [ string string ] [ alien ] ] "infer-effect" set-word-prop +\ fgetc [ [ alien ] [ object ] ] "infer-effect" set-word-prop +\ fwrite [ [ string alien ] [ ] ] "infer-effect" set-word-prop +\ fflush [ [ alien ] [ ] ] "infer-effect" set-word-prop +\ fclose [ [ alien ] [ ] ] "infer-effect" set-word-prop +\ expired? [ [ object ] [ boolean ] ] "infer-effect" set-word-prop + +\ [ [ object ] [ wrapper ] ] "infer-effect" set-word-prop +\ t "flushable" set-word-prop +\ t "foldable" set-word-prop diff --git a/library/inference/optimizer.factor b/library/inference/optimizer.factor new file mode 100644 index 0000000000..5d0a0bf108 --- /dev/null +++ b/library/inference/optimizer.factor @@ -0,0 +1,94 @@ +! Copyright (C) 2004, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: inference +USING: generic hashtables inference kernel lists +matrices namespaces sequences vectors ; + +! We use the recursive-state variable here, to track nested +! label scopes, to prevent infinite loops when inlining +! recursive methods. + +GENERIC: optimize-node* ( node -- node ) + +: keep-optimizing ( node -- node ? ) + dup optimize-node* dup t = + [ drop f ] [ nip keep-optimizing t or ] ifte ; + +DEFER: optimize-node + +: optimize-children ( node -- ) + f swap [ + node-children [ optimize-node swap >r or r> ] map + ] keep set-node-children ; + +: optimize-node ( node -- node ? ) + #! Outputs t if any changes were made. + keep-optimizing >r dup [ + dup optimize-children >r + dup node-successor optimize-node >r + over set-node-successor r> r> r> or or + ] [ r> ] ifte ; + +: optimize-loop ( dataflow -- dataflow ) + recursive-state off + dup kill-set over kill-node + dup infer-classes + optimize-node [ optimize-loop ] when ; + +: optimize ( dataflow -- dataflow ) + [ + dup solve-recursion dup split-node optimize-loop + ] with-scope ; + +: prune-if ( node quot -- successor/t ) + over >r call [ r> node-successor ] [ r> drop t ] ifte ; + inline + +! Generic nodes +M: f optimize-node* drop t ; + +M: node optimize-node* ( node -- t ) + drop t ; + +! #push +M: #push optimize-node* ( node -- node/t ) + [ node-out-d empty? ] prune-if ; + +! #drop +M: #drop optimize-node* ( node -- node/t ) + [ node-in-d empty? ] prune-if ; + +! #ifte +: static-branch? ( node -- lit ? ) + node-in-d first dup literal? ; + +: static-branch ( conditional n -- node ) + over drop-inputs + [ >r swap node-children nth r> set-node-successor ] keep ; + +M: #ifte optimize-node* ( node -- node ) + dup static-branch? + [ literal-value 0 1 ? static-branch ] [ 2drop t ] ifte ; + +! #values +: optimize-fold ( node -- node/t ) + node-successor [ node-successor ] [ t ] ifte* ; + +M: #values optimize-node* ( node -- node/t ) + optimize-fold ; + +! #return +M: #return optimize-node* ( node -- node/t ) + optimize-fold ; + +! M: #label optimize-node* ( node -- node/t ) +! dup node-param over node-children first calls-label? [ +! drop t +! ] [ +! dup node-children first dup node-successor [ +! dup penultimate-node rot +! node-successor swap set-node-successor +! ] [ +! drop node-successor +! ] ifte +! ] ifte ; diff --git a/library/inference/partial-eval.factor b/library/inference/partial-eval.factor deleted file mode 100644 index 850c0a7212..0000000000 --- a/library/inference/partial-eval.factor +++ /dev/null @@ -1,94 +0,0 @@ -! Copyright (C) 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: inference -USING: generic interpreter kernel lists math namespaces -sequences words ; - -: literal-inputs? ( in stack -- ) - tail-slice* dup [ safe-literal? ] all? - [ length #drop node, t ] [ drop f ] ifte ; - -: literal-inputs ( out stack -- ) - tail-slice* [ literal-value ] nmap ; - -: literal-outputs ( out stack -- ) - tail-slice* dup [ recursive-state get ] nmap - length #push node, ; - -: partial-eval? ( word -- ? ) - "infer-effect" word-prop car length - meta-d get literal-inputs? ; - -: infer-eval ( word -- ) - dup partial-eval? [ - dup "infer-effect" word-prop 2unlist - >r length meta-d get - literal-inputs - host-word - r> length meta-d get literal-outputs - ] [ - dup "infer-effect" word-prop consume/produce - ] ifte ; - -: stateless ( word -- ) - #! A stateless word can be evaluated at compile-time. - dup unit [ car infer-eval ] cons "infer" set-word-prop ; - -! Could probably add more words here -[ - eq? - car - cdr - cons - < - <= - > - >= - number= - + - - - * - / - /i - /f - mod - /mod - bitand - bitor - bitxor - shift - bitnot - >fixnum - >bignum - >float - real - imaginary -] [ - stateless -] each - -! Partially-evaluated words need their stack effects to be -! entered by hand. -\ car [ [ general-list ] [ object ] ] "infer-effect" set-word-prop -\ cdr [ [ general-list ] [ object ] ] "infer-effect" set-word-prop -\ < [ [ real real ] [ boolean ] ] "infer-effect" set-word-prop -\ <= [ [ real real ] [ boolean ] ] "infer-effect" set-word-prop -\ > [ [ real real ] [ boolean ] ] "infer-effect" set-word-prop -\ >= [ [ real real ] [ boolean ] ] "infer-effect" set-word-prop -\ number= [ [ real real ] [ boolean ] ] "infer-effect" set-word-prop -\ + [ [ number number ] [ number ] ] "infer-effect" set-word-prop -\ - [ [ number number ] [ number ] ] "infer-effect" set-word-prop -\ * [ [ number number ] [ number ] ] "infer-effect" set-word-prop -\ / [ [ number number ] [ number ] ] "infer-effect" set-word-prop -\ /i [ [ number number ] [ number ] ] "infer-effect" set-word-prop -\ /f [ [ number number ] [ number ] ] "infer-effect" set-word-prop -\ mod [ [ integer integer ] [ integer ] ] "infer-effect" set-word-prop -\ /mod [ [ integer integer ] [ integer integer ] ] "infer-effect" set-word-prop -\ bitand [ [ integer integer ] [ integer ] ] "infer-effect" set-word-prop -\ bitor [ [ integer integer ] [ integer ] ] "infer-effect" set-word-prop -\ bitxor [ [ integer integer ] [ integer ] ] "infer-effect" set-word-prop -\ shift [ [ integer integer ] [ integer ] ] "infer-effect" set-word-prop -\ bitnot [ [ integer ] [ integer ] ] "infer-effect" set-word-prop -\ gcd [ [ integer integer ] [ integer integer ] ] "infer-effect" set-word-prop -\ real [ [ number ] [ real ] ] "infer-effect" set-word-prop -\ imaginary [ [ number ] [ real ] ] "infer-effect" set-word-prop diff --git a/library/inference/print-dataflow.factor b/library/inference/print-dataflow.factor new file mode 100644 index 0000000000..3f7349bc7e --- /dev/null +++ b/library/inference/print-dataflow.factor @@ -0,0 +1,85 @@ +IN: inference +USING: generic hashtables inference io kernel kernel-internals +lists math namespaces prettyprint sequences styles vectors words ; + +! A simple tool for turning dataflow IR into quotations, for +! debugging purposes. + +GENERIC: node>quot ( node -- ) + +TUPLE: comment node text ; + +M: comment pprint* ( ann -- ) + "( " over comment-text " )" append3 + swap comment-node presented swons unit text ; + +: comment, ( ? node text -- ) + rot [ , ] [ 2drop ] ifte ; + +: value-str ( classes values -- str ) + [ swap hash [ object ] unless* ] map-with + [ word-name ] map + " " join ; + +: effect-str ( node -- str ) + [ + dup node-classes swap + 2dup node-in-d value-str % + "--" % + node-out-d value-str % + ] "" make ; + +M: #push node>quot ( ? node -- ) + node-out-d [ literal-value literalize ] map % drop ; + +M: #drop node>quot ( ? node -- ) + node-in-d length dup 3 > [ + \ drop + ] [ + { f [ drop ] [ 2drop ] [ 3drop ] } nth + ] ifte % drop ; + +DEFER: dataflow>quot + +: #call>quot ( ? node -- ) + dup node-param dup + [ , dup effect-str comment, ] [ 3drop ] ifte ; + +M: #call node>quot ( ? node -- ) #call>quot ; + +M: #call-label node>quot ( ? node -- ) #call>quot ; + +M: #label node>quot ( ? node -- ) + [ "#label: " over node-param word-name append comment, ] 2keep + node-children first swap dataflow>quot , \ call , ; + +M: #ifte node>quot ( ? node -- ) + [ "#ifte" comment, ] 2keep + node-children [ swap dataflow>quot ] map-with % \ ifte , ; + +M: #dispatch node>quot ( ? node -- ) + [ "#dispatch" comment, ] 2keep + node-children [ swap dataflow>quot ] map-with , \ dispatch , ; + +M: #return node>quot ( ? node -- ) "#return" comment, ; + +M: #values node>quot ( ? node -- ) "#values" comment, ; + +M: #merge node>quot ( ? node -- ) "#merge" comment, ; + +M: #entry node>quot ( ? node -- ) "#entry" comment, ; + +: (dataflow>quot) ( ? node -- ) + dup [ + 2dup node>quot node-successor (dataflow>quot) + ] [ + 2drop + ] ifte ; + +: dataflow>quot ( node ? -- quot ) + [ swap (dataflow>quot) ] [ ] make ; + +: dataflow. ( quot ? -- ) + #! Print dataflow IR for a quotation. Flag indicates if + #! annotations should be printed or not. + >r dataflow optimize r> dataflow>quot . ; diff --git a/library/inference/recursive-values.factor b/library/inference/recursive-values.factor new file mode 100644 index 0000000000..aff97af702 --- /dev/null +++ b/library/inference/recursive-values.factor @@ -0,0 +1,33 @@ +! Copyright (C) 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: inference +USING: kernel namespaces prettyprint sequences vectors ; + +GENERIC: collect-recursion* ( label node -- ) + +M: node collect-recursion* ( label node -- ) 2drop ; + +M: #call-label collect-recursion* ( label node -- ) + tuck node-param = [ node-in-d , ] [ drop ] ifte ; + +: collect-recursion ( label node -- seq ) + #! Collect the input stacks of all #call-label nodes that + #! call given label. + [ [ collect-recursion* ] each-node-with ] { } make ; + +GENERIC: solve-recursion* + +M: node solve-recursion* ( node -- ) drop ; + +: join-values ( calls entry -- new old ) + add unify-lengths [ unify-stacks ] keep peek ; + +M: #label solve-recursion* ( node -- ) + dup node-param over collect-recursion >r + node-children first dup node-in-d r> swap + join-values rot subst-values ; + +: solve-recursion ( node -- ) + #! Figure out which values survive inner recursions in + #! #labels, and those that don't should be fudged. + [ solve-recursion* ] each-node ; diff --git a/library/inference/split-nodes.factor b/library/inference/split-nodes.factor new file mode 100644 index 0000000000..e6189b7a54 --- /dev/null +++ b/library/inference/split-nodes.factor @@ -0,0 +1,59 @@ +IN: inference +USING: kernel sequences words ; + +! #ifte --> X +! | +! +--> Y +! | +! +--> Z + +! Becomes: + +! #ifte +! | +! +--> Y --> X +! | +! +--> Z --> X + +GENERIC: split-node* ( node -- ) + +: split-node ( node -- ) + [ dup split-node* node-successor split-node ] when* ; + +M: node split-node* ( node -- ) drop ; + +: post-inline ( #return/#values #call/#merge -- ) + dup [ + [ >r node-in-d r> node-out-d unify-length ] keep + node-successor subst-values + ] [ + 2drop + ] ifte ; + +: subst-node ( old new -- ) + #! The last node of 'new' becomes 'old', then values are + #! substituted. A subsequent optimizer phase kills the + #! last node of 'new' and the first node of 'old'. + [ last-node 2dup swap post-inline set-node-successor ] keep + split-node ; + +: split-branch ( node -- ) + dup node-successor over node-children + [ >r clone-node r> subst-node ] each-with + f swap set-node-successor ; + +M: #ifte split-node* ( node -- ) + split-branch ; + +M: #dispatch split-node* ( node -- ) + split-branch ; + +M: #label split-node* ( node -- ) + node-children first split-node ; + +: inline-literals ( node literals -- node ) + #! Make #push -> #return -> successor + over drop-inputs [ + >r [ literalize ] map dataflow [ subst-node ] keep + r> set-node-successor + ] keep ; diff --git a/library/inference/stack.factor b/library/inference/stack.factor deleted file mode 100644 index 5e57b56588..0000000000 --- a/library/inference/stack.factor +++ /dev/null @@ -1,31 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: inference -USING: interpreter kernel namespaces words ; - -\ >r [ - \ >r #call - 1 0 pick node-inputs - pop-d push-r - 0 1 pick node-outputs - node, -] "infer" set-word-prop - -\ r> [ - \ r> #call - 0 1 pick node-inputs - pop-r push-d - 1 0 pick node-outputs - node, -] "infer" set-word-prop - -: infer-shuffle ( word -- ) - dup #call [ - over "infer-effect" word-prop [ host-word ] hairy-node - ] keep node, ; - -\ drop [ 1 #drop node, pop-d drop ] "infer" set-word-prop -\ dup [ \ dup infer-shuffle ] "infer" set-word-prop -\ swap [ \ swap infer-shuffle ] "infer" set-word-prop -\ over [ \ over infer-shuffle ] "infer" set-word-prop -\ pick [ \ pick infer-shuffle ] "infer" set-word-prop diff --git a/library/inference/test.factor b/library/inference/test.factor deleted file mode 100644 index 252e424c6b..0000000000 --- a/library/inference/test.factor +++ /dev/null @@ -1,26 +0,0 @@ -! Copyright (C) 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: test -USING: errors inference kernel lists namespaces prettyprint -io strings unparser ; - -: try-infer ( quot -- effect error ) - [ infer f ] [ [ >r drop f r> ] when* ] catch ; - -: infer-fail ( quot error -- ) - "! " , dup string? [ unparse ] unless , "\n" , - [ [ infer ] cons . \ unit-test-fails . ] string-out % ; - -: infer-pass ( quot effect -- ) - [ unit . [ infer ] cons . \ unit-test . ] string-out % ; - -: infer>test ( quot -- str ) - #! Make a string representing a unit test for the stack - #! effect of a word. - [ - dup try-infer [ infer-fail ] [ infer-pass ] ?ifte - ] make-string ; - -: infer>test. ( word -- ) - #! Print a inference unit test for a word. - infer>test write ; diff --git a/library/inference/values.factor b/library/inference/values.factor deleted file mode 100644 index c5e40e9a0d..0000000000 --- a/library/inference/values.factor +++ /dev/null @@ -1,78 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: inference -USING: generic kernel lists namespaces sequences unparser words ; - -GENERIC: value= ( literal value -- ? ) -GENERIC: value-class-and ( class value -- ) - -SYMBOL: cloned -GENERIC: clone-value ( value -- value ) - -TUPLE: value class recursion safe? ; - -C: value ( recursion -- value ) - [ t swap set-value-safe? ] keep - [ set-value-recursion ] keep ; - -TUPLE: computed ; - -C: computed ( class -- value ) - swap recursive-state get [ set-value-class ] keep - over set-delegate ; - -M: computed value= ( literal value -- ? ) - 2drop f ; - -: failing-class-and ( class class -- class ) - 2dup class-and dup null = [ - -rot [ - word-name % " and " % word-name % - " do not intersect" % - ] make-string inference-warning - ] [ - 2nip - ] ifte ; - -M: computed value-class-and ( class value -- ) - [ - value-class failing-class-and - ] keep set-value-class ; - -TUPLE: literal value ; - -C: literal ( obj rstate -- value ) - [ - >r [ >r dup class r> set-value-class ] keep - r> set-delegate - ] keep - [ set-literal-value ] keep ; - -M: literal clone-value ( value -- value ) ; - -M: literal value= ( literal value -- ? ) - literal-value = ; - -M: literal value-class-and ( class value -- ) - value-class class-and drop ; - -M: literal set-value-class ( class value -- ) - 2drop ; - -M: computed clone-value ( value -- value ) - dup cloned get assq [ ] [ - dup clone [ swap cloned [ acons ] change ] keep - ] ?ifte ; - -M: computed literal-value ( value -- ) - "A literal value was expected where a computed value was" - " found: " rot unparse append3 inference-error ; - -: value-types ( value -- list ) - value-class builtin-supertypes ; - -: >literal< ( literal -- rstate obj ) - dup value-recursion swap literal-value ; - -PREDICATE: tuple safe-literal ( obj -- ? ) - dup literal? [ value-safe? ] [ drop f ] ifte ; diff --git a/library/inference/words.factor b/library/inference/words.factor index 7197fb82a1..9e5391880a 100644 --- a/library/inference/words.factor +++ b/library/inference/words.factor @@ -9,27 +9,22 @@ hashtables parser prettyprint ; [ pop-d 2drop ] each ; : produce-d ( typelist -- ) - [ push-d ] each ; + [ drop push-d ] each ; : consume/produce ( word effect -- ) #! Add a node to the dataflow graph that consumes and #! produces a number of values. swap #call [ over [ - 2unlist swap consume-d produce-d + first2 swap consume-d produce-d ] hairy-node ] keep node, ; : no-effect ( word -- ) - "Unknown stack effect: " swap word-name append + "Stack effect inference of the word " swap word-name + " was already attempted, and failed" append3 inference-error ; -: inhibit-parital ( -- ) - meta-d get [ f swap set-value-safe? ] each ; - -: recursive? ( word -- ? ) - f swap dup word-def [ = or ] tree-each-with ; - : with-block ( word [[ label quot ]] quot -- block-node ) #! Execute a quotation with the word on the stack, and add #! its dataflow contribution to a new #label node in the IR. @@ -39,89 +34,62 @@ hashtables parser prettyprint ; : inline-block ( word -- node-block ) gensym over word-def cons [ - inhibit-parital word-def infer-quot + #entry node, word-def infer-quot #return node, ] with-block ; -: inline-compound ( word -- ) - #! Infer the stack effect of a compound word in the current - #! inferencer instance. If the word in question is recursive - #! we infer its stack effect inside a new block. - dup recursive? [ - inline-block node, - ] [ - word-def infer-quot - ] ifte ; - -: (infer-compound) ( word base-case -- effect ) +: infer-compound ( word base-case -- effect ) #! Infer a word's stack effect in a separate inferencer #! instance. [ inferring-base-case set recursive-state get init-inference dup inline-block drop - effect present-effect + effect ] with-scope [ consume/produce ] keep ; -: infer-compound ( word -- ) +GENERIC: apply-word + +M: object apply-word ( word -- ) + #! A primitive with an unknown stack effect. + no-effect ; + +M: compound apply-word ( word -- ) + #! Infer a compound word's stack effect. [ - dup f (infer-compound) "infer-effect" set-word-prop + dup f infer-compound "infer-effect" set-word-prop ] [ [ swap t "no-effect" set-word-prop rethrow ] when* ] catch ; -GENERIC: (apply-word) - -M: object (apply-word) ( word -- ) - #! A primitive with an unknown stack effect. - no-effect ; - -M: primitive (apply-word) ( word -- ) - dup "infer-effect" word-prop [ - consume/produce - ] [ - no-effect - ] ifte ; - -M: compound (apply-word) ( word -- ) - #! Infer a compound word's stack effect. +: apply-default ( word -- ) dup "no-effect" word-prop [ no-effect ] [ - infer-compound + dup "infer-effect" word-prop [ + over "infer" word-prop [ + swap car ensure-d call drop + ] [ + consume/produce + ] ifte* + ] [ + apply-word + ] ifte* ] ifte ; -M: symbol (apply-word) ( word -- ) - apply-literal ; - -GENERIC: apply-word - -: apply-default ( word -- ) - dup "infer-effect" word-prop [ - over "infer" word-prop [ - swap car ensure-d call drop - ] [ - consume/produce - ] ifte* - ] [ - (apply-word) - ] ifte* ; - -M: word apply-word ( word -- ) +M: word apply-object ( word -- ) apply-default ; -M: compound apply-word ( word -- ) - dup "inline" word-prop [ - inline-compound - ] [ - apply-default - ] ifte ; +M: symbol apply-object ( word -- ) + apply-literal ; : (base-case) ( word label -- ) over "inline" word-prop [ + meta-d get clone >r over inline-block drop - [ #call-label ] [ #call ] ?ifte node, + [ #call-label ] [ #call ] ?ifte + r> over set-node-in-d node, ] [ - drop dup t (infer-compound) "base-case" set-word-prop + drop dup t infer-compound "base-case" set-word-prop ] ifte ; : base-case ( word label -- ) @@ -144,39 +112,24 @@ M: compound apply-word ( word -- ) nip consume/produce ] [ inferring-base-case get [ - 2drop terminate + t base-case-continuation get call ] [ car base-case ] ifte ] ifte* ] ifte* ; -M: word apply-object ( word -- ) +M: compound apply-object ( word -- ) #! Apply the word's stack effect to the inferencer state. dup recursive-state get assoc [ recursive-word ] [ - apply-word + dup "inline" word-prop + [ inline-block node, ] [ apply-default ] ifte ] ifte* ; -\ call [ - pop-literal infer-quot-value -] "infer" set-word-prop - -\ execute [ - pop-literal unit infer-quot-value -] "infer" set-word-prop - -! These hacks will go away soon -\ delegate [ [ object ] [ object ] ] "infer-effect" set-word-prop -\ no-method t "terminator" set-word-prop -\ no-method [ [ object word ] [ ] ] "infer-effect" set-word-prop -\ [ [ object object ] [ tuple ] ] "infer-effect" set-word-prop -\ set-no-method-generic [ [ object tuple ] [ ] ] "infer-effect" set-word-prop -\ set-no-method-object [ [ object tuple ] [ ] ] "infer-effect" set-word-prop -\ not-a-number t "terminator" set-word-prop -\ inference-error t "terminator" set-word-prop -\ throw t "terminator" set-word-prop -\ = [ [ object object ] [ boolean ] ] "infer-effect" set-word-prop -\ integer/ [ [ integer integer ] [ rational ] ] "infer-effect" set-word-prop -\ gcd [ [ integer integer ] [ integer integer ] ] "infer-effect" set-word-prop +: infer-shuffle ( word -- ) + dup #call [ + over "infer-effect" word-prop + [ meta-d [ swap with-datastack ] change ] hairy-node + ] keep node, ; diff --git a/library/io/binary.factor b/library/io/binary.factor index fbb28b4406..2d5a5d2679 100644 --- a/library/io/binary.factor +++ b/library/io/binary.factor @@ -3,10 +3,10 @@ IN: io USING: kernel lists math sequences strings ; -: be> ( seq -- x ) 0 swap [ >r 8 shift r> bitor ] each ; +: be> ( seq -- x ) 0 [ >r 8 shift r> bitor ] reduce ; : le> ( seq -- x ) reverse be> ; : nth-byte ( x n -- b ) -8 * shift HEX: ff bitand ; -: >le ( x n -- string ) [ nth-byte ] project-with >string ; +: >le ( x n -- string ) [ nth-byte ] map-with >string ; : >be ( x n -- string ) >le reverse ; diff --git a/library/io/c-streams.factor b/library/io/c-streams.factor index 6aebdb785d..483dcdfe50 100644 --- a/library/io/c-streams.factor +++ b/library/io/c-streams.factor @@ -34,6 +34,8 @@ M: c-stream stream-close ( stream -- ) : init-io ( -- ) 13 getenv 14 getenv t stdio set ; +: io-multiplex ( ms -- ) drop ; + IN: io : ( path -- stream ) diff --git a/library/io/directories.factor b/library/io/directories.factor deleted file mode 100644 index 5c505f658f..0000000000 --- a/library/io/directories.factor +++ /dev/null @@ -1,24 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: io -USING: hashtables kernel lists namespaces presentation sequences -strings styles unparser ; - -! Hyperlinked directory listings. - -: dir-icon "/library/icons/Folder.png" ; -: file-icon "/library/icons/File.png" ; -: file-icon. directory? dir-icon file-icon ? write-icon ; - -: file-link. ( dir name -- ) - tuck path+ file swons unit format ; - -: file. ( dir name -- ) - #! If "doc-root" set, create links relative to it. - 2dup path+ file-icon. bl file-link. terpri ; - -: directory. ( dir -- ) - #! If "doc-root" set, create links relative to it. - dup directory [ - dup [ "." ".." ] member? [ 2drop ] [ file. ] ifte - ] each-with ; diff --git a/library/io/files.factor b/library/io/files.factor index 1793e68a98..a4d8014d01 100644 --- a/library/io/files.factor +++ b/library/io/files.factor @@ -6,10 +6,16 @@ USING: kernel lists namespaces sequences strings ; ! Words for accessing filesystem meta-data. : path+ ( path path -- path ) "/" swap append3 ; + : exists? ( file -- ? ) stat >boolean ; + : directory? ( file -- ? ) stat car ; -: directory ( dir -- list ) (directory) [ lexi> ] sort ; + +: directory ( dir -- list ) + (directory) { "." ".." } swap seq-diff string-sort ; + : file-length ( file -- length ) stat third ; + : file-extension ( filename -- extension ) "." split cdr dup [ peek ] when ; diff --git a/library/io/lines.factor b/library/io/lines.factor index 7774004bbc..a9dc5ef3af 100644 --- a/library/io/lines.factor +++ b/library/io/lines.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: io -USING: errors generic io kernel math namespaces sequences ; +USING: errors generic io kernel math namespaces sequences +vectors ; TUPLE: line-reader cr ; @@ -26,7 +27,7 @@ C: line-reader ( stream -- line ) [ set-delegate ] keep ; ] ifte ; M: line-reader stream-readln ( line -- string ) - [ f swap (readln) ] make-string + [ f swap (readln) ] "" make dup empty? [ f ? ] [ nip ] ifte ; M: line-reader stream-read ( count line -- string ) @@ -40,19 +41,9 @@ M: line-reader stream-read ( count line -- string ) drop ] ifte ; -! Reading lines and counting line numbers. -SYMBOL: line-number -SYMBOL: parser-stream +: (lines) ( seq -- seq ) + readln [ over push (lines) ] when* ; -: next-line ( -- str ) - parser-stream get stream-readln - line-number [ 1 + ] change ; - -: read-lines ( stream quot -- ) - #! Apply a quotation to each line as its read. Close the - #! stream. - swap [ - parser-stream set 0 line-number set [ next-line ] while - ] [ - parser-stream get stream-close rethrow - ] catch ; +: lines ( stream -- seq ) + #! Read all lines from the stream into a sequence. + [ { } clone (lines) ] with-stream ; diff --git a/library/io/logging.factor b/library/io/logging.factor index 64e8d7ea79..efe44653d9 100644 --- a/library/io/logging.factor +++ b/library/io/logging.factor @@ -1,28 +1,25 @@ ! Copyright (C) 2003, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: io -USING: kernel namespaces io sequences strings unparser ; +USING: io kernel math namespaces parser sequences strings ; ! A simple logging framework. SYMBOL: log-stream -: log ( msg -- ) +: log-message ( msg -- ) #! Log a message to the log stream, either stdio or a file. - log-stream get [ - [ stream-print ] keep stream-flush - ] [ - print flush - ] ifte* ; + log-stream get [ stdio get ] unless* + [ stream-print ] keep stream-flush ; -: log-error ( error -- ) "Error: " swap append log ; +: log-error ( error -- ) "Error: " swap append log-message ; : log-client ( client-stream -- ) [ "Accepted connection from " % dup client-stream-host % CHAR: : , - client-stream-port unparse % - ] make-string log ; + client-stream-port # + ] "" make log-message ; : with-log-file ( file quot -- ) #! Calls to log inside quot will output to a file. diff --git a/library/io/stdio.factor b/library/io/stdio.factor index e43238a45e..3f186edfa6 100644 --- a/library/io/stdio.factor +++ b/library/io/stdio.factor @@ -1,33 +1,33 @@ -! Copyright (C) 2003, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: io -USING: errors generic kernel lists namespaces strings styles ; - -: flush ( -- ) stdio get stream-flush ; -: readln ( -- string/f ) stdio get stream-readln ; -: read1 ( -- char/f ) stdio get stream-read1 ; -: read ( count -- string ) stdio get stream-read ; -: write ( string -- ) stdio get stream-write ; -: write1 ( char -- ) stdio get stream-write1 ; -: format ( string style -- ) stdio get stream-format ; -: print ( string -- ) stdio get stream-print ; -: terpri ( -- ) stdio get stream-terpri ; -: close ( -- ) stdio get stream-close ; - -: crlf ( -- ) "\r\n" write ; -: bl ( -- ) " " write ; - -: write-icon ( resource -- ) - #! Write an icon. Eg, /library/icons/File.png - icon swons unit "" swap format ; - -: with-stream ( stream quot -- ) - #! Close the stream no matter what happens. - [ swap stdio set [ close rethrow ] catch ] with-scope ; - -: with-stream* ( stream quot -- ) - #! Close the stream if there is an error. - [ - swap stdio set - [ [ close rethrow ] when* ] catch - ] with-scope ; +! Copyright (C) 2003, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: io +USING: errors generic kernel lists namespaces strings styles ; + +: flush ( -- ) stdio get stream-flush ; +: readln ( -- string/f ) stdio get stream-readln ; +: read1 ( -- char/f ) stdio get stream-read1 ; +: read ( count -- string ) stdio get stream-read ; +: write ( string -- ) stdio get stream-write ; +: write1 ( char -- ) stdio get stream-write1 ; +: format ( string style -- ) stdio get stream-format ; +: print ( string -- ) stdio get stream-print ; +: terpri ( -- ) stdio get stream-terpri ; +: close ( -- ) stdio get stream-close ; + +: write-object ( string object -- ) + presented swons unit format ; + +: with-stream ( stream quot -- ) + #! Close the stream no matter what happens. + [ swap stdio set [ close rethrow ] catch ] with-scope ; + +: with-stream* ( stream quot -- ) + #! Close the stream if there is an error. + [ + swap stdio set + [ [ close rethrow ] when* ] catch + ] with-scope ; + +: contents ( stream -- string ) + #! Read the entire stream into a string. + 4096 [ stream-copy ] keep >string ; diff --git a/library/io/stream.factor b/library/io/stream.factor index 94af037e41..01710480c9 100644 --- a/library/io/stream.factor +++ b/library/io/stream.factor @@ -51,9 +51,8 @@ TUPLE: wrapper-stream scope ; C: wrapper-stream ( stream -- stream ) 2dup set-delegate [ - >r [ stdio set ] extend r> - set-wrapper-stream-scope + >r [ stdio set ] make-hash r> set-wrapper-stream-scope ] keep ; : with-wrapper ( stream quot -- ) - >r wrapper-stream-scope r> bind ; + >r wrapper-stream-scope r> bind ; inline diff --git a/library/kernel.factor b/library/kernel.factor index 5a5989fe5a..dd686b87c9 100644 --- a/library/kernel.factor +++ b/library/kernel.factor @@ -3,16 +3,35 @@ IN: kernel USING: generic kernel-internals vectors ; -UNION: boolean f t ; +: 2drop ( x x -- ) drop drop ; inline +: 3drop ( x x x -- ) drop drop drop ; inline +: 2dup ( x y -- x y x y ) over over ; inline +: 3dup ( x y z -- x y z x y z ) pick pick pick ; inline +: rot ( x y z -- y z x ) >r swap r> swap ; inline +: -rot ( x y z -- z x y ) swap >r swap r> ; inline +: dupd ( x y -- x x y ) >r dup r> ; inline +: swapd ( x y z -- y x z ) >r swap r> ; inline +: 2swap ( x y z t -- z t x y ) rot >r rot r> ; inline +: nip ( x y -- y ) swap drop ; inline +: 2nip ( x y z -- z ) >r drop drop r> ; inline +: tuck ( x y -- y x y ) dup >r swap r> ; inline + +: clear ( -- ) + #! Clear the datastack. For interactive use only; invoking + #! this from a word definition will clobber any values left + #! on the data stack by the caller. + { } set-datastack ; + +UNION: boolean POSTPONE: f POSTPONE: t ; COMPLEMENT: general-t f -GENERIC: hashcode ( obj -- n ) +GENERIC: hashcode ( obj -- n ) flushable M: object hashcode drop 0 ; -GENERIC: = ( obj obj -- ? ) +GENERIC: = ( obj obj -- ? ) flushable M: object = eq? ; -GENERIC: clone ( obj -- obj ) +GENERIC: clone ( obj -- obj ) flushable M: object clone ; : set-boot ( quot -- ) @@ -21,15 +40,15 @@ M: object clone ; : num-types ( -- n ) #! One more than the maximum value from type primitive. - 21 ; + 21 ; inline : ? ( cond t f -- t/f ) #! Push t if cond is true, otherwise push f. rot [ drop ] [ nip ] ifte ; inline -! defined in parse-syntax.factor -DEFER: not -DEFER: t? +M: wrapper = ( obj wrapper -- ? ) + over wrapper? + [ swap wrapped swap wrapped = ] [ 2drop f ] ifte ; : >boolean t f ? ; inline : and ( a b -- a&b ) f ? ; inline @@ -44,9 +63,65 @@ DEFER: t? os "macosx" = or ; : tag-mask BIN: 111 ; inline +: num-tags 8 ; inline : tag-bits 3 ; inline : fixnum-tag BIN: 000 ; inline : bignum-tag BIN: 001 ; inline : cons-tag BIN: 010 ; inline : object-tag BIN: 011 ; inline + +: slip ( quot x -- x | quot: -- ) + >r call r> ; inline + +: 2slip ( quot x y -- x y | quot: -- ) + >r >r call r> r> ; inline + +: keep ( x quot -- x | quot: x -- ) + over >r call r> ; inline + +: 2keep ( x y quot -- x y | quot: x y -- ) + over >r pick >r call r> r> ; inline + +: 3keep ( x y z quot -- x y z | quot: x y z -- ) + >r 3dup r> swap >r swap >r swap >r call r> r> r> ; inline + +: ifte* ( cond true false -- | true: cond -- | false: -- ) + #! [ X ] [ Y ] ifte* ==> dup [ X ] [ drop Y ] ifte + pick [ drop call ] [ 2nip call ] ifte ; inline + +: ?ifte ( default cond true false -- ) + #! [ X ] [ Y ] ?ifte ==> dup [ nip X ] [ drop Y ] ifte + >r >r dup [ + nip r> r> drop call + ] [ + drop r> drop r> call + ] ifte ; inline + +: unless ( cond quot -- | quot: -- ) + #! Execute a quotation only when the condition is f. The + #! condition is popped off the stack. + [ ] swap ifte ; inline + +: unless* ( cond quot -- | quot: -- ) + #! If cond is f, pop it off the stack and evaluate the + #! quotation. Otherwise, leave cond on the stack. + over [ drop ] [ nip call ] ifte ; inline + +: when ( cond quot -- | quot: -- ) + #! Execute a quotation only when the condition is not f. The + #! condition is popped off the stack. + [ ] ifte ; inline + +: when* ( cond quot -- | quot: cond -- ) + #! If the condition is true, it is left on the stack, and + #! the quotation is evaluated. Otherwise, the condition is + #! popped off the stack. + dupd [ drop ] ifte ; inline + +: with ( obj quot elt -- obj quot ) + #! Utility word for each-with, map-with. + pick pick >r >r swap call r> r> ; inline + +: keep-datastack ( quot -- ) + datastack slip set-datastack drop ; diff --git a/library/math/arc-trig-hyp.factor b/library/math/arc-trig-hyp.factor index 3467a7d8d1..d96a827126 100644 --- a/library/math/arc-trig-hyp.factor +++ b/library/math/arc-trig-hyp.factor @@ -9,16 +9,16 @@ USING: kernel math math-internals ; ! Inverse hyperbolic functions: ! acosh asech asinh acosech atanh acoth -: acosh dup sq 1 - sqrt + log ; -: asech recip acosh ; -: asinh dup sq 1 + sqrt + log ; -: acosech recip asinh ; -: atanh dup 1 + swap 1 - neg / log 2 / ; -: acoth recip atanh ; -: <=1 ( x -- ? ) dup complex? [ drop f ] [ abs 1 <= ] ifte ; -: asin dup <=1 [ fasin ] [ i * asinh -i * ] ifte ; -: acos dup <=1 [ facos ] [ asin pi/2 swap - ] ifte ; -: atan dup <=1 [ fatan ] [ i * atanh i * ] ifte ; -: asec recip acos ; -: acosec recip asin ; -: acot recip atan ; +: acosh dup sq 1 - sqrt + log ; inline +: asech recip acosh ; inline +: asinh dup sq 1 + sqrt + log ; inline +: acosech recip asinh ; inline +: atanh dup 1 + swap 1 - neg / log 2 / ; inline +: acoth recip atanh ; inline +: <=1 ( x -- ? ) dup complex? [ drop f ] [ abs 1 <= ] ifte ; inline +: asin dup <=1 [ fasin ] [ i * asinh -i * ] ifte ; inline +: acos dup <=1 [ facos ] [ asin pi 2 / swap - ] ifte ; inline +: atan dup <=1 [ fatan ] [ i * atanh i * ] ifte ; inline +: asec recip acos ; inline +: acosec recip asin ; inline +: acot recip atan ; inline diff --git a/library/math/complex.factor b/library/math/complex.factor index 170e439fb7..c64f1bba24 100644 --- a/library/math/complex.factor +++ b/library/math/complex.factor @@ -6,12 +6,10 @@ USING: errors generic kernel kernel-internals math ; : (rect>) ( xr xi -- x ) #! Does not perform a check that the arguments are reals. #! Do not use in your own code. - dup 0 number= [ drop ] [ ] ifte ; + dup 0 number= [ drop ] [ ] ifte ; inline IN: math -DEFER: complex? -BUILTIN: complex 6 complex? [ 0 "real" f ] [ 1 "imaginary" f ] ; UNION: number real complex ; M: real real ; @@ -24,39 +22,38 @@ M: number = ( n n -- ? ) number= ; (rect>) ] [ "Complex number must have real components" throw drop - ] ifte ; + ] ifte ; inline -: >rect ( x -- xr xi ) dup real swap imaginary ; +: >rect ( x -- xr xi ) dup real swap imaginary ; inline -: conjugate ( z -- z* ) - >rect neg rect> ; +: conjugate ( z -- z* ) >rect neg rect> ; inline : arg ( z -- arg ) #! Compute the complex argument. - >rect swap fatan2 ; + >rect swap fatan2 ; inline : >polar ( z -- abs arg ) - dup abs swap >rect swap fatan2 ; + dup abs swap >rect swap fatan2 ; inline : cis ( theta -- cis ) - dup fcos swap fsin rect> ; + dup fcos swap fsin rect> ; inline : polar> ( abs arg -- z ) - cis * ; + cis * ; inline -: absq >rect swap sq swap sq + ; +: absq >rect swap sq swap sq + ; inline IN: math-internals : 2>rect ( x y -- xr yr xi yi ) [ swap real swap real ] 2keep - swap imaginary swap imaginary ; + swap imaginary swap imaginary ; inline M: complex number= ( x y -- ? ) 2>rect number= [ number= ] [ 2drop f ] ifte ; -: *re ( x y -- xr*yr xi*ri ) 2>rect * >r * r> ; -: *im ( x y -- xi*yr xr*yi ) 2>rect >r * swap r> * ; +: *re ( x y -- xr*yr xi*ri ) 2>rect * >r * r> ; inline +: *im ( x y -- xi*yr xr*yi ) 2>rect >r * swap r> * ; inline M: complex + 2>rect + >r + r> (rect>) ; M: complex - 2>rect - >r - r> (rect>) ; @@ -64,7 +61,7 @@ M: complex * ( x y -- x*y ) 2dup *re - -rot *im + (rect>) ; : complex/ ( x y -- r i m ) #! r = xr*yr+xi*yi, i = xi*yr-xr*yi, m = yr*yr+yi*yi - dup absq >r 2dup *re + -rot *im - r> ; + dup absq >r 2dup *re + -rot *im - r> ; inline M: complex / ( x y -- x/y ) complex/ tuck / >r / r> (rect>) ; M: complex /f ( x y -- x/y ) complex/ tuck /f >r /f r> (rect>) ; diff --git a/library/math/constants.factor b/library/math/constants.factor index e0430a8535..876fcf4bc5 100644 --- a/library/math/constants.factor +++ b/library/math/constants.factor @@ -9,7 +9,6 @@ USE: kernel : -inf -1.0 0.0 / ; inline : e 2.7182818284590452354 ; inline : pi 3.14159265358979323846 ; inline -: pi/2 1.5707963267948966 ; inline -: deg>rad pi * 180 / ; -: rad>deg 180 * pi / ; +: deg>rad pi * 180 / ; inline +: rad>deg 180 * pi / ; inline diff --git a/library/math/float.factor b/library/math/float.factor index 6e3b33346f..4873e1a6cd 100644 --- a/library/math/float.factor +++ b/library/math/float.factor @@ -3,8 +3,6 @@ IN: math USING: generic kernel math-internals ; -DEFER: float? -BUILTIN: float 5 float? ; UNION: real rational float ; M: real abs dup 0 < [ neg ] when ; diff --git a/library/math/integer.factor b/library/math/integer.factor index 5600a1fd9f..2bc6f814b1 100644 --- a/library/math/integer.factor +++ b/library/math/integer.factor @@ -1,12 +1,8 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: math -USING: errors generic kernel math ; +USING: errors generic kernel math sequences ; -DEFER: fixnum? -BUILTIN: fixnum 0 fixnum? ; -DEFER: bignum? -BUILTIN: bignum 1 bignum? ; UNION: integer fixnum bignum ; : (gcd) ( b a y x -- a d ) @@ -14,35 +10,31 @@ UNION: integer fixnum bignum ; drop nip ] [ tuck /mod >r pick * swap >r swapd - r> r> (gcd) - ] ifte ; + ] ifte ; inline : gcd ( x y -- a d ) #! Compute the greatest common divisor d and multiplier a #! such that a*x=d mod y. - swap 0 1 2swap (gcd) abs ; + swap 0 1 2swap (gcd) abs ; foldable + +: lcm ( a b -- c ) + #! Smallest integer such that c/a and c/b are both integers. + 2dup gcd nip >r * r> /i ; foldable : mod-inv ( x n -- y ) #! Compute the multiplicative inverse of x mod n. gcd 1 = [ "Non-trivial divisor found" throw ] unless ; - -: bitroll ( n s w -- n ) - #! Roll n by s bits to the right, wrapping around after - #! w bits. - [ mod shift ] 3keep over 0 >= [ - ] [ + ] ifte shift bitor ; + foldable IN: math-internals : fraction> ( a b -- a/b ) - dup 1 number= [ - drop - ] [ - (fraction>) - ] ifte ; + dup 1 number= [ drop ] [ (fraction>) ] ifte ; inline : division-by-zero ( x y -- ) - "Division by zero" throw drop ; + "Division by zero" throw drop ; inline -: integer/ ( x y -- x/y ) +M: integer / ( x y -- x/y ) dup 0 number= [ division-by-zero ] [ @@ -50,7 +42,7 @@ IN: math-internals swap neg swap neg ] when 2dup gcd nip tuck /i >r /i r> fraction> - ] ifte ; inline + ] ifte ; M: fixnum number= #! Fixnums are immediate values, so equality testing is @@ -65,7 +57,6 @@ M: fixnum >= fixnum>= ; M: fixnum + fixnum+ ; M: fixnum - fixnum- ; M: fixnum * fixnum* ; -M: fixnum / integer/ ; M: fixnum /i fixnum/i ; M: fixnum /f fixnum/f ; M: fixnum mod fixnum-mod ; @@ -88,7 +79,6 @@ M: bignum >= bignum>= ; M: bignum + bignum+ ; M: bignum - bignum- ; M: bignum * bignum* ; -M: bignum / integer/ ; M: bignum /i bignum/i ; M: bignum /f bignum/f ; M: bignum mod bignum-mod ; @@ -105,3 +95,7 @@ M: bignum bitnot bignum-bitnot ; M: integer truncate ; M: integer floor ; M: integer ceiling ; + +! Integers support the sequence protocol +M: integer length ; +M: integer nth drop ; diff --git a/library/math/math.factor b/library/math/math.factor index b1aab5208d..8ab99a324f 100644 --- a/library/math/math.factor +++ b/library/math/math.factor @@ -4,34 +4,34 @@ IN: math USING: errors generic kernel math-internals ; ! Math operations -G: number= ( x y -- ? ) [ ] [ arithmetic-type ] ; +G: number= ( x y -- ? ) math-combination ; foldable M: object number= 2drop f ; -G: < ( x y -- ? ) [ ] [ arithmetic-type ] ; -G: <= ( x y -- ? ) [ ] [ arithmetic-type ] ; -G: > ( x y -- ? ) [ ] [ arithmetic-type ] ; -G: >= ( x y -- ? ) [ ] [ arithmetic-type ] ; +G: < ( x y -- ? ) math-combination ; foldable +G: <= ( x y -- ? ) math-combination ; foldable +G: > ( x y -- ? ) math-combination ; foldable +G: >= ( x y -- ? ) math-combination ; foldable -G: + ( x y -- x+y ) [ ] [ arithmetic-type ] ; -G: - ( x y -- x-y ) [ ] [ arithmetic-type ] ; -G: * ( x y -- x*y ) [ ] [ arithmetic-type ] ; -G: / ( x y -- x/y ) [ ] [ arithmetic-type ] ; -G: /i ( x y -- x/y ) [ ] [ arithmetic-type ] ; -G: /f ( x y -- x/y ) [ ] [ arithmetic-type ] ; -G: mod ( x y -- x%y ) [ ] [ arithmetic-type ] ; +G: + ( x y -- x+y ) math-combination ; foldable +G: - ( x y -- x-y ) math-combination ; foldable +G: * ( x y -- x*y ) math-combination ; foldable +G: / ( x y -- x/y ) math-combination ; foldable +G: /i ( x y -- x/y ) math-combination ; foldable +G: /f ( x y -- x/y ) math-combination ; foldable +G: mod ( x y -- x%y ) math-combination ; foldable -G: /mod ( x y -- x/y x%y ) [ ] [ arithmetic-type ] ; +G: /mod ( x y -- x/y x%y ) math-combination ; foldable -G: bitand ( x y -- z ) [ ] [ arithmetic-type ] ; -G: bitor ( x y -- z ) [ ] [ arithmetic-type ] ; -G: bitxor ( x y -- z ) [ ] [ arithmetic-type ] ; -G: shift ( x n -- y ) [ ] [ arithmetic-type ] ; +G: bitand ( x y -- z ) math-combination ; foldable +G: bitor ( x y -- z ) math-combination ; foldable +G: bitxor ( x y -- z ) math-combination ; foldable +G: shift ( x n -- y ) math-combination ; foldable -GENERIC: bitnot ( n -- n ) +GENERIC: bitnot ( n -- n ) foldable -GENERIC: truncate ( n -- n ) -GENERIC: floor ( n -- n ) -GENERIC: ceiling ( n -- n ) +GENERIC: truncate ( n -- n ) foldable +GENERIC: floor ( n -- n ) foldable +GENERIC: ceiling ( n -- n ) foldable : max ( x y -- z ) [ > ] 2keep ? ; inline : min ( x y -- z ) [ < ] 2keep ? ; inline @@ -39,7 +39,7 @@ GENERIC: ceiling ( n -- n ) : between? ( x min max -- ? ) #! Push if min <= x <= max. Handles case where min > max #! by swapping them. - 2dup > [ swap ] when >r dupd max r> min = ; + 2dup > [ swap ] when >r dupd max r> min = ; foldable : sq dup * ; inline @@ -48,16 +48,16 @@ GENERIC: ceiling ( n -- n ) : rem ( x y -- x%y ) #! Like modulus, but always gives a positive result. - [ mod ] keep over 0 < [ + ] [ drop ] ifte ; + [ mod ] keep over 0 < [ + ] [ drop ] ifte ; inline : sgn ( n -- -1/0/1 ) #! Push the sign of a real number. - dup 0 = [ drop 0 ] [ 1 < -1 1 ? ] ifte ; + dup 0 = [ drop 0 ] [ 1 < -1 1 ? ] ifte ; foldable GENERIC: abs ( z -- |z| ) : align ( offset width -- offset ) - 2dup mod dup 0 number= [ 2drop ] [ - + ] ifte ; + 2dup mod dup 0 number= [ 2drop ] [ - + ] ifte ; inline : (repeat) ( i n quot -- ) pick pick >= @@ -72,17 +72,12 @@ GENERIC: abs ( z -- |z| ) : times ( n quot -- | quot: -- ) swap [ >r dup slip r> ] repeat drop ; inline -: 2repeat ( i j quot -- | quot: i j -- i j ) - rot [ - rot [ [ rot dup slip -rot ] repeat ] keep -rot - ] repeat 2drop ; inline - : power-of-2? ( n -- ? ) dup 0 > [ dup dup neg bitand = ] [ drop f - ] ifte ; + ] ifte ; foldable : log2 ( n -- b ) #! Log base two for integers. @@ -90,4 +85,6 @@ GENERIC: abs ( z -- |z| ) "Input must be positive" throw ] [ dup 1 = [ drop 0 ] [ 2 /i log2 1 + ] ifte - ] ifte ; + ] ifte ; foldable + +GENERIC: number>string ( str -- num ) foldable diff --git a/library/math/matrices.factor b/library/math/matrices.factor index ea2856761f..6d189eddc5 100644 --- a/library/math/matrices.factor +++ b/library/math/matrices.factor @@ -1,45 +1,41 @@ ! Copyright (C) 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. -IN: matrices -USING: errors generic kernel lists math namespaces sequences -vectors ; +IN: math +USING: generic kernel sequences vectors ; + +! Vectors +: zero-vector ( n -- vector ) 0 >vector ; -! Vector operations : vneg ( v -- v ) [ neg ] map ; -: n*v ( n vec -- vec ) [ * ] map-with ; -: v*n ( vec n -- vec ) swap n*v ; -: n/v ( n vec -- vec ) [ / ] map-with ; -: v/n ( vec n -- vec ) swap [ swap / ] map-with ; +: n*v ( n v -- v ) [ * ] map-with ; +: v*n ( v n -- v ) swap n*v ; +: n/v ( n v -- v ) [ / ] map-with ; +: v/n ( v n -- v ) swap [ swap / ] map-with ; -: v+ ( v v -- v ) [ + ] 2map ; -: v- ( v v -- v ) [ - ] 2map ; -: v* ( v v -- v ) [ * ] 2map ; -: v/ ( v v -- v ) [ / ] 2map ; +: v+ ( v v -- v ) [ + ] 2map ; +: v- ( v v -- v ) [ - ] 2map ; +: v* ( v v -- v ) [ * ] 2map ; +: v/ ( v v -- v ) [ / ] 2map ; : vmax ( v v -- v ) [ max ] 2map ; : vmin ( v v -- v ) [ min ] 2map ; : vand ( v v -- v ) [ and ] 2map ; -: vor ( v v -- v ) [ or ] 2map ; -: v< ( v v -- v ) [ < ] 2map ; -: v<= ( v v -- v ) [ <= ] 2map ; -: v> ( v v -- v ) [ > ] 2map ; -: v>= ( v v -- v ) [ >= ] 2map ; +: vor ( v v -- v ) [ or ] 2map ; +: v< ( v v -- v ) [ < ] 2map ; +: v<= ( v v -- v ) [ <= ] 2map ; +: v> ( v v -- v ) [ > ] 2map ; +: v>= ( v v -- v ) [ >= ] 2map ; -: vbetween? ( v from to -- v ) - >r over >r v>= r> r> v<= vand ; +: vbetween? ( v from to -- v ) >r over >r v>= r> r> v<= vand ; : sum ( v -- n ) 0 [ + ] reduce ; -: product 1 [ * ] reduce ; -: conj ( v -- ? ) [ ] all? ; -: disj ( v -- ? ) [ ] contains? ; +: product ( v -- n ) 1 [ * ] reduce ; : set-axis ( x y axis -- v ) 2dup v* >r >r drop dup r> v* v- r> v+ ; -! Later, this will fixed when 2each works properly -! : v. ( v v -- x ) 0 swap [ conjugate * + ] 2each ; -: v** ( v v -- v ) [ conjugate * ] 2map ; -: v. ( v v -- x ) v** sum ; +: v. ( v v -- x ) 0 [ * + ] 2reduce ; +: c. ( v v -- x ) 0 [ conjugate * + ] 2reduce ; : norm-sq ( v -- n ) 0 [ absq + ] reduce ; @@ -55,136 +51,53 @@ vectors ; : cross ( { x1 y1 z1 } { x2 y2 z2 } -- { z1 z2 z3 } ) #! Cross product of two 3-dimensional vectors. - 3 - [ >r 2dup 1 2 cross-minor 0 r> set-nth ] keep - [ >r 2dup 2 0 cross-minor 1 r> set-nth ] keep - [ >r 2dup 0 1 cross-minor 2 r> set-nth ] keep - 2nip ; + [ 1 2 cross-minor ] 2keep + [ 2 0 cross-minor ] 2keep + 0 1 cross-minor 3vector ; ! Matrices -! The major dimension is the number of elements per row. -TUPLE: matrix rows cols sequence ; -: >matrix< - [ matrix-rows ] keep - [ matrix-cols ] keep - matrix-sequence ; +! A diagonal of a matrix stored as a sequence of rows. +TUPLE: diagonal index ; -M: matrix clone ( matrix -- matrix ) - clone-tuple - dup matrix-sequence clone over set-matrix-sequence ; +C: diagonal ( seq -- diagonal ) [ set-delegate ] keep ; -: matrix@ ( row col matrix -- n ) matrix-cols rot * + ; +: diagonal@ ( n diag -- n vec ) dupd delegate nth ; -: matrix-get ( row col matrix -- elt ) - [ matrix@ ] keep matrix-sequence nth ; +M: diagonal nth ( n diag -- elt ) diagonal@ nth ; -: matrix-set ( elt row col matrix -- ) - [ matrix@ ] keep matrix-sequence set-nth ; +M: diagonal set-nth ( elt n diag -- ) diagonal@ set-nth ; -: ( rows cols -- matrix ) - 2dup * zero-vector ; +: zero-matrix ( m n -- matrix ) + swap [ drop zero-vector ] map-with ; -: ( vector -- matrix ) - #! Turn a vector into a matrix of one row. - [ 1 swap length ] keep ; - -: ( vector -- matrix ) - #! Turn a vector into a matrix of one column. - [ length 1 ] keep ; - -: make-matrix ( rows cols quot -- matrix | quot: i j -- elt ) - -rot [ - [ [ [ rot call , ] 3keep ] 2repeat ] make-vector nip - ] 2keep rot ; inline - -: ( n -- matrix ) +: identity-matrix ( n -- matrix ) #! Make a nxn identity matrix. - dup [ = 1 0 ? ] make-matrix ; - -: transpose ( matrix -- matrix ) - dup matrix-cols over matrix-rows [ - swap pick matrix-get - ] make-matrix nip ; - -! Sequence of elements in a row of a matrix. -TUPLE: row index matrix ; -: >row< dup row-index swap row-matrix ; -M: row length row-matrix matrix-cols ; -M: row nth ( n row -- n ) >row< swapd matrix-get ; -M: row thaw >vector ; - -! Sequence of elements in a column of a matrix. -TUPLE: col index matrix ; -: >col< dup col-index swap col-matrix ; -M: col length col-matrix matrix-rows ; -M: col nth ( n column -- n ) >col< matrix-get ; -M: col thaw >vector ; - -! Sequence of elements on a diagonal. Positive indices are above -! and negative indices are below the main diagonal. Only for -! square matrices. -TUPLE: diagonal index matrix ; -: >diagonal< dup diagonal-index swap diagonal-matrix ; -M: diagonal length ( daig -- n ) - >diagonal< matrix-rows swap abs - ; -M: diagonal nth ( n diag -- n ) - >diagonal< >r [ neg 0 max over + ] keep 0 max rot + r> - matrix-get ; - -: trace ( matrix -- tr ) - #! Product of diagonal elements. - 0 swap product ; - -: +check ( matrix matrix -- ) - #! Check if the two matrices have dimensions compatible - #! for being added or subtracted. - over matrix-rows over matrix-rows = >r - swap matrix-cols swap matrix-cols = r> and [ - "Matrix dimensions do not equal" throw - ] unless ; - -: element-wise ( m m -- rows cols v v ) - 2dup +check >r >matrix< r> matrix-sequence ; + dup zero-matrix dup [ drop 1 ] nmap ; ! Matrix operations -: m+ ( m m -- m ) element-wise v+ ; -: m- ( m m -- m ) element-wise v- ; +: mneg ( m -- m ) [ vneg ] map ; -: m* ( m m -- m ) - #! Multiply two matrices element-wise. This is NOT matrix - #! multiplication in the usual mathematical sense. For that, - #! see the m. word. - element-wise v* ; +: n*m ( n m -- m ) [ n*v ] map-with ; +: m*n ( m n -- m ) swap n*m ; +: n/m ( n m -- m ) [ n/v ] map-with ; +: m/n ( m n -- m ) swap [ swap v/n ] map-with ; -: *check ( matrix matrix -- ) - swap matrix-cols swap matrix-rows = [ - "Matrix dimensions inappropriate for composition" throw - ] unless ; +: m+ ( m m -- m ) [ v+ ] 2map ; +: m- ( m m -- m ) [ v- ] 2map ; +: m* ( m m -- m ) [ v* ] 2map ; +: m/ ( m m -- m ) [ v/ ] 2map ; +: mmax ( m m -- m ) [ vmax ] 2map ; +: mmin ( m m -- m ) [ vmin ] 2map ; +: mand ( m m -- m ) [ vand ] 2map ; +: mor ( m m -- m ) [ vor ] 2map ; +: m< ( m m -- m ) [ v< ] 2map ; +: m<= ( m m -- m ) [ v<= ] 2map ; +: m> ( m m -- m ) [ v> ] 2map ; +: m>= ( m m -- m ) [ v>= ] 2map ; -: *dimensions ( m m -- rows cols ) - swap matrix-rows swap matrix-cols ; +: v.m ( v m -- v ) flip [ v. ] map-with ; +: m.v ( m v -- v ) swap [ v. ] map-with ; +: m. ( m m -- m ) flip swap [ m.v ] map-with ; -: m. ( m1 m2 -- m ) - #! Composition of two matrices. - 2dup *check 2dup *dimensions [ - ( m1 m2 row col -- m1 m2 ) - pick >r pick r> v. - ] make-matrix 2nip ; - -: n*m ( n m -- m ) - #! Multiply a matrix by a scalar. - >matrix< >r rot r> n*v ; - -: m.v ( m v -- v ) - #! Multiply a matrix by a column vector. - m. matrix-sequence ; - -: v.m ( v m -- v ) - #! Multiply a row vector by a matrix. - >r r> m. matrix-sequence ; - -: row-list ( matrix -- list ) - #! A list of lists, where each sublist is a row of the - #! matrix. - dup matrix-rows [ swap >list ] project-with ; +: trace ( matrix -- tr ) product ; diff --git a/library/math/more-matrices.factor b/library/math/more-matrices.factor deleted file mode 100644 index 7889b297e8..0000000000 --- a/library/math/more-matrices.factor +++ /dev/null @@ -1,7 +0,0 @@ -! Copyright (C) 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: matrices -USING: kernel math ; - -: norm ( vec -- n ) norm-sq sqrt ; -: normalize ( vec -- vec ) dup norm v/n ; diff --git a/library/math/parse-numbers.factor b/library/math/parse-numbers.factor new file mode 100644 index 0000000000..6a14eb9bfa --- /dev/null +++ b/library/math/parse-numbers.factor @@ -0,0 +1,75 @@ +! Copyright (C) 2004, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: math +USING: errors generic kernel math-internals namespaces sequences +strings ; + +! Number parsing + +: not-a-number "Not a number" throw ; inline + +GENERIC: digit> ( ch -- n ) +M: digit digit> CHAR: 0 - ; +M: letter digit> CHAR: a - 10 + ; +M: LETTER digit> CHAR: A - 10 + ; +M: object digit> not-a-number ; + +: digit+ ( num digit base -- num ) + 2dup < [ rot * + ] [ not-a-number ] ifte ; + +: (base>) ( base str -- num ) + dup empty? [ + not-a-number + ] [ + 0 [ digit> pick digit+ ] reduce nip + ] ifte ; + +: base> ( str base -- num ) + #! Convert a string to an integer. Throw an error if + #! conversion fails. + swap "-" ?head >r (base>) r> [ neg ] when ; + +: string>ratio ( "a/b" -- a/b ) + "/" split1 >r 10 base> r> 10 base> / ; + +: string>number ( string -- n ) + { + { [ CHAR: / over member? ] [ string>ratio ] } + { [ CHAR: . over member? ] [ string>float ] } + { [ t ] [ 10 base> ] } + } cond ; + +: bin> 2 base> ; +: oct> 8 base> ; +: hex> 16 base> ; + +: >digit ( n -- ch ) + dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] ifte ; + +: integer, ( num radix -- ) + dup >r /mod >digit , dup 0 > + [ r> integer, ] [ r> 2drop ] ifte ; + +: >base ( num radix -- string ) + #! Convert a number to a string in a certain base. + [ + over 0 < [ + swap neg swap integer, CHAR: - , + ] [ + integer, + ] ifte + ] "" make reverse ; + +: >bin ( num -- string ) 2 >base ; +: >oct ( num -- string ) 8 >base ; +: >hex ( num -- string ) 16 >base ; + +M: integer number>string ( obj -- str ) 10 >base ; + +M: ratio number>string ( num -- str ) + [ dup numerator # CHAR: / , denominator # ] "" make ; + +M: float number>string ( float -- str ) + #! This is terrible. Will go away when we do our own float + #! output. + float>string CHAR: . over member? [ ".0" append ] unless ; diff --git a/library/math/pow.factor b/library/math/pow.factor index 3b72f69d94..172eb67a82 100644 --- a/library/math/pow.factor +++ b/library/math/pow.factor @@ -6,23 +6,27 @@ USING: errors kernel math math-internals ; ! Power-related functions: ! exp log sqrt pow ^mod -: exp >rect swap fexp swap polar> ; -: log >polar swap flog swap rect> ; +: exp >rect swap fexp swap polar> ; inline +: log >polar swap flog swap rect> ; inline : sqrt ( z -- sqrt ) >polar dup pi = [ drop fsqrt 0 swap rect> ] [ swap fsqrt swap 2 / polar> - ] ifte ; + ] ifte ; foldable -GENERIC: ^ ( z w -- z^w ) +: norm ( vec -- n ) norm-sq sqrt ; + +: normalize ( vec -- vec ) dup norm v/n ; + +GENERIC: ^ ( z w -- z^w ) foldable : ^mag ( w abs arg -- magnitude ) - >r >r >rect swap r> swap fpow r> rot * fexp / ; + >r >r >rect swap r> swap fpow r> rot * fexp / ; inline : ^theta ( w abs arg -- theta ) - >r >r >rect r> flog * swap r> * + ; + >r >r >rect r> flog * swap r> * + ; inline M: number ^ ( z w -- z^w ) swap >polar 3dup ^theta >r ^mag r> polar> ; @@ -38,18 +42,19 @@ M: number ^ ( z w -- z^w ) : (integer^) ( z w -- z^w ) 1 swap [ 1 number= [ dupd * ] when >r sq r> ] each-bit nip ; + inline M: integer ^ ( z w -- z^w ) over 0 number= over 0 number= and [ "0^0 is not defined" throw ] [ dup 0 < [ neg ^ recip ] [ (integer^) ] ifte - ] ifte ; + ] ifte ; foldable : (^mod) ( n z w -- z^w ) 1 swap [ 1 number= [ dupd * pick mod ] when >r sq over mod r> - ] each-bit 2nip ; + ] each-bit 2nip ; inline : ^mod ( z w n -- z^w ) #! Compute z^w mod n. @@ -57,4 +62,4 @@ M: integer ^ ( z w -- z^w ) [ >r neg r> ^mod ] keep mod-inv ] [ -rot (^mod) - ] ifte ; + ] ifte ; foldable diff --git a/library/math/random.factor b/library/math/random.factor index 2f5f6e1151..e9e642ed7c 100644 --- a/library/math/random.factor +++ b/library/math/random.factor @@ -2,20 +2,19 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: math USING: kernel ; -: power-of-2? ( n -- ? ) dup dup neg bitand = ; - : (random-int-0) ( n bits val -- n ) 3dup - + 1 < [ 2drop (random-int) 2dup swap mod (random-int-0) ] [ 2nip - ] ifte ; + ] ifte ; inline : random-int-0 ( max -- n ) 1 + dup power-of-2? [ (random-int) * -31 shift ] [ (random-int) 2dup swap mod (random-int-0) - ] ifte ; + ] ifte ; inline -: random-int ( min max -- n ) dupd swap - random-int-0 + ; +: random-int ( min max -- n ) + dupd swap - random-int-0 + ; flushable diff --git a/library/math/ratio.factor b/library/math/ratio.factor index 7bee471c5a..f4363a65d4 100644 --- a/library/math/ratio.factor +++ b/library/math/ratio.factor @@ -3,26 +3,24 @@ IN: math USING: generic kernel kernel-internals math math-internals ; -DEFER: ratio? -BUILTIN: ratio 4 ratio? [ 0 "numerator" f ] [ 1 "denominator" f ] ; UNION: rational integer ratio ; M: integer numerator ; M: integer denominator drop 1 ; : >fraction ( a/b -- a b ) - dup numerator swap denominator ; + dup numerator swap denominator ; inline IN: math-internals : 2>fraction ( a/b c/d -- a c b d ) - >r >fraction r> >fraction swapd ; + >r >fraction r> >fraction swapd ; inline M: ratio number= ( a/b c/d -- ? ) 2>fraction number= [ number= ] [ 2drop f ] ifte ; : scale ( a/b c/d -- a*d b*c ) - 2>fraction >r * swap r> * swap ; + 2>fraction >r * swap r> * swap ; inline : ratio+d ( a/b c/d -- b*d ) denominator swap denominator * ; inline @@ -32,10 +30,10 @@ M: ratio <= scale <= ; M: ratio > scale > ; M: ratio >= scale >= ; -M: ratio + ( x y -- x+y ) 2dup scale + -rot ratio+d integer/ ; -M: ratio - ( x y -- x-y ) 2dup scale - -rot ratio+d integer/ ; -M: ratio * ( x y -- x*y ) 2>fraction * >r * r> integer/ ; -M: ratio / scale integer/ ; +M: ratio + ( x y -- x+y ) 2dup scale + -rot ratio+d / ; +M: ratio - ( x y -- x-y ) 2dup scale - -rot ratio+d / ; +M: ratio * ( x y -- x*y ) 2>fraction * >r * r> / ; +M: ratio / scale / ; M: ratio /i scale /i ; M: ratio /f scale /f ; diff --git a/library/math/trig-hyp.factor b/library/math/trig-hyp.factor index 7c7bbf7c06..4b83b9ded5 100644 --- a/library/math/trig-hyp.factor +++ b/library/math/trig-hyp.factor @@ -12,32 +12,32 @@ USING: kernel math math-internals ; : cos ( z -- cos ) >rect 2dup fcosh swap fcos * -rot - fsinh swap fsin neg * rect> ; + fsinh swap fsin neg * rect> ; inline -: sec cos recip ; +: sec cos recip ; inline : cosh ( z -- cosh ) >rect 2dup fcos swap fcosh * -rot - fsin swap fsinh * rect> ; + fsin swap fsinh * rect> ; inline -: sech cosh recip ; +: sech cosh recip ; inline : sin ( z -- sin ) >rect 2dup fcosh swap fsin * -rot - fsinh swap fcos * rect> ; + fsinh swap fcos * rect> ; inline -: cosec sin recip ; +: cosec sin recip ; inline : sinh ( z -- sinh ) >rect 2dup fcos swap fsinh * -rot - fsin swap fcosh * rect> ; + fsin swap fcosh * rect> ; inline -: cosech sinh recip ; +: cosech sinh recip ; inline -: tan dup sin swap cos / ; -: tanh dup sinh swap cosh / ; -: cot dup cos swap sin / ; -: coth dup cosh swap sinh / ; +: tan dup sin swap cos / ; inline +: tanh dup sinh swap cosh / ; inline +: cot dup cos swap sin / ; inline +: coth dup cosh swap sinh / ; inline diff --git a/library/sdl/sdl-gfx.factor b/library/sdl/sdl-gfx.factor index c20827da60..6318679c54 100644 --- a/library/sdl/sdl-gfx.factor +++ b/library/sdl/sdl-gfx.factor @@ -67,16 +67,6 @@ IN: sdl USING: alien ; [ "surface*" "short" "short" "short" "short" "uint" ] alien-invoke ; -: pieColor ( surface x y rad start end color -- ) - "void" "sdl-gfx" "pieColor" - [ "surface*" "short" "short" "short" "short" "short" "uint" ] - alien-invoke ; - -: filledPieColor ( surface x y rad start end color -- ) - "void" "sdl-gfx" "filledPieColor" - [ "surface*" "short" "short" "short" "short" "short" "uint" ] - alien-invoke ; - : trigonColor ( surface x1 y1 x2 y2 x3 y3 color -- ) "void" "sdl-gfx" "trigonColor" [ "surface*" "short" "short" "short" "short" "short" "short" "uint" ] diff --git a/library/sdl/sdl-keyboard.factor b/library/sdl/sdl-keyboard.factor index 3817ec7ffc..6c62969ce1 100644 --- a/library/sdl/sdl-keyboard.factor +++ b/library/sdl/sdl-keyboard.factor @@ -15,7 +15,7 @@ sequences ; : modifiers, ( mod -- ) modifiers get [ - uncons pick bitand 0 = [ drop ] [ unique, ] ifte + uncons pick bitand 0 = [ drop ] [ , ] ifte ] each drop ; @@ -31,4 +31,4 @@ sequences ; [ dup keyboard-event-mod modifiers, keyboard-event-sym keysym, - ] make-list ; + ] [ ] make prune ; diff --git a/library/sdl/sdl-utils.factor b/library/sdl/sdl-utils.factor index f15639d751..6ea4c32332 100644 --- a/library/sdl/sdl-utils.factor +++ b/library/sdl/sdl-utils.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2004, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: sdl -USING: kernel lists math namespaces ; +USING: kernel lists math namespaces sequences ; SYMBOL: surface SYMBOL: width @@ -21,7 +21,7 @@ SYMBOL: bpp [ >r init-screen r> call SDL_Quit ] with-scope ; inline : rgb ( [ r g b ] -- n ) - 3unlist + first3 255 swap >fixnum 8 shift bitor swap >fixnum 16 shift bitor @@ -36,11 +36,11 @@ SYMBOL: bpp swap bitor ; : make-rect ( x y w h -- rect ) - - [ set-rect-h ] keep - [ set-rect-w ] keep - [ set-rect-y ] keep - [ set-rect-x ] keep ; + + [ set-sdl-rect-h ] keep + [ set-sdl-rect-w ] keep + [ set-sdl-rect-y ] keep + [ set-sdl-rect-x ] keep ; : with-pixels ( quot -- ) width get [ @@ -50,6 +50,16 @@ SYMBOL: bpp ] repeat ] repeat drop ; inline +: must-lock-surface? ( surface -- ? ) + #! This is a macro in SDL_video.h. + dup surface-offset 0 = [ + surface-flags + SDL_HWSURFACE SDL_ASYNCBLIT bitor SDL_RLEACCEL bitor + bitand 0 = not + ] [ + drop t + ] ifte ; + : with-surface ( quot -- ) #! Execute a quotation, locking the current surface if it #! is required (eg, hardware surface). @@ -60,3 +70,6 @@ SYMBOL: bpp slip ] ifte SDL_Flip drop ] with-scope ; inline + +: surface-rect ( x y surface -- rect ) + dup surface-w swap surface-h make-rect ; diff --git a/library/sdl/sdl-video.factor b/library/sdl/sdl-video.factor index 821b31101d..0c71978499 100644 --- a/library/sdl/sdl-video.factor +++ b/library/sdl/sdl-video.factor @@ -24,21 +24,21 @@ IN: sdl USING: alien kernel math ; : SDL_SRCALPHA HEX: 00010000 ; ! Blit uses source alpha blending : SDL_PREALLOC HEX: 01000000 ; ! Surface uses preallocated memory -BEGIN-STRUCT: rect +BEGIN-STRUCT: sdl-rect FIELD: short x FIELD: short y FIELD: ushort w FIELD: ushort h END-STRUCT -BEGIN-STRUCT: color +BEGIN-STRUCT: sdl-color FIELD: uchar r FIELD: uchar g FIELD: uchar b FIELD: uchar unused END-STRUCT -BEGIN-STRUCT: format +BEGIN-STRUCT: sdl-format FIELD: void* palette FIELD: uchar BitsPerPixel FIELD: uchar BytesPerPixel @@ -58,43 +58,26 @@ BEGIN-STRUCT: format FIELD: uchar alpha END-STRUCT -BEGIN-STRUCT: rect - FIELD: short clip-x - FIELD: short clip-y - FIELD: ushort clip-w - FIELD: ushort clip-h -END-STRUCT - BEGIN-STRUCT: surface - FIELD: uint flags - FIELD: format* format - FIELD: int w - FIELD: int h - FIELD: ushort pitch - FIELD: void* pixels - FIELD: int offset - FIELD: void* hwdata - FIELD: short clip-x - FIELD: short clip-y - FIELD: ushort clip-w - FIELD: ushort clip-h - FIELD: uint unused1 - FIELD: uint locked - FIELD: int map - FIELD: uint format_version - FIELD: int refcount + FIELD: uint flags + FIELD: sdl-format* format + FIELD: int w + FIELD: int h + FIELD: ushort pitch + FIELD: void* pixels + FIELD: int offset + FIELD: void* hwdata + FIELD: short clip-x + FIELD: short clip-y + FIELD: ushort clip-w + FIELD: ushort clip-h + FIELD: uint unused1 + FIELD: uint locked + FIELD: int map + FIELD: uint format_version + FIELD: int refcount END-STRUCT -: must-lock-surface? ( surface -- ? ) - #! This is a macro in SDL_video.h. - dup surface-offset 0 = [ - surface-flags - SDL_HWSURFACE SDL_ASYNCBLIT bitor SDL_RLEACCEL bitor - bitand 0 = not - ] [ - drop t - ] ifte ; - : SDL_VideoInit ( driver-name flags -- ) "int" "sdl" "SDL_VideoInit" [ "char*" "int" ] alien-invoke ; @@ -137,7 +120,7 @@ END-STRUCT "void" "sdl" "SDL_UnlockSurface" [ "surface*" ] alien-invoke ; : SDL_SetClipRect ( surface rect -- ? ) - "bool" "sdl" "SDL_SetClipRect" [ "surface*" "rect*" ] alien-invoke ; + "bool" "sdl" "SDL_SetClipRect" [ "surface*" "sdl-rect*" ] alien-invoke ; : SDL_FreeSurface ( surface -- ) "void" "sdl" "SDL_FreeSurface" [ "surface*" ] alien-invoke ; @@ -146,14 +129,14 @@ END-STRUCT #! The blit function should not be called on a locked #! surface. "int" "sdl" "SDL_UpperBlit" [ - "surface*" "rect*" - "surface*" "rect*" + "surface*" "sdl-rect*" + "surface*" "sdl-rect*" ] alien-invoke ; : SDL_FillRect ( surface rect color -- n ) #! If rect is null, fills entire surface. "bool" "sdl" "SDL_FillRect" - [ "surface*" "rect*" "uint" ] alien-invoke ; + [ "surface*" "sdl-rect*" "uint" ] alien-invoke ; : SDL_WM_SetCaption ( title icon -- ) "void" "sdl" "SDL_WM_SetCaption" diff --git a/library/stack.factor b/library/stack.factor deleted file mode 100644 index 2894406aaa..0000000000 --- a/library/stack.factor +++ /dev/null @@ -1,22 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: kernel - -: 2drop ( x x -- ) drop drop ; inline -: 3drop ( x x x -- ) drop drop drop ; inline -: 2dup ( x y -- x y x y ) over over ; inline -: 3dup ( x y z -- x y z x y z ) pick pick pick ; inline -: rot ( x y z -- y z x ) >r swap r> swap ; inline -: -rot ( x y z -- z x y ) swap >r swap r> ; inline -: dupd ( x y -- x x y ) >r dup r> ; inline -: swapd ( x y z -- y x z ) >r swap r> ; inline -: 2swap ( x y z t -- z t x y ) rot >r rot r> ; inline -: nip ( x y -- y ) swap drop ; inline -: 2nip ( x y z -- z ) >r drop drop r> ; inline -: tuck ( x y -- y x y ) dup >r swap r> ; inline - -: clear ( -- ) - #! Clear the datastack. For interactive use only; invoking - #! this from a word definition will clobber any values left - #! on the data stack by the caller. - { } set-datastack ; diff --git a/library/styles.factor b/library/styles.factor index a4a4e003b6..b279008e2e 100644 --- a/library/styles.factor +++ b/library/styles.factor @@ -3,12 +3,12 @@ IN: styles ! Colors are RGB triples. -: black [ 0 0 0 ] ; -: gray [ 128 128 128 ] ; -: white [ 255 255 255 ] ; -: red [ 255 0 0 ] ; -: green [ 0 255 0 ] ; -: blue [ 0 0 255 ] ; +: black { 0 0 0 } ; +: gray { 128 128 128 } ; +: white { 255 255 255 } ; +: red { 255 0 0 } ; +: green { 0 255 0 } ; +: blue { 0 0 255 } ; SYMBOL: foreground ! Used for text and outline shapes. SYMBOL: background ! Used for filled shapes. @@ -27,7 +27,5 @@ SYMBOL: bold-italic SYMBOL: underline -SYMBOL: icon - SYMBOL: presented SYMBOL: file diff --git a/library/syntax/generic.factor b/library/syntax/generic.factor index 4a85175cb0..eaf9959eae 100644 --- a/library/syntax/generic.factor +++ b/library/syntax/generic.factor @@ -3,19 +3,16 @@ ! Bootstrapping trick; see doc/bootstrap.txt. IN: !syntax -USING: syntax generic kernel lists namespaces parser words ; +USING: generic kernel lists namespaces parser sequences syntax +words ; : GENERIC: - #! GENERIC: bar == G: bar [ dup ] [ type ] ; - CREATE define-generic ; parsing + #! GENERIC: bar == G: bar simple-combination ; + CREATE dup reset-word define-generic ; parsing : G: - #! G: word picker dispatcher ; - CREATE [ 2unlist rot define-generic* ] [ ] ; parsing - -: BUILTIN: - #! Syntax: BUILTIN: ; - CREATE scan-word scan-word [ define-builtin ] [ ] ; parsing + #! G: word combination ; + CREATE dup reset-word [ define-generic* ] [ ] ; parsing : COMPLEMENT: ( -- ) #! Followed by a class name, then a complemented class. @@ -37,8 +34,7 @@ USING: syntax generic kernel lists namespaces parser words ; CREATE dup intern-symbol dup rot "superclass" set-word-prop dup predicate-word - [ dupd unit "predicate" set-word-prop ] keep - [ define-predicate ] [ ] ; parsing + [ define-predicate-class ] [ ] ; parsing : TUPLE: #! Followed by a tuple name, then slot names, then ; @@ -56,4 +52,9 @@ USING: syntax generic kernel lists namespaces parser words ; #! Followed by a tuple name, then constructor code, then ; #! Constructor code executes with the empty tuple on the #! stack. - scan-word [ define-constructor ] [ ] ; parsing + scan-word [ tuple-constructor ] keep + [ define-constructor ] [ ] ; parsing + +! Tuples. +: << f ; parsing +: >> reverse literal-tuple swons ; parsing diff --git a/library/syntax/math.factor b/library/syntax/math.factor deleted file mode 100644 index 76d24d7fa1..0000000000 --- a/library/syntax/math.factor +++ /dev/null @@ -1,28 +0,0 @@ -! Copyright (C) 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. - -IN: !syntax -USING: kernel lists math matrices parser sequences syntax -vectors ; - -! Complex numbers -: #{ f ; parsing -: }# 2unlist swap rect> swons ; parsing - -! Reading integers in other bases -: (BASE) ( base -- ) - #! Reads an integer in a specific base. - scan swap base> swons ; - -: HEX: 16 (BASE) ; parsing -: DEC: 10 (BASE) ; parsing -: OCT: 8 (BASE) ; parsing -: BIN: 2 (BASE) ; parsing - -! Matrices -: M[ f ; parsing - -: ]M - reverse - [ dup length swap car length ] keep - concat >vector swons ; parsing diff --git a/library/syntax/parse-numbers.factor b/library/syntax/parse-numbers.factor deleted file mode 100644 index f487b97b03..0000000000 --- a/library/syntax/parse-numbers.factor +++ /dev/null @@ -1,51 +0,0 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: parser -USING: errors generic kernel math sequences strings ; - -! Number parsing - -: not-a-number "Not a number" throw ; - -GENERIC: digit> ( ch -- n ) -M: digit digit> CHAR: 0 - ; -M: letter digit> CHAR: a - 10 + ; -M: LETTER digit> CHAR: A - 10 + ; -M: object digit> not-a-number ; - -: digit+ ( num digit base -- num ) - 2dup < [ rot * + ] [ not-a-number ] ifte ; - -: (base>) ( base str -- num ) - dup empty? [ - not-a-number - ] [ - 0 [ digit> pick digit+ ] reduce nip - ] ifte ; - -: base> ( str base -- num ) - #! Convert a string to an integer. Throw an error if - #! conversion fails. - swap "-" ?head [ (base>) neg ] [ (base>) ] ifte ; - -GENERIC: str>number ( str -- num ) - -M: string str>number 10 base> ; - -PREDICATE: string potential-ratio CHAR: / swap member? ; -M: potential-ratio str>number ( str -- num ) - dup CHAR: / swap index swap cut* - swap 10 base> swap 10 base> / ; - -PREDICATE: string potential-float CHAR: . swap member? ; -M: potential-float str>number ( str -- num ) - str>float ; - -: parse-number ( str -- num ) - #! Convert a string to a number; return f on error. - [ str>number ] [ [ drop f ] when ] catch ; - -: bin> 2 base> ; -: oct> 8 base> ; -: dec> 10 base> ; -: hex> 16 base> ; diff --git a/library/syntax/parse-stream.factor b/library/syntax/parse-stream.factor index e9b13221c9..ee45a7299c 100644 --- a/library/syntax/parse-stream.factor +++ b/library/syntax/parse-stream.factor @@ -1,48 +1,49 @@ -! Copyright (C) 2004, 2005 Slava Pestov. -! See http://factor.sf.net/license.txt for BSD license. -IN: parser -USING: kernel lists namespaces sequences io ; - -: file-vocabs ( -- ) - "file-in" get "in" set - "file-use" get "use" set ; - -: (parse-stream) ( name stream -- quot ) - #! Uses the current namespace for temporary variables. - [ - >r file set f ( initial parse tree ) r> - [ (parse) ] read-lines reverse - file off - line-number off - ] with-parser ; - -: parse-stream ( name stream -- quot ) - [ file-vocabs (parse-stream) ] with-scope ; - -: parse-file ( file -- quot ) - dup parse-stream ; - -: run-file ( file -- ) - #! Run a file. The file is read with the default IN:/USE: - #! for files. - parse-file call ; - -: (parse-file) ( file -- quot ) - dup (parse-stream) ; - -: (run-file) ( file -- ) - #! Run a file. The file is read with the same IN:/USE: as - #! the current interactive interpreter. - (parse-file) call ; - -: parse-resource ( path -- quot ) - #! Resources are loaded from the resource-path variable, or - #! the current directory if it is not set. Words defined in - #! resources have a definition source path starting with - #! resource:. This allows words that operate on source - #! files, like "jedit", to use a different resource path - #! at run time than was used at parse time. - "resource:" over append swap parse-stream ; - -: run-resource ( file -- ) - parse-resource call ; +! Copyright (C) 2004, 2005 Slava Pestov. +! See http://factor.sf.net/license.txt for BSD license. +IN: parser +USING: kernel lists namespaces sequences io words ; + +: file-vocabs ( -- ) + "scratchpad" "in" set + [ "syntax" "scratchpad" ] "use" set ; + +: (parse-stream) ( stream -- quot ) + [ + lines dup length [ ] + [ line-number set (parse) ] 2reduce + reverse + ] with-parser ; + +: parse-stream ( name stream -- quot ) + [ + swap file set file-vocabs + (parse-stream) + file off line-number off + ] with-scope ; + +: parse-file ( file -- quot ) + dup parse-stream ; + +: run-file ( file -- ) + parse-file call ; + +: parse-resource ( path -- quot ) + #! Resources are loaded from the resource-path variable, or + #! the current directory if it is not set. Words defined in + #! resources have a definition source path starting with + #! resource:. This allows words that operate on source + #! files, like "jedit", to use a different resource path + #! at run time than was used at parse time. + "resource:" over append swap parse-stream ; + +: run-resource ( file -- ) + parse-resource call ; + +: word-file ( word -- file ) + "file" word-prop dup [ + "resource:/" ?head [ resource-path swap path+ ] when + ] when ; + +: reload ( word -- ) + #! Reload the source file the word originated from. + word-file run-file ; diff --git a/library/syntax/parse-syntax.factor b/library/syntax/parse-syntax.factor index 335ab445ef..b38714b3ca 100644 --- a/library/syntax/parse-syntax.factor +++ b/library/syntax/parse-syntax.factor @@ -4,7 +4,7 @@ ! Bootstrapping trick; see doc/bootstrap.txt. IN: !syntax USING: alien errors generic hashtables kernel lists math -namespaces parser sequences strings syntax unparse vectors +namespaces parser sequences strings syntax vectors words ; : parsing ( -- ) @@ -17,20 +17,27 @@ words ; #! Mark the last word to be inlined. word t "inline" set-word-prop ; parsing +: flushable ( -- ) + #! Declare that a word may be removed if the value it + #! computes is unused. + word t "flushable" set-word-prop ; parsing + +: foldable ( -- ) + #! Declare a word as safe for compile-time evaluation. + #! Foldable implies flushable, since we can first fold to + #! a constant then flush the constant. + word + dup t "foldable" set-word-prop + t "flushable" set-word-prop ; parsing + ! The variable "in-definition" is set inside a : ... ;. ! ( and #! then add "stack-effect" and "documentation" ! properties to the current word if it is set. ! Booleans -! The canonical t is a heap-allocated dummy object. -BUILTIN: t 7 t? ; : t t swons ; parsing -! In the runtime, the canonical f is represented as a null -! pointer with tag 3. So -! f address . ==> 3 -BUILTIN: f 9 not ; : f f swons ; parsing ! Lists @@ -39,7 +46,7 @@ BUILTIN: f 9 not ; ! Conses (whose cdr might not be a list) : [[ f ; parsing -: ]] 2unlist swons swons ; parsing +: ]] first2 swons swons ; parsing ! Vectors : { f ; parsing @@ -49,17 +56,14 @@ BUILTIN: f 9 not ; : {{ f ; parsing : }} alist>hash swons ; parsing -! Tuples. -: << f ; parsing -: >> reverse literal-tuple swons ; parsing - ! Do not execute parsing word : POSTPONE: ( -- ) scan-word swons ; parsing ! Word definitions : : #! Begin a word definition. Word name follows. - CREATE [ define-compound ] [ ] "in-definition" on ; parsing + CREATE dup reset-generic [ define-compound ] + [ ] "in-definition" on ; parsing : ; #! End a word definition. @@ -68,12 +72,16 @@ BUILTIN: f 9 not ; ! Symbols : SYMBOL: #! A symbol is a word that pushes itself when executed. - CREATE define-symbol ; parsing + CREATE dup reset-generic define-symbol ; parsing : \ - #! Parsed as a piece of code that pushes a word on the stack - #! \ foo ==> [ foo ] car - scan-word literalize [ swons ] each ; parsing + #! Word literals: \ foo + scan-word literalize swons ; parsing + +! Long wrapper syntax. Only used in the rare case that another +! wrapper is being wrapped. +: W[ [ ] ; parsing +: ]W first swons ; parsing ! Vocabularies : PRIMITIVE: @@ -83,7 +91,7 @@ BUILTIN: f 9 not ; : DEFER: #! Create a word with no definition. Used for mutually #! recursive words. - CREATE drop ; parsing + CREATE dup reset-generic drop ; parsing : FORGET: #! Followed by a word name. The word is removed from its @@ -125,3 +133,17 @@ BUILTIN: f 9 not ; : #! #! Documentation comment. until-eol parsed-documentation ; parsing + +! Complex numbers +: #{ f ; parsing +: }# dup second swap first rect> swons ; parsing + +! Reading integers in other bases +: (BASE) ( base -- ) + #! Reads an integer in a specific base. + scan swap base> swons ; + +: HEX: 16 (BASE) ; parsing +: DEC: 10 (BASE) ; parsing +: OCT: 8 (BASE) ; parsing +: BIN: 2 (BASE) ; parsing diff --git a/library/syntax/parse-words.factor b/library/syntax/parse-words.factor index 98f84113e2..a67a00eeef 100644 --- a/library/syntax/parse-words.factor +++ b/library/syntax/parse-words.factor @@ -2,7 +2,7 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: parser USING: errors kernel lists math namespaces sequences io -strings unparser words ; +strings words ; ! The parser uses a number of variables: ! line - the line being parsed @@ -14,6 +14,8 @@ strings unparser words ; ! of vocabularies. If it is a parsing word, it is executed ! immediately. Otherwise it is appended to the parse tree. +SYMBOL: line-number + : use+ ( string -- ) "use" [ cons ] change ; : parsing? ( word -- ? ) @@ -58,7 +60,7 @@ global [ string-mode off ] bind : scan-word ( -- obj ) scan dup [ dup ";" = not string-mode get and [ - dup "use" get search [ ] [ str>number ] ?ifte + dup "use" get search [ ] [ string>number ] ?ifte ] unless ] when ; @@ -146,5 +148,5 @@ global [ string-mode off ] bind #! Read a string from the input stream, until it is #! terminated by a ". "col" [ - [ "line" get (parse-string) ] make-string swap + [ "line" get (parse-string) ] "" make swap ] change ; diff --git a/library/syntax/prettyprint.factor b/library/syntax/prettyprint.factor index e1d2a67ab3..1bf739f9aa 100644 --- a/library/syntax/prettyprint.factor +++ b/library/syntax/prettyprint.factor @@ -1,160 +1,364 @@ ! Copyright (C) 2003, 2005 Slava Pestov. ! See http://factor.sf.net/license.txt for BSD license. IN: prettyprint -USING: alien errors generic hashtables io kernel lists math -matrices memory namespaces parser presentation sequences strings -styles unparser vectors words ; +USING: alien generic hashtables io kernel lists math namespaces +parser sequences strings styles vectors words ; -SYMBOL: prettyprint-limit -SYMBOL: one-line -SYMBOL: tab-size +! State +SYMBOL: column +SYMBOL: indent +SYMBOL: last-newline SYMBOL: recursion-check +SYMBOL: line-count +SYMBOL: end-printing -GENERIC: prettyprint* ( indent obj -- indent ) +! Configuration +SYMBOL: tab-size +SYMBOL: margin +SYMBOL: nesting-limit +SYMBOL: length-limit +SYMBOL: line-limit +SYMBOL: string-limit -: unparse. ( obj -- ) - dup unparse swap presented swons unit format ; +global [ + 4 tab-size set + 64 margin set + recursion-check off + 0 column set + 0 indent set + 0 last-newline set + 0 line-count set + string-limit off +] bind -M: object prettyprint* ( indent obj -- indent ) - unparse. ; +TUPLE: pprinter stack ; -M: word prettyprint* ( indent word -- indent ) - dup parsing? [ \ POSTPONE: unparse. bl ] when unparse. ; +GENERIC: pprint-section* -: indent ( indent -- ) - #! Print the given number of spaces. - CHAR: \s fill write ; +TUPLE: section start end nl-after? indent ; -: prettyprint-newline ( indent -- ) - "\n" write indent ; +C: section ( length -- section ) + >r column [ dup rot + dup ] change r> + [ set-section-end ] keep + [ set-section-start ] keep + 0 over set-section-indent ; -: \? ( list -- ? ) - #! Is the head of the list a [ foo ] car? - dup car dup cons? [ - dup car word? [ - cdr [ drop f ] [ second \ car = ] ifte - ] [ - 2drop f - ] ifte +: section-fits? ( section -- ? ) + section-end last-newline get - indent get + margin get <= ; + +: line-limit? ( -- ? ) + line-limit get dup [ line-count get <= ] when ; + +: do-indent indent get CHAR: \s fill write ; + +: fresh-line ( n -- ) + #! n is current column position. + dup last-newline get = [ + drop ] [ - 2drop f + last-newline set + line-count inc + line-limit? [ "..." write end-printing get call ] when + "\n" write do-indent ] ifte ; -: prettyprint-elements ( indent list -- indent ) +TUPLE: text string style ; + +C: text ( string style -- section ) + pick length 1 +
over set-delegate + [ set-text-style ] keep + [ set-text-string ] keep ; + +M: text pprint-section* + dup text-string swap text-style format ; + +TUPLE: block sections ; + +C: block ( -- block ) + 0
over set-delegate + { } clone over set-block-sections + t over set-section-nl-after? + tab-size get over set-section-indent ; + +: pprinter-block pprinter-stack peek ; + +: block-empty? ( section -- ? ) + dup block? [ block-sections empty? ] [ drop f ] ifte ; + +: add-section ( section stream -- ) + over block-empty? [ + 2drop + ] [ + pprinter-block block-sections push + ] ifte ; + +: text ( string style -- ) pprinter get add-section ; + +: ( section -- ) section-indent indent [ swap - ] change ; + +: inset-section ( section -- ) + dup + dup section-nl-after? + [ section-end fresh-line ] [ drop ] ifte ; + +: pprint-section ( section -- ) + dup section-fits? + [ pprint-section* ] [ inset-section ] ifte ; + +TUPLE: newline ; + +C: newline ( -- section ) + 0
over set-delegate ; + +M: newline pprint-section* ( newline -- ) + section-start fresh-line ; + +: advance ( section -- ) + dup newline? [ + drop + ] [ + section-start last-newline get = [ " " write ] unless + ] ifte ; + +M: block pprint-section* ( block -- ) + f swap block-sections [ + over [ dup advance ] when pprint-section drop t + ] each drop ; + +: pprinter get pprinter-stack push ; + +: newline ( -- ) pprinter get add-section ; + +: end-block ( block -- ) column get swap set-section-end ; + +: pop-block ( pprinter -- ) pprinter-stack pop drop ; + +: (block>) ( -- ) + pprinter get dup pprinter-block + dup end-block swap dup pop-block add-section ; + +: last-block? ( -- ? ) + pprinter get pprinter-stack length 1 = ; + +: block> ( -- ) + #! Protect against malformed forms. + last-block? [ (block>) ] unless ; + +: block; ( -- ) + pprinter get pprinter-block f swap set-section-nl-after? + block> ; + +: end-blocks ( -- ) last-block? [ (block>) end-blocks ] unless ; + +C: pprinter ( -- stream ) + 1vector over set-pprinter-stack ; + +: do-pprint ( pprinter -- ) [ - dup \? [ - \ \ unparse. bl - uncons >r car unparse. bl - r> cdr prettyprint-elements - ] [ - uncons >r prettyprint* bl - r> prettyprint-elements - ] ifte - ] when* ; + end-printing set + dup pprinter-block pprint-section + end-blocks + ] callcc0 drop ; -: ?prettyprint-newline ( indent -- ) - one-line get [ - bl drop +GENERIC: pprint* ( obj -- ) + +: vocab-style ( vocab -- style ) + {{ + [[ "syntax" [ [[ foreground [ 128 128 128 ] ]] ] ]] + [[ "kernel" [ [[ foreground [ 0 0 128 ] ]] ] ]] + [[ "sequences" [ [[ foreground [ 128 0 0 ] ]] ] ]] + [[ "math" [ [[ foreground [ 0 128 0 ] ]] ] ]] + [[ "math-internals" [ [[ foreground [ 192 0 0 ] ]] ] ]] + [[ "kernel-internals" [ [[ foreground [ 192 0 0 ] ]] ] ]] + [[ "io-internals" [ [[ foreground [ 192 0 0 ] ]] ] ]] + }} hash ; + +: word-style ( word -- style ) + dup word-vocabulary vocab-style swap presented swons add ; + +: pprint-word ( obj -- ) + dup word-name [ "( unnamed )" ] unless* + swap word-style text ; + +M: object pprint* ( obj -- ) + "( unprintable object: " swap class word-name " )" append3 + f text ; + +M: real pprint* ( obj -- ) number>string f text ; + +: ch>ascii-escape ( ch -- esc ) + {{ + [[ CHAR: \e "\\e" ]] + [[ CHAR: \n "\\n" ]] + [[ CHAR: \r "\\r" ]] + [[ CHAR: \t "\\t" ]] + [[ CHAR: \0 "\\0" ]] + [[ CHAR: \\ "\\\\" ]] + [[ CHAR: \" "\\\"" ]] + }} hash ; + +: ch>unicode-escape ( ch -- esc ) + >hex 4 CHAR: 0 pad-left "\\u" swap append ; + +: unparse-ch ( ch -- ch/str ) + dup quotable? [ + , ] [ - prettyprint-newline + dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?ifte % ] ifte ; -: [ + margin get 3 - swap head "..." append + ] when + ] when ; -: prettyprint> ( indent -- indent ) - tab-size get - one-line get - [ dup prettyprint-newline ] unless ; +: pprint-string ( string prefix -- ) + [ % [ unparse-ch ] each CHAR: " , ] "" make + do-string-limit f text ; -: prettyprint-limit? ( indent -- ? ) - prettyprint-limit get dup [ >= ] [ nip ] ifte ; +M: string pprint* ( str -- str ) "\"" pprint-string ; -: check-recursion ( indent obj quot -- ? indent ) +M: sbuf pprint* ( str -- str ) "SBUF\" " pprint-string ; + +M: word pprint* ( word -- ) + dup "pprint-before-hook" word-prop call + dup pprint-word + "pprint-after-hook" word-prop call ; + +M: t pprint* drop "t" f text ; + +M: f pprint* drop "f" f text ; + +M: dll pprint* ( obj -- str ) dll-path "DLL\" " pprint-string ; + +: nesting-limit? ( -- ? ) + nesting-limit get dup + [ pprinter get pprinter-stack length < ] when ; + +: check-recursion ( obj quot -- indent ) #! We detect circular structure. - pick prettyprint-limit? >r - over recursion-check get memq? r> or [ - 2drop "..." write + nesting-limit? [ + 2drop "#" f text ] [ - over recursion-check [ cons ] change - call - recursion-check [ cdr ] change - ] ifte ; + over recursion-check get memq? [ + 2drop "&" f text + ] [ + over recursion-check [ cons ] change + call + recursion-check [ cdr ] change + ] ifte + ] ifte ; inline -: prettyprint-sequence ( indent start list end -- indent ) - #! Prettyprint a list, with start/end delimiters; eg, [ ], - #! or { }, or << >>. The body of the list is indented, - #! unless the list is empty. - over [ - >r >r unparse. prettyprint-elements - prettyprint> r> unparse. - ] [ - >r >r unparse. bl r> drop r> unparse. - ] ifte ; +: length-limit? ( seq -- seq ? ) + length-limit get dup + [ swap 2dup length < [ head t ] [ nip f ] ifte ] + [ drop f ] ifte ; -M: list prettyprint* ( indent list -- indent ) +: pprint-element ( object -- ) + dup parsing? [ \ POSTPONE: pprint-word ] when pprint* ; + +: pprint-elements ( seq -- ) + length-limit? >r + [ pprint-element ] each + r> [ "... " f text ] when ; + +: pprint-sequence ( seq start end -- ) + swap pprint* swap pprint-elements pprint* ; + +M: complex pprint* ( num -- ) + >rect 2vector \ #{ \ }# pprint-sequence ; + +M: cons pprint* ( list -- ) [ - \ [ swap \ ] prettyprint-sequence + dup list? [ \ [ \ ] ] [ uncons 2vector \ [[ \ ]] ] ifte + pprint-sequence ] check-recursion ; -M: cons prettyprint* ( indent cons -- indent ) - #! Here we turn the cons into a list of two elements. +M: vector pprint* ( vector -- ) + [ \ { \ } pprint-sequence ] check-recursion ; + +M: hashtable pprint* ( hashtable -- ) + [ hash>alist \ {{ \ }} pprint-sequence ] check-recursion ; + +M: tuple pprint* ( tuple -- ) [ - \ [[ swap uncons 2list \ ]] prettyprint-sequence + \ << pprint* + dup first pprint* + + \ >> pprint* ] check-recursion ; -M: vector prettyprint* ( indent vector -- indent ) +M: alien pprint* ( alien -- ) + dup expired? [ + drop "( alien expired )" + ] [ + \ ALIEN: pprint-word alien-address number>string + ] ifte f text ; + +M: wrapper pprint* ( wrapper -- ) + dup wrapped word? [ + \ \ pprint-word wrapped pprint-word + ] [ + wrapped 1vector \ W[ \ ]W pprint-sequence + ] ifte ; + +: with-pprint ( quot -- ) [ - \ { swap >list \ } prettyprint-sequence - ] check-recursion ; + pprinter set call pprinter get do-pprint + ] with-scope ; inline -M: hashtable prettyprint* ( indent hashtable -- indent ) +: pprint ( object -- ) [ pprint* ] with-pprint ; + +: unparse ( object -- str ) [ pprint ] string-out ; + +: . ( obj -- ) pprint terpri ; + +: pprint-short ( object -- string ) [ - \ {{ swap hash>alist \ }} prettyprint-sequence - ] check-recursion ; - -M: tuple prettyprint* ( indent tuple -- indent ) - [ - \ << swap >list \ >> prettyprint-sequence - ] check-recursion ; - -M: alien prettyprint* ( alien -- str ) - \ ALIEN: unparse. bl alien-address unparse write ; - -: matrix-rows. ( indent list -- indent ) - uncons >r [ one-line on prettyprint* ] with-scope r> - [ over ?prettyprint-newline matrix-rows. ] when* ; - -M: matrix prettyprint* ( indent obj -- indent ) - \ M[ unparse. bl >r 3 + r> - row-list matrix-rows. - bl \ ]M unparse. 3 - ; - -: prettyprint ( obj -- ) - [ - recursion-check off - 0 swap prettyprint* drop terpri + 1 line-limit set + 20 length-limit set + 2 nesting-limit set + string-limit on + pprint ] with-scope ; -: . ( obj -- ) - [ - one-line on - 16 prettyprint-limit set - prettyprint - ] with-scope ; +: unparse-short ( object -- str ) [ pprint-short ] string-out ; -: [.] ( sequence -- ) - #! Unparse each element on its own line. - [ . ] each ; +: short. ( object -- ) + dup unparse-short swap write-object terpri ; -: .s datastack reverse [.] flush ; -: .r callstack reverse [.] flush ; -: .n namestack [.] flush ; -: .c catchstack [.] flush ; +: sequence. ( sequence -- ) [ short. ] each ; + +: stack. ( sequence -- ) reverse-slice sequence. ; + +: .s datastack stack. ; +: .r callstack stack. ; ! For integers only : .b >bin print ; : .o >oct print ; : .h >hex print ; -global [ 4 tab-size set ] bind +: define-open + #! The word will be pretty-printed as a block opener. + #! Examples are [ { {{ << and so on. + [ ] "pprint-before-hook" set-word-prop ; + +{ + { POSTPONE: [ POSTPONE: ] } + { POSTPONE: { POSTPONE: } } + { POSTPONE: {{ POSTPONE: }} } + { POSTPONE: [[ POSTPONE: ]] } + { POSTPONE: [[ POSTPONE: ]] } +} [ first2 define-close define-open ] each diff --git a/library/syntax/see.factor b/library/syntax/see.factor index 01a4c93ca1..dc2f19a0c5 100644 --- a/library/syntax/see.factor +++ b/library/syntax/see.factor @@ -2,131 +2,128 @@ ! See http://factor.sf.net/license.txt for BSD license. IN: prettyprint USING: generic hashtables io kernel lists namespaces sequences -streams strings styles unparser words ; +styles words ; -: prettyprint-IN: ( word -- ) - \ IN: unparse. bl word-vocabulary write terpri ; +: declaration. ( word prop -- ) + tuck word-name word-prop [ pprint-word ] [ drop ] ifte ; -: prettyprint-prop ( word prop -- ) - tuck word-name word-prop [ - bl unparse. +: declarations. ( word -- ) + [ + POSTPONE: parsing + POSTPONE: inline + POSTPONE: foldable + POSTPONE: flushable + ] [ declaration. ] each-with ; + +: comment. ( comment -- ) + [ [[ font-style italic ]] ] text ; + +: stack-picture% ( seq -- string ) + [ word-name % " " % ] each ; + +: effect>string ( effect -- string ) + [ + " " % + dup first stack-picture% + "-- " % + second stack-picture% + ] "" make ; + +: stack-effect ( word -- string ) + dup "stack-effect" word-prop [ ] [ + "infer-effect" word-prop + dup [ effect>string ] when + ] ?ifte ; + +: stack-effect. ( string -- ) + [ "(" swap ")" append3 comment. ] when* ; + +: in. ( word -- ) + r [ " " % unparse % ] each r> - " --" % - [ " " % unparse % ] each - " )" % - ] make-string comment. ; - -: stack-effect. ( word -- ) - dup "stack-effect" word-prop [ - [ CHAR: ( , % CHAR: ) , ] make-string - comment. - ] [ - "infer-effect" word-prop dup [ - infer-effect. - ] [ - drop - ] ifte - ] ?ifte ; - -: documentation. ( indent word -- indent ) - "documentation" word-prop [ - "\n" split [ - "#!" swap append comment. - dup prettyprint-newline - ] each - ] when* ; - -: definer. ( word -- ) dup definer unparse. bl unparse. bl ; - -GENERIC: (see) ( word -- ) - -M: compound (see) ( word -- ) - tab-size get dup indent swap - [ documentation. ] keep - [ word-def prettyprint-elements \ ; unparse. ] keep - prettyprint-plist terpri drop ; - -: prettyprint-M: ( -- indent ) - \ M: unparse. bl tab-size get ; - -: prettyprint-; \ ; unparse. terpri ; - -: method. ( word [[ class method ]] -- ) - uncons >r >r >r prettyprint-M: r> r> unparse. bl unparse. bl - dup prettyprint-newline r> prettyprint-elements - prettyprint-; drop ; - -M: generic (see) ( word -- ) - tab-size get dup indent [ - one-line on - over "picker" word-prop prettyprint* bl - over "dispatcher" word-prop prettyprint* bl - ] with-scope - drop - \ ; unparse. terpri - dup methods [ method. ] each-with ; - -M: word (see) drop ; - -GENERIC: class. - M: union class. - \ UNION: unparse. bl - dup unparse. bl - 0 swap "members" word-prop prettyprint-elements drop - prettyprint-; ; + \ UNION: pprint-word + dup pprint-word + "members" word-prop pprint-elements pprint-; newline ; M: complement class. - \ COMPLEMENT: unparse. bl - dup unparse. bl - "complement" word-prop unparse. terpri ; - -M: builtin class. - \ BUILTIN: unparse. bl - dup unparse. bl - dup "builtin-type" word-prop unparse write bl - 0 swap "slots" word-prop prettyprint-elements drop - prettyprint-; ; + \ COMPLEMENT: pprint-word + dup pprint-word + "complement" word-prop pprint-word newline ; M: predicate class. - \ PREDICATE: unparse. bl - dup "superclass" word-prop unparse. bl - dup unparse. bl - tab-size get dup prettyprint-newline swap - "definition" word-prop prettyprint-elements drop - prettyprint-; ; + \ PREDICATE: pprint-word + dup "superclass" word-prop pprint-word + dup pprint-word + digit ( n -- ch ) - dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] ifte ; - -: integer, ( num radix -- ) - dup >r /mod >digit , dup 0 > [ - r> integer, - ] [ - r> 2drop - ] ifte ; - -: >base ( num radix -- string ) - #! Convert a number to a string in a certain base. - [ - over 0 < [ - swap neg swap integer, CHAR: - , - ] [ - integer, - ] ifte - ] make-rstring ; - -: >dec ( num -- string ) 10 >base ; -: >bin ( num -- string ) 2 >base ; -: >oct ( num -- string ) 8 >base ; -: >hex ( num -- string ) 16 >base ; - -M: integer unparse ( obj -- str ) >dec ; - -M: ratio unparse ( num -- str ) - [ - dup - numerator unparse % - CHAR: / , - denominator unparse % - ] make-string ; - -: fix-float ( str -- str ) - #! This is terrible. Will go away when we do our own float - #! output. - CHAR: . over member? [ ".0" append ] unless ; - -M: float unparse ( float -- str ) - (unparse-float) fix-float ; - -M: complex unparse ( num -- str ) - [ - "#{ " % - dup - real unparse % - " " % - imaginary unparse % - " }#" % - ] make-string ; - -: ch>ascii-escape ( ch -- esc ) - [ - [[ CHAR: \e "\\e" ]] - [[ CHAR: \n "\\n" ]] - [[ CHAR: \r "\\r" ]] - [[ CHAR: \t "\\t" ]] - [[ CHAR: \0 "\\0" ]] - [[ CHAR: \\ "\\\\" ]] - [[ CHAR: \" "\\\"" ]] - ] assoc ; - -: ch>unicode-escape ( ch -- esc ) - >hex 4 CHAR: 0 pad-left "\\u" swap append ; - -: unparse-ch ( ch -- ch/str ) - dup quotable? [ - , - ] [ - dup ch>ascii-escape [ ] [ ch>unicode-escape ] ?ifte % - ] ifte ; - -: unparse-string [ unparse-ch ] each ; - -M: string unparse ( str -- str ) - [ CHAR: " , unparse-string CHAR: " , ] make-string ; - -M: sbuf unparse ( str -- str ) - [ "SBUF\" " % unparse-string CHAR: " , ] make-string ; - -M: word unparse ( obj -- str ) word-name dup "( unnamed )" ? ; - -M: t unparse drop "t" ; -M: f unparse drop "f" ; - -M: dll unparse ( obj -- str ) - [ "DLL\" " % dll-path unparse-string CHAR: " , ] make-string ; - -: hex-string ( str -- str ) - [ [ >hex 2 CHAR: 0 pad-left % ] each ] make-string ; diff --git a/library/test/benchmark/empty-loop.factor b/library/test/benchmark/empty-loop.factor index 10efe660c5..b0de42a23b 100644 --- a/library/test/benchmark/empty-loop.factor +++ b/library/test/benchmark/empty-loop.factor @@ -1,8 +1,5 @@ IN: temporary -USE: compiler -USE: kernel -USE: math -USE: test +USING: compiler kernel math sequences test ; : empty-loop-1 ( n -- ) [ ] times ; compiled @@ -10,5 +7,9 @@ USE: test : empty-loop-2 ( n -- ) [ ] repeat ; compiled +: empty-loop-3 ( n -- ) + [ drop ] each ; compiled + [ ] [ 5000000 empty-loop-1 ] unit-test [ ] [ 5000000 empty-loop-2 ] unit-test +[ ] [ 5000000 empty-loop-3 ] unit-test diff --git a/library/test/benchmark/fac.factor b/library/test/benchmark/fac.factor index 56de5debc0..457432406b 100644 --- a/library/test/benchmark/fac.factor +++ b/library/test/benchmark/fac.factor @@ -1,8 +1,5 @@ IN: temporary -USE: math -USE: test -USE: compiler -USE: kernel +USING: compiler kernel math sequences test ; : (fac) ( n! i -- n! ) dup 0 = [ @@ -16,10 +13,10 @@ USE: kernel : small-fac-benchmark #! This tests fixnum math. - 1 swap [ 10 fac 10 [ [ 1 + / ] keep ] repeat max ] times ; compiled + 1 swap [ 10 fac 10 [ 1 + / ] each max ] times ; compiled : big-fac-benchmark - 10000 fac 10000 [ [ 1 + / ] keep ] repeat ; compiled + 10000 fac 10000 [ 1 + / ] each ; compiled [ 1 ] [ big-fac-benchmark ] unit-test diff --git a/library/test/benchmark/hashtables.factor b/library/test/benchmark/hashtables.factor index 53a7a72290..57334e448b 100644 --- a/library/test/benchmark/hashtables.factor +++ b/library/test/benchmark/hashtables.factor @@ -1,10 +1,10 @@ -USING: compiler hashtables kernel math namespaces test ; +USING: compiler hashtables kernel math namespaces sequences test ; : store-hash ( hashtable n -- ) - [ [ >float dup pick set-hash ] keep ] repeat drop ; + [ >float dup pick set-hash ] each drop ; : lookup-hash ( hashtable n -- ) - [ [ >float over hash drop ] keep ] repeat drop ; + [ >float over hash drop ] each drop ; : hashtable-benchmark ( -- ) 100 [ diff --git a/library/test/benchmark/image.factor b/library/test/benchmark/image.factor index 2a06f3a2e4..b4812ec96b 100644 --- a/library/test/benchmark/image.factor +++ b/library/test/benchmark/image.factor @@ -2,7 +2,6 @@ IN: temporary USING: generic image kernel math namespaces parser test ; [ - boot-quot off "/library/bootstrap/boot-stage1.factor" run-resource ] with-image drop diff --git a/library/test/benchmark/prettyprint.factor b/library/test/benchmark/prettyprint.factor index 58f5a0b74d..fa2f583b01 100644 --- a/library/test/benchmark/prettyprint.factor +++ b/library/test/benchmark/prettyprint.factor @@ -6,6 +6,4 @@ USE: words USE: kernel USE: sequences -[ ] [ gensym dup [ ] define-compound . ] unit-test [ ] [ vocabs [ words [ see ] each ] each ] unit-test -[ ] [ classes [ methods. ] each ] unit-test diff --git a/library/test/benchmark/sort.factor b/library/test/benchmark/sort.factor index 266e705744..ef8cc56d93 100644 --- a/library/test/benchmark/sort.factor +++ b/library/test/benchmark/sort.factor @@ -1,13 +1,7 @@ IN: temporary -USE: lists -USE: kernel -USE: math -USE: namespaces -USE: random -USE: test -USE: compiler +USING: compiler kernel math sequences test ; : sort-benchmark - [ 100000 [ 0 10000 random-int , ] times ] make-list [ > ] sort drop ; compiled + 100000 [ drop 0 10000 random-int ] map number-sort drop ; compiled [ ] [ sort-benchmark ] unit-test diff --git a/library/test/benchmark/strings.factor b/library/test/benchmark/strings.factor index c9c86e29d4..dad011b070 100644 --- a/library/test/benchmark/strings.factor +++ b/library/test/benchmark/strings.factor @@ -4,7 +4,7 @@ USING: compiler kernel math namespaces sequences strings test ; : string-step ( n str -- ) 2dup length > [ - dup [ "123" % % "456" % % "789" % ] make-string + dup [ "123" % % "456" % % "789" % ] "" make dup dup length 2 /i 0 swap rot subseq swap dup length 2 /i 1 + 1 swap rot subseq append string-step diff --git a/library/test/benchmark/vectors.factor b/library/test/benchmark/vectors.factor index 86284bb708..99245f8a21 100644 --- a/library/test/benchmark/vectors.factor +++ b/library/test/benchmark/vectors.factor @@ -3,7 +3,7 @@ USING: compiler kernel math sequences test vectors ; ! http://inferno.bell-labs.com/cm/cs/who/bwk/interps/pap.html : fill-vector ( n -- vector ) - dup swap [ [ dup pick set-nth ] keep ] repeat ; compiled + dup swap [ dup pick set-nth ] each ; compiled : copy-elt ( vec-y vec-x n -- ) #! Copy nth element from vec-x to vec-y. diff --git a/library/test/combinators.factor b/library/test/combinators.factor index 4ed848bd37..076edc3f44 100644 --- a/library/test/combinators.factor +++ b/library/test/combinators.factor @@ -1,4 +1,5 @@ IN: temporary +USING: alien errors strings ; USE: kernel USE: math USE: test @@ -30,6 +31,32 @@ USE: namespaces [ "2\n" ] [ [ 1 2 [ . ] [ sq . ] ?ifte ] string-out ] unit-test [ "9\n" ] [ [ 3 f [ . ] [ sq . ] ?ifte ] string-out ] unit-test -[ [ 9 8 7 6 5 4 3 2 1 ] ] -[ [ 10 [ , ] [ 1 - dup dup 0 = [ drop f ] when ] while ] make-list nip ] -unit-test +[ "even" ] [ + 2 { + { [ dup 2 mod 0 = ] [ drop "even" ] } + { [ dup 2 mod 1 = ] [ drop "odd" ] } + } cond +] unit-test + +[ "odd" ] [ + 3 { + { [ dup 2 mod 0 = ] [ drop "even" ] } + { [ dup 2 mod 1 = ] [ drop "odd" ] } + } cond +] unit-test + +[ "neither" ] [ + 3 { + { [ dup string? ] [ drop "string" ] } + { [ dup float? ] [ drop "float" ] } + { [ dup alien? ] [ drop "alien" ] } + { [ t ] [ drop "neither" ] } + } cond +] unit-test + +[ ] [ + [ + [ drop ] [ drop ] catch + [ drop ] [ drop ] catch + ] keep-datastack +] unit-test diff --git a/library/test/compiler/identities.factor b/library/test/compiler/identities.factor new file mode 100644 index 0000000000..2926e540b7 --- /dev/null +++ b/library/test/compiler/identities.factor @@ -0,0 +1,60 @@ +IN: temporary +USING: compiler kernel math test vectors ; + +[ 5 ] [ 5 [ 0 + ] compile-1 ] unit-test +[ 5 ] [ 5 [ 0 swap + ] compile-1 ] unit-test + +[ 5 ] [ 5 [ 0 - ] compile-1 ] unit-test +[ -5 ] [ 5 [ 0 swap - ] compile-1 ] unit-test +[ 0 ] [ 5 [ dup - ] compile-1 ] unit-test + +[ 5 ] [ 5 [ 1 * ] compile-1 ] unit-test +[ 5 ] [ 5 [ 1 swap * ] compile-1 ] unit-test +[ 0 ] [ 5 [ 0 * ] compile-1 ] unit-test +[ 0 ] [ 5 [ 0 swap * ] compile-1 ] unit-test +[ -5 ] [ 5 [ -1 * ] compile-1 ] unit-test +[ -5 ] [ 5 [ -1 swap * ] compile-1 ] unit-test + +[ 5 ] [ 5 [ 1 / ] compile-1 ] unit-test +[ 1/5 ] [ 5 [ 1 swap / ] compile-1 ] unit-test +[ -5 ] [ 5 [ -1 / ] compile-1 ] unit-test + +[ 0 ] [ 5 [ 1 mod ] compile-1 ] unit-test +[ 0 ] [ 5 [ 1 rem ] compile-1 ] unit-test + +[ 5 ] [ 5 [ 1 ^ ] compile-1 ] unit-test +[ 25 ] [ 5 [ 2 ^ ] compile-1 ] unit-test +[ 1/5 ] [ 5 [ -1 ^ ] compile-1 ] unit-test +[ 1/25 ] [ 5 [ -2 ^ ] compile-1 ] unit-test +[ 1 ] [ 5 [ 1 swap ^ ] compile-1 ] unit-test + +[ 5 ] [ 5 [ -1 bitand ] compile-1 ] unit-test +[ 0 ] [ 5 [ 0 bitand ] compile-1 ] unit-test +[ 5 ] [ 5 [ -1 swap bitand ] compile-1 ] unit-test +[ 0 ] [ 5 [ 0 swap bitand ] compile-1 ] unit-test +[ 5 ] [ 5 [ dup bitand ] compile-1 ] unit-test + +[ 5 ] [ 5 [ 0 bitor ] compile-1 ] unit-test +[ -1 ] [ 5 [ -1 bitor ] compile-1 ] unit-test +[ 5 ] [ 5 [ 0 swap bitor ] compile-1 ] unit-test +[ -1 ] [ 5 [ -1 swap bitor ] compile-1 ] unit-test +[ 5 ] [ 5 [ dup bitor ] compile-1 ] unit-test + +[ 5 ] [ 5 [ 0 bitxor ] compile-1 ] unit-test +[ 5 ] [ 5 [ 0 swap bitxor ] compile-1 ] unit-test +[ -6 ] [ 5 [ -1 bitxor ] compile-1 ] unit-test +[ -6 ] [ 5 [ -1 swap bitxor ] compile-1 ] unit-test +[ 0 ] [ 5 [ dup bitxor ] compile-1 ] unit-test + +[ 0 ] [ 5 [ 0 swap shift ] compile-1 ] unit-test +[ 5 ] [ 5 [ 0 shift ] compile-1 ] unit-test + +[ f ] [ 5 [ dup < ] compile-1 ] unit-test +[ t ] [ 5 [ dup <= ] compile-1 ] unit-test +[ f ] [ 5 [ dup > ] compile-1 ] unit-test +[ t ] [ 5 [ dup >= ] compile-1 ] unit-test + +[ t ] [ 5 [ dup eq? ] compile-1 ] unit-test +[ t ] [ 5 [ dup = ] compile-1 ] unit-test +[ t ] [ 5 [ dup number= ] compile-1 ] unit-test +[ t ] [ \ vector [ \ vector = ] compile-1 ] unit-test diff --git a/library/test/compiler/ifte.factor b/library/test/compiler/ifte.factor index 06914b6f38..1768eb4a8c 100644 --- a/library/test/compiler/ifte.factor +++ b/library/test/compiler/ifte.factor @@ -1,4 +1,5 @@ IN: temporary +USING: alien strings ; USE: compiler USE: test USE: math @@ -94,3 +95,41 @@ DEFER: countdown-b [ 3 ] [ f dummy-unless-3 ] unit-test [ 4 ] [ 4 dummy-unless-3 ] unit-test + +[ "even" ] [ + [ + 2 { + { [ dup 2 mod 0 = ] [ drop "even" ] } + { [ dup 2 mod 1 = ] [ drop "odd" ] } + } cond + ] compile-1 +] unit-test + +[ "odd" ] [ + [ + 3 { + { [ dup 2 mod 0 = ] [ drop "even" ] } + { [ dup 2 mod 1 = ] [ drop "odd" ] } + } cond + ] compile-1 +] unit-test + +[ "neither" ] [ + [ + 3 { + { [ dup string? ] [ drop "string" ] } + { [ dup float? ] [ drop "float" ] } + { [ dup alien? ] [ drop "alien" ] } + { [ t ] [ drop "neither" ] } + } cond + ] compile-1 +] unit-test + +[ 3 ] [ + [ + 3 { + { [ dup fixnum? ] [ ] } + { [ t ] [ drop t ] } + } cond + ] compile-1 +] unit-test diff --git a/library/test/compiler/intrinsics.factor b/library/test/compiler/intrinsics.factor index d77988d6b7..b0e74681d1 100644 --- a/library/test/compiler/intrinsics.factor +++ b/library/test/compiler/intrinsics.factor @@ -3,9 +3,6 @@ USING: compiler kernel kernel-internals lists math math-internals test words ; ! Make sure that intrinsic ops compile to correct code. -: compile-1 ( quot -- word ) - gensym [ swap define-compound ] keep dup compile execute ; - [ 1 ] [ [[ 1 2 ]] [ 0 slot ] compile-1 ] unit-test [ 1 ] [ [ [[ 1 2 ]] 0 slot ] compile-1 ] unit-test [ 3 ] [ 3 1 2 cons [ [ 0 set-slot ] keep ] compile-1 car ] unit-test @@ -15,6 +12,9 @@ math-internals test words ; [ 3 ] [ 3 1 2 [ cons [ 1 set-slot ] keep ] compile-1 cdr ] unit-test [ 3 ] [ [ 3 1 2 cons [ 1 set-slot ] keep ] compile-1 cdr ] unit-test +! Write barrier hits on the wrong value were causing segfaults +[ -3 ] [ -3 1 2 [ cons [ 1 set-slot ] keep ] compile-1 cdr ] unit-test + [ ] [ 1 [ drop ] compile-1 ] unit-test [ ] [ [ 1 drop ] compile-1 ] unit-test [ ] [ [ 1 2 2drop ] compile-1 ] unit-test @@ -125,9 +125,6 @@ math-internals test words ; [ t ] [ "hey" type "hey" [ type ] compile-1 eq? ] unit-test [ t ] [ f type f [ type ] compile-1 eq? ] unit-test -[ 1 1 0 ] [ 1 1 [ arithmetic-type ] compile-1 ] unit-test -[ 1.0 1.0 5 ] [ 1.0 1 [ arithmetic-type ] compile-1 ] unit-test - [ 5 ] [ 1 2 [ eq? [ 3 ] [ 5 ] ifte ] compile-1 ] unit-test [ 3 ] [ 2 2 [ eq? [ 3 ] [ 5 ] ifte ] compile-1 ] unit-test [ 3 ] [ 1 2 [ fixnum< [ 3 ] [ 5 ] ifte ] compile-1 ] unit-test @@ -166,3 +163,5 @@ math-internals test words ; [ t ] [ 1 20 shift neg 1 20 shift neg [ fixnum* ] compile-1 1 40 shift = ] unit-test [ 268435456 ] [ -268435456 >fixnum -1 [ fixnum/i ] compile-1 ] unit-test + +[ t ] [ f [ f eq? ] compile-1 ] unit-test diff --git a/library/test/compiler/linearizer.factor b/library/test/compiler/linearizer.factor index 5825c52181..bd89e6ccf8 100644 --- a/library/test/compiler/linearizer.factor +++ b/library/test/compiler/linearizer.factor @@ -6,6 +6,10 @@ USE: compiler-frontend USE: inference USE: words +: fie [ ] [ ] ifte ; + +[ ] [ \ fie word-def dataflow linearize drop ] unit-test + : foo [ drop ] each-word ; [ ] [ \ foo word-def dataflow linearize drop ] unit-test diff --git a/library/test/compiler/optimizer.factor b/library/test/compiler/optimizer.factor index de0fe83399..e56ce41343 100644 --- a/library/test/compiler/optimizer.factor +++ b/library/test/compiler/optimizer.factor @@ -1,4 +1,5 @@ IN: temporary +USING: generic kernel-internals strings vectors ; USE: test USE: assembler USE: compiler @@ -9,26 +10,36 @@ USE: math USE: kernel USE: lists USE: sequences +USE: prettyprint +! Some dataflow tests +! [ 3 ] [ 1 2 3 (subst-value) ] unit-test +! [ 1 ] [ 1 2 2 (subst-value) ] unit-test +! +! [ { "one" "one" "three" "three" } ] +! [ +! { "one" "two" "three" } { 1 2 3 } { 1 1 3 3 } +! clone [ (subst-values) ] keep +! ] unit-test +! +! [ << meet f { "one" 2 3 } >> ] +! [ "one" 1 << meet f { 1 2 3 } >> clone (subst-value) ] unit-test + +! Literal kill tests : kill-set* dataflow kill-set [ literal-value ] map ; : foo 1 2 3 ; -[ [ ] ] [ \ foo word-def dataflow kill-set ] unit-test +[ { } ] [ \ foo word-def dataflow kill-set ] unit-test -[ [ [ 1 ] [ 2 ] ] ] [ [ [ 1 ] [ 2 ] ifte ] kill-set* ] unit-test +[ { [ 1 ] [ 2 ] } ] [ [ [ 1 ] [ 2 ] ifte ] kill-set* ] unit-test -[ [ [ 1 ] [ 2 ] ] ] [ [ [ 1 ] [ 2 ] ifte ] kill-set* ] unit-test +[ { [ 1 ] [ 2 ] } ] [ [ [ 1 ] [ 2 ] ifte ] kill-set* ] unit-test -[ [ t t f ] ] [ [ 1 2 3 ] [ - f ] map - [ [ literal-value 2 <= ] subset ] keep kill-mask -] unit-test - -[ t ] [ - 3 [ 3 over [ ] [ ] ifte drop ] dataflow - kill-set [ value= ] contains-with? +[ [ t t f ] ] [ + [ 1 2 3 ] [ ] map + [ [ literal-value 2 <= ] subset ] keep in-d-node <#drop> kill-mask ] unit-test : literal-kill-test-1 4 compiled-offset cell 2 * - ; compiled @@ -43,7 +54,7 @@ USE: sequences [ 3 ] [ literal-kill-test-3 ] unit-test -[ [ [ 3 ] [ dup ] ] ] [ [ [ 3 ] [ dup ] ifte drop ] kill-set* ] unit-test +[ { [ 3 ] [ dup ] 3 } ] [ [ [ 3 ] [ dup ] ifte drop ] kill-set* ] unit-test : literal-kill-test-4 5 swap [ 3 ] [ dup ] ifte 2drop ; compiled @@ -51,7 +62,7 @@ USE: sequences [ ] [ t literal-kill-test-4 ] unit-test [ ] [ f literal-kill-test-4 ] unit-test -[ [ [ 3 ] [ dup ] ] ] [ \ literal-kill-test-4 word-def kill-set* ] unit-test +[ { 5 [ 3 ] [ dup ] 3 } ] [ \ literal-kill-test-4 word-def kill-set* ] unit-test : literal-kill-test-5 5 swap [ 5 ] [ dup ] ifte 2drop ; compiled @@ -59,7 +70,7 @@ USE: sequences [ ] [ t literal-kill-test-5 ] unit-test [ ] [ f literal-kill-test-5 ] unit-test -[ [ [ 5 ] [ dup ] ] ] [ \ literal-kill-test-5 word-def kill-set* ] unit-test +[ { 5 [ 5 ] [ dup ] 5 } ] [ \ literal-kill-test-5 word-def kill-set* ] unit-test : literal-kill-test-6 5 swap [ dup ] [ dup ] ifte 2drop ; compiled @@ -67,5 +78,96 @@ USE: sequences [ ] [ t literal-kill-test-6 ] unit-test [ ] [ f literal-kill-test-6 ] unit-test -[ [ 5 [ dup ] [ dup ] ] ] [ \ literal-kill-test-6 word-def kill-set* ] unit-test +[ { 5 [ dup ] [ dup ] } ] [ \ literal-kill-test-6 word-def kill-set* ] unit-test +: literal-kill-test-7 + [ 1 2 3 ] >r + r> drop ; compiled + +[ 4 ] [ 2 2 literal-kill-test-7 ] unit-test + +! Test method inlining +[ string ] [ + \ string + [ repeated integer string mirror array reversed sbuf + slice vector diagonal general-list ] + min-class +] unit-test + +[ f ] [ + \ fixnum + [ fixnum integer letter ] + min-class +] unit-test + +[ fixnum ] [ + \ fixnum + [ fixnum integer object ] + min-class +] unit-test + +[ integer ] [ + \ fixnum + [ integer float object ] + min-class +] unit-test + +[ object ] [ + \ word + [ integer float object ] + min-class +] unit-test + +GENERIC: xyz +M: cons xyz xyz ; + +[ ] [ \ xyz compile ] unit-test + +! Test predicate inlining +: pred-test-1 + dup cons? [ + dup general-list? [ "general-list" ] [ "nope" ] ifte + ] [ + "not a cons" + ] ifte ; compiled + +[ [[ 1 2 ]] "general-list" ] [ [[ 1 2 ]] pred-test-1 ] unit-test + +: pred-test-2 + dup fixnum? [ + dup integer? [ "integer" ] [ "nope" ] ifte + ] [ + "not a fixnum" + ] ifte ; compiled + +[ 1 "integer" ] [ 1 pred-test-2 ] unit-test + +TUPLE: pred-test ; + +: pred-test-3 + dup tuple? [ + dup pred-test? [ "pred-test" ] [ "nope" ] ifte + ] [ + "not a tuple" + ] ifte ; compiled + +[ << pred-test >> "pred-test" ] [ << pred-test >> pred-test-3 ] unit-test + +: pred-test-4 + dup pred-test? [ + dup tuple? [ "pred-test" ] [ "nope" ] ifte + ] [ + "not a tuple" + ] ifte ; compiled + +[ << pred-test >> "pred-test" ] [ << pred-test >> pred-test-4 ] unit-test + +: inline-test + "nom" = ; compiled + +[ t ] [ "nom" inline-test ] unit-test +[ f ] [ "shayin" inline-test ] unit-test +[ f ] [ 3 inline-test ] unit-test + +: fixnum-declarations >fixnum 24 shift 1234 bitxor ; compiled + +[ ] [ 1000000 fixnum-declarations . ] unit-test diff --git a/library/test/compiler/print-dataflow.factor b/library/test/compiler/print-dataflow.factor new file mode 100644 index 0000000000..01c0c436bc --- /dev/null +++ b/library/test/compiler/print-dataflow.factor @@ -0,0 +1,9 @@ +USING: inference kernel kernel-internals math test words ; + +[ ] [ [ 2 ] t dataflow. ] unit-test +[ ] [ [ 3 + ] t dataflow. ] unit-test +[ ] [ [ drop ] t dataflow. ] unit-test +[ ] [ [ [ sq ] [ abs ] ifte ] t dataflow. ] unit-test +[ ] [ [ { [ sq ] [ abs ] } dispatch ] t dataflow. ] unit-test +[ ] [ \ unify-values word-def t dataflow. ] unit-test +[ ] [ [ 0 0 / ] t dataflow. ] unit-test diff --git a/library/test/continuations.factor b/library/test/continuations.factor index 755489f841..3c8fd435b0 100644 --- a/library/test/continuations.factor +++ b/library/test/continuations.factor @@ -25,5 +25,10 @@ USE: test ] with-scope ] callcc0 "x" get 5 = ; -[ t ] [ 10 callcc1-test 10 count = ] unit-test +[ t ] [ 10 callcc1-test 10 >list = ] unit-test [ t ] [ callcc-namespace-test ] unit-test + +: multishot-test ( -- stack ) + [ dup "cc" set 5 swap call ] callcc1 "cc" get car interp-data ; + +[ 5 { } ] [ multishot-test ] unit-test diff --git a/library/test/crashes.factor b/library/test/crashes.factor deleted file mode 100644 index 7c015dc35b..0000000000 --- a/library/test/crashes.factor +++ /dev/null @@ -1,33 +0,0 @@ -IN: temporary - -! Various things that broke CFactor at various times. -USING: errors kernel lists math memory namespaces parser -prettyprint sequences strings test vectors words ; - -[ ] [ - "20 \"foo\" set" eval - "full-gc" eval -] unit-test - -[ ] [ - [ - [ drop ] [ drop ] catch - [ drop ] [ drop ] catch - ] keep-datastack -] unit-test - -[ ] [ 10 [ [ -1000000 ] [ drop ] catch ] times ] unit-test -[ ] [ 10 [ [ -1000000 ] [ drop ] catch ] times ] unit-test - -! See how well callstack overflow is handled -: callstack-overflow callstack-overflow f ; -[ callstack-overflow ] unit-test-fails - -! Weird PowerPC bug. -[ ] [ - [ "4" throw ] [ drop ] catch - full-gc - full-gc -] unit-test - -[ 0 ] [ f size ] unit-test diff --git a/library/test/errors.factor b/library/test/errors.factor index a1d224135b..4183ec5ffa 100644 --- a/library/test/errors.factor +++ b/library/test/errors.factor @@ -1,4 +1,5 @@ IN: temporary +USING: memory ; USE: errors USE: kernel USE: namespaces @@ -27,3 +28,14 @@ USE: io ! This should not raise an error [ 1 2 3 ] [ 1 2 3 f throw ] unit-test + +! See how well callstack overflow is handled +: callstack-overflow callstack-overflow f ; +[ callstack-overflow ] unit-test-fails + +! Weird PowerPC bug. +[ ] [ + [ "4" throw ] [ drop ] catch + full-gc + full-gc +] unit-test diff --git a/library/test/files.factor b/library/test/files.factor index 60ef9eddda..d147de9b70 100644 --- a/library/test/files.factor +++ b/library/test/files.factor @@ -9,10 +9,3 @@ USE: test [ "txt" ] [ "foo.bar.txt" file-extension ] unit-test [ "text/plain" ] [ "foo.bar.txt" mime-type ] unit-test [ "text/html" ] [ "index.html" mime-type ] unit-test - -! Some tests to ensure these words simply work, since we can't -! really test them - -[ t ] [ cwd directory list? ] unit-test - -cwd directory. diff --git a/library/test/gadgets/frames.factor b/library/test/gadgets/frames.factor new file mode 100644 index 0000000000..496acb09d5 --- /dev/null +++ b/library/test/gadgets/frames.factor @@ -0,0 +1,65 @@ +IN: temporary +USING: gadgets gadgets-labels gadgets-layouts kernel namespaces +test ; + +[ "Hello world" ] +[ + "frame" set + "Hello world"