@@ -30,6 +30,7 @@ import NodeUtil from './NodeUtil.js';
3030import TexParser from './TexParser.js' ;
3131import TexError from './TexError.js' ;
3232import { entities } from '../../util/Entities.js' ;
33+ import { MmlMunderover } from '../../core/MmlTree/MmlNodes/munderover.js' ;
3334import { em } from '../../util/lengths.js' ;
3435
3536
@@ -360,6 +361,40 @@ namespace ParseUtil {
360361 return parser . create ( 'node' , 'mtext' , [ ] , def , textNode ) ;
361362 }
362363
364+ /**
365+ * Create an munderover node with the given script position.
366+ * @param {TexParser } parser The current TeX parser.
367+ * @param {MmlNode } base The base node.
368+ * @param {MmlNode } script The under- or over-script.
369+ * @param {string } pos Either 'over' or 'under'.
370+ * @param {boolean } stack True if super- or sub-scripts should stack.
371+ * @return {MmlNode } The generated node (MmlMunderover or TeXAtom)
372+ */
373+ export function underOver ( parser : TexParser , base : MmlNode , script : MmlNode , pos : string , stack : boolean ) : MmlNode {
374+ // @test Overline
375+ const symbol = NodeUtil . getForm ( base ) ;
376+ if ( ( symbol && symbol [ 3 ] && symbol [ 3 ] [ 'movablelimits' ] ) || NodeUtil . getProperty ( base , 'movablelimits' ) ) {
377+ // @test Overline Sum
378+ NodeUtil . setProperties ( base , { 'movablelimits' : false } ) ;
379+ }
380+ if ( NodeUtil . isType ( base , 'munderover' ) && NodeUtil . isEmbellished ( base ) ) {
381+ // @test Overline Limits
382+ NodeUtil . setProperties ( NodeUtil . getCoreMO ( base ) , { lspace : 0 , rspace : 0 } ) ;
383+ const mo = parser . create ( 'node' , 'mo' , [ ] , { rspace : 0 } ) ;
384+ base = parser . create ( 'node' , 'mrow' , [ mo , base ] ) ;
385+ // TODO? add an empty <mi> so it's not embellished any more
386+ }
387+ const mml = parser . create ( 'node' , 'munderover' , [ base ] ) as MmlMunderover ;
388+ NodeUtil . setChild ( mml , pos === 'over' ? mml . over : mml . under , script ) ;
389+ let node : MmlNode = mml ;
390+ if ( stack ) {
391+ // @test Overbrace 1 2 3, Underbrace, Overbrace Op 1 2
392+ node = parser . create ( 'node' , 'TeXAtom' , [ mml ] , { texClass : TEXCLASS . OP , movesupsub : true } ) ;
393+ }
394+ NodeUtil . setProperty ( node , 'subsupOK' , true ) ;
395+ return node ;
396+ }
397+
363398 /**
364399 * Trim spaces from a string.
365400 * @param {string } text The string to clean.
@@ -391,7 +426,7 @@ namespace ParseUtil {
391426 } else if ( align === 'b' ) {
392427 array . arraydef . align = 'baseline -1' ;
393428 } else if ( align === 'c' ) {
394- array . arraydef . align = 'center ' ;
429+ array . arraydef . align = 'axis ' ;
395430 } else if ( align ) {
396431 array . arraydef . align = align ;
397432 } // FIXME: should be an error?
@@ -458,6 +493,26 @@ namespace ParseUtil {
458493 return s1 + s2 ;
459494 }
460495
496+ /**
497+ * Report an error if there are too many macro substitutions.
498+ * @param {TexParser } parser The current TeX parser.
499+ * @param {boolean } isMacro True if we are substituting a macro, false for environment.
500+ */
501+ export function checkMaxMacros ( parser : TexParser , isMacro : boolean = true ) {
502+ if ( ++ parser . macroCount <= parser . configuration . options [ 'maxMacros' ] ) {
503+ return ;
504+ }
505+ if ( isMacro ) {
506+ throw new TexError ( 'MaxMacroSub1' ,
507+ 'MathJax maximum macro substitution count exceeded; ' +
508+ 'is here a recursive macro call?' ) ;
509+ } else {
510+ throw new TexError ( 'MaxMacroSub2' ,
511+ 'MathJax maximum substitution count exceeded; ' +
512+ 'is there a recursive latex environment?' ) ;
513+ }
514+ }
515+
461516
462517 /**
463518 * Check for bad nesting of equation environments
@@ -513,8 +568,7 @@ namespace ParseUtil {
513568 for ( let key of Object . keys ( def ) ) {
514569 if ( ! allowed . hasOwnProperty ( key ) ) {
515570 if ( error ) {
516- throw new TexError ( 'InvalidOption' ,
517- 'Invalid optional argument: %1' , key ) ;
571+ throw new TexError ( 'InvalidOption' , 'Invalid option: %1' , key ) ;
518572 }
519573 delete def [ key ] ;
520574 }
0 commit comments