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 {...@@ -42,8 +42,8 @@ struct Rand {
42 /// inclusive and `end` exclusive.42 /// inclusive and `end` exclusive.
43 pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {43 pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
44 const range = end - start;44 const range = end - start;
45 const leftover = #max_int(u64) % range;45 const leftover = #max_value(u64) % range;
46 const upper_bound = #max_int(u64) - leftover;46 const upper_bound = #max_value(u64) - leftover;
47 var rand_val_array : [u8; #sizeof(u64)];47 var rand_val_array : [u8; #sizeof(u64)];
4848
49 while (true) {49 while (true) {
...@@ -90,13 +90,14 @@ pub fn rand_init(r: &Rand, seed: u32) {...@@ -90,13 +90,14 @@ pub fn rand_init(r: &Rand, seed: u32) {
90 var i : #typeof(ARRAY_SIZE) = 1;90 var i : #typeof(ARRAY_SIZE) = 1;
91 while (i < ARRAY_SIZE) {91 while (i < ARRAY_SIZE) {
92 const prev_value : u64 = r.array[i - 1];92 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;
94 i += 1;94 i += 1;
95 }95 }
96}96}
9797
98pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {98pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
99 var rand = rand_init(13);99 var rand : Rand;
100 rand_init(&rand, 13);
100 const answer = rand.range_u64(0, 100) + 1;101 const answer = rand.range_u64(0, 100) + 1;
101 print_str("random number: ");102 print_str("random number: ");
102 print_u64(answer);103 print_u64(answer);
src/analyze.cpp+57-9
...@@ -1482,7 +1482,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -1482,7 +1482,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
1482 }1482 }
14831483
1484 if (implicit_type == nullptr && variable_declaration->is_const) {1484 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"));
1486 implicit_type = g->builtin_types.entry_invalid;1486 implicit_type = g->builtin_types.entry_invalid;
1487 }1487 }
14881488
...@@ -1684,23 +1684,44 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,...@@ -1684,23 +1684,44 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
1684 node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);1684 node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);
1685}1685}
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
1687static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,1702static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1688 TypeTableEntry *expected_type, AstNode *node)1703 TypeTableEntry *expected_type, AstNode *node)
1689{1704{
1690 assert(node->type == NodeTypeCompilerFnType);1705 assert(node->type == NodeTypeCompilerFnType);
16911706
1692 Buf *name = &node->data.compiler_fn_type.name;1707 Buf *name = &node->data.compiler_fn_type.name;
1708 TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
1709
1693 if (buf_eql_str(name, "sizeof")) {1710 if (buf_eql_str(name, "sizeof")) {
1694 TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
1695 uint64_t size_in_bytes = type_entry->size_in_bits / 8;1711 uint64_t size_in_bytes = type_entry->size_in_bits / 8;
16961712
1697 TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes);1713 TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes);
16981714
1699 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;1715 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
1700 assert(!codegen_num_lit->resolved_type);1716 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
1703 return num_lit_type;1720 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'");
1704 } else {1725 } else {
1705 add_node_error(g, node,1726 add_node_error(g, node,
1706 buf_sprintf("invalid compiler function: '%s'", buf_ptr(name)));1727 buf_sprintf("invalid compiler function: '%s'", buf_ptr(name)));
...@@ -1966,16 +1987,43 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1966,16 +1987,43 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1966 break;1987 break;
1967 case PrefixOpBinNot:1988 case PrefixOpBinNot:
1968 {1989 {
1969 // TODO: don't require i321990 AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
1970 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.prefix_op_expr.primary_expr);1991 TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
1971 return_type = g->builtin_types.entry_i32;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 }
1972 break;2005 break;
1973 }2006 }
1974 case PrefixOpNegation:2007 case PrefixOpNegation:
1975 {2008 {
1976 // TODO: don't require i322009 AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
1977 analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.prefix_op_expr.primary_expr);2010 TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
1978 return_type = g->builtin_types.entry_i32;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 }
1979 break;2027 break;
1980 }2028 }
1981 case PrefixOpAddressOf:2029 case PrefixOpAddressOf:
src/codegen.cpp+45-11
...@@ -859,28 +859,38 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV...@@ -859,28 +859,38 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV
859 if (else_node) {859 if (else_node) {
860 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");860 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
861 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");861 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
864 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);870 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
865871
866 LLVMPositionBuilderAtEnd(g->builder, then_block);872 LLVMPositionBuilderAtEnd(g->builder, then_block);
867 LLVMValueRef then_expr_result = gen_expr(g, then_node);873 LLVMValueRef then_expr_result = gen_expr(g, then_node);
868 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)874 if (then_endif_reachable) {
869 LLVMBuildBr(g->builder, endif_block);875 LLVMBuildBr(g->builder, endif_block);
876 }
870877
871 LLVMPositionBuilderAtEnd(g->builder, else_block);878 LLVMPositionBuilderAtEnd(g->builder, else_block);
872 LLVMValueRef else_expr_result = gen_expr(g, else_node);879 LLVMValueRef else_expr_result = gen_expr(g, else_node);
873 if (get_expr_type(else_node)->id != TypeTableEntryIdUnreachable)880 if (else_endif_reachable) {
874 LLVMBuildBr(g->builder, endif_block);881 LLVMBuildBr(g->builder, endif_block);
882 }
875883
876 LLVMPositionBuilderAtEnd(g->builder, endif_block);884 if (then_endif_reachable || else_endif_reachable) {
877 if (use_expr_value) {885 LLVMPositionBuilderAtEnd(g->builder, endif_block);
878 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");886 if (use_expr_value) {
879 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};887 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
880 LLVMBasicBlockRef incoming_blocks[2] = {then_block, else_block};888 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
881 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);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 }
884 }894 }
885895
886 return nullptr;896 return nullptr;
...@@ -1245,14 +1255,38 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {...@@ -1245,14 +1255,38 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
1245 assert(node->type == NodeTypeCompilerFnType);1255 assert(node->type == NodeTypeCompilerFnType);
12461256
1247 Buf *name = &node->data.compiler_fn_type.name;1257 Buf *name = &node->data.compiler_fn_type.name;
1258 TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
1248 if (buf_eql_str(name, "sizeof")) {1259 if (buf_eql_str(name, "sizeof")) {
1249 TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
1250 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;1260 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
1251 AstNodeNumberLiteral num_lit_node;1261 AstNodeNumberLiteral num_lit_node;
1252 num_lit_node.kind = type_entry->data.num_lit.kind;1262 num_lit_node.kind = type_entry->data.num_lit.kind;
1253 num_lit_node.overflow = false;1263 num_lit_node.overflow = false;
1254 num_lit_node.data.x_uint = type_entry->size_in_bits / 8;1264 num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
1255 return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);1265 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 }
1256 } else {1290 } else {
1257 zig_unreachable();1291 zig_unreachable();
1258 }1292 }
std/std.zig+19-2
...@@ -58,15 +58,32 @@ pub fn print_u64(x: u64) -> isize {...@@ -58,15 +58,32 @@ pub fn print_u64(x: u64) -> isize {
58 return write(stdout_fileno, buf.ptr, len);58 return write(stdout_fileno, buf.ptr, len);
59}59}
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
61fn digit_to_char(digit: u64) -> u8 {70fn digit_to_char(digit: u64) -> u8 {
62 '0' + (digit as u8)71 '0' + (digit as u8)
63}72}
6473
65const max_u64_base10_digits: usize = 20;74const 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
67fn buf_print_u64(out_buf: &u8, x: u64) -> usize {85fn buf_print_u64(out_buf: &u8, x: u64) -> usize {
68 // TODO use max_u64_base10_digits instead of hardcoding 2086 var buf: [u8; max_u64_base10_digits];
69 var buf: [u8; 20];
70 var a = x;87 var a = x;
71 var index = max_u64_base10_digits;88 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 {...@@ -399,7 +399,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
399 if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); }399 if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); }
400 if (5 as i32 as i32 != 5) { print_str("BAD 10\n"); }400 if (5 as i32 as i32 != 5) { print_str("BAD 10\n"); }
401 if (!!false) { print_str("BAD 11\n"); }401 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
404 print_str("OK\n");404 print_str("OK\n");
405 return 0;405 return 0;
...@@ -790,6 +790,93 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -790,6 +790,93 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
790 return 0;790 return 0;
791}791}
792 )SOURCE", "20\n");792 )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");
793}880}
794881
795////////////////////////////////////////////////////////////////////////////////////882////////////////////////////////////////////////////////////////////////////////////