Add string_set.cpp; Code clean up

This commit is contained in:
gingerBill
2017-10-30 20:26:05 +00:00
parent 3e05be8eb8
commit 414486829a
9 changed files with 341 additions and 73 deletions
+71 -7
View File
@@ -459,8 +459,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export;
bool is_inline = (pl->tags & ProcTag_inline) != 0;
bool is_no_inline = (pl->tags & ProcTag_no_inline) != 0;
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
String link_name = {};
@@ -513,6 +511,9 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
if (name == "link_name") {
if (ev.kind == ExactValue_String) {
link_name = ev.value_string;
if (!is_foreign_name_valid(link_name)) {
error(elem, "Invalid link name: %.*s", LIT(link_name));
}
} else {
error(elem, "Expected a string value for `%.*s`", LIT(name));
}
@@ -548,10 +549,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
}
if (is_inline && is_no_inline) {
error(pl->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_export) {
error(pl->type, "A foreign procedure cannot have an `export` tag");
}
@@ -673,9 +670,69 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
e->flags |= EntityFlag_Visited;
String link_name = {};
DeclInfo *decl = decl_info_of_entity(&c->info, e);
if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on variable declarations, yet");
StringSet set = {};
string_set_init(&set, heap_allocator());
defer (string_set_destroy(&set));
for_array(i, decl->attributes) {
AstNode *attr = decl->attributes[i];
if (attr->kind != AstNode_Attribute) continue;
for_array(j, attr->Attribute.elems) {
AstNode *elem = attr->Attribute.elems[j];
String name = {};
AstNode *value = nullptr;
switch (elem->kind) {
case_ast_node(i, Ident, elem);
name = i->token.string;
case_end;
case_ast_node(fv, FieldValue, elem);
GB_ASSERT(fv->field->kind == AstNode_Ident);
name = fv->field->Ident.token.string;
value = fv->value;
case_end;
default:
error(elem, "Invalid attribute element");
continue;
}
ExactValue ev = {};
if (value != nullptr) {
Operand op = {};
check_expr(c, &op, value);
if (op.mode != Addressing_Constant) {
error(value, "An attribute element must be constant");
} else {
ev = op.value;
}
}
if (string_set_exists(&set, name)) {
error(elem, "Previous declaration of `%.*s`", LIT(name));
continue;
} else {
string_set_add(&set, name);
}
if (name == "link_name") {
if (ev.kind == ExactValue_String) {
link_name = ev.value_string;
if (!is_foreign_name_valid(link_name)) {
error(elem, "Invalid link name: %.*s", LIT(link_name));
}
} else {
error(elem, "Expected a string value for `%.*s`", LIT(name));
}
} else {
error(elem, "Unknown attribute element name `%.*s`", LIT(name));
}
}
}
}
String context_name = str_lit("variable declaration");
@@ -704,8 +761,15 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
init_entity_foreign_library(c, e);
}
if (link_name.len > 0) {
e->Variable.link_name = link_name;
}
if (e->Variable.is_foreign || e->Variable.is_export) {
String name = e->token.string;
if (link_name.len > 0) {
name = link_name;
}
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
+1 -1
View File
@@ -1670,7 +1670,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
CheckerContext prev_context = c->context;
if (ok) {
c->context.curr_foreign_library = foreign_library;
c->context.default_foreign_cc = ProcCC_C;
c->context.default_foreign_cc = ProcCC_CDecl;
}
check_foreign_block_decl_attributes(c, fb);
+4 -8
View File
@@ -1890,7 +1890,7 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
ProcCallingConvention cc = pt->calling_convention;
if (cc == ProcCC_ForeignBlockDefault) {
cc = ProcCC_C;
cc = ProcCC_CDecl;
if (c->context.default_foreign_cc > 0) {
cc = c->context.default_foreign_cc;
}
@@ -1911,14 +1911,10 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
if (param_count > 0) {
Entity *end = params->Tuple.variables[param_count-1];
if (end->flags&EntityFlag_CVarArg) {
if (cc == ProcCC_Odin) {
error(end->token, "Odin calling convention does not support #c_vararg");
} else if (cc == ProcCC_Contextless) {
error(end->token, "Odin's contextless calling convention does not support #c_vararg");
} else if (cc == ProcCC_Fast) {
error(end->token, "Fast calling convention does not support #c_vararg");
} else {
if (cc == ProcCC_StdCall || cc == ProcCC_CDecl) {
type->Proc.c_vararg = true;
} else {
error(end->token, "Calling convention does not support #c_vararg");
}
}
}
+1 -1
View File
@@ -2126,7 +2126,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
GB_ASSERT(pl->type->kind == AstNode_ProcType);
auto cc = pl->type->ProcType.calling_convention;
if (cc == ProcCC_ForeignBlockDefault) {
cc = ProcCC_C;
cc = ProcCC_CDecl;
if (c->context.default_foreign_cc > 0) {
cc = c->context.default_foreign_cc;
}
+10 -5
View File
@@ -117,6 +117,7 @@ struct irProcedure {
AstNode * type_expr;
AstNode * body;
u64 tags;
ProcInlining inlining;
bool is_foreign;
bool is_export;
bool is_entry_point;
@@ -3695,6 +3696,7 @@ irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, AstNode *exp
m, nullptr, type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
value->Proc.inlining = pl->inlining;
value->Proc.parent = proc;
array_add(&m->procs_to_generate, value);
@@ -5902,6 +5904,7 @@ void ir_build_poly_proc(irProcedure *proc, AstNodeProcLit *pd, Entity *e) {
proc->module, e, e->type, pd->type, pd->body, name);
value->Proc.tags = pd->tags;
value->Proc.inlining = pd->inlining;
value->Proc.parent = proc;
ir_module_add_value(proc->module, e, value);
@@ -5987,6 +5990,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) {
proc->module, e, e->type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
value->Proc.inlining = pl->inlining;
ir_module_add_value(proc->module, e, value);
ir_build_proc(value, proc);
@@ -8295,6 +8299,7 @@ void ir_gen_tree(irGen *s) {
irValue *p = ir_value_procedure(a, m, e, e->type, type_expr, body, name);
p->Proc.tags = pl->tags;
p->Proc.inlining = pl->inlining;
ir_module_add_value(m, e, p);
HashKey hash_name = hash_string(name);
@@ -8363,7 +8368,7 @@ void ir_gen_tree(irGen *s) {
Type *proc_type = make_type_proc(a, proc_scope,
proc_params, 3,
proc_results, 1, false, ProcCC_Std);
proc_results, 1, false, ProcCC_StdCall);
// TODO(bill): make this more robust
proc_type->Proc.abi_compat_params = gb_alloc_array(a, Type *, proc_params->Tuple.variables.count);
@@ -8380,7 +8385,7 @@ void ir_gen_tree(irGen *s) {
map_set(&m->members, hash_string(name), p);
irProcedure *proc = &p->Proc;
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
proc->is_entry_point = true;
e->Procedure.link_name = name;
@@ -8434,7 +8439,7 @@ void ir_gen_tree(irGen *s) {
Type *proc_type = make_type_proc(a, proc_scope,
proc_params, 2,
proc_results, 1, false, ProcCC_C);
proc_results, 1, false, ProcCC_CDecl);
// TODO(bill): make this more robust
proc_type->Proc.abi_compat_params = gb_alloc_array(a, Type *, proc_params->Tuple.variables.count);
@@ -8451,7 +8456,7 @@ void ir_gen_tree(irGen *s) {
map_set(&m->members, hash_string(name), p);
irProcedure *proc = &p->Proc;
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
proc->is_entry_point = true;
e->Procedure.link_name = name;
@@ -8543,7 +8548,7 @@ void ir_gen_tree(irGen *s) {
irProcedure *proc = &p->Proc;
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
proc->inlining = ProcInlining_no_inline; // TODO(bill): is no_inline a good idea?
ir_begin_procedure_body(proc);
+9 -8
View File
@@ -882,9 +882,9 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
switch (cc) {
case ProcCC_Odin: ir_write_string(f, ""); break;
case ProcCC_Contextless: ir_write_string(f, ""); break;
case ProcCC_C: ir_write_string(f, "ccc "); break;
case ProcCC_Std: ir_write_string(f, "cc 64 "); break;
case ProcCC_Fast: ir_write_string(f, "cc 65 "); break;
case ProcCC_CDecl: ir_write_string(f, "ccc "); break;
case ProcCC_StdCall: ir_write_string(f, "cc 64 "); break;
case ProcCC_FastCall: ir_write_string(f, "cc 65 "); break;
default: GB_PANIC("unknown calling convention: %d", cc);
}
}
@@ -1751,14 +1751,15 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
ir_write_string(f, ") ");
if (proc->tags & ProcTag_inline) {
ir_write_string(f, "alwaysinline ");
}
if (proc->tags & ProcTag_no_inline) {
switch (proc->inlining) {
case ProcInlining_no_inline:
ir_write_string(f, "noinline ");
break;
case ProcInlining_inline:
ir_write_string(f, "alwaysinline ");
break;
}
if (proc->entity != nullptr) {
if (proc->body != nullptr) {
irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
+36 -28
View File
@@ -88,28 +88,29 @@ struct Parser {
gbMutex file_decl_mutex;
};
enum ProcInlining {
ProcInlining_none = 0,
ProcInlining_inline = 1,
ProcInlining_no_inline = 2,
};
enum ProcTag {
ProcTag_bounds_check = 1<<0,
ProcTag_no_bounds_check = 1<<1,
ProcTag_require_results = 1<<4,
ProcTag_link_name = 1<<11,
ProcTag_inline = 1<<12,
ProcTag_no_inline = 1<<13,
// ProcTag_dll_import = 1<<15,
// ProcTag_dll_export = 1<<16,
};
enum ProcCallingConvention {
ProcCC_Invalid = 0,
ProcCC_Odin = 1,
ProcCC_Contextless = 2,
ProcCC_C = 3,
ProcCC_Std = 4,
ProcCC_Fast = 5,
ProcCC_Invalid = 0,
ProcCC_Odin,
ProcCC_Contextless,
ProcCC_CDecl,
ProcCC_StdCall,
ProcCC_FastCall,
// TODO(bill): Add extra calling conventions
// ProcCC_VectorCall,
// ProcCC_ClrCall,
ProcCC_ForeignBlockDefault = -1,
};
@@ -172,6 +173,7 @@ Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
AstNode *type; \
AstNode *body; \
u64 tags; \
ProcInlining inlining; \
}) \
AST_NODE_KIND(CompoundLit, "compound literal", struct { \
AstNode *type; \
@@ -2275,11 +2277,20 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
syntax_error(expr, "%.*s must be followed by a procedure literal, got %.*s", LIT(token.string), LIT(ast_node_strings[expr->kind]));
return ast_bad_expr(f, token, f->curr_token);
}
ProcInlining pi = ProcInlining_none;
if (token.kind == Token_inline) {
expr->ProcLit.tags |= ProcTag_inline;
pi = ProcInlining_inline;
} else if (token.kind == Token_no_inline) {
expr->ProcLit.tags |= ProcTag_no_inline;
pi = ProcInlining_no_inline;
}
if (pi != ProcInlining_none) {
if (expr->ProcLit.inlining != ProcInlining_none &&
expr->ProcLit.inlining != pi) {
syntax_error(expr, "You cannot apply both `inline` and `no_inline` to a procedure literal");
}
expr->ProcLit.inlining = pi;
}
return expr;
} break;
@@ -3255,17 +3266,14 @@ AstNode *parse_results(AstFile *f) {
ProcCallingConvention string_to_calling_convention(String s) {
if (s == "odin") {
return ProcCC_Odin;
} else if (s == "contextless") {
return ProcCC_Contextless;
} else if (s == "cdecl" || s == "c") {
return ProcCC_C;
} else if (s == "stdcall" || s == "std") {
return ProcCC_Std;
} else if (s == "fastcall" || s == "fast") {
return ProcCC_Fast;
}
if (s == "odin") return ProcCC_Odin;
if (s == "contextless") return ProcCC_Contextless;
if (s == "cdecl") return ProcCC_CDecl;
if (s == "c") return ProcCC_CDecl;
if (s == "stdcall") return ProcCC_StdCall;
if (s == "std") return ProcCC_StdCall;
if (s == "fastcall") return ProcCC_FastCall;
if (s == "fast") return ProcCC_FastCall;
return ProcCC_Invalid;
}
+184
View File
@@ -0,0 +1,184 @@
struct StringSetFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
struct StringSetEntry {
HashKey key;
isize next;
String value;
};
struct StringSet {
Array<isize> hashes;
Array<StringSetEntry> entries;
};
void string_set_init (StringSet *s, gbAllocator a, isize capacity = 16);
void string_set_destroy(StringSet *s);
void string_set_add (StringSet *s, String str);
bool string_set_exists (StringSet *s, String str);
void string_set_remove (StringSet *s, String str);
void string_set_clear (StringSet *s);
void string_set_grow (StringSet *s);
void string_set_rehash (StringSet *s, isize new_count);
gb_inline void string_set_init(StringSet *s, gbAllocator a, isize capacity) {
array_init(&s->hashes, a);
array_init(&s->entries, a);
}
gb_inline void string_set_destroy(StringSet *s) {
array_free(&s->entries);
array_free(&s->hashes);
}
gb_internal isize string_set__add_entry(StringSet *s, HashKey key) {
StringSetEntry e = {};
e.key = key;
e.next = -1;
array_add(&s->entries, e);
return s->entries.count-1;
}
gb_internal StringSetFindResult string_set__find(StringSet *s, HashKey key) {
StringSetFindResult fr = {-1, -1, -1};
if (s->hashes.count > 0) {
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(s->hashes.count));
fr.hash_index = key.key % s->hashes.count;
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(s->entries[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
gb_internal StringSetFindResult string_set__find_from_entry(StringSet *s, StringSetEntry *e) {
StringSetFindResult fr = {-1, -1, -1};
if (s->hashes.count > 0) {
fr.hash_index = e->key.key % s->hashes.count;
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (&s->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
gb_internal b32 string_set__full(StringSet *s) {
return 0.75f * s->hashes.count <= s->entries.count;
}
gb_inline void string_set_grow(StringSet *s) {
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
string_set_rehash(s, new_count);
}
void string_set_rehash(StringSet *s, isize new_count) {
isize i, j;
StringSet ns = {};
string_set_init(&ns, s->hashes.allocator);
array_resize(&ns.hashes, new_count);
array_reserve(&ns.entries, s->entries.count);
for (i = 0; i < new_count; i++) {
ns.hashes[i] = -1;
}
for (i = 0; i < s->entries.count; i++) {
StringSetEntry *e = &s->entries[i];
StringSetFindResult fr;
if (ns.hashes.count == 0) {
string_set_grow(&ns);
}
fr = string_set__find(&ns, e->key);
j = string_set__add_entry(&ns, e->key);
if (fr.entry_prev < 0) {
ns.hashes[fr.hash_index] = j;
} else {
ns.entries[fr.entry_prev].next = j;
}
ns.entries[j].next = fr.entry_index;
ns.entries[j].value = e->value;
if (string_set__full(&ns)) {
string_set_grow(&ns);
}
}
string_set_destroy(s);
*s = ns;
}
gb_inline bool string_set_exists(StringSet *s, String str) {
HashKey key = hash_string(str);
isize index = string_set__find(s, key).entry_index;
return index >= 0;
}
void string_set_add(StringSet *s, String str) {
isize index;
StringSetFindResult fr;
HashKey key = hash_string(str);
if (s->hashes.count == 0) {
string_set_grow(s);
}
fr = string_set__find(s, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = string_set__add_entry(s, key);
if (fr.entry_prev >= 0) {
s->entries[fr.entry_prev].next = index;
} else {
s->hashes[fr.hash_index] = index;
}
}
s->entries[index].value = str;
if (string_set__full(s)) {
string_set_grow(s);
}
}
void string_set__erase(StringSet *s, StringSetFindResult fr) {
StringSetFindResult last;
if (fr.entry_prev < 0) {
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
} else {
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
}
if (fr.entry_index == s->entries.count-1) {
array_pop(&s->entries);
return;
}
s->entries[fr.entry_index] = s->entries[s->entries.count-1];
last = string_set__find(s, s->entries[fr.entry_index].key);
if (last.entry_prev >= 0) {
s->entries[last.entry_prev].next = fr.entry_index;
} else {
s->hashes[last.hash_index] = fr.entry_index;
}
}
void string_set_remove(StringSet *s, String str) {
HashKey key = hash_string(str);
StringSetFindResult fr = string_set__find(s, key);
if (fr.entry_index >= 0) {
string_set__erase(s, fr);
}
}
gb_inline void string_set_clear(StringSet *s) {
array_clear(&s->hashes);
array_clear(&s->entries);
}
+25 -15
View File
@@ -2436,7 +2436,31 @@ gbString write_type_to_string(gbString str, Type *type) {
break;
case Type_Proc:
str = gb_string_appendc(str, "proc(");
str = gb_string_appendc(str, "proc");
switch (type->Proc.calling_convention) {
case ProcCC_Odin:
break;
case ProcCC_Contextless:
str = gb_string_appendc(str, " \"contextless\" ");
break;
case ProcCC_CDecl:
str = gb_string_appendc(str, " \"cdecl\" ");
break;
case ProcCC_StdCall:
str = gb_string_appendc(str, " \"stdcall\" ");
break;
case ProcCC_FastCall:
str = gb_string_appendc(str, " \"fastcall\" ");
break;
// case ProcCC_VectorCall:
// str = gb_string_appendc(str, " \"vectorcall\" ");
// break;
// case ProcCC_ClrCall:
// str = gb_string_appendc(str, " \"clrcall\" ");
// break;
}
str = gb_string_appendc(str, "(");
if (type->Proc.params) {
str = write_type_to_string(str, type->Proc.params);
}
@@ -2445,20 +2469,6 @@ gbString write_type_to_string(gbString str, Type *type) {
str = gb_string_appendc(str, " -> ");
str = write_type_to_string(str, type->Proc.results);
}
switch (type->Proc.calling_convention) {
case ProcCC_Odin:
// str = gb_string_appendc(str, " #cc_odin");
break;
case ProcCC_C:
str = gb_string_appendc(str, " #cc_c");
break;
case ProcCC_Std:
str = gb_string_appendc(str, " #cc_std");
break;
case ProcCC_Fast:
str = gb_string_appendc(str, " #cc_fast");
break;
}
break;
case Type_BitField: