mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-31 10:22:08 +00:00
fmt improvement; Minor refactoring
This commit is contained in:
108
code/demo.odin
108
code/demo.odin
@@ -1,22 +1,8 @@
|
||||
#import "fmt.odin" as fmt
|
||||
// #import "fmt.odin" as fmt
|
||||
// #import "os.odin" as os
|
||||
|
||||
main :: proc() {
|
||||
Fruit :: enum {
|
||||
APPLE = -2,
|
||||
BANANA,
|
||||
GRAPE,
|
||||
MELON = 123,
|
||||
TOMATO,
|
||||
}
|
||||
|
||||
s1 := enum_to_string(Fruit.BANANA)
|
||||
e := Fruit.MELON
|
||||
s2 := enum_to_string(e)
|
||||
|
||||
fmt.println(Fruit.APPLE)
|
||||
fmt.println(Fruit.count)
|
||||
fmt.println(Fruit.min_value)
|
||||
fmt.println(Fruit.max_value)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +10,51 @@ main :: proc() {
|
||||
|
||||
// #foreign_system_library "Ws2_32"
|
||||
|
||||
|
||||
// SOCKET :: type uint
|
||||
// INVALID_SOCKET :: ~(0 as SOCKET)
|
||||
|
||||
// AF :: enum i32 {
|
||||
// UNSPEC = 0, // unspecified
|
||||
// UNIX = 1, // local to host (pipes, portals)
|
||||
// INET = 2, // internetwork: UDP, TCP, etc.
|
||||
// IMPLINK = 3, // arpanet imp addresses
|
||||
// PUP = 4, // pup protocols: e.g. BSP
|
||||
// CHAOS = 5, // mit CHAOS protocols
|
||||
// NS = 6, // XEROX NS protocols
|
||||
// ISO = 7, // ISO protocols
|
||||
// OSI = ISO, // OSI is ISO
|
||||
// ECMA = 8, // european computer manufacturers
|
||||
// DATAKIT = 9, // datakit protocols
|
||||
// CCITT = 10, // CCITT protocols, X.25 etc
|
||||
// SNA = 11, // IBM SNA
|
||||
// DECnet = 12, // DECnet
|
||||
// DLI = 13, // Direct data link interface
|
||||
// LAT = 14, // LAT
|
||||
// HYLINK = 15, // NSC Hyperchannel
|
||||
// APPLETALK = 16, // AppleTalk
|
||||
// ROUTE = 17, // Internal Routing Protocol
|
||||
// LINK = 18, // Link layer interface
|
||||
// XTP = 19, // eXpress Transfer Protocol (no AF)
|
||||
// COIP = 20, // connection-oriented IP, aka ST II
|
||||
// CNT = 21, // Computer Network Technology
|
||||
// RTIP = 22, // Help Identify RTIP packets
|
||||
// IPX = 23, // Novell Internet Protocol
|
||||
// SIP = 24, // Simple Internet Protocol
|
||||
// PIP = 25, // Help Identify PIP packets
|
||||
// MAX = 26,
|
||||
// }
|
||||
|
||||
// SOCK_STREAM :: 1
|
||||
// SOCKET_ERROR :: -1
|
||||
// IPPROTO_TCP :: 6
|
||||
// AI_PASSIVE :: 0x0020
|
||||
// SOMAXCONN :: 128
|
||||
|
||||
// SD_RECEIVE :: 0
|
||||
// SD_SEND :: 1
|
||||
// SD_BOTH :: 2
|
||||
|
||||
// WSADESCRIPTION_LEN :: 256
|
||||
// WSASYS_STATUS_LEN :: 128
|
||||
// WSADATA :: struct #ordered {
|
||||
@@ -31,6 +62,7 @@ main :: proc() {
|
||||
// high_version: i16
|
||||
|
||||
|
||||
// // NOTE(bill): This is x64 ordering
|
||||
// max_sockets: u16
|
||||
// max_udp_dg: u16
|
||||
// vendor_info: ^byte
|
||||
@@ -55,48 +87,6 @@ main :: proc() {
|
||||
// }
|
||||
|
||||
|
||||
// SOCKET :: type uint
|
||||
// INVALID_SOCKET :: ~(0 as SOCKET)
|
||||
|
||||
// AF_UNSPEC :: 0 // unspecified
|
||||
// AF_UNIX :: 1 // local to host (pipes, portals)
|
||||
// AF_INET :: 2 // internetwork: UDP, TCP, etc.
|
||||
// AF_IMPLINK :: 3 // arpanet imp addresses
|
||||
// AF_PUP :: 4 // pup protocols: e.g. BSP
|
||||
// AF_CHAOS :: 5 // mit CHAOS protocols
|
||||
// AF_NS :: 6 // XEROX NS protocols
|
||||
// AF_ISO :: 7 // ISO protocols
|
||||
// AF_OSI :: AF_ISO // OSI is ISO
|
||||
// AF_ECMA :: 8 // european computer manufacturers
|
||||
// AF_DATAKIT :: 9 // datakit protocols
|
||||
// AF_CCITT :: 10 // CCITT protocols, X.25 etc
|
||||
// AF_SNA :: 11 // IBM SNA
|
||||
// AF_DECnet :: 12 // DECnet
|
||||
// AF_DLI :: 13 // Direct data link interface
|
||||
// AF_LAT :: 14 // LAT
|
||||
// AF_HYLINK :: 15 // NSC Hyperchannel
|
||||
// AF_APPLETALK :: 16 // AppleTalk
|
||||
// AF_ROUTE :: 17 // Internal Routing Protocol
|
||||
// AF_LINK :: 18 // Link layer interface
|
||||
// pseudo_AF_XTP :: 19 // eXpress Transfer Protocol (no AF)
|
||||
// AF_COIP :: 20 // connection-oriented IP, aka ST II
|
||||
// AF_CNT :: 21 // Computer Network Technology
|
||||
// pseudo_AF_RTIP :: 22 // Help Identify RTIP packets
|
||||
// AF_IPX :: 23 // Novell Internet Protocol
|
||||
// AF_SIP :: 24 // Simple Internet Protocol
|
||||
// pseudo_AF_PIP :: 25 // Help Identify PIP packets
|
||||
// AF_MAX :: 26
|
||||
|
||||
// SOCK_STREAM :: 1
|
||||
// SOCKET_ERROR :: -1
|
||||
// IPPROTO_TCP :: 6
|
||||
// AI_PASSIVE :: 0x0020
|
||||
// SOMAXCONN :: 128
|
||||
|
||||
// SD_RECEIVE :: 0
|
||||
// SD_SEND :: 1
|
||||
// SD_BOTH :: 2
|
||||
|
||||
// WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import
|
||||
// WSACleanup :: proc() -> i32 #foreign #dll_import
|
||||
// getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
|
||||
@@ -131,7 +121,7 @@ main :: proc() {
|
||||
// }
|
||||
// defer WSACleanup()
|
||||
|
||||
// hints.family = AF_INET
|
||||
// hints.family = AF.INET as i32
|
||||
// hints.socktype = SOCK_STREAM
|
||||
// hints.protocol = IPPROTO_TCP
|
||||
// hints.flags = AI_PASSIVE
|
||||
|
||||
@@ -120,7 +120,7 @@ variadic_procedures :: proc() {
|
||||
|
||||
print_prefix_f32s("a"); nl()
|
||||
print_prefix_f32s("b", 1); nl()
|
||||
print_prefix_f32s("c", 1, 2, 3); nl()
|
||||
7 print_prefix_f32s("c", 1, 2, 3); nl()
|
||||
|
||||
// Internally, the variadic procedures get allocated to an array on the stack,
|
||||
// and this array is passed a slice
|
||||
|
||||
@@ -2,42 +2,47 @@
|
||||
|
||||
PRINT_BUF_SIZE :: 1<<12
|
||||
|
||||
fprint :: proc(f: ^os.File, args: ..any) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprint :: proc(buf: ^[]byte, args: ..any) {
|
||||
prev_string := false
|
||||
|
||||
for i := 0; i < args.count; i++ {
|
||||
arg := args[i]
|
||||
is_string := arg.data != null && type_info_is_string(arg.type_info)
|
||||
if i > 0 && is_string && !prev_string {
|
||||
print_space_to_buffer(^buf)
|
||||
if i > 0 && !is_string && !prev_string {
|
||||
print_space_to_buffer(buf)
|
||||
}
|
||||
print_any_to_buffer(^buf, arg)
|
||||
print_any_to_buffer(buf, arg)
|
||||
prev_string = is_string;
|
||||
}
|
||||
}
|
||||
|
||||
bprintln :: proc(buf: ^[]byte, args: ..any) {
|
||||
for i := 0; i < args.count; i++ {
|
||||
if i > 0 {
|
||||
append(buf, #rune " ")
|
||||
}
|
||||
print_any_to_buffer(buf, args[i])
|
||||
}
|
||||
print_nl_to_buffer(buf)
|
||||
}
|
||||
|
||||
fprint :: proc(f: ^os.File, args: ..any) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprint(^buf, ..args)
|
||||
os.write(f, buf)
|
||||
}
|
||||
|
||||
fprintln :: proc(f: ^os.File, args: ..any) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
|
||||
for i := 0; i < args.count; i++ {
|
||||
if i > 0 {
|
||||
append(^buf, #rune " ")
|
||||
}
|
||||
print_any_to_buffer(^buf, args[i])
|
||||
}
|
||||
|
||||
print_nl_to_buffer(^buf)
|
||||
bprintln(^buf, ..args)
|
||||
os.write(f, buf)
|
||||
}
|
||||
fprintf :: proc(f: ^os.File, fmt: string, args: ..any) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
printf_to_buffer(^buf, fmt, ..args)
|
||||
bprintf(^buf, fmt, ..args)
|
||||
os.write(f, buf)
|
||||
}
|
||||
|
||||
@@ -52,6 +57,39 @@ printf :: proc(fmt: string, args: ..any) {
|
||||
fprintf(os.stdout, fmt, ..args)
|
||||
}
|
||||
|
||||
sprint :: proc(args: ..any) -> string {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprint(^buf, ..args)
|
||||
s := new_slice(byte, buf.count)
|
||||
copy(s, buf)
|
||||
return s as string
|
||||
}
|
||||
sprintln :: proc(args: ..any) -> string {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprintln(^buf, ..args)
|
||||
s := new_slice(byte, buf.count)
|
||||
copy(s, buf)
|
||||
return s as string
|
||||
}
|
||||
sprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprintf(^buf, fmt, ..args)
|
||||
s := new_slice(byte, buf.count)
|
||||
copy(s, buf)
|
||||
return s as string
|
||||
}
|
||||
|
||||
|
||||
|
||||
fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
print_type_to_buffer(^buf, info)
|
||||
os.write(f, buf)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -561,7 +599,7 @@ type_info_is_string :: proc(info: ^Type_Info) -> bool {
|
||||
}
|
||||
|
||||
|
||||
printf_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
||||
bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
||||
is_digit :: proc(r: rune) -> bool #inline {
|
||||
return r >= #rune "0" && r <= #rune "9"
|
||||
}
|
||||
|
||||
@@ -63,6 +63,18 @@ Type_Info :: union {
|
||||
}
|
||||
}
|
||||
|
||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||
for {
|
||||
match type i : info {
|
||||
case Type_Info.Named:
|
||||
info = i.base
|
||||
continue
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
||||
|
||||
@@ -416,7 +416,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
|
||||
|
||||
void check_scope_usage(Checker *c, Scope *scope) {
|
||||
// TODO(bill): Use this?
|
||||
#if 1
|
||||
#if 0
|
||||
gb_for_array(i, scope->elements.entries) {
|
||||
auto *entry = scope->elements.entries + i;
|
||||
Entity *e = entry->value;
|
||||
@@ -457,9 +457,7 @@ void add_global_entity(Entity *entity) {
|
||||
}
|
||||
|
||||
void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = name;
|
||||
Entity *entity = alloc_entity(a, Entity_Constant, NULL, token, type);
|
||||
Entity *entity = alloc_entity(a, Entity_Constant, NULL, make_token_ident(name), type);
|
||||
entity->Constant.value = value;
|
||||
add_global_entity(entity);
|
||||
}
|
||||
@@ -475,14 +473,10 @@ void init_universal_scope(void) {
|
||||
|
||||
// Types
|
||||
for (isize i = 0; i < gb_count_of(basic_types); i++) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = basic_types[i].Basic.name;
|
||||
add_global_entity(make_entity_type_name(a, NULL, token, &basic_types[i]));
|
||||
add_global_entity(make_entity_type_name(a, NULL, make_token_ident(basic_types[i].Basic.name), &basic_types[i]));
|
||||
}
|
||||
for (isize i = 0; i < gb_count_of(basic_type_aliases); i++) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = basic_type_aliases[i].Basic.name;
|
||||
add_global_entity(make_entity_type_name(a, NULL, token, &basic_type_aliases[i]));
|
||||
add_global_entity(make_entity_type_name(a, NULL, make_token_ident(basic_type_aliases[i].Basic.name), &basic_type_aliases[i]));
|
||||
}
|
||||
|
||||
// Constants
|
||||
@@ -493,9 +487,7 @@ void init_universal_scope(void) {
|
||||
// Builtin Procedures
|
||||
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
|
||||
BuiltinProcId id = cast(BuiltinProcId)i;
|
||||
Token token = {Token_Identifier};
|
||||
token.string = builtin_procs[i].name;
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, NULL, token, t_invalid);
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, NULL, make_token_ident(builtin_procs[i].name), t_invalid);
|
||||
entity->Builtin.id = id;
|
||||
add_global_entity(entity);
|
||||
}
|
||||
@@ -968,7 +960,7 @@ void check_parsed_files(Checker *c) {
|
||||
di->entities = entities;
|
||||
di->entity_count = entity_count;
|
||||
di->type_expr = vd->type;
|
||||
di->init_expr = vd->values[0]; // TODO(bill): Is this correct?
|
||||
di->init_expr = vd->values[0];
|
||||
}
|
||||
|
||||
gb_for_array(i, vd->names) {
|
||||
|
||||
@@ -133,8 +133,7 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): `content_name` is for debugging
|
||||
// TODO(bill): Maybe allow assignment to tuples?
|
||||
// NOTE(bill): `content_name` is for debugging and error messages
|
||||
void check_assignment(Checker *c, Operand *operand, Type *type, String context_name, b32 is_argument = false) {
|
||||
check_not_tuple(c, operand);
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
@@ -153,8 +152,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (type != NULL) {
|
||||
if (!check_is_assignable_to(c, operand, type, is_argument)) {
|
||||
gbString type_string = type_to_string(type);
|
||||
@@ -579,8 +576,6 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
if (named_type != NULL) {
|
||||
constant_type = named_type;
|
||||
}
|
||||
Token blank_token = {Token_Identifier};
|
||||
blank_token.string = make_string("");
|
||||
Entity *blank_entity = make_entity_constant(c->allocator, c->context.scope, blank_token, constant_type, make_exact_value_integer(0));;
|
||||
|
||||
gb_for_array(i, et->fields) {
|
||||
@@ -590,15 +585,15 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
Token name_token = f->field->Ident;
|
||||
|
||||
if (name_token.string == make_string("count")) {
|
||||
error(name_token, "`count` is a reserved identifier for enums");
|
||||
error(name_token, "`count` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
} else if (name_token.string == make_string("min_value")) {
|
||||
error(name_token, "`min_value` is a reserved identifier for enums");
|
||||
error(name_token, "`min_value` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
} else if (name_token.string == make_string("max_value")) {
|
||||
error(name_token, "`max_value` is a reserved identifier for enums");
|
||||
error(name_token, "`max_value` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
}
|
||||
@@ -611,7 +606,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
o.mode = Addressing_Invalid;
|
||||
}
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
check_assignment(c, &o, base_type, make_string("enumeration"));
|
||||
check_assignment(c, &o, constant_type, make_string("enumeration"));
|
||||
}
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
iota = o.value;
|
||||
@@ -639,14 +634,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
error(name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string));
|
||||
} else {
|
||||
map_set(&entity_map, key, e);
|
||||
add_entity(c, c->context.scope, NULL, e);
|
||||
fields[field_index++] = e;
|
||||
}
|
||||
add_entity_use(&c->info, f->field, e);
|
||||
}
|
||||
enum_type->Record.min_value = min_value;
|
||||
enum_type->Record.max_value = max_value;
|
||||
|
||||
enum_type->Record.other_fields = fields;
|
||||
enum_type->Record.other_field_count = gb_array_count(et->fields);
|
||||
|
||||
enum_type->Record.enum_count = make_entity_constant(c->allocator, NULL,
|
||||
make_token_ident(make_string("count")), t_int, make_exact_value_integer(enum_type->Record.other_field_count));
|
||||
enum_type->Record.min_value = make_entity_constant(c->allocator, NULL,
|
||||
make_token_ident(make_string("min_value")), constant_type, make_exact_value_integer(min_value));
|
||||
enum_type->Record.max_value = make_entity_constant(c->allocator, NULL,
|
||||
make_token_ident(make_string("max_value")), constant_type, make_exact_value_integer(max_value));
|
||||
}
|
||||
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_variadic_) {
|
||||
@@ -1019,7 +1021,9 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
||||
case_ast_node(et, EnumType, e);
|
||||
type = make_type_enum(c->allocator);
|
||||
set_base_type(named_type, type);
|
||||
check_open_scope(c, e);
|
||||
check_enum_type(c, type, named_type, e);
|
||||
check_close_scope(c);
|
||||
type->Record.node = e;
|
||||
goto end;
|
||||
case_end;
|
||||
@@ -2070,7 +2074,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
}
|
||||
|
||||
if (entity == NULL) {
|
||||
entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
|
||||
entity = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
|
||||
}
|
||||
if (entity == NULL) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
@@ -2217,7 +2221,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
Operand op = {};
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
Type *type = op.type;
|
||||
if (!type) {
|
||||
if (type == NULL || op.mode == Addressing_Builtin) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `size_of`");
|
||||
return false;
|
||||
}
|
||||
@@ -2231,8 +2235,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_size_of_val:
|
||||
// size_of_val :: proc(val: Type) -> int
|
||||
check_assignment(c, operand, NULL, make_string("argument of `size_of_val`"));
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type));
|
||||
@@ -2244,7 +2249,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
Operand op = {};
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
Type *type = op.type;
|
||||
if (!type) {
|
||||
if (type == NULL || op.mode == Addressing_Builtin) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `align_of`");
|
||||
return false;
|
||||
}
|
||||
@@ -2256,8 +2261,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_align_of_val:
|
||||
// align_of_val :: proc(val: Type) -> int
|
||||
check_assignment(c, operand, NULL, make_string("argument of `align_of_val`"));
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type));
|
||||
@@ -2270,7 +2276,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
Type *type = get_base_type(op.type);
|
||||
AstNode *field_arg = unparen_expr(ce->args[1]);
|
||||
if (type != NULL) {
|
||||
if (type != NULL || op.mode == Addressing_Builtin) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`");
|
||||
return false;
|
||||
}
|
||||
@@ -2286,7 +2292,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
|
||||
ast_node(arg, Ident, field_arg);
|
||||
Selection sel = lookup_field(type, arg->string, operand->mode == Addressing_Type);
|
||||
Selection sel = lookup_field(c->allocator, type, arg->string, operand->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(ast_node_token(ce->args[0]),
|
||||
@@ -2324,7 +2330,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
|
||||
ast_node(i, Ident, s->selector);
|
||||
Selection sel = lookup_field(type, i->string, operand->mode == Addressing_Type);
|
||||
Selection sel = lookup_field(c->allocator, type, i->string, operand->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(ast_node_token(arg),
|
||||
@@ -2341,7 +2347,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_type_of_val:
|
||||
// type_of_val :: proc(val: Type) -> type(Type)
|
||||
check_assignment(c, operand, NULL, make_string("argument of `type_of_val`"));
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin)
|
||||
return false;
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
@@ -2349,11 +2355,16 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
case BuiltinProc_type_info: {
|
||||
// type_info :: proc(val_or_type) -> ^Type_Info
|
||||
Operand op = {};
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
add_type_info_type(c, op.type);
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = t_type_info_ptr;
|
||||
|
||||
Operand op = {};
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
if (op.type == NULL || op.type == t_invalid || operand->mode == Addressing_Builtin) {
|
||||
error(ast_node_token(op.expr), "Invalid argument to `type_info`");
|
||||
return false;
|
||||
}
|
||||
add_type_info_type(c, op.type);
|
||||
} break;
|
||||
|
||||
case BuiltinProc_compile_assert:
|
||||
@@ -3193,7 +3204,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
}
|
||||
String name = kv->field->Ident.string;
|
||||
|
||||
Selection sel = lookup_field(type, name, o->mode == Addressing_Type);
|
||||
Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
error(ast_node_token(elem),
|
||||
"Unknown field `%.*s` in structure literal", LIT(name));
|
||||
|
||||
@@ -120,8 +120,9 @@ struct Type {
|
||||
|
||||
// enum only
|
||||
Type * enum_base; // Default is `int`
|
||||
i64 min_value;
|
||||
i64 max_value;
|
||||
Entity * enum_count;
|
||||
Entity * min_value;
|
||||
Entity * max_value;
|
||||
|
||||
// struct only
|
||||
i64 * struct_offsets;
|
||||
@@ -703,25 +704,28 @@ Selection make_selection(Entity *entity, gbArray(isize) index, b32 indirect) {
|
||||
}
|
||||
|
||||
void selection_add_index(Selection *s, isize index) {
|
||||
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
|
||||
// of heap allocation
|
||||
if (s->index == NULL) {
|
||||
gb_array_init(s->index, gb_heap_allocator());
|
||||
}
|
||||
gb_array_append(s->index, index);
|
||||
}
|
||||
|
||||
gb_global Entity *entity__any_type_info = NULL;
|
||||
gb_global Entity *entity__any_data = NULL;
|
||||
gb_global Entity *entity__string_data = NULL;
|
||||
gb_global Entity *entity__string_count = NULL;
|
||||
gb_global Entity *entity__any_type_info = NULL;
|
||||
gb_global Entity *entity__any_data = NULL;
|
||||
gb_global Entity *entity__string_data = NULL;
|
||||
gb_global Entity *entity__string_count = NULL;
|
||||
gb_global Entity *entity__slice_count = NULL;
|
||||
gb_global Entity *entity__slice_capacity = NULL;
|
||||
|
||||
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||
Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||
GB_ASSERT(type_ != NULL);
|
||||
|
||||
if (field_name == make_string("_")) {
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
gbAllocator a = gb_heap_allocator();
|
||||
Type *type = type_deref(type_);
|
||||
b32 is_ptr = type != type_;
|
||||
type = get_base_type(type);
|
||||
@@ -732,14 +736,10 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
String type_info_str = make_string("type_info");
|
||||
String data_str = make_string("data");
|
||||
if (entity__any_type_info == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = type_info_str;
|
||||
entity__any_type_info = make_entity_field(a, NULL, token, t_type_info_ptr, false, 0);
|
||||
entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 0);
|
||||
}
|
||||
if (entity__any_data == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = data_str;
|
||||
entity__any_data = make_entity_field(a, NULL, token, t_rawptr, false, 1);
|
||||
entity__any_data = make_entity_field(a, NULL, make_token_ident(data_str), t_rawptr, false, 1);
|
||||
}
|
||||
|
||||
if (field_name == type_info_str) {
|
||||
@@ -756,15 +756,11 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
String data_str = make_string("data");
|
||||
String count_str = make_string("count");
|
||||
if (entity__string_data == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = data_str;
|
||||
entity__string_data = make_entity_field(a, NULL, token, make_type_pointer(a, t_u8), false, 0);
|
||||
entity__string_data = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, t_u8), false, 0);
|
||||
}
|
||||
|
||||
if (entity__string_count == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
entity__string_count = make_entity_field(a, NULL, token, t_int, false, 1);
|
||||
entity__string_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
|
||||
}
|
||||
|
||||
if (field_name == data_str) {
|
||||
@@ -784,20 +780,16 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
String count_str = make_string("count");
|
||||
// NOTE(bill): Underlying memory address cannot be changed
|
||||
if (field_name == count_str) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Array.count));
|
||||
sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Array.count));
|
||||
return sel;
|
||||
}
|
||||
} else if (type->kind == Type_Vector) {
|
||||
String count_str = make_string("count");
|
||||
// NOTE(bill): Vectors are not addressable
|
||||
if (field_name == count_str) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Vector.count));
|
||||
sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count));
|
||||
return sel;
|
||||
}
|
||||
} else if (type->kind == Type_Slice) {
|
||||
@@ -807,24 +799,24 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
|
||||
if (field_name == data_str) {
|
||||
selection_add_index(&sel, 0);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = data_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_field(a, NULL, token, make_type_pointer(a, type->Slice.elem), false, 0);
|
||||
sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->Slice.elem), false, 0);
|
||||
return sel;
|
||||
} else if (field_name == count_str) {
|
||||
selection_add_index(&sel, 1);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_field(a, NULL, token, t_int, false, 1);
|
||||
if (entity__slice_count == NULL) {
|
||||
entity__slice_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
|
||||
}
|
||||
|
||||
sel.entity = entity__slice_count;
|
||||
return sel;
|
||||
} else if (field_name == capacity_str) {
|
||||
selection_add_index(&sel, 2);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = capacity_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_field(a, NULL, token, t_int, false, 2);
|
||||
if (entity__slice_capacity == NULL) {
|
||||
entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
|
||||
}
|
||||
|
||||
sel.entity = entity__slice_capacity;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
@@ -834,6 +826,8 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
}
|
||||
if (is_type) {
|
||||
if (is_type_union(type)) {
|
||||
// NOTE(bill): The subtype for a union are stored in the fields
|
||||
// as they are "kind of" like variables but not
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_TypeName);
|
||||
@@ -856,27 +850,14 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
}
|
||||
|
||||
if (is_type_enum(type)) {
|
||||
String count_str = make_string("count");
|
||||
String min_value_str = make_string("min_value");
|
||||
String max_value_str = make_string("max_value");
|
||||
|
||||
if (field_name == count_str) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Record.other_field_count));
|
||||
if (field_name == make_string("count")) {
|
||||
sel.entity = type->Record.enum_count;
|
||||
return sel;
|
||||
} else if (field_name == min_value_str) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = min_value_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, type->Record.enum_base, make_exact_value_integer(type->Record.min_value));
|
||||
} else if (field_name == make_string("min_value")) {
|
||||
sel.entity = type->Record.min_value;
|
||||
return sel;
|
||||
} else if (field_name == max_value_str) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = max_value_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, type->Record.enum_base, make_exact_value_integer(type->Record.max_value));
|
||||
} else if (field_name == make_string("max_value")) {
|
||||
sel.entity = type->Record.max_value;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
@@ -887,7 +868,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
String str = f->token.string;
|
||||
if (field_name == str) {
|
||||
selection_add_index(&sel, i);
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
}
|
||||
@@ -899,7 +880,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
}
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
|
||||
sel = lookup_field(f->type, field_name, is_type, sel);
|
||||
sel = lookup_field(a, f->type, field_name, is_type, sel);
|
||||
|
||||
if (sel.entity != NULL) {
|
||||
if (is_type_pointer(f->type))
|
||||
|
||||
@@ -396,18 +396,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
|
||||
ssa_fprintf(f, "%%%d = alloca ", value->id);
|
||||
ssa_print_type(f, m, type);
|
||||
ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
|
||||
// if (instr->Local.zero_initialized) {
|
||||
// ssa_fprintf(f, "\tstore ");
|
||||
// ssa_print_type(f, m, type);
|
||||
// ssa_fprintf(f, " zeroinitializer, ");
|
||||
// ssa_print_type(f, m, type);
|
||||
// ssa_fprintf(f, "* %%%d\n", value->id);
|
||||
// }
|
||||
} break;
|
||||
|
||||
case ssaInstr_ZeroInit: {
|
||||
Type *type = type_deref(ssa_type(instr->ZeroInit.address));
|
||||
ssa_fprintf(f, "\tstore ");
|
||||
ssa_fprintf(f, "store ");
|
||||
ssa_print_type(f, m, type);
|
||||
ssa_fprintf(f, " zeroinitializer, ");
|
||||
ssa_print_type(f, m, type);
|
||||
|
||||
@@ -385,12 +385,8 @@ void ssa_init_module(ssaModule *m, Checker *c) {
|
||||
// Add type info data
|
||||
{
|
||||
String name = make_string(SSA_TYPE_INFO_DATA_NAME);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = name;
|
||||
|
||||
|
||||
isize count = gb_array_count(c->info.type_info_map.entries);
|
||||
Entity *e = make_entity_variable(m->allocator, NULL, token, make_type_array(m->allocator, t_type_info, count));
|
||||
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, count));
|
||||
ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
|
||||
g->Global.is_private = true;
|
||||
ssa_module_add_value(m, e, g);
|
||||
@@ -421,10 +417,7 @@ void ssa_init_module(ssaModule *m, Checker *c) {
|
||||
}
|
||||
|
||||
String name = make_string(SSA_TYPE_INFO_DATA_MEMBER_NAME);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = name;
|
||||
|
||||
Entity *e = make_entity_variable(m->allocator, NULL, token,
|
||||
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name),
|
||||
make_type_array(m->allocator, t_type_info_member, count));
|
||||
ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
|
||||
ssa_module_add_value(m, e, g);
|
||||
@@ -1095,6 +1088,10 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
|
||||
ssa_emit_ret(proc, NULL);
|
||||
}
|
||||
|
||||
if (gb_array_count(proc->curr_block->instrs) == 0) {
|
||||
ssa_emit_unreachable(proc);
|
||||
}
|
||||
|
||||
proc->curr_block = proc->decl_block;
|
||||
ssa_emit_jump(proc, proc->entry_block);
|
||||
|
||||
@@ -1560,14 +1557,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
|
||||
Type *src = get_enum_base_type(get_base_type(src_type));
|
||||
Type *dst = get_enum_base_type(get_base_type(t));
|
||||
if (are_types_identical(src, dst)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value->kind == ssaValue_Constant) {
|
||||
if (is_type_any(dst)) {
|
||||
Type *dt = default_type(get_base_type(src_type));
|
||||
ssaValue *default_value = ssa_add_local_generated(proc, dt);
|
||||
ssaValue *default_value = ssa_add_local_generated(proc, default_type(src_type));
|
||||
ssa_emit_store(proc, default_value, value);
|
||||
return ssa_emit_conv(proc, ssa_emit_load(proc, default_value), t_any, is_argument);
|
||||
} else if (dst->kind == Type_Basic) {
|
||||
@@ -1587,6 +1580,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
}
|
||||
}
|
||||
|
||||
if (are_types_identical(src, dst)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// integer -> integer
|
||||
if (is_type_integer(src) && is_type_integer(dst)) {
|
||||
GB_ASSERT(src->kind == Type_Basic &&
|
||||
@@ -1684,7 +1681,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
// gb_printf("field_name: %.*s\n", LIT(field_name));
|
||||
if (field_name.len > 0) {
|
||||
// NOTE(bill): It can be casted
|
||||
Selection sel = lookup_field(sb, field_name, false);
|
||||
Selection sel = lookup_field(proc->module->allocator, sb, field_name, false);
|
||||
if (sel.entity != NULL) {
|
||||
ssa_emit_comment(proc, make_string("cast - polymorphism"));
|
||||
if (src_is_ptr) {
|
||||
@@ -1821,7 +1818,7 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
|
||||
String field_name = check_down_cast_name(t, type_deref(ssa_type(value)));
|
||||
GB_ASSERT(field_name.len > 0);
|
||||
Selection sel = lookup_field(t, field_name, false);
|
||||
Selection sel = lookup_field(proc->module->allocator, t, field_name, false);
|
||||
Type *t_u8_ptr = make_type_pointer(allocator, t_u8);
|
||||
ssaValue *bytes = ssa_emit_conv(proc, value, t_u8_ptr);
|
||||
|
||||
@@ -2088,11 +2085,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
|
||||
if (elem->kind == AstNode_FieldValue) {
|
||||
ast_node(kv, FieldValue, elem);
|
||||
Selection sel = lookup_field(base_type, kv->field->Ident.string, false);
|
||||
Selection sel = lookup_field(proc->module->allocator, base_type, kv->field->Ident.string, false);
|
||||
index = sel.index[0];
|
||||
field_expr = ssa_build_expr(proc, kv->value);
|
||||
} else {
|
||||
Selection sel = lookup_field(base_type, st->fields_in_src_order[field_index]->token.string, false);
|
||||
Selection sel = lookup_field(proc->module->allocator, base_type, st->fields_in_src_order[field_index]->token.string, false);
|
||||
index = sel.index[0];
|
||||
field_expr = ssa_build_expr(proc, elem);
|
||||
}
|
||||
@@ -2158,7 +2155,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
Entity *e = *found;
|
||||
switch (e->Builtin.id) {
|
||||
case BuiltinProc_type_info: {
|
||||
ssaValue *x = ssa_build_expr(proc, ce->args[0]);
|
||||
Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
|
||||
return ssa_type_info(proc, t);
|
||||
} break;
|
||||
@@ -2629,7 +2625,7 @@ ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
|
||||
p = ssa_add_using_variable(proc, parent);
|
||||
}
|
||||
|
||||
Selection sel = lookup_field(parent->type, name, false);
|
||||
Selection sel = lookup_field(proc->module->allocator, parent->type, name, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
|
||||
ssaValue *v = NULL;
|
||||
@@ -2694,25 +2690,14 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
|
||||
|
||||
if (type == t_invalid) {
|
||||
// Imports
|
||||
// NOTE(bill): Imports
|
||||
Entity *imp = entity_of_ident(proc->module->info, se->expr);
|
||||
if (imp != NULL) {
|
||||
GB_ASSERT(imp->kind == Entity_ImportName);
|
||||
}
|
||||
return ssa_build_addr(proc, unparen_expr(se->selector));
|
||||
} /* else if (type == t_string) {
|
||||
Selection sel = lookup_field(type, selector, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
|
||||
// NOTE(bill): This could a constant and the only non constant
|
||||
// selector is the `.data`, so build the expression instead
|
||||
ssaValue *e = ssa_build_expr(proc, se->expr);
|
||||
ssaValue *a = ssa_build_addr(proc, se->expr).addr;
|
||||
|
||||
a = ssa_emit_deep_field_gep(proc, type, a, sel);
|
||||
return ssa_make_addr(a, expr);
|
||||
} */else {
|
||||
Selection sel = lookup_field(type, selector, false);
|
||||
} else {
|
||||
Selection sel = lookup_field(proc->module->allocator, type, selector, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
|
||||
ssaValue *a = ssa_build_addr(proc, se->expr).addr;
|
||||
|
||||
@@ -150,6 +150,13 @@ struct Token {
|
||||
};
|
||||
|
||||
Token empty_token = {Token_Invalid};
|
||||
Token blank_token = {Token_Identifier, {cast(u8 *)"_", 1}};
|
||||
|
||||
Token make_token_ident(String s) {
|
||||
Token t = {Token_Identifier};
|
||||
t.string = s;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
struct ErrorCollector {
|
||||
|
||||
Reference in New Issue
Block a user