\r
+ listener/plugin:\r
\r
+- stream server can hang because of exception handler limitations\r
- listener should be multithreaded\r
-- fully socket based communication\r
- compile all, infer all commands\r
- type something -- no completions -- hit another key -- not inserted\r
- faster completion\r
- cat, reverse-cat primitives\r
- first-class hashtables\r
- add a socket timeout\r
-- do transfer-word in fixup\r
\r
+ misc:\r
\r
-- stream server can hang because of exception handler limitations\r
- each-with map-with\r
- step: print NEXT word to execute, not word that JUST executed\r
- perhaps /i should work with all numbers\r
- unit test weirdness: 2 lines appears at end\r
- jedit ==> jedit-word, jedit takes a file name\r
- nicer way to combine two paths\r
-- ditch object paths\r
- browser responder for word links in HTTPd\r
- worddef props\r
- prettyprint: when unparse called due to recursion, write a link\r
dup init-methods
dup <vtable> define-generic ;
-PREDICATE: compound generic ( word -- ? )
- "combination" word-property ;
-
: single-combination ( obj vtable -- )
>r dup type r> dispatch ; inline
dup predicate-word
[ dupd unit "predicate" set-word-property ] keep
[ define-predicate ] [ ] ; parsing
+
+PREDICATE: compound generic ( word -- ? )
+ "combination" word-property ;
SYMBOL: cloned
-: assq* ( key alist -- [ key | value ] )
- #! Looks up the key in an alist. Push the key/value pair.
- #! Most of the time you want to use assq not assq*.
- dup [
- 2dup car car eq? [ nip car ] [ cdr assq* ] ifte
- ] [
- 2drop f
- ] ifte ;
-
-: assq ( key alist -- value )
- #! Looks up the key in an alist.
- assq* dup [ cdr ] when ;
-
: deep-clone ( vector -- vector )
#! Clone a vector if it hasn't already been cloned in this
#! with-deep-clone scope.
- dup cloned get assq dup [
+ dup cloned get assoc dup [
nip
] [
drop vector-clone [ dup cloned [ acons ] change ] keep
d-in [ deep-clone-vector ] change
dataflow-graph off ;
+: terminator? ( obj -- ? )
+ dup word? [ "terminator" word-property ] [ drop f ] ifte ;
+
+: handle-terminator ( quot -- )
+ [ terminator? ] some? [
+ meta-d off meta-r off d-in off
+ ] when ;
+
: infer-branch ( value -- namespace )
<namespace> [
uncons [ unswons set-value-class ] when*
dup value-recursion recursive-state set
copy-inference
- literal-value infer-quot
+ literal-value dup infer-quot
#values values-node
+ handle-terminator
] extend ;
-: terminator? ( obj -- ? )
- dup word? [ "terminator" word-property ] [ drop f ] ifte ;
-
-: terminator-quot? ( [ quot | type-prop ] -- ? )
- car literal-value [ terminator? ] some? ;
-
-: dual-branch ( branch branchlist -- rstate )
- #! Return a recursive state for a branch other than the
- #! given one in the list.
- [ over eq? not ] subset nip car car value-recursion ;
-
-! FIXME this is really bad
-: old-effect ( [ in-types out-types ] -- [ in | out ] )
- uncons car length >r length r> cons ;
-
-: foo>effect ( [ in-types out-types ] -- [ in | out ] )
- [ effect old-effect ] bind ;
-
-: raise ( [ in | out ] -- [ in | out ] )
- uncons 2dup min tuck - >r - r> cons ;
-
-: effect>foo ( [ in | out ] -- [ intypes outtypes ] )
- <namespace> [
- uncons
- [ drop object <computed> ] vector-project meta-d set
- [ drop object <computed> ] vector-project d-in set
- { } meta-r set
- ] extend ;
-
-: decompose ( first second -- solution )
- #! Return a stack effect such that first*solution = second.
- 2dup 2car
- 2dup > [ "No solution to decomposition" throw ] when
- swap - -rot 2cdr >r + r> cons raise effect>foo ;
-
-: set-base ( effect rstate -- )
- #! Set the base case of the current word.
- dup [
- car cdr [
- entry-effect get old-effect dup [ 0 | 0 ] = [
- drop
- ] [
- swap foo>effect decompose
- ] ifte
- base-case cons@
- ] bind
- ] [
- 2drop
- ] ifte ;
-
-: recursive-branch ( branch branchlist -- )
- [
- dupd dual-branch >r infer-branch r> set-base
- ] [
- [ 2drop ] when
- ] catch ;
-
-: no-base-case ( word -- )
- word-name " does not have a base case." cat2 throw ;
-
-: get-base ( word rstate -- effect )
- [ base-case get ] bind dup [
- nip [ unify-effects effect ] with-scope
- ] [
- drop no-base-case
- ] ifte ;
-
-: infer-base-case ( branchlist -- )
- [
- inferring-base-case on
-
- dup [
- 2dup terminator-quot? [
- 2drop
- ] [
- recursive-branch
- ] ifte
- ] each drop
- ] with-scope ;
-
: (infer-branches) ( branchlist -- list )
#! The branchlist is a list of pairs:
#! [ value | typeprop ]
#! value is either a literal or computed instance; typeprop
#! is a pair [ value | class ] indicating a type propagation
#! for the given branch.
- dup infer-base-case [
- dup infer-branch swap terminator-quot? [
- [ meta-d off meta-r off d-in off ] extend
- ] when
- ] map ;
+ [
+ [
+ inferring-base-case get [
+ [
+ infer-branch ,
+ ] [
+ [ drop ] when
+ ] catch
+ ] [
+ infer-branch ,
+ ] ifte
+ ] each
+ ] make-list ;
: unify-dataflow ( inputs instruction effectlist -- )
[ [ get-dataflow ] bind ] map
! inputs.
SYMBOL: d-in
-! Recursive state. Alist maps words to hashmaps...
+! Recursive state. An alist, mapping words to labels.
SYMBOL: recursive-state
-! ... with keys:
-SYMBOL: base-case
-SYMBOL: entry-effect
-! When a call to a combinator is compiled, recursion cannot
-! simply jump to the definition of the combinator. Instead, it
-! makes a local jump to this label.
-SYMBOL: recursive-label
! A value has the following slots:
GENERIC: literal-value ( value -- obj )
d-in get [ value-class ] vector-map vector>list
meta-d get [ value-class ] vector-map vector>list 2list ;
-: <recursive-state> ( -- state )
- <namespace> [
- base-case off effect entry-effect set
- ] extend ;
-
: init-inference ( recursive-state -- )
init-interpreter
0 <vector> d-in set
recursive-state set
- dataflow-graph off ;
+ dataflow-graph off
+ inferring-base-case off ;
DEFER: apply-word
: produce-d ( typelist -- )
[ <computed> push-d ] each ;
-: (consume/produce) ( param op effect -- )
+: (consume/produce) ( param op effect )
[ unswons consume-d car produce-d ] with-dataflow ;
: consume/produce ( word [ in-types out-types ] -- )
#! its dataflow contribution to a new block node in the IR.
over [
>r
- <recursive-state> [ recursive-label set ] extend
dupd cons
recursive-state cons@
r> call
#! Push word we're currently inferring effect of.
recursive-state get car car ;
-: check-recursion ( -- )
+: check-recursion ( word -- )
#! If at the location of the recursive call, we're taking
#! more items from the stack than producing, we have a
- #! diverging recursion.
- d-in get vector-length
- meta-d get vector-length > [
- current-word word-name " diverges." cat2 throw
+ #! diverging recursion. Note that this check is not done for
+ #! mutually-recursive words. Generally they should be
+ #! avoided.
+ recursive-state get car = [
+ d-in get vector-length
+ meta-d get vector-length > [
+ current-word word-name " diverges." cat2 throw
+ ] when
] when ;
-: recursive-word ( word state -- )
+: base-case ( word -- effect )
+ [
+ inferring-base-case on
+ copy-inference
+ inline-compound
+ inferring-base-case off
+ ] with-scope ;
+
+: decompose ( x y -- effect )
+ #! Return a stack effect such that x*effect = y.
+ 2unlist >r swap 2unlist swap length tail append
+ ! workaround
+ [ drop object ] map
+ r> 2list ;
+
+: recursive-word ( word label -- )
#! Handle a recursive call, by either applying a previously
#! inferred base case, or raising an error. If the recursive
#! call is to a local block, emit a label call node.
- [ get-base ] 2keep [ recursive-label get ] bind
- dup [
- ( word effect label )
- nip #call-label
+ inferring-base-case get [
+ drop word-name " does not have a base case." cat2 throw
] [
- drop #call
- ] ifte rot (consume/produce) ;
+ 2dup [ drop #call-label ] [ nip #call ] ifte
+ rot base-case effect swap decompose (consume/produce)
+ ] ifte ;
: apply-word ( word -- )
#! Apply the word's stack effect to the inferencer state.
dup recursive-state get assoc [
- check-recursion recursive-word
+ dup check-recursion recursive-word
] [
dup "infer-effect" word-property [
apply-effect
\ call [ infer-call ] "infer" set-word-property
! These are due to bugs and will be removed
-\ - [ [ number number ] [ number ] ] "infer-effect" set-word-property
\ * [ [ number number ] [ number ] ] "infer-effect" set-word-property
-\ / [ [ number number ] [ number ] ] "infer-effect" set-word-property
\ gcd [ [ number number ] [ number ] ] "infer-effect" set-word-property
-\ hashcode [ [ object ] [ integer ] ] "infer-effect" set-word-property
\ undefined-method t "terminator" set-word-property
\ not-a-number t "terminator" set-word-property
: 2list ( a b -- [ a b ] )
unit cons ;
+: 2unlist ( [ a b ] -- a b )
+ uncons car ;
+
: 3list ( a b c -- [ a b c ] )
2list cons ;
] ifte ;
: cons-hashcode ( cons count -- hash )
- dup 0 = [
+ dup 0 number= [
2drop 0
] [
over cons? [
: rect> ( xr xi -- x )
over real? over real? and [
- dup 0 = [ drop ] [ (rect>) ] ifte
+ dup 0 number= [ drop ] [ (rect>) ] ifte
] [
"Complex number must have real components" throw drop
] ifte ; inline
USE: kernel
USE: math
-: reduce ( x y -- x' y' )
- dup 0 < [ swap neg swap neg ] when
- 2dup gcd tuck /i >r /i r> ; inline
-
: fraction> ( a b -- a/b )
- dup 0 = [
- "Division by zero" throw drop
+ dup 1 number= [
+ drop
] [
- dup 1 = [
- drop
- ] [
- (fraction>)
- ] ifte
+ (fraction>)
] ifte ; inline
: integer/ ( x y -- x/y )
- reduce fraction> ; inline
+ dup 0 number= [
+ "Division by zero" throw drop
+ ] [
+ dup 0 < [
+ swap neg swap neg
+ ] when
+ 2dup gcd tuck /i >r /i r> fraction>
+ ] ifte ;
M: fixnum number= fixnum= ;
M: fixnum < fixnum< ;
M: real abs dup 0 < [ neg ] when ;
: (gcd) ( x y -- z )
- dup 0 = [ drop ] [ tuck mod (gcd) ] ifte ;
+ dup 0 number= [ drop ] [ tuck mod (gcd) ] ifte ;
: gcd ( x y -- z )
#! Greatest common divisor.
abs swap abs 2dup < [ swap ] when (gcd) ;
: align ( offset width -- offset )
- 2dup mod dup 0 = [ 2drop ] [ - + ] ifte ;
+ 2dup mod dup 0 number= [ 2drop ] [ - + ] ifte ;
: see-method ( indent word class method -- indent )
>r >r >r prettyprint-M:
- r> prettyprint-1 " " write
- r> prettyprint-1 " " write
+ r> r> prettyprint-1 " " write
+ prettyprint-1 " " write
dup prettyprint-newline
r> prettyprint-list
prettyprint-;
USE: math-internals
USE: generic
+[ [ [ object object ] f ] ]
+[ [ [ object ] [ object object ] ] [ [ object ] f ] decompose ]
+unit-test
+
+[ [ [ fixnum fixnum ] f ] ]
+[
+ [ [ rational rational ] [ rational fixnum ] ]
+ [ [ object ] f ] decompose
+]
+unit-test
+
+: old-effect ( [ in-types out-types ] -- [ in | out ] )
+ uncons car length >r length r> cons ;
+
[
[ 1 | 2 ]
[ 2 | 1 ]
! Not sure how to fix this one
-! : funny-recursion
-! dup [ funny-recursion 1 ] [ 2 ] ifte drop ;
-!
-! [ [ 1 | 1 ] ] [ [ funny-recursion ] infer old-effect ] unit-test
+: funny-recursion
+ dup [ funny-recursion 1 ] [ 2 ] ifte drop ;
+
+[ [ 1 | 1 ] ] [ [ funny-recursion ] infer old-effect ] unit-test
! Simple combinators
[ [ 1 | 2 ] ] [ [ [ car ] keep cdr ] infer old-effect ] unit-test
] [
over vector? [
2dup vector-length= [
- swap vector>list swap vector>list =
+ swap stack>list swap stack>list =
] [
2drop f
] ifte