mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-20 13:25:19 +00:00
Filename as default import name; as .; as _; panic()
This commit is contained in:
@@ -46,9 +46,6 @@ rem pushd %build_dir%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
del ..\misc\*.pdb > NUL 2> NUL
|
||||
del ..\misc\*.ilk > NUL 2> NUL
|
||||
|
||||
cl %compiler_settings% "src\main.cpp" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run code/demo.odin
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#import "fmt.odin" as fmt
|
||||
#import "os.odin" as os
|
||||
#import "fmt.odin"
|
||||
#import "os.odin"
|
||||
|
||||
|
||||
main :: proc() {
|
||||
Fruit :: enum {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#import "win32.odin" as win32
|
||||
#import "fmt.odin" as fmt
|
||||
#import "win32.odin"
|
||||
#import "fmt.odin"
|
||||
#import "math.odin"
|
||||
#import "opengl.odin" as gl
|
||||
#import "math.odin" as math
|
||||
|
||||
TWO_HEARTS :: #rune "💕"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#import "win32.odin" as win32
|
||||
#import "fmt.odin" as fmt
|
||||
#import "os.odin" as os
|
||||
#import "win32.odin"
|
||||
#import "fmt.odin"
|
||||
#import "os.odin"
|
||||
|
||||
CANVAS_WIDTH :: 128
|
||||
CANVAS_HEIGHT :: 128
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#import "fmt.odin" as fmt
|
||||
#import "fmt.odin"
|
||||
|
||||
thing :: proc() #link_name "frankerooney" {
|
||||
fmt.println("Hello!")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#import "os.odin" as os
|
||||
#import "os.odin"
|
||||
|
||||
PRINT_BUF_SIZE :: 1<<12
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#import "win32.odin" as win32
|
||||
#import "win32.odin"
|
||||
|
||||
File :: type struct {
|
||||
Handle :: type win32.HANDLE
|
||||
@@ -50,7 +50,6 @@ stdin := ^__std_files[File_Standard.INPUT]
|
||||
stdout := ^__std_files[File_Standard.OUTPUT]
|
||||
stderr := ^__std_files[File_Standard.ERROR]
|
||||
|
||||
|
||||
__set_file_standards :: proc() -> [File_Standard.COUNT as int]File {
|
||||
return [File_Standard.COUNT as int]File{
|
||||
File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#shared_global_scope
|
||||
|
||||
#import "os.odin" as os
|
||||
#import "fmt.odin" as fmt
|
||||
#import "os.odin"
|
||||
#import "fmt.odin"
|
||||
|
||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||
// The compiler relies upon this _exact_ order
|
||||
@@ -134,93 +134,6 @@ memory_copy :: proc(dst, src: rawptr, len: int) #inline {
|
||||
llvm_memmove_64bit(dst, src, len, 1, false)
|
||||
}
|
||||
|
||||
__string_eq :: proc(a, b: string) -> bool {
|
||||
if a.count != b.count {
|
||||
return false
|
||||
}
|
||||
if ^a[0] == ^b[0] {
|
||||
return true
|
||||
}
|
||||
return memory_compare(^a[0], ^b[0], a.count) == 0
|
||||
}
|
||||
|
||||
__string_cmp :: proc(a, b : string) -> int {
|
||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||
n := min(a.count, b.count)
|
||||
|
||||
fast := n/size_of(int) + 1
|
||||
offset := (fast-1)*size_of(int)
|
||||
curr_block := 0
|
||||
if n <= size_of(int) {
|
||||
fast = 0
|
||||
}
|
||||
|
||||
la := slice_ptr(^a[0] as ^int, fast)
|
||||
lb := slice_ptr(^b[0] as ^int, fast)
|
||||
|
||||
for ; curr_block < fast; curr_block++ {
|
||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||
for pos := curr_block*size_of(int); pos < n; pos++ {
|
||||
if (a[pos] ~ b[pos]) != 0 {
|
||||
return a[pos] as int - b[pos] as int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ; offset < n; offset++ {
|
||||
if (a[offset] ~ b[offset]) != 0 {
|
||||
return a[offset] as int - b[offset] as int
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
|
||||
__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
||||
__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
||||
__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 }
|
||||
|
||||
|
||||
__assert :: proc(msg: string) {
|
||||
fmt.fprintln(os.stderr, msg)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__bounds_check_error :: proc(file: string, line, column: int,
|
||||
index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
return
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
|
||||
file, line, column, index, count)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__slice_expr_error :: proc(file: string, line, column: int,
|
||||
low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
|
||||
file, line, column, low, high, max)
|
||||
__debug_trap()
|
||||
}
|
||||
__substring_expr_error :: proc(file: string, line, column: int,
|
||||
low, high: int) {
|
||||
if 0 <= low && low <= high {
|
||||
return
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
|
||||
file, line, column, low, high)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -357,6 +270,103 @@ __default_allocator :: proc() -> Allocator {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
__string_eq :: proc(a, b: string) -> bool {
|
||||
if a.count != b.count {
|
||||
return false
|
||||
}
|
||||
if ^a[0] == ^b[0] {
|
||||
return true
|
||||
}
|
||||
return memory_compare(^a[0], ^b[0], a.count) == 0
|
||||
}
|
||||
|
||||
__string_cmp :: proc(a, b : string) -> int {
|
||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||
n := min(a.count, b.count)
|
||||
|
||||
fast := n/size_of(int) + 1
|
||||
offset := (fast-1)*size_of(int)
|
||||
curr_block := 0
|
||||
if n <= size_of(int) {
|
||||
fast = 0
|
||||
}
|
||||
|
||||
la := slice_ptr(^a[0] as ^int, fast)
|
||||
lb := slice_ptr(^b[0] as ^int, fast)
|
||||
|
||||
for ; curr_block < fast; curr_block++ {
|
||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||
for pos := curr_block*size_of(int); pos < n; pos++ {
|
||||
if (a[pos] ~ b[pos]) != 0 {
|
||||
return a[pos] as int - b[pos] as int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ; offset < n; offset++ {
|
||||
if (a[offset] ~ b[offset]) != 0 {
|
||||
return a[offset] as int - b[offset] as int
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
|
||||
__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
||||
__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
||||
__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 }
|
||||
|
||||
|
||||
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
|
||||
file, line, column, msg)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__bounds_check_error :: proc(file: string, line, column: int,
|
||||
index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
return
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
|
||||
file, line, column, index, count)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__slice_expr_error :: proc(file: string, line, column: int,
|
||||
low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
|
||||
file, line, column, low, high, max)
|
||||
__debug_trap()
|
||||
}
|
||||
__substring_expr_error :: proc(file: string, line, column: int,
|
||||
low, high: int) {
|
||||
if 0 <= low && low <= high {
|
||||
return
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
|
||||
file, line, column, low, high)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
||||
info = type_info_base(info)
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ enum BuiltinProcId {
|
||||
|
||||
BuiltinProc_compile_assert,
|
||||
BuiltinProc_assert,
|
||||
BuiltinProc_panic,
|
||||
|
||||
BuiltinProc_copy,
|
||||
BuiltinProc_append,
|
||||
@@ -188,6 +189,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
|
||||
{STR_LIT("compile_assert"), 1, false, Expr_Stmt},
|
||||
{STR_LIT("assert"), 1, false, Expr_Stmt},
|
||||
{STR_LIT("panic"), 1, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("copy"), 2, false, Expr_Expr},
|
||||
{STR_LIT("append"), 2, false, Expr_Expr},
|
||||
@@ -416,12 +418,15 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
|
||||
|
||||
void check_scope_usage(Checker *c, Scope *scope) {
|
||||
// TODO(bill): Use this?
|
||||
#if 0
|
||||
#if 1
|
||||
gb_for_array(i, scope->elements.entries) {
|
||||
auto *entry = scope->elements.entries + i;
|
||||
Entity *e = entry->value;
|
||||
if (e->kind == Entity_Variable && !e->Variable.used) {
|
||||
warning(e->token, "Unused variable: %.*s", LIT(e->token.string));
|
||||
if (e->kind == Entity_Variable) {
|
||||
auto *v = &e->Variable;
|
||||
if (!v->is_field && !v->used) {
|
||||
warning(e->token, "Unused variable: %.*s", LIT(e->token.string));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1040,7 +1045,7 @@ void check_parsed_files(Checker *c) {
|
||||
warning(id->token, "Multiple #import of the same file within this scope");
|
||||
}
|
||||
|
||||
if (id->import_name.string == make_string("_")) {
|
||||
if (id->import_name.string == make_string(".")) {
|
||||
// NOTE(bill): Add imported entities to this file's scope
|
||||
gb_for_array(elem_index, scope->elements.entries) {
|
||||
Entity *e = scope->elements.entries[elem_index].value;
|
||||
@@ -1057,11 +1062,50 @@ void check_parsed_files(Checker *c) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GB_ASSERT(id->import_name.string.len > 0);
|
||||
Entity *e = make_entity_import_name(c->allocator, file_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
add_entity(c, file_scope, NULL, e);
|
||||
String import_name = id->import_name.string;
|
||||
if (import_name.len == 0) {
|
||||
// NOTE(bill): use file name (without extension) as the identifier
|
||||
// If it is a valid identifier
|
||||
String filename = id->fullpath;
|
||||
isize slash = 0;
|
||||
isize dot = 0;
|
||||
for (isize i = filename.len-1; i >= 0; i--) {
|
||||
u8 c = filename.text[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
slash = i;
|
||||
}
|
||||
|
||||
filename.text += slash;
|
||||
filename.len -= slash;
|
||||
|
||||
dot = filename.len;
|
||||
while (dot --> 0) {
|
||||
u8 c = filename.text[dot];
|
||||
if (c == '.') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
filename.len = dot;
|
||||
|
||||
if (is_string_an_identifier(filename)) {
|
||||
import_name = filename;
|
||||
} else {
|
||||
error(ast_node_token(decl),
|
||||
"File name, %.*s, cannot be as an import name as it is not a valid identifier",
|
||||
LIT(filename));
|
||||
}
|
||||
}
|
||||
|
||||
if (import_name.len > 0) {
|
||||
id->import_name.string = import_name;
|
||||
Entity *e = make_entity_import_name(c->allocator, file_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
add_entity(c, file_scope, NULL, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1534,7 +1534,9 @@ b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(xb) && is_type_u8_slice(yb)) {
|
||||
return true;
|
||||
if (is_type_typed(xb)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// proc <-> proc
|
||||
@@ -2422,6 +2424,20 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
}
|
||||
break;
|
||||
|
||||
case BuiltinProc_panic:
|
||||
// panic :: proc(msg: string)
|
||||
|
||||
if (!is_type_string(operand->type)) {
|
||||
gbString str = expr_to_string(ce->args[0]);
|
||||
defer (gb_string_free(str));
|
||||
error(ast_node_token(call),
|
||||
"`%s` is not a string", str);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_NoValue;
|
||||
break;
|
||||
|
||||
case BuiltinProc_copy: {
|
||||
// copy :: proc(x, y: []Type) -> int
|
||||
Type *dest_type = NULL, *src_type = NULL;
|
||||
|
||||
@@ -2230,30 +2230,22 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
ssa_emit_if(proc, cond, err, done);
|
||||
proc->curr_block = err;
|
||||
|
||||
// TODO(bill): Cleanup allocations here
|
||||
Token token = ast_node_token(ce->args[0]);
|
||||
TokenPos pos = token.pos;
|
||||
gbString expr = expr_to_string(ce->args[0]);
|
||||
defer (gb_string_free(expr));
|
||||
isize expr_len = gb_string_length(expr);
|
||||
String expr_str = {};
|
||||
expr_str.text = cast(u8 *)gb_alloc_copy_align(proc->module->allocator, expr, expr_len, 1);
|
||||
expr_str.len = expr_len;
|
||||
|
||||
isize err_len = pos.file.len + 1 + 10 + 1 + 10 + 1;
|
||||
err_len += 20;
|
||||
err_len += gb_string_length(expr);
|
||||
err_len += 2;
|
||||
|
||||
u8 *err_str = gb_alloc_array(proc->module->allocator, u8, err_len);
|
||||
err_len = gb_snprintf(cast(char *)err_str, err_len,
|
||||
"%.*s(%td:%td) Runtime assertion: %s\n",
|
||||
LIT(pos.file), pos.line, pos.column, expr);
|
||||
err_len--;
|
||||
|
||||
ssaValue *array = ssa_add_global_string_array(proc->module, make_string(err_str, err_len));
|
||||
ssaValue *elem = ssa_array_elem(proc, array);
|
||||
ssaValue *len = ssa_make_const_int(proc->module->allocator, err_len);
|
||||
ssaValue *string = ssa_emit_string(proc, elem, len);
|
||||
|
||||
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 1);
|
||||
args[0] = string;
|
||||
ssa_emit_global_call(proc, "__assert", args, 1);
|
||||
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 4);
|
||||
args[0] = ssa_emit_global_string(proc, pos.file);
|
||||
args[1] = ssa_make_const_int(proc->module->allocator, pos.line);
|
||||
args[2] = ssa_make_const_int(proc->module->allocator, pos.column);
|
||||
args[3] = ssa_emit_global_string(proc, expr_str);
|
||||
ssa_emit_global_call(proc, "__assert", args, 4);
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
gb_array_append(proc->blocks, done);
|
||||
@@ -2262,6 +2254,25 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return NULL;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_panic: {
|
||||
ssa_emit_comment(proc, make_string("panic"));
|
||||
ssaValue *msg = ssa_build_expr(proc, ce->args[0]);
|
||||
GB_ASSERT(is_type_string(ssa_type(msg)));
|
||||
|
||||
Token token = ast_node_token(ce->args[0]);
|
||||
TokenPos pos = token.pos;
|
||||
|
||||
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 4);
|
||||
args[0] = ssa_emit_global_string(proc, pos.file);
|
||||
args[1] = ssa_make_const_int(proc->module->allocator, pos.line);
|
||||
args[2] = ssa_make_const_int(proc->module->allocator, pos.column);
|
||||
args[3] = msg;
|
||||
ssa_emit_global_call(proc, "__assert", args, 4);
|
||||
|
||||
return NULL;
|
||||
} break;
|
||||
|
||||
|
||||
case BuiltinProc_copy: {
|
||||
ssa_emit_comment(proc, make_string("copy"));
|
||||
// copy :: proc(dst, src: []Type) -> int
|
||||
|
||||
49
src/main.cpp
49
src/main.cpp
@@ -126,33 +126,46 @@ int main(int argc, char **argv) {
|
||||
isize base_name_len = gb_path_extension(output_name)-1 - output_name;
|
||||
|
||||
|
||||
|
||||
i32 exit_code = 0;
|
||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||
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 "
|
||||
// "-S "
|
||||
// "-debug-pass=Arguments "
|
||||
"",
|
||||
output_name, cast(int)base_name_len, output_name);
|
||||
if (exit_code != 0)
|
||||
return exit_code;
|
||||
{
|
||||
char buf[300] = {};
|
||||
u32 buf_len = GetModuleFileNameA(GetModuleHandleA(NULL), buf, gb_size_of(buf));
|
||||
for (isize i = buf_len-1; i >= 0; i--) {
|
||||
if (buf[i] == '\\' ||
|
||||
buf[i] == '/') {
|
||||
break;
|
||||
}
|
||||
buf_len--;
|
||||
}
|
||||
|
||||
PRINT_TIMER("llvm-opt");
|
||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||
exit_code = win32_exec_command_line_app(
|
||||
// "../misc/llvm-bin/opt %s -o %.*s.bc "
|
||||
"\"%.*sbin\\opt.exe\" %s -o %.*s.bc "
|
||||
"-memcpyopt "
|
||||
"-mem2reg "
|
||||
"-die -dse "
|
||||
"-dce "
|
||||
// "-S "
|
||||
// "-debug-pass=Arguments "
|
||||
"",
|
||||
buf_len, buf,
|
||||
output_name,
|
||||
cast(int)base_name_len, output_name);
|
||||
if (exit_code != 0)
|
||||
return exit_code;
|
||||
|
||||
PRINT_TIMER("llvm-opt");
|
||||
}
|
||||
|
||||
#if 1
|
||||
gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib");
|
||||
gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32");
|
||||
// defer (gb_string_free(lib_str));
|
||||
char lib_str_buf[1024] = {};
|
||||
gb_for_array(i, parser.system_libraries) {
|
||||
String lib = parser.system_libraries[i];
|
||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||
" -l%.*s.lib", LIT(lib));
|
||||
" -l%.*s", LIT(lib));
|
||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -2587,10 +2587,18 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return make_bad_decl(f, token, f->cursor[0]);
|
||||
} else if (tag == make_string("import")) {
|
||||
// TODO(bill): better error messages
|
||||
Token import_name;
|
||||
Token import_name = {};
|
||||
Token file_path = expect_token(f, Token_String);
|
||||
expect_token(f, Token_as);
|
||||
import_name = expect_token(f, Token_Identifier);
|
||||
if (allow_token(f, Token_as)) {
|
||||
// NOTE(bill): Custom import name
|
||||
if (f->cursor[0].kind == Token_Period) {
|
||||
import_name = f->cursor[0];
|
||||
import_name.kind = Token_Identifier;
|
||||
next_token(f);
|
||||
} else {
|
||||
import_name = expect_token(f, Token_Identifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (f->curr_proc == NULL) {
|
||||
return make_import_decl(f, s->TagStmt.token, file_path, import_name, false);
|
||||
@@ -2601,7 +2609,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
// TODO(bill): better error messages
|
||||
Token file_path = expect_token(f, Token_String);
|
||||
Token import_name = file_path;
|
||||
import_name.string = make_string("_");
|
||||
import_name.string = make_string(".");
|
||||
|
||||
if (f->curr_proc == NULL) {
|
||||
return make_import_decl(f, s->TagStmt.token, file_path, import_name, true);
|
||||
@@ -2683,7 +2691,7 @@ AstNodeArray parse_stmt_list(AstFile *f) {
|
||||
|
||||
ParseFileError init_ast_file(AstFile *f, String fullpath) {
|
||||
if (!string_has_extension(fullpath, make_string("odin"))) {
|
||||
gb_printf_err("Only `.odin` files are allowed\n");
|
||||
// gb_printf_err("Only `.odin` files are allowed\n");
|
||||
return ParseFile_WrongExtension;
|
||||
}
|
||||
TokenizerInitError err = init_tokenizer(&f->tokenizer, fullpath);
|
||||
@@ -2775,11 +2783,13 @@ b32 try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
|
||||
|
||||
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
isize str_len = base_dir.len+path.len;
|
||||
|
||||
u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
|
||||
defer (gb_free(gb_heap_allocator(), str));
|
||||
|
||||
gb_memcopy(str, base_dir.text, base_dir.len);
|
||||
gb_memcopy(str+base_dir.len, path.text, path.len);
|
||||
isize i = 0;
|
||||
gb_memcopy(str+i, base_dir.text, base_dir.len); i += base_dir.len;
|
||||
gb_memcopy(str+i, path.text, path.len);
|
||||
str[str_len] = '\0';
|
||||
char *path_str = gb_path_get_full_name(a, cast(char *)str);
|
||||
return make_string(path_str);
|
||||
@@ -2861,6 +2871,26 @@ b32 is_import_path_valid(String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String get_filepath_extension(String path) {
|
||||
isize dot = 0;
|
||||
b32 seen_slash = false;
|
||||
for (isize i = path.len-1; i >= 0; i--) {
|
||||
u8 c = path.text[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
seen_slash = true;
|
||||
}
|
||||
|
||||
if (c == '.') {
|
||||
if (seen_slash) {
|
||||
return make_string("");
|
||||
}
|
||||
|
||||
dot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return make_string(path.text, dot);
|
||||
}
|
||||
|
||||
void parse_file(Parser *p, AstFile *f) {
|
||||
String filepath = f->tokenizer.fullpath;
|
||||
@@ -2900,9 +2930,8 @@ void parse_file(Parser *p, AstFile *f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String import_file = {};
|
||||
String rel_path = get_fullpath_relative(allocator, base_dir, file_str);
|
||||
import_file = rel_path;
|
||||
String import_file = rel_path;
|
||||
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
|
||||
String abs_path = get_fullpath_core(allocator, file_str);
|
||||
if (gb_file_exists(cast(char *)abs_path.text)) {
|
||||
@@ -2956,25 +2985,26 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
if (pos.line != 0) {
|
||||
gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
gb_printf_err("Failed to parse file: %.*s\n", LIT(import_rel_path));
|
||||
gb_printf_err("Failed to parse file: %.*s\n\t", LIT(import_rel_path));
|
||||
defer (gb_printf_err("\n"));
|
||||
switch (err) {
|
||||
case ParseFile_WrongExtension:
|
||||
gb_printf_err("\tInvalid file extension\n");
|
||||
gb_printf_err("Invalid file extension: File must have the extension `.odin`");
|
||||
break;
|
||||
case ParseFile_InvalidFile:
|
||||
gb_printf_err("\tInvalid file\n");
|
||||
gb_printf_err("Invalid file");
|
||||
break;
|
||||
case ParseFile_EmptyFile:
|
||||
gb_printf_err("\tFile is empty\n");
|
||||
gb_printf_err("File is empty");
|
||||
break;
|
||||
case ParseFile_Permission:
|
||||
gb_printf_err("\tFile permissions problem\n");
|
||||
gb_printf_err("File permissions problem");
|
||||
break;
|
||||
case ParseFile_NotFound:
|
||||
gb_printf_err("\tFile cannot be found\n");
|
||||
gb_printf_err("File cannot be found");
|
||||
break;
|
||||
case ParseFile_InvalidToken:
|
||||
gb_printf_err("\tInvalid token found in file\n");
|
||||
gb_printf_err("Invalid token found in file");
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
|
||||
@@ -39,3 +39,28 @@ b32 rune_is_whitespace(Rune r) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
b32 is_string_an_identifier(String s) {
|
||||
if (s.len < 1) {
|
||||
return false;
|
||||
}
|
||||
isize offset = 0;
|
||||
while (offset < s.len) {
|
||||
b32 ok = false;
|
||||
Rune r = -1;
|
||||
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
|
||||
if (offset == 0) {
|
||||
ok = rune_is_letter(r);
|
||||
} else {
|
||||
ok = rune_is_letter(r) || rune_is_digit(r);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
offset += size;
|
||||
}
|
||||
|
||||
return offset == s.len;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user