MathExprImpl.mesa
Carl Waldspurger, August 23, 1986 4:41:31 pm PDT
Mathematics Expressions Module
DIRECTORY
MathRules USING [AtomBoxProc, AtomPaintProc, CompoundBoxProc, CompositionProc, Size, AtomToASRopeProc],
MathBox,
MathTypes USING [Style, FormatClass],
MathDB USING [LookupAtomClass, LookupCompoundClass, LookupMatrixClass, notFound],
Vector USING [VEC],
Rope USING [ROPE, Cat, Equal, FromChar],
Convert USING [RopeFromAtom, RopeFromInt, RopeFromRope],
IO USING [STREAM, RIS, GetChar, PeekChar, SkipWhitespace, GetRopeLiteral, GetAtom, GetCard, Error, EndOfStream],
MathExpr;
MathExprImpl: CEDAR PROGRAM
IMPORTS MathDB, Rope, Convert, IO
EXPORTS MathExpr ~
BEGIN
Abbreviations from Imported Interfaces
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector.VEC;
BOX: TYPE ~ MathBox.BOX;
Style: TYPE ~ MathTypes.Style;
AtomBoxProc: TYPE ~ MathRules.AtomBoxProc;
AtomPaintProc: TYPE ~ MathRules.AtomPaintProc;
AtomToASRopeProc: TYPE ~ MathRules.AtomToASRopeProc;
CompoundBoxProc: TYPE ~ MathRules.CompoundBoxProc;
CompositionProc: TYPE ~ MathRules.CompositionProc;
Size: TYPE ~ MathRules.Size;
TaggedMathExpr: TYPE ~ MathExpr.TaggedMathExpr;
ExprFlavors: TYPE ~ MathExpr.ExprFlavors;
AtomClass: TYPE ~ MathExpr.AtomClass;
AtomClassRep: TYPE ~ MathExpr.AtomClassRep;
AtomFlavor: TYPE ~ MathExpr.AtomFlavor;
CompoundClass: TYPE ~ MathExpr.CompoundClass;
CompoundClassRep: TYPE ~ MathExpr.CompoundClassRep;
MatrixClass: TYPE ~ MathExpr.MatrixClass;
MatrixClassRep: TYPE ~ MathExpr.MatrixClassRep;
FormatClass: TYPE ~ MathTypes.FormatClass;
Argument: TYPE ~ MathExpr.Argument;
Symbol: TYPE ~ MathExpr.Symbol;
Private Type Rep
A Math Expression is either an atomic expression or a compound expression
MathExprRep: PUBLIC TYPE ~
RECORD [
SELECT type:* FROM
atom => [
class: AtomClass, -- atomic data type
value: ROPE -- atomic value, e.g. integer as rope
],
compound => [
class: CompoundClass, -- compound operation class, e.g. summation or product
subExprs: LIST OF TaggedMathExpr ← NIL -- class operation arguments
],
matrix => [
class: MatrixClass, -- type of matrix op, e.g. determinant or matrix, etc.
nRows, nCols: INT, -- matrix size as rows x cols
elements: LIST OF TaggedMathExpr ← NIL -- matrix elements
],
ENDCASE
];
AtomExprRep: PUBLIC TYPE ~ atom MathExprRep;
CompoundExprRep: PUBLIC TYPE ~ compound MathExprRep;
MatrixExprRep: PUBLIC TYPE ~ matrix MathExprRep;
privately (n.b. not public) redefine opaque types in terms of concrete rep
EXPR: TYPE ~ REF MathExprRep;
AtomEXPR: TYPE ~ REF AtomExprRep;
CompoundEXPR: TYPE ~ REF CompoundExprRep;
MatrixEXPR: TYPE ~ REF MatrixExprRep;
Constructors
Primitive Constructors
MakeArgument: PUBLIC PROC[name: ATOM, aliases: LIST OF ATOM, size: Size] RETURNS[Argument] ~ {
effects: constructs and returns an argument object
RETURN[[name: name, aliases: aliases, size: size]];
};
MakeSymbol: PUBLIC PROC[name: ATOM, aliases: LIST OF ATOM, size: Size, value: EXPR] RETURNS[Symbol] ~ {
effects: constructs and returns a symbol object
RETURN[[name: name, aliases: aliases, size: size, value: value]];
};
MakeAtomClass: PUBLIC PROC[name: ATOM, formatClass: FormatClass, flavor: AtomFlavor, style: Style, boxRule: AtomBoxProc, paintRule: AtomPaintProc, cvtASRule: AtomToASRopeProc ← NIL] RETURNS[AtomClass] ~ {
effects: constructs and returns a new atom class object
RETURN[NEW[AtomClassRep ← [name: name, formatClass: formatClass, flavor: flavor, style: style, boxRule: boxRule, paintRule: paintRule, cvtASRope: cvtASRule]]];
};
MakeCompoundClass: PUBLIC PROC[name: ATOM, formatClass: FormatClass, description: ROPE, args: LIST OF Argument, syms: LIST OF Symbol, boxRule: CompoundBoxProc, compBox: CompositionProc, cvtAS: ROPENIL] RETURNS[CompoundClass] ~ {
effects: constructs and returns a new compound class object
RETURN[NEW[CompoundClassRep ← [name: name, formatClass: formatClass, description: description, arguments: args, symbols: syms, boxRule: boxRule, compBox: compBox, cvtAS: cvtAS]]];
};
MakeMatrixClass: PUBLIC PROC[name: ATOM, formatClass: FormatClass,
openSym, closeSym, space: EXPR] RETURNS[MatrixClass] ~ {
effects: constructs and returns a new matrix class object
RETURN[NEW[MatrixClassRep ← [name: name, formatClass: formatClass, space: space, openSym: openSym, closeSym: closeSym]]];
};
Math Expression Constructors
MakeAtomicExpr: PUBLIC PROC[class: ATOM, value: ROPE] RETURNS[EXPR] ~ {
effects: constructs and returns a new atomic expression object
SIGNALS badAtomClass if class is unrecognized
lookup class in database, complain if not found
atomClass: AtomClass ← MathDB.LookupAtomClass[class ! MathDB.notFound => {ERROR badAtomClass}];
RETURN[NEW[atom MathExprRep ← [atom[class: atomClass, value: value]]]];
};
MakeCompoundExpr: PUBLIC PROC[class: ATOM, args: LIST OF TaggedMathExpr] RETURNS[EXPR] ~ {
effects: constructs and returns a new compound expression object
SIGNALS badCompoundClass if class is unrecognized
SIGNALS badExprs if exprs has the wrong number or wrong type of elements
local declarations
validExprs: LIST OF TaggedMathExpr ← NIL;
lookup class in database, complain if not found
compClass: CompoundClass ← MathDB.LookupCompoundClass[class ! MathDB.notFound => {ERROR badCompoundClass}];
check validity of subexpressions (by tagged id)
grab each argument and symbol as needed and stuff into validExprs (cons up list)
FOR l: LIST OF Argument ← compClass.arguments, l.rest UNTIL l = NIL DO
validExprs ← CONS[GetTaggedExpr[l.first.name, args ! exprNotFound => {ERROR badExprs[l.first.name]}], validExprs];
ENDLOOP;
FOR l: LIST OF Symbol ← compClass.symbols, l.rest UNTIL l = NIL DO
validExprs ← CONS[[l.first.name, l.first.value], validExprs];
ENDLOOP;
finally construct and return verified EXPR object
RETURN[NEW[compound MathExprRep ← [compound[class: compClass, subExprs: validExprs]]]];
};
MakeMatrixExpr: PUBLIC PROC[class: ATOM, nRows, nCols: NAT,
elements: LIST OF TaggedMathExpr] RETURNS[EXPR] ~ {
effects: constructs and returns a new matrix expression object
SIGNALS badMatrixClass if class is unrecognized
SIGNALS badMatrixSize if nRows or nCols is invalid
SIGNALS badMatrix if rows has the wrong number or wrong type of elements
matrixClass: MatrixClass ← MathDB.LookupMatrixClass[class ! MathDB.notFound => {ERROR badMatrixClass}];
RETURN[NEW[matrix MathExprRep ← [matrix[class: matrixClass, nRows: nRows, nCols: nCols, elements: elements]]]];
};
Parse/UnParse Routines
RopeFromExpr: PUBLIC PROC[expr: EXPR] RETURNS[ROPE] ~ {
effects: Returns a ROPE in a canonical format which can be parsed
by ExprFromRope[].
WITH expr SELECT FROM
a: AtomEXPR => {
RETURN[Rope.Cat["(ATOM ", Convert.RopeFromAtom[a.class.name], " ", Convert.RopeFromRope[a.value], ")"]];
};
c: CompoundEXPR => {
className: ROPE ← Convert.RopeFromAtom[c.class.name];
ropeVal: ROPE ← Rope.Cat["(CMPD ", className, " "]; -- return value
FOR l: LIST OF Argument ← c.class.arguments, l.rest UNTIL l = NIL DO
argName: ROPE ← Convert.RopeFromAtom[l.first.name];
argRope: ROPE ← RopeFromExpr[GetTaggedExpr[l.first.name, c.subExprs].expression];
ropeVal ← Rope.Cat[ropeVal, "{", argName, " "];
ropeVal ← Rope.Cat[ropeVal, argRope, "}"];
IF l.rest # NIL THEN ropeVal ← Rope.Cat[ropeVal, " "];
ENDLOOP;
ropeVal ← Rope.Cat[ropeVal, ")"];
RETURN[ropeVal];
};
m: MatrixEXPR => {
className: ROPE ← Convert.RopeFromAtom[m.class.name];
nRowsRope: ROPE ← Convert.RopeFromInt[m.nRows];
nColsRope: ROPE ← Convert.RopeFromInt[m.nCols];
ropeVal: ROPE ← Rope.Cat["(MTRX ", className, " [", nRowsRope];
ropeVal ← Rope.Cat[ropeVal, " ", nColsRope, "] "];
FOR l: LIST OF TaggedMathExpr ← m.elements, l.rest UNTIL l = NIL DO
eltTag: ROPE ← Convert.RopeFromAtom[l.first.id];
eltRope: ROPE ← RopeFromExpr[l.first.expression];
ropeVal ← Rope.Cat[ropeVal, "{", eltTag, " "];
ropeVal ← Rope.Cat[ropeVal, eltRope, "}"];
IF l.rest # NIL THEN ropeVal ← Rope.Cat[ropeVal, " "];
ENDLOOP;
ropeVal ← Rope.Cat[ropeVal, ")"];
RETURN[ropeVal];
};
ENDCASE => ERROR;
};
ExprFromRope: PUBLIC PROC[r: ROPE] RETURNS[EXPR] ~ {
effects: Parses r as an EXPR in canonical format output by RopeFromExpr[].
SIGNALS parseError if r is malformed.
expr: EXPR ← ExprFromStream[IO.RIS[r] ! parseError => {ERROR parseError}];
RETURN[expr];
};
ExprFromStream: PROC[stream: IO.STREAM] RETURNS[EXPR] ~ {
effects: Parses stream as an EXPR in canonical format output by RopeFromExpr[].
SIGNALS parseError if stream is malformed.
local declarations
c: CHAR; -- one char buffer
exprFlavor: ROPE ← ""; -- MTRX, CMPD, or ATOM
class: ATOM; -- class name (atom, matrix, or compound)
bail out if anything at all goes wrong
{
ENABLE IO.Error, IO.EndOfStream, badAtomClass, badCompoundClass, badMatrixClass => {
ERROR parseError;
};
[] ← IO.SkipWhitespace[stream];
read initial open paren
c ← IO.GetChar[stream];
IF c # '( THEN ERROR parseError;
read expression type: MTRX, ATOM, or CMPD
FOR i:NAT IN [1..4] DO
exprFlavor ← Rope.Cat[exprFlavor, Rope.FromChar[IO.GetChar[stream]]];
ENDLOOP;
SELECT TRUE FROM
Rope.Equal[exprFlavor, "ATOM", FALSE] => {
local declarations
value: ROPENIL; -- atom value
parse atomic expression
[] ← IO.SkipWhitespace[stream];
class ← IO.GetAtom[stream]; -- get atom class name
[] ← IO.SkipWhitespace[stream];
value ← IO.GetRopeLiteral[stream]; -- get atom value
[] ← IO.SkipWhitespace[stream];
c ← IO.GetChar[stream];
IF c # ') THEN ERROR parseError; -- read closing paren
RETURN[MakeAtomicExpr[class, value]];
};
Rope.Equal[exprFlavor, "CMPD", FALSE] => {
local declarations
argExprs: LIST OF TaggedMathExpr ← NIL; -- cons up list of argument subexprs
argName: ATOM; -- current argument identifier
argExpr: EXPRNIL;
done: BOOLFALSE;
parse compound expression
[] ← IO.SkipWhitespace[stream];
class ← IO.GetAtom[stream]; -- get compound class name
[] ← IO.SkipWhitespace[stream];
get each argument to compound class op
WHILE ~done DO
c ← IO.GetChar[stream];
IF c # '{ THEN ERROR parseError; -- get argument open brace
[] ← IO.SkipWhitespace[stream];
argName ← IO.GetAtom[stream]; -- get argument name
[] ← IO.SkipWhitespace[stream];
make recursive call to get argExpr as an EXPR
argExpr ← ExprFromStream[stream ! parseError => {ERROR parseError}];
argExprs ← CONS[[argName, argExpr], argExprs]; -- add to list of arguments
[] ← IO.SkipWhitespace[stream];
c ← IO.GetChar[stream];
IF c # '} THEN ERROR parseError; -- get argument close brace
[] ← IO.SkipWhitespace[stream];
c ← IO.PeekChar[stream];
IF c = ') THEN done ← TRUE; -- done reading arguments if next char is rparen
ENDLOOP;
c ← IO.GetChar[stream]; -- read the ')
IF c # ') THEN ERROR parseError; -- I'm paranoid
RETURN[MakeCompoundExpr[class, argExprs]];
};
Rope.Equal[exprFlavor, "MTRX", FALSE] => {
local declarations
nRows, nCols: NAT ← 0;
element: EXPRNIL;
eltName: ATOM;
elements: LIST OF TaggedMathExpr ← NIL;
done: BOOLFALSE;
parse matrix expression
[] ← IO.SkipWhitespace[stream];
class ← IO.GetAtom[stream]; -- get matrix class name
[] ← IO.SkipWhitespace[stream];
get matrix size
c ← IO.GetChar[stream];
IF c # '[ THEN ERROR parseError; -- get matrix size open bracket
[] ← IO.SkipWhitespace[stream];
nRows ← IO.GetCard[stream]; -- get #rows
[] ← IO.SkipWhitespace[stream];
nCols ← IO.GetCard[stream]; -- get #cols
[] ← IO.SkipWhitespace[stream];
c ← IO.GetChar[stream];
IF c # '] THEN ERROR parseError; -- get matrix size closed bracket
[] ← IO.SkipWhitespace[stream];
get each element in matrix
WHILE ~done DO
c ← IO.GetChar[stream];
IF c # '{ THEN ERROR parseError; -- get element open brace
[] ← IO.SkipWhitespace[stream];
eltName ← IO.GetAtom[stream]; -- get element name
[] ← IO.SkipWhitespace[stream];
make recursive call to get argExpr as an EXPR
element ← ExprFromStream[stream ! parseError => {ERROR parseError}];
elements ← CONS[[eltName, element], elements]; -- add to list of elements
[] ← IO.SkipWhitespace[stream];
c ← IO.GetChar[stream];
IF c # '} THEN ERROR parseError; -- get element close brace
[] ← IO.SkipWhitespace[stream];
c ← IO.PeekChar[stream];
IF c = ') THEN done ← TRUE; -- done reading elements if next char is rparen
ENDLOOP;
c ← IO.GetChar[stream]; -- read the ')
IF c # ') THEN ERROR parseError; -- I'm paranoid
RETURN[MakeMatrixExpr[class, nRows, nCols, elements]];
};
ENDCASE => ERROR parseError;
}; -- end of enable scope
};
Selectors
GetType: PUBLIC PROC[expr: EXPR] RETURNS[ExprFlavors] ~ {
effect: Returns atom if expr is an AtomEXPR,
Returns compound if expr is a CompoundEXPR
WITH expr SELECT FROM
a: AtomEXPR => RETURN[atom];
c: CompoundEXPR => RETURN[compound];
m: MatrixEXPR => RETURN[matrix];
ENDCASE => ERROR;
};
GetAtomClass: PUBLIC PROC[expr: AtomEXPR] RETURNS[AtomClass] ~ {
effects: Returns the class of atomic expression expr.
RETURN[expr.class];
};
GetAtomExpr: PUBLIC PROC[expr: EXPR] RETURNS[AtomEXPR] ~ {
effects: If expr.Type = atom, returns atomic expression.
Otherwise SIGNALS wrongExprType
WITH expr SELECT FROM
a: AtomEXPR => RETURN[a];
c: CompoundEXPR => ERROR wrongExprType;
m: MatrixEXPR => ERROR wrongExprType;
ENDCASE => ERROR;
};
GetValue: PUBLIC PROC[expr: AtomEXPR] RETURNS[ROPE] ~ {
effects: Returns the value of atomic expression expr.
RETURN[expr.value];
};
GetCompoundClass: PUBLIC PROC[expr: CompoundEXPR] RETURNS[CompoundClass] ~ {
effects: Returns the class of compound expression expr.
RETURN[expr.class];
};
GetCompoundExpr: PUBLIC PROC[expr: EXPR] RETURNS[CompoundEXPR] ~ {
effects: If expr.Type[] = compound, returns compound expression.
Otherwise SIGNALS wrongExprType
WITH expr SELECT FROM
a: AtomEXPR => ERROR wrongExprType;
c: CompoundEXPR => RETURN[c];
m: MatrixEXPR => ERROR wrongExprType;
ENDCASE => ERROR;
};
GetMatrixExpr: PUBLIC PROC[expr: EXPR] RETURNS[MatrixEXPR] ~ {
effects: IF expr.Type[] = matrix, returns matrix expression
Otherwise SIGNALS wrongExprType
WITH expr SELECT FROM
a: AtomEXPR => ERROR wrongExprType;
c: CompoundEXPR => ERROR wrongExprType;
m: MatrixEXPR => RETURN[m];
ENDCASE => ERROR;
};
GetSubExprs: PUBLIC PROC[expr: CompoundEXPR] RETURNS[LIST OF TaggedMathExpr] ~ {
effects: Returns the subexpressions for compound expression expr.
RETURN[expr.subExprs];
};
GetMatrixElements: PUBLIC PROC[expr: MatrixEXPR]
RETURNS[LIST OF TaggedMathExpr] ~ {
effects: Returns the rows of expression for matrix expression expr.
RETURN[expr.elements];
};
GetMatrixSize: PUBLIC PROC[expr: MatrixEXPR] RETURNS[NAT, NAT] ~ {
effects: Returns the size (dimensions) of expr as [nRows, nCols]
RETURN[expr.nRows, expr.nCols];
};
GetMatrixClass: PUBLIC PROC[expr: MatrixEXPR] RETURNS[MatrixClass] ~ {
effects: Returns the flavor of expr.
RETURN[expr.class];
};
List Selectors
GetTaggedExpr: PUBLIC PROC[tag: ATOM, exprs: LIST OF TaggedMathExpr] RETURNS[TaggedMathExpr] ~ {
effects: Returns the TaggedMathExpr in exprs associated with tag.
SIGNALS exprNotFound if no association exists.
cdr down list looking for tag
FOR l: LIST OF TaggedMathExpr ← exprs, l.rest UNTIL l = NIL DO
IF l.first.id = tag THEN RETURN[l.first];
ENDLOOP;
not found, so complain
ERROR exprNotFound;
};
Signals & Errors
badAtomClass: PUBLIC ERROR = CODE;
badCompoundClass: PUBLIC ERROR = CODE;
badMatrixClass: PUBLIC ERROR = CODE;
badExprs: PUBLIC ERROR[reason: ATOM] = CODE;
exprNotFound: PUBLIC ERROR = CODE;
wrongExprType: PUBLIC ERROR = CODE;
parseError: PUBLIC ERROR = CODE;
END.