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;
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:
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]]];
};
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: 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: 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
[] ← 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];
};
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;