@@ -38,9 +38,12 @@ diagnostics: std.ArrayListUnmanaged(CanDiagnostic),
38
38
// Scope state for tracking variable definitions and nested scopes
39
39
scope_state : ScopeState ,
40
40
41
- /// CIR Statement tags - start at 0
41
+ /// Starting offset for statement tags to avoid collision with AST2.Node.Tag
42
+ /// Calculated at compile time based on actual AST2.Node.Tag values
43
+ const STMT_TAG_START = @typeInfo (AST2 .Node .Tag ).@"enum" .fields .len ;
44
+
42
45
pub const StmtTag = enum (u8 ) {
43
- assign , // immutable assignment
46
+ assign = STMT_TAG_START , // immutable assignment
44
47
init_var , // mutable variable initialization
45
48
reassign , // reassignment to existing var
46
49
type_alias , // type alias definition
@@ -58,14 +61,15 @@ pub const StmtTag = enum(u8) {
58
61
};
59
62
60
63
/// Calculate the starting offset for expression tags
61
- /// We start at 100 to avoid collision with AST2.Node.Tag values (which go up to ~68)
62
- const EXPR_TAG_START = 100 ;
64
+ /// Starts after all statement tags
65
+ const EXPR_TAG_START = STMT_TAG_START + @typeInfo ( StmtTag ).@ "enum" .fields . len ;
63
66
64
67
/// CIR Expression tags - start after statement tags
65
68
pub const ExprTag = enum (u8 ) {
66
69
lookup = EXPR_TAG_START , // First expr tag starts at calculated offset
67
70
neg_lookup ,
68
71
not_lookup ,
72
+ module_access , // Module access like Bool.True (uses binop payload)
69
73
num_literal_i32 ,
70
74
int_literal_i32 ,
71
75
num_literal_big ,
@@ -110,12 +114,13 @@ pub const ExprTag = enum(u8) {
110
114
unary_neg , // Unary negation (e.g., -expr)
111
115
unary_not , // Unary not (e.g., !expr)
112
116
unary_double_dot , // Unary double dot (e.g., ..(expr))
117
+ crash , // Crash expression (e.g., crash "message")
113
118
malformed ,
114
119
};
115
120
116
121
/// Calculate the starting offset for pattern tags
117
- /// We start at 150 (EXPR_TAG_START=100 + ~48 ExprTag values + buffer)
118
- const PATT_TAG_START = 150 ;
122
+ /// Starts after all expression tags
123
+ const PATT_TAG_START = EXPR_TAG_START + @typeInfo ( ExprTag ).@ "enum" .fields . len ;
119
124
120
125
/// CIR Pattern tags - start after expression tags
121
126
pub const PattTag = enum (u8 ) {
@@ -254,8 +259,8 @@ pub const Stmts = struct {
254
259
// Skip index 0 (sentinel node)
255
260
for (tags [1.. ]) | tag | {
256
261
const tag_value = @as (u8 , @intFromEnum (tag ));
257
- // Statement tags are in the range [0 , EXPR_TAG_START)
258
- if (tag_value < EXPR_TAG_START ) {
262
+ // Statement tags are in the range [STMT_TAG_START , EXPR_TAG_START)
263
+ if (tag_value >= STMT_TAG_START and tag_value < EXPR_TAG_START ) {
259
264
count += 1 ;
260
265
}
261
266
}
@@ -404,9 +409,18 @@ pub fn getStmt(self: *const CIR, idx: Stmt.Idx) struct {
404
409
.assign = > .assign ,
405
410
.init_var = > .init_var ,
406
411
.reassign = > .reassign ,
412
+ .type_alias = > .type_alias ,
413
+ .type_anno = > .type_anno ,
414
+ .nominal_type = > .nominal_type ,
415
+ .import = > .import ,
416
+ .match = > .match ,
417
+ .if_without_else = > .if_without_else ,
418
+ .ret = > .ret ,
419
+ .for_loop = > .for_loop ,
420
+ .while_loop = > .while_loop ,
421
+ .crash = > .crash ,
407
422
.expr = > .expr ,
408
423
.malformed = > .malformed ,
409
- else = > .malformed , // Fallback for unexpected tags
410
424
};
411
425
412
426
return .{
@@ -445,6 +459,7 @@ pub fn getExpr(self: *const CIR, idx: Expr.Idx) struct {
445
459
.lookup = > .lookup ,
446
460
.neg_lookup = > .neg_lookup ,
447
461
.not_lookup = > .not_lookup ,
462
+ .module_access = > .module_access ,
448
463
.num_literal_i32 = > .num_literal_i32 ,
449
464
.int_literal_i32 = > .int_literal_i32 ,
450
465
.num_literal_big = > .num_literal_big ,
@@ -489,6 +504,7 @@ pub fn getExpr(self: *const CIR, idx: Expr.Idx) struct {
489
504
.unary_neg = > .unary_neg ,
490
505
.unary_not = > .unary_not ,
491
506
.unary_double_dot = > .unary_double_dot ,
507
+ .crash = > .crash ,
492
508
.malformed = > .malformed ,
493
509
};
494
510
@@ -736,6 +752,7 @@ pub const Expr = struct {
736
752
lookup , // .var_lc (e.g. `foo`)
737
753
neg_lookup , // .neg_lc (e.g. `-foo`)
738
754
not_lookup , // .not_lc (e.g. `!foo`)
755
+ module_access , // .binop_dot with UC.UC (e.g. `Bool.True`)
739
756
record_accessor , // .dot_lc (e.g. `.foo`)
740
757
double_dot_ident , // .double_dot_lc (e.g. `..others`)
741
758
dot_num , // dot followed by number (e.g. `.0`) - this is a tuple accessor
@@ -789,6 +806,7 @@ pub const Expr = struct {
789
806
unary_not , // e.g. `!(foo())` - note that `!foo` is special-cased to .not_lc instead
790
807
unary_neg , // e.g. `-(foo())` - note that `-foo` is special-cased to .neg_lc instead
791
808
unary_double_dot , // e.g. `..(foo())` - note that `..foo` is special-cased to .double_dot_lc instead)
809
+ crash , // e.g. `crash "not implemented"` - crash expression with message
792
810
malformed , // e.g. tokenization or parsing failed (stores a Diagnostic.Tag)
793
811
};
794
812
@@ -894,6 +912,7 @@ pub const Type = struct {
894
912
unary_not , // e.g. `!(foo())` - note that `!foo` is special-cased to .not_lc instead
895
913
unary_neg , // e.g. `-(foo())` - note that `-foo` is special-cased to .neg_lc instead
896
914
unary_double_dot , // e.g. `..(foo())` - note that `..foo` is special-cased to .double_dot_lc instead)
915
+ crash , // e.g. `crash "not implemented"` - crash expression with message
897
916
malformed , // e.g. tokenization or parsing failed (stores a Diagnostic.Tag)
898
917
};
899
918
@@ -1106,7 +1125,7 @@ pub fn canonicalizeExpr(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
1106
1125
},
1107
1126
1108
1127
// Binary operators
1109
- .binop_plus , .binop_minus , .binop_star , .binop_slash , .binop_colon , .binop_equals = > {
1128
+ .binop_plus , .binop_minus , .binop_star , .binop_slash , .binop_double_slash , . binop_colon , .binop_equals = > {
1110
1129
// Get the binop data from AST's node slices
1111
1130
const ast_binop = self .ast .* .node_slices .binOp (node .payload .binop );
1112
1131
@@ -1120,6 +1139,7 @@ pub fn canonicalizeExpr(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
1120
1139
.binop_minus = > .binop_minus ,
1121
1140
.binop_star = > .binop_star ,
1122
1141
.binop_slash = > .binop_slash ,
1142
+ .binop_double_slash = > .binop_double_slash ,
1123
1143
.binop_colon = > .binop_colon ,
1124
1144
.binop_equals = > .binop_equals ,
1125
1145
else = > unreachable ,
@@ -1561,8 +1581,7 @@ pub fn canonicalizeExpr(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
1561
1581
1562
1582
if (lhs_tag == .uc and rhs_tag == .uc ) {
1563
1583
// This is module access like Bool.True
1564
- // Treat it as a lookup for now
1565
- self .mutateToExpr (node_idx , .lookup );
1584
+ self .mutateToExpr (node_idx , .module_access );
1566
1585
try self .ensureTypeVarExists (node_idx );
1567
1586
return asExprIdx (node_idx );
1568
1587
} else {
@@ -1603,22 +1622,26 @@ pub fn canonicalizeExpr(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
1603
1622
1604
1623
// Record spread operator (e.g., ..person in { ..person, age: 31 })
1605
1624
.double_dot_lc = > {
1606
- // This represents a record being spread - treat as a special lookup for now
1607
- self .mutateToExpr (node_idx , .lookup );
1625
+ // This represents a record being spread
1626
+ self .mutateToExpr (node_idx , .unary_double_dot );
1608
1627
try self .ensureTypeVarExists (node_idx );
1609
1628
return asExprIdx (node_idx );
1610
1629
},
1611
1630
1612
1631
// Module/package qualified identifiers (e.g., Module.Type, pkg.Module.Type)
1613
1632
.uc_dot_ucs = > {
1614
1633
// Module-qualified type or tag (e.g., Module.Type or Module.Tag)
1615
- self .mutateToExpr (node_idx , .lookup );
1634
+ // These have nodes payload with multiple identifiers
1635
+ // Keep as apply_tag since they're tag applications
1636
+ self .mutateToExpr (node_idx , .apply_tag );
1616
1637
try self .ensureTypeVarExists (node_idx );
1617
1638
return asExprIdx (node_idx );
1618
1639
},
1619
1640
.lc_dot_ucs = > {
1620
1641
// Package-qualified module access (e.g., pkg.Module.Type)
1621
- self .mutateToExpr (node_idx , .lookup );
1642
+ // These have nodes payload with multiple identifiers
1643
+ // Keep as apply_tag since they're tag applications
1644
+ self .mutateToExpr (node_idx , .apply_tag );
1622
1645
try self .ensureTypeVarExists (node_idx );
1623
1646
return asExprIdx (node_idx );
1624
1647
},
@@ -1838,6 +1861,35 @@ pub fn canonicalizeExpr(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
1838
1861
return asExprIdx (node_idx );
1839
1862
},
1840
1863
1864
+ // Crash expression
1865
+ .crash = > {
1866
+ // Crash takes an expression to print before crashing
1867
+ const nodes_iter = self .ast .* .node_slices .nodes (& node .payload .nodes );
1868
+ var iter = nodes_iter ;
1869
+
1870
+ if (iter .next ()) | expr_node_idx | {
1871
+ // Canonicalize the crash message expression
1872
+ _ = try self .canonicalizeExpr (allocator , expr_node_idx , raw_src , idents );
1873
+ }
1874
+
1875
+ // Mutate to crash expression
1876
+ self .mutateToExpr (node_idx , .crash );
1877
+ try self .ensureTypeVarExists (node_idx );
1878
+ return asExprIdx (node_idx );
1879
+ },
1880
+
1881
+ // Return statement in expression context - shouldn't happen but handle it
1882
+ .ret = > {
1883
+ // Return is a statement, but if we encounter it in expression context,
1884
+ // we'll canonicalize it as a statement first
1885
+ const stmt_idx = try self .canonicalizeStmt (allocator , node_idx , raw_src , idents );
1886
+ // Then treat it as a malformed expression
1887
+ self .mutateToExpr (node_idx , .malformed );
1888
+ try self .ensureTypeVarExists (node_idx );
1889
+ _ = stmt_idx ;
1890
+ return asExprIdx (node_idx );
1891
+ },
1892
+
1841
1893
else = > {
1842
1894
// This should never happen if we've handled all cases
1843
1895
std .log .err ("Unhandled AST node tag in canonicalizeExpr: {}" , .{node .tag });
@@ -2010,7 +2062,7 @@ pub fn canonicalizeStmt(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
2010
2062
2011
2063
// Check if this node has already been canonicalized (mutated)
2012
2064
const tag_value = @as (u8 , @intFromEnum (node .tag ));
2013
- if (tag_value < EXPR_TAG_START ) {
2065
+ if (tag_value >= STMT_TAG_START and tag_value < EXPR_TAG_START ) {
2014
2066
// This node has already been canonicalized as a statement
2015
2067
return asStmtIdx (node_idx );
2016
2068
}
@@ -2117,37 +2169,36 @@ pub fn canonicalizeStmt(self: *CIR, allocator: Allocator, node_idx: AST2.Node.Id
2117
2169
}
2118
2170
},
2119
2171
2120
- // Return statement
2121
- .ret = > {
2122
- // Parse return statement with expression
2123
- // Get the expression from nodes payload
2172
+ // Crash statement
2173
+ .crash = > {
2174
+ // Crash takes an expression to print before crashing
2124
2175
const nodes_iter = self .ast .* .node_slices .nodes (& node .payload .nodes );
2125
2176
var iter = nodes_iter ;
2126
2177
2127
2178
if (iter .next ()) | expr_node_idx | {
2128
- // Canonicalize the return expression
2179
+ // Canonicalize the crash message expression
2129
2180
_ = try self .canonicalizeExpr (allocator , expr_node_idx , raw_src , idents );
2130
2181
}
2131
2182
2132
- // Mutate to return statement
2133
- self .mutateToStmt (node_idx , .ret );
2183
+ // Mutate to crash statement
2184
+ self .mutateToStmt (node_idx , .crash );
2134
2185
return asStmtIdx (node_idx );
2135
2186
},
2136
2187
2137
- // Crash statement
2138
- .crash = > {
2139
- // Parse crash statement with expression
2188
+ // Return statement
2189
+ .ret = > {
2190
+ // Parse return statement with expression
2140
2191
// Get the expression from nodes payload
2141
2192
const nodes_iter = self .ast .* .node_slices .nodes (& node .payload .nodes );
2142
2193
var iter = nodes_iter ;
2143
2194
2144
2195
if (iter .next ()) | expr_node_idx | {
2145
- // Canonicalize the crash expression
2196
+ // Canonicalize the return expression
2146
2197
_ = try self .canonicalizeExpr (allocator , expr_node_idx , raw_src , idents );
2147
2198
}
2148
2199
2149
- // Mutate to crash statement
2150
- self .mutateToStmt (node_idx , .crash );
2200
+ // Mutate to return statement
2201
+ self .mutateToStmt (node_idx , .ret );
2151
2202
return asStmtIdx (node_idx );
2152
2203
},
2153
2204
0 commit comments