Skip to content

Commit 8c8c31e

Browse files
committed
change nested exponent precedence
remove function special case for exponent and application precedence
1 parent 0207924 commit 8c8c31e

6 files changed

+300
-260
lines changed

lib/converters/latex-to-ast.js

Lines changed: 90 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -901,9 +901,6 @@ class latexToAst {
901901
if (this.token.token_text === "+") {
902902
this.advance();
903903

904-
if (params.in_exponent_with_no_delimiters) {
905-
return "+";
906-
}
907904

908905
let factor = this.factor(params);
909906
if (factor === false) {
@@ -918,10 +915,6 @@ class latexToAst {
918915
if (this.token.token_type === '-') {
919916
this.advance();
920917

921-
if (params.in_exponent_with_no_delimiters) {
922-
return "-";
923-
}
924-
925918
let factor = this.factor(params);
926919
if (factor > 0) {
927920
return -factor;
@@ -949,53 +942,24 @@ class latexToAst {
949942

950943
nonMinusFactor(params) {
951944

952-
var result = this.nonMinusFactor_sub(params);
953-
954-
// allow arbitrary sequence of factorials
955-
if (this.token.token_type === '!' || this.token.token_type === "'") {
956-
if (result === false) {
957-
result = '\uff3f';
958-
}
959-
while (this.token.token_type === '!' || this.token.token_type === "'") {
960-
if (this.token.token_type === '!')
961-
result = ['apply', 'factorial', result]
962-
else
963-
result = ['prime', result];
964-
this.advance();
965-
}
966-
}
967-
968-
return result;
969-
}
970-
971-
972-
nonMinusFactor_sub(params) {
973-
974945
var result = this.baseFactor(params);
975946

976-
if (this.token.token_type === '^') {
947+
// allow arbitrary sequence of exponents, factorials or primes
948+
while (this.token.token_type === '^' || this.token.token_type === '!' || this.token.token_type === "'") {
977949
if (result === false) {
978950
result = '\uff3f';
979951
}
980-
this.advance();
981-
982-
let num = this.get_single_digit_as_number();
983-
if (num !== null) {
984-
return ['^', result, num]
985-
}
986-
987-
// do not allow absolute value closing here
988-
let params2 = Object.assign({}, params);
989-
delete params2.allow_absolute_value_closing;
990-
delete params2.inside_absolute_value;
991-
params2.in_exponent_with_no_delimiters = true;
992-
993-
let subresult = this.factor(params2);
994-
if (subresult === false) {
995-
subresult = '\uff3f';
952+
if (this.token.token_type === "^") {
953+
this.advance();
954+
let superscript = this.get_subsuperscript(params);
955+
result = ['^', result, superscript];
956+
} else if (this.token.token_type === '!') {
957+
result = ['apply', 'factorial', result]
958+
this.advance();
959+
} else {
960+
result = ['prime', result];
961+
this.advance();
996962
}
997-
998-
return ['^', result, subresult];
999963
}
1000964

1001965
return result;
@@ -1018,11 +982,29 @@ class latexToAst {
1018982
return null;
1019983
}
1020984

985+
get_subsuperscript({ parse_absolute_value }) {
986+
let num = this.get_single_digit_as_number();
987+
if (num !== null) {
988+
return num;
989+
} else if (["+", "-", "PERP"].includes(this.token.token_type)) {
990+
let subresult = this.token.token_type.toLowerCase();
991+
this.advance();
992+
return subresult;
993+
} else {
994+
let subresult = this.baseFactor({ parse_absolute_value, in_subsuperscript_with_no_delimiters: true });
995+
if (subresult === false) {
996+
subresult = '\uff3f';
997+
}
998+
return subresult;
999+
}
1000+
}
1001+
10211002

10221003
baseFactor({
10231004
inside_absolute_value = 0,
10241005
parse_absolute_value = true,
1025-
allow_absolute_value_closing = false
1006+
allow_absolute_value_closing = false,
1007+
in_subsuperscript_with_no_delimiters = false,
10261008
} = {}) {
10271009

10281010
var result = false;
@@ -1160,7 +1142,8 @@ class latexToAst {
11601142
else
11611143
result = ['^', parameter, ['/', 1, root]];
11621144
} else if (this.token.token_type === 'VAR' || this.token.token_type === 'LATEXCOMMAND'
1163-
|| this.token.token_type === 'VARMULTICHAR') {
1145+
|| this.token.token_type === 'VARMULTICHAR'
1146+
) {
11641147
result = this.token.token_text;
11651148

11661149
if (this.token.token_type === 'LATEXCOMMAND') {
@@ -1179,8 +1162,7 @@ class latexToAst {
11791162
result = /\\operatorname\s*\{\s*([a-zA-Z0-9\+\-]+)\s*\}/.exec(result)[1];
11801163
}
11811164

1182-
if (this.appliedFunctionSymbols.includes(result)
1183-
|| this.functionSymbols.includes(result)) {
1165+
if (this.appliedFunctionSymbols.includes(result) || this.functionSymbols.includes(result)) {
11841166
let must_apply = false
11851167
if (this.appliedFunctionSymbols.includes(result))
11861168
must_apply = true;
@@ -1194,94 +1176,78 @@ class latexToAst {
11941176
if (this.token.token_type === '_') {
11951177
this.advance();
11961178

1197-
let num = this.get_single_digit_as_number();
1198-
if (num !== null) {
1199-
result = ['_', result, num];
1200-
} else {
1179+
let subscript = this.get_subsuperscript({ parse_absolute_value });
12011180

1202-
let subresult;
1203-
if (["+", "-"].includes(this.token.token_text)) {
1204-
subresult = this.token.token_text;
1205-
this.advance();
1206-
} else if (this.token.token_type === "PERP") {
1207-
subresult = "perp";
1208-
this.advance();
1209-
} else {
1210-
subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value });
1211-
if (subresult === false) {
1212-
subresult = '\uff3f';
1213-
}
1214-
}
1215-
1216-
if (result === "log" && subresult === 10) {
1217-
result = "log10";
1218-
} else {
1219-
result = ['_', result, subresult];
1220-
}
1181+
if (result === "log" && subscript === 10) {
1182+
result = "log10";
1183+
} else {
1184+
result = ['_', result, subscript];
12211185
}
12221186
}
12231187

1224-
while (this.token.token_type === "'") {
1225-
result = ['prime', result];
1226-
this.advance();
1227-
}
1228-
1229-
if (this.token.token_type === '^') {
1230-
this.advance();
1188+
if (in_subsuperscript_with_no_delimiters) {
1189+
if (must_apply) {
1190+
result = ['apply', result, '\uff3f'];
1191+
}
1192+
} else {
12311193

1232-
let num = this.get_single_digit_as_number();
1233-
if (num !== null) {
1234-
result = ['^', result, num];
1235-
} else {
1236-
let subresult = this.factor({ parse_absolute_value, in_exponent_with_no_delimiters: true });
1237-
if (subresult === false) {
1238-
subresult = '\uff3f';
1239-
}
1240-
result = ['^', result, subresult];
1194+
while (this.token.token_type === "'") {
1195+
result = ['prime', result];
1196+
this.advance();
12411197
}
1242-
}
12431198

1244-
if (this.token.token_type === '{' || this.token.token_type === '(') {
1245-
let expected_right;
1246-
if (this.token.token_type === '{')
1247-
expected_right = '}';
1248-
else
1249-
expected_right = ')';
1199+
while (this.token.token_type === '^') {
1200+
this.advance();
12501201

1251-
this.advance();
1252-
let parameters = this.statement_list();
1202+
let superscript = this.get_subsuperscript({ parse_absolute_value });
12531203

1254-
if (this.token.token_type !== expected_right) {
1255-
throw new ParseError('Expecting ' + expected_right,
1256-
this.lexer.location);
1204+
result = ['^', result, superscript];
12571205
}
1258-
this.advance();
12591206

1260-
if (parameters[0] === 'list') {
1261-
// rename from list to tuple
1262-
parameters[0] = 'tuple';
1263-
}
1207+
if (this.token.token_type === '{' || this.token.token_type === '(') {
1208+
let expected_right;
1209+
if (this.token.token_type === '{')
1210+
expected_right = '}';
1211+
else
1212+
expected_right = ')';
12641213

1265-
result = ['apply', result, parameters];
1214+
this.advance();
1215+
let parameters = this.statement_list();
12661216

1267-
}
1268-
else {
1269-
// if was an applied function symbol,
1270-
// cannot omit argument
1271-
if (must_apply) {
1272-
if (!this.allowSimplifiedFunctionApplication)
1273-
throw new ParseError("Expecting ( after function",
1217+
if (this.token.token_type !== expected_right) {
1218+
throw new ParseError('Expecting ' + expected_right,
12741219
this.lexer.location);
1220+
}
1221+
this.advance();
12751222

1276-
// if allow simplied function application
1277-
// let the argument be the next factor
1278-
let subresult = this.factor({ parse_absolute_value: parse_absolute_value });
1279-
if (subresult === false) {
1280-
subresult = '\uff3f';
1223+
if (parameters[0] === 'list') {
1224+
// rename from list to tuple
1225+
parameters[0] = 'tuple';
1226+
}
1227+
1228+
result = ['apply', result, parameters];
1229+
1230+
}
1231+
else {
1232+
// if was an applied function symbol,
1233+
// cannot omit argument
1234+
if (must_apply) {
1235+
if (!this.allowSimplifiedFunctionApplication)
1236+
throw new ParseError("Expecting ( after function",
1237+
this.lexer.location);
1238+
1239+
// if allow simplied function application
1240+
// let the argument be the next factor
1241+
let subresult = this.factor({ parse_absolute_value: parse_absolute_value });
1242+
if (subresult === false) {
1243+
subresult = '\uff3f';
1244+
}
1245+
result = ['apply', result, subresult];
12811246
}
1282-
result = ['apply', result, subresult];
12831247
}
12841248
}
1249+
1250+
return result; // have function so took care of subscript already
12851251
}
12861252
else if (result in this.operatorSymbols) {
12871253
this.advance();
@@ -1528,26 +1494,9 @@ class latexToAst {
15281494

15291495
this.advance();
15301496

1531-
let num = this.get_single_digit_as_number();
1532-
if (num !== null) {
1533-
return ['_', result, num];
1534-
}
1535-
1536-
let subresult;
1537-
if (["+", "-"].includes(this.token.token_text)) {
1538-
subresult = this.token.token_text;
1539-
this.advance();
1540-
} else if (this.token.token_type === "PERP") {
1541-
subresult = "perp";
1542-
this.advance();
1543-
} else {
1544-
subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value });
1545-
if (subresult === false) {
1546-
subresult = '\uff3f';
1547-
}
1548-
}
1497+
let subscript = this.get_subsuperscript({ parse_absolute_value });
15491498

1550-
return ['_', result, subresult];
1499+
result = ['_', result, subscript];
15511500
}
15521501

15531502
return result;

0 commit comments

Comments
 (0)