compiler: Initialize lowering cursor and function state

38affd56665df547ab569e2e97f12b007597cd919a40e4b36308a2ed4925fa22
Alexis Sellier committed ago 1 parent b7b60331
lib/std/lang/lower.rad +13 -12
279 279
    /// Next declaration to process.
280 280
    next: u32,
281 281
    /// Whether default functions in this module are program entry points.
282 282
    isRoot: bool,
283 283
    /// Instance whose methods are currently being lowered.
284 -
    instanceState: InstanceCursor,
285 -
    /// Whether the instance cursor contains an active declaration.
286 -
    instanceActive: bool,
284 +
    /// Nil when no instance declaration is active.
285 +
    instanceState: ?InstanceCursor,
287 286
}
288 287
289 288
/// Persistent v-table names and position within an instance declaration.
290 289
export record InstanceCursor: Copy {
291 290
    /// Trait whose method slots define the v-table.
834 833
    set low.currentMod = moduleId;
835 834
    try lowerDecls(low, root, isRoot, functionArena);
836 835
}
837 836
838 837
/// Start lowering the declarations of one module.
839 -
export unsafe fn moduleCursor(root: *ast::Node, isRoot: bool) -> ModuleCursor throws (LowerError) {
838 +
export fn moduleCursor(root: *ast::Node, isRoot: bool) -> ModuleCursor throws (LowerError) {
840 839
    let case ast::NodeValue::Block(block) = root.value else {
841 840
        throw LowerError::ExpectedBlock(root);
842 841
    };
843 -
    return ModuleCursor { declarations: block.statements, next: 0, isRoot, instanceState: undefined, instanceActive: false };
842 +
    return ModuleCursor { declarations: block.statements, next: 0, isRoot, instanceState: nil };
844 843
}
845 844
846 845
/// Lower declarations until one function is ready or the module is complete.
847 846
/// The caller must finish using a function before reclaiming its arena storage.
848 847
export unsafe fn lowerNext 'arena 'phase (
849 848
    low: &mut Lowerer 'arena 'phase,
850 849
    cursor: &mut ModuleCursor,
851 850
    functionArena: &mut alloc::Arena
852 851
) -> ?LoweredFunction throws (LowerError) where 'arena: 'phase {
853 852
    loop {
854 -
        if cursor.instanceActive {
855 -
            if let function = try lowerNextInstance(low, &mut cursor.instanceState, functionArena) {
856 -
                return LoweredFunction { function, role: FnRole::Normal };
853 +
        match &mut cursor.instanceState {
854 +
            case nil => {},
855 +
            state => {
856 +
                if let function = try lowerNextInstance(low, state, functionArena) {
857 +
                    return LoweredFunction { function, role: FnRole::Normal };
858 +
                }
857 859
            }
858 -
            set cursor.instanceActive = false;
859 860
        }
861 +
        set cursor.instanceState = nil;
860 862
        if cursor.next >= cursor.declarations.len {
861 863
            return nil;
862 864
        }
863 865
        let node = cursor.declarations[cursor.next];
864 866
        set cursor.next += 1;
872 874
                try lowerDataDecl(low, node, decl.value, true),
873 875
            case ast::NodeValue::StaticDecl(decl) =>
874 876
                try lowerDataDecl(low, node, decl.value, false),
875 877
            case ast::NodeValue::InstanceDecl { traitName, targetType, methods, .. } => {
876 878
                set cursor.instanceState = try instanceCursor(low, traitName, targetType, methods);
877 -
                set cursor.instanceActive = true;
878 879
            }
879 880
            case ast::NodeValue::MethodDecl { name, receiverName, sig, body, .. } => {
880 881
                if let function = try lowerMethodDecl(
881 882
                    low, node, name, receiverName, sig, body, functionArena
882 883
                ) {
995 996
        labelCounter: 0,
996 997
        dataCounter: 0,
997 998
        regCounter: 0,
998 999
        returnReg: nil,
999 1000
        isLeaf: true,
1000 -
        srcLoc: undefined,
1001 +
        srcLoc: il::SrcLoc { moduleId: 0, offset: 0 },
1001 1002
    };
1002 1003
    if fnLow.low.options.debug {
1003 1004
        let modId = fnLow.low.currentMod else {
1004 1005
            panic "fnLowerer: debug enabled but no current module";
1005 1006
        };
1137 1138
    // Lower each instance method as a regular function.
1138 1139
    // Collect qualified names for the v-table. Empty entries are filled
1139 1140
    // later from inherited supertrait methods.
1140 1141
    return InstanceCursor {
1141 1142
        traitInfo, traitName: traitSym.name, typeName: typeSym.name, methods, next: 0,
1142 -
        methodNames: undefined, methodNameSet: [false; ast::MAX_TRAIT_METHODS],
1143 +
        methodNames: [""; ast::MAX_TRAIT_METHODS], methodNameSet: [false; ast::MAX_TRAIT_METHODS],
1143 1144
    };
1144 1145
}
1145 1146
1146 1147
/// Lower the next concrete method, or finish the instance's v-table.
1147 1148
unsafe fn lowerNextInstance 'arena 'phase (
lib/std/lang/module/tests.rad +18 -0
5 5
use std::lang::ast;
6 6
use std::lang::alloc;
7 7
use std::lang::parser;
8 8
use std::lang::scanner;
9 9
use std::lang::strings;
10 +
use std::lang::lower;
11 +
12 +
/// Empty module for checked lowering cursor construction.
13 +
constant EMPTY_LOWER_MODULE: ast::Node = ast::Node {
14 +
    id: 0, span: ast::Span { offset: 0, length: 0 },
15 +
    value: ast::NodeValue::Block(ast::Block { statements: &[], isUnsafe: false }),
16 +
};
17 +
18 +
/// Module cursors begin without an active instance declaration.
19 +
@test fn testSafeLoweringCursor() throws (testing::TestError) {
20 +
    let cursor = try lower::moduleCursor(&EMPTY_LOWER_MODULE, true) catch {
21 +
        throw testing::TestError::Failed;
22 +
    };
23 +
    try testing::expect(cursor.declarations.len == 0);
24 +
    try testing::expect(cursor.next == 0);
25 +
    try testing::expect(cursor.isRoot);
26 +
    try testing::expect(cursor.instanceState == nil);
27 +
}
10 28
11 29
/// Test arena backing storage.
12 30
static TEST_ARENA: [u8; 16384] = [0; 16384];
13 31
/// Interned string pool.
14 32
unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };