diff --git a/README.md b/README.md index acfd04d..38cfc96 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,11 @@ I have no illusions here, this is not the next big language. What I propose is v - **User has full control over compilation!** - **No dependencies, permissive license, single file that compile both in C and C++!** - **Simpler then C:** core of the language is 4000 loc and entire package 11k loc. -- **Statically typed, procedural and MODERN:** it's a mix of Go/Odin/Jai with "return to C" as ideal. +- **Statically typed, procedural and modern:** it's a mix of Go/Odin/Jai with "return to C" as ideal. - **Complete:** it supports conditional compilation, modularity via packages etc. - **State of art error handling techniques** like AST poisoning, proper parsing recovery, catches tons of errors without misreporting! - **Great C integration:** using C libraries feels native, the language compiles easily to C with great debug info. -**Library is in beta so I reserve the right to change things!** - ## Example or [you can try the language online](https://krzosa.xyz/playground.html) ``` odin diff --git a/build.bat b/build.bat index fc8ae12..c4f0075 100644 --- a/build.bat +++ b/build.bat @@ -8,4 +8,4 @@ if not exist build\bld.exe ( ) rem ubuntu run ./build.sh -build\bld.exe +build\bld.exe --quick diff --git a/build_file.cpp b/build_file.cpp index 9de7d1f..72ec765 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -122,7 +122,7 @@ int main(int argc, char **argv) { return 0; } - PackageCompiler(); + // PackageCompiler(); IO_Printf("Compiler packed successfully: lib_compiler.h\n"); if (ShouldRun("test_readme")) { diff --git a/examples/add_dynamic_array_macro/build.cpp b/examples/add_dynamic_array_macro/build.cpp index e5cc626..ceded66 100644 --- a/examples/add_dynamic_array_macro/build.cpp +++ b/examples/add_dynamic_array_macro/build.cpp @@ -9,6 +9,7 @@ bool add_dynamic_array_macro() { LC_Intern name = LC_ILit("add_dynamic_array_macro"); LC_ParsePackagesUsingRegistry(name); + LC_BuildIfPass(); if (L->errors) { LC_LangEnd(lang); return false; diff --git a/examples/generate_type_info/build.cpp b/examples/generate_type_info/build.cpp index d5a3be3..e0c7c5a 100644 --- a/examples/generate_type_info/build.cpp +++ b/examples/generate_type_info/build.cpp @@ -12,6 +12,7 @@ bool generate_type_info() { LC_Intern name = LC_ILit("generate_type_info"); LC_ParsePackagesUsingRegistry(name); + LC_BuildIfPass(); if (L->errors) { LC_LangEnd(lang); return false; diff --git a/examples/sandbox/build.cpp b/examples/sandbox/build.cpp index 35ad1c2..f8ed0dd 100644 --- a/examples/sandbox/build.cpp +++ b/examples/sandbox/build.cpp @@ -65,6 +65,7 @@ bool sandbox() { LC_Intern name = LC_ILit("sandbox"); LC_ParsePackagesUsingRegistry(name); + LC_BuildIfPass(); if (L->errors) { LC_LangEnd(lang); return false; diff --git a/src/build_file/ast_verify.cpp b/src/build_file/ast_verify.cpp index 5f219d6..d267918 100644 --- a/src/build_file/ast_verify.cpp +++ b/src/build_file/ast_verify.cpp @@ -1,4 +1,5 @@ thread_local LC_Map DebugASTMap; +thread_local bool DebugInsideDiscarded; void DebugVerify_WalkAST(LC_ASTWalker *ctx, LC_AST *n) { bool created = LC_InsertWithoutReplace(&DebugASTMap, n, (void *)(intptr_t)100); @@ -23,7 +24,7 @@ void DebugVerify_WalkAST(LC_ASTWalker *ctx, LC_AST *n) { } } - if (LC_IsType(n) && ctx->inside_discarded == 0) { + if (LC_IsType(n) && DebugInsideDiscarded == false) { if (!n->type) { LC_ReportASTError(n, "typespec doesn't hold type"); } @@ -42,7 +43,7 @@ void DebugVerify_WalkAST(LC_ASTWalker *ctx, LC_AST *n) { } } - bool should_have_type = parent_is_builtin == false && ctx->inside_note == 0 && ctx->inside_discarded == 0; + bool should_have_type = parent_is_builtin == false && ctx->inside_note == 0 && DebugInsideDiscarded == false; if (should_have_type && !n->type) { LC_ReportASTError(n, "expression doesn't have type"); } @@ -78,8 +79,7 @@ void VerifyASTCopy(LC_ASTRefList packages) { { LC_ASTWalker walker = LC_GetDefaultWalker(L->arena, VerifyCopy_Walk); - walker.visit_notes = walker.visit_discarded = true; - walker.user_data = (void *)©_counter; + walker.user_data = (void *)©_counter; LC_WalkAST(&walker, copy); walker.user_data = (void *)&original_counter; LC_WalkAST(&walker, copy); @@ -101,13 +101,15 @@ void DebugVerifyAST(LC_ASTRefList packages) { LC_MapReserve(&DebugASTMap, 4096); LC_ASTWalker walker = LC_GetDefaultWalker(L->arena, DebugVerify_WalkAST); - walker.visit_notes = walker.visit_discarded = true; - for (LC_ASTRef *it = packages.first; it; it = it->next) { - LC_WalkAST(&walker, it->ast); - } + walker.visit_notes = true; + for (LC_ASTRef *it = packages.first; it; it = it->next) LC_WalkAST(&walker, it->ast); LC_WalkAST(&walker, L->tstring->decl->ast); LC_WalkAST(&walker, L->tany->decl->ast); + DebugInsideDiscarded = true; + for (LC_ASTRef *it = L->discarded.first; it; it = it->next) LC_WalkAST(&walker, it->ast); + DebugInsideDiscarded = false; + for (int i = 0; i < L->ast_count; i += 1) { LC_AST *it = (LC_AST *)L->ast_arena->memory.data + i; if (it == L->builtin_package) continue; diff --git a/src/build_file/testsuite.cpp b/src/build_file/testsuite.cpp index 503d023..edb2e2a 100644 --- a/src/build_file/testsuite.cpp +++ b/src/build_file/testsuite.cpp @@ -277,6 +277,7 @@ void RunTestFile(TestDesc it) { L->first_package = name; LC_ParsePackagesUsingRegistry(name); + LC_BuildIfPass(); if (L->errors) { result = Failed_Parse; goto end_of_test; diff --git a/src/compiler/ast_copy.c b/src/compiler/ast_copy.c index 5bd804e..efe2b46 100644 --- a/src/compiler/ast_copy.c +++ b/src/compiler/ast_copy.c @@ -19,12 +19,6 @@ LC_FUNCTION LC_AST *LC_CopyAST(LC_Arena *arena, LC_AST *n) { LC_AST *it_copy = LC_CopyAST(arena, it); LC_DLLAdd(result->afile.fdecl, result->afile.ldecl, it_copy); } - LC_ASTFor(it, n->afile.fdiscarded) { - LC_AST *it_copy = LC_CopyAST(arena, it); - LC_DLLAdd(result->afile.fdiscarded, result->afile.ldiscarded, it_copy); - } - - result->afile.build_if = n->afile.build_if; } break; case LC_ASTKind_DeclProc: { diff --git a/src/compiler/ast_walk.c b/src/compiler/ast_walk.c index 3fe01ce..54cd909 100644 --- a/src/compiler/ast_walk.c +++ b/src/compiler/ast_walk.c @@ -58,10 +58,6 @@ LC_FUNCTION void LC_WalkAST(LC_ASTWalker *ctx, LC_AST *n) { case LC_ASTKind_Package: { LC_ASTFor(it, n->apackage.ffile) LC_WalkAST(ctx, it); - - ctx->inside_discarded += 1; - if (ctx->visit_discarded) LC_ASTFor(it, n->apackage.fdiscarded) LC_WalkAST(ctx, it); - ctx->inside_discarded -= 1; } break; case LC_ASTKind_File: { @@ -70,10 +66,6 @@ LC_FUNCTION void LC_WalkAST(LC_ASTWalker *ctx, LC_AST *n) { if (ctx->visit_notes == false && it->kind == LC_ASTKind_DeclNote) continue; LC_WalkAST(ctx, it); } - - ctx->inside_discarded += 1; - if (ctx->visit_discarded) LC_ASTFor(it, n->afile.fdiscarded) LC_WalkAST(ctx, it); - ctx->inside_discarded -= 1; } break; case LC_ASTKind_DeclProc: { diff --git a/src/compiler/lib_compiler.h b/src/compiler/lib_compiler.h index 59d07f2..451bdbb 100644 --- a/src/compiler/lib_compiler.h +++ b/src/compiler/lib_compiler.h @@ -369,12 +369,8 @@ struct LC_ASTFile { LC_AST *limport; LC_AST *fdecl; LC_AST *ldecl; - LC_AST *fdiscarded; - LC_AST *ldiscarded; // @build_if LC_Token *doc_comment; - - bool build_if; }; struct LC_ASTPackage { @@ -384,8 +380,6 @@ struct LC_ASTPackage { LC_StringList injected_filepaths; // to sidestep regular file finding, implement single file packages etc. LC_AST *ffile; LC_AST *lfile; - LC_AST *fdiscarded; - LC_AST *ldiscarded; // #build_if LC_Token *doc_comment; @@ -446,7 +440,7 @@ struct LC_ExprCompoItem { }; // clang-format off -union LC_Val { LC_BigInt i; double d; LC_Intern name; }; +union LC_Val { LC_BigInt i; double d; LC_Intern name; }; struct LC_ExprIdent { LC_Intern name; LC_Decl *resolved_decl; }; struct LC_ExprUnary { LC_TokenKind op; LC_AST *expr; }; struct LC_ExprBinary { LC_TokenKind op; LC_AST *left; LC_AST *right; }; @@ -487,7 +481,7 @@ struct LC_DeclNote { LC_DeclBase base; LC_AST *expr; bool processed; }; / struct LC_GlobImport { LC_Intern name; LC_Intern path; bool resolved; LC_Decl *resolved_decl; }; struct LC_ASTRef { LC_ASTRef *next; LC_ASTRef *prev; LC_AST *ast; }; -struct LC_ASTRefList { LC_ASTRef *first; LC_ASTRef *last; }; +struct LC_ASTRefList { LC_ASTRef *first; LC_ASTRef *last; }; // clang-format on struct LC_TypeAndVal { @@ -650,10 +644,8 @@ struct LC_ASTWalker { LC_ASTArray stack; int inside_builtin; - int inside_discarded; int inside_note; - uint8_t visit_discarded; uint8_t visit_notes; uint8_t depth_first; uint8_t dont_recurse; // breathfirst only @@ -905,6 +897,7 @@ struct LC_Lang { LC_Intern first_package; LC_ASTRefList ordered_packages; LC_StringList package_dirs; + LC_ASTRefList discarded; LC_Map interns; LC_Map declared_notes; @@ -1656,10 +1649,6 @@ LC_FUNCTION wchar_t *LC_ToWidechar(LC_Arena *allocator, LC_String string); (node)->prev->next = (node)->next; \ (node)->next->prev = (node)->prev; \ } \ - if (node) { \ - (node)->prev = 0; \ - (node)->next = 0; \ - } \ } while (0) #define LC_DLLRemove(first, last, node) LC_DLLRemoveMod(first, last, node, next, prev) diff --git a/src/compiler/packages.c b/src/compiler/packages.c index 3eab82a..ea355fb 100644 --- a/src/compiler/packages.c +++ b/src/compiler/packages.c @@ -221,6 +221,36 @@ LC_FUNCTION void LC_ParsePackagesUsingRegistry(LC_Intern name) { } } +LC_FUNCTION void LC_BuildIfPass(void) { + LC_ASTFor(n, L->fpackage) { + for (LC_AST *fit = n->apackage.ffile; fit;) { + LC_AST *next = fit->next; + + LC_AST *build_if = LC_HasNote(fit, L->ibuild_if); + if (build_if) { + if (!LC_ResolveBuildIf(build_if)) { + LC_DLLRemove(n->apackage.ffile, n->apackage.lfile, fit); + LC_AddASTToRefList(&L->discarded, fit); + fit = next; + continue; + } + } + + for (LC_AST *dit = fit->afile.fdecl; dit; dit = dit->next) { + LC_AST *build_if = LC_HasNote(dit, L->ibuild_if); + if (build_if) { + if (!LC_ResolveBuildIf(build_if)) { + LC_DLLRemove(fit->afile.fdecl, fit->afile.ldecl, dit); + LC_AddASTToRefList(&L->discarded, dit); + } + } + } + + fit = next; + } + } +} + LC_FUNCTION void LC_AddOrderedPackageToRefList(LC_AST *n) { LC_ASTRefList *ordered = &L->ordered_packages; for (LC_ASTRef *it = ordered->first; it; it = it->next) { @@ -315,6 +345,7 @@ LC_FUNCTION void LC_ResolveAllProcBodies(void) { LC_FUNCTION LC_ASTRefList LC_ResolvePackageByName(LC_Intern name) { LC_ParsePackagesUsingRegistry(name); + LC_BuildIfPass(); LC_ASTRefList empty = {0}; if (L->errors) return empty; diff --git a/src/compiler/parse.c b/src/compiler/parse.c index af5ead9..86c5c68 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -776,6 +776,33 @@ LC_FUNCTION LC_AST *LC_ParseNotes(void) { return 0; } +LC_FUNCTION bool ParseHashBuildIf(LC_AST *n) { + LC_Token *t0 = LC_GetI(0); + LC_Token *t1 = LC_GetI(1); + if (t0->kind == LC_TokenKind_Hash && t1->kind == LC_TokenKind_Ident && t1->ident == L->ibuild_if) { + LC_Next(); + + LC_AST *note = LC_ParseNote(); + if (note->kind == LC_ASTKind_Error) { + LC_EatUntilNextValidDecl(); + return true; + } + + if (!LC_Match(LC_TokenKind_Semicolon)) { + LC_ReportParseError(LC_GetI(-1), "expected ';' semicolon"); + LC_EatUntilNextValidDecl(); + return true; + } + + LC_AST *note_list = LC_CreateAST(t0, LC_ASTKind_NoteList); + LC_DLLAdd(note_list->anote_list.first, note_list->anote_list.last, note); + n->notes = note_list; + + return LC_ResolveBuildIf(note); + } + return true; +} + LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if) { LC_ExprCompo *note = &build_if->anote; if (note->size != 1) { @@ -785,7 +812,7 @@ LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if) { LC_ExprCompoItem *item = ¬e->first->ecompo_item; if (item->index != NULL || item->name != 0) { - LC_ReportParseError(LC_GetI(-1), "invalid syntax, #build_if shouldn't have a named or indexed first argument"); + LC_ReportParseError(LC_GetI(-1), "invalid syntax, you have passed in a named or indexed argument to #build_if"); return true; } @@ -908,34 +935,6 @@ LC_FUNCTION bool LC_EatUntilNextValidDecl(void) { } } -LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n) { - LC_Token *t0 = LC_GetI(0); - LC_Token *t1 = LC_GetI(1); - if (t0->kind == LC_TokenKind_Hash && t1->kind == LC_TokenKind_Ident && t1->ident == L->ibuild_if) { - LC_Next(); - - LC_AST *build_if = LC_CreateAST(t1, LC_ASTKind_DeclNote); - build_if->dnote.expr = LC_ParseNote(); - if (build_if->dnote.expr->kind == LC_ASTKind_Error) { - LC_EatUntilNextValidDecl(); - return true; - } - - if (!LC_Match(LC_TokenKind_Semicolon)) { - LC_ReportParseError(LC_GetI(-1), "expected ';' semicolon"); - LC_EatUntilNextValidDecl(); - return true; - } - - LC_AST *note_list = LC_CreateAST(t0, LC_ASTKind_NoteList); - LC_DLLAdd(note_list->anote_list.first, note_list->anote_list.last, build_if); - n->notes = note_list; - - return LC_ResolveBuildIf(build_if->dnote.expr); - } - return true; -} - LC_FUNCTION LC_AST *LC_ParseImport(void) { LC_AST *n = NULL; LC_Token *import = LC_MatchKeyword(L->kimport); @@ -965,7 +964,7 @@ LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package) { LC_AST *n = LC_CreateAST(LC_Get(), LC_ASTKind_File); n->afile.x = L->parser->x; n->afile.doc_comment = LC_Match(LC_TokenKind_FileDocComment); - n->afile.build_if = LC_ParseHashBuildOn(n); + ParseHashBuildIf(n); // Parse imports while (!LC_Is(LC_TokenKind_EOF)) { @@ -988,35 +987,15 @@ LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package) { if (decl->kind == LC_ASTKind_Error) { LC_EatUntilNextValidDecl(); } else { - bool skip = false; - - LC_AST *build_if = LC_HasNote(decl, L->ibuild_if); - if (build_if) { - skip = !LC_ResolveBuildIf(build_if); - } - - if (L->on_decl_parsed) { - skip = L->on_decl_parsed(skip, decl); - } - - if (skip) { - LC_DLLAdd(n->afile.fdiscarded, n->afile.ldiscarded, decl); - } else { - LC_DLLAdd(n->afile.fdecl, n->afile.ldecl, decl); - } + if (L->on_decl_parsed) L->on_decl_parsed(false, decl); + LC_DLLAdd(n->afile.fdecl, n->afile.ldecl, decl); } } if (package) { if (package->apackage.doc_comment) LC_ReportParseError(package_doc_comment, "there are more then 1 package doc comments in %s package", (char *)package->apackage.name); package->apackage.doc_comment = package_doc_comment; - - if (n->afile.build_if) { - LC_AddFileToPackage(package, n); - } else { - LC_DLLAdd(package->apackage.fdiscarded, package->apackage.ldiscarded, n); - n->afile.package = package; - } + LC_AddFileToPackage(package, n); } return n;