fmt.String_Buffer, Fix issue #44, Tweak overloading rules

This commit is contained in:
Ginger Bill
2017-04-26 19:43:17 +01:00
parent 29efdc5fc1
commit 5b8be25938
11 changed files with 439 additions and 259 deletions
+150 -74
View File
@@ -8,20 +8,64 @@
_BUFFER_SIZE :: 1<<12;
write_string :: proc(buf: ^[]byte, s: string) {
append(buf, ..cast([]byte)s);
String_Buffer :: struct {
is_dynamic: bool,
sa: []byte,
da: [dynamic]byte,
};
make_string_buffer_from_slice :: proc(b: []byte) -> String_Buffer {
return String_Buffer{
is_dynamic = false,
sa = b,
};
}
write_byte :: proc(buf: ^[]byte, b: byte) {
append(buf, b);
make_string_dynamic_buffer :: proc() -> String_Buffer {
return String_Buffer{
is_dynamic = true,
da = make([dynamic]byte),
};
}
write_rune :: proc(buf: ^[]byte, r: rune) {
string_buffer_data :: proc(buf: ^String_Buffer) -> []byte {
return string_buffer_data(buf^);
}
string_buffer_data :: proc(buf: String_Buffer) -> []byte {
if buf.is_dynamic {
return buf.da[..];
}
return buf.sa[..];
}
to_string :: proc(buf: String_Buffer) -> string {
return cast(string)string_buffer_data(buf);
}
write_string :: proc(buf: ^String_Buffer, s: string) {
write_bytes(buf, cast([]byte)s);
}
write_bytes :: proc(buf: ^String_Buffer, b: []byte) {
if buf.is_dynamic {
append(buf.da, ..b);
} else {
append(buf.sa, ..b);
}
}
write_byte :: proc(buf: ^String_Buffer, b: byte) {
if buf.is_dynamic {
append(buf.da, b);
} else {
append(buf.sa, b);
}
}
write_rune :: proc(buf: ^String_Buffer, r: rune) {
if r < utf8.RUNE_SELF {
write_byte(buf, cast(byte)r);
return;
}
b, n := utf8.encode_rune(r);
append(buf, ..b[0..<n]);
write_bytes(buf, b[0..<n]);
}
Fmt_Info :: struct {
@@ -39,7 +83,7 @@ Fmt_Info :: struct {
reordered: bool,
good_arg_index: bool,
buf: ^[]byte,
buf: ^String_Buffer,
arg: any, // Temporary
}
@@ -47,25 +91,28 @@ Fmt_Info :: struct {
fprint :: proc(fd: os.Handle, args: ..any) -> int {
data: [_BUFFER_SIZE]byte;
buf := data[0..<0];
bprint(^buf, ..args);
os.write(fd, buf);
return len(buf);
buf := make_string_buffer_from_slice(data[0..<0]);
sbprint(^buf, ..args);
res := string_buffer_data(buf);
os.write(fd, res);
return len(res);
}
fprintln :: proc(fd: os.Handle, args: ..any) -> int {
data: [_BUFFER_SIZE]byte;
buf := data[0..<0];
bprintln(^buf, ..args);
os.write(fd, buf);
return len(buf);
buf := make_string_buffer_from_slice(data[0..<0]);
sbprintln(^buf, ..args);
res := string_buffer_data(buf);
os.write(fd, res);
return len(res);
}
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
data: [_BUFFER_SIZE]byte;
buf := data[0..<0];
bprintf(^buf, fmt, ..args);
os.write(fd, buf);
return len(buf);
buf := make_string_buffer_from_slice(data[0..<0]);
sbprintf(^buf, fmt, ..args);
res := string_buffer_data(buf);
os.write(fd, res);
return len(res);
}
@@ -80,14 +127,56 @@ printf :: proc(fmt: string, args: ..any) -> int {
}
fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
data: [_BUFFER_SIZE]byte;
buf := data[0..<0];
write_type(^buf, info);
os.write(fd, buf);
// aprint* procedures return a string that was allocated with the current context
// They must be freed accordingly
aprint :: proc(args: ..any) -> string {
buf := make_string_dynamic_buffer();
sbprint(^buf, ..args);
return to_string(buf);
}
aprintln :: proc(args: ..any) -> string {
buf := make_string_dynamic_buffer();
sbprintln(^buf, ..args);
return to_string(buf);
}
aprintf :: proc(fmt: string, args: ..any) -> string {
buf := make_string_dynamic_buffer();
sbprintf(^buf, fmt, ..args);
return to_string(buf);
}
write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
// bprint* procedures
// aprint* procedure return a string that was allocated with the current context
// They must be freed accordingly
bprint :: proc(buf: []byte, args: ..any) -> int {
sb := make_string_buffer_from_slice(buf[0..<0..<len(buf)]);
return sbprint(^sb, ..args);
}
bprintln :: proc(buf: []byte, args: ..any) -> int {
sb := make_string_buffer_from_slice(buf[0..<0..<len(buf)]);
return sbprintln(^sb, ..args);
}
bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> int {
sb := make_string_buffer_from_slice(buf[0..<0..<len(buf)]);
return sbprintf(^sb, fmt, ..args);
}
fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
data: [_BUFFER_SIZE]byte;
buf := make_string_buffer_from_slice(data[0..<0]);
write_type(^buf, info);
os.write(fd, string_buffer_data(buf));
}
write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
if ti == nil {
return;
}
@@ -273,51 +362,6 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
}
bprint :: proc(buf: ^[]byte, args: ..any) -> int {
fi: Fmt_Info;
fi.buf = buf;
prev_string := false;
for arg, i in args {
is_string := arg != nil && types.is_string(arg.type_info);
if i > 0 && !is_string && !prev_string {
write_byte(buf, ' ');
}
fmt_value(^fi, args[i], 'v');
prev_string = is_string;
}
return len(buf);
}
bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
fi: Fmt_Info;
fi.buf = buf;
for arg, i in args {
if i > 0 {
write_byte(buf, ' ');
}
fmt_value(^fi, args[i], 'v');
}
write_byte(buf, '\n');
return len(buf);
}
sprint :: proc(buf: []byte, args: ..any) -> string {
count := bprint(^buf, ..args);
return cast(string)buf[0..<count];
}
sprintln :: proc(buf: []byte, args: ..any) -> string {
count := bprintln(^buf, ..args);
return cast(string)buf[0..<count];
}
sprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
count := bprintf(^buf, fmt, ..args);
return cast(string)buf[0..<count];
}
_parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
is_digit :: proc(r: rune) -> bool #inline {
@@ -439,9 +483,10 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
pad_byte = '0';
}
count := min(width, cap(fi.buf)-len(fi.buf));
data := string_buffer_data(fi.buf^);
count := min(width, cap(data)-len(data));
for _ in 0..count {
append(fi.buf, pad_byte);
write_byte(fi.buf, pad_byte);
}
}
@@ -998,7 +1043,38 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
}
bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int {
sbprint :: proc(buf: ^String_Buffer, args: ..any) -> int {
fi: Fmt_Info;
fi.buf = buf;
prev_string := false;
for arg, i in args {
is_string := arg != nil && types.is_string(arg.type_info);
if i > 0 && !is_string && !prev_string {
write_byte(buf, ' ');
}
fmt_value(^fi, args[i], 'v');
prev_string = is_string;
}
return len(string_buffer_data(buf));
}
sbprintln :: proc(buf: ^String_Buffer, args: ..any) -> int {
fi: Fmt_Info;
fi.buf = buf;
for arg, i in args {
if i > 0 {
write_byte(buf, ' ');
}
fmt_value(^fi, args[i], 'v');
}
write_byte(buf, '\n');
return len(string_buffer_data(buf));
}
sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ..any) -> int {
fi := Fmt_Info{};
end := len(fmt);
arg_index := 0;
@@ -1128,5 +1204,5 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int {
write_string(b, ")");
}
return len(b);
return len(string_buffer_data(b));
}
+3
View File
@@ -109,6 +109,9 @@ close :: proc(fd: Handle) {
win32.CloseHandle(cast(win32.Handle)fd);
}
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, cast([]byte)str);
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
+43 -32
View File
@@ -413,7 +413,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
void check_alias_decl(Checker *c, Entity *e, AstNode *expr) {
void check_alias_decl(Checker *c, Entity *e, AstNode *expr, Type *named_type) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->kind == Entity_Alias);
@@ -431,36 +431,47 @@ void check_alias_decl(Checker *c, Entity *e, AstNode *expr) {
return;
}
if (expr->kind == AstNode_Ident) {
Operand o = {0};
Entity *f = check_ident(c, &o, expr, NULL, NULL, true);
if (f != NULL) {
e->Alias.original = f;
e->type = f->type;
}
return;
} else if (expr->kind == AstNode_SelectorExpr) {
Operand o = {0};
Entity *f = check_selector(c, &o, expr, NULL);
if (f != NULL) {
e->Alias.original = f;
e->type = f->type;
}
return;
}
Operand o = {0};
check_expr_or_type(c, &o, expr);
if (o.mode == Addressing_Invalid) {
return;
}
switch (o.mode) {
case Addressing_Type:
e->type = o.type;
break;
default:
Operand operand = {0};
check_expr_or_type(c, &operand, expr);
if (operand.mode != Addressing_Type) {
error_node(expr, "#alias declarations only allow types");
return;
}
e->kind = Entity_TypeName;
e->TypeName.is_type_alias = true;
e->type = NULL;
DeclInfo *d = c->context.decl;
d->type_expr = expr;
check_type_decl(c, e, d->type_expr, named_type);
// Operand o = {0};
// Entity *f = NULL;
// if (expr->kind == AstNode_Ident) {
// f = check_ident(c, &o, expr, NULL, NULL, true);
// } else if (expr->kind == AstNode_SelectorExpr) {
// f = check_selector(c, &o, expr, NULL);
// } else {
// check_expr_or_type(c, &o, expr);
// }
// if (o.mode == Addressing_Invalid) {
// return;
// }
// switch (o.mode) {
// case Addressing_Type:
// e->type = o.type;
// // e->kind = Entity_TypeName;
// // e->TypeName.is_type_alias = true;
// e->Alias.kind = EntityAlias_Type;
// e->Alias.original = f;
// break;
// default:
// error_node(expr, "#alias declarations only allow types");
// e->kind = Entity_Invalid;
// e->type = t_invalid;
// break;
// }
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
@@ -495,12 +506,12 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
case Entity_TypeName:
check_type_decl(c, e, d->type_expr, named_type);
break;
case Entity_Alias:
check_alias_decl(c, e, d->init_expr, named_type);
break;
case Entity_Procedure:
check_proc_lit(c, e, d);
break;
case Entity_Alias:
check_alias_decl(c, e, d->init_expr);
break;
}
c->context = prev;
+45 -20
View File
@@ -147,7 +147,31 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
if (dst->kind == Type_Basic) {
if (operand->mode == Addressing_Constant) {
if (check_representable_as_constant(c, operand->value, dst, NULL)) {
return 1;
if (is_type_typed(dst) && src->kind == Type_Basic) {
switch (src->Basic.kind) {
case Basic_UntypedInteger:
if (is_type_integer(dst)) {
return 1;
}
break;
case Basic_UntypedFloat:
if (is_type_float(dst)) {
return 1;
}
break;
case Basic_UntypedComplex:
if (is_type_complex(dst)) {
return 1;
}
break;
case Basic_UntypedQuaternion:
if (is_type_quaternion(dst)) {
return 1;
}
break;
}
}
return 2;
}
return -1;
}
@@ -1058,12 +1082,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
case 32: new_type = t_u32; break;
case 64: new_type = t_u64; break;
default:
// NOTE(bill): It could be an empty struct that is passed
// and if that is the case, no need to pass by pointer
// (I think..)
if (size > 0) {
new_type = make_type_pointer(a, original_type);
}
new_type = make_type_pointer(a, original_type);
break;
}
} break;
@@ -1196,11 +1215,6 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
e->flags |= EntityFlag_Used;
Entity *original_e = e;
while (e != NULL && e->kind == Entity_Alias && e->Alias.original != NULL) {
e = e->Alias.original;
}
Type *type = e->type;
switch (e->kind) {
case Entity_Constant:
@@ -1261,6 +1275,17 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
o->mode = Addressing_Value;
break;
case Entity_Alias: {
// error_node(n, "#alias entities are not yet supported");
// TODO(bill): Fix Entity_Alias rules
if (e->Alias.kind == EntityAlias_Type) {
o->mode = Addressing_Type;
} else {
o->mode = Addressing_Invalid;
return e;
}
} break;
default:
compiler_error("Unknown EntityKind");
break;
@@ -3136,6 +3161,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
operand->builtin_id = entity->Builtin.id;
break;
case Entity_Alias: {
error_node(selector, "#alias entities are not yet supported");
return NULL;
} break;
// NOTE(bill): These cases should never be hit but are here for sanity reasons
case Entity_Nil:
operand->mode = Addressing_Value;
@@ -3899,8 +3929,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
Operand z = {0};
Operand w = {0};
GB_PANIC("BuiltinProc_quaternion");
// NOTE(bill): Invalid will be the default till fixed
operand->type = t_invalid;
operand->mode = Addressing_Invalid;
@@ -3990,12 +4018,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
BasicKind kind = core_type(x.type)->Basic.kind;
switch (kind) {
case Basic_complex64: x.type = t_f32; break;
case Basic_complex128: x.type = t_f64; break;
case Basic_UntypedComplex: x.type = t_untyped_float; break;
case Basic_quaternion128: x.type = t_f32; break;
case Basic_quaternion256: x.type = t_f64; break;
case Basic_UntypedQuaternion: x.type = t_untyped_float; break;
case Basic_f32: operand->type = t_quaternion128; break;
case Basic_f64: operand->type = t_quaternion256; break;
case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break;
default: GB_PANIC("Invalid type"); break;
}
} break;
+130 -112
View File
@@ -432,6 +432,134 @@ void check_label(Checker *c, AstNode *label) {
}
}
// Returns `true` for `continue`, `false` for `return`
bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) {
if (e == NULL) {
error(us->token, "`using` applied to an unknown entity");
return true;
}
switch (e->kind) {
case Entity_Alias: {
if (e->Alias.original != NULL) {
check_using_stmt_entity(c, us, expr, is_selector, e->Alias.original);
} else {
error(us->token, "`using` cannot be applied to the alias `%.*s`", LIT(e->token.string));
return false;
}
} break;
case Entity_TypeName: {
Type *t = base_type(e->type);
if (is_type_union(t)) {
TokenPos pos = ast_node_token(expr).pos;
for (isize i = 1; i < t->Record.variant_count; i++) {
Entity *f = t->Record.variants[i];
// gb_printf_err("%s\n", type_to_string(f->type));
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return false;
}
f->using_parent = e;
}
} else if (is_type_enum(t)) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return false;
}
f->using_parent = e;
}
} else {
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
}
} break;
case Entity_ImportName: {
Scope *scope = e->ImportName.scope;
for_array(i, scope->elements.entries) {
Entity *decl = scope->elements.entries.e[i].value;
Entity *found = scope_insert_entity(c->context.scope, decl);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token,
"Namespace collision while `using` `%s` of: %.*s\n"
"\tat %.*s(%td:%td)\n"
"\tat %.*s(%td:%td)",
expr_str, LIT(found->token.string),
LIT(found->token.pos.file), found->token.pos.line, found->token.pos.column,
LIT(decl->token.pos.file), decl->token.pos.line, decl->token.pos.column
);
gb_string_free(expr_str);
return false;
}
}
} break;
case Entity_Variable: {
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
// TODO(bill): Make it work for unions too
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
if (is_selector) {
uvar->using_expr = expr;
}
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
gb_string_free(expr_str);
return false;
}
}
}
} else {
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
return false;
}
} break;
case Entity_Constant:
error(us->token, "`using` cannot be applied to a constant");
break;
case Entity_Procedure:
case Entity_Builtin:
error(us->token, "`using` cannot be applied to a procedure");
break;
case Entity_Nil:
error(us->token, "`using` cannot be applied to `nil`");
break;
case Entity_Label:
error(us->token, "`using` cannot be applied to a label");
break;
case Entity_Invalid:
error(us->token, "`using` cannot be applied to an invalid entity");
break;
default:
GB_PANIC("TODO(bill): `using` other expressions?");
}
return true;
}
void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
@@ -1341,118 +1469,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
continue;
}
if (e == NULL) {
error(us->token, "`using` applied to an unknown entity");
continue;
}
switch (e->kind) {
case Entity_TypeName: {
Type *t = base_type(e->type);
if (is_type_union(t)) {
TokenPos pos = ast_node_token(expr).pos;
for (isize i = 1; i < t->Record.variant_count; i++) {
Entity *f = t->Record.variants[i];
// gb_printf_err("%s\n", type_to_string(f->type));
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return;
}
f->using_parent = e;
}
} else if (is_type_enum(t)) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return;
}
f->using_parent = e;
}
} else {
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
}
} break;
case Entity_ImportName: {
Scope *scope = e->ImportName.scope;
for_array(i, scope->elements.entries) {
Entity *decl = scope->elements.entries.e[i].value;
Entity *found = scope_insert_entity(c->context.scope, decl);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token,
"Namespace collision while `using` `%s` of: %.*s\n"
"\tat %.*s(%td:%td)\n"
"\tat %.*s(%td:%td)",
expr_str, LIT(found->token.string),
LIT(found->token.pos.file), found->token.pos.line, found->token.pos.column,
LIT(decl->token.pos.file), decl->token.pos.line, decl->token.pos.column
);
gb_string_free(expr_str);
return;
}
}
} break;
case Entity_Variable: {
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
// TODO(bill): Make it work for unions too
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
if (is_selector) {
uvar->using_expr = expr;
}
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
gb_string_free(expr_str);
return;
}
}
}
} else {
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
return;
}
} break;
case Entity_Constant:
error(us->token, "`using` cannot be applied to a constant");
break;
case Entity_Procedure:
case Entity_Builtin:
error(us->token, "`using` cannot be applied to a procedure");
break;
case Entity_Nil:
error(us->token, "`using` cannot be applied to `nil`");
break;
case Entity_Label:
error(us->token, "`using` cannot be applied to a label");
break;
case Entity_Invalid:
error(us->token, "`using` cannot be applied to an invalid entity");
break;
default:
GB_PANIC("TODO(bill): `using` other expressions?");
if (!check_using_stmt_entity(c, us, expr, is_selector, e)) {
return;
}
}
case_end;
+9 -4
View File
@@ -1531,11 +1531,15 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
d->type_expr = type;
d->init_expr = type;
} else if (up_init != NULL && up_init->kind == AstNode_Alias) {
#if 1
error_node(up_init, "#alias declarations are not yet supported");
continue;
// e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, NULL);
// d->init_expr = init->Alias.expr;
}else if (init != NULL && up_init->kind == AstNode_ProcLit) {
#else
e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL);
d->type_expr = vd->type;
d->init_expr = up_init->Alias.expr;
#endif
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_lit = up_init;
d->type_expr = vd->type;
@@ -1989,7 +1993,8 @@ void check_parsed_files(Checker *c) {
// NOTE(bill): Check for illegal cyclic type declarations
for_array(i, c->info.definitions.entries) {
Entity *e = c->info.definitions.entries.e[i].value;
if (e->kind == Entity_TypeName) {
if (e->kind == Entity_TypeName ||
(e->kind == Entity_Alias && e->Alias.kind == EntityAlias_Type)) {
if (e->type != NULL) {
// i64 size = type_size_of(c->sizes, c->allocator, e->type);
i64 align = type_align_of(c->allocator, e->type);
+13 -2
View File
@@ -50,11 +50,18 @@ typedef enum OverloadKind {
Overload_Yes,
} OverloadKind;
typedef enum EntityAliasKind {
EntityAlias_Invalid,
EntityAlias_Type,
EntityAlias_Entity,
} EntityAliasKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity;
struct Entity {
EntityKind kind;
u64 id;
u32 flags;
Token token;
Scope * scope;
@@ -101,7 +108,8 @@ struct Entity {
bool used;
} LibraryName;
struct {
Entity *original;
EntityAliasKind kind;
Entity * original;
} Alias;
i32 Nil;
struct {
@@ -138,6 +146,7 @@ bool is_entity_exported(Entity *e) {
return name.text[0] != '_';
}
gb_global u64 global_entity_id = 0;
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
Entity *entity = gb_alloc_item(a, Entity);
@@ -145,6 +154,7 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
entity->scope = scope;
entity->token = token;
entity->type = type;
entity->id = ++global_entity_id;
return entity;
}
@@ -231,8 +241,9 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
}
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type,
Entity *original) {
EntityAliasKind kind, Entity *original) {
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
entity->Alias.kind = kind;
entity->Alias.original = original;
return entity;
}
+23 -10
View File
@@ -3284,23 +3284,34 @@ String ir_mangle_name(irGen *s, String path, Entity *e) {
char const *ext = gb_path_extension(base);
isize base_len = ext-1-base;
isize max_len = base_len + 1 + 10 + 1 + name.len;
isize max_len = base_len + 1 + 1 + 10 + 1 + name.len;
bool is_overloaded = check_is_entity_overloaded(e);
if (is_overloaded) {
max_len += 21;
}
u8 *new_name = gb_alloc_array(a, u8, max_len);
isize new_name_len = gb_snprintf(
cast(char *)new_name, max_len,
"%.*s-%u.%.*s",
cast(int)base_len, base,
file->id,
LIT(name));
isize new_name_len = 0;
if ((base_len > 0 && gb_char_is_digit(base[0])) ||
base_len == 0) {
new_name_len = gb_snprintf(
cast(char *)new_name, max_len,
"_%.*s-%u.%.*s",
cast(int)base_len, base,
file->id,
LIT(name));
} else {
new_name_len = gb_snprintf(
cast(char *)new_name, max_len,
"%.*s-%u.%.*s",
cast(int)base_len, base,
file->id,
LIT(name));
}
if (is_overloaded) {
char *str = cast(char *)new_name + new_name_len-1;
isize len = max_len-new_name_len;
isize extra = gb_snprintf(str, len, "-%tu", cast(usize)cast(uintptr)e);
isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id);
new_name_len += extra-1;
}
@@ -4311,7 +4322,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
irValue *kmag = ir_build_expr(proc, ce->args.e[3]);
irValue *dst = ir_add_local_generated(proc, tv->type);
Type *ft = base_complex_elem_type(tv->type);
Type *ft = base_quaternion_elem_type(tv->type);
real = ir_emit_conv(proc, real, ft);
imag = ir_emit_conv(proc, imag, ft);
jmag = ir_emit_conv(proc, jmag, ft);
@@ -7217,6 +7228,7 @@ void ir_gen_tree(irGen *s) {
if (var->init != NULL && var->init->kind == irValue_Constant) {
Type *t = type_deref(ir_type(var->var));
if (is_type_any(t)) {
// NOTE(bill): Edge case for `any` type
Type *var_type = default_type(ir_type(var->init));
irValue *g = ir_add_global_generated(proc->module, var_type, var->init);
irValue *data = ir_emit_struct_ep(proc, var->var, 0);
@@ -7233,7 +7245,8 @@ void ir_gen_tree(irGen *s) {
irGlobalVariable *var = &global_variables.e[i];
if (var->init != NULL && var->init->kind != irValue_Constant) {
Type *t = type_deref(ir_type(var->var));
if (is_type_any(t)) {
if (is_type_any(t)) {
// NOTE(bill): Edge case for `any` type
Type *var_type = default_type(ir_type(var->init));
irValue *g = ir_add_global_generated(proc->module, var_type, var->init);
ir_emit_store(proc, g, var->init);
+1 -1
View File
@@ -430,7 +430,7 @@ int main(int argc, char **argv) {
exit_code = system_exec_command_line_app("ld-link", true,
"%s \"%.*s\".o -o \"%.*s%s\" %s "
"-lc "
"-lc -lm "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
+8 -4
View File
@@ -33,6 +33,7 @@ typedef struct AstFile {
// NOTE(bill): Used to prevent type literals in control clauses
isize expr_level;
bool allow_range;
bool ignore_operand;
AstNodeArray decls;
bool is_global_scope;
@@ -1849,10 +1850,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
}
}
Token begin = f->curr_token;
syntax_error(begin, "Expected an operand");
fix_advance_to_next_stmt(f);
return ast_bad_expr(f, begin, f->curr_token);
return NULL;
}
bool is_literal_type(AstNode *node) {
@@ -1937,6 +1935,12 @@ AstNode *parse_macro_call_expr(AstFile *f, AstNode *operand) {
AstNode *parse_atom_expr(AstFile *f, bool lhs) {
AstNode *operand = parse_operand(f, lhs);
if (operand == NULL) {
Token begin = f->curr_token;
syntax_error(begin, "Expected an operand");
fix_advance_to_next_stmt(f);
operand = ast_bad_expr(f, begin, f->curr_token);
}
bool loop = true;
while (loop) {
+14
View File
@@ -551,6 +551,20 @@ bool is_type_named(Type *t) {
}
return t->kind == Type_Named;
}
bool is_type_named_alias(Type *t) {
if (!is_type_named(t)) {
return false;
}
Entity *e = t->Named.type_name;
if (e == NULL) {
return false;
}
if (e->kind != Entity_TypeName) {
return false;
}
return e->TypeName.is_type_alias;
}
bool is_type_boolean(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {