diff --git a/include/linux/ffi.pr b/include/linux/ffi.pr index 39047f4..39d7529 100644 --- a/include/linux/ffi.pr +++ b/include/linux/ffi.pr @@ -20,7 +20,6 @@ export type ffi_java_raw_closure = struct { tramp: [24; char]; cif: *ffi_cif; tr export type ffi_go_closure = struct { tramp: *; cif: *ffi_cif; fun: def (*ffi_cif, *, **, *) -> (); } export import def #extern ffi_closure_alloc(size: ulong, code: **) -> * export import def #extern ffi_closure_free(_0: *) -export import def #extern ffi_prep_closure(_0: *ffi_closure, _1: *ffi_cif, fun: def (*ffi_cif, *, **, *) -> (), user_data: *) -> ffi_status export import def #extern ffi_prep_closure_loc(_0: *ffi_closure, _1: *ffi_cif, fun: def (*ffi_cif, *, **, *) -> (), user_data: *, codeloc: *) -> ffi_status export import def #extern ffi_prep_go_closure(_0: *ffi_go_closure, _1: *ffi_cif, fun: def (*ffi_cif, *, **, *) -> ()) -> ffi_status export import def #extern ffi_call_go(cif: *ffi_cif, fn: def () -> (), rvalue: *, avalue: **, closure: *) diff --git a/include/linux/ffi_sym.pr b/include/linux/ffi_sym.pr index 81c3698..2c16c7c 100644 --- a/include/linux/ffi_sym.pr +++ b/include/linux/ffi_sym.pr @@ -1,29 +1,28 @@ import ffi import symbol -export var __SYMBOLS: [26; symbol::Symbol] +export var __SYMBOLS: [25; symbol::Symbol] __SYMBOLS[0] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_closure_alloc", function = *ffi_closure_alloc !def () -> ()} !symbol::Symbol __SYMBOLS[1] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_closure_free", function = *ffi_closure_free !def () -> ()} !symbol::Symbol -__SYMBOLS[2] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_closure", function = *ffi_prep_closure !def () -> ()} !symbol::Symbol -__SYMBOLS[3] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_closure_loc", function = *ffi_prep_closure_loc !def () -> ()} !symbol::Symbol -__SYMBOLS[4] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_go_closure", function = *ffi_prep_go_closure !def () -> ()} !symbol::Symbol -__SYMBOLS[5] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_call_go", function = *ffi_call_go !def () -> ()} !symbol::Symbol -__SYMBOLS[6] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_cif", function = *ffi_prep_cif !def () -> ()} !symbol::Symbol -__SYMBOLS[7] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_cif_var", function = *ffi_prep_cif_var !def () -> ()} !symbol::Symbol -__SYMBOLS[8] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_call", function = *ffi_call !def () -> ()} !symbol::Symbol -__SYMBOLS[9] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_get_struct_offsets", function = *ffi_get_struct_offsets !def () -> ()} !symbol::Symbol -__SYMBOLS[10] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_void", variable = *ffi_type_void !*} !symbol::Symbol -__SYMBOLS[11] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint8", variable = *ffi_type_uint8 !*} !symbol::Symbol -__SYMBOLS[12] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint8", variable = *ffi_type_sint8 !*} !symbol::Symbol -__SYMBOLS[13] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint16", variable = *ffi_type_uint16 !*} !symbol::Symbol -__SYMBOLS[14] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint16", variable = *ffi_type_sint16 !*} !symbol::Symbol -__SYMBOLS[15] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint32", variable = *ffi_type_uint32 !*} !symbol::Symbol -__SYMBOLS[16] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint32", variable = *ffi_type_sint32 !*} !symbol::Symbol -__SYMBOLS[17] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint64", variable = *ffi_type_uint64 !*} !symbol::Symbol -__SYMBOLS[18] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint64", variable = *ffi_type_sint64 !*} !symbol::Symbol -__SYMBOLS[19] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_float", variable = *ffi_type_float !*} !symbol::Symbol -__SYMBOLS[20] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_double", variable = *ffi_type_double !*} !symbol::Symbol -__SYMBOLS[21] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_pointer", variable = *ffi_type_pointer !*} !symbol::Symbol -__SYMBOLS[22] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_longdouble", variable = *ffi_type_longdouble !*} !symbol::Symbol -__SYMBOLS[23] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_complex_float", variable = *ffi_type_complex_float !*} !symbol::Symbol -__SYMBOLS[24] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_complex_double", variable = *ffi_type_complex_double !*} !symbol::Symbol -__SYMBOLS[25] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_complex_longdouble", variable = *ffi_type_complex_longdouble !*} !symbol::Symbol +__SYMBOLS[2] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_closure_loc", function = *ffi_prep_closure_loc !def () -> ()} !symbol::Symbol +__SYMBOLS[3] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_go_closure", function = *ffi_prep_go_closure !def () -> ()} !symbol::Symbol +__SYMBOLS[4] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_call_go", function = *ffi_call_go !def () -> ()} !symbol::Symbol +__SYMBOLS[5] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_cif", function = *ffi_prep_cif !def () -> ()} !symbol::Symbol +__SYMBOLS[6] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_prep_cif_var", function = *ffi_prep_cif_var !def () -> ()} !symbol::Symbol +__SYMBOLS[7] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_call", function = *ffi_call !def () -> ()} !symbol::Symbol +__SYMBOLS[8] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ffi_get_struct_offsets", function = *ffi_get_struct_offsets !def () -> ()} !symbol::Symbol +__SYMBOLS[9] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_void", variable = *ffi_type_void !*} !symbol::Symbol +__SYMBOLS[10] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint8", variable = *ffi_type_uint8 !*} !symbol::Symbol +__SYMBOLS[11] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint8", variable = *ffi_type_sint8 !*} !symbol::Symbol +__SYMBOLS[12] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint16", variable = *ffi_type_uint16 !*} !symbol::Symbol +__SYMBOLS[13] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint16", variable = *ffi_type_sint16 !*} !symbol::Symbol +__SYMBOLS[14] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint32", variable = *ffi_type_uint32 !*} !symbol::Symbol +__SYMBOLS[15] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint32", variable = *ffi_type_sint32 !*} !symbol::Symbol +__SYMBOLS[16] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_uint64", variable = *ffi_type_uint64 !*} !symbol::Symbol +__SYMBOLS[17] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_sint64", variable = *ffi_type_sint64 !*} !symbol::Symbol +__SYMBOLS[18] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_float", variable = *ffi_type_float !*} !symbol::Symbol +__SYMBOLS[19] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_double", variable = *ffi_type_double !*} !symbol::Symbol +__SYMBOLS[20] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_pointer", variable = *ffi_type_pointer !*} !symbol::Symbol +__SYMBOLS[21] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_longdouble", variable = *ffi_type_longdouble !*} !symbol::Symbol +__SYMBOLS[22] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_complex_float", variable = *ffi_type_complex_float !*} !symbol::Symbol +__SYMBOLS[23] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_complex_double", variable = *ffi_type_complex_double !*} !symbol::Symbol +__SYMBOLS[24] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "ffi_type_complex_longdouble", variable = *ffi_type_complex_longdouble !*} !symbol::Symbol diff --git a/include/linux/linux.pr b/include/linux/linux.pr index db012e6..e54a62c 100644 --- a/include/linux/linux.pr +++ b/include/linux/linux.pr @@ -624,7 +624,6 @@ export import def #extern sethostid(__id: long) -> int export import def #extern getdomainname(__name: *char, __len: ulong) -> int export import def #extern setdomainname(__name: *char, __len: ulong) -> int export import def #extern vhangup() -> int -export import def #extern profil(__sample_buffer: *ushort, __size: ulong, __offset: ulong, __scale: uint) -> int export import def #extern acct(__name: *char) -> int export import def #extern getusershell() -> *char export import def #extern endusershell() diff --git a/include/linux/linux_sym.pr b/include/linux/linux_sym.pr index 4a74b2c..a972ffc 100644 --- a/include/linux/linux_sym.pr +++ b/include/linux/linux_sym.pr @@ -1,6 +1,6 @@ import linux import symbol -export var __SYMBOLS: [282; symbol::Symbol] +export var __SYMBOLS: [281; symbol::Symbol] __SYMBOLS[0] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "stat", function = *stat !def () -> ()} !symbol::Symbol __SYMBOLS[1] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fstat", function = *fstat !def () -> ()} !symbol::Symbol __SYMBOLS[2] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fstatat", function = *fstatat !def () -> ()} !symbol::Symbol @@ -154,132 +154,131 @@ __SYMBOLS[149] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name __SYMBOLS[150] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getdomainname", function = *getdomainname !def () -> ()} !symbol::Symbol __SYMBOLS[151] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setdomainname", function = *setdomainname !def () -> ()} !symbol::Symbol __SYMBOLS[152] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "vhangup", function = *vhangup !def () -> ()} !symbol::Symbol -__SYMBOLS[153] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "profil", function = *profil !def () -> ()} !symbol::Symbol -__SYMBOLS[154] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "acct", function = *acct !def () -> ()} !symbol::Symbol -__SYMBOLS[155] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getusershell", function = *getusershell !def () -> ()} !symbol::Symbol -__SYMBOLS[156] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "endusershell", function = *endusershell !def () -> ()} !symbol::Symbol -__SYMBOLS[157] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setusershell", function = *setusershell !def () -> ()} !symbol::Symbol -__SYMBOLS[158] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "daemon", function = *daemon !def () -> ()} !symbol::Symbol -__SYMBOLS[159] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "chroot", function = *chroot !def () -> ()} !symbol::Symbol -__SYMBOLS[160] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getpass", function = *getpass !def () -> ()} !symbol::Symbol -__SYMBOLS[161] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fsync", function = *fsync !def () -> ()} !symbol::Symbol -__SYMBOLS[162] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "gethostid", function = *gethostid !def () -> ()} !symbol::Symbol -__SYMBOLS[163] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "sync", function = *sync !def () -> ()} !symbol::Symbol -__SYMBOLS[164] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getpagesize", function = *getpagesize !def () -> ()} !symbol::Symbol -__SYMBOLS[165] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getdtablesize", function = *getdtablesize !def () -> ()} !symbol::Symbol -__SYMBOLS[166] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "truncate", function = *truncate !def () -> ()} !symbol::Symbol -__SYMBOLS[167] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ftruncate", function = *ftruncate !def () -> ()} !symbol::Symbol -__SYMBOLS[168] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "brk", function = *brk !def () -> ()} !symbol::Symbol -__SYMBOLS[169] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "sbrk", function = *sbrk !def () -> ()} !symbol::Symbol -__SYMBOLS[170] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "syscall", function = *syscall !def () -> ()} !symbol::Symbol -__SYMBOLS[171] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lockf", function = *lockf !def () -> ()} !symbol::Symbol -__SYMBOLS[172] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fdatasync", function = *fdatasync !def () -> ()} !symbol::Symbol -__SYMBOLS[173] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getentropy", function = *getentropy !def () -> ()} !symbol::Symbol -__SYMBOLS[174] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfgetospeed", function = *cfgetospeed !def () -> ()} !symbol::Symbol -__SYMBOLS[175] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfgetispeed", function = *cfgetispeed !def () -> ()} !symbol::Symbol -__SYMBOLS[176] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfsetospeed", function = *cfsetospeed !def () -> ()} !symbol::Symbol -__SYMBOLS[177] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfsetispeed", function = *cfsetispeed !def () -> ()} !symbol::Symbol -__SYMBOLS[178] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfsetspeed", function = *cfsetspeed !def () -> ()} !symbol::Symbol -__SYMBOLS[179] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcgetattr", function = *tcgetattr !def () -> ()} !symbol::Symbol -__SYMBOLS[180] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcsetattr", function = *tcsetattr !def () -> ()} !symbol::Symbol -__SYMBOLS[181] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfmakeraw", function = *cfmakeraw !def () -> ()} !symbol::Symbol -__SYMBOLS[182] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcsendbreak", function = *tcsendbreak !def () -> ()} !symbol::Symbol -__SYMBOLS[183] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcdrain", function = *tcdrain !def () -> ()} !symbol::Symbol -__SYMBOLS[184] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcflush", function = *tcflush !def () -> ()} !symbol::Symbol -__SYMBOLS[185] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcflow", function = *tcflow !def () -> ()} !symbol::Symbol -__SYMBOLS[186] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcgetsid", function = *tcgetsid !def () -> ()} !symbol::Symbol -__SYMBOLS[187] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "__ctype_get_mb_cur_max", function = *__ctype_get_mb_cur_max !def () -> ()} !symbol::Symbol -__SYMBOLS[188] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "atoll", function = *atoll !def () -> ()} !symbol::Symbol -__SYMBOLS[189] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtof", function = *strtof !def () -> ()} !symbol::Symbol -__SYMBOLS[190] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtold", function = *strtold !def () -> ()} !symbol::Symbol -__SYMBOLS[191] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtoq", function = *strtoq !def () -> ()} !symbol::Symbol -__SYMBOLS[192] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtouq", function = *strtouq !def () -> ()} !symbol::Symbol -__SYMBOLS[193] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtoll", function = *strtoll !def () -> ()} !symbol::Symbol -__SYMBOLS[194] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtoull", function = *strtoull !def () -> ()} !symbol::Symbol -__SYMBOLS[195] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "l64a", function = *l64a !def () -> ()} !symbol::Symbol -__SYMBOLS[196] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "a64l", function = *a64l !def () -> ()} !symbol::Symbol -__SYMBOLS[197] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "random", function = *random !def () -> ()} !symbol::Symbol -__SYMBOLS[198] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srandom", function = *srandom !def () -> ()} !symbol::Symbol -__SYMBOLS[199] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "initstate", function = *initstate !def () -> ()} !symbol::Symbol -__SYMBOLS[200] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setstate", function = *setstate !def () -> ()} !symbol::Symbol -__SYMBOLS[201] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "random_r", function = *random_r !def () -> ()} !symbol::Symbol -__SYMBOLS[202] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srandom_r", function = *srandom_r !def () -> ()} !symbol::Symbol -__SYMBOLS[203] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "initstate_r", function = *initstate_r !def () -> ()} !symbol::Symbol -__SYMBOLS[204] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setstate_r", function = *setstate_r !def () -> ()} !symbol::Symbol -__SYMBOLS[205] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "rand_r", function = *rand_r !def () -> ()} !symbol::Symbol -__SYMBOLS[206] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "drand48", function = *drand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[207] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "erand48", function = *erand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[208] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lrand48", function = *lrand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[209] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "nrand48", function = *nrand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[210] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mrand48", function = *mrand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[211] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "jrand48", function = *jrand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[212] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srand48", function = *srand48 !def () -> ()} !symbol::Symbol -__SYMBOLS[213] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "seed48", function = *seed48 !def () -> ()} !symbol::Symbol -__SYMBOLS[214] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lcong48", function = *lcong48 !def () -> ()} !symbol::Symbol -__SYMBOLS[215] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "drand48_r", function = *drand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[216] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "erand48_r", function = *erand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[217] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lrand48_r", function = *lrand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[218] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "nrand48_r", function = *nrand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[219] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mrand48_r", function = *mrand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[220] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "jrand48_r", function = *jrand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[221] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srand48_r", function = *srand48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[222] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "seed48_r", function = *seed48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[223] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lcong48_r", function = *lcong48_r !def () -> ()} !symbol::Symbol -__SYMBOLS[224] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "reallocarray", function = *reallocarray !def () -> ()} !symbol::Symbol -__SYMBOLS[225] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "valloc", function = *valloc !def () -> ()} !symbol::Symbol -__SYMBOLS[226] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "posix_memalign", function = *posix_memalign !def () -> ()} !symbol::Symbol -__SYMBOLS[227] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "aligned_alloc", function = *aligned_alloc !def () -> ()} !symbol::Symbol -__SYMBOLS[228] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "at_quick_exit", function = *at_quick_exit !def () -> ()} !symbol::Symbol -__SYMBOLS[229] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "on_exit", function = *on_exit !def () -> ()} !symbol::Symbol -__SYMBOLS[230] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "quick_exit", function = *quick_exit !def () -> ()} !symbol::Symbol -__SYMBOLS[231] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "_Exit", function = *_Exit !def () -> ()} !symbol::Symbol -__SYMBOLS[232] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "putenv", function = *putenv !def () -> ()} !symbol::Symbol -__SYMBOLS[233] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setenv", function = *setenv !def () -> ()} !symbol::Symbol -__SYMBOLS[234] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "unsetenv", function = *unsetenv !def () -> ()} !symbol::Symbol -__SYMBOLS[235] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "clearenv", function = *clearenv !def () -> ()} !symbol::Symbol -__SYMBOLS[236] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mkstemp", function = *mkstemp !def () -> ()} !symbol::Symbol -__SYMBOLS[237] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mkstemps", function = *mkstemps !def () -> ()} !symbol::Symbol -__SYMBOLS[238] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mkdtemp", function = *mkdtemp !def () -> ()} !symbol::Symbol -__SYMBOLS[239] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "realpath", function = *realpath !def () -> ()} !symbol::Symbol -__SYMBOLS[240] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "llabs", function = *llabs !def () -> ()} !symbol::Symbol -__SYMBOLS[241] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lldiv", function = *lldiv !def () -> ()} !symbol::Symbol -__SYMBOLS[242] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ecvt", function = *ecvt !def () -> ()} !symbol::Symbol -__SYMBOLS[243] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fcvt", function = *fcvt !def () -> ()} !symbol::Symbol -__SYMBOLS[244] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "gcvt", function = *gcvt !def () -> ()} !symbol::Symbol -__SYMBOLS[245] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qecvt", function = *qecvt !def () -> ()} !symbol::Symbol -__SYMBOLS[246] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qfcvt", function = *qfcvt !def () -> ()} !symbol::Symbol -__SYMBOLS[247] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qgcvt", function = *qgcvt !def () -> ()} !symbol::Symbol -__SYMBOLS[248] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ecvt_r", function = *ecvt_r !def () -> ()} !symbol::Symbol -__SYMBOLS[249] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fcvt_r", function = *fcvt_r !def () -> ()} !symbol::Symbol -__SYMBOLS[250] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qecvt_r", function = *qecvt_r !def () -> ()} !symbol::Symbol -__SYMBOLS[251] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qfcvt_r", function = *qfcvt_r !def () -> ()} !symbol::Symbol -__SYMBOLS[252] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "rpmatch", function = *rpmatch !def () -> ()} !symbol::Symbol -__SYMBOLS[253] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getsubopt", function = *getsubopt !def () -> ()} !symbol::Symbol -__SYMBOLS[254] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getloadavg", function = *getloadavg !def () -> ()} !symbol::Symbol -__SYMBOLS[255] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlopen", function = *dlopen !def () -> ()} !symbol::Symbol -__SYMBOLS[256] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlclose", function = *dlclose !def () -> ()} !symbol::Symbol -__SYMBOLS[257] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlsym", function = *dlsym !def () -> ()} !symbol::Symbol -__SYMBOLS[258] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlerror", function = *dlerror !def () -> ()} !symbol::Symbol -__SYMBOLS[259] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "poll", function = *poll !def () -> ()} !symbol::Symbol -__SYMBOLS[260] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fnmatch", function = *fnmatch !def () -> ()} !symbol::Symbol -__SYMBOLS[261] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "opendir", function = *opendir !def () -> ()} !symbol::Symbol -__SYMBOLS[262] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fdopendir", function = *fdopendir !def () -> ()} !symbol::Symbol -__SYMBOLS[263] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "closedir", function = *closedir !def () -> ()} !symbol::Symbol -__SYMBOLS[264] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "readdir", function = *readdir !def () -> ()} !symbol::Symbol -__SYMBOLS[265] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "readdir_r", function = *readdir_r !def () -> ()} !symbol::Symbol -__SYMBOLS[266] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "rewinddir", function = *rewinddir !def () -> ()} !symbol::Symbol -__SYMBOLS[267] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "seekdir", function = *seekdir !def () -> ()} !symbol::Symbol -__SYMBOLS[268] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "telldir", function = *telldir !def () -> ()} !symbol::Symbol -__SYMBOLS[269] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dirfd", function = *dirfd !def () -> ()} !symbol::Symbol -__SYMBOLS[270] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "scandir", function = *scandir !def () -> ()} !symbol::Symbol -__SYMBOLS[271] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "alphasort", function = *alphasort !def () -> ()} !symbol::Symbol -__SYMBOLS[272] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getdirentries", function = *getdirentries !def () -> ()} !symbol::Symbol -__SYMBOLS[273] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "__errno_location", function = *__errno_location !def () -> ()} !symbol::Symbol -__SYMBOLS[274] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "backtrace", function = *backtrace !def () -> ()} !symbol::Symbol -__SYMBOLS[275] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "backtrace_symbols", function = *backtrace_symbols !def () -> ()} !symbol::Symbol -__SYMBOLS[276] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "backtrace_symbols_fd", function = *backtrace_symbols_fd !def () -> ()} !symbol::Symbol -__SYMBOLS[277] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "__environ", variable = *__environ !*} !symbol::Symbol -__SYMBOLS[278] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "optarg", variable = *optarg !*} !symbol::Symbol -__SYMBOLS[279] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "optind", variable = *optind !*} !symbol::Symbol -__SYMBOLS[280] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "opterr", variable = *opterr !*} !symbol::Symbol -__SYMBOLS[281] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "optopt", variable = *optopt !*} !symbol::Symbol +__SYMBOLS[153] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "acct", function = *acct !def () -> ()} !symbol::Symbol +__SYMBOLS[154] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getusershell", function = *getusershell !def () -> ()} !symbol::Symbol +__SYMBOLS[155] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "endusershell", function = *endusershell !def () -> ()} !symbol::Symbol +__SYMBOLS[156] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setusershell", function = *setusershell !def () -> ()} !symbol::Symbol +__SYMBOLS[157] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "daemon", function = *daemon !def () -> ()} !symbol::Symbol +__SYMBOLS[158] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "chroot", function = *chroot !def () -> ()} !symbol::Symbol +__SYMBOLS[159] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getpass", function = *getpass !def () -> ()} !symbol::Symbol +__SYMBOLS[160] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fsync", function = *fsync !def () -> ()} !symbol::Symbol +__SYMBOLS[161] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "gethostid", function = *gethostid !def () -> ()} !symbol::Symbol +__SYMBOLS[162] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "sync", function = *sync !def () -> ()} !symbol::Symbol +__SYMBOLS[163] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getpagesize", function = *getpagesize !def () -> ()} !symbol::Symbol +__SYMBOLS[164] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getdtablesize", function = *getdtablesize !def () -> ()} !symbol::Symbol +__SYMBOLS[165] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "truncate", function = *truncate !def () -> ()} !symbol::Symbol +__SYMBOLS[166] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ftruncate", function = *ftruncate !def () -> ()} !symbol::Symbol +__SYMBOLS[167] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "brk", function = *brk !def () -> ()} !symbol::Symbol +__SYMBOLS[168] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "sbrk", function = *sbrk !def () -> ()} !symbol::Symbol +__SYMBOLS[169] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "syscall", function = *syscall !def () -> ()} !symbol::Symbol +__SYMBOLS[170] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lockf", function = *lockf !def () -> ()} !symbol::Symbol +__SYMBOLS[171] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fdatasync", function = *fdatasync !def () -> ()} !symbol::Symbol +__SYMBOLS[172] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getentropy", function = *getentropy !def () -> ()} !symbol::Symbol +__SYMBOLS[173] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfgetospeed", function = *cfgetospeed !def () -> ()} !symbol::Symbol +__SYMBOLS[174] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfgetispeed", function = *cfgetispeed !def () -> ()} !symbol::Symbol +__SYMBOLS[175] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfsetospeed", function = *cfsetospeed !def () -> ()} !symbol::Symbol +__SYMBOLS[176] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfsetispeed", function = *cfsetispeed !def () -> ()} !symbol::Symbol +__SYMBOLS[177] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfsetspeed", function = *cfsetspeed !def () -> ()} !symbol::Symbol +__SYMBOLS[178] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcgetattr", function = *tcgetattr !def () -> ()} !symbol::Symbol +__SYMBOLS[179] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcsetattr", function = *tcsetattr !def () -> ()} !symbol::Symbol +__SYMBOLS[180] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "cfmakeraw", function = *cfmakeraw !def () -> ()} !symbol::Symbol +__SYMBOLS[181] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcsendbreak", function = *tcsendbreak !def () -> ()} !symbol::Symbol +__SYMBOLS[182] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcdrain", function = *tcdrain !def () -> ()} !symbol::Symbol +__SYMBOLS[183] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcflush", function = *tcflush !def () -> ()} !symbol::Symbol +__SYMBOLS[184] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcflow", function = *tcflow !def () -> ()} !symbol::Symbol +__SYMBOLS[185] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "tcgetsid", function = *tcgetsid !def () -> ()} !symbol::Symbol +__SYMBOLS[186] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "__ctype_get_mb_cur_max", function = *__ctype_get_mb_cur_max !def () -> ()} !symbol::Symbol +__SYMBOLS[187] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "atoll", function = *atoll !def () -> ()} !symbol::Symbol +__SYMBOLS[188] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtof", function = *strtof !def () -> ()} !symbol::Symbol +__SYMBOLS[189] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtold", function = *strtold !def () -> ()} !symbol::Symbol +__SYMBOLS[190] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtoq", function = *strtoq !def () -> ()} !symbol::Symbol +__SYMBOLS[191] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtouq", function = *strtouq !def () -> ()} !symbol::Symbol +__SYMBOLS[192] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtoll", function = *strtoll !def () -> ()} !symbol::Symbol +__SYMBOLS[193] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "strtoull", function = *strtoull !def () -> ()} !symbol::Symbol +__SYMBOLS[194] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "l64a", function = *l64a !def () -> ()} !symbol::Symbol +__SYMBOLS[195] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "a64l", function = *a64l !def () -> ()} !symbol::Symbol +__SYMBOLS[196] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "random", function = *random !def () -> ()} !symbol::Symbol +__SYMBOLS[197] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srandom", function = *srandom !def () -> ()} !symbol::Symbol +__SYMBOLS[198] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "initstate", function = *initstate !def () -> ()} !symbol::Symbol +__SYMBOLS[199] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setstate", function = *setstate !def () -> ()} !symbol::Symbol +__SYMBOLS[200] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "random_r", function = *random_r !def () -> ()} !symbol::Symbol +__SYMBOLS[201] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srandom_r", function = *srandom_r !def () -> ()} !symbol::Symbol +__SYMBOLS[202] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "initstate_r", function = *initstate_r !def () -> ()} !symbol::Symbol +__SYMBOLS[203] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setstate_r", function = *setstate_r !def () -> ()} !symbol::Symbol +__SYMBOLS[204] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "rand_r", function = *rand_r !def () -> ()} !symbol::Symbol +__SYMBOLS[205] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "drand48", function = *drand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[206] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "erand48", function = *erand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[207] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lrand48", function = *lrand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[208] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "nrand48", function = *nrand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[209] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mrand48", function = *mrand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[210] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "jrand48", function = *jrand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[211] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srand48", function = *srand48 !def () -> ()} !symbol::Symbol +__SYMBOLS[212] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "seed48", function = *seed48 !def () -> ()} !symbol::Symbol +__SYMBOLS[213] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lcong48", function = *lcong48 !def () -> ()} !symbol::Symbol +__SYMBOLS[214] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "drand48_r", function = *drand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[215] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "erand48_r", function = *erand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[216] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lrand48_r", function = *lrand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[217] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "nrand48_r", function = *nrand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[218] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mrand48_r", function = *mrand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[219] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "jrand48_r", function = *jrand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[220] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "srand48_r", function = *srand48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[221] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "seed48_r", function = *seed48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[222] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lcong48_r", function = *lcong48_r !def () -> ()} !symbol::Symbol +__SYMBOLS[223] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "reallocarray", function = *reallocarray !def () -> ()} !symbol::Symbol +__SYMBOLS[224] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "valloc", function = *valloc !def () -> ()} !symbol::Symbol +__SYMBOLS[225] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "posix_memalign", function = *posix_memalign !def () -> ()} !symbol::Symbol +__SYMBOLS[226] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "aligned_alloc", function = *aligned_alloc !def () -> ()} !symbol::Symbol +__SYMBOLS[227] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "at_quick_exit", function = *at_quick_exit !def () -> ()} !symbol::Symbol +__SYMBOLS[228] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "on_exit", function = *on_exit !def () -> ()} !symbol::Symbol +__SYMBOLS[229] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "quick_exit", function = *quick_exit !def () -> ()} !symbol::Symbol +__SYMBOLS[230] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "_Exit", function = *_Exit !def () -> ()} !symbol::Symbol +__SYMBOLS[231] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "putenv", function = *putenv !def () -> ()} !symbol::Symbol +__SYMBOLS[232] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "setenv", function = *setenv !def () -> ()} !symbol::Symbol +__SYMBOLS[233] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "unsetenv", function = *unsetenv !def () -> ()} !symbol::Symbol +__SYMBOLS[234] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "clearenv", function = *clearenv !def () -> ()} !symbol::Symbol +__SYMBOLS[235] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mkstemp", function = *mkstemp !def () -> ()} !symbol::Symbol +__SYMBOLS[236] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mkstemps", function = *mkstemps !def () -> ()} !symbol::Symbol +__SYMBOLS[237] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "mkdtemp", function = *mkdtemp !def () -> ()} !symbol::Symbol +__SYMBOLS[238] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "realpath", function = *realpath !def () -> ()} !symbol::Symbol +__SYMBOLS[239] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "llabs", function = *llabs !def () -> ()} !symbol::Symbol +__SYMBOLS[240] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "lldiv", function = *lldiv !def () -> ()} !symbol::Symbol +__SYMBOLS[241] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ecvt", function = *ecvt !def () -> ()} !symbol::Symbol +__SYMBOLS[242] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fcvt", function = *fcvt !def () -> ()} !symbol::Symbol +__SYMBOLS[243] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "gcvt", function = *gcvt !def () -> ()} !symbol::Symbol +__SYMBOLS[244] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qecvt", function = *qecvt !def () -> ()} !symbol::Symbol +__SYMBOLS[245] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qfcvt", function = *qfcvt !def () -> ()} !symbol::Symbol +__SYMBOLS[246] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qgcvt", function = *qgcvt !def () -> ()} !symbol::Symbol +__SYMBOLS[247] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "ecvt_r", function = *ecvt_r !def () -> ()} !symbol::Symbol +__SYMBOLS[248] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fcvt_r", function = *fcvt_r !def () -> ()} !symbol::Symbol +__SYMBOLS[249] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qecvt_r", function = *qecvt_r !def () -> ()} !symbol::Symbol +__SYMBOLS[250] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "qfcvt_r", function = *qfcvt_r !def () -> ()} !symbol::Symbol +__SYMBOLS[251] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "rpmatch", function = *rpmatch !def () -> ()} !symbol::Symbol +__SYMBOLS[252] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getsubopt", function = *getsubopt !def () -> ()} !symbol::Symbol +__SYMBOLS[253] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getloadavg", function = *getloadavg !def () -> ()} !symbol::Symbol +__SYMBOLS[254] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlopen", function = *dlopen !def () -> ()} !symbol::Symbol +__SYMBOLS[255] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlclose", function = *dlclose !def () -> ()} !symbol::Symbol +__SYMBOLS[256] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlsym", function = *dlsym !def () -> ()} !symbol::Symbol +__SYMBOLS[257] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dlerror", function = *dlerror !def () -> ()} !symbol::Symbol +__SYMBOLS[258] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "poll", function = *poll !def () -> ()} !symbol::Symbol +__SYMBOLS[259] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fnmatch", function = *fnmatch !def () -> ()} !symbol::Symbol +__SYMBOLS[260] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "opendir", function = *opendir !def () -> ()} !symbol::Symbol +__SYMBOLS[261] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "fdopendir", function = *fdopendir !def () -> ()} !symbol::Symbol +__SYMBOLS[262] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "closedir", function = *closedir !def () -> ()} !symbol::Symbol +__SYMBOLS[263] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "readdir", function = *readdir !def () -> ()} !symbol::Symbol +__SYMBOLS[264] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "readdir_r", function = *readdir_r !def () -> ()} !symbol::Symbol +__SYMBOLS[265] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "rewinddir", function = *rewinddir !def () -> ()} !symbol::Symbol +__SYMBOLS[266] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "seekdir", function = *seekdir !def () -> ()} !symbol::Symbol +__SYMBOLS[267] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "telldir", function = *telldir !def () -> ()} !symbol::Symbol +__SYMBOLS[268] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "dirfd", function = *dirfd !def () -> ()} !symbol::Symbol +__SYMBOLS[269] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "scandir", function = *scandir !def () -> ()} !symbol::Symbol +__SYMBOLS[270] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "alphasort", function = *alphasort !def () -> ()} !symbol::Symbol +__SYMBOLS[271] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "getdirentries", function = *getdirentries !def () -> ()} !symbol::Symbol +__SYMBOLS[272] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "__errno_location", function = *__errno_location !def () -> ()} !symbol::Symbol +__SYMBOLS[273] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "backtrace", function = *backtrace !def () -> ()} !symbol::Symbol +__SYMBOLS[274] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "backtrace_symbols", function = *backtrace_symbols !def () -> ()} !symbol::Symbol +__SYMBOLS[275] = { kind = symbol::SymbolKind::FUNCTION, dllimport = false, name = "backtrace_symbols_fd", function = *backtrace_symbols_fd !def () -> ()} !symbol::Symbol +__SYMBOLS[276] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "__environ", variable = *__environ !*} !symbol::Symbol +__SYMBOLS[277] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "optarg", variable = *optarg !*} !symbol::Symbol +__SYMBOLS[278] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "optind", variable = *optind !*} !symbol::Symbol +__SYMBOLS[279] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "opterr", variable = *opterr !*} !symbol::Symbol +__SYMBOLS[280] = { kind = symbol::SymbolKind::VARIABLE, dllimport = false, name = "optopt", variable = *optopt !*} !symbol::Symbol diff --git a/include/preload.pr b/include/preload.pr index 21a402d..04d003f 100644 --- a/include/preload.pr +++ b/include/preload.pr @@ -33,7 +33,8 @@ export let dlls = map::make(DLL) export def load_ffi(syms: [symbol::Symbol]) { for var i in 0..syms.size { let sym = syms[i] - symbols[sym.name] = sym + let s = to_str(sym.name) + symbols[s] = sym } } diff --git a/src/builtins.pr b/src/builtins.pr index ffd197a..54e432b 100644 --- a/src/builtins.pr +++ b/src/builtins.pr @@ -11,7 +11,7 @@ export let builtins_module = toolchain::make_module(null, "builtin", null, built builtins_module.stage = toolchain::Stage::COMPILING builtins.module = builtins_module -def create_int_type(name: &string, size: size_t, unsig: bool) -> &typechecking::Type { +def create_int_type(name: String, size: size_t, unsig: bool) -> &typechecking::Type { let ident = parser::make_identifier(name) var tpe = typechecking::make_type(typechecking::TypeKind::WORD, ident) tpe.size = size @@ -22,7 +22,7 @@ def create_int_type(name: &string, size: size_t, unsig: bool) -> &typechecking:: return tpe } -def create_float_type(name: &string, size: size_t) -> &typechecking::Type { +def create_float_type(name: String, size: size_t) -> &typechecking::Type { let ident = parser::make_identifier(name) var tpe = typechecking::make_type(typechecking::TypeKind::FLOAT, ident) tpe.size = size @@ -114,4 +114,7 @@ export var Type_: &typechecking::Type = null export var Ref_ : &typechecking::Type = null export var Function_: &typechecking::Type = null export var Generator_: &typechecking::Type = null -export var TestEnvironment_: &typechecking::Type = null \ No newline at end of file +export var TestEnvironment_: &typechecking::Type = null + +export var Field_: &typechecking::Type = null +export var EnumValue_: &typechecking::Type = null \ No newline at end of file diff --git a/src/codegen.pr b/src/codegen.pr index 851c7ca..beadac7 100644 --- a/src/codegen.pr +++ b/src/codegen.pr @@ -9,9 +9,12 @@ import debug import toolchain import builtins -def type_to_str(tpe: &typechecking::Type) -> &string { +def type_to_str(tpe: &typechecking::Type) -> Str { if not tpe { return "void" } - var ret: &string + if tpe.kind == typechecking::TypeKind::BOX { + tpe = tpe.weak + } + var ret: StringBuffer = "" switch tpe.kind !int { case typechecking::TypeKind::BOOL: ret = "i1" @@ -108,8 +111,8 @@ def type_to_str(tpe: &typechecking::Type) -> &string { return ret } -def debug_value_to_str(value: compiler::DebugValue) -> &string { - var ret: &string +def debug_value_to_str(value: compiler::DebugValue) -> Str { + var ret: StringBuffer = "" switch value.kind !int { case compiler::DebugValueKind::NULL: ret = "null" @@ -133,8 +136,8 @@ def debug_value_to_str(value: compiler::DebugValue) -> &string { return ret } -def value_to_str(value: compiler::Value) -> &string { - var ret: &string +def value_to_str(value: compiler::Value) -> Str { + var ret: StringBuffer switch value.kind !int { case compiler::ValueKind::ZEROINITIALIZER: ret = "zeroinitializer" @@ -224,8 +227,8 @@ def value_to_str(value: compiler::Value) -> &string { return ret } -def named_parameter_to_str(named: typechecking::NamedParameter) -> &string { - var ret: &string = "" +def named_parameter_to_str(named: typechecking::NamedParameter) -> Str { + var ret: StringBuffer = "" if named.varargs { if named.tpe { ret += "{i" + (size_of size_t) * 8 + ", " + type_to_str(named.tpe) + "*}" @@ -562,7 +565,8 @@ def emit(fp: File, insn: &compiler::Insn) { } def emit_block(fp: File, block: &compiler::Block) { - fprint(fp, (@block).label_, ":\n") + fprint(fp, (@block).label_) + fprint(fp, ":\n") for var i in 0..vector::length((@block).insn) { let insn = (@block).insn[i] emit(fp, insn) @@ -759,7 +763,7 @@ export def gen(module: &toolchain::Module) { let result = module.result let outfile = toolchain::outfolder + '/' + module.file + ".ll" - let fp = open(@outfile, "w") + let fp = open(outfile, "w") fprint(fp, "; This file was compiled by the grace of your highness Princess Vic Nightfall\n") diff --git a/src/compiler.pr b/src/compiler.pr index 03a67be..491e3ed 100644 --- a/src/compiler.pr +++ b/src/compiler.pr @@ -13,9 +13,10 @@ import errors import eval import md5 import optional +import arena export type Label = struct { - name: &string + name: Str } export type DebugValueKind = enum { @@ -24,13 +25,13 @@ export type DebugValueKind = enum { export type DebugValue = struct { kind: DebugValueKind - name: &string - s: &string + name: Str + s: Str i: int64 } export type DebugParam = struct { - name: &string + name: Str value: DebugValue } @@ -45,10 +46,10 @@ export type Value = struct { kind: ValueKind metadata: bool distinct: bool - name: &string + name: Str i: int64 f: double - s: &string + s: &[char] // This is the value of a type value_tpe: &typechecking::Type // Used for both struct and array @@ -325,7 +326,7 @@ export type InsnCall = struct { proto: &[typechecking::NamedParameter] } -export def call(state: &State, name: &string, tpe: &typechecking::Type, args: &[Value], loc: &Value = null) -> Value { +export def call(state: &State, name: Str, tpe: &typechecking::Type, args: &[Value], loc: &Value = null) -> Value { let ret = make_local_value(tpe, null, state) if tpe else NO_VALUE let call = make_insn_dbg(InsnKind::CALL, loc) call.value.call = { @@ -415,7 +416,7 @@ export def destruct(insn: *Insn) { // Block for CFG export type Block = struct { - label_: &string + label_: Str counter: int // Vector of Insn insn: &Vector(&Insn) @@ -432,8 +433,8 @@ export type Function = struct { // True if we have C style varargs varargs: bool - name: &string - unmangled: &string + name: Str + unmangled: Str tpe: &typechecking::Type // Vector of typechecking::NamedParameter args: &Vector(typechecking::NamedParameter) @@ -498,7 +499,7 @@ export type Global = struct { dllexport: bool external: bool private: bool - name: &string + name: Str tpe: &typechecking::Type value: &Value line: int @@ -529,6 +530,7 @@ export type State = struct { discope: &Vector(&Value) // Used by eval globals: &SMap(*) + mem: &arena::Arena scope: weak_ref(scope::Scope) // Destructor function finalizer: &Function @@ -540,6 +542,10 @@ export type State = struct { file_name_value: Value } +export def destruct(state: *State) { + state.mem.free() +} + def current_value(state: &State) -> &scope::Value { if state.current_variable { return state.current_variable @@ -571,16 +577,6 @@ def add_type_meta(tpe: &typechecking::Type, state: &State) { } } -// TODO We are trying to free stuff that doesn't need to be freed like stdout -// This is leaking memory -/*export def destruct(state: *State) { - if not state.globals { return } - let keys = state.globals.keys - for var i in 0..keys.size { - free(state.globals[keys[i]]) - } -}*/ - export def make_block -> &Block { return { label_ = "start", @@ -746,7 +742,7 @@ def push_alloca(insn: &Insn, state: &State, no_yield_capture: bool = false) { } } -def push_declare_arg(node: &parser::Node, val: Value, name: &string, arg: int, state: &State) { +def push_declare_arg(node: &parser::Node, val: Value, name: Str, arg: int, state: &State) { if not toolchain::debug_sym { return } var line = node.loc.line let discope = vector::peek(state.discope) if state.discope.length > 0 else null !&Value @@ -807,7 +803,7 @@ def push_declare_arg(node: &parser::Node, val: Value, name: &string, arg: int, s push_insn(call, state) } -def push_declare(node: &parser::Node, val: Value, name: &string, state: &State) { +def push_declare(node: &parser::Node, val: Value, name: Str, state: &State) { push_declare_arg(node, val, name, -1, state) } @@ -851,13 +847,13 @@ export def make_named_local(tpe: &typechecking::Type, addr: &Value, state: &Stat } !Value } -export def make_global_name(name: &string, state: &State) -> &string { +export def make_global_name(name: Str, state: &State) -> Str { let ret = state.module.module + "::" + name + '.' + state.global_counter state.global_counter += 1 return ret } -export def make_global_value(tpe: &typechecking::Type, name: &string, value: &Value, state: &State, private: bool = true) -> Value { +export def make_global_value(tpe: &typechecking::Type, name: Str, value: &Value, state: &State, private: bool = true) -> Value { name = make_global_name(name, state) let global = { @@ -935,23 +931,23 @@ export def charp_static(global: &Value, state: &State) -> Value { return local } -export def create_global_string(str: &string, state: &State) -> Value { +export def create_global_string(str: Str, state: &State) -> Value { let tpe = typechecking::make_type_raw(typechecking::TypeKind::STATIC_ARRAY) tpe._tpe = builtins::char_ - tpe.length = str.size + tpe.length = str.length() + 1 tpe.size = tpe.length * (size_of char) tpe.align = align_of char let value = { kind = ValueKind::STRING, - s = str, + s = str.to_array(), tpe = tpe } !&Value return make_global_value(tpe, "str", value, state) } -export def charp(str: &string, state: &State) -> Value { +export def charp(str: Str, state: &State) -> Value { return charp_static(create_global_string(str, state), state) } @@ -1021,6 +1017,9 @@ def import_structure(tpe: &typechecking::Type, module: &toolchain::Module) { export def import_structures(tpe: &typechecking::Type, module: &toolchain::Module) { if not tpe { return } + if tpe.kind == typechecking::TypeKind::BOX { + tpe = tpe.weak + } switch tpe.kind !int { case typechecking::TypeKind::STRUCT..=typechecking::TypeKind::UNION: import_structure(tpe, module) @@ -1046,7 +1045,7 @@ export def import_structures(tpe: &typechecking::Type, module: &toolchain::Modul } } -def import_cstd_function(name: &string, state: &State) { +def import_cstd_function(name: Str, state: &State) { let cstd_module = toolchain::find_module("cstd") var func = scope::get(cstd_module.scope, parser::make_identifier(name)) if not func { return } @@ -1118,13 +1117,13 @@ def walk_String(node: &parser::Node, state: &State) -> Value { let strtpe = typechecking::make_type_raw(typechecking::TypeKind::STATIC_ARRAY) (@strtpe)._tpe = builtins::char_ - (@strtpe).length = node.value.str.size + (@strtpe).length = node.value.str.length() + 1 (@strtpe).size = (@strtpe).length * (size_of char) (@strtpe).align = align_of char let str_value = { kind = ValueKind::STRING, - s = node.value.str, + s = node.value.str.to_array(), tpe = tpe } !&Value @@ -1154,7 +1153,7 @@ def walk_String(node: &parser::Node, state: &State) -> Value { values[0] = { kind = ValueKind::INT, tpe = builtins::size_t_, - i = node.value.str.size + i = node.value.str.length() + 1 } !Value values[1] = { kind = ValueKind::UNDEF, @@ -2992,6 +2991,7 @@ def insert_copy_constructor(addr: Value, value: Value, loc: &Value, state: &Stat br.value.br.if_true = loop_end } else { var ctor = typechecking::get_constructor(addr.tpe.tpe) + if not ctor { return } if consteval::is_static { consteval::compile_function(ctor) } @@ -3066,6 +3066,14 @@ def insert_destructor(value: Value, loc: &Value, state: &State) { var destructor = typechecking::get_builtin_destructor(value.tpe.tpe) if not destructor { return } predeclare_function(destructor.tpe, state.module) + + if consteval::is_static { + let udtor = get_user_defined_destructor(value.tpe.tpe) + if udtor { + consteval::compile_function(udtor) + } + } + state.module.imported.add(destructor.tpe.type_name) state.call(destructor.tpe.type_name, null, [value], loc) } @@ -3662,12 +3670,12 @@ type Member = struct { } // This list needs to be reversed to find the actual indices -def resolve_member(vec: &Vector(Member), tpe: &typechecking::Type, name: &string) -> bool { +def resolve_member(vec: &Vector(Member), tpe: &typechecking::Type, name: Str) -> bool { let fields = tpe.fields if not fields { return false } for var i in 0..fields.size { let field = fields[i] - if field.name != null { + if field.name { if field.name == name { let member = { index = i, @@ -3693,6 +3701,11 @@ def resolve_member(vec: &Vector(Member), tpe: &typechecking::Type, name: &string def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, member: &Member, value: Value, state: &State) -> Value { let loc = make_location(node, state) + + var member_type = member.tpe + if member.tpe.kind == typechecking::TypeKind::BOX { + member_type = member.tpe.weak + } if tpe.kind == typechecking::TypeKind::UNION { @@ -3710,7 +3723,7 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb } !InsnGetElementPtr push_insn(gep, state) - let bitcast_ret = make_local_value(typechecking::pointer((@member).tpe), null, state) + let bitcast_ret = make_local_value(typechecking::pointer(member_type), null, state) let bitcast = make_insn_dbg(InsnKind::BITCAST, loc) (@bitcast).value.convert = { ret = bitcast_ret, @@ -3718,13 +3731,13 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb } !InsnConvert push_insn(bitcast, state) - let ret = make_address_value((@member).tpe, bitcast_ret, state) + let ret = make_address_value(member_type, bitcast_ret, state) return ret } else { let index = allocate_ref(Value, 2) index[0] = make_int_value(0) index[1] = make_int_value((@member).index) - return walk_MemberAccess_gep(node, tpe, (@member).tpe, value, index, state) + return walk_MemberAccess_gep(node, tpe, member_type, value, index, state) } } @@ -3950,7 +3963,7 @@ def compare(node: &parser::Node, left: Value, right: Value, state: &State) -> Va if typechecking::equals(left.tpe, right.tpe) { if typechecking::equals(left.tpe, builtins::string_) { - (@(@state).module).imported.add("strcmp") + import_cstd_function("strcmp", state) let args = allocate_ref(Value, 2) args[0] = charp_str(left, state) @@ -3996,7 +4009,10 @@ def compare(node: &parser::Node, left: Value, right: Value, state: &State) -> Va return cmp_ret // TODO There might be better ways of handling this } else if builtins::Type_ and typechecking::equals(left.tpe, typechecking::pointer(builtins::Type_)) { - let svalue = scope::get(toolchain::runtime_.scope, parser::make_identifier("equals")) + let svalue = scope::get(toolchain::runtime_.scope, parser::make_identifier("equals"), not consteval::is_static) + if consteval::is_static { + consteval::compile_function(svalue) + } predeclare_function(svalue.tpe, state.module) state.module.imported.add(svalue.tpe.type_name) @@ -5703,7 +5719,7 @@ def walk_Assert(node: &parser::Node, state: &State) { import_cstd_function("abort", state) var br: &Insn - var fmt: &string + var fmt: Str var args: &[Value] if cond { @@ -5729,7 +5745,7 @@ def walk_Assert(node: &parser::Node, state: &State) { fmt = "%s:%d:%s: Assertion %s failed!\n" } - var msg: &string = "" + var msg: StringBuffer = "" var line = cond.loc.lines[cond.loc.line] if cond.loc.end_line == cond.loc.line { msg += line.substring(cond.loc.column, min(line.length, cond.loc.end_column) !size_t) // TODO We get the wrong end_column, this should be fixed in lexer @@ -5769,7 +5785,7 @@ def walk_Assert(node: &parser::Node, state: &State) { args[2] = charp(node.loc.filename, state) args[3] = { kind = ValueKind::INT, tpe = builtins::int_, i = node.loc.line + 1 } !Value - var function_name: &string = "main" + var function_name: Str = "main" if state.current_function() { function_name = state.current_function().unmangled } @@ -5864,7 +5880,7 @@ export def walk(node: &parser::Node, state: &State) { state.scope = scpe } -def di_basic_type(tpe: &typechecking::Type, name: &string, c: &string, state: &State) -> &Value { +def di_basic_type(tpe: &typechecking::Type, name: Str, c: Str, state: &State) -> &Value { let debug_values = allocate_ref(DebugParam, 4) debug_values[0] = { name = "name", value = { kind = DebugValueKind::STRING, s = name } !DebugValue @@ -5886,7 +5902,7 @@ def di_basic_type(tpe: &typechecking::Type, name: &string, c: &string, state: &S return di } -def di_composite_type(value: &Value, tpe: &typechecking::Type, name: &string, c: &string, state: &State) -> &Value { +def di_composite_type(value: &Value, tpe: &typechecking::Type, name: Str, c: Str, state: &State) -> &Value { let elementsarr = allocate_ref(Value, tpe.fields.size) for var i in 0..tpe.fields.size { let elem = tpe.fields[i] @@ -5895,7 +5911,7 @@ def di_composite_type(value: &Value, tpe: &typechecking::Type, name: &string, c: name = "tag", value = { kind = DebugValueKind::CONST, name = "DW_TAG_member" } !DebugValue } !DebugParam debug_values[1] = { - name = "name", value = { kind = DebugValueKind::STRING, s = elem.name if elem.name else to_string(i) } !DebugValue + name = "name", value = { kind = DebugValueKind::STRING, s = elem.name if elem.name else to_string(i).to_str() } !DebugValue } !DebugParam debug_values[2] = { name = "scope", value = meta_to_debug_value(value) @@ -5960,7 +5976,7 @@ def di_composite_type(value: &Value, tpe: &typechecking::Type, name: &string, c: return di } -def di_forward_declare(tpe: &typechecking::Type, name: &string, state: &State) -> &Value { +def di_forward_declare(tpe: &typechecking::Type, name: Str, state: &State) -> &Value { let debug_values = allocate_ref(DebugParam, 5) debug_values[0] = { name = "tag", value = { kind = DebugValueKind::CONST, name = "DW_TAG_structure_type" } !DebugValue @@ -6155,6 +6171,9 @@ def di_type(tpe: &typechecking::Type, state: &State) -> &Value { (@state).ditypes[tpe.type_name] = ditpep } + if tpe.kind == typechecking::TypeKind::BOX { + tpe = tpe.weak + } switch tpe.kind !int { // TODO compare with char for special casing case typechecking::TypeKind::WORD: @@ -7028,11 +7047,11 @@ export def create_function( errors::current_signature = current_signature } -def make_string(str: &string, state: &State) -> Value { +def make_string(str: Str, state: &State) -> Value { let cp = charp(str, state) let values = allocate_ref(Value, 2) - values[0] = { kind = ValueKind::INT, tpe = builtins::size_t_, i = str.size } !Value + values[0] = { kind = ValueKind::INT, tpe = builtins::size_t_, i = str.length() + 1 } !Value values[1] = { kind = ValueKind::UNDEF, tpe = typechecking::pointer(builtins::char_) } !Value let ret = make_local_value(builtins::string_, null, state) let index = allocate_ref(int, 1) @@ -7288,10 +7307,10 @@ def insert_module_main(module: &toolchain::Module, name: &parser::Node, scpe: &s args.push(arg) let name_size = vector::length(name.value.identifier.path) - let array = zero_allocate(type &string, name_size + 1) + let array = zero_allocate(type String, name_size + 1) defer delete(array) for var j in 0..name_size { - array[j] = @(name.value.identifier.path[j]) + array[j] = name.value.identifier.path[j] } array[array.size - 1] = "__main__" let ident = parser::make_identifier(array) @@ -7347,8 +7366,6 @@ export def create_dyn_dispatch(state: &State) { export let constructors = map::make(type &typechecking::Type) def create_constructors { - let state = toolchain::types_state - var done = set::make() loop { var new_constructors = 0 @@ -7358,38 +7375,45 @@ def create_constructors { if set::contains(done, key) { continue } let tpe = constructors[key] - if typechecking::is_polymorph(tpe) { continue } - - let function = predeclare_function(tpe, state.module) - consteval::const_module.result.functions[function.name] = function - function.forward_declare = false - state.module.imported.add(tpe.type_name) - import_structures(tpe, state.module) - - state.function_stack.push(function) - let block = make_block() - state.current_function.block = block - let previous_block = state.current_block - state.current_block = block - - let first_arg = tpe.parameter_t[0].tpe - let copy = { kind = ValueKind::LOCAL, tpe = first_arg, name = "__copy.value" } !Value - let this = { kind = ValueKind::LOCAL, tpe = first_arg, name = "__this.value" } !Value - state.store(copy, state.load(this.tpe.tpe, this)) - create_constructor(copy, this, state) - - state.ret(NO_VALUE) - vector::insert(block.insn, 0, state.current_function.allocas) + create_constructor(tpe) new_constructors += 1 done.add(key) - state.function_stack.pop() - state.current_block = previous_block } if new_constructors == 0 { break } } } +export def create_constructor(tpe: &typechecking::Type) { + if not tpe { return } + let state = toolchain::types_state + if typechecking::is_polymorph(tpe) { return } + + let function = predeclare_function(tpe, state.module) + consteval::const_module.result.functions[function.name] = function + function.forward_declare = false + state.module.imported.add(tpe.type_name) + import_structures(tpe, state.module) + + state.function_stack.push(function) + let block = make_block() + state.current_function.block = block + let previous_block = state.current_block + state.current_block = block + + let first_arg = tpe.parameter_t[0].tpe + let copy = { kind = ValueKind::LOCAL, tpe = first_arg, name = "__copy.value" } !Value + let this = { kind = ValueKind::LOCAL, tpe = first_arg, name = "__this.value" } !Value + state.store(copy, state.load(this.tpe.tpe, this)) + create_constructor(copy, this, state) + + state.ret(NO_VALUE) + vector::insert(block.insn, 0, state.current_function.allocas) + + state.function_stack.pop() + state.current_block = previous_block +} + def create_constructor(copy: Value, this: Value, state: &State) { if this.tpe.tpe.kind == typechecking::TypeKind::STATIC_ARRAY { let counter_ptr = state.alloca(builtins::size_t_) @@ -7474,35 +7498,42 @@ def create_destructors { if map::contains(done, key) { continue } let tpe = destructors[key] - if typechecking::is_polymorph(tpe) { continue } - - let function = predeclare_function(tpe, state.module) - consteval::const_module.result.functions[function.name] = function - function.forward_declare = false - state.module.imported.add(tpe.type_name) - import_structures(tpe, state.module) + create_destructor(tpe) - state.function_stack.push(function) - let block = make_block() - state.current_function.block = block - let previous_block = state.current_block - state.current_block = block - - let first_arg = (tpe.parameter_t[0]).tpe - create_destructor(first_arg, { kind = ValueKind::LOCAL, tpe = first_arg, name = "__ptr.value" } !Value, state) - - state.ret(NO_VALUE) - vector::insert(block.insn, 0, state.current_function.allocas) - new_destructors += 1 done.add(key) - state.function_stack.pop() - state.current_block = previous_block } if new_destructors == 0 { break } } } +export def create_destructor(tpe: &typechecking::Type) { + if not tpe { return } + let state = toolchain::types_state + if typechecking::is_polymorph(tpe) { return } + + let function = predeclare_function(tpe, state.module) + consteval::const_module.result.functions[function.name] = function + function.forward_declare = false + state.module.imported.add(tpe.type_name) + import_structures(tpe, state.module) + + state.function_stack.push(function) + let block = make_block() + state.current_function.block = block + let previous_block = state.current_block + state.current_block = block + + let first_arg = (tpe.parameter_t[0]).tpe + create_destructor(first_arg, { kind = ValueKind::LOCAL, tpe = first_arg, name = "__ptr.value" } !Value, state) + + state.ret(NO_VALUE) + vector::insert(block.insn, 0, state.current_function.allocas) + + state.function_stack.pop() + state.current_block = previous_block +} + def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { if typechecking::is_polymorph(tpe) { return } assert tpe.kind == typechecking::TypeKind::POINTER @@ -7621,7 +7652,11 @@ def create_destructor(tpe: &typechecking::Type, value: Value, state: &State) { // We need to call the right destructor based on the ref type let ref = state.load(tpe.tpe, value) - let equals = scope::get(toolchain::runtime_.scope, parser::make_identifier("equals")) + let equals = scope::get(toolchain::runtime_.scope, parser::make_identifier("equals"), not consteval::is_static) + if consteval::is_static { + consteval::compile_function(equals) + } + predeclare_function(equals.tpe, state.module) state.module.imported.add(equals.tpe.type_name) @@ -7841,10 +7876,10 @@ def push_struct_members(tpe: &typechecking::Type, global: Value, module: &toolch if not state.consteval { typechecking::lookup_struct_member(field) } - let fname = field.name if field.name != null else to_string(i) + let fname = field.name if field.name else to_string(i).to_str() let name_values = allocate_ref(Value, 2) - name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = fname.size } !Value + name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = fname.length() + 1 } !Value name_values[1] = { kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) } !Value let field_values = allocate_ref(Value, 3) @@ -7952,7 +7987,7 @@ def push_enum_values(tpe: &typechecking::Type, global: Value, module: &toolchain let svalue = tpe.scope.fields[key] let name_values = allocate_ref(Value, 2) - name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = key.size } !Value + name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = key.length() + 1 } !Value name_values[1] = { kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) } !Value let eval_values = allocate_ref(Value, 2) @@ -8033,7 +8068,7 @@ def push_enum_values(tpe: &typechecking::Type, global: Value, module: &toolchain def push_type_member( exported: bool, - f_name: &string, + f_name: Str, pars: &Vector(typechecking::NamedParameter), rets: &Vector(&typechecking::Type), module: &toolchain::Module, @@ -8042,11 +8077,11 @@ def push_type_member( ) -> Value { let name_values = allocate_ref(Value, 2) - name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = f_name.size } !Value + name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = f_name.length() + 1 } !Value name_values[1] = { kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) } !Value let module_values = allocate_ref(Value, 2) - module_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = module.module.size } !Value + module_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = module.module.length() + 1 } !Value module_values[1] = { kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) } !Value let parameter_t_values = allocate_ref(Value, 2) @@ -8207,8 +8242,9 @@ def do_create_type(tpe: &typechecking::Type, svalue: &scope::Value, module: &too let state = toolchain::types_state let global = { kind = ValueKind::GLOBAL, tpe = pointer(builtins::Type_), name = svalue.assembly_name } !Value - let field_type = scope::get_type(toolchain::runtime_.scope, make_identifier("Field")) - let enum_type = scope::get_type(toolchain::runtime_.scope, make_identifier("EnumValue")) + if not builtins::Field_ { return null } + let field_type = builtins::Field_ + let enum_type = builtins::EnumValue_ let value = {} !&Value @@ -8226,11 +8262,11 @@ def do_create_type(tpe: &typechecking::Type, svalue: &scope::Value, module: &too let name_str = debug::type_to_str(tpe, true) let name_values = allocate_ref(Value, 2) - name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = name_str.size } !Value + name_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = name_str.length() + 1 } !Value name_values[1] = { kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) } !Value let module_values = allocate_ref(Value, 2) - module_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = module.module.size } !Value + module_values[0] = { kind = ValueKind::INT, tpe = builtins::int64_, i = module.module.length() + 1 } !Value module_values[1] = { kind = ValueKind::UNDEF, tpe = pointer(builtins::int8_) } !Value let type_names = allocate_ref(Value, 2) @@ -8421,9 +8457,8 @@ export def create_type(tpe: &typechecking::Type, module: &toolchain::Module, cac if name { let to_resolve = { module, tpe } !ToResolve types_to_resolve[name] = to_resolve - } else { - return null } + return null } import_structure(builtins::Type_, toolchain::types) @@ -8508,7 +8543,8 @@ export def make_state(module: &toolchain::Module) -> &State { discope = vector::make(type &Value), current_block = make_block(), globals = map::make(type *), - function_stack = vector::make(type &Function) + function_stack = vector::make(type &Function), + mem = arena::make() } !&State return state @@ -8623,7 +8659,7 @@ def generate_vtable_function(function: &Function, tpe: &typechecking::Type, stat if not function { continue } if consteval::is_static { - let fun = scope::get_function(state.module.scope, parser::make_identifier(tpe.name), parameter_t) + let fun = scope::get_function(state.module.scope, parser::make_identifier(tpe.name), parameter_t, false, false, false) consteval::compile_function(fun) } predeclare_function(function, state.module) diff --git a/src/consteval.pr b/src/consteval.pr index c26bc1e..6c2b8c4 100644 --- a/src/consteval.pr +++ b/src/consteval.pr @@ -645,7 +645,7 @@ def walk_VarDecl(node: &parser::Node, state: &typechecking::State) { compiler_state.current_block = previous_block compiler_state.function_stack.pop() - //recompile_functions(state) + compiler::create_dyn_dispatch(state.module.compiler_state) is_static = prev_is_static return @@ -719,18 +719,6 @@ def load_function(value: &scope::Value) { } } -export var recompiling_functions = false // TODO This is a hack -def recompile_functions(state: &typechecking::State) { - if recompiling_functions { return } - recompiling_functions = true - compiler::create_builtin_functions() - let previous_is_static = is_static - is_static = true - compiler::create_dyn_dispatch(state.module.compiler_state) - is_static = previous_is_static - recompiling_functions = false -} - // This function compiles a function that is called in constant evaluation export def compile_function(value: &scope::Value, arguments: &Vector(typechecking::NamedParameter) = null) -> &scope::Value { var node = value.node @@ -739,38 +727,42 @@ export def compile_function(value: &scope::Value, arguments: &Vector(typecheckin if not node { return value } var function = node.value.def_.function - compiler::predeclare_function(function, overwrite = true) + if function.is_typechecked { return value } + + let is_polymorph = typechecking::is_polymorph(function.tpe) + if not is_polymorph { + compiler::predeclare_function(function, overwrite = true) + const_module.result.functions[function.name] = function + } - const_module.result.functions[function.name] = function if not state { return value } - state.module.result.functions[function.name] = function + if not is_polymorph { state.module.result.functions[function.name] = function } + if function.is_compiled { return value } if not node.value.def_.body { return value } - if not typechecking::is_polymorph(function.tpe) { - function.is_compiled = true - value.phase = scope::Phase::COMPILED - } let prev_static = is_static is_static = true - if arguments and typechecking::is_polymorph(function.tpe) { + if arguments and is_polymorph { node = typechecking::walk_Def_with_type_argument(node, arguments, state) function = node.value.def_.function compiler::predeclare_function(function) } else { - if not function.is_typechecked { - walk_Def(node, state) - typechecking::walk_Def(node, state) - } + walk_Def(node, state) + typechecking::walk_Def(node, state) } + function.is_compiled = true + + //print("Creating function ", function.tpe.type_name, "\n") + // This is a big ugly but what can we do let debug = toolchain::debug_sym toolchain::debug_sym = false compiler::create_function(node, node.tpe, node.value.def_.body, node.inner_scope, null, compiler_state) toolchain::debug_sym = debug - + if function.defer_functions { for var i in 0..vector::length(function.defer_functions) { let deferf = function.defer_functions[i] @@ -778,7 +770,8 @@ export def compile_function(value: &scope::Value, arguments: &Vector(typecheckin } } - recompile_functions(state) + compiler::create_dyn_dispatch(state.module.compiler_state) + is_static = prev_static return function.value } @@ -955,7 +948,7 @@ def walk_Error(node: &parser::Node, state: &typechecking::State) { let function = set_current_function() typechecking::walk(node, expr, state) walk(node, expr, state) - recompile_functions(state) + compiler::create_dyn_dispatch(state.module.compiler_state) is_static = prev_is_static var result = compiler::walk_expression(expr, compiler_state) @@ -1105,6 +1098,10 @@ export def consteval(module: &toolchain::Module) { let state = typechecking::make_state(module) module.state = state consteval(state) + + if module.module == "std" { + toolchain::load_file_type() + } } export var time_spent: int64 = 0 diff --git a/src/debug.pr b/src/debug.pr index b87db53..6d0bbb3 100644 --- a/src/debug.pr +++ b/src/debug.pr @@ -15,7 +15,7 @@ def from_to_json(node: &parser::Node, types: bool) -> &Json { return res } -def bin_op_to_json(str: &string, node: &parser::Node, types: bool) -> &Json { +def bin_op_to_json(str: Str, node: &parser::Node, types: bool) -> &Json { let res = json::make_object() res["kind"] = str res["left"] = node_to_json(node.value.bin_op.left, types) @@ -23,7 +23,7 @@ def bin_op_to_json(str: &string, node: &parser::Node, types: bool) -> &Json { return res } -def un_op_to_json(str: &string, node: &parser::Node, types: bool) -> &Json { +def un_op_to_json(str: Str, node: &parser::Node, types: bool) -> &Json { let res = json::make_object() res["kind"] = str res["expr"] = node_to_json(node.value.expr, types) @@ -129,7 +129,7 @@ def function_t_to_json(node: &parser::Node, types: bool) -> &Json { return res } -def ptrarray_to_json(str: &string, node: &parser::Node, types: bool) -> &Json { +def ptrarray_to_json(str: Str, node: &parser::Node, types: bool) -> &Json { let res = json::make_object() res["kind"] = str res["kw"] = to_string(node.value.t_parr.kw) @@ -585,8 +585,8 @@ export def node_to_json(node: &parser::Node, types: bool = false) -> &Json { return res } -def function_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "def (" if tpe.kind == typechecking::TypeKind::FUNCTION else "(" +def function_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "def (" if tpe.kind == typechecking::TypeKind::FUNCTION else "(" var len = vector::length(tpe.parameter_t) for var i in 0..len { let param = tpe.parameter_t[i] @@ -616,8 +616,8 @@ def function_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def pointer_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "*" +def pointer_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "*" if tpe.kw == parser::VarDecl::LET { ret += "let " } @@ -627,8 +627,8 @@ def pointer_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def reference_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "&" +def reference_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "&" if tpe.kw == parser::VarDecl::LET { ret += "let " } @@ -638,8 +638,8 @@ def reference_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string return ret } -def weak_ref_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "weak_ref(" +def weak_ref_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "weak_ref(" if tpe.kw == parser::VarDecl::LET { ret += "let " @@ -652,8 +652,8 @@ def weak_ref_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def array_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "[" +def array_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "[" if tpe.kw == parser::VarDecl::LET { ret += "let " } @@ -664,8 +664,8 @@ def array_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def static_array_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "[" +def static_array_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "[" if tpe.length !uint64 == std::MAX_UINT64 { ret += '?' } else { @@ -680,8 +680,8 @@ def static_array_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &stri return ret } -def tuple_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string = "(" +def tuple_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer = "(" let len = vector::length(tpe.return_t) for var i in 0..len { let rtpe = tpe.return_t[i] @@ -694,27 +694,27 @@ def tuple_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def word_t_to_string(tpe: &typechecking::Type) -> &string { +def word_t_to_string(tpe: &typechecking::Type) -> Str { if tpe.unsig { return "uint" + tpe.size * 8 } return "int" + tpe.size * 8 } -def float_t_to_string(tpe: &typechecking::Type) -> &string { +def float_t_to_string(tpe: &typechecking::Type) -> Str { return "float" + tpe.size * 8 } -def type_def_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { +def type_def_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { return "Type<" + type_to_str(tpe.tpe, full_name) + '>' } -def variant_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { +def variant_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { if not tpe.variants { return "any" } - var ret: &string = "(" + var ret: StringBuffer = "(" let len = vector::length(tpe.variants) for var i in 0..len { let vtpe = tpe.variants[i] @@ -727,8 +727,8 @@ def variant_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def tc_args_to_string(args: &Vector(&typechecking::Type), full_name: bool) -> &string { - var ret: &string = "(" +def tc_args_to_string(args: &Vector(&typechecking::Type), full_name: bool) -> Str { + var ret: StringBuffer = "(" let len = vector::length(args) for var i in 0..len { let arg = args[i] @@ -745,8 +745,8 @@ def tc_args_to_string(args: &Vector(&typechecking::Type), full_name: bool) -> &s return ret } -def generic_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string +def generic_t_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer if full_name { ret = tpe.tpe.type_name } else { @@ -756,8 +756,8 @@ def generic_t_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -def tc_args_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { - var ret: &string +def tc_args_to_string(tpe: &typechecking::Type, full_name: bool) -> Str { + var ret: StringBuffer if full_name { ret = tpe.tc_tpe.type_name } else { @@ -767,7 +767,7 @@ def tc_args_to_string(tpe: &typechecking::Type, full_name: bool) -> &string { return ret } -export def type_to_str(tpe: &typechecking::Type, full_name: bool = false) -> &string { +export def type_to_str(tpe: &typechecking::Type, full_name: bool = false) -> Str { if not tpe { return "(none)" } if tpe.tc_tpe { return tc_args_to_string(tpe, full_name) } switch tpe.kind !int { @@ -833,7 +833,7 @@ export def type_to_str(tpe: &typechecking::Type, full_name: bool = false) -> &st export var verbose = false let start_time = util::millis() -export def trace(msg: &string...) { +export def trace(msg: String...) { if verbose { let now = util::millis() let time_offset = (now - start_time) !double / 1000 diff --git a/src/errors.pr b/src/errors.pr index a75983f..29844fb 100644 --- a/src/errors.pr +++ b/src/errors.pr @@ -8,15 +8,15 @@ export var error_count = 0 export var suppress_errors = false export type Diagnostic = struct { - filename: &string - function: &string + filename: Str + function: Str signature: uint64 line: int column: int end_line: int end_column: int - text: &string - message: &string + text: Str + message: Str } export def hash(diag: Diagnostic) -> uint64 { @@ -47,7 +47,7 @@ export def != (this: Diagnostic, other: Diagnostic) -> bool { export var error_handler: (Diagnostic) -> () = *print_error -export def errorv(msg: &string...) { +export def errorv(msg: String...) { error("error: [eval] ") for var i in 0..msg.size { error(msg[i]) @@ -57,7 +57,7 @@ export def errorv(msg: &string...) { } // TODO Passing a parameter with global state is a bad idea -export var current_function: &string +export var current_function: String export var current_signature: uint64 export def print_error(diagnostic: Diagnostic) { @@ -84,7 +84,7 @@ export def print_error(diagnostic: Diagnostic) { error_count += 1 } -export def errorn(node: &parser::Node, msg: &string...) { +export def errorn(node: &parser::Node, msg: String...) { if suppress_errors { return } if not node { assert(false) } @@ -94,13 +94,13 @@ export def errorn(node: &parser::Node, msg: &string...) { let end_line = node.loc.end_line var end_column = node.loc.end_column let lines = node.loc.lines - let str = lines[line] if lines else "" !&string + let str = lines[line] if lines else {} !Str if not filename { filename = node.loc.filename } - var message: &string = "" + var message: StringBuffer = "" for var fragment in msg { message += fragment } @@ -118,7 +118,7 @@ export def errorn(node: &parser::Node, msg: &string...) { error_handler(diagnostic) } -export def errort(token: lexer::Token, state: &parser::ParseState, msg: &string...) { +export def errort(token: lexer::Token, state: &parser::ParseState, msg: String...) { if suppress_errors { return } if state.has_error { return } @@ -129,7 +129,7 @@ export def errort(token: lexer::Token, state: &parser::ParseState, msg: &string. var end_column = token.end_column let str = (@state).lines[line] - var message: &string = "" + var message: StringBuffer = "" for var fragment in msg { message += fragment } diff --git a/src/eval.pr b/src/eval.pr index ed81aea..5b89102 100644 --- a/src/eval.pr +++ b/src/eval.pr @@ -15,21 +15,20 @@ import errors import preload import ffi import symbol +import arena export type StackFrame = struct { next: &compiler::Block jump_table: &SMap(&compiler::Block) locals: &SMap(*) - function_name: &string + function_name: Str line: int ret: compiler::Value + mem: &arena::Arena } export def destruct(frame: *StackFrame) { - let keys = frame.locals.keys - for var i in 0..keys.size { - free(frame.locals[keys[i]]) - } + frame.mem.free() } export type State = struct { @@ -66,12 +65,13 @@ def print_stack_trace(state: &State) { } } -export def make_stack_frame(block: &compiler::Block, name: &string, line: int) -> &StackFrame { +export def make_stack_frame(block: &compiler::Block, name: Str, line: int) -> &StackFrame { let stack_frame = { locals = map::make(type *), function_name = name, line = line, - jump_table = map::make(type &compiler::Block) + jump_table = map::make(type &compiler::Block), + mem = arena::make(1024) // TODO maybe calculate the size based on the local variables... } !&StackFrame while block { @@ -121,9 +121,7 @@ export def get(mem: *, tpe: &typechecking::Type) -> compiler::Value { values[2] = { kind = compiler::ValueKind::POINTER, tpe = typechecking::pointer(builtins::Type_), i = @((mem ++ (size_of type *) * 2) !*int64) } !compiler::Value return { kind = compiler::ValueKind::STRUCT, tpe = tpe, values = values } !compiler::Value case typechecking::TypeKind::UNION: - let values = allocate_ref(compiler::Value, 1) - values[0] = get(mem, (tpe.field_types[0]).tpe) - return { kind = compiler::ValueKind::STRUCT, tpe = tpe, values = values } !compiler::Value + return get(mem, typechecking::make_static_array(builtins::int8_, tpe.size)) case typechecking::TypeKind::STRUCT, typechecking::TypeKind::CLOSURE: let len = vector::length(tpe.field_types) let values = allocate_ref(compiler::Value, len) @@ -134,7 +132,7 @@ export def get(mem: *, tpe: &typechecking::Type) -> compiler::Value { return { kind = compiler::ValueKind::STRUCT, tpe = tpe, values = values } !compiler::Value case typechecking::TypeKind::STATIC_ARRAY: if typechecking::equals(tpe.tpe, builtins::char_) { - let str = allocate(char, tpe.size) + let str = allocate_ref(char, tpe.size) memcopy(mem, str.value, tpe.size) return { kind = compiler::ValueKind::STRING, tpe = tpe, s = str } !compiler::Value } else { @@ -175,7 +173,7 @@ export def get_address(loc: compiler::Value, state: &State) -> * { var function = consteval::const_module.result.functions.get_or_default(loc.name, null) if function { - ptr = zero_allocate(FunctionPtr) + ptr = state.cstate.mem.allocate(FunctionPtr) (ptr !*FunctionPtr).function = function //set(ptr, loc.tpe.tpe, { kind = compiler::ValueKind::FUNCTION, tpe = loc.tpe.tpe, function = (ptr !*FunctionPtr) } !compiler::Value) } else { @@ -191,7 +189,7 @@ export def get_address(loc: compiler::Value, state: &State) -> * { errors::errorv("Global by the name of `", loc.name, "` not found") return null } else { - ptr = zero_allocate(loc.tpe.tpe.size) + ptr = state.cstate.mem.allocate(loc.tpe.tpe.size) if global.value { set(ptr, loc.tpe.tpe, @global.value) } @@ -199,10 +197,7 @@ export def get_address(loc: compiler::Value, state: &State) -> * { } } - // TODO Use something like a linear allocator to store these - state.cstate.globals[compiler::make_global_name("__eval_tmp", state.cstate)] = ptr - - mem = allocate(loc.tpe.size) + mem = state.cstate.mem.allocate(loc.tpe.size) let value = { kind = compiler::ValueKind::POINTER, tpe = loc.tpe, i = ptr !int64 } !compiler::Value set(mem, loc.tpe, value) state.cstate.globals[loc.name] = mem @@ -261,8 +256,7 @@ def set(mem: *, tpe: &typechecking::Type, value: compiler::Value) { set(mem ++ type_member.offset, type_member.tpe, value.values[i]) } case typechecking::TypeKind::UNION: - let v = value.values[0] - set(mem, v.tpe, v) + set(mem, typechecking::make_static_array(builtins::int8_, tpe.size), value) case typechecking::TypeKind::STATIC_ARRAY: if typechecking::equals(tpe.tpe, builtins::char_) and value.kind == compiler::ValueKind::STRING { memcopy(value.s.value, mem, tpe.length) @@ -291,21 +285,19 @@ export def set_value(loc: compiler::Value, value: compiler::Value, state: &State if loc.kind == compiler::ValueKind::LOCAL { var mem = get_stack_frame(state).locals.get_or_default(loc.name, null) if not mem { - // TODO This shouldn't need to be initialized, we seem to have a bug elsewhere - mem = zero_allocate(loc.tpe.size) - get_stack_frame(state).locals[loc.name] = mem + let frame = get_stack_frame(state) + mem = frame.mem.allocate(loc.tpe.size) + frame.locals[loc.name] = mem } set(mem, loc.tpe, value) } else if loc.kind == compiler::ValueKind::GLOBAL { var mem = state.cstate.globals.get_or_default(loc.name, null) var ptr: * = null if not mem { - mem = allocate(loc.tpe.size) + mem = state.cstate.mem.allocate(loc.tpe.size) state.cstate.globals[loc.name] = mem - ptr = allocate(loc.tpe.tpe.size) + ptr = state.cstate.mem.allocate(loc.tpe.tpe.size) set(mem, loc.tpe, { kind = compiler::ValueKind::POINTER, tpe = loc.tpe, i = ptr !int64 } !compiler::Value) - state.cstate.globals["__eval_tmp::" + to_string(state.cstate.global_counter)] = ptr - state.cstate.global_counter += 1 } else { ptr = get(mem, loc.tpe).i !* } @@ -364,8 +356,8 @@ def eval_InsertValue(insn: &compiler::Insn, state: &State) { to_set = *to_set.values[j] } else if to_set.tpe.kind == typechecking::TypeKind::STATIC_ARRAY { - if typechecking::equals(to_set.tpe.tpe, builtins::char_) and to_set.s { - to_set.s[j] = element.i !char + if typechecking::equals(to_set.tpe.tpe, builtins::char_) { + to_set.s[j] = element.i !char // TODO Can we assume this? Verify somehow } else { to_set = *to_set.values[j] } @@ -488,13 +480,10 @@ def eval_Alloca(insn: &compiler::Insn, state: &State) { let frame = get_stack_frame(state) let ret = insn.value.alloca.ret - let mem = zero_allocate(ret.tpe.size) // TODO: We shouldn't have to initialize this - frame.locals["__eval_tmp::" + to_string(state.temp_counter)] = mem // TODO again use a linear allocator - state.temp_counter += 1 - + let mem = frame.mem.allocate(ret.tpe.size) // TODO: We shouldn't have to initialize this ret.tpe = typechecking::pointer(ret.tpe) let ptr = { kind = compiler::ValueKind::POINTER, tpe = ret.tpe, i = mem !int64 } !compiler::Value - let addr = allocate(ret.tpe.size) + let addr = frame.mem.allocate(ret.tpe.size) frame.locals[ret.name] = addr set(addr, ret.tpe, ptr) } @@ -856,9 +845,10 @@ def ffi_call(args: &[compiler::Value], ret: compiler::Value, parameter_t: &Vecto if ret_tpe.size > size { size = ret_tpe.size } - rvalue = allocate(size) + let frame = get_stack_frame(state) + rvalue = frame.mem.allocate(size) // TODO This will fail for function pointers - get_stack_frame(state).locals[ret.name] = rvalue + frame.locals[ret.name] = rvalue } ffi::ffi_call(ffi_cif, function, rvalue, avalues) @@ -917,7 +907,7 @@ def eval_Call(insn: &compiler::Insn, state: &State) { if fp.is_fp { let ffi_function = { - name = @name, + name = @name.to_array(), function = fp.fp } !symbol::Symbol @@ -956,7 +946,7 @@ def eval_Call(insn: &compiler::Insn, state: &State) { let arg = args[i] let np = function.args[i] let arg_value = get_value(arg, state) - let mem = allocate(arg.tpe.size) + let mem = stack_frame.mem.allocate(arg.tpe.size) let name = np.name + ".value" stack_frame.locals[name] = mem @@ -1341,7 +1331,7 @@ export def eval(cstate: &compiler::State) -> &State { return state } -export def serialize_value(key: &string, module: &toolchain::Module, cstate: &compiler::State) -> &compiler::Global { +export def serialize_value(key: Str, module: &toolchain::Module, cstate: &compiler::State) -> &compiler::Global { cstate.current_block = module.code let mem = cstate.globals.get_or_default(key, null) diff --git a/src/lexer.pr b/src/lexer.pr index d757719..f5fae13 100644 --- a/src/lexer.pr +++ b/src/lexer.pr @@ -112,7 +112,7 @@ export type TokenType = enum { } export type TokenValue = struct #union { - str: &string + str: StringSlice ch: char i: uint64 f: double @@ -149,11 +149,7 @@ export def construct(copy: *Token, this: *Token) { this.tpe == TokenType::ERROR or this.tpe == TokenType::PRAGMA or this.tpe == TokenType::STRING { - if this.value.str { - let str = allocate_ref(char, this.value.str.size) - memcopy(this.value.str.value, str.value, this.value.str.size) - copy.value.str = str - } + copy.value.str = this.value.str } else { copy.value = this.value } @@ -175,7 +171,7 @@ export def destruct(list: *TokenList) { } type Keyword = struct { token_type: TokenType - str: &string + str: StringSlice } let KEYWORDS = [ @@ -257,7 +253,7 @@ def simple_token(tpe: TokenType, line: int, column: int, end_line: int, end_colu } !Token } -def error_token(s: &string, line: int, column: int, end_line: int, end_column: int) -> Token { +def error_token(s: String, line: int, column: int, end_line: int, end_column: int) -> Token { var tok = { TokenType::ERROR, line, column, end_line, end_column } !Token @@ -306,7 +302,7 @@ def parse_simple_escape_sequence(escape_char: char) -> int { } // TODO Use a state instead of passing all of these parameters one by one -def next_char(s: &string, i: *int, line: *int, column: *int) -> char { +def next_char(s: Str, i: *int, line: *int, column: *int) -> char { @i += 1 if @i >= length(s) { return 0x1A !char @@ -317,18 +313,18 @@ def next_char(s: &string, i: *int, line: *int, column: *int) -> char { return c } -def peek_char(s: &string, i: *int, n: int) -> char { +def peek_char(s: Str, i: *int, n: int) -> char { if @i + n >= length(s) { return 0x1A !char } return s[@i + n] } -def parse_string(s: &string, triple_quoted: bool, i: *int, line: *int, column: *int) -> Token { +def parse_string(s: Str, triple_quoted: bool, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column - var res: &string = "" + var res: StringBuffer = "" var end_of_string = false while @i < length(s) { let c = next_char(s, i, line, column) @@ -402,11 +398,11 @@ def parse_string(s: &string, triple_quoted: bool, i: *int, line: *int, column: * next_char(s, i, line, column) let tok = simple_token(TokenType::STRING, start_line, start_column, @line, @column) - tok.value.str = res + tok.value.str = to_slice(res.to_str()) return tok } -def parse_char(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_char(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -448,7 +444,7 @@ def parse_char(s: &string, i: *int, line: *int, column: *int) -> Token { // TODO Refactor the following three functions into one -def parse_hex_int(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_hex_int(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -472,7 +468,7 @@ def parse_hex_int(s: &string, i: *int, line: *int, column: *int) -> Token { return tok } -def parse_oct_int(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_oct_int(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -496,7 +492,7 @@ def parse_oct_int(s: &string, i: *int, line: *int, column: *int) -> Token { return tok } -def parse_bin_int(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_bin_int(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -520,7 +516,7 @@ def parse_bin_int(s: &string, i: *int, line: *int, column: *int) -> Token { return tok } -def parse_int(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_int(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -554,7 +550,7 @@ def parse_int(s: &string, i: *int, line: *int, column: *int) -> Token { } // TODO This gives the "wrong" bits for 10.555 -def parse_float(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_float(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -604,7 +600,7 @@ def parse_float(s: &string, i: *int, line: *int, column: *int) -> Token { return tok } -def parse_number(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_number(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -634,76 +630,66 @@ def parse_number(s: &string, i: *int, line: *int, column: *int) -> Token { return parse_int(s, i, line, column) } -def parse_identifier(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_identifier(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column var c = peek_char(s, i, 0) - var str: &string = "" + var start = @i while is_alphanumeric(c) { - str += c c = next_char(s, i, line, column) } - for var i in 0..KEYWORDS.size { - let keyword = KEYWORDS[i] - if keyword.str == str { + for var j in 0..KEYWORDS.size { + let keyword = KEYWORDS[j] + if keyword.str == s.slice(start, @i) { return simple_token(keyword.token_type, start_line, start_column, @line, @column) } } let tok = simple_token(TokenType::IDENTIFIER, start_line, start_column, @line, @column) - tok.value.str = str + tok.value.str = s.slice(start, @i) return tok } -def parse_eol_comment(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_eol_comment(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column - - var str: &string = "" + let start = @i next_char(s, i, line, column) next_char(s, i, line, column) - str += "//" var c = peek_char(s, i, 0) while c != '\n' and c != 0x1A { - str += c c = next_char(s, i, line, column) } let tok = simple_token(TokenType::COMMENT, start_line, start_column, @line, @column) - tok.value.str = str + tok.value.str = s.slice(start, @i) return tok } -def parse_comment(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_comment(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column - - var str: &string = "" + let start = @i next_char(s, i, line, column) next_char(s, i, line, column) - str += "/*" var depth = 1 var c = peek_char(s, i, 0) while depth > 0 and c != 0x1A { - str += c - if c == '/' { if peek_char(s, i, 1) == '*' { depth += 1 - str += '*' next_char(s, i, line, column) } } else if c == '*' { if peek_char(s, i, 1) == '/' { depth -= 1 - str += '/' next_char(s, i, line, column) } } else if c == '\n' { @@ -714,27 +700,25 @@ def parse_comment(s: &string, i: *int, line: *int, column: *int) -> Token { } let tok = simple_token(TokenType::COMMENT, start_line, start_column, @line, @column) - tok.value.str = str + tok.value.str = s.slice(start, @i) return tok } -def parse_pragma(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_pragma(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column - - var str: &string = "" + let start = @i var c = peek_char(s, i, 0) while c == '#' or is_text(c) or is_alphanumeric(c) { - str += c c = next_char(s, i, line, column) } let tok = simple_token(TokenType::PRAGMA, start_line, start_column, @line, @column) - tok.value.str = str + tok.value.str = s.slice(start, @i) return tok } -def parse_symbol(s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_symbol(s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -835,7 +819,7 @@ def is_whitespace(c: char) -> bool { return c == ' ' or c == '\t' or c == '\r' } -def parse_whitespace(depth: int, s: &string, i: *int, line: *int, column: *int) -> Token { +def parse_whitespace(depth: int, s: Str, i: *int, line: *int, column: *int) -> Token { let start_line = @line let start_column = @column @@ -853,7 +837,7 @@ def parse_whitespace(depth: int, s: &string, i: *int, line: *int, column: *int) export var time_spent: int64 = 0 -export def lex(s: &string, line: int = 0, column: int = 0, end_line: int = MAX_INT32, end_column: int = MAX_INT32) -> *TokenList { +export def lex(s: Str, line: int = 0, column: int = 0, end_line: int = MAX_INT32, end_column: int = MAX_INT32) -> *TokenList { let start = util::millis() var token_list = zero_allocate(TokenList) diff --git a/src/main.pr b/src/main.pr index de69172..52d6bc9 100644 --- a/src/main.pr +++ b/src/main.pr @@ -107,7 +107,7 @@ if time_report and dependency_graph { exit(1) } -def push_all_strings(value: &getopt::Value, vec: &Vector(&string)) { +def push_all_strings(value: &getopt::Value, vec: &Vector(Str)) { while value { vec.push(value.str) value = value.next diff --git a/src/md5.pr b/src/md5.pr index 09a49ae..ec91316 100644 --- a/src/md5.pr +++ b/src/md5.pr @@ -250,7 +250,7 @@ def to_int32(bytes: *uint8) -> uint32 { (bytes[3] !uint32 << 24 !uint32) } -export def md5(initial_msg: &string) -> [16; uint8] { +export def md5(initial_msg: Str) -> [16; uint8] { let initial_len = length(initial_msg) !uint32 @@ -282,7 +282,7 @@ export def md5(initial_msg: &string) -> [16; uint8] { } msg = allocate(new_len + 8) !*uint8 - memcopy(initial_msg.value, msg, initial_len) + memcopy(initial_msg.to_array().value, msg, initial_len) msg[initial_len] = 0x80 // append the "1" bit most significant bit is "first" diff --git a/src/parser.pr b/src/parser.pr index 7ab2ba2..950bb39 100644 --- a/src/parser.pr +++ b/src/parser.pr @@ -305,7 +305,7 @@ export type NodeIfExpr = struct { } export type NodeIdentifier = struct { - path: &Vector(&string) + path: &Vector(String) args: &Vector(&Node) // Vector of typechecking::NamedParameter types: &Vector(typechecking::NamedParameter) @@ -373,21 +373,21 @@ export type NodeValue = struct #union { body: &Vector(&Node) expr: &Node i: uint64 - str: &string + str: String f: double } export type SourceLoc = struct { - filename: &string - display_name: &string - module: &string + filename: Str + display_name: Str + module: Str line: int column: int end_line: int end_column: int } -export def lines(loc: SourceLoc) -> &[&string] { +export def lines(loc: SourceLoc) -> &[Str] { let module = toolchain::modules.get_or_default(loc.filename, null) return module.lines if module else null } @@ -471,7 +471,7 @@ def hash(nodes: &Vector(&Node)) -> uint64 { return h } -def hash(path: &Vector(&string)) -> uint64 { +def hash(path: &Vector(String)) -> uint64 { if not path { return 0 } var h: uint64 = 17 for var i in 0..path.length { @@ -1167,18 +1167,18 @@ export def find(node: &Node, line: int, column: int) -> &Node { } export type ParseState = struct { - filename: &string - display_name: &string - module: &string + filename: Str + display_name: Str + module: Str has_error: bool has_yield: bool - lines: &[&string] + lines: &[Str] tokens: *lexer::TokenList last_token: *lexer::TokenList } -export def make_identifier(s: &string...) -> &Node { - let vec = vector::make(type &string) +export def make_identifier(s: String...) -> &Node { + let vec = vector::make(String) for var i in 0..s.size { vec.push(s[i]) } @@ -1195,7 +1195,7 @@ export def make_identifier(s: &string...) -> &Node { return node } -export def identifier_from_str(s: &string) -> &Node { +export def identifier_from_str(s: Str) -> &Node { return make_identifier(@util::split(s, "::")) } @@ -1357,9 +1357,9 @@ export def deep_copy_node(node: &Node, clear_svalue: bool = true) -> &Node { return copy } -export def identifier_to_str(node: &Node, types: bool = true) -> &string { +export def identifier_to_str(node: &Node, types: bool = true) -> Str { assert node.kind == NodeKind::IDENTIFIER - var res: &string = "" + var res: StringBuffer = "" let len = vector::length(node.value.identifier.path) for var i in 0..len { res += node.value.identifier.path[i] @@ -1467,7 +1467,7 @@ def back(state: &ParseState) { state.last_token = null } -def expect(state: &ParseState, tpe: lexer::TokenType, msg: &string) -> lexer::Token { +def expect(state: &ParseState, tpe: lexer::TokenType, msg: Str) -> lexer::Token { let token = pop(state) if token.tpe != tpe { errors::errort(token, state, msg) @@ -1515,7 +1515,7 @@ def parse_identifier(parse_state: &ParseState) -> &Node { token = pop(parse_state) } - let path = vector::make(type &string) + let path = vector::make(String) loop { path.push(token.value.str) token = peek(parse_state) @@ -2878,9 +2878,9 @@ def expect_expression_no_assign(parse_state: &ParseState) -> &Node { return node } -def make_operator_ident(name: &string, token: Token, parse_state: &ParseState) -> &Node { +def make_operator_ident(name: String, token: Token, parse_state: &ParseState) -> &Node { let ident = make_node(NodeKind::IDENTIFIER, token.line, token.column, parse_state) - let path = vector::make(type &string) + let path = vector::make(String) path.push(name) ident.value.identifier.path = path ident._hash = combine_hashes(ident.kind !uint64, hash(path)) @@ -4008,8 +4008,8 @@ def parse_block(parse_state: &ParseState, vec: &Vector(&Node)) { } export def make_state( - filename: &string, display_name: &string, module: &string, - lines: &[&string], tokens: *lexer::TokenList) -> &ParseState { + filename: Str, display_name: String, module: String, + lines: &[Str], tokens: *lexer::TokenList) -> &ParseState { return { filename = filename, @@ -4022,7 +4022,7 @@ export def make_state( export var time_spent: int64 = 0 -export def parse(list: *lexer::TokenList, lines: &[&string], filename: &string, module: &string, display_name: &string = null) -> &Node { +export def parse(list: *lexer::TokenList, lines: &[Str], filename: String, module: String, display_name: String = null) -> &Node { debug::trace("Parsing ", module) let start = util::millis() diff --git a/src/repl.pr b/src/repl.pr index a3672a9..914a8a5 100644 --- a/src/repl.pr +++ b/src/repl.pr @@ -18,14 +18,14 @@ import errors } def read_input { - var history = vector::make(type &string) + var history = vector::make(Str) var history_item: size_t = 0 history.push("") let isatty = util::is_a_tty(std::stdin()) loop { - var lines = vector::make(type &string) + var lines = vector::make(Str) lines.push("") var line = 0 @@ -67,7 +67,7 @@ def read_input { } else if c == 9 { // TODO Implement tabs properly print(" ") - lines[line].insert(column, " ") + lines[line] = lines[line].insert(column, " ") column += 4 } else if c == 12 { // ctrl + l @@ -109,10 +109,10 @@ def read_input { column -= 1 lines[line].remove(column) - if column < lines[line].size - 1 { + if column < lines[line].length { print("\x1B7") - for var i in column..(lines[line].size - 1) { - print(lines[line].value[i]) + for var i in column..(lines[line].length) { + print(lines[line][i]) } print(" \x1B8") } @@ -127,13 +127,13 @@ def read_input { c = cstd::getchar() !char if c == 126 { // del - if column < lines[line].size - 1 { - for var i in 0..util::bytes_in_glyph(lines[line].value[column]) { + if column < lines[line].length { + for var i in 0..util::bytes_in_glyph(lines[line][column]) { lines[line].remove(column) } print("\x1B7") - for var i in column..(lines[line].size - 1) { - print(lines[line].value[i]) + for var i in column..(lines[line].length) { + print(lines[line][i]) } print(" \x1B8") } else { @@ -152,7 +152,7 @@ def read_input { print("\x1B[D") } - while lines[line].value[column - 1] & 0b11000000 == 0b10000000 { + while lines[line][column - 1] & 0b11000000 == 0b10000000 { column -= 1 } column -= 1 @@ -162,8 +162,8 @@ def read_input { } } else if c == 67 { // right - if column < lines[line].size - 1 { - column += util::bytes_in_glyph(lines[line].value[column]) + if column < lines[line].length { + column += util::bytes_in_glyph(lines[line][column]) let ucolumn = util::count_glyphs(lines[line], column) let width = util::get_terminal_size().col if (ucolumn + 4) % width == 0 { @@ -188,7 +188,7 @@ def read_input { lines[line] = history[history_item] print(lines[line]) - column = (lines[line].size - 1) !int + column = (lines[line].length) !int } } else if c == 66 { // down @@ -204,7 +204,7 @@ def read_input { lines[line] = history[history_item] print(lines[line]) - column = (lines[line].size - 1) !int + column = (lines[line].length) !int } } } @@ -213,7 +213,7 @@ def read_input { for var i in 0..count { if i > 0 { c = cstd::getchar() !char } - lines[line].insert(column, c) + lines[line] = lines[line].insert(column, c) column += 1 if isatty { print(c) } } @@ -224,10 +224,10 @@ def read_input { if (ucolumn + 4) % width == 0 { print("\x1BE") } - if column < lines[line].size - 1 { + if column < lines[line].length { print("\x1B7") - for var i in column..(lines[line].size - 1) { - print(lines[line].value[i]) + for var i in column..(lines[line].length) { + print(lines[line][i]) } print(" \x1B8") } @@ -241,7 +241,7 @@ def read_input { var in_escape = false let str = lines[line] - for var i in 0..str.size { + for var i in 0..str.length() { let c = str[i] if c == '\\' and in_string { in_escape = true @@ -286,7 +286,7 @@ def read_input { cont = true } - var res: &string = "" + var res: StringBuffer = "" for var i in 0..=line { res += lines[i] + '\n' } @@ -326,7 +326,7 @@ var _args: [string] = args var initialized = false var stored_nodes = vector::make(type &parser::Node) // We need to keep references to all nodes around -def execute(source: &string) { +def execute(source: Str) { #if not defined WIN32 { linux::tcsetattr(0, 1 /* TCSADRAIN */, *default_term) defer linux::tcsetattr(0, 1 /* TCSADRAIN */, *raw_term) diff --git a/src/scope.pr b/src/scope.pr index 38ad2c9..b499893 100644 --- a/src/scope.pr +++ b/src/scope.pr @@ -13,8 +13,8 @@ import consteval // This is used to uniquely identify a value export type Ident = struct { - name: &string - signature: &string + name: Str + signature: Str _hash: uint64 module: weak_ref(toolchain::Module) } @@ -24,7 +24,7 @@ export type ImportedModule = struct { alias: &parser::Node } -export def make_ident(name: &string, module: &toolchain::Module = null, hash: uint64 = 0, signature: &string = null) -> Ident { +export def make_ident(name: Str, module: &toolchain::Module = null, hash: uint64 = 0, signature: String = null) -> Ident { if not signature { signature = name } return { name = name, @@ -76,10 +76,10 @@ export type Value = struct { share: parser::ShareMarker modifier: parser::VarDecl // Name used by the source code - name: &string + name: Str // Name used by the assembly, might be suffixed with a number // in case of shadowed variables - assembly_name: &string + assembly_name: Str tpe: &typechecking::Type value: &compiler::Value _scope: &Scope @@ -421,7 +421,7 @@ def find_functions(value: &Value, resolved: &SMap(&Vector(&typechecking::Type)), } } -def find_functions(scope: &Scope, name: &string, ret: &Vector(&Value), params: &Vector(&typechecking::Type) = null, check_export: bool = false) { +def find_functions(scope: &Scope, name: Str, ret: &Vector(&Value), params: &Vector(&typechecking::Type) = null, check_export: bool = false) { for var key in @scope.fields.keys() { var value = scope.fields[key] if key == name and value.modifier == parser::VarDecl::CONST and @@ -457,7 +457,7 @@ def find_functions(scope: &Scope, name: &string, ret: &Vector(&Value), params: & } } -export def find_functions(scope: &Scope, name: &string, params: &Vector(&typechecking::Type) = null) -> &Vector(&Value) { +export def find_functions(scope: &Scope, name: Str, params: &Vector(&typechecking::Type) = null) -> &Vector(&Value) { let ret = vector::make(type &Value) find_functions(scope, name, ret, params) return ret @@ -648,7 +648,7 @@ def find_function(scope: &Scope, node: &parser::Node, v: &Value, parameter_t: &V return found != null, found } -export def find_implicit_function(scope: &Scope, parameter_t: &Vector(typechecking::NamedParameter), ret: &typechecking::Type) -> &Value { +export def find_implicit_function(scope: &Scope, parameter_t: &Vector(typechecking::NamedParameter), ret: &typechecking::Type, force_compile: bool = true) -> &Value { if not scope { return null } assert parameter_t.length == 1 @@ -667,8 +667,7 @@ export def find_implicit_function(scope: &Scope, parameter_t: &Vector(typechecki v.tpe = typechecking::lookup_parameters(v.node, v.state) } - let retc = typechecking::convert_type_score(v.tpe.return_t[0], r, scope.module, impl = false) - if retc != 0 { continue } + if not typechecking::equals(v.tpe.return_t[0], r) { continue } let s = typechecking::convert_type_score(v.tpe.parameter_t[0].tpe, parameter_t[0].tpe, scope.module, impl = false) if s == @score { d = true @@ -715,7 +714,7 @@ export def find_implicit_function(scope: &Scope, parameter_t: &Vector(typechecki value = find_implicit_function(scope.parent, parameter_t, ret) } - if value and value.phase == Phase::DEFINED and value.state and value.node { + if value and value.phase == Phase::DEFINED and value.state and value.node and force_compile { // TODO Factor this out if typechecking::is_polymorph(value.tpe) { typechecking::walk_Def_with_type_argument(value.node, parameter_t, value.state) @@ -1013,7 +1012,7 @@ export def get_function_check( assert((@id).kind == parser::NodeKind::IDENTIFIER) if vector::length((@id).value.identifier.path) == 1 { - let name = @((@id).value.identifier.path[0]) + let name = (@id).value.identifier.path[0] var score = std::MAX_INT32 !int var code = false @@ -1148,7 +1147,7 @@ export def get( for var i in 0..scope.re_exports.length { let re_export = scope.re_exports[i] if pattern_matches(id, re_export.pattern) { - var value2 = get(re_export.module.scope, id, check_export = true, re_exports = false) + var value2 = get(re_export.module.scope, id, force_compile = force_compile, check_export = true, re_exports = false) if value2 and value2.share !int & parser::ShareMarker::EXPORT !int { if value and value !* != value2 !* { if not dry_run { @@ -1165,7 +1164,7 @@ export def get( } if vector::length((@id).value.identifier.path) == 1 { - let name = @((@id).value.identifier.path[0]) + let name = (@id).value.identifier.path[0] if name == "_" { return get_underscore(scope) } @@ -1296,7 +1295,7 @@ def create_path(scope: &Scope, node: &parser::Node) -> &Scope { let scope_v = scope.fields.get_or_default(ident, null) if not scope_v { let n = parser::copy_node(node) - let vec = vector::make(type &string) + let vec = vector::make(String) vec.push(ident) (@n).value.identifier.path = vec let scope2 = enter_scope(scope) @@ -1316,10 +1315,10 @@ def create_path(scope: &Scope, node: &parser::Node) -> &Scope { // Returns the last element in a path, eg Element for path::Element // TODO Move this elsewhere -export def last_path_element(node: &parser::Node) -> string { - assert((@node).kind == parser::NodeKind::IDENTIFIER) - let length = vector::length((@node).value.identifier.path) - return @((@node).value.identifier.path[length - 1]) +export def last_path_element(node: &parser::Node) -> String { + assert(node.kind == parser::NodeKind::IDENTIFIER) + let length = vector::length(node.value.identifier.path) + return node.value.identifier.path[length - 1] } // This overwrites value with the changes from other, @@ -1436,7 +1435,7 @@ export def create_function( return create_function(scope, name_node, share, tpe, Phase::COMPILED, null, null, impl) } -def append_scope_count(scope: &Scope, name: &string) -> &string { +def append_scope_count(scope: &Scope, name: Str) -> Str { let scope_count = get_scope_count(scope) return name + '.' + scope_count } diff --git a/src/serialize.pr b/src/serialize.pr index 15a51bc..8c11db5 100644 --- a/src/serialize.pr +++ b/src/serialize.pr @@ -97,13 +97,13 @@ def write_module_reference(fp: File, tpe: &typechecking::Type, state: &Serialize fp.write(*TYPE_MOD) let defmodule = tpe.defmodule if tpe.defmodule else tpe.module - fp.write_str(defmodule.module if defmodule else null) + fp.write_str(defmodule.module !String if defmodule else null) if defmodule !* == builtins::builtins_module !* { fp.write_str("builtins") } else if defmodule !* == toolchain::runtime_ { fp.write_str("runtime") } else { - assert defmodule.filename != null + assert defmodule.filename fp.write_str(defmodule.filename) } fp.write_str(tpe.name) @@ -149,8 +149,8 @@ def serialize_type(fp: File, tpe: &typechecking::Type, state: &Serialize) { fp.write(*hash) fp.write_str(tpe.name) fp.write_str(tpe.type_name) - fp.write_str(tpe.defmodule.module if tpe.defmodule else null) - fp.write_str(tpe.module.module if tpe.module else null) + fp.write_str(tpe.defmodule.module !String if tpe.defmodule else null) + fp.write_str(tpe.module.module !String if tpe.module else null) fp.write(*tpe.tc_incomplete) if tpe.tc_args { @@ -626,8 +626,8 @@ def deserialize_function(deserialize: &Deserialize, fp: File) { var imported: bool var impl: bool var polymorph: bool - var name: &string - var type_name: &string + var name: Str + var type_name: Str fp.read(*hash) fp.read(*share) @@ -807,7 +807,7 @@ def deserialize_value(deserialize: &Deserialize, fp: File) -> &compiler::Value { value.name = fp.read_str() fp.read(*value.i) fp.read(*value.f) - value.s = fp.read_str() + value.s = fp.read_str().to_array() value.value_tpe = deserialize_type(deserialize, fp) var sz: uint64 fp.read(*sz) @@ -823,7 +823,7 @@ def deserialize_value(deserialize: &Deserialize, fp: File) -> &compiler::Value { export def serialize(module: &toolchain::Module) { let cache_file = toolchain::outfolder + "/" + module.file + ".prc" - let fp = open(@cache_file, "wb") + let fp = open(cache_file, "wb") defer close(fp) fp.write(MAGIC) @@ -862,7 +862,7 @@ export def serialize(module: &toolchain::Module) { for var i in 0..re_exports.length { let re_export = re_exports[i] fp.write_str(re_export.module.module) - fp.write_str(parser::identifier_to_str(re_export.pattern, types = false) if re_export.pattern else null) + fp.write_str(parser::identifier_to_str(re_export.pattern, types = false) !String if re_export.pattern else null) if re_export.pattern and re_export.pattern.value.identifier.types { let types = re_export.pattern.value.identifier.types fp.write(*types.length) @@ -965,12 +965,12 @@ export def serialize(module: &toolchain::Module) { fp.write(*ident._hash) fp.write_str(ident.name) fp.write_str(ident.signature) - fp.write_str(ident.module.module if ident.module else null) + fp.write_str(ident.module.module !String if ident.module else null) } } type FunctionEntry = struct { - name: &string + name: Str hash: uint64 node: &parser::Node state: &typechecking::State @@ -981,7 +981,7 @@ type FunctionEntry = struct { } type VariableEntry = struct { - name: &string + name: Str hash: uint64 modifier: parser::VarDecl extern: bool @@ -992,7 +992,7 @@ type VariableEntry = struct { } type TypeEntry = struct { - name: &string + name: Str share: parser::ShareMarker hash: uint64 tpe: &typechecking::Type @@ -1032,11 +1032,11 @@ export def resolver_pass(module: &toolchain::Module) { module.deserialize = deserialize - let fp = open(@cache_file, "rb") + let fp = open(cache_file, "rb") if not fp { module.is_dirty = true; return } defer close(fp) - let source_fp = open(@module.filename, "rb") + let source_fp = open(module.filename, "rb") defer close(source_fp) if modified_time(source_fp) > modified_time(fp) { diff --git a/src/server/cache.pr b/src/server/cache.pr index d06c653..ec6b04a 100644 --- a/src/server/cache.pr +++ b/src/server/cache.pr @@ -83,7 +83,7 @@ export def error_handler(diagnostic: errors::Diagnostic) { } } -export def offset_errors(path: &string, start: server::U8Position, end: server::U8Position, text: &string) { +export def offset_errors(path: Str, start: server::U8Position, end: server::U8Position, text: Str) { if not diagnostics.contains(path) { return } let mdiags = diagnostics[path] @@ -443,11 +443,11 @@ def insert_at_position(node: &parser::Node, n: &parser::Node) { } } -export def recompile(path: &string) { +export def recompile(path: Str) { recompile(path, null) } -export def recompile(path: &string, changes: &[server::TextDocumentChangeEvent]) { +export def recompile(path: Str, changes: &[server::TextDocumentChangeEvent]) { var module = toolchain::find_module_by_path(path) let mdiags = diagnostics.get_or_default(path, null) @@ -631,7 +631,7 @@ export def recompile(path: &string, changes: &[server::TextDocumentChangeEvent]) publish_diagnostics(module) } -export def check_imports(path: &string) -> bool { +export def check_imports(path: Str) -> bool { var did_change = false let keys = toolchain::modules.keys() for var i in 0..keys.size { diff --git a/src/server/document.pr b/src/server/document.pr index a4da1b8..4114010 100644 --- a/src/server/document.pr +++ b/src/server/document.pr @@ -13,7 +13,7 @@ export def setup_file_loader { export let open_documents = set::make() -export def load_file(filename: &string) -> &string { +export def load_file(filename: String) -> String { let module = toolchain::find_module_by_path(filename) if module { return module.text @@ -22,18 +22,18 @@ export def load_file(filename: &string) -> &string { return text } -export def open_document(uri: server::DocumentUri, text: &string) { +export def open_document(uri: server::DocumentUri, text: Str) { open_documents.add(uri) let path = uri_to_path(uri) cache::recompile(path) } -export def save_document(uri: server::DocumentUri, text: &string) { +export def save_document(uri: server::DocumentUri, text: Str) { open_document(uri, text) } // TODO This is very inefficient, change the lexer to accept split lines as well instead -export def find_offset(text: &string, pos: server::U16Position) -> size_t { +export def find_offset(text: Str, pos: server::U16Position) -> size_t { var u8_offset = 0 var line = 0 var u16_column = 0 @@ -74,7 +74,7 @@ export def find_offset(text: &string, pos: server::U16Position) -> size_t { return u8_offset } -export def u16_pos_to_u8(filename: &string, pos: server::U16Position) -> server::U8Position { +export def u16_pos_to_u8(filename: Str, pos: server::U16Position) -> server::U8Position { let module = toolchain::find_module_by_path(filename) if not module or pos.line < 0 or pos.character < 0 { return { pos.line, pos.character } !server::U8Position @@ -104,7 +104,7 @@ export def u16_pos_to_u8(filename: &string, pos: server::U16Position) -> server: return { pos.line, u8_column } !server::U8Position } -export def u8_pos_to_u16(filename: &string, pos: server::U8Position) -> server::U16Position { +export def u8_pos_to_u16(filename: Str, pos: server::U8Position) -> server::U16Position { let module = toolchain::find_module_by_path(filename) if not module or pos.line < 0 or pos.character < 0 { return { pos.line, pos.character } !server::U16Position @@ -134,7 +134,7 @@ export def u8_pos_to_u16(filename: &string, pos: server::U8Position) -> server:: return { pos.line, u16_column } !server::U16Position } -def count_new_lines(text: &string) -> int { +def count_new_lines(text: Str) -> int { var new_lines = 0 for var i in 0..text.length { if text[i] == '\n' { @@ -144,7 +144,7 @@ def count_new_lines(text: &string) -> int { return new_lines } -def get_last_line_length(text: &string) -> size_t { +def get_last_line_length(text: Str) -> size_t { let last_nl = last_index_of(text, "\n") if last_nl < 0 { return text.length } else { @@ -159,7 +159,8 @@ export def change_document(uri: server::DocumentUri, changes: &[server::TextDocu let recompile_changes = vector::make(server::TextDocumentChangeEvent) - for var change in @changes { + for var i in 0..changes.size { + let change = changes[i] if change.range { // TODO this is ugly, allow optionals instead let range = json::deserialize(change.range, server::Range).get() @@ -167,15 +168,15 @@ export def change_document(uri: server::DocumentUri, changes: &[server::TextDocu let end_offset = find_offset(module.text, range.end) if start_offset != end_offset { - module.text.remove( + module.text = module.text.remove( min(text.length() - 1, start_offset) !size_t, - end_offset - 1 + end_offset - start_offset ) } if start_offset < text.length() { - module.text.insert(start_offset, change.text) + module.text = module.text.insert(start_offset, change.text) } else { - module.text += change.text + module.text = module.text + change.text } let end = u16_pos_to_u8(path, range.end) diff --git a/src/server/server.pr b/src/server/server.pr index 7f1a914..61b6494 100644 --- a/src/server/server.pr +++ b/src/server/server.pr @@ -29,16 +29,16 @@ type MessageType = enum { Log = 4 } -export type DocumentUri = &string +export type DocumentUri = String -export def uri_to_path(uri: DocumentUri) -> &string { +export def uri_to_path(uri: DocumentUri) -> Str { if uri.starts_with("file://") { return uri.substring(7) } abort("Unsupported protocol in uri: " + uri) } -export def path_to_uri(path: &string) -> DocumentUri { +export def path_to_uri(path: Str) -> DocumentUri { return "file://" + path } @@ -69,14 +69,14 @@ export type U8Position = struct { type WorkspaceFolder = struct { uri: DocumentUri - name: &string + name: Str } type TextDocumentItem = struct { uri: DocumentUri - languageId: &string + languageId: Str version: int - text: &string + text: Str } type DidOpenTextDocumentParams = struct { @@ -95,7 +95,7 @@ type VersionedTextDocumentIdentifier = struct { export type TextDocumentContentChangeEvent = struct { range: &Json - text: &string + text: Str } export type TextDocumentChangeEvent = struct { @@ -115,7 +115,7 @@ def did_change(id: int, params: DidChangeTextDocumentParams) { export type DidSaveTextDocumentParams = struct { textDocument: TextDocumentIdentifier - text: &string + text: Str } def did_save(id: int, params: DidSaveTextDocumentParams) { @@ -131,8 +131,8 @@ const PlainText = "plaintext" const Markdown = "markdown" type MarkupContent = struct { - kind: &string - value: &string + kind: Str + value: Str } type Hover = struct { @@ -145,7 +145,7 @@ def hover(id: int, params: HoverParams) { let svalue = find_value_at(module, params.position) if not svalue or not svalue.tpe { send_reply(id, null); return } - var res: &string + var res: Str if svalue.tpe.kind == typechecking::TypeKind::FUNCTION { res = "(function) " + svalue.name + ": " + debug::type_to_str(svalue.tpe) } else if svalue.tpe.kind == typechecking::TypeKind::NAMESPACE { @@ -252,21 +252,21 @@ type CompletionItemTag = enum { } type CompletionItemLabelDetails = struct { - detail: &string - description: &string + detail: Str + description: Str } type CompletionItem = struct { - _label: &string + _label: Str labelDetails: CompletionItemLabelDetails kind: int tags: &[int] - detail: &string - sortText: &string + detail: Str + sortText: Str } -def params_to_string(tpe: &typechecking::Type) -> &string { - var name: &string = "(" +def params_to_string(tpe: &typechecking::Type) -> Str { + var name: StringBuffer = "(" for var i in 0..tpe.parameter_t.length { let param = tpe.parameter_t[i] name += param.name @@ -293,8 +293,8 @@ def push_completion_value(value: &scope::Value, module: &toolchain::Module, comp if value.is_internal { return } var kind = CompletionItemKind::Variable - var detail: &string = null - var function_type: &string = null + var detail: Str + var function_type: Str if value.modifier == parser::VarDecl::TYPE { let value_tpe = value.value.value_tpe @@ -321,7 +321,7 @@ def push_completion_value(value: &scope::Value, module: &toolchain::Module, comp detail = ": " + debug::type_to_str(value.tpe) } - var smod: &string + var smod: Str if value.ident.module and value.ident.module != module { smod = value.ident.module.module } @@ -329,8 +329,8 @@ def push_completion_value(value: &scope::Value, module: &toolchain::Module, comp completions.push({ _label = value.name, labelDetails = { - detail = detail if detail else "" !&string, - description = smod if smod else "" !&string + detail = detail, + description = smod } !CompletionItemLabelDetails, kind = kind !int, } !CompletionItem) @@ -385,7 +385,7 @@ def complete(id: int, params: CompletionParams) { var scpe = node.scope var check_export = false if node.value.identifier.path.length > 1 { - let prefix = vector::make(type &string) + let prefix = vector::make(String) for var i in 0..(node.value.identifier.path.length - 1) { prefix.push(node.value.identifier.path[i]) } @@ -440,7 +440,7 @@ export type DiagnosticSeverity = enum { export type Diagnostic = struct { range: Range severity: int - message: &string + message: Str } export type PublishDiagnosticsParams = struct { @@ -460,19 +460,19 @@ type SignatureHelpTriggerKind = enum { type SignatureHelpContext = struct { triggerKind: int - triggerCharacter: &string + triggerCharacter: Str isRetrigger: bool activeSignatureHelp: &Json // TODO Allow optionals } type ParameterInformation = struct { _label: &[uint] - documentation: &string + documentation: Str } type SignatureInformation = struct { - _label: &string - documentation: &string + _label: Str + documentation: Str parameters: &[ParameterInformation] } @@ -564,7 +564,7 @@ def signature_help(id: int, params: SignatureHelpParams) { send_reply(id, null); return } - var name: &string + var name: Str if vector::length(left.value.identifier.path) > 1 { // TODO send_reply(id, null); return @@ -649,8 +649,8 @@ type SymbolTag = enum { } type DocumentSymbol = struct { - name: &string - //detail: &string + name: Str + //detail: Str kind: int // TODO SymbolKind //tags: &[SymbolTag] deprecated: bool @@ -659,14 +659,14 @@ type DocumentSymbol = struct { children: &[DocumentSymbol] } -def source_loc_to_range(path: &string, loc: parser::SourceLoc) -> Range { +def source_loc_to_range(path: Str, loc: parser::SourceLoc) -> Range { return { start = document::u8_pos_to_u16(path, { loc.line, loc.column } !U8Position), end = document::u8_pos_to_u16(path, { loc.end_line, loc.end_column } !U8Position) } !Range } -def type_children(path: &string, node: &parser::Node) -> &Vector(DocumentSymbol) { +def type_children(path: Str, node: &parser::Node) -> &Vector(DocumentSymbol) { let children = vector::make(DocumentSymbol) if node.kind == parser::NodeKind::STRUCT_T { for var i in 0..node.value.body.length { @@ -749,7 +749,7 @@ def document_symbol(id: int, params: DocumentSymbolParams) { if not node.value.def_.name or not node.tpe { continue } let tpe = node.tpe - var name: &string = parser::identifier_to_str(node.value.def_.name) + "(" + var name: StringBuffer = parser::identifier_to_str(node.value.def_.name) + "(" for var i in 0..tpe.parameter_t.length { let param = tpe.parameter_t[i] name += debug::type_to_str(param.tpe) @@ -805,15 +805,15 @@ def did_change_watched_files(id: int, params: DidChangeWatchedFilesParams) { type InitializeParams = struct { processId: int clientInfo: struct { - name: &string - version: &string + name: Str + version: Str } - locale: &string - rootPath: &string + locale: Str + rootPath: Str rootUri: DocumentUri initializationOptions: &Json capabilities: &Json - trace: &string + trace: Str workspaceFolders: &[WorkspaceFolder] } @@ -890,22 +890,22 @@ def initialized { send_request("client/registerCapability", obj, reply = on_register) } -type Header = &Vector(&string) +type Header = &Vector(String) -def get(header: Header, key: &string) -> &string { +def get(header: Header, key: Str) -> Str { for var i in 0..header.length { let entry = header[i] if entry.starts_with(key + ": ") { return entry.substring(entry.index_of(": ") + 2) } } - return null + return {} !Str } def read_header -> Header { - let header = vector::make(type &string) + let header = vector::make(String) loop { - var s: &string = "" + var s: StringBuffer = "" loop { var c: char if read(std::stdin(), *c) < 1 { return header } @@ -935,7 +935,7 @@ def send_message(payload: &Json) { fflush(std::stdout()) } -def log_message(str: &string, tpe: int = MessageType::Log) { +def log_message(str: Str, tpe: int = MessageType::Log) { let obj = json::make_object() obj["type"] = tpe obj["message"] = str @@ -943,12 +943,12 @@ def log_message(str: &string, tpe: int = MessageType::Log) { } var request_id: size_t = 0 -def send_request(method: &string, params: &Json, reply: (&Json) -> ()) { +def send_request(method: Str, params: &Json, reply: (&Json) -> ()) { on_reply(request_id, reply) send_request(method, params) } -def send_request(method: &string, params: &Json) { +def send_request(method: Str, params: &Json) { let obj = json::make_object() obj["jsonrpc"] = "2.0" obj["id"] = request_id !int @@ -958,7 +958,7 @@ def send_request(method: &string, params: &Json) { request_id += 1 } -def send_notification(method: &string, params: &Json) { +def send_notification(method: Str, params: &Json) { let obj = json::make_object() obj["jsonrpc"] = "2.0" obj["method"] = method @@ -966,7 +966,7 @@ def send_notification(method: &string, params: &Json) { send_message(obj) } -def send_error(id: int, error_code: int, message: &string, data: &Json = null) { +def send_error(id: int, error_code: int, message: Str, data: &Json = null) { error(message, "\n") let obj = json::make_object() @@ -1044,7 +1044,7 @@ export def main -> int { let message = read_message() if message { let id = message["id"].as_int() if message.has_item("id") else 0 - var method = message["method"].as_string() if message.has_item("method") else null + var method = message["method"].as_string() if message.has_item("method") else {} !Str let params = message["params"] if not method { diff --git a/src/testrunner.pr b/src/testrunner.pr index 05e55ff..45c73b1 100644 --- a/src/testrunner.pr +++ b/src/testrunner.pr @@ -47,15 +47,22 @@ def assertion_handler(result: bool, msg: *char) { flush(io::stdout_orig) } -var stdout_file: &string -var stderr_file: &string +signal(2 /*SIGINT*/, *handle_sigint) + +def handle_sigint(signal: int) { + print("\x1B[?25h\n") + exit(0) +} + +var stdout_file: Str +var stderr_file: Str def get_stdout() -> &string { flush(std::stdout()) let fh = open(stdout_file, "rb") let res = read_all(fh) close(fh) - return res + return res.to_array() } def get_stderr() -> &string { @@ -63,7 +70,7 @@ def get_stderr() -> &string { let fh = open(stderr_file, "rb") let res = read_all(fh) close(fh) - return res + return res.to_array() } var runner = parser.get_value("--runner").b @@ -94,7 +101,7 @@ if runner { let test = symbol.value !def (*runtime::TestEnvironment) -> () test(*test_env) flush(std::stdout()) - if is_ci { + if not is_ci { // TODO This is ugly but apparently the CI wants the newline print("\n") } @@ -122,12 +129,16 @@ var files_to_test = parser.get_value_as_vec("files") const dev_null = "/dev/null" } -let files = vector::make(type &string) +let files = vector::make(String) for var i in 0..files_to_test.length { let file = files_to_test[i] enumerate_dir(file.str, "test*.pr", recursive, files) } +#if not defined WIN32 { + cstd::setvbuf(std::stdout(), null, io::_IONBF, 0) +} + print("Collected " + files.length + " test files\n") if not no_compile { @@ -142,26 +153,26 @@ if not no_compile { let stdout = open(dev_null, "w") // TODO It needs to be incremental in the future let proc = *process::spawn(compiler, - [file, "--no-incremental" !&string, "-o" !&string, dll_file] ![&string], // TODO These arrays are clunky + [file, "--no-incremental" !String, "-o" !String, dll_file !String] ![String], // TODO These arrays are clunky stdout = stdout, stderr = std::stderr() ) let spinner = ['|', '/', '-', '\\'] var index = 0 - if not is_ci { + if is_ci { print(spinner[index]) flush(std::stdout()) } while proc.running { proc.wait(100) - if not is_ci { + if is_ci { print("\x1B[1D") print(spinner[index % spinner.size]) flush(std::stdout()) } index += 1 } - if not is_ci { + if is_ci { print("\x1B[1D") print(" \n") print("\x1B[?25h") @@ -171,7 +182,7 @@ if not no_compile { close(stdout) if proc.exit_code { error("Couldn't compile module " + file + "\n") - files[i] = null + files[i] = null !String // TODO Compiler bug here } } } @@ -184,7 +195,7 @@ for var i in 0..files.length { if not file { continue } let dll_file = file.substring(0, file.length - 3) + dll_ext - let tests_to_run = vector::make(type &string) + let tests_to_run = vector::make(String) let lib = shared::load(dll_file, init = false) // We only want the symbol information for var symbol in @lib.symbols { @@ -197,7 +208,7 @@ for var i in 0..files.length { for var i in 0..tests_to_run.length { let test_function = tests_to_run[i] let proc = *process::spawn(executable_file(), - ["--runner" !&string, "--runner-file=" + dll_file + "", "--runner-test=" + test_function + ""] ![&string], + ["--runner" !String, ("--runner-file=" + dll_file + "") !String, ("--runner-test=" + test_function + "") !String] ![String], stdout = std::stdout() ) proc.wait() @@ -223,9 +234,9 @@ const FILE_ATTRIBUTE_DIRECTORY = 0x10 const INVALID_HANDLE_VALUE = -1 !uint64 // TODO Use a generator and move it to std -def enumerate_dir(file_or_dir: &string, pattern: &string, recursive: bool, res: &Vector(&string)) { +def enumerate_dir(file_or_dir: String, pattern: String, recursive: bool, res: &Vector(String)) { #if defined WIN32 { - let attrib = windows::GetFileAttributesA(file_or_dir.value) + let attrib = windows::GetFileAttributesA(file_or_dir.to_array().value) if not (attrib & FILE_ATTRIBUTE_DIRECTORY) { res.push(file_or_dir) return @@ -236,7 +247,7 @@ def enumerate_dir(file_or_dir: &string, pattern: &string, recursive: bool, res: var handle: * if recursive { - handle = windows::FindFirstFileA(full_pattern.value, *find_data) + handle = windows::FindFirstFileA(full_pattern.to_array().value, *find_data) if handle != INVALID_HANDLE_VALUE !* { loop { let folder = make_string(find_data.cFileName.value) @@ -250,7 +261,7 @@ def enumerate_dir(file_or_dir: &string, pattern: &string, recursive: bool, res: } full_pattern = file_or_dir + "\\" + pattern - handle = windows::FindFirstFileA(full_pattern.value, *find_data) + handle = windows::FindFirstFileA(full_pattern.to_array().value, *find_data) if handle != INVALID_HANDLE_VALUE !* { loop { @@ -265,7 +276,7 @@ def enumerate_dir(file_or_dir: &string, pattern: &string, recursive: bool, res: const DT_DIR = 4 var sres: linux::s_stat - if stat(file_or_dir.value, *sres) < 0 { + if stat(file_or_dir.to_array().value, *sres) < 0 { return } if sres.st_mode & 0o170000 == 0o100000 { @@ -274,7 +285,7 @@ def enumerate_dir(file_or_dir: &string, pattern: &string, recursive: bool, res: } else if sres.st_mode & 0o170000 == 0o040000 { var dir: *linux::DIR - if not (dir = linux::opendir(file_or_dir.value)) { return } + if not (dir = linux::opendir(file_or_dir.to_array().value)) { return } var dirent: *linux::s_dirent while (dirent = linux::readdir(dir)) { @@ -284,7 +295,7 @@ def enumerate_dir(file_or_dir: &string, pattern: &string, recursive: bool, res: if recursive { enumerate_dir(file_or_dir + "/" + name, pattern, recursive, res) } - } else if fnmatch(pattern.value, name.value, 0) == 0 { + } else if fnmatch(pattern.to_array().value, name.to_array().value, 0) == 0 { res.push(file_or_dir + "/" + name) } } diff --git a/src/toolchain.pr b/src/toolchain.pr index 8e4a870..44f1c46 100644 --- a/src/toolchain.pr +++ b/src/toolchain.pr @@ -22,7 +22,7 @@ import json export let modules = map::make(type &Module) modules["builtin"] = builtins::builtins_module -export def find_module(name: &string) -> &Module { +export def find_module(name: Str) -> &Module { let keys = modules.keys() for var i in 0..keys.size { let module = modules[keys[i]] @@ -33,7 +33,7 @@ export def find_module(name: &string) -> &Module { return null } -export def find_module_by_path(path: &string) -> &Module { +export def find_module_by_path(path: Str) -> &Module { let keys = modules.keys() for var i in 0..keys.size { let module = modules[keys[i]] @@ -44,13 +44,13 @@ export def find_module_by_path(path: &string) -> &Module { return null } -export var file_loader: (&string) -> (&string) = *load_file +export var file_loader: (String) -> (String) = *load_file -export var include_path = vector::make(type &string) -export var clang_flags = vector::make(type &string) -export var link_directories = vector::make(type &string) -export var link_libraries = vector::make(type &string) -export var link_flags = vector::make(type &string) +export var include_path = vector::make(Str) +export var clang_flags = vector::make(Str) +export var link_directories = vector::make(Str) +export var link_libraries = vector::make(Str) +export var link_flags = vector::make(Str) export var rdynamic = false export var time_report = false @@ -61,8 +61,8 @@ export var no_dependency_tracking = false export var is_shared = false export var no_stdlib = false -let include: &string = util::exe_folder() + "/../include" -let stdlib: &string = util::exe_folder() + "/../std" +let include: Str = util::exe_folder() + "/../include" +let stdlib: Str = util::exe_folder() + "/../std" #if defined WIN32 { include_path.push(include + "/windows") @@ -75,24 +75,33 @@ let stdlib: &string = util::exe_folder() + "/../std" include_path.push(include) include_path.push(stdlib) include_path.push(".") -export var outfolder: &string = ".princess" +export var outfolder: Str = ".princess" #if defined WIN32 { - export var outfile: &string = "a.exe" + export var outfile: Str = "a.exe" let clang = "clang.exe" } else { - export var outfile: &string = "a.out" + export var outfile: Str = "a.out" let clang = "clang-13" } +def unsafe_copy(s: Str) -> string { + let res = allocate(char, s.length() + 1) + res[s.length()] = '\0' + for var i in 0..s.length() { + res[i] = s[i] + } + return res +} + def create_version_string -> string { - var ret: &string = "Princess " + var ret: StringBuffer = "Princess " let version_file = util::exe_folder() + "/../version" - let fp = open(@version_file, "rb") + let fp = open(version_file, "rb") let version_str = util::replace_all(read_all(fp), "VERSION=", "") ret += version_str close(fp) - return @ret + return unsafe_copy(ret) } export const version = create_version_string() @@ -104,13 +113,13 @@ export var print_typed_ast = false export var continue_on_output = false // This flag controls emitting debug information to llvm export var debug_sym = false -export var main_file_name: &string = null +export var main_file_name: Str -var main_module_file: &string +var main_module_file: Str -export def add_define(define: &string) { +export def add_define(define: Str) { let tokens = lexer::lex(define) - let program = parser::parse(tokens, [define], "", "") + let program = parser::parse(tokens, [define.to_str()], "", "") if errors::error_count != 0 { error("Error parsing define `", define, "`\n") exit(1) @@ -174,12 +183,12 @@ export type Stage = enum { } export type Module = struct { - display_name: &string - filename: &string - file: &string - module: &string - text: &string - lines: &[&string] + display_name: Str + filename: Str + file: Str + module: Str + text: Str + lines: &[Str] node: &parser::Node scope: &scope::Scope // This is code that gets inserted by consteval/eval @@ -190,7 +199,7 @@ export type Module = struct { imported: &SSet difile: &compiler::Value stage: Stage - imports: &Set(&string) + imports: &Set(Str) dependants: &Set(weak_ref(Module)) // List of Type // This is a list of functions that are generated for dynamic dispatch @@ -219,10 +228,10 @@ export def != (this: &Module, other: &Module) -> bool { } export def make_module( - filename: &string, modulename: &string, + filename: String, modulename: String, node: &parser::Node, scpe: &scope::Scope, - text: &string = null, lines: &[&string] = null, - display_name: &string = null + text: String = null, lines: &[Str] = null, + display_name: String = null ) -> &Module { let module = { @@ -236,7 +245,7 @@ export def make_module( result = compiler::make_result(), code = compiler::make_block(), imported = set::make(), - imports = set::make(type &string), + imports = set::make(Str), dependants = set::make(type weak_ref(Module)), dyn_dispatch = vector::make(type &typechecking::Type), unresolved = map::make(scope::Ident, type weak_ref(scope::Value)) @@ -260,10 +269,10 @@ export def is_preload(module: &Module) -> bool { return starts_with(mfilename, ifilename) or starts_with(mfilename, std_filename) } -export def identifier_to_path(module: &parser::Node) -> &string { +export def identifier_to_path(module: &parser::Node) -> Str { assert module.kind == parser::NodeKind::IDENTIFIER - var path: &string = "" + var path: StringBuffer = "" if module.value.identifier.prefixed { path = "/" } @@ -280,11 +289,11 @@ export def identifier_to_path(module: &parser::Node) -> &string { return path } -export def find_module_file(module: &parser::Node, calling_module: &Module) -> &string { +export def find_module_file(module: &parser::Node, calling_module: &Module) -> Str { return find_module_file(identifier_to_path(module), calling_module) } -export def find_module_file(path: &string, calling_module: &Module) -> &string { +export def find_module_file(path: String, calling_module: &Module) -> Str { if path == "runtime" { return "runtime" } else if path == "main" { @@ -304,7 +313,7 @@ export def find_module_file(path: &string, calling_module: &Module) -> &string { return module_path } } - return null + return {} !Str } export def typecheck_module(name: &parser::Node, calling_module: &Module) -> &Module { @@ -366,8 +375,8 @@ export def compile_module(module: &Module) -> &Module { return null } -export def load_file(filename: &string) -> &string { - let fh = open(@filename, "rb") +export def load_file(filename: String) -> String { + let fh = open(filename, "rb") if not fh { return null } @@ -377,7 +386,7 @@ export def load_file(filename: &string) -> &string { return buf } -export def create_module_if_absent(filename: &string, modulename: &string, display_name: &string = null, recompile: bool = false) -> &Module { +export def create_module_if_absent(filename: String, modulename: String, display_name: String = null, recompile: bool = false) -> &Module { if modulename == "runtime" { return runtime_ } @@ -425,7 +434,7 @@ export def reset_and_consteval(module: &Module) { consteval_module(module) } -export def consteval_module(module: &Module, display_name: &string = null) { +export def consteval_module(module: &Module, display_name: String = null) { if (not module.is_dirty and not no_incremental) or module.stage !int >= Stage::PREPROCESS !int { return } let modulename = module.module module.stage = Stage::PREPROCESS @@ -440,10 +449,10 @@ export def consteval_module(module: &Module, display_name: &string = null) { let ident = make_identifier("__file__") if not scope::get(module.scope, ident) { - let filename_type = typechecking::make_static_array(builtins::char_, module.filename.size) + let filename_type = typechecking::make_static_array(builtins::char_, module.filename.length() + 1) let exe_global = compiler::make_global_value( filename_type, "__file__", - { kind = compiler::ValueKind::STRING, tpe = filename_type, s = module.filename } !&compiler::Value, + { kind = compiler::ValueKind::STRING, tpe = filename_type, s = module.filename.to_array() } !&compiler::Value, module.compiler_state, private = false ) let exe_value = scope::create_variable( @@ -457,7 +466,7 @@ export def consteval_module(module: &Module, display_name: &string = null) { consteval::consteval(module) } -export def consteval_file(filename: &string, modulename: &string, display_name: &string = null, recompile: bool = false) -> &Module { +export def consteval_file(filename: String, modulename: String, display_name: String = null, recompile: bool = false) -> &Module { var module: &Module if modules.contains(filename) { module = modules[filename] @@ -504,10 +513,10 @@ export def consteval_module(name: &parser::Node, calling_module: &Module) -> &Mo def generate_runtime_source -> string { let runtime = util::exe_folder() + "/../src/runtime.pr" - let fp = open(@runtime, "rb") + let fp = open(runtime, "rb") let source = read_all(fp) close(fp) - return @source + return unsafe_copy(source) } const runtime_source = generate_runtime_source() @@ -543,10 +552,10 @@ def create_runtime_module { runtime_module.scope.module = runtime_module let exe_file = executable_file() - let exe_file_type = typechecking::make_static_array(builtins::char_, exe_file.size) + let exe_file_type = typechecking::make_static_array(builtins::char_, exe_file.length() + 1) let exe_global = compiler::make_global_value( exe_file_type, "executable", - { kind = compiler::ValueKind::STRING, tpe = exe_file_type, s = exe_file } !&compiler::Value, + { kind = compiler::ValueKind::STRING, tpe = exe_file_type, s = exe_file.to_array() } !&compiler::Value, runtime_module.compiler_state, private = false ) let exe_value = scope::create_variable( @@ -559,8 +568,8 @@ def create_runtime_module { runtime_ = runtime_module consteval::consteval(runtime_module) - runtime_module.stage = Stage::TYPECHECKING - typechecking::typecheck(runtime_module) + //runtime_module.stage = Stage::TYPECHECKING + //typechecking::typecheck(runtime_module) //runtime_module.stage = Stage::COMPILING //compiler::compile(runtime_module) @@ -569,6 +578,9 @@ def create_runtime_module { builtins::Function_ = scope::get_type(runtime_.scope, make_identifier("Function")) builtins::Generator_ = scope::get_type(runtime_.scope, make_identifier("Generator")) builtins::TestEnvironment_ = scope::get_type(runtime_.scope, make_identifier("TestEnvironment")) + + builtins::Field_ = scope::get_type(runtime_.scope, make_identifier("Field")) + builtins::EnumValue_ = scope::get_type(runtime_.scope, make_identifier("EnumValue")) } def create_types_module { @@ -647,7 +659,7 @@ export def reset_types { create_types_main() } -export def extract_module_name(filename: &string) -> &string { +export def extract_module_name(filename: String) -> Str { // TODO Path manipulation should be made easier var folder_sep = filename.last_index_of("/") if folder_sep == -1 { @@ -659,8 +671,8 @@ export def extract_module_name(filename: &string) -> &string { return filename.substring(folder_sep + 1 if folder_sep > 0 else 0, filename.length() - 3) } -def make_build_command -> &string { - var build_command: &string = clang + " " +def make_build_command -> Str { + var build_command: StringBuffer = clang + " " for var i in 0..clang_flags.length { build_command += clang_flags[i] + " " } @@ -671,7 +683,7 @@ def make_build_command -> &string { return build_command } -export def compile_main_file(filename: &string) { +export def compile_main_file(filename: String) { if not filename.ends_with(".pr") { error("File ", filename, " is not a Princess source file\n") exit(1) @@ -698,7 +710,7 @@ export def compile_main_file(filename: &string) { delete(tokens) if error_count > 0 { exit(1) } print(json::to_string(debug::node_to_json(node)), "\n") - if not continue_on_output { exit(0) } + if not continue_on_output { return } } @@ -719,11 +731,9 @@ export def compile_main_file(filename: &string) { if print_typed_ast { if error_count > 0 { exit(1) } print(json::to_string(debug::node_to_json(module.node, types = true)), "\n") - if not continue_on_output { exit(0) } + if not continue_on_output { return } } - load_file_type() - reset_types() compiler::import_structures(builtins::Type_, types) @@ -761,7 +771,7 @@ export def compile_main_file(filename: &string) { if dependency_graph { print_dependency_graph(module) - exit(0) + return } if time_report { @@ -783,7 +793,7 @@ export def compile_main_file(filename: &string) { #if defined WIN32 { let compile_cstd = clang + " -S -emit-llvm -o " + outfolder + "/cstd_include.ll " + include + "/cstd.c" - system(@compile_cstd) + system(compile_cstd) } var build_command = make_build_command() + "-Wno-override-module -c " @@ -852,9 +862,9 @@ export def compile_main_file(filename: &string) { debug::trace(build_command) build_command = "cd \"" + outfolder + "\" && " + build_command - system(@build_command) + system(build_command) - var link_command: &string = clang + var link_command: StringBuffer = clang #if defined WIN32 { link_command += " -lUser32 -lKernel32 -lDbghelp " } else { @@ -901,7 +911,7 @@ export def compile_main_file(filename: &string) { debug::trace("Linking with clang...") debug::trace(link_command) - system(@link_command) + system(link_command) let end_compiling = util::millis() @@ -914,7 +924,7 @@ export def compile_main_file(filename: &string) { } } -def print_dependency_graph(module: &Module, indent: &string, last: bool) { +def print_dependency_graph(module: &Module, indent: String, last: bool) { let branch = "└── " if last else "├── " print(indent, branch, module.module, "\n") diff --git a/src/typechecking.pr b/src/typechecking.pr index 5e6e046..056da07 100644 --- a/src/typechecking.pr +++ b/src/typechecking.pr @@ -74,7 +74,7 @@ export type StructMember = struct { // Source line line: int node: weak_ref(parser::Node) - name: &string + name: Str tpe: &Type // index into the field_types vector index: size_t @@ -85,7 +85,7 @@ export type StructMember = struct { } export type StructuralTypeMember = struct { - name: &string + name: Str // Vector of NamedParameter parameter_t: &Vector(NamedParameter) // Vector of Type @@ -102,9 +102,9 @@ export type Type = struct { state: &State // Name of the type as used by the source code // Might be the name of a typedef - name: &string + name: Str // Unique name of the type - type_name: &string + type_name: Str // Size in bytes size: size_t align: size_t @@ -157,7 +157,6 @@ export type Type = struct { export def hash(tpe: &Type) -> uint64 { if tpe._hash { return tpe._hash } let name = debug::type_to_str(tpe, full_name = true) - if not name { return 0 } tpe._hash = md5::high(md5::md5(name)) return tpe._hash } @@ -218,7 +217,7 @@ export def has_destructor(tpe: &Type) -> bool { } else if tpe.kind == TypeKind::CLOSURE { res = true } - if not consteval::recompiling_functions { + if not consteval::is_static { tm.has_destructor = 1 if res else -1 } return res @@ -226,17 +225,24 @@ export def has_destructor(tpe: &Type) -> bool { export def get_builtin_destructor(tpe: &Type) -> &scope::Value { if not tpe { return null } + if is_polymorph(tpe) { return null } let tm = get_meta(tpe) if tm.has_builtin_destructor != 0 { return tm.builtin_destructor } + var destructor = tm.builtin_destructor let args = vector::make(NamedParameter) args.push({ _tpe = pointer(tpe) } !NamedParameter) - let destructor = scope::generate_function(builtins::builtins, parser::make_identifier("__destruct__"), args, true) - tm.builtin_destructor = destructor - if not consteval::recompiling_functions { + if not tm.builtin_destructor { + destructor = scope::generate_function(builtins::builtins, parser::make_identifier("__destruct__"), args, true) + tm.builtin_destructor = destructor + if consteval::is_static and destructor { + compiler::create_destructor(destructor.tpe) + } + } + if not consteval::is_static { tm.has_builtin_destructor = 1 if destructor else -1 } return destructor @@ -252,16 +258,18 @@ export def get_user_defined_destructor(tpe: &Type) -> &scope::Value { args.push({ _tpe = pointer(tpe) } !NamedParameter) - let destructor = scope::get_function(tpe.module.scope, parser::make_identifier("destruct"), args, false, true) + var destructor = scope::get_function(tpe.module.scope, parser::make_identifier("destruct"), args, false, true, not consteval::is_static) if destructor { - if not consteval::recompiling_functions { - tm.has_destructor = 1 // Don't update the cache when recompiling functions! + if consteval::is_static { + destructor = consteval::compile_function(destructor, args) + } else { + tm.has_destructor = 1 } tm.destructor = destructor return destructor } } - if not consteval::recompiling_functions { + if not consteval::is_static { tm.has_destructor = -1 } return null @@ -270,10 +278,7 @@ export def get_user_defined_destructor(tpe: &Type) -> &scope::Value { export def get_constructor(tpe: &Type) -> &scope::Value { has_copy_constructor(tpe) let tm = get_meta(tpe) - if tm.has_constructor != 0 { - return tm.constructor - } - return null + return tm.constructor } export def has_user_defined_copy_constructor(tpe: &Type) -> bool { @@ -296,13 +301,16 @@ export def has_user_defined_copy_constructor(tpe: &Type) -> bool { } !NamedParameter args.push(arg) args.push(arg) - let constructor = scope::get_function(tpe.module.scope, parser::make_identifier("construct"), args) - if constructor { + var constructor = scope::get_function(tpe.module.scope, parser::make_identifier("construct"), args, false, false, not consteval::is_static) + if constructor { + if consteval::is_static { + constructor = consteval::compile_function(constructor, args) + } tm.constructor = constructor res = true } } - if not consteval::recompiling_functions { + if not consteval::is_static { tm.has_user_defined_constructor = 1 if res else -1 } return res @@ -350,9 +358,12 @@ export def has_copy_constructor(tpe: &Type, lookup: bool = true) -> bool { vector::push(args, { _tpe = pointer(tpe) } !NamedParameter) vector::push(args, { _tpe = pointer(tpe) } !NamedParameter) tm.constructor = scope::generate_function(builtins::builtins, parser::make_identifier("__construct__"), args, dry_run = true) + if consteval::is_static and tm.constructor { + compiler::create_constructor(tm.constructor.tpe) + } } - if not consteval::recompiling_functions { + if not consteval::is_static { tm.has_constructor = 1 if res else -1 } return res @@ -387,13 +398,13 @@ export def box(tpe: &Type) -> &Type { export type NamedParameter = struct { // Might be empty for positional parameters - name: &string + name: Str _tpe: &Type varargs: bool - node: &parser::Node + node: weak_ref(parser::Node) value: &compiler::Value kw: parser::VarDecl - type_node: &parser::Node + type_node: weak_ref(parser::Node) } export def tpe(np: NamedParameter) -> &Type { @@ -575,8 +586,8 @@ export def get_interface(tpe: &Type) -> &Type { return null } -export def append_module(name: &string, module: &string) -> &string { - var res: &string = "" +export def append_module(name: Str, module: Str) -> Str { + var res: StringBuffer = "" if module { res += module + "::" } @@ -716,7 +727,7 @@ export def make_static_array(array_tpe: &Type, size: size_t) -> &Type { return make_static_array(array_tpe, size, parser::VarDecl::VAR) } -def make_unique_name(name: &string, state: &State) -> &string { +def make_unique_name(name: Str, state: &State) -> Str { let counter = state.counter state.counter += 1 return state.module.module + "::" + name + '.' + counter @@ -769,7 +780,7 @@ export def iterate_member_functions(tpe: &Type) -> TypeEntryMember { } } -def do_get_member_functions(name: &string, vec: &Vector(TypeEntryMember)) { +def do_get_member_functions(name: Str, vec: &Vector(TypeEntryMember)) { let type_entry = types_map.get_or_default(name, null) if not type_entry { return } if type_entry.functions { @@ -891,6 +902,7 @@ export def copy_return_t(return_t: &Vector(&Type)) -> &Vector(&Type) { export def copy(a: &Type) -> &Type { if not a { return null } var t: &Type = @a + t._hash = 0 if a.tc_args { t.tc_args = vector::make(type &Type) @@ -918,6 +930,7 @@ export def copy(a: &Type) -> &Type { export def shallow_copy(tpe: &Type) -> &Type { let ret: &Type = @tpe + ret._hash = 0 if tpe.kind == TypeKind::FUNCTION { ret.return_t = vector::copy(tpe.return_t) ret.parameter_t = vector::copy(tpe.parameter_t) @@ -937,10 +950,10 @@ export def equals(a: &Type, b: &Type) -> bool { b = b.weak } - /*if a._hash and b._hash { + if a.kind != TypeKind::TYPE and a.hash() and b.hash() { // Speed up equality if hashes are defined return a._hash == b._hash - }*/ + } if a.kind == TypeKind::STUB or b.kind == TypeKind::STUB { return a.type_name == b.type_name @@ -1421,8 +1434,11 @@ export def convert_type_score(a: &Type, b: &Type, module: &toolchain::Module, is if impl and a.kind != TypeKind::TYPE { let parameter_t = vector::make(NamedParameter) parameter_t.push({_tpe = b} !NamedParameter) - let conv = scope::find_implicit_function(module.scope, parameter_t, a) + let conv = scope::find_implicit_function(module.scope, parameter_t, a, not consteval::is_static) if conv { + if consteval::is_static { + consteval::compile_function(conv, parameter_t) + } return 15 } } @@ -1600,6 +1616,7 @@ def replace_parameter(tpe: &Type, types: &SMap(&Type)) -> &Type { let ntpe = types.get_or_default(tpe.name, null) if ntpe { return ntpe } } + tpe._hash = 0 return tpe } @@ -1778,7 +1795,7 @@ export def overload_score( return sum } -export def mangle_function_name(name: &string, parameter_t: &Vector(NamedParameter), test: bool = false) -> &string { +export def mangle_function_name(name: Str, parameter_t: &Vector(NamedParameter), test: bool = false) -> Str { var res = name + "::(" let len = vector::length(parameter_t) @@ -1817,13 +1834,13 @@ export def mangle_function_name(name: &string, parameter_t: &Vector(NamedParamet } // TODO Move this into parser -export def last_ident_to_str(node: &parser::Node) -> string { +export def last_ident_to_str(node: &parser::Node) -> String { if not node { return "" } assert(node.kind == parser::NodeKind::IDENTIFIER) if vector::length(node.value.identifier.path) > 1 { errors::errorn(node, "Expected plain identifier without path") } - return @(node.value.identifier.path[0]) + return node.value.identifier.path[0] } def flatten_return_type(node: &parser::Node, return_t: &Vector(&Type)) -> &Type { @@ -1856,7 +1873,7 @@ export def make_stub_type(ident: &parser::Node, state: &State) -> &typechecking: let name = parser::identifier_to_str(ident) let tpe = make_type_raw(TypeKind::STUB) - tpe.name = @(ident.value.identifier.path[vector::length(ident.value.identifier.path) - 1]) + tpe.name = ident.value.identifier.path[vector::length(ident.value.identifier.path) - 1] tpe.type_name = name if vector::length(ident.value.identifier.path) == 1 { tpe.type_name = append_module(tpe.type_name, state.module.module) @@ -1989,7 +2006,7 @@ export def generate_concrete_functions(type_constructor: &Type, tpe: &Type, stat } } -export def type_lookup(node: &parser::Node, state: &State, current_type: &Type = null, lookup_default: bool = false, cache: &SMap(&Type) = null, prefix: &string = null) -> &Type { +export def type_lookup(node: &parser::Node, state: &State, current_type: &Type = null, lookup_default: bool = false, cache: &SMap(&Type) = null, prefix: String = null) -> &Type { var tpe = do_type_lookup(node, state, current_type, lookup_default, cache, prefix) if node { node.tpe = tpe } if tpe !* == current_type !* { return current_type } @@ -2029,7 +2046,22 @@ def lookup_field_type(node: &parser::Node, state: &State, current_type: &Type, c if scope::is_global(state.scope) and node.kind == parser::NodeKind::PTR_T or node.kind == parser::NodeKind::REF_T or node.kind == parser::NodeKind::ARRAY_T or - node.kind == parser::NodeKind::WEAK_REF_T { + node.kind == parser::NodeKind::WEAK_REF_T or + node.kind == parser::NodeKind::FUNCTION_T or + node.kind == parser::NodeKind::CLOSURE_T { + + if node.kind == parser::NodeKind::FUNCTION_T { + let box = box(type_lookup(node, state, current_type, false, cache)) + box.size = size_of def () -> () + box.align = align_of def () -> () + return box + } + if node.kind == parser::NodeKind::CLOSURE_T { + let box = box(type_lookup(node, state, current_type, false, cache)) + box.size = size_of () -> () + box.align = align_of () -> () + return box + } var stub: &Type = null let parr = node.value.t_parr.tpe @@ -2062,6 +2094,7 @@ def lookup_field_type(node: &parser::Node, state: &State, current_type: &Type, c stub.module = state.module stub.node = node node.tpe = stub + return stub } else { return type_lookup(node, state, current_type, false, cache) @@ -2069,7 +2102,7 @@ def lookup_field_type(node: &parser::Node, state: &State, current_type: &Type, c } // TODO current_type is basically a hack, there's really no reason why you should already have a type and then look it up again -export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Type = null, lookup_default: bool = false, cache: &map::SMap(&Type) = null, prefix: &string = null) -> &Type { +export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Type = null, lookup_default: bool = false, cache: &map::SMap(&Type) = null, prefix: String = null) -> &Type { if not node { return null } if node.kind == parser::NodeKind::IDENTIFIER { if current_type and not lookup_default and current_type.kind != TypeKind::STUB { @@ -2148,7 +2181,7 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ let line = (@field).loc.line var field_tpe: &Type = null - var name: &string + var name: Str var is_bitfield = false var bit_size = 0 !size_t @@ -2205,7 +2238,7 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ let line = (@field).loc.line var field_tpe: &Type = null - var name: &string + var name: Str var is_bitfield = false var bit_size = 0 !size_t @@ -3124,7 +3157,7 @@ def make_function_call(node: &parser::Node, ident: &parser::Node) -> &parser::No return function } -def convert_to_call(node: &parser::Node, name: &string, args: &Vector(NamedParameter), state: &State) { +def convert_to_call(node: &parser::Node, name: Str, args: &Vector(NamedParameter), state: &State) { let ident = parser::make_identifier(name) let fun = scope::get_function(state.scope, ident, args, false, true, force_compile = not consteval::is_static) if fun { @@ -3136,7 +3169,7 @@ def convert_to_call(node: &parser::Node, name: &string, args: &Vector(NamedParam } } -def convert_to_icall(node: &parser::Node, name: &string, args: &Vector(NamedParameter), state: &State) { +def convert_to_icall(node: &parser::Node, name: Str, args: &Vector(NamedParameter), state: &State) { let ident = parser::make_identifier(name) let fun = scope::get_function(state.scope, ident, args, false, true, force_compile = not consteval::is_static) if fun { @@ -3634,7 +3667,7 @@ export def walk_Def(node: &parser::Node, state: &State, polymorph: bool = false) c_return_t.push(tpe) } - let arr = zero_allocate(type &string, state.function_stack.length) + let arr = zero_allocate(String, state.function_stack.length) for var i in 1..state.function_stack.length { arr[i - 1] = state.function_stack[i].unmangled } @@ -3869,6 +3902,10 @@ export def walk_TypeDecl(node: &parser::Node, state: &State) { left.svalue = node.svalue = scope::create_type(state.scope, name, share, tpe, scope::Phase::COMPILED, node, null) } name.tpe = tpe + + if is_static and tpe.kind != typechecking::TypeKind::STUB { + compiler::create_type(tpe, state.module) + } } } @@ -3942,9 +3979,9 @@ def walk_Yield(node: &parser::Node, state: &State) { node.tpe = tpe } -export def append_arguments(arguments: &Vector(NamedParameter)) -> &string { +export def append_arguments(arguments: &Vector(NamedParameter)) -> Str { let len = vector::length(arguments) - var res: &string = null + var res: StringBuffer = "" if len > 0 { res = "Arguments were of type " } else { @@ -3962,7 +3999,7 @@ export def append_arguments(arguments: &Vector(NamedParameter)) -> &string { def compile_function(function: *&scope::Value, arguments: &Vector(typechecking::NamedParameter)) { if consteval::is_static and @function { - if not (@function).imported and not (@function).node { + if not (@function).imported { consteval::load_function(@function) } @function = consteval::compile_function(@function, arguments) @@ -3989,6 +4026,10 @@ export def walk_Call(node: &parser::Node, dry_run: bool, state: &State) -> bool left = node.value.func_call.left var tpe = (@left).tpe + if tpe and tpe.kind == typechecking::TypeKind::BOX { + tpe = tpe.weak + } + var arguments = vector::make(NamedParameter) for var i in 0..vector::length(node.value.func_call.args) { let n = node.value.func_call.args[i] @@ -4065,7 +4106,7 @@ export def walk_Call(node: &parser::Node, dry_run: bool, state: &State) -> bool return false } if overload_score(function.tpe, arguments, state.module, false) < 0 { - var msg: &string = "Incorrect arguments to overloaded function. " + var msg: StringBuffer = "Incorrect arguments to overloaded function. " msg += append_arguments(arguments) errors::errorn(left, msg) return false @@ -4079,7 +4120,7 @@ export def walk_Call(node: &parser::Node, dry_run: bool, state: &State) -> bool if not np.tpe { return false } } - var msg: &string = "Function `" + parser::identifier_to_str(left) + "` not found. " + var msg: StringBuffer = "Function `" + parser::identifier_to_str(left) + "` not found. " msg += append_arguments(arguments) errors::errorn(left, msg) } @@ -4480,6 +4521,7 @@ export def lookup_struct_member(member: StructMember, resolved: &SSet = null) { if tpe._tpe and tpe._tpe.kind == TypeKind::STUB and tpe._tpe.state { tpe._tpe = box(type_lookup(tpe._tpe.node, tpe._tpe.state)) } + tpe._hash = 0 } else if tpe.kind == typechecking::TypeKind::STRUCT { for var i in 0..tpe.fields.size { let field = tpe.fields[i] @@ -4488,7 +4530,7 @@ export def lookup_struct_member(member: StructMember, resolved: &SSet = null) { } } -def resolve_member(fields: &[StructMember], name: &string) -> &Type { +def resolve_member(fields: &[StructMember], name: String) -> &Type { for var i in 0..fields.size { let member = fields[i] if member.name { @@ -4547,7 +4589,7 @@ def walk_MemberAccess_aggregate(node: &parser::Node, ucs: bool, state: &State) - if (@tpe).kind == TypeKind::STRUCT or (@tpe).kind == TypeKind::UNION { let name = last_ident_to_str(right) - let rtpe = resolve_member((@tpe).fields, name) + var rtpe = resolve_member((@tpe).fields, name) if not rtpe { if ucs { if walk_MemberAccess_ucs(node, state) { return true } @@ -4555,6 +4597,9 @@ def walk_MemberAccess_aggregate(node: &parser::Node, ucs: bool, state: &State) - } return false } + if rtpe.kind == TypeKind::BOX { + rtpe = rtpe.weak + } node.tpe = rtpe } else if (@tpe).kind == TypeKind::ARRAY or (@tpe).kind == TypeKind::STATIC_ARRAY { let name = last_ident_to_str(right) @@ -4782,7 +4827,7 @@ def walk_ComparisionOp(node: &parser::Node, state: &State) { if node.kind != parser::NodeKind::FUNC_CALL { if builtins::Type_ and equals(left.tpe, pointer(builtins::Type_)) { - let equals = scope::get(toolchain::runtime_.scope, parser::make_identifier("equals")) + let equals = scope::get(toolchain::runtime_.scope, parser::make_identifier("equals"), not consteval::is_static) consteval::compile_function(equals) } @@ -4828,6 +4873,11 @@ def walk_Assert(node: &parser::Node, state: &State) { let msg = node.value.assert_.message walk(node, cond, state) walk(node, msg, state) + + if consteval::is_static { + let stderr_fun = get(toolchain::find_module("std").scope, parser::make_identifier("stderr"), force_compile = false) + consteval::compile_function(stderr_fun) + } if cond and not is_boolean(cond.tpe, state.module) { errors::errorn(cond, "Incompatible type ", debug::type_to_str(cond.tpe), ", must be boolean type") diff --git a/src/util.pr b/src/util.pr index 4e8ff2c..979f6be 100644 --- a/src/util.pr +++ b/src/util.pr @@ -7,7 +7,7 @@ import vector -export def find_substr(str: &string, search: &string, start: int) -> int { +export def find_substr(str: String, search: String, start: int) -> int { if start >= length(str) { return -1 } @@ -32,29 +32,23 @@ export def find_substr(str: &string, search: &string, start: int) -> int { return -1 } -export def replace_all(str: &string, search: &string, replace: &string) -> &string { - var ret: &string = "" +export def replace_all(str: String, search: String, replace: String) -> Str { + var ret: StringBuffer = "" var i = 0 var j = find_substr(str, search, 0) while j != -1 { - var before = zero_allocate(char, j - i + 1) - memcopy(str.value ++ i, before.value, j - i) - ret += before + ret += str.slice(i, j) ret += replace - free(before) i = j + (length(search) !int) j = find_substr(str, search, i) } - var after = zero_allocate(char, length(str) - i + 1) - memcopy(str.value ++ i, after.value, length(str) - i) - ret += after - free(after) + ret += str.slice(i, str.length()) return ret } -export def split_lines(s: &string) -> &[&string] { +export def split_lines(s: String) -> &[Str] { let size = length(s) var lines = 1 @@ -64,7 +58,7 @@ export def split_lines(s: &string) -> &[&string] { lines += 1 } } - var result = allocate_ref(type &string, lines) + var result = allocate_ref(Str, lines) if size == 0 { result[0] = "" return result @@ -96,8 +90,8 @@ export def split_lines(s: &string) -> &[&string] { return result } -export def split(str: &string, by: &string) -> &[&string] { - let res = vector::make(type &string) +export def split(str: String, by: String) -> &[String] { + let res = vector::make(String) if str.index_of(by) < 0 { res.push(str) return res.to_array() @@ -114,17 +108,17 @@ export def split(str: &string, by: &string) -> &[&string] { return res.to_array() } -export def exe_folder -> &string { +export def exe_folder -> Str { return dirname(executable_file()) } -export def double_to_hex_str(f: double) -> &string { +export def double_to_hex_str(f: double) -> Str { var n = @(*f !*uint64) return int_to_hex_str(n) } -export def exists(filename: &string) -> bool { - let fp = open(@filename, "r") +export def exists(filename: Str) -> bool { + let fp = open(filename, "r") if fp { close(fp) return true @@ -157,9 +151,8 @@ export def millis -> int64 { } // TODO Unicode... -// TODO StringBuffer -export def repr(s: &string, zero: bool) -> &string { - var res: &string = "\"" +export def repr(s: Str, zero: bool) -> Str { + var res: StringBuffer = "\"" for var i in 0..length(s) { let c = s[i] !uint8 if c < 32 or c > 126 or c == 34 { @@ -173,7 +166,7 @@ export def repr(s: &string, zero: bool) -> &string { } else if c == 92 { res += "\\5C" } else { - res += c + res += c !char } } if zero { @@ -231,7 +224,7 @@ export def bytes_in_glyph(c: char) -> int { } // Most basic unicode handling -export def count_glyphs(str: &string, until: size_t) -> size_t { +export def count_glyphs(str: Str, until: size_t) -> size_t { var i = 0 var count = 0 while i < until { @@ -242,6 +235,6 @@ export def count_glyphs(str: &string, until: size_t) -> size_t { return count } -export def count_glyphs(str: &string) -> size_t { +export def count_glyphs(str: Str) -> size_t { return count_glyphs(str, length(str)) } \ No newline at end of file diff --git a/std/arena.pr b/std/arena.pr new file mode 100644 index 0000000..81e1a8b --- /dev/null +++ b/std/arena.pr @@ -0,0 +1,69 @@ +import cstd +import std + +const DEFAULT_REGION_SIZE = 4 * 1024 // Default page size + +type Region = struct { + next: *Region + capacity: size_t + count: size_t + data: * +} + +export type Arena = struct { + start: *Region + end: *Region + region_capacity: size_t +} + +def make_region(capacity: size_t) -> *Region { + let region = zero_allocate(Region) + region.capacity = capacity + region.count = 0 + region.data = zero_allocate(capacity) // TODO We might not want to do that in the default case + return region +} + +export def make(capacity: size_t = DEFAULT_REGION_SIZE) -> &Arena { + return { + region_capacity = capacity + } !&Arena +} + +export def allocate(arena: &Arena, type T) -> *T { + return allocate(arena, T.size) !*T +} + +export def allocate(arena: &Arena, size: size_t) -> * { + var end = arena.end + if not end { + arena.start = make_region(arena.region_capacity) + end = arena.end = arena.start + } + if end.count + size <= end.capacity { + // We got enought capacity left + let cur = end.count + end.count += size + return end.data ++ cur + } + // We need to create a new region + let new_end = make_region(max(size, arena.region_capacity) !size_t) + new_end.count = size + end.next = new_end + arena.end = new_end + return new_end.data +} + +// TODO Use destructor once we have move semantics +export def free(arena: &Arena) { + var region = arena.start + while region { + free(region.data) + let next_region = region.next + free(region) + region = next_region + } + // Reset the arena + arena.start = null + arena.end = null +} \ No newline at end of file diff --git a/std/getopt.pr b/std/getopt.pr index cdcaf9c..1424124 100644 --- a/std/getopt.pr +++ b/std/getopt.pr @@ -15,8 +15,8 @@ export type Value = struct { next: &Value kind: ValueKind struct #union { - str: &string - arr: &[&string] + str: String + arr: &[String] b: bool } } @@ -31,23 +31,23 @@ export def destruct(value: *Value) { export type Option = struct { shortop: char - longop: &string + longop: String nargs: int repeat: bool default: &Value is_set: bool value: &Value - help: &string - metavar: &string + help: String + metavar: String } -export def option_repeat(shortop: char, longop: &string) -> Option { +export def option_repeat(shortop: char, longop: String) -> Option { return { shortop, longop, 1, true } !Option } -export def option_repeat(shortop: char, longop: &string, nargs: int) -> Option { +export def option_repeat(shortop: char, longop: String, nargs: int) -> Option { return { shortop, longop, nargs, true } !Option } -export def option_repeat(shortop: char, longop: &string, default: [&string]) -> Option { +export def option_repeat(shortop: char, longop: String, default: [String]) -> Option { var value: &Value = null for var i in 0..default.size { let next = { kind = ValueKind::STRING} !&Value @@ -57,7 +57,7 @@ export def option_repeat(shortop: char, longop: &string, default: [&string]) -> } return { shortop, longop, 1, true, value } !Option } -export def option_repeat(shortop: char, longop: &string, nargs: int, default: [[type &string]]) -> Option { +export def option_repeat(shortop: char, longop: String, nargs: int, default: [[String]]) -> Option { var value: &Value = null for var i in 0..default.size { let next = { kind = ValueKind::ARRAY } !&Value @@ -68,82 +68,82 @@ export def option_repeat(shortop: char, longop: &string, nargs: int, default: [[ return { shortop, longop, nargs, true, value } !Option } -export def option_repeat(longop: &string) -> Option { +export def option_repeat(longop: String) -> Option { return option_repeat('\0', longop) } -export def option_repeat(longop: &string, nargs: int) -> Option { +export def option_repeat(longop: String, nargs: int) -> Option { return option_repeat('\0', longop, nargs) } -export def option_repeat(longop: &string, default: [&string]) -> Option { +export def option_repeat(longop: String, default: [String]) -> Option { return option_repeat('\0', longop, default) } -export def option_repeat(longop: &string, nargs: int, default: [[type &string]]) -> Option { +export def option_repeat(longop: String, nargs: int, default: [[String]]) -> Option { return option_repeat('\0', longop, nargs, default) } -export def option(shortop: char, longop: &string, nargs: int, default: [&string]) -> Option { +export def option(shortop: char, longop: String, nargs: int, default: [String]) -> Option { assert(nargs == default.size) assert(nargs > 1) // TODO This is a bit arbitrary let value = { kind = ValueKind::ARRAY } !&Value value.arr = default return { shortop, longop, nargs, false, value } } -export def option(shortop: char, longop: &string, default: bool) -> Option { +export def option(shortop: char, longop: String, default: bool) -> Option { let value = { kind = ValueKind::BOOLEAN } !&Value value.b = default return { shortop, longop, 0, false, value } } -export def option(shortop: char, longop: &string, default: &string) -> Option { +export def option(shortop: char, longop: String, default: String) -> Option { let value = { kind = ValueKind::STRING } !&Value value.str = default return { shortop, longop, 1, false, value } } -export def option(shortop: char, longop: &string, nargs: int) -> Option { +export def option(shortop: char, longop: String, nargs: int) -> Option { assert(nargs > 1) return { shortop, longop, nargs, false } } -export def option(shortop: char, longop: &string) -> Option { +export def option(shortop: char, longop: String) -> Option { return { shortop, longop, 1, false } } -export def option(longop: &string, nargs: int, default: [&string]) -> Option { +export def option(longop: String, nargs: int, default: [String]) -> Option { return option('\0', longop, nargs, default) } -export def option(longop: &string, default: bool) -> Option { +export def option(longop: String, default: bool) -> Option { return option('\0', longop, default) } -export def option(longop: &string, default: &string) -> Option { +export def option(longop: String, default: String) -> Option { return option('\0', longop, default) } -export def option(longop: &string, nargs: int) -> Option { +export def option(longop: String, nargs: int) -> Option { return option('\0', longop, nargs) } -export def option(longop: &string) -> Option { +export def option(longop: String) -> Option { return option('\0', longop) } -export def set_help(option: Option, help: &string) -> Option { +export def set_help(option: Option, help: String) -> Option { option.help = help return option } -export def set_metavar(option: Option, metavar: &string) -> Option { +export def set_metavar(option: Option, metavar: String) -> Option { option.metavar = metavar return option } export type OptionParser = struct { options: [Option] - description: &string + description: String } -export def make_parser(options: [Option], description: &string) -> OptionParser { +export def make_parser(options: [Option], description: String) -> OptionParser { return { options, description } !OptionParser } -export def get_value(parser: *OptionParser, name: &string) -> &Value { +export def get_value(parser: *OptionParser, name: String) -> &Value { let options = parser.options for var i in 0..options.size { let option = *options[i] @@ -154,7 +154,7 @@ export def get_value(parser: *OptionParser, name: &string) -> &Value { return null } -export def get_value_as_vec(parser: *OptionParser, name: &string) -> &Vector(&Value) { +export def get_value_as_vec(parser: *OptionParser, name: String) -> &Vector(&Value) { let res = vector::make(type &Value) var value = get_value(parser, name) while value { @@ -166,7 +166,7 @@ export def get_value_as_vec(parser: *OptionParser, name: &string) -> &Vector(&Va const INDENT = 26 -def print_help(parser: *OptionParser, program: &string) { +def print_help(parser: *OptionParser, program: String) { let options = parser.options print("OVERVIEW: ", parser.description, "\n") print("\n") @@ -215,14 +215,14 @@ def print_help(parser: *OptionParser, program: &string) { while size < INDENT { size += print(" ") } - if option.help.value { + if option.help { print(option.help) } print("\n") } } -def find_option(options: [Option], str: &string, index: int) -> *Option { +def find_option(options: [Option], str: String, index: int) -> *Option { var optindex = 0 for var i in 0..options.size { let option = *options[i] @@ -249,7 +249,7 @@ def find_option(options: [Option], str: &string, index: int) -> *Option { return null } -def set_value(arg: &string, option: *Option, value: &Value) -> bool { +def set_value(arg: String, option: *Option, value: &Value) -> bool { if option.is_set { if option.repeat { if not option.value { @@ -321,7 +321,7 @@ export def parse(option_parser: *OptionParser, args: [string]) -> bool { } else { // parse --opt arg1 arg2 value.kind = ValueKind::ARRAY - let arr = allocate_ref(type &string, option.nargs) + let arr = allocate_ref(String, option.nargs) i += 1 for var j in 0..option.nargs { if i < args.size and not starts_with(args[i], "-") { @@ -373,7 +373,7 @@ export def parse(option_parser: *OptionParser, args: [string]) -> bool { } else { value.kind = ValueKind::ARRAY // parse -X arg1 arg2 - let arr = allocate_ref(type &string, option.nargs) + let arr = allocate_ref(String, option.nargs) i += 1 for var j in 0..option.nargs { if i < args.size and not starts_with(args[i], "-") { @@ -419,7 +419,7 @@ export def parse(option_parser: *OptionParser, args: [string]) -> bool { value.str = args[i] i += 1 } else { - let arr = allocate_ref(type &string, option.nargs) + let arr = allocate_ref(String, option.nargs) for var j in 0..option.nargs { if i < args.size and not starts_with(args[i], "-") { arr[j] = args[i] diff --git a/std/io.pr b/std/io.pr index 04bef21..7ef0712 100644 --- a/std/io.pr +++ b/std/io.pr @@ -13,22 +13,22 @@ var stdout_fh: File const _O_BINARY = 0x8000 - export def redirect_stderr_to_file(file: &string) { + export def redirect_stderr_to_file(file: String) { if stderr_orig_fd < 0 { stderr_orig_fd = cstd::_dup(2) stderr_orig = cstd::_fdopen(stderr_orig_fd, "w".value) } - stderr_fh = open(@file, "wb") + stderr_fh = open(file, "wb") cstd::_dup2(cstd::_fileno(stderr_fh), 2) cstd::_setmode(2, _O_BINARY) } - export def redirect_stdout_to_file(file: &string) { + export def redirect_stdout_to_file(file: String) { if stdout_orig_fd < 0 { stdout_orig_fd = cstd::_dup(1) stdout_orig = cstd::_fdopen(stdout_orig_fd, "w".value) } - stdout_fh = open(@file, "wb") + stdout_fh = open(file, "wb") cstd::_dup2(cstd::_fileno(stdout_fh), 1) cstd::_setmode(1, _O_BINARY) } @@ -55,21 +55,21 @@ var stdout_fh: File } else { import linux - export def redirect_stderr_to_file(file: &string) { + export def redirect_stderr_to_file(file: String) { if stderr_orig_fd < 0 { stderr_orig_fd = linux::dup(2) stderr_orig = cstd::fdopen(stderr_orig_fd, "w".value) } - stderr_fh = open(@file, "w") + stderr_fh = open(file, "w") linux::dup2(cstd::fileno(stderr_fh), 2) } - export def redirect_stdout_to_file(file: &string) { + export def redirect_stdout_to_file(file: String) { if stdout_orig_fd < 0 { stdout_orig_fd = linux::dup(1) stdout_orig = cstd::fdopen(stdout_orig_fd, "w".value) } - stdout_fh = open(@file, "w") + stdout_fh = open(file, "w") linux::dup2(cstd::fileno(stdout_fh), 1) } @@ -83,7 +83,7 @@ var stdout_fh: File close(stdout_fh) } - const _IONBF = 2 + export const _IONBF = 2 export def pipe -> File, File { var res: [2; int] diff --git a/std/json.pr b/std/json.pr index ccd1695..d8c7cbc 100644 --- a/std/json.pr +++ b/std/json.pr @@ -20,7 +20,7 @@ export type Status = enum { JSON_NULL; JSON_EMPTY; JSON_OK; JSON_ERROR } export type Data = struct #union { number: double - str: &string + str: Str b: bool } @@ -51,7 +51,7 @@ export def construct(copy: *JsonTreeNode, this: *JsonTreeNode) { copy.children = null if this.children { - copy.children = @this.children + copy.children = this.children.copy() } } @@ -149,12 +149,12 @@ export def push(tree: &Json, item: bool) { assert tree.root.tpe == Type::ARRAY tree.root.children.push({ tpe = Type::TRUE if item else Type::FALSE, data = { b = item } !Data } !JsonTreeNode) } -export def push(tree: &Json, item: &string) { +export def push(tree: &Json, item: String) { assert tree.root.tpe == Type::ARRAY tree.root.children.push({ tpe = Type::STRING, data = { str = item } !Data } !JsonTreeNode) } -export def set_item(tree: &Json, key: &string, item: &Json) { +export def set_item(tree: &Json, key: String, item: &Json) { assert tree.root.tpe == Type::OBJECT if item == null { item = make_null() } @@ -163,7 +163,7 @@ export def set_item(tree: &Json, key: &string, item: &Json) { } for var i in 0..tree.root.children.length { let child = tree.root.children.get(i) - if child.data.str == tree { + if child.data.str == key { child.children[0] = item.root return } @@ -172,15 +172,15 @@ export def set_item(tree: &Json, key: &string, item: &Json) { children.push(item.root) tree.root.children.push({ tpe = Type::KEY, data = { str = key } !Data, children = children } !JsonTreeNode) } -export def set_item(tree: &Json, key: &string, item: double) { +export def set_item(tree: &Json, key: String, item: double) { let root = { tpe = Type::NUMBER, data = { number = item } !Data } !JsonTreeNode set_item(tree, key, { root = root, status = Status::JSON_OK } !&Json) } -export def set_item(tree: &Json, key: &string, item: bool) { +export def set_item(tree: &Json, key: String, item: bool) { let root = { tpe = Type::TRUE if item else Type::FALSE, data = { b = item } !Data } !JsonTreeNode set_item(tree, key, { root = root, status = Status::JSON_OK } !&Json) } -export def set_item(tree: &Json, key: &string, item: &string) { +export def set_item(tree: &Json, key: String, item: String) { let root = { tpe = Type::STRING, data = { str = item } !Data } !JsonTreeNode set_item(tree, key, { root = root, status = Status::JSON_OK } !&Json) } @@ -191,7 +191,7 @@ export def length(tree: &Json) -> size_t { return tree.root.children.length } -export def has_item(tree: &Json, str: &string) -> bool { +export def has_item(tree: &Json, str: String) -> bool { if tree.root.tpe != Type::OBJECT { return false } if not tree.root.children { return false } for var i in 0..tree.root.children.length { @@ -201,7 +201,7 @@ export def has_item(tree: &Json, str: &string) -> bool { } return false } -export def get_item(tree: &Json, str: &string) -> &Json { +export def get_item(tree: &Json, str: String) -> &Json { assert tree.status == Status::JSON_OK assert tree.root.tpe == Type::OBJECT @@ -237,7 +237,7 @@ export def as_int(tree: &Json) -> int { export def as_double(tree: &Json) -> double { return tree.root.data.number } -export def as_string(tree: &Json) -> &string { +export def as_string(tree: &Json) -> Str { return tree.root.data.str } @@ -282,8 +282,8 @@ def serialize(tpe: *runtime::Type, data: *) -> JsonTreeNode { if tpe == float { return { tpe = Type::NUMBER, data = { number = @(data !*float) !double } !Data } !JsonTreeNode } if tpe == double { return { tpe = Type::NUMBER, data = { number = @(data !*double) } !Data } !JsonTreeNode } - if tpe == string { return { tpe = Type::STRING, data = { str = @(data !*string) !&string } !Data } !JsonTreeNode } - if tpe == type &string { return { tpe = Type::STRING, data = { str = @(data !*&string) !&string } !Data } !JsonTreeNode } + if tpe == Str { return { tpe = Type::STRING, data = { str = @(data !*Str) } !Data } !JsonTreeNode } + //if tpe == String { return { tpe = Type::STRING, data = { str = to_str(@(data !*String)) } !Data } !JsonTreeNode } /*if tpe.kind == runtime::TypeKind::ARRAY { let vec = vector::make(JsonTreeNode) @@ -326,7 +326,7 @@ def serialize(tpe: *runtime::Type, data: *) -> JsonTreeNode { return { tpe = Type::ARRAY, children = vec } !JsonTreeNode } - assert false, @("Can't serialize type " + tpe.name) + assert false, @("Can't serialize type " + tpe.name).to_array() } export def serialize(obj: type *T) -> &Json { @@ -371,25 +371,25 @@ def deserialize(tpe: *runtime::Type, data: *, json: *JsonTreeNode) -> bool { @(data !*float) = json.data.number !float } else if tpe == double { if json.tpe != Type::NUMBER { return false } - @(data !*double) = json.data.number !double - } else if tpe == string { + @(data !*double) = json.data.number !double + } else if tpe == Str { if json.tpe != Type::STRING { return false } - @(data !*string) = @json.data.str - } else if tpe == type &string { + @(data !*Str) = json.data.str + } else if tpe == String { if json.tpe != Type::STRING { return false } - @(data !*&string) = json.data.str + @(data !*String) = json.data.str } else if tpe.kind == runtime::TypeKind::STRUCT { if json.tpe != Type::OBJECT { return false } for var i in 0..tpe.fields.size { let field = tpe.fields[i] - var name: &string = field.name + var name: String = field.name if field.name.starts_with("_") { // TODO This is no longer necessary once we can escape keywords name = field.name.substring(1) } for var j in 0..json.children.length { let child = json.children.get(j) - if @child.data.str == name { + if child.data.str == name { if not deserialize(field.tpe, data ++ field.offset, child.children.get(0)) { return false } @@ -433,15 +433,15 @@ export def deserialize(json: &Json, type T) -> Optional(T) { return optional::none(T) } -export def to_string(tree: &Json) -> &string { +export def to_string(tree: &Json) -> String { return to_string(*tree.root) } -def to_string(node: *JsonTreeNode, level: int = 1) -> &string { +def to_string(node: *JsonTreeNode, level: int = 1) -> String { if not node { return null } switch node.tpe { case Type::OBJECT, Type::ARRAY: - var res: &string = "{\n" if node.tpe == Type::OBJECT else "[\n" + var res: StringBuffer = "{\n" if node.tpe == Type::OBJECT else "[\n" if node.children { for var i in 0..node.children.length { for var j in 0..level { @@ -462,9 +462,8 @@ def to_string(node: *JsonTreeNode, level: int = 1) -> &string { case Type::NIL: return "null" case Type::STRING: - if not node.data.str { return "null" } // TODO This is really slow and doesn't escape everything yet - var ret: &string = "\"" + var ret: StringBuffer = "\"" for var i in 0..node.data.str.length() { var c = node.data.str[i] if c == '\n' { @@ -518,10 +517,6 @@ export def destruct(self: *Json) { var node = *self.root loop { if not stack.node.children { - if (stack.node.tpe == Type::KEY or stack.node.tpe == Type::STRING) and stack.node.data.str != null { - // printf("Free node: \"%s\"\n", stack.node.data.string.str) - stack.node.data.str = null - } if stack.up == null { // terminate free(stack) stack = null @@ -546,7 +541,7 @@ export def destruct(self: *Json) { } } -export def parse(str: &string) -> &Json { +export def parse(str: String) -> &Json { let node = { status = Status::JSON_EMPTY } !&Json @@ -554,8 +549,8 @@ export def parse(str: &string) -> &Json { return node } -def skip_space(text: &string, pos: size_t) -> size_t { - while isspace(text[pos]) { +def skip_space(text: String, pos: size_t) -> size_t { + while pos < text.length() and isspace(text[pos]) { pos += 1 } return pos @@ -571,11 +566,11 @@ def open(parent: *JsonTreeNode) -> *JsonTreeNode { return new } -def json_parse(self: &Json, json_text: &string) { +def json_parse(self: &Json, json_text: String) { var node = *self.root var pos: size_t = 0 pos = skip_space(json_text, pos) - if json_text[pos] == '\0' { // empty json + if pos >= json_text.length() { // empty json return } while pos < json_text.length { @@ -648,16 +643,17 @@ def json_parse(self: &Json, json_text: &string) { // after a value: pos = skip_space(json_text, pos) - next = json_text[pos] - - switch next { - case '\0': // end of file + if pos >= json_text.length() { if node.parent !* != null { self.status = Status::JSON_ERROR } else { self.status = Status::JSON_OK } return + } + + next = json_text[pos] + switch next { case ',': // next element in an array or object if node.parent.tpe == Type::ARRAY { pos = skip_space(json_text, pos + 1) @@ -701,16 +697,16 @@ def json_parse(self: &Json, json_text: &string) { } } -def parse_true_false_nil(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { - if strncmp(text.value ++ @pos, TRUE_VALUE.value, 4) == 0 { +def parse_true_false_nil(node: *JsonTreeNode, text: String, pos: *size_t) -> int { + if text.slice(@pos, text.length()).starts_with(TRUE_VALUE) { node.tpe = Type::TRUE node.data.b = 1 @pos += 4 - } else if strncmp(text.value ++ @pos, FALSE_VALUE.value, 5) == 0 { + } else if text.slice(@pos, text.length()).starts_with(FALSE_VALUE) { node.tpe = Type::FALSE node.data.b = 0 @pos += 5 - } else if strncmp(text.value ++ @pos, NIL_VALUE.value, 4) == 0 { + } else if text.slice(@pos, text.length()).starts_with(NIL_VALUE) { node.tpe = Type::NIL @pos += 4 } else { @@ -719,7 +715,7 @@ def parse_true_false_nil(node: *JsonTreeNode, text: &string, pos: *size_t) -> in return 1 } -def parse_num(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { +def parse_num(node: *JsonTreeNode, text: String, pos: *size_t) -> int { var crawl = @pos var next = text[crawl] if next == '-' { @@ -756,14 +752,15 @@ def parse_num(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { crawl += 1 next = text[crawl] } - node.data.number = strtod(text.value ++ @pos, null) + error(text.slice(@pos, text.length()).to_array(), "\n") + node.data.number = strtod(text.slice(@pos, text.length()).to_array().value, null) @pos = crawl return 1 } // if this handles multi-byte UTF8 characters weirdly it's because they have null bytes in them -def parse_str(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { - var str: &string = "" +def parse_str(node: *JsonTreeNode, text: String, pos: *size_t) -> int { + var str: StringBuffer var crawl = @pos var next = text[crawl] if next != '"' { @@ -771,6 +768,9 @@ def parse_str(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { } crawl += 1 loop { + if crawl >= text.length() { + return 0 + } next = text[crawl] if next == '"' { crawl += 1 @@ -778,6 +778,9 @@ def parse_str(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { } if next == '\\' { crawl += 1 + if crawl >= text.length() { + return 0 + } next = text[crawl] switch next { case '"', '/', '\\': @@ -823,15 +826,10 @@ def parse_str(node: *JsonTreeNode, text: &string, pos: *size_t) -> int { glyph |= append << ((1 - i) * 8) } str += utf8_encode(glyph) - case: - return 0 } crawl += 1 continue } - if next == '\0' { - return 0 - } str += next crawl += 1 } diff --git a/std/map.pr b/std/map.pr index 79f46ca..a9bfe66 100644 --- a/std/map.pr +++ b/std/map.pr @@ -20,7 +20,7 @@ export type Map(type K, type V) = struct { head: weak_ref(Entry(K, V)) } -export type SMap(type V) = Map(&string, V) +export type SMap(type V) = Map(Str, V) export def construct(copy: *Map(type K, type V), this: *Map(K, V)) { assert this.size == 0 @@ -31,15 +31,6 @@ export def destruct(map: *Map(type K, type V)) { delete(map.entries) } -export def hash(str: &string) -> size_t { - if not str { return 0 } - var r: size_t = 7 - for var i in 0..str.length { - r = r * 31 + str[i] - } - return r -} - export def hash(i: size_t) -> size_t { return i } @@ -73,7 +64,7 @@ export def make(type K, type V, size: size_t) -> &Map(K, V) { } export def make(type V, size: size_t) -> &SMap(V) { - return make(type &string, V, size) + return make(Str, V, size) } export def make(type K, type V) -> &Map(K, V) { @@ -217,8 +208,7 @@ export def size(map: &Map(type K, type V)) -> size_t { } export def keys(map: &Map(type K, type V)) -> &[K] { - let keys = zero_allocate(K, size(map)) - defer delete(keys) + let keys = allocate_ref(K, size(map)) var index = 0 var entry = map.head while entry != null { @@ -230,8 +220,7 @@ export def keys(map: &Map(type K, type V)) -> &[K] { } export def reverse_keys(map: &Map(type K, type V)) -> &[K] { - let keys = zero_allocate(K, size(map)) - defer delete(keys) + let keys = allocate_ref(K, size(map)) var index = 0 var entry = map.tail while entry != null { diff --git a/std/process.pr b/std/process.pr index 374d7fe..22b75ef 100644 --- a/std/process.pr +++ b/std/process.pr @@ -20,7 +20,7 @@ import std pi: windows::PROCESS_INFORMATION } - export def spawn(exe: &string, args: &[&string], stdin: File = null, stdout: File = null, stderr: File = null) -> Process { + export def spawn(exe: String, args: &[String], stdin: File = null, stdout: File = null, stderr: File = null) -> Process { var si: windows::STARTUPINFOA var pi: windows::PROCESS_INFORMATION @@ -47,14 +47,14 @@ import std si.dwFlags |= STARTF_USESTDHANDLES } - var cmd: &string = exe + " " + var cmd: StringBuffer = exe + " " for var arg in @args { cmd += arg + " " } if not windows::CreateProcessA( - exe.value, - cmd.value, + exe.to_array().value, + cmd.to_array().value, null, null, 1, 0 !ulong, null, null, *si, *pi ) { abort("Couldn't create process\n") } @@ -96,16 +96,21 @@ import std pid: int } - export def spawn(exe: &string, args: &[&string], + export def spawn(exe: String, args: &[String], stdin: File = null, stdout: File = null, stderr: File = null ) -> Process { var pargs = zero_allocate(type *char, args.size + 2) defer delete(pargs) - pargs[0] = exe.value + let pargs_buf = zero_allocate(type &string, args.size + 1) + defer delete(pargs_buf) + + pargs_buf[0] = exe.to_array() + pargs[0] = pargs_buf[0].value for var i in 0..args.size { - pargs[i + 1] = args[i].value + pargs_buf[i + 1] = args[i].to_array() + pargs[i + 1] = pargs_buf[i + 1].value } var pid = 0 @@ -120,7 +125,7 @@ import std linux::dup2(cstd::fileno(stderr), 2) } - linux::execvp(exe.value, pargs.value) + linux::execvp(exe.to_array().value, pargs.value) exit(1) } diff --git a/std/set.pr b/std/set.pr index 16d7919..02b80fe 100644 --- a/std/set.pr +++ b/std/set.pr @@ -6,14 +6,14 @@ import optional let sentinel = 1 !* export type Set(type T) = map::Map(T, *) -export type SSet = Set(&string) +export type SSet = Set(Str) export def make(type T) -> &Set(T) { return map::make(T, type *) } export def make() -> &SSet { - return map::make(type &string, type *) + return map::make(Str, type *) } export def add(set: &Set(type T), value: T) { diff --git a/std/shared.pr b/std/shared.pr index 4724c1d..f8a64e1 100644 --- a/std/shared.pr +++ b/std/shared.pr @@ -11,17 +11,17 @@ export type SymbolKind = enum { export type Symbol = struct { kind: SymbolKind - name: &string + name: Str value: * } export type Library = struct { - path: &string + path: Str handle: * symbols: &[Symbol] } -export def find_symbol(library: *Library, name: &string) -> Optional(Symbol) { +export def find_symbol(library: *Library, name: String) -> Optional(Symbol) { for var symbol in @library.symbols { if symbol.name == name { return optional::some(symbol) @@ -64,7 +64,7 @@ export def find_symbol(library: *Library, name: &string) -> Optional(Symbol) { return 1 } - export def load(path: &string, init: bool = true) -> Library { + export def load(path: String, init: bool = true) -> Library { windows::SymSetOptions(windows::SymGetOptions() & ~SYMOPT_UNDNAME) let dll = windows::LoadLibraryA(path.value) @@ -161,7 +161,7 @@ export def find_symbol(library: *Library, name: &string) -> Optional(Symbol) { return x & 0xF !byte } - export def load(path: &string, init: bool = true) -> Library { + export def load(path: String, init: bool = true) -> Library { let fh = open(path, "rb") if not fh { abort("Couldn't open library " + path + " (" + make_string(cstd::strerror(@linux::__errno_location())) + ")\n") @@ -172,7 +172,7 @@ export def find_symbol(library: *Library, name: &string) -> Optional(Symbol) { let size: size_t = tell(fh) rewind(fh) - let bytes = linux::mmap(null, size, 1 /*PROT_READ*/, 2 /*MAP_PRIVATE*/, linux::fileno(fh), 0) + let bytes = linux::mmap(null, size, 1 /*PROT_READ*/, 2 /*MAP_PRIVATE*/, cstd::fileno(fh), 0) defer linux::munmap(bytes, size) // Read elf header @@ -184,7 +184,7 @@ export def find_symbol(library: *Library, name: &string) -> Optional(Symbol) { elf_hdr.e_ident[3] == 'F'), "Not an ELF file" assert elf_hdr.e_type == ET_DYN, "Not a shared library" - let handle = linux::dlopen(path.value, RTLD_NOW) + let handle = linux::dlopen(path.to_array().value, RTLD_NOW) if not handle { abort("Couldn't open shared library " + path + "\n") } let symbols = vector::make(Symbol) diff --git a/std/std.pr b/std/std.pr index c9affca..3d572d7 100644 --- a/std/std.pr +++ b/std/std.pr @@ -3,21 +3,21 @@ import runtime import optional import vector +import strings +from strings export * + #if defined DEBUG_REF_CYCLES { import set import map type Root = struct { - file: string + ref: runtime::Ref + file: Str line: int } var lock = false - var ref_roots: *&map::Map(&, Root) = null // This is so that we keep the memory around - - export def hash(ref: &) -> uint64 { - return ref !* !uint64 - } + var ref_roots: *&map::Map(uint64, Root) = null // This is so that we keep the memory around // Internal methods def add_root(ref: runtime::Ref, file: *char, line: int) { @@ -25,10 +25,10 @@ import vector var l = lock lock = true if not ref_roots { - ref_roots = zero_allocate(type &map::Map(&, Root)) - @ref_roots = map::make(type &, Root) + ref_roots = zero_allocate(type &map::Map(uint64, Root)) + @ref_roots = map::make(uint64, Root) } - (@ref_roots)[ref] = { make_string(file), line } !Root + (@ref_roots)[ref.value !uint64] = { ref, make_string(file), line } !Root lock = l } @@ -37,62 +37,136 @@ import vector if not ref_roots { return } var l = lock lock = true - (@ref_roots).remove(ref) + (@ref_roots).remove(ref.value !uint64) lock = l } - def find_cycle_root(ref: &, n: int, all: &Set(&)) -> bool { + def find_cycle_root(ref: uint64, n: *int, all: &Set(uint64), children: &Set(uint64)) -> uint64 { let root = (@ref_roots)[ref] - let visited = set::make(type &) - visited.add(ref) - let cycle = find_cycle(n, root, ref, visited, all) + let visited = set::make(uint64) + let cycle = find_cycle(n, root.ref, visited, all, children) if cycle { - error("Cycle root: ", root.file + "@" + root.line, " (", ref !*, ") \n") + error("Cycle root: ", ref_type(root.ref).tpe.name, " ", root.file + "@" + root.line, " (", ref !*, ") \n") } + all.add(ref) return cycle } - def find_cycle(n: int, root: Root, cur: &, visited: &Set(&), all: &Set(&)) -> bool { - if all.contains(cur) { return false } - all.add(cur) - let tpe = ref_type(cur).tpe - if tpe.kind == runtime::TypeKind::STRUCT { + def copy(cur: &Set(uint64)) -> &Set(uint64) { + let new_map = set::make(uint64) + let keys = cur.keys() + for var i in 0..keys.size { + let key = keys[i] + new_map.add(key) + } + return new_map + } + + def find_cycle(tpe: *runtime::Type, n: *int, cur: *, visited: &Set(uint64), all: &Set(uint64), children: &Set(uint64)) -> uint64 { + if tpe.kind == runtime::TypeKind::REFERENCE { + let ref = @(cur !*runtime::Ref) + let cycle = find_cycle(n, ref, copy(visited), all, children) + children.add(ref.value !uint64) + return cycle + } else if tpe.kind == runtime::TypeKind::STRUCT or tpe.kind == runtime::TypeKind::UNION { for var i in 0..tpe.fields.size { let field = tpe.fields[i] - if field.tpe.kind == runtime::TypeKind::REFERENCE { - let ref = @(((cur !*) ++ field.offset) !*&) - let new_cycle = visited.contains(ref) - visited.add(ref) - if new_cycle { - error(">>> Cycle " + n, "\n") - return true - } - if find_cycle(n, root, ref, visited, all) { - error("-> ", tpe.name + "::", field.name, " (", ref !*, ")\n") - return true - } + + let value = cur ++ field.offset + let cycle = find_cycle(field.tpe, n, value, copy(visited), all, children) + if cycle { + error("-> ", field.tpe.name, ".", field.name, "\n") + return cycle + } + } + } else if tpe.kind == runtime::TypeKind::STATIC_ARRAY { + for var i in 0..tpe.length { + let child = cur ++ (i * tpe.tpe.size) + let cycle = find_cycle(tpe.tpe, n, child, copy(visited), all, children) + if cycle { + error("-> ", tpe.name, "[", i, "]\n") + return cycle + } + } + } else if tpe.kind == runtime::TypeKind::ARRAY { + let value = @(cur !*[int8]) + for var i in 0..value.size { + let child = value.value ++ (i * tpe.tpe.size) + let cycle = find_cycle(tpe.tpe, n, child, copy(visited), all, children) + if cycle { + error("-> ", tpe.name, "[", i, "]\n") + return cycle } } } - return false + return 0 + } + + def find_cycle(n: *int, cur: runtime::Ref, visited: &Set(uint64), all: &Set(uint64), children: &Set(uint64)) -> uint64 { + if cur.value == null or not (@ref_roots).contains(cur.value !uint64) { + return 0 + } + + if visited.contains(cur.value !uint64) { + error("\n>>> Cycle ", @n, "\n") + @n += 1 + return cur.value !uint64 + } + + var cycle: uint64 = 0 + visited.add(cur.value !uint64) + if not all.contains(cur.value !uint64) { + let rtpe = ref_type(cur) + if rtpe and rtpe.tpe { + cycle = find_cycle(rtpe.tpe, n, cur.value, visited, all, children) + } + } + all.add(cur.value !uint64) + return cycle } def find_cycles_impl { + if not ref_roots { + error("No roots found! No references were leaked\n") + return + } error("Starting cycle finder...\n") + let num_roots = (@ref_roots).size + error(num_roots, " roots found\n") let keys = (@ref_roots).keys() - let all = set::make(type &) + let all = set::make(uint64) + let children = set::make(uint64) var n = 1 for var i in 0..keys.size { - let root = keys[i] - if find_cycle_root(root, n, all) { - n += 1 - } + let ref = keys[i] + if not ref { continue } + let root = (@ref_roots)[ref] + cstd::printf("[%*d/%d] ".value, 1 + log10(num_roots) !int, i + 1, num_roots) + let prev_n = n + print(ref !*, ": ", root.ref.tpe.name, " (" , @root.ref.ref_count, ")") + fflush(stdout()) + + find_cycle_root(ref, *n, all, children) + print("\x1B[2K\r") } + print("\n") if n == 1 { error("No cycles found!\n") } else { error(n - 1, " cycles found!\n") } + + var m = 0 + for var i in 0..keys.size { + let ref = keys[i] + if not ref { continue } + if not children.contains(ref) { + let root = (@ref_roots)[ref] + error("No reference to ", ref !*, ": ", root.ref.tpe.name, " ", root.file, "@", root.line, " (", @root.ref.ref_count, ")\n") + m += 1 + } + } + error(m, " out of ", keys.size, " references weren't reachable.\n") } export def find_cycles { @@ -169,9 +243,9 @@ export def combine_hashes(hashes: uint64...) -> uint64 { return hash } -export def parse_int(str: &string) -> int { +export def parse_int(str: String) -> int { var end: *char - return cstd::strtol(str.value, *end, 10) !int + return cstd::strtol(str.to_array().value, *end, 10) !int } // Iterate references to array @@ -191,396 +265,6 @@ export def to_array(gen: &runtime::Generator(type T)) -> &[T] { return vec.to_array() } -// String functions -export def make_string(ptr: *char) -> string { - var s: string - s.value = ptr - s.size = strlen(ptr) + 1 - return s -} - -export def remove(str: &string, i: size_t) { - assert i < str.length() - if str.size > 0 { - cstd::memmove(str.value ++ i, str.value ++ i ++ 1, str.length() - i) - } - str.size -= 1 - str.value[str.size - 1] = '\0' -} - -export def remove(str: &string, start: size_t, end: size_t) { - if start == end { - remove(str, start) - return - } - assert end > start - assert start < str.length() - assert end < str.length() - - let len = end - start + 1 - if str.size > 0 { - cstd::memmove(str.value ++ start, str.value ++ end ++ 1, str.length() - len - start) - } - str.size -= len - str.value[str.size - 1] = '\0' -} - -export def insert(str: &string, i: size_t, s: &string) { - if s.length() == 0 { return } - assert i < str.length() - - let new_size = str.size + length(s) !size_t - str.value = reallocate(str.value, (size_of char) * new_size) - - if str.size >= 1 { - cstd::memmove(str.value ++ i ++ length(s), str.value ++ i, str.size - i) - } - memcopy(s.value, str.value ++ i, length(s)) - str.size = new_size -} - -export def insert(str: &string, i: size_t, c: char) { - let new_size = str.size + 1 !size_t - str.value = reallocate(str.value, (size_of char) * new_size) - - if str.size >= 1 { - cstd::memmove(str.value ++ i ++ 1, str.value ++ i, str.size - i) - } - str.value[i] = c - str.size = new_size -} - -export def substring(str: &string, start: size_t, end: size_t) -> &string { - assert end >= start - assert end <= str.length - assert start >= 0 - - var substr: string - substr.size = end - start - substr.value = str.value ++ start - var res: &string = substr - res.value = reallocate(res.value, res.size + 1) - res.value[res.size] = '\0' - res.size += 1 - return res -} - -export def substring(str: &string, start: size_t) -> &string { - return substring(str, start, str.length) -} - -export def index_of(str: &string, substring: &string, start: size_t = 0) -> int64 { - assert start < str.length - for var i in start..str.length { - let c = str[i] - if c == substring[0] { - var found = true - for var j in 0..substring.length { - if i + j >= str.length { return -1 } - if str[i + j] != substring[j] { - found = false - break - } - } - if found { return i } - } - } - return -1 -} - -export def last_index_of(str: &string, substring: &string) -> int64 { - for var i in 0..str.length { - var k = str.length - i - 1 - let c = str[k] - if c == substring[0] { - var found = true - for var j in 0..substring.length { - if k + j >= str.length { return -1 } - if str[k + j] != substring[j] { - found = false - break - } - } - if found { return k } - } - } - return -1 -} - -export def ends_with(str: &string, suffix: &string) -> bool { - let index = last_index_of(str, suffix) - if index < 0 { return false } - return index == str.length - suffix.length -} - -export def starts_with(str: &string, pre: &string) -> bool { - return (cstd::strncmp(pre.value, str.value, cstd::strlen(pre.value)) == 0) !bool -} - -export def strip_margin(s: &string) -> &string { - var res: &string = "" - let len = length(s) - - var i = 0 - while i < len { - var c = s[i] - if c == '\n' or i == 0 { - if c == '\n' { - res += '\n' - } - i += 1; c = s[i] - while (c == ' ' or c == '\t') and (i + 1) < len { - i += 1; c = s[i] - } - if c == '|' and (i + 1) < len { - i += 1 - continue - } - } - res += c - i += 1 - } - return res -} - -// https://stackoverflow.com/a/23457543/3258949 -// TODO This algorithm is very inefficient - -def match(pattern: &string, candidate: &string, p: int, c: int) -> bool { - if pattern[p] == '\0' { - return candidate[c] == '\0' - } else if pattern[p] == '*' { - while candidate[c] != '\0' { - if match(pattern, candidate, p + 1, c) { - return true - } - c += 1 - } - return match(pattern, candidate, p + 1, c) - } else if pattern[p] != '?' and pattern[p] != candidate[c] { - return false - } else { - return match(pattern, candidate, p + 1, c + 1) - } -} - -export def match(pattern: &string, candidate: &string) -> bool { - return match(pattern, candidate, 0, 0) -} - -export type ToString = interface { - def to_string -> &string -} - -// TODO remove special casing this -export def == (a: string, b: string) -> bool { - return strncmp(a.value, b.value, max(a.size - 1, b.size - 1) !size_t) == 0 -} - -export def != (a: string, b: string) -> bool { - return not (a == b) -} - -export def == (a: string, b: &string) -> bool { - if b { return a == @b } - return false -} - -export def != (a: string, b: &string) -> bool { - return not (a == b) -} - -export def == (a: &string, b: string) -> bool { - if a { return @a == b } - return false -} - -export def != (a: &string, b: string) -> bool { - return not (a == b) -} - -export def == (a: &string, b: &string) -> bool { - if not a and not b { return true } - if not a or not b { return false } - return @a == @b -} - -export def != (a: &string, b: &string) -> bool { - return not (a == b) -} - -export def + (a: &string, b: &string) -> &string { - if not b { return a + "null" } - let ret = allocate(char, a.size + b.size - 1) - defer delete(ret) - memcopy(a.value, ret.value, a.size - 1) - memcopy(b.value, ret.value ++ (a.size - 1), b.size) - return ret !&string -} - -export def += (a: &string, b: &string) -> &string { - return a + b -} - -export def + (a: &string, b: &ToString) -> &string { - return a + b.to_string() -} - -export def += (a: &string, b: &ToString) -> &string { - return a + b -} - -export def + (a: &ToString, b: &string) -> &string { - return a.to_string() + b -} - -// These are defined for better performance -export def + (a: char, b: &string) -> &string { - let ret = zero_allocate(char, b.size + 1) - defer delete(ret) - memcopy(b.value, ret.value ++ 1, b.size) - ret[0] = a - return ret !&string -} - -export def + (a: &string, b: char) -> &string { - let ret = zero_allocate(char, a.size + 1) - defer delete(ret) - memcopy(a.value, ret.value, a.size) - ret[ret.size - 2] = b - return ret !&string -} - -export def += (a: &string, b: char) -> &string { - return a + b -} - -export def to_string(sign: int, n: uint64) -> &string { - let digits = "0123456789" - - var str: &string = "" - if n == 0 { - str += '0' - return str - } - - while n { - str = digits[n % 10] + str - n /= 10 - } - - if sign < 0 { - str = '-' + str - } - - return str -} - -export def to_string(a: &int64) -> &string { - let n = -@a if @a < 0 else @a - return to_string(1 if @a >= 0 else -1, n) -} - -export def to_string(a: &int32) -> &string { - let n = -@a if @a < 0 else @a - return to_string(1 if @a >= 0 else -1, n) -} - -export def to_string(a: &int16) -> &string { - let n = -@a if @a < 0 else @a - return to_string(1 if @a >= 0 else -1, n) -} - -export def to_string(a: &int8) -> &string { - let n = -@a if @a < 0 else @a - return to_string(1 if @a >= 0 else -1, n) -} - -export def to_string(a: &uint64) -> &string { - return to_string(0, @a) -} - -export def to_string(a: &uint32) -> &string { - return to_string(0, @a) -} - -export def to_string(a: &uint16) -> &string { - return to_string(0, @a) -} - -export def to_string(a: &uint8) -> &string { - return to_string(0, @a) -} - -export def to_string(a: &bool) -> &string { - return "true" if @a else "false" -} - -export def to_string(a: &char) -> &string { - return [@a] -} - -export def utf8_encode(code_point: uint64) -> &string { - var res: &string = "" - if code_point <= 0x007F { - res += code_point !char - } else if code_point <= 0x07FF { - res += ((code_point >> 6) | 0b11000000) !char - res += (code_point & 0b00111111 | 0b10000000) !char - } else if code_point <= 0xFFFF { - res += ((code_point >> 12) | 0b11100000) !char - res += ((code_point >> 6 & 0b00111111) | 0b10000000) !char - res += (code_point & 0b00111111 | 0b10000000) !char - } else if code_point <= 0x10FFFF { - res += ((code_point >> 18) | 0b11110000) !char - res += ((code_point >> 12 & 0b00111111) | 0b10000000) !char - res += ((code_point >> 6 & 0b00111111) | 0b10000000) !char - res += (code_point & 0b00111111 | 0b10000000) !char - } - return res -} - -export def int_to_hex_str(n: uint64, prefix: bool = true) -> &string { - let digits = "0123456789ABCDEF" - - if n == 0 { - return "0x0" - } - - var str: &string = "" - while n { - str = digits[n % 16] + str - n /= 16 - } - if prefix { - str = "0x" + str - } - - return str -} - -// TODO Implement these properly -const DOUBLE_MAX_EXP_10 = 308 -const FLOAT_MAX_EXP_10 = 38 - -export def to_string(value: &float) -> &string { - const size = FLOAT_MAX_EXP_10 + 20 - var buf: [size; char] - cstd::snprintf(buf.value, size, "%f".value, @value) - let str: &string = buf - str.size = cstd::strlen(buf.value) - return str -} - -export def to_string(value: &double) -> &string { - const size = DOUBLE_MAX_EXP_10 + 20 - var buf: [size; char] - cstd::snprintf(buf.value, size, "%f".value, @value) - let str: &string = buf - str.size = cstd::strlen(buf.value) - return str -} - export def print(args: &...) -> int { return fprint(stdout(), args) } @@ -604,9 +288,27 @@ def print_val(file: File, ref: runtime::Ref) -> int { if not tpe or not value { return cstd::fprintf(file, "%p".value, value) } else if tpe == string { - return cstd::fprintf(file, "%s".value, (@(value !*string)).value) + let str = value !*string + cstd::fputs(str.value, file) + return (str.size - 1) !int } else if tpe.kind == runtime::TypeKind::STATIC_ARRAY and tpe.tpe == char { return cstd::fprintf(file, "%s".value, value !*char) + } else if tpe == StringSlice { + let slc = ref !&StringSlice + if slc.data { + cstd::fwrite(slc.data ++ slc.offset, 1, slc.count, file) + } else { + for var c in slc.chars() { + cstd::putc(c, file) + } + } + return slc.count !int + } else if tpe == Str { + let str = value !*Str + cstd::fwrite(get_internal_buffer(str), 1, length(@str), file) + return length(@str) !int + } else if tpe == StringBuffer { + fprint(file, to_string(@(value !*StringBuffer))) } else if tpe == type *char { return cstd::fprintf(file, "%s".value, @(value !**char)) } else if tpe == size_t { @@ -695,7 +397,13 @@ def print_val(file: File, ref: runtime::Ref) -> int { return cstd::fprintf(file, "%s".value, str.value) } else if runtime::implements(reftpe, ToString) { let str = (ref !&ToString).to_string() - return cstd::fprintf(file, "%s".value, (@str).value) + return print_val(file, str !Ref) + } else if runtime::implements(reftpe, IString) { + let str = (ref !String) + for var c in str.chars() { + cstd::putc(c, file) + } + return str.length() !int } else if tpe.kind == runtime::TypeKind::STRUCT or tpe.kind == runtime::TypeKind::UNION { let fields = tpe.fields var sum = 0 @@ -730,12 +438,14 @@ export def fprint(file: File, args: &...) -> int { return sum } -export def abort(s: &string) { - abort(@s) +// Optimized version +export def fprint(file: File, str: Str) -> int { + cstd::fwrite(get_internal_buffer(*str), 1, length(str), file) + return length(str) !int } -export def abort(s: string) { - cstd::fprintf(stderr(), "%s\n".value, s.value) +export def abort(s: String) { + fprint(stderr(), s) cstd::abort() } @@ -743,7 +453,7 @@ export def delete(v: type *T) { #if defined __destruct__::(*T) { __destruct__(v) } - free(v) + cstd::free(v) } export def delete(v: type [T]) { @@ -753,7 +463,7 @@ export def delete(v: type [T]) { __destruct__(*v[i]) } } - free(v.value) + cstd::free(v.value) } export def new(t: type T) -> *T { @@ -767,14 +477,6 @@ export def concat(base: string, to_append: string) { cstd::memcpy(base.value ++ strlen(base.value), to_append.value, to_append.size) } -export def length(s: string) -> size_t { - return s.size - 1 -} - -export def length(s: &string) -> size_t { - return s.size - 1 -} - // Allocators export def allocate(size: size_t) -> * { return cstd::malloc(size) @@ -810,7 +512,7 @@ export def allocate_ref(type T, size: size_t) -> &[T] { var arr: [T] arr.size = size arr.value = cstd::calloc(size, T.size) !*T - defer free(arr.value) + defer cstd::free(arr.value) return arr !&[T] } @@ -826,12 +528,12 @@ export def free(value: type [T]) { // File functions -export def open(file_path: &string, mode: &string) -> File { - return cstd::fopen(file_path.value, mode.value) +export def open(file_path: String, mode: String) -> File { + return cstd::fopen(file_path.to_array().value, mode.to_array().value) } -export def reopen(file_path: &string, mode: &string, file: File) -> File { - return cstd::freopen(file_path.value, mode.value, file) +export def reopen(file_path: String, mode: String, file: File) -> File { + return cstd::freopen(file_path.to_array().value, mode.to_array().value, file) } export def close(file: File) -> int { @@ -851,12 +553,13 @@ export def read(file: File, ptr: type *T) -> size_t { return cstd::fread(ptr, T.size, 1, file) } -export def read_str(file: File) -> &string { +export def read_str(file: File) -> Str { var len: size_t file.read(*len) - if len == 0 { return null } - let buf = allocate_ref(char, len) - read(file, @buf, len) + if len == 0 { return {} !Str } + let buf = allocate(char, len + 1) + defer delete(buf) + read(file, buf, len) return buf } @@ -884,12 +587,12 @@ export def write(file: File, c: char) -> size_t { return cstd::fwrite(*c, 1, 1, file) } -export def write_str(file: File, str: &string) -> size_t { +export def write_str(file: File, str: String) -> size_t { if not str { let zero: size_t = 0 return write(file, *zero) } - return write(file, *str.size) + write(file, @str) + return write(file, *str.length()) + write(file, str.to_array().value) } // Deprecated @@ -925,51 +628,47 @@ export def memcopy(src: *, dest: *, size: size_t) -> * { return cstd::memcpy(dest, src, size) } -export def system(command: &string) -> int { - return cstd::system(command.value) +export def system(command: String) -> int { + return cstd::system(command.to_array().value) } -export def getenv(str: &string) -> &string { - let env = cstd::getenv(str.value) +export def getenv(str: String) -> Str { + let env = cstd::getenv(str.to_array().value) if env { return make_string(env) } - return null + return {} !Str } -export def mkdir(path: &string) { +export def mkdir(path: String) { #if defined WIN32 { - windows::CreateDirectoryA(path.value, null) + windows::CreateDirectoryA(path.to_array().value, null) } else { - linux::mkdir(path.value, 0o755 !ushort) // TODO MACOS + linux::mkdir(path.to_array().value, 0o755 !ushort) // TODO MACOS } } -export def dirname(file: &string) -> &string { +export def dirname(file: String) -> Str { var last_slash = -1 - for var i in 0..file.size { + for var i in 0..file.length() { let c = file[i] if c == '/' or c == '\\' { last_slash = i } } - let ret = allocate_ref(char, last_slash + 2) - memcopy(file.value, ret.value, last_slash + 1) - return ret + return file.substring(0, last_slash + 1) } -export def basename(file: &string) -> &string { +export def basename(file: String) -> Str { var last_slash = 0 - for var i in 0..file.size { + for var i in 0..file.length() { let c = file[i] if c == '/' or c == '\\' { last_slash = i } } - let ret = allocate_ref(char, file.size - last_slash) - memcopy(file.value ++ last_slash, ret.value, file.size - last_slash) - return ret + return file.substring(last_slash, file.length()) } -export def executable_file -> &string { +export def executable_file -> Str { let resolved = zero_allocate(char, PATH_MAX) defer delete(resolved) #if defined WIN32 { @@ -986,38 +685,39 @@ export def executable_file -> &string { return resolved } -export def absolute_path(pathname: &string) -> &string { +export def absolute_path(pathname: String) -> Str { let resolved = zero_allocate(char, PATH_MAX) defer delete(resolved) #if defined WIN32 { - windows::GetFullPathNameA(pathname.value, PATH_MAX, resolved.value, null) + windows::GetFullPathNameA(pathname.to_array().value, PATH_MAX, resolved.value, null) } else { - linux::realpath(pathname.value, resolved.value) + linux::realpath(pathname.to_array().value, resolved.value) } return make_string(resolved.value) } -export def tmpfolder(name: &string) -> &string { +export def tmpfolder(name: String) -> Str { + let cstr = name.to_array() #if defined WIN32 { // TODO We shouldn't ignore the name let path = allocate(char, PATH_MAX) defer delete(path) windows::GetTempPathA(PATH_MAX, path.value) - concat(path, @name) + concat(path, @cstr) windows::CreateDirectoryA(path.value, null) return make_string(path.value) } else { let path = zero_allocate(char, PATH_MAX) defer delete(path) concat(path, "/tmp/") - concat(path, @name) + concat(path, @cstr) concat(path, ".XXXXXX") path.size = strlen(path) + 1 return make_string(linux::mkdtemp(path.value)) } } -export def read_all(fh: File) -> &string { +export def read_all(fh: File) -> Str { seek(fh, 0, SEEK_END) let filesize = tell(fh) rewind(fh) @@ -1029,8 +729,8 @@ export def read_all(fh: File) -> &string { return buf } -export def read_all_pipe(pipe: File) -> &string { - var res: &string = "" +export def read_all_pipe(pipe: File) -> Str { + var res: StringBuffer = "" var c: char while read(pipe, *c) { res += c diff --git a/std/strings.pr b/std/strings.pr new file mode 100644 index 0000000..d229908 --- /dev/null +++ b/std/strings.pr @@ -0,0 +1,736 @@ +import cstd +import std +import runtime +import optional + +export def length(s: [char]) -> size_t { + return s.size - 1 +} +export def length(s: &[char]) -> size_t { + return s.size - 1 +} +export def get_item(s: &[char], i: size_t) -> char { + return s.value[i] +} + +type LongString = struct { + refcount: *uint64 + data: *char + count: size_t +} + +const SHORT_STR_LEN = (size_of LongString) - 1 +const LONG_STR_BIT = 1 !size_t << 63 + +type ShortString = struct { + data: [SHORT_STR_LEN; char] + count: ubyte +} + +export type Str = struct #union { + long_str: LongString + short_str: ShortString +} + +export def hash(str: Str) -> size_t { + var r: size_t = 7 + let buf = get_internal_buffer(*str) + for var i in 0..str.length { + r = r * 31 + buf[i] + } + return r +} + +export implicit def to_bool(s: Str) -> bool { + return s.length() != 0 +} + +export def is_short_str(s: *Str) -> bool { + return (s.long_str.count & LONG_STR_BIT) == 0 +} + +export def get_internal_buffer(s: *Str) -> *char { + if is_short_str(s) { + return s.short_str.data.value + } else { + return s.long_str.data + } +} + +export implicit def to_str(s: &string) -> Str { + return to_str(@s) +} + +export implicit def to_str(s: string) -> Str { + return to_str(s.length(), s.value) +} + +export def to_str(len: size_t, value: *char) -> Str { + var res: Str + if len <= SHORT_STR_LEN { + res.short_str.count = len !ubyte + memcopy(value, res.short_str.data.value, len) + } else { + res.long_str.count = len | LONG_STR_BIT + res.long_str.refcount = allocate(uint64) + @res.long_str.refcount = 1 + res.long_str.data = allocate(len) !*char + memcopy(value, res.long_str.data, len) + } + return res +} + +export implicit def to_str(s: String) -> Str { + if not s { return {} !Str } + if ref_type(s) == type &Str { + return @(s !&Str) + } else if ref_type(s) == type &[char] { + return to_str(s !&[char]) + } else if ref_type(s) == type &StringSlice { + let slice = s !&StringSlice + return to_str(@slice) + } else { + let len = s.length() + var res: Str + var data: *char + if len <= SHORT_STR_LEN { + res.short_str.count = len !ubyte + data = res.short_str.data.value + } else { + res.long_str.count = len | LONG_STR_BIT + res.long_str.refcount = allocate(uint64) + @res.long_str.refcount = 1 + res.long_str.data = data = allocate(len) !*char + } + for var i in 0..len { + data[i] = s[i] + } + return res + } +} + +export def length(s: Str) -> size_t { + if is_short_str(*s) { + return s.short_str.count + } else { + return s.long_str.count & ~LONG_STR_BIT + } +} +export def length(s: &Str) -> size_t { + return length(@s) +} + +export def get_item(s: Str, i: size_t) -> char { + return get_internal_buffer(*s)[i] +} +export def get_item(s: &Str, i: size_t) -> char { + return get_internal_buffer(s !*Str)[i] +} + +export def construct(copy: *Str, this: *Str) { + if is_short_str(this) { + copy.short_str = this.short_str + } else { + copy.long_str = this.long_str + @copy.long_str.refcount += 1 + } +} + +export def destruct(this: *Str) { + if not is_short_str(this) { + @this.long_str.refcount -= 1 + if @this.long_str.refcount == 0 { + delete(this.long_str.refcount) + delete(this.long_str.data) + } + } +} + +export type StringBuffer = struct { + prev: &StringBuffer + data: Str + offset: size_t +} + +export def length(s: StringBuffer) -> size_t { + return s.offset + s.data.length() +} + +export implicit def to_str(s: StringBuffer) -> Str { + let count = s.offset + s.data.length() + let data = allocate(count) !*char + defer delete(data) + memcopy(get_internal_buffer(*s.data), data ++ s.offset, s.data.length()) + var prev = s.prev + while prev { + memcopy(get_internal_buffer(*prev.data), data ++ prev.offset, prev.data.length()) + prev = prev.prev + } + return to_str(count, data) +} + +export implicit def to_buffer(s: String) -> StringBuffer { + return { null, to_str(s), 0 } !StringBuffer +} + +export implicit def to_buffer(s: Str) -> StringBuffer { + return { null, s, 0 } !StringBuffer +} + +export implicit def to_buffer(s: StringSlice) -> StringBuffer { + return { null, to_str(s), 0 } !StringBuffer +} + +export implicit def to_buffer(s: &string) -> StringBuffer { + return { null, to_str(s), 0 } !StringBuffer +} + +export implicit def to_buffer(s: string) -> StringBuffer { + return { null, to_str(s), 0 } !StringBuffer +} + +export def + (s: StringBuffer, o: &ToString) -> StringBuffer { + return { s, o.to_string().to_str(), s.offset + s.data.length() } !StringBuffer +} + +export def + (s: StringBuffer, o: Str) -> StringBuffer { + return { s, o, s.offset + s.data.length() } !StringBuffer +} + +export def + (s: StringBuffer, o: StringSlice) -> StringBuffer { + return { s, o.to_str(), s.offset + s.data.length() } !StringBuffer +} + +export def + (s: StringBuffer, o: String) -> StringBuffer { + return { s, o.to_str(), s.offset + s.data.length() } !StringBuffer +} + +export def + (s: StringBuffer, o: &string) -> StringBuffer { + return { s, o.to_str(), s.offset + s.data.length() } !StringBuffer +} + +export def + (s: StringBuffer, o: string) -> StringBuffer { + return { s, o.to_str(), s.offset + s.data.length() } !StringBuffer +} + +export def + (s: &ToString, o: StringBuffer) -> StringBuffer { + let buf = to_buffer(s.to_string()) + return buf + o +} + +/*export def + (s: String, o: StringBuffer) -> StringBuffer { + return { to_buffer(s), to_str(o), s.length() } !StringBuffer +}*/ + +export def + (s: StringBuffer, o: StringBuffer) -> StringBuffer { + let offset = s.length() + if o.prev { + o.prev = @o.prev + o.prev.offset += offset + var c = o.prev + while c.prev { + c.prev = @c.prev + c.prev.offset += offset + c = c.prev + } + c.prev = s + } else { + o.prev = s + } + o.offset += offset + return o +} + +export def += (s: StringBuffer, o: &ToString) -> StringBuffer { + return s + o.to_string() +} + +export def += (s: StringBuffer, o: String) -> StringBuffer { + return s + o +} + +export def += (s: StringBuffer, o: StringBuffer) -> StringBuffer { + return s + o +} + +export implicit def to_string(s: StringBuffer) -> String { + return to_str(s) +} + +export implicit def to_string(s: string) -> String { + return { data = s.value, count = s.length() } !StringSlice +} + +export implicit def to_string(s: &string) -> String { + if not s { return null } + return to_str(s) +} + +export type StringSlice = struct { + parent: String + data: *char + offset: size_t + count: size_t +} + +export implicit def to_bool(s: StringSlice) -> bool { + return s.length() != 0 +} + +export def length(s: StringSlice) -> size_t { + return s.count +} +export def length(s: &StringSlice) -> size_t { + return s.count +} +export def get_item(s: StringSlice, i: size_t) -> char { + return s.data[i + s.offset] if s.data else get_item(s.parent, s.offset + i) +} +export def get_item(s: &StringSlice, i: size_t) -> char { + return get_item(@s, i) +} + +export implicit def to_str(s: StringSlice) -> Str { + if s.count == 0 { return {} !Str } + if s.data { + return to_str(s.count, s.data ++ s.offset) + } else { + return s.parent.substring(s.offset, s.offset + s.count) + } +} + +export type IString = interface { + def length() -> size_t + def get_item(i: size_t) -> char +} + +export type String = &IString + +// TODO Maybe condense these somehow? +export def == (s1: IString, s2: IString) -> bool { + if not s1 and not s2 { return true } + if not s1 or not s2 { return false } + if s1.length() != s2.length() { return false } + for var i in 0..s1.length() { + if s1[i] != s2[i] { return false } + } + return true +} +export def == (s1: IString, s2: [char]) -> bool { + if not s1 and s2.length() == 0 { return true } + if not s1 { return false } + if s1.length() != s2.length() { return false } + for var i in 0..s1.length() { + if s1[i] != s2[i] { return false } + } + return true +} +export def == (s1: [char], s2: IString) -> bool { + if not s2 and s1.length() == 0 { return true } + if not s2 { return false } + if s1.length() != s2.length() { return false } + for var i in 0..s1.length() { + if s1[i] != s2[i] { return false } + } + return true +} +export def == (s1: [char], s2: [char]) -> bool { + if s1.length() != s2.length() { return false } + for var i in 0..s1.length() { + if s1[i] != s2[i] { return false } + } + return true +} +export def == (s1: Str, s2: Str) -> bool { + if s1.length() != s2.length() { return false } + return cstd::memcmp(get_internal_buffer(*s1), get_internal_buffer(*s2), s1.length()) == 0 +} + +export def != (s1: IString, s2: IString) -> bool { + return not (s1 == s2) +} +export def != (s1: IString, s2: [char]) -> bool { + return not (s1 == s2) +} +export def != (s1: [char], s2: IString) -> bool { + return not (s1 == s2) +} +export def != (s1: [char], s2: [char]) -> bool { + return not (s1 == s2) +} +export def != (s1: Str, s2: Str) -> bool { + return not (s1 == s2) +} + +export implicit def to_slice(s: [char]) -> StringSlice { + return slice(s, 0, s.length()) +} + +export implicit def to_slice(s: String) -> StringSlice { + return slice(s, 0, s.length()) +} + +export implicit def to_slice(s: Str) -> StringSlice { + return slice(s, 0, s.length()) +} + +export def slice(s: [char], frm: size_t, to: size_t) -> StringSlice { + return { count = to - frm, offset = frm, data = s.value } !StringSlice +} + +export def slice(s: Str, frm: size_t, to: size_t) -> StringSlice { + let sref = s !&Str + return { parent = sref, count = to - frm, data = get_internal_buffer(sref !*Str), offset = frm } !StringSlice +} + +export def slice(s: String, frm: size_t, to: size_t) -> StringSlice { + if ref_type(s) == type &[char] { + return { parent = s, count = to - frm, offset = frm, data = (s !&[char]).value } !StringSlice + } else if ref_type(s) == type &StringSlice { + let slc = s !&StringSlice + if slc.data { + return { parent = slc.parent, count = to - frm, offset = frm + slc.offset, data = slc.data } !StringSlice + } else { + return { parent = slc.parent, count = to - frm, offset = frm + slc.offset } !StringSlice + } + } else if ref_type(s) == type &Str { + return { parent = s, count = to - frm, data = get_internal_buffer(s !*Str), offset = frm } !StringSlice + } else { + return { parent = s, count = to - frm, offset = frm} !StringSlice + } +} + +// Returns a 0 terminated array +export def to_array(s: String) -> &[char] { + if ref_type(s) == type &[char] { + return s !&[char] + } else if ref_type(s) == type &Str { + let str = s !&Str + let res = allocate_ref(char, str.length() + 1) + memcopy(get_internal_buffer(str !*Str), res.value, str.length()) + res[str.length()] = '\0' + return res + } else if ref_type(s) == type &StringSlice { + let slc = s !&StringSlice + if slc.data { + let res = allocate_ref(char, s.length() + 1) + memcopy(slc.data ++ slc.offset, res.value, s.length()) + res[s.length()] = '\0' + return res + } else { + return to_str(slc).to_array() + } + } else { + let res = allocate_ref(char, s.length() + 1) + for var i in 0..s.length() { + res[i] = s[i] + } + res[s.length()] = '\0' + return res + } +} + +export def chars(s: String) -> char { + for var i in 0..s.length() { + yield s[i] + } +} + +export def to_string(sign: int, n: uint64) -> String { + let digits = "0123456789" + + if n == 0 { + return "0" + } + + let num_digits = (1 + floor(log10(n))) !int + let buf = zero_allocate(char, num_digits + (2 if sign < 0 else 1)) + defer delete(buf) + + var i = num_digits if sign < 0 else num_digits - 1 + while n { + buf[i] = digits[n % 10] + n /= 10 + i -= 1 + } + + if sign < 0 { + buf[0] = '-' + } + + return to_str(buf) +} + +// TODO return Str +export type ToString = interface { + def to_string -> String +} + +export def to_string(a: &int64) -> String { + let n = -@a if @a < 0 else @a + return to_string(1 if @a >= 0 else -1, n) +} + +export def to_string(a: &int32) -> String { + let n = -@a if @a < 0 else @a + return to_string(1 if @a >= 0 else -1, n) +} + +export def to_string(a: &int16) -> String { + let n = -@a if @a < 0 else @a + return to_string(1 if @a >= 0 else -1, n) +} + +export def to_string(a: &int8) -> String { + let n = -@a if @a < 0 else @a + return to_string(1 if @a >= 0 else -1, n) +} + +export def to_string(a: &uint64) -> String { + return to_string(0, @a) +} + +export def to_string(a: &uint32) -> String { + return to_string(0, @a) +} + +export def to_string(a: &uint16) -> String { + return to_string(0, @a) +} + +export def to_string(a: &uint8) -> String { + return to_string(0, @a) +} + +export def to_string(a: &bool) -> String { + return "true" if @a else "false" +} + +export def to_string(a: &char) -> String { + return to_str([@a, '\0']) +} + +// TODO Implement these properly +const DOUBLE_MAX_EXP_10 = 308 +const FLOAT_MAX_EXP_10 = 38 + +export def to_string(value: &float) -> String { + const size = FLOAT_MAX_EXP_10 + 20 + var buf: [size; char] + cstd::snprintf(buf.value, size, "%f".value, @value) + return to_str(cstd::strlen(buf.value), buf.value) +} + +export def to_string(value: &double) -> String { + const size = DOUBLE_MAX_EXP_10 + 20 + var buf: [size; char] + cstd::snprintf(buf.value, size, "%f".value, @value) + return to_str(cstd::strlen(buf.value), buf.value) +} + +export def make_string(ptr: *char) -> Str { + var s: string + s.value = ptr + s.size = strlen(ptr) + 1 + return to_str(s) +} + +// TODO Optimize the user of substring (it works for every String but it creates a copy of the data) +export def remove(str: String, i: size_t) -> Str { + return str.substring(0, i) + str.substring(i + 1, str.length()) +} + +export def remove(str: String, start: size_t, count: size_t) -> Str { + assert start < str.length() + assert start + count < str.length() + + if count == 0 { return str } + if count == 1 { + return remove(str, start) + } + + // TODO Optimize + return str.substring(0, start) + str.substring(start + count, str.length()) +} + +export def insert(str: String, i: size_t, s: String) -> Str { + assert i <= str.length() + if i == str.length() { + return str + s + } else { + return str.substring(0, i) + s + str.substring(i, str.length()) + } +} + +export def insert(str: String, i: size_t, c: char) -> Str { + assert i <= str.length() + if i == str.length() { + return str + c + } else { + return str.substring(0, i) + c + str.substring(i, str.length()) + } +} + +export def substring(str: String, start: size_t, end: size_t) -> Str { + assert start < str.length() + assert end <= str.length() + assert end >= start + + if ref_type(str) == type &Str { + return to_str(end - start, get_internal_buffer(str !*Str) ++ start) + } else if ref_type(str) == type &StringSlice { + let slc = str !&StringSlice + if slc.data { + return to_str(end - start, slc.data ++ start ++ slc.offset) + } else { + return to_str(slc).substring(start, end) + } + } else if ref_type(str) == type &string { + return to_str(end - start, (str !&string).value ++ start) + } else { + return to_str(str).substring(start, end) + } +} + +export def substring(str: String, start: size_t) -> Str { + return substring(str, start, str.length()) +} + +export def index_of(str: String, substring: String, start: size_t = 0) -> int64 { + assert start < str.length + for var i in start..str.length { + let c = str[i] + if c == substring[0] { + var found = true + for var j in 0..substring.length { + if i + j >= str.length { return -1 } + if str[i + j] != substring[j] { + found = false + break + } + } + if found { return i } + } + } + return -1 +} + +export def last_index_of(str: String, substring: String) -> int64 { + for var i in 0..str.length { + var k = str.length - i - 1 + let c = str[k] + if c == substring[0] { + var found = true + for var j in 0..substring.length { + if k + j >= str.length { return -1 } + if str[k + j] != substring[j] { + found = false + break + } + } + if found { return k } + } + } + return -1 +} + +export def ends_with(str: String, suffix: String) -> bool { + let index = last_index_of(str, suffix) + if index < 0 { return false } + return index == str.length - suffix.length +} + +export def starts_with(str: String, pre: String) -> bool { + return str.index_of(pre) == 0 +} + +export def strip_margin(s: String) -> Str { + var res: StringBuffer = "" + let len = length(s) + + var i = 0 + while i < len { + var c = s[i] + if c == '\n' or i == 0 { + if c == '\n' { + res += '\n' + } + if i + 1 >= len { break } + i += 1; c = s[i] + while (c == ' ' or c == '\t') and (i + 1) < len { + i += 1; c = s[i] + } + if c == '|' and (i + 1) < len { + i += 1 + continue + } + } + res += c + i += 1 + } + return res +} + +// https://stackoverflow.com/a/23457543/3258949 +// TODO This algorithm is very inefficient + +def match(pattern: String, candidate: String, p: int, c: int) -> bool { + if p == pattern.length() { + return c == candidate.length() + } else if pattern[p] == '*' { + while c < candidate.length() { + if match(pattern, candidate, p + 1, c) { + return true + } + c += 1 + } + return match(pattern, candidate, p + 1, c) + } else if pattern[p] != '?' and pattern[p] != candidate[c] { + return false + } else { + return match(pattern, candidate, p + 1, c + 1) + } +} + +export def match(pattern: String, candidate: String) -> bool { + return match(pattern, candidate, 0, 0) +} + +export def utf8_encode(code_point: uint64) -> Str { + var res: StringBuffer = "" + if code_point <= 0x007F { + res += code_point !char + } else if code_point <= 0x07FF { + res += ((code_point >> 6) | 0b11000000) !char + res += (code_point & 0b00111111 | 0b10000000) !char + } else if code_point <= 0xFFFF { + res += ((code_point >> 12) | 0b11100000) !char + res += ((code_point >> 6 & 0b00111111) | 0b10000000) !char + res += (code_point & 0b00111111 | 0b10000000) !char + } else if code_point <= 0x10FFFF { + res += ((code_point >> 18) | 0b11110000) !char + res += ((code_point >> 12 & 0b00111111) | 0b10000000) !char + res += ((code_point >> 6 & 0b00111111) | 0b10000000) !char + res += (code_point & 0b00111111 | 0b10000000) !char + } + return res +} + +export def int_to_hex_str(n: uint64, prefix: bool = true) -> Str { + let digits = "0123456789ABCDEF" + + if n == 0 { + return "0x0" + } + + var str: StringBuffer = "" + while n { + str = digits[n % 16] + str + n /= 16 + } + if prefix { + str = "0x" + str + } + + return str +} \ No newline at end of file diff --git a/test/common.pr b/test/common.pr index d7b1f38..ef309bc 100644 --- a/test/common.pr +++ b/test/common.pr @@ -9,14 +9,14 @@ import process export let tmpfolder = tmpfolder("princess") -export def query_compiler -> &string { - var compiler: &string = runtime::executable +export def query_compiler -> Str { + var compiler: Str = runtime::executable let env = cstd::getenv("PRINCESS_COMPILER".value) if env { compiler = make_string(env) } return compiler } -export def run_compiler_on_source(str: &string, args: [&string]) -> &string { +export def run_compiler_on_source(str: String, args: [String]) -> String { let file = tmpfolder + "/main.pr" let fh = open(file, "w") fprint(fh, str) @@ -25,12 +25,12 @@ export def run_compiler_on_source(str: &string, args: [&string]) -> &string { return run_compiler(file, args) } -export def run_compiler(file: &string, args: [&string]) -> &string { +export def run_compiler(file: String, args: [String]) -> String { let r, w = io::pipe() let compiler = query_compiler() - let res = allocate_ref(type &string, args.size + 2) + let res = allocate_ref(String, args.size + 2) res[0] = file res[1] = "--no-incremental" // TODO Enable incremental compilation for var i in 0..args.size { @@ -58,8 +58,8 @@ export def run_compiler(file: &string, args: [&string]) -> &string { return ast } -def read_until_prompt(stream: File) -> &string { - var buf: &string = "" +def read_until_prompt(stream: File) -> Str { + var buf: StringBuffer = "" while not ferror(stream) { var c: char while read(stream, *c) { @@ -69,10 +69,10 @@ def read_until_prompt(stream: File) -> &string { } } } - return null + return {} !Str } -export def run_repl(input: &string) -> &string { +export def run_repl(input: String) -> String { let rstdin, wstdin = io::pipe() let rstdout, wstdout = io::pipe() defer { @@ -85,13 +85,13 @@ export def run_repl(input: &string) -> &string { let compiler = query_compiler() let proc = *process::spawn( compiler, - [] ![&string], + [] ![String], stdout = wstdout, stdin = rstdin ) read_until_prompt(rstdout) - wstdin.write(@input, input.length) + wstdin.write(@input.to_array(), input.length) wstdin.write('\r') fflush(wstdin) @@ -110,22 +110,22 @@ export def run_repl(input: &string) -> &string { return result } -export def test_file(name: &string) -> &string { +export def test_file(name: String) -> Str { return dirname(__file__) + "/runtime/" + name } -export def executable(name: &string) -> &string { +export def executable(name: String) -> Str { #if defined WIN32 { return name + ".exe" } return name } -export def compile_source(src: &string) -> int { +export def compile_source(src: String) -> int { return run_source(src, run = false) } -export def run_source(src: &string, run: bool = true) -> int { +export def run_source(src: String, run: bool = true) -> int { let file = tmpfolder + "/main" let fh = open(file + ".pr", "w") fprint(fh, src) @@ -133,19 +133,19 @@ export def run_source(src: &string, run: bool = true) -> int { return run_file(file, run) } -export def compile_file(name: &string) -> int { +export def compile_file(name: String) -> int { return run_file(name, run = false) } -export def run_file(name: &string, run: bool = true) -> int { +export def run_file(name: String, run: bool = true) -> int { let src = name + ".pr" let exe = executable(name) - let res = run_compiler(src, ["-o"! &string, exe]) + let res = run_compiler(src, ["-o"! String, exe !String]) if not res { return 1 } if run { - let proc = *process::spawn(exe, [] ![&string]) + let proc = *process::spawn(exe, [] ![String]) proc.wait() proc.dispose() return proc.exit_code diff --git a/test/test_arena.pr b/test/test_arena.pr new file mode 100644 index 0000000..d7c0316 --- /dev/null +++ b/test/test_arena.pr @@ -0,0 +1,38 @@ +import arena + +def #test test_alloc { + let arna = arena::make() + for var i in 0..20 { + const size = 1024 + let mem = arna.allocate(size) + cstd::memset(mem, 0xFF, size) + } + arna.free() +} + +def #test test_random_alloc { + cstd::srand(cstd::time(null) !uint) + + let arna = arena::make() + for var i in 0..100 { + let size = (cstd::rand() % 1024) !size_t + let mem = arna.allocate(size) !*uint8 + for var i in 0..size { + let val = mem[i] + if val != 0 { assert } + } + cstd::memset(mem, 0xFF, size) + for var i in 0..size { + let val = mem[i] + if val != 0xFF !uint8 { assert } + } + } + arna.free() +} + +def #test test_big_alloc { + let arna = arena::make(1024) + let mem = arna.allocate(2048) + cstd::memset(mem, 0xFF, 2048) + arna.free() +} \ No newline at end of file diff --git a/test/test_compiler.pr b/test/test_compiler.pr index 8c5222d..7670c2a 100644 --- a/test/test_compiler.pr +++ b/test/test_compiler.pr @@ -1,15 +1,15 @@ import common import json -def compile(str: &string) -> &Json { +def compile(str: String) -> &Json { let include_dir = dirname(__file__) let types = run_compiler_on_source(str, [ - "--continue-on-output" !&string, - "--typed-ast" !&string, - "--name" !&string, - "main" !&string, - "--include" !&string, - include_dir + "--continue-on-output" !String, + "--typed-ast" !String, + "--name" !String, + "main" !String, + "--include" !String, + include_dir !String ]) if not types { return null } @@ -520,6 +520,16 @@ def #test test_typedecl { assert compile(str) != null } +def #test test_generic_type { + var str = """ + type S(type T) = struct { + a: T + } + type F = S(int) + """ + assert compile(str) != null +} + def #test test_typedecl_fail { var str = """ type A = int diff --git a/test/test_ctfe.pr b/test/test_ctfe.pr index 6df597e..b3c2b02 100644 --- a/test/test_ctfe.pr +++ b/test/test_ctfe.pr @@ -69,10 +69,20 @@ def #test test_c_functions { } def #test test_strings { + // TODO Work on letting consteval serialize strings let src = """ + def unsafe_copy(s: Str) -> string { + let res = allocate(char, s.length() + 1) + res[s.length()] = '\\0' + for var i in 0..s.length() { + res[i] = s[i] + } + return res + } + def append_str(a: string, b: string) -> string { let res = a + b - return @res + return unsafe_copy(res) } const hello_world = append_str("Hello ", "World!") diff --git a/test/test_json.pr b/test/test_json.pr index af4b321..e0238da 100644 --- a/test/test_json.pr +++ b/test/test_json.pr @@ -103,7 +103,7 @@ type A = struct { } type B = struct { a: int - s: &string + s: Str } def #test test_serialization { @@ -121,18 +121,18 @@ def #test test_serialization { assert env.out() == strip_margin("""\ |{ - | "a": 10.00000, - | "b": 20.50000, + | "a": 10.000000, + | "b": 20.500000, | "c": { - | "a": 20.00000, + | "a": 20.000000, | "s": "some string" | }, | "d": [ - | 1.00000, - | 2.00000, - | 3.00000, - | 4.00000, - | 5.00000 + | 1.000000, + | 2.000000, + | 3.000000, + | 4.000000, + | 5.000000 | ] |}""") } diff --git a/test/test_leaks.pr b/test/test_leaks.pr new file mode 100644 index 0000000..ffec5b0 --- /dev/null +++ b/test/test_leaks.pr @@ -0,0 +1,10 @@ +import common + +def #test test_leaks { + let file = common::tmpfolder + "/empty.pr" + let fh = open(file, "w") + fprint(fh, """cstd::printf("Hello World!\\n".value)\n""") + fh.close() + + assert system("valgrind --leak-check=full --error-exitcode=1 " + query_compiler() + " " + file + " --no-incremental") == 0 +} \ No newline at end of file diff --git a/test/test_lexer.pr b/test/test_lexer.pr index a5cb3c2..7b7128d 100644 --- a/test/test_lexer.pr +++ b/test/test_lexer.pr @@ -1,15 +1,16 @@ import common import json -def lex(str: &string) -> &Json { - return json::parse(common::run_compiler_on_source(str, ["--tokens" !&string])) +def lex(str: String) -> &Json { + return json::parse(common::run_compiler_on_source(str, ["--tokens" !String])) } def #test test_empty_file { assert lex("") == json::parse("""[{ "kind": "EOF", "line": 0, - "column": 0 }]""") } + "column": 0 }]""") +} def #test test_float_literal { assert lex("123.45678")[0] == json::parse("""{\ diff --git a/test/test_map.pr b/test/test_map.pr index d75810f..06989de 100644 --- a/test/test_map.pr +++ b/test/test_map.pr @@ -45,7 +45,7 @@ def #test test_map_resize { assert m["4"] == 4 } -def is_in(array: &[&string], key: &string) -> bool { +def is_in(array: &[Str], key: String) -> bool { for var i in 0..array.size { let value = array[i] if value == key { diff --git a/test/test_parser.pr b/test/test_parser.pr index 7bc8e68..aa44391 100644 --- a/test/test_parser.pr +++ b/test/test_parser.pr @@ -1,8 +1,8 @@ import json import common -def parse(str: &string) -> &Json { - return json::parse(common::run_compiler_on_source(str, ["--ast" !&string])) +def parse(str: String) -> &Json { + return json::parse(common::run_compiler_on_source(str, ["--ast" !String])) } def program(jsn: &Json) -> &Json { @@ -1384,6 +1384,30 @@ def #test test_array_types { }""")) } +def #test test_generic_type { + assert parse("(type Poly(int))") == program(json::parse("""{ + "kind": "TypeConstructor", + "name": { + "kind": "Identifier", + "path": [ + "Poly" + ], + "prefixed": false, + "args": null + }, + "args": [ + { + "kind": "Identifier", + "path": [ + "int" + ], + "prefixed": false, + "args": null + } + ] + }""")) +} + def #test test_func_call { assert parse("really::long::path::foo()") == program(json::parse("""{ "kind": "FuncCall", @@ -2824,6 +2848,51 @@ def #test test_struct { }""")) } +def #test test_type_constructor { + assert parse(""" + type S(type T) = struct {} + """) == program(json::parse("""{ + "kind": "TypeDecl", + "share": "NONE", + "left": [ + { + "kind": "TypeConstructor", + "name": { + "kind": "Identifier", + "path": [ + "S" + ], + "prefixed": false, + "args": null + }, + "args": [ + { + "kind": "Parameter", + "kw": "VAR", + "name": { + "kind": "Identifier", + "path": [ + "T" + ], + "prefixed": false, + "args": null + }, + "tpe": null, + "value": null + } + ] + } + ], + "right": [ + { + "kind": "Struct", + "body": [ + ] + } + ] + }""")) +} + def #test test_import { assert parse("import module") == program(json::parse("""{ diff --git a/test/test_runtime.pr b/test/test_runtime.pr index 2634522..f3809e9 100644 --- a/test/test_runtime.pr +++ b/test/test_runtime.pr @@ -334,6 +334,21 @@ def #test test_unions { ) } +def #test test_generic_type { + let src = """ + type S(type T) = struct { + t: T + } + + def test_generic_type { + let s = {10} !S(int) + assert (type_of s.t) == int + } + test_generic_type + """ + assert run_source(src) == 0 +} + def #test test_strings { let src = """ def test_strings { diff --git a/test/test_strings.pr b/test/test_strings.pr new file mode 100644 index 0000000..e67b8c4 --- /dev/null +++ b/test/test_strings.pr @@ -0,0 +1,187 @@ +def #test test_conversions { + let a = "some string" + let b: &string = a + let c: Str = a + let d: StringBuffer = a + let e: StringSlice = a.slice(0, a.length()) + assert a == b + assert b == c + assert c == d + assert d == e +} + +def #test test_equality { + let a = "some" + let b = "other" + let c = "some" + + assert a == c + assert a != b +} + +def #test test_append { + var s: String + s = "a" + 10 + assert s == "a10" + s = 10 + "a" + assert s == "10a" + + s = "a" + 10.5 + assert s == "a10.500000" + s = 10.5 + "a" + assert s == "10.500000a" + + s = "a" + 'b' + assert s == "ab" + s = 'b' + "a" + assert s == "ba" +} + +def #test test_string_buffer { + var sb: StringBuffer = "" + sb += 10 + sb += "what" + sb += 'a' + assert sb == "10whata" + + let s: Str = sb + assert s == "10whata" +} + +def #test test_long_str { + let ls: Str = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute + irure dolor in reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint occaecat + cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum. + """ + + assert not is_short_str(*ls) + assert ls.long_str.data != null + assert @ls.long_str.refcount == 2 + assert length(ls) == 522 +} + +def #test test_short_str { + let ss: Str = "short string" + + assert is_short_str(*ss) + assert ss.short_str.data.value != null + assert ss.short_str.count == 12 + assert length(ss) == 12 +} + +def #test test_slice { + let s1 = "some string" + let s2: Str = s1 + let s3: &[char] = s1 + let s4: String = s1 + + let slc1 = s1.slice(0, 4) + let slc2 = s2.slice(0, 4) + let slc3 = s3.slice(0, 4) + let slc4 = s4.slice(0, 4) + + assert slc1 == slc2 + assert slc2 == slc3 + assert slc3 == slc4 + assert slc4 == "some" +} + +type MyString = struct { + str: Str +} + +export def get_item(s: &MyString, index: size_t) -> char { + return s.str[index] +} +export def length(s: &MyString) -> size_t { + return s.str.length() +} + +def #test test_custom_str { + let a: MyString = {"some string"} !MyString + let s: String = a + let slc = s.slice(0, 4) + let sbs = s.substring(0, 4) + + assert slc == "some" + assert sbs == "some" +} + +def #test test_remove { + let a: Str = "some string" + assert a.remove(1) == "sme string" + assert a.remove(1, 5) == "string" + assert a.remove(0) == "ome string" +} + +def #test test_insert { + let a: Str = "some string" + assert a.insert(4, 's') == "somes string" + assert a.insert(4, " more") == "some more string" + assert a.insert(0, "really ") == "really some string" +} + +def #test test_substring { + let a: Str = "abcdefg" + let b: StringSlice = a.slice(0, a.length()) + let c: &[char] = a.to_array() + + assert a.substring(1, 4) == "bcd" + assert b.substring(1, 4) == "bcd" + assert c.substring(1, 4) == "bcd" +} + +def #test test_index_of { + let a: Str = "abcdefabcdef" + assert a.index_of("bcd") == 1 + assert a.index_of("foo") == -1 + assert a.index_of("bcd", 4) == 7 +} + +def #test test_last_index_of { + let a: Str = "abcdefabcdef" + assert a.last_index_of("bcd") == 7 + assert a.last_index_of("foo") == -1 +} + +def #test test_ends_with { + let a: Str = "abcdefabcdef" + assert a.ends_with("cdef") + assert not a.ends_with("abc") +} + +def #test test_starts_with { + let a: Str = "abcdefabcdef" + assert a.starts_with("abcd") + assert not a.starts_with("def") +} + +def #test test_strip_margin { + let a: Str = "\ + |something here + |something there" + assert a.strip_margin() == "something here\nsomething there" +} + +def #test test_match { + let a: Str = "some string" + assert "s*tr*g".match(a) + assert "s?me s?ring".match(a) + assert "s?me s*ng".match(a) + + assert not "a*bc".match(a) + assert not "s?me strong".match(a) + assert not "s?me s*og".match(a) +} + +def #test test_utf8_encode { + assert utf8_encode(0x41) == "A" + assert utf8_encode(0x0500) == "\u0500" + assert utf8_encode(0x1FB00) == "\U0001FB00" +} \ No newline at end of file