remove [let* ] and change [let ] to only establish a scope, leaving :> as the one true way of binding locals

db4
Joe Groff 2009-10-27 14:19:05 -05:00
parent 8f0321a0b1
commit c4e3c15c28
10 changed files with 77 additions and 166 deletions

View File

@ -9,10 +9,10 @@ M: >r/r>-in-lambda-error summary
drop
"Explicit retain stack manipulation is not permitted in lambda bodies" ;
ERROR: binding-form-in-literal-error ;
ERROR: let-form-in-literal-error ;
M: binding-form-in-literal-error summary
drop "[let and [let* not permitted inside literals" ;
M: let-form-in-literal-error summary
drop "[let not permitted inside literals" ;
ERROR: local-writer-in-literal-error ;
@ -27,7 +27,7 @@ M: local-word-in-literal-error summary
ERROR: :>-outside-lambda-error ;
M: :>-outside-lambda-error summary
drop ":> cannot be used outside of lambda expressions" ;
drop ":> cannot be used outside of [let, [|, or :: forms" ;
ERROR: bad-local args obj ;

View File

@ -6,7 +6,7 @@ IN: locals.fry
! Support for mixing locals with fry
M: binding-form count-inputs body>> count-inputs ;
M: let count-inputs body>> count-inputs ;
M: lambda count-inputs body>> count-inputs ;
@ -14,5 +14,5 @@ M: lambda deep-fry
clone [ shallow-fry swap ] change-body
[ [ vars>> length ] keep '[ _ _ mnswap @ ] , ] [ drop [ncurry] % ] 2bi ;
M: binding-form deep-fry
M: let deep-fry
clone [ fry '[ @ call ] ] change-body , ;

View File

@ -8,29 +8,26 @@ HELP: [|
{ $examples "See " { $link "locals-examples" } "." } ;
HELP: [let
{ $syntax "[let | var-1 [ value-1... ]\n var-2 [ value-2... ]\n ... |\n body... ]" }
{ $description "Evaluates each " { $snippet "value-n" } " form and binds its result to a new local variable named " { $snippet "var-n" } " lexically scoped to the " { $snippet "body" } ", then evaluates " { $snippet "body" } ". The " { $snippet "value-n" } " forms are evaluated in parallel, so a " { $snippet "value-n" } " form may not refer to previous " { $snippet "var-n" } " definitions inside the same " { $link POSTPONE: [let } " form, unlike " { $link POSTPONE: [let* } "." }
{ $syntax "[let code :> var code :> var code... ]" }
{ $description "Establishes a new lexical scope for local variable bindings. Variables bound with " { $link POSTPONE: :> } " within the body of the " { $snippet "[let" } " will be lexically scoped to the body of the " { $snippet "[let" } " form." }
{ $examples "See " { $link "locals-examples" } "." } ;
HELP: [let*
{ $syntax "[let* | var-1 [ value-1... ]\n var-2 [ value-2... ]\n ... |\n body... ]" }
{ $description "Evaluates each " { $snippet "value-n" } " form and binds its result to a new local variable named " { $snippet "var-n" } " lexically scoped to the " { $snippet "body" } ", then evaluates " { $snippet "body" } ". The " { $snippet "value-n" } " forms are evaluated sequentially, so a " { $snippet "value-n" } " form may refer to previous " { $snippet "var-n" } " definitions inside the same " { $link POSTPONE: [let* } " form." }
{ $examples "See " { $link "locals-examples" } "." } ;
{ POSTPONE: [let POSTPONE: [let* } related-words
HELP: :>
{ $syntax ":> var" ":> var!" }
{ $description "Binds the value on the top of the datastack to a new local variable named " { $snippet "var" } ", lexically scoped to the enclosing quotation or definition."
$nl
"If the " { $snippet "var" } " name is followed by an exclamation point (" { $snippet "!" } "), the new variable will be mutable. See " { $link "locals-mutable" } " for more information on mutable local bindings." }
{ $notes
"This syntax can only be used inside a " { $link POSTPONE: :: } " word, " { $link POSTPONE: [let } " or " { $link POSTPONE: [let* } " form, or inside a quotation literal inside one of those forms." }
"This syntax can only be used inside a lexical scope established by a " { $link POSTPONE: :: } " definition, " { $link POSTPONE: [let } " form, or " { $link POSTPONE: [| } " quotation. Definition forms such as " { $link POSTPONE: : } " do not establish a lexical scope by themselves, nor is there a lexical scope available at the top level of source files or in the listener. To use local variable bindings in these situations, use " { $link POSTPONE: [let } " to provide a scope for them." }
{ $examples "See " { $link "locals-examples" } "." } ;
{ POSTPONE: [let POSTPONE: :> } related-words
HELP: ::
{ $syntax ":: word ( bindings... -- outputs... ) body... ;" }
{ $description "Defines a word with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope." }
{ $syntax ":: word ( vars... -- outputs... ) body... ;" }
{ $description "Defines a word with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope."
$nl
"If any of the " { $snippet "vars" } "' names is followed by an exclamation point (" { $snippet "!" } "), that variable will be mutable. See " { $link "locals-mutable" } " for more information on mutable local bindings." }
{ $notes "The names of the " { $snippet "outputs" } " do not affect the word's behavior. However, the compiler verifies that the stack effect accurately represents the number of outputs as with " { $link POSTPONE: : } " definitions." }
{ $examples "See " { $link "locals-examples" } "." } ;
@ -38,21 +35,27 @@ HELP: ::
HELP: MACRO::
{ $syntax "MACRO:: word ( bindings... -- outputs... ) body... ;" }
{ $description "Defines a macro with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope." }
{ $description "Defines a macro with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope."
$nl
"If any of the " { $snippet "vars" } "' names is followed by an exclamation point (" { $snippet "!" } "), that variable will be mutable. See " { $link "locals-mutable" } " for more information on mutable local bindings." }
{ $examples "See " { $link "locals-examples" } "." } ;
{ POSTPONE: MACRO: POSTPONE: MACRO:: } related-words
HELP: MEMO::
{ $syntax "MEMO:: word ( bindings... -- outputs... ) body... ;" }
{ $description "Defines a macro with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope." }
{ $description "Defines a memoized word with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope."
$nl
"If any of the " { $snippet "vars" } "' names is followed by an exclamation point (" { $snippet "!" } "), that variable will be mutable. See " { $link "locals-mutable" } " for more information on mutable local bindings." }
{ $examples "See " { $link "locals-examples" } "." } ;
{ POSTPONE: MEMO: POSTPONE: MEMO:: } related-words
HELP: M::
{ $syntax "M:: class generic ( bindings... -- outputs... ) body... ;" }
{ $description "Defines a macro with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope." }
{ $description "Defines a new method on " { $snippet "generic" } " for " { $snippet "class" } " with named inputs; it reads datastack values into local variable bindings from left to right, then executes the body with those bindings in lexical scope."
$nl
"If any of the " { $snippet "vars" } "' names is followed by an exclamation point (" { $snippet "!" } "), that variable will be mutable. See " { $link "locals-mutable" } " for more information on mutable local bindings." }
{ $notes "The names of the " { $snippet "outputs" } " do not affect the word's behavior. However, the compiler verifies that the stack effect accurately represents the number of outputs as with " { $link POSTPONE: M: } " definitions." }
{ $examples "See " { $link "locals-examples" } "." } ;
@ -70,14 +73,13 @@ IN: scratchpad
"""2.0
-3.0"""
}
{ $snippet "quadratic-roots" } " can also be expressed with " { $link POSTPONE: [let } ":"
"If you wanted to perform the quadratic formula interactively from the listener, you could use " { $link POSTPONE: [let } " to provide a scope for the local variables:"
{ $example """USING: locals math math.functions kernel ;
IN: scratchpad
:: quadratic-roots ( a b c -- x y )
[let | disc [ b sq 4 a c * * - sqrt ] |
b neg disc [ + ] [ - ] 2bi [ 2 a * / ] bi@
] ;
1.0 1.0 -6.0 quadratic-roots [ . ] bi@"""
[let 1.0 :> a 1.0 :> b -6.0 :> c
b sq 4 a c * * - sqrt :> disc
b neg disc [ + ] [ - ] 2bi [ 2 a * / ] bi@
] [ . ] bi@"""
"""2.0
-3.0"""
}
@ -200,11 +202,11 @@ $nl
"One exception to the above rule is that array instances containing free local variables (that is, immutable local variables not referenced in a closure) do retain identity. This allows macros such as " { $link cond } " to recognize that the array is constant and expand at compile time." ;
ARTICLE: "locals-mutable" "Mutable locals"
"In the list of bindings supplied to " { $link POSTPONE: :: } ", " { $link POSTPONE: [let } ", " { $link POSTPONE: [let* } " or " { $link POSTPONE: [| } ", a mutable binding may be introduced by suffixing its named with " { $snippet "!" } ". Mutable bindings are read by giving their name as usual; the suffix is not part of the binding's name. To write to a mutable binding, use the binding's name with the " { $snippet "!" } " suffix."
"Whenever a local variable is bound using " { $link POSTPONE: :> } ", " { $link POSTPONE: :: } ", or " { $link POSTPONE: [| } ", the variable may be made mutable by suffixing its name with an exclamation point (" { $snippet "!" } ") when it is bound. The variable's value can be read by giving its name without the exclamation point as usual. To write to the variable, use its name with the " { $snippet "!" } " suffix."
$nl
"Mutable bindings are implemented in a manner similar to the ML language; each mutable binding is actually an immutable binding of a mutable cell (in Factor's case, a 1-element array); reading the binding automatically dereferences the array, and writing to the binding stores into the array."
$nl
"Writing to mutable locals in outer scopes is fully supported and has the expected semantics. See " { $link "locals-examples" } " for examples of mutable local variables in action." ;
"Writing to mutable locals in outer scopes is fully supported and has full closure semantics. See " { $link "locals-examples" } " for examples of mutable local variables in action." ;
ARTICLE: "locals-fry" "Locals and fry"
"Locals integrate with " { $link "fry" } " so that mixing locals with fried quotations gives intuitive results."
@ -280,11 +282,10 @@ ARTICLE: "locals" "Lexical variables and closures"
POSTPONE: MEMO::
POSTPONE: MACRO::
}
"Lexical binding forms:"
"Lexical scoping and binding forms:"
{ $subsections
POSTPONE: :>
POSTPONE: [let
POSTPONE: [let*
POSTPONE: :>
}
"Quotation literals where the inputs are named local variables:"
{ $subsections POSTPONE: [| }

View File

@ -26,30 +26,30 @@ IN: locals.tests
[ { 5 6 7 } ] [ { 1 2 3 } 4 map-test-2 ] unit-test
:: let-test ( c -- d )
[let | a [ 1 ] b [ 2 ] | a b + c + ] ;
[let 1 :> a 2 :> b a b + c + ] ;
[ 7 ] [ 4 let-test ] unit-test
:: let-test-2 ( a -- a )
a [let | a [ ] | [let | b [ a ] | a ] ] ;
a [let :> a [let a :> b a ] ] ;
[ 3 ] [ 3 let-test-2 ] unit-test
:: let-test-3 ( a -- a )
a [let | a [ ] | [let | b [ [ a ] ] | [let | a [ 3 ] | b ] ] ] ;
a [let :> a [let [ a ] :> b [let 3 :> a b ] ] ] ;
:: let-test-4 ( a -- b )
a [let | a [ 1 ] b [ ] | a b 2array ] ;
a [let 1 :> a :> b a b 2array ] ;
[ { 1 2 } ] [ 2 let-test-4 ] unit-test
:: let-test-5 ( a b -- b )
a b [let | a [ ] b [ ] | a b 2array ] ;
a b [let :> a :> b a b 2array ] ;
[ { 2 1 } ] [ 1 2 let-test-5 ] unit-test
:: let-test-6 ( a -- b )
a [let | a [ ] b [ 1 ] | a b 2array ] ;
a [let :> a 1 :> b a b 2array ] ;
[ { 2 1 } ] [ 2 let-test-6 ] unit-test
@ -71,8 +71,7 @@ IN: locals.tests
[ 5 ] [ 2 "q" get call ] unit-test
:: write-test-2 ( -- q )
[let | n! [ 0 ] |
[| i | n i + dup n! ] ] ;
[let 0 :> n! [| i | n i + dup n! ] ] ;
write-test-2 "q" set
@ -93,11 +92,11 @@ write-test-2 "q" set
[ ] [ 1 2 write-test-3 call ] unit-test
:: write-test-4 ( x! -- q ) [ [let | y! [ 0 ] | f x! ] ] ;
:: write-test-4 ( x! -- q ) [ [let 0 :> y! f x! ] ] ;
[ ] [ 5 write-test-4 drop ] unit-test
:: let-let-test ( n -- n ) [let | n [ n 3 + ] | n ] ;
:: let-let-test ( n -- n ) [let n 3 + :> n n ] ;
[ 13 ] [ 10 let-let-test ] unit-test
@ -135,9 +134,9 @@ M:: string lambda-generic ( a b -- c ) a b lambda-generic-2 ;
[ ] [ \ lambda-generic see ] unit-test
:: unparse-test-1 ( a -- ) [let | a! [ 3 ] | ] ;
:: unparse-test-1 ( a -- ) [let 3 :> a! 4 :> b ] ;
[ "[let | a! [ 3 ] | ]" ] [
[ "[let 3 :> a! 4 :> b ]" ] [
\ unparse-test-1 "lambda" word-prop body>> first unparse
] unit-test
@ -163,38 +162,6 @@ DEFER: xyzzy
[ 5 ] [ 10 xyzzy ] unit-test
:: let*-test-1 ( a -- b )
[let* | b [ a 1 + ]
c [ b 1 + ] |
a b c 3array ] ;
[ { 1 2 3 } ] [ 1 let*-test-1 ] unit-test
:: let*-test-2 ( a -- b )
[let* | b [ a 1 + ]
c! [ b 1 + ] |
a b c 3array ] ;
[ { 1 2 3 } ] [ 1 let*-test-2 ] unit-test
:: let*-test-3 ( a -- b )
[let* | b [ a 1 + ]
c! [ b 1 + ] |
c 1 + c! a b c 3array ] ;
[ { 1 2 4 } ] [ 1 let*-test-3 ] unit-test
:: let*-test-4 ( a b -- c d )
[let | a [ b ]
b [ a ] |
[let* | a' [ a ]
a'' [ a' ]
b' [ b ]
b'' [ b' ] |
a'' b'' ] ] ;
[ "xxx" "yyy" ] [ "yyy" "xxx" let*-test-4 ] unit-test
GENERIC: next-method-test ( a -- b )
M: integer next-method-test 3 + ;
@ -209,11 +176,11 @@ M:: fixnum next-method-test ( a -- b ) a call-next-method 1 + ;
{ 3 0 } [| a b c | ] must-infer-as
[ ] [ 1 [let | a [ ] | ] ] unit-test
[ ] [ 1 [let :> a ] ] unit-test
[ 3 ] [ 1 [let | a [ ] | 3 ] ] unit-test
[ 3 ] [ 1 [let :> a 3 ] ] unit-test
[ ] [ 1 2 [let | a [ ] b [ ] | ] ] unit-test
[ ] [ 1 2 [let :> a :> b ] ] unit-test
:: a-word-with-locals ( a b -- ) ;
@ -271,10 +238,10 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
[ t ] [ 12 &&-test ] unit-test
:: let-and-cond-test-1 ( -- a )
[let | a [ 10 ] |
[let | a [ 20 ] |
[let 10 :> a
[let 20 :> a
{
{ [ t ] [ [let | c [ 30 ] | a ] ] }
{ [ t ] [ [let 30 :> c a ] ] }
} cond
]
] ;
@ -284,8 +251,8 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
[ 20 ] [ let-and-cond-test-1 ] unit-test
:: let-and-cond-test-2 ( -- pair )
[let | A [ 10 ] |
[let | B [ 20 ] |
[let 10 :> A
[let 20 :> B
{ { [ t ] [ { A B } ] } } cond
]
] ;
@ -298,7 +265,7 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
[ { 10 20 } ] [ 10 20 [| a b | { a b } ] call ] unit-test
[ { 10 20 30 } ] [ 10 20 30 [| a b c | { a b c } ] call ] unit-test
[ { 10 20 30 } ] [ [let | a [ 10 ] b [ 20 ] c [ 30 ] | { a b c } ] ] unit-test
[ { 10 20 30 } ] [ [let 10 :> a 20 :> b 30 :> c { a b c } ] ] unit-test
[ V{ 10 20 30 } ] [ 10 20 30 [| a b c | V{ a b c } ] call ] unit-test
@ -418,7 +385,7 @@ M:: integer lambda-method-forget-test ( a -- b ) a ;
[ 10 ] [ 10 [| A | { [ A ] } ] call first call ] unit-test
[
"USING: locals fry math ; 1 '[ [let | A [ 10 ] | A _ + ] ]"
"USING: locals fry math ; 1 '[ [let 10 :> A A _ + ] ]"
eval( -- ) call
] [ error>> >r/r>-in-fry-error? ] must-fail-with
@ -430,10 +397,7 @@ M:: integer lambda-method-forget-test ( a -- b ) a ;
[ t ] [ 3 funny-macro-test ] unit-test
[ f ] [ 2 funny-macro-test ] unit-test
! Some odd parser corner cases
[ "USE: locals [let" eval( -- ) ] [ error>> unexpected-eof? ] must-fail-with
[ "USE: locals [let |" eval( -- ) ] [ error>> unexpected-eof? ] must-fail-with
[ "USE: locals [let | a" eval( -- ) ] [ error>> unexpected-eof? ] must-fail-with
[ "USE: locals [|" eval( -- ) ] [ error>> unexpected-eof? ] must-fail-with
[ 25 ] [ 5 [| a | { [ a sq ] } cond ] call ] unit-test
@ -449,11 +413,9 @@ M:: integer lambda-method-forget-test ( a -- b ) a ;
[ 3 ] [ 3 [| a | \ a ] call ] unit-test
[ "USE: locals [| | { [let | a [ 0 ] | a ] } ]" eval( -- ) ] must-fail
[ "USE: locals [| | { [let 0 :> a a ] } ]" eval( -- ) ] must-fail
[ "USE: locals [| | { [let* | a [ 0 ] | a ] } ]" eval( -- ) ] must-fail
[ "USE: locals [| | [let | a! [ 0 ] | { a! } ] ]" eval( -- ) ] must-fail
[ "USE: locals [| | [let 0 :> a! { a! } ] ]" eval( -- ) ] must-fail
[ "USE: locals [| | { :> a } ]" eval( -- ) ] must-fail
@ -466,13 +428,13 @@ M:: integer lambda-method-forget-test ( a -- b ) a ;
[ 3 ] [ 2 [| | :> a! a 1 + a! a ] call ] unit-test
: fry-locals-test-1 ( -- n )
[let | | 6 '[ [let | A [ 4 ] | A _ + ] ] call ] ;
[let 6 '[ [let 4 :> A A _ + ] ] call ] ;
\ fry-locals-test-1 def>> must-infer
[ 10 ] [ fry-locals-test-1 ] unit-test
:: fry-locals-test-2 ( -- n )
[let | | 6 '[ [let | A [ 4 ] | A _ + ] ] call ] ;
[let 6 '[ [let 4 :> A A _ + ] ] call ] ;
\ fry-locals-test-2 def>> must-infer
[ 10 ] [ fry-locals-test-2 ] unit-test
@ -490,18 +452,18 @@ M:: integer lambda-method-forget-test ( a -- b ) a ;
] unit-test
[ 10 ] [
[| | 0 '[ [let | A [ 10 ] | A _ + ] ] call ] call
[| | 0 '[ [let 10 :> A A _ + ] ] call ] call
] unit-test
! littledan found this problem
[ "bar" ] [ [let | a [ [let | foo [ "bar" ] | foo ] ] | a ] ] unit-test
[ 10 ] [ [let | a [ 10 ] | [let | b [ a ] | b ] ] ] unit-test
[ "bar" ] [ [let [let "bar" :> foo foo ] :> a a ] ] unit-test
[ 10 ] [ [let 10 :> a [let a :> b b ] ] ] unit-test
[ { \ + } ] [ [let | x [ \ + ] | { \ x } ] ] unit-test
[ { \ + } ] [ [let \ + :> x { \ x } ] ] unit-test
[ { \ + 3 } ] [ [let | a [ 3 ] | { \ + a } ] ] unit-test
[ { \ + 3 } ] [ [let 3 :> a { \ + a } ] ] unit-test
[ 3 ] [ [let | a [ \ + ] | 1 2 [ \ a execute ] ] call ] unit-test
[ 3 ] [ [let \ + :> a 1 2 [ \ a execute ] ] call ] unit-test
! erg found this problem
:: erg's-:>-bug ( n ? -- n ) ? [ n :> n n ] [ n :> b b ] if ;

View File

@ -13,8 +13,6 @@ SYNTAX: [| parse-lambda over push-all ;
SYNTAX: [let parse-let over push-all ;
SYNTAX: [let* parse-let* over push-all ;
SYNTAX: :: (::) define-declared ;
SYNTAX: M:: (M::) define ;

View File

@ -7,13 +7,11 @@ M: lambda expand-macros clone [ expand-macros ] change-body ;
M: lambda expand-macros* expand-macros literal ;
M: binding-form expand-macros
clone
[ [ expand-macros ] assoc-map ] change-bindings
[ expand-macros ] change-body ;
M: let expand-macros
clone [ expand-macros ] change-body ;
M: binding-form expand-macros* expand-macros literal ;
M: let expand-macros* expand-macros literal ;
M: lambda condomize? drop t ;
M: lambda condomize '[ @ ] ;
M: lambda condomize '[ @ ] ;

View File

@ -56,35 +56,8 @@ M: lambda-parser parse-quotation ( -- quotation )
[ nip scan-object 2array ]
} cond ;
: (parse-bindings) ( end -- )
dup parse-binding dup [
first2 [ make-local ] dip 2array ,
(parse-bindings)
] [ 2drop ] if ;
: with-bindings ( quot -- words assoc )
'[
in-lambda? on
_ H{ } make-assoc
] { } make swap ; inline
: parse-bindings ( end -- bindings vars )
[ (parse-bindings) ] with-bindings ;
: parse-let ( -- form )
"|" expect "|" parse-bindings
(parse-lambda) <let> ?rewrite-closures ;
: parse-bindings* ( end -- words assoc )
[
namespace use-words
(parse-bindings)
namespace unuse-words
] with-bindings ;
: parse-let* ( -- form )
"|" expect "|" parse-bindings*
(parse-lambda) <let*> ?rewrite-closures ;
H{ } clone (parse-lambda) <let> ?rewrite-closures ;
: parse-locals ( -- effect vars assoc )
complete-effect

View File

@ -27,20 +27,12 @@ M: lambda pprint*
: pprint-let ( let word -- )
pprint-word
[ body>> ] [ bindings>> ] bi
\ | pprint-word
t <inset
<block
[ <block [ pprint-var ] dip pprint* block> ] assoc-each
block>
\ | pprint-word
<block pprint-elements block>
block>
<block body>> pprint-elements block>
\ ] pprint-word ;
M: let pprint* \ [let pprint-let ;
M: let* pprint* \ [let* pprint-let ;
M: def pprint*
<block \ :> pprint-word local>> pprint-word block> ;
dup local>> word?
[ <block \ :> pprint-word local>> pprint-var block> ]
[ pprint-tuple ] if ;

View File

@ -6,7 +6,7 @@ locals.errors locals.types make quotations sequences vectors
words ;
IN: locals.rewrite.sugar
! Step 1: rewrite [| [let [let* into :> forms, turn
! Step 1: rewrite [| into :> forms, turn
! literals with locals in them into code which constructs
! the literal after pushing locals on the stack
@ -73,7 +73,7 @@ M: quotation rewrite-element rewrite-sugar* ;
M: lambda rewrite-element rewrite-sugar* ;
M: binding-form rewrite-element binding-form-in-literal-error ;
M: let rewrite-element let-form-in-literal-error ;
M: local rewrite-element , ;
@ -115,12 +115,5 @@ M: word rewrite-sugar*
M: object rewrite-sugar* , ;
: let-rewrite ( body bindings -- )
[ quotation-rewrite % <def> , ] assoc-each
quotation-rewrite % ;
M: let rewrite-sugar*
[ body>> ] [ bindings>> ] bi let-rewrite ;
M: let* rewrite-sugar*
[ body>> ] [ bindings>> ] bi let-rewrite ;
body>> quotation-rewrite % ;

View File

@ -8,16 +8,10 @@ TUPLE: lambda vars body ;
C: <lambda> lambda
TUPLE: binding-form bindings body ;
TUPLE: let < binding-form ;
TUPLE: let body ;
C: <let> let
TUPLE: let* < binding-form ;
C: <let*> let*
TUPLE: quote local ;
C: <quote> quote