strykelang 0.8.0

A highly parallel Perl 5 interpreter written in Rust
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="color-scheme" content="dark light">
  <meta name="description" content="stryke — a highly parallel Perl 5 interpreter in Rust. Rayon-powered builtins, bytecode VM + JIT, pipe-forward syntax, and reflection hashes for every builtin / alias / extension.">
  <title>stryke — Documentation</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&amp;family=Share+Tech+Mono&amp;display=swap" rel="stylesheet">
  <link rel="stylesheet" href="hud-static.css">
  <link rel="stylesheet" href="tutorial.css">
  <style>
    .tutorial-main { max-width: 68rem; }
    .docs-build-line {
      margin: 0.35rem 0 0;
      font-family: 'Share Tech Mono', ui-monospace, monospace;
      font-size: 11px;
      color: var(--text-dim);
      letter-spacing: 0.03em;
      max-width: 42rem;
      opacity: 0.75;
    }
    .hub-scheme-strip {
      border-bottom: 1px dashed var(--border);
      background: color-mix(in srgb, var(--bg-secondary) 85%, transparent);
      padding: 0.55rem 1.5rem 0.65rem;
      position: relative;
    }
    .hub-scheme-strip-inner {
      max-width: 68rem;
      margin: 0 auto;
      display: flex;
      align-items: center;
      gap: 0.85rem;
    }
    .hub-scheme-strip .hud-scheme-label {
      flex: 0 0 auto;
      font-family: 'Orbitron', sans-serif;
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: var(--accent);
      text-align: left;
    }
    .hub-scheme-strip .scheme-grid {
      flex: 1 1 auto;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      gap: 6px;
    }
    @media (max-width: 720px) {
      .hub-scheme-strip-inner { flex-direction: column; align-items: stretch; }
      .hub-scheme-strip .scheme-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }

    /* Reflection / builtin tables */
    .reflection-table {
      width: 100%;
      border-collapse: collapse;
      margin: 0.6rem 0 0.2rem;
      font-size: 12px;
    }
    .reflection-table th {
      background: var(--bg-secondary);
      color: var(--cyan);
      font-family: 'Orbitron', sans-serif;
      font-size: 10px;
      font-weight: 700;
      letter-spacing: 1px;
      text-transform: uppercase;
      text-align: left;
      padding: 6px 10px;
      border: 1px solid var(--border);
    }
    .reflection-table td {
      padding: 6px 10px;
      border: 1px solid var(--border);
      color: var(--text-dim);
      vertical-align: top;
    }
    .reflection-table td code { color: var(--accent-light); background: var(--bg); }

    /* One-liner example blocks — pre with a "copy" affordance via user select */
    .oneliner {
      margin: 0.4rem 0;
      padding: 0.55rem 0.8rem;
      border-left: 2px solid var(--cyan);
      background: var(--bg);
      font-family: 'Share Tech Mono', ui-monospace, monospace;
      font-size: 12px;
      color: var(--text);
      white-space: pre-wrap;
      word-break: break-word;
    }
    .oneliner .comment { color: var(--text-muted); }

    /* Index-card grid for builtin categories */
    .cat-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
      gap: 0.6rem;
      margin: 0.7rem 0;
    }
    .cat-card {
      border: 1px solid var(--border);
      border-left: 2px solid var(--cyan);
      padding: 0.6rem 0.8rem;
      background: color-mix(in srgb, var(--bg-card) 92%, transparent);
      border-radius: 2px;
    }
    .cat-card h4 {
      font-family: 'Orbitron', sans-serif;
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 1.5px;
      text-transform: uppercase;
      color: var(--cyan);
      margin: 0 0 0.35rem;
    }
    .cat-card p {
      margin: 0;
      font-size: 11.5px;
      color: var(--text-dim);
      line-height: 1.5;
    }
    .cat-card code { font-size: 11px; color: var(--accent-light); }
  </style>
</head>
<body>
  <div class="app tutorial-app" id="docsApp">
    <div class="crt-scanline" id="crtH" aria-hidden="true"></div>
    <div class="crt-scanline-v" id="crtV" aria-hidden="true"></div>

    <header class="tutorial-header">
      <div class="tutorial-header-inner">
        <div>
          <h1 class="tutorial-brand">// STRYKE — PARALLEL PERL5 INTERPRETER</h1>
          <nav class="tutorial-crumbs" aria-label="Breadcrumb">
            <span class="current">Docs</span>
            <span class="sep">/</span>
            <a href="reference.html">Full reference</a>
            <span class="sep">/</span>
            <a href="https://github.com/MenkeTechnologies/strykelang" target="_blank" rel="noopener noreferrer">GitHub</a>
            <span class="sep">/</span>
            <a href="https://crates.io/crates/strykelang" target="_blank" rel="noopener noreferrer">crates.io</a>
            <span class="sep">/</span>
            <a href="https://docs.rs/strykelang" target="_blank" rel="noopener noreferrer">docs.rs</a>
          </nav>
          <p class="docs-build-line" id="strykeBuildLine">stryke v0.8.0 · Rust-powered · Rayon work-stealing · Cranelift JIT · Perl 5 compat surface + pipe-forward sugar</p>
        </div>
        <div class="tutorial-toolbar">
          <button type="button" class="btn btn-secondary" id="btnTheme" title="Toggle light/dark">Theme</button>
          <button type="button" class="btn btn-secondary active" id="btnCrt" title="CRT scanline overlay">CRT</button>
          <button type="button" class="btn btn-secondary active" id="btnNeon" title="Neon border pulse">Neon</button>
          <a class="btn btn-secondary" href="reference.html">Reference</a>
          <a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/strykelang" target="_blank" rel="noopener noreferrer">GitHub</a>
          <a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/strykelang/issues" target="_blank" rel="noopener noreferrer">Issues</a>
        </div>
      </div>
    </header>

    <div class="hub-scheme-strip">
      <div class="hub-scheme-strip-inner">
        <span class="hud-scheme-label">// Color scheme</span>
        <div class="scheme-grid" id="hudSchemeGrid"></div>
      </div>
    </div>

    <main class="tutorial-main">
      <h2 class="tutorial-title"><span class="step-hash">&gt;_</span>STRYKE REFERENCE</h2>
      <p class="tutorial-subtitle">A Perl 5 interpreter written in Rust, optimized for parallelism. NaN-boxed <code>PerlValue</code>, rayon work-stealing across every CPU, bytecode VM with Cranelift JIT, and a pipe-forward (<code>|&gt;</code>) syntax that threads values through chained stages without refs or intermediate vars. This hub links to the authoritative docs in <code>README.md</code> and <code>rustdoc</code>; the sections below give a fast tour of the surface.</p>

      <section class="tutorial-section">
        <h2>Quickstart</h2>
        <p>Install from crates.io or source, then run scripts or one-liners with <code>s</code> (short for stryke):</p>
