diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aad51c7bc..bda576347e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,7 +196,7 @@ else() if(MSVC) set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w") else() - set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment") + set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fno-exceptions -fno-rtti -Wno-comment -Wno-class-memaccess -Wno-unknown-warning-option") endif() set_target_properties(embedded_lld_lib PROPERTIES COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS} diff --git a/src/ir.cpp b/src/ir.cpp index 9691e9e635..e2cbba48a7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16555,6 +16555,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t { size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index); inner_fields[1].data.x_maybe = create_const_vals(1); + inner_fields[1].data.x_maybe->special = ConstValSpecialStatic; inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize; bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 804fd802f1..d494ec1fd0 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -25,6 +25,8 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), Character, Buf, BufWidth, + Bytes, + BytesWidth, }; comptime var start_index = 0; @@ -93,6 +95,10 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), '.' => { state = State.Float; }, + 'B' => { + width = 0; + state = State.Bytes; + }, else => @compileError("Unknown format character: " ++ []u8{c}), }, State.Buf => switch (c) { @@ -204,6 +210,30 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context), }, else => @compileError("Unexpected character in format string: " ++ []u8{c}), }, + State.Bytes => switch (c) { + '}' => { + try formatBytes(args[next_arg], 0, context, Errors, output); + next_arg += 1; + state = State.Start; + start_index = i + 1; + }, + '0' ... '9' => { + width_start = i; + state = State.BytesWidth; + }, + else => @compileError("Unexpected character in format string: " ++ []u8{c}), + }, + State.BytesWidth => switch (c) { + '}' => { + width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable); + try formatBytes(args[next_arg], width, context, Errors, output); + next_arg += 1; + state = State.Start; + start_index = i + 1; + }, + '0' ... '9' => {}, + else => @compileError("Unexpected character in format string: " ++ []u8{c}), + }, } } comptime { @@ -513,7 +543,29 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com } } -pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8) Errors!void) Errors!void { +pub fn formatBytes(value: var, width: ?usize, + context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void +{ + if (value == 0) { + return output(context, "0B"); + } + + const mags = " KMGTPEZY"; + const magnitude = math.min(math.log2(value) / 10, mags.len - 1); + const new_value = f64(value) / math.pow(f64, 1024, f64(magnitude)); + const suffix = mags[magnitude]; + + try formatFloatDecimal(new_value, width, context, Errors, output); + + if (suffix != ' ') { + try output(context, (&suffix)[0..1]); + } + return output(context, "B"); +} + +pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, + context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void +{ if (@typeOf(value).is_signed) { return formatIntSigned(value, base, uppercase, width, context, Errors, output); } else { @@ -750,6 +802,12 @@ test "fmt.format" { const result = try bufPrint(buf1[0..], "u3: {}\n", value); assert(mem.eql(u8, result, "u3: 5\n")); } + { + var buf1: [32]u8 = undefined; + const value: usize = 63 * 1024 * 1024; + const result = try bufPrint(buf1[0..], "file size: {B}\n", value); + assert(mem.eql(u8, result, "file size: 63MB\n")); + } { // Dummy field because of https://github.com/zig-lang/zig/issues/557. const Struct = struct { diff --git a/std/zig/parse.zig b/std/zig/parse.zig index f88fdfab62..f2376f0df3 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -17,15 +17,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { defer stack.deinit(); const arena = &tree_arena.allocator; - const root_node = try createNode(arena, ast.Node.Root, - ast.Node.Root { - .base = undefined, - .decls = ast.Node.Root.DeclList.init(arena), - .doc_comments = null, - // initialized when we get the eof token - .eof_token = undefined, - } - ); + const root_node = try arena.construct(ast.Node.Root { + .base = ast.Node { .id = ast.Node.Id.Root }, + .decls = ast.Node.Root.DeclList.init(arena), + .doc_comments = null, + // initialized when we get the eof token + .eof_token = undefined, + }); var tree = ast.Tree { .source = source, @@ -113,15 +111,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_comptime => { - const block = try createNode(arena, ast.Node.Block, - ast.Node.Block { - .base = undefined, - .label = null, - .lbrace = undefined, - .statements = ast.Node.Block.StatementList.init(arena), - .rbrace = undefined, - } - ); + const block = try arena.construct(ast.Node.Block { + .base = ast.Node {.id = ast.Node.Id.Block }, + .label = null, + .lbrace = undefined, + .statements = ast.Node.Block.StatementList.init(arena), + .rbrace = undefined, + }); const node = try arena.construct(ast.Node.Comptime { .base = ast.Node { .id = ast.Node.Id.Comptime, @@ -312,14 +308,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_async => { - const async_node = try createNode(arena, ast.Node.AsyncAttribute, - ast.Node.AsyncAttribute { - .base = undefined, - .async_token = token_index, - .allocator_type = null, - .rangle_bracket = null, - } - ); + const async_node = try arena.construct(ast.Node.AsyncAttribute { + .base = ast.Node {.id = ast.Node.Id.AsyncAttribute }, + .async_token = token_index, + .allocator_type = null, + .rangle_bracket = null, + }); fn_proto.async_attr = async_node; try stack.append(State { @@ -396,27 +390,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token = nextToken(&tok_it, &tree); const token_index = token.index; const token_ptr = token.ptr; - const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.ContainerDecl, - ast.Node.ContainerDecl { - .base = undefined, - .ltoken = ctx.ltoken, - .layout = ctx.layout, - .kind = switch (token_ptr.id) { - Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct, - Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union, - Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum, - else => { - *(try tree.errors.addOne()) = Error { - .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index }, - }; - return tree; - }, + const node = try arena.construct(ast.Node.ContainerDecl { + .base = ast.Node {.id = ast.Node.Id.ContainerDecl }, + .ltoken = ctx.ltoken, + .layout = ctx.layout, + .kind = switch (token_ptr.id) { + Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct, + Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union, + Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum, + else => { + *(try tree.errors.addOne()) = Error { + .ExpectedAggregateKw = Error.ExpectedAggregateKw { .token = token_index }, + }; + return tree; }, - .init_arg_expr = ast.Node.ContainerDecl.InitArg.None, - .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena), - .rbrace_token = undefined, - } - ); + }, + .init_arg_expr = ast.Node.ContainerDecl.InitArg.None, + .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena), + .rbrace_token = undefined, + }); + ctx.opt_ctx.store(&node.base); stack.append(State { .ContainerDecl = node }) catch unreachable; try stack.append(State { .ExpectToken = Token.Id.LBrace }); @@ -647,12 +640,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { switch (token_ptr.id) { Token.Id.Equal => { var_decl.eq_token = token_index; - stack.append(State { - .ExpectTokenSave = ExpectTokenSave { - .id = Token.Id.Semicolon, - .ptr = &var_decl.semicolon_token, - }, - }) catch unreachable; + stack.append(State { .VarDeclSemiColon = var_decl }) catch unreachable; try stack.append(State { .Expression = OptionalCtx { .RequiredNull = &var_decl.init_node } }); continue; }, @@ -669,6 +657,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { } }, + State.VarDeclSemiColon => |var_decl| { + const semicolon_token = nextToken(&tok_it, &tree); + + if (semicolon_token.ptr.id != Token.Id.Semicolon) { + *(try tree.errors.addOne()) = Error { + .ExpectedToken = Error.ExpectedToken { + .token = semicolon_token.index, + .expected_id = Token.Id.Semicolon, + }, + }; + return tree; + } + + var_decl.semicolon_token = semicolon_token.index; + + if (eatToken(&tok_it, &tree, Token.Id.DocComment)) |doc_comment_token| { + const loc = tree.tokenLocation(semicolon_token.ptr.end, doc_comment_token); + if (loc.line == 0) { + try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments); + } else { + putBackToken(&tok_it, &tree); + } + } + }, State.FnDef => |fn_proto| { const token = nextToken(&tok_it, &tree); @@ -844,15 +856,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.LBrace => { - const block = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.Block, - ast.Node.Block { - .base = undefined, - .label = ctx.label, - .lbrace = token_index, - .statements = ast.Node.Block.StatementList.init(arena), - .rbrace = undefined, - } - ); + const block = try arena.construct(ast.Node.Block { + .base = ast.Node {.id = ast.Node.Id.Block}, + .label = ctx.label, + .lbrace = token_index, + .statements = ast.Node.Block.StatementList.init(arena), + .rbrace = undefined, + }); + ctx.opt_ctx.store(&block.base); stack.append(State { .Block = block }) catch unreachable; continue; }, @@ -957,19 +968,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { } }, State.While => |ctx| { - const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.While, - ast.Node.While { - .base = undefined, - .label = ctx.label, - .inline_token = ctx.inline_token, - .while_token = ctx.loop_token, - .condition = undefined, - .payload = null, - .continue_expr = null, - .body = undefined, - .@"else" = null, - } - ); + const node = try arena.construct(ast.Node.While { + .base = ast.Node {.id = ast.Node.Id.While }, + .label = ctx.label, + .inline_token = ctx.inline_token, + .while_token = ctx.loop_token, + .condition = undefined, + .payload = null, + .continue_expr = null, + .body = undefined, + .@"else" = null, + }); + ctx.opt_ctx.store(&node.base); stack.append(State { .Else = &node.@"else" }) catch unreachable; try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }); try stack.append(State { .WhileContinueExpr = &node.continue_expr }); @@ -987,18 +997,17 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.For => |ctx| { - const node = try createToCtxNode(arena, ctx.opt_ctx, ast.Node.For, - ast.Node.For { - .base = undefined, - .label = ctx.label, - .inline_token = ctx.inline_token, - .for_token = ctx.loop_token, - .array_expr = undefined, - .payload = null, - .body = undefined, - .@"else" = null, - } - ); + const node = try arena.construct(ast.Node.For { + .base = ast.Node {.id = ast.Node.Id.For }, + .label = ctx.label, + .inline_token = ctx.inline_token, + .for_token = ctx.loop_token, + .array_expr = undefined, + .payload = null, + .body = undefined, + .@"else" = null, + }); + ctx.opt_ctx.store(&node.base); stack.append(State { .Else = &node.@"else" }) catch unreachable; try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }); try stack.append(State { .PointerIndexPayload = OptionalCtx { .Optional = &node.payload } }); @@ -1009,14 +1018,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { }, State.Else => |dest| { if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| { - const node = try createNode(arena, ast.Node.Else, - ast.Node.Else { - .base = undefined, - .else_token = else_token, - .payload = null, - .body = undefined, - } - ); + const node = try arena.construct(ast.Node.Else { + .base = ast.Node {.id = ast.Node.Id.Else }, + .else_token = else_token, + .payload = null, + .body = undefined, + }); *dest = node; stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }) catch unreachable; @@ -1170,14 +1177,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try createNode(arena, ast.Node.AsmOutput, - ast.Node.AsmOutput { - .base = undefined, - .symbolic_name = undefined, - .constraint = undefined, - .kind = undefined, - } - ); + const node = try arena.construct(ast.Node.AsmOutput { + .base = ast.Node {.id = ast.Node.Id.AsmOutput }, + .symbolic_name = undefined, + .constraint = undefined, + .kind = undefined, + }); try items.push(node); stack.append(State { .AsmOutputItems = items }) catch unreachable; @@ -1223,14 +1228,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try createNode(arena, ast.Node.AsmInput, - ast.Node.AsmInput { - .base = undefined, - .symbolic_name = undefined, - .constraint = undefined, - .expr = undefined, - } - ); + const node = try arena.construct(ast.Node.AsmInput { + .base = ast.Node {.id = ast.Node.Id.AsmInput }, + .symbolic_name = undefined, + .constraint = undefined, + .expr = undefined, + }); try items.push(node); stack.append(State { .AsmInputItems = items }) catch unreachable; @@ -1668,14 +1671,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try createToCtxNode(arena, opt_ctx, ast.Node.Payload, - ast.Node.Payload { - .base = undefined, - .lpipe = token_index, - .error_symbol = undefined, - .rpipe = undefined - } - ); + const node = try arena.construct(ast.Node.Payload { + .base = ast.Node {.id = ast.Node.Id.Payload }, + .lpipe = token_index, + .error_symbol = undefined, + .rpipe = undefined + }); + opt_ctx.store(&node.base); stack.append(State { .ExpectTokenSave = ExpectTokenSave { @@ -1705,15 +1707,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerPayload, - ast.Node.PointerPayload { - .base = undefined, - .lpipe = token_index, - .ptr_token = null, - .value_symbol = undefined, - .rpipe = undefined - } - ); + const node = try arena.construct(ast.Node.PointerPayload { + .base = ast.Node {.id = ast.Node.Id.PointerPayload }, + .lpipe = token_index, + .ptr_token = null, + .value_symbol = undefined, + .rpipe = undefined + }); + opt_ctx.store(&node.base); try stack.append(State { .ExpectTokenSave = ExpectTokenSave { @@ -1749,16 +1750,15 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try createToCtxNode(arena, opt_ctx, ast.Node.PointerIndexPayload, - ast.Node.PointerIndexPayload { - .base = undefined, - .lpipe = token_index, - .ptr_token = null, - .value_symbol = undefined, - .index_symbol = null, - .rpipe = undefined - } - ); + const node = try arena.construct(ast.Node.PointerIndexPayload { + .base = ast.Node {.id = ast.Node.Id.PointerIndexPayload }, + .lpipe = token_index, + .ptr_token = null, + .value_symbol = undefined, + .index_symbol = null, + .rpipe = undefined + }); + opt_ctx.store(&node.base); stack.append(State { .ExpectTokenSave = ExpectTokenSave { @@ -1785,14 +1785,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.ControlFlowExpression, - ast.Node.ControlFlowExpression { - .base = undefined, - .ltoken = token_index, - .kind = undefined, - .rhs = null, - } - ); + const node = try arena.construct(ast.Node.ControlFlowExpression { + .base = ast.Node {.id = ast.Node.Id.ControlFlowExpression }, + .ltoken = token_index, + .kind = undefined, + .rhs = null, + }); + opt_ctx.store(&node.base); stack.append(State { .Expression = OptionalCtx { .Optional = &node.rhs } }) catch unreachable; @@ -1815,19 +1814,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp, - ast.Node.PrefixOp { - .base = undefined, - .op_token = token_index, - .op = switch (token_ptr.id) { - Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} }, - Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} }, - Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} }, - else => unreachable, - }, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.PrefixOp { + .base = ast.Node {.id = ast.Node.Id.PrefixOp }, + .op_token = token_index, + .op = switch (token_ptr.id) { + Token.Id.Keyword_try => ast.Node.PrefixOp.Op { .Try = void{} }, + Token.Id.Keyword_cancel => ast.Node.PrefixOp.Op { .Cancel = void{} }, + Token.Id.Keyword_resume => ast.Node.PrefixOp.Op { .Resume = void{} }, + else => unreachable, + }, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable; continue; @@ -1850,15 +1848,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = ellipsis3, - .op = ast.Node.InfixOp.Op.Range, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = ellipsis3, + .op = ast.Node.InfixOp.Op.Range, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }) catch unreachable; continue; } @@ -1876,15 +1873,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToAssignment(token_ptr.id)) |ass_id| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = ass_id, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = ass_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }); continue; @@ -1907,15 +1903,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = unwrap_id, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = unwrap_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .Expression = OptionalCtx { .Required = &node.rhs } }); @@ -1940,15 +1935,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = or_token, - .op = ast.Node.InfixOp.Op.BoolOr, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = or_token, + .op = ast.Node.InfixOp.Op.BoolOr, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .BoolAndExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -1965,15 +1959,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = and_token, - .op = ast.Node.InfixOp.Op.BoolAnd, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = and_token, + .op = ast.Node.InfixOp.Op.BoolAnd, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .ComparisonExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -1993,15 +1986,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToComparison(token_ptr.id)) |comp_id| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = comp_id, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = comp_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .BinaryOrExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2021,15 +2013,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = pipe, - .op = ast.Node.InfixOp.Op.BitOr, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = pipe, + .op = ast.Node.InfixOp.Op.BitOr, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .BinaryXorExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2046,15 +2037,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = caret, - .op = ast.Node.InfixOp.Op.BitXor, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = caret, + .op = ast.Node.InfixOp.Op.BitXor, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .BinaryAndExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2071,15 +2061,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = ampersand, - .op = ast.Node.InfixOp.Op.BitAnd, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = ampersand, + .op = ast.Node.InfixOp.Op.BitAnd, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .BitShiftExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2099,15 +2088,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = bitshift_id, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = bitshift_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .AdditionExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2130,15 +2118,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToAddition(token_ptr.id)) |add_id| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = add_id, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = add_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .MultiplyExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2161,15 +2148,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToMultiply(token_ptr.id)) |mult_id| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = mult_id, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = mult_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .CurlySuffixExpressionBegin = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2211,16 +2197,15 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp, - ast.Node.SuffixOp { - .base = undefined, - .lhs = lhs, - .op = ast.Node.SuffixOp.Op { - .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena), - }, - .rtoken = undefined, - } - ); + const node = try arena.construct(ast.Node.SuffixOp { + .base = ast.Node {.id = ast.Node.Id.SuffixOp }, + .lhs = lhs, + .op = ast.Node.SuffixOp.Op { + .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena), + }, + .rtoken = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .IfToken = Token.Id.LBrace }); try stack.append(State { @@ -2243,15 +2228,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() ?? continue; if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = bang, - .op = ast.Node.InfixOp.Op.ErrorUnion, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = bang, + .op = ast.Node.InfixOp.Op.ErrorUnion, + .rhs = undefined, + }); + opt_ctx.store(&node.base); stack.append(State { .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .PrefixOpExpression = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2263,25 +2247,22 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| { - var node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp, - ast.Node.PrefixOp { - .base = undefined, - .op_token = token_index, - .op = prefix_id, - .rhs = undefined, - } - ); + var node = try arena.construct(ast.Node.PrefixOp { + .base = ast.Node {.id = ast.Node.Id.PrefixOp }, + .op_token = token_index, + .op = prefix_id, + .rhs = undefined, + }); + opt_ctx.store(&node.base); // Treat '**' token as two derefs if (token_ptr.id == Token.Id.AsteriskAsterisk) { - const child = try createNode(arena, ast.Node.PrefixOp, - ast.Node.PrefixOp { - .base = undefined, - .op_token = token_index, - .op = prefix_id, - .rhs = undefined, - } - ); + const child = try arena.construct(ast.Node.PrefixOp { + .base = ast.Node {.id = ast.Node.Id.PrefixOp}, + .op_token = token_index, + .op = prefix_id, + .rhs = undefined, + }); node.rhs = &child.base; node = child; } @@ -2300,14 +2281,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { State.SuffixOpExpressionBegin => |opt_ctx| { if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| { - const async_node = try createNode(arena, ast.Node.AsyncAttribute, - ast.Node.AsyncAttribute { - .base = undefined, - .async_token = async_token, - .allocator_type = null, - .rangle_bracket = null, - } - ); + const async_node = try arena.construct(ast.Node.AsyncAttribute { + .base = ast.Node {.id = ast.Node.Id.AsyncAttribute}, + .async_token = async_token, + .allocator_type = null, + .rangle_bracket = null, + }); stack.append(State { .AsyncEnd = AsyncEndCtx { .ctx = opt_ctx, @@ -2333,19 +2312,19 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.LParen => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp, - ast.Node.SuffixOp { - .base = undefined, - .lhs = lhs, - .op = ast.Node.SuffixOp.Op { - .Call = ast.Node.SuffixOp.Op.Call { - .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena), - .async_attr = null, - } - }, - .rtoken = undefined, - } - ); + const node = try arena.construct(ast.Node.SuffixOp { + .base = ast.Node {.id = ast.Node.Id.SuffixOp }, + .lhs = lhs, + .op = ast.Node.SuffixOp.Op { + .Call = ast.Node.SuffixOp.Op.Call { + .params = ast.Node.SuffixOp.Op.Call.ParamList.init(arena), + .async_attr = null, + } + }, + .rtoken = undefined, + }); + opt_ctx.store(&node.base); + stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .ExprListItemOrEnd = ExprListCtx { @@ -2357,31 +2336,31 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LBracket => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.SuffixOp, - ast.Node.SuffixOp { - .base = undefined, - .lhs = lhs, - .op = ast.Node.SuffixOp.Op { - .ArrayAccess = undefined, - }, - .rtoken = undefined - } - ); + const node = try arena.construct(ast.Node.SuffixOp { + .base = ast.Node {.id = ast.Node.Id.SuffixOp }, + .lhs = lhs, + .op = ast.Node.SuffixOp.Op { + .ArrayAccess = undefined, + }, + .rtoken = undefined + }); + opt_ctx.store(&node.base); + stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .SliceOrArrayAccess = node }); try stack.append(State { .Expression = OptionalCtx { .Required = &node.op.ArrayAccess }}); continue; }, Token.Id.Period => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.InfixOp, - ast.Node.InfixOp { - .base = undefined, - .lhs = lhs, - .op_token = token_index, - .op = ast.Node.InfixOp.Op.Period, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.InfixOp { + .base = ast.Node {.id = ast.Node.Id.InfixOp }, + .lhs = lhs, + .op_token = token_index, + .op = ast.Node.InfixOp.Op.Period, + .rhs = undefined, + }); + opt_ctx.store(&node.base); + stack.append(State { .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State { .Identifier = OptionalCtx { .Required = &node.rhs } }); continue; @@ -2461,14 +2440,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LParen => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.GroupedExpression, - ast.Node.GroupedExpression { - .base = undefined, - .lparen = token.index, - .expr = undefined, - .rparen = undefined, - } - ); + const node = try arena.construct(ast.Node.GroupedExpression { + .base = ast.Node {.id = ast.Node.Id.GroupedExpression }, + .lparen = token.index, + .expr = undefined, + .rparen = undefined, + }); + opt_ctx.store(&node.base); + stack.append(State { .ExpectTokenSave = ExpectTokenSave { .id = Token.Id.RParen, @@ -2479,14 +2458,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Builtin => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.BuiltinCall, - ast.Node.BuiltinCall { - .base = undefined, - .builtin_token = token.index, - .params = ast.Node.BuiltinCall.ParamList.init(arena), - .rparen_token = undefined, - } - ); + const node = try arena.construct(ast.Node.BuiltinCall { + .base = ast.Node {.id = ast.Node.Id.BuiltinCall }, + .builtin_token = token.index, + .params = ast.Node.BuiltinCall.ParamList.init(arena), + .rparen_token = undefined, + }); + opt_ctx.store(&node.base); + stack.append(State { .ExprListItemOrEnd = ExprListCtx { .list = &node.params, @@ -2498,14 +2477,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LBracket => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.PrefixOp, - ast.Node.PrefixOp { - .base = undefined, - .op_token = token.index, - .op = undefined, - .rhs = undefined, - } - ); + const node = try arena.construct(ast.Node.PrefixOp { + .base = ast.Node {.id = ast.Node.Id.PrefixOp }, + .op_token = token.index, + .op = undefined, + .rhs = undefined, + }); + opt_ctx.store(&node.base); + stack.append(State { .SliceOrArrayType = node }) catch unreachable; continue; }, @@ -2611,18 +2590,18 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_asm => { - const node = try createToCtxNode(arena, opt_ctx, ast.Node.Asm, - ast.Node.Asm { - .base = undefined, - .asm_token = token.index, - .volatile_token = null, - .template = undefined, - .outputs = ast.Node.Asm.OutputList.init(arena), - .inputs = ast.Node.Asm.InputList.init(arena), - .clobbers = ast.Node.Asm.ClobberList.init(arena), - .rparen = undefined, - } - ); + const node = try arena.construct(ast.Node.Asm { + .base = ast.Node {.id = ast.Node.Id.Asm }, + .asm_token = token.index, + .volatile_token = null, + .template = undefined, + .outputs = ast.Node.Asm.OutputList.init(arena), + .inputs = ast.Node.Asm.InputList.init(arena), + .clobbers = ast.Node.Asm.ClobberList.init(arena), + .rparen = undefined, + }); + opt_ctx.store(&node.base); + stack.append(State { .ExpectTokenSave = ExpectTokenSave { .id = Token.Id.RParen, @@ -2978,6 +2957,7 @@ const State = union(enum) { VarDecl: VarDeclCtx, VarDeclAlign: &ast.Node.VarDecl, VarDeclEq: &ast.Node.VarDecl, + VarDeclSemiColon: &ast.Node.VarDecl, FnDef: &ast.Node.FnProto, FnProto: &ast.Node.FnProto, @@ -3082,25 +3062,29 @@ const State = union(enum) { OptionalTokenSave: OptionalTokenSave, }; +fn pushDocComment(arena: &mem.Allocator, line_comment: TokenIndex, result: &?&ast.Node.DocComment) !void { + const node = blk: { + if (*result) |comment_node| { + break :blk comment_node; + } else { + const comment_node = try arena.construct(ast.Node.DocComment { + .base = ast.Node { + .id = ast.Node.Id.DocComment, + }, + .lines = ast.Node.DocComment.LineList.init(arena), + }); + *result = comment_node; + break :blk comment_node; + } + }; + try node.lines.push(line_comment); +} + fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.DocComment { var result: ?&ast.Node.DocComment = null; while (true) { if (eatToken(tok_it, tree, Token.Id.DocComment)) |line_comment| { - const node = blk: { - if (result) |comment_node| { - break :blk comment_node; - } else { - const comment_node = try arena.construct(ast.Node.DocComment { - .base = ast.Node { - .id = ast.Node.Id.DocComment, - }, - .lines = ast.Node.DocComment.LineList.init(arena), - }); - result = comment_node; - break :blk comment_node; - } - }; - try node.lines.push(line_comment); + try pushDocComment(arena, line_comment, &result); continue; } break; @@ -3155,31 +3139,29 @@ fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &con token_ptr: &const Token, token_index: TokenIndex) !bool { switch (token_ptr.id) { Token.Id.Keyword_suspend => { - const node = try createToCtxNode(arena, ctx, ast.Node.Suspend, - ast.Node.Suspend { - .base = undefined, - .label = null, - .suspend_token = token_index, - .payload = null, - .body = null, - } - ); + const node = try arena.construct(ast.Node.Suspend { + .base = ast.Node {.id = ast.Node.Id.Suspend }, + .label = null, + .suspend_token = token_index, + .payload = null, + .body = null, + }); + ctx.store(&node.base); stack.append(State { .SuspendBody = node }) catch unreachable; try stack.append(State { .Payload = OptionalCtx { .Optional = &node.payload } }); return true; }, Token.Id.Keyword_if => { - const node = try createToCtxNode(arena, ctx, ast.Node.If, - ast.Node.If { - .base = undefined, - .if_token = token_index, - .condition = undefined, - .payload = null, - .body = undefined, - .@"else" = null, - } - ); + const node = try arena.construct(ast.Node.If { + .base = ast.Node {.id = ast.Node.Id.If }, + .if_token = token_index, + .condition = undefined, + .payload = null, + .body = undefined, + .@"else" = null, + }); + ctx.store(&node.base); stack.append(State { .Else = &node.@"else" }) catch unreachable; try stack.append(State { .Expression = OptionalCtx { .Required = &node.body } }); @@ -3236,14 +3218,14 @@ fn parseBlockExpr(stack: &std.ArrayList(State), arena: &mem.Allocator, ctx: &con return true; }, Token.Id.Keyword_comptime => { - const node = try createToCtxNode(arena, ctx, ast.Node.Comptime, - ast.Node.Comptime { - .base = undefined, - .comptime_token = token_index, - .expr = undefined, - .doc_comments = null, - } - ); + const node = try arena.construct(ast.Node.Comptime { + .base = ast.Node {.id = ast.Node.Id.Comptime }, + .comptime_token = token_index, + .expr = undefined, + .doc_comments = null, + }); + ctx.store(&node.base); + try stack.append(State { .Expression = OptionalCtx { .Required = &node.expr } }); return true; }, @@ -3390,33 +3372,11 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op { }; } -fn createNode(arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T { - const node = try arena.create(T); - *node = *init_to; - node.base = blk: { - const id = ast.Node.typeToId(T); - break :blk ast.Node { - .id = id, - }; - }; - - return node; -} - -fn createToCtxNode(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, init_to: &const T) !&T { - const node = try createNode(arena, T, init_to); - opt_ctx.store(&node.base); - - return node; -} - fn createLiteral(arena: &mem.Allocator, comptime T: type, token_index: TokenIndex) !&T { - return createNode(arena, T, - T { - .base = undefined, - .token = token_index, - } - ); + return arena.construct(T { + .base = ast.Node {.id = ast.Node.typeToId(T)}, + .token = token_index, + }); } fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, comptime T: type, token_index: TokenIndex) !&T { diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 29b231a4db..f95ecfaee3 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,3 +1,17 @@ +test "zig fmt: same-line doc comment on variable declaration" { + try testTransform( + \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space + \\pub const MAP_FILE = 0x0000; /// map from file (default) + \\ + , + \\/// allocated from memory, swap space + \\pub const MAP_ANONYMOUS = 0x1000; + \\/// map from file (default) + \\pub const MAP_FILE = 0x0000; + \\ + ); +} + test "zig fmt: same-line comment after a statement" { try testCanonical( \\test "" { diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig index f10703e3ee..7bf1e68180 100644 --- a/test/cases/type_info.zig +++ b/test/cases/type_info.zig @@ -4,167 +4,199 @@ const TypeInfo = @import("builtin").TypeInfo; const TypeId = @import("builtin").TypeId; test "type info: tag type, void info" { - comptime { - assert(@TagType(TypeInfo) == TypeId); - const void_info = @typeInfo(void); - assert(TypeId(void_info) == TypeId.Void); - assert(void_info.Void == {}); - } + testBasic(); + comptime testBasic(); +} + +fn testBasic() void { + assert(@TagType(TypeInfo) == TypeId); + const void_info = @typeInfo(void); + assert(TypeId(void_info) == TypeId.Void); + assert(void_info.Void == {}); } test "type info: integer, floating point type info" { - comptime { - const u8_info = @typeInfo(u8); - assert(TypeId(u8_info) == TypeId.Int); - assert(!u8_info.Int.is_signed); - assert(u8_info.Int.bits == 8); + testIntFloat(); + comptime testIntFloat(); +} - const f64_info = @typeInfo(f64); - assert(TypeId(f64_info) == TypeId.Float); - assert(f64_info.Float.bits == 64); - } +fn testIntFloat() void { + const u8_info = @typeInfo(u8); + assert(TypeId(u8_info) == TypeId.Int); + assert(!u8_info.Int.is_signed); + assert(u8_info.Int.bits == 8); + + const f64_info = @typeInfo(f64); + assert(TypeId(f64_info) == TypeId.Float); + assert(f64_info.Float.bits == 64); } test "type info: pointer type info" { - comptime { - const u32_ptr_info = @typeInfo(&u32); - assert(TypeId(u32_ptr_info) == TypeId.Pointer); - assert(u32_ptr_info.Pointer.is_const == false); - assert(u32_ptr_info.Pointer.is_volatile == false); - assert(u32_ptr_info.Pointer.alignment == 4); - assert(u32_ptr_info.Pointer.child == u32); - } + testPointer(); + comptime testPointer(); +} + +fn testPointer() void { + const u32_ptr_info = @typeInfo(&u32); + assert(TypeId(u32_ptr_info) == TypeId.Pointer); + assert(u32_ptr_info.Pointer.is_const == false); + assert(u32_ptr_info.Pointer.is_volatile == false); + assert(u32_ptr_info.Pointer.alignment == 4); + assert(u32_ptr_info.Pointer.child == u32); } test "type info: slice type info" { - comptime { - const u32_slice_info = @typeInfo([]u32); - assert(TypeId(u32_slice_info) == TypeId.Slice); - assert(u32_slice_info.Slice.is_const == false); - assert(u32_slice_info.Slice.is_volatile == false); - assert(u32_slice_info.Slice.alignment == 4); - assert(u32_slice_info.Slice.child == u32); - } + testSlice(); + comptime testSlice(); +} + +fn testSlice() void { + const u32_slice_info = @typeInfo([]u32); + assert(TypeId(u32_slice_info) == TypeId.Slice); + assert(u32_slice_info.Slice.is_const == false); + assert(u32_slice_info.Slice.is_volatile == false); + assert(u32_slice_info.Slice.alignment == 4); + assert(u32_slice_info.Slice.child == u32); } test "type info: array type info" { - comptime { - const arr_info = @typeInfo([42]bool); - assert(TypeId(arr_info) == TypeId.Array); - assert(arr_info.Array.len == 42); - assert(arr_info.Array.child == bool); - } + testArray(); + comptime testArray(); +} + +fn testArray() void { + const arr_info = @typeInfo([42]bool); + assert(TypeId(arr_info) == TypeId.Array); + assert(arr_info.Array.len == 42); + assert(arr_info.Array.child == bool); } test "type info: nullable type info" { - comptime { - const null_info = @typeInfo(?void); - assert(TypeId(null_info) == TypeId.Nullable); - assert(null_info.Nullable.child == void); - } + testNullable(); + comptime testNullable(); +} + +fn testNullable() void { + const null_info = @typeInfo(?void); + assert(TypeId(null_info) == TypeId.Nullable); + assert(null_info.Nullable.child == void); } test "type info: promise info" { - comptime { - const null_promise_info = @typeInfo(promise); - assert(TypeId(null_promise_info) == TypeId.Promise); - assert(null_promise_info.Promise.child == @typeOf(undefined)); + testPromise(); + comptime testPromise(); +} - const promise_info = @typeInfo(promise->usize); - assert(TypeId(promise_info) == TypeId.Promise); - assert(promise_info.Promise.child == usize); - } +fn testPromise() void { + const null_promise_info = @typeInfo(promise); + assert(TypeId(null_promise_info) == TypeId.Promise); + assert(null_promise_info.Promise.child == @typeOf(undefined)); + const promise_info = @typeInfo(promise->usize); + assert(TypeId(promise_info) == TypeId.Promise); + assert(promise_info.Promise.child == usize); } test "type info: error set, error union info" { - comptime { - const TestErrorSet = error { - First, - Second, - Third, - }; + testErrorSet(); + comptime testErrorSet(); +} - const error_set_info = @typeInfo(TestErrorSet); - assert(TypeId(error_set_info) == TypeId.ErrorSet); - assert(error_set_info.ErrorSet.errors.len == 3); - assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); - assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third)); +fn testErrorSet() void { + const TestErrorSet = error { + First, + Second, + Third, + }; - const error_union_info = @typeInfo(TestErrorSet!usize); - assert(TypeId(error_union_info) == TypeId.ErrorUnion); - assert(error_union_info.ErrorUnion.error_set == TestErrorSet); - assert(error_union_info.ErrorUnion.payload == usize); - } + const error_set_info = @typeInfo(TestErrorSet); + assert(TypeId(error_set_info) == TypeId.ErrorSet); + assert(error_set_info.ErrorSet.errors.len == 3); + assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); + assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third)); + + const error_union_info = @typeInfo(TestErrorSet!usize); + assert(TypeId(error_union_info) == TypeId.ErrorUnion); + assert(error_union_info.ErrorUnion.error_set == TestErrorSet); + assert(error_union_info.ErrorUnion.payload == usize); } test "type info: enum info" { - comptime { - const Os = @import("builtin").Os; + testEnum(); + comptime testEnum(); +} - const os_info = @typeInfo(Os); - assert(TypeId(os_info) == TypeId.Enum); - assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); - assert(os_info.Enum.fields.len == 32); - assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas")); - assert(os_info.Enum.fields[10].value == 10); - assert(os_info.Enum.tag_type == u5); - assert(os_info.Enum.defs.len == 0); - } +fn testEnum() void { + const Os = @import("builtin").Os; + + const os_info = @typeInfo(Os); + assert(TypeId(os_info) == TypeId.Enum); + assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); + assert(os_info.Enum.fields.len == 32); + assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas")); + assert(os_info.Enum.fields[10].value == 10); + assert(os_info.Enum.tag_type == u5); + assert(os_info.Enum.defs.len == 0); } test "type info: union info" { - comptime { - const typeinfo_info = @typeInfo(TypeInfo); - assert(TypeId(typeinfo_info) == TypeId.Union); - assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assert(typeinfo_info.Union.tag_type == TypeId); - assert(typeinfo_info.Union.fields.len == 26); - assert(typeinfo_info.Union.fields[4].enum_field != null); - assert((??typeinfo_info.Union.fields[4].enum_field).value == 4); - assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assert(typeinfo_info.Union.defs.len == 21); + testUnion(); + comptime testUnion(); +} - const TestNoTagUnion = union { - Foo: void, - Bar: u32, - }; +fn testUnion() void { + const typeinfo_info = @typeInfo(TypeInfo); + assert(TypeId(typeinfo_info) == TypeId.Union); + assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); + assert(typeinfo_info.Union.tag_type == TypeId); + assert(typeinfo_info.Union.fields.len == 26); + assert(typeinfo_info.Union.fields[4].enum_field != null); + assert((??typeinfo_info.Union.fields[4].enum_field).value == 4); + assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); + assert(typeinfo_info.Union.defs.len == 21); - const notag_union_info = @typeInfo(TestNoTagUnion); - assert(TypeId(notag_union_info) == TypeId.Union); - assert(notag_union_info.Union.tag_type == @typeOf(undefined)); - assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assert(notag_union_info.Union.fields.len == 2); - assert(notag_union_info.Union.fields[0].enum_field == null); - assert(notag_union_info.Union.fields[1].field_type == u32); + const TestNoTagUnion = union { + Foo: void, + Bar: u32, + }; - const TestExternUnion = extern union { - foo: &c_void, - }; + const notag_union_info = @typeInfo(TestNoTagUnion); + assert(TypeId(notag_union_info) == TypeId.Union); + assert(notag_union_info.Union.tag_type == @typeOf(undefined)); + assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); + assert(notag_union_info.Union.fields.len == 2); + assert(notag_union_info.Union.fields[0].enum_field == null); + assert(notag_union_info.Union.fields[1].field_type == u32); - const extern_union_info = @typeInfo(TestExternUnion); - assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); - assert(extern_union_info.Union.tag_type == @typeOf(undefined)); - assert(extern_union_info.Union.fields[0].enum_field == null); - assert(extern_union_info.Union.fields[0].field_type == &c_void); - } + const TestExternUnion = extern union { + foo: &c_void, + }; + + const extern_union_info = @typeInfo(TestExternUnion); + assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); + assert(extern_union_info.Union.tag_type == @typeOf(undefined)); + assert(extern_union_info.Union.fields[0].enum_field == null); + assert(extern_union_info.Union.fields[0].field_type == &c_void); } test "type info: struct info" { - comptime { - const struct_info = @typeInfo(TestStruct); - assert(TypeId(struct_info) == TypeId.Struct); - assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); - assert(struct_info.Struct.fields.len == 3); - assert(struct_info.Struct.fields[1].offset == null); - assert(struct_info.Struct.fields[2].field_type == &TestStruct); - assert(struct_info.Struct.defs.len == 2); - assert(struct_info.Struct.defs[0].is_pub); - assert(!struct_info.Struct.defs[0].data.Fn.is_extern); - assert(struct_info.Struct.defs[0].data.Fn.lib_name == null); - assert(struct_info.Struct.defs[0].data.Fn.return_type == void); - assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void); - } + testStruct(); + comptime testStruct(); +} + +fn testStruct() void { + const struct_info = @typeInfo(TestStruct); + assert(TypeId(struct_info) == TypeId.Struct); + assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); + assert(struct_info.Struct.fields.len == 3); + assert(struct_info.Struct.fields[1].offset == null); + assert(struct_info.Struct.fields[2].field_type == &TestStruct); + assert(struct_info.Struct.defs.len == 2); + assert(struct_info.Struct.defs[0].is_pub); + assert(!struct_info.Struct.defs[0].data.Fn.is_extern); + assert(struct_info.Struct.defs[0].data.Fn.lib_name == null); + assert(struct_info.Struct.defs[0].data.Fn.return_type == void); + assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void); } const TestStruct = packed struct { @@ -178,21 +210,24 @@ const TestStruct = packed struct { }; test "type info: function type info" { - comptime { - const fn_info = @typeInfo(@typeOf(foo)); - assert(TypeId(fn_info) == TypeId.Fn); - assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); - assert(fn_info.Fn.is_generic); - assert(fn_info.Fn.args.len == 2); - assert(fn_info.Fn.is_var_args); - assert(fn_info.Fn.return_type == @typeOf(undefined)); - assert(fn_info.Fn.async_allocator_type == @typeOf(undefined)); + testFunction(); + comptime testFunction(); +} - const test_instance: TestStruct = undefined; - const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); - assert(TypeId(bound_fn_info) == TypeId.BoundFn); - assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct); - } +fn testFunction() void { + const fn_info = @typeInfo(@typeOf(foo)); + assert(TypeId(fn_info) == TypeId.Fn); + assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); + assert(fn_info.Fn.is_generic); + assert(fn_info.Fn.args.len == 2); + assert(fn_info.Fn.is_var_args); + assert(fn_info.Fn.return_type == @typeOf(undefined)); + assert(fn_info.Fn.async_allocator_type == @typeOf(undefined)); + + const test_instance: TestStruct = undefined; + const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); + assert(TypeId(bound_fn_info) == TypeId.BoundFn); + assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct); } fn foo(comptime a: usize, b: bool, args: ...) usize {