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/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
- <label for="sketchSelect">Current Sketch:</label>
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.5.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": "./bin/cli.js"
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("script");
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
- function parsePattern(papagaio, pattern) {
2
- const tokens = []; let i = 0;
3
- const S = papagaio.symbols.sigil, S2 = S + S;
4
- const blockKw = papagaio.symbols.block;
5
- while (i < pattern.length) {
6
- if (pattern.startsWith(S2 + S, i)) {
7
- let j = i + S2.length + S.length, varName = '';
8
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
9
- if (varName) { tokens.push({ type: 'var-ws-optional', varName }); i = j; continue; }
10
- }
11
- if (pattern.startsWith(S2, i)) {
12
- let j = i + S2.length, varName = '';
13
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
14
- if (varName) { tokens.push({ type: 'var-ws', varName }); i = j; continue; }
15
- tokens.push({ type: 'whitespace-optional' }); i += S2.length; continue;
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 (pattern.startsWith(S + blockKw, i)) {
18
- let j = i + S.length + blockKw.length;
19
- while (j < pattern.length && /\s/.test(pattern[j])) j++;
20
- let varName = '';
21
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
22
- if (varName) {
23
- while (j < pattern.length && /\s/.test(pattern[j])) j++;
24
- let openDelim = papagaio.symbols.open;
25
- if (j < pattern.length && pattern[j] === papagaio.symbols.open) {
26
- const [c, e] = extractBlock(papagaio, pattern, j);
27
- openDelim = unescapeDelimiter(c.trim()) || papagaio.symbols.open;
28
- j = e; while (j < pattern.length && /\s/.test(pattern[j])) 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
- let closeDelim = papagaio.symbols.close;
31
- if (j < pattern.length && pattern[j] === papagaio.symbols.open) {
32
- const [c, e] = extractBlock(papagaio, pattern, j);
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
- tokens.push({ type: 'block', varName, openDelim, closeDelim }); i = j; continue;
38
+ t.push({ type: 'block', varName: v, open: od, close: cd });
39
+ i = j; continue;
37
40
  }
38
41
  }
39
- if (pattern[i] === S) {
40
- let j = i + S.length, varName = '';
41
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
42
- if (varName) { tokens.push({ type: 'var', varName }); i = j; continue; }
43
- tokens.push({ type: 'literal', value: S }); i += S.length; continue;
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(pattern[i])) {
46
- while (i < pattern.length && /\s/.test(pattern[i])) i++;
47
- tokens.push({ type: 'whitespace-optional' }); continue;
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 literal = '';
50
- while (i < pattern.length && !pattern.startsWith(S, i) && !/\s/.test(pattern[i])) literal += pattern[i++];
51
- if (literal) tokens.push({ type: 'literal', value: literal });
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 tokens;
61
+ return t;
54
62
  }
55
63
 
56
- function matchPattern(papagaio, src, tokens, startPos = 0) {
57
- let pos = startPos, captures = {};
58
- for (let ti = 0; ti < tokens.length; ti++) {
59
- const token = tokens[ti];
60
- if (token.type === 'whitespace-optional') { while (pos < src.length && /\s/.test(src[pos])) pos++; continue; }
61
- if (token.type === 'literal') { if (!src.startsWith(token.value, pos)) return null; pos += token.value.length; continue; }
62
- if (token.type === 'var') {
63
- const nextToken = findNextSignificantToken(tokens, ti);
64
- let v = '';
65
-
66
- if (nextToken && nextToken.type === 'block') {
67
- while (pos < src.length && !src.startsWith(nextToken.openDelim, pos) && !/\s/.test(src[pos])) {
68
- v += src[pos++];
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 (token.type === 'var-ws' || token.type === 'var-ws-optional') {
79
+ if (t.type === 'var') {
79
80
  while (pos < src.length && /\s/.test(src[pos])) pos++;
80
- const n = findNextSignificantToken(tokens, ti);
81
+ const nx = findNext(tok, ti);
81
82
  let v = '';
82
-
83
- if (n && n.type === 'block') {
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 (!n || ['var', 'var-ws', 'var-ws-optional'].includes(n.type)) {
89
- while (pos < src.length && !/\s/.test(src[pos])) v += src[pos++];
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
- if (token.type === 'var-ws' && !v) return null;
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 (token.type === 'block') {
100
- const { varName, openDelim, closeDelim } = token;
101
- if (!src.startsWith(openDelim, pos)) return null;
102
- const [c, e] = extractBlock(papagaio, src, pos, openDelim, closeDelim);
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 findNextSignificantToken(t, i) { for (let k = i + 1; k < t.length; k++) if (t[k].type !== 'whitespace-optional') return t[k]; return null; }
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, openPos, openDelim = p.symbols.open, closeDelim = p.symbols.close) {
112
- let i = openPos;
113
- if (openDelim.length > 1 || closeDelim.length > 1) {
114
- if (src.substring(i, i + openDelim.length) === openDelim) {
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 + openDelim.length) === openDelim) { d++; i += openDelim.length; }
118
- else if (src.substring(i, i + closeDelim.length) === closeDelim) {
119
- if (!d) return [src.substring(s, i), i + closeDelim.length];
120
- d--; i += closeDelim.length;
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] === openDelim) {
121
+ if (src[i] === od) {
127
122
  i++; const s = i;
128
- if (openDelim === closeDelim) { while (i < src.length && src[i] !== closeDelim) i++; return [src.substring(s, i), i + 1]; }
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] === openDelim) d++; else if (src[i] === closeDelim) d--; if (d > 0) 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 collectPatterns(p, src) {
137
- const A = [];
138
- const r = new RegExp(`(?:^|\\b)${escapeRegex(p.symbols.pattern)}\\s*${escapeRegex(p.symbols.open)}`, "g");
139
- let out = src;
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
- r.lastIndex = 0; const m = r.exec(out); if (!m) break;
143
- const s = m.index, o = m.index + m[0].length - p.symbols.open.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 + p.symbols.open.length) === p.symbols.open) {
140
+ if (k < out.length && out.substring(k, k + O.length) === O) {
147
141
  const [rp, er] = extractBlock(p, out, k);
148
- A.push({ match: mp.trim(), replace: rp.trim() });
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 [A, out];
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 extractEvalExpressions(p, text) {
185
- const evals = [];
186
- const S = p.symbols.sigil;
187
- const O = p.symbols.open;
188
- const C = p.symbols.close;
189
- const evalKeyword = p.symbols.eval;
190
-
191
- let i = 0;
192
- let out = text;
193
- let offset = 0;
194
-
195
- while (i < text.length) {
196
- if (text.substring(i, i + S.length) === S &&
197
- text.substring(i + S.length, i + S.length + evalKeyword.length) === evalKeyword) {
198
-
199
- let j = i + S.length + evalKeyword.length;
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 applyEvalExpressions(p, text, evals) {
233
- let result = text;
234
- for (let i = evals.length - 1; i >= 0; i--) {
235
- const placeholder = `__EVAL_${i}__`;
236
- let evalResult;
237
- try {
238
- evalResult = String(Function("papagaio", "ctx", `"use strict";return(function(){${evals[i].code}})();`)(p, {}));
239
- } catch (e) {
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 result;
182
+ return r;
245
183
  }
246
184
 
247
- function applyPatterns(p, src, pats) {
248
- let clear = false, last = "", S = p.symbols.sigil;
185
+ function applyPats(p, src, pats) {
249
186
  for (const pat of pats) {
250
- const t = parsePattern(p, pat.match); let n = '', pos = 0, ok = false;
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, t, pos);
190
+ const m = matchPattern(p, src, tok, pos);
253
191
  if (m) {
254
- ok = true; const { captures, endPos } = m;
255
- let r = pat.replace;
256
-
257
- const [nestedPats, cleanReplace] = extractNestedPatterns(p, r);
258
- r = cleanReplace;
259
-
260
- for (const [k, v] of Object.entries(captures)) {
261
- const e = escapeRegex(k); r = r.replace(new RegExp(e + '(?![A-Za-z0-9_])', 'g'), v);
262
- }
263
-
264
- if (nestedPats.length > 0) r = applyPatterns(p, r, nestedPats);
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) { src = clear ? last : n; clear = false; }
206
+ if (ok) src = n;
277
207
  }
278
208
  return src;
279
209
  }
280
210
 
281
- function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\""']/g, '\\$&'); }
282
-
283
- function unescapeDelimiter(s) {
284
- let r = ''; for (let i = 0; i < s.length; i++) {
285
- if (s[i] === '\\' && i + 1 < s.length) {
286
- const n = s[i + 1];
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', evalKeyword = 'eval', blockKeyword = 'block') {
296
- this.recursion_limit = 512;
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
- this.content = input; let src = input, last = null, it = 0;
309
- const pend = () => {
310
- const r2 = new RegExp(`(?:^|\\b)${escapeRegex(this.symbols.pattern)}\\s*${escapeRegex(this.symbols.open)}`, "g");
311
- return r2.test(src);
312
- };
313
- while (src !== last && it < this.recursion_limit) {
314
- it++; last = src;
315
- const [p, s2] = collectPatterns(this, src); src = applyPatterns(this, s2, p);
316
- if (!pend()) break;
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
- return this.content = src, src;
242
+ this.content = src;
243
+ if (typeof this.exit == "function") this.exit();
244
+ return this.content;
319
245
  }
320
246
  }