diff --git a/src/translate_c.zig b/src/translate_c.zig index e6629592ed..f885ea98b9 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -3,14 +3,14 @@ const std = @import("std"); const assert = std.debug.assert; -const ast = std.zig.ast; -const Token = std.zig.Token; const clang = @import("clang.zig"); const ctok = std.c.tokenizer; const CToken = std.c.Token; const mem = std.mem; const math = std.math; const Type = @import("type.zig").Type; +const ast = @import("translate_c/ast.zig"); +const Node = ast.Node; const CallingConvention = std.builtin.CallingConvention; @@ -348,47 +348,6 @@ pub const Context = struct { } }; -fn addCBuiltinsNamespace(c: *Context) Error!void { - // pub usingnamespace @import("std").c.builtins; - const pub_tok = try appendToken(c, .Keyword_pub, "pub"); - const use_tok = try appendToken(c, .Keyword_usingnamespace, "usingnamespace"); - const import_tok = try appendToken(c, .Builtin, "@import"); - const lparen_tok = try appendToken(c, .LParen, "("); - const std_tok = try appendToken(c, .StringLiteral, "\"std\""); - const rparen_tok = try appendToken(c, .RParen, ")"); - - const std_node = try c.arena.create(ast.Node.OneToken); - std_node.* = .{ - .base = .{ .tag = .StringLiteral }, - .token = std_tok, - }; - - const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1); - call_node.* = .{ - .builtin_token = import_tok, - .params_len = 1, - .rparen_token = rparen_tok, - }; - call_node.params()[0] = &std_node.base; - - var access_chain = &call_node.base; - access_chain = try transCreateNodeFieldAccess(c, access_chain, "c"); - access_chain = try transCreateNodeFieldAccess(c, access_chain, "builtins"); - - const semi_tok = try appendToken(c, .Semicolon, ";"); - - const bytes = try c.gpa.alignedAlloc(u8, @alignOf(ast.Node.Use), @sizeOf(ast.Node.Use)); - const using_node = @ptrCast(*ast.Node.Use, bytes.ptr); - using_node.* = .{ - .doc_comments = null, - .visib_token = pub_tok, - .use_token = use_tok, - .expr = access_chain, - .semicolon_token = semi_tok, - }; - try c.root_decls.append(c.gpa, &using_node.base); -} - pub fn translate( gpa: *mem.Allocator, args_begin: [*]?[*]const u8, @@ -446,7 +405,7 @@ pub fn translate( context.opaque_demotes.deinit(gpa); } - try addCBuiltinsNamespace(&context); + _ = try Node.usingnamespace_builtins.init(); try prepopulateGlobalNameTable(ast_unit, &context); @@ -1318,26 +1277,6 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node return transCreateNodeIdentifier(c, name); } -fn createAlias(c: *Context, alias: anytype) !void { - const visib_tok = try appendToken(c, .Keyword_pub, "pub"); - const mut_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, alias.alias); - const eq_token = try appendToken(c, .Equal, "="); - const init_node = try transCreateNodeIdentifier(c, alias.name); - const semicolon_token = try appendToken(c, .Semicolon, ";"); - - const node = try ast.Node.VarDecl.create(c.arena, .{ - .name_token = name_tok, - .mut_token = mut_tok, - .semicolon_token = semicolon_token, - }, .{ - .visib_token = visib_tok, - .eq_token = eq_token, - .init_node = init_node, - }); - return addTopLevelDecl(c, alias.alias, &node.base); -} - const ResultUsed = enum { used, unused, @@ -1349,78 +1288,63 @@ const LRValue = enum { }; fn transStmt( - rp: RestorePoint, + c: *Context, scope: *Scope, stmt: *const clang.Stmt, result_used: ResultUsed, lrvalue: LRValue, -) TransError!*ast.Node { +) TransError!Node { const sc = stmt.getStmtClass(); switch (sc) { - .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used), - .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const clang.CompoundStmt, stmt)), - .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue), - .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const clang.DeclStmt, stmt)), - .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue), - .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used), - .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as), - .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const clang.ReturnStmt, stmt)), - .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used), + .BinaryOperatorClass => return transBinaryOperator(c, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used), + .CompoundStmtClass => return transCompoundStmt(c, scope, @ptrCast(*const clang.CompoundStmt, stmt)), + .CStyleCastExprClass => return transCStyleCastExprClass(c, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue), + .DeclStmtClass => return transDeclStmt(c, scope, @ptrCast(*const clang.DeclStmt, stmt)), + .DeclRefExprClass => return transDeclRefExpr(c, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue), + .ImplicitCastExprClass => return transImplicitCastExpr(c, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used), + .IntegerLiteralClass => return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as), + .ReturnStmtClass => return transReturnStmt(c, scope, @ptrCast(*const clang.ReturnStmt, stmt)), + .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used), .ParenExprClass => { - const expr = try transExpr(rp, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue); - if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); - const node = try rp.c.arena.create(ast.Node.GroupedExpression); - node.* = .{ - .lparen = try appendToken(rp.c, .LParen, "("), - .expr = expr, - .rparen = try appendToken(rp.c, .RParen, ")"), - }; - return maybeSuppressResult(rp, scope, result_used, &node.base); + const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue); + return maybeSuppressResult(c, scope, result_used, expr); }, - .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used), - .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used), - .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const clang.IfStmt, stmt)), - .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const clang.WhileStmt, stmt)), - .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const clang.DoStmt, stmt)), + .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used), + .ImplicitValueInitExprClass => return transImplicitValueInitExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used), + .IfStmtClass => return transIfStmt(c, scope, @ptrCast(*const clang.IfStmt, stmt)), + .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)), + .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)), .NullStmtClass => { - const block = try rp.c.createBlock(0); - block.rbrace = try appendToken(rp.c, .RBrace, "}"); - return &block.base; + return Node.empty_block.init(); }, - .ContinueStmtClass => return try transCreateNodeContinue(rp.c), - .BreakStmtClass => return transBreak(rp, scope), - .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const clang.ForStmt, stmt)), - .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used), + .ContinueStmtClass => return try transCreateNodeContinue(c), + .BreakStmtClass => return transBreak(c, scope), + .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)), + .FloatingLiteralClass => return transFloatingLiteral(c, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used), .ConditionalOperatorClass => { - return transConditionalOperator(rp, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used); + return transConditionalOperator(c, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used); }, .BinaryConditionalOperatorClass => { - return transBinaryConditionalOperator(rp, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used); + return transBinaryConditionalOperator(c, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used); }, - .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const clang.SwitchStmt, stmt)), - .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const clang.CaseStmt, stmt)), - .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const clang.DefaultStmt, stmt)), - .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used), - .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used), - .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as), - .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used), - .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used), - .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used), - .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const clang.CallExpr, stmt), result_used), - .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used), - .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used), - .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used), + .SwitchStmtClass => return transSwitch(c, scope, @ptrCast(*const clang.SwitchStmt, stmt)), + .CaseStmtClass => return transCase(c, scope, @ptrCast(*const clang.CaseStmt, stmt)), + .DefaultStmtClass => return transDefault(c, scope, @ptrCast(*const clang.DefaultStmt, stmt)), + .ConstantExprClass => return transConstantExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used), + .PredefinedExprClass => return transPredefinedExpr(c, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used), + .CharacterLiteralClass => return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as), + .StmtExprClass => return transStmtExpr(c, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used), + .MemberExprClass => return transMemberExpr(c, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used), + .ArraySubscriptExprClass => return transArrayAccess(c, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used), + .CallExprClass => return transCallExpr(c, scope, @ptrCast(*const clang.CallExpr, stmt), result_used), + .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(c, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used), + .UnaryOperatorClass => return transUnaryOperator(c, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used), + .CompoundAssignOperatorClass => return transCompoundAssignOperator(c, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used), .OpaqueValueExprClass => { const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?; - const expr = try transExpr(rp, scope, source_expr, .used, lrvalue); - if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); - const node = try rp.c.arena.create(ast.Node.GroupedExpression); - node.* = .{ - .lparen = try appendToken(rp.c, .LParen, "("), - .expr = expr, - .rparen = try appendToken(rp.c, .RParen, ")"), - }; - return maybeSuppressResult(rp, scope, result_used, &node.base); + const expr = try transExpr(c, scope, source_expr, .used, lrvalue); + return maybeSuppressResult(c, scope, result_used, expr); + const node = try c.arena.create(Node.GroupedExpression); }, else => { return revertAndWarn( @@ -1435,175 +1359,139 @@ fn transStmt( } fn transBinaryOperator( - rp: RestorePoint, + c: *Context, scope: *Scope, stmt: *const clang.BinaryOperator, result_used: ResultUsed, -) TransError!*ast.Node { +) TransError!Node { const op = stmt.getOpcode(); const qt = stmt.getType(); - var op_token: ast.TokenIndex = undefined; - var op_id: ast.Node.Tag = undefined; switch (op) { - .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()), + .Assign => return try transCreateNodeAssign(c, scope, result_used, stmt.getLHS(), stmt.getRHS()), .Comma => { var block_scope = try Scope.Block.init(rp.c, scope, true); - const lparen = try appendToken(rp.c, .LParen, "("); + defer block_scope.deinit(); - const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value); + + const lhs = try transExpr(c, &block_scope.base, stmt.getLHS(), .unused, .r_value); try block_scope.statements.append(lhs); const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value); - _ = try appendToken(rp.c, .Semicolon, ";"); - const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs); - try block_scope.statements.append(&break_node.base); + const break_node = try Node.break_val.create(c.arena, .{ + .label = block_scope.label, + .val = rhs, + }); + try block_scope.statements.append(break_node); const block_node = try block_scope.complete(rp.c); - const rparen = try appendToken(rp.c, .RParen, ")"); - const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); - grouped_expr.* = .{ - .lparen = lparen, - .expr = block_node, - .rparen = rparen, - }; - return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); + return maybeSuppressResult(rp, scope, result_used, block_node); }, .Div => { if (cIsSignedInteger(qt)) { // signed integer division uses @divTrunc - const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2); - div_trunc_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value); - _ = try appendToken(rp.c, .Comma, ","); - const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value); - div_trunc_node.params()[1] = rhs; - div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); + const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); + const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); + const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs}); + return maybeSuppressResult(c, scope, result_used, div_trunc); } }, .Rem => { if (cIsSignedInteger(qt)) { // signed integer division uses @rem - const rem_node = try rp.c.createBuiltinCall("@rem", 2); - rem_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value); - _ = try appendToken(rp.c, .Comma, ","); - const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value); - rem_node.params()[1] = rhs; - rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, &rem_node.base); + const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); + const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); + const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs}); + return maybeSuppressResult(c, scope, result_used, rem); } }, .Shl => { - const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<"); - return maybeSuppressResult(rp, scope, result_used, node); + const node = try transCreateNodeShiftOp(c, scope, stmt, .shl); + return maybeSuppressResult(c, scope, result_used, node); }, .Shr => { - const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>"); - return maybeSuppressResult(rp, scope, result_used, node); - }, - .LAnd => { - const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true); - return maybeSuppressResult(rp, scope, result_used, node); - }, - .LOr => { - const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true); - return maybeSuppressResult(rp, scope, result_used, node); + const node = try transCreateNodeShiftOp(c, scope, stmt, .shr); + return maybeSuppressResult(c, scope, result_used, node); }, else => {}, } - const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value); + var op_id: Node.Tag = undefined; switch (op) { .Add => { if (cIsUnsignedInteger(qt)) { - op_token = try appendToken(rp.c, .PlusPercent, "+%"); - op_id = .AddWrap; + op_id = .add_wrap; } else { - op_token = try appendToken(rp.c, .Plus, "+"); - op_id = .Add; + op_id = .add; } }, .Sub => { if (cIsUnsignedInteger(qt)) { - op_token = try appendToken(rp.c, .MinusPercent, "-%"); - op_id = .SubWrap; + op_id = .sub_wrap; } else { - op_token = try appendToken(rp.c, .Minus, "-"); - op_id = .Sub; + op_id = .sub; } }, .Mul => { if (cIsUnsignedInteger(qt)) { - op_token = try appendToken(rp.c, .AsteriskPercent, "*%"); - op_id = .MulWrap; + op_id = .mul_wrap; } else { - op_token = try appendToken(rp.c, .Asterisk, "*"); - op_id = .Mul; + op_id = .mul; } }, .Div => { // unsigned/float division uses the operator - op_id = .Div; - op_token = try appendToken(rp.c, .Slash, "/"); + op_id = .div; }, .Rem => { // unsigned/float division uses the operator - op_id = .Mod; - op_token = try appendToken(rp.c, .Percent, "%"); + op_id = .mod; }, .LT => { - op_id = .LessThan; - op_token = try appendToken(rp.c, .AngleBracketLeft, "<"); + op_id = .less_than; }, .GT => { - op_id = .GreaterThan; - op_token = try appendToken(rp.c, .AngleBracketRight, ">"); + op_id = .greater_than; }, .LE => { - op_id = .LessOrEqual; - op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<="); + op_id = .less_than_equal; }, .GE => { - op_id = .GreaterOrEqual; - op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">="); + op_id = .greater_than_equal; }, .EQ => { - op_id = .EqualEqual; - op_token = try appendToken(rp.c, .EqualEqual, "=="); + op_id = .equal; }, .NE => { - op_id = .BangEqual; - op_token = try appendToken(rp.c, .BangEqual, "!="); + op_id = .not_equal; }, .And => { - op_id = .BitAnd; - op_token = try appendToken(rp.c, .Ampersand, "&"); + op_id = .bit_and; }, .Xor => { - op_id = .BitXor; - op_token = try appendToken(rp.c, .Caret, "^"); + op_id = .bit_xor; }, .Or => { - op_id = .BitOr; - op_token = try appendToken(rp.c, .Pipe, "|"); + op_id = .bit_or; + }, + .LAnd => { + op_id = .@"and"; + }, + .LOr => { + op_id = .@"or"; }, else => unreachable, } - const rhs_node = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value); + const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); + const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); - const lhs = if (isBoolRes(lhs_node)) init: { - const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1); - cast_node.params()[0] = lhs_node; - cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - break :init &cast_node.base; - } else lhs_node; - - const rhs = if (isBoolRes(rhs_node)) init: { - const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1); - cast_node.params()[0] = rhs_node; - cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - break :init &cast_node.base; - } else rhs_node; - - return transCreateNodeInfixOp(rp, scope, lhs, op_id, op_token, rhs, result_used, true); + const payload = try c.arena.create(ast.Payload.BinOp); + payload.* = .{ + .base = .{ .tag = op_id }, + .data = .{ + .lhs = lhs, + .rhs = rhs, + }, + }; + return maybeSuppressResult(c, scope, used, &payload.base); } fn transCompoundStmtInline( @@ -2365,40 +2253,13 @@ fn transEnumToInt(c: *Context, enum_expr: *ast.Node) TypeError!*ast.Node { } fn transExpr( - rp: RestorePoint, + c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed, lrvalue: LRValue, -) TransError!*ast.Node { - return transStmt(rp, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue); -} - -/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore -/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals. -fn transExprCoercing( - rp: RestorePoint, - scope: *Scope, - expr: *const clang.Expr, - used: ResultUsed, - lrvalue: LRValue, -) TransError!*ast.Node { - switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) { - .IntegerLiteralClass => { - return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as); - }, - .CharacterLiteralClass => { - return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, expr), .used, .no_as); - }, - .UnaryOperatorClass => { - const un_expr = @ptrCast(*const clang.UnaryOperator, expr); - if (un_expr.getOpcode() == .Extension) { - return transExprCoercing(rp, scope, un_expr.getSubExpr(), used, lrvalue); - } - }, - else => {}, - } - return transExpr(rp, scope, expr, .used, .r_value); +) TransError!Node { + return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue); } fn transInitListExprRecord( @@ -4150,7 +4011,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool { return qualTypeCanon(qt).isBooleanType(); } -fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 { +fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 { const ty = qt.getTypePtr(); switch (ty.getTypeClass()) { @@ -4174,7 +4035,7 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S .Typedef => { const typedef_ty = @ptrCast(*const clang.TypedefType, ty); const typedef_decl = typedef_ty.getDecl(); - const type_name = try rp.c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin()); + const type_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin()); if (mem.eql(u8, type_name, "uint8_t") or mem.eql(u8, type_name, "int8_t")) { return 8; @@ -4194,51 +4055,17 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S unreachable; } -fn qualTypeToLog2IntRef(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !*ast.Node { - const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc); +fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !Node { + const int_bit_width = try qualTypeIntBitWidth(c, qt, source_loc); if (int_bit_width != 0) { // we can perform the log2 now. const cast_bit_width = math.log2_int(u64, int_bit_width); - const node = try rp.c.arena.create(ast.Node.OneToken); - node.* = .{ - .base = .{ .tag = .IntegerLiteral }, - .token = try appendTokenFmt(rp.c, .Identifier, "u{d}", .{cast_bit_width}), - }; - return &node.base; + return Node.uint_type.create(c.arena, cast_bit_width); } - const zig_type_node = try transQualType(rp, qt, source_loc); - - // @import("std").math.Log2Int(c_long); - // - // FnCall - // FieldAccess - // FieldAccess - // FnCall (.builtin = true) - // Symbol "import" - // StringLiteral "std" - // Symbol "math" - // Symbol "Log2Int" - // Symbol (var from above) - - const import_fn_call = try rp.c.createBuiltinCall("@import", 1); - const std_token = try appendToken(rp.c, .StringLiteral, "\"std\""); - const std_node = try rp.c.arena.create(ast.Node.OneToken); - std_node.* = .{ - .base = .{ .tag = .StringLiteral }, - .token = std_token, - }; - import_fn_call.params()[0] = &std_node.base; - import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); - - const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); - const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int"); - const log2int_fn_call = try rp.c.createCall(outer_field_access, 1); - log2int_fn_call.params()[0] = zig_type_node; - log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); - - return &log2int_fn_call.base; + const zig_type = try transQualType(c, qt, source_loc); + return Node.std_math_Log2Int.create(c.arena, zig_type); } fn qualTypeChildIsFnProto(qt: clang.QualType) bool { @@ -4506,67 +4333,6 @@ fn transCreateNodeSimplePrefixOp( return node; } -fn transCreateNodeInfixOp( - rp: RestorePoint, - scope: *Scope, - lhs_node: *ast.Node, - op: ast.Node.Tag, - op_token: ast.TokenIndex, - rhs_node: *ast.Node, - used: ResultUsed, - grouped: bool, -) !*ast.Node { - var lparen = if (grouped) - try appendToken(rp.c, .LParen, "(") - else - null; - const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); - node.* = .{ - .base = .{ .tag = op }, - .op_token = op_token, - .lhs = lhs_node, - .rhs = rhs_node, - }; - if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base); - const rparen = try appendToken(rp.c, .RParen, ")"); - const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); - grouped_expr.* = .{ - .lparen = lparen.?, - .expr = &node.base, - .rparen = rparen, - }; - return maybeSuppressResult(rp, scope, used, &grouped_expr.base); -} - -fn transCreateNodeBoolInfixOp( - rp: RestorePoint, - scope: *Scope, - stmt: *const clang.BinaryOperator, - op: ast.Node.Tag, - used: ResultUsed, - grouped: bool, -) !*ast.Node { - std.debug.assert(op == .BoolAnd or op == .BoolOr); - - const lhs_hode = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value, true); - const op_token = if (op == .BoolAnd) - try appendToken(rp.c, .Keyword_and, "and") - else - try appendToken(rp.c, .Keyword_or, "or"); - const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value, true); - - return transCreateNodeInfixOp( - rp, - scope, - lhs_hode, - op, - op_token, - rhs, - used, - grouped, - ); -} - fn transCreateNodePtrType( c: *Context, is_const: bool, @@ -4968,40 +4734,33 @@ fn transCreateNodeSwitchElse(c: *Context) !*ast.Node { } fn transCreateNodeShiftOp( - rp: RestorePoint, + c: *Context, scope: *Scope, stmt: *const clang.BinaryOperator, - op: ast.Node.Tag, - op_tok_id: std.zig.Token.Id, - bytes: []const u8, -) !*ast.Node { - std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight); + op: Node.Tag, +) !Node { + std.debug.assert(op == .shl or op == .shr); const lhs_expr = stmt.getLHS(); const rhs_expr = stmt.getRHS(); const rhs_location = rhs_expr.getBeginLoc(); // lhs >> @as(u5, rh) - const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value); - const op_token = try appendToken(rp.c, op_tok_id, bytes); + const lhs = try transExpr(c, scope, lhs_expr, .used, .l_value); - const cast_node = try rp.c.createBuiltinCall("@intCast", 2); - const rhs_type = try qualTypeToLog2IntRef(rp, stmt.getType(), rhs_location); - cast_node.params()[0] = rhs_type; - _ = try appendToken(rp.c, .Comma, ","); - const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value); - cast_node.params()[1] = rhs; - cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location); + const rhs = try transExpr(c, scope, rhs_expr, .used, .r_value); + const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type }); - const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); - node.* = .{ + const payload = try c.arena.create(ast.Payload.BinOp); + payload.* = .{ .base = .{ .tag = op }, - .op_token = op_token, - .lhs = lhs, - .rhs = &cast_node.base, + .data = .{ + .lhs = lhs, + .rhs = rhs_casted, + } }; - - return &node.base; + return &payload.base; } fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { @@ -5025,161 +4784,7 @@ fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAcces return node; } -const RestorePoint = struct { - c: *Context, - token_index: ast.TokenIndex, - src_buf_index: usize, - - fn activate(self: RestorePoint) void { - self.c.token_ids.shrinkAndFree(self.c.gpa, self.token_index); - self.c.token_locs.shrinkAndFree(self.c.gpa, self.token_index); - self.c.source_buffer.shrinkAndFree(self.src_buf_index); - } -}; - -fn makeRestorePoint(c: *Context) RestorePoint { - return RestorePoint{ - .c = c, - .token_index = c.token_ids.items.len, - .src_buf_index = c.source_buffer.items.len, - }; -} - -fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!*ast.Node { - switch (ty.getTypeClass()) { - .Builtin => { - const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); - return transCreateNodeIdentifier(rp.c, switch (builtin_ty.getKind()) { - .Void => "c_void", - .Bool => "bool", - .Char_U, .UChar, .Char_S, .Char8 => "u8", - .SChar => "i8", - .UShort => "c_ushort", - .UInt => "c_uint", - .ULong => "c_ulong", - .ULongLong => "c_ulonglong", - .Short => "c_short", - .Int => "c_int", - .Long => "c_long", - .LongLong => "c_longlong", - .UInt128 => "u128", - .Int128 => "i128", - .Float => "f32", - .Double => "f64", - .Float128 => "f128", - .Float16 => "f16", - .LongDouble => "c_longdouble", - else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), - }); - }, - .FunctionProto => { - const fn_proto_ty = @ptrCast(*const clang.FunctionProtoType, ty); - const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); - return &fn_proto.base; - }, - .FunctionNoProto => { - const fn_no_proto_ty = @ptrCast(*const clang.FunctionType, ty); - const fn_proto = try transFnNoProto(rp, fn_no_proto_ty, source_loc, null, false); - return &fn_proto.base; - }, - .Paren => { - const paren_ty = @ptrCast(*const clang.ParenType, ty); - return transQualType(rp, paren_ty.getInnerType(), source_loc); - }, - .Pointer => { - const child_qt = ty.getPointeeType(); - if (qualTypeChildIsFnProto(child_qt)) { - const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?"); - optional_node.rhs = try transQualType(rp, child_qt, source_loc); - return &optional_node.base; - } - if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) { - const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?"); - const pointer_node = try transCreateNodePtrType( - rp.c, - child_qt.isConstQualified(), - child_qt.isVolatileQualified(), - .Asterisk, - ); - optional_node.rhs = &pointer_node.base; - pointer_node.rhs = try transQualType(rp, child_qt, source_loc); - return &optional_node.base; - } - const pointer_node = try transCreateNodePtrType( - rp.c, - child_qt.isConstQualified(), - child_qt.isVolatileQualified(), - .Identifier, - ); - pointer_node.rhs = try transQualType(rp, child_qt, source_loc); - return &pointer_node.base; - }, - .ConstantArray => { - const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty); - - const size_ap_int = const_arr_ty.getSize(); - const size = size_ap_int.getLimitedValue(math.maxInt(usize)); - const elem_ty = const_arr_ty.getElementType().getTypePtr(); - return try transCreateNodeArrayType(rp, source_loc, elem_ty, size); - }, - .IncompleteArray => { - const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty); - - const child_qt = incomplete_array_ty.getElementType(); - var node = try transCreateNodePtrType( - rp.c, - child_qt.isConstQualified(), - child_qt.isVolatileQualified(), - .Identifier, - ); - node.rhs = try transQualType(rp, child_qt, source_loc); - return &node.base; - }, - .Typedef => { - const typedef_ty = @ptrCast(*const clang.TypedefType, ty); - - const typedef_decl = typedef_ty.getDecl(); - return (try transTypeDef(rp.c, typedef_decl, false)) orelse - revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{}); - }, - .Record => { - const record_ty = @ptrCast(*const clang.RecordType, ty); - - const record_decl = record_ty.getDecl(); - return (try transRecordDecl(rp.c, record_decl)) orelse - revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{}); - }, - .Enum => { - const enum_ty = @ptrCast(*const clang.EnumType, ty); - - const enum_decl = enum_ty.getDecl(); - return (try transEnumDecl(rp.c, enum_decl)) orelse - revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{}); - }, - .Elaborated => { - const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty); - return transQualType(rp, elaborated_ty.getNamedType(), source_loc); - }, - .Decayed => { - const decayed_ty = @ptrCast(*const clang.DecayedType, ty); - return transQualType(rp, decayed_ty.getDecayedType(), source_loc); - }, - .Attributed => { - const attributed_ty = @ptrCast(*const clang.AttributedType, ty); - return transQualType(rp, attributed_ty.getEquivalentType(), source_loc); - }, - .MacroQualified => { - const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty); - return transQualType(rp, macroqualified_ty.getModifiedType(), source_loc); - }, - else => { - const type_name = rp.c.str(ty.getTypeClassName()); - return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); - }, - } -} - -fn transType1(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Type { +fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Type { switch (ty.getTypeClass()) { .Builtin => { const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 0585c26d18..3ceccf16b8 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -1,7 +1,7 @@ const std = @import("std"); const Type = @import("../type.zig").Type; -pub const Node = struct { +pub const Node = extern union { /// If the tag value is less than Tag.no_payload_count, then no pointer /// dereference is needed. tag_if_small_enough: usize, @@ -13,12 +13,15 @@ pub const Node = struct { opaque_literal, true_literal, false_literal, + empty_block, + /// pub usingnamespace @import("std").c.builtins; + usingnamespace_builtins, // After this, the tag requires a payload. - int, - float, - string, - char, + int_literal, + float_literal, + string_literal, + char_literal, identifier, @"if", @"while", @@ -44,6 +47,67 @@ pub const Node = struct { discard, block, + // a + b + add, + // a = b + add_assign, + // c = (a = b) + add_assign_value, + add_wrap, + add_wrap_assign, + add_wrap_assign_value, + sub, + sub_assign, + sub_assign_value, + sub_wrap, + sub_wrap_assign, + sub_wrap_assign_value, + mul, + mul_assign, + mul_assign_value, + mul_wrap, + mul_wrap_assign, + mul_wrap_assign_value, + div, + div_assign, + div_assign_value, + shl, + shl_assign, + shl_assign_value, + shr, + shr_assign, + shr_assign_value, + mod, + mod_assign, + mod_assign_value, + @"and", + and_assign, + and_assign_value, + @"or", + or_assign, + or_assign_value, + xor, + xor_assign, + xor_assign_value, + less_than, + less_than_equal, + greater_than, + greater_than_equal, + equal, + not_equal, + bit_and, + bit_or, + bit_xor, + + /// @import("std").math.Log2Int(operand) + std_math_Log2Int, + /// @intCast(lhs, rhs) + int_cast, + /// @rem(lhs, rhs) + rem, + /// @divTrunc(lhs, rhs) + div_trunc, + pub const last_no_payload_tag = Tag.false_literal; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -54,8 +118,70 @@ pub const Node = struct { .opaque_literal, .true_literal, .false_litral, + .empty_block, + .usingnamespace_builtins, => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), + .array_access, + .std_mem_zeroes, + .@"return", + .discard, + .std_math_Log2Int, + => Payload.UnOp, + + .add, + .add_assign, + .add_assign_value, + .add_wrap, + .add_wrap_assign, + .add_wrap_assign_value, + .sub, + .sub_assign, + .sub_assign_value, + .sub_wrap, + .sub_wrap_assign, + .sub_wrap_assign_value, + .mul, + .mul_assign, + .mul_assign_value, + .mul_wrap, + .mul_wrap_assign, + .mul_wrap_assign_value, + .div, + .div_assign, + .div_assign_value, + .shl, + .shl_assign, + .shl_assign_value, + .shr, + .shr_assign, + .shr_assign_value, + .mod, + .mod_assign, + .mod_assign_value, + .@"and", + .and_assign, + .and_assign_value, + .@"or", + .or_assign, + .or_assign_value, + .xor, + .xor_assign, + .xor_assign_value, + .less_than, + .less_than_equal, + .greater_than, + .greater_than_equal, + .equal, + .not_equal, + .bit_and, + .bit_or, + .bit_xor, + .div_trunc, + .rem, + .int_cast, + => Payload.BinOp, + .int, .float, .string, @@ -71,11 +197,6 @@ pub const Node = struct { .@"switch" => Payload.Switch, .@"break" => Payload.Break, .call => Payload.Call, - .array_access, - .std_mem_zeroes, - .@"return", - .discard, - => Payload.SingleArg, .var_decl => Payload.VarDecl, .func => Payload.Func, .@"enum" => Payload.Enum, @@ -123,11 +244,19 @@ pub const Payload = struct { data: []const u8, }; - pub const SingleArg = struct { + pub const UnOp = struct { base: Node, data: *Node, }; + pub const BinOp = struct { + base: Node, + data: struct { + lhs: *Node, + rhs: *Node, + }, + }; + pub const If = struct { base: Node = .{ .tag = .@"if" }, data: struct {