@simonklee/opentui-tex-native-source 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/native/lib.zig +11 -4
- package/native/microtex.patch +825 -0
- package/native/vendor/{.bootstrap-v5 → .bootstrap-v8} +1 -1
- package/native/vendor/microtex/lib/atom/atom_matrix.cpp +44 -35
- package/native/vendor/microtex/lib/atom/atom_matrix.h +2 -2
- package/native/vendor/microtex/lib/atom/atom_row.cpp +2 -2
- package/native/vendor/microtex/lib/core/parse_limits.h +54 -0
- package/native/vendor/microtex/lib/core/parser.cpp +14 -5
- package/native/vendor/microtex/lib/macro/macro_delims.cpp +5 -5
- package/native/vendor/microtex/lib/macro/macro_env.h +33 -33
- package/native/vendor/microtex/lib/utils/string_utils.h +2 -1
- package/native/vendor/microtex/lib/wrapper/byte_seq.cpp +13 -3
- package/native/vendor/microtex/lib/wrapper/byte_seq.h +1 -0
- package/native/vendor/microtex/lib/wrapper/cwrapper.cpp +25 -14
- package/native/vendor/zigtex/src/root.zig +15 -12
- package/native/vendor/zigtex/src/tex.zig +14 -31
- package/native/zigtex-0.16.patch +209 -16
- package/package.json +1 -1
- package/scripts/bootstrap-native +17 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
zigtex=fda2819e45f57ca2071810c47249a46bfc782cdf microtex=74e8fee9e47edc3a777e64fb2eff9a85a01defac nanosvg=239e102ec2c691f2902e20ace2ed36ee4a35cfe6 zig=0.16-
|
|
1
|
+
zigtex=fda2819e45f57ca2071810c47249a46bfc782cdf microtex=74e8fee9e47edc3a777e64fb2eff9a85a01defac nanosvg=239e102ec2c691f2902e20ace2ed36ee4a35cfe6 zig=0.16-v8
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#include "atom/atom_matrix.h"
|
|
2
2
|
|
|
3
|
+
#include <charconv>
|
|
3
4
|
#include <memory>
|
|
4
5
|
|
|
5
6
|
#include "atom/atom_basic.h"
|
|
6
7
|
#include "atom/atom_row.h"
|
|
7
8
|
#include "core/formula.h"
|
|
8
9
|
#include "core/glue.h"
|
|
10
|
+
#include "core/parse_limits.h"
|
|
9
11
|
#include "env/env.h"
|
|
10
12
|
#include "utils/exceptions.h"
|
|
11
13
|
#include "utils/string_utils.h"
|
|
@@ -31,6 +33,8 @@ void MatrixAtom::defineColumnSpecifier(const string& rep, const string& spe) {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
|
|
36
|
+
ParseDepth depth;
|
|
37
|
+
parse_limits.input(opt.size());
|
|
34
38
|
int len = opt.length();
|
|
35
39
|
int pos = 0;
|
|
36
40
|
char ch;
|
|
@@ -39,6 +43,7 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
|
|
|
39
43
|
// clear first
|
|
40
44
|
lpos.clear();
|
|
41
45
|
while (pos < len) {
|
|
46
|
+
parse_limits.spend();
|
|
42
47
|
ch = opt[pos];
|
|
43
48
|
switch (ch) {
|
|
44
49
|
case 'l': lpos.push_back(Alignment::left); break;
|
|
@@ -79,11 +84,22 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
|
|
|
79
84
|
vector<string> args;
|
|
80
85
|
tp->getOptsArgs(2, 0, args);
|
|
81
86
|
pos += tp->getPos();
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
size_t nrep = 0;
|
|
88
|
+
const auto& count = trim(args[1]);
|
|
89
|
+
auto first = count.data();
|
|
90
|
+
if (!count.empty() && count.front() == '+') ++first;
|
|
91
|
+
const auto parsed = from_chars(first, count.data() + count.size(), nrep);
|
|
92
|
+
if (parsed.ec != errc{} || parsed.ptr != count.data() + count.size() ||
|
|
93
|
+
nrep > ParseLimits::bytes_max ||
|
|
94
|
+
(!args[2].empty() && nrep > (ParseLimits::bytes_max - opt.size()) / args[2].size())) {
|
|
95
|
+
throw ParseLimitExceeded{};
|
|
96
|
+
}
|
|
97
|
+
const auto bytes = nrep * args[2].size();
|
|
98
|
+
parse_limits.spend(nrep + bytes);
|
|
84
99
|
string str;
|
|
85
|
-
|
|
86
|
-
|
|
100
|
+
str.reserve(bytes);
|
|
101
|
+
for (size_t j = 0; j < nrep; j++) str += args[2];
|
|
102
|
+
parse_limits.replace(opt, pos, 0, str);
|
|
87
103
|
len = opt.length();
|
|
88
104
|
pos--;
|
|
89
105
|
} break;
|
|
@@ -102,10 +118,11 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
|
|
|
102
118
|
int spos = len + 1;
|
|
103
119
|
bool hasrep = false;
|
|
104
120
|
while (--spos > pos) {
|
|
121
|
+
parse_limits.spend(spos - pos);
|
|
105
122
|
auto it = _colspeReplacement.find(opt.substr(pos, spos - pos));
|
|
106
123
|
if (it != _colspeReplacement.end()) {
|
|
107
124
|
hasrep = true;
|
|
108
|
-
|
|
125
|
+
parse_limits.replace(opt, spos, 0, it->second);
|
|
109
126
|
len = opt.length();
|
|
110
127
|
pos = spos - 1;
|
|
111
128
|
break;
|
|
@@ -127,9 +144,9 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
|
|
|
127
144
|
if (lpos.empty()) lpos.push_back(Alignment::center);
|
|
128
145
|
}
|
|
129
146
|
|
|
130
|
-
float
|
|
147
|
+
vector<float> MatrixAtom::getColumnSep(Env& env, float width) {
|
|
131
148
|
const int cols = _matrix->cols();
|
|
132
|
-
|
|
149
|
+
vector<float> arr(cols + 1);
|
|
133
150
|
sptr<Box> Align, AlignSep, Hsep;
|
|
134
151
|
float h, w = env.textWidth();
|
|
135
152
|
int i = 0;
|
|
@@ -234,7 +251,7 @@ float* MatrixAtom::getColumnSep(Env& env, float width) {
|
|
|
234
251
|
|
|
235
252
|
void MatrixAtom::recalculateLine(
|
|
236
253
|
const int rows,
|
|
237
|
-
sptr<Box
|
|
254
|
+
vector<vector<sptr<Box>>>& boxarr,
|
|
238
255
|
vector<sptr<Atom>>& multiRows,
|
|
239
256
|
float* height,
|
|
240
257
|
float* depth,
|
|
@@ -406,11 +423,11 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
|
|
|
406
423
|
const int rows = _matrix->rows();
|
|
407
424
|
const int cols = _matrix->cols();
|
|
408
425
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
for (
|
|
426
|
+
vector<float> lineDepth(rows);
|
|
427
|
+
vector<float> lineHeight(rows);
|
|
428
|
+
vector<float> colWidth(cols);
|
|
429
|
+
vector<vector<sptr<Box>>> boxarr(rows);
|
|
430
|
+
for (auto& row : boxarr) row.resize(cols);
|
|
414
431
|
|
|
415
432
|
float matW = 0;
|
|
416
433
|
const auto drt = env.ruleThickness();
|
|
@@ -459,7 +476,7 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
|
|
|
459
476
|
for (int j = 0; j < cols; j++) matW += colWidth[j];
|
|
460
477
|
|
|
461
478
|
// The horizontal separator's width
|
|
462
|
-
|
|
479
|
+
auto Hsep = getColumnSep(env, matW);
|
|
463
480
|
|
|
464
481
|
for (auto& i : multiCols) {
|
|
465
482
|
auto* multi = (MulticolumnAtom*)i.get();
|
|
@@ -486,9 +503,9 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
|
|
|
486
503
|
|
|
487
504
|
auto Vsep = _vsep_in.createBox(env);
|
|
488
505
|
// Recalculate the height of the row
|
|
489
|
-
recalculateLine(rows, boxarr, multiRows, lineHeight, lineDepth, drt, Vsep->_height);
|
|
506
|
+
recalculateLine(rows, boxarr, multiRows, lineHeight.data(), lineDepth.data(), drt, Vsep->_height);
|
|
490
507
|
|
|
491
|
-
auto
|
|
508
|
+
auto vb = sptrOf<VBox>();
|
|
492
509
|
float totalHeight = 0;
|
|
493
510
|
float Vspace = Vsep->_height / 2;
|
|
494
511
|
|
|
@@ -511,11 +528,11 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
|
|
|
511
528
|
|
|
512
529
|
bool isLastVline = true;
|
|
513
530
|
|
|
514
|
-
WrapperBox
|
|
531
|
+
sptr<WrapperBox> wb;
|
|
515
532
|
int tj = j;
|
|
516
533
|
float l = j == 0 ? Hsep[j] : Hsep[j] / 2;
|
|
517
534
|
if (boxarr[i][j]->_type == AtomType::none) {
|
|
518
|
-
wb =
|
|
535
|
+
wb = sptrOf<WrapperBox>(
|
|
519
536
|
boxarr[i][j],
|
|
520
537
|
colWidth[j],
|
|
521
538
|
lineHeight[i],
|
|
@@ -523,18 +540,17 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
|
|
|
523
540
|
_position[j] //
|
|
524
541
|
);
|
|
525
542
|
} else {
|
|
526
|
-
auto b = generateMulticolumn(env, boxarr[i][j], Hsep, colWidth, i, j);
|
|
543
|
+
auto b = generateMulticolumn(env, boxarr[i][j], Hsep.data(), colWidth.data(), i, j);
|
|
527
544
|
auto* matom = (MulticolumnAtom*)_matrix->_array[i][j].get();
|
|
528
545
|
j += matom->skipped() - 1;
|
|
529
|
-
wb =
|
|
546
|
+
wb = sptrOf<WrapperBox>(b, b->_width, lineHeight[i], lineDepth[i], Alignment::left);
|
|
530
547
|
isLastVline = matom->hasRightVline();
|
|
531
548
|
}
|
|
532
549
|
float r = j == cols - 1 ? Hsep[j + 1] : Hsep[j + 1] / 2;
|
|
533
550
|
wb->addInsets(l, Vspace, r, Vspace);
|
|
534
551
|
applyCell(*wb, i, j);
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
hb->add(swb);
|
|
552
|
+
boxarr[i][tj] = wb;
|
|
553
|
+
hb->add(wb);
|
|
538
554
|
|
|
539
555
|
auto it = _vlines.find(j + 1);
|
|
540
556
|
if (isLastVline && it != _vlines.end()) {
|
|
@@ -582,14 +598,7 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
|
|
|
582
598
|
vb->_height = totalHeight / 2 + axis;
|
|
583
599
|
vb->_depth = totalHeight / 2 - axis;
|
|
584
600
|
|
|
585
|
-
|
|
586
|
-
delete[] lineDepth;
|
|
587
|
-
delete[] lineHeight;
|
|
588
|
-
delete[] colWidth;
|
|
589
|
-
for (int i = 0; i < rows; i++) delete[] boxarr[i];
|
|
590
|
-
delete[] boxarr;
|
|
591
|
-
|
|
592
|
-
return sptr<Box>(vb);
|
|
601
|
+
return vb;
|
|
593
602
|
}
|
|
594
603
|
|
|
595
604
|
sptr<Box> MatrixAtom::createBox(Env& env) {
|
|
@@ -709,13 +718,13 @@ sptr<Box> VlineAtom::createBox(Env& env) {
|
|
|
709
718
|
const auto drt = env.ruleThickness();
|
|
710
719
|
auto rb = sptrOf<RuleBox>(_height, drt, _shift, MatrixAtom::LINE_COLOR, true);
|
|
711
720
|
auto sep = sptrOf<StrutBox>(2 * drt, 0.f, 0.f, 0.f);
|
|
712
|
-
auto hb =
|
|
721
|
+
auto hb = sptrOf<HBox>();
|
|
713
722
|
for (int i = 0; i < _n - 1; i++) {
|
|
714
723
|
hb->add(rb);
|
|
715
724
|
hb->add(sep);
|
|
716
725
|
}
|
|
717
726
|
if (_n > 0) hb->add(rb);
|
|
718
|
-
return
|
|
727
|
+
return hb;
|
|
719
728
|
}
|
|
720
729
|
|
|
721
730
|
SpaceAtom MultlineAtom::_vsep_in(UnitType::ex, 0.f, 1.f, 0.f);
|
|
@@ -725,7 +734,7 @@ sptr<Box> MultlineAtom::createBox(Env& env) {
|
|
|
725
734
|
if (tw == POS_INF || _lineType == MultiLineType::gathered)
|
|
726
735
|
return MatrixAtom(_isPartial, _column, "").createBox(env);
|
|
727
736
|
|
|
728
|
-
auto
|
|
737
|
+
auto vb = sptrOf<VBox>();
|
|
729
738
|
auto atom = _column->_array[0][0];
|
|
730
739
|
Alignment alignment = _lineType == MultiLineType::gather ? Alignment::center : Alignment::left;
|
|
731
740
|
if (atom->_alignment != Alignment::none) alignment = atom->_alignment;
|
|
@@ -752,5 +761,5 @@ sptr<Box> MultlineAtom::createBox(Env& env) {
|
|
|
752
761
|
vb->_height = h / 2;
|
|
753
762
|
vb->_depth = h / 2;
|
|
754
763
|
|
|
755
|
-
return
|
|
764
|
+
return vb;
|
|
756
765
|
}
|
|
@@ -87,7 +87,7 @@ private:
|
|
|
87
87
|
|
|
88
88
|
static void recalculateLine(
|
|
89
89
|
int rows,
|
|
90
|
-
sptr<Box
|
|
90
|
+
std::vector<std::vector<sptr<Box>>>& boxarr,
|
|
91
91
|
std::vector<sptr<Atom>>& multiRows,
|
|
92
92
|
float* height,
|
|
93
93
|
float* depth,
|
|
@@ -95,7 +95,7 @@ private:
|
|
|
95
95
|
float vspace
|
|
96
96
|
);
|
|
97
97
|
|
|
98
|
-
float
|
|
98
|
+
std::vector<float> getColumnSep(Env& env, float width);
|
|
99
99
|
|
|
100
100
|
void applyCell(WrapperBox& box, int i, int j);
|
|
101
101
|
|
|
@@ -172,7 +172,7 @@ sptr<TextAtom> RowAtom::processContinues(int& i, bool isMathMode) {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
sptr<Box> RowAtom::createBox(Env& env) {
|
|
175
|
-
auto hbox =
|
|
175
|
+
auto hbox = sptrOf<HBox>();
|
|
176
176
|
// convert atoms to boxes and add to the horizontal box
|
|
177
177
|
const int end = _elements.size() - 1;
|
|
178
178
|
for (int i = -1; i < end;) {
|
|
@@ -326,7 +326,7 @@ sptr<Box> RowAtom::createBox(Env& env) {
|
|
|
326
326
|
}
|
|
327
327
|
// reset previous atom
|
|
328
328
|
_previousAtom = nullptr;
|
|
329
|
-
return
|
|
329
|
+
return hbox;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
void RowAtom::setPreviousAtom(const sptr<AtomDecor>& prev) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#ifndef MICROTEX_PARSE_LIMITS_H
|
|
2
|
+
#define MICROTEX_PARSE_LIMITS_H
|
|
3
|
+
|
|
4
|
+
#include <cstddef>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
namespace microtex {
|
|
8
|
+
|
|
9
|
+
// Deliberately not std::exception: partial parsing must not swallow limit failures.
|
|
10
|
+
struct ParseLimitExceeded {};
|
|
11
|
+
|
|
12
|
+
struct ParseLimits {
|
|
13
|
+
// Allow expansion beyond the 4 KiB public input limit, but bound synchronous work.
|
|
14
|
+
static constexpr size_t bytes_max = 64 * 1024;
|
|
15
|
+
size_t work_left = 1024 * 1024;
|
|
16
|
+
size_t replacements_left = 1024;
|
|
17
|
+
size_t depth = 0;
|
|
18
|
+
|
|
19
|
+
void spend(size_t work = 1) {
|
|
20
|
+
if (work > work_left) throw ParseLimitExceeded{};
|
|
21
|
+
work_left -= work;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
void input(size_t bytes) {
|
|
25
|
+
if (bytes > bytes_max) throw ParseLimitExceeded{};
|
|
26
|
+
spend(bytes);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void replace(std::string& source, size_t pos, size_t count, const std::string& text) {
|
|
30
|
+
if (replacements_left == 0 || text.size() > bytes_max ||
|
|
31
|
+
source.size() > bytes_max - text.size()) throw ParseLimitExceeded{};
|
|
32
|
+
--replacements_left;
|
|
33
|
+
spend(source.size() + text.size());
|
|
34
|
+
source.replace(pos, count, text);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Nested parsers and macro argument substitutions share the caller's budget.
|
|
39
|
+
inline thread_local ParseLimits parse_limits;
|
|
40
|
+
|
|
41
|
+
struct ParseDepth {
|
|
42
|
+
ParseDepth() {
|
|
43
|
+
parse_limits.spend();
|
|
44
|
+
if (parse_limits.depth >= 64) throw ParseLimitExceeded{};
|
|
45
|
+
++parse_limits.depth;
|
|
46
|
+
}
|
|
47
|
+
~ParseDepth() { --parse_limits.depth; }
|
|
48
|
+
ParseDepth(const ParseDepth&) = delete;
|
|
49
|
+
ParseDepth& operator=(const ParseDepth&) = delete;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
} // namespace microtex
|
|
53
|
+
|
|
54
|
+
#endif
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "core/parser.h"
|
|
2
|
+
#include "core/parse_limits.h"
|
|
2
3
|
|
|
3
4
|
#include "atom/atom.h"
|
|
4
5
|
#include "atom/atom_basic.h"
|
|
@@ -39,6 +40,7 @@ static constexpr char BACKPRIME = '`';
|
|
|
39
40
|
} // namespace
|
|
40
41
|
|
|
41
42
|
void Parser::init(bool isPartial, const string& latex, Formula* formula, bool firstPass) {
|
|
43
|
+
parse_limits.input(latex.size());
|
|
42
44
|
_pos = _spos = _len = 0;
|
|
43
45
|
_group = 0;
|
|
44
46
|
_atIsLetter = 0;
|
|
@@ -62,6 +64,7 @@ void Parser::init(bool isPartial, const string& latex, Formula* formula, bool fi
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
void Parser::reset(const string& latex) {
|
|
67
|
+
parse_limits.input(latex.size());
|
|
65
68
|
_latex = latex;
|
|
66
69
|
_len = latex.length();
|
|
67
70
|
_formula->_root = nullptr;
|
|
@@ -284,7 +287,7 @@ string Parser::getCmd() {
|
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
void Parser::insert(int beg, int end, const string& formula) {
|
|
287
|
-
|
|
290
|
+
parse_limits.replace(_latex, beg, end - beg, formula);
|
|
288
291
|
_len = _latex.length();
|
|
289
292
|
_pos = beg;
|
|
290
293
|
_insertion = true;
|
|
@@ -363,6 +366,8 @@ string Parser::forward(std::function<bool(char)>&& f) {
|
|
|
363
366
|
}
|
|
364
367
|
|
|
365
368
|
void Parser::getOptsArgs(int argc, int opts, Args& args) {
|
|
369
|
+
ParseDepth depth;
|
|
370
|
+
if (argc < 0 || argc > 10) throw ParseLimitExceeded{};
|
|
366
371
|
// A maximum of 10 options can be passed to a command,
|
|
367
372
|
// the value will be added at the tail of the args if found any,
|
|
368
373
|
// the last (maximum to 12th) value is reserved for returned value
|
|
@@ -536,6 +541,7 @@ sptr<Atom> Parser::getScripts(char first) {
|
|
|
536
541
|
}
|
|
537
542
|
|
|
538
543
|
sptr<Atom> Parser::getArgument() {
|
|
544
|
+
ParseDepth depth;
|
|
539
545
|
skipWhiteSpace();
|
|
540
546
|
char ch;
|
|
541
547
|
if (_pos < _len)
|
|
@@ -619,7 +625,7 @@ void Parser::preprocessNewCmd(string& cmd, Args& args, int& pos) {
|
|
|
619
625
|
auto mac = MacroInfo::get(cmd);
|
|
620
626
|
getOptsArgs(mac->argc, mac->opt, args);
|
|
621
627
|
mac->invoke(*this, args);
|
|
622
|
-
|
|
628
|
+
parse_limits.replace(_latex, pos, _pos - pos, "");
|
|
623
629
|
_len = _latex.length();
|
|
624
630
|
_pos = pos;
|
|
625
631
|
}
|
|
@@ -632,7 +638,7 @@ void Parser::inflateNewCmd(string& cmd, Args& args, int& pos) {
|
|
|
632
638
|
try {
|
|
633
639
|
mac->invoke(*this, args);
|
|
634
640
|
// The last element is the returned value (after inflated macro)
|
|
635
|
-
|
|
641
|
+
parse_limits.replace(_latex, pos, _pos - pos, args.back());
|
|
636
642
|
} catch (ex_parse& e) {
|
|
637
643
|
if (!_isPartial) throw e;
|
|
638
644
|
pos += cmd.length() + 1;
|
|
@@ -654,7 +660,7 @@ void Parser::inflateEnv(string& cmd, Args& args, int& pos) {
|
|
|
654
660
|
string expr = "{\\makeatletter \\" + args[1] + "@env";
|
|
655
661
|
for (int i = 1; i <= mac->argc - 1; i++) expr += "{" + optargs[i] + "}";
|
|
656
662
|
expr += "{" + grp + "}\\makeatother}";
|
|
657
|
-
|
|
663
|
+
parse_limits.replace(_latex, pos, _pos - pos, expr);
|
|
658
664
|
_len = _latex.length();
|
|
659
665
|
_pos = pos;
|
|
660
666
|
}
|
|
@@ -666,6 +672,7 @@ void Parser::preprocess() {
|
|
|
666
672
|
int spos;
|
|
667
673
|
vector<string> args;
|
|
668
674
|
while (_pos < _len) {
|
|
675
|
+
parse_limits.spend();
|
|
669
676
|
ch = _latex[_pos];
|
|
670
677
|
switch (ch) {
|
|
671
678
|
case ESCAPE: {
|
|
@@ -687,7 +694,7 @@ void Parser::preprocess() {
|
|
|
687
694
|
if (chr == '\r' || chr == '\n') break;
|
|
688
695
|
}
|
|
689
696
|
if (_pos < _len) _pos--;
|
|
690
|
-
|
|
697
|
+
parse_limits.replace(_latex, spos, _pos - spos, "");
|
|
691
698
|
_len = _latex.length();
|
|
692
699
|
_pos = spos;
|
|
693
700
|
break;
|
|
@@ -700,6 +707,7 @@ void Parser::preprocess() {
|
|
|
700
707
|
}
|
|
701
708
|
|
|
702
709
|
void Parser::parse() {
|
|
710
|
+
ParseDepth depth;
|
|
703
711
|
if (_len == 0) {
|
|
704
712
|
if (_formula->_root == nullptr && !_arrayMode) _formula->add(sptrOf<EmptyAtom>());
|
|
705
713
|
return;
|
|
@@ -707,6 +715,7 @@ void Parser::parse() {
|
|
|
707
715
|
|
|
708
716
|
char ch;
|
|
709
717
|
while (_pos < _len) {
|
|
718
|
+
parse_limits.spend();
|
|
710
719
|
ch = _latex[_pos];
|
|
711
720
|
|
|
712
721
|
switch (ch) {
|
|
@@ -13,18 +13,18 @@ macro(xarrow) {
|
|
|
13
13
|
StackArgs::autoSpace(Formula(tp, args[1], false, tp.isMathMode())._root, false);
|
|
14
14
|
const auto& under =
|
|
15
15
|
StackArgs::autoSpace(Formula(tp, args[2], false, tp.isMathMode())._root, false);
|
|
16
|
-
const auto stack =
|
|
16
|
+
const auto stack = sptrOf<StackAtom>(nullptr, over, under);
|
|
17
17
|
const auto& arrow = sptrOf<ExtensibleAtom>(
|
|
18
18
|
name,
|
|
19
19
|
// capture raw pointer to avoid cycle reference
|
|
20
|
-
[stack](const Env& env) -> float {
|
|
20
|
+
[stack = stack.get()](const Env& env) -> float {
|
|
21
21
|
return stack->getMaxWidth() + Units::fsize(UnitType::ex, 1.f, env);
|
|
22
22
|
},
|
|
23
23
|
false
|
|
24
24
|
);
|
|
25
25
|
arrow->_type = AtomType::relation;
|
|
26
26
|
stack->setBaseAtom(arrow);
|
|
27
|
-
return
|
|
27
|
+
return stack;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
macro(left) {
|
|
@@ -45,12 +45,12 @@ macro(left) {
|
|
|
45
45
|
return sptrOf<FencedAtom>(tf._root, sl->name(), sr->name(), tf.middle());
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
auto
|
|
48
|
+
auto ra = sptrOf<RowAtom>();
|
|
49
49
|
ra->add(left);
|
|
50
50
|
ra->add(Formula(tp, grep, false)._root);
|
|
51
51
|
ra->add(right);
|
|
52
52
|
|
|
53
|
-
return
|
|
53
|
+
return ra;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
} // namespace microtex
|
|
@@ -11,68 +11,68 @@
|
|
|
11
11
|
namespace microtex {
|
|
12
12
|
|
|
13
13
|
inline macro(smallmatrixATATenv) {
|
|
14
|
-
auto
|
|
15
|
-
Parser parser(tp.isPartial(), args[1], arr, false);
|
|
14
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
15
|
+
Parser parser(tp.isPartial(), args[1], arr.get(), false);
|
|
16
16
|
parser.parse();
|
|
17
17
|
arr->checkDimensions();
|
|
18
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
18
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::smallMatrix);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
inline macro(matrixATATenv) {
|
|
22
|
-
auto
|
|
23
|
-
Parser parser(tp.isPartial(), args[1], arr, false);
|
|
22
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
23
|
+
Parser parser(tp.isPartial(), args[1], arr.get(), false);
|
|
24
24
|
parser.parse();
|
|
25
25
|
arr->checkDimensions();
|
|
26
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
26
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::matrix);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
inline macro(arrayATATenv) {
|
|
30
|
-
auto
|
|
31
|
-
Parser parser(tp.isPartial(), args[2], arr, false);
|
|
30
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
31
|
+
Parser parser(tp.isPartial(), args[2], arr.get(), false);
|
|
32
32
|
parser.parse();
|
|
33
33
|
arr->checkDimensions();
|
|
34
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
34
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, args[1], true);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
inline macro(alignATATenv) {
|
|
38
|
-
auto
|
|
39
|
-
Parser parser(tp.isPartial(), args[1], arr, false);
|
|
38
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
39
|
+
Parser parser(tp.isPartial(), args[1], arr.get(), false);
|
|
40
40
|
parser.parse();
|
|
41
41
|
arr->checkDimensions();
|
|
42
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
42
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::align);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
inline macro(flalignATATenv) {
|
|
46
|
-
auto
|
|
47
|
-
Parser parser(tp.isPartial(), args[1], arr, false);
|
|
46
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
47
|
+
Parser parser(tp.isPartial(), args[1], arr.get(), false);
|
|
48
48
|
parser.parse();
|
|
49
49
|
arr->checkDimensions();
|
|
50
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
50
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::flAlign);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
inline macro(alignatATATenv) {
|
|
54
|
-
auto
|
|
55
|
-
Parser par(tp.isPartial(), args[2], arr, false);
|
|
54
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
55
|
+
Parser par(tp.isPartial(), args[2], arr.get(), false);
|
|
56
56
|
par.parse();
|
|
57
57
|
arr->checkDimensions();
|
|
58
58
|
size_t n = 0;
|
|
59
59
|
valueOf(args[1], n);
|
|
60
60
|
if (arr->cols() != 2 * n) throw ex_parse("Bad number of equations in alignat environment!");
|
|
61
61
|
|
|
62
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
62
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::alignAt);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
inline macro(alignedATATenv) {
|
|
66
|
-
auto
|
|
67
|
-
Parser p(tp.isPartial(), args[1], arr, false);
|
|
66
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
67
|
+
Parser p(tp.isPartial(), args[1], arr.get(), false);
|
|
68
68
|
p.parse();
|
|
69
69
|
arr->checkDimensions();
|
|
70
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
70
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::aligned);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
inline macro(alignedatATATenv) {
|
|
74
|
-
auto
|
|
75
|
-
Parser p(tp.isPartial(), args[2], arr, false);
|
|
74
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
75
|
+
Parser p(tp.isPartial(), args[2], arr.get(), false);
|
|
76
76
|
p.parse();
|
|
77
77
|
arr->checkDimensions();
|
|
78
78
|
size_t n = 0;
|
|
@@ -81,12 +81,12 @@ inline macro(alignedatATATenv) {
|
|
|
81
81
|
throw ex_parse("Bad number of equations in alignedat environment!");
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
return sptrOf<MatrixAtom>(tp.isPartial(),
|
|
84
|
+
return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::alignedAt);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
inline macro(multlineATATenv) {
|
|
88
|
-
auto
|
|
89
|
-
Parser p(tp.isPartial(), args[1], arr, false);
|
|
88
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
89
|
+
Parser p(tp.isPartial(), args[1], arr.get(), false);
|
|
90
90
|
p.parse();
|
|
91
91
|
arr->checkDimensions();
|
|
92
92
|
if (arr->cols() > 1) {
|
|
@@ -94,29 +94,29 @@ inline macro(multlineATATenv) {
|
|
|
94
94
|
}
|
|
95
95
|
if (arr->cols() == 0) return nullptr;
|
|
96
96
|
|
|
97
|
-
return sptrOf<MultlineAtom>(tp.isPartial(),
|
|
97
|
+
return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::multiline);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
inline macro(gatherATATenv) {
|
|
101
|
-
auto
|
|
102
|
-
Parser p(tp.isPartial(), args[1], arr, false);
|
|
101
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
102
|
+
Parser p(tp.isPartial(), args[1], arr.get(), false);
|
|
103
103
|
p.parse();
|
|
104
104
|
arr->checkDimensions();
|
|
105
105
|
if (arr->cols() > 1) throw ex_parse("Requires exact one column in gather environment!");
|
|
106
106
|
if (arr->cols() == 0) return nullptr;
|
|
107
107
|
|
|
108
|
-
return sptrOf<MultlineAtom>(tp.isPartial(),
|
|
108
|
+
return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::gather);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
inline macro(gatheredATATenv) {
|
|
112
|
-
auto
|
|
113
|
-
Parser p(tp.isPartial(), args[1], arr, false);
|
|
112
|
+
auto arr = sptrOf<ArrayFormula>();
|
|
113
|
+
Parser p(tp.isPartial(), args[1], arr.get(), false);
|
|
114
114
|
p.parse();
|
|
115
115
|
arr->checkDimensions();
|
|
116
116
|
if (arr->cols() > 1) throw ex_parse("Requires exact one column in gathered environment!");
|
|
117
117
|
if (arr->cols() == 0) return nullptr;
|
|
118
118
|
|
|
119
|
-
return sptrOf<MultlineAtom>(tp.isPartial(),
|
|
119
|
+
return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::gathered);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
inline macro(multicolumn) {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include <map>
|
|
9
9
|
#include <string>
|
|
10
10
|
#include <vector>
|
|
11
|
+
#include "core/parse_limits.h"
|
|
11
12
|
|
|
12
13
|
namespace microtex {
|
|
13
14
|
|
|
@@ -119,7 +120,7 @@ inline std::string& replaceAll(std::string& src, const std::string& from, const
|
|
|
119
120
|
if (from.empty()) return src;
|
|
120
121
|
size_t start = 0;
|
|
121
122
|
while ((start = src.find(from, start)) != std::string::npos) {
|
|
122
|
-
|
|
123
|
+
parse_limits.replace(src, start, from.length(), to);
|
|
123
124
|
start += to.length();
|
|
124
125
|
}
|
|
125
126
|
return src;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include "wrapper/byte_seq.h"
|
|
4
4
|
|
|
5
5
|
#include <cstdlib>
|
|
6
|
+
#include <new>
|
|
6
7
|
|
|
7
8
|
#include "utils/log.h"
|
|
8
9
|
|
|
@@ -10,11 +11,16 @@ namespace microtex {
|
|
|
10
11
|
|
|
11
12
|
ByteSeq::ByteSeq() {
|
|
12
13
|
_data = malloc(CHUNK_SIZE);
|
|
14
|
+
if (_data == nullptr) throw std::bad_alloc();
|
|
13
15
|
// the first 4 bytes is the bytes size used
|
|
14
16
|
_index = 4;
|
|
15
17
|
_capacity = CHUNK_SIZE;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
ByteSeq::~ByteSeq() {
|
|
21
|
+
free(_data);
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
void ByteSeq::_put(const char* str) {
|
|
19
25
|
auto l = sizeOf(str);
|
|
20
26
|
strcpy((char*)_data + _index, str);
|
|
@@ -28,8 +34,11 @@ void ByteSeq::ensureCapacity(len_t required) {
|
|
|
28
34
|
#ifdef HAVE_LOG
|
|
29
35
|
logv("grow buffer, _capacity: %u, to be add: %u\n", _capacity, required);
|
|
30
36
|
#endif
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
const auto capacity = _index + required + CHUNK_SIZE;
|
|
38
|
+
auto data = realloc(_data, capacity);
|
|
39
|
+
if (data == nullptr) throw std::bad_alloc();
|
|
40
|
+
_data = data;
|
|
41
|
+
_capacity = capacity;
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
void* ByteSeq::finish() {
|
|
@@ -38,7 +47,8 @@ void* ByteSeq::finish() {
|
|
|
38
47
|
#endif
|
|
39
48
|
auto ptr = (unsigned int*)_data;
|
|
40
49
|
*ptr = _index;
|
|
41
|
-
|
|
50
|
+
_data = nullptr;
|
|
51
|
+
return ptr;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
} // namespace microtex
|