Call expression, either handle all or ignore all results.

This commit is contained in:
Ginger Bill
2016-09-16 11:38:20 +01:00
parent 807256dea4
commit 968de5aae8
11 changed files with 226 additions and 86 deletions

View File

@@ -1,16 +1,28 @@
#import "runtime.odin" as _
#import "punity.odin" as punity
#import "punity.odin" as pn
#import "fmt.odin" as fmt
test :: proc() {
thing :: proc() {
thing :: proc() {
fmt.println("Hello1")
}
fmt.println("Hello")
}
}
main :: proc() {
init :: proc() {
test()
init :: proc(c: ^pn.Core) {
}
step :: proc() {
step :: proc(c: ^pn.Core) {
if pn.key_down(pn.Key.ESCAPE) {
c.running = false
}
}
punity.run(init, step)
pn.run(init, step)
}

View File

@@ -10,7 +10,7 @@ time_now :: proc() -> f64 {
assert(win32_perf_count_freq != 0)
counter: i64
_ = win32.QueryPerformanceCounter(^counter)
win32.QueryPerformanceCounter(^counter)
result := counter as f64 / win32_perf_count_freq as f64
return result
}
@@ -24,7 +24,7 @@ win32_print_last_error :: proc() {
// Yuk!
to_c_string :: proc(s: string) -> []u8 {
c_str := new_slice(u8, s.count+1)
_ = copy(c_str, s as []byte)
copy(c_str, s as []byte)
c_str[s.count] = 0
return c_str
}
@@ -157,8 +157,8 @@ run :: proc() {
if msg.message == WM_QUIT {
running = false
}
_ = TranslateMessage(^msg)
_ = DispatchMessageA(^msg)
TranslateMessage(^msg)
DispatchMessageA(^msg)
}
if is_key_down(Key_Code.ESCAPE) {

View File

@@ -1,10 +1,5 @@
#shared_global_scope
// TODO(bill): Create a standard library "location" so I don't have to manually import "runtime.odin"
#import "win32.odin" as win32
#import "os.odin" as os
#import "fmt.odin" as fmt
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
Type_Info :: union {
@@ -80,20 +75,22 @@ byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
heap_alloc :: proc(len: int) -> rawptr {
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, len)
heap_alloc :: proc(len: int) -> rawptr {
c_malloc :: proc(len: int) -> rawptr #foreign "malloc"
return c_malloc(len)
}
heap_free :: proc(ptr: rawptr) {
_ = win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
c_free :: proc(ptr: rawptr) #foreign "free"
c_free(ptr)
}
current_thread_id :: proc() -> int {
id := win32.GetCurrentThreadId()
return id as int
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
return GetCurrentThreadId() as int
}
memory_zero :: proc(data: rawptr, len: int) {
@@ -168,10 +165,16 @@ __string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
__print_err_str :: proc(s: string) {
}
__print_err_int :: proc(i: int) {
}
__assert :: proc(msg: string) {
_ = os.write(os.get_standard_file(os.File_Standard.ERROR), msg as []byte)
// TODO(bill): Write message
__print_err_str(msg)
__debug_trap()
}
@@ -180,9 +183,10 @@ __bounds_check_error :: proc(file: string, line, column: int,
if 0 <= index && index < count {
return
}
// TODO(bill): Write message
// TODO(bill): Probably reduce the need for `print` in the runtime if possible
fmt.println_err("%(%:%) Index % is out of bounds range [0, %)",
file, line, column, index, count)
// fmt.println_err("%(%:%) Index % is out of bounds range [0, %)",
// file, line, column, index, count)
__debug_trap()
}
@@ -191,8 +195,9 @@ __slice_expr_error :: proc(file: string, line, column: int,
if 0 <= low && low <= high && high <= max {
return
}
fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]",
file, line, column, low, high, max)
// TODO(bill): Write message
// fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]",
// file, line, column, low, high, max)
__debug_trap()
}
__substring_expr_error :: proc(file: string, line, column: int,
@@ -200,8 +205,9 @@ __substring_expr_error :: proc(file: string, line, column: int,
if 0 <= low && low <= high {
return
}
fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]",
file, line, column, low, high)
// TODO(bill): Write message
// fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]",
// file, line, column, low, high)
__debug_trap()
}

View File

@@ -83,14 +83,15 @@ RECT :: struct #ordered {
}
GetLastError :: proc() -> i32 #foreign #dll_import
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
GetLastError :: proc() -> i32 #foreign #dll_import
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
@@ -122,7 +123,7 @@ AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #
GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64
_ = QueryPerformanceFrequency(^r)
QueryPerformanceFrequency(^r)
return r
}
@@ -287,6 +288,7 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
is_key_down :: proc(key: Key_Code) -> bool {

View File

@@ -1034,7 +1034,9 @@ void check_parsed_files(Checker *c) {
Entity *e = scope->elements.entries[elem_index].value;
// NOTE(bill): Do not add other imported entities
if (e->scope == scope && e->kind != Entity_ImportName) {
add_entity(c, file_scope, NULL, e);
if (is_entity_exported(e)) {
add_entity(c, file_scope, NULL, e);
}
}
}
} else {

View File

@@ -51,7 +51,7 @@ struct Entity {
b8 is_field; // Is struct field
} Variable;
struct {
struct DeclInfo *decl; // Usually NULL
// struct DeclInfo *decl; // Usually NULL
} TypeName;
struct {
b8 pure;
@@ -66,6 +66,15 @@ struct Entity {
};
};
b32 is_entity_exported(Entity *e) {
// TODO(bill): Do I really want non-exported entities?
// if (e->token.string.len >= 1 &&
// e->token.string.text[0] == '_') {
// return false;
// }
return true;
}
gb_global gbAtomic64 entity_guid_counter = {0};
EntityGuid next_entity_guid(void) {

View File

@@ -835,27 +835,28 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
}
i64 check_array_count(Checker *c, AstNode *e) {
if (e) {
Operand o = {};
check_expr(c, &o, e);
if (o.mode != Addressing_Constant) {
if (o.mode != Addressing_Invalid) {
error(&c->error_collector, ast_node_token(e), "Array count must be a constant");
}
if (e == NULL) {
return 0;
}
Operand o = {};
check_expr(c, &o, e);
if (o.mode != Addressing_Constant) {
if (o.mode != Addressing_Invalid) {
error(&c->error_collector, ast_node_token(e), "Array count must be a constant");
}
return 0;
}
if (is_type_untyped(o.type) || is_type_integer(o.type)) {
if (o.value.kind == ExactValue_Integer) {
i64 count = o.value.value_integer;
if (count >= 0)
return count;
error(&c->error_collector, ast_node_token(e), "Invalid array count");
return 0;
}
if (is_type_untyped(o.type) || is_type_integer(o.type)) {
if (o.value.kind == ExactValue_Integer) {
i64 count = o.value.value_integer;
if (count >= 0)
return count;
error(&c->error_collector, ast_node_token(e), "Invalid array count");
return 0;
}
}
error(&c->error_collector, ast_node_token(e), "Array count must be an integer");
}
error(&c->error_collector, ast_node_token(e), "Array count must be an integer");
return 0;
}
@@ -2001,17 +2002,24 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
if (e != NULL && e->kind == Entity_ImportName) {
check_op_expr = false;
entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string);
add_entity_use(&c->info, selector, entity);
if (entity == NULL) {
gbString sel_str = expr_to_string(selector);
defer (gb_string_free(sel_str));
error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared in `%.*s`", sel_str, LIT(name));
error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared by `%.*s`", sel_str, LIT(name));
goto error;
}
if (entity->type == NULL) { // Not setup yet
check_entity_decl(c, entity, NULL, NULL);
}
GB_ASSERT(entity->type != NULL);
if (!is_entity_exported(entity)) {
gbString sel_str = expr_to_string(selector);
defer (gb_string_free(sel_str));
error(&c->error_collector, ast_node_token(op_expr), "`%s` is not exported by `%.*s`", sel_str, LIT(name));
// NOTE(bill): Not really an error so don't goto error
}
add_entity_use(&c->info, selector, entity);
}
}
if (check_op_expr) {

View File

@@ -8,6 +8,7 @@ enum StmtFlag : u32 {
void check_stmt(Checker *c, AstNode *node, u32 flags);
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later);
void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
@@ -437,6 +438,44 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
check_scope_usage(c, c->context.scope);
}
b32 are_signatures_similar_enough(Type *a_, Type *b_) {
GB_ASSERT(a_->kind == Type_Proc);
GB_ASSERT(b_->kind == Type_Proc);
auto *a = &a_->Proc;
auto *b = &b_->Proc;
if (a->param_count != b->param_count) {
return false;
}
if (a->result_count != b->result_count) {
return false;
}
for (isize i = 0; i < a->param_count; i++) {
Type *x = get_base_type(a->params->Tuple.variables[i]->type);
Type *y = get_base_type(b->params->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (!are_types_identical(x, y)) {
return false;
}
}
for (isize i = 0; i < a->result_count; i++) {
Type *x = get_base_type(a->results->Tuple.variables[i]->type);
Type *y = get_base_type(b->results->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (!are_types_identical(x, y)) {
return false;
}
}
return true;
}
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
GB_ASSERT(e->type == NULL);
@@ -446,13 +485,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
check_open_scope(c, pd->type);
defer (check_close_scope(c));
check_procedure_type(c, proc_type, pd->type);
// add_proc_entity(c, d->scope, pd->name, e);
if (d->scope->is_proc) {
// Nested procedures
add_entity(c, d->scope->parent, pd->name, e);
}
b32 is_foreign = (pd->tags & ProcTag_foreign) != 0;
@@ -460,8 +492,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
if (d->scope == c->global_scope &&
if ((d->scope->is_file || d->scope->is_global) &&
are_strings_equal(e->token.string, make_string("main"))) {
if (proc_type != NULL) {
auto *pt = &proc_type->Proc;
@@ -511,7 +542,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
TokenPos pos = f->token.pos;
Type *this_type = get_base_type(e->type);
Type *other_type = get_base_type(f->type);
if (!are_types_identical(this_type, other_type)) {
if (!are_signatures_similar_enough(this_type, other_type)) {
error(&c->error_collector, ast_node_token(d->proc_decl),
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
@@ -577,7 +608,10 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
}
}
c->context.decl = d;
// c->context.decl = d;
// Scope *prev = c->context.scope;
// c->context.scope = d->scope;
// defer (c->context.scope = prev);
if (e->kind == Entity_Procedure) {
check_proc_decl(c, e, d, true);
@@ -759,6 +793,12 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
default: {
gbString expr_str = expr_to_string(operand.expr);
defer (gb_string_free(expr_str));
if (kind == Expr_Stmt) {
return;
}
if (operand.expr->kind == AstNode_CallExpr) {
return;
}
error(&c->error_collector, ast_node_token(node), "Expression is not used: `%s`", expr_str);
} break;

View File

@@ -2535,6 +2535,23 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
}
Entity *e = entity_of_ident(proc->module->info, expr);
if (e->kind == Entity_Constant) {
if (get_base_type(e->type) == t_string) {
// HACK TODO(bill): This is lazy but it works
String str = e->Constant.value.value_string;
ssaValue *global_array = ssa_add_global_string_array(proc->module, str);
ssaValue *elem = ssa_array_elem(proc, global_array);
ssaValue *len = ssa_make_const_int(proc->module->allocator, str.len);
ssaValue *v = ssa_add_local_generated(proc, e->type);
ssaValue *str_elem = ssa_emit_struct_gep(proc, v, v_zero32, ssa_type(elem));
ssaValue *str_len = ssa_emit_struct_gep(proc, v, v_one32, t_int);
ssa_emit_store(proc, str_elem, elem);
ssa_emit_store(proc, str_len, len);
return ssa_make_addr(v, expr);
}
}
ssaValue *v = NULL;
ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
if (found) {
@@ -2555,20 +2572,35 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
case_ast_node(se, SelectorExpr, expr);
ssa_emit_comment(proc, make_string("SelectorExpr"));
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
String selector = unparen_expr(se->selector)->Ident.string;
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
if (type == t_invalid) {
// Imports
Entity *imp = entity_of_ident(proc->module->info, se->expr);
GB_ASSERT(imp->kind == Entity_ImportName);
// Entity *e = scope_lookup_entity(e->ImportName.scope, selector);
if (imp != NULL) {
GB_ASSERT(imp->kind == Entity_ImportName);
}
return ssa_build_addr(proc, unparen_expr(se->selector));
} else {
} /* else if (type == t_string) {
Selection sel = lookup_field(type, selector, false);
GB_ASSERT(sel.entity != NULL);
ssaValue *e = ssa_build_addr(proc, se->expr).addr;
e = ssa_emit_deep_field_gep(proc, type, e, sel);
return ssa_make_addr(e, expr);
// 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);
GB_ASSERT(sel.entity != NULL);
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);
}
case_end;

View File

@@ -128,10 +128,10 @@ int main(int argc, char **argv) {
exit_code = win32_exec_command_line_app(
// "../misc/llvm-bin/opt %s -o %.*s.bc "
"opt %s -o %.*s.bc "
// "-memcpyopt "
// "-mem2reg "
// "-die -dse "
// "-dce "
"-memcpyopt "
"-mem2reg "
"-die -dse "
"-dce "
// "-S "
// "-debug-pass=Arguments "
"",

View File

@@ -45,6 +45,7 @@ struct AstFile {
struct ImportedFile {
String path;
String rel_path;
TokenPos pos; // #import
};
@@ -2736,7 +2737,7 @@ void destroy_parser(Parser *p) {
}
// NOTE(bill): Returns true if it's added
b32 try_add_import_path(Parser *p, String path, TokenPos pos) {
b32 try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
gb_for_array(i, p->imports) {
String import = p->imports[i].path;
if (are_strings_equal(import, path)) {
@@ -2746,6 +2747,7 @@ b32 try_add_import_path(Parser *p, String path, TokenPos pos) {
ImportedFile item;
item.path = path;
item.rel_path = rel_path;
item.pos = pos;
gb_array_append(p->imports, item);
return true;
@@ -2807,8 +2809,10 @@ void parse_file(Parser *p, AstFile *f) {
String filepath = f->tokenizer.fullpath;
String base_dir = filepath;
for (isize i = filepath.len-1; i >= 0; i--) {
if (base_dir.text[i] == GB_PATH_SEPARATOR)
if (base_dir.text[i] == '\\' ||
base_dir.text[i] == '/') {
break;
}
base_dir.len--;
}
@@ -2843,7 +2847,7 @@ void parse_file(Parser *p, AstFile *f) {
String import_file = make_string(path_str);
id->fullpath = import_file;
if (!try_add_import_path(p, import_file, ast_node_token(node).pos)) {
if (!try_add_import_path(p, import_file, file_str, ast_node_token(node).pos)) {
// gb_free(gb_heap_allocator(), import_file.text);
}
} else if (node->kind == AstNode_ForeignSystemLibrary) {
@@ -2866,15 +2870,40 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
String init_fullpath = make_string(fullpath_str);
TokenPos init_pos = {};
ImportedFile init_imported_file = {init_fullpath, init_pos};
ImportedFile init_imported_file = {init_fullpath, init_fullpath, init_pos};
gb_array_append(p->imports, init_imported_file);
p->init_fullpath = init_fullpath;
// {
// // IMPORTANT TODO(bill): Don't embed this, do it relative to the .exe
// char *path = gb_path_get_full_name(gb_heap_allocator(), "W:/Odin/core/__runtime.odin");
// String s = make_string(path);
// ImportedFile runtime_file = {s, s, init_pos};
// gb_array_append(p->imports, runtime_file);
// }
gb_for_array(i, p->imports) {
String import_path = p->imports[i].path;
String import_rel_path = p->imports[i].rel_path;
TokenPos pos = p->imports[i].pos;
AstFile file = {};
ParseFileError err = init_ast_file(&file, import_path);
// if (err == ParseFile_NotFound) {
// // HACK(bill): Check core directory
// char buf[300] = {};
// char core[] = "W:/Odin/core/";
// isize len = gb_size_of(core)-1;
// gb_memcopy(buf, core, len);
// gb_memcopy(buf+len, import_rel_path.text, import_rel_path.len);
// char *path = gb_path_get_full_name(gb_heap_allocator(), buf);
// gb_printf_err("%s\n", path);
// import_path = make_string(path);
// err = init_ast_file(&file, import_path);
// p->imports[i].path = import_path;
// }
if (err != ParseFile_None) {
if (pos.line != 0) {
gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);