From ed089b44b9634c431785b5fa40c086f59900d740 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 1 Jul 2017 11:38:44 +0100 Subject: [PATCH] `do` keyword for inline statements instead of blocks --- code/demo.odin | 29 +++++++-------- core/_preload.odin | 79 ++++++++++++++++------------------------- core/_soft_numbers.odin | 2 +- core/decimal.odin | 4 +-- core/fmt.odin | 66 +++++++++++++++++----------------- src/check_expr.cpp | 63 ++++++++++++++++++++------------ src/checker.cpp | 9 ++++- src/entity.cpp | 1 + src/parser.cpp | 48 ++++++++++++++++++------- src/tokenizer.cpp | 53 +++++++++++++++------------ src/types.cpp | 8 +++-- 11 files changed, 198 insertions(+), 164 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 1b07028ee..cba0212fb 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,8 +1,9 @@ import ( + "fmt.odin"; +/* "atomics.odin"; "bits.odin"; "decimal.odin"; - "fmt.odin"; "hash.odin"; "math.odin"; "mem.odin"; @@ -15,6 +16,7 @@ import ( "types.odin"; "utf8.odin"; "utf16.odin"; +*/ ) general_stuff :: proc() { @@ -34,6 +36,8 @@ general_stuff :: proc() { // The variadic part allows for extra type checking too which C does not provide c_printf :: proc(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf" ---; } + str := "%d\n"; + c_printf(&str[0], i32(789456123)); Foo :: struct { @@ -72,9 +76,7 @@ foreign_blocks :: proc() { } default_arguments :: proc() { - hello :: proc(a: int = 9, b: int = 9) { - fmt.printf("a is %d; b is %d\n", a, b); - } + hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b); fmt.println("\nTesting default arguments:"); hello(1, 2); hello(1); @@ -179,7 +181,7 @@ default_return_values :: proc() { some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) { match { - case input == 3: return err = Error.WhyTheNumberThree; + case input == 3: return err = Error.WhyTheNumberThree; case input >= 10: return err = Error.TenIsTooBig; } @@ -215,9 +217,7 @@ call_location :: proc() { explicit_parametric_polymorphic_procedures :: proc() { // This is how `new` is actually implemented, see _preload.odin - alloc_type :: proc(T: type) -> ^T { - return ^T(alloc(size_of(T), align_of(T))); - } + alloc_type :: proc(T: type) -> ^T do return ^T(alloc(size_of(T), align_of(T))); int_ptr := alloc_type(int); defer free(int_ptr); @@ -231,9 +231,7 @@ explicit_parametric_polymorphic_procedures :: proc() { add :: proc(T: type, args: ..T) -> T { res: T; - for arg in args { - res += arg; - } + for arg in args do res += arg; return res; } @@ -298,7 +296,7 @@ explicit_parametric_polymorphic_procedures :: proc() { use_empty_slot :: proc(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity { for ok, i in batch.occupied { - if ok -> continue; + if ok do continue; batch.occupied[i] = true; e := &batch.data[i]; @@ -314,7 +312,7 @@ explicit_parametric_polymorphic_procedures :: proc() { gen_new_entity :: proc(manager: ^EntityManager) -> ^Entity { for b in manager.batches { e := use_empty_slot(manager, b); - if e != nil -> return e; + if e != nil do return e; } new_batch := new(EntityBatch); @@ -366,12 +364,9 @@ explicit_parametric_polymorphic_procedures :: proc() { } } - - - main :: proc() { -/* general_stuff(); +/* foreign_blocks(); default_arguments(); named_arguments(); diff --git a/core/_preload.odin b/core/_preload.odin index 77475de87..269bbdf31 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -118,7 +118,7 @@ __argc__: i32; type_info_base :: proc(info: ^TypeInfo) -> ^TypeInfo { - if info == nil -> return nil; + if info == nil do return nil; base := info; match i in base { @@ -130,7 +130,7 @@ type_info_base :: proc(info: ^TypeInfo) -> ^TypeInfo { type_info_base_without_enum :: proc(info: ^TypeInfo) -> ^TypeInfo { - if info == nil -> return nil; + if info == nil do return nil; base := info; match i in base { @@ -195,7 +195,7 @@ make_source_code_location :: proc(file: string, line, column: i64, procedure: st DEFAULT_ALIGNMENT :: align_of([vector 4]f32); __init_context_from_ptr :: proc(c: ^Context, other: ^Context) #cc_contextless { - if c == nil -> return; + if c == nil do return; c^ = other^; if c.allocator.procedure == nil { @@ -207,7 +207,7 @@ __init_context_from_ptr :: proc(c: ^Context, other: ^Context) #cc_contextless { } __init_context :: proc(c: ^Context) #cc_contextless { - if c == nil -> return; + if c == nil do return; if c.allocator.procedure == nil { c.allocator = default_allocator(); @@ -259,30 +259,22 @@ resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_AL } -new :: proc(T: type) -> ^T #inline { - return ^T(alloc(size_of(T), align_of(T))); -} +new :: proc(T: type) -> ^T #inline do return ^T(alloc(size_of(T), align_of(T))); default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr { - if old_memory == nil { - return alloc(new_size, alignment); - } + if old_memory == nil do return alloc(new_size, alignment); if new_size == 0 { free(old_memory); return nil; } - if new_size == old_size { - return old_memory; - } + if new_size == old_size do return old_memory; new_memory := alloc(new_size, alignment); - if new_memory == nil { - return nil; - } + if new_memory == nil do return nil; __mem_copy(new_memory, old_memory, min(old_size, new_size));; free(old_memory); @@ -326,9 +318,9 @@ default_allocator :: proc() -> Allocator { assert :: proc(condition: bool, message := "", using location := #caller_location) -> bool #cc_contextless { if !condition { if len(message) > 0 { - fmt.printf("%s(%d:%d) Runtime assertion: %s\n", fully_pathed_filename, line, column, message); + fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n", fully_pathed_filename, line, column, message); } else { - fmt.printf("%s(%d:%d) Runtime assertion\n", fully_pathed_filename, line, column); + fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion\n", fully_pathed_filename, line, column); } __debug_trap(); } @@ -337,9 +329,9 @@ assert :: proc(condition: bool, message := "", using location := #caller_locatio panic :: proc(message := "", using location := #caller_location) #cc_contextless { if len(message) > 0 { - fmt.printf("%s(%d:%d) Panic: %s\n", fully_pathed_filename, line, column, message); + fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n", fully_pathed_filename, line, column, message); } else { - fmt.printf("%s(%d:%d) Panic\n", fully_pathed_filename, line, column); + fmt.fprintf(os.stderr, "%s(%d:%d) Panic\n", fully_pathed_filename, line, column); } __debug_trap(); } @@ -348,14 +340,10 @@ panic :: proc(message := "", using location := #caller_location) #cc_contextless __string_eq :: proc(a, b: string) -> bool #cc_contextless { - if len(a) != len(b) { - return false; - } - if len(a) == 0 { - return true; - } - if &a[0] == &b[0] { - return true; + match { + case len(a) != len(b): return false; + case len(a) == 0: return true; + case &a[0] == &b[0]: return true; } return __string_cmp(a, b) == 0; } @@ -379,37 +367,30 @@ __complex128_ne :: proc(a, b: complex128) -> bool #cc_contextless #inline { retu __bounds_check_error :: proc(file: string, line, column: int, index, count: int) #cc_contextless { - if 0 <= index && index < count { - return; - } + if 0 <= index && index < count do return; fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n", file, line, column, index, count); __debug_trap(); } __slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) #cc_contextless { - if 0 <= low && low <= high && high <= max { - return; - } + if 0 <= low && low <= high && high <= max do return; fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..<%d..<%d]\n", file, line, column, low, high, max); __debug_trap(); } __substring_expr_error :: proc(file: string, line, column: int, low, high: int) #cc_contextless { - if 0 <= low && low <= high { - return; - } + if 0 <= low && low <= high do return; fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..<%d]\n", file, line, column, low, high); __debug_trap(); } __type_assertion_check :: proc(ok: bool, file: string, line, column: int, from, to: ^TypeInfo) #cc_contextless { - if !ok { - fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n", - file, line, column, from, to); - __debug_trap(); - } + if ok do return; + fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n", + file, line, column, from, to); + __debug_trap(); } __string_decode_rune :: proc(s: string) -> (rune, int) #cc_contextless #inline { @@ -499,7 +480,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool { array := ^raw.DynamicArray(array_); - if cap <= array.cap -> return true; + if cap <= array.cap do return true; // __check_context(); if array.allocator.procedure == nil { @@ -512,7 +493,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: allocator := array.allocator; 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 do return false; array.data = new_data; array.cap = cap; @@ -523,7 +504,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: array := ^raw.DynamicArray(array_); ok := __dynamic_array_reserve(array_, elem_size, elem_align, len); - if ok -> array.len = len; + if ok do array.len = len; return ok; } @@ -543,7 +524,7 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); } // TODO(bill): Better error handling for failed reservation - if !ok -> return array.len; + if !ok do return array.len; data := ^u8(array.data); assert(data != nil); @@ -561,7 +542,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); } // TODO(bill): Better error handling for failed reservation - if !ok -> return array.len; + if !ok do return array.len; data := ^u8(array.data); assert(data != nil); @@ -650,7 +631,7 @@ __dynamic_map_rehash :: proc(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 i in 0.. bool { __dynamic_map_hash_equal :: proc(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 do return a.str == b.str; return true; } return false; diff --git a/core/_soft_numbers.odin b/core/_soft_numbers.odin index 9488a8c88..ed4bfc133 100644 --- a/core/_soft_numbers.odin +++ b/core/_soft_numbers.odin @@ -98,7 +98,7 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name " d >>= 1; } - if rem != nil { rem^ = r; } + if rem != nil do rem^ = r; return q; } diff --git a/core/decimal.odin b/core/decimal.odin index c6c980eaa..f1d6d5fc2 100644 --- a/core/decimal.odin +++ b/core/decimal.odin @@ -11,7 +11,7 @@ Decimal :: struct { decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string { digit_zero :: proc(buf: []u8) -> int { - for _, i in buf -> buf[i] = '0'; + for _, i in buf do buf[i] = '0'; return len(buf); } @@ -194,7 +194,7 @@ shift :: proc(a: ^Decimal, k: int) { can_round_up :: proc(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 do return true; return nd > 0 && (a.digits[nd-1]-'0')%2 != 0; } diff --git a/core/fmt.odin b/core/fmt.odin index 0814a7eb9..499c5e1dc 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -189,7 +189,7 @@ fprint_type :: proc(fd: os.Handle, info: ^TypeInfo) { } write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { - if ti == nil -> return; + if ti == nil do return; using TypeInfo; match info in ti { @@ -240,7 +240,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { t := info.params.(^Tuple); write_string(buf, "("); for t, i in t.types { - if i > 0 -> write_string(buf, ", "); + if i > 0 do write_string(buf, ", "); write_type(buf, t); } write_string(buf, ")"); @@ -251,9 +251,9 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { } case Tuple: count := len(info.names); - if count != 1 -> write_string(buf, "("); + if count != 1 do write_string(buf, "("); for name, i in info.names { - if i > 0 -> write_string(buf, ", "); + if i > 0 do write_string(buf, ", "); t := info.types[i]; @@ -263,7 +263,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { } write_type(buf, t); } - if count != 1 -> write_string(buf, ")"); + if count != 1 do write_string(buf, ")"); case Array: write_string(buf, "["); @@ -291,8 +291,8 @@ write_type :: proc(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 do write_string(buf, "#packed "); + if info.ordered do write_string(buf, "#ordered "); if info.custom_align { write_string(buf, "#align "); write_int(buf, i64(info.align), 10); @@ -300,7 +300,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { } write_byte(buf, '{'); for name, i in info.names { - if i > 0 -> write_string(buf, ", "); + if i > 0 do write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_type(buf, info.types[i]); @@ -312,14 +312,14 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { cf := info.common_fields; total_count := 0; for name, i in cf.names { - if i > 0 -> write_string(buf, ", "); + if i > 0 do 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 do write_string(buf, ", "); write_string(buf, name); write_byte(buf, '{'); defer write_byte(buf, '}'); @@ -329,7 +329,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { vc := len(variant.names)-len(cf.names); for j in 0.. 0 -> write_string(buf, ", "); + if j > 0 do write_string(buf, ", "); index := j + len(cf.names); write_string(buf, variant.names[index]); write_string(buf, ": "); @@ -341,7 +341,7 @@ write_type :: proc(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 do write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_type(buf, info.types[i]); @@ -353,7 +353,7 @@ write_type :: proc(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 do write_string(buf, ", "); write_string(buf, name); } write_string(buf, "}"); @@ -366,7 +366,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { } write_string(buf, " {"); for name, i in info.names { - if i > 0 -> write_string(buf, ", "); + if i > 0 do write_string(buf, ", "); write_string(buf, name); write_string(buf, ": "); write_int(buf, i64(info.bits[i]), 10); @@ -388,7 +388,7 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: boo i := 0; for i < len(s[offset..]) { c := rune(s[offset+i]); - if !is_digit(c) -> break; + if !is_digit(c) do break; i++; result *= 10; @@ -482,13 +482,13 @@ fmt_bool :: proc(using fi: ^FmtInfo, b: bool, verb: rune) { fmt_write_padding :: proc(fi: ^FmtInfo, width: int) { - if width <= 0 -> return; + if width <= 0 do return; pad_byte: u8 = fi.space ? ' ' : '0'; data := string_buffer_data(fi.buf^); count := min(width, cap(data)-len(data)); - for _ in 0.. write_byte(fi.buf, pad_byte); + for _ in 0.. flags |= strconv.IntFlag.Prefix; - if fi.plus -> flags |= strconv.IntFlag.Plus; - if fi.space -> flags |= strconv.IntFlag.Space; + if fi.hash && !fi.zero do flags |= strconv.IntFlag.Prefix; + if fi.plus do flags |= strconv.IntFlag.Plus; + if fi.space do flags |= strconv.IntFlag.Space; s := strconv.append_bits(buf[start.. 0 && space -> write_byte(fi.buf, ' '); + if i > 0 && space do write_byte(fi.buf, ' '); _fmt_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER); } @@ -777,7 +777,7 @@ fmt_value :: proc(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 do write_string(fi.buf, ", "); write_string(fi.buf, b.names[i]); write_string(fi.buf, " = "); @@ -811,7 +811,7 @@ fmt_value :: proc(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 do write_string(fi.buf, ", "); data := ^u8(v.data) + i*info.elem_size; fmt_arg(fi, any{rawptr(data), info.elem}, verb); @@ -822,7 +822,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, ']'); array := ^raw.DynamicArray(v.data); for i in 0.. 0 -> write_string(fi.buf, ", "); + if i > 0 do write_string(fi.buf, ", "); data := ^u8(array.data) + i*info.elem_size; fmt_arg(fi, any{rawptr(data), info.elem}, verb); @@ -833,7 +833,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, ']'); slice := ^[]u8(v.data); for _, i in slice { - if i > 0 -> write_string(fi.buf, ", "); + if i > 0 do write_string(fi.buf, ", "); data := &slice[0] + i*info.elem_size; fmt_arg(fi, any{rawptr(data), info.elem}, verb); @@ -844,7 +844,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, '>'); for i in 0.. 0 -> write_string(fi.buf, ", "); + if i > 0 do write_string(fi.buf, ", "); data := ^u8(v.data) + i*info.elem_size; fmt_value(fi, any{rawptr(data), info.elem}, verb); @@ -866,7 +866,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { entry_size := ed.elem_size; for i in 0.. 0 -> write_string(fi.buf, ", "); + if i > 0 do write_string(fi.buf, ", "); data := ^u8(entries.data) + i*entry_size; header := ^__MapEntryHeader(data); @@ -891,7 +891,7 @@ fmt_value :: proc(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 do write_string(fi.buf, ", "); write_string(fi.buf, info.names[i]); write_string(fi.buf, " = "); @@ -905,7 +905,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { cf := info.common_fields; for _, i in cf.names { - if i > 0 -> write_string(fi.buf, ", "); + if i > 0 do write_string(fi.buf, ", "); write_string(fi.buf, cf.names[i]); write_string(fi.buf, " = "); @@ -1028,7 +1028,7 @@ sbprintln :: proc(buf: ^StringBuffer, args: ..any) -> string { fi.buf = buf; for arg, i in args { - if i > 0 -> write_byte(buf, ' '); + if i > 0 do write_byte(buf, ' '); fmt_value(&fi, args[i], 'v'); } @@ -1155,10 +1155,10 @@ sbprintf :: proc(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 index > 0 do write_string(b, ", "); - if arg == nil -> write_string(b, ""); - else -> fmt_arg(&fi, args[index], 'v'); + if arg == nil do write_string(b, ""); + else do fmt_arg(&fi, args[index], 'v'); } write_string(b, ")"); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 98a0614a7..10827e1aa 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1073,7 +1073,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As } } -bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound) { +bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type) { Operand o = {Addressing_Value}; o.type = source; switch (poly->kind) { @@ -1085,40 +1085,42 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c return check_is_assignable_to(c, &o, poly); case Type_Generic: { - Type *ds = default_type(source); - gb_memmove(poly, ds, gb_size_of(Type)); + if (modify_type) { + Type *ds = default_type(source); + gb_memmove(poly, ds, gb_size_of(Type)); + } return true; } case Type_Pointer: if (source->kind == Type_Pointer) { - return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true); + return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type); } return false; case Type_Atomic: if (source->kind == Type_Atomic) { - return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true); + return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true, modify_type); } return false; case Type_Array: if (source->kind == Type_Array && poly->Array.count == source->Array.count) { - return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true); + return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type); } return false; case Type_DynamicArray: if (source->kind == Type_DynamicArray) { - return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true); + return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true, modify_type); } return false; case Type_Vector: if (source->kind == Type_Vector && poly->Vector.count == source->Vector.count) { - return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true); + return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true, modify_type); } return false; case Type_Slice: if (source->kind == Type_Slice) { - return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true); + return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true, modify_type); } return false; @@ -1137,8 +1139,8 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c return false; case Type_Map: if (source->kind == Type_Map) { - bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true); - bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true); + bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type); + bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type); return key || value; } return false; @@ -1147,21 +1149,26 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c } Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) { + bool modify_type = !c->context.no_polymorphic_errors; if (!is_operand_value(operand)) { - error(operand.expr, "Cannot determine polymorphic type from parameter"); + if (modify_type) { + error(operand.expr, "Cannot determine polymorphic type from parameter"); + } return t_invalid; } - if (is_polymorphic_type_assignable(c, poly_type, operand.type, false)) { + if (is_polymorphic_type_assignable(c, poly_type, operand.type, false, modify_type)) { return poly_type; } - gbString pts = type_to_string(poly_type); - gbString ots = type_to_string(operand.type); - defer (gb_string_free(pts)); - defer (gb_string_free(ots)); - error(operand.expr, - "Cannot determine polymorphic type from parameter: `%s` to `%s`\n" - "\tNote: Record and procedure types are not yet supported", - ots, pts); + if (modify_type) { + gbString pts = type_to_string(poly_type); + gbString ots = type_to_string(operand.type); + defer (gb_string_free(pts)); + defer (gb_string_free(ots)); + error(operand.expr, + "Cannot determine polymorphic type from parameter: `%s` to `%s`\n" + "\tNote: Record and procedure types are not yet supported", + ots, pts); + } return t_invalid; } @@ -1332,7 +1339,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (o.mode == Addressing_Type) { type = o.type; } else { - error(o.expr, "Expected a type to assign to the type parameter"); + if (!c->context.no_polymorphic_errors) { + error(o.expr, "Expected a type to assign to the type parameter"); + } + success = false; type = t_invalid; } } @@ -5338,7 +5348,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { if (o.mode == Addressing_Invalid) { continue; } else if (o.mode != Addressing_Type) { - error(o.expr, "Expected a type for the argument `%.*s`", LIT(e->token.string)); + if (show_error) { + error(o.expr, "Expected a type for the argument `%.*s`", LIT(e->token.string)); + } err = CallArgumentError_WrongTypes; } @@ -5641,6 +5653,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t for (isize i = 0; i < overload_count; i++) { Entity *e = procs[i]; + GB_ASSERT(e->token.string == name); DeclInfo *d = decl_info_of_entity(&c->info, e); GB_ASSERT(d != NULL); check_entity_decl(c, e, d, NULL); @@ -5651,7 +5664,11 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t Type *pt = base_type(p->type); if (pt != NULL && is_type_proc(pt)) { CallArgumentData data = {}; + bool prev = c->context.no_polymorphic_errors; + defer (c->context.no_polymorphic_errors = prev); + c->context.no_polymorphic_errors = true; CallArgumentError err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data); + if (err == CallArgumentError_None) { valids[valid_count].index = i; valids[valid_count].score = data.score; diff --git a/src/checker.cpp b/src/checker.cpp index abb544ef6..02df0f469 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -262,6 +262,7 @@ struct CheckerContext { u32 stmt_state_flags; bool in_defer; // TODO(bill): Actually handle correctly bool allow_polymorphic_types; + bool no_polymorphic_errors; String proc_name; Type * type_hint; DeclInfo * curr_proc_decl; @@ -1474,8 +1475,10 @@ void check_procedure_overloading(Checker *c, Entity *e) { is_invalid = true; break; case ProcOverload_Polymorphic: + #if 1 error(p->token, "Overloaded procedure `%.*s` has a polymorphic counterpart in this scope which is not allowed", LIT(name)); is_invalid = true; + #endif break; case ProcOverload_ParamCount: case ProcOverload_ParamTypes: @@ -1705,7 +1708,11 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco e->identifier = name; if (fl != NULL && e->kind != Entity_Procedure) { - error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_node_strings[init->kind])); + AstNodeKind kind = init->kind; + error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_node_strings[kind])); + if (kind == AstNode_ProcType) { + gb_printf_err("\tDid you forget to append `---` to the procedure?\n"); + } // continue; } diff --git a/src/entity.cpp b/src/entity.cpp index 1327ae285..e38a374fc 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -92,6 +92,7 @@ struct Entity { bool is_foreign; Entity * foreign_library; AstNode * foreign_library_ident; + String link_name; } Variable; struct { bool is_type_alias; diff --git a/src/parser.cpp b/src/parser.cpp index 69b77bf2f..ae54b1dd6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -882,9 +882,13 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { void error(AstNode *node, char *fmt, ...) { + Token token = {}; + if (node != NULL) { + token = ast_node_token(node); + } va_list va; va_start(va, fmt); - error_va(ast_node_token(node), fmt, va); + error_va(token, fmt, va); va_end(va); } @@ -2265,6 +2269,26 @@ AstNode *parse_operand(AstFile *f, bool lhs) { body = parse_body(f); f->curr_proc = curr_proc; + return ast_proc_lit(f, type, body, tags, link_name); + } else if (allow_token(f, Token_do)) { + if ((tags & ProcTag_foreign) != 0) { + syntax_error(token, "A procedure tagged as `#foreign` cannot have a body"); + } + AstNode *curr_proc = f->curr_proc; + AstNode *body = NULL; + f->curr_proc = type; + body = parse_stmt(f); + if (body->kind == AstNode_BlockStmt) { + syntax_error(body, "Expected a normal statement rather than a block statement"); + } else { + Token open = ast_node_token(body); + Token close = ast_node_token(body); + Array stmts = make_ast_node_array(f, 1); + array_add(&stmts, body); + body = ast_block_stmt(f, stmts, open, close); + } + f->curr_proc = curr_proc; + return ast_proc_lit(f, type, body, tags, link_name); } @@ -3787,7 +3811,7 @@ AstNode *parse_if_stmt(AstFile *f) { syntax_error(f->curr_token, "Expected condition for if statement"); } - if (allow_token(f, Token_ArrowRight)) { + if (allow_token(f, Token_do)) { body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); @@ -3804,8 +3828,8 @@ 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); + case Token_do: { + Token arrow = expect_token(f, Token_do); body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); @@ -3838,7 +3862,7 @@ AstNode *parse_when_stmt(AstFile *f) { syntax_error(f->curr_token, "Expected condition for when statement"); } - if (allow_token(f, Token_ArrowRight)) { + if (allow_token(f, Token_do)) { body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); @@ -3855,8 +3879,8 @@ 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); + case Token_do: { + Token arrow = expect_token(f, Token_do); body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); @@ -3958,7 +3982,7 @@ AstNode *parse_for_stmt(AstFile *f) { } if (!is_range && (f->curr_token.kind == Token_Semicolon || - f->curr_token.kind == Token_ArrowRight)) { + f->curr_token.kind == Token_do)) { next_token(f); init = cond; cond = NULL; @@ -3967,7 +3991,7 @@ AstNode *parse_for_stmt(AstFile *f) { } expect_semicolon(f, cond); if (f->curr_token.kind != Token_OpenBrace && - f->curr_token.kind != Token_ArrowRight) { + f->curr_token.kind != Token_do) { post = parse_simple_stmt(f, StmtAllowFlag_None); } } @@ -3975,7 +3999,7 @@ AstNode *parse_for_stmt(AstFile *f) { f->expr_level = prev_level; } - if (allow_token(f, Token_ArrowRight)) { + if (allow_token(f, Token_do)) { body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); @@ -4236,7 +4260,7 @@ AstNode *parse_stmt(AstFile *f) { AstNode *expr = parse_expr(f, false); f->expr_level = prev_level; - if (allow_token(f, Token_ArrowRight)) { + if (allow_token(f, Token_do)) { body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); @@ -4256,7 +4280,7 @@ AstNode *parse_stmt(AstFile *f) { AstNode *expr = parse_expr(f, false); f->expr_level = prev_level; - if (allow_token(f, Token_ArrowRight)) { + if (allow_token(f, Token_do)) { body = parse_stmt(f); if (body->kind == AstNode_BlockStmt) { syntax_error(body, "Expected a normal statement rather than a block statement"); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 7b478692e..24a2397f2 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -36,27 +36,28 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ TOKEN_KIND(Token_CmpAnd, "&&"), \ TOKEN_KIND(Token_CmpOr, "||"), \ \ -TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ - TOKEN_KIND(Token_AddEq, "+="), \ - TOKEN_KIND(Token_SubEq, "-="), \ - TOKEN_KIND(Token_MulEq, "*="), \ - TOKEN_KIND(Token_QuoEq, "/="), \ - TOKEN_KIND(Token_ModEq, "%="), \ - TOKEN_KIND(Token_ModModEq, "%%="), \ - TOKEN_KIND(Token_AndEq, "&="), \ - TOKEN_KIND(Token_OrEq, "|="), \ - TOKEN_KIND(Token_XorEq, "~="), \ - TOKEN_KIND(Token_AndNotEq, "&~="), \ - TOKEN_KIND(Token_ShlEq, "<<="), \ - TOKEN_KIND(Token_ShrEq, ">>="), \ - TOKEN_KIND(Token_CmpAndEq, "&&="), \ - TOKEN_KIND(Token_CmpOrEq, "||="), \ -TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ - TOKEN_KIND(Token_ArrowRight, "->"), \ - TOKEN_KIND(Token_ThickArrowRight, "=>"), \ - TOKEN_KIND(Token_Inc, "++"), \ - TOKEN_KIND(Token_Dec, "--"), \ - TOKEN_KIND(Token_Undef, "---"), \ +TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ + TOKEN_KIND(Token_AddEq, "+="), \ + TOKEN_KIND(Token_SubEq, "-="), \ + TOKEN_KIND(Token_MulEq, "*="), \ + TOKEN_KIND(Token_QuoEq, "/="), \ + TOKEN_KIND(Token_ModEq, "%="), \ + TOKEN_KIND(Token_ModModEq, "%%="), \ + TOKEN_KIND(Token_AndEq, "&="), \ + TOKEN_KIND(Token_OrEq, "|="), \ + TOKEN_KIND(Token_XorEq, "~="), \ + TOKEN_KIND(Token_AndNotEq, "&~="), \ + TOKEN_KIND(Token_ShlEq, "<<="), \ + TOKEN_KIND(Token_ShrEq, ">>="), \ + TOKEN_KIND(Token_CmpAndEq, "&&="), \ + TOKEN_KIND(Token_CmpOrEq, "||="), \ +TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ + TOKEN_KIND(Token_ArrowRight, "->"), \ + TOKEN_KIND(Token_ArrowLeft, "<-"), \ + TOKEN_KIND(Token_DoubleArrowRight, "=>"), \ + TOKEN_KIND(Token_Inc, "++"), \ + TOKEN_KIND(Token_Dec, "--"), \ + TOKEN_KIND(Token_Undef, "---"), \ \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token_CmpEq, "=="), \ @@ -100,6 +101,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_continue, "continue"), \ TOKEN_KIND(Token_fallthrough, "fallthrough"), \ TOKEN_KIND(Token_defer, "defer"), \ + TOKEN_KIND(Token_do, "do"), \ TOKEN_KIND(Token_return, "return"), \ TOKEN_KIND(Token_proc, "proc"), \ TOKEN_KIND(Token_macro, "macro"), \ @@ -914,7 +916,7 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = Token_Eq; if (t->curr_rune == '>') { advance_to_next_rune(t); - token.kind = Token_ThickArrowRight; + token.kind = Token_DoubleArrowRight; } else if (t->curr_rune == '=') { advance_to_next_rune(t); token.kind = Token_CmpEq; @@ -976,7 +978,12 @@ Token tokenizer_get_token(Tokenizer *t) { } break; case '<': - token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); + if (t->curr_rune == '-') { + advance_to_next_rune(t); + token.kind = Token_ArrowLeft; + } else { + token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); + } break; case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break; diff --git a/src/types.cpp b/src/types.cpp index d41843ddc..d941b5450 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1353,14 +1353,16 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { TypeProc px = base_type(x)->Proc; TypeProc py = base_type(y)->Proc; - // if (px.calling_convention != py.calling_convention) { - // return ProcOverload_CallingConvention; - // } if (px.is_polymorphic != py.is_polymorphic) { return ProcOverload_Polymorphic; } + + // if (px.calling_convention != py.calling_convention) { + // return ProcOverload_CallingConvention; + // } + if (px.param_count != py.param_count) { return ProcOverload_ParamCount; }