<> <> <> DIRECTORY MathDisplayExpr, MathExpr, MathBox, MathConstructors, MathDB, MathTypes, MathRules, Convert USING [RopeFromAtom], Rope USING [ROPE, Length, Find, Replace, Cat], Imager USING [Context, black, SetColor, MaskRectangle], XRope; MathDisplayExprImpl: CEDAR PROGRAM IMPORTS MathBox, MathExpr, MathDB, MathConstructors, Imager, MathRules, Rope, Convert, XRope EXPORTS MathDisplayExpr ~ BEGIN <> <<>> ROPE: TYPE ~ Rope.ROPE; BOX: TYPE ~ MathBox.BOX; EXPR: TYPE ~ MathExpr.EXPR; AtomEXPR: TYPE ~ MathExpr.AtomEXPR; CompoundEXPR: TYPE ~ MathExpr.CompoundEXPR; MatrixEXPR: TYPE ~ MathExpr.MatrixEXPR; Style: TYPE ~ MathTypes.Style; Argument: TYPE ~ MathExpr.Argument; Symbol: TYPE ~ MathExpr.Symbol; AtomClass: TYPE ~ MathExpr.AtomClass; AtomFlavor: TYPE ~ MathExpr.AtomFlavor; CompoundClass: TYPE ~ MathExpr.CompoundClass; MatrixClass: TYPE ~ MathExpr.MatrixClass; Size: TYPE ~ MathRules.Size; Selection: TYPE ~ MathDisplayExpr.Selection; ReplacePair: TYPE ~ MathDisplayExpr.ReplacePair; <> <> DisplayExprRep: PUBLIC TYPE ~ RECORD [ tag: ATOM, -- identifying tag such as $integrand expression: DisplayObj, -- atom, compound expr, or matrix relativeBox: BOX, -- bounding box in relative units absoluteBox: BOX, -- bounding box in absolute units iconic: BOOL _ FALSE, -- TRUE iff expression is currently iconic (2/87apparentlyUnused) parent: DisplayExpr _ NIL -- enclosing parent expression ]; DisplayObj: TYPE ~ REF DisplayObjRep; DisplayObjRep: TYPE ~ RECORD [ SELECT type:* FROM atom => [class: AtomClass, value: ROPE], compound => [class: CompoundClass, subExprs: LIST OF DisplayExpr _ NIL], matrix => [ class: MatrixClass, -- type of matrix op, e.g. matrix, vector, determinant, etc. nRows, nCols: INT, -- matrix size, rows x cols elements: LIST OF DisplayExpr _ NIL, -- matrix elements openSym: DisplayExpr, -- left bracket closeSym: DisplayExpr, -- right bracket space: DisplayExpr -- inter-element spacing ] ENDCASE ]; <> AtomDisplayObj: TYPE ~ REF AtomDisplayObjRep; AtomDisplayObjRep: TYPE ~ atom DisplayObjRep; CompoundDisplayObj: TYPE ~ REF CompoundDisplayObjRep; CompoundDisplayObjRep: TYPE ~ compound DisplayObjRep; MatrixDisplayObj: TYPE ~ REF MatrixDisplayObjRep; MatrixDisplayObjRep: TYPE ~ matrix DisplayObjRep; DisplayExpr: TYPE ~ REF DisplayExprRep; -- inside impl module, use rep <> MakeAtomicDisplayExpr: PUBLIC PROC[tag: ATOM, class: AtomClass, value: ROPE, relBox, absBox: BOX, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { <> RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[AtomDisplayObjRep _ [atom[class: class, value: value]]]]]]; }; MakeCompoundDisplayExpr: PUBLIC PROC[tag: ATOM, class: CompoundClass, subExprs: LIST OF DisplayExpr, relBox, absBox: BOX, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { <> RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[CompoundDisplayObjRep _ [compound[class: class, subExprs: subExprs]]]]]]; }; MakeMatrixDisplayExpr: PUBLIC PROC[tag: ATOM, class: MatrixClass, nRows, nCols: INT, elements: LIST OF DisplayExpr, relBox, absBox: BOX, openSym, closeSym, space: DisplayExpr, parent: DisplayExpr _ NIL] RETURNS[DisplayExpr] ~ { <> RETURN[NEW[DisplayExprRep _ [tag: tag, relativeBox: relBox, absoluteBox: absBox, parent: parent, expression: NEW[MatrixDisplayObjRep _ [matrix[class: class, nRows: nRows, nCols: nCols, elements: elements, openSym: openSym, closeSym: closeSym, space: space]]]]]]; }; <> ASRopeFromDisplayExpr: PUBLIC PROC[expr: DisplayExpr, flavor: ATOM _ $AS] RETURNS[ROPE] ~ { <> <<>> WITH expr.expression SELECT FROM a: AtomDisplayObj => SELECT flavor FROM $Reduce => IF a.class.cvtReduceRope # NIL THEN RETURN[a.class.cvtReduceRope[a.value]] ELSE RETURN[a.value]; $SMP => IF a.class.cvtSMPRope # NIL THEN RETURN[a.class.cvtSMPRope[a.value]] ELSE RETURN[a.value]; ENDCASE => IF a.class.cvtASRope # NIL THEN RETURN[a.class.cvtASRope[a.value]] ELSE RETURN[a.value]; c: CompoundDisplayObj => { template: ROPE _ SELECT flavor FROM $Reduce => c.class.cvtReduce, -- template for return value $SMP => c.class.cvtSMP, -- template for return value ENDCASE => c.class.cvtAS; -- template for return value argName: ROPE _ NIL; position: INT _ -1; IF Rope.Length[template] < 1 THEN RETURN[""]; <> FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO argName _ Convert.RopeFromAtom[l.first.name]; position _ Rope.Find[template, argName]; IF position # -1 THEN template _ Rope.Replace[base: template, start: position, len: Rope.Length[argName], with: ASRopeFromDisplayExpr[GetDisplayExpr[l.first.name, c.subExprs], flavor] ]; ENDLOOP; <> IF c.class.name = $complex THEN { position _ Rope.Find[template, "+ -"]; IF position # -1 THEN template _ Rope.Replace[base: template, start: position, len: 3, with: "- "]; }; RETURN[template]; }; m: MatrixDisplayObj => { Element: TYPE ~ RECORD [ expr: DisplayExpr _ NIL ]; Row: TYPE ~ REF RowRec; RowRec: TYPE ~ RECORD [ elements: SEQUENCE numberOfCols: NAT OF Element ]; Matrix: TYPE ~ REF MatrixRec; MatrixRec: TYPE ~ RECORD[ rows: SEQUENCE numberOfRows: NAT OF Row ]; a: Matrix; currentRow, currentCol: NAT; result: ROPE _ NIL; -- return value <> <> a _ NEW[MatrixRec[m.nRows]]; FOR row:INT IN [0..m.nRows) DO a[row] _ NEW[RowRec[m.nCols]]; ENDLOOP; FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO [currentRow, currentCol] _ MathRules.RowColFromAtom[l.first.tag]; a[currentRow - 1][currentCol - 1].expr _ l.first; ENDLOOP; SELECT m.class.name FROM $matrix => { result _ "List[ "; FOR r:INT IN [0..m.nRows) DO result _ Rope.Cat[result, "List[ "]; -- row start char FOR c:INT IN [0..m.nCols) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[r][c].expr]]; <> IF c # (m.nCols - 1) THEN result _ Rope.Cat[result, ", "]; -- col separator ENDLOOP; result _ Rope.Cat[result, " ]"]; -- row end char <> IF r # (m.nRows - 1) THEN result _ Rope.Cat[result, ", "]; -- row separator ENDLOOP; result _ Rope.Cat[result, " ]"]; -- end with matrix end char }; $vector, $sequence, $set, $point => { result _ "List[ "; -- should select set, sequence, etc. IF m.nRows = 1 THEN { -- row vector FOR c: INT IN [0..m.nCols) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[0][c].expr]]; <> IF c # (m.nCols - 1) THEN result _ Rope.Cat[result, ", "]; -- col separator ENDLOOP; } ELSE { -- column vector FOR r: INT IN [0..m.nRows) DO result _ Rope.Cat[result, ASRopeFromDisplayExpr[a[r][0].expr]]; <> IF r # (m.nRows - 1) THEN result _ Rope.Cat[result, ", "]; -- row separator ENDLOOP; }; result _ Rope.Cat[result, " ]"]; }; ENDCASE => result _ "unknownMatrixType"; RETURN[result]; }; ENDCASE => ERROR; }; DisplayExprFromExpr: PUBLIC PROC[expr: EXPR] RETURNS[DisplayExpr] ~ { <> << All Display formatting information is set to default values.>> <<>> <> myDisplayExpr, tempDisplayExpr: DisplayExpr; emptyAtom: ATOM _ $expr; -- generic identifier emptyRelBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, relative]; emptyAbsBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, absolute]; SELECT expr.GetType[] FROM atom => { a: AtomEXPR _ expr.GetAtomExpr[]; <> RETURN[MakeAtomicDisplayExpr[emptyAtom, MathExpr.GetAtomClass[a], MathExpr.GetValue[a], emptyRelBox, emptyAbsBox]]; }; compound => { c: CompoundEXPR _ expr.GetCompoundExpr[]; compClass: CompoundClass _ MathExpr.GetCompoundClass[c]; <> displaySubExprs: LIST OF DisplayExpr _ NIL; -- cons up list of display expressions <> FOR l: LIST OF Argument _ compClass.arguments, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[MathExpr.GetTaggedExpr[l.first.name, MathExpr.GetSubExprs[c] ! exprNotFound => {ERROR unable[$missingArg]}].expression]; tempDisplayExpr.tag _ l.first.name; -- set name tag for display expr displaySubExprs _ CONS[tempDisplayExpr, displaySubExprs]; ENDLOOP; <> FOR l: LIST OF Symbol _ compClass.symbols, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[MathExpr.GetTaggedExpr[l.first.name, MathExpr.GetSubExprs[c] ! exprNotFound => {ERROR unable[$missingSym]}].expression]; tempDisplayExpr.tag _ l.first.name; -- set name tag for display expr displaySubExprs _ CONS[tempDisplayExpr, displaySubExprs]; ENDLOOP; <<>> <> myDisplayExpr _ MakeCompoundDisplayExpr[emptyAtom, MathExpr.GetCompoundClass[c], displaySubExprs, emptyRelBox, emptyAbsBox]; <> FOR l: LIST OF DisplayExpr _ displaySubExprs, l.rest UNTIL l = NIL DO l.first.parent _ myDisplayExpr; -- set parent ENDLOOP; RETURN[myDisplayExpr]; }; matrix => { m: MatrixEXPR _ expr.GetMatrixExpr[]; elts: LIST OF MathExpr.TaggedMathExpr _ MathExpr.GetMatrixElements[m]; class: MatrixClass _ MathExpr.GetMatrixClass[m]; displayElts, displayEltsPointer: LIST OF DisplayExpr _ NIL; nRows, nCols: NAT; openSym, closeSym, space: DisplayExpr; [nRows, nCols] _ MathExpr.GetMatrixSize[m]; <> <> <> <> <> <> <<>> <> FOR l: LIST OF MathExpr.TaggedMathExpr _ elts, l.rest UNTIL l = NIL DO tempDisplayExpr _ DisplayExprFromExpr[l.first.expression]; tempDisplayExpr.tag _ l.first.id; -- set name tag for display expr IF displayElts = NIL THEN displayElts _ displayEltsPointer _ LIST[tempDisplayExpr] ELSE displayEltsPointer _ displayEltsPointer.rest _ LIST[tempDisplayExpr]; ENDLOOP; openSym _ DisplayExprFromExpr[class.openSym]; closeSym _ DisplayExprFromExpr[class.closeSym]; space _ DisplayExprFromExpr[class.space]; <> myDisplayExpr _ MakeMatrixDisplayExpr[emptyAtom, class, nRows, nCols, displayElts, emptyRelBox, emptyAbsBox, openSym, closeSym, space]; FOR l: LIST OF DisplayExpr _ displayElts, l.rest UNTIL l = NIL DO l.first.parent _ myDisplayExpr; -- set parent ENDLOOP; RETURN[myDisplayExpr]; }; ENDCASE => ERROR; <<>> }; ExprFromDisplayExpr: PUBLIC PROC[expr: DisplayExpr] RETURNS[EXPR] ~ { <> <<2/87 - amounts to just stripping away the formatting info from the DisplayExpr, i.e. stripping relativeBox, absoluteBox, and parent pointers.>> <<>> WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MathExpr.MakeAtomicExpr[a.class.name, a.value]]; }; c: CompoundDisplayObj => { <> args: LIST OF MathExpr.TaggedMathExpr _ NIL; <> FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO args _ CONS[[l.first.tag, ExprFromDisplayExpr[l.first]], args]; ENDLOOP; RETURN[MathExpr.MakeCompoundExpr[c.class.name, args]]; }; m: MatrixDisplayObj => { <> elts, eltsPointer: LIST OF MathExpr.TaggedMathExpr _ NIL; <> <> <> <<>> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO -- changed 3/4/87 taggedMathExpr: MathExpr.TaggedMathExpr _ [l.first.tag, ExprFromDisplayExpr[l.first]]; IF elts = NIL THEN elts _ eltsPointer _ LIST[taggedMathExpr] ELSE eltsPointer _ eltsPointer.rest _ LIST[taggedMathExpr]; ENDLOOP; RETURN[MathExpr.MakeMatrixExpr[m.class.name, m.nRows, m.nCols, elts]]; }; ENDCASE => ERROR; }; Copy: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { <> WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MakeAtomicDisplayExpr[expr.tag, a.class, a.value, expr.relativeBox, expr.absoluteBox]]; }; c: CompoundDisplayObj => { <> exprCopy: DisplayExpr; -- return value copiedSubExprs: LIST OF DisplayExpr _ NIL; -- cons up new list of copies <> FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO copiedSubExprs _ CONS[Copy[l.first], copiedSubExprs]; ENDLOOP; <> exprCopy _ MakeCompoundDisplayExpr[expr.tag, c.class, copiedSubExprs, expr.relativeBox, expr.absoluteBox]; FOR l: LIST OF DisplayExpr _ copiedSubExprs, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; m: MatrixDisplayObj => { <> exprCopy: DisplayExpr; -- return value copiedElts, copiedEltsPtr: LIST OF DisplayExpr _ NIL; -- cons up a new list of copied elements <> <> <> <> <> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF copiedElts = NIL THEN copiedElts _ copiedEltsPtr _ LIST[Copy[l.first] ] ELSE copiedEltsPtr _ copiedEltsPtr.rest _ LIST[Copy[l.first] ]; ENDLOOP; <> exprCopy _ MakeMatrixDisplayExpr[expr.tag, m.class, m.nRows, m.nCols, copiedElts, expr.relativeBox, expr.absoluteBox, Copy[m.openSym], Copy[m.closeSym], Copy[m.space]]; FOR l: LIST OF DisplayExpr _ copiedElts, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; <<>> ENDCASE => ERROR; }; <> Tag: PUBLIC PROC[expr: DisplayExpr] RETURNS[ATOM] ~ { <> RETURN[expr.tag]; }; Class: PUBLIC PROC[expr: DisplayExpr] RETURNS[ATOM] ~ { <> WITH expr.expression SELECT FROM a: AtomDisplayObj => RETURN[a.class.name]; c: CompoundDisplayObj => RETURN[c.class.name]; m: MatrixDisplayObj => RETURN[m.class.name]; ENDCASE => ERROR; }; GetSubExprs: PUBLIC PROC[expr: DisplayExpr] RETURNS[LIST OF DisplayExpr] ~ { <> << Returns NIL if no subexpressions exist>> <<>> WITH expr.expression SELECT FROM a: AtomDisplayObj => RETURN[NIL]; -- atoms don't have any children c: CompoundDisplayObj => RETURN[c.subExprs]; m: MatrixDisplayObj => RETURN[m.elements]; ENDCASE => ERROR; }; <> Format: PUBLIC PROC[expr: DisplayExpr, size: Size] RETURNS[BOX] ~ { <> <> << Returns a bounding box for expr.>> << SIGNALS unable[reason: ATOM] if Formatting can not be completed.>> <<>> <> subExprBoxes: LIST OF BOX; myBox, tempBox: BOX; WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[MathBox.Scale[MathBox.MakeBox[tag: a.class.name, aliases: NIL, formatClass: a.class.formatClass, type: absolute, extents: a.class.boxRule[a.value, a.class.style]], MathRules.VecFromSize[size]]]; }; c: CompoundDisplayObj => { <> subExprBoxes _ NIL; -- cons up list of subexpression boxes <> FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO tempBox _ Format[GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}], MathRules.ComputeSize[base: size, adjustment: l.first.size]]; subExprBoxes _ CONS[MathBox.MakeBox[l.first.name, l.first.aliases, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[]], subExprBoxes]; ENDLOOP; <> FOR l: LIST OF Symbol _ c.class.symbols, l.rest UNTIL l = NIL DO tempBox _ Format[GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingSym]}], MathRules.ComputeSize[base: size, adjustment: l.first.size]]; subExprBoxes _ CONS[MathBox.MakeBox[l.first.name, l.first.aliases, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[]], subExprBoxes]; ENDLOOP; <> subExprBoxes _ c.class.boxRule[subExprBoxes]; <> [myBox, subExprBoxes] _ c.class.compBox[subExprBoxes]; <> myBox _ MathBox.ChangeFormatClass[myBox, c.class.formatClass]; <> FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF l.first.relativeBox.Type # relative THEN ERROR unable[$wrongBoxType]; l.first.relativeBox _ MathBox.GetBox[l.first.tag, subExprBoxes ! MathBox.boxNotFound => {ERROR unable[$boxNotFound]}]; -- set box ENDLOOP; RETURN[myBox]; }; m: MatrixDisplayObj => { <> elementBoxes, elementBoxesPtr: LIST OF BOX _ NIL; tempBox, spaceBox, openSymBox, closeSymBox: BOX; <> <> <> <> <> <> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO tempBox _ Format[l.first, MathRules.ComputeSize[base: size, adjustment: script]]; IF elementBoxes = NIL THEN elementBoxes _ elementBoxesPtr _ LIST[ MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[] ] ] ELSE elementBoxesPtr _ elementBoxesPtr.rest _ LIST[ MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[] ] ]; ENDLOOP; <> spaceBox _ Format[m.space, MathRules.ComputeSize[base: size, adjustment: script]]; openSymBox _ Format[m.openSym, normal]; closeSymBox _ Format[m.closeSym, normal]; <> [myBox, elementBoxes, m.openSym.relativeBox, m.closeSym.relativeBox] _ MathRules.ComposeMatrix[m.nRows, m.nCols, elementBoxes, spaceBox, openSymBox, closeSymBox]; <> myBox _ MathBox.ChangeFormatClass[myBox, m.class.formatClass]; <> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF l.first.relativeBox.Type # relative THEN ERROR unable[$wrongBoxType]; l.first.relativeBox _ MathBox.GetBox[l.first.tag, elementBoxes ! MathBox.boxNotFound => {ERROR unable[$boxNotFound]}]; -- set box ENDLOOP; RETURN[myBox]; }; ENDCASE => ERROR; <<>> }; Paint: PUBLIC PROC[expr: DisplayExpr, context: Imager.Context, absBox: BOX, selections: LIST OF Selection] ~ { <> <> <> << Updates absolute bounding boxes (viewer coords).>> << SIGNALS unable[reason: ATOM] if Painting cannot be completed.>> <<>> <> currentDisplayExpr: DisplayExpr; <<>> <> IF absBox.Type # absolute THEN ERROR unable[$wrongBoxType]; expr.absoluteBox _ absBox; WITH expr.expression SELECT FROM a: AtomDisplayObj => { a.class.paintRule[a.value, a.class.style, context, absBox]; }; c: CompoundDisplayObj => { <> <<>> <> FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO currentDisplayExpr _ GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}]; Paint[currentDisplayExpr, context, MathBox.RelToAbsBox[currentDisplayExpr.relativeBox, absBox], selections]; ENDLOOP; <> FOR l: LIST OF Symbol _ c.class.symbols, l.rest UNTIL l = NIL DO currentDisplayExpr _ GetDisplayExpr[l.first.name, c.subExprs ! exprNotFound => {ERROR unable[$missingArg]}]; Paint[currentDisplayExpr, context, MathBox.RelToAbsBox[currentDisplayExpr.relativeBox, absBox], selections]; ENDLOOP; }; m: MatrixDisplayObj => { <> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO Paint[l.first, context, MathBox.RelToAbsBox[l.first.relativeBox, absBox], selections]; ENDLOOP; <> Paint[m.openSym, context, MathBox.RelToAbsBox[m.openSym.relativeBox, absBox], selections]; Paint[m.closeSym, context, MathBox.RelToAbsBox[m.closeSym.relativeBox, absBox], selections]; }; ENDCASE => ERROR; <> FOR l: LIST OF Selection _ selections, l.rest UNTIL l = NIL DO IF (expr = l.first.expr) THEN { <> context.SetColor[l.first.color]; <> Imager.MaskRectangle[context, [x: absBox.Offset[].x - (absBox.Extents[].leftExtent + 1), y: absBox.Offset[].y - (absBox.Extents[].descent + 1), w: absBox.Width[] + 1, h: absBox.Height[] + 2]]; <> context.SetColor[Imager.black]; }; ENDLOOP; }; <> GetDisplayExpr: PUBLIC PROC[tag: ATOM, exprs: LIST OF DisplayExpr] RETURNS[DisplayExpr] ~ { <> << SIGNALS exprNotFound if no association exists.>> <> FOR l: LIST OF DisplayExpr _ exprs, l.rest UNTIL l = NIL DO IF l.first.tag = tag THEN RETURN[l.first]; ENDLOOP; <> ERROR exprNotFound; }; <> DisplayExprFromCoords: PUBLIC PROC[expr: DisplayExpr, x, y: REAL] RETURNS[DisplayExpr] ~ { <> << SIGNALS noSelection if no association exists.>> <<>> IF expr = NIL THEN ERROR noSelection; IF ~MathBox.Inside[expr.absoluteBox, x, y] THEN ERROR noSelection; WITH expr.expression SELECT FROM a: AtomDisplayObj => { IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; c: CompoundDisplayObj => { <> FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO IF MathBox.Inside[l.first.absoluteBox, x, y] THEN RETURN[DisplayExprFromCoords[l.first, x, y ! noSelection => CONTINUE]]; ENDLOOP; <> IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; m: MatrixDisplayObj => { <> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF MathBox.Inside[l.first.absoluteBox, x, y] THEN RETURN[DisplayExprFromCoords[l.first, x, y ! noSelection => CONTINUE]]; ENDLOOP; <> IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection; }; ENDCASE => ERROR; }; Selectable: PUBLIC PROC[expr: DisplayExpr] RETURNS[BOOL] ~ { <> <<>> IF expr = NIL THEN RETURN[FALSE]; WITH expr.expression SELECT FROM a: AtomDisplayObj => { IF a.class.flavor = symbol THEN RETURN[FALSE] ELSE RETURN[TRUE]; }; c: CompoundDisplayObj => RETURN[TRUE]; m: MatrixDisplayObj => RETURN[TRUE]; ENDCASE => ERROR; }; <<>> SelectableParent: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { <> << SIGNALS noParent if no selectable parent exists.>> <<>> <> IF (expr = NIL) OR (expr.parent) = NIL THEN ERROR noSelection; RETURN[expr.parent]; }; SelectableChild: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { <> << SIGNALS noSelection if no selectable child exists.>> <<>> <> childExpr: DisplayExpr _ NIL; <<>> IF expr = NIL THEN ERROR noSelection; WITH expr.expression SELECT FROM a: AtomDisplayObj => ERROR noSelection; -- atom has no children c: CompoundDisplayObj => { FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO <> childExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[childExpr] THEN RETURN[childExpr]; -- return selected expression ENDLOOP; <> ERROR noSelection; }; m: MatrixDisplayObj => { <<** FOO FIX THIS **>> ERROR noSelection; }; ENDCASE => ERROR; }; ExtendFunctionSelectSibling: PROC [expr: DisplayExpr] RETURNS [DisplayExpr] ~ { <> emptyAtom: ATOM _ $expr; -- generic identifier emptyRelBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, relative]; emptyAbsBox: BOX _ MathBox.MakeBox[emptyAtom, NIL, other, absolute]; arg12Space: DisplayExpr _ MakeAtomicDisplayExpr[$arg12Space, MathDB.LookupAtomClass[$space], Convert.RopeFromAtom[$medium, FALSE], emptyRelBox, emptyAbsBox]; arg23Space: DisplayExpr _ MakeAtomicDisplayExpr[$arg23Space, MathDB.LookupAtomClass[$space], Convert.RopeFromAtom[$medium, FALSE], emptyRelBox, emptyAbsBox]; arg34Space: DisplayExpr _ MakeAtomicDisplayExpr[$arg34Space, MathDB.LookupAtomClass[$space], Convert.RopeFromAtom[$medium, FALSE], emptyRelBox, emptyAbsBox]; comma12: DisplayExpr _ MakeAtomicDisplayExpr[$comma12, MathDB.LookupAtomClass[$italicSym], XRope.FromChar[',] , emptyRelBox, emptyAbsBox]; comma23: DisplayExpr _ MakeAtomicDisplayExpr[$comma23, MathDB.LookupAtomClass[$italicSym], XRope.FromChar[',] , emptyRelBox, emptyAbsBox]; comma34: DisplayExpr _ MakeAtomicDisplayExpr[$comma34, MathDB.LookupAtomClass[$italicSym], XRope.FromChar[',] , emptyRelBox, emptyAbsBox]; newExprs: LIST OF DisplayExpr; sibling: DisplayExpr _ DisplayExprFromExpr[MathConstructors.MakePlaceHolder[] ]; sibling.parent _ expr.parent; WITH expr.parent.expression SELECT FROM c: CompoundDisplayObj => SELECT c.class.name FROM $nullaryFunction, $unaryFunction, $binaryFunction, $ternaryFunction => { SELECT c.class.name FROM $nullaryFunction => { c.class _ MathDB.LookupCompoundClass[$unaryFunction]; sibling.tag _ $arg1; newExprs _ LIST[sibling] }; $unaryFunction => { c.class _ MathDB.LookupCompoundClass[$binaryFunction]; sibling.tag _ $arg2; newExprs _ LIST[sibling, arg12Space, comma12] }; $binaryFunction => { c.class _ MathDB.LookupCompoundClass[$ternaryFunction]; sibling.tag _ $arg3; newExprs _ LIST[sibling, arg23Space, comma23] }; $ternaryFunction => { c.class _ MathDB.LookupCompoundClass[$quaternaryFunction]; sibling.tag _ $arg4; newExprs _ LIST[sibling, arg34Space, comma34] }; ENDCASE => ERROR; -- can't extend quaternaryFunction IF c.subExprs = NIL THEN c.subExprs _ newExprs ELSE { p: LIST OF DisplayExpr _ c.subExprs; WHILE p.rest#NIL DO p _ p.rest ENDLOOP; p.rest _ newExprs; }; }; ENDCASE => ERROR noSelection; ENDCASE => ERROR noSelection; RETURN[sibling]; }; SelectableSibling: PUBLIC PROC[expr: DisplayExpr] RETURNS[DisplayExpr] ~ { <> << SIGNALS noSelection if no selectable sibling exists.>> <<>> <> afterExpr: LIST OF Argument _ NIL; -- sibling after expr in parent's subexpr list siblingExpr: DisplayExpr _ NIL; IF (expr = NIL) OR (expr.parent = NIL) THEN ERROR noSelection; <<"cycle" thru parent's children and return "next" selectable sibling in list>> WITH expr.parent.expression SELECT FROM a: AtomDisplayObj => ERROR noSelection; c: CompoundDisplayObj => { <> FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO IF l.first.name = expr.tag THEN {afterExpr _ l.rest; EXIT}; ENDLOOP; <> FOR l: LIST OF Argument _ afterExpr, l.rest UNTIL l = NIL DO siblingExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[siblingExpr] THEN RETURN[siblingExpr]; -- return selected expression ENDLOOP; SELECT c.class.name FROM $nullaryFunction, $unaryFunction, $binaryFunction, $ternaryFunction => RETURN[ExtendFunctionSelectSibling[expr]]; -- hack ENDCASE; <<*** hack 7/16/87 to handle extra inserted parentheses>> IF c.class.name=$paren THEN RETURN[SelectableSibling[expr.parent] ]; <<*** end hack>> <<>> <> FOR l: LIST OF Argument _ c.class.arguments, l.rest UNTIL l = NIL DO IF l.first.name = expr.tag THEN EXIT; -- already looked thru entire list siblingExpr _ GetDisplayExpr[l.first.name, c.subExprs]; IF Selectable[siblingExpr] THEN RETURN[siblingExpr]; -- return selected expression ENDLOOP; <> ERROR noSelection; }; m: MatrixDisplayObj => { <<** FOO FIX THIS **>> ERROR noSelection; }; ENDCASE => ERROR; }; Replace: PUBLIC PROC[expr, old, new: DisplayExpr] RETURNS[DisplayExpr] ~ { <> <> << Note that new is used (not a copy). Hence if expr = old, then new returned, i.e. a "copy" returned iff old is a proper subexpression of expr.>> RETURN[ReplaceN[expr, LIST[[old: old, new: new]]]]; }; ReplaceN: PUBLIC PROC[expr: DisplayExpr, replacements: LIST OF ReplacePair] RETURNS[DisplayExpr] ~ { <> <> <> <> <<>> <> <> <> FOR l: LIST OF ReplacePair _ replacements, l.rest UNTIL l = NIL DO IF expr = l.first.old THEN { parent: DisplayExpr _ l.first.old.parent; new: DisplayExpr _ l.first.new; <> <> <<-- 7/10/87 -- turn off op precedence for functional notation parsing>> IF FALSE THEN { parenArgTag: ATOM = $a; argDisplayExpr: DisplayExpr; <> parenExpr: DisplayExpr _ DisplayExprFromExpr[MathExpr.MakeCompoundExpr[$paren, LIST[[parenArgTag, MathConstructors.MakePlaceHolder[] ]] ] ]; <<>> <> FOR l: LIST OF DisplayExpr _ GetSubExprs[parenExpr], l.rest UNTIL l = NIL DO IF Tag[l.first] = parenArgTag THEN { argDisplayExpr _ l.first; EXIT }; ENDLOOP; <> parenExpr _ Replace[parenExpr, argDisplayExpr, new]; <> <> parenExpr.tag _ l.first.old.tag; -- replacement has same tag (e.g. $integrand, etc.) parenExpr.parent _ parent; -- replacement has same parent as before RETURN[parenExpr] } ELSE { new.tag _ l.first.old.tag; -- replacement has same tag (e.g. $integrand, etc.) new.parent _ parent; -- replacement has same parent as before RETURN[new] }; }; ENDLOOP; WITH expr.expression SELECT FROM a: AtomDisplayObj => { RETURN[Copy[expr]]; }; c: CompoundDisplayObj => { <> exprCopy: DisplayExpr; -- return value copiedSubExprs: LIST OF DisplayExpr _ NIL; -- cons up new list of copies <> FOR l: LIST OF DisplayExpr _ c.subExprs, l.rest UNTIL l = NIL DO copiedSubExprs _ CONS[ReplaceN[l.first, replacements], copiedSubExprs]; ENDLOOP; <> exprCopy _ MakeCompoundDisplayExpr[expr.tag, c.class, copiedSubExprs, expr.relativeBox, expr.absoluteBox]; FOR l: LIST OF DisplayExpr _ copiedSubExprs, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; m: MatrixDisplayObj => { <> exprCopy: DisplayExpr; -- return value copiedElts, copiedEltsPtr: LIST OF DisplayExpr _ NIL; -- cons up a new list of copied elements <> <> <> <> <> FOR l: LIST OF DisplayExpr _ m.elements, l.rest UNTIL l = NIL DO IF copiedElts = NIL THEN copiedElts _ copiedEltsPtr _ LIST[ReplaceN[l.first, replacements] ] ELSE copiedEltsPtr _ copiedEltsPtr.rest _ LIST[ReplaceN[l.first, replacements] ]; ENDLOOP; <> exprCopy _ MakeMatrixDisplayExpr[expr.tag, m.class, m.nRows, m.nCols, copiedElts, expr.relativeBox, expr.absoluteBox, Copy[m.openSym], Copy[m.closeSym], Copy[m.space]]; FOR l: LIST OF DisplayExpr _ copiedElts, l.rest UNTIL l = NIL DO l.first.parent _ exprCopy; -- set parent pointers appropriately ENDLOOP; RETURN[exprCopy]; }; <<>> ENDCASE => ERROR; }; <> unable: PUBLIC ERROR[reason: ATOM] = CODE; noSelection: PUBLIC ERROR = CODE; exprNotFound: PUBLIC ERROR = CODE; END.