authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-23 23:30:20-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-23 23:30:20-05:00
log32d8686da80d282e8cd6d84a0e5c331d269a1f69
tree889c1f634f4ff2e7b9d8cb078f11dbb41c4a1b2a
parent17cb85dfb837949cd3a559fe8e99dee1f72463a4

various fixes

* comptime expression is a block expression as it should be * fix var args when number of args passed is 0 * implement const value equality for structs * fix indent when rendering container decl AST * IR: prevent duplicate generation of code when it is partially compile-time evaluated * implement compile time struct field pointer evaluation * fix compile time evaluation of slicing

10 files changed, 84 insertions(+), 42 deletions(-)

doc/langref.md+4-4
......@@ -69,7 +69,9 @@ AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | Un
6969
7070AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%="
7171
72BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression
72BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression
73
74CompTimeExpression = option("comptime") Expression
7375
7476SwitchExpression = option("inline") "switch" "(" Expression ")" "{" many(SwitchProng) "}"
7577
......@@ -141,14 +143,12 @@ StructLiteralField = "." Symbol "=" Expression
141143
142144PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
143145
144PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | CompTimeExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
146PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
145147
146148ArrayType = "[" option(Expression) "]" option("const") TypeExpr
147149
148150GotoExpression = "goto" Symbol
149151
150CompTimeExpression = option("comptime") Expression
151
152152GroupedExpression = "(" Expression ")"
153153
154154KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this"
example/cat/main.zig+4-12
......@@ -16,9 +16,7 @@ pub fn main(args: [][]u8) -> %void {
1616 } else {
1717 var is: io.InStream = undefined;
1818 is.open(arg) %% |err| {
19 %%io.stderr.printf("Unable to open file: ");
20 %%io.stderr.printf(@errorName(err));
21 %%io.stderr.printf("\n");
19 %%io.stderr.printf("Unable to open file: {}\n", @errorName(err));
2220 return err;
2321 };
2422 defer %%is.close();
......@@ -34,9 +32,7 @@ pub fn main(args: [][]u8) -> %void {
3432}
3533
3634fn usage(exe: []u8) -> %void {
37 %%io.stderr.printf("Usage: ");
38 %%io.stderr.printf(exe);
39 %%io.stderr.printf(" [FILE]...\n");
35 %%io.stderr.printf("Usage: {} [FILE]...\n", exe);
4036 return error.Invalid;
4137}
4238
......@@ -45,9 +41,7 @@ fn cat_stream(is: &io.InStream) -> %void {
4541
4642 while (true) {
4743 const bytes_read = is.read(buf) %% |err| {
48 %%io.stderr.printf("Unable to read from stream: ");
49 %%io.stderr.printf(@errorName(err));
50 %%io.stderr.printf("\n");
44 %%io.stderr.printf("Unable to read from stream: {}\n", @errorName(err));
5145 return err;
5246 };
5347
......@@ -56,9 +50,7 @@ fn cat_stream(is: &io.InStream) -> %void {
5650 }
5751
5852 io.stdout.write(buf[0...bytes_read]) %% |err| {
59 %%io.stderr.printf("Unable to write to stdout: ");
60 %%io.stderr.printf(@errorName(err));
61 %%io.stderr.printf("\n");
53 %%io.stderr.printf("Unable to write to stdout: {}\n", @errorName(err));
6254 return err;
6355 };
6456 }
src/all_types.hpp-2
......@@ -1042,8 +1042,6 @@ struct FnTableEntry {
10421042
10431043 ZigList<IrInstruction *> alloca_list;
10441044 ZigList<VariableTableEntry *> variable_list;
1045
1046 VariableTableEntry *var_args_var;
10471045};
10481046
10491047uint32_t fn_table_entry_hash(FnTableEntry*);
src/analyze.cpp+7-1
......@@ -3263,7 +3263,13 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
32633263 case TypeTableEntryIdArray:
32643264 zig_panic("TODO");
32653265 case TypeTableEntryIdStruct:
3266 zig_panic("TODO");
3266 for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) {
3267 ConstExprValue *field_a = &a->data.x_struct.fields[i];
3268 ConstExprValue *field_b = &b->data.x_struct.fields[i];
3269 if (!const_values_equal(field_a, field_b))
3270 return false;
3271 }
3272 return true;
32673273 case TypeTableEntryIdUnion:
32683274 zig_panic("TODO");
32693275 case TypeTableEntryIdUndefLit:
src/ast_render.cpp+1
......@@ -600,6 +600,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
600600 }
601601
602602 ar->indent -= ar->indent_size;
603 print_indent(ar);
603604 fprintf(ar->f, "}");
604605 break;
605606 }
src/ir.cpp+46-16
......@@ -5743,6 +5743,8 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
57435743 IrInstruction *dep_instruction = ir_instruction_get_dep(instruction, dep_i);
57445744 if (dep_instruction == nullptr)
57455745 break;
5746 if (dep_instruction->other)
5747 continue;
57465748 if (dep_instruction->owner_bb == old_bb)
57475749 continue;
57485750 ir_get_new_bb(ira, dep_instruction->owner_bb);
......@@ -7565,19 +7567,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
75657567 }
75667568
75677569 Buf *param_name = param_decl_node->data.param_decl.name;
7568 if (is_var_args) {
7569 if (!impl_fn->var_args_var) {
7570 ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
7571 fn_type_id->param_count, fn_type_id->param_count + 1);
7572 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
7573 *child_scope, param_name, true, var_args_val);
7574 var->value.depends_on_compile_var = true;
7575 *child_scope = var->child_scope;
7576 impl_fn->var_args_var = var;
7577 }
7578 impl_fn->var_args_var->value.data.x_arg_tuple.end_index = fn_type_id->param_count + 1;
7579
7580 } else {
7570 if (!is_var_args) {
75817571 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
75827572 *child_scope, param_name, true, arg_val);
75837573 var->value.depends_on_compile_var = true;
......@@ -7611,7 +7601,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
76117601{
76127602 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
76137603 size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0;
7614 size_t src_param_count = fn_type_id->param_count;
7604 size_t var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
7605 size_t src_param_count = fn_type_id->param_count - var_args_1_or_0;
76157606 size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0;
76167607 AstNode *source_node = call_instruction->base.source_node;
76177608
......@@ -7739,11 +7730,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
77397730 return ira->codegen->builtin_types.entry_invalid;
77407731 }
77417732 }
7733
7734 bool found_first_var_arg = false;
7735 size_t first_var_arg = inst_fn_type_id.param_count;
77427736 for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
77437737 IrInstruction *arg = call_instruction->args[call_i]->other;
77447738 if (arg->value.type->id == TypeTableEntryIdInvalid)
77457739 return ira->codegen->builtin_types.entry_invalid;
77467740
7741 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
7742 assert(param_decl_node->type == NodeTypeParamDecl);
7743 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
7744 if (is_var_args && !found_first_var_arg) {
7745 first_var_arg = inst_fn_type_id.param_count;
7746 found_first_var_arg = true;
7747 }
7748
77477749 if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
77487750 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
77497751 {
......@@ -7751,6 +7753,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
77517753 }
77527754 }
77537755
7756 if (fn_proto_node->data.fn_proto.is_var_args) {
7757 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
7758 Buf *param_name = param_decl_node->data.param_decl.name;
7759
7760 ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
7761 first_var_arg, inst_fn_type_id.param_count);
7762 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
7763 impl_fn->child_scope, param_name, true, var_args_val);
7764 var->value.depends_on_compile_var = true;
7765 impl_fn->child_scope = var->child_scope;
7766 }
77547767 {
77557768 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
77567769 TypeTableEntry *return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
......@@ -8317,8 +8330,9 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
83178330 if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
83188331 ConstPtrSpecial ptr_special = is_comptime ? ConstPtrSpecialInline : ConstPtrSpecialNone;
83198332 bool is_const = (var->value.type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
8333 depends_on_compile_var = mem_slot->depends_on_compile_var || depends_on_compile_var || is_comptime;
83208334 return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type,
8321 mem_slot->depends_on_compile_var || depends_on_compile_var, ptr_special, is_const);
8335 depends_on_compile_var, ptr_special, is_const);
83228336 } else {
83238337 ir_build_var_ptr_from(&ira->new_irb, instruction, var, false);
83248338 type_ensure_zero_bits_known(ira->codegen, var->value.type);
......@@ -8513,6 +8527,22 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
85138527
85148528 TypeStructField *field = find_struct_type_field(bare_type, field_name);
85158529 if (field) {
8530 if (instr_is_comptime(container_ptr)) {
8531 ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
8532 if (!ptr_val)
8533 return ira->codegen->builtin_types.entry_invalid;
8534
8535 ConstExprValue *struct_val = const_ptr_pointee(ptr_val);
8536 if (value_is_comptime(struct_val)) {
8537 ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
8538 if (value_is_comptime(field_val)) {
8539 bool depends_on_compile_var = field_val->depends_on_compile_var ||
8540 struct_val->depends_on_compile_var || ptr_val->depends_on_compile_var;
8541 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, field_val,
8542 field_val->type, depends_on_compile_var, ConstPtrSpecialNone, is_const);
8543 }
8544 }
8545 }
85168546 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
85178547 return get_pointer_to_type(ira->codegen, field->type_entry, is_const);
85188548 } else {
......@@ -10937,7 +10967,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1093710967 init_const_ptr(ira->codegen, ptr_val, base_ptr, index, instruction->is_const);
1093810968
1093910969 ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
10940 init_const_usize(ira->codegen, len_val, rel_end);
10970 init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
1094110971
1094210972 return return_type;
1094310973 }
src/parser.cpp+6-6
......@@ -624,7 +624,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
624624}
625625
626626/*
627PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | CompTimeExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
627PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
628628KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this"
629629*/
630630static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
......@@ -709,10 +709,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
709709 if (goto_node)
710710 return goto_node;
711711
712 AstNode *comptime_node = ast_parse_comptime_expr(pc, token_index, false);
713 if (comptime_node)
714 return comptime_node;
715
716712 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
717713 if (grouped_expr_node) {
718714 return grouped_expr_node;
......@@ -1810,7 +1806,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
18101806}
18111807
18121808/*
1813BlockExpression : IfExpression | Block | WhileExpression | ForExpression | SwitchExpression
1809BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression | CompTimeExpression
18141810*/
18151811static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
18161812 Token *token = &pc->tokens->at(*token_index);
......@@ -1835,6 +1831,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool
18351831 if (block)
18361832 return block;
18371833
1834 AstNode *comptime_node = ast_parse_comptime_expr(pc, token_index, false);
1835 if (comptime_node)
1836 return comptime_node;
1837
18381838 if (mandatory)
18391839 ast_invalid_token_error(pc, token);
18401840
test/cases/eval.zig+14
......@@ -1,4 +1,5 @@
11const assert = @import("std").debug.assert;
2const str = @import("std").str;
23
34fn compileTimeRecursion() {
45 @setFnTest(this);
......@@ -161,3 +162,16 @@ fn staticallyInitializedArrayLiteral() {
161162 assert(y[3] == 4);
162163}
163164const st_init_arr_lit_x = []u8{1,2,3,4};
165
166
167fn constSlice() {
168 @setFnTest(this);
169
170 comptime {
171 const a = "1234567890";
172 assert(a.len == 10);
173 const b = a[1...2];
174 assert(b.len == 1);
175 assert(b[0] == '2');
176 }
177}
test/cases/generics.zig+1-1
......@@ -13,7 +13,7 @@ fn max(comptime T: type, a: T, b: T) -> T {
1313}
1414
1515fn add(comptime a: i32, b: i32) -> i32 {
16 return comptime {a} + b;
16 return (comptime {a}) + b;
1717}
1818
1919const the_max = max(u32, 1234, 5678);
test/cases/var_args.zig+1
......@@ -13,4 +13,5 @@ fn testAddArbitraryArgs() {
1313
1414 assert(add(i32(1), i32(2), i32(3), i32(4)) == 10);
1515 assert(add(i32(1234)) == 1234);
16 assert(add() == 0);
1617}