| author | |
| committer | |
| log | 7f589c0cab105a79ff6d71233538dca8a39f8152 |
| tree | cd3a1eb6b05578bbddbe76feab6ffb63d76f5610 |
| parent | 9ccd0ba9611d7828f42bffca919c7ad3177cbbe1 |
6 files changed, 156 insertions(+), 34 deletions(-)
doc/langref.md+1-1| ... | @@ -93,7 +93,7 @@ IfExpression = IfVarExpression | IfBoolExpression | ... | @@ -93,7 +93,7 @@ IfExpression = IfVarExpression | IfBoolExpression |
| 93 | 93 | ||
| 94 | IfBoolExpression = "if" "(" Expression ")" Expression option(Else) | 94 | IfBoolExpression = "if" "(" Expression ")" Expression option(Else) |
| 95 | 95 | ||
| 96 | IfVarExpression = "if" "(" ("const" | "var") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else) | 96 | IfVarExpression = "if" "(" ("const" | "var") option("*") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else) |
| 97 | 97 | ||
| 98 | Else = "else" Expression | 98 | Else = "else" Expression |
| 99 | 99 |
src/all_types.hpp+2-1| ... | @@ -479,6 +479,7 @@ struct AstNodeIfVarExpr { | ... | @@ -479,6 +479,7 @@ struct AstNodeIfVarExpr { |
| 479 | AstNodeVariableDeclaration var_decl; | 479 | AstNodeVariableDeclaration var_decl; |
| 480 | AstNode *then_block; | 480 | AstNode *then_block; |
| 481 | AstNode *else_node; // null, block node, or other if expr node | 481 | AstNode *else_node; // null, block node, or other if expr node |
| 482 | bool var_is_ptr; | ||
| 482 | 483 | ||
| 483 | // populated by semantic analyzer | 484 | // populated by semantic analyzer |
| 484 | TypeTableEntry *type; | 485 | TypeTableEntry *type; |
| ... | @@ -502,6 +503,7 @@ struct AstNodeForExpr { | ... | @@ -502,6 +503,7 @@ struct AstNodeForExpr { |
| 502 | AstNode *elem_node; // always a symbol | 503 | AstNode *elem_node; // always a symbol |
| 503 | AstNode *index_node; // always a symbol, might be null | 504 | AstNode *index_node; // always a symbol, might be null |
| 504 | AstNode *body; | 505 | AstNode *body; |
| 506 | bool elem_is_ptr; | ||
| 505 | 507 | ||
| 506 | // populated by semantic analyzer | 508 | // populated by semantic analyzer |
| 507 | bool contains_break; | 509 | bool contains_break; |
| ... | @@ -509,7 +511,6 @@ struct AstNodeForExpr { | ... | @@ -509,7 +511,6 @@ struct AstNodeForExpr { |
| 509 | Expr resolved_expr; | 511 | Expr resolved_expr; |
| 510 | VariableTableEntry *elem_var; | 512 | VariableTableEntry *elem_var; |
| 511 | VariableTableEntry *index_var; | 513 | VariableTableEntry *index_var; |
| 512 | bool elem_is_ptr; | ||
| 513 | }; | 514 | }; |
| 514 | 515 | ||
| 515 | struct AstNodeSwitchExpr { | 516 | struct AstNodeSwitchExpr { |
src/analyze.cpp+12-6| ... | @@ -41,7 +41,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node); | ... | @@ -41,7 +41,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node); |
| 41 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, | 41 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, |
| 42 | BlockContext *context, AstNode *source_node, | 42 | BlockContext *context, AstNode *source_node, |
| 43 | AstNodeVariableDeclaration *variable_declaration, | 43 | AstNodeVariableDeclaration *variable_declaration, |
| 44 | bool expr_is_maybe, AstNode *decl_node); | 44 | bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr); |
| 45 | static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node); | 45 | static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node); |
| 46 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); | 46 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); |
| 47 | 47 | ||
| ... | @@ -1582,7 +1582,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) | ... | @@ -1582,7 +1582,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) |
| 1582 | { | 1582 | { |
| 1583 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; | 1583 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; |
| 1584 | VariableTableEntry *var = analyze_variable_declaration_raw(g, import, import->block_context, | 1584 | VariableTableEntry *var = analyze_variable_declaration_raw(g, import, import->block_context, |
| 1585 | node, variable_declaration, false, node); | 1585 | node, variable_declaration, false, node, false); |
| 1586 | 1586 | ||
| 1587 | g->global_vars.append(var); | 1587 | g->global_vars.append(var); |
| 1588 | break; | 1588 | break; |
| ... | @@ -3503,7 +3503,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -3503,7 +3503,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i |
| 3503 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, | 3503 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, |
| 3504 | BlockContext *context, AstNode *source_node, | 3504 | BlockContext *context, AstNode *source_node, |
| 3505 | AstNodeVariableDeclaration *variable_declaration, | 3505 | AstNodeVariableDeclaration *variable_declaration, |
| 3506 | bool expr_is_maybe, AstNode *decl_node) | 3506 | bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr) |
| 3507 | { | 3507 | { |
| 3508 | bool is_const = variable_declaration->is_const; | 3508 | bool is_const = variable_declaration->is_const; |
| 3509 | bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport); | 3509 | bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport); |
| ... | @@ -3528,7 +3528,12 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa | ... | @@ -3528,7 +3528,12 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa |
| 3528 | // ignore the poison value | 3528 | // ignore the poison value |
| 3529 | } else if (expr_is_maybe) { | 3529 | } else if (expr_is_maybe) { |
| 3530 | if (implicit_type->id == TypeTableEntryIdMaybe) { | 3530 | if (implicit_type->id == TypeTableEntryIdMaybe) { |
| 3531 | implicit_type = implicit_type->data.maybe.child_type; | 3531 | if (var_is_ptr) { |
| 3532 | // TODO if the expression is constant, can't get pointer to it | ||
| 3533 | implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false); | ||
| 3534 | } else { | ||
| 3535 | implicit_type = implicit_type->data.maybe.child_type; | ||
| 3536 | } | ||
| 3532 | } else { | 3537 | } else { |
| 3533 | add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type")); | 3538 | add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type")); |
| 3534 | implicit_type = g->builtin_types.entry_invalid; | 3539 | implicit_type = g->builtin_types.entry_invalid; |
| ... | @@ -3575,7 +3580,8 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE | ... | @@ -3575,7 +3580,8 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE |
| 3575 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node) | 3580 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node) |
| 3576 | { | 3581 | { |
| 3577 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; | 3582 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; |
| 3578 | return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, false, nullptr); | 3583 | return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, |
| 3584 | false, nullptr, false); | ||
| 3579 | } | 3585 | } |
| 3580 | 3586 | ||
| 3581 | static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import, | 3587 | static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import, |
| ... | @@ -3945,7 +3951,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3945,7 +3951,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 3945 | BlockContext *child_context = new_block_context(node, parent_context); | 3951 | BlockContext *child_context = new_block_context(node, parent_context); |
| 3946 | 3952 | ||
| 3947 | analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true, | 3953 | analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true, |
| 3948 | nullptr); | 3954 | nullptr, node->data.if_var_expr.var_is_ptr); |
| 3949 | VariableTableEntry *var = node->data.if_var_expr.var_decl.variable; | 3955 | VariableTableEntry *var = node->data.if_var_expr.var_decl.variable; |
| 3950 | if (var->type->id == TypeTableEntryIdInvalid) { | 3956 | if (var->type->id == TypeTableEntryIdInvalid) { |
| 3951 | return g->builtin_types.entry_invalid; | 3957 | return g->builtin_types.entry_invalid; |
src/codegen.cpp+94-23| ... | @@ -212,7 +212,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); | ... | @@ -212,7 +212,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); |
| 212 | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); | 212 | static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); |
| 213 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); | 213 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); |
| 214 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, | 214 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, |
| 215 | bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type); | 215 | bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type, bool var_is_ptr); |
| 216 | static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, | 216 | static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, |
| 217 | LLVMValueRef target_ref, LLVMValueRef value, | 217 | LLVMValueRef target_ref, LLVMValueRef value, |
| 218 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); | 218 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); |
| ... | @@ -2102,21 +2102,32 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) { | ... | @@ -2102,21 +2102,32 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) { |
| 2102 | } | 2102 | } |
| 2103 | } | 2103 | } |
| 2104 | 2104 | ||
| 2105 | static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) { | ||
| 2106 | BlockContext *block_context = var->block_context; | ||
| 2107 | AstNode *source_node = var->decl_node; | ||
| 2108 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1, | ||
| 2109 | block_context->di_scope); | ||
| 2110 | LLVMZigInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc, | ||
| 2111 | LLVMGetInsertBlock(g->builder)); | ||
| 2112 | } | ||
| 2113 | |||
| 2105 | static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { | 2114 | static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { |
| 2106 | assert(node->type == NodeTypeIfVarExpr); | 2115 | assert(node->type == NodeTypeIfVarExpr); |
| 2107 | assert(node->data.if_var_expr.var_decl.expr); | 2116 | assert(node->data.if_var_expr.var_decl.expr); |
| 2108 | 2117 | ||
| 2109 | LLVMValueRef init_val; | 2118 | AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl; |
| 2110 | TypeTableEntry *expr_type; | 2119 | VariableTableEntry *variable = var_decl->variable; |
| 2111 | gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, true, &init_val, &expr_type); | ||
| 2112 | 2120 | ||
| 2113 | // test if value is the maybe state | 2121 | // test if value is the maybe state |
| 2114 | assert(expr_type->id == TypeTableEntryIdMaybe); | 2122 | TypeTableEntry *expr_type = get_expr_type(var_decl->expr); |
| 2115 | TypeTableEntry *child_type = expr_type->data.maybe.child_type; | 2123 | TypeTableEntry *child_type = expr_type->data.maybe.child_type; |
| 2124 | |||
| 2125 | LLVMValueRef init_val = gen_expr(g, var_decl->expr); | ||
| 2126 | |||
| 2116 | LLVMValueRef cond_value; | 2127 | LLVMValueRef cond_value; |
| 2117 | if (child_type->id == TypeTableEntryIdPointer || | 2128 | bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; |
| 2118 | child_type->id == TypeTableEntryIdFn) | 2129 | if (maybe_is_ptr) { |
| 2119 | { | 2130 | set_debug_source_node(g, node); |
| 2120 | cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), ""); | 2131 | cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), ""); |
| 2121 | } else { | 2132 | } else { |
| 2122 | set_debug_source_node(g, node); | 2133 | set_debug_source_node(g, node); |
| ... | @@ -2124,11 +2135,80 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { | ... | @@ -2124,11 +2135,80 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { |
| 2124 | cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); | 2135 | cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); |
| 2125 | } | 2136 | } |
| 2126 | 2137 | ||
| 2127 | LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value, | 2138 | AstNode *then_node = node->data.if_var_expr.then_block; |
| 2128 | node->data.if_var_expr.then_block, | 2139 | AstNode *else_node = node->data.if_var_expr.else_node; |
| 2129 | node->data.if_var_expr.else_node); | 2140 | |
| 2141 | TypeTableEntry *then_type = get_expr_type(then_node); | ||
| 2142 | TypeTableEntry *else_type = get_expr_type(else_node); | ||
| 2143 | |||
| 2144 | bool use_then_value = type_has_bits(then_type); | ||
| 2145 | bool use_else_value = type_has_bits(else_type); | ||
| 2146 | |||
| 2147 | LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen"); | ||
| 2148 | LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse"); | ||
| 2149 | |||
| 2150 | LLVMBasicBlockRef endif_block; | ||
| 2151 | bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable; | ||
| 2152 | bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable; | ||
| 2153 | if (then_endif_reachable || else_endif_reachable) { | ||
| 2154 | endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf"); | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | set_debug_source_node(g, node); | ||
| 2158 | LLVMBuildCondBr(g->builder, cond_value, then_block, else_block); | ||
| 2159 | |||
| 2160 | LLVMPositionBuilderAtEnd(g->builder, then_block); | ||
| 2161 | if (node->data.if_var_expr.var_is_ptr) { | ||
| 2162 | LLVMValueRef payload_ptr; | ||
| 2163 | if (maybe_is_ptr) { | ||
| 2164 | zig_panic("TODO"); | ||
| 2165 | } else { | ||
| 2166 | payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, ""); | ||
| 2167 | } | ||
| 2168 | LLVMBuildStore(g->builder, payload_ptr, variable->value_ref); | ||
| 2169 | } else { | ||
| 2170 | LLVMValueRef payload_val; | ||
| 2171 | if (maybe_is_ptr) { | ||
| 2172 | payload_val = init_val; | ||
| 2173 | } else { | ||
| 2174 | LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, ""); | ||
| 2175 | payload_val = get_handle_value(g, node, payload_ptr, child_type); | ||
| 2176 | } | ||
| 2177 | gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val, | ||
| 2178 | variable->type, child_type); | ||
| 2179 | } | ||
| 2180 | gen_var_debug_decl(g, variable); | ||
| 2181 | |||
| 2182 | LLVMValueRef then_expr_result = gen_expr(g, then_node); | ||
| 2183 | if (then_endif_reachable) { | ||
| 2184 | LLVMBuildBr(g->builder, endif_block); | ||
| 2185 | } | ||
| 2186 | LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder); | ||
| 2187 | |||
| 2130 | 2188 | ||
| 2131 | return return_value; | 2189 | LLVMPositionBuilderAtEnd(g->builder, else_block); |
| 2190 | LLVMValueRef else_expr_result = gen_expr(g, else_node); | ||
| 2191 | if (else_endif_reachable) { | ||
| 2192 | LLVMBuildBr(g->builder, endif_block); | ||
| 2193 | } | ||
| 2194 | LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder); | ||
| 2195 | |||
| 2196 | if (then_endif_reachable || else_endif_reachable) { | ||
| 2197 | LLVMPositionBuilderAtEnd(g->builder, endif_block); | ||
| 2198 | if (use_then_value && use_else_value) { | ||
| 2199 | LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), ""); | ||
| 2200 | LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result}; | ||
| 2201 | LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block}; | ||
| 2202 | LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); | ||
| 2203 | return phi; | ||
| 2204 | } else if (use_then_value) { | ||
| 2205 | return then_expr_result; | ||
| 2206 | } else if (use_else_value) { | ||
| 2207 | return else_expr_result; | ||
| 2208 | } | ||
| 2209 | } | ||
| 2210 | |||
| 2211 | return nullptr; | ||
| 2132 | } | 2212 | } |
| 2133 | 2213 | ||
| 2134 | static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { | 2214 | static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { |
| ... | @@ -2456,15 +2536,6 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { | ... | @@ -2456,15 +2536,6 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 2456 | return nullptr; | 2536 | return nullptr; |
| 2457 | } | 2537 | } |
| 2458 | 2538 | ||
| 2459 | static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) { | ||
| 2460 | BlockContext *block_context = var->block_context; | ||
| 2461 | AstNode *source_node = var->decl_node; | ||
| 2462 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1, | ||
| 2463 | block_context->di_scope); | ||
| 2464 | LLVMZigInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc, | ||
| 2465 | LLVMGetInsertBlock(g->builder)); | ||
| 2466 | } | ||
| 2467 | |||
| 2468 | static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { | 2539 | static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { |
| 2469 | assert(node->type == NodeTypeForExpr); | 2540 | assert(node->type == NodeTypeForExpr); |
| 2470 | assert(node->data.for_expr.array_expr); | 2541 | assert(node->data.for_expr.array_expr); |
| ... | @@ -2564,7 +2635,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) { | ... | @@ -2564,7 +2635,7 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) { |
| 2564 | } | 2635 | } |
| 2565 | 2636 | ||
| 2566 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, | 2637 | static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, |
| 2567 | bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type) | 2638 | bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr) |
| 2568 | { | 2639 | { |
| 2569 | VariableTableEntry *variable = var_decl->variable; | 2640 | VariableTableEntry *variable = var_decl->variable; |
| 2570 | 2641 | ||
| ... | @@ -2683,7 +2754,7 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { | ... | @@ -2683,7 +2754,7 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 2683 | 2754 | ||
| 2684 | LLVMValueRef init_val; | 2755 | LLVMValueRef init_val; |
| 2685 | TypeTableEntry *init_val_type; | 2756 | TypeTableEntry *init_val_type; |
| 2686 | return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type); | 2757 | return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type, false); |
| 2687 | } | 2758 | } |
| 2688 | 2759 | ||
| 2689 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { | 2760 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
src/parser.cpp+14-3| ... | @@ -1755,7 +1755,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator | ... | @@ -1755,7 +1755,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator |
| 1755 | /* | 1755 | /* |
| 1756 | IfExpression : IfVarExpression | IfBoolExpression | 1756 | IfExpression : IfVarExpression | IfBoolExpression |
| 1757 | IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) | 1757 | IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else) |
| 1758 | IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else) | 1758 | IfVarExpression = "if" "(" ("const" | "var") option("*") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else) |
| 1759 | */ | 1759 | */ |
| 1760 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1760 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1761 | Token *if_tok = &pc->tokens->at(*token_index); | 1761 | Token *if_tok = &pc->tokens->at(*token_index); |
| ... | @@ -1776,8 +1776,19 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda | ... | @@ -1776,8 +1776,19 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda |
| 1776 | node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst); | 1776 | node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst); |
| 1777 | *token_index += 1; | 1777 | *token_index += 1; |
| 1778 | 1778 | ||
| 1779 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); | 1779 | Token *star_or_symbol = &pc->tokens->at(*token_index); |
| 1780 | ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol); | 1780 | if (star_or_symbol->id == TokenIdStar) { |
| 1781 | *token_index += 1; | ||
| 1782 | node->data.if_var_expr.var_is_ptr = true; | ||
| 1783 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); | ||
| 1784 | ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol); | ||
| 1785 | } else if (star_or_symbol->id == TokenIdSymbol) { | ||
| 1786 | *token_index += 1; | ||
| 1787 | ast_buf_from_token(pc, star_or_symbol, &node->data.if_var_expr.var_decl.symbol); | ||
| 1788 | } else { | ||
| 1789 | ast_invalid_token_error(pc, star_or_symbol); | ||
| 1790 | } | ||
| 1791 | |||
| 1781 | 1792 | ||
| 1782 | Token *eq_or_colon = &pc->tokens->at(*token_index); | 1793 | Token *eq_or_colon = &pc->tokens->at(*token_index); |
| 1783 | if (eq_or_colon->id == TokenIdMaybeAssign) { | 1794 | if (eq_or_colon->id == TokenIdMaybeAssign) { |
test/self_hosted.zig+33| ... | @@ -1409,3 +1409,36 @@ fn string_escapes() { | ... | @@ -1409,3 +1409,36 @@ fn string_escapes() { |
| 1409 | assert(str.eql("\\", "\x5c")); | 1409 | assert(str.eql("\\", "\x5c")); |
| 1410 | assert(str.eql("\u1234\u0069", "\xe1\x88\xb4\x69")); | 1410 | assert(str.eql("\u1234\u0069", "\xe1\x88\xb4\x69")); |
| 1411 | } | 1411 | } |
| 1412 | |||
| 1413 | #attribute("test") | ||
| 1414 | fn if_var_maybe_pointer() { | ||
| 1415 | assert(should_be_a_plus_1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15); | ||
| 1416 | } | ||
| 1417 | #static_eval_enable(false) | ||
| 1418 | fn should_be_a_plus_1(p: Particle) -> u64 { | ||
| 1419 | var maybe_particle: ?Particle = p; | ||
| 1420 | if (const *particle ?= maybe_particle) { | ||
| 1421 | particle.a += 1; | ||
| 1422 | } | ||
| 1423 | if (const particle ?= maybe_particle) { | ||
| 1424 | return particle.a; | ||
| 1425 | } | ||
| 1426 | return 0; | ||
| 1427 | } | ||
| 1428 | struct Particle { | ||
| 1429 | a: u64, | ||
| 1430 | b: u64, | ||
| 1431 | c: u64, | ||
| 1432 | d: u64, | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | #attribute("test") | ||
| 1436 | fn assign_to_if_var_ptr() { | ||
| 1437 | var maybe_bool: ?bool = true; | ||
| 1438 | |||
| 1439 | if (const *b ?= maybe_bool) { | ||
| 1440 | *b = false; | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | assert(??maybe_bool == false); | ||
| 1444 | } |