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;
Type Abbreviations from Imported Interfaces
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;
Private Type Rep
A DisplayExpr is a MUTABLE math expression which is mapped to a viewer.
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
];
useful type shorthands
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
Display Expression Constructors
MakeAtomicDisplayExpr:
PUBLIC
PROC[tag:
ATOM, class: AtomClass, value:
ROPE, relBox, absBox:
BOX, parent: DisplayExpr ←
NIL]
RETURNS[DisplayExpr] ~ {
effects: Constructs and returns a new atomic display expression.
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] ~ {
effects: Constructs and returns a new compound display expression.
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] ~ {
effects: Constructs and returns a new matrix display expression.
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]]]]]];
};
Parse/UnParse Routines
ASRopeFromDisplayExpr:
PUBLIC
PROC[expr: DisplayExpr, flavor:
ATOM ← $AS]
RETURNS[
ROPE] ~ {
effects: Returns a ROPE in selected format
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[""];
recursively copy subexpressions
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;
Hack for complexes with negative imaginary part. December 11, 1986 11:24:18 am PST
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
convert boxes into a SEQUENCE (ugh!) matrix type
instantiate matrix "a" (isn't CLU's array[]$create() much nicer, really?)
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]];
add a comma if not last col in row
IF c # (m.nCols - 1) THEN result ← Rope.Cat[result, ", "]; -- col separator
ENDLOOP;
result ← Rope.Cat[result, " ]"]; -- row end char
add a comma if not last row in matrix
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]];
add a comma if not last col in vector
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]];
add a comma if not last row in vector
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] ~ {
effects: Constructs and returns a new display expression from expr.
All Display formatting information is set to default values.
local declarations
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[];
should really combine passed in style with local atomic style
RETURN[MakeAtomicDisplayExpr[emptyAtom, MathExpr.GetAtomClass[a], MathExpr.GetValue[a], emptyRelBox, emptyAbsBox]];
};
compound => {
c: CompoundEXPR ← expr.GetCompoundExpr[];
compClass: CompoundClass ← MathExpr.GetCompoundClass[c];
recursively generate displayexprs for all subexpressions (arguments & symbols)
displaySubExprs: LIST OF DisplayExpr ← NIL; -- cons up list of display expressions
generate all argument subexpressions
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;
generate all symbol subexpressions
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;
construct return value now so can set "parent" component of subexpressions
myDisplayExpr ← MakeCompoundDisplayExpr[emptyAtom, MathExpr.GetCompoundClass[c], displaySubExprs, emptyRelBox, emptyAbsBox];
set parents of display subexpressions
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];
convert elements from expr to displayexpr
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
displayElts ← CONS[tempDisplayExpr, displayElts];
ENDLOOP;
convert elements from expr to displayexpr -- changed 3/4/87
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];
construct return value now so can set "parent" component of subexpressions
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] ~ {
effects: Constructs and returns a new EXPR from 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 => {
local declarations
args: LIST OF MathExpr.TaggedMathExpr ← NIL;
recursively build a list of tagged arg exprs
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 => {
local declarations
elts, eltsPointer: LIST OF MathExpr.TaggedMathExpr ← NIL;
FOR l: LIST OF DisplayExpr ← m.elements, l.rest UNTIL l = NIL DO
elts ← CONS[[l.first.tag, ExprFromDisplayExpr[l.first]], elts];
ENDLOOP;
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] ~ {
effects: Returns a new, distinct copy of expr.
WITH expr.expression
SELECT
FROM
a: AtomDisplayObj => {
RETURN[MakeAtomicDisplayExpr[expr.tag, a.class, a.value, expr.relativeBox, expr.absoluteBox]];
};
c: CompoundDisplayObj => {
local declarations
exprCopy: DisplayExpr; -- return value
copiedSubExprs: LIST OF DisplayExpr ← NIL; -- cons up new list of copies
recursively copy subexpressions
FOR l:
LIST
OF DisplayExpr ← c.subExprs, l.rest
UNTIL l =
NIL
DO
copiedSubExprs ← CONS[Copy[l.first], copiedSubExprs];
ENDLOOP;
construct return value now so we can set parent pointers for subexprs
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 => {
local declarations
exprCopy: DisplayExpr; -- return value
copiedElts, copiedEltsPtr: LIST OF DisplayExpr ← NIL; -- cons up a new list of copied elements
recursively copy elements
FOR l: LIST OF DisplayExpr ← m.elements, l.rest UNTIL l = NIL DO
copiedElts ← CONS[Copy[l.first], copiedElts];
ENDLOOP;
recursively copy elements -- changed 3/4/87
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;
construct return value now so we can set parent pointers for subexprs
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;
};
Format and Paint
Format:
PUBLIC
PROC[expr: DisplayExpr, size: Size]
RETURNS[
BOX] ~ {
modifies: expr
effects: expr is updated into a "paintable" form (dsa - perhaps in the sense that all subExprs have been given correct relative bounding boxes)
Returns a bounding box for expr.
SIGNALS unable[reason: ATOM] if Formatting can not be completed.
local declarations
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 => {
recursively format all subexpressions (arguments & symbols)
subExprBoxes ← NIL; -- cons up list of subexpression boxes
format all argument subexpressions
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;
format all symbol subexpressions
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;
compute corrected boxes using sizing constraints
subExprBoxes ← c.class.boxRule[subExprBoxes];
compose layout for boxes using alignment constraints
[myBox, subExprBoxes] ← c.class.compBox[subExprBoxes];
set format class for mybox
myBox ← MathBox.ChangeFormatClass[myBox, c.class.formatClass];
set relative boxes of display subexpressions
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 => {
local declarations
elementBoxes, elementBoxesPtr: LIST OF BOX ← NIL;
tempBox, spaceBox, openSymBox, closeSymBox: BOX;
recursively format all matrix elements
FOR l: LIST OF DisplayExpr ← m.elements, l.rest UNTIL l = NIL DO
tempBox ← Format[l.first, MathRules.ComputeSize[base: size, adjustment: script]];
elementBoxes ← CONS[MathBox.MakeBox[l.first.tag, NIL, tempBox.FormatClass[], tempBox.Type[], tempBox.Extents[], tempBox.Offset[], tempBox.SubscriptHint[], tempBox.SuperscriptHint[]], elementBoxes];
ENDLOOP;
recursively format all matrix elements
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;
format openSym, closeSym, and space
spaceBox ← Format[m.space, MathRules.ComputeSize[base: size, adjustment: script]];
openSymBox ← Format[m.openSym, normal];
closeSymBox ← Format[m.closeSym, normal];
compose layout for matrix by using alignment constraints
[myBox, elementBoxes, m.openSym.relativeBox, m.closeSym.relativeBox] ← MathRules.ComposeMatrix[m.nRows, m.nCols, elementBoxes, spaceBox, openSymBox, closeSymBox];
set format class for mybox
myBox ← MathBox.ChangeFormatClass[myBox, m.class.formatClass];
set relative boxes of matrix elements
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] ~ {
requires: absBox is an absolute BOX
modifies: expr
effects: Displays expr in context, bounded by absBox.
Updates absolute bounding boxes (viewer coords).
SIGNALS unable[reason: ATOM] if Painting cannot be completed.
local declarations
currentDisplayExpr: DisplayExpr;
update absolute coordinates
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 => {
paint all subexpressions
paint arguments
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;
paint symbols
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 => {
paint all matrix elements
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 open & close symbols
Paint[m.openSym, context, MathBox.RelToAbsBox[m.openSym.relativeBox, absBox], selections];
Paint[m.closeSym, context, MathBox.RelToAbsBox[m.closeSym.relativeBox, absBox], selections];
};
ENDCASE => ERROR;
if selected, highlight region appropriately, using a one pixel border
FOR l:
LIST
OF Selection ← selections, l.rest
UNTIL l =
NIL
DO
IF (expr = l.first.expr)
THEN {
set proper color depending on selection
context.SetColor[l.first.color];
highlight region
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]];
reset color to black
context.SetColor[Imager.black];
};
ENDLOOP;
};
Selection Operations
DisplayExprFromCoords:
PUBLIC
PROC[expr: DisplayExpr, x, y:
REAL]
RETURNS[DisplayExpr] ~ {
effects: Returns the subexpression associated with coordinates [x, y] in expression expr.
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 => {
see if selection can be further narrowed
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 above loop does not return, then can't narrow selection any more
IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection;
};
m: MatrixDisplayObj => {
see if selection can be further narrowed
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 above loop does not return, then can't narrow selection any more
IF Selectable[expr] THEN RETURN[expr] ELSE ERROR noSelection;
};
ENDCASE => ERROR;
Selectable:
PUBLIC
PROC[expr: DisplayExpr]
RETURNS[
BOOL] ~ {
effects: Returns TRUE iff expr is selectable.
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] ~ {
effects: Returns the parent (enclosing expression) of expr.
SIGNALS noParent if no selectable parent exists.
complain if no expr or no parent
IF (expr = NIL) OR (expr.parent) = NIL THEN ERROR noSelection;
RETURN[expr.parent];
};
SelectableChild:
PUBLIC
PROC[expr: DisplayExpr]
RETURNS[DisplayExpr] ~ {
effects: Returns a child expressions (subexpression) for expr.
SIGNALS noSelection if no selectable child exists.
local declarations
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
keep looking for selectable child
childExpr ← GetDisplayExpr[l.first.name, c.subExprs];
IF Selectable[childExpr] THEN RETURN[childExpr]; -- return selected expression
ENDLOOP;
if there are no selectable children, signal noSelection
ERROR noSelection;
};
m: MatrixDisplayObj => {
** FOO FIX THIS **
ERROR noSelection;
};
ENDCASE => ERROR;
};
ExtendFunctionSelectSibling:
PROC [expr: DisplayExpr]
RETURNS [DisplayExpr] ~ {
Hack 7/10/87: Assuming expr is the last arg of a function, change its parent to be larger function class and select the new last arg.
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] ~ {
effects: Returns the "next" sibling expression from expr.
SIGNALS noSelection if no selectable sibling exists.
local declarations
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 => {
find starting point to begin looking for next selectable sibling expr
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;
look for next selectable sibling in exprs after expr in list (i.e. in afterExpr)
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
if no selectable sibling exists after expr, then wraparound list to before expr
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;
if we haven't RETURNed yet, then there are no selectable siblings
ERROR noSelection;
};
m: MatrixDisplayObj => {
** FOO FIX THIS **
ERROR noSelection;
};
ENDCASE => ERROR;
};
Replace:
PUBLIC
PROC[expr, old, new: DisplayExpr]
RETURNS[DisplayExpr] ~ {
effects: Returns a copy of display expression expr with new substituted for old.
caveats: Return value must be reformatted before Paint[]'ing.
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] ~ {
effects: Returns a copy of display expression expr with new substituted for old for each pair in replacements [old, new].
If expr = old←i, then new←i i.e. a "copy" returned iff each old←i is a proper subexpression of expr.
Note that replacements can "interfere" with each other; outcome depends on their ordering.
caveats: Return value must be reformatted before Paint[]'ing.
Note that "old" components of replace pairs must be the actual pointers to the exprs we wish to replace, i.e. we only replace that actual expr, and not any other expr which is equivalent but physically distinct from it.
Note that the "new" components of replace pairs are used (not copies). Hence anyone who holds the pointer to a "new" component can e.g. later ask to have it replaced by something.
Note that recursion terminates as soon as we find a match, i.e. if expr = one of the olds (i.e. expr is one of the things to be replaced), we won't examine any subexprs of expr for possible additional matches
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;
Parenthesize replacement if its op has lower precedence than parent
IF parent #NIL AND MathDB.CompareOps[Class[new], Class[parent] ] = less THEN {
-- 7/10/87 -- turn off op precedence for functional notation parsing
IF
FALSE
THEN {
parenArgTag: ATOM = $a;
argDisplayExpr: DisplayExpr;
Create skeleton for parenthesized expression (i.e. dummy arg)
parenExpr: DisplayExpr ← DisplayExprFromExpr[MathExpr.MakeCompoundExpr[$paren, LIST[[parenArgTag, MathConstructors.MakePlaceHolder[] ]] ] ];
Grab onto dummy arg
FOR l:
LIST
OF DisplayExpr ← GetSubExprs[parenExpr], l.rest
UNTIL l =
NIL
DO
IF Tag[l.first] = parenArgTag THEN { argDisplayExpr ← l.first; EXIT };
ENDLOOP;
Stuff actual pointer to new into parenExpr
parenExpr ← Replace[parenExpr, argDisplayExpr, new];
Update pointers
new.tag ← $a; new.parent ← parenExpr;
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 => {
local declarations
exprCopy: DisplayExpr; -- return value
copiedSubExprs: LIST OF DisplayExpr ← NIL; -- cons up new list of copies
recursively copy subexpressions
FOR l:
LIST
OF DisplayExpr ← c.subExprs, l.rest
UNTIL l =
NIL
DO
copiedSubExprs ← CONS[ReplaceN[l.first, replacements], copiedSubExprs];
ENDLOOP;
construct return value now so we can set parent pointers for subexprs
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 => {
local declarations
exprCopy: DisplayExpr; -- return value
copiedElts, copiedEltsPtr: LIST OF DisplayExpr ← NIL; -- cons up a new list of copied elements
recursively copy elements
FOR l: LIST OF DisplayExpr ← m.elements, l.rest UNTIL l = NIL DO
copiedElts ← CONS[ReplaceN[l.first, replacements], copiedElts];
ENDLOOP;
recursively copy elements - changed 3/4/87
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;
construct return value now so we can set parent pointers for subexprs
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;
};