authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-11 18:27:06-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-11 18:27:06-04:00
logce68dda4b60914e947088e7cf0c5626ea7cebc08
treefca8e600e1b48862d816e5caa87f6fa5ab50d175
parent588116cacc77535137262832f1b2aa464e7a1131
parented1b028276bc1d17ee5e99863dd5bf150c8aa2f7

Merge remote-tracking branch 'origin/master' into llvm7


38 files changed, 8600 insertions(+), 1975 deletions(-)

CMakeLists.txt+11-2
...@@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE)...@@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE)
5 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)5 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
6endif()6endif()
77
8if(NOT CMAKE_INSTALL_PREFIX)
9 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE STRING
10 "Directory to install zig to" FORCE)
11endif()
12
8project(zig C CXX)13project(zig C CXX)
9set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})14set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
1015
...@@ -432,12 +437,17 @@ set(ZIG_STD_FILES...@@ -432,12 +437,17 @@ set(ZIG_STD_FILES
432 "dwarf.zig"437 "dwarf.zig"
433 "elf.zig"438 "elf.zig"
434 "empty.zig"439 "empty.zig"
435 "endian.zig"440 "event.zig"
436 "fmt/errol/enum3.zig"441 "fmt/errol/enum3.zig"
437 "fmt/errol/index.zig"442 "fmt/errol/index.zig"
438 "fmt/errol/lookup.zig"443 "fmt/errol/lookup.zig"
439 "fmt/index.zig"444 "fmt/index.zig"
440 "hash_map.zig"445 "hash_map.zig"
446 "hash/index.zig"
447 "hash/adler.zig"
448 "hash/crc.zig"
449 "hash/fnv.zig"
450 "hash/siphash.zig"
441 "heap.zig"451 "heap.zig"
442 "index.zig"452 "index.zig"
443 "io.zig"453 "io.zig"
...@@ -498,7 +508,6 @@ set(ZIG_STD_FILES...@@ -498,7 +508,6 @@ set(ZIG_STD_FILES
498 "os/get_user_id.zig"508 "os/get_user_id.zig"
499 "os/index.zig"509 "os/index.zig"
500 "os/linux/errno.zig"510 "os/linux/errno.zig"
501 "os/linux/i386.zig"
502 "os/linux/index.zig"511 "os/linux/index.zig"
503 "os/linux/x86_64.zig"512 "os/linux/x86_64.zig"
504 "os/path.zig"513 "os/path.zig"
README.md+4-4
...@@ -141,10 +141,10 @@ libc. Create demo games using Zig....@@ -141,10 +141,10 @@ libc. Create demo games using Zig.
141```141```
142mkdir build142mkdir build
143cd build143cd build
144cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)144cmake ..
145make145make
146make install146make install
147./zig build --build-file ../build.zig test147bin/zig build --build-file ../build.zig test
148```148```
149149
150##### MacOS150##### MacOS
...@@ -154,9 +154,9 @@ brew install cmake llvm@7...@@ -154,9 +154,9 @@ brew install cmake llvm@7
154brew outdated llvm@7 || brew upgrade llvm@7154brew outdated llvm@7 || brew upgrade llvm@7
155mkdir build155mkdir build
156cd build156cd build
157cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@7/ -DCMAKE_INSTALL_PREFIX=$(pwd)157cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@7/
158make install158make install
159./zig build --build-file ../build.zig test159bin/zig build --build-file ../build.zig test
160```160```
161161
162##### Windows162##### Windows
doc/langref.html.in+39-3
...@@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C };...@@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C };
1947export fn entry(foo: Foo) void { }1947export fn entry(foo: Foo) void { }
1948 {#code_end#}1948 {#code_end#}
1949 {#header_close#}1949 {#header_close#}
1950 <p>TODO packed enum</p>1950 {#header_open|packed enum#}
1951 {#see_also|@memberName|@memberCount|@tagName#}1951 <p>By default, the size of enums is not guaranteed.</p>
1952 <p><code>packed enum</code> causes the size of the enum to be the same as the size of the integer tag type
1953 of the enum:</p>
1954 {#code_begin|test#}
1955const std = @import("std");
1956
1957test "packed enum" {
1958 const Number = packed enum(u8) {
1959 One,
1960 Two,
1961 Three,
1962 };
1963 std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
1964}
1965 {#code_end#}
1966 {#header_close#}
1967 {#see_also|@memberName|@memberCount|@tagName|@sizeOf#}
1952 {#header_close#}1968 {#header_close#}
1953 {#header_open|union#}1969 {#header_open|union#}
1954 {#code_begin|test|union#}1970 {#code_begin|test|union#}
...@@ -2017,7 +2033,27 @@ test "union variant switch" {...@@ -2017,7 +2033,27 @@ test "union variant switch" {
2017 assert(mem.eql(u8, what_is_it, "this is a number"));2033 assert(mem.eql(u8, what_is_it, "this is a number"));
2018}2034}
20192035
2020// TODO union methods2036// Unions can have methods just like structs and enums:
2037
2038const Variant = union(enum) {
2039 Int: i32,
2040 Bool: bool,
2041
2042 fn truthy(self: &const Variant) bool {
2043 return switch (*self) {
2044 Variant.Int => |x_int| x_int != 0,
2045 Variant.Bool => |x_bool| x_bool,
2046 };
2047 }
2048};
2049
2050test "union method" {
2051 var v1 = Variant { .Int = 1 };
2052 var v2 = Variant { .Bool = false };
2053
2054 assert(v1.truthy());
2055 assert(!v2.truthy());
2056}
20212057
20222058
2023const Small = union {2059const Small = union {
src-self-hosted/main.zig+1
...@@ -741,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {...@@ -741,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
741 defer baf.destroy();741 defer baf.destroy();
742742
743 try parser.renderSource(baf.stream(), tree.root_node);743 try parser.renderSource(baf.stream(), tree.root_node);
744 try baf.finish();
744 }745 }
745}746}
746747
src/all_types.hpp+32-12
...@@ -359,7 +359,6 @@ enum NodeType {...@@ -359,7 +359,6 @@ enum NodeType {
359 NodeTypeRoot,359 NodeTypeRoot,
360 NodeTypeFnProto,360 NodeTypeFnProto,
361 NodeTypeFnDef,361 NodeTypeFnDef,
362 NodeTypeFnDecl,
363 NodeTypeParamDecl,362 NodeTypeParamDecl,
364 NodeTypeBlock,363 NodeTypeBlock,
365 NodeTypeGroupedExpr,364 NodeTypeGroupedExpr,
...@@ -453,10 +452,6 @@ struct AstNodeFnDef {...@@ -453,10 +452,6 @@ struct AstNodeFnDef {
453 AstNode *body;452 AstNode *body;
454};453};
455454
456struct AstNodeFnDecl {
457 AstNode *fn_proto;
458};
459
460struct AstNodeParamDecl {455struct AstNodeParamDecl {
461 Buf *name;456 Buf *name;
462 AstNode *type;457 AstNode *type;
...@@ -713,10 +708,6 @@ struct AstNodeSwitchRange {...@@ -713,10 +708,6 @@ struct AstNodeSwitchRange {
713 AstNode *end;708 AstNode *end;
714};709};
715710
716struct AstNodeLabel {
717 Buf *name;
718};
719
720struct AstNodeCompTime {711struct AstNodeCompTime {
721 AstNode *expr;712 AstNode *expr;
722};713};
...@@ -892,7 +883,6 @@ struct AstNode {...@@ -892,7 +883,6 @@ struct AstNode {
892 union {883 union {
893 AstNodeRoot root;884 AstNodeRoot root;
894 AstNodeFnDef fn_def;885 AstNodeFnDef fn_def;
895 AstNodeFnDecl fn_decl;
896 AstNodeFnProto fn_proto;886 AstNodeFnProto fn_proto;
897 AstNodeParamDecl param_decl;887 AstNodeParamDecl param_decl;
898 AstNodeBlock block;888 AstNodeBlock block;
...@@ -917,7 +907,6 @@ struct AstNode {...@@ -917,7 +907,6 @@ struct AstNode {
917 AstNodeSwitchExpr switch_expr;907 AstNodeSwitchExpr switch_expr;
918 AstNodeSwitchProng switch_prong;908 AstNodeSwitchProng switch_prong;
919 AstNodeSwitchRange switch_range;909 AstNodeSwitchRange switch_range;
920 AstNodeLabel label;
921 AstNodeCompTime comptime_expr;910 AstNodeCompTime comptime_expr;
922 AstNodeAsmExpr asm_expr;911 AstNodeAsmExpr asm_expr;
923 AstNodeFieldAccessExpr field_access_expr;912 AstNodeFieldAccessExpr field_access_expr;
...@@ -1654,6 +1643,8 @@ struct CodeGen {...@@ -1654,6 +1643,8 @@ struct CodeGen {
1654 LLVMValueRef coro_save_fn_val;1643 LLVMValueRef coro_save_fn_val;
1655 LLVMValueRef coro_promise_fn_val;1644 LLVMValueRef coro_promise_fn_val;
1656 LLVMValueRef coro_alloc_helper_fn_val;1645 LLVMValueRef coro_alloc_helper_fn_val;
1646 LLVMValueRef merge_err_ret_traces_fn_val;
1647 LLVMValueRef add_error_return_trace_addr_fn_val;
1657 bool error_during_imports;1648 bool error_during_imports;
16581649
1659 const char **clang_argv;1650 const char **clang_argv;
...@@ -2052,6 +2043,8 @@ enum IrInstructionId {...@@ -2052,6 +2043,8 @@ enum IrInstructionId {
2052 IrInstructionIdAwaitBookkeeping,2043 IrInstructionIdAwaitBookkeeping,
2053 IrInstructionIdSaveErrRetAddr,2044 IrInstructionIdSaveErrRetAddr,
2054 IrInstructionIdAddImplicitReturnType,2045 IrInstructionIdAddImplicitReturnType,
2046 IrInstructionIdMergeErrRetTraces,
2047 IrInstructionIdMarkErrRetTracePtr,
2055};2048};
20562049
2057struct IrInstruction {2050struct IrInstruction {
...@@ -2890,6 +2883,11 @@ struct IrInstructionExport {...@@ -2890,6 +2883,11 @@ struct IrInstructionExport {
28902883
2891struct IrInstructionErrorReturnTrace {2884struct IrInstructionErrorReturnTrace {
2892 IrInstruction base;2885 IrInstruction base;
2886
2887 enum Nullable {
2888 Null,
2889 NonNull,
2890 } nullable;
2893};2891};
28942892
2895struct IrInstructionErrorUnion {2893struct IrInstructionErrorUnion {
...@@ -3022,6 +3020,20 @@ struct IrInstructionAddImplicitReturnType {...@@ -3022,6 +3020,20 @@ struct IrInstructionAddImplicitReturnType {
3022 IrInstruction *value;3020 IrInstruction *value;
3023};3021};
30243022
3023struct IrInstructionMergeErrRetTraces {
3024 IrInstruction base;
3025
3026 IrInstruction *coro_promise_ptr;
3027 IrInstruction *src_err_ret_trace_ptr;
3028 IrInstruction *dest_err_ret_trace_ptr;
3029};
3030
3031struct IrInstructionMarkErrRetTracePtr {
3032 IrInstruction base;
3033
3034 IrInstruction *err_ret_trace_ptr;
3035};
3036
3025static const size_t slice_ptr_index = 0;3037static const size_t slice_ptr_index = 0;
3026static const size_t slice_len_index = 1;3038static const size_t slice_len_index = 1;
30273039
...@@ -3031,10 +3043,18 @@ static const size_t maybe_null_index = 1;...@@ -3031,10 +3043,18 @@ static const size_t maybe_null_index = 1;
3031static const size_t err_union_err_index = 0;3043static const size_t err_union_err_index = 0;
3032static const size_t err_union_payload_index = 1;3044static const size_t err_union_payload_index = 1;
30333045
3046// TODO call graph analysis to find out what this number needs to be for every function
3047static const size_t stack_trace_ptr_count = 30;
3048
3049// these belong to the async function
3050#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
3051#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
3052#define RESULT_FIELD_NAME "result"
3034#define ASYNC_ALLOC_FIELD_NAME "allocFn"3053#define ASYNC_ALLOC_FIELD_NAME "allocFn"
3035#define ASYNC_FREE_FIELD_NAME "freeFn"3054#define ASYNC_FREE_FIELD_NAME "freeFn"
3036#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"3055#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
3037#define RESULT_FIELD_NAME "result"3056// these point to data belonging to the awaiter
3057#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3038#define RESULT_PTR_FIELD_NAME "result_ptr"3058#define RESULT_PTR_FIELD_NAME "result_ptr"
30393059
30403060
src/analyze.cpp+23-4
...@@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)...@@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
468468
469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
471 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};471
472 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};472 ZigList<const char *> field_names = {};
473 field_names.append(AWAITER_HANDLE_FIELD_NAME);
474 field_names.append(RESULT_FIELD_NAME);
475 field_names.append(RESULT_PTR_FIELD_NAME);
476 if (g->have_err_ret_tracing) {
477 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
478 field_names.append(ERR_RET_TRACE_FIELD_NAME);
479 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
480 }
481
482 ZigList<TypeTableEntry *> field_types = {};
483 field_types.append(awaiter_handle_type);
484 field_types.append(return_type);
485 field_types.append(result_ptr_type);
486 if (g->have_err_ret_tracing) {
487 field_types.append(get_ptr_to_stack_trace_type(g));
488 field_types.append(g->stack_trace_type);
489 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
490 }
491
492 assert(field_names.length == field_types.length);
473 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));493 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
474 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3);494 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
475495
476 return_type->promise_frame_parent = entry;496 return_type->promise_frame_parent = entry;
477 return entry;497 return entry;
...@@ -3216,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3216,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3216 break;3236 break;
3217 case NodeTypeContainerDecl:3237 case NodeTypeContainerDecl:
3218 case NodeTypeParamDecl:3238 case NodeTypeParamDecl:
3219 case NodeTypeFnDecl:
3220 case NodeTypeReturnExpr:3239 case NodeTypeReturnExpr:
3221 case NodeTypeDefer:3240 case NodeTypeDefer:
3222 case NodeTypeBlock:3241 case NodeTypeBlock:
src/ast_render.cpp-3
...@@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {...@@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {
148 return "Root";148 return "Root";
149 case NodeTypeFnDef:149 case NodeTypeFnDef:
150 return "FnDef";150 return "FnDef";
151 case NodeTypeFnDecl:
152 return "FnDecl";
153 case NodeTypeFnProto:151 case NodeTypeFnProto:
154 return "FnProto";152 return "FnProto";
155 case NodeTypeParamDecl:153 case NodeTypeParamDecl:
...@@ -1098,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1098,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1098 }1096 }
1099 break;1097 break;
1100 }1098 }
1101 case NodeTypeFnDecl:
1102 case NodeTypeParamDecl:1099 case NodeTypeParamDecl:
1103 case NodeTypeTestDecl:1100 case NodeTypeTestDecl:
1104 case NodeTypeStructField:1101 case NodeTypeStructField:
src/codegen.cpp+254-47
...@@ -412,6 +412,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e...@@ -412,6 +412,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
412 if (!g->have_err_ret_tracing) {412 if (!g->have_err_ret_tracing) {
413 return UINT32_MAX;413 return UINT32_MAX;
414 }414 }
415 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
416 return 0;
417 }
415 TypeTableEntry *fn_type = fn_table_entry->type_entry;418 TypeTableEntry *fn_type = fn_table_entry->type_entry;
416 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {419 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
417 return UINT32_MAX;420 return UINT32_MAX;
...@@ -1099,22 +1102,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {...@@ -1099,22 +1102,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1099 return g->return_address_fn_val;1102 return g->return_address_fn_val;
1100}1103}
11011104
1102static LLVMValueRef get_return_err_fn(CodeGen *g) {1105static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1103 if (g->return_err_fn != nullptr)1106 if (g->add_error_return_trace_addr_fn_val != nullptr)
1104 return g->return_err_fn;1107 return g->add_error_return_trace_addr_fn_val;
1105
1106 assert(g->err_tag_type != nullptr);
11071108
1108 LLVMTypeRef arg_types[] = {1109 LLVMTypeRef arg_types[] = {
1109 // error return trace pointer
1110 get_ptr_to_stack_trace_type(g)->type_ref,1110 get_ptr_to_stack_trace_type(g)->type_ref,
1111 g->builtin_types.entry_usize->type_ref,
1111 };1112 };
1112 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);1113 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
11131114
1114 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);1115 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false);
1115 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);1116 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1116 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address1117 addLLVMFnAttr(fn_val, "alwaysinline");
1117 addLLVMFnAttr(fn_val, "cold");
1118 LLVMSetLinkage(fn_val, LLVMInternalLinkage);1118 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1119 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1119 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1120 addLLVMFnAttr(fn_val, "nounwind");1120 addLLVMFnAttr(fn_val, "nounwind");
...@@ -1136,6 +1136,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1136,6 +1136,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1136 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;1136 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
11371137
1138 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);1138 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1139 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
1140
1139 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;1141 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1140 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");1142 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
1141 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;1143 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
...@@ -1157,15 +1159,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1157,15 +1159,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1157 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");1159 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
1158 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");1160 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");
11591161
1160 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1161 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1162 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1163
1164 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
1165 gen_store_untyped(g, address_value, address_slot, 0, false);1162 gen_store_untyped(g, address_value, address_slot, 0, false);
11661163
1167 // stack_trace.index += 1;1164 // stack_trace.index += 1;
1168 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");1165 LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
1169 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);1166 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
11701167
1171 // return;1168 // return;
...@@ -1174,6 +1171,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1174,6 +1171,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1174 LLVMPositionBuilderAtEnd(g->builder, prev_block);1171 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1175 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1172 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
11761173
1174 g->add_error_return_trace_addr_fn_val = fn_val;
1175 return fn_val;
1176}
1177
1178static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1179 if (g->merge_err_ret_traces_fn_val)
1180 return g->merge_err_ret_traces_fn_val;
1181
1182 assert(g->stack_trace_type != nullptr);
1183
1184 LLVMTypeRef param_types[] = {
1185 get_ptr_to_stack_trace_type(g)->type_ref,
1186 get_ptr_to_stack_trace_type(g)->type_ref,
1187 };
1188 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1189
1190 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1191 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1192 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1193 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1194 addLLVMFnAttr(fn_val, "nounwind");
1195 add_uwtable_attr(g, fn_val);
1196 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1197 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1198 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1199 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1200 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1201 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1202 if (g->build_mode == BuildModeDebug) {
1203 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1204 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1205 }
1206
1207 // this is above the ZigLLVMClearCurrentDebugLocation
1208 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1209
1210 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1211 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1212 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1213 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1214 ZigLLVMClearCurrentDebugLocation(g->builder);
1215
1216 // var frame_index: usize = undefined;
1217 // var frames_left: usize = undefined;
1218 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1219 // frame_index = 0;
1220 // frames_left = src_stack_trace.index;
1221 // if (frames_left == 0) return;
1222 // } else {
1223 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1224 // frames_left = src_stack_trace.instruction_addresses.len;
1225 // }
1226 // while (true) {
1227 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1228 // frames_left -= 1;
1229 // if (frames_left == 0) return;
1230 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1231 // }
1232 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1233
1234 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index");
1235 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left");
1236
1237 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1238 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1239
1240 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1241 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1242 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1243 (unsigned)src_index_field_index, "");
1244 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1245 (unsigned)src_addresses_field_index, "");
1246 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1247 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1248 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1249 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1250 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1251 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1252 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1253 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1254 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1255 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1256 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1257 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1258 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1259
1260 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1261 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
1262 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1263 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1264 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1265 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1266
1267 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1268 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
1269 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1270 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1271 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1272 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1273 LLVMBuildBr(g->builder, loop_block);
1274
1275 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1276 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1277 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1278 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1279 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1280 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1281 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1282 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1283 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1284 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1285 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1286
1287 LLVMPositionBuilderAtEnd(g->builder, return_block);
1288 LLVMBuildRetVoid(g->builder);
1289
1290 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1291 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1292 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1293 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1294 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1295 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1296 LLVMBuildBr(g->builder, loop_block);
1297
1298 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1299 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1300
1301 g->merge_err_ret_traces_fn_val = fn_val;
1302 return fn_val;
1303
1304}
1305
1306static LLVMValueRef get_return_err_fn(CodeGen *g) {
1307 if (g->return_err_fn != nullptr)
1308 return g->return_err_fn;
1309
1310 assert(g->err_tag_type != nullptr);
1311
1312 LLVMTypeRef arg_types[] = {
1313 // error return trace pointer
1314 get_ptr_to_stack_trace_type(g)->type_ref,
1315 };
1316 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
1317
1318 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
1319 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1320 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address
1321 addLLVMFnAttr(fn_val, "cold");
1322 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1323 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1324 addLLVMFnAttr(fn_val, "nounwind");
1325 add_uwtable_attr(g, fn_val);
1326 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1327 if (g->build_mode == BuildModeDebug) {
1328 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1329 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1330 }
1331
1332 // this is above the ZigLLVMClearCurrentDebugLocation
1333 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1334
1335 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1336 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1337 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1338 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1339 ZigLLVMClearCurrentDebugLocation(g->builder);
1340
1341 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1342
1343 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
1344 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1345 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1346 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1347
1348 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1349 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1350 LLVMBuildRetVoid(g->builder);
1351
1352 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1353 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1354
1177 g->return_err_fn = fn_val;1355 g->return_err_fn = fn_val;
1178 return fn_val;1356 return fn_val;
1179}1357}
...@@ -1608,7 +1786,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut...@@ -1608,7 +1786,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
1608 };1786 };
1609 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,1787 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1610 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");1788 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1611 LLVMSetTailCall(call_instruction, true);
1612 return call_instruction;1789 return call_instruction;
1613}1790}
16141791
...@@ -4119,6 +4296,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -4119,6 +4296,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4119 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");4296 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
4120}4297}
41214298
4299static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
4300 IrInstructionMergeErrRetTraces *instruction)
4301{
4302 assert(g->have_err_ret_tracing);
4303
4304 LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr);
4305 LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr);
4306
4307 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
4308 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4309 return nullptr;
4310}
4311
4312static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable,
4313 IrInstructionMarkErrRetTracePtr *instruction)
4314{
4315 assert(g->have_err_ret_tracing);
4316 g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr);
4317 return nullptr;
4318}
4319
4122static void set_debug_location(CodeGen *g, IrInstruction *instruction) {4320static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
4123 AstNode *source_node = instruction->source_node;4321 AstNode *source_node = instruction->source_node;
4124 Scope *scope = instruction->scope;4322 Scope *scope = instruction->scope;
...@@ -4336,6 +4534,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4336,6 +4534,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4336 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);4534 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4337 case IrInstructionIdSaveErrRetAddr:4535 case IrInstructionIdSaveErrRetAddr:
4338 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);4536 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
4537 case IrInstructionIdMergeErrRetTraces:
4538 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
4539 case IrInstructionIdMarkErrRetTracePtr:
4540 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
4339 }4541 }
4340 zig_unreachable();4542 zig_unreachable();
4341}4543}
...@@ -5225,38 +5427,14 @@ static void do_code_gen(CodeGen *g) {...@@ -5225,38 +5427,14 @@ static void do_code_gen(CodeGen *g) {
5225 g->cur_err_ret_trace_val_arg = nullptr;5427 g->cur_err_ret_trace_val_arg = nullptr;
5226 }5428 }
52275429
5430 // error return tracing setup
5228 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;5431 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
5229 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&5432 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
5230 (is_async || !have_err_ret_trace_arg);5433 LLVMValueRef err_ret_array_val = nullptr;
5231 if (have_err_ret_trace_stack) {5434 if (have_err_ret_trace_stack) {
5232 // TODO call graph analysis to find out what this number needs to be for every function5435 TypeTableEntry *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
5233 static const size_t stack_trace_ptr_count = 30;5436 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
5234
5235 TypeTableEntry *usize = g->builtin_types.entry_usize;
5236 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
5237 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
5238 get_abi_alignment(g, array_type));
5239 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));5437 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
5240 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5241 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5242 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5243
5244 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5245 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5246
5247 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5248 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5249 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5250 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5251 LLVMValueRef indices[] = {zero, zero};
5252 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5253 indices, 2, "");
5254 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr,
5255 get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false));
5256
5257 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5258 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5259 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5260 } else {5438 } else {
5261 g->cur_err_ret_trace_val_stack = nullptr;5439 g->cur_err_ret_trace_val_stack = nullptr;
5262 }5440 }
...@@ -5351,6 +5529,31 @@ static void do_code_gen(CodeGen *g) {...@@ -5351,6 +5529,31 @@ static void do_code_gen(CodeGen *g) {
5351 }5529 }
5352 }5530 }
53535531
5532 // finishing error return trace setup. we have to do this after all the allocas.
5533 if (have_err_ret_trace_stack) {
5534 TypeTableEntry *usize = g->builtin_types.entry_usize;
5535 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5536 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5537 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5538
5539 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5540 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5541
5542 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5543 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5544 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5545 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5546 LLVMValueRef indices[] = {zero, zero};
5547 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5548 indices, 2, "");
5549 TypeTableEntry *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false);
5550 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type);
5551
5552 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5553 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5554 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5555 }
5556
5354 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;5557 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
53555558
5356 // create debug variable declarations for parameters5559 // create debug variable declarations for parameters
...@@ -5858,6 +6061,8 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5858,6 +6061,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
5858 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);6061 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5859 Buf *contents = buf_alloc();6062 Buf *contents = buf_alloc();
58606063
6064 // Modifications to this struct must be coordinated with code that does anything with
6065 // g->stack_trace_type. There are hard-coded references to the field indexes.
5861 buf_append_str(contents,6066 buf_append_str(contents,
5862 "pub const StackTrace = struct {\n"6067 "pub const StackTrace = struct {\n"
5863 " index: usize,\n"6068 " index: usize,\n"
...@@ -6122,7 +6327,9 @@ static void init(CodeGen *g) {...@@ -6122,7 +6327,9 @@ static void init(CodeGen *g) {
6122 g->builder = LLVMCreateBuilder();6327 g->builder = LLVMCreateBuilder();
6123 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);6328 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);
61246329
6125 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);6330 // Don't use ZIG_VERSION_STRING here, llvm misparses it when it includes
6331 // the git revision.
6332 Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH);
6126 const char *flags = "";6333 const char *flags = "";
6127 unsigned runtime_version = 0;6334 unsigned runtime_version = 0;
6128 ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),6335 ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),
src/ir.cpp+196-83
...@@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur...@@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
725 return IrInstructionIdAddImplicitReturnType;725 return IrInstructionIdAddImplicitReturnType;
726}726}
727727
728static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
729 return IrInstructionIdMergeErrRetTraces;
730}
731
732static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
733 return IrInstructionIdMarkErrRetTracePtr;
734}
735
728template<typename T>736template<typename T>
729static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {737static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
730 T *special_instruction = allocate<T>(1);738 T *special_instruction = allocate<T>(1);
...@@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast...@@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
956 return &const_instruction->base;964 return &const_instruction->base;
957}965}
958966
959static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
960 TypeTableEntry *return_type)
961{
962 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
963
964 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
965 const_instruction->base.value.type = struct_type;
966 const_instruction->base.value.special = ConstValSpecialStatic;
967 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
968 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
969 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
970 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
971 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
972 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
973 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
974 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
975 return &const_instruction->base;
976}
977
978static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,967static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
979 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)968 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
980{969{
...@@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
2495 return &instruction->base;2484 return &instruction->base;
2496}2485}
24972486
2498static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {2487static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
2499 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);2488 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2489 instruction->nullable = nullable;
25002490
2501 return &instruction->base;2491 return &instruction->base;
2502}2492}
...@@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s...@@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
2717 return &instruction->base;2707 return &instruction->base;
2718}2708}
27192709
2710static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
2711 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
2712{
2713 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
2714 instruction->coro_promise_ptr = coro_promise_ptr;
2715 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
2716 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
2717
2718 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
2719 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
2720 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
2721
2722 return &instruction->base;
2723}
2724
2725static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
2726 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
2727 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
2728
2729 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
2730
2731 return &instruction->base;
2732}
2733
2720static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2734static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2721 results[ReturnKindUnconditional] = 0;2735 results[ReturnKindUnconditional] = 0;
2722 results[ReturnKindError] = 0;2736 results[ReturnKindError] = 0;
...@@ -2741,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {...@@ -2741,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
27412755
2742static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {2756static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
2743 Scope *scope = inner_scope;2757 Scope *scope = inner_scope;
2758 bool is_noreturn = false;
2744 while (scope != outer_scope) {2759 while (scope != outer_scope) {
2745 if (!scope)2760 if (!scope)
2746 return false;2761 return is_noreturn;
27472762
2748 if (scope->id == ScopeIdDefer) {2763 if (scope->id == ScopeIdDefer) {
2749 AstNode *defer_node = scope->source_node;2764 AstNode *defer_node = scope->source_node;
...@@ -2756,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -2756,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
2756 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;2771 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
2757 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);2772 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
2758 if (defer_expr_value != irb->codegen->invalid_instruction) {2773 if (defer_expr_value != irb->codegen->invalid_instruction) {
2759 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));2774 if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
2775 is_noreturn = true;
2776 } else {
2777 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
2778 }
2760 }2779 }
2761 }2780 }
27622781
2763 }2782 }
2764 scope = scope->parent;2783 scope = scope->parent;
2765 }2784 }
2766 return true;2785 return is_noreturn;
2767}2786}
27682787
2769static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {2788static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
...@@ -2822,34 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2822,34 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2822 // the above blocks are rendered by ir_gen after the rest of codegen2841 // the above blocks are rendered by ir_gen after the rest of codegen
2823}2842}
28242843
2825static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2826 if (!g->have_err_ret_tracing)
2827 return false;
2828 FnTableEntry *fn_entry = exec_fn_entry(exec);
2829 if (fn_entry == nullptr)
2830 return false;
2831 if (exec->is_inline)
2832 return false;
2833 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2834}
2835
2836static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2837 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2838 return;
2839
2840 bool is_async = exec_is_async(irb->exec);
2841
2842 if (is_async) {
2843 //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2844 //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node);
2845 //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2846 //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2847 return;
2848 }
2849
2850 ir_build_save_err_ret_addr(irb, scope, node);
2851}
2852
2853static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2844static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2854 assert(node->type == NodeTypeReturnExpr);2845 assert(node->type == NodeTypeReturnExpr);
28552846
...@@ -2895,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2895,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28952886
2896 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);2887 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
28972888
2889 bool should_inline = ir_should_inline(irb->exec, scope);
2898 IrInstruction *is_comptime;2890 IrInstruction *is_comptime;
2899 if (ir_should_inline(irb->exec, scope)) {2891 if (should_inline) {
2900 is_comptime = ir_build_const_bool(irb, scope, node, true);2892 is_comptime = ir_build_const_bool(irb, scope, node, true);
2901 } else {2893 } else {
2902 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);2894 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
...@@ -2909,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2909,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2909 if (have_err_defers) {2901 if (have_err_defers) {
2910 ir_gen_defers_for_block(irb, scope, outer_scope, true);2902 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2911 }2903 }
2912 ir_gen_save_err_ret_addr(irb, scope, node);2904 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2905 ir_build_save_err_ret_addr(irb, scope, node);
2906 }
2913 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2907 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
29142908
2915 ir_set_cursor_at_end_and_append_block(irb, ok_block);2909 ir_set_cursor_at_end_and_append_block(irb, ok_block);
...@@ -2938,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2938,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2938 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");2932 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
2939 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");2933 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
2940 IrInstruction *is_comptime;2934 IrInstruction *is_comptime;
2941 if (ir_should_inline(irb->exec, scope)) {2935 bool should_inline = ir_should_inline(irb->exec, scope);
2936 if (should_inline) {
2942 is_comptime = ir_build_const_bool(irb, scope, node, true);2937 is_comptime = ir_build_const_bool(irb, scope, node, true);
2943 } else {2938 } else {
2944 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);2939 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
...@@ -2946,10 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2946,10 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2946 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));2941 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
29472942
2948 ir_set_cursor_at_end_and_append_block(irb, return_block);2943 ir_set_cursor_at_end_and_append_block(irb, return_block);
2949 ir_gen_defers_for_block(irb, scope, outer_scope, true);2944 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
2950 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);2945 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2951 ir_gen_save_err_ret_addr(irb, scope, node);2946 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2952 ir_gen_async_return(irb, scope, node, err_val, false);2947 ir_build_save_err_ret_addr(irb, scope, node);
2948 }
2949 ir_gen_async_return(irb, scope, node, err_val, false);
2950 }
29532951
2954 ir_set_cursor_at_end_and_append_block(irb, continue_block);2952 ir_set_cursor_at_end_and_append_block(irb, continue_block);
2955 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);2953 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
...@@ -4242,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4242,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4242 }4240 }
4243 case BuiltinFnIdErrorReturnTrace:4241 case BuiltinFnIdErrorReturnTrace:
4244 {4242 {
4245 return ir_build_error_return_trace(irb, scope, node);4243 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4246 }4244 }
4247 case BuiltinFnIdAtomicRmw:4245 case BuiltinFnIdAtomicRmw:
4248 {4246 {
...@@ -5703,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -5703,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
57035701
5704 IrBasicBlock *dest_block = loop_scope->continue_block;5702 IrBasicBlock *dest_block = loop_scope->continue_block;
5705 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);5703 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);
5706 return ir_build_br(irb, continue_scope, node, dest_block, is_comptime);5704 return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime));
5707}5705}
57085706
5709static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {5707static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -6125,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6125,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6125 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6123 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6126 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);6124 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
61276125
6126 if (irb->codegen->have_err_ret_tracing) {
6127 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6128 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6129 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6130 ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
6131 }
6132
6128 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6133 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6129 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,6134 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
6130 awaiter_handle_field_name);6135 awaiter_handle_field_name);
...@@ -6148,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6148,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6148 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);6153 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6149 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");6154 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6150 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");6155 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6151 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");6156 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend");
6152 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);6157 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
61536158
6154 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);6159 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6160 if (irb->codegen->have_err_ret_tracing) {
6161 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6162 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name);
6163 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6164 ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
6165 }
6155 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6166 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6156 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);6167 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6157 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);6168 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
...@@ -6173,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6173,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
61736184
6174 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6185 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6175 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6186 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6176 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6187 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
61776188
6178 ir_set_cursor_at_end_and_append_block(irb, resume_block);6189 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6179 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);6190 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
...@@ -6249,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -6249,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
62496260
6250 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6261 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6251 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6262 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6252 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6263 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
62536264
6254 ir_set_cursor_at_end_and_append_block(irb, resume_block);6265 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6255 return ir_build_const_void(irb, parent_scope, node);6266 return ir_build_const_void(irb, parent_scope, node);
...@@ -6268,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -6268,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
6268 case NodeTypeSwitchRange:6279 case NodeTypeSwitchRange:
6269 case NodeTypeStructField:6280 case NodeTypeStructField:
6270 case NodeTypeFnDef:6281 case NodeTypeFnDef:
6271 case NodeTypeFnDecl:
6272 case NodeTypeTestDecl:6282 case NodeTypeTestDecl:
6273 zig_unreachable();6283 zig_unreachable();
6274 case NodeTypeBlock:6284 case NodeTypeBlock:
...@@ -6407,6 +6417,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6407,6 +6417,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6407 IrInstruction *coro_id;6417 IrInstruction *coro_id;
6408 IrInstruction *u8_ptr_type;6418 IrInstruction *u8_ptr_type;
6409 IrInstruction *const_bool_false;6419 IrInstruction *const_bool_false;
6420 IrInstruction *coro_promise_ptr;
6421 IrInstruction *err_ret_trace_ptr;
6410 TypeTableEntry *return_type;6422 TypeTableEntry *return_type;
6411 Buf *result_ptr_field_name;6423 Buf *result_ptr_field_name;
6412 VariableTableEntry *coro_size_var;6424 VariableTableEntry *coro_size_var;
...@@ -6417,9 +6429,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6417,9 +6429,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6417 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6429 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
64186430
6419 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;6431 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
6420 IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type);6432 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6421 ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init);6433 TypeTableEntry *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
6422 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);6434 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
6435 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
6436 ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
6437 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
64236438
6424 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6439 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6425 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);6440 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
...@@ -6452,7 +6467,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6452,7 +6467,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6452 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);6467 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6453 // we can return undefined here, because the caller passes a pointer to the error struct field6468 // we can return undefined here, because the caller passes a pointer to the error struct field
6454 // in the error union result, and we populate it in case of allocation failure.6469 // in the error union result, and we populate it in case of allocation failure.
6455 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6456 ir_build_return(irb, coro_scope, node, undef);6470 ir_build_return(irb, coro_scope, node, undef);
64576471
6458 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);6472 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
...@@ -6460,13 +6474,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6460,13 +6474,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6460 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);6474 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
64616475
6462 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6476 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6463 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr,6477 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6464 awaiter_handle_field_name);6478 awaiter_handle_field_name);
6479 ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value);
6465 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6480 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6466 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name);6481 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6467 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6482 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6468 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name);6483 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
6469 ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);6484 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6485 if (irb->codegen->have_err_ret_tracing) {
6486 // initialize the error return trace
6487 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
6488 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
6489
6490 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6491 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
6492 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
6493
6494 // coordinate with builtin.zig
6495 Buf *index_name = buf_create_from_str("index");
6496 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name);
6497 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6498 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
6499
6500 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
6501 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
6502
6503 IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false);
6504 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
6505 }
64706506
64716507
6472 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");6508 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
...@@ -6517,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6517,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6517 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);6553 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
6518 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);6554 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
6519 }6555 }
6556 if (irb->codegen->have_err_ret_tracing) {
6557 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6558 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6559 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
6560 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
6561 }
6520 ir_build_br(irb, scope, node, check_free_block, const_bool_false);6562 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
65216563
6522 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);6564 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
...@@ -11579,18 +11621,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {...@@ -11579,18 +11621,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
11579static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,11621static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11580 IrInstructionErrorReturnTrace *instruction)11622 IrInstructionErrorReturnTrace *instruction)
11581{11623{
11582 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11624 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
11583 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);11625 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11584 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {11626 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11585 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11627 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11586 out_val->data.x_maybe = nullptr;11628 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11629 out_val->data.x_maybe = nullptr;
11630 return nullable_type;
11631 }
11632 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11633 instruction->base.source_node, instruction->nullable);
11634 ir_link_new_instruction(new_instruction, &instruction->base);
11587 return nullable_type;11635 return nullable_type;
11636 } else {
11637 assert(ira->codegen->have_err_ret_tracing);
11638 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11639 instruction->base.source_node, instruction->nullable);
11640 ir_link_new_instruction(new_instruction, &instruction->base);
11641 return get_ptr_to_stack_trace_type(ira->codegen);
11588 }11642 }
11589
11590 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11591 instruction->base.source_node);
11592 ir_link_new_instruction(new_instruction, &instruction->base);
11593 return nullable_type;
11594}11643}
1159511644
11596static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,11645static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
...@@ -11755,7 +11804,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -11755,7 +11804,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
11755 }11804 }
11756 }11805 }
1175711806
11758 bool comptime_arg = param_decl_node->data.param_decl.is_inline;11807 bool comptime_arg = param_decl_node->data.param_decl.is_inline ||
11808 casted_arg->value.type->id == TypeTableEntryIdNumLitInt || casted_arg->value.type->id == TypeTableEntryIdNumLitFloat;
1175911809
11760 ConstExprValue *arg_val;11810 ConstExprValue *arg_val;
1176111811
...@@ -11780,6 +11830,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -11780,6 +11830,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
11780 var->shadowable = !comptime_arg;11830 var->shadowable = !comptime_arg;
1178111831
11782 *next_proto_i += 1;11832 *next_proto_i += 1;
11833 } else if (casted_arg->value.type->id == TypeTableEntryIdNumLitInt ||
11834 casted_arg->value.type->id == TypeTableEntryIdNumLitFloat)
11835 {
11836 ir_add_error(ira, casted_arg,
11837 buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557"));
11838 return false;
11783 }11839 }
1178411840
11785 if (!comptime_arg) {11841 if (!comptime_arg) {
...@@ -13072,6 +13128,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -13072,6 +13128,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
13072{13128{
13073 if (!is_slice(bare_struct_type)) {13129 if (!is_slice(bare_struct_type)) {
13074 ScopeDecls *container_scope = get_container_scope(bare_struct_type);13130 ScopeDecls *container_scope = get_container_scope(bare_struct_type);
13131 assert(container_scope != nullptr);
13075 auto entry = container_scope->decl_table.maybe_get(field_name);13132 auto entry = container_scope->decl_table.maybe_get(field_name);
13076 Tld *tld = entry ? entry->value : nullptr;13133 Tld *tld = entry ? entry->value : nullptr;
13077 if (tld && tld->id == TldIdFn) {13134 if (tld && tld->id == TldIdFn) {
...@@ -16702,6 +16759,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -16702,6 +16759,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
16702 return ira->codegen->builtin_types.entry_invalid;16759 return ira->codegen->builtin_types.entry_invalid;
1670316760
16704 if (fn_type_id.cc == CallingConventionAsync) {16761 if (fn_type_id.cc == CallingConventionAsync) {
16762 if (instruction->async_allocator_type_value == nullptr) {
16763 ir_add_error(ira, &instruction->base,
16764 buf_sprintf("async fn proto missing allocator type"));
16765 return ira->codegen->builtin_types.entry_invalid;
16766 }
16705 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;16767 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;
16706 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);16768 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
16707 if (type_is_invalid(fn_type_id.async_allocator_type))16769 if (type_is_invalid(fn_type_id.async_allocator_type))
...@@ -17904,6 +17966,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,...@@ -17904,6 +17966,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
17904 return out_val->type;17966 return out_val->type;
17905}17967}
1790617968
17969static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
17970 IrInstructionMergeErrRetTraces *instruction)
17971{
17972 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other;
17973 if (type_is_invalid(coro_promise_ptr->value.type))
17974 return ira->codegen->builtin_types.entry_invalid;
17975
17976 assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer);
17977 TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
17978 assert(promise_frame_type->id == TypeTableEntryIdStruct);
17979 TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
17980
17981 if (!type_can_fail(promise_result_type)) {
17982 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17983 out_val->type = ira->codegen->builtin_types.entry_void;
17984 return out_val->type;
17985 }
17986
17987 IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other;
17988 if (type_is_invalid(src_err_ret_trace_ptr->value.type))
17989 return ira->codegen->builtin_types.entry_invalid;
17990
17991 IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other;
17992 if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
17993 return ira->codegen->builtin_types.entry_invalid;
17994
17995 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
17996 instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
17997 ir_link_new_instruction(result, &instruction->base);
17998 result->value.type = ira->codegen->builtin_types.entry_void;
17999 return result->value.type;
18000}
18001
17907static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {18002static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
17908 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,18003 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
17909 instruction->base.source_node);18004 instruction->base.source_node);
...@@ -17912,6 +18007,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira,...@@ -17912,6 +18007,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira,
17912 return result->value.type;18007 return result->value.type;
17913}18008}
1791418009
18010static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) {
18011 IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other;
18012 if (type_is_invalid(err_ret_trace_ptr->value.type))
18013 return ira->codegen->builtin_types.entry_invalid;
18014
18015 IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope,
18016 instruction->base.source_node, err_ret_trace_ptr);
18017 ir_link_new_instruction(result, &instruction->base);
18018 result->value.type = ira->codegen->builtin_types.entry_void;
18019 return result->value.type;
18020}
18021
17915static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {18022static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17916 switch (instruction->id) {18023 switch (instruction->id) {
17917 case IrInstructionIdInvalid:18024 case IrInstructionIdInvalid:
...@@ -18155,6 +18262,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -18155,6 +18262,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
18155 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);18262 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
18156 case IrInstructionIdAddImplicitReturnType:18263 case IrInstructionIdAddImplicitReturnType:
18157 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);18264 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
18265 case IrInstructionIdMergeErrRetTraces:
18266 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
18267 case IrInstructionIdMarkErrRetTracePtr:
18268 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
18158 }18269 }
18159 zig_unreachable();18270 zig_unreachable();
18160}18271}
...@@ -18282,6 +18393,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18282,6 +18393,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18282 case IrInstructionIdAwaitBookkeeping:18393 case IrInstructionIdAwaitBookkeeping:
18283 case IrInstructionIdSaveErrRetAddr:18394 case IrInstructionIdSaveErrRetAddr:
18284 case IrInstructionIdAddImplicitReturnType:18395 case IrInstructionIdAddImplicitReturnType:
18396 case IrInstructionIdMergeErrRetTraces:
18397 case IrInstructionIdMarkErrRetTracePtr:
18285 return true;18398 return true;
1828618399
18287 case IrInstructionIdPhi:18400 case IrInstructionIdPhi:
src/ir_print.cpp+32-1
...@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {...@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
1024}1024}
10251025
1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1027 fprintf(irp->f, "@errorReturnTrace()");1027 fprintf(irp->f, "@errorReturnTrace(");
1028 switch (instruction->nullable) {
1029 case IrInstructionErrorReturnTrace::Null:
1030 fprintf(irp->f, "Null");
1031 break;
1032 case IrInstructionErrorReturnTrace::NonNull:
1033 fprintf(irp->f, "NonNull");
1034 break;
1035 }
1036 fprintf(irp->f, ")");
1028}1037}
10291038
1030static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {1039static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
...@@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl...@@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
1179 fprintf(irp->f, ")");1188 fprintf(irp->f, ")");
1180}1189}
11811190
1191static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1192 fprintf(irp->f, "@mergeErrRetTraces(");
1193 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1194 fprintf(irp->f, ",");
1195 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1196 fprintf(irp->f, ",");
1197 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1198 fprintf(irp->f, ")");
1199}
1200
1201static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1202 fprintf(irp->f, "@markErrRetTracePtr(");
1203 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1204 fprintf(irp->f, ")");
1205}
1206
1182static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1207static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1183 ir_print_prefix(irp, instruction);1208 ir_print_prefix(irp, instruction);
1184 switch (instruction->id) {1209 switch (instruction->id) {
...@@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1559 case IrInstructionIdAddImplicitReturnType:1584 case IrInstructionIdAddImplicitReturnType:
1560 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);1585 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
1561 break;1586 break;
1587 case IrInstructionIdMergeErrRetTraces:
1588 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
1589 break;
1590 case IrInstructionIdMarkErrRetTracePtr:
1591 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
1592 break;
1562 }1593 }
1563 fprintf(irp->f, "\n");1594 fprintf(irp->f, "\n");
1564}1595}
src/parser.cpp-3
...@@ -2923,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2923,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2923 visit_field(&node->data.fn_def.fn_proto, visit, context);2923 visit_field(&node->data.fn_def.fn_proto, visit, context);
2924 visit_field(&node->data.fn_def.body, visit, context);2924 visit_field(&node->data.fn_def.body, visit, context);
2925 break;2925 break;
2926 case NodeTypeFnDecl:
2927 visit_field(&node->data.fn_decl.fn_proto, visit, context);
2928 break;
2929 case NodeTypeParamDecl:2926 case NodeTypeParamDecl:
2930 visit_field(&node->data.param_decl.type, visit, context);2927 visit_field(&node->data.param_decl.type, visit, context);
2931 break;2928 break;
std/buf_map.zig+34-17
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const HashMap = @import("hash_map.zig").HashMap;1const std = @import("index.zig");
2const mem = @import("mem.zig");2const HashMap = std.HashMap;
3const mem = std.mem;
3const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
5const assert = std.debug.assert;
46
5/// BufMap copies keys and values before they go into the map, and7/// BufMap copies keys and values before they go into the map, and
6/// frees them when they get removed.8/// frees them when they get removed.
...@@ -28,18 +30,12 @@ pub const BufMap = struct {...@@ -28,18 +30,12 @@ pub const BufMap = struct {
28 }30 }
2931
30 pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void {32 pub fn set(self: &BufMap, key: []const u8, value: []const u8) !void {
31 if (self.hash_map.get(key)) |entry| {33 self.delete(key);
32 const value_copy = try self.copy(value);34 const key_copy = try self.copy(key);
33 errdefer self.free(value_copy);35 errdefer self.free(key_copy);
34 _ = try self.hash_map.put(key, value_copy);36 const value_copy = try self.copy(value);
35 self.free(entry.value);37 errdefer self.free(value_copy);
36 } else {38 _ = try self.hash_map.put(key_copy, value_copy);
37 const key_copy = try self.copy(key);
38 errdefer self.free(key_copy);
39 const value_copy = try self.copy(value);
40 errdefer self.free(value_copy);
41 _ = try self.hash_map.put(key_copy, value_copy);
42 }
43 }39 }
4440
45 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {41 pub fn get(self: &BufMap, key: []const u8) ?[]const u8 {
...@@ -66,8 +62,29 @@ pub const BufMap = struct {...@@ -66,8 +62,29 @@ pub const BufMap = struct {
66 }62 }
6763
68 fn copy(self: &BufMap, value: []const u8) ![]const u8 {64 fn copy(self: &BufMap, value: []const u8) ![]const u8 {
69 const result = try self.hash_map.allocator.alloc(u8, value.len);65 return mem.dupe(self.hash_map.allocator, u8, value);
70 mem.copy(u8, result, value);
71 return result;
72 }66 }
73};67};
68
69test "BufMap" {
70 var direct_allocator = std.heap.DirectAllocator.init();
71 defer direct_allocator.deinit();
72
73 var bufmap = BufMap.init(&direct_allocator.allocator);
74 defer bufmap.deinit();
75
76 try bufmap.set("x", "1");
77 assert(mem.eql(u8, ??bufmap.get("x"), "1"));
78 assert(1 == bufmap.count());
79
80 try bufmap.set("x", "2");
81 assert(mem.eql(u8, ??bufmap.get("x"), "2"));
82 assert(1 == bufmap.count());
83
84 try bufmap.set("x", "3");
85 assert(mem.eql(u8, ??bufmap.get("x"), "3"));
86 assert(1 == bufmap.count());
87
88 bufmap.delete("x");
89 assert(0 == bufmap.count());
90}
std/c/darwin.zig+8
...@@ -55,3 +55,11 @@ pub const dirent = extern struct {...@@ -55,3 +55,11 @@ pub const dirent = extern struct {
55 d_type: u8,55 d_type: u8,
56 d_name: u8, // field address is address of first byte of name56 d_name: u8, // field address is address of first byte of name
57};57};
58
59pub const sockaddr = extern struct {
60 sa_len: u8,
61 sa_family: sa_family_t,
62 sa_data: [14]u8,
63};
64
65pub const sa_family_t = u8;
std/endian.zig deleted-25
...@@ -1,25 +0,0 @@
1const mem = @import("mem.zig");
2const builtin = @import("builtin");
3
4pub fn swapIfLe(comptime T: type, x: T) T {
5 return swapIf(builtin.Endian.Little, T, x);
6}
7
8pub fn swapIfBe(comptime T: type, x: T) T {
9 return swapIf(builtin.Endian.Big, T, x);
10}
11
12pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) T {
13 return if (builtin.endian == endian) swap(T, x) else x;
14}
15
16pub fn swap(comptime T: type, x: T) T {
17 var buf: [@sizeOf(T)]u8 = undefined;
18 mem.writeInt(buf[0..], x, builtin.Endian.Little);
19 return mem.readInt(buf, T, builtin.Endian.Big);
20}
21
22test "swap" {
23 const debug = @import("debug/index.zig");
24 debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE);
25}
std/event.zig created+235
...@@ -0,0 +1,235 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const event = this;
5const mem = std.mem;
6const posix = std.os.posix;
7
8pub const TcpServer = struct {
9 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
10
11 loop: &Loop,
12 sockfd: i32,
13 accept_coro: ?promise,
14 listen_address: std.net.Address,
15
16 waiting_for_emfile_node: PromiseNode,
17
18 const PromiseNode = std.LinkedList(promise).Node;
19
20 pub fn init(loop: &Loop) !TcpServer {
21 const sockfd = try std.os.posixSocket(posix.AF_INET,
22 posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
23 posix.PROTO_tcp);
24 errdefer std.os.close(sockfd);
25
26 // TODO can't initialize handler coroutine here because we need well defined copy elision
27 return TcpServer {
28 .loop = loop,
29 .sockfd = sockfd,
30 .accept_coro = null,
31 .handleRequestFn = undefined,
32 .waiting_for_emfile_node = undefined,
33 .listen_address = undefined,
34 };
35 }
36
37 pub fn listen(self: &TcpServer, address: &const std.net.Address,
38 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
39 {
40 self.handleRequestFn = handleRequestFn;
41
42 try std.os.posixBind(self.sockfd, &address.os_addr);
43 try std.os.posixListen(self.sockfd, posix.SOMAXCONN);
44 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
45
46 self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self);
47 errdefer cancel ??self.accept_coro;
48
49 try self.loop.addFd(self.sockfd, ??self.accept_coro);
50 errdefer self.loop.removeFd(self.sockfd);
51
52 }
53
54 pub fn deinit(self: &TcpServer) void {
55 self.loop.removeFd(self.sockfd);
56 if (self.accept_coro) |accept_coro| cancel accept_coro;
57 std.os.close(self.sockfd);
58 }
59
60 pub async fn handler(self: &TcpServer) void {
61 while (true) {
62 var accepted_addr: std.net.Address = undefined;
63 if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
64 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
65 {
66 var socket = std.os.File.openHandle(accepted_fd);
67 _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
68 error.OutOfMemory => {
69 socket.close();
70 continue;
71 },
72 };
73 } else |err| switch (err) {
74 error.WouldBlock => {
75 suspend; // we will get resumed by epoll_wait in the event loop
76 continue;
77 },
78 error.ProcessFdQuotaExceeded => {
79 errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
80 suspend |p| {
81 self.waiting_for_emfile_node = PromiseNode.init(p);
82 std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
83 }
84 continue;
85 },
86 error.ConnectionAborted,
87 error.FileDescriptorClosed => continue,
88
89 error.PageFault => unreachable,
90 error.InvalidSyscall => unreachable,
91 error.FileDescriptorNotASocket => unreachable,
92 error.OperationNotSupported => unreachable,
93
94 error.SystemFdQuotaExceeded,
95 error.SystemResources,
96 error.ProtocolFailure,
97 error.BlockedByFirewall,
98 error.Unexpected => {
99 @panic("TODO handle this error");
100 },
101 }
102 }
103 }
104};
105
106pub const Loop = struct {
107 allocator: &mem.Allocator,
108 epollfd: i32,
109 keep_running: bool,
110
111 fn init(allocator: &mem.Allocator) !Loop {
112 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
113 return Loop {
114 .keep_running = true,
115 .allocator = allocator,
116 .epollfd = epollfd,
117 };
118 }
119
120 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
121 var ev = std.os.linux.epoll_event {
122 .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,
123 .data = std.os.linux.epoll_data {
124 .ptr = @ptrToInt(prom),
125 },
126 };
127 try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
128 }
129
130 pub fn removeFd(self: &Loop, fd: i32) void {
131 std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
132 }
133
134 async fn waitFd(self: &Loop, fd: i32) !void {
135 defer self.removeFd(fd);
136 suspend |p| {
137 try self.addFd(fd, p);
138 }
139 }
140
141 pub fn stop(self: &Loop) void {
142 // TODO make atomic
143 self.keep_running = false;
144 // TODO activate an fd in the epoll set
145 }
146
147 pub fn run(self: &Loop) void {
148 while (self.keep_running) {
149 var events: [16]std.os.linux.epoll_event = undefined;
150 const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1);
151 for (events[0..count]) |ev| {
152 const p = @intToPtr(promise, ev.data.ptr);
153 resume p;
154 }
155 }
156 }
157};
158
159pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
160 var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733
161
162 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);
163 errdefer std.os.close(sockfd);
164
165 try std.os.posixConnectAsync(sockfd, &address.os_addr);
166 try await try async loop.waitFd(sockfd);
167 try std.os.posixGetSockOptConnectError(sockfd);
168
169 return std.os.File.openHandle(sockfd);
170}
171
172test "listen on a port, send bytes, receive bytes" {
173 if (builtin.os != builtin.Os.linux) {
174 // TODO build abstractions for other operating systems
175 return;
176 }
177 const MyServer = struct {
178 tcp_server: TcpServer,
179
180 const Self = this;
181
182 async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,
183 _socket: &const std.os.File) void
184 {
185 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
186 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
187 defer socket.close();
188 const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
189 error.OutOfMemory => @panic("unable to handle connection: out of memory"),
190 };
191 (await next_handler) catch |err| {
192 std.debug.panic("unable to handle connection: {}\n", err);
193 };
194 suspend |p| { cancel p; }
195 }
196
197 async fn errorableHandler(self: &Self, _addr: &const std.net.Address,
198 _socket: &const std.os.File) !void
199 {
200 const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
201 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
202
203 var adapter = std.io.FileOutStream.init(&socket);
204 var stream = &adapter.stream;
205 try stream.print("hello from server\n");
206 }
207 };
208
209 const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable;
210 const addr = std.net.Address.initIp4(ip4addr, 0);
211
212 var loop = try Loop.init(std.debug.global_allocator);
213 var server = MyServer {
214 .tcp_server = try TcpServer.init(&loop),
215 };
216 defer server.tcp_server.deinit();
217 try server.tcp_server.listen(addr, MyServer.handler);
218
219 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address);
220 defer cancel p;
221 loop.run();
222}
223
224async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void {
225 errdefer @panic("test failure");
226
227 var socket_file = try await try async event.connect(loop, address);
228 defer socket_file.close();
229
230 var buf: [512]u8 = undefined;
231 const amt_read = try socket_file.read(buf[0..]);
232 const msg = buf[0..amt_read];
233 assert(mem.eql(u8, msg, "hello from server\n"));
234 loop.stop();
235}
std/fmt/index.zig+1-1
...@@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned...@@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
465 return x;465 return x;
466}466}
467467
468fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {468pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
469 const value = switch (c) {469 const value = switch (c) {
470 '0' ... '9' => c - '0',470 '0' ... '9' => c - '0',
471 'A' ... 'Z' => c - 'A' + 10,471 'A' ... 'Z' => c - 'A' + 10,
std/hash/adler.zig created+112
...@@ -0,0 +1,112 @@
1// Adler32 checksum.
2//
3// https://tools.ietf.org/html/rfc1950#section-9
4// https://github.com/madler/zlib/blob/master/adler32.c
5
6const std = @import("../index.zig");
7const debug = std.debug;
8
9pub const Adler32 = struct {
10 const base = 65521;
11 const nmax = 5552;
12
13 adler: u32,
14
15 pub fn init() Adler32 {
16 return Adler32 {
17 .adler = 1,
18 };
19 }
20
21 // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
22 // buffer inputs and should be much quicker.
23 pub fn update(self: &Adler32, input: []const u8) void {
24 var s1 = self.adler & 0xffff;
25 var s2 = (self.adler >> 16) & 0xffff;
26
27 if (input.len == 1) {
28 s1 +%= input[0];
29 if (s1 >= base) {
30 s1 -= base;
31 }
32 s2 +%= s1;
33 if (s2 >= base) {
34 s2 -= base;
35 }
36 }
37 else if (input.len < 16) {
38 for (input) |b| {
39 s1 +%= b;
40 s2 +%= s1;
41 }
42 if (s1 >= base) {
43 s1 -= base;
44 }
45
46 s2 %= base;
47 }
48 else {
49 var i: usize = 0;
50 while (i + nmax <= input.len) : (i += nmax) {
51 const n = nmax / 16; // note: 16 | nmax
52
53 var rounds: usize = 0;
54 while (rounds < n) : (rounds += 1) {
55 comptime var j: usize = 0;
56 inline while (j < 16) : (j += 1) {
57 s1 +%= input[i + n * j];
58 s2 +%= s1;
59 }
60 }
61 }
62
63 if (i < input.len) {
64 while (i + 16 <= input.len) : (i += 16) {
65 comptime var j: usize = 0;
66 inline while (j < 16) : (j += 1) {
67 s1 +%= input[i + j];
68 s2 +%= s1;
69 }
70 }
71 while (i < input.len) : (i += 1) {
72 s1 +%= input[i];
73 s2 +%= s1;
74 }
75
76 s1 %= base;
77 s2 %= base;
78 }
79 }
80
81 self.adler = s1 | (s2 << 16);
82 }
83
84 pub fn final(self: &Adler32) u32 {
85 return self.adler;
86 }
87
88 pub fn hash(input: []const u8) u32 {
89 var c = Adler32.init();
90 c.update(input);
91 return c.final();
92 }
93};
94
95test "adler32 sanity" {
96 debug.assert(Adler32.hash("a") == 0x620062);
97 debug.assert(Adler32.hash("example") == 0xbc002ed);
98}
99
100test "adler32 long" {
101 const long1 = []u8 {1} ** 1024;
102 debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
103
104 const long2 = []u8 {1} ** 1025;
105 debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
106}
107
108test "adler32 very long" {
109 const long = []u8 {1} ** 5553;
110 debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
111}
112
std/hash/crc.zig created+180
...@@ -0,0 +1,180 @@
1// There are two implementations of CRC32 implemented with the following key characteristics:
2//
3// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
4//
5// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
6// still moderately fast just slow relative to the slicing approach.
7
8const std = @import("../index.zig");
9const debug = std.debug;
10
11pub const Polynomial = struct {
12 const IEEE = 0xedb88320;
13 const Castagnoli = 0x82f63b78;
14 const Koopman = 0xeb31d82e;
15};
16
17// IEEE is by far the most common CRC and so is aliased by default.
18pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);
19
20// slicing-by-8 crc32 implementation.
21pub fn Crc32WithPoly(comptime poly: u32) type {
22 return struct {
23 const Self = this;
24 const lookup_tables = comptime block: {
25 @setEvalBranchQuota(20000);
26 var tables: [8][256]u32 = undefined;
27
28 for (tables[0]) |*e, i| {
29 var crc = u32(i);
30 var j: usize = 0; while (j < 8) : (j += 1) {
31 if (crc & 1 == 1) {
32 crc = (crc >> 1) ^ poly;
33 } else {
34 crc = (crc >> 1);
35 }
36 }
37 *e = crc;
38 }
39
40 var i: usize = 0;
41 while (i < 256) : (i += 1) {
42 var crc = tables[0][i];
43 var j: usize = 1; while (j < 8) : (j += 1) {
44 const index = @truncate(u8, crc);
45 crc = tables[0][index] ^ (crc >> 8);
46 tables[j][i] = crc;
47 }
48 }
49
50 break :block tables;
51 };
52
53 crc: u32,
54
55 pub fn init() Self {
56 return Self {
57 .crc = 0xffffffff,
58 };
59 }
60
61 pub fn update(self: &Self, input: []const u8) void {
62 var i: usize = 0;
63 while (i + 8 <= input.len) : (i += 8) {
64 const p = input[i..i+8];
65
66 // Unrolling this way gives ~50Mb/s increase
67 self.crc ^= (u32(p[0]) << 0);
68 self.crc ^= (u32(p[1]) << 8);
69 self.crc ^= (u32(p[2]) << 16);
70 self.crc ^= (u32(p[3]) << 24);
71
72 self.crc =
73 lookup_tables[0][p[7]] ^
74 lookup_tables[1][p[6]] ^
75 lookup_tables[2][p[5]] ^
76 lookup_tables[3][p[4]] ^
77 lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
78 lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
79 lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
80 lookup_tables[7][@truncate(u8, self.crc >> 0)];
81 }
82
83 while (i < input.len) : (i += 1) {
84 const index = @truncate(u8, self.crc) ^ input[i];
85 self.crc = (self.crc >> 8) ^ lookup_tables[0][index];
86 }
87 }
88
89 pub fn final(self: &Self) u32 {
90 return ~self.crc;
91 }
92
93 pub fn hash(input: []const u8) u32 {
94 var c = Self.init();
95 c.update(input);
96 return c.final();
97 }
98 };
99}
100
101test "crc32 ieee" {
102 const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);
103
104 debug.assert(Crc32Ieee.hash("") == 0x00000000);
105 debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
106 debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
107}
108
109test "crc32 castagnoli" {
110 const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);
111
112 debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
113 debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
114 debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
115}
116
117// half-byte lookup table implementation.
118pub fn Crc32SmallWithPoly(comptime poly: u32) type {
119 return struct {
120 const Self = this;
121 const lookup_table = comptime block: {
122 var table: [16]u32 = undefined;
123
124 for (table) |*e, i| {
125 var crc = u32(i * 16);
126 var j: usize = 0; while (j < 8) : (j += 1) {
127 if (crc & 1 == 1) {
128 crc = (crc >> 1) ^ poly;
129 } else {
130 crc = (crc >> 1);
131 }
132 }
133 *e = crc;
134 }
135
136 break :block table;
137 };
138
139 crc: u32,
140
141 pub fn init() Self {
142 return Self {
143 .crc = 0xffffffff,
144 };
145 }
146
147 pub fn update(self: &Self, input: []const u8) void {
148 for (input) |b| {
149 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 0))] ^ (self.crc >> 4);
150 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 4))] ^ (self.crc >> 4);
151 }
152 }
153
154 pub fn final(self: &Self) u32 {
155 return ~self.crc;
156 }
157
158 pub fn hash(input: []const u8) u32 {
159 var c = Self.init();
160 c.update(input);
161 return c.final();
162 }
163 };
164}
165
166test "small crc32 ieee" {
167 const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);
168
169 debug.assert(Crc32Ieee.hash("") == 0x00000000);
170 debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
171 debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
172}
173
174test "small crc32 castagnoli" {
175 const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);
176
177 debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
178 debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
179 debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
180}
std/hash/fnv.zig created+60
...@@ -0,0 +1,60 @@
1// FNV1a - Fowler-Noll-Vo hash function
2//
3// FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties.
4//
5// https://tools.ietf.org/html/draft-eastlake-fnv-14
6
7const std = @import("../index.zig");
8const debug = std.debug;
9
10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5);
11pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
12pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d);
13
14fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
15 return struct {
16 const Self = this;
17
18 value: T,
19
20 pub fn init() Self {
21 return Self {
22 .value = offset,
23 };
24 }
25
26 pub fn update(self: &Self, input: []const u8) void {
27 for (input) |b| {
28 self.value ^= b;
29 self.value *%= prime;
30 }
31 }
32
33 pub fn final(self: &Self) T {
34 return self.value;
35 }
36
37 pub fn hash(input: []const u8) T {
38 var c = Self.init();
39 c.update(input);
40 return c.final();
41 }
42 };
43}
44
45test "fnv1a-32" {
46 debug.assert(Fnv1a_32.hash("") == 0x811c9dc5);
47 debug.assert(Fnv1a_32.hash("a") == 0xe40c292c);
48 debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968);
49}
50
51test "fnv1a-64" {
52 debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325);
53 debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c);
54 debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8);
55}
56
57test "fnv1a-128" {
58 debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d);
59 debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964);
60}
std/hash/index.zig created+22
...@@ -0,0 +1,22 @@
1const adler = @import("adler.zig");
2pub const Adler32 = adler.Adler32;
3
4// pub for polynomials + generic crc32 construction
5pub const crc = @import("crc.zig");
6pub const Crc32 = crc.Crc32;
7
8const fnv = @import("fnv.zig");
9pub const Fnv1a_32 = fnv.Fnv1a_32;
10pub const Fnv1a_64 = fnv.Fnv1a_64;
11pub const Fnv1a_128 = fnv.Fnv1a_128;
12
13const siphash = @import("siphash.zig");
14pub const SipHash64 = siphash.SipHash64;
15pub const SipHash128 = siphash.SipHash128;
16
17test "hash" {
18 _ = @import("adler.zig");
19 _ = @import("crc.zig");
20 _ = @import("fnv.zig");
21 _ = @import("siphash.zig");
22}
std/hash/siphash.zig created+320
...@@ -0,0 +1,320 @@
1// Siphash
2//
3// SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance
4// against hash flooding DoS attacks.
5//
6// https://131002.net/siphash/
7
8const std = @import("../index.zig");
9const debug = std.debug;
10const math = std.math;
11const mem = std.mem;
12
13const Endian = @import("builtin").Endian;
14
15pub fn SipHash64(comptime c_rounds: usize, comptime d_rounds: usize) type {
16 return SipHash(u64, c_rounds, d_rounds);
17}
18
19pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type {
20 return SipHash(u128, c_rounds, d_rounds);
21}
22
23fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type {
24 debug.assert(T == u64 or T == u128);
25 debug.assert(c_rounds > 0 and d_rounds > 0);
26
27 return struct {
28 const Self = this;
29 const digest_size = 64;
30 const block_size = 64;
31
32 v0: u64,
33 v1: u64,
34 v2: u64,
35 v3: u64,
36
37 // streaming cache
38 buf: [8]u8,
39 buf_len: usize,
40 msg_len: u8,
41
42 pub fn init(key: []const u8) Self {
43 debug.assert(key.len >= 16);
44
45 const k0 = mem.readInt(key[0..8], u64, Endian.Little);
46 const k1 = mem.readInt(key[8..16], u64, Endian.Little);
47
48 var d = Self {
49 .v0 = k0 ^ 0x736f6d6570736575,
50 .v1 = k1 ^ 0x646f72616e646f6d,
51 .v2 = k0 ^ 0x6c7967656e657261,
52 .v3 = k1 ^ 0x7465646279746573,
53
54 .buf = undefined,
55 .buf_len = 0,
56 .msg_len = 0,
57 };
58
59 if (T == u128) {
60 d.v1 ^= 0xee;
61 }
62
63 return d;
64 }
65
66 pub fn update(d: &Self, b: []const u8) void {
67 var off: usize = 0;
68
69 // Partial from previous.
70 if (d.buf_len != 0 and d.buf_len + b.len > 8) {
71 off += 8 - d.buf_len;
72 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
73 d.round(d.buf[0..]);
74 d.buf_len = 0;
75 }
76
77 // Full middle blocks.
78 while (off + 8 <= b.len) : (off += 8) {
79 d.round(b[off..off + 8]);
80 }
81
82 // Remainder for next pass.
83 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
84 d.buf_len += u8(b[off..].len);
85 d.msg_len +%= @truncate(u8, b.len);
86 }
87
88 pub fn final(d: &Self) T {
89 // Padding
90 mem.set(u8, d.buf[d.buf_len..], 0);
91 d.buf[7] = d.msg_len;
92 d.round(d.buf[0..]);
93
94 if (T == u128) {
95 d.v2 ^= 0xee;
96 } else {
97 d.v2 ^= 0xff;
98 }
99
100 comptime var i: usize = 0;
101 inline while (i < d_rounds) : (i += 1) {
102 @inlineCall(sipRound, d);
103 }
104
105 const b1 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3;
106 if (T == u64) {
107 return b1;
108 }
109
110 d.v1 ^= 0xdd;
111
112 comptime var j: usize = 0;
113 inline while (j < d_rounds) : (j += 1) {
114 @inlineCall(sipRound, d);
115 }
116
117 const b2 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3;
118 return (u128(b2) << 64) | b1;
119 }
120
121 fn round(d: &Self, b: []const u8) void {
122 debug.assert(b.len == 8);
123
124 const m = mem.readInt(b[0..], u64, Endian.Little);
125 d.v3 ^= m;
126
127 comptime var i: usize = 0;
128 inline while (i < c_rounds) : (i += 1) {
129 @inlineCall(sipRound, d);
130 }
131
132 d.v0 ^= m;
133 }
134
135 fn sipRound(d: &Self) void {
136 d.v0 +%= d.v1;
137 d.v1 = math.rotl(u64, d.v1, u64(13));
138 d.v1 ^= d.v0;
139 d.v0 = math.rotl(u64, d.v0, u64(32));
140 d.v2 +%= d.v3;
141 d.v3 = math.rotl(u64, d.v3, u64(16));
142 d.v3 ^= d.v2;
143 d.v0 +%= d.v3;
144 d.v3 = math.rotl(u64, d.v3, u64(21));
145 d.v3 ^= d.v0;
146 d.v2 +%= d.v1;
147 d.v1 = math.rotl(u64, d.v1, u64(17));
148 d.v1 ^= d.v2;
149 d.v2 = math.rotl(u64, d.v2, u64(32));
150 }
151
152 pub fn hash(key: []const u8, input: []const u8) T {
153 var c = Self.init(key);
154 c.update(input);
155 return c.final();
156 }
157 };
158}
159
160// Test vectors from reference implementation.
161// https://github.com/veorq/SipHash/blob/master/vectors.h
162const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
163
164test "siphash64-2-4 sanity" {
165 const vectors = [][]const u8 {
166 "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
167 "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
168 "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
169 "\x2d\x7e\xfb\xd7\x96\x66\x67\x85",
170 "\xb7\x87\x71\x27\xe0\x94\x27\xcf",
171 "\x8d\xa6\x99\xcd\x64\x55\x76\x18",
172 "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb",
173 "\x37\xd1\x01\x8b\xf5\x00\x02\xab",
174 "\x62\x24\x93\x9a\x79\xf5\xf5\x93",
175 "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e",
176 "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a",
177 "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4",
178 "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75",
179 "\x90\x3d\x84\xc0\x27\x56\xea\x14",
180 "\xee\xf2\x7a\x8e\x90\xca\x23\xf7",
181 "\xe5\x45\xbe\x49\x61\xca\x29\xa1",
182 "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f",
183 "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69",
184 "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b",
185 "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb",
186 "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe",
187 "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0",
188 "\x88\x3e\xa3\xe3\x95\x67\x53\x93",
189 "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8",
190 "\x94\xaf\x49\xf6\xc6\x50\xad\xb8",
191 "\xea\xb8\x85\x8a\xde\x92\xe1\xbc",
192 "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17",
193 "\xad\xcf\x6b\x07\x63\x61\x2e\x2f",
194 "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde",
195 "\x71\x65\x95\x87\x66\x50\xa2\xa6",
196 "\x28\xef\x49\x5c\x53\xa3\x87\xad",
197 "\x42\xc3\x41\xd8\xfa\x92\xd8\x32",
198 "\xce\x7c\xf2\x72\x2f\x51\x27\x71",
199 "\xe3\x78\x59\xf9\x46\x23\xf3\xa7",
200 "\x38\x12\x05\xbb\x1a\xb0\xe0\x12",
201 "\xae\x97\xa1\x0f\xd4\x34\xe0\x15",
202 "\xb4\xa3\x15\x08\xbe\xff\x4d\x31",
203 "\x81\x39\x62\x29\xf0\x90\x79\x02",
204 "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca",
205 "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a",
206 "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e",
207 "\x92\x59\x58\xfc\xd6\x42\x0c\xad",
208 "\xa9\x15\xc2\x9b\xc8\x06\x73\x18",
209 "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4",
210 "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9",
211 "\x87\x57\x75\x19\x04\x8f\x53\xa9",
212 "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb",
213 "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0",
214 "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6",
215 "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7",
216 "\x72\xfe\x52\x97\x5a\x43\x64\xee",
217 "\x5a\x16\x45\xb2\x76\xd5\x92\xa1",
218 "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a",
219 "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81",
220 "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f",
221 "\x99\x24\xa4\x3c\xc1\x31\x57\x24",
222 "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7",
223 "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea",
224 "\x13\x50\x79\xa3\x23\x1c\xe6\x60",
225 "\x93\x2b\x28\x46\xe4\xd7\x06\x66",
226 "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c",
227 "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f",
228 "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5",
229 "\x72\x45\x06\xeb\x4c\x32\x8a\x95",
230 };
231
232 const siphash = SipHash64(2, 4);
233
234 var buffer: [64]u8 = undefined;
235 for (vectors) |vector, i| {
236 buffer[i] = u8(i);
237
238 const expected = mem.readInt(vector, u64, Endian.Little);
239 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
240 }
241}
242
243test "siphash128-2-4 sanity" {
244 const vectors = [][]const u8 {
245 "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
246 "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
247 "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
248 "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51",
249 "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79",
250 "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27",
251 "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e",
252 "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39",
253 "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4",
254 "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed",
255 "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba",
256 "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18",
257 "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25",
258 "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7",
259 "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02",
260 "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9",
261 "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77",
262 "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40",
263 "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23",
264 "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1",
265 "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb",
266 "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12",
267 "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae",
268 "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c",
269 "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad",
270 "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f",
271 "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66",
272 "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94",
273 "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4",
274 "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7",
275 "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87",
276 "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35",
277 "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68",
278 "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf",
279 "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde",
280 "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8",
281 "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11",
282 "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b",
283 "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5",
284 "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9",
285 "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8",
286 "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb",
287 "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b",
288 "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89",
289 "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42",
290 "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c",
291 "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02",
292 "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b",
293 "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16",
294 "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03",
295 "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f",
296 "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38",
297 "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c",
298 "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e",
299 "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87",
300 "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda",
301 "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36",
302 "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e",
303 "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d",
304 "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59",
305 "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40",
306 "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a",
307 "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd",
308 "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c",
309 };
310
311 const siphash = SipHash128(2, 4);
312
313 var buffer: [64]u8 = undefined;
314 for (vectors) |vector, i| {
315 buffer[i] = u8(i);
316
317 const expected = mem.readInt(vector, u128, Endian.Little);
318 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
319 }
320}
std/hash_map.zig+5-1
...@@ -114,6 +114,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -114,6 +114,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
114 }114 }
115115
116 pub fn remove(hm: &Self, key: K) ?&Entry {116 pub fn remove(hm: &Self, key: K) ?&Entry {
117 if (hm.entries.len == 0) return null;
117 hm.incrementModificationCount();118 hm.incrementModificationCount();
118 const start_index = hm.keyToIndex(key);119 const start_index = hm.keyToIndex(key);
119 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {120 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
...@@ -236,7 +237,10 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -236,7 +237,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
236}237}
237238
238test "basic hash map usage" {239test "basic hash map usage" {
239 var map = HashMap(i32, i32, hash_i32, eql_i32).init(debug.global_allocator);240 var direct_allocator = std.heap.DirectAllocator.init();
241 defer direct_allocator.deinit();
242
243 var map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
240 defer map.deinit();244 defer map.deinit();
241245
242 assert((map.put(1, 11) catch unreachable) == null);246 assert((map.put(1, 11) catch unreachable) == null);
std/index.zig+5-3
...@@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig");...@@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig");
17pub const dwarf = @import("dwarf.zig");17pub const dwarf = @import("dwarf.zig");
18pub const elf = @import("elf.zig");18pub const elf = @import("elf.zig");
19pub const empty_import = @import("empty.zig");19pub const empty_import = @import("empty.zig");
20pub const endian = @import("endian.zig");20pub const event = @import("event.zig");
21pub const fmt = @import("fmt/index.zig");21pub const fmt = @import("fmt/index.zig");
22pub const hash = @import("hash/index.zig");
22pub const heap = @import("heap.zig");23pub const heap = @import("heap.zig");
23pub const io = @import("io.zig");24pub const io = @import("io.zig");
24pub const macho = @import("macho.zig");25pub const macho = @import("macho.zig");
...@@ -49,14 +50,15 @@ test "std" {...@@ -49,14 +50,15 @@ test "std" {
49 _ = @import("dwarf.zig");50 _ = @import("dwarf.zig");
50 _ = @import("elf.zig");51 _ = @import("elf.zig");
51 _ = @import("empty.zig");52 _ = @import("empty.zig");
52 _ = @import("endian.zig");53 _ = @import("event.zig");
53 _ = @import("fmt/index.zig");54 _ = @import("fmt/index.zig");
55 _ = @import("hash/index.zig");
54 _ = @import("io.zig");56 _ = @import("io.zig");
55 _ = @import("macho.zig");57 _ = @import("macho.zig");
56 _ = @import("math/index.zig");58 _ = @import("math/index.zig");
57 _ = @import("mem.zig");59 _ = @import("mem.zig");
58 _ = @import("heap.zig");
59 _ = @import("net.zig");60 _ = @import("net.zig");
61 _ = @import("heap.zig");
60 _ = @import("os/index.zig");62 _ = @import("os/index.zig");
61 _ = @import("rand/index.zig");63 _ = @import("rand/index.zig");
62 _ = @import("sort.zig");64 _ = @import("sort.zig");
std/io.zig+5
...@@ -486,6 +486,11 @@ pub fn readLine(buf: []u8) !usize {...@@ -486,6 +486,11 @@ pub fn readLine(buf: []u8) !usize {
486 while (true) {486 while (true) {
487 const byte = stream.readByte() catch return error.EndOfFile;487 const byte = stream.readByte() catch return error.EndOfFile;
488 switch (byte) {488 switch (byte) {
489 '\r' => {
490 // trash the following \n
491 _ = stream.readByte() catch return error.EndOfFile;
492 return index;
493 },
489 '\n' => return index,494 '\n' => return index,
490 else => {495 else => {
491 if (index == buf.len) return error.InputTooLong;496 if (index == buf.len) return error.InputTooLong;
std/linked_list.zig+1
...@@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
161 }161 }
162162
163 list.len -= 1;163 list.len -= 1;
164 assert(list.len == 0 or (list.first != null and list.last != null));
164 }165 }
165166
166 /// Remove and return the last node in the list.167 /// Remove and return the last node in the list.
std/mem.zig+26
...@@ -3,6 +3,7 @@ const debug = std.debug;...@@ -3,6 +3,7 @@ const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const math = std.math;4const math = std.math;
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const mem = this;
67
7pub const Allocator = struct {8pub const Allocator = struct {
8 const Error = error {OutOfMemory};9 const Error = error {OutOfMemory};
...@@ -550,3 +551,28 @@ test "std.mem.rotate" {...@@ -550,3 +551,28 @@ test "std.mem.rotate" {
550551
551 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));552 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
552}553}
554
555// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
556// endian-casting the pointer and then dereferencing
557
558pub fn endianSwapIfLe(comptime T: type, x: T) T {
559 return endianSwapIf(builtin.Endian.Little, T, x);
560}
561
562pub fn endianSwapIfBe(comptime T: type, x: T) T {
563 return endianSwapIf(builtin.Endian.Big, T, x);
564}
565
566pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T {
567 return if (builtin.endian == endian) endianSwap(T, x) else x;
568}
569
570pub fn endianSwap(comptime T: type, x: T) T {
571 var buf: [@sizeOf(T)]u8 = undefined;
572 mem.writeInt(buf[0..], x, builtin.Endian.Little);
573 return mem.readInt(buf, T, builtin.Endian.Big);
574}
575
576test "std.mem.endianSwap" {
577 assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
578}
std/net.zig+121-162
...@@ -1,143 +1,120 @@...@@ -1,143 +1,120 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const linux = std.os.linux;2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const endian = std.endian;4const net = this;
5const posix = std.os.posix;
6const mem = std.mem;
57
6// TODO don't trust this file, it bit rotted. start over8pub const TmpWinAddr = struct {
79 family: u8,
8const Connection = struct {10 data: [14]u8,
9 socket_fd: i32,
10
11 pub fn send(c: Connection, buf: []const u8) !usize {
12 const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
13 const send_err = linux.getErrno(send_ret);
14 switch (send_err) {
15 0 => return send_ret,
16 linux.EINVAL => unreachable,
17 linux.EFAULT => unreachable,
18 linux.ECONNRESET => return error.ConnectionReset,
19 linux.EINTR => return error.SigInterrupt,
20 // TODO there are more possible errors
21 else => return error.Unexpected,
22 }
23 }
24
25 pub fn recv(c: Connection, buf: []u8) ![]u8 {
26 const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
27 const recv_err = linux.getErrno(recv_ret);
28 switch (recv_err) {
29 0 => return buf[0..recv_ret],
30 linux.EINVAL => unreachable,
31 linux.EFAULT => unreachable,
32 linux.ENOTSOCK => return error.NotSocket,
33 linux.EINTR => return error.SigInterrupt,
34 linux.ENOMEM => return error.OutOfMemory,
35 linux.ECONNREFUSED => return error.ConnectionRefused,
36 linux.EBADF => return error.BadFd,
37 // TODO more error values
38 else => return error.Unexpected,
39 }
40 }
41
42 pub fn close(c: Connection) !void {
43 switch (linux.getErrno(linux.close(c.socket_fd))) {
44 0 => return,
45 linux.EBADF => unreachable,
46 linux.EINTR => return error.SigInterrupt,
47 linux.EIO => return error.Io,
48 else => return error.Unexpected,
49 }
50 }
51};11};
5212
53const Address = struct {13pub const OsAddress = switch (builtin.os) {
54 family: u16,14 builtin.Os.windows => TmpWinAddr,
55 scope_id: u32,15 else => posix.sockaddr,
56 addr: [16]u8,
57 sort_key: i32,
58};16};
5917
60pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {18pub const Address = struct {
61 if (hostname.len == 0) {19 os_addr: OsAddress,
6220
63 unreachable; // TODO21 pub fn initIp4(ip4: u32, port: u16) Address {
22 return Address {
23 .os_addr = posix.sockaddr {
24 .in = posix.sockaddr_in {
25 .family = posix.AF_INET,
26 .port = std.mem.endianSwapIfLe(u16, port),
27 .addr = ip4,
28 .zero = []u8{0} ** 8,
29 },
30 },
31 };
64 }32 }
6533
66 unreachable; // TODO34 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
67}35 return Address {
36 .family = posix.AF_INET6,
37 .os_addr = posix.sockaddr {
38 .in6 = posix.sockaddr_in6 {
39 .family = posix.AF_INET6,
40 .port = std.mem.endianSwapIfLe(u16, port),
41 .flowinfo = 0,
42 .addr = ip6.addr,
43 .scope_id = ip6.scope_id,
44 },
45 },
46 };
47 }
6848
69pub fn connectAddr(addr: &Address, port: u16) !Connection {49 pub fn initPosix(addr: &const posix.sockaddr) Address {
70 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);50 return Address {
71 const socket_err = linux.getErrno(socket_ret);51 .os_addr = *addr,
72 if (socket_err > 0) {52 };
73 // TODO figure out possible errors from socket()
74 return error.Unexpected;
75 }53 }
76 const socket_fd = i32(socket_ret);
7754
78 const connect_ret = if (addr.family == linux.AF_INET) x: {55 pub fn format(self: &const Address, out_stream: var) !void {
79 var os_addr: linux.sockaddr_in = undefined;56 switch (self.os_addr.in.family) {
80 os_addr.family = addr.family;57 posix.AF_INET => {
81 os_addr.port = endian.swapIfLe(u16, port);58 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
82 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);59 const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
83 @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));60 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
84 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));61 },
85 } else if (addr.family == linux.AF_INET6) x: {62 posix.AF_INET6 => {
86 var os_addr: linux.sockaddr_in6 = undefined;63 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
87 os_addr.family = addr.family;64 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
88 os_addr.port = endian.swapIfLe(u16, port);
89 os_addr.flowinfo = 0;
90 os_addr.scope_id = addr.scope_id;
91 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
92 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
93 } else {
94 unreachable;
95 };
96 const connect_err = linux.getErrno(connect_ret);
97 if (connect_err > 0) {
98 switch (connect_err) {
99 linux.ETIMEDOUT => return error.TimedOut,
100 else => {
101 // TODO figure out possible errors from connect()
102 return error.Unexpected;
103 },65 },
66 else => try out_stream.write("(unrecognized address family)"),
104 }67 }
105 }68 }
69};
10670
107 return Connection {71pub fn parseIp4(buf: []const u8) !u32 {
108 .socket_fd = socket_fd,72 var result: u32 = undefined;
109 };73 const out_ptr = ([]u8)((&result)[0..1]);
110}
111
112pub fn connect(hostname: []const u8, port: u16) !Connection {
113 var addrs_buf: [1]Address = undefined;
114 const addrs_slice = try lookup(hostname, addrs_buf[0..]);
115 const main_addr = &addrs_slice[0];
116
117 return connectAddr(main_addr, port);
118}
11974
120pub fn parseIpLiteral(buf: []const u8) !Address {75 var x: u8 = 0;
76 var index: u8 = 0;
77 var saw_any_digits = false;
78 for (buf) |c| {
79 if (c == '.') {
80 if (!saw_any_digits) {
81 return error.InvalidCharacter;
82 }
83 if (index == 3) {
84 return error.InvalidEnd;
85 }
86 out_ptr[index] = x;
87 index += 1;
88 x = 0;
89 saw_any_digits = false;
90 } else if (c >= '0' and c <= '9') {
91 saw_any_digits = true;
92 const digit = c - '0';
93 if (@mulWithOverflow(u8, x, 10, &x)) {
94 return error.Overflow;
95 }
96 if (@addWithOverflow(u8, x, digit, &x)) {
97 return error.Overflow;
98 }
99 } else {
100 return error.InvalidCharacter;
101 }
102 }
103 if (index == 3 and saw_any_digits) {
104 out_ptr[index] = x;
105 return result;
106 }
121107
122 return error.InvalidIpLiteral;108 return error.Incomplete;
123}109}
124110
125fn hexDigit(c: u8) u8 {111pub const Ip6Addr = struct {
126 // TODO use switch with range112 scope_id: u32,
127 if ('0' <= c and c <= '9') {113 addr: [16]u8,
128 return c - '0';114};
129 } else if ('A' <= c and c <= 'Z') {
130 return c - 'A' + 10;
131 } else if ('a' <= c and c <= 'z') {
132 return c - 'a' + 10;
133 } else {
134 return @maxValue(u8);
135 }
136}
137115
138fn parseIp6(buf: []const u8) !Address {116pub fn parseIp6(buf: []const u8) !Ip6Addr {
139 var result: Address = undefined;117 var result: Ip6Addr = undefined;
140 result.family = linux.AF_INET6;
141 result.scope_id = 0;118 result.scope_id = 0;
142 const ip_slice = result.addr[0..];119 const ip_slice = result.addr[0..];
143120
...@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {...@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {
156 return error.Overflow;133 return error.Overflow;
157 }134 }
158 } else {135 } else {
159 return error.InvalidChar;136 return error.InvalidCharacter;
160 }137 }
161 } else if (c == ':') {138 } else if (c == ':') {
162 if (!saw_any_digits) {139 if (!saw_any_digits) {
163 return error.InvalidChar;140 return error.InvalidCharacter;
164 }141 }
165 if (index == 14) {142 if (index == 14) {
166 return error.JunkAtEnd;143 return error.InvalidEnd;
167 }144 }
168 ip_slice[index] = @truncate(u8, x >> 8);145 ip_slice[index] = @truncate(u8, x >> 8);
169 index += 1;146 index += 1;
...@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {...@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {
174 saw_any_digits = false;151 saw_any_digits = false;
175 } else if (c == '%') {152 } else if (c == '%') {
176 if (!saw_any_digits) {153 if (!saw_any_digits) {
177 return error.InvalidChar;154 return error.InvalidCharacter;
178 }155 }
179 if (index == 14) {156 if (index == 14) {
180 ip_slice[index] = @truncate(u8, x >> 8);157 ip_slice[index] = @truncate(u8, x >> 8);
...@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {...@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {
185 scope_id = true;162 scope_id = true;
186 saw_any_digits = false;163 saw_any_digits = false;
187 } else {164 } else {
188 const digit = hexDigit(c);165 const digit = try std.fmt.charToDigit(c, 16);
189 if (digit == @maxValue(u8)) {
190 return error.InvalidChar;
191 }
192 if (@mulWithOverflow(u16, x, 16, &x)) {166 if (@mulWithOverflow(u16, x, 16, &x)) {
193 return error.Overflow;167 return error.Overflow;
194 }168 }
...@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {...@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {
216 return error.Incomplete;190 return error.Incomplete;
217}191}
218192
219fn parseIp4(buf: []const u8) !u32 {193test "std.net.parseIp4" {
220 var result: u32 = undefined;194 assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
221 const out_ptr = ([]u8)((&result)[0..1]);
222195
223 var x: u8 = 0;196 testParseIp4Fail("256.0.0.1", error.Overflow);
224 var index: u8 = 0;197 testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
225 var saw_any_digits = false;198 testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
226 for (buf) |c| {199 testParseIp4Fail("127.0.0.", error.Incomplete);
227 if (c == '.') {200 testParseIp4Fail("100..0.1", error.InvalidCharacter);
228 if (!saw_any_digits) {201}
229 return error.InvalidChar;202
230 }203fn testParseIp4Fail(buf: []const u8, expected_err: error) void {
231 if (index == 3) {204 if (parseIp4(buf)) |_| {
232 return error.JunkAtEnd;205 @panic("expected error");
233 }206 } else |e| {
234 out_ptr[index] = x;207 assert(e == expected_err);
235 index += 1;
236 x = 0;
237 saw_any_digits = false;
238 } else if (c >= '0' and c <= '9') {
239 saw_any_digits = true;
240 const digit = c - '0';
241 if (@mulWithOverflow(u8, x, 10, &x)) {
242 return error.Overflow;
243 }
244 if (@addWithOverflow(u8, x, digit, &x)) {
245 return error.Overflow;
246 }
247 } else {
248 return error.InvalidChar;
249 }
250 }
251 if (index == 3 and saw_any_digits) {
252 out_ptr[index] = x;
253 return result;
254 }208 }
209}
255210
256 return error.Incomplete;211test "std.net.parseIp6" {
212 const addr = try parseIp6("FF01:0:0:0:0:0:0:FB");
213 assert(addr.addr[0] == 0xff);
214 assert(addr.addr[1] == 0x01);
215 assert(addr.addr[2] == 0x00);
257}216}
std/os/darwin.zig+3
...@@ -301,6 +301,9 @@ pub const timespec = c.timespec;...@@ -301,6 +301,9 @@ pub const timespec = c.timespec;
301pub const Stat = c.Stat;301pub const Stat = c.Stat;
302pub const dirent = c.dirent;302pub const dirent = c.dirent;
303303
304pub const sa_family_t = c.sa_family_t;
305pub const sockaddr = c.sockaddr;
306
304/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.307/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
305pub const Sigaction = struct {308pub const Sigaction = struct {
306 handler: extern fn(i32)void,309 handler: extern fn(i32)void,
std/os/index.zig+507-21
...@@ -4,6 +4,19 @@ const Os = builtin.Os;...@@ -4,6 +4,19 @@ const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;4const is_windows = builtin.os == Os.windows;
5const os = this;5const os = this;
66
7test "std.os" {
8 _ = @import("child_process.zig");
9 _ = @import("darwin.zig");
10 _ = @import("darwin_errno.zig");
11 _ = @import("get_user_id.zig");
12 _ = @import("linux/errno.zig");
13 _ = @import("linux/index.zig");
14 _ = @import("linux/x86_64.zig");
15 _ = @import("path.zig");
16 _ = @import("test.zig");
17 _ = @import("windows/index.zig");
18}
19
7pub const windows = @import("windows/index.zig");20pub const windows = @import("windows/index.zig");
8pub const darwin = @import("darwin.zig");21pub const darwin = @import("darwin.zig");
9pub const linux = @import("linux/index.zig");22pub const linux = @import("linux/index.zig");
...@@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {...@@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {
14 Os.zen => zen,27 Os.zen => zen,
15 else => @compileError("Unsupported OS"),28 else => @compileError("Unsupported OS"),
16};29};
30pub const net = @import("net.zig");
1731
18pub const ChildProcess = @import("child_process.zig").ChildProcess;32pub const ChildProcess = @import("child_process.zig").ChildProcess;
19pub const path = @import("path.zig");33pub const path = @import("path.zig");
...@@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {...@@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {
173 }187 }
174}188}
175189
190/// When a file descriptor is closed on linux, it pops the first
191/// node from this queue and resumes it.
192/// Async functions which get the EMFILE error code can suspend,
193/// putting their coroutine handle into this list.
194/// TODO make this an atomic linked list
195pub var emfile_promise_queue = std.LinkedList(promise).init();
196
176/// Closes the file handle. Keeps trying if it gets interrupted by a signal.197/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
177pub fn close(handle: FileHandle) void {198pub fn close(handle: FileHandle) void {
178 if (is_windows) {199 if (is_windows) {
...@@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {...@@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {
180 } else {201 } else {
181 while (true) {202 while (true) {
182 const err = posix.getErrno(posix.close(handle));203 const err = posix.getErrno(posix.close(handle));
183 if (err == posix.EINTR) {204 switch (err) {
184 continue;205 posix.EINTR => continue,
185 } else {206 else => {
186 return;207 if (emfile_promise_queue.popFirst()) |p| resume p.data;
208 return;
209 },
187 }210 }
188 }211 }
189 }212 }
...@@ -1753,27 +1776,16 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const...@@ -1753,27 +1776,16 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
1753 assert(it.next(debug.global_allocator) == null);1776 assert(it.next(debug.global_allocator) == null);
1754}1777}
17551778
1756test "std.os" {
1757 _ = @import("child_process.zig");
1758 _ = @import("darwin_errno.zig");
1759 _ = @import("darwin.zig");
1760 _ = @import("get_user_id.zig");
1761 _ = @import("linux/errno.zig");
1762 //_ = @import("linux_i386.zig");
1763 _ = @import("linux/x86_64.zig");
1764 _ = @import("linux/index.zig");
1765 _ = @import("path.zig");
1766 _ = @import("windows/index.zig");
1767 _ = @import("test.zig");
1768}
1769
1770
1771// TODO make this a build variable that you can set1779// TODO make this a build variable that you can set
1772const unexpected_error_tracing = false;1780const unexpected_error_tracing = false;
1781const UnexpectedError = error {
1782 /// The Operating System returned an undocumented error code.
1783 Unexpected,
1784};
17731785
1774/// Call this when you made a syscall or something that sets errno1786/// Call this when you made a syscall or something that sets errno
1775/// and you get an unexpected error.1787/// and you get an unexpected error.
1776pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {1788pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
1777 if (unexpected_error_tracing) {1789 if (unexpected_error_tracing) {
1778 debug.warn("unexpected errno: {}\n", errno);1790 debug.warn("unexpected errno: {}\n", errno);
1779 debug.dumpCurrentStackTrace(null);1791 debug.dumpCurrentStackTrace(null);
...@@ -1783,7 +1795,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {...@@ -1783,7 +1795,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
17831795
1784/// Call this when you made a windows DLL call or something that does SetLastError1796/// Call this when you made a windows DLL call or something that does SetLastError
1785/// and you get an unexpected error.1797/// and you get an unexpected error.
1786pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {1798pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
1787 if (unexpected_error_tracing) {1799 if (unexpected_error_tracing) {
1788 debug.warn("unexpected GetLastError(): {}\n", err);1800 debug.warn("unexpected GetLastError(): {}\n", err);
1789 debug.dumpCurrentStackTrace(null);1801 debug.dumpCurrentStackTrace(null);
...@@ -1898,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool {...@@ -1898,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool {
1898 }1910 }
1899 }1911 }
1900}1912}
1913
1914pub const PosixSocketError = error {
1915 /// Permission to create a socket of the specified type and/or
1916 /// pro‐tocol is denied.
1917 PermissionDenied,
1918
1919 /// The implementation does not support the specified address family.
1920 AddressFamilyNotSupported,
1921
1922 /// Unknown protocol, or protocol family not available.
1923 ProtocolFamilyNotAvailable,
1924
1925 /// The per-process limit on the number of open file descriptors has been reached.
1926 ProcessFdQuotaExceeded,
1927
1928 /// The system-wide limit on the total number of open files has been reached.
1929 SystemFdQuotaExceeded,
1930
1931 /// Insufficient memory is available. The socket cannot be created until sufficient
1932 /// resources are freed.
1933 SystemResources,
1934
1935 /// The protocol type or the specified protocol is not supported within this domain.
1936 ProtocolNotSupported,
1937};
1938
1939pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
1940 const rc = posix.socket(domain, socket_type, protocol);
1941 const err = posix.getErrno(rc);
1942 switch (err) {
1943 0 => return i32(rc),
1944 posix.EACCES => return PosixSocketError.PermissionDenied,
1945 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
1946 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
1947 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
1948 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
1949 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
1950 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
1951 else => return unexpectedErrorPosix(err),
1952 }
1953}
1954
1955pub const PosixBindError = error {
1956 /// The address is protected, and the user is not the superuser.
1957 /// For UNIX domain sockets: Search permission is denied on a component
1958 /// of the path prefix.
1959 AccessDenied,
1960
1961 /// The given address is already in use, or in the case of Internet domain sockets,
1962 /// The port number was specified as zero in the socket
1963 /// address structure, but, upon attempting to bind to an ephemeral port, it was
1964 /// determined that all port numbers in the ephemeral port range are currently in
1965 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
1966 AddressInUse,
1967
1968 /// sockfd is not a valid file descriptor.
1969 InvalidFileDescriptor,
1970
1971 /// The socket is already bound to an address, or addrlen is wrong, or addr is not
1972 /// a valid address for this socket's domain.
1973 InvalidSocketOrAddress,
1974
1975 /// The file descriptor sockfd does not refer to a socket.
1976 FileDescriptorNotASocket,
1977
1978 /// A nonexistent interface was requested or the requested address was not local.
1979 AddressNotAvailable,
1980
1981 /// addr points outside the user's accessible address space.
1982 PageFault,
1983
1984 /// Too many symbolic links were encountered in resolving addr.
1985 SymLinkLoop,
1986
1987 /// addr is too long.
1988 NameTooLong,
1989
1990 /// A component in the directory prefix of the socket pathname does not exist.
1991 FileNotFound,
1992
1993 /// Insufficient kernel memory was available.
1994 SystemResources,
1995
1996 /// A component of the path prefix is not a directory.
1997 NotDir,
1998
1999 /// The socket inode would reside on a read-only filesystem.
2000 ReadOnlyFileSystem,
2001
2002 Unexpected,
2003};
2004
2005/// addr is `&const T` where T is one of the sockaddr
2006pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
2007 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
2008 const err = posix.getErrno(rc);
2009 switch (err) {
2010 0 => return,
2011 posix.EACCES => return PosixBindError.AccessDenied,
2012 posix.EADDRINUSE => return PosixBindError.AddressInUse,
2013 posix.EBADF => return PosixBindError.InvalidFileDescriptor,
2014 posix.EINVAL => return PosixBindError.InvalidSocketOrAddress,
2015 posix.ENOTSOCK => return PosixBindError.FileDescriptorNotASocket,
2016 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
2017 posix.EFAULT => return PosixBindError.PageFault,
2018 posix.ELOOP => return PosixBindError.SymLinkLoop,
2019 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
2020 posix.ENOENT => return PosixBindError.FileNotFound,
2021 posix.ENOMEM => return PosixBindError.SystemResources,
2022 posix.ENOTDIR => return PosixBindError.NotDir,
2023 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
2024 else => return unexpectedErrorPosix(err),
2025 }
2026}
2027
2028const PosixListenError = error {
2029 /// Another socket is already listening on the same port.
2030 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2031 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
2032 /// was determined that all port numbers in the ephemeral port range are currently in
2033 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2034 AddressInUse,
2035
2036 /// The argument sockfd is not a valid file descriptor.
2037 InvalidFileDescriptor,
2038
2039 /// The file descriptor sockfd does not refer to a socket.
2040 FileDescriptorNotASocket,
2041
2042 /// The socket is not of a type that supports the listen() operation.
2043 OperationNotSupported,
2044
2045 Unexpected,
2046};
2047
2048pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2049 const rc = posix.listen(sockfd, backlog);
2050 const err = posix.getErrno(rc);
2051 switch (err) {
2052 0 => return,
2053 posix.EADDRINUSE => return PosixListenError.AddressInUse,
2054 posix.EBADF => return PosixListenError.InvalidFileDescriptor,
2055 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
2056 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
2057 else => return unexpectedErrorPosix(err),
2058 }
2059}
2060
2061pub const PosixAcceptError = error {
2062 /// The socket is marked nonblocking and no connections are present to be accepted.
2063 WouldBlock,
2064
2065 /// sockfd is not an open file descriptor.
2066 FileDescriptorClosed,
2067
2068 ConnectionAborted,
2069
2070 /// The addr argument is not in a writable part of the user address space.
2071 PageFault,
2072
2073 /// Socket is not listening for connections, or addrlen is invalid (e.g., is negative),
2074 /// or invalid value in flags.
2075 InvalidSyscall,
2076
2077 /// The per-process limit on the number of open file descriptors has been reached.
2078 ProcessFdQuotaExceeded,
2079
2080 /// The system-wide limit on the total number of open files has been reached.
2081 SystemFdQuotaExceeded,
2082
2083 /// Not enough free memory. This often means that the memory allocation is limited
2084 /// by the socket buffer limits, not by the system memory.
2085 SystemResources,
2086
2087 /// The file descriptor sockfd does not refer to a socket.
2088 FileDescriptorNotASocket,
2089
2090 /// The referenced socket is not of type SOCK_STREAM.
2091 OperationNotSupported,
2092
2093 ProtocolFailure,
2094
2095 /// Firewall rules forbid connection.
2096 BlockedByFirewall,
2097
2098 Unexpected,
2099};
2100
2101pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2102 while (true) {
2103 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2104 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2105 const err = posix.getErrno(rc);
2106 switch (err) {
2107 0 => return i32(rc),
2108 posix.EINTR => continue,
2109 else => return unexpectedErrorPosix(err),
2110
2111 posix.EAGAIN => return PosixAcceptError.WouldBlock,
2112 posix.EBADF => return PosixAcceptError.FileDescriptorClosed,
2113 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2114 posix.EFAULT => return PosixAcceptError.PageFault,
2115 posix.EINVAL => return PosixAcceptError.InvalidSyscall,
2116 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2117 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2118 posix.ENOBUFS, posix.ENOMEM => return PosixAcceptError.SystemResources,
2119 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2120 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2121 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2122 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2123 }
2124 }
2125}
2126
2127pub const LinuxEpollCreateError = error {
2128 /// Invalid value specified in flags.
2129 InvalidSyscall,
2130
2131 /// The per-user limit on the number of epoll instances imposed by
2132 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2133 /// details.
2134 /// Or, The per-process limit on the number of open file descriptors has been reached.
2135 ProcessFdQuotaExceeded,
2136
2137 /// The system-wide limit on the total number of open files has been reached.
2138 SystemFdQuotaExceeded,
2139
2140 /// There was insufficient memory to create the kernel object.
2141 SystemResources,
2142
2143 Unexpected,
2144};
2145
2146pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2147 const rc = posix.epoll_create1(flags);
2148 const err = posix.getErrno(rc);
2149 switch (err) {
2150 0 => return i32(rc),
2151 else => return unexpectedErrorPosix(err),
2152
2153 posix.EINVAL => return LinuxEpollCreateError.InvalidSyscall,
2154 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
2155 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
2156 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
2157 }
2158}
2159
2160pub const LinuxEpollCtlError = error {
2161 /// epfd or fd is not a valid file descriptor.
2162 InvalidFileDescriptor,
2163
2164 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2165 /// with this epoll instance.
2166 FileDescriptorAlreadyPresentInSet,
2167
2168 /// epfd is not an epoll file descriptor, or fd is the same as epfd, or the requested
2169 /// operation op is not supported by this interface, or
2170 /// An invalid event type was specified along with EPOLLEXCLUSIVE in events, or
2171 /// op was EPOLL_CTL_MOD and events included EPOLLEXCLUSIVE, or
2172 /// op was EPOLL_CTL_MOD and the EPOLLEXCLUSIVE flag has previously been applied to
2173 /// this epfd, fd pair, or
2174 /// EPOLLEXCLUSIVE was specified in event and fd refers to an epoll instance.
2175 InvalidSyscall,
2176
2177 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
2178 /// circular loop of epoll instances monitoring one another.
2179 OperationCausesCircularLoop,
2180
2181 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
2182 /// instance.
2183 FileDescriptorNotRegistered,
2184
2185 /// There was insufficient memory to handle the requested op control operation.
2186 SystemResources,
2187
2188 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
2189 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
2190 /// See epoll(7) for further details.
2191 UserResourceLimitReached,
2192
2193 /// The target file fd does not support epoll. This error can occur if fd refers to,
2194 /// for example, a regular file or a directory.
2195 FileDescriptorIncompatibleWithEpoll,
2196
2197 Unexpected,
2198};
2199
2200pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) LinuxEpollCtlError!void {
2201 const rc = posix.epoll_ctl(epfd, op, fd, event);
2202 const err = posix.getErrno(rc);
2203 switch (err) {
2204 0 => return,
2205 else => return unexpectedErrorPosix(err),
2206
2207 posix.EBADF => return LinuxEpollCtlError.InvalidFileDescriptor,
2208 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
2209 posix.EINVAL => return LinuxEpollCtlError.InvalidSyscall,
2210 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
2211 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
2212 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
2213 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
2214 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
2215 }
2216}
2217
2218pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2219 while (true) {
2220 const rc = posix.epoll_wait(epfd, events.ptr, u32(events.len), timeout);
2221 const err = posix.getErrno(rc);
2222 switch (err) {
2223 0 => return rc,
2224 posix.EINTR => continue,
2225 posix.EBADF => unreachable,
2226 posix.EFAULT => unreachable,
2227 posix.EINVAL => unreachable,
2228 else => unreachable,
2229 }
2230 }
2231}
2232
2233pub const PosixGetSockNameError = error {
2234 /// Insufficient resources were available in the system to perform the operation.
2235 SystemResources,
2236
2237 Unexpected,
2238};
2239
2240pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2241 var addr: posix.sockaddr = undefined;
2242 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
2243 const rc = posix.getsockname(sockfd, &addr, &addrlen);
2244 const err = posix.getErrno(rc);
2245 switch (err) {
2246 0 => return addr,
2247 else => return unexpectedErrorPosix(err),
2248
2249 posix.EBADF => unreachable,
2250 posix.EFAULT => unreachable,
2251 posix.EINVAL => unreachable,
2252 posix.ENOTSOCK => unreachable,
2253 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2254 }
2255}
2256
2257pub const PosixConnectError = error {
2258 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2259 /// file, or search permission is denied for one of the directories in the path prefix.
2260 /// or
2261 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2262 /// the connection request failed because of a local firewall rule.
2263 PermissionDenied,
2264
2265 /// Local address is already in use.
2266 AddressInUse,
2267
2268 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2269 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2270 /// in the ephemeral port range are currently in use. See the discussion of
2271 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2272 AddressNotAvailable,
2273
2274 /// The passed address didn't have the correct address family in its sa_family field.
2275 AddressFamilyNotSupported,
2276
2277 /// Insufficient entries in the routing cache.
2278 SystemResources,
2279
2280 /// A connect() on a stream socket found no one listening on the remote address.
2281 ConnectionRefused,
2282
2283 /// Network is unreachable.
2284 NetworkUnreachable,
2285
2286 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2287 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2288 ConnectionTimedOut,
2289
2290 Unexpected,
2291};
2292
2293pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2294 while (true) {
2295 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2296 const err = posix.getErrno(rc);
2297 switch (err) {
2298 0 => return,
2299 else => return unexpectedErrorPosix(err),
2300
2301 posix.EACCES => return PosixConnectError.PermissionDenied,
2302 posix.EPERM => return PosixConnectError.PermissionDenied,
2303 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2304 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2305 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2306 posix.EAGAIN => return PosixConnectError.SystemResources,
2307 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2308 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2309 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2310 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2311 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2312 posix.EINTR => continue,
2313 posix.EISCONN => unreachable, // The socket is already connected.
2314 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2315 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2316 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2317 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2318 }
2319 }
2320}
2321
2322/// Same as posixConnect except it is for blocking socket file descriptors.
2323/// It expects to receive EINPROGRESS.
2324pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2325 while (true) {
2326 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2327 const err = posix.getErrno(rc);
2328 switch (err) {
2329 0, posix.EINPROGRESS => return,
2330 else => return unexpectedErrorPosix(err),
2331
2332 posix.EACCES => return PosixConnectError.PermissionDenied,
2333 posix.EPERM => return PosixConnectError.PermissionDenied,
2334 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2335 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2336 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2337 posix.EAGAIN => return PosixConnectError.SystemResources,
2338 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2339 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2340 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2341 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2342 posix.EINTR => continue,
2343 posix.EISCONN => unreachable, // The socket is already connected.
2344 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2345 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2346 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2347 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2348 }
2349 }
2350}
2351
2352pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2353 var err_code: i32 = undefined;
2354 var size: u32 = @sizeOf(i32);
2355 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast(&u8, &err_code), &size);
2356 assert(size == 4);
2357 const err = posix.getErrno(rc);
2358 switch (err) {
2359 0 => switch (err_code) {
2360 0 => return,
2361 else => return unexpectedErrorPosix(err),
2362
2363 posix.EACCES => return PosixConnectError.PermissionDenied,
2364 posix.EPERM => return PosixConnectError.PermissionDenied,
2365 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2366 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2367 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2368 posix.EAGAIN => return PosixConnectError.SystemResources,
2369 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2370 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2371 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2372 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2373 posix.EISCONN => unreachable, // The socket is already connected.
2374 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2375 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2376 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2377 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2378 },
2379 else => return unexpectedErrorPosix(err),
2380 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2381 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2382 posix.EINVAL => unreachable,
2383 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2384 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2385 }
2386}
std/os/linux/i386.zig deleted-505
...@@ -1,505 +0,0 @@
1const std = @import("../../index.zig");
2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;
5
6pub const SYS_restart_syscall = 0;
7pub const SYS_exit = 1;
8pub const SYS_fork = 2;
9pub const SYS_read = 3;
10pub const SYS_write = 4;
11pub const SYS_open = 5;
12pub const SYS_close = 6;
13pub const SYS_waitpid = 7;
14pub const SYS_creat = 8;
15pub const SYS_link = 9;
16pub const SYS_unlink = 10;
17pub const SYS_execve = 11;
18pub const SYS_chdir = 12;
19pub const SYS_time = 13;
20pub const SYS_mknod = 14;
21pub const SYS_chmod = 15;
22pub const SYS_lchown = 16;
23pub const SYS_break = 17;
24pub const SYS_oldstat = 18;
25pub const SYS_lseek = 19;
26pub const SYS_getpid = 20;
27pub const SYS_mount = 21;
28pub const SYS_umount = 22;
29pub const SYS_setuid = 23;
30pub const SYS_getuid = 24;
31pub const SYS_stime = 25;
32pub const SYS_ptrace = 26;
33pub const SYS_alarm = 27;
34pub const SYS_oldfstat = 28;
35pub const SYS_pause = 29;
36pub const SYS_utime = 30;
37pub const SYS_stty = 31;
38pub const SYS_gtty = 32;
39pub const SYS_access = 33;
40pub const SYS_nice = 34;
41pub const SYS_ftime = 35;
42pub const SYS_sync = 36;
43pub const SYS_kill = 37;
44pub const SYS_rename = 38;
45pub const SYS_mkdir = 39;
46pub const SYS_rmdir = 40;
47pub const SYS_dup = 41;
48pub const SYS_pipe = 42;
49pub const SYS_times = 43;
50pub const SYS_prof = 44;
51pub const SYS_brk = 45;
52pub const SYS_setgid = 46;
53pub const SYS_getgid = 47;
54pub const SYS_signal = 48;
55pub const SYS_geteuid = 49;
56pub const SYS_getegid = 50;
57pub const SYS_acct = 51;
58pub const SYS_umount2 = 52;
59pub const SYS_lock = 53;
60pub const SYS_ioctl = 54;
61pub const SYS_fcntl = 55;
62pub const SYS_mpx = 56;
63pub const SYS_setpgid = 57;
64pub const SYS_ulimit = 58;
65pub const SYS_oldolduname = 59;
66pub const SYS_umask = 60;
67pub const SYS_chroot = 61;
68pub const SYS_ustat = 62;
69pub const SYS_dup2 = 63;
70pub const SYS_getppid = 64;
71pub const SYS_getpgrp = 65;
72pub const SYS_setsid = 66;
73pub const SYS_sigaction = 67;
74pub const SYS_sgetmask = 68;
75pub const SYS_ssetmask = 69;
76pub const SYS_setreuid = 70;
77pub const SYS_setregid = 71;
78pub const SYS_sigsuspend = 72;
79pub const SYS_sigpending = 73;
80pub const SYS_sethostname = 74;
81pub const SYS_setrlimit = 75;
82pub const SYS_getrlimit = 76;
83pub const SYS_getrusage = 77;
84pub const SYS_gettimeofday = 78;
85pub const SYS_settimeofday = 79;
86pub const SYS_getgroups = 80;
87pub const SYS_setgroups = 81;
88pub const SYS_select = 82;
89pub const SYS_symlink = 83;
90pub const SYS_oldlstat = 84;
91pub const SYS_readlink = 85;
92pub const SYS_uselib = 86;
93pub const SYS_swapon = 87;
94pub const SYS_reboot = 88;
95pub const SYS_readdir = 89;
96pub const SYS_mmap = 90;
97pub const SYS_munmap = 91;
98pub const SYS_truncate = 92;
99pub const SYS_ftruncate = 93;
100pub const SYS_fchmod = 94;
101pub const SYS_fchown = 95;
102pub const SYS_getpriority = 96;
103pub const SYS_setpriority = 97;
104pub const SYS_profil = 98;
105pub const SYS_statfs = 99;
106pub const SYS_fstatfs = 100;
107pub const SYS_ioperm = 101;
108pub const SYS_socketcall = 102;
109pub const SYS_syslog = 103;
110pub const SYS_setitimer = 104;
111pub const SYS_getitimer = 105;
112pub const SYS_stat = 106;
113pub const SYS_lstat = 107;
114pub const SYS_fstat = 108;
115pub const SYS_olduname = 109;
116pub const SYS_iopl = 110;
117pub const SYS_vhangup = 111;
118pub const SYS_idle = 112;
119pub const SYS_vm86old = 113;
120pub const SYS_wait4 = 114;
121pub const SYS_swapoff = 115;
122pub const SYS_sysinfo = 116;
123pub const SYS_ipc = 117;
124pub const SYS_fsync = 118;
125pub const SYS_sigreturn = 119;
126pub const SYS_clone = 120;
127pub const SYS_setdomainname = 121;
128pub const SYS_uname = 122;
129pub const SYS_modify_ldt = 123;
130pub const SYS_adjtimex = 124;
131pub const SYS_mprotect = 125;
132pub const SYS_sigprocmask = 126;
133pub const SYS_create_module = 127;
134pub const SYS_init_module = 128;
135pub const SYS_delete_module = 129;
136pub const SYS_get_kernel_syms = 130;
137pub const SYS_quotactl = 131;
138pub const SYS_getpgid = 132;
139pub const SYS_fchdir = 133;
140pub const SYS_bdflush = 134;
141pub const SYS_sysfs = 135;
142pub const SYS_personality = 136;
143pub const SYS_afs_syscall = 137;
144pub const SYS_setfsuid = 138;
145pub const SYS_setfsgid = 139;
146pub const SYS__llseek = 140;
147pub const SYS_getdents = 141;
148pub const SYS__newselect = 142;
149pub const SYS_flock = 143;
150pub const SYS_msync = 144;
151pub const SYS_readv = 145;
152pub const SYS_writev = 146;
153pub const SYS_getsid = 147;
154pub const SYS_fdatasync = 148;
155pub const SYS__sysctl = 149;
156pub const SYS_mlock = 150;
157pub const SYS_munlock = 151;
158pub const SYS_mlockall = 152;
159pub const SYS_munlockall = 153;
160pub const SYS_sched_setparam = 154;
161pub const SYS_sched_getparam = 155;
162pub const SYS_sched_setscheduler = 156;
163pub const SYS_sched_getscheduler = 157;
164pub const SYS_sched_yield = 158;
165pub const SYS_sched_get_priority_max = 159;
166pub const SYS_sched_get_priority_min = 160;
167pub const SYS_sched_rr_get_interval = 161;
168pub const SYS_nanosleep = 162;
169pub const SYS_mremap = 163;
170pub const SYS_setresuid = 164;
171pub const SYS_getresuid = 165;
172pub const SYS_vm86 = 166;
173pub const SYS_query_module = 167;
174pub const SYS_poll = 168;
175pub const SYS_nfsservctl = 169;
176pub const SYS_setresgid = 170;
177pub const SYS_getresgid = 171;
178pub const SYS_prctl = 172;
179pub const SYS_rt_sigreturn = 173;
180pub const SYS_rt_sigaction = 174;
181pub const SYS_rt_sigprocmask = 175;
182pub const SYS_rt_sigpending = 176;
183pub const SYS_rt_sigtimedwait = 177;
184pub const SYS_rt_sigqueueinfo = 178;
185pub const SYS_rt_sigsuspend = 179;
186pub const SYS_pread64 = 180;
187pub const SYS_pwrite64 = 181;
188pub const SYS_chown = 182;
189pub const SYS_getcwd = 183;
190pub const SYS_capget = 184;
191pub const SYS_capset = 185;
192pub const SYS_sigaltstack = 186;
193pub const SYS_sendfile = 187;
194pub const SYS_getpmsg = 188;
195pub const SYS_putpmsg = 189;
196pub const SYS_vfork = 190;
197pub const SYS_ugetrlimit = 191;
198pub const SYS_mmap2 = 192;
199pub const SYS_truncate64 = 193;
200pub const SYS_ftruncate64 = 194;
201pub const SYS_stat64 = 195;
202pub const SYS_lstat64 = 196;
203pub const SYS_fstat64 = 197;
204pub const SYS_lchown32 = 198;
205pub const SYS_getuid32 = 199;
206pub const SYS_getgid32 = 200;
207pub const SYS_geteuid32 = 201;
208pub const SYS_getegid32 = 202;
209pub const SYS_setreuid32 = 203;
210pub const SYS_setregid32 = 204;
211pub const SYS_getgroups32 = 205;
212pub const SYS_setgroups32 = 206;
213pub const SYS_fchown32 = 207;
214pub const SYS_setresuid32 = 208;
215pub const SYS_getresuid32 = 209;
216pub const SYS_setresgid32 = 210;
217pub const SYS_getresgid32 = 211;
218pub const SYS_chown32 = 212;
219pub const SYS_setuid32 = 213;
220pub const SYS_setgid32 = 214;
221pub const SYS_setfsuid32 = 215;
222pub const SYS_setfsgid32 = 216;
223pub const SYS_pivot_root = 217;
224pub const SYS_mincore = 218;
225pub const SYS_madvise = 219;
226pub const SYS_madvise1 = 219;
227pub const SYS_getdents64 = 220;
228pub const SYS_fcntl64 = 221;
229pub const SYS_gettid = 224;
230pub const SYS_readahead = 225;
231pub const SYS_setxattr = 226;
232pub const SYS_lsetxattr = 227;
233pub const SYS_fsetxattr = 228;
234pub const SYS_getxattr = 229;
235pub const SYS_lgetxattr = 230;
236pub const SYS_fgetxattr = 231;
237pub const SYS_listxattr = 232;
238pub const SYS_llistxattr = 233;
239pub const SYS_flistxattr = 234;
240pub const SYS_removexattr = 235;
241pub const SYS_lremovexattr = 236;
242pub const SYS_fremovexattr = 237;
243pub const SYS_tkill = 238;
244pub const SYS_sendfile64 = 239;
245pub const SYS_futex = 240;
246pub const SYS_sched_setaffinity = 241;
247pub const SYS_sched_getaffinity = 242;
248pub const SYS_set_thread_area = 243;
249pub const SYS_get_thread_area = 244;
250pub const SYS_io_setup = 245;
251pub const SYS_io_destroy = 246;
252pub const SYS_io_getevents = 247;
253pub const SYS_io_submit = 248;
254pub const SYS_io_cancel = 249;
255pub const SYS_fadvise64 = 250;
256pub const SYS_exit_group = 252;
257pub const SYS_lookup_dcookie = 253;
258pub const SYS_epoll_create = 254;
259pub const SYS_epoll_ctl = 255;
260pub const SYS_epoll_wait = 256;
261pub const SYS_remap_file_pages = 257;
262pub const SYS_set_tid_address = 258;
263pub const SYS_timer_create = 259;
264pub const SYS_timer_settime = SYS_timer_create+1;
265pub const SYS_timer_gettime = SYS_timer_create+2;
266pub const SYS_timer_getoverrun = SYS_timer_create+3;
267pub const SYS_timer_delete = SYS_timer_create+4;
268pub const SYS_clock_settime = SYS_timer_create+5;
269pub const SYS_clock_gettime = SYS_timer_create+6;
270pub const SYS_clock_getres = SYS_timer_create+7;
271pub const SYS_clock_nanosleep = SYS_timer_create+8;
272pub const SYS_statfs64 = 268;
273pub const SYS_fstatfs64 = 269;
274pub const SYS_tgkill = 270;
275pub const SYS_utimes = 271;
276pub const SYS_fadvise64_64 = 272;
277pub const SYS_vserver = 273;
278pub const SYS_mbind = 274;
279pub const SYS_get_mempolicy = 275;
280pub const SYS_set_mempolicy = 276;
281pub const SYS_mq_open = 277;
282pub const SYS_mq_unlink = SYS_mq_open+1;
283pub const SYS_mq_timedsend = SYS_mq_open+2;
284pub const SYS_mq_timedreceive = SYS_mq_open+3;
285pub const SYS_mq_notify = SYS_mq_open+4;
286pub const SYS_mq_getsetattr = SYS_mq_open+5;
287pub const SYS_kexec_load = 283;
288pub const SYS_waitid = 284;
289pub const SYS_add_key = 286;
290pub const SYS_request_key = 287;
291pub const SYS_keyctl = 288;
292pub const SYS_ioprio_set = 289;
293pub const SYS_ioprio_get = 290;
294pub const SYS_inotify_init = 291;
295pub const SYS_inotify_add_watch = 292;
296pub const SYS_inotify_rm_watch = 293;
297pub const SYS_migrate_pages = 294;
298pub const SYS_openat = 295;
299pub const SYS_mkdirat = 296;
300pub const SYS_mknodat = 297;
301pub const SYS_fchownat = 298;
302pub const SYS_futimesat = 299;
303pub const SYS_fstatat64 = 300;
304pub const SYS_unlinkat = 301;
305pub const SYS_renameat = 302;
306pub const SYS_linkat = 303;
307pub const SYS_symlinkat = 304;
308pub const SYS_readlinkat = 305;
309pub const SYS_fchmodat = 306;
310pub const SYS_faccessat = 307;
311pub const SYS_pselect6 = 308;
312pub const SYS_ppoll = 309;
313pub const SYS_unshare = 310;
314pub const SYS_set_robust_list = 311;
315pub const SYS_get_robust_list = 312;
316pub const SYS_splice = 313;
317pub const SYS_sync_file_range = 314;
318pub const SYS_tee = 315;
319pub const SYS_vmsplice = 316;
320pub const SYS_move_pages = 317;
321pub const SYS_getcpu = 318;
322pub const SYS_epoll_pwait = 319;
323pub const SYS_utimensat = 320;
324pub const SYS_signalfd = 321;
325pub const SYS_timerfd_create = 322;
326pub const SYS_eventfd = 323;
327pub const SYS_fallocate = 324;
328pub const SYS_timerfd_settime = 325;
329pub const SYS_timerfd_gettime = 326;
330pub const SYS_signalfd4 = 327;
331pub const SYS_eventfd2 = 328;
332pub const SYS_epoll_create1 = 329;
333pub const SYS_dup3 = 330;
334pub const SYS_pipe2 = 331;
335pub const SYS_inotify_init1 = 332;
336pub const SYS_preadv = 333;
337pub const SYS_pwritev = 334;
338pub const SYS_rt_tgsigqueueinfo = 335;
339pub const SYS_perf_event_open = 336;
340pub const SYS_recvmmsg = 337;
341pub const SYS_fanotify_init = 338;
342pub const SYS_fanotify_mark = 339;
343pub const SYS_prlimit64 = 340;
344pub const SYS_name_to_handle_at = 341;
345pub const SYS_open_by_handle_at = 342;
346pub const SYS_clock_adjtime = 343;
347pub const SYS_syncfs = 344;
348pub const SYS_sendmmsg = 345;
349pub const SYS_setns = 346;
350pub const SYS_process_vm_readv = 347;
351pub const SYS_process_vm_writev = 348;
352pub const SYS_kcmp = 349;
353pub const SYS_finit_module = 350;
354pub const SYS_sched_setattr = 351;
355pub const SYS_sched_getattr = 352;
356pub const SYS_renameat2 = 353;
357pub const SYS_seccomp = 354;
358pub const SYS_getrandom = 355;
359pub const SYS_memfd_create = 356;
360pub const SYS_bpf = 357;
361pub const SYS_execveat = 358;
362pub const SYS_socket = 359;
363pub const SYS_socketpair = 360;
364pub const SYS_bind = 361;
365pub const SYS_connect = 362;
366pub const SYS_listen = 363;
367pub const SYS_accept4 = 364;
368pub const SYS_getsockopt = 365;
369pub const SYS_setsockopt = 366;
370pub const SYS_getsockname = 367;
371pub const SYS_getpeername = 368;
372pub const SYS_sendto = 369;
373pub const SYS_sendmsg = 370;
374pub const SYS_recvfrom = 371;
375pub const SYS_recvmsg = 372;
376pub const SYS_shutdown = 373;
377pub const SYS_userfaultfd = 374;
378pub const SYS_membarrier = 375;
379pub const SYS_mlock2 = 376;
380
381
382pub const O_CREAT = 0o100;
383pub const O_EXCL = 0o200;
384pub const O_NOCTTY = 0o400;
385pub const O_TRUNC = 0o1000;
386pub const O_APPEND = 0o2000;
387pub const O_NONBLOCK = 0o4000;
388pub const O_DSYNC = 0o10000;
389pub const O_SYNC = 0o4010000;
390pub const O_RSYNC = 0o4010000;
391pub const O_DIRECTORY = 0o200000;
392pub const O_NOFOLLOW = 0o400000;
393pub const O_CLOEXEC = 0o2000000;
394
395pub const O_ASYNC = 0o20000;
396pub const O_DIRECT = 0o40000;
397pub const O_LARGEFILE = 0o100000;
398pub const O_NOATIME = 0o1000000;
399pub const O_PATH = 0o10000000;
400pub const O_TMPFILE = 0o20200000;
401pub const O_NDELAY = O_NONBLOCK;
402
403pub const F_DUPFD = 0;
404pub const F_GETFD = 1;
405pub const F_SETFD = 2;
406pub const F_GETFL = 3;
407pub const F_SETFL = 4;
408
409pub const F_SETOWN = 8;
410pub const F_GETOWN = 9;
411pub const F_SETSIG = 10;
412pub const F_GETSIG = 11;
413
414pub const F_GETLK = 12;
415pub const F_SETLK = 13;
416pub const F_SETLKW = 14;
417
418pub const F_SETOWN_EX = 15;
419pub const F_GETOWN_EX = 16;
420
421pub const F_GETOWNER_UIDS = 17;
422
423pub inline fn syscall0(number: usize) usize {
424 return asm volatile ("int $0x80"
425 : [ret] "={eax}" (-> usize)
426 : [number] "{eax}" (number));
427}
428
429pub inline fn syscall1(number: usize, arg1: usize) usize {
430 return asm volatile ("int $0x80"
431 : [ret] "={eax}" (-> usize)
432 : [number] "{eax}" (number),
433 [arg1] "{ebx}" (arg1));
434}
435
436pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
437 return asm volatile ("int $0x80"
438 : [ret] "={eax}" (-> usize)
439 : [number] "{eax}" (number),
440 [arg1] "{ebx}" (arg1),
441 [arg2] "{ecx}" (arg2));
442}
443
444pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
445 return asm volatile ("int $0x80"
446 : [ret] "={eax}" (-> usize)
447 : [number] "{eax}" (number),
448 [arg1] "{ebx}" (arg1),
449 [arg2] "{ecx}" (arg2),
450 [arg3] "{edx}" (arg3));
451}
452
453pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
454 return asm volatile ("int $0x80"
455 : [ret] "={eax}" (-> usize)
456 : [number] "{eax}" (number),
457 [arg1] "{ebx}" (arg1),
458 [arg2] "{ecx}" (arg2),
459 [arg3] "{edx}" (arg3),
460 [arg4] "{esi}" (arg4));
461}
462
463pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize,
464 arg4: usize, arg5: usize) usize
465{
466 return asm volatile ("int $0x80"
467 : [ret] "={eax}" (-> usize)
468 : [number] "{eax}" (number),
469 [arg1] "{ebx}" (arg1),
470 [arg2] "{ecx}" (arg2),
471 [arg3] "{edx}" (arg3),
472 [arg4] "{esi}" (arg4),
473 [arg5] "{edi}" (arg5));
474}
475
476pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize,
477 arg4: usize, arg5: usize, arg6: usize) usize
478{
479 return asm volatile ("int $0x80"
480 : [ret] "={eax}" (-> usize)
481 : [number] "{eax}" (number),
482 [arg1] "{ebx}" (arg1),
483 [arg2] "{ecx}" (arg2),
484 [arg3] "{edx}" (arg3),
485 [arg4] "{esi}" (arg4),
486 [arg5] "{edi}" (arg5),
487 [arg6] "{ebp}" (arg6));
488}
489
490pub nakedcc fn restore() void {
491 asm volatile (
492 \\popl %%eax
493 \\movl $119, %%eax
494 \\int $0x80
495 :
496 :
497 : "rcx", "r11");
498}
499
500pub nakedcc fn restore_rt() void {
501 asm volatile ("int $0x80"
502 :
503 : [number] "{eax}" (usize(SYS_rt_sigreturn))
504 : "rcx", "r11");
505}
std/os/linux/index.zig+538-62
...@@ -101,17 +101,6 @@ pub const SIG_BLOCK = 0;...@@ -101,17 +101,6 @@ pub const SIG_BLOCK = 0;
101pub const SIG_UNBLOCK = 1;101pub const SIG_UNBLOCK = 1;
102pub const SIG_SETMASK = 2;102pub const SIG_SETMASK = 2;
103103
104pub const SOCK_STREAM = 1;
105pub const SOCK_DGRAM = 2;
106pub const SOCK_RAW = 3;
107pub const SOCK_RDM = 4;
108pub const SOCK_SEQPACKET = 5;
109pub const SOCK_DCCP = 6;
110pub const SOCK_PACKET = 10;
111pub const SOCK_CLOEXEC = 0o2000000;
112pub const SOCK_NONBLOCK = 0o4000;
113
114
115pub const PROTO_ip = 0o000;104pub const PROTO_ip = 0o000;
116pub const PROTO_icmp = 0o001;105pub const PROTO_icmp = 0o001;
117pub const PROTO_igmp = 0o002;106pub const PROTO_igmp = 0o002;
...@@ -149,6 +138,20 @@ pub const PROTO_encap = 0o142;...@@ -149,6 +138,20 @@ pub const PROTO_encap = 0o142;
149pub const PROTO_pim = 0o147;138pub const PROTO_pim = 0o147;
150pub const PROTO_raw = 0o377;139pub const PROTO_raw = 0o377;
151140
141pub const SHUT_RD = 0;
142pub const SHUT_WR = 1;
143pub const SHUT_RDWR = 2;
144
145pub const SOCK_STREAM = 1;
146pub const SOCK_DGRAM = 2;
147pub const SOCK_RAW = 3;
148pub const SOCK_RDM = 4;
149pub const SOCK_SEQPACKET = 5;
150pub const SOCK_DCCP = 6;
151pub const SOCK_PACKET = 10;
152pub const SOCK_CLOEXEC = 0o2000000;
153pub const SOCK_NONBLOCK = 0o4000;
154
152pub const PF_UNSPEC = 0;155pub const PF_UNSPEC = 0;
153pub const PF_LOCAL = 1;156pub const PF_LOCAL = 1;
154pub const PF_UNIX = PF_LOCAL;157pub const PF_UNIX = PF_LOCAL;
...@@ -193,7 +196,10 @@ pub const PF_CAIF = 37;...@@ -193,7 +196,10 @@ pub const PF_CAIF = 37;
193pub const PF_ALG = 38;196pub const PF_ALG = 38;
194pub const PF_NFC = 39;197pub const PF_NFC = 39;
195pub const PF_VSOCK = 40;198pub const PF_VSOCK = 40;
196pub const PF_MAX = 41;199pub const PF_KCM = 41;
200pub const PF_QIPCRTR = 42;
201pub const PF_SMC = 43;
202pub const PF_MAX = 44;
197203
198pub const AF_UNSPEC = PF_UNSPEC;204pub const AF_UNSPEC = PF_UNSPEC;
199pub const AF_LOCAL = PF_LOCAL;205pub const AF_LOCAL = PF_LOCAL;
...@@ -239,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;...@@ -239,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;
239pub const AF_ALG = PF_ALG;245pub const AF_ALG = PF_ALG;
240pub const AF_NFC = PF_NFC;246pub const AF_NFC = PF_NFC;
241pub const AF_VSOCK = PF_VSOCK;247pub const AF_VSOCK = PF_VSOCK;
248pub const AF_KCM = PF_KCM;
249pub const AF_QIPCRTR = PF_QIPCRTR;
250pub const AF_SMC = PF_SMC;
242pub const AF_MAX = PF_MAX;251pub const AF_MAX = PF_MAX;
243252
253pub const SO_DEBUG = 1;
254pub const SO_REUSEADDR = 2;
255pub const SO_TYPE = 3;
256pub const SO_ERROR = 4;
257pub const SO_DONTROUTE = 5;
258pub const SO_BROADCAST = 6;
259pub const SO_SNDBUF = 7;
260pub const SO_RCVBUF = 8;
261pub const SO_KEEPALIVE = 9;
262pub const SO_OOBINLINE = 10;
263pub const SO_NO_CHECK = 11;
264pub const SO_PRIORITY = 12;
265pub const SO_LINGER = 13;
266pub const SO_BSDCOMPAT = 14;
267pub const SO_REUSEPORT = 15;
268pub const SO_PASSCRED = 16;
269pub const SO_PEERCRED = 17;
270pub const SO_RCVLOWAT = 18;
271pub const SO_SNDLOWAT = 19;
272pub const SO_RCVTIMEO = 20;
273pub const SO_SNDTIMEO = 21;
274pub const SO_ACCEPTCONN = 30;
275pub const SO_SNDBUFFORCE = 32;
276pub const SO_RCVBUFFORCE = 33;
277pub const SO_PROTOCOL = 38;
278pub const SO_DOMAIN = 39;
279
280pub const SO_SECURITY_AUTHENTICATION = 22;
281pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
282pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
283
284pub const SO_BINDTODEVICE = 25;
285
286pub const SO_ATTACH_FILTER = 26;
287pub const SO_DETACH_FILTER = 27;
288pub const SO_GET_FILTER = SO_ATTACH_FILTER;
289
290pub const SO_PEERNAME = 28;
291pub const SO_TIMESTAMP = 29;
292pub const SCM_TIMESTAMP = SO_TIMESTAMP;
293
294pub const SO_PEERSEC = 31;
295pub const SO_PASSSEC = 34;
296pub const SO_TIMESTAMPNS = 35;
297pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
298pub const SO_MARK = 36;
299pub const SO_TIMESTAMPING = 37;
300pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
301pub const SO_RXQ_OVFL = 40;
302pub const SO_WIFI_STATUS = 41;
303pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
304pub const SO_PEEK_OFF = 42;
305pub const SO_NOFCS = 43;
306pub const SO_LOCK_FILTER = 44;
307pub const SO_SELECT_ERR_QUEUE = 45;
308pub const SO_BUSY_POLL = 46;
309pub const SO_MAX_PACING_RATE = 47;
310pub const SO_BPF_EXTENSIONS = 48;
311pub const SO_INCOMING_CPU = 49;
312pub const SO_ATTACH_BPF = 50;
313pub const SO_DETACH_BPF = SO_DETACH_FILTER;
314pub const SO_ATTACH_REUSEPORT_CBPF = 51;
315pub const SO_ATTACH_REUSEPORT_EBPF = 52;
316pub const SO_CNX_ADVICE = 53;
317pub const SCM_TIMESTAMPING_OPT_STATS = 54;
318pub const SO_MEMINFO = 55;
319pub const SO_INCOMING_NAPI_ID = 56;
320pub const SO_COOKIE = 57;
321pub const SCM_TIMESTAMPING_PKTINFO = 58;
322pub const SO_PEERGROUPS = 59;
323pub const SO_ZEROCOPY = 60;
324
325pub const SOL_SOCKET = 1;
326
327pub const SOL_IP = 0;
328pub const SOL_IPV6 = 41;
329pub const SOL_ICMPV6 = 58;
330
331pub const SOL_RAW = 255;
332pub const SOL_DECNET = 261;
333pub const SOL_X25 = 262;
334pub const SOL_PACKET = 263;
335pub const SOL_ATM = 264;
336pub const SOL_AAL = 265;
337pub const SOL_IRDA = 266;
338pub const SOL_NETBEUI = 267;
339pub const SOL_LLC = 268;
340pub const SOL_DCCP = 269;
341pub const SOL_NETLINK = 270;
342pub const SOL_TIPC = 271;
343pub const SOL_RXRPC = 272;
344pub const SOL_PPPOL2TP = 273;
345pub const SOL_BLUETOOTH = 274;
346pub const SOL_PNPIPE = 275;
347pub const SOL_RDS = 276;
348pub const SOL_IUCV = 277;
349pub const SOL_CAIF = 278;
350pub const SOL_ALG = 279;
351pub const SOL_NFC = 280;
352pub const SOL_KCM = 281;
353pub const SOL_TLS = 282;
354
355pub const SOMAXCONN = 128;
356
357pub const MSG_OOB = 0x0001;
358pub const MSG_PEEK = 0x0002;
359pub const MSG_DONTROUTE = 0x0004;
360pub const MSG_CTRUNC = 0x0008;
361pub const MSG_PROXY = 0x0010;
362pub const MSG_TRUNC = 0x0020;
363pub const MSG_DONTWAIT = 0x0040;
364pub const MSG_EOR = 0x0080;
365pub const MSG_WAITALL = 0x0100;
366pub const MSG_FIN = 0x0200;
367pub const MSG_SYN = 0x0400;
368pub const MSG_CONFIRM = 0x0800;
369pub const MSG_RST = 0x1000;
370pub const MSG_ERRQUEUE = 0x2000;
371pub const MSG_NOSIGNAL = 0x4000;
372pub const MSG_MORE = 0x8000;
373pub const MSG_WAITFORONE = 0x10000;
374pub const MSG_BATCH = 0x40000;
375pub const MSG_ZEROCOPY = 0x4000000;
376pub const MSG_FASTOPEN = 0x20000000;
377pub const MSG_CMSG_CLOEXEC = 0x40000000;
378
244pub const DT_UNKNOWN = 0;379pub const DT_UNKNOWN = 0;
245pub const DT_FIFO = 1;380pub const DT_FIFO = 1;
246pub const DT_CHR = 2;381pub const DT_CHR = 2;
...@@ -343,6 +478,126 @@ pub const CLOCK_BOOTTIME_ALARM = 9;...@@ -343,6 +478,126 @@ pub const CLOCK_BOOTTIME_ALARM = 9;
343pub const CLOCK_SGI_CYCLE = 10;478pub const CLOCK_SGI_CYCLE = 10;
344pub const CLOCK_TAI = 11;479pub const CLOCK_TAI = 11;
345480
481pub const CSIGNAL = 0x000000ff;
482pub const CLONE_VM = 0x00000100;
483pub const CLONE_FS = 0x00000200;
484pub const CLONE_FILES = 0x00000400;
485pub const CLONE_SIGHAND = 0x00000800;
486pub const CLONE_PTRACE = 0x00002000;
487pub const CLONE_VFORK = 0x00004000;
488pub const CLONE_PARENT = 0x00008000;
489pub const CLONE_THREAD = 0x00010000;
490pub const CLONE_NEWNS = 0x00020000;
491pub const CLONE_SYSVSEM = 0x00040000;
492pub const CLONE_SETTLS = 0x00080000;
493pub const CLONE_PARENT_SETTID = 0x00100000;
494pub const CLONE_CHILD_CLEARTID = 0x00200000;
495pub const CLONE_DETACHED = 0x00400000;
496pub const CLONE_UNTRACED = 0x00800000;
497pub const CLONE_CHILD_SETTID = 0x01000000;
498pub const CLONE_NEWCGROUP = 0x02000000;
499pub const CLONE_NEWUTS = 0x04000000;
500pub const CLONE_NEWIPC = 0x08000000;
501pub const CLONE_NEWUSER = 0x10000000;
502pub const CLONE_NEWPID = 0x20000000;
503pub const CLONE_NEWNET = 0x40000000;
504pub const CLONE_IO = 0x80000000;
505
506pub const MS_RDONLY = 1;
507pub const MS_NOSUID = 2;
508pub const MS_NODEV = 4;
509pub const MS_NOEXEC = 8;
510pub const MS_SYNCHRONOUS = 16;
511pub const MS_REMOUNT = 32;
512pub const MS_MANDLOCK = 64;
513pub const MS_DIRSYNC = 128;
514pub const MS_NOATIME = 1024;
515pub const MS_NODIRATIME = 2048;
516pub const MS_BIND = 4096;
517pub const MS_MOVE = 8192;
518pub const MS_REC = 16384;
519pub const MS_SILENT = 32768;
520pub const MS_POSIXACL = (1<<16);
521pub const MS_UNBINDABLE = (1<<17);
522pub const MS_PRIVATE = (1<<18);
523pub const MS_SLAVE = (1<<19);
524pub const MS_SHARED = (1<<20);
525pub const MS_RELATIME = (1<<21);
526pub const MS_KERNMOUNT = (1<<22);
527pub const MS_I_VERSION = (1<<23);
528pub const MS_STRICTATIME = (1<<24);
529pub const MS_LAZYTIME = (1<<25);
530pub const MS_NOREMOTELOCK = (1<<27);
531pub const MS_NOSEC = (1<<28);
532pub const MS_BORN = (1<<29);
533pub const MS_ACTIVE = (1<<30);
534pub const MS_NOUSER = (1<<31);
535
536pub const MS_RMT_MASK = (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME);
537
538pub const MS_MGC_VAL = 0xc0ed0000;
539pub const MS_MGC_MSK = 0xffff0000;
540
541pub const MNT_FORCE = 1;
542pub const MNT_DETACH = 2;
543pub const MNT_EXPIRE = 4;
544pub const UMOUNT_NOFOLLOW = 8;
545
546
547pub const S_IFMT = 0o170000;
548
549pub const S_IFDIR = 0o040000;
550pub const S_IFCHR = 0o020000;
551pub const S_IFBLK = 0o060000;
552pub const S_IFREG = 0o100000;
553pub const S_IFIFO = 0o010000;
554pub const S_IFLNK = 0o120000;
555pub const S_IFSOCK = 0o140000;
556
557pub const S_ISUID = 0o4000;
558pub const S_ISGID = 0o2000;
559pub const S_ISVTX = 0o1000;
560pub const S_IRUSR = 0o400;
561pub const S_IWUSR = 0o200;
562pub const S_IXUSR = 0o100;
563pub const S_IRWXU = 0o700;
564pub const S_IRGRP = 0o040;
565pub const S_IWGRP = 0o020;
566pub const S_IXGRP = 0o010;
567pub const S_IRWXG = 0o070;
568pub const S_IROTH = 0o004;
569pub const S_IWOTH = 0o002;
570pub const S_IXOTH = 0o001;
571pub const S_IRWXO = 0o007;
572
573pub fn S_ISREG(m: u32) bool {
574 return m & S_IFMT == S_IFREG;
575}
576
577pub fn S_ISDIR(m: u32) bool {
578 return m & S_IFMT == S_IFDIR;
579}
580
581pub fn S_ISCHR(m: u32) bool {
582 return m & S_IFMT == S_IFCHR;
583}
584
585pub fn S_ISBLK(m: u32) bool {
586 return m & S_IFMT == S_IFBLK;
587}
588
589pub fn S_ISFIFO(m: u32) bool {
590 return m & S_IFMT == S_IFIFO;
591}
592
593pub fn S_ISLNK(m: u32) bool {
594 return m & S_IFMT == S_IFLNK;
595}
596
597pub fn S_ISSOCK(m: u32) bool {
598 return m & S_IFMT == S_IFSOCK;
599}
600
346pub const TFD_NONBLOCK = O_NONBLOCK;601pub const TFD_NONBLOCK = O_NONBLOCK;
347pub const TFD_CLOEXEC = O_CLOEXEC;602pub const TFD_CLOEXEC = O_CLOEXEC;
348603
...@@ -380,6 +635,10 @@ pub fn chdir(path: &const u8) usize {...@@ -380,6 +635,10 @@ pub fn chdir(path: &const u8) usize {
380 return syscall1(SYS_chdir, @ptrToInt(path));635 return syscall1(SYS_chdir, @ptrToInt(path));
381}636}
382637
638pub fn chroot(path: &const u8) usize {
639 return syscall1(SYS_chroot, @ptrToInt(path));
640}
641
383pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {642pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) usize {
384 return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));643 return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
385}644}
...@@ -409,6 +668,18 @@ pub fn mkdir(path: &const u8, mode: u32) usize {...@@ -409,6 +668,18 @@ pub fn mkdir(path: &const u8, mode: u32) usize {
409 return syscall2(SYS_mkdir, @ptrToInt(path), mode);668 return syscall2(SYS_mkdir, @ptrToInt(path), mode);
410}669}
411670
671pub fn mount(special: &const u8, dir: &const u8, fstype: &const u8, flags: usize, data: usize) usize {
672 return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
673}
674
675pub fn umount(special: &const u8) usize {
676 return syscall2(SYS_umount2, @ptrToInt(special), 0);
677}
678
679pub fn umount2(special: &const u8, flags: u32) usize {
680 return syscall2(SYS_umount2, @ptrToInt(special), flags);
681}
682
412pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {683pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {
413 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),684 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
414 @bitCast(usize, offset));685 @bitCast(usize, offset));
...@@ -515,6 +786,58 @@ pub fn setregid(rgid: u32, egid: u32) usize {...@@ -515,6 +786,58 @@ pub fn setregid(rgid: u32, egid: u32) usize {
515 return syscall2(SYS_setregid, rgid, egid);786 return syscall2(SYS_setregid, rgid, egid);
516}787}
517788
789pub fn getuid() u32 {
790 return u32(syscall0(SYS_getuid));
791}
792
793pub fn getgid() u32 {
794 return u32(syscall0(SYS_getgid));
795}
796
797pub fn geteuid() u32 {
798 return u32(syscall0(SYS_geteuid));
799}
800
801pub fn getegid() u32 {
802 return u32(syscall0(SYS_getegid));
803}
804
805pub fn seteuid(euid: u32) usize {
806 return syscall1(SYS_seteuid, euid);
807}
808
809pub fn setegid(egid: u32) usize {
810 return syscall1(SYS_setegid, egid);
811}
812
813pub fn getresuid(ruid: &u32, euid: &u32, suid: &u32) usize {
814 return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
815}
816
817pub fn getresgid(rgid: &u32, egid: &u32, sgid: &u32) usize {
818 return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
819}
820
821pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
822 return syscall3(SYS_setresuid, ruid, euid, suid);
823}
824
825pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
826 return syscall3(SYS_setresgid, rgid, egid, sgid);
827}
828
829pub fn getgroups(size: usize, list: &u32) usize {
830 return syscall2(SYS_getgroups, size, @ptrToInt(list));
831}
832
833pub fn setgroups(size: usize, list: &const u32) usize {
834 return syscall2(SYS_setgroups, size, @ptrToInt(list));
835}
836
837pub fn getpid() i32 {
838 return @bitCast(i32, u32(syscall0(SYS_getpid)));
839}
840
518pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {841pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) usize {
519 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);842 return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);
520}843}
...@@ -599,30 +922,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {...@@ -599,30 +922,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {
599 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;922 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
600}923}
601924
602925pub const in_port_t = u16;
603pub const sa_family_t = u16;926pub const sa_family_t = u16;
604pub const socklen_t = u32;927pub const socklen_t = u32;
605pub const in_addr = u32;
606pub const in6_addr = [16]u8;
607928
608pub const sockaddr = extern struct {929pub const sockaddr = extern union {
609 family: sa_family_t,930 in: sockaddr_in,
610 port: u16,931 in6: sockaddr_in6,
611 data: [12]u8,
612};932};
613933
614pub const sockaddr_in = extern struct {934pub const sockaddr_in = extern struct {
615 family: sa_family_t,935 family: sa_family_t,
616 port: u16,936 port: in_port_t,
617 addr: in_addr,937 addr: u32,
618 zero: [8]u8,938 zero: [8]u8,
619};939};
620940
621pub const sockaddr_in6 = extern struct {941pub const sockaddr_in6 = extern struct {
622 family: sa_family_t,942 family: sa_family_t,
623 port: u16,943 port: in_port_t,
624 flowinfo: u32,944 flowinfo: u32,
625 addr: in6_addr,945 addr: [16]u8,
626 scope_id: u32,946 scope_id: u32,
627};947};
628948
...@@ -639,16 +959,16 @@ pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) us...@@ -639,16 +959,16 @@ pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) us
639 return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));959 return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
640}960}
641961
642pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize {962pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
643 return syscall3(SYS_socket, usize(domain), usize(socket_type), usize(protocol));963 return syscall3(SYS_socket, domain, socket_type, protocol);
644}964}
645965
646pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {966pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize {
647 return syscall5(SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));967 return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen));
648}968}
649969
650pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize {970pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: &u8, noalias optlen: &socklen_t) usize {
651 return syscall5(SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen));971 return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
652}972}
653973
654pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {974pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
...@@ -677,8 +997,8 @@ pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {...@@ -677,8 +997,8 @@ pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
677 return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));997 return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
678}998}
679999
680pub fn listen(fd: i32, backlog: i32) usize {1000pub fn listen(fd: i32, backlog: u32) usize {
681 return syscall2(SYS_listen, usize(fd), usize(backlog));1001 return syscall2(SYS_listen, usize(fd), backlog);
682}1002}
6831003
684pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {1004pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {
...@@ -697,46 +1017,83 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:...@@ -697,46 +1017,83 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
697 return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);1017 return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
698}1018}
6991019
700// error NameTooLong;
701// error SystemResources;
702// error Io;
703//
704// pub fn if_nametoindex(name: []u8) !u32 {
705// var ifr: ifreq = undefined;
706//
707// if (name.len >= ifr.ifr_name.len) {
708// return error.NameTooLong;
709// }
710//
711// const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
712// const socket_err = getErrno(socket_ret);
713// if (socket_err > 0) {
714// return error.SystemResources;
715// }
716// const socket_fd = i32(socket_ret);
717// @memcpy(&ifr.ifr_name[0], &name[0], name.len);
718// ifr.ifr_name[name.len] = 0;
719// const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr);
720// close(socket_fd);
721// const ioctl_err = getErrno(ioctl_ret);
722// if (ioctl_err > 0) {
723// return error.Io;
724// }
725// return ifr.ifr_ifindex;
726// }
727
728pub fn fstat(fd: i32, stat_buf: &Stat) usize {1020pub fn fstat(fd: i32, stat_buf: &Stat) usize {
729 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));1021 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
730}1022}
7311023
732pub const epoll_data = extern union {1024pub fn stat(pathname: &const u8, statbuf: &Stat) usize {
1025 return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf));
1026}
1027
1028pub fn lstat(pathname: &const u8, statbuf: &Stat) usize {
1029 return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf));
1030}
1031
1032pub fn listxattr(path: &const u8, list: &u8, size: usize) usize {
1033 return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
1034}
1035
1036pub fn llistxattr(path: &const u8, list: &u8, size: usize) usize {
1037 return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
1038}
1039
1040pub fn flistxattr(fd: usize, list: &u8, size: usize) usize {
1041 return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
1042}
1043
1044pub fn getxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize {
1045 return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1046}
1047
1048pub fn lgetxattr(path: &const u8, name: &const u8, value: &void, size: usize) usize {
1049 return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
1050}
1051
1052pub fn fgetxattr(fd: usize, name: &const u8, value: &void, size: usize) usize {
1053 return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
1054}
1055
1056pub fn setxattr(path: &const u8, name: &const u8, value: &const void,
1057 size: usize, flags: usize) usize {
1058
1059 return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1060 size, flags);
1061}
1062
1063pub fn lsetxattr(path: &const u8, name: &const u8, value: &const void,
1064 size: usize, flags: usize) usize {
1065
1066 return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value),
1067 size, flags);
1068}
1069
1070pub fn fsetxattr(fd: usize, name: &const u8, value: &const void,
1071 size: usize, flags: usize) usize {
1072
1073 return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value),
1074 size, flags);
1075}
1076
1077pub fn removexattr(path: &const u8, name: &const u8) usize {
1078 return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
1079}
1080
1081pub fn lremovexattr(path: &const u8, name: &const u8) usize {
1082 return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
1083}
1084
1085pub fn fremovexattr(fd: usize, name: &const u8) usize {
1086 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
1087}
1088
1089pub const epoll_data = packed union {
733 ptr: usize,1090 ptr: usize,
734 fd: i32,1091 fd: i32,
735 @"u32": u32,1092 @"u32": u32,
736 @"u64": u64,1093 @"u64": u64,
737};1094};
7381095
739pub const epoll_event = extern struct {1096pub const epoll_event = packed struct {
740 events: u32,1097 events: u32,
741 data: epoll_data,1098 data: epoll_data,
742};1099};
...@@ -749,7 +1106,7 @@ pub fn epoll_create1(flags: usize) usize {...@@ -749,7 +1106,7 @@ pub fn epoll_create1(flags: usize) usize {
749 return syscall1(SYS_epoll_create1, flags);1106 return syscall1(SYS_epoll_create1, flags);
750}1107}
7511108
752pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) usize {1109pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: &epoll_event) usize {
753 return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));1110 return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
754}1111}
7551112
...@@ -774,6 +1131,125 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va...@@ -774,6 +1131,125 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va
774 return syscall4(SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));1131 return syscall4(SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
775}1132}
7761133
1134pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1135pub const _LINUX_CAPABILITY_U32S_1 = 1;
1136
1137pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1138pub const _LINUX_CAPABILITY_U32S_2 = 2;
1139
1140pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1141pub const _LINUX_CAPABILITY_U32S_3 = 2;
1142
1143pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1144pub const VFS_CAP_REVISION_SHIFT = 24;
1145pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1146pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
1147
1148pub const VFS_CAP_REVISION_1 = 0x01000000;
1149pub const VFS_CAP_U32_1 = 1;
1150pub const XATTR_CAPS_SZ_1 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_1);
1151
1152pub const VFS_CAP_REVISION_2 = 0x02000000;
1153pub const VFS_CAP_U32_2 = 2;
1154pub const XATTR_CAPS_SZ_2 = @sizeOf(u32)*(1 + 2*VFS_CAP_U32_2);
1155
1156pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1157pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1158pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
1159
1160pub const vfs_cap_data = extern struct {
1161 //all of these are mandated as little endian
1162 //when on disk.
1163 const Data = struct {
1164 permitted: u32,
1165 inheritable: u32,
1166 };
1167
1168 magic_etc: u32,
1169 data: [VFS_CAP_U32]Data,
1170};
1171
1172
1173pub const CAP_CHOWN = 0;
1174pub const CAP_DAC_OVERRIDE = 1;
1175pub const CAP_DAC_READ_SEARCH = 2;
1176pub const CAP_FOWNER = 3;
1177pub const CAP_FSETID = 4;
1178pub const CAP_KILL = 5;
1179pub const CAP_SETGID = 6;
1180pub const CAP_SETUID = 7;
1181pub const CAP_SETPCAP = 8;
1182pub const CAP_LINUX_IMMUTABLE = 9;
1183pub const CAP_NET_BIND_SERVICE = 10;
1184pub const CAP_NET_BROADCAST = 11;
1185pub const CAP_NET_ADMIN = 12;
1186pub const CAP_NET_RAW = 13;
1187pub const CAP_IPC_LOCK = 14;
1188pub const CAP_IPC_OWNER = 15;
1189pub const CAP_SYS_MODULE = 16;
1190pub const CAP_SYS_RAWIO = 17;
1191pub const CAP_SYS_CHROOT = 18;
1192pub const CAP_SYS_PTRACE = 19;
1193pub const CAP_SYS_PACCT = 20;
1194pub const CAP_SYS_ADMIN = 21;
1195pub const CAP_SYS_BOOT = 22;
1196pub const CAP_SYS_NICE = 23;
1197pub const CAP_SYS_RESOURCE = 24;
1198pub const CAP_SYS_TIME = 25;
1199pub const CAP_SYS_TTY_CONFIG = 26;
1200pub const CAP_MKNOD = 27;
1201pub const CAP_LEASE = 28;
1202pub const CAP_AUDIT_WRITE = 29;
1203pub const CAP_AUDIT_CONTROL = 30;
1204pub const CAP_SETFCAP = 31;
1205pub const CAP_MAC_OVERRIDE = 32;
1206pub const CAP_MAC_ADMIN = 33;
1207pub const CAP_SYSLOG = 34;
1208pub const CAP_WAKE_ALARM = 35;
1209pub const CAP_BLOCK_SUSPEND = 36;
1210pub const CAP_AUDIT_READ = 37;
1211pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1212
1213pub fn cap_valid(u8: x) bool {
1214 return x >= 0 and x <= CAP_LAST_CAP;
1215}
1216
1217pub fn CAP_TO_MASK(cap: u8) u32 {
1218 return u32(1) << u5(cap & 31);
1219}
1220
1221pub fn CAP_TO_INDEX(cap: u8) u8 {
1222 return cap >> 5;
1223}
1224
1225pub const cap_t = extern struct {
1226 hdrp: &cap_user_header_t,
1227 datap: &cap_user_data_t,
1228};
1229
1230pub const cap_user_header_t = extern struct {
1231 version: u32,
1232 pid: usize,
1233};
1234
1235pub const cap_user_data_t = extern struct {
1236 effective: u32,
1237 permitted: u32,
1238 inheritable: u32,
1239};
1240
1241pub fn unshare(flags: usize) usize {
1242 return syscall1(SYS_unshare, usize(flags));
1243}
1244
1245pub fn capget(hdrp: &cap_user_header_t, datap: &cap_user_data_t) usize {
1246 return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
1247}
1248
1249pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize {
1250 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
1251}
1252
777test "import linux test" {1253test "import linux test" {
778 // TODO lazy analysis should prevent this test from being compiled on windows, but1254 // TODO lazy analysis should prevent this test from being compiled on windows, but
779 // it is still compiled on windows1255 // it is still compiled on windows
std/special/builtin.zig+25-8
...@@ -14,26 +14,43 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn...@@ -14,26 +14,43 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn
14 }14 }
15}15}
1616
17// Note that memset does not return `dest`, like the libc API.17export fn memset(dest: ?&u8, c: u8, n: usize) ?&u8 {
18// The semantics of memset is dictated by the corresponding
19// LLVM intrinsics, not by the libc API.
20export fn memset(dest: ?&u8, c: u8, n: usize) void {
21 @setRuntimeSafety(false);18 @setRuntimeSafety(false);
2219
23 var index: usize = 0;20 var index: usize = 0;
24 while (index != n) : (index += 1)21 while (index != n) : (index += 1)
25 (??dest)[index] = c;22 (??dest)[index] = c;
23
24 return dest;
26}25}
2726
28// Note that memcpy does not return `dest`, like the libc API.27export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) ?&u8 {
29// The semantics of memcpy is dictated by the corresponding
30// LLVM intrinsics, not by the libc API.
31export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) void {
32 @setRuntimeSafety(false);28 @setRuntimeSafety(false);
3329
34 var index: usize = 0;30 var index: usize = 0;
35 while (index != n) : (index += 1)31 while (index != n) : (index += 1)
36 (??dest)[index] = (??src)[index];32 (??dest)[index] = (??src)[index];
33
34 return dest;
35}
36
37export fn memmove(dest: ?&u8, src: ?&const u8, n: usize) ?&u8 {
38 @setRuntimeSafety(false);
39
40 if (@ptrToInt(dest) < @ptrToInt(src)) {
41 var index: usize = 0;
42 while (index != n) : (index += 1) {
43 (??dest)[index] = (??src)[index];
44 }
45 } else {
46 var index = n;
47 while (index != 0) {
48 index -= 1;
49 (??dest)[index] = (??src)[index];
50 }
51 }
52
53 return dest;
37}54}
3855
39comptime {56comptime {
std/zig/ast.zig+1386-226
...@@ -9,85 +9,180 @@ pub const Node = struct {...@@ -9,85 +9,180 @@ pub const Node = struct {
9 comment: ?&NodeLineComment,9 comment: ?&NodeLineComment,
1010
11 pub const Id = enum {11 pub const Id = enum {
12 // Top level
12 Root,13 Root,
14 Use,
15 TestDecl,
16
17 // Statements
13 VarDecl,18 VarDecl,
14 Identifier,19 Defer,
15 FnProto,20
16 ParamDecl,21 // Operators
17 Block,
18 InfixOp,22 InfixOp,
19 PrefixOp,23 PrefixOp,
24 SuffixOp,
25
26 // Control flow
27 Switch,
28 While,
29 For,
30 If,
31 ControlFlowExpression,
32 Suspend,
33
34 // Type expressions
35 VarType,
36 ErrorType,
37 FnProto,
38
39 // Primary expressions
20 IntegerLiteral,40 IntegerLiteral,
21 FloatLiteral,41 FloatLiteral,
22 StringLiteral,42 StringLiteral,
43 MultilineStringLiteral,
44 CharLiteral,
45 BoolLiteral,
46 NullLiteral,
23 UndefinedLiteral,47 UndefinedLiteral,
48 ThisLiteral,
49 Unreachable,
50 Identifier,
51 GroupedExpression,
24 BuiltinCall,52 BuiltinCall,
25 Call,53 ErrorSetDecl,
54 ContainerDecl,
55 Asm,
56 Comptime,
57 Block,
58
59 // Misc
26 LineComment,60 LineComment,
27 TestDecl,61 SwitchCase,
62 SwitchElse,
63 Else,
64 Payload,
65 PointerPayload,
66 PointerIndexPayload,
67 StructField,
68 UnionTag,
69 EnumTag,
70 AsmInput,
71 AsmOutput,
72 AsyncAttribute,
73 ParamDecl,
74 FieldInitializer,
75 };
76
77 const IdTypePair = struct {
78 id: Id,
79 Type: type,
28 };80 };
2981
82 // TODO: When @field exists, we could generate this by iterating over all members of `Id`,
83 // and making an array of `IdTypePair { .id = @field(Id, @memberName(Id, i)), .Type = @field(ast, "Node" ++ @memberName(Id, i)) }`
84 const idTypeTable = []IdTypePair {
85 IdTypePair { .id = Id.Root, .Type = NodeRoot },
86 IdTypePair { .id = Id.Use, .Type = NodeUse },
87 IdTypePair { .id = Id.TestDecl, .Type = NodeTestDecl },
88
89 IdTypePair { .id = Id.VarDecl, .Type = NodeVarDecl },
90 IdTypePair { .id = Id.Defer, .Type = NodeDefer },
91
92 IdTypePair { .id = Id.InfixOp, .Type = NodeInfixOp },
93 IdTypePair { .id = Id.PrefixOp, .Type = NodePrefixOp },
94 IdTypePair { .id = Id.SuffixOp, .Type = NodeSuffixOp },
95
96 IdTypePair { .id = Id.Switch, .Type = NodeSwitch },
97 IdTypePair { .id = Id.While, .Type = NodeWhile },
98 IdTypePair { .id = Id.For, .Type = NodeFor },
99 IdTypePair { .id = Id.If, .Type = NodeIf },
100 IdTypePair { .id = Id.ControlFlowExpression, .Type = NodeControlFlowExpression },
101 IdTypePair { .id = Id.Suspend, .Type = NodeSuspend },
102
103 IdTypePair { .id = Id.VarType, .Type = NodeVarType },
104 IdTypePair { .id = Id.ErrorType, .Type = NodeErrorType },
105 IdTypePair { .id = Id.FnProto, .Type = NodeFnProto },
106
107 IdTypePair { .id = Id.IntegerLiteral, .Type = NodeIntegerLiteral },
108 IdTypePair { .id = Id.FloatLiteral, .Type = NodeFloatLiteral },
109 IdTypePair { .id = Id.StringLiteral, .Type = NodeStringLiteral },
110 IdTypePair { .id = Id.MultilineStringLiteral, .Type = NodeMultilineStringLiteral },
111 IdTypePair { .id = Id.CharLiteral, .Type = NodeCharLiteral },
112 IdTypePair { .id = Id.BoolLiteral, .Type = NodeBoolLiteral },
113 IdTypePair { .id = Id.NullLiteral, .Type = NodeNullLiteral },
114 IdTypePair { .id = Id.UndefinedLiteral, .Type = NodeUndefinedLiteral },
115 IdTypePair { .id = Id.ThisLiteral, .Type = NodeThisLiteral },
116 IdTypePair { .id = Id.Unreachable, .Type = NodeUnreachable },
117 IdTypePair { .id = Id.Identifier, .Type = NodeIdentifier },
118 IdTypePair { .id = Id.GroupedExpression, .Type = NodeGroupedExpression },
119 IdTypePair { .id = Id.BuiltinCall, .Type = NodeBuiltinCall },
120 IdTypePair { .id = Id.ErrorSetDecl, .Type = NodeErrorSetDecl },
121 IdTypePair { .id = Id.ContainerDecl, .Type = NodeContainerDecl },
122 IdTypePair { .id = Id.Asm, .Type = NodeAsm },
123 IdTypePair { .id = Id.Comptime, .Type = NodeComptime },
124 IdTypePair { .id = Id.Block, .Type = NodeBlock },
125
126 IdTypePair { .id = Id.LineComment, .Type = NodeLineComment },
127 IdTypePair { .id = Id.SwitchCase, .Type = NodeSwitchCase },
128 IdTypePair { .id = Id.SwitchElse, .Type = NodeSwitchElse },
129 IdTypePair { .id = Id.Else, .Type = NodeElse },
130 IdTypePair { .id = Id.Payload, .Type = NodePayload },
131 IdTypePair { .id = Id.PointerPayload, .Type = NodePointerPayload },
132 IdTypePair { .id = Id.PointerIndexPayload, .Type = NodePointerIndexPayload },
133 IdTypePair { .id = Id.StructField, .Type = NodeStructField },
134 IdTypePair { .id = Id.UnionTag, .Type = NodeUnionTag },
135 IdTypePair { .id = Id.EnumTag, .Type = NodeEnumTag },
136 IdTypePair { .id = Id.AsmInput, .Type = NodeAsmInput },
137 IdTypePair { .id = Id.AsmOutput, .Type = NodeAsmOutput },
138 IdTypePair { .id = Id.AsyncAttribute, .Type = NodeAsyncAttribute },
139 IdTypePair { .id = Id.ParamDecl, .Type = NodeParamDecl },
140 IdTypePair { .id = Id.FieldInitializer, .Type = NodeFieldInitializer },
141 };
142
143 pub fn IdToType(comptime id: Id) type {
144 inline for (idTypeTable) |id_type_pair| {
145 if (id == id_type_pair.id)
146 return id_type_pair.Type;
147 }
148
149 unreachable;
150 }
151
152 pub fn typeToId(comptime T: type) Id {
153 inline for (idTypeTable) |id_type_pair| {
154 if (T == id_type_pair.Type)
155 return id_type_pair.id;
156 }
157
158 unreachable;
159 }
160
30 pub fn iterate(base: &Node, index: usize) ?&Node {161 pub fn iterate(base: &Node, index: usize) ?&Node {
31 return switch (base.id) {162 inline for (idTypeTable) |id_type_pair| {
32 Id.Root => @fieldParentPtr(NodeRoot, "base", base).iterate(index),163 if (base.id == id_type_pair.id)
33 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).iterate(index),164 return @fieldParentPtr(id_type_pair.Type, "base", base).iterate(index);
34 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).iterate(index),165 }
35 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).iterate(index),166
36 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).iterate(index),167 unreachable;
37 Id.Block => @fieldParentPtr(NodeBlock, "base", base).iterate(index),
38 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).iterate(index),
39 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).iterate(index),
40 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).iterate(index),
41 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).iterate(index),
42 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).iterate(index),
43 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).iterate(index),
44 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).iterate(index),
45 Id.Call => @fieldParentPtr(NodeCall, "base", base).iterate(index),
46 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).iterate(index),
47 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).iterate(index),
48 };
49 }168 }
50169
51 pub fn firstToken(base: &Node) Token {170 pub fn firstToken(base: &Node) Token {
52 return switch (base.id) {171 inline for (idTypeTable) |id_type_pair| {
53 Id.Root => @fieldParentPtr(NodeRoot, "base", base).firstToken(),172 if (base.id == id_type_pair.id)
54 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).firstToken(),173 return @fieldParentPtr(id_type_pair.Type, "base", base).firstToken();
55 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).firstToken(),174 }
56 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).firstToken(),175
57 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).firstToken(),176 unreachable;
58 Id.Block => @fieldParentPtr(NodeBlock, "base", base).firstToken(),
59 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).firstToken(),
60 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).firstToken(),
61 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).firstToken(),
62 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).firstToken(),
63 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).firstToken(),
64 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).firstToken(),
65 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).firstToken(),
66 Id.Call => @fieldParentPtr(NodeCall, "base", base).firstToken(),
67 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).firstToken(),
68 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).firstToken(),
69 };
70 }177 }
71178
72 pub fn lastToken(base: &Node) Token {179 pub fn lastToken(base: &Node) Token {
73 return switch (base.id) {180 inline for (idTypeTable) |id_type_pair| {
74 Id.Root => @fieldParentPtr(NodeRoot, "base", base).lastToken(),181 if (base.id == id_type_pair.id)
75 Id.VarDecl => @fieldParentPtr(NodeVarDecl, "base", base).lastToken(),182 return @fieldParentPtr(id_type_pair.Type, "base", base).lastToken();
76 Id.Identifier => @fieldParentPtr(NodeIdentifier, "base", base).lastToken(),183 }
77 Id.FnProto => @fieldParentPtr(NodeFnProto, "base", base).lastToken(),184
78 Id.ParamDecl => @fieldParentPtr(NodeParamDecl, "base", base).lastToken(),185 unreachable;
79 Id.Block => @fieldParentPtr(NodeBlock, "base", base).lastToken(),
80 Id.InfixOp => @fieldParentPtr(NodeInfixOp, "base", base).lastToken(),
81 Id.PrefixOp => @fieldParentPtr(NodePrefixOp, "base", base).lastToken(),
82 Id.IntegerLiteral => @fieldParentPtr(NodeIntegerLiteral, "base", base).lastToken(),
83 Id.FloatLiteral => @fieldParentPtr(NodeFloatLiteral, "base", base).lastToken(),
84 Id.StringLiteral => @fieldParentPtr(NodeStringLiteral, "base", base).lastToken(),
85 Id.UndefinedLiteral => @fieldParentPtr(NodeUndefinedLiteral, "base", base).lastToken(),
86 Id.BuiltinCall => @fieldParentPtr(NodeBuiltinCall, "base", base).lastToken(),
87 Id.Call => @fieldParentPtr(NodeCall, "base", base).lastToken(),
88 Id.LineComment => @fieldParentPtr(NodeLineComment, "base", base).lastToken(),
89 Id.TestDecl => @fieldParentPtr(NodeTestDecl, "base", base).lastToken(),
90 };
91 }186 }
92};187};
93188
...@@ -119,7 +214,7 @@ pub const NodeVarDecl = struct {...@@ -119,7 +214,7 @@ pub const NodeVarDecl = struct {
119 eq_token: Token,214 eq_token: Token,
120 mut_token: Token,215 mut_token: Token,
121 comptime_token: ?Token,216 comptime_token: ?Token,
122 extern_token: ?Token,217 extern_export_token: ?Token,
123 lib_name: ?&Node,218 lib_name: ?&Node,
124 type_node: ?&Node,219 type_node: ?&Node,
125 align_node: ?&Node,220 align_node: ?&Node,
...@@ -150,7 +245,7 @@ pub const NodeVarDecl = struct {...@@ -150,7 +245,7 @@ pub const NodeVarDecl = struct {
150 pub fn firstToken(self: &NodeVarDecl) Token {245 pub fn firstToken(self: &NodeVarDecl) Token {
151 if (self.visib_token) |visib_token| return visib_token;246 if (self.visib_token) |visib_token| return visib_token;
152 if (self.comptime_token) |comptime_token| return comptime_token;247 if (self.comptime_token) |comptime_token| return comptime_token;
153 if (self.extern_token) |extern_token| return extern_token;248 if (self.extern_export_token) |extern_export_token| return extern_export_token;
154 assert(self.lib_name == null);249 assert(self.lib_name == null);
155 return self.mut_token;250 return self.mut_token;
156 }251 }
...@@ -160,20 +255,236 @@ pub const NodeVarDecl = struct {...@@ -160,20 +255,236 @@ pub const NodeVarDecl = struct {
160 }255 }
161};256};
162257
163pub const NodeIdentifier = struct {258pub const NodeUse = struct {
259 base: Node,
260 visib_token: ?Token,
261 expr: &Node,
262 semicolon_token: Token,
263
264 pub fn iterate(self: &NodeUse, index: usize) ?&Node {
265 var i = index;
266
267 if (i < 1) return self.expr;
268 i -= 1;
269
270 return null;
271 }
272
273 pub fn firstToken(self: &NodeUse) Token {
274 if (self.visib_token) |visib_token| return visib_token;
275 return self.expr.firstToken();
276 }
277
278 pub fn lastToken(self: &NodeUse) Token {
279 return self.semicolon_token;
280 }
281};
282
283pub const NodeErrorSetDecl = struct {
284 base: Node,
285 error_token: Token,
286 decls: ArrayList(&NodeIdentifier),
287 rbrace_token: Token,
288
289 pub fn iterate(self: &NodeErrorSetDecl, index: usize) ?&Node {
290 var i = index;
291
292 if (i < self.decls.len) return &self.decls.at(i).base;
293 i -= self.decls.len;
294
295 return null;
296 }
297
298 pub fn firstToken(self: &NodeErrorSetDecl) Token {
299 return self.error_token;
300 }
301
302 pub fn lastToken(self: &NodeErrorSetDecl) Token {
303 return self.rbrace_token;
304 }
305};
306
307pub const NodeContainerDecl = struct {
308 base: Node,
309 ltoken: Token,
310 layout: Layout,
311 kind: Kind,
312 init_arg_expr: InitArg,
313 fields_and_decls: ArrayList(&Node),
314 rbrace_token: Token,
315
316 const Layout = enum {
317 Auto,
318 Extern,
319 Packed,
320 };
321
322 const Kind = enum {
323 Struct,
324 Enum,
325 Union,
326 };
327
328 const InitArg = union(enum) {
329 None,
330 Enum,
331 Type: &Node,
332 };
333
334 pub fn iterate(self: &NodeContainerDecl, index: usize) ?&Node {
335 var i = index;
336
337 switch (self.init_arg_expr) {
338 InitArg.Type => |t| {
339 if (i < 1) return t;
340 i -= 1;
341 },
342 InitArg.None,
343 InitArg.Enum => { }
344 }
345
346 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i);
347 i -= self.fields_and_decls.len;
348
349 return null;
350 }
351
352 pub fn firstToken(self: &NodeContainerDecl) Token {
353 return self.ltoken;
354 }
355
356 pub fn lastToken(self: &NodeContainerDecl) Token {
357 return self.rbrace_token;
358 }
359};
360
361pub const NodeStructField = struct {
362 base: Node,
363 visib_token: ?Token,
364 name_token: Token,
365 type_expr: &Node,
366
367 pub fn iterate(self: &NodeStructField, index: usize) ?&Node {
368 var i = index;
369
370 if (i < 1) return self.type_expr;
371 i -= 1;
372
373 return null;
374 }
375
376 pub fn firstToken(self: &NodeStructField) Token {
377 if (self.visib_token) |visib_token| return visib_token;
378 return self.name_token;
379 }
380
381 pub fn lastToken(self: &NodeStructField) Token {
382 return self.type_expr.lastToken();
383 }
384};
385
386pub const NodeUnionTag = struct {
387 base: Node,
388 name_token: Token,
389 type_expr: ?&Node,
390
391 pub fn iterate(self: &NodeUnionTag, index: usize) ?&Node {
392 var i = index;
393
394 if (self.type_expr) |type_expr| {
395 if (i < 1) return type_expr;
396 i -= 1;
397 }
398
399 return null;
400 }
401
402 pub fn firstToken(self: &NodeUnionTag) Token {
403 return self.name_token;
404 }
405
406 pub fn lastToken(self: &NodeUnionTag) Token {
407 if (self.type_expr) |type_expr| {
408 return type_expr.lastToken();
409 }
410
411 return self.name_token;
412 }
413};
414
415pub const NodeEnumTag = struct {
164 base: Node,416 base: Node,
165 name_token: Token,417 name_token: Token,
418 value: ?&Node,
419
420 pub fn iterate(self: &NodeEnumTag, index: usize) ?&Node {
421 var i = index;
422
423 if (self.value) |value| {
424 if (i < 1) return value;
425 i -= 1;
426 }
427
428 return null;
429 }
430
431 pub fn firstToken(self: &NodeEnumTag) Token {
432 return self.name_token;
433 }
434
435 pub fn lastToken(self: &NodeEnumTag) Token {
436 if (self.value) |value| {
437 return value.lastToken();
438 }
439
440 return self.name_token;
441 }
442};
443
444pub const NodeIdentifier = struct {
445 base: Node,
446 token: Token,
166447
167 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {448 pub fn iterate(self: &NodeIdentifier, index: usize) ?&Node {
168 return null;449 return null;
169 }450 }
170451
171 pub fn firstToken(self: &NodeIdentifier) Token {452 pub fn firstToken(self: &NodeIdentifier) Token {
172 return self.name_token;453 return self.token;
173 }454 }
174455
175 pub fn lastToken(self: &NodeIdentifier) Token {456 pub fn lastToken(self: &NodeIdentifier) Token {
176 return self.name_token;457 return self.token;
458 }
459};
460
461pub const NodeAsyncAttribute = struct {
462 base: Node,
463 async_token: Token,
464 allocator_type: ?&Node,
465 rangle_bracket: ?Token,
466
467 pub fn iterate(self: &NodeAsyncAttribute, index: usize) ?&Node {
468 var i = index;
469
470 if (self.allocator_type) |allocator_type| {
471 if (i < 1) return allocator_type;
472 i -= 1;
473 }
474
475 return null;
476 }
477
478 pub fn firstToken(self: &NodeAsyncAttribute) Token {
479 return self.async_token;
480 }
481
482 pub fn lastToken(self: &NodeAsyncAttribute) Token {
483 if (self.rangle_bracket) |rangle_bracket| {
484 return rangle_bracket;
485 }
486
487 return self.async_token;
177 }488 }
178};489};
179490
...@@ -185,16 +496,15 @@ pub const NodeFnProto = struct {...@@ -185,16 +496,15 @@ pub const NodeFnProto = struct {
185 params: ArrayList(&Node),496 params: ArrayList(&Node),
186 return_type: ReturnType,497 return_type: ReturnType,
187 var_args_token: ?Token,498 var_args_token: ?Token,
188 extern_token: ?Token,499 extern_export_inline_token: ?Token,
189 inline_token: ?Token,
190 cc_token: ?Token,500 cc_token: ?Token,
501 async_attr: ?&NodeAsyncAttribute,
191 body_node: ?&Node,502 body_node: ?&Node,
192 lib_name: ?&Node, // populated if this is an extern declaration503 lib_name: ?&Node, // populated if this is an extern declaration
193 align_expr: ?&Node, // populated if align(A) is present504 align_expr: ?&Node, // populated if align(A) is present
194505
195 pub const ReturnType = union(enum) {506 pub const ReturnType = union(enum) {
196 Explicit: &Node,507 Explicit: &Node,
197 Infer: Token,
198 InferErrorSet: &Node,508 InferErrorSet: &Node,
199 };509 };
200510
...@@ -216,7 +526,6 @@ pub const NodeFnProto = struct {...@@ -216,7 +526,6 @@ pub const NodeFnProto = struct {
216 if (i < 1) return node;526 if (i < 1) return node;
217 i -= 1;527 i -= 1;
218 },528 },
219 ReturnType.Infer => {},
220 }529 }
221530
222 if (self.align_expr) |align_expr| {531 if (self.align_expr) |align_expr| {
...@@ -237,9 +546,8 @@ pub const NodeFnProto = struct {...@@ -237,9 +546,8 @@ pub const NodeFnProto = struct {
237546
238 pub fn firstToken(self: &NodeFnProto) Token {547 pub fn firstToken(self: &NodeFnProto) Token {
239 if (self.visib_token) |visib_token| return visib_token;548 if (self.visib_token) |visib_token| return visib_token;
240 if (self.extern_token) |extern_token| return extern_token;549 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
241 assert(self.lib_name == null);550 assert(self.lib_name == null);
242 if (self.inline_token) |inline_token| return inline_token;
243 if (self.cc_token) |cc_token| return cc_token;551 if (self.cc_token) |cc_token| return cc_token;
244 return self.fn_token;552 return self.fn_token;
245 }553 }
...@@ -250,7 +558,6 @@ pub const NodeFnProto = struct {...@@ -250,7 +558,6 @@ pub const NodeFnProto = struct {
250 // TODO allow this and next prong to share bodies since the types are the same558 // TODO allow this and next prong to share bodies since the types are the same
251 ReturnType.Explicit => |node| return node.lastToken(),559 ReturnType.Explicit => |node| return node.lastToken(),
252 ReturnType.InferErrorSet => |node| return node.lastToken(),560 ReturnType.InferErrorSet => |node| return node.lastToken(),
253 ReturnType.Infer => |token| return token,
254 }561 }
255 }562 }
256};563};
...@@ -287,9 +594,10 @@ pub const NodeParamDecl = struct {...@@ -287,9 +594,10 @@ pub const NodeParamDecl = struct {
287594
288pub const NodeBlock = struct {595pub const NodeBlock = struct {
289 base: Node,596 base: Node,
290 begin_token: Token,597 label: ?Token,
291 end_token: Token,598 lbrace: Token,
292 statements: ArrayList(&Node),599 statements: ArrayList(&Node),
600 rbrace: Token,
293601
294 pub fn iterate(self: &NodeBlock, index: usize) ?&Node {602 pub fn iterate(self: &NodeBlock, index: usize) ?&Node {
295 var i = index;603 var i = index;
...@@ -301,187 +609,820 @@ pub const NodeBlock = struct {...@@ -301,187 +609,820 @@ pub const NodeBlock = struct {
301 }609 }
302610
303 pub fn firstToken(self: &NodeBlock) Token {611 pub fn firstToken(self: &NodeBlock) Token {
304 return self.begin_token;612 if (self.label) |label| {
613 return label;
614 }
615
616 return self.lbrace;
305 }617 }
306618
307 pub fn lastToken(self: &NodeBlock) Token {619 pub fn lastToken(self: &NodeBlock) Token {
308 return self.end_token;620 return self.rbrace;
309 }621 }
310};622};
311623
312pub const NodeInfixOp = struct {624pub const NodeDefer = struct {
313 base: Node,625 base: Node,
314 op_token: Token,626 defer_token: Token,
315 lhs: &Node,627 kind: Kind,
316 op: InfixOp,628 expr: &Node,
317 rhs: &Node,
318629
319 const InfixOp = enum {630 const Kind = enum {
320 Add,631 Error,
321 AddWrap,632 Unconditional,
322 ArrayCat,
323 ArrayMult,
324 Assign,
325 AssignBitAnd,
326 AssignBitOr,
327 AssignBitShiftLeft,
328 AssignBitShiftRight,
329 AssignBitXor,
330 AssignDiv,
331 AssignMinus,
332 AssignMinusWrap,
333 AssignMod,
334 AssignPlus,
335 AssignPlusWrap,
336 AssignTimes,
337 AssignTimesWarp,
338 BangEqual,
339 BitAnd,
340 BitOr,
341 BitShiftLeft,
342 BitShiftRight,
343 BitXor,
344 BoolAnd,
345 BoolOr,
346 Div,
347 EqualEqual,
348 ErrorUnion,
349 GreaterOrEqual,
350 GreaterThan,
351 LessOrEqual,
352 LessThan,
353 MergeErrorSets,
354 Mod,
355 Mult,
356 MultWrap,
357 Period,
358 Sub,
359 SubWrap,
360 UnwrapMaybe,
361 };633 };
362634
363 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {635 pub fn iterate(self: &NodeDefer, index: usize) ?&Node {
364 var i = index;636 var i = index;
365637
366 if (i < 1) return self.lhs;638 if (i < 1) return self.expr;
367 i -= 1;639 i -= 1;
368640
369 switch (self.op) {641 return null;
370 InfixOp.Add,642 }
371 InfixOp.AddWrap,643
372 InfixOp.ArrayCat,644 pub fn firstToken(self: &NodeDefer) Token {
373 InfixOp.ArrayMult,645 return self.defer_token;
374 InfixOp.Assign,646 }
375 InfixOp.AssignBitAnd,647
376 InfixOp.AssignBitOr,648 pub fn lastToken(self: &NodeDefer) Token {
377 InfixOp.AssignBitShiftLeft,649 return self.expr.lastToken();
378 InfixOp.AssignBitShiftRight,650 }
379 InfixOp.AssignBitXor,651};
380 InfixOp.AssignDiv,652
381 InfixOp.AssignMinus,653pub const NodeComptime = struct {
382 InfixOp.AssignMinusWrap,654 base: Node,
383 InfixOp.AssignMod,655 comptime_token: Token,
384 InfixOp.AssignPlus,656 expr: &Node,
385 InfixOp.AssignPlusWrap,657
386 InfixOp.AssignTimes,658 pub fn iterate(self: &NodeComptime, index: usize) ?&Node {
387 InfixOp.AssignTimesWarp,659 var i = index;
388 InfixOp.BangEqual,660
389 InfixOp.BitAnd,661 if (i < 1) return self.expr;
390 InfixOp.BitOr,662 i -= 1;
391 InfixOp.BitShiftLeft,663
392 InfixOp.BitShiftRight,664 return null;
393 InfixOp.BitXor,665 }
394 InfixOp.BoolAnd,666
395 InfixOp.BoolOr,667 pub fn firstToken(self: &NodeComptime) Token {
396 InfixOp.Div,668 return self.comptime_token;
397 InfixOp.EqualEqual,669 }
398 InfixOp.ErrorUnion,670
399 InfixOp.GreaterOrEqual,671 pub fn lastToken(self: &NodeComptime) Token {
400 InfixOp.GreaterThan,672 return self.expr.lastToken();
401 InfixOp.LessOrEqual,673 }
402 InfixOp.LessThan,674};
403 InfixOp.MergeErrorSets,675
404 InfixOp.Mod,676pub const NodePayload = struct {
677 base: Node,
678 lpipe: Token,
679 error_symbol: &NodeIdentifier,
680 rpipe: Token,
681
682 pub fn iterate(self: &NodePayload, index: usize) ?&Node {
683 var i = index;
684
685 if (i < 1) return &self.error_symbol.base;
686 i -= 1;
687
688 return null;
689 }
690
691 pub fn firstToken(self: &NodePayload) Token {
692 return self.lpipe;
693 }
694
695 pub fn lastToken(self: &NodePayload) Token {
696 return self.rpipe;
697 }
698};
699
700pub const NodePointerPayload = struct {
701 base: Node,
702 lpipe: Token,
703 is_ptr: bool,
704 value_symbol: &NodeIdentifier,
705 rpipe: Token,
706
707 pub fn iterate(self: &NodePointerPayload, index: usize) ?&Node {
708 var i = index;
709
710 if (i < 1) return &self.value_symbol.base;
711 i -= 1;
712
713 return null;
714 }
715
716 pub fn firstToken(self: &NodePointerPayload) Token {
717 return self.lpipe;
718 }
719
720 pub fn lastToken(self: &NodePointerPayload) Token {
721 return self.rpipe;
722 }
723};
724
725pub const NodePointerIndexPayload = struct {
726 base: Node,
727 lpipe: Token,
728 is_ptr: bool,
729 value_symbol: &NodeIdentifier,
730 index_symbol: ?&NodeIdentifier,
731 rpipe: Token,
732
733 pub fn iterate(self: &NodePointerIndexPayload, index: usize) ?&Node {
734 var i = index;
735
736 if (i < 1) return &self.value_symbol.base;
737 i -= 1;
738
739 if (self.index_symbol) |index_symbol| {
740 if (i < 1) return &index_symbol.base;
741 i -= 1;
742 }
743
744 return null;
745 }
746
747 pub fn firstToken(self: &NodePointerIndexPayload) Token {
748 return self.lpipe;
749 }
750
751 pub fn lastToken(self: &NodePointerIndexPayload) Token {
752 return self.rpipe;
753 }
754};
755
756pub const NodeElse = struct {
757 base: Node,
758 else_token: Token,
759 payload: ?&NodePayload,
760 body: &Node,
761
762 pub fn iterate(self: &NodeElse, index: usize) ?&Node {
763 var i = index;
764
765 if (self.payload) |payload| {
766 if (i < 1) return &payload.base;
767 i -= 1;
768 }
769
770 if (i < 1) return self.body;
771 i -= 1;
772
773 return null;
774 }
775
776 pub fn firstToken(self: &NodeElse) Token {
777 return self.else_token;
778 }
779
780 pub fn lastToken(self: &NodeElse) Token {
781 return self.body.lastToken();
782 }
783};
784
785pub const NodeSwitch = struct {
786 base: Node,
787 switch_token: Token,
788 expr: &Node,
789 cases: ArrayList(&NodeSwitchCase),
790 rbrace: Token,
791
792 pub fn iterate(self: &NodeSwitch, index: usize) ?&Node {
793 var i = index;
794
795 if (i < 1) return self.expr;
796 i -= 1;
797
798 if (i < self.cases.len) return &self.cases.at(i).base;
799 i -= self.cases.len;
800
801 return null;
802 }
803
804 pub fn firstToken(self: &NodeSwitch) Token {
805 return self.switch_token;
806 }
807
808 pub fn lastToken(self: &NodeSwitch) Token {
809 return self.rbrace;
810 }
811};
812
813pub const NodeSwitchCase = struct {
814 base: Node,
815 items: ArrayList(&Node),
816 payload: ?&NodePointerPayload,
817 expr: &Node,
818
819 pub fn iterate(self: &NodeSwitchCase, index: usize) ?&Node {
820 var i = index;
821
822 if (i < self.items.len) return self.items.at(i);
823 i -= self.items.len;
824
825 if (self.payload) |payload| {
826 if (i < 1) return &payload.base;
827 i -= 1;
828 }
829
830 if (i < 1) return self.expr;
831 i -= 1;
832
833 return null;
834 }
835
836 pub fn firstToken(self: &NodeSwitchCase) Token {
837 return self.items.at(0).firstToken();
838 }
839
840 pub fn lastToken(self: &NodeSwitchCase) Token {
841 return self.expr.lastToken();
842 }
843};
844
845pub const NodeSwitchElse = struct {
846 base: Node,
847 token: Token,
848
849 pub fn iterate(self: &NodeSwitchElse, index: usize) ?&Node {
850 return null;
851 }
852
853 pub fn firstToken(self: &NodeSwitchElse) Token {
854 return self.token;
855 }
856
857 pub fn lastToken(self: &NodeSwitchElse) Token {
858 return self.token;
859 }
860};
861
862pub const NodeWhile = struct {
863 base: Node,
864 label: ?Token,
865 inline_token: ?Token,
866 while_token: Token,
867 condition: &Node,
868 payload: ?&NodePointerPayload,
869 continue_expr: ?&Node,
870 body: &Node,
871 @"else": ?&NodeElse,
872
873 pub fn iterate(self: &NodeWhile, index: usize) ?&Node {
874 var i = index;
875
876 if (i < 1) return self.condition;
877 i -= 1;
878
879 if (self.payload) |payload| {
880 if (i < 1) return &payload.base;
881 i -= 1;
882 }
883
884 if (self.continue_expr) |continue_expr| {
885 if (i < 1) return continue_expr;
886 i -= 1;
887 }
888
889 if (i < 1) return self.body;
890 i -= 1;
891
892 if (self.@"else") |@"else"| {
893 if (i < 1) return &@"else".base;
894 i -= 1;
895 }
896
897 return null;
898 }
899
900 pub fn firstToken(self: &NodeWhile) Token {
901 if (self.label) |label| {
902 return label;
903 }
904
905 if (self.inline_token) |inline_token| {
906 return inline_token;
907 }
908
909 return self.while_token;
910 }
911
912 pub fn lastToken(self: &NodeWhile) Token {
913 if (self.@"else") |@"else"| {
914 return @"else".body.lastToken();
915 }
916
917 return self.body.lastToken();
918 }
919};
920
921pub const NodeFor = struct {
922 base: Node,
923 label: ?Token,
924 inline_token: ?Token,
925 for_token: Token,
926 array_expr: &Node,
927 payload: ?&NodePointerIndexPayload,
928 body: &Node,
929 @"else": ?&NodeElse,
930
931 pub fn iterate(self: &NodeFor, index: usize) ?&Node {
932 var i = index;
933
934 if (i < 1) return self.array_expr;
935 i -= 1;
936
937 if (self.payload) |payload| {
938 if (i < 1) return &payload.base;
939 i -= 1;
940 }
941
942 if (i < 1) return self.body;
943 i -= 1;
944
945 if (self.@"else") |@"else"| {
946 if (i < 1) return &@"else".base;
947 i -= 1;
948 }
949
950 return null;
951 }
952
953 pub fn firstToken(self: &NodeFor) Token {
954 if (self.label) |label| {
955 return label;
956 }
957
958 if (self.inline_token) |inline_token| {
959 return inline_token;
960 }
961
962 return self.for_token;
963 }
964
965 pub fn lastToken(self: &NodeFor) Token {
966 if (self.@"else") |@"else"| {
967 return @"else".body.lastToken();
968 }
969
970 return self.body.lastToken();
971 }
972};
973
974pub const NodeIf = struct {
975 base: Node,
976 if_token: Token,
977 condition: &Node,
978 payload: ?&NodePointerPayload,
979 body: &Node,
980 @"else": ?&NodeElse,
981
982 pub fn iterate(self: &NodeIf, index: usize) ?&Node {
983 var i = index;
984
985 if (i < 1) return self.condition;
986 i -= 1;
987
988 if (self.payload) |payload| {
989 if (i < 1) return &payload.base;
990 i -= 1;
991 }
992
993 if (i < 1) return self.body;
994 i -= 1;
995
996 if (self.@"else") |@"else"| {
997 if (i < 1) return &@"else".base;
998 i -= 1;
999 }
1000
1001 return null;
1002 }
1003
1004 pub fn firstToken(self: &NodeIf) Token {
1005 return self.if_token;
1006 }
1007
1008 pub fn lastToken(self: &NodeIf) Token {
1009 if (self.@"else") |@"else"| {
1010 return @"else".body.lastToken();
1011 }
1012
1013 return self.body.lastToken();
1014 }
1015};
1016
1017pub const NodeInfixOp = struct {
1018 base: Node,
1019 op_token: Token,
1020 lhs: &Node,
1021 op: InfixOp,
1022 rhs: &Node,
1023
1024 const InfixOp = union(enum) {
1025 Add,
1026 AddWrap,
1027 ArrayCat,
1028 ArrayMult,
1029 Assign,
1030 AssignBitAnd,
1031 AssignBitOr,
1032 AssignBitShiftLeft,
1033 AssignBitShiftRight,
1034 AssignBitXor,
1035 AssignDiv,
1036 AssignMinus,
1037 AssignMinusWrap,
1038 AssignMod,
1039 AssignPlus,
1040 AssignPlusWrap,
1041 AssignTimes,
1042 AssignTimesWarp,
1043 BangEqual,
1044 BitAnd,
1045 BitOr,
1046 BitShiftLeft,
1047 BitShiftRight,
1048 BitXor,
1049 BoolAnd,
1050 BoolOr,
1051 Catch: ?&NodePayload,
1052 Div,
1053 EqualEqual,
1054 ErrorUnion,
1055 GreaterOrEqual,
1056 GreaterThan,
1057 LessOrEqual,
1058 LessThan,
1059 MergeErrorSets,
1060 Mod,
1061 Mult,
1062 MultWrap,
1063 Period,
1064 Range,
1065 Sub,
1066 SubWrap,
1067 UnwrapMaybe,
1068 };
1069
1070 pub fn iterate(self: &NodeInfixOp, index: usize) ?&Node {
1071 var i = index;
1072
1073 if (i < 1) return self.lhs;
1074 i -= 1;
1075
1076 switch (self.op) {
1077 InfixOp.Catch => |maybe_payload| {
1078 if (maybe_payload) |payload| {
1079 if (i < 1) return &payload.base;
1080 i -= 1;
1081 }
1082 },
1083
1084 InfixOp.Add,
1085 InfixOp.AddWrap,
1086 InfixOp.ArrayCat,
1087 InfixOp.ArrayMult,
1088 InfixOp.Assign,
1089 InfixOp.AssignBitAnd,
1090 InfixOp.AssignBitOr,
1091 InfixOp.AssignBitShiftLeft,
1092 InfixOp.AssignBitShiftRight,
1093 InfixOp.AssignBitXor,
1094 InfixOp.AssignDiv,
1095 InfixOp.AssignMinus,
1096 InfixOp.AssignMinusWrap,
1097 InfixOp.AssignMod,
1098 InfixOp.AssignPlus,
1099 InfixOp.AssignPlusWrap,
1100 InfixOp.AssignTimes,
1101 InfixOp.AssignTimesWarp,
1102 InfixOp.BangEqual,
1103 InfixOp.BitAnd,
1104 InfixOp.BitOr,
1105 InfixOp.BitShiftLeft,
1106 InfixOp.BitShiftRight,
1107 InfixOp.BitXor,
1108 InfixOp.BoolAnd,
1109 InfixOp.BoolOr,
1110 InfixOp.Div,
1111 InfixOp.EqualEqual,
1112 InfixOp.ErrorUnion,
1113 InfixOp.GreaterOrEqual,
1114 InfixOp.GreaterThan,
1115 InfixOp.LessOrEqual,
1116 InfixOp.LessThan,
1117 InfixOp.MergeErrorSets,
1118 InfixOp.Mod,
405 InfixOp.Mult,1119 InfixOp.Mult,
406 InfixOp.MultWrap,1120 InfixOp.MultWrap,
407 InfixOp.Period,1121 InfixOp.Period,
1122 InfixOp.Range,
408 InfixOp.Sub,1123 InfixOp.Sub,
409 InfixOp.SubWrap,1124 InfixOp.SubWrap,
410 InfixOp.UnwrapMaybe => {},1125 InfixOp.UnwrapMaybe => {},
411 }1126 }
4121127
413 if (i < 1) return self.rhs;1128 if (i < 1) return self.rhs;
1129 i -= 1;
1130
1131 return null;
1132 }
1133
1134 pub fn firstToken(self: &NodeInfixOp) Token {
1135 return self.lhs.firstToken();
1136 }
1137
1138 pub fn lastToken(self: &NodeInfixOp) Token {
1139 return self.rhs.lastToken();
1140 }
1141};
1142
1143pub const NodePrefixOp = struct {
1144 base: Node,
1145 op_token: Token,
1146 op: PrefixOp,
1147 rhs: &Node,
1148
1149 const PrefixOp = union(enum) {
1150 AddrOf: AddrOfInfo,
1151 ArrayType: &Node,
1152 Await,
1153 BitNot,
1154 BoolNot,
1155 Cancel,
1156 Deref,
1157 MaybeType,
1158 Negation,
1159 NegationWrap,
1160 Resume,
1161 SliceType: AddrOfInfo,
1162 Try,
1163 UnwrapMaybe,
1164 };
1165
1166 const AddrOfInfo = struct {
1167 align_expr: ?&Node,
1168 bit_offset_start_token: ?Token,
1169 bit_offset_end_token: ?Token,
1170 const_token: ?Token,
1171 volatile_token: ?Token,
1172 };
1173
1174 pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {
1175 var i = index;
1176
1177 switch (self.op) {
1178 PrefixOp.SliceType => |addr_of_info| {
1179 if (addr_of_info.align_expr) |align_expr| {
1180 if (i < 1) return align_expr;
1181 i -= 1;
1182 }
1183 },
1184 PrefixOp.AddrOf => |addr_of_info| {
1185 if (addr_of_info.align_expr) |align_expr| {
1186 if (i < 1) return align_expr;
1187 i -= 1;
1188 }
1189 },
1190 PrefixOp.ArrayType => |size_expr| {
1191 if (i < 1) return size_expr;
1192 i -= 1;
1193 },
1194 PrefixOp.Await,
1195 PrefixOp.BitNot,
1196 PrefixOp.BoolNot,
1197 PrefixOp.Cancel,
1198 PrefixOp.Deref,
1199 PrefixOp.MaybeType,
1200 PrefixOp.Negation,
1201 PrefixOp.NegationWrap,
1202 PrefixOp.Try,
1203 PrefixOp.Resume,
1204 PrefixOp.UnwrapMaybe => {},
1205 }
1206
1207 if (i < 1) return self.rhs;
1208 i -= 1;
1209
1210 return null;
1211 }
1212
1213 pub fn firstToken(self: &NodePrefixOp) Token {
1214 return self.op_token;
1215 }
1216
1217 pub fn lastToken(self: &NodePrefixOp) Token {
1218 return self.rhs.lastToken();
1219 }
1220};
1221
1222pub const NodeFieldInitializer = struct {
1223 base: Node,
1224 period_token: Token,
1225 name_token: Token,
1226 expr: &Node,
1227
1228 pub fn iterate(self: &NodeFieldInitializer, index: usize) ?&Node {
1229 var i = index;
1230
1231 if (i < 1) return self.expr;
1232 i -= 1;
1233
1234 return null;
1235 }
1236
1237 pub fn firstToken(self: &NodeFieldInitializer) Token {
1238 return self.period_token;
1239 }
1240
1241 pub fn lastToken(self: &NodeFieldInitializer) Token {
1242 return self.expr.lastToken();
1243 }
1244};
1245
1246pub const NodeSuffixOp = struct {
1247 base: Node,
1248 lhs: &Node,
1249 op: SuffixOp,
1250 rtoken: Token,
1251
1252 const SuffixOp = union(enum) {
1253 Call: CallInfo,
1254 ArrayAccess: &Node,
1255 Slice: SliceRange,
1256 ArrayInitializer: ArrayList(&Node),
1257 StructInitializer: ArrayList(&NodeFieldInitializer),
1258 };
1259
1260 const CallInfo = struct {
1261 params: ArrayList(&Node),
1262 async_attr: ?&NodeAsyncAttribute,
1263 };
1264
1265 const SliceRange = struct {
1266 start: &Node,
1267 end: ?&Node,
1268 };
1269
1270 pub fn iterate(self: &NodeSuffixOp, index: usize) ?&Node {
1271 var i = index;
1272
1273 if (i < 1) return self.lhs;
1274 i -= 1;
1275
1276 switch (self.op) {
1277 SuffixOp.Call => |call_info| {
1278 if (i < call_info.params.len) return call_info.params.at(i);
1279 i -= call_info.params.len;
1280 },
1281 SuffixOp.ArrayAccess => |index_expr| {
1282 if (i < 1) return index_expr;
1283 i -= 1;
1284 },
1285 SuffixOp.Slice => |range| {
1286 if (i < 1) return range.start;
1287 i -= 1;
1288
1289 if (range.end) |end| {
1290 if (i < 1) return end;
1291 i -= 1;
1292 }
1293 },
1294 SuffixOp.ArrayInitializer => |exprs| {
1295 if (i < exprs.len) return exprs.at(i);
1296 i -= exprs.len;
1297 },
1298 SuffixOp.StructInitializer => |fields| {
1299 if (i < fields.len) return &fields.at(i).base;
1300 i -= fields.len;
1301 },
1302 }
1303
1304 return null;
1305 }
1306
1307 pub fn firstToken(self: &NodeSuffixOp) Token {
1308 return self.lhs.firstToken();
1309 }
1310
1311 pub fn lastToken(self: &NodeSuffixOp) Token {
1312 return self.rtoken;
1313 }
1314};
1315
1316pub const NodeGroupedExpression = struct {
1317 base: Node,
1318 lparen: Token,
1319 expr: &Node,
1320 rparen: Token,
1321
1322 pub fn iterate(self: &NodeGroupedExpression, index: usize) ?&Node {
1323 var i = index;
1324
1325 if (i < 1) return self.expr;
414 i -= 1;1326 i -= 1;
4151327
416 return null;1328 return null;
417 }1329 }
4181330
419 pub fn firstToken(self: &NodeInfixOp) Token {1331 pub fn firstToken(self: &NodeGroupedExpression) Token {
420 return self.lhs.firstToken();1332 return self.lparen;
421 }1333 }
4221334
423 pub fn lastToken(self: &NodeInfixOp) Token {1335 pub fn lastToken(self: &NodeGroupedExpression) Token {
424 return self.rhs.lastToken();1336 return self.rparen;
425 }1337 }
426};1338};
4271339
428pub const NodePrefixOp = struct {1340pub const NodeControlFlowExpression = struct {
429 base: Node,1341 base: Node,
430 op_token: Token,1342 ltoken: Token,
431 op: PrefixOp,1343 kind: Kind,
432 rhs: &Node,1344 rhs: ?&Node,
4331345
434 const PrefixOp = union(enum) {1346 const Kind = union(enum) {
435 AddrOf: AddrOfInfo,1347 Break: ?Token,
436 BitNot,1348 Continue: ?Token,
437 BoolNot,
438 Deref,
439 Negation,
440 NegationWrap,
441 Return,1349 Return,
442 Try,
443 UnwrapMaybe,
444 };
445 const AddrOfInfo = struct {
446 align_expr: ?&Node,
447 bit_offset_start_token: ?Token,
448 bit_offset_end_token: ?Token,
449 const_token: ?Token,
450 volatile_token: ?Token,
451 };1350 };
4521351
453 pub fn iterate(self: &NodePrefixOp, index: usize) ?&Node {1352 pub fn iterate(self: &NodeControlFlowExpression, index: usize) ?&Node {
454 var i = index;1353 var i = index;
4551354
456 switch (self.op) {1355 if (self.rhs) |rhs| {
457 PrefixOp.AddrOf => |addr_of_info| {1356 if (i < 1) return rhs;
458 if (addr_of_info.align_expr) |align_expr| {1357 i -= 1;
459 if (i < 1) return align_expr;1358 }
460 i -= 1;1359
1360 return null;
1361 }
1362
1363 pub fn firstToken(self: &NodeControlFlowExpression) Token {
1364 return self.ltoken;
1365 }
1366
1367 pub fn lastToken(self: &NodeControlFlowExpression) Token {
1368 if (self.rhs) |rhs| {
1369 return rhs.lastToken();
1370 }
1371
1372 switch (self.kind) {
1373 Kind.Break => |maybe_blk_token| {
1374 if (maybe_blk_token) |blk_token| {
1375 return blk_token;
461 }1376 }
462 },1377 },
463 PrefixOp.BitNot,1378 Kind.Continue => |maybe_blk_token| {
464 PrefixOp.BoolNot,1379 if (maybe_blk_token) |blk_token| {
465 PrefixOp.Deref,1380 return blk_token;
466 PrefixOp.Negation,1381 }
467 PrefixOp.NegationWrap,1382 },
468 PrefixOp.Return,1383 Kind.Return => return self.ltoken,
469 PrefixOp.Try,
470 PrefixOp.UnwrapMaybe => {},
471 }1384 }
4721385
473 if (i < 1) return self.rhs;1386 return self.ltoken;
474 i -= 1;1387 }
1388};
1389
1390pub const NodeSuspend = struct {
1391 base: Node,
1392 suspend_token: Token,
1393 payload: ?&NodePayload,
1394 body: ?&Node,
1395
1396 pub fn iterate(self: &NodeSuspend, index: usize) ?&Node {
1397 var i = index;
1398
1399 if (self.payload) |payload| {
1400 if (i < 1) return &payload.base;
1401 i -= 1;
1402 }
1403
1404 if (self.body) |body| {
1405 if (i < 1) return body;
1406 i -= 1;
1407 }
4751408
476 return null;1409 return null;
477 }1410 }
4781411
479 pub fn firstToken(self: &NodePrefixOp) Token {1412 pub fn firstToken(self: &NodeSuspend) Token {
480 return self.op_token;1413 return self.suspend_token;
481 }1414 }
4821415
483 pub fn lastToken(self: &NodePrefixOp) Token {1416 pub fn lastToken(self: &NodeSuspend) Token {
484 return self.rhs.lastToken();1417 if (self.body) |body| {
1418 return body.lastToken();
1419 }
1420
1421 if (self.payload) |payload| {
1422 return payload.lastToken();
1423 }
1424
1425 return self.suspend_token;
485 }1426 }
486};1427};
4871428
...@@ -543,46 +1484,87 @@ pub const NodeBuiltinCall = struct {...@@ -543,46 +1484,87 @@ pub const NodeBuiltinCall = struct {
543 }1484 }
544};1485};
5451486
546pub const NodeCall = struct {1487pub const NodeStringLiteral = struct {
547 base: Node,1488 base: Node,
548 callee: &Node,1489 token: Token,
549 params: ArrayList(&Node),
550 rparen_token: Token,
5511490
552 pub fn iterate(self: &NodeCall, index: usize) ?&Node {1491 pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {
553 var i = index;1492 return null;
1493 }
5541494
555 if (i < 1) return self.callee;1495 pub fn firstToken(self: &NodeStringLiteral) Token {
556 i -= 1;1496 return self.token;
1497 }
5571498
558 if (i < self.params.len) return self.params.at(i);1499 pub fn lastToken(self: &NodeStringLiteral) Token {
559 i -= self.params.len;1500 return self.token;
1501 }
1502};
1503
1504pub const NodeMultilineStringLiteral = struct {
1505 base: Node,
1506 tokens: ArrayList(Token),
5601507
1508 pub fn iterate(self: &NodeMultilineStringLiteral, index: usize) ?&Node {
561 return null;1509 return null;
562 }1510 }
5631511
564 pub fn firstToken(self: &NodeCall) Token {1512 pub fn firstToken(self: &NodeMultilineStringLiteral) Token {
565 return self.callee.firstToken();1513 return self.tokens.at(0);
566 }1514 }
5671515
568 pub fn lastToken(self: &NodeCall) Token {1516 pub fn lastToken(self: &NodeMultilineStringLiteral) Token {
569 return self.rparen_token;1517 return self.tokens.at(self.tokens.len - 1);
570 }1518 }
571};1519};
5721520
573pub const NodeStringLiteral = struct {1521pub const NodeCharLiteral = struct {
574 base: Node,1522 base: Node,
575 token: Token,1523 token: Token,
5761524
577 pub fn iterate(self: &NodeStringLiteral, index: usize) ?&Node {1525 pub fn iterate(self: &NodeCharLiteral, index: usize) ?&Node {
578 return null;1526 return null;
579 }1527 }
5801528
581 pub fn firstToken(self: &NodeStringLiteral) Token {1529 pub fn firstToken(self: &NodeCharLiteral) Token {
582 return self.token;1530 return self.token;
583 }1531 }
5841532
585 pub fn lastToken(self: &NodeStringLiteral) Token {1533 pub fn lastToken(self: &NodeCharLiteral) Token {
1534 return self.token;
1535 }
1536};
1537
1538pub const NodeBoolLiteral = struct {
1539 base: Node,
1540 token: Token,
1541
1542 pub fn iterate(self: &NodeBoolLiteral, index: usize) ?&Node {
1543 return null;
1544 }
1545
1546 pub fn firstToken(self: &NodeBoolLiteral) Token {
1547 return self.token;
1548 }
1549
1550 pub fn lastToken(self: &NodeBoolLiteral) Token {
1551 return self.token;
1552 }
1553};
1554
1555pub const NodeNullLiteral = struct {
1556 base: Node,
1557 token: Token,
1558
1559 pub fn iterate(self: &NodeNullLiteral, index: usize) ?&Node {
1560 return null;
1561 }
1562
1563 pub fn firstToken(self: &NodeNullLiteral) Token {
1564 return self.token;
1565 }
1566
1567 pub fn lastToken(self: &NodeNullLiteral) Token {
586 return self.token;1568 return self.token;
587 }1569 }
588};1570};
...@@ -604,6 +1586,185 @@ pub const NodeUndefinedLiteral = struct {...@@ -604,6 +1586,185 @@ pub const NodeUndefinedLiteral = struct {
604 }1586 }
605};1587};
6061588
1589pub const NodeThisLiteral = struct {
1590 base: Node,
1591 token: Token,
1592
1593 pub fn iterate(self: &NodeThisLiteral, index: usize) ?&Node {
1594 return null;
1595 }
1596
1597 pub fn firstToken(self: &NodeThisLiteral) Token {
1598 return self.token;
1599 }
1600
1601 pub fn lastToken(self: &NodeThisLiteral) Token {
1602 return self.token;
1603 }
1604};
1605
1606pub const NodeAsmOutput = struct {
1607 base: Node,
1608 symbolic_name: &NodeIdentifier,
1609 constraint: &Node,
1610 kind: Kind,
1611
1612 const Kind = union(enum) {
1613 Variable: &NodeIdentifier,
1614 Return: &Node
1615 };
1616
1617 pub fn iterate(self: &NodeAsmOutput, index: usize) ?&Node {
1618 var i = index;
1619
1620 if (i < 1) return &self.symbolic_name.base;
1621 i -= 1;
1622
1623 if (i < 1) return self.constraint;
1624 i -= 1;
1625
1626 switch (self.kind) {
1627 Kind.Variable => |variable_name| {
1628 if (i < 1) return &variable_name.base;
1629 i -= 1;
1630 },
1631 Kind.Return => |return_type| {
1632 if (i < 1) return return_type;
1633 i -= 1;
1634 }
1635 }
1636
1637 return null;
1638 }
1639
1640 pub fn firstToken(self: &NodeAsmOutput) Token {
1641 return self.symbolic_name.firstToken();
1642 }
1643
1644 pub fn lastToken(self: &NodeAsmOutput) Token {
1645 return switch (self.kind) {
1646 Kind.Variable => |variable_name| variable_name.lastToken(),
1647 Kind.Return => |return_type| return_type.lastToken(),
1648 };
1649 }
1650};
1651
1652pub const NodeAsmInput = struct {
1653 base: Node,
1654 symbolic_name: &NodeIdentifier,
1655 constraint: &Node,
1656 expr: &Node,
1657
1658 pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node {
1659 var i = index;
1660
1661 if (i < 1) return &self.symbolic_name.base;
1662 i -= 1;
1663
1664 if (i < 1) return self.constraint;
1665 i -= 1;
1666
1667 if (i < 1) return self.expr;
1668 i -= 1;
1669
1670 return null;
1671 }
1672
1673 pub fn firstToken(self: &NodeAsmInput) Token {
1674 return self.symbolic_name.firstToken();
1675 }
1676
1677 pub fn lastToken(self: &NodeAsmInput) Token {
1678 return self.expr.lastToken();
1679 }
1680};
1681
1682pub const NodeAsm = struct {
1683 base: Node,
1684 asm_token: Token,
1685 is_volatile: bool,
1686 template: &Node,
1687 //tokens: ArrayList(AsmToken),
1688 outputs: ArrayList(&NodeAsmOutput),
1689 inputs: ArrayList(&NodeAsmInput),
1690 cloppers: ArrayList(&Node),
1691 rparen: Token,
1692
1693 pub fn iterate(self: &NodeAsm, index: usize) ?&Node {
1694 var i = index;
1695
1696 if (i < self.outputs.len) return &self.outputs.at(index).base;
1697 i -= self.outputs.len;
1698
1699 if (i < self.inputs.len) return &self.inputs.at(index).base;
1700 i -= self.inputs.len;
1701
1702 if (i < self.cloppers.len) return self.cloppers.at(index);
1703 i -= self.cloppers.len;
1704
1705 return null;
1706 }
1707
1708 pub fn firstToken(self: &NodeAsm) Token {
1709 return self.asm_token;
1710 }
1711
1712 pub fn lastToken(self: &NodeAsm) Token {
1713 return self.rparen;
1714 }
1715};
1716
1717pub const NodeUnreachable = struct {
1718 base: Node,
1719 token: Token,
1720
1721 pub fn iterate(self: &NodeUnreachable, index: usize) ?&Node {
1722 return null;
1723 }
1724
1725 pub fn firstToken(self: &NodeUnreachable) Token {
1726 return self.token;
1727 }
1728
1729 pub fn lastToken(self: &NodeUnreachable) Token {
1730 return self.token;
1731 }
1732};
1733
1734pub const NodeErrorType = struct {
1735 base: Node,
1736 token: Token,
1737
1738 pub fn iterate(self: &NodeErrorType, index: usize) ?&Node {
1739 return null;
1740 }
1741
1742 pub fn firstToken(self: &NodeErrorType) Token {
1743 return self.token;
1744 }
1745
1746 pub fn lastToken(self: &NodeErrorType) Token {
1747 return self.token;
1748 }
1749};
1750
1751pub const NodeVarType = struct {
1752 base: Node,
1753 token: Token,
1754
1755 pub fn iterate(self: &NodeVarType, index: usize) ?&Node {
1756 return null;
1757 }
1758
1759 pub fn firstToken(self: &NodeVarType) Token {
1760 return self.token;
1761 }
1762
1763 pub fn lastToken(self: &NodeVarType) Token {
1764 return self.token;
1765 }
1766};
1767
607pub const NodeLineComment = struct {1768pub const NodeLineComment = struct {
608 base: Node,1769 base: Node,
609 lines: ArrayList(Token),1770 lines: ArrayList(Token),
...@@ -624,7 +1785,7 @@ pub const NodeLineComment = struct {...@@ -624,7 +1785,7 @@ pub const NodeLineComment = struct {
624pub const NodeTestDecl = struct {1785pub const NodeTestDecl = struct {
625 base: Node,1786 base: Node,
626 test_token: Token,1787 test_token: Token,
627 name_token: Token,1788 name: &Node,
628 body_node: &Node,1789 body_node: &Node,
6291790
630 pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {1791 pub fn iterate(self: &NodeTestDecl, index: usize) ?&Node {
...@@ -644,4 +1805,3 @@ pub const NodeTestDecl = struct {...@@ -644,4 +1805,3 @@ pub const NodeTestDecl = struct {
644 return self.body_node.lastToken();1805 return self.body_node.lastToken();
645 }1806 }
646};1807};
647
std/zig/parser.zig+4222-748
...@@ -53,20 +53,33 @@ pub const Parser = struct {...@@ -53,20 +53,33 @@ pub const Parser = struct {
53 }53 }
5454
55 const TopLevelDeclCtx = struct {55 const TopLevelDeclCtx = struct {
56 decls: &ArrayList(&ast.Node),
56 visib_token: ?Token,57 visib_token: ?Token,
57 extern_token: ?Token,58 extern_export_inline_token: ?Token,
59 lib_name: ?&ast.Node,
60 };
61
62 const ContainerExternCtx = struct {
63 dest_ptr: DestPtr,
64 ltoken: Token,
65 layout: ast.NodeContainerDecl.Layout,
58 };66 };
5967
60 const DestPtr = union(enum) {68 const DestPtr = union(enum) {
61 Field: &&ast.Node,69 Field: &&ast.Node,
62 NullableField: &?&ast.Node,70 NullableField: &?&ast.Node,
63 List: &ArrayList(&ast.Node),
6471
65 pub fn store(self: &const DestPtr, value: &ast.Node) !void {72 pub fn store(self: &const DestPtr, value: &ast.Node) void {
66 switch (*self) {73 switch (*self) {
67 DestPtr.Field => |ptr| *ptr = value,74 DestPtr.Field => |ptr| *ptr = value,
68 DestPtr.NullableField => |ptr| *ptr = value,75 DestPtr.NullableField => |ptr| *ptr = value,
69 DestPtr.List => |list| try list.append(value),76 }
77 }
78
79 pub fn get(self: &const DestPtr) &ast.Node {
80 switch (*self) {
81 DestPtr.Field => |ptr| return *ptr,
82 DestPtr.NullableField => |ptr| return ??*ptr,
70 }83 }
71 }84 }
72 };85 };
...@@ -76,22 +89,70 @@ pub const Parser = struct {...@@ -76,22 +89,70 @@ pub const Parser = struct {
76 ptr: &Token,89 ptr: &Token,
77 };90 };
7891
92 const RevertState = struct {
93 parser: Parser,
94 tokenizer: Tokenizer,
95
96 // We expect, that if something is optional, then there is a field,
97 // that needs to be set to null, when we revert.
98 ptr: &?&ast.Node,
99 };
100
101 const ExprListCtx = struct {
102 list: &ArrayList(&ast.Node),
103 end: Token.Id,
104 ptr: &Token,
105 };
106
107 const ElseCtx = struct {
108 payload: ?DestPtr,
109 body: DestPtr,
110 };
111
112 fn ListSave(comptime T: type) type {
113 return struct {
114 list: &ArrayList(T),
115 ptr: &Token,
116 };
117 }
118
119 const LabelCtx = struct {
120 label: ?Token,
121 dest_ptr: DestPtr,
122 };
123
124 const InlineCtx = struct {
125 label: ?Token,
126 inline_token: ?Token,
127 dest_ptr: DestPtr,
128 };
129
130 const LoopCtx = struct {
131 label: ?Token,
132 inline_token: ?Token,
133 loop_token: Token,
134 dest_ptr: DestPtr,
135 };
136
137 const AsyncEndCtx = struct {
138 dest_ptr: DestPtr,
139 attribute: &ast.NodeAsyncAttribute,
140 };
141
79 const State = union(enum) {142 const State = union(enum) {
80 TopLevel,143 TopLevel,
81 TopLevelExtern: ?Token,144 TopLevelExtern: TopLevelDeclCtx,
145 TopLevelLibname: TopLevelDeclCtx,
82 TopLevelDecl: TopLevelDeclCtx,146 TopLevelDecl: TopLevelDeclCtx,
83 Expression: DestPtr,147 ContainerExtern: ContainerExternCtx,
84 ExpectOperand,148 ContainerDecl: &ast.NodeContainerDecl,
85 Operand: &ast.Node,149 SliceOrArrayAccess: &ast.NodeSuffixOp,
86 AfterOperand,
87 InfixOp: &ast.NodeInfixOp,
88 PrefixOp: &ast.NodePrefixOp,
89 SuffixOp: &ast.Node,
90 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,150 AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo,
91 TypeExpr: DestPtr,
92 VarDecl: &ast.NodeVarDecl,151 VarDecl: &ast.NodeVarDecl,
93 VarDeclAlign: &ast.NodeVarDecl,152 VarDeclAlign: &ast.NodeVarDecl,
94 VarDeclEq: &ast.NodeVarDecl,153 VarDeclEq: &ast.NodeVarDecl,
154 IfToken: @TagType(Token.Id),
155 IfTokenSave: ExpectTokenSave,
95 ExpectToken: @TagType(Token.Id),156 ExpectToken: @TagType(Token.Id),
96 ExpectTokenSave: ExpectTokenSave,157 ExpectTokenSave: ExpectTokenSave,
97 FnProto: &ast.NodeFnProto,158 FnProto: &ast.NodeFnProto,
...@@ -100,10 +161,75 @@ pub const Parser = struct {...@@ -100,10 +161,75 @@ pub const Parser = struct {
100 ParamDecl: &ast.NodeFnProto,161 ParamDecl: &ast.NodeFnProto,
101 ParamDeclComma,162 ParamDeclComma,
102 FnDef: &ast.NodeFnProto,163 FnDef: &ast.NodeFnProto,
164 LabeledExpression: LabelCtx,
165 Inline: InlineCtx,
166 While: LoopCtx,
167 For: LoopCtx,
103 Block: &ast.NodeBlock,168 Block: &ast.NodeBlock,
169 Else: &?&ast.NodeElse,
170 WhileContinueExpr: &?&ast.Node,
104 Statement: &ast.NodeBlock,171 Statement: &ast.NodeBlock,
105 ExprListItemOrEnd: &ArrayList(&ast.Node),172 Semicolon: &const &const ast.Node,
106 ExprListCommaOrEnd: &ArrayList(&ast.Node),173 AsmOutputItems: &ArrayList(&ast.NodeAsmOutput),
174 AsmInputItems: &ArrayList(&ast.NodeAsmInput),
175 AsmClopperItems: &ArrayList(&ast.Node),
176 ExprListItemOrEnd: ExprListCtx,
177 ExprListCommaOrEnd: ExprListCtx,
178 FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer),
179 FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer),
180 FieldListCommaOrEnd: &ast.NodeContainerDecl,
181 IdentifierListItemOrEnd: ListSave(&ast.NodeIdentifier),
182 IdentifierListCommaOrEnd: ListSave(&ast.NodeIdentifier),
183 SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase),
184 SuspendBody: &ast.NodeSuspend,
185 AsyncEnd: AsyncEndCtx,
186 Payload: &?&ast.NodePayload,
187 PointerPayload: &?&ast.NodePointerPayload,
188 PointerIndexPayload: &?&ast.NodePointerIndexPayload,
189 SwitchCaseCommaOrEnd: ListSave(&ast.NodeSwitchCase),
190 SwitchCaseItem: &ArrayList(&ast.Node),
191 SwitchCaseItemCommaOrEnd: &ArrayList(&ast.Node),
192
193 /// A state that can be appended before any other State. If an error occures,
194 /// the parser will first try looking for the closest optional state. If an
195 /// optional state is found, the parser will revert to the state it was in
196 /// when the optional was added. This will polute the arena allocator with
197 /// "leaked" nodes. TODO: Figure out if it's nessesary to handle leaked nodes.
198 Optional: RevertState,
199
200 Expression: DestPtr,
201 RangeExpressionBegin: DestPtr,
202 RangeExpressionEnd: DestPtr,
203 AssignmentExpressionBegin: DestPtr,
204 AssignmentExpressionEnd: DestPtr,
205 UnwrapExpressionBegin: DestPtr,
206 UnwrapExpressionEnd: DestPtr,
207 BoolOrExpressionBegin: DestPtr,
208 BoolOrExpressionEnd: DestPtr,
209 BoolAndExpressionBegin: DestPtr,
210 BoolAndExpressionEnd: DestPtr,
211 ComparisonExpressionBegin: DestPtr,
212 ComparisonExpressionEnd: DestPtr,
213 BinaryOrExpressionBegin: DestPtr,
214 BinaryOrExpressionEnd: DestPtr,
215 BinaryXorExpressionBegin: DestPtr,
216 BinaryXorExpressionEnd: DestPtr,
217 BinaryAndExpressionBegin: DestPtr,
218 BinaryAndExpressionEnd: DestPtr,
219 BitShiftExpressionBegin: DestPtr,
220 BitShiftExpressionEnd: DestPtr,
221 AdditionExpressionBegin: DestPtr,
222 AdditionExpressionEnd: DestPtr,
223 MultiplyExpressionBegin: DestPtr,
224 MultiplyExpressionEnd: DestPtr,
225 CurlySuffixExpressionBegin: DestPtr,
226 CurlySuffixExpressionEnd: DestPtr,
227 TypeExprBegin: DestPtr,
228 TypeExprEnd: DestPtr,
229 PrefixOpExpression: DestPtr,
230 SuffixOpExpressionBegin: DestPtr,
231 SuffixOpExpressionEnd: DestPtr,
232 PrimaryExpression: DestPtr,
107 };233 };
108234
109 /// Returns an AST tree, allocated with the parser's allocator.235 /// Returns an AST tree, allocated with the parser's allocator.
...@@ -117,7 +243,14 @@ pub const Parser = struct {...@@ -117,7 +243,14 @@ pub const Parser = struct {
117 errdefer arena_allocator.deinit();243 errdefer arena_allocator.deinit();
118244
119 const arena = &arena_allocator.allocator;245 const arena = &arena_allocator.allocator;
120 const root_node = try self.createRoot(arena);246 const root_node = try self.createNode(arena, ast.NodeRoot,
247 ast.NodeRoot {
248 .base = undefined,
249 .decls = ArrayList(&ast.Node).init(arena),
250 // initialized when we get the eof token
251 .eof_token = undefined,
252 }
253 );
121254
122 try stack.append(State.TopLevel);255 try stack.append(State.TopLevel);
123256
...@@ -136,8 +269,7 @@ pub const Parser = struct {...@@ -136,8 +269,7 @@ pub const Parser = struct {
136269
137 // look for line comments270 // look for line comments
138 while (true) {271 while (true) {
139 const token = self.getNextToken();272 if (self.eatToken(Token.Id.LineComment)) |line_comment| {
140 if (token.id == Token.Id.LineComment) {
141 const node = blk: {273 const node = blk: {
142 if (self.pending_line_comment_node) |comment_node| {274 if (self.pending_line_comment_node) |comment_node| {
143 break :blk comment_node;275 break :blk comment_node;
...@@ -154,10 +286,9 @@ pub const Parser = struct {...@@ -154,10 +286,9 @@ pub const Parser = struct {
154 break :blk comment_node;286 break :blk comment_node;
155 }287 }
156 };288 };
157 try node.lines.append(token);289 try node.lines.append(line_comment);
158 continue;290 continue;
159 }291 }
160 self.putBackToken(token);
161 break;292 break;
162 }293 }
163294
...@@ -168,104 +299,303 @@ pub const Parser = struct {...@@ -168,104 +299,303 @@ pub const Parser = struct {
168 State.TopLevel => {299 State.TopLevel => {
169 const token = self.getNextToken();300 const token = self.getNextToken();
170 switch (token.id) {301 switch (token.id) {
171 Token.Id.Keyword_pub, Token.Id.Keyword_export => {
172 stack.append(State { .TopLevelExtern = token }) catch unreachable;
173 continue;
174 },
175 Token.Id.Keyword_test => {302 Token.Id.Keyword_test => {
176 stack.append(State.TopLevel) catch unreachable;303 stack.append(State.TopLevel) catch unreachable;
177304
178 const name_token = self.getNextToken();305 const name_token = self.getNextToken();
179 if (name_token.id != Token.Id.StringLiteral)306 const name = (try self.parseStringLiteral(arena, name_token)) ?? {
180 return self.parseError(token, "expected {}, found {}", @tagName(Token.Id.StringLiteral), @tagName(name_token.id));307 try self.parseError(&stack, name_token, "expected string literal, found {}", @tagName(name_token.id));
181308 continue;
182 const lbrace = self.getNextToken();309 };
183 if (lbrace.id != Token.Id.LBrace)310 const lbrace = (try self.expectToken(&stack, Token.Id.LBrace)) ?? continue;
184 return self.parseError(token, "expected {}, found {}", @tagName(Token.Id.LBrace), @tagName(name_token.id));311
185312 const block = try self.createNode(arena, ast.NodeBlock,
186 const block = try self.createBlock(arena, token);313 ast.NodeBlock {
187 const test_decl = try self.createAttachTestDecl(arena, &root_node.decls, token, name_token, block);314 .base = undefined,
188 try stack.append(State { .Block = block });315 .label = null,
316 .lbrace = lbrace,
317 .statements = ArrayList(&ast.Node).init(arena),
318 .rbrace = undefined,
319 }
320 );
321 _ = try self.createAttachNode(arena, &root_node.decls, ast.NodeTestDecl,
322 ast.NodeTestDecl {
323 .base = undefined,
324 .test_token = token,
325 .name = name,
326 .body_node = &block.base,
327 }
328 );
329 stack.append(State { .Block = block }) catch unreachable;
189 continue;330 continue;
190 },331 },
191 Token.Id.Eof => {332 Token.Id.Eof => {
192 root_node.eof_token = token;333 root_node.eof_token = token;
193 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};334 return Tree {.root_node = root_node, .arena_allocator = arena_allocator};
194 },335 },
336 Token.Id.Keyword_pub => {
337 stack.append(State.TopLevel) catch unreachable;
338 try stack.append(State {
339 .TopLevelExtern = TopLevelDeclCtx {
340 .decls = &root_node.decls,
341 .visib_token = token,
342 .extern_export_inline_token = null,
343 .lib_name = null,
344 }
345 });
346 continue;
347 },
348 Token.Id.Keyword_comptime => {
349 const node = try self.createAttachNode(arena, &root_node.decls, ast.NodeComptime,
350 ast.NodeComptime {
351 .base = undefined,
352 .comptime_token = token,
353 .expr = undefined,
354 }
355 );
356 stack.append(State.TopLevel) catch unreachable;
357 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
358 continue;
359 },
195 else => {360 else => {
196 self.putBackToken(token);361 self.putBackToken(token);
197 stack.append(State { .TopLevelExtern = null }) catch unreachable;362 stack.append(State.TopLevel) catch unreachable;
363 try stack.append(State {
364 .TopLevelExtern = TopLevelDeclCtx {
365 .decls = &root_node.decls,
366 .visib_token = null,
367 .extern_export_inline_token = null,
368 .lib_name = null,
369 }
370 });
198 continue;371 continue;
199 },372 },
200 }373 }
201 },374 },
202 State.TopLevelExtern => |visib_token| {375 State.TopLevelExtern => |ctx| {
203 const token = self.getNextToken();376 const token = self.getNextToken();
204 if (token.id == Token.Id.Keyword_extern) {377 switch (token.id) {
205 stack.append(State {378 Token.Id.Keyword_export, Token.Id.Keyword_inline => {
206 .TopLevelDecl = TopLevelDeclCtx {379 stack.append(State {
207 .visib_token = visib_token,380 .TopLevelDecl = TopLevelDeclCtx {
208 .extern_token = token,381 .decls = ctx.decls,
209 },382 .visib_token = ctx.visib_token,
210 }) catch unreachable;383 .extern_export_inline_token = token,
211 continue;384 .lib_name = null,
385 },
386 }) catch unreachable;
387 continue;
388 },
389 Token.Id.Keyword_extern => {
390 stack.append(State {
391 .TopLevelLibname = TopLevelDeclCtx {
392 .decls = ctx.decls,
393 .visib_token = ctx.visib_token,
394 .extern_export_inline_token = token,
395 .lib_name = null,
396 },
397 }) catch unreachable;
398 continue;
399 },
400 else => {
401 self.putBackToken(token);
402 stack.append(State { .TopLevelDecl = ctx }) catch unreachable;
403 continue;
404 }
212 }405 }
213 self.putBackToken(token);406 },
407
408 State.TopLevelLibname => |ctx| {
409 const lib_name = blk: {
410 const lib_name_token = self.getNextToken();
411 break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? {
412 self.putBackToken(lib_name_token);
413 break :blk null;
414 };
415 };
416
214 stack.append(State {417 stack.append(State {
215 .TopLevelDecl = TopLevelDeclCtx {418 .TopLevelDecl = TopLevelDeclCtx {
216 .visib_token = visib_token,419 .decls = ctx.decls,
217 .extern_token = null,420 .visib_token = ctx.visib_token,
421 .extern_export_inline_token = ctx.extern_export_inline_token,
422 .lib_name = lib_name,
218 },423 },
219 }) catch unreachable;424 }) catch unreachable;
220 continue;
221 },425 },
426
222 State.TopLevelDecl => |ctx| {427 State.TopLevelDecl => |ctx| {
223 const token = self.getNextToken();428 const token = self.getNextToken();
224 switch (token.id) {429 switch (token.id) {
430 Token.Id.Keyword_use => {
431 if (ctx.extern_export_inline_token != null) {
432 try self.parseError(&stack, token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id));
433 continue;
434 }
435
436 const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse,
437 ast.NodeUse {
438 .base = undefined,
439 .visib_token = ctx.visib_token,
440 .expr = undefined,
441 .semicolon_token = undefined,
442 }
443 );
444 stack.append(State {
445 .ExpectTokenSave = ExpectTokenSave {
446 .id = Token.Id.Semicolon,
447 .ptr = &node.semicolon_token,
448 }
449 }) catch unreachable;
450 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
451 continue;
452 },
225 Token.Id.Keyword_var, Token.Id.Keyword_const => {453 Token.Id.Keyword_var, Token.Id.Keyword_const => {
226 stack.append(State.TopLevel) catch unreachable;454 if (ctx.extern_export_inline_token) |extern_export_inline_token| {
227 // TODO shouldn't need these casts455 if (extern_export_inline_token.id == Token.Id.Keyword_inline) {
228 const var_decl_node = try self.createAttachVarDecl(arena, &root_node.decls, ctx.visib_token,456 try self.parseError(&stack, token, "Invalid token {}", @tagName(extern_export_inline_token.id));
229 token, (?Token)(null), ctx.extern_token);457 continue;
230 try stack.append(State { .VarDecl = var_decl_node });458 }
459 }
460
461 const var_decl_node = try self.createAttachNode(arena, ctx.decls, ast.NodeVarDecl,
462 ast.NodeVarDecl {
463 .base = undefined,
464 .visib_token = ctx.visib_token,
465 .mut_token = token,
466 .comptime_token = null,
467 .extern_export_token = ctx.extern_export_inline_token,
468 .type_node = null,
469 .align_node = null,
470 .init_node = null,
471 .lib_name = ctx.lib_name,
472 // initialized later
473 .name_token = undefined,
474 .eq_token = undefined,
475 .semicolon_token = undefined,
476 }
477 );
478 stack.append(State { .VarDecl = var_decl_node }) catch unreachable;
231 continue;479 continue;
232 },480 },
233 Token.Id.Keyword_fn => {481 Token.Id.Keyword_fn => {
234 stack.append(State.TopLevel) catch unreachable;482 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
235 // TODO shouldn't need these casts483 ast.NodeFnProto {
236 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, token,484 .base = undefined,
237 ctx.extern_token, (?Token)(null), ctx.visib_token, (?Token)(null));485 .visib_token = ctx.visib_token,
238 try stack.append(State { .FnDef = fn_proto });486 .name_token = null,
487 .fn_token = token,
488 .params = ArrayList(&ast.Node).init(arena),
489 .return_type = undefined,
490 .var_args_token = null,
491 .extern_export_inline_token = ctx.extern_export_inline_token,
492 .cc_token = null,
493 .async_attr = null,
494 .body_node = null,
495 .lib_name = ctx.lib_name,
496 .align_expr = null,
497 }
498 );
499 stack.append(State { .FnDef = fn_proto }) catch unreachable;
239 try stack.append(State { .FnProto = fn_proto });500 try stack.append(State { .FnProto = fn_proto });
240 continue;501 continue;
241 },502 },
242 Token.Id.StringLiteral => {
243 @panic("TODO extern with string literal");
244 },
245 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {503 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
246 stack.append(State.TopLevel) catch unreachable;504 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
247 const fn_token = try self.eatToken(Token.Id.Keyword_fn);505 ast.NodeFnProto {
248 // TODO shouldn't need this cast506 .base = undefined,
249 const fn_proto = try self.createAttachFnProto(arena, &root_node.decls, fn_token,507 .visib_token = ctx.visib_token,
250 ctx.extern_token, (?Token)(token), (?Token)(null), (?Token)(null));508 .name_token = null,
251 try stack.append(State { .FnDef = fn_proto });509 .fn_token = undefined,
510 .params = ArrayList(&ast.Node).init(arena),
511 .return_type = undefined,
512 .var_args_token = null,
513 .extern_export_inline_token = ctx.extern_export_inline_token,
514 .cc_token = token,
515 .async_attr = null,
516 .body_node = null,
517 .lib_name = ctx.lib_name,
518 .align_expr = null,
519 }
520 );
521 stack.append(State { .FnDef = fn_proto }) catch unreachable;
522 try stack.append(State { .FnProto = fn_proto });
523 try stack.append(State {
524 .ExpectTokenSave = ExpectTokenSave {
525 .id = Token.Id.Keyword_fn,
526 .ptr = &fn_proto.fn_token,
527 }
528 });
529 continue;
530 },
531 Token.Id.Keyword_async => {
532 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
533 ast.NodeAsyncAttribute {
534 .base = undefined,
535 .async_token = token,
536 .allocator_type = null,
537 .rangle_bracket = null,
538 }
539 );
540
541 const fn_proto = try self.createAttachNode(arena, ctx.decls, ast.NodeFnProto,
542 ast.NodeFnProto {
543 .base = undefined,
544 .visib_token = ctx.visib_token,
545 .name_token = null,
546 .fn_token = undefined,
547 .params = ArrayList(&ast.Node).init(arena),
548 .return_type = undefined,
549 .var_args_token = null,
550 .extern_export_inline_token = ctx.extern_export_inline_token,
551 .cc_token = null,
552 .async_attr = async_node,
553 .body_node = null,
554 .lib_name = ctx.lib_name,
555 .align_expr = null,
556 }
557 );
558 stack.append(State { .FnDef = fn_proto }) catch unreachable;
252 try stack.append(State { .FnProto = fn_proto });559 try stack.append(State { .FnProto = fn_proto });
560 try stack.append(State {
561 .ExpectTokenSave = ExpectTokenSave {
562 .id = Token.Id.Keyword_fn,
563 .ptr = &fn_proto.fn_token,
564 }
565 });
566
567 const langle_bracket = self.getNextToken();
568 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
569 self.putBackToken(langle_bracket);
570 continue;
571 }
572
573 async_node.rangle_bracket = Token(undefined);
574 try stack.append(State {
575 .ExpectTokenSave = ExpectTokenSave {
576 .id = Token.Id.AngleBracketRight,
577 .ptr = &??async_node.rangle_bracket,
578 }
579 });
580 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
581 continue;
582 },
583 else => {
584 try self.parseError(&stack, token, "expected variable declaration or function, found {}", @tagName(token.id));
253 continue;585 continue;
254 },586 },
255 else => return self.parseError(token, "expected variable declaration or function, found {}", @tagName(token.id)),
256 }587 }
257 },588 },
258 State.VarDecl => |var_decl| {589 State.VarDecl => |var_decl| {
259 var_decl.name_token = try self.eatToken(Token.Id.Identifier);
260 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;590 stack.append(State { .VarDeclAlign = var_decl }) catch unreachable;
261591 try stack.append(State { .TypeExprBegin = DestPtr {.NullableField = &var_decl.type_node} });
262 const next_token = self.getNextToken();592 try stack.append(State { .IfToken = Token.Id.Colon });
263 if (next_token.id == Token.Id.Colon) {593 try stack.append(State {
264 try stack.append(State { .TypeExpr = DestPtr {.NullableField = &var_decl.type_node} });594 .ExpectTokenSave = ExpectTokenSave {
265 continue;595 .id = Token.Id.Identifier,
266 }596 .ptr = &var_decl.name_token,
267597 }
268 self.putBackToken(next_token);598 });
269 continue;599 continue;
270 },600 },
271 State.VarDeclAlign => |var_decl| {601 State.VarDeclAlign => |var_decl| {
...@@ -273,9 +603,9 @@ pub const Parser = struct {...@@ -273,9 +603,9 @@ pub const Parser = struct {
273603
274 const next_token = self.getNextToken();604 const next_token = self.getNextToken();
275 if (next_token.id == Token.Id.Keyword_align) {605 if (next_token.id == Token.Id.Keyword_align) {
276 _ = try self.eatToken(Token.Id.LParen);
277 try stack.append(State { .ExpectToken = Token.Id.RParen });606 try stack.append(State { .ExpectToken = Token.Id.RParen });
278 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });607 try stack.append(State { .Expression = DestPtr{.NullableField = &var_decl.align_node} });
608 try stack.append(State { .ExpectToken = Token.Id.LParen });
279 continue;609 continue;
280 }610 }
281611
...@@ -283,261 +613,1667 @@ pub const Parser = struct {...@@ -283,261 +613,1667 @@ pub const Parser = struct {
283 continue;613 continue;
284 },614 },
285 State.VarDeclEq => |var_decl| {615 State.VarDeclEq => |var_decl| {
286 const token = self.getNextToken();
287 if (token.id == Token.Id.Equal) {
288 var_decl.eq_token = token;
289 stack.append(State {
290 .ExpectTokenSave = ExpectTokenSave {
291 .id = Token.Id.Semicolon,
292 .ptr = &var_decl.semicolon_token,
293 },
294 }) catch unreachable;
295 try stack.append(State {
296 .Expression = DestPtr {.NullableField = &var_decl.init_node},
297 });
298 continue;
299 }
300 if (token.id == Token.Id.Semicolon) {
301 var_decl.semicolon_token = token;
302 continue;
303 }
304 return self.parseError(token, "expected '=' or ';', found {}", @tagName(token.id));
305 },
306 State.ExpectToken => |token_id| {
307 _ = try self.eatToken(token_id);
308 continue;
309 },
310
311 State.ExpectTokenSave => |expect_token_save| {
312 *expect_token_save.ptr = try self.eatToken(expect_token_save.id);
313 continue;
314 },
315
316 State.Expression => |dest_ptr| {
317 // save the dest_ptr for later
318 stack.append(state) catch unreachable;
319 try stack.append(State.ExpectOperand);
320 continue;
321 },
322 State.ExpectOperand => {
323 // we'll either get an operand (like 1 or x),
324 // or a prefix operator (like ~ or return).
325 const token = self.getNextToken();616 const token = self.getNextToken();
326 switch (token.id) {617 switch (token.id) {
327 Token.Id.Keyword_return => {618 Token.Id.Equal => {
328 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,619 var_decl.eq_token = token;
329 ast.NodePrefixOp.PrefixOp.Return) });620 stack.append(State {
330 try stack.append(State.ExpectOperand);621 .ExpectTokenSave = ExpectTokenSave {
331 continue;622 .id = Token.Id.Semicolon,
332 },623 .ptr = &var_decl.semicolon_token,
333 Token.Id.Keyword_try => {624 },
334 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,625 }) catch unreachable;
335 ast.NodePrefixOp.PrefixOp.Try) });626 try stack.append(State { .Expression = DestPtr {.NullableField = &var_decl.init_node} });
336 try stack.append(State.ExpectOperand);
337 continue;
338 },
339 Token.Id.Minus => {
340 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,
341 ast.NodePrefixOp.PrefixOp.Negation) });
342 try stack.append(State.ExpectOperand);
343 continue;
344 },
345 Token.Id.MinusPercent => {
346 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,
347 ast.NodePrefixOp.PrefixOp.NegationWrap) });
348 try stack.append(State.ExpectOperand);
349 continue;
350 },
351 Token.Id.Tilde => {
352 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,
353 ast.NodePrefixOp.PrefixOp.BitNot) });
354 try stack.append(State.ExpectOperand);
355 continue;
356 },
357 Token.Id.QuestionMarkQuestionMark => {
358 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,
359 ast.NodePrefixOp.PrefixOp.UnwrapMaybe) });
360 try stack.append(State.ExpectOperand);
361 continue;627 continue;
362 },628 },
363 Token.Id.Bang => {629 Token.Id.Semicolon => {
364 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,630 var_decl.semicolon_token = token;
365 ast.NodePrefixOp.PrefixOp.BoolNot) });
366 try stack.append(State.ExpectOperand);
367 continue;631 continue;
368 },632 },
369 Token.Id.Asterisk => {633 else => {
370 try stack.append(State { .PrefixOp = try self.createPrefixOp(arena, token,634 try self.parseError(&stack, token, "expected '=' or ';', found {}", @tagName(token.id));
371 ast.NodePrefixOp.PrefixOp.Deref) });
372 try stack.append(State.ExpectOperand);
373 continue;635 continue;
636 }
637 }
638 },
639
640 State.ContainerExtern => |ctx| {
641 const token = self.getNextToken();
642 const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeContainerDecl,
643 ast.NodeContainerDecl {
644 .base = undefined,
645 .ltoken = ctx.ltoken,
646 .layout = ctx.layout,
647 .kind = switch (token.id) {
648 Token.Id.Keyword_struct => ast.NodeContainerDecl.Kind.Struct,
649 Token.Id.Keyword_union => ast.NodeContainerDecl.Kind.Union,
650 Token.Id.Keyword_enum => ast.NodeContainerDecl.Kind.Enum,
651 else => {
652 try self.parseError(&stack, token, "expected {}, {} or {}, found {}",
653 @tagName(Token.Id.Keyword_struct),
654 @tagName(Token.Id.Keyword_union),
655 @tagName(Token.Id.Keyword_enum),
656 @tagName(token.id));
657 continue;
658 },
659 },
660 .init_arg_expr = undefined,
661 .fields_and_decls = ArrayList(&ast.Node).init(arena),
662 .rbrace_token = undefined,
663 }
664 );
665
666 stack.append(State { .ContainerDecl = node }) catch unreachable;
667 try stack.append(State { .ExpectToken = Token.Id.LBrace });
668
669 const lparen = self.getNextToken();
670 if (lparen.id != Token.Id.LParen) {
671 self.putBackToken(lparen);
672 node.init_arg_expr = ast.NodeContainerDecl.InitArg.None;
673 continue;
674 }
675
676 try stack.append(State { .ExpectToken = Token.Id.RParen });
677
678 const init_arg_token = self.getNextToken();
679 switch (init_arg_token.id) {
680 Token.Id.Keyword_enum => {
681 node.init_arg_expr = ast.NodeContainerDecl.InitArg.Enum;
374 },682 },
375 Token.Id.Ampersand => {683 else => {
376 const prefix_op = try self.createPrefixOp(arena, token, ast.NodePrefixOp.PrefixOp{684 self.putBackToken(init_arg_token);
377 .AddrOf = ast.NodePrefixOp.AddrOfInfo {685 node.init_arg_expr = ast.NodeContainerDecl.InitArg { .Type = undefined };
378 .align_expr = null,686 try stack.append(State {
379 .bit_offset_start_token = null,687 .Expression = DestPtr {
380 .bit_offset_end_token = null,688 .Field = &node.init_arg_expr.Type
381 .const_token = null,
382 .volatile_token = null,
383 }689 }
384 });690 });
385 try stack.append(State { .PrefixOp = prefix_op });
386 try stack.append(State.ExpectOperand);
387 try stack.append(State { .AddrOfModifiers = &prefix_op.op.AddrOf });
388 continue;
389 },691 },
692 }
693 continue;
694 },
695
696 State.ContainerDecl => |container_decl| {
697 const token = self.getNextToken();
698
699 switch (token.id) {
390 Token.Id.Identifier => {700 Token.Id.Identifier => {
391 try stack.append(State {701 switch (container_decl.kind) {
392 .Operand = &(try self.createIdentifier(arena, token)).base702 ast.NodeContainerDecl.Kind.Struct => {
393 });703 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
394 try stack.append(State.AfterOperand);704 ast.NodeStructField {
395 continue;705 .base = undefined,
396 },706 .visib_token = null,
397 Token.Id.IntegerLiteral => {707 .name_token = token,
398 try stack.append(State {708 .type_expr = undefined,
399 .Operand = &(try self.createIntegerLiteral(arena, token)).base709 }
400 });710 );
401 try stack.append(State.AfterOperand);711
402 continue;712 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
713 try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
714 try stack.append(State { .ExpectToken = Token.Id.Colon });
715 continue;
716 },
717 ast.NodeContainerDecl.Kind.Union => {
718 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeUnionTag,
719 ast.NodeUnionTag {
720 .base = undefined,
721 .name_token = token,
722 .type_expr = null,
723 }
724 );
725
726 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
727
728 const next = self.getNextToken();
729 if (next.id != Token.Id.Colon) {
730 self.putBackToken(next);
731 continue;
732 }
733
734 try stack.append(State { .Expression = DestPtr { .NullableField = &node.type_expr } });
735 continue;
736 },
737 ast.NodeContainerDecl.Kind.Enum => {
738 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeEnumTag,
739 ast.NodeEnumTag {
740 .base = undefined,
741 .name_token = token,
742 .value = null,
743 }
744 );
745
746 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
747
748 const next = self.getNextToken();
749 if (next.id != Token.Id.Equal) {
750 self.putBackToken(next);
751 continue;
752 }
753
754 try stack.append(State { .Expression = DestPtr { .NullableField = &node.value } });
755 continue;
756 },
757 }
403 },758 },
404 Token.Id.FloatLiteral => {759 Token.Id.Keyword_pub => {
760 if (self.eatToken(Token.Id.Identifier)) |identifier| {
761 switch (container_decl.kind) {
762 ast.NodeContainerDecl.Kind.Struct => {
763 const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField,
764 ast.NodeStructField {
765 .base = undefined,
766 .visib_token = token,
767 .name_token = identifier,
768 .type_expr = undefined,
769 }
770 );
771
772 stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable;
773 try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } });
774 try stack.append(State { .ExpectToken = Token.Id.Colon });
775 continue;
776 },
777 else => {
778 self.putBackToken(identifier);
779 }
780 }
781 }
782
783 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
405 try stack.append(State {784 try stack.append(State {
406 .Operand = &(try self.createFloatLiteral(arena, token)).base785 .TopLevelExtern = TopLevelDeclCtx {
786 .decls = &container_decl.fields_and_decls,
787 .visib_token = token,
788 .extern_export_inline_token = null,
789 .lib_name = null,
790 }
407 });791 });
408 try stack.append(State.AfterOperand);
409 continue;792 continue;
410 },793 },
411 Token.Id.Keyword_undefined => {794 Token.Id.Keyword_export => {
795 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
412 try stack.append(State {796 try stack.append(State {
413 .Operand = &(try self.createUndefined(arena, token)).base797 .TopLevelExtern = TopLevelDeclCtx {
798 .decls = &container_decl.fields_and_decls,
799 .visib_token = token,
800 .extern_export_inline_token = null,
801 .lib_name = null,
802 }
414 });803 });
415 try stack.append(State.AfterOperand);
416 continue;804 continue;
417 },805 },
418 Token.Id.Builtin => {806 Token.Id.RBrace => {
419 const node = try arena.create(ast.NodeBuiltinCall);807 container_decl.rbrace_token = token;
420 *node = ast.NodeBuiltinCall {
421 .base = self.initNode(ast.Node.Id.BuiltinCall),
422 .builtin_token = token,
423 .params = ArrayList(&ast.Node).init(arena),
424 .rparen_token = undefined,
425 };
426 try stack.append(State {
427 .Operand = &node.base
428 });
429 try stack.append(State.AfterOperand);
430 try stack.append(State {.ExprListItemOrEnd = &node.params });
431 try stack.append(State {
432 .ExpectTokenSave = ExpectTokenSave {
433 .id = Token.Id.LParen,
434 .ptr = &node.rparen_token,
435 },
436 });
437 continue;808 continue;
438 },809 },
439 Token.Id.StringLiteral => {810 else => {
440 const node = try arena.create(ast.NodeStringLiteral);811 self.putBackToken(token);
441 *node = ast.NodeStringLiteral {812 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
442 .base = self.initNode(ast.Node.Id.StringLiteral),
443 .token = token,
444 };
445 try stack.append(State {813 try stack.append(State {
446 .Operand = &node.base814 .TopLevelExtern = TopLevelDeclCtx {
815 .decls = &container_decl.fields_and_decls,
816 .visib_token = null,
817 .extern_export_inline_token = null,
818 .lib_name = null,
819 }
447 });820 });
448 try stack.append(State.AfterOperand);
449 continue;821 continue;
450 },822 }
451
452 else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)),
453 }823 }
454 },824 },
455825
456 State.AfterOperand => {826 State.ExpectToken => |token_id| {
457 // we'll either get an infix operator (like != or ^),827 _ = (try self.expectToken(&stack, token_id)) ?? continue;
458 // or a postfix operator (like () or {}),828 continue;
459 // otherwise this expression is done (like on a ; or else).829 },
460 var token = self.getNextToken();
461 if (tokenIdToInfixOp(token.id)) |infix_id| {
462 try stack.append(State {
463 .InfixOp = try self.createInfixOp(arena, token, infix_id)
464 });
465 try stack.append(State.ExpectOperand);
466 continue;
467
468 } else if (token.id == Token.Id.LParen) {
469 self.putBackToken(token);
470830
471 const node = try arena.create(ast.NodeCall);831 State.ExpectTokenSave => |expect_token_save| {
472 *node = ast.NodeCall {832 *expect_token_save.ptr = (try self.expectToken(&stack, expect_token_save.id)) ?? continue;
473 .base = self.initNode(ast.Node.Id.Call),833 continue;
474 .callee = undefined,834 },
475 .params = ArrayList(&ast.Node).init(arena),835
476 .rparen_token = undefined,836 State.IfToken => |token_id| {
477 };837 const token = self.getNextToken();
478 try stack.append(State { .SuffixOp = &node.base });838 if (@TagType(Token.Id)(token.id) != token_id) {
479 try stack.append(State.AfterOperand);839 self.putBackToken(token);
480 try stack.append(State {.ExprListItemOrEnd = &node.params });840 _ = stack.pop();
841 continue;
842 }
843 continue;
844 },
845
846 State.IfTokenSave => |if_token_save| {
847 const token = self.getNextToken();
848 if (@TagType(Token.Id)(token.id) != if_token_save.id) {
849 self.putBackToken(token);
850 _ = stack.pop();
851 continue;
852 }
853
854 *if_token_save.ptr = token;
855 continue;
856 },
857
858 State.Optional => { },
859
860 State.Expression => |dest_ptr| {
861 const token = self.getNextToken();
862 switch (token.id) {
863 Token.Id.Keyword_return => {
864 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeControlFlowExpression,
865 ast.NodeControlFlowExpression {
866 .base = undefined,
867 .ltoken = token,
868 .kind = ast.NodeControlFlowExpression.Kind.Return,
869 .rhs = undefined,
870 }
871 );
872
873 // TODO: Find another way to do optional expressions
874 stack.append(State {
875 .Optional = RevertState {
876 .parser = *self,
877 .tokenizer = *self.tokenizer,
878 .ptr = &node.rhs,
879 }
880 }) catch unreachable;
881 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
882 continue;
883 },
884 Token.Id.Keyword_break, Token.Id.Keyword_continue => {
885 const label = blk: {
886 const colon = self.getNextToken();
887 if (colon.id != Token.Id.Colon) {
888 self.putBackToken(colon);
889 break :blk null;
890 }
891
892 break :blk (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
893 };
894
895 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeControlFlowExpression,
896 ast.NodeControlFlowExpression {
897 .base = undefined,
898 .ltoken = token,
899 .kind = switch (token.id) {
900 Token.Id.Keyword_break => ast.NodeControlFlowExpression.Kind { .Break = label },
901 Token.Id.Keyword_continue => ast.NodeControlFlowExpression.Kind { .Continue = label },
902 else => unreachable,
903 },
904 .rhs = undefined,
905 }
906 );
907
908 // TODO: Find another way to do optional expressions
909 stack.append(State {
910 .Optional = RevertState {
911 .parser = *self,
912 .tokenizer = *self.tokenizer,
913 .ptr = &node.rhs,
914 }
915 }) catch unreachable;
916 try stack.append(State { .Expression = DestPtr { .NullableField = &node.rhs } });
917 continue;
918 },
919 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
920 const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
921 ast.NodePrefixOp {
922 .base = undefined,
923 .op_token = token,
924 .op = switch (token.id) {
925 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{} },
926 Token.Id.Keyword_cancel => ast.NodePrefixOp.PrefixOp { .Cancel = void{} },
927 Token.Id.Keyword_resume => ast.NodePrefixOp.PrefixOp { .Resume = void{} },
928 else => unreachable,
929 },
930 .rhs = undefined,
931 }
932 );
933
934 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
935 continue;
936 },
937 else => {
938 if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
939 self.putBackToken(token);
940 stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable;
941 }
942 continue;
943 }
944 }
945 },
946
947 State.RangeExpressionBegin => |dest_ptr| {
948 stack.append(State { .RangeExpressionEnd = dest_ptr }) catch unreachable;
949 try stack.append(State { .Expression = dest_ptr });
950 continue;
951 },
952
953 State.RangeExpressionEnd => |dest_ptr| {
954 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
955 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
956 ast.NodeInfixOp {
957 .base = undefined,
958 .lhs = dest_ptr.get(),
959 .op_token = ellipsis3,
960 .op = ast.NodeInfixOp.InfixOp.Range,
961 .rhs = undefined,
962 }
963 );
964 stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable;
965 }
966
967 continue;
968 },
969
970 State.AssignmentExpressionBegin => |dest_ptr| {
971 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
972 try stack.append(State { .Expression = dest_ptr });
973 continue;
974 },
975
976 State.AssignmentExpressionEnd => |dest_ptr| {
977 const token = self.getNextToken();
978 if (tokenIdToAssignment(token.id)) |ass_id| {
979 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
980 ast.NodeInfixOp {
981 .base = undefined,
982 .lhs = dest_ptr.get(),
983 .op_token = token,
984 .op = ass_id,
985 .rhs = undefined,
986 }
987 );
988 stack.append(State { .AssignmentExpressionEnd = dest_ptr }) catch unreachable;
989 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
990 continue;
991 } else {
992 self.putBackToken(token);
993 continue;
994 }
995 },
996
997 State.UnwrapExpressionBegin => |dest_ptr| {
998 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
999 try stack.append(State { .BoolOrExpressionBegin = dest_ptr });
1000 continue;
1001 },
1002
1003 State.UnwrapExpressionEnd => |dest_ptr| {
1004 const token = self.getNextToken();
1005 switch (token.id) {
1006 Token.Id.Keyword_catch, Token.Id.QuestionMarkQuestionMark => {
1007 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1008 ast.NodeInfixOp {
1009 .base = undefined,
1010 .lhs = dest_ptr.get(),
1011 .op_token = token,
1012 .op = switch (token.id) {
1013 Token.Id.Keyword_catch => ast.NodeInfixOp.InfixOp { .Catch = null },
1014 Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp { .UnwrapMaybe = void{} },
1015 else => unreachable,
1016 },
1017 .rhs = undefined,
1018 }
1019 );
1020
1021 stack.append(State { .UnwrapExpressionEnd = dest_ptr }) catch unreachable;
1022 try stack.append(State { .Expression = DestPtr { .Field = &node.rhs } });
1023
1024 if (node.op == ast.NodeInfixOp.InfixOp.Catch) {
1025 try stack.append(State { .Payload = &node.op.Catch });
1026 }
1027 continue;
1028 },
1029 else => {
1030 self.putBackToken(token);
1031 continue;
1032 },
1033 }
1034 },
1035
1036 State.BoolOrExpressionBegin => |dest_ptr| {
1037 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
1038 try stack.append(State { .BoolAndExpressionBegin = dest_ptr });
1039 continue;
1040 },
1041
1042 State.BoolOrExpressionEnd => |dest_ptr| {
1043 const token = self.getNextToken();
1044 switch (token.id) {
1045 Token.Id.Keyword_or => {
1046 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1047 ast.NodeInfixOp {
1048 .base = undefined,
1049 .lhs = dest_ptr.get(),
1050 .op_token = token,
1051 .op = ast.NodeInfixOp.InfixOp.BoolOr,
1052 .rhs = undefined,
1053 }
1054 );
1055 stack.append(State { .BoolOrExpressionEnd = dest_ptr }) catch unreachable;
1056 try stack.append(State { .BoolAndExpressionBegin = DestPtr { .Field = &node.rhs } });
1057 continue;
1058 },
1059 else => {
1060 self.putBackToken(token);
1061 continue;
1062 },
1063 }
1064 },
1065
1066 State.BoolAndExpressionBegin => |dest_ptr| {
1067 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1068 try stack.append(State { .ComparisonExpressionBegin = dest_ptr });
1069 continue;
1070 },
1071
1072 State.BoolAndExpressionEnd => |dest_ptr| {
1073 const token = self.getNextToken();
1074 switch (token.id) {
1075 Token.Id.Keyword_and => {
1076 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1077 ast.NodeInfixOp {
1078 .base = undefined,
1079 .lhs = dest_ptr.get(),
1080 .op_token = token,
1081 .op = ast.NodeInfixOp.InfixOp.BoolAnd,
1082 .rhs = undefined,
1083 }
1084 );
1085 stack.append(State { .BoolAndExpressionEnd = dest_ptr }) catch unreachable;
1086 try stack.append(State { .ComparisonExpressionBegin = DestPtr { .Field = &node.rhs } });
1087 continue;
1088 },
1089 else => {
1090 self.putBackToken(token);
1091 continue;
1092 },
1093 }
1094 },
1095
1096 State.ComparisonExpressionBegin => |dest_ptr| {
1097 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1098 try stack.append(State { .BinaryOrExpressionBegin = dest_ptr });
1099 continue;
1100 },
1101
1102 State.ComparisonExpressionEnd => |dest_ptr| {
1103 const token = self.getNextToken();
1104 if (tokenIdToComparison(token.id)) |comp_id| {
1105 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1106 ast.NodeInfixOp {
1107 .base = undefined,
1108 .lhs = dest_ptr.get(),
1109 .op_token = token,
1110 .op = comp_id,
1111 .rhs = undefined,
1112 }
1113 );
1114 stack.append(State { .ComparisonExpressionEnd = dest_ptr }) catch unreachable;
1115 try stack.append(State { .BinaryOrExpressionBegin = DestPtr { .Field = &node.rhs } });
1116 continue;
1117 } else {
1118 self.putBackToken(token);
1119 continue;
1120 }
1121 },
1122
1123 State.BinaryOrExpressionBegin => |dest_ptr| {
1124 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1125 try stack.append(State { .BinaryXorExpressionBegin = dest_ptr });
1126 continue;
1127 },
1128
1129 State.BinaryOrExpressionEnd => |dest_ptr| {
1130 const token = self.getNextToken();
1131 switch (token.id) {
1132 Token.Id.Pipe => {
1133 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1134 ast.NodeInfixOp {
1135 .base = undefined,
1136 .lhs = dest_ptr.get(),
1137 .op_token = token,
1138 .op = ast.NodeInfixOp.InfixOp.BitOr,
1139 .rhs = undefined,
1140 }
1141 );
1142 stack.append(State { .BinaryOrExpressionEnd = dest_ptr }) catch unreachable;
1143 try stack.append(State { .BinaryXorExpressionBegin = DestPtr { .Field = &node.rhs } });
1144 continue;
1145 },
1146 else => {
1147 self.putBackToken(token);
1148 continue;
1149 },
1150 }
1151 },
1152
1153 State.BinaryXorExpressionBegin => |dest_ptr| {
1154 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1155 try stack.append(State { .BinaryAndExpressionBegin = dest_ptr });
1156 continue;
1157 },
1158
1159 State.BinaryXorExpressionEnd => |dest_ptr| {
1160 const token = self.getNextToken();
1161 switch (token.id) {
1162 Token.Id.Caret => {
1163 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1164 ast.NodeInfixOp {
1165 .base = undefined,
1166 .lhs = dest_ptr.get(),
1167 .op_token = token,
1168 .op = ast.NodeInfixOp.InfixOp.BitXor,
1169 .rhs = undefined,
1170 }
1171 );
1172 stack.append(State { .BinaryXorExpressionEnd = dest_ptr }) catch unreachable;
1173 try stack.append(State { .BinaryAndExpressionBegin = DestPtr { .Field = &node.rhs } });
1174 continue;
1175 },
1176 else => {
1177 self.putBackToken(token);
1178 continue;
1179 },
1180 }
1181 },
1182
1183 State.BinaryAndExpressionBegin => |dest_ptr| {
1184 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1185 try stack.append(State { .BitShiftExpressionBegin = dest_ptr });
1186 continue;
1187 },
1188
1189 State.BinaryAndExpressionEnd => |dest_ptr| {
1190 const token = self.getNextToken();
1191 switch (token.id) {
1192 Token.Id.Ampersand => {
1193 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1194 ast.NodeInfixOp {
1195 .base = undefined,
1196 .lhs = dest_ptr.get(),
1197 .op_token = token,
1198 .op = ast.NodeInfixOp.InfixOp.BitAnd,
1199 .rhs = undefined,
1200 }
1201 );
1202 stack.append(State { .BinaryAndExpressionEnd = dest_ptr }) catch unreachable;
1203 try stack.append(State { .BitShiftExpressionBegin = DestPtr { .Field = &node.rhs } });
1204 continue;
1205 },
1206 else => {
1207 self.putBackToken(token);
1208 continue;
1209 },
1210 }
1211 },
1212
1213 State.BitShiftExpressionBegin => |dest_ptr| {
1214 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
1215 try stack.append(State { .AdditionExpressionBegin = dest_ptr });
1216 continue;
1217 },
1218
1219 State.BitShiftExpressionEnd => |dest_ptr| {
1220 const token = self.getNextToken();
1221 if (tokenIdToBitShift(token.id)) |bitshift_id| {
1222 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1223 ast.NodeInfixOp {
1224 .base = undefined,
1225 .lhs = dest_ptr.get(),
1226 .op_token = token,
1227 .op = bitshift_id,
1228 .rhs = undefined,
1229 }
1230 );
1231 stack.append(State { .BitShiftExpressionEnd = dest_ptr }) catch unreachable;
1232 try stack.append(State { .AdditionExpressionBegin = DestPtr { .Field = &node.rhs } });
1233 continue;
1234 } else {
1235 self.putBackToken(token);
1236 continue;
1237 }
1238 },
1239
1240 State.AdditionExpressionBegin => |dest_ptr| {
1241 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1242 try stack.append(State { .MultiplyExpressionBegin = dest_ptr });
1243 continue;
1244 },
1245
1246 State.AdditionExpressionEnd => |dest_ptr| {
1247 const token = self.getNextToken();
1248 if (tokenIdToAddition(token.id)) |add_id| {
1249 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1250 ast.NodeInfixOp {
1251 .base = undefined,
1252 .lhs = dest_ptr.get(),
1253 .op_token = token,
1254 .op = add_id,
1255 .rhs = undefined,
1256 }
1257 );
1258 stack.append(State { .AdditionExpressionEnd = dest_ptr }) catch unreachable;
1259 try stack.append(State { .MultiplyExpressionBegin = DestPtr { .Field = &node.rhs } });
1260 continue;
1261 } else {
1262 self.putBackToken(token);
1263 continue;
1264 }
1265 },
1266
1267 State.MultiplyExpressionBegin => |dest_ptr| {
1268 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1269 try stack.append(State { .CurlySuffixExpressionBegin = dest_ptr });
1270 continue;
1271 },
1272
1273 State.MultiplyExpressionEnd => |dest_ptr| {
1274 const token = self.getNextToken();
1275 if (tokenIdToMultiply(token.id)) |mult_id| {
1276 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1277 ast.NodeInfixOp {
1278 .base = undefined,
1279 .lhs = dest_ptr.get(),
1280 .op_token = token,
1281 .op = mult_id,
1282 .rhs = undefined,
1283 }
1284 );
1285 stack.append(State { .MultiplyExpressionEnd = dest_ptr }) catch unreachable;
1286 try stack.append(State { .CurlySuffixExpressionBegin = DestPtr { .Field = &node.rhs } });
1287 continue;
1288 } else {
1289 self.putBackToken(token);
1290 continue;
1291 }
1292 },
1293
1294 State.CurlySuffixExpressionBegin => |dest_ptr| {
1295 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1296 try stack.append(State { .TypeExprBegin = dest_ptr });
1297 continue;
1298 },
1299
1300 State.CurlySuffixExpressionEnd => |dest_ptr| {
1301 if (self.eatToken(Token.Id.LBrace) == null) {
1302 continue;
1303 }
1304
1305 if (self.isPeekToken(Token.Id.Period)) {
1306 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1307 ast.NodeSuffixOp {
1308 .base = undefined,
1309 .lhs = dest_ptr.get(),
1310 .op = ast.NodeSuffixOp.SuffixOp {
1311 .StructInitializer = ArrayList(&ast.NodeFieldInitializer).init(arena),
1312 },
1313 .rtoken = undefined,
1314 }
1315 );
1316 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
481 try stack.append(State {1317 try stack.append(State {
482 .ExpectTokenSave = ExpectTokenSave {1318 .FieldInitListItemOrEnd = ListSave(&ast.NodeFieldInitializer) {
483 .id = Token.Id.LParen,1319 .list = &node.op.StructInitializer,
484 .ptr = &node.rparen_token,1320 .ptr = &node.rtoken,
485 },1321 }
486 });1322 });
487 continue;1323 continue;
1324 } else {
1325 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1326 ast.NodeSuffixOp {
1327 .base = undefined,
1328 .lhs = dest_ptr.get(),
1329 .op = ast.NodeSuffixOp.SuffixOp {
1330 .ArrayInitializer = ArrayList(&ast.Node).init(arena),
1331 },
1332 .rtoken = undefined,
1333 }
1334 );
1335 stack.append(State { .CurlySuffixExpressionEnd = dest_ptr }) catch unreachable;
1336 try stack.append(State {
1337 .ExprListItemOrEnd = ExprListCtx {
1338 .list = &node.op.ArrayInitializer,
1339 .end = Token.Id.RBrace,
1340 .ptr = &node.rtoken,
1341 }
1342 });
1343 continue;
1344 }
1345 },
1346
1347 State.TypeExprBegin => |dest_ptr| {
1348 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1349 try stack.append(State { .PrefixOpExpression = dest_ptr });
1350 continue;
1351 },
1352
1353 State.TypeExprEnd => |dest_ptr| {
1354 const token = self.getNextToken();
1355 switch (token.id) {
1356 Token.Id.Bang => {
1357 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1358 ast.NodeInfixOp {
1359 .base = undefined,
1360 .lhs = dest_ptr.get(),
1361 .op_token = token,
1362 .op = ast.NodeInfixOp.InfixOp.ErrorUnion,
1363 .rhs = undefined,
1364 }
1365 );
1366 stack.append(State { .TypeExprEnd = dest_ptr }) catch unreachable;
1367 try stack.append(State { .PrefixOpExpression = DestPtr { .Field = &node.rhs } });
1368 continue;
1369 },
1370 else => {
1371 self.putBackToken(token);
1372 continue;
1373 },
1374 }
1375 },
1376
1377 State.PrefixOpExpression => |dest_ptr| {
1378 const token = self.getNextToken();
1379 if (tokenIdToPrefixOp(token.id)) |prefix_id| {
1380 var node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
1381 ast.NodePrefixOp {
1382 .base = undefined,
1383 .op_token = token,
1384 .op = prefix_id,
1385 .rhs = undefined,
1386 }
1387 );
1388
1389 if (token.id == Token.Id.AsteriskAsterisk) {
1390 const child = try self.createNode(arena, ast.NodePrefixOp,
1391 ast.NodePrefixOp {
1392 .base = undefined,
1393 .op_token = token,
1394 .op = prefix_id,
1395 .rhs = undefined,
1396 }
1397 );
1398 node.rhs = &child.base;
1399 node = child;
1400 }
4881401
489 // TODO: Parse postfix operator1402 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1403 if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) {
1404 try stack.append(State { .AddrOfModifiers = &node.op.AddrOf });
1405 }
1406 continue;
490 } else {1407 } else {
491 // no postfix/infix operator after this operand.
492 self.putBackToken(token);1408 self.putBackToken(token);
1409 stack.append(State { .SuffixOpExpressionBegin = dest_ptr }) catch unreachable;
1410 continue;
1411 }
1412 },
1413
1414 State.SuffixOpExpressionBegin => |dest_ptr| {
1415 const token = self.getNextToken();
1416 switch (token.id) {
1417 Token.Id.Keyword_async => {
1418 const async_node = try self.createNode(arena, ast.NodeAsyncAttribute,
1419 ast.NodeAsyncAttribute {
1420 .base = undefined,
1421 .async_token = token,
1422 .allocator_type = null,
1423 .rangle_bracket = null,
1424 }
1425 );
1426 stack.append(State {
1427 .AsyncEnd = AsyncEndCtx {
1428 .dest_ptr = dest_ptr,
1429 .attribute = async_node,
1430 }
1431 }) catch unreachable;
1432 try stack.append(State { .SuffixOpExpressionEnd = dest_ptr });
1433 try stack.append(State { .PrimaryExpression = dest_ptr });
1434
1435 const langle_bracket = self.getNextToken();
1436 if (langle_bracket.id != Token.Id.AngleBracketLeft) {
1437 self.putBackToken(langle_bracket);
1438 continue;
1439 }
1440
1441 async_node.rangle_bracket = Token(undefined);
1442 try stack.append(State {
1443 .ExpectTokenSave = ExpectTokenSave {
1444 .id = Token.Id.AngleBracketRight,
1445 .ptr = &??async_node.rangle_bracket,
1446 }
1447 });
1448 try stack.append(State { .TypeExprBegin = DestPtr { .NullableField = &async_node.allocator_type } });
1449 continue;
1450 },
1451 else => {
1452 self.putBackToken(token);
1453 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1454 try stack.append(State { .PrimaryExpression = dest_ptr });
1455 continue;
1456 }
1457 }
1458 },
1459
1460 State.SuffixOpExpressionEnd => |dest_ptr| {
1461 const token = self.getNextToken();
1462 switch (token.id) {
1463 Token.Id.LParen => {
1464 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1465 ast.NodeSuffixOp {
1466 .base = undefined,
1467 .lhs = dest_ptr.get(),
1468 .op = ast.NodeSuffixOp.SuffixOp {
1469 .Call = ast.NodeSuffixOp.CallInfo {
1470 .params = ArrayList(&ast.Node).init(arena),
1471 .async_attr = null,
1472 }
1473 },
1474 .rtoken = undefined,
1475 }
1476 );
1477 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1478 try stack.append(State {
1479 .ExprListItemOrEnd = ExprListCtx {
1480 .list = &node.op.Call.params,
1481 .end = Token.Id.RParen,
1482 .ptr = &node.rtoken,
1483 }
1484 });
1485 continue;
1486 },
1487 Token.Id.LBracket => {
1488 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuffixOp,
1489 ast.NodeSuffixOp {
1490 .base = undefined,
1491 .lhs = dest_ptr.get(),
1492 .op = ast.NodeSuffixOp.SuffixOp {
1493 .ArrayAccess = undefined,
1494 },
1495 .rtoken = undefined
1496 }
1497 );
1498 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1499 try stack.append(State { .SliceOrArrayAccess = node });
1500 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayAccess }});
1501 continue;
1502 },
1503 Token.Id.Period => {
1504 const identifier = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined));
1505 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp,
1506 ast.NodeInfixOp {
1507 .base = undefined,
1508 .lhs = dest_ptr.get(),
1509 .op_token = token,
1510 .op = ast.NodeInfixOp.InfixOp.Period,
1511 .rhs = &identifier.base,
1512 }
1513 );
1514 stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable;
1515 try stack.append(State {
1516 .ExpectTokenSave = ExpectTokenSave {
1517 .id = Token.Id.Identifier,
1518 .ptr = &identifier.token
1519 }
1520 });
1521 continue;
1522 },
1523 else => {
1524 self.putBackToken(token);
1525 continue;
1526 },
1527 }
1528 },
1529
1530 State.PrimaryExpression => |dest_ptr| {
1531 const token = self.getNextToken();
1532 switch (token.id) {
1533 Token.Id.IntegerLiteral => {
1534 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base);
1535 continue;
1536 },
1537 Token.Id.FloatLiteral => {
1538 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeFloatLiteral, token)).base);
1539 continue;
1540 },
1541 Token.Id.CharLiteral => {
1542 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeCharLiteral, token)).base);
1543 continue;
1544 },
1545 Token.Id.Keyword_undefined => {
1546 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUndefinedLiteral, token)).base);
1547 continue;
1548 },
1549 Token.Id.Keyword_true, Token.Id.Keyword_false => {
1550 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeBoolLiteral, token)).base);
1551 continue;
1552 },
1553 Token.Id.Keyword_null => {
1554 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeNullLiteral, token)).base);
1555 continue;
1556 },
1557 Token.Id.Keyword_this => {
1558 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeThisLiteral, token)).base);
1559 continue;
1560 },
1561 Token.Id.Keyword_var => {
1562 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeVarType, token)).base);
1563 continue;
1564 },
1565 Token.Id.Keyword_unreachable => {
1566 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUnreachable, token)).base);
1567 continue;
1568 },
1569 Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => {
1570 dest_ptr.store((try self.parseStringLiteral(arena, token)) ?? unreachable);
1571 },
1572 Token.Id.LParen => {
1573 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeGroupedExpression,
1574 ast.NodeGroupedExpression {
1575 .base = undefined,
1576 .lparen = token,
1577 .expr = undefined,
1578 .rparen = undefined,
1579 }
1580 );
1581 stack.append(State {
1582 .ExpectTokenSave = ExpectTokenSave {
1583 .id = Token.Id.RParen,
1584 .ptr = &node.rparen,
1585 }
1586 }) catch unreachable;
1587 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
1588 continue;
1589 },
1590 Token.Id.Builtin => {
1591 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeBuiltinCall,
1592 ast.NodeBuiltinCall {
1593 .base = undefined,
1594 .builtin_token = token,
1595 .params = ArrayList(&ast.Node).init(arena),
1596 .rparen_token = undefined,
1597 }
1598 );
1599 stack.append(State {
1600 .ExprListItemOrEnd = ExprListCtx {
1601 .list = &node.params,
1602 .end = Token.Id.RParen,
1603 .ptr = &node.rparen_token,
1604 }
1605 }) catch unreachable;
1606 try stack.append(State { .ExpectToken = Token.Id.LParen, });
1607 continue;
1608 },
1609 Token.Id.LBracket => {
1610 const rbracket_token = self.getNextToken();
1611 if (rbracket_token.id == Token.Id.RBracket) {
1612 const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
1613 ast.NodePrefixOp {
1614 .base = undefined,
1615 .op_token = token,
1616 .op = ast.NodePrefixOp.PrefixOp{
1617 .SliceType = ast.NodePrefixOp.AddrOfInfo {
1618 .align_expr = null,
1619 .bit_offset_start_token = null,
1620 .bit_offset_end_token = null,
1621 .const_token = null,
1622 .volatile_token = null,
1623 }
1624 },
1625 .rhs = undefined,
1626 }
1627 );
1628 dest_ptr.store(&node.base);
1629 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1630 try stack.append(State { .AddrOfModifiers = &node.op.SliceType });
1631 continue;
1632 }
1633
1634 self.putBackToken(rbracket_token);
1635
1636 const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp,
1637 ast.NodePrefixOp {
1638 .base = undefined,
1639 .op_token = token,
1640 .op = ast.NodePrefixOp.PrefixOp{
1641 .ArrayType = undefined,
1642 },
1643 .rhs = undefined,
1644 }
1645 );
1646 stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable;
1647 try stack.append(State { .ExpectToken = Token.Id.RBracket });
1648 try stack.append(State { .Expression = DestPtr { .Field = &node.op.ArrayType } });
1649
1650 },
1651 Token.Id.Keyword_error => {
1652 if (self.eatToken(Token.Id.LBrace) == null) {
1653 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeErrorType, token)).base);
1654 continue;
1655 }
4931656
494 var expression = popSuffixOp(&stack);1657 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeErrorSetDecl,
495 while (true) {1658 ast.NodeErrorSetDecl {
496 switch (stack.pop()) {1659 .base = undefined,
497 State.Expression => |dest_ptr| {1660 .error_token = token,
498 // we're done1661 .decls = ArrayList(&ast.NodeIdentifier).init(arena),
499 try dest_ptr.store(expression);1662 .rbrace_token = undefined,
500 break;1663 }
1664 );
1665
1666 stack.append(State {
1667 .IdentifierListItemOrEnd = ListSave(&ast.NodeIdentifier) {
1668 .list = &node.decls,
1669 .ptr = &node.rbrace_token,
1670 }
1671 }) catch unreachable;
1672 continue;
1673 },
1674 Token.Id.Keyword_packed => {
1675 stack.append(State {
1676 .ContainerExtern = ContainerExternCtx {
1677 .dest_ptr = dest_ptr,
1678 .ltoken = token,
1679 .layout = ast.NodeContainerDecl.Layout.Packed,
501 },1680 },
502 State.InfixOp => |infix_op| {1681 }) catch unreachable;
503 infix_op.rhs = expression;1682 },
504 infix_op.lhs = popSuffixOp(&stack);1683 Token.Id.Keyword_extern => {
505 expression = &infix_op.base;1684 const next = self.getNextToken();
506 continue;1685 if (next.id == Token.Id.Keyword_fn) {
1686 const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
1687 ast.NodeFnProto {
1688 .base = undefined,
1689 .visib_token = null,
1690 .name_token = null,
1691 .fn_token = next,
1692 .params = ArrayList(&ast.Node).init(arena),
1693 .return_type = undefined,
1694 .var_args_token = null,
1695 .extern_export_inline_token = token,
1696 .cc_token = null,
1697 .async_attr = null,
1698 .body_node = null,
1699 .lib_name = null,
1700 .align_expr = null,
1701 }
1702 );
1703 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1704 continue;
1705 }
1706
1707 self.putBackToken(next);
1708 stack.append(State {
1709 .ContainerExtern = ContainerExternCtx {
1710 .dest_ptr = dest_ptr,
1711 .ltoken = token,
1712 .layout = ast.NodeContainerDecl.Layout.Extern,
507 },1713 },
508 State.PrefixOp => |prefix_op| {1714 }) catch unreachable;
509 prefix_op.rhs = expression;1715 },
510 expression = &prefix_op.base;1716 Token.Id.Keyword_struct, Token.Id.Keyword_union, Token.Id.Keyword_enum => {
511 continue;1717 self.putBackToken(token);
1718 stack.append(State {
1719 .ContainerExtern = ContainerExternCtx {
1720 .dest_ptr = dest_ptr,
1721 .ltoken = token,
1722 .layout = ast.NodeContainerDecl.Layout.Auto,
512 },1723 },
513 else => unreachable,1724 }) catch unreachable;
1725 },
1726 Token.Id.Identifier => {
1727 const next = self.getNextToken();
1728 if (next.id != Token.Id.Colon) {
1729 self.putBackToken(next);
1730 dest_ptr.store(&(try self.createLiteral(arena, ast.NodeIdentifier, token)).base);
1731 continue;
1732 }
1733
1734 stack.append(State {
1735 .LabeledExpression = LabelCtx {
1736 .label = token,
1737 .dest_ptr = dest_ptr
1738 }
1739 }) catch unreachable;
1740 continue;
1741 },
1742 Token.Id.Keyword_fn => {
1743 const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
1744 ast.NodeFnProto {
1745 .base = undefined,
1746 .visib_token = null,
1747 .name_token = null,
1748 .fn_token = token,
1749 .params = ArrayList(&ast.Node).init(arena),
1750 .return_type = undefined,
1751 .var_args_token = null,
1752 .extern_export_inline_token = null,
1753 .cc_token = null,
1754 .async_attr = null,
1755 .body_node = null,
1756 .lib_name = null,
1757 .align_expr = null,
1758 }
1759 );
1760 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1761 continue;
1762 },
1763 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
1764 const fn_token = (try self.expectToken(&stack, Token.Id.Keyword_fn)) ?? continue;
1765 const fn_proto = try self.createToDestNode(arena, dest_ptr, ast.NodeFnProto,
1766 ast.NodeFnProto {
1767 .base = undefined,
1768 .visib_token = null,
1769 .name_token = null,
1770 .fn_token = fn_token,
1771 .params = ArrayList(&ast.Node).init(arena),
1772 .return_type = undefined,
1773 .var_args_token = null,
1774 .extern_export_inline_token = null,
1775 .cc_token = token,
1776 .async_attr = null,
1777 .body_node = null,
1778 .lib_name = null,
1779 .align_expr = null,
1780 }
1781 );
1782 stack.append(State { .FnProto = fn_proto }) catch unreachable;
1783 continue;
1784 },
1785 Token.Id.Keyword_asm => {
1786 const is_volatile = blk: {
1787 const volatile_token = self.getNextToken();
1788 if (volatile_token.id != Token.Id.Keyword_volatile) {
1789 self.putBackToken(volatile_token);
1790 break :blk false;
1791 }
1792 break :blk true;
1793 };
1794 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
1795
1796 const template_token = self.getNextToken();
1797 const template = (try self.parseStringLiteral(arena, template_token)) ?? {
1798 try self.parseError(&stack, template_token, "expected string literal, found {}", @tagName(template_token.id));
1799 continue;
1800 };
1801 // TODO parse template
1802
1803 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeAsm,
1804 ast.NodeAsm {
1805 .base = undefined,
1806 .asm_token = token,
1807 .is_volatile = is_volatile,
1808 .template = template,
1809 //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena),
1810 .outputs = ArrayList(&ast.NodeAsmOutput).init(arena),
1811 .inputs = ArrayList(&ast.NodeAsmInput).init(arena),
1812 .cloppers = ArrayList(&ast.Node).init(arena),
1813 .rparen = undefined,
1814 }
1815 );
1816 stack.append(State {
1817 .ExpectTokenSave = ExpectTokenSave {
1818 .id = Token.Id.RParen,
1819 .ptr = &node.rparen,
1820 }
1821 }) catch unreachable;
1822 try stack.append(State { .AsmClopperItems = &node.cloppers });
1823 try stack.append(State { .IfToken = Token.Id.Colon });
1824 try stack.append(State { .AsmInputItems = &node.inputs });
1825 try stack.append(State { .IfToken = Token.Id.Colon });
1826 try stack.append(State { .AsmOutputItems = &node.outputs });
1827 try stack.append(State { .IfToken = Token.Id.Colon });
1828 },
1829 Token.Id.Keyword_inline => {
1830 stack.append(State {
1831 .Inline = InlineCtx {
1832 .label = null,
1833 .inline_token = token,
1834 .dest_ptr = dest_ptr,
1835 }
1836 }) catch unreachable;
1837 continue;
1838 },
1839 else => {
1840 if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) {
1841 try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id));
514 }1842 }
1843 continue;
515 }1844 }
516 continue;
517 }1845 }
518 },1846 },
5191847
520 State.ExprListItemOrEnd => |params| {1848 State.SliceOrArrayAccess => |node| {
521 var token = self.getNextToken();1849 var token = self.getNextToken();
1850
522 switch (token.id) {1851 switch (token.id) {
523 Token.Id.RParen => continue,1852 Token.Id.Ellipsis2 => {
1853 const start = node.op.ArrayAccess;
1854 node.op = ast.NodeSuffixOp.SuffixOp {
1855 .Slice = ast.NodeSuffixOp.SliceRange {
1856 .start = start,
1857 .end = undefined,
1858 }
1859 };
1860
1861 const rbracket_token = self.getNextToken();
1862 if (rbracket_token.id != Token.Id.RBracket) {
1863 self.putBackToken(rbracket_token);
1864 stack.append(State {
1865 .ExpectTokenSave = ExpectTokenSave {
1866 .id = Token.Id.RBracket,
1867 .ptr = &node.rtoken,
1868 }
1869 }) catch unreachable;
1870 try stack.append(State { .Expression = DestPtr { .NullableField = &node.op.Slice.end } });
1871 } else {
1872 node.rtoken = rbracket_token;
1873 }
1874 continue;
1875 },
1876 Token.Id.RBracket => {
1877 node.rtoken = token;
1878 continue;
1879 },
524 else => {1880 else => {
525 self.putBackToken(token);1881 try self.parseError(&stack, token, "expected ']' or '..', found {}", @tagName(token.id));
526 stack.append(State { .ExprListCommaOrEnd = params }) catch unreachable;1882 continue;
527 try stack.append(State { .Expression = DestPtr{.List = params} });1883 }
1884 }
1885 },
1886
1887
1888 State.AsmOutputItems => |items| {
1889 const lbracket = self.getNextToken();
1890 if (lbracket.id != Token.Id.LBracket) {
1891 self.putBackToken(lbracket);
1892 continue;
1893 }
1894
1895 stack.append(State { .AsmOutputItems = items }) catch unreachable;
1896 try stack.append(State { .IfToken = Token.Id.Comma });
1897
1898 const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
1899 _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue;
1900
1901 const constraint_token = self.getNextToken();
1902 const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? {
1903 try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id));
1904 continue;
1905 };
1906
1907 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
1908 try stack.append(State { .ExpectToken = Token.Id.RParen });
1909
1910 const node = try self.createNode(arena, ast.NodeAsmOutput,
1911 ast.NodeAsmOutput {
1912 .base = undefined,
1913 .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name),
1914 .constraint = constraint,
1915 .kind = undefined,
1916 }
1917 );
1918 try items.append(node);
1919
1920 const symbol_or_arrow = self.getNextToken();
1921 switch (symbol_or_arrow.id) {
1922 Token.Id.Identifier => {
1923 node.kind = ast.NodeAsmOutput.Kind { .Variable = try self.createLiteral(arena, ast.NodeIdentifier, symbol_or_arrow) };
528 },1924 },
1925 Token.Id.Arrow => {
1926 node.kind = ast.NodeAsmOutput.Kind { .Return = undefined };
1927 try stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.kind.Return } });
1928 },
1929 else => {
1930 try self.parseError(&stack, symbol_or_arrow, "expected '->' or {}, found {}",
1931 @tagName(Token.Id.Identifier),
1932 @tagName(symbol_or_arrow.id));
1933 continue;
1934 },
1935 }
1936 },
1937
1938 State.AsmInputItems => |items| {
1939 const lbracket = self.getNextToken();
1940 if (lbracket.id != Token.Id.LBracket) {
1941 self.putBackToken(lbracket);
1942 continue;
529 }1943 }
1944
1945 stack.append(State { .AsmInputItems = items }) catch unreachable;
1946 try stack.append(State { .IfToken = Token.Id.Comma });
1947
1948 const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
1949 _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue;
1950
1951 const constraint_token = self.getNextToken();
1952 const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? {
1953 try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id));
1954 continue;
1955 };
1956
1957 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
1958 try stack.append(State { .ExpectToken = Token.Id.RParen });
1959
1960 const node = try self.createNode(arena, ast.NodeAsmInput,
1961 ast.NodeAsmInput {
1962 .base = undefined,
1963 .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name),
1964 .constraint = constraint,
1965 .expr = undefined,
1966 }
1967 );
1968 try items.append(node);
1969 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
530 },1970 },
5311971
532 State.ExprListCommaOrEnd => |params| {1972 State.AsmClopperItems => |items| {
1973 const string_token = self.getNextToken();
1974 const string = (try self.parseStringLiteral(arena, string_token)) ?? {
1975 self.putBackToken(string_token);
1976 continue;
1977 };
1978 try items.append(string);
1979
1980 stack.append(State { .AsmClopperItems = items }) catch unreachable;
1981 try stack.append(State { .IfToken = Token.Id.Comma });
1982 },
1983
1984 State.ExprListItemOrEnd => |list_state| {
533 var token = self.getNextToken();1985 var token = self.getNextToken();
534 switch (token.id) {1986
535 Token.Id.Comma => {1987 const IdTag = @TagType(Token.Id);
536 stack.append(State { .ExprListItemOrEnd = params }) catch unreachable;1988 if (IdTag(list_state.end) == token.id) {
1989 *list_state.ptr = token;
1990 continue;
1991 }
1992
1993 self.putBackToken(token);
1994 stack.append(State { .ExprListCommaOrEnd = list_state }) catch unreachable;
1995 try stack.append(State { .Expression = DestPtr{ .Field = try list_state.list.addOne() } });
1996 },
1997
1998 State.FieldInitListItemOrEnd => |list_state| {
1999 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
2000 *list_state.ptr = rbrace;
2001 continue;
2002 }
2003
2004 const node = try self.createNode(arena, ast.NodeFieldInitializer,
2005 ast.NodeFieldInitializer {
2006 .base = undefined,
2007 .period_token = undefined,
2008 .name_token = undefined,
2009 .expr = undefined,
2010 }
2011 );
2012 try list_state.list.append(node);
2013
2014 stack.append(State { .FieldInitListCommaOrEnd = list_state }) catch unreachable;
2015 try stack.append(State { .Expression = DestPtr{.Field = &node.expr} });
2016 try stack.append(State { .ExpectToken = Token.Id.Equal });
2017 try stack.append(State {
2018 .ExpectTokenSave = ExpectTokenSave {
2019 .id = Token.Id.Identifier,
2020 .ptr = &node.name_token,
2021 }
2022 });
2023 try stack.append(State {
2024 .ExpectTokenSave = ExpectTokenSave {
2025 .id = Token.Id.Period,
2026 .ptr = &node.period_token,
2027 }
2028 });
2029 },
2030
2031 State.IdentifierListItemOrEnd => |list_state| {
2032 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
2033 *list_state.ptr = rbrace;
2034 continue;
2035 }
2036
2037 const node = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined));
2038 try list_state.list.append(node);
2039
2040 stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable;
2041 try stack.append(State {
2042 .ExpectTokenSave = ExpectTokenSave {
2043 .id = Token.Id.Identifier,
2044 .ptr = &node.token,
2045 }
2046 });
2047 },
2048
2049 State.SwitchCaseOrEnd => |list_state| {
2050 if (self.eatToken(Token.Id.RBrace)) |rbrace| {
2051 *list_state.ptr = rbrace;
2052 continue;
2053 }
2054
2055 const node = try self.createNode(arena, ast.NodeSwitchCase,
2056 ast.NodeSwitchCase {
2057 .base = undefined,
2058 .items = ArrayList(&ast.Node).init(arena),
2059 .payload = null,
2060 .expr = undefined,
2061 }
2062 );
2063 try list_state.list.append(node);
2064 stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable;
2065 try stack.append(State { .AssignmentExpressionBegin = DestPtr{ .Field = &node.expr } });
2066 try stack.append(State { .PointerPayload = &node.payload });
2067
2068 const maybe_else = self.getNextToken();
2069 if (maybe_else.id == Token.Id.Keyword_else) {
2070 const else_node = try self.createAttachNode(arena, &node.items, ast.NodeSwitchElse,
2071 ast.NodeSwitchElse {
2072 .base = undefined,
2073 .token = maybe_else,
2074 }
2075 );
2076 try stack.append(State { .ExpectToken = Token.Id.EqualAngleBracketRight });
2077 continue;
2078 } else {
2079 self.putBackToken(maybe_else);
2080 try stack.append(State { .SwitchCaseItem = &node.items });
2081 continue;
2082 }
2083 },
2084
2085 State.SwitchCaseItem => |case_items| {
2086 stack.append(State { .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
2087 try stack.append(State { .RangeExpressionBegin = DestPtr{ .Field = try case_items.addOne() } });
2088 },
2089
2090 State.ExprListCommaOrEnd => |list_state| {
2091 try self.commaOrEnd(&stack, list_state.end, list_state.ptr, State { .ExprListItemOrEnd = list_state });
2092 continue;
2093 },
2094
2095 State.FieldInitListCommaOrEnd => |list_state| {
2096 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .FieldInitListItemOrEnd = list_state });
2097 continue;
2098 },
2099
2100 State.FieldListCommaOrEnd => |container_decl| {
2101 try self.commaOrEnd(&stack, Token.Id.RBrace, &container_decl.rbrace_token,
2102 State { .ContainerDecl = container_decl });
2103 continue;
2104 },
2105
2106 State.IdentifierListCommaOrEnd => |list_state| {
2107 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .IdentifierListItemOrEnd = list_state });
2108 continue;
2109 },
2110
2111 State.SwitchCaseCommaOrEnd => |list_state| {
2112 try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state });
2113 continue;
2114 },
2115
2116 State.SwitchCaseItemCommaOrEnd => |case_items| {
2117 try self.commaOrEnd(&stack, Token.Id.EqualAngleBracketRight, null, State { .SwitchCaseItem = case_items });
2118 continue;
2119 },
2120
2121 State.Else => |dest| {
2122 const else_token = self.getNextToken();
2123 if (else_token.id != Token.Id.Keyword_else) {
2124 self.putBackToken(else_token);
2125 continue;
2126 }
2127
2128 const node = try self.createNode(arena, ast.NodeElse,
2129 ast.NodeElse {
2130 .base = undefined,
2131 .else_token = else_token,
2132 .payload = null,
2133 .body = undefined,
2134 }
2135 );
2136 *dest = node;
2137
2138 stack.append(State { .Expression = DestPtr { .Field = &node.body } }) catch unreachable;
2139 try stack.append(State { .Payload = &node.payload });
2140 },
2141
2142 State.WhileContinueExpr => |dest| {
2143 const colon = self.getNextToken();
2144 if (colon.id != Token.Id.Colon) {
2145 self.putBackToken(colon);
2146 continue;
2147 }
2148
2149 _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue;
2150 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
2151 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = dest } });
2152 },
2153
2154 State.SuspendBody => |suspend_node| {
2155 if (suspend_node.payload != null) {
2156 try stack.append(State { .AssignmentExpressionBegin = DestPtr { .NullableField = &suspend_node.body } });
2157 }
2158 continue;
2159 },
2160
2161 State.AsyncEnd => |ctx| {
2162 const node = ctx.dest_ptr.get();
2163
2164 switch (node.id) {
2165 ast.Node.Id.FnProto => {
2166 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", node);
2167 fn_proto.async_attr = ctx.attribute;
2168 },
2169 ast.Node.Id.SuffixOp => {
2170 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", node);
2171 if (suffix_op.op == ast.NodeSuffixOp.SuffixOp.Call) {
2172 suffix_op.op.Call.async_attr = ctx.attribute;
2173 continue;
2174 }
2175
2176 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2177 @tagName(suffix_op.op));
2178 continue;
537 },2179 },
538 Token.Id.RParen => continue,2180 else => {
539 else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)),2181 try self.parseError(&stack, node.firstToken(), "expected call or fn proto, found {}.",
2182 @tagName(node.id));
2183 continue;
2184 }
2185 }
2186 },
2187
2188 State.Payload => |dest| {
2189 const lpipe = self.getNextToken();
2190 if (lpipe.id != Token.Id.Pipe) {
2191 self.putBackToken(lpipe);
2192 continue;
2193 }
2194
2195 const error_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2196 const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
2197 *dest = try self.createNode(arena, ast.NodePayload,
2198 ast.NodePayload {
2199 .base = undefined,
2200 .lpipe = lpipe,
2201 .error_symbol = try self.createLiteral(arena, ast.NodeIdentifier, error_symbol),
2202 .rpipe = rpipe
2203 }
2204 );
2205 },
2206
2207 State.PointerPayload => |dest| {
2208 const lpipe = self.getNextToken();
2209 if (lpipe.id != Token.Id.Pipe) {
2210 self.putBackToken(lpipe);
2211 continue;
2212 }
2213
2214 const is_ptr = blk: {
2215 const asterik = self.getNextToken();
2216 if (asterik.id == Token.Id.Asterisk) {
2217 break :blk true;
2218 } else {
2219 self.putBackToken(asterik);
2220 break :blk false;
2221 }
2222 };
2223
2224 const value_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2225 const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
2226 *dest = try self.createNode(arena, ast.NodePointerPayload,
2227 ast.NodePointerPayload {
2228 .base = undefined,
2229 .lpipe = lpipe,
2230 .is_ptr = is_ptr,
2231 .value_symbol = try self.createLiteral(arena, ast.NodeIdentifier, value_symbol),
2232 .rpipe = rpipe
2233 }
2234 );
2235 },
2236
2237 State.PointerIndexPayload => |dest| {
2238 const lpipe = self.getNextToken();
2239 if (lpipe.id != Token.Id.Pipe) {
2240 self.putBackToken(lpipe);
2241 continue;
540 }2242 }
2243
2244 const is_ptr = blk: {
2245 const asterik = self.getNextToken();
2246 if (asterik.id == Token.Id.Asterisk) {
2247 break :blk true;
2248 } else {
2249 self.putBackToken(asterik);
2250 break :blk false;
2251 }
2252 };
2253
2254 const value_symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2255 const index_symbol = blk: {
2256 const comma = self.getNextToken();
2257 if (comma.id != Token.Id.Comma) {
2258 self.putBackToken(comma);
2259 break :blk null;
2260 }
2261
2262 const symbol = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue;
2263 break :blk try self.createLiteral(arena, ast.NodeIdentifier, symbol);
2264 };
2265
2266 const rpipe = (try self.expectToken(&stack, Token.Id.Pipe)) ?? continue;
2267 *dest = try self.createNode(arena, ast.NodePointerIndexPayload,
2268 ast.NodePointerIndexPayload {
2269 .base = undefined,
2270 .lpipe = lpipe,
2271 .is_ptr = is_ptr,
2272 .value_symbol = try self.createLiteral(arena, ast.NodeIdentifier, value_symbol),
2273 .index_symbol = index_symbol,
2274 .rpipe = rpipe
2275 }
2276 );
541 },2277 },
5422278
543 State.AddrOfModifiers => |addr_of_info| {2279 State.AddrOfModifiers => |addr_of_info| {
...@@ -545,21 +2281,30 @@ pub const Parser = struct {...@@ -545,21 +2281,30 @@ pub const Parser = struct {
545 switch (token.id) {2281 switch (token.id) {
546 Token.Id.Keyword_align => {2282 Token.Id.Keyword_align => {
547 stack.append(state) catch unreachable;2283 stack.append(state) catch unreachable;
548 if (addr_of_info.align_expr != null) return self.parseError(token, "multiple align qualifiers");2284 if (addr_of_info.align_expr != null) {
549 _ = try self.eatToken(Token.Id.LParen);2285 try self.parseError(&stack, token, "multiple align qualifiers");
2286 continue;
2287 }
550 try stack.append(State { .ExpectToken = Token.Id.RParen });2288 try stack.append(State { .ExpectToken = Token.Id.RParen });
551 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });2289 try stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} });
2290 try stack.append(State { .ExpectToken = Token.Id.LParen });
552 continue;2291 continue;
553 },2292 },
554 Token.Id.Keyword_const => {2293 Token.Id.Keyword_const => {
555 stack.append(state) catch unreachable;2294 stack.append(state) catch unreachable;
556 if (addr_of_info.const_token != null) return self.parseError(token, "duplicate qualifier: const");2295 if (addr_of_info.const_token != null) {
2296 try self.parseError(&stack, token, "duplicate qualifier: const");
2297 continue;
2298 }
557 addr_of_info.const_token = token;2299 addr_of_info.const_token = token;
558 continue;2300 continue;
559 },2301 },
560 Token.Id.Keyword_volatile => {2302 Token.Id.Keyword_volatile => {
561 stack.append(state) catch unreachable;2303 stack.append(state) catch unreachable;
562 if (addr_of_info.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile");2304 if (addr_of_info.volatile_token != null) {
2305 try self.parseError(&stack, token, "duplicate qualifier: volatile");
2306 continue;
2307 }
563 addr_of_info.volatile_token = token;2308 addr_of_info.volatile_token = token;
564 continue;2309 continue;
565 },2310 },
...@@ -570,17 +2315,6 @@ pub const Parser = struct {...@@ -570,17 +2315,6 @@ pub const Parser = struct {
570 }2315 }
571 },2316 },
5722317
573 State.TypeExpr => |dest_ptr| {
574 const token = self.getNextToken();
575 if (token.id == Token.Id.Keyword_var) {
576 @panic("TODO param with type var");
577 }
578 self.putBackToken(token);
579
580 stack.append(State { .Expression = dest_ptr }) catch unreachable;
581 continue;
582 },
583
584 State.FnProto => |fn_proto| {2318 State.FnProto => |fn_proto| {
585 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;2319 stack.append(State { .FnProtoAlign = fn_proto }) catch unreachable;
586 try stack.append(State { .ParamDecl = fn_proto });2320 try stack.append(State { .ParamDecl = fn_proto });
...@@ -596,11 +2330,9 @@ pub const Parser = struct {...@@ -596,11 +2330,9 @@ pub const Parser = struct {
596 },2330 },
5972331
598 State.FnProtoAlign => |fn_proto| {2332 State.FnProtoAlign => |fn_proto| {
599 const token = self.getNextToken();2333 if (self.eatToken(Token.Id.Keyword_align)) |align_token| {
600 if (token.id == Token.Id.Keyword_align) {
601 @panic("TODO fn proto align");2334 @panic("TODO fn proto align");
602 }2335 }
603 self.putBackToken(token);
604 stack.append(State {2336 stack.append(State {
605 .FnProtoReturnType = fn_proto,2337 .FnProtoReturnType = fn_proto,
606 }) catch unreachable;2338 }) catch unreachable;
...@@ -610,63 +2342,74 @@ pub const Parser = struct {...@@ -610,63 +2342,74 @@ pub const Parser = struct {
610 State.FnProtoReturnType => |fn_proto| {2342 State.FnProtoReturnType => |fn_proto| {
611 const token = self.getNextToken();2343 const token = self.getNextToken();
612 switch (token.id) {2344 switch (token.id) {
613 Token.Id.Keyword_var => {
614 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Infer = token };
615 },
616 Token.Id.Bang => {2345 Token.Id.Bang => {
617 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };2346 fn_proto.return_type = ast.NodeFnProto.ReturnType { .InferErrorSet = undefined };
618 stack.append(State {2347 stack.append(State {
619 .TypeExpr = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},2348 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.InferErrorSet},
620 }) catch unreachable;2349 }) catch unreachable;
2350 continue;
2351 },
2352 Token.Id.Keyword_align => {
2353 @panic("TODO fn proto align");
2354 continue;
621 },2355 },
622 else => {2356 else => {
2357 // TODO: this is a special case. Remove this when #760 is fixed
2358 if (token.id == Token.Id.Keyword_error) {
2359 if (self.isPeekToken(Token.Id.LBrace)) {
2360 fn_proto.return_type = ast.NodeFnProto.ReturnType {
2361 .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base
2362 };
2363 continue;
2364 }
2365 }
2366
623 self.putBackToken(token);2367 self.putBackToken(token);
624 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };2368 fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined };
625 stack.append(State {2369 stack.append(State {
626 .TypeExpr = DestPtr {.Field = &fn_proto.return_type.Explicit},2370 .TypeExprBegin = DestPtr {.Field = &fn_proto.return_type.Explicit},
627 }) catch unreachable;2371 }) catch unreachable;
2372 continue;
628 },2373 },
629 }2374 }
630 if (token.id == Token.Id.Keyword_align) {
631 @panic("TODO fn proto align");
632 }
633 continue;
634 },2375 },
6352376
636 State.ParamDecl => |fn_proto| {2377 State.ParamDecl => |fn_proto| {
637 var token = self.getNextToken();2378 if (self.eatToken(Token.Id.RParen)) |_| {
638 if (token.id == Token.Id.RParen) {
639 continue;2379 continue;
640 }2380 }
641 const param_decl = try self.createAttachParamDecl(arena, &fn_proto.params);2381 const param_decl = try self.createAttachNode(arena, &fn_proto.params, ast.NodeParamDecl,
642 if (token.id == Token.Id.Keyword_comptime) {2382 ast.NodeParamDecl {
643 param_decl.comptime_token = token;2383 .base = undefined,
644 token = self.getNextToken();2384 .comptime_token = null,
645 } else if (token.id == Token.Id.Keyword_noalias) {2385 .noalias_token = null,
646 param_decl.noalias_token = token;2386 .name_token = null,
647 token = self.getNextToken();2387 .type_node = undefined,
648 }2388 .var_args_token = null,
649 if (token.id == Token.Id.Identifier) {2389 },
650 const next_token = self.getNextToken();2390 );
651 if (next_token.id == Token.Id.Colon) {2391 if (self.eatToken(Token.Id.Keyword_comptime)) |comptime_token| {
652 param_decl.name_token = token;2392 param_decl.comptime_token = comptime_token;
653 token = self.getNextToken();2393 } else if (self.eatToken(Token.Id.Keyword_noalias)) |noalias_token| {
2394 param_decl.noalias_token = noalias_token;
2395 }
2396 if (self.eatToken(Token.Id.Identifier)) |identifier| {
2397 if (self.eatToken(Token.Id.Colon)) |_| {
2398 param_decl.name_token = identifier;
654 } else {2399 } else {
655 self.putBackToken(next_token);2400 self.putBackToken(identifier);
656 }2401 }
657 }2402 }
658 if (token.id == Token.Id.Ellipsis3) {2403 if (self.eatToken(Token.Id.Ellipsis3)) |ellipsis3| {
659 param_decl.var_args_token = token;2404 param_decl.var_args_token = ellipsis3;
660 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;2405 stack.append(State { .ExpectToken = Token.Id.RParen }) catch unreachable;
661 continue;2406 continue;
662 } else {
663 self.putBackToken(token);
664 }2407 }
6652408
666 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;2409 stack.append(State { .ParamDecl = fn_proto }) catch unreachable;
667 try stack.append(State.ParamDeclComma);2410 try stack.append(State.ParamDeclComma);
668 try stack.append(State {2411 try stack.append(State {
669 .TypeExpr = DestPtr {.Field = &param_decl.type_node}2412 .TypeExprBegin = DestPtr {.Field = &param_decl.type_node}
670 });2413 });
671 continue;2414 continue;
672 },2415 },
...@@ -679,7 +2422,10 @@ pub const Parser = struct {...@@ -679,7 +2422,10 @@ pub const Parser = struct {
679 continue;2422 continue;
680 },2423 },
681 Token.Id.Comma => continue,2424 Token.Id.Comma => continue,
682 else => return self.parseError(token, "expected ',' or ')', found {}", @tagName(token.id)),2425 else => {
2426 try self.parseError(&stack, token, "expected ',' or ')', found {}", @tagName(token.id));
2427 continue;
2428 },
683 }2429 }
684 },2430 },
6852431
...@@ -687,21 +2433,163 @@ pub const Parser = struct {...@@ -687,21 +2433,163 @@ pub const Parser = struct {
687 const token = self.getNextToken();2433 const token = self.getNextToken();
688 switch(token.id) {2434 switch(token.id) {
689 Token.Id.LBrace => {2435 Token.Id.LBrace => {
690 const block = try self.createBlock(arena, token);2436 const block = try self.createNode(arena, ast.NodeBlock,
2437 ast.NodeBlock {
2438 .base = undefined,
2439 .label = null,
2440 .lbrace = token,
2441 .statements = ArrayList(&ast.Node).init(arena),
2442 .rbrace = undefined,
2443 }
2444 );
691 fn_proto.body_node = &block.base;2445 fn_proto.body_node = &block.base;
692 stack.append(State { .Block = block }) catch unreachable;2446 stack.append(State { .Block = block }) catch unreachable;
693 continue;2447 continue;
694 },2448 },
695 Token.Id.Semicolon => continue,2449 Token.Id.Semicolon => continue,
696 else => return self.parseError(token, "expected ';' or '{{', found {}", @tagName(token.id)),2450 else => {
2451 try self.parseError(&stack, token, "expected ';' or '{{', found {}", @tagName(token.id));
2452 continue;
2453 },
2454 }
2455 },
2456
2457 State.LabeledExpression => |ctx| {
2458 const token = self.getNextToken();
2459 switch (token.id) {
2460 Token.Id.LBrace => {
2461 const block = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeBlock,
2462 ast.NodeBlock {
2463 .base = undefined,
2464 .label = ctx.label,
2465 .lbrace = token,
2466 .statements = ArrayList(&ast.Node).init(arena),
2467 .rbrace = undefined,
2468 }
2469 );
2470 stack.append(State { .Block = block }) catch unreachable;
2471 continue;
2472 },
2473 Token.Id.Keyword_while => {
2474 stack.append(State {
2475 .While = LoopCtx {
2476 .label = ctx.label,
2477 .inline_token = null,
2478 .loop_token = token,
2479 .dest_ptr = ctx.dest_ptr,
2480 }
2481 }) catch unreachable;
2482 continue;
2483 },
2484 Token.Id.Keyword_for => {
2485 stack.append(State {
2486 .For = LoopCtx {
2487 .label = ctx.label,
2488 .inline_token = null,
2489 .loop_token = token,
2490 .dest_ptr = ctx.dest_ptr,
2491 }
2492 }) catch unreachable;
2493 continue;
2494 },
2495 Token.Id.Keyword_inline => {
2496 stack.append(State {
2497 .Inline = InlineCtx {
2498 .label = ctx.label,
2499 .inline_token = token,
2500 .dest_ptr = ctx.dest_ptr,
2501 }
2502 }) catch unreachable;
2503 continue;
2504 },
2505 else => {
2506 try self.parseError(&stack, token, "expected 'while', 'for', 'inline' or '{{', found {}", @tagName(token.id));
2507 continue;
2508 },
2509 }
2510 },
2511
2512 State.Inline => |ctx| {
2513 const token = self.getNextToken();
2514 switch (token.id) {
2515 Token.Id.Keyword_while => {
2516 stack.append(State {
2517 .While = LoopCtx {
2518 .inline_token = ctx.inline_token,
2519 .label = ctx.label,
2520 .loop_token = token,
2521 .dest_ptr = ctx.dest_ptr,
2522 }
2523 }) catch unreachable;
2524 continue;
2525 },
2526 Token.Id.Keyword_for => {
2527 stack.append(State {
2528 .For = LoopCtx {
2529 .inline_token = ctx.inline_token,
2530 .label = ctx.label,
2531 .loop_token = token,
2532 .dest_ptr = ctx.dest_ptr,
2533 }
2534 }) catch unreachable;
2535 continue;
2536 },
2537 else => {
2538 try self.parseError(&stack, token, "expected 'while' or 'for', found {}", @tagName(token.id));
2539 continue;
2540 },
697 }2541 }
698 },2542 },
6992543
2544 State.While => |ctx| {
2545 const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeWhile,
2546 ast.NodeWhile {
2547 .base = undefined,
2548 .label = ctx.label,
2549 .inline_token = ctx.inline_token,
2550 .while_token = ctx.loop_token,
2551 .condition = undefined,
2552 .payload = null,
2553 .continue_expr = null,
2554 .body = undefined,
2555 .@"else" = null,
2556 }
2557 );
2558 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2559 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2560 try stack.append(State { .WhileContinueExpr = &node.continue_expr });
2561 try stack.append(State { .PointerPayload = &node.payload });
2562 try stack.append(State { .ExpectToken = Token.Id.RParen });
2563 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2564 try stack.append(State { .ExpectToken = Token.Id.LParen });
2565 },
2566
2567 State.For => |ctx| {
2568 const node = try self.createToDestNode(arena, ctx.dest_ptr, ast.NodeFor,
2569 ast.NodeFor {
2570 .base = undefined,
2571 .label = ctx.label,
2572 .inline_token = ctx.inline_token,
2573 .for_token = ctx.loop_token,
2574 .array_expr = undefined,
2575 .payload = null,
2576 .body = undefined,
2577 .@"else" = null,
2578 }
2579 );
2580 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2581 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2582 try stack.append(State { .PointerIndexPayload = &node.payload });
2583 try stack.append(State { .ExpectToken = Token.Id.RParen });
2584 try stack.append(State { .Expression = DestPtr { .Field = &node.array_expr } });
2585 try stack.append(State { .ExpectToken = Token.Id.LParen });
2586 },
2587
700 State.Block => |block| {2588 State.Block => |block| {
701 const token = self.getNextToken();2589 const token = self.getNextToken();
702 switch (token.id) {2590 switch (token.id) {
703 Token.Id.RBrace => {2591 Token.Id.RBrace => {
704 block.end_token = token;2592 block.rbrace = token;
705 continue;2593 continue;
706 },2594 },
707 else => {2595 else => {
...@@ -714,365 +2602,527 @@ pub const Parser = struct {...@@ -714,365 +2602,527 @@ pub const Parser = struct {
714 },2602 },
7152603
716 State.Statement => |block| {2604 State.Statement => |block| {
717 {2605 const next = self.getNextToken();
718 // Look for comptime var, comptime const2606 switch (next.id) {
719 const comptime_token = self.getNextToken();2607 Token.Id.Keyword_comptime => {
720 if (comptime_token.id == Token.Id.Keyword_comptime) {
721 const mut_token = self.getNextToken();2608 const mut_token = self.getNextToken();
722 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {2609 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {
723 // TODO shouldn't need these casts2610 const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
724 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),2611 ast.NodeVarDecl {
725 mut_token, (?Token)(comptime_token), (?Token)(null));2612 .base = undefined,
726 try stack.append(State { .VarDecl = var_decl });2613 .visib_token = null,
2614 .mut_token = mut_token,
2615 .comptime_token = next,
2616 .extern_export_token = null,
2617 .type_node = null,
2618 .align_node = null,
2619 .init_node = null,
2620 .lib_name = null,
2621 // initialized later
2622 .name_token = undefined,
2623 .eq_token = undefined,
2624 .semicolon_token = undefined,
2625 }
2626 );
2627 stack.append(State { .VarDecl = var_decl }) catch unreachable;
727 continue;2628 continue;
2629 } else {
2630 self.putBackToken(mut_token);
2631 self.putBackToken(next);
2632 const statememt = try block.statements.addOne();
2633 stack.append(State { .Semicolon = statememt }) catch unreachable;
2634 try stack.append(State { .Expression = DestPtr{.Field = statememt } });
728 }2635 }
729 self.putBackToken(mut_token);2636 },
730 }2637 Token.Id.Keyword_var, Token.Id.Keyword_const => {
731 self.putBackToken(comptime_token);2638 const var_decl = try self.createAttachNode(arena, &block.statements, ast.NodeVarDecl,
732 }2639 ast.NodeVarDecl {
733 {2640 .base = undefined,
734 // Look for const, var2641 .visib_token = null,
735 const mut_token = self.getNextToken();2642 .mut_token = next,
736 if (mut_token.id == Token.Id.Keyword_var or mut_token.id == Token.Id.Keyword_const) {2643 .comptime_token = null,
737 // TODO shouldn't need these casts2644 .extern_export_token = null,
738 const var_decl = try self.createAttachVarDecl(arena, &block.statements, (?Token)(null),2645 .type_node = null,
739 mut_token, (?Token)(null), (?Token)(null));2646 .align_node = null,
740 try stack.append(State { .VarDecl = var_decl });2647 .init_node = null,
2648 .lib_name = null,
2649 // initialized later
2650 .name_token = undefined,
2651 .eq_token = undefined,
2652 .semicolon_token = undefined,
2653 }
2654 );
2655 stack.append(State { .VarDecl = var_decl }) catch unreachable;
2656 continue;
2657 },
2658 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
2659 const node = try self.createAttachNode(arena, &block.statements, ast.NodeDefer,
2660 ast.NodeDefer {
2661 .base = undefined,
2662 .defer_token = next,
2663 .kind = switch (next.id) {
2664 Token.Id.Keyword_defer => ast.NodeDefer.Kind.Unconditional,
2665 Token.Id.Keyword_errdefer => ast.NodeDefer.Kind.Error,
2666 else => unreachable,
2667 },
2668 .expr = undefined,
2669 }
2670 );
2671 stack.append(State { .Semicolon = &node.base }) catch unreachable;
2672 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = &node.expr } });
2673 continue;
2674 },
2675 Token.Id.LBrace => {
2676 const inner_block = try self.createAttachNode(arena, &block.statements, ast.NodeBlock,
2677 ast.NodeBlock {
2678 .base = undefined,
2679 .label = null,
2680 .lbrace = next,
2681 .statements = ArrayList(&ast.Node).init(arena),
2682 .rbrace = undefined,
2683 }
2684 );
2685 stack.append(State { .Block = inner_block }) catch unreachable;
2686 continue;
2687 },
2688 else => {
2689 self.putBackToken(next);
2690 const statememt = try block.statements.addOne();
2691 stack.append(State { .Semicolon = statememt }) catch unreachable;
2692 try stack.append(State { .AssignmentExpressionBegin = DestPtr{.Field = statememt } });
741 continue;2693 continue;
742 }2694 }
743 self.putBackToken(mut_token);
744 }2695 }
7452696
746 stack.append(State { .ExpectToken = Token.Id.Semicolon }) catch unreachable;
747 try stack.append(State { .Expression = DestPtr{.List = &block.statements} });
748 continue;
749 },2697 },
7502698
751 // These are data, not control flow.2699 State.Semicolon => |node_ptr| {
752 State.InfixOp => unreachable,2700 const node = *node_ptr;
753 State.PrefixOp => unreachable,2701 if (requireSemiColon(node)) {
754 State.SuffixOp => unreachable,2702 _ = (try self.expectToken(&stack, Token.Id.Semicolon)) ?? continue;
755 State.Operand => unreachable,2703 }
2704 }
756 }2705 }
757 }2706 }
758 }2707 }
7592708
760 fn popSuffixOp(stack: &ArrayList(State)) &ast.Node {2709 fn requireSemiColon(node: &const ast.Node) bool {
761 var expression: &ast.Node = undefined;2710 var n = node;
762 var left_leaf_ptr: &&ast.Node = &expression;
763 while (true) {2711 while (true) {
764 switch (stack.pop()) {2712 switch (n.id) {
765 State.SuffixOp => |suffix_op| {2713 ast.Node.Id.Root,
766 switch (suffix_op.id) {2714 ast.Node.Id.StructField,
767 ast.Node.Id.Call => {2715 ast.Node.Id.UnionTag,
768 const call = @fieldParentPtr(ast.NodeCall, "base", suffix_op);2716 ast.Node.Id.EnumTag,
769 *left_leaf_ptr = &call.base;2717 ast.Node.Id.ParamDecl,
770 left_leaf_ptr = &call.callee;2718 ast.Node.Id.Block,
771 continue;2719 ast.Node.Id.Payload,
772 },2720 ast.Node.Id.PointerPayload,
773 else => unreachable,2721 ast.Node.Id.PointerIndexPayload,
2722 ast.Node.Id.Switch,
2723 ast.Node.Id.SwitchCase,
2724 ast.Node.Id.SwitchElse,
2725 ast.Node.Id.FieldInitializer,
2726 ast.Node.Id.LineComment,
2727 ast.Node.Id.TestDecl => return false,
2728 ast.Node.Id.While => {
2729 const while_node = @fieldParentPtr(ast.NodeWhile, "base", n);
2730 if (while_node.@"else") |@"else"| {
2731 n = @"else".base;
2732 continue;
774 }2733 }
2734
2735 return while_node.body.id != ast.Node.Id.Block;
775 },2736 },
776 State.Operand => |operand| {2737 ast.Node.Id.For => {
777 *left_leaf_ptr = operand;2738 const for_node = @fieldParentPtr(ast.NodeFor, "base", n);
778 break;2739 if (for_node.@"else") |@"else"| {
779 },2740 n = @"else".base;
780 else => unreachable,2741 continue;
781 }2742 }
782 }
7832743
784 return expression;2744 return for_node.body.id != ast.Node.Id.Block;
785 }2745 },
2746 ast.Node.Id.If => {
2747 const if_node = @fieldParentPtr(ast.NodeIf, "base", n);
2748 if (if_node.@"else") |@"else"| {
2749 n = @"else".base;
2750 continue;
2751 }
7862752
787 fn tokenIdToInfixOp(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {2753 return if_node.body.id != ast.Node.Id.Block;
788 return switch (*id) {2754 },
789 Token.Id.Ampersand => ast.NodeInfixOp.InfixOp.BitAnd,2755 ast.Node.Id.Else => {
790 Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp.AssignBitAnd,2756 const else_node = @fieldParentPtr(ast.NodeElse, "base", n);
791 Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp.BitShiftLeft,2757 n = else_node.body;
792 Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp.AssignBitShiftLeft,2758 continue;
793 Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp.BitShiftRight,2759 },
794 Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp.AssignBitShiftRight,2760 ast.Node.Id.Defer => {
795 Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp.LessThan,2761 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n);
796 Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp.LessOrEqual,2762 return defer_node.expr.id != ast.Node.Id.Block;
797 Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp.GreaterThan,2763 },
798 Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp.GreaterOrEqual,2764 ast.Node.Id.Comptime => {
799 Token.Id.Asterisk => ast.NodeInfixOp.InfixOp.Mult,2765 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n);
800 Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp.ArrayMult,2766 return comptime_node.expr.id != ast.Node.Id.Block;
801 Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp.AssignTimes,2767 },
802 Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp.MultWrap,2768 ast.Node.Id.Suspend => {
803 Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp.AssignTimesWarp,2769 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n);
804 Token.Id.Bang => ast.NodeInfixOp.InfixOp.ErrorUnion,2770 if (suspend_node.body) |body| {
805 Token.Id.BangEqual => ast.NodeInfixOp.InfixOp.BangEqual,2771 return body.id != ast.Node.Id.Block;
806 Token.Id.Caret => ast.NodeInfixOp.InfixOp.BitXor,2772 }
807 Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp.AssignBitXor,
808 Token.Id.Equal => ast.NodeInfixOp.InfixOp.Assign,
809 Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp.EqualEqual,
810 Token.Id.Keyword_and => ast.NodeInfixOp.InfixOp.BoolAnd,
811 Token.Id.Keyword_or => ast.NodeInfixOp.InfixOp.BoolOr,
812 Token.Id.Minus => ast.NodeInfixOp.InfixOp.Sub,
813 Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp.AssignMinus,
814 Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp.SubWrap,
815 Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp.AssignMinusWrap,
816 Token.Id.Percent => ast.NodeInfixOp.InfixOp.Mod,
817 Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp.AssignMod,
818 Token.Id.Period => ast.NodeInfixOp.InfixOp.Period,
819 Token.Id.Pipe => ast.NodeInfixOp.InfixOp.BitOr,
820 Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp.AssignBitOr,
821 Token.Id.PipePipe => ast.NodeInfixOp.InfixOp.MergeErrorSets,
822 Token.Id.Plus => ast.NodeInfixOp.InfixOp.Add,
823 Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp.AssignPlus,
824 Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp.AddWrap,
825 Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp.AssignPlusWrap,
826 Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp.ArrayCat,
827 Token.Id.QuestionMarkQuestionMark => ast.NodeInfixOp.InfixOp.UnwrapMaybe,
828 Token.Id.Slash => ast.NodeInfixOp.InfixOp.Div,
829 Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp.AssignDiv,
830 else => null,
831 };
832 }
8332773
834 fn initNode(self: &Parser, id: ast.Node.Id) ast.Node {2774 return true;
835 if (self.pending_line_comment_node) |comment_node| {2775 },
836 self.pending_line_comment_node = null;2776 else => return true,
837 return ast.Node {.id = id, .comment = comment_node};2777 }
838 }2778 }
839 return ast.Node {.id = id, .comment = null };
840 }2779 }
8412780
842 fn createRoot(self: &Parser, arena: &mem.Allocator) !&ast.NodeRoot {2781 fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node {
843 const node = try arena.create(ast.NodeRoot);2782 switch (token.id) {
2783 Token.Id.StringLiteral => {
2784 return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base;
2785 },
2786 Token.Id.MultilineStringLiteralLine => {
2787 const node = try self.createNode(arena, ast.NodeMultilineStringLiteral,
2788 ast.NodeMultilineStringLiteral {
2789 .base = undefined,
2790 .tokens = ArrayList(Token).init(arena),
2791 }
2792 );
2793 try node.tokens.append(token);
2794 while (true) {
2795 const multiline_str = self.getNextToken();
2796 if (multiline_str.id != Token.Id.MultilineStringLiteralLine) {
2797 self.putBackToken(multiline_str);
2798 break;
2799 }
8442800
845 *node = ast.NodeRoot {2801 try node.tokens.append(multiline_str);
846 .base = self.initNode(ast.Node.Id.Root),2802 }
847 .decls = ArrayList(&ast.Node).init(arena),
848 // initialized when we get the eof token
849 .eof_token = undefined,
850 };
851 return node;
852 }
8532803
854 fn createVarDecl(self: &Parser, arena: &mem.Allocator, visib_token: &const ?Token, mut_token: &const Token,2804 return &node.base;
855 comptime_token: &const ?Token, extern_token: &const ?Token) !&ast.NodeVarDecl2805 },
856 {2806 // TODO: We shouldn't need a cast, but:
857 const node = try arena.create(ast.NodeVarDecl);2807 // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed.
8582808 else => return (?&ast.Node)(null),
859 *node = ast.NodeVarDecl {2809 }
860 .base = self.initNode(ast.Node.Id.VarDecl),
861 .visib_token = *visib_token,
862 .mut_token = *mut_token,
863 .comptime_token = *comptime_token,
864 .extern_token = *extern_token,
865 .type_node = null,
866 .align_node = null,
867 .init_node = null,
868 .lib_name = null,
869 // initialized later
870 .name_token = undefined,
871 .eq_token = undefined,
872 .semicolon_token = undefined,
873 };
874 return node;
875 }2810 }
8762811
877 fn createTestDecl(self: &Parser, arena: &mem.Allocator, test_token: &const Token, name_token: &const Token,2812 fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, dest_ptr: &const DestPtr, token: &const Token) !bool {
878 block: &ast.NodeBlock) !&ast.NodeTestDecl2813 switch (token.id) {
879 {2814 Token.Id.Keyword_suspend => {
880 const node = try arena.create(ast.NodeTestDecl);2815 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuspend,
2816 ast.NodeSuspend {
2817 .base = undefined,
2818 .suspend_token = *token,
2819 .payload = null,
2820 .body = null,
2821 }
2822 );
8812823
882 *node = ast.NodeTestDecl {2824 stack.append(State { .SuspendBody = node }) catch unreachable;
883 .base = self.initNode(ast.Node.Id.TestDecl),2825 try stack.append(State { .Payload = &node.payload });
884 .test_token = *test_token,2826 return true;
885 .name_token = *name_token,2827 },
886 .body_node = &block.base,2828 Token.Id.Keyword_if => {
887 };2829 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf,
888 return node;2830 ast.NodeIf {
889 }2831 .base = undefined,
2832 .if_token = *token,
2833 .condition = undefined,
2834 .payload = null,
2835 .body = undefined,
2836 .@"else" = null,
2837 }
2838 );
2839
2840 stack.append(State { .Else = &node.@"else" }) catch unreachable;
2841 try stack.append(State { .Expression = DestPtr { .Field = &node.body } });
2842 try stack.append(State { .PointerPayload = &node.payload });
2843 try stack.append(State { .ExpectToken = Token.Id.RParen });
2844 try stack.append(State { .Expression = DestPtr { .Field = &node.condition } });
2845 try stack.append(State { .ExpectToken = Token.Id.LParen });
2846 return true;
2847 },
2848 Token.Id.Keyword_while => {
2849 stack.append(State {
2850 .While = LoopCtx {
2851 .label = null,
2852 .inline_token = null,
2853 .loop_token = *token,
2854 .dest_ptr = *dest_ptr,
2855 }
2856 }) catch unreachable;
2857 return true;
2858 },
2859 Token.Id.Keyword_for => {
2860 stack.append(State {
2861 .For = LoopCtx {
2862 .label = null,
2863 .inline_token = null,
2864 .loop_token = *token,
2865 .dest_ptr = *dest_ptr,
2866 }
2867 }) catch unreachable;
2868 return true;
2869 },
2870 Token.Id.Keyword_switch => {
2871 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch,
2872 ast.NodeSwitch {
2873 .base = undefined,
2874 .switch_token = *token,
2875 .expr = undefined,
2876 .cases = ArrayList(&ast.NodeSwitchCase).init(arena),
2877 .rbrace = undefined,
2878 }
2879 );
8902880
891 fn createFnProto(self: &Parser, arena: &mem.Allocator, fn_token: &const Token, extern_token: &const ?Token,2881 stack.append(State {
892 cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) !&ast.NodeFnProto2882 .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) {
893 {2883 .list = &node.cases,
894 const node = try arena.create(ast.NodeFnProto);2884 .ptr = &node.rbrace,
8952885 },
896 *node = ast.NodeFnProto {2886 }) catch unreachable;
897 .base = self.initNode(ast.Node.Id.FnProto),2887 try stack.append(State { .ExpectToken = Token.Id.LBrace });
898 .visib_token = *visib_token,2888 try stack.append(State { .ExpectToken = Token.Id.RParen });
899 .name_token = null,2889 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
900 .fn_token = *fn_token,2890 try stack.append(State { .ExpectToken = Token.Id.LParen });
901 .params = ArrayList(&ast.Node).init(arena),2891 return true;
902 .return_type = undefined,2892 },
903 .var_args_token = null,2893 Token.Id.Keyword_comptime => {
904 .extern_token = *extern_token,2894 const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime,
905 .inline_token = *inline_token,2895 ast.NodeComptime {
906 .cc_token = *cc_token,2896 .base = undefined,
907 .body_node = null,2897 .comptime_token = *token,
908 .lib_name = null,2898 .expr = undefined,
909 .align_expr = null,2899 }
910 };2900 );
911 return node;2901 try stack.append(State { .Expression = DestPtr { .Field = &node.expr } });
2902 return true;
2903 },
2904 Token.Id.LBrace => {
2905 const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock,
2906 ast.NodeBlock {
2907 .base = undefined,
2908 .label = null,
2909 .lbrace = *token,
2910 .statements = ArrayList(&ast.Node).init(arena),
2911 .rbrace = undefined,
2912 }
2913 );
2914 stack.append(State { .Block = block }) catch unreachable;
2915 return true;
2916 },
2917 else => {
2918 return false;
2919 }
2920 }
912 }2921 }
9132922
914 fn createParamDecl(self: &Parser, arena: &mem.Allocator) !&ast.NodeParamDecl {2923 fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void {
915 const node = try arena.create(ast.NodeParamDecl);2924 var token = self.getNextToken();
2925 switch (token.id) {
2926 Token.Id.Comma => {
2927 stack.append(state_after_comma) catch unreachable;
2928 },
2929 else => {
2930 const IdTag = @TagType(Token.Id);
2931 if (IdTag(*end) == token.id) {
2932 if (maybe_ptr) |ptr| {
2933 *ptr = token;
2934 }
2935 return;
2936 }
9162937
917 *node = ast.NodeParamDecl {2938 try self.parseError(stack, token, "expected ',' or {}, found {}", @tagName(*end), @tagName(token.id));
918 .base = self.initNode(ast.Node.Id.ParamDecl),2939 },
919 .comptime_token = null,2940 }
920 .noalias_token = null,
921 .name_token = null,
922 .type_node = undefined,
923 .var_args_token = null,
924 };
925 return node;
926 }2941 }
9272942
928 fn createBlock(self: &Parser, arena: &mem.Allocator, begin_token: &const Token) !&ast.NodeBlock {2943 fn tokenIdToAssignment(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
929 const node = try arena.create(ast.NodeBlock);2944 // TODO: We have to cast all cases because of this:
9302945 // error: expected type '?InfixOp', found '?@TagType(InfixOp)'
931 *node = ast.NodeBlock {2946 return switch (*id) {
932 .base = self.initNode(ast.Node.Id.Block),2947 Token.Id.AmpersandEqual => ast.NodeInfixOp.InfixOp { .AssignBitAnd = void{} },
933 .begin_token = *begin_token,2948 Token.Id.AngleBracketAngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftLeft = void{} },
934 .end_token = undefined,2949 Token.Id.AngleBracketAngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .AssignBitShiftRight = void{} },
935 .statements = ArrayList(&ast.Node).init(arena),2950 Token.Id.AsteriskEqual => ast.NodeInfixOp.InfixOp { .AssignTimes = void{} },
2951 Token.Id.AsteriskPercentEqual => ast.NodeInfixOp.InfixOp { .AssignTimesWarp = void{} },
2952 Token.Id.CaretEqual => ast.NodeInfixOp.InfixOp { .AssignBitXor = void{} },
2953 Token.Id.Equal => ast.NodeInfixOp.InfixOp { .Assign = void{} },
2954 Token.Id.MinusEqual => ast.NodeInfixOp.InfixOp { .AssignMinus = void{} },
2955 Token.Id.MinusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignMinusWrap = void{} },
2956 Token.Id.PercentEqual => ast.NodeInfixOp.InfixOp { .AssignMod = void{} },
2957 Token.Id.PipeEqual => ast.NodeInfixOp.InfixOp { .AssignBitOr = void{} },
2958 Token.Id.PlusEqual => ast.NodeInfixOp.InfixOp { .AssignPlus = void{} },
2959 Token.Id.PlusPercentEqual => ast.NodeInfixOp.InfixOp { .AssignPlusWrap = void{} },
2960 Token.Id.SlashEqual => ast.NodeInfixOp.InfixOp { .AssignDiv = void{} },
2961 else => null,
936 };2962 };
937 return node;
938 }2963 }
9392964
940 fn createInfixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) !&ast.NodeInfixOp {2965 fn tokenIdToComparison(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
941 const node = try arena.create(ast.NodeInfixOp);2966 return switch (*id) {
9422967 Token.Id.BangEqual => ast.NodeInfixOp.InfixOp { .BangEqual = void{} },
943 *node = ast.NodeInfixOp {2968 Token.Id.EqualEqual => ast.NodeInfixOp.InfixOp { .EqualEqual = void{} },
944 .base = self.initNode(ast.Node.Id.InfixOp),2969 Token.Id.AngleBracketLeft => ast.NodeInfixOp.InfixOp { .LessThan = void{} },
945 .op_token = *op_token,2970 Token.Id.AngleBracketLeftEqual => ast.NodeInfixOp.InfixOp { .LessOrEqual = void{} },
946 .lhs = undefined,2971 Token.Id.AngleBracketRight => ast.NodeInfixOp.InfixOp { .GreaterThan = void{} },
947 .op = *op,2972 Token.Id.AngleBracketRightEqual => ast.NodeInfixOp.InfixOp { .GreaterOrEqual = void{} },
948 .rhs = undefined,2973 else => null,
949 };2974 };
950 return node;
951 }2975 }
9522976
953 fn createPrefixOp(self: &Parser, arena: &mem.Allocator, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) !&ast.NodePrefixOp {2977 fn tokenIdToBitShift(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
954 const node = try arena.create(ast.NodePrefixOp);2978 return switch (*id) {
9552979 Token.Id.AngleBracketAngleBracketLeft => ast.NodeInfixOp.InfixOp { .BitShiftLeft = void{} },
956 *node = ast.NodePrefixOp {2980 Token.Id.AngleBracketAngleBracketRight => ast.NodeInfixOp.InfixOp { .BitShiftRight = void{} },
957 .base = self.initNode(ast.Node.Id.PrefixOp),2981 else => null,
958 .op_token = *op_token,
959 .op = *op,
960 .rhs = undefined,
961 };2982 };
962 return node;
963 }2983 }
9642984
965 fn createIdentifier(self: &Parser, arena: &mem.Allocator, name_token: &const Token) !&ast.NodeIdentifier {2985 fn tokenIdToAddition(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
966 const node = try arena.create(ast.NodeIdentifier);2986 return switch (*id) {
9672987 Token.Id.Minus => ast.NodeInfixOp.InfixOp { .Sub = void{} },
968 *node = ast.NodeIdentifier {2988 Token.Id.MinusPercent => ast.NodeInfixOp.InfixOp { .SubWrap = void{} },
969 .base = self.initNode(ast.Node.Id.Identifier),2989 Token.Id.Plus => ast.NodeInfixOp.InfixOp { .Add = void{} },
970 .name_token = *name_token,2990 Token.Id.PlusPercent => ast.NodeInfixOp.InfixOp { .AddWrap = void{} },
2991 Token.Id.PlusPlus => ast.NodeInfixOp.InfixOp { .ArrayCat = void{} },
2992 else => null,
971 };2993 };
972 return node;
973 }2994 }
9742995
975 fn createIntegerLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeIntegerLiteral {2996 fn tokenIdToMultiply(id: &const Token.Id) ?ast.NodeInfixOp.InfixOp {
976 const node = try arena.create(ast.NodeIntegerLiteral);2997 return switch (*id) {
9772998 Token.Id.Slash => ast.NodeInfixOp.InfixOp { .Div = void{} },
978 *node = ast.NodeIntegerLiteral {2999 Token.Id.Asterisk => ast.NodeInfixOp.InfixOp { .Mult = void{} },
979 .base = self.initNode(ast.Node.Id.IntegerLiteral),3000 Token.Id.AsteriskAsterisk => ast.NodeInfixOp.InfixOp { .ArrayMult = void{} },
980 .token = *token,3001 Token.Id.AsteriskPercent => ast.NodeInfixOp.InfixOp { .MultWrap = void{} },
3002 Token.Id.Percent => ast.NodeInfixOp.InfixOp { .Mod = void{} },
3003 Token.Id.PipePipe => ast.NodeInfixOp.InfixOp { .MergeErrorSets = void{} },
3004 else => null,
981 };3005 };
982 return node;
983 }3006 }
9843007
985 fn createFloatLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeFloatLiteral {3008 fn tokenIdToPrefixOp(id: &const Token.Id) ?ast.NodePrefixOp.PrefixOp {
986 const node = try arena.create(ast.NodeFloatLiteral);3009 return switch (*id) {
9873010 Token.Id.Bang => ast.NodePrefixOp.PrefixOp { .BoolNot = void{} },
988 *node = ast.NodeFloatLiteral {3011 Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} },
989 .base = self.initNode(ast.Node.Id.FloatLiteral),3012 Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} },
990 .token = *token,3013 Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} },
3014 Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} },
3015 Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp {
3016 .AddrOf = ast.NodePrefixOp.AddrOfInfo {
3017 .align_expr = null,
3018 .bit_offset_start_token = null,
3019 .bit_offset_end_token = null,
3020 .const_token = null,
3021 .volatile_token = null,
3022 },
3023 },
3024 Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} },
3025 Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} },
3026 Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} },
3027 Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } },
3028 else => null,
991 };3029 };
992 return node;
993 }3030 }
9943031
995 fn createUndefined(self: &Parser, arena: &mem.Allocator, token: &const Token) !&ast.NodeUndefinedLiteral {3032 fn createNode(self: &Parser, arena: &mem.Allocator, comptime T: type, init_to: &const T) !&T {
996 const node = try arena.create(ast.NodeUndefinedLiteral);3033 const node = try arena.create(T);
9973034 *node = *init_to;
998 *node = ast.NodeUndefinedLiteral {3035 node.base = blk: {
999 .base = self.initNode(ast.Node.Id.UndefinedLiteral),3036 const id = ast.Node.typeToId(T);
1000 .token = *token,3037 if (self.pending_line_comment_node) |comment_node| {
3038 self.pending_line_comment_node = null;
3039 break :blk ast.Node {.id = id, .comment = comment_node};
3040 }
3041 break :blk ast.Node {.id = id, .comment = null };
1001 };3042 };
1002 return node;
1003 }
10043043
1005 fn createAttachIdentifier(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, name_token: &const Token) !&ast.NodeIdentifier {
1006 const node = try self.createIdentifier(arena, name_token);
1007 try dest_ptr.store(&node.base);
1008 return node;3044 return node;
1009 }3045 }
10103046
1011 fn createAttachParamDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node)) !&ast.NodeParamDecl {3047 fn createAttachNode(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), comptime T: type, init_to: &const T) !&T {
1012 const node = try self.createParamDecl(arena);3048 const node = try self.createNode(arena, T, init_to);
1013 try list.append(&node.base);3049 try list.append(&node.base);
1014 return node;
1015 }
10163050
1017 fn createAttachFnProto(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node), fn_token: &const Token,
1018 extern_token: &const ?Token, cc_token: &const ?Token, visib_token: &const ?Token,
1019 inline_token: &const ?Token) !&ast.NodeFnProto
1020 {
1021 const node = try self.createFnProto(arena, fn_token, extern_token, cc_token, visib_token, inline_token);
1022 try list.append(&node.base);
1023 return node;3051 return node;
1024 }3052 }
10253053
1026 fn createAttachVarDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),3054 fn createToDestNode(self: &Parser, arena: &mem.Allocator, dest_ptr: &const DestPtr, comptime T: type, init_to: &const T) !&T {
1027 visib_token: &const ?Token, mut_token: &const Token, comptime_token: &const ?Token,3055 const node = try self.createNode(arena, T, init_to);
1028 extern_token: &const ?Token) !&ast.NodeVarDecl3056 dest_ptr.store(&node.base);
1029 {3057
1030 const node = try self.createVarDecl(arena, visib_token, mut_token, comptime_token, extern_token);
1031 try list.append(&node.base);
1032 return node;3058 return node;
1033 }3059 }
10343060
1035 fn createAttachTestDecl(self: &Parser, arena: &mem.Allocator, list: &ArrayList(&ast.Node),3061 fn createLiteral(self: &Parser, arena: &mem.Allocator, comptime T: type, token: &const Token) !&T {
1036 test_token: &const Token, name_token: &const Token, block: &ast.NodeBlock) !&ast.NodeTestDecl3062 return self.createNode(arena, T,
1037 {3063 T {
1038 const node = try self.createTestDecl(arena, test_token, name_token, block);3064 .base = undefined,
1039 try list.append(&node.base);3065 .token = *token,
1040 return node;3066 }
3067 );
1041 }3068 }
10423069
1043 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {3070 fn parseError(self: &Parser, stack: &ArrayList(State), token: &const Token, comptime fmt: []const u8, args: ...) !void {
1044 const loc = self.tokenizer.getTokenLocation(token);3071 // Before reporting an error. We pop the stack to see if our state was optional
1045 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, token.line + 1, token.column + 1, args);3072 self.revertIfOptional(stack) catch {
1046 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);3073 const loc = self.tokenizer.getTokenLocation(0, token);
1047 {3074 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
1048 var i: usize = 0;3075 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
1049 while (i < token.column) : (i += 1) {3076 {
1050 warn(" ");3077 var i: usize = 0;
3078 while (i < loc.column) : (i += 1) {
3079 warn(" ");
3080 }
1051 }3081 }
1052 }3082 {
1053 {3083 const caret_count = token.end - token.start;
1054 const caret_count = token.end - token.start;3084 var i: usize = 0;
1055 var i: usize = 0;3085 while (i < caret_count) : (i += 1) {
1056 while (i < caret_count) : (i += 1) {3086 warn("~");
1057 warn("~");3087 }
1058 }3088 }
1059 }3089 warn("\n");
1060 warn("\n");3090 return error.ParseError;
1061 return error.ParseError;3091 };
1062 }3092 }
10633093
1064 fn expectToken(self: &Parser, token: &const Token, id: @TagType(Token.Id)) !void {3094 fn revertIfOptional(self: &Parser, stack: &ArrayList(State)) !void {
1065 if (token.id != id) {3095 while (stack.popOrNull()) |state| {
1066 return self.parseError(token, "expected {}, found {}", @tagName(id), @tagName(token.id));3096 switch (state) {
3097 State.Optional => |revert| {
3098 *self = revert.parser;
3099 *self.tokenizer = revert.tokenizer;
3100 *revert.ptr = null;
3101 return;
3102 },
3103 else => { }
3104 }
1067 }3105 }
3106
3107 return error.NoOptionalStateFound;
1068 }3108 }
10693109
1070 fn eatToken(self: &Parser, id: @TagType(Token.Id)) !Token {3110 fn expectToken(self: &Parser, stack: &ArrayList(State), id: @TagType(Token.Id)) !?Token {
1071 const token = self.getNextToken();3111 const token = self.getNextToken();
1072 try self.expectToken(token, id);3112 if (token.id != id) {
3113 try self.parseError(stack, token, "expected {}, found {}", @tagName(id), @tagName(token.id));
3114 return null;
3115 }
1073 return token;3116 return token;
1074 }3117 }
10753118
3119 fn eatToken(self: &Parser, id: @TagType(Token.Id)) ?Token {
3120 if (self.isPeekToken(id)) {
3121 return self.getNextToken();
3122 }
3123 return null;
3124 }
3125
1076 fn putBackToken(self: &Parser, token: &const Token) void {3126 fn putBackToken(self: &Parser, token: &const Token) void {
1077 self.put_back_tokens[self.put_back_count] = *token;3127 self.put_back_tokens[self.put_back_count] = *token;
1078 self.put_back_count += 1;3128 self.put_back_count += 1;
...@@ -1089,6 +3139,12 @@ pub const Parser = struct {...@@ -1089,6 +3139,12 @@ pub const Parser = struct {
1089 }3139 }
1090 }3140 }
10913141
3142 fn isPeekToken(self: &Parser, id: @TagType(Token.Id)) bool {
3143 const token = self.getNextToken();
3144 defer self.putBackToken(token);
3145 return id == token.id;
3146 }
3147
1092 const RenderAstFrame = struct {3148 const RenderAstFrame = struct {
1093 node: &ast.Node,3149 node: &ast.Node,
1094 indent: usize,3150 indent: usize,
...@@ -1129,6 +3185,7 @@ pub const Parser = struct {...@@ -1129,6 +3185,7 @@ pub const Parser = struct {
1129 Expression: &ast.Node,3185 Expression: &ast.Node,
1130 VarDecl: &ast.NodeVarDecl,3186 VarDecl: &ast.NodeVarDecl,
1131 Statement: &ast.Node,3187 Statement: &ast.Node,
3188 FieldInitializer: &ast.NodeFieldInitializer,
1132 PrintIndent,3189 PrintIndent,
1133 Indent: usize,3190 Indent: usize,
1134 };3191 };
...@@ -1149,9 +3206,8 @@ pub const Parser = struct {...@@ -1149,9 +3206,8 @@ pub const Parser = struct {
1149 try stack.append(RenderState {3206 try stack.append(RenderState {
1150 .Text = blk: {3207 .Text = blk: {
1151 const prev_node = root_node.decls.at(i - 1);3208 const prev_node = root_node.decls.at(i - 1);
1152 const prev_line_index = prev_node.lastToken().line;3209 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, decl.firstToken());
1153 const this_line_index = decl.firstToken().line;3210 if (loc.line >= 2) {
1154 if (this_line_index - prev_line_index >= 2) {
1155 break :blk "\n\n";3211 break :blk "\n\n";
1156 }3212 }
1157 break :blk "\n";3213 break :blk "\n";
...@@ -1169,38 +3225,24 @@ pub const Parser = struct {...@@ -1169,38 +3225,24 @@ pub const Parser = struct {
1169 switch (decl.id) {3225 switch (decl.id) {
1170 ast.Node.Id.FnProto => {3226 ast.Node.Id.FnProto => {
1171 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);3227 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", decl);
1172 if (fn_proto.visib_token) |visib_token| {
1173 switch (visib_token.id) {
1174 Token.Id.Keyword_pub => try stream.print("pub "),
1175 Token.Id.Keyword_export => try stream.print("export "),
1176 else => unreachable,
1177 }
1178 }
1179 if (fn_proto.extern_token) |extern_token| {
1180 try stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
1181 }
1182 try stream.print("fn");
11833228
1184 if (fn_proto.name_token) |name_token| {3229 if (fn_proto.body_node) |body_node| {
1185 try stream.print(" {}", self.tokenizer.getTokenSlice(name_token));3230 stack.append(RenderState { .Expression = body_node}) catch unreachable;
3231 try stack.append(RenderState { .Text = " "});
3232 } else {
3233 stack.append(RenderState { .Text = ";" }) catch unreachable;
1186 }3234 }
11873235
1188 try stream.print("(");3236 try stack.append(RenderState { .Expression = decl });
11893237 },
1190 if (fn_proto.body_node == null) {3238 ast.Node.Id.Use => {
1191 try stack.append(RenderState { .Text = ";" });3239 const use_decl = @fieldParentPtr(ast.NodeUse, "base", decl);
1192 }3240 if (use_decl.visib_token) |visib_token| {
11933241 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
1194 try stack.append(RenderState { .FnProtoRParen = fn_proto});
1195 var i = fn_proto.params.len;
1196 while (i != 0) {
1197 i -= 1;
1198 const param_decl_node = fn_proto.params.items[i];
1199 try stack.append(RenderState { .ParamDecl = param_decl_node});
1200 if (i != 0) {
1201 try stack.append(RenderState { .Text = ", " });
1202 }
1203 }3242 }
3243 try stream.print("use ");
3244 try stack.append(RenderState { .Text = ";" });
3245 try stack.append(RenderState { .Expression = use_decl.expr });
1204 },3246 },
1205 ast.Node.Id.VarDecl => {3247 ast.Node.Id.VarDecl => {
1206 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);3248 const var_decl = @fieldParentPtr(ast.NodeVarDecl, "base", decl);
...@@ -1208,29 +3250,54 @@ pub const Parser = struct {...@@ -1208,29 +3250,54 @@ pub const Parser = struct {
1208 },3250 },
1209 ast.Node.Id.TestDecl => {3251 ast.Node.Id.TestDecl => {
1210 const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);3252 const test_decl = @fieldParentPtr(ast.NodeTestDecl, "base", decl);
1211 try stream.print("test {} ", self.tokenizer.getTokenSlice(test_decl.name_token));3253 try stream.print("test ");
1212 try stack.append(RenderState { .Expression = test_decl.body_node });3254 try stack.append(RenderState { .Expression = test_decl.body_node });
3255 try stack.append(RenderState { .Text = " " });
3256 try stack.append(RenderState { .Expression = test_decl.name });
3257 },
3258 ast.Node.Id.StructField => {
3259 const field = @fieldParentPtr(ast.NodeStructField, "base", decl);
3260 if (field.visib_token) |visib_token| {
3261 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));
3262 }
3263 try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token));
3264 try stack.append(RenderState { .Expression = field.type_expr});
3265 },
3266 ast.Node.Id.UnionTag => {
3267 const tag = @fieldParentPtr(ast.NodeUnionTag, "base", decl);
3268 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3269
3270 if (tag.type_expr) |type_expr| {
3271 try stream.print(": ");
3272 try stack.append(RenderState { .Expression = type_expr});
3273 }
3274 },
3275 ast.Node.Id.EnumTag => {
3276 const tag = @fieldParentPtr(ast.NodeEnumTag, "base", decl);
3277 try stream.print("{}", self.tokenizer.getTokenSlice(tag.name_token));
3278
3279 if (tag.value) |value| {
3280 try stream.print(" = ");
3281 try stack.append(RenderState { .Expression = value});
3282 }
3283 },
3284 ast.Node.Id.Comptime => {
3285 if (requireSemiColon(decl)) {
3286 try stack.append(RenderState { .Text = ";" });
3287 }
3288 try stack.append(RenderState { .Expression = decl });
1213 },3289 },
1214 else => unreachable,3290 else => unreachable,
1215 }3291 }
1216 },3292 },
12173293
1218 RenderState.VarDecl => |var_decl| {3294 RenderState.FieldInitializer => |field_init| {
1219 if (var_decl.visib_token) |visib_token| {3295 try stream.print(".{}", self.tokenizer.getTokenSlice(field_init.name_token));
1220 try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token));3296 try stream.print(" = ");
1221 }3297 try stack.append(RenderState { .Expression = field_init.expr });
1222 if (var_decl.extern_token) |extern_token| {3298 },
1223 try stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
1224 if (var_decl.lib_name != null) {
1225 @panic("TODO");
1226 }
1227 }
1228 if (var_decl.comptime_token) |comptime_token| {
1229 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_token));
1230 }
1231 try stream.print("{} ", self.tokenizer.getTokenSlice(var_decl.mut_token));
1232 try stream.print("{}", self.tokenizer.getTokenSlice(var_decl.name_token));
12333299
3300 RenderState.VarDecl => |var_decl| {
1234 try stack.append(RenderState { .Text = ";" });3301 try stack.append(RenderState { .Text = ";" });
1235 if (var_decl.init_node) |init_node| {3302 if (var_decl.init_node) |init_node| {
1236 try stack.append(RenderState { .Expression = init_node });3303 try stack.append(RenderState { .Expression = init_node });
...@@ -1242,8 +3309,30 @@ pub const Parser = struct {...@@ -1242,8 +3309,30 @@ pub const Parser = struct {
1242 try stack.append(RenderState { .Text = " align(" });3309 try stack.append(RenderState { .Text = " align(" });
1243 }3310 }
1244 if (var_decl.type_node) |type_node| {3311 if (var_decl.type_node) |type_node| {
1245 try stream.print(": ");
1246 try stack.append(RenderState { .Expression = type_node });3312 try stack.append(RenderState { .Expression = type_node });
3313 try stack.append(RenderState { .Text = ": " });
3314 }
3315 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.name_token) });
3316 try stack.append(RenderState { .Text = " " });
3317 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(var_decl.mut_token) });
3318
3319 if (var_decl.comptime_token) |comptime_token| {
3320 try stack.append(RenderState { .Text = " " });
3321 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) });
3322 }
3323
3324 if (var_decl.extern_export_token) |extern_export_token| {
3325 if (var_decl.lib_name != null) {
3326 try stack.append(RenderState { .Text = " " });
3327 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
3328 }
3329 try stack.append(RenderState { .Text = " " });
3330 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) });
3331 }
3332
3333 if (var_decl.visib_token) |visib_token| {
3334 try stack.append(RenderState { .Text = " " });
3335 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
1247 }3336 }
1248 },3337 },
12493338
...@@ -1270,10 +3359,14 @@ pub const Parser = struct {...@@ -1270,10 +3359,14 @@ pub const Parser = struct {
1270 RenderState.Expression => |base| switch (base.id) {3359 RenderState.Expression => |base| switch (base.id) {
1271 ast.Node.Id.Identifier => {3360 ast.Node.Id.Identifier => {
1272 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);3361 const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base);
1273 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token));3362 try stream.print("{}", self.tokenizer.getTokenSlice(identifier.token));
1274 },3363 },
1275 ast.Node.Id.Block => {3364 ast.Node.Id.Block => {
1276 const block = @fieldParentPtr(ast.NodeBlock, "base", base);3365 const block = @fieldParentPtr(ast.NodeBlock, "base", base);
3366 if (block.label) |label| {
3367 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
3368 }
3369
1277 if (block.statements.len == 0) {3370 if (block.statements.len == 0) {
1278 try stream.write("{}");3371 try stream.write("{}");
1279 } else {3372 } else {
...@@ -1292,10 +3385,9 @@ pub const Parser = struct {...@@ -1292,10 +3385,9 @@ pub const Parser = struct {
1292 try stack.append(RenderState {3385 try stack.append(RenderState {
1293 .Text = blk: {3386 .Text = blk: {
1294 if (i != 0) {3387 if (i != 0) {
1295 const prev_statement_node = block.statements.items[i - 1];3388 const prev_node = block.statements.items[i - 1];
1296 const prev_line_index = prev_statement_node.lastToken().line;3389 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, statement_node.firstToken());
1297 const this_line_index = statement_node.firstToken().line;3390 if (loc.line >= 2) {
1298 if (this_line_index - prev_line_index >= 2) {
1299 break :blk "\n\n";3391 break :blk "\n\n";
1300 }3392 }
1301 }3393 }
...@@ -1305,54 +3397,99 @@ pub const Parser = struct {...@@ -1305,54 +3397,99 @@ pub const Parser = struct {
1305 }3397 }
1306 }3398 }
1307 },3399 },
3400 ast.Node.Id.Defer => {
3401 const defer_node = @fieldParentPtr(ast.NodeDefer, "base", base);
3402 try stream.print("{} ", self.tokenizer.getTokenSlice(defer_node.defer_token));
3403 try stack.append(RenderState { .Expression = defer_node.expr });
3404 },
3405 ast.Node.Id.Comptime => {
3406 const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", base);
3407 try stream.print("{} ", self.tokenizer.getTokenSlice(comptime_node.comptime_token));
3408 try stack.append(RenderState { .Expression = comptime_node.expr });
3409 },
3410 ast.Node.Id.AsyncAttribute => {
3411 const async_attr = @fieldParentPtr(ast.NodeAsyncAttribute, "base", base);
3412 try stream.print("{}", self.tokenizer.getTokenSlice(async_attr.async_token));
3413
3414 if (async_attr.allocator_type) |allocator_type| {
3415 try stack.append(RenderState { .Text = ">" });
3416 try stack.append(RenderState { .Expression = allocator_type });
3417 try stack.append(RenderState { .Text = "<" });
3418 }
3419 },
3420 ast.Node.Id.Suspend => {
3421 const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", base);
3422 try stream.print("{}", self.tokenizer.getTokenSlice(suspend_node.suspend_token));
3423
3424 if (suspend_node.body) |body| {
3425 try stack.append(RenderState { .Expression = body });
3426 try stack.append(RenderState { .Text = " " });
3427 }
3428
3429 if (suspend_node.payload) |payload| {
3430 try stack.append(RenderState { .Expression = &payload.base });
3431 try stack.append(RenderState { .Text = " " });
3432 }
3433 },
1308 ast.Node.Id.InfixOp => {3434 ast.Node.Id.InfixOp => {
1309 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);3435 const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base);
1310 try stack.append(RenderState { .Expression = prefix_op_node.rhs });3436 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
1311 const text = switch (prefix_op_node.op) {
1312 ast.NodeInfixOp.InfixOp.Add => " + ",
1313 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
1314 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
1315 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
1316 ast.NodeInfixOp.InfixOp.Assign => " = ",
1317 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
1318 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
1319 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
1320 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
1321 ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
1322 ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
1323 ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
1324 ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
1325 ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
1326 ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
1327 ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
1328 ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
1329 ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
1330 ast.NodeInfixOp.InfixOp.BangEqual => " != ",
1331 ast.NodeInfixOp.InfixOp.BitAnd => " & ",
1332 ast.NodeInfixOp.InfixOp.BitOr => " | ",
1333 ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
1334 ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
1335 ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
1336 ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
1337 ast.NodeInfixOp.InfixOp.BoolOr => " or ",
1338 ast.NodeInfixOp.InfixOp.Div => " / ",
1339 ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
1340 ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
1341 ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
1342 ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
1343 ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
1344 ast.NodeInfixOp.InfixOp.LessThan => " < ",
1345 ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
1346 ast.NodeInfixOp.InfixOp.Mod => " % ",
1347 ast.NodeInfixOp.InfixOp.Mult => " * ",
1348 ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
1349 ast.NodeInfixOp.InfixOp.Period => ".",
1350 ast.NodeInfixOp.InfixOp.Sub => " - ",
1351 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
1352 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
1353 };
13543437
1355 try stack.append(RenderState { .Text = text });3438 if (prefix_op_node.op == ast.NodeInfixOp.InfixOp.Catch) {
3439 if (prefix_op_node.op.Catch) |payload| {
3440 try stack.append(RenderState { .Text = " " });
3441 try stack.append(RenderState { .Expression = &payload.base });
3442 }
3443 try stack.append(RenderState { .Text = " catch " });
3444 } else {
3445 const text = switch (prefix_op_node.op) {
3446 ast.NodeInfixOp.InfixOp.Add => " + ",
3447 ast.NodeInfixOp.InfixOp.AddWrap => " +% ",
3448 ast.NodeInfixOp.InfixOp.ArrayCat => " ++ ",
3449 ast.NodeInfixOp.InfixOp.ArrayMult => " ** ",
3450 ast.NodeInfixOp.InfixOp.Assign => " = ",
3451 ast.NodeInfixOp.InfixOp.AssignBitAnd => " &= ",
3452 ast.NodeInfixOp.InfixOp.AssignBitOr => " |= ",
3453 ast.NodeInfixOp.InfixOp.AssignBitShiftLeft => " <<= ",
3454 ast.NodeInfixOp.InfixOp.AssignBitShiftRight => " >>= ",
3455 ast.NodeInfixOp.InfixOp.AssignBitXor => " ^= ",
3456 ast.NodeInfixOp.InfixOp.AssignDiv => " /= ",
3457 ast.NodeInfixOp.InfixOp.AssignMinus => " -= ",
3458 ast.NodeInfixOp.InfixOp.AssignMinusWrap => " -%= ",
3459 ast.NodeInfixOp.InfixOp.AssignMod => " %= ",
3460 ast.NodeInfixOp.InfixOp.AssignPlus => " += ",
3461 ast.NodeInfixOp.InfixOp.AssignPlusWrap => " +%= ",
3462 ast.NodeInfixOp.InfixOp.AssignTimes => " *= ",
3463 ast.NodeInfixOp.InfixOp.AssignTimesWarp => " *%= ",
3464 ast.NodeInfixOp.InfixOp.BangEqual => " != ",
3465 ast.NodeInfixOp.InfixOp.BitAnd => " & ",
3466 ast.NodeInfixOp.InfixOp.BitOr => " | ",
3467 ast.NodeInfixOp.InfixOp.BitShiftLeft => " << ",
3468 ast.NodeInfixOp.InfixOp.BitShiftRight => " >> ",
3469 ast.NodeInfixOp.InfixOp.BitXor => " ^ ",
3470 ast.NodeInfixOp.InfixOp.BoolAnd => " and ",
3471 ast.NodeInfixOp.InfixOp.BoolOr => " or ",
3472 ast.NodeInfixOp.InfixOp.Div => " / ",
3473 ast.NodeInfixOp.InfixOp.EqualEqual => " == ",
3474 ast.NodeInfixOp.InfixOp.ErrorUnion => "!",
3475 ast.NodeInfixOp.InfixOp.GreaterOrEqual => " >= ",
3476 ast.NodeInfixOp.InfixOp.GreaterThan => " > ",
3477 ast.NodeInfixOp.InfixOp.LessOrEqual => " <= ",
3478 ast.NodeInfixOp.InfixOp.LessThan => " < ",
3479 ast.NodeInfixOp.InfixOp.MergeErrorSets => " || ",
3480 ast.NodeInfixOp.InfixOp.Mod => " % ",
3481 ast.NodeInfixOp.InfixOp.Mult => " * ",
3482 ast.NodeInfixOp.InfixOp.MultWrap => " *% ",
3483 ast.NodeInfixOp.InfixOp.Period => ".",
3484 ast.NodeInfixOp.InfixOp.Sub => " - ",
3485 ast.NodeInfixOp.InfixOp.SubWrap => " -% ",
3486 ast.NodeInfixOp.InfixOp.UnwrapMaybe => " ?? ",
3487 ast.NodeInfixOp.InfixOp.Range => " ... ",
3488 ast.NodeInfixOp.InfixOp.Catch => unreachable,
3489 };
3490
3491 try stack.append(RenderState { .Text = text });
3492 }
1356 try stack.append(RenderState { .Expression = prefix_op_node.lhs });3493 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
1357 },3494 },
1358 ast.Node.Id.PrefixOp => {3495 ast.Node.Id.PrefixOp => {
...@@ -1373,15 +3510,179 @@ pub const Parser = struct {...@@ -1373,15 +3510,179 @@ pub const Parser = struct {
1373 try stack.append(RenderState { .Expression = align_expr});3510 try stack.append(RenderState { .Expression = align_expr});
1374 }3511 }
1375 },3512 },
3513 ast.NodePrefixOp.PrefixOp.SliceType => |addr_of_info| {
3514 try stream.write("[]");
3515 if (addr_of_info.volatile_token != null) {
3516 try stack.append(RenderState { .Text = "volatile "});
3517 }
3518 if (addr_of_info.const_token != null) {
3519 try stack.append(RenderState { .Text = "const "});
3520 }
3521 if (addr_of_info.align_expr) |align_expr| {
3522 try stream.print("align(");
3523 try stack.append(RenderState { .Text = ") "});
3524 try stack.append(RenderState { .Expression = align_expr});
3525 }
3526 },
3527 ast.NodePrefixOp.PrefixOp.ArrayType => |array_index| {
3528 try stack.append(RenderState { .Text = "]"});
3529 try stack.append(RenderState { .Expression = array_index});
3530 try stack.append(RenderState { .Text = "["});
3531 },
1376 ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"),3532 ast.NodePrefixOp.PrefixOp.BitNot => try stream.write("~"),
1377 ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"),3533 ast.NodePrefixOp.PrefixOp.BoolNot => try stream.write("!"),
1378 ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"),3534 ast.NodePrefixOp.PrefixOp.Deref => try stream.write("*"),
1379 ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"),3535 ast.NodePrefixOp.PrefixOp.Negation => try stream.write("-"),
1380 ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"),3536 ast.NodePrefixOp.PrefixOp.NegationWrap => try stream.write("-%"),
1381 ast.NodePrefixOp.PrefixOp.Return => try stream.write("return "),
1382 ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "),3537 ast.NodePrefixOp.PrefixOp.Try => try stream.write("try "),
1383 ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"),3538 ast.NodePrefixOp.PrefixOp.UnwrapMaybe => try stream.write("??"),
3539 ast.NodePrefixOp.PrefixOp.MaybeType => try stream.write("?"),
3540 ast.NodePrefixOp.PrefixOp.Await => try stream.write("await "),
3541 ast.NodePrefixOp.PrefixOp.Cancel => try stream.write("cancel "),
3542 ast.NodePrefixOp.PrefixOp.Resume => try stream.write("resume "),
3543 }
3544 },
3545 ast.Node.Id.SuffixOp => {
3546 const suffix_op = @fieldParentPtr(ast.NodeSuffixOp, "base", base);
3547
3548 switch (suffix_op.op) {
3549 ast.NodeSuffixOp.SuffixOp.Call => |call_info| {
3550 try stack.append(RenderState { .Text = ")"});
3551 var i = call_info.params.len;
3552 while (i != 0) {
3553 i -= 1;
3554 const param_node = call_info.params.at(i);
3555 try stack.append(RenderState { .Expression = param_node});
3556 if (i != 0) {
3557 try stack.append(RenderState { .Text = ", " });
3558 }
3559 }
3560 try stack.append(RenderState { .Text = "("});
3561 try stack.append(RenderState { .Expression = suffix_op.lhs });
3562
3563 if (call_info.async_attr) |async_attr| {
3564 try stack.append(RenderState { .Text = " "});
3565 try stack.append(RenderState { .Expression = &async_attr.base });
3566 }
3567 },
3568 ast.NodeSuffixOp.SuffixOp.ArrayAccess => |index_expr| {
3569 try stack.append(RenderState { .Text = "]"});
3570 try stack.append(RenderState { .Expression = index_expr});
3571 try stack.append(RenderState { .Text = "["});
3572 try stack.append(RenderState { .Expression = suffix_op.lhs });
3573 },
3574 ast.NodeSuffixOp.SuffixOp.Slice => |range| {
3575 try stack.append(RenderState { .Text = "]"});
3576 if (range.end) |end| {
3577 try stack.append(RenderState { .Expression = end});
3578 }
3579 try stack.append(RenderState { .Text = ".."});
3580 try stack.append(RenderState { .Expression = range.start});
3581 try stack.append(RenderState { .Text = "["});
3582 try stack.append(RenderState { .Expression = suffix_op.lhs });
3583 },
3584 ast.NodeSuffixOp.SuffixOp.StructInitializer => |field_inits| {
3585 try stack.append(RenderState { .Text = " }"});
3586 var i = field_inits.len;
3587 while (i != 0) {
3588 i -= 1;
3589 const field_init = field_inits.at(i);
3590 try stack.append(RenderState { .FieldInitializer = field_init });
3591 try stack.append(RenderState { .Text = " " });
3592 if (i != 0) {
3593 try stack.append(RenderState { .Text = "," });
3594 }
3595 }
3596 try stack.append(RenderState { .Text = "{"});
3597 try stack.append(RenderState { .Expression = suffix_op.lhs });
3598 },
3599 ast.NodeSuffixOp.SuffixOp.ArrayInitializer => |exprs| {
3600 try stack.append(RenderState { .Text = " }"});
3601 var i = exprs.len;
3602 while (i != 0) {
3603 i -= 1;
3604 const expr = exprs.at(i);
3605 try stack.append(RenderState { .Expression = expr });
3606 try stack.append(RenderState { .Text = " " });
3607 if (i != 0) {
3608 try stack.append(RenderState { .Text = "," });
3609 }
3610 }
3611 try stack.append(RenderState { .Text = "{"});
3612 try stack.append(RenderState { .Expression = suffix_op.lhs });
3613 },
3614 }
3615 },
3616 ast.Node.Id.ControlFlowExpression => {
3617 const flow_expr = @fieldParentPtr(ast.NodeControlFlowExpression, "base", base);
3618 switch (flow_expr.kind) {
3619 ast.NodeControlFlowExpression.Kind.Break => |maybe_blk_token| {
3620 try stream.print("break");
3621 if (maybe_blk_token) |blk_token| {
3622 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3623 }
3624 },
3625 ast.NodeControlFlowExpression.Kind.Continue => |maybe_blk_token| {
3626 try stream.print("continue");
3627 if (maybe_blk_token) |blk_token| {
3628 try stream.print(" :{}", self.tokenizer.getTokenSlice(blk_token));
3629 }
3630 },
3631 ast.NodeControlFlowExpression.Kind.Return => {
3632 try stream.print("return");
3633 },
3634
3635 }
3636
3637 if (flow_expr.rhs) |rhs| {
3638 try stream.print(" ");
3639 try stack.append(RenderState { .Expression = rhs });
3640 }
3641 },
3642 ast.Node.Id.Payload => {
3643 const payload = @fieldParentPtr(ast.NodePayload, "base", base);
3644 try stack.append(RenderState { .Text = "|"});
3645 try stack.append(RenderState { .Expression = &payload.error_symbol.base });
3646 try stack.append(RenderState { .Text = "|"});
3647 },
3648 ast.Node.Id.PointerPayload => {
3649 const payload = @fieldParentPtr(ast.NodePointerPayload, "base", base);
3650 try stack.append(RenderState { .Text = "|"});
3651 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3652
3653 if (payload.is_ptr) {
3654 try stack.append(RenderState { .Text = "*"});
3655 }
3656
3657 try stack.append(RenderState { .Text = "|"});
3658 },
3659 ast.Node.Id.PointerIndexPayload => {
3660 const payload = @fieldParentPtr(ast.NodePointerIndexPayload, "base", base);
3661 try stack.append(RenderState { .Text = "|"});
3662
3663 if (payload.index_symbol) |index_symbol| {
3664 try stack.append(RenderState { .Expression = &index_symbol.base });
3665 try stack.append(RenderState { .Text = ", "});
1384 }3666 }
3667
3668 try stack.append(RenderState { .Expression = &payload.value_symbol.base });
3669
3670 if (payload.is_ptr) {
3671 try stack.append(RenderState { .Text = "*"});
3672 }
3673
3674 try stack.append(RenderState { .Text = "|"});
3675 },
3676 ast.Node.Id.GroupedExpression => {
3677 const grouped_expr = @fieldParentPtr(ast.NodeGroupedExpression, "base", base);
3678 try stack.append(RenderState { .Text = ")"});
3679 try stack.append(RenderState { .Expression = grouped_expr.expr });
3680 try stack.append(RenderState { .Text = "("});
3681 },
3682 ast.Node.Id.FieldInitializer => {
3683 const field_init = @fieldParentPtr(ast.NodeFieldInitializer, "base", base);
3684 try stream.print(".{} = ", self.tokenizer.getTokenSlice(field_init.name_token));
3685 try stack.append(RenderState { .Expression = field_init.expr });
1385 },3686 },
1386 ast.Node.Id.IntegerLiteral => {3687 ast.Node.Id.IntegerLiteral => {
1387 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);3688 const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base);
...@@ -1395,6 +3696,147 @@ pub const Parser = struct {...@@ -1395,6 +3696,147 @@ pub const Parser = struct {
1395 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);3696 const string_literal = @fieldParentPtr(ast.NodeStringLiteral, "base", base);
1396 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));3697 try stream.print("{}", self.tokenizer.getTokenSlice(string_literal.token));
1397 },3698 },
3699 ast.Node.Id.CharLiteral => {
3700 const char_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3701 try stream.print("{}", self.tokenizer.getTokenSlice(char_literal.token));
3702 },
3703 ast.Node.Id.BoolLiteral => {
3704 const bool_literal = @fieldParentPtr(ast.NodeCharLiteral, "base", base);
3705 try stream.print("{}", self.tokenizer.getTokenSlice(bool_literal.token));
3706 },
3707 ast.Node.Id.NullLiteral => {
3708 const null_literal = @fieldParentPtr(ast.NodeNullLiteral, "base", base);
3709 try stream.print("{}", self.tokenizer.getTokenSlice(null_literal.token));
3710 },
3711 ast.Node.Id.ThisLiteral => {
3712 const this_literal = @fieldParentPtr(ast.NodeThisLiteral, "base", base);
3713 try stream.print("{}", self.tokenizer.getTokenSlice(this_literal.token));
3714 },
3715 ast.Node.Id.Unreachable => {
3716 const unreachable_node = @fieldParentPtr(ast.NodeUnreachable, "base", base);
3717 try stream.print("{}", self.tokenizer.getTokenSlice(unreachable_node.token));
3718 },
3719 ast.Node.Id.ErrorType => {
3720 const error_type = @fieldParentPtr(ast.NodeErrorType, "base", base);
3721 try stream.print("{}", self.tokenizer.getTokenSlice(error_type.token));
3722 },
3723 ast.Node.Id.VarType => {
3724 const var_type = @fieldParentPtr(ast.NodeVarType, "base", base);
3725 try stream.print("{}", self.tokenizer.getTokenSlice(var_type.token));
3726 },
3727 ast.Node.Id.ContainerDecl => {
3728 const container_decl = @fieldParentPtr(ast.NodeContainerDecl, "base", base);
3729
3730 switch (container_decl.layout) {
3731 ast.NodeContainerDecl.Layout.Packed => try stream.print("packed "),
3732 ast.NodeContainerDecl.Layout.Extern => try stream.print("extern "),
3733 ast.NodeContainerDecl.Layout.Auto => { },
3734 }
3735
3736 switch (container_decl.kind) {
3737 ast.NodeContainerDecl.Kind.Struct => try stream.print("struct"),
3738 ast.NodeContainerDecl.Kind.Enum => try stream.print("enum"),
3739 ast.NodeContainerDecl.Kind.Union => try stream.print("union"),
3740 }
3741
3742 try stack.append(RenderState { .Text = "}"});
3743 try stack.append(RenderState.PrintIndent);
3744 try stack.append(RenderState { .Indent = indent });
3745 try stack.append(RenderState { .Text = "\n"});
3746
3747 const fields_and_decls = container_decl.fields_and_decls.toSliceConst();
3748 var i = fields_and_decls.len;
3749 while (i != 0) {
3750 i -= 1;
3751 const node = fields_and_decls[i];
3752 try stack.append(RenderState { .TopLevelDecl = node});
3753 try stack.append(RenderState.PrintIndent);
3754 try stack.append(RenderState {
3755 .Text = blk: {
3756 if (i != 0) {
3757 const prev_node = fields_and_decls[i - 1];
3758 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3759 if (loc.line >= 2) {
3760 break :blk "\n\n";
3761 }
3762 }
3763 break :blk "\n";
3764 },
3765 });
3766
3767 if (i != 0) {
3768 const prev_node = fields_and_decls[i - 1];
3769 switch (prev_node.id) {
3770 ast.Node.Id.StructField,
3771 ast.Node.Id.UnionTag,
3772 ast.Node.Id.EnumTag => {
3773 try stack.append(RenderState { .Text = "," });
3774 },
3775 else => { }
3776 }
3777 }
3778 }
3779 try stack.append(RenderState { .Indent = indent + indent_delta});
3780 try stack.append(RenderState { .Text = "{"});
3781
3782 switch (container_decl.init_arg_expr) {
3783 ast.NodeContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
3784 ast.NodeContainerDecl.InitArg.Enum => try stack.append(RenderState { .Text = "(enum) "}),
3785 ast.NodeContainerDecl.InitArg.Type => |type_expr| {
3786 try stack.append(RenderState { .Text = ") "});
3787 try stack.append(RenderState { .Expression = type_expr});
3788 try stack.append(RenderState { .Text = "("});
3789 },
3790 }
3791 },
3792 ast.Node.Id.ErrorSetDecl => {
3793 const err_set_decl = @fieldParentPtr(ast.NodeErrorSetDecl, "base", base);
3794 try stream.print("error ");
3795
3796 try stack.append(RenderState { .Text = "}"});
3797 try stack.append(RenderState.PrintIndent);
3798 try stack.append(RenderState { .Indent = indent });
3799 try stack.append(RenderState { .Text = "\n"});
3800
3801 const decls = err_set_decl.decls.toSliceConst();
3802 var i = decls.len;
3803 while (i != 0) {
3804 i -= 1;
3805 const node = decls[i];
3806 try stack.append(RenderState { .Expression = &node.base});
3807 try stack.append(RenderState.PrintIndent);
3808 try stack.append(RenderState {
3809 .Text = blk: {
3810 if (i != 0) {
3811 const prev_node = decls[i - 1];
3812 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3813 if (loc.line >= 2) {
3814 break :blk "\n\n";
3815 }
3816 }
3817 break :blk "\n";
3818 },
3819 });
3820
3821 if (i != 0) {
3822 try stack.append(RenderState { .Text = "," });
3823 }
3824 }
3825 try stack.append(RenderState { .Indent = indent + indent_delta});
3826 try stack.append(RenderState { .Text = "{"});
3827 },
3828 ast.Node.Id.MultilineStringLiteral => {
3829 const multiline_str_literal = @fieldParentPtr(ast.NodeMultilineStringLiteral, "base", base);
3830 try stream.print("\n");
3831
3832 var i : usize = 0;
3833 while (i < multiline_str_literal.tokens.len) : (i += 1) {
3834 const t = multiline_str_literal.tokens.at(i);
3835 try stream.writeByteNTimes(' ', indent + indent_delta);
3836 try stream.print("{}", self.tokenizer.getTokenSlice(t));
3837 }
3838 try stream.writeByteNTimes(' ', indent + indent_delta);
3839 },
1398 ast.Node.Id.UndefinedLiteral => {3840 ast.Node.Id.UndefinedLiteral => {
1399 const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);3841 const undefined_literal = @fieldParentPtr(ast.NodeUndefinedLiteral, "base", base);
1400 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));3842 try stream.print("{}", self.tokenizer.getTokenSlice(undefined_literal.token));
...@@ -1413,26 +3855,419 @@ pub const Parser = struct {...@@ -1413,26 +3855,419 @@ pub const Parser = struct {
1413 }3855 }
1414 }3856 }
1415 },3857 },
1416 ast.Node.Id.Call => {3858 ast.Node.Id.FnProto => {
1417 const call = @fieldParentPtr(ast.NodeCall, "base", base);3859 const fn_proto = @fieldParentPtr(ast.NodeFnProto, "base", base);
3860
3861 switch (fn_proto.return_type) {
3862 ast.NodeFnProto.ReturnType.Explicit => |node| {
3863 try stack.append(RenderState { .Expression = node});
3864 },
3865 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
3866 try stack.append(RenderState { .Expression = node});
3867 try stack.append(RenderState { .Text = "!"});
3868 },
3869 }
3870
3871 if (fn_proto.align_expr != null) {
3872 @panic("TODO");
3873 }
3874
3875 try stack.append(RenderState { .Text = ") " });
3876 var i = fn_proto.params.len;
3877 while (i != 0) {
3878 i -= 1;
3879 const param_decl_node = fn_proto.params.items[i];
3880 try stack.append(RenderState { .ParamDecl = param_decl_node});
3881 if (i != 0) {
3882 try stack.append(RenderState { .Text = ", " });
3883 }
3884 }
3885
3886 try stack.append(RenderState { .Text = "(" });
3887 if (fn_proto.name_token) |name_token| {
3888 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(name_token) });
3889 try stack.append(RenderState { .Text = " " });
3890 }
3891
3892 try stack.append(RenderState { .Text = "fn" });
3893
3894 if (fn_proto.async_attr) |async_attr| {
3895 try stack.append(RenderState { .Text = " " });
3896 try stack.append(RenderState { .Expression = &async_attr.base });
3897 }
3898
3899 if (fn_proto.cc_token) |cc_token| {
3900 try stack.append(RenderState { .Text = " " });
3901 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(cc_token) });
3902 }
3903
3904 if (fn_proto.lib_name) |lib_name| {
3905 try stack.append(RenderState { .Text = " " });
3906 try stack.append(RenderState { .Expression = lib_name });
3907 }
3908 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
3909 try stack.append(RenderState { .Text = " " });
3910 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) });
3911 }
3912
3913 if (fn_proto.visib_token) |visib_token| {
3914 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
3915 try stack.append(RenderState { .Text = " " });
3916 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(visib_token) });
3917 }
3918 },
3919 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
3920 ast.Node.Id.Switch => {
3921 const switch_node = @fieldParentPtr(ast.NodeSwitch, "base", base);
3922 try stream.print("{} (", self.tokenizer.getTokenSlice(switch_node.switch_token));
3923
3924 try stack.append(RenderState { .Text = "}"});
3925 try stack.append(RenderState.PrintIndent);
3926 try stack.append(RenderState { .Indent = indent });
3927 try stack.append(RenderState { .Text = "\n"});
3928
3929 const cases = switch_node.cases.toSliceConst();
3930 var i = cases.len;
3931 while (i != 0) {
3932 i -= 1;
3933 const node = cases[i];
3934 try stack.append(RenderState { .Expression = &node.base});
3935 try stack.append(RenderState.PrintIndent);
3936 try stack.append(RenderState {
3937 .Text = blk: {
3938 if (i != 0) {
3939 const prev_node = cases[i - 1];
3940 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
3941 if (loc.line >= 2) {
3942 break :blk "\n\n";
3943 }
3944 }
3945 break :blk "\n";
3946 },
3947 });
3948
3949 if (i != 0) {
3950 try stack.append(RenderState { .Text = "," });
3951 }
3952 }
3953 try stack.append(RenderState { .Indent = indent + indent_delta});
3954 try stack.append(RenderState { .Text = ") {"});
3955 try stack.append(RenderState { .Expression = switch_node.expr });
3956 },
3957 ast.Node.Id.SwitchCase => {
3958 const switch_case = @fieldParentPtr(ast.NodeSwitchCase, "base", base);
3959
3960 try stack.append(RenderState { .Expression = switch_case.expr });
3961 if (switch_case.payload) |payload| {
3962 try stack.append(RenderState { .Text = " " });
3963 try stack.append(RenderState { .Expression = &payload.base });
3964 }
3965 try stack.append(RenderState { .Text = " => "});
3966
3967 const items = switch_case.items.toSliceConst();
3968 var i = items.len;
3969 while (i != 0) {
3970 i -= 1;
3971 try stack.append(RenderState { .Expression = items[i] });
3972
3973 if (i != 0) {
3974 try stack.append(RenderState { .Text = ", " });
3975 }
3976 }
3977 },
3978 ast.Node.Id.SwitchElse => {
3979 const switch_else = @fieldParentPtr(ast.NodeSwitchElse, "base", base);
3980 try stream.print("{}", self.tokenizer.getTokenSlice(switch_else.token));
3981 },
3982 ast.Node.Id.Else => {
3983 const else_node = @fieldParentPtr(ast.NodeElse, "base", base);
3984 try stream.print("{}", self.tokenizer.getTokenSlice(else_node.else_token));
3985
3986 switch (else_node.body.id) {
3987 ast.Node.Id.Block, ast.Node.Id.If,
3988 ast.Node.Id.For, ast.Node.Id.While,
3989 ast.Node.Id.Switch => {
3990 try stream.print(" ");
3991 try stack.append(RenderState { .Expression = else_node.body });
3992 },
3993 else => {
3994 try stack.append(RenderState { .Indent = indent });
3995 try stack.append(RenderState { .Expression = else_node.body });
3996 try stack.append(RenderState.PrintIndent);
3997 try stack.append(RenderState { .Indent = indent + indent_delta });
3998 try stack.append(RenderState { .Text = "\n" });
3999 }
4000 }
4001
4002 if (else_node.payload) |payload| {
4003 try stack.append(RenderState { .Text = " " });
4004 try stack.append(RenderState { .Expression = &payload.base });
4005 }
4006 },
4007 ast.Node.Id.While => {
4008 const while_node = @fieldParentPtr(ast.NodeWhile, "base", base);
4009 if (while_node.label) |label| {
4010 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4011 }
4012
4013 if (while_node.inline_token) |inline_token| {
4014 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4015 }
4016
4017 try stream.print("{} ", self.tokenizer.getTokenSlice(while_node.while_token));
4018
4019 if (while_node.@"else") |@"else"| {
4020 try stack.append(RenderState { .Expression = &@"else".base });
4021
4022 if (while_node.body.id == ast.Node.Id.Block) {
4023 try stack.append(RenderState { .Text = " " });
4024 } else {
4025 try stack.append(RenderState.PrintIndent);
4026 try stack.append(RenderState { .Text = "\n" });
4027 }
4028 }
4029
4030 if (while_node.body.id == ast.Node.Id.Block) {
4031 try stack.append(RenderState { .Expression = while_node.body });
4032 try stack.append(RenderState { .Text = " " });
4033 } else {
4034 try stack.append(RenderState { .Indent = indent });
4035 try stack.append(RenderState { .Expression = while_node.body });
4036 try stack.append(RenderState.PrintIndent);
4037 try stack.append(RenderState { .Indent = indent + indent_delta });
4038 try stack.append(RenderState { .Text = "\n" });
4039 }
4040
4041 if (while_node.continue_expr) |continue_expr| {
4042 try stack.append(RenderState { .Text = ")" });
4043 try stack.append(RenderState { .Expression = continue_expr });
4044 try stack.append(RenderState { .Text = ": (" });
4045 try stack.append(RenderState { .Text = " " });
4046 }
4047
4048 if (while_node.payload) |payload| {
4049 try stack.append(RenderState { .Expression = &payload.base });
4050 try stack.append(RenderState { .Text = " " });
4051 }
4052
4053 try stack.append(RenderState { .Text = ")" });
4054 try stack.append(RenderState { .Expression = while_node.condition });
4055 try stack.append(RenderState { .Text = "(" });
4056 },
4057 ast.Node.Id.For => {
4058 const for_node = @fieldParentPtr(ast.NodeFor, "base", base);
4059 if (for_node.label) |label| {
4060 try stream.print("{}: ", self.tokenizer.getTokenSlice(label));
4061 }
4062
4063 if (for_node.inline_token) |inline_token| {
4064 try stream.print("{} ", self.tokenizer.getTokenSlice(inline_token));
4065 }
4066
4067 try stream.print("{} ", self.tokenizer.getTokenSlice(for_node.for_token));
4068
4069 if (for_node.@"else") |@"else"| {
4070 try stack.append(RenderState { .Expression = &@"else".base });
4071
4072 if (for_node.body.id == ast.Node.Id.Block) {
4073 try stack.append(RenderState { .Text = " " });
4074 } else {
4075 try stack.append(RenderState.PrintIndent);
4076 try stack.append(RenderState { .Text = "\n" });
4077 }
4078 }
4079
4080 if (for_node.body.id == ast.Node.Id.Block) {
4081 try stack.append(RenderState { .Expression = for_node.body });
4082 try stack.append(RenderState { .Text = " " });
4083 } else {
4084 try stack.append(RenderState { .Indent = indent });
4085 try stack.append(RenderState { .Expression = for_node.body });
4086 try stack.append(RenderState.PrintIndent);
4087 try stack.append(RenderState { .Indent = indent + indent_delta });
4088 try stack.append(RenderState { .Text = "\n" });
4089 }
4090
4091 if (for_node.payload) |payload| {
4092 try stack.append(RenderState { .Expression = &payload.base });
4093 try stack.append(RenderState { .Text = " " });
4094 }
4095
4096 try stack.append(RenderState { .Text = ")" });
4097 try stack.append(RenderState { .Expression = for_node.array_expr });
4098 try stack.append(RenderState { .Text = "(" });
4099 },
4100 ast.Node.Id.If => {
4101 const if_node = @fieldParentPtr(ast.NodeIf, "base", base);
4102 try stream.print("{} ", self.tokenizer.getTokenSlice(if_node.if_token));
4103
4104 switch (if_node.body.id) {
4105 ast.Node.Id.Block, ast.Node.Id.If,
4106 ast.Node.Id.For, ast.Node.Id.While,
4107 ast.Node.Id.Switch => {
4108 if (if_node.@"else") |@"else"| {
4109 try stack.append(RenderState { .Expression = &@"else".base });
4110
4111 if (if_node.body.id == ast.Node.Id.Block) {
4112 try stack.append(RenderState { .Text = " " });
4113 } else {
4114 try stack.append(RenderState.PrintIndent);
4115 try stack.append(RenderState { .Text = "\n" });
4116 }
4117 }
4118 },
4119 else => {
4120 if (if_node.@"else") |@"else"| {
4121 try stack.append(RenderState { .Expression = @"else".body });
4122
4123 if (@"else".payload) |payload| {
4124 try stack.append(RenderState { .Text = " " });
4125 try stack.append(RenderState { .Expression = &payload.base });
4126 }
4127
4128 try stack.append(RenderState { .Text = " " });
4129 try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(@"else".else_token) });
4130 try stack.append(RenderState { .Text = " " });
4131 }
4132 }
4133 }
4134
4135 try stack.append(RenderState { .Expression = if_node.body });
4136 try stack.append(RenderState { .Text = " " });
4137
4138 if (if_node.payload) |payload| {
4139 try stack.append(RenderState { .Expression = &payload.base });
4140 try stack.append(RenderState { .Text = " " });
4141 }
4142
4143 try stack.append(RenderState { .Text = ")" });
4144 try stack.append(RenderState { .Expression = if_node.condition });
4145 try stack.append(RenderState { .Text = "(" });
4146 },
4147 ast.Node.Id.Asm => {
4148 const asm_node = @fieldParentPtr(ast.NodeAsm, "base", base);
4149 try stream.print("{} ", self.tokenizer.getTokenSlice(asm_node.asm_token));
4150
4151 if (asm_node.is_volatile) {
4152 try stream.write("volatile ");
4153 }
4154
4155 try stack.append(RenderState { .Indent = indent });
4156 try stack.append(RenderState { .Text = ")" });
4157 {
4158 const cloppers = asm_node.cloppers.toSliceConst();
4159 var i = cloppers.len;
4160 while (i != 0) {
4161 i -= 1;
4162 try stack.append(RenderState { .Expression = cloppers[i] });
4163
4164 if (i != 0) {
4165 try stack.append(RenderState { .Text = ", " });
4166 }
4167 }
4168 }
4169 try stack.append(RenderState { .Text = ": " });
4170 try stack.append(RenderState.PrintIndent);
4171 try stack.append(RenderState { .Indent = indent + indent_delta });
4172 try stack.append(RenderState { .Text = "\n" });
4173 {
4174 const inputs = asm_node.inputs.toSliceConst();
4175 var i = inputs.len;
4176 while (i != 0) {
4177 i -= 1;
4178 const node = inputs[i];
4179 try stack.append(RenderState { .Expression = &node.base});
4180
4181 if (i != 0) {
4182 try stack.append(RenderState.PrintIndent);
4183 try stack.append(RenderState {
4184 .Text = blk: {
4185 const prev_node = inputs[i - 1];
4186 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4187 if (loc.line >= 2) {
4188 break :blk "\n\n";
4189 }
4190 break :blk "\n";
4191 },
4192 });
4193 try stack.append(RenderState { .Text = "," });
4194 }
4195 }
4196 }
4197 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4198 try stack.append(RenderState { .Text = ": "});
4199 try stack.append(RenderState.PrintIndent);
4200 try stack.append(RenderState { .Indent = indent + indent_delta});
4201 try stack.append(RenderState { .Text = "\n" });
4202 {
4203 const outputs = asm_node.outputs.toSliceConst();
4204 var i = outputs.len;
4205 while (i != 0) {
4206 i -= 1;
4207 const node = outputs[i];
4208 try stack.append(RenderState { .Expression = &node.base});
4209
4210 if (i != 0) {
4211 try stack.append(RenderState.PrintIndent);
4212 try stack.append(RenderState {
4213 .Text = blk: {
4214 const prev_node = outputs[i - 1];
4215 const loc = self.tokenizer.getTokenLocation(prev_node.lastToken().end, node.firstToken());
4216 if (loc.line >= 2) {
4217 break :blk "\n\n";
4218 }
4219 break :blk "\n";
4220 },
4221 });
4222 try stack.append(RenderState { .Text = "," });
4223 }
4224 }
4225 }
4226 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
4227 try stack.append(RenderState { .Text = ": "});
4228 try stack.append(RenderState.PrintIndent);
4229 try stack.append(RenderState { .Indent = indent + indent_delta});
4230 try stack.append(RenderState { .Text = "\n" });
4231 try stack.append(RenderState { .Expression = asm_node.template });
4232 try stack.append(RenderState { .Text = "(" });
4233 },
4234 ast.Node.Id.AsmInput => {
4235 const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base);
4236
4237 try stack.append(RenderState { .Text = ")"});
4238 try stack.append(RenderState { .Expression = asm_input.expr});
4239 try stack.append(RenderState { .Text = " ("});
4240 try stack.append(RenderState { .Expression = asm_input.constraint });
4241 try stack.append(RenderState { .Text = "] "});
4242 try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base});
4243 try stack.append(RenderState { .Text = "["});
4244 },
4245 ast.Node.Id.AsmOutput => {
4246 const asm_output = @fieldParentPtr(ast.NodeAsmOutput, "base", base);
4247
1418 try stack.append(RenderState { .Text = ")"});4248 try stack.append(RenderState { .Text = ")"});
1419 var i = call.params.len;4249 switch (asm_output.kind) {
1420 while (i != 0) {4250 ast.NodeAsmOutput.Kind.Variable => |variable_name| {
1421 i -= 1;4251 try stack.append(RenderState { .Expression = &variable_name.base});
1422 const param_node = call.params.at(i);4252 },
1423 try stack.append(RenderState { .Expression = param_node});4253 ast.NodeAsmOutput.Kind.Return => |return_type| {
1424 if (i != 0) {4254 try stack.append(RenderState { .Expression = return_type});
1425 try stack.append(RenderState { .Text = ", " });4255 try stack.append(RenderState { .Text = "-> "});
1426 }4256 },
1427 }4257 }
1428 try stack.append(RenderState { .Text = "("});4258 try stack.append(RenderState { .Text = " ("});
1429 try stack.append(RenderState { .Expression = call.callee });4259 try stack.append(RenderState { .Expression = asm_output.constraint });
4260 try stack.append(RenderState { .Text = "] "});
4261 try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base});
4262 try stack.append(RenderState { .Text = "["});
1430 },4263 },
1431 ast.Node.Id.FnProto => @panic("TODO fn proto in an expression"),
1432 ast.Node.Id.LineComment => @panic("TODO render line comment in an expression"),
14334264
4265 ast.Node.Id.StructField,
4266 ast.Node.Id.UnionTag,
4267 ast.Node.Id.EnumTag,
1434 ast.Node.Id.Root,4268 ast.Node.Id.Root,
1435 ast.Node.Id.VarDecl,4269 ast.Node.Id.VarDecl,
4270 ast.Node.Id.Use,
1436 ast.Node.Id.TestDecl,4271 ast.Node.Id.TestDecl,
1437 ast.Node.Id.ParamDecl => unreachable,4272 ast.Node.Id.ParamDecl => unreachable,
1438 },4273 },
...@@ -1450,9 +4285,6 @@ pub const Parser = struct {...@@ -1450,9 +4285,6 @@ pub const Parser = struct {
1450 ast.NodeFnProto.ReturnType.Explicit => |node| {4285 ast.NodeFnProto.ReturnType.Explicit => |node| {
1451 try stack.append(RenderState { .Expression = node});4286 try stack.append(RenderState { .Expression = node});
1452 },4287 },
1453 ast.NodeFnProto.ReturnType.Infer => {
1454 try stream.print("var");
1455 },
1456 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {4288 ast.NodeFnProto.ReturnType.InferErrorSet => |node| {
1457 try stream.print("!");4289 try stream.print("!");
1458 try stack.append(RenderState { .Expression = node});4290 try stack.append(RenderState { .Expression = node});
...@@ -1472,8 +4304,10 @@ pub const Parser = struct {...@@ -1472,8 +4304,10 @@ pub const Parser = struct {
1472 try stack.append(RenderState { .VarDecl = var_decl});4304 try stack.append(RenderState { .VarDecl = var_decl});
1473 },4305 },
1474 else => {4306 else => {
1475 try stack.append(RenderState { .Text = ";"});4307 if (requireSemiColon(base)) {
1476 try stack.append(RenderState { .Expression = base});4308 try stack.append(RenderState { .Text = ";" });
4309 }
4310 try stack.append(RenderState { .Expression = base });
1477 },4311 },
1478 }4312 }
1479 },4313 },
...@@ -1557,7 +4391,7 @@ fn testCanonical(source: []const u8) !void {...@@ -1557,7 +4391,7 @@ fn testCanonical(source: []const u8) !void {
1557 }4391 }
1558}4392}
15594393
1560test "zig fmt" {4394test "zig fmt: get stdout or fail" {
1561 try testCanonical(4395 try testCanonical(
1562 \\const std = @import("std");4396 \\const std = @import("std");
1563 \\4397 \\
...@@ -1568,7 +4402,9 @@ test "zig fmt" {...@@ -1568,7 +4402,9 @@ test "zig fmt" {
1568 \\}4402 \\}
1569 \\4403 \\
1570 );4404 );
4405}
15714406
4407test "zig fmt: preserve spacing" {
1572 try testCanonical(4408 try testCanonical(
1573 \\const std = @import("std");4409 \\const std = @import("std");
1574 \\4410 \\
...@@ -1581,25 +4417,26 @@ test "zig fmt" {...@@ -1581,25 +4417,26 @@ test "zig fmt" {
1581 \\}4417 \\}
1582 \\4418 \\
1583 );4419 );
4420}
15844421
4422test "zig fmt: return types" {
1585 try testCanonical(4423 try testCanonical(
1586 \\pub fn main() !void {}4424 \\pub fn main() !void {}
1587 \\pub fn main() var {}4425 \\pub fn main() var {}
1588 \\pub fn main() i32 {}4426 \\pub fn main() i32 {}
1589 \\4427 \\
1590 );4428 );
4429}
15914430
4431test "zig fmt: imports" {
1592 try testCanonical(4432 try testCanonical(
1593 \\const std = @import("std");4433 \\const std = @import("std");
1594 \\const std = @import();4434 \\const std = @import();
1595 \\4435 \\
1596 );4436 );
4437}
15974438
1598 try testCanonical(4439test "zig fmt: global declarations" {
1599 \\extern fn puts(s: &const u8) c_int;
1600 \\
1601 );
1602
1603 try testCanonical(4440 try testCanonical(
1604 \\const a = b;4441 \\const a = b;
1605 \\pub const a = b;4442 \\pub const a = b;
...@@ -1609,61 +4446,85 @@ test "zig fmt" {...@@ -1609,61 +4446,85 @@ test "zig fmt" {
1609 \\pub const a: i32 = b;4446 \\pub const a: i32 = b;
1610 \\var a: i32 = b;4447 \\var a: i32 = b;
1611 \\pub var a: i32 = b;4448 \\pub var a: i32 = b;
4449 \\extern const a: i32 = b;
4450 \\pub extern const a: i32 = b;
4451 \\extern var a: i32 = b;
4452 \\pub extern var a: i32 = b;
4453 \\extern "a" const a: i32 = b;
4454 \\pub extern "a" const a: i32 = b;
4455 \\extern "a" var a: i32 = b;
4456 \\pub extern "a" var a: i32 = b;
1612 \\4457 \\
1613 );4458 );
4459}
16144460
4461test "zig fmt: extern declaration" {
1615 try testCanonical(4462 try testCanonical(
1616 \\extern var foo: c_int;4463 \\extern var foo: c_int;
1617 \\4464 \\
1618 );4465 );
4466}
16194467
1620 try testCanonical(4468test "zig fmt: alignment" {
4469 try testCanonical(
1621 \\var foo: c_int align(1);4470 \\var foo: c_int align(1);
1622 \\4471 \\
1623 );4472 );
4473}
16244474
4475test "zig fmt: C main" {
1625 try testCanonical(4476 try testCanonical(
1626 \\fn main(argc: c_int, argv: &&u8) c_int {4477 \\fn main(argc: c_int, argv: &&u8) c_int {
1627 \\ const a = b;4478 \\ const a = b;
1628 \\}4479 \\}
1629 \\4480 \\
1630 );4481 );
4482}
16314483
4484test "zig fmt: return" {
1632 try testCanonical(4485 try testCanonical(
1633 \\fn foo(argc: c_int, argv: &&u8) c_int {4486 \\fn foo(argc: c_int, argv: &&u8) c_int {
1634 \\ return 0;4487 \\ return 0;
1635 \\}4488 \\}
1636 \\4489 \\
1637 );4490 \\fn bar() void {
16384491 \\ return;
1639 try testCanonical(4492 \\}
1640 \\extern fn f1(s: &align(&u8) u8) c_int;
1641 \\4493 \\
1642 );4494 );
4495}
16434496
4497test "zig fmt: pointer attributes" {
1644 try testCanonical(4498 try testCanonical(
1645 \\extern fn f1(s: &&align(1) &const &volatile u8) c_int;4499 \\extern fn f1(s: &align(&u8) u8) c_int;
1646 \\extern fn f2(s: &align(1) const &align(1) volatile &const volatile u8) c_int;4500 \\extern fn f2(s: &&align(1) &const &volatile u8) c_int;
1647 \\extern fn f3(s: &align(1) const volatile u8) c_int;4501 \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int;
4502 \\extern fn f4(s: &align(1) const volatile u8) c_int;
1648 \\4503 \\
1649 );4504 );
4505}
16504506
4507test "zig fmt: slice attributes" {
1651 try testCanonical(4508 try testCanonical(
1652 \\fn f1(a: bool, b: bool) bool {4509 \\extern fn f1(s: &align(&u8) u8) c_int;
1653 \\ a != b;4510 \\extern fn f2(s: &&align(1) &const &volatile u8) c_int;
1654 \\ return a == b;4511 \\extern fn f3(s: &align(1) const &align(1) volatile &const volatile u8) c_int;
1655 \\}4512 \\extern fn f4(s: &align(1) const volatile u8) c_int;
1656 \\4513 \\
1657 );4514 );
4515}
16584516
1659 try testCanonical(4517test "zig fmt: test declaration" {
4518 try testCanonical(
1660 \\test "test name" {4519 \\test "test name" {
1661 \\ const a = 1;4520 \\ const a = 1;
1662 \\ var b = 1;4521 \\ var b = 1;
1663 \\}4522 \\}
1664 \\4523 \\
1665 );4524 );
4525}
16664526
4527test "zig fmt: infix operators" {
1667 try testCanonical(4528 try testCanonical(
1668 \\test "infix operators" {4529 \\test "infix operators" {
1669 \\ var i = undefined;4530 \\ var i = undefined;
...@@ -1713,14 +4574,49 @@ test "zig fmt" {...@@ -1713,14 +4574,49 @@ test "zig fmt" {
1713 \\}4574 \\}
1714 \\4575 \\
1715 );4576 );
4577}
4578
4579test "zig fmt: precedence" {
4580 try testCanonical(
4581 \\test "precedence" {
4582 \\ a!b();
4583 \\ (a!b)();
4584 \\ !a!b;
4585 \\ !(a!b);
4586 \\ !a{ };
4587 \\ !(a{ });
4588 \\ a + b{ };
4589 \\ (a + b){ };
4590 \\ a << b + c;
4591 \\ (a << b) + c;
4592 \\ a & b << c;
4593 \\ (a & b) << c;
4594 \\ a ^ b & c;
4595 \\ (a ^ b) & c;
4596 \\ a | b ^ c;
4597 \\ (a | b) ^ c;
4598 \\ a == b | c;
4599 \\ (a == b) | c;
4600 \\ a and b == c;
4601 \\ (a and b) == c;
4602 \\ a or b and c;
4603 \\ (a or b) and c;
4604 \\ (a or b) and c;
4605 \\}
4606 \\
4607 );
4608}
17164609
4610test "zig fmt: prefix operators" {
1717 try testCanonical(4611 try testCanonical(
1718 \\test "prefix operators" {4612 \\test "prefix operators" {
1719 \\ --%~??!*&0;4613 \\ try return --%~??!*&0;
1720 \\}4614 \\}
1721 \\4615 \\
1722 );4616 );
4617}
17234618
4619test "zig fmt: call expression" {
1724 try testCanonical(4620 try testCanonical(
1725 \\test "test calls" {4621 \\test "test calls" {
1726 \\ a();4622 \\ a();
...@@ -1731,3 +4627,581 @@ test "zig fmt" {...@@ -1731,3 +4627,581 @@ test "zig fmt" {
1731 \\4627 \\
1732 );4628 );
1733}4629}
4630
4631test "zig fmt: var args" {
4632 try testCanonical(
4633 \\fn print(args: ...) void {}
4634 \\
4635 );
4636}
4637
4638test "zig fmt: var type" {
4639 try testCanonical(
4640 \\fn print(args: var) var {}
4641 \\const Var = var;
4642 \\const i: var = 0;
4643 \\
4644 );
4645}
4646
4647test "zig fmt: extern function" {
4648 try testCanonical(
4649 \\extern fn puts(s: &const u8) c_int;
4650 \\extern "c" fn puts(s: &const u8) c_int;
4651 \\export fn puts(s: &const u8) c_int;
4652 \\inline fn puts(s: &const u8) c_int;
4653 \\
4654 );
4655}
4656
4657test "zig fmt: multiline string" {
4658 try testCanonical(
4659 \\const s =
4660 \\ \\ something
4661 \\ \\ something else
4662 \\ ;
4663 \\
4664 );
4665}
4666
4667test "zig fmt: values" {
4668 try testCanonical(
4669 \\test "values" {
4670 \\ 1;
4671 \\ 1.0;
4672 \\ "string";
4673 \\ c"cstring";
4674 \\ 'c';
4675 \\ true;
4676 \\ false;
4677 \\ null;
4678 \\ undefined;
4679 \\ error;
4680 \\ this;
4681 \\ unreachable;
4682 \\}
4683 \\
4684 );
4685}
4686
4687test "zig fmt: indexing" {
4688 try testCanonical(
4689 \\test "test index" {
4690 \\ a[0];
4691 \\ a[0 + 5];
4692 \\ a[0..];
4693 \\ a[0..5];
4694 \\ a[a[0]];
4695 \\ a[a[0..]];
4696 \\ a[a[0..5]];
4697 \\ a[a[0]..];
4698 \\ a[a[0..5]..];
4699 \\ a[a[0]..a[0]];
4700 \\ a[a[0..5]..a[0]];
4701 \\ a[a[0..5]..a[0..5]];
4702 \\}
4703 \\
4704 );
4705}
4706
4707test "zig fmt: struct declaration" {
4708 try testCanonical(
4709 \\const S = struct {
4710 \\ const Self = this;
4711 \\ f1: u8,
4712 \\ pub f3: u8,
4713 \\
4714 \\ fn method(self: &Self) Self {
4715 \\ return *self;
4716 \\ }
4717 \\
4718 \\ f2: u8
4719 \\};
4720 \\
4721 \\const Ps = packed struct {
4722 \\ a: u8,
4723 \\ pub b: u8,
4724 \\
4725 \\ c: u8
4726 \\};
4727 \\
4728 \\const Es = extern struct {
4729 \\ a: u8,
4730 \\ pub b: u8,
4731 \\
4732 \\ c: u8
4733 \\};
4734 \\
4735 );
4736}
4737
4738test "zig fmt: enum declaration" {
4739 try testCanonical(
4740 \\const E = enum {
4741 \\ Ok,
4742 \\ SomethingElse = 0
4743 \\};
4744 \\
4745 \\const E2 = enum(u8) {
4746 \\ Ok,
4747 \\ SomethingElse = 255,
4748 \\ SomethingThird
4749 \\};
4750 \\
4751 \\const Ee = extern enum {
4752 \\ Ok,
4753 \\ SomethingElse,
4754 \\ SomethingThird
4755 \\};
4756 \\
4757 \\const Ep = packed enum {
4758 \\ Ok,
4759 \\ SomethingElse,
4760 \\ SomethingThird
4761 \\};
4762 \\
4763 );
4764}
4765
4766test "zig fmt: union declaration" {
4767 try testCanonical(
4768 \\const U = union {
4769 \\ Int: u8,
4770 \\ Float: f32,
4771 \\ None,
4772 \\ Bool: bool
4773 \\};
4774 \\
4775 \\const Ue = union(enum) {
4776 \\ Int: u8,
4777 \\ Float: f32,
4778 \\ None,
4779 \\ Bool: bool
4780 \\};
4781 \\
4782 \\const E = enum {
4783 \\ Int,
4784 \\ Float,
4785 \\ None,
4786 \\ Bool
4787 \\};
4788 \\
4789 \\const Ue2 = union(E) {
4790 \\ Int: u8,
4791 \\ Float: f32,
4792 \\ None,
4793 \\ Bool: bool
4794 \\};
4795 \\
4796 \\const Eu = extern union {
4797 \\ Int: u8,
4798 \\ Float: f32,
4799 \\ None,
4800 \\ Bool: bool
4801 \\};
4802 \\
4803 );
4804}
4805
4806test "zig fmt: error set declaration" {
4807 try testCanonical(
4808 \\const E = error {
4809 \\ A,
4810 \\ B,
4811 \\
4812 \\ C
4813 \\};
4814 \\
4815 );
4816}
4817
4818test "zig fmt: arrays" {
4819 try testCanonical(
4820 \\test "test array" {
4821 \\ const a: [2]u8 = [2]u8{ 1, 2 };
4822 \\ const a: [2]u8 = []u8{ 1, 2 };
4823 \\ const a: [0]u8 = []u8{ };
4824 \\}
4825 \\
4826 );
4827}
4828
4829test "zig fmt: container initializers" {
4830 try testCanonical(
4831 \\const a1 = []u8{ };
4832 \\const a2 = []u8{ 1, 2, 3, 4 };
4833 \\const s1 = S{ };
4834 \\const s2 = S{ .a = 1, .b = 2 };
4835 \\
4836 );
4837}
4838
4839test "zig fmt: catch" {
4840 try testCanonical(
4841 \\test "catch" {
4842 \\ const a: error!u8 = 0;
4843 \\ _ = a catch return;
4844 \\ _ = a catch |err| return;
4845 \\}
4846 \\
4847 );
4848}
4849
4850test "zig fmt: blocks" {
4851 try testCanonical(
4852 \\test "blocks" {
4853 \\ {
4854 \\ const a = 0;
4855 \\ const b = 0;
4856 \\ }
4857 \\
4858 \\ blk: {
4859 \\ const a = 0;
4860 \\ const b = 0;
4861 \\ }
4862 \\
4863 \\ const r = blk: {
4864 \\ const a = 0;
4865 \\ const b = 0;
4866 \\ };
4867 \\}
4868 \\
4869 );
4870}
4871
4872test "zig fmt: switch" {
4873 try testCanonical(
4874 \\test "switch" {
4875 \\ switch (0) {
4876 \\ 0 => {},
4877 \\ 1 => unreachable,
4878 \\ 2, 3 => {},
4879 \\ 4 ... 7 => {},
4880 \\ 1 + 4 * 3 + 22 => {},
4881 \\ else => {
4882 \\ const a = 1;
4883 \\ const b = a;
4884 \\ }
4885 \\ }
4886 \\
4887 \\ const res = switch (0) {
4888 \\ 0 => 0,
4889 \\ 1 => 2,
4890 \\ 1 => a = 4,
4891 \\ else => 4
4892 \\ };
4893 \\
4894 \\ const Union = union(enum) {
4895 \\ Int: i64,
4896 \\ Float: f64
4897 \\ };
4898 \\
4899 \\ const u = Union{ .Int = 0 };
4900 \\ switch (u) {
4901 \\ Union.Int => |int| {},
4902 \\ Union.Float => |*float| unreachable
4903 \\ }
4904 \\}
4905 \\
4906 );
4907}
4908
4909test "zig fmt: while" {
4910 try testCanonical(
4911 \\test "while" {
4912 \\ while (10 < 1) {
4913 \\ unreachable;
4914 \\ }
4915 \\
4916 \\ while (10 < 1)
4917 \\ unreachable;
4918 \\
4919 \\ var i: usize = 0;
4920 \\ while (i < 10) : (i += 1) {
4921 \\ continue;
4922 \\ }
4923 \\
4924 \\ i = 0;
4925 \\ while (i < 10) : (i += 1)
4926 \\ continue;
4927 \\
4928 \\ i = 0;
4929 \\ var j: usize = 0;
4930 \\ while (i < 10) : ({
4931 \\ i += 1;
4932 \\ j += 1;
4933 \\ }) {
4934 \\ continue;
4935 \\ }
4936 \\
4937 \\ var a: ?u8 = 2;
4938 \\ while (a) |v| : (a = null) {
4939 \\ continue;
4940 \\ }
4941 \\
4942 \\ while (a) |v| : (a = null)
4943 \\ unreachable;
4944 \\
4945 \\ label: while (10 < 0) {
4946 \\ unreachable;
4947 \\ }
4948 \\
4949 \\ const res = while (0 < 10) {
4950 \\ break 7;
4951 \\ } else {
4952 \\ unreachable;
4953 \\ };
4954 \\
4955 \\ const res = while (0 < 10)
4956 \\ break 7
4957 \\ else
4958 \\ unreachable;
4959 \\
4960 \\ var a: error!u8 = 0;
4961 \\ while (a) |v| {
4962 \\ a = error.Err;
4963 \\ } else |err| {
4964 \\ i = 1;
4965 \\ }
4966 \\
4967 \\ comptime var k: usize = 0;
4968 \\ inline while (i < 10) : (i += 1)
4969 \\ j += 2;
4970 \\}
4971 \\
4972 );
4973}
4974
4975test "zig fmt: for" {
4976 try testCanonical(
4977 \\test "for" {
4978 \\ const a = []u8{ 1, 2, 3 };
4979 \\ for (a) |v| {
4980 \\ continue;
4981 \\ }
4982 \\
4983 \\ for (a) |v|
4984 \\ continue;
4985 \\
4986 \\ for (a) |*v|
4987 \\ continue;
4988 \\
4989 \\ for (a) |v, i| {
4990 \\ continue;
4991 \\ }
4992 \\
4993 \\ for (a) |v, i|
4994 \\ continue;
4995 \\
4996 \\ const res = for (a) |v, i| {
4997 \\ break v;
4998 \\ } else {
4999 \\ unreachable;
5000 \\ };
5001 \\
5002 \\ var num: usize = 0;
5003 \\ inline for (a) |v, i| {
5004 \\ num += v;
5005 \\ num += i;
5006 \\ }
5007 \\}
5008 \\
5009 );
5010}
5011
5012test "zig fmt: if" {
5013 try testCanonical(
5014 \\test "if" {
5015 \\ if (10 < 0) {
5016 \\ unreachable;
5017 \\ }
5018 \\
5019 \\ if (10 < 0) unreachable;
5020 \\
5021 \\ if (10 < 0) {
5022 \\ unreachable;
5023 \\ } else {
5024 \\ const a = 20;
5025 \\ }
5026 \\
5027 \\ if (10 < 0) {
5028 \\ unreachable;
5029 \\ } else if (5 < 0) {
5030 \\ unreachable;
5031 \\ } else {
5032 \\ const a = 20;
5033 \\ }
5034 \\
5035 \\ const is_world_broken = if (10 < 0) true else false;
5036 \\ const some_number = 1 + if (10 < 0) 2 else 3;
5037 \\
5038 \\ const a: ?u8 = 10;
5039 \\ const b: ?u8 = null;
5040 \\ if (a) |v| {
5041 \\ const some = v;
5042 \\ } else if (b) |*v| {
5043 \\ unreachable;
5044 \\ } else {
5045 \\ const some = 10;
5046 \\ }
5047 \\
5048 \\ const non_null_a = if (a) |v| v else 0;
5049 \\
5050 \\ const a_err: error!u8 = 0;
5051 \\ if (a_err) |v| {
5052 \\ const p = v;
5053 \\ } else |err| {
5054 \\ unreachable;
5055 \\ }
5056 \\}
5057 \\
5058 );
5059}
5060
5061test "zig fmt: defer" {
5062 try testCanonical(
5063 \\test "defer" {
5064 \\ var i: usize = 0;
5065 \\ defer i = 1;
5066 \\ defer {
5067 \\ i += 2;
5068 \\ i *= i;
5069 \\ }
5070 \\
5071 \\ errdefer i += 3;
5072 \\ errdefer {
5073 \\ i += 2;
5074 \\ i /= i;
5075 \\ }
5076 \\}
5077 \\
5078 );
5079}
5080
5081test "zig fmt: comptime" {
5082 try testCanonical(
5083 \\fn a() u8 {
5084 \\ return 5;
5085 \\}
5086 \\
5087 \\fn b(comptime i: u8) u8 {
5088 \\ return i;
5089 \\}
5090 \\
5091 \\const av = comptime a();
5092 \\const av2 = comptime blk: {
5093 \\ var res = a();
5094 \\ res *= b(2);
5095 \\ break :blk res;
5096 \\};
5097 \\
5098 \\comptime {
5099 \\ _ = a();
5100 \\}
5101 \\
5102 \\test "comptime" {
5103 \\ const av3 = comptime a();
5104 \\ const av4 = comptime blk: {
5105 \\ var res = a();
5106 \\ res *= a();
5107 \\ break :blk res;
5108 \\ };
5109 \\
5110 \\ comptime var i = 0;
5111 \\ comptime {
5112 \\ i = a();
5113 \\ i += b(i);
5114 \\ }
5115 \\}
5116 \\
5117 );
5118}
5119
5120test "zig fmt: fn type" {
5121 try testCanonical(
5122 \\fn a(i: u8) u8 {
5123 \\ return i + 1;
5124 \\}
5125 \\
5126 \\const a: fn(u8) u8 = undefined;
5127 \\const b: extern fn(u8) u8 = undefined;
5128 \\const c: nakedcc fn(u8) u8 = undefined;
5129 \\const ap: fn(u8) u8 = a;
5130 \\
5131 );
5132}
5133
5134test "zig fmt: inline asm" {
5135 try testCanonical(
5136 \\pub fn syscall1(number: usize, arg1: usize) usize {
5137 \\ return asm volatile ("syscall"
5138 \\ : [ret] "={rax}" (-> usize)
5139 \\ : [number] "{rax}" (number),
5140 \\ [arg1] "{rdi}" (arg1)
5141 \\ : "rcx", "r11");
5142 \\}
5143 \\
5144 );
5145}
5146
5147test "zig fmt: coroutines" {
5148 try testCanonical(
5149 \\async fn simpleAsyncFn() void {
5150 \\ const a = async a.b();
5151 \\ x += 1;
5152 \\ suspend;
5153 \\ x += 1;
5154 \\ suspend |p| {}
5155 \\ const p = async simpleAsyncFn() catch unreachable;
5156 \\ await p;
5157 \\}
5158 \\
5159 \\test "coroutine suspend, resume, cancel" {
5160 \\ const p = try async<std.debug.global_allocator> testAsyncSeq();
5161 \\ resume p;
5162 \\ cancel p;
5163 \\}
5164 \\
5165 );
5166}
5167
5168test "zig fmt: Block after if" {
5169 try testCanonical(
5170 \\test "Block after if" {
5171 \\ if (true) {
5172 \\ const a = 0;
5173 \\ }
5174 \\
5175 \\ {
5176 \\ const a = 0;
5177 \\ }
5178 \\}
5179 \\
5180 );
5181}
5182
5183test "zig fmt: use" {
5184 try testCanonical(
5185 \\use @import("std");
5186 \\pub use @import("std");
5187 \\
5188 );
5189}
5190
5191test "zig fmt: string identifier" {
5192 try testCanonical(
5193 \\const @"a b" = @"c d".@"e f";
5194 \\fn @"g h"() void {}
5195 \\
5196 );
5197}
5198
5199test "zig fmt: error return" {
5200 try testCanonical(
5201 \\fn err() error {
5202 \\ call();
5203 \\ return error.InvalidArgs;
5204 \\}
5205 \\
5206 );
5207}
std/zig/tokenizer.zig+146-33
...@@ -5,8 +5,6 @@ pub const Token = struct {...@@ -5,8 +5,6 @@ pub const Token = struct {
5 id: Id,5 id: Id,
6 start: usize,6 start: usize,
7 end: usize,7 end: usize,
8 line: usize,
9 column: usize,
108
11 const KeywordId = struct {9 const KeywordId = struct {
12 bytes: []const u8,10 bytes: []const u8,
...@@ -17,14 +15,18 @@ pub const Token = struct {...@@ -17,14 +15,18 @@ pub const Token = struct {
17 KeywordId{.bytes="align", .id = Id.Keyword_align},15 KeywordId{.bytes="align", .id = Id.Keyword_align},
18 KeywordId{.bytes="and", .id = Id.Keyword_and},16 KeywordId{.bytes="and", .id = Id.Keyword_and},
19 KeywordId{.bytes="asm", .id = Id.Keyword_asm},17 KeywordId{.bytes="asm", .id = Id.Keyword_asm},
18 KeywordId{.bytes="async", .id = Id.Keyword_async},
19 KeywordId{.bytes="await", .id = Id.Keyword_await},
20 KeywordId{.bytes="break", .id = Id.Keyword_break},20 KeywordId{.bytes="break", .id = Id.Keyword_break},
21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},21 KeywordId{.bytes="catch", .id = Id.Keyword_catch},
22 KeywordId{.bytes="cancel", .id = Id.Keyword_cancel},
22 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},23 KeywordId{.bytes="comptime", .id = Id.Keyword_comptime},
23 KeywordId{.bytes="const", .id = Id.Keyword_const},24 KeywordId{.bytes="const", .id = Id.Keyword_const},
24 KeywordId{.bytes="continue", .id = Id.Keyword_continue},25 KeywordId{.bytes="continue", .id = Id.Keyword_continue},
25 KeywordId{.bytes="defer", .id = Id.Keyword_defer},26 KeywordId{.bytes="defer", .id = Id.Keyword_defer},
26 KeywordId{.bytes="else", .id = Id.Keyword_else},27 KeywordId{.bytes="else", .id = Id.Keyword_else},
27 KeywordId{.bytes="enum", .id = Id.Keyword_enum},28 KeywordId{.bytes="enum", .id = Id.Keyword_enum},
29 KeywordId{.bytes="errdefer", .id = Id.Keyword_errdefer},
28 KeywordId{.bytes="error", .id = Id.Keyword_error},30 KeywordId{.bytes="error", .id = Id.Keyword_error},
29 KeywordId{.bytes="export", .id = Id.Keyword_export},31 KeywordId{.bytes="export", .id = Id.Keyword_export},
30 KeywordId{.bytes="extern", .id = Id.Keyword_extern},32 KeywordId{.bytes="extern", .id = Id.Keyword_extern},
...@@ -39,10 +41,12 @@ pub const Token = struct {...@@ -39,10 +41,12 @@ pub const Token = struct {
39 KeywordId{.bytes="or", .id = Id.Keyword_or},41 KeywordId{.bytes="or", .id = Id.Keyword_or},
40 KeywordId{.bytes="packed", .id = Id.Keyword_packed},42 KeywordId{.bytes="packed", .id = Id.Keyword_packed},
41 KeywordId{.bytes="pub", .id = Id.Keyword_pub},43 KeywordId{.bytes="pub", .id = Id.Keyword_pub},
44 KeywordId{.bytes="resume", .id = Id.Keyword_resume},
42 KeywordId{.bytes="return", .id = Id.Keyword_return},45 KeywordId{.bytes="return", .id = Id.Keyword_return},
43 KeywordId{.bytes="section", .id = Id.Keyword_section},46 KeywordId{.bytes="section", .id = Id.Keyword_section},
44 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},47 KeywordId{.bytes="stdcallcc", .id = Id.Keyword_stdcallcc},
45 KeywordId{.bytes="struct", .id = Id.Keyword_struct},48 KeywordId{.bytes="struct", .id = Id.Keyword_struct},
49 KeywordId{.bytes="suspend", .id = Id.Keyword_suspend},
46 KeywordId{.bytes="switch", .id = Id.Keyword_switch},50 KeywordId{.bytes="switch", .id = Id.Keyword_switch},
47 KeywordId{.bytes="test", .id = Id.Keyword_test},51 KeywordId{.bytes="test", .id = Id.Keyword_test},
48 KeywordId{.bytes="this", .id = Id.Keyword_this},52 KeywordId{.bytes="this", .id = Id.Keyword_this},
...@@ -72,7 +76,8 @@ pub const Token = struct {...@@ -72,7 +76,8 @@ pub const Token = struct {
72 Invalid,76 Invalid,
73 Identifier,77 Identifier,
74 StringLiteral: StrLitKind,78 StringLiteral: StrLitKind,
75 StringIdentifier,79 MultilineStringLiteralLine: StrLitKind,
80 CharLiteral,
76 Eof,81 Eof,
77 Builtin,82 Builtin,
78 Bang,83 Bang,
...@@ -81,6 +86,7 @@ pub const Token = struct {...@@ -81,6 +86,7 @@ pub const Token = struct {
81 PipeEqual,86 PipeEqual,
82 Equal,87 Equal,
83 EqualEqual,88 EqualEqual,
89 EqualAngleBracketRight,
84 BangEqual,90 BangEqual,
85 LParen,91 LParen,
86 RParen,92 RParen,
...@@ -89,6 +95,8 @@ pub const Token = struct {...@@ -89,6 +95,8 @@ pub const Token = struct {
89 PercentEqual,95 PercentEqual,
90 LBrace,96 LBrace,
91 RBrace,97 RBrace,
98 LBracket,
99 RBracket,
92 Period,100 Period,
93 Ellipsis2,101 Ellipsis2,
94 Ellipsis3,102 Ellipsis3,
...@@ -132,7 +140,10 @@ pub const Token = struct {...@@ -132,7 +140,10 @@ pub const Token = struct {
132 Keyword_align,140 Keyword_align,
133 Keyword_and,141 Keyword_and,
134 Keyword_asm,142 Keyword_asm,
143 Keyword_async,
144 Keyword_await,
135 Keyword_break,145 Keyword_break,
146 Keyword_cancel,
136 Keyword_catch,147 Keyword_catch,
137 Keyword_comptime,148 Keyword_comptime,
138 Keyword_const,149 Keyword_const,
...@@ -140,6 +151,7 @@ pub const Token = struct {...@@ -140,6 +151,7 @@ pub const Token = struct {
140 Keyword_defer,151 Keyword_defer,
141 Keyword_else,152 Keyword_else,
142 Keyword_enum,153 Keyword_enum,
154 Keyword_errdefer,
143 Keyword_error,155 Keyword_error,
144 Keyword_export,156 Keyword_export,
145 Keyword_extern,157 Keyword_extern,
...@@ -154,10 +166,12 @@ pub const Token = struct {...@@ -154,10 +166,12 @@ pub const Token = struct {
154 Keyword_or,166 Keyword_or,
155 Keyword_packed,167 Keyword_packed,
156 Keyword_pub,168 Keyword_pub,
169 Keyword_resume,
157 Keyword_return,170 Keyword_return,
158 Keyword_section,171 Keyword_section,
159 Keyword_stdcallcc,172 Keyword_stdcallcc,
160 Keyword_struct,173 Keyword_struct,
174 Keyword_suspend,
161 Keyword_switch,175 Keyword_switch,
162 Keyword_test,176 Keyword_test,
163 Keyword_this,177 Keyword_this,
...@@ -176,28 +190,34 @@ pub const Token = struct {...@@ -176,28 +190,34 @@ pub const Token = struct {
176pub const Tokenizer = struct {190pub const Tokenizer = struct {
177 buffer: []const u8,191 buffer: []const u8,
178 index: usize,192 index: usize,
179 line: usize,
180 column: usize,
181 pending_invalid_token: ?Token,193 pending_invalid_token: ?Token,
182194
183 pub const LineLocation = struct {195 pub const Location = struct {
196 line: usize,
197 column: usize,
184 line_start: usize,198 line_start: usize,
185 line_end: usize,199 line_end: usize,
186 };200 };
187201
188 pub fn getTokenLocation(self: &Tokenizer, token: &const Token) LineLocation {202 pub fn getTokenLocation(self: &Tokenizer, start_index: usize, token: &const Token) Location {
189 var loc = LineLocation {203 var loc = Location {
190 .line_start = 0,204 .line = 0,
205 .column = 0,
206 .line_start = start_index,
191 .line_end = self.buffer.len,207 .line_end = self.buffer.len,
192 };208 };
193 for (self.buffer) |c, i| {209 for (self.buffer[start_index..]) |c, i| {
194 if (i == token.start) {210 if (i + start_index == token.start) {
195 loc.line_end = i;211 loc.line_end = i + start_index;
196 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}212 while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {}
197 return loc;213 return loc;
198 }214 }
199 if (c == '\n') {215 if (c == '\n') {
216 loc.line += 1;
217 loc.column = 0;
200 loc.line_start = i + 1;218 loc.line_start = i + 1;
219 } else {
220 loc.column += 1;
201 }221 }
202 }222 }
203 return loc;223 return loc;
...@@ -212,8 +232,6 @@ pub const Tokenizer = struct {...@@ -212,8 +232,6 @@ pub const Tokenizer = struct {
212 return Tokenizer {232 return Tokenizer {
213 .buffer = buffer,233 .buffer = buffer,
214 .index = 0,234 .index = 0,
215 .line = 0,
216 .column = 0,
217 .pending_invalid_token = null,235 .pending_invalid_token = null,
218 };236 };
219 }237 }
...@@ -225,6 +243,12 @@ pub const Tokenizer = struct {...@@ -225,6 +243,12 @@ pub const Tokenizer = struct {
225 C,243 C,
226 StringLiteral,244 StringLiteral,
227 StringLiteralBackslash,245 StringLiteralBackslash,
246 MultilineStringLiteralLine,
247 MultilineStringLiteralLineBackslash,
248 CharLiteral,
249 CharLiteralBackslash,
250 CharLiteralEnd,
251 Backslash,
228 Equal,252 Equal,
229 Bang,253 Bang,
230 Pipe,254 Pipe,
...@@ -261,26 +285,22 @@ pub const Tokenizer = struct {...@@ -261,26 +285,22 @@ pub const Tokenizer = struct {
261 self.pending_invalid_token = null;285 self.pending_invalid_token = null;
262 return token;286 return token;
263 }287 }
288 const start_index = self.index;
264 var state = State.Start;289 var state = State.Start;
265 var result = Token {290 var result = Token {
266 .id = Token.Id.Eof,291 .id = Token.Id.Eof,
267 .start = self.index,292 .start = self.index,
268 .end = undefined,293 .end = undefined,
269 .line = self.line,
270 .column = self.column,
271 };294 };
272 while (self.index < self.buffer.len) {295 while (self.index < self.buffer.len) : (self.index += 1) {
273 const c = self.buffer[self.index];296 const c = self.buffer[self.index];
274 switch (state) {297 switch (state) {
275 State.Start => switch (c) {298 State.Start => switch (c) {
276 ' ' => {299 ' ' => {
277 result.start = self.index + 1;300 result.start = self.index + 1;
278 result.column += 1;
279 },301 },
280 '\n' => {302 '\n' => {
281 result.start = self.index + 1;303 result.start = self.index + 1;
282 result.line += 1;
283 result.column = 0;
284 },304 },
285 'c' => {305 'c' => {
286 state = State.C;306 state = State.C;
...@@ -290,6 +310,9 @@ pub const Tokenizer = struct {...@@ -290,6 +310,9 @@ pub const Tokenizer = struct {
290 state = State.StringLiteral;310 state = State.StringLiteral;
291 result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal };311 result.id = Token.Id { .StringLiteral = Token.StrLitKind.Normal };
292 },312 },
313 '\'' => {
314 state = State.CharLiteral;
315 },
293 'a'...'b', 'd'...'z', 'A'...'Z', '_' => {316 'a'...'b', 'd'...'z', 'A'...'Z', '_' => {
294 state = State.Identifier;317 state = State.Identifier;
295 result.id = Token.Id.Identifier;318 result.id = Token.Id.Identifier;
...@@ -316,6 +339,16 @@ pub const Tokenizer = struct {...@@ -316,6 +339,16 @@ pub const Tokenizer = struct {
316 self.index += 1;339 self.index += 1;
317 break;340 break;
318 },341 },
342 '[' => {
343 result.id = Token.Id.LBracket;
344 self.index += 1;
345 break;
346 },
347 ']' => {
348 result.id = Token.Id.RBracket;
349 self.index += 1;
350 break;
351 },
319 ';' => {352 ';' => {
320 result.id = Token.Id.Semicolon;353 result.id = Token.Id.Semicolon;
321 self.index += 1;354 self.index += 1;
...@@ -352,6 +385,10 @@ pub const Tokenizer = struct {...@@ -352,6 +385,10 @@ pub const Tokenizer = struct {
352 '^' => {385 '^' => {
353 state = State.Caret;386 state = State.Caret;
354 },387 },
388 '\\' => {
389 state = State.Backslash;
390 result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.Normal };
391 },
355 '{' => {392 '{' => {
356 result.id = Token.Id.LBrace;393 result.id = Token.Id.LBrace;
357 self.index += 1;394 self.index += 1;
...@@ -396,7 +433,7 @@ pub const Tokenizer = struct {...@@ -396,7 +433,7 @@ pub const Tokenizer = struct {
396433
397 State.SawAtSign => switch (c) {434 State.SawAtSign => switch (c) {
398 '"' => {435 '"' => {
399 result.id = Token.Id.StringIdentifier;436 result.id = Token.Id.Identifier;
400 state = State.StringLiteral;437 state = State.StringLiteral;
401 },438 },
402 else => {439 else => {
...@@ -532,8 +569,17 @@ pub const Tokenizer = struct {...@@ -532,8 +569,17 @@ pub const Tokenizer = struct {
532 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},569 'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
533 else => break,570 else => break,
534 },571 },
572 State.Backslash => switch (c) {
573 '\\' => {
574 state = State.MultilineStringLiteralLine;
575 },
576 else => break,
577 },
535 State.C => switch (c) {578 State.C => switch (c) {
536 '\\' => @panic("TODO"),579 '\\' => {
580 state = State.Backslash;
581 result.id = Token.Id { .MultilineStringLiteralLine = Token.StrLitKind.C };
582 },
537 '"' => {583 '"' => {
538 state = State.StringLiteral;584 state = State.StringLiteral;
539 result.id = Token.Id { .StringLiteral = Token.StrLitKind.C };585 result.id = Token.Id { .StringLiteral = Token.StrLitKind.C };
...@@ -562,6 +608,64 @@ pub const Tokenizer = struct {...@@ -562,6 +608,64 @@ pub const Tokenizer = struct {
562 },608 },
563 },609 },
564610
611 State.CharLiteral => switch (c) {
612 '\\' => {
613 state = State.CharLiteralBackslash;
614 },
615 '\'' => {
616 result.id = Token.Id.Invalid;
617 break;
618 },
619 else => {
620 if (c < 0x20 or c == 0x7f) {
621 result.id = Token.Id.Invalid;
622 break;
623 }
624
625 state = State.CharLiteralEnd;
626 }
627 },
628
629 State.CharLiteralBackslash => switch (c) {
630 '\n' => {
631 result.id = Token.Id.Invalid;
632 break;
633 },
634 else => {
635 state = State.CharLiteralEnd;
636 },
637 },
638
639 State.CharLiteralEnd => switch (c) {
640 '\'' => {
641 result.id = Token.Id.CharLiteral;
642 self.index += 1;
643 break;
644 },
645 else => {
646 result.id = Token.Id.Invalid;
647 break;
648 },
649 },
650
651 State.MultilineStringLiteralLine => switch (c) {
652 '\\' => {
653 state = State.MultilineStringLiteralLineBackslash;
654 },
655 '\n' => {
656 self.index += 1;
657 break;
658 },
659 else => self.checkLiteralCharacter(),
660 },
661
662 State.MultilineStringLiteralLineBackslash => switch (c) {
663 '\n' => break, // Look for this error later.
664 else => {
665 state = State.MultilineStringLiteralLine;
666 },
667 },
668
565 State.Bang => switch (c) {669 State.Bang => switch (c) {
566 '=' => {670 '=' => {
567 result.id = Token.Id.BangEqual;671 result.id = Token.Id.BangEqual;
...@@ -597,6 +701,11 @@ pub const Tokenizer = struct {...@@ -597,6 +701,11 @@ pub const Tokenizer = struct {
597 self.index += 1;701 self.index += 1;
598 break;702 break;
599 },703 },
704 '>' => {
705 result.id = Token.Id.EqualAngleBracketRight;
706 self.index += 1;
707 break;
708 },
600 else => {709 else => {
601 result.id = Token.Id.Equal;710 result.id = Token.Id.Equal;
602 break;711 break;
...@@ -794,14 +903,6 @@ pub const Tokenizer = struct {...@@ -794,14 +903,6 @@ pub const Tokenizer = struct {
794 else => break,903 else => break,
795 },904 },
796 }905 }
797
798 self.index += 1;
799 if (c == '\n') {
800 self.line += 1;
801 self.column = 0;
802 } else {
803 self.column += 1;
804 }
805 } else if (self.index == self.buffer.len) {906 } else if (self.index == self.buffer.len) {
806 switch (state) {907 switch (state) {
807 State.Start,908 State.Start,
...@@ -811,6 +912,7 @@ pub const Tokenizer = struct {...@@ -811,6 +912,7 @@ pub const Tokenizer = struct {
811 State.FloatFraction,912 State.FloatFraction,
812 State.FloatExponentNumber,913 State.FloatExponentNumber,
813 State.StringLiteral, // find this error later914 State.StringLiteral, // find this error later
915 State.MultilineStringLiteralLine,
814 State.Builtin => {},916 State.Builtin => {},
815917
816 State.Identifier => {918 State.Identifier => {
...@@ -825,6 +927,11 @@ pub const Tokenizer = struct {...@@ -825,6 +927,11 @@ pub const Tokenizer = struct {
825 State.NumberDot,927 State.NumberDot,
826 State.FloatExponentUnsigned,928 State.FloatExponentUnsigned,
827 State.SawAtSign,929 State.SawAtSign,
930 State.Backslash,
931 State.MultilineStringLiteralLineBackslash,
932 State.CharLiteral,
933 State.CharLiteralBackslash,
934 State.CharLiteralEnd,
828 State.StringLiteralBackslash => {935 State.StringLiteralBackslash => {
829 result.id = Token.Id.Invalid;936 result.id = Token.Id.Invalid;
830 },937 },
...@@ -894,6 +1001,7 @@ pub const Tokenizer = struct {...@@ -894,6 +1001,7 @@ pub const Tokenizer = struct {
894 },1001 },
895 }1002 }
896 }1003 }
1004
897 if (result.id == Token.Id.Eof) {1005 if (result.id == Token.Id.Eof) {
898 if (self.pending_invalid_token) |token| {1006 if (self.pending_invalid_token) |token| {
899 self.pending_invalid_token = null;1007 self.pending_invalid_token = null;
...@@ -917,8 +1025,6 @@ pub const Tokenizer = struct {...@@ -917,8 +1025,6 @@ pub const Tokenizer = struct {
917 .id = Token.Id.Invalid,1025 .id = Token.Id.Invalid,
918 .start = self.index,1026 .start = self.index,
919 .end = self.index + invalid_length,1027 .end = self.index + invalid_length,
920 .line = self.line,
921 .column = self.column,
922 };1028 };
923 }1029 }
9241030
...@@ -968,9 +1074,16 @@ test "tokenizer" {...@@ -968,9 +1074,16 @@ test "tokenizer" {
968 });1074 });
969}1075}
9701076
1077test "tokenizer - chars" {
1078 testTokenize("'c'", []Token.Id {Token.Id.CharLiteral});
1079}
1080
971test "tokenizer - invalid token characters" {1081test "tokenizer - invalid token characters" {
972 testTokenize("#", []Token.Id{Token.Id.Invalid});1082 testTokenize("#", []Token.Id{Token.Id.Invalid});
973 testTokenize("`", []Token.Id{Token.Id.Invalid});1083 testTokenize("`", []Token.Id{Token.Id.Invalid});
1084 testTokenize("'c", []Token.Id {Token.Id.Invalid});
1085 testTokenize("'", []Token.Id {Token.Id.Invalid});
1086 testTokenize("''", []Token.Id {Token.Id.Invalid, Token.Id.Invalid});
974}1087}
9751088
976test "tokenizer - invalid literal/comment characters" {1089test "tokenizer - invalid literal/comment characters" {
...@@ -1022,7 +1135,7 @@ test "tokenizer - string identifier and builtin fns" {...@@ -1022,7 +1135,7 @@ test "tokenizer - string identifier and builtin fns" {
1022 ,1135 ,
1023 []Token.Id{1136 []Token.Id{
1024 Token.Id.Keyword_const,1137 Token.Id.Keyword_const,
1025 Token.Id.StringIdentifier,1138 Token.Id.Identifier,
1026 Token.Id.Equal,1139 Token.Id.Equal,
1027 Token.Id.Builtin,1140 Token.Id.Builtin,
1028 Token.Id.LParen,1141 Token.Id.LParen,
test/cases/coroutines.zig+35
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
34
4var x: i32 = 1;5var x: i32 = 1;
...@@ -189,3 +190,37 @@ async fn failing() !void {...@@ -189,3 +190,37 @@ async fn failing() !void {
189 suspend;190 suspend;
190 return error.Fail;191 return error.Fail;
191}192}
193
194test "error return trace across suspend points - early return" {
195 const p = nonFailing();
196 resume p;
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
198 cancel p2;
199}
200
201test "error return trace across suspend points - async return" {
202 const p = nonFailing();
203 const p2 = try async<std.debug.global_allocator> printTrace(p);
204 resume p;
205 cancel p2;
206}
207
208fn nonFailing() promise->error!void {
209 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
210}
211
212async fn suspendThenFail() error!void {
213 suspend;
214 return error.Fail;
215}
216
217async fn printTrace(p: promise->error!void) void {
218 (await p) catch |e| {
219 std.debug.assert(e == error.Fail);
220 if (@errorReturnTrace()) |trace| {
221 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {
223 @panic("expected return trace");
224 }
225 };
226}
test/cases/fn.zig+10
...@@ -94,3 +94,13 @@ test "inline function call" {...@@ -94,3 +94,13 @@ test "inline function call" {
94}94}
9595
96fn add(a: i32, b: i32) i32 { return a + b; }96fn add(a: i32, b: i32) i32 { return a + b; }
97
98
99test "number literal as an argument" {
100 numberLiteralArg(3);
101 comptime numberLiteralArg(3);
102}
103
104fn numberLiteralArg(a: var) void {
105 assert(a == 3);
106}
test/compile_errors.zig+1-1
...@@ -1723,7 +1723,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {...@@ -1723,7 +1723,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
1723 \\}1723 \\}
1724 \\1724 \\
1725 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }1725 \\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
1726 , ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime");1726 , ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted");
17271727
1728 cases.add("assign too big number to u16",1728 cases.add("assign too big number to u16",
1729 \\export fn foo() void {1729 \\export fn foo() void {