| author | |
| committer | |
| log | 2ed949a6ae053262ee563b198a8758ba82f50e84 |
| tree | 6bb367b942f9f4b319a9e1b452260e9a7725d6a3 |
| parent | 0d5ecc4312f45f9288c4a349837f04b733405960 |
11 files changed, 99 insertions(+), 14 deletions(-)
doc/langref.md+1-1| ... | @@ -151,7 +151,7 @@ GotoExpression = "goto" Symbol | ... | @@ -151,7 +151,7 @@ GotoExpression = "goto" Symbol |
| 151 | 151 | ||
| 152 | GroupedExpression = "(" Expression ")" | 152 | GroupedExpression = "(" Expression ")" |
| 153 | 153 | ||
| 154 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | 154 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type" |
| 155 | ``` | 155 | ``` |
| 156 | 156 | ||
| 157 | ## Operator Precedence | 157 | ## Operator Precedence |
src/all_types.hpp+17-2| ... | @@ -62,11 +62,18 @@ struct ConstErrValue { | ... | @@ -62,11 +62,18 @@ struct ConstErrValue { |
| 62 | ConstExprValue *payload; | 62 | ConstExprValue *payload; |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | enum ConstValSpecial { | ||
| 66 | ConstValSpecialOther, | ||
| 67 | ConstValSpecialUndef, | ||
| 68 | ConstValSpecialZeroes, | ||
| 69 | }; | ||
| 70 | |||
| 65 | struct ConstExprValue { | 71 | struct ConstExprValue { |
| 66 | bool ok; // true if constant expression evalution worked | 72 | bool ok; |
| 67 | bool depends_on_compile_var; | 73 | bool depends_on_compile_var; |
| 68 | bool undef; | 74 | ConstValSpecial special; |
| 69 | 75 | ||
| 76 | // populated if val_type == ConstValTypeOk | ||
| 70 | union { | 77 | union { |
| 71 | BigNum x_bignum; | 78 | BigNum x_bignum; |
| 72 | bool x_bool; | 79 | bool x_bool; |
| ... | @@ -167,6 +174,7 @@ enum NodeType { | ... | @@ -167,6 +174,7 @@ enum NodeType { |
| 167 | NodeTypeBoolLiteral, | 174 | NodeTypeBoolLiteral, |
| 168 | NodeTypeNullLiteral, | 175 | NodeTypeNullLiteral, |
| 169 | NodeTypeUndefinedLiteral, | 176 | NodeTypeUndefinedLiteral, |
| 177 | NodeTypeZeroesLiteral, | ||
| 170 | NodeTypeIfBoolExpr, | 178 | NodeTypeIfBoolExpr, |
| 171 | NodeTypeIfVarExpr, | 179 | NodeTypeIfVarExpr, |
| 172 | NodeTypeWhileExpr, | 180 | NodeTypeWhileExpr, |
| ... | @@ -694,6 +702,12 @@ struct AstNodeUndefinedLiteral { | ... | @@ -694,6 +702,12 @@ struct AstNodeUndefinedLiteral { |
| 694 | Expr resolved_expr; | 702 | Expr resolved_expr; |
| 695 | }; | 703 | }; |
| 696 | 704 | ||
| 705 | struct AstNodeZeroesLiteral { | ||
| 706 | // populated by semantic analyzer | ||
| 707 | StructValExprCodeGen resolved_struct_val_expr; | ||
| 708 | Expr resolved_expr; | ||
| 709 | }; | ||
| 710 | |||
| 697 | struct AstNodeSymbolExpr { | 711 | struct AstNodeSymbolExpr { |
| 698 | Buf *symbol; | 712 | Buf *symbol; |
| 699 | 713 | ||
| ... | @@ -791,6 +805,7 @@ struct AstNode { | ... | @@ -791,6 +805,7 @@ struct AstNode { |
| 791 | AstNodeStructValueField struct_val_field; | 805 | AstNodeStructValueField struct_val_field; |
| 792 | AstNodeNullLiteral null_literal; | 806 | AstNodeNullLiteral null_literal; |
| 793 | AstNodeUndefinedLiteral undefined_literal; | 807 | AstNodeUndefinedLiteral undefined_literal; |
| 808 | AstNodeZeroesLiteral zeroes_literal; | ||
| 794 | AstNodeSymbolExpr symbol_expr; | 809 | AstNodeSymbolExpr symbol_expr; |
| 795 | AstNodeBoolLiteral bool_literal; | 810 | AstNodeBoolLiteral bool_literal; |
| 796 | AstNodeBreakExpr break_expr; | 811 | AstNodeBreakExpr break_expr; |
src/analyze.cpp+23-2| ... | @@ -90,6 +90,7 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -90,6 +90,7 @@ static AstNode *first_executing_node(AstNode *node) { |
| 90 | case NodeTypeBoolLiteral: | 90 | case NodeTypeBoolLiteral: |
| 91 | case NodeTypeNullLiteral: | 91 | case NodeTypeNullLiteral: |
| 92 | case NodeTypeUndefinedLiteral: | 92 | case NodeTypeUndefinedLiteral: |
| 93 | case NodeTypeZeroesLiteral: | ||
| 93 | case NodeTypeIfBoolExpr: | 94 | case NodeTypeIfBoolExpr: |
| 94 | case NodeTypeIfVarExpr: | 95 | case NodeTypeIfVarExpr: |
| 95 | case NodeTypeLabel: | 96 | case NodeTypeLabel: |
| ... | @@ -1849,6 +1850,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) | ... | @@ -1849,6 +1850,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) |
| 1849 | case NodeTypeBoolLiteral: | 1850 | case NodeTypeBoolLiteral: |
| 1850 | case NodeTypeNullLiteral: | 1851 | case NodeTypeNullLiteral: |
| 1851 | case NodeTypeUndefinedLiteral: | 1852 | case NodeTypeUndefinedLiteral: |
| 1853 | case NodeTypeZeroesLiteral: | ||
| 1852 | case NodeTypeSymbol: | 1854 | case NodeTypeSymbol: |
| 1853 | case NodeTypePrefixOpExpr: | 1855 | case NodeTypePrefixOpExpr: |
| 1854 | case NodeTypeIfBoolExpr: | 1856 | case NodeTypeIfBoolExpr: |
| ... | @@ -3937,7 +3939,19 @@ static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEnt | ... | @@ -3937,7 +3939,19 @@ static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEnt |
| 3937 | ConstExprValue *const_val = &expr->const_val; | 3939 | ConstExprValue *const_val = &expr->const_val; |
| 3938 | 3940 | ||
| 3939 | const_val->ok = true; | 3941 | const_val->ok = true; |
| 3940 | const_val->undef = true; | 3942 | const_val->special = ConstValSpecialUndef; |
| 3943 | |||
| 3944 | return expected_type ? expected_type : g->builtin_types.entry_undef; | ||
| 3945 | } | ||
| 3946 | |||
| 3947 | static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 3948 | TypeTableEntry *expected_type, AstNode *node) | ||
| 3949 | { | ||
| 3950 | Expr *expr = get_resolved_expr(node); | ||
| 3951 | ConstExprValue *const_val = &expr->const_val; | ||
| 3952 | |||
| 3953 | const_val->ok = true; | ||
| 3954 | const_val->special = ConstValSpecialZeroes; | ||
| 3941 | 3955 | ||
| 3942 | return expected_type ? expected_type : g->builtin_types.entry_undef; | 3956 | return expected_type ? expected_type : g->builtin_types.entry_undef; |
| 3943 | } | 3957 | } |
| ... | @@ -4252,7 +4266,7 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -4252,7 +4266,7 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import |
| 4252 | } | 4266 | } |
| 4253 | 4267 | ||
| 4254 | ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val; | 4268 | ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val; |
| 4255 | if (cond_val->undef) { | 4269 | if (cond_val->special == ConstValSpecialUndef) { |
| 4256 | add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value")); | 4270 | add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value")); |
| 4257 | return cond_type; | 4271 | return cond_type; |
| 4258 | } | 4272 | } |
| ... | @@ -6504,6 +6518,9 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn | ... | @@ -6504,6 +6518,9 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn |
| 6504 | case NodeTypeUndefinedLiteral: | 6518 | case NodeTypeUndefinedLiteral: |
| 6505 | return_type = analyze_undefined_literal_expr(g, import, context, expected_type, node); | 6519 | return_type = analyze_undefined_literal_expr(g, import, context, expected_type, node); |
| 6506 | break; | 6520 | break; |
| 6521 | case NodeTypeZeroesLiteral: | ||
| 6522 | return_type = analyze_zeroes_literal_expr(g, import, context, expected_type, node); | ||
| 6523 | break; | ||
| 6507 | case NodeTypeSymbol: | 6524 | case NodeTypeSymbol: |
| 6508 | return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only); | 6525 | return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only); |
| 6509 | break; | 6526 | break; |
| ... | @@ -6771,6 +6788,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte | ... | @@ -6771,6 +6788,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte |
| 6771 | case NodeTypeBoolLiteral: | 6788 | case NodeTypeBoolLiteral: |
| 6772 | case NodeTypeNullLiteral: | 6789 | case NodeTypeNullLiteral: |
| 6773 | case NodeTypeUndefinedLiteral: | 6790 | case NodeTypeUndefinedLiteral: |
| 6791 | case NodeTypeZeroesLiteral: | ||
| 6774 | case NodeTypeSymbol: | 6792 | case NodeTypeSymbol: |
| 6775 | case NodeTypePrefixOpExpr: | 6793 | case NodeTypePrefixOpExpr: |
| 6776 | case NodeTypeIfBoolExpr: | 6794 | case NodeTypeIfBoolExpr: |
| ... | @@ -7029,6 +7047,8 @@ Expr *get_resolved_expr(AstNode *node) { | ... | @@ -7029,6 +7047,8 @@ Expr *get_resolved_expr(AstNode *node) { |
| 7029 | return &node->data.null_literal.resolved_expr; | 7047 | return &node->data.null_literal.resolved_expr; |
| 7030 | case NodeTypeUndefinedLiteral: | 7048 | case NodeTypeUndefinedLiteral: |
| 7031 | return &node->data.undefined_literal.resolved_expr; | 7049 | return &node->data.undefined_literal.resolved_expr; |
| 7050 | case NodeTypeZeroesLiteral: | ||
| 7051 | return &node->data.zeroes_literal.resolved_expr; | ||
| 7032 | case NodeTypeGoto: | 7052 | case NodeTypeGoto: |
| 7033 | return &node->data.goto_expr.resolved_expr; | 7053 | return &node->data.goto_expr.resolved_expr; |
| 7034 | case NodeTypeBreak: | 7054 | case NodeTypeBreak: |
| ... | @@ -7111,6 +7131,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) { | ... | @@ -7111,6 +7131,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) { |
| 7111 | case NodeTypeBoolLiteral: | 7131 | case NodeTypeBoolLiteral: |
| 7112 | case NodeTypeNullLiteral: | 7132 | case NodeTypeNullLiteral: |
| 7113 | case NodeTypeUndefinedLiteral: | 7133 | case NodeTypeUndefinedLiteral: |
| 7134 | case NodeTypeZeroesLiteral: | ||
| 7114 | case NodeTypeLabel: | 7135 | case NodeTypeLabel: |
| 7115 | case NodeTypeGoto: | 7136 | case NodeTypeGoto: |
| 7116 | case NodeTypeBreak: | 7137 | case NodeTypeBreak: |
src/ast_render.cpp+4| ... | @@ -171,6 +171,8 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -171,6 +171,8 @@ static const char *node_type_str(NodeType node_type) { |
| 171 | return "NullLiteral"; | 171 | return "NullLiteral"; |
| 172 | case NodeTypeUndefinedLiteral: | 172 | case NodeTypeUndefinedLiteral: |
| 173 | return "UndefinedLiteral"; | 173 | return "UndefinedLiteral"; |
| 174 | case NodeTypeZeroesLiteral: | ||
| 175 | return "ZeroesLiteral"; | ||
| 174 | case NodeTypeIfBoolExpr: | 176 | case NodeTypeIfBoolExpr: |
| 175 | return "IfBoolExpr"; | 177 | return "IfBoolExpr"; |
| 176 | case NodeTypeIfVarExpr: | 178 | case NodeTypeIfVarExpr: |
| ... | @@ -591,6 +593,8 @@ static void render_node(AstRender *ar, AstNode *node) { | ... | @@ -591,6 +593,8 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 591 | zig_panic("TODO"); | 593 | zig_panic("TODO"); |
| 592 | case NodeTypeUndefinedLiteral: | 594 | case NodeTypeUndefinedLiteral: |
| 593 | zig_panic("TODO"); | 595 | zig_panic("TODO"); |
| 596 | case NodeTypeZeroesLiteral: | ||
| 597 | zig_panic("TODO"); | ||
| 594 | case NodeTypeIfBoolExpr: | 598 | case NodeTypeIfBoolExpr: |
| 595 | zig_panic("TODO"); | 599 | zig_panic("TODO"); |
| 596 | case NodeTypeIfVarExpr: | 600 | case NodeTypeIfVarExpr: |
src/codegen.cpp+17-5| ... | @@ -3141,11 +3141,15 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa | ... | @@ -3141,11 +3141,15 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 3141 | } | 3141 | } |
| 3142 | 3142 | ||
| 3143 | bool have_init_expr = false; | 3143 | bool have_init_expr = false; |
| 3144 | bool want_zeroes = false; | ||
| 3144 | if (var_decl->expr) { | 3145 | if (var_decl->expr) { |
| 3145 | ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val; | 3146 | ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val; |
| 3146 | if (!const_val->ok || !const_val->undef) { | 3147 | if (!const_val->ok || const_val->special == ConstValSpecialOther) { |
| 3147 | have_init_expr = true; | 3148 | have_init_expr = true; |
| 3148 | } | 3149 | } |
| 3150 | if (const_val->ok && const_val->special == ConstValSpecialZeroes) { | ||
| 3151 | want_zeroes = true; | ||
| 3152 | } | ||
| 3149 | } | 3153 | } |
| 3150 | if (have_init_expr) { | 3154 | if (have_init_expr) { |
| 3151 | TypeTableEntry *expr_type = get_expr_type(var_decl->expr); | 3155 | TypeTableEntry *expr_type = get_expr_type(var_decl->expr); |
| ... | @@ -3204,7 +3208,8 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa | ... | @@ -3204,7 +3208,8 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 3204 | } | 3208 | } |
| 3205 | } | 3209 | } |
| 3206 | } | 3210 | } |
| 3207 | if (!ignore_uninit && want_debug_safety(g, source_node)) { | 3211 | bool want_safe = want_debug_safety(g, source_node); |
| 3212 | if (!ignore_uninit && (want_safe || want_zeroes)) { | ||
| 3208 | TypeTableEntry *usize = g->builtin_types.entry_usize; | 3213 | TypeTableEntry *usize = g->builtin_types.entry_usize; |
| 3209 | uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref); | 3214 | uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref); |
| 3210 | uint64_t align_bytes = get_memcpy_align(g, variable->type); | 3215 | uint64_t align_bytes = get_memcpy_align(g, variable->type); |
| ... | @@ -3212,7 +3217,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa | ... | @@ -3212,7 +3217,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 3212 | // memset uninitialized memory to 0xa | 3217 | // memset uninitialized memory to 0xa |
| 3213 | set_debug_source_node(g, source_node); | 3218 | set_debug_source_node(g, source_node); |
| 3214 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | 3219 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| 3215 | LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); | 3220 | LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), want_zeroes ? 0x00 : 0xaa, false); |
| 3216 | LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, ""); | 3221 | LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, ""); |
| 3217 | LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); | 3222 | LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); |
| 3218 | LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false); | 3223 | LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false); |
| ... | @@ -3535,6 +3540,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -3535,6 +3540,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 3535 | case NodeTypeCharLiteral: | 3540 | case NodeTypeCharLiteral: |
| 3536 | case NodeTypeNullLiteral: | 3541 | case NodeTypeNullLiteral: |
| 3537 | case NodeTypeUndefinedLiteral: | 3542 | case NodeTypeUndefinedLiteral: |
| 3543 | case NodeTypeZeroesLiteral: | ||
| 3538 | case NodeTypeErrorType: | 3544 | case NodeTypeErrorType: |
| 3539 | case NodeTypeTypeLiteral: | 3545 | case NodeTypeTypeLiteral: |
| 3540 | case NodeTypeArrayType: | 3546 | case NodeTypeArrayType: |
| ... | @@ -3562,8 +3568,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -3562,8 +3568,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 3562 | static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) { | 3568 | static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) { |
| 3563 | assert(const_val->ok); | 3569 | assert(const_val->ok); |
| 3564 | 3570 | ||
| 3565 | if (const_val->undef) { | 3571 | switch (const_val->special) { |
| 3566 | return LLVMGetUndef(type_entry->type_ref); | 3572 | case ConstValSpecialUndef: |
| 3573 | return LLVMGetUndef(type_entry->type_ref); | ||
| 3574 | case ConstValSpecialZeroes: | ||
| 3575 | return LLVMConstNull(type_entry->type_ref); | ||
| 3576 | case ConstValSpecialOther: | ||
| 3577 | break; | ||
| 3578 | |||
| 3567 | } | 3579 | } |
| 3568 | 3580 | ||
| 3569 | switch (type_entry->id) { | 3581 | switch (type_entry->id) { |
src/eval.cpp+4-3| ... | @@ -545,7 +545,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -545,7 +545,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 545 | ConstExprValue *const_val, TypeTableEntry *new_type) | 545 | ConstExprValue *const_val, TypeTableEntry *new_type) |
| 546 | { | 546 | { |
| 547 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | 547 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; |
| 548 | const_val->undef = other_val->undef; | 548 | const_val->special = other_val->special; |
| 549 | 549 | ||
| 550 | assert(other_val != const_val); | 550 | assert(other_val != const_val); |
| 551 | switch (cast_op) { | 551 | switch (cast_op) { |
| ... | @@ -572,7 +572,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -572,7 +572,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 572 | const_val->data.x_ptr.ptr = ptr_val; | 572 | const_val->data.x_ptr.ptr = ptr_val; |
| 573 | const_val->data.x_ptr.len = 1; | 573 | const_val->data.x_ptr.len = 1; |
| 574 | const_val->ok = true; | 574 | const_val->ok = true; |
| 575 | const_val->undef = other_val->undef; | 575 | const_val->special = other_val->special; |
| 576 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | 576 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; |
| 577 | } else { | 577 | } else { |
| 578 | zig_panic("TODO"); | 578 | zig_panic("TODO"); |
| ... | @@ -608,7 +608,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -608,7 +608,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 608 | 608 | ||
| 609 | const_val->data.x_maybe = ptr_parent; | 609 | const_val->data.x_maybe = ptr_parent; |
| 610 | const_val->ok = true; | 610 | const_val->ok = true; |
| 611 | const_val->undef = other_val->undef; | 611 | const_val->special = other_val->special; |
| 612 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | 612 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; |
| 613 | } else { | 613 | } else { |
| 614 | zig_panic("TODO"); | 614 | zig_panic("TODO"); |
| ... | @@ -1277,6 +1277,7 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ... | @@ -1277,6 +1277,7 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { |
| 1277 | case NodeTypeSliceExpr: | 1277 | case NodeTypeSliceExpr: |
| 1278 | case NodeTypeNullLiteral: | 1278 | case NodeTypeNullLiteral: |
| 1279 | case NodeTypeUndefinedLiteral: | 1279 | case NodeTypeUndefinedLiteral: |
| 1280 | case NodeTypeZeroesLiteral: | ||
| 1280 | case NodeTypeIfVarExpr: | 1281 | case NodeTypeIfVarExpr: |
| 1281 | case NodeTypeSwitchExpr: | 1282 | case NodeTypeSwitchExpr: |
| 1282 | case NodeTypeSwitchProng: | 1283 | case NodeTypeSwitchProng: |
src/parser.cpp+11-1| ... | @@ -606,7 +606,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand | ... | @@ -606,7 +606,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand |
| 606 | 606 | ||
| 607 | /* | 607 | /* |
| 608 | PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol") | 608 | PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol") |
| 609 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | 609 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type" |
| 610 | */ | 610 | */ |
| 611 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { | 611 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 612 | Token *token = &pc->tokens->at(*token_index); | 612 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -654,6 +654,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -654,6 +654,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 654 | AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token); | 654 | AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token); |
| 655 | *token_index += 1; | 655 | *token_index += 1; |
| 656 | return node; | 656 | return node; |
| 657 | } else if (token->id == TokenIdKeywordZeroes) { | ||
| 658 | AstNode *node = ast_create_node(pc, NodeTypeZeroesLiteral, token); | ||
| 659 | *token_index += 1; | ||
| 660 | return node; | ||
| 657 | } else if (token->id == TokenIdKeywordType) { | 661 | } else if (token->id == TokenIdKeywordType) { |
| 658 | AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token); | 662 | AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token); |
| 659 | *token_index += 1; | 663 | *token_index += 1; |
| ... | @@ -2539,6 +2543,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -2539,6 +2543,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2539 | case NodeTypeUndefinedLiteral: | 2543 | case NodeTypeUndefinedLiteral: |
| 2540 | // none | 2544 | // none |
| 2541 | break; | 2545 | break; |
| 2546 | case NodeTypeZeroesLiteral: | ||
| 2547 | // none | ||
| 2548 | break; | ||
| 2542 | case NodeTypeIfBoolExpr: | 2549 | case NodeTypeIfBoolExpr: |
| 2543 | visit_field(&node->data.if_bool_expr.condition, visit, context); | 2550 | visit_field(&node->data.if_bool_expr.condition, visit, context); |
| 2544 | visit_field(&node->data.if_bool_expr.then_block, visit, context); | 2551 | visit_field(&node->data.if_bool_expr.then_block, visit, context); |
| ... | @@ -2813,6 +2820,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, | ... | @@ -2813,6 +2820,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, |
| 2813 | case NodeTypeUndefinedLiteral: | 2820 | case NodeTypeUndefinedLiteral: |
| 2814 | // none | 2821 | // none |
| 2815 | break; | 2822 | break; |
| 2823 | case NodeTypeZeroesLiteral: | ||
| 2824 | // none | ||
| 2825 | break; | ||
| 2816 | case NodeTypeIfBoolExpr: | 2826 | case NodeTypeIfBoolExpr: |
| 2817 | clone_subtree_field(&new_node->data.if_bool_expr.condition, old_node->data.if_bool_expr.condition, next_node_index); | 2827 | clone_subtree_field(&new_node->data.if_bool_expr.condition, old_node->data.if_bool_expr.condition, next_node_index); |
| 2818 | clone_subtree_field(&new_node->data.if_bool_expr.then_block, old_node->data.if_bool_expr.then_block, next_node_index); | 2828 | clone_subtree_field(&new_node->data.if_bool_expr.then_block, old_node->data.if_bool_expr.then_block, next_node_index); |
src/tokenizer.cpp+2| ... | @@ -137,6 +137,7 @@ static const struct ZigKeyword zig_keywords[] = { | ... | @@ -137,6 +137,7 @@ static const struct ZigKeyword zig_keywords[] = { |
| 137 | {"var", TokenIdKeywordVar}, | 137 | {"var", TokenIdKeywordVar}, |
| 138 | {"volatile", TokenIdKeywordVolatile}, | 138 | {"volatile", TokenIdKeywordVolatile}, |
| 139 | {"while", TokenIdKeywordWhile}, | 139 | {"while", TokenIdKeywordWhile}, |
| 140 | {"zeroes", TokenIdKeywordZeroes}, | ||
| 140 | }; | 141 | }; |
| 141 | 142 | ||
| 142 | bool is_zig_keyword(Buf *buf) { | 143 | bool is_zig_keyword(Buf *buf) { |
| ... | @@ -1467,6 +1468,7 @@ const char * token_name(TokenId id) { | ... | @@ -1467,6 +1468,7 @@ const char * token_name(TokenId id) { |
| 1467 | case TokenIdKeywordNoAlias: return "noalias"; | 1468 | case TokenIdKeywordNoAlias: return "noalias"; |
| 1468 | case TokenIdKeywordSwitch: return "switch"; | 1469 | case TokenIdKeywordSwitch: return "switch"; |
| 1469 | case TokenIdKeywordUndefined: return "undefined"; | 1470 | case TokenIdKeywordUndefined: return "undefined"; |
| 1471 | case TokenIdKeywordZeroes: return "zeroes"; | ||
| 1470 | case TokenIdKeywordError: return "error"; | 1472 | case TokenIdKeywordError: return "error"; |
| 1471 | case TokenIdKeywordType: return "type"; | 1473 | case TokenIdKeywordType: return "type"; |
| 1472 | case TokenIdKeywordInline: return "inline"; | 1474 | case TokenIdKeywordInline: return "inline"; |
src/tokenizer.hpp+1| ... | @@ -40,6 +40,7 @@ enum TokenId { | ... | @@ -40,6 +40,7 @@ enum TokenId { |
| 40 | TokenIdKeywordNoAlias, | 40 | TokenIdKeywordNoAlias, |
| 41 | TokenIdKeywordSwitch, | 41 | TokenIdKeywordSwitch, |
| 42 | TokenIdKeywordUndefined, | 42 | TokenIdKeywordUndefined, |
| 43 | TokenIdKeywordZeroes, | ||
| 43 | TokenIdKeywordError, | 44 | TokenIdKeywordError, |
| 44 | TokenIdKeywordType, | 45 | TokenIdKeywordType, |
| 45 | TokenIdKeywordInline, | 46 | TokenIdKeywordInline, |
test/cases/zeroes.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | struct Foo { | ||
| 4 | a: f32, | ||
| 5 | b: i32, | ||
| 6 | c: bool, | ||
| 7 | d: ?i32, | ||
| 8 | } | ||
| 9 | |||
| 10 | #attribute("test") | ||
| 11 | fn initializing_a_struct_with_zeroes() { | ||
| 12 | const foo: Foo = zeroes; | ||
| 13 | assert(foo.a == 0.0); | ||
| 14 | assert(foo.b == 0); | ||
| 15 | assert(foo.c == false); | ||
| 16 | assert(if (const x ?= foo.d) false else true); | ||
| 17 | } | ||
| 18 | |||
test/self_hosted.zig+1| ... | @@ -4,6 +4,7 @@ const str = std.str; | ... | @@ -4,6 +4,7 @@ const str = std.str; |
| 4 | const cstr = std.cstr; | 4 | const cstr = std.cstr; |
| 5 | const other = @import("other.zig"); | 5 | const other = @import("other.zig"); |
| 6 | const cases_return_type_type = @import("cases/return_type_type.zig"); | 6 | const cases_return_type_type = @import("cases/return_type_type.zig"); |
| 7 | const test_zeroes = @import("cases/zeroes.zig"); | ||
| 7 | 8 | ||
| 8 | // normal comment | 9 | // normal comment |
| 9 | /// this is a documentation comment | 10 | /// this is a documentation comment |