From 5ce65557219d57d19e9e45c5670b48bb40e22c3f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 12 Nov 2017 17:55:16 +0000 Subject: [PATCH] Allow for default arguments after a variadic parameter --- core/_preload.odin | 152 ++++++++++++++++++++++----------------------- src/check_expr.cpp | 21 ++++++- src/check_type.cpp | 45 ++++++++++---- src/ir.cpp | 150 +++++++++++++++++++++++++++++--------------- src/parser.cpp | 88 ++++++++++++++------------ src/types.cpp | 3 +- 6 files changed, 278 insertions(+), 181 deletions(-) diff --git a/core/_preload.odin b/core/_preload.odin index db9786697..667be2a46 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -144,7 +144,7 @@ __argv__: ^^u8; Source_Code_Location :: struct #ordered { file_path: string, - line, column: i64, + line, column: int, procedure: string, } @@ -259,7 +259,7 @@ foreign __llvm_core { -make_source_code_location :: inline proc "contextless" (file: string, line, column: i64, procedure: string) -> Source_Code_Location { +make_source_code_location :: inline proc "contextless" (file: string, line, column: int, procedure: string) -> Source_Code_Location { return Source_Code_Location{file, line, column, procedure}; } @@ -296,28 +296,28 @@ __check_context :: proc() { } */ -alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr { +alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr { a := context.allocator; - return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, location); + return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc); } -free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, location := #caller_location) { +free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, loc := #caller_location) { if ptr == nil do return; if a.procedure == nil do return; - a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, location); + a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc); } -free_ptr :: inline proc(ptr: rawptr, location := #caller_location) do free_ptr_with_allocator(context.allocator, ptr); +free_ptr :: inline proc(ptr: rawptr, loc := #caller_location) do free_ptr_with_allocator(context.allocator, ptr); -free_all :: inline proc(location := #caller_location) { +free_all :: inline proc(loc := #caller_location) { a := context.allocator; - a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0, location); + a.procedure(a.data, Allocator_Mode.FreeAll, 0, 0, nil, 0, 0, loc); } -resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, location := #caller_location) -> rawptr { +resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr { a := context.allocator; - return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, location); + return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc); } @@ -345,7 +345,7 @@ append :: proc "contextless" (array: ^$T/[]$E, args: ...E) -> int { return len(array); } -append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int { +append :: proc(array: ^$T/[dynamic]$E, args: ...E, loc := #caller_location) -> int { if array == nil do return 0; arg_len := len(args); @@ -355,7 +355,7 @@ append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int { ok := true; if cap(array) <= len(array)+arg_len { cap := 2 * cap(array) + max(8, arg_len); - ok = reserve(array, cap); + ok = reserve(array, cap, loc); } // TODO(bill): Better error handling for failed reservation if ok { @@ -370,13 +370,13 @@ append :: proc(array: ^$T/[dynamic]$E, args: ...E) -> int { append :: proc(array: ^$T/[]u8, args: ...string) -> int { for arg in args { - append(array, ...cast([]u8)arg); + append(array, ...cast(T)arg); } return len(array); } -append :: proc(array: ^$T/[dynamic]u8, args: ...string) -> int { +append :: proc(array: ^$T/[dynamic]$E/u8, args: ...string, loc := #caller_location) -> int { for arg in args { - append(array, ...cast([]u8)arg); + append(array = array, args = cast([]E)arg, loc = loc); } return len(array); } @@ -412,7 +412,7 @@ clear :: inline proc "contextless" (m: ^$T/map[$K]$V) { entries.len = 0; } -reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, location := #caller_location) -> bool { +reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool { if array == nil do return false; a := cast(^raw.Dynamic_Array)array; @@ -429,7 +429,7 @@ reserve :: proc(array: ^$T/[dynamic]$E, capacity: int, location := #caller_locat new_data := allocator.procedure( allocator.data, Allocator_Mode.Resize, new_size, align_of(E), - a.data, old_size, 0, location, + a.data, old_size, 0, loc, ); if new_data == nil do return false; @@ -499,39 +499,39 @@ delete :: proc(m: ^$T/map[$K]$V, key: K) { -new :: inline proc(T: type, location := #caller_location) -> ^T { - ptr := cast(^T)alloc(size_of(T), align_of(T), location); +new :: inline proc(T: type, loc := #caller_location) -> ^T { + ptr := cast(^T)alloc(size_of(T), align_of(T), loc); ptr^ = T{}; return ptr; } -new_clone :: inline proc(data: $T, location := #caller_location) -> ^T { - ptr := cast(^T)alloc(size_of(T), align_of(T), location); +new_clone :: inline proc(data: $T, loc := #caller_location) -> ^T { + ptr := cast(^T)alloc(size_of(T), align_of(T), loc); ptr^ = data; return ptr; } -free :: proc(ptr: rawptr, location := #caller_location) { - free_ptr(ptr, location); +free :: proc(ptr: rawptr, loc := #caller_location) { + free_ptr(ptr, loc); } -free :: proc(str: $T/string, location := #caller_location) { - free_ptr((^raw.String)(&str).data, location); +free :: proc(str: $T/string, loc := #caller_location) { + free_ptr((^raw.String)(&str).data, loc); } -free :: proc(array: $T/[dynamic]$E, location := #caller_location) { - free_ptr((^raw.Dynamic_Array)(&array).data, location); +free :: proc(array: $T/[dynamic]$E, loc := #caller_location) { + free_ptr((^raw.Dynamic_Array)(&array).data, loc); } -free :: proc(slice: $T/[]$E, location := #caller_location) { - free_ptr((^raw.Slice)(&slice).data, location); +free :: proc(slice: $T/[]$E, loc := #caller_location) { + free_ptr((^raw.Slice)(&slice).data, loc); } -free :: proc(m: $T/map[$K]$V, location := #caller_location) { +free :: proc(m: $T/map[$K]$V, loc := #caller_location) { raw := cast(^raw.Map)&m; - free(raw.hashes, location); - free(raw.entries.data, location); + free(raw.hashes, loc); + free(raw.entries.data, loc); } // NOTE(bill): This code works but I will prefer having `make` a built-in procedure // to have better error messages /* -make :: proc(T: type/[]$E, len: int, using location := #caller_location) -> T { +make :: proc(T: type/[]$E, len: int, using loc := #caller_location) -> T { cap := len; __slice_expr_error(file_path, int(line), int(column), 0, len, cap); data := cast(^E)alloc(len * size_of(E), align_of(E)); @@ -539,14 +539,14 @@ make :: proc(T: type/[]$E, len: int, using location := #caller_location) -> T { s := raw.Slice{data = data, len = len, cap = len}; return (cast(^T)&s)^; } -make :: proc(T: type/[]$E, len, cap: int, using location := #caller_location) -> T { +make :: proc(T: type/[]$E, len, cap: int, using loc := #caller_location) -> T { __slice_expr_error(file_path, int(line), int(column), 0, len, cap); data := cast(^E)alloc(len * size_of(E), align_of(E)); for i in 0..len do (data+i)^ = E{}; s := raw.Slice{data = data, len = len, cap = len}; return (cast(^T)&s)^; } -make :: proc(T: type/[dynamic]$E, len: int = 8, using location := #caller_location) -> T { +make :: proc(T: type/[dynamic]$E, len: int = 8, using loc := #caller_location) -> T { cap := len; __slice_expr_error(file_path, int(line), int(column), 0, len, cap); data := cast(^E)alloc(cap * size_of(E), align_of(E)); @@ -554,7 +554,7 @@ make :: proc(T: type/[dynamic]$E, len: int = 8, using location := #caller_locati s := raw.Dynamic_Array{data = data, len = len, cap = cap, allocator = context.allocator}; return (cast(^T)&s)^; } -make :: proc(T: type/[dynamic]$E, len, cap: int, using location := #caller_location) -> T { +make :: proc(T: type/[dynamic]$E, len, cap: int, using loc := #caller_location) -> T { __slice_expr_error(file_path, int(line), int(column), 0, len, cap); data := cast(^E)alloc(cap * size_of(E), align_of(E)); for i in 0..len do (data+i)^ = E{}; @@ -562,7 +562,7 @@ make :: proc(T: type/[dynamic]$E, len, cap: int, using location := #caller_locat return (cast(^T)&s)^; } -make :: proc(T: type/map[$K]$V, cap: int = 16, using location := #caller_location) -> T { +make :: proc(T: type/map[$K]$V, cap: int = 16, using loc := #caller_location) -> T { if cap < 0 do cap = 16; m: T; @@ -574,28 +574,28 @@ make :: proc(T: type/map[$K]$V, cap: int = 16, using location := #caller_locatio -default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, location := #caller_location) -> rawptr { - if old_memory == nil do return alloc(new_size, alignment, location); +default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr { + if old_memory == nil do return alloc(new_size, alignment, loc); if new_size == 0 { - free(old_memory, location); + free(old_memory, loc); return nil; } if new_size == old_size do return old_memory; - new_memory := alloc(new_size, alignment, location); + new_memory := alloc(new_size, alignment, loc); if new_memory == nil do return nil; __mem_copy(new_memory, old_memory, min(old_size, new_size));; - free(old_memory, location); + free(old_memory, loc); return new_memory; } default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr { + old_memory: rawptr, old_size: int, flags: u64, loc := #caller_location) -> rawptr { using Allocator_Mode; switch mode { @@ -626,7 +626,7 @@ default_allocator :: proc() -> Allocator { } -assert :: proc "contextless" (condition: bool, message := "", using location := #caller_location) -> bool { +assert :: proc "contextless" (condition: bool, message := "", using loc := #caller_location) -> bool { if !condition { if len(message) > 0 { fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n", file_path, line, column, message); @@ -638,7 +638,7 @@ assert :: proc "contextless" (condition: bool, message := "", using location := return condition; } -panic :: proc "contextless" (message := "", using location := #caller_location) { +panic :: proc "contextless" (message := "", using loc := #caller_location) { if len(message) > 0 { fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n", file_path, line, column, message); } else { @@ -800,18 +800,18 @@ __abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 { -__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int) { +__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) { array := cast(^raw.Dynamic_Array)array_; array.allocator = context.allocator; assert(array.allocator.procedure != nil); if cap > 0 { - __dynamic_array_reserve(array_, elem_size, elem_align, cap); + __dynamic_array_reserve(array_, elem_size, elem_align, cap, loc); array.len = len; } } -__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool { +__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool { array := cast(^raw.Dynamic_Array)array_; if cap <= array.cap do return true; @@ -825,7 +825,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: new_size := cap * elem_size; allocator := array.allocator; - new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0); + new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0, loc); if new_data == nil do return false; array.data = new_data; @@ -833,17 +833,17 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: return true; } -__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int) -> bool { +__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool { array := cast(^raw.Dynamic_Array)array_; - ok := __dynamic_array_reserve(array_, elem_size, elem_align, len); + ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc); if ok do array.len = len; return ok; } __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, - items: rawptr, item_count: int) -> int { + items: rawptr, item_count: int, loc := #caller_location) -> int { array := cast(^raw.Dynamic_Array)array_; if items == nil do return 0; @@ -853,7 +853,7 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, ok := true; if array.cap <= array.len+item_count { cap := 2 * array.cap + max(8, item_count); - ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); + ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc); } // TODO(bill): Better error handling for failed reservation if !ok do return array.len; @@ -865,13 +865,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, return array.len; } -__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int { +__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int { array := cast(^raw.Dynamic_Array)array_; ok := true; if array.cap <= array.len+1 { cap := 2 * array.cap + max(8, 1); - ok = __dynamic_array_reserve(array, elem_size, elem_align, cap); + ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc); } // TODO(bill): Better error handling for failed reservation if !ok do return array.len; @@ -897,12 +897,12 @@ __default_hash :: proc(data: []u8) -> u128 { } __default_hash_string :: proc(s: string) -> u128 do return __default_hash(cast([]u8)s); -__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int) { - __dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap); - __dynamic_array_reserve(&m.entries, entry_size, entry_align, cap); +__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int, loc := #caller_location) { + __dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap, loc); + __dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc); } -__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { +__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int, loc := #caller_location) { new_header: __Map_Header = header; nm: raw.Map; new_header.m = &nm; @@ -910,18 +910,18 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { header_hashes := cast(^raw.Dynamic_Array)&header.m.hashes; nm_hashes := cast(^raw.Dynamic_Array)&nm.hashes; - __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); + __dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count, loc); + __dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len, loc); for i in 0..new_count do nm.hashes[i] = -1; for i in 0..m.entries.len { - if len(nm.hashes) == 0 do __dynamic_map_grow(new_header); + if len(nm.hashes) == 0 do __dynamic_map_grow(new_header, loc); entry_header := __dynamic_map_get_entry(header, i); data := cast(^u8)entry_header; fr := __dynamic_map_find(new_header, entry_header.key); - j := __dynamic_map_add_entry(new_header, entry_header.key); + j := __dynamic_map_add_entry(new_header, entry_header.key, loc); if fr.entry_prev < 0 { nm.hashes[fr.hash_index] = j; } else { @@ -934,10 +934,10 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { ndata := cast(^u8)e; __mem_copy(ndata+value_offset, data+value_offset, value_size); - if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header); + if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc); } - free_ptr_with_allocator(header_hashes.allocator, header_hashes.data); - free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data); + free_ptr_with_allocator(header_hashes.allocator, header_hashes.data, loc); + free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data, loc); header.m^ = nm; } @@ -950,20 +950,20 @@ __dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr { return nil; } -__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) { +__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr, loc := #caller_location) { index: int; assert(value != nil); if len(m.hashes) == 0 { - __dynamic_map_reserve(h, __INITIAL_MAP_CAP); - __dynamic_map_grow(h); + __dynamic_map_reserve(h, __INITIAL_MAP_CAP, loc); + __dynamic_map_grow(h, loc); } fr := __dynamic_map_find(h, key); if fr.entry_index >= 0 { index = fr.entry_index; } else { - index = __dynamic_map_add_entry(h, key); + index = __dynamic_map_add_entry(h, key, loc); if fr.entry_prev >= 0 { entry := __dynamic_map_get_entry(h, fr.entry_prev); entry.next = index; @@ -979,14 +979,14 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) } if __dynamic_map_full(h) { - __dynamic_map_grow(h); + __dynamic_map_grow(h, loc); } } -__dynamic_map_grow :: proc(using h: __Map_Header) { +__dynamic_map_grow :: proc(using h: __Map_Header, loc := #caller_location) { new_count := max(2*m.entries.cap + 8, __INITIAL_MAP_CAP); - __dynamic_map_rehash(h, new_count); + __dynamic_map_rehash(h, new_count, loc); } __dynamic_map_full :: inline proc(using h: __Map_Header) -> bool { @@ -1017,9 +1017,9 @@ __dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_ return fr; } -__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int { +__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key, loc := #caller_location) -> int { prev := m.entries.len; - c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align); + c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc); if c != prev { end := __dynamic_map_get_entry(h, c-1); end.key = key; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5e24c575e..a19522746 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4156,6 +4156,22 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { param_count = param_tuple->variables.count; if (variadic) { + for (isize i = param_count-1; i >= 0; i--) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_TypeName) { + break; + } + + if (e->kind == Entity_Variable) { + if (e->Variable.default_value.kind != ExactValue_Invalid || + e->Variable.default_is_nil || + e->Variable.default_is_location) { + param_count--; + continue; + } + } + break; + } param_count--; } } @@ -4262,9 +4278,8 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { continue; } - if (variadic) { - o = operands[operand_index]; - } + + i64 s = 0; if (!check_is_assignable_to_with_score(c, &o, t, &s)) { if (show_error) { diff --git a/src/check_type.cpp b/src/check_type.cpp index befe56711..fe9c9c4ae 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1210,7 +1210,7 @@ Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand opera } -Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, isize *specialization_count_, Array *operands) { +Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array *operands) { if (_params == nullptr) { return nullptr; } @@ -1250,6 +1250,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari bool is_variadic = false; + isize variadic_index = -1; bool is_c_vararg = false; Array variables = {}; array_init(&variables, c->allocator, variable_count); @@ -1270,7 +1271,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari bool detemine_type_from_operand = false; Type *specialization = nullptr; - bool is_using = (p->flags&FieldFlag_using) != 0; + bool is_using = (p->flags&FieldFlag_using) != 0; bool is_constant_value = (p->flags&FieldFlag_const) != 0; @@ -1304,6 +1305,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari add_entity_use(c, e->identifier, e); } else { error(default_value, "Default parameter must be a constant"); + continue; } } } else { @@ -1315,12 +1317,21 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } else { if (type_expr->kind == AstNode_Ellipsis) { type_expr = type_expr->Ellipsis.expr; + #if 1 + is_variadic = true; + variadic_index = variables.count; + if (p->names.count != 1) { + error(param, "Invalid AST: Invalid variadic parameter with multiple names"); + success = false; + } + #else if (i+1 == params.count) { is_variadic = true; } else { error(param, "Invalid AST: Invalid variadic parameter"); success = false; } + #endif } if (type_expr->kind == AstNode_TypeType) { ast_node(tt, TypeType, type_expr); @@ -1360,8 +1371,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (default_value != nullptr) { if (type_expr->kind == AstNode_TypeType) { error(default_value, "A type parameter may not have a default value"); + continue; } else if (is_constant_value) { error(default_value, "A constant parameter may not have a default value"); + continue; } else { Operand o = {}; if (default_value->kind == AstNode_BasicDirective && @@ -1404,23 +1417,22 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari check_is_assignable_to(c, &o, type); } } - } if (type == nullptr) { - error(params[i], "Invalid parameter type"); + error(param, "Invalid parameter type"); type = t_invalid; } if (is_type_untyped(type)) { if (is_type_untyped_undef(type)) { - error(params[i], "Cannot determine parameter type from ---"); + error(param, "Cannot determine parameter type from ---"); } else { - error(params[i], "Cannot determine parameter type from a nil"); + error(param, "Cannot determine parameter type from a nil"); } type = t_invalid; } if (is_type_empty_union(type)) { gbString str = type_to_string(type); - error(params[i], "Invalid use of an empty union `%s`", str); + error(param, "Invalid use of an empty union `%s`", str); gb_string_free(str); type = t_invalid; } @@ -1429,7 +1441,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (p->flags&FieldFlag_c_vararg) { if (p->type == nullptr || p->type->kind != AstNode_Ellipsis) { - error(params[i], "`#c_vararg` can only be applied to variadic type fields"); + error(param, "`#c_vararg` can only be applied to variadic type fields"); p->flags &= ~FieldFlag_c_vararg; // Remove the flag } else { is_c_vararg = true; @@ -1438,10 +1450,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (is_constant_value) { if (is_type_param) { - error(p->type, "`$` is not needed for a `type` parameter"); + error(param, "`$` is not needed for a `type` parameter"); } if (p->flags&FieldFlag_no_alias) { - error(p->type, "`#no_alias` can only be applied to variable fields of pointer type"); + error(param, "`#no_alias` can only be applied to variable fields of pointer type"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } @@ -1505,7 +1517,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (p->flags&FieldFlag_no_alias) { if (!is_type_pointer(type)) { - error(params[i], "`#no_alias` can only be applied to fields of pointer type"); + error(name, "`#no_alias` can only be applied to fields of pointer type"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } } @@ -1549,11 +1561,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } + if (is_variadic) { + GB_ASSERT(variadic_index >= 0); + } + if (is_variadic) { GB_ASSERT(params.count > 0); // NOTE(bill): Change last variadic parameter to be a slice // Custom Calling convention for variadic parameters - Entity *end = variables[variable_count-1]; + Entity *end = variables[variadic_index]; end->type = make_type_slice(c->allocator, end->type); end->flags |= EntityFlag_Ellipsis; if (is_c_vararg) { @@ -1581,6 +1597,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (success_) *success_ = success; if (specialization_count_) *specialization_count_ = specialization_count; if (is_variadic_) *is_variadic_ = is_variadic; + if (variadic_index_) *variadic_index_ = variadic_index; return tuple; } @@ -1904,9 +1921,10 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array } bool variadic = false; + isize variadic_index = -1; bool success = true; isize specialization_count = 0; - Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, &specialization_count, operands); + Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands); Type *results = check_get_results(c, c->context.scope, pt->results); @@ -1941,6 +1959,7 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array type->Proc.results = results; type->Proc.result_count = cast(i32)result_count; type->Proc.variadic = variadic; + type->Proc.variadic_index = variadic_index; type->Proc.calling_convention = cc; type->Proc.is_polymorphic = pt->generic; type->Proc.specialization_count = specialization_count; diff --git a/src/ir.cpp b/src/ir.cpp index e5aaa06cd..5f7333816 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1821,6 +1821,11 @@ Type *ir_addr_type(irAddr addr) { return type_deref(t); } +irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, TokenPos pos); +irValue *ir_emit_source_code_location(irProcedure *proc, AstNode *node); +irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset); +irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type); + irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, irValue *map_key, irValue *map_value) { map_type = base_type(map_type); @@ -1832,17 +1837,15 @@ irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, T irValue *ptr = ir_add_local_generated(proc, ir_type(v)); ir_emit_store(proc, ptr, v); - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4); args[0] = h; args[1] = key; args[2] = ir_emit_conv(proc, ptr, t_rawptr); - - return ir_emit_global_call(proc, "__dynamic_map_set", args, 3); + args[3] = ir_emit_source_code_location(proc, nullptr); + return ir_emit_global_call(proc, "__dynamic_map_set", args, 4); } -irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset); -irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type); irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == nullptr) { @@ -3943,12 +3946,25 @@ irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, Token gbAllocator a = proc->module->allocator; irValue **args = gb_alloc_array(a, irValue *, 4); args[0] = ir_find_or_add_entity_string(proc->module, pos.file); - args[1] = ir_const_i64(a, pos.line); - args[2] = ir_const_i64(a, pos.column); + args[1] = ir_const_int(a, pos.line); + args[2] = ir_const_int(a, pos.column); args[3] = ir_find_or_add_entity_string(proc->module, procedure); return ir_emit_global_call(proc, "make_source_code_location", args, 4); } + +irValue *ir_emit_source_code_location(irProcedure *proc, AstNode *node) { + String proc_name = {}; + if (proc->entity) { + proc_name = proc->entity->token.string; + } + TokenPos pos = {}; + if (node) { + pos = ast_node_token(node).pos; + } + return ir_emit_source_code_location(proc, proc_name, pos); +} + void ir_emit_increment(irProcedure *proc, irValue *addr) { GB_ASSERT(is_type_pointer(ir_type(addr))); Type *type = type_deref(ir_type(addr)); @@ -4182,10 +4198,11 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv irValue *map = ir_add_local_generated(proc, type); irValue *header = ir_gen_map_header(proc, map, base_type(type)); - irValue **args = gb_alloc_array(a, irValue *, 2); + irValue **args = gb_alloc_array(a, irValue *, 3); args[0] = header; args[1] = cap; - ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + args[2] = ir_emit_source_code_location(proc, ce->args[0]); + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 3); return ir_emit_load(proc, map); } else if (is_type_dynamic_array(type)) { @@ -4202,13 +4219,14 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false); irValue *array = ir_add_local_generated(proc, type); - irValue **args = gb_alloc_array(a, irValue *, 5); + irValue **args = gb_alloc_array(a, irValue *, 6); args[0] = ir_emit_conv(proc, array, t_rawptr); args[1] = ir_const_int(a, type_size_of(a, elem_type)); args[2] = ir_const_int(a, type_align_of(a, elem_type)); args[3] = len; args[4] = cap; - ir_emit_global_call(proc, "__dynamic_array_make", args, 5); + args[5] = ir_emit_source_code_location(proc, ce->args[0]); + ir_emit_global_call(proc, "__dynamic_array_make", args, 6); if (ir_type_has_default_values(elem_type)) { ir_init_data_with_defaults(proc, ir_dynamic_array_elem(proc, ir_emit_load(proc, array)), len); @@ -5006,10 +5024,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { GB_ASSERT(value != nullptr); Type *proc_type_ = base_type(ir_type(value)); GB_ASSERT(proc_type_->kind == Type_Proc); - TypeProc *type = &proc_type_->Proc; + TypeProc *pt = &proc_type_->Proc; if (is_call_expr_field_value(ce)) { - isize param_count = type->param_count; + isize param_count = pt->param_count; irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count); for_array(arg_index, ce->args) { @@ -5017,7 +5035,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { ast_node(fv, FieldValue, arg); GB_ASSERT(fv->field->kind == AstNode_Ident); String name = fv->field->Ident.token.string; - isize index = lookup_procedure_parameter(type, name); + isize index = lookup_procedure_parameter(pt, name); GB_ASSERT(index >= 0); TypeAndValue tav = type_and_value_of_expr(proc->module->info, fv->value); if (tav.mode == Addressing_Type) { @@ -5026,9 +5044,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { args[index] = ir_build_expr(proc, fv->value); } } - TypeTuple *pt = &type->params->Tuple; + TypeTuple *params = &pt->params->Tuple; for (isize i = 0; i < param_count; i++) { - Entity *e = pt->variables[i]; + Entity *e = params->variables[i]; if (e->kind == Entity_TypeName) { args[i] = ir_value_nil(proc->module->allocator, e->type); } else if (e->kind == Entity_Constant) { @@ -5063,10 +5081,29 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count)); - bool variadic = type->variadic; + i64 param_count = 0; + if (pt->params) { + GB_ASSERT(pt->params->kind == Type_Tuple); + param_count = pt->params->Tuple.variables.count; + } + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(param_count, arg_count)); + isize variadic_index = pt->variadic_index; + bool variadic = pt->variadic && variadic_index >= 0; bool vari_expand = ce->ellipsis.pos.line != 0; - bool is_c_vararg = type->c_vararg; + bool is_c_vararg = pt->c_vararg; + + String proc_name = {}; + if (proc->entity != nullptr) { + proc_name = proc->entity->token.string; + } + TokenPos pos = ast_node_token(ce->proc).pos; + + TypeTuple *param_tuple = nullptr; + if (pt->params) { + GB_ASSERT(pt->params->kind == Type_Tuple); + param_tuple = &pt->params->Tuple; + } for_array(i, ce->args) { AstNode *arg = ce->args[i]; @@ -5088,32 +5125,23 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } - i64 param_count = type->param_count; - if (type->param_count > 0) { - GB_ASSERT_MSG(type->params != nullptr, "%s %td", expr_to_string(expr), type->param_count); - TypeTuple *pt = &type->params->Tuple; - param_count = type->param_count; + if (param_count > 0) { + GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count); GB_ASSERT(param_count < 1000000); if (arg_count < param_count) { - String procedure = {}; - if (proc->entity != nullptr) { - procedure = proc->entity->token.string; - } - TokenPos pos = ast_node_token(ce->proc).pos; - isize end = param_count; if (variadic) { - end--; + end = variadic_index; } while (arg_index < end) { - Entity *e = pt->variables[arg_index]; + Entity *e = param_tuple->variables[arg_index]; GB_ASSERT(e->kind == Entity_Variable); if (e->Variable.default_value.kind != ExactValue_Invalid) { args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); } else if (e->Variable.default_is_location) { - args[arg_index++] = ir_emit_source_code_location(proc, procedure, pos); + args[arg_index++] = ir_emit_source_code_location(proc, proc_name, pos); } else { args[arg_index++] = ir_value_nil(proc->module->allocator, e->type); } @@ -5124,13 +5152,13 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { GB_ASSERT(variadic); GB_ASSERT(!vari_expand); isize i = 0; - for (; i < param_count-1; i++) { - Entity *e = pt->variables[i]; + for (; i < variadic_index; i++) { + Entity *e = param_tuple->variables[i]; if (e->kind == Entity_Variable) { args[i] = ir_emit_conv(proc, args[i], e->type); } } - Type *variadic_type = pt->variables[i]->type; + Type *variadic_type = param_tuple->variables[i]->type; GB_ASSERT(is_type_slice(variadic_type)); variadic_type = base_type(variadic_type)->Slice.elem; if (!is_type_any(variadic_type)) { @@ -5144,14 +5172,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } else if (variadic) { isize i = 0; - for (; i < param_count-1; i++) { - Entity *e = pt->variables[i]; + for (; i < variadic_index; i++) { + Entity *e = param_tuple->variables[i]; if (e->kind == Entity_Variable) { args[i] = ir_emit_conv(proc, args[i], e->type); } } if (!vari_expand) { - Type *variadic_type = pt->variables[i]->type; + Type *variadic_type = param_tuple->variables[i]->type; GB_ASSERT(is_type_slice(variadic_type)); variadic_type = base_type(variadic_type)->Slice.elem; for (; i < arg_count; i++) { @@ -5160,7 +5188,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } else { for (i64 i = 0; i < param_count; i++) { - Entity *e = pt->variables[i]; + Entity *e = param_tuple->variables[i]; if (e->kind == Entity_Variable) { GB_ASSERT(args[i] != nullptr); args[i] = ir_emit_conv(proc, args[i], e->type); @@ -5171,15 +5199,15 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { if (variadic && !vari_expand && !is_c_vararg) { ir_emit_comment(proc, str_lit("variadic call argument generation")); gbAllocator allocator = proc->module->allocator; - Type *slice_type = pt->variables[param_count-1]->type; + Type *slice_type = param_tuple->variables[variadic_index]->type; Type *elem_type = base_type(slice_type)->Slice.elem; irValue *slice = ir_add_local_generated(proc, slice_type); - isize slice_len = arg_count+1 - param_count; + isize slice_len = arg_count+1 - (variadic_index+1); if (slice_len > 0) { irValue *base_array = ir_add_local_generated(proc, make_type_array(allocator, elem_type, slice_len)); - for (isize i = param_count-1, j = 0; i < arg_count; i++, j++) { + for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) { irValue *addr = ir_emit_array_epi(proc, base_array, cast(i32)j); ir_emit_store(proc, addr, args[i]); } @@ -5190,7 +5218,20 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } arg_count = param_count; - args[arg_count-1] = ir_emit_load(proc, slice); + args[variadic_index] = ir_emit_load(proc, slice); + } + } + + if (variadic && variadic_index+1 < param_count) { + for (isize i = variadic_index+1; i < param_count; i++) { + Entity *e = param_tuple->variables[i]; + if (e->Variable.default_value.kind != ExactValue_Invalid) { + args[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + } else if (e->Variable.default_is_location) { + args[i] = ir_emit_source_code_location(proc, proc_name, pos); + } else { + args[i] = ir_value_nil(proc->module->allocator, e->type); + } } } @@ -5695,6 +5736,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { case Type_Slice: et = bt->Slice.elem; break; } + String proc_name = {}; + if (proc->entity) { + proc_name = proc->entity->token.string; + } + TokenPos pos = ast_node_token(expr).pos; + switch (bt->kind) { default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; @@ -5776,10 +5823,11 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } gbAllocator a = proc->module->allocator; { - irValue **args = gb_alloc_array(a, irValue *, 2); + irValue **args = gb_alloc_array(a, irValue *, 3); args[0] = ir_gen_map_header(proc, v, type); args[1] = ir_const_int(a, 2*cl->elems.count); - ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + args[2] = ir_emit_source_code_location(proc, proc_name, pos); + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 3); } for_array(field_index, cl->elems) { AstNode *elem = cl->elems[field_index]; @@ -5801,12 +5849,13 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { irValue *size = ir_const_int(a, type_size_of(a, elem)); irValue *align = ir_const_int(a, type_align_of(a, elem)); { - irValue **args = gb_alloc_array(a, irValue *, 4); + irValue **args = gb_alloc_array(a, irValue *, 5); args[0] = ir_emit_conv(proc, v, t_rawptr); args[1] = size; args[2] = align; args[3] = ir_const_int(a, 2*cl->elems.count); - ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4); + args[4] = ir_emit_source_code_location(proc, proc_name, pos); + ir_emit_global_call(proc, "__dynamic_array_reserve", args, 5); } i64 item_count = cl->elems.count; @@ -5820,13 +5869,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } { - irValue **args = gb_alloc_array(a, irValue *, 5); + irValue **args = gb_alloc_array(a, irValue *, 6); args[0] = ir_emit_conv(proc, v, t_rawptr); args[1] = size; args[2] = align; args[3] = ir_emit_conv(proc, items, t_rawptr); args[4] = ir_const_int(a, item_count); - ir_emit_global_call(proc, "__dynamic_array_append", args, 5); + args[5] = ir_emit_source_code_location(proc, proc_name, pos); + ir_emit_global_call(proc, "__dynamic_array_append", args, 6); } break; } diff --git a/src/parser.cpp b/src/parser.cpp index 8c26d8cba..b6a86a7c0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2616,8 +2616,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { bool prefix_ellipsis = false; if (f->curr_token.kind == Token_Ellipsis) { prefix_ellipsis = true; - ellipsis = f->curr_token; - advance_token(f); + ellipsis = expect_token(f, Token_Ellipsis); } AstNode *arg = parse_expr(f, false); @@ -2627,10 +2626,6 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { if (prefix_ellipsis) { syntax_error(ellipsis, "`...` must be applied to value rather than the field name"); } - if (f->curr_token.kind == Token_Ellipsis) { - ellipsis = f->curr_token; - advance_token(f); - } AstNode *value = parse_value(f); arg = ast_field_value(f, arg, value, eq); @@ -3339,12 +3334,13 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) enum FieldPrefixKind { - FieldPrefix_Invalid, + FieldPrefix_Unknown = -1, + FieldPrefix_Invalid = 0, - FieldPrefix_Using, - FieldPrefix_NoAlias, - FieldPrefix_CVarArg, - FieldPrefix_Const, + FieldPrefix_using, + FieldPrefix_no_alias, + FieldPrefix_c_var_arg, + FieldPrefix_const, }; FieldPrefixKind is_token_field_prefix(AstFile *f) { @@ -3353,23 +3349,22 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) { return FieldPrefix_Invalid; case Token_using: - return FieldPrefix_Using; + return FieldPrefix_using; - - case Token_Hash: { + case Token_Hash: advance_token(f); switch (f->curr_token.kind) { case Token_Ident: if (f->curr_token.string == "no_alias") { - return FieldPrefix_NoAlias; + return FieldPrefix_no_alias; } else if (f->curr_token.string == "c_vararg") { - return FieldPrefix_CVarArg; + return FieldPrefix_c_var_arg; } else if (f->curr_token.string == "const") { - return FieldPrefix_Const; + return FieldPrefix_const; } break; } - } break; + return FieldPrefix_Unknown; } return FieldPrefix_Invalid; } @@ -3386,24 +3381,30 @@ u32 parse_field_prefixes(AstFile *f) { if (kind == FieldPrefix_Invalid) { break; } + if (kind == FieldPrefix_Unknown) { + syntax_error(f->curr_token, "Unknown prefix kind `#%.*s`", LIT(f->curr_token.string)); + advance_token(f); + continue; + } + switch (kind) { - case FieldPrefix_Using: using_count += 1; advance_token(f); break; - case FieldPrefix_NoAlias: no_alias_count += 1; advance_token(f); break; - case FieldPrefix_CVarArg: c_vararg_count += 1; advance_token(f); break; - case FieldPrefix_Const: const_count += 1; advance_token(f); break; + case FieldPrefix_using: using_count += 1; advance_token(f); break; + case FieldPrefix_no_alias: no_alias_count += 1; advance_token(f); break; + case FieldPrefix_c_var_arg: c_vararg_count += 1; advance_token(f); break; + case FieldPrefix_const: const_count += 1; advance_token(f); break; } } if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list"); if (no_alias_count > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list"); if (c_vararg_count > 1) syntax_error(f->curr_token, "Multiple `#c_vararg` in this field list"); - if (const_count > 1) syntax_error(f->curr_token, "Multiple `$` in this field list"); + if (const_count > 1) syntax_error(f->curr_token, "Multiple `#const` in this field list"); u32 field_flags = 0; if (using_count > 0) field_flags |= FieldFlag_using; if (no_alias_count > 0) field_flags |= FieldFlag_no_alias; if (c_vararg_count > 0) field_flags |= FieldFlag_c_vararg; - if (const_count > 0) field_flags |= FieldFlag_const; + if (const_count > 0) field_flags |= FieldFlag_const; return field_flags; } @@ -3534,10 +3535,10 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok u32 flags = parse_field_prefixes(f); AstNode *param = parse_var_type(f, allow_ellipsis, allow_type_token); if (param->kind == AstNode_Ellipsis) { - if (seen_ellipsis) syntax_error(param, "Extra variadic parameter"); + if (seen_ellipsis) syntax_error(param, "Extra variadic parameter after ellipsis"); seen_ellipsis = true; } else if (seen_ellipsis) { - syntax_error(param, "Extra parameter have variadic parameters"); + syntax_error(param, "Extra parameter after ellipsis"); } AstNodeAndFlags naf = {param, flags}; array_add(&list, naf); @@ -3566,12 +3567,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok if (f->curr_token.kind != Token_Eq) { type = parse_var_type(f, allow_ellipsis, allow_type_token); } - if (type != nullptr && type->kind == AstNode_Ellipsis) { - if (seen_ellipsis) syntax_error(type, "Extra variadic parameter"); - seen_ellipsis = true; - } else if (seen_ellipsis) { - syntax_error(f->curr_token, "Extra variadic parameter"); - } + if (allow_token(f, Token_Eq)) { // TODO(bill): Should this be true==lhs or false==rhs? default_value = parse_expr(f, false); @@ -3584,6 +3580,16 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok syntax_error(f->curr_token, "Default parameters can only be applied to single values"); } + if (type != nullptr && type->kind == AstNode_Ellipsis) { + if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis"); + seen_ellipsis = true; + if (names.count != 1) { + syntax_error(type, "Variadic parameters can only have one field name"); + } + } else if (seen_ellipsis && default_value == nullptr) { + syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); + } + parse_expect_field_separator(f, type); AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); array_add(¶ms, param); @@ -3608,12 +3614,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok if (f->curr_token.kind != Token_Eq) { type = parse_var_type(f, allow_ellipsis, allow_type_token); } - if (type != nullptr && type->kind == AstNode_Ellipsis) { - if (seen_ellipsis) syntax_error(type, "Extra variadic parameter"); - seen_ellipsis = true; - } else if (seen_ellipsis) { - syntax_error(f->curr_token, "Extra variadic parameter"); - } + if (allow_token(f, Token_Eq)) { // TODO(bill): Should this be true==lhs or false==rhs? default_value = parse_expr(f, false); @@ -3626,6 +3627,17 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok syntax_error(f->curr_token, "Default parameters can only be applied to single values"); } + if (type != nullptr && type->kind == AstNode_Ellipsis) { + if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis"); + seen_ellipsis = true; + if (names.count != 1) { + syntax_error(type, "Variadic parameters can only have one field name"); + } + } else if (seen_ellipsis && default_value == nullptr) { + syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); + } + + bool ok = parse_expect_field_separator(f, param); AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); array_add(¶ms, param); diff --git a/src/types.cpp b/src/types.cpp index 54ed86d52..087f9208e 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -31,7 +31,7 @@ enum BasicKind { Basic_uintptr, Basic_rawptr, Basic_string, // ^u8 + int - Basic_any, // ^Type_Info + rawptr + Basic_any, // rawptr + ^Type_Info Basic_UntypedBool, Basic_UntypedInteger, @@ -153,6 +153,7 @@ struct TypeStruct { Type * abi_compat_result_type; \ bool return_by_pointer; \ bool variadic; \ + i32 variadic_index; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \