added runtime package ids; strptime implementation
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Sep 2022 22:06:55 +0000 (17:06 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Sep 2022 22:06:55 +0000 (17:06 -0500)
14 files changed:
compiler/include/astnodes.h
compiler/src/astnodes.c
compiler/src/builtins.c
compiler/src/checker.c
compiler/src/parser.c
compiler/src/utils.c
compiler/src/wasm_emit.c
compiler/src/wasm_type_table.h
core/builtin.onyx
core/runtime/info/proc_tags.onyx
core/string.onyx
core/time/time.onyx
runtime/onyx_runtime.c
runtime/src/ort_time.h

index 0ad33558f3ac64dc14aabfb0efbc62708bf8fd4b..01003252c0aa666742689f0d8862d17958ce27d9 100644 (file)
@@ -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;
index fc6e708572e34a28aeffab7c1423f85ae5813b4b..c7744d779e4b9d77aa138c132d935f019a501215 100644 (file)
@@ -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);
 
index b6eacef0705032cb7ed986abd0dd04f5d67e19ea..8b60c4f1007453a7127c16d2197084880fa89ca3 100644 (file)
@@ -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) {
index 01b7eb2955bf48d9217e2834852c68a7b7de84ac..df26f20eeda8e4094c755d24780163ef2df8dc37 100644 (file)
@@ -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.",
index e8d74118f326ed67bd969eff14179ff506565253..78a74d6b9bc00f2ebe5a1565aae7a12e8de35de2 100644 (file)
@@ -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);
index 5cbef6399623da0d8f724ddf889e654e5e0edbc3..33fbdea362083d6ef98965fbfdabf714a3a40694 100644 (file)
@@ -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);
         }
index f380970fb31c51a8128b9b5060295b26cd4ecca9..37ea48bd39ba4a4382a3d374ab967b93b1d38350 100644 (file)
@@ -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
index 2cb1c67199c08b947f176c2d5403eeb3a5a658fd..d80f2f0ed3c310800da12a2ce39d292edfa9ff05 100644 (file)
@@ -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) {
index 5d9a16bc662e3666bd3f08d8a52be1d23334cae1..6f8b6a07c5f59c2e6fba01a0fe5bb6cd64b62164 100644 (file)
@@ -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;
index 9f8826bf30a435802d6de8c46d33e6982eb6d442..8236f99be246236fd98b762200d960c84a6ee824 100644 (file)
@@ -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,
             });
         }
     }
index 268c6b7467406ab72bccdb6dd2c496e62cec0dff..0db20e7d7bf26b2a54bda37f0896f8f530de7706 100644 (file)
@@ -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);
 
index 6021e2726e48cf267e309e0a5605f9ca0299a26b..0f2d61f6abf3252375c73b443aff8e18907d9342 100644 (file)
@@ -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 ---
     }
 }
 
index cdcf83e1ceae85c5b7a464e4dc260cfac349a649..c8bbacaff07bdea6fd873c06a5a92f15a722ca3b 100644 (file)
@@ -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)
index 998e9f91ec5801fff357053fa8e16c7720fa436c..7dd76751c2ed3570ed68df564bc8c890a9164eed 100644 (file)
@@ -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;
-}
-