compiler/ lib/ examples/ std/ arch/ rv64/ tests/ abi.sizes.rad 3.4 KiB aggregate.return.rad 4.0 KiB arith.assignment.rad 580 B arith.basic.rad 176 B arith.modulo.rad 96 B arith.subword.rad 3.8 KiB arith.sum.rad 177 B arith.w64.rad 4.1 KiB array.assign.rad 221 B array.bounds.check.rad 321 B array.index.assign.rad 367 B array.index.rad 249 B array.length.rad 262 B array.math.rad 1.2 KiB array.nested.assign.rad 319 B array.nested.rad 325 B array.record.elements.rad 1.7 KiB array.repeat.edge.rad 548 B array.repeat.rad 828 B array.return.rad 330 B array.slice.empty.rad 108 B array.slice.gen.end.rad 126 B array.slice.gen.index.rad 139 B array.slice.gen.open.rad 125 B array.slice.gen.start.end.rad 127 B array.slice.gen.start.rad 126 B array.slice.rad 759 B as.precedence.rad 212 B assert.basic.rad 387 B assert.fail.rad 138 B assert.false.rad 140 B assert.true.rad 100 B assign.mutable.rad 6.1 KiB assign.rad 129 B assign.shadow.mutable.rad 461 B binop.bitwise.rad 1.2 KiB binop.cmp.rad 426 B bool.comparison.array.rad 688 B bool.comparison.nested.gen.rad 1.0 KiB bool.comparison.opt.rad 905 B bool.comparison.record.gen.rad 1.0 KiB bool.comparison.record.rad 1.1 KiB bool.comparison.slice.gen.rad 157 B bool.comparison.slice.rad 4.1 KiB bool.comparison.slice.record.gen.rad 2.0 KiB bool.comparison.slice.union.gen.rad 2.5 KiB bool.comparison.union.ctor.rad 690 B bool.comparison.union.gen.rad 1.2 KiB bool.comparison.union.record.gen.rad 1.5 KiB bool.comparison.union.simple.gen.rad 281 B bool.operators.complex.rad 384 B bool.operators.rad 831 B bool.short.circuit.rad 2.3 KiB bool.simple.rad 194 B bool.values.rad 772 B builtin.size.align.rad 1.3 KiB builtin.sliceof.mut.rad 606 B builtin.sliceof.rad 505 B call.arg.clobber.rad 717 B call.basic.rad 241 B call.clobber.rad 462 B cast.same.size.rad 1.0 KiB casting.numbers.rad 1.5 KiB char.literal.rad 165 B compound.assign.field.rad 285 B compound.assign.rad 1.1 KiB cond.assign.rad 723 B cond.expr.aggregate.rad 1.1 KiB cond.expr.rad 1.8 KiB cond.for.else.break.rad 326 B cond.for.indexed.rad 238 B cond.for.rad 165 B cond.for.range.indexed.rad 526 B cond.for.range.rad 171 B cond.for.unsigned.range.rad 644 B cond.forever.break.continue.rad 182 B cond.forever.break.rad 232 B cond.fused.rad 926 B cond.if.case.rad 2.2 KiB cond.if.else.min.rad 143 B cond.if.else.rad 225 B cond.if.elseif.rad 420 B cond.if.noelse.rad 120 B cond.if.rad 865 B cond.match.fallthrough.rad 369 B cond.match.guard.rad 1.4 KiB cond.match.guard.regalloc.rad 1.3 KiB cond.while.else.break.rad 282 B cond.while.rad 119 B const.array.copy.mutate.rad 386 B const.array.rad 195 B const.basic.rad 325 B const.char.rad 159 B const.fn.array.rad 664 B const.record.array.rad 1.2 KiB const.record.array.simple.rad 523 B const.record.ctor.rad 170 B const.record.fn.rad 353 B const.record.rad 182 B const.slice.param.rad 333 B const.union.payload.ctor.rad 349 B const.union.record.literal.rad 359 B data.array.rad 767 B data.bool.rad 216 B data.i16.rad 261 B data.i32.rad 281 B data.i8.rad 248 B data.record.rad 561 B data.simple.rad 436 B data.u16.rad 220 B data.u32.rad 240 B data.u8.rad 208 B data.union.rad 886 B debug.tag.rad 557 B edge.cases.2.rad 337 B edge.cases.3.rad 594 B edge.cases.4.rad 1.2 KiB edge.cases.5.rad 1.0 KiB edge.cases.6.rad 2.6 KiB edge.cases.7.addr.bug.rad 224 B edge.cases.8.bug.rad 508 B edge.cases.rad 223 B error.basic.rad 159 B error.catch.rad 1.6 KiB error.division.zero.rad 164 B error.modulo.zero.rad 162 B error.multi.basic.rad 672 B error.multi.catch.rad 772 B error.multi.catch.typed.binding.rad 791 B error.multi.catch.typed.catchall.rad 1.0 KiB error.multi.catch.typed.rad 1.1 KiB error.multi.propagate.multi.rad 953 B error.multi.propagate.rad 825 B error.multi.try.optional.rad 507 B error.slice.bounds.rad 219 B error.try.bang.success.rad 370 B error.try.catch.binding.rad 2.0 KiB error.try.optional.rad 1.8 KiB error.try.rad 4.0 KiB fn.block.scope.rad 508 B fn.callback.nested.rad 1.2 KiB fn.default.rad 131 B fn.local.rad 140 B fn.recursion.2.rad 239 B fn.void.rad 150 B for.else.continue.rad 1.1 KiB frame.large.rad 567 B if-let-mut.rad 1.1 KiB iflet.shadow.leak.rad 317 B integer.bitwise.basic.rad 693 B integer.overflow.rad 1.8 KiB large.blit.store.rad 2.1 KiB let.guard.rad 1.9 KiB literal.w64.rad 1.7 KiB loc.addr.offset.bug.rad 410 B loc.addr.opt.to.opt.rad 433 B loc.addr.optional.assign.rad 408 B loc.addr.record.assign.rad 443 B loop.complex.flow.rad 1007 B loop.sealblock.rad 911 B match.array.rad 3.4 KiB match.char.rad 1.6 KiB match.multi.seal.rad 987 B match.multi.survive.rad 1.6 KiB match.mutref.push.rad 1.0 KiB match.mutref.union.rad 662 B match.nested.call.rad 1.7 KiB match.nested.deep.rad 2.2 KiB match.nested.deref.rad 3.7 KiB match.nested.guard.rad 1.6 KiB match.nested.iflet.guard.rad 1.6 KiB match.nested.iflet.rad 1.4 KiB match.nested.letelse.rad 813 B match.nested.letelse.union.rad 1.3 KiB match.nested.literal.rad 3.1 KiB match.nested.multi.rad 2.4 KiB match.nested.pattern.rad 5.2 KiB match.nested.record.rad 2.0 KiB match.nested.union.rad 2.3 KiB match.nested.whilelet.rad 2.4 KiB match.string.rad 1.8 KiB match.value.copy.rad 2.0 KiB match.void.then.or.rad 1.6 KiB memzero.result.bug.rad 806 B memzero.union.bug.rad 576 B mutref.loop.bug.rad 1.8 KiB opt.assignment.bug.rad 1.3 KiB opt.bug.test.rad 1.4 KiB opt.if.let.complex.rad 6.2 KiB opt.if.let.guard.rad 809 B opt.if.let.rad 956 B opt.nil.check.rad 1.5 KiB opt.record.eq.rad 842 B opt.record.rad 655 B opt.return.array.rad 289 B opt.return.nested.rad 797 B opt.return.record.rad 344 B opt.slice.npo.rad 2.8 KiB opt.type.rad 200 B opt.while.let.complex.rad 404 B panic.rad 111 B placeholder.basic.rad 133 B placeholder.comprehensive.rad 562 B pointer.copy.edge.case.rad 1.3 KiB pointer.slice.index.rad 269 B pointer.slice.store.rad 881 B prog.ackermann.rad 5.0 KiB prog.bignum.rad 9.4 KiB prog.binsearch.rad 2.4 KiB prog.bubblesort.rad 2.0 KiB prog.cordic.rad 6.9 KiB prog.crc32.rad 2.7 KiB prog.dijkstra.rad 7.7 KiB prog.eval.rad 6.2 KiB prog.hanoi.rad 3.8 KiB prog.huffman.rad 9.3 KiB prog.hybridsort.rad 3.0 KiB prog.linkedlist.rad 5.8 KiB prog.lzw.rad 6.7 KiB prog.matmul.rad 2.9 KiB prog.mersenne.rad 5.2 KiB prog.nqueens.rad 3.4 KiB prog.rbtree.rad 8.2 KiB prog.regex.rad 10.2 KiB prog.sha256.rad 7.0 KiB prog.sieve.rad 2.8 KiB prog.symtab.rad 10.1 KiB prog.tokenizer.rad 13.8 KiB prog.vm.rad 17.4 KiB ptr.assign.rad 137 B ptr.deref.rad 622 B ptr.eq.rad 966 B ptr.mutate.rad 244 B ptr.opaque.rad 1.4 KiB record.access.rad 285 B record.alignment.rad 179 B record.array.elements.rad 1.7 KiB record.copy.rad 2.0 KiB record.field.assign.rad 184 B record.nested.calls.2.rad 612 B record.nested.calls.3.rad 734 B record.param.lit.rad 353 B record.ptr.access.rad 227 B record.ptr.mutate.rad 243 B record.shorthand.rad 1.5 KiB record.unlabeled.rad 407 B ref.if.bug.rad 519 B ref.immut.loop.bug.rad 670 B ref.mut.ptr.rad 261 B regalloc.callee.save.rad 1.5 KiB regalloc.spill.reuse.rad 473 B reserve.loop.rad 392 B result.void.success.rad 716 B slice.alloc.loop.rad 788 B slice.append.rad 3.3 KiB slice.cap.rad 941 B slice.delete.rad 971 B slice.of.rad 460 B slice.subslice.rad 1.4 KiB spill.blockarg.clobber.rad 3.5 KiB spill.loop.rad 1.6 KiB stack.local.corrupt.rad 320 B static.array.mutate.rad 387 B static.basic.rad 327 B static.fn.array.rad 628 B static.record.array.rad 503 B static.slice.index.assign.rad 408 B static.slice.offset.rad 668 B string.basic.rad 149 B string.escape.rad 349 B string.index.rad 116 B switch.blockargs.clobber.rad 1.3 KiB trait.aggregate.ret.rad 1.5 KiB trait.array.optional.rad 1.7 KiB trait.basic.rad 565 B trait.control.flow.rad 1.1 KiB trait.fn.param.rad 1.6 KiB trait.multiple.methods.rad 1.2 KiB trait.multiple.traits.rad 1.2 KiB trait.multiple.types.rad 1.3 KiB trait.supertrait.rad 2.5 KiB trait.throws.rad 1.0 KiB trait.writer.rad 2.6 KiB type.unify.rad 4.5 KiB undefined.rad 417 B union-tag.rad 911 B union.bitfield.rad 1.2 KiB union.discriminant.cast.rad 389 B union.edge.case.2.rad 679 B union.edge.case.3.rad 608 B union.mixed.assign.rad 977 B union.payload.mutref.rad 1.4 KiB union.payload.rad 580 B union.record.forward.rad 1.3 KiB union.void.match.rad 403 B union.void.rad 824 B unsigned.compare.rad 1.9 KiB var.align.rad 1013 B var.infer.rad 549 B decode.rad 14.6 KiB emit.rad 24.4 KiB encode.rad 19.9 KiB isel.rad 41.1 KiB printer.rad 13.0 KiB tests.rad 15.7 KiB rv64.rad 13.0 KiB collections/ lang/ sys/ arch.rad 65 B collections.rad 36 B fmt.rad 3.8 KiB intrinsics.rad 206 B io.rad 1.2 KiB lang.rad 222 B mem.rad 2.2 KiB sys.rad 167 B testing.rad 2.4 KiB tests.rad 11.6 KiB vec.rad 3.1 KiB std.rad 231 B scripts/ seed/ test/ vim/ .gitignore 353 B .gitsigners 112 B LICENSE 1.1 KiB Makefile 3.1 KiB README 2.5 KiB std.lib 987 B std.lib.test 252 B
lib/std/arch/rv64/tests/prog.tokenizer.rad 13.8 KiB raw
1
//! Tokenizer / lexer.
2
//! A simplified lexer that tokenizes arithmetic expressions into tokens,
3
//! then parses and evaluates them. Exercises: tagged unions with payloads,
4
//! match statements, optionals, if-let, while-let, for-in loops, records
5
//! with slice fields, and complex control flow.
6
7
/// Token types produced by the lexer.
8
union Token {
9
    /// Integer literal with its value.
10
    Number(i32),
11
    /// +
12
    Plus,
13
    /// -
14
    Minus,
15
    /// *
16
    Star,
17
    /// /
18
    Slash,
19
    /// (
20
    LParen,
21
    /// )
22
    RParen,
23
    /// End of input.
24
    Eof,
25
    /// Invalid character.
26
    Invalid(u8),
27
}
28
29
/// A lexer state over a byte slice.
30
record Lexer {
31
    source: *[u8],
32
    pos: u32,
33
}
34
35
/// A list of tokens with a fixed-size backing store.
36
record TokenList {
37
    tokens: *mut [Token],
38
    count: u32,
39
}
40
41
/// AST node for parsed expressions.
42
union Expr {
43
    Num(i32),
44
    BinOp(BinOpData),
45
    Neg(u32),
46
}
47
48
/// Binary operation data.
49
record BinOpData {
50
    op: u8,
51
    left: u32,
52
    right: u32,
53
}
54
55
/// Pool of AST nodes.
56
record ExprPool {
57
    nodes: *mut [Expr],
58
    count: u32,
59
}
60
61
/// Parser state.
62
record Parser {
63
    tokens: *[Token],
64
    tokenCount: u32,
65
    pos: u32,
66
    pool: *mut ExprPool,
67
}
68
69
/// Check if a byte is a digit.
70
fn isDigit(c: u8) -> bool {
71
    return c >= 48 and c <= 57;
72
}
73
74
/// Check if a byte is whitespace.
75
fn isSpace(c: u8) -> bool {
76
    return c == 32 or c == 9 or c == 10 or c == 13;
77
}
78
79
/// Peek at the current character, returning nil at end.
80
fn peek(lex: *Lexer) -> ?u8 {
81
    if lex.pos < lex.source.len {
82
        return lex.source[lex.pos];
83
    }
84
    return nil;
85
}
86
87
/// Advance the lexer by one character.
88
fn advance(lex: *mut Lexer) {
89
    if lex.pos < lex.source.len {
90
        lex.pos += 1;
91
    }
92
}
93
94
/// Skip whitespace characters.
95
fn skipWhitespace(lex: *mut Lexer) {
96
    while let ch = peek(lex); isSpace(ch) {
97
        advance(lex);
98
    }
99
}
100
101
/// Scan a number literal.
102
fn scanNumber(lex: *mut Lexer) -> i32 {
103
    let mut value: i32 = 0;
104
    while let ch = peek(lex); isDigit(ch) {
105
        value = value * 10 + (ch - 48) as i32;
106
        advance(lex);
107
    }
108
    return value;
109
}
110
111
/// Get the next token from the lexer.
112
fn nextToken(lex: *mut Lexer) -> Token {
113
    skipWhitespace(lex);
114
115
    if let ch = peek(lex) {
116
        if isDigit(ch) {
117
            return Token::Number(scanNumber(lex));
118
        }
119
120
        advance(lex);
121
        match ch {
122
            case 43 => { return Token::Plus; }
123
            case 45 => { return Token::Minus; }
124
            case 42 => { return Token::Star; }
125
            case 47 => { return Token::Slash; }
126
            case 40 => { return Token::LParen; }
127
            case 41 => { return Token::RParen; }
128
            else => { return Token::Invalid(ch); }
129
        }
130
    }
131
    return Token::Eof;
132
}
133
134
/// Tokenize the entire source into a token list.
135
fn tokenize(lex: *mut Lexer, list: *mut TokenList) -> bool {
136
    let mut done: bool = false;
137
    while not done {
138
        let tok = nextToken(lex);
139
        match tok {
140
            case Token::Invalid(_) => {
141
                return false;
142
            }
143
            case Token::Eof => {
144
                list.tokens[list.count] = tok;
145
                list.count += 1;
146
                done = true;
147
            }
148
            else => {
149
                if list.count >= list.tokens.len - 1 {
150
                    return false;
151
                }
152
                list.tokens[list.count] = tok;
153
                list.count += 1;
154
            }
155
        }
156
    }
157
    return true;
158
}
159
160
/// Allocate a new expression node.
161
fn newExpr(pool: *mut ExprPool, expr: Expr) -> u32 {
162
    let idx = pool.count;
163
    pool.nodes[idx] = expr;
164
    pool.count += 1;
165
    return idx;
166
}
167
168
/// Get the current token in the parser.
169
fn currentToken(p: *Parser) -> Token {
170
    if p.pos < p.tokenCount {
171
        return p.tokens[p.pos];
172
    }
173
    return Token::Eof;
174
}
175
176
/// Advance the parser to the next token.
177
fn advanceParser(p: *mut Parser) {
178
    if p.pos < p.tokenCount {
179
        p.pos += 1;
180
    }
181
}
182
183
/// Parse a primary expression (number, parenthesized expression, or unary minus).
184
fn parsePrimary(p: *mut Parser) -> ?u32 {
185
    let tok = currentToken(p);
186
187
    match tok {
188
        case Token::Number(n) => {
189
            advanceParser(p);
190
            return newExpr(p.pool, Expr::Num(n));
191
        }
192
        case Token::LParen => {
193
            advanceParser(p);
194
            let inner = parsePrimary(p) else {
195
                return nil;
196
            };
197
            // Actually parse a full expression inside parens.
198
            let expr = parseAddSub(p, inner);
199
            let close = currentToken(p);
200
            match close {
201
                case Token::RParen => {
202
                    advanceParser(p);
203
                    return expr;
204
                }
205
                else => {
206
                    return nil;
207
                }
208
            }
209
        }
210
        case Token::Minus => {
211
            advanceParser(p);
212
            let operand = parsePrimary(p) else {
213
                return nil;
214
            };
215
            return newExpr(p.pool, Expr::Neg(operand));
216
        }
217
        else => {
218
            return nil;
219
        }
220
    }
221
}
222
223
/// Parse multiplication and division (higher precedence).
224
fn parseMulDiv(p: *mut Parser, left: u32) -> u32 {
225
    let mut result: u32 = left;
226
    let mut cont: bool = true;
227
228
    while cont {
229
        let tok = currentToken(p);
230
        match tok {
231
            case Token::Star => {
232
                advanceParser(p);
233
                if let right = parsePrimary(p) {
234
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 42, left: result, right }));
235
                } else {
236
                    cont = false;
237
                }
238
            }
