aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--build.bat2
-rw-r--r--code/demo.odin105
-rw-r--r--core/_preload.odin2
-rw-r--r--core/opengl.odin2
-rw-r--r--core/os.odin4
-rw-r--r--src/build.c20
-rw-r--r--src/check_expr.c28
-rw-r--r--src/checker.c31
-rw-r--r--src/entity.c17
-rw-r--r--src/parser.c43
-rw-r--r--src/tokenizer.c76
12 files changed, 164 insertions, 170 deletions
diff --git a/README.md b/README.md
index 7e717e18e..b32d61eb3 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
## Roadmap
-Not in any particular order
+Not in any particular order and not be implemented
* Compile Time Execution (CTE)
- More metaprogramming madness
@@ -45,10 +45,8 @@ Not in any particular order
* Replace LLVM backend with my own custom backend
* Improve SSA design to accommodate for lowering to a "bytecode"
* SSA optimizations
-* Parametric Polymorphism ("Generics")
* Documentation Generator for "Entities"
* Multiple Architecture support
-* Language level atomics and concurrency support
* Debug Information
- pdb format too
* Command Line Tooling
diff --git a/build.bat b/build.bat
index bddb6ebf1..bf007f574 100644
--- a/build.bat
+++ b/build.bat
@@ -4,7 +4,7 @@
set exe_name=odin.exe
:: Debug = 0, Release = 1
-set release_mode=0
+set release_mode=1
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug
diff --git a/code/demo.odin b/code/demo.odin
index 401853f1d..b95ae52af 100644
--- a/code/demo.odin
+++ b/code/demo.odin
@@ -1,15 +1,41 @@
-#import . "fmt.odin";
-#import "atomic.odin";
-#import "hash.odin";
-#import "math.odin";
-#import "mem.odin";
-#import "opengl.odin";
-#import "os.odin";
-#import "sync.odin";
-#import "types.odin";
-#import "utf8.odin";
+#import "fmt.odin";
main :: proc() {
+/*
+ Version 0.1.0
+
+ Added:
+ * Dynamic Arrays `[...]Type`
+ * Dynamic Maps `map[Key]Value`
+ * Dynamic array and map literals
+ * Custom struct alignemnt `struct #align 8 { bar: i8 }`
+ * Allow `_` in numbers
+ * Variadic `append`
+ * fmt.sprint*
+ * Entities prefixes with an underscore do not get exported on imports
+ * Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
+ * enum types have an implict `names` field, a []string of all the names in that enum
+
+ Removed:
+ * Maybe/option types
+ * immutable variables
+ * Remove `type` keyword and other "reserved" keywords
+ * `compile_assert` and `assert`return the value of the condition for semantic reasons
+
+ Changed:
+ * thread_local -> #thread_local
+ * #include -> #load
+ * Files only get checked if they are actually used
+ * match x in y {} // For type match statements
+ * Version numbering now starts from 0.1.0 and uses the convention:
+ - major.minor.patch
+
+ Fixes:
+ * Many fmt.* fixes
+
+ To come very Soon™:
+ * Linux and OS X builds (unofficial ones do exist already)
+*/
{
Fruit :: enum {
@@ -17,10 +43,9 @@ main :: proc() {
BANANA,
COCONUT,
}
- println(x, Fruit.names);
+ fmt.println(Fruit.names);
}
-when false {
{
m: map[f32]int;
reserve(m, 16);
@@ -33,16 +58,16 @@ when false {
c := m[3.0];
assert(ok && c == 564);
- print("map[");
+ fmt.print("map[");
i := 0;
for val, key in m {
if i > 0 {
- print(", ");
+ fmt.print(", ");
}
- printf("%v=%v", key, val);
+ fmt.printf("%v=%v", key, val);
i += 1;
}
- println("]");
+ fmt.println("]");
}
{
m := map[string]u32{
@@ -56,39 +81,47 @@ when false {
_, ok := m["c"];
assert(ok && c == 7654);
- println(m);
+ fmt.println(m);
}
{
- println("Hellope!");
-
- x: [dynamic]f64;
+ x: [...]f64;
reserve(x, 16);
defer free(x);
append(x, 2_000_000.500_000, 3, 5, 7);
for p, i in x {
- if i > 0 { print(", "); }
- print(p);
+ if i > 0 { fmt.print(", "); }
+ fmt.print(p);
}
- println();
+ fmt.println();
+ }
+
+ {
+ x := [...]f64{2_000_000.500_000, 3, 5, 7};
+ defer free(x);
+ fmt.println(x);
+ }
+
- {
- Vec3 :: [vector 3]f32;
+ {
+ Vec3 :: [vector 3]f32;
- x := Vec3{1, 2, 3};
- y := Vec3{4, 5, 6};
- println(x < y);
- println(x + y);
- println(x - y);
- println(x * y);
- println(x / y);
+ x := Vec3{1, 2, 3};
+ y := Vec3{4, 5, 6};
+ fmt.println(x < y);
+ fmt.println(x + y);
+ fmt.println(x - y);
+ fmt.println(x * y);
+ fmt.println(x / y);
- for i in x {
- println(i);
- }
+ for i in x {
+ fmt.println(i);
}
+
+ compile_assert(size_of([vector 7]bool) == size_of([7]bool));
+ compile_assert(size_of([vector 7]i32) == size_of([7]i32));
+ // align_of([vector 7]i32) != align_of([7]i32) // this may be the case
}
}
-}
diff --git a/core/_preload.odin b/core/_preload.odin
index 8924bf87c..a2c1ebe3d 100644
--- a/core/_preload.odin
+++ b/core/_preload.odin
@@ -169,7 +169,7 @@ Context :: struct #ordered {
user_index: int,
}
-thread_local __context: Context;
+#thread_local __context: Context;
DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
diff --git a/core/opengl.odin b/core/opengl.odin
index 44ebc26c5..e76e63f06 100644
--- a/core/opengl.odin
+++ b/core/opengl.odin
@@ -1,6 +1,6 @@
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
-#include "opengl_constants.odin";
+#load "opengl_constants.odin";
Clear :: proc(mask: u32) #foreign lib "glClear";
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
diff --git a/core/os.odin b/core/os.odin
index 0ce897bd7..d10b08bd2 100644
--- a/core/os.odin
+++ b/core/os.odin
@@ -1,3 +1,3 @@
-#include "os_windows.odin" when ODIN_OS == "windows";
-#include "os_x.odin" when ODIN_OS == "osx";
+#load "os_windows.odin" when ODIN_OS == "windows";
+#load "os_x.odin" when ODIN_OS == "osx";
diff --git a/src/build.c b/src/build.c
index 3afc05047..cb4b96f91 100644
--- a/src/build.c
+++ b/src/build.c
@@ -213,26 +213,6 @@ String get_fullpath_core(gbAllocator a, String path) {
return res;
}
-String get_filepath_extension(String path) {
- isize dot = 0;
- bool 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 str_lit("");
- }
-
- dot = i;
- break;
- }
- }
- return make_string(path.text, dot);
-}
diff --git a/src/check_expr.c b/src/check_expr.c
index a6a07b140..de494a9cd 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -2532,7 +2532,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
}
if (op_expr->kind == AstNode_Ident) {
- b32 is_not_exported = true;
String name = op_expr->Ident.string;
Entity *e = scope_lookup_entity(c->context.scope, name);
@@ -2576,14 +2575,19 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
}
}
-
- is_not_exported = !is_entity_name_exported(entity);
+ bool implicit_is_found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL;
+ bool is_not_exported = !is_entity_exported(entity);
+ if (!implicit_is_found) {
+ is_not_exported = false;
+ } else if (entity->kind == Entity_ImportName) {
+ is_not_exported = true;
+ }
if (is_not_exported) {
gbString sel_str = expr_to_string(selector);
error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
gb_string_free(sel_str);
- // NOTE(bill): We will have to cause an error his even though it exists
+ // NOTE(bill): Not really an error so don't goto error
goto error;
}
@@ -2629,22 +2633,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
return procs[0];
}
}
-
- bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity));
- if (!found) {
- is_not_exported = false;
- } else {
- if (entity->kind == Entity_ImportName) {
- is_not_exported = true;
- }
- }
-
- if (is_not_exported) {
- gbString sel_str = expr_to_string(selector);
- error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
- gb_string_free(sel_str);
- // NOTE(bill): Not really an error so don't goto error
- }
}
}
diff --git a/src/checker.c b/src/checker.c
index 7f1d74f0d..657df6f57 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -1470,7 +1470,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
if (id->is_import) {
error_node(decl, "#import declarations are only allowed in the file scope");
} else {
- error_node(decl, "#include declarations are only allowed in the file scope");
+ error_node(decl, "#load declarations are only allowed in the file scope");
}
// NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't
@@ -1686,7 +1686,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (!previously_added) {
array_add(&parent_scope->imported, scope);
} else {
- warning(token, "Multiple #import of the same file within this scope");
+ warning(token, "Multiple import of the same file within this scope");
}
scope->has_been_imported = true;
@@ -1698,24 +1698,19 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (e->scope == parent_scope) {
continue;
}
- switch (e->kind) {
- case Entity_ImportName:
- case Entity_LibraryName:
- break;
- default: {
-
- if (id->is_import) {
- if (is_entity_name_exported(e)) {
- // TODO(bill): Should these entities be imported but cause an error when used?
- bool ok = add_entity(c, parent_scope, NULL, e);
- if (ok) {
- map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
- }
+ if (!is_entity_kind_exported(e->kind)) {
+ continue;
+ }
+ if (id->is_import) {
+ if (is_entity_exported(e)) {
+ // TODO(bill): Should these entities be imported but cause an error when used?
+ bool ok = add_entity(c, parent_scope, NULL, e);
+ if (ok) {
+ map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
}
- } else {
- /* bool ok = */add_entity(c, parent_scope, NULL, e);
}
- } break;
+ } else {
+ add_entity(c, parent_scope, NULL, e);
}
}
} else {
diff --git a/src/entity.c b/src/entity.c
index b571f98e6..04ef323a1 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -98,8 +98,23 @@ struct Entity {
gb_global Entity *e_context = NULL;
-bool is_entity_name_exported(Entity *e) {
+bool is_entity_kind_exported(EntityKind kind) {
+ switch (kind) {
+ case Entity_Builtin:
+ case Entity_ImportName:
+ case Entity_LibraryName:
+ case Entity_Nil:
+ return false;
+ }
+ return true;
+}
+
+bool is_entity_exported(Entity *e) {
GB_ASSERT(e != NULL);
+ if (!is_entity_kind_exported(e->kind)) {
+ return false;
+ }
+
String name = e->token.string;
if (name.len == 0) {
return false;
diff --git a/src/parser.c b/src/parser.c
index b4902982c..085aade38 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1232,7 +1232,7 @@ void fix_advance_to_next_stmt(AstFile *f) {
case Token_defer:
case Token_asm:
case Token_using:
- case Token_thread_local:
+ // case Token_thread_local:
case Token_no_alias:
// case Token_immutable:
@@ -3294,25 +3294,6 @@ AstNode *parse_stmt(AstFile *f) {
} break;
#endif
- case Token_thread_local: {
- Token token = expect_token(f, Token_thread_local);
- AstNode *node = parse_stmt(f);
-
- if (node->kind == AstNode_ValueDecl) {
- if (!node->ValueDecl.is_var) {
- syntax_error(token, "`thread_local` may not be applied to constant declarations");
- }
- if (f->curr_proc != NULL) {
- syntax_error(token, "`thread_local` is only allowed at the file scope");
- } else {
- node->ValueDecl.flags |= VarDeclFlag_thread_local;
- }
- return node;
- }
- syntax_error(token, "`thread_local` may only be applied to a variable declaration");
- return ast_bad_stmt(f, token, f->curr_token);
- }
-
case Token_push_allocator: {
next_token(f);
isize prev_level = f->expr_level;
@@ -3378,9 +3359,9 @@ AstNode *parse_stmt(AstFile *f) {
}
expect_semicolon(f, decl);
return decl;
- } else if (str_eq(tag, str_lit("include"))) {
+ } else if (str_eq(tag, str_lit("load"))) {
AstNode *cond = NULL;
- Token file_path = expect_token_after(f, Token_String, "#include");
+ Token file_path = expect_token_after(f, Token_String, "#load");
Token import_name = file_path;
import_name.string = str_lit(".");
@@ -3390,7 +3371,7 @@ AstNode *parse_stmt(AstFile *f) {
AstNode *decl = NULL;
if (f->curr_proc != NULL) {
- syntax_error(import_name, "You cannot use `#include` within a procedure. This must be done at the file scope");
+ syntax_error(import_name, "You cannot use `#load` within a procedure. This must be done at the file scope");
decl = ast_bad_decl(f, import_name, file_path);
} else {
decl = ast_import_decl(f, hash_token, false, file_path, import_name, cond);
@@ -3469,6 +3450,22 @@ AstNode *parse_stmt(AstFile *f) {
}
expect_semicolon(f, s);
return s;
+ } else if (str_eq(tag, str_lit("thread_local"))) {
+ AstNode *s = parse_stmt(f);
+
+ if (s->kind == AstNode_ValueDecl) {
+ if (!s->ValueDecl.is_var) {
+ syntax_error(token, "`thread_local` may not be applied to constant declarations");
+ }
+ if (f->curr_proc != NULL) {
+ syntax_error(token, "`thread_local` is only allowed at the file scope");
+ } else {
+ s->ValueDecl.flags |= VarDeclFlag_thread_local;
+ }
+ return s;
+ }
+ syntax_error(token, "`thread_local` may only be applied to a variable declaration");
+ return ast_bad_stmt(f, token, f->curr_token);
} else if (str_eq(tag, str_lit("bounds_check"))) {
s = parse_stmt(f);
s->stmt_state_flags |= StmtStateFlag_bounds_check;
diff --git a/src/tokenizer.c b/src/tokenizer.c
index 766e8b912..f2cabfb02 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -31,11 +31,6 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_Shl, "<<"), \
TOKEN_KIND(Token_Shr, ">>"), \
\
- /*TOKEN_KIND(Token_as, "as"), */\
- /*TOKEN_KIND(Token_transmute, "transmute"), */\
- /*TOKEN_KIND(Token_down_cast, "down_cast"), */\
- /*TOKEN_KIND(Token_union_cast, "union_cast"), */\
-\
TOKEN_KIND(Token_CmpAnd, "&&"), \
TOKEN_KIND(Token_CmpOr, "||"), \
\
@@ -83,45 +78,38 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
- /* TODO(bill): Of these keywords are not used but "reserved", why not remove them? */ \
- TOKEN_KIND(Token_when, "when"), \
- TOKEN_KIND(Token_if, "if"), \
- TOKEN_KIND(Token_else, "else"), \
- TOKEN_KIND(Token_for, "for"), \
- TOKEN_KIND(Token_in, "in"), \
- TOKEN_KIND(Token_break, "break"), \
- TOKEN_KIND(Token_continue, "continue"), \
- TOKEN_KIND(Token_fallthrough, "fallthrough"), \
- TOKEN_KIND(Token_match, "match"), \
- /* TOKEN_KIND(Token_type, "type"), */ \
- TOKEN_KIND(Token_default, "default"), \
- TOKEN_KIND(Token_case, "case"), \
- TOKEN_KIND(Token_defer, "defer"), \
- TOKEN_KIND(Token_return, "return"), \
- TOKEN_KIND(Token_give, "give"), \
- TOKEN_KIND(Token_proc, "proc"), \
- TOKEN_KIND(Token_macro, "macro"), \
- TOKEN_KIND(Token_struct, "struct"), \
- TOKEN_KIND(Token_union, "union"), \
- TOKEN_KIND(Token_raw_union, "raw_union"), \
- TOKEN_KIND(Token_enum, "enum"), \
- TOKEN_KIND(Token_vector, "vector"), \
- TOKEN_KIND(Token_map, "map"), \
- /* TOKEN_KIND(Token_static, "static"), */ \
- /* TOKEN_KIND(Token_dynamic, "dynamic"), */ \
- TOKEN_KIND(Token_using, "using"), \
- TOKEN_KIND(Token_no_alias, "no_alias"), \
- /* TOKEN_KIND(Token_mutable, "mutable"), */ \
- /* TOKEN_KIND(Token_immutable, "immutable"), */ \
- TOKEN_KIND(Token_thread_local, "thread_local"), \
- TOKEN_KIND(Token_cast, "cast"), \
- TOKEN_KIND(Token_transmute, "transmute"), \
- TOKEN_KIND(Token_down_cast, "down_cast"), \
- TOKEN_KIND(Token_union_cast, "union_cast"), \
- TOKEN_KIND(Token_context, "context"), \
- TOKEN_KIND(Token_push_context, "push_context"), \
- TOKEN_KIND(Token_push_allocator, "push_allocator"), \
- TOKEN_KIND(Token_asm, "asm"), \
+ TOKEN_KIND(Token_when, "when"), \
+ TOKEN_KIND(Token_if, "if"), \
+ TOKEN_KIND(Token_else, "else"), \
+ TOKEN_KIND(Token_for, "for"), \
+ TOKEN_KIND(Token_in, "in"), \
+ TOKEN_KIND(Token_match, "match"), \
+ TOKEN_KIND(Token_default, "default"), \
+ TOKEN_KIND(Token_case, "case"), \
+ TOKEN_KIND(Token_break, "break"), \
+ TOKEN_KIND(Token_continue, "continue"), \
+ TOKEN_KIND(Token_fallthrough, "fallthrough"), \
+ TOKEN_KIND(Token_defer, "defer"), \
+ TOKEN_KIND(Token_return, "return"), \
+ TOKEN_KIND(Token_give, "give"), \
+ TOKEN_KIND(Token_proc, "proc"), \
+ TOKEN_KIND(Token_macro, "macro"), \
+ TOKEN_KIND(Token_struct, "struct"), \
+ TOKEN_KIND(Token_union, "union"), \
+ TOKEN_KIND(Token_raw_union, "raw_union"), \
+ TOKEN_KIND(Token_enum, "enum"), \
+ TOKEN_KIND(Token_vector, "vector"), \
+ TOKEN_KIND(Token_map, "map"), \
+ TOKEN_KIND(Token_using, "using"), \
+ TOKEN_KIND(Token_no_alias, "no_alias"), \
+ TOKEN_KIND(Token_cast, "cast"), \
+ TOKEN_KIND(Token_transmute, "transmute"), \
+ TOKEN_KIND(Token_down_cast, "down_cast"), \
+ TOKEN_KIND(Token_union_cast, "union_cast"), \
+ TOKEN_KIND(Token_context, "context"), \
+ TOKEN_KIND(Token_push_context, "push_context"), \
+ TOKEN_KIND(Token_push_allocator, "push_allocator"), \
+ TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "")