Browse Source

Remove () grouping for `foreign_library`

Ginger Bill 8 years ago
parent
commit
2d20bde495
12 changed files with 133 additions and 370 deletions
  1. 1 1
      build.bat
  2. 1 1
      core/atomics.odin
  3. 3 4
      core/opengl.odin
  4. 3 4
      core/os_linux.odin
  5. 2 4
      core/os_x.odin
  6. 5 7
      core/sys/windows.odin
  7. 24 37
      src/checker.cpp
  8. 0 22
      src/docs.cpp
  9. 3 3
      src/ir.cpp
  10. 90 281
      src/parser.cpp
  11. 0 6
      src/ssa.cpp
  12. 1 0
      src/tokenizer.cpp

+ 1 - 1
build.bat

@@ -43,7 +43,7 @@ del *.ilk > NUL 2> NUL
 
 
 cl %compiler_settings% "src\main.cpp" ^
 cl %compiler_settings% "src\main.cpp" ^
 	/link %linker_settings% -OUT:%exe_name% ^
 	/link %linker_settings% -OUT:%exe_name% ^
-	&& odin run examples/punity.odin -opt=0
+	&& odin run examples/demo.odin -opt=0
 	rem && odin docs core/fmt.odin
 	rem && odin docs core/fmt.odin
 
 
 del *.obj > NUL 2> NUL
 del *.obj > NUL 2> NUL

+ 1 - 1
core/atomics.odin

@@ -2,7 +2,7 @@
 // Inline vs external file?
 // Inline vs external file?
 
 
 import win32 "sys/windows.odin" when ODIN_OS == "windows";
 import win32 "sys/windows.odin" when ODIN_OS == "windows";
-_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
+_ :: compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
 
 
 
 
 yield_thread :: proc() { win32.mm_pause(); }
 yield_thread :: proc() { win32.mm_pause(); }

+ 3 - 4
core/opengl.odin

@@ -1,7 +1,6 @@
-foreign_system_library (
-	lib "opengl32.lib" when ODIN_OS == "windows";
-	lib "gl" when ODIN_OS == "linux";
-)
+foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
+foreign_system_library lib "gl" when ODIN_OS == "linux";
+
 import win32 "sys/windows.odin" when ODIN_OS == "windows";
 import win32 "sys/windows.odin" when ODIN_OS == "windows";
 import "sys/wgl.odin"           when ODIN_OS == "windows";
 import "sys/wgl.odin"           when ODIN_OS == "windows";
 using import . "opengl_constants.odin";
 using import . "opengl_constants.odin";

+ 3 - 4
core/os_linux.odin

@@ -1,7 +1,6 @@
-foreign_system_library (
-	dl   "dl";
-	libc "c";
-)
+foreign_system_library dl   "dl";
+foreign_system_library libc "c";
+
 import "strings.odin";
 import "strings.odin";
 
 
 Handle   :: i32;
 Handle   :: i32;

+ 2 - 4
core/os_x.odin

@@ -1,7 +1,5 @@
-foreign_system_library (
-	dl   "dl";
-	libc "c";
-)
+foreign_system_library dl   "dl";
+foreign_system_library libc "c";
 
 
 import "strings.odin";
 import "strings.odin";
 
 

+ 5 - 7
core/sys/windows.odin

@@ -1,10 +1,8 @@
-foreign_system_library (
-	"kernel32.lib" when ODIN_OS == "windows";
-	"user32.lib"   when ODIN_OS == "windows";
-	"gdi32.lib"    when ODIN_OS == "windows";
-	"winmm.lib"    when ODIN_OS == "windows";
-	"shell32.lib"  when ODIN_OS == "windows";
-)
+foreign_system_library "kernel32.lib" when ODIN_OS == "windows";
+foreign_system_library "user32.lib"   when ODIN_OS == "windows";
+foreign_system_library "gdi32.lib"    when ODIN_OS == "windows";
+foreign_system_library "winmm.lib"    when ODIN_OS == "windows";
+foreign_system_library "shell32.lib"  when ODIN_OS == "windows";
 
 
 Handle    :: rawptr;
 Handle    :: rawptr;
 Hwnd      :: Handle;
 Hwnd      :: Handle;