<pre># install
cargo install strykelang

# from source
git clone https://github.com/MenkeTechnologies/strykelang
cd strykelang &amp;&amp; cargo build --release

# one-liners
s 'p "hello, world"'
s '1..20 |&gt; grep { $_ % 2 == 0 } |&gt; map { $_ * $_ } |&gt; sum |&gt; p'
s 'qw(a b c) |&gt; map uc |&gt; join "," |&gt; p'

# parallel primitives
s '(1..8) |&gt; pmap { expensive($_) } |&gt; p'

# read + parse JSON
s 'read_json("data.json") |&gt; to_yaml |&gt; p'</pre>
        <p>Full install + usage live in the <a href="https://github.com/MenkeTechnologies/strykelang#readme">README</a>.</p>
        <p><strong><code>-e</code> is optional.</strong> If the first argument isn't a file and looks like code, <code>s</code> runs it directly. <code>s 'p 42'</code> and <code>s -e 'p 42'</code> are equivalent.</p>
      </section>

      <section class="tutorial-section">
        <h2>Why stryke — One-Liner Comparison</h2>
        <table class="comparison-table" style="width:100%; border-collapse:collapse; font-size:0.85em;">
          <thead>
            <tr style="border-bottom:2px solid #0ff;">
              <th style="text-align:left; padding:4px;">Feature</th>
              <th style="padding:4px;">stryke</th>
              <th style="padding:4px;">perl5</th>
              <th style="padding:4px;">ruby</th>
              <th style="padding:4px;">python</th>
              <th style="padding:4px;">awk</th>
              <th style="padding:4px;">jq</th>
            </tr>
          </thead>
          <tbody>
            <tr><td>No <code>-e</code> flag needed</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>—</td><td>—</td></tr>
            <tr><td>No semicolons</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10003;</td><td>&#10003;</td><td>&#10003;</td><td>&#10003;</td></tr>
            <tr><td>Built-in HTTP</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Built-in JSON</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10003;</td><td>&#10007;</td><td>&#10003;</td></tr>
            <tr><td>Built-in CSV</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10003;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Built-in SQLite</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10003;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Parallel map/grep</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Pipe-forward <code>|&gt;</code></td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td><code>|</code></td></tr>
            <tr><td>Thread macro</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>In-place edit <code>-i</code></td><td style="color:#0f0;">parallel</td><td>sequential</td><td>sequential</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Data viz (spark/bars/flame)</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Clipboard</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>JIT compiler</td><td style="color:#0f0;">Cranelift</td><td>&#10007;</td><td>YJIT</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Single binary</td><td style="color:#0f0;">26MB</td><td>pkg</td><td>pkg</td><td>pkg</td><td>pkg</td><td>3MB</td></tr>
          </tbody>
        </table>
        <h3 style="margin-top:1em;">Character count — real tasks</h3>
        <table style="width:100%; border-collapse:collapse; font-size:0.85em;">
          <thead>
            <tr style="border-bottom:2px solid #0ff;">
              <th style="text-align:left; padding:4px;">Task</th>
              <th style="padding:4px;">s</th>
              <th style="padding:4px;">perl5</th>
              <th style="padding:4px;">ruby</th>
              <th style="padding:4px;">python</th>
            </tr>
          </thead>
          <tbody>
            <tr><td>Sum 1..100</td><td style="color:#0f0;"><code>s 'p sum 1..100'</code> <b>19c</b></td><td>45c</td><td>28c</td><td>38c</td></tr>
            <tr><td>Word freq</td><td style="color:#0f0;"><code>s -an 'freq(@F) |&gt; dd'</code> <b>25c</b></td><td>61c</td><td>—</td><td>—</td></tr>
            <tr><td>SHA256 file</td><td style="color:#0f0;"><code>s 'p s256"f"'</code> <b>14c</b></td><td>70c+</td><td>—</td><td>80c+</td></tr>
            <tr><td>CSV → JSON</td><td style="color:#0f0;"><code>s 'csv_read("f") |&gt; tj |&gt; p'</code> <b>33c</b></td><td>needs modules</td><td>needs modules</td><td>90c</td></tr>
            <tr><td>Parallel map</td><td style="color:#0f0;"><code>s '1..1e6 |&gt; pmap { $_ * 2 }'</code> <b>33c</b></td><td>—</td><td>—</td><td>—</td></tr>
          </tbody>
        </table>
      </section>

      <section class="tutorial-section">
        <h2>Overview</h2>
        <ul>
          <li><strong>Parser &amp; compiler</strong> — recursive-descent parser in <code>src/parser.rs</code>, producing an AST consumed by both a tree-walking <code>Interpreter</code> and a bytecode <code>Compiler</code> (<code>src/compiler.rs</code>) that feeds the VM (<code>src/vm.rs</code>). Cranelift JIT kicks in for hot blocks and linear subs (<code>src/jit.rs</code>).</li>
          <li><strong>Values</strong> — <code>PerlValue</code> is a NaN-boxed <code>u64</code>: immediates (<code>undef</code>, <code>i32</code>, raw <code>f64</code> bits) and tagged <code>Arc&lt;HeapObject&gt;</code> pointers for big ints, strings, arrays, hashes, refs, regexes, atomics, channels.</li>
          <li><strong>Regex</strong> — three-tier engine: Rust <code>regex</code> → <code>fancy-regex</code> (backrefs) → <code>pcre2</code> (PCRE-only verbs).</li>
          <li><strong>Parallelism</strong> — every parallel builtin uses rayon work-stealing across all cores. See <code>pmap</code>, <code>pflat_map</code>, <code>pgrep</code>, <code>pfor</code>, <code>psort</code>, <code>preduce</code>, <code>pcache</code>, <code>ppool</code>, <code>fan</code>, <code>pipeline</code>, <code>par_pipeline_stream</code>, <code>pchannel</code>, <code>pselect</code>, <code>par_walk</code>, <code>par_lines</code>, <code>par_sed</code>.</li>
          <li><strong>Binary size</strong> — ~21 MB stripped with LTO + O3.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>Language reflection</h2>
        <p>Everything the parser and dispatcher know about is exposed as plain Perl hashes, populated from the source of truth at compile time. <code>build.rs</code> parses category-labeled section comments in <code>is_perl5_core</code> / <code>stryke_extension_name</code>, the <code>try_builtin</code> match arms, and LSP hover docs in <code>doc_for_label_text</code>. <strong>Eight hashes — every direct lookup is O(1)</strong>.</p>

        <h3>Forward maps</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Long name</th><th>Short</th><th>Key → Value</th></tr>
          </thead>
          <tbody>
            <tr><td><code>%stryke::builtins</code></td><td><code>%b</code></td><td><strong>primary</strong> callable name → category. Clean unique-op count.</td></tr>
            <tr><td><code>%stryke::all</code></td><td><code>%all</code></td><td><strong>every spelling</strong> (primary + alias) → category. Aliases inherit their primary's tag. Use for <code>scalar keys %all</code>.</td></tr>
            <tr><td><code>%stryke::perl_compats</code></td><td><code>%pc</code></td><td>subset of <code>%b</code>: Perl 5 core only, name → category</td></tr>
            <tr><td><code>%stryke::extensions</code></td><td><code>%e</code></td><td>subset of <code>%b</code>: stryke-only, name → category</td></tr>
            <tr><td><code>%stryke::aliases</code></td><td><code>%a</code></td><td>alias → canonical primary</td></tr>
            <tr><td><code>%stryke::descriptions</code></td><td><code>%d</code></td><td>name → LSP one-liner (<em>sparse</em>)</td></tr>
          </tbody>
        </table>

        <h3>Inverted indexes (O(1) reverse-query)</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Long name</th><th>Short</th><th>Key → Value</th></tr>
          </thead>
          <tbody>
            <tr><td><code>%stryke::categories</code></td><td><code>%c</code></td><td>category → arrayref of names (<code>$c{parallel}</code> → <code>[pmap, pgrep, …]</code>)</td></tr>
            <tr><td><code>%stryke::primaries</code></td><td><code>%p</code></td><td>primary → arrayref of its aliases (<code>$p{to_json}</code> → <code>[tj]</code>)</td></tr>
          </tbody>
        </table>

        <h3>Examples</h3>
        <div class="oneliner">s 'p $b{pmap}'                              <span class="comment"># "parallel"</span></div>
        <div class="oneliner">s 'p $b{to_json}'                           <span class="comment"># "serialization"</span></div>
        <div class="oneliner">s 'p $all{tj}'                              <span class="comment"># "serialization"  (alias resolves via %all)</span></div>
        <div class="oneliner">s 'p scalar keys %all'                      <span class="comment"># total callable spellings (primaries + aliases)</span></div>
        <div class="oneliner">s 'p $pc{map}'                              <span class="comment"># "array / list"   (Perl core only)</span></div>
        <div class="oneliner">s 'p $e{pmap}'                              <span class="comment"># "parallel"       (extensions only)</span></div>
        <div class="oneliner">s 'p $a{tj}'                                <span class="comment"># "to_json"</span></div>
        <div class="oneliner">s 'p $d{pmap}'                              <span class="comment"># LSP one-liner</span></div>
        <div class="oneliner">s '$c{parallel} |&gt; e p'                      <span class="comment"># every parallel op, O(1) reverse-lookup</span></div>
        <div class="oneliner">s '$p{to_json} |&gt; e p'                       <span class="comment"># every alias of to_json</span></div>
        <div class="oneliner">s 'keys %pc |&gt; sort |&gt; p'                    <span class="comment"># every Perl compat, sorted</span></div>
        <div class="oneliner">s 'keys %e  |&gt; sort |&gt; p'                    <span class="comment"># every stryke extension</span></div>
        <div class="oneliner">s 'keys %all |&gt; less'                       <span class="comment"># browse every spelling in $PAGER</span></div>
        <div class="oneliner">s 'my %f; $f{$b{$_}}++ for keys %b; dd \%f'  <span class="comment"># per-category frequency</span></div>
        <div class="oneliner">s 'for my $h (qw(b all pc e a d c p)) { printf "%%%-4s %d\n", $h, scalar keys %$h }'  <span class="comment"># catalog</span></div>

        <h3>Notes</h3>
        <ul>
          <li>Every <code>$h{name}</code> lookup is O(1). Inverted indexes (<code>%c</code>, <code>%p</code>) let you do reverse-queries in O(1) too; filters like <code>grep { cond } keys %h</code> are still O(n).</li>
          <li>Hash sigil namespace is separate from scalars/subs — the short-alias letters don't collide with <code>$a</code>/<code>$b</code> sort specials, the <code>e</code> extension sub, or any other stryke name.</li>
          <li><code>%descriptions</code> is sparse: <code>exists $d{$name}</code> doubles as "is this documented in the LSP?".</li>
          <li>A value of <code>"uncategorized"</code> in <code>%builtins</code> flags a name that's dispatched at runtime but missing a <code>// ── category ──</code> section comment in <code>parser.rs</code>.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>Pipe-forward</h2>
        <p>The <code>|&gt;</code> operator (F# / Elixir) threads a value into the <strong>first argument</strong> of the next call — parse-time only, zero runtime cost.</p>
<pre>x |&gt; f          # f(x)
x |&gt; f(a, b)    # f(x, a, b)
x |&gt; f |&gt; g(2)  # g(f(x), 2)

# real pipeline — count words per file, top 10 longest:
f("*.txt") |&gt; map { [$_, slurp($_) |&gt; split(/\s+/) |&gt; scalar] }
            |&gt; sort { $b-&gt;[1] &lt;=&gt; $a-&gt;[1] }
            |&gt; take(10)
            |&gt; dd</pre>
        <p>Precedence sits between <code>?:</code> and <code>||</code>, so <code>x + 1 |&gt; f || y</code> parses as <code>f(x + 1) || y</code>.</p>

        <h3>Pipe-RHS sugar</h3>
        <ul>
          <li><strong>Thread macro</strong> — <code>t EXPR s1 s2 s3</code> expands to <code>EXPR |&gt; s1 |&gt; s2 |&gt; s3</code>. Stages like <code>pow($_, 2)</code> use <code>$_</code> as a placeholder, auto-wrapped in a coderef.</li>
          <li><strong><code>&gt;{ BLOCK }</code></strong> — IIFE anywhere an expression is valid; also works as a pipe stage (<code>lhs |&gt; &gt;{ body }</code>).</li>
          <li><strong><code>@[...]</code></strong> — sugar for <code>@{[...]}</code> (deref anonymous arrayref inline).</li>
          <li><strong><code>%[k =&gt; v]</code></strong> — sugar for <code>%{+{k =&gt; v}}</code> (deref anonymous hashref inline, sidesteps the block-vs-hashref ambiguity).</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>Builtin categories</h2>
        <p>3200+ operations across 3700+ spellings. Query them via <code>keys %stryke::builtins</code> — the table below is a navigational overview, not a full index. Run <code>s 'p scalar keys %b'</code> for the live count.</p>
        <div class="cat-grid">
          <div class="cat-card"><h4>Array / List (134+)</h4><p><code>map maps flat_map grep sort reverse push pop shift unshift splice reduce fold fore e first any all none take take_while drop skip_while partition min_by max_by zip zip_with interleave frequencies count_by chunk windowed enumerate shuffle uniq dedup compact flatten concat pluck grep_v with_index sorted sorted_desc sorted_nums without take_last drop_last pairwise batch rotate swap_pairs sliding_pairs run_length_encode group_consecutive permutations combinations power_set cartesian_product</code> &hellip;</p></div>
          <div class="cat-card"><h4>String (129+)</h4><p><code>chomp chop length substr index rindex split join uc lc ucfirst lcfirst chr ord trim lines words chars snake_case camel_case kebab_case pascal_case constant_case capitalize swap_case title_case squish pad_left pad_right center truncate_at reverse_str rot13 rot47 caesar_shift count_vowels count_consonants first_word last_word left_str right_str wrap_text dedent indent strip_html levenshtein soundex extract_numbers extract_emails extract_urls</code> &hellip;</p></div>
          <div class="cat-card"><h4>Math / Numeric (147+)</h4><p><code>abs int sqrt sin cos tan asin acos atan sinh cosh tanh exp log rand srand inc dec avg stddev clamp normalize range even odd zero positive negative sign negate double triple half round floor ceil gcd lcm factorial fibonacci is_prime divisors sieve_primes cbrt log2 log10 hypot rad_to_deg deg_to_rad pow2 softmax argmax argmin</code> &hellip;</p></div>
          <div class="cat-card"><h4>Conversion / Units (102+)</h4><p><code>c_to_f f_to_c c_to_k k_to_c miles_to_km km_to_miles feet_to_m m_to_feet inches_to_cm kg_to_lbs lbs_to_kg bytes_to_kb bytes_to_mb bytes_to_gb seconds_to_minutes hours_to_seconds liters_to_gallons cups_to_ml joules_to_cal watts_to_hp pascals_to_psi to_bin to_hex to_oct from_bin from_hex from_oct to_base from_base</code> &hellip;</p></div>
          <div class="cat-card"><h4>Validation (91+)</h4><p><code>is_empty is_blank is_numeric is_upper is_lower is_alpha is_digit is_alnum is_space is_palindrome is_prime is_sorted is_subset is_superset is_valid_ipv4 is_valid_ipv6 is_valid_email is_valid_url is_valid_json is_valid_semver is_valid_base64 is_ascii is_printable luhn_check is_undef is_defined is_array is_hash is_code is_ref is_int is_float</code> &hellip;</p></div>
          <div class="cat-card"><h4>Hash / Map (52+)</h4><p><code>keys values each delete exists select_keys top invert merge_hash has_key has_any_key has_all_keys pick omit hash_size hash_from_pairs pairs_from_hash hash_eq keys_sorted values_sorted hash_insert hash_update hash_delete zipmap counter</code></p></div>
          <div class="cat-card"><h4>Encoding / Crypto (64+)</h4><p><code>sha1 sha256 sha384 sha512 md5 hmac_sha256 uuid crc32 base64_encode base64_decode hex_encode hex_decode url_encode url_decode gzip gunzip zstd zstd_decode jwt_encode jwt_decode html_escape_str html_unescape_str shell_escape sql_escape hex_dump random_password random_hex_str</code></p></div>
          <div class="cat-card"><h4>I/O (62+)</h4><p><code>print p say printf open close eof readline read seek tell slurp input capture pager/pg/less binmode flock getc select truncate read_lines append_file to_file read_json write_json tempfile tempdir file_size file_mtime file_atime is_symlink is_readable is_writable is_executable xopen/xo</code></p></div>
          <div class="cat-card"><h4>Filesystem (84+)</h4><p><code>files/f fr dirs/d dr sym_links glob glob_par basename dirname realpath which stat lstat size copy move spurt read_bytes path_ext path_stem path_parent path_join path_split path_is_abs path_is_rel strip_prefix strip_suffix ensure_prefix ensure_suffix</code></p></div>
          <div class="cat-card"><h4>Serialization</h4><p><code>to_json/tj to_csv/tc to_toml/tt to_yaml/ty to_xml/tx to_html/th to_markdown/to_md/tmd ddump/dd stringify/str json_encode/decode yaml_encode/decode toml_encode/decode xml_encode/decode json_pretty json_minify escape_json</code></p></div>
          <div class="cat-card"><h4>Parallel (31)</h4><p><code>pmap pflat_map pgrep pfor psort preduce preduce_init pmap_reduce pmap_chunked pcache ppool pchannel pselect puniq pfirst pany fan fan_cap pipeline par_pipeline_stream glob_par par_walk par_lines par_sed par_find_files par_line_count pwatch watch</code></p></div>
          <div class="cat-card"><h4>Functional (56+)</h4><p><code>reduce fold inject collect complement constantly coalesce default_to when_true when_false if_else safe_div safe_mod safe_sqrt safe_log scan accumulate keep_if reject_if group_consecutive normalize_list softmax argmax argmin juxt2 juxt3 tap_val debug_val converge iterate_n unfold</code> &hellip;</p></div>
          <div class="cat-card"><h4>Matrix / Linear Algebra (29+)</h4><p><code>dot_product cross_product matrix_add matrix_scale matrix_multiply identity_matrix zeros_matrix ones_matrix diagonal matrix_trace matrix_shape matrix_row matrix_col magnitude vec_normalize vec_add vec_sub vec_scale linspace arange</code></p></div>
          <div class="cat-card"><h4>Data / Network (50+)</h4><p><code>fetch fetch_json fetch_async par_fetch csv_read csv_write dataframe sqlite json_jq ipv4_to_int int_to_ipv4 email_domain email_local url_host url_path url_query url_scheme</code></p></div>
          <div class="cat-card"><h4>Date / Time (48+)</h4><p><code>time localtime gmtime is_leap_year days_in_month month_name weekday_name quarter_of now_ms now_us now_ns unix_epoch today yesterday tomorrow is_weekend is_weekday datetime_utc datetime_from_epoch datetime_strftime</code></p></div>
          <div class="cat-card"><h4>System / Process (35+)</h4><p><code>system exec exit fork wait waitpid kill alarm sleep os_name os_arch num_cpus pid ppid uid gid username home_dir temp_dir cwd is_root uptime_secs cmd_exists env_get env_has env_set env_keys env_pairs signal_name has_stdin_tty has_stdout_tty</code></p></div>
          <div class="cat-card"><h4>Geometry</h4><p><code>distance_2d distance_3d midpoint slope area_triangle area_circle circumference perimeter_rect area_rect point_in_circle point_in_rect</code></p></div>
          <div class="cat-card"><h4>Color / ANSI</h4><p><code>rgb_to_hex hex_to_rgb ansi_red ansi_green ansi_blue ansi_yellow ansi_cyan ansi_magenta ansi_bold ansi_dim strip_ansi darken lighten mix_colors is_dark is_light</code></p></div>
          <div class="cat-card"><h4>Random</h4><p><code>rand srand coin_flip dice_roll random_int random_float random_bool random_choice random_between random_string random_alpha random_digit random_password random_hex_str</code></p></div>
          <div class="cat-card"><h4>Data Structures</h4><p><code>set heap deque stack_new queue_new lru_new counter counter_most_common defaultdict ordered_set bitset_new bitset_set bitset_test bitset_clear</code></p></div>
          <div class="cat-card"><h4>Async / Timing</h4><p><code>async spawn await timer bench trace eval_timeout retry rate_limit every gen</code></p></div>
          <div class="cat-card"><h4>Reflection</h4><p>Eight O(1) hashes — <code>%b</code> builtins, <code>%all</code> every spelling, <code>%pc</code> perl_compats, <code>%e</code> extensions, <code>%a</code> aliases, <code>%d</code> descriptions, <code>%c</code> categories, <code>%p</code> primaries.</p></div>
        </div>
      </section>

      <section class="tutorial-section">
        <h2>Parallel primitives (highlights)</h2>
        <p>Every <code>p*</code> primitive uses rayon work-stealing, saturates all cores by default, and takes three surface forms:</p>
<pre># block form   ($_ = element)
pmap { $_ * 2 } 1..1_000_000

# expression form
pmap $_ * 2, 1..1_000_000

# bare-fn form   (sub double { $_0 * 2 })
pmap double, 1..1_000_000</pre>

        <h3>fan / pchannel / ppool</h3>
<pre># fan — run a block N times in parallel ($_/$_0 = index 0..N-1)
fan 16 { heavy_work($_) }

# pchannel — bounded MPMC queue
my ($tx, $rx) = pchannel(100)
async { $tx-&gt;send($_) for 1..1000; undef $tx }
while (defined(my $v = $rx-&gt;recv)) { p $v }

# ppool — persistent worker pool
my $pool = ppool 4, sub {
  while (defined(my $j = $rx-&gt;recv)) { process($j) }
}
$tx-&gt;send($_) for @jobs;  undef $tx
$pool-&gt;join</pre>

        <h3>Pipelines</h3>
<pre># sequential (each stage drains list before next)
pipeline(
  sub { map { $_ * 2 } @_ },
  sub { grep { $_ &gt; 10 } @_ },
  sub { sum(@_) },
)-&gt;run(1..1000)

# streaming — bounded crossbeam channels, concurrent stages
par_pipeline_stream([\&amp;stage1, \&amp;stage2, \&amp;stage3], \@input)</pre>
      </section>

      <section class="tutorial-section">
        <h2>Perl-compat highlights</h2>
        <ul>
          <li><strong>OOP</strong> — <code>@ISA</code>, C3 MRO (live, not cached), <code>$obj-&gt;SUPER::method</code>, <code>tie</code> for scalars/arrays/hashes with <code>TIESCALAR</code>/<code>TIEARRAY</code>/<code>TIEHASH</code>, plus <code>EXISTS</code>/<code>DELETE</code>; <code>use overload</code> with full binary dispatch, <code>nomethod</code>, unary <code>neg</code>/<code>bool</code>/<code>abs</code>. Native <code>class</code> syntax with inheritance, traits, abstract/final, visibility, static fields, operator overloading, and reflection — see <a href="#oop">OOP section</a> below.</li>
          <li><strong>Specials</strong> — <code>$?</code> packed POSIX status, <code>$|</code> autoflush, <code>$.</code> line count (undef until first read), <code>@ARGV</code>, <code>%ENV</code>, <code>%SIG</code> (<code>SIGINT</code>/<code>SIGTERM</code>/<code>SIGALRM</code>/<code>SIGCHLD</code>), <code>format</code>/<code>write</code> (partial).</li>
          <li><strong>Phases</strong> — <code>BEGIN</code> / <code>UNITCHECK</code> / <code>CHECK</code> / <code>INIT</code> / <code>END</code> run in Perl order; <code>${^GLOBAL_PHASE}</code> matches Perl in both tree-walker and VM.</li>
          <li><strong>Interpolation</strong> — <code>$var</code>, <code>#{expr}</code>, <code>$h{k}</code>, <code>$a[i]</code>, <code>@a</code>, <code>@a[slice]</code>, <code>$#a</code>, <code>$0</code>, <code>$1</code>..<code>$n</code>; <code>\x{hex}</code> and unbraced <code>\x</code>.</li>
          <li><strong>Strict / modules</strong> — per-mode <code>use strict 'refs'</code> etc., <code>@INC</code> built from <code>-I</code>, <code>vendor/perl</code>, system Perl's <code>@INC</code>, script dir, <code>STRYKE_INC</code>. <code>List::Util</code> is native Rust.</li>
        </ul>
        <p>Full list in the <a href="https://github.com/MenkeTechnologies/strykelang#0x08-supported-perl-features">README §0x08</a>.</p>
      </section>

      <section class="tutorial-section" id="oop">
        <h2>Object-Oriented Programming</h2>
        <p>Stryke supports both Perl 5 OOP (<code>bless</code>, <code>@ISA</code>, <code>tie</code>, <code>use overload</code>) and a native <code>class</code> syntax with inheritance, traits, visibility, static fields, operator overloading, and full reflection.</p>

        <h3>Class basics</h3>
        <p>Declare classes with typed fields, defaults, and instance methods. Fields get auto-generated getters/setters. <code>$self</code> is implicit in methods.</p>
<pre>class Dog {
    name: Str
    breed: Str = "Mixed"
    fn bark { "Woof from " . $self-&gt;name }
}

my $d = Dog(name =&gt; "Rex")           <span class="comment"># named construction</span>
my $d = Dog("Rex", "Lab")             <span class="comment"># positional construction</span>
p $d-&gt;name                            <span class="comment"># getter → "Rex"</span>
$d-&gt;name("Max")                       <span class="comment"># setter</span>
p $d-&gt;bark()                          <span class="comment"># "Woof from Max"</span></pre>

        <h3>Methods with parameters</h3>
<pre>class Calculator {
    value: Int = 0
    fn add($n) { $self-&gt;value + $n }
}
my $c = Calculator(value =&gt; 10)
p $c-&gt;add(5)                          <span class="comment"># 15</span></pre>

        <h3>Static methods</h3>
<pre>class Math {
    fn Self.add($a, $b) { $a + $b }
    fn Self.pi { 3.14159 }
}
p Math::add(3, 4)                      <span class="comment"># 7</span>
p Math::pi()                           <span class="comment"># 3.14159</span></pre>

        <h3>Inheritance (<code>extends</code>)</h3>
        <p>Single and multiple inheritance. Parent fields and methods are inherited. C3 MRO for diamond resolution.</p>
<pre>class Animal {
    name: Str
    fn speak { "Animal: " . $self-&gt;name }
}
class Dog extends Animal {
    fn speak { "Woof from " . $self-&gt;name }  <span class="comment"># override</span>
}
my $d = Dog(name =&gt; "Rex")
p $d-&gt;speak()                         <span class="comment"># "Woof from Rex"</span>

<span class="comment"># multiple inheritance</span>
class A { a: Int = 1 }
class B { b: Int = 2 }
class C extends A, B { c: Int = 3 }
my $c = C()
p $c-&gt;a . "," . $c-&gt;b . "," . $c-&gt;c  <span class="comment"># "1,2,3"</span></pre>

        <h3>Abstract classes</h3>
        <p>Cannot be instantiated directly. Subclasses must implement abstract methods.</p>
<pre>abstract class Shape {
    name: Str
    fn describe { "Shape: " . $self-&gt;name }
}

<span class="comment"># Shape(name =&gt; "x")  → ERROR: cannot instantiate abstract class</span>

class Circle extends Shape { radius: Int }
my $c = Circle(name =&gt; "ring", radius =&gt; 5)
p $c-&gt;describe()                      <span class="comment"># "Shape: ring"</span></pre>

        <h3>Final classes and methods</h3>
        <p><code>final class</code> prevents subclassing. <code>final fn</code> prevents method override in subclasses. Both checked at declaration time.</p>
<pre>final class Config { value: Int = 42 }
<span class="comment"># class Bad extends Config { }  → ERROR: cannot extend final class</span>

class Base {
    final fn id { 42 }
    fn label { "base" }                <span class="comment"># can be overridden</span>
}
class Child extends Base { }
my $c = Child()
p $c-&gt;id()                            <span class="comment"># 42 (inherited, cannot override)</span></pre>

        <h3>Visibility (<code>pub</code> / <code>prot</code> / <code>priv</code>)</h3>
        <p>Applies to both fields and methods. Runtime enforcement on access.</p>
<pre>class Secret {
    pub visible: Int = 1               <span class="comment"># public (default)</span>
    priv hidden: Int = 42              <span class="comment"># own class only</span>
    prot internal: Int = 99            <span class="comment"># class + subclasses</span>

    fn get_hidden { $self-&gt;hidden }    <span class="comment"># internal access ok</span>
}
class Child extends Secret {
    fn get_internal { $self-&gt;internal } <span class="comment"># prot: ok from subclass</span>
}
my $s = Secret()
p $s-&gt;get_hidden()                    <span class="comment"># 42</span>
<span class="comment"># $s-&gt;hidden  → ERROR: private field</span>

my $c = Child()
p $c-&gt;get_internal()                  <span class="comment"># 99</span>
<span class="comment"># $c-&gt;internal  → ERROR: protected field (outside class hierarchy)</span></pre>

        <h3>Static fields</h3>
        <p>Shared across all instances. Access via <code>ClassName::field()</code> (getter) / <code>ClassName::field(value)</code> (setter).</p>
<pre>class Tracker {
    static total: Int = 0
    name: Str
    fn BUILD { Tracker::total(Tracker::total() + 1) }
}
my $a = Tracker(name =&gt; "a")
my $b = Tracker(name =&gt; "b")
p Tracker::total()                     <span class="comment"># 2</span></pre>

        <h3>BUILD / DESTROY hooks</h3>
        <p><code>BUILD</code> runs after field init (parent first, then child). <code>DESTROY</code> runs in reverse (child first, then parent).</p>
<pre>class Base {
    log: Str = ""
    fn BUILD { $self-&gt;log("base") }
}
class Child extends Base {
    fn BUILD { $self-&gt;log($self-&gt;log . "+child") }
}
my $c = Child()
p $c-&gt;log                             <span class="comment"># "base+child"</span>

<span class="comment"># DESTROY — child runs first</span>
class Base {
    static log: Str = ""
    fn DESTROY { Base::log(Base::log() . "base,") }
}
class Child extends Base {
    fn DESTROY { Base::log(Base::log() . "child,") }
}
my $c = Child()
$c-&gt;destroy()
p Base::log()                          <span class="comment"># "child,base,"</span></pre>

        <h3>Traits</h3>
        <p>Interface contracts with required and default methods. Enforced at class declaration.</p>
<pre>trait Loggable {
    fn log_prefix { "LOG" }            <span class="comment"># default (optional to implement)</span>
    fn log_msg                         <span class="comment"># required (no body)</span>
}

class Event impl Loggable {
    msg: Str
    fn log_msg { $self-&gt;msg }
}
my $e = Event(msg =&gt; "hello")
p $e-&gt;log_msg()                       <span class="comment"># "hello"</span>
p $e-&gt;does("Loggable")               <span class="comment"># 1</span>

<span class="comment"># Missing required method → compile-time error</span>
<span class="comment"># class Bad impl Loggable { }  → ERROR: missing required method 'log_msg'</span></pre>

        <h3>Late static binding (<code>static::</code>)</h3>
        <p>Resolves to the runtime class of <code>$self</code>, unlike <code>SUPER::</code> which is compile-time.</p>
<pre>class Base {
    fn class_name { static::identify() }
    fn identify { "Base" }
}
class Child extends Base {
    fn identify { "Child" }
}
my $c = Child()
p $c-&gt;class_name()                    <span class="comment"># "Child" (not "Base")</span></pre>

        <h3>Operator overloading</h3>
        <p>Define <code>op_add</code>, <code>op_sub</code>, <code>op_mul</code>, <code>op_div</code>, <code>op_mod</code>, <code>op_pow</code>, <code>op_eq</code>, <code>op_ne</code>, <code>op_lt</code>, <code>op_gt</code>, <code>op_le</code>, <code>op_ge</code>, <code>op_spaceship</code>, <code>op_neg</code>, <code>op_bool</code>, <code>op_abs</code>, <code>op_concat</code>, <code>stringify</code>, and more.</p>
<pre>class Vec2 {
    x: Int
    y: Int
    fn op_add($other) {
        Vec2(x =&gt; $self-&gt;x + $other-&gt;x, y =&gt; $self-&gt;y + $other-&gt;y)
    }
    fn op_neg { Vec2(x =&gt; -$self-&gt;x, y =&gt; -$self-&gt;y) }
    fn stringify { "(" . $self-&gt;x . "," . $self-&gt;y . ")" }
}
my $a = Vec2(x =&gt; 1, y =&gt; 2)
my $b = Vec2(x =&gt; 3, y =&gt; 4)
my $c = $a + $b
p "$c"                                 <span class="comment"># "(4,6)"</span>
my $d = -$a
p "$d"                                 <span class="comment"># "(-1,-2)"</span></pre>

        <h3>Reflection / introspection</h3>
<pre>class Animal { name: Str; fn speak { "..." }; fn eat { "nom" } }
class Dog extends Animal { breed: Str }
my $d = Dog(name =&gt; "Rex", breed =&gt; "Lab")

p join(",", $d-&gt;fields())             <span class="comment"># "name,breed"</span>
p join(",", $d-&gt;methods())            <span class="comment"># "speak,eat"  (inherited)</span>
p join(",", $d-&gt;superclass())         <span class="comment"># "Animal"</span>
p $d-&gt;isa("Dog")                      <span class="comment"># 1</span>
p $d-&gt;isa("Animal")                   <span class="comment"># 1  (inherited)</span>
p $d-&gt;isa("Cat")                      <span class="comment"># ""  (false)</span></pre>

        <h3>Built-in instance methods</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Method</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td><code>$obj-&gt;fields()</code></td><td>List of all field names (including inherited)</td></tr>
            <tr><td><code>$obj-&gt;methods()</code></td><td>List of all method names (including inherited)</td></tr>
            <tr><td><code>$obj-&gt;superclass()</code></td><td>List of parent class names</td></tr>
            <tr><td><code>$obj-&gt;isa("Class")</code></td><td>Checks inheritance chain</td></tr>
            <tr><td><code>$obj-&gt;does("Trait")</code></td><td>Checks trait implementation</td></tr>
            <tr><td><code>$obj-&gt;clone()</code></td><td>Deep copy (independent instance)</td></tr>
            <tr><td><code>$obj-&gt;with(k =&gt; v)</code></td><td>Functional update — returns new instance with changed fields</td></tr>
            <tr><td><code>$obj-&gt;to_hash()</code></td><td>Convert to hash reference</td></tr>
            <tr><td><code>$obj-&gt;destroy()</code></td><td>Explicit destructor call (triggers DESTROY chain)</td></tr>
            <tr><td><code>"$obj"</code></td><td>Stringify — <code>Class(field =&gt; val, ...)</code> or custom <code>stringify</code></td></tr>
          </tbody>
        </table>

        <h3>Field types</h3>
        <p>Runtime validation on setter. <code>Float</code> accepts both int and float. Custom types (struct/enum names) also work.</p>
<pre>class Typed {
    count: Int               <span class="comment"># integer</span>
    name: Str                <span class="comment"># string</span>
    ratio: Float             <span class="comment"># int or float</span>
    items: Array             <span class="comment"># array reference</span>
    map: Hash                <span class="comment"># hash reference</span>
    any_val                  <span class="comment"># untyped (Any)</span>
}</pre>
      </section>

      <section class="tutorial-section">
        <h2>Extensions beyond stock Perl 5</h2>
        <ul>
          <li><strong>Native data</strong> — CSV (<code>csv_read</code>/<code>csv_write</code>), columnar <code>dataframe</code>, embedded <code>sqlite</code>, TOML/YAML helpers.</li>
          <li><strong>HTTP</strong> — <code>fetch</code> / <code>fetch_json</code> / <code>fetch_async</code> / <code>par_fetch</code>.</li>
          <li><strong>Crypto / compression</strong> — <code>sha256</code>, <code>hmac_sha256</code>, <code>jwt_encode</code>/<code>decode</code>, <code>gzip</code> / <code>gunzip</code> / <code>zstd</code>.</li>
          <li><strong>Standalone binaries</strong> — <code>s build SCRIPT -o OUT</code> bakes a script into a self-contained executable.</li>
          <li><strong>Inline Rust FFI</strong> — <code>rust { pub extern "C" fn ... }</code> blocks compile to a cdylib on first run, dlopen + register as Perl-callable subs.</li>
          <li><strong>Bytecode cache</strong> — <code>STRYKE_BC_CACHE=1</code> skips parse + compile on warm starts via on-disk <code>.pec</code> bundles.</li>
          <li><strong>Distributed compute</strong> — <code>cluster([...])</code> builds an SSH worker pool; <code>pmap_on $cluster { } @list</code> fans a map across persistent remote workers with fault tolerance.</li>
          <li><strong>Shared state</strong> — <code>mysync</code> declares atomic variables safe to mutate from parallel workers.</li>
          <li><strong>Language server</strong> — <code>s lsp</code> (or <code>s --lsp</code>) runs an LSP server over stdio with diagnostics, hover, completion. The five reflection hashes above are part of the completion surface.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>CLI flags (common)</h2>
<pre>-e CODE                // one-line program (multiple -e's allowed)
-E CODE                // like -e, but enables all optional features
-c                     // syntax check only
--lint / --check       // parse + compile bytecode without running
--disasm               // print bytecode disassembly before VM run
--ast                  // dump parsed AST as JSON and exit
--fmt                  // pretty-print parsed Perl to stdout and exit
--profile              // wall-clock profile stderr (flamegraph-ready)
--flame                // flamegraph: terminal bars (TTY) or SVG
--no-jit               // disable Cranelift JIT (bytecode interpreter only)
--compat               // Perl 5 strict-compat: disable all stryke extensions
-n / -p / -i           // stdin line-mode + in-place edit
-j N                   // parallel threads for multi-file execution

// Subcommands
s build SCRIPT -o OUT  // AOT compile to standalone binary
s build --project DIR  // bundle project (main.stk + lib/) into binary
s check FILE...        // parse + compile without executing (CI/editor)
s disasm FILE          // disassemble bytecode
s profile FILE         // run with profiling (--flame for SVG)
s fmt -i FILE...       // format source files in place
s bench                // run benchmarks from bench/ or benches/
s test                 // run tests from t/
s init NAME            // scaffold new project (lib/, bench/, t/)
s repl --load FILE     // REPL with pre-loaded file
s lsp                  // language server over stdio
s completions zsh      // emit shell completions
s ast FILE             // dump AST as JSON
s prun FILE...         // run multiple files in parallel
s convert FILE...      // convert Perl to stryke syntax
s deconvert FILE...    // convert stryke back to Perl
s --remote-worker      // worker process for distributed cluster</pre>
      </section>

      <section class="tutorial-section">
        <h2>Repository &amp; links</h2>
        <ul>
          <li><strong>Source</strong> — <a href="https://github.com/MenkeTechnologies/strykelang">github.com/MenkeTechnologies/stryke</a></li>
          <li><strong>Crate</strong> — <a href="https://crates.io/crates/strykelang">crates.io/crates/stryke</a> (<code>cargo install strykelang</code>)</li>
          <li><strong>Rust API docs</strong> — <a href="https://docs.rs/strykelang">docs.rs/stryke</a></li>
          <li><strong>Issues</strong> — <a href="https://github.com/MenkeTechnologies/strykelang/issues">github.com/MenkeTechnologies/stryke/issues</a></li>
          <li><strong>Full README</strong> — <a href="https://github.com/MenkeTechnologies/strykelang#readme">README on GitHub</a> (install, parallel primitives, mysync, CLI flags, architecture, benchmarks, standalone binaries, inline Rust, bytecode cache, distributed <code>pmap_on</code>, LSP).</li>
          <li><strong>Parity</strong> — <code>parity/cases/*.pl</code> holds 20k+ Perl-vs-s test cases run by <code>parity/run_parity.sh</code>.</li>
        </ul>
      </section>
    </main>
  </div>

  <script src="hud-theme.js"></script>
</body>
</html>