papagaio 0.1.3
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 +340 -0
- package/index.html +424 -0
- package/node.js +14 -0
- package/package.json +28 -0
- package/papagaio.js +649 -0
package/README.md
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Papagaio Preprocessor
|
|
2
|
+
|
|
3
|
+
*(Version 0.1.1)*
|
|
4
|
+
|
|
5
|
+
Papagaio is a lightweight, class‑based text preprocessor designed to support pattern rewriting, macro expansion, scoped transforms, and embedded JavaScript evaluation. It is engineered to be predictable, recursion‑safe, and easily embeddable in any JavaScript runtime.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Papagaio processes an input string through a deterministic multi‑stage pipeline:
|
|
12
|
+
|
|
13
|
+
1. **Scope blocks** (recursive processing)
|
|
14
|
+
2. **Eval blocks** (JS execution)
|
|
15
|
+
3. **Macro collection**
|
|
16
|
+
4. **Pattern collection**
|
|
17
|
+
5. **Pattern application**
|
|
18
|
+
6. **Macro expansion**
|
|
19
|
+
|
|
20
|
+
The engine runs until it reaches a fixed point or hits the recursion limit.
|
|
21
|
+
|
|
22
|
+
Papagaio supports **nested delimiters**, **custom sigils**, and **configurable keywords**.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Papagaio ships as a standalone ES module or CommonJS export.
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
const { Papagaio } = require("./papagaio.js");
|
|
32
|
+
// or
|
|
33
|
+
import { Papagaio } from "./papagaio.js";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Basic Usage
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
const p = new Papagaio();
|
|
42
|
+
const output = p.process("pattern {a} {b} a a a");
|
|
43
|
+
console.log(output); // "b b b"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Core Features
|
|
49
|
+
|
|
50
|
+
### 1. Pattern Blocks
|
|
51
|
+
|
|
52
|
+
Patterns rewrite text using a match → replacement structure:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
pattern { MATCH } { REPLACEMENT }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Patterns are collected once per iteration and applied globally.
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
pattern {hello} {hi}
|
|
64
|
+
hello world
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Output:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
hi world
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### Variables
|
|
74
|
+
|
|
75
|
+
Variables use the configured **sigil** (default `$`).
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
pattern {say $x} {[$x]}
|
|
79
|
+
say hello
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
→ `[hello]`
|
|
83
|
+
|
|
84
|
+
#### Balanced Block Variables
|
|
85
|
+
|
|
86
|
+
Papagaio supports deep matching of balanced blocks:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
pattern {($x)} {[BLOCK:$x]}
|
|
90
|
+
(do something)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
→ `[BLOCK:do something]`
|
|
94
|
+
|
|
95
|
+
#### Spread Variables
|
|
96
|
+
|
|
97
|
+
Spread variables capture until a terminating token:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
pattern {from $x...to} {$x}
|
|
101
|
+
from A B C to
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
→ `A B C`
|
|
105
|
+
|
|
106
|
+
#### Metavariables
|
|
107
|
+
|
|
108
|
+
Papagaio provides special `$keywords` inside replacements:
|
|
109
|
+
|
|
110
|
+
| Variable | Meaning |
|
|
111
|
+
| --------- | ------------------------------------------ |
|
|
112
|
+
| `$match` | Full matched text |
|
|
113
|
+
| `$pre` | Text before match |
|
|
114
|
+
| `$post` | Text after match |
|
|
115
|
+
| `$unique` | Auto‑increment unique token |
|
|
116
|
+
| `$$` | Whitespace wildcard in patterns |
|
|
117
|
+
| `$clear` | Triggers clear‑rewrite of last replacement |
|
|
118
|
+
|
|
119
|
+
Example:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
pattern {x} {$pre[${unique}]$post}
|
|
123
|
+
abcxdef
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### 2. Macro Blocks
|
|
129
|
+
|
|
130
|
+
Macros behave like simple template functions.
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
macro name { BODY }
|
|
134
|
+
name(arg1, arg2)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Example:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
macro wrap {[$1][$2]}
|
|
141
|
+
wrap(a, b)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
→ `[a][b]`
|
|
145
|
+
|
|
146
|
+
#### Argument Mapping
|
|
147
|
+
|
|
148
|
+
Arguments map to `$1`, `$2`, … automatically. `$0` expands to the macro name.
|
|
149
|
+
|
|
150
|
+
Example:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
macro tag {<$0 $1>}
|
|
154
|
+
tag(title)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
→ `<tag title>`
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### 3. Eval Blocks
|
|
162
|
+
|
|
163
|
+
Executes embedded JavaScript and returns the result as a string.
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
eval { return 3 + 7 }
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
→ `10`
|
|
170
|
+
|
|
171
|
+
Eval executes inside a strict IIFE.
|
|
172
|
+
|
|
173
|
+
You may access:
|
|
174
|
+
|
|
175
|
+
* `papagaio` → the processor instance
|
|
176
|
+
* `ctx` → an empty object for temporary state
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
pattern {sum $a $b} {eval { return Number($a) + Number($b) }}
|
|
182
|
+
sum 2 8
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
→ `10`
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### 4. Scope Blocks
|
|
190
|
+
|
|
191
|
+
Scope blocks create isolated processing regions using the same pipeline.
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
scope {
|
|
195
|
+
pattern {x} {y}
|
|
196
|
+
x x x
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
→ `y y y`
|
|
201
|
+
|
|
202
|
+
Scopes do not leak macros or patterns to the outside.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Delimiters
|
|
207
|
+
|
|
208
|
+
Papagaio supports configurable opening/closing pairs.
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
p.delimiters = [["{", "}"], ["(", ")"]];
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Balanced variable matching works across all registered delimiter pairs.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Recursion Model
|
|
219
|
+
|
|
220
|
+
Papagaio runs a fixed‑point loop:
|
|
221
|
+
|
|
222
|
+
1. Process scopes
|
|
223
|
+
2. Process eval blocks
|
|
224
|
+
3. Collect macros
|
|
225
|
+
4. Collect top‑level patterns
|
|
226
|
+
5. Apply patterns
|
|
227
|
+
6. Expand macros
|
|
228
|
+
|
|
229
|
+
If any Papagaio keyword remains in the output, it repeats.
|
|
230
|
+
|
|
231
|
+
You can configure the iteration cap:
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
p.maxRecursion = 256;
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Error Handling
|
|
240
|
+
|
|
241
|
+
Eval blocks are wrapped in a try/catch. Exceptions produce empty output.
|
|
242
|
+
|
|
243
|
+
Pattern/macro recursion halts upon reaching `maxRecursion`.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Advanced Examples
|
|
248
|
+
|
|
249
|
+
### Nested Macros
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
macro A {($1)}
|
|
253
|
+
macro B {A($1)}
|
|
254
|
+
B(hello)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
→ `(hello)`
|
|
258
|
+
|
|
259
|
+
### Dynamic Rewriting with `$unique`
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
pattern {node} {id_$unique}
|
|
263
|
+
node node node
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
→ `id_0 id_1 id_2`
|
|
267
|
+
|
|
268
|
+
### Working with Pre/Post Context
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
pattern {x} {$pre|X|$post}
|
|
272
|
+
a x b
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
→ `a |X| b`
|
|
276
|
+
|
|
277
|
+
### Spread Matching
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
pattern {let $name = $v...;} {[decl $name $v]}
|
|
281
|
+
let x = 1 + 2 + 3;
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
→ `[decl x 1 + 2 + 3]`
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## API Reference
|
|
289
|
+
|
|
290
|
+
### Class: `Papagaio`
|
|
291
|
+
|
|
292
|
+
#### `process(input: string): string`
|
|
293
|
+
|
|
294
|
+
Runs the full pipeline and returns the transformed text.
|
|
295
|
+
|
|
296
|
+
#### `delimiters: Array<[string, string]>`
|
|
297
|
+
|
|
298
|
+
List of opening/closing delimiter pairs.
|
|
299
|
+
|
|
300
|
+
#### `sigil: string`
|
|
301
|
+
|
|
302
|
+
Variable prefix. Default `$`.
|
|
303
|
+
|
|
304
|
+
#### `keywords`
|
|
305
|
+
|
|
306
|
+
Keyword configuration:
|
|
307
|
+
|
|
308
|
+
* `pattern`
|
|
309
|
+
* `macro`
|
|
310
|
+
* `eval`
|
|
311
|
+
* `scope`
|
|
312
|
+
|
|
313
|
+
#### Internal State
|
|
314
|
+
|
|
315
|
+
For debugging only:
|
|
316
|
+
|
|
317
|
+
* `content` → latest processed text
|
|
318
|
+
* `#matchContent`
|
|
319
|
+
* `#scopeContent`
|
|
320
|
+
* `#evalContent`
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Embedding
|
|
325
|
+
|
|
326
|
+
Papagaio is pure JS and safe to embed in build pipelines, CLIs, game engines, or runtime scripting layers.
|
|
327
|
+
|
|
328
|
+
Example minimal CLI wrapper:
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
#!/usr/bin/env node
|
|
332
|
+
const fs = require("fs");
|
|
333
|
+
const { Papagaio } = require("./papagaio");
|
|
334
|
+
|
|
335
|
+
const input = fs.readFileSync(0, "utf8");
|
|
336
|
+
const out = new Papagaio().process(input);
|
|
337
|
+
process.stdout.write(out);
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|