239
            case Token::Slash => {
240
                advanceParser(p);
241
                if let right = parsePrimary(p) {
242
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 47, left: result, right }));
243
                } else {
244
                    cont = false;
245
                }
246
            }
247
            else => {
248
                cont = false;
249
            }
250
        }
251
    }
252
    return result;
253
}
254
255
/// Parse addition and subtraction (lower precedence).
256
fn parseAddSub(p: *mut Parser, left: u32) -> u32 {
257
    let mut result: u32 = parseMulDiv(p, left);
258
    let mut cont: bool = true;
259
260
    while cont {
261
        let tok = currentToken(p);
262
        match tok {
263
            case Token::Plus => {
264
                advanceParser(p);
265
                if let right = parsePrimary(p) {
266
                    let rhs = parseMulDiv(p, right);
267
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 43, left: result, right: rhs }));
268
                } else {
269
                    cont = false;
270
                }
271
            }
272
            case Token::Minus => {
273
                advanceParser(p);
274
                if let right = parsePrimary(p) {
275
                    let rhs = parseMulDiv(p, right);
276
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 45, left: result, right: rhs }));
277
                } else {
278
                    cont = false;
279
                }
280
            }
281
            else => {
282
                cont = false;
283
            }
284
        }
285
    }
286
    return result;
