papagaio 0.5.0 → 0.6.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/README.md +309 -95
- package/bin/cli.qjs +1 -1
- package/examples/simple.html +2 -2
- package/examples/wasm.papagaio +70 -0
- package/index.html +12 -3
- package/package.json +7 -3
- package/src/papagaio-bootstrap.mjs +3 -5
- package/src/papagaio.js +169 -243
- package/tests/tests.json +37 -37
package/index.html
CHANGED
|
@@ -7,13 +7,16 @@
|
|
|
7
7
|
</head>
|
|
8
8
|
<body>
|
|
9
9
|
|
|
10
|
-
<h1>🦜 papagaio</h1>
|
|
10
|
+
<h1>🦜 papagaio </h1>
|
|
11
11
|
<p>
|
|
12
12
|
easy yet powerful text preprocessor.
|
|
13
13
|
</p>
|
|
14
14
|
<hr>
|
|
15
15
|
<div>
|
|
16
|
-
<
|
|
16
|
+
<strong>
|
|
17
|
+
<label for="sketchSelect">Current Sketch:</label>
|
|
18
|
+
</strong>
|
|
19
|
+
|
|
17
20
|
<select id="sketchSelect" onchange="switchSketch()">
|
|
18
21
|
<option value="">-- Select Sketch --</option>
|
|
19
22
|
</select>
|
|
@@ -24,7 +27,9 @@
|
|
|
24
27
|
</div>
|
|
25
28
|
<hr>
|
|
26
29
|
<div>
|
|
30
|
+
<strong>
|
|
27
31
|
<label for="sketchSelect">Sketches:</label>
|
|
32
|
+
</strong>
|
|
28
33
|
<button onclick="exportSketches()">Export</button>
|
|
29
34
|
<input type="file" id="importFileInput" onchange="importSketches(this.files[0])" accept=".json">
|
|
30
35
|
</div>
|
|
@@ -270,7 +275,8 @@
|
|
|
270
275
|
function exportSketches() {
|
|
271
276
|
const data = {
|
|
272
277
|
papagaio_sketches: localStorage.getItem('papagaio_sketches'),
|
|
273
|
-
papagaio_current_sketch: localStorage.getItem('papagaio_current_sketch')
|
|
278
|
+
papagaio_current_sketch: localStorage.getItem('papagaio_current_sketch'),
|
|
279
|
+
papagaio_config: localStorage.getItem('papagaio_config')
|
|
274
280
|
};
|
|
275
281
|
|
|
276
282
|
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
|
@@ -297,6 +303,9 @@
|
|
|
297
303
|
if (data.papagaio_current_sketch) {
|
|
298
304
|
localStorage.setItem('papagaio_current_sketch', data.papagaio_current_sketch);
|
|
299
305
|
}
|
|
306
|
+
if (data.papagaio_config) {
|
|
307
|
+
localStorage.setItem('papagaio_config', data.papagaio_config);
|
|
308
|
+
}
|
|
300
309
|
location.reload();
|
|
301
310
|
} catch (err) {
|
|
302
311
|
alert('Error importing file: ' + err.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "papagaio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "easy yet powerful preprocessor",
|
|
5
5
|
"main": "src/papagaio.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
"macro",
|
|
17
17
|
"pattern",
|
|
18
18
|
"eval",
|
|
19
|
-
"parser"
|
|
19
|
+
"parser",
|
|
20
|
+
"codegen",
|
|
21
|
+
"regex",
|
|
22
|
+
"syntax",
|
|
23
|
+
"easy"
|
|
20
24
|
],
|
|
21
25
|
"author": "jardimdanificado",
|
|
22
26
|
"bugs": {
|
|
@@ -24,6 +28,6 @@
|
|
|
24
28
|
},
|
|
25
29
|
"homepage": "https://github.com/jardimdanificado/papagaio#readme",
|
|
26
30
|
"bin": {
|
|
27
|
-
"papagaio": "
|
|
31
|
+
"papagaio": "bin/cli.js"
|
|
28
32
|
}
|
|
29
33
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// papagaio-bootstrap.js
|
|
2
|
+
// only needed if using <script type="papagaio"> in browser
|
|
2
3
|
import { Papagaio } from "./papagaio.js";
|
|
3
4
|
|
|
4
5
|
(async () => {
|
|
@@ -15,11 +16,8 @@ import { Papagaio } from "./papagaio.js";
|
|
|
15
16
|
|
|
16
17
|
const out = p.process(src);
|
|
17
18
|
|
|
18
|
-
const s = document.createElement("
|
|
19
|
-
s.type = "module";
|
|
19
|
+
const s = document.createElement("div");
|
|
20
20
|
s.textContent = out;
|
|
21
|
-
|
|
22
|
-
// executa no mesmo ponto onde script estava
|
|
23
|
-
el.replaceWith(s);
|
|
21
|
+
window.document.body.appendChild(s);
|
|
24
22
|
}
|
|
25
23
|
})();
|
package/src/papagaio.js
CHANGED
|
@@ -1,320 +1,246 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const S =
|
|
4
|
-
|
|
5
|
-
while (i <
|
|
6
|
-
if (
|
|
7
|
-
let j = i +
|
|
8
|
-
while (j <
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
// papagaio - https://github.com/jardimdanificado/papagaio
|
|
2
|
+
function parsePattern(p, pat) {
|
|
3
|
+
const t = [], S = p.symbols.sigil, O = p.symbols.open;
|
|
4
|
+
let i = 0;
|
|
5
|
+
while (i < pat.length) {
|
|
6
|
+
if (pat.startsWith(S + p.symbols.regex, i)) {
|
|
7
|
+
let j = i + S.length + p.symbols.regex.length;
|
|
8
|
+
while (j < pat.length && /\s/.test(pat[j])) j++;
|
|
9
|
+
let v = '';
|
|
10
|
+
while (j < pat.length && /[A-Za-z0-9_]/.test(pat[j])) v += pat[j++];
|
|
11
|
+
if (v) {
|
|
12
|
+
while (j < pat.length && /\s/.test(pat[j])) j++;
|
|
13
|
+
if (pat[j] === O) {
|
|
14
|
+
const [rx, e] = extractBlock(p, pat, j);
|
|
15
|
+
t.push({ type: 'regex', varName: v, regex: rx.trim() });
|
|
16
|
+
i = e; continue;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
16
19
|
}
|
|
17
|
-
if (
|
|
18
|
-
let j = i + S.length +
|
|
19
|
-
while (j <
|
|
20
|
-
let
|
|
21
|
-
while (j <
|
|
22
|
-
if (
|
|
23
|
-
while (j <
|
|
24
|
-
let
|
|
25
|
-
if (
|
|
26
|
-
const [c, e] = extractBlock(
|
|
27
|
-
|
|
28
|
-
j = e; while (j <
|
|
20
|
+
if (pat.startsWith(S + p.symbols.block, i)) {
|
|
21
|
+
let j = i + S.length + p.symbols.block.length;
|
|
22
|
+
while (j < pat.length && /\s/.test(pat[j])) j++;
|
|
23
|
+
let v = '';
|
|
24
|
+
while (j < pat.length && /[A-Za-z0-9_]/.test(pat[j])) v += pat[j++];
|
|
25
|
+
if (v) {
|
|
26
|
+
while (j < pat.length && /\s/.test(pat[j])) j++;
|
|
27
|
+
let od = O, cd = p.symbols.close;
|
|
28
|
+
if (pat[j] === O) {
|
|
29
|
+
const [c, e] = extractBlock(p, pat, j);
|
|
30
|
+
od = unescapeDelim(c.trim()) || O;
|
|
31
|
+
j = e; while (j < pat.length && /\s/.test(pat[j])) j++;
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
closeDelim = unescapeDelimiter(c.trim()) || papagaio.symbols.close;
|
|
33
|
+
if (pat[j] === O) {
|
|
34
|
+
const [c, e] = extractBlock(p, pat, j);
|
|
35
|
+
cd = unescapeDelim(c.trim()) || cd;
|
|
34
36
|
j = e;
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
t.push({ type: 'block', varName: v, open: od, close: cd });
|
|
39
|
+
i = j; continue;
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
|
-
if (
|
|
40
|
-
let j = i + S.length,
|
|
41
|
-
while (j <
|
|
42
|
-
if (
|
|
43
|
-
|
|
42
|
+
if (pat[i] === S) {
|
|
43
|
+
let j = i + S.length, v = '';
|
|
44
|
+
while (j < pat.length && /[A-Za-z0-9_]/.test(pat[j])) v += pat[j++];
|
|
45
|
+
if (v) {
|
|
46
|
+
const optional = pat[j] === '?';
|
|
47
|
+
if (optional) j++;
|
|
48
|
+
t.push({ type: 'var', varName: v, optional });
|
|
49
|
+
i = j; continue;
|
|
50
|
+
}
|
|
51
|
+
t.push({ type: 'lit', value: S }); i += S.length; continue;
|
|
44
52
|
}
|
|
45
|
-
if (/\s/.test(
|
|
46
|
-
while (i <
|
|
47
|
-
|
|
53
|
+
if (/\s/.test(pat[i])) {
|
|
54
|
+
while (i < pat.length && /\s/.test(pat[i])) i++;
|
|
55
|
+
t.push({ type: 'ws' }); continue;
|
|
48
56
|
}
|
|
49
|
-
let
|
|
50
|
-
while (i <
|
|
51
|
-
if (
|
|
57
|
+
let lit = '';
|
|
58
|
+
while (i < pat.length && pat[i] !== S && !/\s/.test(pat[i])) lit += pat[i++];
|
|
59
|
+
if (lit) t.push({ type: 'lit', value: lit });
|
|
52
60
|
}
|
|
53
|
-
return
|
|
61
|
+
return t;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
function matchPattern(
|
|
57
|
-
let
|
|
58
|
-
for (let ti = 0; ti <
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
while (pos < src.length && !/\s/.test(src[pos])) v += src[pos++];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!v) return null;
|
|
75
|
-
captures[papagaio.symbols.sigil + token.varName] = v;
|
|
64
|
+
function matchPattern(p, src, tok, pos = 0) {
|
|
65
|
+
let cap = {};
|
|
66
|
+
for (let ti = 0; ti < tok.length; ti++) {
|
|
67
|
+
const t = tok[ti];
|
|
68
|
+
if (t.type === 'ws') { while (pos < src.length && /\s/.test(src[pos])) pos++; continue; }
|
|
69
|
+
if (t.type === 'lit') { if (!src.startsWith(t.value, pos)) return null; pos += t.value.length; continue; }
|
|
70
|
+
if (t.type === 'regex') {
|
|
71
|
+
try {
|
|
72
|
+
const rx = new RegExp(t.regex), m = src.slice(pos).match(rx);
|
|
73
|
+
if (!m || m.index !== 0) return null;
|
|
74
|
+
cap[p.symbols.sigil + t.varName] = m[0];
|
|
75
|
+
pos += m[0].length;
|
|
76
|
+
} catch (e) { return null; }
|
|
76
77
|
continue;
|
|
77
78
|
}
|
|
78
|
-
if (
|
|
79
|
+
if (t.type === 'var') {
|
|
79
80
|
while (pos < src.length && /\s/.test(src[pos])) pos++;
|
|
80
|
-
const
|
|
81
|
+
const nx = findNext(tok, ti);
|
|
81
82
|
let v = '';
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
while (pos < src.length && !src.startsWith(n.openDelim, pos) && src[pos] !== '\n') {
|
|
85
|
-
v += src[pos++];
|
|
86
|
-
}
|
|
83
|
+
if (nx && nx.type === 'block') {
|
|
84
|
+
while (pos < src.length && !src.startsWith(nx.open, pos) && src[pos] !== '\n') v += src[pos++];
|
|
87
85
|
v = v.trimEnd();
|
|
88
|
-
} else if (
|
|
89
|
-
while (pos < src.length &&
|
|
90
|
-
} else if (n.type === 'literal') {
|
|
91
|
-
while (pos < src.length && !src.startsWith(n.value, pos) && src[pos] !== '\n') v += src[pos++];
|
|
86
|
+
} else if (nx && nx.type === 'lit') {
|
|
87
|
+
while (pos < src.length && !src.startsWith(nx.value, pos) && src[pos] !== '\n') v += src[pos++];
|
|
92
88
|
v = v.trimEnd();
|
|
89
|
+
} else {
|
|
90
|
+
while (pos < src.length && !/\s/.test(src[pos])) v += src[pos++];
|
|
93
91
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
captures[papagaio.symbols.sigil + token.varName] = v;
|
|
92
|
+
if (!v && !t.optional) return null;
|
|
93
|
+
cap[p.symbols.sigil + t.varName] = v;
|
|
97
94
|
continue;
|
|
98
95
|
}
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
captures[papagaio.symbols.sigil + varName] = c; pos = e; continue;
|
|
96
|
+
if (t.type === 'block') {
|
|
97
|
+
if (!src.startsWith(t.open, pos)) return null;
|
|
98
|
+
const [c, e] = extractBlock(p, src, pos, t.open, t.close);
|
|
99
|
+
cap[p.symbols.sigil + t.varName] = c; pos = e; continue;
|
|
104
100
|
}
|
|
105
101
|
}
|
|
106
|
-
return { captures, endPos: pos };
|
|
102
|
+
return { captures: cap, endPos: pos };
|
|
107
103
|
}
|
|
108
104
|
|
|
109
|
-
function
|
|
105
|
+
function findNext(t, i) { for (let k = i + 1; k < t.length; k++) if (t[k].type !== 'ws') return t[k]; return null; }
|
|
110
106
|
|
|
111
|
-
function extractBlock(p, src,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
i += openDelim.length; const s = i; let d = 0;
|
|
107
|
+
function extractBlock(p, src, i, od = p.symbols.open, cd = p.symbols.close) {
|
|
108
|
+
if (od.length > 1 || cd.length > 1) {
|
|
109
|
+
if (src.substring(i, i + od.length) === od) {
|
|
110
|
+
i += od.length; const s = i; let d = 0;
|
|
116
111
|
while (i < src.length) {
|
|
117
|
-
if (src.substring(i, i +
|
|
118
|
-
else if (src.substring(i, i +
|
|
119
|
-
if (!d) return [src.substring(s, i), i +
|
|
120
|
-
d--; i +=
|
|
112
|
+
if (src.substring(i, i + od.length) === od) { d++; i += od.length; }
|
|
113
|
+
else if (src.substring(i, i + cd.length) === cd) {
|
|
114
|
+
if (!d) return [src.substring(s, i), i + cd.length];
|
|
115
|
+
d--; i += cd.length;
|
|
121
116
|
} else i++;
|
|
122
117
|
}
|
|
123
118
|
return [src.substring(s), src.length];
|
|
124
119
|
}
|
|
125
120
|
}
|
|
126
|
-
if (src[i] ===
|
|
121
|
+
if (src[i] === od) {
|
|
127
122
|
i++; const s = i;
|
|
128
|
-
if (
|
|
123
|
+
if (od === cd) { while (i < src.length && src[i] !== cd) i++; return [src.substring(s, i), i + 1]; }
|
|
129
124
|
let d = 1;
|
|
130
|
-
while (i < src.length && d > 0) { if (src[i] ===
|
|
125
|
+
while (i < src.length && d > 0) { if (src[i] === od) d++; else if (src[i] === cd) d--; if (d > 0) i++; }
|
|
131
126
|
return [src.substring(s, i), i + 1];
|
|
132
127
|
}
|
|
133
128
|
return ['', i];
|
|
134
129
|
}
|
|
135
130
|
|
|
136
|
-
function
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
131
|
+
function extractNested(p, txt) {
|
|
132
|
+
const loc = [], S = p.symbols.sigil, O = p.symbols.open;
|
|
133
|
+
let out = txt;
|
|
134
|
+
const rx = new RegExp(`${esc(S)}${esc(p.symbols.pattern)}\\s*${esc(O)}`, "g");
|
|
141
135
|
while (1) {
|
|
142
|
-
|
|
143
|
-
const s = m.index, o = m.index + m[0].length -
|
|
136
|
+
rx.lastIndex = 0; const m = rx.exec(out); if (!m) break;
|
|
137
|
+
const s = m.index, o = m.index + m[0].length - O.length;
|
|
144
138
|
const [mp, em] = extractBlock(p, out, o); let k = em;
|
|
145
139
|
while (k < out.length && /\s/.test(out[k])) k++;
|
|
146
|
-
if (k < out.length && out.substring(k, k +
|
|
140
|
+
if (k < out.length && out.substring(k, k + O.length) === O) {
|
|
147
141
|
const [rp, er] = extractBlock(p, out, k);
|
|
148
|
-
|
|
142
|
+
loc.push({ m: mp.trim(), r: rp.trim() });
|
|
149
143
|
out = out.slice(0, s) + out.slice(er); continue;
|
|
150
144
|
}
|
|
151
145
|
out = out.slice(0, s) + out.slice(em);
|
|
152
146
|
}
|
|
153
|
-
return [
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function extractNestedPatterns(p, replaceText) {
|
|
157
|
-
const nested = [];
|
|
158
|
-
const r = new RegExp(`${escapeRegex(p.symbols.sigil)}${escapeRegex(p.symbols.pattern)}\\s*${escapeRegex(p.symbols.open)}`, "g");
|
|
159
|
-
let out = replaceText;
|
|
160
|
-
|
|
161
|
-
while (1) {
|
|
162
|
-
r.lastIndex = 0;
|
|
163
|
-
const m = r.exec(out);
|
|
164
|
-
if (!m) break;
|
|
165
|
-
|
|
166
|
-
const s = m.index, o = m.index + m[0].length - p.symbols.open.length;
|
|
167
|
-
const [mp, em] = extractBlock(p, out, o);
|
|
168
|
-
let k = em;
|
|
169
|
-
|
|
170
|
-
while (k < out.length && /\s/.test(out[k])) k++;
|
|
171
|
-
|
|
172
|
-
if (k < out.length && out.substring(k, k + p.symbols.open.length) === p.symbols.open) {
|
|
173
|
-
const [rp, er] = extractBlock(p, out, k);
|
|
174
|
-
nested.push({ match: mp.trim(), replace: rp.trim() });
|
|
175
|
-
out = out.slice(0, s) + out.slice(er);
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
out = out.slice(0, s) + out.slice(em);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return [nested, out];
|
|
147
|
+
return [loc, out];
|
|
182
148
|
}
|
|
183
149
|
|
|
184
|
-
function
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
while (j < text.length && /\s/.test(text[j])) j++;
|
|
202
|
-
|
|
203
|
-
if (j < text.length && text.substring(j, j + O.length) === O) {
|
|
204
|
-
const startPos = i;
|
|
205
|
-
const blockStart = j;
|
|
206
|
-
|
|
207
|
-
const [content, endPos] = extractBlock(p, text, blockStart, O, C);
|
|
208
|
-
|
|
209
|
-
evals.push({
|
|
210
|
-
fullMatch: text.substring(startPos, endPos),
|
|
211
|
-
code: content,
|
|
212
|
-
startPos: startPos - offset,
|
|
213
|
-
endPos: endPos - offset
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const before = out.substring(0, startPos - offset);
|
|
217
|
-
const after = out.substring(endPos - offset);
|
|
218
|
-
const placeholder = `__EVAL_${evals.length - 1}__`;
|
|
219
|
-
out = before + placeholder + after;
|
|
220
|
-
|
|
221
|
-
offset += (endPos - startPos) - placeholder.length;
|
|
222
|
-
i = endPos;
|
|
223
|
-
continue;
|
|
150
|
+
function extractEvals(p, txt) {
|
|
151
|
+
const ev = [], S = p.symbols.sigil, O = p.symbols.open;
|
|
152
|
+
let i = 0, out = txt, off = 0;
|
|
153
|
+
while (i < txt.length) {
|
|
154
|
+
if (txt.substring(i, i + S.length) === S) {
|
|
155
|
+
const rest = txt.substring(i + S.length);
|
|
156
|
+
if (rest.startsWith(p.symbols.eval)) {
|
|
157
|
+
let j = i + S.length + p.symbols.eval.length;
|
|
158
|
+
while (j < txt.length && /\s/.test(txt[j])) j++;
|
|
159
|
+
if (j < txt.length && txt.substring(j, j + O.length) === O) {
|
|
160
|
+
const sp = i, bp = j, [c, ep] = extractBlock(p, txt, bp);
|
|
161
|
+
ev.push({ code: c, sp: sp - off, ep: ep - off });
|
|
162
|
+
const ph = `__E${ev.length - 1}__`;
|
|
163
|
+
out = out.substring(0, sp - off) + ph + out.substring(ep - off);
|
|
164
|
+
off += (ep - sp) - ph.length; i = ep; continue;
|
|
165
|
+
}
|
|
224
166
|
}
|
|
225
167
|
}
|
|
226
168
|
i++;
|
|
227
169
|
}
|
|
228
|
-
|
|
229
|
-
return [evals, out];
|
|
170
|
+
return [ev, out];
|
|
230
171
|
}
|
|
231
172
|
|
|
232
|
-
function
|
|
233
|
-
let
|
|
234
|
-
for (let i =
|
|
235
|
-
const
|
|
236
|
-
let
|
|
237
|
-
try {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
evalResult = "javascript error: " + e.message;
|
|
241
|
-
}
|
|
242
|
-
result = result.replace(placeholder, evalResult);
|
|
173
|
+
function applyEvals(p, txt, ev) {
|
|
174
|
+
let r = txt;
|
|
175
|
+
for (let i = ev.length - 1; i >= 0; i--) {
|
|
176
|
+
const ph = `__E${i}__`;
|
|
177
|
+
let res;
|
|
178
|
+
try { res = String(Function("papagaio", "ctx", `"use strict";return(function(){${ev[i].code}})();`)(p, {})); }
|
|
179
|
+
catch (e) { res = "error: " + e.message; }
|
|
180
|
+
r = r.replace(ph, res);
|
|
243
181
|
}
|
|
244
|
-
return
|
|
182
|
+
return r;
|
|
245
183
|
}
|
|
246
184
|
|
|
247
|
-
function
|
|
248
|
-
let clear = false, last = "", S = p.symbols.sigil;
|
|
185
|
+
function applyPats(p, src, pats) {
|
|
249
186
|
for (const pat of pats) {
|
|
250
|
-
const
|
|
187
|
+
const tok = parsePattern(p, pat.m);
|
|
188
|
+
let n = '', pos = 0, ok = false;
|
|
251
189
|
while (pos < src.length) {
|
|
252
|
-
const m = matchPattern(p, src,
|
|
190
|
+
const m = matchPattern(p, src, tok, pos);
|
|
253
191
|
if (m) {
|
|
254
|
-
ok = true;
|
|
255
|
-
let r = pat.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
p.match = src.slice(pos, endPos);
|
|
267
|
-
|
|
268
|
-
const [evals, cleanText] = extractEvalExpressions(p, r);
|
|
269
|
-
if (evals.length > 0) {
|
|
270
|
-
r = applyEvalExpressions(p, cleanText, evals);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
n += r; last = r; pos = endPos;
|
|
192
|
+
ok = true;
|
|
193
|
+
let r = pat.r;
|
|
194
|
+
const [loc, cln] = extractNested(p, r);
|
|
195
|
+
r = cln;
|
|
196
|
+
Object.keys(m.captures).forEach(k => {
|
|
197
|
+
r = r.replace(new RegExp(esc(k) + '(?![A-Za-z0-9_])', 'g'), m.captures[k]);
|
|
198
|
+
});
|
|
199
|
+
if (loc.length) r = applyPats(p, r, loc);
|
|
200
|
+
p.match = src.slice(pos, m.endPos);
|
|
201
|
+
const [ev, ct] = extractEvals(p, r);
|
|
202
|
+
if (ev.length) r = applyEvals(p, ct, ev);
|
|
203
|
+
n += r; pos = m.endPos;
|
|
274
204
|
} else { n += src[pos]; pos++; }
|
|
275
205
|
}
|
|
276
|
-
if (ok)
|
|
206
|
+
if (ok) src = n;
|
|
277
207
|
}
|
|
278
208
|
return src;
|
|
279
209
|
}
|
|
280
210
|
|
|
281
|
-
function
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (s[i] === '\\' && i + 1 < s.length) {
|
|
286
|
-
|
|
287
|
-
if (n === '"' || n === "'" || n === '\\') { r += n; i++; }
|
|
288
|
-
else r += s[i];
|
|
289
|
-
} else r += s[i];
|
|
211
|
+
function esc(s) { return s.replace(/[.*+?^${}()|[\]\\""']/g, '\\$&'); }
|
|
212
|
+
function unescapeDelim(s) {
|
|
213
|
+
let r = '';
|
|
214
|
+
for (let i = 0; i < s.length; i++) {
|
|
215
|
+
if (s[i] === '\\' && i + 1 < s.length && (s[i+1] === '"' || s[i+1] === "'" || s[i+1] === '\\')) { r += s[i+1]; i++; }
|
|
216
|
+
else r += s[i];
|
|
290
217
|
}
|
|
291
218
|
return r;
|
|
292
219
|
}
|
|
293
220
|
|
|
294
221
|
export class Papagaio {
|
|
295
|
-
constructor(sigil = '$', open = '{', close = '}', pattern = 'pattern',
|
|
296
|
-
this.
|
|
297
|
-
this.symbols = {
|
|
298
|
-
pattern: pattern,
|
|
299
|
-
open: open,
|
|
300
|
-
close: close,
|
|
301
|
-
sigil: sigil,
|
|
302
|
-
eval: evalKeyword,
|
|
303
|
-
block: blockKeyword
|
|
304
|
-
};
|
|
222
|
+
constructor(sigil = '$', open = '{', close = '}', pattern = 'pattern', evalKw = 'eval', blockKw = 'block', regexKw = 'regex') {
|
|
223
|
+
this.symbols = { pattern, open, close, sigil, eval: evalKw, block: blockKw, regex: regexKw };
|
|
305
224
|
this.content = "";
|
|
225
|
+
this.match = "";
|
|
306
226
|
}
|
|
307
227
|
process(input) {
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
228
|
+
const [loc, cln] = extractNested(this, input);
|
|
229
|
+
const [evals, ph] = extractEvals(this, cln);
|
|
230
|
+
let proc = applyEvals(this, ph, evals);
|
|
231
|
+
if (loc.length === 0) {
|
|
232
|
+
this.content = proc;
|
|
233
|
+
return proc;
|
|
234
|
+
}
|
|
235
|
+
let src = proc, last = null;
|
|
236
|
+
while (src !== last) {
|
|
237
|
+
last = src;
|
|
238
|
+
src = applyPats(this, src, loc);
|
|
239
|
+
const [nested] = extractNested(this, src);
|
|
240
|
+
if (nested.length === 0) break;
|
|
317
241
|
}
|
|
318
|
-
|
|
242
|
+
this.content = src;
|
|
243
|
+
if (typeof this.exit == "function") this.exit();
|
|
244
|
+
return this.content;
|
|
319
245
|
}
|
|
320
246
|
}
|