compiler: Initialize lowering cursor and function state
38affd56665df547ab569e2e97f12b007597cd919a40e4b36308a2ed4925fa22
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 }; |