aboutsummaryrefslogtreecommitdiff
path: root/src/interp
diff options
context:
space:
mode:
Diffstat (limited to 'src/interp')
-rw-r--r--src/interp/compiler.boot101
-rw-r--r--src/interp/fnewmeta.lisp16
-rw-r--r--src/interp/functor.boot2
-rw-r--r--src/interp/g-opt.boot4
-rw-r--r--src/interp/lisp-backend.boot42
5 files changed, 107 insertions, 58 deletions
diff --git a/src/interp/compiler.boot b/src/interp/compiler.boot
index c85d1e9f..1dc074ce 100644
--- a/src/interp/compiler.boot
+++ b/src/interp/compiler.boot
@@ -2306,7 +2306,7 @@ localReferenceIfThere m ==
massageLoop x == main x where
main x ==
x isnt ['CATCH,tag,['REPEAT,:iters,body]] => x
- $mayHaveFreeIteratorVariables or CONTAINED('TAGGEDexit,x) => x
+ CONTAINED('TAGGEDexit,x) => x
replaceThrowWithLeave(body,tag)
containsNonLocalControl?(body,nil) => systemErrorHere ['massageLoop,x]
['CATCH,tag,['%loop,:iters,body,'%nil]]
@@ -2339,7 +2339,6 @@ compRepeatOrCollect(form,m,e) ==
$iterateCount: local := 0
$loopBodyTag: local := nil
$breakCount: local := 0
- $mayHaveFreeIteratorVariables: local := false
oldEnv := e
aggr := nil
[$loopKind,:itl,body]:= form
@@ -2399,6 +2398,28 @@ joinIntegerModes(x,y,e) ==
isSubset(y,x,e) => x
$Integer
+++ Given a for-loop iterator `x', return
+++ a. its storage class
+++ b. its name
+++ c. an environment containing its declaration in case a type
+++ was specified.
+classifyIteratorVariable(x,e) == check(main(x,e),x) where
+ main(x,e) ==
+ x is [":",var,t] =>
+ not ident? var => nil
+ checkVariableName var
+ t is 'local => ['%local,var,e]
+ t is 'free => ['%free,var,e]
+ [.,.,e] := compMakeDeclaration(var,t,e) => ['%local,var,e]
+ nil
+ ident? x =>
+ checkVariableName x
+ ['%local,x,e]
+ nil
+ check(x,y) ==
+ x ~= nil => x
+ stackAndThrow('"invalid loop variable %1bp",[y])
+
++ Subroutine of compStepIterator.
++ We are elaborating the STEP form of a for-iterator, where all
++ bounds and increment are expected to be integer-valued expressions.
@@ -2427,21 +2448,13 @@ compIntegerValue(x,e) ==
comp(x,$NonNegativeInteger,e) or
compOrCroak(x,$Integer,e)
-++ Issue a diagnostic if `x' names a loop variable with a matching
-++ declaration or definition in the enclosing scope.
-complainIfShadowing(x,e) ==
- $loopKind = 'COLLECT => nil -- collect loop variables always shadow
- if getmode(x,e) ~= nil then
- $mayHaveFreeIteratorVariables := true -- bound in compRepeatOrCollect
- stackWarning('"loop variable %1b shadows variable from enclosing scope",[x])
-
++ Attempt to compile a `for' iterator of the form
++ for index in start..final by inc
++ where the bound `final' may be missing.
compStepIterator(index,start,final,inc,e) ==
- checkVariableName index
- complainIfShadowing(index,e)
- $formalArgList := [index,:$formalArgList]
+ [sc,index,e] := classifyIteratorVariable(index,e)
+ if sc = '%local then
+ $formalArgList := [index,:$formalArgList]
[start,startMode,e] := compIntegerValue(start,e) or return
stackMessage('"start value of index: %1b must be an integer",[start])
[inc,incMode,e] := compIntegerValue(inc,e) or return
@@ -2456,38 +2469,42 @@ compStepIterator(index,start,final,inc,e) ==
if get(index,"mode",e) = nil then
[.,.,e] := compMakeDeclaration(index,indexMode,e) or return nil
e := giveVariableSomeValue(index,indexMode,e)
- [["STEP",index,start,inc,:final],e]
+ [["STEP",[sc,:index],start,inc,:final],e]
+compINIterator(x,y,e) ==
+ [sc,x,e] := classifyIteratorVariable(x,e)
+ --these two lines must be in this order, to get "for f in list f"
+ --to give an error message if f is undefined
+ [y',m,e]:= comp(y,$EmptyMode,e) or return nil
+ if sc = '%local then
+ $formalArgList := [x,:$formalArgList]
+ [mOver,mUnder]:=
+ modeIsAggregateOf("List",m,e) or return
+ stackMessage('"mode: %1pb must be a list of some mode",[m])
+ if null get(x,"mode",e) then [.,.,e]:=
+ compMakeDeclaration(x,mUnder,e) or return nil
+ e:= giveVariableSomeValue(x,mUnder,e)
+ [y'',m'',e] := coerce([y',m,e], mOver) or return nil
+ [["IN",[sc,:x],y''],e]
+
+compONIterator(x,y,e) ==
+ [sc,x,e] := classifyIteratorVariable(x,e)
+ if sc = '%local then
+ $formalArgList := [x,:$formalArgList]
+ [y',m,e]:= comp(y,$EmptyMode,e) or return nil
+ [mOver,mUnder]:=
+ modeIsAggregateOf("List",m,e) or return
+ stackMessage('"mode: %1pb must be a list of other modes",[m])
+ if null get(x,"mode",e) then [.,.,e]:=
+ compMakeDeclaration(x,m,e) or return nil
+ e:= giveVariableSomeValue(x,m,e)
+ [y'',m'',e] := coerce([y',m,e], mOver) or return nil
+ [["ON",[sc,:x],y''],e]
+
compIterator(it,e) ==
-- ??? Allow for declared iterator variable.
- it is ["IN",x,y] =>
- checkVariableName x
- complainIfShadowing(x,e)
- --these two lines must be in this order, to get "for f in list f"
- --to give an error message if f is undefined
- [y',m,e]:= comp(y,$EmptyMode,e) or return nil
- $formalArgList:= [x,:$formalArgList]
- [mOver,mUnder]:=
- modeIsAggregateOf("List",m,e) or return
- stackMessage('"mode: %1pb must be a list of some mode",[m])
- if null get(x,"mode",e) then [.,.,e]:=
- compMakeDeclaration(x,mUnder,e) or return nil
- e:= giveVariableSomeValue(x,mUnder,e)
- [y'',m'',e] := coerce([y',m,e], mOver) or return nil
- [["IN",x,y''],e]
- it is ["ON",x,y] =>
- checkVariableName x
- complainIfShadowing(x,e)
- $formalArgList:= [x,:$formalArgList]
- [y',m,e]:= comp(y,$EmptyMode,e) or return nil
- [mOver,mUnder]:=
- modeIsAggregateOf("List",m,e) or return
- stackMessage('"mode: %1pb must be a list of other modes",[m])
- if null get(x,"mode",e) then [.,.,e]:=
- compMakeDeclaration(x,m,e) or return nil
- e:= giveVariableSomeValue(x,m,e)
- [y'',m'',e] := coerce([y',m,e], mOver) or return nil
- [["ON",x,y''],e]
+ it is ["IN",x,y] => compINIterator(x,y,e)
+ it is ["ON",x,y] => compONIterator(x,y,e)
it is ["STEP",index,start,inc,:optFinal] =>
compStepIterator(index,start,optFinal,inc,e)
it is ["WHILE",p] =>
diff --git a/src/interp/fnewmeta.lisp b/src/interp/fnewmeta.lisp
index f1cd15e0..28c9e03c 100644
--- a/src/interp/fnewmeta.lisp
+++ b/src/interp/fnewmeta.lisp
@@ -263,7 +263,7 @@
(MUST (MATCH-ADVANCE-STRING ")"))))
(DEFUN |PARSE-QuantifiedVariable| ()
- (AND (PARSE-IDENTIFIER)
+ (AND (|PARSE-Name|)
(MUST (MATCH-ADVANCE-STRING ":"))
(MUST (|PARSE-Application|))
(MUST (PUSH-REDUCTION '|PARSE-QuantifiedVariable|
@@ -437,8 +437,18 @@
(CONS 'REPEAT (CONS (POP-STACK-1) NIL))))))
+(DEFUN |PARSE-Variable| ()
+ (OR (AND (|PARSE-Name|)
+ (OPTIONAL (AND (MATCH-ADVANCE-STRING ":")
+ (MUST (|PARSE-Application|))
+ (MUST (PUSH-REDUCTION '|PARSE-Variable|
+ (CONS '|:|
+ (CONS (POP-STACK-2)
+ (CONS (POP-STACK-1) NIL))))))))
+ (|PARSE-Primary|)))
+
(DEFUN |PARSE-Iterator| ()
- (OR (AND (MATCH-ADVANCE-KEYWORD "for") (MUST (|PARSE-Primary|))
+ (OR (AND (MATCH-ADVANCE-KEYWORD "for") (MUST (|PARSE-Variable|))
(MUST (MATCH-ADVANCE-KEYWORD "in"))
(MUST (|PARSE-Expression|))
(MUST (OR (AND (MATCH-ADVANCE-KEYWORD "by")
@@ -792,7 +802,7 @@
(DEFUN |PARSE-AnyId| ()
- (OR (PARSE-IDENTIFIER)
+ (OR (|PARSE-Name|)
(OR (AND (MATCH-STRING "$")
(PUSH-REDUCTION '|PARSE-AnyId| (CURRENT-SYMBOL))
(ACTION (ADVANCE-TOKEN)))
diff --git a/src/interp/functor.boot b/src/interp/functor.boot
index 8c6fc79c..be229149 100644
--- a/src/interp/functor.boot
+++ b/src/interp/functor.boot
@@ -284,7 +284,7 @@ optFunctorBody x ==
first pred="HasCategory" => nil
['%when,:l]
['%when,:l]
- [optFunctorBody u for u in x]
+ [optFunctorBody first x,:optFunctorBody rest x]
optFunctorBodyQuotable u ==
u = nil or integer? u or string? u => true
diff --git a/src/interp/g-opt.boot b/src/interp/g-opt.boot
index 69c333e3..f644ddda 100644
--- a/src/interp/g-opt.boot
+++ b/src/interp/g-opt.boot
@@ -624,7 +624,9 @@ optCollectVector form ==
-- pick a loop variable that we can use as the loop index.
[.,var,lo,inc,:etc] := iter
if lo = 0 and inc = 1 then
- index := var
+ index :=
+ var is [.,:var'] => var'
+ var
if [hi] := etc then
sz :=
inc = 1 =>
diff --git a/src/interp/lisp-backend.boot b/src/interp/lisp-backend.boot
index 36075241..6354a5cf 100644
--- a/src/interp/lisp-backend.boot
+++ b/src/interp/lisp-backend.boot
@@ -55,27 +55,39 @@ module lisp_-backend where
--% 3. predicate guarding loop body execution
--% 4. loop termination predicate
+++ Dummy free var name.
+$freeVarName == KEYWORD::freeVar
+
+loopVarInit(x,y) ==
+ x is ['%free,:id] => [id,[$freeVarName,middleEndExpand ['%LET,id,y]]]
+ if x is ['%local,:.] then
+ x := x.rest
+ [x,[x,middleEndExpand y]]
+
++ Generate code that sequentially visits each component of a list.
expandIN(x,l,early?) ==
g := gensym() -- rest of the list yet to be visited
early? => -- give the loop variable a wider scope.
- [[[g,middleEndExpand l],[x,'NIL]],
+ [x,init] := loopVarInit(x,'%nil)
+ [[[g,middleEndExpand l],init],
nil,[['SETQ,g,['CDR,g]]],
nil,[['NOT,['CONSP,g]],['PROGN,['SETQ,x,['CAR,g]],'NIL]]]
+ [x,init] := loopVarInit(x,['%head,g])
[[[g,middleEndExpand l]],
- [[x,['CAR,g]]],[['SETQ,g,['CDR,g]]],
+ [init],[['SETQ,g,['CDR,g]]],
nil,[['NOT,['CONSP,g]]]]
expandON(x,l) ==
- [[[x,middleEndExpand l]],nil,[["SETQ",x,["CDR",x]]],nil,[["ATOM",x]]]
+ [x,init] := loopVarInit(x,l)
+ [[init],nil,[["SETQ",x,["CDR",x]]],nil,[["ATOM",x]]]
++ Generate code that traverses an interval with lower bound 'lo',
++ arithmetic progression `step, and possible upper bound `final'.
expandSTEP(id,lo,step,final)==
- lo := middleEndExpand lo
step := middleEndExpand step
final := middleEndExpand final
- loopvar := [[id,lo]]
+ [id,init] := loopVarInit(id,lo)
+ loopvar := [init]
inc :=
atomic? step => step
g1 := gensym()
@@ -133,6 +145,16 @@ expandIterators iters ==
it is ["%init",var,val] => expandInit(var,val)
nil
+massageFreeVarInits(body,inits) ==
+ inits = nil => body
+ inits is [[var,init]] and sameObject?(var,$freeVarName) =>
+ ['SEQ,init,['EXIT,body]]
+ for init in inits repeat
+ sameObject?(init.first,$freeVarName) =>
+ init.first := gensym()
+ ['LET,inits,body]
+
+
expandLoop ['%loop,:iters,body,ret] ==
itersCode := expandIterators iters
itersCode = "failed" => systemErrorHere ["expandLoop",iters]
@@ -145,25 +167,23 @@ expandLoop ['%loop,:iters,body,ret] ==
if filters ~= nil then
body := mkpf([:filters,body],"AND")
-- If there is any body-wide initialization, now is the time.
- if bodyInits ~= nil then
- body := ["LET",bodyInits,body]
+ body := massageFreeVarInits(body,bodyInits)
exits := ["COND",
[mkpf(exits,"OR"),["RETURN",expandToVMForm ret]],
[true,body]]
body := ["LOOP",exits,:cont]
-- Finally, set up loop-wide initializations.
- loopInits = nil => body
- ["LET",loopInits,body]
+ massageFreeVarInits(body,loopInits)
++ Generate code for list comprehension.
expandCollect ['%collect,:iters,body] ==
val := gensym() -- result of the list comprehension
-- Transform the body to build the list as we go.
- body := ["SETQ",val,["CONS",middleEndExpand body,val]]
+ body := ['%store,val,['%pair,body,val]]
-- Initialize the variable holding the result; expand as
-- if ordinary loop. But don't forget we built the result
-- in reverse order.
- expandLoop ['%loop,:iters,["%init",val,nil],body,["reverse!",val]]
+ expandLoop ['%loop,:iters,["%init",val,nil],body,['%lreverse!,val]]
expandList(x is ['%list,:args]) ==
args := [expandToVMForm arg for arg in args]