Procházet zdrojové kódy

Merging from gingerBill's master

Zachary Pierson před 8 roky
rodič
revize
c50aabd916
12 změnil soubory, kde provedl 163 přidání a 170 odebrání
  1. 1 3
      README.md
  2. 1 1
      build.bat
  3. 69 36
      code/demo.odin
  4. 1 1
      core/_preload.odin
  5. 1 1
      core/opengl.odin
  6. 1 2
      core/os.odin
  7. 0 20
      src/build.c
  8. 8 20
      src/check_expr.c
  9. 13 18
      src/checker.c
  10. 16 1
      src/entity.c
  11. 20 23
      src/parser.c
  12. 32 44
      src/tokenizer.c

+ 1 - 3
README.md

@@ -47,7 +47,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
@@ -57,10 +57,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

+ 1 - 1
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

+ 69 - 36
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
 	}
 }
-}
 

+ 1 - 1
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);

+ 1 - 1
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";

+ 1 - 2
core/os.odin

@@ -1,4 +1,3 @@
 #include "os_windows.odin" when ODIN_OS == "windows";
 #include "os_x.odin" when ODIN_OS == "osx";
-#include "os_linux.odin" when ODIN_OS == "linux";
-
+#include "os_linux.odin" when ODIN_OS == "linux";

+ 0 - 20
src/build.c

@@ -268,26 +268,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);
-}
 
 
 

+ 8 - 20
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
-			}
 		}
 	}
 

+ 13 - 18
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
@@ -1699,7 +1699,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;
@@ -1711,24 +1711,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 {

+ 16 - 1
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;

+ 20 - 23
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;

+ 32 - 44
src/tokenizer.c

@@ -30,11 +30,6 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
 	TOKEN_KIND(Token_AndNot,   "&~"), \
 	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, "")