mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-27 09:50:03 +00:00
Win32 Window Test
This commit is contained in:
@@ -452,7 +452,8 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode
|
||||
|
||||
if (mode == Addressing_Constant) {
|
||||
GB_ASSERT(value.kind != ExactValue_Invalid);
|
||||
GB_ASSERT(type == t_invalid || is_type_constant_type(type));
|
||||
GB_ASSERT_MSG(type != t_invalid || is_type_constant_type(type),
|
||||
"type: %s", type_to_string(type));
|
||||
}
|
||||
|
||||
TypeAndValue tv = {};
|
||||
@@ -473,7 +474,11 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||
if (!are_strings_equal(entity->token.string, make_string("_"))) {
|
||||
Entity *insert_entity = scope_insert_entity(scope, entity);
|
||||
if (insert_entity) {
|
||||
error(&c->error_collector, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string));
|
||||
error(&c->error_collector, entity->token,
|
||||
"Redeclararation of `%.*s` in this scope\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(entity->token.string),
|
||||
LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-19
@@ -843,19 +843,19 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// untyped integers -> pointers
|
||||
if (is_type_untyped(xb) && is_type_integer(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
// // untyped integers -> pointers
|
||||
// if (is_type_untyped(xb) && is_type_integer(xb)) {
|
||||
// if (is_type_pointer(yb))
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// (u)int <-> pointer
|
||||
if (is_type_pointer(xb) || is_type_int_or_uint(xb)) {
|
||||
if (is_type_pointer(xb) || (is_type_int_or_uint(xb) && !is_type_untyped(xb))) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
if (is_type_pointer(xb)) {
|
||||
if (is_type_pointer(yb) || is_type_int_or_uint(yb))
|
||||
if (is_type_pointer(yb) || (is_type_int_or_uint(yb) && !is_type_untyped(yb)))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -888,9 +888,9 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
b32 can_convert = false;
|
||||
|
||||
if (is_const_expr && is_type_constant_type(type)) {
|
||||
Type *t = get_base_type(type);
|
||||
if (t->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, x->value, t, &x->value)) {
|
||||
Type *base_type = get_base_type(type);
|
||||
if (base_type->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, x->value, base_type, &x->value)) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
@@ -1807,7 +1807,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
case Token_Float: t = t_untyped_float; break;
|
||||
case Token_String: t = t_untyped_string; break;
|
||||
case Token_Rune: t = t_untyped_rune; break;
|
||||
default: GB_PANIC("Unknown literal"); break;
|
||||
default: GB_PANIC("Unknown literal"); break;
|
||||
}
|
||||
o->mode = Addressing_Constant;
|
||||
o->type = t;
|
||||
@@ -1815,16 +1815,16 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
case_end;
|
||||
|
||||
case_ast_node(pl, ProcLit, node);
|
||||
auto curr_context = c->context;
|
||||
c->context.scope = c->global_scope;
|
||||
check_open_scope(c, pl->type);
|
||||
c->context.decl = make_declaration_info(c->allocator, c->context.scope);
|
||||
defer ({
|
||||
check_close_scope(c);
|
||||
c->context = curr_context;
|
||||
});
|
||||
Type *proc_type = check_type(c, pl->type);
|
||||
if (proc_type != NULL) {
|
||||
auto context = c->context;
|
||||
c->context.scope = c->global_scope;
|
||||
check_open_scope(c, pl->type);
|
||||
c->context.decl = make_declaration_info(c->allocator, c->context.scope);
|
||||
defer ({
|
||||
c->context = context;
|
||||
check_close_scope(c);
|
||||
});
|
||||
check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);
|
||||
o->mode = Addressing_Value;
|
||||
o->type = proc_type;
|
||||
|
||||
@@ -351,7 +351,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
|
||||
e->type = t;
|
||||
}
|
||||
|
||||
Operand operand = {Addressing_Invalid};
|
||||
Operand operand = {};
|
||||
if (init_expr)
|
||||
check_expr(c, &operand, init_expr);
|
||||
check_init_constant(c, e, &operand);
|
||||
|
||||
+11
-8
@@ -71,14 +71,15 @@ void ssa_gen_code(ssaGen *s) {
|
||||
} break;
|
||||
|
||||
case Entity_Variable: {
|
||||
ssaValue *value = ssa_build_expr(&dummy_proc, decl->init_expr);
|
||||
if (value->kind == ssaValue_Instr) {
|
||||
ssaInstr *i = &value->instr;
|
||||
if (i->kind == ssaInstr_Load) {
|
||||
value = i->load.address;
|
||||
}
|
||||
}
|
||||
ssaValue *g = ssa_make_value_global(a, e, value);
|
||||
// ssaValue *value = ssa_build_expr(&dummy_proc, decl->init_expr);
|
||||
// if (value->kind == ssaValue_Instr) {
|
||||
// ssaInstr *i = &value->instr;
|
||||
// if (i->kind == ssaInstr_Load) {
|
||||
// value = i->load.address;
|
||||
// }
|
||||
// }
|
||||
// TODO(bill): global runtime initialization
|
||||
ssaValue *g = ssa_make_value_global(a, e, NULL);
|
||||
map_set(&m->values, hash_pointer(e), g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
} break;
|
||||
@@ -91,6 +92,8 @@ void ssa_gen_code(ssaGen *s) {
|
||||
name = pd->foreign_name;
|
||||
}
|
||||
ssaValue *p = ssa_make_value_procedure(a, m, e->type, decl->type_expr, body, name);
|
||||
p->proc.tags = pd->tags;
|
||||
|
||||
map_set(&m->values, hash_pointer(e), p);
|
||||
map_set(&m->members, hash_string(name), p);
|
||||
} break;
|
||||
|
||||
+60
-32
@@ -174,21 +174,22 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
|
||||
ssa_fprintf(f, "}");
|
||||
}
|
||||
break;
|
||||
case Type_Proc:
|
||||
case Type_Proc: {
|
||||
if (t->proc.result_count == 0) {
|
||||
ssa_fprintf(f, "void");
|
||||
} else {
|
||||
ssa_print_type(f, s, t->proc.results);
|
||||
}
|
||||
ssa_fprintf(f, " (");
|
||||
auto *params = &t->proc.params->tuple;
|
||||
for (isize i = 0; i < t->proc.param_count; i++) {
|
||||
if (i > 0) {
|
||||
ssa_fprintf(f, ", ");
|
||||
}
|
||||
ssa_print_type(f, s, &t->proc.params[i]);
|
||||
ssa_print_type(f, s, params->variables[i]->type);
|
||||
}
|
||||
ssa_fprintf(f, ")*");
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,9 +209,9 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
|
||||
ssa_print_escape_string(f, value.value_string, false);
|
||||
ssa_fprintf(f, "\"");
|
||||
} break;
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Integer: {
|
||||
ssa_fprintf(f, "%lld", value.value_integer);
|
||||
break;
|
||||
} break;
|
||||
case ExactValue_Float: {
|
||||
u64 u = *cast(u64*)&value.value_float;
|
||||
if (is_type_float(type) && type->basic.kind == Basic_f32) {
|
||||
@@ -506,7 +507,7 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
|
||||
case ssaInstr_Call: {
|
||||
auto *call = &instr->call;
|
||||
Type *result_type = call->type->proc.results;
|
||||
Type *result_type = call->type;
|
||||
if (result_type) {
|
||||
ssa_fprintf(f, "%%%d = ", value->id);
|
||||
}
|
||||
@@ -521,18 +522,22 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
|
||||
|
||||
ssa_fprintf(f, "(");
|
||||
auto *params = &call->type->proc.params->tuple;
|
||||
for (isize i = 0; i < call->arg_count; i++) {
|
||||
Entity *e = params->variables[i];
|
||||
GB_ASSERT(e != NULL);
|
||||
Type *t = e->type;
|
||||
if (i > 0) {
|
||||
ssa_fprintf(f, ", ");
|
||||
if (call->arg_count > 0) {
|
||||
Type *proc_type = get_base_type(ssa_value_type(call->value));
|
||||
GB_ASSERT(proc_type->kind == Type_Proc);
|
||||
auto *params = &proc_type->proc.params->tuple;
|
||||
for (isize i = 0; i < call->arg_count; i++) {
|
||||
Entity *e = params->variables[i];
|
||||
GB_ASSERT(e != NULL);
|
||||
Type *t = e->type;
|
||||
if (i > 0) {
|
||||
ssa_fprintf(f, ", ");
|
||||
}
|
||||
ssa_print_type(f, m->sizes, t);
|
||||
ssa_fprintf(f, " ");
|
||||
ssaValue *arg = call->args[i];
|
||||
ssa_print_value(f, m, arg, t);
|
||||
}
|
||||
ssa_print_type(f, m->sizes, t);
|
||||
ssa_fprintf(f, " ");
|
||||
ssaValue *arg = call->args[i];
|
||||
ssa_print_value(f, m, arg, t);
|
||||
}
|
||||
ssa_fprintf(f, ")\n");
|
||||
|
||||
@@ -650,9 +655,18 @@ void ssa_print_proc(gbFile *f, ssaModule *m, ssaProcedure *proc) {
|
||||
|
||||
ssa_fprintf(f, ") ");
|
||||
|
||||
if (proc->body == NULL) {
|
||||
ssa_fprintf(f, "; foreign procedure\n\n");
|
||||
} else {
|
||||
if (proc->tags != 0) {
|
||||
if (proc->tags & ProcTag_inline)
|
||||
ssa_fprintf(f, "alwaysinline ");
|
||||
if (proc->tags & ProcTag_no_inline)
|
||||
ssa_fprintf(f, "noinline ");
|
||||
|
||||
|
||||
if (proc->tags & ProcTag_foreign)
|
||||
ssa_fprintf(f, "; foreign\n");
|
||||
}
|
||||
|
||||
if (proc->body != NULL) {
|
||||
ssa_fprintf(f, "{\n");
|
||||
gb_for_array(i, proc->blocks) {
|
||||
ssaBlock *block = proc->blocks[i];
|
||||
@@ -682,6 +696,7 @@ void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) {
|
||||
ssa_fprintf(f, "\n");
|
||||
}
|
||||
|
||||
|
||||
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||
if (m->layout.len > 0) {
|
||||
ssa_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
|
||||
@@ -695,17 +710,6 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||
ssa_print_encoded_local(f, make_string(".rawptr"));
|
||||
ssa_fprintf(f, " = type i8* ; Basic_rawptr\n\n");
|
||||
|
||||
ssa_fprintf(f, "declare void @llvm.memmove.p0i8.p0i8.");
|
||||
ssa_print_type(f, m->sizes, t_int);
|
||||
ssa_fprintf(f, "(i8*, i8*, ");
|
||||
ssa_print_type(f, m->sizes, t_int);
|
||||
ssa_fprintf(f, ", i32, i1) argmemonly nounwind \n\n");
|
||||
|
||||
gb_for_array(i, m->nested_type_names) {
|
||||
ssaValue *v = m->nested_type_names[i];
|
||||
ssa_print_type_name(f, m, v);
|
||||
}
|
||||
|
||||
gb_for_array(member_index, m->members.entries) {
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
ssaValue *v = entry->value;
|
||||
@@ -716,7 +720,27 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||
ssa_print_type(f, m->sizes, get_base_type(v->type_name.type));
|
||||
ssa_fprintf(f, "\n");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
gb_for_array(i, m->nested_type_names) {
|
||||
ssaValue *v = m->nested_type_names[i];
|
||||
ssa_print_type_name(f, m, v);
|
||||
}
|
||||
|
||||
|
||||
ssa_fprintf(f, "declare void @llvm.memmove.p0i8.p0i8.");
|
||||
ssa_print_type(f, m->sizes, t_int);
|
||||
ssa_fprintf(f, "(i8*, i8*, ");
|
||||
ssa_print_type(f, m->sizes, t_int);
|
||||
ssa_fprintf(f, ", i32, i1) argmemonly nounwind \n\n");
|
||||
|
||||
|
||||
|
||||
gb_for_array(member_index, m->members.entries) {
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
ssaValue *v = entry->value;
|
||||
switch (v->kind) {
|
||||
case ssaValue_Global: {
|
||||
auto *g = &v->global;
|
||||
ssa_print_encoded_global(f, g->entity->token.string);
|
||||
@@ -729,7 +753,11 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
|
||||
|
||||
ssa_print_type(f, m->sizes, get_base_type(g->entity->type));
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, g->value, g->entity->type);
|
||||
if (g->value != NULL) {
|
||||
ssa_print_value(f, m, g->value, g->entity->type);
|
||||
} else {
|
||||
ssa_fprintf(f, "zeroinitializer");
|
||||
}
|
||||
ssa_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
|
||||
+23
-12
@@ -46,6 +46,7 @@ struct ssaProcedure {
|
||||
Type * type;
|
||||
AstNode * type_expr;
|
||||
AstNode * body;
|
||||
u64 tags;
|
||||
|
||||
gbArray(ssaBlock *) blocks;
|
||||
ssaBlock * curr_block;
|
||||
@@ -318,13 +319,13 @@ Type *ssa_instr_type(ssaInstr *instr) {
|
||||
case ssaInstr_Select:
|
||||
return ssa_value_type(instr->select.true_value);
|
||||
case ssaInstr_Call: {
|
||||
Type *pt = instr->call.type;
|
||||
GB_ASSERT(pt->kind == Type_Proc);
|
||||
auto *tuple = &pt->proc.results->tuple;
|
||||
if (tuple->variable_count != 1)
|
||||
return pt->proc.results;
|
||||
else
|
||||
return tuple->variables[0]->type;
|
||||
Type *pt = get_base_type(instr->call.type);
|
||||
if (pt != NULL) {
|
||||
if (pt->kind == Type_Tuple && pt->tuple.variable_count == 1)
|
||||
return pt->tuple.variables[0]->type;
|
||||
return pt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
case ssaInstr_CopyMemory:
|
||||
return t_int;
|
||||
@@ -891,7 +892,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
|
||||
case ssaInstr_CopyMemory:
|
||||
continue;
|
||||
case ssaInstr_Call:
|
||||
if (instr->call.type->proc.results == NULL) {
|
||||
if (instr->call.type == NULL) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -1194,6 +1195,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
Type *src = get_base_type(src_type);
|
||||
Type *dst = get_base_type(t);
|
||||
if (are_types_identical(t, src_type))
|
||||
@@ -1208,6 +1210,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
//
|
||||
} else if (is_type_integer(dst)) {
|
||||
ev = exact_value_to_integer(ev);
|
||||
} else if (is_type_pointer(dst)) {
|
||||
// IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect `null`
|
||||
ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_uint, ev);
|
||||
return ssa_emit(proc, ssa_make_instr_conv(proc, ssaConv_inttoptr, i, t_uint, dst));
|
||||
}
|
||||
return ssa_make_value_constant(proc->module->allocator, t, ev);
|
||||
}
|
||||
@@ -1459,6 +1465,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
|
||||
proc->module, type, pl->type, pl->body, name);
|
||||
|
||||
value->proc.tags = pl->tags;
|
||||
|
||||
gb_array_append(proc->children, &value->proc);
|
||||
ssa_build_proc(value, proc);
|
||||
|
||||
@@ -1693,8 +1701,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
}
|
||||
}
|
||||
|
||||
ssaValue *call = ssa_make_instr_call(proc, value, args, arg_count, tv->type);
|
||||
ssa_value_set_type(call, proc_type_);
|
||||
ssaValue *call = ssa_make_instr_call(proc, value, args, arg_count, type->results);
|
||||
return ssa_emit(proc, call);
|
||||
case_end;
|
||||
|
||||
@@ -1725,6 +1732,7 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) {
|
||||
ssaValue *elem = ssa_array_elem(proc, array);
|
||||
return ssa_emit_load(proc, ssa_emit_string(proc, elem, ssa_array_len(proc, array)));
|
||||
}
|
||||
|
||||
return ssa_make_value_constant(proc->module->allocator, tv->type, tv->value);
|
||||
}
|
||||
|
||||
@@ -2043,6 +2051,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
if (proc->children == NULL) {
|
||||
gb_array_init(proc->children, gb_heap_allocator());
|
||||
}
|
||||
|
||||
|
||||
if (pd->body != NULL) {
|
||||
// NOTE(bill): Generate a new name
|
||||
// parent$name-guid
|
||||
@@ -2059,6 +2069,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
|
||||
proc->module, e->type, pd->type, pd->body, name);
|
||||
|
||||
value->proc.tags = pd->tags;
|
||||
|
||||
ssa_module_add_value(proc->module, e, value);
|
||||
gb_array_append(proc->children, &value->proc);
|
||||
ssa_build_proc(value, proc);
|
||||
@@ -2273,7 +2285,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
proc->curr_block = init;
|
||||
ssa_build_stmt(proc, fs->init);
|
||||
}
|
||||
ssaBlock *body = ssa__make_block(proc, node, make_string("for.body"));
|
||||
ssaBlock *body = ssa_add_block(proc, node, make_string("for.body"));
|
||||
ssaBlock *done = ssa__make_block(proc, node, make_string("for.done")); // NOTE(bill): Append later
|
||||
|
||||
ssaBlock *loop = body;
|
||||
@@ -2289,7 +2301,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
proc->curr_block = loop;
|
||||
if (loop != body) {
|
||||
ssa_build_cond(proc, fs->cond, body, done);
|
||||
gb_array_append(proc->blocks, body);
|
||||
proc->curr_block = body;
|
||||
}
|
||||
|
||||
|
||||
+106
-95
@@ -87,6 +87,7 @@ enum ProcTag {
|
||||
AST_NODE_KIND(ProcLit, struct { \
|
||||
AstNode *type; \
|
||||
AstNode *body; \
|
||||
u64 tags; \
|
||||
}) \
|
||||
AST_NODE_KIND(CompoundLit, struct { \
|
||||
AstNode *type; \
|
||||
@@ -559,23 +560,24 @@ gb_inline AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_inline AstNode *make_identifier(AstFile *f, Token token, AstEntity *entity = NULL) {
|
||||
gb_inline AstNode *make_ident(AstFile *f, Token token, AstEntity *entity = NULL) {
|
||||
AstNode *result = make_node(f, AstNode_Ident);
|
||||
result->Ident.token = token;
|
||||
result->Ident.entity = entity;
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_inline AstNode *make_procedure_literal(AstFile *f, AstNode *type, AstNode *body) {
|
||||
gb_inline AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) {
|
||||
AstNode *result = make_node(f, AstNode_ProcLit);
|
||||
result->ProcLit.type = type;
|
||||
result->ProcLit.body = body;
|
||||
result->ProcLit.tags = tags;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
gb_inline AstNode *make_compound_literal(AstFile *f, AstNode *type, AstNode *elem_list, isize elem_count,
|
||||
Token open, Token close) {
|
||||
gb_inline AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNode *elem_list, isize elem_count,
|
||||
Token open, Token close) {
|
||||
AstNode *result = make_node(f, AstNode_CompoundLit);
|
||||
result->CompoundLit.type = type;
|
||||
result->CompoundLit.elem_list = elem_list;
|
||||
@@ -845,16 +847,12 @@ gb_internal void add_ast_entity(AstFile *f, AstScope *scope, AstNode *declaratio
|
||||
AstEntity *insert_entity = ast_scope_insert(scope, *entity);
|
||||
if (insert_entity != NULL && !is_blank_ident(insert_entity->token.string)) {
|
||||
ast_file_err(f, entity->token,
|
||||
"There is already a previous declaration of `%.*s` in the current scope at\n"
|
||||
"\t%.*s(%td:%td)",
|
||||
"There is already a previous declaration of `%.*s` in the current scope\n"
|
||||
"at \t%.*s(%td:%td)",
|
||||
LIT(insert_entity->token.string),
|
||||
LIT(insert_entity->token.pos.file),
|
||||
insert_entity->token.pos.line,
|
||||
insert_entity->token.pos.column);
|
||||
|
||||
gb_printf_err("Hashes\n");
|
||||
gb_printf_err("%16llx - %.*s\n", hash_string(insert_entity->token.string), LIT(insert_entity->token.string));
|
||||
gb_printf_err("%16llx - %.*s\n\n", hash_string(entity->token.string), LIT(entity->token.string));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -911,7 +909,7 @@ AstNode *parse_identifier(AstFile *f) {
|
||||
token.string = make_string("_");
|
||||
expect_token(f, Token_Identifier);
|
||||
}
|
||||
return make_identifier(f, token);
|
||||
return make_ident(f, token);
|
||||
}
|
||||
|
||||
AstNode *parse_tag_expr(AstFile *f, AstNode *expression) {
|
||||
@@ -971,7 +969,7 @@ AstNode *parse_literal_value(AstFile *f, AstNode *type) {
|
||||
f->expr_level--;
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return make_compound_literal(f, type, element_list, element_count, open, close);
|
||||
return make_compound_lit(f, type, element_list, element_count, open, close);
|
||||
}
|
||||
|
||||
AstNode *parse_value(AstFile *f) {
|
||||
@@ -984,6 +982,93 @@ AstNode *parse_value(AstFile *f) {
|
||||
|
||||
AstNode *parse_identifier_or_type(AstFile *f);
|
||||
|
||||
|
||||
void check_proc_add_tag(AstFile *f, AstNode *tag_expr, u64 *tags, ProcTag tag, String tag_name) {
|
||||
if (*tags & tag) {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Procedure tag already used: %.*s", LIT(tag_name));
|
||||
}
|
||||
*tags |= tag;
|
||||
}
|
||||
|
||||
b32 is_foreign_name_valid(String name) {
|
||||
// TODO(bill): is_foreign_name_valid
|
||||
if (name.len == 0)
|
||||
return false;
|
||||
isize offset = 0;
|
||||
while (offset < name.len) {
|
||||
Rune rune;
|
||||
isize remaining = name.len - offset;
|
||||
isize width = gb_utf8_decode(name.text+offset, remaining, &rune);
|
||||
if (rune == GB_RUNE_INVALID && width == 1) {
|
||||
return false;
|
||||
} else if (rune == GB_RUNE_BOM && remaining > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
switch (rune) {
|
||||
case '-':
|
||||
case '$':
|
||||
case '.':
|
||||
case '_':
|
||||
break;
|
||||
default:
|
||||
if (!rune_is_letter(rune))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (rune) {
|
||||
case '-':
|
||||
case '$':
|
||||
case '.':
|
||||
case '_':
|
||||
break;
|
||||
default:
|
||||
if (!rune_is_letter(rune) && !rune_is_digit(rune)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset += width;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) {
|
||||
// TODO(bill): Add this to procedure literals too
|
||||
while (f->cursor[0].kind == Token_Hash) {
|
||||
AstNode *tag_expr = parse_tag_expr(f, NULL);
|
||||
ast_node(te, TagExpr, tag_expr);
|
||||
String tag_name = te->name.string;
|
||||
if (are_strings_equal(tag_name, make_string("foreign"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name);
|
||||
if (f->cursor[0].kind == Token_String) {
|
||||
*foreign_name = f->cursor[0].string;
|
||||
// TODO(bill): Check if valid string
|
||||
if (!is_foreign_name_valid(*foreign_name)) {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Invalid alternative foreign procedure name");
|
||||
}
|
||||
|
||||
next_token(f);
|
||||
}
|
||||
} else if (are_strings_equal(tag_name, make_string("inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name);
|
||||
} else {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
|
||||
}
|
||||
}
|
||||
|
||||
if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) {
|
||||
ast_file_err(f, f->cursor[0], "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *parse_operand(AstFile *f, b32 lhs) {
|
||||
AstNode *operand = NULL; // Operand
|
||||
switch (f->cursor[0].kind) {
|
||||
@@ -1024,6 +1109,13 @@ AstNode *parse_operand(AstFile *f, b32 lhs) {
|
||||
AstScope *scope = NULL;
|
||||
AstNode *type = parse_proc_type(f, &scope);
|
||||
|
||||
u64 tags = 0;
|
||||
String foreign_name = {};
|
||||
parse_proc_tags(f, &tags, &foreign_name);
|
||||
if (tags & ProcTag_foreign) {
|
||||
ast_file_err(f, f->cursor[0], "#foreign cannot be applied to procedure literals");
|
||||
}
|
||||
|
||||
if (f->cursor[0].kind != Token_OpenBrace) {
|
||||
return type;
|
||||
} else {
|
||||
@@ -1036,7 +1128,7 @@ AstNode *parse_operand(AstFile *f, b32 lhs) {
|
||||
f->expr_level--;
|
||||
f->curr_scope = curr_scope;
|
||||
|
||||
return make_procedure_literal(f, type, body);
|
||||
return make_proc_lit(f, type, body, tags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1605,60 +1697,7 @@ AstNode *parse_body(AstFile *f, AstScope *scope) {
|
||||
return make_block_stmt(f, statement_list, statement_list_count, open, close);
|
||||
}
|
||||
|
||||
b32 is_foreign_name_valid(String name) {
|
||||
// TODO(bill): is_foreign_name_valid
|
||||
if (name.len == 0)
|
||||
return false;
|
||||
isize offset = 0;
|
||||
while (offset < name.len) {
|
||||
Rune rune;
|
||||
isize remaining = name.len - offset;
|
||||
isize width = gb_utf8_decode(name.text+offset, remaining, &rune);
|
||||
if (rune == GB_RUNE_INVALID && width == 1) {
|
||||
return false;
|
||||
} else if (rune == GB_RUNE_BOM && remaining > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
switch (rune) {
|
||||
case '-':
|
||||
case '$':
|
||||
case '.':
|
||||
case '_':
|
||||
break;
|
||||
default:
|
||||
if (!rune_is_letter(rune))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (rune) {
|
||||
case '-':
|
||||
case '$':
|
||||
case '.':
|
||||
case '_':
|
||||
break;
|
||||
default:
|
||||
if (!rune_is_letter(rune) && !rune_is_digit(rune)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset += width;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void check_proc_add_tag(AstFile *f, AstNode *tag_expr, u64 *tags, ProcTag tag, String tag_name) {
|
||||
if (*tags & tag) {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Procedure tag already used: %.*s", LIT(tag_name));
|
||||
}
|
||||
*tags |= tag;
|
||||
}
|
||||
|
||||
AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
|
||||
AstNode *param_list = NULL;
|
||||
@@ -1673,36 +1712,8 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
|
||||
AstNode *body = NULL;
|
||||
u64 tags = 0;
|
||||
String foreign_name = {};
|
||||
while (f->cursor[0].kind == Token_Hash) {
|
||||
AstNode *tag_expr = parse_tag_expr(f, NULL);
|
||||
ast_node(te, TagExpr, tag_expr);
|
||||
String tag_name = te->name.string;
|
||||
if (are_strings_equal(tag_name, make_string("foreign"))) {
|
||||
check_proc_add_tag(f, tag_expr, &tags, ProcTag_foreign, tag_name);
|
||||
if (f->cursor[0].kind == Token_String) {
|
||||
foreign_name = f->cursor[0].string;
|
||||
// TODO(bill): Check if valid string
|
||||
if (!is_foreign_name_valid(foreign_name)) {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Invalid alternative foreign procedure name");
|
||||
}
|
||||
|
||||
next_token(f);
|
||||
}
|
||||
} else if (are_strings_equal(tag_name, make_string("inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, &tags, ProcTag_inline, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, &tags, ProcTag_no_inline, tag_name);
|
||||
} else {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
|
||||
}
|
||||
}
|
||||
|
||||
b32 is_inline = (tags & ProcTag_inline) != 0;
|
||||
b32 is_no_inline = (tags & ProcTag_no_inline) != 0;
|
||||
|
||||
if (is_inline && is_no_inline) {
|
||||
ast_file_err(f, f->cursor[0], "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||
}
|
||||
parse_proc_tags(f, &tags, &foreign_name);
|
||||
|
||||
if (f->cursor[0].kind == Token_OpenBrace) {
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
|
||||
@@ -85,6 +85,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_continue, "continue"), \
|
||||
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
|
||||
TOKEN_KIND(Token_case, "case"), \
|
||||
TOKEN_KIND(Token_then, "then"), \
|
||||
TOKEN_KIND(Token_if, "if"), \
|
||||
TOKEN_KIND(Token_else, "else"), \
|
||||
TOKEN_KIND(Token_for, "for"), \
|
||||
|
||||
Reference in New Issue
Block a user