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.symtab.rad 10.1 KiB raw
1
//! Symbol table.
2
//! Implement a multi-scope symbol table with hash-based lookup, scope
3
//! push/pop, and symbol resolution. Exercises: optionals, if-let,
4
//! while-let, let-else, for-in with indexing, records with pointer
5
//! fields, and complex interactions between data structures.
6
7
const MAX_SYMBOLS: u32 = 256;
8
const MAX_SCOPES: u32 = 16;
9
const HASH_SIZE: u32 = 64;
10
const NIL: u32 = 0xFFFFFFFF;
11
12
/// A symbol entry in the table.
13
record Symbol {
14
    /// Name of the symbol (hash for comparison).
15
    nameHash: u32,
16
    /// The value associated with this symbol.
17
    value: i32,
18
    /// Scope depth at which this symbol was defined.
19
    depth: u32,
20
    /// Next symbol in hash chain.
21
    next: u32,
22
    /// Previous symbol with the same name (for shadowing).
23
    shadow: u32,
24
}
25
26
/// A scope boundary marker.
27
record ScopeMarker {
28
    /// Number of symbols when scope was entered.
29
    symbolCount: u32,
30
}
31
32
/// The symbol table.
33
record SymTab {
34
    symbols: *mut [Symbol],
35
    symbolCount: u32,
36
    scopes: *mut [ScopeMarker],
37
    scopeDepth: u32,
38
    buckets: *mut [u32],
39
}
40
41
/// Simple string hash function.
42
fn hashName(name: *[u8]) -> u32 {
43
    let mut h: u32 = 5381;
44
    for ch in name {
45
        h = ((h << 5) + h) + ch as u32;
46
    }
47
    return h;
48
}
49
50
/// Initialize the symbol table.
51
fn init(tab: *mut SymTab) {
52
    tab.symbolCount = 0;
53
    tab.scopeDepth = 0;
54
55
    for i in 0..HASH_SIZE {
56
        tab.buckets[i] = NIL;
57
    }
58
}
59
60
/// Push a new scope.
61
fn pushScope(tab: *mut SymTab) {
62
    tab.scopes[tab.scopeDepth] = ScopeMarker { symbolCount: tab.symbolCount };
63
    tab.scopeDepth += 1;
64
}
65
66
/// Pop the current scope, removing all symbols defined in it.
67
fn popScope(tab: *mut SymTab) {
68
    if tab.scopeDepth == 0 {
69
        return;
70
    }
71
    tab.scopeDepth -= 1;
72
    let marker = tab.scopes[tab.scopeDepth];
73
74
    // Remove symbols added in this scope (in reverse order).
75
    while tab.symbolCount > marker.symbolCount {
76
        tab.symbolCount -= 1;
77
        let sym = tab.symbols[tab.symbolCount];
78
        let bucket = sym.nameHash % HASH_SIZE;
79
80
        // Remove from hash chain.
81
        tab.buckets[bucket] = sym.next;
82
83
        // Restore shadowed symbol if any.
84
        if sym.shadow != NIL {
85
            // The shadowed symbol is still in the symbols array;
86
            // re-link it into the hash chain.
87
            let shadowIdx = sym.shadow;
88
            tab.symbols[shadowIdx].next = tab.buckets[bucket];
89
            tab.buckets[bucket] = shadowIdx;
90
        }
91
    }
92
}
93
94
/// Define a symbol in the current scope.
95
fn define(tab: *mut SymTab, name: *[u8], value: i32) -> u32 {
96
    let h = hashName(name);
97
    let bucket = h % HASH_SIZE;
98
99
    // Check for shadowed symbol with same name.
100
    let mut shadowIdx: u32 = NIL;
101
    let mut cur = tab.buckets[bucket];
102
    while cur != NIL {
103
        if tab.symbols[cur].nameHash == h {
104
            // Found existing symbol with same hash - shadow it.
105
            // Remove it from hash chain first.
106
            shadowIdx = cur;
107
            // Remove the shadowed symbol from the bucket chain.
108
            if tab.buckets[bucket] == cur {
109
                tab.buckets[bucket] = tab.symbols[cur].next;
110
            }
111
            break;
112
        }
113
        cur = tab.symbols[cur].next;
114
    }
115
116
    let idx = tab.symbolCount;
117
    tab.symbols[idx] = Symbol {
118
        nameHash: h,
119
        value,
120
        depth: tab.scopeDepth,
121
        next: tab.buckets[bucket],
122
        shadow: shadowIdx,
123
    };
124
    tab.buckets[bucket] = idx;
125
    tab.symbolCount += 1;
126
    return idx;
127
}
128
129
/// Look up a symbol by name. Returns the value if found.
130
fn lookup(tab: *SymTab, name: *[u8]) -> ?i32 {
131
    let h = hashName(name);
132
    let bucket = h % HASH_SIZE;
133
    let mut cur = tab.buckets[bucket];
134
135
    while cur != NIL {
136
        if tab.symbols[cur].nameHash == h {
137
            return tab.symbols[cur].value;
138
        }
139
        cur = tab.symbols[cur].next;
140
    }
141
    return nil;
142
}
143
144
/// Update a symbol's value. Returns true if the symbol was found.
145
fn update(tab: *mut SymTab, name: *[u8], newValue: i32) -> bool {
146
    let h = hashName(name);
147
    let bucket = h % HASH_SIZE;
148
    let mut cur = tab.buckets[bucket];
149
150
    while cur != NIL {
151
        if tab.symbols[cur].nameHash == h {
152
            tab.symbols[cur].value = newValue;
153
            return true;
154
        }
155
        cur = tab.symbols[cur].next;
156
    }
157
    return false;
158
}
159
160
/// Test basic define and lookup.
161
fn testBasic(tab: *mut SymTab) -> i32 {
162
    init(tab);
163
    pushScope(tab);
164
165
    define(tab, "x", 10);
166
    define(tab, "y", 20);
167
    define(tab, "z", 30);
168
169
    let x = lookup(tab, "x") else {
170
        return 1;
171
    };
172
    assert x == 10;
173
174
    let y = lookup(tab, "y") else {
175
        return 3;
176
    };
177
    assert y == 20;
178
179
    let z = lookup(tab, "z") else {
180
        return 5;
181
    };
182
    assert z == 30;
183
184
    // Lookup nonexistent symbol.
185
    if let val = lookup(tab, "w") {
186
        return 7;
187
    }
188
189
    popScope(tab);
190
    return 0;
191
}
192
193
/// Test scope shadowing.
194
fn testShadowing(tab: *mut SymTab) -> i32 {
195
    init(tab);
196
    pushScope(tab);
197
    define(tab, "x", 1);
198
199
    // Verify outer x.
200
    let x1 = lookup(tab, "x") else {
201
        return 1;
202
    };
203
    assert x1 == 1;
204
205
    // Push inner scope, shadow x.
206
    pushScope(tab);
207
    define(tab, "x", 2);
208
209
    let x2 = lookup(tab, "x") else {
210
        return 3;
211
    };
212
    assert x2 == 2;
213
214
    // Pop inner scope, x should revert.
215
    popScope(tab);
216
217
    let x3 = lookup(tab, "x") else {
218
        return 5;
219
    };
220
    assert x3 == 1;
221
222
    popScope(tab);
223
    return 0;
224
}
225
226
/// Test deep nesting with shadowing.
227
fn testDeepNesting(tab: *mut SymTab) -> i32 {
228
    init(tab);
229
230
    // Define x at each of 8 scope levels.
231
    let mut i: u32 = 0;
232
    while i < 8 {
233
        pushScope(tab);
234
        define(tab, "x", i as i32 * 10);
235
        i += 1;
236
    }
237
238
    // x should be the innermost value.
239
    let x = lookup(tab, "x") else {
240
        return 1;
241
    };
242
    assert x == 70;
243
244
    // Pop scopes one by one and check.
245
    i = 7;
246
    while i > 0 {
247
        popScope(tab);
248
        let val = lookup(tab, "x") else {
249
            return 3;
250
        };
251
        let expected = (i - 1) as i32 * 10;
252
        assert val == expected;
253
        i -= 1;
254
    }
255
256
    popScope(tab);
257
    return 0;
258
}
259
260
/// Test multiple symbols per scope.
261
fn testMultipleSymbols(tab: *mut SymTab) -> i32 {
262
    init(tab);
263
    pushScope(tab);
264
265
    // Define a bunch of symbols.
266
    let names: [*[u8]; 8] = ["a", "bb", "ccc", "dddd", "eeeee", "ff", "ggg", "h"];
267
    let values: [i32; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
268
269
    for name, i in names {
270
        define(tab, name, values[i]);
271
    }
272
273
    // Verify all of them.
274
    let mut sum: i32 = 0;
275
    for name, i in names {
276
        if let val = lookup(tab, name) {
277
            sum += val;
278
        } else {
279
            return 1;
280
        }
281
    }
282
283
    // 1+2+3+4+5+6+7+8 = 36
284
    assert sum == 36;
285
286
    popScope(tab);
287
    return 0;
288
}
289
290
/// Test update functionality.
291
fn testUpdate(tab: *mut SymTab) -> i32 {
292
    init(tab);
293
    pushScope(tab);
294
295
    define(tab, "counter", 0);
296
297
    // Increment counter 10 times.
298
    let mut i: u32 = 0;
299
    while i < 10 {
300
        let cur = lookup(tab, "counter") else {
301
            return 1;
302
        };
303
        assert update(tab, "counter", cur + 1);
304
        i += 1;
305
    }
306
307
    let finalVal = lookup(tab, "counter") else {
308
        return 3;
309
    };
310
    assert finalVal == 10;
311
312
    // Update nonexistent symbol should fail.
313
    if update(tab, "nonexistent", 99) {
314
        return 5;
315
    }
316
317
    popScope(tab);
318
    return 0;
319
}
320
321
/// Test scope isolation: symbols in popped scopes are gone.
322
fn testScopeIsolation(tab: *mut SymTab) -> i32 {
323
    init(tab);
324
325
    pushScope(tab);
326
    define(tab, "outer", 1);
327
328
    pushScope(tab);
329
    define(tab, "inner", 2);
330
331
    // Both visible.
332
    if let val = lookup(tab, "outer") {
333
        assert val == 1;
334
    } else {
335
        return 2;
336
    }
337
    if let val = lookup(tab, "inner") {
338
        assert val == 2;
339
    } else {
340
        return 4;
341
    }
342
343
    popScope(tab);
344
345
    // outer still visible, inner gone.
346
    if let val = lookup(tab, "outer") {
347
        assert val == 1;
348
    } else {
349
        return 6;
350
    }
351
    if let val = lookup(tab, "inner") {
352
        return 7;
353
    }
354
355
    popScope(tab);
356
    return 0;
357
}
358
359
/// Test interleaved defines and lookups across scopes using while-let.
360
fn testInterleaved(tab: *mut SymTab) -> i32 {
361
    init(tab);
362
    pushScope(tab);
363
364
    define(tab, "a", 100);
365
    define(tab, "b", 200);
366
367
    pushScope(tab);
368
    define(tab, "a", 111);
369
    define(tab, "c", 300);
370
371
    // Verify values with expected lookup results.
372
    let queries: [*[u8]; 4] = ["a", "b", "c", "d"];
373
    let expected: [?i32; 4] = [111, 200, 300, nil];
374
    let mut failures: u32 = 0;
375
376
    for name, i in queries {
377
        let result = lookup(tab, name);
378
        if let exp = expected[i] {
379
            // We expect a value.
380
            if let r = result {
381
                if r != exp {
382
                    failures += 1;
383
                }
384
            } else {
385
                failures += 1;
386
            }
387
        } else {
388
            // We expect nil.
389
            if let _ = result {
390
                failures += 1;
391
            }
392
        }
393
    }
394
395
    if failures != 0 {
396
        return failures as i32;
397
    }
398
399
    popScope(tab);
400
    popScope(tab);
401
    return 0;
402
}
403
404
@default fn main() -> i32 {
405
    let mut symbols: [Symbol; 256] = [Symbol { nameHash: 0, value: 0, depth: 0, next: NIL, shadow: NIL }; 256];
406
    let mut scopes: [ScopeMarker; 16] = [ScopeMarker { symbolCount: 0 }; 16];
407
    let mut buckets: [u32; 64] = [NIL; 64];
408
409
    let mut tab = SymTab {
410
        symbols: &mut symbols[..],
411
        symbolCount: 0,
412
        scopes: &mut scopes[..],
413
        scopeDepth: 0,
414
        buckets: &mut buckets[..],
415
    };
416
417
    let r1 = testBasic(&mut tab);
418
    if r1 != 0 {
419
        return 10 + r1;
420
    }
421
422
    let r2 = testShadowing(&mut tab);
423
    if r2 != 0 {
424
        return 20 + r2;
425
    }
426
427
    let r3 = testDeepNesting(&mut tab);
428
    if r3 != 0 {
429
        return 30 + r3;
430
    }
431
432
    let r4 = testMultipleSymbols(&mut tab);
433
    if r4 != 0 {
434
        return 40 + r4;
435
    }
436
437
    let r5 = testUpdate(&mut tab);
438
    if r5 != 0 {
439
        return 50 + r5;
440
    }
441
442
    let r6 = testScopeIsolation(&mut tab);
443
    if r6 != 0 {
444
        return 60 + r6;
445
    }
446
447
    let r7 = testInterleaved(&mut tab);
448
    if r7 != 0 {
449
        return 70 + r7;
450
    }
451
452
    return 0;
453
}