diff --git a/core/bufio/read_writer.odin b/core/bufio/read_writer.odin index 9026abcfd..ccd59a398 100644 --- a/core/bufio/read_writer.odin +++ b/core/bufio/read_writer.odin @@ -25,10 +25,6 @@ _read_writer_vtable := &io.Stream_VTable{ b := (^Read_Writer)(s.stream_data).r return reader_read(b, p) }, - impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) { - b := (^Read_Writer)(s.stream_data).r - return reader_read_byte(b) - }, impl_unread_byte = proc(s: io.Stream) -> io.Error { b := (^Read_Writer)(s.stream_data).r return reader_unread_byte(b) diff --git a/core/io/conv.odin b/core/io/conv.odin index baaf5a864..39a72d69d 100644 --- a/core/io/conv.odin +++ b/core/io/conv.odin @@ -122,73 +122,3 @@ to_write_seeker :: proc(s: Stream) -> (w: Write_Seeker, ok: bool = true) #option } return } - - -to_byte_reader :: proc(s: Stream) -> (b: Byte_Reader, ok: bool = true) #optional_ok { - b.stream = s - if s.stream_vtable == nil || s.impl_read_byte == nil { - ok = false - if s.stream_vtable != nil && s.impl_read != nil { - ok = true - } - } - return -} -to_byte_scanner :: proc(s: Stream) -> (b: Byte_Scanner, ok: bool = true) #optional_ok { - b.stream = s - if s.stream_vtable != nil { - if s.impl_unread_byte == nil { - ok = false - return - } - if s.impl_read_byte != nil { - ok = true - } else if s.impl_read != nil { - ok = true - } else { - ok = false - } - } - return -} -to_byte_writer :: proc(s: Stream) -> (b: Byte_Writer, ok: bool = true) #optional_ok { - b.stream = s - if s.stream_vtable == nil || s.impl_write_byte == nil { - ok = false - if s.stream_vtable != nil && s.impl_write != nil { - ok = true - } - } - return -} - -to_rune_reader :: proc(s: Stream) -> (r: Rune_Reader, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read_rune == nil { - ok = false - if s.stream_vtable != nil && s.impl_read != nil { - ok = true - } - } - return - -} -to_rune_scanner :: proc(s: Stream) -> (r: Rune_Scanner, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable != nil { - if s.impl_unread_rune == nil { - ok = false - return - } - if s.impl_read_rune != nil { - ok = true - } else if s.impl_read != nil { - ok = true - } else { - ok = false - } - } else { - ok = false - } - return -} diff --git a/core/io/io.odin b/core/io/io.odin index 3ad34d607..7faa500b1 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -123,13 +123,6 @@ Writer_At :: struct {using stream: Stream} Reader_From :: struct {using stream: Stream} Writer_To :: struct {using stream: Stream} -Byte_Reader :: struct {using stream: Stream} -Byte_Scanner :: struct {using stream: Stream} -Byte_Writer :: struct {using stream: Stream} - -Rune_Reader :: struct {using stream: Stream} -Rune_Scanner :: struct {using stream: Stream} - destroy :: proc(s: Stream) -> Error { close_err := close({s}) @@ -147,24 +140,48 @@ destroy :: proc(s: Stream) -> Error { // When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of // bytes read along with the error. read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) { - if s.stream_vtable != nil && s.impl_read != nil { - n, err = s->impl_read(p) - if n_read != nil { - n_read^ += n + if s.stream_vtable != nil { + if s.impl_read != nil { + n, err = s->impl_read(p) + if n_read != nil { + n_read^ += n + } + return + } else if s.impl_read_byte != nil { + bytes_read := 0 + defer if n_read != nil { + n_read^ += bytes_read + } + for _, i in p { + p[i] = s->impl_read_byte() or_return + bytes_read += 1 + } + return } - return } return 0, .Empty } // write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred. write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) { - if s.stream_vtable != nil && s.impl_write != nil { - n, err = s->impl_write(p) - if n_written != nil { - n_written^ += n + if s.stream_vtable != nil { + if s.impl_write != nil { + n, err = s->impl_write(p) + if n_written != nil { + n_written^ += n + } + return + } else if s.impl_write_byte != nil { + bytes_written := 0 + defer if n_written != nil { + n_written^ += bytes_written + } + for c in p { + s->impl_write_byte(c) or_return + bytes_written += 1 + } + return } - return } return 0, .Empty } @@ -319,7 +336,7 @@ read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) { // read_byte reads and returns the next byte from r. -read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) { +read_byte :: proc(r: Reader, n_read: ^int = nil) -> (b: byte, err: Error) { defer if err == nil && n_read != nil { n_read^ += 1 } @@ -339,21 +356,12 @@ read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) { return buf[0], err } -write_byte :: proc{ - write_byte_to_byte_writer, - write_byte_to_writer, -} - -write_byte_to_byte_writer :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> Error { - return _write_byte(w, c, n_written) -} - -write_byte_to_writer :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error { +write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error { return _write_byte(auto_cast w, c, n_written) } @(private) -_write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Error) { +_write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> (err: Error) { defer if err == nil && n_written != nil { n_written^ += 1 } @@ -373,7 +381,7 @@ _write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Err } // read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes. -read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) { +read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) { defer if err == nil && n_read != nil { n_read^ += size } @@ -417,13 +425,21 @@ read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, return } -unread_byte :: proc(s: Byte_Scanner) -> Error { - if s.stream_vtable != nil && s.impl_unread_byte != nil { +unread_byte :: proc(s: Stream) -> Error { + if s.stream_vtable == nil { + return .Empty + } + if s.impl_unread_byte != nil { return s->impl_unread_byte() } + if s.impl_seek != nil { + _, err := s->impl_seek(-1, .Current) + return err + } + return .Empty } -unread_rune :: proc(s: Rune_Scanner) -> Error { +unread_rune :: proc(s: Writer) -> Error { if s.stream_vtable != nil && s.impl_unread_rune != nil { return s->impl_unread_rune() } @@ -442,7 +458,10 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err n_written^ += size } - if s.stream_vtable != nil && s.impl_write_rune != nil { + if s.stream_vtable == nil { + return 0, .Empty + } + if s.impl_write_rune != nil { return s->impl_write_rune(r) } diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index c8f73a31b..99b2cde98 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -6,7 +6,7 @@ Proc_Tag :: enum { Bounds_Check, No_Bounds_Check, Optional_Ok, - Optional_Second, + Optional_Allocator_Error, } Proc_Tags :: distinct bit_set[Proc_Tag; u32] diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index bd1422da3..b70c8528e 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2062,7 +2062,7 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { case "bounds_check": tags += {.Bounds_Check} case "no_bounds_check": tags += {.No_Bounds_Check} case "optional_ok": tags += {.Optional_Ok} - case "optional_second": tags += {.Optional_Second} + case "optional_allocator_error": tags += {.Optional_Allocator_Error} case: } } diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index e3960088d..4c736b6f6 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -189,7 +189,7 @@ delete :: proc{ // The new built-in procedure allocates memory. The first argument is a type, not a value, and the value // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator @builtin -new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second { +new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error { return new_aligned(T, align_of(T), allocator, loc) } new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { @@ -199,7 +199,7 @@ new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, } @builtin -new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_second { +new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error { t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return t = (^T)(raw_data(t_data)) if t != nil { @@ -210,7 +210,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat DEFAULT_RESERVE_CAPACITY :: 16 -make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { +make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { make_slice_error_loc(loc, len) data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc) if data == nil && size_of(E) != 0 { @@ -221,19 +221,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat } @(builtin) -make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { +make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { return make_aligned(T, len, align_of(E), allocator, loc) } @(builtin) -make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { +make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc) } @(builtin) -make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { +make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { return make_dynamic_array_len_cap(T, len, len, allocator, loc) } @(builtin) -make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { +make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { make_dynamic_array_error_loc(loc, len, cap) data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator} @@ -253,7 +253,7 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPAC return m } @(builtin) -make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_second { +make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error { make_slice_error_loc(loc, len) data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return if data == nil && size_of(E) != 0 { diff --git a/core/runtime/core_builtin_soa.odin b/core/runtime/core_builtin_soa.odin index 077027a9a..a6b356642 100644 --- a/core/runtime/core_builtin_soa.odin +++ b/core/runtime/core_builtin_soa.odin @@ -79,7 +79,7 @@ raw_soa_footer :: proc{ @builtin -make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { +make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { if length <= 0 { return } @@ -138,7 +138,7 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc } @builtin -make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { +make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { return make_soa_aligned(T, length, align_of(E), allocator, loc) } diff --git a/core/strings/reader.odin b/core/strings/reader.odin index 9b2e10b68..a38f1fbe4 100644 --- a/core/strings/reader.odin +++ b/core/strings/reader.odin @@ -42,20 +42,6 @@ to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At { return rr } -// init a reader to the string `s` and return an io.Byte_Reader -to_byte_reader :: proc(r: ^Reader, s: string) -> io.Byte_Reader { - reader_init(r, s) - rr, _ := io.to_byte_reader(reader_to_stream(r)) - return rr -} - -// init a reader to the string `s` and return an io.Rune_Reader -to_rune_reader :: proc(r: ^Reader, s: string) -> io.Rune_Reader { - reader_init(r, s) - rr, _ := io.to_rune_reader(reader_to_stream(r)) - return rr -} - // remaining length of the reader reader_length :: proc(r: ^Reader) -> int { if r.i >= i64(len(r.s)) { diff --git a/core/strings/strings.odin b/core/strings/strings.odin index fcfc133f3..a0f553a68 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -937,14 +937,14 @@ index_any :: proc(s, chars: string) -> int { } /* - returns the index of any first char of `chars` found in `s`, -1 if not found + returns the last matching index in `s` of any char in `chars` found in `s`, -1 if not found iterates the string in reverse - strings.index_any("test", "s") -> 2 - strings.index_any("test", "se") -> 2 - strings.index_any("test", "et") -> 1 - strings.index_any("test", "set") -> 3 - strings.index_any("test", "x") -> -1 + strings.last_index_any("test", "s") -> 2 + strings.last_index_any("test", "se") -> 2 + strings.last_index_any("test", "et") -> 3 + strings.last_index_any("test", "set") -> 3 + strings.last_index_any("test", "x") -> -1 */ last_index_any :: proc(s, chars: string) -> int { if chars == "" { diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b877b8cb7..fc5a9d19f 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1355,6 +1355,12 @@ bool init_build_paths(String init_filename) { // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); + { + String build_project_name = last_path_element(bc->build_paths[BuildPath_Main_Package].basename); + GB_ASSERT(build_project_name.len > 0); + bc->ODIN_BUILD_PROJECT_NAME = build_project_name; + } + bool produces_output_file = false; if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { produces_output_file = true; @@ -1538,12 +1544,6 @@ bool init_build_paths(String init_filename) { enable_target_feature({}, bc->target_features_string); } - { - String build_project_name = last_path_element(bc->build_paths[BuildPath_Main_Package].basename); - GB_ASSERT(build_project_name.len > 0); - bc->ODIN_BUILD_PROJECT_NAME = build_project_name; - } - return true; } diff --git a/src/check_type.cpp b/src/check_type.cpp index 66417f97e..c024e0842 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2006,22 +2006,21 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, } } } - if (pt->tags & ProcTag_optional_second) { + if (pt->tags & ProcTag_optional_allocator_error) { if (optional_ok) { - error(proc_type_node, "A procedure type cannot have both an #optional_ok tag and #optional_second"); + error(proc_type_node, "A procedure type cannot have both an #optional_ok tag and #optional_allocator_error"); } optional_ok = true; if (result_count != 2) { - error(proc_type_node, "A procedure type with the #optional_second tag requires 2 return values, got %td", result_count); + error(proc_type_node, "A procedure type with the #optional_allocator_error tag requires 2 return values, got %td", result_count); } else { - bool ok = false; - AstFile *file = proc_type_node->file(); - if (file && file->pkg) { - ok = file->pkg->scope == ctx->info->runtime_package->scope; - } + init_mem_allocator(c->checker); - if (!ok) { - error(proc_type_node, "A procedure type with the #optional_second may only be allowed within 'package runtime'"); + Type *type = results->Tuple.variables[1]->type; + if (!are_types_identical(type, t_allocator_error)) { + gbString t = type_to_string(type); + error(proc_type_node, "A procedure type with the #optional_allocator_error expects a `runtime.Allocator_Error`, got '%s'", t); + gb_string_free(t); } } } diff --git a/src/checker.cpp b/src/checker.cpp index 16e480786..cdc0630bf 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2809,17 +2809,9 @@ void init_mem_allocator(Checker *c) { if (t_allocator != nullptr) { return; } - AstPackage *pkg = get_core_package(&c->info, str_lit("runtime")); - - String name = str_lit("Allocator"); - Entity *e = scope_lookup_current(pkg->scope, name); - if (e == nullptr) { - compiler_error("Could not find type declaration for '%.*s'\n", LIT(name)); - // NOTE(bill): This will exit the program as it's cannot continue without it! - } - - t_allocator = e->type; + t_allocator = find_core_type(c, str_lit("Allocator")); t_allocator_ptr = alloc_type_pointer(t_allocator); + t_allocator_error = find_core_type(c, str_lit("Allocator_Error")); } void init_core_context(Checker *c) { @@ -2827,7 +2819,6 @@ void init_core_context(Checker *c) { return; } t_context = find_core_type(c, str_lit("Context")); - GB_ASSERT(t_context != nullptr); t_context_ptr = alloc_type_pointer(t_context); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 17501d657..82e577032 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -578,7 +578,7 @@ void lb_begin_procedure_body(lbProcedure *p) { GB_ASSERT(!is_blank_ident(e->token)); lbAddr res = {}; - if (return_ptr_value.value) { + if (return_ptr_value.value != nullptr) { lbValue ptr = return_ptr_value; if (results->variables.count != 1) { ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); @@ -586,6 +586,7 @@ void lb_begin_procedure_body(lbProcedure *p) { res = lb_addr(ptr); lb_add_entity(p->module, e, ptr); + lb_add_debug_local_variable(p, ptr.value, e->type, e->token); } else { res = lb_add_local(p, e->type, e); } @@ -594,8 +595,10 @@ void lb_begin_procedure_body(lbProcedure *p) { lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); lb_addr_store(p, res, c); } + } } + } } if (p->type->Proc.calling_convention == ProcCC_Odin) { diff --git a/src/parser.cpp b/src/parser.cpp index 70a87d2a5..2109945ec 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1857,7 +1857,7 @@ void parse_proc_tags(AstFile *f, u64 *tags) { if (false) {} ELSE_IF_ADD_TAG(optional_ok) - ELSE_IF_ADD_TAG(optional_second) + ELSE_IF_ADD_TAG(optional_allocator_error) ELSE_IF_ADD_TAG(require_results) ELSE_IF_ADD_TAG(bounds_check) ELSE_IF_ADD_TAG(no_bounds_check) diff --git a/src/parser.hpp b/src/parser.hpp index 7433744e6..e384f1e7e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -232,7 +232,7 @@ enum ProcTag { ProcTag_require_results = 1<<4, ProcTag_optional_ok = 1<<5, - ProcTag_optional_second = 1<<6, + ProcTag_optional_allocator_error = 1<<6, }; enum ProcCallingConvention : i32 { diff --git a/src/types.cpp b/src/types.cpp index b7cb4dd2c..e917d30fa 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -681,6 +681,7 @@ gb_global Type *t_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; gb_global Type *t_context = nullptr; gb_global Type *t_context_ptr = nullptr; +gb_global Type *t_allocator_error = nullptr; gb_global Type *t_source_code_location = nullptr; gb_global Type *t_source_code_location_ptr = nullptr;