MathExprImpl.mesa
Carl Waldspurger, August 23, 1986 4:41:31 pm PDT
Manipulate EXPR's. Create EXPR Classes.
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 ~
Type 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;
Additions 3/2/87
EXPR: TYPE ~ MathExpr.EXPR;
MathExprRep: TYPE ~ MathExpr.MathExprRep;
AtomEXPR: TYPE ~ MathExpr.AtomEXPR;
CompoundEXPR: TYPE ~ MathExpr.CompoundEXPR;
MatrixEXPR: TYPE ~ MathExpr.MatrixEXPR;
Private Type Rep -- commented out 3/2/87
A Math Expression is either an atomic, compound, or matrix 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;
Expression Class 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, cvtReduceRule, cvtSMPRule, cvtOtherRule: 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, cvtReduceRope: cvtReduceRule, cvtSMPRope: cvtSMPRule, cvtOtherRope: cvtOtherRule]]];
};
MakeCompoundClass:
PUBLIC
PROC[name:
ATOM, formatClass: FormatClass, description:
ROPE, args:
LIST
OF Argument, syms:
LIST
OF Symbol, boxRule: CompoundBoxProc, compBox: CompositionProc, cvtAS, cvtReduce, cvtSMP, cvtOther:
ROPE ←
NIL]
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, cvtReduce: cvtReduce, cvtSMP: cvtSMP, cvtOther: cvtOther]]];
};
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]]];
};
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:
PUBLIC 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: ROPE ← NIL; -- 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: EXPR ← NIL;
done: BOOL ← FALSE;
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: EXPR ← NIL;
eltName: ATOM;
elements, elementsPtr: LIST OF TaggedMathExpr ← NIL;
done: BOOL ← FALSE;
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
make recursive call to get argExpr as an EXPR -- changed 3/4/87
element ← ExprFromStream[stream ! parseError => {ERROR parseError}];
IF elements=NIL THEN elements ← elementsPtr ← LIST[[eltName, element]] ELSE elementsPtr ← elementsPtr.rest ← LIST[[eltName, element]];
[] ← 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
Expression 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;