--- /dev/null
+package core
+
+Buffer :: struct {
+ length: u32;
+ data: rawptr;
+}
\ No newline at end of file
[ ] Struct literals
+ [ ] #union on structs
+
+ [ ] #align on structs
+
[ ] 'use' enums and packages at an arbitrary scope
+ [ ] Array literals
+
+ [ ] Top level variable initialization
+ - Works for numeric literals
+
[ ] multiple lvals and compound assignment
a := 2
b := 5
a, b = b, a;
-
+
[ ] All code paths return correct value
+ [ ] Type parameterized structs
+
[ ] Add slices
- Arrays without a size
- Converted to a struct that looks like:
[ ] returning structs
- This will put forward a lot of the work that will be done for multiple return values
- [ ] Type parameterized structs
-
- [ ] Array literals
-
- [ ] Top level variable initialization
- - Works for numeric literals
-
[X] Start work on evaluating compile time known values.
- An expression marked COMPTIME will be reduced to its value in the parse tree.
#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 forll(T, var, start, step) for (T* var = (start); var != NULL; var = var->step)
#ifdef BH_DEBUG
bh_arr_new(alloc, imap->hashes, hash_count);
bh_arr_new(alloc, imap->entries, 4);
- fori(count, 0, hash_count - 1) bh_arr_push(imap->hashes, -1);
+ fori(count, 0, hash_count) bh_arr_push(imap->hashes, -1);
}
void bh_imap_free(bh_imap* imap) {
typedef struct AstSizeOf AstSizeOf;
typedef struct AstAlignOf AstAlignOf;
typedef struct AstFileContents AstFileContents;
+typedef struct AstStructLiteral AstStructLiteral;
typedef struct AstReturn AstReturn;
typedef struct AstBreak AstBreak;
typedef struct AstFunctionType AstFunctionType;
typedef struct AstArrayType AstArrayType;
typedef struct AstStructType AstStructType;
-typedef struct AstStructMember AstStructMember;
typedef struct AstEnumType AstEnumType;
typedef struct AstEnumValue AstEnumValue;
typedef struct AstTypeAlias AstTypeAlias;
Ast_Kind_Size_Of,
Ast_Kind_Align_Of,
Ast_Kind_File_Contents,
+ Ast_Kind_Struct_Literal,
Ast_Kind_If,
Ast_Kind_For,
struct AstSizeOf { AstTyped_base; AstType *so_type; u64 size; };
struct AstAlignOf { AstTyped_base; AstType *ao_type; u64 alignment; };
struct AstFileContents { AstTyped_base; OnyxToken *filename; };
+struct AstStructLiteral { AstTyped_base; AstTyped *stnode; bh_arr(AstTyped *) values; };
// Intruction Node
struct AstReturn { AstNode_base; AstTyped* expr; };
struct AstStructType {
AstType_base;
- bh_arr(AstStructMember *) members;
+ bh_arr(AstTyped *) members;
// NOTE: Used to cache the actual type, since building
// a struct type is kind of complicated and should
// only happen once.
Type *stcache;
};
-struct AstStructMember { AstTyped_base; u64 offset; };
struct AstEnumType {
AstType_base;
Scope *scope;
#include_file "printing"
#include_file "alloc"
+#include_file "test"
use package printing
use package memory
+use package core as core
sort :: proc (arr: [N]i32, cmp: proc (i32, i32) -> i32) -> [N] i32 {
for i: 0, N {
z: i32;
}
-mag_squared :: proc (v: Vec3) -> i32 {
- return v.x * v.x + v.y * v.y + v.z * v.z;
+mag_squared :: proc (use v: Vec3) -> i32 {
+ return x * x + y * y + z * z;
}
vec_add :: proc (v: Vec3, u: Vec3, use out: ^Vec3) {
//
// This is intended behavior since creating new
// procs at runtime is very difficult with WASM
-stupid_idea :: proc (n: i32) -> proc () -> i32 {
+stupid_idea :: proc (n: i32) -> proc (i32) -> i32 {
if n == 1234 {
- return proc -> i32 { return 5678; };
+ return proc (a: i32) -> i32 { return 5678 + a; };
}
- return proc -> i32 { return -1; };
+ return proc (a: i32) -> i32 { return -1 + a; };
}
some_value := 20 + 30 * 4 + 15 / 5;
for i: 0, N do something[i] = N - i;
for i: 0, N do print(something[i]);
- val := something
+ something
|> sort(proc (a: i32, b: i32) -> i32 { return a - b; })
|> sumN()
- |> clamp(30, 100);
- print(val);
+ |> clamp(30, 100)
+ |> print();
for i: 0, N do
something[i]
|> clamp(3, 6)
|> print();
- stupid_idea(1234)() |> print();
+ stupid_idea(1234)(1234) |> print();
varr : [5] Vec3;
- varr[2].x = 4;
- varr[2].y = 5;
- varr[2].z = 6;
- mag_squared(varr[2]) |> print();
+ varr[2] = Vec3 .{4, 5, 6};
- v1 : Vec3;
- v1.x = 1;
- v1.y = 2;
- v1.z = 4;
+ mag_squared(varr[2]) |> print();
- v2 := v1;
+ v1 := Vec3 .{ 1, 2, 4 };
+ v2 := *vadd(Vec3.{4, 3, 2}, Vec3.{1, 1, 1});
+
+ print(v2.x);
+ print(v2.y);
+ print(v2.z);
- v3 := *vadd(v1, v2);
- print(v3.x);
- print(v3.y);
- print(v3.z);
+ buf := core.Buffer.{ 16, null };
}
vadd :: proc (v1: Vec3, v2: Vec3) -> ^Vec3 {
// NOTE: Add the current folder
bh_arr_push(options.included_folders, ".");
- fori(i, 1, argc - 1) {
+ fori(i, 1, argc) {
if (!strcmp(argv[i], "-help")) {
options.action = ONYX_COMPILE_ACTION_PRINT_HELP;
break;
static char* lookup_included_file(CompilerState* cs, OnyxToken* filename) {
static char path[256];
- fori (i, 0, 255) path[i] = 0;
+ fori (i, 0, 256) path[i] = 0;
static char fn[128];
- fori (i, 0, 127) fn[i] = 0;
+ fori (i, 0, 128) fn[i] = 0;
token_toggle_end(filename);
if (!bh_str_ends_with(filename->text, ".onyx")) {
bh_snprintf(fn, 128, "%s.onyx", filename->text);
CHECK(call, AstCall* call);
CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok);
CHECK(unaryop, AstUnaryOp** punop);
+CHECK(struct_literal, AstStructLiteral* sl);
CHECK(expression, AstTyped** expr);
CHECK(address_of, AstAddressOf* aof);
CHECK(dereference, AstDereference* deref);
return 0;
}
+CHECK(struct_literal, AstStructLiteral* sl) {
+ fill_in_type((AstTyped *) sl);
+
+ TypeStruct* st = &sl->type->Struct;
+ if (st->mem_count != bh_arr_length(sl->values)) {
+ onyx_message_add(Msg_Type_Literal,
+ sl->token->pos,
+ "incorrect number of initial values for this type");
+ return 1;
+ }
+
+ AstTyped** actual = sl->values;
+ StructMember** formal = st->memarr;
+
+ fori (i, 0, st->mem_count) {
+ if (check_expression(actual)) return 1;
+
+ if (!types_are_compatible((*formal)->type, (*actual)->type)) {
+ onyx_message_add(Msg_Type_Assignment_Mismatch,
+ (*actual)->token->pos,
+ type_get_name((*formal)->type),
+ type_get_name((*actual)->type));
+ return 1;
+ }
+
+ actual++, formal++;
+ }
+
+ return 0;
+}
+
CHECK(address_of, AstAddressOf* aof) {
if (check_expression(&aof->expr)) return 1;
assert(expr->type != NULL);
break;
+ case Ast_Kind_Struct_Literal:
+ retval = check_struct_literal((AstStructLiteral *) expr);
+ break;
+
case Ast_Kind_Function:
expr->flags |= Ast_Flag_Function_Used;
break;
return 1;
}
- bh_arr_each(AstStructMember *, member, s_node->members) {
+ bh_arr_each(AstTyped *, member, s_node->members) {
token_toggle_end((*member)->token);
if (bh_table_has(i32, mem_set, (*member)->token->text)) {
// NOTE: The one weird define you need to know before read the code below
#define make_node(nclass, kind) onyx_ast_node_new(parser->allocator, sizeof(nclass), kind)
+#define STORE_PARSER_STATE \
+ OnyxToken* __parser_curr = parser->curr; \
+ OnyxToken* __parser_prev = parser->prev;
+
+#define RESTORE_PARSER_STATE \
+ parser->curr = __parser_curr; \
+ parser->prev = __parser_prev;
+
static AstNode error_node = { Ast_Kind_Error, 0, NULL, NULL };
// NOTE: Forward declarations
static AstNumLit* parse_int_literal(OnyxParser* parser);
static AstNumLit* parse_float_literal(OnyxParser* parser);
+static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret);
static AstTyped* parse_factor(OnyxParser* parser);
static AstTyped* parse_expression(OnyxParser* parser);
static AstIf* parse_if_stmt(OnyxParser* parser);
static AstWhile* parse_while_stmt(OnyxParser* parser);
static AstFor* parse_for_stmt(OnyxParser* parser);
-static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret);
+static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret);
static AstReturn* parse_return_statement(OnyxParser* parser);
static AstBlock* parse_block(OnyxParser* parser);
static AstNode* parse_statement(OnyxParser* parser);
return token;
}
+static OnyxToken* soft_expect_token(OnyxParser* parser, TokenType token_type) {
+ if (parser->hit_unexpected_token) return NULL;
+
+ OnyxToken* token = parser->curr;
+
+ if (token->type == token_type) {
+ consume_token(parser);
+ return token;
+ }
+
+ return NULL;
+}
+
static void add_node_to_process(OnyxParser* parser, AstNode* node) {
bh_arr_push(parser->results.nodes_to_process, ((NodeToProcess) {
.package = parser->package,
return float_node;
}
+static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped** ret) {
+ if (parser->curr->type != Token_Type_Symbol) return 0;
+
+ STORE_PARSER_STATE;
+
+ OnyxToken *symbol1 = NULL, *symbol2 = NULL;
+ symbol1 = expect_token(parser, Token_Type_Symbol);
+
+ if (!soft_expect_token(parser, '.')) {
+ RESTORE_PARSER_STATE;
+ return 0;
+ }
+
+ if (parser->curr->type == Token_Type_Symbol) {
+ symbol2 = soft_expect_token(parser, Token_Type_Symbol);
+
+ if (!soft_expect_token(parser, '.')) {
+ RESTORE_PARSER_STATE;
+ return 0;
+ }
+ }
+
+ if (parser->curr->type != '{') {
+ RESTORE_PARSER_STATE;
+ return 0;
+ }
+
+ AstStructLiteral* sl = make_node(AstStructLiteral, Ast_Kind_Struct_Literal);
+ sl->token = parser->curr;
+ bh_arr_new(global_heap_allocator, sl->values, 4);
+
+ if (symbol2 != NULL) {
+ AstTyped *package = make_node(AstTyped, Ast_Kind_Symbol);
+ package->token = symbol1;
+
+ AstFieldAccess *fa = make_node(AstFieldAccess, Ast_Kind_Field_Access);
+ fa->token = symbol2;
+ fa->expr = package;
+
+ sl->stnode = (AstTyped *) fa;
+
+ } else {
+ sl->stnode = make_node(AstTyped, Ast_Kind_Symbol);
+ sl->stnode->token = symbol1;
+ }
+
+ expect_token(parser, '{');
+ while (parser->curr->type != '}') {
+ if (parser->hit_unexpected_token) break;
+
+ AstTyped *expr = parse_expression(parser);
+ bh_arr_push(sl->values, expr);
+
+ if (parser->curr->type != '}')
+ expect_token(parser, ',');
+ }
+
+ expect_token(parser, '}');
+
+ *ret = (AstTyped *) sl;
+
+ return 1;
+}
+
// ( <expr> )
// - <factor>
// ! <factor>
}
case Token_Type_Symbol: {
+ if (parse_possible_struct_literal(parser, &retval)) return retval;
+
OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
sym_node->token = sym_token;
// <symbol> : <type> : <expr>
// <symbol> := <expr>
// <symbol> :: <expr>
-static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret) {
+static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret) {
if (parser->curr->type != Token_Type_Symbol) return 0;
if ((parser->curr + 1)->type != ':') return 0;
break;
case Token_Type_Symbol:
- if (parse_symbol_declaration(parser, &retval)) break;
+ if (parse_possible_symbol_declaration(parser, &retval)) break;
// fallthrough
case '(':
new->return_type = return_type;
if (param_count > 0)
- fori (i, 0, param_count - 1) new->params[i] = params[i];
+ fori (i, 0, param_count) new->params[i] = params[i];
*next_insertion = (AstType *) new;
next_insertion = NULL;
while (parser->curr->type != '}') {
if (parser->hit_unexpected_token) return s_node;
- AstStructMember* mem = make_node(AstStructMember, Ast_Kind_Struct_Member);
- mem->offset = 0;
+ AstTyped* mem = make_node(AstTyped, Ast_Kind_Struct_Member);
mem->token = expect_token(parser, Token_Type_Symbol);
expect_token(parser, ':');
ftype->return_type = symres_type(ftype->return_type);
if (ftype->param_count > 0)
- fori (i, 0, ftype->param_count - 1) {
+ fori (i, 0, ftype->param_count) {
ftype->params[i] = symres_type(ftype->params[i]);
}
s_node->flags |= Ast_Flag_Type_Is_Resolved;
- bh_arr_each(AstStructMember *, member, s_node->members) {
+ bh_arr_each(AstTyped *, member, s_node->members) {
(*member)->type_node = symres_type((*member)->type_node);
}
(*unaryop)->type_node = ((AstUnaryOp *)(*unaryop))->expr->type_node;
}
+static void symres_struct_literal(AstStructLiteral* sl) {
+ if (sl->stnode != NULL) symres_expression(&sl->stnode);
+ if (sl->stnode == NULL) return;
+
+ if (sl->stnode->kind != Ast_Kind_Struct_Type) {
+ onyx_message_add(Msg_Type_Literal,
+ sl->token->pos,
+ "type is not a struct type (BAD ERROR MESSAGE)");
+ return;
+ }
+
+ sl->type_node = (AstType *) sl->stnode;
+
+ bh_arr_each(AstTyped *, expr, sl->values) symres_expression(expr);
+}
+
static void symres_expression(AstTyped** expr) {
switch ((*expr)->kind) {
case Ast_Kind_Symbol:
symres_expression(&((AstBinaryOp *)(*expr))->left);
symres_expression(&((AstBinaryOp *)(*expr))->right);
- (*expr)->type_node = ((AstBinaryOp *)(*expr))->left->type_node;
+ if (((AstBinaryOp *) (*expr))->left)
+ (*expr)->type_node = ((AstBinaryOp *)(*expr))->left->type_node;
break;
case Ast_Kind_Unary_Op: symres_unaryop((AstUnaryOp **) expr); break;
symres_expression(&((AstArrayAccess *)(*expr))->expr);
break;
+ case Ast_Kind_Struct_Literal:
+ symres_struct_literal((AstStructLiteral *)(*expr));
+ break;
+
default: break;
}
}
param->type_node = symres_type(param->type_node);
param->type = type_build_from_ast(semstate.allocator, param->type_node);
+ if (param->type == NULL) break;
+
symbol_introduce(semstate.curr_scope, param->token, (AstNode *) param);
if (param->flags & Ast_Flag_Param_Use) {
st = (AstStructType *) ((AstPointerType *) param->type_node)->elem;
}
- bh_arr_each(AstStructMember *, mem, st->members) {
+ bh_arr_each(AstTyped *, mem, st->members) {
AstFieldAccess* fa = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access);
fa->token = (*mem)->token;
fa->type_node = (*mem)->type_node;
case Type_Kind_Struct: {
if (t2->kind != Type_Kind_Struct) return 0;
if (t1->Struct.mem_count != t2->Struct.mem_count) return 0;
- if (t1->Struct.name && t2->Struct.name)
- if (strcmp(t1->Struct.name, t2->Struct.name) == 0) return 1;
b32 works = 1;
bh_table_each_start(StructMember, t1->Struct.members);
if (!types_are_compatible(t1->Function.return_type, t2->Function.return_type)) return 0;
if (t1->Function.param_count > 0) {
- fori (i, 0, t1->Function.param_count - 1) {
+ fori (i, 0, t1->Function.param_count) {
if (!types_are_compatible(t1->Function.params[i], t2->Function.params[i])) return 0;
}
}
func_type->Function.return_type = type_build_from_ast(alloc, ftype_node->return_type);
if (param_count > 0)
- fori (i, 0, param_count - 1) {
+ fori (i, 0, param_count) {
func_type->Function.params[i] = type_build_from_ast(alloc, ftype_node->params[i]);
}
u32 offset = 0;
u32 alignment = 1, mem_alignment;
u32 idx = 0;
- bh_arr_each(AstStructMember *, member, s_node->members) {
+ bh_arr_each(AstTyped *, member, s_node->members) {
(*member)->type = type_build_from_ast(alloc, (*member)->type_node);
// TODO: Add alignment checking here
token_toggle_end((*member)->token);
bh_table_put(StructMember, s_type->Struct.members, (*member)->token->text, smem);
- bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, (*member)->token->text));
token_toggle_end((*member)->token);
offset += type_size_of((*member)->type);
idx++;
}
+ // NOTE: Need to do a second pass because the references to the
+ // elements of the table may change if the internal arrays of the
+ // table need to be resized.
+ bh_arr_each(AstTyped *, member, s_node->members) {
+ token_toggle_end((*member)->token);
+ bh_arr_push(s_type->Struct.memarr, &bh_table_get(StructMember, s_type->Struct.members, (*member)->token->text));
+ token_toggle_end((*member)->token);
+ }
+
s_type->Struct.aligment = alignment;
if (offset % alignment != 0) {
COMPILE_FUNC(memory_reservation_location, AstMemRes* memres);
COMPILE_FUNC(struct_load, Type* type, u64 offset);
COMPILE_FUNC(struct_store, AstTyped* lval);
+COMPILE_FUNC(struct_literal, AstStructLiteral* sl);
COMPILE_FUNC(expression, AstTyped* expr);
COMPILE_FUNC(cast, AstUnaryOp* cast);
COMPILE_FUNC(return, AstReturn* ret);
*pcode = code;
}
+COMPILE_FUNC(struct_literal, AstStructLiteral* sl) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ bh_arr_each(AstTyped *, val, sl->values) {
+ compile_expression(mod, &code, *val);
+ }
+
+ *pcode = code;
+}
+
COMPILE_FUNC(expression, AstTyped* expr) {
bh_arr(WasmInstruction) code = *pcode;
break;
}
+ case Ast_Kind_Struct_Literal: {
+ compile_struct_literal(mod, &code, (AstStructLiteral *) expr);
+ break;
+ }
+
case Ast_Kind_Function: {
i32 elemidx = get_element_idx(mod, (AstFunction *) expr);
WID(WI_I32_CONST, elemidx);
leb = uint_to_uleb128((u64) datum->length, &leb_len);
bh_buffer_append(&vec_buff, leb, leb_len);
- fori (i, 0, datum->length - 1) bh_buffer_write_byte(&vec_buff, ((u8 *) datum->data)[i]);
+ fori (i, 0, datum->length) bh_buffer_write_byte(&vec_buff, ((u8 *) datum->data)[i]);
}
leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len);