authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-06 18:45:45+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:37:07+02:00
log4c0c9b07555bb69d05142dfe038a7cad79068ba9
treebb89130d3cd278c4e40d7fcca6dc82a638ff16de
parentd835f5cce5fc3b296f55e208905d9ff4d368e497
signature Commit is signed but in an unrecognized format.

translate-c: convert transBinaryOperator


2 files changed, 273 insertions(+), 539 deletions(-)

src/translate_c.zig+133-528
......@@ -3,14 +3,14 @@
33
44const std = @import("std");
55const assert = std.debug.assert;
6const ast = std.zig.ast;
7const Token = std.zig.Token;
86const clang = @import("clang.zig");
97const ctok = std.c.tokenizer;
108const CToken = std.c.Token;
119const mem = std.mem;
1210const math = std.math;
1311const Type = @import("type.zig").Type;
12const ast = @import("translate_c/ast.zig");
13const Node = ast.Node;
1414
1515const CallingConvention = std.builtin.CallingConvention;
1616
......@@ -348,47 +348,6 @@ pub const Context = struct {
348348 }
349349};
350350
351fn addCBuiltinsNamespace(c: *Context) Error!void {
352 // pub usingnamespace @import("std").c.builtins;
353 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
354 const use_tok = try appendToken(c, .Keyword_usingnamespace, "usingnamespace");
355 const import_tok = try appendToken(c, .Builtin, "@import");
356 const lparen_tok = try appendToken(c, .LParen, "(");
357 const std_tok = try appendToken(c, .StringLiteral, "\"std\"");
358 const rparen_tok = try appendToken(c, .RParen, ")");
359
360 const std_node = try c.arena.create(ast.Node.OneToken);
361 std_node.* = .{
362 .base = .{ .tag = .StringLiteral },
363 .token = std_tok,
364 };
365
366 const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
367 call_node.* = .{
368 .builtin_token = import_tok,
369 .params_len = 1,
370 .rparen_token = rparen_tok,
371 };
372 call_node.params()[0] = &std_node.base;
373
374 var access_chain = &call_node.base;
375 access_chain = try transCreateNodeFieldAccess(c, access_chain, "c");
376 access_chain = try transCreateNodeFieldAccess(c, access_chain, "builtins");
377
378 const semi_tok = try appendToken(c, .Semicolon, ";");
379
380 const bytes = try c.gpa.alignedAlloc(u8, @alignOf(ast.Node.Use), @sizeOf(ast.Node.Use));
381 const using_node = @ptrCast(*ast.Node.Use, bytes.ptr);
382 using_node.* = .{
383 .doc_comments = null,
384 .visib_token = pub_tok,
385 .use_token = use_tok,
386 .expr = access_chain,
387 .semicolon_token = semi_tok,
388 };
389 try c.root_decls.append(c.gpa, &using_node.base);
390}
391
392351pub fn translate(
393352 gpa: *mem.Allocator,
394353 args_begin: [*]?[*]const u8,
......@@ -446,7 +405,7 @@ pub fn translate(
446405 context.opaque_demotes.deinit(gpa);
447406 }
448407
449 try addCBuiltinsNamespace(&context);
408 _ = try Node.usingnamespace_builtins.init();
450409
451410 try prepopulateGlobalNameTable(ast_unit, &context);
452411
......@@ -1318,26 +1277,6 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
13181277 return transCreateNodeIdentifier(c, name);
13191278}
13201279
1321fn createAlias(c: *Context, alias: anytype) !void {
1322 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1323 const mut_tok = try appendToken(c, .Keyword_const, "const");
1324 const name_tok = try appendIdentifier(c, alias.alias);
1325 const eq_token = try appendToken(c, .Equal, "=");
1326 const init_node = try transCreateNodeIdentifier(c, alias.name);
1327 const semicolon_token = try appendToken(c, .Semicolon, ";");
1328
1329 const node = try ast.Node.VarDecl.create(c.arena, .{
1330 .name_token = name_tok,
1331 .mut_token = mut_tok,
1332 .semicolon_token = semicolon_token,
1333 }, .{
1334 .visib_token = visib_tok,
1335 .eq_token = eq_token,
1336 .init_node = init_node,
1337 });
1338 return addTopLevelDecl(c, alias.alias, &node.base);
1339}
1340
13411280const ResultUsed = enum {
13421281 used,
13431282 unused,
......@@ -1349,78 +1288,63 @@ const LRValue = enum {
13491288};
13501289
13511290fn transStmt(
1352 rp: RestorePoint,
1291 c: *Context,
13531292 scope: *Scope,
13541293 stmt: *const clang.Stmt,
13551294 result_used: ResultUsed,
13561295 lrvalue: LRValue,
1357) TransError!*ast.Node {
1296) TransError!Node {
13581297 const sc = stmt.getStmtClass();
13591298 switch (sc) {
1360 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used),
1361 .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const clang.CompoundStmt, stmt)),
1362 .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue),
1363 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const clang.DeclStmt, stmt)),
1364 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue),
1365 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used),
1366 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as),
1367 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const clang.ReturnStmt, stmt)),
1368 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),
1299 .BinaryOperatorClass => return transBinaryOperator(c, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used),
1300 .CompoundStmtClass => return transCompoundStmt(c, scope, @ptrCast(*const clang.CompoundStmt, stmt)),
1301 .CStyleCastExprClass => return transCStyleCastExprClass(c, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue),
1302 .DeclStmtClass => return transDeclStmt(c, scope, @ptrCast(*const clang.DeclStmt, stmt)),
1303 .DeclRefExprClass => return transDeclRefExpr(c, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue),
1304 .ImplicitCastExprClass => return transImplicitCastExpr(c, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used),
1305 .IntegerLiteralClass => return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as),
1306 .ReturnStmtClass => return transReturnStmt(c, scope, @ptrCast(*const clang.ReturnStmt, stmt)),
1307 .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),
13691308 .ParenExprClass => {
1370 const expr = try transExpr(rp, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue);
1371 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1372 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1373 node.* = .{
1374 .lparen = try appendToken(rp.c, .LParen, "("),
1375 .expr = expr,
1376 .rparen = try appendToken(rp.c, .RParen, ")"),
1377 };
1378 return maybeSuppressResult(rp, scope, result_used, &node.base);
1379 },
1380 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),
1381 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1382 .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const clang.IfStmt, stmt)),
1383 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const clang.WhileStmt, stmt)),
1384 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const clang.DoStmt, stmt)),
1309 const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue);
1310 return maybeSuppressResult(c, scope, result_used, expr);
1311 },
1312 .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),
1313 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1314 .IfStmtClass => return transIfStmt(c, scope, @ptrCast(*const clang.IfStmt, stmt)),
1315 .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)),
1316 .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)),
13851317 .NullStmtClass => {
1386 const block = try rp.c.createBlock(0);
1387 block.rbrace = try appendToken(rp.c, .RBrace, "}");
1388 return &block.base;
1389 },
1390 .ContinueStmtClass => return try transCreateNodeContinue(rp.c),
1391 .BreakStmtClass => return transBreak(rp, scope),
1392 .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const clang.ForStmt, stmt)),
1393 .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
1318 return Node.empty_block.init();
1319 },
1320 .ContinueStmtClass => return try transCreateNodeContinue(c),
1321 .BreakStmtClass => return transBreak(c, scope),
1322 .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)),
1323 .FloatingLiteralClass => return transFloatingLiteral(c, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
13941324 .ConditionalOperatorClass => {
1395 return transConditionalOperator(rp, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used);
1325 return transConditionalOperator(c, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used);
13961326 },
13971327 .BinaryConditionalOperatorClass => {
1398 return transBinaryConditionalOperator(rp, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used);
1399 },
1400 .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const clang.SwitchStmt, stmt)),
1401 .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const clang.CaseStmt, stmt)),
1402 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const clang.DefaultStmt, stmt)),
1403 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1404 .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used),
1405 .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as),
1406 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used),
1407 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used),
1408 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used),
1409 .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const clang.CallExpr, stmt), result_used),
1410 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used),
1411 .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used),
1412 .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used),
1328 return transBinaryConditionalOperator(c, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used);
1329 },
1330 .SwitchStmtClass => return transSwitch(c, scope, @ptrCast(*const clang.SwitchStmt, stmt)),
1331 .CaseStmtClass => return transCase(c, scope, @ptrCast(*const clang.CaseStmt, stmt)),
1332 .DefaultStmtClass => return transDefault(c, scope, @ptrCast(*const clang.DefaultStmt, stmt)),
1333 .ConstantExprClass => return transConstantExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1334 .PredefinedExprClass => return transPredefinedExpr(c, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used),
1335 .CharacterLiteralClass => return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as),
1336 .StmtExprClass => return transStmtExpr(c, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used),
1337 .MemberExprClass => return transMemberExpr(c, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used),
1338 .ArraySubscriptExprClass => return transArrayAccess(c, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used),
1339 .CallExprClass => return transCallExpr(c, scope, @ptrCast(*const clang.CallExpr, stmt), result_used),
1340 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(c, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used),
1341 .UnaryOperatorClass => return transUnaryOperator(c, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used),
1342 .CompoundAssignOperatorClass => return transCompoundAssignOperator(c, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used),
14131343 .OpaqueValueExprClass => {
14141344 const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;
1415 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);
1416 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1417 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1418 node.* = .{
1419 .lparen = try appendToken(rp.c, .LParen, "("),
1420 .expr = expr,
1421 .rparen = try appendToken(rp.c, .RParen, ")"),
1422 };
1423 return maybeSuppressResult(rp, scope, result_used, &node.base);
1345 const expr = try transExpr(c, scope, source_expr, .used, lrvalue);
1346 return maybeSuppressResult(c, scope, result_used, expr);
1347 const node = try c.arena.create(Node.GroupedExpression);
14241348 },
14251349 else => {
14261350 return revertAndWarn(
......@@ -1435,175 +1359,139 @@ fn transStmt(
14351359}
14361360
14371361fn transBinaryOperator(
1438 rp: RestorePoint,
1362 c: *Context,
14391363 scope: *Scope,
14401364 stmt: *const clang.BinaryOperator,
14411365 result_used: ResultUsed,
1442) TransError!*ast.Node {
1366) TransError!Node {
14431367 const op = stmt.getOpcode();
14441368 const qt = stmt.getType();
1445 var op_token: ast.TokenIndex = undefined;
1446 var op_id: ast.Node.Tag = undefined;
14471369 switch (op) {
1448 .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()),
1370 .Assign => return try transCreateNodeAssign(c, scope, result_used, stmt.getLHS(), stmt.getRHS()),
14491371 .Comma => {
14501372 var block_scope = try Scope.Block.init(rp.c, scope, true);
1451 const lparen = try appendToken(rp.c, .LParen, "(");
1373 defer block_scope.deinit();
1374
14521375
1453 const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value);
1376 const lhs = try transExpr(c, &block_scope.base, stmt.getLHS(), .unused, .r_value);
14541377 try block_scope.statements.append(lhs);
14551378
14561379 const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value);
1457 _ = try appendToken(rp.c, .Semicolon, ";");
1458 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs);
1459 try block_scope.statements.append(&break_node.base);
1380 const break_node = try Node.break_val.create(c.arena, .{
1381 .label = block_scope.label,
1382 .val = rhs,
1383 });
1384 try block_scope.statements.append(break_node);
14601385 const block_node = try block_scope.complete(rp.c);
1461 const rparen = try appendToken(rp.c, .RParen, ")");
1462 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
1463 grouped_expr.* = .{
1464 .lparen = lparen,
1465 .expr = block_node,
1466 .rparen = rparen,
1467 };
1468 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
1386 return maybeSuppressResult(rp, scope, result_used, block_node);
14691387 },
14701388 .Div => {
14711389 if (cIsSignedInteger(qt)) {
14721390 // signed integer division uses @divTrunc
1473 const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2);
1474 div_trunc_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);
1475 _ = try appendToken(rp.c, .Comma, ",");
1476 const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);
1477 div_trunc_node.params()[1] = rhs;
1478 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1479 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
1391 const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
1392 const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
1393 const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs});
1394 return maybeSuppressResult(c, scope, result_used, div_trunc);
14801395 }
14811396 },
14821397 .Rem => {
14831398 if (cIsSignedInteger(qt)) {
14841399 // signed integer division uses @rem
1485 const rem_node = try rp.c.createBuiltinCall("@rem", 2);
1486 rem_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);
1487 _ = try appendToken(rp.c, .Comma, ",");
1488 const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);
1489 rem_node.params()[1] = rhs;
1490 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1491 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
1400 const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
1401 const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
1402 const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs});
1403 return maybeSuppressResult(c, scope, result_used, rem);
14921404 }
14931405 },
14941406 .Shl => {
1495 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
1496 return maybeSuppressResult(rp, scope, result_used, node);
1407 const node = try transCreateNodeShiftOp(c, scope, stmt, .shl);
1408 return maybeSuppressResult(c, scope, result_used, node);
14971409 },
14981410 .Shr => {
1499 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
1500 return maybeSuppressResult(rp, scope, result_used, node);
1501 },
1502 .LAnd => {
1503 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true);
1504 return maybeSuppressResult(rp, scope, result_used, node);
1505 },
1506 .LOr => {
1507 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true);
1508 return maybeSuppressResult(rp, scope, result_used, node);
1411 const node = try transCreateNodeShiftOp(c, scope, stmt, .shr);
1412 return maybeSuppressResult(c, scope, result_used, node);
15091413 },
15101414 else => {},
15111415 }
1512 const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);
1416 var op_id: Node.Tag = undefined;
15131417 switch (op) {
15141418 .Add => {
15151419 if (cIsUnsignedInteger(qt)) {
1516 op_token = try appendToken(rp.c, .PlusPercent, "+%");
1517 op_id = .AddWrap;
1420 op_id = .add_wrap;
15181421 } else {
1519 op_token = try appendToken(rp.c, .Plus, "+");
1520 op_id = .Add;
1422 op_id = .add;
15211423 }
15221424 },
15231425 .Sub => {
15241426 if (cIsUnsignedInteger(qt)) {
1525 op_token = try appendToken(rp.c, .MinusPercent, "-%");
1526 op_id = .SubWrap;
1427 op_id = .sub_wrap;
15271428 } else {
1528 op_token = try appendToken(rp.c, .Minus, "-");
1529 op_id = .Sub;
1429 op_id = .sub;
15301430 }
15311431 },
15321432 .Mul => {
15331433 if (cIsUnsignedInteger(qt)) {
1534 op_token = try appendToken(rp.c, .AsteriskPercent, "*%");
1535 op_id = .MulWrap;
1434 op_id = .mul_wrap;
15361435 } else {
1537 op_token = try appendToken(rp.c, .Asterisk, "*");
1538 op_id = .Mul;
1436 op_id = .mul;
15391437 }
15401438 },
15411439 .Div => {
15421440 // unsigned/float division uses the operator
1543 op_id = .Div;
1544 op_token = try appendToken(rp.c, .Slash, "/");
1441 op_id = .div;
15451442 },
15461443 .Rem => {
15471444 // unsigned/float division uses the operator
1548 op_id = .Mod;
1549 op_token = try appendToken(rp.c, .Percent, "%");
1445 op_id = .mod;
15501446 },
15511447 .LT => {
1552 op_id = .LessThan;
1553 op_token = try appendToken(rp.c, .AngleBracketLeft, "<");
1448 op_id = .less_than;
15541449 },
15551450 .GT => {
1556 op_id = .GreaterThan;
1557 op_token = try appendToken(rp.c, .AngleBracketRight, ">");
1451 op_id = .greater_than;
15581452 },
15591453 .LE => {
1560 op_id = .LessOrEqual;
1561 op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<=");
1454 op_id = .less_than_equal;
15621455 },
15631456 .GE => {
1564 op_id = .GreaterOrEqual;
1565 op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">=");
1457 op_id = .greater_than_equal;
15661458 },
15671459 .EQ => {
1568 op_id = .EqualEqual;
1569 op_token = try appendToken(rp.c, .EqualEqual, "==");
1460 op_id = .equal;
15701461 },
15711462 .NE => {
1572 op_id = .BangEqual;
1573 op_token = try appendToken(rp.c, .BangEqual, "!=");
1463 op_id = .not_equal;
15741464 },
15751465 .And => {
1576 op_id = .BitAnd;
1577 op_token = try appendToken(rp.c, .Ampersand, "&");
1466 op_id = .bit_and;
15781467 },
15791468 .Xor => {
1580 op_id = .BitXor;
1581 op_token = try appendToken(rp.c, .Caret, "^");
1469 op_id = .bit_xor;
15821470 },
15831471 .Or => {
1584 op_id = .BitOr;
1585 op_token = try appendToken(rp.c, .Pipe, "|");
1472 op_id = .bit_or;
1473 },
1474 .LAnd => {
1475 op_id = .@"and";
1476 },
1477 .LOr => {
1478 op_id = .@"or";
15861479 },
15871480 else => unreachable,
15881481 }
15891482
1590 const rhs_node = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);
1591
1592 const lhs = if (isBoolRes(lhs_node)) init: {
1593 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1594 cast_node.params()[0] = lhs_node;
1595 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1596 break :init &cast_node.base;
1597 } else lhs_node;
1598
1599 const rhs = if (isBoolRes(rhs_node)) init: {
1600 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1601 cast_node.params()[0] = rhs_node;
1602 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1603 break :init &cast_node.base;
1604 } else rhs_node;
1483 const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
1484 const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
16051485
1606 return transCreateNodeInfixOp(rp, scope, lhs, op_id, op_token, rhs, result_used, true);
1486 const payload = try c.arena.create(ast.Payload.BinOp);
1487 payload.* = .{
1488 .base = .{ .tag = op_id },
1489 .data = .{
1490 .lhs = lhs,
1491 .rhs = rhs,
1492 },
1493 };
1494 return maybeSuppressResult(c, scope, used, &payload.base);
16071495}
16081496
16091497fn transCompoundStmtInline(
......@@ -2365,40 +2253,13 @@ fn transEnumToInt(c: *Context, enum_expr: *ast.Node) TypeError!*ast.Node {
23652253}
23662254
23672255fn transExpr(
2368 rp: RestorePoint,
2369 scope: *Scope,
2370 expr: *const clang.Expr,
2371 used: ResultUsed,
2372 lrvalue: LRValue,
2373) TransError!*ast.Node {
2374 return transStmt(rp, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue);
2375}
2376
2377/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
2378/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
2379fn transExprCoercing(
2380 rp: RestorePoint,
2256 c: *Context,
23812257 scope: *Scope,
23822258 expr: *const clang.Expr,
23832259 used: ResultUsed,
23842260 lrvalue: LRValue,
2385) TransError!*ast.Node {
2386 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
2387 .IntegerLiteralClass => {
2388 return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as);
2389 },
2390 .CharacterLiteralClass => {
2391 return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, expr), .used, .no_as);
2392 },
2393 .UnaryOperatorClass => {
2394 const un_expr = @ptrCast(*const clang.UnaryOperator, expr);
2395 if (un_expr.getOpcode() == .Extension) {
2396 return transExprCoercing(rp, scope, un_expr.getSubExpr(), used, lrvalue);
2397 }
2398 },
2399 else => {},
2400 }
2401 return transExpr(rp, scope, expr, .used, .r_value);
2261) TransError!Node {
2262 return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue);
24022263}
24032264
24042265fn transInitListExprRecord(
......@@ -4150,7 +4011,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool {
41504011 return qualTypeCanon(qt).isBooleanType();
41514012}
41524013
4153fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 {
4014fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 {
41544015 const ty = qt.getTypePtr();
41554016
41564017 switch (ty.getTypeClass()) {
......@@ -4174,7 +4035,7 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S
41744035 .Typedef => {
41754036 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
41764037 const typedef_decl = typedef_ty.getDecl();
4177 const type_name = try rp.c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
4038 const type_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
41784039
41794040 if (mem.eql(u8, type_name, "uint8_t") or mem.eql(u8, type_name, "int8_t")) {
41804041 return 8;
......@@ -4194,51 +4055,17 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S
41944055 unreachable;
41954056}
41964057
4197fn qualTypeToLog2IntRef(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !*ast.Node {
4198 const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);
4058fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !Node {
4059 const int_bit_width = try qualTypeIntBitWidth(c, qt, source_loc);
41994060
42004061 if (int_bit_width != 0) {
42014062 // we can perform the log2 now.
42024063 const cast_bit_width = math.log2_int(u64, int_bit_width);
4203 const node = try rp.c.arena.create(ast.Node.OneToken);
4204 node.* = .{
4205 .base = .{ .tag = .IntegerLiteral },
4206 .token = try appendTokenFmt(rp.c, .Identifier, "u{d}", .{cast_bit_width}),
4207 };
4208 return &node.base;
4209 }
4210
4211 const zig_type_node = try transQualType(rp, qt, source_loc);
4212
4213 // @import("std").math.Log2Int(c_long);
4214 //
4215 // FnCall
4216 // FieldAccess
4217 // FieldAccess
4218 // FnCall (.builtin = true)
4219 // Symbol "import"
4220 // StringLiteral "std"
4221 // Symbol "math"
4222 // Symbol "Log2Int"
4223 // Symbol <zig_type_node> (var from above)
4224
4225 const import_fn_call = try rp.c.createBuiltinCall("@import", 1);
4226 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
4227 const std_node = try rp.c.arena.create(ast.Node.OneToken);
4228 std_node.* = .{
4229 .base = .{ .tag = .StringLiteral },
4230 .token = std_token,
4231 };
4232 import_fn_call.params()[0] = &std_node.base;
4233 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
4234
4235 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
4236 const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
4237 const log2int_fn_call = try rp.c.createCall(outer_field_access, 1);
4238 log2int_fn_call.params()[0] = zig_type_node;
4239 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
4064 return Node.uint_type.create(c.arena, cast_bit_width);
4065 }
42404066
4241 return &log2int_fn_call.base;
4067 const zig_type = try transQualType(c, qt, source_loc);
4068 return Node.std_math_Log2Int.create(c.arena, zig_type);
42424069}
42434070
42444071fn qualTypeChildIsFnProto(qt: clang.QualType) bool {
......@@ -4506,67 +4333,6 @@ fn transCreateNodeSimplePrefixOp(
45064333 return node;
45074334}
45084335
4509fn transCreateNodeInfixOp(
4510 rp: RestorePoint,
4511 scope: *Scope,
4512 lhs_node: *ast.Node,
4513 op: ast.Node.Tag,
4514 op_token: ast.TokenIndex,
4515 rhs_node: *ast.Node,
4516 used: ResultUsed,
4517 grouped: bool,
4518) !*ast.Node {
4519 var lparen = if (grouped)
4520 try appendToken(rp.c, .LParen, "(")
4521 else
4522 null;
4523 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4524 node.* = .{
4525 .base = .{ .tag = op },
4526 .op_token = op_token,
4527 .lhs = lhs_node,
4528 .rhs = rhs_node,
4529 };
4530 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
4531 const rparen = try appendToken(rp.c, .RParen, ")");
4532 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
4533 grouped_expr.* = .{
4534 .lparen = lparen.?,
4535 .expr = &node.base,
4536 .rparen = rparen,
4537 };
4538 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
4539}
4540
4541fn transCreateNodeBoolInfixOp(
4542 rp: RestorePoint,
4543 scope: *Scope,
4544 stmt: *const clang.BinaryOperator,
4545 op: ast.Node.Tag,
4546 used: ResultUsed,
4547 grouped: bool,
4548) !*ast.Node {
4549 std.debug.assert(op == .BoolAnd or op == .BoolOr);
4550
4551 const lhs_hode = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value, true);
4552 const op_token = if (op == .BoolAnd)
4553 try appendToken(rp.c, .Keyword_and, "and")
4554 else
4555 try appendToken(rp.c, .Keyword_or, "or");
4556 const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value, true);
4557
4558 return transCreateNodeInfixOp(
4559 rp,
4560 scope,
4561 lhs_hode,
4562 op,
4563 op_token,
4564 rhs,
4565 used,
4566 grouped,
4567 );
4568}
4569
45704336fn transCreateNodePtrType(
45714337 c: *Context,
45724338 is_const: bool,
......@@ -4968,40 +4734,33 @@ fn transCreateNodeSwitchElse(c: *Context) !*ast.Node {
49684734}
49694735
49704736fn transCreateNodeShiftOp(
4971 rp: RestorePoint,
4737 c: *Context,
49724738 scope: *Scope,
49734739 stmt: *const clang.BinaryOperator,
4974 op: ast.Node.Tag,
4975 op_tok_id: std.zig.Token.Id,
4976 bytes: []const u8,
4977) !*ast.Node {
4978 std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight);
4740 op: Node.Tag,
4741) !Node {
4742 std.debug.assert(op == .shl or op == .shr);
49794743
49804744 const lhs_expr = stmt.getLHS();
49814745 const rhs_expr = stmt.getRHS();
49824746 const rhs_location = rhs_expr.getBeginLoc();
49834747 // lhs >> @as(u5, rh)
49844748
4985 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
4986 const op_token = try appendToken(rp.c, op_tok_id, bytes);
4749 const lhs = try transExpr(c, scope, lhs_expr, .used, .l_value);
49874750
4988 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
4989 const rhs_type = try qualTypeToLog2IntRef(rp, stmt.getType(), rhs_location);
4990 cast_node.params()[0] = rhs_type;
4991 _ = try appendToken(rp.c, .Comma, ",");
4992 const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);
4993 cast_node.params()[1] = rhs;
4994 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
4751 const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location);
4752 const rhs = try transExpr(c, scope, rhs_expr, .used, .r_value);
4753 const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type });
49954754
4996 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4997 node.* = .{
4755 const payload = try c.arena.create(ast.Payload.BinOp);
4756 payload.* = .{
49984757 .base = .{ .tag = op },
4999 .op_token = op_token,
5000 .lhs = lhs,
5001 .rhs = &cast_node.base,
4758 .data = .{
4759 .lhs = lhs,
4760 .rhs = rhs_casted,
4761 }
50024762 };
5003
5004 return &node.base;
4763 return &payload.base;
50054764}
50064765
50074766fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
......@@ -5025,161 +4784,7 @@ fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAcces
50254784 return node;
50264785}
50274786
5028const RestorePoint = struct {
5029 c: *Context,
5030 token_index: ast.TokenIndex,
5031 src_buf_index: usize,
5032
5033 fn activate(self: RestorePoint) void {
5034 self.c.token_ids.shrinkAndFree(self.c.gpa, self.token_index);
5035 self.c.token_locs.shrinkAndFree(self.c.gpa, self.token_index);
5036 self.c.source_buffer.shrinkAndFree(self.src_buf_index);
5037 }
5038};
5039
5040fn makeRestorePoint(c: *Context) RestorePoint {
5041 return RestorePoint{
5042 .c = c,
5043 .token_index = c.token_ids.items.len,
5044 .src_buf_index = c.source_buffer.items.len,
5045 };
5046}
5047
5048fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!*ast.Node {
5049 switch (ty.getTypeClass()) {
5050 .Builtin => {
5051 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
5052 return transCreateNodeIdentifier(rp.c, switch (builtin_ty.getKind()) {
5053 .Void => "c_void",
5054 .Bool => "bool",
5055 .Char_U, .UChar, .Char_S, .Char8 => "u8",
5056 .SChar => "i8",
5057 .UShort => "c_ushort",
5058 .UInt => "c_uint",
5059 .ULong => "c_ulong",
5060 .ULongLong => "c_ulonglong",
5061 .Short => "c_short",
5062 .Int => "c_int",
5063 .Long => "c_long",
5064 .LongLong => "c_longlong",
5065 .UInt128 => "u128",
5066 .Int128 => "i128",
5067 .Float => "f32",
5068 .Double => "f64",
5069 .Float128 => "f128",
5070 .Float16 => "f16",
5071 .LongDouble => "c_longdouble",
5072 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
5073 });
5074 },
5075 .FunctionProto => {
5076 const fn_proto_ty = @ptrCast(*const clang.FunctionProtoType, ty);
5077 const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);
5078 return &fn_proto.base;
5079 },
5080 .FunctionNoProto => {
5081 const fn_no_proto_ty = @ptrCast(*const clang.FunctionType, ty);
5082 const fn_proto = try transFnNoProto(rp, fn_no_proto_ty, source_loc, null, false);
5083 return &fn_proto.base;
5084 },
5085 .Paren => {
5086 const paren_ty = @ptrCast(*const clang.ParenType, ty);
5087 return transQualType(rp, paren_ty.getInnerType(), source_loc);
5088 },
5089 .Pointer => {
5090 const child_qt = ty.getPointeeType();
5091 if (qualTypeChildIsFnProto(child_qt)) {
5092 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
5093 optional_node.rhs = try transQualType(rp, child_qt, source_loc);
5094 return &optional_node.base;
5095 }
5096 if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) {
5097 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
5098 const pointer_node = try transCreateNodePtrType(
5099 rp.c,
5100 child_qt.isConstQualified(),
5101 child_qt.isVolatileQualified(),
5102 .Asterisk,
5103 );
5104 optional_node.rhs = &pointer_node.base;
5105 pointer_node.rhs = try transQualType(rp, child_qt, source_loc);
5106 return &optional_node.base;
5107 }
5108 const pointer_node = try transCreateNodePtrType(
5109 rp.c,
5110 child_qt.isConstQualified(),
5111 child_qt.isVolatileQualified(),
5112 .Identifier,
5113 );
5114 pointer_node.rhs = try transQualType(rp, child_qt, source_loc);
5115 return &pointer_node.base;
5116 },
5117 .ConstantArray => {
5118 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
5119
5120 const size_ap_int = const_arr_ty.getSize();
5121 const size = size_ap_int.getLimitedValue(math.maxInt(usize));
5122 const elem_ty = const_arr_ty.getElementType().getTypePtr();
5123 return try transCreateNodeArrayType(rp, source_loc, elem_ty, size);
5124 },
5125 .IncompleteArray => {
5126 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
5127
5128 const child_qt = incomplete_array_ty.getElementType();
5129 var node = try transCreateNodePtrType(
5130 rp.c,
5131 child_qt.isConstQualified(),
5132 child_qt.isVolatileQualified(),
5133 .Identifier,
5134 );
5135 node.rhs = try transQualType(rp, child_qt, source_loc);
5136 return &node.base;
5137 },
5138 .Typedef => {
5139 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
5140
5141 const typedef_decl = typedef_ty.getDecl();
5142 return (try transTypeDef(rp.c, typedef_decl, false)) orelse
5143 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});
5144 },
5145 .Record => {
5146 const record_ty = @ptrCast(*const clang.RecordType, ty);
5147
5148 const record_decl = record_ty.getDecl();
5149 return (try transRecordDecl(rp.c, record_decl)) orelse
5150 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});
5151 },
5152 .Enum => {
5153 const enum_ty = @ptrCast(*const clang.EnumType, ty);
5154
5155 const enum_decl = enum_ty.getDecl();
5156 return (try transEnumDecl(rp.c, enum_decl)) orelse
5157 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
5158 },
5159 .Elaborated => {
5160 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
5161 return transQualType(rp, elaborated_ty.getNamedType(), source_loc);
5162 },
5163 .Decayed => {
5164 const decayed_ty = @ptrCast(*const clang.DecayedType, ty);
5165 return transQualType(rp, decayed_ty.getDecayedType(), source_loc);
5166 },
5167 .Attributed => {
5168 const attributed_ty = @ptrCast(*const clang.AttributedType, ty);
5169 return transQualType(rp, attributed_ty.getEquivalentType(), source_loc);
5170 },
5171 .MacroQualified => {
5172 const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty);
5173 return transQualType(rp, macroqualified_ty.getModifiedType(), source_loc);
5174 },
5175 else => {
5176 const type_name = rp.c.str(ty.getTypeClassName());
5177 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
5178 },
5179 }
5180}
5181
5182fn transType1(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Type {
4787fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Type {
51834788 switch (ty.getTypeClass()) {
51844789 .Builtin => {
51854790 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
src/translate_c/ast.zig+140-11
......@@ -1,7 +1,7 @@
11const std = @import("std");
22const Type = @import("../type.zig").Type;
33
4pub const Node = struct {
4pub const Node = extern union {
55 /// If the tag value is less than Tag.no_payload_count, then no pointer
66 /// dereference is needed.
77 tag_if_small_enough: usize,
......@@ -13,12 +13,15 @@ pub const Node = struct {
1313 opaque_literal,
1414 true_literal,
1515 false_literal,
16 empty_block,
17 /// pub usingnamespace @import("std").c.builtins;
18 usingnamespace_builtins,
1619 // After this, the tag requires a payload.
1720
18 int,
19 float,
20 string,
21 char,
21 int_literal,
22 float_literal,
23 string_literal,
24 char_literal,
2225 identifier,
2326 @"if",
2427 @"while",
......@@ -44,6 +47,67 @@ pub const Node = struct {
4447 discard,
4548 block,
4649
50 // a + b
51 add,
52 // a = b
53 add_assign,
54 // c = (a = b)
55 add_assign_value,
56 add_wrap,
57 add_wrap_assign,
58 add_wrap_assign_value,
59 sub,
60 sub_assign,
61 sub_assign_value,
62 sub_wrap,
63 sub_wrap_assign,
64 sub_wrap_assign_value,
65 mul,
66 mul_assign,
67 mul_assign_value,
68 mul_wrap,
69 mul_wrap_assign,
70 mul_wrap_assign_value,
71 div,
72 div_assign,
73 div_assign_value,
74 shl,
75 shl_assign,
76 shl_assign_value,
77 shr,
78 shr_assign,
79 shr_assign_value,
80 mod,
81 mod_assign,
82 mod_assign_value,
83 @"and",
84 and_assign,
85 and_assign_value,
86 @"or",
87 or_assign,
88 or_assign_value,
89 xor,
90 xor_assign,
91 xor_assign_value,
92 less_than,
93 less_than_equal,
94 greater_than,
95 greater_than_equal,
96 equal,
97 not_equal,
98 bit_and,
99 bit_or,
100 bit_xor,
101
102 /// @import("std").math.Log2Int(operand)
103 std_math_Log2Int,
104 /// @intCast(lhs, rhs)
105 int_cast,
106 /// @rem(lhs, rhs)
107 rem,
108 /// @divTrunc(lhs, rhs)
109 div_trunc,
110
47111 pub const last_no_payload_tag = Tag.false_literal;
48112 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
49113
......@@ -54,8 +118,70 @@ pub const Node = struct {
54118 .opaque_literal,
55119 .true_literal,
56120 .false_litral,
121 .empty_block,
122 .usingnamespace_builtins,
57123 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
58124
125 .array_access,
126 .std_mem_zeroes,
127 .@"return",
128 .discard,
129 .std_math_Log2Int,
130 => Payload.UnOp,
131
132 .add,
133 .add_assign,
134 .add_assign_value,
135 .add_wrap,
136 .add_wrap_assign,
137 .add_wrap_assign_value,
138 .sub,
139 .sub_assign,
140 .sub_assign_value,
141 .sub_wrap,
142 .sub_wrap_assign,
143 .sub_wrap_assign_value,
144 .mul,
145 .mul_assign,
146 .mul_assign_value,
147 .mul_wrap,
148 .mul_wrap_assign,
149 .mul_wrap_assign_value,
150 .div,
151 .div_assign,
152 .div_assign_value,
153 .shl,
154 .shl_assign,
155 .shl_assign_value,
156 .shr,
157 .shr_assign,
158 .shr_assign_value,
159 .mod,
160 .mod_assign,
161 .mod_assign_value,
162 .@"and",
163 .and_assign,
164 .and_assign_value,
165 .@"or",
166 .or_assign,
167 .or_assign_value,
168 .xor,
169 .xor_assign,
170 .xor_assign_value,
171 .less_than,
172 .less_than_equal,
173 .greater_than,
174 .greater_than_equal,
175 .equal,
176 .not_equal,
177 .bit_and,
178 .bit_or,
179 .bit_xor,
180 .div_trunc,
181 .rem,
182 .int_cast,
183 => Payload.BinOp,
184
59185 .int,
60186 .float,
61187 .string,
......@@ -71,11 +197,6 @@ pub const Node = struct {
71197 .@"switch" => Payload.Switch,
72198 .@"break" => Payload.Break,
73199 .call => Payload.Call,
74 .array_access,
75 .std_mem_zeroes,
76 .@"return",
77 .discard,
78 => Payload.SingleArg,
79200 .var_decl => Payload.VarDecl,
80201 .func => Payload.Func,
81202 .@"enum" => Payload.Enum,
......@@ -123,11 +244,19 @@ pub const Payload = struct {
123244 data: []const u8,
124245 };
125246
126 pub const SingleArg = struct {
247 pub const UnOp = struct {
127248 base: Node,
128249 data: *Node,
129250 };
130251
252 pub const BinOp = struct {
253 base: Node,
254 data: struct {
255 lhs: *Node,
256 rhs: *Node,
257 },
258 };
259
131260 pub const If = struct {
132261 base: Node = .{ .tag = .@"if" },
133262 data: struct {