diff options
Diffstat (limited to 'src/interp')
-rw-r--r-- | src/interp/g-opt.boot | 2 | ||||
-rw-r--r-- | src/interp/g-util.boot | 41 | ||||
-rw-r--r-- | src/interp/i-map.boot | 2 | ||||
-rw-r--r-- | src/interp/i-spec1.boot | 6 | ||||
-rw-r--r-- | src/interp/i-spec2.boot | 7 |
5 files changed, 36 insertions, 22 deletions
diff --git a/src/interp/g-opt.boot b/src/interp/g-opt.boot index 2717312a..6e0ea498 100644 --- a/src/interp/g-opt.boot +++ b/src/interp/g-opt.boot @@ -124,7 +124,7 @@ subrname u == nil changeThrowToExit(s,g) == - atom s or first s in '(QUOTE SEQ REPEAT COLLECT %collect) => nil + atom s or first s in '(QUOTE SEQ REPEAT COLLECT %collect %repeat) => nil s is ["THROW", =g,:u] => (s.first := "EXIT"; s.rest := u) changeThrowToExit(first s,g) changeThrowToExit(rest s,g) diff --git a/src/interp/g-util.boot b/src/interp/g-util.boot index 72c05126..8958843e 100644 --- a/src/interp/g-util.boot +++ b/src/interp/g-util.boot @@ -116,6 +116,9 @@ expandUNTIL p == g := gensym() [[[g,false]],nil,[["SETQ",g,middleEndExpand p]],nil,[g]] +expandInit(var,val) == + [[[var,middleEndExpand val]],nil,nil,nil,nil] + expandIterators iters == [toLisp it or leave "failed" for it in iters] where toLisp it == @@ -125,37 +128,49 @@ expandIterators iters == it is ["WHILE",pred] => expandWHILE pred it is [op,pred] and op in '(SUCHTHAT _|) => expandSUCHTHAT pred it is ["UNTIL",pred] => expandUNTIL pred + it is ["%init",var,val] => expandInit(var,val) nil -++ Generate code for list comprehension. -expandCollect ["%collect",:iters,body] == +expandLoop(iters,body,ret) == itersCode := expandIterators iters - itersCode = "failed" => systemErrorHere ["expandCollect",iters] - val := gensym() -- result of the list comprehension + itersCode = "failed" => systemErrorHere ["expandLoop",iters] + body := middleEndExpand body itersCode := "coagulate"/itersCode where coagulate(it1,it2) == [append(it1.k,it2.k) for k in 0..4] - [loopInits,bodyInits,cont,filters,exits,value] := itersCode - -- Transform the body to build the list as we go. - body := ["SETQ",val,["CONS",middleEndExpand body,val]] - -- Guard th execution of the body by the filters. + [loopInits,bodyInits,cont,filters,exits] := itersCode + -- Guard the execution of the body by the filters. 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] - if value ~= nil then - value := first value exits := ["COND", - [mkpf(exits,"OR"),["RETURN",["NREVERSE",val]]], + [mkpf(exits,"OR"),["RETURN",ret]], [true,body]] body := ["LOOP",exits,:cont] -- Finally, set up loop-wide initializations. - ["LET",[:loopInits,[val,nil]],body] + loopInits = nil => body + ["LET",loopInits,body] + +++ 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]] + -- Initialize the variable holding the result; expand as + -- if ordinary loop. But don't forget we built the result + -- in reverse order. + expandLoop([:iters,["%init",val,nil]],body,["NREVERSE",val]) + +++ Generate code for plain loop. +expandRepeat ["%repeat",:iters,body] == + expandLoop(iters,body,["voidValue"]) ++ Table of opcode-expander pairs. $OpcodeExpanders == [ - ["%collect",:"expandCollect"] + ["%collect",:"expandCollect"], + ["%repeat",:"expandRepeat"] ] ++ Return the expander of a middle-end opcode, or nil if there is none. diff --git a/src/interp/i-map.boot b/src/interp/i-map.boot index 9bb6bf4e..bfc99b6d 100644 --- a/src/interp/i-map.boot +++ b/src/interp/i-map.boot @@ -1031,7 +1031,7 @@ findLocalVars1(op,form) == form is ['is,l,pattern] => findLocalVars1(op,l) for var in listOfVariables rest pattern repeat mkLocalVar(op,var) - form is [oper,:itrl,body] and oper in '(REPEAT COLLECT %collect) => + form is [oper,:itrl,body] and oper in '(REPEAT COLLECT %collect %repeat) => findLocalsInLoop(op,itrl,body) form is [y,:argl] => y is "Record" or (y is "Union" and argl is [[":",.,.],:.]) => diff --git a/src/interp/i-spec1.boot b/src/interp/i-spec1.boot index 769af133..2b3b5ba3 100644 --- a/src/interp/i-spec1.boot +++ b/src/interp/i-spec1.boot @@ -572,11 +572,11 @@ interpCOLLECT(op,itrl,body) == emptyAtree op emptyAtree itrl emptyAtree body - code := ['COLLECT,:[interpIter itr for itr in itrl], + code := ["%collect",:[interpIter itr for itr in itrl], interpCOLLECTbody(body,$indexVars,$indexTypes)] value := timedEVALFUN code t := - null value => '(None) + null value => $None last $collectTypeList rm := ['Tuple,t] value := [objValUnwrap coerceInteractive(objNewWrap(v,m),t) @@ -817,7 +817,7 @@ checkForFreeVariables(v,locals) == op in '(LAMBDA QUOTE getValueFromEnvironment) => v op = "LETT" => -- Expands to a SETQ. ["SETF",:[checkForFreeVariables(a,locals) for a in args]] - op in '(COLLECT REPEAT %collect) => -- Introduces a new bound variable? + op in '(COLLECT REPEAT %collect %repeat) => first(args) is ["STEP",var,:.] => $boundVariables := [var,:$boundVariables] r := [op,:[checkForFreeVariables(a,locals) for a in args]] diff --git a/src/interp/i-spec2.boot b/src/interp/i-spec2.boot index d874e184..85035890 100644 --- a/src/interp/i-spec2.boot +++ b/src/interp/i-spec2.boot @@ -952,11 +952,10 @@ evalREPEAT(op,[:itrl,body],repeatMode) == bodyCode := getArgValue(body,bodyMode) if $iterateCount > 0 then bodyCode := ["CATCH",$repeatBodyLabel,bodyCode] - code := ['REPEAT,:[evalLoopIter itr for itr in itrl], bodyCode] - if repeatMode = $Void then code := ['OR,code,'(voidValue)] + code := ["%repeat",:[evalLoopIter itr for itr in itrl], bodyCode] code := timedOptimization code if $breakCount > 0 then code := ['CATCH,$repeatLabel,code] - val:= + val := $genValue => timedEVALFUN code objNewWrap(voidValue(),repeatMode) @@ -975,7 +974,7 @@ interpREPEAT(op,itrl,body,repeatMode) == $indexTypes: local := NIL code := -- we must insert a CATCH for the iterate clause - ["REPEAT",:[interpIter itr for itr in itrl], + ["%repeat",:[interpIter itr for itr in itrl], ["CATCH",$repeatBodyLabel,interpLoop(body,$indexVars, $indexTypes,nil)]] SPADCATCH(eval $repeatLabel,timedEVALFUN code) |