diff --git a/src/buildHTML.js b/src/buildHTML.js
index b54d6a85..401012ff 100644
--- a/src/buildHTML.js
+++ b/src/buildHTML.js
@@ -571,12 +571,6 @@ export const groupTypes = {
return makeSpan(["mrel", "x-arrow"], [vlist], options);
},
- mclass(group, options) {
- const elements = buildExpression(group.value.value, options, true);
-
- return makeSpan([group.value.mclass], elements, options);
- },
-
raisebox(group, options) {
const body = groupTypes.sizing({value: {
value: [{
diff --git a/src/buildMathML.js b/src/buildMathML.js
index a828e4f7..aecbbea0 100644
--- a/src/buildMathML.js
+++ b/src/buildMathML.js
@@ -275,11 +275,6 @@ groupTypes.xArrow = function(group, options) {
return node;
};
-groupTypes.mclass = function(group, options) {
- const inner = buildExpression(group.value.value, options);
- return new mathMLTree.MathNode("mstyle", inner);
-};
-
groupTypes.raisebox = function(group, options) {
const node = new mathMLTree.MathNode(
"mpadded", [buildGroup(group.value.body, options)]);
diff --git a/src/functions.js b/src/functions.js
index f9c7c808..4360025a 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -1,7 +1,6 @@
// @flow
/** Include this to ensure that all functions are defined. */
import ParseError from "./ParseError";
-import ParseNode from "./ParseNode";
import {
default as _defineFunction,
ordargument,
@@ -51,70 +50,7 @@ import "./functions/kern";
import "./functions/phantom";
-// Math class commands except \mathop
-defineFunction("mclass", [
- "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",
- "\\mathclose", "\\mathpunct", "\\mathinner",
-], {
- numArgs: 1,
-}, function(context, args) {
- const body = args[0];
- return {
- type: "mclass",
- mclass: "m" + context.funcName.substr(5),
- value: ordargument(body),
- };
-});
-
-// Build a relation or stacked op by placing one symbol on top of another
-defineFunction("mclass", ["\\stackrel", "\\overset", "\\underset"], {
- numArgs: 2,
-}, function(context, args) {
- const baseArg = args[1];
- const shiftedArg = args[0];
-
- let mclass = "mrel"; // default. May change below.
- if (context.funcName !== "\\stackrel") {
- // LaTeX applies \binrel spacing to \overset and \underset.
- // \binrel spacing varies with (bin|rel|ord) of the atom in the argument.
- // We'll do the same.
- let atomType = "";
- if (baseArg.type === "ordgroup") {
- atomType = baseArg.value[0].type;
- } else {
- atomType = baseArg.type;
- }
- if (/^(bin|rel)$/.test(atomType)) {
- mclass = "m" + atomType;
- } else {
- // This may capture some instances in which the baseArg is more than
- // just a single symbol. Say a \overset inside an \overset.
- // TODO: A more comprehensive way to determine the baseArg type.
- mclass = "mord";
- }
- }
-
- const baseOp = new ParseNode("op", {
- type: "op",
- limits: true,
- alwaysHandleSupSub: true,
- symbol: false,
- suppressBaseShift: context.funcName !== "\\stackrel",
- value: ordargument(baseArg),
- }, baseArg.mode);
-
- const supsub = new ParseNode("supsub", {
- base: baseOp,
- sup: context.funcName === "\\underset" ? null : shiftedArg,
- sub: context.funcName === "\\underset" ? shiftedArg : null,
- }, shiftedArg.mode);
-
- return {
- type: "mclass",
- mclass: mclass,
- value: [supsub],
- };
-});
+import "./functions/mclass";
import "./functions/mod";
diff --git a/src/functions/mclass.js b/src/functions/mclass.js
new file mode 100644
index 00000000..3b5eb23d
--- /dev/null
+++ b/src/functions/mclass.js
@@ -0,0 +1,100 @@
+// @flow
+import defineFunction, {ordargument} from "../defineFunction";
+import buildCommon from "../buildCommon";
+import mathMLTree from "../mathMLTree";
+import ParseNode from "../ParseNode";
+
+import * as html from "../buildHTML";
+import * as mml from "../buildMathML";
+
+const makeSpan = buildCommon.makeSpan;
+
+function htmlBuilder(group, options) {
+ const elements = html.buildExpression(group.value.value, options, true);
+ return makeSpan([group.value.mclass], elements, options);
+}
+
+function mathmlBuilder(group, options) {
+ const inner = mml.buildExpression(group.value.value, options);
+ return new mathMLTree.MathNode("mstyle", inner);
+}
+
+// Math class commands except \mathop
+defineFunction({
+ type: "mclass",
+ names: [
+ "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",
+ "\\mathclose", "\\mathpunct", "\\mathinner",
+ ],
+ props: {
+ numArgs: 1,
+ },
+ handler(context, args) {
+ const body = args[0];
+ return {
+ type: "mclass",
+ mclass: "m" + context.funcName.substr(5),
+ value: ordargument(body),
+ };
+ },
+ htmlBuilder,
+ mathmlBuilder,
+});
+
+// Build a relation or stacked op by placing one symbol on top of another
+defineFunction({
+ type: "mclass",
+ names: ["\\stackrel", "\\overset", "\\underset"],
+ props: {
+ numArgs: 2,
+ },
+ handler(context, args) {
+ const baseArg = args[1];
+ const shiftedArg = args[0];
+
+ let mclass = "mrel"; // default. May change below.
+ if (context.funcName !== "\\stackrel") {
+ // LaTeX applies \binrel spacing to \overset and \underset. \binrel
+ // spacing varies with (bin|rel|ord) of the atom in the argument.
+ // We'll do the same.
+ let atomType = "";
+ if (baseArg.type === "ordgroup") {
+ atomType = baseArg.value[0].type;
+ } else {
+ atomType = baseArg.type;
+ }
+ if (/^(bin|rel)$/.test(atomType)) {
+ mclass = "m" + atomType;
+ } else {
+ // This may capture some instances in which the baseArg is more
+ // than just a single symbol. Say a \overset inside an \overset.
+ // TODO: A more comprehensive way to determine the baseArg type.
+ mclass = "mord";
+ }
+ }
+
+ const baseOp = new ParseNode("op", {
+ type: "op",
+ limits: true,
+ alwaysHandleSupSub: true,
+ symbol: false,
+ suppressBaseShift: context.funcName !== "\\stackrel",
+ value: ordargument(baseArg),
+ }, baseArg.mode);
+
+ const supsub = new ParseNode("supsub", {
+ base: baseOp,
+ sup: context.funcName === "\\underset" ? null : shiftedArg,
+ sub: context.funcName === "\\underset" ? shiftedArg : null,
+ }, shiftedArg.mode);
+
+ return {
+ type: "mclass",
+ mclass: mclass,
+ value: [supsub],
+ };
+ },
+ htmlBuilder,
+ mathmlBuilder,
+});
+