+ 24 - 37
src/checker.cpp

@@ -1953,42 +1953,29 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
 			array_add(&c->delayed_imports, di);
 			array_add(&c->delayed_imports, di);
 		case_end;
 		case_end;
 
 
-		case_ast_node(gd, GenDecl, decl);
-			for_array(i, gd->specs) {
-				AstNode *spec = gd->specs[i];
-				switch (gd->token.kind) {
-				case Token_foreign_library:
-				case Token_foreign_system_library:  {
-					ast_node(fl, ForeignLibrarySpec, spec);
-					if (!c->context.scope->is_file) {
-						if (fl->is_system) {
-							error(spec, "foreign_system_library declarations are only allowed in the file scope");
-						} else {
-							error(spec, "foreign_library 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
-						continue;
-					}
-
-					if (fl->cond != nullptr) {
-						Operand operand = {Addressing_Invalid};
-						check_expr(c, &operand, fl->cond);
-						if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
-							error(fl->cond, "Non-constant boolean `when` condition");
-							continue;
-						}
-						if (operand.value.kind == ExactValue_Bool &&
-							!operand.value.value_bool) {
-							continue;
-						}
-					}
+		case_ast_node(fl, ForeignLibraryDecl, decl);
+			if (!c->context.scope->is_file) {
+				error(decl, "%.*s declarations are only allowed in the file scope", LIT(fl->token.string));
+				// NOTE(bill): _Should_ be caught by the parser
+				// TODO(bill): Better error handling if it isn't
+				continue;
+			}
 
 
-					DelayedDecl di = {c->context.scope, spec};
-					array_add(&c->delayed_foreign_libraries, di);
-				} break;
+			if (fl->cond != nullptr) {
+				Operand operand = {Addressing_Invalid};
+				check_expr(c, &operand, fl->cond);
+				if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
+					error(fl->cond, "Non-constant boolean `when` condition");
+					continue;
+				}
+				if (operand.value.kind == ExactValue_Bool &&
+					!operand.value.value_bool) {
+					continue;
 				}
 				}
 			}
 			}
+
+			DelayedDecl di = {c->context.scope, decl};
+			array_add(&c->delayed_foreign_libraries, di);
 		case_end;
 		case_end;
 
 
 		case_ast_node(fb, ForeignBlockDecl, decl);
 		case_ast_node(fb, ForeignBlockDecl, decl);
