| ... | ... | @@ -305,54 +305,83 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 305 | 305 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 306 | 306 | if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice |
| 307 | 307 | const rp = makeRestorePoint(c); |
| 308 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 309 | |
| 310 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) |
| 311 | null |
| 312 | else |
| 313 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); |
| 314 | |
| 308 | 315 | var scope = &c.global_scope.base; |
| 309 | 316 | const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); |
| 310 | 317 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); |
| 311 | 318 | |
| 312 | | switch (ZigClangVarDecl_getTLSKind(var_decl)) { |
| 313 | | .None => {}, |
| 314 | | .Static => return failDecl(c, var_decl_loc, var_name, "static thread local storage not supported", .{}), |
| 315 | | .Dynamic => return failDecl(c, var_decl_loc, var_name, "dynamic thread local storag not supported", .{}), |
| 316 | | } |
| 317 | | |
| 318 | | const qual_type = ZigClangVarDecl_getType(var_decl); |
| 319 | | const is_extern = ZigClangVarDecl_hasExternalStorage(var_decl); |
| 320 | | const is_static = ZigClangVarDecl_isFileVarDecl(var_decl); |
| 319 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 320 | const storage_class = ZigClangVarDecl_getStorageClass(var_decl); |
| 321 | 321 | const is_const = ZigClangQualType_isConstQualified(qual_type); |
| 322 | 322 | |
| 323 | | var var_node = try transCreateNodeVarDecl(c, true, is_extern, is_const, var_name); |
| 323 | const extern_tok = if (storage_class == .Extern) |
| 324 | try appendToken(c, .Keyword_extern, "extern") |
| 325 | else if (storage_class != .Static) |
| 326 | try appendToken(c, .Keyword_export, "export") |
| 327 | else |
| 328 | null; |
| 329 | |
| 330 | const mut_tok = if (is_const) |
| 331 | try appendToken(c, .Keyword_const, "const") |
| 332 | else |
| 333 | try appendToken(c, .Keyword_var, "var"); |
| 324 | 334 | |
| 325 | | _ = try appendToken(rp.c, .Colon, ":"); |
| 326 | | var_node.type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { |
| 335 | const name_tok = try appendToken(c, .Identifier, var_name); |
| 336 | |
| 337 | _ = try appendToken(c, .Colon, ":"); |
| 338 | const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { |
| 327 | 339 | error.UnsupportedType => { |
| 328 | 340 | return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{}); |
| 329 | 341 | }, |
| 330 | 342 | error.OutOfMemory => |e| return e, |
| 331 | 343 | }; |
| 332 | 344 | |
| 333 | | if (is_static and !is_extern) { |
| 334 | | const eq_tok = try appendToken(c, .Equal, "="); |
| 335 | | const init_node = if (ZigClangVarDecl_hasInit(var_decl)) blk: { |
| 336 | | const ap_value = ZigClangVarDecl_evaluateValue(var_decl) orelse |
| 337 | | return failDecl(c, var_decl_loc, var_name, "unable to evaluate initializer", .{}); |
| 338 | | break :blk transApValue(rp, ap_value, qual_type, var_decl_loc) catch |err| switch (err) { |
| 345 | var eq_tok: ast.TokenIndex = undefined; |
| 346 | var init_node: ?*ast.Node = null; |
| 347 | |
| 348 | if (ZigClangVarDecl_hasInit(var_decl)) { |
| 349 | eq_tok = try appendToken(c, .Equal, "="); |
| 350 | init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| blk: { |
| 351 | var res = transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { |
| 339 | 352 | error.UnsupportedTranslation, |
| 340 | 353 | error.UnsupportedType, |
| 341 | 354 | => { |
| 342 | | return failDecl(c, var_decl_loc, var_name, "unable to evaluate initializer", .{}); |
| 355 | return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{}); |
| 343 | 356 | }, |
| 344 | 357 | error.OutOfMemory => |e| return e, |
| 345 | 358 | }; |
| 359 | break :blk res.node; |
| 346 | 360 | } else |
| 347 | 361 | try transCreateNodeUndefinedLiteral(c); |
| 348 | | var_node.eq_token = eq_tok; |
| 349 | | var_node.init_node = init_node; |
| 350 | | } else if (!is_extern) { |
| 351 | | return failDecl(c, var_decl_loc, var_name, "non-extern, non-static variable not supported", .{}); |
| 362 | } else if (storage_class != .Extern) { |
| 363 | return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{}); |
| 352 | 364 | } |
| 353 | 365 | |
| 354 | | var_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 355 | | return addTopLevelDecl(c, var_name, &var_node.base); |
| 366 | const node = try c.a().create(ast.Node.VarDecl); |
| 367 | node.* = ast.Node.VarDecl{ |
| 368 | .base = ast.Node{ .id = .VarDecl }, |
| 369 | .doc_comments = null, |
| 370 | .visib_token = visib_tok, |
| 371 | .thread_local_token = thread_local_token, |
| 372 | .name_token = name_tok, |
| 373 | .eq_token = eq_tok, |
| 374 | .mut_token = mut_tok, |
| 375 | .comptime_token = null, |
| 376 | .extern_export_token = extern_tok, |
| 377 | .lib_name = null, |
| 378 | .type_node = type_node, |
| 379 | .align_node = null, |
| 380 | .section_node = null, |
| 381 | .init_node = init_node, |
| 382 | .semicolon_token = try appendToken(c, .Semicolon, ";"), |
| 383 | }; |
| 384 | return addTopLevelDecl(c, var_name, &node.base); |
| 356 | 385 | } |
| 357 | 386 | |
| 358 | 387 | const ResultUsed = enum { |
| ... | ... | @@ -384,6 +413,7 @@ fn transStmt( |
| 384 | 413 | .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), |
| 385 | 414 | .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), |
| 386 | 415 | .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue), |
| 416 | .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), |
| 387 | 417 | else => { |
| 388 | 418 | return revertAndWarn( |
| 389 | 419 | rp, |
| ... | ... | @@ -635,7 +665,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe |
| 635 | 665 | const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| |
| 636 | 666 | (try transExpr(rp, scope, expr, .used, .r_value)).node |
| 637 | 667 | else |
| 638 | | try transCreateNodeUndefinedLiteral(rp.c); |
| 668 | try transCreateNodeUndefinedLiteral(c); |
| 639 | 669 | const semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 640 | 670 | |
| 641 | 671 | const node = try c.a().create(ast.Node.VarDecl); |
| ... | ... | @@ -725,7 +755,7 @@ fn transImplicitCastExpr( |
| 725 | 755 | .FunctionToPointerDecay, .ArrayToPointerDecay => { |
| 726 | 756 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 727 | 757 | }, |
| 728 | | .LValueToRValue => { |
| 758 | .LValueToRValue, .NoOp => { |
| 729 | 759 | return transExpr(rp, scope, sub_expr, .used, .r_value); |
| 730 | 760 | }, |
| 731 | 761 | else => |kind| return revertAndWarn( |
| ... | ... | @@ -906,6 +936,88 @@ fn transExpr( |
| 906 | 936 | return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue); |
| 907 | 937 | } |
| 908 | 938 | |
| 939 | fn transInitListExpr( |
| 940 | rp: RestorePoint, |
| 941 | scope: *Scope, |
| 942 | expr: *const ZigClangInitListExpr, |
| 943 | used: ResultUsed, |
| 944 | ) TransError!TransResult { |
| 945 | // TODO use anon literals once they work properly |
| 946 | const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr)); |
| 947 | const qual_type = ZigClangQualType_getTypePtr(qt); |
| 948 | const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr)); |
| 949 | const arr_type = ZigClangType_getAsArrayTypeUnsafe(qual_type); |
| 950 | const child_qt = ZigClangArrayType_getElementType(arr_type); |
| 951 | const init_count = ZigClangInitListExpr_getNumInits(expr); |
| 952 | const all_count = 200; //ZigClangArrayType_getSize(arr_type); |
| 953 | const leftover_count = all_count - init_count; |
| 954 | |
| 955 | var init_node: *ast.Node.SuffixOp = undefined; |
| 956 | var cat_tok: ast.TokenIndex = undefined; |
| 957 | if (init_count != 0) { |
| 958 | var type_node = try transQualType(rp, qt, source_loc); |
| 959 | init_node = try transCreateNodeArrayInitializer(rp.c, type_node); |
| 960 | var i: c_uint = 0; |
| 961 | while (i < init_count) : (i += 1) { |
| 962 | const elem_expr = ZigClangInitListExpr_getInit(expr, i); |
| 963 | try init_node.op.ArrayInitializer.push((try transExpr(rp, scope, elem_expr, .used, .r_value)).node); |
| 964 | _ = try appendToken(rp.c, .Comma, ","); |
| 965 | } |
| 966 | init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| 967 | if (leftover_count == 0) { |
| 968 | return TransResult{ |
| 969 | .node = &init_node.base, |
| 970 | .child_scope = scope, |
| 971 | .node_scope = scope, |
| 972 | }; |
| 973 | } |
| 974 | cat_tok = try appendToken(rp.c, .PlusPlus, "++"); |
| 975 | } |
| 976 | |
| 977 | var filler_type_node = try transQualType(rp, qt, source_loc); |
| 978 | var filler_init_node = try transCreateNodeArrayInitializer(rp.c, filler_type_node); |
| 979 | const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); |
| 980 | try filler_init_node.op.ArrayInitializer.push((try transExpr(rp, scope, filler_val_expr, .used, .r_value)).node); |
| 981 | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| 982 | |
| 983 | const rhs_node = if (leftover_count == 1) |
| 984 | &filler_init_node.base |
| 985 | else blk: { |
| 986 | const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**"); |
| 987 | const mul_node = try rp.c.a().create(ast.Node.InfixOp); |
| 988 | mul_node.* = .{ |
| 989 | .base = .{ .id = .InfixOp }, |
| 990 | .op_token = mul_tok, |
| 991 | .lhs = &filler_init_node.base, |
| 992 | .op = .ArrayMult, |
| 993 | .rhs = try transCreateNodeInt(rp.c, leftover_count), |
| 994 | }; |
| 995 | break :blk &mul_node.base; |
| 996 | }; |
| 997 | |
| 998 | if (init_count == 0) { |
| 999 | return TransResult{ |
| 1000 | .node = rhs_node, |
| 1001 | .child_scope = scope, |
| 1002 | .node_scope = scope, |
| 1003 | }; |
| 1004 | } |
| 1005 | |
| 1006 | const cat_node = try rp.c.a().create(ast.Node.InfixOp); |
| 1007 | cat_node.* = .{ |
| 1008 | .base = .{ .id = .InfixOp }, |
| 1009 | .op_token = cat_tok, |
| 1010 | .lhs = &init_node.base, |
| 1011 | .op = .ArrayCat, |
| 1012 | .rhs = rhs_node, |
| 1013 | }; |
| 1014 | return TransResult{ |
| 1015 | .node = &cat_node.base, |
| 1016 | .child_scope = scope, |
| 1017 | .node_scope = scope, |
| 1018 | }; |
| 1019 | } |
| 1020 | |
| 909 | 1021 | fn findBlockScope(inner: *Scope) *Scope.Block { |
| 910 | 1022 | var scope = inner; |
| 911 | 1023 | while (true) : (scope = scope.parent orelse unreachable) { |
| ... | ... | @@ -1295,51 +1407,6 @@ fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node |
| 1295 | 1407 | return node; |
| 1296 | 1408 | } |
| 1297 | 1409 | |
| 1298 | | fn transCreateNodeVarDecl( |
| 1299 | | c: *Context, |
| 1300 | | is_pub: bool, |
| 1301 | | is_extern: bool, |
| 1302 | | is_const: bool, |
| 1303 | | var_name: []const u8, |
| 1304 | | ) !*ast.Node.VarDecl { |
| 1305 | | const visb_tok = if (is_pub) |
| 1306 | | try appendToken(c, .Keyword_pub, "pub") |
| 1307 | | else |
| 1308 | | null; |
| 1309 | | |
| 1310 | | const extern_tok = if (is_extern) |
| 1311 | | try appendToken(c, .Keyword_extern, "extern") |
| 1312 | | else |
| 1313 | | null; |
| 1314 | | |
| 1315 | | const mut_tok = if (is_const) |
| 1316 | | try appendToken(c, .Keyword_const, "const") |
| 1317 | | else |
| 1318 | | try appendToken(c, .Keyword_var, "var"); |
| 1319 | | |
| 1320 | | const name_tok = try appendToken(c, .Identifier, var_name); |
| 1321 | | |
| 1322 | | const node = try c.a().create(ast.Node.VarDecl); |
| 1323 | | node.* = ast.Node.VarDecl{ |
| 1324 | | .base = ast.Node{ .id = .VarDecl }, |
| 1325 | | .doc_comments = null, |
| 1326 | | .visib_token = visb_tok, |
| 1327 | | .thread_local_token = null, |
| 1328 | | .name_token = name_tok, |
| 1329 | | .eq_token = undefined, // set by caller |
| 1330 | | .mut_token = mut_tok, |
| 1331 | | .comptime_token = null, |
| 1332 | | .extern_export_token = extern_tok, |
| 1333 | | .lib_name = null, |
| 1334 | | .type_node = null, |
| 1335 | | .align_node = null, |
| 1336 | | .section_node = null, |
| 1337 | | .init_node = null, |
| 1338 | | .semicolon_token = undefined, // set by caller |
| 1339 | | }; |
| 1340 | | return node; |
| 1341 | | } |
| 1342 | | |
| 1343 | 1410 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 1344 | 1411 | const token = try appendToken(c, .IntegerLiteral, try std.fmt.allocPrint(c.a(), "{}", .{int})); |
| 1345 | 1412 | const node = try c.a().create(ast.Node.IntegerLiteral); |
| ... | ... | @@ -1474,94 +1541,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 1474 | 1541 | } |
| 1475 | 1542 | } |
| 1476 | 1543 | |
| 1477 | | fn transApValue(rp: RestorePoint, ap_value: *const ZigClangAPValue, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TransError!*ast.Node { |
| 1478 | | switch (ZigClangAPValue_getKind(ap_value)) { |
| 1479 | | .None => return transCreateNodeUndefinedLiteral(rp.c), |
| 1480 | | .Int => return transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(ap_value)), |
| 1481 | | .Array => { |
| 1482 | | // TODO evaluateValue is null for Array init for some reason |
| 1483 | | // TODO use anon literals once they work properly |
| 1484 | | const init_count = ZigClangAPValue_getArrayInitializedElts(ap_value); |
| 1485 | | const all_count = ZigClangAPValue_getArraySize(ap_value); |
| 1486 | | const leftover_count = all_count - init_count; |
| 1487 | | const qt_type = ZigClangQualType_getTypePtr(qt); |
| 1488 | | const child_qt = ZigClangArrayType_getElementType(ZigClangType_getAsArrayTypeUnsafe(qt_type)); |
| 1489 | | |
| 1490 | | var init_node: *ast.Node.SuffixOp = undefined; |
| 1491 | | var cat_tok: ast.TokenIndex = undefined; |
| 1492 | | if (init_count != 0) { |
| 1493 | | var type_node = try transQualType(rp, qt, source_loc); |
| 1494 | | init_node = try transCreateNodeArrayInitializer(rp.c, type_node); |
| 1495 | | var i: c_uint = 0; |
| 1496 | | while (i < init_count) : (i += 1) { |
| 1497 | | const elem_ap_val = ZigClangAPValue_getArrayInitializedElt(ap_value, i); |
| 1498 | | try init_node.op.ArrayInitializer.push(try transApValue(rp, elem_ap_val, child_qt, source_loc)); |
| 1499 | | _ = try appendToken(rp.c, .Comma, ","); |
| 1500 | | } |
| 1501 | | init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| 1502 | | if (leftover_count == 0) { |
| 1503 | | return &init_node.base; |
| 1504 | | } |
| 1505 | | cat_tok = try appendToken(rp.c, .PlusPlus, "++"); |
| 1506 | | } |
| 1507 | | |
| 1508 | | var filler_type_node = try transQualType(rp, qt, source_loc); |
| 1509 | | var filler_init_node = try transCreateNodeArrayInitializer(rp.c, filler_type_node); |
| 1510 | | const filler_ap_val = ZigClangAPValue_getArrayFiller(ap_value); |
| 1511 | | try filler_init_node.op.ArrayInitializer.push(try transApValue(rp, filler_ap_val, child_qt, source_loc)); |
| 1512 | | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| 1513 | | |
| 1514 | | const rhs_node = if (leftover_count == 1) |
| 1515 | | &filler_init_node.base |
| 1516 | | else blk: { |
| 1517 | | const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**"); |
| 1518 | | const mul_node = try rp.c.a().create(ast.Node.InfixOp); |
| 1519 | | mul_node.* = .{ |
| 1520 | | .base = .{ .id = .InfixOp }, |
| 1521 | | .op_token = mul_tok, |
| 1522 | | .lhs = &filler_init_node.base, |
| 1523 | | .op = .ArrayMult, |
| 1524 | | .rhs = try transCreateNodeInt(rp.c, leftover_count), |
| 1525 | | }; |
| 1526 | | break :blk &mul_node.base; |
| 1527 | | }; |
| 1528 | | |
| 1529 | | if (init_count == 0) { |
| 1530 | | return rhs_node; |
| 1531 | | } |
| 1532 | | |
| 1533 | | const cat_node = try rp.c.a().create(ast.Node.InfixOp); |
| 1534 | | cat_node.* = .{ |
| 1535 | | .base = .{ .id = .InfixOp }, |
| 1536 | | .op_token = cat_tok, |
| 1537 | | .lhs = &init_node.base, |
| 1538 | | .op = .ArrayCat, |
| 1539 | | .rhs = rhs_node, |
| 1540 | | }; |
| 1541 | | return &cat_node.base; |
| 1542 | | }, |
| 1543 | | .LValue => { |
| 1544 | | const lval_base = ZigClangAPValue_getLValueBase(ap_value); |
| 1545 | | const expr = ZigClangAPValueLValueBase_dyn_cast_Expr(lval_base); |
| 1546 | | if (expr) |e| { |
| 1547 | | return (try transExpr(rp, &rp.c.global_scope.base, e, .used, .r_value)).node; |
| 1548 | | } |
| 1549 | | try emitWarning(rp.c, source_loc, "TODO handle initializer LValue ValueDecl", .{}); |
| 1550 | | }, |
| 1551 | | .Float => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: Float", .{}), |
| 1552 | | .ComplexInt => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: ComplexInt", .{}), |
| 1553 | | .ComplexFloat => try emitWarning(rp.c, source_loc, "Tunsupported initializer value kind: ComplexFloat", .{}), |
| 1554 | | .Vector => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: Vector", .{}), |
| 1555 | | .Struct => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: Struct", .{}), |
| 1556 | | .Union => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: Union", .{}), |
| 1557 | | .MemberPointer => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: MemberPointer", .{}), |
| 1558 | | .AddrLabelDiff => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: AddrLabelDiff", .{}), |
| 1559 | | .Indeterminate => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: Indeterminate", .{}), |
| 1560 | | .FixedPoint => try emitWarning(rp.c, source_loc, "unsupported initializer value kind: FixedPoint", .{}), |
| 1561 | | } |
| 1562 | | return error.UnsupportedTranslation; |
| 1563 | | } |
| 1564 | | |
| 1565 | 1544 | const FnDeclContext = struct { |
| 1566 | 1545 | fn_name: []const u8, |
| 1567 | 1546 | has_body: bool, |