@@ -113,14 +113,26 @@ fn warn(c: *Context, scope: *Scope, loc: TokenIndex, comptime format: []const u8
113
113
try scope .appendNode (try ZigTag .warning .create (c .arena , value ));
114
114
}
115
115
116
- fn tokenIndex (c : * Context , node : NodeIndex ) ? TokenIndex {
116
+ fn nodeLoc (c : * Context , node : NodeIndex ) TokenIndex {
117
117
const token_index = c .tree .nodes .items (.loc )[@intFromEnum (node )];
118
118
return switch (token_index ) {
119
- .none = > null ,
119
+ .none = > unreachable ,
120
120
else = > @intFromEnum (token_index ),
121
121
};
122
122
}
123
123
124
+ fn nodeTag (c : * Context , node : NodeIndex ) Tree.Tag {
125
+ return c .tree .nodes .items (.tag )[@intFromEnum (node )];
126
+ }
127
+
128
+ fn nodeType (c : * Context , node : NodeIndex ) Type {
129
+ return c .tree .nodes .items (.ty )[@intFromEnum (node )];
130
+ }
131
+
132
+ fn nodeData (c : * Context , node : NodeIndex ) Tree.Node.Data {
133
+ return c .tree .nodes .items (.data )[@intFromEnum (node )];
134
+ }
135
+
124
136
pub fn translate (
125
137
gpa : mem.Allocator ,
126
138
comp : * aro.Compilation ,
@@ -244,9 +256,7 @@ fn transTopLevelDecls(c: *Context) !void {
244
256
}
245
257
246
258
fn transDecl (c : * Context , scope : * Scope , decl : NodeIndex ) ! void {
247
- const node_tags = c .tree .nodes .items (.tag );
248
- const node_ty = c .tree .nodes .items (.ty );
249
- switch (node_tags [@intFromEnum (decl )]) {
259
+ switch (c .nodeTag (decl )) {
250
260
.typedef = > {
251
261
try c .transTypeDef (scope , decl );
252
262
},
@@ -256,13 +266,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
256
266
.struct_decl ,
257
267
.union_decl ,
258
268
= > {
259
- try c .transRecordDecl (scope , node_ty [ @intFromEnum (decl )] );
269
+ try c .transRecordDecl (scope , c . nodeType (decl ));
260
270
},
261
271
262
272
.enum_decl_two , .enum_decl = > {
263
273
const fields = c .tree .childNodes (decl );
264
- const enum_decl = node_ty [ @intFromEnum (decl )] .canonicalize (.standard ).data .@"enum" ;
265
- try c .transEnumDecl (scope , enum_decl , fields , c .tokenIndex (decl ) orelse 0 );
274
+ const enum_decl = c . nodeType (decl ).canonicalize (.standard ).data .@"enum" ;
275
+ try c .transEnumDecl (scope , enum_decl , fields , c .nodeLoc (decl ));
266
276
},
267
277
268
278
.enum_field_decl ,
@@ -302,18 +312,18 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
302
312
}
303
313
304
314
fn transTypeDef (c : * Context , scope : * Scope , typedef_decl : NodeIndex ) Error ! void {
305
- const ty = c .tree . nodes . items ( .ty )[ @intFromEnum ( typedef_decl )] ;
306
- const data = c .tree . nodes . items ( .data )[ @intFromEnum ( typedef_decl )] ;
315
+ const ty = c .nodeType ( typedef_decl );
316
+ const decl = c .nodeData ( typedef_decl ). decl ;
307
317
308
318
const toplevel = scope .id == .root ;
309
319
const bs : * Scope.Block = if (! toplevel ) try scope .findBlockScope (c ) else undefined ;
310
320
311
- var name : []const u8 = c .tree .tokSlice (data . decl .name );
321
+ var name : []const u8 = c .tree .tokSlice (decl .name );
312
322
try c .typedefs .put (c .gpa , name , {});
313
323
314
324
if (! toplevel ) name = try bs .makeMangledName (name );
315
325
316
- const typedef_loc = data . decl .name ;
326
+ const typedef_loc = decl .name ;
317
327
const init_node = c .transType (scope , ty , .standard , typedef_loc ) catch | err | switch (err ) {
318
328
error .UnsupportedType = > {
319
329
return c .failDecl (typedef_loc , name , "unable to resolve typedef child type" , .{});
@@ -495,25 +505,25 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void {
495
505
}
496
506
}
497
507
498
- fn transFnDecl (c : * Context , fn_decl : NodeIndex , is_pub : bool ) Error ! void {
499
- const raw_ty = c .tree . nodes . items ( .ty )[ @intFromEnum ( fn_decl )] ;
508
+ fn transFnDecl (c : * Context , fn_decl_node : NodeIndex , is_pub : bool ) Error ! void {
509
+ const raw_ty = c .nodeType ( fn_decl_node ) ;
500
510
const fn_ty = raw_ty .canonicalize (.standard );
501
- const node_data = c .tree . nodes . items ( .data )[ @intFromEnum ( fn_decl )] ;
511
+ const decl = c .nodeData ( fn_decl_node ). decl ;
502
512
if (c .decl_table .get (@intFromPtr (fn_ty .data .func ))) | _ |
503
513
return ; // Avoid processing this decl twice
504
514
505
- const fn_name = c .tree .tokSlice (node_data . decl .name );
515
+ const fn_name = c .tree .tokSlice (decl .name );
506
516
if (c .global_scope .sym_table .contains (fn_name ))
507
517
return ; // Avoid processing this decl twice
508
518
509
- const fn_decl_loc = 0 ; // TODO
510
- const has_body = node_data . decl .node != .none ;
519
+ const fn_decl_loc = c . nodeLoc ( fn_decl_node );
520
+ const has_body = decl .node != .none ;
511
521
const is_always_inline = has_body and raw_ty .getAttribute (.always_inline ) != null ;
512
522
const proto_ctx = FnProtoContext {
513
523
.fn_name = fn_name ,
514
524
.is_inline = is_always_inline ,
515
525
.is_extern = ! has_body ,
516
- .is_export = switch (c .tree . nodes . items ( .tag )[ @intFromEnum ( fn_decl )] ) {
526
+ .is_export = switch (c .nodeTag ( fn_decl_node ) ) {
517
527
.fn_proto , .fn_def = > has_body and ! is_always_inline ,
518
528
519
529
.inline_fn_proto , .inline_fn_def , .inline_static_fn_proto , .inline_static_fn_def , .static_fn_proto , .static_fn_def = > false ,
@@ -536,7 +546,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
536
546
const proto_payload = proto_node .castTag (.func ).? ;
537
547
538
548
// actual function definition with body
539
- const body_stmt = node_data . decl .node ;
549
+ const body_stmt = decl .node ;
540
550
var block_scope = try Scope .Block .init (c , & c .global_scope .base , false );
541
551
block_scope .return_type = fn_ty .data .func .return_type ;
542
552
defer block_scope .deinit ();
@@ -590,9 +600,9 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
590
600
}
591
601
592
602
fn transVarDecl (c : * Context , node : NodeIndex ) Error ! void {
593
- const data = c .tree . nodes . items ( .data )[ @intFromEnum ( node )] ;
594
- const name = c .tree .tokSlice (data . decl .name );
595
- return c .failDecl (data . decl .name , name , "unable to translate variable declaration" , .{});
603
+ const decl = c .nodeData ( node ). decl ;
604
+ const name = c .tree .tokSlice (decl .name );
605
+ return c .failDecl (decl .name , name , "unable to translate variable declaration" , .{});
596
606
}
597
607
598
608
fn transEnumDecl (c : * Context , scope : * Scope , enum_decl : * const Type.Enum , field_nodes : []const NodeIndex , source_loc : ? TokenIndex ) Error ! void {
@@ -678,20 +688,20 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_
678
688
}
679
689
680
690
fn transStaticAssert (c : * Context , scope : * Scope , static_assert_node : NodeIndex ) Error ! void {
681
- const node_data = c .tree . nodes . items ( .data )[ @intFromEnum ( static_assert_node )] ;
691
+ const node_data = c .nodeData ( static_assert_node ). bin ;
682
692
683
- const condition = c .transExpr (scope , node_data .bin . lhs , .used ) catch | err | switch (err ) {
693
+ const condition = c .transExpr (scope , node_data .lhs , .used ) catch | err | switch (err ) {
684
694
error .UnsupportedTranslation , error .UnsupportedType = > {
685
- return try c .warn (& c .global_scope .base , c .tokenIndex (node_data .bin . lhs ).? , "unable to translate _Static_assert condition" , .{});
695
+ return try c .warn (& c .global_scope .base , c .nodeLoc (node_data .lhs ), "unable to translate _Static_assert condition" , .{});
686
696
},
687
697
error .OutOfMemory = > | e | return e ,
688
698
};
689
699
690
700
// generate @compileError message that matches C compiler output
691
- const diagnostic = if (node_data .bin . rhs != .none ) str : {
701
+ const diagnostic = if (node_data .rhs != .none ) str : {
692
702
// Aro guarantees this to be a string literal.
693
- const str_val = c .tree .value_map .get (node_data .bin . rhs ).? ;
694
- const str_ty = c .tree . nodes . items ( .ty )[ @intFromEnum ( node_data .bin . rhs )] ;
703
+ const str_val = c .tree .value_map .get (node_data .rhs ).? ;
704
+ const str_ty = c .nodeType ( node_data .rhs );
695
705
696
706
const bytes = c .comp .interner .get (str_val .ref ()).bytes ;
697
707
var buf = std .ArrayList (u8 ).init (c .gpa );
@@ -1094,7 +1104,7 @@ fn isFunctionDeclRef(c: *Context, base_node: NodeIndex) bool {
1094
1104
node = node_data [@intFromEnum (node )].un ;
1095
1105
},
1096
1106
.decl_ref_expr = > {
1097
- const res_ty = c .tree . nodes . items ( .ty )[ @intFromEnum ( node )] ;
1107
+ const res_ty = c .nodeType ( node );
1098
1108
return res_ty .isFunc ();
1099
1109
},
1100
1110
.implicit_cast = > {
@@ -1116,14 +1126,22 @@ fn isFunctionDeclRef(c: *Context, base_node: NodeIndex) bool {
1116
1126
else = > return false ,
1117
1127
};
1118
1128
}
1129
+ fn typeHasWrappingOverflow (c : * Context , ty : Type ) bool {
1130
+ if (ty .isUnsignedInt (c .comp )) {
1131
+ // unsigned integer overflow wraps around.
1132
+ return true ;
1133
+ } else {
1134
+ // float, signed integer, and pointer overflow is undefined behavior.
1135
+ return false ;
1136
+ }
1137
+ }
1119
1138
1120
1139
// =====================
1121
1140
// Statement translation
1122
1141
// =====================
1123
1142
1124
1143
fn transStmt (c : * Context , scope : * Scope , stmt : NodeIndex ) TransError ! ZigNode {
1125
- const node_tags = c .tree .nodes .items (.tag );
1126
- switch (node_tags [@intFromEnum (stmt )]) {
1144
+ switch (c .nodeTag (stmt )) {
1127
1145
.compound_stmt , .compound_stmt_two = > {
1128
1146
return c .transCompoundStmt (scope , stmt );
1129
1147
},
@@ -1133,7 +1151,7 @@ fn transStmt(c: *Context, scope: *Scope, stmt: NodeIndex) TransError!ZigNode {
1133
1151
},
1134
1152
.return_stmt = > return c .transReturnStmt (scope , stmt ),
1135
1153
.null_stmt = > return ZigTag .empty_block .init (),
1136
- else = > return c .fail (error .UnsupportedTranslation , c .tokenIndex (stmt ).? , "TODO implement translation of stmt {s}" , .{@tagName (node_tags [ @intFromEnum ( stmt )] )}),
1154
+ else = > | tag | return c .fail (error .UnsupportedTranslation , c .nodeLoc (stmt ), "TODO implement translation of stmt {s}" , .{@tagName (tag )}),
1137
1155
}
1138
1156
}
1139
1157
@@ -1156,10 +1174,10 @@ fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError
1156
1174
}
1157
1175
1158
1176
fn transReturnStmt (c : * Context , scope : * Scope , return_stmt : NodeIndex ) TransError ! ZigNode {
1159
- const data = c .tree . nodes . items ( .data )[ @intFromEnum ( return_stmt )] ;
1160
- if (data . un == .none ) return ZigTag .return_void .init ();
1177
+ const operand = c .nodeData ( return_stmt ). un ;
1178
+ if (operand == .none ) return ZigTag .return_void .init ();
1161
1179
1162
- var rhs = try c .transExprCoercing (scope , data . un );
1180
+ var rhs = try c .transExprCoercing (scope , operand );
1163
1181
const return_ty = scope .findBlockReturnType ();
1164
1182
if (rhs .isBoolRes () and ! return_ty .is (.bool )) {
1165
1183
rhs = try ZigTag .int_from_bool .create (c .arena , rhs );
@@ -1171,10 +1189,10 @@ fn transReturnStmt(c: *Context, scope: *Scope, return_stmt: NodeIndex) TransErro
1171
1189
// Expression translation
1172
1190
// ======================
1173
1191
1174
- fn transExpr (c : * Context , scope : * Scope , node : NodeIndex , used : ResultUsed ) TransError ! ZigNode {
1175
- std .debug .assert (node != .none );
1176
- const ty = c .tree . nodes . items ( .ty )[ @intFromEnum ( node )] ;
1177
- if (c .tree .value_map .get (node )) | val | {
1192
+ fn transExpr (c : * Context , scope : * Scope , expr : NodeIndex , used : ResultUsed ) TransError ! ZigNode {
1193
+ std .debug .assert (expr != .none );
1194
+ const ty = c .nodeType ( expr ) ;
1195
+ if (c .tree .value_map .get (expr )) | val | {
1178
1196
// TODO handle other values
1179
1197
const int = try c .transCreateNodeInt (val );
1180
1198
const as_node = try ZigTag .as .create (c .arena , .{
@@ -1183,10 +1201,52 @@ fn transExpr(c: *Context, scope: *Scope, node: NodeIndex, used: ResultUsed) Tran
1183
1201
});
1184
1202
return c .maybeSuppressResult (used , as_node );
1185
1203
}
1186
- const node_tags = c .tree .nodes .items (.tag );
1187
- switch (node_tags [@intFromEnum (node )]) {
1188
- .explicit_cast , .implicit_cast = > return c .transCastExpr (scope , node , used ),
1189
- .decl_ref_expr = > return c .transDeclRefExpr (scope , node ),
1204
+ switch (c .nodeTag (expr )) {
1205
+ .explicit_cast , .implicit_cast = > return c .transCastExpr (scope , expr , used ),
1206
+ .decl_ref_expr = > return c .transDeclRefExpr (scope , expr ),
1207
+ .addr_of_expr = > {
1208
+ const operand = c .nodeData (expr ).un ;
1209
+ const res = try ZigTag .address_of .create (c .arena , try c .transExpr (scope , operand , .used ));
1210
+ return c .maybeSuppressResult (used , res );
1211
+ },
1212
+ .deref_expr = > {
1213
+ if (c .typeWasDemotedToOpaque (ty ))
1214
+ return fail (c , error .UnsupportedTranslation , c .nodeLoc (expr ), "cannot dereference opaque type" , .{});
1215
+
1216
+ const operand = c .nodeData (expr ).un ;
1217
+ // Dereferencing a function pointer is a no-op.
1218
+ if (ty .isFunc ()) return try c .transExpr (scope , operand , used );
1219
+
1220
+ const res = try ZigTag .deref .create (c .arena , try c .transExpr (scope , operand , .used ));
1221
+ return c .maybeSuppressResult (used , res );
1222
+ },
1223
+ .bool_not_expr = > {
1224
+ const operand = c .nodeData (expr ).un ;
1225
+ const res = try ZigTag .not .create (c .arena , try c .transBoolExpr (scope , operand , .used ));
1226
+ return c .maybeSuppressResult (used , res );
1227
+ },
1228
+ .bit_not_expr = > {
1229
+ const operand = c .nodeData (expr ).un ;
1230
+ const res = try ZigTag .bit_not .create (c .arena , try c .transExpr (scope , operand , .used ));
1231
+ return c .maybeSuppressResult (used , res );
1232
+ },
1233
+ .negate_expr = > {
1234
+ const operand = c .nodeData (expr ).un ;
1235
+ const operand_ty = c .nodeType (expr );
1236
+ if (! c .typeHasWrappingOverflow (operand_ty )) {
1237
+ const sub_expr_node = try c .transExpr (scope , operand , .used );
1238
+ const to_negate = if (sub_expr_node .isBoolRes ()) blk : {
1239
+ const ty_node = try ZigTag .type .create (c .arena , "c_int" );
1240
+ const int_node = try ZigTag .int_from_bool .create (c .arena , sub_expr_node );
1241
+ break :blk try ZigTag .as .create (c .arena , .{ .lhs = ty_node , .rhs = int_node });
1242
+ } else sub_expr_node ;
1243
+
1244
+ return ZigTag .negate .create (c .arena , to_negate );
1245
+ } else if (operand_ty .isUnsignedInt (c .comp )) {
1246
+ // use -% x for unsigned integers
1247
+ return ZigTag .negate_wrap .create (c .arena , try c .transExpr (scope , operand , .used ));
1248
+ } else return fail (c , error .UnsupportedTranslation , c .nodeLoc (expr ), "C negation with non float non integer" , .{});
1249
+ },
1190
1250
else = > unreachable , // Not an expression.
1191
1251
}
1192
1252
}
@@ -1198,19 +1258,67 @@ fn transExprCoercing(c: *Context, scope: *Scope, expr: NodeIndex) TransError!Zig
1198
1258
return c .transExpr (scope , expr , .used );
1199
1259
}
1200
1260
1261
+ fn transBoolExpr (c : * Context , scope : * Scope , expr : NodeIndex , used : ResultUsed ) TransError ! ZigNode {
1262
+ const expr_tag = c .nodeTag (expr );
1263
+ if (expr_tag == .int_literal ) {
1264
+ const int_val = c .tree .value_map .get (expr ).? ;
1265
+ return if (int_val .isZero (c .comp ))
1266
+ ZigTag .false_literal .init ()
1267
+ else
1268
+ ZigTag .true_literal .init ();
1269
+ }
1270
+ if (expr_tag == .implicit_cast ) {
1271
+ const cast = c .nodeData (expr ).cast ;
1272
+ if (cast .kind == .bool_to_int ) {
1273
+ const bool_res = try c .transExpr (scope , cast .operand , .used );
1274
+ return c .maybeSuppressResult (used , bool_res );
1275
+ }
1276
+ }
1277
+
1278
+ const maybe_bool_res = try c .transExpr (scope , expr , .used );
1279
+ if (maybe_bool_res .isBoolRes ()) {
1280
+ return c .maybeSuppressResult (used , maybe_bool_res );
1281
+ }
1282
+
1283
+ const ty = c .nodeType (expr );
1284
+ const res = try c .finishBoolExpr (ty , maybe_bool_res );
1285
+ return c .maybeSuppressResult (used , res );
1286
+ }
1287
+
1288
+ fn finishBoolExpr (c : * Context , ty : Type , node : ZigNode ) TransError ! ZigNode {
1289
+ if (ty .is (.nullptr_t )) {
1290
+ // node == null, always true
1291
+ return ZigTag .equal .create (c .arena , .{ .lhs = node , .rhs = ZigTag .null_literal .init () });
1292
+ }
1293
+ if (ty .isPtr ()) {
1294
+ if (node .tag () == .string_literal ) {
1295
+ // @intFromPtr(node) != 0, always true
1296
+ const int_from_ptr = try ZigTag .int_from_ptr .create (c .arena , node );
1297
+ return ZigTag .not_equal .create (c .arena , .{ .lhs = int_from_ptr , .rhs = ZigTag .zero_literal .init () });
1298
+ }
1299
+ // node != null
1300
+ return ZigTag .not_equal .create (c .arena , .{ .lhs = node , .rhs = ZigTag .null_literal .init () });
1301
+ }
1302
+ if (ty .isScalar ()) {
1303
+ // node != 0
1304
+ return ZigTag .not_equal .create (c .arena , .{ .lhs = node , .rhs = ZigTag .zero_literal .init () });
1305
+ }
1306
+ unreachable ; // Unexpected bool expression type
1307
+ }
1308
+
1201
1309
fn transCastExpr (c : * Context , scope : * Scope , cast_node : NodeIndex , used : ResultUsed ) TransError ! ZigNode {
1202
- const cast = c .tree . nodes . items ( .data )[ @intFromEnum ( cast_node )] .cast ;
1310
+ const cast = c .nodeData ( cast_node ).cast ;
1203
1311
switch (cast .kind ) {
1204
1312
.lval_to_rval , .no_op , .function_to_pointer = > {
1205
1313
const sub_expr_node = try c .transExpr (scope , cast .operand , .used );
1206
1314
return c .maybeSuppressResult (used , sub_expr_node );
1207
1315
},
1208
- else = > return c .fail (error .UnsupportedTranslation , c .tokenIndex (cast_node ).? , "TODO translate {s} cast" , .{@tagName (cast .kind )}),
1316
+ else = > return c .fail (error .UnsupportedTranslation , c .nodeLoc (cast_node ), "TODO translate {s} cast" , .{@tagName (cast .kind )}),
1209
1317
}
1210
1318
}
1211
1319
1212
1320
fn transDeclRefExpr (c : * Context , scope : * Scope , decl_ref_node : NodeIndex ) TransError ! ZigNode {
1213
- const decl_ref = c .tree . nodes . items ( .data )[ @intFromEnum ( decl_ref_node )] .decl_ref ;
1321
+ const decl_ref = c .nodeData ( decl_ref_node ).decl_ref ;
1214
1322
1215
1323
const name = c .tree .tokSlice (decl_ref );
1216
1324
const mangled_name = scope .getAlias (name );
0 commit comments