Fix some bugs in locals, throw a parse time error if usage of >r r> is detected

db4
Slava Pestov 2008-11-21 05:18:41 -06:00
parent 420ff0a447
commit 6324b4dd65
3 changed files with 50 additions and 16 deletions

View File

@ -132,8 +132,8 @@ $nl
"Unlike some languages such as Python and Java, writing to mutable locals in outer scopes is fully supported and has the expected semantics." ; "Unlike some languages such as Python and Java, writing to mutable locals in outer scopes is fully supported and has the expected semantics." ;
ARTICLE: "locals-limitations" "Limitations of locals" 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." "The first limitation is also shared by " { $vocab-link "fry" } ": the " { $link >r } " and " { $link r> } " words may not be used together with locals. Instead, use the " { $link dip } " combinator. An error is thrown at parse time if an attempt is made to use " { $link >r } " and " { $link r> } " inside a lambda body:"
$nl { $subsection >r/r>-in-lambda-error }
"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:" "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 { $code
":: good-cond-usage ( a -- ... )" ":: good-cond-usage ( a -- ... )"

View File

@ -2,7 +2,7 @@ USING: locals math sequences tools.test hashtables words kernel
namespaces arrays strings prettyprint io.streams.string parser namespaces arrays strings prettyprint io.streams.string parser
accessors generic eval combinators combinators.short-circuit accessors generic eval combinators combinators.short-circuit
combinators.short-circuit.smart math.order math.functions combinators.short-circuit.smart math.order math.functions
definitions compiler.units ; definitions compiler.units fry ;
IN: locals.tests IN: locals.tests
:: foo ( a b -- a a ) a a ; :: foo ( a b -- a a ) a a ;
@ -286,6 +286,8 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
{ [ a b > ] [ 5 ] } { [ a b > ] [ 5 ] }
} cond ; } cond ;
\ cond-test must-infer
[ 3 ] [ 1 2 cond-test ] unit-test [ 3 ] [ 1 2 cond-test ] unit-test
[ 4 ] [ 2 2 cond-test ] unit-test [ 4 ] [ 2 2 cond-test ] unit-test
[ 5 ] [ 3 2 cond-test ] unit-test [ 5 ] [ 3 2 cond-test ] unit-test
@ -293,6 +295,8 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
:: 0&&-test ( a -- ? ) :: 0&&-test ( a -- ? )
{ [ a integer? ] [ a even? ] [ a 10 > ] } 0&& ; { [ a integer? ] [ a even? ] [ a 10 > ] } 0&& ;
\ 0&&-test must-infer
[ f ] [ 1.5 0&&-test ] unit-test [ f ] [ 1.5 0&&-test ] unit-test
[ f ] [ 3 0&&-test ] unit-test [ f ] [ 3 0&&-test ] unit-test
[ f ] [ 8 0&&-test ] unit-test [ f ] [ 8 0&&-test ] unit-test
@ -301,6 +305,8 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
:: &&-test ( a -- ? ) :: &&-test ( a -- ? )
{ [ a integer? ] [ a even? ] [ a 10 > ] } && ; { [ a integer? ] [ a even? ] [ a 10 > ] } && ;
\ &&-test must-infer
[ f ] [ 1.5 &&-test ] unit-test [ f ] [ 1.5 &&-test ] unit-test
[ f ] [ 3 &&-test ] unit-test [ f ] [ 3 &&-test ] unit-test
[ f ] [ 8 &&-test ] unit-test [ f ] [ 8 &&-test ] unit-test
@ -346,6 +352,10 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
{ 3 1 } [| from to seq | T{ slice f from to seq } ] must-infer-as { 3 1 } [| from to seq | T{ slice f from to seq } ] must-infer-as
ERROR: punned-class x ;
[ T{ punned-class f 3 } ] [ 3 [| a | T{ punned-class f a } ] call ] unit-test
:: literal-identity-test ( -- a b ) :: literal-identity-test ( -- a b )
{ } V{ } ; { } V{ } ;
@ -390,6 +400,18 @@ M:: integer lambda-method-forget-test ( a -- b ) ;
[ { [ 10 ] } ] [ 10 [| A | { [ A ] } ] call ] unit-test [ { [ 10 ] } ] [ 10 [| A | { [ A ] } ] call ] unit-test
[
"USING: locals fry math ; [ 0 '[ [let | A [ 10 ] | A _ + ] ] ]" eval
] [ error>> >r/r>-in-fry-error? ] must-fail-with
:: (funny-macro-test) ( obj quot -- ? ) obj { quot } 1&& ; inline
: funny-macro-test ( n -- ? ) [ odd? ] (funny-macro-test) ;
\ funny-macro-test must-infer
[ t ] [ 3 funny-macro-test ] unit-test
[ f ] [ 2 funny-macro-test ] unit-test
! :: wlet-&&-test ( a -- ? ) ! :: wlet-&&-test ( a -- ? )
! [wlet | is-integer? [ a integer? ] ! [wlet | is-integer? [ a integer? ]
! is-even? [ a even? ] ! is-even? [ a even? ]

View File

@ -6,12 +6,18 @@ quotations debugger macros arrays macros splitting combinators
prettyprint.backend definitions prettyprint hashtables prettyprint.backend definitions prettyprint hashtables
prettyprint.sections sets sequences.private effects prettyprint.sections sets sequences.private effects
effects.parser generic generic.parser compiler.units accessors effects.parser generic generic.parser compiler.units accessors
locals.backend memoize macros.expander lexer classes ; locals.backend memoize macros.expander lexer classes summary ;
IN: locals IN: locals
! Inspired by ! Inspired by
! http://cat-language.googlecode.com/svn/trunk/CatPointFreeForm.cs ! http://cat-language.googlecode.com/svn/trunk/CatPointFreeForm.cs
ERROR: >r/r>-in-lambda-error ;
M: >r/r>-in-lambda-error summary
drop
"Explicit retain stack manipulation is not permitted in lambda bodies" ;
<PRIVATE <PRIVATE
TUPLE: lambda vars body ; TUPLE: lambda vars body ;
@ -141,20 +147,17 @@ GENERIC: free-vars* ( form -- )
: free-vars ( form -- vars ) : free-vars ( form -- vars )
[ free-vars* ] { } make prune ; [ free-vars* ] { } make prune ;
: add-if-free ( object -- ) M: local-writer free-vars* "local-reader" word-prop , ;
{
{ [ dup local-writer? ] [ "local-reader" word-prop , ] } M: lexical free-vars* , ;
{ [ dup lexical? ] [ , ] }
{ [ dup quote? ] [ local>> , ] } M: quote free-vars* , ;
{ [ t ] [ free-vars* ] }
} cond ;
M: object free-vars* drop ; M: object free-vars* drop ;
M: quotation free-vars* [ add-if-free ] each ; M: quotation free-vars* [ free-vars* ] each ;
M: lambda free-vars* M: lambda free-vars* [ vars>> ] [ body>> ] bi free-vars swap diff % ;
[ vars>> ] [ body>> ] bi free-vars swap diff % ;
GENERIC: lambda-rewrite* ( obj -- ) GENERIC: lambda-rewrite* ( obj -- )
@ -201,6 +204,8 @@ M: special rewrite-literal? drop t ;
M: array rewrite-literal? [ rewrite-literal? ] contains? ; M: array rewrite-literal? [ rewrite-literal? ] contains? ;
M: quotation rewrite-literal? [ rewrite-literal? ] contains? ;
M: hashtable rewrite-literal? drop t ; M: hashtable rewrite-literal? drop t ;
M: vector rewrite-literal? drop t ; M: vector rewrite-literal? drop t ;
@ -215,17 +220,20 @@ GENERIC: rewrite-element ( obj -- )
[ rewrite-element ] each ; [ rewrite-element ] each ;
: rewrite-sequence ( seq -- ) : rewrite-sequence ( seq -- )
[ rewrite-elements ] [ length , ] [ , ] tri \ nsequence , ; [ rewrite-elements ] [ length , ] [ 0 head , ] tri \ nsequence , ;
M: array rewrite-element M: array rewrite-element
dup rewrite-literal? [ rewrite-sequence ] [ , ] if ; dup rewrite-literal? [ rewrite-sequence ] [ , ] if ;
M: quotation rewrite-element
dup rewrite-literal? [ rewrite-sequence ] [ , ] if ;
M: vector rewrite-element rewrite-sequence ; M: vector rewrite-element rewrite-sequence ;
M: hashtable rewrite-element >alist rewrite-sequence \ >hashtable , ; M: hashtable rewrite-element >alist rewrite-sequence \ >hashtable , ;
M: tuple rewrite-element M: tuple rewrite-element
[ tuple-slots rewrite-elements ] [ class , ] bi \ boa , ; [ tuple-slots rewrite-elements ] [ class literalize , ] bi \ boa , ;
M: local rewrite-element , ; M: local rewrite-element , ;
@ -243,6 +251,10 @@ M: tuple local-rewrite* rewrite-element ;
M: hashtable local-rewrite* rewrite-element ; M: hashtable local-rewrite* rewrite-element ;
M: word local-rewrite*
dup { >r r> } memq?
[ >r/r>-in-lambda-error ] [ call-next-method ] if ;
M: object lambda-rewrite* , ; M: object lambda-rewrite* , ;
M: object local-rewrite* , ; M: object local-rewrite* , ;