typedef struct AstCall AstCall;
typedef struct AstIntrinsicCall AstIntrinsicCall;
typedef struct AstArgument AstArgument;
+typedef struct AstAddressOf AstAddressOf;
+typedef struct AstDereference AstDereference;
typedef struct AstArrayAccess AstArrayAccess;
typedef struct AstAssign AstAssign;
Ast_Kind_Call,
Ast_Kind_Intrinsic_Call,
Ast_Kind_Return,
+ Ast_Kind_Address_Of,
+ Ast_Kind_Dereference,
Ast_Kind_Array_Access,
Ast_Kind_If,
struct AstCall { AstTyped_base; AstArgument *arguments; u64 arg_count; AstNode *callee; };
struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; u64 arg_count; OnyxIntrinsic intrinsic; };
struct AstArgument { AstTyped_base; AstTyped *value; };
+struct AstAddressOf { AstTyped_base; AstTyped *expr; };
+struct AstDereference { AstTyped_base; AstTyped *expr; };
struct AstArrayAccess { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
// Intruction Node
struct AstType;
b32 types_are_compatible(Type* t1, Type* t2);
Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node);
+
+Type* type_make_pointer(bh_allocator alloc, Type* to);
+
const char* type_get_name(Type* type);
b32 type_is_pointer(Type* type);
str_test :: proc {
hello_str :: "Hello World!";
- walker := other_str;
- while walker[0] != 0 as u8 {
- print(walker[0] as i32);
-
- walker = (walker as i32 + 1) as ^u8;
- }
+ // Address of and dereference cancel each other out
+ print(^*hello_str);
print("This is a test"[10] as i32);
}
}
}
+// NOTE: print null-terminated string
+print_str :: proc (str: ^u8) {
+ c := str;
+ while *c != 0 as u8 {
+ print((*c) as i32);
+ c = (c as i32 + 1) as ^u8;
+ }
+}
+
print :: proc #overloaded {
print_bool,
print_i32,
print_i64arr,
print_f32arr,
print_f64arr,
+
+ print_str,
}
CHECK(call, AstCall* call);
CHECK(binaryop, AstBinaryOp* binop);
CHECK(expression, AstTyped* expr);
+CHECK(address_of, AstAddressOf* aof);
+CHECK(dereference, AstDereference* deref);
CHECK(array_access, AstArrayAccess* expr);
CHECK(global, AstGlobal* global);
CHECK(function, AstFunction* func);
return 0;
}
+CHECK(address_of, AstAddressOf* aof) {
+ if (check_expression(aof->expr)) return 1;
+
+ if (aof->expr->kind != Ast_Kind_Array_Access
+ && aof->expr->kind != Ast_Kind_Dereference) {
+ onyx_message_add(Msg_Type_Literal,
+ aof->token->pos,
+ "cannot take the address of this");
+ return 1;
+ }
+
+ aof->type = type_make_pointer(semstate.allocator, aof->expr->type);
+
+ return 0;
+}
+
+CHECK(dereference, AstDereference* deref) {
+ if (check_expression(deref->expr)) return 1;
+
+ if (!type_is_pointer(deref->expr->type)) {
+ onyx_message_add(Msg_Type_Literal,
+ deref->token->pos,
+ "cannot dereference non-pointer");
+ return 1;
+ }
+
+ if (deref->expr->type == basic_type_rawptr.type) {
+ onyx_message_add(Msg_Type_Literal,
+ deref->token->pos,
+ "cannot dereference rawptr");
+ return 1;
+ }
+
+ deref->type = deref->expr->type->Pointer.elem;
+
+ return 0;
+}
+
CHECK(array_access, AstArrayAccess* aa) {
- check_expression(aa->addr);
- check_expression(aa->expr);
+ if (check_expression(aa->addr)) return 1;
+ if (check_expression(aa->expr)) return 1;
if (!type_is_pointer(aa->addr->type)) {
onyx_message_add(Msg_Type_Literal,
case Ast_Kind_Local: break;
- case Ast_Kind_Array_Access:
- retval = check_array_access((AstArrayAccess *) expr);
- break;
+ case Ast_Kind_Address_Of: retval = check_address_of((AstAddressOf *) expr); break;
+ case Ast_Kind_Dereference: retval = check_dereference((AstDereference *) expr); break;
+ case Ast_Kind_Array_Access: retval = check_array_access((AstArrayAccess *) expr); break;
case Ast_Kind_Global:
if (expr->type == NULL) {
AstTyped* retval = NULL;
switch ((u16) parser->curr->type) {
- case '(':
- {
- consume_token(parser);
- AstTyped* expr = parse_expression(parser);
- expect_token(parser, ')');
- retval = expr;
- break;
- }
+ case '(': {
+ consume_token(parser);
+ AstTyped* expr = parse_expression(parser);
+ expect_token(parser, ')');
+ retval = expr;
+ break;
+ }
- case '-':
- {
- consume_token(parser);
- AstTyped* factor = parse_factor(parser);
+ case '-': {
+ consume_token(parser);
+ AstTyped* factor = parse_factor(parser);
- AstUnaryOp* negate_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
- negate_node->operation = Unary_Op_Negate;
- negate_node->expr = factor;
+ AstUnaryOp* negate_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
+ negate_node->operation = Unary_Op_Negate;
+ negate_node->expr = factor;
- if ((factor->flags & Ast_Flag_Comptime) != 0) {
- negate_node->flags |= Ast_Flag_Comptime;
- }
+ if ((factor->flags & Ast_Flag_Comptime) != 0) {
+ negate_node->flags |= Ast_Flag_Comptime;
+ }
- retval = (AstTyped *) negate_node;
- break;
+ retval = (AstTyped *) negate_node;
+ break;
+ }
+
+ case '!': {
+ AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
+ not_node->operation = Unary_Op_Not;
+ not_node->token = expect_token(parser, '!');
+ not_node->expr = parse_factor(parser);
+
+ if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
+ not_node->flags |= Ast_Flag_Comptime;
}
- case '!':
- {
- AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
- not_node->operation = Unary_Op_Not;
- not_node->token = expect_token(parser, '!');
- not_node->expr = parse_factor(parser);
+ retval = (AstTyped *) not_node;
+ break;
+ }
- if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
- not_node->flags |= Ast_Flag_Comptime;
- }
+ case '*': {
+ AstDereference* deref_node = make_node(AstDereference, Ast_Kind_Dereference);
+ deref_node->token = expect_token(parser, '*');
+ deref_node->expr = parse_factor(parser);
- retval = (AstTyped *) not_node;
+ retval = (AstTyped *) deref_node;
+ break;
+ }
+
+ case '^': {
+ AstAddressOf* aof_node = make_node(AstAddressOf, Ast_Kind_Address_Of);
+ aof_node->token = expect_token(parser, '^');
+ aof_node->expr = parse_factor(parser);
+
+ retval = (AstTyped *) aof_node;
+ break;
+ }
+
+ case Token_Type_Symbol: {
+ OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
+ AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
+ sym_node->token = sym_token;
+
+ if (parser->curr->type != '(') {
+ retval = sym_node;
break;
}
- case Token_Type_Symbol:
- {
- OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
- AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
- sym_node->token = sym_token;
+ // NOTE: Function call
+ AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
+ call_node->token = expect_token(parser, '(');
+ call_node->callee = (AstNode *) sym_node;
+ call_node->arg_count = 0;
- if (parser->curr->type != '(') {
- retval = sym_node;
- break;
+ AstArgument** prev = &call_node->arguments;
+ AstArgument* curr = NULL;
+ while (parser->curr->type != ')') {
+ curr = make_node(AstArgument, Ast_Kind_Argument);
+ curr->token = parser->curr;
+ curr->value = parse_expression(parser);
+
+ if (curr != NULL && curr->kind != Ast_Kind_Error) {
+ *prev = curr;
+ prev = (AstArgument **) &curr->next;
+
+ call_node->arg_count++;
}
- // NOTE: Function call
- AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
- call_node->token = expect_token(parser, '(');
- call_node->callee = (AstNode *) sym_node;
- call_node->arg_count = 0;
-
- AstArgument** prev = &call_node->arguments;
- AstArgument* curr = NULL;
- while (parser->curr->type != ')') {
- curr = make_node(AstArgument, Ast_Kind_Argument);
- curr->token = parser->curr;
- curr->value = parse_expression(parser);
-
- if (curr != NULL && curr->kind != Ast_Kind_Error) {
- *prev = curr;
- prev = (AstArgument **) &curr->next;
-
- call_node->arg_count++;
- }
-
- if (parser->curr->type == ')')
- break;
-
- if (parser->curr->type != ',') {
- onyx_message_add(Msg_Type_Expected_Token,
- parser->curr->pos,
- token_name(','),
- token_name(parser->curr->type));
- return (AstTyped *) &error_node;
- }
-
- consume_token(parser);
+ if (parser->curr->type == ')')
+ break;
+
+ if (parser->curr->type != ',') {
+ onyx_message_add(Msg_Type_Expected_Token,
+ parser->curr->pos,
+ token_name(','),
+ token_name(parser->curr->type));
+ return (AstTyped *) &error_node;
}
- consume_token(parser);
- retval = (AstTyped *) call_node;
- break;
+ consume_token(parser);
}
+ consume_token(parser);
+
+ retval = (AstTyped *) call_node;
+ break;
+ }
case Token_Type_Literal_Numeric:
retval = (AstTyped *) parse_numeric_literal(parser);
(*expr)->type_node = symres_type((*expr)->type_node);
break;
+ case Ast_Kind_Address_Of:
+ symres_expression(&((AstAddressOf *)(*expr))->expr);
+ break;
+
+ case Ast_Kind_Dereference:
+ symres_expression(&((AstDereference *)(*expr))->expr);
+ break;
+
case Ast_Kind_Array_Access:
symres_expression(&((AstArrayAccess *)(*expr))->addr);
symres_expression(&((AstArrayAccess *)(*expr))->expr);
switch (type_node->kind) {
case Ast_Kind_Pointer_Type: {
- Type* ptr_type = bh_alloc_item(alloc, Type);
-
- ptr_type->kind = Type_Kind_Pointer;
- ptr_type->Pointer.base.flags |= Basic_Flag_Pointer;
- ptr_type->Pointer.base.size = 4;
- ptr_type->Pointer.elem = type_build_from_ast(alloc, ((AstPointerType *) type_node)->elem);
-
- return (Type *) ptr_type;
+ return type_make_pointer(alloc, type_build_from_ast(alloc, ((AstPointerType *) type_node)->elem));
}
case Ast_Kind_Function_Type: {
}
}
+Type* type_make_pointer(bh_allocator alloc, Type* to) {
+ Type* ptr_type = bh_alloc_item(alloc, Type);
+
+ ptr_type->kind = Type_Kind_Pointer;
+ ptr_type->Pointer.base.flags |= Basic_Flag_Pointer;
+ ptr_type->Pointer.base.size = 4;
+ ptr_type->Pointer.elem = to;
+
+ return ptr_type;
+}
+
const char* type_get_name(Type* type) {
if (type == NULL) return "unknown";
"ARGUMENT",
"CALL",
"RETURN",
+ "ADDRESS OF",
+ "DEREFERENCE",
"ARRAY_ACCESS",
"IF",
case WI_I64_REINTERPRET_F64: return "WI_I64_REINTERPRET_F64";
case WI_F32_REINTERPRET_I32: return "WI_F32_REINTERPRET_I32";
case WI_F64_REINTERPRET_I64: return "WI_F64_REINTERPRET_I64";
+ case WI_I32_EXTEND_8_S: return "WI_I32_EXTEND_8_S";
+ case WI_I32_EXTEND_16_S: return "WI_I32_EXTEND_16_S";
+ case WI_I64_EXTEND_8_S: return "WI_I64_EXTEND_8_S";
+ case WI_I64_EXTEND_16_S: return "WI_I64_EXTEND_16_S";
+ case WI_I64_EXTEND_32_S: return "WI_I64_EXTEND_32_S";
}
}
case Ast_Kind_Binary_Op: compile_binop(mod, &code, (AstBinaryOp *) expr); break;
case Ast_Kind_Unary_Op: compile_unaryop(mod, &code, (AstUnaryOp *) expr); break;
+ case Ast_Kind_Address_Of: {
+ AstAddressOf* aof = (AstAddressOf *) expr;
+
+ switch (aof->expr->kind) {
+ case Ast_Kind_Dereference: {
+ compile_expression(mod, &code, ((AstDereference *) aof->expr)->expr);
+ break;
+ }
+
+ case Ast_Kind_Array_Access: {
+ AstArrayAccess* aa = (AstArrayAccess *) aof->expr;
+
+ compile_expression(mod, &code, aa->expr);
+ if (aa->elem_size != 1) {
+ WID(WI_I32_CONST, aa->elem_size);
+ WI(WI_I32_MUL);
+ }
+ compile_expression(mod, &code, aa->addr);
+ WI(WI_I32_ADD);
+ break;
+ }
+
+ default:
+ onyx_message_add(Msg_Type_Literal,
+ aof->token->pos,
+ "unsupported address of");
+ }
+
+ break;
+ }
+
+ case Ast_Kind_Dereference: {
+ AstDereference* deref = (AstDereference *) expr;
+ compile_expression(mod, &code, deref->expr);
+
+ i32 load_size = deref->type->Basic.size;
+ i32 is_integer = (deref->type->Basic.flags & Basic_Flag_Integer)
+ || (deref->type->Basic.flags & Basic_Flag_Pointer);
+ i32 is_unsigned = deref->type->Basic.flags & Basic_Flag_Unsigned;
+
+ WasmInstructionType instr = WI_NOP;
+ i32 alignment = log2_dumb(load_size);
+
+ if (is_integer) {
+ if (load_size == 1) instr = WI_I32_LOAD_8_S;
+ else if (load_size == 2) instr = WI_I32_LOAD_16_S;
+ else if (load_size == 4) instr = WI_I32_LOAD;
+ else if (load_size == 8) instr = WI_I64_LOAD;
+
+ if (alignment < 4 && is_unsigned) instr += 1;
+ } else {
+ if (load_size == 4) instr = WI_F32_LOAD;
+ else if (load_size == 8) instr = WI_F64_LOAD;
+ }
+
+ if (instr != WI_NOP) {
+ WID(instr, ((WasmInstructionData) { alignment, 0 }));
+ } else {
+ DEBUG_HERE;
+ }
+
+ break;
+ }
+
case Ast_Kind_Array_Access: {
AstArrayAccess* aa = (AstArrayAccess *) expr;
compile_expression(mod, &code, aa->expr);