@@ -2533,13 +2520,13 @@ void check_import_entities(Checker *c, Map<Scope *> *file_scopes) {
 
 
 	for_array(i, c->delayed_foreign_libraries) {
 	for_array(i, c->delayed_foreign_libraries) {
 		Scope *parent_scope = c->delayed_foreign_libraries[i].parent;
 		Scope *parent_scope = c->delayed_foreign_libraries[i].parent;
-		AstNode *spec = c->delayed_foreign_libraries[i].decl;
-		ast_node(fl, ForeignLibrarySpec, spec);
+		AstNode *decl = c->delayed_foreign_libraries[i].decl;
+		ast_node(fl, ForeignLibraryDecl, decl);
 
 
 		String file_str = fl->filepath.string;
 		String file_str = fl->filepath.string;
 		String base_dir = fl->base_dir;
 		String base_dir = fl->base_dir;
 
 
-		if (!fl->is_system) {
+		if (fl->token.kind == Token_foreign_library) {
 			gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
 			gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
 
 
 			String rel_path = get_fullpath_relative(a, base_dir, file_str);
 			String rel_path = get_fullpath_relative(a, base_dir, file_str);
@@ -2569,7 +2556,7 @@ void check_import_entities(Checker *c, Map<Scope *> *file_scopes) {
 
 
 		String library_name = path_to_entity_name(fl->library_name.string, file_str);
 		String library_name = path_to_entity_name(fl->library_name.string, file_str);
 		if (is_blank_ident(library_name)) {
 		if (is_blank_ident(library_name)) {
-			error(spec, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
+			error(decl, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
 		} else {
 		} else {
 			GB_ASSERT(fl->library_name.pos.line != 0);
 			GB_ASSERT(fl->library_name.pos.line != 0);
 			fl->library_name.string = library_name;
 			fl->library_name.string = library_name;

+ 0 - 22
src/docs.cpp

@@ -90,28 +90,6 @@ void print_proc_decl(AstNodeProcDecl *pd) {
 }
 }
 #endif
 #endif
 void print_declaration(AstNode *decl) {
 void print_declaration(AstNode *decl) {
-	switch (decl->kind) {
-	case_ast_node(gd, GenDecl, decl);
-		for_array(spec_index, gd->specs) {
-			AstNode *spec = gd->specs[spec_index];
-			switch(gd->token.kind) {
-			case Token_import:
-				break;
-			case Token_foreign_library:
-			case Token_foreign_system_library:
-				break;
-			}
-		}
-	case_end;
-
-	// case_ast_node(pd, ProcDecl, decl);
-	// 	print_proc_decl(pd);
-	// case_end;
-
-	case_ast_node(fb, ForeignBlockDecl, decl);
-		// TODO(bill)
-	case_end;
-	}
 }
 }
 
 
 void generate_documentation(Parser *parser) {
 void generate_documentation(Parser *parser) {

+ 3 - 3
src/ir.cpp

@@ -6227,9 +6227,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 	case_ast_node(us, UsingStmt, node);
 	case_ast_node(us, UsingStmt, node);
 		for_array(i, us->list) {
 		for_array(i, us->list) {
 			AstNode *decl = unparen_expr(us->list[i]);
 			AstNode *decl = unparen_expr(us->list[i]);
-			if (decl->kind == AstNode_GenDecl) {
-				ir_build_stmt(proc, decl);
-			}
+			// if (decl->kind == AstNode_GenDecl) {
+				// ir_build_stmt(proc, decl);
+			// }
 		}
 		}
 	case_end;
 	case_end;
 
 

+ 90 - 281
src/parser.cpp

@@ -335,14 +335,6 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		Token token; \
 		Token token; \
 		AstNode *name; \
 		AstNode *name; \
 	}) \
 	}) \
-	AST_NODE_KIND(GenDecl, "generic declaration", struct { \
-		Token            token; \
-		Token            open;  \
-		Token            close; \
-		Array<AstNode *> specs; \
-		u64              flags; \
-		CommentGroup docs; \
-	}) \
 	AST_NODE_KIND(ValueDecl, "value declaration", struct { \
 	AST_NODE_KIND(ValueDecl, "value declaration", struct { \
 		Array<AstNode *> names;      \
 		Array<AstNode *> names;      \
 		AstNode *        type;       \
 		AstNode *        type;       \
@@ -362,12 +354,12 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		CommentGroup docs;      \
 		CommentGroup docs;      \
 		CommentGroup comment;   \
 		CommentGroup comment;   \
 	}) \
 	}) \
-	AST_NODE_KIND(ForeignLibrarySpec, "foreign library specification", struct { \
+	AST_NODE_KIND(ForeignLibraryDecl, "foreign library declaration", struct { \
+		Token    token;         \
 		Token    filepath;      \
 		Token    filepath;      \
 		Token    library_name;  \
 		Token    library_name;  \
 		String   base_dir;      \
 		String   base_dir;      \
 		AstNode *cond;          \
 		AstNode *cond;          \
-		bool     is_system;     \
 		CommentGroup docs;      \
 		CommentGroup docs;      \
 		CommentGroup comment;   \
 		CommentGroup comment;   \
 	}) \
 	}) \
@@ -578,12 +570,11 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_PushContext:   return node->PushContext.token;
 	case AstNode_PushContext:   return node->PushContext.token;
 
 
 	case AstNode_BadDecl:            return node->BadDecl.begin;
 	case AstNode_BadDecl:            return node->BadDecl.begin;
-	case AstNode_ForeignLibrarySpec: return node->ForeignLibrarySpec.filepath;
 	case AstNode_Label:              return node->Label.token;
 	case AstNode_Label:              return node->Label.token;
 
 
-	case AstNode_GenDecl:            return node->GenDecl.token;
 	case AstNode_ValueDecl:          return ast_node_token(node->ValueDecl.names[0]);
 	case AstNode_ValueDecl:          return ast_node_token(node->ValueDecl.names[0]);
 	case AstNode_ImportDecl:         return node->ImportDecl.token;
 	case AstNode_ImportDecl:         return node->ImportDecl.token;
+	case AstNode_ForeignLibraryDecl: return node->ForeignLibraryDecl.token;
 
 
 	case AstNode_ForeignBlockDecl:   return node->ForeignBlockDecl.token;
 	case AstNode_ForeignBlockDecl:   return node->ForeignBlockDecl.token;
 
 
@@ -822,16 +813,13 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
 	case AstNode_Label:
 	case AstNode_Label:
 		n->Label.name = clone_ast_node(a, n->Label.name);
 		n->Label.name = clone_ast_node(a, n->Label.name);
 		break;
 		break;
-	case AstNode_GenDecl:
-		n->GenDecl.specs = clone_ast_node_array(a, n->GenDecl.specs);
-		break;
 	case AstNode_ValueDecl:
 	case AstNode_ValueDecl:
 		n->ValueDecl.names  = clone_ast_node_array(a, n->ValueDecl.names);
 		n->ValueDecl.names  = clone_ast_node_array(a, n->ValueDecl.names);
 		n->ValueDecl.type   = clone_ast_node(a, n->ValueDecl.type);
 		n->ValueDecl.type   = clone_ast_node(a, n->ValueDecl.type);
 		n->ValueDecl.values = clone_ast_node_array(a, n->ValueDecl.values);
 		n->ValueDecl.values = clone_ast_node_array(a, n->ValueDecl.values);
 		break;
 		break;
-	case AstNode_ForeignLibrarySpec:
-		n->ForeignLibrarySpec.cond = clone_ast_node(a, n->ForeignLibrarySpec.cond);
+	case AstNode_ForeignLibraryDecl:
+		n->ForeignLibraryDecl.cond = clone_ast_node(a, n->ForeignLibraryDecl.cond);
 		break;
 		break;
 
 
 	case AstNode_Field:
 	case AstNode_Field:
@@ -1526,16 +1514,6 @@ AstNode *ast_label_decl(AstFile *f, Token token, AstNode *name) {
 	return result;
 	return result;
 }
 }
 
 
-AstNode *ast_gen_decl(AstFile *f, Token token, Token open, Token close, Array<AstNode *> specs, CommentGroup docs) {
-	AstNode *result = make_ast_node(f, AstNode_GenDecl);
-	result->GenDecl.token = token;
-	result->GenDecl.open  = open;
-	result->GenDecl.close = close;
-	result->GenDecl.specs = specs;
-	result->GenDecl.docs = docs;
-	return result;
-}
-
 AstNode *ast_value_decl(AstFile *f, Array<AstNode *> names, AstNode *type, Array<AstNode *> values, bool is_mutable,
 AstNode *ast_value_decl(AstFile *f, Array<AstNode *> names, AstNode *type, Array<AstNode *> values, bool is_mutable,
                         CommentGroup docs, CommentGroup comment) {
                         CommentGroup docs, CommentGroup comment) {
 	AstNode *result = make_ast_node(f, AstNode_ValueDecl);
 	AstNode *result = make_ast_node(f, AstNode_ValueDecl);
@@ -1561,15 +1539,15 @@ AstNode *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath,
 	return result;
 	return result;
 }
 }
 
 
-AstNode *ast_foreign_library_spec(AstFile *f, Token filepath, Token library_name, AstNode *cond, bool is_system,
+AstNode *ast_foreign_library_decl(AstFile *f, Token token, Token filepath, Token library_name, AstNode *cond,
                                   CommentGroup docs, CommentGroup comment) {
                                   CommentGroup docs, CommentGroup comment) {
-	AstNode *result = make_ast_node(f, AstNode_ForeignLibrarySpec);
-	result->ForeignLibrarySpec.filepath     = filepath;
-	result->ForeignLibrarySpec.library_name = library_name;
-	result->ForeignLibrarySpec.cond         = cond;
-	result->ForeignLibrarySpec.is_system    = is_system;
-	result->ForeignLibrarySpec.docs         = docs;
-	result->ForeignLibrarySpec.comment      = comment;
+	AstNode *result = make_ast_node(f, AstNode_ForeignLibraryDecl);
+	result->ForeignLibraryDecl.token        = token;
+	result->ForeignLibraryDecl.filepath     = filepath;
+	result->ForeignLibraryDecl.library_name = library_name;
+	result->ForeignLibraryDecl.cond         = cond;
+	result->ForeignLibraryDecl.docs         = docs;
+	result->ForeignLibraryDecl.comment      = comment;
 	return result;
 	return result;
 }
 }
 
 
@@ -1853,15 +1831,6 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
 		}
 		}
 		break;
 		break;
 
 
-	case AstNode_GenDecl:
-		if (s->GenDecl.close.pos.line != 0) {
-			return true;
-		}
-		if (s->GenDecl.specs.count == 1) {
-			return is_semicolon_optional_for_node(f, s->GenDecl.specs[0]);
-		}
-		break;
-
 	case AstNode_ForeignBlockDecl:
 	case AstNode_ForeignBlockDecl:
 		if (s->ForeignBlockDecl.close.pos.line != 0) {
 		if (s->ForeignBlockDecl.close.pos.line != 0) {
 			return true;
 			return true;
@@ -1898,18 +1867,6 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 			return;
 			return;
 		}
 		}
 		String node_string = ast_node_strings[s->kind];
 		String node_string = ast_node_strings[s->kind];
-		if (s->kind == AstNode_GenDecl) {
-			switch (s->GenDecl.token.kind) {
-			case Token_import:
-				node_string = str_lit("import declaration");
-				break;
-			case Token_foreign_library:
-			case Token_foreign_system_library:
-				node_string = str_lit("foreign library declaration");
-				break;
-			}
-		}
-
 		syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
 		syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
 		             LIT(node_string), LIT(token_strings[prev_token.kind]));
 		             LIT(node_string), LIT(token_strings[prev_token.kind]));
 	} else {
 	} else {
@@ -3025,165 +2982,6 @@ AstNode *parse_type(AstFile *f) {
 	return type;
 	return type;
 }
 }
 
 
-#define PARSE_SPEC_FUNC(name) AstNode *name(AstFile *f, CommentGroup docs, Token token)
-typedef PARSE_SPEC_FUNC(ParseSpecFunc);
-
-AstNode *parse_gen_decl(AstFile *f, Token token, ParseSpecFunc *func) {
-	Array<AstNode *> specs = {};
-	Token open = {};
-	Token close = {};
-
-	CommentGroup docs = f->lead_comment;
-
-	if (f->curr_token.kind == Token_OpenParen) {
-		specs = make_ast_node_array(f);
-		open = expect_token(f, Token_OpenParen);
-		while (f->curr_token.kind != Token_CloseParen &&
-		       f->curr_token.kind != Token_EOF) {
-			AstNode *spec = func(f, docs, token);
-			array_add(&specs, spec);
-		}
-		close = expect_token(f, Token_CloseParen);
-		if (f->curr_token.pos.line == close.pos.line ||
-		    open.pos.line == close.pos.line) {
-			expect_semicolon(f, nullptr);
-		}
-	} else {
-		specs = make_ast_node_array(f, 1);
-		AstNode *spec = func(f, docs, token);
-		array_add(&specs, spec);
-	}
-
-	if (specs.count == 0) {
-		syntax_error(token, "Empty %.*s declaration list", LIT(token_strings[token.kind]));
-	}
-
-	return ast_gen_decl(f, token, open, close, specs, docs);
-}
-
-// PARSE_SPEC_FUNC(parse_import_spec) {
-// 	AstNode *spec = nullptr;
-// 	if (token.kind == Token_import) {
-// 		AstNode *cond = nullptr;
-// 		Token import_name = {};
-
-// 		switch (f->curr_token.kind) {
-// 		case Token_Period:
-// 			import_name = advance_token(f);
-// 			import_name.kind = Token_Ident;
-// 			break;
-// 		case Token_Ident:
-// 			import_name = advance_token(f);
-// 			break;
-// 		default:
-// 			import_name.pos = f->curr_token.pos;
-// 			break;
-// 		}
-
-// 		if (is_blank_ident(import_name)) {
-// 			syntax_error(import_name, "Illegal import name: `_`");
-// 		}
-
-// 		Token file_path = expect_token_after(f, Token_String, "import");
-// 		if (allow_token(f, Token_when)) {
-// 			cond = parse_expr(f, false);
-// 		}
-
-// 		expect_semicolon(f, nullptr);
-// 		if (f->curr_proc != nullptr) {
-// 			syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope");
-// 			spec = ast_bad_decl(f, import_name, file_path);
-// 		} else {
-// 			spec = ast_import_decl(f, true, file_path, import_name, cond, docs, f->line_comment);
-// 		}
-// 	} else {
-// 		AstNode *cond = nullptr;
-// 		Token file_path = expect_token_after(f, Token_String, "import_load");
-// 		Token import_name = file_path;
-// 		import_name.string = str_lit(".");
-
-// 		if (allow_token(f, Token_when)) {
-// 			cond = parse_expr(f, false);
-// 		}
-
-// 		expect_semicolon(f, nullptr);
-// 		if (f->curr_proc != nullptr) {
-// 			syntax_error(import_name, "You cannot use `import_load` within a procedure. This must be done at the file scope");
-// 			spec = ast_bad_decl(f, import_name, file_path);
-// 		} else {
-// 			spec = ast_import_decl(f, false, file_path, import_name, cond, docs, f->line_comment);
-// 		}
-// 	}
-// 	return spec;
-// }
-
-PARSE_SPEC_FUNC(parse_foreign_library_spec) {
-	AstNode *spec = nullptr;
-	if (token.kind == Token_foreign_system_library) {
-		AstNode *cond = nullptr;
-		Token lib_name = {};
-
-		switch (f->curr_token.kind) {
-		case Token_Ident:
-			lib_name = advance_token(f);
-			break;
-		default:
-			lib_name.pos = f->curr_token.pos;
-			break;
-		}
-		if (is_blank_ident(lib_name)) {
-			syntax_error(lib_name, "Illegal foreign_library name: `_`");
-		}
-		Token file_path = expect_token(f, Token_String);
-
-		if (allow_token(f, Token_when)) {
-			cond = parse_expr(f, false);
-		}
-
-		expect_semicolon(f, nullptr);
-
-		if (f->curr_proc == nullptr) {
-			spec = ast_foreign_library_spec(f, file_path, lib_name, cond, true, docs, f->line_comment);
-		} else {
-			syntax_error(lib_name, "You cannot use foreign_system_library within a procedure. This must be done at the file scope");
-			spec = ast_bad_decl(f, lib_name, file_path);
-		}
-	} else {
-		AstNode *cond = nullptr;
-		Token lib_name = {};
-
-		switch (f->curr_token.kind) {
-		case Token_Ident:
-			lib_name = advance_token(f);
-			break;
-		default:
-			lib_name.pos = f->curr_token.pos;
-			break;
-		}
-
-		if (is_blank_ident(lib_name)) {
-			syntax_error(lib_name, "Illegal foreign_library name: `_`");
-		}
-		Token file_path = expect_token(f, Token_String);
-
-		if (allow_token(f, Token_when)) {
-			cond = parse_expr(f, false);
-		}
-
-		expect_semicolon(f, nullptr);
-
-		if (f->curr_proc == nullptr) {
-			spec = ast_foreign_library_spec(f, file_path, lib_name, cond, false, docs, f->line_comment);
-		} else {
-			syntax_error(lib_name, "You cannot use foreign_library within a procedure. This must be done at the file scope");
-			spec = ast_bad_decl(f, lib_name, file_path);
-		}
-	}
-	return spec;
-}
-
-AstNode *parse_decl(AstFile *f);
-
 void parse_foreign_block_decl(AstFile *f, Array<AstNode *> *decls) {
 void parse_foreign_block_decl(AstFile *f, Array<AstNode *> *decls) {
 	AstNode *decl = parse_stmt(f);
 	AstNode *decl = parse_stmt(f);
 	switch (decl->kind) {
 	switch (decl->kind) {
@@ -3203,55 +3001,35 @@ void parse_foreign_block_decl(AstFile *f, Array<AstNode *> *decls) {
 	}
 	}
 }
 }
 
 
-AstNode *parse_decl(AstFile *f) {
-	ParseSpecFunc *func = nullptr;
-	switch (f->curr_token.kind) {
-	// case Token_import:
-		// func = parse_import_spec;
-		// break;
-
-	case Token_foreign_library:
-	case Token_foreign_system_library:
-		func = parse_foreign_library_spec;
-		break;
+AstNode *parse_foreign_block(AstFile *f) {
+	CommentGroup docs = f->lead_comment;
+	Token token = expect_token(f, Token_foreign);
+	AstNode *foreign_library = parse_ident(f);
+	Token open = {};
+	Token close = {};
+	Array<AstNode *> decls = make_ast_node_array(f);
 
 
-	case Token_foreign: {
-		CommentGroup docs = f->lead_comment;
-		Token token = expect_token(f, Token_foreign);
-		AstNode *foreign_library = parse_ident(f);
-		Token open = {};
-		Token close = {};
-		Array<AstNode *> decls = make_ast_node_array(f);
+	bool prev_in_foreign_block = f->in_foreign_block;
+	defer (f->in_foreign_block = prev_in_foreign_block);
+	f->in_foreign_block = true;
 
 
-		bool prev_in_foreign_block = f->in_foreign_block;
-		defer (f->in_foreign_block = prev_in_foreign_block);
-		f->in_foreign_block = true;
+	if (f->curr_token.kind != Token_OpenBrace) {
+		parse_foreign_block_decl(f, &decls);
+	} else {
+		open = expect_token(f, Token_OpenBrace);
 
 
-		if (f->curr_token.kind != Token_OpenBrace) {
+		while (f->curr_token.kind != Token_CloseBrace &&
+		       f->curr_token.kind != Token_EOF) {
 			parse_foreign_block_decl(f, &decls);
 			parse_foreign_block_decl(f, &decls);
-		} else {
-			open = expect_token(f, Token_OpenBrace);
-
-			while (f->curr_token.kind != Token_CloseBrace &&
-			       f->curr_token.kind != Token_EOF) {
-				parse_foreign_block_decl(f, &decls);
-			}
-
-			close = expect_token(f, Token_CloseBrace);
 		}
 		}
 
 
-		return ast_foreign_block_decl(f, token, foreign_library, open, close, decls, docs);
-	} break;
-
-	default: {
-		Token tok = f->curr_token;
-		fix_advance_to_next_stmt(f);
-		syntax_error(tok, "Expected a declaration got %.*s", LIT(token_strings[tok.kind]));
-		return ast_bad_decl(f, tok, f->curr_token);
-	}
+		close = expect_token(f, Token_CloseBrace);
 	}
 	}
 
 
-	return parse_gen_decl(f, advance_token(f), func);
+
+	AstNode *decl = ast_foreign_block_decl(f, token, foreign_library, open, close, decls, docs);
+	expect_semicolon(f, decl);
+	return decl;
 }
 }
 
 
 AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs) {
 AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs) {
@@ -4565,6 +4343,50 @@ AstNode *parse_import_decl(AstFile *f, bool is_using) {
 	return ast_import_decl(f, token, is_using, file_path, import_name, cond, docs, f->line_comment);
 	return ast_import_decl(f, token, is_using, file_path, import_name, cond, docs, f->line_comment);
 }
 }
 
 
+AstNode *parse_foreign_decl(AstFile *f) {
+	CommentGroup docs = f->lead_comment;
+	Token token = {};
+	switch (f->curr_token.kind) {
+	case Token_foreign_library:
+	case Token_foreign_system_library:
+		token = advance_token(f);
+		break;
+	default:
+		token = advance_token(f);
+		syntax_error(token, "Expected either foreign_library or foreign_system_library, got `%.*s`", LIT(token.string));
+		return ast_bad_decl(f, token, token);
+	}
+
+	AstNode *cond = nullptr;
+	Token lib_name = {};
+
+	switch (f->curr_token.kind) {
+	case Token_Ident:
+		lib_name = advance_token(f);
+		break;
+	default:
+		lib_name.pos = f->curr_token.pos;
+		break;
+	}
+	if (is_blank_ident(lib_name)) {
+		syntax_error(lib_name, "Illegal foreign_library name: `_`");
+	}
+	Token file_path = expect_token(f, Token_String);
+
+	if (allow_token(f, Token_when)) {
+		cond = parse_expr(f, false);
+	}
+
+	expect_semicolon(f, nullptr);
+
+	if (f->curr_proc != nullptr) {
+		syntax_error(lib_name, "You cannot use foreign_system_library within a procedure. This must be done at the file scope");
+		return ast_bad_decl(f, lib_name, file_path);
+	}
+
+	return ast_foreign_library_decl(f, token, file_path, lib_name, cond, docs, f->line_comment);
+}
+
 
 
 AstNode *parse_stmt(AstFile *f) {
 AstNode *parse_stmt(AstFile *f) {
 	AstNode *s = nullptr;
 	AstNode *s = nullptr;
@@ -4592,11 +4414,11 @@ AstNode *parse_stmt(AstFile *f) {
 
 
 
 
 	case Token_foreign:
 	case Token_foreign:
+		return parse_foreign_block(f);
+
 	case Token_foreign_library:
 	case Token_foreign_library:
 	case Token_foreign_system_library:
 	case Token_foreign_system_library:
-		s = parse_decl(f);
-		expect_semicolon(f, s);
-		return s;
+		return parse_foreign_decl(f);
 
 
 	case Token_import:
 	case Token_import:
 		return parse_import_decl(f, false);
 		return parse_import_decl(f, false);
@@ -4979,28 +4801,15 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNod
 
 
 			id->fullpath = import_file;
 			id->fullpath = import_file;
 			try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
 			try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
-		} else if (node->kind == AstNode_GenDecl) {
-			ast_node(gd, GenDecl, node);
-			if (gd->token.kind == Token_foreign_library ||
-			           gd->token.kind == Token_foreign_system_library) {
-				for_array(spec_index, gd->specs) {
-					AstNode *spec = gd->specs[spec_index];
-					ast_node(fl, ForeignLibrarySpec, spec);
-					String file_str = fl->filepath.string;
-
-					if (!is_import_path_valid(file_str)) {
-						if (fl->is_system) {
-							syntax_error(node, "Invalid `foreign_system_library` path");
-						} else {
-							syntax_error(node, "Invalid `foreign_library` path");
-						}
-						// NOTE(bill): It's a naughty name
-						gd->specs[spec_index] = ast_bad_decl(f, fl->filepath, fl->filepath);
-						continue;
-					}
-
-					fl->base_dir = base_dir;
-				}
+		} 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));
+				// NOTE(bill): It's a naughty name
+				decls[i] = ast_bad_decl(f, fl->filepath, fl->filepath);
+			} else {
+				fl->base_dir = base_dir;
 			}
 			}
 		}
 		}
 	}
 	}

+ 0 - 6
src/ssa.cpp

@@ -1935,12 +1935,6 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
 	case_end;
 	case_end;
 
 
 	case_ast_node(us, UsingStmt, node);
 	case_ast_node(us, UsingStmt, node);
-		for_array(i, us->list) {
-			AstNode *decl = unparen_expr(us->list[i]);
-			if (decl->kind == AstNode_GenDecl) {
-				ssa_build_stmt(p, decl);
-			}
-		}
 	case_end;
 	case_end;
 
 
 	case_ast_node(ws, WhenStmt, node);
 	case_ast_node(ws, WhenStmt, node);

+ 1 - 0
src/tokenizer.cpp

@@ -85,6 +85,7 @@ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
 \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_import,                 "import"),                 \
 	TOKEN_KIND(Token_import,                 "import"),                 \
+	TOKEN_KIND(Token_export,                 "export"),                 \
 	TOKEN_KIND(Token_foreign,                "foreign"),                \
 	TOKEN_KIND(Token_foreign,                "foreign"),                \
 	TOKEN_KIND(Token_foreign_library,        "foreign_library"),        \
 	TOKEN_KIND(Token_foreign_library,        "foreign_library"),        \
 	TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
 	TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \