diff --git a/ts/input/tex/Stack.ts b/ts/input/tex/Stack.ts index baa577772..02009d4f3 100644 --- a/ts/input/tex/Stack.ts +++ b/ts/input/tex/Stack.ts @@ -99,7 +99,9 @@ export default class Stack { this.Push(...top); continue; } - this.stack.push(item); + if (!item.isKind('null')) { + this.stack.push(item); + } if (item.env) { if (item.copyEnv) { Object.assign(item.env, this.env); diff --git a/ts/input/tex/StackItem.ts b/ts/input/tex/StackItem.ts index 2e1cabcc4..03b03f333 100644 --- a/ts/input/tex/StackItem.ts +++ b/ts/input/tex/StackItem.ts @@ -414,7 +414,7 @@ export abstract class BaseItem extends MmlStack implements StackItem { /** * @return {string} The type of the stack item. */ - public get kind(): string { + public get kind(): string { return 'base'; } diff --git a/ts/input/tex/TexParser.ts b/ts/input/tex/TexParser.ts index d78de4619..8969b57dd 100644 --- a/ts/input/tex/TexParser.ts +++ b/ts/input/tex/TexParser.ts @@ -570,11 +570,13 @@ export default class TexParser { } // These are the cases to handle sub and superscripts. if (node.attributes.get(TexConstant.Attr.LATEX) === '^' && - str !== '^' && str !== '\\^') { - if (str === '}') { - this.composeBraces(node.childNodes[2]); - } else { - node.childNodes[2].attributes.set(TexConstant.Attr.LATEX, str); + str !== '^' && str !== '\\^') { + if (node.childNodes[2]) { + if (str === '}') { + this.composeBraces(node.childNodes[2]); + } else { + node.childNodes[2].attributes.set(TexConstant.Attr.LATEX, str); + } } if (node.childNodes[1]) { const sub = node.childNodes[1].attributes.get(TexConstant.Attr.LATEX); @@ -585,11 +587,13 @@ export default class TexParser { return; } if (node.attributes.get(TexConstant.Attr.LATEX) === '_' && - str !== '_' && str !== '\\_') { - if (str === '}') { - this.composeBraces(node.childNodes[1]); - } else { - node.childNodes[1].attributes.set(TexConstant.Attr.LATEX, str); + str !== '_' && str !== '\\_') { + if (node.childNodes[1]) { + if (str === '}') { + this.composeBraces(node.childNodes[1]); + } else { + node.childNodes[1].attributes.set(TexConstant.Attr.LATEX, str); + } } if (node.childNodes[2]) { const sub = node.childNodes[2].attributes.get(TexConstant.Attr.LATEX); @@ -616,6 +620,7 @@ export default class TexParser { */ private composeLatex( node: MmlNode, comp: string, pos1: number, pos2: number) { + if (!node.childNodes[pos1] || !node.childNodes[pos2]) return; const expr = node.childNodes[pos1].attributes.get(TexConstant.Attr.LATEX) + comp + node.childNodes[pos2].attributes.get(TexConstant.Attr.LATEX); node.attributes.set(TexConstant.Attr.LATEX, expr); diff --git a/ts/input/tex/ams/AmsMethods.ts b/ts/input/tex/ams/AmsMethods.ts index 985e57953..a480a3a0f 100644 --- a/ts/input/tex/ams/AmsMethods.ts +++ b/ts/input/tex/ams/AmsMethods.ts @@ -220,6 +220,7 @@ AmsMethods.HandleDeclareOp = function (parser: TexParser, name: string) { let op = parser.GetArgument(name); (parser.configuration.handlers.retrieve(NEW_OPS) as CommandMap). add(cs, new Macro(cs, AmsMethods.Macro, [`\\operatorname${star}{${op}}`])); + parser.Push(parser.itemFactory.create('null')); }; @@ -586,6 +587,7 @@ AmsMethods.HandleTag = function(parser: TexParser, name: string) { let star = parser.GetStar(); let tagId = ParseUtil.trimSpaces(parser.GetArgument(name)); parser.tags.tag(tagId, star); + parser.Push(parser.itemFactory.create('null')); }; diff --git a/ts/input/tex/base/BaseConfiguration.ts b/ts/input/tex/base/BaseConfiguration.ts index 50796a2a3..825b3c9f8 100644 --- a/ts/input/tex/base/BaseConfiguration.ts +++ b/ts/input/tex/base/BaseConfiguration.ts @@ -168,6 +168,7 @@ export const BaseConfiguration: Configuration = Configuration.create( [bitem.StopItem.prototype.kind]: bitem.StopItem, [bitem.OpenItem.prototype.kind]: bitem.OpenItem, [bitem.CloseItem.prototype.kind]: bitem.CloseItem, + [bitem.NullItem.prototype.kind]: bitem.NullItem, [bitem.PrimeItem.prototype.kind]: bitem.PrimeItem, [bitem.SubsupItem.prototype.kind]: bitem.SubsupItem, [bitem.OverItem.prototype.kind]: bitem.OverItem, diff --git a/ts/input/tex/base/BaseItems.ts b/ts/input/tex/base/BaseItems.ts index d9f588c6f..87bf8bfc6 100644 --- a/ts/input/tex/base/BaseItems.ts +++ b/ts/input/tex/base/BaseItems.ts @@ -176,6 +176,18 @@ export class CloseItem extends BaseItem { } +/** + * Item pushed when a macro doesn't produce any output. + */ +export class NullItem extends BaseItem { + /** + * @override + */ + public get kind() { + return 'null'; + } +} + /** * Item indicating an we are currently dealing with a prime mark. diff --git a/ts/input/tex/base/BaseMethods.ts b/ts/input/tex/base/BaseMethods.ts index 3e5fb255d..87d369634 100644 --- a/ts/input/tex/base/BaseMethods.ts +++ b/ts/input/tex/base/BaseMethods.ts @@ -268,8 +268,7 @@ BaseMethods.Prime = function(parser: TexParser, c: string) { } while (c === '\'' || c === entities.rsquo); sup = ['', '\u2032', '\u2033', '\u2034', '\u2057'][sup.length] || sup; const node = parser.create('token', 'mo', {variantForm: true}, sup); - parser.Push( - parser.itemFactory.create('prime', base, node) ); + parser.Push(parser.itemFactory.create('prime', base, node)); }; @@ -327,6 +326,7 @@ BaseMethods.MathFont = function(parser: TexParser, name: string, variant: string */ BaseMethods.SetFont = function(parser: TexParser, _name: string, font: string) { parser.stack.env['font'] = font; +// parser.Push(parser.itemFactory.create('null')); }; /** @@ -811,6 +811,7 @@ BaseMethods.VBox = function(parser: TexParser, name: string, align: string) { BaseMethods.Hsize = function (parser: TexParser, name: string) { parser.GetNext() === '=' && parser.i++; parser.stack.env.hsize = parser.GetDimen(name); + parser.Push(parser.itemFactory.create('null')); }; /** @@ -1538,10 +1539,11 @@ BaseMethods.NewColumnType = function (parser: TexParser, name: string) { throw new TexError('BadColumnName', 'Column specifier must be exactly one character: %1', c); } if (!n.match(/^\d+$/)) { - throw new TexError('PositiveIntegerArg', 'Argument to %1 must me a positive integer', n); + throw new TexError('PositiveIntegerArg', 'Argument to %1 must be a positive integer', n); } const cparser = parser.configuration.columnParser; cparser.columnHandler[c] = (state: ColumnState) => cparser.macroColumn(state, macro, parseInt(n)); + parser.Push(parser.itemFactory.create('null')); } diff --git a/ts/input/tex/color/ColorMethods.ts b/ts/input/tex/color/ColorMethods.ts index 2b55afc33..619213e53 100644 --- a/ts/input/tex/color/ColorMethods.ts +++ b/ts/input/tex/color/ColorMethods.ts @@ -112,6 +112,7 @@ ColorMethods.DefineColor = function (parser: TexParser, name: string) { const colorModel: ColorModel = parser.configuration.packageData.get('color').model; colorModel.defineColor(model, cname, def); + parser.Push(parser.itemFactory.create('null')); }; /** diff --git a/ts/input/tex/extpfeil/ExtpfeilConfiguration.ts b/ts/input/tex/extpfeil/ExtpfeilConfiguration.ts index e3411afa2..014680bbe 100644 --- a/ts/input/tex/extpfeil/ExtpfeilConfiguration.ts +++ b/ts/input/tex/extpfeil/ExtpfeilConfiguration.ts @@ -67,6 +67,7 @@ ExtpfeilMethods.NewExtArrow = function(parser: TexParser, name: string) { let spaces = space.split(','); NewcommandUtil.addMacro(parser, cs, ExtpfeilMethods.xArrow, [parseInt(chr), parseInt(spaces[0]), parseInt(spaces[1])]); + parser.Push(parser.itemFactory.create('null')); }; diff --git a/ts/input/tex/mathtools/MathtoolsMethods.ts b/ts/input/tex/mathtools/MathtoolsMethods.ts index ee720aad1..07320682f 100644 --- a/ts/input/tex/mathtools/MathtoolsMethods.ts +++ b/ts/input/tex/mathtools/MathtoolsMethods.ts @@ -515,6 +515,7 @@ export const MathtoolsMethods: Record = { const open = parser.GetArgument(name); const close = parser.GetArgument(name); MathtoolsUtil.addPairedDelims(parser.configuration, cs, [open, close]); + parser.Push(parser.itemFactory.create('null')); }, /** @@ -530,6 +531,7 @@ export const MathtoolsMethods: Record = { const close = parser.GetArgument(name); const body = parser.GetArgument(name); MathtoolsUtil.addPairedDelims(parser.configuration, cs, [open, close, body, n]); + parser.Push(parser.itemFactory.create('null')); }, /** @@ -547,6 +549,7 @@ export const MathtoolsMethods: Record = { const post = parser.GetArgument(name); const body = parser.GetArgument(name); MathtoolsUtil.addPairedDelims(parser.configuration, cs, [open, close, body, n, pre, post]); + parser.Push(parser.itemFactory.create('null')); }, /** @@ -710,6 +713,7 @@ export const MathtoolsMethods: Record = { throw new TexError('DuplicateTagForm', 'Duplicate tag form: %1', id); } tags.mtFormats.set(id, [left, right, format]); + parser.Push(parser.itemFactory.create('null')); }, /** @@ -726,12 +730,14 @@ export const MathtoolsMethods: Record = { const id = parser.GetArgument(name).trim(); if (!id) { tags.mtCurrent = null; + parser.Push(parser.itemFactory.create('null')); return; } if (!tags.mtFormats.has(id)) { throw new TexError('UndefinedTagForm', 'Undefined tag form: %1', id); } tags.mtCurrent = tags.mtFormats.get(id); + parser.Push(parser.itemFactory.create('null')); }, /** @@ -756,6 +762,7 @@ export const MathtoolsMethods: Record = { for (const id of Object.keys(keys)) { options[id] = keys[id]; } + parser.Push(parser.itemFactory.create('null')); }, /** diff --git a/ts/input/tex/newcommand/NewcommandMethods.ts b/ts/input/tex/newcommand/NewcommandMethods.ts index e4957023a..17b2479cd 100644 --- a/ts/input/tex/newcommand/NewcommandMethods.ts +++ b/ts/input/tex/newcommand/NewcommandMethods.ts @@ -49,6 +49,7 @@ NewcommandMethods.NewCommand = function(parser: TexParser, name: string) { let opt = parser.GetBrackets(name); let def = parser.GetArgument(name); NewcommandUtil.addMacro(parser, cs, NewcommandMethods.Macro, [def, n, opt]); + parser.Push(parser.itemFactory.create('null')); }; @@ -65,6 +66,7 @@ NewcommandMethods.NewEnvironment = function(parser: TexParser, name: string) { let bdef = parser.GetArgument(name); let edef = parser.GetArgument(name); NewcommandUtil.addEnvironment(parser, env, NewcommandMethods.BeginEnv, [true, bdef, edef, n, opt]); + parser.Push(parser.itemFactory.create('null')); }; @@ -83,6 +85,7 @@ NewcommandMethods.MacroDef = function(parser: TexParser, name: string) { NewcommandUtil.addMacro(parser, cs, NewcommandMethods.Macro, [def, params]) : // @test Def Let NewcommandUtil.addMacro(parser, cs, NewcommandMethods.MacroWithTemplate, [def].concat(params)); + parser.Push(parser.itemFactory.create('null')); }; @@ -112,6 +115,7 @@ NewcommandMethods.Let = function(parser: TexParser, name: string) { c = parser.GetNext(); } const handlers = parser.configuration.handlers; + parser.Push(parser.itemFactory.create('null')); if (c === '\\') { // @test Let Bar, Let Brace Equal Stretchy name = NewcommandUtil.GetCSname(parser, name); diff --git a/ts/input/tex/require/RequireConfiguration.ts b/ts/input/tex/require/RequireConfiguration.ts index c563f92ff..f32c60032 100644 --- a/ts/input/tex/require/RequireConfiguration.ts +++ b/ts/input/tex/require/RequireConfiguration.ts @@ -192,6 +192,7 @@ export const RequireMethods: Record = { throw new TexError('BadPackageName', 'Argument for %1 is not a valid package name', name); } RequireLoad(parser, required); + parser.Push(parser.itemFactory.create('null')); } }; diff --git a/ts/input/tex/setoptions/SetOptionsConfiguration.ts b/ts/input/tex/setoptions/SetOptionsConfiguration.ts index ffbd59ed7..cbea1dfe6 100644 --- a/ts/input/tex/setoptions/SetOptionsConfiguration.ts +++ b/ts/input/tex/setoptions/SetOptionsConfiguration.ts @@ -113,6 +113,7 @@ const setOptionsMap = new CommandMap('setoptions', { config.filterValue(parser, extension, key, options[key]); } } + parser.Push(parser.itemFactory.create('null')); } });