<> <> DIRECTORY MathExpr, MathRules, MathDB, MathTypes, MathBox, ImagerFont, ImagerTransformation, Imager, Rope USING [ROPE, Fetch, Length, Substr, Equal, FromChar], Vector USING [VEC], Convert USING [RopeFromReal, AtomFromRope, RopeFromAtom], MathConstructors; MathConstructorsImpl: CEDAR PROGRAM IMPORTS MathBox, MathRules, ImagerFont, Imager, ImagerTransformation, MathExpr, MathDB, Convert, Rope EXPORTS MathConstructors ~ BEGIN <> EXPR: TYPE ~ MathExpr.EXPR; BOX: TYPE ~ MathBox.BOX; ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector.VEC; AtomBoxProc: TYPE ~ MathRules.AtomBoxProc; AtomPaintProc: TYPE ~ MathRules.AtomPaintProc; AtomToASRopeProc: TYPE ~ MathRules.AtomToASRopeProc; 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; AtomClass: TYPE ~ MathExpr.AtomClass; AtomFlavor: TYPE ~ MathExpr.AtomFlavor; CompoundClass: TYPE ~ MathExpr.CompoundClass; FormatClass: TYPE ~ MathTypes.FormatClass; MatrixClass: TYPE ~ MathExpr.MatrixClass; Style: TYPE ~ MathTypes.Style; <> 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; MakeAtomClass: PROC[name: ATOM, formatClass: FormatClass, flavor: AtomFlavor, style: Style, boxRule: AtomBoxProc, paintRule: AtomPaintProc, cvtASRule: AtomToASRopeProc _ NIL] RETURNS[AtomClass] ~ MathExpr.MakeAtomClass; MakeCompoundClass: PROC[name: ATOM, formatClass: FormatClass, description: ROPE, args: LIST OF Argument, syms: LIST OF Symbol, boxRule: CompoundBoxProc, compBox: CompositionProc, cvtAS: ROPE _ NIL] RETURNS[CompoundClass] ~ MathExpr.MakeCompoundClass; <> smallGap: REAL = 0.05; medGap: REAL = 0.10; bigGap: REAL = 0.25; <> <<>> <<>> <> <<>> GreekVarToASRope: AtomToASRopeProc ~ { IF value.Length[] < 1 THEN RETURN["unknown"] ELSE RETURN[CharToGreekName[value.Fetch[0]]]; }; PlaceHolderToASRope: AtomToASRopeProc ~ { RETURN["?"]; }; InfinityToASRope: AtomToASRopeProc ~ { RETURN["infinity"]; }; <> PaintChar: AtomPaintProc ~ { <> <> IF (absBox.Type[] # absolute) THEN ERROR wrongBoxType ELSE { font: ImagerFont.Font _ ImagerFont.Find[style.font]; extents: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[font, value]; xFactor: REAL _ absBox.Width[] / (extents.leftExtent + extents.rightExtent); yFactor: REAL _ absBox.Height[] / (extents.descent + extents.ascent); Imager.SetXY[context, absBox.Offset[]]; Imager.SetFont[context, ImagerFont.Modify[font, ImagerTransformation.Scale2[[xFactor, yFactor]]]]; Imager.ShowRope[context, value]; }; }; PaintOverlay: AtomPaintProc ~ { <> << This is useful for things like negated symbols (/ slashed through)... >> <<>> <> IF (absBox.Type[] # absolute) THEN ERROR wrongBoxType ELSE { font: ImagerFont.Font _ ImagerFont.Find[style.font]; extents: ImagerFont.Extents _ OverlayBox[value, style]; xFactor: REAL _ absBox.Width[] / (extents.rightExtent + extents.leftExtent); yFactor: REAL _ absBox.Height[] / (extents.ascent + extents.descent); <> font _ ImagerFont.Modify[font, ImagerTransformation.Scale2[[xFactor, yFactor]]]; <> FOR i:INT IN [0..value.Length[]-1] DO char: ROPE _ value.Substr[i, 1]; box: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[font, char]; position: VEC _ [MathRules.AlignHorizontal[box, [center], absBox, [center]], MathRules.AlignVertical[box, [center], absBox, [center]]]; Imager.SetXY[context, position]; Imager.SetFont[context, font]; Imager.ShowRope[context, char]; ENDLOOP; }; }; PaintRope: AtomPaintProc ~ { <> <> IF (absBox.Type[] # absolute) THEN ERROR wrongBoxType ELSE { font: ImagerFont.Font _ ImagerFont.Find[style.font]; extents: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[font, value]; xFactor: REAL _ absBox.Width[] / (extents.rightExtent + extents.leftExtent); yFactor: REAL _ absBox.Height[] / (extents.ascent + extents.descent); Imager.SetXY[context, absBox.Offset[]]; Imager.SetFont[context, ImagerFont.Modify[font, ImagerTransformation.Scale2[[xFactor, yFactor]]]]; Imager.ShowRope[context, value]; }; }; PaintLine: AtomPaintProc ~ { <> <> r: Imager.Rectangle _ [x: absBox.Offset[].x + absBox.Extents[].leftExtent, y: absBox.Offset[].y + absBox.Extents[].descent, w: absBox.Width[], h: absBox.Height[]]; Imager.MaskRectangle[context, r]; }; PaintSpace: AtomPaintProc ~ { <> RETURN; }; <> LineBox: AtomBoxProc ~ { <> << Note that this is always a dummy value>> <> RETURN[[leftExtent: 0.0, rightExtent: 1.0, descent: 0.0, ascent: 0.03]]; }; CharBox: AtomBoxProc ~ { <> font: ImagerFont.Font _ ImagerFont.Scale[ImagerFont.Find[style.font], style.scale]; RETURN[ImagerFont.RopeBoundingBox[font, value]]; }; OverlayBox: AtomBoxProc ~ { <> font: ImagerFont.Font _ ImagerFont.Scale[ImagerFont.Find[style.font], style.scale]; farLeft, farRight, farUp, farDown: REAL _ 0.0; -- extreme edges of overlayed extents FOR i:INT IN [0..value.Length[]-1] DO box: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[font, value.Substr[i, 1]]; farLeft _ MAX[farLeft, box.leftExtent]; farRight _ MAX[farRight, box.rightExtent]; farUp _ MAX[farUp, box.ascent]; farDown _ MAX[farDown, box.descent]; ENDLOOP; RETURN[[leftExtent: farLeft, rightExtent: farRight, descent: farDown, ascent: farUp]]; }; RopeBox: AtomBoxProc ~ { <> font: ImagerFont.Font _ ImagerFont.Scale[ImagerFont.Find[style.font], style.scale]; RETURN[ImagerFont.RopeBoundingBox[font, value]]; }; SpaceBox: AtomBoxProc ~ { <> size: ATOM _ Convert.AtomFromRope[value]; RETURN[ SELECT size FROM $null => [leftExtent: 0.0, rightExtent: 0.001, descent: 0.0, ascent: 0.001], $thin => [leftExtent: 0.0, rightExtent: 0.05, ascent: 0.05, descent: 0.0], $medium => [leftExtent: 0.0, rightExtent: 0.12, ascent: 0.12, descent: 0.0], $thick => [leftExtent: 0.0, rightExtent: 0.25, ascent: 0.25, descent: 0.0], $veryThick => [leftExtent: 0.0, rightExtent: 0.4, ascent: 0.4, descent: 0.0], $matrix => [leftExtent: 0.0, rightExtent: 0.9, ascent: 0.65, descent: 0.0], $limit => [leftExtent: 0.0, rightExtent: 0.25, ascent: 0.12, descent: 0.0], $product => [leftExtent: 0.0, rightExtent: 0.001, ascent: 0.21, descent: -0.19] <> ENDCASE => [leftExtent: 0.0, rightExtent: 0.05, ascent: 0.05, descent: 0.0] ]; }; <> <> FixedSizeBoxRule: CompoundBoxProc ~ { <> RETURN[boxes]; }; FractionBoxRule: CompoundBoxProc ~ { <> <> 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]; <> scaleX: REAL _ 1.1 * MAX[numBox.Width[], denomBox.Width[]] / fbarBox.Width[]; <> fbarBox _ MathBox.Scale[fbarBox, [scaleX, 1.0]]; RETURN[LIST[fbarBox, numBox, denomBox, topSpaceBox, bottomSpaceBox]]; }; ParenBoxRule: CompoundBoxProc ~ { <> <<>> leftParenBox: BOX _ MathBox.GetBox[$leftParen, boxes]; rightParenBox: BOX _ MathBox.GetBox[$rightParen, boxes]; aBox: BOX _ MathBox.GetBox[$a, boxes]; <> scaleFactor: REAL _ MAX[0.25, 1.1 * aBox.Height[] / leftParenBox.Height[]]; leftParenBox _ MathBox.Scale[leftParenBox, [scaleFactor, scaleFactor]]; rightParenBox _ MathBox.Scale[rightParenBox, [scaleFactor, scaleFactor]]; RETURN[LIST[aBox, leftParenBox, rightParenBox]]; }; NRadicalBoxRule: CompoundBoxProc ~ { <> <> radRootBox: BOX _ MathBox.GetBox[$radRoot, boxes]; radLineBox: BOX _ MathBox.GetBox[$radLine, boxes]; nBox: BOX _ MathBox.GetBox[$n, boxes]; spaceBox: BOX _ MathBox.GetBox[$space, boxes]; radicandBox: BOX _ MathBox.GetBox[$radicand, boxes]; <> <> rootScale: REAL _ ((2 * spaceBox.Height[]) + radicandBox.Height[]) / radRootBox.Height[]; lineScale: VEC _ [radicandBox.Width[]/radLineBox.Width[], 1.0]; <> radRootBox _ MathBox.Scale[radRootBox, [rootScale, rootScale]]; radLineBox _ MathBox.Scale[radLineBox, lineScale]; RETURN[LIST[radRootBox, radLineBox, nBox, radicandBox, spaceBox]]; }; RadicalBoxRule: CompoundBoxProc ~ { <> <> radRootBox: BOX _ MathBox.GetBox[$radRoot, boxes]; radLineBox: BOX _ MathBox.GetBox[$radLine, boxes]; spaceBox: BOX _ MathBox.GetBox[$space, boxes]; radicandBox: BOX _ MathBox.GetBox[$radicand, boxes]; <> <> rootScale: REAL _ ((2 * spaceBox.Height[]) + radicandBox.Height[]) / radRootBox.Height[]; lineScale: VEC _ [radicandBox.Width[]/radLineBox.Width[], 1.0]; <> radRootBox _ MathBox.Scale[radRootBox, [rootScale, rootScale]]; radLineBox _ MathBox.Scale[radLineBox, lineScale]; RETURN[LIST[radRootBox, radLineBox, radicandBox, spaceBox]]; }; FunctionBoxRule: CompoundBoxProc ~ { <> <> lParenBox: BOX _ MathBox.GetBox[$leftParen, boxes]; rParenBox: BOX _ MathBox.GetBox[$rightParen, boxes]; spaceBox: BOX _ MathBox.GetBox[$space, boxes]; fBox: BOX _ MathBox.GetBox[$f, boxes]; argsBox: BOX _ MathBox.GetBox[$args, boxes]; <> <> scaleFactor: REAL _ MAX[1.0, 1.1 * argsBox.Height[] / lParenBox.Height[]]; lParenBox _ MathBox.Scale[lParenBox, [scaleFactor, scaleFactor]]; rParenBox _ MathBox.Scale[rParenBox, [scaleFactor, scaleFactor]]; <<>> RETURN[LIST[fBox, spaceBox, lParenBox, rParenBox, argsBox]]; }; <> PowCompRule: CompositionProc ~ { <> 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 { <> horizOffsetBase _ [origin, hintBox.Offset[].x + hintBox.Extents[].rightExtent]; IF (hintBox.Height[] * baseBox.Height[]) > exponentBox.Height[] THEN { vertOffsetExponent _ [bottom, 0.2]; <> 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 { <> 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]; }; SubscriptCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; vertOffsetSubscript, vertOffsetBase: Offset; alignments: LIST OF Alignment2D _ NIL; IF MathBox.GetBox[$base, boxes].Height[] > MathBox.GetBox[$subscript, boxes].Height[] THEN { vertOffsetSubscript _ [top, -0.2]; vertOffsetBase _ [bottom]; } ELSE { vertOffsetSubscript _ [top]; vertOffsetBase _ [bottom, +0.2]; }; alignments _ LIST[ [$subscript, [$base, [left], [right]], [$base, vertOffsetSubscript, vertOffsetBase]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$base, [origin]], [$base, [origin]]]; <> tempBox _ tempBox.ChangeSuperHint[MathBox.GetBox[$base, tempBoxes]]; RETURN[tempBox, tempBoxes]; }; FractionCompRule: CompositionProc ~ { <> 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]; }; ListCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$car, [$comma, [right], [left]], [$comma, [origin], [origin]]], [$space, [$comma, [left], [right]], [$comma, [origin], [origin]]], [$cdr, [$space, [left], [right]], [$comma, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$car, [origin]], [$comma, [origin]]]; RETURN[tempBox, tempBoxes]; }; FunctionCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$leftParen, [$args, [right], [left]], [$args, [center], [center]]], [$rightParen, [$args, [left], [right]], [$args, [center], [center]]], [$space, [$leftParen, [right], [left]], [$args, [origin], [origin]]], [$f, [$space, [right], [left]], [$args, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$f, [origin]], [$f, [origin]]]; RETURN[tempBox, tempBoxes]; }; LimitCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; limBox: BOX _ MathBox.GetBox[$lim, boxes]; approachesBox: BOX _ MathBox.GetBox[$approaches, boxes]; alignments: LIST OF Alignment2D; IF approachesBox.Width[] > limBox.Width[] THEN { alignments _ LIST[ [$space, [$of, [right], [left]], [$of, [center], [center]]], [$approaches, [$space, [right], [left]], [$space, [top], [bottom]]], [$lim, [$approaches, [center], [center]], [$space, [bottom], [top]]]]; } ELSE { alignments _ LIST[ [$space, [$of, [right], [left]], [$of, [center], [center]]], [$lim, [$space, [right], [left]], [$space, [bottom], [top]]], [$approaches, [$lim, [center], [center]], [$space, [top], [bottom]]]]; }; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$approaches, [origin]], [$of, [origin]]]; RETURN[tempBox, tempBoxes]; }; SummationCompRule: CompositionProc ~ { <> << $summand)>> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ NIL; vertSigmaOffset, vertSummandOffset: Offset; SELECT MathBox.GetBox[$summand, boxes].FormatClass[] FROM over => { vertSigmaOffset _ [center]; vertSummandOffset _ [center]; }; ENDCASE => { vertSummandOffset _ [origin]; vertSigmaOffset _ [center, -0.2]; }; alignments _ LIST[ [$lowerbound, [$sigma, [center], [center]], [$sigma, [top], [bottom, -smallGap]]], [$upperbound, [$sigma, [center], [center]], [$sigma, [bottom], [top, +smallGap]]], [$summand, [$sigma, [left], [right, medGap]], [$sigma, vertSummandOffset, vertSigmaOffset]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$sigma, [origin]], [$sigma, [center, -0.2]]]; RETURN[tempBox, tempBoxes]; }; NRadicalCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$radRoot, [$radicand, [right], [left]], [$radicand, [center], [center]]], [$space, [$radicand, [center], [center]], [$radicand, [bottom], [top]]], [$radLine, [$radRoot, [left], [right]], [$radRoot, [top], [top]]], [$n, [$radRoot, [right], [left, bigGap]], [$radRoot, [bottom], [center, +smallGap]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$n, [origin]], [$radicand, [origin]]]; RETURN[tempBox, tempBoxes]; }; RadicalCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$radRoot, [$radicand, [right], [left]], [$radicand, [center], [center]]], [$space, [$radicand, [center], [center]], [$radicand, [bottom], [top]]], [$radLine, [$radRoot, [left], [right]], [$radRoot, [top], [top]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$radicand, [origin]], [$radicand, [origin]]]; RETURN[tempBox, tempBoxes]; }; IntegrationCompRule: CompositionProc ~ { <> << $upperlimit $integrand $dx $wrt)>> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ NIL; vertIntegralOffset, vertIntegrandOffset: Offset; SELECT MathBox.GetBox[$integrand, boxes].FormatClass[] FROM over => { vertIntegralOffset _ [center]; vertIntegrandOffset _ [center]; }; ENDCASE => { vertIntegralOffset _ [center, -0.2]; vertIntegrandOffset _ [origin]; }; alignments _ LIST[ [$lowerlimit, [$integral, [right], [left, +bigGap]], [$integral, [top], [bottom, -smallGap]]], [$upperlimit, [$integral, [right], [right]], [$integral, [bottom], [top, +smallGap]]], [$integrand, [$integral, [left], [right]], [$integral, vertIntegrandOffset, vertIntegralOffset]], [$space, [$integrand, [left], [right]], [$integrand, [origin], [origin]]], [$dx, [$space, [left], [right]], [$space, [origin], [origin]]], [$wrt, [$dx, [left], [right]], [$dx, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$lowerlimit, [origin]], [$integral, [center, -0.2]]]; RETURN[tempBox, tempBoxes]; }; IndefiniteIntCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; vertIntegralOffset, vertIntegrandOffset: Offset; alignments: LIST OF Alignment2D _ NIL; SELECT MathBox.GetBox[$integrand, boxes].FormatClass[] FROM over => { vertIntegralOffset _ [center]; vertIntegrandOffset _ [center]; }; ENDCASE => { vertIntegralOffset _ [center, -0.2]; vertIntegrandOffset _ [origin]; }; alignments _ LIST[ [$integrand, [$integral, [left], [right]], [$integral, vertIntegrandOffset, vertIntegralOffset]], [$space, [$integrand, [left], [right]], [$integrand, [origin], [origin]]], [$dx, [$space, [left], [right,]], [$space, [origin], [origin]]], [$wrt, [$dx, [left], [right]], [$dx, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$integral, [origin]], [$integral, [center, -0.2]]]; RETURN[tempBox, tempBoxes]; }; UnaryOpCompRule: CompositionProc ~ { <> 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 ~ { <> << symbols $aliasLeftSpace & $aliasRightSpace.>> <<>> tempBox: BOX; tempBoxes: LIST OF BOX; leftVertOffsetA, leftVertOffsetOp, rightVertOffsetB, rightVertOffsetOp: Offset; alignments: LIST OF Alignment2D; <> 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]; }; RelationCompRule: CompositionProc ~ { <> << symbols $aliasLeftSpace & $aliasRightSpace.>> <<>> tempBox: BOX; tempBoxes: LIST OF BOX; leftVertOffsetLHS, leftVertOffsetRel, rightVertOffsetRHS, rightVertOffsetRel: Offset; alignments: LIST OF Alignment2D; <> SELECT MathBox.GetBox[$aliasLHS, boxes].FormatClass[] FROM over => { leftVertOffsetLHS _ [origin]; leftVertOffsetRel _ [center]; }; matrix => { leftVertOffsetLHS _ [center]; leftVertOffsetRel _ [center]; }; ENDCASE => { leftVertOffsetLHS _ [origin]; leftVertOffsetRel _ [origin]; }; SELECT MathBox.GetBox[$aliasRHS, boxes].FormatClass[] FROM over => { rightVertOffsetRHS _ [origin]; rightVertOffsetRel _ [center]; }; matrix => { rightVertOffsetRHS _ [center]; rightVertOffsetRel _ [center]; }; ENDCASE => { rightVertOffsetRHS _ [origin]; rightVertOffsetRel _ [origin]; }; alignments _ LIST[ [$aliasLeftSpace, [$aliasRelation, [right], [left]], [$aliasRelation, [origin], [origin]]], [$aliasLHS, [$aliasLeftSpace, [right], [left]], [$aliasRelation, leftVertOffsetLHS, leftVertOffsetRel]], [$aliasRightSpace, [$aliasRelation, [left], [right]], [$aliasRelation, [origin], [origin]]], [$aliasRHS, [$aliasRightSpace, [left], [right]], [$aliasRelation, rightVertOffsetRHS, rightVertOffsetRel]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$aliasLHS, [origin]], [$aliasRelation, [origin]]]; RETURN[tempBox, tempBoxes]; }; ComplexCompRule: CompositionProc ~ { <> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[[$a, [$plus, [right], [left, -smallGap]], [$plus, [origin], [origin]]], [$b, [$plus, [left], [right, smallGap]], [$plus, [origin], [origin]]], [$i, [$b, [left], [right, smallGap]], [$b, [origin], [origin]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$a, [origin]], [$plus, [origin]]]; RETURN[tempBox, tempBoxes]; }; FactorialCompRule: CompositionProc ~ { <> 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]; }; ParenCompRule: CompositionProc ~ { <> << $leftParen and $rightParen>> tempBox: BOX; tempBoxes: LIST OF BOX; alignments: LIST OF Alignment2D _ LIST[ [$leftParen, [$a, [right], [left]], [$a, [center], [center]]], [$rightParen, [$a, [left], [right]], [$a, [center], [center]]]]; [tempBox, tempBoxes] _ MathRules.Compose[boxes, alignments, [$leftParen, [origin]], [$self, [center, -0.25]]]; RETURN[tempBox, tempBoxes]; }; <> <<>> MakeBinOpClass: PUBLIC PROC[class, op, a, b: ATOM, operation: EXPR, description: ROPE, cvtAS: ROPE] RETURNS[CompoundClass] ~ { <> << 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, MakeSpace[$thin]]; rightSpace: Symbol _ MakeSymbol[$rightThinSpace, LIST[$aliasRightSpace], normal, MakeSpace[$thin]]; RETURN[MakeCompoundClass[class, binaryOp, description, LIST[aArg, bArg], LIST[opSym, leftSpace, rightSpace], FixedSizeBoxRule, BinaryOpCompRule, cvtAS]]; }; MakeRelationClass: PUBLIC PROC[class, rel, lhs, rhs: ATOM, relation: EXPR, description: ROPE, cvtAS: ROPE] RETURNS[CompoundClass] ~ { <> << The alignment is "lhs relation rhs"; alignment is thru baselines. >> << All of lhs, rhs, rel are of fixed size "normal".>> lhsArg: Argument _ MakeArgument[lhs, LIST[$aliasLHS, $aliasHot], normal]; rhsArg: Argument _ MakeArgument[rhs, LIST[$aliasRHS], normal]; relSym: Symbol _ MakeSymbol[rel, LIST[$aliasRelation], normal, relation]; leftSpace: Symbol _ MakeSymbol[$leftSpace, LIST[$aliasLeftSpace], normal, MakeSpace[$thick]]; rightSpace: Symbol _ MakeSymbol[$rightSpace, LIST[$aliasRightSpace], normal, MakeSpace[$thick]]; RETURN[MakeCompoundClass[class, relation, description, LIST[lhsArg, rhsArg], LIST[relSym, leftSpace, rightSpace], FixedSizeBoxRule, RelationCompRule, cvtAS]]; }; MakeUnaryOpClass: PUBLIC PROC[class, op, arg: ATOM, operation: EXPR, description: ROPE, cvtAS: ROPE] RETURNS[CompoundClass] ~ { <> << 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, MakeSpace[$medium]]; unaryOpSym: Symbol _ MakeSymbol[op, LIST[$aliasUnaryOp], normal, operation]; RETURN[MakeCompoundClass[class, unaryOp, description, LIST[argArg], LIST[unaryOpSym, spaceSym], FixedSizeBoxRule, UnaryOpCompRule, cvtAS]]; }; <> <> MakePlainSym: PROC[c: CHAR] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$plainSym, Rope.FromChar[c]]]; }; MakePlainRope: PROC[r: ROPE] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$plainSym, r]]; }; MakeOverlaySym: PROC[r: ROPE] RETURNS[EXPR] ~ { <> RETURN[MathExpr.MakeAtomicExpr[$overlaySym, r]]; }; MakeBigMathSym: PROC[c: CHAR] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$bigMathSym, Rope.FromChar[c]]]; }; MakeSmallMathSym: PROC[c: CHAR] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$smallMathSym, Rope.FromChar[c]]]; }; MakeItalSym: PROC[c: CHAR] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$italicSym, Rope.FromChar[c]]]; }; MakeMathItalSym: PROC[c: CHAR] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$mathItalicSym, Rope.FromChar[c]]]; }; MakeLine: PROC[] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$line, "LINE"]]; }; MakeSpace: PROC[size: ATOM] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$space, Convert.RopeFromAtom[size, FALSE]]]; }; MakePlaceHolder: PUBLIC PROC[] RETURNS[EXPR] ~ { RETURN[MathExpr.MakeAtomicExpr[$placeholder, "\056\057"]]; }; MakeInfinity: PUBLIC PROC[] RETURNS[EXPR] ~ { <> RETURN[MathExpr.MakeAtomicExpr[$infinity, "\061"]]; }; MakeInt: PUBLIC PROC[n: ROPE] RETURNS[EXPR] ~ { <> << SIGNALS badFormat if n is not a legal integer.>> <<>> IF n.Length[] = 0 THEN ERROR badFormat; SELECT n.Fetch[0] FROM IN ['0..'9] => NULL; '- => IF n.Length[] = 1 THEN ERROR badFormat; -- a lone minus sign is invalid ENDCASE => ERROR badFormat; <> FOR i:INT IN[1..n.Length[]-1] DO SELECT n.Fetch[i] FROM IN ['0..'9] => NULL; ENDCASE => ERROR badFormat; ENDLOOP; RETURN[MathExpr.MakeAtomicExpr[$integer, n]]; }; MakeReal: PUBLIC PROC[r: REAL] RETURNS[EXPR] ~ { <> RETURN[MathExpr.MakeAtomicExpr[$real, Convert.RopeFromReal[r]]]; }; MakeVariable: PUBLIC PROC[var: ROPE] RETURNS[EXPR] ~ { <> << SIGNALS badFormat if n is not a legal variable (e.g. invalid chars).>> <<>> IF var.Length[] = 0 THEN ERROR badFormat; <<>> <> <> <