Files
DocumentServer-v-9.2.0/sdkjs/word/Math/LaTeXParser.js
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

1758 lines
42 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2024
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
"use strict";
(function (window) {
const Literals = AscMath.MathLiterals;
const Struc = AscMath.MathStructures;
const ConvertTokens = AscMath.ConvertTokens;
const Tokenizer = AscMath.Tokenizer;
const GetTypeFont = AscMath.GetTypeFont;
const GetMathFontChar = AscMath.GetMathFontChar;
function CLaTeXParser()
{
this.oTokenizer = new Tokenizer(true);
this.intMathFontType = -1;
this.isReceiveOneTokenAtTime = false;
this.isNowMatrix = false;
this.EscapeSymbol = "";
this.isOneSymbol = false;
}
CLaTeXParser.prototype.IsNotEscapeSymbol = function ()
{
return this.oLookahead.data !== this.EscapeSymbol;
};
CLaTeXParser.prototype.ReadTokensWhileEnd = function (arrTypeOfLiteral, type)
{
let arrLiterals = [];
let strLiteral = "";
let styles = [];
let isOne = this.isReceiveOneTokenAtTime;
let isSymbol;
if ((isOne || this.isOneSymbol) && this.oLookahead.class === arrTypeOfLiteral.id)
{
let oItem = this.oLookahead;
let strValue = this.EatToken(arrTypeOfLiteral.id).data;
let oStyle = oItem.style;
type = Struc.char;
strLiteral = this.intMathFontType === -1
? strValue
: GetMathFontChar[strValue][this.intMathFontType];
styles.push(oStyle);
if (this.isOneSymbol)
this.isOneSymbol = false;
}
else
{
while (this.oLookahead.class === arrTypeOfLiteral.id
&& this.EscapeSymbol !== this.oLookahead.data
&& (styles.length === 0 || styles[styles.length - 1].IsStyleEqual(this.oLookahead.style)))
{
let oCurrentItem = this.oLookahead;
let strCurrent = oCurrentItem.data;
let oStyle = oCurrentItem.style.Copy();
this.EatToken(arrTypeOfLiteral.id);
if (GetMathFontChar[strCurrent] && GetMathFontChar[strCurrent][this.intMathFontType])
{
strLiteral += GetMathFontChar[strCurrent][this.intMathFontType];
isSymbol = true;
}
else
{
strLiteral += strCurrent;
if (this.isMathRm)
{
let metaData = oStyle.GetMathMetaData();
metaData.setIsMathRm(true);
}
}
styles.push(oStyle);
}
}
if (styles.length === 1)
styles = styles[0];
arrLiterals.push({type: isSymbol ? Struc.other : type, value: strLiteral, style: styles});
if (arrLiterals.length === 1)
return arrLiterals[0];
return arrLiterals
};
CLaTeXParser.prototype.SaveState = function (oLookahead)
{
this.oTokenizer.SaveState(oLookahead);
};
CLaTeXParser.prototype.RestoreState = function ()
{
let oRestore = this.oTokenizer.RestoreState();
if (oRestore)
this.oLookahead = oRestore;
};
CLaTeXParser.prototype.Parse = function (string)
{
this.oTokenizer.Init(string);
this.oLookahead = this.oTokenizer.GetNextToken();
return this.GetASTTree();
};
CLaTeXParser.prototype.GetASTTree2 = function(isEndFunc)
{
let arrExp = [];
while (this.oLookahead.data)
{
if (isEndFunc && isEndFunc())
return arrExp;
if (this.IsElementLiteral())
{
arrExp.push(this.GetExpressionLiteral(undefined, isEndFunc))
}
else
{
let oData = this.oLookahead;
this.EatToken(this.oLookahead.class);
let strValue = oData.data;
let oStyle = oData.style;
if ("\\bmod" === strValue) // todo в новой версии конвертора добавить отдельный модуль для такого типа токенов
{
strValue = " mod "; // в обратную сторону (линейную) такие токены вряд ли получится конвертнуть,
// а ворде такого токена просто нет
// todo продумать как будет происходить преобразование в линейную форму
}
arrExp.push({
type: Struc.char,
value: strValue,
style: oStyle,
})
}
}
return arrExp;
}
CLaTeXParser.prototype.GetASTTree = function ()
{
return {
type: "LaTeXEquation",
body: this.GetASTTree2()
};
};
CLaTeXParser.prototype.GetCharLiteral = function ()
{
return this.ReadTokensWhileEnd(Literals.char, Struc.char);
};
CLaTeXParser.prototype.GetOperandLiteral = function ()
{
let oPr = this.oLookahead.style;
const strToken = this.EatToken(Literals.operand.id);
return {
type: Struc.char,
value: strToken.data,
style: oPr
};
}
CLaTeXParser.prototype.GetOtherLiteral = function ()
{
return this.ReadTokensWhileEnd(Literals.other, Struc.other);
};
CLaTeXParser.prototype.GetSpaceLiteral = function ()
{
// LaTex skip all normal spaces
while (this.oLookahead.data === " ")
{
this.EatToken(this.oLookahead.class);
}
let oStyle = this.oLookahead.style;
if (this.oLookahead.data === "\\ "
|| this.oLookahead.data === "\\quad"
// || this.oLookahead.data === "\\:"
// || this.oLookahead.data === "\\;"
)
{
let strSpace = "";
if (this.oLookahead.data === "\\ ")
strSpace = " ";
else if (this.oLookahead.data === "\\quad")
strSpace = " ";
// else if (this.oLookahead.data === "\\:")
// strSpace = "";
// else if (this.oLookahead.data === "\\;")
// strSpace = "";
this.EatToken(this.oLookahead.class)
return {
type: Struc.char,
value: strSpace,
style: oStyle
}
}
//this.ReadTokensWhileEnd(Literals.space, Struc.space);
};
CLaTeXParser.prototype.GetNumberLiteral = function ()
{
return this.ReadTokensWhileEnd(Literals.number, Struc.number);
};
CLaTeXParser.prototype.GetOperatorLiteral = function ()
{
let oPr = this.oLookahead.style;
const strToken = this.EatToken(Literals.operator.id);
return {
type: Struc.char,
value: strToken.data,
style: oPr
};
};
CLaTeXParser.prototype.IsAccentLiteral = function ()
{
return this.oLookahead.class === Literals.accent.id;
};
CLaTeXParser.prototype.GetAccentLiteral = function (oBase)
{
let strAccent,
oResultAccent,
oPr;
if (this.oLookahead.data === "'" || this.oLookahead.data === "''")
{
return this.GetSubSupLiteral(oBase);
}
else
{
oPr = this.oLookahead.style;
strAccent = this.oLookahead;
this.EatToken(this.oLookahead.class);
strAccent.value = AscMath.MathLiterals.accent.LaTeX[strAccent.data];
oBase = this.GetArguments(1);
oBase = this.GetContentOfLiteral(oBase);
oResultAccent = {
type: Struc.accent,
base: oBase,
value: strAccent,
style: oPr,
};
}
return oResultAccent;
};
CLaTeXParser.prototype.IsFractionLiteral = function ()
{
return this.oLookahead.data === "\\frac"
|| this.oLookahead.data === "\\binom"
|| this.oLookahead.data === "\\cfrac"
|| this.oLookahead.data === "\\sfrac";
};
CLaTeXParser.prototype.GetFractionType = function (str)
{
switch (str)
{
case "\\frac" : return BAR_FRACTION; break;
case "\\over" : return BAR_FRACTION; break;
case "\\binom" : return NO_BAR_FRACTION; break;
case "\\atop" : return NO_BAR_FRACTION; break;
default : return SKEWED_FRACTION; break;
}
}
CLaTeXParser.prototype.GetFractionLiteral = function ()
{
let strName = this.oLookahead.data;
let oFracStyle = this.oLookahead.style;
let type = this.GetFractionType(this.oLookahead.data);
this.EatToken(this.oLookahead.class);
let oResult = this.GetArguments(2);
let oFrac = {
type: Struc.frac,
up: oResult[0] || {},
down: oResult[1] || {},
fracType: type,
style: oFracStyle,
};
if (strName === '\\binom')
{
return {
type: Struc.bracket_block,
left: "(",
right: ")",
value: [oFrac],
style: {
startStyle : oFracStyle,
endStyle : oFracStyle,
middle: oFracStyle,
},
};
}
return oFrac
};
CLaTeXParser.prototype.IsOverLikeLiteral = function ()
{
return this.oLookahead.data === "\\over"
|| this.oLookahead.data === "\\atop"
}
CLaTeXParser.prototype.GetOverLikeLiteral = function (oNum)
{
if (!oNum)
oNum = this.GetArguments(1);
let oFracStyle = this.oLookahead.style;
let type = this.GetFractionType(this.oLookahead.data);
this.EatToken(this.oLookahead.class);
let oDen = this.GetArguments(1);
return {
type: Struc.frac,
up: oNum || {},
down: oDen || {},
fracType: type,
style: oFracStyle,
};
}
CLaTeXParser.prototype.IsExpBracket = function ()
{
return this.oLookahead.class === Literals.lrBrackets.id
|| this.oLookahead.class === Literals.lBrackets.id
|| this.oLookahead.data === "\\left";
};
CLaTeXParser.prototype.GetBracketLiteral = function ()
{
let arrBracketContent,
strLeftSymbol,
strRightSymbol,
startStyle,
middle_styles = [],
endStyle;
let isRightAndLeft = false;
this.SaveState(this.oLookahead);
if (this.oLookahead.data === "\\left")
{
if (this.oLookahead.data === "\\left")
isRightAndLeft = true;
this.EatToken(this.oLookahead.class);
if (this.oLookahead.data !== "\\left"
&& this.oLookahead.class === Literals.lBrackets.id
|| this.oLookahead.data === "."
|| this.oLookahead.class === Literals.lrBrackets.id
|| this.oLookahead.class === Literals.rBrackets.id)
{
startStyle = this.oLookahead.style;
strLeftSymbol = this.EatToken(this.oLookahead.class).data;
}
else
{
this.RestoreState();
let oData = this.oLookahead;
this.EatToken(this.oLookahead.class);
return {
type: Struc.char,
value: oData.data,
style: oData.style,
}
}
arrBracketContent = this.GetContentOfBracket("\\right", middle_styles);
if (this.oLookahead.data === "\\right")
{
if (this.oLookahead.data === "\\right" && isRightAndLeft)
isRightAndLeft = true;
else
isRightAndLeft = false;
this.EatToken(this.oLookahead.class);
if (this.oLookahead.data !== "\\right"
&& this.oLookahead.class === Literals.rBrackets.id
|| this.oLookahead.data === "."
|| this.oLookahead.class === Literals.lrBrackets.id
|| this.oLookahead.class === Literals.lBrackets.id)
{
endStyle = this.oLookahead.style;
strRightSymbol = this.EatToken(this.oLookahead.class).data;
}
}
}
else if (this.oLookahead.class === Literals.lBrackets.id || this.oLookahead.class === Literals.lrBrackets.id)
{
startStyle = this.oLookahead.style;
strLeftSymbol = this.EatToken(this.oLookahead.class).data;
if (this.oLookahead.data === "_" || this.oLookahead.data === "^")
return this.GetPreScriptLiteral();
if (this.oLookahead.class === undefined) {
return {
type: Struc.char,
value: strLeftSymbol,
style: startStyle,
}
}
if (strLeftSymbol === "|" || strLeftSymbol === "‖" || strLeftSymbol === "\\|")
{
arrBracketContent = this.GetContentOfBracket(strLeftSymbol, middle_styles);
}
else
{
arrBracketContent = this.GetContentOfBracket(undefined, middle_styles);
}
if (this.oLookahead.class === Literals.rBrackets.id || this.oLookahead.class === Literals.lrBrackets.id)
{
endStyle = this.oLookahead.style;
strRightSymbol = this.EatToken(this.oLookahead.class).data;
}
}
if (strLeftSymbol === "{" && strRightSymbol === "}" && !isRightAndLeft)
return arrBracketContent;
return {
type: Struc.bracket_block,
left: strLeftSymbol,
right: strRightSymbol,
value: arrBracketContent,
style: {
startStyle : startStyle,
endStyle : endStyle,
middle: middle_styles,
},
};
};
CLaTeXParser.prototype.GetContentOfBracket = function (strLeftSymbol, arrMiddleStyles)
{
let arrContent = [];
let intCountOfBracketBlock = 1;
while (this.IsElementLiteral()
|| this.oLookahead.data === ""
|| this.oLookahead.data === "\\mid"
|| this.oLookahead.data === "ⓜ")
{
if (strLeftSymbol && this.oLookahead.data === strLeftSymbol)
break;
if (this.oLookahead.data === "\\right")
break;
if (this.IsElementLiteral())
{
// normal space always skip in LaTeX brackets
this.SkipFreeSpace();
let oToken = [this.GetExpressionLiteral([strLeftSymbol])];
if ((oToken && !Array.isArray(oToken)) || Array.isArray(oToken) && oToken.length > 0)
{
arrContent.push(oToken)
}
// normal space always skip in LaTeX brackets
this.SkipFreeSpace();
}
else
{
arrMiddleStyles.push(this.oLookahead.style)
this.EatToken(this.oLookahead.class);
intCountOfBracketBlock++;
// normal space always skip in LaTeX brackets
this.SkipFreeSpace();
}
}
while (arrContent.length < intCountOfBracketBlock)
{
arrContent.push([]);
}
return arrContent;
};
CLaTeXParser.prototype.IsElementLiteral = function ()
{
return this.oLookahead.class !== null && this.IsNotEscapeSymbol() && (
this.IsFractionLiteral() ||
this.oLookahead.class === Literals.number.id ||
this.oLookahead.class === Literals.char.id ||
this.oLookahead.class === Literals.space.id ||
this.IsSqrtLiteral() ||
this.IsExpBracket() ||
this.IsFuncLiteral() ||
this.oLookahead.class === "\\middle" ||
this.IsAccentLiteral() ||
this.IsPreScript() ||
this.IsMathFontLiteral() ||
this.oLookahead.class === "{" ||
this.oLookahead.class === Literals.operator.id ||
this.IsReactLiteral() ||
this.IsBoxLiteral() ||
// this.oLookahead.class === oLiteralNames.opDecimal[0] ||
this.IsArrayLiteral() ||
this.IsMatrixLiteral() ||
this.IsHBracket() ||
this.oLookahead.data === "\\below" ||
this.oLookahead.data === "\\above" ||
this.IsOverUnderBarLiteral() ||
this.IsTextLiteral() ||
this.IsSpecialSymbol() ||
this.oLookahead.class === Literals.other.id ||
this.oLookahead.class === Literals.operand.id ||
this.IsHorizontalArrowLiteral() ||
this.oLookahead.class === Literals.punct.id ||
this.IsUnderOverSet() ||
this.IsOperatorName()
);
};
CLaTeXParser.prototype.IsSpecialSymbol = function ()
{
return this.oLookahead.data === "/" ||
this.oLookahead.data === "&" ||
this.oLookahead.data === "@";
}
CLaTeXParser.prototype.GetSpecialSymbol = function ()
{
let oData = this.oLookahead;
this.EatToken(this.oLookahead.class)
return {
type: Struc.char,
value: oData.data,
style: oData.style,
}
}
CLaTeXParser.prototype.GetElementLiteral = function ()
{
if (this.IsSpecialSymbol())
{
return this.GetSpecialSymbol()
}
else if (this.IsFractionLiteral())
{
return this.GetFractionLiteral();
}
else if (this.oLookahead.class === Literals.number.id)
{
return this.GetNumberLiteral();
}
else if (this.oLookahead.class === Literals.operand.id)
{
return this.GetOperandLiteral();
}
else if (this.oLookahead.class === Literals.char.id)
{
return this.GetCharLiteral();
}
else if (this.oLookahead.class === Literals.punct.id)
{
return this.ReadTokensWhileEnd(Literals.punct, Struc.char);
}
else if (this.IsHorizontalArrowLiteral())
{
return this.GetHorizontalArrowLiteral();
}
else if (this.oLookahead.class === Literals.char.id)
{
return this.GetOtherLiteral();
}
// else if (this.oLookahead.class === oLiteralNames.opDecimal[0])
// {
// let strDecimalLiteral = this.EatToken(this.oLookahead.class).data;
// return {
// type: oLiteralNames.opDecimal[num],
// value: strDecimalLiteral
// }
// }
else if (this.oLookahead.class === Literals.space.id)
{
return this.GetSpaceLiteral();
}
else if (this.IsSqrtLiteral())
{
return this.GetSqrtLiteral();
}
else if (this.IsExpBracket())
{
return this.GetBracketLiteral();
}
else if (this.IsFuncLiteral())
{
return this.GetFuncLiteral();
}
else if (this.oLookahead.class === "\\middle")
{
this.EatToken("\\middle");
return {
type: "MiddleLiteral",
value: this.EatToken(this.oLookahead.class).data,
};
}
else if (this.IsAccentLiteral())
{
return this.GetAccentLiteral();
}
else if (this.IsPreScript())
{
return this.GetPreScriptLiteral();
}
else if (this.IsMathFontLiteral())
{
return this.GetMathFontLiteral();
}
else if (this.oLookahead.data === "{")
{
return this.GetArguments(1)[0];
}
else if (this.oLookahead.class ===Literals.operator.id)
{
return this.GetOperatorLiteral()
}
else if (this.IsReactLiteral())
{
return this.GetRectLiteral()
}
else if (this.IsBoxLiteral())
{
return this.GetBoxLiteral()
}
else if (this.IsMatrixLiteral())
{
return this.GetMatrixLiteral();
}
else if (this.IsArrayLiteral())
{
return this.GetArrayLiteral();
}
else if (this.IsOverUnderBarLiteral())
{
return this.GetUnderOverBarLiteral();
}
else if (this.IsHBracket())
{
return this.GetHBracketLiteral()
}
else if (this.IsTextLiteral())
{
return this.GetTextLiteral();
}
else if (this.IsUnderOverSet())
{
return this.GetUnderOverSetLiteral();
}
else if (this.IsOperatorName())
{
return this.GetOperatorName();
}
else if (this.oLookahead.data === "/")
{
this.EatToken(this.oLookahead.class);
return {
type: Struc.char,
value: "/",
}
}
};
CLaTeXParser.prototype.IsOperatorName = function ()
{
return this.oLookahead.data === "\\operatorname"
};
CLaTeXParser.prototype.GetOperatorName = function ()
{
let style = this.oLookahead.style;
this.EatToken(this.oLookahead.class);
let arg = this.GetArguments(1);
return {
type: Struc.func_lim,
value: arg.value,
style: style,
}
};
CLaTeXParser.prototype.IsUnderOverSet = function ()
{
return this.oLookahead.data === "\\underset"
|| this.oLookahead.data === "\\overset";
};
CLaTeXParser.prototype.GetUnderOverSetLiteral = function()
{
let style = this.oLookahead.style;
let isUnder = this.oLookahead.data === "\\underset";
this.EatToken(this.oLookahead.class); // skip name of function;
let args = this.GetArguments(2);
return {
type: Struc.limit,
base: args[1],
value: args[0],
isBelow: (isUnder === true) ? VJUST_TOP : VJUST_BOT,
style: style,
}
};
CLaTeXParser.prototype.IsHorizontalArrowLiteral = function()
{
return this.oLookahead.class === Literals.horizontal.id;
}
CLaTeXParser.prototype.GetHorizontalArrowLiteral = function ()
{
let oStyle = this.oLookahead.style;
let oData = this.EatToken(this.oLookahead.class);
oData.data = Literals.horizontal.LaTeX[oData.data];
if (this.IsGetBelowAboveLiteral())
{
let isBelow = this.oLookahead.data === "\\below" ? VJUST_TOP : VJUST_BOT;
this.EatToken(this.oLookahead.class);
let oContent = this.GetArguments(1);
return {
type: Struc.group_character,
value: oContent,
hBrack: oData,
down: undefined,
up: undefined,
style: oStyle,
isBelow: isBelow,
}
}
return {
type: Struc.char,
value: oData.data,
style: oStyle,
}
}
CLaTeXParser.prototype.IsGetBelowAboveLiteral = function()
{
return this.oLookahead.data === "\\below" || this.oLookahead.data === "\\above";
}
CLaTeXParser.prototype.GetBelowAboveLiteral = function(base)
{
let oStyle = this.oLookahead.style;
let isBelow = false;
if (this.oLookahead.data === "\\above")
isBelow = true;
this.EatToken(this.oLookahead.class);
let oContent = this.GetArguments(1);
if(base && base.type === Struc.func || base.type === Struc.func_lim)
{
this.SkipFreeSpace();
let third = this.GetArguments(1);
return {
type: Struc.func_lim,
value: {
type: Struc.char,
value: base.type === Struc.func_lim ? base.value.value : base.value,
style: base.style
},
up: isBelow ? oContent : undefined,
down: !isBelow ? oContent : undefined,
third: third,
style: base.style,
}
}
let strNewBaseValue = AscMath.ConvertWord(base.value, true);
if (strNewBaseValue)
base.value = strNewBaseValue;
return {
type: Struc.limit,
base: base,
value: oContent,
isBelow: (isBelow === false) ? VJUST_TOP : VJUST_BOT,
style: oStyle,
}
}
CLaTeXParser.prototype.IsTextLiteral = function ()
{
return this.oLookahead.class === Literals.text.id;
}
CLaTeXParser.prototype.GetTextLiteral = function ()
{
let style = this.oLookahead.style.Copy();
this.EatToken(this.oLookahead.class);
let oContent = this.GetTextArgument();
let metaData = style.GetMathMetaData();
metaData.setIsText(true);
return {
type: Struc.char,
value: oContent,
style: style
}
}
CLaTeXParser.prototype.GetTextArgument = function ()
{
let strText = "";
this.SkipFreeSpace();
this.EatToken(this.oLookahead.class); // {
while (this.oLookahead.data !== "}" && this.oLookahead.data !== undefined)
{
strText += this.EatToken(this.oLookahead.class).data;
}
this.EatToken(this.oLookahead.class); // }
return strText;
}
CLaTeXParser.prototype.IsFuncLiteral = function ()
{
return this.oLookahead.class === Literals.func.id || this.oLookahead.class === Literals.nary.id
};
CLaTeXParser.prototype.GetFuncLiteral = function (oFunc)
{
let oFuncContent = oFunc ? oFunc : this.EatToken(this.oLookahead.class);
let oPr = oFuncContent.style;
let oThirdStyle;
let isNoLimits = false;
let SetStyleAndGetArgument = function (oThis)
{
oThirdStyle = oThis.oLookahead.style;
return oThis.GetArguments(1);
}
if (this.oLookahead.class === "\\limits")
this.EatToken("\\limits");
if (this.oLookahead.class === "\\nolimits")
{
isNoLimits = true;
this.EatToken("\\nolimits")
}
if (this.oLookahead.data === " ")
this.EatToken(this.oLookahead.class);
let oThirdContent = !this.IsSubSup() && !this.IsGetBelowAboveLiteral()
? SetStyleAndGetArgument(this)
: undefined;
let name = oFuncContent.data ? oFuncContent.data : oFuncContent.value;
this.SkipOneSpace();
if (oFuncContent.class === Literals.nary.id)
{
if(AscMath.MathLiterals.func.IsLaTeXIncludeLimit(name) && !isNoLimits)
{
let metaData = oPr.GetMathMetaData();
metaData.setIsLimitNary(true);
}
return {
type: Struc.nary,
value: Literals.nary.LaTeX[name],
style: oPr,
third: oThirdContent,
thirdStyle: oThirdStyle
}
}
else if (AscMath.MathLiterals.func.IsLaTeXIncludeLimit(name) && (this.IsSubSup() || this.IsGetBelowAboveLiteral() || this.oLookahead.data === '\\limits'))
{
return {
type: Struc.func_lim,
value: {
type: Struc.char,
value: name.slice(1),
style: oPr
},
style: oPr,
third: oThirdContent
}
}
else if (AscMath.MathLiterals.func.IsLaTeXIncludeNormal(name))
{
return {
type: Struc.func,
value: {
type: Struc.char,
value: name.slice(1),
style: oPr
},
style: oPr,
third: oThirdContent
}
}
else if (!oThirdContent)
{
return {
type: Struc.func,
value: name.slice(1),
style: oPr
}
}
};
CLaTeXParser.prototype.IsReactLiteral = function ()
{
return this.oLookahead.class === Literals.rect.id;
};
CLaTeXParser.prototype.GetRectLiteral = function ()
{
let oCtrPr = this.oLookahead.style;
this.EatToken(this.oLookahead.class);
let oContent = this.GetArguments(1);
return {
type: Struc.rect,
value: oContent,
style: oCtrPr,
}
};
CLaTeXParser.prototype.IsOverUnderBarLiteral = function ()
{
return this.oLookahead.data === "\\underline" || this.oLookahead.data === "\\overline"
};
CLaTeXParser.prototype.GetUnderOverBarLiteral = function ()
{
let oStyle = this.oLookahead.style;
let strUnderOverLine = this.EatToken(this.oLookahead.class);
let oOperand = this.GetArguments(1);
strUnderOverLine.data = (strUnderOverLine.data === "\\underline")
? "▁"
: "¯";
return {
type: Struc.bar,
bar: strUnderOverLine,
value: oOperand,
style: oStyle,
};
};
CLaTeXParser.prototype.IsBoxLiteral = function ()
{
return this.oLookahead.class === Literals.box.id;
}
CLaTeXParser.prototype.GetBoxLiteral = function ()
{
this.EatToken(this.oLookahead.class);
let oContent = this.GetArguments(1);
return {
type: Struc.box,
value: oContent,
}
};
CLaTeXParser.prototype.GetBorderBoxLiteral = function ()
{
return this.oLookahead.class === Literals.rect.id;
}
CLaTeXParser.prototype.IsGetBorderBoxLiteral = function ()
{
this.EatToken(this.oLookahead.class);
let oContent = this.GetArguments(1);
return {
type: Struc.rect,
value: oContent,
}
}
CLaTeXParser.prototype.IsHBracket = function ()
{
return this.oLookahead.class === Literals.hbrack.id;
};
CLaTeXParser.prototype.GetHBracketLiteral = function ()
{
let oHBracket = this.oLookahead,
oPr = this.oLookahead.style,
oDown,
oUp;
oHBracket.data = Literals.hbrack.LaTeX[oHBracket.data];
let isBelow = Literals.hbrack.GetPos(oHBracket.data);
this.EatToken(this.oLookahead.class);
let oContent = this.GetArguments(1);
this.SkipFreeSpace();
if (this.IsSubSup())
{
if (this.oLookahead.data === "_")
{
this.EatToken(this.oLookahead.class);
oDown = this.GetArguments(1);
}
else
{
this.EatToken(this.oLookahead.class);
oUp = this.GetArguments(1);
}
}
return {
type: Struc.group_character,
value: oContent,
hBrack: oHBracket,
down: oDown,
up: oUp,
style: oPr,
isBelow: isBelow,
}
};
CLaTeXParser.prototype.GetWrapperElementLiteral = function ()
{
if (!this.IsSubSup() && this.oLookahead.class !== "\\over")
{
let oWrapperContent = this.GetElementLiteral();
if (oWrapperContent)
{
if (this.IsSubSup() || this.oLookahead.class === "\\limits")
{
while (this.IsSubSup())
{
oWrapperContent = this.GetSubSupLiteral(oWrapperContent);
}
return oWrapperContent;
}
//else if (this.oLookahead.class === Literals.accent.id)
//{
// return this.GetAccentLiteral(oWrapperContent);
//}
else if (this.IsGetBelowAboveLiteral())
{
return this.GetBelowAboveLiteral(oWrapperContent)
}
else if (this.IsOverLikeLiteral())
{
return this.GetOverLikeLiteral(oWrapperContent);
}
}
return oWrapperContent;
}
};
CLaTeXParser.prototype.GetWrapperElement2 = function ()
{
this.isOneSymbol = true;
let oWrapperContent = this.GetElementLiteral();
if (this.oLookahead.class === Literals.accent.id)
{
return this.GetAccentLiteral(oWrapperContent);
}
else if (this.IsGetBelowAboveLiteral())
{
return this.GetBelowAboveLiteral(oWrapperContent)
}
return oWrapperContent;
};
CLaTeXParser.prototype.IsSubSup = function ()
{
return this.oLookahead.data === "^" || this.oLookahead.data === "_";
};
CLaTeXParser.prototype.GetSubSupLiteral = function (oBaseContent, isSingle)
{
let isLimits,
oDownContent,
oUpContent,
oThirdContent,
oSubStyle,
oSupStyle;
if (undefined === oBaseContent)
{
oBaseContent = this.GetElementLiteral();
}
if (this.oLookahead.class === "\\limits")
{
this.EatToken("\\limits");
isLimits = true;
}
else if (oBaseContent.type === Struc.func_lim || oBaseContent.isLimits)
{
isLimits = true;
}
if (oBaseContent && oBaseContent.type === Struc.bracket_block && oBaseContent.left === "{" && oBaseContent.right === "}")
{
oBaseContent = oBaseContent.value;
}
if (this.oLookahead.data === "'" || this.oLookahead.data === "''")
{
oUpContent = {
type: Struc.char,
value: this.EatToken(this.oLookahead.class).data
}
}
if (this.oLookahead.data === "_")
{
oSubStyle = this.oLookahead.style;
oDownContent = this.GetPartOfSupSup();
this.SkipFreeSpace();
if (this.oLookahead.data === "^" && isSingle !== true)
{
oSupStyle = this.oLookahead.style;
oUpContent = this.GetPartOfSupSup();
}
else if (oDownContent && oDownContent.down === undefined && oDownContent.base)
{
oDownContent = oDownContent.base;
}
}
else if (this.oLookahead.data === "^")
{
oSupStyle = this.oLookahead.style;
oUpContent = this.GetPartOfSupSup();
this.SkipFreeSpace();
if (this.oLookahead.data === "_" && isSingle !== true)
{
oSubStyle = this.oLookahead.style;
oDownContent = this.GetPartOfSupSup();
}
else if (oUpContent && oUpContent.up === undefined && oUpContent.base && oUpContent.type !== "BelowAboveLiteral")
{
oUpContent = oUpContent.base;
}
}
if (oBaseContent && (oBaseContent.type === Struc.func || oBaseContent.type == Struc.func_lim || oBaseContent.type === Struc.nary))
{
this.SkipOneSpace();
oThirdContent = this.GetArguments(1);
}
if (oBaseContent.type === Struc.func_lim && oUpContent && oDownContent)
{
oBaseContent.type = Struc.func;
isLimits = false;
}
return {
type: Struc.sub_sub,
value: oBaseContent,
up: oUpContent,
down: oDownContent,
third: oThirdContent,
isLimits: isLimits,
style: {supStyle: oSupStyle, subStyle: oSubStyle},
};
};
CLaTeXParser.prototype.GetPartOfSupSup = function ()
{
let oElement;
let strSymbol = this.oLookahead.class;
this.EatToken(strSymbol);
if (this.oLookahead.data === "'" || this.oLookahead.data === "''")
{
oElement = {
type: Struc.char,
value: this.EatToken(this.oLookahead.class).data
}
}
else
{
if (this.oLookahead.data === "{")
{
oElement = this.GetArguments(1);
}
else
{
oElement = this.GetWrapperElement2();
}
}
if (this.oLookahead.data === strSymbol) {
oElement = this.GetSubSupLiteral(oElement, true);
}
return oElement;
};
CLaTeXParser.prototype.IsPreScript = function ()
{
return (this.oLookahead.class === "^" || this.oLookahead.class === "_");
};
CLaTeXParser.prototype.GetPreScriptLiteral = function ()
{
let oUpContent;
let oDownContent;
let oBaseContent;
let oOutput;
if (this.oLookahead.data === "_") {
oDownContent = this.GetPartOfSupSup();
if (this.oLookahead.data === "^") {
oUpContent = this.GetPartOfSupSup();
}
}
else if (this.oLookahead.data === "^") {
oUpContent = this.GetPartOfSupSup();
if (this.oLookahead.data === "_") {
oDownContent = this.GetPartOfSupSup();
}
}
if (this.oLookahead.data === "}") {
this.EatToken(this.oLookahead.class)
}
this.SkipFreeSpace();
oBaseContent = this.GetElementLiteral();
oOutput = { type: Struc.pre_script };
if (oUpContent)
oOutput.up = oUpContent;
if (oDownContent)
oOutput.down = oDownContent;
if (oBaseContent)
oOutput.value = oBaseContent;
return oOutput;
};
CLaTeXParser.prototype.IsSqrtLiteral = function ()
{
return this.oLookahead.class === Literals.radical.id;
};
CLaTeXParser.prototype.GetSqrtLiteral = function ()
{
let oBaseContent,
oIndexContent,
oOutput,
oStyle = this.oLookahead.style;
this.EatToken(Literals.radical.id);
if (this.oLookahead.data === "[")
{
this.EatToken(this.oLookahead.class);
oIndexContent = this.GetExpressionLiteral(["]"]);
if (this.oLookahead.data === "]")
{
this.EatToken(this.oLookahead.class);
}
}
oBaseContent = this.GetArguments(1);
oOutput = {
type: Struc.radical,
value: oBaseContent,
style: oStyle,
};
if (oIndexContent)
oOutput.index = oIndexContent;
return oOutput;
};
CLaTeXParser.prototype.IsMathFontLiteral = function ()
{
return this.oLookahead.class === Literals.font.id;
}
CLaTeXParser.prototype.GetMathFontLiteral = function ()
{
let intPrevType = this.intMathFontType;
this.isMathRm = this.oLookahead.data === "\\mathrm";
this.intMathFontType = GetTypeFont[this.oLookahead.data];
this.EatToken(this.oLookahead.class);
let oOutput = this.GetArguments(1);
this.isMathRm = null;
this.intMathFontType = intPrevType;
return oOutput;
};
CLaTeXParser.prototype.IsMatrixLiteral = function ()
{
return (this.oLookahead.class === Literals.matrix.id
|| this.oLookahead.data === "\\substack")
&& !this.IsEndMatrixLiteral()
};
CLaTeXParser.prototype.IsEndMatrixLiteral = function ()
{
return this.oLookahead.class === Literals.matrix.id
&& Literals.matrix.LaTeX[this.oLookahead.data] === 2
|| this.oLookahead.data === "}";
};
CLaTeXParser.prototype.IsAlignBlockForArray = function ()
{
if (this.oLookahead.data !== "{")
return false;
this.SaveState(this.oLookahead);
let oAlignBlock = this.GetArguments(1);
const IsAlignContent = function (str)
{
let arr = [];
for (let i = 0; i < str.length; i++)
{
if (str[i] === "l" || str[i] === "c" || str[i] === "r")
arr.push(true);
}
if (arr.length === str.length)
return true;
return false;
}
if (oAlignBlock.type === Struc.char)
{
let strAlignBlock = oAlignBlock.value.trim();
if (IsAlignContent(strAlignBlock))
return strAlignBlock;
}
else
{
this.RestoreState();
}
};
CLaTeXParser.prototype.IsArrayLiteral = function ()
{
return this.oLookahead.class === Literals.array.id && Literals.array.LaTeX[this.oLookahead.data] === 1
}
CLaTeXParser.prototype.IsEndArrayLiteral = function ()
{
return this.oLookahead.class === Literals.array.id && Literals.array.LaTeX[this.oLookahead.data] === 2
}
CLaTeXParser.prototype.GetArrayLiteral = function ()
{
let name = this.EatToken(this.oLookahead.class).data,
data;
if (name !== "\\array{")
{
// set align in NamesOfLiterals
let align = this.IsAlignBlockForArray();
data = this.GetContentOfMatrixOrArray(function (oThis) {return oThis.IsEndArrayLiteral()});
}
else
{
data = this.GetContentOfMatrixOrArray(function (oThis) {return oThis.oLookahead.data === "}"});
}
return {
type: Struc.matrix,
value: data.value,
style: data.style,
strMatrixType: ""
}
}
CLaTeXParser.prototype.GetMatrixLiteral = function ()
{
let strMatrixType;
switch (this.oLookahead.data)
{
case "\\begin{cases}":
strMatrixType = "{";
break
case "\\begin{pmatrix}":
case "\\pmatrix":
case "⒨":
strMatrixType = "()";
break;
case "\\begin{bmatrix}":
case "\\bmatrix":
strMatrixType = "[]";
break;
case "\\begin{Bmatrix}":
case "\\Bmatrix":
strMatrixType = "{}";
break;
case "\\begin{vmatrix}":
case "\\vmatrix":
strMatrixType = "|";
break;
case "\\begin{Vmatrix}":
case "⒩":
case "\\Vmatrix":
strMatrixType = "‖";
break;
case "\\begin{array}":
case "\\begin{matrix}":
case "\\begin{equation}":
case "\\substack":
case "■":
//case "█":
default:
strMatrixType = "";
}
this.isNowMatrix = true;
let name = this.EatToken(this.oLookahead.class).data;
if (name === "\\substack")
{
this.EatToken(this.oLookahead.class);
}
while (this.oLookahead.data === "[")
{
this.GetArguments(1);
}
this.SkipFreeSpace();
let data = this.GetContentOfMatrixOrArray(function (oThis) {return oThis.IsEndMatrixLiteral()});
this.isNowMatrix = false;
return {
type: Struc.matrix,
value: data.value,
style: data.style,
strMatrixType: strMatrixType,
}
};
CLaTeXParser.prototype.GetContentOfMatrixOrArray = function (oFunc)
{
let oLookahead;
let arrMatrixContent = [];
let styles = {};
let nRow = 0;
styles.head = this.oLookahead.style;
styles.cols = {};
styles.rows = {};
while (this.oLookahead.class !== undefined && !oFunc(this))
{
oLookahead = this.oLookahead;
let oContent = this.GetRayLiteral(styles.cols, styles.rows, nRow, oFunc);
if (oLookahead === this.oLookahead)
break;
if (oContent)
arrMatrixContent.push(oContent);
else if (oContent === false)
arrMatrixContent.push({}, {});
else if (oContent === undefined)
arrMatrixContent.push({});
else if (this.IsEndMatrixLiteral())
arrMatrixContent.push({}, {});
nRow++;
}
let intMaxLengthOfMatrixRow = -Infinity;
let intIndexOfMaxMatrixRow = -1;
for (let i = 0; i < arrMatrixContent.length; i++)
{
let arrContent = arrMatrixContent[i];
intMaxLengthOfMatrixRow = arrContent.length;
intIndexOfMaxMatrixRow = i;
}
for (let i = 0; i < arrMatrixContent.length; i++)
{
if (i !== intIndexOfMaxMatrixRow)
{
let arrMatrix = arrMatrixContent[i];
for (let j = arrMatrix.length; j < intMaxLengthOfMatrixRow; j++)
{
arrMatrix.push({});
}
}
}
if (oFunc(this))
{
this.EatToken(this.oLookahead.class)
}
return {
value: arrMatrixContent,
style: styles,
}
};
CLaTeXParser.prototype.GetRayLiteral = function (cols, rows, nRow, oFunc)
{
let arrRayContent;
let oLookahead;
while (this.oLookahead.class !== Literals.arrayMatrix.id && !oFunc(this))
{
if (oLookahead === this.oLookahead)
return arrRayContent;
else
oLookahead = this.oLookahead;
rows[nRow] = {}
arrRayContent = this.GetElementOfMatrix(rows[nRow]);
nRow++;
}
if (this.oLookahead.class === Literals.arrayMatrix.id)
{
cols[nRow] = this.oLookahead.style;
this.EatToken(this.oLookahead.class)
if (!arrRayContent && this.IsEndMatrixLiteral())
return false;
}
this.SkipFreeSpace();
return arrRayContent
};
CLaTeXParser.prototype.GetElementOfMatrix = function (oStyle)
{
let arrRow = [];
let intLength = 0;
let intCount = 0;
let isAlreadyGetContent = false;
while (this.IsElementLiteral() || this.oLookahead.data === "&" )
{
let intCopyOfLength = intLength;
if (this.oLookahead.data === "\\\\" || this.IsEndMatrixLiteral())
break;
if (this.oLookahead.data !== "&")
{
const checkIsEndFunc = function()
{
return this.IsEndMatrixLiteral() || this.IsEndArrayLiteral() || this.oLookahead.data === '&' || this.oLookahead.data === '\\\\'
}.bind(this);
arrRow.push(this.GetASTTree2(checkIsEndFunc));
intLength++;
isAlreadyGetContent = true;
this.SkipFreeSpace();
}
else
{
oStyle[intCount] = this.oLookahead.style;
this.EatToken(this.oLookahead.class);
if (isAlreadyGetContent === false)
{
arrRow.push({});
intCount++;
intLength++;
}
else if (intCopyOfLength === intLength)
{
intCount++;
}
this.SkipFreeSpace();
}
}
if (intLength !== intCount + 1)
{
for (let j = intLength; j <= intCount; j++)
{
arrRow.push({});
}
}
else if (arrRow.length === 1 && arrRow[0].length === 0)
{
arrRow.push([]);
}
return arrRow;
};
CLaTeXParser.prototype.IsExpressionLiteral = function(arrBreak)
{
const arrEndOfExpression = ["}", "\\endgroup", "\\end", "┤"];
let isEndOfExp = !arrEndOfExpression.includes(this.oLookahead.data);
let isEnd = false;
if (Array.isArray(arrBreak))
isEnd = !arrBreak.includes(this.oLookahead.data);
else
isEnd = this.oLookahead.data !== arrBreak;
let isEscape = this.oLookahead.data !== this.EscapeSymbol
return isEnd
&& isEscape
&& isEndOfExp
&& this.IsElementLiteral();
};
CLaTeXParser.prototype.GetExpressionLiteral = function (arrBreakSymbol, fBreak)
{
this.EscapeSymbol = arrBreakSymbol;
const arrExpList = [];
while (this.IsExpressionLiteral(arrBreakSymbol) && (!fBreak || !fBreak()))
{
if (this.IsPreScript())
{
let el = this.GetPreScriptLiteral();
if (el)
arrExpList.push(el);
}
else
{
let el = this.GetWrapperElementLiteral();
if (el)
arrExpList.push(el);
}
}
this.EscapeSymbol = undefined;
return this.GetContentOfLiteral(arrExpList)
};
CLaTeXParser.prototype.EatToken = function (tokenType)
{
if (tokenType !== undefined && this.oLookahead.class === tokenType) {
const oToken = this.oLookahead;
// if (oToken === null) {
// console.log('Unexpected end of input, expected: ' + tokenType);
// }
// if (oToken.class !== tokenType) {
// console.log('Unexpected token: ' + oToken.class + ', expected: ' + tokenType);
// }
this.oLookahead = this.oTokenizer.GetNextToken();
return oToken;
}
};
CLaTeXParser.prototype.SkipFreeSpace = function ()
{
while (this.oLookahead.data === " ") {
this.oLookahead = this.oTokenizer.GetNextToken();
}
};
CLaTeXParser.prototype.SkipOneSpace = function ()
{
if (this.oLookahead.data === " ") {
this.oLookahead = this.oTokenizer.GetNextToken();
}
}
CLaTeXParser.prototype.GetArguments = function (intCountOfArguments)
{
let oArgument = [];
while (intCountOfArguments > 0) {
this.SkipFreeSpace();
if (this.oLookahead.data === "{") {
this.SkipFreeSpace();
this.EatToken(this.oLookahead.class);
if (this.oLookahead.data === '\\prime')
{
this.EatToken(this.oLookahead.class);
oArgument.push({
type: Struc.char,
value: ""
});
this.EatToken(this.oLookahead.class);
return oArgument;
}
else if (this.oLookahead.data === "\\pprime")
{
this.EatToken(this.oLookahead.class);
oArgument.push({
type: Struc.char,
value: "″"
});
this.EatToken(this.oLookahead.class);
return oArgument;
}
oArgument.push(this.GetExpressionLiteral());
this.EatToken(this.oLookahead.class);
}
else {
this.SkipFreeSpace();
oArgument.push(this.GetWrapperElementLiteral());
}
intCountOfArguments--;
}
if (oArgument.length === 1 && Array.isArray(oArgument)) {
return oArgument[0];
}
return oArgument;
};
CLaTeXParser.prototype.GetContentOfLiteral = function (oContent)
{
if (Array.isArray(oContent))
{
if (oContent.length === 1)
return oContent[0];
return oContent;
}
return oContent;
};
function ConvertLaTeXToTokensList(str, oContext, isGetOnlyTokens)
{
if (undefined === str || null === str)
return;
const oConverter = new CLaTeXParser(true);
const oTokens = oConverter.Parse(str);
if (!isGetOnlyTokens)
ConvertTokens(oTokens, oContext);
else
return oTokens;
return true;
};
//---------------------------------------export----------------------------------------------------
window["AscMath"] = window["AscMath"] || {};
window["AscMath"].ConvertLaTeXToTokensList = ConvertLaTeXToTokensList;
})(window);