authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-05 06:30:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-05 06:30:49-07:00
log3327b0488d869710940bbd834a3d1e41758a61b5
tree7b50f83acf3de1ca558d92fbf3cfea681b36d312
parenta11d0aaf62e3ebf2f46307d1546b8105792c8dd0

add #min_value() and #max_value()


5 files changed, 214 insertions(+), 27 deletions(-)

example/rand/main.zig+5-4
......@@ -42,8 +42,8 @@ struct Rand {
4242 /// inclusive and `end` exclusive.
4343 pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
4444 const range = end - start;
45 const leftover = #max_int(u64) % range;
46 const upper_bound = #max_int(u64) - leftover;
45 const leftover = #max_value(u64) % range;
46 const upper_bound = #max_value(u64) - leftover;
4747 var rand_val_array : [u8; #sizeof(u64)];
4848
4949 while (true) {
......@@ -90,13 +90,14 @@ pub fn rand_init(r: &Rand, seed: u32) {
9090 var i : #typeof(ARRAY_SIZE) = 1;
9191 while (i < ARRAY_SIZE) {
9292 const prev_value : u64 = r.array[i - 1];
93 r.array[i] = ((previous_value ^ (previous_value << 30)) * 0x6c078965 + i) as u32;
93 r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32;
9494 i += 1;
9595 }
9696}
9797
9898pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
99 var rand = rand_init(13);
99 var rand : Rand;
100 rand_init(&rand, 13);
100101 const answer = rand.range_u64(0, 100) + 1;
101102 print_str("random number: ");
102103 print_u64(answer);
src/analyze.cpp+57-9
......@@ -1482,7 +1482,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
14821482 }
14831483
14841484 if (implicit_type == nullptr && variable_declaration->is_const) {
1485 add_node_error(g, source_node, buf_sprintf("variables must have initial values or be declared 'mut'."));
1485 add_node_error(g, source_node, buf_sprintf("const variable missing initialization"));
14861486 implicit_type = g->builtin_types.entry_invalid;
14871487 }
14881488
......@@ -1684,23 +1684,44 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
16841684 node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);
16851685}
16861686
1687static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTableEntry *type_entry,
1688 const char *err_format)
1689{
1690 if (type_entry->id == TypeTableEntryIdInt ||
1691 type_entry->id == TypeTableEntryIdFloat ||
1692 type_entry->id == TypeTableEntryIdBool)
1693 {
1694 return type_entry;
1695 } else {
1696 add_node_error(g, node,
1697 buf_sprintf(err_format, buf_ptr(&type_entry->name)));
1698 return g->builtin_types.entry_invalid;
1699 }
1700}
1701
16871702static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
16881703 TypeTableEntry *expected_type, AstNode *node)
16891704{
16901705 assert(node->type == NodeTypeCompilerFnType);
16911706
16921707 Buf *name = &node->data.compiler_fn_type.name;
1708 TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
1709
16931710 if (buf_eql_str(name, "sizeof")) {
1694 TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
16951711 uint64_t size_in_bytes = type_entry->size_in_bits / 8;
16961712
16971713 TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes);
16981714
16991715 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
17001716 assert(!codegen_num_lit->resolved_type);
1701 codegen_num_lit->resolved_type = resolve_type_compatibility(g, context, node, expected_type, num_lit_type);
1717 codegen_num_lit->resolved_type = resolve_type_compatibility(g, context, node,
1718 expected_type, num_lit_type);
17021719
17031720 return num_lit_type;
1721 } else if (buf_eql_str(name, "min_value")) {
1722 return analyze_min_max_value(g, node, type_entry, "no min value available for type '%s'");
1723 } else if (buf_eql_str(name, "max_value")) {
1724 return analyze_min_max_value(g, node, type_entry, "no max value available for type '%s'");
17041725 } else {
17051726 add_node_error(g, node,
17061727 buf_sprintf("invalid compiler function: '%s'", buf_ptr(name)));
......@@ -1966,16 +1987,43 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
19661987 break;
19671988 case PrefixOpBinNot:
19681989 {
1969 // TODO: don't require i32
1970 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.prefix_op_expr.primary_expr);
1971 return_type = g->builtin_types.entry_i32;
1990 AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
1991 TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
1992 operand_node);
1993 if (expr_type->id == TypeTableEntryIdInvalid) {
1994 return_type = expr_type;
1995 } else if (expr_type->id == TypeTableEntryIdInt ||
1996 (expr_type->id == TypeTableEntryIdNumberLiteral &&
1997 !is_num_lit_float(expr_type->data.num_lit.kind)))
1998 {
1999 return_type = expr_type;
2000 } else {
2001 add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'",
2002 buf_ptr(&expr_type->name)));
2003 return_type = g->builtin_types.entry_invalid;
2004 }
19722005 break;
19732006 }
19742007 case PrefixOpNegation:
19752008 {
1976 // TODO: don't require i32
1977 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.prefix_op_expr.primary_expr);
1978 return_type = g->builtin_types.entry_i32;
2009 AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
2010 TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
2011 operand_node);
2012 if (expr_type->id == TypeTableEntryIdInvalid) {
2013 return_type = expr_type;
2014 } else if (expr_type->id == TypeTableEntryIdInt &&
2015 expr_type->data.integral.is_signed)
2016 {
2017 return_type = expr_type;
2018 } else if (expr_type->id == TypeTableEntryIdFloat) {
2019 return_type = expr_type;
2020 } else if (expr_type->id == TypeTableEntryIdNumberLiteral) {
2021 return_type = expr_type;
2022 } else {
2023 add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'",
2024 buf_ptr(&expr_type->name)));
2025 return_type = g->builtin_types.entry_invalid;
2026 }
19792027 break;
19802028 }
19812029 case PrefixOpAddressOf:
src/codegen.cpp+45-11
......@@ -859,28 +859,38 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV
859859 if (else_node) {
860860 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
861861 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
862 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
862
863 LLVMBasicBlockRef endif_block;
864 bool then_endif_reachable = get_expr_type(then_node)->id != TypeTableEntryIdUnreachable;
865 bool else_endif_reachable = get_expr_type(else_node)->id != TypeTableEntryIdUnreachable;
866 if (then_endif_reachable || else_endif_reachable) {
867 endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
868 }
863869
864870 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
865871
866872 LLVMPositionBuilderAtEnd(g->builder, then_block);
867873 LLVMValueRef then_expr_result = gen_expr(g, then_node);
868 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
874 if (then_endif_reachable) {
869875 LLVMBuildBr(g->builder, endif_block);
876 }
870877
871878 LLVMPositionBuilderAtEnd(g->builder, else_block);
872879 LLVMValueRef else_expr_result = gen_expr(g, else_node);
873 if (get_expr_type(else_node)->id != TypeTableEntryIdUnreachable)
880 if (else_endif_reachable) {
874881 LLVMBuildBr(g->builder, endif_block);
882 }
875883
876 LLVMPositionBuilderAtEnd(g->builder, endif_block);
877 if (use_expr_value) {
878 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
879 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
880 LLVMBasicBlockRef incoming_blocks[2] = {then_block, else_block};
881 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
884 if (then_endif_reachable || else_endif_reachable) {
885 LLVMPositionBuilderAtEnd(g->builder, endif_block);
886 if (use_expr_value) {
887 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
888 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
889 LLVMBasicBlockRef incoming_blocks[2] = {then_block, else_block};
890 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
882891
883 return phi;
892 return phi;
893 }
884894 }
885895
886896 return nullptr;
......@@ -1245,14 +1255,38 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
12451255 assert(node->type == NodeTypeCompilerFnType);
12461256
12471257 Buf *name = &node->data.compiler_fn_type.name;
1258 TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
12481259 if (buf_eql_str(name, "sizeof")) {
1249 TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
12501260 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
12511261 AstNodeNumberLiteral num_lit_node;
12521262 num_lit_node.kind = type_entry->data.num_lit.kind;
12531263 num_lit_node.overflow = false;
12541264 num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
12551265 return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
1266 } else if (buf_eql_str(name, "min_value")) {
1267 if (type_entry->id == TypeTableEntryIdInt) {
1268 if (type_entry->data.integral.is_signed) {
1269 return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
1270 } else {
1271 return LLVMConstNull(type_entry->type_ref);
1272 }
1273 } else if (type_entry->id == TypeTableEntryIdFloat) {
1274 zig_panic("TODO codegen min_value float");
1275 } else {
1276 zig_unreachable();
1277 }
1278 } else if (buf_eql_str(name, "max_value")) {
1279 if (type_entry->id == TypeTableEntryIdInt) {
1280 if (type_entry->data.integral.is_signed) {
1281 return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
1282 } else {
1283 return LLVMConstAllOnes(type_entry->type_ref);
1284 }
1285 } else if (type_entry->id == TypeTableEntryIdFloat) {
1286 zig_panic("TODO codegen max_value float");
1287 } else {
1288 zig_unreachable();
1289 }
12561290 } else {
12571291 zig_unreachable();
12581292 }
std/std.zig+19-2
......@@ -58,15 +58,32 @@ pub fn print_u64(x: u64) -> isize {
5858 return write(stdout_fileno, buf.ptr, len);
5959}
6060
61// TODO handle buffering and flushing (mutex protected)
62// TODO error handling
63pub fn print_i64(x: i64) -> isize {
64 // TODO use max_u64_base10_digits instead of hardcoding 20
65 var buf: [u8; 20];
66 const len = buf_print_i64(buf.ptr, x);
67 return write(stdout_fileno, buf.ptr, len);
68}
69
6170fn digit_to_char(digit: u64) -> u8 {
6271 '0' + (digit as u8)
6372}
6473
6574const max_u64_base10_digits: usize = 20;
6675
76fn buf_print_i64(out_buf: &u8, x: i64) -> usize {
77 if (x < 0) {
78 out_buf[0] = '-';
79 return 1 + buf_print_u64(&out_buf[1], ((-(x + 1)) as u64) + 1);
80 } else {
81 return buf_print_u64(out_buf, x as u64);
82 }
83}
84
6785fn buf_print_u64(out_buf: &u8, x: u64) -> usize {
68 // TODO use max_u64_base10_digits instead of hardcoding 20
69 var buf: [u8; 20];
86 var buf: [u8; max_u64_base10_digits];
7087 var a = x;
7188 var index = max_u64_base10_digits;
7289
test/run_tests.cpp+88-1
......@@ -399,7 +399,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
399399 if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); }
400400 if (5 as i32 as i32 != 5) { print_str("BAD 10\n"); }
401401 if (!!false) { print_str("BAD 11\n"); }
402 if (7 != --7) { print_str("BAD 12\n"); }
402 if (7 as i32 != --(7 as i32)) { print_str("BAD 12\n"); }
403403
404404 print_str("OK\n");
405405 return 0;
......@@ -790,6 +790,93 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
790790 return 0;
791791}
792792 )SOURCE", "20\n");
793
794 add_simple_case("#min_value() and #max_value()", R"SOURCE(
795use "std.zig";
796pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
797 print_str("max u8: ");
798 print_u64(#max_value(u8));
799 print_str("\n");
800
801 print_str("max u16: ");
802 print_u64(#max_value(u16));
803 print_str("\n");
804
805 print_str("max u32: ");
806 print_u64(#max_value(u32));
807 print_str("\n");
808
809 print_str("max u64: ");
810 print_u64(#max_value(u64));
811 print_str("\n");
812
813 print_str("max i8: ");
814 print_i64(#max_value(i8));
815 print_str("\n");
816
817 print_str("max i16: ");
818 print_i64(#max_value(i16));
819 print_str("\n");
820
821 print_str("max i32: ");
822 print_i64(#max_value(i32));
823 print_str("\n");
824
825 print_str("max i64: ");
826 print_i64(#max_value(i64));
827 print_str("\n");
828
829 print_str("min u8: ");
830 print_u64(#min_value(u8));
831 print_str("\n");
832
833 print_str("min u16: ");
834 print_u64(#min_value(u16));
835 print_str("\n");
836
837 print_str("min u32: ");
838 print_u64(#min_value(u32));
839 print_str("\n");
840
841 print_str("min u64: ");
842 print_u64(#min_value(u64));
843 print_str("\n");
844
845 print_str("min i8: ");
846 print_i64(#min_value(i8));
847 print_str("\n");
848
849 print_str("min i16: ");
850 print_i64(#min_value(i16));
851 print_str("\n");
852
853 print_str("min i32: ");
854 print_i64(#min_value(i32));
855 print_str("\n");
856
857 print_str("min i64: ");
858 print_i64(#min_value(i64));
859 print_str("\n");
860
861 return 0;
862}
863 )SOURCE",
864 "max u8: 255\n"
865 "max u16: 65535\n"
866 "max u32: 4294967295\n"
867 "max u64: 18446744073709551615\n"
868 "max i8: 127\n"
869 "max i16: 32767\n"
870 "max i32: 2147483647\n"
871 "max i64: 9223372036854775807\n"
872 "min u8: 0\n"
873 "min u16: 0\n"
874 "min u32: 0\n"
875 "min u64: 0\n"
876 "min i8: -128\n"
877 "min i16: -32768\n"
878 "min i32: -2147483648\n"
879 "min i64: -9223372036854775808\n");
793880}
794881
795882////////////////////////////////////////////////////////////////////////////////////