aboutsummaryrefslogtreecommitdiff
path: root/src/interp/as.boot
diff options
context:
space:
mode:
Diffstat (limited to 'src/interp/as.boot')
-rw-r--r--src/interp/as.boot1188
1 files changed, 1188 insertions, 0 deletions
diff --git a/src/interp/as.boot b/src/interp/as.boot
new file mode 100644
index 00000000..189b5f7d
--- /dev/null
+++ b/src/interp/as.boot
@@ -0,0 +1,1188 @@
+-- Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+-- All rights reserved.
+-- Copyright (C) 2007, Gabriel Dos Reis.
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are
+-- met:
+--
+-- - Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- - Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in
+-- the documentation and/or other materials provided with the
+-- distribution.
+--
+-- - Neither the name of The Numerical ALgorithms Group Ltd. nor the
+-- names of its contributors may be used to endorse or promote products
+-- derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+-- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+-- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+-- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+-- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import '"macros"
+)package "BOOT"
+
+--global hash tables for new compiler
+$docHash := MAKE_-HASH_-TABLE()
+$conHash := MAKE_-HASH_-TABLE()
+$opHash := MAKE_-HASH_-TABLE()
+$asyPrint := false
+
+asList() ==
+ OBEY '"rm -f temp.text"
+ OBEY '"ls as/*.asy > temp.text"
+ instream := OPEN '"temp.text"
+ lines := [READLINE instream while not EOFP instream]
+ CLOSE instream
+ lines
+
+asAll lines ==
+ for x in lines repeat
+ sayBrightly ['"-----> ",x]
+ asTran x
+ 'done
+
+as name ==
+ astran STRCONC(STRINGIMAGE name,'".asy")
+ 'done
+
+astran asyFile ==
+--global hash tables for new compiler
+ $docHash := MAKE_-HASH_-TABLE()
+ $conHash := MAKE_-HASH_-TABLE()
+ $constantHash := MAKE_-HASH_-TABLE()
+ $niladics : local := nil
+ $asyFile: local := asyFile
+ $asFilename: local := STRCONC(PATHNAME_-NAME asyFile,'".as")
+ asytran asyFile
+ conlist := [x for x in HKEYS $conHash | HGET($conHash,x) isnt [.,.,"function",:.]]
+ $mmAlist : local :=
+ [[con,:asyConstructorModemap con] for con in conlist]
+ $docAlist : local :=
+ [[con,:REMDUP asyDocumentation con] for con in conlist]
+ $parentsHash : local := MAKE_-HASH_-TABLE()
+--$childrenHash: local := MAKE_-HASH_-TABLE()
+ for con in conlist repeat
+ parents := asyParents con
+ HPUT($parentsHash,con,asyParents con)
+-- for [parent,:pred] in parents repeat
+-- parentOp := opOf parent
+-- HPUT($childrenHash,parentOp,insert([con,:pred],HGET($childrenHash,parentOp)))
+ $newConlist := union(conlist, $newConlist)
+ [[x,:asMakeAlist x] for x in HKEYS $conHash]
+
+asyParents(conform) ==
+ acc := nil
+ con:= opOf conform
+--formals := TAKE(#formalParams,$TriangleVariableList)
+ modemap := LASSOC(con,$mmAlist)
+ $constructorCategory :local := asySubstMapping CADAR modemap
+ for x in folks $constructorCategory repeat
+-- x := SUBLISLIS(formalParams,formals,x)
+-- x := SUBLISLIS(IFCDR conform,formalParams,x)
+-- x := SUBST('Type,'Object,x)
+ acc := [:explodeIfs x,:acc]
+ NREVERSE acc
+
+asySubstMapping u ==
+ u is [op,:r] =>
+ op = "->" =>
+ [s, t] := r
+ args :=
+ s is [op,:u] and asyComma? op => [asySubstMapping y for y in u]
+ [asySubstMapping s]
+ ['Mapping, asySubstMapping t, :args]
+ [asySubstMapping x for x in u]
+ u
+
+--asyFilePackage asyFile ==
+-- name := INTERN PATHNAME_-NAME asyFile
+-- modemap :=
+-- [[[name],['CATEGORY,'domain,
+-- :[asyMkSignature(con,CDAR mm) for [con,:mm] in $mmAlist]]],['T,name]]
+-- opAlist := [[con,[CDAR mm]] for [con,:mm] in $mmAlist]
+-- documentation :=
+-- [[con,[CDAR mm,fn LASSOC(con,$docAlist)]] for [con,:mm] in $mmAlist]
+-- where fn u ==
+-- LASSOC('constructor,u) is [[=nil,doc]] => doc
+-- '""
+-- res := [['constructorForm,name],['constant,:'true],
+-- ['constructorKind,:'file],
+-- ['constructorModemap,:modemap],
+-- ['sourceFile,:PNAME name],
+-- ['operationAlist,:zeroOneConversion opAlist],
+-- ['documentation,:documentation]]
+--asyDisplay(name,res)
+-- [name,:res]
+
+asyMkSignature(con,sig) ==
+-- atom sig => ['TYPE,con,sig]
+-- following line converts constants into nullary functions
+ atom sig => ['SIGNATURE,con,[sig]]
+ ['SIGNATURE,con,sig]
+
+asMakeAlist con ==
+ record := HGET($conHash,con)
+ [form,sig,predlist,kind,exposure,comments,typeCode,:filename] := first record
+--TTT in case we put the wrong thing in for niladic catgrs
+--if ATOM(form) and kind='category then form:=[form]
+ if ATOM(form) then form:=[form]
+ kind = 'function => asMakeAlistForFunction con
+ abb := asyAbbreviation(con,#(KDR sig))
+ if null KDR form then PUT(opOf form,'NILADIC,'T)
+ modemap := asySubstMapping LASSOC(con,$mmAlist)
+ $constructorCategory :local := CADAR modemap
+ parents := mySort HGET($parentsHash,con)
+--children:= mySort HGET($childrenHash,con)
+ alists := HGET($opHash,con)
+ opAlist := SUBLISLIS($FormalMapVariableList,KDR form,CDDR alists)
+ ancestorAlist:= SUBLISLIS($FormalMapVariableList,KDR form,CAR alists)
+ catAttrs := [[x,:true] for x in getAttributesFromCATEGORY $constructorCategory]
+ attributeAlist := REMDUP [:CADR alists,:catAttrs]
+ documentation :=
+ SUBLISLIS($FormalMapVariableList,KDR form,LASSOC(con,$docAlist))
+ filestring := STRCONC(PATHNAME_-NAME STRINGIMAGE filename,'".as")
+ constantPart := HGET($constantHash,con) and [['constant,:true]]
+ niladicPart := MEMQ(con,$niladics) and [['NILADIC,:true]]
+ falist := TAKE(#KDR form,$FormalMapVariableList)
+ constructorCategory :=
+ kind = 'category =>
+ talist := TAKE(#KDR form, $TriangleVariableList)
+ SUBLISLIS(talist, falist, $constructorCategory)
+ SUBLISLIS(falist,KDR form,$constructorCategory)
+ if constructorCategory='Category then kind := 'category
+ exportAlist := asGetExports(kind, form, constructorCategory)
+ constructorModemap := SUBLISLIS(falist,KDR form,modemap)
+--TTT fix a niladic category constructormodemap (remove the joins)
+ if kind = 'category then
+ SETF(CADAR(constructorModemap),['Category])
+ res := [['constructorForm,:form],:constantPart,:niladicPart,
+ ['constructorKind,:kind],
+ ['constructorModemap,:constructorModemap],
+ ['abbreviation,:abb],
+ ['constructorCategory,:constructorCategory],
+ ['parents,:parents],
+ ['attributes,:attributeAlist],
+ ['ancestors,:ancestorAlist],
+ -- ['children,:children],
+ ['sourceFile,:filestring],
+ ['operationAlist,:zeroOneConversion opAlist],
+ ['modemaps,:asGetModemaps(exportAlist,form,kind,modemap)],
+ ['sourcefile,:$asFilename],
+ ['typeCode,:typeCode],
+ ['documentation,:documentation]]
+ if $asyPrint then asyDisplay(con,res)
+ res
+
+asGetExports(kind, conform, catform) ==
+ u := asCategoryParts(kind, conform, catform, true) or return nil
+ -- ensure that signatures are lists
+ [[op, sigpred] for [op,sig,:pred] in CDDR u] where
+ sigpred() ==
+ pred :=
+ pred = "T" => nil
+ pred
+ [sig, nil, :pred]
+
+asMakeAlistForFunction fn ==
+ record := HGET($conHash,fn)
+ [form,sig,predlist,kind,exposure,comments,typeCode,:filename] := first record
+ modemap := LASSOC(fn,$mmAlist)
+ newsig := asySignature(sig,nil)
+ opAlist := [[fn,[newsig,nil,:predlist]]]
+ res := [['modemaps,:asGetModemaps(opAlist,fn,'function,modemap)],
+ ['typeCode,:typeCode]]
+ if $asyPrint then asyDisplay(fn,res)
+ res
+
+getAttributesFromCATEGORY catform ==
+ catform is ['CATEGORY,.,:r] => [y for x in r | x is ['ATTRIBUTE,y]]
+ catform is ['Join,:m,x] => getAttributesFromCATEGORY x
+ nil
+
+displayDatabase x == main where
+ main() ==
+ for y in
+ '(CONSTRUCTORFORM CONSTRUCTORKIND _
+ CONSTRUCTORMODEMAP _
+ ABBREVIATION _
+ CONSTRUCTORCATEGORY _
+ PARENTS _
+ ATTRIBUTES _
+ ANCESTORS _
+ SOURCEFILE _
+ OPERATIONALIST _
+ MODEMAPS _
+ SOURCEFILE _
+ DOCUMENTATION) repeat fn(x,y)
+ where
+ fn(x,y) ==
+ sayBrightly ['"----------------- ",y,'" --------------------"]
+ pp GETDATABASE(x,y)
+
+-- For some reason Dick has modified as.boot to convert the
+-- identifier |0| or |1| to an integer in the list of operations.
+-- This is WRONG, all existing code assumes that operation names
+-- are always identifiers not numbers.
+-- This function breaks the ability of the interpreter to find
+-- |0| or |1| as exports of new compiler domains.
+-- Unless someone has a strong reason for keeping the change,
+-- this function should be no-opped, i.e.
+-- zeroOneConversion opAlist == opAlist
+-- If this change is made, then we are able to find asharp constants again.
+-- bmt Mar 26, 1994 and executed by rss
+
+zeroOneConversion opAlist == opAlist
+-- for u in opAlist repeat
+-- [op,:.] := u
+-- DIGITP (PNAME op).0 => RPLACA(u, string2Integer PNAME op)
+-- opAlist
+
+asyDisplay(con,alist) ==
+ banner := '"=============================="
+ sayBrightly [banner,'" ",con,'" ",banner]
+ for [prop,:value] in alist repeat
+ sayBrightlyNT [prop,'": "]
+ pp value
+
+asGetModemaps(opAlist,oform,kind,modemap) ==
+ acc:= nil
+ rpvl:=
+ MEMQ(kind, '(category function)) => rest $PatternVariableList -- *1 is special for $
+ $PatternVariableList
+ form := [opOf oform,:[y for x in KDR oform for y in rpvl]]
+ dc :=
+ MEMQ(kind, '(category function)) => "*1"
+ form
+ pred1 :=
+ kind = 'category => [["*1",form]]
+ nil
+ signature := CDAR modemap
+ domainList :=
+ [[a,m] for a in rest form for m in rest signature |
+ asIsCategoryForm m]
+ catPredList:=
+ kind = 'function => [["isFreeFunction","*1",opOf form]]
+ [['ofCategory,:u] for u in [:pred1,:domainList]]
+-- for [op,:itemlist] in SUBLISLIS(rpvl, $FormalMapVariableList,opAlist) repeat
+-- the code seems to oscillate between generating $FormalMapVariableList
+-- and generating $TriangleVariableList
+ for [op,:itemlist] in SUBLISLIS(rpvl, $FormalMapVariableList,opAlist) repeat
+ for [sig0, pred] in itemlist repeat
+ sig := SUBST(dc,"$",sig0)
+ pred:= SUBST(dc,"$",pred)
+ sig := SUBLISLIS(rpvl,KDR oform,sig)
+ pred:= SUBLISLIS(rpvl,KDR oform,pred)
+ pred := pred or 'T
+ ----------> Constants change <--------------
+ if IDENTP sig0 then
+ sig := [sig]
+ pred := MKPF([pred,'(isAsConstant)],'AND)
+ pred' := MKPF([pred,:catPredList],'AND)
+ mm := [[dc,:sig],[pred']]
+ acc := [[op,:interactiveModemapForm mm],:acc]
+ NREVERSE acc
+
+asIsCategoryForm m ==
+ m = 'BasicType or GETDATABASE(opOf m,'CONSTRUCTORKIND) = 'category
+
+asyDocumentation con ==
+ docHash := HGET($docHash,con)
+ u := [[op,:[fn(x,op) for x in rec]] for op in HKEYS docHash
+ | rec := HGET(docHash,op)] where fn(x,op) ==
+ [form,sig,pred,origin,where?,comments,:.] := x
+ ----------> Constants change <--------------
+ if IDENTP sig then sig := [sig]
+ [asySignature(sig,nil),trimComments comments]
+ [form,sig,pred,origin,where?,comments] := first HGET($conHash,con)
+ --above "first" assumes only one entry
+ comments := trimComments asyExtractDescription comments
+ [:u,['constructor,[nil,comments]]]
+
+asyExtractDescription str ==
+ k := STRPOS('"Description:",str,0,nil) => asyExtractDescription SUBSTRING(str,k + 12,nil)
+ k := STRPOS('"Author:",str,0,nil) => asyExtractDescription SUBSTRING(str,0,k)
+ str
+
+trimComments str ==
+ null str or str = '"" => '""
+ m := MAXINDEX str
+ str := SUBSTRING(str,0,m)
+ trimString str
+
+asyExportAlist con ==
+--format of 'operationAlist property of LISPLIBS (as returned from koOps):
+-- <sig slotNumberOrNil optPred optELT>
+-- <sig sig' predOrT "Subsumed">
+--!!! asyFile NEED: need to know if function is implemented by domain!!!
+ docHash := HGET($docHash,con)
+ [[op,:[fn(x,op) for x in rec]] for op in HKEYS docHash | rec := HGET(docHash,op)]
+ where fn(x,op) ==
+ [form,sig,pred,origin,where?,comments,:.] := x
+ tail :=
+ pred => [pred]
+ nil
+ newSig := asySignature(sig,nil)
+ [newSig,nil,:tail]
+
+asyMakeOperationAlist(con,proplist, key) ==
+ oplist :=
+ u := LASSOC('domExports,proplist) =>
+ kind := 'domain
+ u
+ u := LASSOC('catExports,proplist) =>
+ kind := 'category
+ u
+ key = 'domain =>
+ kind := 'domain
+ u := NIL
+ return nil
+ ht := MAKE_-HASH_-TABLE()
+ ancestorAlist := nil
+ for ['Declare,id,form,r] in oplist repeat
+ id = "%%" =>
+ opOf form = con => nil
+ y := asyAncestors form
+ [attrs, na] := asyFindAttrs y
+ y := na
+ if opOf(y)^=con then ancestorAlist := [ [y,:true],:ancestorAlist]
+ idForm :=
+ form is ['Apply,'_-_>,source,target] => [id,:asyArgs source]
+ ----------> Constants change <--------------
+ id
+ pred :=
+ LASSOC('condition,r) is p => hackToRemoveAnd p
+ nil
+ sig := asySignature(asytranForm(form,[idForm],nil),nil)
+ entry :=
+ --id ^= "%%" and IDENTP idForm => [[sig],nil,nil,'ASCONST]
+ id ^= "%%" and IDENTP idForm =>
+ pred => [[sig],nil,asyPredTran pred,'ASCONST]
+ [[sig],nil,true,'ASCONST]
+ pred => [sig,nil,asyPredTran pred]
+ [sig]
+ HPUT(ht,id,[entry,:HGET(ht,id)])
+ opalist := [[op,:REMDUP HGET(ht,op)] for op in HKEYS ht]
+ --HPUT($opHash,con,[ancestorAlist,attributeAlist,:opalist])
+ HPUT($opHash,con,[ancestorAlist,nil,:opalist])
+
+hackToRemoveAnd p ==
+---remove this as soon as .asy files do not contain forms (And pred) forms
+ p is ['And,q,:r] =>
+ r => ['AND,q,:r]
+ q
+ p
+
+asyAncestors x ==
+ x is ['Apply,:r] => asyAncestorList r
+ x is [op,y,:.] and MEMQ(op, '(PretendTo RestrictTo)) => asyAncestors y
+ atom x =>
+ x = '_% => '_$
+ MEMQ(x, $niladics) => [x]
+ GETDATABASE(x ,'NILADIC) => [x]
+ x
+ asyAncestorList x
+
+asyAncestorList x == [asyAncestors y for y in x]
+--============================================================================
+-- Build Operation Alist from sig
+--============================================================================
+
+--format of operations as returned from koOps
+-- <sig pred pakOriginOrNil TifPakExposedOrNil>
+-- <sig pred origin exposed?>
+
+--abb,kind,file,sourcefile,coSig,dbLineNumber,constructorArgs,libfile
+--((sig where(NIL or #) condition(T or pred) ELTorSubsumed) ...
+--expanded lists are: sig, predicate, origin, exposeFlag, comments
+
+--============================================================================
+-- Building Hash Tables for Operations/Constructors
+--============================================================================
+asytran fn ==
+--put operations into table format for browser:
+-- <sig pred origin exposed? comments>
+ inStream := OPEN fn
+ sayBrightly ['" Reading ",fn]
+ u := VMREAD inStream
+ $niladics := mkNiladics u
+ for x in $niladics repeat PUT(x,'NILADIC,true)
+ for d in u repeat
+ ['Declare,name,:.] := d
+ name = "%%" => 'skip --skip over top-level properties
+ $docHashLocal: local := MAKE_-HASH_-TABLE()
+ asytranDeclaration(d,'(top),nil,false)
+ if null name then hohohoho()
+ HPUT($docHash,name,$docHashLocal)
+ CLOSE inStream
+ 'done
+
+mkNiladics u ==
+ [name for x in u | x is ['Declare,name,y,:.] and y isnt ['Apply,'_-_>,:.]]
+
+--OLD DEFINITION FOLLOWS
+asytranDeclaration(dform,levels,predlist,local?) ==
+ ['Declare,id,form,r] := dform
+ id = 'failed => id
+ KAR dform ^= 'Declare => systemError '"asytranDeclaration"
+ if levels = '(top) then
+ if form isnt ['Apply,"->",:.] then HPUT($constantHash,id,true)
+ comments := LASSOC('documentation,r) or '""
+ idForm :=
+ levels is ['top,:.] =>
+ form is ['Apply,'_-_>,source,target] => [id,:asyArgs source]
+ id
+ ----------> Constants change <--------------
+ id
+ newsig := asytranForm(form,[idForm,:levels],local?)
+ key :=
+ levels is ['top,:.] =>
+ MEMQ(id,'(%% Category Type)) => 'constant
+ asyLooksLikeCatForm? form => 'category
+ form is ['Apply, '_-_>,.,u] =>
+ if u is ['Apply, construc,:.] then u:= construc
+ GETDATABASE(opOf u,'CONSTRUCTORKIND) = 'domain => 'function
+ asyLooksLikeCatForm? u => 'category
+ 'domain
+ 'domain
+ first levels
+ typeCode := LASSOC('symeTypeCode,r)
+ record := [idForm,newsig,asyMkpred predlist,key,true,comments,typeCode,:$asyFile]
+ if not local? then
+ ht :=
+ levels = '(top) => $conHash
+ $docHashLocal
+ HPUT(ht,id,[record,:HGET(ht,id)])
+ if levels = '(top) then asyMakeOperationAlist(id,r, key)
+ ['Declare,id,newsig,r]
+
+asyLooksLikeCatForm? x ==
+--TTT don't see a Third in my version ....
+ x is ['Define, ['Declare, ., ['Apply, 'Third,:.],:.],:.] or
+ x is ['Define, ['Declare, ., 'Category ],:.]
+
+--asytranDeclaration(dform,levels,predlist,local?) ==
+-- ['Declare,id,form,r] := dform
+-- id = 'failed => id
+-- levels isnt ['top,:.] => asytranForm(form,[id,:levels],local?)
+-- idForm :=
+-- form is ['Apply,'_-_>,source,target] => [id,:asyArgs source]
+-- id
+-- if form isnt ['Apply,"->",:.] then HPUT($constantHash,id,true)
+-- comments := LASSOC('documentation,r) or '""
+-- newsig := asytranForm(form,[idForm,:levels],local?)
+-- key :=
+-- MEMQ(id,'(%% Category Type)) => 'constant
+-- form is ['Apply,'Third,:.] => 'category
+-- form is ['Apply,.,.,target] and target is ['Apply,name,:.]
+-- and MEMQ(name,'(Third Join)) => 'category
+-- 'domain
+-- record := [newsig,asyMkpred predlist,key,true,comments,:$asyFile]
+-- if not local? then
+-- ht :=
+-- levels = '(top) => $conHash
+-- $docHashLocal
+-- HPUT(ht,id,[record,:HGET(ht,id)])
+-- if levels = '(top) then asyMakeOperationAlist(id,r)
+-- ['Declare,id,newsig,r]
+
+asyIsCatForm form ==
+ form is ['Apply,:r] =>
+ r is ['_-_>,.,a] => asyIsCatForm a
+ r is ['Third,'Type,:.] => true
+ false
+ false
+
+asyArgs source ==
+ args :=
+ source is [op,:u] and asyComma? op => u
+ [source]
+ [asyArg x for x in args]
+
+asyArg x ==
+ x is ['Declare,id,:.] => id
+ x
+
+asyMkpred predlist ==
+ null predlist => nil
+ predlist is [p] => p
+ ['AND,:predlist]
+
+asytranForm(form,levels,local?) ==
+ u := asytranForm1(form,levels,local?)
+ null u => hahah()
+ u
+
+asytranForm1(form,levels,local?) ==
+ form is ['With,left,cat] =>
+-- left ^= nil => error '"WITH cannot take a left argument yet"
+ asytranCategory(form,levels,nil,local?)
+ form is ['Apply,:.] => asytranApply(form,levels,local?)
+ form is ['Declare,:.] => asytranDeclaration(form,levels,nil,local?)
+ form is ['Comma,:r] => ['Comma,:[asytranForm(x,levels,local?) for x in r]]
+--form is ['_-_>,:s] => asytranMapping(s,levels,local?)
+ form is [op,a,b] and MEMQ(a,'(PretendTo RestrictTo)) =>
+ asytranForm1(a,levels,local?)
+ form is ['LitInteger,s] =>
+ READ_-FROM_-STRING(s)
+ form is ['Define,:.] =>
+ form is ['Define,['Declare,.,x,:.],rest] =>
+--TTT i don't know about this one but looks ok
+ x = 'Category => asytranForm1(rest,levels, local?)
+ asytranForm1(x,levels,local?)
+ error '"DEFINE forms are not handled yet"
+ if form = '_% then $hasPerCent := true
+ IDENTP form =>
+ form = "%" => "$"
+ GETL(form,'NILADIC) => [form]
+ form
+ [asytranForm(x,levels,local?) for x in form]
+
+asytranApply(['Apply,name,:arglist],levels,local?) ==
+ MEMQ(name,'(Record Union)) =>
+ [name,:[asytranApplySpecial(x, levels, local?) for x in arglist]]
+ null arglist => [name]
+ name is [ 'RestrictTo, :.] =>
+ asytranApply(['Apply, CAR CDR name,:arglist], levels, local?)
+ name is [ 'Qualify, :.] =>
+ asytranApply(['Apply, CAR CDR name,:arglist], levels, local?)
+ name is 'string => asytranLiteral CAR arglist
+ name is 'integer => asytranLiteral CAR arglist
+ name is 'float => asytranLiteral CAR arglist
+ name = 'Enumeration =>
+ ["Enumeration",:[asytranEnumItem arg for arg in arglist]]
+ [:argl,lastArg] := arglist
+ [name,:[asytranFormSpecial(arg,levels,true) for arg in argl],
+ asytranFormSpecial(lastArg,levels,false)]
+
+asytranLiteral(lit) ==
+ CAR CDR lit
+
+asytranEnumItem arg ==
+ arg is ['Declare, name, :.] => name
+ error '"Bad Enumeration entry"
+
+asytranApplySpecial(x, levels, local?) ==
+ x is ['Declare, name, typ, :.] => [":",name,asytranForm(typ, levels, local?)]
+ asytranForm(x, levels, local?)
+
+asytranFormSpecial(x, levels, local?) == --> this throws away variable name (revise later)
+ x is ['Declare, name, typ, :.] => asytranForm(typ, levels, local?)
+ asytranForm(x, levels, local?)
+
+asytranCategory(form,levels,predlist,local?) ==
+ cat :=
+ form is ['With,left,right] =>
+ right is ['Blank,:.] => ['Sequence]
+ right
+ form
+ left :=
+ form is ['With,left,right] =>
+ left is ['Blank,:.] => nil
+ left
+ nil
+ $hasPerCent: local := nil
+ items :=
+ cat is ['Sequence,:s] => s
+ [cat]
+ catTable := MAKE_-HASH_-TABLE()
+ catList := nil
+ for x in items | x repeat
+ if null x then systemError()
+ dform := asytranCategoryItem(x,levels,predlist,local?)
+ null dform => nil
+ dform is ['Declare,id,record,r] =>
+ HPUT(catTable,id,[asyWrap(record,predlist),:HGET(catTable,id)])
+ catList := [asyWrap(dform,predlist),:catList]
+ keys := listSort(function GLESSEQP,HKEYS catTable)
+ right1 := NREVERSE catList
+ right2 := [[key,:HGET(catTable,key)] for key in keys]
+ right :=
+ right2 => [:right1,['Exports,:right2]]
+ right1
+ res :=
+ left => [left,:right]
+ right
+ res is [x] and x is ['IF,:.] => x
+ ['With,:res]
+
+asyWrap(record,predlist) ==
+ predlist => ['IF,MKPF(predlist,'AND),record]
+ record
+
+asytranCategoryItem(x,levels,predlist,local?) ==
+ x is ['If,predicate,item,:r] =>
+ IFCAR r => error '"ELSE expressions not allowed yet in conditionals"
+ pred :=
+ predicate is ['Test,r] => r
+ predicate
+ asytranCategory(item,levels,[pred,:predlist],local?)
+ MEMQ(KAR x,'(Default Foreign)) => nil
+ x is ['Declare,:.] => asytranDeclaration(x,levels,predlist,local?)
+ x
+
+--============================================================================
+-- Extending Constructor Datatable
+--============================================================================
+--FORMAT of $constructorDataTable entry:
+--abb kind libFile sourceFile coSig constructorArgs
+--alist is ((kind . domain) (libFile . MATRIX) (sourceFile . "matrix")
+-- (coSig NIL T) (dbLineNumber . 29187) (constructorArgs R)
+-- (modemap . (
+-- (|Matrix| |#1|)
+-- (Join (MatrixCategory #1 (Vector #1) (Vector #1))
+-- (CATEGORY domain
+-- (SIGNATURE diagonalMatrix ($ (Vector #1)))
+-- (IF (has #1 (Field))
+-- (SIGNATURE inverse ((Union $ "failed") $)) noBranch)))
+-- (Ring))
+-- (T Matrix)) )
+extendConstructorDataTable() ==
+-- tb := $constructorDataTable
+ for x in listSort(function GLESSEQP,HKEYS $conHash) repeat
+-- if LASSOC(x,tb) then tb := DELLASOS(x,tb)
+ record := HGET($conHash,x)
+ [form,sig,predlist,origin,exposure,comments,typeCode,:filename] := first record
+ abb := asyAbbreviation(x,#(rest sig))
+ kind := 'domain
+ --Note: this "first" assumes that there is ONLY one sig per name
+ cosig := [nil,:asyCosig sig]
+ args := asyConstructorArgs sig
+ tb :=
+ [[x,abb,
+ ['kind,:kind],
+ ['cosig,:cosig],
+ ['libfile,filename],
+ ['sourceFile,STRINGIMAGE filename],
+ ['constructorArgs,:args]],:tb]
+ listSort(function GLESSEQP,ASSOCLEFT tb)
+
+asyConstructorArgs sig ==
+ sig is ['With,:.] => nil
+ sig is ['_-_>,source,target] =>
+ source is [op,:argl] and asyComma? op => [asyConstructorArg x for x in argl]
+ [asyConstructorArg source]
+
+asyConstructorArg x ==
+ x is ['Declare,name,t,:.] => name
+ x
+
+asyCosig sig == --can be a type or could be a signature
+ atom sig or sig is ['With,:.] => nil
+ sig is ['_-_>,source,target] =>
+ source is [op,:argl] and asyComma? op => [asyCosigType x for x in argl]
+ [asyCosigType source]
+ error false
+
+asyCosigType u ==
+ u is [name,t] =>
+ t is [fn,:.] =>
+ asyComma? fn => fn
+ fn = 'With => 'T
+ nil
+ t = 'Type => 'T
+ error '"Unknown atomic type"
+ error false
+
+asyAbbreviation(id,n) == chk(id,main) where --> n = number of arguments
+ main() ==
+ a := createAbbreviation id => a
+ name := PNAME id
+-- #name < 8 => INTERN UPCASE name
+ parts := asySplit(name,MAXINDEX name)
+ newname := "STRCONC"/[asyShorten x for x in parts]
+ #newname < 8 => INTERN newname
+ tryname := SUBSTRING(name,0,7)
+ not createAbbreviation tryname => INTERN UPCASE tryname
+ nil
+ chk(conname,abb) ==
+ (xx := asyGetAbbrevFromComments conname) => xx
+ con := abbreviation? abb =>
+ conname = con => abb
+ conname
+ abb
+
+asyGetAbbrevFromComments con ==
+ docHash := HGET($docHash,con)
+ u := [[op,:[fn(x,op) for x in rec]] for op in HKEYS docHash
+ | rec := HGET(docHash,op)] where fn(x,op) ==
+ [form,sig,pred,origin,where?,comments,:.] := x
+ ----------> Constants change <--------------
+ if IDENTP sig then sig := [sig]
+ [asySignature(sig,nil),trimComments comments]
+ [form,sig,pred,origin,where?,comments] := first HGET($conHash,con)
+ --above "first" assumes only one entry
+ x := asyExtractAbbreviation comments
+ x => intern x
+ NIL
+
+asyExtractAbbreviation str ==
+ not (k:= STRPOS('"Abbrev: ",str,0,nil)) => NIL
+ str := SUBSTRING(str, k+8, nil)
+ k := STRPOS($stringNewline, str,0,nil)
+ k => SUBSTRING(str, 0, k)
+ str
+
+asyShorten x ==
+ y := createAbbreviation x
+ or LASSOC(x,
+ '(("Small" . "SM") ("Single" ."S") ("Half" . "H")("Point" . "PT")
+ ("Floating" . "F") ("System" . "SYS") ("Number" . "N")
+ ("Inventor" . "IV")
+ ("Finite" . "F") ("Double" . "D") ("Builtin" . "BI"))) => y
+ UPCASE x
+
+asySplit(name,end) ==
+ end < 1 => [name]
+ k := 0
+ for i in 1..end while LOWER_-CASE_-P name.i repeat k := i
+ k := k + 1
+ [SUBSTRING(name,0,k),:asySplit(SUBSTRING(name,k,nil),end-k)]
+
+createAbbreviation s ==
+ if STRINGP s then s := INTERN s
+ a := constructor? s
+ a ^= s => a
+ nil
+
+--============================================================================
+-- extending getConstructorModemap Property
+--============================================================================
+--Note: modemap property is built when getConstructorModemap is called
+
+asyConstructorModemap con ==
+ HGET($conHash,con) isnt [record,:.] => nil --not there
+ [form,sig,predlist,kind,exposure,comments,typeCode,:filename] := record
+ $kind: local := kind
+ --NOTE: sig has the form (-> source target) or simply (target)
+ $constructorArgs: local := KDR form
+ signature := asySignature(sig,false)
+ formals := ['_$,:TAKE(#$constructorArgs,$FormalMapVariableList)]
+ mm := [[[con,:$constructorArgs],:signature],['T,con]]
+ SUBLISLIS(formals,['_%,:$constructorArgs],mm)
+
+asySignature(sig,names?) ==
+ sig is ['Join,:.] => [asySig(sig,nil)]
+ sig is ['With,:.] => [asySig(sig,nil)]
+ sig is ['_-_>,source,target] =>
+ target :=
+ names? => ['dummy,target]
+ target
+ source is [op,:argl] and asyComma? op =>
+ [asySigTarget(target,names?),:[asySig(x,names?) for x in argl]]
+ [asySigTarget(target,names?),asySig(source,names?)]
+ ----------> The following is a hack for constants which are category names<--
+ sig is ['Third,:.] => [asySig(sig,nil)]
+ ----------> Constants change <--------------
+ asySig(sig,nil)
+
+asySigTarget(u,name?) == asySig1(u,name?,true)
+
+asySig(u,name?) == asySig1(u,name?,false)
+
+asySig1(u,name?,target?) ==
+ x :=
+ name? and u is [name,t] => t
+ u
+ x is [fn,:r] =>
+ fn = 'Join => asyTypeJoin r ---------> jump out to newer code 4/94
+ MEMQ(fn, '(RestrictTo PretendTo)) => asySig(first r,name?)
+ asyComma? fn =>
+ u := [asySig(x,name?) for x in r]
+ target? =>
+ null u => '(Void)
+ -- this implies a multiple value return, not currently supported
+ -- in the interpreter
+ ['Multi,:u]
+ u
+ fn = 'With => asyCATEGORY r
+ fn = 'Third =>
+ r is [b] =>
+ b is ['With,:s] => asyCATEGORY s
+ b is ['Blank,:.] => asyCATEGORY nil
+ error x
+ fn = 'Apply and r is ['_-_>,:s] => asyMapping(s,name?)
+ fn = '_-_> => asyMapping(r,name?)
+ fn = 'Declare and r is [name,typ,:.] =>
+ asySig1(typ, name?, target?)
+ x is '(_%) => '(_$)
+ [fn,:[asySig(x,name?) for x in r]]
+--x = 'Type => '(Type)
+ x = '_% => '_$
+ x
+
+-- old version was :
+--asyMapping([a,b],name?) ==
+-- a := asySig(a,name?)
+-- b := asySig(b,name?)
+-- args :=
+-- a is [op,:r] and asyComma? op => r
+-- [a]
+-- ['Mapping,b,:args]
+
+asyMapping([a,b],name?) ==
+ newa := asySig(a,name?)
+ b := asySig(b,name?)
+ args :=
+ a is [op,:r] and asyComma? op => newa
+ [a]
+ ['Mapping,b,:args]
+
+--============================================================================
+-- code for asySignatures of the form (Join,:...)
+--============================================================================
+asyType x ==
+ x is [fn,:r] =>
+ fn = 'Join => asyTypeJoin r
+ MEMQ(fn, '(RestrictTo PretendTo)) => asyType first r
+ asyComma? fn =>
+ u := [asyType x for x in r]
+ u
+ fn = 'With => asyCATEGORY r
+ fn = '_-_> => asyTypeMapping r
+ fn = 'Apply => r
+-- fn = 'Declare and r is [name,typ,:.] => typ
+ x is '(_%) => '(_$)
+ x
+--x = 'Type => '(Type)
+ x = '_% => '_$
+ x
+
+asyTypeJoin r ==
+ $conStack : local := nil
+ $opStack : local := nil
+ $predlist : local := nil
+ for x in r repeat asyTypeJoinPart(x,$predlist)
+ catpart :=
+ $opStack => ['CATEGORY,$kind,:asyTypeJoinStack REVERSE $opStack]
+ nil
+ conpart := asyTypeJoinStack REVERSE $conStack
+ conpart =>
+ catpart => ['Join,:conpart,catpart]
+ CDR conpart => ['Join,:conpart]
+ conpart
+ catpart
+
+asyTypeJoinPart(x,$predlist) ==
+ x is ['Join,:y] => for z in y repeat asyTypeJoinPart(z, $predlist)
+ x is ['With,:y] => for p in y repeat asyTypeJoinPartWith p
+ asyTypeJoinPartWith x
+
+asyTypeJoinPartWith x ==
+ x is ['Exports,:y] => for p in y repeat asyTypeJoinPartExport p
+ x is ['Exports,:.] => systemError 'exports
+ x is ['Comma] => nil
+ x is ['Export,:y] => nil
+ x is ['IF,:r] => asyTypeJoinPartIf r
+ x is ['Sequence,:x] => for y in x repeat asyTypeJoinItem y
+ asyTypeJoinItem x
+
+asyTypeJoinPartIf [pred,value] ==
+ predlist := [asyTypeJoinPartPred pred,:$predlist]
+ asyTypeJoinPart(value,predlist)
+
+asyTypeJoinPartPred x ==
+ x is ['Test, y] => asyTypeUnit y
+ asyTypeUnit x
+
+asyTypeJoinItem x ==
+ result := asyTypeUnit x
+ isLowerCaseLetter (PNAME opOf result).0 =>
+ $opStack := [[['ATTRIBUTE,result],:$predlist],:$opStack]
+ $conStack := [[result,:$predlist],:$conStack]
+
+asyTypeMapping([a,b]) ==
+ a := asyTypeUnit a
+ b := asyTypeUnit b
+ args :=
+ a is [op,:r] and asyComma? op => r
+ [a]
+ ['Mapping,b,:args]
+
+asyTypeUnit x ==
+ x is [fn,:r] =>
+ fn = 'Join => systemError 'Join ----->asyTypeJoin r
+ MEMQ(fn, '(RestrictTo PretendTo)) => asyTypeUnit first r
+ asyComma? fn =>
+ u := [asyTypeUnit x for x in r]
+ u
+ fn = 'With => asyCATEGORY r
+ fn = '_-_> => asyTypeMapping r
+ fn = 'Apply => asyTypeUnitList r
+ fn = 'Declare and r is [name,typ,:.] => asyTypeUnitDeclare(name,typ)
+ x is '(_%) => '(_$)
+ [fn,:asyTypeUnitList r]
+ GETL(x,'NILADIC) => [x]
+--x = 'Type => '(Type)
+ x = '_% => '_$
+ x
+
+asyTypeUnitList x == [asyTypeUnit y for y in x]
+
+asyTypeUnitDeclare(op,typ) ==
+ typ is ['Apply, :r] => asyCatSignature(op,r)
+ asyTypeUnit typ
+--============================================================================
+-- Translator for ['With,:.]
+--============================================================================
+asyCATEGORY x ==
+ if x is [join,:y] and join is ['Apply,:s] then
+ exports := y
+ joins :=
+ s is ['Join,:r] => [asyJoinPart u for u in r]
+ [asyJoinPart s]
+ else if x is [id,:y] and IDENTP id then
+ joins := [[id]]
+ exports := y
+ else
+ joins := nil
+ exports := x
+ cats := exports
+ operations := nil
+ if exports is [:r,['Exports,:ops]] then
+ cats := r
+ operations := ops
+ exportPart :=
+ ['CATEGORY,'domain,:"APPEND"/[asyCatItem y for y in operations]]
+ [attribs, na] := asyFindAttrs joins
+ joins := na
+ cats := "append"/[asyCattran c for c in cats]
+ [a, na] := asyFindAttrs cats
+ cats := na
+ attribs := APPEND(attribs, a)
+ attribs := [['ATTRIBUTE, x] for x in attribs]
+ exportPart := [:exportPart,:attribs]
+ joins or cats or attribs =>
+ ['Join,:joins,:cats, exportPart]
+ exportPart
+
+asyFindAttrs l ==
+ attrs := []
+ notattrs := []
+ for x in l repeat
+ x0 := x
+ while CONSP x repeat x := CAR x
+ if MEMQ(x, _*ATTRIBUTES_*) then attrs := [:attrs, x]
+ else notattrs := [:notattrs, x0]
+ [attrs, notattrs]
+
+simpCattran x ==
+ u := asyCattran x
+ u is [y] => y
+ ['Join,:u]
+
+asyCattran x ==
+ x is ['With,:r] => "append"/[asyCattran1 x for x in r]
+ x is ['IF,:.] => "append"/[asyCattranConstructors(x,nil)]
+ [x]
+
+asyCattran1 x ==
+ x is ['Exports,:y] => "append"/[asyCattranOp u for u in y]
+ x is ['IF,:.] => "append"/[asyCattranConstructors(x,nil)]
+ systemError nil
+
+asyCattranOp [op,:items] ==
+ "append"/[asyCattranOp1(op,item,nil) for item in items]
+
+asyCattranOp1(op, item, predlist) ==
+ item is ['IF, p, x] =>
+ pred := asyPredTran
+ p is ['Test,t] => t
+ p
+-- x is ['IF,:.] => "append"/[asyCattranOp1('IF, x, [pred,:predlist])]
+-- This line used to call asyCattranOp1 with too few arguments. Following
+-- fix suggested by RDJ.
+ x is ['IF,:.] => "append"/[asyCattranOp1(op,y,[pred,:predlist]) for y in x]
+ [['IF, asySimpPred(pred,predlist), asyCattranSig(op,x), 'noBranch]]
+ [asyCattranSig(op,item)]
+
+asyPredTran p == asyPredTran1 asyJoinPart p
+
+asyPredTran1 p ==
+ p is ['Has,x,y] => ['has,x, simpCattran y]
+ p is ['Test, q] => asyPredTran1 q
+ p is [op,:r] and MEMQ(op,'(AND OR NOT)) =>
+ [op,:[asyPredTran1 q for q in r]]
+ p
+
+asyCattranConstructors(item, predlist) ==
+ item is ['IF, p, x] =>
+ pred := asyPredTran
+ p is ['Test,t] => t
+ p
+ x is ['IF,:.] => "append"/[asyCattranConstructors(x, [pred,:predlist])]
+ form := ['ATTRIBUTE, asyJoinPart x]
+ [['IF, asySimpPred(pred,predlist), form, 'noBranch]]
+ systemError()
+
+asySimpPred(p, predlist) ==
+ while predlist is [q,:predlist] repeat p := quickAnd(q,p)
+ p
+
+asyCattranSig(op,y) ==
+ y isnt ["->",source,t] =>
+-- ['SIGNATURE, op, asyTypeUnit y]
+-- following makes constants into nullary functions
+ ['SIGNATURE, op, [asyTypeUnit y]]
+ s :=
+ source is ['Comma,:s] => [asyTypeUnit z for z in s]
+ [asyTypeUnit source]
+ t := asyTypeUnit t
+ null t => ['SIGNATURE,op,s]
+ ['SIGNATURE,op,[t,:s]]
+
+asyJoinPart x ==
+ IDENTP x => [x]
+ asytranForm(x,nil,true)
+
+asyCatItem item ==
+ atom item => [item]
+ item is ['IF,.,.] => [item]
+ [op,:sigs] := item
+ [asyCatSignature(op,sig) for sig in sigs | sig]
+
+asyCatSignature(op,sig) ==
+ sig is ['_-_>,source,target] =>
+ ['SIGNATURE,op, [asyTypeItem target,:asyUnTuple source]]
+ ----------> Constants change <--------------
+-- ['TYPE,op,asyTypeItem sig]
+-- following line converts constants into nullary functions
+ ['SIGNATURE,op,[asyTypeItem sig]]
+
+asyUnTuple x ==
+ x is [op,:u] and asyComma? op => [asyTypeItem y for y in u]
+ [asyTypeItem x]
+
+asyTypeItem x ==
+ atom x =>
+ x = '_% => '_$
+ x
+ x is ['_-_>,a,b] =>
+ ['Mapping,b,:asyUnTuple a]
+ x is ['Apply,:r] =>
+ r is ['_-_>,a,b] =>
+ ['Mapping,b,:asyUnTuple a]
+ r is ['Record,:parts] =>
+ ['Record,:[[":",a,b] for ['Declare,a,b,:.] in parts]]
+ r is ['Segment,:parts] =>
+ ['Segment,:[asyTypeItem x for x in parts]]
+ asytranApply(x,nil,true)
+ x is ['Declare,.,t,:.] => asyTypeItem t
+ x is ['Comma,:args] =>
+ -- this implies a multiple value return, not currently supported
+ -- in the interpreter
+ args => ['Multi,:[asyTypeItem y for y in args]]
+ ['Void]
+ [asyTypeItem y for y in x]
+
+--============================================================================
+-- Utilities
+--============================================================================
+asyComma? op == MEMQ(op,'(Comma Multi))
+
+
+hput(table,name,value) ==
+ if null name then systemError()
+ HPUT(table,name,value)
+
+--============================================================================
+-- category parts
+--============================================================================
+
+-- this constructs operation information from a category.
+-- NB: This is categoryParts, but with the kind supplied by
+-- an arguments
+asCategoryParts(kind,conform,category,:options) == main where
+ main() ==
+ cons? := IFCAR options --means to include constructors as well
+ $attrlist: local := nil
+ $oplist : local := nil
+ $conslist: local := nil
+ conname := opOf conform
+ for x in exportsOf(category) repeat build(x,true)
+ $attrlist := listSort(function GLESSEQP,$attrlist)
+ $oplist := listSort(function GLESSEQP,$oplist)
+ res := [$attrlist,:$oplist]
+ if cons? then res := [listSort(function GLESSEQP,$conslist),:res]
+ if kind = 'category then
+ tvl := TAKE(#rest conform,$TriangleVariableList)
+ res := SUBLISLIS($FormalMapVariableList,tvl,res)
+ res
+ where
+ build(item,pred) ==
+ item is ['SIGNATURE,op,sig,:.] => $oplist := [[opOf op,sig,:pred],:$oplist]
+ --note: opOf is needed!!! Bug in compiler puts in (One) and (Zero)
+ item is ['ATTRIBUTE,attr] =>
+ constructor? opOf attr =>
+ $conslist := [[attr,:pred],:$conslist]
+ nil
+ opOf attr = 'nothing => 'skip
+ $attrlist := [[opOf attr,IFCDR attr,:pred],:$attrlist]
+ item is ['TYPE,op,type] =>
+ $oplist := [[op,[type],:pred],:$oplist]
+ item is ['IF,pred1,s1,s2] =>
+ build(s1,quickAnd(pred,pred1))
+ s2 => build(s2,quickAnd(pred,['NOT,pred1]))
+ item is ['PROGN,:r] => for x in r repeat build(x,pred)
+ item in '(noBranch) => 'ok
+ null item => 'ok
+ systemError '"build error"
+ exportsOf(target) ==
+ target is ['CATEGORY,.,:r] => r
+ target is ['Join,:r,f] =>
+ for x in r repeat $conslist := [[x,:true],:$conslist]
+ exportsOf f
+ $conslist := [[target,:true],:$conslist]
+ nil
+
+--============================================================================
+-- Dead Code (for a very odd value of 'dead')
+--============================================================================
+asyTypeJoinPartExport x ==
+ [op,:items] := x
+ for y in items repeat
+ y isnt ["->",source,t] =>
+-- sig := ['TYPE, op, asyTypeUnit y]
+-- converts constants to nullary functions (this code isn't dead)
+ sig := ['SIGNATURE, op, [asyTypeUnit y]]
+ $opStack := [[sig,:$predlist],:$opStack]
+ s :=
+ source is ['Comma,:s] => [asyTypeUnit z for z in s]
+ [asyTypeUnit source]
+ t := asyTypeUnit t
+ sig :=
+ null t => ['SIGNATURE,op,s]
+ ['SIGNATURE,op,[t,:s]]
+ $opStack := [[sig,:$predlist],:$opStack]
+
+--============================================================================
+-- Code to create opDead Code
+--============================================================================
+asyTypeJoinStack r ==
+ al := [[[x while r is [[x, :q],:s] and p = q and (r := s; true)],:p]
+ while r is [[.,:p],:.]]
+ result := "append"/[fn for [y,:p] in al] where fn() ==
+ p => [['IF,asyTypeMakePred p,:y]]
+ y
+ result
+
+asyTypeMakePred [p,:u] ==
+ while u is [q,:u] repeat p := quickAnd(q,p)
+ p
+
+
+
+