From: Brendan Hansen Date: Mon, 12 Sep 2022 22:06:55 +0000 (-0500) Subject: added runtime package ids; strptime implementation X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=3120213246a7b03bc6f35ad2b2e52c187b46d9aa;p=onyx.git added runtime package ids; strptime implementation --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 0ad33558..01003252 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1516,6 +1516,8 @@ struct Package { Scope *scope; Scope *private_scope; + u32 id; + // NOTE: This tracks all of the 'use package' statements of this package throughout // the code base. This is used when a static if clears and new symbols are introduced. // 'use package' statements have to be reevaluated to pull in the new symbols. @@ -1645,6 +1647,7 @@ extern AstType *builtin_callsite_type; extern AstType *builtin_any_type; extern AstType *builtin_code_type; extern AstType *builtin_link_options_type; +extern AstType *builtin_package_id_type; extern AstTyped *type_table_node; extern AstTyped *foreign_blocks_node; extern AstType *foreign_block_type; diff --git a/compiler/src/astnodes.c b/compiler/src/astnodes.c index fc6e7085..c7744d77 100644 --- a/compiler/src/astnodes.c +++ b/compiler/src/astnodes.c @@ -887,6 +887,11 @@ Type* resolve_expression_type(AstTyped* node) { return resolve_expression_type((AstTyped *) ((AstMacro *) node)->body); } + if (node->kind == Ast_Kind_Package) { + node->type_node = builtin_package_id_type; + node->type = type_build_from_ast(context.ast_alloc, node->type_node); + } + if (node->type == NULL) node->type = type_build_from_ast(context.ast_alloc, node->type_node); diff --git a/compiler/src/builtins.c b/compiler/src/builtins.c index b6eacef0..8b60c4f1 100644 --- a/compiler/src/builtins.c +++ b/compiler/src/builtins.c @@ -60,6 +60,7 @@ AstType *builtin_callsite_type; AstType *builtin_any_type; AstType *builtin_code_type; AstType *builtin_link_options_type; +AstType *builtin_package_id_type; AstTyped *type_table_node = NULL; AstTyped *foreign_blocks_node = NULL; @@ -462,6 +463,12 @@ void initialize_builtins(bh_allocator a) { return; } + builtin_package_id_type = (AstType *) symbol_raw_resolve(p->scope, "package_id"); + if (builtin_package_id_type == NULL) { + onyx_report_error((OnyxFilePos) { 0 }, Error_Critical, "'package_id' type not found."); + return; + } + bh_arr_new(global_heap_allocator, init_procedures, 4); fori (i, 0, Binary_Op_Count) { diff --git a/compiler/src/checker.c b/compiler/src/checker.c index 01b7eb29..df26f20e 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -1667,6 +1667,10 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { YIELD(field->token->pos, "Trying to resolve type of source expression."); } + if (field->expr->kind == Ast_Kind_Package) { + return Check_Return_To_Symres; + } + if (!type_is_structlike(field->expr->type)) { ERROR_(field->token->pos, "Cannot access field '%b' on '%s'. Type is not a struct.", diff --git a/compiler/src/parser.c b/compiler/src/parser.c index e8d74118..78a74d6b 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -3359,6 +3359,8 @@ submit_binding_to_entities: static AstPackage* parse_package_expression(OnyxParser* parser) { AstPackage* package_node = make_node(AstPackage, Ast_Kind_Package); + package_node->flags |= Ast_Flag_Comptime; + package_node->type_node = builtin_package_id_type; package_node->token = expect_token(parser, Token_Type_Keyword_Package); bh_arr_new(global_heap_allocator, package_node->path, 2); @@ -3420,6 +3422,7 @@ static Package* parse_file_package(OnyxParser* parser) { pnode->token = *symbol; pnode->package = newpackage; pnode->package_name = newpackage->name; + pnode->flags |= Ast_Flag_Comptime; if (prevpackage != NULL) { symbol_subpackage_introduce(prevpackage->scope, (*symbol)->text, pnode); diff --git a/compiler/src/utils.c b/compiler/src/utils.c index 5cbef639..33fbdea3 100644 --- a/compiler/src/utils.c +++ b/compiler/src/utils.c @@ -17,6 +17,8 @@ bh_allocator global_heap_allocator; // // Program info and packages // +static u64 next_package_id = 1; + Package* package_lookup(char* package_name) { i32 index = shgeti(context.packages, package_name); if (index != -1) { @@ -40,6 +42,7 @@ Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_al package->name = pac_name; package->use_package_entities = NULL; + package->id = next_package_id++; if (!strcmp(pac_name, "builtin")) { package->private_scope = scope_create(alloc, context.global_scope, pos); @@ -55,6 +58,8 @@ Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_al AstPackage* package_node = onyx_ast_node_new(alloc, sizeof(AstPackage), Ast_Kind_Package); package_node->package_name = package->name; package_node->package = package; + package_node->type_node = builtin_package_id_type; + package_node->flags |= Ast_Flag_Comptime; symbol_raw_introduce(context.global_scope, pac_name, pos, (AstNode *) package_node); } diff --git a/compiler/src/wasm_emit.c b/compiler/src/wasm_emit.c index f380970f..37ea48bd 100644 --- a/compiler/src/wasm_emit.c +++ b/compiler/src/wasm_emit.c @@ -3375,6 +3375,12 @@ EMIT_FUNC(expression, AstTyped* expr) { break; } + case Ast_Kind_Package: { + AstPackage *package = (AstPackage *) expr; + WID(NULL, WI_I32_CONST, package->package->id); + break; + } + default: bh_printf("Unhandled case: %d\n", expr->kind); DEBUG_HERE; @@ -4080,6 +4086,12 @@ static b32 emit_constexpr_(ConstExprContext *ctx, AstTyped *node, u32 offset) { break; } + case Ast_Kind_Package: { + AstPackage *package = (AstPackage *) node; + CE(u32, 0) = package->package->id; + break; + } + case Ast_Kind_NumLit: { // NOTE: This makes a big assumption that we are running on a // little endian machine, since WebAssembly is little endian diff --git a/compiler/src/wasm_type_table.h b/compiler/src/wasm_type_table.h index 2cb1c671..d80f2f0e 100644 --- a/compiler/src/wasm_type_table.h +++ b/compiler/src/wasm_type_table.h @@ -829,9 +829,12 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) { bh_buffer_align(&tag_proc_buffer, 4); tag_proc_info[index++] = tag_proc_buffer.length; + assert(func->entity && func->entity->package); + bh_buffer_write_u32(&tag_proc_buffer, get_element_idx(module, func)); bh_buffer_write_u32(&tag_proc_buffer, func->type->id); WRITE_SLICE(tag_array_base, tag_count); + bh_buffer_write_u32(&tag_proc_buffer, func->entity->package->id); } if (context.options->verbose_output == 1) { diff --git a/core/builtin.onyx b/core/builtin.onyx index 5d9a16bc..6f8b6a07 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -314,4 +314,10 @@ Link_Options :: struct { memory_min_size := 1024; memory_max_size := 65536; -} \ No newline at end of file +} + + +package_id :: #distinct u32 +any_package :: cast(package_id) 0 +#operator == macro (p1, p2: package_id) => cast(u32) p1 == cast(u32) p2; +#operator != macro (p1, p2: package_id) => cast(u32) p1 != cast(u32) p2; diff --git a/core/runtime/info/proc_tags.onyx b/core/runtime/info/proc_tags.onyx index 9f8826bf..8236f99b 100644 --- a/core/runtime/info/proc_tags.onyx +++ b/core/runtime/info/proc_tags.onyx @@ -9,6 +9,7 @@ Tagged_Procedure :: struct { func: () -> void; type: type_expr; tags: [] any; + pack: package_id; } get_tags_for_procedure :: (func: $T) -> [] any { @@ -25,6 +26,7 @@ get_tags_for_procedure :: (func: $T) -> [] any { func: () -> void; type: type_expr; tag : ^T; + pack: package_id; } get_procedures_with_tag :: ($tag_type: type_expr) -> [] GPWT_Result(tag_type) { @@ -36,7 +38,8 @@ get_procedures_with_tag :: ($tag_type: type_expr) -> [] GPWT_Result(tag_type) { array.push(^results, .{ func = proc.func, type = proc.type, - tag = cast(^tag_type) tag.data + tag = cast(^tag_type) tag.data, + pack = proc.pack, }); } } diff --git a/core/string.onyx b/core/string.onyx index 268c6b74..0db20e7d 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -161,6 +161,21 @@ equal :: (str1: str, str2: str) -> bool { return true; } +equal_insensitive :: (s1, s2: str) -> bool { + if s1.count != s2.count do return false; + while i := 0; i < s1.count { + defer i += 1; + if s1[i] == s2[i] do continue; + + c1 := s1[i]; + c2 := s2[i]; + if c1 >= #char "A" && c1 <= #char "Z" do c1 += 32; + if c2 >= #char "A" && c2 <= #char "Z" do c2 += 32; + if c1 != c2 do return false; + } + return true; +} + #operator == equal #operator != macro (s1: str, s2: str) => !(s1 == s2); diff --git a/core/time/time.onyx b/core/time/time.onyx index 6021e272..0f2d61f6 100644 --- a/core/time/time.onyx +++ b/core/time/time.onyx @@ -15,15 +15,15 @@ package core.time // This structure has to match the 'struct tm' // defined in time.h of POSIX. Timestamp :: struct #size (sizeof u32 * 12) { - sec: u32; - min: u32; - hour: u32; - mday: u32; - mon: u32; - year: u32; - wday: u32; - yday: u32; - isdst: u32; + sec: i32; + min: i32; + hour: i32; + mday: i32; + mon: i32; + year: i32; + wday: i32; + yday: i32; + isdst: i32; } localtime :: __time_localtime @@ -38,20 +38,241 @@ strftime :: (buf: [] u8, format: [] u8, tm: ^Timestamp) -> str { return buf[0..len]; } -strptime :: (buf: [] u8, format: [] u8, tm: ^Timestamp) -> bool { - f := cast(cstr) core.alloc.from_stack(format.length + 1); - core.memory.copy(f, format.data, format.length); - f[format.length] = 0; +strptime :: (buf_: [] u8, format_: [] u8, tm: ^Timestamp) -> bool { + use core + + #persist weekdays := str.[ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ]; + #persist monthnames := str.[ "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" ]; + + buf := buf_; + format := format_; + + working := true; + while working && buf.length > 0 && format.length > 0 { + c := format[0]; + switch c { + case #char "%" { + string.advance(^format); + switch format[0] { + case #char "a", #char "A" { + for i: weekdays.count { + w := weekdays[i]; + if string.equal_insensitive(w, buf[0 .. w.length]) { + string.advance(^buf, w.length); + tm.wday = i; + break break; + + } elseif string.equal_insensitive(w[0 .. 3], buf[0 .. 3]) { + string.advance(^buf, 3); + tm.wday = i; + break break; + } + } + + tm.wday = -1; + working = false; + } + + case #char "b", #char "B", #char "h" { + for i: monthnames.count { + m := monthnames[i]; + if string.equal_insensitive(m, buf[0 .. m.length]) { + string.advance(^buf, m.length); + tm.mon = i; + break break; + + } elseif string.equal_insensitive(m[0 .. 3], buf[0 .. 3]) { + string.advance(^buf, 3); + tm.mon = i; + break break; + } + } + + tm.mon = -1; + working = false; + } + + case #char "d", #char "e" { + working = parse_number_and_advance(^buf, ^tm.mday, 1, 31, 0); + } + + case #char "D" { + working = parse_number_and_advance(^buf, ^tm.mon, 1, 12, -1); + if !working do break; + + if buf[0] == #char "/" { + string.advance(^buf); + working = parse_number_and_advance(^buf, ^tm.mday, 1, 31, 0); + if !working do break; + + if buf[0] == #char "/" { + string.advance(^buf); + working = parse_number_and_advance(^buf, ^tm.year, 0, 99, 0); + if working && tm.year < 69 { + tm.year += 100; + } + } + } + } + + case #char "H" do working = parse_number_and_advance(^buf, ^tm.hour, 0, 23, 0); + case #char "I" do working = parse_number_and_advance(^buf, ^tm.hour, 1, 12, 0); + case #char "j" do working = parse_number_and_advance(^buf, ^tm.yday, 1, 366, -1); + case #char "m" do working = parse_number_and_advance(^buf, ^tm.mon, 1, 12, -1); + case #char "M" do working = parse_number_and_advance(^buf, ^tm.min, 0, 59, 0); + case #char "n", #char "t" do string.strip_leading_whitespace(^buf); + + case #char "p" { + if string.equal_insensitive(buf[0 .. 2], "am") { + if tm.hour == 12 do tm.hour = 0; + string.advance(^buf, 2); + + } elseif string.equal_insensitive(buf[0 .. 2], "pm") { + if tm.hour < 12 do tm.hour += 12; + string.advance(^buf, 2); + + } else { + working = false; + } + } + + case #char "r" { + working = parse_number_and_advance(^buf, ^tm.hour, 1, 12, 0); + if !working do break; + + if buf[0] == #char ":" { + string.advance(^buf); + + working = parse_number_and_advance(^buf, ^tm.min, 0, 59, 0); + if !working do break; + + if buf[0] == #char ":" { + string.advance(^buf); + + working = parse_number_and_advance(^buf, ^tm.sec, 0, 59, 0); + if !working do break; + + string.strip_leading_whitespace(^buf); + + if string.equal_insensitive(buf[0 .. 2], "am") { + if tm.hour == 12 do tm.hour = 0; + string.advance(^buf, 2); + + } elseif string.equal_insensitive(buf[0 .. 2], "pm") { + if tm.hour < 12 do tm.hour += 12; + string.advance(^buf, 2); + + } else { + working = false; + } + } + } + } - return __time_strptime(buf, f, tm); + case #char "R" { + working = parse_number_and_advance(^buf, ^tm.hour, 1, 12, 0); + if !working do break; + + if buf[0] == #char ":" { + string.advance(^buf); + + working = parse_number_and_advance(^buf, ^tm.min, 0, 59, 0); + } + } + + case #char "S" do working = parse_number_and_advance(^buf, ^tm.sec, 0, 59, 0); + + case #char "T" { + working = parse_number_and_advance(^buf, ^tm.hour, 1, 12, 0); + if !working do break; + + if buf[0] == #char ":" { + string.advance(^buf); + + working = parse_number_and_advance(^buf, ^tm.min, 0, 59, 0); + if !working do break; + + if buf[0] == #char ":" { + string.advance(^buf); + + working = parse_number_and_advance(^buf, ^tm.sec, 0, 59, 0); + } + } + } + + case #char "w" do working = parse_number_and_advance(^buf, ^tm.wday, 0, 6, 0); + case #char "Y" do working = parse_number_and_advance(^buf, ^tm.year, 1900, 65535, -1900); + + case #char "y" { + working = parse_number_and_advance(^buf, ^tm.year, 0, 99, 0); + if working && tm.year < 69 { + tm.year += 100; + } + } + + case #char "%" { + if buf[0] != #char "%" { + working = false; + } + string.advance(^buf); + } + + case #default { + working = false; + } + } + } + + case #char " ", #char "\t", #char "\r", #char "\n", #char "\f", #char "\v" { + string.strip_leading_whitespace(^buf); + } + + case #default { + if c != buf[0] { + working = false; + + } else { + string.advance(^buf); + } + } + } + + string.advance(^format); + } + + return working; } +#local +parse_number_and_advance :: (buf: ^[] u8, result: ^i32, low, high, offset: i32) -> bool { + use core {string} + + n := 0; + while buf.count > 0 { + c := buf.data[0]; + if c < #char "0" || c > #char "9" { + break; + } + + n *= 10; + n += ~~(c - #char "0"); + string.advance(buf); + } + + if n >= low && n <= high { + *result = n + offset; + return true; + } + + return false; +} + + #local { #foreign "onyx_runtime" { __time_localtime :: (time: u64, tm: ^Timestamp) -> void --- __time_gmtime :: (time: u64, tm: ^Timestamp) -> void --- __time_strftime :: (buf: [] u8, format: cstr, tm: ^Timestamp) -> u32 --- - __time_strptime :: (buf: [] u8, format: cstr, tm: ^Timestamp) -> bool --- } } diff --git a/runtime/onyx_runtime.c b/runtime/onyx_runtime.c index cdcf83e1..c8bbacaf 100644 --- a/runtime/onyx_runtime.c +++ b/runtime/onyx_runtime.c @@ -74,7 +74,6 @@ ONYX_LIBRARY { ONYX_FUNC(__time_localtime) ONYX_FUNC(__time_gmtime) ONYX_FUNC(__time_strftime) - ONYX_FUNC(__time_strptime) ONYX_FUNC(__net_create_socket) ONYX_FUNC(__net_close_socket) diff --git a/runtime/src/ort_time.h b/runtime/src/ort_time.h index 998e9f91..7dd76751 100644 --- a/runtime/src/ort_time.h +++ b/runtime/src/ort_time.h @@ -19,14 +19,3 @@ ONYX_DEF(__time_strftime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) results->data[0] = WASM_I32_VAL(len); return NULL; } - -ONYX_DEF(__time_strptime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { - #if defined(_BH_LINUX) - char *rem = strptime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32)); - results->data[0] = WASM_I32_VAL(rem != NULL); - #else - results->data[0] = WASM_I32_VAL(0); - #endif - return NULL; -} -