Fix locals with smart combinator macros, document that locals work with macros now

db4
Slava Pestov 2008-08-26 20:40:34 -05:00
parent 47cb866891
commit 19c5317d97
3 changed files with 71 additions and 11 deletions

View File

@ -101,15 +101,27 @@ $nl
ARTICLE: "locals-limitations" "Limitations of locals"
"The first limitation is that the " { $link >r } " and " { $link r> } " words may not be used together with locals. Instead, use the " { $link dip } " combinator."
$nl
"Another limitation is that closure conversion does not descend into arrays, hashtables or other types of literals. For example, the following does not work:"
"Another limitation concerns combinators implemented as macros. Locals can only be used with such combinators if the input array immediately precedes the combinator call. For example, the following will work:"
{ $code
":: bad-cond-usage ( a -- ... )"
":: good-cond-usage ( a -- ... )"
" {"
" { [ a 0 < ] [ ... ] }"
" { [ a 0 > ] [ ... ] }"
" { [ a 0 = ] [ ... ] }"
" } cond ;"
} ;
}
"But not the following:"
{ $code
": my-cond ( alist -- ) cond ; inline"
""
":: bad-cond-usage ( a -- ... )"
" {"
" { [ a 0 < ] [ ... ] }"
" { [ a 0 > ] [ ... ] }"
" { [ a 0 = ] [ ... ] }"
" } my-cond ;"
}
"The reason is that locals are rewritten into stack code at parse time, whereas macro expansion is performed later during compile time. To circumvent this problem, the " { $vocab-link "macros.expander" } " vocabulary is used to rewrite simple macro usages prior to local transformation, however "{ $vocab-link "macros.expander" } " does not deal with more complicated cases where the literal inputs to the macro do not immediately precede the macro call in the source." ;
ARTICLE: "locals" "Local variables and lexical closures"
"The " { $vocab-link "locals" } " vocabulary implements lexical scope with full closures, both downward and upward. Mutable bindings are supported, including assignment to bindings in outer scope."

View File

@ -1,6 +1,7 @@
USING: locals math sequences tools.test hashtables words kernel
namespaces arrays strings prettyprint io.streams.string parser
accessors generic eval ;
accessors generic eval combinators combinators.short-circuit
combinators.short-circuit.smart ;
IN: locals.tests
:: foo ( a b -- a a ) a a ;
@ -276,3 +277,42 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
[ \ sequence \ method-with-locals method see ] with-string-writer
method-definition =
] unit-test
:: cond-test ( a b -- c )
{
{ [ a b < ] [ 3 ] }
{ [ a b = ] [ 4 ] }
{ [ a b > ] [ 5 ] }
} cond ;
[ 3 ] [ 1 2 cond-test ] unit-test
[ 4 ] [ 2 2 cond-test ] unit-test
[ 5 ] [ 3 2 cond-test ] unit-test
:: 0&&-test ( a -- ? )
{ [ a integer? ] [ a even? ] [ a 10 > ] } 0&& ;
[ f ] [ 1.5 0&&-test ] unit-test
[ f ] [ 3 0&&-test ] unit-test
[ f ] [ 8 0&&-test ] unit-test
[ t ] [ 12 0&&-test ] unit-test
:: &&-test ( a -- ? )
{ [ a integer? ] [ a even? ] [ a 10 > ] } && ;
[ f ] [ 1.5 &&-test ] unit-test
[ f ] [ 3 &&-test ] unit-test
[ f ] [ 8 &&-test ] unit-test
[ t ] [ 12 &&-test ] unit-test
:: wlet-&&-test ( a -- ? )
[wlet | is-integer? [ a integer? ]
is-even? [ a even? ]
>10? [ a 10 > ] |
{ [ is-integer? ] [ is-even? ] [ >10? ] } &&
] ;
! [ f ] [ 1.5 wlet-&&-test ] unit-test
! [ f ] [ 3 wlet-&&-test ] unit-test
! [ f ] [ 8 wlet-&&-test ] unit-test
! [ t ] [ 12 wlet-&&-test ] unit-test

View File

@ -5,7 +5,8 @@ parser words quotations debugger macros arrays macros splitting
combinators prettyprint.backend definitions prettyprint
hashtables prettyprint.sections sets sequences.private effects
effects.parser generic generic.parser compiler.units accessors
locals.backend memoize macros.expander lexer ;
locals.backend memoize macros.expander lexer
stack-checker.known-words ;
IN: locals
! Inspired by
@ -42,7 +43,9 @@ PREDICATE: local < word "local?" word-prop ;
: <local> ( name -- word )
#! Create a local variable identifier
f <word> dup t "local?" set-word-prop ;
f <word>
dup t "local?" set-word-prop
dup { } { object } define-primitive ;
PREDICATE: local-word < word "local-word?" word-prop ;
@ -52,15 +55,20 @@ PREDICATE: local-word < word "local-word?" word-prop ;
PREDICATE: local-reader < word "local-reader?" word-prop ;
: <local-reader> ( name -- word )
f <word> dup t "local-reader?" set-word-prop ;
f <word>
dup t "local-reader?" set-word-prop
dup { } { object } define-primitive ;
PREDICATE: local-writer < word "local-writer?" word-prop ;
: <local-writer> ( reader -- word )
dup name>> "!" append f <word>
[ t "local-writer?" set-word-prop ] keep
[ "local-writer" set-word-prop ] 2keep
[ swap "local-reader" set-word-prop ] keep ;
dup name>> "!" append f <word> {
[ nip { object } { } define-primitive ]
[ nip t "local-writer?" set-word-prop ]
[ swap "local-reader" set-word-prop ]
[ "local-writer" set-word-prop ]
[ nip ]
} 2cleave ;
TUPLE: quote local ;