diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index ffa8f434a3e0..47933917b14d 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -581,7 +581,7 @@ pub const Node = struct { } pub const Root = struct { - base: Node, + base: Node = Node {.id = .Root}, decls: DeclList, eof_token: TokenIndex, @@ -604,7 +604,7 @@ pub const Node = struct { }; pub const VarDecl = struct { - base: Node, + base: Node = Node {.id = .VarDecl}, doc_comments: ?*DocComment, visib_token: ?TokenIndex, thread_local_token: ?TokenIndex, @@ -661,7 +661,7 @@ pub const Node = struct { }; pub const Use = struct { - base: Node, + base: Node = Node {.id = .Use}, doc_comments: ?*DocComment, visib_token: ?TokenIndex, use_token: TokenIndex, @@ -688,7 +688,7 @@ pub const Node = struct { }; pub const ErrorSetDecl = struct { - base: Node, + base: Node = Node {.id = .ErrorSetDecl}, error_token: TokenIndex, decls: DeclList, rbrace_token: TokenIndex, @@ -714,7 +714,7 @@ pub const Node = struct { }; pub const ContainerDecl = struct { - base: Node, + base: Node = Node {.id = .ContainerDecl}, layout_token: ?TokenIndex, kind_token: TokenIndex, init_arg_expr: InitArg, @@ -801,7 +801,7 @@ pub const Node = struct { }; pub const ErrorTag = struct { - base: Node, + base: Node = Node {.id = .ErrorTag}, doc_comments: ?*DocComment, name_token: TokenIndex, @@ -826,7 +826,7 @@ pub const Node = struct { }; pub const Identifier = struct { - base: Node, + base: Node = Node {.id = .Identifier}, token: TokenIndex, pub fn iterate(self: *Identifier, index: usize) ?*Node { @@ -843,7 +843,7 @@ pub const Node = struct { }; pub const FnProto = struct { - base: Node, + base: Node = Node {.id = .FnProto}, doc_comments: ?*DocComment, visib_token: ?TokenIndex, fn_token: TokenIndex, @@ -925,7 +925,7 @@ pub const Node = struct { }; pub const AnyFrameType = struct { - base: Node, + base: Node = Node {.id = .AnyFrameType}, anyframe_token: TokenIndex, result: ?Result, @@ -956,7 +956,7 @@ pub const Node = struct { }; pub const ParamDecl = struct { - base: Node, + base: Node = Node {.id = .ParamDecl}, doc_comments: ?*DocComment, comptime_token: ?TokenIndex, noalias_token: ?TokenIndex, @@ -989,7 +989,7 @@ pub const Node = struct { }; pub const Block = struct { - base: Node, + base: Node = Node {.id = .Block}, label: ?TokenIndex, lbrace: TokenIndex, statements: StatementList, @@ -1020,7 +1020,7 @@ pub const Node = struct { }; pub const Defer = struct { - base: Node, + base: Node = Node {.id = .Defer}, defer_token: TokenIndex, expr: *Node, @@ -1043,7 +1043,7 @@ pub const Node = struct { }; pub const Comptime = struct { - base: Node, + base: Node = Node {.id = .Comptime}, doc_comments: ?*DocComment, comptime_token: TokenIndex, expr: *Node, @@ -1067,7 +1067,7 @@ pub const Node = struct { }; pub const Payload = struct { - base: Node, + base: Node = Node {.id = .Payload}, lpipe: TokenIndex, error_symbol: *Node, rpipe: TokenIndex, @@ -1091,7 +1091,7 @@ pub const Node = struct { }; pub const PointerPayload = struct { - base: Node, + base: Node = Node {.id = .PointerPayload}, lpipe: TokenIndex, ptr_token: ?TokenIndex, value_symbol: *Node, @@ -1116,7 +1116,7 @@ pub const Node = struct { }; pub const PointerIndexPayload = struct { - base: Node, + base: Node = Node {.id = .PointerIndexPayload}, lpipe: TokenIndex, ptr_token: ?TokenIndex, value_symbol: *Node, @@ -1147,7 +1147,7 @@ pub const Node = struct { }; pub const Else = struct { - base: Node, + base: Node = Node {.id = .Else}, else_token: TokenIndex, payload: ?*Node, body: *Node, @@ -1176,7 +1176,7 @@ pub const Node = struct { }; pub const Switch = struct { - base: Node, + base: Node = Node {.id = .Switch}, switch_token: TokenIndex, expr: *Node, @@ -1208,7 +1208,7 @@ pub const Node = struct { }; pub const SwitchCase = struct { - base: Node, + base: Node = Node {.id = .SwitchCase}, items: ItemList, arrow_token: TokenIndex, payload: ?*Node, @@ -1243,7 +1243,7 @@ pub const Node = struct { }; pub const SwitchElse = struct { - base: Node, + base: Node = Node {.id = .SwitchElse}, token: TokenIndex, pub fn iterate(self: *SwitchElse, index: usize) ?*Node { @@ -1260,7 +1260,7 @@ pub const Node = struct { }; pub const While = struct { - base: Node, + base: Node = Node {.id = .While}, label: ?TokenIndex, inline_token: ?TokenIndex, while_token: TokenIndex, @@ -1319,7 +1319,7 @@ pub const Node = struct { }; pub const For = struct { - base: Node, + base: Node = Node {.id = .For}, label: ?TokenIndex, inline_token: ?TokenIndex, for_token: TokenIndex, @@ -1370,7 +1370,7 @@ pub const Node = struct { }; pub const If = struct { - base: Node, + base: Node = Node {.id = .If}, if_token: TokenIndex, condition: *Node, payload: ?*Node, @@ -1413,7 +1413,7 @@ pub const Node = struct { }; pub const InfixOp = struct { - base: Node, + base: Node = Node {.id = .InfixOp}, op_token: TokenIndex, lhs: *Node, op: Op, @@ -1646,7 +1646,7 @@ pub const Node = struct { }; pub const FieldInitializer = struct { - base: Node, + base: Node = Node {.id = .FieldInitializer}, period_token: TokenIndex, name_token: TokenIndex, expr: *Node, @@ -1670,7 +1670,7 @@ pub const Node = struct { }; pub const SuffixOp = struct { - base: Node, + base: Node = Node {.id = .SuffixOp}, lhs: Lhs, op: Op, rtoken: TokenIndex, @@ -1766,7 +1766,7 @@ pub const Node = struct { }; pub const GroupedExpression = struct { - base: Node, + base: Node = Node {.id = .GroupedExpression}, lparen: TokenIndex, expr: *Node, rparen: TokenIndex, @@ -1790,7 +1790,7 @@ pub const Node = struct { }; pub const ControlFlowExpression = struct { - base: Node, + base: Node = Node {.id = .ControlFlowExpression}, ltoken: TokenIndex, kind: Kind, rhs: ?*Node, @@ -1856,7 +1856,7 @@ pub const Node = struct { }; pub const Suspend = struct { - base: Node, + base: Node = Node {.id = .Suspend}, suspend_token: TokenIndex, body: ?*Node, @@ -1885,7 +1885,7 @@ pub const Node = struct { }; pub const IntegerLiteral = struct { - base: Node, + base: Node = Node {.id = .IntegerLiteral}, token: TokenIndex, pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node { @@ -1902,7 +1902,7 @@ pub const Node = struct { }; pub const EnumLiteral = struct { - base: Node, + base: Node = Node {.id = .EnumLiteral}, dot: TokenIndex, name: TokenIndex, @@ -1920,7 +1920,7 @@ pub const Node = struct { }; pub const FloatLiteral = struct { - base: Node, + base: Node = Node {.id = .FloatLiteral}, token: TokenIndex, pub fn iterate(self: *FloatLiteral, index: usize) ?*Node { @@ -1937,7 +1937,7 @@ pub const Node = struct { }; pub const BuiltinCall = struct { - base: Node, + base: Node = Node {.id = .BuiltinCall}, builtin_token: TokenIndex, params: ParamList, rparen_token: TokenIndex, @@ -1963,7 +1963,7 @@ pub const Node = struct { }; pub const StringLiteral = struct { - base: Node, + base: Node = Node {.id = .StringLiteral}, token: TokenIndex, pub fn iterate(self: *StringLiteral, index: usize) ?*Node { @@ -1980,7 +1980,7 @@ pub const Node = struct { }; pub const MultilineStringLiteral = struct { - base: Node, + base: Node = Node {.id = .MultilineStringLiteral}, lines: LineList, pub const LineList = SegmentedList(TokenIndex, 4); @@ -1999,7 +1999,7 @@ pub const Node = struct { }; pub const CharLiteral = struct { - base: Node, + base: Node = Node {.id = .CharLiteral}, token: TokenIndex, pub fn iterate(self: *CharLiteral, index: usize) ?*Node { @@ -2016,7 +2016,7 @@ pub const Node = struct { }; pub const BoolLiteral = struct { - base: Node, + base: Node = Node {.id = .BoolLiteral}, token: TokenIndex, pub fn iterate(self: *BoolLiteral, index: usize) ?*Node { @@ -2033,7 +2033,7 @@ pub const Node = struct { }; pub const NullLiteral = struct { - base: Node, + base: Node = Node {.id = .NullLiteral}, token: TokenIndex, pub fn iterate(self: *NullLiteral, index: usize) ?*Node { @@ -2050,7 +2050,7 @@ pub const Node = struct { }; pub const UndefinedLiteral = struct { - base: Node, + base: Node = Node {.id = .UndefinedLiteral}, token: TokenIndex, pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node { @@ -2067,7 +2067,7 @@ pub const Node = struct { }; pub const AsmOutput = struct { - base: Node, + base: Node = Node {.id = .AsmOutput}, lbracket: TokenIndex, symbolic_name: *Node, constraint: *Node, @@ -2112,7 +2112,7 @@ pub const Node = struct { }; pub const AsmInput = struct { - base: Node, + base: Node = Node {.id = .AsmInput}, lbracket: TokenIndex, symbolic_name: *Node, constraint: *Node, @@ -2144,7 +2144,7 @@ pub const Node = struct { }; pub const Asm = struct { - base: Node, + base: Node = Node {.id = .Asm}, asm_token: TokenIndex, volatile_token: ?TokenIndex, template: *Node, @@ -2179,7 +2179,7 @@ pub const Node = struct { }; pub const Unreachable = struct { - base: Node, + base: Node = Node {.id = .Unreachable}, token: TokenIndex, pub fn iterate(self: *Unreachable, index: usize) ?*Node { @@ -2196,7 +2196,7 @@ pub const Node = struct { }; pub const ErrorType = struct { - base: Node, + base: Node = Node {.id = .ErrorType}, token: TokenIndex, pub fn iterate(self: *ErrorType, index: usize) ?*Node { @@ -2230,7 +2230,7 @@ pub const Node = struct { }; pub const DocComment = struct { - base: Node, + base: Node = Node {.id = .DocComment}, lines: LineList, pub const LineList = SegmentedList(TokenIndex, 4); @@ -2249,7 +2249,7 @@ pub const Node = struct { }; pub const TestDecl = struct { - base: Node, + base: Node = Node {.id = .TestDecl}, doc_comments: ?*DocComment, test_token: TokenIndex, name: *Node, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 2e95a4605d50..bcf0ea01da5f 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -56,7 +56,6 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root { const node = try arena.create(Node.Root); node.* = Node.Root{ - .base = Node{ .id = .Root }, .decls = undefined, .eof_token = undefined, }; @@ -176,7 +175,6 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) const node = try arena.create(Node.DocComment); node.* = Node.DocComment{ - .base = Node{ .id = .DocComment }, .lines = lines, }; return &node.base; @@ -194,7 +192,6 @@ fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const test_node = try arena.create(Node.TestDecl); test_node.* = Node.TestDecl{ - .base = Node{ .id = .TestDecl }, .doc_comments = null, .test_token = test_token, .name = name_node, @@ -217,7 +214,6 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* const comptime_node = try arena.create(Node.Comptime); comptime_node.* = Node.Comptime{ - .base = Node{ .id = .Comptime }, .doc_comments = null, .comptime_token = tok, .expr = block_node, @@ -338,7 +334,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const fn_proto_node = try arena.create(Node.FnProto); fn_proto_node.* = Node.FnProto{ - .base = Node{ .id = .FnProto }, .doc_comments = null, .visib_token = null, .fn_token = fn_token, @@ -389,7 +384,6 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.VarDecl); node.* = Node.VarDecl{ - .base = Node{ .id = .VarDecl }, .doc_comments = null, .visib_token = null, .thread_local_token = null, @@ -477,7 +471,6 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const node = try arena.create(Node.Comptime); node.* = Node.Comptime{ - .base = Node{ .id = .Comptime }, .doc_comments = null, .comptime_token = token, .expr = block_expr, @@ -496,7 +489,6 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const node = try arena.create(Node.Suspend); node.* = Node.Suspend{ - .base = Node{ .id = .Suspend }, .suspend_token = suspend_token, .body = body_node, }; @@ -510,7 +502,6 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No }); const node = try arena.create(Node.Defer); node.* = Node.Defer{ - .base = Node{ .id = .Defer }, .defer_token = token, .expr = expr_node, }; @@ -558,7 +549,6 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = try arena.create(Node.Else); node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = payload, .body = else_body, @@ -652,7 +642,6 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = null, .body = statement_node, @@ -677,7 +666,6 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = null, .body = statement_node, @@ -714,7 +702,6 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = payload, .body = statement_node, @@ -741,7 +728,6 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = payload, .body = statement_node, @@ -870,7 +856,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const expr_node = try parseExpr(arena, it, tree); const node = try arena.create(Node.ControlFlowExpression); node.* = Node.ControlFlowExpression{ - .base = Node{ .id = .ControlFlowExpression }, .ltoken = token, .kind = Node.ControlFlowExpression.Kind{ .Break = label }, .rhs = expr_node, @@ -884,7 +869,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node }); const node = try arena.create(Node.Comptime); node.* = Node.Comptime{ - .base = Node{ .id = .Comptime }, .doc_comments = null, .comptime_token = token, .expr = expr_node, @@ -896,7 +880,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const label = try parseBreakLabel(arena, it, tree); const node = try arena.create(Node.ControlFlowExpression); node.* = Node.ControlFlowExpression{ - .base = Node{ .id = .ControlFlowExpression }, .ltoken = token, .kind = Node.ControlFlowExpression.Kind{ .Continue = label }, .rhs = null, @@ -910,7 +893,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node }); const node = try arena.create(Node.PrefixOp); node.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, .op_token = token, .op = Node.PrefixOp.Op.Resume, .rhs = expr_node, @@ -922,7 +904,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const expr_node = try parseExpr(arena, it, tree); const node = try arena.create(Node.ControlFlowExpression); node.* = Node.ControlFlowExpression{ - .base = Node{ .id = .ControlFlowExpression }, .ltoken = token, .kind = Node.ControlFlowExpression.Kind.Return, .rhs = expr_node, @@ -970,7 +951,6 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const block_node = try arena.create(Node.Block); block_node.* = Node.Block{ - .base = Node{ .id = .Block }, .label = null, .lbrace = lbrace, .statements = statements, @@ -1020,7 +1000,6 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = null, .body = body, @@ -1050,7 +1029,6 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = payload, .body = body, @@ -1102,7 +1080,6 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ - .base = Node{ .id = .SuffixOp }, .lhs = .{ .node = undefined }, // set by caller .op = op, .rtoken = try expectToken(it, tree, .RBrace), @@ -1171,7 +1148,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ - .base = Node{ .id = .SuffixOp }, .lhs = .{ .node = res }, .op = Node.SuffixOp.Op{ .Call = Node.SuffixOp.Op.Call{ @@ -1199,7 +1175,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (try parseFnCallArguments(arena, it, tree)) |params| { const call = try arena.create(Node.SuffixOp); call.* = Node.SuffixOp{ - .base = Node{ .id = .SuffixOp }, .lhs = .{ .node = res }, .op = Node.SuffixOp.Op{ .Call = Node.SuffixOp.Op.Call{ @@ -1248,7 +1223,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N if (eatToken(it, .CharLiteral)) |token| { const node = try arena.create(Node.CharLiteral); node.* = Node.CharLiteral{ - .base = Node{ .id = .CharLiteral }, .token = token, }; return &node.base; @@ -1267,7 +1241,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N const expr = (try parseTypeExpr(arena, it, tree)) orelse return null; const node = try arena.create(Node.Comptime); node.* = Node.Comptime{ - .base = Node{ .id = .Comptime }, .doc_comments = null, .comptime_token = token, .expr = expr, @@ -1282,7 +1255,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N const global_error_set = try createLiteral(arena, Node.ErrorType, token); const node = try arena.create(Node.InfixOp); node.* = Node.InfixOp{ - .base = Node{ .id = .InfixOp }, .op_token = period, .lhs = global_error_set, .op = Node.InfixOp.Op.Period, @@ -1295,7 +1267,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N if (eatToken(it, .Keyword_anyframe)) |token| { const node = try arena.create(Node.AnyFrameType); node.* = Node.AnyFrameType{ - .base = Node{ .id = .AnyFrameType }, .anyframe_token = token, .result = null, }; @@ -1337,7 +1308,6 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = try arena.create(Node.ErrorSetDecl); node.* = Node.ErrorSetDecl{ - .base = Node{ .id = .ErrorSetDecl }, .error_token = error_token, .decls = decls, .rbrace_token = rbrace, @@ -1355,7 +1325,6 @@ fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = try arena.create(Node.GroupedExpression); node.* = Node.GroupedExpression{ - .base = Node{ .id = .GroupedExpression }, .lparen = lparen, .expr = expr, .rparen = rparen, @@ -1438,7 +1407,6 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = null, .body = else_expr, @@ -1469,7 +1437,6 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = null, .body = else_expr, @@ -1495,7 +1462,6 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.Switch); node.* = Node.Switch{ - .base = Node{ .id = .Switch }, .switch_token = switch_token, .expr = expr_node, .cases = cases, @@ -1515,7 +1481,6 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.Asm); node.* = Node.Asm{ - .base = Node{ .id = .Asm }, .asm_token = asm_token, .volatile_token = volatile_token, .template = template, @@ -1538,7 +1503,6 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (eatToken(it, .Identifier)) |name| { const node = try arena.create(Node.EnumLiteral); node.* = Node.EnumLiteral{ - .base = Node{ .id = .EnumLiteral }, .dot = dot, .name = name, }; @@ -1591,7 +1555,6 @@ fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod const node = try arena.create(Node.AsmOutput); node.* = Node.AsmOutput{ - .base = Node{ .id = .AsmOutput }, .lbracket = lbracket, .symbolic_name = name, .constraint = constraint, @@ -1628,7 +1591,6 @@ fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = try arena.create(Node.AsmInput); node.* = Node.AsmInput{ - .base = Node{ .id = .AsmInput }, .lbracket = lbracket, .symbolic_name = name, .constraint = constraint, @@ -1687,7 +1649,6 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.FieldInitializer); node.* = Node.FieldInitializer{ - .base = Node{ .id = .FieldInitializer }, .period_token = period_token, .name_token = name_token, .expr = expr_node, @@ -1760,7 +1721,6 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const param_decl = try arena.create(Node.ParamDecl); param_decl.* = Node.ParamDecl{ - .base = Node{ .id = .ParamDecl }, .doc_comments = doc_comments, .comptime_token = comptime_token, .noalias_token = noalias_token, @@ -1807,7 +1767,6 @@ fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.If); node.* = Node.If{ - .base = Node{ .id = .If }, .if_token = if_token, .condition = condition, .payload = payload, @@ -1832,7 +1791,6 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = try arena.create(Node.While); node.* = Node.While{ - .base = Node{ .id = .While }, .label = null, .inline_token = null, .while_token = while_token, @@ -1861,7 +1819,6 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.For); node.* = Node.For{ - .base = Node{ .id = .For }, .label = null, .inline_token = null, .for_token = for_token, @@ -1883,7 +1840,6 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.Payload); node.* = Node.Payload{ - .base = Node{ .id = .Payload }, .lpipe = lpipe, .error_symbol = identifier, .rpipe = rpipe, @@ -1902,7 +1858,6 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.PointerPayload); node.* = Node.PointerPayload{ - .base = Node{ .id = .PointerPayload }, .lpipe = lpipe, .ptr_token = asterisk, .value_symbol = identifier, @@ -1930,7 +1885,6 @@ fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N const node = try arena.create(Node.PointerIndexPayload); node.* = Node.PointerIndexPayload{ - .base = Node{ .id = .PointerIndexPayload }, .lpipe = lpipe, .ptr_token = asterisk, .value_symbol = identifier, @@ -1972,7 +1926,6 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } else if (eatToken(it, .Keyword_else)) |else_token| { const else_node = try arena.create(Node.SwitchElse); else_node.* = Node.SwitchElse{ - .base = Node{ .id = .SwitchElse }, .token = else_token, }; try list.push(&else_node.base); @@ -1980,7 +1933,6 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.SwitchCase); node.* = Node.SwitchCase{ - .base = Node{ .id = .SwitchCase }, .items = list, .arrow_token = undefined, // set by caller .payload = null, @@ -1999,7 +1951,6 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.InfixOp); node.* = Node.InfixOp{ - .base = Node{ .id = .InfixOp }, .op_token = token, .lhs = expr, .op = Node.InfixOp.Op{ .Range = {} }, @@ -2052,7 +2003,6 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.InfixOp); node.* = Node.InfixOp{ - .base = Node{ .id = .InfixOp }, .op_token = token.index, .lhs = undefined, // set by caller .op = op, @@ -2212,7 +2162,6 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.PrefixOp); node.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, .op_token = token.index, .op = op, .rhs = undefined, @@ -2236,7 +2185,6 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (eatToken(it, .QuestionMark)) |token| { const node = try arena.create(Node.PrefixOp); node.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, .op_token = token, .op = Node.PrefixOp.Op.OptionalType, .rhs = undefined, // set by caller @@ -2255,7 +2203,6 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node }; const node = try arena.create(Node.AnyFrameType); node.* = Node.AnyFrameType{ - .base = Node{ .id = .AnyFrameType }, .anyframe_token = token, .result = Node.AnyFrameType.Result{ .arrow_token = arrow, @@ -2430,7 +2377,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { // this grammar rule be altered? const node = try arena.create(Node.InfixOp); node.* = Node.InfixOp{ - .base = Node{ .id = .InfixOp }, .op_token = period, .lhs = undefined, // set by caller .op = Node.InfixOp.Op.Period, @@ -2452,7 +2398,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ - .base = Node{ .id = .SuffixOp }, .lhs = undefined, // set by caller .op = op_and_token.op, .rtoken = op_and_token.token, @@ -2506,7 +2451,6 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No const node = try arena.create(Node.PrefixOp); node.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, .op_token = lbracket, .op = op, .rhs = undefined, // set by caller @@ -2656,7 +2600,6 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? const node = try arena.create(Node.ContainerDecl); node.* = Node.ContainerDecl{ - .base = Node{ .id = .ContainerDecl }, .layout_token = null, .kind_token = kind_token.index, .init_arg_expr = init_arg_expr, @@ -2729,7 +2672,6 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No const op_token = eatToken(it, token) orelse return null; const node = try arena.create(Node.InfixOp); node.* = Node.InfixOp{ - .base = Node{ .id = .InfixOp }, .op_token = op_token, .lhs = undefined, // set by caller .op = op, @@ -2752,7 +2694,6 @@ fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node }; const node = try arena.create(Node.BuiltinCall); node.* = Node.BuiltinCall{ - .base = Node{ .id = .BuiltinCall }, .builtin_token = token, .params = params.list, .rparen_token = params.rparen, @@ -2766,7 +2707,6 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.ErrorTag); node.* = Node.ErrorTag{ - .base = Node{ .id = .ErrorTag }, .doc_comments = doc_comments, .name_token = token, }; @@ -2777,7 +2717,6 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Identifier) orelse return null; const node = try arena.create(Node.Identifier); node.* = Node.Identifier{ - .base = Node{ .id = .Identifier }, .token = token, }; return &node.base; @@ -2787,7 +2726,6 @@ fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_var) orelse return null; const node = try arena.create(Node.VarType); node.* = Node.VarType{ - .base = Node{ .id = .VarType }, .token = token, }; return &node.base; @@ -2807,7 +2745,6 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod if (eatToken(it, .StringLiteral)) |token| { const node = try arena.create(Node.StringLiteral); node.* = Node.StringLiteral{ - .base = Node{ .id = .StringLiteral }, .token = token, }; return &node.base; @@ -2816,7 +2753,6 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { const node = try arena.create(Node.MultilineStringLiteral); node.* = Node.MultilineStringLiteral{ - .base = Node{ .id = .MultilineStringLiteral }, .lines = Node.MultilineStringLiteral.LineList.init(arena), }; try node.lines.push(first_line); @@ -2833,7 +2769,6 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No const token = eatToken(it, .IntegerLiteral) orelse return null; const node = try arena.create(Node.IntegerLiteral); node.* = Node.IntegerLiteral{ - .base = Node{ .id = .IntegerLiteral }, .token = token, }; return &node.base; @@ -2843,7 +2778,6 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const token = eatToken(it, .FloatLiteral) orelse return null; const node = try arena.create(Node.FloatLiteral); node.* = Node.FloatLiteral{ - .base = Node{ .id = .FloatLiteral }, .token = token, }; return &node.base; @@ -2853,7 +2787,6 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_try) orelse return null; const node = try arena.create(Node.PrefixOp); node.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, .op_token = token, .op = Node.PrefixOp.Op.Try, .rhs = undefined, // set by caller @@ -2865,7 +2798,6 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_usingnamespace) orelse return null; const node = try arena.create(Node.Use); node.* = Node.Use{ - .base = Node{ .id = .Use }, .doc_comments = null, .visib_token = null, .use_token = token, @@ -2891,7 +2823,6 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node }); const else_node = try arena.create(Node.Else); else_node.* = Node.Else{ - .base = Node{ .id = .Else }, .else_token = else_token, .payload = payload, .body = else_expr, @@ -2912,7 +2843,6 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D const node = try arena.create(Node.DocComment); node.* = Node.DocComment{ - .base = Node{ .id = .DocComment }, .lines = lines, }; return node; @@ -2924,7 +2854,6 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a if (tree.tokensOnSameLine(after_token, comment_token)) { const node = try arena.create(Node.DocComment); node.* = Node.DocComment{ - .base = Node{ .id = .DocComment }, .lines = Node.DocComment.LineList.init(arena), }; try node.lines.push(comment_token); @@ -3031,7 +2960,6 @@ fn parseBinOpExpr( fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { const node = try arena.create(Node.InfixOp); node.* = Node.InfixOp{ - .base = Node{ .id = .InfixOp }, .op_token = index, .lhs = undefined, .op = op, diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 9add521c00e5..41b8c48b1094 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -193,6 +193,7 @@ fn renderRoot( fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void { const first_token = node.firstToken(); var prev_token = first_token; + if (prev_token == 0) return; while (tree.tokens.at(prev_token - 1).id == .DocComment) { prev_token -= 1; } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 93fbfa18a78c..eda152710007 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -9,66 +9,77 @@ pub const Token = struct { pub const Keyword = struct { bytes: []const u8, id: Id, + hash: u32, + + fn init(bytes: []const u8, id: Id) Keyword { + @setEvalBranchQuota(2000); + return .{ + .bytes = bytes, + .id = id, + .hash = std.hash_map.hashString(bytes), + }; + } }; pub const keywords = [_]Keyword{ - Keyword{ .bytes = "align", .id = Id.Keyword_align }, - Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero }, - Keyword{ .bytes = "and", .id = Id.Keyword_and }, - Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe }, - Keyword{ .bytes = "asm", .id = Id.Keyword_asm }, - Keyword{ .bytes = "async", .id = Id.Keyword_async }, - Keyword{ .bytes = "await", .id = Id.Keyword_await }, - Keyword{ .bytes = "break", .id = Id.Keyword_break }, - Keyword{ .bytes = "catch", .id = Id.Keyword_catch }, - Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime }, - Keyword{ .bytes = "const", .id = Id.Keyword_const }, - Keyword{ .bytes = "continue", .id = Id.Keyword_continue }, - Keyword{ .bytes = "defer", .id = Id.Keyword_defer }, - Keyword{ .bytes = "else", .id = Id.Keyword_else }, - Keyword{ .bytes = "enum", .id = Id.Keyword_enum }, - Keyword{ .bytes = "errdefer", .id = Id.Keyword_errdefer }, - Keyword{ .bytes = "error", .id = Id.Keyword_error }, - Keyword{ .bytes = "export", .id = Id.Keyword_export }, - Keyword{ .bytes = "extern", .id = Id.Keyword_extern }, - Keyword{ .bytes = "false", .id = Id.Keyword_false }, - Keyword{ .bytes = "fn", .id = Id.Keyword_fn }, - Keyword{ .bytes = "for", .id = Id.Keyword_for }, - Keyword{ .bytes = "if", .id = Id.Keyword_if }, - Keyword{ .bytes = "inline", .id = Id.Keyword_inline }, - Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc }, - Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias }, - Keyword{ .bytes = "noasync", .id = Id.Keyword_noasync }, - Keyword{ .bytes = "noinline", .id = Id.Keyword_noinline }, - Keyword{ .bytes = "null", .id = Id.Keyword_null }, - Keyword{ .bytes = "or", .id = Id.Keyword_or }, - Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse }, - Keyword{ .bytes = "packed", .id = Id.Keyword_packed }, - Keyword{ .bytes = "pub", .id = Id.Keyword_pub }, - Keyword{ .bytes = "resume", .id = Id.Keyword_resume }, - Keyword{ .bytes = "return", .id = Id.Keyword_return }, - Keyword{ .bytes = "linksection", .id = Id.Keyword_linksection }, - Keyword{ .bytes = "stdcallcc", .id = Id.Keyword_stdcallcc }, - Keyword{ .bytes = "struct", .id = Id.Keyword_struct }, - Keyword{ .bytes = "suspend", .id = Id.Keyword_suspend }, - Keyword{ .bytes = "switch", .id = Id.Keyword_switch }, - Keyword{ .bytes = "test", .id = Id.Keyword_test }, - Keyword{ .bytes = "threadlocal", .id = Id.Keyword_threadlocal }, - Keyword{ .bytes = "true", .id = Id.Keyword_true }, - Keyword{ .bytes = "try", .id = Id.Keyword_try }, - Keyword{ .bytes = "undefined", .id = Id.Keyword_undefined }, - Keyword{ .bytes = "union", .id = Id.Keyword_union }, - Keyword{ .bytes = "unreachable", .id = Id.Keyword_unreachable }, - Keyword{ .bytes = "usingnamespace", .id = Id.Keyword_usingnamespace }, - Keyword{ .bytes = "var", .id = Id.Keyword_var }, - Keyword{ .bytes = "volatile", .id = Id.Keyword_volatile }, - Keyword{ .bytes = "while", .id = Id.Keyword_while }, + Keyword.init("align", .Keyword_align), + Keyword.init("allowzero", .Keyword_allowzero), + Keyword.init("and", .Keyword_and), + Keyword.init("anyframe", .Keyword_anyframe), + Keyword.init("asm", .Keyword_asm), + Keyword.init("async", .Keyword_async), + Keyword.init("await", .Keyword_await), + Keyword.init("break", .Keyword_break), + Keyword.init("catch", .Keyword_catch), + Keyword.init("comptime", .Keyword_comptime), + Keyword.init("const", .Keyword_const), + Keyword.init("continue", .Keyword_continue), + Keyword.init("defer", .Keyword_defer), + Keyword.init("else", .Keyword_else), + Keyword.init("enum", .Keyword_enum), + Keyword.init("errdefer", .Keyword_errdefer), + Keyword.init("error", .Keyword_error), + Keyword.init("export", .Keyword_export), + Keyword.init("extern", .Keyword_extern), + Keyword.init("false", .Keyword_false), + Keyword.init("fn", .Keyword_fn), + Keyword.init("for", .Keyword_for), + Keyword.init("if", .Keyword_if), + Keyword.init("inline", .Keyword_inline), + Keyword.init("nakedcc", .Keyword_nakedcc), + Keyword.init("noalias", .Keyword_noalias), + Keyword.init("noasync", .Keyword_noasync), + Keyword.init("noinline", .Keyword_noinline), + Keyword.init("null", .Keyword_null), + Keyword.init("or", .Keyword_or), + Keyword.init("orelse", .Keyword_orelse), + Keyword.init("packed", .Keyword_packed), + Keyword.init("pub", .Keyword_pub), + Keyword.init("resume", .Keyword_resume), + Keyword.init("return", .Keyword_return), + Keyword.init("linksection", .Keyword_linksection), + Keyword.init("stdcallcc", .Keyword_stdcallcc), + Keyword.init("struct", .Keyword_struct), + Keyword.init("suspend", .Keyword_suspend), + Keyword.init("switch", .Keyword_switch), + Keyword.init("test", .Keyword_test), + Keyword.init("threadlocal", .Keyword_threadlocal), + Keyword.init("true", .Keyword_true), + Keyword.init("try", .Keyword_try), + Keyword.init("undefined", .Keyword_undefined), + Keyword.init("union", .Keyword_union), + Keyword.init("unreachable", .Keyword_unreachable), + Keyword.init("usingnamespace", .Keyword_usingnamespace), + Keyword.init("var", .Keyword_var), + Keyword.init("volatile", .Keyword_volatile), + Keyword.init("while", .Keyword_while), }; // TODO perfect hash at comptime - fn getKeyword(bytes: []const u8) ?Id { + pub fn getKeyword(bytes: []const u8) ?Id { + var hash = std.hash_map.hashString(bytes); for (keywords) |kw| { - if (mem.eql(u8, kw.bytes, bytes)) { + if (kw.hash == hash and mem.eql(u8, kw.bytes, bytes)) { return kw.id; } } diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 0313d6e91811..4b3aa44fabaf 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -713,6 +713,10 @@ pub const ZigClangRecordDecl_field_iterator = extern struct { opaque: *c_void, }; +pub const ZigClangEnumDecl_enumerator_iterator = extern struct { + opaque: *c_void, +}; + pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; @@ -723,7 +727,7 @@ pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*st pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool; pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl; -pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl; +pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl; pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl; @@ -742,6 +746,11 @@ pub extern fn ZigClangRecordDecl_field_iterator_next(ZigClangRecordDecl_field_it pub extern fn ZigClangRecordDecl_field_iterator_deref(ZigClangRecordDecl_field_iterator) *const struct_ZigClangFieldDecl; pub extern fn ZigClangRecordDecl_field_iterator_neq(ZigClangRecordDecl_field_iterator, ZigClangRecordDecl_field_iterator) bool; pub extern fn ZigClangEnumDecl_getIntegerType(self: ?*const struct_ZigClangEnumDecl) struct_ZigClangQualType; +pub extern fn ZigClangEnumDecl_enumerator_begin(*const ZigClangEnumDecl) ZigClangEnumDecl_enumerator_iterator; +pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangEnumDecl_enumerator_iterator; +pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator; +pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl; +pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool; pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8; pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool; pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl; @@ -992,6 +1001,8 @@ pub extern fn ZigClangBinaryOperator_getLHS(*const ZigClangBinaryOperator) *cons pub extern fn ZigClangBinaryOperator_getRHS(*const ZigClangBinaryOperator) *const ZigClangExpr; pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigClangQualType; +pub extern fn ZigClangDecayedType_getDecayedType(*const ZigClangDecayedType) ZigClangQualType; + pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigClangStringLiteral_StringKind; pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8; @@ -1000,3 +1011,6 @@ pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigC pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool; pub extern fn ZigClangFieldDecl_getType(*const struct_ZigClangFieldDecl) struct_ZigClangQualType; pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) struct_ZigClangSourceLocation; + +pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr; +pub extern fn ZigClangEnumConstantDecl_getInitVal(*const ZigClangEnumConstantDecl) *const ZigClangAPSInt; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 4478233270dd..5cd019891123 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -15,7 +15,7 @@ pub const Error = error{OutOfMemory}; const TypeError = Error || error{UnsupportedType}; const TransError = TypeError || error{UnsupportedTranslation}; -const DeclTable = std.HashMap(usize, void, addrHash, addrEql); +const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql); fn addrHash(x: usize) u32 { switch (@typeInfo(usize).Int.bits) { @@ -109,6 +109,12 @@ const Context = struct { global_scope: *Scope.Root, ptr_params: std.BufSet, clang_context: *ZigClangASTContext, + mangle_count: u64 = 0, + + fn getMangle(c: *Context) u64 { + c.mangle_count += 1; + return c.mangle_count; + } fn a(c: *Context) *std.mem.Allocator { return &c.tree.arena_allocator.allocator; @@ -239,7 +245,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); }, .Enum => { - try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{}); + _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); }, .Record => { return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); @@ -255,9 +261,10 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { } fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { - if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice + if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); + _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name); const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); const fn_qt = ZigClangFunctionDecl_getType(fn_decl); const fn_type = ZigClangQualType_getTypePtr(fn_qt); @@ -319,7 +326,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { } fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { - if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice + if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const visib_tok = try appendToken(c, .Keyword_pub, "pub"); @@ -330,6 +337,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { var scope = &c.global_scope.base; const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); + _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); @@ -348,7 +356,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { else try appendToken(c, .Keyword_var, "var"); - const name_tok = try appendToken(c, .Identifier, var_name); + const name_tok = try appendIdentifier(c, var_name); _ = try appendToken(c, .Colon, ":"); const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { @@ -381,7 +389,6 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ - .base = ast.Node{ .id = .VarDecl }, .doc_comments = null, .visib_token = visib_tok, .thread_local_token = thread_local_token, @@ -401,13 +408,16 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { } fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { - if (try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), {})) |_| return; // Avoid processing this decl twice + if (c.decl_table.contains( + @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), + )) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const const_tok = try appendToken(c, .Keyword_const, "const"); const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); - const name_tok = try appendToken(c, .Identifier, typedef_name); + _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); + const name_tok = try appendIdentifier(c, typedef_name); const eq_tok = try appendToken(c, .Equal, "="); const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); @@ -421,7 +431,6 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ - .base = ast.Node{ .id = .VarDecl }, .doc_comments = null, .visib_token = visib_tok, .thread_local_token = null, @@ -441,7 +450,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err } fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { - if (try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), {})) |_| return; // Avoid processing this decl twice + if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); @@ -451,7 +460,7 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! else if (ZigClangRecordDecl_isStruct(record_decl)) "struct" else - return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), bare_name, "record {} is not a struct or union", .{bare_name}); + return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) return; @@ -460,7 +469,8 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! const const_tok = try appendToken(c, .Keyword_const, "const"); const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); - const name_tok = try appendToken(c, .Identifier, name); + _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); + const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { @@ -473,7 +483,6 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ - .base = ast.Node{ .id = .VarDecl }, .doc_comments = null, .visib_token = visib_tok, .thread_local_token = null, @@ -497,14 +506,13 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! fn createAlias(c: *Context, alias: var) !void { const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const mut_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendToken(c, .Identifier, alias.alias); + const name_tok = try appendIdentifier(c, alias.alias); const eq_tok = try appendToken(c, .Equal, "="); - const init_node = try appendIdentifier(c, alias.name); + const init_node = try transCreateNodeIdentifier(c, alias.name); const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ - .base = ast.Node{ .id = .VarDecl }, .doc_comments = null, .visib_token = visib_tok, .thread_local_token = null, @@ -787,7 +795,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe const c_name = try c.str(ZigClangDecl_getName_bytes_begin( @ptrCast(*const ZigClangDecl, var_decl), )); - const name_token = try appendToken(c, .Identifier, c_name); + const name_token = try appendIdentifier(c, c_name); const var_scope = try c.a().create(Scope.Var); var_scope.* = Scope.Var{ @@ -810,7 +818,6 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ - .base = ast.Node{ .id = .VarDecl }, .doc_comments = null, .visib_token = null, .thread_local_token = thread_local_token, @@ -856,7 +863,7 @@ fn transDeclRefExpr( const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); const zig_name = transLookupZigIdentifier(scope, c_name); if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name); - const node = try appendIdentifier(rp.c, zig_name); + const node = try transCreateNodeIdentifier(rp.c, zig_name); return TransResult{ .node = node, .node_scope = scope, @@ -978,7 +985,6 @@ fn transStringLiteral( const token = try appendToken(rp.c, .StringLiteral, buf); const node = try rp.c.a().create(ast.Node.StringLiteral); node.* = ast.Node.StringLiteral{ - .base = ast.Node{ .id = .StringLiteral }, .token = token, }; const res = TransResult{ @@ -1145,7 +1151,6 @@ fn transInitListExpr( const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**"); const mul_node = try rp.c.a().create(ast.Node.InfixOp); mul_node.* = .{ - .base = .{ .id = .InfixOp }, .op_token = mul_tok, .lhs = &filler_init_node.base, .op = .ArrayMult, @@ -1164,7 +1169,6 @@ fn transInitListExpr( const cat_node = try rp.c.a().create(ast.Node.InfixOp); cat_node.* = .{ - .base = .{ .id = .InfixOp }, .op_token = cat_tok, .lhs = &init_node.base, .op = .ArrayCat, @@ -1292,11 +1296,10 @@ fn maybeSuppressResult( if (used == .used) return result; // NOTE: This is backwards, but the semicolon must immediately follow the node. _ = try appendToken(rp.c, .Semicolon, ";"); - const lhs = try appendIdentifier(rp.c, "_"); + const lhs = try transCreateNodeIdentifier(rp.c, "_"); const op_token = try appendToken(rp.c, .Equal, "="); const op_node = try rp.c.a().create(ast.Node.InfixOp); op_node.* = ast.Node.InfixOp{ - .base = ast.Node{ .id = .InfixOp }, .op_token = op_token, .lhs = lhs, .op = .Assign, @@ -1352,7 +1355,6 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro const container_node = try c.a().create(ast.Node.ContainerDecl); container_node.* = .{ - .base = ast.Node{ .id = .ContainerDecl }, .layout_token = extern_tok, .kind_token = container_tok, .init_arg_expr = .None, @@ -1374,7 +1376,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro return node; } - const field_name = try appendToken(c, .Identifier, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); + const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); _ = try appendToken(c, .Colon, ":"); const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); @@ -1396,6 +1398,195 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro return &container_node.base; } +fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { + if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| + return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice + const rp = makeRestorePoint(c); + const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); + + const visib_tok = try appendToken(c, .Keyword_pub, "pub"); + const const_tok = try appendToken(c, .Keyword_const, "const"); + + var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); + var is_unnamed = false; + if (bare_name.len == 0) { + bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); + is_unnamed = true; + } + + const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); + _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); + const name_tok = try appendIdentifier(c, name); + const eq_tok = try appendToken(c, .Equal, "="); + + const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { + var pure_enum = true; + var it = ZigClangEnumDecl_enumerator_begin(enum_def); + var end_it = ZigClangEnumDecl_enumerator_end(enum_def); + while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { + const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); + if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { + pure_enum = false; + break; + } + } + + const extern_tok = try appendToken(c, .Keyword_extern, "extern"); + const container_tok = try appendToken(c, .Keyword_enum, "enum"); + + const container_node = try c.a().create(ast.Node.ContainerDecl); + container_node.* = .{ + .layout_token = extern_tok, + .kind_token = container_tok, + .init_arg_expr = .None, + .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), + .lbrace_token = undefined, + .rbrace_token = undefined, + }; + + const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); + + // TODO only emit this tag type if the enum tag type is not the default. + // I don't know what the default is, need to figure out how clang is deciding. + // it appears to at least be different across gcc/msvc + if (!isCBuiltinType(int_type, .UInt) and + !isCBuiltinType(int_type, .Int)) + { + _ = try appendToken(c, .LParen, "("); + container_node.init_arg_expr = .{ + .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { + error.UnsupportedType => { + if (is_unnamed) { + try emitWarning(c, enum_loc, "unable to translate enum tag type", .{}); + } else { + try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); + } + return null; + }, + else => |e| return e, + }, + }; + _ = try appendToken(c, .RParen, ")"); + } + + container_node.lbrace_token = try appendToken(c, .LBrace, "{"); + + it = ZigClangEnumDecl_enumerator_begin(enum_def); + end_it = ZigClangEnumDecl_enumerator_end(enum_def); + while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { + const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); + + const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); + + const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name)) + enum_val_name[bare_name.len..] + else + enum_val_name; + + const field_name_tok = try appendIdentifier(c, field_name); + + const int_node = if (!pure_enum) blk: { + _ = try appendToken(c, .Colon, "="); + break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); + } else + null; + + const field_node = try c.a().create(ast.Node.ContainerField); + field_node.* = .{ + .doc_comments = null, + .comptime_token = null, + .name_token = field_name_tok, + .type_expr = null, + .value_expr = int_node, + .align_expr = null, + }; + + try container_node.fields_and_decls.push(&field_node.base); + _ = try appendToken(c, .Comma, ","); + // In C each enum value is in the global namespace. So we put them there too. + // At this point we can rely on the enum emitting successfully. + try addEnumTopLevel(c, name, field_name, enum_val_name); + } + container_node.rbrace_token = try appendToken(c, .RBrace, "}"); + + break :blk &container_node.base; + } else + try transCreateNodeOpaqueType(c); + + const semicolon_token = try appendToken(c, .Semicolon, ";"); + + const node = try c.a().create(ast.Node.VarDecl); + node.* = ast.Node.VarDecl{ + .visib_token = visib_tok, + .mut_token = const_tok, + .name_token = name_tok, + .eq_token = eq_tok, + .init_node = init_node, + .semicolon_token = semicolon_token, + .doc_comments = null, + .comptime_token = null, + .extern_export_token = null, + .thread_local_token = null, + .lib_name = null, + .type_node = null, + .align_node = null, + .section_node = null, + }; + + try addTopLevelDecl(c, name, &node.base); + if (!is_unnamed) + try c.alias_list.push(.{ .alias = bare_name, .name = name }); + return transCreateNodeIdentifier(c, name); +} + +fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { + const visib_tok = try appendToken(c, .Keyword_pub, "pub"); + const const_tok = try appendToken(c, .Keyword_const, "const"); + const name_tok = try appendIdentifier(c, enum_val_name); + const eq_tok = try appendToken(c, .Equal, "="); + + const enum_ident = try transCreateNodeIdentifier(c, enum_name); + const period_tok = try appendToken(c, .Period, "."); + const field_ident = try transCreateNodeIdentifier(c, field_name); + + const field_access_node = try c.a().create(ast.Node.InfixOp); + field_access_node.* = .{ + .op_token = period_tok, + .lhs = enum_ident, + .op = .Period, + .rhs = field_ident, + }; + const semicolon_token = try appendToken(c, .Semicolon, ";"); + + const node = try c.a().create(ast.Node.VarDecl); + node.* = ast.Node.VarDecl{ + .visib_token = visib_tok, + .mut_token = const_tok, + .name_token = name_tok, + .eq_token = eq_tok, + .init_node = &field_access_node.base, + .semicolon_token = semicolon_token, + .thread_local_token = null, + .doc_comments = null, + .comptime_token = null, + .extern_export_token = null, + .lib_name = null, + .type_node = null, + .align_node = null, + .section_node = null, + }; + + try addTopLevelDecl(c, field_name, &node.base); +} + +fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { + const c_type = qualTypeCanon(qt); + if (ZigClangType_getTypeClass(c_type) != .Builtin) + return false; + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type); + return ZigClangBuiltinType_getKind(builtin_ty) == kind; +} + fn qualTypeIsPtr(qt: ZigClangQualType) bool { return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; } @@ -1523,7 +1714,6 @@ fn transCreateNodeAssign( const node = try rp.c.a().create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ - .base = ast.Node{ .id = .InfixOp }, .op_token = eq_token, .lhs = lhs_node.node, .op = .Assign, @@ -1553,7 +1743,6 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti _ = try appendToken(c, .LParen, "("); const node = try c.a().create(ast.Node.BuiltinCall); node.* = ast.Node.BuiltinCall{ - .base = ast.Node{ .id = .BuiltinCall }, .builtin_token = builtin_token, .params = ast.Node.BuiltinCall.ParamList.init(c.a()), .rparen_token = undefined, // set after appending args @@ -1565,7 +1754,6 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { _ = try appendToken(c, .LParen, "("); const node = try c.a().create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ - .base = ast.Node{ .id = .SuffixOp }, .lhs = fn_expr, .op = ast.Node.SuffixOp.Op{ .Call = ast.Node.SuffixOp.Op.Call{ @@ -1586,7 +1774,6 @@ fn transCreateNodePrefixOp( ) !*ast.Node.PrefixOp { const node = try c.a().create(ast.Node.PrefixOp); node.* = ast.Node.PrefixOp{ - .base = ast.Node{ .id = .PrefixOp }, .op_token = try appendToken(c, op_tok_id, bytes), .op = op, .rhs = undefined, // translate and set afterward @@ -1609,7 +1796,6 @@ fn transCreateNodeInfixOp( const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); const node = try rp.c.a().create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ - .base = ast.Node{ .id = .InfixOp }, .op_token = op_token, .lhs = lhs.node, .op = op, @@ -1619,7 +1805,6 @@ fn transCreateNodeInfixOp( const rparen = try appendToken(rp.c, .RParen, ")"); const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); grouped_expr.* = ast.Node.GroupedExpression{ - .base = ast.Node{ .id = .GroupedExpression }, .lparen = lparen, .expr = &node.base, .rparen = rparen, @@ -1644,7 +1829,7 @@ fn transCreateNodePtrType( .Identifier => blk: { const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token _ = try appendToken(c, .Asterisk, "*"); - _ = try appendToken(c, .Identifier, "c"); + _ = try appendIdentifier(c, "c"); _ = try appendToken(c, .RBracket, "]"); break :blk lbracket; }, @@ -1652,7 +1837,6 @@ fn transCreateNodePtrType( else => unreachable, }; node.* = ast.Node.PrefixOp{ - .base = ast.Node{ .id = .PrefixOp }, .op_token = op_token, .op = ast.Node.PrefixOp.Op{ .PtrType = .{ @@ -1679,7 +1863,6 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { const token = try appendToken(c, .IntegerLiteral, str); const node = try c.a().create(ast.Node.IntegerLiteral); node.* = ast.Node.IntegerLiteral{ - .base = ast.Node{ .id = .IntegerLiteral }, .token = token, }; return &node.base; @@ -1689,7 +1872,6 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node { const ltoken = try appendToken(c, .Keyword_return, "return"); const node = try c.a().create(ast.Node.ControlFlowExpression); node.* = ast.Node.ControlFlowExpression{ - .base = ast.Node{ .id = .ControlFlowExpression }, .ltoken = ltoken, .kind = .Return, .rhs = null, @@ -1701,7 +1883,6 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { const token = try appendToken(c, .Keyword_undefined, "undefined"); const node = try c.a().create(ast.Node.UndefinedLiteral); node.* = ast.Node.UndefinedLiteral{ - .base = ast.Node{ .id = .UndefinedLiteral }, .token = token, }; return &node.base; @@ -1711,7 +1892,6 @@ fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { const token = try appendToken(c, .Keyword_null, "null"); const node = try c.a().create(ast.Node.NullLiteral); node.* = ast.Node.NullLiteral{ - .base = ast.Node{ .id = .NullLiteral }, .token = token, }; return &node.base; @@ -1724,7 +1904,6 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { try appendToken(c, .Keyword_false, "false"); const node = try c.a().create(ast.Node.BoolLiteral); node.* = ast.Node.BoolLiteral{ - .base = ast.Node{ .id = .BoolLiteral }, .token = token, }; return &node.base; @@ -1734,7 +1913,6 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N _ = try appendToken(c, .LBrace, "{"); const node = try c.a().create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ - .base = ast.Node{ .id = .SuffixOp }, .lhs = .{ .dot = dot_tok }, .op = .{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()), @@ -1748,7 +1926,6 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); const node = try c.a().create(ast.Node.IntegerLiteral); node.* = ast.Node.IntegerLiteral{ - .base = ast.Node{ .id = .IntegerLiteral }, .token = token, }; return &node.base; @@ -1793,25 +1970,25 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour .Builtin => { const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); switch (ZigClangBuiltinType_getKind(builtin_ty)) { - .Void => return appendIdentifier(rp.c, "c_void"), - .Bool => return appendIdentifier(rp.c, "bool"), - .Char_U, .UChar, .Char_S, .Char8 => return appendIdentifier(rp.c, "u8"), - .SChar => return appendIdentifier(rp.c, "i8"), - .UShort => return appendIdentifier(rp.c, "c_ushort"), - .UInt => return appendIdentifier(rp.c, "c_uint"), - .ULong => return appendIdentifier(rp.c, "c_ulong"), - .ULongLong => return appendIdentifier(rp.c, "c_ulonglong"), - .Short => return appendIdentifier(rp.c, "c_short"), - .Int => return appendIdentifier(rp.c, "c_int"), - .Long => return appendIdentifier(rp.c, "c_long"), - .LongLong => return appendIdentifier(rp.c, "c_longlong"), - .UInt128 => return appendIdentifier(rp.c, "u128"), - .Int128 => return appendIdentifier(rp.c, "i128"), - .Float => return appendIdentifier(rp.c, "f32"), - .Double => return appendIdentifier(rp.c, "f64"), - .Float128 => return appendIdentifier(rp.c, "f128"), - .Float16 => return appendIdentifier(rp.c, "f16"), - .LongDouble => return appendIdentifier(rp.c, "c_longdouble"), + .Void => return transCreateNodeIdentifier(rp.c, "c_void"), + .Bool => return transCreateNodeIdentifier(rp.c, "bool"), + .Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"), + .SChar => return transCreateNodeIdentifier(rp.c, "i8"), + .UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"), + .UInt => return transCreateNodeIdentifier(rp.c, "c_uint"), + .ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"), + .ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"), + .Short => return transCreateNodeIdentifier(rp.c, "c_short"), + .Int => return transCreateNodeIdentifier(rp.c, "c_int"), + .Long => return transCreateNodeIdentifier(rp.c, "c_long"), + .LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"), + .UInt128 => return transCreateNodeIdentifier(rp.c, "u128"), + .Int128 => return transCreateNodeIdentifier(rp.c, "i128"), + .Float => return transCreateNodeIdentifier(rp.c, "f32"), + .Double => return transCreateNodeIdentifier(rp.c, "f64"), + .Float128 => return transCreateNodeIdentifier(rp.c, "f128"), + .Float16 => return transCreateNodeIdentifier(rp.c, "f16"), + .LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"), else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), } }, @@ -1891,21 +2068,36 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); - return appendIdentifier(rp.c, typedef_name); + return transCreateNodeIdentifier(rp.c, typedef_name); }, .Record => { const record_ty = @ptrCast(*const ZigClangRecordType, ty); const record_decl = ZigClangRecordType_getDecl(record_ty); - if (try getContainerName(rp.c, record_decl)) |name| - return appendIdentifier(rp.c, name) + if (try getContainerName(rp, record_decl)) |name| + return transCreateNodeIdentifier(rp.c, name) else return transRecordDecl(rp.c, record_decl); }, + .Enum => { + const enum_ty = @ptrCast(*const ZigClangEnumType, ty); + + const enum_decl = ZigClangEnumType_getDecl(enum_ty); + 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 ZigClangElaboratedType, ty); return transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc); }, + .Decayed => { + const decayed_ty = @ptrCast(*const ZigClangDecayedType, ty); + return transQualType(rp, ZigClangDecayedType_getDecayedType(decayed_ty), source_loc); + }, + .Attributed => { + const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); + return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); + }, else => { const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); @@ -1913,22 +2105,20 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour } } -fn getContainerName(c: *Context, record_decl: *const ZigClangRecordDecl) !?[]const u8 { - const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); +fn getContainerName(rp: RestorePoint, record_decl: *const ZigClangRecordDecl) !?[]const u8 { + const bare_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) "union" else if (ZigClangRecordDecl_isStruct(record_decl)) "struct" - else { - try emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); - return null; - }; + else + return revertAndWarn(rp, error.UnsupportedType, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) return null; - return try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); + return try std.fmt.allocPrint(rp.c.a(), "{}_{}", .{ container_kind_name, bare_name }); } fn isCVoid(qt: ZigClangQualType) bool { @@ -2020,7 +2210,7 @@ fn finishTransFnProto( else null; const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); - const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null; + const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null; const lparen_tok = try appendToken(rp.c, .LParen, "("); var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a()); @@ -2038,7 +2228,7 @@ fn finishTransFnProto( const param_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); if (param_name.len > 0) { // TODO: If len == 0, auto-generate arg1, arg2, etc? Or leave the name blank? - const result = try appendToken(rp.c, .Identifier, param_name); + const result = try appendIdentifier(rp.c, param_name); _ = try appendToken(rp.c, .Colon, ":"); break :blk result; } @@ -2087,12 +2277,12 @@ fn finishTransFnProto( const return_type_node = blk: { if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { - break :blk try appendIdentifier(rp.c, "noreturn"); + break :blk try transCreateNodeIdentifier(rp.c, "noreturn"); } else { const return_qt = ZigClangFunctionType_getReturnType(fn_ty); if (isCVoid(return_qt)) { // convert primitive c_void to actual void (only for return type) - break :blk try appendIdentifier(rp.c, "void"); + break :blk try transCreateNodeIdentifier(rp.c, "void"); } else { break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) { error.UnsupportedType => { @@ -2145,7 +2335,7 @@ fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []cons fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: var) !void { // const name = @compileError(msg); const const_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendToken(c, .Identifier, name); + const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); const builtin_tok = try appendToken(c, .Builtin, "@compileError"); const lparen_tok = try appendToken(c, .LParen, "("); @@ -2190,6 +2380,7 @@ fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime } fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex { + std.debug.assert(token_id != .Identifier); // use appendIdentifier return appendTokenFmt(c, token_id, "{}", .{bytes}); } @@ -2218,8 +2409,27 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, return token_index; } -fn appendIdentifier(c: *Context, name: []const u8) !*ast.Node { - const token_index = try appendToken(c, .Identifier, name); +fn isValidZigIdentifier(name: []const u8) bool { + for (name) |c, i| { + switch (c) { + '_', 'a'...'z', 'A'...'Z' => {}, + '0'...'9' => if (i == 0) return false, + else => return false, + } + } + return true; +} + +fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { + if (!isValidZigIdentifier(name) or std.zig.Token.getKeyword(name) != null) { + return appendTokenFmt(c, .Identifier, "@\"{}\"", .{name}); + } else { + return appendTokenFmt(c, .Identifier, "{}", .{name}); + } +} + +fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { + const token_index = try appendIdentifier(c, name); const identifier = try c.a().create(ast.Node.Identifier); identifier.* = ast.Node.Identifier{ .base = ast.Node{ .id = ast.Node.Id.Identifier }, diff --git a/test/translate_c.zig b/test/translate_c.zig index 92ebdb9d2616..97cfc129f761 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -217,6 +217,72 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const OpenGLProcs = union_OpenGLProcs; }); + cases.add_2("enums", + \\typedef enum { + \\ a, + \\ b, + \\ c, + \\} d; + \\enum { + \\ e, + \\ f = 4, + \\ g, + \\} h = e; + \\struct Baz { + \\ enum { + \\ i, + \\ j, + \\ k, + \\ } l; + \\ d m; + \\}; + \\enum i { + \\ n, + \\ o, + \\ p, + \\}; + , &[_][]const u8{ + \\pub const a = enum_unnamed_1.a; + \\pub const b = enum_unnamed_1.b; + \\pub const c = enum_unnamed_1.c; + \\pub const enum_unnamed_1 = extern enum { + \\ a, + \\ b, + \\ c, + \\}; + \\pub const d = enum_unnamed_1; + \\pub const e = enum_unnamed_2.e; + \\pub const f = enum_unnamed_2.f; + \\pub const g = enum_unnamed_2.g; + \\pub const enum_unnamed_2 = extern enum { + \\ e = 0, + \\ f = 4, + \\ g = 5, + \\}; + \\pub export var h: enum_unnamed_2 = @as(enum_unnamed_2, e); + \\pub const i = enum_unnamed_3.i; + \\pub const j = enum_unnamed_3.j; + \\pub const k = enum_unnamed_3.k; + \\pub const enum_unnamed_3 = extern enum { + \\ i, + \\ j, + \\ k, + \\}; + \\pub const struct_Baz = extern struct { + \\ l: enum_unnamed_3, + \\ m: d, + \\}; + \\pub const n = enum_i.n; + \\pub const o = enum_i.o; + \\pub const p = enum_i.p; + \\pub const enum_i = extern enum { + \\ n, + \\ o, + \\ p, + \\}; + \\pub const Baz = struct_Baz; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", @@ -440,7 +506,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("enums", + cases.add_both("enums", \\enum Foo { \\ FooA, \\ FooB, @@ -462,7 +528,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = enum_Foo; }); - cases.add("enums", + cases.add_both("enums", \\enum Foo { \\ FooA = 2, \\ FooB = 5, @@ -686,7 +752,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); }); - cases.add("zig keywords in C code", + cases.add_both("zig keywords in C code", \\struct comptime { \\ int defer; \\};