add #min_value() and #max_value()
This commit is contained in:
parent
a11d0aaf62
commit
3327b0488d
@ -42,8 +42,8 @@ struct Rand {
|
||||
/// inclusive and `end` exclusive.
|
||||
pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
|
||||
const range = end - start;
|
||||
const leftover = #max_int(u64) % range;
|
||||
const upper_bound = #max_int(u64) - leftover;
|
||||
const leftover = #max_value(u64) % range;
|
||||
const upper_bound = #max_value(u64) - leftover;
|
||||
var rand_val_array : [u8; #sizeof(u64)];
|
||||
|
||||
while (true) {
|
||||
@ -90,13 +90,14 @@ pub fn rand_init(r: &Rand, seed: u32) {
|
||||
var i : #typeof(ARRAY_SIZE) = 1;
|
||||
while (i < ARRAY_SIZE) {
|
||||
const prev_value : u64 = r.array[i - 1];
|
||||
r.array[i] = ((previous_value ^ (previous_value << 30)) * 0x6c078965 + i) as u32;
|
||||
r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
var rand = rand_init(13);
|
||||
var rand : Rand;
|
||||
rand_init(&rand, 13);
|
||||
const answer = rand.range_u64(0, 100) + 1;
|
||||
print_str("random number: ");
|
||||
print_u64(answer);
|
||||
|
@ -1482,7 +1482,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
||||
}
|
||||
|
||||
if (implicit_type == nullptr && variable_declaration->is_const) {
|
||||
add_node_error(g, source_node, buf_sprintf("variables must have initial values or be declared 'mut'."));
|
||||
add_node_error(g, source_node, buf_sprintf("const variable missing initialization"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
@ -1684,23 +1684,44 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
|
||||
node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTableEntry *type_entry,
|
||||
const char *err_format)
|
||||
{
|
||||
if (type_entry->id == TypeTableEntryIdInt ||
|
||||
type_entry->id == TypeTableEntryIdFloat ||
|
||||
type_entry->id == TypeTableEntryIdBool)
|
||||
{
|
||||
return type_entry;
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf(err_format, buf_ptr(&type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
assert(node->type == NodeTypeCompilerFnType);
|
||||
|
||||
Buf *name = &node->data.compiler_fn_type.name;
|
||||
TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
|
||||
|
||||
if (buf_eql_str(name, "sizeof")) {
|
||||
TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
|
||||
uint64_t size_in_bytes = type_entry->size_in_bits / 8;
|
||||
|
||||
TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes);
|
||||
|
||||
NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
|
||||
assert(!codegen_num_lit->resolved_type);
|
||||
codegen_num_lit->resolved_type = resolve_type_compatibility(g, context, node, expected_type, num_lit_type);
|
||||
codegen_num_lit->resolved_type = resolve_type_compatibility(g, context, node,
|
||||
expected_type, num_lit_type);
|
||||
|
||||
return num_lit_type;
|
||||
} else if (buf_eql_str(name, "min_value")) {
|
||||
return analyze_min_max_value(g, node, type_entry, "no min value available for type '%s'");
|
||||
} else if (buf_eql_str(name, "max_value")) {
|
||||
return analyze_min_max_value(g, node, type_entry, "no max value available for type '%s'");
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("invalid compiler function: '%s'", buf_ptr(name)));
|
||||
@ -1966,16 +1987,43 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||
break;
|
||||
case PrefixOpBinNot:
|
||||
{
|
||||
// TODO: don't require i32
|
||||
analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.prefix_op_expr.primary_expr);
|
||||
return_type = g->builtin_types.entry_i32;
|
||||
AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
|
||||
operand_node);
|
||||
if (expr_type->id == TypeTableEntryIdInvalid) {
|
||||
return_type = expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdInt ||
|
||||
(expr_type->id == TypeTableEntryIdNumberLiteral &&
|
||||
!is_num_lit_float(expr_type->data.num_lit.kind)))
|
||||
{
|
||||
return_type = expr_type;
|
||||
} else {
|
||||
add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'",
|
||||
buf_ptr(&expr_type->name)));
|
||||
return_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrefixOpNegation:
|
||||
{
|
||||
// TODO: don't require i32
|
||||
analyze_expression(g, import, context, g->builtin_types.entry_i32, node->data.prefix_op_expr.primary_expr);
|
||||
return_type = g->builtin_types.entry_i32;
|
||||
AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
|
||||
operand_node);
|
||||
if (expr_type->id == TypeTableEntryIdInvalid) {
|
||||
return_type = expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdInt &&
|
||||
expr_type->data.integral.is_signed)
|
||||
{
|
||||
return_type = expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdFloat) {
|
||||
return_type = expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdNumberLiteral) {
|
||||
return_type = expr_type;
|
||||
} else {
|
||||
add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'",
|
||||
buf_ptr(&expr_type->name)));
|
||||
return_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrefixOpAddressOf:
|
||||
|
@ -859,28 +859,38 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV
|
||||
if (else_node) {
|
||||
LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
|
||||
LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
|
||||
LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
|
||||
|
||||
LLVMBasicBlockRef endif_block;
|
||||
bool then_endif_reachable = get_expr_type(then_node)->id != TypeTableEntryIdUnreachable;
|
||||
bool else_endif_reachable = get_expr_type(else_node)->id != TypeTableEntryIdUnreachable;
|
||||
if (then_endif_reachable || else_endif_reachable) {
|
||||
endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
|
||||
}
|
||||
|
||||
LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, then_block);
|
||||
LLVMValueRef then_expr_result = gen_expr(g, then_node);
|
||||
if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
|
||||
if (then_endif_reachable) {
|
||||
LLVMBuildBr(g->builder, endif_block);
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, else_block);
|
||||
LLVMValueRef else_expr_result = gen_expr(g, else_node);
|
||||
if (get_expr_type(else_node)->id != TypeTableEntryIdUnreachable)
|
||||
if (else_endif_reachable) {
|
||||
LLVMBuildBr(g->builder, endif_block);
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, endif_block);
|
||||
if (use_expr_value) {
|
||||
LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
|
||||
LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
|
||||
LLVMBasicBlockRef incoming_blocks[2] = {then_block, else_block};
|
||||
LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
|
||||
if (then_endif_reachable || else_endif_reachable) {
|
||||
LLVMPositionBuilderAtEnd(g->builder, endif_block);
|
||||
if (use_expr_value) {
|
||||
LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
|
||||
LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
|
||||
LLVMBasicBlockRef incoming_blocks[2] = {then_block, else_block};
|
||||
LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
|
||||
|
||||
return phi;
|
||||
return phi;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -1245,14 +1255,38 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeCompilerFnType);
|
||||
|
||||
Buf *name = &node->data.compiler_fn_type.name;
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
|
||||
if (buf_eql_str(name, "sizeof")) {
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
|
||||
NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = type_entry->data.num_lit.kind;
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
} else if (buf_eql_str(name, "min_value")) {
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
|
||||
} else {
|
||||
return LLVMConstNull(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen min_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else if (buf_eql_str(name, "max_value")) {
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
|
||||
} else {
|
||||
return LLVMConstAllOnes(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen max_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
21
std/std.zig
21
std/std.zig
@ -58,15 +58,32 @@ pub fn print_u64(x: u64) -> isize {
|
||||
return write(stdout_fileno, buf.ptr, len);
|
||||
}
|
||||
|
||||
// TODO handle buffering and flushing (mutex protected)
|
||||
// TODO error handling
|
||||
pub fn print_i64(x: i64) -> isize {
|
||||
// TODO use max_u64_base10_digits instead of hardcoding 20
|
||||
var buf: [u8; 20];
|
||||
const len = buf_print_i64(buf.ptr, x);
|
||||
return write(stdout_fileno, buf.ptr, len);
|
||||
}
|
||||
|
||||
fn digit_to_char(digit: u64) -> u8 {
|
||||
'0' + (digit as u8)
|
||||
}
|
||||
|
||||
const max_u64_base10_digits: usize = 20;
|
||||
|
||||
fn buf_print_i64(out_buf: &u8, x: i64) -> usize {
|
||||
if (x < 0) {
|
||||
out_buf[0] = '-';
|
||||
return 1 + buf_print_u64(&out_buf[1], ((-(x + 1)) as u64) + 1);
|
||||
} else {
|
||||
return buf_print_u64(out_buf, x as u64);
|
||||
}
|
||||
}
|
||||
|
||||
fn buf_print_u64(out_buf: &u8, x: u64) -> usize {
|
||||
// TODO use max_u64_base10_digits instead of hardcoding 20
|
||||
var buf: [u8; 20];
|
||||
var buf: [u8; max_u64_base10_digits];
|
||||
var a = x;
|
||||
var index = max_u64_base10_digits;
|
||||
|
||||
|
@ -399,7 +399,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
|
||||
if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); }
|
||||
if (5 as i32 as i32 != 5) { print_str("BAD 10\n"); }
|
||||
if (!!false) { print_str("BAD 11\n"); }
|
||||
if (7 != --7) { print_str("BAD 12\n"); }
|
||||
if (7 as i32 != --(7 as i32)) { print_str("BAD 12\n"); }
|
||||
|
||||
print_str("OK\n");
|
||||
return 0;
|
||||
@ -790,6 +790,93 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
return 0;
|
||||
}
|
||||
)SOURCE", "20\n");
|
||||
|
||||
add_simple_case("#min_value() and #max_value()", R"SOURCE(
|
||||
use "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
|
||||
print_str("max u8: ");
|
||||
print_u64(#max_value(u8));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max u16: ");
|
||||
print_u64(#max_value(u16));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max u32: ");
|
||||
print_u64(#max_value(u32));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max u64: ");
|
||||
print_u64(#max_value(u64));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max i8: ");
|
||||
print_i64(#max_value(i8));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max i16: ");
|
||||
print_i64(#max_value(i16));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max i32: ");
|
||||
print_i64(#max_value(i32));
|
||||
print_str("\n");
|
||||
|
||||
print_str("max i64: ");
|
||||
print_i64(#max_value(i64));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min u8: ");
|
||||
print_u64(#min_value(u8));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min u16: ");
|
||||
print_u64(#min_value(u16));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min u32: ");
|
||||
print_u64(#min_value(u32));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min u64: ");
|
||||
print_u64(#min_value(u64));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min i8: ");
|
||||
print_i64(#min_value(i8));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min i16: ");
|
||||
print_i64(#min_value(i16));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min i32: ");
|
||||
print_i64(#min_value(i32));
|
||||
print_str("\n");
|
||||
|
||||
print_str("min i64: ");
|
||||
print_i64(#min_value(i64));
|
||||
print_str("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
)SOURCE",
|
||||
"max u8: 255\n"
|
||||
"max u16: 65535\n"
|
||||
"max u32: 4294967295\n"
|
||||
"max u64: 18446744073709551615\n"
|
||||
"max i8: 127\n"
|
||||
"max i16: 32767\n"
|
||||
"max i32: 2147483647\n"
|
||||
"max i64: 9223372036854775807\n"
|
||||
"min u8: 0\n"
|
||||
"min u16: 0\n"
|
||||
"min u32: 0\n"
|
||||
"min u64: 0\n"
|
||||
"min i8: -128\n"
|
||||
"min i16: -32768\n"
|
||||
"min i32: -2147483648\n"
|
||||
"min i64: -9223372036854775808\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
x
Reference in New Issue
Block a user