287
}
288
289
/// Parse a full expression.
290
fn parseExpr(p: *mut Parser) -> ?u32 {
291
    let left = parsePrimary(p) else {
292
        return nil;
293
    };
294
    return parseAddSub(p, left);
295
}
296
297
/// Evaluate an expression tree.
298
fn eval(nodes: *[Expr], idx: u32) -> i32 {
299
    let node = nodes[idx];
300
    match node {
301
        case Expr::Num(n) => {
302
            return n;
303
        }
304
        case Expr::BinOp(data) => {
305
            let l = eval(nodes, data.left);
306
            let r = eval(nodes, data.right);
307
            if data.op == 43 {
308
                return l + r;
309
            } else if data.op == 45 {
310
                return l - r;
311
            } else if data.op == 42 {
312
                return l * r;
313
            } else if data.op == 47 {
314
                if r == 0 {
315
                    return 0;
316
                }
317
                return l / r;
318
            }
319
            return 0;
320
        }
321
        case Expr::Neg(child) => {
322
            return 0 - eval(nodes, child);
323
        }
324
    }
325
}
326
327
/// Count nodes in an expression tree.
328
fn countNodes(nodes: *[Expr], idx: u32) -> u32 {
329
    let node = nodes[idx];
330
    match node {
331
        case Expr::Num(_) => { return 1; }
332
        case Expr::BinOp(data) => {
333
            return 1 + countNodes(nodes, data.left) + countNodes(nodes, data.right);
334
        }
335
        case Expr::Neg(child) => {
336
            return 1 + countNodes(nodes, child);
337
        }
338
    }
339
}
340
341
/// Helper: tokenize, parse, and evaluate a string expression.
342
fn evaluate(
343
    source: *[u8],
344
    tokenBuf: *mut [Token],
345
    exprBuf: *mut [Expr]
346
) -> ?i32 {
347
    let mut lex = Lexer { source, pos: 0 };
348
    let mut list = TokenList { tokens: tokenBuf, count: 0 };
349
350
    if not tokenize(&mut lex, &mut list) {
351
        return nil;
352
    }
353
354
    let mut pool = ExprPool { nodes: exprBuf, count: 0 };
355
    let mut parser = Parser {
356
        tokens: tokenBuf,
357
        tokenCount: list.count,
358
        pos: 0,
359
        pool: &mut pool,
360
    };
361
362
    let root = parseExpr(&mut parser) else {
363
        return nil;
364
    };
365
    return eval(exprBuf, root);
366
}
367
368
/// Test simple number.
369
fn testNumber(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
370
    let result = evaluate("42", tokenBuf, exprBuf) else {
371
        return 1;
372
    };
373
    assert result == 42;
374
    return 0;
375
}
376
377
/// Test addition.
378
fn testAdd(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
379
    let result = evaluate("3 + 4", tokenBuf, exprBuf) else {
380
        return 1;
381
    };
382
    assert result == 7;
383
    return 0;
384
}
385
386
/// Test precedence: multiplication before addition.
387
fn testPrecedence(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
388
    let result = evaluate("2 + 3 * 4", tokenBuf, exprBuf) else {
389
        return 1;
390
    };
391
    assert result == 14;
392
    return 0;
393
}
394
395
/// Test parenthesized expression.
396
fn testParens(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
397
    let result = evaluate("(2 + 3) * 4", tokenBuf, exprBuf) else {
398
        return 1;
399
    };
400
    assert result == 20;
401
    return 0;
402
}
403
404
/// Test negation.
405
fn testNeg(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
406
    let result = evaluate("-5 + 8", tokenBuf, exprBuf) else {
407
        return 1;
408
    };
409
    assert result == 3;
410
    return 0;
411
}
412
413
/// Test complex expression.
414
fn testComplex(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
415
    // (10 - 3) * (2 + 1) = 7 * 3 = 21
416
    let result = evaluate("(10 - 3) * (2 + 1)", tokenBuf, exprBuf) else {
417
        return 1;
418
    };
419
    assert result == 21;
420
    return 0;
421
}
422
423
/// Test chained operations.
424
fn testChained(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
425
    // 100 - 20 - 30 - 10 = 40
426
    let result = evaluate("100 - 20 - 30 - 10", tokenBuf, exprBuf) else {
427
        return 1;
428
    };
429
    assert result == 40;
430
    return 0;
431
}
432
433
/// Test token counting via for-in.
434
fn testTokenCount(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
435
    let mut lex = Lexer { source: "1 + 2 * 3", pos: 0 };
436
    let mut list = TokenList { tokens: tokenBuf, count: 0 };
437
    assert tokenize(&mut lex, &mut list);
438
439
    // Should be: 1, +, 2, *, 3, Eof = 6 tokens
440
    assert list.count == 6;
441
442
    // Count number tokens using for-in.
443
    let mut numCount: u32 = 0;
444
    let slice = &tokenBuf[0..list.count];
445
    for tok in slice {
446
        match tok {
447
            case Token::Number(_) => {
448
                numCount += 1;
449
            }
450
            else => {}
451
        }
452
    }
453
    assert numCount == 3;
454
455
    return 0;
456
}
457
458
/// Test division and mixed operations.
459
fn testDivision(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
460
    // 20 / 4 + 3 = 5 + 3 = 8
461
    let result = evaluate("20 / 4 + 3", tokenBuf, exprBuf) else {
462
        return 1;
463
    };
464
    assert result == 8;
465
    return 0;
466
}
467
468
/// Test deeply nested parentheses.
469
fn testDeepNesting(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
470
    // ((((5)))) = 5
471
    let result = evaluate("((((5))))", tokenBuf, exprBuf) else {
472
        return 1;
473
    };
474
    assert result == 5;
475
    return 0;
476
}
477
478
/// Test node count of complex expression.
479
fn testNodeCount(tokenBuf: *mut [Token], exprBuf: *mut [Expr]) -> i32 {
480
    let mut lex = Lexer { source: "1 + 2 * 3", pos: 0 };
481
    let mut list = TokenList { tokens: tokenBuf, count: 0 };
482
    assert tokenize(&mut lex, &mut list);
483
484
    let mut pool = ExprPool { nodes: exprBuf, count: 0 };
485
    let mut parser = Parser {
486
        tokens: tokenBuf,
487
        tokenCount: list.count,
488
        pos: 0,
489
        pool: &mut pool,
490
    };
491
492
    let root = parseExpr(&mut parser) else {
493
        return 2;
494
    };
495
496
    // 1 + (2 * 3) = 5 nodes: Num(1), Num(2), Num(3), BinOp(*), BinOp(+)
497
    let count = countNodes(exprBuf, root);
498
    assert count == 5;
499
    return 0;
500
}
501
502
@default fn main() -> i32 {
503
    let mut tokenBuf: [Token; 128] = [Token::Eof; 128];
504
    let mut exprBuf: [Expr; 128] = [Expr::Num(0); 128];
505
506
    let r1 = testNumber(&mut tokenBuf[..], &mut exprBuf[..]);
507
    if r1 != 0 {
508
        return 10 + r1;
509
    }
510
511
    let r2 = testAdd(&mut tokenBuf[..], &mut exprBuf[..]);
512
    if r2 != 0 {
513
        return 20 + r2;
514
    }
515
516
    let r3 = testPrecedence(&mut tokenBuf[..], &mut exprBuf[..]);
517
    if r3 != 0 {
518
        return 30 + r3;
519
    }
520
521
    let r4 = testParens(&mut tokenBuf[..], &mut exprBuf[..]);
522
    if r4 != 0 {
523
        return 40 + r4;
524
    }
525
526
    let r5 = testNeg(&mut tokenBuf[..], &mut exprBuf[..]);
527
    if r5 != 0 {
528
        return 50 + r5;
529
    }
530
531
    let r6 = testComplex(&mut tokenBuf[..], &mut exprBuf[..]);
532
    if r6 != 0 {
533
        return 60 + r6;
534
    }
535
536
    let r7 = testChained(&mut tokenBuf[..], &mut exprBuf[..]);
537
    if r7 != 0 {
538
        return 70 + r7;
539
    }
540
541
    let r8 = testTokenCount(&mut tokenBuf[..], &mut exprBuf[..]);
542
    if r8 != 0 {
543
        return 80 + r8;
544
    }
545
546
    let r9 = testDivision(&mut tokenBuf[..], &mut exprBuf[..]);
547
    if r9 != 0 {
548
        return 90 + r9;
549
    }
550
551
    let r10 = testDeepNesting(&mut tokenBuf[..], &mut exprBuf[..]);
552
    if r10 != 0 {
553
        return 100 + r10;
554
    }
555
556
    let r11 = testNodeCount(&mut tokenBuf[..], &mut exprBuf[..]);
557
    if r11 != 0 {
558
        return 110 + r11;
559
    }
560
561
    return 0;
562
}