diff --git a/core/_preload.odin b/core/_preload.odin index 85941c768..4ebce18e1 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -121,9 +121,8 @@ var ( ) proc type_info_base(info: ^TypeInfo) -> ^TypeInfo { - if info == nil { - return nil; - } + if info == nil -> return nil; + var base = info; match i in base { case TypeInfo.Named: @@ -134,9 +133,8 @@ proc type_info_base(info: ^TypeInfo) -> ^TypeInfo { proc type_info_base_without_enum(info: ^TypeInfo) -> ^TypeInfo { - if info == nil { - return nil; - } + if info == nil -> return nil; + var base = info; match i in base { case TypeInfo.Named: @@ -202,16 +200,20 @@ proc make_source_code_location(file: string, line, column: i64, procedure: strin const DEFAULT_ALIGNMENT = align_of([vector 4]f32); proc __init_context_from_ptr(c: ^Context, other: ^Context) #cc_contextless { - if c == nil { - return; - } + if c == nil -> return; c^ = other^; + + if c.allocator.procedure == nil { + c.allocator = default_allocator(); + } + if c.thread_id == 0 { + c.thread_id = os.current_thread_id(); + } } proc __init_context(c: ^Context) #cc_contextless { - if c == nil { - return; - } + if c == nil -> return; + if c.allocator.procedure == nil { c.allocator = default_allocator(); } @@ -497,9 +499,7 @@ proc __dynamic_array_make(array_: rawptr, elem_size, elem_align: int, len, cap: proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool { var array = ^raw.DynamicArray(array_); - if cap <= array.cap { - return true; - } + if cap <= array.cap -> return true; // __check_context(); if array.allocator.procedure == nil { @@ -512,9 +512,7 @@ proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: in var allocator = array.allocator; var new_data = allocator.procedure(allocator.data, AllocatorMode.Resize, new_size, elem_align, array.data, old_size, 0); - if new_data == nil { - return false; - } + if new_data == nil -> return false; array.data = new_data; array.cap = cap; @@ -525,9 +523,7 @@ proc __dynamic_array_resize(array_: rawptr, elem_size, elem_align: int, len: int var array = ^raw.DynamicArray(array_); var ok = __dynamic_array_reserve(array_, elem_size, elem_align, len); - if ok { - array.len = len; - } + if ok -> array.len = len; return ok; } @@ -546,10 +542,9 @@ proc __dynamic_array_append(array_: rawptr, elem_size, elem_align: int, var cap = 2 * array.cap + max(8, item_count); ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); } - if !ok { - // TODO(bill): Better error handling for failed reservation - return array.len; - } + // TODO(bill): Better error handling for failed reservation + if !ok -> return array.len; + var data = ^u8(array.data); assert(data != nil); __mem_copy(data + (elem_size*array.len), items, elem_size * item_count); @@ -565,10 +560,9 @@ proc __dynamic_array_append_nothing(array_: rawptr, elem_size, elem_align: int) var cap = 2 * array.cap + max(8, 1); ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); } - if !ok { - // TODO(bill): Better error handling for failed reservation - return array.len; - } + // TODO(bill): Better error handling for failed reservation + if !ok -> return array.len; + var data = ^u8(array.data); assert(data != nil); __mem_zero(data + (elem_size*array.len), elem_size); @@ -658,9 +652,7 @@ proc __dynamic_map_rehash(using header: __MapHeader, new_count: int) { __dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count); __dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len); - for i in 0.. nm.hashes[i] = -1; for var i = 0; i < m.entries.len; i++ { if len(nm.hashes) == 0 { @@ -750,9 +742,7 @@ proc __dynamic_map_full(using h: __MapHeader) -> bool { proc __dynamic_map_hash_equal(h: __MapHeader, a, b: __MapKey) -> bool { if a.hash == b.hash { - if h.is_key_string { - return a.str == b.str; - } + if h.is_key_string -> return a.str == b.str; return true; } return false; diff --git a/core/decimal.odin b/core/decimal.odin index 9c982003c..6b89810a7 100644 --- a/core/decimal.odin +++ b/core/decimal.odin @@ -11,9 +11,7 @@ type Decimal struct { proc decimal_to_string(buf: []u8, a: ^Decimal) -> string { proc digit_zero(buf: []u8) -> int { - for _, i in buf { - buf[i] = '0'; - } + for _, i in buf -> buf[i] = '0'; return len(buf); } @@ -198,9 +196,7 @@ proc shift(a: ^Decimal, k: int) { proc can_round_up(a: ^Decimal, nd: int) -> bool { if nd < 0 || nd >= a.count { return false ; } if a.digits[nd] == '5' && nd+1 == a.count { - if a.trunc { - return true; - } + if a.trunc -> return true; return nd > 0 && (a.digits[nd-1]-'0')%2 != 0; } diff --git a/core/fmt.odin b/core/fmt.odin index c1841a7ef..3ded6a6a6 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -189,9 +189,7 @@ proc fprint_type(fd: os.Handle, info: ^TypeInfo) { } proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { - if ti == nil { - return; - } + if ti == nil -> return; using TypeInfo; match info in ti { @@ -242,7 +240,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { var t = info.params.(^Tuple); write_string(buf, "("); for t, i in t.types { - if i > 0 { write_string(buf, ", "); } + if i > 0 -> write_string(buf, ", "); write_type(buf, t); } write_string(buf, ")"); @@ -253,9 +251,9 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { } case Tuple: var count = len(info.names); - if count != 1 { write_string(buf, "("); } + if count != 1 -> write_string(buf, "("); for name, i in info.names { - if i > 0 { write_string(buf, ", "); } + if i > 0 -> write_string(buf, ", "); var t = info.types[i]; @@ -265,7 +263,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { } write_type(buf, t); } - if count != 1 { write_string(buf, ")"); } + if count != 1 -> write_string(buf, ")"); case Array: write_string(buf, "["); @@ -293,8 +291,8 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { case Struct: write_string(buf, "struct "); - if info.packed { write_string(buf, "#packed "); } - if info.ordered { write_string(buf, "#ordered "); } + if info.packed -> write_string(buf, "#packed "); + if info.ordered -> write_string(buf, "#ordered "); if info.custom_align { write_string(buf, "#align "); write_int(buf, i64(info.align), 10); @@ -302,9 +300,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { } write_byte(buf, '{'); for name, i in info.names { - if i > 0 { - write_string(buf, ", "); - } + if i > 0 -> write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_type(buf, info.types[i]); @@ -316,18 +312,14 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { var cf = info.common_fields; var total_count = 0; for name, i in cf.names { - if i > 0 { - write_string(buf, ", "); - } + if i > 0 -> write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_type(buf, cf.types[i]); total_count++; } for name, i in info.variant_names { - if total_count > 0 || i > 0 { - write_string(buf, ", "); - } + if total_count > 0 || i > 0 -> write_string(buf, ", "); write_string(buf, name); write_byte(buf, '{'); defer write_byte(buf, '}'); @@ -337,9 +329,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { var vc = len(variant.names)-len(cf.names); for j in 0..vc { - if j > 0 { - write_string(buf, ", "); - } + if j > 0 -> write_string(buf, ", "); var index = j + len(cf.names); write_string(buf, variant.names[index]); write_string(buf, ": "); @@ -351,9 +341,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { case RawUnion: write_string(buf, "raw_union {"); for name, i in info.names { - if i > 0 { - write_string(buf, ", "); - } + if i > 0 -> write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_type(buf, info.types[i]); @@ -365,9 +353,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { write_type(buf, info.base); write_string(buf, " {"); for name, i in info.names { - if i > 0 { - write_string(buf, ", "); - } + if i > 0 -> write_string(buf, ", "); write_string(buf, name); } write_string(buf, "}"); @@ -380,9 +366,7 @@ proc write_type(buf: ^StringBuffer, ti: ^TypeInfo) { } write_string(buf, " {"); for name, i in info.names { - if i > 0 { - write_string(buf, ", "); - } + if i > 0 -> write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_int(buf, i64(info.bits[i]), 10); @@ -404,9 +388,7 @@ proc _parse_int(s: string, offset: int) -> (result: int, offset: int, ok: bool) var i = 0; for i < len(s[offset..]) { var c = rune(s[offset+i]); - if !is_digit(c) { - break; - } + if !is_digit(c) -> break; i++; result *= 10; @@ -500,19 +482,13 @@ proc fmt_bool(using fi: ^FmtInfo, b: bool, verb: rune) { proc fmt_write_padding(fi: ^FmtInfo, width: int) { - if width <= 0 { - return; - } - var pad_byte: u8 = '0'; - if fi.space { - pad_byte = ' '; - } + if width <= 0 -> return; + + var pad_byte: u8 = fi.space ? ' ' : '0'; var data = string_buffer_data(fi.buf^); var count = min(width, cap(data)-len(data)); - for _ in 0.. write_byte(fi.buf, pad_byte); } proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) { @@ -557,9 +533,9 @@ proc _fmt_int(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, var flags: strconv.IntFlag; - if fi.hash && !fi.zero { flags |= strconv.IntFlag.Prefix; } - if fi.plus { flags |= strconv.IntFlag.Plus; } - if fi.space { flags |= strconv.IntFlag.Space; } + if fi.hash && !fi.zero -> flags |= strconv.IntFlag.Prefix; + if fi.plus -> flags |= strconv.IntFlag.Plus; + if fi.space -> flags |= strconv.IntFlag.Space; var s = strconv.append_bits(buf[start.. 0 && space { - write_byte(fi.buf, ' '); - } + if i > 0 && space -> write_byte(fi.buf, ' '); _fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER); } @@ -810,9 +781,7 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { write_string(fi.buf, info.name); write_byte(fi.buf, '{'); for _, i in b.names { - if i > 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); write_string(fi.buf, b.names[i]); write_string(fi.buf, " = "); @@ -846,9 +815,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { write_byte(fi.buf, '['); defer write_byte(fi.buf, ']'); for i in 0.. 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); + var data = ^u8(v.data) + i*info.elem_size; fmt_arg(fi, any{rawptr(data), info.elem}, verb); } @@ -858,9 +826,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, ']'); var array = ^raw.DynamicArray(v.data); for i in 0.. 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); + var data = ^u8(array.data) + i*info.elem_size; fmt_arg(fi, any{rawptr(data), info.elem}, verb); } @@ -870,9 +837,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, ']'); var slice = ^[]u8(v.data); for _, i in slice { - if i > 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); + var data = &slice[0] + i*info.elem_size; fmt_arg(fi, any{rawptr(data), info.elem}, verb); } @@ -882,9 +848,7 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, '>'); for i in 0.. 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); var data = ^u8(v.data) + i*info.elem_size; fmt_value(fi, any{rawptr(data), info.elem}, verb); @@ -906,9 +870,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { entry_size = ed.elem_size; ) for i in 0.. 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); + var data = ^u8(entries.data) + i*entry_size; var header = ^__MapEntryHeader(data); @@ -932,9 +895,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, '}'); for _, i in info.names { - if i > 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); + write_string(fi.buf, info.names[i]); write_string(fi.buf, " = "); var data = ^u8(v.data) + info.offsets[i]; @@ -947,9 +909,8 @@ proc fmt_value(fi: ^FmtInfo, v: any, verb: rune) { var cf = info.common_fields; for _, i in cf.names { - if i > 0 { - write_string(fi.buf, ", "); - } + if i > 0 -> write_string(fi.buf, ", "); + write_string(fi.buf, cf.names[i]); write_string(fi.buf, " = "); var data = ^u8(v.data) + cf.offsets[i]; @@ -1071,9 +1032,8 @@ proc sbprintln(buf: ^StringBuffer, args: ..any) -> string { fi.buf = buf; for arg, i in args { - if i > 0 { - write_byte(buf, ' '); - } + if i > 0 -> write_byte(buf, ' '); + fmt_value(&fi, args[i], 'v'); } write_byte(buf, '\n'); @@ -1200,14 +1160,10 @@ proc sbprintf(b: ^StringBuffer, fmt: string, args: ..any) -> string { if !fi.reordered && arg_index < len(args) { write_string(b, "%!(EXTRA "); for arg, index in args[arg_index..] { - if index > 0 { - write_string(b, ", "); - } - if arg == nil { - write_string(b, ""); - } else { - fmt_arg(&fi, args[index], 'v'); - } + if index > 0 -> write_string(b, ", "); + + if arg == nil -> write_string(b, ""); + else -> fmt_arg(&fi, args[index], 'v'); } write_string(b, ")"); } diff --git a/misc/shell.bat b/misc/shell.bat index 6135fa507..36db84570 100644 --- a/misc/shell.bat +++ b/misc/shell.bat @@ -1,10 +1,10 @@ @echo off rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL -rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL +call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL +rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL set _NO_DEBUG_HEAP=1 set path=w:\Odin\misc;%path% diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 639cc27db..317822b84 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1221,15 +1221,64 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { isize variable_index = 0; for_array(i, results) { ast_node(field, Field, results[i]); - Type *type = check_type(c, field->type); + AstNode *default_value = unparen_expr(field->default_value); + ExactValue value = {}; + bool default_is_nil = false; + + Type *type = NULL; + if (field->type == NULL) { + Operand o = {}; + check_expr(c, &o, default_value); + if (is_operand_nil(o)) { + default_is_nil = true; + } else if (o.mode != Addressing_Constant) { + error(default_value, "Default parameter must be a constant"); + } else { + value = o.value; + } + + type = default_type(o.type); + } else { + type = check_type(c, field->type); + + if (default_value != NULL) { + Operand o = {}; + check_expr_with_type_hint(c, &o, default_value, type); + + if (is_operand_nil(o)) { + default_is_nil = true; + } else if (o.mode != Addressing_Constant) { + error(default_value, "Default parameter must be a constant"); + } else { + value = o.value; + } + check_is_assignable_to(c, &o, type); + } + } + + if (type == NULL) { + error(results[i], "Invalid parameter type"); + type = t_invalid; + } + if (is_type_untyped(type)) { + error(results[i], "Cannot determine parameter type from a nil"); + type = t_invalid; + } + + if (field->names.count == 0) { Token token = ast_node_token(field->type); token.string = str_lit(""); Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); + param->Variable.default_value = value; + param->Variable.default_is_nil = default_is_nil; variables[variable_index++] = param; } else { for_array(j, field->names) { - Token token = ast_node_token(field->type); + Token token = ast_node_token(results[i]); + if (field->type != NULL) { + token = ast_node_token(field->type); + } token.string = str_lit(""); AstNode *name = field->names[j]; @@ -1240,6 +1289,8 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { } Entity *param = make_entity_param(c->allocator, scope, token, type, false, false); + param->Variable.default_value = value; + param->Variable.default_is_nil = default_is_nil; variables[variable_index++] = param; } } @@ -5002,6 +5053,20 @@ isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { } return -1; } +isize lookup_procedure_result(TypeProc *pt, String result_name) { + isize result_count = pt->result_count; + for (isize i = 0; i < result_count; i++) { + Entity *e = pt->results->Tuple.variables[i]; + String name = e->token.string; + if (name == "_") { + continue; + } + if (name == result_name) { + return i; + } + } + return -1; +} CALL_ARGUMENT_CHECKER(check_named_call_arguments) { ast_node(ce, CallExpr, call); @@ -5013,7 +5078,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { CallArgumentError err = CallArgumentError_None; isize param_count = pt->param_count; - bool *params_visited = gb_alloc_array(c->allocator, bool, param_count); + bool *visited = gb_alloc_array(c->allocator, bool, param_count); for_array(i, ce->args) { AstNode *arg = ce->args[i]; @@ -5036,7 +5101,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { err = CallArgumentError_ParameterNotFound; continue; } - if (params_visited[index]) { + if (visited[index]) { if (show_error) { error(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name)); } @@ -5044,7 +5109,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { continue; } - params_visited[index] = true; + visited[index] = true; Operand *o = &operands[i]; Entity *e = pt->params->Tuple.variables[index]; @@ -5076,7 +5141,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { param_count_to_check--; } for (isize i = 0; i < param_count_to_check; i++) { - if (!params_visited[i]) { + if (!visited[i]) { Entity *e = pt->params->Tuple.variables[i]; if (e->token.string == "_") { continue; @@ -5095,7 +5160,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { if (show_error) { gbString str = type_to_string(e->type); error(call, "Parameter `%.*s` of type `%s` is missing in procedure call", - LIT(e->token.string), str); + LIT(e->token.string), str); gb_string_free(str); } err = CallArgumentError_ParameterMissing; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c4ad2570e..fcd601446 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -786,37 +786,141 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { break; } + bool first_is_field_value = false; + if (rs->results.count > 0) { + bool fail = false; + first_is_field_value = (rs->results[0]->kind == AstNode_FieldValue); + for_array(i, rs->results) { + AstNode *arg = rs->results[i]; + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != AstNode_FieldValue; + } else { + mix = arg->kind == AstNode_FieldValue; + } + if (mix) { + error(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed"); + fail = true; + } + } + + if (fail) { + return; + } + } + Type *proc_type = c->proc_stack[c->proc_stack.count-1]; + TypeProc *pt = &proc_type->Proc; isize result_count = 0; - if (proc_type->Proc.results) { + if (pt->results) { result_count = proc_type->Proc.results->Tuple.variable_count; } - if (result_count > 0) { - Entity **variables = NULL; - if (proc_type->Proc.results != NULL) { - TypeTuple *tuple = &proc_type->Proc.results->Tuple; - variables = tuple->variables; + + isize result_count_excluding_defaults = result_count; + for (isize i = result_count-1; i >= 0; i--) { + Entity *e = pt->results->Tuple.variables[i]; + if (e->kind == Entity_TypeName) { + break; } - if (rs->results.count == 0) { - error(node, "Expected %td return values, got 0", result_count); - } else { - // TokenPos pos = rs->token.pos; - // if (pos.line == 10) { - // gb_printf_err("%s\n", type_to_string(variables[0]->type)); - // } - check_init_variables(c, variables, result_count, - rs->results, str_lit("return statement")); - // if (pos.line == 10) { - // AstNode *x = rs->results[0]; - // gb_printf_err("%s\n", expr_to_string(x)); - // gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x))); - // } + + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.default_value.kind != ExactValue_Invalid || + e->Variable.default_is_nil) { + result_count_excluding_defaults--; + continue; } - } else if (rs->results.count > 0) { - error(rs->results[0], "No return values expected"); + break; } + + Array operands = {}; + defer (array_free(&operands)); + + if (first_is_field_value) { + array_init_count(&operands, heap_allocator(), rs->results.count); + for_array(i, rs->results) { + AstNode *arg = rs->results[i]; + ast_node(fv, FieldValue, arg); + check_expr(c, &operands[i], fv->value); + } + } else { + array_init(&operands, heap_allocator(), 2*rs->results.count); + check_unpack_arguments(c, -1, &operands, rs->results, false); + } + + + if (first_is_field_value) { + bool *visited = gb_alloc_array(c->allocator, bool, result_count); + + for_array(i, rs->results) { + AstNode *arg = rs->results[i]; + ast_node(fv, FieldValue, arg); + if (fv->field->kind != AstNode_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name `%s` in return statement", expr_str); + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.string; + isize index = lookup_procedure_result(pt, name); + if (index < 0) { + error(arg, "No result named `%.*s` for this procedure type", LIT(name)); + continue; + } + if (visited[index]) { + error(arg, "Duplicate result `%.*s` in return statement", LIT(name)); + continue; + } + + visited[index] = true; + Operand *o = &operands[i]; + Entity *e = pt->results->Tuple.variables[index]; + check_assignment(c, &operands[i], e->type, str_lit("return statement")); + } + + for (isize i = 0; i < result_count; i++) { + if (!visited[i]) { + Entity *e = pt->results->Tuple.variables[i]; + if (e->token.string == "_") { + continue; + } + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.default_value.kind != ExactValue_Invalid) { + continue; + } + + if (e->Variable.default_is_nil) { + continue; + } + + gbString str = type_to_string(e->type); + error(node, "Return value `%.*s` of type `%s` is missing in return statement", + LIT(e->token.string), str); + gb_string_free(str); + } + } + } else { + // TODO(bill): Cleanup this checking of variables + if (result_count == 0 && rs->results.count > 0) { + error(rs->results[0], "No return values expected"); + } else if (operands.count > result_count) { + error(node, "Expected a maximum of %td return values, got %td", result_count, operands.count); + } else if (operands.count < result_count_excluding_defaults) { + error(node, "Expected %td return values, got %td", result_count_excluding_defaults, operands.count); + } else if (result_count_excluding_defaults == 0) { + return; + } else if (rs->results.count == 0) { + error(node, "Expected %td return values, got 0", result_count_excluding_defaults); + } else { + isize max_count = rs->results.count; + for (isize i = 0; i < max_count; i++) { + Entity *e = pt->results->Tuple.variables[i]; + check_assignment(c, &operands[i], e->type, str_lit("return statement")); + } + } + } + case_end; case_ast_node(fs, ForStmt, node); diff --git a/src/exact_value.cpp b/src/exact_value.cpp index ac3d6a23f..e84b5b794 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -117,6 +117,39 @@ f64 float_from_string(String string) { i++; } +#if 0 + if (len-i > 2 && + str[i] == '0' && + str[i+1] == 'h') { + i += 2; + u8 *text = string.text; + isize len = string.len; + if (has_prefix) { + text += 2; + len -= 2; + } + + u64 base = 16; + + u64 result = {0}; + for (isize i = 0; i < len; i++) { + Rune r = cast(Rune)text[i]; + if (r == '_') { + continue; + } + u64 v = bit128__digit_value(r); + if (v >= base) { + break; + } + result *= base; + result += v; + } + + + return *cast(f64 *)&result; + } +#endif + f64 value = 0.0; for (; i < len; i++) { Rune r = cast(Rune)str[i]; diff --git a/src/ir.cpp b/src/ir.cpp index 976153e42..b9a2029d9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6120,21 +6120,81 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { case_ast_node(rs, ReturnStmt, node); ir_emit_comment(proc, str_lit("ReturnStmt")); irValue *v = NULL; - TypeTuple *return_type_tuple = &proc->type->Proc.results->Tuple; + TypeTuple *tuple = &proc->type->Proc.results->Tuple; isize return_count = proc->type->Proc.result_count; - if (return_count == 0) { + isize res_count = rs->results.count; + + if (res_count > 0 && + rs->results[0]->kind == AstNode_FieldValue) { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + + Array results; + array_init_count(&results, proc->module->tmp_allocator, return_count); + + for_array(arg_index, rs->results) { + AstNode *arg = rs->results[arg_index]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == AstNode_Ident); + String name = fv->field->Ident.string; + isize index = lookup_procedure_result(&proc->type->Proc, name); + GB_ASSERT(index >= 0); + irValue *expr = ir_build_expr(proc, fv->value); + results[index] = expr; + } + for (isize i = 0; i < return_count; i++) { + Entity *e = tuple->variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + if (results[i] == NULL) { + if (e->Variable.default_value.kind != ExactValue_Invalid) { + results[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + } else { + results[i] = ir_value_nil(proc->module->allocator, e->type); + } + } else { + results[i] = ir_emit_conv(proc, results[i], e->type); + } + } + + if (results.count == 1) { + v = results[0]; + } else { + GB_ASSERT(results.count == return_count); + + Type *ret_type = proc->type->Proc.results; + v = ir_add_local_generated(proc, ret_type); + for_array(i, results) { + irValue *field = ir_emit_struct_ep(proc, v, i); + irValue *res = results[i]; + ir_emit_store(proc, field, res); + } + + v = ir_emit_load(proc, v); + } + } else if (return_count == 0) { // No return values } else if (return_count == 1) { - Entity *e = return_type_tuple->variables[0]; - v = ir_build_expr(proc, rs->results[0]); - v = ir_emit_conv(proc, v, e->type); + Entity *e = tuple->variables[0]; + if (res_count == 0) { + if (e->Variable.default_value.kind != ExactValue_Invalid) { + v = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + } else { + v = ir_value_nil(proc->module->allocator, e->type); + } + } else { + v = ir_build_expr(proc, rs->results[0]); + v = ir_emit_conv(proc, v, e->type); + } } else { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); Array results; array_init(&results, proc->module->tmp_allocator, return_count); - for_array(res_index, rs->results) { + isize total_index = 0; + isize res_index = 0; + for (; res_index < res_count; res_index++) { irValue *res = ir_build_expr(proc, rs->results[res_index]); Type *t = ir_type(res); if (t->kind == Type_Tuple) { @@ -6142,16 +6202,31 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Entity *e = t->Tuple.variables[i]; irValue *v = ir_emit_struct_ev(proc, res, i); array_add(&results, v); + total_index++; } } else { array_add(&results, res); + total_index++; } } + while (total_index < return_count) { + Entity *e = tuple->variables[total_index]; + irValue *res = NULL; + if (e->Variable.default_value.kind != ExactValue_Invalid) { + res = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + } else { + res = ir_value_nil(proc->module->allocator, e->type); + } + array_add(&results, res); + total_index++; + } + + GB_ASSERT(results.count == return_count); Type *ret_type = proc->type->Proc.results; v = ir_add_local_generated(proc, ret_type); for_array(i, results) { - Entity *e = return_type_tuple->variables[i]; + Entity *e = tuple->variables[i]; irValue *res = ir_emit_conv(proc, results[i], e->type); irValue *field = ir_emit_struct_ep(proc, v, i); ir_emit_store(proc, field, res); @@ -6159,7 +6234,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { v = ir_emit_load(proc, v); - gb_temp_arena_memory_end(tmp); } ir_emit_return(proc, v); diff --git a/src/parser.cpp b/src/parser.cpp index 6dc1dd152..ddad5a9f3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3158,7 +3158,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) { return parse_body(f); } -AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow); +AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters); AstNode *parse_results(AstFile *f) { @@ -3170,7 +3170,7 @@ AstNode *parse_results(AstFile *f) { CommentGroup empty_group = {}; Token begin_token = f->curr_token; Array empty_names = {}; - Array list = make_ast_node_array(f); + Array list = make_ast_node_array(f, 1); AstNode *type = parse_type(f); array_add(&list, ast_field(f, empty_names, type, NULL, 0, empty_group, empty_group)); return ast_field_list(f, begin_token, list); @@ -3178,7 +3178,7 @@ AstNode *parse_results(AstFile *f) { AstNode *list = NULL; expect_token(f, Token_OpenParen); - list = parse_field_list(f, NULL, 0, Token_CloseParen); + list = parse_field_list(f, NULL, 0, Token_CloseParen, true); expect_token_after(f, Token_CloseParen, "parameter list"); return list; } @@ -3188,7 +3188,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) { AstNode *results = NULL; expect_token(f, Token_OpenParen); - params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen); + params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen, true); expect_token_after(f, Token_CloseParen, "parameter list"); results = parse_results(f); @@ -3357,7 +3357,7 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) { return false; } -AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) { +AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) { TokenKind separator = Token_Comma; Token start_token = f->curr_token; @@ -3370,13 +3370,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; - bool is_procedure = allowed_flags == FieldFlag_Signature; while (f->curr_token.kind != follow && f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { u32 flags = parse_field_prefixes(f); - AstNode *param = parse_var_type(f, allow_ellipsis, is_procedure); + AstNode *param = parse_var_type(f, allow_ellipsis, allow_default_parameters); AstNodeAndFlags naf = {param, flags}; array_add(&list, naf); if (f->curr_token.kind != Token_Comma) { @@ -3403,12 +3402,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok if (f->curr_token.kind != Token_Eq) { expect_token_after(f, Token_Colon, "field list"); - type = parse_var_type(f, allow_ellipsis, is_procedure); + type = parse_var_type(f, allow_ellipsis, allow_default_parameters); } if (allow_token(f, Token_Eq)) { // TODO(bill): Should this be true==lhs or false==rhs? default_value = parse_expr(f, false); - if (!is_procedure) { + if (!allow_default_parameters) { syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); } } @@ -3439,12 +3438,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok AstNode *default_value = NULL; if (f->curr_token.kind != Token_Eq) { expect_token_after(f, Token_Colon, "field list"); - type = parse_var_type(f, allow_ellipsis, is_procedure); + type = parse_var_type(f, allow_ellipsis, allow_default_parameters); } if (allow_token(f, Token_Eq)) { // TODO(bill): Should this be true==lhs or false==rhs? default_value = parse_expr(f, false); - if (!is_procedure) { + if (!allow_default_parameters) { syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); } } @@ -3486,7 +3485,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) { - return parse_field_list(f, field_count_, flags, Token_CloseBrace); + return parse_field_list(f, field_count_, flags, Token_CloseBrace, false); } AstNode *parse_type_or_ident(AstFile *f) { @@ -3821,7 +3820,14 @@ AstNode *parse_if_stmt(AstFile *f) { syntax_error(f->curr_token, "Expected condition for if statement"); } - body = parse_block_stmt(f, false); + if (allow_token(f, Token_ArrowRight)) { + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } else { + body = parse_block_stmt(f, false); + } if (allow_token(f, Token_else)) { switch (f->curr_token.kind) { @@ -3831,6 +3837,13 @@ AstNode *parse_if_stmt(AstFile *f) { case Token_OpenBrace: else_stmt = parse_block_stmt(f, false); break; + case Token_ArrowRight: { + Token arrow = expect_token(f, Token_ArrowRight); + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } break; default: syntax_error(f->curr_token, "Expected if statement block statement"); else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]); @@ -3858,7 +3871,14 @@ AstNode *parse_when_stmt(AstFile *f) { syntax_error(f->curr_token, "Expected condition for when statement"); } - body = parse_block_stmt(f, true); + if (allow_token(f, Token_ArrowRight)) { + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } else { + body = parse_block_stmt(f, true); + } if (allow_token(f, Token_else)) { switch (f->curr_token.kind) { @@ -3868,6 +3888,13 @@ AstNode *parse_when_stmt(AstFile *f) { case Token_OpenBrace: else_stmt = parse_block_stmt(f, true); break; + case Token_ArrowRight: { + Token arrow = expect_token(f, Token_ArrowRight); + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } break; default: syntax_error(f->curr_token, "Expected when statement block statement"); else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]); @@ -3890,11 +3917,22 @@ AstNode *parse_return_stmt(AstFile *f) { } Token token = expect_token(f, Token_return); - Array results; - if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { - results = parse_rhs_expr_list(f); - } else { - results = make_ast_node_array(f); + Array results = make_ast_node_array(f); + + while (f->curr_token.kind != Token_Semicolon) { + AstNode *arg = parse_expr(f, false); + if (f->curr_token.kind == Token_Eq) { + Token eq = expect_token(f, Token_Eq); + AstNode *value = parse_value(f); + arg = ast_field_value(f, arg, value, eq); + } + + array_add(&results, arg); + if (f->curr_token.kind != Token_Comma || + f->curr_token.kind == Token_EOF) { + break; + } + next_token(f); } AstNode *end = NULL; @@ -3952,7 +3990,8 @@ AstNode *parse_for_stmt(AstFile *f) { } } - if (!is_range && f->curr_token.kind == Token_Semicolon) { + if (!is_range && (f->curr_token.kind == Token_Semicolon || + f->curr_token.kind == Token_ArrowRight)) { next_token(f); init = cond; cond = NULL; @@ -3960,7 +3999,8 @@ AstNode *parse_for_stmt(AstFile *f) { cond = parse_simple_stmt(f, StmtAllowFlag_None); } expect_semicolon(f, cond); - if (f->curr_token.kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace && + f->curr_token.kind != Token_ArrowRight) { post = parse_simple_stmt(f, StmtAllowFlag_None); } } @@ -3968,7 +4008,14 @@ AstNode *parse_for_stmt(AstFile *f) { f->expr_level = prev_level; } - body = parse_block_stmt(f, false); + if (allow_token(f, Token_ArrowRight)) { + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } else { + body = parse_block_stmt(f, false); + } if (is_range) { GB_ASSERT(cond->kind == AstNode_AssignStmt); @@ -4002,7 +4049,7 @@ AstNode *parse_for_stmt(AstFile *f) { AstNode *parse_case_clause(AstFile *f, bool is_type) { Token token = f->curr_token; - Array list = make_ast_node_array(f); + Array list = {}; expect_token(f, Token_case); bool prev_allow_range = f->allow_range; f->allow_range = !is_type; @@ -4224,23 +4271,41 @@ AstNode *parse_stmt(AstFile *f) { case Token_push_allocator: { next_token(f); + AstNode *body = NULL; isize prev_level = f->expr_level; f->expr_level = -1; AstNode *expr = parse_expr(f, false); f->expr_level = prev_level; - AstNode *body = parse_block_stmt(f, false); + if (allow_token(f, Token_ArrowRight)) { + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } else { + body = parse_block_stmt(f, false); + } + return ast_push_allocator(f, token, expr, body); } break; case Token_push_context: { next_token(f); + AstNode *body = NULL; isize prev_level = f->expr_level; f->expr_level = -1; AstNode *expr = parse_expr(f, false); f->expr_level = prev_level; - AstNode *body = parse_block_stmt(f, false); + if (allow_token(f, Token_ArrowRight)) { + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } + } else { + body = parse_block_stmt(f, false); + } + return ast_push_context(f, token, expr, body); } break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d33926260..09a5d3dd9 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -546,7 +546,14 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) { if (t->curr - prev <= 2) { token.kind = Token_Invalid; } - } else { + } /* else if (t->curr_rune == 'h') { // Hexadecimal Float + token.kind = Token_Float; + advance_to_next_rune(t); + scan_mantissa(t, 16); + if (t->curr - prev <= 2) { + token.kind = Token_Invalid; + } + } */ else { seen_decimal_point = false; scan_mantissa(t, 10);