vyre-libs 0.6.3

vyre Category A library ecosystem - pure-IR compositions over vyre-ops hardware primitives
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
use super::*;
use crate::parsing::c::lex::lexer::sections;

pub fn c11_lexer(
    haystack: &str,
    out_tok_types: &str,
    out_tok_starts: &str,
    out_tok_lens: &str,
    out_counts: &str,
    haystack_len: u32,
) -> Program {
    let t = Expr::InvocationId { axis: 0 };

    let next_byte = |offset: u32| {
        Expr::select(
            Expr::lt(
                Expr::add(Expr::var("pos"), Expr::u32(offset)),
                Expr::buf_len(haystack),
            ),
            byte_load(haystack, Expr::add(Expr::var("pos"), Expr::u32(offset))),
            Expr::u32(0),
        )
    };

    let mut classify_at_pos = vec![
        Node::let_bind("byte", byte_load(haystack, Expr::var("pos"))),
        Node::let_bind(
            "prev_byte",
            Expr::select(
                Expr::gt(Expr::var("pos"), Expr::u32(0)),
                byte_load(
                    haystack,
                    Expr::saturating_sub(Expr::var("pos"), Expr::u32(1)),
                ),
                Expr::u32(0),
            ),
        ),
        Node::let_bind("next_byte", next_byte(1)),
        Node::let_bind("next2_byte", next_byte(2)),
        Node::let_bind("emit", Expr::u32(0)),
        Node::let_bind("tok_type", Expr::u32(TOK_WHITESPACE)),
        Node::let_bind("tok_len", Expr::u32(1)),
    ];

    classify_at_pos.push(set_token(
        Expr::and(
            byte_eq(Expr::var("byte"), b'#'),
            Expr::eq(Expr::var("line_allows_directive"), Expr::u32(1)),
        ),
        TOK_PREPROC,
        Expr::u32(1),
    ));
    classify_at_pos.push(Node::if_then(
        Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_PREPROC)),
        vec![
            Node::let_bind("preproc_done", Expr::u32(0)),
            Node::let_bind("preproc_spliced_cr", Expr::u32(0)),
            Node::loop_for(
                "scan_preproc",
                Expr::add(Expr::var("pos"), Expr::u32(1)),
                scan_upper_bound_with_cap(
                    haystack,
                    Expr::add(Expr::var("pos"), Expr::u32(1)),
                    MAX_PREPROC_SCAN,
                ),
                vec![Node::if_then(
                    Expr::eq(Expr::var("preproc_done"), Expr::u32(0)),
                    vec![
                        Node::let_bind("scan_byte", byte_load(haystack, Expr::var("scan_preproc"))),
                        Node::let_bind(
                            "scan_prev",
                            Expr::select(
                                Expr::gt(Expr::var("scan_preproc"), Expr::var("pos")),
                                byte_load(
                                    haystack,
                                    Expr::saturating_sub(Expr::var("scan_preproc"), Expr::u32(1)),
                                ),
                                Expr::u32(0),
                            ),
                        ),
                        Node::if_then_else(
                            Expr::or(
                                byte_eq(Expr::var("scan_byte"), b'\n'),
                                byte_eq(Expr::var("scan_byte"), b'\r'),
                            ),
                            vec![Node::if_then_else(
                                Expr::or(
                                    byte_eq(Expr::var("scan_prev"), b'\\'),
                                    Expr::and(
                                        byte_eq(Expr::var("scan_byte"), b'\n'),
                                        Expr::eq(Expr::var("preproc_spliced_cr"), Expr::u32(1)),
                                    ),
                                ),
                                vec![
                                    Node::assign(
                                        "tok_len",
                                        Expr::add(Expr::var("tok_len"), Expr::u32(1)),
                                    ),
                                    Node::assign(
                                        "preproc_spliced_cr",
                                        Expr::select(
                                            byte_eq(Expr::var("scan_byte"), b'\r'),
                                            Expr::u32(1),
                                            Expr::u32(0),
                                        ),
                                    ),
                                ],
                                vec![Node::assign("preproc_done", Expr::u32(1))],
                            )],
                            vec![Node::assign(
                                "tok_len",
                                Expr::add(Expr::var("tok_len"), Expr::u32(1)),
                            )],
                        ),
                    ],
                )],
            ),
        ],
    ));

    classify_at_pos.push(set_token(
        Expr::and(
            byte_eq(Expr::var("byte"), b'/'),
            byte_eq(Expr::var("next_byte"), b'/'),
        ),
        TOK_COMMENT,
        Expr::u32(2),
    ));
    classify_at_pos.push(Node::if_then(
        Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_COMMENT)),
        vec![
            Node::let_bind("comment_done", Expr::u32(0)),
            Node::loop_for(
                "scan_comment",
                Expr::add(Expr::var("pos"), Expr::u32(2)),
                scan_upper_bound_with_cap(
                    haystack,
                    Expr::add(Expr::var("pos"), Expr::u32(2)),
                    MAX_COMMENT_SCAN,
                ),
                vec![Node::if_then(
                    Expr::eq(Expr::var("comment_done"), Expr::u32(0)),
                    vec![
                        Node::let_bind("scan_byte", byte_load(haystack, Expr::var("scan_comment"))),
                        Node::if_then_else(
                            byte_eq(Expr::var("scan_byte"), b'\n'),
                            vec![Node::assign("comment_done", Expr::u32(1))],
                            vec![Node::assign(
                                "tok_len",
                                Expr::add(Expr::var("tok_len"), Expr::u32(1)),
                            )],
                        ),
                    ],
                )],
            ),
        ],
    ));

    classify_at_pos.push(set_token(
        Expr::and(
            byte_eq(Expr::var("byte"), b'/'),
            byte_eq(Expr::var("next_byte"), b'*'),
        ),
        TOK_COMMENT,
        Expr::u32(2),
    ));
    classify_at_pos.push(Node::if_then(
        Expr::and(
            Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_COMMENT)),
            byte_eq(Expr::var("next_byte"), b'*'),
        ),
        vec![
            Node::let_bind("block_done", Expr::u32(0)),
            Node::loop_for(
                "scan_block_comment",
                Expr::add(Expr::var("pos"), Expr::u32(2)),
                scan_upper_bound_with_cap(
                    haystack,
                    Expr::add(Expr::var("pos"), Expr::u32(2)),
                    MAX_BLOCK_COMMENT_SCAN,
                ),
                vec![Node::if_then(
                    Expr::eq(Expr::var("block_done"), Expr::u32(0)),
                    vec![
                        Node::assign("tok_len", Expr::add(Expr::var("tok_len"), Expr::u32(1))),
                        Node::let_bind(
                            "scan_byte",
                            byte_load(haystack, Expr::var("scan_block_comment")),
                        ),
                        Node::let_bind(
                            "scan_next",
                            Expr::select(
                                Expr::lt(
                                    Expr::add(Expr::var("scan_block_comment"), Expr::u32(1)),
                                    Expr::buf_len(haystack),
                                ),
                                byte_load(
                                    haystack,
                                    Expr::add(Expr::var("scan_block_comment"), Expr::u32(1)),
                                ),
                                Expr::u32(0),
                            ),
                        ),
                        Node::if_then(
                            Expr::and(
                                byte_eq(Expr::var("scan_byte"), b'*'),
                                byte_eq(Expr::var("scan_next"), b'/'),
                            ),
                            vec![
                                Node::assign(
                                    "tok_len",
                                    Expr::add(Expr::var("tok_len"), Expr::u32(1)),
                                ),
                                Node::assign("block_done", Expr::u32(1)),
                            ],
                        ),
                    ],
                )],
            ),
            Node::if_then(
                Expr::eq(Expr::var("block_done"), Expr::u32(0)),
                vec![Node::assign(
                    "tok_type",
                    Expr::u32(TOK_ERR_UNTERMINATED_COMMENT),
                )],
            ),
        ],
    ));

    classify_at_pos.push(set_token(
        Expr::or(
            Expr::and(
                Expr::or(
                    byte_eq(Expr::var("byte"), b'L'),
                    Expr::or(
                        byte_eq(Expr::var("byte"), b'u'),
                        byte_eq(Expr::var("byte"), b'U'),
                    ),
                ),
                byte_eq(Expr::var("next_byte"), b'"'),
            ),
            Expr::and(
                Expr::and(
                    byte_eq(Expr::var("byte"), b'u'),
                    byte_eq(Expr::var("next_byte"), b'8'),
                ),
                byte_eq(Expr::var("next2_byte"), b'"'),
            ),
        ),
        TOK_STRING,
        Expr::select(
            Expr::and(
                byte_eq(Expr::var("byte"), b'u'),
                byte_eq(Expr::var("next_byte"), b'8'),
            ),
            Expr::u32(3),
            Expr::u32(2),
        ),
    ));
    classify_at_pos.push(set_token(
        Expr::or(
            Expr::and(
                Expr::or(
                    byte_eq(Expr::var("byte"), b'L'),
                    Expr::or(
                        byte_eq(Expr::var("byte"), b'u'),
                        byte_eq(Expr::var("byte"), b'U'),
                    ),
                ),
                byte_eq(Expr::var("next_byte"), b'\''),
            ),
            Expr::and(
                Expr::and(
                    byte_eq(Expr::var("byte"), b'u'),
                    byte_eq(Expr::var("next_byte"), b'8'),
                ),
                byte_eq(Expr::var("next2_byte"), b'\''),
            ),
        ),
        TOK_CHAR,
        Expr::select(
            Expr::and(
                byte_eq(Expr::var("byte"), b'u'),
                byte_eq(Expr::var("next_byte"), b'8'),
            ),
            Expr::u32(3),
            Expr::u32(2),
        ),
    ));

    classify_at_pos.push(set_token(
        Expr::and(
            is_ident_start(Expr::var("byte")),
            Expr::not(is_ident_continue(Expr::var("prev_byte"))),
        ),
        TOK_IDENTIFIER,
        Expr::u32(1),
    ));
    classify_at_pos.push(Node::if_then(
        Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_IDENTIFIER)),
        vec![
            Node::let_bind("ident_done", Expr::u32(0)),
            Node::loop_for(
                "scan_ident",
                Expr::add(Expr::var("pos"), Expr::u32(1)),
                scan_upper_bound_with_cap(
                    haystack,
                    Expr::add(Expr::var("pos"), Expr::u32(1)),
                    MAX_IDENT_SCAN,
                ),
                vec![Node::if_then(
                    Expr::eq(Expr::var("ident_done"), Expr::u32(0)),
                    vec![
                        Node::let_bind("scan_byte", byte_load(haystack, Expr::var("scan_ident"))),
                        Node::if_then_else(
                            is_ident_continue(Expr::var("scan_byte")),
                            vec![Node::assign(
                                "tok_len",
                                Expr::add(Expr::var("tok_len"), Expr::u32(1)),
                            )],
                            vec![Node::assign("ident_done", Expr::u32(1))],
                        ),
                    ],
                )],
            ),
        ],
    ));
    classify_at_pos.push(set_token(
        Expr::and(
            is_digit(Expr::var("byte")),
            Expr::not(is_ident_continue(Expr::var("prev_byte"))),
        ),
        TOK_INTEGER,
        Expr::u32(1),
    ));
    classify_at_pos.push(set_token(
        Expr::and(
            byte_eq(Expr::var("byte"), b'.'),
            is_digit(Expr::var("next_byte")),
        ),
        TOK_FLOAT,
        Expr::u32(1),
    ));
    classify_at_pos.push(Node::if_then(
        Expr::or(
            Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_INTEGER)),
            Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_FLOAT)),
        ),
        vec![
            Node::let_bind("number_done", Expr::u32(0)),
            Node::let_bind(
                "number_is_float",
                Expr::select(
                    Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_FLOAT)),
                    Expr::u32(1),
                    Expr::u32(0),
                ),
            ),
            Node::loop_for(
                "scan_number",
                Expr::add(Expr::var("pos"), Expr::u32(1)),
                scan_upper_bound_with_cap(
                    haystack,
                    Expr::add(Expr::var("pos"), Expr::u32(1)),
                    MAX_NUMBER_SCAN,
                ),
                vec![Node::if_then(
                    Expr::eq(Expr::var("number_done"), Expr::u32(0)),
                    vec![
                        Node::let_bind("scan_byte", byte_load(haystack, Expr::var("scan_number"))),
                        Node::let_bind(
                            "scan_prev",
                            byte_load(
                                haystack,
                                Expr::saturating_sub(Expr::var("scan_number"), Expr::u32(1)),
                            ),
                        ),
                        Node::let_bind(
                            "scan_next",
                            Expr::select(
                                Expr::lt(
                                    Expr::add(Expr::var("scan_number"), Expr::u32(1)),
                                    Expr::buf_len(haystack),
                                ),
                                byte_load(
                                    haystack,
                                    Expr::add(Expr::var("scan_number"), Expr::u32(1)),
                                ),
                                Expr::u32(0),
                            ),
                        ),
                        Node::let_bind(
                            "scan_can_start_exponent",
                            Expr::and(
                                Expr::or(
                                    byte_eq(Expr::var("scan_byte"), b'e'),
                                    Expr::or(
                                        byte_eq(Expr::var("scan_byte"), b'E'),
                                        Expr::or(
                                            byte_eq(Expr::var("scan_byte"), b'p'),
                                            byte_eq(Expr::var("scan_byte"), b'P'),
                                        ),
                                    ),
                                ),
                                Expr::or(
                                    is_digit(Expr::var("scan_next")),
                                    Expr::or(
                                        byte_eq(Expr::var("scan_next"), b'+'),
                                        byte_eq(Expr::var("scan_next"), b'-'),
                                    ),
                                ),
                            ),
                        ),
                        Node::let_bind(
                            "scan_is_exponent_sign",
                            Expr::and(
                                Expr::or(
                                    byte_eq(Expr::var("scan_byte"), b'+'),
                                    byte_eq(Expr::var("scan_byte"), b'-'),
                                ),
                                Expr::or(
                                    byte_eq(Expr::var("scan_prev"), b'e'),
                                    Expr::or(
                                        byte_eq(Expr::var("scan_prev"), b'E'),
                                        Expr::or(
                                            byte_eq(Expr::var("scan_prev"), b'p'),
                                            byte_eq(Expr::var("scan_prev"), b'P'),
                                        ),
                                    ),
                                ),
                            ),
                        ),
                        Node::let_bind("scan_is_float_dot", byte_eq(Expr::var("scan_byte"), b'.')),
                        Node::let_bind(
                            "scan_is_number_tail",
                            Expr::or(
                                is_ident_continue(Expr::var("scan_byte")),
                                Expr::or(
                                    Expr::var("scan_is_float_dot"),
                                    Expr::var("scan_is_exponent_sign"),
                                ),
                            ),
                        ),
                        Node::if_then_else(
                            Expr::var("scan_is_number_tail"),
                            vec![
                                Node::assign(
                                    "tok_len",
                                    Expr::add(Expr::var("tok_len"), Expr::u32(1)),
                                ),
                                Node::if_then(
                                    Expr::or(
                                        Expr::var("scan_is_float_dot"),
                                        Expr::var("scan_can_start_exponent"),
                                    ),
                                    vec![Node::assign("number_is_float", Expr::u32(1))],
                                ),
                            ],
                            vec![Node::assign("number_done", Expr::u32(1))],
                        ),
                    ],
                )],
            ),
            Node::if_then(
                Expr::eq(Expr::var("number_is_float"), Expr::u32(1)),
                vec![Node::assign("tok_type", Expr::u32(TOK_FLOAT))],
            ),
        ],
    ));

    classify_at_pos.push(set_token(
        byte_eq(Expr::var("byte"), b'"'),
        TOK_STRING,
        Expr::u32(1),
    ));
    classify_at_pos.push(set_token(
        byte_eq(Expr::var("byte"), b'\''),
        TOK_CHAR,
        Expr::u32(1),
    ));
    classify_at_pos.push(Node::if_then(
        Expr::or(
            Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_STRING)),
            Expr::eq(Expr::var("tok_type"), Expr::u32(TOK_CHAR)),
        ),
        vec![
            Node::let_bind(
                "literal_quote_offset",
                Expr::select(
                    Expr::or(
                        byte_eq(Expr::var("byte"), b'"'),
                        byte_eq(Expr::var("byte"), b'\''),
                    ),
                    Expr::u32(0),
                    Expr::select(
                        Expr::and(
                            byte_eq(Expr::var("byte"), b'u'),
                            byte_eq(Expr::var("next_byte"), b'8'),
                        ),
                        Expr::u32(2),
                        Expr::u32(1),
                    ),
                ),
            ),
            Node::let_bind(
                "quote",
                byte_load(
                    haystack,
                    Expr::add(Expr::var("pos"), Expr::var("literal_quote_offset")),
                ),
            ),
            Node::let_bind("literal_done", Expr::u32(0)),
            Node::let_bind("escaped", Expr::u32(0)),
            Node::let_bind("literal_unterminated", Expr::u32(0)),
            Node::let_bind("invalid_escape", Expr::u32(0)),
            Node::loop_for(
                "scan_literal",
                Expr::add(
                    Expr::add(Expr::var("pos"), Expr::var("literal_quote_offset")),
                    Expr::u32(1),
                ),
                scan_upper_bound_with_cap(
                    haystack,
                    Expr::add(
                        Expr::add(Expr::var("pos"), Expr::var("literal_quote_offset")),
                        Expr::u32(1),
                    ),
                    MAX_LITERAL_SCAN,
                ),
                vec![Node::if_then(
                    Expr::eq(Expr::var("literal_done"), Expr::u32(0)),
                    vec![
                        Node::assign("tok_len", Expr::add(Expr::var("tok_len"), Expr::u32(1))),
                        Node::let_bind("scan_byte", byte_load(haystack, Expr::var("scan_literal"))),
                        Node::if_then_else(
                            Expr::eq(Expr::var("escaped"), Expr::u32(1)),
                            vec![
                                Node::if_then(
                                    Expr::not(is_valid_escape_byte(
                                        haystack,
                                        Expr::var("scan_literal"),
                                        Expr::var("scan_byte"),
                                        haystack_len,
                                    )),
                                    vec![Node::assign("invalid_escape", Expr::u32(1))],
                                ),
                                Node::assign("escaped", Expr::u32(0)),
                            ],
                            vec![Node::if_then_else(
                                byte_eq(Expr::var("scan_byte"), b'\\'),
                                vec![Node::assign("escaped", Expr::u32(1))],
                                vec![Node::if_then_else(
                                    Expr::eq(Expr::var("scan_byte"), Expr::var("quote")),
                                    vec![Node::assign("literal_done", Expr::u32(1))],
                                    vec![Node::if_then(
                                        Expr::or(
                                            byte_eq(Expr::var("scan_byte"), b'\n'),
                                            byte_eq(Expr::var("scan_byte"), b'\r'),
                                        ),
                                        vec![
                                            Node::assign("literal_unterminated", Expr::u32(1)),
                                            Node::assign("literal_done", Expr::u32(1)),
                                        ],
                                    )],
                                )],
                            )],
                        ),
                    ],
                )],
            ),
            Node::if_then(
                Expr::eq(Expr::var("literal_done"), Expr::u32(0)),
                vec![Node::assign("literal_unterminated", Expr::u32(1))],
            ),
            Node::if_then(
                Expr::eq(Expr::var("literal_unterminated"), Expr::u32(1)),
                vec![Node::assign(
                    "tok_type",
                    Expr::select(
                        Expr::eq(Expr::var("quote"), ascii(b'"')),
                        Expr::u32(TOK_ERR_UNTERMINATED_STRING),
                        Expr::u32(TOK_ERR_UNTERMINATED_CHAR),
                    ),
                )],
            ),
            Node::if_then(
                Expr::and(
                    Expr::eq(Expr::var("literal_unterminated"), Expr::u32(0)),
                    Expr::eq(Expr::var("invalid_escape"), Expr::u32(1)),
                ),
                vec![Node::assign("tok_type", Expr::u32(TOK_ERR_INVALID_ESCAPE))],
            ),
        ],
    ));

    classify_at_pos.extend(sections::operator_punct_pushes());
    classify_at_pos.extend(sections::store_token_and_advance_pushes(
        haystack,
        haystack_len,
        out_tok_types,
        out_tok_starts,
        out_tok_lens,
    ));

    Program::wrapped(
        vec![
            BufferDecl::storage(haystack, 0, BufferAccess::ReadOnly, DataType::U32)
                .with_count(haystack_len.max(1)),
            BufferDecl::storage(out_tok_types, 1, BufferAccess::ReadWrite, DataType::U32)
                .with_count(haystack_len.max(1)),
            BufferDecl::storage(out_tok_starts, 2, BufferAccess::ReadWrite, DataType::U32)
                .with_count(haystack_len.max(1)),
            BufferDecl::storage(out_tok_lens, 3, BufferAccess::ReadWrite, DataType::U32)
                .with_count(haystack_len.max(1)),
            BufferDecl::storage(out_counts, 4, BufferAccess::ReadWrite, DataType::U32)
                .with_count(1),
        ],
        [256, 1, 1],
        {
            let entry_body = vec![Node::if_then(
                Expr::eq(t.clone(), Expr::u32(0)),
                vec![
                    Node::let_bind("cursor", Expr::u32(0)),
                    Node::let_bind("line_allows_directive", Expr::u32(1)),
                    Node::let_bind("tok_idx", Expr::u32(0)),
                    Node::loop_for(
                        "token_iter",
                        Expr::u32(0),
                        Expr::buf_len(haystack),
                        vec![Node::if_then(
                            Expr::lt(Expr::var("cursor"), Expr::buf_len(haystack)),
                            {
                                let mut body = vec![Node::let_bind("pos", Expr::var("cursor"))];
                                body.push(child_phase(
                                    "vyre-libs::parsing::c_lexer",
                                    "vyre-libs::parsing::c_lexer::classify_at_pos",
                                    classify_at_pos,
                                ));
                                body
                            },
                        )],
                    ),
                    Node::store(out_counts, Expr::u32(0), Expr::var("tok_idx")),
                ],
            )];
            vec![wrap_anonymous("vyre-libs::parsing::c_lexer", entry_body)]
        },
    )
    .with_entry_op_id("vyre-libs::parsing::c_lexer")
    .with_non_composable_with_self(true)
}