func(data, AllocAction.Free, 0, 0, ptr);
}
+calloc :: proc (size: u32) -> rawptr do return alloc(context.allocator, size);
+cresize :: proc (ptr: rawptr, size: u32) -> rawptr do return resize(context.allocator, ptr, size);
+cfree :: proc (ptr: rawptr) do free(context.allocator, ptr);
+
context : struct {
allocator : Allocator;
temp_allocator : Allocator;
--- /dev/null
+package file
+
+// Many of these functions will be improved when
+// multiple return values are implemented.
+
+use package builtin
+use package wasi
+
+OpenMode :: enum {
+ Read;
+ Write;
+ Append;
+}
+
+File :: struct {
+ fd : FileDescriptor;
+}
+
+file_open :: proc (file: ^File, path: string, mode := OpenMode.Read, flags := FDFlags.Sync) -> bool {
+ // Currently the directory's file descriptor appears to always be 3
+ DIR_FD :: 3;
+
+ open_flags := cast(OFlags) 0;
+ rights := Rights.DataSync
+ | Rights.Sync
+ | Rights.FilestatGet
+ | Rights.FilestatSetSize
+ | Rights.FilestatSetTimes
+ | Rights.Advise
+ | Rights.Allocate
+ | Rights.PathOpen
+ | Rights.PathCreateFile;
+ fdflags := flags;
+
+ switch mode {
+ case OpenMode.Write {
+ open_flags |= OFlags.Creat | OFlags.Trunc;
+ rights |= Rights.Write;
+ }
+
+ case OpenMode.Append {
+ open_flags |= OFlags.Creat;
+ rights |= Rights.Write;
+ fdflags |= FDFlags.Append;
+ }
+
+ case OpenMode.Read {
+ rights |= Rights.Read | Rights.Seek | Rights.Tell;
+ }
+ }
+
+ if err := path_open(
+ DIR_FD,
+ LookupFlags.SymLinkFollow,
+ path,
+ open_flags,
+ rights,
+ rights,
+ fdflags,
+ ^file.fd);
+ err != Errno.Success {
+ return false;
+ }
+
+ return true;
+}
+
+file_close :: proc (file: File) -> bool {
+ if fd_close(file.fd) != Errno.Success {
+ return false;
+ }
+
+ return true;
+}
+
+file_get_size :: proc (file: File) -> i64 {
+ //size: i64 = 0l;
+ //prev: i64;
+
+ //if fd_seek(file.fd, 0l, Whence.Cur, ^prev) != Errno.Success do return -1l;
+ //if fd_seek(file.fd, 0l, Whence.End, ^size) != Errno.Success do return -1l;
+ //if fd_seek(file.fd, prev, Whence.Set, ^prev) != Errno.Success do return -1l;
+
+ fs: FileStat;
+ if fd_filestat_get(file.fd, ^fs) != Errno.Success do return -1l;
+
+ return fs.size;
+}
+
+file_get_contents_from_file :: proc (file: File) -> string {
+ size := cast(u32) file_get_size(file);
+
+ data := cast(^u8) alloc(context.allocator, size);
+
+ prev_loc: i64;
+ fd_tell(file.fd, ^prev_loc);
+
+ dummy: i64;
+ fd_seek(file.fd, 0l, Whence.Set, ^dummy);
+
+ dummy2: u32;
+ buf := IOVec.{ cast(rawptr) data, size };
+ fd_pread(file.fd, IOVecArray.{ ^buf, 1 }, 0l, ^dummy2);
+
+ fd_seek(file.fd, prev_loc, Whence.Set, ^dummy);
+
+ return data[0 : size];
+}
+
+file_get_contents :: proc #overloaded {
+ file_get_contents_from_file,
+
+ proc (path: string) -> string {
+ tmp_file: File;
+
+ if !file_open(^tmp_file, path, OpenMode.Read) do return "";
+ defer file_close(tmp_file);
+
+ return file_get_contents(tmp_file);
+ }
+}
\ No newline at end of file
--- /dev/null
+package stdio
+
+use package builtin
+use package core
+use package wasi
+
+print_string :: proc (s: string) {
+ string_builder_append(^cout_state.sb, s);
+ if s.data[s.count - 1] == #char "\n" do print_flush();
+}
+
+print_cstring :: proc (s: cstring) do string_builder_append(^cout_state.sb, s);
+print_u64 :: proc (n: u64, base := 10l) do string_builder_append(^cout_state.sb, n);
+print_u32 :: proc (n: u32, base := 10) do string_builder_append(^cout_state.sb, cast(u64) n, cast(u64) base);
+
+print :: proc #overloaded {
+ print_string,
+ print_cstring,
+ print_u64,
+ print_u32,
+}
+
+print_flush :: proc {
+ ^cout_state.sb |> string_builder_to_string() |> raw_print(cout_state.fd);
+ ^cout_state.sb |> string_builder_clear();
+}
+
+#private
+raw_print :: proc (s: string, fd: FileDescriptor) -> u32 {
+ vec := IOVec.{ buf = s.data, len = s.count };
+ tmp : Size;
+ fd_write(fd, IOVecArray.{ ^vec, 1 }, ^tmp);
+ fd_datasync(fd);
+ return tmp;
+}
+
+ConsoleOutput :: struct {
+ sb : StringBuilder;
+ fd : FileDescriptor;
+}
+
+#private
+cout_state : ConsoleOutput
+
+stdio_init :: proc {
+ cout_state.fd = cast(FileDescriptor) 1;
+ cout_state.sb = string_builder_make(2048);
+}
\ No newline at end of file
#private
string_length_string :: proc (s: string) -> u32 do return s.count;
-string_concat :: proc (a: Allocator, s1: string, s2: string) -> string {
+string_concat :: proc (s1: string, s2: string) -> string {
len1 :: string_length(s1);
len2 :: string_length(s2);
- data := cast(^u8) alloc(a, len1 + len2);
+ data := cast(^u8) calloc(len1 + len2);
for i: 0, len1 do data[i] = s1.data[i];
for i: 0, len2 do data[i + len1] = s2.data[i];
return string.{ data, len1 + len2 };
}
-string_free :: proc (a: Allocator, s: string) do free(a, s.data);
+string_free :: proc (s: string) do cfree(s.data);
// This is an example doc string
// You can have as many comments as you want
// It documents the string_split function
-string_split :: proc (a: Allocator, str: string, delim: u8) -> []string {
+string_split :: proc (str: string, delim: u8) -> []string {
delim_count := 0;
for i: 0, str.count do if str.data[i] == delim do delim_count += 1;
- strarr := cast(^string) alloc(a, sizeof string * (delim_count + 1));
+ strarr := cast(^string) calloc(sizeof string * (delim_count + 1));
curr_str := 0;
begin := 0;
return str.data[0:0];
}
+string_contains :: proc (str: string, c: u8) -> bool {
+ for i: 0, str.count do if str.data[i] == c do return true;
+ return false;
+}
+
StringBuilder :: struct {
alloc : Allocator;
cap : u32 = 0;
}
-string_builder_make :: proc (a: Allocator, initial_cap: u32) -> StringBuilder {
+string_builder_make :: proc (initial_cap: u32) -> StringBuilder {
data: ^u8 = null;
if initial_cap > 0 {
- data = cast(^u8) alloc(a, initial_cap);
+ data = cast(^u8) calloc(initial_cap);
}
return StringBuilder.{
- alloc = a,
+ alloc = context.allocator,
data = data,
cap = initial_cap,
};
package wasi
+#include_file "stdio"
+
use package main as main
use package builtin
use package memory
+use package stdio as io
Size :: #type u32;
Filesize :: #type u64;
args_get(argv, argv_buf);
+ io.stdio_init();
+
main.main(argv[0 : argc]);
+
+ io.print_flush();
}
-
-Package main:
- main :: proc (args: [] cstring) -> i32
-
-Package string:
- string_split :: proc (a: Allocator, s: string, delim: u8) -> [] string
- at /usr/share/onyx/core/string.onyx:50,0
- Auto documentation for string_split
[ ] transmute
+ [ ] explicit memory controls at top level
+
[ ] Put type info in data section so it is runtime accessible
- type name
- size
--- /dev/null
+Current basic plan for polymorphic procedures
+
+0. Cleanup some of the aspects of the type system and make slices their own special type.
+
+1. Detect polymorphic parameters
+ Polymorphic parameters will have a $ in from a symbol in their type
+
+2. Polymorphic procedures (polyproc) will have a seperate entity type
+ Most of the stages will ignore them however
+
+3. Polyprocs will store a tabel on them mapping from specific, filled in types to the corresponding function.
+ "T=u32;R=[] u8" -> <function>
+
+4. When a polyproc is called, the polymoprhic parameters are parallel-recursived to find the type matching the polyparam.
+ For example:
+
+ foo :: proc (a: ^[] $T, b: u32) -> T {
+ return a.data[b];
+ }
+
+ arr : [128] []u8;
+ // init arr
+ a := arr[4 : 10];
+ foo(^a, 2);
+
+ When foo is called, we look at the polymorphic parameters, a in this example, are do the following recursion:
+
+ (^[] $T, ^[] []u8) Both are pointers, so remove ^
+ ([] $T, [] []u8) Both are slices, so remove []
+ ($T, []u8) T is resolved to be []u8 in this case
+
+ If at any point, both sides cannot be removed, it is an invalid parameter.
+
+5. When the specific types of the polyproc are resolved, if no matching function already exists, a copy is made.
+ Copies are made from an un-symbol-resolved version of the procedure.
+ Some nodes can be marked as NO_COPY which signals that a copy should not be made.
+
+6. After a copy is made, it is fed through symbol resolution using the correct scope, and then type checking, and then function header and function entities are added to the entity list in the correct position.
+
+
+Ideally, nothing should change with the WASM output.
#define BH_BIT(x) (1 << (x))
#define BH_MASK_SET(var, set, mask) ((set) ? (var) |= (mask) : (var) &= ~(mask))
-#define fori(var, lo, hi) for (i64 var = (lo); var < (hi); var++)
+#define fori(var, lo, hi) for (i64 var = (lo); var < (hi); var++)
+#define forir(var, hi, lo) for (i64 var = (hi); var >= (lo); var--)
#define forll(T, var, start, step) for (T* var = (start); var != NULL; var = var->step)
#ifdef BH_DEBUG
if (type == NULL) return CC_Undefined;
if (type->kind != Type_Kind_Function) return CC_Undefined;
if (type->Function.return_type->kind == Type_Kind_Struct) return CC_Return_Stack;
+ if (type->Function.return_type->kind == Type_Kind_Slice) return CC_Return_Stack;
return CC_Return_Wasm;
}
bh_arr(StructMember *) memarr; \
}) \
TYPE_KIND(Array, struct { u32 size; u32 count; Type *elem; }) \
+ TYPE_KIND(Slice, struct { Type *ptr_to_data; }) \
TYPE_KIND(Enum, struct { char* name; Type* backing; })
typedef enum TypeKind {
const char* type_get_name(Type* type);
u32 type_get_alignment_log2(Type* type);
-b32 type_struct_lookup_member(Type* type, char* member, StructMember* smem);
+b32 type_lookup_member(Type* type, char* member, StructMember* smem);
+b32 type_lookup_member_by_idx(Type* type, i32 idx, StructMember* smem);
+
b32 type_struct_is_simple(Type* type);
b32 type_is_pointer(Type* type);
b32 type_is_numeric(Type* type);
b32 type_is_compound(Type* type);
b32 type_results_in_void(Type* type);
+b32 type_is_structlike(Type* type);
+b32 type_is_structlike_strict(Type* type);
+u32 type_structlike_mem_count(Type* type);
+u32 type_structlike_is_simple(Type* type);
#endif // #ifndef ONYX_TYPES
--- /dev/null
+Onyx
+ filter remove_inline //.*$
+ filter call_regexp_common C++
+ extension onyx
+ 3rd_gen_scale 2.30
scope: keyword.control.onyx
- match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr)\b'
- scope: constant.type.onyx
+ scope: keyword.control.onyx
- - match: '\b(true|false|null)\b'
+ - match: '\b(true|false|null|context)\b'
scope: constant.numeric.onyx
# Numbers
#include_file "intrinsics"
#include_file "random"
#include_file "string"
+#include_file "file"
use package builtin
use package wasi
use package intrinsics
use package random
-
-print_u64 :: proc (n_: u64, base := 10l) {
- n := n_;
- str: [256] u8;
- for i: 0, 256 do str[i] = #char "\0";
-
- c := cast(^u8) ^str[255];
- *c = #char "\0";
- c -= 1;
-
- s :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
-
- if n == 0l {
- *c = #char "0";
- c -= 1;
- } else {
- while n > 0l {
- m :: n % base;
-
- *c = s.data[cast(u32) m];
- c -= 1;
-
- n /= base;
- }
- }
-
- if base == 16l {
- *c = #char "x";
- c -= 1;
- *c = #char "0";
- c -= 1;
- }
-
- if base == 2l {
- *c = #char "b";
- c -= 1;
- *c = #char "0";
- c -= 1;
- }
-
- print(c + 1);
-}
-
-print_string :: proc (s: string) -> u32 {
- vec := IOVec.{ buf = s.data, len = s.count };
- tmp : Size;
- fd_write(1, IOVecArray.{ ^vec, 1 }, ^tmp);
- fd_datasync(1);
-
- return tmp;
-}
-
-print_u8 :: proc (s: cstring) -> u32 {
- return string_make(s) |> print_string();
-}
-
-print :: proc #overloaded { print_string, print_u8 }
+use package file
+use package stdio
print_rights :: proc (rights: Rights) {
- print_u64(cast(u64) rights, 2l);
+ print(cast(u32) rights, 2);
print("\n");
if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n");
random_seed(cast(u32) now);
- sb := string_builder_make(heap_allocator, 256);
+ sb := string_builder_make(256);
timer := timer_start();
defer {
|> string_builder_to_string()
|> print();
- fd: FileDescriptor = -1;
- if err := path_open(3, LookupFlags.SymLinkFollow, string_make(args.data[1]), cast(OFlags) 0, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, FDFlags.Sync, ^fd); err != Errno.Success {
- print("Failed to open file\n");
- print("Error code: ");
- print_u64(cast(u64) err, 16l);
- proc_exit(1);
- }
- defer fd_close(fd);
-
- print_u64(cast(u64) fd, 16l);
- print("\n");
-
- filelen : Filesize;
- if fd_seek(fd, 0l, Whence.End, ^filelen) != Errno.Success {
- print("Failed to seek in file\n");
- proc_exit(1);
- }
- print("the size is: ");
- print_u64(cast(u64) filelen);
- print("\n");
+ cont := file_get_contents(string_make(args.data[1]));
+ defer cfree(cont.data);
+ print(cont);
sum := 0l;
for i: 0, 20000 do if is_prime(i) do sum += cast(u64) i;
print_u64(sum);
print("\n");
- matches := string_split(heap_allocator, "This is a test string to test splitting. It surprisingly works very well.", #char " ");
- defer free(heap_allocator, matches.data);
+ matches := string_split("This is a test string to test splitting. It surprisingly works very well.", #char " ");
+ defer cfree(matches.data);
string_builder_clear(^sb);
for i: 0, matches.count {
^sb |> string_builder_to_string() |> print();
program := "+ + * s - /";
- tokens := string_split(heap_allocator, program, #char " ");
- defer free(heap_allocator, tokens.data);
+ tokens := string_split(program, #char " ");
+ defer cfree(tokens.data);
acc := 0;
for i: 0, tokens.count {
sl := make_i32_arr();
print_u64(cast(u64) sl.count);
+
+ print_u64(cast(u64) fib(20));
}
foobar :: proc (a: i32, b := 1, c := 5l) {
print("\n");
print_u64(c);
print("\n");
-}
\ No newline at end of file
+}
+
+fib :: proc (n: i32) -> i32 {
+ switch n {
+ case 0 do return 1;
+ case 1 do return 1;
+ case #default {
+ return fib(n - 1) + fib(n - 2);
+ }
+ }
+
+ return 0;
+}
+
+//make_slice :: proc (ptr: ^$T, count: u32) -> [] T {
+// return ptr[0 : count];
+//}
\ No newline at end of file
return 1;
}
- if (actual_param->value->type->kind == Type_Kind_Struct) {
- if (!type_struct_is_simple(actual_param->value->type)) {
+ if (type_is_structlike_strict(actual_param->value->type)) {
+ if (!type_structlike_is_simple(actual_param->value->type)) {
onyx_message_add(Msg_Type_Literal,
actual_param->token->pos,
"can only pass simple structs as parameters (no nested structures). passing by pointer is the only way for now.");
return 1;
}
- if (binop->left->type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(binop->left->type)) {
onyx_message_add(Msg_Type_Literal,
binop->token->pos,
"invalid type for left side of binary operator");
return 1;
}
- if (binop->right->type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(binop->right->type)) {
onyx_message_add(Msg_Type_Literal,
binop->token->pos,
"invalid type for right side of binary operator");
b32 check_struct_literal(AstStructLiteral* sl) {
fill_in_type((AstTyped *) sl);
- TypeStruct* st = &sl->type->Struct;
- if (st->mem_count != bh_arr_length(sl->values)) {
+ u32 mem_count = type_structlike_mem_count(sl->type);
+
+ if (mem_count != bh_arr_length(sl->values)) {
onyx_message_add(Msg_Type_Literal,
sl->token->pos,
"incorrect number of initial values for this type");
}
AstTyped** actual = sl->values;
- StructMember** formal = st->memarr;
+ StructMember smem;
- fori (i, 0, st->mem_count) {
+ fori (i, 0, mem_count) {
if (check_expression(actual)) return 1;
- if (!types_are_compatible((*formal)->type, (*actual)->type)) {
+ // NOTE: Not checking the return on this function because
+ // this for loop is bounded by the number of members in the
+ // type.
+ type_lookup_member_by_idx(sl->type, i, &smem);
+ Type* formal = smem.type;
+
+ if (!types_are_compatible(formal, (*actual)->type)) {
onyx_message_add(Msg_Type_Assignment_Mismatch,
sl->token->pos,
- type_get_name((*formal)->type),
+ type_get_name(formal),
type_get_name((*actual)->type));
return 1;
}
- actual++, formal++;
+ actual++;
}
return 0;
AstFieldAccess* field = *pfield;
if (check_expression(&field->expr)) return 1;
- if (!type_is_struct(field->expr->type)) {
+ if (!type_is_structlike(field->expr->type)) {
onyx_message_add(Msg_Type_Literal,
field->token->pos,
- "expected expression of kind struct or pointer to struct");
+ "cannot access field on non structures");
return 1;
}
token_toggle_end(field->token);
StructMember smem;
- if (!type_struct_lookup_member(field->expr->type, field->token->text, &smem)) {
+ if (!type_lookup_member(field->expr->type, field->token->text, &smem)) {
onyx_message_add(Msg_Type_No_Field,
field->token->pos,
field->token->text,
sl->type_node = (AstType *) sl->stnode;
sl->type = type_build_from_ast(semstate.allocator, sl->type_node);
- if (sl->type->kind != Type_Kind_Struct) {
+ if (!type_is_structlike_strict(sl->type)) {
onyx_message_add(Msg_Type_Literal,
sl->token->pos,
- "type is not a struct type (BAD ERROR MESSAGE)");
+ "type is not a constructable using a struct literal");
return;
}
if (bh_arr_length(sl->values) == 0) {
- bh_arr_set_length(sl->values, sl->type->Struct.mem_count);
+ bh_arr_set_length(sl->values, type_structlike_mem_count(sl->type));
bh_arr_zero(sl->values);
StructMember s;
bh_arr_each(AstStructMember *, smem, sl->named_values) {
token_toggle_end((*smem)->token);
- if (!type_struct_lookup_member(sl->type, (*smem)->token->text, &s)) {
+ if (!type_lookup_member(sl->type, (*smem)->token->text, &s)) {
onyx_message_add(Msg_Type_No_Field,
(*smem)->token->pos,
(*smem)->token->text, type_get_name(sl->type));
sl->values[s.idx] = (*smem)->initial_value;
}
- AstStructType* st = (AstStructType *) sl->type_node;
- bh_arr_each(StructMember*, smem, sl->type->Struct.memarr) {
- u32 idx = (*smem)->idx;
-
- if (sl->values[idx] == NULL) {
- if (st->members[idx]->initial_value == NULL) {
- onyx_message_add(Msg_Type_Field_No_Value,
- sl->token->pos,
- st->members[idx]->token->text,
- st->members[idx]->token->length);
- return;
+ if (sl->type->kind == Type_Kind_Struct) {
+ AstStructType* st = (AstStructType *) sl->type_node;
+ bh_arr_each(StructMember*, smem, sl->type->Struct.memarr) {
+ u32 idx = (*smem)->idx;
+
+ if (sl->values[idx] == NULL) {
+ if (st->members[idx]->initial_value == NULL) {
+ onyx_message_add(Msg_Type_Field_No_Value,
+ sl->token->pos,
+ st->members[idx]->token->text,
+ st->members[idx]->token->length);
+ return;
+ }
+
+ sl->values[idx] = st->members[idx]->initial_value;
}
-
- sl->values[idx] = st->members[idx]->initial_value;
}
}
}
return t1 == t2;
}
+ case Type_Kind_Slice: {
+ if (t2->kind != Type_Kind_Slice) return 0;
+ return types_are_compatible(t1->Slice.ptr_to_data->Pointer.elem, t2->Slice.ptr_to_data->Pointer.elem);
+ }
+
default:
assert(("Invalid type", 0));
break;
return 1;
}
+ case Type_Kind_Slice: {
+ if (t2->kind != Type_Kind_Slice) return 0;
+ return types_are_compatible(t1->Slice.ptr_to_data->Pointer.elem, t2->Slice.ptr_to_data->Pointer.elem);
+ }
+
default:
assert(("Invalid type", 0));
break;
case Type_Kind_Array: return type->Array.size;
case Type_Kind_Struct: return type->Struct.size;
case Type_Kind_Enum: return type_size_of(type->Enum.backing);
+ case Type_Kind_Slice: return 8;
default: return 0;
}
}
case Type_Kind_Array: return type_alignment_of(type->Array.elem);
case Type_Kind_Struct: return type->Struct.alignment;
case Type_Kind_Enum: return type_alignment_of(type->Enum.backing);
+ case Type_Kind_Slice: return 4;
default: return 1;
}
}
}
Type* type_make_slice(bh_allocator alloc, Type* of) {
- Type* s_type = bh_alloc(alloc, sizeof(Type));
- s_type->kind = Type_Kind_Struct;
- s_type->Struct.name = bh_aprintf(global_heap_allocator, "[] %s", type_get_name(of));
- s_type->Struct.mem_count = 2;
- s_type->Struct.memarr = NULL;
-
- bh_table_init(global_heap_allocator, s_type->Struct.members, s_type->Struct.mem_count);
- bh_arr_new(global_heap_allocator, s_type->Struct.memarr, s_type->Struct.mem_count);
-
- StructMember smem;
- smem = (StructMember) { .offset = 0, .type = type_make_pointer(alloc, of), .idx = 0, };
- bh_table_put(StructMember, s_type->Struct.members, "data", smem);
- smem = (StructMember) { .offset = 4, .type = &basic_types[Basic_Kind_U32], .idx = 1, };
- bh_table_put(StructMember, s_type->Struct.members, "count", smem);
-
- bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, "data"));
- bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, "count"));
-
- s_type->Struct.alignment = 4;
- s_type->Struct.size = 8;
+ Type* slice_type = bh_alloc(alloc, sizeof(Type));
+ slice_type->kind = Type_Kind_Slice;
+ slice_type->Slice.ptr_to_data = type_make_pointer(alloc, of);
- return s_type;
+ return slice_type;
}
const char* type_get_name(Type* type) {
return 2;
}
-b32 type_struct_lookup_member(Type* type, char* member, StructMember* smem) {
- if (!type_is_struct(type)) return 0;
+b32 type_lookup_member(Type* type, char* member, StructMember* smem) {
if (type->kind == Type_Kind_Pointer) type = type->Pointer.elem;
- TypeStruct* stype = &type->Struct;
+ switch (type->kind) {
+ case Type_Kind_Struct: {
+ TypeStruct* stype = &type->Struct;
- if (!bh_table_has(StructMember, stype->members, member)) return 0;
- *smem = bh_table_get(StructMember, stype->members, member);
- return 1;
+ if (!bh_table_has(StructMember, stype->members, member)) return 0;
+ *smem = bh_table_get(StructMember, stype->members, member);
+ return 1;
+ }
+
+ case Type_Kind_Slice: {
+ if (strcmp(member, "data") == 0) {
+ smem->idx = 0;
+ smem->offset = 0;
+ smem->type = type->Slice.ptr_to_data;
+ return 1;
+ }
+ if (strcmp(member, "count") == 0) {
+ smem->idx = 1;
+ smem->offset = 4;
+ smem->type = &basic_types[Basic_Kind_U32];
+ return 1;
+ }
+
+ return 0;
+ }
+
+ default: return 0;
+ }
+}
+
+b32 type_lookup_member_by_idx(Type* type, i32 idx, StructMember* smem) {
+ if (type->kind == Type_Kind_Pointer) type = type->Pointer.elem;
+
+ switch (type->kind) {
+ case Type_Kind_Struct: {
+ TypeStruct* stype = &type->Struct;
+
+ if (idx > stype->mem_count) return 0;
+ *smem = *stype->memarr[idx];
+ return 1;
+ }
+
+ case Type_Kind_Slice: {
+ if (idx == 0) {
+ smem->idx = 0;
+ smem->offset = 0;
+ smem->type = type->Slice.ptr_to_data;
+ return 1;
+ }
+ if (idx == 1) {
+ smem->idx = 1;
+ smem->offset = 4;
+ smem->type = &basic_types[Basic_Kind_U32];
+ return 1;
+ }
+
+ return 0;
+ }
+
+ default: return 0;
+ }
}
b32 type_struct_is_simple(Type* type) {
&& (type->Function.return_type->kind == Type_Kind_Basic)
&& (type->Function.return_type->Basic.kind == Basic_Kind_Void));
}
+
+b32 type_is_structlike(Type* type) {
+ if (type->kind == Type_Kind_Struct) return 1;
+ if (type->kind == Type_Kind_Slice) return 1;
+ if (type->kind == Type_Kind_Pointer) {
+ if (type->Pointer.elem->kind == Type_Kind_Struct) return 1;
+ if (type->Pointer.elem->kind == Type_Kind_Slice) return 1;
+ }
+ return 0;
+}
+
+b32 type_is_structlike_strict(Type* type) {
+ if (type->kind == Type_Kind_Struct) return 1;
+ if (type->kind == Type_Kind_Slice) return 1;
+ return 0;
+}
+
+u32 type_structlike_mem_count(Type* type) {
+ switch (type->kind) {
+ case Type_Kind_Struct: return type->Struct.mem_count;
+ case Type_Kind_Slice: return 2;
+ default: return 0;
+ }
+}
+
+u32 type_structlike_is_simple(Type* type) {
+ switch (type->kind) {
+ case Type_Kind_Struct: return type_struct_is_simple(type);
+ case Type_Kind_Slice: return 1;
+ default: return 0;
+ }
+}
\ No newline at end of file
return WASM_TYPE_VOID;
}
+ if (type->kind == Type_Kind_Slice) {
+ return WASM_TYPE_VOID;
+ }
+
if (type->kind == Type_Kind_Enum) {
return onyx_type_to_wasm_type(type->Enum.backing);
}
COMPILE_FUNC(assignment, AstBinaryOp* assign) {
bh_arr(WasmInstruction) code = *pcode;
- if (assign->right->type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(assign->right->type)) {
compile_expression(mod, &code, assign->right);
compile_struct_lval(mod, &code, assign->left);
COMPILE_FUNC(store_instruction, Type* type, u32 offset) {
bh_arr(WasmInstruction) code = *pcode;
- if (type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(type)) {
compile_struct_store(mod, pcode, type, offset);
return;
}
COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
bh_arr(WasmInstruction) code = *pcode;
- if (type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(type)) {
compile_struct_load(mod, pcode, type, offset);
return;
}
u64 offset = field->offset;
AstTyped* source_expr = field->expr;
while (source_expr->kind == Ast_Kind_Field_Access
- && (source_expr->type->kind == Type_Kind_Struct)) {
+ && type_is_structlike_strict(source_expr->type)) {
offset += ((AstFieldAccess *) source_expr)->offset;
source_expr = (AstTyped *) ((AstFieldAccess *) source_expr)->expr;
}
bh_arr(WasmInstruction) code = *pcode;
- assert(type->kind == Type_Kind_Struct);
+ assert(type_is_structlike_strict(type));
- if (type->Struct.mem_count == 1) {
- compile_load_instruction(mod, &code, type->Struct.memarr[0]->type, offset);
+ u32 mem_count = type_structlike_mem_count(type);
+ StructMember smem;
+
+ if (mem_count == 1) {
+ type_lookup_member_by_idx(type, 0, &smem);
+ compile_load_instruction(mod, &code, smem.type, offset);
*pcode = code;
return;
}
u64 tmp_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
WIL(WI_LOCAL_TEE, tmp_idx);
- b32 first = 1;
- bh_arr_each(StructMember *, smem, type->Struct.memarr) {
- if (first) first = 0;
- else WIL(WI_LOCAL_GET, tmp_idx);
- compile_load_instruction(mod, &code, (*smem)->type, offset + (*smem)->offset);
+ fori (i, 0, mem_count) {
+ type_lookup_member_by_idx(type, i, &smem);
+ if (i != 0) WIL(WI_LOCAL_GET, tmp_idx);
+ compile_load_instruction(mod, &code, smem.type, offset + smem.offset);
}
local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
bh_arr(WasmInstruction) code = *pcode;
- assert(lval->type->kind == Type_Kind_Struct);
+ assert(type_is_structlike_strict(lval->type));
u64 offset = 0;
bh_arr(WasmInstruction) code = *pcode;
- assert(type->kind == Type_Kind_Struct);
+ assert(type_is_structlike_strict(type));
u64 loc_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
WIL(WI_LOCAL_SET, loc_idx);
- bh_arr_rev_each(StructMember *, smem, type->Struct.memarr) {
- if ((*smem)->type->kind == Type_Kind_Struct) {
+ StructMember smem;
+
+ u32 mem_count = type_structlike_mem_count(type);
+ forir (i, mem_count - 1, 0) {
+ type_lookup_member_by_idx(type, i, &smem);
+
+ if (type_is_structlike_strict(smem.type)) {
if (bh_arr_last(code).type == WI_LOCAL_SET && bh_arr_last(code).data.l == loc_idx) {
bh_arr_last(code).type = WI_LOCAL_TEE;
} else {
WIL(WI_LOCAL_GET, loc_idx);
}
- compile_struct_store(mod, &code, (*smem)->type, offset + (*smem)->offset);
+ compile_struct_store(mod, &code, smem.type, offset + smem.offset);
} else {
- WasmType wt = onyx_type_to_wasm_type((*smem)->type);
+ WasmType wt = onyx_type_to_wasm_type(smem.type);
u64 tmp_idx = local_raw_allocate(mod->local_alloc, wt);
WIL(WI_LOCAL_SET, tmp_idx);
WIL(WI_LOCAL_GET, loc_idx);
WIL(WI_LOCAL_GET, tmp_idx);
- compile_store_instruction(mod, &code, (*smem)->type, offset + (*smem)->offset);
+ compile_store_instruction(mod, &code, smem.type, offset + smem.offset);
local_raw_free(mod->local_alloc, wt);
}
case Ast_Kind_Field_Access: {
AstFieldAccess* field = (AstFieldAccess *) expr;
- if (field->expr->kind == Ast_Kind_Param && field->expr->type->kind == Type_Kind_Struct) {
+ if (field->expr->kind == Ast_Kind_Param && type_is_structlike_strict(field->expr->type)) {
StructMember smem;
token_toggle_end(field->token);
- type_struct_lookup_member(field->expr->type, field->token->text, &smem);
+ type_lookup_member(field->expr->type, field->token->text, &smem);
token_toggle_end(field->token);
u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + smem.idx;
case Ast_Kind_Param: {
u64 localidx = bh_imap_get(&mod->local_map, (u64) expr);
- if (expr->type->kind == Type_Kind_Struct) {
- TypeStruct* st = &expr->type->Struct;
+ if (type_is_structlike_strict(expr->type)) {
+ u32 mem_count = type_structlike_mem_count(expr->type);
- fori (idx, 0, st->mem_count) {
+ fori (idx, 0, mem_count) {
WIL(WI_LOCAL_GET, localidx + idx);
}
case Ast_Kind_Field_Access: {
AstFieldAccess* field = (AstFieldAccess* ) expr;
- if (field->expr->kind == Ast_Kind_Param && field->expr->type->kind == Type_Kind_Struct) {
+ if (field->expr->kind == Ast_Kind_Param && type_is_structlike_strict(field->expr->type)) {
StructMember smem;
token_toggle_end(field->token);
- type_struct_lookup_member(field->expr->type, field->token->text, &smem);
+ type_lookup_member(field->expr->type, field->token->text, &smem);
token_toggle_end(field->token);
u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + smem.idx;
StructMember smem;
token_toggle_end(field->token);
- type_struct_lookup_member(field->expr->type, field->token->text, &smem);
+ type_lookup_member(field->expr->type, field->token->text, &smem);
token_toggle_end(field->token);
if (smem.idx == 0)
return;
}
+ if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) {
+ onyx_message_add(Msg_Type_Literal,
+ cast->token->pos,
+ "cannot cast to or from a slice");
+ WI(WI_DROP);
+ *pcode = code;
+ return;
+ }
+
if (to->kind == Type_Kind_Function) {
onyx_message_add(Msg_Type_Literal,
cast->token->pos,
if (ret->expr) {
if (mod->curr_cc == CC_Return_Stack) {
- if (ret->expr->type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(ret->expr->type)) {
compile_expression(mod, &code, ret->expr);
WIL(WI_LOCAL_GET, mod->stack_base_idx);
i32 param_count = ft->Function.param_count;
i32 params_left = param_count;
while (params_left-- > 0) {
- if ((*param_type)->kind == Type_Kind_Struct) {
- bh_arr_each(StructMember *, smem, (*param_type)->Struct.memarr) {
- *(t++) = (char) onyx_type_to_wasm_type((*smem)->type);
- }
+ if (type_is_structlike_strict(*param_type)) {
+ u32 mem_count = type_structlike_mem_count(*param_type);
+ StructMember smem;
- param_count += (*param_type)->Struct.mem_count - 1;
+ fori (i, 0, mem_count) {
+ type_lookup_member_by_idx(*param_type, i, &smem);
+ *(t++) = (char) onyx_type_to_wasm_type(smem.type);
+ }
+ param_count += mem_count - 1;
} else {
*(t++) = (char) onyx_type_to_wasm_type(*param_type);
}
// NOTE: Generate the local map
u64 localidx = 0;
bh_arr_each(AstParam, param, fd->params) {
- if (param->local->type->kind == Type_Kind_Struct) {
+ if (type_is_structlike_strict(param->local->type)) {
bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM);
- localidx += param->local->type->Struct.mem_count;
+ localidx += type_structlike_mem_count(param->local->type);
} else {
bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM);