aboutsummaryrefslogtreecommitdiff
path: root/src/interp/pf2atree.boot.pamphlet
diff options
context:
space:
mode:
Diffstat (limited to 'src/interp/pf2atree.boot.pamphlet')
-rw-r--r--src/interp/pf2atree.boot.pamphlet575
1 files changed, 575 insertions, 0 deletions
diff --git a/src/interp/pf2atree.boot.pamphlet b/src/interp/pf2atree.boot.pamphlet
new file mode 100644
index 00000000..29e85ad1
--- /dev/null
+++ b/src/interp/pf2atree.boot.pamphlet
@@ -0,0 +1,575 @@
+\documentclass{article}
+\usepackage{axiom}
+\begin{document}
+\title{\$SPAD/src/interp pf2atree.boot}
+\author{The Axiom Team}
+\maketitle
+\begin{abstract}
+\end{abstract}
+\eject
+\tableofcontents
+\eject
+\section{License}
+<<license>>=
+-- Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+-- 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.
+
+@
+<<*>>=
+<<license>>
+
+-- not hooked in yet
+
+-- BB parser tree to interpreter vectorized attributed trees.
+-- Used to interface the BB parser
+-- technology to the interpreter. The input is a parseTree and the
+-- output is an interpreter attributed tree.
+
+SETANDFILEQ($useParserSrcPos, true)
+SETANDFILEQ($transferParserSrcPos, true)
+
+pf2Sexpr pf == packageTran (pf2Sex1)(pf)
+
+pf2Atree pf ==
+ (intUnsetQuiet)()
+
+ $insideRule: local := false
+ $insideApplication: local := false
+ $insideSEQ: local := false
+
+ -- we set the following because we will be using some things
+ -- within pf2sex.boot and they are in the spadcomp package.
+
+ ($insideRule): local := false
+ ($insideApplication): local := false
+ ($insideSEQ): local := false
+
+ pf2Atree1 pf
+
+pf2Atree1 pf ==
+ -- some simple things that are really just S-expressions
+
+ (pfNothing?)(pf) =>
+ mkAtree1WithSrcPos(pf2Sexpr(pf), pf)
+ (pfSymbol?) pf =>
+ mkAtree1WithSrcPos(pf2Sexpr(pf), pf)
+ (pfLiteral?)(pf) =>
+ mkAtree1WithSrcPos(pf2Sexpr(pf), pf)
+ (pfId?) pf =>
+ mkAtree1WithSrcPos(pf2Sexpr(pf), pf)
+
+ -- Now some compound forms
+
+ (pfApplication?)(pf) =>
+ pfApplication2Atree pf
+
+ (pfTuple?)(pf) =>
+ [mkAtreeNodeWithSrcPos("Tuple",pf),
+ :[pf2Atree1 x for x in (pf0TupleParts)(pf)]]
+
+ (pfIf?)(pf) =>
+ condPf := (pfIfCond)(pf)
+ condPart := pf2Atree1 condPf
+ thenPart := pf2Atree1 (pfIfThen)(pf)
+ elsePart := pf2Atree1 (pfIfElse)(pf)
+ ifPart := mkAtreeNodeWithSrcPos("IF", pf)
+ thenPart = "noBranch" =>
+ [ifPart, [mkAtreeNodeWithSrcPos("not", condPf), condPart],
+ elsePart, thenPart]
+ [ifPart, condPart, thenPart, elsePart]
+
+ (pfTagged?)(pf) =>
+ tag := (pfTaggedTag)(pf)
+ tagPart :=
+ (pfTuple?) tag =>
+ ["Tuple", :[pf2Sexpr(arg) for arg in (pf0TupleParts)(tag)]]
+ pf2Sexpr(tag)
+ [mkAtreeNodeWithSrcPos("Declare",pf), tagPart,
+ pf2Sexpr((pfTaggedExpr)(pf))]
+
+ (pfCoerceto?)(pf) =>
+ [mkAtreeNodeWithSrcPos("COERCE",pf),
+ pf2Atree1 (pfCoercetoExpr)(pf),
+ pf2Sexpr((pfCoercetoType)(pf))]
+
+ (pfPretend?)(pf) =>
+ [mkAtreeNodeWithSrcPos("pretend",pf),
+ pf2Atree1 (pfPretendExpr)(pf),
+ pf2Sexpr((pfPretendType)(pf))]
+
+ (pfFromdom?)(pf) =>
+ op := packageTran (opTran)(pf2Sexpr((pfFromdomWhat)(pf)))
+ if op = "braceFromCurly" then op := "SEQ" -- ??
+
+ op = 0 =>
+ -- 0$Foo => Zero()$Foo
+ [mkAtreeNodeWithSrcPos("Dollar",pf),
+ pf2Sexpr((pfFromdomDomain)(pf)),
+ [mkAtreeNodeWithSrcPos("Zero",pf)]]
+ op = 1 =>
+ -- 1$Foo => One()$Foo
+ [mkAtreeNodeWithSrcPos("Dollar",pf),
+ pf2Sexpr((pfFromdomDomain)(pf)),
+ [mkAtreeNodeWithSrcPos("One",pf)]]
+ INTEGERP op =>
+ -- n$Foo => n * One()$Foo
+ [mkAtreeNodeWithSrcPos("*",pf),
+ mkAtree1WithSrcPos(op,pf),
+ [mkAtreeNodeWithSrcPos("Dollar",pf),
+ pf2Sexpr((pfFromdomDomain)(pf)),
+ [mkAtreeNodeWithSrcPos("One",pf)]]]
+
+ [mkAtreeNodeWithSrcPos("Dollar",pf),
+ pf2Sexpr((pfFromdomDomain)(pf)),
+ mkAtreeNodeWithSrcPos(op,pf)]
+
+ (pfSequence?)(pf) =>
+ pfSequence2Atree pf
+
+ (pfExit?)(pf) =>
+ $insideSEQ =>
+ [mkAtreeNodeWithSrcPos("exit",pf),
+ pf2Atree1 (pfExitCond)(pf),
+ pf2Atree1 (pfExitExpr)(pf)]
+ [mkAtreeNodeWithSrcPos("IF",pf),
+ pf2Atree1 (pfExitCond)(pf),
+ pf2Atree1 (pfExitExpr)(pf), "noBranch"]
+
+ (pfLoop?)(pf) =>
+ [mkAtreeNodeWithSrcPos("REPEAT",pf),
+ :loopIters2Atree (pf0LoopIterators)(pf)]
+
+ (pfCollect?)(pf) =>
+ pfCollect2Atree(pf)
+
+ (pfForin?)(pf) =>
+ ["IN", :[pf2Atree1 x for x in (pf0ForinLhs)(pf)],
+ pf2Atree1 (pfForinWhole)(pf)]
+
+ (pfWhile?)(pf) =>
+ ["WHILE", pf2Atree1((pfWhileCond)(pf))]
+
+ (pfSuchthat?)(pf) =>
+ $insideRule = 'left =>
+ keyedSystemError('"S2GE0017", ['"pf2Atree1: pfSuchThat"])
+ ["SUCHTHAT", pf2Atree1 (pfSuchthatCond)(pf)]
+
+ (pfDo?)(pf) =>
+ pf2Atree1 (pfDoBody)(pf)
+
+-- (pfTyped?)(pf) =>
+-- type := pfTypedType pf
+-- pfNothing? type => pf2Atree1 pfTypedId pf
+-- [":", pf2Atree1 pfTypedId pf, pf2Atree1 pfTypedType pf]
+
+ (pfAssign?)(pf) =>
+ -- declarations on the lhs are broken out into another
+ -- statement preceding the LET of the id(s)
+ lhsThings := (pf0AssignLhsItems)(pf)
+ if #lhsThings = 1 and (pfTuple?)(first lhsThings) then
+ lhsThings := (pf0TupleParts)(first lhsThings)
+ decls := nil
+ ids := nil
+ for x in lhsThings repeat
+ (pfTagged?)(x) =>
+ decls := [x, :decls]
+ ids := [(pfTaggedTag)(x), :ids]
+ ids := [x, :ids]
+ idList := [pf2Atree1 x for x in reverse ids]
+ if #idList ^= 1 then idList :=
+ [mkAtreeNodeWithSrcPos("Tuple",pf), :idList]
+ else idList := first idList
+ x := [mkAtreeNodeWithSrcPos("LET",pf),
+ idList, pf2Atree1 (pfAssignRhs)(pf)]
+ decls =>
+ [mkAtreeNodeWithSrcPos("SEQ",pf),
+ :[pf2Atree1 decl for decl in nreverse decls], x]
+ x
+
+-- (pfDefinition?)(pf) =>
+-- pfDefinition2Atree pf
+
+-- (pfLambda?)(pf) =>
+-- pfLambda2Atree pf
+-- (pfRestrict?)(pf) =>
+-- ["@", pf2Atree1 pfRestrictExpr pf, pf2Atree1 pfRestrictType pf]
+
+ (pfFree?)(pf) =>
+ [mkAtreeNodeWithSrcPos("free",pf),
+ :[pf2Atree1 item for item in (pf0FreeItems)(pf)]]
+ (pfLocal?)(pf) =>
+ [mkAtreeNodeWithSrcPos("local",pf),
+ :[pf2Atree1 item for item in (pf0LocalItems)(pf)]]
+
+ (pfWrong?)(pf) =>
+ spadThrow()
+
+ -- next 3 are probably be handled in pfApplication2Atree
+
+ (pfAnd?)(pf) =>
+ [mkAtreeNodeWithSrcPos("and",pf),
+ pf2Atree1 (pfAndLeft)(pf),
+ pf2Atree1 (pfAndRight)(pf)]
+ (pfOr?)(pf) =>
+ [mkAtreeNodeWithSrcPos("or",pf),
+ pf2Atree1 (pfOrLeft)(pf),
+ pf2Atree1 (pfOrRight)(pf)]
+ (pfNot?)(pf) =>
+ [mkAtreeNodeWithSrcPos("not",pf),
+ pf2Atree1 (pfNotArg)(pf)]
+
+-- (pfNovalue?)(pf) =>
+-- intSetQuiet()
+-- ["SEQ", pf2Atree1 pfNovalueExpr pf]
+-- (pfRule?)(pf) =>
+-- pfRule2Atree pf
+
+ (pfBreak?)(pf) =>
+ [mkAtreeNodeWithSrcPos("break",pf), (pfBreakFrom)(pf)]
+
+ (pfMacro?)(pf) =>
+ tree := mkAtree1WithSrcPos('(void), pf)
+ putValue(tree,objNewWrap(voidValue(),$Void))
+ putModeSet(tree,[$Void])
+ tree
+
+ (pfReturn?)(pf) =>
+ [mkAtreeNodeWithSrcPos("return",pf),
+ pf2Atree1 (pfReturnExpr)(pf)]
+
+ (pfIterate?)(pf) =>
+ [mkAtreeNodeWithSrcPos("iterate",pf)]
+
+-- (pfWhere?)(pf) =>
+-- args := [pf2Atree1 p for p in pf0WhereContext pf]
+-- #args = 1 =>
+-- ["where", pf2Atree1 pfWhereExpr pf, :args]
+-- ["where", pf2Atree1 pfWhereExpr pf, ["SEQ", :args]]
+
+ mkAtree1WithSrcPos(pf2Sexpr(pf), pf)
+
+-- keyedSystemError('"S2GE0017", ['"pf2Atree1"])
+--
+
+pfApplication2Atree pf ==
+ $insideApplication: local := true
+ ($insideApplication): local := true
+
+ opPf := (pfApplicationOp)(pf)
+ op := packageTran ((opTran)(pfOp2Sex)(opPf))
+ op = "->" =>
+ args := (pf0TupleParts)((pfApplicationArg)(pf))
+ if (pfTuple?)(CAR args) then
+ typeList := [pf2Atree1 arg for arg in (pf0TupleParts)(CAR args)]
+ else
+ typeList := [pf2Atree1 CAR args]
+ args := [pf2Atree1 CADR args, :typeList]
+ [mkAtreeNodeWithSrcPos("Mapping", opPf), :args]
+
+ (symEqual)(op, '":") and $insideRule = 'left =>
+ [mkAtreeNodeWithSrcPos("multiple",opPf),
+ pf2Atree (pfApplicationArg)(pf)]
+
+ (symEqual)(op, '"?") and $insideRule = 'left =>
+ [mkAtreeNodeWithSrcPos("optional",opPf),
+ pf2Atree (pfApplicationArg)(pf)]
+
+ args := (pfApplicationArg)(pf)
+
+ (pfTuple?)(args) =>
+--! symEqual(op, '"|") and $insideRule = 'left =>
+--! pfSuchThat2Atree args
+ argAtree := [pf2Atree1 arg for arg in (pf0TupleParts)(args)]
+
+ (symEqual)(op, '">") =>
+ [mkAtreeNodeWithSrcPos("<",opPf), :reverse(argAtree)]
+ (symEqual)(op, '">=") =>
+ [mkAtreeNodeWithSrcPos("not",opPf),
+ [mkAtreeNodeWithSrcPos("<",opPf), :argAtree]]
+ (symEqual)(op, '"<=") =>
+ [mkAtreeNodeWithSrcPos("not",opPf),
+ [mkAtreeNodeWithSrcPos("<",opPf), :reverse(argAtree)]]
+ (symEqual)(op, '"AND") =>
+ [mkAtreeNodeWithSrcPos("and",opPf), :argAtree]
+ (symEqual)(op, '"OR") =>
+ [mkAtreeNodeWithSrcPos("or",opPf), :argAtree]
+ (symEqual) (op, '"Iterate") =>
+ [mkAtreeNodeWithSrcPos("iterate",opPf)]
+ (symEqual)(op, '"by") =>
+ [mkAtreeNodeWithSrcPos("BY",opPf), :argAtree]
+ (symEqual)(op, '"braceFromCurly") =>
+ argAtree and getUnname first argAtree = "SEQ" => argAtree
+ [mkAtreeNodeWithSrcPos("SEQ",opPf), :argAtree]
+ op is [qt, realOp] and (symEqual)(qt, '"QUOTE") =>
+ [mkAtreeNodeWithSrcPos("applyQuote",opPf),
+ mkAtreeNodeWithSrcPos(op,opPf), :argAtree]
+--! val := (hasOptArgs?)(argSex) => [op, :val]
+ -- handle package call
+ (pfFromdom?)(opPf) =>
+ opAtree := pf2Atree1 opPf
+ [CAR opAtree, CADR opAtree, [CADDR opAtree, :argAtree]]
+ -- regular call
+ [mkAtreeNodeWithSrcPos(op,opPf), :argAtree]
+
+ op is [qt, realOp] and (symEqual)(qt, '"QUOTE") =>
+ [mkAtreeNodeWithSrcPos("applyQuote",opPf),
+ mkAtreeNodeWithSrcPos(op,opPf), pf2Atree1 args]
+ (symEqual)(op, '"braceFromCurly") =>
+ x := pf2Atree1 args
+ x and getUnname x = "SEQ" => x
+ [mkAtreeNodeWithSrcPos("SEQ",opPf), x]
+ (symEqual)(op, '"by") =>
+ [mkAtreeNodeWithSrcPos("BY",opPf), pf2Atree1 args]
+ -- handle package call
+ (pfFromdom?)(opPf) =>
+ opAtree := pf2Atree1 opPf
+ [CAR opAtree, CADR opAtree, [CADDR opAtree, pf2Atree1 args]]
+ -- regular call
+ [mkAtreeNodeWithSrcPos(op,opPf), pf2Atree1 args]
+
+-- pfDefinition2Atree pf ==
+-- --! $insideApplication =>
+-- --! ["OPTARG", pf2Atree1 CAR pf0DefinitionLhsItems pf,
+-- --! pf2Atree1 pfDefinitionRhs pf]
+-- idList := [pf2Atree1 x for x in (pf0DefinitionLhsItems)(pf)]
+-- #idList ^= 1 =>
+-- systemError '"lhs of definition must be a single item in the interpreter"
+-- id := first idList
+-- rhs := (pfDefinitionRhs)(pf)
+-- [argList, :body] := pfLambdaTran rhs
+-- ["DEF", (argList = 'id => id; [id, :argList]), :body]
+
+-- pfLambdaTran pf ==
+-- pfLambda? pf =>
+-- argTypeList := nil
+-- argList := nil
+-- for arg in pf0LambdaArgs pf repeat
+-- pfTyped? arg =>
+-- argList := [pfCollectArgTran pfTypedId arg, :argList]
+-- pfNothing? pfTypedType arg =>
+-- argTypeList := [nil, :argTypeList]
+-- argTypeList := [pf2Atree1 pfTypedType arg, :argTypeList]
+-- systemError '"definition args should be typed"
+-- argList := nreverse argList
+-- retType :=
+-- pfNothing? pfLambdaRets pf => nil
+-- pf2Atree1 pfLambdaRets pf
+-- argTypeList := [retType, :nreverse argTypeList]
+-- [argList, :[argTypeList, [nil for arg in argTypeList],
+-- pf2Atree1 pfLambdaBody pf]]
+-- ['id, :['(()), '(()), pf2Atree1 pf]]
+--
+-- pfLambda2Atree pf ==
+-- [argList, :body] := pfLambdaTran pf
+-- ["ADEF", argList, :body]
+--
+-- pfCollectArgTran pf ==
+-- pfCollect? pf =>
+-- conds := [pf2Atree1 x for x in pfParts pfCollectIterators pf]
+-- id := pf2Atree1 pfCollectBody pf
+-- conds is [["|", cond]] =>
+-- ["|", id, cond]
+-- [id, :conds]
+-- pf2Atree1 pf
+--
+
+pfSequence2Atree pf ==
+ $insideSEQ: local := true
+ ($insideSEQ): local := true
+
+ seq := pfSequence2Atree0([pf2Atree1 x for x in (pf0SequenceArgs)(pf)], pf)
+ seqSex := (pfSequence2Sex0)([pf2Sexpr(x) for x in (pf0SequenceArgs)(pf)])
+ seqSex is ["SEQ", :ruleList] and ruleList is [["rule", :.], :.] =>
+ [mkAtreeNodeWithSrcPos("ruleset",pf),
+ [mkAtreeNodeWithSrcPos("construct",pf), :rest seq]]
+ seq
+
+pfSequence2Atree0(seqList, pf) ==
+ null seqList => "noBranch"
+ seqTranList := []
+ while seqList ^= nil repeat
+ item := first seqList
+ item is [exitVal, cond, value] and getUnname(exitVal) = "exit" =>
+ item := [mkAtreeNodeWithSrcPos("IF",pf), cond, value,
+ pfSequence2Atree0(rest seqList, pf)]
+ seqTranList := [item, :seqTranList]
+ seqList := nil
+ seqTranList := [item ,:seqTranList]
+ seqList := rest seqList
+ #seqTranList = 1 => first seqTranList
+ [mkAtreeNodeWithSrcPos("SEQ",pf), :nreverse seqTranList]
+
+--
+-- float2Atree num ==
+-- eIndex := SEARCH('"e", num)
+-- mantPart :=
+-- eIndex => SUBSEQ(num, 0, eIndex)
+-- num
+-- expPart := (eIndex => READ_-FROM_-STRING SUBSEQ(num, eIndex+1); 0)
+-- dotIndex := SEARCH('".", mantPart)
+-- intPart :=
+-- dotIndex => READ_-FROM_-STRING SUBSEQ(mantPart, 0, dotIndex)
+-- READ_-FROM_-STRING mantPart
+-- fracPartString :=
+-- dotIndex => SUBSEQ(mantPart, dotIndex+1)
+-- '"0"
+-- bfForm := MAKE_-FLOAT(intPart, READ_-FROM_-STRING fracPartString,
+-- LENGTH fracPartString, expPart)
+-- [., frac, :exp] := bfForm
+-- [["$elt", intNewFloat(), 'float], frac, exp, 10]
+--
+
+loopIters2Atree iterList ==
+ -- could probably do a better job of getting accurate SrcPos info onto parts
+ result := nil
+ for iter in iterList repeat
+ -- ON and UNTIL forms are no longer supported
+ sex := pf2Sexpr(iter)
+ sex is ['IN, var, ['SEGMENT, i, ["BY", incr]]] =>
+ newIter := ["STEP", var, mkAtree1WithSrcPos(i,iter),
+ mkAtree1WithSrcPos(incr, iter)]
+ result := [newIter, :result]
+ sex is ['IN, var, ["BY", ['SEGMENT, i, j], incr]] =>
+ newIter := ["STEP", var, mkAtree1WithSrcPos(i,iter),
+ mkAtree1WithSrcPos(incr, iter), mkAtree1WithSrcPos(j,iter)]
+ result := [newIter, :result]
+ sex is ['IN, var, ['SEGMENT, i, j]] =>
+ newIter := ["STEP", var, mkAtree1WithSrcPos(i,iter),
+ mkAtree1WithSrcPos(1,iter), mkAtree1WithSrcPos(j,iter)]
+ result := [newIter, :result]
+ sex is ['IN, var, s] =>
+ newIter := ["IN", var, mkAtree1 s]
+ result := [newIter, :result]
+ result := [pf2Atree1(iter), :result]
+ nreverse result
+
+pfCollect2Atree pf ==
+ atree := [mkAtree1WithSrcPos("COLLECT",pf),
+ :loopIters2Atree (pfParts)((pfCollectIterators)(pf)),
+ pf2Atree1 (pfCollectBody)(pf)]
+
+ -- next are for what appears to a parser screw-up
+ sex := ["COLLECT",
+ :(loopIters2Sex)((pfParts)((pfCollectIterators)(pf))),
+ pf2Sexpr (pfCollectBody)(pf)]
+ sex is ["COLLECT", ["|", cond], var] and SYMBOLP var =>
+ [., [., condAtree], varAtree] := atree
+ ["SUCHTHAT", varAtree, condAtree]
+
+ atree
+
+--
+-- pfRule2Atree pf ==
+-- $quotedOpList:local := nil
+-- $predicateList:local := nil
+-- $multiVarPredicateList:local := nil
+-- lhs := pfLhsRule2Atree pfRuleLhsItems pf
+-- rhs := pfRhsRule2Atree pfRuleRhs pf
+-- lhs := ruleLhsTran lhs
+-- rulePredicateTran
+-- $quotedOpList => ["rule", lhs, rhs, ["construct", :$quotedOpList]]
+-- ["rule", lhs, rhs]
+--
+--
+-- ruleLhsTran ruleLhs ==
+-- for pred in $predicateList repeat
+-- [name, predLhs, :predRhs] := pred
+-- vars := patternVarsOf predRhs
+-- CDR vars => -- if there is more than one patternVariable
+-- ruleLhs := NSUBST(predLhs, name, ruleLhs)
+-- $multiVarPredicateList := [pred, :$multiVarPredicateList]
+-- predicate :=
+-- [., var] := predLhs
+-- ["suchThat", predLhs, ["ADEF", [var],
+-- '((Boolean) (Expression (Integer))), '(() ()), predRhs]]
+-- ruleLhs := NSUBST(predicate, name, ruleLhs)
+-- ruleLhs
+--
+-- rulePredicateTran rule ==
+-- null $multiVarPredicateList => rule
+-- varList := patternVarsOf [rhs for [.,.,:rhs] in $multiVarPredicateList]
+-- predBody :=
+-- CDR $multiVarPredicateList =>
+-- ['AND, :[:pvarPredTran(rhs, varList) for [.,.,:rhs] in
+-- $multiVarPredicateList]]
+-- [[.,.,:rhs],:.] := $multiVarPredicateList
+-- pvarPredTran(rhs, varList)
+-- ['suchThat, rule,
+-- ['construct, :[["QUOTE", var] for var in varList]],
+-- ['ADEF, '(predicateVariable),
+-- '((Boolean) (List (Expression (Integer)))), '(() ()),
+-- predBody]]
+--
+-- pvarPredTran(rhs, varList) ==
+-- for var in varList for i in 1.. repeat
+-- rhs := NSUBST(['elt, 'predicateVariable, i], var, rhs)
+-- rhs
+--
+-- patternVarsOf expr ==
+-- patternVarsOf1(expr, nil)
+--
+-- patternVarsOf1(expr, varList) ==
+-- NULL expr => varList
+-- ATOM expr =>
+-- null SYMBOLP expr => varList
+-- SymMemQ(expr, varList) => varList
+-- [expr, :varList]
+-- expr is [op, :argl] =>
+-- for arg in argl repeat
+-- varList := patternVarsOf1(arg, varList)
+-- varList
+-- varList
+--
+-- pfLhsRule2Atree lhs ==
+-- $insideRule: local := 'left
+-- ($insideRule): local := 'left
+-- pf2Atree1 lhs
+--
+--
+-- pfRhsRule2Atree rhs ==
+-- $insideRule: local := 'right
+-- ($insideRule): local := 'right
+-- pf2Atree1 rhs
+--
+
+-- pfSuchThat2Atree args ==
+-- name := GENTEMP()
+-- argList := pf0TupleParts args
+-- lhsSex := pf2Atree1 CAR argList
+-- rhsSex := pf2Atree CADR argList
+-- $predicateList := [[name, lhsSex, :rhsSex], :$predicateList]
+-- name
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}