diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 8a96eb1d00..1dbe000163 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -30,23 +30,24 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { while (true) { print_str("\nGuess a number between 1 and 100: "); var line_buf : [20]u8; - const line = readline(line_buf) ?? { + var line_len : usize; + // TODO fix this awkward error handling + if (readline(line_buf, &line_len) || line_len == line_buf.len) { // TODO full error message fprint_str(stderr_fileno, "unable to read input\n"); return 1; - }; + } - if (const guess ?= parse_u64(line)) { - if (guess > answer) { - print_str("Guess lower.\n"); - } else if (guess < answer) { - print_str("Guess higher.\n"); - } else { - print_str("You win!\n"); - return 0; - } - } else { + var guess : u64; + if (parse_u64(line_buf, 10, &guess)) { print_str("Invalid number format.\n"); + } else if (guess > answer) { + print_str("Guess lower.\n"); + } else if (guess < answer) { + print_str("Guess higher.\n"); + } else { + print_str("You win!\n"); + return 0; } } } diff --git a/src/analyze.hpp b/src/analyze.hpp index c34ec84c05..886bc5ec97 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -209,7 +209,6 @@ struct CodeGen { OutType out_type; FnTableEntry *cur_fn; - LLVMBasicBlockRef cur_basic_block; BlockContext *cur_block_context; ZigList break_block_stack; ZigList continue_block_stack; diff --git a/src/codegen.cpp b/src/codegen.cpp index 93e1c05db6..a9a9bc41e7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -905,6 +905,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { add_debug_source_node(g, node); LLVMBuildBr(g->builder, end_block); } + LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder); LLVMPositionBuilderAtEnd(g->builder, null_block); LLVMValueRef null_result = gen_expr(g, op2_node); @@ -912,6 +913,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { add_debug_source_node(g, node); LLVMBuildBr(g->builder, end_block); } + LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder); if (end_reachable) { LLVMPositionBuilderAtEnd(g->builder, end_block); @@ -919,7 +921,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { add_debug_source_node(g, node); LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), ""); LLVMValueRef incoming_values[2] = {non_null_result, null_result}; - LLVMBasicBlockRef incoming_blocks[2] = {non_null_block, null_block}; + LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block}; LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); return phi; } else { @@ -1015,19 +1017,21 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV if (then_endif_reachable) { LLVMBuildBr(g->builder, endif_block); } + LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder); LLVMPositionBuilderAtEnd(g->builder, else_block); LLVMValueRef else_expr_result = gen_expr(g, else_node); if (else_endif_reachable) { LLVMBuildBr(g->builder, endif_block); } + LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder); 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}; + LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block}; LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); return phi; diff --git a/std/std.zig b/std/std.zig index 411f59b423..da412e3f90 100644 --- a/std/std.zig +++ b/std/std.zig @@ -39,28 +39,63 @@ pub fn print_i64(x: i64) -> isize { return write(stdout_fileno, buf.ptr, len); } -/* // TODO error handling -pub fn readline(buf: []u8) -> ?[]u8 { - var index : usize = 0; - while (index < buf.len) { - // TODO unknown size array indexing operator - const err = read(stdin_fileno, &buf.ptr[index], 1); - if (err != 0) { - return null; - } - // TODO unknown size array indexing operator - if (buf.ptr[index] == '\n') { - return buf[0...index + 1]; - } - index += 1; +pub fn readline(buf: []u8, out_len: &usize) -> bool { + // TODO unknown size array indexing operator + const amt_read = read(stdin_fileno, buf.ptr, buf.len); + if (amt_read < 0) { + return true; } - return null; + *out_len = amt_read as usize; + return false; } -*/ -fn digit_to_char(digit: u64) -> u8 { - '0' + (digit as u8) +// TODO return ?u64 when we support returning struct byval +pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool { + var x : u64 = 0; + + var i : #typeof(buf.len) = 0; + while (i < buf.len) { + // TODO array indexing operator + const c = buf.ptr[i]; + const digit = char_to_digit(c); + + if (digit > radix) { + return true; + } + + x *= radix; + x += digit; + + /* TODO intrinsics mul and add with overflow + // x *= radix + if (@mul_with_overflow_u64(x, radix, &x)) { + return true; + } + + // x += digit + if (@add_with_overflow_u64(x, digit, &x)) { + return true; + } + */ + + i += 1; + } + + *result = x; + return false; +} + +fn char_to_digit(c: u8) -> u8 { + if ('0' <= c && c <= '9') { + c - '0' + } else if ('A' <= c && c <= 'Z') { + c - 'A' + 10 + } else if ('a' <= c && c <= 'z') { + c - 'a' + 10 + } else { + #max_value(u8) + } } const max_u64_base10_digits: usize = 20; @@ -86,7 +121,7 @@ fn buf_print_u64(out_buf: &u8, x: u64) -> usize { while (true) { const digit = a % 10; index -= 1; - buf[index] = digit_to_char(digit); + buf[index] = '0' + (digit as u8); a /= 10; if (a == 0) break; diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 71158e9327..cc93e188e3 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -936,7 +936,27 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { } )SOURCE", "OK\n"); + + add_simple_case("else if expression", R"SOURCE( +use "std.zig"; +pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { + if (f(1) == 1) { + print_str("OK\n"); + } + return 0; } +fn f(c: u8) -> u8 { + if (c == 0) { + 0 + } else if (c == 1) { + 1 + } else { + 2 + } +} + )SOURCE", "OK\n"); +} + ////////////////////////////////////////////////////////////////////////////////////