aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-09-07 20:55:59 +0100
committerGinger Bill <bill@gingerbill.org>2017-09-07 20:55:59 +0100
commit8e3b77aba81a6bd71c7e8b23f09fc76474f401d7 (patch)
tree812e5e8fe937a8c3d7c8b3e5b931f9c7f8984c7d /src
parent36e3a02f67997131507c1d6b389317324e04a0b6 (diff)
Library collections
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp66
-rw-r--r--src/common.cpp28
-rw-r--r--src/main.cpp98
-rw-r--r--src/parser.cpp109
-rw-r--r--src/string.cpp23
5 files changed, 250 insertions, 74 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index a63ff7b4e..b6846a9f6 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -29,7 +29,28 @@ struct BuildContext {
gb_global BuildContext build_context = {0};
+struct LibraryCollections {
+ String name;
+ String path;
+};
+
+gb_global Array<LibraryCollections> library_collections = {0};
+
+void add_library_collection(String name, String path) {
+ // TODO(bill): Check the path is valid and a directory
+ LibraryCollections lc = {name, string_trim_whitespace(path)};
+ array_add(&library_collections, lc);
+}
+bool find_library_collection_path(String name, String *path) {
+ for_array(i, library_collections) {
+ if (library_collections[i].name == name) {
+ if (path) *path = library_collections[i].path;
+ return true;
+ }
+ }
+ return false;
+}
// TODO(bill): OS dependent versions for the BuildContext
@@ -248,38 +269,39 @@ String path_to_fullpath(gbAllocator a, String s) {
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
- String res = {0};
- isize str_len = base_dir.len+path.len;
-
- u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
+ u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
+ defer (gb_free(heap_allocator(), str));
isize i = 0;
- gb_memmove(str+i, &base_dir[0], base_dir.len); i += base_dir.len;
- gb_memmove(str+i, &path[0], path.len);
- str[str_len] = '\0';
- res = path_to_fullpath(a, make_string(str, str_len));
- gb_free(heap_allocator(), str);
- return res;
+ gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
+ gb_memmove(str+i, "/", 1); i += 1;
+ gb_memmove(str+i, path.text, path.len); i += path.len;
+ str[i] = 0;
+
+ String res = make_string(str, i);
+ res = string_trim_whitespace(res);
+ return path_to_fullpath(a, res);
}
+
String get_fullpath_core(gbAllocator a, String path) {
String module_dir = odin_root_dir();
- String res = {0};
- char core[] = "core/";
- isize core_len = gb_size_of(core)-1;
+ String core = str_lit("core/");
- isize str_len = module_dir.len + core_len + path.len;
+ isize str_len = module_dir.len + core.len + path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
+ defer (gb_free(heap_allocator(), str));
- gb_memmove(str, &module_dir[0], module_dir.len);
- gb_memmove(str+module_dir.len, core, core_len);
- gb_memmove(str+module_dir.len+core_len, &path[0], path.len);
- str[str_len] = '\0';
-
- res = path_to_fullpath(a, make_string(str, str_len));
- gb_free(heap_allocator(), str);
- return res;
+ isize i = 0;
+ gb_memmove(str+i, module_dir.text, module_dir.len); i += module_dir.len;
+ gb_memmove(str+i, core.text, core.len); i += core.len;
+ gb_memmove(str+i, path.text, path.len); i += path.len;
+ str[i] = 0;
+
+ String res = make_string(str, i);
+ res = string_trim_whitespace(res);
+ return path_to_fullpath(a, res);
}
diff --git a/src/common.cpp b/src/common.cpp
index 06cb674dd..173ef4210 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -463,3 +463,31 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
}
#endif
+
+
+#if defined(GB_SYSTEM_WINDOWS)
+ bool path_is_directory(String path) {
+ gbAllocator a = heap_allocator();
+ String16 wstr = string_to_string16(a, path);
+ defer (gb_free(a, wstr.text));
+
+ i32 attribs = GetFileAttributesW(wstr.text);
+ if (attribs < 0) return false;
+
+ return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ }
+
+#else
+ bool path_is_directory(String path) {
+ gbAllocator a = heap_allocator();
+ String copy = copy_string(a, path);
+ defer (gb_free(a, copy.text));
+
+ struct stat s;
+ if (stat(copy.text, &s) == 0) {
+ return (s.st_mode & S_IFDIR) != 0;
+ }
+ return false;
+ }
+#endif
+
diff --git a/src/main.cpp b/src/main.cpp
index 0301b1186..eda4de2d1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -177,6 +177,7 @@ enum BuildFlagKind {
BuildFlag_ShowTimings,
BuildFlag_ThreadCount,
BuildFlag_KeepTempFiles,
+ BuildFlag_Collection,
BuildFlag_COUNT,
};
@@ -204,6 +205,36 @@ void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, Bu
array_add(build_flags, flag);
}
+bool string_is_valid_identifier(String str) {
+ if (str.len <= 0) return false;
+
+ isize rune_count = 0;
+
+ isize w = 0;
+ isize offset = 0;
+ while (offset < str.len) {
+ Rune r = 0;
+ w = gb_utf8_decode(str.text, str.len, &r);
+ if (r == GB_RUNE_INVALID) {
+ return false;
+ }
+
+ if (rune_count == 0) {
+ if (!rune_is_letter(r)) {
+ return false;
+ }
+ } else {
+ if (!rune_is_letter(r) && !rune_is_digit(r)) {
+ return false;
+ }
+ }
+ rune_count += 1;
+ offset += w;
+ }
+
+ return true;
+}
+
bool parse_build_flags(Array<String> args) {
Array<BuildFlag> build_flags = {};
array_init(&build_flags, heap_allocator(), BuildFlag_COUNT);
@@ -211,6 +242,7 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
+ add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
Array<String> flag_args = args;
@@ -358,6 +390,68 @@ bool parse_build_flags(Array<String> args) {
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.keep_temp_files = true;
break;
+
+ case BuildFlag_Collection: {
+ GB_ASSERT(value.kind == ExactValue_String);
+ String str = value.value_string;
+ isize eq_pos = -1;
+ for (isize i = 0; i < str.len; i++) {
+ if (str[i] == '=') {
+ eq_pos = i;
+ break;
+ }
+ }
+ if (eq_pos < 0) {
+ gb_printf_err("Expected `name=path`, got `%.*s`\n", LIT(param));
+ ok = false;
+ bad_flags = true;
+ break;
+ }
+ String name = substring(str, 0, eq_pos);
+ String path = substring(str, eq_pos+1, str.len);
+ if (name.len == 0 || path.len == 0) {
+ gb_printf_err("Expected `name=path`, got `%.*s`\n", LIT(param));
+ ok = false;
+ bad_flags = true;
+ break;
+ }
+
+ if (!string_is_valid_identifier(name)) {
+ gb_printf_err("Library collection name `%.*s` must be a valid identifier\n", LIT(name));
+ ok = false;
+ bad_flags = true;
+ break;
+ }
+
+ if (name == "_") {
+ gb_printf_err("Library collection name cannot be an underscore\n");
+ ok = false;
+ bad_flags = true;
+ break;
+ }
+
+ String prev_path = {};
+ bool found = find_library_collection_path(name, &prev_path);
+ if (found) {
+ gb_printf_err("Library collection `%.*s` already exists with path `%.*s`\n", LIT(name), LIT(prev_path));
+ ok = false;
+ bad_flags = true;
+ break;
+ }
+
+ gbAllocator a = heap_allocator();
+ String fullpath = path_to_fullpath(a, path);
+ if (!path_is_directory(fullpath)) {
+ gb_printf_err("Library collection `%.*s` path must be a directory, got `%.*s`\n", LIT(name), LIT(fullpath));
+ gb_free(a, fullpath.text);
+ ok = false;
+ bad_flags = true;
+ break;
+ }
+
+ add_library_collection(name, path);
+
+ } break;
}
}
@@ -449,6 +543,10 @@ int main(int arg_count, char **arg_ptr) {
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
+ array_init(&library_collections, heap_allocator());
+ add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
+ add_library_collection(str_lit("shared"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
+
Array<String> args = setup_args(arg_count, arg_ptr);
#if 1
diff --git a/src/parser.cpp b/src/parser.cpp
index e335888b8..e9e829457 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -4796,6 +4796,54 @@ bool is_import_path_valid(String path) {
return false;
}
+bool determine_path_from_string(Parser *p, AstNode *node, String base_dir, String original_string, String *path) {
+ GB_ASSERT(path != nullptr);
+
+ gbAllocator a = heap_allocator();
+ String collection_name = {};
+
+ isize colon_pos = -1;
+ for (isize j = 0; j < original_string.len; j++) {
+ if (original_string[j] == ':') {
+ colon_pos = j;
+ break;
+ }
+ }
+
+ String file_str = {};
+ if (colon_pos == 0) {
+ syntax_error(node, "Expected a collection name");
+ return false;
+ }
+
+ if (original_string.len > 0 && colon_pos > 0) {
+ collection_name = substring(original_string, 0, colon_pos);
+ file_str = substring(original_string, colon_pos+1, original_string.len);
+ } else {
+ file_str = original_string;
+ }
+
+ if (!is_import_path_valid(file_str)) {
+ syntax_error(node, "Invalid import path: `%.*s`", LIT(file_str));
+ return false;
+ }
+
+ gb_mutex_lock(&p->file_decl_mutex);
+ defer (gb_mutex_unlock(&p->file_decl_mutex));
+
+ if (collection_name.len > 0) {
+ if (!find_library_collection_path(collection_name, &base_dir)) {
+ // NOTE(bill): It's a naughty name
+ syntax_error(node, "Unknown library colleciton: `%.*s`", LIT(base_dir));
+ return false;
+ }
+ }
+ String fullpath = string_trim_whitespace(get_fullpath_relative(a, base_dir, file_str));
+ *path = fullpath;
+
+ return true;
+}
+
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNode *> decls) {
for_array(i, decls) {
AstNode *node = decls[i];
@@ -4803,73 +4851,38 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNod
node->kind != AstNode_BadStmt &&
node->kind != AstNode_EmptyStmt) {
// NOTE(bill): Sanity check
- syntax_error(node, "Only declarations are allowed at file scope %.*s", LIT(ast_node_strings[node->kind]));
+ syntax_error(node, "Only declarations are allowed at file scope, got %.*s", LIT(ast_node_strings[node->kind]));
} else if (node->kind == AstNode_ImportDecl) {
ast_node(id, ImportDecl, node);
- String collection_name = {};
- String oirignal_string = id->relpath.string;
- String file_str = id->relpath.string;
- gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
- String import_file = {};
- String rel_path = {};
- if (!is_import_path_valid(file_str)) {
- syntax_error(node, "Invalid import path: `%.*s`", LIT(file_str));
- // NOTE(bill): It's a naughty name
+ String original_string = id->relpath.string;
+ String import_path = {};
+ bool ok = determine_path_from_string(p, node, base_dir, original_string, &import_path);
+ if (!ok) {
decls[i] = ast_bad_decl(f, id->relpath, id->relpath);
continue;
}
- gb_mutex_lock(&p->file_decl_mutex);
- defer (gb_mutex_unlock(&p->file_decl_mutex));
-
- rel_path = get_fullpath_relative(a, base_dir, file_str);
- 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(a, file_str);
- if (gb_file_exists(cast(char *)abs_path.text)) {
- import_file = abs_path;
- }
- }
-
- import_file = string_trim_whitespace(import_file);
-
- id->fullpath = import_file;
- try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
+ id->fullpath = import_path;
+ try_add_import_path(p, import_path, original_string, ast_node_token(node).pos);
} else if (node->kind == AstNode_ExportDecl) {
ast_node(ed, ExportDecl, node);
- String collection_name = {};
- String oirignal_string = ed->relpath.string;
- String file_str = ed->relpath.string;
- gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
- String export_path = {};
- String rel_path = {};
- if (!is_import_path_valid(file_str)) {
- syntax_error(node, "Invalid export path: `%.*s`", LIT(file_str));
- // NOTE(bill): It's a naughty name
+ String original_string = ed->relpath.string;
+ String export_path = {};
+ bool ok = determine_path_from_string(p, node, base_dir, original_string, &export_path);
+ if (!ok) {
decls[i] = ast_bad_decl(f, ed->relpath, ed->relpath);
continue;
}
- gb_mutex_lock(&p->file_decl_mutex);
- defer (gb_mutex_unlock(&p->file_decl_mutex));
-
- rel_path = get_fullpath_relative(a, base_dir, file_str);
- export_path = rel_path;
- if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
- String abs_path = get_fullpath_core(a, file_str);
- if (gb_file_exists(cast(char *)abs_path.text)) {
- export_path = abs_path;
- }
- }
-
export_path = string_trim_whitespace(export_path);
ed->fullpath = export_path;
- try_add_import_path(p, export_path, file_str, ast_node_token(node).pos);
+ try_add_import_path(p, export_path, original_string, ast_node_token(node).pos);
} else if (node->kind == AstNode_ForeignLibraryDecl) {
ast_node(fl, ForeignLibraryDecl, node);
+
String file_str = fl->filepath.string;
if (!is_import_path_valid(file_str)) {
syntax_error(node, "Invalid `%.*s` path", LIT(fl->token.string));
diff --git a/src/string.cpp b/src/string.cpp
index 397f41063..8e6006c46 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -16,11 +16,11 @@ struct String {
isize len;
u8 &operator[](isize i) {
- GB_ASSERT(0 <= i && i < len);
+ GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
u8 const &operator[](isize i) const {
- GB_ASSERT(0 <= i && i < len);
+ GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
};
@@ -38,11 +38,11 @@ struct String16 {
wchar_t *text;
isize len;
wchar_t &operator[](isize i) {
- GB_ASSERT(0 <= i && i < len);
+ GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
wchar_t const &operator[](isize i) const {
- GB_ASSERT(0 <= i && i < len);
+ GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
};
@@ -284,6 +284,21 @@ String remove_directory_from_path(String s) {
}
+String concatenate_strings(gbAllocator a, String x, String y) {
+ isize len = x.len+y.len;
+ u8 *data = gb_alloc_array(a, u8, len+1);
+ gb_memmove(data, x.text, x.len);
+ gb_memmove(data+x.len, y.text, y.len);
+ data[len] = 0;
+ return make_string(data, len);
+}
+
+String copy_string(gbAllocator a, String s) {
+ u8 *data = gb_alloc_array(a, u8, s.len+1);
+ gb_memmove(data, s.text, s.len);
+ data[s.len] = 0;
+ return make_string(data, s.len);
+}