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/README.md
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
# Papagaio
|
|
2
|
-
Minimal yet powerful text preprocessor
|
|
2
|
+
Minimal yet powerful text preprocessor.
|
|
3
|
+
|
|
4
|
+
- **It's portable!** papagaio requires only ES6 and nothing else.
|
|
5
|
+
- **It's small!** papagaio is around ~250 lines and ~10kb.
|
|
6
|
+
- **It's easy!** papagaio doesnt have any complicated stuff, 1 class and 1 method for doing everything!
|
|
7
|
+
- **It's flexible!** do papagaio sigil and delimiters conflict with whatever you want to process? then simply change it! papagaio allow us to modify ANY of its keywords and symbols.
|
|
8
|
+
- **It's powerful!!** aside been inspired by the m4 preprocessor and meant to be a preprocessor, papagaio still a fully-featured programming language because it can evaluate any valid javascript code using $eval;
|
|
3
9
|
|
|
4
10
|
## Installation
|
|
5
11
|
```javascript
|
|
6
12
|
import { Papagaio } from './src/papagaio.js';
|
|
7
|
-
const
|
|
8
|
-
const result =
|
|
13
|
+
const papagaio = new Papagaio();
|
|
14
|
+
const result = papagaio.process(input);
|
|
9
15
|
```
|
|
10
16
|
|
|
11
17
|
## Configuration
|
|
12
18
|
```javascript
|
|
13
|
-
|
|
19
|
+
papagaio.symbols = {
|
|
14
20
|
pattern: "pattern", // pattern keyword
|
|
15
21
|
open: "{", // opening delimiter (multi-char supported)
|
|
16
22
|
close: "}", // closing delimiter (multi-char supported)
|
|
17
|
-
sigil: "$"
|
|
23
|
+
sigil: "$", // variable marker
|
|
24
|
+
eval: "eval", // eval keyword
|
|
25
|
+
block: "block", // block keyword
|
|
26
|
+
regex: "regex" // regex keyword
|
|
18
27
|
};
|
|
19
|
-
p.recursion_limit = 512;
|
|
20
28
|
```
|
|
21
29
|
|
|
22
30
|
---
|
|
@@ -25,48 +33,95 @@ p.recursion_limit = 512;
|
|
|
25
33
|
|
|
26
34
|
### 1. Simple Variables
|
|
27
35
|
```
|
|
28
|
-
pattern {$x} {$x}
|
|
36
|
+
$pattern {$x} {$x}
|
|
29
37
|
hello
|
|
30
38
|
```
|
|
31
39
|
Output: `hello`
|
|
32
40
|
|
|
33
41
|
### 2. Multiple Variables
|
|
34
42
|
```
|
|
35
|
-
pattern {$x $y $z} {$z, $y, $x}
|
|
43
|
+
$pattern {$x $y $z} {$z, $y, $x}
|
|
36
44
|
apple banana cherry
|
|
37
45
|
```
|
|
38
46
|
Output: `cherry, banana, apple`
|
|
39
47
|
|
|
40
48
|
---
|
|
41
49
|
|
|
42
|
-
##
|
|
50
|
+
## Variables
|
|
43
51
|
|
|
44
|
-
Papagaio provides flexible
|
|
52
|
+
Papagaio provides flexible variable capture with automatic context-aware behavior.
|
|
53
|
+
|
|
54
|
+
### `$x` - Smart Variable
|
|
55
|
+
Automatically adapts based on context:
|
|
56
|
+
- **Before a block**: Captures everything until the block's opening delimiter
|
|
57
|
+
- **Before a literal**: Captures everything until that literal appears
|
|
58
|
+
- **Otherwise**: Captures a single word (non-whitespace token)
|
|
45
59
|
|
|
46
|
-
### `$x` - Single Word Variable
|
|
47
|
-
Captures a single non-whitespace token.
|
|
48
60
|
```
|
|
49
|
-
pattern {$x} {[$x]}
|
|
61
|
+
$pattern {$x} {[$x]}
|
|
50
62
|
hello world
|
|
51
63
|
```
|
|
52
|
-
Output: `[hello]`
|
|
64
|
+
Output: `[hello] [world]`
|
|
53
65
|
|
|
54
|
-
### `$$x` - Whitespace-Sensitive Variable
|
|
55
|
-
Captures text including surrounding whitespace until the next significant token.
|
|
56
66
|
```
|
|
57
|
-
pattern {
|
|
58
|
-
hello
|
|
67
|
+
$pattern {$name $block content {(}{)}} {$name: $content}
|
|
68
|
+
greeting (hello world)
|
|
59
69
|
```
|
|
60
|
-
Output: `
|
|
70
|
+
Output: `greeting: hello world`
|
|
61
71
|
|
|
62
|
-
### `$$$x` - Optional Whitespace Variable
|
|
63
|
-
Captures with optional whitespace (no error if empty).
|
|
64
72
|
```
|
|
65
|
-
pattern {
|
|
73
|
+
$pattern {$prefix:$suffix} {$suffix-$prefix}
|
|
74
|
+
key:value
|
|
75
|
+
```
|
|
76
|
+
Output: `value-key`
|
|
77
|
+
|
|
78
|
+
### `$x?` - Optional Variable
|
|
79
|
+
Same behavior as `$x`, but won't fail if empty or not found.
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
$pattern {$x? world} {<$x>}
|
|
66
83
|
world
|
|
67
84
|
```
|
|
68
85
|
Output: `<>`
|
|
69
86
|
|
|
87
|
+
```
|
|
88
|
+
$pattern {$greeting? $name} {Hello $name$greeting}
|
|
89
|
+
Hi John
|
|
90
|
+
```
|
|
91
|
+
Output: `Hello JohnHi`
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Regex Matching
|
|
96
|
+
|
|
97
|
+
Capture content using JavaScript regular expressions.
|
|
98
|
+
|
|
99
|
+
### Syntax
|
|
100
|
+
```
|
|
101
|
+
$regex varName {pattern}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Basic Example
|
|
105
|
+
```
|
|
106
|
+
$pattern {$regex num {[0-9]+}} {Number: $num}
|
|
107
|
+
The answer is 42
|
|
108
|
+
```
|
|
109
|
+
Output: `Number: 42`
|
|
110
|
+
|
|
111
|
+
### Complex Patterns
|
|
112
|
+
```
|
|
113
|
+
$pattern {$regex email {\w+@\w+\.\w+}} {Email found: $email}
|
|
114
|
+
Contact: user@example.com
|
|
115
|
+
```
|
|
116
|
+
Output: `Email found: user@example.com`
|
|
117
|
+
|
|
118
|
+
### Multiple Regex Variables
|
|
119
|
+
```
|
|
120
|
+
$pattern {$regex year {[0-9]{4}}-$regex month {[0-9]{2}}} {Month $month in $year}
|
|
121
|
+
2024-03
|
|
122
|
+
```
|
|
123
|
+
Output: `Month 03 in 2024`
|
|
124
|
+
|
|
70
125
|
---
|
|
71
126
|
|
|
72
127
|
## Blocks
|
|
@@ -80,21 +135,21 @@ $block varName {open}{close}
|
|
|
80
135
|
|
|
81
136
|
### Basic Example
|
|
82
137
|
```
|
|
83
|
-
pattern {$name $block content {(}{)}} {[$content]}
|
|
138
|
+
$pattern {$name $block content {(}{)}} {[$content]}
|
|
84
139
|
data (hello world)
|
|
85
140
|
```
|
|
86
141
|
Output: `[hello world]`
|
|
87
142
|
|
|
88
143
|
### Custom Delimiters
|
|
89
144
|
```
|
|
90
|
-
pattern {$block data {<<}{>>}} {DATA: $data}
|
|
145
|
+
$pattern {$block data {<<}{>>}} {DATA: $data}
|
|
91
146
|
<<json stuff>>
|
|
92
147
|
```
|
|
93
148
|
Output: `DATA: json stuff`
|
|
94
149
|
|
|
95
150
|
### Multi-Character Delimiters
|
|
96
151
|
```
|
|
97
|
-
pattern {$block code {```}{```}} {<pre>$code</pre>}
|
|
152
|
+
$pattern {$block code {```}{```}} {<pre>$code</pre>}
|
|
98
153
|
```markdown
|
|
99
154
|
# Title
|
|
100
155
|
```
|
|
@@ -102,138 +157,255 @@ Output: `<pre># Title</pre>`
|
|
|
102
157
|
|
|
103
158
|
### Multiple Blocks
|
|
104
159
|
```
|
|
105
|
-
pattern {$block a {(}{)}, $block b {[}{]}} {$a|$b}
|
|
160
|
+
$pattern {$block a {(}{)}, $block b {[}{]}} {$a|$b}
|
|
106
161
|
(first), [second]
|
|
107
162
|
```
|
|
108
163
|
Output: `first|second`
|
|
109
164
|
|
|
110
165
|
### Nested Blocks
|
|
111
166
|
```
|
|
112
|
-
pattern {$block outer {(}{)}} {[$outer]}
|
|
167
|
+
$pattern {$block outer {(}{)}} {[$outer]}
|
|
113
168
|
(outer (inner))
|
|
114
169
|
```
|
|
115
170
|
Output: `[outer (inner)]`
|
|
116
171
|
|
|
117
172
|
---
|
|
118
173
|
|
|
119
|
-
##
|
|
174
|
+
## Pattern Scopes
|
|
175
|
+
|
|
176
|
+
Patterns defined within a replacement body create nested scopes with hierarchical inheritance.
|
|
120
177
|
|
|
121
178
|
### Basic Pattern
|
|
122
179
|
```
|
|
123
|
-
pattern {
|
|
180
|
+
$pattern {hello} {world}
|
|
181
|
+
hello
|
|
124
182
|
```
|
|
183
|
+
Output: `world`
|
|
125
184
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
Output: `<h1>Welcome</h1>`
|
|
185
|
+
**Key Properties:**
|
|
186
|
+
* Patterns are scoped to their context
|
|
187
|
+
* Child patterns inherit parent patterns
|
|
188
|
+
* Patterns do not persist between `process()` calls
|
|
189
|
+
* Perfect for hierarchical transformations
|
|
132
190
|
|
|
133
|
-
###
|
|
191
|
+
### Nested Patterns with Inheritance
|
|
134
192
|
```
|
|
135
|
-
pattern {
|
|
136
|
-
pattern {
|
|
137
|
-
|
|
138
|
-
|
|
193
|
+
$pattern {outer $x} {
|
|
194
|
+
$pattern {inner $y} {[$y from $x]}
|
|
195
|
+
inner $x
|
|
196
|
+
}
|
|
197
|
+
outer hello
|
|
139
198
|
```
|
|
140
|
-
Output: `
|
|
141
|
-
|
|
142
|
-
---
|
|
199
|
+
Output: `[hello from hello]`
|
|
143
200
|
|
|
144
|
-
|
|
201
|
+
The inner pattern has access to `$x` from the outer pattern's capture.
|
|
145
202
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
### Syntax
|
|
203
|
+
### Deep Nesting
|
|
149
204
|
```
|
|
150
|
-
$pattern {
|
|
205
|
+
$pattern {level1 $a} {
|
|
206
|
+
$pattern {level2 $b} {
|
|
207
|
+
$pattern {level3 $c} {$a > $b > $c}
|
|
208
|
+
level3 $b
|
|
209
|
+
}
|
|
210
|
+
level2 $a
|
|
211
|
+
}
|
|
212
|
+
level1 ROOT
|
|
151
213
|
```
|
|
214
|
+
Output: `ROOT > ROOT > ROOT`
|
|
215
|
+
|
|
216
|
+
Each nested level inherits all patterns from parent scopes.
|
|
152
217
|
|
|
153
|
-
###
|
|
218
|
+
### Sibling Scopes Don't Share
|
|
154
219
|
```
|
|
155
|
-
pattern {
|
|
156
|
-
$
|
|
157
|
-
|
|
158
|
-
$code;
|
|
159
|
-
return "";
|
|
160
|
-
}
|
|
220
|
+
$pattern {branch1} {
|
|
221
|
+
$pattern {x} {A}
|
|
222
|
+
x
|
|
161
223
|
}
|
|
162
|
-
|
|
224
|
+
$pattern {branch2} {
|
|
225
|
+
x
|
|
226
|
+
}
|
|
227
|
+
branch1
|
|
228
|
+
branch2
|
|
163
229
|
```
|
|
164
230
|
Output:
|
|
165
231
|
```
|
|
166
|
-
|
|
232
|
+
A
|
|
233
|
+
x
|
|
167
234
|
```
|
|
168
235
|
|
|
169
|
-
|
|
170
|
-
* Subpatterns exist only within the running pattern.
|
|
171
|
-
* They do not leak into the global pattern list.
|
|
172
|
-
* They can recursively modify inner content before `$eval` or other processors.
|
|
173
|
-
* Multiple subpatterns can coexist in the same replacement.
|
|
236
|
+
Patterns in `branch1` are not available in `branch2` (they are siblings, not parent-child).
|
|
174
237
|
|
|
175
238
|
---
|
|
176
239
|
|
|
177
240
|
## Special Keywords
|
|
178
241
|
|
|
179
242
|
### $eval
|
|
180
|
-
Executes JavaScript code.
|
|
243
|
+
Executes JavaScript code with access to the Papagaio instance.
|
|
244
|
+
|
|
181
245
|
```
|
|
182
|
-
pattern {$x} {$eval{return parseInt($x)*2;}}
|
|
246
|
+
$pattern {$x} {$eval{return parseInt($x)*2;}}
|
|
183
247
|
5
|
|
184
248
|
```
|
|
185
249
|
Output: `10`
|
|
186
250
|
|
|
187
|
-
|
|
251
|
+
**Accessing Papagaio Instance:**
|
|
252
|
+
```
|
|
253
|
+
$pattern {info} {$eval{
|
|
254
|
+
return `Content length: ${papagaio.content.length}`;
|
|
255
|
+
}}
|
|
256
|
+
info
|
|
188
257
|
```
|
|
189
|
-
|
|
258
|
+
|
|
259
|
+
**Multi-character delimiters:**
|
|
260
|
+
```
|
|
261
|
+
$pattern {$x} {$eval<<parseInt($x)*2>>}
|
|
190
262
|
5
|
|
191
263
|
```
|
|
192
264
|
Output: `10`
|
|
193
265
|
|
|
266
|
+
---
|
|
194
267
|
|
|
195
268
|
## Important Rules
|
|
196
269
|
|
|
197
|
-
### Matching
|
|
198
|
-
* `$x` =
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
270
|
+
### Variable Matching
|
|
271
|
+
* `$x` = smart capture (context-aware: word, until literal, or until block)
|
|
272
|
+
* `$x?` = optional version of `$x` (won't fail if empty)
|
|
273
|
+
* `$regex name {pattern}` = regex-based capture
|
|
274
|
+
* Variables automatically skip leading whitespace
|
|
275
|
+
* Trailing whitespace is trimmed when variables appear before literals
|
|
276
|
+
|
|
277
|
+
### Pattern Matching
|
|
278
|
+
* `$pattern {match} {replace}` = pattern scoped to current context
|
|
279
|
+
* Patterns inherit from parent scopes hierarchically
|
|
280
|
+
* Each `process()` call starts with a clean slate (no persistence)
|
|
203
281
|
|
|
204
282
|
### Block Matching
|
|
205
283
|
* `$block name {open}{close}` captures delimited regions
|
|
206
284
|
* Supports nested delimiters of any length
|
|
207
285
|
* Multi-character delimiters fully supported (e.g., `{>>>}{<<<}`)
|
|
208
|
-
|
|
209
|
-
### Whitespace Handling
|
|
210
|
-
* Whitespace-optional tokens (`$$` alone) skip optional whitespace
|
|
211
|
-
* Variables automatically skip leading whitespace when needed
|
|
212
|
-
* Trailing whitespace is trimmed when variables appear before literals
|
|
286
|
+
* Blocks support arbitrary nesting depth
|
|
213
287
|
|
|
214
288
|
---
|
|
215
289
|
|
|
216
290
|
## Multi-Character Delimiter Support
|
|
217
291
|
|
|
218
|
-
|
|
292
|
+
Papagaio fully supports multi-character delimiters throughout all features.
|
|
219
293
|
|
|
220
|
-
###
|
|
294
|
+
### Configuration
|
|
221
295
|
```javascript
|
|
222
296
|
const p = new Papagaio('$', '<<<', '>>>');
|
|
223
297
|
```
|
|
224
298
|
|
|
299
|
+
### In Patterns
|
|
300
|
+
```
|
|
301
|
+
$pattern<<<$x>>> <<<[$x]>>>
|
|
302
|
+
hello
|
|
303
|
+
```
|
|
304
|
+
Output: `[hello]`
|
|
305
|
+
|
|
225
306
|
### In Blocks
|
|
226
307
|
```
|
|
227
|
-
pattern
|
|
308
|
+
$pattern<<<$block data {<<}{>>}>>> <<<$data>>>
|
|
228
309
|
<<content>>
|
|
229
310
|
```
|
|
311
|
+
Output: `content`
|
|
230
312
|
|
|
231
313
|
### In Eval
|
|
232
314
|
```
|
|
233
|
-
|
|
234
|
-
pattern <<<$x>>> <<<$eval<<<return $x + 1>>>>>>
|
|
315
|
+
$pattern<<<$x>>> <<<$eval<<<return $x + 1>>>>>>
|
|
235
316
|
5
|
|
236
317
|
```
|
|
318
|
+
Output: `6`
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Advanced Examples
|
|
323
|
+
|
|
324
|
+
### Markdown-like Processor
|
|
325
|
+
```javascript
|
|
326
|
+
const p = new Papagaio();
|
|
327
|
+
const template = `
|
|
328
|
+
$pattern {# $title} {<h1>$title</h1>}
|
|
329
|
+
$pattern {## $title} {<h2>$title</h2>}
|
|
330
|
+
$pattern {**$text**} {<strong>$text</strong>}
|
|
331
|
+
|
|
332
|
+
# Hello World
|
|
333
|
+
## Subtitle
|
|
334
|
+
**bold text**
|
|
335
|
+
`;
|
|
336
|
+
|
|
337
|
+
p.process(template);
|
|
338
|
+
// Output:
|
|
339
|
+
// <h1>Hello World</h1>
|
|
340
|
+
// <h2>Subtitle</h2>
|
|
341
|
+
// <strong>bold text</strong>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Template System with State
|
|
345
|
+
```javascript
|
|
346
|
+
const p = new Papagaio();
|
|
347
|
+
p.vars = {}; // Custom property for storing variables
|
|
348
|
+
|
|
349
|
+
const template = `
|
|
350
|
+
$pattern {var $name = $value} {$eval{
|
|
351
|
+
papagaio.vars['$name'] = '$value';
|
|
352
|
+
return '';
|
|
353
|
+
}}
|
|
354
|
+
$pattern {get $name} {$eval{
|
|
355
|
+
return papagaio.vars['$name'] || 'undefined';
|
|
356
|
+
}}
|
|
357
|
+
|
|
358
|
+
var title = My Page
|
|
359
|
+
var author = John Doe
|
|
360
|
+
Title: get title
|
|
361
|
+
Author: get author
|
|
362
|
+
`;
|
|
363
|
+
|
|
364
|
+
p.process(template);
|
|
365
|
+
// Output:
|
|
366
|
+
// Title: My Page
|
|
367
|
+
// Author: John Doe
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Conditional Processing
|
|
371
|
+
```javascript
|
|
372
|
+
const p = new Papagaio();
|
|
373
|
+
const template = `
|
|
374
|
+
$pattern {if $block cond {(}{)} then $block yes {[}{]} else $block no {<}{>}} {
|
|
375
|
+
$eval{
|
|
376
|
+
const condition = ($cond).trim();
|
|
377
|
+
return condition === 'true' ? '$yes' : '$no';
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (true) then [yes branch] else <no branch>
|
|
382
|
+
if (false) then [yes branch] else <no branch>
|
|
383
|
+
`;
|
|
384
|
+
|
|
385
|
+
p.process(template);
|
|
386
|
+
// Output:
|
|
387
|
+
// yes branch
|
|
388
|
+
// no branch
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Function-like Patterns
|
|
392
|
+
```javascript
|
|
393
|
+
const p = new Papagaio();
|
|
394
|
+
const template = `
|
|
395
|
+
$pattern {double $x} {$eval{return parseInt('$x') * 2}}
|
|
396
|
+
$pattern {add $x $y} {$eval{return parseInt('$x') + parseInt('$y')}}
|
|
397
|
+
|
|
398
|
+
double 5
|
|
399
|
+
add 3 7
|
|
400
|
+
add (double 4) 10
|
|
401
|
+
`;
|
|
402
|
+
|
|
403
|
+
p.process(template);
|
|
404
|
+
// Output:
|
|
405
|
+
// 10
|
|
406
|
+
// 10
|
|
407
|
+
// 18
|
|
408
|
+
```
|
|
237
409
|
|
|
238
410
|
---
|
|
239
411
|
|
|
@@ -241,31 +413,73 @@ pattern <<<$x>>> <<<$eval<<<return $x + 1>>>>>>
|
|
|
241
413
|
|
|
242
414
|
| Problem | Solution |
|
|
243
415
|
|---------|----------|
|
|
244
|
-
| Variable not captured | Check
|
|
416
|
+
| Variable not captured | Check context: use `$x?` for optional, or verify literals/blocks exist |
|
|
245
417
|
| Block mismatch | Verify opening and closing delimiters match the declaration |
|
|
246
|
-
| Infinite recursion |
|
|
247
|
-
| Pattern not matching |
|
|
418
|
+
| Infinite recursion | Pattern creates circular transformation; redesign pattern logic |
|
|
419
|
+
| Pattern not matching | Verify whitespace between tokens, check if variable should be optional |
|
|
420
|
+
| Pattern not available | Check scope hierarchy; patterns only inherit from parents, not siblings |
|
|
248
421
|
| Nested blocks fail | Ensure delimiters are properly balanced |
|
|
249
422
|
| Multi-char delimiters broken | Check delimiters don't conflict; use escaping if needed |
|
|
423
|
+
| Regex not matching | Test regex pattern separately; ensure it matches at the exact position |
|
|
250
424
|
|
|
251
425
|
---
|
|
252
426
|
|
|
253
427
|
## Syntax Reference
|
|
254
428
|
|
|
255
429
|
```
|
|
256
|
-
pattern {$x $y} {$y, $x}
|
|
257
|
-
pattern {
|
|
258
|
-
pattern {
|
|
259
|
-
pattern {$block n {o}{c}} {$n}
|
|
260
|
-
$
|
|
261
|
-
|
|
430
|
+
$pattern {$x $y} {$y, $x} # pattern with variables
|
|
431
|
+
$pattern {$x? $y} {$y, $x} # optional variable
|
|
432
|
+
$pattern {$regex n {[0-9]+}} {$n} # regex capture
|
|
433
|
+
$pattern {$block n {o}{c}} {$n} # block capture with custom delimiters
|
|
434
|
+
$eval{code} # JavaScript evaluation
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## API Reference
|
|
440
|
+
|
|
441
|
+
### Constructor
|
|
442
|
+
```javascript
|
|
443
|
+
new Papagaio(sigil, open, close, pattern, evalKw, blockKw, regexKw)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**Parameters:**
|
|
447
|
+
- `sigil` (default: `'$'`) - Variable prefix
|
|
448
|
+
- `open` (default: `'{'`) - Opening delimiter
|
|
449
|
+
- `close` (default: `'}'`) - Closing delimiter
|
|
450
|
+
- `pattern` (default: `'pattern'`) - Pattern keyword
|
|
451
|
+
- `evalKw` (default: `'eval'`) - Eval keyword
|
|
452
|
+
- `blockKw` (default: `'block'`) - Block keyword
|
|
453
|
+
- `regexKw` (default: `'regex'`) - Regex keyword
|
|
454
|
+
|
|
455
|
+
### Properties
|
|
456
|
+
- `papagaio.content` - Last processed output
|
|
457
|
+
- `papagaio.match` - Last matched substring (available in replacements)
|
|
458
|
+
- `papagaio.symbols` - Configuration object
|
|
459
|
+
- `papagaio.exit` - Optional hook function called after processing
|
|
460
|
+
|
|
461
|
+
### Methods
|
|
462
|
+
- `papagaio.process(input)` - Process input text and return transformed output
|
|
463
|
+
|
|
464
|
+
### Exit Hook
|
|
465
|
+
```javascript
|
|
466
|
+
const p = new Papagaio();
|
|
467
|
+
p.exit = function() {
|
|
468
|
+
console.log('Processing complete:', this.content);
|
|
469
|
+
};
|
|
470
|
+
p.process('$pattern {x} {y}\nx');
|
|
262
471
|
```
|
|
263
472
|
|
|
264
473
|
---
|
|
265
474
|
|
|
266
475
|
## Performance Notes
|
|
267
476
|
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
* Nested blocks and
|
|
271
|
-
* Large recursion limits can impact performance on complex inputs
|
|
477
|
+
* Multi-character delimiter matching is optimized with substring operations
|
|
478
|
+
* Nested patterns inherit parent patterns through recursive application
|
|
479
|
+
* Nested blocks and patterns have no theoretical depth limit
|
|
480
|
+
* Large recursion limits can impact performance on complex inputs
|
|
481
|
+
* Each `process()` call is independent with no persistent state between calls
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
***PAPAGAIO IS CURRENTLY IN HEAVY DEVELOPMENT AND EXPERIMENTATION PHASE***
|
package/bin/cli.qjs
CHANGED
|
@@ -7,7 +7,7 @@ import * as os from "os";
|
|
|
7
7
|
import { Papagaio } from "../src/papagaio.js";
|
|
8
8
|
|
|
9
9
|
// Version (você pode hardcoded ou ler de um arquivo JSON se necessário)
|
|
10
|
-
const VERSION = "
|
|
10
|
+
const VERSION = "0.6.0";
|
|
11
11
|
|
|
12
12
|
// Parse command line arguments
|
|
13
13
|
const args = scriptArgs.slice(1); // QuickJS usa scriptArgs ao invés de process.argv
|
package/examples/simple.html
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>papagaio test</title>
|
|
7
7
|
</head>
|
|
8
|
-
<script src="src/papagaio-bootstrap.mjs" type="module"></script>
|
|
8
|
+
<script src="../src/papagaio-bootstrap.mjs" type="module"></script>
|
|
9
9
|
<script type="papagaio">
|
|
10
|
-
pattern {abc} {$eval{console.log(papagaio)}}
|
|
10
|
+
$pattern {abc} {$eval{console.log(papagaio)} aaaaaaaaaaaaaaaaaaaaaaaaaaaa}
|
|
11
11
|
abc
|
|
12
12
|
</script>
|
|
13
13
|
<body>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// generic ts-like to wasm compiler
|
|
2
|
+
|
|
3
|
+
// util patterns
|
|
4
|
+
$pattern {// $comment $regex newline{[^\n]*}} {}
|
|
5
|
+
$pattern {$regex spaces{\s\s}}{ }
|
|
6
|
+
|
|
7
|
+
$eval{
|
|
8
|
+
papagaio.exit = function()
|
|
9
|
+
{
|
|
10
|
+
papagaio.content = "(module\n" + papagaio.content + "\n)";
|
|
11
|
+
papagaio.exit = null;
|
|
12
|
+
};
|
|
13
|
+
return ""
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
$pattern {export function $name $block params{(}{)}:$rets $block content{}{}} {
|
|
17
|
+
$pattern {parametrize}
|
|
18
|
+
{
|
|
19
|
+
$eval {
|
|
20
|
+
let str = "$params".replace("(", "").replace(")", "");
|
|
21
|
+
let params = str.split(",").map(p => p.trim()).filter(p => p);
|
|
22
|
+
let new_stuff = "";
|
|
23
|
+
for (const param of params) {
|
|
24
|
+
if (!param.includes(":")) continue; // Pula se não tem ':'
|
|
25
|
+
const [name, type] = param.split(":");
|
|
26
|
+
if (name && type) { // Verifica se ambos existem
|
|
27
|
+
new_stuff += ` (param $${name.trim()} ${type.trim()}) `;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return new_stuff;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
(func (export "$name") parametrize (result $rets)
|
|
35
|
+
$content
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
$pattern {function $name $block params{(}{)}:$rets $block content{}{}} {
|
|
40
|
+
$pattern {parametrize}
|
|
41
|
+
{
|
|
42
|
+
$eval {
|
|
43
|
+
let str = "$params".replace("(", "").replace(")", "");
|
|
44
|
+
let params = str.split(",").map(p => p.trim()).filter(p => p);
|
|
45
|
+
let new_stuff = "";
|
|
46
|
+
for (const param of params) {
|
|
47
|
+
if (!param.includes(":")) continue; // Pula se não tem ':'
|
|
48
|
+
const [name, type] = param.split(":");
|
|
49
|
+
if (name && type) { // Verifica se ambos existem
|
|
50
|
+
new_stuff += ` (param $${name.trim()} ${type.trim()}) `;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return new_stuff;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
(func $$name parametrize (result $rets)
|
|
58
|
+
$content
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function name(a:i32, b:i32):i64 i64
|
|
63
|
+
{
|
|
64
|
+
contentnans
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function funcao_exportada(a:f32, b:f32, c:f32):i64 i64 i64 i64
|
|
68
|
+
{
|
|
69
|
+
fução expoortada1
|
|
70
|
+
}
|