MathExprClassesArithmetic.mesa
Carl Waldspurger, August 30, 1986 7:12:37 pm PDT
Bier, November 20, 1986 2:02:38 pm PST
Arnon, March 24, 1987 4:15:37 pm PST
DIRECTORY
MathExpr,
MathRules,
MathDB,
MathTypes,
MathBox,
Imager,
Rope,
Vector,
MathConstructors;
MathExprClassesArithmetic: CEDAR PROGRAM
IMPORTS MathBox, MathRules, MathExpr,
MathDB, MathConstructors
~
BEGIN
Type Abbreviations from Imported Interfaces
EXPR: TYPE ~ MathExpr.EXPR;
BOX: TYPE ~ MathBox.BOX;
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector.VEC;
CompoundBoxProc: TYPE ~ MathRules.CompoundBoxProc;
CompositionProc: TYPE ~ MathRules.CompositionProc;
Alignment2D: TYPE ~ MathRules.Alignment2D;
Offset: TYPE ~ MathRules.Offset;
Size: TYPE ~ MathRules.Size;
Argument: TYPE ~ MathExpr.Argument;
Symbol: TYPE ~ MathExpr.Symbol;
CompoundClass: TYPE ~ MathExpr.CompoundClass;
FormatClass: TYPE ~ MathTypes.FormatClass;
Style: TYPE ~ MathTypes.Style;
Procedure Abbreviations from Imported Interfaces
MakeArgument: PROC[name: ATOM, aliases: LIST OF ATOM, size: Size] RETURNS[Argument] ~ MathExpr.MakeArgument;
MakeSymbol: PROC[name: ATOM, aliases: LIST OF ATOM, size: Size, value: EXPR] RETURNS[Symbol] ~ MathExpr.MakeSymbol;
MakeCompoundClass: PROC[name: ATOM, formatClass: FormatClass, description: ROPE, args: LIST OF Argument, syms: LIST OF Symbol, boxRule: CompoundBoxProc, compBox: CompositionProc, cvtAS, cvtReduce, cvtSMP, cvtOther: ROPENIL] RETURNS[CompoundClass] ~ MathExpr.MakeCompoundClass;
Constants
smallGap: REAL = 0.05;
medGap: REAL = 0.10;
bigGap: REAL = 0.25;
Box Procs for Compound Expr Classes
FixedSizeBoxRule: CompoundBoxProc ~ {
effects: Returns unaltered boxes (i.e. no resizing takes place)
RETURN[boxes];
};
AbsBoxRule: CompoundBoxProc ~ {
effects: Sizes boxes for expr of form ($abs $a)
leftBox: BOX ← MathBox.GetBox[$leftAbs, boxes];
rightBox: BOX ← MathBox.GetBox[$rightAbs, boxes];
aBox: BOX ← MathBox.GetBox[$a, boxes];
right and left absolute value bars must be as tall as expression "a"
scaleFactor: REALMAX[0.25, 1.1 * aBox.Height[] / leftBox.Height[] ]; -- don't allow scaling to less than 1/4 size
leftBox ← MathBox.Scale[leftBox, [1.2 * scaleFactor, scaleFactor]]; -- make wider than tall
rightBox ← MathBox.Scale[rightBox, [1.2 * scaleFactor, scaleFactor]];
RETURN[LIST[aBox, leftBox, rightBox]];
};
FractionBoxRule: CompoundBoxProc ~ {
effects: Sizes boxes for expr of form ($fractionBar $numerator $denominator)
should ENABLE noSuchBox
fbarBox: BOX ← MathBox.GetBox[$fractionBar, boxes];
numBox: BOX ← MathBox.GetBox[$numerator, boxes];
denomBox: BOX ← MathBox.GetBox[$denominator, boxes];
topSpaceBox: BOX ← MathBox.GetBox[$topSpace, boxes];
bottomSpaceBox: BOX ← MathBox.GetBox[$bottomSpace, boxes];
fraction bar must be as wide as the wider of numerator, denominator
scaleX: REAL ← 1.1 * MAX[numBox.Width[], denomBox.Width[] ] / fbarBox.Width[];
adjust fbarBox extents
fbarBox ← MathBox.Scale[fbarBox, [scaleX, 1.0]];
RETURN[LIST[fbarBox, numBox, denomBox, topSpaceBox, bottomSpaceBox]];
};
Composition Procs for Compound Expr Classes
PowCompRule: CompositionProc ~ {
effects: Composes layout for expr of form ($exponent $base)
tempBox: BOX;
tempBoxes: LIST OF BOX;
vertOffsetExponent, vertOffsetBase, horizOffsetBase: Offset;
alignments: LIST OF Alignment2D ← NIL;
baseBox: BOX ← MathBox.GetBox[$base, boxes];
exponentBox: BOX ← MathBox.GetBox[$exponent, boxes];
hintBox: BOX ← baseBox.SuperscriptHint[]; -- hint about where to place subscript w/i base
IF hintBox # NIL THEN {
hint, so align exponent with base via hintBox
horizOffsetBase ← [origin, hintBox.Offset[].x + hintBox.Extents[].rightExtent];
IF (hintBox.Height[] * baseBox.Height[]) > exponentBox.Height[] THEN {
vertOffsetExponent ← [bottom, 0.2];
top of hint box inside base box
vertOffsetBase ← [origin, hintBox.Offset[].y + hintBox.Extents[].ascent];
}
ELSE {
vertOffsetExponent ← [bottom];
0.8 way up on hint box
vertOffsetBase ← [origin, 0.8 * (hintBox.Offset[].y + hintBox.Extents[].ascent)];
};
}
ELSE {
no hint, so align exponent directly with base
horizOffsetBase ← [right];
IF baseBox.Height[] > exponentBox.Height[] THEN {
vertOffsetExponent ← [bottom, 0.2];
vertOffsetBase ← [top];
}
ELSE {
vertOffsetExponent ← [bottom];
vertOffsetBase ← [top, -0.2];
};
};
alignments ← LIST[
[$exponent,
[$base, [left], horizOffsetBase],
[$base, vertOffsetExponent, vertOffsetBase]]];
[tempBox, tempBoxes] ←
MathRules.Compose[boxes, alignments, [$base, [origin]], [$base, [origin]]];
RETURN[tempBox, tempBoxes];
};
FractionCompRule: CompositionProc ~ {
effects: Composes layout for expr of form ($fractionBar $numerator $denominator)
tempBox: BOX;
tempBoxes: LIST OF BOX;
alignments: LIST OF Alignment2D ← LIST[
[$topSpace,
[$fractionBar, [center], [center]],
[$fractionBar, [bottom], [top]]],
[$bottomSpace,
[$fractionBar, [center], [center]],
[$fractionBar, [top], [bottom]]],
[$numerator,
[$fractionBar, [center], [center]],
[$topSpace, [bottom], [top]]],
[$denominator,
[$fractionBar, [center], [center]],
[$bottomSpace, [top], [bottom]]]];
[tempBox, tempBoxes] ←
MathRules.Compose[boxes, alignments, [$fractionBar, [origin]],
[$fractionBar, [origin]]];
RETURN[tempBox, tempBoxes];
};
UnaryOpCompRule: CompositionProc ~ {
effects: Composes layout for expr of form ($aliasUnaryOp $aliasA).
tempBox: BOX;
tempBoxes: LIST OF BOX;
alignments: LIST OF Alignment2D ← LIST[
[$aliasSpace,
[$aliasUnaryOp, [left], [right]],
[$aliasUnaryOp, [origin], [origin]]],
[$aliasA,
[$aliasSpace, [left], [right]],
[$aliasSpace, [origin], [origin]]]];
[tempBox, tempBoxes] ←
MathRules.Compose[boxes, alignments, [$aliasUnaryOp, [origin]],
[$aliasUnaryOp, [origin]]];
RETURN[tempBox, tempBoxes];
};
BinaryOpCompRule: CompositionProc ~ {
effects: Composes layout for expr of form ($aliasBinOp $aliasA $aliasB) with
symbols $aliasLeftSpace & $aliasRightSpace.
tempBox: BOX;
tempBoxes: LIST OF BOX;
leftVertOffsetA, leftVertOffsetOp, rightVertOffsetB, rightVertOffsetOp: Offset;
alignments: LIST OF Alignment2D;
set vertical offset depending on format classes of A & B arguments
SELECT MathBox.GetBox[$aliasA, boxes].FormatClass[] FROM
over => {
leftVertOffsetA ← [origin];
leftVertOffsetOp ← [center];
};
matrix => {
leftVertOffsetA ← [center];
leftVertOffsetOp ← [center];
};
ENDCASE => {
leftVertOffsetA ← [origin];
leftVertOffsetOp ← [origin];
};
SELECT MathBox.GetBox[$aliasB, boxes].FormatClass[] FROM
over => {
rightVertOffsetB ← [origin];
rightVertOffsetOp ← [center];
};
matrix => {
rightVertOffsetB ← [center];
rightVertOffsetOp ← [center];
};
ENDCASE => {
rightVertOffsetB ← [origin];
rightVertOffsetOp ← [origin];
};
alignments ← LIST[
[$aliasLeftSpace,
[$aliasBinOp, [right], [left]],
[$aliasBinOp, [origin], [origin]]],
[$aliasA,
[$aliasLeftSpace, [right], [left]],
[$aliasBinOp, leftVertOffsetA, leftVertOffsetOp]],
[$aliasRightSpace,
[$aliasBinOp, [left], [right]],
[$aliasBinOp, [origin], [origin]]],
[$aliasB,
[$aliasRightSpace, [left], [right]],
[$aliasBinOp, rightVertOffsetB, rightVertOffsetOp]]];
[tempBox, tempBoxes] ←
MathRules.Compose[boxes, alignments, [$aliasA, [origin]], [$aliasBinOp, [origin]]];
RETURN[tempBox, tempBoxes];
};
FactorialCompRule: CompositionProc ~ {
effects: Composes layout for expr of form ($bang $a $space)
tempBox: BOX;
tempBoxes: LIST OF BOX;
alignments: LIST OF Alignment2D ← LIST[
[$space,
[$a, [left], [right]],
[$a, [origin], [origin]]],
[$bang,
[$space, [left], [right]],
[$a, [origin], [origin]]]];
[tempBox, tempBoxes] ←
MathRules.Compose[boxes, alignments, [$a, [origin]], [$a, [origin]]];
RETURN[tempBox, tempBoxes];
};
AbsCompRule: CompositionProc ~ {
effects: Composes layout for expr of form ($abs $a) with symbols
$absBar and $absBar
tempBox: BOX;
tempBoxes: LIST OF BOX;
alignments: LIST OF Alignment2D ← LIST[
[$leftAbs,
[$a, [right], [left]],
[$a, [center], [center]]],
[$rightAbs,
[$a, [left], [right]],
[$a, [center], [center]]]];
[tempBox, tempBoxes] ←
MathRules.Compose[boxes, alignments, [$leftAbs, [origin]],
[$self, [center, -0.25]]];
RETURN[tempBox, tempBoxes];
};
Class Constructors
MakeUnaryOpClass: PUBLIC PROC[class, op, arg: ATOM, operation: EXPR, description: ROPE, cvtAS, cvtReduce, cvtSMP, cvtOther: ROPENIL] RETURNS[CompoundClass] ~ {
effects: Creates and returns standard unary operation compound class named "class".
The alignment is "operation arg"; alignment is thru baselines.
Both op, arg are of fixed size "normal".
argArg: Argument ← MakeArgument[arg, LIST[$aliasA, $aliasHot], normal];
spaceSym: Symbol ← MakeSymbol[$Space, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$medium]];
unaryOpSym: Symbol ← MakeSymbol[op, LIST[$aliasUnaryOp], normal, operation];
RETURN[MakeCompoundClass[class, unaryOp, description, LIST[argArg], LIST[unaryOpSym, spaceSym], FixedSizeBoxRule, UnaryOpCompRule, cvtAS, cvtReduce, cvtSMP, cvtOther]];
};
MakeBinOpClass: PUBLIC PROC[class, op, a, b: ATOM, operation: EXPR,
description: ROPE, cvtAS, cvtReduce, cvtSMP, cvtOther: ROPENIL] RETURNS[CompoundClass] ~ {
effects: Creates and returns standard binary operation compound class named "class".
The alignment is "a operation b"; alignment is thru baselines.
All of a, b, op are of fixed size "normal".
aArg: Argument ← MakeArgument[a, LIST[$aliasA, $aliasHot], normal];
bArg: Argument ← MakeArgument[b, LIST[$aliasB], normal];
opSym: Symbol ← MakeSymbol[op, LIST[$aliasBinOp], normal, operation];
leftSpace: Symbol ← MakeSymbol[$leftThinSpace, LIST[$aliasLeftSpace], normal, MathConstructors.MakeSpace[$thin]];
rightSpace: Symbol ← MakeSymbol[$rightThinSpace, LIST[$aliasRightSpace], normal, MathConstructors.MakeSpace[$thin]];
RETURN[MakeCompoundClass[class, binaryOp, description, LIST[aArg, bArg], LIST[opSym, leftSpace, rightSpace], FixedSizeBoxRule, BinaryOpCompRule, cvtAS, cvtReduce, cvtSMP, cvtOther]];
};
Signals & Errors
wrongBoxType: PUBLIC ERROR = CODE;
Define & Install Expression Classes
InstallArithmeticClassesA: PROC [] ~ {
local declarations
sumClass, fractionClass, differenceClass, powClass, productClass, negationClass, inverseClass: CompoundClass;
baseArg, exponentArg, numeratorArg, denominatorArg: Argument;
lineSym, numerSpSym, denomSpSym: Symbol;
define info for "pow base exponent" & "subscript base subscript" & "hat base hat"
baseArg ← MakeArgument[$base, LIST[$aliasA, $aliasHot], normal];
exponentArg ← MakeArgument[$exponent, LIST[$aliasB], script];
define info for "fraction numerator denominator"
numeratorArg ← MakeArgument[$numerator, LIST[$aliasA, $aliasHot], normal];
denominatorArg ← MakeArgument[$denominator, LIST[$aliasB], normal];
denomSpSym ← MakeSymbol[$bottomSpace, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$thin]];
numerSpSym ← MakeSymbol[$topSpace, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$thin]];
lineSym ← MakeSymbol[$fractionBar, LIST[$aliasLine], normal, MathConstructors.MakeLine[]];
define compound classes
inverseClass ← MakeUnaryOpClass[$invert, $inv, $a, MathConstructors.MakePlainRope["inv"], "inv a", "recip($a)", "$a ** (-1)"];
negationClass ← MakeUnaryOpClass[$negation, $minus, $a, MathConstructors.MakePlainSym['-], "-a", "-$a", "minus($a)", "Minus[$a]"];
sumClass ← MakeBinOpClass[$sum, $plus, $addend, $augend, MathConstructors.MakePlainSym['+], "a + b", "$addend + $augend", "plus($addend, $augend)", "Plus[$addend, $augend]"];
differenceClass ← MakeBinOpClass[$difference, $minus, $subtrahend, $minuend, MathConstructors.MakePlainSym['-], "a - b", "$subtrahend - $minuend", "difference($subtrahend, $minuend)", "Minus[$subtrahend, $minuend]"];
productClass ← MakeBinOpClass[$product, $times, $multiplier, $multiplicand, MathConstructors.MakeSpace[$product], "a * b", "$multiplier * $multiplicand", "times($multiplier, $multiplicand)", "Mult[$multiplier, $multiplicand]"];
powClass ← MakeCompoundClass[$pow, other, "a^b", LIST[baseArg, exponentArg], NIL, FixedSizeBoxRule, PowCompRule, "$base ** $exponent", "expt($base, $exponent)", "Pow[$base, $exponent]"];
fractionClass ← MakeCompoundClass[$fraction, over, "a / b", LIST[numeratorArg, denominatorArg], LIST[lineSym, numerSpSym, denomSpSym], FractionBoxRule, FractionCompRule, "$numerator / $denominator", "quotient($numerator, $denominator)", "Div[$numerator, $denominator]"];
Register compound classes in user-friendly order
MathDB.InstallCompoundClass[sumClass];
MathDB.AddOperator[sumClass, $Arithmetic];
MathDB.InstallCompoundClass[negationClass];
MathDB.AddOperator[negationClass, $Arithmetic];
MathDB.InstallCompoundClass[differenceClass];
MathDB.AddOperator[differenceClass, $Arithmetic];
MathDB.InstallCompoundClass[productClass];
MathDB.AddOperator[productClass, $Arithmetic];
MathDB.InstallCompoundClass[gcdClass];
MathDB.AddOperator[gcdClass, $Arithmetic];
MathDB.InstallCompoundClass[powClass];
MathDB.AddOperator[powClass, $Arithmetic];
MathDB.InstallCompoundClass[fractionClass];
MathDB.AddOperator[fractionClass, $Arithmetic];
MathDB.InstallCompoundClass[inverseClass];
MathDB.AddOperator[inverseClass, $Arithmetic];
};
InstallArithmeticClassesAA: PROC [] ~ {
local declarations
absClass, factorialClass: CompoundClass;
aAbsArg, factorialArg: Argument;
leftAbsSym, rightAbsSym, factorialSym, factorialSpSym: Symbol;
define info for "| a |"
aAbsArg ← MakeArgument[$a, LIST[$aliasA, $aliasHot], normal];
leftAbsSym ← MakeSymbol[$leftAbs, NIL, normal, MathConstructors.MakePlainSym['\174]];
rightAbsSym ← MakeSymbol[$rightAbs, NIL, normal, MathConstructors.MakePlainSym['\174]];
define into for factorial
factorialArg ← MakeArgument[$a, LIST[$aliasA, $aliasHot], normal];
factorialSym ← MakeSymbol[$bang, NIL, normal, MathConstructors.MakePlainSym['!]];
factorialSpSym ← MakeSymbol[$space, LIST[$aliasSpace], normal, MathConstructors.MakeSpace[$thin]];
absClass ← MakeCompoundClass[$abs, paren, "| a |", LIST[aAbsArg], LIST[leftAbsSym, rightAbsSym], AbsBoxRule, AbsCompRule, "| $a |"];
factorialClass ← MakeCompoundClass[$factorial, other, "a!", LIST[factorialArg], LIST[factorialSym, factorialSpSym], FixedSizeBoxRule, FactorialCompRule, "$a!"];
MathDB.InstallCompoundClass[absClass];
MathDB.AddOperator[absClass, $Arithmetic];
MathDB.InstallCompoundClass[factorialClass];
MathDB.AddOperator[factorialClass, $Arithmetic];
};
Install Classes Defined in this Module
InstallArithmeticClassesA[];
InstallArithmeticClassesAA[];
END.